/** * 考试状态机(纯函数) * * 状态流转(ISSUE-003 仲裁 scheme A): * draft → published → in_progress → grading → graded → archived * └→ cancelled(终态) * cancelled 可从 published/in_progress/grading 流入(异常终止) * * archived 为软删除终态(ISSUE-006 决策 #7:archived 仅做软删除,不物理删除) */ export type ExamStatus = | "draft" | "published" | "in_progress" | "grading" | "graded" | "archived" | "cancelled"; export type ExamAction = "publish" | "start" | "submit" | "grade" | "archive" | "cancel"; const TRANSITIONS: Record< ExamStatus, Partial> > = { draft: { publish: "published", cancel: "cancelled" }, published: { start: "in_progress", cancel: "cancelled" }, in_progress: { submit: "grading", cancel: "cancelled" }, grading: { grade: "graded", cancel: "cancelled" }, graded: { archive: "archived" }, archived: {}, cancelled: {}, }; export function canTransition(from: ExamStatus, action: ExamAction): boolean { return TRANSITIONS[from]?.[action] !== undefined; } export function transition(from: ExamStatus, action: ExamAction): ExamStatus { const next = TRANSITIONS[from]?.[action]; if (!next) { throw new Error(`Invalid exam state transition: ${from} --${action}-->`); } return next; } export function isTerminal(status: ExamStatus): boolean { return status === "archived" || status === "cancelled"; } export const EXAM_STATUSES: readonly ExamStatus[] = [ "draft", "published", "in_progress", "grading", "graded", "archived", "cancelled", ] as const;