feat(core-edu): 完整实现 core-edu 教学核心服务

包含 classes/exams/homework/grades/attendance/scheduling 域、outbox、iam-consumer、redis 配置等完整实现
This commit is contained in:
SpecialX
2026-07-10 19:08:56 +08:00
parent 06a646ea4e
commit 58c0ba1bd9
55 changed files with 4204 additions and 305 deletions

View File

@@ -0,0 +1,60 @@
/**
* 考试状态机(纯函数)
*
* 状态流转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;