Просмотр исходного кода

Merge branch 'dev' of http://192.168.1.245:11111/jinjilong/onlineEducation-fwd into dev

honorfire 7 месяцев назад
Родитель
Сommit
fb642afec0

+ 4 - 0
snowy-plugin/snowy-plugin-dev/snowy-plugin-dev-api/src/main/java/vip/xiaonuo/dev/api/DevDictApi.java

@@ -12,6 +12,9 @@
  */
 package vip.xiaonuo.dev.api;
 
+
+import java.util.List;
+import com.alibaba.fastjson.JSONObject;
 /**
  * 字典API
  *
@@ -19,4 +22,5 @@ package vip.xiaonuo.dev.api;
  * @date 2022/9/2 15:58
  */
 public interface DevDictApi {
+    List<JSONObject> getDictByDictCode(String bankType);
 }

+ 25 - 0
snowy-plugin/snowy-plugin-dev/snowy-plugin-dev-func/src/main/java/vip/xiaonuo/dev/modular/dict/provider/DevDictApiProvider.java

@@ -12,8 +12,18 @@
  */
 package vip.xiaonuo.dev.modular.dict.provider;
 
+
+import com.alibaba.fastjson.JSONObject;
 import org.springframework.stereotype.Service;
 import vip.xiaonuo.dev.api.DevDictApi;
+import vip.xiaonuo.dev.modular.dict.entity.DevDict;
+import vip.xiaonuo.dev.modular.dict.param.DevDictListParam;
+import vip.xiaonuo.dev.modular.dict.service.DevDictService;
+
+import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
 
 /**
  * 字典API接口实现类
@@ -23,4 +33,19 @@ import vip.xiaonuo.dev.api.DevDictApi;
  */
 @Service
 public class DevDictApiProvider implements DevDictApi {
+
+    @Resource
+    private DevDictService devDictService;
+    @Override
+    public List<JSONObject> getDictByDictCode(String bankType) {
+        List<JSONObject> result = new ArrayList<JSONObject>();
+        DevDictListParam devDictListParam = new DevDictListParam();
+        devDictListParam.setParentDictValue(bankType);
+        List<DevDict> devDictList = devDictService.list(devDictListParam);
+        if(devDictList != null && !devDictList.isEmpty()){
+            result = devDictList.stream().map(devDict ->
+                    (JSONObject)JSONObject.toJSON(devDict)).collect(Collectors.toList());
+        }
+        return result;
+    }
 }

+ 26 - 0
snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/controller/admin/MessageController.java

@@ -1,6 +1,7 @@
 package vip.xiaonuo.exam.controller.admin;
 
 
+import com.alibaba.fastjson.JSONObject;
 import com.github.pagehelper.PageInfo;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.RequestBody;
@@ -8,6 +9,8 @@ import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.RestController;
 import vip.xiaonuo.auth.core.pojo.SaBaseLoginUser;
+import vip.xiaonuo.common.pojo.CommonResult;
+import vip.xiaonuo.dev.api.DevMessageApi;
 import vip.xiaonuo.exam.base.BaseApiController;
 import vip.xiaonuo.exam.base.RestResponse;
 import vip.xiaonuo.exam.domain.Message;
@@ -19,6 +22,7 @@ import vip.xiaonuo.exam.viewmodel.admin.message.MessagePageRequestVM;
 import vip.xiaonuo.exam.viewmodel.admin.message.MessageResponseVM;
 import vip.xiaonuo.exam.viewmodel.admin.message.MessageSendVM;
 
+import javax.annotation.Resource;
 import javax.validation.Valid;
 import java.util.Date;
 import java.util.List;
@@ -30,6 +34,8 @@ public class MessageController extends BaseApiController {
 
     private final MessageService messageService;
 
+    @Resource
+    private DevMessageApi devMessageApi;
 
     @Autowired
     public MessageController(MessageService messageService) {
@@ -81,4 +87,24 @@ public class MessageController extends BaseApiController {
         return RestResponse.ok();
     }
 
+    @RequestMapping(value = "/sendCommitRemind", method = RequestMethod.POST)
+    public CommonResult sendCommitRemind(@RequestBody JSONObject model) {
+        try {
+            SaBaseLoginUser user = getCurrentUser();
+            if(user == null || user.getId() == null){
+                throw new RuntimeException("未登录!!!");
+            }
+            String content = "教师-"+user.getNickname()+"-提醒您提交试卷!!!";
+            List<String> receiverIdList = model.getJSONArray("receiverIdList").toJavaList(String.class);
+            if(receiverIdList.isEmpty()){
+                throw new RuntimeException("入参 receiverIdList 不能为空!!!");
+            }
+            devMessageApi.sendMessage(receiverIdList,content);
+        } catch (Exception e) {
+            System.err.println("sendCommitRemind 提交提醒失败!!!");
+            e.printStackTrace();
+            throw new RuntimeException("sendCommitRemind 提交提醒失败!!!");
+        }
+        return CommonResult.ok();
+    }
 }

+ 12 - 0
snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/controller/admin/QuestionController.java

@@ -1,6 +1,7 @@
 package vip.xiaonuo.exam.controller.admin;
 
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.springframework.web.multipart.MultipartFile;
 import vip.xiaonuo.common.pojo.CommonResult;
 import vip.xiaonuo.exam.base.BaseApiController;
 import vip.xiaonuo.exam.base.RestResponse;
@@ -82,6 +83,17 @@ public class QuestionController extends BaseApiController {
         return CommonResult.ok();
     }
 
+    @RequestMapping(value = "/checkExcel", method = RequestMethod.POST)
+    public CommonResult checkExcel(@RequestParam("file") MultipartFile file) {
+        return CommonResult.data(questionService.checkExcel(file,getCurrentUser()));
+    }
+
+    @RequestMapping(value = "/loadExcel", method = RequestMethod.POST)
+    public CommonResult loadExcel(@RequestParam("file") MultipartFile file) {
+        return CommonResult.data(questionService.loadExcel(file,getCurrentUser()));
+    }
+
+
     private CommonResult validQuestionEditRequestVM(QuestionEditRequestVM model) {
         int qType = model.getQuestionType().intValue();
         boolean requireCorrect = qType == QuestionTypeEnum.SingleChoice.getCode() || qType == QuestionTypeEnum.TrueFalse.getCode();

+ 72 - 0
snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/domain/question/QuestionExcel.java

@@ -0,0 +1,72 @@
+package vip.xiaonuo.exam.domain.question;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.alibaba.fastjson.JSONObject;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * @PackageName:vip.xiaonuo.exam.domain.question
+ * @ClassName:QuestionExcel
+ * @Author ZSS
+ * @Date 2025-07-18 13:49
+ * @Note: 题目文档导入实体
+ **/
+@Data
+public class QuestionExcel {
+    /**
+     * 题目序号
+     */
+    @ExcelProperty("题目序号")
+    private String id;
+    /**
+     * 题库类型 1练习题目库  2问卷题目库
+     */
+    @ExcelProperty("所属题库")
+    private String bankType;
+    /**
+     * 	1.单选题 2.多选题 3.判断题 4.填空题 5.简答题
+     */
+    @ExcelProperty("题目类型")
+    private String questionType;
+    /**
+     * 题目内容
+     */
+    @ExcelProperty("题目内容")
+    private String titleContent;
+    /**
+     * 题目解析
+     */
+    @ExcelProperty("题目解析")
+    private String analyze;
+    /**
+     * 	选项名称
+     */
+    @ExcelProperty("选项名称")
+    private String itemName;
+    /**
+     * 	选项内容
+     */
+    @ExcelProperty("选项内容")
+    private String itemContent;
+    /**
+     * 答案(简答题)
+     */
+    @ExcelProperty("答案")
+    private String correctContent;
+    /**
+     * 	题目分数
+     */
+    @ExcelProperty("题目分数")
+    private String itemScore;
+    /**
+     * 	题目难度
+     */
+    @ExcelProperty("题目难度")
+    private String difficult;
+
+    // 判断是题目内容 条,还是选项内容 条
+    private Boolean isContent;
+
+}

+ 7 - 0
snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/service/QuestionService.java

@@ -1,6 +1,9 @@
 package vip.xiaonuo.exam.service;
 
+import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.springframework.web.multipart.MultipartFile;
+import vip.xiaonuo.auth.core.pojo.SaBaseLoginUser;
 import vip.xiaonuo.exam.domain.Question;
 import vip.xiaonuo.exam.viewmodel.admin.question.QuestionEditRequestVM;
 import vip.xiaonuo.exam.viewmodel.admin.question.QuestionPageRequestVM;
@@ -23,4 +26,8 @@ public interface QuestionService extends BaseService<Question> {
     Integer selectAllCount();
 
     List<Integer> selectMothCount();
+
+    JSONObject checkExcel(MultipartFile file, SaBaseLoginUser currentUser);
+
+    JSONObject loadExcel(MultipartFile file, SaBaseLoginUser currentUser);
 }

+ 459 - 6
snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/service/impl/QuestionServiceImpl.java

@@ -1,22 +1,31 @@
 package vip.xiaonuo.exam.service.impl;
 
+import cn.hutool.core.collection.ListUtil;
+import cn.hutool.core.io.FileUtil;
+import com.alibaba.excel.EasyExcel;
+import com.alibaba.excel.EasyExcelFactory;
+import com.alibaba.excel.support.ExcelTypeEnum;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.springframework.transaction.interceptor.TransactionAspectSupport;
+import org.springframework.web.multipart.MultipartFile;
+import vip.xiaonuo.auth.core.pojo.SaBaseLoginUser;
+import vip.xiaonuo.dev.api.DevDictApi;
 import vip.xiaonuo.exam.domain.ExamPaper;
 import vip.xiaonuo.exam.domain.other.KeyValue;
 import vip.xiaonuo.exam.domain.Question;
 import vip.xiaonuo.exam.domain.TextContent;
 import vip.xiaonuo.exam.domain.enums.QuestionStatusEnum;
 import vip.xiaonuo.exam.domain.enums.QuestionTypeEnum;
+import vip.xiaonuo.exam.domain.question.QuestionExcel;
 import vip.xiaonuo.exam.domain.question.QuestionItemObject;
 import vip.xiaonuo.exam.domain.question.QuestionObject;
 import vip.xiaonuo.exam.mapper.QuestionMapper;
 import vip.xiaonuo.exam.service.QuestionService;
 import vip.xiaonuo.exam.service.SubjectService;
 import vip.xiaonuo.exam.service.TextContentService;
-import vip.xiaonuo.exam.utility.DateTimeUtil;
-import vip.xiaonuo.exam.utility.JsonUtil;
-import vip.xiaonuo.exam.utility.ModelMapperSingle;
-import vip.xiaonuo.exam.utility.ExamUtil;
+import vip.xiaonuo.exam.utility.*;
 import vip.xiaonuo.exam.viewmodel.admin.question.QuestionEditItemVM;
 import vip.xiaonuo.exam.viewmodel.admin.question.QuestionEditRequestVM;
 import vip.xiaonuo.exam.viewmodel.admin.question.QuestionPageRequestVM;
@@ -27,9 +36,18 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
-import java.util.Date;
-import java.util.List;
+import java.io.File;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 import java.util.stream.Collectors;
+import cn.hutool.core.util.NumberUtil;
+
+import javax.annotation.Resource;
+
+import static cn.hutool.core.date.DateTime.now;
 
 @Service
 public class QuestionServiceImpl extends BaseServiceImpl<Question> implements QuestionService {
@@ -39,6 +57,9 @@ public class QuestionServiceImpl extends BaseServiceImpl<Question> implements Qu
     private final TextContentService textContentService;
     private final SubjectService subjectService;
 
+    @Resource
+    private DevDictApi devDictApi;
+
     @Autowired
     public QuestionServiceImpl(QuestionMapper questionMapper, TextContentService textContentService, SubjectService subjectService) {
         super(questionMapper);
@@ -205,5 +226,437 @@ public class QuestionServiceImpl extends BaseServiceImpl<Question> implements Qu
         }).collect(Collectors.toList());
     }
 
+    /**
+     * 检查导入的Excel文件
+     */
+    @Override
+    public JSONObject checkExcel(MultipartFile file, SaBaseLoginUser currentUser) {
+        JSONObject result = new JSONObject();
+        try {
+            if(currentUser == null || currentUser.getId() == null){
+                throw new RuntimeException("未登录!!!");
+            }
+            return checkExcelData(file, result, false);
+        } catch (Exception e) {
+            System.err.println("检查导入的Excel文件失败!!!");
+            e.printStackTrace();
+        }
+        return result;
+    }
+
+    /**
+     * 导入Excel文件
+     */
+    @Override
+    public JSONObject loadExcel(MultipartFile file, SaBaseLoginUser currentUser) {
+        JSONObject result = new JSONObject();
+        try {
+            if(currentUser == null || currentUser.getId() == null){
+                throw new RuntimeException("未登录!!!");
+            }
+            JSONObject checkResult = checkExcelData(file, result, true);
+            if (checkResult.getIntValue("questionErrorCount") !=0 || checkResult.getJSONArray("questionOKList").isEmpty()) {
+                // 有错误的数据返回检查结果
+                return checkResult.getJSONObject("data");
+            }else{
+                // 无错误执行导入
+                List<QuestionExcel> questionOKList = checkResult.getJSONArray("questionOKList").toJavaList(QuestionExcel.class);
+                return saveFromLoad(questionOKList,currentUser.getId(),result);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return result;
+    }
+
+    /**
+     * 检查导入的数据
+     * backAllData 是否返回所有数据
+     */
+    public JSONObject checkExcelData(MultipartFile file, JSONObject result, boolean backAllData) {
+        try {
+            String fileName = file.getOriginalFilename();
+            if (fileName == null){
+                throw new RuntimeException("请上传xlsx导入数据文件!!!");
+            }
+            String suffix = FileUtil.getSuffix(fileName);
+            if (!suffix.equals("xlsx")) {
+                throw new RuntimeException("请上传xlsx导入数据文件!!!");
+            }
+
+            // 创建临时文件
+            File tempFile = FileUtil.writeBytes(file.getBytes(), FileUtil.file(FileUtil.getTmpDir() +
+                    FileUtil.FILE_SEPARATOR + fileName));
+            // 读取excel
+            List<QuestionExcel> questionList =  EasyExcel.read(tempFile).head(QuestionExcel.class).sheet()
+                    .headRowNumber(1).doReadSync();
+            List<QuestionExcel> questionOKList = new ArrayList<QuestionExcel>();
+            if(!questionList.isEmpty()){
+                LinkedHashSet<String> errorIdSet = new LinkedHashSet<String>();
+                List<String> errorQuestionList = new ArrayList<String>();
+
+                for(int i = 0; i < questionList.size(); i++){
+                    // 判断ID是否为空 是否是正整数
+                    String questionId = questionList.get(i).getId();
+                    if(questionId == null || questionId.trim().isEmpty()){
+                        errorQuestionList.add("第"+(i+1)+"行, 题目序号为空请检查.");
+                        continue;
+                    }
+                    boolean isQuestionIdInteger = NumberUtil.isInteger(questionId);
+                    if(!isQuestionIdInteger){
+                        errorIdSet.add(questionId);
+                        errorQuestionList.add("题目序号: "+questionId+" 数据格式不正确请检查.");
+                        continue;
+                    }
+                    QuestionExcel okExcel = have(questionOKList, questionId);
+                    if(okExcel == null){
+                        okExcel = new QuestionExcel();
+                        okExcel.setId(questionId);
+                        okExcel.setIsContent(true);
+                    }else{
+                        okExcel = new QuestionExcel();
+                        okExcel.setId(questionId);
+                        okExcel.setIsContent(false);
+                    }
+
+                    /////////////////////////////////////////////////////////////////////////////////////////////////////
+                    if(okExcel.getIsContent()){
+                        String bankType = questionList.get(i).getBankType();
+                        boolean isBankType = setBankType(bankType, okExcel);
+                        if(!isBankType){
+                            errorQuestionList.add("题目序号: "+questionId+" , 所属题库数据格式错误请检查.");
+                            errorIdSet.add(questionId);
+                        }
+                    }
+                    /////////////////////////////////////////////////////////////////////////////////////////////////////
+                    if(okExcel.getIsContent()){
+                        String questionType = questionList.get(i).getQuestionType();
+                        boolean isQuestionType = setQuestionType(questionType, okExcel);
+                        if(!isQuestionType){
+                            errorQuestionList.add("题目序号: "+questionId+" , 题目类型数据格式错误请检查.");
+                            errorIdSet.add(questionId);
+                        }
+                    }
+                    /////////////////////////////////////////////////////////////////////////////////////////////////////
+                    if(okExcel.getIsContent()){
+                        String questionContent = questionList.get(i).getTitleContent();
+                        if(questionContent == null || questionContent.trim().isEmpty()){
+                            errorQuestionList.add("题目序号: "+questionId+" , 题目内容为空请检查.");
+                            errorIdSet.add(questionId);
+                        }else{
+                            String questionType = questionList.get(i).getQuestionType();
+                            if(questionType !=null && questionType.equals("填空题")){
+                                int emptyCount = checkEmptyCount(questionContent);
+                                if(emptyCount == 0){
+                                    errorQuestionList.add("题目序号: "+questionId+" , 是填空题但没有留空请检查.");
+                                    errorIdSet.add(questionId);
+                                }else{
+                                    okExcel.setTitleContent(questionContent);
+                                }
+                            }else{
+                                okExcel.setTitleContent(questionContent);
+                            }
+                        }
+                    }
+                    /////////////////////////////////////////////////////////////////////////////////////////////////////
+                    if(okExcel.getIsContent()){
+                        String questionAnalyze = questionList.get(i).getAnalyze();
+                        if(questionAnalyze !=null && !questionAnalyze.trim().isEmpty()){
+                            okExcel.setAnalyze(questionAnalyze);
+                        }
+                    }
+                    /////////////////////////////////////////////////////////////////////////////////////////////////////
+                    String itemName = questionList.get(i).getItemName();
+                    boolean isItemName = checkItemName(itemName);
+                    if(!isItemName){
+                        errorQuestionList.add("题目序号: "+questionId+" , 数据格式错误请检查.");
+                        errorIdSet.add(questionId);
+                    }else{
+                        okExcel.setItemName(itemName);
+                    }
+                    /////////////////////////////////////////////////////////////////////////////////////////////////////
+                    String itemContent = questionList.get(i).getItemContent();
+                    if(itemContent == null || itemContent.trim().isEmpty()){
+                        errorQuestionList.add("题目序号: "+questionId+" , 选项内容为空请检查.");
+                        errorIdSet.add(questionId);
+                    }else{
+                        okExcel.setItemContent(itemContent);
+                    }
+                    /////////////////////////////////////////////////////////////////////////////////////////////////////
+                    if(okExcel.getIsContent()){
+                        String questionType = questionList.get(i).getQuestionType();
+                        if(questionType ==null || !questionType.equals("填空题")){
+                            String correctContent = questionList.get(i).getCorrectContent();
+                            if(correctContent == null || correctContent.trim().isEmpty()){
+                                errorQuestionList.add("题目序号: "+questionId+" , 答案内容为空请检查.");
+                                errorIdSet.add(questionId);
+                            }else{
+                                okExcel.setCorrectContent(correctContent);
+                            }
+                        }
+                    }
+                    /////////////////////////////////////////////////////////////////////////////////////////////////////
+                    if(okExcel.getIsContent()){
+                        String itemScore = questionList.get(i).getItemScore();
+                        boolean isItemScore = positiveInteger(itemScore);
+                        if(!isItemScore){
+                            errorQuestionList.add("题目序号: "+questionId+" , 题目分数数据格式错误请检查.");
+                            errorIdSet.add(questionId);
+                        }else{
+                            okExcel.setItemScore(itemScore);
+                        }
+                    }
+                    /////////////////////////////////////////////////////////////////////////////////////////////////////
+                    if(okExcel.getIsContent()){
+                        String difficult = questionList.get(i).getDifficult();
+                        boolean isDifficult = positiveInteger(difficult);
+                        if(!isDifficult){
+                            errorQuestionList.add("题目序号: "+questionId+" , 题目难度数据格式错误请检查.");
+                            errorIdSet.add(questionId);
+                        }else{
+                            okExcel.setDifficult(difficult);
+                        }
+                    }
+                    /////////////////////////////////////////////////////////////////////////////////////////////////////
+                    questionOKList.add(okExcel);
+                }
+                result.put("errorIdSet", errorIdSet);
+                result.put("questionOKCount", questionOKList.size());
+                result.put("errorQuestionList", errorQuestionList);
+                result.put("questionErrorCount", errorQuestionList.size());
+                if(backAllData){
+                    result.put("allData", questionList);
+                    result.put("questionOKList", questionOKList);
+                }
+                return result;
+            }else{
+                throw new RuntimeException("导入的Excel文件内容为空!!!");
+            }
+        } catch (Exception e) {
+            System.err.println("checkExcelData 检查导入的Excel文件失败!!!");
+            e.printStackTrace();
+        }
+        return result;
+    }
+
+
+
+    @Transactional(rollbackFor = Exception.class)
+    public JSONObject saveFromLoad(List<QuestionExcel> questionOKList, String userId, JSONObject result) {
+        List<String> saveIds = new ArrayList<>(); // 保存成功的序号ID
+        for(QuestionExcel okExcel : questionOKList){
+            if(okExcel.getIsContent() && !saveIds.contains(okExcel.getId())){
+                // 题目内容 条
+                List<QuestionExcel> itemList = questionOKList.stream().filter(item -> item.getId().equals(okExcel.getId())).collect(Collectors.toList());
+                List<String> correct = itemList.stream().map(QuestionExcel::getCorrectContent).filter(Objects::nonNull).collect(Collectors.toList());
+                int questionType = Integer.parseInt(okExcel.getQuestionType());
+                int score = Integer.parseInt(okExcel.getItemScore());
+                int difficult = Integer.parseInt(okExcel.getDifficult());
+                Question question = new Question();
+                question.setBankType(okExcel.getBankType());
+                question.setQuestionType(questionType);
+                question.setScore(score);
+                question.setDifficult(difficult);
+                question.setCreateUser(userId);
+                question.setStatus(1);
+                question.setCreateTime(now());
+                question.setDeleted(false);
+
+
 
+
+                if(QuestionTypeEnum.GapFilling.getCode() == questionType){ // 填空题
+                   int count = checkEmptyCount(okExcel.getTitleContent());
+                   if(count == 0){
+                       throw new RuntimeException("序号 "+okExcel.getId()+" 题目填空题留空数量为0,请检查!!!");
+                   }
+                }
+                if(QuestionTypeEnum.ShortAnswer.getCode() == questionType){ // 简答题
+                }
+                if(QuestionTypeEnum.SingleChoice.getCode()  == questionType){ // 单选题
+                    if(itemList.size() < 2){
+                        throw new RuntimeException("序号 "+okExcel.getId()+" 题目选项数量不正确,请检查!!!");
+                    }
+                    if(correct.size() != 1){
+                        throw new RuntimeException("序号 "+okExcel.getId()+" 答案数量不正确,请检查!!!");
+                    }
+                    question.setCorrect(String.join(",", correct));
+                }
+                if(QuestionTypeEnum.MultipleChoice.getCode()  == questionType) { // 多选题
+                    if(itemList.size() < 2){
+                        throw new RuntimeException("序号 "+okExcel.getId()+" 题目选项数量不正确,请检查!!!");
+                    }
+                    if(correct.isEmpty()){
+                        throw new RuntimeException("序号 "+okExcel.getId()+" 答案数量不正确,请检查!!!");
+                    }
+                    question.setCorrect(String.join(",", correct));
+                }
+                if(QuestionTypeEnum.TrueFalse.getCode()  == questionType) { // 判断题
+                    if(itemList.size() != 2){
+                        throw new RuntimeException("序号 "+okExcel.getId()+" 题目选项数量不正确,请检查!!!");
+                    }
+                    if(correct.size() != 1){
+                        throw new RuntimeException("序号 "+okExcel.getId()+" 答案数量不正确,请检查!!!");
+                    }
+                    question.setCorrect(String.join(",", correct));
+                }
+                TextContent textContent = SaveTextContent(questionType,okExcel.getTitleContent(),okExcel.getAnalyze(),score,correct,itemList);
+                question.setInfoTextContentId(textContent.getId());
+                questionMapper.insertSelective(question);
+            }else{
+                // 选项内容 条 跳过
+                continue;
+            }
+        }
+        return result;
+    }
+
+
+
+
+
+
+
+
+    public QuestionExcel have(List<QuestionExcel> questionList, String questionId){
+        for(QuestionExcel questionExcel : questionList){
+            if(questionExcel.getId().equals(questionId)){
+                return questionExcel;
+            }
+        }
+        return null;
+    }
+
+    public boolean setBankType(String bankType, QuestionExcel okExcel){
+        boolean set = false;
+        if(bankType != null && !bankType.trim().isEmpty()){
+            List<JSONObject> bizDictList = devDictApi.getDictByDictCode("BANK_TYPE");
+            for(JSONObject dict : bizDictList){
+                if(dict.getString("dictLabel").equals(bankType.trim())){
+                    okExcel.setBankType(dict.getString("dictValue"));
+                    set = true;
+                    break;
+                }
+            }
+        }
+        return set;
+    }
+    public boolean setQuestionType(String questionType, QuestionExcel okExcel){
+        boolean set = false;
+        if(questionType != null && !questionType.trim().isEmpty()){
+            List<JSONObject> bizDictList = devDictApi.getDictByDictCode("QUESTION_TYPE");
+            for(JSONObject dict : bizDictList){
+                if(dict.getString("dictLabel").equals(questionType.trim())){
+                    okExcel.setQuestionType(dict.getString("dictValue"));
+                    set = true;
+                    break;
+                }
+            }
+        }
+        return set;
+    }
+
+    /**
+     * 检查填空题 题目内容是否有正确的留空
+     * 格式 {{1}}
+     * @param questionContent
+     * @return
+     */
+    public static int checkEmptyCount(String questionContent) {
+        int emptyCount = 0;
+        if (questionContent != null && !questionContent.trim().isEmpty()) {
+            // 清理隐藏字符
+            questionContent = questionContent.replaceAll("[\\s\\u200B\\u200C\\u200D\\uFEFF]", "");
+
+            // 使用正则表达式匹配 (数字) 或 (数字)格式的内容
+            Pattern pattern = Pattern.compile("\\{\\s*\\{\\s*\\d+\\s*\\}\\s*\\}");
+            Matcher matcher = pattern.matcher(questionContent);
+            while (matcher.find()) {
+                System.out.println("匹配到的内容: " + matcher.group());
+                emptyCount++;
+            }
+        }
+        return emptyCount;
+    }
+
+    public static boolean checkItemName(String itemName){
+        boolean check = false;
+        // 只能是大写字母或数字
+        if(itemName != null && !itemName.trim().isEmpty()){
+            Pattern pattern = Pattern.compile("^[A-Z0-9]+$");
+            Matcher matcher = pattern.matcher(itemName);
+            check = matcher.matches();
+            return check;
+        }
+        return check;
+    }
+
+    public static boolean positiveInteger(String number){
+        boolean check = false;
+        if(number == null || number.trim().isEmpty()){
+            return check;
+        }
+        // 正整数正则
+        String reg = "^[0-9]*[1-9][0-9]*$";
+        if(number.matches(reg)){
+            return true;
+        }
+        return check;
+    }
+
+    /**
+     * 保存TextContent
+     * @param questionType
+     * @param titleContent
+     * @param analyze
+     * @param correct
+     * @param itemList
+     * @return
+     */
+    public TextContent SaveTextContent(int questionType,String titleContent, String analyze, int score, List<String> correct, List<QuestionExcel> itemList){
+        TextContent textContent = new TextContent();
+        textContent.setCreateTime(now());
+        JSONObject jsonObject = new JSONObject();
+        jsonObject.put("titleContent", "<p>"+titleContent+"</p>");
+        jsonObject.put("analyze", "<p>"+analyze+"</p>");
+        if(QuestionTypeEnum.GapFilling.getCode() == questionType){ // 填空题
+            // 留空富文本 数据样例 <span class=\"gapfilling-span gapfilling-1752750215744-8712\" style=\"color: red; padding: 0 30px; margin: 0 5px; border-bottom: 3px double red;\">1</span>
+            // itemUuid 数据样例 gapfilling-1752750215744-8712\" style=\"color: red; padding: 0 30px; margin: 0 5px; border-bottom: 3px double red;
+            JSONArray questionItemObjects = new JSONArray();
+            for(QuestionExcel item :itemList){
+                String uuid = System.currentTimeMillis() + "";
+                String randomNum = 1000 + new Random().nextInt(9000) + "";
+                titleContent = titleContent.replace("{{"+item.getItemName()+"}}", "<span class=\"gapfilling-span gapfilling-"+uuid+"-"+randomNum+"\" style=\"color: red; padding: 0 30px; margin: 0 5px; border-bottom: 3px double red;\">"+item.getItemName()+"</span>");
+                JSONObject ItemJson = new JSONObject();
+                ItemJson.put("prefix", item.getItemName());
+                ItemJson.put("content", "<p>"+item.getItemContent()+"</p>");
+                ItemJson.put("score", score);
+                ItemJson.put("itemUuid", "gapfilling-"+uuid+"-"+randomNum+"\" style=\"color: red; padding: 0 30px; margin: 0 5px; border-bottom: 3px double red;");
+                questionItemObjects.add(ItemJson);
+            }
+            jsonObject.put("questionItemObjects", questionItemObjects);
+            jsonObject.put("titleContent", titleContent);
+        }else if(QuestionTypeEnum.ShortAnswer.getCode() == questionType){ // 简答题
+            jsonObject.put("questionItemObjects", ListUtil.empty());
+            jsonObject.put("correct", "<p>"+correct.get(0)+"</p>");
+            textContent.setContent(jsonObject.toJSONString());
+        } else {
+            // 单选 多选 判断
+            String corrects =  String.join(",", correct);
+            jsonObject.put("correct", "<p>"+corrects+"</p>");
+            JSONArray questionItemObjects = new JSONArray();
+            for(QuestionExcel item :itemList){
+                JSONObject ItemJson = new JSONObject();
+                ItemJson.put("prefix", item.getItemName());
+                ItemJson.put("content", "<p>"+item.getItemContent()+"</p>");
+                ItemJson.put("score", null);
+                ItemJson.put("itemUuid", null);
+                questionItemObjects.add(ItemJson);
+            }
+            jsonObject.put("questionItemObjects", questionItemObjects);
+        }
+        textContent.setContent(jsonObject.toJSONString());
+        textContentService.insertByFilter(textContent);
+        return textContent;
+    }
 }