7.3 KiB
7.3 KiB
问卷功能完整实现方案
📋 需求概述
系统需要支持完整的问卷功能,包括:
- 问卷在量表管理中显示:创建的问卷能够出现在量表管理中
- 问卷答题功能:用户填写完问卷后,客观题自动打分,主观题传给管理员进行打分
- 多种题目类型支持:单选、多选、判断、填空、排序、计算、简答、问答、作文等
- 多种组卷形式:自助组卷、随机组卷、手动随机相结合
- 成绩排名统计:客观题系统自动实现打分,成绩自动排名统计
🎯 实现方案
阶段一:让问卷显示在量表管理中
方案1:统一查询接口(推荐)
- 修改量表列表查询,同时返回问卷数据
- 添加类型标识字段(
sourceType: 'scale' 或 'questionnaire') - 前端统一显示,根据类型标识区分操作
方案2:创建统一视图
- 在数据库创建视图,统一量表和问卷
- 查询时使用视图
选择方案1,因为更灵活,不需要修改数据库结构。
阶段二:问卷答题功能
参考量表测评的实现方式:
- 开始问卷:创建问卷答题记录
- 获取题目:根据组卷方式获取题目列表
- 保存答案:实时保存用户答案
- 提交问卷:
- 客观题自动计分
- 主观题标记为待评分
- 计算客观题总分
- 更新排名
阶段三:自动打分功能
客观题类型
- radio(单选):根据选项的
is_correct和option_score计分 - checkbox(多选):全对得满分,部分对按比例得分
- boolean(判断):根据选项的
is_correct计分 - input(填空):如果有标准答案,进行文本匹配(支持模糊匹配)
- sort(排序):顺序完全正确得满分,部分正确按比例得分
- calculate(计算):数值匹配,允许误差范围
主观题类型
- text(简答):需要管理员评分
- textarea(问答):需要管理员评分
- essay(作文):需要管理员评分
- input(无标准答案):需要管理员评分
阶段四:主观题评分管理
- 待评分列表:显示所有待评分的主观题
- 评分界面:管理员可以查看题目、答案,进行评分
- 批量评分:支持批量评分功能
- 评分后更新:评分后更新总分和排名
阶段五:成绩排名统计
- 排名计算:
- 按总分从高到低排序
- 相同分数按提交时间排序(先提交的排名靠前)
- 排名更新:提交问卷或评分后自动更新排名
- 排名查询:支持按问卷查询排名列表
📁 需要创建/修改的文件
数据库
psy_questionnaire- 问卷表(已存在)psy_questionnaire_item- 问卷题目表(已存在)psy_questionnaire_option- 问卷选项表(已存在)psy_questionnaire_answer- 问卷答题记录表(已存在)psy_questionnaire_answer_detail- 问卷答案详情表(需要创建)
后端Java文件
PsyQuestionnaireAnswerDetail.java- 问卷答案详情实体类PsyQuestionnaireAnswerDetailMapper.java- Mapper接口PsyQuestionnaireAnswerDetailMapper.xml- MyBatis映射IPsyQuestionnaireAnswerService.java- 问卷答题服务接口PsyQuestionnaireAnswerServiceImpl.java- 问卷答题服务实现PsyQuestionnaireController.java- 问卷控制器(需要增强)PsyScaleController.java- 量表控制器(需要修改列表查询)
前端Vue文件
questionnaire/taking.vue- 问卷答题页面questionnaire/start.vue- 开始问卷页面questionnaire/scoring.vue- 主观题评分页面questionnaire/ranking.vue- 成绩排名页面scale/index.vue- 量表管理页面(需要修改,显示问卷)
🔧 技术实现细节
1. 量表列表统一显示问卷
后端修改:
// PsyScaleController.java
@GetMapping("/list")
public TableDataInfo list(PsyScale scale, @RequestParam(required = false) Boolean includeQuestionnaire)
{
startPage();
List<PsyScale> scaleList = scaleService.selectScaleList(scale);
// 如果需要包含问卷
if (includeQuestionnaire != null && includeQuestionnaire) {
List<PsyQuestionnaire> questionnaireList = questionnaireService.selectQuestionnaireList(...);
// 转换为统一的Scale格式,添加sourceType标识
// 合并到scaleList
}
return getDataTable(scaleList);
}
前端修改:
// scale/index.vue
// 在表格中添加类型列
<el-table-column label="类型" prop="sourceType" width="100">
<template slot-scope="scope">
<el-tag v-if="scope.row.sourceType === 'questionnaire'" type="warning">问卷</el-tag>
<el-tag v-else type="primary">量表</el-tag>
</template>
</el-table-column>
2. 问卷答题流程
参考量表测评的实现:
- 开始问卷 → 创建
PsyQuestionnaireAnswer记录 - 获取题目 → 根据
paper_type获取题目列表 - 保存答案 → 保存到
PsyQuestionnaireAnswerDetail - 提交问卷 → 自动计分 + 更新排名
3. 自动计分逻辑
// 客观题计分
private BigDecimal calculateObjectiveScore(PsyQuestionnaireItem item, AnswerDetailVO answer) {
switch(item.getItemType()) {
case "radio":
// 单选:检查选项是否正确
return checkOptionCorrect(item, answer.getOptionId()) ? item.getScore() : BigDecimal.ZERO;
case "checkbox":
// 多选:检查所有选项是否正确
return calculateMultiChoiceScore(item, answer.getOptionIds());
case "boolean":
// 判断:检查选项是否正确
return checkOptionCorrect(item, answer.getOptionId()) ? item.getScore() : BigDecimal.ZERO;
case "input":
// 填空:文本匹配
return checkTextMatch(item, answer.getAnswerText()) ? item.getScore() : BigDecimal.ZERO;
// ... 其他类型
}
}
4. 排名计算
-- 更新排名
UPDATE psy_questionnaire_answer qa
SET qa.rank = (
SELECT COUNT(*) + 1
FROM psy_questionnaire_answer qa2
WHERE qa2.questionnaire_id = qa.questionnaire_id
AND (
qa2.total_score > qa.total_score
OR (qa2.total_score = qa.total_score AND qa2.submit_time < qa.submit_time)
)
)
WHERE qa.questionnaire_id = #{questionnaireId}
AND qa.status = '1'
📌 实施步骤
- ✅ 创建问卷答案详情表(SQL)
- ⏳ 修改量表列表查询,包含问卷(后端)
- ⏳ 修改量表管理页面,显示问卷(前端)
- ⏳ 创建问卷答题功能(后端+前端)
- ⏳ 实现自动计分功能(后端)
- ⏳ 实现主观题评分功能(后端+前端)
- ⏳ 实现成绩排名功能(后端+前端)
⚠️ 注意事项
- 问卷和量表的数据结构不同,需要统一转换
- 组卷方式(随机、手动、混合)需要在获取题目时实现
- 主观题评分需要权限控制
- 排名计算要考虑性能,可能需要定时任务
- 填空题的文本匹配需要考虑容错性
创建时间: 2025-01-XX
最后更新: 2025-01-XX