diff --git a/contracts/manifest.json b/contracts/manifest.json
index 0f3d7a5..464233d 100644
--- a/contracts/manifest.json
+++ b/contracts/manifest.json
@@ -7,7 +7,7 @@
},
"server": {
"file": "server-v1.openapi.json",
- "sha256": "9cd5b962e9556ec227c52d0dc7d4ef4af562dcea86e16877c923c37de0f4f704"
+ "sha256": "b003a57c9b8c1a041b644363ef58afb8bfcede1fe076ce48a190d2a1ac915e3f"
}
}
}
diff --git a/contracts/server-v1.openapi.json b/contracts/server-v1.openapi.json
index f6ddeac..cd08f0e 100644
--- a/contracts/server-v1.openapi.json
+++ b/contracts/server-v1.openapi.json
@@ -2598,6 +2598,18 @@
"title": "Map Y",
"type": "number"
},
+ "max_pipe_diameter": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "节点关联管道的最大管径,单位:毫米",
+ "title": "Max Pipe Diameter"
+ },
"node_id": {
"title": "Node Id",
"type": "string"
@@ -2613,6 +2625,7 @@
},
"required": [
"node_id",
+ "max_pipe_diameter",
"project_x",
"project_y",
"map_x",
@@ -35546,6 +35559,114 @@
]
}
},
+ "/api/v1/sensor-placement-candidates/{node_id}": {
+ "get": {
+ "operationId": "get_sensor_placement_candidates_node_id",
+ "parameters": [
+ {
+ "in": "path",
+ "name": "node_id",
+ "required": true,
+ "schema": {
+ "maxLength": 32,
+ "minLength": 1,
+ "title": "Node Id",
+ "type": "string"
+ }
+ },
+ {
+ "in": "header",
+ "name": "X-Project-Id",
+ "required": true,
+ "schema": {
+ "title": "X-Project-Id",
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/SensorPointResponse"
+ }
+ }
+ },
+ "description": "Successful Response"
+ },
+ "401": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ProblemDetails"
+ }
+ }
+ },
+ "description": "Authentication required"
+ },
+ "403": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ProblemDetails"
+ }
+ }
+ },
+ "description": "Insufficient permission"
+ },
+ "404": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ProblemDetails"
+ }
+ }
+ },
+ "description": "Resource not found"
+ },
+ "409": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ProblemDetails"
+ }
+ }
+ },
+ "description": "Resource conflict"
+ },
+ "422": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ProblemDetails"
+ }
+ }
+ },
+ "description": "Validation error"
+ },
+ "503": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ProblemDetails"
+ }
+ }
+ },
+ "description": "Dependency unavailable"
+ }
+ },
+ "security": [
+ {
+ "OAuth2PasswordBearer": []
+ }
+ ],
+ "summary": "获取监测点候选节点详情",
+ "tags": [
+ "Sensor Placement"
+ ]
+ }
+ },
"/api/v1/sensor-placement-optimization-runs": {
"post": {
"operationId": "post_sensor_placement_optimization_runs",
diff --git a/src/components/olmap/MonitoringPlaceOptimization/MonitoringPlaceOptimizationPanel.test.tsx b/src/components/olmap/MonitoringPlaceOptimization/MonitoringPlaceOptimizationPanel.test.tsx
index 5b0206a..fa71ecb 100644
--- a/src/components/olmap/MonitoringPlaceOptimization/MonitoringPlaceOptimizationPanel.test.tsx
+++ b/src/components/olmap/MonitoringPlaceOptimization/MonitoringPlaceOptimizationPanel.test.tsx
@@ -1,5 +1,6 @@
import { act, fireEvent, render, screen } from "@testing-library/react";
import MonitoringPlaceOptimizationPanel, {
+ getMonitoringLayerVisibility,
getTabIndicatorSx,
getTabIndicatorTransform,
} from "./MonitoringPlaceOptimizationPanel";
@@ -7,6 +8,7 @@ import { getSensorPlacementScheme } from "./schemeApi";
import type { SensorPlacementScheme } from "./types";
const mockSchemeEditorRender = jest.fn();
+const mockSchemeQueryRender = jest.fn();
jest.mock("@refinedev/core", () => ({
useNotification: () => ({ open: jest.fn() }),
@@ -20,9 +22,16 @@ jest.mock("./OptimizationParameters", () => ({
jest.mock("./SchemeQuery", () => ({
__esModule: true,
- default: ({ onEdit }: { onEdit: (schemeId: number) => void }) => (
-
- ),
+ default: ({
+ onEdit,
+ active,
+ }: {
+ onEdit: (schemeId: number) => void;
+ active?: boolean;
+ }) => {
+ mockSchemeQueryRender(active);
+ return ;
+ },
createMonitoringSchemeQueryState: () => ({}),
}));
@@ -66,6 +75,7 @@ const scheme: SensorPlacementScheme = {
describe("MonitoringPlaceOptimizationPanel", () => {
beforeEach(() => {
mockSchemeEditorRender.mockClear();
+ mockSchemeQueryRender.mockClear();
});
it("applies equal-width positioning to the rendered tab indicator", () => {
@@ -90,6 +100,21 @@ describe("MonitoringPlaceOptimizationPanel", () => {
expect(indicator).toHaveStyle({ transform: "translateX(200%)" });
});
+ it("keeps query and editor layers mutually exclusive by active tab", () => {
+ expect(getMonitoringLayerVisibility(0)).toEqual({
+ editor: false,
+ query: false,
+ });
+ expect(getMonitoringLayerVisibility(1)).toEqual({
+ editor: true,
+ query: false,
+ });
+ expect(getMonitoringLayerVisibility(2)).toEqual({
+ editor: false,
+ query: true,
+ });
+ });
+
it("prepares a queried scheme before switching to the result editor", async () => {
let resolveScheme: (value: SensorPlacementScheme) => void = () => {};
mockGetSensorPlacementScheme.mockReturnValue(
@@ -119,5 +144,23 @@ describe("MonitoringPlaceOptimizationPanel", () => {
false,
true,
]);
+ expect(mockSchemeQueryRender.mock.calls.at(-1)?.[0]).toBe(false);
+ });
+
+ it("keeps the active result layer visible when the panel is collapsed", async () => {
+ mockGetSensorPlacementScheme.mockResolvedValue(scheme);
+ render();
+
+ fireEvent.click(screen.getByRole("tab", { name: /方案查询/ }));
+ fireEvent.click(screen.getByRole("button", { name: "打开测试方案" }));
+ await screen.findByTestId("scheme-editor");
+
+ const collapseButton = screen
+ .getByTestId("ChevronRightIcon")
+ .closest("button");
+ expect(collapseButton).not.toBeNull();
+ fireEvent.click(collapseButton!);
+
+ expect(mockSchemeEditorRender.mock.calls.at(-1)?.[0]).toBe(true);
});
});
diff --git a/src/components/olmap/MonitoringPlaceOptimization/MonitoringPlaceOptimizationPanel.tsx b/src/components/olmap/MonitoringPlaceOptimization/MonitoringPlaceOptimizationPanel.tsx
index f6e9388..5975baf 100644
--- a/src/components/olmap/MonitoringPlaceOptimization/MonitoringPlaceOptimizationPanel.tsx
+++ b/src/components/olmap/MonitoringPlaceOptimization/MonitoringPlaceOptimizationPanel.tsx
@@ -69,6 +69,11 @@ export const getTabIndicatorSx = (tabIndex: number) => ({
},
});
+export const getMonitoringLayerVisibility = (tabIndex: number) => ({
+ editor: tabIndex === 1,
+ query: tabIndex === 2,
+});
+
interface PreparedSchemeEditorProps
extends React.ComponentProps {
onReady?: () => void;
@@ -126,6 +131,7 @@ const MonitoringPlaceOptimizationPanel: React.FC<
};
const drawerWidth = currentTab === 1 ? 820 : 520;
+ const layerVisibility = getMonitoringLayerVisibility(currentTab);
const handleSchemeEditorReady = useCallback(() => {
setCurrentTab(1);
@@ -326,7 +332,7 @@ const MonitoringPlaceOptimizationPanel: React.FC<
void) | undefined;
+let mockGridColumns: Array<{
+ field: string;
+ headerName?: string;
+ valueFormatter?: (value: unknown) => string;
+}> = [];
const mockMap = {
addLayer: jest.fn(),
@@ -32,19 +39,23 @@ jest.mock("@components/olmap/core/MapComponent", () => ({
jest.mock("@mui/x-data-grid", () => ({
DataGrid: (props: {
+ columns: typeof mockGridColumns;
density?: string;
initialState?: { density?: string };
rowHeight?: number;
columnHeaderHeight?: number;
- }) => (
-
- ),
+ }) => {
+ mockGridColumns = props.columns;
+ return (
+
+ );
+ },
GridToolbar: () => null,
}));
@@ -119,11 +130,6 @@ jest.mock("ol/style", () => ({
Text: class {},
}));
-jest.mock("ol/proj", () => ({
- fromLonLat: (coordinates: number[]) => coordinates,
- toLonLat: (coordinates: number[]) => coordinates,
-}));
-
jest.mock("@/utils/mapQueryService", () => ({
handleMapClickSelectFeatures: jest.fn(),
}));
@@ -135,6 +141,7 @@ jest.mock("./SchemeDrawingDialog", () => ({
jest.mock("./schemeApi", () => ({
exportSensorPlacementExcel: jest.fn(),
+ getSensorPlacementCandidate: jest.fn(),
overwriteSensorPlacementScheme: jest.fn(),
}));
@@ -149,6 +156,7 @@ const scheme: SensorPlacementScheme = {
sensor_points: [
{
node_id: "J1",
+ max_pipe_diameter: 400,
project_x: 10,
project_y: 20,
map_x: 13500010,
@@ -161,10 +169,18 @@ const scheme: SensorPlacementScheme = {
can_edit: true,
};
+const mockGetSensorPlacementCandidate = jest.mocked(
+ getSensorPlacementCandidate,
+);
+const mockHandleMapClickSelectFeatures = jest.mocked(
+ handleMapClickSelectFeatures,
+);
+
describe("SchemeEditor notifications", () => {
beforeEach(() => {
jest.clearAllMocks();
mockSingleClickHandler = undefined;
+ mockGridColumns = [];
});
it("uses the same error notification contract as scheme query when replace starts outside an existing sensor", async () => {
@@ -187,6 +203,38 @@ describe("SchemeEditor notifications", () => {
});
});
+ it("loads authoritative point details when adding a map-selected node", async () => {
+ mockHandleMapClickSelectFeatures.mockResolvedValue({
+ get: (key: string) => (key === "id" ? "J2" : undefined),
+ getId: () => "J2",
+ } as never);
+ mockGetSensorPlacementCandidate.mockResolvedValue({
+ node_id: "J2",
+ max_pipe_diameter: 500,
+ project_x: 30,
+ project_y: 40,
+ map_x: 13500030,
+ map_y: 3600040,
+ longitude: 121.1,
+ latitude: 31.1,
+ elevation: 6,
+ });
+ render();
+
+ fireEvent.click(screen.getByRole("button", { name: "添加" }));
+ await waitFor(() => expect(mockSingleClickHandler).toBeDefined());
+ await act(async () => {
+ mockSingleClickHandler?.({
+ pixel: [0, 0],
+ coordinate: [13500030, 3600040],
+ stopPropagation: jest.fn(),
+ });
+ await Promise.resolve();
+ });
+
+ expect(mockGetSensorPlacementCandidate).toHaveBeenCalledWith("J2");
+ });
+
it("lets the Data Grid density selector control row sizing", () => {
render();
@@ -207,4 +255,22 @@ describe("SchemeEditor notifications", () => {
"automatic",
);
});
+
+ it("places actions and status first and displays the selected pipe diameter", () => {
+ render();
+
+ expect(mockGridColumns.slice(0, 5).map((column) => column.field)).toEqual([
+ "actions",
+ "adjustment_status",
+ "sequence",
+ "node_id",
+ "max_pipe_diameter",
+ ]);
+ const diameterColumn = mockGridColumns.find(
+ (column) => column.field === "max_pipe_diameter",
+ );
+ expect(diameterColumn?.headerName).toBe("最大管径 (mm)");
+ expect(diameterColumn?.valueFormatter?.(400)).toBe("400");
+ expect(diameterColumn?.valueFormatter?.(null)).toBe("无");
+ });
});
diff --git a/src/components/olmap/MonitoringPlaceOptimization/SchemeEditor.tsx b/src/components/olmap/MonitoringPlaceOptimization/SchemeEditor.tsx
index 14895a1..f0f1d71 100644
--- a/src/components/olmap/MonitoringPlaceOptimization/SchemeEditor.tsx
+++ b/src/components/olmap/MonitoringPlaceOptimization/SchemeEditor.tsx
@@ -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 = ({
const [saveDialogOpen, setSaveDialogOpen] = useState(false);
const [drawingOpen, setDrawingOpen] = useState(false);
const markerLayerRef = useRef | null>(null);
+ const activeRef = useRef(active);
+ activeRef.current = active;
useEffect(() => {
setEditor(createSchemeEditorState(scheme));
@@ -171,6 +171,7 @@ const SchemeEditor: React.FC = ({
},
zIndex: 120,
});
+ layer.setVisible(activeRef.current);
markerLayerRef.current = layer;
map.addLayer(layer);
return () => {
@@ -206,47 +207,8 @@ const SchemeEditor: React.FC = ({
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 = ({
const columns = useMemo[]>(
() => [
+ {
+ field: "actions",
+ headerName: "操作",
+ width: scheme.can_edit ? 138 : 54,
+ sortable: false,
+ filterable: false,
+ renderCell: ({ row }) => (
+
+
+ locateRow(row)}
+ sx={{ width: 40, height: 40 }}
+ >
+
+
+
+ {scheme.can_edit && (
+ <>
+
+ activateMode("replace", row.node_id)}
+ sx={{ width: 40, height: 40 }}
+ >
+
+
+
+
+
+ handleDelete(row.node_id)}
+ disabled={rows.length <= 1}
+ sx={{ width: 40, height: 40 }}
+ >
+
+
+
+
+ >
+ )}
+
+ ),
+ },
+ {
+ field: "adjustment_status",
+ headerName: "调整状态",
+ width: 108,
+ renderCell: ({ value }) => {
+ const status = value as AdjustmentStatus;
+ return (
+
+ );
+ },
+ },
{
field: "sequence",
headerName: "序号",
@@ -445,6 +471,21 @@ const SchemeEditor: React.FC = ({
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 = ({
headerAlign: "right",
valueFormatter: (value) => Number(value).toFixed(3),
},
- {
- field: "adjustment_status",
- headerName: "调整状态",
- width: 108,
- renderCell: ({ value }) => {
- const status = value as AdjustmentStatus;
- return (
-
- );
- },
- },
- {
- field: "actions",
- headerName: "操作",
- width: scheme.can_edit ? 138 : 54,
- sortable: false,
- filterable: false,
- renderCell: ({ row }) => (
-
-
- locateRow(row)}
- sx={{ width: 40, height: 40 }}
- >
-
-
-
- {scheme.can_edit && (
- <>
-
- activateMode("replace", row.node_id)}
- sx={{ width: 40, height: 40 }}
- >
-
-
-
-
-
- handleDelete(row.node_id)}
- disabled={rows.length <= 1}
- sx={{ width: 40, height: 40 }}
- >
-
-
-
-
- >
- )}
-
- ),
- },
],
[activateMode, handleDelete, locateRow, rows.length, scheme.can_edit],
);
diff --git a/src/components/olmap/MonitoringPlaceOptimization/SchemeQuery.tsx b/src/components/olmap/MonitoringPlaceOptimization/SchemeQuery.tsx
index c57a603..7345846 100644
--- a/src/components/olmap/MonitoringPlaceOptimization/SchemeQuery.tsx
+++ b/src/components/olmap/MonitoringPlaceOptimization/SchemeQuery.tsx
@@ -1,6 +1,6 @@
"use client";
-import React, { useEffect, useMemo, useState } from "react";
+import React, { useEffect, useMemo, useRef, useState } from "react";
import {
Box,
Button,
@@ -53,6 +53,7 @@ interface SchemaItem {
interface SchemeQueryProps {
schemes?: SchemeRecord[];
+ active?: boolean;
onSchemesChange?: (schemes: SchemeRecord[]) => void;
onEdit?: (id: number) => void;
network?: string;
@@ -77,6 +78,7 @@ export const createMonitoringSchemeQueryState =
const SchemeQuery: React.FC = ({
schemes: externalSchemes,
+ active = true,
onSchemesChange,
onEdit,
network = NETWORK_NAME,
@@ -98,6 +100,8 @@ const SchemeQuery: React.FC = ({
const [highlightLayer, setHighlightLayer] =
useState | null>(null);
+ const activeRef = useRef(active);
+ activeRef.current = active;
const [highlightFeatures, setHighlightFeatures] = useState([]);
// 使用外部提供的 schemes 或内部状态
const schemes =
@@ -142,6 +146,7 @@ const SchemeQuery: React.FC = ({
queryable: false,
},
});
+ highlightLayer.setVisible(activeRef.current);
map.addLayer(highlightLayer);
setHighlightLayer(highlightLayer);
@@ -151,6 +156,10 @@ const SchemeQuery: React.FC = ({
};
}, [map]);
+ useEffect(() => {
+ highlightLayer?.setVisible(active);
+ }, [active, highlightLayer]);
+
// 高亮要素的函数
useEffect(() => {
if (!highlightLayer) {
diff --git a/src/components/olmap/MonitoringPlaceOptimization/engineeringDrawing.test.ts b/src/components/olmap/MonitoringPlaceOptimization/engineeringDrawing.test.ts
index cc18913..42dc0b4 100644
--- a/src/components/olmap/MonitoringPlaceOptimization/engineeringDrawing.test.ts
+++ b/src/components/olmap/MonitoringPlaceOptimization/engineeringDrawing.test.ts
@@ -107,6 +107,7 @@ const point = (
map_y: number,
): SensorPointRow => ({
node_id,
+ max_pipe_diameter: 300,
sequence,
map_x,
map_y,
diff --git a/src/components/olmap/MonitoringPlaceOptimization/schemeApi.ts b/src/components/olmap/MonitoringPlaceOptimization/schemeApi.ts
index 1428e13..f73f3e2 100644
--- a/src/components/olmap/MonitoringPlaceOptimization/schemeApi.ts
+++ b/src/components/olmap/MonitoringPlaceOptimization/schemeApi.ts
@@ -3,6 +3,7 @@ import { config } from "@/config/config";
import type {
AdjustmentStatus,
SensorPlacementScheme,
+ SensorPoint,
} from "./types";
export interface OptimizeSchemeInput {
@@ -32,6 +33,15 @@ export const getSensorPlacementScheme = async (
return response.data;
};
+export const getSensorPlacementCandidate = async (
+ nodeId: string,
+): Promise => {
+ const response = await api.get(
+ `${config.BACKEND_URL}/api/v1/sensor-placement-candidates/${encodeURIComponent(nodeId)}`,
+ );
+ return response.data;
+};
+
export const overwriteSensorPlacementScheme = async (
schemeId: number,
expectedSensorLocation: string[],
diff --git a/src/components/olmap/MonitoringPlaceOptimization/schemeEditor.test.ts b/src/components/olmap/MonitoringPlaceOptimization/schemeEditor.test.ts
index f26cd6d..b0c62b6 100644
--- a/src/components/olmap/MonitoringPlaceOptimization/schemeEditor.test.ts
+++ b/src/components/olmap/MonitoringPlaceOptimization/schemeEditor.test.ts
@@ -13,6 +13,7 @@ import type { SensorPlacementScheme, SensorPoint } from "./types";
const point = (node_id: string): SensorPoint => ({
node_id,
+ max_pipe_diameter: 300,
project_x: Number(node_id.slice(1)) * 10,
project_y: Number(node_id.slice(1)) * 20,
map_x: 13500000 + Number(node_id.slice(1)) * 10,
diff --git a/src/components/olmap/MonitoringPlaceOptimization/types.ts b/src/components/olmap/MonitoringPlaceOptimization/types.ts
index 1c3b058..38e0984 100644
--- a/src/components/olmap/MonitoringPlaceOptimization/types.ts
+++ b/src/components/olmap/MonitoringPlaceOptimization/types.ts
@@ -2,6 +2,7 @@ export type AdjustmentStatus = "current" | "original" | "added" | "replaced";
export interface SensorPoint {
node_id: string;
+ max_pipe_diameter: number | null;
project_x: number;
project_y: number;
map_x: number;
diff --git a/src/generated/serverApi.ts b/src/generated/serverApi.ts
index 611f8ce..c0737cd 100644
--- a/src/generated/serverApi.ts
+++ b/src/generated/serverApi.ts
@@ -4833,6 +4833,23 @@ export interface paths {
patch?: never;
trace?: never;
};
+ "/api/v1/sensor-placement-candidates/{node_id}": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ /** 获取监测点候选节点详情 */
+ get: operations["get_sensor_placement_candidates_node_id"];
+ put?: never;
+ post?: never;
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
"/api/v1/sensor-placement-optimization-runs": {
parameters: {
query?: never;
@@ -8153,6 +8170,11 @@ export interface components {
map_x: number;
/** Map Y */
map_y: number;
+ /**
+ * Max Pipe Diameter
+ * @description 节点关联管道的最大管径,单位:毫米
+ */
+ max_pipe_diameter: number | null;
/** Node Id */
node_id: string;
/** Project X */
@@ -31651,6 +31673,84 @@ export interface operations {
};
};
};
+ get_sensor_placement_candidates_node_id: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-Project-Id": string;
+ };
+ path: {
+ node_id: string;
+ };
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description Successful Response */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["SensorPointResponse"];
+ };
+ };
+ /** @description Authentication required */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Insufficient permission */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Resource not found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Resource conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Validation error */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Dependency unavailable */
+ 503: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
post_sensor_placement_optimization_runs: {
parameters: {
query?: never;