浏览代码

导入题库时,失败后需要导出失败的数据

yfh 9 小时之前
父节点
当前提交
d8f87e875d

+ 35 - 8
fs-admin/src/main/java/com/fs/course/controller/FsCourseQuestionBankController.java

@@ -13,6 +13,7 @@ import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.course.config.CourseConfig;
 import com.fs.course.domain.FsCourseQuestionBank;
 import com.fs.course.dto.FsCourseQuestionBankImportDTO;
+import com.fs.course.dto.ImportResultDTO;
 import com.fs.course.service.IFsCourseQuestionBankService;
 import com.fs.framework.web.service.TokenService;
 import com.fs.system.service.ISysConfigService;
@@ -21,7 +22,9 @@ import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
 
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 /**
  * 题库Controller
@@ -80,6 +83,15 @@ public class FsCourseQuestionBankController extends BaseController
         return util.exportExcel(list, "题库数据");
     }
 
+    @PreAuthorize("@ss.hasPermi('course:courseQuestionBank:exportFail')")
+    @Log(title = "题库", businessType = BusinessType.EXPORT)
+    @PostMapping("/exportFail")
+    public AjaxResult export( @RequestBody List<FsCourseQuestionBankImportDTO> list)
+    {
+        ExcelUtil<FsCourseQuestionBankImportDTO> util = new ExcelUtil<>(FsCourseQuestionBankImportDTO.class);
+        return util.exportExcel(list, "题库错误数据");
+    }
+
     /**
      * 获取题库详细信息
      */
@@ -144,19 +156,34 @@ public class FsCourseQuestionBankController extends BaseController
     @PreAuthorize("@ss.hasPermi('course:courseQuestionBank:importData')")
     @PostMapping("/importData")
     public AjaxResult importData(MultipartFile file) throws Exception {
-        ExcelUtil<FsCourseQuestionBankImportDTO> util = new ExcelUtil<>(FsCourseQuestionBankImportDTO.class);
-        List<FsCourseQuestionBankImportDTO> list = util.importExcel(file.getInputStream());
+
+        ExcelUtil<FsCourseQuestionBankImportDTO> util =
+                new ExcelUtil<>(FsCourseQuestionBankImportDTO.class);
+        List<FsCourseQuestionBankImportDTO> list =
+                util.importExcel(file.getInputStream());
 
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         Long userId = loginUser.getUser().getUserId();
+
+        // 读取配置
         String json = configService.selectConfigByKey("course.config");
         CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
-        if (ObjectUtil.isNotEmpty(config.getIsBound())&&config.getIsBound()){
-            String message = fsCourseQuestionBankService.importData(list, loginUser.getUser().getNickName(),userId);
-            return AjaxResult.success(message);
-        }
-        String message = fsCourseQuestionBankService.importData(list, loginUser.getUser().getNickName(),null);
-        return AjaxResult.success(message);
+
+        // 绑定状态控制 userId
+        Long finalUserId = (ObjectUtil.isNotEmpty(config.getIsBound()) && config.getIsBound())
+                ? userId
+                : null;
+
+        // 调用 service
+        ImportResultDTO result =
+                fsCourseQuestionBankService.importData(list, loginUser.getUser().getNickName(), finalUserId);
+
+        // 返回 message + failList
+        Map<String, Object> resp = new HashMap<>();
+        resp.put("message", result.buildResultMessage());
+        resp.put("failList", result.getFailureList());
+
+        return AjaxResult.success(resp);
     }
 
     @GetMapping(value = "/getByIds")

+ 17 - 0
fs-service/src/main/java/com/fs/course/dto/ImportFailItemDTO.java

@@ -0,0 +1,17 @@
+package com.fs.course.dto;
+
+import lombok.Data;
+
+@Data
+public class ImportFailItemDTO {
+
+    private FsCourseQuestionBankImportDTO rowData; // 原始 Excel 行
+    private String reason; // 失败原因
+
+    public ImportFailItemDTO(FsCourseQuestionBankImportDTO rowData, String reason) {
+        this.rowData = rowData;
+        this.reason = reason;
+    }
+
+}
+

+ 62 - 0
fs-service/src/main/java/com/fs/course/dto/ImportResultDTO.java

@@ -0,0 +1,62 @@
+package com.fs.course.dto;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ImportResultDTO {
+
+
+    private int successNum = 0;
+    private int failureNum = 0;
+
+    // 用于 message 拼接
+    private final List<String> failureMsgList = new ArrayList<>();
+
+    // 返回给前端的失败原始数据 list(你要的)
+    private final List<FsCourseQuestionBankImportDTO> failureList = new ArrayList<>();
+
+    public void addSuccess() {
+        successNum++;
+    }
+
+    public void addFailure(FsCourseQuestionBankImportDTO dto, String reason) {
+        failureNum++;
+
+        // message 用
+        failureMsgList.add("题目 " + dto.getTitle() + " 导入失败:" + reason);
+
+        // list 记录原始数据
+        failureList.add(dto);
+    }
+
+    public List<FsCourseQuestionBankImportDTO> getFailureList() {
+        return failureList;
+    }
+
+    /**
+     * 构建你要的 HTML 格式 message
+     */
+    public String buildResultMessage() {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append("导入完成!成功")
+                .append(successNum)
+                .append(" 条,失败")
+                .append(failureNum)
+                .append("条。");
+
+        if (!failureMsgList.isEmpty()) {
+            sb.append("<br/>");
+            int index = 1;
+            for (String msg : failureMsgList) {
+                sb.append(index++)
+                        .append("、")
+                        .append(msg)
+                        .append("<br/>");
+            }
+        }
+
+        return sb.toString();
+    }
+    }
+

+ 2 - 1
fs-service/src/main/java/com/fs/course/service/IFsCourseQuestionBankService.java

@@ -3,6 +3,7 @@ package com.fs.course.service;
 import com.fs.common.core.domain.R;
 import com.fs.course.domain.FsCourseQuestionBank;
 import com.fs.course.dto.FsCourseQuestionBankImportDTO;
+import com.fs.course.dto.ImportResultDTO;
 import com.fs.course.param.FsCourseQuestionAnswerUParam;
 
 import javax.validation.constraints.Size;
@@ -73,7 +74,7 @@ public interface IFsCourseQuestionBankService
      * @param nickName 昵称
      * @return String
      */
-    String importData(List<FsCourseQuestionBankImportDTO> list, String nickName,Long userId);
+    ImportResultDTO importData(List<FsCourseQuestionBankImportDTO> list, String nickName, Long userId);
 
     /**
      * 根据ID查询题目

+ 19 - 11
fs-service/src/main/java/com/fs/course/service/impl/FsCourseQuestionBankServiceImpl.java

@@ -11,6 +11,7 @@ import com.fs.common.utils.StringUtils;
 import com.fs.course.config.CourseConfig;
 import com.fs.course.domain.*;
 import com.fs.course.dto.FsCourseQuestionBankImportDTO;
+import com.fs.course.dto.ImportResultDTO;
 import com.fs.course.mapper.*;
 import com.fs.course.param.FsCourseQuestionAnswerUParam;
 import com.fs.course.service.IFsCourseQuestionBankService;
@@ -468,43 +469,50 @@ public class FsCourseQuestionBankServiceImpl implements IFsCourseQuestionBankSer
      * @return String
      */
     @Override
-    public String importData(List<FsCourseQuestionBankImportDTO> list, String nickName,Long userId) {
+    public ImportResultDTO importData(List<FsCourseQuestionBankImportDTO> list, String nickName, Long userId) {
+
         if (Objects.isNull(list) || list.isEmpty()) {
             throw new ServiceException("导入数据不能为空");
         }
 
-        ImportResult result = new ImportResult();
+        ImportResultDTO result = new ImportResultDTO();
         List<FsCourseQuestionBank> importData = new ArrayList<>();
-        Map<String, FsUserCourseCategory> categoryData = courseCategoryMapper.queryAllCategoryData();
+
+        // 分类数据判空保护
+        Map<String, FsUserCourseCategory> categoryData =
+                Optional.ofNullable(courseCategoryMapper.queryAllCategoryData())
+                        .orElse(Collections.emptyMap());
 
         for (FsCourseQuestionBankImportDTO importDTO : list) {
             try {
-                // 数据验证
                 ValidationResult validation = validateImportData(importDTO);
                 if (!validation.isValid()) {
-                    result.addFailure(importDTO.getTitle(), validation.getErrorMessage());
+                    result.addFailure(importDTO, validation.getErrorMessage());
                     continue;
                 }
 
-                // 构建题目对象
-                FsCourseQuestionBank questionBank = buildQuestionBank(importDTO, categoryData, nickName);
+                FsCourseQuestionBank questionBank =
+                        buildQuestionBank(importDTO, categoryData, nickName);
+
                 questionBank.setUserId(userId);
+
                 importData.add(questionBank);
-                result.addSuccess(importDTO.getTitle());
+                result.addSuccess();
 
             } catch (Exception e) {
-                result.addFailure(importDTO.getTitle(), "导入异常: " + e.getMessage());
+                result.addFailure(importDTO, "导入异常:" + e.getMessage());
             }
         }
 
-        // 批量保存
+        // 4. 批量插入
         if (!importData.isEmpty()) {
             fsCourseQuestionBankMapper.insertFsCourseQuestionBankBatch(importData);
         }
 
-        return result.buildResultMessage();
+        return result;
     }
 
+
     /**
      * 验证导入数据
      */