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 架构文档
This commit is contained in:
@@ -125,18 +125,23 @@ export function HomeworkTakeView({ assignmentId, initialData }: HomeworkTakeView
|
||||
|
||||
const handleStart = async () => {
|
||||
setIsBusy(true)
|
||||
const fd = new FormData()
|
||||
fd.set("assignmentId", assignmentId)
|
||||
const res = await startHomeworkSubmissionAction(null, fd)
|
||||
if (res.success && res.data) {
|
||||
setSubmissionId(res.data)
|
||||
setSubmissionStatus("started")
|
||||
toast.success(t("homework.take.startSuccess"))
|
||||
router.refresh()
|
||||
} else {
|
||||
toast.error(res.message || t("homework.take.startFailed"))
|
||||
try {
|
||||
const fd = new FormData()
|
||||
fd.set("assignmentId", assignmentId)
|
||||
const res = await startHomeworkSubmissionAction(null, fd)
|
||||
if (res.success && res.data) {
|
||||
setSubmissionId(res.data)
|
||||
setSubmissionStatus("started")
|
||||
toast.success(t("homework.take.startSuccess"))
|
||||
router.refresh()
|
||||
} else {
|
||||
toast.error(res.message || t("homework.take.startFailed"))
|
||||
}
|
||||
} catch {
|
||||
toast.error(t("homework.take.startFailed"))
|
||||
} finally {
|
||||
setIsBusy(false)
|
||||
}
|
||||
setIsBusy(false)
|
||||
}
|
||||
|
||||
const handleSaveQuestion = async (questionId: string) => {
|
||||
@@ -156,22 +161,29 @@ export function HomeworkTakeView({ assignmentId, initialData }: HomeworkTakeView
|
||||
const handleSubmit = async () => {
|
||||
if (!submissionId) return
|
||||
setIsBusy(true)
|
||||
// P2-9: 提交前 flush 自动保存队列,确保所有答案已落库
|
||||
await autoSave.flush()
|
||||
try {
|
||||
// P2-9: 提交前 flush 自动保存队列,确保所有答案已落库
|
||||
// flush 失败应中止提交,避免丢失未保存的答案
|
||||
await autoSave.flush()
|
||||
|
||||
const submitFd = new FormData()
|
||||
submitFd.set("submissionId", submissionId)
|
||||
const submitRes = await submitHomeworkAction(null, submitFd)
|
||||
if (submitRes.success) {
|
||||
// 提交成功后清除离线缓存
|
||||
clearOfflineCache(offlineStorageKey)
|
||||
toast.success(t("homework.take.submitSuccess"))
|
||||
setSubmissionStatus("submitted")
|
||||
router.push("/student/learning/assignments")
|
||||
} else {
|
||||
toast.error(submitRes.message || t("homework.take.submitFailed"))
|
||||
const submitFd = new FormData()
|
||||
submitFd.set("submissionId", submissionId)
|
||||
const submitRes = await submitHomeworkAction(null, submitFd)
|
||||
if (submitRes.success) {
|
||||
// 提交成功后清除离线缓存
|
||||
clearOfflineCache(offlineStorageKey)
|
||||
toast.success(t("homework.take.submitSuccess"))
|
||||
setSubmissionStatus("submitted")
|
||||
// V3-9: 提交后跳转到结果页,展示即时反馈
|
||||
router.push(`/student/learning/assignments/${assignmentId}/result`)
|
||||
} else {
|
||||
toast.error(submitRes.message || t("homework.take.submitFailed"))
|
||||
}
|
||||
} catch {
|
||||
toast.error(t("homework.take.submitFailed"))
|
||||
} finally {
|
||||
setIsBusy(false)
|
||||
}
|
||||
setIsBusy(false)
|
||||
}
|
||||
|
||||
// 统计未作答题目数
|
||||
@@ -378,7 +390,7 @@ export function HomeworkTakeView({ assignmentId, initialData }: HomeworkTakeView
|
||||
if (el) el.scrollIntoView({ behavior: "smooth", block: "start" })
|
||||
}}
|
||||
className={cn(
|
||||
"h-8 w-8 rounded flex items-center justify-center text-xs font-medium border transition-colors hover:opacity-80 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1",
|
||||
"h-11 w-11 sm:h-8 sm:w-8 rounded flex items-center justify-center text-xs font-medium border transition-colors hover:opacity-80 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1",
|
||||
hasAnswer ? "bg-primary text-primary-foreground border-primary" : "bg-background text-muted-foreground border-input"
|
||||
)}
|
||||
aria-label={t("homework.take.jumpToQuestion", { index: i + 1 })}
|
||||
|
||||
Reference in New Issue
Block a user