2
0

6 Коммитууд a21711fcaf ... 8829aa3c2a

Эзэн SHA1 Мессеж Огноо
  zhulu 8829aa3c2a Merge remote-tracking branch 'remotes/origin/V1.0.13' into V1.0.14 2 долоо хоног өмнө
  zhulu 9ba205c865 定时统计本年履职任务完成情况 1 сар өмнө
  zhulu 5a25bc5e0e 新增数据导出接口,可传入时间过滤字段和时间范围 1 сар өмнө
  zhulu 861196c5e7 新增 补偿生产履职PDF 接口 忽略已生成机构 1 сар өмнө
  zhulu ea60a71547 新增脚本 1 сар өмнө
  zhulu d49f3c9053 新增本年 履职任务完成数量统计定时任务 1 сар өмнө
24 өөрчлөгдсөн 939 нэмэгдсэн , 23 устгасан
  1. 4 0
      project_data/sql/1.0.13/quartz/quartz.sql
  2. 53 0
      project_data/sql/1.0.13/soc/soc.sql
  3. 3 0
      soc-api/soc-api-system/src/main/java/com/xunmei/system/api/RemoteResumptionTaskService.java
  4. 5 0
      soc-api/soc-api-system/src/main/java/com/xunmei/system/api/factory/RemoteResumptionTaskFallbackFactory.java
  5. 4 4
      soc-api/soc-api-system/src/main/java/com/xunmei/system/api/function/RemoteCallHandlerExecutor.java
  6. 11 0
      soc-modules/soc-modules-core/src/main/java/com/xunmei/core/board/controller/WebCockpitController.java
  7. 64 0
      soc-modules/soc-modules-core/src/main/java/com/xunmei/core/board/domain/ResumptionTaskCount.java
  8. 3 0
      soc-modules/soc-modules-core/src/main/java/com/xunmei/core/board/mapper/CockpitMapper.java
  9. 18 0
      soc-modules/soc-modules-core/src/main/java/com/xunmei/core/board/mapper/ResumptionTaskCountMapper.java
  10. 2 0
      soc-modules/soc-modules-core/src/main/java/com/xunmei/core/board/service/CockpitService.java
  11. 12 0
      soc-modules/soc-modules-core/src/main/java/com/xunmei/core/board/service/ResumptionTaskCountService.java
  12. 133 4
      soc-modules/soc-modules-core/src/main/java/com/xunmei/core/board/service/impl/CockpitServiceImpl.java
  13. 18 0
      soc-modules/soc-modules-core/src/main/java/com/xunmei/core/board/service/impl/ResumptionTaskCountServiceImpl.java
  14. 28 0
      soc-modules/soc-modules-core/src/main/java/com/xunmei/core/board/vo/web/ResumptionTaskStatisticVo.java
  15. 13 0
      soc-modules/soc-modules-core/src/main/java/com/xunmei/core/resumption/controller/ApiPlanController.java
  16. 2 0
      soc-modules/soc-modules-core/src/main/java/com/xunmei/core/resumption/service/AppPlanService.java
  17. 238 14
      soc-modules/soc-modules-core/src/main/java/com/xunmei/core/resumption/service/impl/AppPlanServiceImpl.java
  18. 19 0
      soc-modules/soc-modules-core/src/main/resources/mapper/board/CockpitMapper.xml
  19. 9 0
      soc-modules/soc-modules-job/src/main/java/com/xunmei/job/task/CoreResumptionTask.java
  20. 5 1
      soc-modules/soc-modules-system/pom.xml
  21. 15 0
      soc-modules/soc-modules-system/src/main/java/com/xunmei/system/controller/ExportSqlController.java
  22. 8 0
      soc-modules/soc-modules-system/src/main/java/com/xunmei/system/service/ExportSqlService.java
  23. 108 0
      soc-modules/soc-modules-system/src/main/java/com/xunmei/system/service/impl/ExportSqlServiceImpl.java
  24. 164 0
      soc-modules/soc-modules-system/src/main/java/com/xunmei/system/util/ExportDatabaseUtil.java

+ 4 - 0
project_data/sql/1.0.13/quartz/quartz.sql

@@ -0,0 +1,4 @@
+
+delete from sys_job where job_name ='本年履职完成数量统计';
+
+INSERT INTO `sys_job` (`job_name`, `job_group`, `invoke_target`, `cron_expression`, `misfire_policy`, `concurrent`, `status`, `create_by`, `create_time`, `update_by`, `update_time`) VALUES ('本年履职完成数量统计', 'DEFAULT', 'CoreResumptionTask.statisticTaskCount', '0 0 2 * * ?', '1', '1', '0', '超级管理员', '2025-09-22 14:09:16', '超级管理员', '2025-09-22 14:09:36');

+ 53 - 0
project_data/sql/1.0.13/soc/soc.sql

@@ -0,0 +1,53 @@
+-- v 1.0.13 版本升级脚本
+
+DELIMITER ??
+DROP PROCEDURE IF EXISTS schema_change ??
+CREATE PROCEDURE schema_change()
+BEGIN
+
+    IF NOT EXISTS(SELECT DISTINCT INDEX_NAME
+            FROM INFORMATION_SCHEMA.STATISTICS
+            WHERE TABLE_SCHEMA = DATABASE()
+              AND TABLE_NAME = 'core_resumption_data_nfc'
+              AND INDEX_NAME = 'index_submit_time') THEN
+        ALTER TABLE `core_resumption_data_nfc`
+            ADD INDEX `index_submit_time`(`submit_time`) USING BTREE;
+    end if;
+
+    IF NOT EXISTS(SELECT DISTINCT INDEX_NAME
+            FROM INFORMATION_SCHEMA.STATISTICS
+            WHERE TABLE_SCHEMA = DATABASE()
+              AND TABLE_NAME = 'core_register_book_pdf'
+              AND INDEX_NAME = 'index_org_path') THEN
+        ALTER TABLE `core_register_book_pdf`
+            ADD INDEX `index_org_path`(`org_path`) USING BTREE;
+    end if;
+
+    IF NOT EXISTS(SELECT DISTINCT INDEX_NAME
+            FROM INFORMATION_SCHEMA.STATISTICS
+            WHERE TABLE_SCHEMA = DATABASE()
+              AND TABLE_NAME = 'core_register_book_pdf'
+              AND INDEX_NAME = 'index_org_id') THEN
+        ALTER TABLE `core_register_book_pdf`
+            ADD INDEX `index_org_id`(`org_id`) USING BTREE;
+    end if;
+END ??
+DELIMITER ;
+CALL schema_change();
+
+DROP TABLE IF EXISTS `core_resumption_task_count_statistic`;
+CREATE TABLE `core_resumption_task_count_statistic` (
+    `id` bigint NOT NULL,
+    `org_id` bigint DEFAULT NULL COMMENT '机构ID',
+    `org_path` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '机构业务路径',
+    `task_total` int DEFAULT NULL COMMENT '任务总数',
+    `completed_count` int DEFAULT NULL COMMENT '已完成数量',
+    `create_by` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+    `create_time` datetime DEFAULT NULL,
+    `update_by` varchar(125) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL COMMENT '修改人名称',
+    `update_time` datetime DEFAULT NULL COMMENT '修改时间',
+    PRIMARY KEY (`id`) USING BTREE,
+    KEY `index_org_id` (`org_id`) USING BTREE,
+    KEY `index_org_path` (`org_path`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='机构本年度履职任务完成情况统计表,供WEB驾驶舱查询使用';
+

+ 3 - 0
soc-api/soc-api-system/src/main/java/com/xunmei/system/api/RemoteResumptionTaskService.java

@@ -52,4 +52,7 @@ public interface RemoteResumptionTaskService {
 
     @GetMapping(value = "/api/plan/buildPdf")
     AjaxResult buildPdf();
+
+    @GetMapping(value = "/cockpit/statistic/resumption")
+    R<Boolean> statisticTaskCount();
 }

+ 5 - 0
soc-api/soc-api-system/src/main/java/com/xunmei/system/api/factory/RemoteResumptionTaskFallbackFactory.java

@@ -71,6 +71,11 @@ public class RemoteResumptionTaskFallbackFactory implements FallbackFactory<Remo
                 return AjaxResult.error();
             }
 
+            @Override
+            public R<Boolean> statisticTaskCount() {
+                return R.fail();
+            }
+
 
         };
     }

+ 4 - 4
soc-api/soc-api-system/src/main/java/com/xunmei/system/api/function/RemoteCallHandlerExecutor.java

@@ -20,21 +20,21 @@ public class RemoteCallHandlerExecutor {
             if (handle instanceof AjaxResult) {
                 final AjaxResult ajaxResult = (AjaxResult) handle;
                 if (!ajaxResult.isSuccess()) {
-                    throw new SystemException(ErrorMsgConstants.REMOTE_CALL_ERROR + errorMessage);
+                    throw new SystemException(ErrorMsgConstants.REMOTE_CALL_ERROR + errorMessage +" ajaxResult.isSuccess false");
                 }
             }
             if (handle instanceof R) {
                 final R result = (R) handle;
                 if (!R.isSuccess(result)) {
-                    throw new SystemException(ErrorMsgConstants.REMOTE_CALL_ERROR + errorMessage);
+                    throw new SystemException(ErrorMsgConstants.REMOTE_CALL_ERROR + errorMessage +" R.isSuccess false");
                 }
             }
             if (ObjectUtil.isNull(handle)) {
-                throw new SystemException(ErrorMsgConstants.REMOTE_CALL_ERROR + errorMessage);
+                throw new SystemException(ErrorMsgConstants.REMOTE_CALL_ERROR + errorMessage+" 返回值为空");
             }
             return handle;
         } catch (Exception e) {
-            throw new SystemException(ErrorMsgConstants.REMOTE_CALL_ERROR + errorMessage);
+            throw new SystemException(ErrorMsgConstants.REMOTE_CALL_ERROR + errorMessage+e.getMessage()+e.getStackTrace());
         }
     }
 }

+ 11 - 0
soc-modules/soc-modules-core/src/main/java/com/xunmei/core/board/controller/WebCockpitController.java

@@ -36,6 +36,17 @@ public class WebCockpitController extends BaseController {
     }
 
 
+
+    @GetMapping("/statistic/resumption")
+    public AjaxResult statisticResumptionTaskCount() {
+        try {
+            cockpitService.statisticCurrentYearResumptionTaskCount();
+            return AjaxResult.success("提前统计机构履职任务完成数量成功");
+        } catch (Exception e) {
+            return AjaxResult.error("提前统计机构履职任务完成数量失败"+e.getMessage()+e.getStackTrace());
+        }
+    }
+
     /**
      * 统计近期下级机构安全检查情况
      */

+ 64 - 0
soc-modules/soc-modules-core/src/main/java/com/xunmei/core/board/domain/ResumptionTaskCount.java

@@ -0,0 +1,64 @@
+package com.xunmei.core.board.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.xunmei.common.core.utils.Ymd;
+import com.xunmei.common.core.web.domain.BaseEntity;
+import com.xunmei.core.resumption.domain.AppPlan;
+import com.xunmei.system.api.domain.SysOrg;
+import feign.form.FormData;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Date;
+import java.util.List;
+
+
+/**
+ * 履职
+ */
+@Data
+@AllArgsConstructor
+@Builder
+@TableName("core_resumption_task_count_statistic")
+public class ResumptionTaskCount extends BaseEntity {
+
+    private static Logger log = LoggerFactory.getLogger(ResumptionTaskCount.class);
+
+    /**
+     * 编号
+     */
+    @TableId
+    private Long id;
+
+    /**
+     * 机构
+     */
+    private Long orgId;
+
+    /**
+     * 机构路径
+     */
+    private String orgPath;
+
+    /**
+     * 任务总数
+     */
+    private Integer taskTotal;
+
+
+    /**
+     * 已完成数目
+     */
+    private Integer completedCount;
+
+    public ResumptionTaskCount() {
+    }
+}

+ 3 - 0
soc-modules/soc-modules-core/src/main/java/com/xunmei/core/board/mapper/CockpitMapper.java

@@ -1,6 +1,7 @@
 package com.xunmei.core.board.mapper;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.xunmei.core.board.domain.ResumptionTaskCount;
 import com.xunmei.core.board.dto.web.OrgMapDto;
 import com.xunmei.core.board.dto.web.WebGA38InfoDto;
 import com.xunmei.core.board.dto.web.WebSyntheticQuestionDto;
@@ -14,6 +15,8 @@ import java.util.Map;
 public interface CockpitMapper extends BaseMapper {
     List<TaskStatisticVo> resumption(@Param("startDate") Date start,@Param("endDate") Date end,@Param("orgPath") String orgPath);
 
+    ResumptionTaskStatisticVo statisticOneOrgResumptionTask(@Param("startDate") Date startDate, @Param("endDate") Date endDate, @Param("orgId") Long orgId);
+
     List<WebSafetyCheckVo> safetyCheck(@Param("startDate") Date start,@Param("endDate") Date end,@Param("orgPath") String orgPath);
 
     List<TaskStatisticVo> edu(@Param("startDate") Date start,@Param("endDate") Date end,@Param("orgPath") String orgPath);

+ 18 - 0
soc-modules/soc-modules-core/src/main/java/com/xunmei/core/board/mapper/ResumptionTaskCountMapper.java

@@ -0,0 +1,18 @@
+package com.xunmei.core.board.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.xunmei.core.board.domain.ResumptionTaskCount;
+import org.apache.ibatis.annotations.Delete;
+
+/**
+ * @Description: 类描述
+ * @Author: LuZhu
+ * @CreateDate: 2025/9/19 14:38
+ */
+public interface ResumptionTaskCountMapper extends BaseMapper<ResumptionTaskCount> {
+    /**
+     * 强制清空整张表(绕过 MyBatis-Plus 全表删除保护)
+     */
+    @Delete("DELETE FROM core_resumption_task_count_statistic WHERE org_id is not null")
+    void deleteAll();
+}

+ 2 - 0
soc-modules/soc-modules-core/src/main/java/com/xunmei/core/board/service/CockpitService.java

@@ -11,6 +11,8 @@ public interface CockpitService {
      */
     List<TaskStatisticVo> resumption(TaskStatisticDto dto);
 
+    void statisticCurrentYearResumptionTaskCount();
+
     /**
      * 统计近期下级机构安全检查情况
      */

+ 12 - 0
soc-modules/soc-modules-core/src/main/java/com/xunmei/core/board/service/ResumptionTaskCountService.java

@@ -0,0 +1,12 @@
+package com.xunmei.core.board.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.xunmei.core.board.domain.ResumptionTaskCount;
+
+/**
+ * @Description: 类描述
+ * @Author: LuZhu
+ * @CreateDate: 2025/9/19 14:39
+ */
+public interface ResumptionTaskCountService extends IService<ResumptionTaskCount> {
+}

+ 133 - 4
soc-modules/soc-modules-core/src/main/java/com/xunmei/core/board/service/impl/CockpitServiceImpl.java

@@ -2,32 +2,42 @@ package com.xunmei.core.board.service.impl;
 
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.xunmei.common.core.constant.SecurityConstants;
 import com.xunmei.common.core.domain.DateRange;
+import com.xunmei.common.core.domain.R;
 import com.xunmei.common.core.enums.CycleCommonEnum;
 import com.xunmei.common.core.enums.OrgTypeEnum;
 import com.xunmei.common.core.exception.ServiceException;
 import com.xunmei.common.core.utils.DateUtils;
+import com.xunmei.common.core.utils.IDHelper;
 import com.xunmei.common.core.utils.NumberUtils;
 import com.xunmei.common.core.utils.StringUtils;
+import com.xunmei.core.board.domain.ResumptionTaskCount;
 import com.xunmei.core.board.dto.web.OrgMapDto;
 import com.xunmei.core.board.dto.web.TaskStatisticDto;
 import com.xunmei.core.board.dto.web.WebSyntheticQuestionDto;
 import com.xunmei.core.board.enums.PeriodEnum;
 import com.xunmei.core.board.mapper.CockpitMapper;
+import com.xunmei.core.board.mapper.ResumptionTaskCountMapper;
 import com.xunmei.core.board.service.CockpitService;
+import com.xunmei.core.board.service.ResumptionTaskCountService;
 import com.xunmei.core.board.vo.web.*;
 import com.xunmei.system.api.RemoteDictDataService;
 import com.xunmei.system.api.RemoteOrgService;
 import com.xunmei.system.api.domain.SysDictData;
 import com.xunmei.system.api.domain.SysOrg;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.http.annotation.Obsolete;
+import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
 import javax.annotation.Resource;
 import java.util.*;
 import java.util.stream.Collectors;
-
+@Slf4j
 @Service
 public class CockpitServiceImpl implements CockpitService {
     @Resource
@@ -39,15 +49,134 @@ public class CockpitServiceImpl implements CockpitService {
     @Resource
     RemoteDictDataService remoteDictDataService;
 
+    @Resource
+    ResumptionTaskCountMapper resumptionTaskCountMapper;
+
+    @Resource
+    ResumptionTaskCountService resumptionTaskCountService;
+
+
+
     @Override
     public List<TaskStatisticVo> resumption(TaskStatisticDto dto) {
+        List<TaskStatisticVo> list;
         Date date = getStartDate(dto.getPeriod());
         SysOrg org = getOrgThrowIfNull(dto.getOrgId());
         String orgPath = org.getPath();
-        List<TaskStatisticVo> list = cockpitMapper.resumption(date, DateUtil.endOfDay(new Date()), orgPath);
-//        return taskStatistic(list, org, Arrays.asList(OrgTypeEnum.LIHANG_ZIZHU_YINGHANG.getCode(), OrgTypeEnum.YINGYE_WANGDIAN.getCode()));
+
+        // 判断是否为本年查询
+        if (PeriodEnum.ThisYear.getCode().equals(dto.getPeriod())) {
+            list= handleThisYearCase(org.getPath());
+        } else {
+            list = cockpitMapper.resumption(date, DateUtil.endOfDay(new Date()), orgPath);
+        }
         return taskStatistic(list, org, Arrays.asList(OrgTypeEnum.YINGYE_WANGDIAN.getCode()));
     }
+    /**
+     * 处理“本年”特殊逻辑
+     */
+    private List<TaskStatisticVo> handleThisYearCase(String orgPath)
+    {
+        // 1. 从统计表获取历史数据(年初到昨天)
+        List<TaskStatisticVo> list = resumptionTaskCountService.list().stream().map(this::convertToVo).collect(Collectors.toList());
+
+        // 2. 实时查询今日数据
+        List<TaskStatisticVo> toDayTaskStatistic = cockpitMapper.resumption(DateUtil.beginOfDay(new Date()), DateUtil.endOfDay(new Date()), orgPath);
+
+        // 3. 统计表数据为空 直接返回 实时查询的今日数据
+        if(CollectionUtils.isEmpty(list))
+        {
+            return toDayTaskStatistic;
+        }
+
+        // 4. 合并:按 orgId 聚合,任务数和完成数相加
+        Map<Long, TaskStatisticVo> map = new HashMap<>(list.size());
+        for (TaskStatisticVo task : list) {
+            map.put(task.getOrgId(),task);
+        }
+
+        toDayTaskStatistic.stream().forEach(x->{
+            TaskStatisticVo existing = map.get(x.getOrgId());
+            if (existing != null) {
+                existing.setTaskTotal(existing.getTaskTotal() + x.getTaskTotal());
+                existing.setCompletedCount(existing.getCompletedCount() + x.getCompletedCount());
+            } else {
+                map.put(x.getOrgId(), x);
+            }
+        });
+
+        return new ArrayList<>(map.values());
+    }
+
+    /**
+     * VO 转换:Entity -> VO
+     */
+    private TaskStatisticVo convertToVo(ResumptionTaskCount x) {
+        TaskStatisticVo vo = new TaskStatisticVo();
+        vo.setOrgId(x.getOrgId());
+        vo.setOrgPath(x.getOrgPath());
+        vo.setTaskTotal(x.getTaskTotal());
+        vo.setCompletedCount(x.getCompletedCount());
+        return vo;
+    }
+
+    /**
+     * VO 转换:VO -> Entity
+     */
+    private ResumptionTaskCount convertToEntity(ResumptionTaskStatisticVo vo,SysOrg org) {
+        ResumptionTaskCount entity = new ResumptionTaskCount();
+        entity.setId(IDHelper.id());
+        entity.setOrgId(org.getId());
+        entity.setOrgPath(org.getPath());
+        entity.setTaskTotal(vo.getTaskTotal());
+        entity.setCreateTime(new Date());
+        entity.setCompletedCount(ObjectUtil.isNull(vo.getCompletedCount()) ? 0: vo.getCompletedCount());
+        return entity;
+    }
+
+    /**
+     * 由于履职任务数据量较大,为提高查询速度,定时提前统计机构任务数据
+     * 统计每个机构本年内的履职任务总数量和已完成数量
+     * 统计范围:年初到当前时间的前一天
+     */
+    @Async
+    @Override
+    @Transactional
+    public void statisticCurrentYearResumptionTaskCount() {
+        try {
+            log.info("开始:统计本年履职任务数量和已完成数量");
+            Date startDate = getStartDate(PeriodEnum.ThisYear.getCode());
+            Date endDate = DateUtil.offsetDay(DateUtil.endOfDay(new Date()), -1);
+
+            //开年第一天不统计
+            if(endDate.before(startDate))
+            {
+                //删除前一年的结果
+                resumptionTaskCountMapper.deleteAll();
+                return;
+            }
+
+            final R<List<SysOrg>> allOrgResult = remoteOrgService.getAllOrg(SecurityConstants.INNER);
+            if (allOrgResult == null || allOrgResult.getData() == null || allOrgResult.getData().isEmpty()) {
+                return;
+            }
+            List<SysOrg> allOrg = allOrgResult.getData();
+            List<ResumptionTaskCount> taskCountList =new ArrayList<>();
+            for (SysOrg org : allOrg) {
+                ResumptionTaskStatisticVo taskStatisticVo = cockpitMapper.statisticOneOrgResumptionTask(startDate, endDate, org.getId());
+                if(taskStatisticVo!=null && taskStatisticVo.getTaskTotal()!=null &&  taskStatisticVo.getTaskTotal()>0)
+                {
+                    taskCountList.add(convertToEntity(taskStatisticVo,org));
+                }
+            }
+            //先删除,再插入
+            resumptionTaskCountMapper.deleteAll();
+            resumptionTaskCountService.saveBatch(taskCountList);
+            log.info("结束:统计本年履职任务数量和已完成数量");
+        } catch (Exception ex) {
+            log.error("提前统计本年履职任务数量和已完成数量失败:{},{}",ex.getMessage(),ex.getStackTrace());
+        }
+    }
 
     @Override
     public List<WebSafetyCheckVo> safetyCheck(TaskStatisticDto dto) {
@@ -259,7 +388,7 @@ public class CockpitServiceImpl implements CockpitService {
     /**
      * 本月来访
      *
-     * @param orgPath
+     * @param orgId
      * @return
      */
     @Override

+ 18 - 0
soc-modules/soc-modules-core/src/main/java/com/xunmei/core/board/service/impl/ResumptionTaskCountServiceImpl.java

@@ -0,0 +1,18 @@
+package com.xunmei.core.board.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.xunmei.core.board.domain.ResumptionTaskCount;
+import com.xunmei.core.board.mapper.ResumptionTaskCountMapper;
+import com.xunmei.core.board.service.ResumptionTaskCountService;
+import org.springframework.stereotype.Service;
+
+/**
+ * @ClassName ResumptionTaskCountServiceImpl
+ * @Description: 类描述
+ * @Author: LuZhu
+ * @CreateDate: 2025/9/19 16:23
+ */
+@Service
+public class ResumptionTaskCountServiceImpl extends ServiceImpl<ResumptionTaskCountMapper, ResumptionTaskCount> implements ResumptionTaskCountService {
+
+}

+ 28 - 0
soc-modules/soc-modules-core/src/main/java/com/xunmei/core/board/vo/web/ResumptionTaskStatisticVo.java

@@ -0,0 +1,28 @@
+package com.xunmei.core.board.vo.web;
+
+import lombok.Data;
+
+/**
+ * @ClassName ResumptionTaskStatiscVo
+ * @Description: 类描述
+ * @Author: LuZhu
+ * @CreateDate: 2025/9/22 14:57
+ */
+@Data
+public class ResumptionTaskStatisticVo {
+    /**
+     *
+     */
+    private Long orgId;
+
+    private String orgPath;
+    /**
+     * 任务总数
+     */
+    private Integer taskTotal;
+
+    /**
+     * 完成数量
+     */
+    private Integer completedCount;
+}

+ 13 - 0
soc-modules/soc-modules-core/src/main/java/com/xunmei/core/resumption/controller/ApiPlanController.java

@@ -4,6 +4,7 @@ import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.util.ObjectUtil;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.xunmei.common.core.constant.Constants;
+import com.xunmei.common.core.exception.SystemException;
 import com.xunmei.common.core.web.domain.AjaxResult;
 import com.xunmei.common.core.web.page.TableDataInfo;
 import com.xunmei.common.security.annotation.RequiresPermissions;
@@ -129,6 +130,18 @@ public class ApiPlanController {
         return AjaxResult.success();
     }
 
+    @GetMapping("/buildPdf/ignorecreatedpdforg/{dateStr}")
+    public AjaxResult buildPdfAndIgnoreCreatedPdfOrg(@PathVariable("dateStr") String dateStr) {
+        Date date;
+        if (ObjectUtil.isEmpty(dateStr)) {
+            throw new SystemException("dateStr 参数不能为空");
+        } else {
+            date = DateUtil.parse(dateStr, Constants.DAILY_FORMAT);
+        }
+        appPlanService.buildPdfAndIgnoreCreatedPdfOrg(date);
+        return AjaxResult.success();
+    }
+
     /**
      * 新增 修改履职计划
      *

+ 2 - 0
soc-modules/soc-modules-core/src/main/java/com/xunmei/core/resumption/service/AppPlanService.java

@@ -90,6 +90,8 @@ public interface AppPlanService extends IService<AppPlan> {
 
     void buildPdf(Date date);
 
+    void buildPdfAndIgnoreCreatedPdfOrg(Date date);
+
     void buildResumptionNotWorkTimePdf(Long orgId, Date date);
 
     void buildResumptionPdfDaily(Long orgId, Date date);

+ 238 - 14
soc-modules/soc-modules-core/src/main/java/com/xunmei/core/resumption/service/impl/AppPlanServiceImpl.java

@@ -1597,8 +1597,61 @@ public class AppPlanServiceImpl extends ServiceImpl<AppPlanMapper, AppPlan> impl
     @Override
     public void buildResumptionNotWorkTimePdf(Long orgId, Date date) {
         SysOrg sysOrg = RemoteCallHandlerExecutor.executeRemoteCall(() -> orgService.selectOrgById(orgId, SecurityConstants.INNER), ErrorMsgConstants.QUERY_ORG_DATA_ERROR);
+        buildResumptionNotWorkTimePdf(sysOrg,date);
+//        String fileName = registerBookPdfService.getPdfFileName(RegisterBookType.ON_DUTY_USER, sysOrg);
+//        Map<String, Object> data = this.getFtlResumptionNotWorkTime(orgId, date);
+//        if (!checkHasData(data)) {
+//            log.error("未查询到履职数据,未能生成{},机构名称:{}", RegisterBookType.ON_DUTY_USER.getText(), sysOrg.getShortName());
+//            return;
+//        }
+//        data.put("title", RegisterBookType.ON_DUTY_USER.getText());
+//        data.put("fileName", fileName);
+//        data.put("orgName", sysOrg.getShortName());
+//        data.put("dateStr", DateUtil.format(date, Constants.DAILY_FORMAT_ZH));
+//        data.put("remark", "");
+//        CompletableFuture.runAsync(() -> {
+//            R<String> r = RemoteCallHandlerExecutor.executeRemoteCall(() -> fileService.generateResumptionPdf(data), ErrorMsgConstants.GENERATE_PDF_ERROR);
+//            if (null == r || null == r.getData()) {
+//                throw new SystemException(ErrorMsgConstants.GENERATE_PDF_ERROR);
+//            }
+//           /* Long id = (Long) data.get("id");
+//            if (ObjectUtil.isNull(id)) {
+//                throw new SystemException(ErrorMsgConstants.GENERATE_PDF_ERROR);
+//            }*/
+//            String pdfUrl = r.getData();
+//            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+//            String dateStr = sdf.format(date);
+//            LambdaQueryWrapper<CoreRegisterBookPdf> wrapper = new LambdaQueryWrapper<>();
+//            wrapper.eq(CoreRegisterBookPdf::getOrgId, orgId)
+//                    .eq(CoreRegisterBookPdf::getDate, dateStr)
+//                    .eq(CoreRegisterBookPdf::getRegisterBookType, RegisterBookType.ON_DUTY_USER.getNum())
+//                    .like(CoreRegisterBookPdf::getFileName, sysOrg.getName() + "_" + RegisterBookType.ON_DUTY_USER.getText() + "_");
+//            CoreRegisterBookPdf registerBookPdf = coreRegisterBookPdfMapper.selectOne(wrapper);
+//            if (ObjectUtil.isEmpty(registerBookPdf)) {
+//                registerBookPdf = new CoreRegisterBookPdf();
+//                registerBookPdf.setId(IdWorker.getId());
+//                registerBookPdf.setRegisterBookType(RegisterBookType.ON_DUTY_USER.getNum());
+//                registerBookPdf.setDate(date);
+//                registerBookPdf.setOrgId(orgId);
+//                registerBookPdf.setOrgName(sysOrg.getShortName());
+//                registerBookPdf.setOrgPath(sysOrg.getPath());
+//                registerBookPdf.setFileUrl(pdfUrl);
+//                registerBookPdf.setFileName(fileName);
+//            } else {
+//                registerBookPdf.setFileUrl(pdfUrl);
+//                registerBookPdf.setFileName(fileName);
+//            }
+//            if (StringUtils.isEmpty(registerBookPdf.getFileName()) || StringUtils.isEmpty(pdfUrl)) {
+//                throw new SystemException(ErrorMsgConstants.GENERATE_PDF_ERROR);
+//            }
+//            registerBookPdfService.saveOrUpdate(registerBookPdf);
+//        }, threadPoolTaskExecutor);
+    }
+
+
+    public void buildResumptionNotWorkTimePdf(SysOrg sysOrg, Date date) {
         String fileName = registerBookPdfService.getPdfFileName(RegisterBookType.ON_DUTY_USER, sysOrg);
-        Map<String, Object> data = this.getFtlResumptionNotWorkTime(orgId, date);
+        Map<String, Object> data = this.getFtlResumptionNotWorkTime(sysOrg.getId(), date);
         if (!checkHasData(data)) {
             log.error("未查询到履职数据,未能生成{},机构名称:{}", RegisterBookType.ON_DUTY_USER.getText(), sysOrg.getShortName());
             return;
@@ -1621,7 +1674,7 @@ public class AppPlanServiceImpl extends ServiceImpl<AppPlanMapper, AppPlan> impl
             SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
             String dateStr = sdf.format(date);
             LambdaQueryWrapper<CoreRegisterBookPdf> wrapper = new LambdaQueryWrapper<>();
-            wrapper.eq(CoreRegisterBookPdf::getOrgId, orgId)
+            wrapper.eq(CoreRegisterBookPdf::getOrgId, sysOrg.getId())
                     .eq(CoreRegisterBookPdf::getDate, dateStr)
                     .eq(CoreRegisterBookPdf::getRegisterBookType, RegisterBookType.ON_DUTY_USER.getNum())
                     .like(CoreRegisterBookPdf::getFileName, sysOrg.getName() + "_" + RegisterBookType.ON_DUTY_USER.getText() + "_");
@@ -1631,7 +1684,7 @@ public class AppPlanServiceImpl extends ServiceImpl<AppPlanMapper, AppPlan> impl
                 registerBookPdf.setId(IdWorker.getId());
                 registerBookPdf.setRegisterBookType(RegisterBookType.ON_DUTY_USER.getNum());
                 registerBookPdf.setDate(date);
-                registerBookPdf.setOrgId(orgId);
+                registerBookPdf.setOrgId(sysOrg.getId());
                 registerBookPdf.setOrgName(sysOrg.getShortName());
                 registerBookPdf.setOrgPath(sysOrg.getPath());
                 registerBookPdf.setFileUrl(pdfUrl);
@@ -1648,13 +1701,66 @@ public class AppPlanServiceImpl extends ServiceImpl<AppPlanMapper, AppPlan> impl
     }
 
 
-    @Async
+//    @Async
     @Override
     @Transactional(rollbackFor = Exception.class)
     public void buildResumptionPdfDaily(Long orgId, Date date) {
         SysOrg sysOrg = RemoteCallHandlerExecutor.executeRemoteCall(() -> orgService.selectOrgById(orgId, SecurityConstants.INNER), ErrorMsgConstants.QUERY_ORG_DATA_ERROR);
+        buildResumptionPdfDaily(sysOrg,date);
+//        String fileName = registerBookPdfService.getPdfFileName(RegisterBookType.SECURITY_PERFORMANCE, sysOrg);
+//        Map<String, Object> data = this.getFtlResumptionDaily(orgId, date);
+//        if (!checkHasData(data)) {
+//            log.error("未查询到履职数据,未能生成{},机构名称:{}", RegisterBookType.SECURITY_PERFORMANCE.getText(), sysOrg.getShortName());
+//            return;
+//        }
+//        data.put("fileName", fileName);
+//        data.put("title", RegisterBookType.SECURITY_PERFORMANCE.getText());
+//        data.put("orgName", sysOrg.getShortName());
+//        data.put("dateStr", DateUtil.format(date, Constants.DAILY_FORMAT_ZH));
+//        data.put("remark", "");
+//        CompletableFuture.runAsync(() -> {
+//            R<String> r = RemoteCallHandlerExecutor.executeRemoteCall(() -> fileService.generateResumptionPdf(data), ErrorMsgConstants.GENERATE_PDF_ERROR);
+//            if (null == r || null == r.getData()) {
+//                throw new SystemException(ErrorMsgConstants.GENERATE_PDF_ERROR);
+//            }
+//            /*Long id = (Long) data.get("id");
+//            if (ObjectUtil.isNull(id)) {
+//                throw new SystemException(ErrorMsgConstants.GENERATE_PDF_ERROR);
+//            }*/
+//            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+//            String dateStr = sdf.format(date);
+//
+//            String pdfUrl = r.getData();
+//            LambdaQueryWrapper<CoreRegisterBookPdf> wrapper = new LambdaQueryWrapper<>();
+//            wrapper.eq(CoreRegisterBookPdf::getOrgId, orgId)
+//                    .eq(CoreRegisterBookPdf::getDate, dateStr)
+//                    .eq(CoreRegisterBookPdf::getRegisterBookType, RegisterBookType.SECURITY_PERFORMANCE.getNum())
+//                    .like(CoreRegisterBookPdf::getFileName, sysOrg.getName() + "_" + RegisterBookType.SECURITY_PERFORMANCE.getText() + "_");
+//            CoreRegisterBookPdf registerBookPdf = coreRegisterBookPdfMapper.selectOne(wrapper);
+//            if (ObjectUtil.isEmpty(registerBookPdf)) {
+//                registerBookPdf = new CoreRegisterBookPdf();
+//                registerBookPdf.setId(IdWorker.getId());
+//                registerBookPdf.setRegisterBookType(RegisterBookType.SECURITY_PERFORMANCE.getNum());
+//                registerBookPdf.setDate(date);
+//                registerBookPdf.setOrgId(orgId);
+//                registerBookPdf.setOrgName(sysOrg.getShortName());
+//                registerBookPdf.setOrgPath(sysOrg.getPath());
+//                registerBookPdf.setFileUrl(pdfUrl);
+//                registerBookPdf.setFileName(fileName);
+//            } else {
+//                registerBookPdf.setFileUrl(pdfUrl);
+//                registerBookPdf.setFileName(fileName);
+//            }
+//            if (StringUtils.isEmpty(registerBookPdf.getFileName()) || StringUtils.isEmpty(pdfUrl)) {
+//                throw new SystemException(ErrorMsgConstants.GENERATE_PDF_ERROR);
+//            }
+//            registerBookPdfService.saveOrUpdate(registerBookPdf);
+//        }, threadPoolTaskExecutor);
+    }
+
+    public void buildResumptionPdfDaily(SysOrg sysOrg, Date date) {
         String fileName = registerBookPdfService.getPdfFileName(RegisterBookType.SECURITY_PERFORMANCE, sysOrg);
-        Map<String, Object> data = this.getFtlResumptionDaily(orgId, date);
+        Map<String, Object> data = this.getFtlResumptionDaily(sysOrg.getId(), date);
         if (!checkHasData(data)) {
             log.error("未查询到履职数据,未能生成{},机构名称:{}", RegisterBookType.SECURITY_PERFORMANCE.getText(), sysOrg.getShortName());
             return;
@@ -1678,7 +1784,7 @@ public class AppPlanServiceImpl extends ServiceImpl<AppPlanMapper, AppPlan> impl
 
             String pdfUrl = r.getData();
             LambdaQueryWrapper<CoreRegisterBookPdf> wrapper = new LambdaQueryWrapper<>();
-            wrapper.eq(CoreRegisterBookPdf::getOrgId, orgId)
+            wrapper.eq(CoreRegisterBookPdf::getOrgId, sysOrg.getId())
                     .eq(CoreRegisterBookPdf::getDate, dateStr)
                     .eq(CoreRegisterBookPdf::getRegisterBookType, RegisterBookType.SECURITY_PERFORMANCE.getNum())
                     .like(CoreRegisterBookPdf::getFileName, sysOrg.getName() + "_" + RegisterBookType.SECURITY_PERFORMANCE.getText() + "_");
@@ -1688,7 +1794,7 @@ public class AppPlanServiceImpl extends ServiceImpl<AppPlanMapper, AppPlan> impl
                 registerBookPdf.setId(IdWorker.getId());
                 registerBookPdf.setRegisterBookType(RegisterBookType.SECURITY_PERFORMANCE.getNum());
                 registerBookPdf.setDate(date);
-                registerBookPdf.setOrgId(orgId);
+                registerBookPdf.setOrgId(sysOrg.getId());
                 registerBookPdf.setOrgName(sysOrg.getShortName());
                 registerBookPdf.setOrgPath(sysOrg.getPath());
                 registerBookPdf.setFileUrl(pdfUrl);
@@ -1715,12 +1821,79 @@ public class AppPlanServiceImpl extends ServiceImpl<AppPlanMapper, AppPlan> impl
                 .select(Resumption::getOrgId));
         List<Long> orgIds = resumptions.stream().map(Resumption::getOrgId).distinct().collect(Collectors.toList());
         for (Long orgId : orgIds) {
-            buildResumptionPdfDaily(orgId, date);
-            buildResumptionNotWorkTimePdf(orgId, date);
-            buildResumptionAllDayPdf(orgId, date);
+            try{
+                SysOrg sysOrg = RemoteCallHandlerExecutor.executeRemoteCall(() -> orgService.selectOrgById(orgId, SecurityConstants.INNER), ErrorMsgConstants.QUERY_ORG_DATA_ERROR);
+                buildResumptionPdfDaily(sysOrg, date);
+                buildResumptionNotWorkTimePdf(sysOrg, date);
+                buildResumptionAllDayPdf(sysOrg, date);
+            }
+            catch (Exception e)
+            {
+                log.error("生成机构ID为{}的登记簿异常,异常原因{}", orgId, e.getMessage()+e.getStackTrace());
+            }
         }
     }
 
+    public void buildPdfAndIgnoreCreatedPdfOrg(Date date,Map<String, List<CoreRegisterBookPdf>> existPdfGrouped) {
+
+        List<Resumption> resumptions = resumptionMapper.selectList(new LambdaQueryWrapper<Resumption>()
+                .le(Resumption::getPlanStartTime, DateUtils.toLocalDate(date))
+                .ge(Resumption::getPlanEndTime, DateUtils.toLocalDate(date))
+                .select(Resumption::getOrgId));
+        List<Long> orgIds = resumptions.stream().map(Resumption::getOrgId).distinct().collect(Collectors.toList());
+        for (Long orgId : orgIds) {
+            try{
+                SysOrg sysOrg = RemoteCallHandlerExecutor.executeRemoteCall(() -> orgService.selectOrgById(orgId, SecurityConstants.INNER), ErrorMsgConstants.QUERY_ORG_DATA_ERROR);
+                // 安保履职登记簿
+                String dailyPdfKey =getPdfKey(orgId,RegisterBookType.SECURITY_PERFORMANCE.getNum());
+                if(!existPdfGrouped.containsKey(dailyPdfKey))
+                {
+                    buildResumptionPdfDaily(sysOrg, date);
+                }
+                // 值班履职登记簿
+                String onDutyPdfKey =getPdfKey(orgId,RegisterBookType.ON_DUTY_USER.getNum());
+                if(!existPdfGrouped.containsKey(onDutyPdfKey))
+                {
+                    buildResumptionNotWorkTimePdf(sysOrg, date);
+                }
+                //4:“110”入侵报警系统测试 5:不间断电源(UPS)维护 6:离行式自助银行巡检
+                String alarmPdfKey =getPdfKey(orgId,RegisterBookType.ALARM_TEST.getNum());
+                String selfPdfKey =getPdfKey(orgId,RegisterBookType.SELF_SERVICE_BANK.getNum());
+                String backupPowerPdfKey =getPdfKey(orgId,RegisterBookType.BACKUP_POWER.getNum());
+                if(!existPdfGrouped.containsKey(alarmPdfKey)&&!existPdfGrouped.containsKey(selfPdfKey) &&!existPdfGrouped.containsKey(backupPowerPdfKey))
+                {
+                    buildResumptionAllDayPdf(sysOrg, date);
+                }
+            }
+            catch (Exception e)
+            {
+                log.error("buildPdfAndIgnoreCreatedPdfOrg 生成机构ID为{}的登记簿异常,异常原因{}", orgId, e.getMessage()+e.getStackTrace());
+            }
+        }
+    }
+
+    private String getPdfKey(Long orgId,Integer registerBookType)
+    {
+        return orgId + "_" + registerBookType;
+    }
+
+    @Async
+    @Override
+    public void buildPdfAndIgnoreCreatedPdfOrg(Date date) {
+        Integer[] bookTypes={0,4,5,6,7};
+        List<CoreRegisterBookPdf> existPdfList= registerBookPdfService.list(new LambdaQueryWrapper<CoreRegisterBookPdf>()
+                .eq(CoreRegisterBookPdf::getDate, DateUtils.toLocalDate(date))
+                .in(CoreRegisterBookPdf::getRegisterBookType,bookTypes)
+                .select(CoreRegisterBookPdf::getOrgId,CoreRegisterBookPdf::getRegisterBookType));
+
+        Map<String, List<CoreRegisterBookPdf>> existPdfGrouped = existPdfList.stream()
+                .collect(Collectors.groupingBy(
+                        pdf -> getPdfKey(pdf.getOrgId(),pdf.getRegisterBookType()) //pdf.getOrgId() + "_" + pdf.getRegisterBookType()
+                ));
+
+        buildPdfAndIgnoreCreatedPdfOrg(date,existPdfGrouped);
+    }
+
     private Boolean checkHasData(Map<String, Object> data) {
         final List<SysDictData> dictCache = DictUtils.getDictCache(DictConstants.RESUMPTION_PLAN_EXEC);
         final List<String> names = dictCache.stream().map(SysDictData::getDictLabel).collect(Collectors.toList());
@@ -1736,6 +1909,59 @@ public class AppPlanServiceImpl extends ServiceImpl<AppPlanMapper, AppPlan> impl
     @Override
     public void buildResumptionAllDayPdf(Long orgId, Date date) {
         SysOrg sysOrg = RemoteCallHandlerExecutor.executeRemoteCall(() -> orgService.selectOrgById(orgId, SecurityConstants.INNER), ErrorMsgConstants.QUERY_ORG_DATA_ERROR);
+        buildResumptionAllDayPdf(sysOrg,date);
+//        //110报警:4
+//        //电源:5
+//        final List<Map<String, Object>> mapList = this.getFtlResumptionAllDay(sysOrg, date);
+//        for (Map<String, Object> data : mapList) {
+//            if (!checkHasData(data)) {
+//                log.error("未查询到履职数据,未能生成{},机构名称:{}", RegisterBookType.getEnums((Integer) data.get("planType")).getText(), sysOrg.getShortName());
+//                return;
+//            }
+//            CompletableFuture.runAsync(() -> {
+//                R<String> r = RemoteCallHandlerExecutor.executeRemoteCall(() -> fileService.generateResumptionPdf(data), ErrorMsgConstants.GENERATE_PDF_ERROR);
+//                if (null == r || null == r.getData()) {
+//                    throw new SystemException(ErrorMsgConstants.GENERATE_PDF_ERROR);
+//                }
+//               /* Long id = (Long) data.get("id");
+//                if (ObjectUtil.isNull(id)) {
+//                    throw new SystemException(ErrorMsgConstants.GENERATE_PDF_ERROR);
+//                }*/
+//                String pdfUrl = r.getData();
+//                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+//                String dateStr = sdf.format(date);
+//                LambdaQueryWrapper<CoreRegisterBookPdf> wrapper = new LambdaQueryWrapper<>();
+//                wrapper.eq(CoreRegisterBookPdf::getOrgId, orgId)
+//                        .eq(CoreRegisterBookPdf::getDate, dateStr)
+//                        .eq(CoreRegisterBookPdf::getRegisterBookType, RegisterBookType.getEnums((Integer) data.get("planType")).getNum())
+//                        .like(CoreRegisterBookPdf::getFileName, sysOrg.getName() + "_" + RegisterBookType.getEnums((Integer) data.get("planType")).getText() + "_");
+//                CoreRegisterBookPdf registerBookPdf = coreRegisterBookPdfMapper.selectOne(wrapper);
+//                if (ObjectUtil.isEmpty(registerBookPdf)) {
+//                    registerBookPdf = new CoreRegisterBookPdf();
+//                    registerBookPdf.setId(IdWorker.getId());
+//                    registerBookPdf.setRegisterBookType(RegisterBookType.getEnums((Integer) data.get("planType")).getNum());
+//                    registerBookPdf.setDate(date);
+//                    registerBookPdf.setOrgId(orgId);
+//                    registerBookPdf.setOrgName(sysOrg.getShortName());
+//                    registerBookPdf.setOrgPath(sysOrg.getPath());
+//                    registerBookPdf.setFileUrl(pdfUrl);
+//                    registerBookPdf.setFileName(data.get("fileName").toString());
+//                } else {
+//                    registerBookPdf.setFileUrl(pdfUrl);
+//                    registerBookPdf.setFileName(data.get("fileName").toString());
+//                }
+//
+//                if (StringUtils.isEmpty(registerBookPdf.getFileName()) || StringUtils.isEmpty(pdfUrl)) {
+//                    throw new SystemException(ErrorMsgConstants.GENERATE_PDF_ERROR);
+//                }
+//                registerBookPdfService.saveOrUpdate(registerBookPdf);
+//            }, threadPoolTaskExecutor);
+//        }
+
+
+    }
+
+    public void buildResumptionAllDayPdf(SysOrg sysOrg, Date date) {
         //110报警:4
         //电源:5
         final List<Map<String, Object>> mapList = this.getFtlResumptionAllDay(sysOrg, date);
@@ -1757,7 +1983,7 @@ public class AppPlanServiceImpl extends ServiceImpl<AppPlanMapper, AppPlan> impl
                 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                 String dateStr = sdf.format(date);
                 LambdaQueryWrapper<CoreRegisterBookPdf> wrapper = new LambdaQueryWrapper<>();
-                wrapper.eq(CoreRegisterBookPdf::getOrgId, orgId)
+                wrapper.eq(CoreRegisterBookPdf::getOrgId, sysOrg.getId())
                         .eq(CoreRegisterBookPdf::getDate, dateStr)
                         .eq(CoreRegisterBookPdf::getRegisterBookType, RegisterBookType.getEnums((Integer) data.get("planType")).getNum())
                         .like(CoreRegisterBookPdf::getFileName, sysOrg.getName() + "_" + RegisterBookType.getEnums((Integer) data.get("planType")).getText() + "_");
@@ -1767,7 +1993,7 @@ public class AppPlanServiceImpl extends ServiceImpl<AppPlanMapper, AppPlan> impl
                     registerBookPdf.setId(IdWorker.getId());
                     registerBookPdf.setRegisterBookType(RegisterBookType.getEnums((Integer) data.get("planType")).getNum());
                     registerBookPdf.setDate(date);
-                    registerBookPdf.setOrgId(orgId);
+                    registerBookPdf.setOrgId(sysOrg.getId());
                     registerBookPdf.setOrgName(sysOrg.getShortName());
                     registerBookPdf.setOrgPath(sysOrg.getPath());
                     registerBookPdf.setFileUrl(pdfUrl);
@@ -1783,8 +2009,6 @@ public class AppPlanServiceImpl extends ServiceImpl<AppPlanMapper, AppPlan> impl
                 registerBookPdfService.saveOrUpdate(registerBookPdf);
             }, threadPoolTaskExecutor);
         }
-
-
     }
 
     private List<Map<String, Object>> getFtlResumptionAllDay(SysOrg sysOrg, Date date) {

+ 19 - 0
soc-modules/soc-modules-core/src/main/resources/mapper/board/CockpitMapper.xml

@@ -19,6 +19,25 @@
         and org_path like concat(#{orgPath},'%')
         GROUP BY org_id,org_path
     </select>
+
+    <select id="statisticOneOrgResumptionTask" resultType="com.xunmei.core.board.vo.web.ResumptionTaskStatisticVo">
+        SELECT
+            org_id,
+            org_path,
+            count( 0 ) AS task_total,
+            SUM( CASE `status` WHEN 3 THEN 1 ELSE 0 END ) AS completed_count
+        FROM
+            core_resumption r
+            inner join core_resumption_plan p on r.plan_id=p.id and p.plan_cycle &lt; 5 and p.plan_exec in (2,3,4)
+        WHERE
+            (
+               #{startDate}    <![CDATA[<=]]> r.plan_end_time
+               and #{endDate} >= r.plan_end_time
+            )
+          and r.org_id = #{orgId}
+    </select>
+
+
     <!--    <select id="safetyCheck" resultType="com.xunmei.core.board.vo.web.TaskStatisticVo">-->
     <!--        SELECT-->
     <!--        org_id,-->

+ 9 - 0
soc-modules/soc-modules-job/src/main/java/com/xunmei/job/task/CoreResumptionTask.java

@@ -48,4 +48,13 @@ public class CoreResumptionTask {
         AjaxResult result = remoteResumptionTaskService.buildPdf();
         log.info("生成pdf,当前任务 时间:{},结果:{}", new Date(), JSON.toJSONString(result));
     }
+
+    /**
+     * 每天定时计算每个机构本年内的履职任务数量和完成数量,供驾驶舱使用
+     */
+    public void statisticTaskCount() {
+        log.info("开始统计机构履职任务数量 时间:{}", new Date());
+        R<Boolean> result = remoteResumptionTaskService.statisticTaskCount();
+        log.info("统计机构履职任务数量完成,当前任务 时间:{},结果:{}", new Date(), JSON.toJSONString(result));
+    }
 }

+ 5 - 1
soc-modules/soc-modules-system/pom.xml

@@ -113,7 +113,11 @@
             <groupId>com.xunmei</groupId>
             <artifactId>soc-common-websocket</artifactId>
         </dependency>
-
+        <dependency>
+            <groupId>org.apache.ant</groupId>
+            <artifactId>ant</artifactId>
+            <version>1.8.0</version>
+        </dependency>
     </dependencies>
 
     <build>

+ 15 - 0
soc-modules/soc-modules-system/src/main/java/com/xunmei/system/controller/ExportSqlController.java

@@ -1,5 +1,7 @@
 package com.xunmei.system.controller;
 
+import cn.hutool.core.date.DateUtil;
+import com.xunmei.common.core.constant.Constants;
 import com.xunmei.common.log.annotation.Log;
 import com.xunmei.common.log.enums.BusinessType;
 import com.xunmei.system.service.ExportSqlService;
@@ -12,6 +14,7 @@ import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
 import javax.servlet.http.HttpServletResponse;
+import java.util.Date;
 import java.util.List;
 
 @Slf4j
@@ -41,6 +44,18 @@ public class ExportSqlController {
         }
     }
 
+    @GetMapping("/table/filter/date/range")
+    public void exportDataBaseWithFilter(HttpServletResponse response,String tableName,String filterColumnName,String startDate,String endDate){
+        try {
+            //验证日期参数是否传入正常
+            Date start = DateUtil.parse(startDate, Constants.DAILY_FORMAT);
+            Date end = DateUtil.parse(endDate, Constants.DAILY_FORMAT);
+            exportSqlService.exportTableOneWithFilter(response,tableName,filterColumnName,DateUtil.format(start,Constants.DAILY_FORMAT),DateUtil.format(end,Constants.DAILY_FORMAT));
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
     @GetMapping("/tables")
     public void exportDataBase(HttpServletResponse response,@RequestParam List<String> tableNames){
         try {

+ 8 - 0
soc-modules/soc-modules-system/src/main/java/com/xunmei/system/service/ExportSqlService.java

@@ -1,6 +1,7 @@
 package com.xunmei.system.service;
 
 import javax.servlet.http.HttpServletResponse;
+import java.util.Date;
 import java.util.List;
 
 /**
@@ -22,6 +23,13 @@ public interface ExportSqlService {
     void exportTableOne(HttpServletResponse response,String tableName)throws Exception;
 
     /**
+     * 导出单表数据
+     * @param tableName
+     * @throws Exception
+     */
+    void exportTableOneWithFilter(HttpServletResponse response, String tableName, String filterColumnName, String startDate, String endDate)throws Exception;
+
+    /**
      * 导出多个表sql文件
      * @param tableNames
      * @throws Exception

+ 108 - 0
soc-modules/soc-modules-system/src/main/java/com/xunmei/system/service/impl/ExportSqlServiceImpl.java

@@ -1,21 +1,33 @@
 package com.xunmei.system.service.impl;
 
+import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.io.FileUtil;
+import com.xunmei.common.core.constant.Constants;
+import com.xunmei.common.core.domain.registerbook.vo.PdfToZipTempVo;
+import com.xunmei.common.core.utils.DateHelper;
 import com.xunmei.system.mapper.ObjectMapper;
 import com.xunmei.system.service.ExportSqlService;
 import com.xunmei.system.util.ExportDatabaseUtil;
 import com.xunmei.system.util.Sm4Util;
+import org.apache.tools.zip.ZipEntry;
+import org.apache.tools.zip.ZipOutputStream;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.boot.system.ApplicationHome;
 import org.springframework.stereotype.Service;
 
+import javax.servlet.ServletOutputStream;
 import javax.servlet.http.HttpServletResponse;
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.OutputStream;
 import java.net.URLEncoder;
+import java.util.Date;
 import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.CountDownLatch;
+import java.util.stream.Collectors;
 
 @Service
 public class ExportSqlServiceImpl implements ExportSqlService {
@@ -58,6 +70,22 @@ public class ExportSqlServiceImpl implements ExportSqlService {
     }
 
     @Override
+    public void exportTableOneWithFilter(HttpServletResponse response, String tableName, String filterColumnName, String startDate, String endDate) throws Exception {
+        ApplicationHome home = new ApplicationHome(getClass());
+        String path = home.getSource().getParent();
+        File file = new File(path,tableName+"_"+startDate +"_"+endDate+ ".sql");
+        if(file.exists()) {
+            file.delete();
+        }
+        //为方便处理日期边界问题 将结束日期加1天
+        Date end= DateUtil.parse(endDate);
+        String newEndDateStr =DateUtil.format(DateUtil.offsetDay(end, 1), Constants.DAILY_FORMAT);
+        ExportDatabaseUtil.exportTableSqlWithDateFilter(url,username,password,tableName,filterColumnName,startDate,newEndDateStr,file);
+        downloadCompressFile(response,file);
+    }
+
+
+    @Override
     public void exportTables(HttpServletResponse response, List<String> tableNames) throws Exception {
         ApplicationHome home = new ApplicationHome(getClass());
         String path = home.getSource().getParent();
@@ -119,4 +147,84 @@ public class ExportSqlServiceImpl implements ExportSqlService {
         }
     }
 
+        /**
+         * 导出数据
+         * @param response
+         * @param file
+         */
+        private void downloadCompressFile(HttpServletResponse response,File file){
+//        OutputStream os;//新建一个输出流对象
+            try {
+                response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(file.getName()+".zip", "UTF-8"));
+                response.setContentType("application/octet-stream");
+                ServletOutputStream outputStream = response.getOutputStream();
+                ZipOutputStream zos = new ZipOutputStream(outputStream);
+                zos.setEncoding("GBK");
+                FileInputStream fileInputStream = new FileInputStream(file);
+                zos.putNextEntry(new ZipEntry(file.getName()));
+                byte[] buffer = new byte[4096];
+                int len;
+                while ((len = fileInputStream.read(buffer)) > 0) {
+                    zos.write(buffer, 0, len);
+                }
+                zos.closeEntry();
+                fileInputStream.close();
+                zos.flush();
+                zos.close();
+                outputStream.close();
+            }catch (Exception e){
+                System.out.println("文件下载失败");
+            }finally {
+                if(file.exists()){
+                    file.delete();
+                }
+            }
+
+//        try {
+//            String zipName = URLEncoder.encode(pdfDto.getFileName() + DateHelper.getDateString(new Date()) + ".zip", "UTF-8");
+//            final CountDownLatch count = new CountDownLatch(registerBookPdfList.size());
+//            ServletOutputStream outputStream = response.getOutputStream();
+//            ZipOutputStream zos = new ZipOutputStream(outputStream);
+//            response.setContentType("application/octet-stream");
+//            response.setHeader("Content-Disposition", "attachment; filename=" + zipName);
+//            List<PdfToZipTempVo> pdfToZipTempVoList = registerBookPdfList.parallelStream().map(pdf -> {
+//                        return resolve(pdf, count);
+//                    }).filter(Objects::nonNull)
+//                    .collect(Collectors.toList());
+//            count.await();
+//            pdfToZipTempVoList.removeIf(pdfToZipTempVo -> !FileUtil.exist(pdfToZipTempVo.getFile()));
+//            log.info("登记簿全部下载完成,开始压缩文件,数量:{}", pdfToZipTempVoList.size());
+//            for (PdfToZipTempVo tempVo : pdfToZipTempVoList) {
+//                log.info("当前开始处理第{}个文件 ", pdfToZipTempVoList.indexOf(tempVo) + 1);
+//                deal(zos, tempVo);
+//            }
+//            zos.flush();
+//            zos.close();
+//            outputStream.close();
+//            log.info("登记簿批量导出压缩文件完成,文件数量:{}", pdfToZipTempVoList.size());
+//        } catch (Throwable e) {
+//            String errMsg = String.format("登记簿导出失败:%s", e);
+//            log.error(errMsg);
+//        } finally {
+//            final File temp = new File(TEMP_DIR_NAME);
+//            if (temp.exists()) {
+//                FileUtil.del(temp);
+//                log.info("临时目录已删除");
+//            }
+//        }
+    }
+
+    public void deal(ZipOutputStream zos, PdfToZipTempVo zipTempVo) throws Throwable {
+        zos.setEncoding("GBK");
+        FileInputStream fileInputStream = new FileInputStream(zipTempVo.getFile());
+        zos.putNextEntry(new ZipEntry(zipTempVo.getEntryName()));
+        byte[] buffer = new byte[4096];
+        int len;
+        while ((len = fileInputStream.read(buffer)) > 0) {
+            zos.write(buffer, 0, len);
+        }
+        zos.closeEntry();
+        fileInputStream.close();
+    }
+
 }

+ 164 - 0
soc-modules/soc-modules-system/src/main/java/com/xunmei/system/util/ExportDatabaseUtil.java

@@ -1,5 +1,7 @@
 package com.xunmei.system.util;
 
+import cn.hutool.core.date.DateUtil;
+import com.xunmei.common.core.constant.Constants;
 import com.xunmei.common.security.utils.SecurityUtils;
 
 import java.io.BufferedWriter;
@@ -8,6 +10,7 @@ import java.io.FileWriter;
 import java.io.IOException;
 import java.sql.*;
 import java.util.ArrayList;
+import java.util.Date;
 import java.util.List;
 
 public class ExportDatabaseUtil {
@@ -118,6 +121,61 @@ public class ExportDatabaseUtil {
     }
 
     /**
+     * 根据表名和过滤字段导出指定间范围内的数据 sql语句
+     * @param url
+     * @param username
+     * @param password
+     * @param tableName 表名
+     * @param filterColumnName 过滤字段名
+     * @param startDate 开始日期
+     * @param endDate 结束日期
+     * @param file
+     */
+    public static void exportTableSqlWithDateFilter(String url,String username,String password,String tableName,String filterColumnName,String startDate,String endDate, File file){
+        Connection conn = null;
+        Statement stmt = null;
+        ResultSet rs = null;
+
+        try {
+            // 建立与数据库的连接
+            conn = DriverManager.getConnection(url, username, password);
+
+            // 创建Statement对象
+            stmt = conn.createStatement();
+
+            FileWriter fw = new FileWriter(file, false);
+            BufferedWriter bw = new BufferedWriter(fw);
+
+            //写入table
+            writeTableWithDateFilter(stmt,rs,bw,tableName,filterColumnName,startDate,endDate);
+            bw.flush();
+            bw.close();
+            // 关闭资源
+            fw.close();
+
+            System.out.println("数据库已成功导出!");
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            // 关闭资源
+            try {
+                if (rs != null) {
+                    rs.close();
+                }
+                if (stmt != null) {
+                    stmt.close();
+                }
+                if (conn != null) {
+                    conn.close();
+                }
+            } catch (SQLException ex) {
+                ex.printStackTrace();
+            }
+        }
+    }
+
+
+    /**
      * 根据表名导出sql语句
      * @param url
      * @param username
@@ -224,6 +282,44 @@ public class ExportDatabaseUtil {
     }
 
     /**
+     * 导出指定表名sql
+     * @param stmt
+     * @param rs
+     * @param bw
+     * @param tableName
+     * @throws Exception
+     */
+    private static void writeTableWithDateFilter(Statement stmt,ResultSet rs,BufferedWriter bw,String tableName,String filterColumnName,String startDate,String endDate) throws Exception {
+
+        //写入文件头部
+        wirteHeader(bw);
+
+        //写入表格导出头部
+        writeTableHeader(bw,tableName);
+
+        //写入按时间范围删除数据语句
+        writeDeleteTableDataWithFilterSql(bw,tableName,filterColumnName,startDate,endDate);
+
+        Date start = DateUtil.parse(startDate);
+        Date end = DateUtil.parse(endDate);
+
+        // 数据量较大时一次查询全部数据很慢且内存也会爆炸,改为按天查
+        for (Date current = start; !current.after(end); current = DateUtil.offsetDay(current, 1)) {
+            Date currentEnd=DateUtil.offsetDay(current, 1);
+            if(currentEnd.after(end))
+            {
+                return;
+            }
+            writeTableDateFilterInsertSql(stmt, rs, bw, tableName, filterColumnName,
+                    DateUtil.format(current,  Constants.DAILY_FORMAT),
+                    DateUtil.format(currentEnd,  Constants.DAILY_FORMAT));
+        }
+
+        //写入插入语句
+//        writeTableDateFilterInsertSql(stmt,rs,bw,tableName,filterColumnName,startDate,endDate);
+    }
+
+    /**
      * 写入sql语句
      * @param tables 数据库所有表名
      * @param stmt Statement对象
@@ -314,6 +410,23 @@ public class ExportDatabaseUtil {
     }
 
     /**
+     * 写入按时间范围删除表数据SQL
+     * @param bw
+     * @param tableName
+     * @param filterColumnName
+     * @param startDate
+     * @param endDate
+     * @throws SQLException
+     * @throws IOException
+     */
+    private static void writeDeleteTableDataWithFilterSql(BufferedWriter bw,String tableName,String filterColumnName,String startDate,String endDate) throws SQLException, IOException {
+        //写入删除表数据语句
+        String dropTableDataSql =String.format("DELETE FROM %s WHERE `%s` >= '%s' AND `%s`< '%s' ;",tableName,filterColumnName,startDate,filterColumnName,endDate);
+        bw.write(dropTableDataSql);
+        bw.newLine();
+    }
+
+    /**
      * 写入insert语句
      * @param stmt Statement对象
      * @param rs ResultSet结果对象
@@ -358,6 +471,57 @@ public class ExportDatabaseUtil {
     }
 
     /**
+     * 按过滤条件写入insert语句
+     * @param stmt
+     * @param rs
+     * @param bw
+     * @param tableName
+     * @param filterColumnName
+     * @param startDate
+     * @param endDate
+     * @throws SQLException
+     * @throws IOException
+     */
+    private static void writeTableDateFilterInsertSql(Statement stmt,ResultSet rs,BufferedWriter bw,String tableName,String filterColumnName,String startDate,String endDate) throws SQLException, IOException {
+        String columnStr = getColumnStr(stmt, tableName);
+
+//        String selectSql = "SELECT "+ columnStr +" FROM `" + tableName + "`";
+        String selectSql =String.format("SELECT %s FROM `%s` WHERE `%s` >= '%s' AND `%s`< '%s' ;",columnStr,tableName,filterColumnName,startDate,filterColumnName,endDate);
+        // 生成INSERT INTO语句
+        rs = stmt.executeQuery(selectSql);
+
+
+        int columnCount = rs.getMetaData().getColumnCount();
+        while (rs.next()) {
+            StringBuilder insertIntoBuilder = new StringBuilder();
+            insertIntoBuilder.append("INSERT INTO " ).append(tableName).append(" (").append(columnStr).append(") ")
+                    .append(" VALUES (");
+
+            for (int i = 1; i <= columnCount; i++) {
+                int columnType = rs.getMetaData().getColumnType(i);
+                String value = rs.getString(i);
+                if (value == null) {
+                    insertIntoBuilder.append("NULL");
+                } else {
+                    String val = dealColumnType(columnType,value);
+                    insertIntoBuilder.append(val);
+                }
+                if (i < columnCount) {
+                    insertIntoBuilder.append(", ");
+                }
+            }
+
+            insertIntoBuilder.append(");");
+
+            System.out.println(insertIntoBuilder.toString());
+            // 写入输出流
+            bw.write(insertIntoBuilder.toString());
+            bw.newLine();
+        }
+    }
+
+
+    /**
      * 获取数据库的所有表名
      * @param stmt Statement对象
      * @param rs 查询结果对象