feat(charts): manage investigation charts in a scrolling workspace
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { groupInvestigationCharts } from "./investigation-chart-groups";
|
||||
import type { InvestigationChart } from "../hooks/use-investigation-presentation";
|
||||
|
||||
const comparison = (id: string, metric = "压力", unit = "m", date = "2026-07-16"): InvestigationChart => ({
|
||||
action: "open_chart", chart_id: `chart_tc_${id}`, evidence_refs: [`evidence:${id}`],
|
||||
chart: { title: `${id} ${metric}七日同时刻对照(${unit})`, chart_type: "time_comparison",
|
||||
x_axis_name: "时间", y_axis_name: `${metric}(${unit})`, x_data: ["07:45", "08:00"],
|
||||
series: [
|
||||
{ name: `${id} 当前 ${date}`, type: "line", data: [30, 25], sample_times: [`${date}T07:45:00+08:00`, `${date}T08:00:00+08:00`] },
|
||||
{ name: `${id} 2026-07-09`, type: "scatter", data: [null, 32], sample_times: [null, "2026-07-09T08:00:00+08:00"] }
|
||||
] }
|
||||
});
|
||||
|
||||
const legacyComparison = (id: string, metric = "压力", unit = "m", date = "2026-07-16") => {
|
||||
const command = comparison(id, metric, unit, date);
|
||||
command.chart.title = `${id} ${metric}三小时趋势与七天同期对照(${unit})`;
|
||||
command.chart.series[0].name = `${id} ${date.slice(5)}(${unit})`;
|
||||
command.chart.series[1].name = "07-09";
|
||||
return command;
|
||||
};
|
||||
|
||||
describe("investigation comparison groups", () => {
|
||||
it("groups pressure objects and pipe flow objects separately without changing data or evidence", () => {
|
||||
const charts = [comparison("170486"), comparison("175618"), comparison("542017", "管流", "m³/h"), comparison("486033", "管流", "m³/h")];
|
||||
const groups = groupInvestigationCharts(charts);
|
||||
expect(groups).toHaveLength(2);
|
||||
expect(groups[0].items.map((item) => item.label)).toEqual(["170486", "175618"]);
|
||||
expect(groups[1].items.map((item) => item.label)).toEqual(["542017", "486033"]);
|
||||
expect(groups[0].title).toBe("压力七日同时刻对照(m)");
|
||||
expect(groups[0].items[1].command).toBe(charts[1]);
|
||||
expect(charts[1].chart.series[1].data).toEqual([null, 32]);
|
||||
});
|
||||
|
||||
it("groups saved pressure and flow charts whose titles put the metric before the object ID", () => {
|
||||
const charts = [["170486", "压力", "m"], ["175618", "压力", "m"], ["541061", "流量", "m³/h"], ["542017", "流量", "m³/h"]].map(([id, metric, unit]) => {
|
||||
const command = comparison(id, metric, unit);
|
||||
command.chart.title = `${metric}测点 ${id} 当前曲线与前七天同期对比(${unit})`;
|
||||
return command;
|
||||
});
|
||||
const groups = groupInvestigationCharts(charts);
|
||||
expect(groups.map((group) => ({ title: group.title, objects: group.items.map((item) => item.label) }))).toEqual([
|
||||
{ title: "压力当前曲线与前七天同期对比(m)", objects: ["170486", "175618"] },
|
||||
{ title: "流量当前曲线与前七天同期对比(m³/h)", objects: ["541061", "542017"] }
|
||||
]);
|
||||
});
|
||||
|
||||
it("recognizes the same explicit object comparison in all three saved title formats", () => {
|
||||
const charts = [comparison("170486"), comparison("175618"), comparison("159673")];
|
||||
charts[0].chart.title = "170486 压力三小时与历史对照(m)";
|
||||
charts[1].chart.title = "测点 175618 压力三小时与历史对照(m)";
|
||||
charts[2].chart.title = "压力测点 159673 三小时与历史对照(m)";
|
||||
const groups = groupInvestigationCharts(charts);
|
||||
expect(groups).toHaveLength(1);
|
||||
expect(groups[0].title).toBe("压力三小时与历史对照(m)");
|
||||
expect(groups[0].items.map((item) => item.label)).toEqual(["170486", "175618", "159673"]);
|
||||
});
|
||||
|
||||
it("groups saved date-only historical labels without rewriting commands, readings or evidence", () => {
|
||||
const charts = [legacyComparison("170486"), legacyComparison("175618")];
|
||||
charts[1].chart.series[1].data[1] = 0;
|
||||
const original = structuredClone(charts);
|
||||
const groups = groupInvestigationCharts(charts);
|
||||
expect(groups).toHaveLength(1);
|
||||
expect(groups[0].items.map((item) => item.label)).toEqual(["170486", "175618"]);
|
||||
groups[0].items.forEach((item, index) => {
|
||||
expect(item.command).toBe(charts[index]);
|
||||
expect(item.command.chart.series).toBe(charts[index].chart.series);
|
||||
expect(item.command.chart.series[1].sample_times).toBe(charts[index].chart.series[1].sample_times);
|
||||
expect(item.command.evidence_refs).toBe(charts[index].evidence_refs);
|
||||
});
|
||||
expect(charts).toEqual(original);
|
||||
});
|
||||
|
||||
it("keeps legacy comparisons with different units, windows or current dates separate", () => {
|
||||
const shifted = legacyComparison("175618");
|
||||
shifted.chart.x_data = ["08:00", "08:15"];
|
||||
shifted.chart.series[0].sample_times = ["2026-07-16T08:00:00+08:00", "2026-07-16T08:15:00+08:00"];
|
||||
shifted.chart.series[1].sample_times = [null, "2026-07-09T08:15:00+08:00"];
|
||||
const charts = [legacyComparison("170486"), legacyComparison("P2", "压力", "MPa"), shifted, legacyComparison("P3", "压力", "m", "2026-07-17")];
|
||||
expect(groupInvestigationCharts(charts)).toHaveLength(charts.length);
|
||||
});
|
||||
|
||||
it("leaves ambiguous or mixed-object legacy charts and unproven historical dates separate", () => {
|
||||
const ambiguous = legacyComparison("P2"); ambiguous.chart.title = "压力测点历史对照";
|
||||
const foreign = legacyComparison("P3"); foreign.chart.series[1].name = "P4 07-09";
|
||||
const mixed = legacyComparison("P4"); mixed.chart.series.push({ ...mixed.chart.series[0], name: "P5 当前 2026-07-16" });
|
||||
const missing = legacyComparison("P5"); delete missing.chart.series[1].sample_times;
|
||||
const mismatched = legacyComparison("P6"); mismatched.chart.series[1].sample_times = [null, "2026-07-10T08:00:00+08:00"];
|
||||
const empty = legacyComparison("P7"); empty.chart.series[1].data = [null, null]; empty.chart.series[1].sample_times = [null, null];
|
||||
const sameDateInUtc8 = legacyComparison("P8"); sameDateInUtc8.chart.series[1].sample_times = [null, "2026-07-09T00:00:00Z"];
|
||||
const charts = [legacyComparison("170486"), ambiguous, foreign, mixed, missing, mismatched, empty, sameDateInUtc8];
|
||||
const groups = groupInvestigationCharts(charts);
|
||||
expect(groups).toHaveLength(charts.length - 1);
|
||||
expect(groups[0].items.map((item) => item.label)).toEqual(["170486", "P8"]);
|
||||
});
|
||||
|
||||
it("keeps incompatible units, sampling windows, comparison dates and ordinary trends separate", () => {
|
||||
const base = comparison("170486");
|
||||
const window = comparison("175618"); window.chart.x_data = ["08:00", "08:15"];
|
||||
const trend = comparison("159673"); trend.chart.series = [trend.chart.series[0]];
|
||||
expect(groupInvestigationCharts([base, comparison("P2", "压力", "MPa"), comparison("P3", "压力", "m", "2026-07-17"), window, trend])).toHaveLength(5);
|
||||
const noTimes = [comparison("P4"), comparison("P5", "压力", "m", "2026-07-17")];
|
||||
for (const command of noTimes) for (const series of command.chart.series) delete series.sample_times;
|
||||
expect(groupInvestigationCharts(noTimes)).toHaveLength(2);
|
||||
});
|
||||
|
||||
it("keeps group identity stable as objects arrive or are closed and leaves ambiguous titles alone", () => {
|
||||
const first = comparison("170486"), second = comparison("175618");
|
||||
expect(groupInvestigationCharts([first])[0].id).toBe(groupInvestigationCharts([second, first])[0].id);
|
||||
const ambiguous = comparison("159673"); ambiguous.chart.title = "压力同期对照";
|
||||
expect(groupInvestigationCharts([first, ambiguous])).toHaveLength(2);
|
||||
expect(groupInvestigationCharts([])).toEqual([]);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user