# 仪表公告和消息模块 Web 功能测试报告

> 测试日期：2026-06-22 19:44:12
> 测试范围：仪表公告和消息模块（Announcements & Messages）
> 项目版本：0.1.0
> 测试工具：Playwright + Chromium (headless)
> Base URL：http://localhost:3000
> 测试角色：admin / teacher / student / parent

---

## 一、测试概览

| 指标 | 数值 |
|------|------|
| 总测试用例数 | 46 |
| 通过 | 29 |
| 失败 | 0 |
| 警告 | 17 |
| 通过率 | 63.0% |

### 按角色统计

| 角色 | 总计 | 通过 | 失败 | 警告 | 通过率 |
|------|------|------|------|------|--------|
| admin | 16 | 10 | 0 | 6 | 62.5% |
| teacher | 10 | 6 | 0 | 4 | 60.0% |
| student | 10 | 7 | 0 | 3 | 70.0% |
| parent | 10 | 6 | 0 | 4 | 60.0% |

---

## 二、测试范围

### 公告模块（Announcements）

- **路由覆盖**：
  - `/announcements` - 公告列表页（所有已认证用户）
  - `/announcements/[id]` - 公告详情页
  - `/admin/announcements` - 管理员公告管理页（仅 admin）
  - `/admin/announcements/[id]` - 管理员编辑公告页（仅 admin）
- **功能覆盖**：
  - 列表访问、详情查看、状态过滤
  - 管理员：创建、编辑、发布、归档、删除
- **权限矩阵**：
  - admin: ANNOUNCEMENT_MANAGE + ANNOUNCEMENT_READ
  - teacher/student/parent: ANNOUNCEMENT_READ

### 消息模块（Messages）

- **路由覆盖**：
  - `/messages` - 消息列表页（收件箱/已发送 Tab）
  - `/messages/[id]` - 消息详情页
  - `/messages/compose` - 撰写消息页
- **功能覆盖**：
  - 列表访问、Tab 切换、搜索、详情查看
  - 撰写、发送、回复、删除
- **权限矩阵**：
  - 所有角色: MESSAGE_SEND + MESSAGE_READ + MESSAGE_DELETE

---

## 三、测试用例详情

### admin 角色测试结果

| 状态 | 用例 ID | 名称 | 详情 |
|------|---------|------|------|
| ⚠️ | `ANN-LIST-admin` | 公告列表页访问 | HTTP 200, URL: http://localhost:3000/announcements, 标题: 公告, 卡片数: 3 |
| ⚠️ | `ANN-DETAIL-admin` | 公告详情页访问 | HTTP 200, URL: http://localhost:3000/announcements/ann_class_g1c1 |
| ⚠️ | `ANN-ADMIN-LIST-admin` | 管理员公告管理页访问 | HTTP 200, URL: http://localhost:3000/admin/announcements |
| ✅ | `ANN-CREATE-admin` | 创建公告（草稿） | 创建成功，URL: http://localhost:3000/admin/announcements |
| ✅ | `ANN-EDIT-admin` | 编辑公告 | HTTP 200, URL: http://localhost:3000/admin/announcements/nks4mojr6okoomxl2gbl9rwz, 编辑表单存在, 编辑提交成功 |
| ✅ | `ANN-PUBLISH-admin` | 发布公告（编辑页访问） | HTTP 200, URL: http://localhost:3000/admin/announcements/nks4mojr6okoomxl2gbl9rwz, 编辑页可访问 |
| ✅ | `ANN-FILTER-admin-draft` | 公告过滤-draft | 过滤=draft, HTTP 200 |
| ✅ | `ANN-FILTER-admin-published` | 公告过滤-published | 过滤=published, HTTP 200 |
| ✅ | `ANN-FILTER-admin-archived` | 公告过滤-archived | 过滤=archived, HTTP 200 |
| ✅ | `MSG-LIST-admin` | 消息列表页访问 | HTTP 200, URL: http://localhost:3000/messages, 收件箱Tab存在, 已发送Tab存在, Tab切换成功, 撰写按钮存在 |
| ✅ | `MSG-SEARCH-admin` | 消息搜索 | 搜索功能可用 |
| ✅ | `MSG-COMPOSE-admin` | 撰写消息页访问 | HTTP 200, URL: http://localhost:3000/messages/compose, 收件人选择器存在, 主题输入框存在, 内容输入框存在 |
| ✅ | `MSG-SEND-admin` | 发送消息 | 发送成功，跳转至: http://localhost:3000/messages |
| ⚠️ | `MSG-DETAIL-admin` | 消息详情页访问 | 未发现消息详情链接（可能无消息） |
| ⚠️ | `MSG-REPLY-admin` | 消息回复 | 无可用消息，跳过回复测试 |
| ⚠️ | `MSG-DELETE-BTN-admin` | 消息删除按钮 | 无可用消息，跳过删除测试 |

### teacher 角色测试结果

| 状态 | 用例 ID | 名称 | 详情 |
|------|---------|------|------|
| ⚠️ | `ANN-LIST-teacher` | 公告列表页访问 | HTTP 200, URL: http://localhost:3000/announcements, 标题: 公告, 卡片数: 2 |
| ✅ | `ANN-DETAIL-teacher` | 公告详情页访问 | HTTP 200, URL: http://localhost:3000/announcements/ann_grade_g1 |
| ⚠️ | `ANN-ADMIN-LIST-teacher` | 管理员公告管理页访问 | HTTP 200, URL: http://localhost:3000/teacher/dashboard?from=%2Fadmin%2Fannouncements&reason=forbidden |
| ✅ | `MSG-LIST-teacher` | 消息列表页访问 | HTTP 200, URL: http://localhost:3000/messages, 收件箱Tab存在, 已发送Tab存在, Tab切换成功, 撰写按钮存在 |
| ✅ | `MSG-SEARCH-teacher` | 消息搜索 | 搜索功能可用 |
| ⚠️ | `MSG-COMPOSE-teacher` | 撰写消息页访问 | HTTP 200, URL: http://localhost:3000/messages/compose |
| ✅ | `MSG-SEND-teacher` | 发送消息 | 发送成功，跳转至: http://localhost:3000/messages |
| ⚠️ | `MSG-DETAIL-teacher` | 消息详情页访问 | HTTP 200, URL: http://localhost:3000/messages/ezekhvfwi58nqwus0zojv69j |
| ✅ | `MSG-REPLY-teacher` | 消息回复 | 回复链接正确，URL: http://localhost:3000/messages/compose?parentId=ezekhvfwi58nqwus0zojv69j&receiverId=user_p_s_g1c1_1&subject=Re%3A%20%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B%E8%AF%95%E6%B6%88%E6%81%AF_194327 |
| ✅ | `MSG-DELETE-BTN-teacher` | 消息删除按钮 | 删除按钮存在 |

### student 角色测试结果

| 状态 | 用例 ID | 名称 | 详情 |
|------|---------|------|------|
| ⚠️ | `ANN-LIST-student` | 公告列表页访问 | HTTP 200, URL: http://localhost:3000/announcements, 标题: 公告, 卡片数: 3 |
| ✅ | `ANN-DETAIL-student` | 公告详情页访问 | HTTP 200, URL: http://localhost:3000/announcements/ann_class_g1c1 |
| ⚠️ | `ANN-ADMIN-LIST-student` | 管理员公告管理页访问 | HTTP 200, URL: http://localhost:3000/student/dashboard?from=%2Fadmin%2Fannouncements&reason=forbidden |
| ✅ | `MSG-LIST-student` | 消息列表页访问 | HTTP 200, URL: http://localhost:3000/messages, 收件箱Tab存在, 已发送Tab存在, Tab切换成功, 撰写按钮存在 |
| ✅ | `MSG-SEARCH-student` | 消息搜索 | 搜索功能可用 |
| ✅ | `MSG-COMPOSE-student` | 撰写消息页访问 | HTTP 200, URL: http://localhost:3000/messages/compose, 收件人选择器存在, 主题输入框存在, 内容输入框存在 |
| ✅ | `MSG-SEND-student` | 发送消息 | 发送成功，跳转至: http://localhost:3000/messages |
| ⚠️ | `MSG-DETAIL-student` | 消息详情页访问 | HTTP 200, URL: http://localhost:3000/messages/l4lxgdpkdm3twlqox85msd1f |
| ✅ | `MSG-REPLY-student` | 消息回复 | 回复链接正确，URL: http://localhost:3000/messages/compose?parentId=l4lxgdpkdm3twlqox85msd1f&receiverId=user_T_C1&subject=Re%3A%20%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B%E8%AF%95%E6%B6%88%E6%81%AF_194612 |
| ✅ | `MSG-DELETE-BTN-student` | 消息删除按钮 | 删除按钮存在 |

### parent 角色测试结果

| 状态 | 用例 ID | 名称 | 详情 |
|------|---------|------|------|
| ✅ | `ANN-LIST-parent` | 公告列表页访问 | HTTP 200, URL: http://localhost:3000/announcements, 标题: 公告, 卡片数: 3 |
| ⚠️ | `ANN-DETAIL-parent` | 公告详情页访问 | HTTP 200, URL: http://localhost:3000/announcements/ann_class_g1c1 |
| ⚠️ | `ANN-ADMIN-LIST-parent` | 管理员公告管理页访问 | HTTP 200, URL: http://localhost:3000/parent/dashboard?from=%2Fadmin%2Fannouncements&reason=forbidden |
| ✅ | `MSG-LIST-parent` | 消息列表页访问 | HTTP 200, URL: http://localhost:3000/messages, 收件箱Tab存在, 已发送Tab存在, Tab切换成功, 撰写按钮存在 |
| ✅ | `MSG-SEARCH-parent` | 消息搜索 | 搜索功能可用 |
| ⚠️ | `MSG-COMPOSE-parent` | 撰写消息页访问 | HTTP 200, URL: http://localhost:3000/messages/compose |
| ✅ | `MSG-SEND-parent` | 发送消息 | 发送成功，跳转至: http://localhost:3000/messages |
| ⚠️ | `MSG-DETAIL-parent` | 消息详情页访问 | HTTP 200, URL: http://localhost:3000/messages/zy7o8kx9m2jm2z7t1kh4opkk |
| ✅ | `MSG-REPLY-parent` | 消息回复 | 回复链接正确，URL: http://localhost:3000/messages/compose?parentId=zy7o8kx9m2jm2z7t1kh4opkk&receiverId=user_admin&subject=Re%3A%20%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B%E8%AF%95%E6%B6%88%E6%81%AF_194519 |
| ✅ | `MSG-DELETE-BTN-parent` | 消息删除按钮 | 删除按钮存在 |

---

## 五、警告用例详情

### ⚠️ `ANN-LIST-admin` - 公告列表页访问

- **角色**: admin
- **详情**: HTTP 200, URL: http://localhost:3000/announcements, 标题: 公告, 卡片数: 3
  - 控制台错误 1 条

### ⚠️ `ANN-DETAIL-admin` - 公告详情页访问

- **角色**: admin
- **详情**: HTTP 200, URL: http://localhost:3000/announcements/ann_class_g1c1
  - 控制台错误 1 条

### ⚠️ `ANN-ADMIN-LIST-admin` - 管理员公告管理页访问

- **角色**: admin
- **详情**: HTTP 200, URL: http://localhost:3000/admin/announcements
  - 控制台错误 1 条

### ⚠️ `MSG-DETAIL-admin` - 消息详情页访问

- **角色**: admin
- **详情**: 未发现消息详情链接（可能无消息）

### ⚠️ `MSG-REPLY-admin` - 消息回复

- **角色**: admin
- **详情**: 无可用消息，跳过回复测试

### ⚠️ `MSG-DELETE-BTN-admin` - 消息删除按钮

- **角色**: admin
- **详情**: 无可用消息，跳过删除测试

### ⚠️ `ANN-LIST-teacher` - 公告列表页访问

- **角色**: teacher
- **详情**: HTTP 200, URL: http://localhost:3000/announcements, 标题: 公告, 卡片数: 2
  - 控制台错误 1 条

### ⚠️ `ANN-ADMIN-LIST-teacher` - 管理员公告管理页访问

- **角色**: teacher
- **详情**: HTTP 200, URL: http://localhost:3000/teacher/dashboard?from=%2Fadmin%2Fannouncements&reason=forbidden
  - 非管理员访问管理页未显示明确的权限拒绝

### ⚠️ `MSG-COMPOSE-teacher` - 撰写消息页访问

- **角色**: teacher
- **详情**: HTTP 200, URL: http://localhost:3000/messages/compose
  - 控制台错误 1 条

### ⚠️ `MSG-DETAIL-teacher` - 消息详情页访问

- **角色**: teacher
- **详情**: HTTP 200, URL: http://localhost:3000/messages/ezekhvfwi58nqwus0zojv69j
  - 控制台错误 1 条

### ⚠️ `ANN-LIST-student` - 公告列表页访问

- **角色**: student
- **详情**: HTTP 200, URL: http://localhost:3000/announcements, 标题: 公告, 卡片数: 3
  - 控制台错误 1 条

### ⚠️ `ANN-ADMIN-LIST-student` - 管理员公告管理页访问

- **角色**: student
- **详情**: HTTP 200, URL: http://localhost:3000/student/dashboard?from=%2Fadmin%2Fannouncements&reason=forbidden
  - 非管理员访问管理页未显示明确的权限拒绝

### ⚠️ `MSG-DETAIL-student` - 消息详情页访问

- **角色**: student
- **详情**: HTTP 200, URL: http://localhost:3000/messages/l4lxgdpkdm3twlqox85msd1f
  - 控制台错误 1 条

### ⚠️ `ANN-DETAIL-parent` - 公告详情页访问

- **角色**: parent
- **详情**: HTTP 200, URL: http://localhost:3000/announcements/ann_class_g1c1
  - 控制台错误 1 条

### ⚠️ `ANN-ADMIN-LIST-parent` - 管理员公告管理页访问

- **角色**: parent
- **详情**: HTTP 200, URL: http://localhost:3000/parent/dashboard?from=%2Fadmin%2Fannouncements&reason=forbidden
  - 非管理员访问管理页未显示明确的权限拒绝

### ⚠️ `MSG-COMPOSE-parent` - 撰写消息页访问

- **角色**: parent
- **详情**: HTTP 200, URL: http://localhost:3000/messages/compose
  - 控制台错误 1 条

### ⚠️ `MSG-DETAIL-parent` - 消息详情页访问

- **角色**: parent
- **详情**: HTTP 200, URL: http://localhost:3000/messages/zy7o8kx9m2jm2z7t1kh4opkk
  - 控制台错误 1 条

---

## 六、修复记录

### 🔧 修复 /announcements 页面 HTTP 500 错误

- **文件**: `src/modules/announcements/components/announcement-list.tsx, src/app/(dashboard)/announcements/page.tsx`
- **问题**: Server Component (/announcements/page.tsx) 直接传递函数 detailHrefBuilder 给 Client Component (AnnouncementList)，违反 Next.js 16 的序列化规则，导致 'Functions cannot be passed directly to Client Components' 错误。
- **修复**: 在 AnnouncementList 中新增 detailHrefPrefix prop（字符串类型，Server Component 安全），内部通过 prefix + id 拼接构建详情链接。/announcements 和 /admin/announcements 页面改用 detailHrefPrefix 代替 detailHrefBuilder。保留 detailHrefBuilder 以兼容现有 Client Component 间调用。

### 🔧 修复消息发送失败 - 数据库 schema 不同步

- **文件**: `数据库 messages 表`
- **问题**: schema.ts 中定义了 senderDeletedAt 和 receiverDeletedAt 列（用于软删除），但数据库 messages 表缺失这两列，导致 createMessage INSERT 查询失败，返回 'Failed query: insert into messages' 错误。
- **修复**: 通过 ALTER TABLE messages ADD COLUMN sender_deleted_at TIMESTAMP NULL 和 ALTER TABLE messages ADD COLUMN receiver_deleted_at TIMESTAMP NULL 手动添加缺失列，使数据库 schema 与代码 schema 保持同步。

---

## 七、控制台错误汇总

共收集到 11 条控制台错误：

1. **[admin] ANN-LIST-admin**: `A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. This can happen if a SSR`
2. **[admin] ANN-DETAIL-admin**: `A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. This can happen if a SSR`
3. **[admin] ANN-ADMIN-LIST-admin**: `A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. This can happen if a SSR`
4. **[teacher] ANN-LIST-teacher**: `A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. This can happen if a SSR`
5. **[teacher] MSG-COMPOSE-teacher**: `A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. This can happen if a SSR`
6. **[teacher] MSG-DETAIL-teacher**: `A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. This can happen if a SSR`
7. **[student] ANN-LIST-student**: `A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. This can happen if a SSR`
8. **[student] MSG-DETAIL-student**: `A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. This can happen if a SSR`
9. **[parent] ANN-DETAIL-parent**: `A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. This can happen if a SSR`
10. **[parent] MSG-COMPOSE-parent**: `A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. This can happen if a SSR`
11. **[parent] MSG-DETAIL-parent**: `A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. This can happen if a SSR`

---

## 八、测试结论

✅ **无失败用例**，但有 17 个警告需要关注。

🔧 本次测试期间已修复 2 个问题。

---

*报告自动生成于 2026-06-22 19:44:12*