包含 classes/exams/homework/grades/attendance/scheduling 域、outbox、iam-consumer、redis 配置等完整实现
61 lines
1.7 KiB
TypeScript
61 lines
1.7 KiB
TypeScript
/**
|
||
* 考试状态机(纯函数)
|
||
*
|
||
* 状态流转(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<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;
|