From 3a3393c31aca5c9a18fa127fa53f4997fa5e217f Mon Sep 17 00:00:00 2001
From: PoffyZhang <99775271@qq.com>
Date: Fri, 13 Oct 2023 16:16:19 +0800
Subject: [PATCH] =?UTF-8?q?=E9=A9=BE=E9=A9=B6=E8=88=B1=20=E7=BB=9F?=
 =?UTF-8?q?=E8=AE=A1=E9=80=BB=E8=BE=91=E6=8E=A5=E5=8F=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../dashboard/controller/DashboardController.java  |  11 +
 .../dashboard/manage/DashboardProjectManage.java   |   6 +-
 .../pmapi/dashboard/mapper/CockpitStatsMapper.java |   4 +
 .../pmapi/dashboard/mapper/CockpitStatsMapper.xml  |  31 ++
 .../dashboard/model/po/SecrecyPasswordGradePO.java |  42 +++
 .../dashboard/service/ICockpitStatsService.java    |   2 +
 .../service/impl/CockpitStatsServiceImpl.java      |   9 +
 .../scheduler/task/CockpitStatsStatisticsTask.java | 403 +++++++++++++++++++++
 .../projectCollection/ProjectCollectionTest.java   |   2 +-
 9 files changed, 506 insertions(+), 4 deletions(-)
 create mode 100644 pmapi/src/main/java/com/ningdatech/pmapi/dashboard/mapper/CockpitStatsMapper.xml
 create mode 100644 pmapi/src/main/java/com/ningdatech/pmapi/dashboard/model/po/SecrecyPasswordGradePO.java
 create mode 100644 pmapi/src/main/java/com/ningdatech/pmapi/scheduler/task/CockpitStatsStatisticsTask.java

diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/dashboard/controller/DashboardController.java b/pmapi/src/main/java/com/ningdatech/pmapi/dashboard/controller/DashboardController.java
index 3b8a91c..c49534b 100644
--- a/pmapi/src/main/java/com/ningdatech/pmapi/dashboard/controller/DashboardController.java
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/dashboard/controller/DashboardController.java
@@ -6,12 +6,14 @@ import com.ningdatech.pmapi.dashboard.manage.DashboardExpertManage;
 import com.ningdatech.pmapi.dashboard.manage.DashboardProjectManage;
 import com.ningdatech.pmapi.dashboard.model.po.QueryYearPO;
 import com.ningdatech.pmapi.dashboard.model.vo.*;
+import com.ningdatech.pmapi.scheduler.task.CockpitStatsStatisticsTask;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.RequiredArgsConstructor;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 import javax.validation.Valid;
+import java.net.UnknownHostException;
 
 /**
  * @author liuxinxin
@@ -30,6 +32,8 @@ public class DashboardController {
 
     private final CockpitStatsManage cockpitStatsManage;
 
+    private final CockpitStatsStatisticsTask cockpitStatsStatisticsTask;
+
     @PostMapping("/expert-summary")
     @ApiOperation("专家驾驶舱统计数据")
     @WebLog("专家驾驶舱统计数据")
@@ -70,4 +74,11 @@ public class DashboardController {
                                   @RequestParam(required = false) Integer year) {
         return cockpitStatsManage.getData(regionCode,year);
     }
+
+    @GetMapping("cockpit-stats-start")
+    @ApiOperation("驾驶舱-统计数据接口 强制运行任务")
+    public String statsStart() throws UnknownHostException {
+        cockpitStatsStatisticsTask.doTask();
+        return "运行成功";
+    }
 }
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/dashboard/manage/DashboardProjectManage.java b/pmapi/src/main/java/com/ningdatech/pmapi/dashboard/manage/DashboardProjectManage.java
index 72b57d0..db1a097 100644
--- a/pmapi/src/main/java/com/ningdatech/pmapi/dashboard/manage/DashboardProjectManage.java
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/dashboard/manage/DashboardProjectManage.java
@@ -377,13 +377,13 @@ public class DashboardProjectManage {
         String safetyInputDescribe = project.getSafetyInputDescribe();
         if(org.apache.commons.lang3.StringUtils.isNotBlank(safetyInputDescribe)){
             JSONArray array = JSON.parseArray(safetyInputDescribe);
-            final Integer[] total = {0};
+            final Double[] total = {0.0};
             array.forEach(j -> {
                 JSONObject json = JSON.parseObject(JSON.toJSONString(j));
-                Integer safetyInputAmount = json.getInteger(DashboardConstant.Protrait.FEILD_SAFETYMONEY);
+                Double safetyInputAmount = json.getDouble(DashboardConstant.Protrait.FEILD_SAFETYMONEY);
                 total[0] += safetyInputAmount;
             });
-            Integer totalAmount = total[0];
+            Double totalAmount = total[0];
             //申报金额
             BigDecimal declareAmount = project.getDeclareAmount();
             if(Objects.isNull(declareAmount) || declareAmount.compareTo(BigDecimal.ZERO) == 0){
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/dashboard/mapper/CockpitStatsMapper.java b/pmapi/src/main/java/com/ningdatech/pmapi/dashboard/mapper/CockpitStatsMapper.java
index acd821b..b468436 100644
--- a/pmapi/src/main/java/com/ningdatech/pmapi/dashboard/mapper/CockpitStatsMapper.java
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/dashboard/mapper/CockpitStatsMapper.java
@@ -2,6 +2,8 @@ package com.ningdatech.pmapi.dashboard.mapper;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.ningdatech.pmapi.dashboard.model.entity.CockpitStats;
+import com.ningdatech.pmapi.dashboard.model.po.SecrecyPasswordGradePO;
+import org.apache.ibatis.annotations.Param;
 
 /**
  * <p>
@@ -13,4 +15,6 @@ import com.ningdatech.pmapi.dashboard.model.entity.CockpitStats;
  */
 public interface CockpitStatsMapper extends BaseMapper<CockpitStats> {
 
+    SecrecyPasswordGradePO getSecrecyPasswordGrade(@Param("regionCode") String regionCode,
+                                                   @Param("year") Integer year);
 }
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/dashboard/mapper/CockpitStatsMapper.xml b/pmapi/src/main/java/com/ningdatech/pmapi/dashboard/mapper/CockpitStatsMapper.xml
new file mode 100644
index 0000000..a3e935d
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/dashboard/mapper/CockpitStatsMapper.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ningdatech.pmapi.dashboard.mapper.CockpitStatsMapper">
+    <select id="getSecrecyPasswordGrade" resultType="com.ningdatech.pmapi.dashboard.model.po.SecrecyPasswordGradePO">
+        SELECT
+            sum(CASE WHEN a.secrecy_grade = 1 THEN 1 ELSE 0 end) monitorSecrecyGrade1Num,
+            sum(CASE WHEN a.secrecy_grade = 2 THEN 1 ELSE 0 end) monitorSecrecyGrade2Num,
+            sum(CASE WHEN a.secrecy_grade = 3 THEN 1 ELSE 0 end) monitorSecrecyGrade3Num,
+            sum(CASE WHEN a.secrecy_grade = 4 THEN 1 ELSE 0 end) monitorSecrecyGrade4Num,
+            sum(CASE WHEN a.secrecy_grade = 5 THEN 1 ELSE 0 end) monitorSecrecyGrade5Num,
+            sum(CASE WHEN a.password_grade = 1 THEN 1 ELSE 0 end) monitorPasswordGrade1Num,
+            sum(CASE WHEN a.password_grade = 2 THEN 1 ELSE 0 end) monitorPasswordGrade2Num,
+            sum(CASE WHEN a.password_grade = 3 THEN 1 ELSE 0 end) monitorPasswordGrade3Num,
+            sum(CASE WHEN a.password_grade = 4 THEN 1 ELSE 0 end) monitorPasswordGrade4Num,
+            sum(CASE WHEN a.password_grade = 5 THEN 1 ELSE 0 end) monitorPasswordGrade5Num
+        FROM nd_project_application a
+                 LEFT JOIN nd_project p ON a."project_code" = p."project_code"  AND a."project_version"  = p.version
+        WHERE p."newest" = TRUE
+          <if test="regionCode != null and regionCode != 'TOTAL'">
+              AND p."area_code" =#{regionCode}
+          </if>
+          <choose>
+              <when test="year != null and year != 0">
+                  AND p.project_year =#{year}
+              </when>
+              <otherwise>
+                  AND p.project_year in (2021,2022,2023)
+              </otherwise>
+          </choose>
+    </select>
+</mapper>
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/dashboard/model/po/SecrecyPasswordGradePO.java b/pmapi/src/main/java/com/ningdatech/pmapi/dashboard/model/po/SecrecyPasswordGradePO.java
new file mode 100644
index 0000000..63df01d
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/dashboard/model/po/SecrecyPasswordGradePO.java
@@ -0,0 +1,42 @@
+package com.ningdatech.pmapi.dashboard.model.po;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import java.io.Serializable;
+
+@Data
+@ApiModel(value = "等保密评PO", description = "")
+public class SecrecyPasswordGradePO implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty("项目监控-等保1级数量")
+    private Integer monitorSecrecyGrade1Num;
+
+    @ApiModelProperty("项目监控-等保2级数量")
+    private Integer monitorSecrecyGrade2Num;
+
+    @ApiModelProperty("项目监控-等保3级数量")
+    private Integer monitorSecrecyGrade3Num;
+
+    @ApiModelProperty("项目监控-等保4级数量")
+    private Integer monitorSecrecyGrade4Num;
+
+    @ApiModelProperty("项目监控-等保5级数量")
+    private Integer monitorSecrecyGrade5Num;
+
+    @ApiModelProperty("项目监控-密评1级数量")
+    private Integer monitorPasswordGrade1Num;
+
+    @ApiModelProperty("项目监控-密评2级数量")
+    private Integer monitorPasswordGrade2Num;
+
+    @ApiModelProperty("项目监控-密评3级数量")
+    private Integer monitorPasswordGrade3Num;
+
+    @ApiModelProperty("项目监控-密评4级数量")
+    private Integer monitorPasswordGrade4Num;
+
+    @ApiModelProperty("项目监控-密评5级数量")
+    private Integer monitorPasswordGrade5Num;
+}
\ No newline at end of file
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/dashboard/service/ICockpitStatsService.java b/pmapi/src/main/java/com/ningdatech/pmapi/dashboard/service/ICockpitStatsService.java
index 578848b..bd75fd8 100644
--- a/pmapi/src/main/java/com/ningdatech/pmapi/dashboard/service/ICockpitStatsService.java
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/dashboard/service/ICockpitStatsService.java
@@ -2,6 +2,7 @@ package com.ningdatech.pmapi.dashboard.service;
 
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.ningdatech.pmapi.dashboard.model.entity.CockpitStats;
+import com.ningdatech.pmapi.dashboard.model.po.SecrecyPasswordGradePO;
 
 /**
  * <p>
@@ -13,4 +14,5 @@ import com.ningdatech.pmapi.dashboard.model.entity.CockpitStats;
  */
 public interface ICockpitStatsService extends IService<CockpitStats> {
 
+    SecrecyPasswordGradePO getSecrecyPasswordGrade(String regionCode,Integer year);
 }
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/dashboard/service/impl/CockpitStatsServiceImpl.java b/pmapi/src/main/java/com/ningdatech/pmapi/dashboard/service/impl/CockpitStatsServiceImpl.java
index 05f9806..af59d07 100644
--- a/pmapi/src/main/java/com/ningdatech/pmapi/dashboard/service/impl/CockpitStatsServiceImpl.java
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/dashboard/service/impl/CockpitStatsServiceImpl.java
@@ -3,7 +3,9 @@ package com.ningdatech.pmapi.dashboard.service.impl;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.ningdatech.pmapi.dashboard.mapper.CockpitStatsMapper;
 import com.ningdatech.pmapi.dashboard.model.entity.CockpitStats;
+import com.ningdatech.pmapi.dashboard.model.po.SecrecyPasswordGradePO;
 import com.ningdatech.pmapi.dashboard.service.ICockpitStatsService;
+import lombok.RequiredArgsConstructor;
 import org.springframework.stereotype.Service;
 
 /**
@@ -15,7 +17,14 @@ import org.springframework.stereotype.Service;
  * @since 2023-02-05
  */
 @Service
+@RequiredArgsConstructor
 public class CockpitStatsServiceImpl extends ServiceImpl<CockpitStatsMapper, CockpitStats>
         implements ICockpitStatsService {
 
+    private final CockpitStatsMapper cockpitStatsMapper;
+
+    @Override
+    public SecrecyPasswordGradePO getSecrecyPasswordGrade(String regionCode, Integer year) {
+        return cockpitStatsMapper.getSecrecyPasswordGrade(regionCode,year);
+    }
 }
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/scheduler/task/CockpitStatsStatisticsTask.java b/pmapi/src/main/java/com/ningdatech/pmapi/scheduler/task/CockpitStatsStatisticsTask.java
new file mode 100644
index 0000000..445a9e5
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/scheduler/task/CockpitStatsStatisticsTask.java
@@ -0,0 +1,403 @@
+package com.ningdatech.pmapi.scheduler.task;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.date.StopWatch;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.google.common.collect.Lists;
+import com.ningdatech.pmapi.common.constant.BizConst;
+import com.ningdatech.pmapi.common.constant.RegionConst;
+import com.ningdatech.pmapi.common.helper.RegionCacheHelper;
+import com.ningdatech.pmapi.dashboard.constant.DashboardConstant;
+import com.ningdatech.pmapi.dashboard.model.entity.CockpitStats;
+import com.ningdatech.pmapi.dashboard.model.po.SecrecyPasswordGradePO;
+import com.ningdatech.pmapi.dashboard.service.ICockpitStatsService;
+import com.ningdatech.pmapi.expert.entity.ExpertUserFullInfo;
+import com.ningdatech.pmapi.expert.service.IExpertUserFullInfoService;
+import com.ningdatech.pmapi.performance.model.entity.PerformanceAppraisalProject;
+import com.ningdatech.pmapi.performance.service.IPerformanceAppraisalProjectService;
+import com.ningdatech.pmapi.projectlib.enumeration.ProjectStatusEnum;
+import com.ningdatech.pmapi.projectlib.model.entity.Project;
+import com.ningdatech.pmapi.projectlib.service.IProjectService;
+import com.ningdatech.pmapi.sys.model.dto.RegionDTO;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+import java.math.BigDecimal;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.time.LocalDateTime;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/**
+ * @author ZPF
+ * @Class CockpitStatsStatisticsTask
+ * 驾驶舱 统计 每日任务
+ * @since 2023/08/31 18:16
+ */
+@Component
+@Slf4j
+@RequiredArgsConstructor
+public class CockpitStatsStatisticsTask {
+
+    @Value("${hostname}")
+    public String HOST;
+
+    @Value("${spring.profiles.active}")
+    public String active;
+
+    @Autowired
+    private ICockpitStatsService cockpitStatsService;
+
+    @Autowired
+    private RegionCacheHelper regionCacheHelper;
+
+    @Autowired
+    private IProjectService projectService;
+
+    @Autowired
+    private IExpertUserFullInfoService expertUserFullInfoService;
+
+    @Autowired
+    private IPerformanceAppraisalProjectService performanceAppraisalProjectService;
+
+
+    /**
+     * 前置机每天晚上10点自动清空,第二天早上6点获取数据
+     * 定时同步前置机数据 每天1点开始执行一次
+     *
+     */
+    @Scheduled(cron = "0 0 3 * * ?")
+    public void doTask() throws UnknownHostException {
+        if (!HOST.equals(InetAddress.getLocalHost().getHostName())) {
+            log.info("定时器没开启或者host不对! {}:{}",
+                    HOST,InetAddress.getLocalHost().getHostName());
+            return;
+        }
+        if(BizConst.PRE.equals(active)){
+            log.info("预发环境不用同步!");
+            return;
+        }
+
+        log.info("驾驶舱数据统计任务开始=====");
+
+        StopWatch stopWatch = new StopWatch();
+        stopWatch.start();
+
+        List<Integer> years = Lists.newArrayList(2021,2022,2023,2024);
+
+        List<CockpitStats> res = Lists.newArrayList();
+        //1.根据2个维度来统计 区域和分年
+        //1.总的
+        res.add(statisticsData(DashboardConstant.CockpitStats.TOTAL,
+                DashboardConstant.CockpitStats.TOTAL,0));
+        for(Integer year : years){
+            res.add(statisticsData(DashboardConstant.CockpitStats.TOTAL,
+                    DashboardConstant.CockpitStats.TOTAL,year));
+        }
+
+        List<RegionDTO> regions = regionCacheHelper.listChildren(RegionConst.RC_LS, RegionConst.RL_COUNTY);
+
+        for(RegionDTO regionDto :  regions){
+            res.add(statisticsData(regionDto.getRegionCode(),regionDto.getRegionName(),0));
+            for(Integer year : years){
+                res.add(statisticsData(regionDto.getRegionCode(),regionDto.getRegionName(),year));
+            }
+        }
+
+        //如果结果不为空 就删除之前的 插入最新的数据
+        if(CollUtil.isEmpty(res)){
+            if(cockpitStatsService.remove(Wrappers.lambdaQuery(CockpitStats.class))){
+                cockpitStatsService.saveBatch(res);
+            }
+        }
+
+        stopWatch.stop();
+        log.info("驾驶舱数据统计任务结束====={}s",stopWatch.getTotalTimeSeconds());
+    }
+
+    /**
+     * 统计的具体逻辑
+     * @param regionCode
+     * @param regionName
+     * @param year
+     * @return
+     */
+    private CockpitStats statisticsData(String regionCode, String regionName, Integer year) {
+        CockpitStats cockpitStats = new CockpitStats();
+        cockpitStats.setRegionCode(regionCode);
+        cockpitStats.setRegionName(regionName);
+        cockpitStats.setYear(year);
+
+        List<Project> projects = projectService.list(Wrappers.lambdaQuery(Project.class)
+                .eq(Project::getNewest, Boolean.TRUE)
+                .eq(StringUtils.isNotBlank(regionCode) && !DashboardConstant.CockpitStats.TOTAL.equals(regionCode),
+                        Project::getAreaCode, regionCode)
+                .eq(Objects.nonNull(year) && !year.equals(DashboardConstant.CockpitStats.NONE_YEAR),
+                        Project::getProjectYear, year)
+                .in(Objects.isNull(year) && year.equals(DashboardConstant.CockpitStats.NONE_YEAR),
+                        Project::getProjectYear, Lists.newArrayList(2021,2022,2023,2024)));
+        //1.项目监测
+        //1.1 超期在建项目
+        Integer overdueConstructionProjectsNum = projects.stream().filter(p -> {
+            if(Objects.nonNull(p.getPlanAcceptanceTime()) && p.getPlanAcceptanceTime().compareTo(LocalDateTime.now()) < 0){
+                return Boolean.TRUE;
+            }
+            return Boolean.FALSE;
+        }).collect(Collectors.toList()).size();
+        cockpitStats.setMonitorOverdueConstructionProjectsNum(overdueConstructionProjectsNum);
+        //1.2 环节滞后项目
+        cockpitStats.setMonitorLaggingProjectsNum(0);
+        //1.3预审驳回项目
+        Integer preFailed = projects.stream().filter(p -> {
+            if(Objects.nonNull(p.getStatus()) && p.getStatus().equals(ProjectStatusEnum.PREQUALIFICATION_FAILED.getCode())){
+                return Boolean.TRUE;
+            }
+            return Boolean.FALSE;
+        }).collect(Collectors.toList()).size();
+        cockpitStats.setMonitorRejectedPreReviewProjectsNum(preFailed);
+        //1.4 建设方案评审失败
+        Integer constructionFailed = projects.stream().filter(p -> {
+            if(Objects.nonNull(p.getStatus()) && p.getStatus().equals(ProjectStatusEnum.SCHEME_REVIEW_FAILED.getCode())){
+                return Boolean.TRUE;
+            }
+            return Boolean.FALSE;
+        }).collect(Collectors.toList()).size();
+        cockpitStats.setMonitorRejectedApproveProjectsNum(constructionFailed);
+        //1.5 验收不达标
+        cockpitStats.setMonitorAcceptConditionsNotStandardsNum(0);
+        //1.6 总申报金额
+        Double totalDeclaredAmount = projects.stream().mapToDouble(p -> Objects.nonNull(p.getDeclareAmount()) ? p.getDeclareAmount().doubleValue() : 0.0).sum();
+        cockpitStats.setMonitorDeclaredAmount(BigDecimal.valueOf(totalDeclaredAmount));
+        //1.7 总安全投入
+        Double totalSafytyAmount = projects.stream().mapToDouble(p -> {
+            if(Objects.nonNull(p.getSafetyInputDescribe())){
+                final Double[] total = {0.0};
+                JSONArray array = JSON.parseArray(p.getSafetyInputDescribe());
+                array.forEach(j -> {
+                    JSONObject json = JSON.parseObject(JSON.toJSONString(j));
+                    Double safetyInputAmount = json.getDouble(DashboardConstant.Protrait.FEILD_SAFETYMONEY);
+                    total[0] += safetyInputAmount;
+                });
+                return total[0];
+            }
+            return 0.0;
+        }).sum();
+        cockpitStats.setMonitorSafetyInputAmount(BigDecimal.valueOf(totalSafytyAmount));
+
+        //1.8等保密评
+        SecrecyPasswordGradePO secrecyPasswordGradePo = cockpitStatsService.getSecrecyPasswordGrade(regionCode, year);
+        cockpitStats.setMonitorSecrecyGrade1Num(secrecyPasswordGradePo.getMonitorSecrecyGrade1Num());
+        cockpitStats.setMonitorSecrecyGrade2Num(secrecyPasswordGradePo.getMonitorSecrecyGrade2Num());
+        cockpitStats.setMonitorSecrecyGrade3Num(secrecyPasswordGradePo.getMonitorSecrecyGrade3Num());
+        cockpitStats.setMonitorSecrecyGrade4Num(secrecyPasswordGradePo.getMonitorSecrecyGrade4Num());
+        cockpitStats.setMonitorSecrecyGrade5Num(secrecyPasswordGradePo.getMonitorSecrecyGrade5Num());
+        cockpitStats.setMonitorPasswordGrade1Num(secrecyPasswordGradePo.getMonitorPasswordGrade1Num());
+        cockpitStats.setMonitorPasswordGrade2Num(secrecyPasswordGradePo.getMonitorPasswordGrade2Num());
+        cockpitStats.setMonitorPasswordGrade3Num(secrecyPasswordGradePo.getMonitorPasswordGrade3Num());
+        cockpitStats.setMonitorPasswordGrade4Num(secrecyPasswordGradePo.getMonitorPasswordGrade4Num());
+        cockpitStats.setMonitorPasswordGrade5Num(secrecyPasswordGradePo.getMonitorPasswordGrade5Num());
+
+        //2.专家统计
+        List<ExpertUserFullInfo> experts = expertUserFullInfoService.list(Wrappers.lambdaQuery(ExpertUserFullInfo.class)
+                .eq(StringUtils.isNotBlank(regionCode) && !DashboardConstant.CockpitStats.TOTAL.equals(regionCode),
+                        ExpertUserFullInfo::getRegionCode, regionCode));
+        cockpitStats.setExpertTotalNum(experts.size());
+        cockpitStats.setExpertFinancialNum(0);
+        cockpitStats.setExpertNetworkSecurityNum(0);
+        cockpitStats.setExpertXinchuangNum(0);
+        cockpitStats.setExpertPlanRationalityNum(0);
+        cockpitStats.setExpertPromotionInfoTechnologyNum(0);
+        cockpitStats.setExpertPartyGovInfoNum(0);
+        cockpitStats.setExpertSoftHardPricingNum(0);
+        cockpitStats.setExpertTechnicalFeasibilityAssessmentNum(0);
+
+        //3.顶部数据
+        //3.1 计划项目数(通过单位内部审核的项目)
+        Integer planProjectNum = projects.stream().filter(p -> {
+            if(Objects.nonNull(p.getStatus()) && p.getStatus().compareTo(ProjectStatusEnum.PENDING_PREQUALIFICATION.getCode()) >= 0){
+                return Boolean.TRUE;
+            }
+            return Boolean.FALSE;
+        }).collect(Collectors.toList()).size();
+        cockpitStats.setTopPlanProjectsNum(planProjectNum);
+        //3.2 批复项目数(可以用批复金额来判断)
+        Integer approvalNum = projects.stream().filter(p -> {
+            if(Objects.nonNull(p.getApprovalAmount())){
+                return Boolean.TRUE;
+            }
+            return Boolean.FALSE;
+        }).collect(Collectors.toList()).size();
+        Double approvalAmount = projects.stream().filter(p -> {
+            if(Objects.nonNull(p.getApprovalAmount())){
+                return Boolean.TRUE;
+            }
+            return Boolean.FALSE;
+        }).mapToDouble(p -> p.getApprovalAmount().doubleValue()).sum();
+        cockpitStats.setTopApprovalProjectsNum(approvalNum);
+        cockpitStats.setTopApprovalProjectsAmount(BigDecimal.valueOf(approvalAmount));
+        //3.3 平均建设周期
+        Double average = projects.stream().mapToInt(p -> {
+            if (StringUtils.isNotBlank(p.getBuildCycle())) {
+                try {
+                    Integer buildCycle = Integer.valueOf(p.getBuildCycle());
+                    return buildCycle;
+                } catch (Exception e) {
+                    return 0;
+                }
+            }
+            return 0;
+        }).average().getAsDouble();
+        cockpitStats.setTopAverageConstructionPeriod(average.intValue());
+        //3.4 在建项目数 采购备案后的项目
+        Integer contructionNum = projects.stream().filter(p -> {
+            if(Objects.nonNull(p.getStatus()) && p.getStatus().compareTo(ProjectStatusEnum.UNDER_CONSTRUCTION.getCode()) >= 0){
+                return Boolean.TRUE;
+            }
+            return Boolean.FALSE;
+        }).collect(Collectors.toList()).size();
+        cockpitStats.setTopOngoingProjectsNum(contructionNum);
+        //4.地图 只要放总数 取的时候 会有逻辑
+        cockpitStats.setProjectsTotal(projects.size());
+
+        //5.下面项目状态数
+        //5.1 处于计划 (单位内部)
+        Integer inPlanNum = projects.stream().filter(p -> {
+            if(Objects.nonNull(p.getStatus()) && p.getStatus().equals(ProjectStatusEnum.UNDER_INTERNAL_AUDIT.getCode())){
+                return Boolean.TRUE;
+            }
+            return Boolean.FALSE;
+        }).collect(Collectors.toList()).size();
+        cockpitStats.setProjectsTotalPlan(inPlanNum);
+        //5.2 处于申报 (预审)
+        Integer inApplyNum = projects.stream().filter(p -> {
+            if(Objects.nonNull(p.getStatus()) && p.getStatus().equals(ProjectStatusEnum.PRE_APPLYING.getCode())){
+                return Boolean.TRUE;
+            }
+            return Boolean.FALSE;
+        }).collect(Collectors.toList()).size();
+        //5.3 处于审批 (建设方案)
+        Integer inApproveNum = projects.stream().filter(p -> {
+            if(Objects.nonNull(p.getStatus()) && p.getStatus().equals(ProjectStatusEnum.SCHEME_UNDER_REVIEW.getCode())){
+                return Boolean.TRUE;
+            }
+            return Boolean.FALSE;
+        }).collect(Collectors.toList()).size();
+        cockpitStats.setProjectsTotalApprove(inApproveNum);
+        //5.4 建设 (建设中)
+        Integer inContructionNum = projects.stream().filter(p -> {
+            if(Objects.nonNull(p.getStatus()) &&
+                    p.getStatus().equals(ProjectStatusEnum.UNDER_CONSTRUCTION.getCode())){
+                return Boolean.TRUE;
+            }
+            return Boolean.FALSE;
+        }).collect(Collectors.toList()).size();
+        cockpitStats.setProjectsTotalConstruction(inContructionNum);
+        //5.5 验收 和 绩效 可以一起查
+        List<Project> inAccpetProjects = projects.stream().filter(p -> {
+            if(Objects.nonNull(p.getStatus()) &&
+                    p.getStatus().equals(ProjectStatusEnum.ACCEPTED.getCode())){
+                return Boolean.TRUE;
+            }
+            return Boolean.FALSE;
+        }).collect(Collectors.toList());
+        List<String> inAccpetCodes = inAccpetProjects.stream().map(Project::getProjectCode).collect(Collectors.toList());
+        List<PerformanceAppraisalProject> performances = performanceAppraisalProjectService.list(Wrappers.lambdaQuery(PerformanceAppraisalProject.class)
+                .in(PerformanceAppraisalProject::getProjectCode, inAccpetCodes)
+                .isNotNull(PerformanceAppraisalProject::getVerifyTotalScore));
+        cockpitStats.setProjectsTotalAccept(inAccpetProjects.size() - performances.size());
+        cockpitStats.setProjectsTotalPerformance(performances.size());
+        cockpitStats.setProjectsTotalLogOff(0);
+        cockpitStats.setProjectsTotalOperation(0);
+
+        //6.项目效益
+        cockpitStats.setExcellentBestAppNum(0);
+        cockpitStats.setExcellentMajorAppNum(0);
+        cockpitStats.setExcellentCrossLevelSharingNum(0);
+        cockpitStats.setExcellentMajorAppNum(0);
+
+        //7 核减资金
+        Double reduceFundsTotal = projects.stream().mapToDouble(p -> {
+            if(Objects.nonNull(p.getApprovalAmount()) && Objects.nonNull(p.getDeclareAmount())){
+                if(Objects.nonNull(p.getContractAmount())){
+                    return (p.getDeclareAmount().subtract(p.getContractAmount())).doubleValue();
+                }else{
+                    return (p.getDeclareAmount().subtract(p.getApprovalAmount())).doubleValue();
+                }
+            }
+            return 0.0;
+        }).sum();
+        cockpitStats.setReduceFundsTotal(BigDecimal.valueOf(reduceFundsTotal));
+        //7.2驳回节约资金
+        List<Project> rejectPreProjects = projects.stream().filter(p -> {
+            if (Objects.nonNull(p.getStatus()) && p.getStatus().equals(ProjectStatusEnum.PREQUALIFICATION_FAILED.getCode())) {
+                return Boolean.TRUE;
+            }
+            return Boolean.FALSE;
+        }).collect(Collectors.toList());
+        Double rejectPreSum = rejectPreProjects.stream().mapToDouble(p -> {
+            if (Objects.nonNull(p.getDeclareAmount())) {
+                return p.getDeclareAmount().doubleValue();
+            }
+            return 0.0;
+        }).sum();
+        cockpitStats.setRejectSavingsFunds(BigDecimal.valueOf(rejectPreSum));
+        //7.3 柱状图
+        //7.3.1 申报状态的3个资金
+//        projects.stream()
+        cockpitStats.setApprovalAmountApproval(BigDecimal.ZERO);
+        cockpitStats.setApprovalAmountApprove(BigDecimal.ZERO);
+        cockpitStats.setApprovalAmountContract(BigDecimal.ZERO);
+        cockpitStats.setDeclaredAmountApproval(BigDecimal.ZERO);
+        cockpitStats.setDeclaredAmountApprove(BigDecimal.ZERO);
+        cockpitStats.setDeclaredAmountContract(BigDecimal.ZERO);
+        cockpitStats.setDifferenceApproval(BigDecimal.ZERO);
+        cockpitStats.setDifferenceApprove(BigDecimal.ZERO);
+        cockpitStats.setDifferenceContract(BigDecimal.ZERO);
+
+        //8 产出数据
+        cockpitStats.setProduceAppNum(0);
+        cockpitStats.setProduceDataNum(0);
+        cockpitStats.setProduceComponentNum(0);
+        cockpitStats.setProduceBrainElementsNum(0);
+
+        //9.绩效
+        List<String> projectCodes = projects.stream().map(Project::getProjectCode).collect(Collectors.toList());
+        Map<String, String> projectMap = projects.stream().collect(Collectors.toMap(Project::getProjectCode, Project::getProjectName));
+        List<PerformanceAppraisalProject> performanceAll = performanceAppraisalProjectService.list(Wrappers.lambdaQuery(PerformanceAppraisalProject.class)
+                .in(PerformanceAppraisalProject::getProjectCode, projectCodes));
+        List<PerformanceAppraisalProject> verified = performanceAll.stream().filter(p -> {
+            if (Objects.nonNull(p.getVerifyTotalScore())) {
+                return Boolean.TRUE;
+            }
+            return Boolean.FALSE;
+        }).sorted(Comparator.comparing(PerformanceAppraisalProject::getVerifyTotalScore).reversed())
+                .collect(Collectors.toList());
+        cockpitStats.setPerformanceTotal(performanceAll.size());
+        cockpitStats.setPerformanceReviewedTotal(verified.size());
+        cockpitStats.setPerformanceTobeReviewTotal(performanceAll.size() - verified.size());
+
+        cockpitStats.setPerformanceTop1Name(projectMap.get(verified.get(0).getProjectCode()));
+        cockpitStats.setPerformanceTop1Score(verified.get(0).getVerifyTotalScore());
+        cockpitStats.setPerformanceTop2Name(verified.get(1).getProjectCode());
+        cockpitStats.setPerformanceTop2Score(verified.get(1).getVerifyTotalScore());
+        cockpitStats.setPerformanceTop3Name(verified.get(2).getProjectCode());
+        cockpitStats.setPerformanceTop3Score(verified.get(2).getVerifyTotalScore());
+        cockpitStats.setPerformanceTop4Name(verified.get(3).getProjectCode());
+        cockpitStats.setPerformanceTop4Score(verified.get(3).getVerifyTotalScore());
+        cockpitStats.setPerformanceTop5Name(verified.get(4).getProjectCode());
+        cockpitStats.setPerformanceTop5Score(verified.get(4).getVerifyTotalScore());
+
+        return cockpitStats;
+    }
+}
diff --git a/pmapi/src/test/java/com/ningdatech/pmapi/projectCollection/ProjectCollectionTest.java b/pmapi/src/test/java/com/ningdatech/pmapi/projectCollection/ProjectCollectionTest.java
index bc06602..a811d1d 100644
--- a/pmapi/src/test/java/com/ningdatech/pmapi/projectCollection/ProjectCollectionTest.java
+++ b/pmapi/src/test/java/com/ningdatech/pmapi/projectCollection/ProjectCollectionTest.java
@@ -75,7 +75,7 @@ public class ProjectCollectionTest extends AppTests {
 
     @Test
     public void test(){
-        List<String> baseProjIds = Lists.newArrayList("33110000020220100244");
+        List<String> baseProjIds = Lists.newArrayList("33110000020230100021");
         for(String baseProjId : baseProjIds){
             GovBizProjectBaseinfo baseinfo = baseinfoService.getOne(Wrappers.lambdaQuery(GovBizProjectBaseinfo.class)
                     .eq(GovBizProjectBaseinfo::getBaseProjId, baseProjId)