refactor(grades,diagnostic): 完成成绩和学情诊断模块审计 P1+P2 改进项

P1-1: 抽取 stats-service.ts,将 8 个统计计算纯函数从 data-access 层分离
P1-5: 创建 WidgetBoundary 组件 + 补齐 teacher 路由 loading.tsx/error.tsx (14 文件)
P1-6: 同步架构图文档 004/005,新增 stats-service 与 widget-boundary 节点
P2-1: 补充 a11y ARIA 属性(5 图表 role=img + aria-label,2 表格 caption,3 列表 role=list,3 按钮 aria-label)
P2-3: 修复班级报告 studentId 字段语义错误(schema 改为可空 + 迁移 + 代码适配)
P2-4: 修复 grade_managed scope 返回空数据(改为子查询 classes 表按 gradeId 过滤)
P2-5: 新增 /parent/diagnostic/ 页面(多子女学情诊断聚合 + loading + error)
P2-6: 统一 SearchParams 工具(student/grades 和 management/grade/insights 改用 @/shared/lib/search-params)
This commit is contained in:
SpecialX
2026-06-22 17:07:32 +08:00
parent e997abaf5e
commit 5f3a1a4662
41 changed files with 9043 additions and 381 deletions

View File

@@ -109,7 +109,7 @@ export async function generateClassDiagnosticReport(
const id = createId()
await db.insert(learningDiagnosticReports).values({
id,
studentId: generatedBy, // 班级报告 studentId 存生成者 IDschema 要求 NOT NULL
studentId: null, // 班级报告无单个学生,studentId 置空P2-3 修复:不再存生成者 ID
generatedBy,
reportType: "class",
period,
@@ -141,14 +141,16 @@ export const getDiagnosticReports = cache(
// 收集所有需要查询姓名的用户 ID学生 + 生成者),通过 users data-access 统一获取
const userIds = new Set<string>()
for (const r of rows) {
userIds.add(r.report.studentId)
if (r.report.studentId) userIds.add(r.report.studentId)
if (r.report.generatedBy) userIds.add(r.report.generatedBy)
}
const userMap = await getUserNamesByIds(Array.from(userIds))
return rows.map((r) => ({
...serializeReport(r.report),
studentName: userMap.get(r.report.studentId)?.name ?? "Unknown",
studentName: r.report.studentId
? userMap.get(r.report.studentId)?.name ?? "Unknown"
: null,
generatedByName: r.report.generatedBy
? userMap.get(r.report.generatedBy)?.name ?? "Unknown"
: null,
@@ -167,13 +169,16 @@ export const getDiagnosticReportById = cache(
if (!row) return null
// 通过 users data-access 获取学生姓名和生成者姓名
const userIds = [row.report.studentId]
const userIds: string[] = []
if (row.report.studentId) userIds.push(row.report.studentId)
if (row.report.generatedBy) userIds.push(row.report.generatedBy)
const userMap = await getUserNamesByIds(userIds)
return {
...serializeReport(row.report),
studentName: userMap.get(row.report.studentId)?.name ?? "Unknown",
studentName: row.report.studentId
? userMap.get(row.report.studentId)?.name ?? "Unknown"
: null,
generatedByName: row.report.generatedBy
? userMap.get(row.report.generatedBy)?.name ?? null
: null,