# 家长端 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`](../src/proxy.ts#L10-L16) 中 `/teacher` 路由前缀仅要求 `EXAM_READ` 权限
- [`src/shared/lib/permissions.ts`](../src/shared/lib/permissions.ts#L125-L136) 中家长角色被授予了 `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） |

**修复建议**：

1. 在 `src/proxy.ts` 中为 `/teacher` 路由前缀增加角色校验（要求 `teacher` / `grade_head` / `teaching_head` 角色），或
2. 在 `src/shared/lib/permissions.ts` 中移除家长角色的 `EXAM_READ` 权限（如果家长不需要查看考试），或
3. 在各教师端页面的 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`<br>跨角色访问被权限系统拦截 |
| ✅ | `/admin/school` | 200 | passed | 重定向: `/parent/dashboard?from=%2Fadmin%2Fschool&reason=forbidden`<br>跨角色访问被权限系统拦截 |
| ❌ | `/teacher/dashboard` | 500 | failed | 错误: 跨角色访问返回 HTTP 500（应被重定向拦截）<br>错误: Failed to load resource: the server responded with a status of 500 (Internal Server Error) |
| ❌ | `/teacher/exams` | 200 | failed | 重定向: `/teacher/exams/all`<br>错误: ⚠️ 安全漏洞：家长成功访问了受限页面（最终 URL: http://localhost:3000/teacher/exams/all），权限隔离失效<br>错误: %o |
| ❌ | `/teacher/homework` | 500 | failed | 重定向: `/teacher/homework/assignments`<br>错误: 跨角色访问返回 HTTP 500（应被重定向拦截）<br>错误: 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`<br>错误: ⚠️ 安全漏洞：家长成功访问了受限页面（最终 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`<br>跨角色访问被权限系统拦截 |
| ✅ | `/student/learning` | 200 | passed | 重定向: `/parent/dashboard?from=%2Fstudent%2Flearning&reason=forbidden`<br>跨角色访问被权限系统拦截 |
| ✅ | `/student/grades` | 200 | passed | 重定向: `/parent/dashboard?from=%2Fstudent%2Fgrades&reason=forbidden`<br>跨角色访问被权限系统拦截 |
| ✅ | `/student/attendance` | 200 | passed | 重定向: `/parent/dashboard?from=%2Fstudent%2Fattendance&reason=forbidden`<br>跨角色访问被权限系统拦截 |
| ✅ | `/management/grade/classes` | 200 | passed | 重定向: `/parent/dashboard?from=%2Fmanagement%2Fgrade%2Fclasses&reason=forbidden`<br>跨角色访问被权限系统拦截 |

### 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*