Browse Source

Merge branch 'refs/heads/feat-20250730-userexport' into pre

lixuesong 5 days ago
parent
commit
4761bf341c
33 changed files with 3247 additions and 427 deletions
  1. 5 0
      hnqz-common/hnqz-common-core/src/main/java/com/qunzhixinxi/hnqz/common/core/constant/CommonConstants.java
  2. 9 1
      hnqz-upms/hnqz-upms-api/src/main/java/com/qunzhixinxi/hnqz/admin/api/constant/enums/ExportType.java
  3. 30 0
      hnqz-upms/hnqz-upms-api/src/main/java/com/qunzhixinxi/hnqz/admin/api/constant/enums/TaskCheck.java
  4. 30 0
      hnqz-upms/hnqz-upms-api/src/main/java/com/qunzhixinxi/hnqz/admin/api/constant/enums/TaskSupervisionApproval.java
  5. 16 0
      hnqz-upms/hnqz-upms-api/src/main/java/com/qunzhixinxi/hnqz/admin/api/dto/WmPkgDTO.java
  6. 26 0
      hnqz-upms/hnqz-upms-api/src/main/java/com/qunzhixinxi/hnqz/admin/api/model/excel/TaskCheckConverter.java
  7. 239 63
      hnqz-upms/hnqz-upms-api/src/main/java/com/qunzhixinxi/hnqz/admin/api/model/excel/TaskCheckHistoryExcelModel.java
  8. 26 0
      hnqz-upms/hnqz-upms-api/src/main/java/com/qunzhixinxi/hnqz/admin/api/model/excel/TaskSupervisionApprovalConverter.java
  9. 561 0
      hnqz-upms/hnqz-upms-api/src/main/java/com/qunzhixinxi/hnqz/admin/api/model/excel/WmScorePackageSubInfoExcelModel.java
  10. 20 0
      hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/aspect/ExportGuard.java
  11. 50 0
      hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/aspect/ExportGuardAspect.java
  12. 50 0
      hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/config/RetryConfiguration.java
  13. 10 0
      hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/config/UpmsConfig.java
  14. 24 168
      hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/controller/init/InitController.java
  15. 74 0
      hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/controller/pkg/WmScorePackageExportController.java
  16. 17 2
      hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/controller/user/SysUserExportController.java
  17. 39 0
      hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/event/PackageExportEvent.java
  18. 26 0
      hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/event/TaskCheckSupExportEvent.java
  19. 36 0
      hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/listener/PackageExportEventListener.java
  20. 37 0
      hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/listener/TaskCheckSupExportEventListener.java
  21. 3 1
      hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/manager/WmPackageExportScope.java
  22. 6 0
      hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/mapper/WmTaskSupervisionMapper.java
  23. 22 0
      hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/service/SysCommonExportService.java
  24. 0 9
      hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/service/SysUserExportService.java
  25. 37 0
      hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/service/WmScorePackageExportService.java
  26. 17 0
      hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/service/WmTaskSupervisionService.java
  27. 69 0
      hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/service/impl/SysCommonExportServiceImpl.java
  28. 73 183
      hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/service/impl/SysUserExportServiceImpl.java
  29. 854 0
      hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/service/impl/WmScorePackageExportServiceImpl.java
  30. 48 0
      hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/service/impl/WmTaskSupervisionServiceImpl.java
  31. 93 0
      hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/util/ExportUtils.java
  32. 35 0
      hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/util/RedisUtils.java
  33. 665 0
      hnqz-upms/hnqz-upms-biz/src/main/resources/mapper/WmTaskSupervisionMapper.xml

+ 5 - 0
hnqz-common/hnqz-common-core/src/main/java/com/qunzhixinxi/hnqz/common/core/constant/CommonConstants.java

@@ -82,4 +82,9 @@ public interface CommonConstants {
 	 */
 	String IMAGE_CODE_TYPE = "blockPuzzle";
 
+	/**
+	 * 报告文件有效期
+	 */
+	long DEF_REPORT_TTL = 7L * 24 * 60 * 60 * 1000;
+
 }

+ 9 - 1
hnqz-upms/hnqz-upms-api/src/main/java/com/qunzhixinxi/hnqz/admin/api/constant/enums/ExportType.java

@@ -1,5 +1,7 @@
 package com.qunzhixinxi.hnqz.admin.api.constant.enums;
 
+import com.qunzhixinxi.hnqz.admin.api.constant.CacheConstants;
+
 import lombok.AllArgsConstructor;
 import lombok.Getter;
 
@@ -13,7 +15,9 @@ import lombok.Getter;
 @AllArgsConstructor
 public enum ExportType {
 
-	USER("USER", "人员信息");
+	USER("USER", "人员"),
+	CHECK_SUP("CHECK_SUP", "审核监督信息"),
+	SCORE_PACKAGE_SUB("SCORE_PACKAGE_SUB", "个人执行包数据");
 
 	/**
 	 * 类型
@@ -24,4 +28,8 @@ public enum ExportType {
 	 * 描述
 	 */
 	private final String description;
+
+	public static String getAsyncExportCache(ExportType exportType, Integer userId) {
+        return String.format(CacheConstants.ASYNC_EXPORT_CACHE, exportType.getType(), userId);
+    }
 }

+ 30 - 0
hnqz-upms/hnqz-upms-api/src/main/java/com/qunzhixinxi/hnqz/admin/api/constant/enums/TaskCheck.java

@@ -0,0 +1,30 @@
+package com.qunzhixinxi.hnqz.admin.api.constant.enums;
+
+import com.baomidou.mybatisplus.annotation.EnumValue;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * {@code TargetType}
+ * <p>
+ * Task Check 枚举
+ *
+ */
+@Getter
+@AllArgsConstructor
+public enum TaskCheck {
+
+	REJECTED(0, "拒绝"),
+	PASSED(1, "通过");
+
+	@EnumValue
+	private final int code;
+
+	private final String desc;
+
+	@Override
+    public String toString() {
+        return desc;
+    }
+
+}

+ 30 - 0
hnqz-upms/hnqz-upms-api/src/main/java/com/qunzhixinxi/hnqz/admin/api/constant/enums/TaskSupervisionApproval.java

@@ -0,0 +1,30 @@
+package com.qunzhixinxi.hnqz.admin.api.constant.enums;
+
+import com.baomidou.mybatisplus.annotation.EnumValue;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * {@code TargetType}
+ * <p>
+ * Task Check 枚举
+ *
+ */
+@Getter
+@AllArgsConstructor
+public enum TaskSupervisionApproval {
+
+	REJECTED(0, "不同意"),
+	PASSED(1, "同意");
+
+	@EnumValue
+	private final int code;
+
+	private final String desc;
+
+	@Override
+    public String toString() {
+        return desc;
+    }
+
+}

+ 16 - 0
hnqz-upms/hnqz-upms-api/src/main/java/com/qunzhixinxi/hnqz/admin/api/dto/WmPkgDTO.java

@@ -13,6 +13,7 @@ import javax.validation.constraints.Min;
 import javax.validation.constraints.NotBlank;
 import javax.validation.constraints.NotEmpty;
 import javax.validation.constraints.NotNull;
+import java.time.LocalDate;
 import java.util.List;
 
 /**
@@ -187,4 +188,19 @@ public final class WmPkgDTO {
     @NotBlank(message = "执行包领取ID必填")
     private String pkgId;
   }
+
+  /**
+   * 个人执行包导出参数
+   *
+   * @author snows
+   * @date 2025/08/05
+   */
+  @Data
+  public static class OnPkgSubExport {
+    @NotNull(message = "开始日期必填")
+    private LocalDate startDate;
+
+    private LocalDate endDate;
+  }
+
 }

+ 26 - 0
hnqz-upms/hnqz-upms-api/src/main/java/com/qunzhixinxi/hnqz/admin/api/model/excel/TaskCheckConverter.java

@@ -0,0 +1,26 @@
+package com.qunzhixinxi.hnqz.admin.api.model.excel;
+
+import com.alibaba.excel.converters.Converter;
+import com.alibaba.excel.enums.CellDataTypeEnum;
+import com.alibaba.excel.metadata.GlobalConfiguration;
+import com.alibaba.excel.metadata.data.WriteCellData;
+import com.alibaba.excel.metadata.property.ExcelContentProperty;
+import com.qunzhixinxi.hnqz.admin.api.constant.enums.TaskCheck;
+
+public class TaskCheckConverter implements Converter<TaskCheck> {
+
+    @Override
+    public Class<?> supportJavaTypeKey() {
+        return TaskCheck.class;
+    }
+
+    @Override
+    public CellDataTypeEnum supportExcelTypeKey() {
+        return CellDataTypeEnum.STRING;
+    }
+
+    @Override
+    public WriteCellData<?> convertToExcelData(TaskCheck value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
+        return new WriteCellData<>(value != null ? value.getDesc() : "");
+    }
+}

+ 239 - 63
hnqz-upms/hnqz-upms-api/src/main/java/com/qunzhixinxi/hnqz/admin/api/model/excel/TaskCheckHistoryExcelModel.java

@@ -2,6 +2,9 @@ package com.qunzhixinxi.hnqz.admin.api.model.excel;
 
 import com.alibaba.excel.annotation.ExcelProperty;
 import com.alibaba.excel.annotation.write.style.ColumnWidth;
+import com.qunzhixinxi.hnqz.admin.api.constant.enums.TaskCheck;
+import com.qunzhixinxi.hnqz.admin.api.constant.enums.TaskSupervisionApproval;
+
 import lombok.Data;
 
 /**
@@ -11,110 +14,283 @@ import lombok.Data;
  * @date 2025-01-06 11:24
  */
 @Data
-@ColumnWidth(64)
+@ColumnWidth(16)
 public class TaskCheckHistoryExcelModel {
 
     @ExcelProperty("任务ID")
     private String taskId;
 
-    @ExcelProperty("任务编号")
-    private String taskNumber;
+    @ExcelProperty("区域")
+    private String divisionName;
 
-    @ExcelProperty("执行人")
-    private String salesName;
+    @ExcelProperty("省简称")
+    private String provAbbr;
 
-    @ExcelProperty("执行人所在企业")
-    private String vendorName;
+    @ExcelProperty("市场服务供应商公司名称")
+    private String csoName;
 
-    @ExcelProperty("区域")
-    private String area;
+    @ExcelProperty("省区下发执行包名称")
+    private String scorePackageName;
 
-    @ExcelProperty("执行包名称")
-    private String pkgName;
+    @ExcelProperty("执行包ID")
+    private String scorePackageId;
 
-    @ExcelProperty("任务内容ID")
-    private String taskContentId;
+    @ExcelProperty("执行包年度")
+    private String packageYear;
+
+    @ExcelProperty("执行包开始时间")
+    private String packageStartTime;
+
+    @ExcelProperty("执行包结束时间")
+    private String packageEndTime;
+
+    @ExcelProperty("任务编号")
+    private String taskNumber;
 
     @ExcelProperty("任务类型")
-    private String taskType;
+    private String taskTypeName;
+
+    @ExcelProperty("系统单项任务对应积分")
+    private String taskScore;
+
+    @ExcelProperty("本服务任务对应产品")
+    private String drugnameTy;
+
+    @ExcelProperty("本服务任务对应产品生产企业")
+    private String drugEntName;
 
-    @ExcelProperty("产品名称(通用名)")
-    private String skuName;
+    @ExcelProperty("服务供应商业务员姓名")
+    private String workerRealname;
 
-    @ExcelProperty("生产企业")
-    private String mahName;
+    @ExcelProperty("服务提交时间")
+    private String taskCreateTime;
 
-    // 服务商
-    @ExcelProperty("服务商负责人审核时间")
-    private String vendorCheckTime;
+    @ExcelProperty("服务商管理员名称")
+    private String vendorRealname;
 
-    @ExcelProperty("服务商负责人是否通过")
-    private String vendorCheckResult;
+    @ExcelProperty("服务审核时间")
+    private String vendorUpdateTime;
 
-    @ExcelProperty("服务商负责人审核意见")
+    @ExcelProperty(value = "审核意见", converter = TaskCheckConverter.class)
+    private TaskCheck vendorCheckResult;
+
+    @ExcelProperty("通过/拒绝原因")
     private String vendorCheckMsg;
 
-    // 地市
-    @ExcelProperty("事业部地市经理审核时间")
-    private String cityCheckTime;
+    @ExcelProperty("地市经理姓名")
+    private String cityRealname;
+
+    @ExcelProperty("服务审核时间")
+    private String cityUpdateTime;
 
-    @ExcelProperty("事业部地市经理是否通过")
-    private String cityCheckResult;
+    @ExcelProperty(value = "审核意见", converter = TaskCheckConverter.class)
+    private TaskCheck cityCheckResult;
 
-    @ExcelProperty("事业部地市经理审核意见")
+    @ExcelProperty("通过/拒绝原因")
     private String cityCheckMsg;
 
-    // 区域
-    @ExcelProperty("事业部区域经理审核时间")
-    private String areaCheckTime;
+    @ExcelProperty("区域经理姓名")
+    private String divisionRealname;
+
+    @ExcelProperty("服务审核时间")
+    private String divisionUpdateTime;
+
+    @ExcelProperty(value = "审核意见", converter = TaskCheckConverter.class)
+    private TaskCheck divisionCheckResult;
 
-    @ExcelProperty("事业部区域经理是否通过")
-    private String areaCheckResult;
+    @ExcelProperty("通过/拒绝原因")
+    private String divisionCheckMsg;
 
-    @ExcelProperty("事业部区域经理审核意见")
-    private String areaCheckMsg;
+    @ExcelProperty("市场组经理姓名")
+    private String marketingRealname;
 
-    // 市场组
-    @ExcelProperty("事业部市场组审核时间")
-    private String mktCheckTime;
+    @ExcelProperty("服务审核时间")
+    private String marketingUpdateTime;
 
-    @ExcelProperty("事业部市场组是否通过")
-    private String mktCheckResult;
+    @ExcelProperty(value = "审核意见", converter = TaskCheckConverter.class)
+    private TaskCheck marketingCheckResult;
 
-    @ExcelProperty("事业部市场组审核意见")
-    private String mktCheckMsg;
+    @ExcelProperty("通过/拒绝原因")
+    private String marketingCheckMsg;
 
-    // 商务组
-    @ExcelProperty("事业部商务组是否通过")
-    private String bizCheckTime;
+    @ExcelProperty("商务组经理姓名")
+    private String bizRealname;
 
-    @ExcelProperty("事业部商务组是否通过")
-    private String bizCheckResult;
+    @ExcelProperty("服务审核时间")
+    private String bizUpdateTime;
 
-    @ExcelProperty("事业部商务组审核意见")
+    @ExcelProperty(value = "审核意见", converter = TaskCheckConverter.class)
+    private TaskCheck bizCheckResult;
+
+    @ExcelProperty("通过/拒绝原因")
     private String bizCheckMsg;
 
-    // 分管领导
-    @ExcelProperty("事业部分管销售领导审核时间")
-    private String subMgrCheckTime;
+    @ExcelProperty("分管领导姓名")
+    private String submgrRealname;
+
+    @ExcelProperty("服务审核时间")
+    private String submgrUpdateTime;
 
-    @ExcelProperty("事业部分管销售领导是否通过")
-    private String subMgrCheckResult;
+    @ExcelProperty(value = "审核意见", converter = TaskCheckConverter.class)
+    private TaskCheck submgrCheckResult;
 
-    @ExcelProperty("事业部分管销售领导审核意见")
-    private String subMgrCheckMsg;
+    @ExcelProperty("通过/拒绝原因")
+    private String submgrCheckMsg;
 
-    // 总经理
-    @ExcelProperty("事业部总经理审核时间")
-    private String mgrCheckTime;
+    @ExcelProperty("总负责领导姓名")
+    private String mgrRealname;
 
-    @ExcelProperty("事业部总经理是否通过")
-    private String mgrCheckResult;
+    @ExcelProperty("服务审核时间")
+    private String mgrUpdateTime;
 
-    @ExcelProperty("事业部总经理导审核意见")
+    @ExcelProperty(value = "审核意见", converter = TaskCheckConverter.class)
+    private TaskCheck mgrCheckResult;
+
+    @ExcelProperty("通过/拒绝原因")
     private String mgrCheckMsg;
 
+    @ExcelProperty("生产企业财务监督员")
+    private String factoryFinanceRealname;
+
+    @ExcelProperty("监督检查时间")
+    private String factoryFinanceCreateTime;
+
+    @ExcelProperty(value = "审核意见", converter = TaskCheckConverter.class)
+    private TaskCheck factoryFinanceSupRes;
+
+    @ExcelProperty("通过/拒绝原因")
+    private String factoryFinanceRemarks;
+
+    @ExcelProperty("生产企业财务负责人")
+    private String factoryFinanceLeaderRealname;
+
+    @ExcelProperty("监督检查时间")
+    private String factoryFinanceLeaderCreateTime;
+
+    @ExcelProperty(value = "监督意见", converter = TaskSupervisionApprovalConverter.class)
+    private TaskSupervisionApproval factoryFinanceLeaderAdviceResult;
+
+    @ExcelProperty("通过/拒绝原因")
+    private String factoryFinanceLeaderRemarks;
+
+    @ExcelProperty("生产企业财务分管领导")
+    private String factoryFinanceSubmgrRealname;
+
+    @ExcelProperty("监督检查时间")
+    private String factoryFinanceSubmgrCreateTime;
+
+    @ExcelProperty(value = "监督意见", converter = TaskSupervisionApprovalConverter.class)
+    private TaskSupervisionApproval factoryFinanceSubmgrAdviceResult;
+
+    @ExcelProperty("通过/拒绝原因")
+    private String factoryFinanceSubmgrRemarks;
+
+    @ExcelProperty("生产企业销售监督员")
+    private String factoryBizRealname;
+
+    @ExcelProperty("监督检查时间")
+    private String factoryBizCreateTime;
+
+    @ExcelProperty(value = "审核意见", converter = TaskCheckConverter.class)
+    private TaskCheck factoryBizSupRes;
+
+    @ExcelProperty("通过/拒绝原因")
+    private String factoryBizRemarks;
+
+    @ExcelProperty("生产企业销售负责人")
+    private String factoryBizLeaderRealname;
+
+    @ExcelProperty("监督检查时间")
+    private String factoryBizLeaderCreateTime;
+
+    @ExcelProperty(value = "监督意见", converter = TaskSupervisionApprovalConverter.class)
+    private TaskSupervisionApproval factoryBizLeaderAdviceResult;
+
+    @ExcelProperty("通过/拒绝原因")
+    private String factoryBizLeaderRemarks;
+
+    @ExcelProperty("生产企业销售分管领导")
+    private String factoryBizSubmgrRealname;
+
+    @ExcelProperty("监督检查时间")
+    private String factoryBizSubmgrCreateTime;
+
+    @ExcelProperty(value = "监督意见", converter = TaskSupervisionApprovalConverter.class)
+    private TaskSupervisionApproval factoryBizSubmgrAdviceResult;
+
+    @ExcelProperty("通过/拒绝原因")
+    private String factoryBizSubmgrRemarks;
+
+    @ExcelProperty("营销合规监督员")
+    private String lawyerRealname;
+
+    @ExcelProperty("监督检查时间")
+    private String lawyerCreateTime;
+
+    @ExcelProperty(value = "审核意见", converter = TaskCheckConverter.class)
+    private TaskCheck lawyerSupRes;
+
+    @ExcelProperty("通过/拒绝原因")
+    private String lawyerRemarks;
+
+    @ExcelProperty("营销合规监督负责人")
+    private String lawyerLeaderRealname;
+
+    @ExcelProperty("监督检查时间")
+    private String lawyerLeaderCreateTime;
+
+    @ExcelProperty(value = "监督意见", converter = TaskSupervisionApprovalConverter.class)
+    private TaskSupervisionApproval lawyerLeaderAdviceResult;
+
+    @ExcelProperty("通过/拒绝原因")
+    private String lawyerLeaderRemarks;
+
+    @ExcelProperty("营销合规监督分管领导")
+    private String lawyerSubmgrRealname;
+
+    @ExcelProperty("监督检查时间")
+    private String lawyerSubmgrCreateTime;
+
+    @ExcelProperty(value = "监督意见", converter = TaskSupervisionApprovalConverter.class)
+    private TaskSupervisionApproval lawyerSubmgrAdviceResult;
+
+    @ExcelProperty("通过/拒绝原因")
+    private String lawyerSubmgrRemarks;
+
+    @ExcelProperty("营销财务监督员")
+    private String financeRealname;
+
+    @ExcelProperty("监督检查时间")
+    private String financeCreateTime;
+
+    @ExcelProperty(value = "审核意见", converter = TaskCheckConverter.class)
+    private TaskCheck financeSupRes;
+
+    @ExcelProperty("通过/拒绝原因")
+    private String financeRemarks;
+
+    @ExcelProperty("营销财务负责人")
+    private String financeLeaderRealname;
+
+    @ExcelProperty("监督检查时间")
+    private String financeLeaderCreateTime;
+
+    @ExcelProperty(value = "监督意见", converter = TaskSupervisionApprovalConverter.class)
+    private TaskSupervisionApproval financeLeaderAdviceResult;
+
+    @ExcelProperty("通过/拒绝原因")
+    private String financeLeaderRemarks;
+
+    @ExcelProperty("营销财务监督分管领导")
+    private String financeSubmgrRealname;
+
+    @ExcelProperty("监督检查时间")
+    private String financeSubmgrCreateTime;
 
+    @ExcelProperty(value = "监督意见", converter = TaskSupervisionApprovalConverter.class)
+    private TaskSupervisionApproval financeSubmgrAdviceResult;
 
+    @ExcelProperty("通过/拒绝原因")
+    private String financeSubmgrRemarks;
 
 }

+ 26 - 0
hnqz-upms/hnqz-upms-api/src/main/java/com/qunzhixinxi/hnqz/admin/api/model/excel/TaskSupervisionApprovalConverter.java

@@ -0,0 +1,26 @@
+package com.qunzhixinxi.hnqz.admin.api.model.excel;
+
+import com.alibaba.excel.converters.Converter;
+import com.alibaba.excel.enums.CellDataTypeEnum;
+import com.alibaba.excel.metadata.GlobalConfiguration;
+import com.alibaba.excel.metadata.data.WriteCellData;
+import com.alibaba.excel.metadata.property.ExcelContentProperty;
+import com.qunzhixinxi.hnqz.admin.api.constant.enums.TaskSupervisionApproval;
+
+public class TaskSupervisionApprovalConverter implements Converter<TaskSupervisionApproval> {
+
+    @Override
+    public Class<?> supportJavaTypeKey() {
+        return TaskSupervisionApproval.class;
+    }
+
+    @Override
+    public CellDataTypeEnum supportExcelTypeKey() {
+        return CellDataTypeEnum.STRING;
+    }
+
+    @Override
+    public WriteCellData<?> convertToExcelData(TaskSupervisionApproval value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
+        return new WriteCellData<>(value != null ? value.getDesc() : "");
+    }
+}

+ 561 - 0
hnqz-upms/hnqz-upms-api/src/main/java/com/qunzhixinxi/hnqz/admin/api/model/excel/WmScorePackageSubInfoExcelModel.java

@@ -0,0 +1,561 @@
+package com.qunzhixinxi.hnqz.admin.api.model.excel;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.alibaba.excel.annotation.write.style.ColumnWidth;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 执行包包信息模型(个人执行包维度统计)
+ */
+@Data
+public class WmScorePackageSubInfoExcelModel implements Serializable {
+    private static final long serialVersionUID = -2712453720764666659L;
+
+    /**
+     * 个人执行包ID
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("个人执行包ID")
+    private String pkgId;
+
+    /**
+     * 个人执行包名称
+     */
+    @ColumnWidth(128)
+    @ExcelProperty("个人执行包名称")
+    private String pkgName;
+
+    /**
+     * 父级执行包
+     */
+    @ColumnWidth(128)
+    @ExcelProperty("父级执行包")
+    private String parentPkgName;
+
+    /**
+     * 父级执行包所属省份
+     */
+    @ColumnWidth(128)
+    @ExcelProperty("所属省份")
+    private String parentPkgProvAbbr;
+
+    /**
+     * 产品名称
+     */
+    @ColumnWidth(32)
+    @ExcelProperty("产品名称(通用名)")
+    private String skuName;
+
+    /**
+     * 产品名称
+     */
+    @ColumnWidth(32)
+    @ExcelProperty("产品名称(商品名)")
+    private String prodName;
+
+    /**
+     * 生产企业
+     */
+    @ColumnWidth(32)
+    @ExcelProperty("生产企业")
+    private String mah;
+
+    /**
+     * 接包人名称
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("接包人名称")
+    private String taskUserName;
+
+    /**
+     * 接包人电话
+     */
+    @ColumnWidth(20)
+    private String taskUserPhone;
+
+    /**
+     * 个人执行包总值
+     */
+    @ColumnWidth(16)
+    @ExcelProperty("个人执行包总值")
+    private String score;
+
+
+    /**
+     * 任务下发总次数
+     */
+    @ColumnWidth(16)
+    @ExcelProperty("任务下发总次数")
+    private String scoreTasks;
+
+    // tt -> task_type
+    // ~53============================
+
+    /**
+     * 基础拜访(已下发)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("基础拜访(已下发)")
+    private String tt53dist;
+
+
+    /**
+     * 基础拜访(已提交)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("基础拜访(已提交)")
+    private String tt53Submit;
+
+
+    /**
+     * 基础拜访(已完成审批)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("基础拜访(已完成审批)")
+    private String tt53checked;
+
+
+    /**
+     * 基础拜访(已拒绝)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("基础拜访(已拒绝)")
+    private String tt53rejected;
+
+    // ~52============================
+
+
+    /**
+     * 专项拜访(已下发)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("专项拜访(已下发)")
+    private String tt52dist;
+
+
+    /**
+     * 专项拜访(已提交)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("专项拜访(已提交)")
+    private String tt52submit;
+
+
+    /**
+     * 基础拜访(已完成审批)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("专项拜访(已完成审批)")
+    private String tt52checked;
+
+    /**
+     * 专项拜访(已拒绝)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("专项拜访(已拒绝)")
+    private String tt52rejected;
+
+    // ~51============================
+
+
+    /**
+     * 专业拜访(已下发)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("专业拜访(已下发)")
+    private String tt51dist;
+
+
+    /**
+     * 专业拜访(已提交)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("专业拜访(已提交)")
+    private String tt51submit;
+
+
+    /**
+     * 专业拜访(已完成审批)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("专业拜访(已完成审批)")
+    private String tt51checked;
+
+    /**
+     * 专业拜访(已拒绝)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("专业拜访(已拒绝)")
+    private String tt51rejected;
+
+
+    // ~14============================
+
+
+    /**
+     * 数据收集(已下发)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("数据收集(已下发)")
+    private String tt14dist;
+
+
+    /**
+     * 数据收集(已提交)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("数据收集(已提交)")
+    private String tt14submit;
+
+
+    /**
+     * 数据收集(已完成审批)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("数据收集(已完成审批)")
+    private String tt14checked;
+
+    /**
+     * 数据收集(已拒绝)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("数据收集(已拒绝)")
+    private String tt14rejected;
+
+
+    // ~17============================
+
+
+    /**
+     * 医学警戒信息收集(已下发)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("医学警戒信息收集(已下发)")
+    private String tt17dist;
+
+
+    /**
+     * 医学警戒信息收集(已提交)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("医学警戒信息收集(已提交)")
+    private String tt17submit;
+
+
+    /**
+     * 医学警戒信息收集(已完成审批)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("医学警戒信息收集(已完成审批)")
+    private String tt17checked;
+
+    /**
+     * 医学警戒信息收集(已拒绝)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("医学警戒信息收集(已拒绝)")
+    private String tt17rejected;
+
+    // ~12============================
+
+
+    /**
+     * 产品展示(已下发)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("产品展示(已下发)")
+    private String tt12dist;
+
+
+    /**
+     * 产品展示(已提交)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("产品展示(已提交)")
+    private String tt12submit;
+
+
+    /**
+     * 产品展示(已完成审批)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("产品展示(已完成审批)")
+    private String tt12Checked;
+
+    /**
+     * 产品展示(已拒绝)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("产品展示(已拒绝)")
+    private String tt12rejected;
+
+
+
+    // ~13============================
+
+
+    /**
+     * 业务宣传服务(已下发)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("业务宣传服务(已下发)")
+    private String tt13dist;
+
+
+    /**
+     * 业务宣传服务(已提交)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("业务宣传服务(已提交)")
+    private String tt13submit;
+
+
+    /**
+     * 业务宣传服务(已完成审批)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("业务宣传服务(已完成审批)")
+    private String tt13checked;
+
+    /**
+     * 业务宣传服务(已拒绝)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("业务宣传服务(已拒绝)")
+    private String tt13rejected;
+
+    // ~1============================
+
+
+    /**
+     * POV科室会(已下发)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("POV科室会(已下发)")
+    private String tt1dist;
+
+
+    /**
+     * POV科室会(已提交)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("POV科室会(已提交)")
+    private String tt1submit;
+
+
+    /**
+     * POV科室会(已完成审批)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("POV科室会(已完成审批)")
+    private String tt1checked;
+
+    /**
+     * POV科室会(已拒绝)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("POV科室会(已拒绝)")
+    private String tt1rejected;
+
+
+    // ~2============================
+
+
+    /**
+     * 区县学术会议(已下发)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("区县学术会议(已下发)")
+    private String tt2dist;
+
+
+    /**
+     * 区县学术会议(已提交)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("区县学术会议(已提交)")
+    private String tt2submit;
+
+
+    /**
+     * 区县学术会议(已完成审批)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("区县学术会议(已完成审批)")
+    private String tt2checked;
+
+    /**
+     * 区县学术会议(已拒绝)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("区县学术会议(已拒绝)")
+    private String tt2rejected;
+
+    // ~5============================
+
+
+    /**
+     * 沙龙会(已下发)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("沙龙会(已下发)")
+    private String tt5dist;
+
+
+    /**
+     * 沙龙会(已提交)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("沙龙会(已提交)")
+    private String tt5submit;
+
+
+    /**
+     * 沙龙会(已完成审批)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("沙龙会(已完成审批)")
+    private String tt5checked;
+
+    /**
+     * 沙龙会(已拒绝)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("沙龙会(已拒绝)")
+    private String tt5rejected;
+
+    // ~3============================
+
+
+    /**
+     * 市级学术会议(已下发)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("市级学术会议(已下发)")
+    private String tt3dist;
+
+
+    /**
+     * 市级学术会议(已提交)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("市级学术会议(已提交)")
+    private String tt3submit;
+
+
+    /**
+     * 市级学术会议(已完成审批)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("市级学术会议(已完成审批)")
+    private String tt3checked;
+
+    /**
+     * 市级学术会议(已拒绝)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("市级学术会议(已拒绝)")
+    private String tt3rejected;
+
+    // ~4============================
+
+
+    /**
+     * 省级学术会议(已下发)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("省级学术会议(已下发)")
+    private String tt4dist;
+
+
+    /**
+     * 省级学术会议(已提交)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("省级学术会议(已提交)")
+    private String tt4submit;
+
+
+    /**
+     * 省级学术会议(已完成审批)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("省级学术会议(已完成审批)")
+    private String tt4checked;
+
+    /**
+     * 省级学术会议(已拒绝)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("省级学术会议(已拒绝)")
+    private String tt4rejected;
+
+    // ~64============================
+
+
+    /**
+     * 线上学术会议(已下发)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("线上学术会议(已下发)")
+    private String tt64dist;
+
+
+    /**
+     * 线上学术会议(已提交)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("线上学术会议(已提交)")
+    private String tt64submit;
+
+
+    /**
+     * 线上学术会议(已完成审批)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("线上学术会议(已完成审批)")
+    private String tt64checked;
+
+    /**
+     * 线上学术会议(已拒绝)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("线上学术会议(已拒绝)")
+    private String tt64rejected;
+
+    // ~19============================
+
+
+    /**
+     * 健康教育课堂(已下发)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("健康教育课堂(已下发)")
+    private String tt19dist;
+
+
+    /**
+     * 健康教育课堂(已提交)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("健康教育课堂(已提交)")
+    private String tt19submit;
+
+
+    /**
+     * 健康教育课堂(已完成审批)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("健康教育课堂(已完成审批)")
+    private String tt19checked;
+
+    /**
+     * 健康教育课堂(已拒绝)
+     */
+    @ColumnWidth(20)
+    @ExcelProperty("健康教育课堂(已拒绝)")
+    private String tt19rejected;
+
+}

+ 20 - 0
hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/aspect/ExportGuard.java

@@ -0,0 +1,20 @@
+
+package com.qunzhixinxi.hnqz.admin.aspect;
+
+import java.lang.annotation.*;
+
+/**
+ * @author hnqz
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface ExportGuard {
+
+	/**
+	 * enum ExportType
+	 * @return {String}
+	 */
+	String type();
+
+}

+ 50 - 0
hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/aspect/ExportGuardAspect.java

@@ -0,0 +1,50 @@
+
+package com.qunzhixinxi.hnqz.admin.aspect;
+
+import com.qunzhixinxi.hnqz.admin.api.constant.enums.ExportType;
+import com.qunzhixinxi.hnqz.common.security.service.HnqzUser;
+
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
+
+import cn.hutool.extra.spring.SpringUtil;
+import lombok.AllArgsConstructor;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+
+/**
+ *
+ */
+@Slf4j
+@Aspect
+@AllArgsConstructor
+@Component
+public class ExportGuardAspect {
+
+	@SneakyThrows
+	@Around("@annotation(exportGuard)")
+	public Object around(ProceedingJoinPoint point, ExportGuard exportGuard) {
+		ExportType exportType = ExportType.valueOf(exportGuard.type());
+		if (point.getArgs().length < 1) {
+			throw new RuntimeException("第一个参数必须是用户对象");
+		}
+		HnqzUser user = (HnqzUser) point.getArgs()[0];
+		if (user == null) {
+			throw new RuntimeException("第一个参数必须是用户对象");
+		}
+		String key = ExportType.getAsyncExportCache(exportType, user.getId());
+		// RedisTemplateConfig
+		@SuppressWarnings("unchecked")
+		RedisTemplate<String, Object> redisTemplate = (RedisTemplate<String, Object>) SpringUtil.getBean("redisTemplate");
+		String status = (String) redisTemplate.opsForValue().get(key);
+		if ("GENERATING".equals(status)) {
+			throw new RuntimeException("导出正在生成中,请稍后再试");
+		}
+		
+		return point.proceed();
+	}
+
+}

+ 50 - 0
hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/config/RetryConfiguration.java

@@ -0,0 +1,50 @@
+package com.qunzhixinxi.hnqz.admin.config;
+
+import com.qunzhixinxi.hnqz.common.core.exception.BizException;
+import lombok.RequiredArgsConstructor;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.retry.annotation.EnableRetry;
+import org.springframework.retry.backoff.FixedBackOffPolicy;
+import org.springframework.retry.policy.SimpleRetryPolicy;
+import org.springframework.retry.support.RetryTemplate;
+
+import java.util.Collections;
+
+/**
+ * 重试配置
+ *
+ * @author snows
+ * @date 2025/08/04
+ */
+@EnableRetry
+@Configuration
+@RequiredArgsConstructor
+public class RetryConfiguration {
+
+	private final UpmsConfig upmsConfig;
+
+	/**
+	 * 重试模板
+	 *
+	 * @return {@link RetryTemplate } 重试模板实例
+	 */
+	@Bean
+	public RetryTemplate retryTemplate() {
+		// 构建重试模板实例
+		RetryTemplate retryTemplate = new RetryTemplate();
+
+		// 设置重试回退操作策略,主要设置重试间隔时间
+		FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
+		backOffPolicy.setBackOffPeriod(upmsConfig.getRetryBackOffPeriod());
+
+		// 设置重试策略,主要设置重试次数
+		SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy(upmsConfig.getMaxRetryTimes(), Collections
+				.<Class<? extends Throwable>, Boolean>singletonMap(BizException.class, true));
+
+		retryTemplate.setRetryPolicy(retryPolicy);
+		retryTemplate.setBackOffPolicy(backOffPolicy);
+
+		return retryTemplate;
+	}
+}

+ 10 - 0
hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/config/UpmsConfig.java

@@ -69,4 +69,14 @@ public class UpmsConfig {
 	 */
 	private Integer asyncExportLimit = 3;
 
+	/**
+	 * 异步导出重试间隔时间(固定时间的退避策略)
+	 */
+	private Long retryBackOffPeriod = 60000L;
+
+	/**
+	 * 异步最大重试次数
+	 */
+	private Integer maxRetryTimes = 3;
+
 }

+ 24 - 168
hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/controller/init/InitController.java

@@ -6,6 +6,7 @@ import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.date.DatePattern;
 import cn.hutool.core.date.LocalDateTimeUtil;
 import cn.hutool.core.text.StrPool;
+import cn.hutool.core.util.ArrayUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.extra.spring.SpringUtil;
 import cn.hutool.json.JSONUtil;
@@ -51,6 +52,7 @@ import com.qunzhixinxi.hnqz.admin.mapper.TargetDept1Mapper;
 import com.qunzhixinxi.hnqz.admin.mapper.WmDaAgentMapper;
 import com.qunzhixinxi.hnqz.admin.mapper.WmDaDrugEntMapper;
 import com.qunzhixinxi.hnqz.admin.mapper.WmPackageTaskTypeQtyMapper;
+import com.qunzhixinxi.hnqz.admin.mapper.WmTaskSupervisionMapper;
 import com.qunzhixinxi.hnqz.admin.mapper.WmTaskTypeMapper;
 import com.qunzhixinxi.hnqz.admin.service.SysAreaEntityService;
 import com.qunzhixinxi.hnqz.admin.service.SysCheckChainNodeCheckHistoryService;
@@ -64,6 +66,7 @@ import com.qunzhixinxi.hnqz.admin.service.WmPackageTaskTypeQtyService;
 import com.qunzhixinxi.hnqz.admin.service.WmScorePackageService;
 import com.qunzhixinxi.hnqz.admin.service.WmTaskContentService;
 import com.qunzhixinxi.hnqz.admin.service.WmTaskService;
+import com.qunzhixinxi.hnqz.admin.service.WmTaskSupervisionService;
 import com.qunzhixinxi.hnqz.admin.util.OsEnvUtils;
 import com.qunzhixinxi.hnqz.admin.util.OsEnvUtils.EnvType;
 import com.qunzhixinxi.hnqz.admin.util.OsEnvUtils.TargetFile;
@@ -73,6 +76,9 @@ import com.qunzhixinxi.hnqz.common.core.util.R;
 import com.qunzhixinxi.hnqz.common.oss.OssProperties;
 import com.qunzhixinxi.hnqz.common.oss.service.OssTemplate;
 import com.qunzhixinxi.hnqz.common.security.annotation.Inner;
+import com.qunzhixinxi.hnqz.common.security.service.HnqzUser;
+import com.qunzhixinxi.hnqz.common.security.util.SecurityUtils;
+
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
@@ -80,6 +86,8 @@ import java.io.InputStream;
 import java.net.URL;
 import java.net.URLConnection;
 import java.time.format.DateTimeFormatter;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.TemporalUnit;
 import java.util.Arrays;
 import java.util.Objects;
 import java.util.TreeMap;
@@ -175,6 +183,7 @@ public class InitController {
   private final SysRoleService roleService;
   private final SysChainNodeCheckHisNode43TempMapper node43TempMapper;
   private final TargetDept1Mapper targetDept1Mapper;
+  private final WmTaskSupervisionService wmTaskSupervisionService;
 
   @Inner(value = false)
   @GetMapping(value = "/cnbg/task/check/stat")
@@ -1457,180 +1466,27 @@ public class InitController {
     return R.ok(r);
   }
 
-  @Inner(value = false)
-  @ResponseExcel(
+  /* @ResponseExcel(
       name = "taskCheckHistoryExcel",
-      sheets = {@Sheet(sheetName = "审核信息")})
+      sheets = {@Sheet(sheetName = "审核信息")}) */
   @GetMapping(value = "/cnbg/init/task/check/his/export")
-  public List<TaskCheckHistoryExcelModel> exportTaskCheckHistoryExcel() {
-
-    // 获取全部的审核信息
-    List<SysCheckChainNodeCheckHistory> his = checkChainNodeCheckHistoryService.list();
-
-    if (CollUtil.isEmpty(his)) {
-      return Collections.emptyList();
+  public List<TaskCheckHistoryExcelModel> exportTaskCheckHistoryExcel(
+    @RequestParam(value = "taskPeriod", required = true) LocalDate[] taskPeriod) {
+    
+    if(taskPeriod == null || taskPeriod.length < 2 || taskPeriod[1].minus(31, ChronoUnit.DAYS).isAfter(taskPeriod[0])) {
+      throw new RuntimeException("合法的任务导出区间是一个月");
     }
 
-    ListOperations operations = redisTemplate.opsForList();
-    // 从缓存中获取用户信息
-    List<SysUser> users = operations.range(CacheConstants.USER_KEY, 0, -1);
-    Map<Integer, SysUser> userMap =
-        users.stream().collect(Collectors.toMap(SysUser::getUserId, Function.identity()));
-
-    // 从缓存中获取企业信息
-    List<SysDept> depts = operations.range(CacheConstants.DEPT_KEY, 0, -1);
-    Map<Integer, SysDept> deptMap =
-        depts.stream().collect(Collectors.toMap(SysDept::getDeptId, Function.identity()));
-
-    // 从缓存中获取商品信息
-    List<WmDaDrugEntDrugtable> drugs = operations.range(CacheConstants.DRUG_KEY, 0, -1);
-    Map<String, WmDaDrugEntDrugtable> drugtableMap =
-        drugs.stream().collect(Collectors.toMap(WmDaDrugEntDrugtable::getId, Function.identity()));
-
-    // 丛缓存中获取任务类型
-    List<WmTaskType> range = operations.range(CacheConstants.TASK_TYPE_KEY, 0, -1);
-    Map<String, WmTaskType> taskTypeMap =
-        range.stream().collect(Collectors.toMap(WmTaskType::getId, Function.identity()));
-
-    List<WmScorePackage> pkgs = wmScorePackageService.list();
-
-    Map<String, WmScorePackage> pkgMap =
-        pkgs.stream().collect(Collectors.toMap(WmScorePackage::getId, Function.identity()));
-
-    Map<Integer, List<SysCheckChainNodeCheckHistory>> taskId2HisMap =
-        his.stream().collect(Collectors.groupingBy(SysCheckChainNodeCheckHistory::getTargetId));
-
-    List<WmTask> tasks = taskService.list();
-    Map<String, WmTask> taskMap =
-        tasks.stream().collect(Collectors.toMap(WmTask::getId, Function.identity()));
-
-    // 获取任务
-    DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
-    List<TaskCheckHistoryExcelModel> collect =
-        taskId2HisMap.entrySet().parallelStream()
-            .map(
-                entry -> {
-                  Integer key = entry.getKey();
-
-                  WmTask task = taskMap.get(key.toString());
-
-                  if (task == null) {
-                    return null;
-                  }
-
-                  TaskCheckHistoryExcelModel model = new TaskCheckHistoryExcelModel();
-                  model.setTaskId(task.getId());
-                  model.setTaskNumber(task.getTaskNumber());
-
-                  String taskUserId = task.getTaskUserId();
-                  SysUser sysUser = userMap.get(Integer.parseInt(taskUserId));
-
-                  if (sysUser != null) {
-                    model.setSalesName(sysUser.getRealname());
-                    SysDept dept = deptMap.get(sysUser.getDeptId());
-                    model.setVendorName(dept.getName());
-                  } else {
-                    model.setSalesName("");
-                    model.setVendorName("");
-                  }
-
-                  model.setArea("");
-                  model.setTaskContentId(task.getTaskContentId());
-                  WmTaskType wmTaskType = taskTypeMap.get(task.getTaskTypeId());
-                  model.setTaskType(wmTaskType == null ? "" : wmTaskType.getTaskTypeName());
-
-                  WmScorePackage wmScorePackage = pkgMap.get(task.getScorePackageId());
-
-                  model.setPkgName(wmScorePackage.getScorePackageName());
-
-                  String drugId = wmScorePackage.getDrugtable()[0];
-
-                  WmDaDrugEntDrugtable drugtable = drugtableMap.get(drugId);
-
-                  model.setSkuName(drugtable.getDrugnameTy());
-                  model.setMahName(drugtable.getDrugEntName());
-
-                  Map<Integer, List<SysCheckChainNodeCheckHistory>> nodeId2CheckMap =
-                      entry.getValue().stream()
-                          .collect(Collectors.groupingBy(SysCheckChainNodeCheckHistory::getNodeId));
-
-                  // 服务商
-                  List<SysCheckChainNodeCheckHistory> vendor = nodeId2CheckMap.get(1);
-
-                  if (CollUtil.isNotEmpty(vendor)) {
-
-                    Map<String, String> info = getInfo(vendor, dtf);
-
-                    model.setVendorCheckTime(info.get("time"));
-                    model.setVendorCheckResult(info.get("result"));
-                    model.setVendorCheckMsg(info.get("msg"));
-                  }
-
-                  // 地市
-                  List<SysCheckChainNodeCheckHistory> city = nodeId2CheckMap.get(2);
-
-                  if (CollUtil.isNotEmpty(city)) {
-                    Map<String, String> info = getInfo(city, dtf);
-                    model.setCityCheckTime(info.get("time"));
-                    model.setCityCheckResult(info.get("result"));
-                    model.setCityCheckMsg(info.get("msg"));
-                  }
-
-                  // 区域
-                  List<SysCheckChainNodeCheckHistory> area = nodeId2CheckMap.get(3);
-
-                  if (CollUtil.isNotEmpty(area)) {
-                    Map<String, String> info = getInfo(area, dtf);
-                    model.setAreaCheckTime(info.get("time"));
-                    model.setAreaCheckResult(info.get("result"));
-                    model.setAreaCheckMsg(info.get("msg"));
-                  }
-
-                  // 市场
-                  List<SysCheckChainNodeCheckHistory> mkt = nodeId2CheckMap.get(8);
-
-                  if (CollUtil.isNotEmpty(mkt)) {
-                    Map<String, String> info = getInfo(mkt, dtf);
-                    model.setMktCheckTime(info.get("time"));
-                    model.setMktCheckResult(info.get("result"));
-                    model.setMktCheckMsg(info.get("msg"));
-                  }
-
-                  // 商务
-                  List<SysCheckChainNodeCheckHistory> biz = nodeId2CheckMap.get(9);
-
-                  if (CollUtil.isNotEmpty(biz)) {
-                    Map<String, String> info = getInfo(biz, dtf);
-                    model.setBizCheckTime(info.get("time"));
-                    model.setBizCheckResult(info.get("result"));
-                    model.setBizCheckMsg(info.get("msg"));
-                  }
-
-                  // 分管领导
-                  List<SysCheckChainNodeCheckHistory> subMgr = nodeId2CheckMap.get(5);
+    if(!CollUtil.contains(SecurityUtils.getRoles(),53)) {
+      throw new RuntimeException("没有导出审核监督明细的权限");
+    }
 
-                  if (CollUtil.isNotEmpty(subMgr)) {
-                    Map<String, String> info = getInfo(subMgr, dtf);
-                    model.setSubMgrCheckTime(info.get("time"));
-                    model.setSubMgrCheckResult(info.get("result"));
-                    model.setSubMgrCheckMsg(info.get("msg"));
-                  }
-
-                  // 总经理
-                  List<SysCheckChainNodeCheckHistory> mgr = nodeId2CheckMap.get(6);
-
-                  if (CollUtil.isNotEmpty(mgr)) {
-                    Map<String, String> info = getInfo(mgr, dtf);
-                    model.setMgrCheckTime(info.get("time"));
-                    model.setMgrCheckResult(info.get("result"));
-                    model.setMgrCheckMsg(info.get("msg"));
-                  }
-
-                  return model;
-                })
-            .collect(Collectors.toList());
+    // sync
+    // return wmTaskSupervisionService.selectTaskSupProcess(SecurityUtils.getUser(), taskPeriod);
 
-    return collect;
+    // async
+    wmTaskSupervisionService.asyncExportTaskCheckSup(SecurityUtils.getUser(), taskPeriod);
+    return List.of();
   }
 
   private Map<String, String> getInfo(

+ 74 - 0
hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/controller/pkg/WmScorePackageExportController.java

@@ -0,0 +1,74 @@
+package com.qunzhixinxi.hnqz.admin.controller.pkg;
+
+import com.qunzhixinxi.hnqz.admin.api.constant.CacheConstants;
+import com.qunzhixinxi.hnqz.admin.api.constant.enums.ExportType;
+import com.qunzhixinxi.hnqz.admin.api.dto.WmPkgDTO;
+import com.qunzhixinxi.hnqz.admin.api.entity.WmReportOpt;
+import com.qunzhixinxi.hnqz.admin.service.SysCommonExportService;
+import com.qunzhixinxi.hnqz.admin.service.WmScorePackageExportService;
+import com.qunzhixinxi.hnqz.common.core.util.R;
+import com.qunzhixinxi.hnqz.common.log.annotation.SysLog;
+import com.qunzhixinxi.hnqz.common.security.service.HnqzUser;
+import com.qunzhixinxi.hnqz.common.security.util.SecurityUtils;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.time.LocalDate;
+
+/**
+ * 积分包导出控制器
+ *
+ * @author snows
+ * @date 2025/08/04
+ */
+@Slf4j
+@RestController
+@RequiredArgsConstructor
+public class WmScorePackageExportController {
+
+	private final WmScorePackageExportService scorePackageExportService;
+	private final SysCommonExportService commonExportService;
+
+
+	/**
+	 * 导出个人执行包信息
+	 *
+	 * @param params 查询参数
+	 * @return {@link R }<{@link Boolean }> 是否成功
+	 */
+	@SysLog("个人执行包数据异步导出")
+	@PostMapping("/pkg/sub-info/export")
+	public R<Boolean> exportPackageSubInfo(@Validated @RequestBody WmPkgDTO.OnPkgSubExport params) {
+		LocalDate startDate = params.getStartDate();
+		LocalDate endDate = params.getEndDate();
+
+		LocalDate today = LocalDate.now();
+		if(endDate == null) {
+			endDate = today;
+		}
+		if(startDate == null) {
+			// 当月的第一天
+			startDate = LocalDate.of(today.getYear(),  today.getMonth(), 1);
+		}
+
+		return R.ok(scorePackageExportService.asyncExport(SecurityUtils.getUser(), SecurityUtils.getRoles(), startDate, endDate));
+	}
+
+	/**
+	 * 导出个人执行包信息的结果
+	 *
+	 * @return {@link WmReportOpt } 状态和结果
+	 */
+	@GetMapping("/pkg/sub-info/export-result")
+	public R<WmReportOpt> exportResult() {
+		HnqzUser user = SecurityUtils.getUser();
+		String key = String.format(CacheConstants.ASYNC_EXPORT_CACHE, ExportType.SCORE_PACKAGE_SUB.getType(), user.getId());
+
+		return R.ok(commonExportService.exportResult(user, key));
+	}
+}

+ 17 - 2
hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/controller/user/SysUserExportController.java

@@ -1,12 +1,19 @@
 package com.qunzhixinxi.hnqz.admin.controller.user;
 
+import com.qunzhixinxi.hnqz.admin.api.constant.CacheConstants;
+import com.qunzhixinxi.hnqz.admin.api.constant.enums.ExportType;
 import com.qunzhixinxi.hnqz.admin.api.dto.SysUserDTO;
 import com.qunzhixinxi.hnqz.admin.api.entity.WmReportOpt;
 import com.qunzhixinxi.hnqz.admin.api.model.excel.SysUserExcelModel;
+import com.qunzhixinxi.hnqz.admin.service.SysCommonExportService;
+import com.qunzhixinxi.hnqz.admin.aspect.ExportGuard;
 import com.qunzhixinxi.hnqz.admin.service.SysUserExportService;
 import com.qunzhixinxi.hnqz.common.core.util.R;
 import com.qunzhixinxi.hnqz.common.log.annotation.SysLog;
+import com.qunzhixinxi.hnqz.common.security.service.HnqzUser;
 import com.qunzhixinxi.hnqz.common.security.util.SecurityUtils;
+
+import cn.hutool.core.util.ArrayUtil;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -30,6 +37,7 @@ import java.util.List;
 public class SysUserExportController {
 
 	private final SysUserExportService userExportService;
+	private final SysCommonExportService commonExportService;
 
 	/**
 	 * 导出用户列表
@@ -39,7 +47,11 @@ public class SysUserExportController {
 	@SysLog("导出用户信息")
 	@PostMapping("/export-user")
 	public R<Boolean> exportUser(@RequestBody SysUserDTO.OnList query) {
-		return R.ok(userExportService.asyncExport(SecurityUtils.getUser(), SecurityUtils.getRoles(), query));
+		HnqzUser user = SecurityUtils.getUser();
+		if (!ArrayUtil.contains(user.getRoles(), 50)) { // 事业部系统管理员
+			throw new RuntimeException("没有导出人员权限");
+		}
+		return R.ok(userExportService.asyncExport(user, SecurityUtils.getRoles(), query));
 	}
 
 	/**
@@ -49,6 +61,9 @@ public class SysUserExportController {
 	 */
 	@GetMapping("/export-user-result")
 	public R<WmReportOpt> exportResult() {
-		return R.ok(userExportService.exportResult(SecurityUtils.getUser()));
+		HnqzUser user = SecurityUtils.getUser();
+		String key = String.format(CacheConstants.ASYNC_EXPORT_CACHE, ExportType.USER.getType(), user.getId());
+
+		return R.ok(commonExportService.exportResult(user, key));
 	}
 }

+ 39 - 0
hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/event/PackageExportEvent.java

@@ -0,0 +1,39 @@
+package com.qunzhixinxi.hnqz.admin.event;
+
+import com.qunzhixinxi.hnqz.common.security.service.HnqzUser;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.time.LocalDate;
+import java.util.List;
+
+/**
+ * 执行包导出事件
+ *
+ * @author snows
+ * @date 2025/08/05
+ */
+@Getter
+@AllArgsConstructor
+public class PackageExportEvent {
+
+	/**
+	 * 用户
+	 */
+	private HnqzUser user;
+
+	/**
+	 * 角色
+	 */
+	private List<Integer> roles;
+
+	/**
+	 * 开始时间
+	 */
+	private LocalDate startDate;
+
+	/**
+	 * 结束时间
+	 */
+	private LocalDate endDate;
+}

+ 26 - 0
hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/event/TaskCheckSupExportEvent.java

@@ -0,0 +1,26 @@
+package com.qunzhixinxi.hnqz.admin.event;
+
+import com.qunzhixinxi.hnqz.common.security.service.HnqzUser;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.time.LocalDate;
+
+/**
+ * 任务审核监督导出事件
+ *
+ */
+@Getter
+@AllArgsConstructor
+public class TaskCheckSupExportEvent {
+
+	/**
+	 * 用户
+	 */
+	private HnqzUser user;
+
+	/**
+	 * 查询参数
+	 */
+	private LocalDate[] taskPeriod;
+}

+ 36 - 0
hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/listener/PackageExportEventListener.java

@@ -0,0 +1,36 @@
+package com.qunzhixinxi.hnqz.admin.listener;
+
+import com.qunzhixinxi.hnqz.admin.event.PackageExportEvent;
+import com.qunzhixinxi.hnqz.admin.service.WmScorePackageExportService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.event.EventListener;
+import org.springframework.core.annotation.Order;
+import org.springframework.scheduling.annotation.Async;
+
+/**
+ * 执行包导出事件侦听器
+ *
+ * @author snows
+ * @date 2025/08/05
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Configuration
+public class PackageExportEventListener {
+
+	private final WmScorePackageExportService scorePackageExportService;
+
+	/**
+	 * 推送事件
+	 *
+	 * @param event 事件
+	 */
+	@Async
+	@Order
+	@EventListener(PackageExportEvent.class)
+	public void pushEvent(PackageExportEvent event) {
+		scorePackageExportService.export(event.getUser(), event.getRoles(), event.getStartDate(), event.getEndDate());
+	}
+}

+ 37 - 0
hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/listener/TaskCheckSupExportEventListener.java

@@ -0,0 +1,37 @@
+package com.qunzhixinxi.hnqz.admin.listener;
+
+import com.qunzhixinxi.hnqz.admin.event.TaskCheckSupExportEvent;
+import com.qunzhixinxi.hnqz.admin.event.UserExportEvent;
+import com.qunzhixinxi.hnqz.admin.service.SysUserExportService;
+import com.qunzhixinxi.hnqz.admin.service.WmTaskSupervisionService;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.event.EventListener;
+import org.springframework.core.annotation.Order;
+import org.springframework.scheduling.annotation.Async;
+
+/**
+ * 任务审核监督导出事件监听器
+ *
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Configuration
+public class TaskCheckSupExportEventListener {
+
+	private final WmTaskSupervisionService wmTaskSupervisionService;
+
+	/**
+	 * 推送事件
+	 *
+	 * @param event 事件
+	 */
+	@Async
+	@Order
+	@EventListener(TaskCheckSupExportEvent.class)
+	public void pushEvent(TaskCheckSupExportEvent event) {
+		wmTaskSupervisionService.selectTaskSupProcess(event.getUser(), event.getTaskPeriod());
+	}
+}

+ 3 - 1
hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/manager/WmPackageExportScope.java

@@ -8,8 +8,10 @@ import com.qunzhixinxi.hnqz.admin.api.entity.SysDept;
 import com.qunzhixinxi.hnqz.admin.api.entity.WmDaDrugEntDrugtable;
 import com.qunzhixinxi.hnqz.admin.api.entity.WmPackageTaskTypeQty;
 import com.qunzhixinxi.hnqz.admin.api.entity.WmScorePackage;
+import lombok.Data;
 
-final class WmPackageExportScope {
+@Data
+public final class WmPackageExportScope {
 
     public WmPackageExportScope(Map<Integer, SysDept> dis,
         Map<Integer, SysDept> service,

+ 6 - 0
hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/mapper/WmTaskSupervisionMapper.java

@@ -2,6 +2,7 @@ package com.qunzhixinxi.hnqz.admin.mapper;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.qunzhixinxi.hnqz.admin.api.entity.WmTaskSupervision;
+import com.qunzhixinxi.hnqz.admin.api.model.excel.TaskCheckHistoryExcelModel;
 
 import java.time.LocalDateTime;
 import java.util.List;
@@ -19,4 +20,9 @@ public interface WmTaskSupervisionMapper extends BaseMapper<WmTaskSupervision> {
     List<WmTaskSupervision> selectByPkgIds(@Param("pkgIds") List<String> pkgIds,
                                             @Param("taskBeginTime") LocalDateTime taskBeginTime,
                                             @Param("taskEndTime") LocalDateTime taskEndTime);
+
+    List<TaskCheckHistoryExcelModel> selectTaskSupProcess(
+        @Param("taskBeginTime") LocalDateTime taskBeginTime,
+        @Param("taskEndTime") LocalDateTime taskEndTime
+    );
 }

+ 22 - 0
hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/service/SysCommonExportService.java

@@ -0,0 +1,22 @@
+package com.qunzhixinxi.hnqz.admin.service;
+
+import com.qunzhixinxi.hnqz.admin.api.entity.WmReportOpt;
+import com.qunzhixinxi.hnqz.common.security.service.HnqzUser;
+
+/**
+ * 通用导出服务
+ *
+ * @author snows
+ * @date 2025/08/04
+ */
+public interface SysCommonExportService {
+
+	/**
+	 * 导出信息的结果
+	 *
+	 * @param user     用户
+	 * @param redisKey Redis key
+	 * @return {@link WmReportOpt } 状态和结果
+	 */
+	WmReportOpt exportResult(HnqzUser user, String redisKey);
+}

+ 0 - 9
hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/service/SysUserExportService.java

@@ -1,7 +1,6 @@
 package com.qunzhixinxi.hnqz.admin.service;
 
 import com.qunzhixinxi.hnqz.admin.api.dto.SysUserDTO;
-import com.qunzhixinxi.hnqz.admin.api.entity.WmReportOpt;
 import com.qunzhixinxi.hnqz.common.security.service.HnqzUser;
 
 import java.util.List;
@@ -33,12 +32,4 @@ public interface SysUserExportService {
 	 * @return {@link Boolean } 是否成功
 	 */
 	Boolean export(HnqzUser user, List<Integer> roles, SysUserDTO.OnList query);
-
-	/**
-	 * 导出用户信息的结果
-	 *
-	 * @param user 用户
-	 * @return {@link WmReportOpt } 状态和结果
-	 */
-	WmReportOpt exportResult(HnqzUser user);
 }

+ 37 - 0
hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/service/WmScorePackageExportService.java

@@ -0,0 +1,37 @@
+package com.qunzhixinxi.hnqz.admin.service;
+
+import com.qunzhixinxi.hnqz.common.security.service.HnqzUser;
+
+import java.time.LocalDate;
+import java.util.List;
+
+/**
+ * 积分包导出服务
+ *
+ * @author snows
+ * @date 2025/08/04
+ */
+public interface WmScorePackageExportService {
+
+	/**
+	 * 异步导出
+	 *
+	 * @param user      用户
+	 * @param roles     角色
+	 * @param startDate 开始日期
+	 * @param endDate   结束日期
+	 * @return {@link Boolean } 是否成功
+	 */
+	Boolean asyncExport(HnqzUser user, List<Integer> roles, LocalDate startDate, LocalDate endDate);
+
+	/**
+	 * 导出积分包
+	 *
+	 * @param user      用户
+	 * @param roles     角色
+	 * @param startDate 开始日期
+	 * @param endDate   结束日期
+	 * @return {@link Boolean } 是否成功
+	 */
+	Boolean export(HnqzUser user, List<Integer> roles, LocalDate startDate, LocalDate endDate);
+}

+ 17 - 0
hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/service/WmTaskSupervisionService.java

@@ -1,11 +1,13 @@
 package com.qunzhixinxi.hnqz.admin.service;
 
+import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.util.List;
 
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.qunzhixinxi.hnqz.admin.api.dto.WmSupervisionDto;
 import com.qunzhixinxi.hnqz.admin.api.entity.WmTaskSupervision;
+import com.qunzhixinxi.hnqz.admin.api.model.excel.TaskCheckHistoryExcelModel;
 import com.qunzhixinxi.hnqz.common.security.service.HnqzUser;
 
 /**
@@ -49,5 +51,20 @@ public interface WmTaskSupervisionService extends IService<WmTaskSupervision> {
      * @return
      */
     List<WmTaskSupervision> getSupervisionByPkgIds(List<String> pkgIds, LocalDateTime taskBeginTime, LocalDateTime taskEndTime);
+
+    /**
+     * 导出审核监察明细
+     * @param user
+     * @param taskPeriod
+     * @return
+     */
+    List<TaskCheckHistoryExcelModel> selectTaskSupProcess(HnqzUser user,  LocalDate[] taskPeriod);
+
+    /**
+     * 异步导出
+     * @param user
+     * @param taskPeriod
+     */
+    void asyncExportTaskCheckSup(HnqzUser user, LocalDate[] taskPeriod);
 }
 

+ 69 - 0
hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/service/impl/SysCommonExportServiceImpl.java

@@ -0,0 +1,69 @@
+package com.qunzhixinxi.hnqz.admin.service.impl;
+
+import cn.hutool.core.util.StrUtil;
+import com.qunzhixinxi.hnqz.admin.api.entity.WmReportOpt;
+import com.qunzhixinxi.hnqz.admin.service.SysCommonExportService;
+import com.qunzhixinxi.hnqz.common.security.service.HnqzUser;
+import lombok.RequiredArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDateTime;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 通用导出服务impl
+ *
+ * @author snows
+ * @date 2025/08/04
+ */
+@Service
+@RequiredArgsConstructor
+public class SysCommonExportServiceImpl implements SysCommonExportService {
+
+	private final RedisTemplate<String, Object> redisTemplate;
+
+	/**
+	 * 导出信息的结果
+	 *
+	 * @param user     用户
+	 * @param redisKey Redis key
+	 * @return {@link WmReportOpt } 状态和结果
+	 */
+	@Override
+	public WmReportOpt exportResult(HnqzUser user, String redisKey) {
+		String o = (String) redisTemplate.opsForValue().get(redisKey);
+		WmReportOpt opt = new WmReportOpt();
+
+		if (StringUtils.isNotEmpty(o)) {
+			// 生成中的
+			if ("GENERATING".equals(o)) {
+				opt.setStatus(WmReportOpt.WmReportOptStatus.GENERATING);
+			}
+			// 生成失败的
+			else if (o.startsWith("ERROR")) {
+				opt.setStatus(WmReportOpt.WmReportOptStatus.ERROR);
+				opt.setErrorMsg(o.split(StrUtil.UNDERLINE)[1]);
+			}
+			// 生成失败的2
+			else if (!o.startsWith("/admin/sys-file")) {
+				opt.setStatus(WmReportOpt.WmReportOptStatus.ERROR);
+				opt.setErrorMsg(o);
+			}
+			// 成功的
+			else {
+				LocalDateTime now = LocalDateTime.now();
+				Long expire = redisTemplate.opsForValue().getOperations().getExpire(redisKey, TimeUnit.SECONDS);
+				opt.setStatus(WmReportOpt.WmReportOptStatus.GENERATED);
+				opt.setTtl(expire != null ? now.plusSeconds(expire) : now);
+				opt.setLatestUrl(o);
+			}
+
+		} else {
+			opt.setStatus(WmReportOpt.WmReportOptStatus.NOT_GENERATE);
+		}
+
+		return opt;
+	}
+}

+ 73 - 183
hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/service/impl/SysUserExportServiceImpl.java

@@ -19,6 +19,7 @@ import com.qunzhixinxi.hnqz.admin.api.entity.SysUserCertificate;
 import com.qunzhixinxi.hnqz.admin.api.entity.SysUserRole;
 import com.qunzhixinxi.hnqz.admin.api.entity.WmReportOpt;
 import com.qunzhixinxi.hnqz.admin.api.model.excel.SysUserExcelModel;
+import com.qunzhixinxi.hnqz.admin.aspect.ExportGuard;
 import com.qunzhixinxi.hnqz.admin.config.UpmsConfig;
 import com.qunzhixinxi.hnqz.admin.controller.user.SysUserController;
 import com.qunzhixinxi.hnqz.admin.event.UserExportEvent;
@@ -31,15 +32,18 @@ import com.qunzhixinxi.hnqz.admin.mapper.SysUserRoleMapper;
 import com.qunzhixinxi.hnqz.admin.service.SysFileService;
 import com.qunzhixinxi.hnqz.admin.service.SysUserAreaService;
 import com.qunzhixinxi.hnqz.admin.service.SysUserExportService;
+import com.qunzhixinxi.hnqz.admin.util.ExportUtils;
 import com.qunzhixinxi.hnqz.admin.util.OsEnvUtils;
+import com.qunzhixinxi.hnqz.admin.util.RedisUtils;
+import com.qunzhixinxi.hnqz.common.core.constant.CommonConstants;
 import com.qunzhixinxi.hnqz.common.core.exception.BizException;
 import com.qunzhixinxi.hnqz.common.core.util.SpringContextHolder;
 import com.qunzhixinxi.hnqz.common.security.service.HnqzUser;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.RandomStringUtils;
-import org.apache.commons.lang3.StringUtils;
 import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.retry.support.RetryTemplate;
 import org.springframework.stereotype.Service;
 
 import java.io.File;
@@ -76,17 +80,14 @@ public class SysUserExportServiceImpl implements SysUserExportService {
 	private final SysUserAreaService userAreaService;
 	private final SysDeptMapper deptMapper;
 	private final SysUserCertificateMapper userCertificateMapper;
-	private final SysFileService fileService;
 	private final UpmsConfig upmsConfig;
-
-	private static final long DEF_REPORT_TTL = 7L * 24 * 60 * 60 * 1000;
-	private static final String ERROR_MSG_UNKNOWN = "ERROR_未知错误,请联系管理员";
-	private static final String ERROR_MSG_NO_DATA = "ERROR_没有数据";
-	private static final String ERROR_MSG_UPLOAD_FAIL = "ERROR_上传OSS失败";
-
+	private final RetryTemplate retryTemplate;
+	private final RedisUtils redisUtils;
+	private final ExportUtils exportUtils;
 
 	/**
 	 * 异步导出
+	 * 设置重试次数和重试间隔
 	 *
 	 * @param user  用户
 	 * @param roles 角色
@@ -94,30 +95,12 @@ public class SysUserExportServiceImpl implements SysUserExportService {
 	 * @return {@link Boolean } 是否成功
 	 */
 	@Override
+	@ExportGuard(type = "USER")
 	public Boolean asyncExport(HnqzUser user, List<Integer> roles, SysUserDTO.OnList query) {
-		// 使用Redis原子操作实现限流,避免使用synchronized影响并发性能
-		String key = CacheConstants.ASYNC_EXPORT_LIMIT_KEY;
-		Long increment = redisTemplate.opsForValue().increment(key);
-
-		// 设置key的过期时间,避免计数器无限增长
-		if (increment != null && increment.equals(1L)) {
-			redisTemplate.expire(key, 1, TimeUnit.MINUTES);
-		}
-
-		// 检查是否超过限流阈值
-		if (increment != null && increment > upmsConfig.getAsyncExportLimit()) {
-			// 超过限流阈值时,减少计数器并抛出异常
-			redisTemplate.opsForValue().decrement(key);
-			throw new BizException("系统繁忙,请稍后再试");
-		}
-
-		// 缓存key
-		String cacheKey = String.format(CacheConstants.ASYNC_EXPORT_CACHE, ExportType.USER.getType(), user.getId());
-		// 更新状态为生成中
-		redisTemplate.opsForValue().set(cacheKey, WmReportOpt.WmReportOptStatus.GENERATING.name(), DEF_REPORT_TTL, TimeUnit.MILLISECONDS);
 
+		redisUtils.setExportStarting(ExportType.USER, user.getId());
 		SpringContextHolder.getApplicationContext().publishEvent(new UserExportEvent(user, roles, query));
-		return Boolean.TRUE;
+		return true;	
 	}
 
 	/**
@@ -130,114 +113,76 @@ public class SysUserExportServiceImpl implements SysUserExportService {
 	 */
 	@Override
 	public Boolean export(HnqzUser user, List<Integer> roles, SysUserDTO.OnList query) {
-		// 缓存key
-		String key = String.format(CacheConstants.ASYNC_EXPORT_CACHE, ExportType.USER.getType(), user.getId());
-
-		// 临时文件路径
-		String tempPath = OsEnvUtils.getEachEnvPaths().get(OsEnvUtils.TargetFile.TEMP.getName());
-		// 缓存文件名
-		String fileName = "人员_" + DateTimeFormatter.ofPattern(DatePattern.PURE_DATE_PATTERN)
-				.format(LocalDateTime.now()) + RandomStringUtils.randomNumeric(6) + ".xlsx";
-		String fullPath = tempPath + fileName;
-
 		try {
-			// 查询用户列表
-			List<SysUser> users = this.listUsers(user, roles, query);
+			return retryTemplate.execute(retryContext -> {
+				log.info("人员异步导出第{}次重试", retryContext.getRetryCount());
 
-			if (CollUtil.isEmpty(users)) {
-				log.info("用户列表为空");
-				redisTemplate.opsForValue().set(key, ERROR_MSG_NO_DATA, DEF_REPORT_TTL, TimeUnit.MILLISECONDS);
-				return Boolean.FALSE;
-			}
+				redisUtils.checkExportGlobalAllows(upmsConfig.getAsyncExportLimit());
 
-			// 构建Excel数据并导出
-			String resultValue = buildAndExportExcel(users, fullPath, fileName, user);
-			redisTemplate.opsForValue().set(key, resultValue, DEF_REPORT_TTL, TimeUnit.MILLISECONDS);
+				// 查询用户列表 构建Excel数据
+				List<SysUser> users = this.listUsers(user, roles, query);
+				List<SysUserExcelModel> data = buildExcelModel(users);
 
-			return !StrUtil.startWith(resultValue, "ERROR");
-		} finally {
-			// 清理临时文件
-			cleanupTempFile(fullPath);
+				// 导出
+				String resultValue = exportUtils.WriteExportExcel(ExportType.USER, data, SysUserExcelModel.class, user);
+				return !StrUtil.startWith(resultValue, "ERROR");
+			});
 
-			// 删除限流key
-			String limitKey = CacheConstants.ASYNC_EXPORT_LIMIT_KEY;
-			redisTemplate.delete(limitKey);
+		} finally {
+			// 释放全局限流
+			redisTemplate.opsForValue().decrement(CacheConstants.ASYNC_EXPORT_LIMIT_KEY);
 		}
 	}
+	
 
-	/**
-	 * 构建Excel数据并导出到文件
-	 *
-	 * @param users 用户列表
-	 * @param fullPath 完整文件路径
-	 * @param fileName 文件名
-	 * @param user 当前用户
-	 * @return 结果值(URL或错误信息)
-	 */
-	private String buildAndExportExcel(List<SysUser> users, String fullPath, String fileName, HnqzUser user) {
-		try {
-			// 查询企业信息
-			Map<Integer, SysDept> deptMap = queryDeptInfo(users);
-
-			// 查询角色信息
-			Map<Integer, String> roleMap = queryRoleInfo(users);
-			Map<Integer, List<SysUserRole>> userRolesMap = queryUserRoles(users);
-
-			// 查询备案信息
-			Map<Integer, Long> userCertMap = queryCertificateInfo(users);
-
-			// 转为excel列表
-			List<SysUserExcelModel> excelModels = users.stream().map(u -> {
-				SysUserExcelModel excelModel = BeanUtil.copyProperties(u, SysUserExcelModel.class, "lockFlag");
-				excelModel.setRealName(u.getRealname());
-				excelModel.setPhoneNumber(u.getPhone());
-				// 锁定状态
-				excelModel.setLockFlag("0".equals(u.getLockFlag()) ? "活跃" : "休眠");
-				// 创建时间
-				excelModel.setCreateTime(u.getCreateTime().format(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN)));
-
-				// 派工方
-				SysDept dept = deptMap.get(u.getDeptId());
-				if (dept != null) {
-					excelModel.setDeptName(dept.getName());
-				}
-
-				// 角色
-				List<SysUserRole> userRoleList = userRolesMap.get(u.getUserId());
-				if (CollUtil.isNotEmpty(userRoleList)) {
-					String roleNames = userRoleList.stream()
-							.map(userRole -> roleMap.getOrDefault(userRole.getRoleId(), ""))
-							.collect(Collectors.joining(","));
-					excelModel.setRoleList(roleNames);
-				}
-
-				// 备案状态
-				long certCount = userCertMap.getOrDefault(u.getUserId(), 0L);
-				excelModel.setCertificateFlag(certCount > 0 ? "是" : "否");
-
-				return excelModel;
-			}).collect(Collectors.toList());
-
-			// 写入excel文件
-			EasyExcel.write(fullPath, SysUserExcelModel.class).sheet("人员")
-					.doWrite(excelModels);
-			log.info("人员导出生成缓存文件:{}", fullPath);
-
-			// 上传oss
-			try (FileInputStream inputStream = new FileInputStream(fullPath)) {
-				Map<String, String> uploadResult = fileService.upload(inputStream, fileName, fileName, user.getUsername());
-				log.info("人员导出生成oss文件:{}", uploadResult);
-
-				if (CollUtil.isNotEmpty(uploadResult)) {
-					return uploadResult.get("url");
-				} else {
-					return ERROR_MSG_UPLOAD_FAIL;
-				}
-			}
-		} catch (Exception e) {
-			log.error("人员导出失败", e);
-			return ERROR_MSG_UNKNOWN;
+	private List<SysUserExcelModel> buildExcelModel(List<SysUser> users) {
+		if (CollUtil.isEmpty(users)) {
+			log.info("用户列表为空");
+			return List.of();
 		}
+		// 查询企业信息
+		Map<Integer, SysDept> deptMap = queryDeptInfo(users);
+
+		// 查询角色信息
+		Map<Integer, String> roleMap = queryRoleInfo(users);
+		Map<Integer, List<SysUserRole>> userRolesMap = queryUserRoles(users);
+
+		// 查询备案信息
+		Map<Integer, Long> userCertMap = queryCertificateInfo(users);
+
+		// 转为excel列表
+		List<SysUserExcelModel> excelModels = users.stream().map(u -> {
+			SysUserExcelModel excelModel = BeanUtil.copyProperties(u, SysUserExcelModel.class, "lockFlag");
+			excelModel.setRealName(u.getRealname());
+			excelModel.setPhoneNumber(u.getPhone());
+			// 锁定状态
+			excelModel.setLockFlag("0".equals(u.getLockFlag()) ? "活跃" : "休眠");
+			// 创建时间
+			excelModel.setCreateTime(u.getCreateTime().format(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN)));
+
+			// 派工方
+			SysDept dept = deptMap.get(u.getDeptId());
+			if (dept != null) {
+				excelModel.setDeptName(dept.getName());
+			}
+
+			// 角色
+			List<SysUserRole> userRoleList = userRolesMap.get(u.getUserId());
+			if (CollUtil.isNotEmpty(userRoleList)) {
+				String roleNames = userRoleList.stream()
+						.map(userRole -> roleMap.getOrDefault(userRole.getRoleId(), ""))
+						.collect(Collectors.joining(","));
+				excelModel.setRoleList(roleNames);
+			}
+
+			// 备案状态
+			long certCount = userCertMap.getOrDefault(u.getUserId(), 0L);
+			excelModel.setCertificateFlag(certCount > 0 ? "是" : "否");
+
+			return excelModel;
+		}).collect(Collectors.toList());
+
+		return excelModels;
 	}
 
 	/**
@@ -295,19 +240,6 @@ public class SysUserExportServiceImpl implements SysUserExportService {
 				.collect(Collectors.groupingBy(SysUserCertificate::getUserId, Collectors.counting()));
 	}
 
-	/**
-	 * 清理临时文件
-	 */
-	private void cleanupTempFile(String fullPath) {
-		try {
-			File file = new File(fullPath);
-			if (file.exists()) {
-				file.delete();
-			}
-		} catch (Exception e) {
-			log.warn("删除临时文件失败: {}", fullPath, e);
-		}
-	}
 
 
 	/**
@@ -442,46 +374,4 @@ public class SysUserExportServiceImpl implements SysUserExportService {
 		return userMapper.selectList(queryWrapper);
 	}
 
-	/**
-	 * 导出用户信息的结果
-	 *
-	 * @param user 用户
-	 * @return {@link WmReportOpt } 状态和结果
-	 */
-	@Override
-	public WmReportOpt exportResult(HnqzUser user) {
-		String key = String.format(CacheConstants.ASYNC_EXPORT_CACHE, ExportType.USER.getType(), user.getId());
-
-		String o = (String) redisTemplate.opsForValue().get(key);
-		WmReportOpt opt = new WmReportOpt();
-
-		if (StringUtils.isNotEmpty(o)) {
-			// 生成中的
-			if ("GENERATING".equals(o)) {
-				opt.setStatus(WmReportOpt.WmReportOptStatus.GENERATING);
-			}
-			// 生成失败的
-			else if (o.startsWith("ERROR")) {
-				opt.setStatus(WmReportOpt.WmReportOptStatus.ERROR);
-				opt.setErrorMsg(o.split(StrUtil.UNDERLINE)[1]);
-			}
-			// 生成失败的2
-			else if (!o.startsWith("/admin/sys-file")) {
-				opt.setStatus(WmReportOpt.WmReportOptStatus.ERROR);
-				opt.setErrorMsg(o);
-			}
-			// 成功的
-			else {
-				Long expire = redisTemplate.opsForValue().getOperations().getExpire(key, TimeUnit.SECONDS);
-				opt.setStatus(WmReportOpt.WmReportOptStatus.GENERATED);
-				opt.setTtl(LocalDateTime.now().plusSeconds(expire));
-				opt.setLatestUrl(o);
-			}
-
-		} else {
-			opt.setStatus(WmReportOpt.WmReportOptStatus.NOT_GENERATE);
-		}
-
-		return opt;
-	}
 }

+ 854 - 0
hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/service/impl/WmScorePackageExportServiceImpl.java

@@ -0,0 +1,854 @@
+package com.qunzhixinxi.hnqz.admin.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.date.DatePattern;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.qunzhixinxi.hnqz.admin.api.constant.CacheConstants;
+import com.qunzhixinxi.hnqz.admin.api.constant.UpmsState;
+import com.qunzhixinxi.hnqz.admin.api.constant.enums.EnableEnum;
+import com.qunzhixinxi.hnqz.admin.api.constant.enums.ExportType;
+import com.qunzhixinxi.hnqz.admin.api.constant.enums.PackageStatusEnum;
+import com.qunzhixinxi.hnqz.admin.api.entity.SysCheckChainNodeCheckHistory;
+import com.qunzhixinxi.hnqz.admin.api.entity.SysDept;
+import com.qunzhixinxi.hnqz.admin.api.entity.SysDeptRelation;
+import com.qunzhixinxi.hnqz.admin.api.entity.SysUser;
+import com.qunzhixinxi.hnqz.admin.api.entity.WmDaDrugEntDrugtable;
+import com.qunzhixinxi.hnqz.admin.api.entity.WmPackageTaskTypeQty;
+import com.qunzhixinxi.hnqz.admin.api.entity.WmScorePackage;
+import com.qunzhixinxi.hnqz.admin.api.entity.WmScorePackageStatus;
+import com.qunzhixinxi.hnqz.admin.api.entity.WmTask;
+import com.qunzhixinxi.hnqz.admin.api.model.excel.SysUserExcelModel;
+import com.qunzhixinxi.hnqz.admin.api.model.excel.WmScorePackageSubInfoExcelModel;
+import com.qunzhixinxi.hnqz.admin.aspect.ExportGuard;
+import com.qunzhixinxi.hnqz.admin.config.UpmsConfig;
+import com.qunzhixinxi.hnqz.admin.event.PackageExportEvent;
+import com.qunzhixinxi.hnqz.admin.manager.WmPackageExportScope;
+import com.qunzhixinxi.hnqz.admin.manager.WmPackageManager;
+import com.qunzhixinxi.hnqz.admin.mapper.SysCheckChainNodeCheckHistoryMapper;
+import com.qunzhixinxi.hnqz.admin.mapper.SysDeptMapper;
+import com.qunzhixinxi.hnqz.admin.mapper.SysDeptRelationMapper;
+import com.qunzhixinxi.hnqz.admin.mapper.SysUserMapper;
+import com.qunzhixinxi.hnqz.admin.mapper.WmDaDrugEntDrugtableMapper;
+import com.qunzhixinxi.hnqz.admin.mapper.WmScorePackageMapper;
+import com.qunzhixinxi.hnqz.admin.mapper.WmScorePackageStatusMapper;
+import com.qunzhixinxi.hnqz.admin.mapper.WmTaskMapper;
+import com.qunzhixinxi.hnqz.admin.service.WmPackageTaskTypeQtyService;
+import com.qunzhixinxi.hnqz.admin.service.WmScorePackageExportService;
+import com.qunzhixinxi.hnqz.admin.util.ExportUtils;
+import com.qunzhixinxi.hnqz.admin.util.RedisUtils;
+import com.qunzhixinxi.hnqz.common.core.constant.CommonConstants;
+import com.qunzhixinxi.hnqz.common.core.exception.BizException;
+import com.qunzhixinxi.hnqz.common.core.util.SpringContextHolder;
+import com.qunzhixinxi.hnqz.common.security.service.HnqzUser;
+import com.qunzhixinxi.hnqz.common.security.util.SecurityUtils;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * 积分包导出服务 impl
+ *
+ * @author snows
+ * @date 2025/08/04
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class WmScorePackageExportServiceImpl implements WmScorePackageExportService {
+	private final WmScorePackageMapper scorePackageMapper;
+	private final WmTaskMapper taskMapper;
+	private final SysUserMapper userMapper;
+	private final SysDeptMapper deptMapper;
+	private final SysDeptRelationMapper deptRelationMapper;
+	private final WmDaDrugEntDrugtableMapper drugEntDrugtableMapper;
+	private final WmScorePackageStatusMapper scorePackageStatusMapper;
+	private final SysCheckChainNodeCheckHistoryMapper checkChainNodeCheckHistoryMapper;
+	private final WmPackageTaskTypeQtyService packageTaskTypeQtyService;
+	private final RedisTemplate<String, Object> redisTemplate;
+	private final UpmsConfig upmsConfig;
+	private final RedisUtils redisUtils;
+	private final ExportUtils exportUtils;
+
+
+	/**
+	 * 异步导出
+	 *
+	 * @param user      用户
+	 * @param roles     角色
+	 * @param startDate 开始日期
+	 * @param endDate   结束日期
+	 * @return {@link Boolean } 是否成功
+	 */
+	@Override
+	@ExportGuard(type = "SCORE_PACKAGE_SUB")
+	public Boolean asyncExport(HnqzUser user, List<Integer> roles, LocalDate startDate, LocalDate endDate) {
+			redisUtils.setExportStarting(ExportType.SCORE_PACKAGE_SUB, user.getId());
+
+			SpringContextHolder.getApplicationContext().publishEvent(new PackageExportEvent(user, roles, startDate, endDate));
+			return Boolean.TRUE;
+	}
+
+	/**
+	 * 导出积分包
+	 *
+	 * @param user      用户
+	 * @param roles     角色
+	 * @param startDate 开始日期
+	 * @param endDate   结束日期
+	 * @return {@link Boolean } 是否成功
+	 */
+	@Override
+	public Boolean export(HnqzUser user, List<Integer> roles, LocalDate startDate, LocalDate endDate) {
+		redisUtils.checkExportGlobalAllows(upmsConfig.getAsyncExportLimit());
+
+		try {
+			// 获取数据
+			List<WmScorePackageSubInfoExcelModel> data = this.getExportData(user, roles, startDate, endDate);
+
+			// 导出
+			String resultValue = exportUtils.WriteExportExcel(ExportType.SCORE_PACKAGE_SUB, data, SysUserExcelModel.class, user);
+			return !StrUtil.startWith(resultValue, "ERROR");
+		} finally {
+			// 释放全局限流
+			redisTemplate.opsForValue().decrement(CacheConstants.ASYNC_EXPORT_LIMIT_KEY);
+		}
+	}
+
+	/**
+	 * 获取导出数据
+	 *
+	 * @param user      用户
+	 * @param roles     角色
+	 * @param startDate 开始日期
+	 * @param endDate   结束日期
+	 * @return {@link List }<{@link WmScorePackageSubInfoExcelModel }> 结果
+	 * @see WmPackageManager#exportPkgInfo(LocalDate, LocalDate) 参考代码(存在冗余待合并)
+	 */
+	private List<WmScorePackageSubInfoExcelModel> getExportData(HnqzUser user, List<Integer> roles, LocalDate startDate, LocalDate endDate) {
+		WmPackageExportScope scope = this.getWmPackageExportScope(user, roles, startDate, endDate);
+		Map<String, WmDaDrugEntDrugtable> drugtableMap = scope.getDrugtableMap();
+		Set<Integer> operatorRoleIds = scope.getOperatorRoleIds();
+		List<String> cPkgIds = scope.getCPkgIds();
+		List<WmScorePackage> childrenPkgs = scope.getChildrenPkgs();
+		Map<String, List<String>> parentId2PkgMap = scope.getParentId2PkgMap();
+		Map<Integer, List<WmPackageTaskTypeQty>> pttMap = scope.getPttMap();
+
+		// 获取区域的上级包
+		List<String> pids =
+				childrenPkgs.stream()
+						.map(WmScorePackage::getRelationScoreId)
+						.distinct()
+						.sorted()
+						.collect(Collectors.toList());
+
+		Map<String, WmScorePackage> pMap =
+				scorePackageMapper
+						.selectList(
+								Wrappers.<WmScorePackage>lambdaQuery()
+										.eq(WmScorePackage::getEnableFlag, EnableEnum.ENABLE.val())
+										.in(WmScorePackage::getId, pids))
+						.stream()
+						.collect(Collectors.toMap(WmScorePackage::getId, Function.identity()));
+
+		// 获取全部的任务
+		List<WmTask> tasks =
+				taskMapper.selectList(
+						Wrappers.<WmTask>lambdaQuery()
+								.in(
+										WmTask::getScorePackageId,
+										cPkgIds));
+
+		// 获取所有执行包领取记录
+		List<WmScorePackageStatus> scorePackageStatuses =
+				scorePackageStatusMapper.selectList(Wrappers.<WmScorePackageStatus>lambdaQuery()
+						.in(WmScorePackageStatus::getPackageId, cPkgIds)
+						.eq(WmScorePackageStatus::getStatus, PackageStatusEnum.APPROVED.val()));
+		Set<String> userIds = scorePackageStatuses.stream().map(WmScorePackageStatus::getUserId).collect(Collectors.toSet());
+
+		// 获取所有任务的user
+		List<SysUser> users = userMapper.selectBatchIds(userIds);
+		Map<Integer, SysUser> userMap =
+				users.stream().collect(Collectors.toMap(SysUser::getUserId, Function.identity()));
+
+		// 转换为每个执行包对应的接包人信息
+		Map<String, SysUser> packageUserMap = scorePackageStatuses.stream()
+				.collect(Collectors.toMap(WmScorePackageStatus::getPackageId,
+						ps -> userMap.get(Integer.parseInt(ps.getUserId())), (u1, u2) -> u1));
+
+		// 根据包id分组
+		Map<String, List<WmTask>> pkg2TaskListMap =
+				tasks.stream().collect(Collectors.groupingBy(WmTask::getScorePackageId));
+
+		Set<Integer> collect =
+				checkChainNodeCheckHistoryMapper
+						.selectList(
+								Wrappers.<SysCheckChainNodeCheckHistory>lambdaQuery()
+										.eq(
+												SysCheckChainNodeCheckHistory::getCheckResult,
+												Boolean.TRUE)
+										.eq(SysCheckChainNodeCheckHistory::getNodeId, 6))
+						.stream()
+						.map(SysCheckChainNodeCheckHistory::getTargetId)
+						.collect(Collectors.toSet());
+
+		List<WmScorePackageSubInfoExcelModel> result =
+				childrenPkgs.parallelStream()
+						.map(
+								pkg -> {
+
+									// 基础信息
+									WmScorePackageSubInfoExcelModel model = new WmScorePackageSubInfoExcelModel();
+									model.setPkgId(pkg.getId());
+									model.setPkgName(pkg.getScorePackageName());
+									if (!operatorRoleIds.contains(37)) {
+										model.setScore(String.valueOf(pkg.getScore()));
+									}
+
+									// 父级包
+									WmScorePackage wmScorePackages = pMap.get(pkg.getRelationScoreId());
+									model.setParentPkgProvAbbr(pkg.getProvAbbr());
+									model.setParentPkgName(
+											wmScorePackages != null ? wmScorePackages.getScorePackageName() : "");
+
+									// 产品&生产企业
+									WmDaDrugEntDrugtable drugtable = drugtableMap.get(pkg.getDrugtable()[0]);
+
+									model.setSkuName(drugtable == null ? "未分配产品" : drugtable.getDrugname());
+									model.setProdName(drugtable == null ? "未分配产品" : drugtable.getDrugnameTy());
+									model.setMah(drugtable == null ? "未知" : drugtable.getDrugEntName());
+
+									SysUser taskUser = packageUserMap.get(pkg.getId());
+									// 接包人姓名
+									model.setTaskUserName(taskUser != null ? taskUser.getRealname() : "");
+									// 接包人电话
+									model.setTaskUserPhone(taskUser != null ? taskUser.getPhone() : "");
+
+									List<String> cPkgIdList = parentId2PkgMap.get(pkg.getId());
+
+									// 任务数据统计
+									if (CollUtil.isNotEmpty(cPkgIdList)) {
+
+										// 任务提交总数
+										int tt53Submit = 0;
+										int tt52submit = 0;
+										int tt51submit = 0;
+										int tt14submit = 0;
+										int tt17submit = 0;
+										int tt12submit = 0;
+										int tt13submit = 0;
+										int tt1submit = 0;
+										int tt2submit = 0;
+										int tt5submit = 0;
+										int tt3submit = 0;
+										int tt4submit = 0;
+										int tt64submit = 0;
+										int tt19submit = 0;
+
+										// 任务拒绝记录
+										int tt53rejected = 0;
+										int tt52rejected = 0;
+										int tt51rejected = 0;
+										int tt14rejected = 0;
+										int tt17rejected = 0;
+										int tt12rejected = 0;
+										int tt13rejected = 0;
+										int tt1rejected = 0;
+										int tt2rejected = 0;
+										int tt5rejected = 0;
+										int tt3rejected = 0;
+										int tt4rejected = 0;
+										int tt64rejected = 0;
+										int tt19rejected = 0;
+
+										for (String cPkgId : cPkgIdList) {
+
+											List<WmTask> list = pkg2TaskListMap.get(cPkgId);
+
+											if (CollUtil.isEmpty(list)) {
+												continue;
+											}
+
+											for (WmTask task : list) {
+
+												boolean rejected =
+														UpmsState.TaskState.REJECTED.getState().equals(task.getTaskStatus());
+
+												String taskTypeId = task.getTaskTypeId();
+
+												if (StrUtil.equals(taskTypeId, "53")) {
+													tt53Submit++;
+
+													if (rejected) {
+														tt53rejected++;
+													}
+												}
+
+												if (StrUtil.equals(taskTypeId, "52")) {
+													tt52submit++;
+
+													if (rejected) {
+														tt52rejected++;
+													}
+												}
+
+												if (StrUtil.equals(taskTypeId, "51")) {
+													tt51submit++;
+													if (rejected) {
+														tt51rejected++;
+													}
+												}
+
+												if (StrUtil.equals(taskTypeId, "14")) {
+													tt14submit++;
+													if (rejected) {
+														tt14rejected++;
+													}
+												}
+
+												if (StrUtil.equals(taskTypeId, "17")) {
+													tt17submit++;
+													if (rejected) {
+														tt17rejected++;
+													}
+												}
+
+												if (StrUtil.equals(taskTypeId, "12")) {
+													tt12submit++;
+													if (rejected) {
+														tt12rejected++;
+													}
+												}
+
+												if (StrUtil.equals(taskTypeId, "13")) {
+													tt13submit++;
+													if (rejected) {
+														tt13rejected++;
+													}
+												}
+
+												if (StrUtil.equals(taskTypeId, "1")) {
+													tt1submit++;
+													if (rejected) {
+														tt1rejected++;
+													}
+												}
+
+												if (StrUtil.equals(taskTypeId, "2")) {
+													tt2submit++;
+													if (rejected) {
+														tt2rejected++;
+													}
+												}
+
+												if (StrUtil.equals(taskTypeId, "5")) {
+													tt5submit++;
+													if (rejected) {
+														tt5rejected++;
+													}
+												}
+
+												if (StrUtil.equals(taskTypeId, "3")) {
+													tt3submit++;
+													if (rejected) {
+														tt3rejected++;
+													}
+												}
+
+												if (StrUtil.equals(taskTypeId, "4")) {
+													tt4submit++;
+													if (rejected) {
+														tt4rejected++;
+													}
+												}
+
+												if (StrUtil.equals(taskTypeId, "64")) {
+													tt64submit++;
+													if (rejected) {
+														tt64rejected++;
+													}
+												}
+
+												if (StrUtil.equals(taskTypeId, "19")) {
+													tt19submit++;
+													if (rejected) {
+														tt19rejected++;
+													}
+												}
+											}
+										}
+
+										model.setTt53Submit(String.valueOf(tt53Submit - tt53rejected));
+										model.setTt52submit(String.valueOf(tt52submit - tt52rejected));
+										model.setTt51submit(String.valueOf(tt51submit - tt51rejected));
+										model.setTt14submit(String.valueOf(tt14submit - tt14rejected));
+										model.setTt17submit(String.valueOf(tt17submit - tt17rejected));
+										model.setTt12submit(String.valueOf(tt12submit - tt12rejected));
+										model.setTt13submit(String.valueOf(tt13submit - tt13rejected));
+										model.setTt1submit(String.valueOf(tt1submit - tt1rejected));
+										model.setTt2submit(String.valueOf(tt2submit - tt2rejected));
+										model.setTt5submit(String.valueOf(tt5submit - tt5rejected));
+										model.setTt3submit(String.valueOf(tt3submit - tt3rejected));
+										model.setTt4submit(String.valueOf(tt4submit - tt4rejected));
+										model.setTt64submit(String.valueOf(tt64submit - tt64rejected));
+										model.setTt19submit(String.valueOf(tt19submit - tt19rejected));
+
+										model.setTt53rejected(String.valueOf(tt53rejected));
+										model.setTt52rejected(String.valueOf(tt52rejected));
+										model.setTt51rejected(String.valueOf(tt51rejected));
+										model.setTt14rejected(String.valueOf(tt14rejected));
+										model.setTt17rejected(String.valueOf(tt17rejected));
+										model.setTt12rejected(String.valueOf(tt12rejected));
+										model.setTt13rejected(String.valueOf(tt13rejected));
+										model.setTt1rejected(String.valueOf(tt1rejected));
+										model.setTt2rejected(String.valueOf(tt2rejected));
+										model.setTt5rejected(String.valueOf(tt5rejected));
+										model.setTt3rejected(String.valueOf(tt3rejected));
+										model.setTt4rejected(String.valueOf(tt4rejected));
+										model.setTt64rejected(String.valueOf(tt64rejected));
+										model.setTt19rejected(String.valueOf(tt19rejected));
+									}
+
+									// 下发任务统计
+									if (CollUtil.isNotEmpty(cPkgIdList)) {
+
+										int tt53dist = 0;
+										int tt52dist = 0;
+										int tt51dist = 0;
+										int tt14dist = 0;
+										int tt17dist = 0;
+										int tt12dist = 0;
+										int tt13dist = 0;
+										int tt1dist = 0;
+										int tt2dist = 0;
+										int tt5dist = 0;
+										int tt3dist = 0;
+										int tt4dist = 0;
+										int tt64dist = 0;
+										int tt19dist = 0;
+										long scoreTasks = 0;
+
+										for (String cPkgId : cPkgIdList) {
+											List<WmPackageTaskTypeQty> packageTaskTypeQtyList =
+													pttMap.get(Integer.parseInt(cPkgId));
+											if (CollUtil.isEmpty(packageTaskTypeQtyList)) {
+												continue;
+											}
+
+											for (WmPackageTaskTypeQty packageTaskTypeQty : packageTaskTypeQtyList) {
+												String taskTypeName = packageTaskTypeQty.getTaskTypeName();
+
+												scoreTasks += packageTaskTypeQty.getPrice() * packageTaskTypeQty.getQty();
+
+												if (StrUtil.equals(taskTypeName, "基础拜访")) {
+													tt53dist += packageTaskTypeQty.getQty();
+												}
+
+												if (StrUtil.equals(taskTypeName, "专项拜访")) {
+													tt52dist += packageTaskTypeQty.getQty();
+												}
+
+												if (StrUtil.equals(taskTypeName, "专业拜访")) {
+													tt51dist += packageTaskTypeQty.getQty();
+												}
+
+												if (StrUtil.equals(taskTypeName, "数据信息收集")) {
+													tt14dist += packageTaskTypeQty.getQty();
+												}
+
+												if (StrUtil.equals(taskTypeName, "医学警戒信息收集")) {
+													tt17dist += packageTaskTypeQty.getQty();
+												}
+
+												if (StrUtil.equals(taskTypeName, "产品展示")) {
+													tt12dist += packageTaskTypeQty.getQty();
+												}
+
+												if (StrUtil.equals(taskTypeName, "业务宣传服务")) {
+													tt13dist += packageTaskTypeQty.getQty();
+												}
+
+												if (StrUtil.equals(taskTypeName, "POV科室会")) {
+													tt1dist += packageTaskTypeQty.getQty();
+												}
+
+												if (StrUtil.equals(taskTypeName, "区县学术会议")) {
+													tt2dist += packageTaskTypeQty.getQty();
+												}
+
+												if (StrUtil.equals(taskTypeName, "沙龙会")) {
+													tt5dist += packageTaskTypeQty.getQty();
+												}
+
+												if (StrUtil.equals(taskTypeName, "市级学术会议")) {
+													tt3dist += packageTaskTypeQty.getQty();
+												}
+
+												if (StrUtil.equals(taskTypeName, "省级学术会议")) {
+													tt4dist += packageTaskTypeQty.getQty();
+												}
+
+												if (StrUtil.equals(taskTypeName, "线上学术会议")) {
+													tt64dist += packageTaskTypeQty.getQty();
+												}
+
+												if (StrUtil.equals(taskTypeName, "健康教育课堂")) {
+													tt19dist += packageTaskTypeQty.getQty();
+												}
+											}
+										}
+
+										model.setScoreTasks(String.valueOf(scoreTasks));
+
+										model.setTt53dist(String.valueOf(tt53dist));
+										model.setTt52dist(String.valueOf(tt52dist));
+										model.setTt51dist(String.valueOf(tt51dist));
+										model.setTt14dist(String.valueOf(tt14dist));
+										model.setTt17dist(String.valueOf(tt17dist));
+										model.setTt12dist(String.valueOf(tt12dist));
+										model.setTt13dist(String.valueOf(tt13dist));
+										model.setTt1dist(String.valueOf(tt1dist));
+										model.setTt2dist(String.valueOf(tt2dist));
+										model.setTt5dist(String.valueOf(tt5dist));
+										model.setTt3dist(String.valueOf(tt3dist));
+										model.setTt4dist(String.valueOf(tt4dist));
+										model.setTt64dist(String.valueOf(tt64dist));
+										model.setTt19dist(String.valueOf(tt19dist));
+									}
+
+									// 审批统计
+									if (CollUtil.isNotEmpty(cPkgIdList)) {
+
+										int tt53checked = 0;
+										int tt52checked = 0;
+										int tt51checked = 0;
+										int tt14checked = 0;
+										int tt17checked = 0;
+										int tt12Checked = 0;
+										int tt13checked = 0;
+										int tt1checked = 0;
+										int tt2Checked = 0;
+										int tt5checked = 0;
+										int tt3checked = 0;
+										int tt4checked = 0;
+										int tt64checked = 0;
+										int tt19checked = 0;
+
+										for (String cPkgId : cPkgIdList) {
+											// 获取单个子包任务信息
+											List<WmTask> tasks1 = pkg2TaskListMap.get(cPkgId);
+											if (CollUtil.isEmpty(tasks1)) {
+												continue;
+											}
+
+											List<Integer> tIds =
+													tasks1.stream()
+															.mapToInt(t -> Integer.parseInt(t.getId()))
+															.boxed()
+															.distinct()
+															.sorted()
+															.collect(Collectors.toList());
+
+											if (CollUtil.isEmpty(collect)) {
+												continue;
+											}
+
+											for (WmTask task : tasks1) {
+												Integer id = Integer.valueOf(task.getId());
+
+												if (!collect.contains(id)) {
+													continue;
+												}
+
+												String taskTypeId = task.getTaskTypeId();
+
+												if (StrUtil.equals(taskTypeId, "53")) {
+													tt53checked++;
+												}
+
+												if (StrUtil.equals(taskTypeId, "52")) {
+													tt52checked++;
+												}
+
+												if (StrUtil.equals(taskTypeId, "51")) {
+													tt51checked++;
+												}
+
+												if (StrUtil.equals(taskTypeId, "14")) {
+													tt14checked++;
+												}
+
+												if (StrUtil.equals(taskTypeId, "17")) {
+													tt17checked++;
+												}
+
+												if (StrUtil.equals(taskTypeId, "12")) {
+													tt12Checked++;
+												}
+
+												if (StrUtil.equals(taskTypeId, "13")) {
+													tt13checked++;
+												}
+
+												if (StrUtil.equals(taskTypeId, "1")) {
+													tt1checked++;
+												}
+
+												if (StrUtil.equals(taskTypeId, "2")) {
+													tt2Checked++;
+												}
+
+												if (StrUtil.equals(taskTypeId, "5")) {
+													tt5checked++;
+												}
+
+												if (StrUtil.equals(taskTypeId, "3")) {
+													tt3checked++;
+												}
+
+												if (StrUtil.equals(taskTypeId, "4")) {
+													tt4checked++;
+												}
+
+												if (StrUtil.equals(taskTypeId, "64")) {
+													tt64checked++;
+												}
+
+												if (StrUtil.equals(taskTypeId, "19")) {
+													tt19checked++;
+												}
+											}
+										}
+
+										model.setTt53checked(String.valueOf(tt53checked));
+										model.setTt52checked(String.valueOf(tt52checked));
+										model.setTt51checked(String.valueOf(tt51checked));
+										model.setTt14checked(String.valueOf(tt14checked));
+										model.setTt17checked(String.valueOf(tt17checked));
+										model.setTt12Checked(String.valueOf(tt12Checked));
+										model.setTt13checked(String.valueOf(tt13checked));
+										model.setTt1checked(String.valueOf(tt1checked));
+										model.setTt2checked(String.valueOf(tt2Checked));
+										model.setTt5checked(String.valueOf(tt5checked));
+										model.setTt3checked(String.valueOf(tt3checked));
+										model.setTt4checked(String.valueOf(tt4checked));
+										model.setTt64checked(String.valueOf(tt64checked));
+										model.setTt19checked(String.valueOf(tt19checked));
+									}
+
+									return model;
+								})
+						.collect(Collectors.toList());
+
+		return result;
+	}
+
+	private WmPackageExportScope getWmPackageExportScope(HnqzUser user, List<Integer> roles, LocalDate startDate, LocalDate endDate) {
+		Set<Integer> ignoreIds = new HashSet<>();
+		ignoreIds.add(1716964676);
+		ignoreIds.add(-1020826);
+		ignoreIds.add(-1019986);
+
+		Set<Integer> operatorRoleIds = new HashSet<>(roles);
+
+		// 获取所有的企业
+		List<SysDept> depts =
+				deptMapper
+						.selectList(
+								Wrappers.<SysDept>lambdaQuery()
+										.eq(SysDept::getDelFlag, CommonConstants.STATUS_NORMAL))
+						.stream()
+						.filter(d -> !ignoreIds.contains(d.getDeptId()))
+						.collect(Collectors.toList());
+
+		if (CollUtil.isEmpty(depts)) {
+			throw new BizException("不存在生效的企业信息,无法获取导出数据");
+		}
+
+		// 分别过滤区域和服务商
+		List<Integer> parentDeptIds =
+				operatorRoleIds.contains(37)
+						? // 服务商的区域ID
+						deptRelationMapper
+								.selectList(
+										Wrappers.<SysDeptRelation>lambdaQuery()
+												.ne(SysDeptRelation::getAncestor, SecurityUtils.getUser().getDeptId())
+												.eq(SysDeptRelation::getDescendant, SecurityUtils.getUser().getDeptId()))
+								.stream()
+								.map(SysDeptRelation::getAncestor)
+								.collect(Collectors.toList())
+						: new ArrayList<>();
+		if (operatorRoleIds.contains(37) && CollUtil.isEmpty(parentDeptIds)) {
+			throw new RuntimeException("没有找到对应的区域");
+		}
+		List<Integer> childDeptIds =
+				operatorRoleIds.contains(4)
+						? // 区域的服务商ID
+						deptRelationMapper
+								.selectList(
+										Wrappers.<SysDeptRelation>lambdaQuery()
+												.eq(SysDeptRelation::getAncestor, user.getDeptId())
+												.ne(SysDeptRelation::getDescendant, user.getDeptId()))
+								.stream()
+								.map(SysDeptRelation::getDescendant)
+								.collect(Collectors.toList())
+						: new ArrayList<>();
+		if (operatorRoleIds.contains(4) && CollUtil.isEmpty(childDeptIds)) {
+			throw new RuntimeException("没有找到对应的服务商");
+		}
+
+		Map<Integer, SysDept> dis =
+				depts.stream()
+						.filter(d -> d.getLevel() == 3)
+						.filter(
+								d ->
+										!operatorRoleIds.contains(4)
+												|| operatorRoleIds.contains(4)
+												&& d.getDeptId().equals(user.getDeptId())) // 区域管理员
+						.filter(
+								d ->
+										!operatorRoleIds.contains(43)
+												|| operatorRoleIds.contains(43)
+												&& d.getDeptId().equals(user.getDeptId())) // 地市管理员
+						.filter(
+								d ->
+										!operatorRoleIds.contains(37)
+												|| operatorRoleIds.contains(37)
+												&& parentDeptIds.contains(d.getDeptId())) // 服务商管理员
+						.collect(Collectors.toMap(SysDept::getDeptId, Function.identity()));
+		Map<Integer, SysDept> service =
+				depts.stream()
+						.filter(d -> d.getLevel() == 4)
+						.filter(
+								d ->
+										!operatorRoleIds.contains(4)
+												|| operatorRoleIds.contains(4)
+												&& childDeptIds.contains(d.getDeptId())) // 区域管理员
+						.filter(
+								d ->
+										!operatorRoleIds.contains(43)
+												|| operatorRoleIds.contains(43)
+												&& childDeptIds.contains(d.getDeptId())) // 地市管理员
+						.filter(
+								d ->
+										!operatorRoleIds.contains(37)
+												|| operatorRoleIds.contains(37)
+												&& d.getDeptId().equals(user.getDeptId())) // 服务商管理员
+						.collect(Collectors.toMap(SysDept::getDeptId, Function.identity()));
+
+		if (CollUtil.isEmpty(dis) || CollUtil.isEmpty(service)) {
+			throw new BizException("不存在生效的区域或服务商,无法获取导出数据");
+		}
+
+		// 获取区域发的包
+		List<WmScorePackage> pkgs =
+				scorePackageMapper.selectList(
+						Wrappers.<WmScorePackage>lambdaQuery()
+								.eq(WmScorePackage::getEnableFlag, EnableEnum.ENABLE.val())
+								.between(WmScorePackage::getCreateTime, startDate, endDate)
+								.in(
+										WmScorePackage::getSendPackageDeptId,
+										dis.keySet().stream()
+												.map(String::valueOf)
+												.sorted()
+												.collect(Collectors.toList())));
+		if (operatorRoleIds.contains(37)) {
+			pkgs =
+					pkgs.stream()
+							.filter(
+									p -> p.getDeptId().equals(Integer.toString(user.getDeptId())))
+							.collect(Collectors.toList());
+		}
+		if (CollUtil.isEmpty(pkgs)) {
+			throw new BizException(
+					String.format(
+							"%s至%s没有区域发包记录,不支持导出",
+							DateTimeFormatter.ofPattern(DatePattern.CHINESE_DATE_PATTERN).format(startDate),
+							DateTimeFormatter.ofPattern(DatePattern.CHINESE_DATE_PATTERN).format(endDate)));
+		}
+
+		List<String> pkgIds =
+				pkgs.stream().map(WmScorePackage::getId).distinct().sorted().collect(Collectors.toList());
+
+		// 获取子集包
+		List<WmScorePackage> childrenPkgs =
+				scorePackageMapper.selectList(
+						Wrappers.<WmScorePackage>lambdaQuery()
+								.eq(WmScorePackage::getEnableFlag, EnableEnum.ENABLE.val())
+								.in(WmScorePackage::getRelationScoreId, pkgIds));
+
+		if (CollUtil.isEmpty(childrenPkgs)) {
+			throw new BizException("没有找到可导出的个人包记录");
+		}
+		List<String> cPkgIds =
+				childrenPkgs.stream()
+						.map(WmScorePackage::getId)
+						.distinct()
+						.sorted()
+						.collect(Collectors.toList());
+
+		// 父级下的所有子集
+		Map<String, List<String>> parentId2PkgMap =
+				CollUtil.isEmpty(childrenPkgs)
+						? Collections.emptyMap()
+						: childrenPkgs.stream()
+						.collect(
+								Collectors.groupingBy(
+										WmScorePackage::getRelationScoreId,
+										Collectors.mapping(WmScorePackage::getId, Collectors.toList())));
+
+		// 获取下发的
+		List<WmPackageTaskTypeQty> taskTypeQties =
+				packageTaskTypeQtyService.listPkgTaskTypeQtyByPkgIds(
+						cPkgIds.stream()
+								.mapToInt(Integer::parseInt)
+								.boxed()
+								.distinct()
+								.sorted()
+								.collect(Collectors.toList()));
+
+		if (CollUtil.isEmpty(taskTypeQties)) {
+			throw new BizException("没有找到可导出的任务下发记录");
+		}
+		Map<Integer, List<WmPackageTaskTypeQty>> pttMap =
+				taskTypeQties.stream().collect(Collectors.groupingBy(WmPackageTaskTypeQty::getPackageId));
+
+		// 获取包所关联的产品
+		List<String> drugIds =
+				pkgs.stream()
+						.flatMap(p -> Arrays.stream(p.getDrugtable()))
+						.distinct()
+						.sorted()
+						.collect(Collectors.toList());
+
+		Map<String, WmDaDrugEntDrugtable> drugtableMap =
+				CollUtil.isEmpty(drugIds)
+						? Collections.emptyMap()
+						: drugEntDrugtableMapper.selectBatchIds(drugIds).stream()
+						.collect(Collectors.toMap(WmDaDrugEntDrugtable::getId, Function.identity()));
+
+		return new WmPackageExportScope(
+				dis,
+				service,
+				pkgs,
+				drugtableMap,
+				operatorRoleIds,
+				childrenPkgs,
+				cPkgIds,
+				parentId2PkgMap,
+				pttMap);
+	}
+}

+ 48 - 0
hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/service/impl/WmTaskSupervisionServiceImpl.java

@@ -4,18 +4,31 @@ import cn.hutool.core.collection.CollUtil;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.qunzhixinxi.hnqz.admin.api.constant.UpmsState;
+import com.qunzhixinxi.hnqz.admin.api.constant.enums.ExportType;
 import com.qunzhixinxi.hnqz.admin.api.dto.WmSupervisionDto;
 import com.qunzhixinxi.hnqz.admin.api.entity.WmTaskSupervision;
+import com.qunzhixinxi.hnqz.admin.api.model.excel.TaskCheckHistoryExcelModel;
+import com.qunzhixinxi.hnqz.admin.aspect.ExportGuard;
+import com.qunzhixinxi.hnqz.admin.config.UpmsConfig;
+import com.qunzhixinxi.hnqz.admin.event.TaskCheckSupExportEvent;
 import com.qunzhixinxi.hnqz.admin.mapper.WmTaskSupervisionMapper;
 import com.qunzhixinxi.hnqz.admin.service.WmTaskSupervisionService;
+import com.qunzhixinxi.hnqz.admin.util.ExportUtils;
+import com.qunzhixinxi.hnqz.admin.util.RedisUtils;
+import com.qunzhixinxi.hnqz.common.core.util.SpringContextHolder;
 import com.qunzhixinxi.hnqz.common.security.service.HnqzUser;
 import com.qunzhixinxi.hnqz.common.security.util.SecurityUtils;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+
+import org.springframework.retry.support.RetryTemplate;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
+import java.time.LocalDate;
 import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -29,6 +42,12 @@ import java.util.List;
 @AllArgsConstructor
 public class WmTaskSupervisionServiceImpl extends ServiceImpl<WmTaskSupervisionMapper, WmTaskSupervision> implements WmTaskSupervisionService {
 
+    private final WmTaskSupervisionMapper wmTaskSupervisionMapper;
+	private final RetryTemplate retryTemplate;
+	private final RedisUtils redisUtils;
+	private final UpmsConfig upmsConfig;
+    private final ExportUtils exportUtils;
+
     /**
      * 创建审核
      *
@@ -121,4 +140,33 @@ public class WmTaskSupervisionServiceImpl extends ServiceImpl<WmTaskSupervisionM
         return this.baseMapper.selectByPkgIds(pkgIds, taskBeginTime, taskEndTime);
     }
 
+    @Override
+    @ExportGuard(type = "CHECK_SUP")
+    public void asyncExportTaskCheckSup(HnqzUser user, LocalDate[] taskPeriod) {
+
+        redisUtils.setExportStarting(ExportType.CHECK_SUP, user.getId());
+        SpringContextHolder.getApplicationContext().publishEvent(new TaskCheckSupExportEvent(user, taskPeriod));
+    }
+
+    @Override
+    public List<TaskCheckHistoryExcelModel> selectTaskSupProcess(HnqzUser user,  LocalDate[] taskPeriod) {
+        List<TaskCheckHistoryExcelModel> t = List.of();
+        try {
+            t = retryTemplate.execute(retryContext -> {
+                log.info("人员异步导出第{}次重试", retryContext.getRetryCount());
+
+                redisUtils.checkExportGlobalAllows(upmsConfig.getAsyncExportLimit());
+                List<TaskCheckHistoryExcelModel> data = 
+                    wmTaskSupervisionMapper.selectTaskSupProcess(LocalDateTime.of(taskPeriod[0], LocalTime.MIN), LocalDateTime.of(taskPeriod[1], LocalTime.MAX));
+                // 导出
+                exportUtils.WriteExportExcel(ExportType.CHECK_SUP, data, TaskCheckHistoryExcelModel.class, user);
+
+                return data;
+            });
+		} finally {
+            redisUtils.releaseExportGlobalAllows();
+		}
+
+        return t;
+    }
 }

+ 93 - 0
hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/util/ExportUtils.java

@@ -0,0 +1,93 @@
+package com.qunzhixinxi.hnqz.admin.util;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.date.DatePattern;
+import com.alibaba.excel.EasyExcel;
+import com.qunzhixinxi.hnqz.admin.api.constant.enums.ExportType;
+import com.qunzhixinxi.hnqz.admin.service.SysFileService;
+import com.qunzhixinxi.hnqz.common.core.constant.CommonConstants;
+import com.qunzhixinxi.hnqz.common.security.service.HnqzUser;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import javax.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+
+import org.apache.commons.lang3.RandomStringUtils;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
+
+/**
+ * async export 工具类
+ *
+ */
+@Slf4j
+@Component
+public final class ExportUtils {
+
+  @Resource private RedisTemplate<String, Object> redisTemplate;
+  @Resource private SysFileService fileService;
+
+  public static final String ERROR_MSG_UNKNOWN = "ERROR_未知错误,请联系管理员";
+	public static final String ERROR_MSG_NO_DATA = "ERROR_没有数据";
+	public static final String ERROR_MSG_UPLOAD_FAIL = "ERROR_上传OSS失败";
+
+	public String WriteExportExcel(ExportType exportType, List<?> data, Class head, HnqzUser user) {
+		// 临时文件路径
+		String tempPath = OsEnvUtils.getEachEnvPaths().get(OsEnvUtils.TargetFile.TEMP.getName());
+		// 缓存文件名
+		String fileName = exportType.getDescription() + DateTimeFormatter.ofPattern(DatePattern.PURE_DATE_PATTERN)
+				.format(LocalDateTime.now()) + RandomStringUtils.randomNumeric(6) + ".xlsx";
+		String fullPath = tempPath + fileName;
+
+		String ret = ERROR_MSG_UNKNOWN;
+		try {
+			// 写入excel文件
+			EasyExcel.write(fullPath, head).sheet(exportType.getDescription())
+					.doWrite(data);
+			log.info("{}导出生成缓存文件:{}", exportType.getDescription(), fullPath);
+
+			// 上传oss
+			try (FileInputStream inputStream = new FileInputStream(fullPath)) {
+				Map<String, String> uploadResult = fileService.upload(inputStream, fileName, fileName, user.getUsername());
+				log.info("{}导出生成oss文件:{}", exportType.getDescription(), uploadResult);
+
+				if (CollUtil.isNotEmpty(uploadResult)) {
+					ret = uploadResult.get("url");
+				} else {
+					ret = ERROR_MSG_UPLOAD_FAIL;
+				}
+			}
+		} catch (Exception e) {
+			log.error(exportType.getDescription() + "导出失败", e);
+			// 清理临时文件
+			cleanupTempFile(fullPath);
+			ret = ERROR_MSG_UNKNOWN;
+		}
+
+		// 缓存key
+		String key = ExportType.getAsyncExportCache(exportType, user.getId());
+		redisTemplate.opsForValue().set(key, ret, CommonConstants.DEF_REPORT_TTL, TimeUnit.MILLISECONDS);
+		return ret;
+	}
+
+  	/**
+	 * 清理临时文件
+	 */
+	private void cleanupTempFile(String fullPath) {
+		try {
+			File file = new File(fullPath);
+			if (file.exists()) {
+				file.delete();
+			}
+		} catch (Exception e) {
+			log.warn("删除临时文件失败: {}", fullPath, e);
+		}
+	}
+
+}

+ 35 - 0
hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/util/RedisUtils.java

@@ -2,6 +2,11 @@ package com.qunzhixinxi.hnqz.admin.util;
 
 import cn.hutool.core.collection.ListUtil;
 import cn.hutool.core.util.IdUtil;
+
+import com.qunzhixinxi.hnqz.admin.api.constant.CacheConstants;
+import com.qunzhixinxi.hnqz.admin.api.constant.enums.ExportType;
+import com.qunzhixinxi.hnqz.admin.api.entity.WmReportOpt;
+import com.qunzhixinxi.hnqz.common.core.constant.CommonConstants;
 import com.qunzhixinxi.hnqz.common.core.exception.BizException;
 import java.time.LocalDateTime;
 import java.util.Collections;
@@ -61,6 +66,36 @@ public final class RedisUtils {
     return new Token(token, value, LocalDateTime.now().plusSeconds(DEF_DURATION));
   }
 
+  public void checkExportGlobalAllows(int max) {
+    // 使用Redis原子操作实现限流
+			String key = CacheConstants.ASYNC_EXPORT_LIMIT_KEY;
+			Long increment = redisTemplate.opsForValue().increment(key);
+
+			// 设置key的过期时间,避免计数器无限增长
+			if (increment != null && increment.equals(1L)) {
+				redisTemplate.expire(key, 1, TimeUnit.MINUTES);
+			}
+
+			// 检查是否超过限流阈值
+			if (increment != null && increment > max) {
+				// 超过限流阈值时,减少计数器并抛出异常
+				redisTemplate.opsForValue().decrement(key);
+				throw new BizException("系统繁忙,请稍后再试");
+			}
+  }
+
+  public void setExportStarting(ExportType exportType, Integer userId) {
+      // 缓存key
+			String cacheKey = ExportType.getAsyncExportCache(exportType, userId);
+			// 更新状态为生成中
+			redisTemplate.opsForValue().set(cacheKey, WmReportOpt.WmReportOptStatus.GENERATING.name(), CommonConstants.DEF_REPORT_TTL, TimeUnit.MILLISECONDS);
+  }
+
+  public void releaseExportGlobalAllows() {
+      // 释放全局限流
+		  redisTemplate.opsForValue().decrement(CacheConstants.ASYNC_EXPORT_LIMIT_KEY);
+  }
+
   @Data
   @AllArgsConstructor
   public static class Token{

+ 665 - 0
hnqz-upms/hnqz-upms-biz/src/main/resources/mapper/WmTaskSupervisionMapper.xml

@@ -58,4 +58,669 @@
     </where>
   </select>
 
+  <resultMap id="wmTaskSupProcessMap" type="com.qunzhixinxi.hnqz.admin.api.model.excel.TaskCheckHistoryExcelModel">
+    <result property="taskId" column="id"/>
+    <result property="divisionName" column="division_name"/>
+    <result property="provAbbr" column="prov_abbr"/>
+    <result property="csoName" column="cso_name"/>
+    <result property="scorePackageName" column="score_package_name"/>
+    <result property="scorePackageId" column="score_package_id"/>
+    <result property="packageYear" column="package_year"/>
+    <result property="packageStartTime" column="package_start_time"/>
+    <result property="packageEndTime" column="package_end_time"/>
+    <result property="taskNumber" column="task_number"/>
+    <result property="taskTypeName" column="task_type_name"/>
+    <result property="taskScore" column="task_score"/>
+    <result property="drugnameTy" column="drugname_ty"/>
+    <result property="drugEntName" column="drug_ent_name"/>
+    <result property="workerRealname" column="worker_realname"/>
+    <result property="taskCreateTime" column="task_create_time"/>
+
+    <result property="vendorRealname" column="vendor_realname"/>
+    <result property="vendorUpdateTime" column="vendor_update_time"/>
+    <result property="vendorCheckResult" column="vendor_check_result"/>
+    <result property="vendorCheckMsg" column="vendor_check_msg"/>
+
+    <result property="cityRealname" column="city_realname"/>
+    <result property="cityUpdateTime" column="city_update_time"/>
+    <result property="cityCheckResult" column="city_check_result"/>
+    <result property="cityCheckMsg" column="city_check_msg"/>
+
+    <result property="divisionRealname" column="division_realname"/>
+    <result property="divisionUpdateTime" column="division_update_time"/>
+    <result property="divisionCheckResult" column="division_check_result"/>
+    <result property="divisionCheckMsg" column="division_check_msg"/>
+
+    <result property="marketingRealname" column="marketing_realname"/>
+    <result property="marketingUpdateTime" column="marketing_update_time"/>
+    <result property="marketingCheckResult" column="marketing_check_result"/>
+    <result property="marketingCheckMsg" column="marketing_check_msg"/>
+
+    <result property="bizRealname" column="biz_realname"/>
+    <result property="bizUpdateTime" column="biz_update_time"/>
+    <result property="bizCheckResult" column="biz_check_result"/>
+    <result property="bizCheckMsg" column="biz_check_msg"/>
+
+    <result property="submgrRealname" column="submgr_realname"/>
+    <result property="submgrUpdateTime" column="submgr_update_time"/>
+    <result property="submgrCheckResult" column="submgr_check_result"/>
+    <result property="submgrCheckMsg" column="submgr_check_msg"/>
+
+    <result property="mgrRealname" column="mgr_realname"/>
+    <result property="mgrUpdateTime" column="mgr_update_time"/>
+    <result property="mgrCheckResult" column="mgr_check_result"/>
+    <result property="mgrCheckMsg" column="mgr_check_msg"/>
+
+    <result property="factoryFinanceRealname" column="factory_finance_realname"/>
+    <result property="factoryFinanceCreateTime" column="factory_finance_create_time"/>
+    <result property="factoryFinanceSupRes" column="factory_finance_sup_res"/>
+    <result property="factoryFinanceRemarks" column="factory_finance_remarks"/>
+
+    <result property="factoryFinanceLeaderRealname" column="factory_finance_leader_realname"/>
+    <result property="factoryFinanceLeaderCreateTime" column="factory_finance_leader_create_time"/>
+    <result property="factoryFinanceLeaderAdviceResult" column="factory_finance_leader_advice_result"/>
+    <result property="factoryFinanceLeaderRemarks" column="factory_finance_leader_remarks"/>
+
+    <result property="factoryFinanceSubmgrRealname" column="factory_finance_submgr_realname"/>
+    <result property="factoryFinanceSubmgrCreateTime" column="factory_finance_submgr_create_time"/>
+    <result property="factoryFinanceSubmgrAdviceResult" column="factory_finance_submgr_advice_result"/>
+    <result property="factoryFinanceSubmgrRemarks" column="factory_finance_submgr_remarks"/>
+
+    <result property="factoryBizRealname" column="factory_biz_realname"/>
+    <result property="factoryBizCreateTime" column="factory_biz_create_time"/>
+    <result property="factoryBizSupRes" column="factory_biz_sup_res"/>
+    <result property="factoryBizRemarks" column="factory_biz_remarks"/>
+
+    <result property="factoryBizLeaderRealname" column="factory_biz_leader_realname"/>
+    <result property="factoryBizLeaderCreateTime" column="factory_biz_leader_create_time"/>
+    <result property="factoryBizLeaderAdviceResult" column="factory_biz_leader_advice_result"/>
+    <result property="factoryBizLeaderRemarks" column="factory_biz_leader_remarks"/>
+
+    <result property="factoryBizSubmgrRealname" column="factory_biz_submgr_realname"/>
+    <result property="factoryBizSubmgrCreateTime" column="factory_biz_submgr_create_time"/>
+    <result property="factoryBizSubmgrAdviceResult" column="factory_biz_submgr_advice_result"/>
+    <result property="factoryBizSubmgrRemarks" column="factory_biz_submgr_remarks"/>
+
+    <result property="lawyerRealname" column="lawyer_realname"/>
+    <result property="lawyerCreateTime" column="lawyer_create_time"/>
+    <result property="lawyerSupRes" column="lawyer_sup_res"/>
+    <result property="lawyerRemarks" column="lawyer_remarks"/>
+
+    <result property="lawyerLeaderRealname" column="lawyer_leader_realname"/>
+    <result property="lawyerLeaderCreateTime" column="lawyer_leader_create_time"/>
+    <result property="lawyerLeaderAdviceResult" column="lawyer_leader_advice_result"/>
+    <result property="lawyerLeaderRemarks" column="lawyer_leader_remarks"/>
+
+    <result property="lawyerSubmgrRealname" column="lawyer_submgr_realname"/>
+    <result property="lawyerSubmgrCreateTime" column="lawyer_submgr_create_time"/>
+    <result property="lawyerSubmgrAdviceResult" column="lawyer_submgr_advice_result"/>
+    <result property="lawyerSubmgrRemarks" column="lawyer_submgr_remarks"/>
+
+    <result property="financeRealname" column="finance_realname"/>
+    <result property="financeCreateTime" column="finance_create_time"/>
+    <result property="financeSupRes" column="finance_sup_res"/>
+    <result property="financeRemarks" column="finance_remarks"/>
+
+    <result property="financeLeaderRealname" column="finance_leader_realname"/>
+    <result property="financeLeaderCreateTime" column="finance_leader_create_time"/>
+    <result property="financeLeaderAdviceResult" column="finance_leader_advice_result"/>
+    <result property="financeLeaderRemarks" column="finance_leader_remarks"/>
+
+    <result property="financeSubmgrRealname" column="finance_submgr_realname"/>
+    <result property="financeSubmgrCreateTime" column="finance_submgr_create_time"/>
+    <result property="financeSubmgrAdviceResult" column="finance_submgr_advice_result"/>
+    <result property="financeSubmgrRemarks" column="finance_submgr_remarks"/>
+  </resultMap>
+
+<select id="selectTaskSupProcess" resultMap="wmTaskSupProcessMap">
+  select
+
+    t.id,
+
+    division.name division_name,
+
+    pp."prov_abbr",
+
+    cso.name cso_name,
+
+    pp.score_package_name,
+
+    pp.id score_package_id,
+
+    year(pp.start_time) package_year,
+
+    pp.start_time package_start_time,
+
+    pp.end_time package_end_time,
+
+    t."task_number",
+
+    ttype.task_type_name,
+
+    t.score task_score,
+
+    drug.drugname_ty,
+
+    drug.drug_ent_name,
+
+    task_user.realname worker_realname,
+
+    t.create_time task_create_time,
+
+    t1.realname vendor_realname,
+
+    t1.update_time vendor_update_time,
+
+    t1.check_result vendor_check_result,
+
+    t1.check_msg vendor_check_msg,
+
+    t2.realname city_realname,
+
+    t2.update_time city_update_time,
+
+    t2.check_result city_check_result,
+
+    t2.check_msg city_check_msg,
+
+    t3.realname division_realname,
+
+    t3.update_time division_update_time,
+
+    t3.check_result division_check_result,
+
+    t3.check_msg division_check_msg,
+
+    t8.realname marketing_realname,
+
+    t8.update_time marketing_update_time,
+
+    t8.check_result marketing_check_result,
+
+    t8.check_msg marketing_check_msg,
+
+    t9.realname biz_realname,
+
+    t9.update_time biz_update_time,
+
+    t9.check_result biz_check_result,
+
+    t9.check_msg biz_check_msg,
+
+    t5.realname submgr_realname,
+
+    t5.update_time submgr_update_time,
+
+    t5.check_result submgr_check_result,
+
+    t5.check_msg submgr_check_msg,
+
+    t6.realname mgr_realname,
+
+    t6.update_time mgr_update_time,
+
+    t6.check_result mgr_check_result,
+
+    t6.check_msg mgr_check_msg,
+
+    sup1."realname" factory_finance_realname,
+
+    sup1."create_time" factory_finance_create_time,
+
+    sup1."sup_res" factory_finance_sup_res,
+
+    sup1.remarks factory_finance_remarks,
+
+    sup11."realname" factory_finance_leader_realname,
+
+    sup11."create_time" factory_finance_leader_create_time,
+
+    sup11."advice_result" factory_finance_leader_advice_result,
+
+    sup11.remarks factory_finance_leader_remarks,
+
+    sup12."realname" factory_finance_submgr_realname,
+
+    sup12."create_time" factory_finance_submgr_create_time,
+
+    sup12."advice_result" factory_finance_submgr_advice_result,
+
+    sup12.remarks factory_finance_submgr_remarks,
+
+    sup2."realname" factory_biz_realname,
+
+    sup2."create_time" factory_biz_create_time,
+
+    sup2."sup_res" factory_biz_sup_res,
+
+    sup2.remarks factory_biz_remarks,
+
+    sup21."realname" factory_biz_leader_realname,
+
+    sup21."create_time" factory_biz_leader_create_time,
+
+    sup21."advice_result" factory_biz_leader_advice_result,
+
+    sup21.remarks factory_biz_leader_remarks,
+
+    sup22."realname" factory_biz_submgr_realname,
+
+    sup22."create_time" factory_biz_submgr_create_time,
+
+    sup22."advice_result" factory_biz_submgr_advice_result,
+
+    sup22.remarks factory_biz_submgr_remarks,
+
+    sup3."realname" lawyer_realname,
+
+    sup3."create_time" lawyer_create_time,
+
+    sup3."sup_res" lawyer_sup_res,
+
+    sup3.remarks lawyer_remarks,
+
+    sup31."realname" lawyer_leader_realname,
+
+    sup31."create_time" lawyer_leader_create_time,
+
+    sup31."advice_result" lawyer_leader_advice_result,
+
+    sup31.remarks lawyer_leader_remarks,
+
+    sup32."realname" lawyer_submgr_realname,
+
+    sup32."create_time" lawyer_submgr_create_time,
+
+    sup32."advice_result" lawyer_submgr_advice_result,
+
+    sup32.remarks lawyer_submgr_remarks,
+
+    sup4."realname" finance_realname,
+
+    sup4."create_time" finance_create_time,
+
+    sup4."sup_res" finance_sup_res,
+
+    sup4.remarks finance_remarks,
+
+    sup41."realname" finance_leader_realname,
+
+    sup41."create_time" finance_leader_create_time,
+
+    sup41."advice_result" finance_leader_advice_result,
+
+    sup41.remarks finance_leader_remarks,
+
+    sup42."realname" finance_submgr_realname,
+
+    sup42."create_time" finance_submgr_create_time,
+
+    sup42."advice_result" finance_submgr_advice_result,
+
+    sup42.remarks finance_submgr_remarks
+
+  from wm_task t
+
+  join wm_task_type ttype
+
+  on t.task_type_id = ttype.id
+
+  join "wm_score_package" p
+
+  on t."score_package_id" = p."id"
+
+  left join "wm_score_package" pp
+
+  on p.relation_score_id = pp.id
+
+  left join sys_dept cso
+
+  on p.dept_id = cso.dept_id
+
+  left join sys_dept division
+
+  on pp.send_package_dept_id = division.dept_id
+
+  left join sys_user task_user
+
+  on t.task_user_id = task_user.user_id
+
+  left join wm_da_drug_ent_drugtable drug
+
+  on p.drugtable = drug.id  
+
+  left join
+
+  (
+
+    select "target_id", "check_result", "check_msg", his."update_time1" update_time, u."realname"
+
+    from "sys_chain_node_check_his" his
+
+    join (select distinct username, realname from sys_user) u
+
+    on u."username" = his."create_by1"
+
+    where "node_id" = 1 and create_time1 &gt;= #{taskBeginTime} <!-- 服务商 -->
+
+  ) t1
+
+  on t1.target_id = t.id
+
+  left join
+
+  (
+
+    select "target_id", "check_result", "check_msg", his."update_time1" update_time, u."realname"
+
+    from "sys_chain_node_check_his" his
+
+    join (select distinct username, realname from sys_user) u
+
+    on u."username" = his."create_by1"
+
+    where "node_id" = 2 and create_time1 &gt;= #{taskBeginTime} <!-- 地市 -->
+
+  ) t2
+
+  on t2.target_id = t.id
+
+  left join
+
+  (
+
+    select "target_id", "check_result", "check_msg", his."update_time1" update_time, u."realname"
+
+    from "sys_chain_node_check_his" his join (select distinct username, realname from sys_user) u
+
+    on u."username" = his."create_by1"
+
+    where "node_id" = 3 and create_time1 &gt;= #{taskBeginTime} <!-- 区域 -->
+
+  ) t3
+
+  on t3.target_id = t.id
+
+  left join
+
+  (
+
+    select "target_id", "check_result", "check_msg", his."update_time1" update_time, u."realname"
+
+    from "sys_chain_node_check_his" his join (select distinct username, realname from sys_user) u
+
+    on u."username" = his."create_by1"
+
+    where "node_id" = 8 and create_time1 &gt;= #{taskBeginTime} <!-- 市场 -->
+
+  ) t8
+
+    on t8.target_id = t.id
+
+    left join
+
+    (
+
+    select "target_id", "check_result", "check_msg", his."update_time1" update_time, u."realname"
+
+    from "sys_chain_node_check_his" his join (select distinct username, realname from sys_user) u
+
+    on u."username" = his."create_by1"
+
+    where "node_id" = 9 and create_time1 &gt;= #{taskBeginTime} <!-- 商务 -->
+
+    ) t9
+
+    on t9.target_id = t.id
+
+    left join
+
+    (
+
+    select "target_id", "check_result", "check_msg", his."update_time1" update_time, u."realname"
+
+    from "sys_chain_node_check_his" his join (select distinct username, realname from sys_user) u
+
+    on u."username" = his."create_by1"
+
+    where "node_id" = 5 and create_time1 &gt;= #{taskBeginTime} <!-- 分管领导 -->
+
+    ) t5
+
+    on t5.target_id = t.id
+
+    left join
+
+    (
+
+    select distinct "target_id", "check_result", "check_msg", his."update_time1" update_time, u."realname"
+
+    from "sys_chain_node_check_his" his join (select distinct username, realname from sys_user) u
+
+    on u."username" = his."create_by1"
+
+    where "node_id" = 6 and create_time1 &gt;= #{taskBeginTime} <!-- 总经理 -->
+
+    ) t6
+
+    on t6.target_id = t.id
+
+    left join
+
+    (
+
+    select sup."task_id", u.realname, sup.create_time, sup.sup_res, sup."remarks" from wm_task_sup sup 
+
+    join wm_task_sup_adv adv on adv.task_supervision_id = sup.sup_id
+
+    join sys_user u on u."username" = sup."create_by"
+
+    join "sys_user_role" ur on u.user_id = ur."user_id"
+
+    where ur."role_id" = 49 and sup."create_time" &gt;= #{taskBeginTime}  <!-- 厂家财务 -->
+
+    ) sup1
+
+    on sup1."task_id" = t.id
+
+    left join
+
+    (
+
+    select sup."task_id", u.realname, adv.create_time, adv.advice_result, adv.remarks  from wm_task_sup sup 
+
+    join wm_task_sup_adv adv on adv.task_supervision_id = sup.sup_id
+
+    join sys_user u on u."username" = adv."create_by"
+
+    join "sys_user_role" ur on u.user_id = ur."user_id"
+
+    where ur."role_id" = 57 and sup."create_time" &gt;= #{taskBeginTime} and adv.del_flag = '0'   <!-- 厂家财务负责人 -->
+
+    ) sup11
+
+    on sup11."task_id" = t.id
+
+    left join
+
+    (
+
+    select sup."task_id", u.realname, adv.create_time, adv.advice_result, adv.remarks  from wm_task_sup sup 
+
+    join wm_task_sup_adv adv on adv.task_supervision_id = sup.sup_id
+
+    join sys_user u on u."username" = adv."create_by"
+
+    join "sys_user_role" ur on u.user_id = ur."user_id"
+
+    where ur."role_id" = 51 and sup."create_time" &gt;= #{taskBeginTime} and adv.del_flag = '0'  <!-- 厂家财务分管领导 -->
+
+    ) sup12
+
+    on sup12."task_id" = t.id
+
+    left join
+
+    (
+
+    select sup."task_id", u.realname, sup.create_time, sup.sup_res, sup."remarks" from wm_task_sup sup 
+
+    join sys_user u on u."username" = sup."create_by"
+
+    join "sys_user_role" ur on u.user_id = ur."user_id"
+
+    where ur."role_id" = 52 and sup."create_time" &gt;= #{taskBeginTime}  <!-- 厂家销售 -->
+
+    ) sup2
+
+    on sup2."task_id" = t.id
+
+    left join
+
+    (
+
+    select sup."task_id", u.realname, adv.create_time, adv.advice_result, adv.remarks  from wm_task_sup sup 
+
+    join wm_task_sup_adv adv on adv.task_supervision_id = sup.sup_id
+
+    join sys_user u on u."username" = adv."create_by"
+
+    join "sys_user_role" ur on u.user_id = ur."user_id"
+
+    where ur."role_id" = 58 and sup."create_time" &gt;= #{taskBeginTime} and adv.del_flag = '0'  <!-- 厂家销售负责人 -->
+
+    ) sup21
+
+    on sup21."task_id" = t.id
+
+    left join
+
+    (
+
+    select sup."task_id", u.realname, adv.create_time, adv.advice_result, adv.remarks  from wm_task_sup sup 
+
+    join wm_task_sup_adv adv on adv.task_supervision_id = sup.sup_id
+
+    join sys_user u on u."username" = adv."create_by"
+
+    join "sys_user_role" ur on u.user_id = ur."user_id"
+
+    where ur."role_id" = 61 and sup."create_time" &gt;= #{taskBeginTime} and adv.del_flag = '0'  <!-- 厂家销售分管领导 -->
+
+    ) sup22
+
+    on sup22."task_id" = t.id
+
+    left join
+
+    (
+
+    select sup."task_id", u.realname, sup.create_time, sup.sup_res, sup."remarks" from wm_task_sup sup 
+
+    join sys_user u on u."username" = sup."create_by"
+
+    join "sys_user_role" ur on u.user_id = ur."user_id"
+
+    where ur."role_id" = 53 and sup."create_time" &gt;= #{taskBeginTime}  <!-- 营销合规 -->
+
+    ) sup3
+
+    on sup3."task_id" = t.id
+
+    left join
+
+    (
+
+    select sup."task_id", u.realname, adv.create_time, adv.advice_result, adv.remarks  from wm_task_sup sup 
+
+    join wm_task_sup_adv adv on adv.task_supervision_id = sup.sup_id
+
+    join sys_user u on u."username" = adv."create_by"
+
+    join "sys_user_role" ur on u.user_id = ur."user_id"
+
+    where ur."role_id" = 60 and sup."create_time" &gt;= #{taskBeginTime} and adv.del_flag = '0'  <!-- 营销合规负责人 -->
+
+    ) sup31
+
+    on sup31."task_id" = t.id
+
+    left join
+
+    (
+
+    select sup."task_id", u.realname, adv.create_time, adv.advice_result, adv.remarks  from wm_task_sup sup 
+
+    join wm_task_sup_adv adv on adv.task_supervision_id = sup.sup_id
+
+    join sys_user u on u."username" = adv."create_by"
+
+    join "sys_user_role" ur on u.user_id = ur."user_id"
+
+    where ur."role_id" = 54 and sup."create_time" &gt;= #{taskBeginTime} and adv.del_flag = '0'  <!-- 营销合规分管领导 -->
+
+    ) sup32
+
+    on sup32."task_id" = t.id
+
+    left join
+
+    (
+
+    select sup."task_id", u.realname, sup.create_time, sup.sup_res, sup."remarks" from wm_task_sup sup 
+
+    join sys_user u on u."username" = sup."create_by"
+
+    join "sys_user_role" ur on u.user_id = ur."user_id"
+
+    where ur."role_id" = 56 and sup."create_time" &gt;= #{taskBeginTime}  <!-- 营销财务 -->
+
+    ) sup4
+
+    on sup4."task_id" = t.id
+
+    left join
+
+    (
+
+    select sup."task_id", u.realname, adv.create_time, adv.advice_result, adv.remarks  from wm_task_sup sup 
+
+    join wm_task_sup_adv adv on adv.task_supervision_id = sup.sup_id
+
+    join sys_user u on u."username" = adv."create_by"
+
+    join "sys_user_role" ur on u.user_id = ur."user_id"
+
+    where ur."role_id" = 59 and sup."create_time" &gt;= #{taskBeginTime} and adv.del_flag = '0'  <!-- 营销财务负责人 -->
+
+    ) sup41
+
+    on sup41."task_id" = t.id
+
+    left join
+
+    (
+
+    select sup."task_id", u.realname, adv.create_time, adv.advice_result, adv.remarks  from wm_task_sup sup 
+
+    join wm_task_sup_adv adv on adv.task_supervision_id = sup.sup_id
+
+    join sys_user u on u."username" = adv."create_by"
+
+    join "sys_user_role" ur on u.user_id = ur."user_id"
+
+    where ur."role_id" = 55 and sup."create_time" &gt;= #{taskBeginTime} and adv.del_flag = '0'  <!-- 营销财务分管领导 -->
+
+    ) sup42
+
+    on sup42."task_id" = t.id
+
+
+    where t.create_time &gt;= #{taskBeginTime} and t.create_time &lt;= #{taskEndTime} and t.del_flag = '0'
+      and cso.dept_id &gt; 0 <!-- remove test data -->
+
+ </select>
+
+
+
 </mapper>