新增features多选模式
This commit is contained in:
@@ -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}
|
||||||
|
|||||||
Reference in New Issue
Block a user