"use client"; import React, { useState, useRef, useEffect, useCallback } from "react"; import { Box, TextField, Button, Typography, IconButton, Stack, } from "@mui/material"; import { Close as CloseIcon } from "@mui/icons-material"; import { DateTimePicker } from "@mui/x-date-pickers/DateTimePicker"; import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider"; import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"; import dayjs, { Dayjs } from "dayjs"; import "dayjs/locale/zh-cn"; import { useMap } from "@app/OlMap/MapComponent"; import VectorLayer from "ol/layer/Vector"; import VectorSource from "ol/source/Vector"; import { Style, Stroke, Icon } from "ol/style"; import { handleMapClickSelectFeatures as mapClickSelectFeatures } from "@/utils/mapQueryService"; import Feature, { FeatureLike } from "ol/Feature"; import { useNotification } from "@refinedev/core"; import axios from "axios"; import { config, NETWORK_NAME } from "@/config/config"; import { along, lineString, length, toMercator } from "@turf/turf"; import { Point } from "ol/geom"; import { toLonLat } from "ol/proj"; interface PipePoint { id: string; diameter: number; area: number; feature?: any; // 存储管道要素用于高亮 } const AnalysisParameters: React.FC = () => { const map = useMap(); const { open, close } = useNotification(); const [pipePoints, setPipePoints] = useState([]); const [startTime, setStartTime] = useState(dayjs(new Date())); const [duration, setDuration] = useState(3600); const [schemeName, setSchemeName] = useState( "FANGAN" + new Date().getTime() ); const [network, setNetwork] = useState(NETWORK_NAME); const [isSelecting, setIsSelecting] = useState(false); const [highlightLayer, setHighlightLayer] = useState | null>(null); const [highlightFeatures, setHighlightFeatures] = useState([]); const [analyzing, setAnalyzing] = useState(false); // 检查是否所有必要参数都已填写 const isFormValid = pipePoints.length > 0 && startTime !== null && duration > 0 && schemeName.trim() !== ""; // 初始化管道图层和高亮图层 useEffect(() => { if (!map) return; const burstPipeStyle = function (feature: FeatureLike) { const styles = []; // 线条样式(底层发光,主线条,内层高亮线) styles.push( new Style({ stroke: new Stroke({ color: "rgba(255, 0, 0, 0.3)", width: 12, }), }), new Style({ stroke: new Stroke({ color: "rgba(255, 0, 0, 1)", width: 6, lineDash: [15, 10], }), }), new Style({ stroke: new Stroke({ color: "rgba(255, 102, 102, 1)", width: 3, lineDash: [15, 10], }), }) ); const geometry = feature.getGeometry(); const lineCoords = geometry?.getType() === "LineString" ? (geometry as any).getCoordinates() : null; if (geometry) { const lineCoordsWGS84 = lineCoords.map((coord: []) => { const [lon, lat] = toLonLat(coord); return [lon, lat]; }); // 计算中点 const lineStringFeature = lineString(lineCoordsWGS84); const lineLength = length(lineStringFeature); const midPoint = along(lineStringFeature, lineLength / 2).geometry .coordinates; // 在中点添加 icon 样式 const midPointMercator = toMercator(midPoint); styles.push( new Style({ geometry: new Point(midPointMercator), image: new Icon({ src: "/icons/burst_pipe.svg", scale: 0.2, anchor: [0.5, 1], }), }) ); } return styles; }; // 创建高亮图层 const highlightLayer = new VectorLayer({ source: new VectorSource(), style: burstPipeStyle, properties: { name: "高亮管道", value: "highlight_pipeline", }, }); map.addLayer(highlightLayer); setHighlightLayer(highlightLayer); return () => { map.removeLayer(highlightLayer); map.un("click", handleMapClickSelectFeatures); }; }, [map]); // 高亮要素的函数 useEffect(() => { if (!highlightLayer) { return; } const source = highlightLayer.getSource(); if (!source) { return; } // 清除之前的高亮 source.clear(); // 添加新的高亮要素 highlightFeatures.forEach((feature) => { if (feature instanceof Feature) { source.addFeature(feature); } }); }, [highlightFeatures]); // 同步高亮要素和爆管点信息 useEffect(() => { setPipePoints((prevPipes) => { // 移除不在highlightFeatures中的 const filtered = prevPipes.filter((pipe) => highlightFeatures.some( (feature) => feature.getProperties().id === pipe.id ) ); // 添加新的 const newPipes = highlightFeatures .filter( (feature) => !filtered.some((p) => p.id === feature.getProperties().id) ) .map((feature) => { const properties = feature.getProperties(); return { id: properties.id, diameter: properties.diameter || 0, area: 15, feature: feature, }; }); return [...filtered, ...newPipes]; }); }, [highlightFeatures]); // 地图点击选择要素事件处理函数 const handleMapClickSelectFeatures = useCallback( async (event: { coordinate: number[] }) => { if (!map) return; const feature = await mapClickSelectFeatures(event, map); if (!feature) return; if (feature.getGeometry()?.getType() === "Point") { // 点类型几何不处理 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; setIsSelecting(true); // 注册点击事件 map.on("click", handleMapClickSelectFeatures); }; // 结束选择管道 const handleEndSelection = () => { if (!map) return; setIsSelecting(false); // 移除点击事件 map.un("click", handleMapClickSelectFeatures); }; const handleRemovePipe = (id: string) => { // 从高亮features中移除 setHighlightFeatures((prev) => prev.filter((f) => f.getProperties().id !== id) ); }; const handleAreaChange = (id: string, value: string) => { const numValue = parseFloat(value) || 0; setPipePoints((prev) => prev.map((pipe) => (pipe.id === id ? { ...pipe, area: numValue } : pipe)) ); }; const handleAnalyze = async () => { setAnalyzing(true); // 显示处理中的通知 open?.({ key: "burst-analysis", type: "progress", message: "方案提交分析中", undoableTimeout: 3, }); const burst_ID = pipePoints.map((pipe) => pipe.id); const burst_size = pipePoints.map((pipe) => parseInt(pipe.area.toString(), 10) ); // 格式化开始时间,去除秒部分 const modify_pattern_start_time = startTime ? startTime.format("YYYY-MM-DDTHH:mm:00Z") : ""; const modify_total_duration = duration; const body = { name: network, modify_pattern_start_time: modify_pattern_start_time, burst_ID: burst_ID, burst_size: burst_size, modify_total_duration: modify_total_duration, scheme_Name: schemeName, }; try { await axios.post(`${config.backendUrl}/burst_analysis/`, body, { headers: { "Accept-Encoding": "gzip", "Content-Type": "application/json", }, }); // 更新弹窗为成功状态 open?.({ key: "burst-analysis", type: "success", message: "方案分析成功", description: "方案分析完成,请在方案查询中查看结果。", }); } catch (error) { console.error("分析请求失败:", error); // 更新弹窗为失败状态 open?.({ key: "burst-analysis", type: "error", message: "提交分析失败", description: error instanceof Error ? error.message : "请检查网络连接或稍后重试", }); } finally { setAnalyzing(false); } }; return ( {/* 选择爆管点 */} 选择爆管点 {/* 开始/结束选择按钮 */} {!isSelecting ? ( ) : ( )} {isSelecting && ( 💡 点击地图上的管道添加爆管点 )} {pipePoints.map((pipe) => ( {pipe.id} 管径: {pipe.diameter} mm 爆管点面积 handleAreaChange(pipe.id, e.target.value)} type="number" className="w-25" slotProps={{ input: { endAdornment: ( cm² ), }, }} /> handleRemovePipe(pipe.id)} className="ml-auto" > ))} {/* 选择开始时间 */} 选择开始时间 value && dayjs.isDayjs(value) && setStartTime(value) } format="YYYY-MM-DD HH:mm" slotProps={{ textField: { size: "small", fullWidth: true, }, }} /> {/* 持续时长 */} 持续时长 (秒) setDuration(parseInt(e.target.value) || 0)} placeholder="输入持续时长" /> {/* 方案名称 */} 方案名称 setSchemeName(e.target.value)} placeholder="输入方案名称" /> {/* 方案分析按钮 */} ); }; export default AnalysisParameters;