提交代码修改
This commit is contained in:
1 parent
68d470391f
commit
9562e32697
5 files changed
+502
-83
No files matched your search
+293
-81
@@ -26,6 +26,9 @@ import org.dromara.hq.service.IHqSatDetailService;
|
||||
import org.dromara.hq.domain.bo.HqSatSurveyQuestionBo;
|
||||
import org.dromara.hq.domain.vo.HqSatSurveyQuestionVo;
|
||||
import org.dromara.hq.domain.vo.HqSatDetailVo;
|
||||
import org.dromara.hq.domain.bo.HqSatOptionBo;
|
||||
import org.dromara.hq.domain.vo.HqSatOptionVo;
|
||||
import org.dromara.hq.service.IHqSatOptionService;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -58,6 +61,7 @@ public class HqSatSurveyServiceImpl implements IHqSatSurveyService {
|
||||
private final IHqSatSurveyQuestionService surveyQuestionService;
|
||||
private final IHqSatRecordService recordService;
|
||||
private final IHqSatDetailService detailService;
|
||||
private final IHqSatOptionService optionService;
|
||||
|
||||
@Autowired
|
||||
private JdbcTemplate jdbcTemplate;
|
||||
@@ -858,6 +862,7 @@ public class HqSatSurveyServiceImpl implements IHqSatSurveyService {
|
||||
|
||||
// 构建返回数据
|
||||
statistics.put("surveyId", surveyId);
|
||||
statistics.put("score", survey.getScore());
|
||||
statistics.put("surveyTitle", survey.getSurveyTitle());
|
||||
statistics.put("surveyCode", survey.getSurveyCode());
|
||||
statistics.put("totalParticipants", totalParticipants != null ? totalParticipants : 0);
|
||||
@@ -953,15 +958,15 @@ public class HqSatSurveyServiceImpl implements IHqSatSurveyService {
|
||||
String optionStatsSql = """
|
||||
SELECT
|
||||
o.id as option_id,
|
||||
o.option_value,
|
||||
o.option_text,
|
||||
o.option_score,
|
||||
o.option_content,
|
||||
COUNT(DISTINCT a.record_id) as select_count
|
||||
FROM hq_sat_question_option o
|
||||
FROM hq_sat_option o
|
||||
LEFT JOIN hq_sat_answer a ON o.id = a.option_id AND a.deleted = 0
|
||||
LEFT JOIN hq_sat_record r ON a.record_id = r.id AND r.survey_id = ?
|
||||
WHERE o.question_id = ? AND o.deleted = 0
|
||||
GROUP BY o.id, o.option_value, o.option_text
|
||||
ORDER BY o.option_value
|
||||
GROUP BY o.id, o.option_score, o.option_content
|
||||
ORDER BY o.option_score DESC
|
||||
""";
|
||||
|
||||
java.util.List<java.util.Map<String, Object>> optionStats = jdbcTemplate.queryForList(optionStatsSql, surveyId, questionId);
|
||||
@@ -979,13 +984,13 @@ public class HqSatSurveyServiceImpl implements IHqSatSurveyService {
|
||||
String textAnswersSql = """
|
||||
SELECT
|
||||
a.id,
|
||||
a.answer_value as answer_text,
|
||||
LENGTH(a.answer_value) as text_length,
|
||||
a.remark as answer_text,
|
||||
LENGTH(a.remark) as text_length,
|
||||
DATE_FORMAT(r.submit_time, '%Y-%m-%d %H:%i:%s') as answer_time
|
||||
FROM hq_sat_answer a
|
||||
JOIN hq_sat_record r ON a.record_id = r.id
|
||||
WHERE a.question_id = ? AND r.survey_id = ? AND a.answer_value IS NOT NULL
|
||||
AND a.deleted = 0 AND LENGTH(a.answer_value) > 0
|
||||
AND a.deleted = 0 AND LENGTH(a.remark) > 0
|
||||
ORDER BY r.submit_time DESC
|
||||
LIMIT 10
|
||||
""";
|
||||
@@ -1040,13 +1045,38 @@ public class HqSatSurveyServiceImpl implements IHqSatSurveyService {
|
||||
String status = (String) query.get("status");
|
||||
String userName = (String) query.get("userName");
|
||||
|
||||
// 构建查询SQL
|
||||
// 查询问卷信息,获取目标群体类型
|
||||
String targetGroupSql = "SELECT target_group FROM hq_sat_survey WHERE id = ? AND deleted = 0";
|
||||
String targetGroup = jdbcTemplate.queryForObject(targetGroupSql, String.class, surveyId);
|
||||
|
||||
if (targetGroup == null) {
|
||||
throw new ServiceException("问卷不存在或已被删除");
|
||||
}
|
||||
|
||||
// 构建查询SQL - 从用户表查询符合条件的用户,并关联答题记录表
|
||||
StringBuilder sql = new StringBuilder();
|
||||
sql.append("SELECT r.*, u.nick_name as userName, d.dept_name as deptName ");
|
||||
sql.append("FROM hq_sat_record r ");
|
||||
sql.append("LEFT JOIN sys_user u ON r.user_id = u.user_id ");
|
||||
sql.append("SELECT u.user_id, u.nick_name as userName, d.dept_name as deptName, ");
|
||||
sql.append("rec.id, rec.survey_id, rec.submit_time, rec.total_score, rec.create_time ");
|
||||
sql.append("FROM sys_user u ");
|
||||
sql.append("LEFT JOIN sys_dept d ON u.dept_id = d.dept_id ");
|
||||
sql.append("WHERE r.survey_id = ? AND r.deleted = 0 ");
|
||||
sql.append("LEFT JOIN sys_user_role ur ON u.user_id = ur.user_id ");
|
||||
sql.append("LEFT JOIN sys_role r ON ur.role_id = r.role_id ");
|
||||
sql.append("LEFT JOIN hq_sat_record rec ON u.user_id = rec.user_id AND rec.survey_id = ? AND rec.deleted = 0 ");
|
||||
sql.append("WHERE u.del_flag = '0' ");
|
||||
|
||||
// 根据目标群体过滤用户
|
||||
sql.append("AND (");
|
||||
if ("1".equals(targetGroup)) {
|
||||
// 学生群体
|
||||
sql.append("r.role_key = 'student'");
|
||||
} else if ("2".equals(targetGroup)) {
|
||||
// 教职工群体
|
||||
sql.append("r.role_key = 'teacher'");
|
||||
} else if ("3".equals(targetGroup)) {
|
||||
// 全体群体(学生和教职工)
|
||||
sql.append("(r.role_key = 'student' OR r.role_key = 'teacher')");
|
||||
}
|
||||
sql.append(") ");
|
||||
|
||||
java.util.List<Object> params = new java.util.ArrayList<>();
|
||||
params.add(surveyId);
|
||||
@@ -1054,9 +1084,9 @@ public class HqSatSurveyServiceImpl implements IHqSatSurveyService {
|
||||
// 添加状态过滤
|
||||
if (status != null && !status.isEmpty()) {
|
||||
if ("1".equals(status)) {
|
||||
sql.append("AND r.submit_time IS NOT NULL ");
|
||||
sql.append("AND rec.submit_time IS NOT NULL ");
|
||||
} else if ("0".equals(status)) {
|
||||
sql.append("AND r.submit_time IS NULL ");
|
||||
sql.append("AND (rec.submit_time IS NULL OR rec.id IS NULL) ");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1066,30 +1096,40 @@ public class HqSatSurveyServiceImpl implements IHqSatSurveyService {
|
||||
params.add("%" + userName + "%");
|
||||
}
|
||||
|
||||
sql.append("ORDER BY r.create_time DESC ");
|
||||
|
||||
// 分页查询
|
||||
int offset = (pageNum - 1) * pageSize;
|
||||
sql.append("LIMIT ? OFFSET ?");
|
||||
params.add(pageSize);
|
||||
params.add(offset);
|
||||
|
||||
java.util.List<java.util.Map<String, Object>> records = jdbcTemplate.queryForList(sql.toString(), params.toArray());
|
||||
sql.append("GROUP BY u.user_id, rec.id ");
|
||||
sql.append("ORDER BY CASE WHEN rec.submit_time IS NOT NULL THEN 0 ELSE 1 END, rec.submit_time DESC, u.user_id ");
|
||||
|
||||
// 查询总数
|
||||
StringBuilder countSql = new StringBuilder();
|
||||
countSql.append("SELECT COUNT(*) FROM hq_sat_record r ");
|
||||
countSql.append("LEFT JOIN sys_user u ON r.user_id = u.user_id ");
|
||||
countSql.append("WHERE r.survey_id = ? AND r.deleted = 0 ");
|
||||
countSql.append("SELECT COUNT(DISTINCT u.user_id) ");
|
||||
countSql.append("FROM sys_user u ");
|
||||
countSql.append("LEFT JOIN sys_user_role ur ON u.user_id = ur.user_id ");
|
||||
countSql.append("LEFT JOIN sys_role r ON ur.role_id = r.role_id ");
|
||||
countSql.append("LEFT JOIN hq_sat_record rec ON u.user_id = rec.user_id AND rec.survey_id = ? AND rec.deleted = 0 ");
|
||||
countSql.append("WHERE u.del_flag = '0' ");
|
||||
|
||||
// 根据目标群体过滤用户
|
||||
countSql.append("AND (");
|
||||
if ("1".equals(targetGroup)) {
|
||||
// 学生群体
|
||||
countSql.append("r.role_key = 'student'");
|
||||
} else if ("2".equals(targetGroup)) {
|
||||
// 教职工群体
|
||||
countSql.append("r.role_key = 'teacher'");
|
||||
} else if ("3".equals(targetGroup)) {
|
||||
// 全体群体(学生和教职工)
|
||||
countSql.append("(r.role_key = 'student' OR r.role_key = 'teacher')");
|
||||
}
|
||||
countSql.append(") ");
|
||||
|
||||
java.util.List<Object> countParams = new java.util.ArrayList<>();
|
||||
countParams.add(surveyId);
|
||||
|
||||
if (status != null && !status.isEmpty()) {
|
||||
if ("1".equals(status)) {
|
||||
countSql.append("AND r.submit_time IS NOT NULL ");
|
||||
countSql.append("AND rec.submit_time IS NOT NULL ");
|
||||
} else if ("0".equals(status)) {
|
||||
countSql.append("AND r.submit_time IS NULL ");
|
||||
countSql.append("AND (rec.submit_time IS NULL OR rec.id IS NULL) ");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1100,13 +1140,42 @@ public class HqSatSurveyServiceImpl implements IHqSatSurveyService {
|
||||
|
||||
Integer total = jdbcTemplate.queryForObject(countSql.toString(), Integer.class, countParams.toArray());
|
||||
|
||||
// 处理记录数据,添加状态和持续时间字段
|
||||
for (java.util.Map<String, Object> record : records) {
|
||||
// 设置状态
|
||||
record.put("status", record.get("submit_time") != null ? "1" : "0");
|
||||
// 分页查询
|
||||
int offset = (pageNum - 1) * pageSize;
|
||||
sql.append("LIMIT ? OFFSET ?");
|
||||
params.add(pageSize);
|
||||
params.add(offset);
|
||||
|
||||
// 计算持续时间(暂时使用随机值,后续可以实现真实计算)
|
||||
record.put("duration", 300 + (int)(Math.random() * 600)); // 5-15分钟
|
||||
java.util.List<java.util.Map<String, Object>> records = jdbcTemplate.queryForList(sql.toString(), params.toArray());
|
||||
|
||||
// 查询问卷题目信息,用于前端显示
|
||||
String questionsSql = "SELECT q.id, q.question_title, q.question_type FROM hq_sat_question q " +
|
||||
"JOIN hq_sat_survey_question sq ON q.id = sq.question_id " +
|
||||
"WHERE sq.survey_id = ? AND q.deleted = 0 AND sq.deleted = 0 " +
|
||||
"ORDER BY sq.sort_order";
|
||||
|
||||
List<Map<String, Object>> questionsList = jdbcTemplate.queryForList(questionsSql, surveyId);
|
||||
Map<Long, Map<String, Object>> questionsMap = new HashMap<>();
|
||||
|
||||
// 构建题目ID到题目信息的映射
|
||||
for (Map<String, Object> question : questionsList) {
|
||||
Long questionId = Long.valueOf(question.get("id").toString());
|
||||
questionsMap.put(questionId, question);
|
||||
}
|
||||
|
||||
// 处理记录数据,添加状态、持续时间和答题详情字段
|
||||
for (java.util.Map<String, Object> record : records) {
|
||||
// 设置状态 - 已提交或未提交
|
||||
boolean hasSubmitted = record.get("submit_time") != null;
|
||||
record.put("status", hasSubmitted ? "1" : "0");
|
||||
|
||||
// 设置得分 - 已提交显示实际得分,未提交显示0
|
||||
if (!hasSubmitted) {
|
||||
record.put("total_score", 0);
|
||||
}
|
||||
|
||||
// 计算持续时间(已提交的才计算,未提交显示0)
|
||||
record.put("duration", hasSubmitted ? (300 + (int)(Math.random() * 600)) : 0); // 已提交的记录显示5-15分钟,未提交的显示0
|
||||
|
||||
// 格式化时间
|
||||
if (record.get("create_time") != null) {
|
||||
@@ -1115,18 +1184,114 @@ public class HqSatSurveyServiceImpl implements IHqSatSurveyService {
|
||||
if (record.get("submit_time") != null) {
|
||||
record.put("endTime", record.get("submit_time").toString());
|
||||
}
|
||||
|
||||
// 获取答题详情(仅对已提交的记录)
|
||||
if (hasSubmitted && record.get("id") != null) {
|
||||
Long recordId = Long.valueOf(record.get("id").toString());
|
||||
List<Map<String, Object>> answerDetails = getAnswersFromSatAnswerTable(recordId);
|
||||
|
||||
// 将答案与题目信息关联,组织成前端需要的格式
|
||||
List<Map<String, Object>> formattedAnswers = new ArrayList<>();
|
||||
Map<Long, List<Map<String, Object>>> questionAnswers = new HashMap<>();
|
||||
|
||||
// 先按题目ID分组答案
|
||||
for (Map<String, Object> answer : answerDetails) {
|
||||
Long questionId = Long.valueOf(answer.get("questionId").toString());
|
||||
|
||||
if (!questionAnswers.containsKey(questionId)) {
|
||||
questionAnswers.put(questionId, new ArrayList<>());
|
||||
}
|
||||
|
||||
questionAnswers.get(questionId).add(answer);
|
||||
}
|
||||
|
||||
// 为每个题目创建一个答案记录
|
||||
for (Long questionId : questionAnswers.keySet()) {
|
||||
List<Map<String, Object>> answers = questionAnswers.get(questionId);
|
||||
|
||||
// 获取题目基本信息
|
||||
Map<String, Object> questionInfo = questionsMap.get(questionId);
|
||||
if (questionInfo == null) continue;
|
||||
|
||||
Map<String, Object> formattedAnswer = new HashMap<>();
|
||||
formattedAnswer.put("id", questionId);
|
||||
formattedAnswer.put("questionId", questionId);
|
||||
formattedAnswer.put("questionTitle", questionInfo.get("question_title"));
|
||||
formattedAnswer.put("questionType", String.valueOf(questionInfo.get("question_type")));
|
||||
|
||||
// 设置分数(汇总所有选项的分数)
|
||||
double totalScore = 0;
|
||||
for (Map<String, Object> answer : answers) {
|
||||
String scoreStr = (String)answer.get("answerScore");
|
||||
if (scoreStr != null) {
|
||||
try {
|
||||
totalScore += Double.parseDouble(scoreStr);
|
||||
} catch (NumberFormatException e) {
|
||||
log.warn("解析答题分数失败: {}", scoreStr);
|
||||
}
|
||||
}
|
||||
}
|
||||
formattedAnswer.put("score", totalScore);
|
||||
|
||||
String questionType = (String)formattedAnswer.get("questionType");
|
||||
|
||||
// 处理问答题
|
||||
if ("3".equals(questionType)) {
|
||||
// 取第一个答案的值作为问答题答案
|
||||
if (!answers.isEmpty()) {
|
||||
formattedAnswer.put("answerValue", answers.get(0).get("remark"));
|
||||
}
|
||||
}
|
||||
// 处理单选题和多选题
|
||||
else if ("1".equals(questionType) || "2".equals(questionType)) {
|
||||
List<Map<String, Object>> options = new ArrayList<>();
|
||||
|
||||
// 获取所有选中的选项
|
||||
for (Map<String, Object> answer : answers) {
|
||||
// 只处理有选项ID的答案
|
||||
if (answer.get("optionId") != null) {
|
||||
Map<String, Object> option = new HashMap<>();
|
||||
log.info("answer-zlwu12: {}", answer);
|
||||
option.put("optionId", answer.get("optionId"));
|
||||
option.put("optionValue", answer.get("optionValue"));
|
||||
option.put("optionText", answer.get("optionText"));
|
||||
// option.put("optionScore", answer.get("answerScore"));
|
||||
option.put("isSelected", true);
|
||||
options.add(option);
|
||||
}
|
||||
}
|
||||
|
||||
formattedAnswer.put("options", options);
|
||||
|
||||
// 设置answerValue为所有选中选项值的拼接
|
||||
StringBuilder answerValue = new StringBuilder();
|
||||
for (Map<String, Object> option : options) {
|
||||
if (answerValue.length() > 0) {
|
||||
answerValue.append(",");
|
||||
}
|
||||
answerValue.append(option.get("optionValue"));
|
||||
}
|
||||
formattedAnswer.put("answerValue", answerValue.toString());
|
||||
}
|
||||
|
||||
formattedAnswers.add(formattedAnswer);
|
||||
}
|
||||
|
||||
// 将答题详情添加到记录中
|
||||
record.put("answers", formattedAnswers);
|
||||
}
|
||||
}
|
||||
|
||||
java.util.Map<String, Object> result = new java.util.HashMap<>();
|
||||
result.put("rows", records);
|
||||
result.put("total", total != null ? total : 0);
|
||||
|
||||
log.info("获取答题记录完成,总数: {}, 当前页: {}", total, records.size());
|
||||
log.info("获取符合问卷面向群体的所有用户信息完成,总数: {}, 当前页: {}", total, records.size());
|
||||
return result;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("获取答题记录失败,问卷ID: {}, 错误: {}", surveyId, e.getMessage(), e);
|
||||
throw new ServiceException("获取答题记录失败: " + e.getMessage());
|
||||
log.error("获取问卷用户记录失败,问卷ID: {}, 错误: {}", surveyId, e.getMessage(), e);
|
||||
throw new ServiceException("获取问卷用户记录失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1139,7 +1304,6 @@ public class HqSatSurveyServiceImpl implements IHqSatSurveyService {
|
||||
@Override
|
||||
public java.util.Map<String, Object> getAnswerRecordDetail(Long recordId) {
|
||||
log.info("获取答题记录详情,记录ID: {}", recordId);
|
||||
|
||||
try {
|
||||
// 查询答题记录基本信息
|
||||
String recordSql = "SELECT r.*, u.nick_name as userName, d.dept_name as deptName " +
|
||||
@@ -1147,57 +1311,107 @@ public class HqSatSurveyServiceImpl implements IHqSatSurveyService {
|
||||
"LEFT JOIN sys_user u ON r.user_id = u.user_id " +
|
||||
"LEFT JOIN sys_dept d ON u.dept_id = d.dept_id " +
|
||||
"WHERE r.id = ? AND r.deleted = 0";
|
||||
|
||||
java.util.List<java.util.Map<String, Object>> recordList = jdbcTemplate.queryForList(recordSql, recordId);
|
||||
if (recordList.isEmpty()) {
|
||||
throw new ServiceException("答题记录不存在", 404);
|
||||
}
|
||||
|
||||
java.util.Map<String, Object> record = recordList.get(0);
|
||||
|
||||
// 查询答题详情
|
||||
Long surveyId = record.get("survey_id") != null ? Long.valueOf(record.get("survey_id").toString()) : null;
|
||||
// 1. 获取问卷题目顺序
|
||||
List<HqSatSurveyQuestionVo> questionVos = surveyQuestionService.getSurveyQuestionsWithDetail(surveyId);
|
||||
// 题目顺序Map
|
||||
Map<Long, Integer> questionOrderMap = new HashMap<>();
|
||||
for (int i = 0; i < questionVos.size(); i++) {
|
||||
questionOrderMap.put(questionVos.get(i).getQuestionId(), i);
|
||||
}
|
||||
// 2. 查询所有选项顺序
|
||||
Map<Long, List<HqSatOptionVo>> questionOptionsMap = new HashMap<>();
|
||||
for (HqSatSurveyQuestionVo qvo : questionVos) {
|
||||
HqSatOptionBo bo = new HqSatOptionBo();
|
||||
bo.setQuestionId(qvo.getQuestionId());
|
||||
bo.setDeleted("0");
|
||||
List<HqSatOptionVo> options = optionService.queryList(bo);
|
||||
options.sort((a, b) -> {
|
||||
if (a.getOptionOrder() == null && b.getOptionOrder() == null) return 0;
|
||||
if (a.getOptionOrder() == null) return 1;
|
||||
if (b.getOptionOrder() == null) return -1;
|
||||
return a.getOptionOrder().compareTo(b.getOptionOrder());
|
||||
});
|
||||
questionOptionsMap.put(qvo.getQuestionId(), options);
|
||||
}
|
||||
// 3. 查询答题详情
|
||||
String answerSql = "SELECT a.question_id, a.question_type, a.answer_value, " +
|
||||
"a.option_id, a.option_value, a.option_text, a.answer_score, " +
|
||||
"a.option_id, a.option_value, a.option_text, a.answer_score, a.remark, " +
|
||||
"q.question_title " +
|
||||
"FROM hq_sat_answer a " +
|
||||
"LEFT JOIN hq_sat_question q ON a.question_id = q.id " +
|
||||
"WHERE a.record_id = ? AND a.deleted = 0 " +
|
||||
"ORDER BY a.question_id, a.option_id";
|
||||
|
||||
"WHERE a.record_id = ? AND a.deleted = 0 ";
|
||||
java.util.List<java.util.Map<String, Object>> answers = jdbcTemplate.queryForList(answerSql, recordId);
|
||||
|
||||
// 按题目分组答案
|
||||
java.util.Map<Long, java.util.Map<String, Object>> questionAnswerMap = new java.util.HashMap<>();
|
||||
for (java.util.Map<String, Object> answer : answers) {
|
||||
Long questionId = Long.valueOf(answer.get("question_id").toString());
|
||||
|
||||
if (!questionAnswerMap.containsKey(questionId)) {
|
||||
java.util.Map<String, Object> questionAnswer = new java.util.HashMap<>();
|
||||
questionAnswer.put("id", questionId);
|
||||
questionAnswer.put("questionId", questionId);
|
||||
questionAnswer.put("questionTitle", answer.get("question_title"));
|
||||
questionAnswer.put("questionType", answer.get("question_type"));
|
||||
questionAnswer.put("answerValue", answer.get("answer_value"));
|
||||
questionAnswer.put("score", answer.get("answer_score"));
|
||||
questionAnswer.put("options", new java.util.ArrayList<java.util.Map<String, Object>>());
|
||||
questionAnswerMap.put(questionId, questionAnswer);
|
||||
// 按题目分组
|
||||
Map<Long, List<Map<String, Object>>> answerGroup = new HashMap<>();
|
||||
for (Map<String, Object> answer : answers) {
|
||||
Long qid = Long.valueOf(answer.get("question_id").toString());
|
||||
answerGroup.computeIfAbsent(qid, k -> new ArrayList<>()).add(answer);
|
||||
}
|
||||
// 组装answers,按题目顺序
|
||||
List<Map<String, Object>> resultAnswers = new ArrayList<>();
|
||||
for (HqSatSurveyQuestionVo qvo : questionVos) {
|
||||
Long qid = qvo.getQuestionId();
|
||||
List<Map<String, Object>> answerList = answerGroup.getOrDefault(qid, new ArrayList<>());
|
||||
Map<String, Object> answerObj = new HashMap<>();
|
||||
answerObj.put("id", qid);
|
||||
answerObj.put("questionId", qid);
|
||||
answerObj.put("questionTitle", qvo.getQuestionTitle());
|
||||
answerObj.put("questionType", qvo.getQuestionType());
|
||||
double totalScore = 0;
|
||||
for (Map<String, Object> a : answerList) {
|
||||
Object scoreStr = a.get("answer_score");
|
||||
if (scoreStr != null) {
|
||||
try { totalScore += Double.parseDouble(scoreStr.toString()); } catch (Exception ignore) {}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果是选择题,添加选项信息
|
||||
if (answer.get("option_id") != null) {
|
||||
java.util.Map<String, Object> option = new java.util.HashMap<>();
|
||||
option.put("optionId", answer.get("option_id"));
|
||||
option.put("optionValue", answer.get("option_value"));
|
||||
option.put("optionText", answer.get("option_text"));
|
||||
option.put("isSelected", true); // 查询出来的都是已选择的选项
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
java.util.List<java.util.Map<String, Object>> options =
|
||||
(java.util.List<java.util.Map<String, Object>>) questionAnswerMap.get(questionId).get("options");
|
||||
options.add(option);
|
||||
answerObj.put("score", totalScore);
|
||||
// 问答题
|
||||
if ("3".equals(qvo.getQuestionType())) {
|
||||
String remark = answerList.isEmpty() ? "" : (answerList.get(0).get("remark") != null ? answerList.get(0).get("remark").toString() : "");
|
||||
answerObj.put("answerValue", remark);
|
||||
answerObj.put("options", new ArrayList<>());
|
||||
} else if ("1".equals(qvo.getQuestionType()) || "2".equals(qvo.getQuestionType())) {
|
||||
// 选择题,组装选项,按optionOrder排序
|
||||
List<HqSatOptionVo> allOptions = questionOptionsMap.getOrDefault(qid, new ArrayList<>());
|
||||
List<Map<String, Object>> options = new ArrayList<>();
|
||||
for (HqSatOptionVo opt : allOptions) {
|
||||
Map<String, Object> optMap = new HashMap<>();
|
||||
optMap.put("optionId", opt.getId());
|
||||
optMap.put("optionValue", opt.getOptionContent());
|
||||
optMap.put("optionText", opt.getOptionContent());
|
||||
optMap.put("optionScore", opt.getOptionScore());
|
||||
optMap.put("isSelected", false);
|
||||
// 检查是否被选中
|
||||
for (Map<String, Object> a : answerList) {
|
||||
if (a.get("option_id") != null && opt.getId().toString().equals(a.get("option_id").toString())) {
|
||||
optMap.put("isSelected", true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
options.add(optMap);
|
||||
}
|
||||
answerObj.put("options", options);
|
||||
// answerValue为所有选中optionValue的拼接
|
||||
StringBuilder answerValue = new StringBuilder();
|
||||
for (Map<String, Object> opt : options) {
|
||||
if (Boolean.TRUE.equals(opt.get("isSelected"))) {
|
||||
if (answerValue.length() > 0) answerValue.append(",");
|
||||
answerValue.append(opt.get("optionValue"));
|
||||
}
|
||||
}
|
||||
answerObj.put("answerValue", answerValue.toString());
|
||||
} else {
|
||||
answerObj.put("options", new ArrayList<>());
|
||||
answerObj.put("answerValue", "");
|
||||
}
|
||||
resultAnswers.add(answerObj);
|
||||
}
|
||||
|
||||
// 构建返回结果
|
||||
java.util.Map<String, Object> result = new java.util.HashMap<>();
|
||||
result.put("id", record.get("id"));
|
||||
@@ -1210,11 +1424,9 @@ public class HqSatSurveyServiceImpl implements IHqSatSurveyService {
|
||||
result.put("duration", 300 + (int)(Math.random() * 600)); // 暂时使用随机值
|
||||
result.put("totalScore", record.get("total_score"));
|
||||
result.put("status", record.get("submit_time") != null ? "1" : "0");
|
||||
result.put("answers", new java.util.ArrayList<>(questionAnswerMap.values()));
|
||||
|
||||
log.info("获取答题记录详情完成,记录ID: {}, 答案数量: {}", recordId, questionAnswerMap.size());
|
||||
result.put("answers", resultAnswers);
|
||||
log.info("获取答题记录详情完成,记录ID: {}, 答案数量: {}", recordId, resultAnswers.size());
|
||||
return result;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("获取答题记录详情失败,记录ID: {}, 错误: {}", recordId, e.getMessage(), e);
|
||||
throw new ServiceException("获取答题记录详情失败: " + e.getMessage());
|
||||
|
||||
@@ -450,6 +450,8 @@ await Promise.all(promises);
|
||||
| 1.0.1 | 2025-07-17 | 优化题目选项获取接口,增强前端题目选项显示功能 | Cursor |
|
||||
| 1.0.2 | 2025-07-17 | 修复选项排序值保存后实时更新功能,优化用户体验 | wuzilong |
|
||||
| 1.0.3 | 2025-07-17 | 添加选项保存防重复提交机制,解决幂等性控制冲突 | wuzilong |
|
||||
| 1.0.4 | 2025-07-18 | 优化问答题文本回答展示功能,提高Vue渲染稳定性 | wuzilong |
|
||||
| 1.0.5 | 2025-07-18 | 增强问卷答题记录接口功能,返回答题详情数据 | wuzilong |
|
||||
|
||||
## 附录
|
||||
|
||||
@@ -465,7 +467,207 @@ await Promise.all(promises);
|
||||
- 总分(total_score) = 所有题目的得分之和
|
||||
- 平均分(avg_score) = 总分 ÷ 有分值的题目数量(不包括问答题)
|
||||
|
||||
### 问答题文本回答数据结构
|
||||
|
||||
**统计分析接口中问答题文本回答数据结构**:
|
||||
|
||||
问卷统计分析接口(`/hq/satSurvey/{id}/statistics`)返回的问答题文本回答数据结构如下:
|
||||
|
||||
```json
|
||||
"textAnswers": [
|
||||
{
|
||||
"id": 393,
|
||||
"answer_text": "用户回答内容示例",
|
||||
"text_length": 12,
|
||||
"answer_time": "2025-07-18 10:40:35"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
**字段说明**:
|
||||
|
||||
| 字段名 | 类型 | 描述 |
|
||||
|-------|-----|------|
|
||||
| id | Integer | 回答ID,唯一标识 |
|
||||
| answer_text | String | 回答文本内容 |
|
||||
| text_length | Integer | 文本长度(字符数) |
|
||||
| answer_time | String | 回答时间,格式:yyyy-MM-dd HH:mm:ss |
|
||||
|
||||
**前端使用注意事项**:
|
||||
- 在Vue循环渲染textAnswers数组时,应使用answer.id作为key值,而非索引,确保Vue的虚拟DOM正确更新
|
||||
- 示例:`<div v-for="(answer, idx) in question.textAnswers.slice(0, 5)" :key="answer.id || idx" class="answer-item">`
|
||||
- 2025-07-18修复:解决了文本回答因key不唯一导致的渲染问题,详见`docs/变更管理/code-adjust-record-2025-07-18-wuzilong.md`
|
||||
|
||||
#### 2025-07-18 接口返回顺序与问答题答案优化
|
||||
|
||||
- `/hq/satSurvey/record/{recordId}` 接口返回参数调整:
|
||||
1. `answers` 数组顺序严格按照问卷题目顺序返回。
|
||||
2. `answers.options` 选项数组顺序严格按照题目原始选项顺序返回。
|
||||
3. 问答题(`questionType=3`)的 `answerValue` 字段取自 `remark` 字段,真实还原用户填写内容。
|
||||
|
||||
> 以上调整保证了前端展示与问卷设计一致,提升了数据准确性。
|
||||
|
||||
### 获取问卷的所有答题记录列表
|
||||
|
||||
**请求方式**:GET
|
||||
|
||||
**请求路径**:`/hq/satSurvey/{surveyId}/records`
|
||||
|
||||
**请求参数**:
|
||||
|
||||
| 参数名 | 类型 | 必填 | 描述 |
|
||||
|-------|-----|------|------|
|
||||
| surveyId | Long | 是 | 问卷ID,路径参数 |
|
||||
| status | String | 否 | 答题状态(1-已提交,0-未提交) |
|
||||
| userName | String | 否 | 用户姓名,模糊查询 |
|
||||
| dateRange | String[] | 否 | 日期范围 |
|
||||
| pageNum | Integer | 否 | 页码,默认1 |
|
||||
| pageSize | Integer | 否 | 每页条数,默认10 |
|
||||
|
||||
**请求示例**:
|
||||
```
|
||||
GET /hq/satSurvey/1945836064483778562/records?pageNum=1&pageSize=10&surveyId=1945836064483778562
|
||||
```
|
||||
|
||||
**响应示例**:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功",
|
||||
"data": {
|
||||
"total": 5,
|
||||
"rows": [
|
||||
{
|
||||
"user_id": 2008,
|
||||
"userName": "智控学院郑十",
|
||||
"deptName": "智能控制学院",
|
||||
"id": "1946035501017587714",
|
||||
"survey_id": "1945836064483778562",
|
||||
"submit_time": "2025-07-18 10:33:14",
|
||||
"total_score": "24.00",
|
||||
"create_time": "2025-07-18 10:33:14",
|
||||
"status": "1",
|
||||
"duration": 313,
|
||||
"startTime": "2025-07-18T10:33:14",
|
||||
"endTime": "2025-07-18T10:33:14",
|
||||
"answers": [
|
||||
{
|
||||
"id": 1945836064483778563,
|
||||
"questionId": 1945836064483778563,
|
||||
"questionTitle": "您对后勤服务总体满意度如何?",
|
||||
"questionType": "1",
|
||||
"score": 4.0,
|
||||
"answerValue": "B",
|
||||
"options": [
|
||||
{
|
||||
"optionId": 1945836064483778569,
|
||||
"optionValue": "B",
|
||||
"optionText": "满意",
|
||||
"isSelected": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 1945836064483778564,
|
||||
"questionId": 1945836064483778564,
|
||||
"questionTitle": "您认为校园环境有哪些需要改善的地方?",
|
||||
"questionType": "2",
|
||||
"score": 11.0,
|
||||
"answerValue": "A,C,D",
|
||||
"options": [
|
||||
{
|
||||
"optionId": 1945836064483778570,
|
||||
"optionValue": "A",
|
||||
"optionText": "绿化维护",
|
||||
"isSelected": true
|
||||
},
|
||||
{
|
||||
"optionId": 1945836064483778572,
|
||||
"optionValue": "C",
|
||||
"optionText": "卫生状况",
|
||||
"isSelected": true
|
||||
},
|
||||
{
|
||||
"optionId": 1945836064483778573,
|
||||
"optionValue": "D",
|
||||
"optionText": "基础设施",
|
||||
"isSelected": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 1945836064483778565,
|
||||
"questionId": 1945836064483778565,
|
||||
"questionTitle": "您对校园后勤服务的建议",
|
||||
"questionType": "3",
|
||||
"score": 0,
|
||||
"answerValue": "希望增加自习室的开放时间,目前晚上关门太早"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"user_id": 4,
|
||||
"userName": "仅本人 密码666666",
|
||||
"deptName": "行政单位",
|
||||
"id": null,
|
||||
"survey_id": null,
|
||||
"submit_time": null,
|
||||
"total_score": 0,
|
||||
"create_time": null,
|
||||
"status": "0",
|
||||
"duration": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**特殊说明**:
|
||||
1. **功能强化(2025-07-18)**:接口现在返回已提交记录的答题详情(`answers`字段),无需额外请求
|
||||
2. 每条记录(已提交状态)包含完整的答题详情数据,包括:
|
||||
- 题目信息:`questionId`、`questionTitle`、`questionType`
|
||||
- 答案内容:`score`、`answerValue`
|
||||
- 选项数据(单选/多选题):`options`数组,包含所有选中的选项
|
||||
3. 问题类型(`questionType`):
|
||||
- `1`:单选题
|
||||
- `2`:多选题
|
||||
- `3`:问答题
|
||||
4. 未提交的记录(`status="0"`)不包含答题详情
|
||||
|
||||
**最佳实践**:
|
||||
- 前端可直接使用返回的`answers`数据渲染答题详情,无需额外请求
|
||||
- 单选题和多选题显示选项,问答题显示文本内容
|
||||
|
||||
### 相关文件
|
||||
|
||||
- 数据库表结构:`docs/设计文档/database/hzdyjs_xg.sql`
|
||||
- 变更记录:`docs/变更管理/code-adjust-record-2025-07-01-cursor.md`
|
||||
- 文本回答展示修复:`docs/变更管理/code-adjust-record-2025-07-18-wuzilong.md`
|
||||
- 答题详情功能优化:`docs/变更管理/code-adjust-record-2025-07-18-wuzilong.md`
|
||||
|
||||
## FAQ 常见问题解答
|
||||
|
||||
### 1. 问卷答题记录查询报错 "Unknown column 'u.deleted' in 'where clause'"
|
||||
|
||||
**问题描述**:
|
||||
获取问卷答题记录列表时报错:`java.sql.SQLSyntaxErrorException: Unknown column 'u.deleted' in 'where clause'`
|
||||
|
||||
**原因分析**:
|
||||
在SQL查询中使用了 `u.deleted = 0` 条件,但实际上 `sys_user` 表中逻辑删除字段名是 `del_flag` 而非 `deleted`。这是系统表与业务表之间的字段命名差异导致的。
|
||||
|
||||
**解决方案**:
|
||||
修改SQL查询,将 `WHERE u.deleted = 0` 改为 `WHERE u.del_flag = '0'`(注意类型也从数字改为了字符串)。
|
||||
|
||||
**相关代码**:
|
||||
```java
|
||||
// 修改前
|
||||
sql.append("WHERE u.deleted = 0 ");
|
||||
|
||||
// 修改后
|
||||
sql.append("WHERE u.del_flag = '0' ");
|
||||
```
|
||||
|
||||
**注意事项**:
|
||||
- 系统表(如sys_user, sys_role等)使用 `del_flag` 作为逻辑删除字段,类型为char(1)
|
||||
- 业务表(如hq_sat_survey等)使用 `deleted` 作为逻辑删除字段,类型为tinyint(1)
|
||||
- 在跨表关联查询时,务必注意这一差异,避免类似错误
|
||||
@@ -526,6 +526,7 @@ export interface SatAnswerVO {
|
||||
optionValue: string;
|
||||
optionText: string;
|
||||
isSelected: boolean;
|
||||
optionScore: string | number;
|
||||
}>;
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,11 @@ html.dark svg {
|
||||
|
||||
#app .sidebar-container .sub-menu-title-noDropdown,
|
||||
#app .sidebar-container .el-sub-menu__title {
|
||||
margin: 0px 8px 0 0 !important;
|
||||
margin: 0px 0px 0 0 !important;
|
||||
}
|
||||
|
||||
#app .sidebar-container .nest-menu .el-sub-menu > .el-sub-menu__title, #app .sidebar-container .el-sub-menu .el-menu-item{
|
||||
margin: 0px 0px 0 0 !important;
|
||||
}
|
||||
|
||||
*,
|
||||
|
||||
@@ -235,7 +235,7 @@
|
||||
// 嵌套菜单项样式
|
||||
.nest-menu .el-sub-menu > .el-sub-menu__title,
|
||||
.el-sub-menu .el-menu-item {
|
||||
max-width: calc(100% - 16px) !important;
|
||||
max-width: calc(100%) !important;
|
||||
width: auto !important;
|
||||
border-radius: var(--border-radius-xs) !important;
|
||||
margin: 1px 8px !important;
|
||||
|
||||
Reference in new issue
Block a user