From f0f9d3f4f93cddaf305f347bba120b0a2fe56035 Mon Sep 17 00:00:00 2001 From: JIANG Date: Tue, 10 Mar 2026 18:15:11 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20lint=20warnings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- next.config.mjs | 8 ++ src/app/login/page.tsx | 5 +- .../BurstSimulation/AnalysisParameters.tsx | 73 +++++++------- .../olmap/BurstSimulation/SchemeQuery.tsx | 2 +- .../AnalysisParameters.tsx | 54 +++++----- .../DMALeakDetectionPanel.tsx | 2 +- .../FlushingAnalysis/AnalysisParameters.tsx | 98 +++++++++---------- .../olmap/HealthRiskAnalysis/Timeline.tsx | 12 +-- .../SchemeQuery.tsx | 2 +- src/components/olmap/SCADA/SCADADataPanel.tsx | 3 +- .../olmap/SCADA/SCADADeviceList.tsx | 2 +- .../olmap/core/Controls/BaseLayers.tsx | 9 +- .../olmap/core/Controls/HistoryDataPanel.tsx | 6 +- .../olmap/core/Controls/LayerControl.tsx | 30 +++--- .../olmap/core/Controls/StyleEditorPanel.tsx | 4 +- .../olmap/core/Controls/Timeline.tsx | 66 +++++++------ .../olmap/core/Controls/Toolbar.tsx | 5 +- src/components/olmap/core/MapComponent.tsx | 2 + src/contexts/ProjectContext.tsx | 42 ++++---- 19 files changed, 225 insertions(+), 200 deletions(-) diff --git a/next.config.mjs b/next.config.mjs index 427cf11..f07358f 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -1,6 +1,14 @@ /** @type {import('next').NextConfig} */ const nextConfig = { output: "standalone", + images: { + remotePatterns: [ + { + protocol: "https", + hostname: "refine.ams3.cdn.digitaloceanspaces.com", + }, + ], + }, turbopack: { rules: { "*.svg": { diff --git a/src/app/login/page.tsx b/src/app/login/page.tsx index ee6f578..089a9ed 100644 --- a/src/app/login/page.tsx +++ b/src/app/login/page.tsx @@ -1,5 +1,6 @@ "use client"; +import Image from "next/image"; import Box from "@mui/material/Box"; import Button from "@mui/material/Button"; import Container from "@mui/material/Container"; @@ -38,10 +39,12 @@ export default function Login() { Powered by - Keycloak Keycloak diff --git a/src/components/olmap/BurstSimulation/AnalysisParameters.tsx b/src/components/olmap/BurstSimulation/AnalysisParameters.tsx index 5482313..b39756a 100644 --- a/src/components/olmap/BurstSimulation/AnalysisParameters.tsx +++ b/src/components/olmap/BurstSimulation/AnalysisParameters.tsx @@ -61,6 +61,39 @@ const AnalysisParameters: React.FC = () => { duration > 0 && schemeName.trim() !== ""; + // 地图点击选择要素事件处理函数 + const handleMapClickSelectFeatures = useCallback( + async (event: { coordinate: number[] }) => { + if (!map) return; + const feature = await mapClickSelectFeatures(event, map); + const layer = feature?.getId()?.toString().split(".")[0]; + + if (!feature) return; + if ( + feature.getGeometry()?.getType() === "Point" || + (layer !== "geo_pipes_mat" && layer !== "geo_pipes") + ) { + open?.({ + type: "error", + message: "请选择线类型管道要素。", + }); + return; + } + const featureId = feature.getProperties().id; + setHighlightFeatures((prev) => { + const existingIndex = prev.findIndex( + (f) => f.getProperties().id === featureId, + ); + if (existingIndex !== -1) { + return prev.filter((_, i) => i !== existingIndex); + } else { + return [...prev, feature]; + } + }); + }, + [map, open], + ); + // 初始化管道图层和高亮图层 useEffect(() => { if (!map) return; @@ -137,7 +170,7 @@ const AnalysisParameters: React.FC = () => { map.removeLayer(highlightLayer); map.un("click", handleMapClickSelectFeatures); }; - }, [map]); + }, [map, handleMapClickSelectFeatures]); // 高亮要素的函数 useEffect(() => { if (!highlightLayer) { @@ -155,7 +188,7 @@ const AnalysisParameters: React.FC = () => { source.addFeature(feature); } }); - }, [highlightFeatures]); + }, [highlightFeatures, highlightLayer]); // 同步高亮要素和爆管点信息 useEffect(() => { @@ -185,42 +218,6 @@ const AnalysisParameters: React.FC = () => { }); }, [highlightFeatures]); - // 地图点击选择要素事件处理函数 - const handleMapClickSelectFeatures = useCallback( - async (event: { coordinate: number[] }) => { - if (!map) return; - const feature = await mapClickSelectFeatures(event, map); - const layer = feature?.getId()?.toString().split(".")[0]; - - if (!feature) return; - if ( - feature.getGeometry()?.getType() === "Point" || - (layer !== "geo_pipes_mat" && layer !== "geo_pipes") - ) { - // 点类型几何不处理 - open?.({ - type: "error", - message: "请选择线类型管道要素。", - }); - return; - } - const featureId = feature.getProperties().id; - setHighlightFeatures((prev) => { - const existingIndex = prev.findIndex( - (f) => f.getProperties().id === featureId, - ); - if (existingIndex !== -1) { - // 如果已存在,移除 - return prev.filter((_, i) => i !== existingIndex); - } else { - // 如果不存在,添加 - return [...prev, feature]; - } - }); - }, - [map], - ); - // 开始选择管道 const handleStartSelection = () => { if (!map) return; diff --git a/src/components/olmap/BurstSimulation/SchemeQuery.tsx b/src/components/olmap/BurstSimulation/SchemeQuery.tsx index 6256d16..65fce5c 100644 --- a/src/components/olmap/BurstSimulation/SchemeQuery.tsx +++ b/src/components/olmap/BurstSimulation/SchemeQuery.tsx @@ -299,7 +299,7 @@ const SchemeQuery: React.FC = ({ source.addFeature(feature); } }); - }, [highlightFeatures]); + }, [highlightFeatures, highlightLayer]); return ( <> diff --git a/src/components/olmap/ContaminantSimulation/AnalysisParameters.tsx b/src/components/olmap/ContaminantSimulation/AnalysisParameters.tsx index 8303e65..66f95ea 100644 --- a/src/components/olmap/ContaminantSimulation/AnalysisParameters.tsx +++ b/src/components/olmap/ContaminantSimulation/AnalysisParameters.tsx @@ -59,6 +59,32 @@ const AnalysisParameters: React.FC = () => { ); }, [network, startTime, sourceNode, concentration, duration, schemeName]); + const handleMapClickSelectFeatures = useCallback( + async (event: { coordinate: number[] }) => { + if (!map) return; + const feature = await mapClickSelectFeatures(event, map); + if (!feature) return; + + const layerId = feature.getId()?.toString().split(".")[0] || ""; + const isJunction = layerId.includes("junction"); + if (!isJunction) { + open?.({ + type: "error", + message: "请选择节点类型要素作为污染源。", + }); + return; + } + + const id = feature.getProperties().id; + if (!id) return; + setSourceNode(id); + setHighlightFeature(feature); + setIsSelecting(false); + map.un("click", handleMapClickSelectFeatures); + }, + [map, open], + ); + useEffect(() => { if (!map) return; @@ -106,7 +132,7 @@ const AnalysisParameters: React.FC = () => { map.removeLayer(layer); map.un("click", handleMapClickSelectFeatures); }; - }, [map]); + }, [map, handleMapClickSelectFeatures]); useEffect(() => { if (!highlightLayer) return; @@ -118,32 +144,6 @@ const AnalysisParameters: React.FC = () => { } }, [highlightFeature, highlightLayer]); - const handleMapClickSelectFeatures = useCallback( - async (event: { coordinate: number[] }) => { - if (!map) return; - const feature = await mapClickSelectFeatures(event, map); - if (!feature) return; - - const layerId = feature.getId()?.toString().split(".")[0] || ""; - const isJunction = layerId.includes("junction"); - if (!isJunction) { - open?.({ - type: "error", - message: "请选择节点类型要素作为污染源。", - }); - return; - } - - const id = feature.getProperties().id; - if (!id) return; - setSourceNode(id); - setHighlightFeature(feature); - setIsSelecting(false); - map.un("click", handleMapClickSelectFeatures); - }, - [map, open], - ); - const handleStartSelection = () => { if (!map) return; setIsSelecting(true); diff --git a/src/components/olmap/DMALeakDetection/DMALeakDetectionPanel.tsx b/src/components/olmap/DMALeakDetection/DMALeakDetectionPanel.tsx index 9dd5fd3..ec36d49 100644 --- a/src/components/olmap/DMALeakDetection/DMALeakDetectionPanel.tsx +++ b/src/components/olmap/DMALeakDetection/DMALeakDetectionPanel.tsx @@ -55,7 +55,7 @@ const DMALeakDetectionPanel: React.FC = () => { const drawerWidth = 450; const panelTitle = "DMA 漏损识别"; - const activeAreas = loadedResult?.areas ?? []; + const activeAreas = useMemo(() => loadedResult?.areas ?? [], [loadedResult]); const legendColors = useMemo( () => activeAreas.map((area) => getAreaColor(area.area_id)), [activeAreas], diff --git a/src/components/olmap/FlushingAnalysis/AnalysisParameters.tsx b/src/components/olmap/FlushingAnalysis/AnalysisParameters.tsx index 40dbb9f..b9e07e8 100644 --- a/src/components/olmap/FlushingAnalysis/AnalysisParameters.tsx +++ b/src/components/olmap/FlushingAnalysis/AnalysisParameters.tsx @@ -55,6 +55,54 @@ const AnalysisParameters: React.FC = () => { const [highlightLayer, setHighlightLayer] = useState | null>(null); + // Map click handler + const handleMapClickSelectFeatures = useCallback( + async (event: { coordinate: number[] }) => { + if (!map || selectionMode === 'none') return; + + const feature = await mapClickSelectFeatures(event, map); + if (!feature) return; + + const layer = feature.getId()?.toString().split(".")[0]; + const featureId = feature.getProperties().id; + + if (selectionMode === 'valve') { + if (layer !== 'geo_valves') { + open?.({ + type: "error", + message: "请选择阀门要素", + }); + return; + } + + setValves((prev) => { + if (prev.some((v) => v.id === featureId)) { + open?.({ + type: "error", + message: "该阀门已添加", + }); + return prev; + } + return [...prev, { id: featureId, k: 1.0, feature }]; + }); + + } else if (selectionMode === 'drainage') { + if (layer !== 'geo_junctions') { + open?.({ + type: "error", + message: "请选择节点要素作为排水点", + }); + return; + } + setDrainageNode(featureId); + setDrainageFeature(feature); + setSelectionMode('none'); + map.un("click", handleMapClickSelectFeatures); + } + }, + [map, selectionMode, open] + ); + // Initialize highlight layer useEffect(() => { if (!map) return; @@ -103,7 +151,7 @@ const AnalysisParameters: React.FC = () => { map.removeLayer(layer); map.un("click", handleMapClickSelectFeatures); }; - }, [map]); + }, [map, handleMapClickSelectFeatures]); // Update highlight layer features useEffect(() => { @@ -134,54 +182,6 @@ const AnalysisParameters: React.FC = () => { }, [highlightLayer, valves, drainageFeature]); - // Map click handler - const handleMapClickSelectFeatures = useCallback( - async (event: { coordinate: number[] }) => { - if (!map || selectionMode === 'none') return; - - const feature = await mapClickSelectFeatures(event, map); - if (!feature) return; - - const layer = feature.getId()?.toString().split(".")[0]; - const featureId = feature.getProperties().id; - - if (selectionMode === 'valve') { - if (layer !== 'geo_valves') { - open?.({ - type: "error", - message: "请选择阀门要素", - }); - return; - } - - setValves((prev) => { - if (prev.some((v) => v.id === featureId)) { - open?.({ - type: "error", - message: "该阀门已添加", - }); - return prev; - } - return [...prev, { id: featureId, k: 1.0, feature }]; // Default k=1.0? User can change. - }); - - } else if (selectionMode === 'drainage') { - if (layer !== 'geo_junctions') { - open?.({ - type: "error", - message: "请选择节点要素作为排水点", - }); - return; - } - setDrainageNode(featureId); - setDrainageFeature(feature); - setSelectionMode('none'); // Auto exit selection after picking one - map.un("click", handleMapClickSelectFeatures); - } - }, - [map, selectionMode, open] - ); - // Bind click event based on selection mode useEffect(() => { if (!map || selectionMode === "none") return; diff --git a/src/components/olmap/HealthRiskAnalysis/Timeline.tsx b/src/components/olmap/HealthRiskAnalysis/Timeline.tsx index a4f0bde..9d8742b 100644 --- a/src/components/olmap/HealthRiskAnalysis/Timeline.tsx +++ b/src/components/olmap/HealthRiskAnalysis/Timeline.tsx @@ -117,7 +117,7 @@ const Timeline: React.FC = ({ setCurrentYear(value); }, 500); // 500ms 防抖延迟 }, - [minTime, maxTime], + [minTime, maxTime, setCurrentYear], ); // 播放控制 @@ -133,7 +133,7 @@ const Timeline: React.FC = ({ }); }, playInterval); } - }, [isPlaying, playInterval]); + }, [isPlaying, playInterval, maxTime, minTime, setCurrentYear]); const handlePause = useCallback(() => { setIsPlaying(false); @@ -172,7 +172,7 @@ const Timeline: React.FC = ({ if (next < minTime) next += maxTime - minTime + 1; return next; }); - }, [minTime, maxTime]); + }, [minTime, maxTime, setCurrentYear]); const handleStepForward = useCallback(() => { setCurrentYear((prev: number) => { @@ -180,7 +180,7 @@ const Timeline: React.FC = ({ if (next > maxTime) next = minTime; return next; }); - }, [minTime, maxTime]); + }, [minTime, maxTime, setCurrentYear]); // 日期时间选择处理 const handleDateTimeChange = useCallback((newDate: Date | null) => { @@ -207,7 +207,7 @@ const Timeline: React.FC = ({ }, newInterval); } }, - [isPlaying], + [isPlaying, maxTime, minTime, setCurrentYear], ); // 组件加载时设置初始时间为当前时间的最近15分钟 @@ -372,7 +372,7 @@ const Timeline: React.FC = ({ if (predictionResults.length > 0 && pipeLayer) { applyPipeHealthStyle(); } - }, [applyPipeHealthStyle]); + }, [applyPipeHealthStyle, pipeLayer, predictionResults.length]); // 这里防止地图缩放时,瓦片重新加载引起的属性更新出错 useEffect(() => { diff --git a/src/components/olmap/MonitoringPlaceOptimization/SchemeQuery.tsx b/src/components/olmap/MonitoringPlaceOptimization/SchemeQuery.tsx index 23198b4..be17175 100644 --- a/src/components/olmap/MonitoringPlaceOptimization/SchemeQuery.tsx +++ b/src/components/olmap/MonitoringPlaceOptimization/SchemeQuery.tsx @@ -140,7 +140,7 @@ const SchemeQuery: React.FC = ({ source.addFeature(feature); } }); - }, [highlightFeatures]); + }, [highlightFeatures, highlightLayer]); // 查询方案 const handleQuery = async () => { diff --git a/src/components/olmap/SCADA/SCADADataPanel.tsx b/src/components/olmap/SCADA/SCADADataPanel.tsx index a788247..cf481f0 100644 --- a/src/components/olmap/SCADA/SCADADataPanel.tsx +++ b/src/components/olmap/SCADA/SCADADataPanel.tsx @@ -416,6 +416,7 @@ const SCADADataPanel: React.FC = ({ const hasDevices = deviceIds.length > 0; const hasData = timeSeries.length > 0; + const deviceIdsKey = useMemo(() => deviceIds.join(","), [deviceIds]); const dataset = useMemo( () => buildDataset(timeSeries, deviceIds, fractionDigits, showCleaning), @@ -528,7 +529,7 @@ const SCADADataPanel: React.FC = ({ } else { setTimeSeries([]); } - }, [deviceIds.join(",")]); + }, [deviceIdsKey, handleFetch, hasDevices]); // 当设备数量变化时,调整数据源选择 useEffect(() => { diff --git a/src/components/olmap/SCADA/SCADADeviceList.tsx b/src/components/olmap/SCADA/SCADADeviceList.tsx index 9626b1c..f93e2d4 100644 --- a/src/components/olmap/SCADA/SCADADeviceList.tsx +++ b/src/components/olmap/SCADA/SCADADeviceList.tsx @@ -741,7 +741,7 @@ const SCADADeviceList: React.FC = ({ source.addFeature(feature); } }); - }, [selectedDeviceIds, highlightFeatures]); + }, [selectedDeviceIds, highlightFeatures, highlightLayer]); // 清理定时器 useEffect(() => { return () => { diff --git a/src/components/olmap/core/Controls/BaseLayers.tsx b/src/components/olmap/core/Controls/BaseLayers.tsx index 03f2a76..244323f 100644 --- a/src/components/olmap/core/Controls/BaseLayers.tsx +++ b/src/components/olmap/core/Controls/BaseLayers.tsx @@ -1,4 +1,5 @@ import React, { useState, useEffect } from "react"; +import Image from "next/image"; import { useMap } from "../MapComponent"; import TileLayer from "ol/layer/Tile.js"; import XYZ from "ol/source/XYZ.js"; @@ -136,7 +137,7 @@ const BaseLayers: React.FC = () => { } layerInfo.layer.setVisible(layerInfo.id === activeId); }); - }, [map]); + }, [map, activeId]); const changeMapLayers = (id: string) => { if (map) { @@ -187,7 +188,7 @@ const BaseLayers: React.FC = () => { >