Selaa lähdekoodia

1、调整答题参数

yys 4 päivää sitten
vanhempi
commit
d51128850e

+ 11 - 2
fs-service/src/main/java/com/fs/live/param/LiveCompletionCouponAnswerItem.java

@@ -13,8 +13,17 @@ public class LiveCompletionCouponAnswerItem {
 
     /**
      * 用户答案
-     * 单选:如 A
-     * 多选:如 A,B 或 JSON 数组字符串 ["A","B"]
+     * 单选:选项文案,如「一斤半」
+     * 多选:JSON 数组字符串,如 ["A","B"]
      */
     private String answer;
+
+    /** 选项下标(App 扁平提交时使用) */
+    private Integer answerIndex;
+
+    /** 选项文案(App 扁平提交时使用,优先于 answer) */
+    private String answerName;
+
+    /** 是否为用户选中项:1 是 0 否(App 扁平提交时使用) */
+    private Integer isAnswer;
 }

+ 77 - 1
fs-service/src/main/java/com/fs/live/service/impl/LiveCompletionCouponServiceImpl.java

@@ -212,7 +212,8 @@ public class LiveCompletionCouponServiceImpl implements ILiveCompletionCouponSer
             throw new BaseException("未配置今日问题");
         }
 
-        boolean allCorrect = evaluateAnswers(param.getAnswers(), configuredQuestionIds);
+        List<LiveCompletionCouponAnswerItem> normalizedAnswers = normalizeUserAnswers(param.getAnswers());
+        boolean allCorrect = evaluateAnswers(normalizedAnswers, configuredQuestionIds);
         saveAnswerRecordToday(liveId, userId, allCorrect);
 
         LiveCompletionCouponAnswerResult result = new LiveCompletionCouponAnswerResult();
@@ -255,6 +256,81 @@ public class LiveCompletionCouponServiceImpl implements ILiveCompletionCouponSer
         return couponUser;
     }
 
+    /**
+     * 将 App 扁平选项格式归一为每题一条作答记录。
+     * <p>App 可能按「每个选项一条」提交(含 answerIndex / answerName / isAnswer),
+     * 而题库答案按选项文案存储,需合并后再校验。</p>
+     */
+    private List<LiveCompletionCouponAnswerItem> normalizeUserAnswers(List<LiveCompletionCouponAnswerItem> rawAnswers) {
+        if (rawAnswers == null || rawAnswers.isEmpty()) {
+            return Collections.emptyList();
+        }
+
+        boolean flatOptionFormat = rawAnswers.stream().anyMatch(a -> a.getIsAnswer() != null)
+                || rawAnswers.stream()
+                .filter(a -> a.getQuestionId() != null)
+                .collect(Collectors.groupingBy(LiveCompletionCouponAnswerItem::getQuestionId))
+                .values().stream().anyMatch(list -> list.size() > 1);
+        if (!flatOptionFormat) {
+            return rawAnswers;
+        }
+
+        Map<Long, List<LiveCompletionCouponAnswerItem>> grouped = rawAnswers.stream()
+                .filter(a -> a.getQuestionId() != null)
+                .collect(Collectors.groupingBy(LiveCompletionCouponAnswerItem::getQuestionId));
+
+        List<Long> questionIds = new ArrayList<>(grouped.keySet());
+        Map<Long, LiveQuestionBank> questionMap = liveQuestionBankMapper.selectLiveQuestionBankByIds(questionIds)
+                .stream()
+                .collect(Collectors.toMap(LiveQuestionBank::getId, q -> q, (a, b) -> a));
+
+        List<LiveCompletionCouponAnswerItem> normalized = new ArrayList<>();
+        for (Map.Entry<Long, List<LiveCompletionCouponAnswerItem>> entry : grouped.entrySet()) {
+            Long questionId = entry.getKey();
+            List<LiveCompletionCouponAnswerItem> options = entry.getValue();
+
+            List<LiveCompletionCouponAnswerItem> selected = options.stream()
+                    .filter(a -> a.getIsAnswer() != null && a.getIsAnswer() == 1)
+                    .collect(Collectors.toList());
+
+            LiveCompletionCouponAnswerItem item = new LiveCompletionCouponAnswerItem();
+            item.setQuestionId(questionId);
+
+            if (selected.isEmpty()) {
+                if (options.size() == 1) {
+                    item.setAnswer(resolveAnswerText(options.get(0)));
+                    normalized.add(item);
+                }
+                continue;
+            }
+
+            LiveQuestionBank question = questionMap.get(questionId);
+            boolean multiChoice = question != null && question.getType() != null && question.getType() == 2L;
+
+            if (multiChoice) {
+                List<String> names = selected.stream()
+                        .map(this::resolveAnswerText)
+                        .filter(StringUtils::isNotEmpty)
+                        .collect(Collectors.toList());
+                item.setAnswer(JSON.toJSONString(names));
+            } else {
+                item.setAnswer(resolveAnswerText(selected.get(0)));
+            }
+            normalized.add(item);
+        }
+        return normalized;
+    }
+
+    private String resolveAnswerText(LiveCompletionCouponAnswerItem item) {
+        if (item == null) {
+            return null;
+        }
+        if (StringUtils.isNotEmpty(item.getAnswerName())) {
+            return item.getAnswerName().trim();
+        }
+        return StringUtils.isEmpty(item.getAnswer()) ? null : item.getAnswer().trim();
+    }
+
     /**
      * 校验是否答完全部题目,并返回是否全部答对(答错不阻断记录)
      */

+ 10 - 0
fs-user-app/src/main/java/com/fs/app/exception/FSExceptionHandler.java

@@ -7,6 +7,7 @@ import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.domain.R;
 import com.fs.common.exception.CustomException;
 import com.fs.common.exception.ServiceException;
+import com.fs.common.exception.base.BaseException;
 import com.fs.common.utils.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -82,6 +83,15 @@ public class FSExceptionHandler {
 	public R handleException(CustomException e){
 		return R.error(e.getMessage());
 	}
+
+	/**
+	 * 业务校验异常(如完课优惠券答题/领取校验)
+	 */
+	@ExceptionHandler(BaseException.class)
+	public R handleBaseException(BaseException e) {
+		return R.error(e.getMessage());
+	}
+
 	@ExceptionHandler(Exception.class)
 	public R handleException(Exception e){
 		logger.error(e.getMessage(), e);