Browse Source

feat: 个人执行包数据导出接口

lixuesong 4 days ago
parent
commit
28f10f8a18

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

@@ -15,7 +15,8 @@ import lombok.Getter;
 @AllArgsConstructor
 public enum ExportType {
 
-	USER("USER", "人员信息");
+	USER("USER", "人员信息"),
+	SCORE_PACKAGE_SUB("SCORE_PACKAGE_SUB", "个人执行包数据");
 
 	/**
 	 * 类型

+ 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;
+  }
+
 }

+ 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;
+
+}

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

@@ -0,0 +1,73 @@
+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(),  1, 1);  // first day of Year
+		}
+
+		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));
+	}
+}

+ 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;
+}

+ 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());
+	}
+}

+ 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,

+ 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);
+}

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

@@ -0,0 +1,929 @@
+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.alibaba.excel.EasyExcel;
+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.WmReportOpt;
+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.config.UpmsConfig;
+import com.qunzhixinxi.hnqz.admin.event.PackageExportEvent;
+import com.qunzhixinxi.hnqz.admin.manager.WmPackageExportScope;
+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.SysFileService;
+import com.qunzhixinxi.hnqz.admin.service.WmPackageTaskTypeQtyService;
+import com.qunzhixinxi.hnqz.admin.service.WmScorePackageExportService;
+import com.qunzhixinxi.hnqz.admin.util.OsEnvUtils;
+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.apache.commons.lang3.RandomStringUtils;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.retry.support.RetryTemplate;
+import org.springframework.stereotype.Service;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+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.concurrent.TimeUnit;
+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 SysFileService fileService;
+	private final WmPackageTaskTypeQtyService packageTaskTypeQtyService;
+	private final RedisTemplate<String, Object> redisTemplate;
+	private final RetryTemplate retryTemplate;
+	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失败";
+
+
+	/**
+	 * 异步导出
+	 *
+	 * @param user      用户
+	 * @param roles     角色
+	 * @param startDate 开始日期
+	 * @param endDate   结束日期
+	 * @return {@link Boolean } 是否成功
+	 */
+	@Override
+	public Boolean asyncExport(HnqzUser user, List<Integer> roles, LocalDate startDate, LocalDate endDate) {
+		return retryTemplate.execute(retryContext -> {
+			log.info("个人执行包数据异步导出第{}次重试", retryContext.getRetryCount());
+
+			// 使用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 > upmsConfig.getAsyncExportLimit()) {
+				// 超过限流阈值时,减少计数器并抛出异常
+				redisTemplate.opsForValue().decrement(key);
+				throw new BizException("系统繁忙,请稍后再试");
+			}
+
+			// 缓存key
+			String cacheKey = String.format(CacheConstants.ASYNC_EXPORT_CACHE, ExportType.SCORE_PACKAGE_SUB.getType(), user.getId());
+			// 更新状态为生成中
+			redisTemplate.opsForValue().set(cacheKey, WmReportOpt.WmReportOptStatus.GENERATING.name(), DEF_REPORT_TTL, TimeUnit.MILLISECONDS);
+
+			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) {
+		// 缓存key
+		String key = String.format(CacheConstants.ASYNC_EXPORT_CACHE, ExportType.SCORE_PACKAGE_SUB.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;
+
+		String resultValue = ERROR_MSG_UNKNOWN;
+
+		try {
+			// 获取数据
+			List<WmScorePackageSubInfoExcelModel> packageSubModels = this.getExportData(user, roles, startDate, endDate);
+			if (CollUtil.isEmpty(packageSubModels)) {
+				log.info("个人执行包数据为空");
+				redisTemplate.opsForValue().set(key, ERROR_MSG_NO_DATA, DEF_REPORT_TTL, TimeUnit.MILLISECONDS);
+				return Boolean.FALSE;
+			}
+
+			// 写入excel文件
+			EasyExcel.write(fullPath, SysUserExcelModel.class).sheet("个人执行包数据")
+					.doWrite(packageSubModels);
+			log.info("个人执行包数据导出生成缓存文件:{}", fullPath);
+
+			// 上传oss
+			FileInputStream inputStream = new FileInputStream(fullPath);
+			Map<String, String> uploadResult = fileService.upload(inputStream, fileName, fileName, user.getUsername());
+			log.info("个人执行包数据导出生成oss文件:{}", uploadResult);
+
+			if (CollUtil.isNotEmpty(uploadResult)) {
+				resultValue = uploadResult.get("url");
+			} else {
+				resultValue = ERROR_MSG_UPLOAD_FAIL;
+			}
+
+			redisTemplate.opsForValue().set(key, resultValue, DEF_REPORT_TTL, TimeUnit.MILLISECONDS);
+		} catch (Exception e) {
+			log.error("个人执行包数据失败", e);
+		} finally {
+			// 清理临时文件
+			cleanupTempFile(fullPath);
+
+			// 删除限流key
+			String limitKey = CacheConstants.ASYNC_EXPORT_LIMIT_KEY;
+			redisTemplate.delete(limitKey);
+		}
+
+		return !StrUtil.startWith(resultValue, "ERROR");
+	}
+
+	/**
+	 * 清理临时文件
+	 */
+	private void cleanupTempFile(String fullPath) {
+		try {
+			File file = new File(fullPath);
+			if (file.exists()) {
+				file.delete();
+			}
+		} catch (Exception e) {
+			log.warn("删除临时文件失败: {}", fullPath, e);
+		}
+	}
+
+	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);
+	}
+}