feat(charts): manage investigation charts in a scrolling workspace
Generic Container CI/CD / test-build-publish (push) Successful in 2m7s
Frontend CI/CD / build-test-publish-and-deploy (push) Successful in 2m8s

This commit is contained in:
2026-11-10 17:56:23 +08:00
parent 865491cb23
commit 0ae0a41e61
80 changed files with 4672 additions and 470 deletions
@@ -0,0 +1,90 @@
import { expect, test } from "@playwright/test";
import { basename, resolve } from "node:path";
import { investigationFixture, mockInvestigationPresentation, selectInvestigation } from "./support/mock-investigation-presentation";
const pressureIds = ["170486", "175618", "159673", "135160", "174754"];
const flowIds = ["542017", "486033", "524529", "541061", "542121"];
const times = Array.from({ length: 13 }, (_, i) => `${String(5 + Math.floor(i / 4)).padStart(2, "0")}:${String(i % 4 * 15).padStart(2, "0")}`);
const chart = (id: string, flow: boolean) => ({
action: "open_chart", chart_id: `chart_tc_${id}`, evidence_refs: [`synthetic:${id}`],
chart: { title: `${id} ${flow ? "管流" : "压力"}七日同时刻对照(${flow ? "m³/h" : "m"})`, chart_type: "time_comparison",
x_axis_name: "时间", y_axis_name: `${flow ? "流量(m³/h)" : "压力(m)"}`, x_data: times,
series: [{ name: `${id} 当前 2026-07-16`, type: "line", data: times.map((_, i) => 30 - i / 2),
sample_times: times.map((time) => `2026-07-16T${time}:00+08:00`) },
...Array.from({ length: 7 }, (_, day) => ({ name: `${id} 2026-07-${String(9 + day).padStart(2, "0")}`, type: "scatter",
data: times.map((_, i) => i < 10 ? null : 30 + day / 2),
sample_times: times.map((time, i) => i < 10 ? null : `2026-07-${String(9 + day).padStart(2, "0")}T${time}:00+08:00`) }))] }
});
test.use({ reducedMotion: "reduce" });
for (const width of [1440, 375, 320]) {
test(`groups comparisons with object selection and legends below the plot at ${width}px`, async ({ page }, testInfo) => {
test.setTimeout(60_000);
await page.setViewportSize({ width: 1440, height: 900 });
// This workspace links dependencies outside Vite's root. Serve the installed font for visual checks.
await page.route("**/@fs/**/noto-sans-sc-*.woff2", (route) => route.fulfill({
path: resolve("node_modules/@fontsource-variable/noto-sans-sc/files", basename(new URL(route.request().url()).pathname)),
contentType: "font/woff2"
}));
const task = investigationFixture(1, "同类图表聚合核查");
const mock = await mockInvestigationPresentation(page, [task]);
await selectInvestigation(page, task.title);
await page.setViewportSize({ width, height: 900 });
for (const [ids, flow] of [[pressureIds, false], [flowIds, true]] as const) for (const id of ids) {
await mock.emit(task, chart(id, flow));
await expect(page.locator(`[data-presentation-scope="investigation"] [data-investigation-chart="chart_tc_${id}"]`)).toHaveCount(1);
}
const manager = page.getByRole("dialog", { name: "图表管理", exact: true });
await expect(manager).toBeVisible();
await expect(manager.getByRole("group", { name: "压力七日同时刻对照(m)", exact: true })).toBeVisible();
await expect(page.locator("[data-floating-window]")).toHaveCount(1);
await manager.getByRole("button", { name: "关闭窗口", exact: true }).click();
const panel = page.getByLabel("调查实时展示", { exact: true });
await panel.getByRole("button", { name: "放大查看 压力七日同时刻对照(m)", exact: true }).click();
const pressure = page.getByRole("dialog", { name: "压力七日同时刻对照(m)", exact: true });
const flow = page.getByRole("dialog", { name: "管流七日同时刻对照(m³/h)", exact: true });
await expect(pressure).toBeVisible();
await expect(flow).toHaveCount(0);
await expect(page.locator("[data-floating-window]")).toHaveCount(1);
if (width < 640) await pressure.getByRole("button", { name: "最大化窗口", exact: true }).click();
await expect(pressure.getByLabel("选择图表对象").getByRole("button")).toHaveCount(5);
const objects = pressure.getByLabel("选择图表对象");
const select = objects.getByRole("button", { name: "切换对象 175618", exact: true });
const bounds = await pressure.boundingBox();
await select.click();
expect(await pressure.boundingBox()).toEqual(bounds);
await expect(select).toHaveAttribute("aria-pressed", "true");
await expect(objects.getByRole("button", { pressed: true })).toHaveCount(1);
await expect(pressure.getByRole("img", { name: "175618 压力七日同时刻对照(m)", exact: true })).toBeVisible();
const legends = pressure.getByLabel("图表图例");
await expect(legends.getByRole("button")).toHaveCount(8);
const drawing = pressure.getByRole("img", { name: "175618 压力七日同时刻对照(m)", exact: true });
const plotBox = (await drawing.boundingBox())!;
const legendBox = (await legends.boundingBox())!;
const objectBox = (await objects.boundingBox())!;
expect(legendBox.y).toBeGreaterThanOrEqual(plotBox.y + plotBox.height - 1);
if (width > 640) expect(objectBox.x).toBeGreaterThanOrEqual(plotBox.x + plotBox.width);
else expect(objectBox.y).toBeGreaterThanOrEqual(legendBox.y + legendBox.height - 1);
expect(plotBox.height).toBeGreaterThanOrEqual(120);
expect(await pressure.evaluate((node) => node.scrollWidth - node.clientWidth)).toBeLessThanOrEqual(1);
await page.evaluate(() => document.fonts.ready);
await testInfo.attach(`grouped-pressure-${width}`, { body: await pressure.screenshot({ path: testInfo.outputPath(`grouped-pressure-${width}.png`) }), contentType: "image/png" });
await legends.getByRole("button", { name: "175618 2026-07-09", exact: true }).click();
await expect(legends.getByRole("button", { name: "175618 2026-07-09", exact: true })).toHaveAttribute("aria-pressed", "false");
await pressure.getByRole("tab", { name: "数据", exact: true }).click();
await expect(pressure.getByRole("table").getByRole("row")).toHaveCount(14);
await expect(pressure.getByRole("table")).toContainText("2026-07-16 08:00:00+08:00");
await objects.getByRole("button", { name: "切换对象 159673", exact: true }).focus();
await page.keyboard.press("Enter");
await expect(pressure.getByRole("img", { name: "159673 压力七日同时刻对照(m)", exact: true })).toBeVisible();
await mock.emit(task, { action: "close_chart", chart_id: "chart_tc_159673" });
await expect(objects.getByRole("button")).toHaveCount(4);
await expect(objects.getByRole("button", { pressed: true })).toHaveCount(1);
await expect(panel.getByText("部分未完成", { exact: true })).toHaveCount(0);
await pressure.getByRole("button", { name: "关闭窗口", exact: true }).click();
await panel.getByRole("button", { name: "关闭图表 压力七日同时刻对照(m)", exact: true }).click();
await expect(panel.locator('[data-investigation-chart^="chart_tc_1"]')).toHaveCount(0);
await expect(panel.locator("[data-investigation-chart]")).toHaveCount(5);
expect(mock.mutations).toEqual([]);
});
}