From dd93b3768551cf7393abc013e496be1150dfd8c6 Mon Sep 17 00:00:00 2001 From: JIANG Date: Fri, 14 Nov 2025 11:34:36 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=96=B0=E8=AE=BE=E8=AE=A1=E5=B1=9E?= =?UTF-8?q?=E6=80=A7=E9=9D=A2=E6=9D=BF=EF=BC=8C=E4=B8=BA=20demand=20?= =?UTF-8?q?=E6=8F=90=E4=BE=9B=E4=BA=8C=E7=BA=A7=E8=A1=A8=E6=A0=BC=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=E6=9B=B4=E5=A4=9A=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/OlMap/Controls/PropertyPanel.tsx | 83 +++++++++++++++++++++--- src/app/OlMap/Controls/Timeline.tsx | 6 +- src/app/OlMap/Controls/Toolbar.tsx | 74 +++++++++++++++++++-- 3 files changed, 147 insertions(+), 16 deletions(-) diff --git a/src/app/OlMap/Controls/PropertyPanel.tsx b/src/app/OlMap/Controls/PropertyPanel.tsx index da941b6..eee1907 100644 --- a/src/app/OlMap/Controls/PropertyPanel.tsx +++ b/src/app/OlMap/Controls/PropertyPanel.tsx @@ -7,10 +7,20 @@ interface BaseProperty { formatter?: (value: string | number) => string; } +// 新增:表格型属性(用于二级数据) +interface TableProperty { + type: "table"; + label: string; + columns: string[]; // 表头 + rows: (string | number)[][]; // 每行的数据 +} + +type PropertyItem = BaseProperty | TableProperty; + interface PropertyPanelProps { id?: string; type?: string; - properties?: BaseProperty[]; + properties?: PropertyItem[]; } const PropertyPanel: React.FC = ({ @@ -30,8 +40,17 @@ const PropertyPanel: React.FC = ({ const isImportantKeys = ["ID", "类型", "Name", "面积", "长度"]; + // 统计属性数量(表格型按行数计入) + const totalProps = id + ? 2 + + properties.reduce((sum, p) => { + if ("type" in p && p.type === "table") return sum + p.rows.length; + return sum + 1; + }, 0) + : 0; + return ( -
+
{/* 头部 */}
@@ -98,12 +117,60 @@ const PropertyPanel: React.FC = ({
- {/* 其他属性 */} + {/* 其他属性(包含二级表格) */} {properties.map((property, index) => { - const isImportant = isImportantKeys.includes(property.label); + // 二级表格 + if ("type" in property && property.type === "table") { + return ( +
+
+ + {property.label} + +
+
+ + + + {property.columns.map((col, ci) => ( + + ))} + + + + {property.rows.map((row, ri) => ( + + {row.map((cell, cci) => ( + + ))} + + ))} + +
+ {col} +
+ {cell} +
+
+
+ ); + } + + // 普通属性 + const base = property as BaseProperty; + const isImportant = isImportantKeys.includes(base.label); return (
= ({ isImportant ? "text-blue-700" : "text-gray-600" }`} > - {property.label} + {base.label} - {formatValue(property)} + {formatValue(base)}
@@ -150,7 +217,7 @@ const PropertyPanel: React.FC = ({ d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" /> - 共 {id ? properties.length + 2 : 0} 个属性 + 共 {totalProps} 个属性 {id && ( diff --git a/src/app/OlMap/Controls/Timeline.tsx b/src/app/OlMap/Controls/Timeline.tsx index de6cefe..0e8ebb2 100644 --- a/src/app/OlMap/Controls/Timeline.tsx +++ b/src/app/OlMap/Controls/Timeline.tsx @@ -68,7 +68,7 @@ const Timeline: React.FC = ({ const { open, close } = useNotification(); const [isPlaying, setIsPlaying] = useState(false); - const [playInterval, setPlayInterval] = useState(5000); // 毫秒 + const [playInterval, setPlayInterval] = useState(15000); // 毫秒 const [calculatedInterval, setCalculatedInterval] = useState(15); // 分钟 const [isCalculating, setIsCalculating] = useState(false); @@ -206,9 +206,9 @@ const Timeline: React.FC = ({ // 播放时间间隔选项 const intervalOptions = [ - { value: 2000, label: "2秒" }, - { value: 5000, label: "5秒" }, { value: 10000, label: "10秒" }, + { value: 15000, label: "15秒" }, + { value: 20000, label: "20秒" }, ]; // 强制计算时间段选项 const calculatedIntervalOptions = [ diff --git a/src/app/OlMap/Controls/Toolbar.tsx b/src/app/OlMap/Controls/Toolbar.tsx index dbf2ecc..ff935f5 100644 --- a/src/app/OlMap/Controls/Toolbar.tsx +++ b/src/app/OlMap/Controls/Toolbar.tsx @@ -4,6 +4,7 @@ import ToolbarButton from "@/components/olmap/common/ToolbarButton"; import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined"; import EditOutlinedIcon from "@mui/icons-material/EditOutlined"; import PaletteOutlinedIcon from "@mui/icons-material/PaletteOutlined"; +import QueryStatsOutlinedIcon from "@mui/icons-material/QueryStatsOutlined"; import PropertyPanel from "./PropertyPanel"; // 引入属性面板组件 import DrawPanel from "./DrawPanel"; // 引入绘图面板组件 @@ -266,6 +267,9 @@ const Toolbar: React.FC = ({ hiddenButtons, queryType }) => { case "draw": setShowDrawPanel(false); break; + case "history": + // 取消历史查询激活时的清理(目前不保留额外状态) + break; } }; @@ -278,6 +282,47 @@ const Toolbar: React.FC = ({ hiddenButtons, queryType }) => { case "draw": setShowDrawPanel(true); break; + case "history": + // 激活历史查询后立即触发一次网络历史数据查询(结果暂时打印到控制台) + queryNetworkHistory(); + break; + } + }; + + // 查询管网历史数据的函数(激活时调用) + const queryNetworkHistory = async () => { + try { + // 由当前选中日期和 currentTime 构造查询时间(UTC ISO) + let dateObj: Date; + if (selectedDate instanceof Date) { + dateObj = new Date(selectedDate); + } else { + dateObj = new Date(selectedDate as any); + } + const minutes = Number(currentTime) || 0; + dateObj.setHours(Math.floor(minutes / 60), minutes % 60, 0, 0); + const querytime = dateObj.toISOString(); + + let url: string; + if (queryType === "scheme") { + url = `${backendUrl}/queryschemesimulationrecordsbytime/?scheme_name=${schemeName}&querytime=${querytime}`; + } else { + url = `${backendUrl}/querysimulationrecordsbytime/?querytime=${querytime}`; + } + + const response = await fetch(url); + if (!response.ok) { + console.error("查询管网历史数据失败:", response.statusText); + return; + } + const result = await response.json(); + // TODO: 根据需要把结果展示到面板或状态中,目前先打印 + console.log("管网历史数据:", result); + // 简单提示用户已查询(可改为更友好的 UI) + // eslint-disable-next-line no-alert + alert("已查询管网历史数据(请查看控制台或后续面板展示)。"); + } catch (error) { + console.error("查询管网历史数据出错:", error); } }; @@ -363,7 +408,7 @@ const Toolbar: React.FC = ({ hiddenButtons, queryType }) => { const nodeComputedFields = [ { key: "actualdemand", label: "实际需水量", unit: "m³/s" }, { key: "head", label: "水头", unit: "m" }, - { key: "pressure", label: "压力", unit: "kPa" }, + { key: "pressure", label: "压力", unit: "m" }, { key: "quality", label: "水质", unit: "mg/L" }, ]; @@ -410,11 +455,22 @@ const Toolbar: React.FC = ({ hiddenButtons, queryType }) => { value: properties.elevation?.toFixed?.(1), unit: "m", }, + // 将 demand1~demand5 与 pattern1~pattern5 作为二级表格展示 { - label: "需求量", - value: properties.demand?.toFixed?.(1), - unit: "m³/s", - }, + type: "table", + label: "基本需水量", + columns: ["demand", "pattern"], + rows: Array.from({ length: 5 }, (_, i) => i + 1) + .map((idx) => { + const d = properties?.[`demand${idx}`]?.toFixed?.(3); + const p = properties?.[`pattern${idx}`]; + // 仅当 demand 有效时展示该行 + if (d !== undefined && d !== null && d !== "") { + return [typeof d === "number" ? d.toFixed(3) : d, p ?? "-"]; + } + }) + .filter(Boolean) as (string | number)[][], + } as any, ], }; // 追加计算属性 @@ -623,6 +679,14 @@ const Toolbar: React.FC = ({ hiddenButtons, queryType }) => { onClick={() => handleToolClick("info")} /> )} + {!hiddenButtons?.includes("history") && ( + } + name="查询历史数据" + isActive={activeTools.includes("history")} + onClick={() => handleToolClick("history")} + /> + )} {!hiddenButtons?.includes("draw") && ( }