新增features多选模式

This commit is contained in:
JIANG
2025-12-19 16:27:59 +08:00
parent eb15100f4f
commit 3b4f7fd694

View File

@@ -12,12 +12,12 @@ import HistoryDataPanel from "./HistoryDataPanel"; // 引入绘图面板组件
import VectorSource from "ol/source/Vector"; import VectorSource from "ol/source/Vector";
import VectorLayer from "ol/layer/Vector"; import VectorLayer from "ol/layer/Vector";
import { Style, Stroke, Fill, Circle } from "ol/style"; import { Style, Stroke, Fill, Circle } from "ol/style";
import { FeatureLike } from "ol/Feature";
import Feature from "ol/Feature"; import Feature from "ol/Feature";
import StyleEditorPanel from "./StyleEditorPanel"; import StyleEditorPanel from "./StyleEditorPanel";
import { LayerStyleState } from "./StyleEditorPanel"; import { LayerStyleState } from "./StyleEditorPanel";
import StyleLegend from "./StyleLegend"; // 引入图例组件 import StyleLegend from "./StyleLegend"; // 引入图例组件
import { handleMapClickSelectFeatures as mapClickSelectFeatures } from "@/utils/mapQueryService"; import { handleMapClickSelectFeatures as mapClickSelectFeatures } from "@/utils/mapQueryService";
import { useNotification } from "@refinedev/core";
import { config } from "@/config/config"; import { config } from "@/config/config";
const backendUrl = config.BACKEND_URL; const backendUrl = config.BACKEND_URL;
@@ -35,12 +35,11 @@ const Toolbar: React.FC<ToolbarProps> = ({
}) => { }) => {
const map = useMap(); const map = useMap();
const data = useData(); const data = useData();
const { open } = useNotification();
if (!data) return null; if (!data) return null;
const { currentTime, selectedDate, schemeName } = data; const { currentTime, selectedDate, schemeName } = data;
const [activeTools, setActiveTools] = useState<string[]>([]); const [activeTools, setActiveTools] = useState<string[]>([]);
const [highlightFeature, setHighlightFeature] = useState<FeatureLike | null>( const [highlightFeatures, setHighlightFeatures] = useState<Feature[]>([]);
null
);
const [showPropertyPanel, setShowPropertyPanel] = useState<boolean>(false); const [showPropertyPanel, setShowPropertyPanel] = useState<boolean>(false);
const [showDrawPanel, setShowDrawPanel] = useState<boolean>(false); const [showDrawPanel, setShowDrawPanel] = useState<boolean>(false);
const [showStyleEditor, setShowStyleEditor] = useState<boolean>(false); const [showStyleEditor, setShowStyleEditor] = useState<boolean>(false);
@@ -56,7 +55,7 @@ const Toolbar: React.FC<ToolbarProps> = ({
layerName: "节点图层", layerName: "节点图层",
styleConfig: { styleConfig: {
property: "pressure", property: "pressure",
classificationMethod: "pretty_breaks", classificationMethod: "custom_breaks",
segments: 6, segments: 6,
minSize: 4, minSize: 4,
maxSize: 12, maxSize: 12,
@@ -175,18 +174,74 @@ const Toolbar: React.FC<ToolbarProps> = ({
// 清除之前的高亮 // 清除之前的高亮
source.clear(); source.clear();
// 添加新的高亮要素 // 添加新的高亮要素
if (highlightFeature instanceof Feature) { highlightFeatures.forEach((feature) => {
source.addFeature(highlightFeature); if (feature instanceof Feature) {
} source.addFeature(feature);
}, [highlightFeature]); }
});
}, [highlightFeatures, highlightLayer]);
// 地图点击选择要素事件处理函数 // 地图点击选择要素事件处理函数
const handleMapClickSelectFeatures = useCallback( const handleMapClickSelectFeatures = useCallback(
async (event: { coordinate: number[] }) => { async (event: { coordinate: number[] }) => {
if (!map) return; if (!map) return;
const feature = await mapClickSelectFeatures(event, map); // 调用导入的函数 const feature = await mapClickSelectFeatures(event, map); // 调用导入的函数
setHighlightFeature(feature); if (!feature || !(feature instanceof Feature)) return;
if (activeTools.includes("history")) {
// 历史查询模式:支持同类型多选
const featureId = feature.getProperties().id;
const layerId = feature.getId()?.toString().split(".")[0] || "";
// 简单的类型检查函数
const getBaseType = (lid: string) => {
if (lid.includes("pipe")) return "pipe";
if (lid.includes("junction")) return "junction";
if (lid.includes("tank")) return "tank";
if (lid.includes("reservoir")) return "reservoir";
if (lid.includes("pump")) return "pump";
if (lid.includes("valve")) return "valve";
return lid;
};
// 检查是否与已选要素类型一致
if (highlightFeatures.length > 0) {
const firstLayerId =
highlightFeatures[0].getId()?.toString().split(".")[0] || "";
if (getBaseType(layerId) !== getBaseType(firstLayerId)) {
// 如果点击的是已选中的要素(为了取消选中),则不报错
const isAlreadySelected = highlightFeatures.some(
(f) => f.getProperties().id === featureId
);
if (!isAlreadySelected) {
open?.({
type: "error",
message: "请选择相同类型的要素进行多选查询。",
});
return;
}
}
}
setHighlightFeatures((prev) => {
const existingIndex = prev.findIndex(
(f) => f.getProperties().id === featureId
);
if (existingIndex !== -1) {
// 如果已存在,移除
return prev.filter((_, i) => i !== existingIndex);
} else {
// 如果不存在,添加
return [...prev, feature];
}
});
} else {
// 其他模式(如 info单选
setHighlightFeatures([feature]);
}
}, },
[map, setHighlightFeature] [map, activeTools, highlightFeatures, open]
); );
// 添加矢量属性查询事件监听器 // 添加矢量属性查询事件监听器
useEffect(() => { useEffect(() => {
@@ -243,13 +298,14 @@ const Toolbar: React.FC<ToolbarProps> = ({
switch (tool) { switch (tool) {
case "info": case "info":
setShowPropertyPanel(false); setShowPropertyPanel(false);
setHighlightFeature(null); setHighlightFeatures([]);
break; break;
case "draw": case "draw":
setShowDrawPanel(false); setShowDrawPanel(false);
break; break;
case "history": case "history":
setShowHistoryPanel(false); setShowHistoryPanel(false);
setHighlightFeatures([]);
break; break;
} }
}; };
@@ -273,7 +329,7 @@ const Toolbar: React.FC<ToolbarProps> = ({
// 关闭所有面板(除了样式编辑器) // 关闭所有面板(除了样式编辑器)
const closeAllPanelsExceptStyle = () => { const closeAllPanelsExceptStyle = () => {
setShowPropertyPanel(false); setShowPropertyPanel(false);
setHighlightFeature(null); setHighlightFeatures([]);
setShowDrawPanel(false); setShowDrawPanel(false);
setShowHistoryPanel(false); setShowHistoryPanel(false);
// 样式编辑器保持其当前状态,不自动关闭 // 样式编辑器保持其当前状态,不自动关闭
@@ -283,11 +339,12 @@ const Toolbar: React.FC<ToolbarProps> = ({
>({}); >({});
// 添加 useEffect 来查询计算属性 // 添加 useEffect 来查询计算属性
useEffect(() => { useEffect(() => {
if (!highlightFeature || !selectedDate || !showPropertyPanel) { if (highlightFeatures.length === 0 || !selectedDate || !showPropertyPanel) {
setComputedProperties({}); setComputedProperties({});
return; return;
} }
const highlightFeature = highlightFeatures[0];
const id = highlightFeature.getProperties().id; const id = highlightFeature.getProperties().id;
if (!id) { if (!id) {
setComputedProperties({}); setComputedProperties({});
@@ -334,11 +391,12 @@ const Toolbar: React.FC<ToolbarProps> = ({
}; };
// 仅当 currentTime 有效时查询 // 仅当 currentTime 有效时查询
if (currentTime !== -1 && queryType) queryComputedProperties(); if (currentTime !== -1 && queryType) queryComputedProperties();
}, [highlightFeature, currentTime, selectedDate]); }, [highlightFeatures, currentTime, selectedDate]);
// 从要素属性中提取属性面板需要的数据 // 从要素属性中提取属性面板需要的数据
const getFeatureProperties = useCallback(() => { const getFeatureProperties = useCallback(() => {
if (!highlightFeature) return {}; if (highlightFeatures.length === 0) return {};
const highlightFeature = highlightFeatures[0];
const layer = highlightFeature?.getId()?.toString().split(".")[0]; const layer = highlightFeature?.getId()?.toString().split(".")[0];
const properties = highlightFeature.getProperties(); const properties = highlightFeature.getProperties();
// 计算属性字段,增加 key 字段 // 计算属性字段,增加 key 字段
@@ -613,7 +671,7 @@ const Toolbar: React.FC<ToolbarProps> = ({
return result; return result;
} }
return {}; return {};
}, [highlightFeature, computedProperties]); }, [highlightFeatures, computedProperties]);
return ( return (
<> <>
@@ -663,34 +721,40 @@ const Toolbar: React.FC<ToolbarProps> = ({
(HistoryPanel ? ( (HistoryPanel ? (
<HistoryPanel <HistoryPanel
featureInfos={(() => { featureInfos={(() => {
if (!highlightFeature || !showHistoryPanel) return []; if (highlightFeatures.length === 0 || !showHistoryPanel)
const properties = highlightFeature.getProperties();
const id = properties.id;
if (!id) return [];
// 从图层名称推断类型
const layerId =
highlightFeature.getId()?.toString().split(".")[0] || "";
let type = "unknown";
if (layerId.includes("pipe")) {
type = "pipe";
} else if (layerId.includes("junction")) {
type = "junction";
} else if (layerId.includes("tank")) {
type = "tank";
} else if (layerId.includes("reservoir")) {
type = "reservoir";
} else if (layerId.includes("pump")) {
type = "pump";
} else if (layerId.includes("valve")) {
type = "valve";
}
// 仅处理 type 为 pipe 或 junction 的情况
if (type !== "pipe" && type !== "junction") {
return []; return [];
}
return [[id, type]]; return highlightFeatures
.map((feature) => {
const properties = feature.getProperties();
const id = properties.id;
if (!id) return null;
// 从图层名称推断类型
const layerId =
feature.getId()?.toString().split(".")[0] || "";
let type = "unknown";
if (layerId.includes("pipe")) {
type = "pipe";
} else if (layerId.includes("junction")) {
type = "junction";
} else if (layerId.includes("tank")) {
type = "tank";
} else if (layerId.includes("reservoir")) {
type = "reservoir";
} else if (layerId.includes("pump")) {
type = "pump";
} else if (layerId.includes("valve")) {
type = "valve";
}
// 仅处理 type 为 pipe 或 junction 的情况
if (type !== "pipe" && type !== "junction") {
return null;
}
return [id, type];
})
.filter(Boolean) as [string, string][];
})()} })()}
scheme_type="burst_Analysis" scheme_type="burst_Analysis"
scheme_name={schemeName} scheme_name={schemeName}
@@ -699,34 +763,40 @@ const Toolbar: React.FC<ToolbarProps> = ({
) : ( ) : (
<HistoryDataPanel <HistoryDataPanel
featureInfos={(() => { featureInfos={(() => {
if (!highlightFeature || !showHistoryPanel) return []; if (highlightFeatures.length === 0 || !showHistoryPanel)
const properties = highlightFeature.getProperties();
const id = properties.id;
if (!id) return [];
// 从图层名称推断类型
const layerId =
highlightFeature.getId()?.toString().split(".")[0] || "";
let type = "unknown";
if (layerId.includes("pipe")) {
type = "pipe";
} else if (layerId.includes("junction")) {
type = "junction";
} else if (layerId.includes("tank")) {
type = "tank";
} else if (layerId.includes("reservoir")) {
type = "reservoir";
} else if (layerId.includes("pump")) {
type = "pump";
} else if (layerId.includes("valve")) {
type = "valve";
}
// 仅处理 type 为 pipe 或 junction 的情况
if (type !== "pipe" && type !== "junction") {
return []; return [];
}
return [[id, type]]; return highlightFeatures
.map((feature) => {
const properties = feature.getProperties();
const id = properties.id;
if (!id) return null;
// 从图层名称推断类型
const layerId =
feature.getId()?.toString().split(".")[0] || "";
let type = "unknown";
if (layerId.includes("pipe")) {
type = "pipe";
} else if (layerId.includes("junction")) {
type = "junction";
} else if (layerId.includes("tank")) {
type = "tank";
} else if (layerId.includes("reservoir")) {
type = "reservoir";
} else if (layerId.includes("pump")) {
type = "pump";
} else if (layerId.includes("valve")) {
type = "valve";
}
// 仅处理 type 为 pipe 或 junction 的情况
if (type !== "pipe" && type !== "junction") {
return null;
}
return [id, type];
})
.filter(Boolean) as [string, string][];
})()} })()}
scheme_type="burst_Analysis" scheme_type="burst_Analysis"
scheme_name={schemeName} scheme_name={schemeName}