"use client"; import React, { useState, useEffect, useRef } from "react"; import { Box, Typography, Chip, IconButton, Tooltip, Link, } from "@mui/material"; import { LocationOn as LocationIcon, } from "@mui/icons-material"; import { queryFeaturesByIds } from "@/utils/mapQueryService"; import { useMap } from "@components/olmap/core/MapComponent"; import { GeoJSON } from "ol/format"; import VectorLayer from "ol/layer/Vector"; import VectorSource from "ol/source/Vector"; import { Stroke, Style, Icon } from "ol/style"; import Feature, { FeatureLike } from "ol/Feature"; import { along, lineString, length, toMercator, bbox, featureCollection, } from "@turf/turf"; import { Point } from "ol/geom"; import { toLonLat } from "ol/proj"; import moment from "moment"; import "moment-timezone"; import { LocationResult } from "./types"; import { FLOW_DISPLAY_UNIT } from "@utils/units"; interface LocationResultsProps { results?: LocationResult[]; } const LocationResults: React.FC = ({ results = [], }) => { const highlightLayerRef = useRef | null>(null); const [highlightFeatures, setHighlightFeatures] = useState([]); const map = useMap(); // 格式化时间为 UTC+8 const formatTime = (timeStr: string) => { return moment(timeStr).utcOffset(8).format("YYYY-MM-DD HH:mm:ss"); }; const handleLocatePipes = (pipeIds: string[]) => { if (pipeIds.length > 0) { queryFeaturesByIds(pipeIds, "geo_pipes_mat").then((features) => { if (features.length > 0) { // 设置高亮要素 setHighlightFeatures(features); // 将 OpenLayers Feature 转换为 GeoJSON Feature const geojsonFormat = new GeoJSON(); const geojsonFeatures = features.map((feature) => geojsonFormat.writeFeatureObject(feature), ); const extent = bbox(featureCollection(geojsonFeatures as any)); if (extent) { map?.getView().fit(extent, { maxZoom: 18, duration: 1000 }); } } }); } }; // 初始化管道图层和高亮图层 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 && lineCoords) { 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, maxZoom: 24, minZoom: 12, properties: { name: "爆管管段高亮", value: "burst_pipe_highlight", }, }); map.addLayer(highlightLayer); highlightLayerRef.current = highlightLayer; return () => { highlightLayerRef.current = null; map.removeLayer(highlightLayer); }; }, [map]); // 高亮要素的函数 useEffect(() => { const source = highlightLayerRef.current?.getSource(); if (!source) { return; } // 清除之前的高亮 source.clear(); // 添加新的高亮要素 highlightFeatures.forEach((feature) => { if (feature instanceof Feature) { source.addFeature(feature); } }); }, [highlightFeatures]); // 取第一条记录或空对象 const result = results.length > 0 ? results[0] : null; return ( {/* 结果展示 */} {!result ? ( 暂无定位结果 请先执行方案分析 ) : ( {/* 头部:标识信息 */} {result.burst_incident} ID: {result.id} {/* 主要信息:三栏卡片布局 */} {/* 检测时间卡片 */} 检测时间 {formatTime(result.detect_time)} {/* 漏损量卡片 */} 漏损量 {result.leakage !== null ? `${result.leakage.toFixed(2)} ${FLOW_DISPLAY_UNIT}` : "N/A"} {/* 定位管段数量卡片 */} 定位管段 {result.locate_result ? result.locate_result.length : 0}{" "} 个管段 {/* 定位管段详细列表 */} {result.locate_result && result.locate_result.length > 0 && ( 管段列表 handleLocatePipes(result.locate_result!)} color="primary" sx={{ backgroundColor: "rgba(37, 125, 212, 0.1)", "&:hover": { backgroundColor: "rgba(37, 125, 212, 0.2)", }, }} > {result.locate_result.map((pipeId, idx) => ( handleLocatePipes([pipeId])} sx={{ "&:active": { transform: "scale(0.98)", boxShadow: "0 1px 2px rgba(25, 118, 210, 0.2)", }, }} > {pipeId} {/* { e.stopPropagation(); handleLocatePipes([pipeId]); }} sx={{ "&:hover": { backgroundColor: "rgba(37, 125, 212, 0.1)", }, }} > */} ))} )} )} ); }; export default LocationResults;