完善爆管分析面板;整合地图查询函数

This commit is contained in:
JIANG
2025-10-23 11:59:45 +08:00
parent 720f8a5dc2
commit ad893ac19d
7 changed files with 1185 additions and 899 deletions

View File

@@ -1,6 +1,6 @@
"use client";
import React, { useState, useRef, useEffect } from "react";
import React, { useState, useRef, useEffect, useCallback } from "react";
import {
Box,
TextField,
@@ -20,12 +20,11 @@ import VectorLayer from "ol/layer/Vector";
import VectorSource from "ol/source/Vector";
import Style from "ol/style/Style";
import Stroke from "ol/style/Stroke";
import GeoJson from "ol/format/GeoJSON";
import config from "@config/config";
import type { Feature } from "ol";
import type { Geometry } from "ol/geom";
const mapUrl = config.mapUrl;
import { handleMapClickSelectFeatures as mapClickSelectFeatures } from "@/utils/mapQueryService";
import Feature from "ol/Feature";
import { useNotification } from "@refinedev/core";
import axios from "axios";
import { config, NETWORK_NAME } from "@/config/config";
interface PipePoint {
id: string;
@@ -34,36 +33,23 @@ interface PipePoint {
feature?: any; // 存储管道要素用于高亮
}
interface AnalysisParametersProps {
onAnalyze?: (params: AnalysisParams) => void;
}
interface AnalysisParams {
pipePoints: PipePoint[];
startTime: Dayjs | null;
duration: number;
schemeName: string;
}
const AnalysisParameters: React.FC<AnalysisParametersProps> = ({
onAnalyze,
}) => {
const AnalysisParameters: React.FC = () => {
const map = useMap();
const { open, close } = useNotification();
const [pipePoints, setPipePoints] = useState<PipePoint[]>([
{ id: "541022", diameter: 110, area: 15 },
{ id: "532748", diameter: 110, area: 15 },
]);
const [startTime, setStartTime] = useState<Dayjs | null>(
dayjs("2025-10-21T00:00:00")
);
const [pipePoints, setPipePoints] = useState<PipePoint[]>([]);
const [startTime, setStartTime] = useState<Dayjs | null>(dayjs(new Date()));
const [duration, setDuration] = useState<number>(3000);
const [schemeName, setSchemeName] = useState<string>("Fangan1021100506");
const [schemeName, setSchemeName] = useState<string>(
"FANGAN" + new Date().getTime()
);
const [network, setNetwork] = useState<string>(NETWORK_NAME);
const [isSelecting, setIsSelecting] = useState<boolean>(false);
const highlightLayerRef = useRef<VectorLayer<VectorSource> | null>(null);
const clickListenerRef = useRef<((evt: any) => void) | null>(null);
const [highlightLayer, setHighlightLayer] =
useState<VectorLayer<VectorSource> | null>(null);
const [highlightFeatures, setHighlightFeatures] = useState<Feature[]>([]);
const [analyzing, setAnalyzing] = useState<boolean>(false);
// 初始化管道图层和高亮图层
useEffect(() => {
if (!map) return;
@@ -71,80 +57,130 @@ const AnalysisParameters: React.FC<AnalysisParametersProps> = ({
// 创建高亮图层
const highlightLayer = new VectorLayer({
source: new VectorSource(),
style: new Style({
stroke: new Stroke({
color: "#ff0000",
width: 5,
style: [
// 外层发光效果(底层)
new Style({
stroke: new Stroke({
color: "rgba(255, 0, 0, 0.3)",
width: 12,
}),
}),
}),
// 主线条 - 使用虚线表示爆管
new Style({
stroke: new Stroke({
color: "#ff0000",
width: 6,
lineDash: [15, 10], // 虚线样式,表示管道损坏/爆管
}),
}),
// 内层高亮线
new Style({
stroke: new Stroke({
color: "#ff6666",
width: 3,
lineDash: [15, 10],
}),
}),
],
properties: {
name: "高亮管道",
value: "highlight_pipeline",
},
zIndex: 999,
});
map.addLayer(highlightLayer);
highlightLayerRef.current = highlightLayer;
setHighlightLayer(highlightLayer);
return () => {
map.removeLayer(highlightLayer);
if (clickListenerRef.current) {
map.un("click", clickListenerRef.current);
}
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();
console.log("管道属性:", feature, properties);
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);
// 显示管道图层
// 注册点击事件
const clickListener = (evt: any) => {
let clickedFeature: any = null;
map.forEachFeatureAtPixel(
evt.pixel,
(feature) => {
if (!clickedFeature) {
clickedFeature = feature;
}
return true;
},
{ hitTolerance: 5 }
);
if (clickedFeature) {
const properties = clickedFeature.getProperties();
const pipeId = properties.Id || properties.id || properties.ID;
const diameter = properties.Diameter || properties.diameter || 100;
// 检查是否已存在
const exists = pipePoints.some((pipe) => pipe.id === pipeId);
if (!exists && pipeId) {
const newPipe: PipePoint = {
id: String(pipeId),
diameter: Number(diameter),
area: 15,
feature: clickedFeature,
};
setPipePoints((prev) => [...prev, newPipe]);
// 添加到高亮图层
const highlightSource = highlightLayerRef.current?.getSource();
if (highlightSource) {
highlightSource.addFeature(clickedFeature);
}
}
}
};
clickListenerRef.current = clickListener;
map.on("click", clickListener);
map.on("click", handleMapClickSelectFeatures);
};
// 结束选择管道
@@ -154,26 +190,14 @@ const AnalysisParameters: React.FC<AnalysisParametersProps> = ({
setIsSelecting(false);
// 移除点击事件
if (clickListenerRef.current) {
map.un("click", clickListenerRef.current);
clickListenerRef.current = null;
}
map.un("click", handleMapClickSelectFeatures);
};
const handleRemovePipe = (id: string) => {
// 找到要删除的管道
const pipeToRemove = pipePoints.find((pipe) => pipe.id === id);
// 从高亮图层中移除对应的要素
if (pipeToRemove && pipeToRemove.feature && highlightLayerRef.current) {
const highlightSource = highlightLayerRef.current.getSource();
if (highlightSource) {
highlightSource.removeFeature(pipeToRemove.feature);
}
}
// 从状态中移除
setPipePoints((prev) => prev.filter((pipe) => pipe.id !== id));
// 从高亮features中移除
setHighlightFeatures((prev) =>
prev.filter((f) => f.getProperties().id !== id)
);
};
const handleAreaChange = (id: string, value: string) => {
@@ -183,14 +207,55 @@ const AnalysisParameters: React.FC<AnalysisParametersProps> = ({
);
};
const handleAnalyze = () => {
if (onAnalyze) {
onAnalyze({
pipePoints,
startTime,
duration,
schemeName,
const handleAnalyze = async () => {
setAnalyzing(true);
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:ssZ")
: "";
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);
}
};
@@ -339,7 +404,7 @@ const AnalysisParameters: React.FC<AnalysisParametersProps> = ({
</Box>
{/* 方案名称 */}
<Box className="mb-6">
<Box className="mb-4">
<Typography variant="subtitle2" className="mb-2 font-medium">
</Typography>
@@ -359,9 +424,10 @@ const AnalysisParameters: React.FC<AnalysisParametersProps> = ({
variant="contained"
size="large"
onClick={handleAnalyze}
disabled={analyzing}
className="bg-blue-600 hover:bg-blue-700"
>
{analyzing ? "方案提交中..." : "方案分析"}
</Button>
</Box>
</Box>