feat(student-portal): 实现CICD参考项目差距功能 - 错题本/请假/选课/自适应练习/公告/课案/课程计划/成绩报告卡/学情诊断增强
This commit is contained in:
51
apps/student-portal/src/mocks/fixtures/announcements.json
Normal file
51
apps/student-portal/src/mocks/fixtures/announcements.json
Normal file
@@ -0,0 +1,51 @@
|
||||
[
|
||||
{
|
||||
"id": "an-001",
|
||||
"title": "关于期末考试安排的通知",
|
||||
"content": "各位同学:本学期期末考试将于 7 月 20 日至 7 月 25 日进行,具体科目时间安排请查看考试日程表。请同学们提前做好复习准备,注意考场纪律,携带学生证入场。",
|
||||
"type": "school",
|
||||
"status": "published",
|
||||
"authorName": "教务处",
|
||||
"publishedAt": "2026-07-10T09:00:00.000Z",
|
||||
"isPinned": true,
|
||||
"isReadByCurrentUser": false,
|
||||
"createdAt": "2026-07-10T08:30:00.000Z",
|
||||
"updatedAt": "2026-07-10T09:00:00.000Z"
|
||||
},
|
||||
{
|
||||
"id": "an-002",
|
||||
"title": "高三年级暑期辅导报名通知",
|
||||
"content": "高三年级暑期辅导班即日起开始报名,涵盖数学、物理、化学等核心科目。有意参加的同学请在 7 月 18 日前到教务处登记。名额有限,先到先得。",
|
||||
"type": "grade",
|
||||
"status": "published",
|
||||
"authorName": "年级组",
|
||||
"publishedAt": "2026-07-09T14:00:00.000Z",
|
||||
"isPinned": false,
|
||||
"isReadByCurrentUser": true,
|
||||
"createdAt": "2026-07-09T13:00:00.000Z"
|
||||
},
|
||||
{
|
||||
"id": "an-003",
|
||||
"title": "班级卫生值日调整通知",
|
||||
"content": "因近期天气炎热,本周班级卫生值日表有所调整,请值日同学按时到岗。具体安排见班级公告栏。",
|
||||
"type": "class",
|
||||
"status": "published",
|
||||
"authorName": "王老师",
|
||||
"publishedAt": "2026-07-08T10:00:00.000Z",
|
||||
"isPinned": false,
|
||||
"isReadByCurrentUser": true,
|
||||
"createdAt": "2026-07-08T09:30:00.000Z"
|
||||
},
|
||||
{
|
||||
"id": "an-004",
|
||||
"title": "校园文化艺术节活动通知",
|
||||
"content": "一年一度的校园文化艺术节将于 7 月 15 日开幕,设有歌唱、舞蹈、书法、摄影等多项比赛。欢迎同学们踊跃报名参加,报名截止日期 7 月 13 日。",
|
||||
"type": "school",
|
||||
"status": "published",
|
||||
"authorName": "校团委",
|
||||
"publishedAt": "2026-07-05T15:00:00.000Z",
|
||||
"isPinned": false,
|
||||
"isReadByCurrentUser": false,
|
||||
"createdAt": "2026-07-05T14:00:00.000Z"
|
||||
}
|
||||
]
|
||||
47
apps/student-portal/src/mocks/fixtures/coursePlans.json
Normal file
47
apps/student-portal/src/mocks/fixtures/coursePlans.json
Normal file
@@ -0,0 +1,47 @@
|
||||
[
|
||||
{
|
||||
"id": "cp-001",
|
||||
"className": "高三(2)班",
|
||||
"subjectName": "数学",
|
||||
"teacherName": "张老师",
|
||||
"semester": "1",
|
||||
"totalHours": 72,
|
||||
"completedHours": 48,
|
||||
"weeklyHours": 4,
|
||||
"startDate": "2026-02-20",
|
||||
"endDate": "2026-07-15",
|
||||
"syllabus": "高三数学上学期教学计划,涵盖函数与导数、三角函数、数列等核心章节。",
|
||||
"objectives": "掌握函数与导数的基本概念与应用,提升数学建模与解题能力。",
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"id": "cp-002",
|
||||
"className": "高三(2)班",
|
||||
"subjectName": "语文",
|
||||
"teacherName": "李老师",
|
||||
"semester": "1",
|
||||
"totalHours": 64,
|
||||
"completedHours": 52,
|
||||
"weeklyHours": 4,
|
||||
"startDate": "2026-02-20",
|
||||
"endDate": "2026-07-15",
|
||||
"syllabus": "高三语文上学期教学计划,涵盖现代文阅读、古代诗文、写作训练。",
|
||||
"objectives": "提升阅读理解与写作能力,掌握古代诗文鉴赏方法。",
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"id": "cp-003",
|
||||
"className": "高三(2)班",
|
||||
"subjectName": "英语",
|
||||
"teacherName": "刘老师",
|
||||
"semester": "1",
|
||||
"totalHours": 60,
|
||||
"completedHours": 60,
|
||||
"weeklyHours": 4,
|
||||
"startDate": "2026-02-20",
|
||||
"endDate": "2026-07-15",
|
||||
"syllabus": "高三英语上学期教学计划,涵盖语法复习、阅读理解、写作与听力训练。",
|
||||
"objectives": "系统复习语法知识,提升综合语言运用能力。",
|
||||
"status": "completed"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,45 @@
|
||||
[
|
||||
{
|
||||
"id": "dr-001",
|
||||
"reportType": "individual",
|
||||
"period": "2025-2026学年第一学期",
|
||||
"summary": "该生本学期整体学习状态良好,数学与英语表现突出,语文阅读理解有待加强。建议保持优势科目,针对薄弱环节加强练习。",
|
||||
"strengths": [
|
||||
"数学逻辑思维能力强,函数与导数章节掌握扎实",
|
||||
"英语词汇量丰富,听力与阅读理解正确率高"
|
||||
],
|
||||
"weaknesses": [
|
||||
"语文文言文阅读得分率偏低",
|
||||
"物理力学综合题解题速度需提升"
|
||||
],
|
||||
"recommendations": [
|
||||
"每周增加 2 篇文言文阅读训练",
|
||||
"针对物理力学综合题进行限时练习",
|
||||
"保持数学与英语的日常练习频率"
|
||||
],
|
||||
"overallScore": 87,
|
||||
"status": "published",
|
||||
"createdAt": "2026-05-10T10:00:00.000Z"
|
||||
},
|
||||
{
|
||||
"id": "dr-002",
|
||||
"reportType": "individual",
|
||||
"period": "2025-2026学年第二学期期中",
|
||||
"summary": "期中考试后诊断显示,该生在各科均衡发展方面有所进步,数学成绩显著提升,化学实验题仍需加强。",
|
||||
"strengths": [
|
||||
"数学成绩从 85 分提升至 92 分,进步明显",
|
||||
"英语写作能力提升,语法运用准确率提高"
|
||||
],
|
||||
"weaknesses": [
|
||||
"化学实验设计题得分率仅 60%",
|
||||
"历史材料分析题时间分配不足"
|
||||
],
|
||||
"recommendations": [
|
||||
"加强化学实验原理理解与设计训练",
|
||||
"历史答题注意时间管理,先易后难"
|
||||
],
|
||||
"overallScore": 89,
|
||||
"status": "published",
|
||||
"createdAt": "2026-05-05T14:00:00.000Z"
|
||||
}
|
||||
]
|
||||
82
apps/student-portal/src/mocks/fixtures/electiveCourses.json
Normal file
82
apps/student-portal/src/mocks/fixtures/electiveCourses.json
Normal file
@@ -0,0 +1,82 @@
|
||||
[
|
||||
{
|
||||
"id": "ec-001",
|
||||
"name": "创意写作工作坊",
|
||||
"teacherName": "李老师",
|
||||
"subjectName": "语文",
|
||||
"gradeName": "高三",
|
||||
"description": "通过沉浸式写作训练,提升文学创作与表达能力,涵盖散文、小说、诗歌等多种体裁。",
|
||||
"capacity": 30,
|
||||
"enrolledCount": 22,
|
||||
"classroom": "文科楼 305",
|
||||
"schedule": "每周三 16:00-17:40",
|
||||
"startDate": "2026-09-01",
|
||||
"endDate": "2027-01-15",
|
||||
"selectionStartAt": "2026-07-01T00:00:00.000Z",
|
||||
"selectionEndAt": "2026-07-20T23:59:59.000Z",
|
||||
"dropDeadline": "2026-09-15T23:59:59.000Z",
|
||||
"status": "open",
|
||||
"selectionMode": "fcfs",
|
||||
"credit": "2"
|
||||
},
|
||||
{
|
||||
"id": "ec-002",
|
||||
"name": "数学建模入门",
|
||||
"teacherName": "张老师",
|
||||
"subjectName": "数学",
|
||||
"gradeName": "高三",
|
||||
"description": "学习数学建模基本方法,结合实际问题进行建模实践,培养数学应用能力。",
|
||||
"capacity": 40,
|
||||
"enrolledCount": 40,
|
||||
"classroom": "理科楼 201",
|
||||
"schedule": "每周二 16:00-17:40",
|
||||
"startDate": "2026-09-01",
|
||||
"endDate": "2027-01-15",
|
||||
"selectionStartAt": "2026-07-01T00:00:00.000Z",
|
||||
"selectionEndAt": "2026-07-20T23:59:59.000Z",
|
||||
"dropDeadline": "2026-09-15T23:59:59.000Z",
|
||||
"status": "open",
|
||||
"selectionMode": "lottery",
|
||||
"credit": "3"
|
||||
},
|
||||
{
|
||||
"id": "ec-003",
|
||||
"name": "趣味物理实验",
|
||||
"teacherName": "陈老师",
|
||||
"subjectName": "物理",
|
||||
"gradeName": "高三",
|
||||
"description": "通过动手实验探索物理规律,涵盖力学、电磁学、光学等领域的经典实验。",
|
||||
"capacity": 25,
|
||||
"enrolledCount": 18,
|
||||
"classroom": "物理实验室",
|
||||
"schedule": "每周四 16:00-17:40",
|
||||
"startDate": "2026-09-01",
|
||||
"endDate": "2027-01-15",
|
||||
"selectionStartAt": "2026-07-01T00:00:00.000Z",
|
||||
"selectionEndAt": "2026-07-20T23:59:59.000Z",
|
||||
"dropDeadline": "2026-09-15T23:59:59.000Z",
|
||||
"status": "open",
|
||||
"selectionMode": "fcfs",
|
||||
"credit": "2"
|
||||
},
|
||||
{
|
||||
"id": "ec-004",
|
||||
"name": "英语演讲与辩论",
|
||||
"teacherName": "刘老师",
|
||||
"subjectName": "英语",
|
||||
"gradeName": "高三",
|
||||
"description": "提升英语口语表达与逻辑思辨能力,模拟辩论赛制进行实战训练。",
|
||||
"capacity": 20,
|
||||
"enrolledCount": 15,
|
||||
"classroom": "外语楼 102",
|
||||
"schedule": "每周五 16:00-17:40",
|
||||
"startDate": "2026-09-01",
|
||||
"endDate": "2027-01-15",
|
||||
"selectionStartAt": "2026-07-01T00:00:00.000Z",
|
||||
"selectionEndAt": "2026-07-20T23:59:59.000Z",
|
||||
"dropDeadline": "2026-09-15T23:59:59.000Z",
|
||||
"status": "open",
|
||||
"selectionMode": "fcfs",
|
||||
"credit": "2"
|
||||
}
|
||||
]
|
||||
102
apps/student-portal/src/mocks/fixtures/errorBook.json
Normal file
102
apps/student-portal/src/mocks/fixtures/errorBook.json
Normal file
@@ -0,0 +1,102 @@
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"id": "eb-001",
|
||||
"questionId": "q-101",
|
||||
"questionContent": "已知函数 f(x) = x² - 2x + 1,求 f(x) 在区间 [0, 2] 上的最小值。",
|
||||
"sourceType": "exam",
|
||||
"subject": { "id": "subject-math", "name": "数学" },
|
||||
"knowledgePointIds": ["kp-001"],
|
||||
"knowledgePointName": "二次函数最值",
|
||||
"status": "learning",
|
||||
"masteryLevel": 0.4,
|
||||
"nextReviewAt": "2026-07-14T08:00:00.000Z",
|
||||
"reviewCount": 2,
|
||||
"correctStreak": 1,
|
||||
"note": "配方时容易漏掉常数项",
|
||||
"errorTags": ["概念不清", "计算错误"],
|
||||
"createdAt": "2026-07-01T10:00:00.000Z",
|
||||
"updatedAt": "2026-07-10T14:30:00.000Z"
|
||||
},
|
||||
{
|
||||
"id": "eb-002",
|
||||
"questionId": "q-205",
|
||||
"questionContent": "阅读下面文段,回答问题:\"月光如流水一般,静静地泻在这一片叶子和花上。\" 这句话运用了什么修辞手法?",
|
||||
"sourceType": "homework",
|
||||
"subject": { "id": "subject-chinese", "name": "语文" },
|
||||
"knowledgePointIds": ["kp-201"],
|
||||
"knowledgePointName": "修辞手法辨析",
|
||||
"status": "new",
|
||||
"masteryLevel": 0.2,
|
||||
"nextReviewAt": "2026-07-13T08:00:00.000Z",
|
||||
"reviewCount": 0,
|
||||
"correctStreak": 0,
|
||||
"note": null,
|
||||
"errorTags": ["审题不清"],
|
||||
"createdAt": "2026-07-08T09:00:00.000Z",
|
||||
"updatedAt": "2026-07-08T09:00:00.000Z"
|
||||
},
|
||||
{
|
||||
"id": "eb-003",
|
||||
"questionId": "q-308",
|
||||
"questionContent": "Choose the correct word to fill in the blank: She ___ to school every day.",
|
||||
"sourceType": "exam",
|
||||
"subject": { "id": "subject-english", "name": "英语" },
|
||||
"knowledgePointIds": ["kp-301"],
|
||||
"knowledgePointName": "一般现在时",
|
||||
"status": "mastered",
|
||||
"masteryLevel": 0.9,
|
||||
"nextReviewAt": "2026-07-20T08:00:00.000Z",
|
||||
"reviewCount": 5,
|
||||
"correctStreak": 4,
|
||||
"note": null,
|
||||
"errorTags": [],
|
||||
"createdAt": "2026-06-15T10:00:00.000Z",
|
||||
"updatedAt": "2026-07-11T16:00:00.000Z"
|
||||
},
|
||||
{
|
||||
"id": "eb-004",
|
||||
"questionId": "q-410",
|
||||
"questionContent": "计算:(-3)² + |-5| - √16 的值。",
|
||||
"sourceType": "manual",
|
||||
"subject": { "id": "subject-math", "name": "数学" },
|
||||
"knowledgePointIds": ["kp-002"],
|
||||
"knowledgePointName": "有理数运算",
|
||||
"status": "new",
|
||||
"masteryLevel": 0.1,
|
||||
"nextReviewAt": "2026-07-13T08:00:00.000Z",
|
||||
"reviewCount": 0,
|
||||
"correctStreak": 0,
|
||||
"note": "绝对值和平方容易混淆",
|
||||
"errorTags": ["概念不清", "粗心大意"],
|
||||
"createdAt": "2026-07-12T11:00:00.000Z",
|
||||
"updatedAt": "2026-07-12T11:00:00.000Z"
|
||||
},
|
||||
{
|
||||
"id": "eb-005",
|
||||
"questionId": "q-502",
|
||||
"questionContent": "简述光合作用的过程及其对生物圈的意义。",
|
||||
"sourceType": "homework",
|
||||
"subject": { "id": "subject-biology", "name": "生物" },
|
||||
"knowledgePointIds": ["kp-501"],
|
||||
"knowledgePointName": "光合作用",
|
||||
"status": "learning",
|
||||
"masteryLevel": 0.55,
|
||||
"nextReviewAt": "2026-07-15T08:00:00.000Z",
|
||||
"reviewCount": 3,
|
||||
"correctStreak": 2,
|
||||
"note": "光反应和暗反应阶段容易混淆",
|
||||
"errorTags": ["记忆错误"],
|
||||
"createdAt": "2026-06-28T14:00:00.000Z",
|
||||
"updatedAt": "2026-07-09T10:00:00.000Z"
|
||||
}
|
||||
],
|
||||
"stats": {
|
||||
"totalCount": 5,
|
||||
"newCount": 2,
|
||||
"learningCount": 2,
|
||||
"masteredCount": 1,
|
||||
"dueReviewCount": 3,
|
||||
"masteredRate": 0.2
|
||||
}
|
||||
}
|
||||
58
apps/student-portal/src/mocks/fixtures/leaveRequests.json
Normal file
58
apps/student-portal/src/mocks/fixtures/leaveRequests.json
Normal file
@@ -0,0 +1,58 @@
|
||||
[
|
||||
{
|
||||
"id": "lv-001",
|
||||
"leaveType": "sick",
|
||||
"startDate": "2026-07-10",
|
||||
"endDate": "2026-07-11",
|
||||
"reason": "感冒发烧,需在家休息恢复。",
|
||||
"status": "approved",
|
||||
"reviewComment": "注意休息,祝早日康复。",
|
||||
"reviewedAt": "2026-07-09T14:30:00.000Z",
|
||||
"reviewerName": "王老师",
|
||||
"className": "高三(2)班",
|
||||
"attendanceSynced": true,
|
||||
"createdAt": "2026-07-09T08:15:00.000Z"
|
||||
},
|
||||
{
|
||||
"id": "lv-002",
|
||||
"leaveType": "personal",
|
||||
"startDate": "2026-07-15",
|
||||
"endDate": "2026-07-15",
|
||||
"reason": "家中有事需处理,请假一天。",
|
||||
"status": "pending",
|
||||
"reviewComment": null,
|
||||
"reviewedAt": null,
|
||||
"reviewerName": null,
|
||||
"className": "高三(2)班",
|
||||
"attendanceSynced": false,
|
||||
"createdAt": "2026-07-13T09:00:00.000Z"
|
||||
},
|
||||
{
|
||||
"id": "lv-003",
|
||||
"leaveType": "family",
|
||||
"startDate": "2026-06-20",
|
||||
"endDate": "2026-06-22",
|
||||
"reason": "参加亲属婚礼,需请假三天。",
|
||||
"status": "rejected",
|
||||
"reviewComment": "临近期末考试,建议调整时间。",
|
||||
"reviewedAt": "2026-06-19T16:00:00.000Z",
|
||||
"reviewerName": "王老师",
|
||||
"className": "高三(2)班",
|
||||
"attendanceSynced": false,
|
||||
"createdAt": "2026-06-18T10:00:00.000Z"
|
||||
},
|
||||
{
|
||||
"id": "lv-004",
|
||||
"leaveType": "other",
|
||||
"startDate": "2026-07-05",
|
||||
"endDate": "2026-07-05",
|
||||
"reason": "参加市级学科竞赛培训。",
|
||||
"status": "cancelled",
|
||||
"reviewComment": null,
|
||||
"reviewedAt": null,
|
||||
"reviewerName": null,
|
||||
"className": "高三(2)班",
|
||||
"attendanceSynced": false,
|
||||
"createdAt": "2026-07-04T11:20:00.000Z"
|
||||
}
|
||||
]
|
||||
46
apps/student-portal/src/mocks/fixtures/lessonPlans.json
Normal file
46
apps/student-portal/src/mocks/fixtures/lessonPlans.json
Normal file
@@ -0,0 +1,46 @@
|
||||
[
|
||||
{
|
||||
"id": "lp-001",
|
||||
"title": "二次函数的图像与性质",
|
||||
"subjectName": "数学",
|
||||
"gradeName": "高三",
|
||||
"chapterTitle": "第一章 函数与导数",
|
||||
"creatorName": "张老师",
|
||||
"status": "published",
|
||||
"publishedAt": "2026-07-08T08:00:00.000Z",
|
||||
"updatedAt": "2026-07-08T08:00:00.000Z"
|
||||
},
|
||||
{
|
||||
"id": "lp-002",
|
||||
"title": "文言文阅读:赤壁赋",
|
||||
"subjectName": "语文",
|
||||
"gradeName": "高三",
|
||||
"chapterTitle": "第三章 古代散文",
|
||||
"creatorName": "李老师",
|
||||
"status": "published",
|
||||
"publishedAt": "2026-07-07T10:00:00.000Z",
|
||||
"updatedAt": "2026-07-07T10:00:00.000Z"
|
||||
},
|
||||
{
|
||||
"id": "lp-003",
|
||||
"title": "牛顿运动定律的应用",
|
||||
"subjectName": "物理",
|
||||
"gradeName": "高三",
|
||||
"chapterTitle": "第二章 力学",
|
||||
"creatorName": "陈老师",
|
||||
"status": "published",
|
||||
"publishedAt": "2026-07-06T09:00:00.000Z",
|
||||
"updatedAt": "2026-07-06T09:00:00.000Z"
|
||||
},
|
||||
{
|
||||
"id": "lp-004",
|
||||
"title": "化学平衡常数与计算",
|
||||
"subjectName": "化学",
|
||||
"gradeName": "高三",
|
||||
"chapterTitle": "第四章 化学反应原理",
|
||||
"creatorName": "赵老师",
|
||||
"status": "published",
|
||||
"publishedAt": "2026-07-05T14:00:00.000Z",
|
||||
"updatedAt": "2026-07-05T14:00:00.000Z"
|
||||
}
|
||||
]
|
||||
49
apps/student-portal/src/mocks/fixtures/masterySummary.json
Normal file
49
apps/student-portal/src/mocks/fixtures/masterySummary.json
Normal file
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"studentId": "stu-001",
|
||||
"studentName": "陈同学",
|
||||
"averageMastery": 76,
|
||||
"totalKnowledgePoints": 42,
|
||||
"confidenceLevel": "high",
|
||||
"mastery": [
|
||||
{
|
||||
"knowledgePointId": "kp-math-01",
|
||||
"knowledgePointName": "函数与导数",
|
||||
"masteryLevel": 92,
|
||||
"totalQuestions": 35,
|
||||
"correctQuestions": 32,
|
||||
"lastAssessedAt": "2026-07-10T14:00:00.000Z"
|
||||
},
|
||||
{
|
||||
"knowledgePointId": "kp-math-02",
|
||||
"knowledgePointName": "三角函数",
|
||||
"masteryLevel": 78,
|
||||
"totalQuestions": 28,
|
||||
"correctQuestions": 22,
|
||||
"lastAssessedAt": "2026-07-09T10:00:00.000Z"
|
||||
},
|
||||
{
|
||||
"knowledgePointId": "kp-chinese-01",
|
||||
"knowledgePointName": "文言文阅读",
|
||||
"masteryLevel": 58,
|
||||
"totalQuestions": 20,
|
||||
"correctQuestions": 12,
|
||||
"lastAssessedAt": "2026-07-08T15:00:00.000Z"
|
||||
},
|
||||
{
|
||||
"knowledgePointId": "kp-english-01",
|
||||
"knowledgePointName": "阅读理解",
|
||||
"masteryLevel": 85,
|
||||
"totalQuestions": 40,
|
||||
"correctQuestions": 34,
|
||||
"lastAssessedAt": "2026-07-11T09:00:00.000Z"
|
||||
},
|
||||
{
|
||||
"knowledgePointId": "kp-physics-01",
|
||||
"knowledgePointName": "力学综合",
|
||||
"masteryLevel": 68,
|
||||
"totalQuestions": 25,
|
||||
"correctQuestions": 17,
|
||||
"lastAssessedAt": "2026-07-07T11:00:00.000Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
55
apps/student-portal/src/mocks/fixtures/practiceSessions.json
Normal file
55
apps/student-portal/src/mocks/fixtures/practiceSessions.json
Normal file
@@ -0,0 +1,55 @@
|
||||
{
|
||||
"sessions": [
|
||||
{
|
||||
"id": "ps-001",
|
||||
"practiceType": "error_variant",
|
||||
"status": "completed",
|
||||
"totalQuestions": 10,
|
||||
"answeredQuestions": 10,
|
||||
"correctCount": 8,
|
||||
"accuracy": 0.8,
|
||||
"startedAt": "2026-07-10T14:00:00.000Z",
|
||||
"completedAt": "2026-07-10T14:25:00.000Z"
|
||||
},
|
||||
{
|
||||
"id": "ps-002",
|
||||
"practiceType": "knowledge_point",
|
||||
"status": "completed",
|
||||
"totalQuestions": 8,
|
||||
"answeredQuestions": 8,
|
||||
"correctCount": 6,
|
||||
"accuracy": 0.75,
|
||||
"startedAt": "2026-07-11T19:00:00.000Z",
|
||||
"completedAt": "2026-07-11T19:18:00.000Z"
|
||||
},
|
||||
{
|
||||
"id": "ps-003",
|
||||
"practiceType": "weak_chapter",
|
||||
"status": "in_progress",
|
||||
"totalQuestions": 12,
|
||||
"answeredQuestions": 5,
|
||||
"correctCount": 3,
|
||||
"accuracy": 0.6,
|
||||
"startedAt": "2026-07-13T10:00:00.000Z",
|
||||
"completedAt": null
|
||||
},
|
||||
{
|
||||
"id": "ps-004",
|
||||
"practiceType": "ai_recommended",
|
||||
"status": "abandoned",
|
||||
"totalQuestions": 10,
|
||||
"answeredQuestions": 2,
|
||||
"correctCount": 1,
|
||||
"accuracy": 0.5,
|
||||
"startedAt": "2026-07-08T16:00:00.000Z",
|
||||
"completedAt": null
|
||||
}
|
||||
],
|
||||
"stats": {
|
||||
"totalSessions": 4,
|
||||
"completedSessions": 2,
|
||||
"totalQuestionsAnswered": 25,
|
||||
"totalCorrect": 18,
|
||||
"overallAccuracy": 0.72
|
||||
}
|
||||
}
|
||||
101
apps/student-portal/src/mocks/fixtures/reportCard.json
Normal file
101
apps/student-portal/src/mocks/fixtures/reportCard.json
Normal file
@@ -0,0 +1,101 @@
|
||||
{
|
||||
"studentId": "stu-001",
|
||||
"studentName": "陈同学",
|
||||
"classId": "cls-001",
|
||||
"className": "高三(2)班",
|
||||
"classTeacherName": "王老师",
|
||||
"academicYearName": "2025-2026学年",
|
||||
"semester": "1",
|
||||
"subjects": [
|
||||
{
|
||||
"subjectId": "subject-math",
|
||||
"subjectName": "数学",
|
||||
"averageScore": 88.5,
|
||||
"rankInSubject": 5,
|
||||
"totalStudentsInSubject": 45,
|
||||
"fullScoreTotal": 442.5,
|
||||
"records": [
|
||||
{
|
||||
"id": "gr-001",
|
||||
"examName": "月考一",
|
||||
"score": 85,
|
||||
"maxScore": 100,
|
||||
"grade": "良好",
|
||||
"rank": 6,
|
||||
"submittedAt": "2026-03-15T10:00:00.000Z"
|
||||
},
|
||||
{
|
||||
"id": "gr-002",
|
||||
"examName": "期中考试",
|
||||
"score": 92,
|
||||
"maxScore": 100,
|
||||
"grade": "优秀",
|
||||
"rank": 3,
|
||||
"submittedAt": "2026-04-20T10:00:00.000Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"subjectId": "subject-chinese",
|
||||
"subjectName": "语文",
|
||||
"averageScore": 82.0,
|
||||
"rankInSubject": 8,
|
||||
"totalStudentsInSubject": 45,
|
||||
"fullScoreTotal": 410.0,
|
||||
"records": [
|
||||
{
|
||||
"id": "gr-003",
|
||||
"examName": "月考一",
|
||||
"score": 80,
|
||||
"maxScore": 100,
|
||||
"grade": "良好",
|
||||
"rank": 10,
|
||||
"submittedAt": "2026-03-16T10:00:00.000Z"
|
||||
},
|
||||
{
|
||||
"id": "gr-004",
|
||||
"examName": "期中考试",
|
||||
"score": 84,
|
||||
"maxScore": 100,
|
||||
"grade": "良好",
|
||||
"rank": 7,
|
||||
"submittedAt": "2026-04-21T10:00:00.000Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"subjectId": "subject-english",
|
||||
"subjectName": "英语",
|
||||
"averageScore": 90.5,
|
||||
"rankInSubject": 3,
|
||||
"totalStudentsInSubject": 45,
|
||||
"fullScoreTotal": 452.5,
|
||||
"records": [
|
||||
{
|
||||
"id": "gr-005",
|
||||
"examName": "月考一",
|
||||
"score": 89,
|
||||
"maxScore": 100,
|
||||
"grade": "良好",
|
||||
"rank": 4,
|
||||
"submittedAt": "2026-03-17T10:00:00.000Z"
|
||||
},
|
||||
{
|
||||
"id": "gr-006",
|
||||
"examName": "期中考试",
|
||||
"score": 92,
|
||||
"maxScore": 100,
|
||||
"grade": "优秀",
|
||||
"rank": 2,
|
||||
"submittedAt": "2026-04-22T10:00:00.000Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"overallAverage": 87.0,
|
||||
"overallRank": 4,
|
||||
"classTotalStudents": 45,
|
||||
"overallPassRate": 0.96,
|
||||
"overallExcellentRate": 0.33,
|
||||
"generatedAt": "2026-07-13T12:00:00.000Z"
|
||||
}
|
||||
@@ -40,6 +40,17 @@ import myScheduleFixture from "./fixtures/mySchedule.json";
|
||||
import studentGrowthFixture from "./fixtures/studentGrowth.json";
|
||||
import assignmentAnalysisFixture from "./fixtures/assignmentAnalysis.json";
|
||||
import myProfileFixture from "./fixtures/myProfile.json";
|
||||
// 批次 A 扩展 fixture
|
||||
import errorBookFixture from "./fixtures/errorBook.json";
|
||||
import leaveRequestsFixture from "./fixtures/leaveRequests.json";
|
||||
import electiveCoursesFixture from "./fixtures/electiveCourses.json";
|
||||
import practiceSessionsFixture from "./fixtures/practiceSessions.json";
|
||||
import announcementsFixture from "./fixtures/announcements.json";
|
||||
import lessonPlansFixture from "./fixtures/lessonPlans.json";
|
||||
import coursePlansFixture from "./fixtures/coursePlans.json";
|
||||
import reportCardFixture from "./fixtures/reportCard.json";
|
||||
import diagnosticReportsFixture from "./fixtures/diagnosticReports.json";
|
||||
import masterySummaryFixture from "./fixtures/masterySummary.json";
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// GraphQL 请求/响应类型
|
||||
@@ -275,6 +286,181 @@ function handleQuery(
|
||||
case "myProfile":
|
||||
return graphqlOk("myProfile", ok(myProfileFixture));
|
||||
|
||||
// === 批次 A 扩展查询 ===
|
||||
case "myErrorBook":
|
||||
return graphqlOk("myErrorBook", ok(errorBookFixture));
|
||||
|
||||
case "myLeaveRequests":
|
||||
return graphqlOk("myLeaveRequests", ok(leaveRequestsFixture));
|
||||
|
||||
case "myElectiveSelections": {
|
||||
// 从可选课程中派生选课记录
|
||||
const selections = electiveCoursesFixture.slice(0, 2).map((c) => ({
|
||||
id: `sel-${c.id}`,
|
||||
courseId: c.id,
|
||||
courseName: c.name,
|
||||
status: "enrolled" as const,
|
||||
selectedAt: "2026-07-02T10:00:00.000Z",
|
||||
enrolledAt: "2026-07-03T08:00:00.000Z",
|
||||
droppedAt: null,
|
||||
dropReason: null,
|
||||
course: {
|
||||
id: c.id,
|
||||
name: c.name,
|
||||
teacherName: c.teacherName,
|
||||
subjectName: c.subjectName,
|
||||
capacity: c.capacity,
|
||||
enrolledCount: c.enrolledCount,
|
||||
classroom: c.classroom,
|
||||
schedule: c.schedule,
|
||||
credit: c.credit,
|
||||
status: c.status,
|
||||
},
|
||||
}));
|
||||
return graphqlOk("myElectiveSelections", ok(selections));
|
||||
}
|
||||
|
||||
case "availableElectiveCourses":
|
||||
return graphqlOk(
|
||||
"availableElectiveCourses",
|
||||
ok(electiveCoursesFixture),
|
||||
);
|
||||
|
||||
case "myPracticeSessions":
|
||||
return graphqlOk("myPracticeSessions", ok(practiceSessionsFixture));
|
||||
|
||||
case "startPracticeSession": {
|
||||
const input = (variables["input"] ?? {}) as Record<string, unknown>;
|
||||
const practiceType = (input["practiceType"] as string) ?? "error_variant";
|
||||
const session = {
|
||||
id: `ps-${Date.now()}`,
|
||||
practiceType,
|
||||
status: "in_progress" as const,
|
||||
totalQuestions: 10,
|
||||
answeredQuestions: 0,
|
||||
correctCount: 0,
|
||||
accuracy: 0,
|
||||
startedAt: new Date().toISOString(),
|
||||
currentQuestionIndex: 0,
|
||||
questions: [
|
||||
{
|
||||
id: "pq-001",
|
||||
questionId: "q-001",
|
||||
content: "已知函数 f(x) = x² - 2x + 1,求 f(x) 的最小值。",
|
||||
type: "short-answer",
|
||||
options: [],
|
||||
maxScore: 5,
|
||||
status: "pending" as const,
|
||||
},
|
||||
{
|
||||
id: "pq-002",
|
||||
questionId: "q-002",
|
||||
content: "下列哪个是二次函数的标准形式?",
|
||||
type: "single-choice",
|
||||
options: [
|
||||
{ id: "opt-a", text: "y = ax + b" },
|
||||
{ id: "opt-b", text: "y = ax² + bx + c (a≠0)" },
|
||||
{ id: "opt-c", text: "y = a/x" },
|
||||
{ id: "opt-d", text: "y = √x" },
|
||||
],
|
||||
maxScore: 5,
|
||||
status: "pending" as const,
|
||||
},
|
||||
],
|
||||
};
|
||||
return graphqlOk("startPracticeSession", ok({ session }));
|
||||
}
|
||||
|
||||
case "announcements":
|
||||
return graphqlOk("announcements", ok(announcementsFixture));
|
||||
|
||||
case "announcementDetail": {
|
||||
const announcementId =
|
||||
(variables["announcementId"] as string) ?? "an-001";
|
||||
const detail =
|
||||
announcementsFixture.find((a) => a.id === announcementId) ??
|
||||
announcementsFixture[0];
|
||||
return graphqlOk("announcementDetail", ok(detail));
|
||||
}
|
||||
|
||||
case "myLessonPlans":
|
||||
return graphqlOk("myLessonPlans", ok(lessonPlansFixture));
|
||||
|
||||
case "lessonPlanDetail": {
|
||||
const planId = (variables["planId"] as string) ?? "lp-001";
|
||||
const item =
|
||||
lessonPlansFixture.find((l) => l.id === planId) ?? lessonPlansFixture[0];
|
||||
const detail = {
|
||||
...item,
|
||||
content: {
|
||||
objectives:
|
||||
"1. 理解核心概念与基本原理\n2. 掌握解题方法与技巧\n3. 能够综合运用解决实际问题",
|
||||
keyPoints: "重点:核心公式的推导与应用\n难点:综合题型的分析与解题策略",
|
||||
summary: "本节课围绕核心知识点展开,通过例题讲解与课堂练习巩固理解。",
|
||||
homework: "完成课后练习第 1-5 题,预习下一节内容。",
|
||||
blackboard: "板书要点:公式推导流程图 + 例题解题步骤",
|
||||
},
|
||||
};
|
||||
return graphqlOk("lessonPlanDetail", ok(detail));
|
||||
}
|
||||
|
||||
case "myCoursePlans":
|
||||
return graphqlOk("myCoursePlans", ok(coursePlansFixture));
|
||||
|
||||
case "coursePlanDetail": {
|
||||
const planId = (variables["planId"] as string) ?? "cp-001";
|
||||
const item =
|
||||
coursePlansFixture.find((c) => c.id === planId) ?? coursePlansFixture[0];
|
||||
const detail = {
|
||||
...item,
|
||||
items: [
|
||||
{
|
||||
id: "cpi-001",
|
||||
week: 1,
|
||||
topic: "函数的基本概念",
|
||||
content: "函数定义、定义域、值域、表示方法",
|
||||
hours: 4,
|
||||
textbookChapter: "第 1.1 节",
|
||||
notes: null,
|
||||
isCompleted: true,
|
||||
completedAt: "2026-02-23T16:00:00.000Z",
|
||||
},
|
||||
{
|
||||
id: "cpi-002",
|
||||
week: 2,
|
||||
topic: "函数的单调性与奇偶性",
|
||||
content: "单调性判定、奇偶性判定、综合应用",
|
||||
hours: 4,
|
||||
textbookChapter: "第 1.2-1.3 节",
|
||||
notes: "注意数形结合",
|
||||
isCompleted: true,
|
||||
completedAt: "2026-03-02T16:00:00.000Z",
|
||||
},
|
||||
{
|
||||
id: "cpi-013",
|
||||
week: 13,
|
||||
topic: "期末复习与综合训练",
|
||||
content: "全册知识点梳理、模拟试卷讲评",
|
||||
hours: 4,
|
||||
textbookChapter: "复习章节",
|
||||
notes: null,
|
||||
isCompleted: false,
|
||||
completedAt: null,
|
||||
},
|
||||
],
|
||||
};
|
||||
return graphqlOk("coursePlanDetail", ok(detail));
|
||||
}
|
||||
|
||||
case "myReportCard":
|
||||
return graphqlOk("myReportCard", ok(reportCardFixture));
|
||||
|
||||
case "myDiagnosticReports":
|
||||
return graphqlOk("myDiagnosticReports", ok(diagnosticReportsFixture));
|
||||
|
||||
case "myMasterySummary":
|
||||
return graphqlOk("myMasterySummary", ok(masterySummaryFixture));
|
||||
|
||||
default: {
|
||||
// 未覆盖的查询操作名,返回错误
|
||||
return graphqlError(
|
||||
@@ -433,6 +619,127 @@ function handleMutation(
|
||||
return graphqlOk("leaveClass", ok(result));
|
||||
}
|
||||
|
||||
// === 批次 A 扩展变更 ===
|
||||
case "addErrorBookItem": {
|
||||
const input = (variables["input"] ?? {}) as Record<string, unknown>;
|
||||
const result = {
|
||||
id: `eb-${Date.now()}`,
|
||||
status: "new" as const,
|
||||
createdAt: new Date().toISOString(),
|
||||
};
|
||||
void input;
|
||||
return graphqlOk("addErrorBookItem", ok(result));
|
||||
}
|
||||
|
||||
case "updateErrorBookItem": {
|
||||
const input = (variables["input"] ?? {}) as Record<string, unknown>;
|
||||
const id = (input["id"] as string) ?? "";
|
||||
const reviewResult = input["reviewResult"] as
|
||||
| "again"
|
||||
| "hard"
|
||||
| "good"
|
||||
| "easy"
|
||||
| undefined;
|
||||
const masteryMap: Record<string, number> = {
|
||||
again: 0.2,
|
||||
hard: 0.4,
|
||||
good: 0.7,
|
||||
easy: 0.9,
|
||||
};
|
||||
const mastery = reviewResult ? masteryMap[reviewResult] ?? 0.5 : 0.5;
|
||||
const nextReview = new Date();
|
||||
nextReview.setDate(nextReview.getDate() + (reviewResult === "again" ? 1 : reviewResult === "hard" ? 3 : 7));
|
||||
const result = {
|
||||
id,
|
||||
status: mastery >= 0.8 ? ("mastered" as const) : ("learning" as const),
|
||||
masteryLevel: mastery,
|
||||
nextReviewAt: nextReview.toISOString(),
|
||||
reviewCount: 1,
|
||||
};
|
||||
return graphqlOk("updateErrorBookItem", ok(result));
|
||||
}
|
||||
|
||||
case "deleteErrorBookItem": {
|
||||
const input = (variables["input"] ?? {}) as Record<string, unknown>;
|
||||
const id = (input["id"] as string) ?? "";
|
||||
return graphqlOk("deleteErrorBookItem", ok({ id, deleted: true }));
|
||||
}
|
||||
|
||||
case "createLeaveRequest": {
|
||||
const input = (variables["input"] ?? {}) as Record<string, unknown>;
|
||||
const result = {
|
||||
id: `lv-${Date.now()}`,
|
||||
status: "pending" as const,
|
||||
createdAt: new Date().toISOString(),
|
||||
};
|
||||
void input;
|
||||
return graphqlOk("createLeaveRequest", ok(result));
|
||||
}
|
||||
|
||||
case "cancelLeaveRequest": {
|
||||
const input = (variables["input"] ?? {}) as Record<string, unknown>;
|
||||
const id = (input["id"] as string) ?? "";
|
||||
return graphqlOk(
|
||||
"cancelLeaveRequest",
|
||||
ok({ id, status: "cancelled" as const }),
|
||||
);
|
||||
}
|
||||
|
||||
case "selectElectiveCourse": {
|
||||
const input = (variables["input"] ?? {}) as Record<string, unknown>;
|
||||
const courseId = (input["courseId"] as string) ?? "";
|
||||
const result = {
|
||||
id: `sel-${Date.now()}`,
|
||||
courseId,
|
||||
status: "enrolled" as const,
|
||||
selectedAt: new Date().toISOString(),
|
||||
};
|
||||
return graphqlOk("selectElectiveCourse", ok(result));
|
||||
}
|
||||
|
||||
case "dropElectiveCourse": {
|
||||
const input = (variables["input"] ?? {}) as Record<string, unknown>;
|
||||
const courseId = (input["courseId"] as string) ?? "";
|
||||
const result = {
|
||||
id: `sel-${courseId}`,
|
||||
courseId,
|
||||
status: "dropped" as const,
|
||||
droppedAt: new Date().toISOString(),
|
||||
};
|
||||
return graphqlOk("dropElectiveCourse", ok(result));
|
||||
}
|
||||
|
||||
case "submitPracticeAnswer": {
|
||||
const input = (variables["input"] ?? {}) as Record<string, unknown>;
|
||||
const questionId = (input["questionId"] as string) ?? "";
|
||||
const isCorrect = questionId === "q-002" && input["answer"] === "opt-b";
|
||||
const result = {
|
||||
answerId: `ans-${Date.now()}`,
|
||||
isCorrect,
|
||||
score: isCorrect ? 5 : 0,
|
||||
maxScore: 5,
|
||||
correctAnswer: questionId === "q-002" ? "opt-b" : "x=1",
|
||||
sessionCompleted: false,
|
||||
session: {
|
||||
id: (input["sessionId"] as string) ?? "",
|
||||
answeredQuestions: 1,
|
||||
correctCount: isCorrect ? 1 : 0,
|
||||
accuracy: isCorrect ? 1 : 0,
|
||||
status: "in_progress" as const,
|
||||
},
|
||||
};
|
||||
return graphqlOk("submitPracticeAnswer", ok(result));
|
||||
}
|
||||
|
||||
case "markAnnouncementRead": {
|
||||
const input = (variables["input"] ?? {}) as Record<string, unknown>;
|
||||
const announcementId = (input["announcementId"] as string) ?? "";
|
||||
return graphqlOk(
|
||||
"markAnnouncementRead",
|
||||
ok({ announcementId, read: true }),
|
||||
);
|
||||
}
|
||||
|
||||
default: {
|
||||
// 未覆盖的变更操作名,返回错误
|
||||
return graphqlError(
|
||||
@@ -469,6 +776,21 @@ const QUERY_NAMES = new Set<QueryOperationName>([
|
||||
"studentGrowth",
|
||||
"assignmentAnalysis",
|
||||
"myProfile",
|
||||
"myErrorBook",
|
||||
"myLeaveRequests",
|
||||
"myElectiveSelections",
|
||||
"availableElectiveCourses",
|
||||
"myPracticeSessions",
|
||||
"startPracticeSession",
|
||||
"announcements",
|
||||
"announcementDetail",
|
||||
"myLessonPlans",
|
||||
"lessonPlanDetail",
|
||||
"myCoursePlans",
|
||||
"coursePlanDetail",
|
||||
"myReportCard",
|
||||
"myDiagnosticReports",
|
||||
"myMasterySummary",
|
||||
]);
|
||||
|
||||
/** 变更操作名集合 */
|
||||
@@ -571,6 +893,16 @@ export const fixtures = {
|
||||
studentGrowth: studentGrowthFixture,
|
||||
assignmentAnalysis: assignmentAnalysisFixture,
|
||||
myProfile: myProfileFixture,
|
||||
errorBook: errorBookFixture,
|
||||
leaveRequests: leaveRequestsFixture,
|
||||
electiveCourses: electiveCoursesFixture,
|
||||
practiceSessions: practiceSessionsFixture,
|
||||
announcements: announcementsFixture,
|
||||
lessonPlans: lessonPlansFixture,
|
||||
coursePlans: coursePlansFixture,
|
||||
reportCard: reportCardFixture,
|
||||
diagnosticReports: diagnosticReportsFixture,
|
||||
masterySummary: masterySummaryFixture,
|
||||
};
|
||||
|
||||
/** 导出工具函数供测试使用 */
|
||||
|
||||
Reference in New Issue
Block a user