93 lines
4.3 KiB
TypeScript
93 lines
4.3 KiB
TypeScript
import type { Page } from "@playwright/test";
|
|
import { mockWorkbenchContext } from "./mock-workbench-context";
|
|
|
|
type WorkOrderPhase = "execution" | "reply";
|
|
|
|
export async function mockHierarchicalWorkOrder(page: Page, phase: WorkOrderPhase) {
|
|
const parentTitle = phase === "execution"
|
|
? "演示工单:北辰分区阀门开度调整"
|
|
: "演示工单:泵站边界复核复令";
|
|
const parentStatus = phase === "execution" ? "running" : "awaiting_reply";
|
|
const subtaskTitles = phase === "execution"
|
|
? ["上传阀门操作前后照片", "记录最终开度", "复核北辰末端压力不低于 0.22MPa"]
|
|
: ["上传泵站运行截图", "填写出水压力复核结果", "确认模型边界已同步更新"];
|
|
const activeIndex = phase === "execution" ? 1 : 2;
|
|
const scheduledAt = shanghaiTimestamp(10, 30);
|
|
const workOrderId = `mock-${phase}-work-order`;
|
|
|
|
await mockWorkbenchContext(page, {
|
|
availability: "not_configured",
|
|
source: "none",
|
|
scenario_availability: "not_configured",
|
|
artifact_availability: "not_configured",
|
|
schedule_availability: "not_configured",
|
|
work_order_availability: "ready",
|
|
alert_availability: "not_configured",
|
|
generated_at: scheduledAt,
|
|
conditions: [],
|
|
alerts: [],
|
|
scenarios: [],
|
|
latest_analysis: null,
|
|
work_orders: [{
|
|
id: workOrderId,
|
|
code: phase === "execution" ? "DEMO-EXEC-001" : "DEMO-REPLY-001",
|
|
scheduled_at: scheduledAt,
|
|
title: parentTitle,
|
|
summary: phase === "execution"
|
|
? "现场调整边界阀门并逐项复核。"
|
|
: "完成泵站边界复核并等待调度复令。",
|
|
status: parentStatus,
|
|
risk_level: phase === "execution" ? "attention" : "normal",
|
|
updated_at: scheduledAt,
|
|
detail: "浏览器测试使用的后端工单投影。",
|
|
recommendation: "按子任务逐项完成并回传。",
|
|
duration_minutes: 45,
|
|
source: "生产工单系统",
|
|
dispatcher: "调度中心",
|
|
priority: phase === "execution" ? "urgent" : "normal",
|
|
subtasks: subtaskTitles.map((title, index) => {
|
|
const position = index < activeIndex ? "before" : index > activeIndex ? "after" : "active";
|
|
const stageStatuses = phase === "execution" && position === "active"
|
|
? ["done", "current", "pending"]
|
|
: phase === "reply" && position === "active"
|
|
? ["done", "done", "current"]
|
|
: position === "before"
|
|
? ["done", "done", "done"]
|
|
: ["pending", "pending", "pending"];
|
|
|
|
return {
|
|
id: `${workOrderId}-subtask-${index + 1}`,
|
|
title,
|
|
summary: `完成“${title}”并保留阶段记录。`,
|
|
status: position === "before" ? "completed" : position === "active" ? "running" : "pending",
|
|
scheduled_at: shanghaiTimestamp(10, 30 + index * 15),
|
|
location: phase === "execution" ? "北辰分区边界阀门 BV-07" : "北辰二级泵站 P-02",
|
|
assignee: phase === "execution" ? "北辰抢修二组" : "泵站运行班组",
|
|
duration_minutes: 15,
|
|
reply_window_minutes: 20,
|
|
stages: [
|
|
{ id: "dispatch", sequence: 1, title: "派发", status: stageStatuses[0], owner: "调度中心", time_label: "10:20", description: "确认范围并派发。" },
|
|
{ id: "execution", sequence: 2, title: "执行中", status: stageStatuses[1], owner: "现场班组", time_label: "10:30-10:45", description: "现场执行本项任务。" },
|
|
{ id: "reply", sequence: 3, title: "待复令", status: stageStatuses[2], owner: "现场班组", time_label: "10:45-11:05", description: "回传结果并等待复令。" }
|
|
],
|
|
reply_requirements: [`回传“${title}”的执行结果`]
|
|
};
|
|
})
|
|
}]
|
|
});
|
|
}
|
|
|
|
function shanghaiTimestamp(hour: number, minute: number) {
|
|
const target = new Date();
|
|
const parts = new Intl.DateTimeFormat("en-CA", {
|
|
timeZone: "Asia/Shanghai",
|
|
year: "numeric",
|
|
month: "2-digit",
|
|
day: "2-digit"
|
|
}).formatToParts(target);
|
|
const get = (type: Intl.DateTimeFormatPartTypes) =>
|
|
parts.find((part) => part.type === type)?.value ?? "";
|
|
const normalizedHour = hour + Math.floor(minute / 60);
|
|
return `${get("year")}-${get("month")}-${get("day")}T${String(normalizedHour).padStart(2, "0")}:${String(minute % 60).padStart(2, "0")}:00+08:00`;
|
|
}
|