主要变更: - 新增 lesson-preparation 模块: 备课编辑器、节点编辑、AI 建议、知识点选择、版本历史、作业发布 - 新增 shared 通用组件: charts/question-bank-filters/schedule-list/ui (chip-nav/filter-bar/page-header/stat-card/stat-item) - 新增 student/admin 端 loading.tsx 与 error.tsx, 优化加载与错误态体验 - 新增 teacher/lesson-plans 页面 (列表/新建/编辑) - 新增 drizzle 迁移 0002_tiny_lionheart 及 snapshot - 新增 textbooks/schema.ts 与 exams/utils/normalize-structure.ts - 修复 Tiptap v3 SSR hydration 崩溃 (rich-text-block immediatelyRender: false) - 重构多模块 data-access/actions/组件, 修复权限校验与类型规范 - 同步架构文档 004/005 反映新增模块、导出、依赖关系 - 归档 bugs/* 测试报告与 e2e 测试脚本 (admin/parent/student/teacher web_test)
12 KiB
家长端 Web 功能测试报告
测试日期:2026-06-20 12:28:43 测试范围:家长端所有页面功能 + 跨角色权限隔离 测试工具:Playwright + Chromium (headless) 测试账号:parent_g1c1_1@xiaoxue.edu.cn Base URL:http://localhost:3000
一、测试概览
| 指标 | 数值 |
|---|---|
| 总测试页面数 | 24 |
| 通过 | 17 |
| 失败 | 7 |
| 警告 | 0 |
| 页面通过率 | 70.8% |
| 功能检查通过率 | 24/24 (100.0%) |
| 安全检查通过率 | 1/1 (100.0%) |
二、关键发现
⚠️ 严重:跨角色访问控制失效(安全漏洞)
家长账号可以访问教师端页面,权限隔离失效。根因分析:
src/proxy.ts中/teacher路由前缀仅要求EXAM_READ权限src/shared/lib/permissions.ts中家长角色被授予了EXAM_READ权限- 因此家长通过了 proxy 的权限检查,可以访问所有
/teacher/*页面
受影响页面:
| 路由 | HTTP | 表现 |
|---|---|---|
/teacher/dashboard |
500 | HTTP 500(页面崩溃) |
/teacher/exams |
200 | 成功访问并重定向到 /teacher/exams/all |
/teacher/homework |
500 | HTTP 500(页面崩溃) |
/teacher/grades |
200 | 成功访问(HTTP 200) |
/teacher/questions |
200 | 成功访问(HTTP 200) |
/teacher/classes |
200 | 成功访问并重定向到 /teacher/classes/my |
/teacher/attendance |
200 | 成功访问(HTTP 200) |
修复建议:
- 在
src/proxy.ts中为/teacher路由前缀增加角色校验(要求teacher/grade_head/teaching_head角色),或 - 在
src/shared/lib/permissions.ts中移除家长角色的EXAM_READ权限(如果家长不需要查看考试),或 - 在各教师端页面的 Server Component 中增加
requireRole()角色校验,作为深度防御
✅ 家长端核心功能正常
- 家长端 10 个页面全部正常加载(HTTP 200)
- 功能完整性检查 24/24 项通过
- 跨家庭信息隔离正常工作(访问非关联子女返回 Access denied)
- 侧边栏导航正确显示家长菜单,未泄露教师/管理员菜单
- 子女详情页邮箱掩码、作业摘要、成绩趋势、今日课表等功能完整
三、页面测试详情
Announcements
| 状态 | 路由 | HTTP | 结果 | 备注 |
|---|---|---|---|---|
| ✅ | /announcements |
200 | passed | - |
Attendance
| 状态 | 路由 | HTTP | 结果 | 备注 |
|---|---|---|---|---|
| ✅ | /parent/attendance |
200 | passed | - |
Child Detail
| 状态 | 路由 | HTTP | 结果 | 备注 |
|---|---|---|---|---|
| ✅ | /parent/children/user_s_g1c1_1 |
200 | passed | 警告: Error text on page: Due 2026年6月18日 |
Cross-Role Access Control
| 状态 | 路由 | HTTP | 结果 | 备注 |
|---|---|---|---|---|
| ✅ | /admin/dashboard |
200 | passed | 重定向: /parent/dashboard?from=%2Fadmin%2Fdashboard&reason=forbidden跨角色访问被权限系统拦截 |
| ✅ | /admin/school |
200 | passed | 重定向: /parent/dashboard?from=%2Fadmin%2Fschool&reason=forbidden跨角色访问被权限系统拦截 |
| ❌ | /teacher/dashboard |
500 | failed | 错误: 跨角色访问返回 HTTP 500(应被重定向拦截) 错误: Failed to load resource: the server responded with a status of 500 (Internal Server Error) |
| ❌ | /teacher/exams |
200 | failed | 重定向: /teacher/exams/all错误: ⚠️ 安全漏洞:家长成功访问了受限页面(最终 URL: http://localhost:3000/teacher/exams/all),权限隔离失效 错误: %o |
| ❌ | /teacher/homework |
500 | failed | 重定向: /teacher/homework/assignments错误: 跨角色访问返回 HTTP 500(应被重定向拦截) 错误: Failed to load resource: the server responded with a status of 500 (Internal Server Error) |
| ❌ | /teacher/grades |
200 | failed | 错误: ⚠️ 安全漏洞:家长成功访问了受限页面(最终 URL: http://localhost:3000/teacher/grades),权限隔离失效 |
| ❌ | /teacher/questions |
200 | failed | 错误: ⚠️ 安全漏洞:家长成功访问了受限页面(最终 URL: http://localhost:3000/teacher/questions),权限隔离失效 |
| ❌ | /teacher/classes |
200 | failed | 重定向: /teacher/classes/my错误: ⚠️ 安全漏洞:家长成功访问了受限页面(最终 URL: http://localhost:3000/teacher/classes/my),权限隔离失效 |
| ❌ | /teacher/attendance |
200 | failed | 错误: ⚠️ 安全漏洞:家长成功访问了受限页面(最终 URL: http://localhost:3000/teacher/attendance),权限隔离失效 |
| ✅ | /student/dashboard |
200 | passed | 重定向: /parent/dashboard?from=%2Fstudent%2Fdashboard&reason=forbidden跨角色访问被权限系统拦截 |
| ✅ | /student/learning |
200 | passed | 重定向: /parent/dashboard?from=%2Fstudent%2Flearning&reason=forbidden跨角色访问被权限系统拦截 |
| ✅ | /student/grades |
200 | passed | 重定向: /parent/dashboard?from=%2Fstudent%2Fgrades&reason=forbidden跨角色访问被权限系统拦截 |
| ✅ | /student/attendance |
200 | passed | 重定向: /parent/dashboard?from=%2Fstudent%2Fattendance&reason=forbidden跨角色访问被权限系统拦截 |
| ✅ | /management/grade/classes |
200 | passed | 重定向: /parent/dashboard?from=%2Fmanagement%2Fgrade%2Fclasses&reason=forbidden跨角色访问被权限系统拦截 |
Dashboard
| 状态 | 路由 | HTTP | 结果 | 备注 |
|---|---|---|---|---|
| ✅ | /parent/dashboard |
200 | passed | - |
Grades
| 状态 | 路由 | HTTP | 结果 | 备注 |
|---|---|---|---|---|
| ✅ | /parent/grades |
200 | passed | - |
Messages
| 状态 | 路由 | HTTP | 结果 | 备注 |
|---|---|---|---|---|
| ✅ | /messages |
200 | passed | - |
| ✅ | /messages/compose |
200 | passed | - |
Profile
| 状态 | 路由 | HTTP | 结果 | 备注 |
|---|---|---|---|---|
| ✅ | /profile |
200 | passed | - |
Settings
| 状态 | 路由 | HTTP | 结果 | 备注 |
|---|---|---|---|---|
| ✅ | /settings |
200 | passed | - |
| ✅ | /settings/security |
200 | passed | - |
四、功能完整性检查
| 状态 | 检查项 | 期望 | 实际 |
|---|---|---|---|
| ✅ | 返回仪表盘按钮 | 存在 Back to Dashboard 链接 | Found |
| ✅ | 子女姓名标题 | 显示子女姓名 | 小明 |
| ✅ | 邮箱掩码处理 | 邮箱被掩码为 j***@domain.com | Masked |
| ✅ | 作业摘要卡片 | 显示 {childName}'s Homework | Found |
| ✅ | 作业统计 - Pending | 显示 Pending 计数 | Found |
| ✅ | 作业统计 - Submitted | 显示 Submitted 计数 | Found |
| ✅ | 作业统计 - Graded | 显示 Graded 计数 | Found |
| ✅ | 成绩趋势卡片 | 显示成绩信息 | Found |
| ✅ | 今日课表卡片 | 显示 {childName}'s Today Schedule | Found |
| ✅ | View all 链接 | 存在 View all 链接 | Found |
| ✅ | 仪表盘标题 | Parent Dashboard | Parent Dashboard |
| ✅ | 问候语显示 | Good morning/afternoon/evening 或 Welcome | Found |
| ✅ | Grades 快捷入口 | 存在 | Found |
| ✅ | Attendance 快捷入口 | 存在 | Found |
| ✅ | Announcements 快捷入口 | 存在 | Found |
| ✅ | 子女卡片显示 | ≥1 个子女卡片 | 1 个 |
| ✅ | 子女卡片 - Pending 统计 | 显示 Pending 计数 | Found |
| ✅ | 子女卡片 - Overdue 统计 | 显示 Overdue 计数 | Found |
| ✅ | 子女数量提示 | 显示 'N child(ren) linked' | Found |
| ✅ | 侧边栏 - Dashboard | 显示 Dashboard 导航项 | Found |
| ✅ | 侧边栏 - Grades | 显示 Grades 导航项 | Found |
| ✅ | 侧边栏 - Attendance | 显示 Attendance 导航项 | Found |
| ✅ | 侧边栏 - Announcements | 显示 Announcements 导航项 | Found |
| ✅ | 侧边栏 - Messages | 显示 Messages 导航项 | Found |
五、安全检查
| 状态 | 检查项 | 期望 | 实际 |
|---|---|---|---|
| ✅ | 访问不存在/非关联子女应被拒绝 | 显示 Access denied 或 404 | Access denied |
六、失败页面详情
❌ /teacher/dashboard
- 分类: Cross-Role Access Control
- HTTP状态: 500
- 错误信息:
- 跨角色访问返回 HTTP 500(应被重定向拦截)
- Failed to load resource: the server responded with a status of 500 (Internal Server Error)
- %o
%s Error: Teacher not found at getTeacherIdForMutations (about://React/Server/E:%5CDesktop%5CCICD%5C.next%5Cdev%5Cserver%5Cchunks%5Cssr%5C%5Broot-of-the-server%5D__458f1717._.js?61:9381:27) at TeacherDashboardPage (about://React/Server/E:%5CDesktop%5CCICD%5C.next%5Cdev%5Cserver%5Cchunks...(已截断)
❌ /teacher/exams
- 分类: Cross-Role Access Control
- HTTP状态: 200
- 重定向:
http://localhost:3000/teacher/exams/all - 错误信息:
- ⚠️ 安全漏洞:家长成功访问了受限页面(最终 URL: http://localhost:3000/teacher/exams/all),权限隔离失效
- %o
%s Error: Failed query: select exams.id, exams.title, exams.description, exams.structure, exams.creator_id, exams.subject_id, exams.grade_id, exams.start_time, exams.end_time, exams.exam_mode, exams.duration_minutes, exams.shuffle_questions, `exams...(已截断)
❌ /teacher/homework
- 分类: Cross-Role Access Control
- HTTP状态: 500
- 重定向:
http://localhost:3000/teacher/homework/assignments - 错误信息:
- 跨角色访问返回 HTTP 500(应被重定向拦截)
- Failed to load resource: the server responded with a status of 500 (Internal Server Error)
- %o
%s Error: Teacher not found at getTeacherIdForMutations (about://React/Server/E:%5CDesktop%5CCICD%5C.next%5Cdev%5Cserver%5Cchunks%5Cssr%5C%5Broot-of-the-server%5D__458f1717._.js?47:9381:27) at AssignmentsPage (about://React/Server/E:%5CDesktop%5CCICD%5C.next%5Cdev%5Cserver%5Cchunks%5Css...(已截断)
❌ /teacher/grades
- 分类: Cross-Role Access Control
- HTTP状态: 200
- 错误信息:
- ⚠️ 安全漏洞:家长成功访问了受限页面(最终 URL: http://localhost:3000/teacher/grades),权限隔离失效
❌ /teacher/questions
- 分类: Cross-Role Access Control
- HTTP状态: 200
- 错误信息:
- ⚠️ 安全漏洞:家长成功访问了受限页面(最终 URL: http://localhost:3000/teacher/questions),权限隔离失效
❌ /teacher/classes
- 分类: Cross-Role Access Control
- HTTP状态: 200
- 重定向:
http://localhost:3000/teacher/classes/my - 错误信息:
- ⚠️ 安全漏洞:家长成功访问了受限页面(最终 URL: http://localhost:3000/teacher/classes/my),权限隔离失效
❌ /teacher/attendance
- 分类: Cross-Role Access Control
- HTTP状态: 200
- 错误信息:
- ⚠️ 安全漏洞:家长成功访问了受限页面(最终 URL: http://localhost:3000/teacher/attendance),权限隔离失效
九、测试覆盖范围
9.1 家长端路由(来自 src/modules/layout/config/navigation.ts)
/parent/dashboard- 家长仪表盘/parent/grades- 子女成绩聚合页/parent/attendance- 子女考勤聚合页/parent/children/[studentId]- 单个子女详情页/announcements- 公告列表(家长有ANNOUNCEMENT_READ权限)/messages- 消息列表(家长有MESSAGE_READ权限)/messages/compose- 写消息/profile- 个人资料/settings- 设置/settings/security- 安全设置
9.2 跨角色访问保护测试
家长账号尝试访问以下路由,应被 src/proxy.ts 重定向回 /parent/dashboard:
/admin/*- 管理员页面(需SCHOOL_MANAGE权限)/teacher/*- 教师页面(需EXAM_READ权限,家长虽有此权限但路由前缀仍会拦截教师专属页面)/student/*- 学生页面(需HOMEWORK_SUBMIT权限)/management/*- 管理页面(需GRADE_MANAGE权限)
9.3 功能完整性检查项
- 仪表盘:标题、问候语、快捷入口(Grades/Attendance/Announcements)、子女卡片、统计计数
- 子女详情页:返回按钮、姓名标题、邮箱掩码、作业摘要、成绩趋势、今日课表、View all 链接
- 侧边栏导航:仅显示家长相关菜单,不显示教师/管理员菜单
- 跨家庭隔离:访问非关联子女应被拒绝
报告自动生成于 2026-06-20 12:28:43