# 学情诊断(Diagnostic)模块审计报告 v2 > 审计日期:2026-06-25 > 审计范围:`src/modules/diagnostic/**`、`src/app/(dashboard)/{teacher,student,parent}/diagnostic/**` > 参照规则:`.trae/rules/project_rules.md`、`docs/architecture/004_architecture_impact_map.md` §2.22、`docs/architecture/005_architecture_data.json` > 前置文档: > - [diagnostic-audit-report.md](./diagnostic-audit-report.md)(v1,2026-06-22,3 P0 + 5 P1 + 5 P2 全部完成) > - [grades-diagnostic-audit-report-v4.md](./grades-diagnostic-audit-report-v4.md)(v4,2026-06-23,12 项 P1 全部完成) --- ## 一、现有实现概要 ### 1.1 v1/v4 已完成项回顾 v1 与 v4 审计共完成 **25 项**改进(3 P0 + 5 P1 + 5 P2 + 12 v4-P1),涵盖:跨模块 WidgetBoundary 提升到 shared、教师页面标题 i18n 化、教师 error.tsx i18n 化、as 断言消除、分享按钮移除、报告内容 i18n 驱动、Excel 导出 i18n 化、班级报告导出明细、角色配置驱动(role-config.ts)、年级诊断报告纵向切片、热力图键盘导航、DataScope 行级权限、师生关系校验、草稿隔离、通知机制、热力图图例、移动端表格滚动等。 ### 1.2 当前文件分布(v2 实测) | 层 | 文件 | 行数 | 职责 | |------|------|------|------| | 类型 | [types.ts](file:///e:/Desktop/CICD/src/modules/diagnostic/types.ts) | 126 | DiagnosticReport / Mastery / Summary 类型定义(含 v4-P2-3 GradeMasterySummary) | | 数据访问 | [data-access.ts](file:///e:/Desktop/CICD/src/modules/diagnostic/data-access.ts) | 519 | 掌握度查询 + 从提交/作业/成绩更新掌握度(含事务) | | 数据访问 | [data-access-reports.ts](file:///e:/Desktop/CICD/src/modules/diagnostic/data-access-reports.ts) | 323 | 诊断报告 CRUD + DataScope 过滤 + 结构化错误码 | | 统计服务 | [stats-service.ts](file:///e:/Desktop/CICD/src/modules/diagnostic/stats-service.ts) | 506 | 14 个纯统计函数(含年级聚合) | | Server Actions | [actions.ts](file:///e:/Desktop/CICD/src/modules/diagnostic/actions.ts) | 302 | 6 个 Action(含年级生成 + 通知) | | 校验 | [schema.ts](file:///e:/Desktop/CICD/src/modules/diagnostic/schema.ts) | 39 | 5 个 Zod schema | | 导出 | [export.ts](file:///e:/Desktop/CICD/src/modules/diagnostic/export.ts) | 175 | Excel 导出(含班级明细 3 Sheet) | | 角色配置 | [role-config.ts](file:///e:/Desktop/CICD/src/modules/diagnostic/role-config.ts) | 40 | 角色配置驱动(v4-P2-2) | | 组件 | [components/student-diagnostic-view.tsx](file:///e:/Desktop/CICD/src/modules/diagnostic/components/student-diagnostic-view.tsx) | 299 | 学生诊断视图(概览+雷达+强弱项+报告+历史) | | 组件 | [components/class-diagnostic-view.tsx](file:///e:/Desktop/CICD/src/modules/diagnostic/components/class-diagnostic-view.tsx) | 449 | 班级诊断视图(热力图+筛选+排名+关注列表+生成) | | 组件 | [components/report-list.tsx](file:///e:/Desktop/CICD/src/modules/diagnostic/components/report-list.tsx) | 373 | 报告列表(过滤+表格+发布/删除/导出) | | 组件 | [components/mastery-radar-chart.tsx](file:///e:/Desktop/CICD/src/modules/diagnostic/components/mastery-radar-chart.tsx) | 85 | 雷达图封装 | | 组件 | [components/confidence-utils.ts](file:///e:/Desktop/CICD/src/modules/diagnostic/components/confidence-utils.ts) | 31 | 置信度计算 | | 页面 | 4 个 `page.tsx` + 5 个 `loading.tsx` + 5 个 `error.tsx` | — | teacher/student/parent 三角色路由 | | i18n | [zh-CN/diagnostic.json](file:///e:/Desktop/CICD/src/shared/i18n/messages/zh-CN/diagnostic.json) + [en/diagnostic.json](file:///e:/Desktop/CICD/src/shared/i18n/messages/en/diagnostic.json) | 252 / 同步 | 翻译文件 | ### 1.3 数据流 ``` page.tsx (RSC) ├─ getStudentMasterySummary / getClassMasterySummary / getGradeMasterySummary / getKnowledgePointStats (data-access) │ └─ db (drizzle) → knowledgePointMastery / knowledgePoints 表 │ └─ 跨模块 data-access:classes / users / school / exams / homework / questions ├─ getDiagnosticReports (data-access-reports, 含 DataScope 过滤) │ └─ db → learningDiagnosticReports 表 └─ / / (client) └─ generateStudentReportAction / generateClassReportAction / generateGradeReportAction / publishReportAction / deleteReportAction / exportDiagnosticReportAction / getClassStudentsByKnowledgePointAction ``` ### 1.4 架构图记录完整性 经核对 [004_architecture_impact_map.md](file:///e:/Desktop/CICD/docs/architecture/004_architecture_impact_map.md) §2.22 与 [005_architecture_data.json](file:///e:/Desktop/CICD/docs/architecture/005_architecture_data.json) `modules.diagnostic` 节点,架构图对诊断模块的记录**基本完整**,已涵盖 v1/v4 全部修复。但本次 v2 审计发现以下偏差需后续同步: - 架构图未记录 `getDiagnosticReports` 中 `grade_managed` scope 未过滤的已知缺陷(v2-P1-1)。 - 架构图未记录 `confidence-utils.ts` 的置信度计算逻辑过于简化(v2-P1-5)。 - 架构图未记录 3 个子路由 error.tsx 仍存在硬编码中文(v2-P0-1)。 --- ## 二、现存问题与原因分析 ### 2.1 国际化 #### 问题 2.1.1 | 3 个子路由 error.tsx 硬编码中文(P0) - **位置**: - [teacher/diagnostic/class/[classId]/error.tsx#L17-22](file:///e:/Desktop/CICD/src/app/(dashboard)/teacher/diagnostic/class/[classId]/error.tsx#L17):`title="班级学情诊断加载失败"` `description="抱歉,加载班级诊断数据时发生了意外错误。请稍后重试。"` `label="重试"` - [teacher/diagnostic/student/[studentId]/error.tsx#L17-22](file:///e:/Desktop/CICD/src/app/(dashboard)/teacher/diagnostic/student/[studentId]/error.tsx#L17):`title="学生学情诊断加载失败"` 同样硬编码 - [parent/diagnostic/error.tsx#L17-22](file:///e:/Desktop/CICD/src/app/(dashboard)/parent/diagnostic/error.tsx#L17):`title="子女学情诊断加载失败"` 同样硬编码 - **现象**:三个 error.tsx 客户端组件未使用 `useTranslations`,全部硬编码中文文案。 - **违反规则**:项目规则"所有用户可见文本必须适配 i18n(使用 next-intl),提取翻译键"。 - **原因**:v1 审计 P0-3 仅修复了 `teacher/diagnostic/error.tsx`(教师报告列表页),遗漏了教师子路由和学生/家长子路由的 error.tsx。 - **后果**:英文环境下这三个错误页显示中文,与系统其他已 i18n 化的错误页风格不一致。 #### 问题 2.1.2 | i18n 标签与代码逻辑不一致(P1) - **位置**: - i18n:[zh-CN/diagnostic.json#L78](file:///e:/Desktop/CICD/src/shared/i18n/messages/zh-CN/diagnostic.json#L78):`"weaknesses": { "title": "弱项(<60%)" }` - 代码:[stats-service.ts#L83-99](file:///e:/Desktop/CICD/src/modules/diagnostic/stats-service.ts#L83):`classifyStrengthsWeaknesses` 中弱项阈值为 `< 80`(P3-16 修复:消除 60-79 盲区) - **现象**:i18n 标签显示"弱项(<60%)",但代码实际将掌握度 < 80 的知识点都归类为弱项。 - **违反规则**:项目规则"所有用户可见文本必须适配 i18n"——文本需与逻辑一致。 - **原因**:P3-16 修复弱项分类阈值时未同步更新 i18n 标签。 - **后果**:用户看到"弱项(<60%)"标签,但实际列表包含 60-79% 的知识点,造成认知混乱。 #### 问题 2.1.3 | 死 i18n 键未清理(P2) - **位置**:[zh-CN/diagnostic.json#L157-165](file:///e:/Desktop/CICD/src/shared/i18n/messages/zh-CN/diagnostic.json#L157) - **现象**:`reportList.share`、`reportList.shareAriaLabel`、`reportList.shareTitle`、`reportList.shareDescription`、`reportList.shareLinkLabel`、`reportList.copyLink`、`reportList.copyLinkSuccess`、`reportList.copyLinkFailed`、`reportList.shareLinkAriaLabel` 共 9 个键仍保留在翻译文件中,但 v1-P1-3 已移除分享按钮,这些键不再被引用。 - **违反规则**:项目规则精神——保持代码与配置一致,避免死代码。 - **原因**:移除分享按钮时未清理对应的 i18n 键。 - **后果**:翻译文件臃肿,维护成本增加;新增语言时需翻译无用的键。 #### 问题 2.1.4 | 热力图 aria-label 硬编码中文标点格式(P1) - **位置**:[class-diagnostic-view.tsx#L195](file:///e:/Desktop/CICD/src/modules/diagnostic/components/class-diagnostic-view.tsx#L195) - **现象**:`aria-label={`${kp.knowledgePointName}:${kp.averageMastery.toFixed(1)}%,${levelLabel},${kp.masteredCount}/${kp.totalStudents}`}` 使用硬编码中文全角冒号":"和逗号","。 - **违反规则**:项目规则"所有用户可见文本必须适配 i18n"。 - **原因**:aria-label 拼接时未使用 i18n 模板。 - **后果**:英文环境下屏幕阅读器读出中文标点,影响无障碍体验。 #### 问题 2.1.5 | export.ts 错误消息硬编码英文(P2) - **位置**:[export.ts#L28](file:///e:/Desktop/CICD/src/modules/diagnostic/export.ts#L28):`throw new Error("Report not found")` - **现象**:导出报告不存在时抛出硬编码英文错误。 - **违反规则**:项目规则"所有用户可见文本必须适配 i18n"。 - **后果**:中文环境下用户看到英文错误消息。 ### 2.2 权限与安全 #### 问题 2.2.1 | grade_managed DataScope 未过滤(P1,安全漏洞) - **位置**:[data-access-reports.ts#L220-238](file:///e:/Desktop/CICD/src/modules/diagnostic/data-access-reports.ts#L220) - **现象**:`getDiagnosticReports` 仅处理 `children` 和 `class_taught` 两种 DataScope,对 `grade_managed`(年级主任)和 `class_members`(学生)scope 不做任何过滤。代码注释明确写道:`// grade_managed 需要跨模块查询年级学生,由调用方自行过滤`。 - **违反规则**:项目规则"所有敏感数据查询必须在 data-access 层结合当前用户权限过滤,Server Action 二次校验"。 - **原因**:grade_managed scope 需要跨模块查询年级学生 ID(通过 `getUserIdsByGradeId`),实现时为避免跨模块依赖未在 data-access 层完成过滤。 - **后果**:年级主任(grade_head / teaching_head)角色调用时,`getDiagnosticReports` 返回全校所有学生的诊断报告,存在数据越权风险。虽然当前 teacher/diagnostic/page.tsx 在客户端对 class_members 做了二次过滤,但 grade_managed 完全未过滤。 #### 问题 2.2.2 | 教师报告列表页客户端过滤 class_members(P2) - **位置**:[teacher/diagnostic/page.tsx#L56-59](file:///e:/Desktop/CICD/src/app/(dashboard)/teacher/diagnostic/page.tsx#L56) - **现象**:`const visibleReports = ctx.dataScope.type === "class_members" ? reports.reports.filter((r) => r.studentId === ctx.userId) : reports.reports` - **违反规则**:项目规则"所有敏感数据查询必须在 data-access 层结合当前用户权限过滤"——客户端过滤不安全。 - **原因**:教师页面理论上不应被学生角色访问,但代码保留了 class_members 分支作为防御性过滤。这种过滤应在 data-access 层完成。 - **后果**:虽然不影响功能(学生不会访问教师路由),但违背了"数据过滤在 data-access 层"的原则,且 data-access 已返回了不该返回的数据。 ### 2.3 架构解耦 #### 问题 2.3.1 | 组件直接 import actions,无服务接口抽象(P1) - **位置**: - [report-list.tsx#L41](file:///e:/Desktop/CICD/src/modules/diagnostic/components/report-list.tsx#L41):`import { publishReportAction, deleteReportAction, exportDiagnosticReportAction } from "../actions"` - [class-diagnostic-view.tsx#L33](file:///e:/Desktop/CICD/src/modules/diagnostic/components/class-diagnostic-view.tsx#L33):`import { generateClassReportAction, getClassStudentsByKnowledgePointAction } from "../actions"` - **现象**:客户端组件直接 import 并调用 Server Actions,未通过接口抽象或依赖注入。 - **违反规则**:项目规则"通过定义 TypeScript 接口抽象数据依赖,使用 React Context 注入数据服务,模块内部组件绝不直接 import 其他业务模块的 actions 或 data-access(只能通过注入的接口调用)"。 - **原因**:v1 审计将此项列为"后续建议"未实施,但用户在本次审计中将其升级为强制要求。 - **后果**:组件无法独立测试(测试时必须 mock 整个 actions 模块);无法在不修改组件代码的情况下替换 actions 实现;组件与 Server Action 实现紧耦合。 ### 2.4 错误处理与边界 #### 问题 2.4.1 | 无 Error Boundary 包裹独立数据区块(P1) - **位置**: - [student-diagnostic-view.tsx](file:///e:/Desktop/CICD/src/modules/diagnostic/components/student-diagnostic-view.tsx):概览卡片、雷达图、强弱项、报告、历史列表均在同一组件内,无 Error Boundary 隔离。 - [class-diagnostic-view.tsx](file:///e:/Desktop/CICD/src/modules/diagnostic/components/class-diagnostic-view.tsx):概览、热力图、筛选、排名、关注列表、生成报告均在同一组件内。 - **现象**:仅页面级有 error.tsx 错误边界,组件内部各数据区块无独立 Error Boundary。 - **违反规则**:项目规则"每个独立的数据区块必须用 React Error Boundary 包裹"。 - **原因**:v4-P2 已将 WidgetBoundary 提升到 shared 层并用于页面级包裹,但未下沉到组件内部各数据区块。 - **后果**:雷达图渲染失败会导致整个诊断页面崩溃;热力图数据异常会波及排名表和关注列表。 #### 问题 2.4.2 | 异步数据无 Suspense + 骨架屏(P2) - **位置**:所有页面均使用 `await Promise.all` 一次性获取所有数据后传给客户端组件。 - **现象**:未使用 React Suspense 流式渲染,数据获取完成前整个页面阻塞。 - **违反规则**:项目规则"异步数据使用 React Suspense + 骨架屏"。 - **后果**:首屏白屏时间长;无法渐进式展示数据区块。 ### 2.5 可测试性与置信度 #### 问题 2.5.1 | 置信度计算过于简化(P1) - **位置**:[confidence-utils.ts#L18-21](file:///e:/Desktop/CICD/src/modules/diagnostic/components/confidence-utils.ts#L18) - **现象**:`getConfidenceLevel` 仅判断 `overallScore === null` 返回 "insufficient",否则一律返回 "high"。注释承认"后续可扩展为基于 totalQuestions 等数据量字段的多级判断",但未实施。 - **违反规则**:项目规则"数据获取、计算、格式化等纯逻辑全部放入纯函数或 hooks,与 UI 分离"——置信度计算虽已提取为纯函数,但逻辑不完整。 - **原因**:v4-P3-7 引入置信度时为简化首版,未实现多级判断。 - **后果**:仅做了 1 道题的报告也显示"高置信度",误导教师判断报告可信度。 #### 问题 2.5.2 | stats-service 14 个纯函数无单测(P2) - **位置**:[stats-service.ts](file:///e:/Desktop/CICD/src/modules/diagnostic/stats-service.ts) - **现象**:14 个纯函数(`computeAverageMastery`、`classifyStrengthsWeaknesses`、`aggregateClassMastery` 等)已正确提取为纯函数,但无对应的单元测试文件。 - **违反规则**:项目规则"可测试性:数据获取、计算、格式化等纯逻辑全部放入纯函数或 hooks,与 UI 分离;导出清晰的接口类型以便 mock"。 - **后果**:统计数据计算逻辑变更无回归保障;P3-16 弱项阈值修复这类边界 case 无法自动验证。 ### 2.6 可复用性与扩展性 #### 问题 2.6.1 | 雷达图知识点名称截断无 tooltip(P2) - **位置**:[mastery-radar-chart.tsx#L22-26](file:///e:/Desktop/CICD/src/modules/diagnostic/components/mastery-radar-chart.tsx#L22) - **现象**:`shortName: d.knowledgePoint.length > 8 ? ${d.knowledgePoint.slice(0, 8)}... : d.knowledgePoint` 截断超过 8 字符的知识点名称,但未提供 tooltip 显示完整名称。 - **违反规则**:项目规则"明确处理空数据、无权限、网络异常等边界状态"——信息截断是边界状态。 - **后果**:长名称知识点被截断,用户无法查看完整名称,影响数据理解。 #### 问题 2.6.2 | 通知类型使用 "grade" 而非专用类型(P2) - **位置**:[actions.ts#L157, L173](file:///e:/Desktop/CICD/src/modules/diagnostic/actions.ts#L157) - **现象**:`createNotification({ type: "grade", ... })` 诊断报告发布通知复用了成绩通知类型 "grade"。 - **违反规则**:项目规则精神——类型应语义准确,便于分类与过滤。 - **后果**:学生无法区分"成绩通知"和"诊断报告通知";通知筛选功能无法按类型精确过滤诊断报告。 #### 问题 2.6.3 | 无监控埋点接口(P2) - **位置**:整个模块无任何监控/埋点代码。 - **现象**:报告生成、发布、删除、导出等关键操作无埋点。 - **违反规则**:项目规则"监控:方案中预留关键操作埋点接口"。 - **后果**:无法追踪诊断报告的使用情况;无法度量报告生成/发布转化率;异常无法主动发现。 ### 2.7 parent 页面细节 #### 问题 2.7.1 | parent/diagnostic/page.tsx noRecordsTitle 与 noRecordsDescription 重复(P2) - **位置**:[parent/diagnostic/page.tsx#L97-98](file:///e:/Desktop/CICD/src/app/(dashboard)/parent/diagnostic/page.tsx#L97) - **现象**:`noRecordsTitle={t("parent.noReports")}` 和 `noRecordsDescription={t("parent.noReports")}` 使用同一个 i18n 键。 - **原因**:复制粘贴时未区分标题和描述。 - **后果**:空状态时标题和描述显示相同文本,UI 不够精细。 --- ## 三、行业差距对比 对标 PowerSchool、Infinite Campus、Skyward、Alma、智学网、班级小管家、超星学习通、ClassIn 等 K12 系统,本模块在 v1/v4 修复后仍有以下差距: | 维度 | 优秀实践 | 本模块现状 | 影响 | |------|---------|-----------|------| | **掌握度时间线** | PowerSchool/智学网支持掌握度时间线,展示知识点掌握度随时间的变化趋势,支持按知识点钻取历史 | 仅展示当前快照,`knowledgePointMastery` 表无历史版本,`lastAssessedAt` 仅记录最近一次 | 教师无法判断学生是否在进步或退步;无法评估教学干预效果 | | **个性化学习路径** | Alma/智学网基于弱项推荐具体学习资源(题目、视频、文档),形成学习路径 | 仅提供练习按钮跳转题目库,无资源推荐算法 | 推荐不够精准,学生需自行筛选练习内容 | | **学生×知识点掌握度矩阵** | Infinite Campus/Alma 提供学生×知识点矩阵热力图,支持点击单元格查看明细 | 班级视图仅有知识点聚合热力图,无学生维度矩阵 | 教师无法快速定位"哪个学生在哪个知识点上薄弱" | | **预测性分析(at-risk 预警)** | PowerSchool/Infinite Campus 基于历史数据预测 at-risk 学生,提前干预 | 无预测模型,仅基于当前掌握度 <60 判定需关注 | 无法主动预警,错失早期干预窗口 | | **报告模板自定义** | PowerSchool 支持学校自定义报告模板(推荐话术、评分区间、logo) | 报告内容固定由 stats-service 生成,仅 i18n 可切换语言 | 无法按学校需求定制报告风格 | | **多维度诊断** | Infinite Campus 结合成绩+出勤+行为做多维综合诊断 | 仅基于知识点掌握度单一维度 | 诊断维度单一,无法反映学生综合学习状态 | | **PDF 导出** | 所有对标系统支持 PDF 导出(便于打印分发) | 仅支持 Excel 导出 | 无法满足打印分发场景 | | **数据置信度可视化** | Alma 在报告上标注数据量与置信度,帮助教师判断结论可靠性 | 置信度计算过于简化(仅 null/非 null 两级) | 教师无法判断报告可信度 | | **流式渲染** | 现代 K12 系统使用 React Suspense 流式渲染,首屏快速可见 | 全部 `await Promise.all` 阻塞渲染 | 首屏白屏时间长 | --- ## 四、改进优先级建议 ### P0(紧急,影响核心规范或安全) | 编号 | 问题 | 改进方向 | |------|------|---------| | v2-P0-1 | 3 个子路由 error.tsx 硬编码中文 | 接入 `useTranslations("diagnostic")`,新增对应 i18n 键 | ### P1(重要,影响安全/解耦/一致性) | 编号 | 问题 | 改进方向 | |------|------|---------| | v2-P1-1 | grade_managed DataScope 未过滤 | 在 data-access-reports.ts 中处理 grade_managed scope,调用 `getUserIdsByGradeId` 过滤 | | v2-P1-2 | i18n 弱项标签与代码逻辑不一致 | 更新 i18n 标签为"弱项(<80%)" | | v2-P1-3 | 热力图 aria-label 硬编码中文标点 | 使用 i18n 模板键 `heatmapCellAriaLabel` | | v2-P1-4 | 组件直接 import actions 无接口抽象 | 定义 `DiagnosticService` 接口,通过 React Context 注入;组件通过 `useDiagnosticService()` 获取 | | v2-P1-5 | 置信度计算过于简化 | 基于 `totalQuestions` 实现多级置信度(<5 insufficient / 5-15 low / 16-30 medium / >30 high) | | v2-P1-6 | 无 Error Boundary 包裹独立数据区块 | 在概览、雷达图、强弱项、报告、历史等区块外包裹 WidgetBoundary | ### P2(增强,提升完整性与企业级能力) | 编号 | 问题 | 改进方向 | |------|------|---------| | v2-P2-1 | 死 i18n 键未清理 | 移除 9 个 share 相关 i18n 键 | | v2-P2-2 | 教师页面客户端过滤 class_members | 在 data-access 层过滤,移除客户端 filter | | v2-P2-3 | export.ts 错误消息硬编码 | 改用 DiagnosticReportError 结构化错误码 | | v2-P2-4 | 异步数据无 Suspense 流式渲染 | 拆分数据获取为独立 async 组件,使用 Suspense 包裹(中长期) | | v2-P2-5 | 雷达图名称截断无 tooltip | 为截断的名称添加 Tooltip 显示完整名称 | | v2-P2-6 | 通知类型使用 "grade" | 新增 "diagnostic" 通知类型(需 notifications 模块配合) | | v2-P2-7 | 无监控埋点接口 | 定义 `DiagnosticMonitor` 接口,在关键操作处调用 | | v2-P2-8 | stats-service 无单测 | 为 14 个纯函数补充单元测试 | | v2-P2-9 | parent noRecordsTitle/Description 重复 | 区分标题和描述 i18n 键 | ### P3(长期,需较大投入) | 编号 | 问题 | 改进方向 | |------|------|---------| | v2-P3-1 | 掌握度时间线 | 新增 `knowledgePointMasteryHistory` 表记录历史版本,前端展示时间线图表 | | v2-P3-2 | 个性化学习路径推荐 | 基于弱项推荐具体学习资源 | | v2-P3-3 | 学生×知识点掌握度矩阵 | 新增矩阵视图组件 | | v2-P3-4 | 预测性分析 | 基于 historical mastery 训练 at-risk 预测模型 | | v2-P3-5 | 报告模板自定义 | 允许学校配置报告模板 | | v2-P3-6 | PDF 导出 | 新增 PDF 导出能力 | --- ## 五、架构图同步说明 本次 v2 审计发现架构图需同步以下内容: ### 004_architecture_impact_map.md §2.22 1. **已知问题新增**: - 记录 v2-P0-1 三个子路由 error.tsx 硬编码中文及修复 - 记录 v2-P1-1 grade_managed DataScope 未过滤及修复 - 记录 v2-P1-4 组件解耦 Context 注入 - 记录 v2-P1-5 置信度计算改进 - 记录 v2-P1-6 数据区块 Error Boundary 包裹 2. **依赖关系更新**:标注 diagnostic 模块新增 `DiagnosticServiceContext` 依赖注入机制 ### 005_architecture_data.json 1. `modules.diagnostic.exports` 补充 `DiagnosticService` 接口、`DiagnosticServiceProvider`、`useDiagnosticService` hook 2. `modules.diagnostic.knownIssues` 新增 v2 系列问题记录 3. `modules.diagnostic.dependencies` 标注 grade_managed scope 现已调用 `getUserIdsByGradeId` 过滤 --- ## 六、实施计划 ### 6.1 本次实施范围(P0 + P1 + 可快速完成的 P2) 本次实施 **P0 全部 + P1 全部 + 6 项 P2**,P3 长期项记录备查不实施。 ### 6.2 重构方案设计(满足强制原则) #### 完全解耦 定义 TypeScript 接口 `DiagnosticService` 抽象所有数据依赖: ```typescript // src/modules/diagnostic/services/diagnostic-service.ts export interface DiagnosticService { generateStudentReport(studentId: string, period: string): Promise generateClassReport(classId: string, period: string): Promise generateGradeReport(gradeId: string, period: string): Promise publishReport(id: string): Promise deleteReport(id: string): Promise exportReport(reportId: string): Promise<{ buffer: string; filename: string }> getClassStudentsByKp(classId: string, kpId: string, threshold?: number): Promise<...> } ``` 通过 React Context 注入: ```typescript // src/modules/diagnostic/services/diagnostic-service-context.tsx const DiagnosticServiceContext = createContext(null) export function DiagnosticServiceProvider({ service, children }) { ... } export function useDiagnosticService(): DiagnosticService { ... } ``` 默认实现绑定现有 Server Actions;测试时可注入 mock 实现。 #### 组合优先 - `StudentDiagnosticView`、`ClassDiagnosticView`、`ReportList` 通过 `children` / slots 组合子区块。 - 逻辑复用提取为 `useDiagnosticActions` hook(内部调用 `useDiagnosticService()`)。 #### 国际化就绪 - 所有新增文本使用 `diagnostic.*` 命名空间翻译键。 - aria-label 模板使用 i18n 占位符:`heatmapCellAriaLabel: "{name}:{level}%,{label},{mastered}/{total}"`。 #### 最大化复用 - `DiagnosticSection` 通用区块组件(含 WidgetBoundary + Suspense + 标题 + 内容 slot)。 - `useDiagnosticActions` hook 统一封装 actions 调用 + toast + router.refresh。 #### 错误与边界处理 - 每个数据区块外包裹 `WidgetBoundary`。 - 异步子区块使用 `Suspense` + 骨架屏(本次仅在页面级流式拆分,组件级 Suspense 列入 P2-4 长期)。 #### 可测试性 - `DiagnosticService` 接口清晰,可 mock。 - `confidence-utils` 置信度计算改为基于 `totalQuestions` 的多级判断。 #### 可扩展性 - 角色差异通过 `role-config.ts` 配置驱动(v4-P2-2 已实现)。 - 通知类型、监控埋点通过接口预留扩展点。 #### 企业级补充 - a11y:热力图 aria-label i18n 化;雷达图 tooltip。 - 性能:保持 RSC 获取初始数据。 - 安全:grade_managed scope 在 data-access 层过滤。 - 监控:定义 `DiagnosticMonitor` 接口预留埋点。 ### 6.3 翻译文件结构示例 ```json { "diagnostic": { "error": { "classLoadFailed": "班级学情诊断加载失败", "classLoadFailedDesc": "抱歉,加载班级诊断数据时发生了意外错误。请稍后重试。", "studentLoadFailed": "学生学情诊断加载失败", "studentLoadFailedDesc": "抱歉,加载学生诊断数据时发生了意外错误。请稍后重试。", "parentLoadFailed": "子女学情诊断加载失败", "parentLoadFailedDesc": "抱歉,加载子女诊断数据时发生了意外错误。请稍后重试。", "retry": "重试" }, "weaknesses": { "title": "弱项(<80%)" }, "classDiagnostic": { "heatmapCellAriaLabel": "{name}:{level}%,{label},{mastered}/{total}" }, "reportList": { "radarPointTooltip": "{fullName}" } } } ```