feat(frontend): enforce RBAC and refine burst analysis

This commit is contained in:
2026-07-30 16:45:10 +08:00
parent f355ddd002
commit 723931b6ae
15 changed files with 772 additions and 390 deletions
@@ -11,7 +11,10 @@ import AnalysisReport, {
matchesValveAnalysis,
} from "./AnalysisReport";
import { SchemeRecord, ValveIsolationResult } from "./types";
import { isAllowedAccidentPipe } from "./valveIsolationScope";
import {
isAllowedAccidentPipe,
normalizeValveIsolationResult,
} from "./valveIsolationScope";
jest.mock("@/utils/mapQueryService", () => ({
queryFeaturesByIds: jest.fn(),
@@ -139,12 +142,69 @@ describe("AnalysisReport", () => {
);
});
it("shows only the affected count for a non-isolatable result", async () => {
const legacyAffectedNodes = Array.from(
{ length: 100 },
(_, index) => `legacy-node-${index}`,
);
const nonIsolatableResult = {
...valveResult,
affected_nodes: legacyAffectedNodes,
affected_node_count: 85747,
must_close_valves: [],
isolatable: false,
};
render(
<AnalysisReport
scheme={scheme}
valveResult={nonIsolatableResult}
disabledValves={[]}
generatedAt={new Date("2026-07-30T10:00:00+08:00")}
/>,
);
const preview = within(
screen.getByTestId("burst-analysis-report-preview"),
);
expect(preview.getByText("85747 个")).toBeInTheDocument();
expect(
preview.getByText("不可隔离,未生成受影响节点清单。"),
).toBeInTheDocument();
expect(preview.queryByText("legacy-node-0")).not.toBeInTheDocument();
expect(preview.queryByText("legacy-node-99")).not.toBeInTheDocument();
await waitFor(() =>
expect(preview.getByText("315 mm")).toBeInTheDocument(),
);
});
it("limits scheme-bound valve analysis to the scheme accident pipes", () => {
expect(isAllowedAccidentPipe("P-1", ["P-1", "P-2"])).toBe(true);
expect(isAllowedAccidentPipe("P-99", ["P-1", "P-2"])).toBe(false);
expect(isAllowedAccidentPipe("P-99", undefined)).toBe(true);
});
it("normalizes legacy valve results without changing isolatable lists", () => {
expect(
normalizeValveIsolationResult({
...valveResult,
affected_nodes: ["J-1", "J-2", "J-3"],
must_close_valves: [],
isolatable: false,
}),
).toMatchObject({
affected_nodes: [],
affected_node_count: 3,
isolatable: false,
});
expect(normalizeValveIsolationResult(valveResult)).toMatchObject({
affected_nodes: ["J-1", "J-2"],
affected_node_count: 2,
isolatable: true,
});
});
it("prints only after assigning the report print state", async () => {
const originalTitle = document.title;
const print = jest