feat(workbench): integrate runtime data and map tooling

This commit is contained in:
2026-09-22 10:45:46 +08:00
parent bf44cc0f25
commit bebcf2a06c
163 changed files with 15642 additions and 1312 deletions
@@ -24,13 +24,29 @@ const workOrder: ScheduledConditionItem = {
updatedAt: 1,
durationMinutes: 40,
source: "调度方案",
location: "边界阀门 BV-07",
dispatcher: "调度",
assignee: "班组",
priority: "urgent",
replyWindowMinutes: 20,
stages: [],
replyRequirements: []
subtasks: [{
id: "work-1-subtask-1",
title: "调整阀门开度",
summary: "现场调整并记录开度。",
status: "running",
scheduledAt: "2026-08-19T10:00:00.000Z",
location: "边界阀门 BV-07",
assignee: "班组",
durationMinutes: 40,
replyWindowMinutes: 20,
stages: [{
id: "execution",
sequence: 1,
title: "执行",
status: "current",
owner: "班组",
timeLabel: "10:00 - 10:40",
description: "现场调整阀门。"
}],
replyRequirements: ["回传阀门开度"]
}]
};
describe("operational timeline model", () => {
@@ -176,10 +176,13 @@ function createConditionEvents(item: ScheduledConditionRecord): OperationalEvent
}
function createWorkOrderEvents(item: ScheduledWorkOrderItem): OperationalEvent[] {
const subtask = getRepresentativeWorkOrderSubtask(item);
const planEvent: OperationalEvent = {
id: `plan-${item.id}`,
title: item.title,
description: `${item.location} · ${item.assignee}`,
description: subtask
? `${subtask.title} · ${subtask.location} · ${subtask.assignee}`
: item.summary,
lane: "plan",
status: "planned",
importance: item.priority === "urgent" ? "important" : "normal",
@@ -210,8 +213,8 @@ function createWorkOrderEvents(item: ScheduledWorkOrderItem): OperationalEvent[]
cursorTime: actualTime,
description:
item.status === "running"
? `${item.assignee}正在执行,位置:${item.location}`
: `${item.assignee}已完成现场执行,等待调度复令`
? `${subtask?.assignee ?? "执行班组"}正在执行,位置:${subtask?.location ?? "待确认"}`
: `${subtask?.assignee ?? "执行班组"}已完成现场执行,等待调度复令`
};
return [planEvent, actualEvent];
@@ -228,13 +231,32 @@ function getConditionMapTargets(item: ScheduledConditionRecord): FeatureTarget[]
}
function getWorkOrderMapTargets(item: ScheduledWorkOrderItem): FeatureTarget[] {
if (item.location.includes("阀")) {
return [{ sourceId: "valves", featureId: extractAssetId(item.location) }];
}
if (item.location.includes("流量计")) {
return [{ sourceId: "scada", featureId: extractAssetId(item.location) }];
}
return [];
const targets = item.subtasks.flatMap((subtask): FeatureTarget[] => {
if (subtask.location.includes("阀")) {
return [{ sourceId: "valves", featureId: extractAssetId(subtask.location) }];
}
if (subtask.location.includes("流量计")) {
return [{ sourceId: "scada", featureId: extractAssetId(subtask.location) }];
}
return [];
});
return targets.filter((target, index) =>
targets.findIndex((candidate) =>
candidate.sourceId === target.sourceId && candidate.featureId === target.featureId
) === index
);
}
function getRepresentativeWorkOrderSubtask(item: ScheduledWorkOrderItem) {
return item.subtasks.find((subtask) => subtask.status === "running")
?? item.subtasks.find((subtask) => subtask.status === "blocked")
?? item.subtasks.find((subtask) =>
subtask.stages.some((stage) => stage.status === "current")
)
?? item.subtasks.find((subtask) => subtask.status === "pending")
?? item.subtasks.at(-1)
?? null;
}
function extractAssetId(location: string) {