"use client"; import MenuItem from "@mui/material/MenuItem"; import Select from "@mui/material/Select"; import clsx from "clsx"; import { useId, useState, type ReactNode } from "react"; import { FiBox, FiCamera, FiCheck, FiChevronDown, FiChevronRight, FiClock, FiCrosshair, FiDroplet, FiHome, FiInfo, FiLayers, FiMaximize, FiPlus, FiRotateCcw, FiSliders, FiTrash2, FiX, } from "react-icons/fi"; import type { SceneAssetSelection, SceneCommand, SceneMode, SceneRuntimeState, } from "./sceneProtocol"; const sceneModes: Array<{ mode: SceneMode; label: string }> = [ { mode: "network", label: "供水管网" }, { mode: "hydraulic", label: "泵组与管网" }, { mode: "map", label: "站区轻量版" }, { mode: "detail", label: "站房精细版" }, { mode: "pump", label: "CAD 泵房参考" }, { mode: "meters", label: "设备样件" }, ]; const glassSurface = "bg-[linear-gradient(135deg,rgba(255,255,255,0.50),rgba(224,239,250,0.28))] [backdrop-filter:blur(24px)_saturate(170%)_contrast(94%)] [-webkit-backdrop-filter:blur(24px)_saturate(170%)_contrast(94%)] [box-shadow:inset_0_1px_0_rgba(255,255,255,0.88),inset_0_-1px_0_rgba(112,145,168,0.18),0_18px_50px_rgba(15,43,69,0.20)] ring-1 ring-white/55"; const fieldClass = "h-10 w-full rounded-lg border border-slate-300/70 bg-white/55 px-3 text-sm text-slate-800 outline-none transition focus:border-blue-500 focus:bg-white/80 focus:ring-2 focus:ring-blue-500/20 disabled:cursor-not-allowed disabled:opacity-50"; const selectSx = { height: 40, borderRadius: "0.5rem", backgroundColor: "rgba(255,255,255,0.55)", color: "#1e293b", fontSize: "0.875rem", transition: "background-color 150ms ease, box-shadow 150ms ease", "&:hover": { backgroundColor: "rgba(255,255,255,0.78)", }, "& .MuiSelect-select": { display: "flex", alignItems: "center", minHeight: "0 !important", padding: "8px 38px 8px 12px !important", }, "& .MuiSelect-icon": { right: 12, color: "#64748b", fontSize: 16, transition: "transform 150ms ease", }, "& .MuiOutlinedInput-notchedOutline": { borderColor: "rgba(148,163,184,0.7)", }, "&:hover .MuiOutlinedInput-notchedOutline": { borderColor: "rgba(59,130,246,0.65)", }, "&.Mui-focused": { backgroundColor: "rgba(255,255,255,0.82)", boxShadow: "0 0 0 3px rgba(59,130,246,0.16)", }, "&.Mui-focused .MuiOutlinedInput-notchedOutline": { borderColor: "#3b82f6", borderWidth: 1, }, }; const selectMenuProps = { disableScrollLock: true, PaperProps: { elevation: 0, sx: { mt: 0.75, overflow: "hidden", borderRadius: "0.75rem", border: "1px solid rgba(255,255,255,0.72)", background: "linear-gradient(135deg, rgba(244,249,252,0.94), rgba(225,239,248,0.88))", backdropFilter: "blur(24px) saturate(155%)", WebkitBackdropFilter: "blur(24px) saturate(155%)", boxShadow: "inset 0 1px 0 rgba(255,255,255,0.92), 0 16px 42px rgba(15,43,69,0.22)", }, }, MenuListProps: { sx: { p: 0.75, }, }, }; const selectMenuItemSx = { minHeight: 40, gap: 1, borderRadius: "0.5rem", px: 1.25, color: "#334155", fontSize: "0.875rem", transition: "background-color 120ms ease, color 120ms ease", "&:hover": { backgroundColor: "rgba(255,255,255,0.68)", color: "#1d4ed8", }, "&.Mui-selected": { backgroundColor: "#2563eb", color: "#fff", }, "&.Mui-selected:hover": { backgroundColor: "#1d4ed8", }, "&.Mui-focusVisible": { outline: "2px solid rgba(59,130,246,0.42)", outlineOffset: -2, }, }; export type ControlTab = "scene" | "style" | "properties"; export type ThreeDimensionalControlsProps = { open: boolean; activeTab: ControlTab; ready: boolean; state: SceneRuntimeState; selection: SceneAssetSelection | null; timelineOpen: boolean; onOpenChange: (open: boolean) => void; onTimelineOpenChange: (open: boolean) => void; onTabChange: (tab: ControlTab) => void; onCommand: (command: SceneCommand) => void; }; export function ThreeDimensionalControls({ open, activeTab, ready, state, selection, timelineOpen, onOpenChange, onTimelineOpenChange, onTabChange, onCommand, }: ThreeDimensionalControlsProps) { const [cameraLabel, setCameraLabel] = useState(""); const selectTab = (tab: ControlTab) => { if (open && activeTab === tab) { onOpenChange(false); return; } onTabChange(tab); onOpenChange(true); }; return ( <> {open && ( )} ); } function ToolButton({ label, active = false, disabled = false, onClick, children }: { label: string; active?: boolean; disabled?: boolean; onClick: () => void; children: ReactNode }) { return (
{label}
); } function IconButton({ label, disabled = false, onClick, children }: { label: string; disabled?: boolean; onClick: () => void; children: ReactNode }) { return ( ); } function TabButton({ active, onClick, icon, children }: { active: boolean; onClick: () => void; icon: ReactNode; children: ReactNode }) { return ( ); } function ControlSection({ title, description, children }: { title: string; description?: string; children: ReactNode }) { return (

{title}

{description &&

{description}

}
{children}
); } function SelectField({ label, value, options, onChange }: { label: string; value: string; options: Array<{ value: string; label: string }>; onChange: (value: string) => void }) { const labelId = useId(); const selected = options.find((option) => option.value === value); return (
{label}
); } function SwitchRow({ label, checked, onChange }: { label: string; checked: boolean; onChange: (checked: boolean) => void }) { return ( ); } function LabeledSlider({ label, value, min, max, step, disabled = false, onChange }: { label: string; value: number; min: number; max: number; step: number; disabled?: boolean; onChange: (value: number) => void }) { return ( ); } function ColorInput({ label, value, onChange }: { label: string; value: string; onChange: (value: string) => void }) { return ( ); } function NumberInput({ label, value, onCommit }: { label: string; value: number; onCommit: (value: number) => void }) { return ( ); } function AssetProperties({ selection, onCommand }: { selection: SceneAssetSelection | null; onCommand: (command: SceneCommand) => void }) { if (!selection) { return (

尚未选择三维构件

在模型中点击节点、管段、泵或阀门,这里会显示模型属性和当前后端结果。

); } return (

{selection.title}

模型编号 {selection.elementId}

{selection.sections.map((section) => (

{section.title}

{section.fields.map((field, index) => (
0 && "border-t border-slate-200/55")}>
{field.label}
{field.value}
))}
))} {selection.neighbors.length > 0 && (

相邻管段

{selection.neighbors.map((neighbor) => ( ))}
)}
); }