feat: expand intelligent investigation workspace
Generic Container CI/CD / test-build-publish (push) Successful in 1m52s
Frontend CI/CD / build-test-publish-and-deploy (push) Successful in 1m52s

This commit is contained in:
2026-10-30 17:30:19 +08:00
parent ddd03dbff6
commit c0e4231b83
223 changed files with 13155 additions and 5304 deletions
@@ -43,6 +43,10 @@ test.beforeEach(async ({ page }) => {
task = { ...task, latest_report: { ...report, revision: task.latest_report.revision + 1,
report: { ...report.report, current_conclusion: "新增现场记录已接收,等待复核。" } } };
render();
}, showLongInvestigationReport: () => {
task = { ...task, latest_report: { ...report, revision: task.latest_report.revision + 1,
report: { ...report.report, current_conclusion: "这是仅用于浏览器验证的长篇调查记录,需结合监测时间、资料来源和现场核查结果逐项复核。".repeat(40) } } };
render();
}, showHistoricalUtcReport: () => {
task = { ...task, latest_report: { ...report, revision: 2, report: { ...report.report,
current_conclusion: "上报时间2026-10-08T04:00:00Z,查询04:00–05:00Z。",
@@ -88,7 +92,7 @@ for (const clearProgressDiagram of [false, true]) {
await page.evaluate(() => (window as unknown as { startNextInvestigationRound: () => void }).startNextInvestigationRound());
await expect(report).toContainText("上一轮报告,本轮分析中");
await expect(page.getByRole("region", { name: "当前调查进展", exact: true })).toContainText("正在复核本轮现场反馈");
const diagram = page.getByRole("region", { name: "调查脉络", exact: true });
const diagram = page.getByRole("region", { name: "调查脉络", exact: true, includeHidden: true });
await expect(diagram.locator(".investigation-diagram svg:has(g.node)")).toContainText("现场反馈复核");
await expect(diagram.locator("svg g.node.tjRunning")).toHaveCount(1);
await page.evaluate((clear) => (window as unknown as { finishInvestigationRound: (value: boolean) => void }).finishInvestigationRound(clear), clearProgressDiagram);
@@ -142,7 +146,8 @@ test("报告摘要与有界详情分层,保留人工事项、阅读版本和
await trigger.click();
const detail = page.getByRole("dialog", { name: "当前结果", exact: true });
await expect(detail.getByText("建议安排现场采样。", { exact: true })).toBeVisible();
await expect.poll(async () => Math.round((await detail.boundingBox())!.width)).toBe(704);
await expect.poll(async () => Math.round((await detail.boundingBox())!.width)).toBeGreaterThan(704);
expect((await detail.boundingBox())!.width).toBeLessThanOrEqual(900);
await detail.screenshot({ path: testInfo.outputPath("report-expanded-desktop.png") });
await page.evaluate(() => (window as unknown as { updateInvestigationReport: () => void }).updateInvestigationReport());
await expect(detail).toContainText("上游监测未见明显异常,仍需现场核查。");
@@ -164,8 +169,8 @@ test("报告摘要与有界详情分层,保留人工事项、阅读版本和
await page.getByRole("button", { name: "展开主要依据" }).click();
const evidence = page.getByRole("dialog", { name: "主要依据", exact: true });
await expect(evidence).toContainText("原始监测记录与来源详情");
await expect.poll(async () => Math.round((await evidence.boundingBox())!.width)).toBe(343);
expect((await evidence.boundingBox())!.height).toBeLessThanOrEqual(688);
await expect.poll(async () => Math.round((await evidence.boundingBox())!.width)).toBe(359);
expect((await evidence.boundingBox())!.height).toBeLessThanOrEqual(704);
await evidence.screenshot({ path: testInfo.outputPath("report-expanded-narrow.png") });
await evidence.getByRole("button", { name: "关闭详情" }).click();
await expect(evidence).toHaveCount(0);
@@ -174,7 +179,7 @@ test("报告摘要与有界详情分层,保留人工事项、阅读版本和
test("数据刷新按整份报告错峰揭示,保留图表与滚动位置并支持减少动态效果", async ({ page }, testInfo) => {
const report = page.getByRole("article", { name: "调查任务报告" });
const diagram = page.getByRole("region", { name: "调查脉络", exact: true });
const diagram = page.getByRole("region", { name: "调查脉络", exact: true, includeHidden: true });
await expect(diagram.locator("svg .node")).toHaveCount(2);
const before = await report.evaluate((element) => {
const graph = element.querySelector(".investigation-diagram svg");
@@ -226,12 +231,68 @@ test("数据刷新按整份报告错峰揭示,保留图表与滚动位置并
await page.locator("#reader").evaluate((element) => { element.scrollTop = 0; });
await update();
await expect(report).toContainText("报告第 5 版");
// Pointer interaction must end the refresh before shared-layout expansion starts.
// Pointer interaction ends the refresh before the reading dialog opens.
await page.getByRole("button", { name: "展开当前结果", exact: true }).dispatchEvent("pointerdown");
await page.getByRole("button", { name: "展开当前结果", exact: true }).click();
const detail = page.getByRole("dialog", { name: "当前结果", exact: true });
await expect(detail).toBeVisible();
await expect.poll(async () => Math.round((await detail.boundingBox())!.width)).toBe(343);
await expect.poll(async () => Math.round((await detail.boundingBox())!.width)).toBe(359);
expect(await page.evaluate(() => document.documentElement.scrollWidth)).toBeLessThanOrEqual(375);
await page.screenshot({ path: testInfo.outputPath("report-refresh-narrow-detail.png") });
});
for (const width of [1440, 320]) {
test(`当前结果和图示采用统一暗色阅读窗口 ${width}px`, async ({ page }, testInfo) => {
await page.setViewportSize({ width, height: 900 });
await page.emulateMedia({ reducedMotion: "reduce" });
const trigger = page.getByRole("button", { name: "展开当前结果", exact: true });
await trigger.click();
const result = page.getByRole("dialog", { name: "当前结果", exact: true });
await expect(result).toBeVisible();
await expect(result).toHaveCSS("animation-name", "none");
await expect(result).toHaveCSS("border-radius", "12px");
const backdrop = page.locator(".investigation-detail-backdrop");
await expect(backdrop).toHaveCSS("animation-name", "none");
await expect(backdrop).toHaveCSS("background-color", /0?\.8|80%/);
expect(await backdrop.boundingBox()).toEqual({ x: 0, y: 0, width, height: 900 });
const bounds = (await result.boundingBox())!;
expect(bounds.x).toBeGreaterThanOrEqual(8);
expect(bounds.y).toBeGreaterThan(0);
expect(bounds.x + bounds.width).toBeLessThanOrEqual(width - 8);
expect(bounds.y + bounds.height).toBeLessThan(900);
await expect(result.getByText("上游监测未见明显异常,仍需现场核查。", { exact: true })).toHaveCSS("font-size", "16px");
await page.evaluate(() => document.fonts.ready);
await page.screenshot({ path: testInfo.outputPath(`current-result-${width}.png`) });
if (width === 320) {
await page.evaluate(() => (window as unknown as { showLongInvestigationReport: () => void }).showLongInvestigationReport());
await result.getByRole("button", { name: "查看最新内容", exact: true }).click();
const scroll = result.locator(".investigation-detail-scroll");
expect(await scroll.evaluate((element) => element.scrollHeight > element.clientHeight)).toBe(true);
expect((await result.boundingBox())!.height).toBeLessThanOrEqual(792);
await scroll.evaluate((element) => { element.scrollTop = element.scrollHeight; });
await expect(result.getByText("核实楼栋二次供水记录。", { exact: true })).toBeInViewport();
expect(await result.evaluate((element) => element.scrollWidth > element.clientWidth)).toBe(false);
}
await page.keyboard.press("Escape");
await expect(result).toHaveCount(0);
await expect(trigger).toBeFocused();
const diagram = page.getByRole("region", { name: "调查脉络", exact: true, includeHidden: true });
await diagram.scrollIntoViewIfNeeded();
await expect(diagram.locator("svg .node")).toHaveCount(2);
await diagram.locator(".investigation-diagram svg[id]").evaluate((element) => { Object.assign(window, { originalExpandedGraph: element }); });
const expandGraph = diagram.getByRole("button", { name: "放大查看", exact: true });
await expandGraph.click();
const graphWindow = page.getByRole("dialog", { name: "现场核查路线", exact: true });
await expect(graphWindow).toBeVisible();
expect(await graphWindow.locator(".investigation-diagram svg[id]").evaluate((element) => element === (window as unknown as { originalExpandedGraph: Element }).originalExpandedGraph)).toBe(true);
await expect(diagram.locator("[data-reading-preview] svg[id]")).toBeVisible();
await graphWindow.getByRole("button", { name: "Zoom in", exact: true }).click();
await expect(graphWindow.locator('[role="application"]')).toHaveCSS("transform", "matrix(1.1, 0, 0, 1.1, 0, 0)");
await page.screenshot({ path: testInfo.outputPath(`current-report-diagram-${width}.png`) });
await page.keyboard.press("Escape");
await expect(graphWindow).toHaveCount(0);
await expect(expandGraph).toBeFocused();
await expect(diagram.locator('[role="application"]')).toHaveCSS("transform", "matrix(1.1, 0, 0, 1.1, 0, 0)");
});
}