diff --git a/public/icons/valve.svg b/public/icons/valve.svg index 84c3055..2e5bf85 100644 --- a/public/icons/valve.svg +++ b/public/icons/valve.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/src/app/OlMap/Controls/HistoryDataPanel.tsx b/src/app/OlMap/Controls/HistoryDataPanel.tsx index c923edd..2949962 100644 --- a/src/app/OlMap/Controls/HistoryDataPanel.tsx +++ b/src/app/OlMap/Controls/HistoryDataPanel.tsx @@ -70,7 +70,6 @@ export interface HistoryDataPanelProps { defaultTab?: "chart" | "table"; /** Y 轴数值的小数位数 */ fractionDigits?: number; - // 清洗功能已移除,相关参数请通过外部面板/服务清洗后再传入 } type PanelTab = "chart" | "table"; @@ -235,7 +234,7 @@ const HistoryDataPanel: React.FC = ({ fetchTimeSeriesData = defaultFetcher, visible = true, defaultTab = "chart", - fractionDigits = 2, + fractionDigits = 3, }) => { // 从 devices 中提取 id 列表用于渲染与查询 const deviceIds = devices?.map((d) => d.id) ?? []; diff --git a/src/app/OlMap/Controls/StyleEditorPanel.tsx b/src/app/OlMap/Controls/StyleEditorPanel.tsx index d3fdf19..4fdf6c1 100644 --- a/src/app/OlMap/Controls/StyleEditorPanel.tsx +++ b/src/app/OlMap/Controls/StyleEditorPanel.tsx @@ -301,7 +301,7 @@ const StyleEditorPanel: React.FC = ({ if (layerId !== undefined && property !== undefined) { // 验证自定义断点设置 if (styleConfig.classificationMethod === "custom_breaks") { - const expected = styleConfig.segments + 1; + const expected = styleConfig.segments; const custom = styleConfig.customBreaks || []; if ( custom.length !== expected || @@ -609,7 +609,6 @@ const StyleEditorPanel: React.FC = ({ // 更新当前 VectorTileSource 中的所有缓冲要素属性 const updateVectorTileSource = (property: string, data: any[]) => { if (!map) return; - const vectorTileSources = map .getAllLayers() .filter((layer) => layer instanceof WebGLVectorTileLayer) @@ -636,7 +635,12 @@ const StyleEditorPanel: React.FC = ({ const featureId = renderFeature.get("id"); const value = dataMap.get(featureId); if (value !== undefined) { - (renderFeature as any).properties_[property] = value; + if (property === "flow") { + // 特殊处理流量属性,取绝对值 + (renderFeature as any).properties_[property] = Math.abs(value); + } else { + (renderFeature as any).properties_[property] = value; + } } }); }); @@ -677,7 +681,12 @@ const StyleEditorPanel: React.FC = ({ const featureId = renderFeature.get("id"); const value = dataMap.get(featureId); if (value !== undefined) { - (renderFeature as any).properties_[property] = value; + if (property === "flow") { + // 特殊处理流量属性,取绝对值 + (renderFeature as any).properties_[property] = Math.abs(value); + } else { + (renderFeature as any).properties_[property] = value; + } } }); } @@ -845,7 +854,7 @@ const StyleEditorPanel: React.FC = ({ useEffect(() => { if (styleConfig.classificationMethod !== "custom_breaks") return; - const numBreaks = styleConfig.segments + 1; + const numBreaks = styleConfig.segments; setStyleConfig((prev) => { const prevBreaks = prev.customBreaks || []; if (prevBreaks.length === numBreaks) return prev; @@ -1372,46 +1381,44 @@ const StyleEditorPanel: React.FC = ({ className="flex flex-col gap-2" sx={{ maxHeight: "240px", overflowY: "auto", paddingTop: "12px" }} > - {Array.from({ length: styleConfig.segments + 1 }).map( - (_, idx) => ( - { - const v = parseFloat(e.target.value); - setStyleConfig((prev) => { - const prevBreaks = prev.customBreaks - ? [...prev.customBreaks] - : []; - // 保证长度 - while (prevBreaks.length < styleConfig.segments + 1) - prevBreaks.push(0); - prevBreaks[idx] = isNaN(v) ? 0 : Math.max(0, v); - return { ...prev, customBreaks: prevBreaks }; - }); - }} - onBlur={() => { - // on blur 保证升序 - setStyleConfig((prev) => { - const prevBreaks = (prev.customBreaks || []).slice( - 0, - styleConfig.segments + 1 - ); - prevBreaks.sort((a, b) => a - b); - return { ...prev, customBreaks: prevBreaks }; - }); - }} - /> - ) - )} + {Array.from({ length: styleConfig.segments }).map((_, idx) => ( + { + const v = parseFloat(e.target.value); + setStyleConfig((prev) => { + const prevBreaks = prev.customBreaks + ? [...prev.customBreaks] + : []; + // 保证长度 + while (prevBreaks.length < styleConfig.segments + 1) + prevBreaks.push(0); + prevBreaks[idx] = isNaN(v) ? 0 : Math.max(0, v); + return { ...prev, customBreaks: prevBreaks }; + }); + }} + onBlur={() => { + // on blur 保证升序 + setStyleConfig((prev) => { + const prevBreaks = (prev.customBreaks || []).slice( + 0, + styleConfig.segments + 1 + ); + prevBreaks.sort((a, b) => a - b); + return { ...prev, customBreaks: prevBreaks }; + }); + }} + /> + ))} )} @@ -1473,7 +1480,7 @@ const StyleEditorPanel: React.FC = ({ } /> } - label="显示属性(放大后显示)" + label="显示属性(缩放 >=15 级时显示)" />
{/* 操作按钮 */} diff --git a/src/app/OlMap/Controls/Toolbar.tsx b/src/app/OlMap/Controls/Toolbar.tsx index a4860dd..e2572f1 100644 --- a/src/app/OlMap/Controls/Toolbar.tsx +++ b/src/app/OlMap/Controls/Toolbar.tsx @@ -403,7 +403,7 @@ const Toolbar: React.FC = ({ hiddenButtons, queryType }) => { result.properties.push({ label, value: - computedProperties[key].toFixed?.(2) || computedProperties[key], + computedProperties[key].toFixed?.(3) || computedProperties[key], unit, }); } @@ -446,7 +446,7 @@ const Toolbar: React.FC = ({ hiddenButtons, queryType }) => { result.properties.push({ label, value: - computedProperties[key].toFixed?.(2) || computedProperties[key], + computedProperties[key].toFixed?.(3) || computedProperties[key], unit, }); } diff --git a/src/app/OlMap/MapComponent.tsx b/src/app/OlMap/MapComponent.tsx index 6804d06..448a972 100644 --- a/src/app/OlMap/MapComponent.tsx +++ b/src/app/OlMap/MapComponent.tsx @@ -400,7 +400,7 @@ const MapComponent: React.FC = ({ children }) => { useEffect(() => { if (!mapRef.current) return; - // 缓存 junction、pipe 数据,提供给 deck.gl 显示标签使用 + // 缓存 junction、pipe 数据,提供给 deck.gl 提供坐标供标签显示 junctionSource.on("tileloadend", (event) => { try { if (event.tile instanceof VectorTile) { @@ -555,14 +555,14 @@ const MapComponent: React.FC = ({ children }) => { }); // 重新排列图层顺序,确保顺序 点>线>面 availableLayers.sort((a, b) => { - // 明确顺序(点类优先) + // 明确顺序(点类优先),这里 valves 特殊处理 const order = [ + "valves", "junctions", "scada", "reservoirs", "pumps", "tanks", - "valves", "pipes", ].reverse(); // 取值时做安全检查,兼容不同写法(properties.value 或 直接 value) @@ -850,7 +850,9 @@ const MapComponent: React.FC = ({ children }) => { pipeProperties === "flow" && record.value < 0 && p.flowFlag > 0 ? [...p.path].reverse() : p.path, - [pipeProperties]: record.value, + // 流量数值 + [pipeProperties]: + pipeProperties === "flow" ? Math.abs(record.value) : record.value, }; } return p; diff --git a/src/components/olmap/BurstPipeAnalysis/LocationResults.tsx b/src/components/olmap/BurstPipeAnalysis/LocationResults.tsx index 44e142a..ce564eb 100644 --- a/src/components/olmap/BurstPipeAnalysis/LocationResults.tsx +++ b/src/components/olmap/BurstPipeAnalysis/LocationResults.tsx @@ -1,6 +1,6 @@ -'use client'; +"use client"; -import React, { useState } from 'react'; +import React, { useState } from "react"; import { Box, Typography, @@ -14,8 +14,11 @@ import { Chip, IconButton, Tooltip, -} from '@mui/material'; -import { LocationOn as LocationIcon, Visibility as VisibilityIcon } from '@mui/icons-material'; +} from "@mui/material"; +import { + LocationOn as LocationIcon, + Visibility as VisibilityIcon, +} from "@mui/icons-material"; interface LocationResult { id: number; @@ -24,7 +27,7 @@ interface LocationResult { pressure: number; waterLevel: number; flow: number; - status: 'normal' | 'warning' | 'danger'; + status: "normal" | "warning" | "danger"; coordinates: [number, number]; } @@ -33,7 +36,10 @@ interface LocationResultsProps { onViewDetail?: (id: number) => void; } -const LocationResults: React.FC = ({ onLocate, onViewDetail }) => { +const LocationResults: React.FC = ({ + onLocate, + onViewDetail, +}) => { const [results, setResults] = useState([ // 示例数据 // { @@ -50,27 +56,27 @@ const LocationResults: React.FC = ({ onLocate, onViewDetai const getStatusColor = (status: string) => { switch (status) { - case 'normal': - return 'success'; - case 'warning': - return 'warning'; - case 'danger': - return 'error'; + case "normal": + return "success"; + case "warning": + return "warning"; + case "danger": + return "error"; default: - return 'default'; + return "default"; } }; const getStatusText = (status: string) => { switch (status) { - case 'normal': - return '正常'; - case 'warning': - return '预警'; - case 'danger': - return '危险'; + case "normal": + return "正常"; + case "warning": + return "预警"; + case "danger": + return "危险"; default: - return '未知'; + return "未知"; } }; @@ -95,7 +101,7 @@ const LocationResults: React.FC = ({ onLocate, onViewDetai 正常 - {results.filter((r) => r.status === 'normal').length} + {results.filter((r) => r.status === "normal").length} @@ -103,7 +109,7 @@ const LocationResults: React.FC = ({ onLocate, onViewDetai 预警 - {results.filter((r) => r.status === 'warning').length} + {results.filter((r) => r.status === "warning").length} @@ -111,7 +117,7 @@ const LocationResults: React.FC = ({ onLocate, onViewDetai 危险 - {results.filter((r) => r.status === 'danger').length} + {results.filter((r) => r.status === "danger").length} @@ -129,12 +135,46 @@ const LocationResults: React.FC = ({ onLocate, onViewDetai fill="none" className="opacity-40" > - + - - - - + + + + 暂无定位结果 @@ -161,9 +201,15 @@ const LocationResults: React.FC = ({ onLocate, onViewDetai {result.nodeName} {result.nodeId} - {result.pressure.toFixed(2)} - {result.waterLevel.toFixed(2)} - {result.flow.toFixed(1)} + + {result.pressure.toFixed(3)} + + + {result.waterLevel.toFixed(3)} + + + {result.flow.toFixed(1)} +