Browse Source

feat(business): 添加盲注结构导入功能

- 新增盲注结构导入相关的 BO、VO 类- 实现盲注结构导入的控制器、服务层和持久层逻辑
- 添加文件上传任务相关的实体类和 Mapper 接口
- 优化盲注结构列表查询,增加创建人和更新人信息
fugui001 5 tháng trước cách đây
mục cha
commit
f302eefb9b
26 tập tin đã thay đổi với 1273 bổ sung29 xóa
  1. 1 1
      ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/core/OssClient.java
  2. 57 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/controller/BlindLevelsController.java
  3. 40 8
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/controller/BlindStructuresController.java
  4. 5 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/domain/BlindStructures.java
  5. 107 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/domain/FileUploadTask.java
  6. 4 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/domain/bo/BlindLevelsBo.java
  7. 4 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/domain/bo/BlindStructuresBo.java
  8. 105 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/domain/bo/FileUploadTaskBo.java
  9. 59 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/domain/vo/BlindLevelsImportVo.java
  10. 12 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/domain/vo/BlindStructuresVo.java
  11. 130 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/domain/vo/FileUploadTaskVo.java
  12. 3 1
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/mapper/BlindLevelsMapper.java
  13. 29 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/mapper/FileUploadTaskMapper.java
  14. 10 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/service/IBlindLevelsService.java
  15. 4 2
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/service/IBlindStructuresService.java
  16. 102 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/service/IFileUploadTaskService.java
  17. 6 1
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/service/impl/BlindLevelsServiceImpl.java
  18. 193 11
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/service/impl/BlindStructuresServiceImpl.java
  19. 294 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/service/impl/FileUploadTaskServiceImpl.java
  20. 1 1
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysOssController.java
  21. 6 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserImportVo.java
  22. 8 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOssService.java
  23. 1 1
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssServiceImpl.java
  24. 4 0
      ruoyi-modules/ruoyi-system/src/main/resources/mapper/business/BlindLevelsMapper.xml
  25. 9 3
      ruoyi-modules/ruoyi-system/src/main/resources/mapper/business/BlindStructuresMapper.xml
  26. 79 0
      ruoyi-modules/ruoyi-system/src/main/resources/mapper/business/FileUploadTaskMapper.xml

+ 1 - 1
ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/core/OssClient.java

@@ -161,7 +161,7 @@ public class OssClient {
     /**
      * 上传 InputStream 到 Amazon S3
      *
-     * @param inputStream 要上传的输入流
+     * @param inputStream 要上传的输入流2
      * @param key         在 Amazon S3 中的对象键
      * @param length      输入流的长度
      * @param contentType 文件内容类型

+ 57 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/controller/BlindLevelsController.java

@@ -1,10 +1,12 @@
 package org.dromara.business.controller;
 
+import java.util.ArrayList;
 import java.util.List;
 import lombok.RequiredArgsConstructor;
 import jakarta.servlet.http.HttpServletResponse;
 import jakarta.validation.constraints.*;
 import cn.dev33.satoken.annotation.SaCheckPermission;
+import org.dromara.business.domain.vo.BlindLevelsImportVo;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.validation.annotation.Validated;
 import org.dromara.common.idempotent.annotation.RepeatSubmit;
@@ -35,6 +37,7 @@ public class BlindLevelsController extends BaseController {
 
     private final IBlindLevelsService blindLevelsService;
 
+
     /**
      * 查询【盲注级别】列表
      */
@@ -101,4 +104,58 @@ public class BlindLevelsController extends BaseController {
                           @PathVariable Long[] ids) {
         return toAjax(blindLevelsService.deleteWithValidByIds(List.of(ids), true));
     }
+
+
+
+
+
+
+
+
+
+
+
+
+
+  /*  *//**
+     * 导入数据
+     *
+     * @param file          导入文件
+     *//*
+
+    @Log(title = "【盲注级别-导入】", businessType = BusinessType.IMPORT)
+    @SaCheckPermission("business:levels:import")
+    @PostMapping(value = "/importData", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+    public R<String> importData(@RequestPart("file") MultipartFile file) throws Exception {
+        Long userId = LoginHelper.getUserId();
+       return R.ok(iFileUploadTaskService.handleFileUpload(file, userId));
+    }
+
+
+    @Log(title = "【盲注级别-获取上传的状态】", businessType = BusinessType.IMPORT)
+    @SaCheckPermission("business:levels:selectFileUploadTaskInfoByTaskId")
+    @PostMapping(value = "/selectFileUploadTaskInfoByTaskId")
+    public R<FileUploadTaskVo> selectFileUploadTaskInfoByTaskId(@RequestBody FileUploadTaskBo bo) throws Exception {
+       return  R.ok(iFileUploadTaskService.selectFileUploadTaskInfoByTaskId(bo.getTaskId()));
+    }
+
+
+    @Log(title = "【盲注级别-重新上传】", businessType = BusinessType.IMPORT)
+    @SaCheckPermission("business:levels:retryUpload")
+    @PostMapping(value = "/retryUpload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+    public R<Void> retryUpload(@RequestBody FileUploadTaskBo bo) throws Exception {
+        Long userId = LoginHelper.getUserId();
+        return iFileUploadTaskService.retryUpload(bo.getTaskId(), userId);
+    }
+
+
+    */
+
+    /**
+     * 获取导入模板
+     */
+    @PostMapping("/importTemplate")
+    public void importTemplate(HttpServletResponse response) {
+        ExcelUtil.exportExcel(new ArrayList<>(), "盲注表模版", BlindLevelsImportVo.class, response);
+    }
 }

+ 40 - 8
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/controller/BlindStructuresController.java

@@ -6,6 +6,7 @@ import lombok.RequiredArgsConstructor;
 import jakarta.servlet.http.HttpServletResponse;
 import jakarta.validation.constraints.*;
 import cn.dev33.satoken.annotation.SaCheckPermission;
+import org.springframework.http.MediaType;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.validation.annotation.Validated;
 import org.dromara.common.idempotent.annotation.RepeatSubmit;
@@ -13,14 +14,13 @@ import org.dromara.common.log.annotation.Log;
 import org.dromara.common.web.core.BaseController;
 import org.dromara.common.mybatis.core.page.PageQuery;
 import org.dromara.common.core.domain.R;
-import org.dromara.common.core.validate.AddGroup;
-import org.dromara.common.core.validate.EditGroup;
 import org.dromara.common.log.enums.BusinessType;
 import org.dromara.common.excel.utils.ExcelUtil;
 import org.dromara.business.domain.vo.BlindStructuresVo;
 import org.dromara.business.domain.bo.BlindStructuresBo;
 import org.dromara.business.service.IBlindStructuresService;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.springframework.web.multipart.MultipartFile;
 
 /**
  * 【盲注结构管理】
@@ -74,9 +74,26 @@ public class BlindStructuresController extends BaseController {
     @SaCheckPermission("business:structures:add")
     @Log(title = "【盲注结构】", businessType = BusinessType.INSERT)
     @RepeatSubmit()
-    @PostMapping()
-    public R<Void> add(@Validated(AddGroup.class) @RequestBody BlindStructuresBo bo) {
-        return toAjax(blindStructuresService.insertByBo(bo));
+    @PostMapping(path = "", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+    public R<Boolean> add(
+        @RequestPart("name") String name,
+        @RequestPart("description") String description,
+        @RequestParam("file") MultipartFile file
+    ) {
+        // 构造 BO 对象
+        BlindStructuresBo bo = new BlindStructuresBo();
+        bo.setName(name);
+        bo.setDescription(description);
+
+        // 处理文件上传逻辑
+        if (file == null && file.isEmpty()) {
+            // TODO: 文件处理逻辑,比如保存到服务器或存储路径
+        /*    String filePath = uploadService.saveFile(file); // 示例方法
+            bo.setFilePath(filePath); // 假设 BO 中有字段记录文件路径*/
+            return R.fail();
+        }
+
+        return blindStructuresService.insertByBo(bo,file);
     }
 
     /**
@@ -85,9 +102,24 @@ public class BlindStructuresController extends BaseController {
     @SaCheckPermission("business:structures:edit")
     @Log(title = "【盲注结构】", businessType = BusinessType.UPDATE)
     @RepeatSubmit()
-    @PutMapping()
-    public R<Void> edit(@Validated(EditGroup.class) @RequestBody BlindStructuresBo bo) {
-        return toAjax(blindStructuresService.updateByBo(bo));
+    @PostMapping(value = "/edit")
+     public R<Boolean> edit(
+        @RequestPart(name = "BlindStructuresBo") BlindStructuresBo bo,
+        @RequestPart(name = "file") MultipartFile file
+    ) {
+        if (file == null || file.isEmpty()) {
+            return R.fail("文件为空");
+        }
+
+        // 处理文件上传逻辑
+        if (file == null && file.isEmpty()) {
+            // TODO: 文件处理逻辑,比如保存到服务器或存储路径
+        /*    String filePath = uploadService.saveFile(file); // 示例方法
+            bo.setFilePath(filePath); // 假设 BO 中有字段记录文件路径*/
+            return R.fail();
+        }
+
+        return blindStructuresService.updateByBo(bo,file);
     }
 
     /**

+ 5 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/domain/BlindStructures.java

@@ -45,4 +45,9 @@ public class BlindStructures{
     private Date updatedAt;
 
 
+    private Long createUserId;
+
+
+    private Long updateUserId;
+
 }

+ 107 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/domain/FileUploadTask.java

@@ -0,0 +1,107 @@
+package org.dromara.business.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import java.util.Date;
+
+import java.io.Serial;
+
+/**
+ * 【请填写功能名称】对象 file_upload_task
+ *
+ * @author Lion Li
+ * @date 2025-06-27
+ */
+@Data
+@TableName("file_upload_task")
+public class FileUploadTask{
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     *
+     */
+    @TableId(value = "id")
+    private Long id;
+
+    /**
+     * 任务ID
+     */
+    private String taskId;
+
+    /**
+     * 文件名称
+     */
+    private String fileName;
+
+    /**
+     * 错误消息
+     */
+    private String errorMessage;
+
+    /**
+     * 状态
+     */
+    private String status;
+
+    /**
+     * 上传时间
+     */
+    private Date uploadTime;
+
+    /**
+     * 完成时间
+     */
+    private Date finishTime;
+
+    /**
+     * 备注
+     */
+    private String remark;
+
+    /**
+     * 后台端用户ID(上传人)
+     */
+    private Long userId;
+
+    /**
+     * 文件地址
+     */
+    private String fileUrl;
+
+    /**
+     * 已尝试重试次数
+     */
+    private Integer retryCount;
+
+    /**
+     * 最大重试次数
+     */
+    private Integer maxRetry;
+
+    /**
+     * 文件大小
+     */
+    private Integer fileSize;
+
+    /**
+     * 总行数
+     */
+    private Integer totalRows;
+
+    /**
+     * 成功并入库的行数
+     */
+    private Integer successRows;
+
+    /**
+     * 失败数
+     */
+    private Integer failedRows;
+
+    /**
+     * 对象存储主键
+     */
+    private Long ossId;
+}

+ 4 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/domain/bo/BlindLevelsBo.java

@@ -73,4 +73,8 @@ public class BlindLevelsBo extends BaseEntity {
     private Date updatedAt;
 
 
+    private Long createUserId;
+
+
+    private Long updateUserId;
 }

+ 4 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/domain/bo/BlindStructuresBo.java

@@ -34,6 +34,10 @@ public class BlindStructuresBo extends BaseEntity {
     @NotBlank(message = "盲注结构名称,如:Standard, Turbo不能为空", groups = { AddGroup.class, EditGroup.class })
     private String name;
 
+
+    @NotNull(message = "文件不能为空", groups = { AddGroup.class,EditGroup.class })
+    private String taskId;
+
     /**
      * 描述信息
      */

+ 105 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/domain/bo/FileUploadTaskBo.java

@@ -0,0 +1,105 @@
+package org.dromara.business.domain.bo;
+
+import org.dromara.business.domain.FileUploadTask;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.common.core.validate.EditGroup;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import jakarta.validation.constraints.*;
+import java.util.Date;
+
+/**
+ * 【请填写功能名称】业务对象 file_upload_task
+ *
+ * @author Lion Li
+ * @date 2025-06-27
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = FileUploadTask.class, reverseConvertGenerate = false)
+public class FileUploadTaskBo extends BaseEntity {
+
+    /**
+     *
+     */
+    @NotNull(message = "不能为空", groups = { EditGroup.class })
+    private Long id;
+
+    /**
+     * 任务ID
+     */
+    private String taskId;
+
+    /**
+     * 文件名称
+     */
+    private String fileName;
+
+    /**
+     * 错误消息
+     */
+    private String errorMessage;
+
+    /**
+     * 状态
+     */
+    private String status;
+
+    /**
+     * 上传时间
+     */
+    private Date uploadTime;
+
+    /**
+     * 完成时间
+     */
+    private Date finishTime;
+
+    /**
+     * 备注
+     */
+    private String remark;
+
+    /**
+     * 后台端用户ID(上传人)
+     */
+    private Long userId;
+
+    /**
+     * 文件地址
+     */
+    private String fileUrl;
+
+    /**
+     * 已尝试重试次数
+     */
+    private Long retryCount;
+
+    /**
+     * 最大重试次数
+     */
+    private Long maxRetry;
+
+    /**
+     * 文件大小
+     */
+    private Long fileSize;
+
+    /**
+     * 总行数
+     */
+    private Long totalRows;
+
+    /**
+     * 成功并入库的行数
+     */
+    private Long successRows;
+
+    /**
+     * 失败数
+     */
+    private Long failedRows;
+
+
+}

+ 59 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/domain/vo/BlindLevelsImportVo.java

@@ -0,0 +1,59 @@
+package org.dromara.business.domain.vo;
+
+import cn.idev.excel.annotation.ExcelProperty;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 盲注导入VO
+ *
+ * @author Lion Li
+ */
+
+@Data
+@NoArgsConstructor
+// @Accessors(chain = true) // 导入不允许使用 会找不到set方法
+public class BlindLevelsImportVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 级别编号,如第1级、第2级
+     */
+    @ExcelProperty(value = "等级")
+    private Long levelNumber;
+
+    /**
+     * 小盲金额
+     */
+    @ExcelProperty(value = "小盲预置分")
+    private Long smallBlind;
+
+
+    /**
+     * 大盲金额
+     */
+    @ExcelProperty(value = "大盲预置分")
+    private Long bigBlind;
+
+
+
+    /**
+     * 底注(可选)
+     */
+    @ExcelProperty(value = "前置预置分")
+    private Long ante;
+
+
+
+    /**
+     * 本级别持续时间(分钟)
+     */
+    @ExcelProperty(value = "升级时间")
+    private Long durationMinutes;
+
+}

+ 12 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/domain/vo/BlindStructuresVo.java

@@ -8,6 +8,7 @@ import io.github.linpeilie.annotations.AutoMapper;
 import lombok.Data;
 import java.io.Serial;
 import java.io.Serializable;
+import java.util.List;
 
 /**
  * 【请填写功能名称】视图对象 blind_structures
@@ -54,4 +55,15 @@ public class BlindStructuresVo implements Serializable {
     private Date updatedAt;
 
 
+    private List<BlindLevelsVo> blindLevels;
+
+
+    private Long createUserId;
+
+
+    private Long updateUserId;
+
+    private String createName;
+
+
 }

+ 130 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/domain/vo/FileUploadTaskVo.java

@@ -0,0 +1,130 @@
+package org.dromara.business.domain.vo;
+
+import java.util.Date;
+
+import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
+import cn.idev.excel.annotation.ExcelProperty;
+import org.dromara.business.domain.FileUploadTask;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+
+
+/**
+ * 【请填写功能名称】视图对象 file_upload_task
+ *
+ * @author Lion Li
+ * @date 2025-06-27
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = FileUploadTask.class)
+public class FileUploadTaskVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     *
+     */
+    @ExcelProperty(value = "")
+    private Long id;
+
+    /**
+     * 任务ID
+     */
+    @ExcelProperty(value = "任务ID")
+    private String taskId;
+
+    /**
+     * 文件名称
+     */
+    @ExcelProperty(value = "文件名称")
+    private String fileName;
+
+    /**
+     * 错误消息
+     */
+    @ExcelProperty(value = "错误消息")
+    private String errorMessage;
+
+    /**
+     * 状态
+     */
+    @ExcelProperty(value = "状态")
+    private String status;
+
+    /**
+     * 上传时间
+     */
+    @ExcelProperty(value = "上传时间")
+    private Date uploadTime;
+
+    /**
+     * 完成时间
+     */
+    @ExcelProperty(value = "完成时间")
+    private Date finishTime;
+
+    /**
+     * 备注
+     */
+    @ExcelProperty(value = "备注")
+    private String remark;
+
+    /**
+     * 后台端用户ID(上传人)
+     */
+    @ExcelProperty(value = "后台端用户ID", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(readConverterExp = "上=传人")
+    private Long userId;
+
+    /**
+     * 文件地址
+     */
+    @ExcelProperty(value = "文件地址")
+    private String fileUrl;
+
+    /**
+     * 已尝试重试次数
+     */
+    @ExcelProperty(value = "已尝试重试次数")
+    private Integer retryCount;
+
+    /**
+     * 最大重试次数
+     */
+    @ExcelProperty(value = "最大重试次数")
+    private Integer maxRetry;
+
+    /**
+     * 文件大小
+     */
+    @ExcelProperty(value = "文件大小")
+    private Integer fileSize;
+
+    /**
+     * 总行数
+     */
+    @ExcelProperty(value = "总行数")
+    private Integer totalRows;
+
+    /**
+     * 成功并入库的行数
+     */
+    @ExcelProperty(value = "成功并入库的行数")
+    private Integer successRows;
+
+    /**
+     * 失败数
+     */
+    @ExcelProperty(value = "失败数")
+    private Integer failedRows;
+
+
+}

+ 3 - 1
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/mapper/BlindLevelsMapper.java

@@ -38,8 +38,10 @@ public interface BlindLevelsMapper extends BaseMapperPlus<BlindLevels, BlindLeve
     int deleteBlindLevelById(@Param("ids") Collection<Long> ids);
 
     @InterceptorIgnore(tenantLine = "true")
-    List<BlindLevelsVo> selectBlindStructuresVoList(@Param("ew") Wrapper<BlindLevels> wrapper);
+    List<BlindLevelsVo> selectBlindLevelVoList(@Param("ew") Wrapper<BlindLevels> wrapper);
 
+    @InterceptorIgnore(tenantLine = "true")
+    int deleteBlindLevelByBlindStructureId(Long blindStructureId);
 
 
 

+ 29 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/mapper/FileUploadTaskMapper.java

@@ -0,0 +1,29 @@
+package org.dromara.business.mapper;
+
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
+import org.dromara.business.domain.FileUploadTask;
+import org.dromara.business.domain.vo.FileUploadTaskVo;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+
+/**
+ * 【请填写功能名称】Mapper接口
+ *
+ * @author Lion Li
+ * @date 2025-06-27
+ */
+
+@DS("mysql2")
+public interface FileUploadTaskMapper extends BaseMapperPlus<FileUploadTask, FileUploadTaskVo> {
+
+    @InterceptorIgnore(tenantLine = "true")
+    FileUploadTaskVo selectFileUploadTaskInfoByTaskId(String taskId);
+
+    @InterceptorIgnore(tenantLine = "true")
+    int insertFileUploadTask(FileUploadTask insert);
+
+    @InterceptorIgnore(tenantLine = "true")
+    int updateFileUploadTaskById(FileUploadTask uploadTask);
+
+
+}

+ 10 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/service/IBlindLevelsService.java

@@ -65,4 +65,14 @@ public interface IBlindLevelsService {
      * @return 是否删除成功
      */
     Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
+
+
+    /**
+     * 删除【盲注结构对应的相关等级信息】信息
+     *
+     * @param id 主键
+     * @return 是否删除成功
+     */
+    Boolean deleteBlindLevelByBlindStructureId(Long blindStructureId);
+
 }

+ 4 - 2
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/service/IBlindStructuresService.java

@@ -2,8 +2,10 @@ package org.dromara.business.service;
 
 import org.dromara.business.domain.vo.BlindStructuresVo;
 import org.dromara.business.domain.bo.BlindStructuresBo;
+import org.dromara.common.core.domain.R;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
 import org.dromara.common.mybatis.core.page.PageQuery;
+import org.springframework.web.multipart.MultipartFile;
 
 import java.util.Collection;
 import java.util.List;
@@ -47,7 +49,7 @@ public interface IBlindStructuresService {
      * @param bo 【请填写功能名称】
      * @return 是否新增成功
      */
-    Boolean insertByBo(BlindStructuresBo bo);
+    R<Boolean> insertByBo(BlindStructuresBo bo, MultipartFile file);
 
     /**
      * 修改【请填写功能名称】
@@ -55,7 +57,7 @@ public interface IBlindStructuresService {
      * @param bo 【请填写功能名称】
      * @return 是否修改成功
      */
-    Boolean updateByBo(BlindStructuresBo bo);
+    R<Boolean> updateByBo(BlindStructuresBo bo, MultipartFile file);
 
     /**
      * 校验并批量删除【请填写功能名称】信息

+ 102 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/service/IFileUploadTaskService.java

@@ -0,0 +1,102 @@
+package org.dromara.business.service;
+
+import org.dromara.business.domain.bo.FileUploadTaskBo;
+import org.dromara.business.domain.vo.FileUploadTaskVo;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 【请填写功能名称】Service接口
+ *
+ * @author Lion Li
+ * @date 2025-06-27
+ */
+public interface IFileUploadTaskService {
+
+    /**
+     * 查询【请填写功能名称】
+     *
+     * @param id 主键
+     * @return 【请填写功能名称】
+     */
+    FileUploadTaskVo queryById(Long id);
+
+    /**
+     * 分页查询【请填写功能名称】列表
+     *
+     * @param bo        查询条件
+     * @param pageQuery 分页参数
+     * @return 【请填写功能名称】分页列表
+     */
+    TableDataInfo<FileUploadTaskVo> queryPageList(FileUploadTaskBo bo, PageQuery pageQuery);
+
+    /**
+     * 查询符合条件的【请填写功能名称】列表
+     *
+     * @param bo 查询条件
+     * @return 【请填写功能名称】列表
+     */
+    List<FileUploadTaskVo> queryList(FileUploadTaskBo bo);
+
+    /**
+     * 新增【请填写功能名称】
+     *
+     * @param bo 【请填写功能名称】
+     * @return 是否新增成功
+     */
+    Boolean insertByBo(FileUploadTaskBo bo);
+
+    /**
+     * 修改【请填写功能名称】
+     *
+     * @param bo 【请填写功能名称】
+     * @return 是否修改成功
+     */
+    Boolean updateByBo(FileUploadTaskBo bo);
+
+    /**
+     * 校验并批量删除【请填写功能名称】信息
+     *
+     * @param ids     待删除的主键集合
+     * @param isValid 是否进行有效性校验
+     * @return 是否删除成功
+     */
+    Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
+
+
+    /**
+     * 上传文件
+     *
+     * @param file 文件
+     * @param userId 用户ID
+     * @return 任务ID
+     */
+    String handleFileUpload(MultipartFile file, Long userId);
+
+
+    /**
+     * 根据任务ID查询任务信息
+     *
+     * @param taskId 任务ID
+     * @return 任务信息
+     */
+    FileUploadTaskVo selectFileUploadTaskInfoByTaskId(String taskId);
+
+    /**
+     * 重试上传
+     *
+     * @param taskId 任务ID
+     * @param userId 用户ID
+     * @return 是否成功
+     */
+    R<Void> retryUpload(String taskId, Long userId);
+
+
+
+
+}

+ 6 - 1
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/service/impl/BlindLevelsServiceImpl.java

@@ -66,7 +66,7 @@ public class BlindLevelsServiceImpl implements IBlindLevelsService {
     @Override
     public List<BlindLevelsVo> queryList(BlindLevelsBo bo) {
         LambdaQueryWrapper<BlindLevels> lqw = buildQueryWrapper(bo);
-        return baseMapper.selectBlindStructuresVoList(lqw);
+        return baseMapper.selectBlindLevelVoList(lqw);
     }
 
     private LambdaQueryWrapper<BlindLevels> buildQueryWrapper(BlindLevelsBo bo) {
@@ -135,4 +135,9 @@ public class BlindLevelsServiceImpl implements IBlindLevelsService {
         }
         return baseMapper.deleteBlindLevelById(ids) > 0;
     }
+
+    @Override
+    public Boolean deleteBlindLevelByBlindStructureId(Long blindStructureId) {
+        return baseMapper.deleteBlindLevelByBlindStructureId(blindStructureId)>0;
+    }
 }

+ 193 - 11
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/service/impl/BlindStructuresServiceImpl.java

@@ -1,4 +1,13 @@
 package org.dromara.business.service.impl;
+import cn.idev.excel.EasyExcel;
+import cn.idev.excel.context.AnalysisContext;
+import cn.idev.excel.event.AnalysisEventListener;
+import org.apache.commons.collections4.CollectionUtils;
+import org.dromara.business.domain.bo.BlindLevelsBo;
+import org.dromara.business.domain.vo.BlindLevelsImportVo;
+import org.dromara.business.service.IBlindLevelsService;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.service.UserService;
 import org.dromara.common.core.utils.MapstructUtils;
 import org.dromara.common.core.utils.StringUtils;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
@@ -8,13 +17,18 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.satoken.utils.LoginHelper;
 import org.springframework.stereotype.Service;
 import org.dromara.business.domain.bo.BlindStructuresBo;
 import org.dromara.business.domain.vo.BlindStructuresVo;
 import org.dromara.business.domain.BlindStructures;
 import org.dromara.business.mapper.BlindStructuresMapper;
 import org.dromara.business.service.IBlindStructuresService;
+import org.springframework.web.multipart.MultipartFile;
 
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import java.util.Collection;
@@ -32,6 +46,9 @@ public class BlindStructuresServiceImpl implements IBlindStructuresService {
 
     private final BlindStructuresMapper baseMapper;
 
+    private final IBlindLevelsService blindLevelsService;
+
+    private final UserService userService;
     /**
      * 查询【请填写功能名称】
      *
@@ -54,6 +71,17 @@ public class BlindStructuresServiceImpl implements IBlindStructuresService {
     public TableDataInfo<BlindStructuresVo> queryPageList(BlindStructuresBo bo, PageQuery pageQuery) {
         LambdaQueryWrapper<BlindStructures> lqw = buildQueryWrapper(bo);
         Page<BlindStructuresVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+        List<BlindStructuresVo> resultRecords = result.getRecords();
+       for (BlindStructuresVo record : resultRecords) {
+           BlindLevelsBo blindLevelsBo=new BlindLevelsBo();
+           record.setBlindLevels(blindLevelsService.queryList(blindLevelsBo));
+           if(record.getCreateUserId()!=null){
+               String createName = userService.selectUserNameById(record.getCreateUserId());
+               record.setCreateName(createName);
+           }
+
+       }
+
         return TableDataInfo.build(result);
     }
 
@@ -87,16 +115,77 @@ public class BlindStructuresServiceImpl implements IBlindStructuresService {
      * @return 是否新增成功
      */
     @Override
-    public Boolean insertByBo(BlindStructuresBo bo) {
-        BlindStructures add = MapstructUtils.convert(bo, BlindStructures.class);
-        validEntityBeforeSave(add);
-        boolean flag = baseMapper.insertBlindStructures(add) > 0;
-        if (flag) {
-            bo.setId(add.getId());
+    public R<Boolean> insertByBo(BlindStructuresBo bo, MultipartFile file) {
+        try {
+            // 1. 转换 BO -> PO
+            BlindStructures add = MapstructUtils.convert(bo, BlindStructures.class);
+            validEntityBeforeSave(add);
+
+            // 2. 解析 Excel 文件
+            List<BlindLevelsImportVo> dataList;
+            try (InputStream inputStream = file.getInputStream()) {
+                dataList = parseExcel(inputStream);
+            } catch (IOException e) {
+                log.error("读取文件失败", e);
+                return R.fail("读取文件失败");
+            }
+
+            if (CollectionUtils.isEmpty(dataList)) {
+                return R.fail("导入数据为空");
+            }
+
+            // 3. 校验数据逻辑(可选)
+       /*     if (!validateData(dataList)) {
+                return R.fail("导入数据校验失败,请检查等级顺序或数值是否正确");
+            }*/
+            Long userId = LoginHelper.getUserId();
+            add.setCreateUserId(userId);
+            // 4. 插入主表
+            boolean flag = baseMapper.insertBlindStructures(add) > 0;
+            if (!flag) {
+                return R.fail("插入主表失败");
+            }
+
+            bo.setId(add.getId()); // 同步 ID
+
+            // 5. 插入子表数据
+            for (BlindLevelsImportVo vo : dataList) {
+                BlindLevelsBo levelBo = new BlindLevelsBo();
+                levelBo.setBlindStructureId(add.getId());
+                levelBo.setLevelNumber(vo.getLevelNumber());
+                levelBo.setSmallBlind(vo.getSmallBlind());
+                levelBo.setBigBlind(vo.getBigBlind());
+                levelBo.setAnte(vo.getAnte());
+                levelBo.setDurationMinutes(vo.getDurationMinutes());
+                levelBo.setCreateUserId(userId);
+                blindLevelsService.insertByBo(levelBo);
+            }
+
+            return R.ok(true); // 成功返回
+
+        } catch (Exception e) {
+            log.error("插入盲注结构失败", e);
+            throw e; // 抛出异常以触发事务回滚
         }
-        return flag;
     }
 
+    // 解析 Excel 方法
+    private List<BlindLevelsImportVo> parseExcel(InputStream inputStream) {
+        List<BlindLevelsImportVo> list = new ArrayList<>();
+        EasyExcel.read(inputStream, BlindLevelsImportVo.class, new AnalysisEventListener<BlindLevelsImportVo>() {
+            @Override
+            public void invoke(BlindLevelsImportVo data, AnalysisContext context) {
+                list.add(data);
+            }
+
+            @Override
+            public void doAfterAllAnalysed(AnalysisContext context) {
+                // 解析完成
+            }
+        }).sheet().doRead();
+
+        return list;
+    }
     /**
      * 修改【请填写功能名称】
      *
@@ -104,10 +193,58 @@ public class BlindStructuresServiceImpl implements IBlindStructuresService {
      * @return 是否修改成功
      */
     @Override
-    public Boolean updateByBo(BlindStructuresBo bo) {
-        BlindStructures update = MapstructUtils.convert(bo, BlindStructures.class);
-        validEntityBeforeSave(update);
-        return baseMapper.updateBlindStructuresById(update) > 0;
+    //@Transactional(rollbackFor = Exception.class) // 开启事务
+    public R<Boolean> updateByBo(BlindStructuresBo bo, MultipartFile file) {
+        try {
+            // 1. 转换 BO -> PO
+            BlindStructures update = MapstructUtils.convert(bo, BlindStructures.class);
+            validEntityBeforeSave(update);
+            Long userId = LoginHelper.getUserId();
+            update.setUpdateUserId(userId);
+            // 2. 更新主表
+            int i = baseMapper.updateBlindStructuresById(update);
+            if (i <= 0) {
+                return R.fail("更新失败");
+            }
+
+            // 3. 删除原有等级数据
+            Boolean b = blindLevelsService.deleteBlindLevelByBlindStructureId(update.getId());
+            if (!b) {
+                return R.fail("删除历史等级失败");
+            }
+
+            // 4. 解析 Excel 文件
+            List<BlindLevelsImportVo> dataList;
+            try (InputStream inputStream = file.getInputStream()) {
+                dataList = parseExcel(inputStream);
+            } catch (IOException e) {
+                log.error("读取文件失败", e);
+                return R.fail("读取文件失败");
+            }
+
+            if (CollectionUtils.isEmpty(dataList)) {
+                return R.fail("导入数据为空");
+            }
+
+            // 5. 插入新等级数据
+            for (BlindLevelsImportVo vo : dataList) {
+                BlindLevelsBo levelBo = new BlindLevelsBo();
+                levelBo.setBlindStructureId(update.getId());
+                levelBo.setLevelNumber(vo.getLevelNumber());
+                levelBo.setSmallBlind(vo.getSmallBlind());
+                levelBo.setBigBlind(vo.getBigBlind());
+                levelBo.setAnte(vo.getAnte());
+                levelBo.setDurationMinutes(vo.getDurationMinutes());
+                levelBo.setCreateUserId(userId);
+                blindLevelsService.insertByBo(levelBo);
+            }
+
+            return R.ok(true); // 成功返回 true
+
+        } catch (Exception e) {
+            log.error("更新盲注结构失败", e);
+            throw e; // 抛出异常触发事务回滚
+        }
     }
 
     /**
@@ -131,4 +268,49 @@ public class BlindStructuresServiceImpl implements IBlindStructuresService {
         }
         return baseMapper.deleteBlindStructuresByIds(ids) > 0;
     }
+
+
+
+
+    public static boolean validateData(List<BlindLevelsImportVo> dataList) {
+        if (dataList == null || dataList.isEmpty()) {
+            return false;
+        }
+
+        return validateDataRecursively(dataList, 0);
+    }
+
+    private static boolean validateDataRecursively(List<BlindLevelsImportVo> dataList, int currentIndex) {
+        if (currentIndex >= dataList.size() - 1) {
+            return true;
+        }
+
+        BlindLevelsImportVo current = dataList.get(currentIndex);
+        BlindLevelsImportVo next = dataList.get(currentIndex + 1);
+
+        // Check if levels are continuous
+        if (current.getLevelNumber() + 1 != next.getLevelNumber()) {
+            System.out.println("Error: Levels are not continuous at index " + currentIndex);
+            return false;
+        }
+
+        // Check if values are increasing
+        if (current.getSmallBlind() >= next.getSmallBlind() ||
+            current.getBigBlind() >= next.getBigBlind() ||
+            current.getAnte() >= next.getAnte()) {
+            System.out.println("Error: Values are not increasing at index " + currentIndex);
+            return false;
+        }
+
+        // Check if upgrade time is positive
+        if (next.getDurationMinutes() <= 0){
+            System.out.println("Error: Upgrade time is not positive at index " + (currentIndex + 1));
+            return false;
+        }
+
+        return validateDataRecursively(dataList, currentIndex + 1);
+    }
+
+
+
 }

+ 294 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/service/impl/FileUploadTaskServiceImpl.java

@@ -0,0 +1,294 @@
+package org.dromara.business.service.impl;
+
+import cn.idev.excel.EasyExcel;
+import cn.idev.excel.context.AnalysisContext;
+import cn.idev.excel.event.AnalysisEventListener;
+import cn.idev.excel.read.listener.ReadListener;
+import org.dromara.business.domain.FileUploadTask;
+import org.dromara.business.domain.bo.FileUploadTaskBo;
+import org.dromara.business.domain.vo.BlindLevelsImportVo;
+import org.dromara.business.domain.vo.BlindLevelsVo;
+import org.dromara.business.domain.vo.FileUploadTaskVo;
+import org.dromara.business.mapper.FileUploadTaskMapper;
+import org.dromara.business.service.IFileUploadTaskService;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.system.domain.vo.SysOssVo;
+import org.dromara.system.service.ISysOssService;
+import org.springframework.beans.BeanUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+import java.io.InputStream;
+import java.util.*;
+
+/**
+ * 【请填写功能名称】Service业务层处理
+ *
+ * @author Lion Li
+ * @date 2025-06-27
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class FileUploadTaskServiceImpl implements IFileUploadTaskService {
+
+    private final FileUploadTaskMapper baseMapper;
+
+
+    private final ISysOssService ossService;
+
+    /**
+     * 查询【请填写功能名称】
+     *
+     * @param id 主键
+     * @return 【请填写功能名称】
+     */
+    @Override
+    public FileUploadTaskVo queryById(Long id){
+        return baseMapper.selectVoById(id);
+    }
+
+    /**
+     * 分页查询【请填写功能名称】列表
+     *
+     * @param bo        查询条件
+     * @param pageQuery 分页参数
+     * @return 【请填写功能名称】分页列表
+     */
+    @Override
+    public TableDataInfo<FileUploadTaskVo> queryPageList(FileUploadTaskBo bo, PageQuery pageQuery) {
+        LambdaQueryWrapper<FileUploadTask> lqw = buildQueryWrapper(bo);
+        Page<FileUploadTaskVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+        return TableDataInfo.build(result);
+    }
+
+    /**
+     * 查询符合条件的【请填写功能名称】列表
+     *
+     * @param bo 查询条件
+     * @return 【请填写功能名称】列表
+     */
+    @Override
+    public List<FileUploadTaskVo> queryList(FileUploadTaskBo bo) {
+        LambdaQueryWrapper<FileUploadTask> lqw = buildQueryWrapper(bo);
+        return baseMapper.selectVoList(lqw);
+    }
+
+    private LambdaQueryWrapper<FileUploadTask> buildQueryWrapper(FileUploadTaskBo bo) {
+        Map<String, Object> params = bo.getParams();
+        LambdaQueryWrapper<FileUploadTask> lqw = Wrappers.lambdaQuery();
+        lqw.orderByAsc(FileUploadTask::getId);
+        lqw.eq(StringUtils.isNotBlank(bo.getTaskId()), FileUploadTask::getTaskId, bo.getTaskId());
+        lqw.like(StringUtils.isNotBlank(bo.getFileName()), FileUploadTask::getFileName, bo.getFileName());
+        lqw.eq(StringUtils.isNotBlank(bo.getErrorMessage()), FileUploadTask::getErrorMessage, bo.getErrorMessage());
+        lqw.eq(StringUtils.isNotBlank(bo.getStatus()), FileUploadTask::getStatus, bo.getStatus());
+        lqw.eq(bo.getUploadTime() != null, FileUploadTask::getUploadTime, bo.getUploadTime());
+        lqw.eq(bo.getFinishTime() != null, FileUploadTask::getFinishTime, bo.getFinishTime());
+        lqw.eq(bo.getUserId() != null, FileUploadTask::getUserId, bo.getUserId());
+        lqw.eq(StringUtils.isNotBlank(bo.getFileUrl()), FileUploadTask::getFileUrl, bo.getFileUrl());
+        lqw.eq(bo.getRetryCount() != null, FileUploadTask::getRetryCount, bo.getRetryCount());
+        lqw.eq(bo.getMaxRetry() != null, FileUploadTask::getMaxRetry, bo.getMaxRetry());
+        lqw.eq(bo.getFileSize() != null, FileUploadTask::getFileSize, bo.getFileSize());
+        lqw.eq(bo.getTotalRows() != null, FileUploadTask::getTotalRows, bo.getTotalRows());
+        lqw.eq(bo.getSuccessRows() != null, FileUploadTask::getSuccessRows, bo.getSuccessRows());
+        lqw.eq(bo.getFailedRows() != null, FileUploadTask::getFailedRows, bo.getFailedRows());
+        return lqw;
+    }
+
+    /**
+     * 新增【请填写功能名称】
+     *
+     * @param bo 【请填写功能名称】
+     * @return 是否新增成功
+     */
+    @Override
+    public Boolean insertByBo(FileUploadTaskBo bo) {
+        FileUploadTask add = MapstructUtils.convert(bo, FileUploadTask.class);
+        validEntityBeforeSave(add);
+        boolean flag = baseMapper.insert(add) > 0;
+        if (flag) {
+            bo.setId(add.getId());
+        }
+        return flag;
+    }
+
+    /**
+     * 修改【请填写功能名称】
+     *
+     * @param bo 【请填写功能名称】
+     * @return 是否修改成功
+     */
+    @Override
+    public Boolean updateByBo(FileUploadTaskBo bo) {
+        FileUploadTask update = MapstructUtils.convert(bo, FileUploadTask.class);
+        validEntityBeforeSave(update);
+        return baseMapper.updateById(update) > 0;
+    }
+
+    /**
+     * 保存前的数据校验
+     */
+    private void validEntityBeforeSave(FileUploadTask entity){
+        //TODO 做一些数据校验,如唯一约束
+    }
+
+    /**
+     * 校验并批量删除【请填写功能名称】信息
+     *
+     * @param ids     待删除的主键集合
+     * @param isValid 是否进行有效性校验
+     * @return 是否删除成功
+     */
+    @Override
+    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
+        if(isValid){
+            //TODO 做一些业务上的校验,判断是否需要校验
+        }
+        return baseMapper.deleteByIds(ids) > 0;
+    }
+
+    @Override
+    public String handleFileUpload(MultipartFile file, Long userId) {
+        String taskId = UUID.randomUUID().toString();
+
+        FileUploadTask task = new FileUploadTask();
+        task.setId(System.currentTimeMillis());
+        task.setTaskId(taskId);
+        task.setFileName(file.getOriginalFilename());
+        task.setStatus("UPLOADING");
+        task.setUserId(userId);
+        task.setUploadTime(new Date());
+        task.setRetryCount(0);
+        task.setMaxRetry(3);
+        baseMapper.insertFileUploadTask(task);
+
+        // 使用 CompletableFuture 实现异步上传
+   /*     CompletableFuture.runAsync(() -> processUpload(taskId, file));*/
+
+        processUpload(taskId, file);
+
+        return taskId;
+
+    }
+
+    @Override
+    public FileUploadTaskVo selectFileUploadTaskInfoByTaskId(String taskId) {
+        return baseMapper.selectFileUploadTaskInfoByTaskId(taskId);
+    }
+
+    @Override
+    public R<Void> retryUpload(String taskId, Long userId) {
+        FileUploadTaskVo task = baseMapper.selectFileUploadTaskInfoByTaskId(taskId);
+        if (task== null) {
+            return R.fail("任务不存在");
+        }
+
+
+        if (!"FAILED".equals(task.getStatus())) {
+            return R.fail("只有失败的任务才可以重试一下");
+        }
+
+        if (task.getRetryCount() >= task.getMaxRetry()) {
+            return R.fail("重试次数超出");
+        }
+
+        // 获取原始文件内容(假设已缓存或可从 OSS 下载)  todo 需要加逻辑
+        MultipartFile file = null; // 这里需要你根据实际情况获取原始文件流
+        if (file == null) {
+            return R.fail("无法获取原始文件进行重试");
+        }
+
+
+        FileUploadTask task2 = new FileUploadTask();
+        BeanUtils.copyProperties(task, task2);
+        task2.setStatus("UPLOADING");
+        task2.setRetryCount(task.getRetryCount() + 1);
+        task2.setUploadTime(new Date());
+        task2.setFinishTime(null);
+        task2.setErrorMessage(null);
+        baseMapper.updateFileUploadTaskById(task2);
+
+        //TODO 做文件校验
+
+
+        // 异步执行重传任务
+   /*     CompletableFuture.runAsync(() -> processUpload(taskId, file));*/
+        processUpload(taskId, file);
+        return R.ok();
+    }
+
+
+    private void processUpload(String taskId, MultipartFile file) {
+        try {
+            // 1. 上传文件到 OSS
+            SysOssVo sysOssVo = ossService.upload(file);
+            String fileUrl=sysOssVo.getUrl();
+            // 2. 解析 Excel 并入库
+            List<BlindLevelsImportVo> dataList = parseExcel(file.getInputStream());
+            // 3. 更新成功状态
+            updateTaskSuccess(taskId, fileUrl, sysOssVo.getOssId(),dataList.size(), 0);
+
+        } catch (Exception e) {
+            updateTaskFailed(taskId, e.getMessage());
+        }
+    }
+
+
+    // 解析 Excel 方法
+    private List<BlindLevelsImportVo> parseExcel(InputStream inputStream) {
+        List<BlindLevelsImportVo> list = new ArrayList<>();
+        EasyExcel.read(inputStream, BlindLevelsImportVo.class, new AnalysisEventListener<BlindLevelsImportVo>() {
+            @Override
+            public void invoke(BlindLevelsImportVo data, AnalysisContext context) {
+                list.add(data);
+            }
+
+            @Override
+            public void doAfterAllAnalysed(AnalysisContext context) {
+                // 解析完成
+            }
+        }).sheet().doRead();
+
+        return list;
+    }
+
+
+
+    private void updateTaskSuccess(String taskId, String fileUrl,Long ossId,int total, int success) {
+        FileUploadTaskVo fileUploadTaskVo = baseMapper.selectFileUploadTaskInfoByTaskId(taskId);
+        FileUploadTask task = new FileUploadTask();
+        BeanUtils.copyProperties(fileUploadTaskVo, task);
+        task.setStatus("SUCCESS");
+        task.setFileUrl(fileUrl);
+        task.setFinishTime(new Date());
+        task.setTotalRows(total);
+        task.setSuccessRows(success);
+        task.setFailedRows(total - success);
+        task.setOssId(ossId);
+        baseMapper.updateFileUploadTaskById(task);
+    }
+
+
+    private void updateTaskFailed(String taskId, String errorMessage) {
+        FileUploadTaskVo fileUploadTaskVo = baseMapper.selectFileUploadTaskInfoByTaskId(taskId);
+        FileUploadTask task = new FileUploadTask();
+        BeanUtils.copyProperties(fileUploadTaskVo, task);
+        task.setStatus("FAILED");
+        task.setErrorMessage(errorMessage);
+        task.setId(fileUploadTaskVo.getId());
+        baseMapper.updateFileUploadTaskById(task);
+    }
+
+
+
+
+
+}

+ 1 - 1
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysOssController.java

@@ -27,7 +27,7 @@ import java.util.Arrays;
 import java.util.List;
 
 /**
- * 文件上传 控制层
+ * 文件上传 控制层2
  *
  * @author Lion Li
  */

+ 6 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserImportVo.java

@@ -73,4 +73,10 @@ public class SysUserImportVo implements Serializable {
     @ExcelDictFormat(dictType = "sys_normal_disable")
     private String status;
 
+
+    private Long createUserId;
+
+
+    private Long updateUserId;
+
 }

+ 8 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOssService.java

@@ -77,4 +77,12 @@ public interface ISysOssService {
      */
     Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
 
+
+
+
+
+
+
+
+
 }

+ 1 - 1
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssServiceImpl.java

@@ -185,7 +185,7 @@ public class SysOssServiceImpl implements ISysOssService, OssService {
      * 上传 MultipartFile 到对象存储服务,并保存文件信息到数据库
      *
      * @param file 要上传的 MultipartFile 对象
-     * @return 上传成功后的 SysOssVo 对象,包含文件信息
+     * @return 上传成功后的 SysOssVo 对象,包含文件信息2
      * @throws ServiceException 如果上传过程中发生异常,则抛出 ServiceException 异常
      */
     @Override

+ 4 - 0
ruoyi-modules/ruoyi-system/src/main/resources/mapper/business/BlindLevelsMapper.xml

@@ -133,4 +133,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         </where>
     </delete>
 
+    <delete id="deleteBlindLevelByBlindStructureId">
+        DELETE FROM blind_levels where  blind_structure_id=#{blindStructureId}
+    </delete>
+
 </mapper>

+ 9 - 3
ruoyi-modules/ruoyi-system/src/main/resources/mapper/business/BlindStructuresMapper.xml

@@ -5,17 +5,17 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 <mapper namespace="org.dromara.business.mapper.BlindStructuresMapper">
 
     <select id="selectVoPage" resultType="org.dromara.business.domain.vo.BlindStructuresVo">
-        SELECT id, name, description, created_at, updated_at
+        SELECT id, name, description, created_at, updated_at, create_user_id, update_user_id
         FROM blind_structures ${ew.customSqlSegment}
     </select>
 
 
     <select id="selectBlindStructuresVoList" resultType="org.dromara.business.domain.vo.BlindStructuresVo">
-        SELECT  id, name, description, created_at, updated_at FROM blind_structures  ${ew.customSqlSegment}
+        SELECT  id, name, description, created_at, updated_at, create_user_id, update_user_id FROM blind_structures  ${ew.customSqlSegment}
     </select>
 
     <select id="selectVoByIdInfo" resultType="org.dromara.business.domain.vo.BlindStructuresVo">
-       SELECT  id, name, description, created_at, updated_at FROM blind_structures WHERE id =  #{id}
+       SELECT  id, name, description, created_at, updated_at, create_user_id, update_user_id FROM blind_structures WHERE id =  #{id}
     </select>
 
 
@@ -29,6 +29,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="description != null and description != ''">
                 description = #{description},
             </if>
+            <if test="updateUserId != null and updateUserId != ''">
+                update_user_id = #{updateUserId},
+            </if>
             updated_at = NOW()
         </set>
         WHERE id = #{id}
@@ -40,10 +43,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <trim prefix="(" suffix=")" suffixOverrides=",">
             <if test="name != null and name != ''">name,</if>
             <if test="description != null and description != ''">description,</if>
+            <if test="createUserId != null and createUserId != ''">create_user_id,</if>
+
         </trim>
         <trim prefix="VALUES (" suffix=")" suffixOverrides=",">
             <if test="name != null and name != ''">#{name},</if>
             <if test="description != null and description != ''">#{description},</if>
+            <if test="createUserId != null and createUserId != ''">#{createUserId},</if>
         </trim>
     </insert>
 

+ 79 - 0
ruoyi-modules/ruoyi-system/src/main/resources/mapper/business/FileUploadTaskMapper.xml

@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.business.mapper.FileUploadTaskMapper">
+
+
+    <select id="selectFileUploadTaskInfoByTaskId" resultType="org.dromara.business.domain.vo.FileUploadTaskVo">
+        SELECT *  FROM file_upload_task  where task_id=#{taskId}
+    </select>
+
+
+    <insert id="insertFileUploadTask"  useGeneratedKeys="true" keyProperty="id">
+        INSERT INTO file_upload_task
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="taskId != null and taskId != ''">task_id,</if>
+            <if test="fileName != null and fileName != ''">file_name,</if>
+            <if test="errorMessage != null and errorMessage != ''">error_message,</if>
+            <if test="status != null and status != ''">status,</if>
+            <if test="uploadTime != null">upload_time,</if>
+            <if test="finishTime != null">finish_time,</if>
+            <if test="remark != null and remark != ''">remark,</if>
+            <if test="userId != null">user_id,</if>
+            <if test="fileUrl != null and fileUrl != ''">file_url,</if>
+            <if test="retryCount != null">retry_count,</if>
+            <if test="maxRetry != null">max_retry,</if>
+            <if test="fileSize != null">file_size,</if>
+            <if test="totalRows != null">total_rows,</if>
+            <if test="successRows != null">success_rows,</if>
+            <if test="failedRows != null">failed_rows,</if>
+            <if test="ossId != null">oss_id,</if>
+        </trim>
+        VALUES
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="taskId != null and taskId != ''">#{taskId},</if>
+            <if test="fileName != null and fileName != ''">#{fileName},</if>
+            <if test="errorMessage != null and errorMessage != ''">#{errorMessage},</if>
+            <if test="status != null and status != ''">#{status},</if>
+            <if test="uploadTime != null">#{uploadTime},</if>
+            <if test="finishTime != null">#{finishTime},</if>
+            <if test="remark != null and remark != ''">#{remark},</if>
+            <if test="userId != null">#{userId},</if>
+            <if test="fileUrl != null and fileUrl != ''">#{fileUrl},</if>
+            <if test="retryCount != null">#{retryCount},</if>
+            <if test="maxRetry != null">#{maxRetry},</if>
+            <if test="fileSize != null">#{fileSize},</if>
+            <if test="totalRows != null">#{totalRows},</if>
+            <if test="successRows != null">#{successRows},</if>
+            <if test="failedRows != null">#{failedRows},</if>
+            <if test="ossId != null">#{ossId},</if>
+        </trim>
+    </insert>
+
+
+    <update id="updateFileUploadTaskById">
+        UPDATE file_upload_task
+        <set>
+            <if test="taskId != null and taskId != ''">task_id = #{taskId},</if>
+            <if test="fileName != null and fileName != ''">file_name = #{fileName},</if>
+            <if test="errorMessage != null and errorMessage != ''">error_message = #{errorMessage},</if>
+            <if test="status != null and status != ''">status = #{status},</if>
+            <if test="uploadTime != null">upload_time = #{uploadTime},</if>
+            <if test="finishTime != null">finish_time = #{finishTime},</if>
+            <if test="remark != null and remark != ''">remark = #{remark},</if>
+            <if test="userId != null">user_id = #{userId},</if>
+            <if test="fileUrl != null and fileUrl != ''">file_url = #{fileUrl},</if>
+            <if test="retryCount != null">retry_count = #{retryCount},</if>
+            <if test="maxRetry != null">max_retry = #{maxRetry},</if>
+            <if test="fileSize != null">file_size = #{fileSize},</if>
+            <if test="totalRows != null">total_rows = #{totalRows},</if>
+            <if test="successRows != null">success_rows = #{successRows},</if>
+            <if test="failedRows != null">failed_rows = #{failedRows},</if>
+            <if test="ossId != null">oss_id = #{ossId},</if>
+        </set>
+        WHERE id = #{id}
+    </update>
+
+
+</mapper>