# 问答答疑多选最佳答案功能实现说明 ## 功能概述 将原有的单选最佳答案功能升级为多选最佳答案功能,支持以下特性: - ✅ 最多可选择5条内容作为最佳答案 - ✅ 五条内容可以是同一人 - ✅ 每个内容均进行赋分 - ✅ 不限制每个人只能获得1次的分数 - ✅ 统一提交后对回答人和提问人员进行赋分 ## 数据库变更 ### 1. 新建表: work_knowledge_base_best_answer **文件**: `alter_work_knowledge_base_add_best_answers.sql` ```sql CREATE TABLE IF NOT EXISTS work_knowledge_base_best_answer ( id VARCHAR(64) NOT NULL COMMENT '主键ID', question_id VARCHAR(64) NOT NULL COMMENT '问题ID', answer_id VARCHAR(64) NOT NULL COMMENT '答案ID', sort_order INT DEFAULT 0 COMMENT '排序号', create_by VARCHAR(64) COMMENT '创建人ID', create_date DATETIME COMMENT '创建时间', del_flag CHAR(1) DEFAULT '0' COMMENT '删除标记', PRIMARY KEY (id), KEY idx_question_id (question_id), KEY idx_answer_id (answer_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='问答最佳答案关联表'; ``` **说明**: - 原`work_knowledge_base_share_info`表中的`answer_id`字段保留但不再使用 - 新表支持一对多关系,一个问题可对应多条最佳答案 ## 后端实现 ### 1. 实体类 - WorkKnowledgeBaseBestAnswer.java **位置**: `src/main/java/com/jeeplus/modules/WorkKnowledgeBase/entity/WorkKnowledgeBaseBestAnswer.java` **主要字段**: - `questionId`: 问题ID - `answerId`: 答案ID - `sortOrder`: 排序号 - `answerContent`: 回答内容(关联查询) - `answerUserName`: 回答人姓名(关联查询) - `answerUserId`: 回答人ID(关联查询) ### 2. DAO层 - WorkKnowledgeBaseBestAnswerDao.java **位置**: `src/main/java/com/jeeplus/modules/WorkKnowledgeBase/dao/WorkKnowledgeBaseBestAnswerDao.java` **主要方法**: - `findByQuestionId()`: 根据问题ID查询最佳答案列表 - `countByQuestionId()`: 统计问题的最佳答案数量 - `isBestAnswer()`: 检查答案是否已被设为最佳答案 - `batchInsert()`: 批量插入最佳答案 - `deleteByQuestionId()`: 删除问题的所有最佳答案 ### 3. MyBatis映射 - WorkKnowledgeBaseBestAnswerDao.xml **位置**: `src/main/resources/mappings/modules/WorkKnowledgeBase/WorkKnowledgeBaseBestAnswerDao.xml` **关键SQL**: - 关联查询最佳答案及回答内容、回答人信息 - 批量插入最佳答案记录 ### 4. Service层 - WorkKnowledgeBaseShareService.java #### 新增方法: **confirmMultipleBestAnswers(String questionId, List answerIds)** ```java /** * 确认多个最佳答案(最多5条) * @param questionId 问题ID * @param answerIds 答案ID列表 * @return 返回所有回答人ID列表(不重复) */ ``` **核心逻辑**: 1. 验证参数(至少1条,最多5条) 2. 检查问题状态和分类 3. 验证每个答案是否存在且属于该问题 4. 删除旧的最佳答案记录 5. 批量插入新的最佳答案记录 6. 更新问题状态为已结束(8) 7. 收集并返回所有不重复的回答人ID **findBestAnswers(String questionId)** - 查询问题的最佳答案列表 **isBestAnswer(String questionId, String answerId)** - 检查答案是否已被设为最佳答案 #### 修改方法: **grantQaPointsToMultipleUsers(String questionId, List answerUserIds)** ```java /** * 给问答参与人员发放积分(支持多个回答人) * @param questionId 问题ID * @param answerUserIds 所有回答人ID列表(不重复) */ ``` **核心逻辑**: 1. 查询"问答答疑"分类配置 2. 获取提问积分规则和回答积分规则 3. 给问题发起人发放积分(一次) 4. **遍历每个回答人发放积分**(同一个人如果有多条最佳答案,会多次发放) ### 5. Controller层 - WorkKnowledgeBaseShareController.java #### 修改接口: **confirmMultipleBestAnswers()** ```java @RequestMapping(value = "confirmMultipleBestAnswers") @ResponseBody public Map confirmMultipleBestAnswers( @RequestParam String questionId, @RequestParam List answerIds) ``` **处理流程**: 1. 验证是否为问题发起人 2. 调用Service保存多条最佳答案 3. 调用Service发放积分给所有回答人 4. 返回成功信息和回答人数量 ## 前端实现 ### 1. 详情页 - workKnowledgeBaseShareDetail.jsp #### UI变更: **新增确认区域**: ```html ``` **回答项变更**: - 原"确认为最佳答案"链接改为复选框 - 复选框样式: `` - 仅问题发起人且未确认答案时显示复选框 #### JavaScript变更: **新增变量**: ```javascript var hasConfirmedAnswers = false; // 是否已确认答案 ``` **新增函数**: **bindCheckboxEvents()** - 监听复选框变化 - 限制最多选择5条 - 实时更新已选择数量 - 启用/禁用确认按钮 **batchConfirmBestAnswers()** - 收集所有选中的答案ID - 调用后端API批量确认 - 成功后刷新列表并隐藏确认区域 **修改函数**: **renderAnswers()** - 渲染完成后绑定复选框事件 - 显示确认区域(仅问题发起人) - 更新`hasConfirmedAnswers`全局变量 **renderAnswerItem()** - 将"确认最佳答案"链接改为复选框 - 条件判断使用`hasConfirmedAnswers`替代`hasBestAnswer` ### 2. 列表页 - workKnowledgeBaseShareList.jsp #### 变更: **确认答案按钮**: - 原来: `openDetailDialogWithRead()` - 只读模式 - 现在: `openQaDetailDialogWithRead()` - 带确认功能的只读模式 - 目的: 打开详情页让用户选择多个最佳答案 ## 积分发放规则 ### 发放时机 - 问题发起人确认最佳答案后立即发放 ### 发放对象 **1. 问题发起人** - 发放一次提问积分(rule_type=1) - 从"问答答疑"分类的积分规则中读取固定分值 **2. 回答人** - 每条最佳答案都发放回答积分(rule_type=2) - **五条内容可以是同一人** - **每个内容均进行赋分** - **不限制每个人只能获得1次的分数** ### 示例场景 **场景1**: 5条最佳答案来自5个不同的人 - 问题发起人获得1次提问积分 - 5个回答人各获得1次回答积分 **场景2**: 5条最佳答案全部来自同一个人 - 问题发起人获得1次提问积分 - 该回答人获得5次回答积分(5 × 单次积分值) **场景3**: 3条最佳答案,其中2条来自A,1条来自B - 问题发起人获得1次提问积分 - A获得2次回答积分 - B获得1次回答积分 ## 使用说明 ### 操作流程 1. **问题发起人**点击"确认答案"按钮 2. 系统打开详情页,显示所有回答 3. 每个回答右侧显示复选框"选择为最佳答案" 4. 发起人勾选最多5条最佳答案 5. 页面实时显示已选择数量(X/5) 6. 点击"确认选择的答案"按钮 7. 系统提示确认信息 8. 确认后: - 问题状态变为"已结束"(8) - 最佳答案被标记 - 积分自动发放 - 其他人无法继续回答 ### 限制条件 - ✅ 只有问题发起人可以确认答案 - ✅ 最多选择5条最佳答案 - ✅ 至少选择1条最佳答案 - ✅ 确认后不可撤销 - ✅ 问题结束后无法继续回答 ## 技术要点 ### 1. 数据去重 - Service层使用`HashSet`收集回答人ID - 确保即使同一人有多条最佳答案,在列表中只出现一次 - 但积分发放时会遍历原始答案列表,保证多次发放 ### 2. 事务控制 - `@Transactional(readOnly = false)`确保原子性 - 最佳答案保存和积分发放要么全部成功,要么全部失败 ### 3. 批量操作 - 使用MyBatis的``标签实现批量插入 - 减少数据库交互次数,提高性能 ### 4. 前端交互 - 使用jQuery事件委托(`on('change')`)绑定动态元素 - 实时反馈用户操作(计数更新、按钮启用/禁用) - Layer弹窗提供友好的确认提示 ## 测试建议 ### 功能测试 1. **基本功能** - [ ] 选择1-5条最佳答案并确认 - [ ] 尝试选择6条,验证限制 - [ ] 不选择任何答案,验证提示 2. **积分发放** - [ ] 5条答案来自5个人,验证每人获得1次积分 - [ ] 5条答案来自1个人,验证该人获得5次积分 - [ ] 混合场景,验证积分正确发放 3. **边界情况** - [ ] 问题已确认后再次确认,验证拦截 - [ ] 非发起人尝试确认,验证权限 - [ ] 只读模式打开,验证复选框不显示 ### 性能测试 - [ ] 大量答案场景下的选择性能 - [ ] 批量插入5条记录的数据库性能 - [ ] 并发确认同一问题的锁机制 ## 注意事项 1. **数据库迁移** - 执行SQL脚本前备份数据 - 建议在测试环境先验证 2. **兼容性** - 旧的单条最佳答案数据仍然保留在`answer_id`字段 - 新数据存储在关联表中 - 后续可编写迁移脚本将旧数据迁移到新表 3. **日志记录** - 建议在Service层添加操作日志 - 记录谁在何时确认了哪些答案为最佳 4. **权限控制** - 已有`@RequiresPermissions`注解保护 - 前端也进行了发起人身份验证 - 双重保障确保安全 ## 相关文件清单 ### 后端文件 - `WorkKnowledgeBaseBestAnswer.java` - 实体类 - `WorkKnowledgeBaseBestAnswerDao.java` - DAO接口 - `WorkKnowledgeBaseBestAnswerDao.xml` - MyBatis映射 - `WorkKnowledgeBaseShareService.java` - Service层(修改) - `WorkKnowledgeBaseShareController.java` - Controller层(修改) ### 前端文件 - `workKnowledgeBaseShareDetail.jsp` - 详情页(修改) - `workKnowledgeBaseShareList.jsp` - 列表页(修改) ### 数据库脚本 - `alter_work_knowledge_base_add_best_answers.sql` - 建表脚本 --- **完成日期**: 2026-01-16 **版本**: v1.0 **作者**: AI Assistant