feat(dashboard): 仪表盘模块审计重构 — 权限校验 + i18n + 逻辑抽离

基于 dashboard-audit-report.md 审计结论,对仪表盘模块进行 P0/P1 级修复:

- 新增 4 个 dashboard 权限点(DASHBOARD_ADMIN/TEACHER/STUDENT/PARENT_READ),补充到 permissions.ts 和角色-权限映射

- 新建 actions.ts:4 个 Server Action 均调用 requirePermission() 校验权限,消除 admin 页面零鉴权、teacher/student/parent 仅 requireAuth 的安全隐患

- 根重定向页 /dashboard 改用 resolvePermissions() + 权限点判断,不再 role === xxx 硬编码

- 新建 lib/dashboard-utils.ts:抽取 toWeekday / countStudentAssignments / sortUpcomingAssignments / filterTodaySchedule / computeTeacherMetrics / getGreetingKey 纯函数,与 UI 分离,便于单测

- 新建 messages/{zh-CN,en}/dashboard.json 翻译文件,i18n request.ts 加载 dashboard 命名空间;所有视图组件接入 useTranslations / getTranslations,消除中英混杂硬编码

- 重构 4 个角色 page.tsx:通过 actions 获取数据,generateMetadata 使用 i18n

- 同步更新架构图 004 / 005 文档(dashboard exports / permissions / 文件清单)
This commit is contained in:
SpecialX
2026-06-22 15:50:56 +08:00
parent 2548f70f40
commit 868ac5f9cf
28 changed files with 1507 additions and 399 deletions

View File

@@ -121,7 +121,11 @@
"LESSON_PLAN_READ": "lesson_plan:read",
"LESSON_PLAN_UPDATE": "lesson_plan:update",
"LESSON_PLAN_DELETE": "lesson_plan:delete",
"LESSON_PLAN_PUBLISH": "lesson_plan:publish"
"LESSON_PLAN_PUBLISH": "lesson_plan:publish",
"DASHBOARD_ADMIN_READ": "dashboard:admin_read",
"DASHBOARD_TEACHER_READ": "dashboard:teacher_read",
"DASHBOARD_STUDENT_READ": "dashboard:student_read",
"DASHBOARD_PARENT_READ": "dashboard:parent_read"
},
"rolePermissions": {
"admin": [
@@ -176,7 +180,8 @@
"ELECTIVE_MANAGE",
"ELECTIVE_READ",
"EXAM_PROCTOR",
"EXAM_PROCTOR_READ"
"EXAM_PROCTOR_READ",
"DASHBOARD_ADMIN_READ"
],
"teacher": [
"EXAM_CREATE",
@@ -216,7 +221,8 @@
"ELECTIVE_MANAGE",
"ELECTIVE_READ",
"EXAM_PROCTOR",
"EXAM_PROCTOR_READ"
"EXAM_PROCTOR_READ",
"DASHBOARD_TEACHER_READ"
],
"student": [
"EXAM_READ",
@@ -236,7 +242,8 @@
"MESSAGE_DELETE",
"DIAGNOSTIC_READ",
"ELECTIVE_SELECT",
"ELECTIVE_READ"
"ELECTIVE_READ",
"DASHBOARD_STUDENT_READ"
],
"parent": [
"EXAM_READ",
@@ -248,7 +255,8 @@
"ATTENDANCE_READ",
"MESSAGE_SEND",
"MESSAGE_READ",
"MESSAGE_DELETE"
"MESSAGE_DELETE",
"DASHBOARD_PARENT_READ"
],
"grade_head": [
"EXAM_CREATE",
@@ -5724,8 +5732,96 @@
},
"dashboard": {
"path": "src/modules/dashboard",
"description": "各角色仪表盘数据聚合与展示",
"description": "各角色仪表盘数据聚合与展示(含权限校验 + i18n + 纯逻辑工具函数)",
"exports": {
"actions": [
{
"name": "getAdminDashboardAction",
"signature": "() => Promise<AdminDashboardData>",
"deps": [
"shared/lib/auth-guard.requirePermission",
"dashboard/data-access.getAdminDashboardData",
"Permissions.DASHBOARD_ADMIN_READ"
],
"usedBy": [
"admin/dashboard/page.tsx"
]
},
{
"name": "getTeacherDashboardAction",
"signature": "() => Promise<TeacherDashboardData & { metrics: TeacherDashboardMetrics }>",
"deps": [
"shared/lib/auth-guard.requirePermission",
"classes/data-access.getTeacherClasses/getClassSchedule/getTeacherIdForMutations",
"homework/data-access.getHomeworkAssignments/getHomeworkSubmissions/getTeacherGradeTrends",
"users/data-access.getUserBasicInfo",
"dashboard/lib/dashboard-utils.computeTeacherMetrics",
"Permissions.DASHBOARD_TEACHER_READ"
],
"usedBy": [
"teacher/dashboard/page.tsx"
]
},
{
"name": "getStudentDashboardAction",
"signature": "() => Promise<{ student, dashboardProps }>",
"deps": [
"shared/lib/auth-guard.requirePermission",
"users/data-access.getCurrentStudentUser",
"classes/data-access.getStudentClasses/getStudentSchedule",
"homework/data-access.getStudentHomeworkAssignments/getStudentDashboardGrades",
"dashboard/lib/dashboard-utils.countStudentAssignments/sortUpcomingAssignments/toWeekday/filterTodaySchedule",
"Permissions.DASHBOARD_STUDENT_READ"
],
"usedBy": [
"student/dashboard/page.tsx"
]
},
{
"name": "getParentDashboardAction",
"signature": "() => Promise<{ data, hasChildren }>",
"deps": [
"shared/lib/auth-guard.requirePermission",
"parent/data-access.getParentDashboardData",
"Permissions.DASHBOARD_PARENT_READ"
],
"usedBy": [
"parent/dashboard/page.tsx"
]
}
],
"lib": [
{
"name": "toWeekday",
"signature": "(d: Date) => Weekday",
"purpose": "Date 转 1-7 周几(周一=1周日=7"
},
{
"name": "countStudentAssignments",
"signature": "(assignments, now, dueSoonWindowDays?) => StudentAssignmentStats",
"purpose": "单次遍历统计学生作业:即将到期/已逾期/已批改"
},
{
"name": "sortUpcomingAssignments",
"signature": "(assignments, limit?) => StudentHomeworkAssignmentListItem[]",
"purpose": "按截止日期升序排序取前 N 条"
},
{
"name": "filterTodaySchedule",
"signature": "(schedule, weekday, classNameById?) => StudentTodayScheduleItem[] | TeacherTodayScheduleItem[]",
"purpose": "筛选指定周几课表并按开始时间排序"
},
{
"name": "computeTeacherMetrics",
"signature": "(classes, schedule, assignments, submissions, gradeTrends, now) => TeacherDashboardMetrics",
"purpose": "计算教师仪表盘派生指标:待批改数/进行中作业/平均分/提交率/今日课表/待批改列表"
},
{
"name": "getGreetingKey",
"signature": "(now: Date) => 'morning' | 'afternoon' | 'evening'",
"purpose": "根据当前小时返回问候语时段 key"
}
],
"dataAccess": [
{
"name": "getAdminDashboardData",
@@ -5740,7 +5836,7 @@
"DataScope"
],
"usedBy": [
"admin/dashboard/page.tsx"
"dashboard/actions.getAdminDashboardAction"
]
}
],