feat(settings): 设置与个人信息模块审计重构 — i18n + 服务注入解耦 + Error Boundary + 流式渲染

- 新增 SettingsService 接口 + Context 注入,组件层不再直接 import users/messaging actions

- 新增 resolveRoleSettingsConfig 配置驱动角色路由,删除 parent/student/teacher-settings-view 冗余文件

- 新增 SettingsSectionErrorBoundary,每个 TabsContent + profile 角色概览区块均包裹

- 新增 ProfileStudentOverview/ProfileTeacherOverview 异步 Server Component + 骨架屏,支持流式渲染

- 抽取 buildStudentOverviewData 等纯函数到 lib/student-overview-data.ts,便于单元测试

- 新增 settings.json 翻译文件(zh-CN + en),所有组件改用 useTranslations/getTranslations

- 重构 profile/page.tsx:i18n 适配 + Suspense 分区加载 + 业务逻辑抽离

- 同步更新架构图 004/005
This commit is contained in:
SpecialX
2026-06-22 16:15:36 +08:00
parent 21c7e65fee
commit 5d42495480
29 changed files with 2445 additions and 1094 deletions

View File

@@ -2735,6 +2735,14 @@
"createExamAction"
]
},
{
"name": "addExamQuestions",
"signature": "addExamQuestions(examId: string, items: Array<{ questionId: string; score: number; order: number }>): Promise<void>",
"purpose": "批量插入考试-题目关联(跨模块写接口,供 lesson-preparation/publish-service 调用,避免直查 examQuestions 表)",
"usedBy": [
"lesson-preparation/publish-service.publishLessonPlanHomework"
]
},
{
"name": "persistAiGeneratedExamDraft",
"signature": "persistAiGeneratedExamDraft(input: { examId, title, creatorId, subjectId, gradeId, scheduledAt?, description, structure, generated }): Promise<void>",
@@ -6258,56 +6266,125 @@
"usedBy": [
"data-access.getAiProviderForUpdate"
]
},
{
"name": "SettingsService",
"file": "types.ts",
"type": "interface",
"definition": "设置模块统一服务接口profile + notifications + trackEvent通过 React Context 注入实现解耦",
"usedBy": [
"components/settings-service-context.tsx",
"app/(dashboard)/settings/page.tsx"
]
},
{
"name": "ProfileService",
"file": "types.ts",
"type": "interface",
"definition": "个人资料服务接口getProfile + updateProfile解耦组件对 users/actions 的直接依赖",
"usedBy": [
"types.SettingsService",
"components/profile-settings-form.tsx"
]
},
{
"name": "NotificationPreferenceService",
"file": "types.ts",
"type": "interface",
"definition": "通知偏好服务接口getPreferences + updatePreferences解耦组件对 messaging/actions 的直接依赖",
"usedBy": [
"types.SettingsService",
"components/notification-preferences-form.tsx"
]
}
],
"components": [
{
"name": "AiProviderSettingsCard",
"purpose": "AI Provider设置卡片"
"purpose": "AI Provider设置卡片i18nsettings.ai.providers"
},
{
"name": "AdminSettingsView",
"purpose": "系统设置视图(学校信息/安全策略/文件上传/通知配置 4 个 Card模拟保存;消费方:/admin/settings 页面)",
"purpose": "系统设置视图(学校信息/安全策略/文件上传/通知配置 4 个 Cardi18n;消费方:/admin/settings 页面)",
"usedBy": [
"app/(dashboard)/admin/settings/page.tsx"
]
},
{
"name": "ProfileSettingsForm",
"purpose": "个人资料设置表单"
"purpose": "个人资料设置表单(通过 useSettingsService().profile.updateProfile 调用i18nsettings.profile",
"deps": [
"useSettingsService",
"shared/components/form-fields/text-field",
"shared/components/form-fields/select-field"
]
},
{
"name": "ThemePreferencesCard",
"purpose": "主题偏好卡片"
"purpose": "主题偏好卡片i18nsettings.appearance"
},
{
"name": "StudentSettingsView",
"purpose": "学生设置视图(含 Notifications tab"
},
{
"name": "TeacherSettingsView",
"purpose": "教师设置视图(含 Notifications tab"
},
{
"name": "ParentSettingsView",
"purpose": "家长设置视图(复用 SettingsView 布局backHref 指向 /parent/dashboard含家长专属快捷链接消费方/settings 页面 parent 角色分支)",
"name": "SettingsView",
"purpose": "统一设置页布局5 标签页General/Notifications/Appearance/Security/AI角色差异通过 resolveRoleSettingsConfig 配置驱动 + generalExtra props 注入Tab URL 持久化;每个 TabsContent 包裹 SettingsSectionErrorBoundary + Suspense 骨架屏AI 标签页条件渲染需 AI_CONFIGURE 权限;登出 AlertDialog 二次确认i18nsettings 命名空间)",
"usedBy": [
"app/(dashboard)/settings/page.tsx"
]
},
{
"name": "SettingsView",
"purpose": "统一设置页布局5 标签页General/Notifications/Appearance/Security/AI角色差异通过 description/backHref/generalExtra 三个 props 注入Tab 通过 URL ?tab= 参数持久化AI 标签页条件渲染需 AI_CONFIGURE 权限;登出按钮使用 AlertDialog 二次确认4 个消费方admin/teacher/student/parent 设置页)",
"name": "SettingsServiceProvider",
"file": "components/settings-service-context.tsx",
"purpose": "SettingsService React Context Provider页面层注入服务实现组件层通过 useSettingsService() 消费",
"usedBy": [
"AdminSettingsView",
"TeacherSettingsView",
"StudentSettingsView",
"ParentSettingsView"
"app/(dashboard)/settings/page.tsx"
]
},
{
"name": "SettingsSectionErrorBoundary",
"file": "components/settings-section-error-boundary.tsx",
"purpose": "分区 Error Boundary包裹每个 TabsContent 和 profile 角色概览区块,局部失败不影响整页",
"usedBy": [
"components/settings-view.tsx",
"app/(dashboard)/profile/page.tsx"
]
},
{
"name": "QuickLinksCard",
"file": "components/quick-links-card.tsx",
"purpose": "快捷链接卡片客户端组件i18n 键驱动settings.quickLinks",
"usedBy": [
"config/role-settings-config.tsx"
]
},
{
"name": "ProfileStudentOverview",
"file": "components/profile-student-overview.tsx",
"purpose": "学生概览异步 Server Component独立获取学生数据并渲染StatsGrid + UpcomingAssignments + Grades + TodaySchedule可被 Suspense + ErrorBoundary 包裹实现流式渲染",
"deps": [
"classes/data-access.getStudentClasses",
"classes/data-access.getStudentSchedule",
"homework/data-access.getStudentHomeworkAssignments",
"homework/data-access.getStudentDashboardGrades",
"lib/student-overview-data.buildStudentOverviewData"
],
"usedBy": [
"app/(dashboard)/profile/page.tsx"
]
},
{
"name": "ProfileTeacherOverview",
"file": "components/profile-teacher-overview.tsx",
"purpose": "教师概览异步 Server Component独立获取教师数据并渲染任教科目 + 任教班级),可被 Suspense + ErrorBoundary 包裹",
"deps": [
"classes/data-access.getTeacherClasses",
"classes/data-access.getTeacherTeachingSubjects"
],
"usedBy": [
"app/(dashboard)/profile/page.tsx"
]
},
{
"name": "PasswordChangeForm",
"purpose": "密码修改表单(当前密码/新密码/确认密码 + 强度指示器 + 需求提示)",
"purpose": "密码修改表单(当前密码/新密码/确认密码 + 强度指示器 + 需求提示i18nsettings.securitya11yaria-label",
"deps": [
"changePasswordAction",
"getPasswordStrength",
@@ -6317,17 +6394,14 @@
{
"name": "NotificationPreferencesForm",
"file": "components/notification-preferences-form.tsx",
"purpose": "通知偏好设置表单Switch 切换 email/sms/push 通道 + 5 个分类开关:作业/成绩/公告/消息/考勤;隐藏 checkbox 与 Switch 同步useActionState 调用 updateNotificationPreferencesAction",
"purpose": "通知偏好设置表单Switch 切换 email/sms/push 通道 + 5 个分类开关;通过 useSettingsService().notifications.updatePreferences 调用i18nsettings.notifications",
"deps": [
"updateNotificationPreferencesAction",
"useSettingsService",
"shared/components/ui/switch",
"shared/components/ui/card",
"react.useActionState"
"shared/components/ui/card"
],
"usedBy": [
"TeacherSettingsView",
"StudentSettingsView",
"ParentSettingsView"
"SettingsView"
]
}
]
@@ -12083,17 +12157,17 @@
},
{
"name": "buildInitialContent",
"file": "data-access.ts",
"file": "lib/document-migration.tsdata-access.ts re-export",
"purpose": "基于模板构建初始课案内容v2 nodes+edges"
},
{
"name": "migrateV1ToV2",
"file": "data-access.ts",
"purpose": "v1→v2 迁移:将旧 blocks 数组转换为 nodes + 线性 edges节点按网格布局"
"file": "lib/document-migration.tsdata-access.ts re-export",
"purpose": "v1→v2 迁移:将旧 blocks 数组转换为 nodes + 线性 edges节点按网格布局,使用类型守卫 isV1Document/isV2Document 替代 as 断言"
},
{
"name": "normalizeDocument",
"file": "data-access.ts",
"file": "lib/document-migration.tsdata-access.ts re-export",
"purpose": "规范化:确保 content 为 v2 格式,兼容旧 v1 数据(自动调用 migrateV1ToV2"
},
{
@@ -12149,7 +12223,7 @@
{
"name": "publishLessonPlanHomework",
"file": "publish-service.ts",
"purpose": "发布课案为作业(编排 homework/exams/classes"
"purpose": "发布课案为作业(编排 homework/exams/classes,通过对方 data-access 调用 addExamQuestions/getStudentIdsByClassIds无直查跨模块表"
},
{
"name": "suggestKnowledgePoints",
@@ -12264,6 +12338,10 @@
"types.ts",
"constants.ts",
"schema.ts",
"lib/document-migration.ts",
"lib/node-summary.ts",
"lib/rf-mappers.ts",
"config/block-registry.tsx",
"data-access.ts",
"data-access-versions.ts",
"data-access-templates.ts",
@@ -12283,6 +12361,8 @@
"components/node-editor.tsx",
"components/node-edit-panel.tsx",
"components/nodes/lesson-node.tsx",
"components/lesson-plan-error-boundary.tsx",
"components/lesson-plan-skeleton.tsx",
"components/block-renderer.tsx",
"components/template-picker.tsx",
"components/version-history-drawer.tsx",
@@ -13027,7 +13107,11 @@
"dependsOn": [
"shared",
"auth",
"messaging"
"classes",
"homework",
"dashboard",
"users",
"notifications"
],
"uses": {
"shared": [
@@ -13035,17 +13119,41 @@
"auth-guard",
"ai",
"types",
"components.ui.switch"
"components.ui.switch",
"components.ui.card",
"components.ui.tabs",
"components.ui.alert-dialog",
"components.form-fields"
],
"auth": [
"auth"
],
"messaging": [
"notification-preferences.getNotificationPreferences",
"actions.getNotificationPreferencesAction",
"actions.updateNotificationPreferencesAction"
"classes": [
"data-access.getStudentClasses",
"data-access.getStudentSchedule",
"data-access.getTeacherClasses",
"data-access.getTeacherTeachingSubjects"
],
"homework": [
"data-access.getStudentHomeworkAssignments",
"data-access.getStudentDashboardGrades"
],
"dashboard": [
"components.student-dashboard.student-grades-card",
"components.student-dashboard.student-stats-grid",
"components.student-dashboard.student-today-schedule-card",
"components.student-dashboard.student-upcoming-assignments-card"
],
"users": [
"data-access.UserProfile",
"data-access.UpdateUserProfileInput"
],
"notifications": [
"types.NotificationPreferences",
"types.UpdateNotificationPreferencesInput"
]
}
},
"note": "组件层通过 SettingsService 接口注入解耦,不直接 import messaging/actions页面层 app/(dashboard)/settings/page.tsx 负责注入 users/actions + messaging/actions 实现"
},
"users": {
"dependsOn": [