Files
Edu/services/core-edu/src/exams/exam-state-machine.ts
SpecialX 58c0ba1bd9 feat(core-edu): 完整实现 core-edu 教学核心服务
包含 classes/exams/homework/grades/attendance/scheduling 域、outbox、iam-consumer、redis 配置等完整实现
2026-07-10 19:08:56 +08:00

61 lines
1.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 考试状态机(纯函数)
*
* 状态流转ISSUE-003 仲裁 scheme A
* draft → published → in_progress → grading → graded → archived
* └→ cancelled终态
* cancelled 可从 published/in_progress/grading 流入(异常终止)
*
* archived 为软删除终态ISSUE-006 决策 #7archived 仅做软删除,不物理删除)
*/
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<Record<ExamAction, ExamStatus>>
> = {
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;