26.1.26新功能开发计划.md 21.8 KB

26.1.26 新功能开发计划

背景

为了增强用户在打卡列表的互动性和管理能力,需要在打卡卡片(CheckinCard)上增加更多操作选项,包括置顶、评论、海报分享以及展示评论列表。这些功能将通过环境变量开关进行控制,以便按需开启。

需求拆解

  1. 置顶功能 (优先级: 🔴 高) - 允许教师将特定打卡内容置顶
  2. 评论功能 (优先级: 🔴 高) - 允许用户对打卡内容进行评论
  3. 评论列表 (优先级: 🔴 高) - 在打卡卡片下方显示该打卡的评论记录
  4. 海报功能 (优先级: 🟡 中) - 生成包含打卡内容的长图海报,支持分享

环境变量规划

.env 中增加以下开关(默认 '0' 关闭,'1' 开启):

  • VITE_FEATURE_CHECKIN_TOP=1 (置顶功能)
  • VITE_FEATURE_CHECKIN_COMMENT=1 (评论功能)
  • VITE_FEATURE_CHECKIN_POSTER=1 (海报功能)
  • VITE_FEATURE_CHECKIN_COMMENT_LIST=1 (评论列表显示)

详细设计与逻辑流程

1. 入口改造 (CheckinCard)

位置: 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 teacherPinCheckinAPI - 教师置顶打卡 (参数: checkin_id)
  • POST teacherUnpinCheckinAPI - 教师取消置顶打卡 (参数: checkin_id)

数据字段扩展

{
  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=1post.comments.length > 0

评论列表展示 (CheckinCommentList)

组件: CheckinCommentList.vue (参考 StudyCommentsSection.vue 的实现模式)

显示逻辑:

  • 首屏最多展示 5 条评论
  • 超过 5 条显示"查看全部"按钮
  • 点击"查看全部"加载完整评论列表(懒加载)
  • 样式参考微信朋友圈(灰色背景,每行 用户: 内容)

数据结构 (扁平化设计):

{
  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: '' }

数据字段扩展:

{
  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_iduser_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: '' }

数据字段扩展

{
  comments_count: 0,           // 评论总数(用于列表展示)
  comments: []                 // 评论列表(最多 5 条,用于首屏渲染)
}

5. 海报功能 🟡 中优先级

逻辑流程

  1. 点击"海报"菜单
  2. 弹出 海报预览组件 (CheckinPoster,参考 SharePoster)
  3. 渲染内容:
    • 用户信息(头像、昵称)
    • 打卡内容(文本、图片缩略图)
    • 底部二维码(打卡主页的网址自动生成)
    • 支持长图,若内容过长通过滚动查看
  4. 生成图片: 使用 html2canvashtml-to-image 将 DOM 转为图片
  5. 展示生成的图片,提示"长按保存"

降级方案

  • 海报生成是异步操作,可能会失败
  • 生成失败时显示降级卡片:
    • 卡片包含: 用户头像、昵称、打卡内容摘要
    • 底部提示: "长按截图保存分享"
    • 用户可手动截图保存

技术要点

  • 处理跨域图片: 配置 useCORS: true 且 CDN 支持 CORS
  • 长图渲染: 需限制最大高度或分段(第一版暂不考虑极端情况)
  • 字体加载: 确保字体加载完成后再生成图片

开发步骤

🔴 第 1 阶段: 置顶功能 (高优先级)

目标: 实现教师置顶打卡功能

步骤:

  1. 环境准备:

    • .env 添加 VITE_FEATURE_CHECKIN_TOP=1
    • src/api/teacher.js 中定义 teacherPinCheckinAPIteacherUnpinCheckinAPI (已实现)
  2. 用户权限获取:

    • 创建 useAuthRole.js composable
    • 实现实时请求用户角色接口(不依赖 localStorage)
    • 返回 { is_teacher: boolean }
  3. 改造 CheckinCard:

    • 引入 van-action-sheet
    • 在菜单中添加"置顶"/"取消置顶"选项(根据 is_pinnedis_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_countcomments 字段渲染
    • 评论发表成功后自动刷新列表
  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. 字符计数与 Emoji 处理

问题: Emoji 符号在某些设备上占用 2 个字符位置(代理对)

解决方案:

// 错误方式
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 对象新增字段

{
  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 对象数据结构

{
  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 对象新增字段

{
  id: 123,
  name: "张三",
  avatar: "...",

  // 🆕 角色字段
  is_teacher: false             // 是否是教师(需实时请求后端获取)
}

API 接口汇总

置顶功能

  • POST teacherPinCheckinAPI - 教师置顶打卡 (参数: checkin_id)
  • POST teacherUnpinCheckinAPI - 教师取消置顶打卡 (参数: 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 批)

  1. 海报功能 - 实现打卡海报生成与分享

里程碑

第 1 里程碑: 置顶功能完成

  • ✅ 教师可以置顶/取消置顶打卡
  • ✅ 置顶打卡显示 📌 图标
  • ✅ 权限控制正确(仅教师可见)

第 2 里程碑: 评论功能完成

  • ✅ 用户可以发表评论(文本 + 表情)
  • ✅ 表情选择器正常工作
  • ✅ 输入验证正确(最少 5 字,最多 200 字)
  • ✅ 评论成功后通知后端(后端发送通知)

第 3 里程碑: 评论列表完成

  • ✅ 评论列表正常展示(一级评论 + 回复评论)
  • ✅ 回复功能正常工作
  • ✅ 删除功能正常工作(仅删除自己的评论)
  • ✅ 懒加载正常工作(查看全部)
  • ✅ 教师可以审核评论(屏蔽/通过)

第 4 里程碑: 海报功能完成

  • ✅ 海报正常生成
  • ✅ 支持长内容
  • ✅ 降级方案正常工作(生成失败时)

下一步行动

  1. ✅ 与后端/产品确认"待确认事项"中的所有问题
  2. ✅ 确认开发优先级和里程碑节点
  3. ⏳ 开始第 1 阶段开发(置顶功能)
  4. ⏳ 同步准备 API Mock 数据,以便前端独立开发
  5. ⏳ 确认后端 API 开发进度,确保前后端同步

附录: 常用表情列表

😊😂❤️👍🎉✨🙏💪🔥💯😍👏🤝🌟🎁
😭😡🤔💭😴🎂🌈⭐🌙☀️🌺🌸🍀🎁🎈
🎵🎶📱💻⚽🏀🎾🎯🎨🎬📷🎤🎧📚✏️📝
💡🔔💬📧📞

总计: 64 个常用表情符号


变更记录

2026-01-27:

  • ✅ 与后端/产品确认所有待确认事项
  • ✅ 新增教师评论管理功能
  • ✅ 更新开发优先级(置顶、评论、评论列表为高优先级,海报为中优先级)
  • ✅ 完善数据字段定义
  • ✅ 完善业务规则(字符限制、权限控制、通知机制)
  • ✅ 按优先级重新组织开发步骤