Files
NextEdu/src/instrumentation.ts
SpecialX a60105455e feat(exams,homework,parent): V3 审计深度修复 — 批量批改/考试分析/提交反馈/家长视图/移动端优化
V3-5: exam-actions.tsx 集成 useExamHomeworkFeatures hook,按角色控制菜单项可见性
V3-7: 批量批改 — 新增 batchAutoGradeSubmissions data-access + Server Action + HomeworkBatchGradingView 组件
V3-8: 考试分析仪表盘 — 新增 getExamAnalytics stats-service + ExamAnalyticsDashboard 组件 + /teacher/exams/[id]/analytics 路由
V3-9: 提交后即时反馈页 — 新增 HomeworkSubmissionResult 组件 + /student/learning/assignments/[id]/result 路由
V3-11: 家长考试详情 — 新增 ChildExamDetail 组件 + getStudentExamResults data-access + child-detail-panel exams Tab
V3-12: 移动端触控优化 — 题目导航与考试操作按钮 44px 最小触控目标

修复: instrumentation.ts 适配器补全 questionCount/averageScore/overdueCount 字段
修复: exam-homework-port.ts 类型导入对齐 ExamWithQuestionsForHomework
修复: trend-line-chart.tsx 数据类型允许 undefined(classAverage 可选场景)

同步更新 004/005 架构文档
2026-06-23 01:06:27 +08:00

81 lines
2.7 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Next.js Instrumentation 钩子
*
* 在应用启动时执行一次性初始化操作。
* 文档https://nextjs.org/docs/app/building-your-application/optimizing/instrumentation
*
* V3-3: 注册 ExamHomeworkServicePort 实现
* 将 modules 层的 data-access 函数注入到 shared 层的 ServicePort
* 使 app 层可以通过 EXAM_HOMEWORK_SERVICE_PROVIDER.get() 调用,
* 而不直接依赖 modules 内部实现。
*/
import { registerExamHomeworkService } from "@/shared/services/exam-homework-port"
import { getExamById, getExams, getExamCreatorId, getExamTitleById } from "@/modules/exams/data-access"
import {
getHomeworkAssignmentById,
getHomeworkAssignments,
getAssignmentMaxScoreById,
} from "@/modules/homework/data-access"
import { getExamWithQuestionsForHomework } from "@/modules/exams/data-access"
import type { DataScope } from "@/shared/types/permissions"
import type { Exam } from "@/modules/exams/types"
import type { HomeworkAssignmentListItem } from "@/modules/homework/types"
/**
* 适配器:将 getExamById 的返回值补全为 Exam 类型
* data-access 返回的对象包含 questions 数组但缺少 questionCount 字段
*/
const adaptExam = (raw: Awaited<ReturnType<typeof getExamById>>): Exam | null => {
if (!raw) return null
return {
...raw,
questionCount: raw.questions?.length ?? 0,
}
}
/**
* 适配器:将 getHomeworkAssignmentById 的返回值补全为 HomeworkAssignmentListItem 类型
* data-access 返回的对象缺少 averageScore 和 overdueCount 字段
*/
const adaptAssignment = (raw: Awaited<ReturnType<typeof getHomeworkAssignmentById>>): HomeworkAssignmentListItem | null => {
if (!raw) return null
return {
id: raw.id,
sourceExamId: raw.sourceExamId,
sourceExamTitle: raw.sourceExamTitle,
title: raw.title,
status: raw.status,
availableAt: raw.availableAt,
dueAt: raw.dueAt,
allowLate: raw.allowLate,
lateDueAt: raw.lateDueAt,
maxAttempts: raw.maxAttempts,
createdAt: raw.createdAt,
updatedAt: raw.updatedAt,
targetCount: raw.targetCount,
submittedCount: raw.submittedCount,
gradedCount: raw.gradedCount,
averageScore: null,
overdueCount: 0,
}
}
export async function register(): Promise<void> {
registerExamHomeworkService({
// 考试
getExamById: async (id: string, scope?: DataScope) => adaptExam(await getExamById(id, scope)),
getExams,
getExamCreatorId,
getExamTitleById,
// 作业
getHomeworkAssignmentById: async (id: string, scope?: DataScope) => adaptAssignment(await getHomeworkAssignmentById(id, scope)),
getHomeworkAssignments,
getAssignmentMaxScoreByIds: getAssignmentMaxScoreById,
// 跨模块
getExamWithQuestionsForHomework,
})
}