feat: extend supply workbench demo and map navigation

This commit is contained in:
2026-09-23 13:19:30 +08:00
parent bebcf2a06c
commit 1752b9ef84
45 changed files with 2137 additions and 449 deletions
+176 -13
View File
@@ -217,12 +217,34 @@ test.describe("外围样板管理", () => {
await page.goto("/");
await page.getByRole("button", { name: "外围样板管理" }).click();
await expect(page.getByText(/118 个测点 · 告警来源未配置 · 真实项目样本回放/)).toBeVisible();
const hierarchy = page.getByLabel("任务层级");
await expect(hierarchy).toContainText("外围合成数据核查");
await expect(hierarchy).toContainText("3 个子任务");
await expect(page.getByLabel("子任务阶段 合成通信核查")).toContainText(/派发.*当前阶段.*执行.*待开始.*复令.*待开始/);
await expect(page.getByLabel("子任务阶段 合成压力偏差复核")).toContainText(/派发.*已完成.*执行.*当前阶段.*复令.*待开始/);
await expect(page.getByLabel("子任务阶段 合成零流量样本确认")).toContainText(/派发.*已完成.*执行.*已完成.*复令.*已完成/);
const workOrderList = page.getByLabel("工单列表");
await expect(workOrderList).toContainText("合成通信核查");
await expect(workOrderList).toContainText("合成压力偏差复核");
await expect(workOrderList).toContainText("合成零流量样本确认");
await expect(workOrderList).toContainText("待处理");
await expect(workOrderList).toContainText("处理中");
await expect(workOrderList).toContainText("已完成");
await expect(page.getByLabel("工单步骤 合成通信核查")).toContainText(/派发.*当前步骤.*执行.*待开始.*复令.*待开始/);
await expect(page.getByLabel("工单步骤 合成压力偏差复核")).toContainText(/派发.*已完成.*执行.*当前步骤.*复令.*待开始/);
await expect(page.getByLabel("工单步骤 合成零流量样本确认")).toContainText(/派发.*已完成.*执行.*已完成.*复令.*已完成/);
await expect(workOrderList).not.toContainText("外围合成数据核查");
await expect(workOrderList).not.toContainText("子任务");
await testInfo.attach("peripheral-work-orders-1280", {
body: await workOrderList.screenshot(),
contentType: "image/png"
});
for (const width of [375, 320]) {
await page.setViewportSize({ width, height: 720 });
const firstOrderSteps = page.getByLabel("工单步骤 合成通信核查");
await firstOrderSteps.scrollIntoViewIfNeeded();
await expect(firstOrderSteps).toBeVisible();
expect(await page.evaluate(() => document.documentElement.scrollWidth)).toBeLessThanOrEqual(width);
await testInfo.attach(`peripheral-work-orders-${width}`, {
body: await page.screenshot(),
contentType: "image/png"
});
}
await page.setViewportSize({ width: 1280, height: 720 });
const scenarioSelect = page.getByRole("combobox", { name: "场景" });
await scenarioSelect.focus();
await page.keyboard.press("Enter");
@@ -375,7 +397,7 @@ test.describe("外围样板管理", () => {
expect(managedRequests).toEqual([]);
});
test("创建、修改并软删除测试工单和测试数据", async ({ page }) => {
test("创建、修改并软删除测试工单和测试数据", async ({ page }, testInfo) => {
const projectId = "324ff7ee-c2d4-5184-a84b-48fb14a2933e";
let workOrders: Record<string, unknown>[] = [];
let testData: Record<string, unknown>[] = [];
@@ -418,19 +440,33 @@ test.describe("外围样板管理", () => {
await page.goto("/");
await page.getByRole("button", { name: "外围样板管理" }).click();
const panel = page.getByRole("complementary", { name: "外围样板管理" });
await expect(panel.getByText("外围任务编排", { exact: true })).toBeVisible();
await expect(panel.getByLabel("任务层级")).toContainText("外围合成数据核查");
await expect(panel.getByText("外围工单与测试数据", { exact: true })).toBeVisible();
await expect(panel.getByLabel("工单列表")).toContainText("暂无测试工单");
await expect(panel.getByRole("textbox", { name: "标题" })).toBeHidden();
await panel.getByRole("button", { name: "新增子任务" }).click();
await panel.getByRole("button", { name: "新增工单" }).click();
const workOrderEditor = panel.getByRole("textbox", { name: "标题" }).locator("xpath=../..");
await expect(workOrderEditor).toHaveCSS("background-color", "rgb(255, 255, 255)");
await testInfo.attach("work-order-editor-1280", {
body: await workOrderEditor.screenshot(),
contentType: "image/png"
});
await page.setViewportSize({ width: 375, height: 720 });
await workOrderEditor.scrollIntoViewIfNeeded();
expect(await page.evaluate(() => document.documentElement.scrollWidth)).toBeLessThanOrEqual(375);
await testInfo.attach("work-order-editor-375", {
body: await page.screenshot(),
contentType: "image/png"
});
await page.setViewportSize({ width: 1280, height: 720 });
await panel.getByRole("textbox", { name: "标题" }).fill("演示 测试工单");
await panel.getByRole("textbox", { name: "说明" }).fill("外围 CRUD 联调");
await panel.getByRole("button", { name: "创建子任务" }).click();
await panel.getByRole("button", { name: "创建工单" }).click();
await expect(panel.getByText("演示 测试工单", { exact: true })).toBeVisible();
await panel.getByRole("button", { name: "编辑子任务 演示 测试工单" }).click();
await panel.getByRole("button", { name: "编辑工单 演示 测试工单" }).click();
await panel.getByRole("textbox", { name: "标题" }).fill("演示 测试工单(已改)");
await panel.getByRole("button", { name: "保存修改" }).click();
await expect(panel.getByText("演示 测试工单(已改)", { exact: true })).toBeVisible();
await panel.getByRole("button", { name: "删除子任务 演示 测试工单(已改)" }).click();
await panel.getByRole("button", { name: "删除工单 演示 测试工单(已改)" }).click();
await expect(panel.getByText("演示 测试工单(已改)", { exact: true })).toBeHidden();
await panel.getByRole("group", { name: "外围样板资源类型" }).getByRole("button", { name: /测试数据/ }).click();
@@ -447,6 +483,133 @@ test.describe("外围样板管理", () => {
await expect(panel.getByText("演示 压力样本", { exact: true })).toBeHidden();
});
test("创建水质投诉工单后进入结构化工况任务并由用户打开 Agent", async ({ page }, testInfo) => {
const projectId = "324ff7ee-c2d4-5184-a84b-48fb14a2933e";
const workOrderId = "50000000-0000-4000-8000-000000000099";
const agentRequests: Array<Record<string, unknown>> = [];
let workOrders: Record<string, unknown>[] = [];
page.on("request", (request) => {
if (
request.method() === "POST" &&
request.url().includes("/api/v1/agent/chat/") &&
request.postData()
) {
agentRequests.push(request.postDataJSON() as Record<string, unknown>);
}
});
await page.route("**/runtime-config.js", (route) => route.fulfill({
contentType: "text/javascript",
body: `globalThis.__TJWATER_CONFIG__=${JSON.stringify({
TJWATER_AUTH_MODE: "disabled",
TJWATER_SERVER_API_BASE_URL: "http://server.test",
TJWATER_AGENT_API_BASE_URL: "http://127.0.0.1:8787",
TJWATER_PERIPHERAL_SAMPLE_API_BASE_URL: "http://peripheral.test"
})}`
}));
await page.route("http://peripheral.test/api/sample/v1/**", async (route) => {
const request = route.request();
const path = new URL(request.url()).pathname;
if (path.endsWith("/context")) return route.fulfill({ json: {
protocol_version: "tjwater-peripheral-sample@1", origin: "synthetic",
project_id: projectId, user_id: "50000000-0000-4000-8000-000000000001",
can_write: true, scenarios: ["normal"],
managed_resources: { work_orders: "available", test_data: "available" },
state_transitions: { pending: [], processing: [], pending_review: [], completed: [] }
} });
if (path.endsWith("/scenario")) return route.fulfill({ json: { scenario: "normal", revision: 1 } });
if (path.endsWith("/monitoring/points")) return route.fulfill({ json: { items: [], next_cursor: null, origin: "historical_replay", source_id: "test" } });
if (path.endsWith("/monitoring/alerts")) return route.fulfill({ json: { items: [], availability: "not_configured", reason: "未配置", origin: "historical_replay", source_id: "test" } });
if (path.endsWith("/work-orders") && request.method() === "GET") return route.fulfill({ json: { items: workOrders, next_cursor: null } });
if (path.endsWith("/work-orders") && request.method() === "POST") {
const body = request.postDataJSON() as Record<string, unknown>;
const item = {
...body,
work_order_id: workOrderId,
project_id: projectId,
revision: 1,
origin: "synthetic",
created_at: "2026-09-22T02:00:00Z",
updated_at: "2026-09-22T02:00:00Z",
created_by: "tester",
updated_by: "tester"
};
delete item.request_id;
workOrders = [item];
return route.fulfill({ status: 201, json: item });
}
if (path.endsWith("/test-data")) return route.fulfill({ json: { items: [], next_cursor: null } });
return route.fulfill({ status: 404, json: { code: "NOT_FOUND", message: "not found", effect: "none", request_id: null } });
});
await page.goto("/");
await page.getByRole("button", { name: "外围样板管理" }).click();
const panel = page.getByRole("complementary", { name: "外围样板管理" });
await panel.getByRole("button", { name: "水质投诉演示" }).click();
await expect(panel).toBeHidden();
await expect(page.getByRole("complementary", { name: "Agent 命令面板" })).toBeHidden();
const conditionPanel = page.getByRole("region", { name: "工况任务", exact: true });
await expect(conditionPanel).toBeVisible();
await expect(conditionPanel.getByRole("heading", { name: "水质投诉调查", exact: true })).toBeVisible();
await expect(conditionPanel.getByText("演示执行流程 · 水质投诉调查流程", { exact: true })).toBeVisible();
await expect(conditionPanel.getByText("接收投诉工单", { exact: true }).last()).toBeVisible();
await expect(conditionPanel.getByText("校验上游水质监测", { exact: true }).last()).toBeVisible();
await expect(conditionPanel.getByText("研判供水链路", { exact: true }).last()).toBeVisible();
await expect(conditionPanel.getByText("核查二次供水", { exact: true }).last()).toBeVisible();
await expect(conditionPanel.getByText("汇总结论与处置", { exact: true }).last()).toBeVisible();
await testInfo.attach("water-quality-condition-task-1280", {
body: await conditionPanel.screenshot(),
contentType: "image/png"
});
for (const width of [375, 320]) {
await page.setViewportSize({ width, height: 720 });
const responsiveConditionPanel = page.getByRole("region", { name: "工况任务", exact: true });
if (!await responsiveConditionPanel.isVisible()) {
await page.getByRole("button", { name: "打开工况任务", exact: true }).click();
}
await expect(responsiveConditionPanel).toBeVisible();
const expandResponsiveTask = responsiveConditionPanel.getByRole("button", { name: "展开工况任务" });
if (await expandResponsiveTask.isVisible()) {
await expandResponsiveTask.click();
}
await expect(responsiveConditionPanel.getByRole("heading", { name: "水质投诉调查" })).toBeVisible();
const responsiveWorkflowStep = responsiveConditionPanel
.getByText("校验上游水质监测", { exact: true })
.last();
await responsiveWorkflowStep.scrollIntoViewIfNeeded();
await expect(responsiveWorkflowStep).toBeVisible();
await page.waitForTimeout(350);
expect(await page.evaluate(() => document.documentElement.scrollWidth)).toBeLessThanOrEqual(width);
await testInfo.attach(`water-quality-condition-task-${width}`, {
body: await page.screenshot(),
contentType: "image/png"
});
}
await page.setViewportSize({ width: 1280, height: 720 });
const restoredConditionPanel = page.getByRole("region", { name: "工况任务", exact: true });
if (!await restoredConditionPanel.isVisible()) {
await page.getByRole("button", { name: "工况任务", exact: true }).click();
}
const agentCollaborationButton = restoredConditionPanel.getByRole("button", { name: "与 Agent 协同" });
if (!await agentCollaborationButton.isVisible()) {
await restoredConditionPanel.getByRole("button", { name: "展开工况任务" }).click();
}
await agentCollaborationButton.click();
await expect(page.getByRole("complementary", { name: "Agent 命令面板" })).toBeVisible();
expect(workOrders[0]).toMatchObject({
work_order_type: "water_quality_complaint",
scenario_code: "WQ-SECONDARY-SUPPLY-001",
status: "open"
});
const triggerRequests = agentRequests.filter((body) => "trigger_context" in body);
expect(triggerRequests).toHaveLength(2);
expect(new Set(triggerRequests.map((body) =>
(body.trigger_context as { trigger_id: string }).trigger_id
))).toEqual(new Set([
`peripheral.work_order.created:${projectId}:${workOrderId}:1`
]));
});
test("在 375px 视口内完整呈现面板", async ({ page }) => {
await page.setViewportSize({ width: 375, height: 720 });
await page.goto("/");