feat(portal-shell): homework 模块 7 页迁移(教师域 §9.1 B2)

§9.1 教师域 homework 模块完整迁移(继 exams 之后第二个 B2 模块):

7 页路由结构(与旧 teacher-portal 同构):
- /shell/teacher/homework:列表页(?classId/status/q 筛选)
- /shell/teacher/homework/new:布置作业表单页
- /shell/teacher/homework/[id]:详情 + 内联批改(含提交列表 + recordGrade 表单)
- /shell/teacher/homework/submissions:跨作业提交评审列表
- /shell/teacher/homework/submissions/[submissionId]:单份提交批改 + AI 建议 + 上下份导航
- /shell/teacher/homework/submissions/[submissionId]/scan-grading:扫描批改工作台(三栏)
- /shell/teacher/homework/assignments/[id]/submissions:按作业批量批改 + 统计 + AI 批量评分

数据契约(混合):
-  homework(id: ID!) 真实查询(schema 已就绪,详情页用)
-  列表/mutation/submissions/grading/aiBatchGrading 全部 @contract-pending MSW 兜底
  · 9 个 hook 走 MSW,待后端补齐 mutation 后切换真实 fetcher

§11.3 DoD 11 项验收:
1. route-permissions:EXACT + PREFIX 表 /shell/teacher/homework 已配置
2. 页面模板:list/new 用 ListPageShell/FormPageShell;detail/grading 用 DetailPageShell;
   scan-grading 用 WorkbenchPageShell(三栏,未使用 emptyNode)
3. 三态:loading(Skeleton)/error(errorNode 或 errorSummary)/empty(emptyNode) 全实现
4. lib/api hooks:homework.ts 10 个 hooks(useHomework 真实 + 9 个 MSW)
5. @contract-pending MSW:graphql-data.ts 扩展 6 块 mock + 10 个 switch case
6. i18n:homework 节点扩展 8 个分区共 130+ keys(list/detail/new/submissions/grading/
   scan/assignment/error)中英对齐
7. lint:0 errors(4 warnings 在 __generated__)
8. lint:tokens:0 errors
9. notify:mutation 反馈走 @/shared/lib/notify(非 sonner 直引)
10. vitest:transformations 纯函数单测齐全,全量 323/323 通过(新增 ~50 测试)
11. typecheck:0 errors(noUncheckedIndexedAccess 安全访问)

附带修复:
- 修复 2 处遗留 broken link:
  · widgets/sidebar/quick-actions: /homework/new → /shell/teacher/homework/new
  · widgets/topbar/global-search: /homework → /shell/teacher/homework
- scripts/check-page-count.ts baseline 同步 13 → 26(与 exams 6 + homework 7 一致)

剩余模块:grades(5)+lesson-plans(6)+questions(1)+textbooks(2)+attendance(4)+classes(3)+
students(1)+course-plans(2)+elective(3)+error-book(1)+diagnostic(2)+analytics(2)+ai-*(3)+
knowledge-graph(1)+practice(1)+schedule-changes(1)+leave(1) 共 39 页。
This commit is contained in:
SpecialX
2026-07-22 18:11:15 +08:00
parent dca25fc42f
commit 081cb5fbc3
28 changed files with 4810 additions and 6 deletions

View File

@@ -302,7 +302,215 @@
}
},
"homework": {
"title": "Homework"
"title": "Homework",
"list": {
"title": "Homework",
"description": "View and manage all homework",
"new": "Assign Homework",
"searchPlaceholder": "Search homework name...",
"statusFilter": "Filter by status",
"statusAll": "All statuses",
"statusDraft": "Draft",
"statusPublished": "Published",
"statusClosed": "Closed",
"statusArchived": "Archived",
"total": "{count} total",
"colName": "Name",
"colStatus": "Status",
"colDueDate": "Due Date",
"colGracePeriod": "Grace Period",
"colActions": "Actions",
"viewDetail": "View Detail →",
"mswNotice": "List query contract is pending, please ensure NEXT_PUBLIC_MSW=1 is enabled."
},
"detail": {
"title": "Homework Detail",
"edit": "Edit",
"notFound": "Homework not found, may have been deleted",
"createdAtPrefix": "Created on {date}",
"sectionBasic": "Basic Info",
"sectionSubmissions": "Submissions",
"sectionInlineGrade": "Inline Grade",
"fieldTitle": "Title",
"fieldDescription": "Description",
"fieldDueDate": "Due Date",
"fieldGracePeriod": "Grace Period",
"fieldStatus": "Status",
"fieldClassId": "Class ID",
"fieldSubjectId": "Subject ID",
"fieldCreatedBy": "Created By",
"fieldUpdatedAt": "Updated At",
"viewAllSubmissions": "All Submissions",
"noSubmissions": "No submissions yet",
"colStudent": "Student",
"colStatus": "Status",
"colSubmittedAt": "Submitted At",
"colScore": "Score",
"colActions": "Actions",
"grade": "Grade",
"gradeStudentId": "Student ID",
"gradeScore": "Score",
"gradeFeedback": "Feedback",
"gradeFeedbackPlaceholder": "Write feedback to the student...",
"gradeSubmit": "Submit Grade",
"gradeSubmitting": "Submitting...",
"gradeSuccess": "Grade submitted successfully",
"gradeError": "Grading failed",
"gradeErrorStudentRequired": "Please fill in Student ID",
"gradeErrorScoreInvalid": "Score is invalid, please enter a non-negative number",
"gradeContractPending": "Grade contract is @contract-pending, currently backed by MSW."
},
"new": {
"title": "Assign Homework",
"description": "Fill in homework basic information",
"submit": "Assign",
"success": "Homework assigned successfully",
"error": "Assignment failed",
"classId": "Class ID",
"subjectId": "Subject ID",
"titleLabel": "Title",
"titlePlaceholder": "e.g. Set and Function Practice",
"descriptionLabel": "Description",
"descriptionPlaceholder": "Scope, notes, etc.",
"dueDate": "Due Date",
"gracePeriod": "Grace Period (hours)",
"gracePeriodHint": "Hours of grace after the deadline, 0 means no grace",
"errorClassRequired": "Please fill in Class ID",
"errorTitleRequired": "Please fill in homework title",
"errorDateRequired": "Please select due date",
"contractPending": "Assign homework contract is @contract-pending, currently backed by MSW. Will switch to real submission once backend mutation is ready."
},
"submissions": {
"title": "Submission Grading",
"description": "View all homework submissions and grade them",
"searchPlaceholder": "Search student/no/homework...",
"classIdFilter": "Filter by class",
"classIdPlaceholder": "Class ID",
"statusFilter": "Filter by status",
"statusAll": "All statuses",
"statusSubmitted": "Submitted",
"statusGrading": "Grading",
"statusGraded": "Graded",
"statusReturned": "Returned",
"statusLate": "Late",
"total": "{count} total",
"colStudent": "Student",
"colHomework": "Homework",
"colClass": "Class",
"colStatus": "Status",
"colSubmittedAt": "Submitted At",
"colScore": "Score",
"colActions": "Actions",
"toGrade": "Grade",
"mswNotice": "Submission query contract is pending, please ensure NEXT_PUBLIC_MSW=1 is enabled."
},
"grading": {
"title": "Grade: {name}",
"titleLoading": "Loading grade...",
"subtitle": "Homework: {homework} · No.: {no}",
"notFound": "Submission not found, may have been deleted",
"sectionStudent": "Student Info",
"sectionAnswers": "Answers",
"sectionNavigation": "Navigation",
"fieldStudentName": "Name",
"fieldStudentNo": "Student No.",
"fieldClass": "Class",
"fieldHomework": "Homework",
"fieldStatus": "Status",
"fieldSubmittedAt": "Submitted At",
"fieldFeedback": "Current Feedback",
"questionType": "Type",
"maxScore": "Max Score",
"maxScoreTotal": "Total Max",
"studentAnswer": "Student Answer",
"score": "Score",
"teacherComment": "Teacher Comment",
"overallFeedback": "Overall Feedback",
"overallFeedbackPlaceholder": "Write overall feedback to the student...",
"applyAi": "Apply AI Suggestion",
"aiSuggestionLabel": "AI Suggestion",
"aiSuggestionApplied": "AI suggestion applied",
"prev": "Previous",
"next": "Next",
"position": "{current}/{total}",
"submit": "Submit Grade",
"submitting": "Submitting...",
"success": "Grade submitted successfully",
"error": "Grading failed",
"errorScoreInvalid": "Score for question {qid} is invalid",
"contractPending": "Grading contract is @contract-pending, currently backed by MSW."
},
"scan": {
"title": "Scan Grade: {name}",
"titleLoading": "Loading scan grade...",
"subtitle": "Homework: {homework}",
"notFound": "Submission not found, may have been deleted",
"scanPreview": "Scan Preview",
"imagePlaceholder": "Scan image (submissionId: {id})",
"imageContractPending": "Scan image preview contract is @contract-pending, currently a placeholder.",
"recognizedAnswers": "Recognized Answers",
"recognizedAnswer": "Recognized Answer",
"recognizedCorrect": "Recognized correct",
"recognizedIncorrect": "Recognized incorrect",
"questionType": "Type",
"aiSuggestionLabel": "AI Suggestion",
"noAnswers": "No answer data",
"gradingForm": "Grading Form",
"scoreLabel": "Score for {qid}",
"totalScore": "Current Total",
"applyAllAi": "Apply All AI Suggestions",
"aiAppliedCount": "Applied {count} AI suggestions",
"confidence": "Confidence",
"overallFeedback": "Overall Feedback",
"overallFeedbackPlaceholder": "Write overall feedback to the student...",
"save": "Save Grade",
"saving": "Saving...",
"saveSuccess": "Scan grading saved successfully",
"saveError": "Save failed",
"errorScoreInvalid": "Score for question {qid} is invalid",
"unitScore": "pts",
"contractPending": "Scan grading contract is @contract-pending, currently backed by MSW."
},
"assignment": {
"title": "Batch Grading by Homework",
"description": "Homework: {title}",
"descriptionLoading": "Loading homework info...",
"backToHomework": "Back to Homework Detail",
"total": "{count} submissions",
"mswNotice": "Assignment submissions query contract is pending, please ensure NEXT_PUBLIC_MSW=1 is enabled.",
"sectionHomework": "Homework Info",
"sectionSubmissions": "Submissions",
"sectionAiGrading": "AI Batch Grading",
"homeworkTitle": "Title",
"homeworkId": "Homework ID",
"className": "Class",
"dueDate": "Due Date",
"colStudent": "Student",
"colStatus": "Status",
"colSubmittedAt": "Submitted At",
"colScore": "Score",
"colActions": "Actions",
"scanGrade": "Scan Grade",
"detailGrade": "Detail Grade",
"statsTotalStudents": "Expected",
"statsSubmitted": "Submitted",
"statsGraded": "Graded",
"statsPending": "Pending",
"statsAvgScore": "Avg",
"statsSubmissionRate": "Submission Rate",
"aiBatchGrade": "Batch Auto Grade",
"aiTriggered": "AI grading request triggered",
"aiSummary": "Processed {processed}/{total}, avg confidence {avg}",
"aiEmpty": "No AI suggestions yet, click the button to trigger",
"aiContractPending": "AI grading contract is @contract-pending, currently backed by MSW.",
"suggestedScore": "Suggested",
"confidence": "Confidence"
},
"error": {
"title": "Homework page error",
"unknown": "Unknown error",
"retry": "Retry"
}
},
"grades": {
"title": "Grades"

View File

@@ -302,7 +302,215 @@
}
},
"homework": {
"title": "作业管理"
"title": "作业管理",
"list": {
"title": "作业管理",
"description": "查看和管理所有作业",
"new": "布置作业",
"searchPlaceholder": "搜索作业名称...",
"statusFilter": "按状态筛选",
"statusAll": "全部状态",
"statusDraft": "草稿",
"statusPublished": "已发布",
"statusClosed": "已关闭",
"statusArchived": "已归档",
"total": "共 {count} 条",
"colName": "名称",
"colStatus": "状态",
"colDueDate": "截止时间",
"colGracePeriod": "宽限期",
"colActions": "操作",
"viewDetail": "查看详情 →",
"mswNotice": "列表查询契约待补齐,请确认 NEXT_PUBLIC_MSW=1 已启用。"
},
"detail": {
"title": "作业详情",
"edit": "编辑",
"notFound": "未找到作业,可能已被删除",
"createdAtPrefix": "创建于 {date}",
"sectionBasic": "基本信息",
"sectionSubmissions": "提交列表",
"sectionInlineGrade": "内联批改",
"fieldTitle": "标题",
"fieldDescription": "描述",
"fieldDueDate": "截止时间",
"fieldGracePeriod": "宽限期",
"fieldStatus": "状态",
"fieldClassId": "班级 ID",
"fieldSubjectId": "科目 ID",
"fieldCreatedBy": "创建人",
"fieldUpdatedAt": "更新时间",
"viewAllSubmissions": "全部提交",
"noSubmissions": "暂无提交",
"colStudent": "学生",
"colStatus": "状态",
"colSubmittedAt": "提交时间",
"colScore": "分数",
"colActions": "操作",
"grade": "去批改",
"gradeStudentId": "学生 ID",
"gradeScore": "分数",
"gradeFeedback": "反馈",
"gradeFeedbackPlaceholder": "给学生写下评语...",
"gradeSubmit": "提交批改",
"gradeSubmitting": "提交中...",
"gradeSuccess": "批改成功",
"gradeError": "批改失败",
"gradeErrorStudentRequired": "请填写学生 ID",
"gradeErrorScoreInvalid": "分数无效,请输入非负数字",
"gradeContractPending": "批改契约为 @contract-pending当前通过 MSW 兜底。"
},
"new": {
"title": "布置作业",
"description": "填写作业基本信息",
"submit": "布置作业",
"success": "作业布置成功",
"error": "布置失败",
"classId": "班级 ID",
"subjectId": "科目 ID",
"titleLabel": "标题",
"titlePlaceholder": "例如:集合与函数练习",
"descriptionLabel": "描述",
"descriptionPlaceholder": "作业范围、注意事项等",
"dueDate": "截止时间",
"gracePeriod": "宽限期(小时)",
"gracePeriodHint": "超过截止时间后的宽限小时数0 表示无宽限期",
"errorClassRequired": "请填写班级 ID",
"errorTitleRequired": "请填写作业标题",
"errorDateRequired": "请选择截止时间",
"contractPending": "布置作业契约为 @contract-pending当前通过 MSW 兜底。后端补齐 mutation 后将切换为真实提交。"
},
"submissions": {
"title": "提交批改",
"description": "查看所有作业的提交记录并批改",
"searchPlaceholder": "搜索学生姓名/学号/作业...",
"classIdFilter": "按班级筛选",
"classIdPlaceholder": "班级 ID",
"statusFilter": "按状态筛选",
"statusAll": "全部状态",
"statusSubmitted": "已提交",
"statusGrading": "批改中",
"statusGraded": "已批改",
"statusReturned": "已退回",
"statusLate": "迟交",
"total": "共 {count} 条",
"colStudent": "学生",
"colHomework": "作业",
"colClass": "班级",
"colStatus": "状态",
"colSubmittedAt": "提交时间",
"colScore": "分数",
"colActions": "操作",
"toGrade": "去批改",
"mswNotice": "提交查询契约待补齐,请确认 NEXT_PUBLIC_MSW=1 已启用。"
},
"grading": {
"title": "批改:{name}",
"titleLoading": "批改加载中...",
"subtitle": "作业:{homework} · 学号:{no}",
"notFound": "未找到提交,可能已被删除",
"sectionStudent": "学生信息",
"sectionAnswers": "题目作答",
"sectionNavigation": "翻页",
"fieldStudentName": "姓名",
"fieldStudentNo": "学号",
"fieldClass": "班级",
"fieldHomework": "作业",
"fieldStatus": "状态",
"fieldSubmittedAt": "提交时间",
"fieldFeedback": "当前反馈",
"questionType": "题型",
"maxScore": "满分",
"maxScoreTotal": "总分",
"studentAnswer": "学生作答",
"score": "分数",
"teacherComment": "教师评语",
"overallFeedback": "整体反馈",
"overallFeedbackPlaceholder": "给学生写下整体评语...",
"applyAi": "采用 AI 建议",
"aiSuggestionLabel": "AI 建议",
"aiSuggestionApplied": "已应用 AI 建议",
"prev": "上一份",
"next": "下一份",
"position": "第 {current}/{total} 份",
"submit": "提交批改",
"submitting": "提交中...",
"success": "批改成功",
"error": "批改失败",
"errorScoreInvalid": "题目 {qid} 的分数无效",
"contractPending": "批改契约为 @contract-pending当前通过 MSW 兜底。"
},
"scan": {
"title": "扫描批改:{name}",
"titleLoading": "扫描批改加载中...",
"subtitle": "作业:{homework}",
"notFound": "未找到提交,可能已被删除",
"scanPreview": "扫描预览",
"imagePlaceholder": "扫描图submissionId: {id}",
"imageContractPending": "扫描图片预览契约为 @contract-pending当前用占位符。",
"recognizedAnswers": "已识别答案",
"recognizedAnswer": "已识别答案",
"recognizedCorrect": "识别正确",
"recognizedIncorrect": "识别错误",
"questionType": "题型",
"aiSuggestionLabel": "AI 建议",
"noAnswers": "暂无作答数据",
"gradingForm": "批改表单",
"scoreLabel": "题目 {qid} 分数",
"totalScore": "当前总分",
"applyAllAi": "采用全部 AI 建议",
"aiAppliedCount": "已应用 {count} 条 AI 建议",
"confidence": "置信度",
"overallFeedback": "整体反馈",
"overallFeedbackPlaceholder": "给学生写下整体评语...",
"save": "保存批改",
"saving": "保存中...",
"saveSuccess": "扫描批改保存成功",
"saveError": "保存失败",
"errorScoreInvalid": "题目 {qid} 的分数无效",
"unitScore": "分",
"contractPending": "扫描批改契约为 @contract-pending当前通过 MSW 兜底。"
},
"assignment": {
"title": "按作业批量批改",
"description": "作业:{title}",
"descriptionLoading": "加载作业信息...",
"backToHomework": "返回作业详情",
"total": "共 {count} 份提交",
"mswNotice": "按作业提交查询契约待补齐,请确认 NEXT_PUBLIC_MSW=1 已启用。",
"sectionHomework": "作业信息",
"sectionSubmissions": "提交列表",
"sectionAiGrading": "AI 批量评分",
"homeworkTitle": "作业标题",
"homeworkId": "作业 ID",
"className": "班级",
"dueDate": "截止时间",
"colStudent": "学生",
"colStatus": "状态",
"colSubmittedAt": "提交时间",
"colScore": "分数",
"colActions": "操作",
"scanGrade": "扫描批改",
"detailGrade": "详情批改",
"statsTotalStudents": "应交人数",
"statsSubmitted": "已交人数",
"statsGraded": "已批改",
"statsPending": "待批改",
"statsAvgScore": "平均分",
"statsSubmissionRate": "提交率",
"aiBatchGrade": "批量自动评分",
"aiTriggered": "AI 评分请求已触发",
"aiSummary": "已处理 {processed}/{total} 份,平均置信度 {avg}",
"aiEmpty": "暂无 AI 评分建议,点击右侧按钮触发",
"aiContractPending": "AI 评分契约为 @contract-pending当前通过 MSW 兜底。",
"suggestedScore": "建议分数",
"confidence": "置信度"
},
"error": {
"title": "作业页面出错了",
"unknown": "未知错误",
"retry": "重试"
}
},
"grades": {
"title": "成绩查询"