fix(api): align frontend with project-scoped backend
Use project-scoped endpoints and run IDs for current project, SCADA metadata, historical time series, migrated DMA results, and sensor placement runs. The regressions recurred because tests mocked pre-interceptor and new-only payload shapes, while history queries relied on implicit global scheme state and unbounded request fan-out. Cover post-interceptor pages, migrated result_rows, explicit run_id routing, multi-element requests, request limits, and cancellation.
This commit is contained in:
@@ -17,7 +17,7 @@ import {
|
||||
ChevronRight,
|
||||
FormatListBulleted,
|
||||
} from "@mui/icons-material";
|
||||
import { useMap } from "@components/olmap/core/MapComponent";
|
||||
import { useData, useMap } from "@components/olmap/core/MapComponent";
|
||||
import StyleLegend from "@components/olmap/core/Controls/StyleLegend";
|
||||
import AnalysisParameters, {
|
||||
createDMALeakAnalysisParametersState,
|
||||
@@ -50,6 +50,7 @@ const DMA_AREA_INDEX_PROPERTY = "dma_area_index";
|
||||
|
||||
const DMALeakDetectionPanel: React.FC = () => {
|
||||
const map = useMap();
|
||||
const setSchemeRunId = useData()?.setSchemeRunId;
|
||||
const [open, setOpen] = useState(true);
|
||||
const [tab, setTab] = useState(0);
|
||||
const [result, setResult] = useState<LeakageResultDetail | null>(null);
|
||||
@@ -79,15 +80,23 @@ const DMALeakDetectionPanel: React.FC = () => {
|
||||
[activeAreas.length],
|
||||
);
|
||||
|
||||
const handleAnalysisResult = useCallback((res: LeakageResultDetail) => {
|
||||
setResult(res);
|
||||
}, []);
|
||||
const handleAnalysisResult = useCallback(
|
||||
(res: LeakageResultDetail) => {
|
||||
setSchemeRunId?.("");
|
||||
setResult(res);
|
||||
},
|
||||
[setSchemeRunId],
|
||||
);
|
||||
|
||||
const handleViewResult = useCallback((res: LeakageResultDetail) => {
|
||||
setResult(res);
|
||||
setLoadedResult(res);
|
||||
setTab(2);
|
||||
}, []);
|
||||
const handleViewResult = useCallback(
|
||||
(res: LeakageResultDetail, runId: string) => {
|
||||
setSchemeRunId?.(runId);
|
||||
setResult(res);
|
||||
setLoadedResult(res);
|
||||
setTab(2);
|
||||
},
|
||||
[setSchemeRunId],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!map) return;
|
||||
|
||||
@@ -27,13 +27,17 @@ import {
|
||||
listAnalysisSchemes,
|
||||
} from "@/lib/analysisRuns";
|
||||
import { useControllableObjectState } from "@components/olmap/core/useControllableState";
|
||||
import { LeakageResultDetail, LeakageSchemeRecord } from "./types";
|
||||
import {
|
||||
LeakageResultDetail,
|
||||
LeakageSchemeRecord,
|
||||
normalizeLeakageRows,
|
||||
} from "./types";
|
||||
import { FLOW_DISPLAY_UNIT, toM3h } from "@utils/units";
|
||||
import { useSchemeCreatorName } from "@components/olmap/core/useSchemeCreatorName";
|
||||
import { SchemeQueryEmptyState } from "@components/olmap/common/PanelEmptyState";
|
||||
|
||||
interface Props {
|
||||
onViewResult: (result: LeakageResultDetail) => void;
|
||||
onViewResult: (result: LeakageResultDetail, runId: string) => void;
|
||||
schemes?: LeakageSchemeRecord[];
|
||||
onSchemesChange?: (schemes: LeakageSchemeRecord[]) => void;
|
||||
state?: DMALeakSchemeQueryState;
|
||||
@@ -131,14 +135,18 @@ const SchemeQuery: React.FC<Props> = ({
|
||||
if (!result) {
|
||||
throw new Error("方案详情缺少漏损识别结果");
|
||||
}
|
||||
onViewResult({
|
||||
...result,
|
||||
scheme_name: scheme.scheme_name,
|
||||
scheme_detail: scheme.scheme_detail,
|
||||
scheme_start_time: scheme.scheme_start_time,
|
||||
create_time: scheme.create_time,
|
||||
username: scheme.username,
|
||||
} as LeakageResultDetail);
|
||||
onViewResult(
|
||||
{
|
||||
...result,
|
||||
rows: normalizeLeakageRows(result),
|
||||
scheme_name: scheme.scheme_name,
|
||||
scheme_detail: scheme.scheme_detail,
|
||||
scheme_start_time: scheme.scheme_start_time,
|
||||
create_time: scheme.create_time,
|
||||
username: scheme.username,
|
||||
} as LeakageResultDetail,
|
||||
runId,
|
||||
);
|
||||
} catch (error: any) {
|
||||
open?.({
|
||||
type: "error",
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import { normalizeLeakageRows } from "./types";
|
||||
|
||||
const migratedRow = {
|
||||
Area: "DMA-01",
|
||||
LeakageRatioRaw: 0.12,
|
||||
LeakageRatio: 0.1,
|
||||
LeakageFlow_m3_per_s: 0.02,
|
||||
};
|
||||
|
||||
describe("normalizeLeakageRows", () => {
|
||||
it("restores migrated DMA results stored under result_rows", () => {
|
||||
expect(normalizeLeakageRows({ result_rows: [migratedRow] })).toEqual([
|
||||
migratedRow,
|
||||
]);
|
||||
});
|
||||
|
||||
it("prefers the canonical rows field when both shapes are present", () => {
|
||||
const canonicalRow = { ...migratedRow, Area: "DMA-02" };
|
||||
|
||||
expect(
|
||||
normalizeLeakageRows({
|
||||
rows: [canonicalRow],
|
||||
result_rows: [migratedRow],
|
||||
}),
|
||||
).toEqual([canonicalRow]);
|
||||
});
|
||||
});
|
||||
@@ -5,6 +5,18 @@ export interface LeakageRow {
|
||||
LeakageFlow_m3_per_s: number;
|
||||
}
|
||||
|
||||
export const normalizeLeakageRows = (
|
||||
payload: Record<string, unknown>,
|
||||
): LeakageRow[] => {
|
||||
if (Array.isArray(payload.rows)) {
|
||||
return payload.rows as LeakageRow[];
|
||||
}
|
||||
|
||||
return Array.isArray(payload.result_rows)
|
||||
? (payload.result_rows as LeakageRow[])
|
||||
: [];
|
||||
};
|
||||
|
||||
export interface LeakageSchemeRecord {
|
||||
scheme_id: string;
|
||||
scheme_name: string;
|
||||
|
||||
Reference in New Issue
Block a user