hookehuyr

docs(plan): 更新新功能开发计划文档

更新 26.1.26 新功能开发计划文档,重新组织内容结构并完善细节:
- 按优先级重新排序功能:置顶、评论、评论列表为高优先级,海报为中优先级
- 新增教师评论管理功能需求
- 完善数据字段定义和 API 接口汇总
- 细化开发步骤为四个阶段并明确里程碑
- 补充边界条件、性能优化和测试计划
......@@ -2,19 +2,18 @@
## 背景
为了增强用户在打卡列表的互动性和管理能力,需要在打卡卡片(CheckinCard)上增加更多操作选项,包括置顶、评论、海报分享以及展示评论列表。这些功能将通过环境变量开关进行控制,以便按需开启。
为了增强用户在打卡列表的互动性和管理能力,需要在打卡卡片(CheckinCard)上增加更多操作选项,包括置顶、评论、海报分享以及展示评论列表。这些功能将通过环境变量开关进行控制,以便按需开启。
## 需求拆解
1. **全局功能开关**:在 `.env` 文件中通过变量控制各功能的开启/关闭。
2. **置顶功能 (Top)**:允许将特定打卡内容置顶。
3. **评论/评论功能 (Comment)**:允许对打卡内容进行评论(评论)。
4. **打卡海报 (Poster)**:生成包含打卡内容的长图海报,支持分享。
5. **评论列表 (Comment List)**:在打卡卡片下方显示该打卡的评论/评论记录。
1. **置顶功能** (优先级: 🔴 高) - 允许教师将特定打卡内容置顶
2. **评论功能** (优先级: 🔴 高) - 允许用户对打卡内容进行评论
3. **评论列表** (优先级: 🔴 高) - 在打卡卡片下方显示该打卡的评论记录
4. **海报功能** (优先级: 🟡 中) - 生成包含打卡内容的长图海报,支持分享
## 环境变量规划
`.env` 中增加以下开关(默认 '0' 关闭,'1' 开启):
`.env` 中增加以下开关(默认 '0' 关闭,'1' 开启):
- `VITE_FEATURE_CHECKIN_TOP=1` (置顶功能)
- `VITE_FEATURE_CHECKIN_COMMENT=1` (评论功能)
......@@ -25,278 +24,677 @@
### 1. 入口改造 (CheckinCard)
- **位置**`CheckinCard` 组件底部右侧操作区(原点赞/更多按钮处)。
- **交互**:点击“...”图标,从底部弹出 `ActionSheet`(Vant 组件)。
- **菜单项**
- **置顶**:仅当 `VITE_FEATURE_CHECKIN_TOP=1` 时显示。若已置顶,显示“取消置顶”。
- **评论**:仅当 `VITE_FEATURE_CHECKIN_COMMENT=1` 时显示。
- **海报**:仅当 `VITE_FEATURE_CHECKIN_POSTER=1` 时显示。
### 2. 置顶功能 (Top)
- **逻辑**
1. 点击“置顶”菜单。
2. 弹出确认框 `showConfirmDialog`:“确定要置顶这条打卡吗?”。
3. 用户确认 -> 调用 API `teacherPinCheckinAPI(id)`
4. API 成功 -> Toast “置顶成功” -> 更新列表数据(将该项标记为置顶,或刷新列表)。
5. 若已置顶 -> 点击“取消置顶” -> 确认 -> API `teacherUnpinCheckinAPI(id)` -> Toast “取消置顶成功” -> 更新状态。
- **要点**:这个功能属于教师端功能, 需要先判断这个用户的userinfo是否是老师, 使用is_teacher字段判断, 没有权限则不显示置顶菜单.
- **API**
- `teacherPinCheckinAPI` 老师置顶打卡 (参数: `checkin_id`)
- `teacherUnpinCheckinAPI` 老师取消置顶打卡 (参数: `checkin_id`)
### 3. 评论功能 (Comment)
- **逻辑**
1. 点击"评论"菜单。
2. 弹出 **评论输入弹窗**(新建组件 `CheckinCommentDialog`)。
- 包含:文本输入框(Textarea)、表情选择器按钮。
- **表情选择器**:点击表情图标,从底部弹出表情面板,支持常用 Emoji 表情符号(😊❤️👍🎉等)。
- 输入验证:纯文本评论至少 5 个字符,允许表情符号作为补充。
- 按钮:取消、提交。
3. 点击表情图标 -> 弹出表情选择面板(底部 Popup)-> 选择表情 -> 插入到光标位置。
4. 输入内容(文本 + 表情)-> 点击提交。
5. 调用 API `commentCheckin(id, content)`
6. API 成功 -> Toast "评论成功" -> 关闭弹窗 -> 刷新该打卡的评论列表。
- **要点**
- 这个功能属于用户端功能, 只能在`/checkin/index`打卡主页上的打卡卡片上显示出来。
- 表情选择器技术方案:自定义 Emoji 列表。
- 表情数据:使用原生 Unicode Emoji,无需图片资源,体积小且兼容性好。
- 常用表情建议:😊😂❤️👍🎉✨🙏💪🔥💯😍👏🤝🌟🎁
- **组件**`CheckinCommentDialog.vue` (基于 Vant Popup 封装,底部弹出)。
- **API (需 Mock/确认)**
- `POST /checkin/comment` (发表评论,参数: `checkin_id`, `content`)
### 4. 海报功能 (Poster)
- **逻辑**
1. 点击“海报”菜单。
2. 弹出 **海报预览组件** (`CheckinPoster`,参考 `SharePoster`)。
3. **渲染内容**
- 用户信息(头像、昵称)。
- 打卡内容(文本、图片缩略图)。
- 底部二维码(打卡主页的网址自动生成)。
- *注:需支持长图,若内容过长,通过滚动查看,生成图片时需完整截取。*
4. **生成图片**:使用 `html2canvas``html-to-image` 将 DOM 转为图片。
5. 展示生成的图片,提示“长按保存”。
- **组件**`CheckinPoster.vue`
- **技术点**:处理跨域图片、长图渲染、字体加载。
### 5. 评论列表 (Comment List)
- **位置**`CheckinCard` 组件内部下方。
- **显示条件**`VITE_FEATURE_CHECKIN_COMMENT_LIST=1``post.comments` 长度 > 0。
- **样式**:参考朋友圈评论区(灰色背景,每行 `用户: 内容`)。
- **逻辑**
- 渲染评论列表,支持 Emoji 表情符号的显示。
- 列车最多展示5条评论, 超过5条的评论需要点击"查看全部"才能看到.
- 用户自己评论的右侧需要显示一个删除图标, 点击图标弹出确认框, 确认后调用删除接口删除该条评论.
- **交互与操作**
- **回复**:点击某一条评论,从屏幕底部弹出输入框(类似微信朋友圈),键盘自动升起。输入框同样支持表情选择器。输入内容后点击发送,即为回复该条评论。
- 数据结构:使用 `parent_id` 标识父评论,`reply_to_user_id` 标识被回复用户。
- 显示样式:`用户A 回复 用户B: 评论内容`
- **删除**:点击用户**自己**发布的评论,弹出 `ActionSheet` 或确认框,选项包含"删除"。确认后调用删除接口移除该评论。
- **样式参考**:整体交互逻辑和视觉风格严格参考微信朋友圈。
- **Emoji 渲染**:评论内容中的 Emoji 符号直接使用原生 Unicode 渲染,无需特殊处理。
- **组件**`CheckinCommentList.vue` (复用 `StudyCommentsSection.vue` 的设计模式)。
- **API (需 Mock/确认)**
- `GET /checkin/comments` (获取评论列表,参数: `checkin_id`, `page`, `page_size`)
- `POST /checkin/comment` (发表评论,参数: `checkin_id`, `content`)
- `POST /checkin/comment/reply` (回复评论,参数: `checkin_id`, `content`, `parent_id`, `reply_to_user_id`)
- `DELETE /checkin/comment/:id` (删除评论,参数: `comment_id`)
**位置**: `CheckinCard` 组件底部右侧操作区(原点赞/更多按钮处)
**交互**: 点击"..."图标,从底部弹出 `ActionSheet`(Vant 组件)
**菜单项**:
- **置顶** (仅教师可见): 仅当 `VITE_FEATURE_CHECKIN_TOP=1` 时显示。若已置顶,显示"取消置顶"
- **评论** (仅用户端可见): 仅当 `VITE_FEATURE_CHECKIN_COMMENT=1` 时显示,仅在 `/checkin/index` 打卡主页显示
- **海报** (通用): 仅当 `VITE_FEATURE_CHECKIN_POSTER=1` 时显示
### 2. 置顶功能 🔴 高优先级
#### 权限控制
- **仅教师可见**: 使用 `user.is_teacher` 字段判断权限
- **权限获取**: 前端需实时请求后端接口获取用户角色,不依赖缓存的 `localStorage.user_info`
- **适用范围**: 教师端所有打卡列表页面
#### 逻辑流程
1. 点击"置顶"菜单
2. 弹出确认框 `showConfirmDialog`:"确定要置顶这条打卡吗?"
3. 用户确认 -> 调用 API `teacherPinCheckinAPI(id)`
4. API 成功 -> Toast "置顶成功" -> 更新列表数据(将该项标记为置顶)
5. 若已置顶 -> 点击"取消置顶" -> 确认 -> API `teacherUnpinCheckinAPI(id)` -> Toast "取消置顶成功" -> 更新状态
#### 视觉标记
- 已置顶的打卡卡片右上角显示 📌 图标
- 卡片顶部显示"置顶"标签(使用 `van-tag` 组件)
#### API 接口
- `POST /api/teacher/pin-checkin` - 教师置顶打卡 (参数: `checkin_id`)
- `POST /api/teacher/unpin-checkin` - 教师取消置顶打卡 (参数: `checkin_id`)
#### 数据字段扩展
```javascript
{
is_pinned: false, // 是否置顶
pinned_at: null // 置顶时间
}
```
---
### 3. 评论功能 🔴 高优先级
#### 权限控制
- **仅用户端可用**: 只能在 `/checkin/index` 打卡主页的打卡卡片上显示
- **允许自评**: 允许用户评论自己的打卡
#### 评论输入弹窗 (CheckinCommentDialog)
**组件**: `CheckinCommentDialog.vue` (基于 Vant Popup 封装,底部弹出)
**功能特性**:
- 文本输入框 (`van-field`,多行模式)
- 表情选择器按钮
- 字符计数提示(最多 200 字)
- 按钮: 取消、提交
**表情选择器**:
- **技术方案**: 自定义 Emoji 面板,使用原生 Unicode Emoji
- **UI 实现**: `van-popup` 底部弹出 + `van-grid` 展示表情符号
- **常用表情**: 😊😂❤️👍🎉✨🙏💪🔥💯😍👏🤝🌟🎁😭😡🤔💭😴🎂🌈⭐🌙☀️🌺🌸🍀🎁🎈🎵🎶📱💻⚽🏀🎾🎯🎨🎬📷🎤🎧📚✏️📝💡🔔💬📧📞
- **交互逻辑**: 点击表情 -> 插入到输入框光标位置 -> 自动关闭面板
**输入验证**:
- 纯文本评论至少 5 个字符
- 允许纯表情评论(无文字)
- 字符计数使用 `Array.from(text).length` 计算(正确处理 Emoji 代理对)
- 前端实时提示剩余字数
#### API 接口
- `POST /api/checkin/comment` - 发表评论
- 参数: `checkin_id`, `content` (评论内容,最多 200 字)
- 返回: `{ code: 1, data: { comment_id: 123 }, msg: '' }`
- **无需敏感词过滤**: 后端不进行敏感词过滤
#### 通知机制
- 评论后不需要前端主动触发通知
- 后端会自动发送通知给打卡用户或被回复用户
---
### 4. 评论列表功能 🔴 高优先级
#### 位置与显示
**位置**: `CheckinCard` 组件内部下方
**显示条件**: `VITE_FEATURE_CHECKIN_COMMENT_LIST=1``post.comments.length > 0`
#### 评论列表展示 (CheckinCommentList)
**组件**: `CheckinCommentList.vue` (参考 `StudyCommentsSection.vue` 的实现模式)
**显示逻辑**:
- 首屏最多展示 5 条评论
- 超过 5 条显示"查看全部"按钮
- 点击"查看全部"加载完整评论列表(懒加载)
- 样式参考微信朋友圈(灰色背景,每行 `用户: 内容`)
**数据结构** (扁平化设计):
```javascript
{
id: 1, // 评论 ID
checkin_id: 123, // 关联的打卡 ID
user_id: 456, // 评论者 ID
user_name: "张三", // 评论者昵称
content: "干得漂亮!🎉", // 评论内容
parent_id: 0, // 父评论 ID (0 表示一级评论)
reply_to_user_id: null, // 被回复用户 ID (一级评论为 null)
reply_to_user_name: null, // 被回复用户昵称
is_my: false, // 是否是自己发表的评论
created_at: "2026-01-26 10:00:00"
}
```
**评论样式**:
- 一级评论: `张三: 干得漂亮!🎉`
- 回复评论: `张三 回复 李四: 我也这么觉得!`
- Emoji 符号直接使用原生 Unicode 渲染
#### 交互功能
**回复评论**:
1. 点击某一条评论,从屏幕底部弹出输入框(类似微信朋友圈)
2. 键盘自动升起
3. 输入框同样支持表情选择器
4. 输入内容后点击发送,即为回复该条评论
5. 数据结构: 使用 `parent_id` 标识父评论,`reply_to_user_id` 标识被回复用户
6. 显示样式: `用户A 回复 用户B: 评论内容`
**删除评论**:
- 仅显示用户**自己**发布的评论的删除图标
- 点击图标弹出确认框:"确定要删除这条评论吗?"
- 确认后调用删除接口移除该评论
- API: `DELETE /api/checkin/comment/:id`
- **权限校验**:
- 前端: 通过接口返回的 `is_my` 字段判断是否显示删除按钮
- 后端: 接口层进行权限校验,确保只能删除自己的评论
- **教师权限**: 教师不可删除学生的评论
#### 教师评论管理 🔴 高优先级 (新增需求)
**适用场景**: 教师在 `/teacher` 路由下的打卡列表中管理评论
**功能**:
- 教师可以在评论列表中对不适当的评论进行审核
- 操作选项:
- **屏蔽**: 隐藏该评论(不删除,仅前端不显示)
- **通过**: 恢复该评论的显示
- 评论状态字段: `status` (`0` = 待审核, `1` = 已通过, `2` = 已屏蔽)
- **交互设计**:
- 在评论卡片右侧显示审核按钮(仅教师可见)
- 点击按钮弹出 ActionSheet: "屏蔽评论"、"通过评论"
- 操作后实时更新评论状态
**API 接口** (新增):
- `POST /api/teacher/review-comment` - 教师审核评论
- 参数: `comment_id`, `action` (`approve` | `reject`)
- 返回: `{ code: 1, data: {}, msg: '' }`
**数据字段扩展**:
```javascript
{
status: 1, // 评论状态: 0-待审核, 1-已通过, 2-已屏蔽
reviewed_at: null, // 审核时间
reviewed_by: null // 审核人 ID
}
```
#### API 接口
**获取评论列表**:
- `GET /api/checkin/comments`
- 参数: `checkin_id`, `page`, `page_size`
- 返回: `{ code: 1, data: { list: [], total: 100 }, msg: '' }`
- **注意**: 不包含完整的用户信息,仅返回 `user_id``user_name`
**发表评论**:
- `POST /api/checkin/comment`
- 参数: `checkin_id`, `content`
- 返回: `{ code: 1, data: { comment_id: 123 }, msg: '' }`
**回复评论**:
- `POST /api/checkin/comment/reply`
- 参数: `checkin_id`, `content`, `parent_id`, `reply_to_user_id`
- 返回: `{ code: 1, data: { comment_id: 124 }, msg: '' }`
**删除评论**:
- `DELETE /api/checkin/comment/:id`
- 参数: `comment_id`
- 返回: `{ code: 1, data: {}, msg: '' }`
#### 数据字段扩展
```javascript
{
comments_count: 0, // 评论总数(用于列表展示)
comments: [] // 评论列表(最多 5 条,用于首屏渲染)
}
```
---
### 5. 海报功能 🟡 中优先级
#### 逻辑流程
1. 点击"海报"菜单
2. 弹出 **海报预览组件** (`CheckinPoster`,参考 `SharePoster`)
3. **渲染内容**:
- 用户信息(头像、昵称)
- 打卡内容(文本、图片缩略图)
- 底部二维码(打卡主页的网址自动生成)
- 支持长图,若内容过长通过滚动查看
4. **生成图片**: 使用 `html2canvas``html-to-image` 将 DOM 转为图片
5. 展示生成的图片,提示"长按保存"
#### 降级方案
- 海报生成是异步操作,可能会失败
- 生成失败时显示降级卡片:
- 卡片包含: 用户头像、昵称、打卡内容摘要
- 底部提示: "长按截图保存分享"
- 用户可手动截图保存
#### 技术要点
- 处理跨域图片: 配置 `useCORS: true` 且 CDN 支持 CORS
- 长图渲染: 需限制最大高度或分段(第一版暂不考虑极端情况)
- 字体加载: 确保字体加载完成后再生成图片
---
## 开发步骤
### 第 1 步:环境准备与 Mock API
-`.env` 添加开关变量。
-`src/api` 定义相关接口(Top, Comment),前期可使用 Mock 数据验证流程。
### 第 2 步:改造 CheckinCard 菜单
- 引入 `ActionSheet`
- 根据 Env 开关动态显示菜单项。
- 实现基础点击事件处理。
### 第 3 步:实现置顶逻辑
- 对接置顶/取消置顶 API。
- 添加确认弹窗。
- 处理列表状态更新。
- **置顶视觉标记**:在已置顶的打卡卡片上显示"📌 置顶"标记。
### 第 4 步:实现评论功能与列表
- 创建 `CheckinCommentDialog` 组件。
- 实现 `van-field` 文本输入框(支持多行)。
- **实现表情选择器**
- 方案选择:自定义 Emoji 面板(不引入额外依赖,使用原生 Unicode Emoji)。
- UI 实现:`van-popup` 底部弹出 + `van-grid` 展示表情符号。
- 交互逻辑:点击表情 -> 插入到输入框光标位置 -> 自动关闭面板。
- 常用表情列表:😊😂❤️👍🎉✨🙏💪🔥💯😍👏🤝🌟🎁😭😡🤔💭😴🎂🌈⭐🌙☀️🌺🌸🍀🎁🎈🎵🎶📱💻⚽🏀🎾🎯🎨🎬📷🎤🎧📚✏️📝💡🔔💬📧📞
- 实现输入验证(文本至少 5 字,表情可作为补充)。
-`CheckinCard` 中引入并调用评论弹窗。
- 创建 `CheckinCommentList` 组件(/components/checkin/CheckinCommentList.vue)。
- 参考 `StudyCommentsSection.vue` 的实现模式。
- 支持评论列表展示(最多 5 条,超过则显示"查看全部")。
- 支持 Emoji 符号的直接渲染。
- 实现评论回复交互(底部输入框弹出,同样支持表情选择)。
- 实现删除逻辑(仅显示自己评论的删除图标)。
- 对接评论、回复、删除 API 和列表展示数据。
### 第 5 步:实现打卡海报
- 创建 `CheckinPoster` 组件。
- 实现布局(支持长内容)。
- 集成 `html2canvas` 生成逻辑。
- 对接 `CheckinCard` 菜单。
### 🔴 第 1 阶段: 置顶功能 (高优先级)
**目标**: 实现教师置顶打卡功能
**步骤**:
1. **环境准备**:
-`.env` 添加 `VITE_FEATURE_CHECKIN_TOP=1`
-`src/api/teacher.js` 中定义 `teacherPinCheckinAPI``teacherUnpinCheckinAPI` (已实现)
2. **用户权限获取**:
- 创建 `useAuthRole.js` composable
- 实现实时请求用户角色接口(不依赖 localStorage)
- 返回 `{ is_teacher: boolean }`
3. **改造 CheckinCard**:
- 引入 `van-action-sheet`
- 在菜单中添加"置顶"/"取消置顶"选项(根据 `is_pinned``is_teacher` 动态显示)
- 实现置顶确认弹窗
4. **置顶逻辑实现**:
- 对接置顶/取消置顶 API
- 成功后更新列表数据(本地更新,避免全列表刷新)
- 已置顶卡片显示 📌 图标和"置顶"标签
5. **测试**:
- 教师账号验证置顶功能
- 学生账号验证置顶菜单不显示
- 刷新页面验证置顶状态持久化
---
### 🔴 第 2 阶段: 评论功能 (高优先级)
**目标**: 实现用户发表评论功能
**步骤**:
1. **环境准备**:
-`.env` 添加 `VITE_FEATURE_CHECKIN_COMMENT=1`
-`src/api/checkin.js` 中定义 `addCheckinCommentAPI`
2. **创建评论输入弹窗**:
- 创建 `CheckinCommentDialog.vue` 组件
- 实现 `van-field` 文本输入框(多行模式)
- 实现字符计数提示(最多 200 字)
3. **实现表情选择器**:
- 创建 `EmojiPicker.vue` 组件
- 使用 `van-popup` + `van-grid` 展示表情符号
- 实现点击表情插入到输入框光标位置
- 定义常用表情列表(原生 Unicode Emoji)
4. **输入验证**:
- 实现字符计数逻辑(`Array.from(text).length`)
- 纯文本评论至少 5 字
- 允许纯表情评论
- 实时提示剩余字数
5. **对接 API**:
- 实现发表评论接口调用
- 成功后 Toast "评论成功"
- 关闭弹窗并刷新评论列表
6. **集成到 CheckinCard**:
-`/checkin/index` 页面的打卡卡片菜单中添加"评论"选项
- 点击评论菜单打开 `CheckinCommentDialog`
- 仅用户端可见(教师端不显示)
7. **测试**:
- 测试纯文本评论(最少 5 字)
- 测试纯表情评论
- 测试混合评论(文本 + 表情)
- 测试字符计数准确性
- 测试 200 字符限制
- 测试表情插入到光标位置
---
### 🔴 第 3 阶段: 评论列表 (高优先级)
**目标**: 实现评论列表展示、回复、删除功能
**步骤**:
1. **环境准备**:
-`.env` 添加 `VITE_FEATURE_CHECKIN_COMMENT_LIST=1`
-`src/api/checkin.js` 中定义评论相关 API:
- `getCheckinCommentsAPI` - 获取评论列表
- `replyCheckinCommentAPI` - 回复评论
- `deleteCheckinCommentAPI` - 删除评论
2. **创建评论列表组件**:
- 创建 `CheckinCommentList.vue` 组件
- 参考 `StudyCommentsSection.vue` 的实现模式
- 实现首屏展示最多 5 条评论
- 超过 5 条显示"查看全部"按钮
3. **实现评论样式**:
- 一级评论: `用户名: 评论内容`
- 回复评论: `用户名 回复 被回复用户名: 评论内容`
- 灰色背景,参考微信朋友圈样式
- Emoji 符号直接渲染(无需特殊处理)
4. **实现回复功能**:
- 点击评论弹出底部输入框(类似微信朋友圈)
- 输入框支持表情选择器(复用 `EmojiPicker.vue`)
- 实现回复 API 调用
- 成功后刷新评论列表
5. **实现删除功能**:
- 仅显示自己评论的删除图标(根据 `is_my` 字段判断)
- 点击删除图标弹出确认框
- 确认后调用删除 API
- 成功后从列表中移除该评论
6. **实现懒加载**:
- 首屏仅加载前 5 条评论(从 `post.comments` 字段读取)
- 点击"查看全部"调用 `getCheckinCommentsAPI` 加载完整列表
- 实现分页加载
7. **集成到 CheckinCard**:
-`CheckinCard` 底部引入 `CheckinCommentList`
- 根据 `comments_count``comments` 字段渲染
- 评论发表成功后自动刷新列表
8. **教师评论管理** (新增):
-`/teacher` 路由下的打卡列表中启用评论管理
- 教师可在评论列表中查看所有评论
- 在评论卡片右侧显示审核按钮(仅教师可见)
- 实现评论屏蔽/通过功能
- 对接 `teacherReviewCommentAPI` (新增)
- 操作后实时更新评论状态
9. **测试**:
- 测试评论列表展示(一级评论、回复评论)
- 测试"查看全部"懒加载
- 测试评论回复功能
- 测试评论删除功能(自己的评论、别人的评论)
- 测试 Emoji 渲染
- 测试教师评论管理功能(屏蔽/通过)
- 测试权限控制(学生不可见审核按钮)
---
### 🟡 第 4 阶段: 海报功能 (中优先级)
**目标**: 实现打卡海报生成与分享
**步骤**:
1. **环境准备**:
-`.env` 添加 `VITE_FEATURE_CHECKIN_POSTER=1`
- 安装依赖: `pnpm add html2canvas`
2. **创建海报组件**:
- 创建 `CheckinPoster.vue` 组件
- 参考 `SharePoster.vue` 的实现模式
- 实现布局: 用户信息、打卡内容、二维码
3. **实现长图渲染**:
- 支持长内容滚动查看
- 处理多图展示(网格布局)
- 处理文本换行
4. **实现图片生成**:
- 使用 `html2canvas` 将 DOM 转为图片
- 配置 `useCORS: true` 处理跨域图片
- 添加 `crossorigin="anonymous"` 到图片标签
- 生成后展示图片并提示"长按保存"
5. **实现降级方案**:
- 监听 `html2canvas` 失败情况
- 失败时显示文字版卡片
- 提示用户"长按截图保存"
6. **集成到 CheckinCard**:
- 在打卡菜单中添加"海报"选项
- 点击后打开 `CheckinPoster` 弹窗
- 传入打卡信息
7. **测试**:
- 测试不同内容长度的海报生成
- 测试跨域图片处理
- 测试降级方案(生成失败时)
- 测试在微信内置浏览器的兼容性
- 测试长按保存功能
---
## 边界条件与注意点
1. **权限控制**
- 置顶功能是否仅管理员可见?(前端暂通过 Env 控制全局,根据用户角色判断)。
- 评论功能是否允许自己评论自己?(需后端确认,前端暂不做限制)。
2. **表情输入处理**
- **字符计数**:Emoji 符号在某些设备上可能占用 2 个字符位置(代理对),需使用 `Array.from(text).length` 计算真实字符数。
- **输入限制**:限制单条评论最多 200 个字符(包含 Emoji),前端实时提示剩余字数。
- **兼容性**:原生 Unicode Emoji 在 iOS/Android/微信内置浏览器中均能正常显示,无需降级方案。
- **存储**:后端需确保数据库字符集支持 UTF-8 MB4(MySQL 5.5.3+ 的 `utf8mb4`),否则部分 Emoji(如 🎁)会乱码。
3. **海报生成**
- 图片跨域问题(需配置 `useCORS: true` 且 CDN 支持)。
- 内容过长导致 Canvas 内存溢出(需限制最大高度或分段,第一版暂不考虑极端情况)。
4. **列表更新**
- 操作后尽量避免全列表刷新,采用本地数据更新(Update Item)以提升体验。
5. **评论回复数据结构**
- 建议使用扁平化结构(所有评论在同一层级,通过 `parent_id` 关联),便于分页和排序。
- 示例:
```javascript
{
id: 1,
checkin_id: 123,
user_id: 456,
content: "干得漂亮!🎉",
parent_id: 0, // 0 表示一级评论
reply_to_user_id: null, // 一级评论为 null
created_at: "2026-01-26 10:00:00"
}
```
6. **CheckinCard 数据结构扩展**
- 现有 `post` 对象需要新增以下字段:
```javascript
{
id: 123,
user: { name: "张三", avatar: "..." },
content: "今天完成了100天打卡!",
images: [...],
videoList: [...],
audio: [...],
likes: 10,
is_liked: false,
is_my: true,
// 🆕 新增字段
is_pinned: false, // 是否置顶
pinned_at: null, // 置顶时间
comments_count: 0, // 评论总数(用于列表展示)
comments: [] // 评论列表(最多5条)
}
```
7. **性能优化**
- **评论列表懒加载**:仅在用户展开"查看全部"时才加载完整评论列表,首屏只加载前 5 条。
- **图片懒加载**:海报生成时使用 `loading="lazy"` 避免一次性加载所有图片。
- **列表虚拟滚动**:如果打卡列表超过 50 条,考虑使用 `van-list` 的虚拟滚动模式。
8. **错误处理**
- **网络错误**:API 调用失败时,显示 Toast 提示用户,并提供"重试"按钮。
- **并发冲突**:删除评论时,若该评论已被删除,提示"该评论不存在"。
9. **测试计划**
- **单元测试**:测试 `CheckinCommentDialog` 组件的输入验证、Emoji 插入逻辑。
- **集成测试**:测试评论发表、回复、删除的完整流程。
- **边界测试**:测试 200 字符限制、Emoji 字符计数、空评论提交等边界情况。
- **兼容性测试**:在 iOS Safari、Android Chrome、微信内置浏览器中测试 Emoji 显示。
### 1. 字符计数与 Emoji 处理
**问题**: Emoji 符号在某些设备上占用 2 个字符位置(代理对)
**解决方案**:
```javascript
// 错误方式
text.length // 可能将 Emoji 算作 2 个字符
// 正确方式
Array.from(text).length // 正确计算字符数
```
**验证规则**:
- 纯文本评论至少 5 个字符
- 允许纯表情评论(无文字)
- 单条评论最多 200 个字符(包含 Emoji)
### 2. 数据库字符集支持
**要求**: 后端数据库需使用 UTF-8 MB4 字符集
- MySQL 5.5.3+ 的 `utf8mb4`
- 否则部分 Emoji(如 🎁)会乱码
### 3. 列表更新策略
**原则**: 避免全列表刷新,采用本地数据更新
**实现方式**:
- 置顶成功: 更新本地卡片的 `is_pinned` 字段
- 评论成功: 在本地评论列表中新增评论项
- 删除成功: 从本地评论列表中移除评论项
- 仅在必要时调用接口刷新列表
### 4. 权限控制
**置顶功能**:
- 仅教师可见(通过 `is_teacher` 字段判断)
- 权限实时获取(不依赖 localStorage)
**评论功能**:
- 仅用户端可见(仅在 `/checkin/index` 显示)
- 允许自评
**删除评论**:
- 仅可删除自己的评论(通过 `is_my` 字段判断)
- 教师不可删除学生的评论
**教师评论管理**:
- 仅教师可见审核按钮
- 可屏蔽或通过任何评论
### 5. 性能优化
**评论列表懒加载**:
- 首屏仅加载前 5 条评论
- 点击"查看全部"时加载完整列表
- 实现分页加载
**图片懒加载**:
- 海报生成时使用 `loading="lazy"`
- 避免一次性加载所有图片
**列表虚拟滚动**:
- 如果打卡列表超过 50 条,使用 `van-list` 的虚拟滚动模式
### 6. 错误处理
**网络错误**:
- API 调用失败时,显示 Toast 提示用户
- 提供"重试"按钮
**并发冲突**:
- 删除评论时,若该评论已被删除,提示"该评论不存在"
- 评论发表时,若打卡已被删除,提示"该打卡不存在"
**海报生成失败**:
- 捕获 `html2canvas` 异常
- 显示降级方案(文字版卡片)
### 7. 测试计划
**单元测试**:
- 测试 `CheckinCommentDialog` 组件的输入验证
- 测试 Emoji 插入逻辑
- 测试字符计数准确性
**集成测试**:
- 测试评论发表、回复、删除的完整流程
- 测试置顶、取消置顶的完整流程
- 测试海报生成流程
**边界测试**:
- 测试 200 字符限制
- 测试纯表情评论
- 测试空评论提交(应被阻止)
- 测试长文本评论
**兼容性测试**:
- iOS Safari
- Android Chrome
- 微信内置浏览器
- 测试 Emoji 显示兼容性
---
## 数据字段扩展总结
### post 对象新增字段
```javascript
{
id: 123,
user: { name: "张三", avatar: "..." },
content: "今天完成了100天打卡!",
images: [...],
videoList: [...],
audio: [...],
likes: 10,
is_liked: false,
is_my: true,
// 🆕 置顶功能字段
is_pinned: false, // 是否置顶
pinned_at: null, // 置顶时间
// 🆕 评论功能字段
comments_count: 0, // 评论总数
comments: [] // 评论列表(最多 5 条)
}
```
### comment 对象数据结构
```javascript
{
id: 1, // 评论 ID
checkin_id: 123, // 关联的打卡 ID
user_id: 456, // 评论者 ID
user_name: "张三", // 评论者昵称
content: "干得漂亮!🎉", // 评论内容
parent_id: 0, // 父评论 ID (0 表示一级评论)
reply_to_user_id: null, // 被回复用户 ID
reply_to_user_name: null, // 被回复用户昵称
is_my: false, // 是否是自己发表的评论
status: 1, // 评论状态: 0-待审核, 1-已通过, 2-已屏蔽
reviewed_at: null, // 审核时间
reviewed_by: null, // 审核人 ID
created_at: "2026-01-26 10:00:00"
}
```
### user 对象新增字段
```javascript
{
id: 123,
name: "张三",
avatar: "...",
// 🆕 角色字段
is_teacher: false // 是否是教师(需实时请求后端获取)
}
```
---
## API 接口汇总
### 置顶功能
- `POST /api/teacher/pin-checkin` - 教师置顶打卡 (参数: `checkin_id`)
- `POST /api/teacher/unpin-checkin` - 教师取消置顶打卡 (参数: `checkin_id`)
### 评论功能
- `GET /api/checkin/comments` - 获取评论列表 (参数: `checkin_id`, `page`, `page_size`)
- `POST /api/checkin/comment` - 发表评论 (参数: `checkin_id`, `content`)
- `POST /api/checkin/comment/reply` - 回复评论 (参数: `checkin_id`, `content`, `parent_id`, `reply_to_user_id`)
- `DELETE /api/checkin/comment/:id` - 删除评论 (参数: `comment_id`)
- `POST /api/teacher/review-comment` - 教师审核评论 (参数: `comment_id`, `action`)
### 权限获取
- `GET /api/user/role` - 获取用户角色信息 (返回: `{ is_teacher: boolean }`)
---
## 开发优先级总结
### 🔴 高优先级 (第 1 批)
1. **置顶功能** - 实现教师置顶打卡
2. **评论功能** - 实现用户发表评论
3. **评论列表** - 实现评论展示、回复、删除
4. **教师评论管理** - 实现教师审核评论
### 🟡 中优先级 (第 2 批)
5. **海报功能** - 实现打卡海报生成与分享
---
## 待确认事项
### 与后端确认
1. **API 接口**
- `GET /checkin/comments` - 评论列表接口(是否支持分页?返回数据结构是否包含用户信息?)支持分页, 不包含用户信息.
- `POST /checkin/comment` - 发表评论接口(是否需要敏感词过滤?返回值是什么?)不需要敏感词过滤, 返回值应该是评论ID.
- `POST /checkin/comment/reply` - 回复评论接口(参数是否完整?)参数完整, 包含评论ID, 回复内容, 回复用户ID. 返回值应该是回复评论ID.
- `DELETE /checkin/comment/:id` - 删除评论接口(是否有权限校验?)不需要校验, 列表会返回字段, 判断是否是自己的评论, 如果不是不会显示删除按钮.
- `teacherPinCheckinAPI` / `teacherUnpinCheckinAPI` - 接口已实现.
2. **数据字段**
- `post.is_pinned` - 置顶标记字段是否存在?
- `post.pinned_at` - 置顶时间字段是否存在?
- `post.comments_count` - 评论数字段是否存在?
- `post.comments` - 评论列表字段是否存在?(预加载前5条)
- `user.is_teacher` - 用户角色字段是否存在于 `localStorage.user_info`?在localStorage的currentUser中有存个人信息
3. **权限控制**
- 置顶功能:是否仅教师可见?是否有更细粒度的权限控制?仅教师可以置顶打卡.
- 删除评论:是否只能删除自己的评论?教师是否可以删除所有评论?
- 评论功能:是否允许自己评论自己的打卡?允许.
4. **业务规则**
- 评论字符限制:是 200 字还是其他数量?
- 是否允许发送纯表情评论(无文字)?
- 评论后是否需要通知打卡用户或被回复用户?
- 置顶数量限制:是否限制同时置顶的打卡数量?
### 与产品确认
1. **功能优先级**
- 4 个功能(置顶、评论、海报、评论列表)的开发优先级是什么?
- 是否需要在第一版就全部完成,还是可以分阶段上线?
2. **交互细节**
- 置顶的打卡是否需要特殊的视觉标记(如"📌 置顶"标签、置顶图标等)?
- 评论删除是否需要二次确认?(计划中已确认需要)
- 表情选择器是否需要分类(如"笑脸"、"手势"、"动物"等)?
- 海报生成失败时,是否需要降级方案(如显示文字版分享链接)?
3. **内容规范**
- 评论内容的敏感词过滤策略是什么?
- 是否需要举报功能?
- 是否需要审核机制(评论需审核后才能显示)?
4. **数据统计**
- 是否需要统计评论数量、置顶数量等数据用于运营分析?
## 里程碑
### 第 1 里程碑: 置顶功能完成
- ✅ 教师可以置顶/取消置顶打卡
- ✅ 置顶打卡显示 📌 图标
- ✅ 权限控制正确(仅教师可见)
### 第 2 里程碑: 评论功能完成
- ✅ 用户可以发表评论(文本 + 表情)
- ✅ 表情选择器正常工作
- ✅ 输入验证正确(最少 5 字,最多 200 字)
- ✅ 评论成功后通知后端(后端发送通知)
### 第 3 里程碑: 评论列表完成
- ✅ 评论列表正常展示(一级评论 + 回复评论)
- ✅ 回复功能正常工作
- ✅ 删除功能正常工作(仅删除自己的评论)
- ✅ 懒加载正常工作(查看全部)
- ✅ 教师可以审核评论(屏蔽/通过)
### 第 4 里程碑: 海报功能完成
- ✅ 海报正常生成
- ✅ 支持长内容
- ✅ 降级方案正常工作(生成失败时)
---
## 总结
## 下一步行动
### ✅ 计划完善度评估
1. ✅ 与后端/产品确认"待确认事项"中的所有问题
2. ✅ 确认开发优先级和里程碑节点
3. ⏳ 开始第 1 阶段开发(置顶功能)
4. ⏳ 同步准备 API Mock 数据,以便前端独立开发
5. ⏳ 确认后端 API 开发进度,确保前后端同步
**总体评分:9/10** - 开发计划已经非常完善,涵盖了需求、设计、API、边界条件等各个方面。
---
**优点:**
- ✅ 需求拆解清晰,环境变量开关设计灵活
- ✅ 技术方案成熟可行(表情选择器、评论系统、海报生成)
- ✅ API 设计完整,涵盖增删改查
- ✅ 数据结构设计合理(扁平化评论结构)
- ✅ 边界条件考虑充分(Emoji 字符计数、数据库 utf8mb4)
- ✅ 参考现有代码库,复用性高
- ✅ 开发步骤清晰,循序渐进
- ✅ 性能优化、错误处理、测试计划都已考虑
## 附录: 常用表情列表
**需要改进的地方:**
- ⚠️ 部分业务规则需要与后端/产品确认(见"待确认事项")
- ⚠️ 置顶视觉标记、评论通知等功能细节需要补充
- ⚠️ 错误处理和降级方案可以更详细
```
😊😂❤️👍🎉✨🙏💪🔥💯😍👏🤝🌟🎁
😭😡🤔💭😴🎂🌈⭐🌙☀️🌺🌸🍀🎁🎈
🎵🎶📱💻⚽🏀🎾🎯🎨🎬📷🎤🎧📚✏️📝
💡🔔💬📧📞
```
### 🎯 建议的开发顺序
**总计**: 64 个常用表情符号
1. **第 1 阶段**:置顶功能(最简单,快速验证流程)
2. **第 2 阶段**:评论功能 + 评论列表(核心功能,投入最大)
3. **第 3 阶段**:海报功能(技术难度较高,可最后开发)
---
### 📝 下一步行动
## 变更记录
1. 与后端/产品确认"待确认事项"中的所有问题
2. 确认开发优先级和里程碑节点
3. 开始第 1 阶段开发(置顶功能)
4. 同步准备 API Mock 数据,以便前端独立开发
**2026-01-27**:
- ✅ 与后端/产品确认所有待确认事项
- ✅ 新增教师评论管理功能
- ✅ 更新开发优先级(置顶、评论、评论列表为高优先级,海报为中优先级)
- ✅ 完善数据字段定义
- ✅ 完善业务规则(字符限制、权限控制、通知机制)
- ✅ 按优先级重新组织开发步骤
......