فهرست منبع

pms 专业公司计划工作量 汇总统计

zhangcl 1 هفته پیش
والد
کامیت
d61671b1df
10فایلهای تغییر یافته به همراه769 افزوده شده و 12 حذف شده
  1. 17 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotprojecttaskplan/IotProjectTaskPlanController.java
  2. 9 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotprojecttaskplan/vo/IotProjectTaskPlanRespVO.java
  3. 8 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotprojecttaskplan/vo/IotProjectTaskPlanSaveReqVO.java
  4. 76 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotprojecttaskplan/vo/IotProjectTaskPlanStatisticsItemRespVO.java
  5. 95 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotprojecttaskplan/vo/IotProjectTaskPlanStatisticsRespVO.java
  6. 12 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/dataobject/iotprojecttaskplan/IotProjectTaskPlanDO.java
  7. 4 2
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/iotprojecttaskplan/IotProjectTaskPlanMapper.java
  8. 7 8
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotfivedailyreport/IotFiveDailyReportServiceImpl.java
  9. 9 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotprojecttaskplan/IotProjectTaskPlanService.java
  10. 532 2
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotprojecttaskplan/IotProjectTaskPlanServiceImpl.java

+ 17 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotprojecttaskplan/IotProjectTaskPlanController.java

@@ -9,6 +9,7 @@ import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
 import cn.iocoder.yudao.module.pms.controller.admin.iotprojecttaskplan.vo.IotProjectTaskPlanPageReqVO;
 import cn.iocoder.yudao.module.pms.controller.admin.iotprojecttaskplan.vo.IotProjectTaskPlanRespVO;
 import cn.iocoder.yudao.module.pms.controller.admin.iotprojecttaskplan.vo.IotProjectTaskPlanSaveReqVO;
+import cn.iocoder.yudao.module.pms.controller.admin.iotprojecttaskplan.vo.IotProjectTaskPlanStatisticsRespVO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotprojecttaskattrs.IotTaskAttrModelProperty;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotprojecttaskplan.IotProjectTaskPlanDO;
 import cn.iocoder.yudao.module.pms.service.iotprojecttaskplan.IotProjectTaskPlanService;
@@ -23,7 +24,10 @@ import javax.annotation.Resource;
 import javax.servlet.http.HttpServletResponse;
 import javax.validation.Valid;
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@@ -86,6 +90,19 @@ public class IotProjectTaskPlanController {
         return success(taskPlanExtProperties);
     }
 
+    @GetMapping("/summaryStatistics")
+    @Operation(summary = "专业公司工作量计划 汇总 统计")
+    @PreAuthorize("@ss.hasPermission('pms:iot-rd-daily-report:query')")
+    public CommonResult<Map<String, Object>> summaryStatistics(@Valid IotProjectTaskPlanPageReqVO pageReqVO) {
+        List<IotProjectTaskPlanStatisticsRespVO> result = new ArrayList<>();
+        Map<String, Object> resultMap = new HashMap<>();
+        List<IotProjectTaskPlanStatisticsRespVO> statistics = iotProjectTaskPlanService.summaryStatistics(pageReqVO);
+        result.addAll(statistics);
+        resultMap.put("list", result);
+        resultMap.put("total", result.size());
+        return success(resultMap);
+    }
+
     @GetMapping("/export-excel")
     @Operation(summary = "导出日报任务计划(工作量) Excel")
     @PreAuthorize("@ss.hasPermission('pms:iot-project-task-plan:export')")

+ 9 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotprojecttaskplan/vo/IotProjectTaskPlanRespVO.java

@@ -77,6 +77,15 @@ public class IotProjectTaskPlanRespVO {
     @ExcelProperty("备注")
     private String remark;
 
+    @Schema(description = "流程实例id", example = "16415")
+    private String processInstanceId;
+
+    @Schema(description = "审批状态 0未提交、10审批中、20审批通过、30审批不通过、已取消", example = "1")
+    private Integer auditStatus;
+
+    @Schema(description = "审批意见", example = "审核通过")
+    private String opinion;
+
     @Schema(description = "创建时间")
     @ExcelProperty("创建时间")
     private LocalDateTime createTime;

+ 8 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotprojecttaskplan/vo/IotProjectTaskPlanSaveReqVO.java

@@ -58,4 +58,12 @@ public class IotProjectTaskPlanSaveReqVO {
     @Schema(description = "备注", example = "你说的对")
     private String remark;
 
+    @Schema(description = "流程实例id", example = "16415")
+    private String processInstanceId;
+
+    @Schema(description = "审批状态 未提交0、审批中10、审批通过20、审批不通过30、已取消40", example = "1")
+    private Integer auditStatus;
+
+    @Schema(description = "审批意见", example = "审核通过")
+    private String opinion;
 }

+ 76 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotprojecttaskplan/vo/IotProjectTaskPlanStatisticsItemRespVO.java

@@ -0,0 +1,76 @@
+package cn.iocoder.yudao.module.pms.controller.admin.iotprojecttaskplan.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - 项目任务 工作量统计 月度明细 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class IotProjectTaskPlanStatisticsItemRespVO {
+
+    @Schema(description = "年-月份", example = "2025-01")
+    private String yearMonth;
+
+    @Schema(description = "年份", example = "2025")
+    private String year;
+
+    @Schema(description = "月份", example = "02")
+    private String month;
+
+    @Schema(description = "队伍id", example = "125")
+    private Long teamId;
+
+    @Schema(description = "队伍名称", example = "HY-A1")
+    @ExcelProperty("队伍名称")
+    private String teamName;
+
+    @Schema(description = "部门类型(公司级1 项目部2 队伍3)", example = "1")
+    private String type;
+
+    @Schema(description = "任务id", example = "15678")
+    private Long taskId;
+
+    @Schema(description = "项目业务类型 (注气/钻井/修井/压裂/连油/井下)")
+    @ExcelProperty("项目业务类型")
+    private BigDecimal business;
+
+    @Schema(description = "总工作量")
+    @ExcelProperty("总工作量")
+    private BigDecimal workloadDesign;
+
+    @Schema(description = "已完成工作量")
+    private BigDecimal finishedWorkload;
+
+    @Schema(description = "任务创建时间")
+    private LocalDateTime createTime;
+
+    @Schema(description = "排序", example = "1")
+    private Integer sort;
+
+    // 汇总统计 工作量
+    @Schema(description = "累计注气量(万方)")
+    @ExcelProperty("累计注气量(万方)")
+    private BigDecimal cumulativeGasInjection;
+
+    @Schema(description = "累计进尺(米)")
+    @ExcelProperty("累计进尺(米)")
+    private BigDecimal cumulativeFootage;
+
+    @Schema(description = "累计井次(井) 修井 连油")
+    @ExcelProperty("累计井次(井)")
+    private BigDecimal cumulativeWellCount;
+
+    @Schema(description = "累计压裂(层) 瑞都压裂 5#项目压裂")
+    @ExcelProperty("累计压裂(层)")
+    private BigDecimal cumulativeFracLayer;
+
+    @Schema(description = "工作量单位")
+    @ExcelProperty("工作量单位")
+    private String workloadUnit;
+
+}

+ 95 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotprojecttaskplan/vo/IotProjectTaskPlanStatisticsRespVO.java

@@ -0,0 +1,95 @@
+package cn.iocoder.yudao.module.pms.controller.admin.iotprojecttaskplan.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.util.List;
+
+@Schema(description = "管理后台 - 项目任务 工作量统计 统计 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class IotProjectTaskPlanStatisticsRespVO {
+
+    @Schema(description = "主键id", requiredMode = Schema.RequiredMode.REQUIRED, example = "13853")
+    private Long id;
+
+    @Schema(description = "公司id", example = "157")
+    private Long companyId;
+
+    @Schema(description = "公司名称", example = "瑞恒兴域")
+    @ExcelProperty("公司名称")
+    private String companyName;
+
+    @Schema(description = "项目部id", example = "125")
+    private Long deptId;
+
+    @Schema(description = "项目部id", example = "125")
+    private Long projectDeptId;
+
+    @Schema(description = "项目部名称", example = "西南压裂项目部")
+    @ExcelProperty("项目部名称")
+    private String projectDeptName;
+
+    @Schema(description = "队伍名称", example = "压裂二队")
+    @ExcelProperty("队伍名称")
+    private String deptName;
+
+    @Schema(description = "队伍id", example = "125")
+    private Long teamId;
+
+    @Schema(description = "队伍名称", example = "HY-A1")
+    @ExcelProperty("队伍名称")
+    private String teamName;
+
+    @Schema(description = "部门类型(公司级1 项目部2 队伍3)", example = "1")
+    private String type;
+
+    @Schema(description = "任务id", example = "15678")
+    private Long taskId;
+
+    @Schema(description = "项目业务类型 (注气/钻井/修井/压裂/连油/井下)")
+    @ExcelProperty("项目业务类型")
+    private String business;
+
+    @Schema(description = "总工作量")
+    @ExcelProperty("总工作量")
+    private BigDecimal workloadDesign;
+
+    @Schema(description = "已完成工作量")
+    private BigDecimal finishedWorkload;
+
+    @Schema(description = "任务创建时间")
+    private LocalDateTime createTime;
+
+    @Schema(description = "排序", example = "1")
+    private Integer sort;
+
+    // 汇总统计 工作量
+    @Schema(description = "累计注气量(万方)")
+    @ExcelProperty("累计注气量(万方)")
+    private BigDecimal cumulativeGasInjection;
+
+    @Schema(description = "累计进尺(米)")
+    @ExcelProperty("累计进尺(米)")
+    private BigDecimal cumulativeFootage;
+
+    @Schema(description = "累计井次(井) 修井 连油")
+    @ExcelProperty("累计井次(井)")
+    private BigDecimal cumulativeWellCount;
+
+    @Schema(description = "累计压裂(层) 瑞都压裂 5#项目压裂")
+    @ExcelProperty("累计压裂(层)")
+    private BigDecimal cumulativeFracLayer;
+
+    @Schema(description = "工作量单位")
+    @ExcelProperty("工作量单位")
+    private String workloadUnit;
+
+    @Schema(description = "月度 工作量汇总 明细")
+    private List<IotProjectTaskPlanStatisticsItemRespVO> items;
+
+}

+ 12 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/dataobject/iotprojecttaskplan/IotProjectTaskPlanDO.java

@@ -89,5 +89,17 @@ public class IotProjectTaskPlanDO extends BaseDO {
      * 备注
      */
     private String remark;
+    /**
+     * 流程实例id
+     */
+    private String processInstanceId;
+    /**
+     * 审批状态 0未提交、10审批中、20审批通过、30审批不通过、已取消
+     */
+    private Integer auditStatus;
+    /**
+     * 审核意见
+     */
+    private String opinion;
 
 }

+ 4 - 2
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/iotprojecttaskplan/IotProjectTaskPlanMapper.java

@@ -20,7 +20,8 @@ public interface IotProjectTaskPlanMapper extends BaseMapperX<IotProjectTaskPlan
 
     default PageResult<IotProjectTaskPlanDO> selectPage(IotProjectTaskPlanPageReqVO reqVO) {
         return selectPage(reqVO, new LambdaQueryWrapperX<IotProjectTaskPlanDO>()
-                .eqIfPresent(IotProjectTaskPlanDO::getDeptId, reqVO.getDeptId())
+                // .eqIfPresent(IotProjectTaskPlanDO::getDeptId, reqVO.getDeptId())
+                .inIfPresent(IotProjectTaskPlanDO::getDeptId, reqVO.getDeptIds())
                 .eqIfPresent(IotProjectTaskPlanDO::getCompanyId, reqVO.getCompanyId())
                 .eqIfPresent(IotProjectTaskPlanDO::getProjectId, reqVO.getProjectId())
                 .eqIfPresent(IotProjectTaskPlanDO::getTaskId, reqVO.getTaskId())
@@ -67,7 +68,7 @@ public interface IotProjectTaskPlanMapper extends BaseMapperX<IotProjectTaskPlan
      * @param excludeId 需要排除的记录ID(更新时传入自身ID,新增时传 null)
      * @return 匹配到的第一条记录,若无则返回 null
      */
-    default IotProjectTaskPlanDO selectOneByDeptIdAndMonth(Long deptId, LocalDateTime startTime, Long excludeId) {
+    default IotProjectTaskPlanDO selectOneByDeptIdAndMonth(Long deptId, LocalDateTime startTime, String business, Long excludeId) {
         if (deptId == null || startTime == null) {
             return null;
         }
@@ -79,6 +80,7 @@ public interface IotProjectTaskPlanMapper extends BaseMapperX<IotProjectTaskPlan
         // 显式声明为 LambdaQueryWrapperX 类型,避免类型推断问题
         LambdaQueryWrapperX<IotProjectTaskPlanDO> wrapper = new LambdaQueryWrapperX<>();
         wrapper.eq(IotProjectTaskPlanDO::getDeptId, deptId)
+                .eq(IotProjectTaskPlanDO::getBusiness, business)
                 .between(IotProjectTaskPlanDO::getStartTime, startOfMonth, endOfMonth);
 
         // 排除指定ID(若不为null)

+ 7 - 8
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotfivedailyreport/IotFiveDailyReportServiceImpl.java

@@ -206,6 +206,7 @@ public class IotFiveDailyReportServiceImpl implements IotFiveDailyReportService
         if (StrUtil.isNotBlank(pageReqVO.getWellName()) && (CollUtil.isEmpty(pageReqVO.getTaskIds()))) {
             return new ArrayList<>();
         }
+        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
         PageResult<IotFiveDailyReportDO> pageReports = iotFiveDailyReportMapper.selectPage(pageReqVO);
         List<IotFiveDailyReportDO> dailyReports = pageReports.getList();
 
@@ -360,7 +361,7 @@ public class IotFiveDailyReportServiceImpl implements IotFiveDailyReportService
                         // 累计主压层数(层)
                         if (cumulativeWorkingLayersPair.containsKey(projectDeptId)) {
                             BigDecimal existTotalLayers = cumulativeWorkingLayersPair.get(projectDeptId);
-                            BigDecimal tempTotalLayers = existTotalLayers.add(dailyFuel);
+                            BigDecimal tempTotalLayers = existTotalLayers.add(dailyLayers);
                             cumulativeWorkingLayersPair.put(projectDeptId, tempTotalLayers);
                         } else {
                             cumulativeWorkingLayersPair.put(projectDeptId, dailyLayers);
@@ -368,7 +369,7 @@ public class IotFiveDailyReportServiceImpl implements IotFiveDailyReportService
                         // 累计加砂
                         if (cumulativeMixSandPair.containsKey(projectDeptId)) {
                             BigDecimal existTotalSand = cumulativeMixSandPair.get(projectDeptId);
-                            BigDecimal tempTotalSand = existTotalSand.add(dailyFuel);
+                            BigDecimal tempTotalSand = existTotalSand.add(dailySand);
                             cumulativeMixSandPair.put(projectDeptId, tempTotalSand);
                         } else {
                             cumulativeMixSandPair.put(projectDeptId, dailySand);
@@ -376,7 +377,7 @@ public class IotFiveDailyReportServiceImpl implements IotFiveDailyReportService
                         // 累计注液
                         if (cumulativeLiquidPair.containsKey(projectDeptId)) {
                             BigDecimal existTotalLiquid = cumulativeLiquidPair.get(projectDeptId);
-                            BigDecimal tempTotalLiquid = existTotalLiquid.add(dailyFuel);
+                            BigDecimal tempTotalLiquid = existTotalLiquid.add(dailyLiquid);
                             cumulativeLiquidPair.put(projectDeptId, tempTotalLiquid);
                         } else {
                             cumulativeLiquidPair.put(projectDeptId, dailyLiquid);
@@ -429,8 +430,6 @@ public class IotFiveDailyReportServiceImpl implements IotFiveDailyReportService
                 statistics.setTotalDailyFuel(FuelWan);
             }
 
-            statistics.setCumulativeBridgePlug(cumulativeBridgePlugPair.get(deptId));
-
             result.add(statistics);
         });
         return result;
@@ -538,7 +537,7 @@ public class IotFiveDailyReportServiceImpl implements IotFiveDailyReportService
                         // 累计主压层数(层)
                         if (cumulativeWorkingLayersPair.containsKey(detailDeptId)) {
                             BigDecimal existTotalLayers = cumulativeWorkingLayersPair.get(detailDeptId);
-                            BigDecimal tempTotalLayers = existTotalLayers.add(dailyFuel);
+                            BigDecimal tempTotalLayers = existTotalLayers.add(dailyLayers);
                             cumulativeWorkingLayersPair.put(detailDeptId, tempTotalLayers);
                         } else {
                             cumulativeWorkingLayersPair.put(detailDeptId, dailyLayers);
@@ -546,7 +545,7 @@ public class IotFiveDailyReportServiceImpl implements IotFiveDailyReportService
                         // 累计加砂
                         if (cumulativeMixSandPair.containsKey(detailDeptId)) {
                             BigDecimal existTotalSand = cumulativeMixSandPair.get(detailDeptId);
-                            BigDecimal tempTotalSand = existTotalSand.add(dailyFuel);
+                            BigDecimal tempTotalSand = existTotalSand.add(dailySand);
                             cumulativeMixSandPair.put(detailDeptId, tempTotalSand);
                         } else {
                             cumulativeMixSandPair.put(detailDeptId, dailySand);
@@ -554,7 +553,7 @@ public class IotFiveDailyReportServiceImpl implements IotFiveDailyReportService
                         // 累计注液
                         if (cumulativeLiquidPair.containsKey(detailDeptId)) {
                             BigDecimal existTotalLiquid = cumulativeLiquidPair.get(detailDeptId);
-                            BigDecimal tempTotalLiquid = existTotalLiquid.add(dailyFuel);
+                            BigDecimal tempTotalLiquid = existTotalLiquid.add(dailyLiquid);
                             cumulativeLiquidPair.put(detailDeptId, tempTotalLiquid);
                         } else {
                             cumulativeLiquidPair.put(detailDeptId, dailyLiquid);

+ 9 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotprojecttaskplan/IotProjectTaskPlanService.java

@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.pms.service.iotprojecttaskplan;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.module.pms.controller.admin.iotprojecttaskplan.vo.IotProjectTaskPlanPageReqVO;
 import cn.iocoder.yudao.module.pms.controller.admin.iotprojecttaskplan.vo.IotProjectTaskPlanSaveReqVO;
+import cn.iocoder.yudao.module.pms.controller.admin.iotprojecttaskplan.vo.IotProjectTaskPlanStatisticsRespVO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotprojecttaskattrs.IotTaskAttrModelProperty;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotprojecttaskplan.IotProjectTaskPlanDO;
 
@@ -61,4 +62,12 @@ public interface IotProjectTaskPlanService {
      * @return 工作量计划扩展属性列表
      */
     List<IotTaskAttrModelProperty> planExtProperties(IotProjectTaskPlanPageReqVO pageReqVO);
+
+    /**
+     * 专业公司工作量计划 汇总统计
+     *
+     * @param pageReqVO 分页查询
+     * @return 工作量计划汇总统计对象列表
+     */
+    List<IotProjectTaskPlanStatisticsRespVO> summaryStatistics(IotProjectTaskPlanPageReqVO pageReqVO);
 }

+ 532 - 2
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotprojecttaskplan/IotProjectTaskPlanServiceImpl.java

@@ -9,17 +9,26 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
 import cn.iocoder.yudao.module.pms.controller.admin.iotoperationmeetingattrs.vo.IotOperationMeetingAttrsPageReqVO;
 import cn.iocoder.yudao.module.pms.controller.admin.iotprojecttaskplan.vo.IotProjectTaskPlanPageReqVO;
 import cn.iocoder.yudao.module.pms.controller.admin.iotprojecttaskplan.vo.IotProjectTaskPlanSaveReqVO;
+import cn.iocoder.yudao.module.pms.controller.admin.iotprojecttaskplan.vo.IotProjectTaskPlanStatisticsItemRespVO;
+import cn.iocoder.yudao.module.pms.controller.admin.iotprojecttaskplan.vo.IotProjectTaskPlanStatisticsRespVO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotoperationmeetingattrs.IotOperationMeetingAttrsDO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotprojecttaskattrs.IotTaskAttrModelProperty;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotprojecttaskplan.IotProjectTaskPlanDO;
 import cn.iocoder.yudao.module.pms.dal.mysql.iotoperationmeetingattrs.IotOperationMeetingAttrsMapper;
 import cn.iocoder.yudao.module.pms.dal.mysql.iotprojecttaskplan.IotProjectTaskPlanMapper;
+import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptListReqVO;
 import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
+import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO;
 import cn.iocoder.yudao.module.system.dal.mysql.dept.DeptMapper;
+import cn.iocoder.yudao.module.system.service.dept.DeptService;
+import cn.iocoder.yudao.module.system.service.dict.DictDataService;
 import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
 
 import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.time.YearMonth;
 import java.util.*;
 import java.util.stream.Collectors;
 
@@ -45,6 +54,12 @@ public class IotProjectTaskPlanServiceImpl implements IotProjectTaskPlanService
     @Resource
     private DeptMapper deptMapper;
 
+    @Resource
+    private DeptService deptService;
+
+    @Resource
+    private DictDataService dictDataService;
+
     @Override
     public Long createIotProjectTaskPlan(IotProjectTaskPlanSaveReqVO createReqVO) {
         // 插入
@@ -53,7 +68,7 @@ public class IotProjectTaskPlanServiceImpl implements IotProjectTaskPlanService
             throw exception(IOT_PROJECT_TASK_PLAN_NOT_EXISTS);
         }
         // 校验当前队伍部门 指定时间所属月份 是否已经存在 工作量计划记录
-        IotProjectTaskPlanDO existPlan = iotProjectTaskPlanMapper.selectOneByDeptIdAndMonth(createReqVO.getDeptId(), createReqVO.getStartTime(), null);
+        IotProjectTaskPlanDO existPlan = iotProjectTaskPlanMapper.selectOneByDeptIdAndMonth(createReqVO.getDeptId(), createReqVO.getStartTime(), createReqVO.getBusiness(), null);
         if (ObjUtil.isNotEmpty(existPlan)) {
             throw exception(IOT_PROJECT_TASK_PLAN_EXISTS);
         }
@@ -67,7 +82,7 @@ public class IotProjectTaskPlanServiceImpl implements IotProjectTaskPlanService
         // 校验存在
         validateIotProjectTaskPlanExists(updateReqVO.getId());
         // 校验当前队伍部门 指定时间所属月份 是否已经存在 工作量计划记录
-        IotProjectTaskPlanDO existPlan = iotProjectTaskPlanMapper.selectOneByDeptIdAndMonth(updateReqVO.getDeptId(), updateReqVO.getStartTime(), updateReqVO.getId());
+        IotProjectTaskPlanDO existPlan = iotProjectTaskPlanMapper.selectOneByDeptIdAndMonth(updateReqVO.getDeptId(), updateReqVO.getStartTime(), updateReqVO.getBusiness(), updateReqVO.getId());
         if (ObjUtil.isNotEmpty(existPlan)) {
             throw exception(IOT_PROJECT_TASK_PLAN_EXISTS);
         }
@@ -146,4 +161,519 @@ public class IotProjectTaskPlanServiceImpl implements IotProjectTaskPlanService
         return result;
     }
 
+    @Override
+    public List<IotProjectTaskPlanStatisticsRespVO> summaryStatistics(IotProjectTaskPlanPageReqVO pageReqVO) {
+        List<IotProjectTaskPlanStatisticsRespVO> result = new ArrayList<>();
+        // 不分页统计所有数据
+        Set<Long> ids = new HashSet<>();
+        if (ObjUtil.isEmpty(pageReqVO.getDeptId())) {
+            // 如果没有传递 deptId 参数 默认根据当前登录人所属公司
+            return result;
+        }
+        ids = deptService.getChildDeptIdListFromCache(pageReqVO.getDeptId());
+        // 找到所有根部门子部门对象集合
+        ids.add(pageReqVO.getDeptId());
+        // 查询所有工作量计划列表
+        pageReqVO.setDeptIds(ids);
+        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+        PageResult<IotProjectTaskPlanDO> pagePlans = iotProjectTaskPlanMapper.selectPage(pageReqVO);
+        List<IotProjectTaskPlanDO> plans = pagePlans.getList();
+        /* if (CollUtil.isEmpty(plans)) {
+            return result;
+        } */
+        // 默认显示所有公司的汇总数据 点击公司 显示各项目部数据
+        // 点击项目部 显示 下属队伍的数据
+        // 首先判断点击的部门是属于 公司 还是 队伍 如果没有点击任何部门 默认选中最顶级部门
+        // 判断点击的组织树中的部门类型 类型(公司级1 项目部2 队伍3)
+        DeptDO selectedDept = deptService.getDept(pageReqVO.getDeptId());
+        if ("0".equals(selectedDept.getType())) {
+            // 选中集团 查询所有公司的汇总数据
+            // result = statisticsByCompany(plans, pageReqVO);
+        } else if ("1".equals(selectedDept.getType())) {
+            // 选中公司 查询公司下所有项目部的汇总数据
+            result = statisticsByProjectDept(plans, pageReqVO);
+        } else if ("2".equals(selectedDept.getType())) {
+            // 选中项目部 查询项目部下所有队伍的汇总数据
+            result = statisticsByProjectTeam(plans, pageReqVO);
+        } else if ("3".equals(selectedDept.getType())) {
+            // 选中队伍 查询单个队伍的汇总数据
+            result = statisticsByProjectTeam(plans, pageReqVO);
+        } else {
+            // 点击的部门没有类型 如 瑞恒 新疆分公司 查询下属项目部的汇总数据
+            result = statisticsByProjectDept(plans, pageReqVO);
+        }
+
+        // 根据result集合内对象的 sort 属性正序排列 sort 类型为 integer 类型
+        if (CollUtil.isNotEmpty(result)) {
+            result.sort(Comparator.comparing(
+                    IotProjectTaskPlanStatisticsRespVO::getSort,
+                    Comparator.nullsLast(Comparator.naturalOrder())
+            ));
+        }
+
+        return result;
+    }
+
+
+    /**
+     * 按项目部维度 汇总 统计数据
+     * @param plans 月度计划工作量列表
+     * @param pageReqVO 包含根部门ID(如 163L为 瑞都 根部门,或其他公司级部门ID)
+     * @return 项目部维度统计结果列表
+     */
+    private List<IotProjectTaskPlanStatisticsRespVO> statisticsByProjectDept(List<IotProjectTaskPlanDO> plans, IotProjectTaskPlanPageReqVO pageReqVO) {
+        List<IotProjectTaskPlanStatisticsRespVO> result = new ArrayList<>();
+
+        Set<Long> projectDeptIds = new HashSet<>();
+        // key项目部id    value项目部名称
+        Map<Long, DeptDO> projectDeptPair = new HashMap<>();
+        // key部门id   value部门parentId
+        Map<Long, Long> teamProjectIdPair = new HashMap<>();
+        // key队伍id    value队伍部门
+        Map<Long, DeptDO> teamDeptPair = new HashMap<>();
+
+        // key队伍id/项目部id   value累计 注气量(万方)
+        Map<Long, BigDecimal> cumulativeGasInjectionPair = new HashMap<>();
+        // key队伍id/项目部id   value累计 进尺(米)
+        Map<Long, BigDecimal> cumulativeFootagePair = new HashMap<>();
+        // key队伍id/项目部id   value累计 井次(井)    修井 井下 连油 井次
+        Map<Long, BigDecimal> cumulativeWellCountPair = new HashMap<>();
+        // key队伍id/项目部id   value累计 压裂(层)    瑞都压裂层  5#国压裂层
+        Map<Long, BigDecimal> cumulativeFracLayerPair = new HashMap<>();
+        // key队伍id/项目部id   value业务类型
+        Map<Long, String> projectBusinessPair = new HashMap<>();
+
+        // 月度统计(项目部 -> 年月 -> 统计值)
+        Map<Long, Map<String, MonthlyStats>> projectMonthStatsMap = new HashMap<>();
+
+        //  计划工作量 项目业务类型 key字典键值     value字典标签
+        Map<String, String> workloadPlanDictPair = new HashMap<>();
+
+        // key项目业务类型     value项目部id集合
+        Map<String, Set<Long>> projectBizPair = new HashMap<>();
+
+        // 队伍id 集合
+        Set<Long> teamIds = new HashSet<>();
+
+        // 以项目部为维度统计数据
+        // 找到所有项目部与队伍的对应关系
+        // 查询指定根部门下的所有子部门
+        Set<Long> allRhChildDeptIds = deptService.getChildDeptIdListFromCache(pageReqVO.getDeptId());
+        DeptListReqVO reqVO = new DeptListReqVO();
+        reqVO.setDeptIds(allRhChildDeptIds);
+        List<DeptDO> departments = deptService.getDeptList(reqVO);
+
+        // 查询 计划工作量 项目业务类型 项目业务(注气/钻井/修井/压裂/连油/井下)
+        List<DictDataDO> workloadPlanBizData = dictDataService.getDictDataListByDictType("rq_iot_workload_plan_biz");
+        if (CollUtil.isNotEmpty(workloadPlanBizData)) {
+            workloadPlanBizData.forEach(tech -> {
+                String label = tech.getLabel();
+                workloadPlanDictPair.put(tech.getValue(), label);
+                // 设置每个项目部的业务类型
+                String projectDeptIdsStr = tech.getRemark();
+                if (StrUtil.isNotBlank(projectDeptIdsStr)) {
+                    // 数据格式 234,124,832
+                    // 逗号分割、转Long、过滤空字符串、收集到Set
+                    Set<Long> deptIdSet = StrUtil.splitTrim(projectDeptIdsStr, ",")
+                            .stream()
+                            .filter(StrUtil::isNotBlank)
+                            .map(Long::valueOf)
+                            .collect(Collectors.toSet());
+
+                    // 存入map:存在则合并集合,不存在则新建
+                    projectBizPair.computeIfAbsent(label, k -> new HashSet<>()).addAll(deptIdSet);
+                }
+            });
+        }
+
+        // 构建项目部映射和父子部门关系
+        departments.forEach(dept -> {
+            if ("2".equals(dept.getType())) {
+                // 项目部
+                projectDeptIds.add(dept.getId());
+                projectDeptPair.put(dept.getId(), dept);
+            }
+            if ("3".equals(dept.getType())) {
+                // 队伍
+                teamIds.add(dept.getId());
+                teamDeptPair.put(dept.getId(), dept);
+            }
+            // 所有部门与上级部门的 id 对应关系
+            teamProjectIdPair.put(dept.getId(), dept.getParentId());
+
+        });
+        // 遍历 计划工作量列表 以项目部为维度组装 工作量数据
+        plans.forEach(plan -> {
+            BigDecimal gasInjection = ObjUtil.isNotEmpty(plan.getPlanGasInjection()) ? plan.getPlanGasInjection() : BigDecimal.ZERO;
+            BigDecimal footage = ObjUtil.isNotEmpty(plan.getPlanFootage()) ? plan.getPlanFootage() : BigDecimal.ZERO;
+            BigDecimal wellTrips = ObjUtil.isNotEmpty(plan.getPlanWellTrips()) ? plan.getPlanWellTrips() : BigDecimal.ZERO;
+            BigDecimal layers = ObjUtil.isNotEmpty(plan.getPlanLayers()) ? plan.getPlanLayers() : BigDecimal.ZERO;
+            String business = plan.getBusiness();
+            if (ObjUtil.isNotEmpty(plan.getDeptId()) && teamProjectIdPair.containsKey(plan.getDeptId())) {
+                // 项目部id
+                Long projectDeptId = 0l;
+                if (teamDeptPair.containsKey(plan.getDeptId())) {
+                    // 日报 deptId 如果是队伍 获取队伍的上级项目部
+                    projectDeptId = teamProjectIdPair.get(plan.getDeptId());
+                }
+                if (projectDeptPair.containsKey(plan.getDeptId())) {
+                    // 日报 deptId 如果是项目部 使用当前项目部
+                    projectDeptId = plan.getDeptId();
+                }
+
+                if (ObjUtil.isNotEmpty(projectDeptId) && (projectDeptId > 0)) {
+                    // 累计注气量
+                    cumulativeGasInjectionPair.compute(projectDeptId, (k, v) -> ObjUtil.isEmpty(v) ? gasInjection : v.add(gasInjection));
+                    // 累计进尺
+                    cumulativeFootagePair.compute(projectDeptId, (k, v) -> ObjUtil.isEmpty(v) ? footage : v.add(footage));
+                    // 累计井次
+                    cumulativeWellCountPair.compute(projectDeptId, (k, v) -> ObjUtil.isEmpty(v) ? wellTrips : v.add(wellTrips));
+                    // 累计压裂层
+                    cumulativeFracLayerPair.compute(projectDeptId, (k, v) -> ObjUtil.isEmpty(v) ? layers : v.add(layers));
+                    // 工作量业务类型
+                    if (StrUtil.isNotBlank(business) && workloadPlanDictPair.containsKey(business)) {
+                        projectBusinessPair.put(projectDeptId, workloadPlanDictPair.get(business));
+                    }
+                }
+
+                // 按照 年 月 汇总统计 计划工作量 如 2025-03
+                LocalDateTime startTime = plan.getStartTime();
+                if (ObjUtil.isNotEmpty(startTime)) {
+                    // 提取出时间中的 年 月
+                    Integer year = startTime.getYear();
+                    Integer month = startTime.getMonthValue();
+                    String uniqueKey = StrUtil.join("-", year, month);
+                    // 统计各项目下包含的按照 yyyy-MM 统计的各项工作量
+                    // 获取该项目部的月度Map
+                    Map<String, MonthlyStats> monthMap = projectMonthStatsMap.computeIfAbsent(projectDeptId, k -> new HashMap<>());
+                    // 获取该年月的统计对象
+                    MonthlyStats stats = monthMap.computeIfAbsent(uniqueKey, k -> new MonthlyStats());
+                    // 累加
+                    stats.gasInjection = stats.gasInjection.add(gasInjection);
+                    stats.footage = stats.footage.add(footage);
+                    stats.wellCount = stats.wellCount.add(wellTrips);
+                    stats.fracLayer = stats.fracLayer.add(layers);
+                }
+            }
+        });
+
+        // 组装查询时间区间内包含的 年 月
+        LocalDateTime[] startTimeArr = pageReqVO.getStartTime();
+        if (ObjUtil.isEmpty(startTimeArr)) {
+            return result;
+        }
+        if (startTimeArr.length < 1) {
+            return result;
+        }
+        List<String> allMonths = generateMonthRange(startTimeArr[0], startTimeArr[1]);
+
+        // 生成返回的数据列表集合
+        projectDeptPair.forEach((deptId, dept) -> {
+            IotProjectTaskPlanStatisticsRespVO statistics = new IotProjectTaskPlanStatisticsRespVO();
+            statistics.setProjectDeptId(deptId);
+            statistics.setProjectDeptName(dept.getName());
+            statistics.setSort(dept.getSort());
+            statistics.setType("2");
+            statistics.setCumulativeGasInjection(cumulativeGasInjectionPair.getOrDefault(deptId, BigDecimal.ZERO));
+            statistics.setCumulativeFootage(cumulativeFootagePair.getOrDefault(deptId, BigDecimal.ZERO));
+            statistics.setCumulativeWellCount(cumulativeWellCountPair.getOrDefault(deptId, BigDecimal.ZERO));
+            statistics.setCumulativeFracLayer(cumulativeFracLayerPair.getOrDefault(deptId, BigDecimal.ZERO));
+
+            // 遍历全部业务映射,收集该项目部绑定的所有业务(支持多业务)
+            List<String> bizNameList = new ArrayList<>();
+            for (Map.Entry<String, Set<Long>> bizEntry : projectBizPair.entrySet()) {
+                Set<Long> bindDeptIds = bizEntry.getValue();
+                if (CollUtil.isNotEmpty(bindDeptIds) && bindDeptIds.contains(deptId)) {
+                    bizNameList.add(bizEntry.getKey());
+                }
+            }
+            // 多业务逗号拼接,无匹配则为null
+            String businessName = CollUtil.isNotEmpty(bizNameList) ? CollUtil.join(bizNameList, ",") : StrUtil.EMPTY;
+            statistics.setBusiness(businessName);
+
+            // 处理月度明细
+            Map<String, MonthlyStats> existingMonthMap = projectMonthStatsMap.get(deptId);
+            List<IotProjectTaskPlanStatisticsItemRespVO> items = new ArrayList<>();
+            if (allMonths.isEmpty()) {
+                // 无时间范围时,仅输出已有的月度(兼容原逻辑)
+                if (CollUtil.isNotEmpty(existingMonthMap)) {
+                    items = existingMonthMap.entrySet().stream()
+                            .sorted(Map.Entry.comparingByKey())
+                            .map(entry -> {
+                                IotProjectTaskPlanStatisticsItemRespVO item = new IotProjectTaskPlanStatisticsItemRespVO();
+                                item.setYearMonth(entry.getKey());
+                                MonthlyStats ms = entry.getValue();
+                                item.setCumulativeGasInjection(ms.gasInjection);
+                                item.setCumulativeFootage(ms.footage);
+                                item.setCumulativeWellCount(ms.wellCount);
+                                item.setCumulativeFracLayer(ms.fracLayer);
+                                return item;
+                            })
+                            .collect(Collectors.toList());
+                }
+            } else {
+                // ★ 补全所有月份
+                for (String month : allMonths) {
+                    MonthlyStats stats = CollUtil.isNotEmpty(existingMonthMap) ? existingMonthMap.get(month) : null;
+                    if (stats == null) {
+                        stats = new MonthlyStats(); // 默认所有字段为 0
+                    }
+                    IotProjectTaskPlanStatisticsItemRespVO item = new IotProjectTaskPlanStatisticsItemRespVO();
+                    item.setYearMonth(month);
+                    item.setCumulativeGasInjection(stats.gasInjection);
+                    item.setCumulativeFootage(stats.footage);
+                    item.setCumulativeWellCount(stats.wellCount);
+                    item.setCumulativeFracLayer(stats.fracLayer);
+                    items.add(item);
+                }
+            }
+
+            if (!items.isEmpty()) {
+                statistics.setItems(items);
+            }
+
+            result.add(statistics);
+        });
+
+        return result;
+    }
+
+    /**
+     * 按队伍维度 汇总 统计数据
+     * @param plans 月度计划工作量列表
+     * @param pageReqVO 包含根部门ID(如 163L为 瑞都 根部门,或其他公司级部门ID)
+     * @return 队伍维度统计结果列表
+     */
+    private List<IotProjectTaskPlanStatisticsRespVO> statisticsByProjectTeam(List<IotProjectTaskPlanDO> plans, IotProjectTaskPlanPageReqVO pageReqVO) {
+        List<IotProjectTaskPlanStatisticsRespVO> result = new ArrayList<>();
+
+        Set<Long> teamDeptIds = new HashSet<>();
+        // key项目部id    value项目部名称
+        Map<Long, DeptDO> projectDeptPair = new HashMap<>();
+        // key队伍id    value队伍名称
+        Map<Long, DeptDO> teamDeptPair = new HashMap<>();
+        // key部门id   value部门parentId
+        Map<Long, Long> teamProjectIdPair = new HashMap<>();
+
+        // key队伍id/项目部id   value累计 注气量(万方)
+        Map<Long, BigDecimal> cumulativeGasInjectionPair = new HashMap<>();
+        // key队伍id/项目部id   value累计 进尺(米)
+        Map<Long, BigDecimal> cumulativeFootagePair = new HashMap<>();
+        // key队伍id/项目部id   value累计 井次(井)    修井 井下 连油 井次
+        Map<Long, BigDecimal> cumulativeWellCountPair = new HashMap<>();
+        // key队伍id/项目部id   value累计 压裂(层)    瑞都压裂层  5#国压裂层
+        Map<Long, BigDecimal> cumulativeFracLayerPair = new HashMap<>();
+        // key队伍id/项目部id   value业务类型
+        Map<Long, String> projectBusinessPair = new HashMap<>();
+
+        // 月度统计(队伍 -> 年月 -> 统计值)
+        Map<Long, Map<String, MonthlyStats>> teamMonthStatsMap = new HashMap<>();
+
+        //  计划工作量 项目业务类型 key字典键值     value字典标签
+        Map<String, String> workloadPlanDictPair = new HashMap<>();
+
+        // key项目业务类型     value项目部id集合
+        Map<String, Set<Long>> projectBizPair = new HashMap<>();
+
+        // 以 队伍 为维度统计数据
+        // 查询指定根部门下的所有子部门
+        Set<Long> allRhChildDeptIds = deptService.getChildDeptIdListFromCache(pageReqVO.getDeptId());
+        DeptListReqVO reqVO = new DeptListReqVO();
+        // 查询某支队伍 或 所属项目部的信息
+        allRhChildDeptIds.add(pageReqVO.getDeptId());
+        reqVO.setDeptIds(allRhChildDeptIds);
+        List<DeptDO> departments = deptService.getDeptList(reqVO);
+
+        // 查询 计划工作量 项目业务类型 项目业务(注气/钻井/修井/压裂/连油/井下)
+        List<DictDataDO> workloadPlanBizData = dictDataService.getDictDataListByDictType("rq_iot_workload_plan_biz");
+        if (CollUtil.isNotEmpty(workloadPlanBizData)) {
+            workloadPlanBizData.forEach(tech -> {
+                String label = tech.getLabel();
+                workloadPlanDictPair.put(tech.getValue(), label);
+                // 设置每个项目部的业务类型
+                String projectDeptIdsStr = tech.getRemark();
+                if (StrUtil.isNotBlank(projectDeptIdsStr)) {
+                    // 数据格式 234,124,832
+                    // 逗号分割、转Long、过滤空字符串、收集到Set
+                    Set<Long> deptIdSet = StrUtil.splitTrim(projectDeptIdsStr, ",")
+                            .stream()
+                            .filter(StrUtil::isNotBlank)
+                            .map(Long::valueOf)
+                            .collect(Collectors.toSet());
+
+                    // 存入map:存在则合并集合,不存在则新建
+                    projectBizPair.computeIfAbsent(label, k -> new HashSet<>()).addAll(deptIdSet);
+                }
+            });
+        }
+        // 组装队伍集合
+        departments.forEach(dept -> {
+            if ("3".equals(dept.getType())) {
+                // 队伍
+                teamDeptIds.add(dept.getId());
+                teamDeptPair.put(dept.getId(), dept);
+            }
+            if ("2".equals(dept.getType())) {
+                // 项目部
+                projectDeptPair.put(dept.getId(), dept);
+            }
+            teamProjectIdPair.put(dept.getId(), dept.getParentId());
+        });
+
+        // 遍历 计划工作量列表 以队伍为维度组装 工作量数据
+        plans.forEach(plan -> {
+            Long deptId = plan.getDeptId();
+            BigDecimal gasInjection = ObjUtil.isNotEmpty(plan.getPlanGasInjection()) ? plan.getPlanGasInjection() : BigDecimal.ZERO;
+            BigDecimal footage = ObjUtil.isNotEmpty(plan.getPlanFootage()) ? plan.getPlanFootage() : BigDecimal.ZERO;
+            BigDecimal wellTrips = ObjUtil.isNotEmpty(plan.getPlanWellTrips()) ? plan.getPlanWellTrips() : BigDecimal.ZERO;
+            BigDecimal layers = ObjUtil.isNotEmpty(plan.getPlanLayers()) ? plan.getPlanLayers() : BigDecimal.ZERO;
+            String business = plan.getBusiness();
+            if (ObjUtil.isNotEmpty(deptId) && teamProjectIdPair.containsKey(deptId)) {
+                // 累计注气量
+                cumulativeGasInjectionPair.compute(deptId, (k, v) -> ObjUtil.isEmpty(v) ? gasInjection : v.add(gasInjection));
+                // 累计进尺
+                cumulativeFootagePair.compute(deptId, (k, v) -> ObjUtil.isEmpty(v) ? footage : v.add(footage));
+                // 累计井次
+                cumulativeWellCountPair.compute(deptId, (k, v) -> ObjUtil.isEmpty(v) ? wellTrips : v.add(wellTrips));
+                // 累计压裂层
+                cumulativeFracLayerPair.compute(deptId, (k, v) -> ObjUtil.isEmpty(v) ? layers : v.add(layers));
+                // 工作量业务类型
+                if (StrUtil.isNotBlank(business) && workloadPlanDictPair.containsKey(business)) {
+                    projectBusinessPair.put(deptId, workloadPlanDictPair.get(business));
+                }
+
+                // 按照 年 月 汇总统计 计划工作量 如 2025-03
+                LocalDateTime startTime = plan.getStartTime();
+                if (ObjUtil.isNotEmpty(startTime)) {
+                    // 提取出时间中的 年 月
+                    Integer year = startTime.getYear();
+                    Integer month = startTime.getMonthValue();
+                    String uniqueKey = StrUtil.join("-", year, month);
+                    // 统计各项目下包含的按照 yyyy-MM 统计的各项工作量
+                    // 获取该项目部的月度Map
+                    Map<String, MonthlyStats> monthMap = teamMonthStatsMap.computeIfAbsent(deptId, k -> new HashMap<>());
+                    // 获取该年月的统计对象
+                    MonthlyStats stats = monthMap.computeIfAbsent(uniqueKey, k -> new MonthlyStats());
+                    // 累加
+                    stats.gasInjection = stats.gasInjection.add(gasInjection);
+                    stats.footage = stats.footage.add(footage);
+                    stats.wellCount = stats.wellCount.add(wellTrips);
+                    stats.fracLayer = stats.fracLayer.add(layers);
+                }
+            }
+        });
+
+        // 组装查询时间区间内包含的 年 月
+        LocalDateTime[] startTimeArr = pageReqVO.getStartTime();
+        if (ObjUtil.isEmpty(startTimeArr)) {
+            return result;
+        }
+        if (startTimeArr.length < 1) {
+            return result;
+        }
+        List<String> allMonths = generateMonthRange(startTimeArr[0], startTimeArr[1]);
+
+        // 队伍数据  生成返回的数据列表集合
+        teamDeptPair.forEach((teamDeptId, dept) -> {
+            IotProjectTaskPlanStatisticsRespVO statistics = new IotProjectTaskPlanStatisticsRespVO();
+            statistics.setTeamId(teamDeptId);
+            statistics.setTeamName(dept.getName());
+            statistics.setSort(dept.getSort());
+            if (teamDeptPair.containsKey(teamDeptId)) {
+                statistics.setType("3");    // 最好是 项目部小队同时展示 因为有的瑞都日报挂在了项目部下
+            }
+            statistics.setCumulativeGasInjection(cumulativeGasInjectionPair.getOrDefault(teamDeptId, BigDecimal.ZERO));
+            statistics.setCumulativeFootage(cumulativeFootagePair.getOrDefault(teamDeptId, BigDecimal.ZERO));
+            statistics.setCumulativeWellCount(cumulativeWellCountPair.getOrDefault(teamDeptId, BigDecimal.ZERO));
+            statistics.setCumulativeFracLayer(cumulativeFracLayerPair.getOrDefault(teamDeptId, BigDecimal.ZERO));
+
+            // 遍历全部业务映射,收集该项目部绑定的所有业务(支持多业务)
+            List<String> bizNameList = new ArrayList<>();
+            if (teamProjectIdPair.containsKey(teamDeptId)) {
+                // 当前队伍的上级项目部id
+                Long projectDeptId = teamProjectIdPair.get(teamDeptId);
+                for (Map.Entry<String, Set<Long>> bizEntry : projectBizPair.entrySet()) {
+                    Set<Long> bindDeptIds = bizEntry.getValue();
+                    if (CollUtil.isNotEmpty(bindDeptIds) && bindDeptIds.contains(projectDeptId)) {
+                        bizNameList.add(bizEntry.getKey());
+                    }
+                }
+            }
+            // 多业务逗号拼接,无匹配则为null
+            String businessName = CollUtil.isNotEmpty(bizNameList) ? CollUtil.join(bizNameList, ",") : StrUtil.EMPTY;
+            statistics.setBusiness(businessName);
+
+            // 处理月度明细
+            Map<String, MonthlyStats> existingMonthMap = teamMonthStatsMap.get(teamDeptId);
+            List<IotProjectTaskPlanStatisticsItemRespVO> items = new ArrayList<>();
+            if (allMonths.isEmpty()) {
+                // 无时间范围时,仅输出已有的月度(兼容原逻辑)
+                if (CollUtil.isNotEmpty(existingMonthMap)) {
+                    items = existingMonthMap.entrySet().stream()
+                            .sorted(Map.Entry.comparingByKey())
+                            .map(entry -> {
+                                IotProjectTaskPlanStatisticsItemRespVO item = new IotProjectTaskPlanStatisticsItemRespVO();
+                                item.setYearMonth(entry.getKey());
+                                MonthlyStats ms = entry.getValue();
+                                item.setCumulativeGasInjection(ms.gasInjection);
+                                item.setCumulativeFootage(ms.footage);
+                                item.setCumulativeWellCount(ms.wellCount);
+                                item.setCumulativeFracLayer(ms.fracLayer);
+                                return item;
+                            })
+                            .collect(Collectors.toList());
+                }
+            } else {
+                // ★ 补全所有月份
+                for (String month : allMonths) {
+                    MonthlyStats stats = existingMonthMap != null ? existingMonthMap.get(month) : null;
+                    if (stats == null) {
+                        stats = new MonthlyStats(); // 默认所有字段为 0
+                    }
+                    IotProjectTaskPlanStatisticsItemRespVO item = new IotProjectTaskPlanStatisticsItemRespVO();
+                    item.setYearMonth(month);
+                    item.setCumulativeGasInjection(stats.gasInjection);
+                    item.setCumulativeFootage(stats.footage);
+                    item.setCumulativeWellCount(stats.wellCount);
+                    item.setCumulativeFracLayer(stats.fracLayer);
+                    items.add(item);
+                }
+            }
+
+            if (!items.isEmpty()) {
+                statistics.setItems(items);
+            }
+
+            result.add(statistics);
+        });
+
+        return result;
+    }
+
+    /**
+     * 生成从 start 到 end 之间的所有月份字符串(格式:yyyy-M,无前导零)
+     */
+    private List<String> generateMonthRange(LocalDateTime start, LocalDateTime end) {
+        if (ObjUtil.isEmpty(start) || ObjUtil.isEmpty(end)) {
+            return Collections.emptyList();
+        }
+        List<String> months = new ArrayList<>();
+        YearMonth startYm = YearMonth.from(start);
+        YearMonth endYm = YearMonth.from(end);
+        YearMonth current = startYm;
+        while (!current.isAfter(endYm)) {
+            months.add(current.getYear() + "-" + current.getMonthValue());
+            current = current.plusMonths(1);
+        }
+        return months;
+    }
+
+    // 内部类:月度统计辅助类
+    private static class MonthlyStats {
+        BigDecimal gasInjection = BigDecimal.ZERO;
+        BigDecimal footage = BigDecimal.ZERO;
+        BigDecimal wellCount = BigDecimal.ZERO;
+        BigDecimal fracLayer = BigDecimal.ZERO;
+    }
+
 }