refactor(attendance,elective): 审计第二轮 — 全量完成 P0/P1 改进项

P0 修复:
- 页面层 i18n 全量补齐(admin/teacher/parent/student × attendance/elective)
- types.ts 状态标签常量迁移至 constants.ts(i18n key + Badge variant)
- 修复 getTranslations 导入路径(next-intl → next-intl/server)

P1 改进:
- 解耦 parent 模块对 attendance 类型的直接依赖(本地 view-model 类型)
- 导出纯函数(computeStats/buildWarnings/buildLotteryRankCase 等)
- 统一空状态为 EmptyState 组件
- 清理死代码读 Action(attendance 5 个 + elective 3 个)
- 预留监控埋点接口(trackEvent 13 个新事件名)
- 补齐骨架屏 loading.tsx(8 个页面)
- AlertDialog 替换 window.confirm(student-selection-view)
- a11y 改进(aria-label/role/键盘导航)

修复:
- AttendanceStatus 从 constants.ts 重导出,消除 types/constants 双源混乱
- buildWarnings 的 Translator 类型改用 ReturnType<typeof useTranslations>
This commit is contained in:
SpecialX
2026-06-22 17:33:29 +08:00
parent 76966581b8
commit f62b8c0f86
46 changed files with 1748 additions and 545 deletions

View File

@@ -0,0 +1,65 @@
/**
* 考勤模块共享常量(消除 types.ts / attendance-sheet.tsx / attendance-filters.tsx / parent-attendance-calendar.tsx 重复定义)。
*
* 注意:标签使用 i18n key`status.*`),由组件层通过 `useTranslations("attendance")` 解析。
*/
import type { AttendanceStatus } from "./types"
/** 重导出类型,便于组件层从 constants 单点导入(消除 types/constants 双源混乱) */
export type { AttendanceStatus } from "./types"
/** 考勤状态选项(顺序即 UI 展示顺序) */
export const ATTENDANCE_STATUS_OPTIONS: AttendanceStatus[] = [
"present",
"absent",
"late",
"early_leave",
"excused",
]
/** 考勤状态 → i18n key 映射(组件层 `t(key)` 解析) */
export const ATTENDANCE_STATUS_LABEL_KEYS: Record<AttendanceStatus, string> = {
present: "status.present",
absent: "status.absent",
late: "status.late",
early_leave: "status.early_leave",
excused: "status.excused",
}
/** 考勤状态 → Badge variant 映射 */
export const ATTENDANCE_STATUS_BADGE_VARIANTS: Record<AttendanceStatus, "default" | "secondary" | "destructive" | "outline"> = {
present: "default",
absent: "destructive",
late: "secondary",
early_leave: "outline",
excused: "outline",
}
/** 考勤状态 → Tailwind 圆点颜色类 */
export const ATTENDANCE_STATUS_DOT_COLORS: Record<AttendanceStatus, string> = {
present: "bg-green-500",
absent: "bg-red-500",
late: "bg-yellow-500",
early_leave: "bg-blue-500",
excused: "bg-purple-500",
}
/** 键盘快捷键映射 */
export const ATTENDANCE_STATUS_SHORTCUTS: Record<string, AttendanceStatus> = {
p: "present",
a: "absent",
l: "late",
e: "early_leave",
x: "excused",
}
/** 初始化状态计数,避免 `{} as Record<...>` 类型断言 */
export function createInitialStatusCounts(): Record<AttendanceStatus, number> {
return {
present: 0,
absent: 0,
late: 0,
early_leave: 0,
excused: 0,
}
}