docs(plan): 更新新功能开发计划文档
更新 26.1.26 新功能开发计划文档,重新组织内容结构并完善细节: - 按优先级重新排序功能:置顶、评论、评论列表为高优先级,海报为中优先级 - 新增教师评论管理功能需求 - 完善数据字段定义和 API 接口汇总 - 细化开发步骤为四个阶段并明确里程碑 - 补充边界条件、性能优化和测试计划
Showing
1 changed file
with
660 additions
and
262 deletions
| ... | @@ -2,19 +2,18 @@ | ... | @@ -2,19 +2,18 @@ |
| 2 | 2 | ||
| 3 | ## 背景 | 3 | ## 背景 |
| 4 | 4 | ||
| 5 | -为了增强用户在打卡列表的互动性和管理能力,需要在打卡卡片(CheckinCard)上增加更多操作选项,包括置顶、评论、海报分享以及展示评论列表。这些功能将通过环境变量开关进行控制,以便按需开启。 | 5 | +为了增强用户在打卡列表的互动性和管理能力,需要在打卡卡片(CheckinCard)上增加更多操作选项,包括置顶、评论、海报分享以及展示评论列表。这些功能将通过环境变量开关进行控制,以便按需开启。 |
| 6 | 6 | ||
| 7 | ## 需求拆解 | 7 | ## 需求拆解 |
| 8 | 8 | ||
| 9 | -1. **全局功能开关**:在 `.env` 文件中通过变量控制各功能的开启/关闭。 | 9 | +1. **置顶功能** (优先级: 🔴 高) - 允许教师将特定打卡内容置顶 |
| 10 | -2. **置顶功能 (Top)**:允许将特定打卡内容置顶。 | 10 | +2. **评论功能** (优先级: 🔴 高) - 允许用户对打卡内容进行评论 |
| 11 | -3. **评论/评论功能 (Comment)**:允许对打卡内容进行评论(评论)。 | 11 | +3. **评论列表** (优先级: 🔴 高) - 在打卡卡片下方显示该打卡的评论记录 |
| 12 | -4. **打卡海报 (Poster)**:生成包含打卡内容的长图海报,支持分享。 | 12 | +4. **海报功能** (优先级: 🟡 中) - 生成包含打卡内容的长图海报,支持分享 |
| 13 | -5. **评论列表 (Comment List)**:在打卡卡片下方显示该打卡的评论/评论记录。 | ||
| 14 | 13 | ||
| 15 | ## 环境变量规划 | 14 | ## 环境变量规划 |
| 16 | 15 | ||
| 17 | -在 `.env` 中增加以下开关(默认 '0' 关闭,'1' 开启): | 16 | +在 `.env` 中增加以下开关(默认 '0' 关闭,'1' 开启): |
| 18 | 17 | ||
| 19 | - `VITE_FEATURE_CHECKIN_TOP=1` (置顶功能) | 18 | - `VITE_FEATURE_CHECKIN_TOP=1` (置顶功能) |
| 20 | - `VITE_FEATURE_CHECKIN_COMMENT=1` (评论功能) | 19 | - `VITE_FEATURE_CHECKIN_COMMENT=1` (评论功能) |
| ... | @@ -25,278 +24,677 @@ | ... | @@ -25,278 +24,677 @@ |
| 25 | 24 | ||
| 26 | ### 1. 入口改造 (CheckinCard) | 25 | ### 1. 入口改造 (CheckinCard) |
| 27 | 26 | ||
| 28 | -- **位置**:`CheckinCard` 组件底部右侧操作区(原点赞/更多按钮处)。 | 27 | +**位置**: `CheckinCard` 组件底部右侧操作区(原点赞/更多按钮处) |
| 29 | -- **交互**:点击“...”图标,从底部弹出 `ActionSheet`(Vant 组件)。 | 28 | + |
| 30 | -- **菜单项**: | 29 | +**交互**: 点击"..."图标,从底部弹出 `ActionSheet`(Vant 组件) |
| 31 | - - **置顶**:仅当 `VITE_FEATURE_CHECKIN_TOP=1` 时显示。若已置顶,显示“取消置顶”。 | 30 | + |
| 32 | - - **评论**:仅当 `VITE_FEATURE_CHECKIN_COMMENT=1` 时显示。 | 31 | +**菜单项**: |
| 33 | - - **海报**:仅当 `VITE_FEATURE_CHECKIN_POSTER=1` 时显示。 | 32 | +- **置顶** (仅教师可见): 仅当 `VITE_FEATURE_CHECKIN_TOP=1` 时显示。若已置顶,显示"取消置顶" |
| 34 | - | 33 | +- **评论** (仅用户端可见): 仅当 `VITE_FEATURE_CHECKIN_COMMENT=1` 时显示,仅在 `/checkin/index` 打卡主页显示 |
| 35 | -### 2. 置顶功能 (Top) | 34 | +- **海报** (通用): 仅当 `VITE_FEATURE_CHECKIN_POSTER=1` 时显示 |
| 36 | - | 35 | + |
| 37 | -- **逻辑**: | 36 | +### 2. 置顶功能 🔴 高优先级 |
| 38 | - 1. 点击“置顶”菜单。 | 37 | + |
| 39 | - 2. 弹出确认框 `showConfirmDialog`:“确定要置顶这条打卡吗?”。 | 38 | +#### 权限控制 |
| 40 | - 3. 用户确认 -> 调用 API `teacherPinCheckinAPI(id)`。 | 39 | +- **仅教师可见**: 使用 `user.is_teacher` 字段判断权限 |
| 41 | - 4. API 成功 -> Toast “置顶成功” -> 更新列表数据(将该项标记为置顶,或刷新列表)。 | 40 | +- **权限获取**: 前端需实时请求后端接口获取用户角色,不依赖缓存的 `localStorage.user_info` |
| 42 | - 5. 若已置顶 -> 点击“取消置顶” -> 确认 -> API `teacherUnpinCheckinAPI(id)` -> Toast “取消置顶成功” -> 更新状态。 | 41 | +- **适用范围**: 教师端所有打卡列表页面 |
| 43 | -- **要点**:这个功能属于教师端功能, 需要先判断这个用户的userinfo是否是老师, 使用is_teacher字段判断, 没有权限则不显示置顶菜单. | 42 | + |
| 44 | -- **API**: | 43 | +#### 逻辑流程 |
| 45 | - - `teacherPinCheckinAPI` 老师置顶打卡 (参数: `checkin_id`) | 44 | +1. 点击"置顶"菜单 |
| 46 | - - `teacherUnpinCheckinAPI` 老师取消置顶打卡 (参数: `checkin_id`) | 45 | +2. 弹出确认框 `showConfirmDialog`:"确定要置顶这条打卡吗?" |
| 47 | - | 46 | +3. 用户确认 -> 调用 API `teacherPinCheckinAPI(id)` |
| 48 | -### 3. 评论功能 (Comment) | 47 | +4. API 成功 -> Toast "置顶成功" -> 更新列表数据(将该项标记为置顶) |
| 49 | - | 48 | +5. 若已置顶 -> 点击"取消置顶" -> 确认 -> API `teacherUnpinCheckinAPI(id)` -> Toast "取消置顶成功" -> 更新状态 |
| 50 | -- **逻辑**: | 49 | + |
| 51 | - 1. 点击"评论"菜单。 | 50 | +#### 视觉标记 |
| 52 | - 2. 弹出 **评论输入弹窗**(新建组件 `CheckinCommentDialog`)。 | 51 | +- 已置顶的打卡卡片右上角显示 📌 图标 |
| 53 | - - 包含:文本输入框(Textarea)、表情选择器按钮。 | 52 | +- 卡片顶部显示"置顶"标签(使用 `van-tag` 组件) |
| 54 | - - **表情选择器**:点击表情图标,从底部弹出表情面板,支持常用 Emoji 表情符号(😊❤️👍🎉等)。 | 53 | + |
| 55 | - - 输入验证:纯文本评论至少 5 个字符,允许表情符号作为补充。 | 54 | +#### API 接口 |
| 56 | - - 按钮:取消、提交。 | 55 | +- `POST /api/teacher/pin-checkin` - 教师置顶打卡 (参数: `checkin_id`) |
| 57 | - 3. 点击表情图标 -> 弹出表情选择面板(底部 Popup)-> 选择表情 -> 插入到光标位置。 | 56 | +- `POST /api/teacher/unpin-checkin` - 教师取消置顶打卡 (参数: `checkin_id`) |
| 58 | - 4. 输入内容(文本 + 表情)-> 点击提交。 | 57 | + |
| 59 | - 5. 调用 API `commentCheckin(id, content)`。 | 58 | +#### 数据字段扩展 |
| 60 | - 6. API 成功 -> Toast "评论成功" -> 关闭弹窗 -> 刷新该打卡的评论列表。 | 59 | +```javascript |
| 61 | -- **要点**: | 60 | +{ |
| 62 | - - 这个功能属于用户端功能, 只能在`/checkin/index`打卡主页上的打卡卡片上显示出来。 | 61 | + is_pinned: false, // 是否置顶 |
| 63 | - - 表情选择器技术方案:自定义 Emoji 列表。 | 62 | + pinned_at: null // 置顶时间 |
| 64 | - - 表情数据:使用原生 Unicode Emoji,无需图片资源,体积小且兼容性好。 | 63 | +} |
| 65 | - - 常用表情建议:😊😂❤️👍🎉✨🙏💪🔥💯😍👏🤝🌟🎁 | 64 | +``` |
| 66 | -- **组件**:`CheckinCommentDialog.vue` (基于 Vant Popup 封装,底部弹出)。 | 65 | + |
| 67 | -- **API (需 Mock/确认)**: | 66 | +--- |
| 68 | - - `POST /checkin/comment` (发表评论,参数: `checkin_id`, `content`) | 67 | + |
| 69 | - | 68 | +### 3. 评论功能 🔴 高优先级 |
| 70 | -### 4. 海报功能 (Poster) | 69 | + |
| 71 | - | 70 | +#### 权限控制 |
| 72 | -- **逻辑**: | 71 | +- **仅用户端可用**: 只能在 `/checkin/index` 打卡主页的打卡卡片上显示 |
| 73 | - 1. 点击“海报”菜单。 | 72 | +- **允许自评**: 允许用户评论自己的打卡 |
| 74 | - 2. 弹出 **海报预览组件** (`CheckinPoster`,参考 `SharePoster`)。 | 73 | + |
| 75 | - 3. **渲染内容**: | 74 | +#### 评论输入弹窗 (CheckinCommentDialog) |
| 76 | - - 用户信息(头像、昵称)。 | 75 | + |
| 77 | - - 打卡内容(文本、图片缩略图)。 | 76 | +**组件**: `CheckinCommentDialog.vue` (基于 Vant Popup 封装,底部弹出) |
| 78 | - - 底部二维码(打卡主页的网址自动生成)。 | 77 | + |
| 79 | - - *注:需支持长图,若内容过长,通过滚动查看,生成图片时需完整截取。* | 78 | +**功能特性**: |
| 80 | - 4. **生成图片**:使用 `html2canvas` 或 `html-to-image` 将 DOM 转为图片。 | 79 | +- 文本输入框 (`van-field`,多行模式) |
| 81 | - 5. 展示生成的图片,提示“长按保存”。 | 80 | +- 表情选择器按钮 |
| 82 | -- **组件**:`CheckinPoster.vue`。 | 81 | +- 字符计数提示(最多 200 字) |
| 83 | -- **技术点**:处理跨域图片、长图渲染、字体加载。 | 82 | +- 按钮: 取消、提交 |
| 84 | - | 83 | + |
| 85 | -### 5. 评论列表 (Comment List) | 84 | +**表情选择器**: |
| 86 | - | 85 | +- **技术方案**: 自定义 Emoji 面板,使用原生 Unicode Emoji |
| 87 | -- **位置**:`CheckinCard` 组件内部下方。 | 86 | +- **UI 实现**: `van-popup` 底部弹出 + `van-grid` 展示表情符号 |
| 88 | -- **显示条件**:`VITE_FEATURE_CHECKIN_COMMENT_LIST=1` 且 `post.comments` 长度 > 0。 | 87 | +- **常用表情**: 😊😂❤️👍🎉✨🙏💪🔥💯😍👏🤝🌟🎁😭😡🤔💭😴🎂🌈⭐🌙☀️🌺🌸🍀🎁🎈🎵🎶📱💻⚽🏀🎾🎯🎨🎬📷🎤🎧📚✏️📝💡🔔💬📧📞 |
| 89 | -- **样式**:参考朋友圈评论区(灰色背景,每行 `用户: 内容`)。 | 88 | +- **交互逻辑**: 点击表情 -> 插入到输入框光标位置 -> 自动关闭面板 |
| 90 | -- **逻辑**: | 89 | + |
| 91 | - - 渲染评论列表,支持 Emoji 表情符号的显示。 | 90 | +**输入验证**: |
| 92 | - - 列车最多展示5条评论, 超过5条的评论需要点击"查看全部"才能看到. | 91 | +- 纯文本评论至少 5 个字符 |
| 93 | - - 用户自己评论的右侧需要显示一个删除图标, 点击图标弹出确认框, 确认后调用删除接口删除该条评论. | 92 | +- 允许纯表情评论(无文字) |
| 94 | - - **交互与操作**: | 93 | +- 字符计数使用 `Array.from(text).length` 计算(正确处理 Emoji 代理对) |
| 95 | - - **回复**:点击某一条评论,从屏幕底部弹出输入框(类似微信朋友圈),键盘自动升起。输入框同样支持表情选择器。输入内容后点击发送,即为回复该条评论。 | 94 | +- 前端实时提示剩余字数 |
| 96 | - - 数据结构:使用 `parent_id` 标识父评论,`reply_to_user_id` 标识被回复用户。 | 95 | + |
| 97 | - - 显示样式:`用户A 回复 用户B: 评论内容`。 | 96 | +#### API 接口 |
| 98 | - - **删除**:点击用户**自己**发布的评论,弹出 `ActionSheet` 或确认框,选项包含"删除"。确认后调用删除接口移除该评论。 | 97 | +- `POST /api/checkin/comment` - 发表评论 |
| 99 | - - **样式参考**:整体交互逻辑和视觉风格严格参考微信朋友圈。 | 98 | + - 参数: `checkin_id`, `content` (评论内容,最多 200 字) |
| 100 | - - **Emoji 渲染**:评论内容中的 Emoji 符号直接使用原生 Unicode 渲染,无需特殊处理。 | 99 | + - 返回: `{ code: 1, data: { comment_id: 123 }, msg: '' }` |
| 101 | -- **组件**:`CheckinCommentList.vue` (复用 `StudyCommentsSection.vue` 的设计模式)。 | 100 | +- **无需敏感词过滤**: 后端不进行敏感词过滤 |
| 102 | -- **API (需 Mock/确认)**: | 101 | + |
| 103 | - - `GET /checkin/comments` (获取评论列表,参数: `checkin_id`, `page`, `page_size`) | 102 | +#### 通知机制 |
| 104 | - - `POST /checkin/comment` (发表评论,参数: `checkin_id`, `content`) | 103 | +- 评论后不需要前端主动触发通知 |
| 105 | - - `POST /checkin/comment/reply` (回复评论,参数: `checkin_id`, `content`, `parent_id`, `reply_to_user_id`) | 104 | +- 后端会自动发送通知给打卡用户或被回复用户 |
| 106 | - - `DELETE /checkin/comment/:id` (删除评论,参数: `comment_id`) | 105 | + |
| 106 | +--- | ||
| 107 | + | ||
| 108 | +### 4. 评论列表功能 🔴 高优先级 | ||
| 109 | + | ||
| 110 | +#### 位置与显示 | ||
| 111 | +**位置**: `CheckinCard` 组件内部下方 | ||
| 112 | +**显示条件**: `VITE_FEATURE_CHECKIN_COMMENT_LIST=1` 且 `post.comments.length > 0` | ||
| 113 | + | ||
| 114 | +#### 评论列表展示 (CheckinCommentList) | ||
| 115 | + | ||
| 116 | +**组件**: `CheckinCommentList.vue` (参考 `StudyCommentsSection.vue` 的实现模式) | ||
| 117 | + | ||
| 118 | +**显示逻辑**: | ||
| 119 | +- 首屏最多展示 5 条评论 | ||
| 120 | +- 超过 5 条显示"查看全部"按钮 | ||
| 121 | +- 点击"查看全部"加载完整评论列表(懒加载) | ||
| 122 | +- 样式参考微信朋友圈(灰色背景,每行 `用户: 内容`) | ||
| 123 | + | ||
| 124 | +**数据结构** (扁平化设计): | ||
| 125 | +```javascript | ||
| 126 | +{ | ||
| 127 | + id: 1, // 评论 ID | ||
| 128 | + checkin_id: 123, // 关联的打卡 ID | ||
| 129 | + user_id: 456, // 评论者 ID | ||
| 130 | + user_name: "张三", // 评论者昵称 | ||
| 131 | + content: "干得漂亮!🎉", // 评论内容 | ||
| 132 | + parent_id: 0, // 父评论 ID (0 表示一级评论) | ||
| 133 | + reply_to_user_id: null, // 被回复用户 ID (一级评论为 null) | ||
| 134 | + reply_to_user_name: null, // 被回复用户昵称 | ||
| 135 | + is_my: false, // 是否是自己发表的评论 | ||
| 136 | + created_at: "2026-01-26 10:00:00" | ||
| 137 | +} | ||
| 138 | +``` | ||
| 139 | + | ||
| 140 | +**评论样式**: | ||
| 141 | +- 一级评论: `张三: 干得漂亮!🎉` | ||
| 142 | +- 回复评论: `张三 回复 李四: 我也这么觉得!` | ||
| 143 | +- Emoji 符号直接使用原生 Unicode 渲染 | ||
| 144 | + | ||
| 145 | +#### 交互功能 | ||
| 146 | + | ||
| 147 | +**回复评论**: | ||
| 148 | +1. 点击某一条评论,从屏幕底部弹出输入框(类似微信朋友圈) | ||
| 149 | +2. 键盘自动升起 | ||
| 150 | +3. 输入框同样支持表情选择器 | ||
| 151 | +4. 输入内容后点击发送,即为回复该条评论 | ||
| 152 | +5. 数据结构: 使用 `parent_id` 标识父评论,`reply_to_user_id` 标识被回复用户 | ||
| 153 | +6. 显示样式: `用户A 回复 用户B: 评论内容` | ||
| 154 | + | ||
| 155 | +**删除评论**: | ||
| 156 | +- 仅显示用户**自己**发布的评论的删除图标 | ||
| 157 | +- 点击图标弹出确认框:"确定要删除这条评论吗?" | ||
| 158 | +- 确认后调用删除接口移除该评论 | ||
| 159 | +- API: `DELETE /api/checkin/comment/:id` | ||
| 160 | +- **权限校验**: | ||
| 161 | + - 前端: 通过接口返回的 `is_my` 字段判断是否显示删除按钮 | ||
| 162 | + - 后端: 接口层进行权限校验,确保只能删除自己的评论 | ||
| 163 | +- **教师权限**: 教师不可删除学生的评论 | ||
| 164 | + | ||
| 165 | +#### 教师评论管理 🔴 高优先级 (新增需求) | ||
| 166 | + | ||
| 167 | +**适用场景**: 教师在 `/teacher` 路由下的打卡列表中管理评论 | ||
| 168 | + | ||
| 169 | +**功能**: | ||
| 170 | +- 教师可以在评论列表中对不适当的评论进行审核 | ||
| 171 | +- 操作选项: | ||
| 172 | + - **屏蔽**: 隐藏该评论(不删除,仅前端不显示) | ||
| 173 | + - **通过**: 恢复该评论的显示 | ||
| 174 | +- 评论状态字段: `status` (`0` = 待审核, `1` = 已通过, `2` = 已屏蔽) | ||
| 175 | +- **交互设计**: | ||
| 176 | + - 在评论卡片右侧显示审核按钮(仅教师可见) | ||
| 177 | + - 点击按钮弹出 ActionSheet: "屏蔽评论"、"通过评论" | ||
| 178 | + - 操作后实时更新评论状态 | ||
| 179 | + | ||
| 180 | +**API 接口** (新增): | ||
| 181 | +- `POST /api/teacher/review-comment` - 教师审核评论 | ||
| 182 | + - 参数: `comment_id`, `action` (`approve` | `reject`) | ||
| 183 | + - 返回: `{ code: 1, data: {}, msg: '' }` | ||
| 184 | + | ||
| 185 | +**数据字段扩展**: | ||
| 186 | +```javascript | ||
| 187 | +{ | ||
| 188 | + status: 1, // 评论状态: 0-待审核, 1-已通过, 2-已屏蔽 | ||
| 189 | + reviewed_at: null, // 审核时间 | ||
| 190 | + reviewed_by: null // 审核人 ID | ||
| 191 | +} | ||
| 192 | +``` | ||
| 193 | + | ||
| 194 | +#### API 接口 | ||
| 195 | + | ||
| 196 | +**获取评论列表**: | ||
| 197 | +- `GET /api/checkin/comments` | ||
| 198 | +- 参数: `checkin_id`, `page`, `page_size` | ||
| 199 | +- 返回: `{ code: 1, data: { list: [], total: 100 }, msg: '' }` | ||
| 200 | +- **注意**: 不包含完整的用户信息,仅返回 `user_id` 和 `user_name` | ||
| 201 | + | ||
| 202 | +**发表评论**: | ||
| 203 | +- `POST /api/checkin/comment` | ||
| 204 | +- 参数: `checkin_id`, `content` | ||
| 205 | +- 返回: `{ code: 1, data: { comment_id: 123 }, msg: '' }` | ||
| 206 | + | ||
| 207 | +**回复评论**: | ||
| 208 | +- `POST /api/checkin/comment/reply` | ||
| 209 | +- 参数: `checkin_id`, `content`, `parent_id`, `reply_to_user_id` | ||
| 210 | +- 返回: `{ code: 1, data: { comment_id: 124 }, msg: '' }` | ||
| 211 | + | ||
| 212 | +**删除评论**: | ||
| 213 | +- `DELETE /api/checkin/comment/:id` | ||
| 214 | +- 参数: `comment_id` | ||
| 215 | +- 返回: `{ code: 1, data: {}, msg: '' }` | ||
| 216 | + | ||
| 217 | +#### 数据字段扩展 | ||
| 218 | +```javascript | ||
| 219 | +{ | ||
| 220 | + comments_count: 0, // 评论总数(用于列表展示) | ||
| 221 | + comments: [] // 评论列表(最多 5 条,用于首屏渲染) | ||
| 222 | +} | ||
| 223 | +``` | ||
| 224 | + | ||
| 225 | +--- | ||
| 226 | + | ||
| 227 | +### 5. 海报功能 🟡 中优先级 | ||
| 228 | + | ||
| 229 | +#### 逻辑流程 | ||
| 230 | +1. 点击"海报"菜单 | ||
| 231 | +2. 弹出 **海报预览组件** (`CheckinPoster`,参考 `SharePoster`) | ||
| 232 | +3. **渲染内容**: | ||
| 233 | + - 用户信息(头像、昵称) | ||
| 234 | + - 打卡内容(文本、图片缩略图) | ||
| 235 | + - 底部二维码(打卡主页的网址自动生成) | ||
| 236 | + - 支持长图,若内容过长通过滚动查看 | ||
| 237 | +4. **生成图片**: 使用 `html2canvas` 或 `html-to-image` 将 DOM 转为图片 | ||
| 238 | +5. 展示生成的图片,提示"长按保存" | ||
| 239 | + | ||
| 240 | +#### 降级方案 | ||
| 241 | +- 海报生成是异步操作,可能会失败 | ||
| 242 | +- 生成失败时显示降级卡片: | ||
| 243 | + - 卡片包含: 用户头像、昵称、打卡内容摘要 | ||
| 244 | + - 底部提示: "长按截图保存分享" | ||
| 245 | + - 用户可手动截图保存 | ||
| 246 | + | ||
| 247 | +#### 技术要点 | ||
| 248 | +- 处理跨域图片: 配置 `useCORS: true` 且 CDN 支持 CORS | ||
| 249 | +- 长图渲染: 需限制最大高度或分段(第一版暂不考虑极端情况) | ||
| 250 | +- 字体加载: 确保字体加载完成后再生成图片 | ||
| 251 | + | ||
| 252 | +--- | ||
| 107 | 253 | ||
| 108 | ## 开发步骤 | 254 | ## 开发步骤 |
| 109 | 255 | ||
| 110 | -### 第 1 步:环境准备与 Mock API | 256 | +### 🔴 第 1 阶段: 置顶功能 (高优先级) |
| 111 | -- 在 `.env` 添加开关变量。 | 257 | + |
| 112 | -- 在 `src/api` 定义相关接口(Top, Comment),前期可使用 Mock 数据验证流程。 | 258 | +**目标**: 实现教师置顶打卡功能 |
| 113 | - | 259 | + |
| 114 | -### 第 2 步:改造 CheckinCard 菜单 | 260 | +**步骤**: |
| 115 | -- 引入 `ActionSheet`。 | 261 | +1. **环境准备**: |
| 116 | -- 根据 Env 开关动态显示菜单项。 | 262 | + - 在 `.env` 添加 `VITE_FEATURE_CHECKIN_TOP=1` |
| 117 | -- 实现基础点击事件处理。 | 263 | + - 在 `src/api/teacher.js` 中定义 `teacherPinCheckinAPI` 和 `teacherUnpinCheckinAPI` (已实现) |
| 118 | - | 264 | + |
| 119 | -### 第 3 步:实现置顶逻辑 | 265 | +2. **用户权限获取**: |
| 120 | -- 对接置顶/取消置顶 API。 | 266 | + - 创建 `useAuthRole.js` composable |
| 121 | -- 添加确认弹窗。 | 267 | + - 实现实时请求用户角色接口(不依赖 localStorage) |
| 122 | -- 处理列表状态更新。 | 268 | + - 返回 `{ is_teacher: boolean }` |
| 123 | -- **置顶视觉标记**:在已置顶的打卡卡片上显示"📌 置顶"标记。 | 269 | + |
| 124 | - | 270 | +3. **改造 CheckinCard**: |
| 125 | -### 第 4 步:实现评论功能与列表 | 271 | + - 引入 `van-action-sheet` |
| 126 | -- 创建 `CheckinCommentDialog` 组件。 | 272 | + - 在菜单中添加"置顶"/"取消置顶"选项(根据 `is_pinned` 和 `is_teacher` 动态显示) |
| 127 | - - 实现 `van-field` 文本输入框(支持多行)。 | 273 | + - 实现置顶确认弹窗 |
| 128 | - - **实现表情选择器**: | 274 | + |
| 129 | - - 方案选择:自定义 Emoji 面板(不引入额外依赖,使用原生 Unicode Emoji)。 | 275 | +4. **置顶逻辑实现**: |
| 130 | - - UI 实现:`van-popup` 底部弹出 + `van-grid` 展示表情符号。 | 276 | + - 对接置顶/取消置顶 API |
| 131 | - - 交互逻辑:点击表情 -> 插入到输入框光标位置 -> 自动关闭面板。 | 277 | + - 成功后更新列表数据(本地更新,避免全列表刷新) |
| 132 | - - 常用表情列表:😊😂❤️👍🎉✨🙏💪🔥💯😍👏🤝🌟🎁😭😡🤔💭😴🎂🌈⭐🌙☀️🌺🌸🍀🎁🎈🎵🎶📱💻⚽🏀🎾🎯🎨🎬📷🎤🎧📚✏️📝💡🔔💬📧📞 | 278 | + - 已置顶卡片显示 📌 图标和"置顶"标签 |
| 133 | - - 实现输入验证(文本至少 5 字,表情可作为补充)。 | 279 | + |
| 134 | -- 在 `CheckinCard` 中引入并调用评论弹窗。 | 280 | +5. **测试**: |
| 135 | -- 创建 `CheckinCommentList` 组件(/components/checkin/CheckinCommentList.vue)。 | 281 | + - 教师账号验证置顶功能 |
| 136 | - - 参考 `StudyCommentsSection.vue` 的实现模式。 | 282 | + - 学生账号验证置顶菜单不显示 |
| 137 | - - 支持评论列表展示(最多 5 条,超过则显示"查看全部")。 | 283 | + - 刷新页面验证置顶状态持久化 |
| 138 | - - 支持 Emoji 符号的直接渲染。 | 284 | + |
| 139 | - - 实现评论回复交互(底部输入框弹出,同样支持表情选择)。 | 285 | +--- |
| 140 | - - 实现删除逻辑(仅显示自己评论的删除图标)。 | 286 | + |
| 141 | -- 对接评论、回复、删除 API 和列表展示数据。 | 287 | +### 🔴 第 2 阶段: 评论功能 (高优先级) |
| 142 | - | 288 | + |
| 143 | -### 第 5 步:实现打卡海报 | 289 | +**目标**: 实现用户发表评论功能 |
| 144 | -- 创建 `CheckinPoster` 组件。 | 290 | + |
| 145 | -- 实现布局(支持长内容)。 | 291 | +**步骤**: |
| 146 | -- 集成 `html2canvas` 生成逻辑。 | 292 | +1. **环境准备**: |
| 147 | -- 对接 `CheckinCard` 菜单。 | 293 | + - 在 `.env` 添加 `VITE_FEATURE_CHECKIN_COMMENT=1` |
| 294 | + - 在 `src/api/checkin.js` 中定义 `addCheckinCommentAPI` | ||
| 295 | + | ||
| 296 | +2. **创建评论输入弹窗**: | ||
| 297 | + - 创建 `CheckinCommentDialog.vue` 组件 | ||
| 298 | + - 实现 `van-field` 文本输入框(多行模式) | ||
| 299 | + - 实现字符计数提示(最多 200 字) | ||
| 300 | + | ||
| 301 | +3. **实现表情选择器**: | ||
| 302 | + - 创建 `EmojiPicker.vue` 组件 | ||
| 303 | + - 使用 `van-popup` + `van-grid` 展示表情符号 | ||
| 304 | + - 实现点击表情插入到输入框光标位置 | ||
| 305 | + - 定义常用表情列表(原生 Unicode Emoji) | ||
| 306 | + | ||
| 307 | +4. **输入验证**: | ||
| 308 | + - 实现字符计数逻辑(`Array.from(text).length`) | ||
| 309 | + - 纯文本评论至少 5 字 | ||
| 310 | + - 允许纯表情评论 | ||
| 311 | + - 实时提示剩余字数 | ||
| 312 | + | ||
| 313 | +5. **对接 API**: | ||
| 314 | + - 实现发表评论接口调用 | ||
| 315 | + - 成功后 Toast "评论成功" | ||
| 316 | + - 关闭弹窗并刷新评论列表 | ||
| 317 | + | ||
| 318 | +6. **集成到 CheckinCard**: | ||
| 319 | + - 在 `/checkin/index` 页面的打卡卡片菜单中添加"评论"选项 | ||
| 320 | + - 点击评论菜单打开 `CheckinCommentDialog` | ||
| 321 | + - 仅用户端可见(教师端不显示) | ||
| 322 | + | ||
| 323 | +7. **测试**: | ||
| 324 | + - 测试纯文本评论(最少 5 字) | ||
| 325 | + - 测试纯表情评论 | ||
| 326 | + - 测试混合评论(文本 + 表情) | ||
| 327 | + - 测试字符计数准确性 | ||
| 328 | + - 测试 200 字符限制 | ||
| 329 | + - 测试表情插入到光标位置 | ||
| 330 | + | ||
| 331 | +--- | ||
| 332 | + | ||
| 333 | +### 🔴 第 3 阶段: 评论列表 (高优先级) | ||
| 334 | + | ||
| 335 | +**目标**: 实现评论列表展示、回复、删除功能 | ||
| 336 | + | ||
| 337 | +**步骤**: | ||
| 338 | +1. **环境准备**: | ||
| 339 | + - 在 `.env` 添加 `VITE_FEATURE_CHECKIN_COMMENT_LIST=1` | ||
| 340 | + - 在 `src/api/checkin.js` 中定义评论相关 API: | ||
| 341 | + - `getCheckinCommentsAPI` - 获取评论列表 | ||
| 342 | + - `replyCheckinCommentAPI` - 回复评论 | ||
| 343 | + - `deleteCheckinCommentAPI` - 删除评论 | ||
| 344 | + | ||
| 345 | +2. **创建评论列表组件**: | ||
| 346 | + - 创建 `CheckinCommentList.vue` 组件 | ||
| 347 | + - 参考 `StudyCommentsSection.vue` 的实现模式 | ||
| 348 | + - 实现首屏展示最多 5 条评论 | ||
| 349 | + - 超过 5 条显示"查看全部"按钮 | ||
| 350 | + | ||
| 351 | +3. **实现评论样式**: | ||
| 352 | + - 一级评论: `用户名: 评论内容` | ||
| 353 | + - 回复评论: `用户名 回复 被回复用户名: 评论内容` | ||
| 354 | + - 灰色背景,参考微信朋友圈样式 | ||
| 355 | + - Emoji 符号直接渲染(无需特殊处理) | ||
| 356 | + | ||
| 357 | +4. **实现回复功能**: | ||
| 358 | + - 点击评论弹出底部输入框(类似微信朋友圈) | ||
| 359 | + - 输入框支持表情选择器(复用 `EmojiPicker.vue`) | ||
| 360 | + - 实现回复 API 调用 | ||
| 361 | + - 成功后刷新评论列表 | ||
| 362 | + | ||
| 363 | +5. **实现删除功能**: | ||
| 364 | + - 仅显示自己评论的删除图标(根据 `is_my` 字段判断) | ||
| 365 | + - 点击删除图标弹出确认框 | ||
| 366 | + - 确认后调用删除 API | ||
| 367 | + - 成功后从列表中移除该评论 | ||
| 368 | + | ||
| 369 | +6. **实现懒加载**: | ||
| 370 | + - 首屏仅加载前 5 条评论(从 `post.comments` 字段读取) | ||
| 371 | + - 点击"查看全部"调用 `getCheckinCommentsAPI` 加载完整列表 | ||
| 372 | + - 实现分页加载 | ||
| 373 | + | ||
| 374 | +7. **集成到 CheckinCard**: | ||
| 375 | + - 在 `CheckinCard` 底部引入 `CheckinCommentList` | ||
| 376 | + - 根据 `comments_count` 和 `comments` 字段渲染 | ||
| 377 | + - 评论发表成功后自动刷新列表 | ||
| 378 | + | ||
| 379 | +8. **教师评论管理** (新增): | ||
| 380 | + - 在 `/teacher` 路由下的打卡列表中启用评论管理 | ||
| 381 | + - 教师可在评论列表中查看所有评论 | ||
| 382 | + - 在评论卡片右侧显示审核按钮(仅教师可见) | ||
| 383 | + - 实现评论屏蔽/通过功能 | ||
| 384 | + - 对接 `teacherReviewCommentAPI` (新增) | ||
| 385 | + - 操作后实时更新评论状态 | ||
| 386 | + | ||
| 387 | +9. **测试**: | ||
| 388 | + - 测试评论列表展示(一级评论、回复评论) | ||
| 389 | + - 测试"查看全部"懒加载 | ||
| 390 | + - 测试评论回复功能 | ||
| 391 | + - 测试评论删除功能(自己的评论、别人的评论) | ||
| 392 | + - 测试 Emoji 渲染 | ||
| 393 | + - 测试教师评论管理功能(屏蔽/通过) | ||
| 394 | + - 测试权限控制(学生不可见审核按钮) | ||
| 395 | + | ||
| 396 | +--- | ||
| 397 | + | ||
| 398 | +### 🟡 第 4 阶段: 海报功能 (中优先级) | ||
| 399 | + | ||
| 400 | +**目标**: 实现打卡海报生成与分享 | ||
| 401 | + | ||
| 402 | +**步骤**: | ||
| 403 | +1. **环境准备**: | ||
| 404 | + - 在 `.env` 添加 `VITE_FEATURE_CHECKIN_POSTER=1` | ||
| 405 | + - 安装依赖: `pnpm add html2canvas` | ||
| 406 | + | ||
| 407 | +2. **创建海报组件**: | ||
| 408 | + - 创建 `CheckinPoster.vue` 组件 | ||
| 409 | + - 参考 `SharePoster.vue` 的实现模式 | ||
| 410 | + - 实现布局: 用户信息、打卡内容、二维码 | ||
| 411 | + | ||
| 412 | +3. **实现长图渲染**: | ||
| 413 | + - 支持长内容滚动查看 | ||
| 414 | + - 处理多图展示(网格布局) | ||
| 415 | + - 处理文本换行 | ||
| 416 | + | ||
| 417 | +4. **实现图片生成**: | ||
| 418 | + - 使用 `html2canvas` 将 DOM 转为图片 | ||
| 419 | + - 配置 `useCORS: true` 处理跨域图片 | ||
| 420 | + - 添加 `crossorigin="anonymous"` 到图片标签 | ||
| 421 | + - 生成后展示图片并提示"长按保存" | ||
| 422 | + | ||
| 423 | +5. **实现降级方案**: | ||
| 424 | + - 监听 `html2canvas` 失败情况 | ||
| 425 | + - 失败时显示文字版卡片 | ||
| 426 | + - 提示用户"长按截图保存" | ||
| 427 | + | ||
| 428 | +6. **集成到 CheckinCard**: | ||
| 429 | + - 在打卡菜单中添加"海报"选项 | ||
| 430 | + - 点击后打开 `CheckinPoster` 弹窗 | ||
| 431 | + - 传入打卡信息 | ||
| 432 | + | ||
| 433 | +7. **测试**: | ||
| 434 | + - 测试不同内容长度的海报生成 | ||
| 435 | + - 测试跨域图片处理 | ||
| 436 | + - 测试降级方案(生成失败时) | ||
| 437 | + - 测试在微信内置浏览器的兼容性 | ||
| 438 | + - 测试长按保存功能 | ||
| 439 | + | ||
| 440 | +--- | ||
| 148 | 441 | ||
| 149 | ## 边界条件与注意点 | 442 | ## 边界条件与注意点 |
| 150 | 443 | ||
| 151 | -1. **权限控制**: | 444 | +### 1. 字符计数与 Emoji 处理 |
| 152 | - - 置顶功能是否仅管理员可见?(前端暂通过 Env 控制全局,根据用户角色判断)。 | 445 | + |
| 153 | - - 评论功能是否允许自己评论自己?(需后端确认,前端暂不做限制)。 | 446 | +**问题**: Emoji 符号在某些设备上占用 2 个字符位置(代理对) |
| 154 | - | 447 | + |
| 155 | -2. **表情输入处理**: | 448 | +**解决方案**: |
| 156 | - - **字符计数**:Emoji 符号在某些设备上可能占用 2 个字符位置(代理对),需使用 `Array.from(text).length` 计算真实字符数。 | 449 | +```javascript |
| 157 | - - **输入限制**:限制单条评论最多 200 个字符(包含 Emoji),前端实时提示剩余字数。 | 450 | +// 错误方式 |
| 158 | - - **兼容性**:原生 Unicode Emoji 在 iOS/Android/微信内置浏览器中均能正常显示,无需降级方案。 | 451 | +text.length // 可能将 Emoji 算作 2 个字符 |
| 159 | - - **存储**:后端需确保数据库字符集支持 UTF-8 MB4(MySQL 5.5.3+ 的 `utf8mb4`),否则部分 Emoji(如 🎁)会乱码。 | 452 | + |
| 160 | - | 453 | +// 正确方式 |
| 161 | -3. **海报生成**: | 454 | +Array.from(text).length // 正确计算字符数 |
| 162 | - - 图片跨域问题(需配置 `useCORS: true` 且 CDN 支持)。 | 455 | +``` |
| 163 | - - 内容过长导致 Canvas 内存溢出(需限制最大高度或分段,第一版暂不考虑极端情况)。 | 456 | + |
| 164 | - | 457 | +**验证规则**: |
| 165 | -4. **列表更新**: | 458 | +- 纯文本评论至少 5 个字符 |
| 166 | - - 操作后尽量避免全列表刷新,采用本地数据更新(Update Item)以提升体验。 | 459 | +- 允许纯表情评论(无文字) |
| 167 | - | 460 | +- 单条评论最多 200 个字符(包含 Emoji) |
| 168 | -5. **评论回复数据结构**: | 461 | + |
| 169 | - - 建议使用扁平化结构(所有评论在同一层级,通过 `parent_id` 关联),便于分页和排序。 | 462 | +### 2. 数据库字符集支持 |
| 170 | - - 示例: | 463 | + |
| 171 | - ```javascript | 464 | +**要求**: 后端数据库需使用 UTF-8 MB4 字符集 |
| 172 | - { | 465 | +- MySQL 5.5.3+ 的 `utf8mb4` |
| 173 | - id: 1, | 466 | +- 否则部分 Emoji(如 🎁)会乱码 |
| 174 | - checkin_id: 123, | 467 | + |
| 175 | - user_id: 456, | 468 | +### 3. 列表更新策略 |
| 176 | - content: "干得漂亮!🎉", | 469 | + |
| 177 | - parent_id: 0, // 0 表示一级评论 | 470 | +**原则**: 避免全列表刷新,采用本地数据更新 |
| 178 | - reply_to_user_id: null, // 一级评论为 null | 471 | + |
| 179 | - created_at: "2026-01-26 10:00:00" | 472 | +**实现方式**: |
| 180 | - } | 473 | +- 置顶成功: 更新本地卡片的 `is_pinned` 字段 |
| 181 | - ``` | 474 | +- 评论成功: 在本地评论列表中新增评论项 |
| 182 | - | 475 | +- 删除成功: 从本地评论列表中移除评论项 |
| 183 | -6. **CheckinCard 数据结构扩展**: | 476 | +- 仅在必要时调用接口刷新列表 |
| 184 | - - 现有 `post` 对象需要新增以下字段: | 477 | + |
| 185 | - ```javascript | 478 | +### 4. 权限控制 |
| 186 | - { | 479 | + |
| 187 | - id: 123, | 480 | +**置顶功能**: |
| 188 | - user: { name: "张三", avatar: "..." }, | 481 | +- 仅教师可见(通过 `is_teacher` 字段判断) |
| 189 | - content: "今天完成了100天打卡!", | 482 | +- 权限实时获取(不依赖 localStorage) |
| 190 | - images: [...], | 483 | + |
| 191 | - videoList: [...], | 484 | +**评论功能**: |
| 192 | - audio: [...], | 485 | +- 仅用户端可见(仅在 `/checkin/index` 显示) |
| 193 | - likes: 10, | 486 | +- 允许自评 |
| 194 | - is_liked: false, | 487 | + |
| 195 | - is_my: true, | 488 | +**删除评论**: |
| 196 | - // 🆕 新增字段 | 489 | +- 仅可删除自己的评论(通过 `is_my` 字段判断) |
| 197 | - is_pinned: false, // 是否置顶 | 490 | +- 教师不可删除学生的评论 |
| 198 | - pinned_at: null, // 置顶时间 | 491 | + |
| 199 | - comments_count: 0, // 评论总数(用于列表展示) | 492 | +**教师评论管理**: |
| 200 | - comments: [] // 评论列表(最多5条) | 493 | +- 仅教师可见审核按钮 |
| 201 | - } | 494 | +- 可屏蔽或通过任何评论 |
| 202 | - ``` | 495 | + |
| 203 | - | 496 | +### 5. 性能优化 |
| 204 | -7. **性能优化**: | 497 | + |
| 205 | - - **评论列表懒加载**:仅在用户展开"查看全部"时才加载完整评论列表,首屏只加载前 5 条。 | 498 | +**评论列表懒加载**: |
| 206 | - - **图片懒加载**:海报生成时使用 `loading="lazy"` 避免一次性加载所有图片。 | 499 | +- 首屏仅加载前 5 条评论 |
| 207 | - - **列表虚拟滚动**:如果打卡列表超过 50 条,考虑使用 `van-list` 的虚拟滚动模式。 | 500 | +- 点击"查看全部"时加载完整列表 |
| 208 | - | 501 | +- 实现分页加载 |
| 209 | -8. **错误处理**: | 502 | + |
| 210 | - - **网络错误**:API 调用失败时,显示 Toast 提示用户,并提供"重试"按钮。 | 503 | +**图片懒加载**: |
| 211 | - - **并发冲突**:删除评论时,若该评论已被删除,提示"该评论不存在"。 | 504 | +- 海报生成时使用 `loading="lazy"` |
| 212 | - | 505 | +- 避免一次性加载所有图片 |
| 213 | -9. **测试计划**: | 506 | + |
| 214 | - - **单元测试**:测试 `CheckinCommentDialog` 组件的输入验证、Emoji 插入逻辑。 | 507 | +**列表虚拟滚动**: |
| 215 | - - **集成测试**:测试评论发表、回复、删除的完整流程。 | 508 | +- 如果打卡列表超过 50 条,使用 `van-list` 的虚拟滚动模式 |
| 216 | - - **边界测试**:测试 200 字符限制、Emoji 字符计数、空评论提交等边界情况。 | 509 | + |
| 217 | - - **兼容性测试**:在 iOS Safari、Android Chrome、微信内置浏览器中测试 Emoji 显示。 | 510 | +### 6. 错误处理 |
| 511 | + | ||
| 512 | +**网络错误**: | ||
| 513 | +- API 调用失败时,显示 Toast 提示用户 | ||
| 514 | +- 提供"重试"按钮 | ||
| 515 | + | ||
| 516 | +**并发冲突**: | ||
| 517 | +- 删除评论时,若该评论已被删除,提示"该评论不存在" | ||
| 518 | +- 评论发表时,若打卡已被删除,提示"该打卡不存在" | ||
| 519 | + | ||
| 520 | +**海报生成失败**: | ||
| 521 | +- 捕获 `html2canvas` 异常 | ||
| 522 | +- 显示降级方案(文字版卡片) | ||
| 523 | + | ||
| 524 | +### 7. 测试计划 | ||
| 525 | + | ||
| 526 | +**单元测试**: | ||
| 527 | +- 测试 `CheckinCommentDialog` 组件的输入验证 | ||
| 528 | +- 测试 Emoji 插入逻辑 | ||
| 529 | +- 测试字符计数准确性 | ||
| 530 | + | ||
| 531 | +**集成测试**: | ||
| 532 | +- 测试评论发表、回复、删除的完整流程 | ||
| 533 | +- 测试置顶、取消置顶的完整流程 | ||
| 534 | +- 测试海报生成流程 | ||
| 535 | + | ||
| 536 | +**边界测试**: | ||
| 537 | +- 测试 200 字符限制 | ||
| 538 | +- 测试纯表情评论 | ||
| 539 | +- 测试空评论提交(应被阻止) | ||
| 540 | +- 测试长文本评论 | ||
| 541 | + | ||
| 542 | +**兼容性测试**: | ||
| 543 | +- iOS Safari | ||
| 544 | +- Android Chrome | ||
| 545 | +- 微信内置浏览器 | ||
| 546 | +- 测试 Emoji 显示兼容性 | ||
| 547 | + | ||
| 548 | +--- | ||
| 549 | + | ||
| 550 | +## 数据字段扩展总结 | ||
| 551 | + | ||
| 552 | +### post 对象新增字段 | ||
| 553 | + | ||
| 554 | +```javascript | ||
| 555 | +{ | ||
| 556 | + id: 123, | ||
| 557 | + user: { name: "张三", avatar: "..." }, | ||
| 558 | + content: "今天完成了100天打卡!", | ||
| 559 | + images: [...], | ||
| 560 | + videoList: [...], | ||
| 561 | + audio: [...], | ||
| 562 | + likes: 10, | ||
| 563 | + is_liked: false, | ||
| 564 | + is_my: true, | ||
| 565 | + | ||
| 566 | + // 🆕 置顶功能字段 | ||
| 567 | + is_pinned: false, // 是否置顶 | ||
| 568 | + pinned_at: null, // 置顶时间 | ||
| 569 | + | ||
| 570 | + // 🆕 评论功能字段 | ||
| 571 | + comments_count: 0, // 评论总数 | ||
| 572 | + comments: [] // 评论列表(最多 5 条) | ||
| 573 | +} | ||
| 574 | +``` | ||
| 575 | + | ||
| 576 | +### comment 对象数据结构 | ||
| 577 | + | ||
| 578 | +```javascript | ||
| 579 | +{ | ||
| 580 | + id: 1, // 评论 ID | ||
| 581 | + checkin_id: 123, // 关联的打卡 ID | ||
| 582 | + user_id: 456, // 评论者 ID | ||
| 583 | + user_name: "张三", // 评论者昵称 | ||
| 584 | + content: "干得漂亮!🎉", // 评论内容 | ||
| 585 | + parent_id: 0, // 父评论 ID (0 表示一级评论) | ||
| 586 | + reply_to_user_id: null, // 被回复用户 ID | ||
| 587 | + reply_to_user_name: null, // 被回复用户昵称 | ||
| 588 | + is_my: false, // 是否是自己发表的评论 | ||
| 589 | + status: 1, // 评论状态: 0-待审核, 1-已通过, 2-已屏蔽 | ||
| 590 | + reviewed_at: null, // 审核时间 | ||
| 591 | + reviewed_by: null, // 审核人 ID | ||
| 592 | + created_at: "2026-01-26 10:00:00" | ||
| 593 | +} | ||
| 594 | +``` | ||
| 595 | + | ||
| 596 | +### user 对象新增字段 | ||
| 597 | + | ||
| 598 | +```javascript | ||
| 599 | +{ | ||
| 600 | + id: 123, | ||
| 601 | + name: "张三", | ||
| 602 | + avatar: "...", | ||
| 603 | + | ||
| 604 | + // 🆕 角色字段 | ||
| 605 | + is_teacher: false // 是否是教师(需实时请求后端获取) | ||
| 606 | +} | ||
| 607 | +``` | ||
| 608 | + | ||
| 609 | +--- | ||
| 610 | + | ||
| 611 | +## API 接口汇总 | ||
| 612 | + | ||
| 613 | +### 置顶功能 | ||
| 614 | +- `POST /api/teacher/pin-checkin` - 教师置顶打卡 (参数: `checkin_id`) | ||
| 615 | +- `POST /api/teacher/unpin-checkin` - 教师取消置顶打卡 (参数: `checkin_id`) | ||
| 616 | + | ||
| 617 | +### 评论功能 | ||
| 618 | +- `GET /api/checkin/comments` - 获取评论列表 (参数: `checkin_id`, `page`, `page_size`) | ||
| 619 | +- `POST /api/checkin/comment` - 发表评论 (参数: `checkin_id`, `content`) | ||
| 620 | +- `POST /api/checkin/comment/reply` - 回复评论 (参数: `checkin_id`, `content`, `parent_id`, `reply_to_user_id`) | ||
| 621 | +- `DELETE /api/checkin/comment/:id` - 删除评论 (参数: `comment_id`) | ||
| 622 | +- `POST /api/teacher/review-comment` - 教师审核评论 (参数: `comment_id`, `action`) | ||
| 623 | + | ||
| 624 | +### 权限获取 | ||
| 625 | +- `GET /api/user/role` - 获取用户角色信息 (返回: `{ is_teacher: boolean }`) | ||
| 626 | + | ||
| 627 | +--- | ||
| 628 | + | ||
| 629 | +## 开发优先级总结 | ||
| 630 | + | ||
| 631 | +### 🔴 高优先级 (第 1 批) | ||
| 632 | +1. **置顶功能** - 实现教师置顶打卡 | ||
| 633 | +2. **评论功能** - 实现用户发表评论 | ||
| 634 | +3. **评论列表** - 实现评论展示、回复、删除 | ||
| 635 | +4. **教师评论管理** - 实现教师审核评论 | ||
| 636 | + | ||
| 637 | +### 🟡 中优先级 (第 2 批) | ||
| 638 | +5. **海报功能** - 实现打卡海报生成与分享 | ||
| 218 | 639 | ||
| 219 | --- | 640 | --- |
| 220 | 641 | ||
| 221 | -## 待确认事项 | 642 | +## 里程碑 |
| 222 | - | 643 | + |
| 223 | -### 与后端确认 | 644 | +### 第 1 里程碑: 置顶功能完成 |
| 224 | -1. **API 接口**: | 645 | +- ✅ 教师可以置顶/取消置顶打卡 |
| 225 | - - `GET /checkin/comments` - 评论列表接口(是否支持分页?返回数据结构是否包含用户信息?)支持分页, 不包含用户信息. | 646 | +- ✅ 置顶打卡显示 📌 图标 |
| 226 | - - `POST /checkin/comment` - 发表评论接口(是否需要敏感词过滤?返回值是什么?)不需要敏感词过滤, 返回值应该是评论ID. | 647 | +- ✅ 权限控制正确(仅教师可见) |
| 227 | - - `POST /checkin/comment/reply` - 回复评论接口(参数是否完整?)参数完整, 包含评论ID, 回复内容, 回复用户ID. 返回值应该是回复评论ID. | 648 | + |
| 228 | - - `DELETE /checkin/comment/:id` - 删除评论接口(是否有权限校验?)不需要校验, 列表会返回字段, 判断是否是自己的评论, 如果不是不会显示删除按钮. | 649 | +### 第 2 里程碑: 评论功能完成 |
| 229 | - - `teacherPinCheckinAPI` / `teacherUnpinCheckinAPI` - 接口已实现. | 650 | +- ✅ 用户可以发表评论(文本 + 表情) |
| 230 | - | 651 | +- ✅ 表情选择器正常工作 |
| 231 | -2. **数据字段**: | 652 | +- ✅ 输入验证正确(最少 5 字,最多 200 字) |
| 232 | - - `post.is_pinned` - 置顶标记字段是否存在? | 653 | +- ✅ 评论成功后通知后端(后端发送通知) |
| 233 | - - `post.pinned_at` - 置顶时间字段是否存在? | 654 | + |
| 234 | - - `post.comments_count` - 评论数字段是否存在? | 655 | +### 第 3 里程碑: 评论列表完成 |
| 235 | - - `post.comments` - 评论列表字段是否存在?(预加载前5条) | 656 | +- ✅ 评论列表正常展示(一级评论 + 回复评论) |
| 236 | - - `user.is_teacher` - 用户角色字段是否存在于 `localStorage.user_info`?在localStorage的currentUser中有存个人信息 | 657 | +- ✅ 回复功能正常工作 |
| 237 | - | 658 | +- ✅ 删除功能正常工作(仅删除自己的评论) |
| 238 | -3. **权限控制**: | 659 | +- ✅ 懒加载正常工作(查看全部) |
| 239 | - - 置顶功能:是否仅教师可见?是否有更细粒度的权限控制?仅教师可以置顶打卡. | 660 | +- ✅ 教师可以审核评论(屏蔽/通过) |
| 240 | - - 删除评论:是否只能删除自己的评论?教师是否可以删除所有评论? | 661 | + |
| 241 | - - 评论功能:是否允许自己评论自己的打卡?允许. | 662 | +### 第 4 里程碑: 海报功能完成 |
| 242 | - | 663 | +- ✅ 海报正常生成 |
| 243 | -4. **业务规则**: | 664 | +- ✅ 支持长内容 |
| 244 | - - 评论字符限制:是 200 字还是其他数量? | 665 | +- ✅ 降级方案正常工作(生成失败时) |
| 245 | - - 是否允许发送纯表情评论(无文字)? | ||
| 246 | - - 评论后是否需要通知打卡用户或被回复用户? | ||
| 247 | - - 置顶数量限制:是否限制同时置顶的打卡数量? | ||
| 248 | - | ||
| 249 | -### 与产品确认 | ||
| 250 | -1. **功能优先级**: | ||
| 251 | - - 4 个功能(置顶、评论、海报、评论列表)的开发优先级是什么? | ||
| 252 | - - 是否需要在第一版就全部完成,还是可以分阶段上线? | ||
| 253 | - | ||
| 254 | -2. **交互细节**: | ||
| 255 | - - 置顶的打卡是否需要特殊的视觉标记(如"📌 置顶"标签、置顶图标等)? | ||
| 256 | - - 评论删除是否需要二次确认?(计划中已确认需要) | ||
| 257 | - - 表情选择器是否需要分类(如"笑脸"、"手势"、"动物"等)? | ||
| 258 | - - 海报生成失败时,是否需要降级方案(如显示文字版分享链接)? | ||
| 259 | - | ||
| 260 | -3. **内容规范**: | ||
| 261 | - - 评论内容的敏感词过滤策略是什么? | ||
| 262 | - - 是否需要举报功能? | ||
| 263 | - - 是否需要审核机制(评论需审核后才能显示)? | ||
| 264 | - | ||
| 265 | -4. **数据统计**: | ||
| 266 | - - 是否需要统计评论数量、置顶数量等数据用于运营分析? | ||
| 267 | 666 | ||
| 268 | --- | 667 | --- |
| 269 | 668 | ||
| 270 | -## 总结 | 669 | +## 下一步行动 |
| 271 | 670 | ||
| 272 | -### ✅ 计划完善度评估 | 671 | +1. ✅ 与后端/产品确认"待确认事项"中的所有问题 |
| 672 | +2. ✅ 确认开发优先级和里程碑节点 | ||
| 673 | +3. ⏳ 开始第 1 阶段开发(置顶功能) | ||
| 674 | +4. ⏳ 同步准备 API Mock 数据,以便前端独立开发 | ||
| 675 | +5. ⏳ 确认后端 API 开发进度,确保前后端同步 | ||
| 273 | 676 | ||
| 274 | -**总体评分:9/10** - 开发计划已经非常完善,涵盖了需求、设计、API、边界条件等各个方面。 | 677 | +--- |
| 275 | 678 | ||
| 276 | -**优点:** | 679 | +## 附录: 常用表情列表 |
| 277 | -- ✅ 需求拆解清晰,环境变量开关设计灵活 | ||
| 278 | -- ✅ 技术方案成熟可行(表情选择器、评论系统、海报生成) | ||
| 279 | -- ✅ API 设计完整,涵盖增删改查 | ||
| 280 | -- ✅ 数据结构设计合理(扁平化评论结构) | ||
| 281 | -- ✅ 边界条件考虑充分(Emoji 字符计数、数据库 utf8mb4) | ||
| 282 | -- ✅ 参考现有代码库,复用性高 | ||
| 283 | -- ✅ 开发步骤清晰,循序渐进 | ||
| 284 | -- ✅ 性能优化、错误处理、测试计划都已考虑 | ||
| 285 | 680 | ||
| 286 | -**需要改进的地方:** | 681 | +``` |
| 287 | -- ⚠️ 部分业务规则需要与后端/产品确认(见"待确认事项") | 682 | +😊😂❤️👍🎉✨🙏💪🔥💯😍👏🤝🌟🎁 |
| 288 | -- ⚠️ 置顶视觉标记、评论通知等功能细节需要补充 | 683 | +😭😡🤔💭😴🎂🌈⭐🌙☀️🌺🌸🍀🎁🎈 |
| 289 | -- ⚠️ 错误处理和降级方案可以更详细 | 684 | +🎵🎶📱💻⚽🏀🎾🎯🎨🎬📷🎤🎧📚✏️📝 |
| 685 | +💡🔔💬📧📞 | ||
| 686 | +``` | ||
| 290 | 687 | ||
| 291 | -### 🎯 建议的开发顺序 | 688 | +**总计**: 64 个常用表情符号 |
| 292 | 689 | ||
| 293 | -1. **第 1 阶段**:置顶功能(最简单,快速验证流程) | 690 | +--- |
| 294 | -2. **第 2 阶段**:评论功能 + 评论列表(核心功能,投入最大) | ||
| 295 | -3. **第 3 阶段**:海报功能(技术难度较高,可最后开发) | ||
| 296 | 691 | ||
| 297 | -### 📝 下一步行动 | 692 | +## 变更记录 |
| 298 | 693 | ||
| 299 | -1. 与后端/产品确认"待确认事项"中的所有问题 | 694 | +**2026-01-27**: |
| 300 | -2. 确认开发优先级和里程碑节点 | 695 | +- ✅ 与后端/产品确认所有待确认事项 |
| 301 | -3. 开始第 1 阶段开发(置顶功能) | 696 | +- ✅ 新增教师评论管理功能 |
| 302 | -4. 同步准备 API Mock 数据,以便前端独立开发 | 697 | +- ✅ 更新开发优先级(置顶、评论、评论列表为高优先级,海报为中优先级) |
| 698 | +- ✅ 完善数据字段定义 | ||
| 699 | +- ✅ 完善业务规则(字符限制、权限控制、通知机制) | ||
| 700 | +- ✅ 按优先级重新组织开发步骤 | ... | ... |
-
Please register or login to post a comment