feat(sensor): 完善监测点结果编辑与图层切换
This commit is contained in:
@@ -45,10 +45,7 @@ import Point from "ol/geom/Point";
|
||||
import VectorLayer from "ol/layer/Vector";
|
||||
import VectorSource from "ol/source/Vector";
|
||||
import { Circle, Fill, Stroke, Style, Text } from "ol/style";
|
||||
import { fromLonLat, toLonLat } from "ol/proj";
|
||||
import { useNotification } from "@refinedev/core";
|
||||
import { api } from "@/lib/api";
|
||||
import { config } from "@/config/config";
|
||||
import { useMap } from "@components/olmap/core/MapComponent";
|
||||
import { handleMapClickSelectFeatures } from "@/utils/mapQueryService";
|
||||
import {
|
||||
@@ -65,6 +62,7 @@ import {
|
||||
} from "./schemeEditor";
|
||||
import {
|
||||
exportSensorPlacementExcel,
|
||||
getSensorPlacementCandidate,
|
||||
overwriteSensorPlacementScheme,
|
||||
} from "./schemeApi";
|
||||
import SchemeDrawingDialog from "./SchemeDrawingDialog";
|
||||
@@ -147,6 +145,8 @@ const SchemeEditor: React.FC<SchemeEditorProps> = ({
|
||||
const [saveDialogOpen, setSaveDialogOpen] = useState(false);
|
||||
const [drawingOpen, setDrawingOpen] = useState(false);
|
||||
const markerLayerRef = useRef<VectorLayer<VectorSource> | null>(null);
|
||||
const activeRef = useRef(active);
|
||||
activeRef.current = active;
|
||||
|
||||
useEffect(() => {
|
||||
setEditor(createSchemeEditorState(scheme));
|
||||
@@ -171,6 +171,7 @@ const SchemeEditor: React.FC<SchemeEditorProps> = ({
|
||||
},
|
||||
zIndex: 120,
|
||||
});
|
||||
layer.setVisible(activeRef.current);
|
||||
markerLayerRef.current = layer;
|
||||
map.addLayer(layer);
|
||||
return () => {
|
||||
@@ -206,47 +207,8 @@ const SchemeEditor: React.FC<SchemeEditorProps> = ({
|
||||
const feature = await handleMapClickSelectFeatures(event, map);
|
||||
const nodeId = String(feature?.get("id") ?? feature?.getId() ?? "").trim();
|
||||
if (!nodeId) return null;
|
||||
const featureGeometry = feature?.getGeometry();
|
||||
const featureCoordinate =
|
||||
featureGeometry instanceof Point
|
||||
? featureGeometry.getCoordinates()
|
||||
: event.coordinate;
|
||||
const projectedFeatureCoordinate =
|
||||
Math.abs(featureCoordinate[0]) <= 180 &&
|
||||
Math.abs(featureCoordinate[1]) <= 90
|
||||
? fromLonLat(featureCoordinate)
|
||||
: featureCoordinate;
|
||||
const resolution = map.getView().getResolution() ?? 1;
|
||||
const isAlignedWithMap =
|
||||
Math.hypot(
|
||||
projectedFeatureCoordinate[0] - event.coordinate[0],
|
||||
projectedFeatureCoordinate[1] - event.coordinate[1],
|
||||
) <=
|
||||
resolution * 20;
|
||||
const [mapX, mapY] = isAlignedWithMap
|
||||
? projectedFeatureCoordinate
|
||||
: event.coordinate;
|
||||
try {
|
||||
const response = await api.get<{
|
||||
id: string;
|
||||
x: number;
|
||||
y: number;
|
||||
elevation: number;
|
||||
}>(`${config.BACKEND_URL}/api/v1/junctions/properties`, {
|
||||
params: { junction: nodeId },
|
||||
});
|
||||
if (!response.data?.id) return null;
|
||||
const [longitude, latitude] = toLonLat([mapX, mapY]);
|
||||
return {
|
||||
node_id: String(response.data.id),
|
||||
project_x: Number(response.data.x),
|
||||
project_y: Number(response.data.y),
|
||||
map_x: mapX,
|
||||
map_y: mapY,
|
||||
longitude,
|
||||
latitude,
|
||||
elevation: Number(response.data.elevation),
|
||||
};
|
||||
return await getSensorPlacementCandidate(nodeId);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
@@ -436,6 +398,70 @@ const SchemeEditor: React.FC<SchemeEditorProps> = ({
|
||||
|
||||
const columns = useMemo<GridColDef<SensorPointRow>[]>(
|
||||
() => [
|
||||
{
|
||||
field: "actions",
|
||||
headerName: "操作",
|
||||
width: scheme.can_edit ? 138 : 54,
|
||||
sortable: false,
|
||||
filterable: false,
|
||||
renderCell: ({ row }) => (
|
||||
<Stack direction="row" spacing={0.25} sx={{ alignItems: "center" }}>
|
||||
<Tooltip title="地图定位">
|
||||
<IconButton
|
||||
aria-label={`定位节点 ${row.node_id}`}
|
||||
size="small"
|
||||
onClick={() => locateRow(row)}
|
||||
sx={{ width: 40, height: 40 }}
|
||||
>
|
||||
<LocateIcon fontSize="small" />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
{scheme.can_edit && (
|
||||
<>
|
||||
<Tooltip title="替换节点">
|
||||
<IconButton
|
||||
aria-label={`替换节点 ${row.node_id}`}
|
||||
size="small"
|
||||
onClick={() => activateMode("replace", row.node_id)}
|
||||
sx={{ width: 40, height: 40 }}
|
||||
>
|
||||
<ReplaceIcon fontSize="small" />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title="删除节点">
|
||||
<span>
|
||||
<IconButton
|
||||
aria-label={`删除节点 ${row.node_id}`}
|
||||
size="small"
|
||||
onClick={() => handleDelete(row.node_id)}
|
||||
disabled={rows.length <= 1}
|
||||
sx={{ width: 40, height: 40 }}
|
||||
>
|
||||
<DeleteIcon fontSize="small" />
|
||||
</IconButton>
|
||||
</span>
|
||||
</Tooltip>
|
||||
</>
|
||||
)}
|
||||
</Stack>
|
||||
),
|
||||
},
|
||||
{
|
||||
field: "adjustment_status",
|
||||
headerName: "调整状态",
|
||||
width: 108,
|
||||
renderCell: ({ value }) => {
|
||||
const status = value as AdjustmentStatus;
|
||||
return (
|
||||
<Chip
|
||||
label={STATUS_LABELS[status]}
|
||||
color={STATUS_COLORS[status]}
|
||||
variant="outlined"
|
||||
size="small"
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
field: "sequence",
|
||||
headerName: "序号",
|
||||
@@ -445,6 +471,21 @@ const SchemeEditor: React.FC<SchemeEditorProps> = ({
|
||||
sortable: false,
|
||||
},
|
||||
{ field: "node_id", headerName: "节点 ID", minWidth: 120, flex: 0.8 },
|
||||
{
|
||||
field: "max_pipe_diameter",
|
||||
headerName: "最大管径 (mm)",
|
||||
description: "节点关联管道中的最大管径",
|
||||
minWidth: 132,
|
||||
flex: 0.75,
|
||||
align: "right",
|
||||
headerAlign: "right",
|
||||
valueFormatter: (value) => {
|
||||
if (value == null || !Number.isFinite(Number(value))) return "无";
|
||||
return Number(value).toLocaleString("zh-CN", {
|
||||
maximumFractionDigits: 3,
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
field: "longitude",
|
||||
headerName: "经度",
|
||||
@@ -507,70 +548,6 @@ const SchemeEditor: React.FC<SchemeEditorProps> = ({
|
||||
headerAlign: "right",
|
||||
valueFormatter: (value) => Number(value).toFixed(3),
|
||||
},
|
||||
{
|
||||
field: "adjustment_status",
|
||||
headerName: "调整状态",
|
||||
width: 108,
|
||||
renderCell: ({ value }) => {
|
||||
const status = value as AdjustmentStatus;
|
||||
return (
|
||||
<Chip
|
||||
label={STATUS_LABELS[status]}
|
||||
color={STATUS_COLORS[status]}
|
||||
variant="outlined"
|
||||
size="small"
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
field: "actions",
|
||||
headerName: "操作",
|
||||
width: scheme.can_edit ? 138 : 54,
|
||||
sortable: false,
|
||||
filterable: false,
|
||||
renderCell: ({ row }) => (
|
||||
<Stack direction="row" spacing={0.25} sx={{ alignItems: "center" }}>
|
||||
<Tooltip title="地图定位">
|
||||
<IconButton
|
||||
aria-label={`定位节点 ${row.node_id}`}
|
||||
size="small"
|
||||
onClick={() => locateRow(row)}
|
||||
sx={{ width: 40, height: 40 }}
|
||||
>
|
||||
<LocateIcon fontSize="small" />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
{scheme.can_edit && (
|
||||
<>
|
||||
<Tooltip title="替换节点">
|
||||
<IconButton
|
||||
aria-label={`替换节点 ${row.node_id}`}
|
||||
size="small"
|
||||
onClick={() => activateMode("replace", row.node_id)}
|
||||
sx={{ width: 40, height: 40 }}
|
||||
>
|
||||
<ReplaceIcon fontSize="small" />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title="删除节点">
|
||||
<span>
|
||||
<IconButton
|
||||
aria-label={`删除节点 ${row.node_id}`}
|
||||
size="small"
|
||||
onClick={() => handleDelete(row.node_id)}
|
||||
disabled={rows.length <= 1}
|
||||
sx={{ width: 40, height: 40 }}
|
||||
>
|
||||
<DeleteIcon fontSize="small" />
|
||||
</IconButton>
|
||||
</span>
|
||||
</Tooltip>
|
||||
</>
|
||||
)}
|
||||
</Stack>
|
||||
),
|
||||
},
|
||||
],
|
||||
[activateMode, handleDelete, locateRow, rows.length, scheme.can_edit],
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user