新增点击地图选中设备,查看历史数据的功能
This commit is contained in:
@@ -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 }}>
|
||||
|
||||
Reference in New Issue
Block a user