diff --git a/src/components/olmap/DMALeakDetection/AnalysisParameters.tsx b/src/components/olmap/DMALeakDetection/AnalysisParameters.tsx index a19bd44..6489ec5 100644 --- a/src/components/olmap/DMALeakDetection/AnalysisParameters.tsx +++ b/src/components/olmap/DMALeakDetection/AnalysisParameters.tsx @@ -120,11 +120,19 @@ const AnalysisParameters: React.FC = ({ onResult }) => { value={dmaCount} onChange={(e) => { const value = Number.parseInt(e.target.value, 10); - setDmaCount(Number.isNaN(value) ? 5 : Math.max(3, value)); + // Limit between 3 and 10 + if (Number.isNaN(value)) { + setDmaCount(5); + } else if (value > 10) { + setDmaCount(10); + } else { + setDmaCount(Math.max(3, value)); + } }} fullWidth size="small" - inputProps={{ min: 3, step: 1 }} + inputProps={{ min: 3, max: 10, step: 1 }} + helperText="DMA 数量限制为 3-10 个" /> diff --git a/src/components/olmap/DMALeakDetection/DMALeakDetectionPanel.tsx b/src/components/olmap/DMALeakDetection/DMALeakDetectionPanel.tsx index 6c1e3de..575d649 100644 --- a/src/components/olmap/DMALeakDetection/DMALeakDetectionPanel.tsx +++ b/src/components/olmap/DMALeakDetection/DMALeakDetectionPanel.tsx @@ -9,12 +9,6 @@ import { Typography, IconButton, Tooltip, - Table, - TableBody, - TableCell, - TableHead, - TableRow, - Chip, } from "@mui/material"; import { Analytics as AnalyticsIcon, @@ -23,7 +17,6 @@ import { ChevronRight, FormatListBulleted, } from "@mui/icons-material"; -import dayjs from "dayjs"; import { Circle as CircleStyle, Fill, Stroke, Style } from "ol/style"; import VectorLayer from "ol/layer/Vector"; import VectorSource from "ol/source/Vector"; @@ -33,6 +26,8 @@ import { useMap } from "@app/OlMap/MapComponent"; import StyleLegend from "@app/OlMap/Controls/StyleLegend"; import AnalysisParameters from "./AnalysisParameters"; import SchemeQuery from "./SchemeQuery"; +import RecognitionResults from "./RecognitionResults"; +import { getAreaColor } from "./utils"; import { LeakageResultDetail } from "./types"; const TabPanel = ({ @@ -49,27 +44,7 @@ const TabPanel = ({ ); -const AREA_COLORS = [ - "#2563eb", - "#7c3aed", - "#0891b2", - "#16a34a", - "#ca8a04", - "#dc2626", - "#ea580c", - "#0f766e", - "#4338ca", - "#be123c", -]; -const getAreaColor = (areaId: string | number | undefined) => { - const text = String(areaId ?? ""); - let hash = 0; - for (let i = 0; i < text.length; i += 1) { - hash = (hash * 31 + text.charCodeAt(i)) >>> 0; - } - return AREA_COLORS[hash % AREA_COLORS.length]; -}; const DMALeakDetectionPanel: React.FC = () => { const map = useMap(); @@ -79,12 +54,6 @@ const DMALeakDetectionPanel: React.FC = () => { const [loadedResult, setLoadedResult] = useState(null); const [nodeLayer, setNodeLayer] = useState | null>(null); - const sortedRows = useMemo(() => { - if (!result?.rows) return []; - return [...result.rows].sort( - (a, b) => b.LeakageFlow_m3_per_s - a.LeakageFlow_m3_per_s, - ); - }, [result]); const drawerWidth = 450; const panelTitle = "DMA漏损识别"; const activeAreas = loadedResult?.areas ?? []; @@ -262,150 +231,7 @@ const DMALeakDetectionPanel: React.FC = () => { - {!result || !sortedRows.length ? ( - - - - - - - - 暂无识别结果 - - 请先加载方案或执行识别分析 - - - ) : ( - - {/* 方案详情卡片 */} - - - - - - {result.scheme_name || "漏损识别结果"} - - - {result.username && ( - - )} - - - - {/* 方案时间 */} - - - 方案时间 - - - {dayjs(result.scheme_start_time || result.create_time).format("MM-DD HH:mm")} - - - - {/* 总漏损流量 */} - - - 总漏损流量 - - - {(() => { - const val = (result.scheme_detail as any)?.algorithm_params?.q_sum; - const unit = (result.scheme_detail as any)?.algorithm_params?.q_sum_unit || "m3/s"; - return val !== undefined ? `${Number(val).toFixed(3)} ${unit}` : "-"; - })()} - - - - {/* 分区数量 */} - - - 分区数量 - - - {(result.scheme_detail as any)?.result_summary?.area_count ?? result.areas?.length ?? 0} 个 - - - - {/* 最大漏损 */} - - - 最大漏损 - - - {(() => { - const maxL = (result.scheme_detail as any)?.result_summary?.max_leakage; - return maxL !== undefined ? `${Number(maxL).toFixed(3)} m3/s` : "-"; - })()} - - - - - - {/* 漏损列表 */} - - - - - - 区域漏损列表 - - - - - - - - 区域 - 漏损量占比 (%) - 漏损量 (m3/s) - - - - {sortedRows.map((row) => ( - - - - - - {row.Area} - - - - {(row.LeakageRatio * 100).toFixed(3)} - {row.LeakageFlow_m3_per_s.toFixed(3)} - - ))} - -
-
-
- )} +
diff --git a/src/components/olmap/DMALeakDetection/RecognitionResults.tsx b/src/components/olmap/DMALeakDetection/RecognitionResults.tsx new file mode 100644 index 0000000..ac37d11 --- /dev/null +++ b/src/components/olmap/DMALeakDetection/RecognitionResults.tsx @@ -0,0 +1,258 @@ +"use client"; + +import React, { useMemo } from "react"; +import { + Box, + Typography, + Chip, + Table, + TableBody, + TableCell, + TableHead, + TableRow, +} from "@mui/material"; +import { FormatListBulleted } from "@mui/icons-material"; +import dayjs from "dayjs"; +import { getAreaColor } from "./utils"; +import { LeakageResultDetail } from "./types"; + +interface Props { + result: LeakageResultDetail | null; +} + +const RecognitionResults: React.FC = ({ result }) => { + const sortedRows = useMemo(() => { + if (!result?.rows) return []; + return [...result.rows].sort( + (a, b) => b.LeakageFlow_m3_per_s - a.LeakageFlow_m3_per_s, + ); + }, [result]); + + if (!result || !sortedRows.length) { + return ( + + + + + + + + 暂无识别结果 + + 请先加载方案或执行识别分析 + + + ); + } + + return ( + + {/* 方案详情卡片 */} + + + + + + {result.scheme_name || "漏损识别结果"} + + + {result.username && ( + + )} + + + + {/* 方案时间 */} + + + 方案时间 + + + {dayjs(result.scheme_start_time || result.create_time).format( + "MM-DD HH:mm", + )} + + + + {/* 总漏损流量 */} + + + 总漏损流量 + + + {(() => { + const val = (result.scheme_detail as any)?.algorithm_params + ?.q_sum; + const unit = + (result.scheme_detail as any)?.algorithm_params?.q_sum_unit || + "m3/s"; + return val !== undefined + ? `${Number(val).toFixed(3)} ${unit}` + : "-"; + })()} + + + + {/* 分区数量 */} + + + 分区数量 + + + {(result.scheme_detail as any)?.result_summary?.area_count ?? + result.areas?.length ?? + 0}{" "} + 个 + + + + {/* 最大漏损 */} + + + 最大漏损 + + + {(() => { + const maxL = (result.scheme_detail as any)?.result_summary + ?.max_leakage; + return maxL !== undefined + ? `${Number(maxL).toFixed(3)} m3/s` + : "-"; + })()} + + + + + + {/* 漏损列表 */} + + + + + + 区域漏损列表 + + + + + + + + + 区域 + + + 漏损量占比 (%) + + + 漏损量 (m3/s) + + + + + {sortedRows.map((row) => ( + + + + + + {row.Area} + + + + + {(row.LeakageRatio * 100).toFixed(3)} + + + {row.LeakageFlow_m3_per_s.toFixed(3)} + + + ))} + +
+
+
+ ); +}; + +export default RecognitionResults; diff --git a/src/components/olmap/DMALeakDetection/utils.ts b/src/components/olmap/DMALeakDetection/utils.ts new file mode 100644 index 0000000..bd46411 --- /dev/null +++ b/src/components/olmap/DMALeakDetection/utils.ts @@ -0,0 +1,21 @@ +export const AREA_COLORS = [ + "#2563eb", + "#7c3aed", + "#0891b2", + "#16a34a", + "#ca8a04", + "#dc2626", + "#ea580c", + "#0f766e", + "#4338ca", + "#be123c", +]; + +export const getAreaColor = (areaId: string | number | undefined) => { + const text = String(areaId ?? ""); + let hash = 0; + for (let i = 0; i < text.length; i += 1) { + hash = (hash * 31 + text.charCodeAt(i)) >>> 0; + } + return AREA_COLORS[hash % AREA_COLORS.length]; +};