feat: migrate drainage frontend to Vite

This commit is contained in:
2026-07-22 12:47:36 +08:00
parent e0cfa3d6eb
commit 72850761ce
213 changed files with 5726 additions and 5283 deletions
+107 -54
View File
@@ -1,12 +1,14 @@
import { expect, test, type Page } from "playwright/test";
test("frontend actions replace SCADA analysis results and remain legible at 375px", async ({ page }) => {
test("frontend actions replace SCADA analysis results and remain legible at 375px", async ({
page
}) => {
const receipts: Array<Record<string, unknown>> = [];
await mockAgentActions(page, receipts);
await page.goto("/", { waitUntil: "domcontentloaded" });
await page.waitForFunction(() => Boolean(
window.__waterNetworkMap?.getSource("agent-scada-analysis")
));
await page.waitForFunction(() =>
Boolean(window.__waterNetworkMap?.getSource("agent-scada-analysis"))
);
await expect(
page.getByRole("button", { name: "选择 Agent 模型" }).filter({ visible: true }).first()
).toContainText("测试模型");
@@ -23,11 +25,17 @@ test("frontend actions replace SCADA analysis results and remain legible at 375p
});
});
const prompt = page.getByPlaceholder(/输入调度问题/).filter({ visible: true }).first();
const prompt = page
.getByPlaceholder(/输入调度问题/)
.filter({ visible: true })
.first();
await prompt.fill("将 MP01 标为高、MP02 标为低并显示编号");
await page.getByRole("button", { name: "发送 Agent 指令" }).filter({ visible: true }).first().click();
await page
.getByRole("button", { name: "发送 Agent 指令" })
.filter({ visible: true })
.first()
.click();
await expect(page.getByText("已渲染 1 个,高 0、中 0、低 1。")).toBeVisible();
await page.waitForFunction(() => {
const source = window.__waterNetworkMap?.getSource("agent-scada-analysis") as unknown as {
_data?: { features?: Array<{ properties?: Record<string, unknown> }> };
@@ -73,35 +81,44 @@ test("frontend actions replace SCADA analysis results and remain legible at 375p
levelColors: [
"match",
["get", "analysis_level"],
"high", "#F43F5E",
"medium", "#F59E0B",
"low", "#10B981",
"high",
"#F43F5E",
"medium",
"#F59E0B",
"low",
"#10B981",
"#8B5CF6"
],
indicatorLayer: "circle"
});
await expect.poll(() => receipts.length).toBe(2);
expect(receipts).toEqual(expect.arrayContaining([
expect.objectContaining({ status: "failed", error: expect.objectContaining({ code: "ACTION_SUPERSEDED" }) }),
expect.objectContaining({
status: "succeeded",
output: expect.objectContaining({ rendered_ids: ["MP02"], fitted: true })
})
]));
expect(receipts).toEqual(
expect.arrayContaining([
expect.objectContaining({
status: "failed",
error: expect.objectContaining({ code: "ACTION_SUPERSEDED" })
}),
expect.objectContaining({
status: "succeeded",
output: expect.objectContaining({ rendered_ids: ["MP02"], fitted: true })
})
])
);
await page.setViewportSize({ width: 375, height: 812 });
await page.evaluate(() => window.__waterNetworkMap?.resize());
await expect(page.getByText("已渲染 1 个,高 0、中 0、低 1。")).toBeVisible();
expect(await page.evaluate(() => {
const source = window.__waterNetworkMap?.getSource("agent-scada-analysis") as unknown as {
_data?: { features?: Array<{ properties?: Record<string, unknown> }> };
};
return {
label: source?._data?.features?.[0]?.properties?.analysis_label,
viewportWidth: document.documentElement.clientWidth
};
})).toEqual({ label: "MP02 · 低", viewportWidth: 375 });
expect(
await page.evaluate(() => {
const source = window.__waterNetworkMap?.getSource("agent-scada-analysis") as unknown as {
_data?: { features?: Array<{ properties?: Record<string, unknown> }> };
};
return {
label: source?._data?.features?.[0]?.properties?.analysis_label,
viewportWidth: document.documentElement.clientWidth
};
})
).toEqual({ label: "MP02 · 低", viewportWidth: 375 });
await page.setViewportSize({ width: 1440, height: 900 });
await page.getByRole("button", { name: "新建 Agent 对话" }).filter({ visible: true }).click();
@@ -112,9 +129,16 @@ test("frontend actions replace SCADA analysis results and remain legible at 375p
return source?._data?.features?.length === 0;
});
const nextPrompt = page.getByPlaceholder(/输入调度问题/).filter({ visible: true }).first();
const nextPrompt = page
.getByPlaceholder(/输入调度问题/)
.filter({ visible: true })
.first();
await nextPrompt.fill("新一组分析:将 MP01 标为高、MP02 标为低并显示编号");
await page.getByRole("button", { name: "发送 Agent 指令" }).filter({ visible: true }).first().click();
await page
.getByRole("button", { name: "发送 Agent 指令" })
.filter({ visible: true })
.first()
.click();
await page.waitForFunction(() => {
const source = window.__waterNetworkMap?.getSource("agent-scada-analysis") as unknown as {
_data?: { features?: Array<{ properties?: Record<string, unknown> }> };
@@ -123,12 +147,14 @@ test("frontend actions replace SCADA analysis results and remain legible at 375p
return features.length === 1 && features[0].properties?.analysis_label === "MP02 · 低";
});
await page.waitForTimeout(250);
expect(await page.evaluate(() => {
const source = window.__waterNetworkMap?.getSource("agent-scada-analysis") as unknown as {
_data?: { features?: Array<{ properties?: Record<string, unknown> }> };
};
return source?._data?.features?.map((feature) => feature.properties?.analysis_label);
})).toEqual(["MP02 · 低"]);
expect(
await page.evaluate(() => {
const source = window.__waterNetworkMap?.getSource("agent-scada-analysis") as unknown as {
_data?: { features?: Array<{ properties?: Record<string, unknown> }> };
};
return source?._data?.features?.map((feature) => feature.properties?.analysis_label);
})
).toEqual(["MP02 · 低"]);
await expect.poll(() => receipts.length).toBe(4);
});
@@ -142,11 +168,16 @@ async function mockAgentActions(page: Page, receipts: Array<Record<string, unkno
await route.fulfill({
json: {
type: "FeatureCollection",
features: [{
type: "Feature",
geometry: { type: "Point", coordinates: sensorId === "MP01" ? [120.7, 28] : [120.72, 28.02] },
properties: { sensor_id: sensorId }
}]
features: [
{
type: "Feature",
geometry: {
type: "Point",
coordinates: sensorId === "MP01" ? [120.7, 28] : [120.72, 28.02]
},
properties: { sensor_id: sensorId }
}
]
}
});
});
@@ -160,20 +191,26 @@ async function mockAgentActions(page: Page, receipts: Array<Record<string, unkno
return;
}
if (path.endsWith("/frontend-action-registry")) {
await route.fulfill({ json: {
schema_version: "frontend-action-registry@1",
actions: [
{ id: "render_scada_analysis", version: "frontend-action@1" },
{ id: "clear_scada_analysis", version: "frontend-action@1" }
]
} });
await route.fulfill({
json: {
schema_version: "frontend-action-registry@1",
actions: [
{ id: "render_scada_analysis", version: "frontend-action@1" },
{ id: "clear_scada_analysis", version: "frontend-action@1" }
]
}
});
return;
}
if (path.endsWith("/models")) {
await route.fulfill({ json: {
default_model: "test/model",
models: [{ id: "test/model", label: "测试模型", description: "SCADA 动作测试", icon: "bolt" }]
} });
await route.fulfill({
json: {
default_model: "test/model",
models: [
{ id: "test/model", label: "测试模型", description: "SCADA 动作测试", icon: "bolt" }
]
}
});
return;
}
if (path.endsWith("/sessions")) {
@@ -181,7 +218,9 @@ async function mockAgentActions(page: Page, receipts: Array<Record<string, unkno
return;
}
if (path.endsWith("/ui-registry")) {
await route.fulfill({ json: { schema_version: "agent-ui-registry@1", components: [], actions: [] } });
await route.fulfill({
json: { schema_version: "agent-ui-registry@1", components: [], actions: [] }
});
return;
}
if (path.endsWith("/stream") && route.request().method() === "POST") {
@@ -190,8 +229,22 @@ async function mockAgentActions(page: Page, receipts: Array<Record<string, unkno
const sessionId = `scada-session-${streamRequestCount}`;
const chunks = [
{ type: "start", messageId: `assistant-scada-action-${streamRequestCount}` },
frontendActionChunk(`action-${streamRequestCount}-first`, `call-${streamRequestCount}-first`, sessionId, "MP01", "high", now),
frontendActionChunk(`action-${streamRequestCount}-second`, `call-${streamRequestCount}-second`, sessionId, "MP02", "low", now),
frontendActionChunk(
`action-${streamRequestCount}-first`,
`call-${streamRequestCount}-first`,
sessionId,
"MP01",
"high",
now
),
frontendActionChunk(
`action-${streamRequestCount}-second`,
`call-${streamRequestCount}-second`,
sessionId,
"MP02",
"low",
now
),
{ type: "text-start", id: "answer" },
{ type: "text-delta", id: "answer", delta: "已更新地图结果。" },
{ type: "text-end", id: "answer" },