diff --git a/src/views/survey/components/SurveyResultsDialog.vue b/src/views/survey/components/SurveyResultsDialog.vue index e2faad0..94b4194 100644 --- a/src/views/survey/components/SurveyResultsDialog.vue +++ b/src/views/survey/components/SurveyResultsDialog.vue @@ -264,16 +264,25 @@
- -
- {{ getAnswerForQuestion(q.id) || '未填写' }} + +
+
+ {{ opt.value || opt.key }} + 已选 +
- -
- - {{ getAnswerForQuestion(q.id).join('、') || '未填写' }} - - {{ getAnswerForQuestion(q.id) || '未填写' }} + +
+
+ {{ opt.value || opt.key }} + 已选 +
@@ -406,16 +415,17 @@ export default { async viewResponseDetail(response) { this.responsesLoading = true try { - // 获取详情 const res = await formResponseShow({ id: response.id, show_relation: ['user'] - }) - - this.currentResponse = res || response - // 解析答案数据 + }, false) + // 表单记录含 user,答案为 data。若后端返回 { data: record } 则取 res.data + const record = (res && res.user) ? res : ((res && res.data && res.data.user) ? res.data : (res || response)) + this.currentResponse = record this.parseResponseAnswers(this.currentResponse) - this.detailDialogVisible = true + this.$nextTick(() => { + this.detailDialogVisible = true + }) } catch (error) { console.error('获取回复详情失败:', error) this.$message.error('获取回复详情失败,请重试') @@ -433,7 +443,6 @@ export default { let answerData = null try { - // 尝试解析 JSON 字符串 if (typeof response.data === 'string') { answerData = JSON.parse(response.data) } else { @@ -448,22 +457,44 @@ export default { return } - // 将答案数据转换为以题目ID为键的对象 + // 若 API 返回的是题目数组,转为 id -> 答案 的映射 + let dataByQId = {} + if (Array.isArray(answerData)) { + answerData.forEach(item => { + if (item && item.id != null) { + dataByQId[item.id] = item + } + }) + } else { + dataByQId = answerData + } + + // 提取答案值:API 可能返回完整题目对象 { id, name, value, select_item... },需取 value + const extractAnswer = (raw, q) => { + if (raw === undefined || raw === null) return null + // 若为完整题目对象(含 value 且含 edit_input/select_item),取 value + if (typeof raw === 'object' && raw.value !== undefined && (raw.edit_input || raw.select_item)) { + return raw.value + } + return raw + } + this.questions.forEach(q => { - if (answerData[q.id] !== undefined && answerData[q.id] !== null) { - // 如果是多维度题目,需要特殊处理 + const raw = dataByQId[q.id] + if (raw !== undefined && raw !== null) { if (q.edit_input === 'multi_dimension') { - let dimensionValue = answerData[q.id] + let dimensionValue = raw + if (typeof raw === 'object' && raw.value !== undefined && (raw.edit_input || raw.select_item)) { + dimensionValue = raw.value + } if (typeof dimensionValue === 'string') { try { dimensionValue = JSON.parse(dimensionValue) - } catch (e) { - console.error('解析多维度答案失败:', e) - } + } catch (e) {} } - this.$set(this.responseAnswers, q.id, dimensionValue || {}) + this.$set(this.responseAnswers, q.id, dimensionValue && typeof dimensionValue === 'object' ? dimensionValue : {}) } else { - this.$set(this.responseAnswers, q.id, answerData[q.id]) + this.$set(this.responseAnswers, q.id, extractAnswer(raw, q)) } } }) @@ -471,6 +502,19 @@ export default { getAnswerForQuestion(questionId) { return this.responseAnswers[questionId] !== undefined ? this.responseAnswers[questionId] : null }, + isOptionSelected(questionId, opt, type) { + const ans = this.getAnswerForQuestion(questionId) + if (ans == null) return false + const optVal = opt.value || opt.key || '' + if (type === 'radio') { + return String(ans).trim() === String(optVal).trim() + } + if (type === 'checkbox') { + const selected = Array.isArray(ans) ? ans : (typeof ans === 'string' ? ans.split(/[,,]/).map(s => s.trim()) : []) + return selected.some(v => String(v).trim() === String(optVal).trim()) + } + return false + }, getQuestionTypeText(type) { const typeMap = { 'radio': '单选题', @@ -794,6 +838,36 @@ export default { color: #303133; } +.options-list { + display: flex; + flex-direction: column; + gap: 8px; +} + +.option-item { + display: flex; + align-items: center; + justify-content: space-between; + padding: 8px 12px; + border-radius: 6px; + background: #f5f7fa; + font-size: 14px; +} + +.option-item.option-selected { + background: #ecf5ff; + border-left: 3px solid #409eff; +} + +.option-label { + color: #303133; +} + +.option-check { + color: #409eff; + font-size: 13px; +} + .answer-empty { color: #c0c4cc; font-style: italic;