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
@@ -0,0 +1,284 @@
import type { AnswerUiBlock } from "@/features/agent";
import type { InvestigationPresentationCommand } from "../api/investigation-presentation";
import type { InvestigationMapTarget } from "../api/investigation-report";
import {
createInvestigationDevSample,
createPresentationRecord,
createUiRecord,
normalizeDevCenter,
serializeInvestigationDevJsonl
} from "./investigation-dev-preview";
export const investigationDevCases = [
{
id: "combined",
label: "组合联动",
expected: "合成空间点、压力曲线、候选表格与数据一同展示;有调查地图目标时同时高亮。"
},
{
id: "map_targets",
label: "地图定位与高亮",
expected: "显示地图中心附近的合成点,并高亮所选调查已有的地图目标;无目标时仅显示合成点。"
},
{
id: "pressure_line",
label: "压力趋势对比",
expected: "打开两条合成压力曲线,核对时间轴、单位、图例和数据表。"
},
{
id: "impact_bar",
label: "影响用户统计",
expected: "打开合成用户数柱状图;统计仅供展示测试,不是实际停水户数。"
},
{
id: "impact_area",
label: "合成影响范围",
expected: "在当前地图中心附近显示一个合成面;不代表真实隔离边界。"
},
{
id: "complaint_heatmap",
label: "投诉热力分布",
expected: "显示三个带非负权重的合成投诉点,按热力模式渲染。"
},
{
id: "candidates_table",
label: "候选管段对比",
expected: "展示两条合成候选数据和对比表格,不查询或高亮虚拟管段。"
},
{
id: "valves_table",
label: "隔离阀门清单",
expected: "展示两条合成阀门数据和核查表格,不执行关阀或发布处置方案。"
},
{
id: "data_only",
label: "纯 JSONL 数据",
expected: "仅展示候选与影响数据;数据行中出现 action 字段也不会触发地图动作。"
},
{
id: "invalid_json",
label: "错误:JSON 语法",
expected: "第 2 行报语法错误,整批不执行;可点击执行验证拦截结果。"
},
{
id: "invalid_command",
label: "错误:不支持的动作",
expected: "第 1 行展示指令被拒绝,不执行任意命令。"
},
{
id: "invalid_chart",
label: "错误:图表数据不齐",
expected: "第 1 行图表校验失败,时间轴和序列长度不一致时不能执行。"
}
] as const;
export type InvestigationDevCaseId = (typeof investigationDevCases)[number]["id"];
const jsonl = serializeInvestigationDevJsonl;
const presentation = createPresentationRecord;
// Invalid cases deliberately bypass the validated writer to exercise rejection.
const invalidJsonl = (records: unknown[]) =>
records.map((record) => JSON.stringify(record)).join("\n");
const data = (record_type: string, fields: Record<string, unknown>) => ({
record_type,
origin: "synthetic",
source_evidence_refs: [],
...fields
});
function table(id: string, title: string, columns: string[], rows: string[][]): unknown {
const block: AnswerUiBlock = {
version: "answer-ui@1",
block_id: `dev-case-${id}`,
fallback_text: `${title},仅供本地展示测试。`,
spec: {
root: "table",
elements: {
table: { type: "Table", props: { title, columns, rows }, children: [] }
}
}
};
return createUiRecord(block);
}
/** Fixtures use current map coordinates and existing task targets, never invented query IDs. */
export function createInvestigationDevCase(
caseId: InvestigationDevCaseId,
center: [number, number],
target?: InvestigationMapTarget
): string {
const [longitude, latitude] = normalizeDevCenter(center);
if (caseId === "combined") return createInvestigationDevSample([longitude, latitude], target);
const point = (dx = 0, dy = 0): [number, number] => [
Math.max(-180, Math.min(180, longitude + dx)),
latitude + dy
];
const overlay = (
mode: "geometry" | "heatmap",
title: string,
features: Extract<
InvestigationPresentationCommand,
{ action: "set_overlay" }
>["data"]["features"]
) =>
presentation({
action: "set_overlay",
overlay_id: `dev-case-${caseId}`,
title,
mode,
evidence_id: "dev:synthetic",
data: { type: "FeatureCollection", features }
});
switch (caseId) {
case "map_targets":
return jsonl([
...(target
? [
presentation({
action: "highlight_features",
layer: target.source_id,
feature_ids: [target.feature_id],
effect: "pulse"
})
]
: []),
overlay("geometry", "本地合成定位点", [
{
type: "Feature",
properties: { origin: "synthetic" },
geometry: { type: "Point", coordinates: point() }
}
])
]);
case "pressure_line":
return jsonl([
presentation({
action: "open_chart",
chart_id: "dev-case-pressure-line",
evidence_refs: ["dev:synthetic"],
chart: {
title: "本地合成压力对比",
chart_type: "line",
x_data: ["08:00", "08:15", "08:30", "08:45"],
series: [
{ name: "异常日压力水头(m)", data: [32, 18, 22, 30] },
{ name: "基线压力水头(m)", data: [33, 32, 32, 33] }
]
}
})
]);
case "impact_bar":
return jsonl([
presentation({
action: "open_chart",
chart_id: "dev-case-impact-bar",
evidence_refs: ["dev:synthetic"],
chart: {
title: "本地合成影响用户统计",
chart_type: "bar",
x_data: ["合成片区 A", "合成片区 B", "合成片区 C"],
series: [{ name: "合成用户数(户)", data: [120, 80, 45] }]
}
})
]);
case "impact_area":
return jsonl([
overlay("geometry", "本地合成影响范围", [
{
type: "Feature",
properties: { origin: "synthetic", purpose: "display_test_only" },
geometry: {
type: "Polygon",
coordinates: [
[
point(-0.002, -0.0015),
point(0.002, -0.0015),
point(0.002, 0.0015),
point(-0.002, 0.0015),
point(-0.002, -0.0015)
]
]
}
}
])
]);
case "complaint_heatmap":
return jsonl([
overlay(
"heatmap",
"本地合成投诉热力",
[-0.0015, 0, 0.0015].map((offset, index) => ({
type: "Feature",
properties: { origin: "synthetic", weight: [1, 3, 2][index] },
geometry: { type: "Point", coordinates: point(offset, offset / 2) }
}))
)
]);
case "candidates_table":
return jsonl([
table(
"candidates",
"合成候选管段对比",
["候选", "优先级", "核查依据"],
[
["DEMO-PIPE-01", "1", "合成压力降幅较大,待核查"],
["DEMO-PIPE-02", "2", "合成相关性较弱,待排除"]
]
),
data("candidate", { element_id: "DEMO-PIPE-01", rank: 1, status: "unverified" }),
data("candidate", { element_id: "DEMO-PIPE-02", rank: 2, status: "unverified" })
]);
case "valves_table":
return jsonl([
table(
"valves",
"合成隔离阀门清单",
["阀门", "操作建议", "核查要求"],
[
["DEMO-VALVE-01", "待评估", "位置与可操作性未核实"],
["DEMO-VALVE-02", "待评估", "连通性与影响范围未核实"]
]
),
data("valve", { element_id: "DEMO-VALVE-01", status: "unverified", executed: false }),
data("valve", { element_id: "DEMO-VALVE-02", status: "unverified", executed: false })
]);
case "data_only":
return jsonl([
data("candidate", {
element_id: "DEMO-PIPE-03",
action: "clear_highlights",
status: "data_only"
}),
data("impact", {
item: "合成片区 A",
estimated_users: 120,
unit: "户",
status: "example_only"
})
]);
case "invalid_json":
return `${jsonl([presentation({ action: "clear_highlights" })])}\n{"record_type":"candidate",`;
case "invalid_command":
return invalidJsonl([
{ record_type: "presentation", command: { action: "unsupported_test_action" } }
]);
case "invalid_chart":
return invalidJsonl([
{
record_type: "presentation",
command: {
action: "open_chart",
chart_id: "dev-invalid-chart",
evidence_refs: ["dev:synthetic"],
chart: {
title: "错误案例:数据长度不齐",
chart_type: "line",
x_data: ["08:00", "08:15"],
series: [{ name: "合成压力水头(m)", data: [32] }]
}
}
}
]);
}
}