新增点击地图选中设备,查看历史数据的功能

This commit is contained in:
JIANG
2025-10-31 18:22:38 +08:00
parent d4f8b9fd32
commit 72e046de10

View File

@@ -37,11 +37,14 @@ import {
FilterList,
Clear,
DeviceHub,
TouchApp,
} from "@mui/icons-material";
import { FixedSizeList } from "react-window";
import { useNotification } from "@refinedev/core";
import { useMap } from "@app/OlMap/MapComponent";
import { GeoJSON } from "ol/format";
import { handleMapClickSelectFeatures as mapClickSelectFeatures } from "@/utils/mapQueryService";
import VectorLayer from "ol/layer/Vector";
import VectorSource from "ol/source/Vector";
import { Stroke, Style, Circle, Fill } from "ol/style";
@@ -95,6 +98,7 @@ const SCADADeviceList: React.FC<SCADADeviceListProps> = ({
const [selectedStatus, setSelectedStatus] = useState<string>("all");
const [selectedReliability, setSelectedReliability] = useState<string>("all");
const [isExpanded, setIsExpanded] = useState<boolean>(true);
const [isSelecting, setIsSelecting] = useState<boolean>(false);
const [internalSelection, setInternalSelection] = useState<string[]>([]);
const [pendingSelection, setPendingSelection] = useState<string[] | null>(
null
@@ -106,7 +110,6 @@ const SCADADeviceList: React.FC<SCADADeviceListProps> = ({
const [highlightLayer, setHighlightLayer] =
useState<VectorLayer<VectorSource> | null>(null);
const [highlightFeatures, setHighlightFeatures] = useState<Feature[]>([]);
const [blinkingFeature, setBlinkingFeature] = useState<Feature | null>(null);
const blinkListenerKeyRef = useRef<any>(null);
const debounceTimerRef = useRef<NodeJS.Timeout | null>(null);
@@ -125,7 +128,8 @@ const SCADADeviceList: React.FC<SCADADeviceListProps> = ({
const activeSelection = selectedDeviceIds ?? internalSelection;
const map = useMap(); // 移到此处确保在条件检查前调用
const map = useMap(); // 移到此处,确保在条件检查前调用
const { open } = useNotification();
useEffect(() => {
if (selectedDeviceIds) {
@@ -323,7 +327,6 @@ const SCADADeviceList: React.FC<SCADADeviceListProps> = ({
const blinkFeature = new Feature({
geometry: new Point(coordinates),
});
setBlinkingFeature(blinkFeature);
const duration = 2000; // 闪烁持续时间
const start = Date.now();
@@ -334,7 +337,6 @@ const SCADADeviceList: React.FC<SCADADeviceListProps> = ({
if (elapsed > duration) {
// 动画结束
unByKey(listenerKey);
setBlinkingFeature(null);
blinkListenerKeyRef.current = null;
map.render(); // 最后渲染一次以清除效果
return;
@@ -435,6 +437,91 @@ const SCADADeviceList: React.FC<SCADADeviceListProps> = ({
setPendingSelection([]);
}, []);
// 地图点击选择 SCADA 设备事件处理函数
const handleMapClickSelectFeatures = useCallback(
async (event: { coordinate: number[] }) => {
if (!map) return;
const feature = await mapClickSelectFeatures(event, map);
const layer = feature?.getId()?.toString().split(".")[0];
if (!feature) return;
if (layer !== "geo_scada_mat" && layer !== "geo_scada") {
open?.({
type: "error",
message: "请选择 SCADA 设备。",
});
return;
}
const featureId = feature.getProperties().id;
// 在设备列表中查找对应的设备
const device = effectiveDevices.find((d) => d.id === featureId);
if (!device) {
open?.({
type: "error",
message: "未找到对应的 SCADA 设备。",
});
return;
}
// 更新选择状态
setInternalSelection((prev) => {
const exists = prev.includes(featureId);
const nextSelection = multiSelect
? exists
? prev.filter((id) => id !== featureId)
: [...prev, featureId]
: exists
? []
: [featureId];
setPendingSelection(nextSelection);
return nextSelection;
});
// 更新高亮要素
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, effectiveDevices, multiSelect, open]
);
// 开始选择 SCADA 设备
const handleStartSelection = useCallback(() => {
if (!map) return;
setIsSelecting(true);
// 注册点击事件
map.on("click", handleMapClickSelectFeatures);
}, [map, handleMapClickSelectFeatures]);
// 结束选择 SCADA 设备
const handleEndSelection = useCallback(() => {
if (!map) return;
setIsSelecting(false);
// 移除点击事件
map.un("click", handleMapClickSelectFeatures);
}, [map, handleMapClickSelectFeatures]);
// 组件卸载时清理地图事件
useEffect(() => {
return () => {
if (map && isSelecting) {
map.un("click", handleMapClickSelectFeatures);
}
};
}, [map, isSelecting, handleMapClickSelectFeatures]);
// 初始化管道图层和高亮图层
useEffect(() => {
if (!map) return;
@@ -635,12 +722,35 @@ const SCADADeviceList: React.FC<SCADADeviceListProps> = ({
</Stack>
{/* 筛选结果统计 */}
<Stack direction="row" alignItems="center" spacing={2}>
<Typography variant="caption" color="text.secondary">
{filteredDevices.length}
{devices.length !== filteredDevices.length &&
` (共 ${effectiveDevices.length} 个设备)`}
</Typography>
{/* 地图选择按钮 */}
<Tooltip title={isSelecting ? "结束地图选择" : "从地图选择设备"}>
<IconButton
size="small"
color={isSelecting ? "primary" : "default"}
onClick={
isSelecting ? handleEndSelection : handleStartSelection
}
sx={{
border: 1,
borderColor: isSelecting ? "primary.main" : "divider",
backgroundColor: isSelecting ? "primary.50" : "transparent",
"&:hover": {
backgroundColor: isSelecting ? "primary.100" : "grey.100",
},
}}
>
<TouchApp fontSize="small" />
</IconButton>
</Tooltip>
</Stack>
{/* 清除选择按钮 */}
{activeSelection.length > 0 && (
<Box sx={{ display: "flex", alignItems: "center", gap: 1 }}>