|
|
@@ -256,6 +256,7 @@
|
|
|
:key="option.id || index"
|
|
|
:label="String.fromCharCode(65 + index)"
|
|
|
class="answer-option-horizontal"
|
|
|
+ :class="{ 'is-checked': question.userAnswer === String.fromCharCode(65 + index) }"
|
|
|
>
|
|
|
{{ String.fromCharCode(65 + index) }}.
|
|
|
{{ option.optionContent || option.optionText || option.text || option.content || `选项${index + 1}` }}
|
|
|
@@ -274,6 +275,7 @@
|
|
|
:key="option.id || index"
|
|
|
:label="String.fromCharCode(65 + index)"
|
|
|
class="answer-option-horizontal"
|
|
|
+ :class="{ 'is-checked': Array.isArray(question.userAnswer) && question.userAnswer.includes(String.fromCharCode(65 + index)) }"
|
|
|
>
|
|
|
{{ String.fromCharCode(65 + index) }}.
|
|
|
{{ option.optionContent || option.optionText || option.text || option.content || `选项${index + 1}` }}
|
|
|
@@ -289,7 +291,11 @@
|
|
|
placeholder="请输入答案..."
|
|
|
disabled
|
|
|
class="answer-textarea"
|
|
|
- />
|
|
|
+ >
|
|
|
+ <template #append v-if="question.userAnswer && question.userAnswer.trim()">
|
|
|
+ <el-tag size="small" type="success">已作答</el-tag>
|
|
|
+ </template>
|
|
|
+ </el-input>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -1016,14 +1022,35 @@ const loadPreviousAnswers = async (surveyId: string | number, formData: Record<s
|
|
|
// 从remark字段中提取JSON字符串并解析
|
|
|
const jsonStr = userData.remark.split('ANSWERS_DATA:')[1];
|
|
|
|
|
|
+ // 修复方式1:先用正则表达式提取所有questionId,以便后续修复
|
|
|
+ const idMatches = jsonStr.match(/"questionId":(\d+)/g);
|
|
|
+ const originalIds = idMatches ? idMatches.map((match) => match.split(':')[1]) : [];
|
|
|
+
|
|
|
+ console.log('从JSON字符串中提取的原始questionId列表:', originalIds);
|
|
|
+
|
|
|
// 使用 JSON.parse 时配合 reviver 函数处理大整数
|
|
|
- answersData = JSON.parse(jsonStr, (key, value) => {
|
|
|
- // 如果是 questionId 字段,确保作为字符串处理
|
|
|
- if (key === 'questionId' && typeof value === 'number') {
|
|
|
- return String(value);
|
|
|
- }
|
|
|
- return value;
|
|
|
- });
|
|
|
+ answersData = JSON.parse(jsonStr);
|
|
|
+
|
|
|
+ // 解析后直接使用提取的原始ID进行修复
|
|
|
+ if (originalIds.length === answersData.length) {
|
|
|
+ console.log('使用提取的原始ID进行修复,数量匹配');
|
|
|
+ answersData.forEach((answer, index) => {
|
|
|
+ if (index < originalIds.length) {
|
|
|
+ // 始终将ID作为字符串处理,避免精度丢失
|
|
|
+ answer.questionId = String(originalIds[index]);
|
|
|
+ console.log(`修复第 ${index + 1} 条数据的 questionId: ${answer.questionId}`);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ console.warn('ID数量不匹配,尝试其他修复方式');
|
|
|
+
|
|
|
+ // 备选修复方法:确保所有questionId都是字符串类型
|
|
|
+ answersData.forEach((answer) => {
|
|
|
+ if (answer.questionId) {
|
|
|
+ answer.questionId = String(answer.questionId);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
|
|
|
console.log('成功解析历史答题数据:', answersData);
|
|
|
|
|
|
@@ -1031,30 +1058,6 @@ const loadPreviousAnswers = async (surveyId: string | number, formData: Record<s
|
|
|
const uniqueIds = new Set(answersData.map((a) => a.questionId));
|
|
|
console.log('解析后唯一的 questionId 数量:', uniqueIds.size);
|
|
|
console.log('唯一的 questionId 列表:', Array.from(uniqueIds));
|
|
|
-
|
|
|
- // 如果所有 questionId 都变成相同的,尝试手动修复
|
|
|
- if (uniqueIds.size === 1 && answersData.length > 1) {
|
|
|
- console.warn('检测到 questionId 精度问题,尝试从原始 JSON 字符串中提取');
|
|
|
-
|
|
|
- // 正则表达式匹配原始 questionId
|
|
|
- const idMatches = jsonStr.match(/"questionId":(\d+)/g);
|
|
|
- if (idMatches && idMatches.length === answersData.length) {
|
|
|
- console.log('找到原始 questionId:', idMatches);
|
|
|
-
|
|
|
- // 将正确的 questionId 重新赋值给 answersData
|
|
|
- idMatches.forEach((match, index) => {
|
|
|
- if (index < answersData.length) {
|
|
|
- const originalId = match.split(':')[1];
|
|
|
- answersData[index].questionId = originalId;
|
|
|
- console.log(`修复第 ${index + 1} 条数据的 questionId: ${originalId}`);
|
|
|
- }
|
|
|
- });
|
|
|
-
|
|
|
- // 再次检查唯一 ID
|
|
|
- const fixedUniqueIds = new Set(answersData.map((a) => a.questionId));
|
|
|
- console.log('修复后唯一的 questionId 数量:', fixedUniqueIds.size);
|
|
|
- }
|
|
|
- }
|
|
|
} catch (error) {
|
|
|
console.error('解析ANSWERS_DATA失败:', error);
|
|
|
return false;
|
|
|
@@ -1310,7 +1313,7 @@ const submitAnswer = async () => {
|
|
|
|
|
|
// 遍历所有答题数据,构造答案列表
|
|
|
for (const question of answerQuestions.value) {
|
|
|
- const questionId = question.questionId || question.id;
|
|
|
+ const questionId = String(question.questionId || question.id); // 确保questionId是字符串类型
|
|
|
const questionType = String(question.questionType);
|
|
|
const userAnswer = answerForm.value[questionId];
|
|
|
|
|
|
@@ -1358,7 +1361,7 @@ const submitAnswer = async () => {
|
|
|
const optionLetter = String.fromCharCode(65 + optionIndex); // A, B, C, D...
|
|
|
|
|
|
const answerItem: SubmitAnswerItem = {
|
|
|
- questionId: questionId,
|
|
|
+ questionId: String(questionId), // 确保questionId是字符串类型
|
|
|
questionType: questionType,
|
|
|
answerValue: '', // 不再使用answerValue字段
|
|
|
optionId: selectedOption.id || selectedOption.optionId, // 确保有选项ID
|
|
|
@@ -1409,7 +1412,7 @@ const submitAnswer = async () => {
|
|
|
|
|
|
// 创建单独的答案记录
|
|
|
const answerItem: SubmitAnswerItem = {
|
|
|
- questionId: questionId,
|
|
|
+ questionId: String(questionId), // 确保questionId是字符串类型
|
|
|
questionType: questionType,
|
|
|
answerValue: '', // 不再使用answerValue字段
|
|
|
optionId: selectedOption.id || selectedOption.optionId, // 确保有选项ID
|
|
|
@@ -1436,7 +1439,7 @@ const submitAnswer = async () => {
|
|
|
const answerText = userAnswer != null ? String(userAnswer) : '';
|
|
|
|
|
|
const answerItem: SubmitAnswerItem = {
|
|
|
- questionId: questionId,
|
|
|
+ questionId: String(questionId), // 确保questionId是字符串类型
|
|
|
questionType: questionType,
|
|
|
answerValue: '', // 不再使用answerValue字段
|
|
|
optionId: null, // 问答题没有选项ID
|
|
|
@@ -1506,13 +1509,30 @@ const loadQuestionData = async () => {
|
|
|
if (readonly.value) {
|
|
|
console.log('只读模式:尝试加载用户答题记录...');
|
|
|
try {
|
|
|
+ // 与答题按钮功能保持一致,使用同一个API获取历史答题记录
|
|
|
userAnswerRes = await getUserSurveyAnswer(currentSurvey.value!.id);
|
|
|
- console.log('✅ 成功加载用户答题记录');
|
|
|
+ console.log('✅ 成功加载用户答题记录:', userAnswerRes);
|
|
|
+
|
|
|
+ // 检查API返回数据,判断是否包含历史答题记录
|
|
|
+ if (userAnswerRes && userAnswerRes.code === 200 && userAnswerRes.data) {
|
|
|
+ console.log('✅ 获取到历史答题数据成功');
|
|
|
+ } else {
|
|
|
+ console.log('⚠️ API返回成功但无历史答题数据');
|
|
|
+ }
|
|
|
} catch (error) {
|
|
|
+ // 处理API请求失败的情况
|
|
|
if ((error as any)?.response?.status === 404) {
|
|
|
console.log('ℹ️ 用户尚未回答此问卷,将显示空白题目');
|
|
|
} else {
|
|
|
console.warn('⚠️ 加载用户答题记录失败,将显示空白题目:', error);
|
|
|
+
|
|
|
+ // 调试输出完整错误信息
|
|
|
+ if (error && typeof error === 'object') {
|
|
|
+ const err = error as any;
|
|
|
+ console.error('错误详情:', err.response?.data || err.message || String(error));
|
|
|
+ } else {
|
|
|
+ console.error('错误详情:', String(error));
|
|
|
+ }
|
|
|
}
|
|
|
userAnswerRes = null; // 确保为null,后续逻辑会处理
|
|
|
}
|
|
|
@@ -1537,8 +1557,56 @@ const loadQuestionData = async () => {
|
|
|
console.log('查看模式-答题明细样例:', userAnswers.details[0]);
|
|
|
} else {
|
|
|
console.log('查看模式-未找到有效的答题明细数据');
|
|
|
- // 确保details属性存在
|
|
|
- userAnswers.details = [];
|
|
|
+
|
|
|
+ // 检查是否存在remark字段并尝试从中提取答题数据(与loadPreviousAnswers一致)
|
|
|
+ if (userAnswers.remark && userAnswers.remark.includes('ANSWERS_DATA:')) {
|
|
|
+ try {
|
|
|
+ // 从remark字段中提取JSON字符串并解析
|
|
|
+ const jsonStr = userAnswers.remark.split('ANSWERS_DATA:')[1];
|
|
|
+ console.log('查看模式-找到ANSWERS_DATA,尝试解析:', jsonStr);
|
|
|
+
|
|
|
+ // 修复方式1:先用正则表达式提取所有questionId,以便后续修复
|
|
|
+ const idMatches = jsonStr.match(/"questionId":(\d+)/g);
|
|
|
+ const originalIds = idMatches ? idMatches.map((match) => match.split(':')[1]) : [];
|
|
|
+
|
|
|
+ console.log('从JSON字符串中提取的原始questionId列表:', originalIds);
|
|
|
+
|
|
|
+ // 使用 JSON.parse 时配合 reviver 函数处理大整数
|
|
|
+ const answersData = JSON.parse(jsonStr);
|
|
|
+
|
|
|
+ // 解析后直接使用提取的原始ID进行修复
|
|
|
+ if (originalIds.length === answersData.length) {
|
|
|
+ console.log('使用提取的原始ID进行修复,数量匹配');
|
|
|
+ answersData.forEach((answer, index) => {
|
|
|
+ if (index < originalIds.length) {
|
|
|
+ // 始终将ID作为字符串处理,避免精度丢失
|
|
|
+ answer.questionId = String(originalIds[index]);
|
|
|
+ console.log(`修复第 ${index + 1} 条数据的 questionId: ${answer.questionId}`);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ console.warn('ID数量不匹配,尝试其他修复方式');
|
|
|
+
|
|
|
+ // 备选修复方法:确保所有questionId都是字符串类型
|
|
|
+ answersData.forEach((answer) => {
|
|
|
+ if (answer.questionId) {
|
|
|
+ answer.questionId = String(answer.questionId);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ console.log('成功解析历史答题数据:', answersData);
|
|
|
+
|
|
|
+ // 将答题数据转换为details格式,方便后续处理
|
|
|
+ userAnswers.details = answersData;
|
|
|
+ console.log('查看模式-转换后的答题明细数据:', userAnswers.details.length, '条记录');
|
|
|
+ } catch (error) {
|
|
|
+ console.error('解析ANSWERS_DATA失败:', error);
|
|
|
+ userAnswers.details = [];
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ userAnswers.details = [];
|
|
|
+ }
|
|
|
}
|
|
|
} else {
|
|
|
console.log('ℹ️ 查看模式-用户尚未回答此问卷,显示空白题目');
|
|
|
@@ -1603,13 +1671,28 @@ const loadQuestionData = async () => {
|
|
|
if (question.questionType === '1' || question.questionType === 1) {
|
|
|
// 单选题:设置选中的选项值
|
|
|
const detail = questionAnswers[0];
|
|
|
- question.userAnswer = String(detail.answerScore || detail.answer_score || '');
|
|
|
+ // 使用answerScore作为答案标识,确保类型匹配
|
|
|
+ const answerScore = detail.answerScore || detail.answer_score || 0;
|
|
|
+ question.userAnswer = String.fromCharCode(
|
|
|
+ 65 +
|
|
|
+ question.options.findIndex(
|
|
|
+ (opt) =>
|
|
|
+ Number(opt.optionScore) === Number(answerScore) || (opt.score !== undefined && Number(opt.score) === Number(answerScore))
|
|
|
+ )
|
|
|
+ );
|
|
|
console.log(`✅ 查看模式-单选题${questionId}用户答案:`, question.userAnswer);
|
|
|
} else if (question.questionType === '2' || question.questionType === 2) {
|
|
|
- // 多选题:从多条记录中收集选项值
|
|
|
+ // 多选题:从多条记录中收集选项值并转换为字母标识
|
|
|
question.userAnswer = questionAnswers
|
|
|
- .map((detail) => String(detail.answerScore || detail.answer_score || ''))
|
|
|
- .filter((val) => val !== null && val !== undefined && val !== '');
|
|
|
+ .map((detail) => {
|
|
|
+ const answerScore = detail.answerScore || detail.answer_score || 0;
|
|
|
+ const optionIndex = question.options.findIndex(
|
|
|
+ (opt) =>
|
|
|
+ Number(opt.optionScore) === Number(answerScore) || (opt.score !== undefined && Number(opt.score) === Number(answerScore))
|
|
|
+ );
|
|
|
+ return optionIndex >= 0 ? String.fromCharCode(65 + optionIndex) : '';
|
|
|
+ })
|
|
|
+ .filter((val) => val !== '');
|
|
|
console.log(`✅ 查看模式-多选题${questionId}用户答案:`, question.userAnswer);
|
|
|
} else if (question.questionType === '3' || question.questionType === 3) {
|
|
|
// 问答题:从remark字段获取文本答案
|