Browse Source

增加统计分析

tags/24080901
WendyYang 10 months ago
parent
commit
a179482251
8 changed files with 883 additions and 4 deletions
  1. +88
    -0
      hz-pm-api/src/main/java/com/hz/pm/api/dashboard/controller/StatisticsController.java
  2. +164
    -0
      hz-pm-api/src/main/java/com/hz/pm/api/dashboard/manage/DashboardExpertManage.java
  3. +345
    -0
      hz-pm-api/src/main/java/com/hz/pm/api/dashboard/manage/ExpertStatisticsManage.java
  4. +201
    -0
      hz-pm-api/src/main/java/com/hz/pm/api/dashboard/manage/MeetingStatisticsManage.java
  5. +24
    -0
      hz-pm-api/src/main/java/com/hz/pm/api/dashboard/manage/ProjectStatisticsManage.java
  6. +54
    -0
      hz-pm-api/src/main/java/com/hz/pm/api/dashboard/model/vo/ProjectStatisticsVO.java
  7. +4
    -1
      hz-pm-api/src/main/java/com/hz/pm/api/fiscal/entity/CompanyFiscalCode.java
  8. +3
    -3
      hz-pm-api/src/main/java/com/hz/pm/api/user/manage/UserInfoManage.java

+ 88
- 0
hz-pm-api/src/main/java/com/hz/pm/api/dashboard/controller/StatisticsController.java View File

@@ -0,0 +1,88 @@
package com.hz.pm.api.dashboard.controller;

import com.hz.pm.api.dashboard.manage.*;
import com.hz.pm.api.dashboard.model.vo.*;
import com.ningdatech.log.annotation.DataScopeQueryCheck;
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.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
* @author ZPF
* @date 2023/11/25 上午10:36
*/
@RestController
@RequestMapping("/api/v1/statistics")
@Validated
@RequiredArgsConstructor
@Api(value = "StatisticsController", tags = "统计")
public class StatisticsController {

private final FundStatisticsManage fundStatisticsManage;

private final ExpertStatisticsManage expertStatisticsManage;

private final MeetingStatisticsManage meetingStatisticsManage;

private final ProjectCostStatisticsManage costStatisticsManage;

private final EarlyWarningStatisticsManage earlyWarningStatisticsManage;

private final PerformanceStatisticsManage performanceStatisticsManage;

private final ProjectStatisticsManage projectStatisticsManage;

@DataScopeQueryCheck
@GetMapping("/fund")
@ApiOperation("项目资金统计")
public FundStatisticsVO fund(@RequestParam(required = false) Integer year) {
return fundStatisticsManage.statistics(year);
}

@DataScopeQueryCheck
@GetMapping("/expert")
@ApiOperation("专家统计")
public ExpertStatisticsVO expert(@RequestParam(required = false) Integer year) {
return expertStatisticsManage.statistics(year);
}

@DataScopeQueryCheck
@GetMapping("/meeting")
@ApiOperation("评审会议统计")
public MeetingStatisticsVO meeting(@RequestParam(required = false) Integer year) {
return meetingStatisticsManage.statistics(year);
}

@DataScopeQueryCheck
@GetMapping("/project-cost")
@ApiOperation("项目成本统计")
public CostStatisticsVO projectCost() {
return costStatisticsManage.statistics();
}

@DataScopeQueryCheck
@GetMapping("/early-warning")
@ApiOperation("预警统计")
public EarlyWarningStatisticsVO earlyWarning(@RequestParam(required = false) Integer year) {
return earlyWarningStatisticsManage.statistics(year);
}

@DataScopeQueryCheck
@GetMapping("/performance")
@ApiOperation("绩效统计")
public PerformanceStatisticsVO performance(@RequestParam(required = false) Integer year) {
return performanceStatisticsManage.statistics(year);
}

@DataScopeQueryCheck
@GetMapping("/project")
@ApiOperation("项目统计")
public ProjectStatisticsVO project(@RequestParam(required = false) Integer year) {
return projectStatisticsManage.statistics(year);
}
}

+ 164
- 0
hz-pm-api/src/main/java/com/hz/pm/api/dashboard/manage/DashboardExpertManage.java View File

@@ -0,0 +1,164 @@
package com.hz.pm.api.dashboard.manage;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.hz.pm.api.dashboard.constant.ChartTypeEnum;
import com.hz.pm.api.dashboard.helper.DashboardChartAssembler;
import com.hz.pm.api.dashboard.helper.DashboardHelper;
import com.hz.pm.api.dashboard.model.basic.AnalysisChart;
import com.hz.pm.api.dashboard.model.basic.AnalysisData;
import com.hz.pm.api.dashboard.model.basic.StarExpertBO;
import com.hz.pm.api.dashboard.model.po.QueryYearPO;
import com.hz.pm.api.dashboard.model.vo.ExpertDashboardSummaryVO;
import com.hz.pm.api.expert.constant.ExpertUserInfoStepEnum;
import com.hz.pm.api.expert.entity.ExpertUserFullInfo;
import com.hz.pm.api.expert.service.IExpertUserFullInfoService;
import com.hz.pm.api.meeting.entity.domain.Meeting;
import com.hz.pm.api.meeting.entity.domain.MeetingExpertJudge;
import com.hz.pm.api.meeting.entity.enumeration.MeetingStatusEnum;
import com.hz.pm.api.meeting.service.IMeetingExpertJudgeService;
import com.hz.pm.api.meeting.service.IMeetingService;
import com.hz.pm.api.meta.constant.ExpertDictTypeEnum;
import com.hz.pm.api.meta.model.entity.ExpertDictionary;
import com.hz.pm.api.meta.service.IExpertDictionaryService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
* @author liuxinxin
* @date 2023/8/2 上午10:39
*/

@Component
@RequiredArgsConstructor
public class DashboardExpertManage {

private final DashboardHelper dashboardHelper;
private final IExpertUserFullInfoService iExpertUserFullInfoService;
private final IMeetingService iMeetingService;
private final IMeetingExpertJudgeService iMeetingExpertJudgeService;
private final IExpertDictionaryService iExpertDictionaryService;
private final DashboardChartAssembler dashboardChartAssembler;


public ExpertDashboardSummaryVO getExpertDashboardSummary(QueryYearPO queryYearPO) {
String queryRegionCode = queryYearPO.getRegionCode();
List<AnalysisChart> analysisChartList = new ArrayList<>();

// 获取丽水区域 code name Map
Map<String, String> liShuiRegionCodeNameMap = dashboardHelper.getLiShuiRegionCodeNameMap();
// 获取库内所有的专家列表
List<ExpertUserFullInfo> evidenceHasBeenSubmittedExpertInfoList = iExpertUserFullInfoService.list();

// 专家regionCode分组map列表
Map<String, List<ExpertUserFullInfo>> regionCodeExpertMap = Collections.emptyMap();

// 各区域专家数量
AnalysisChart regionExpertNumberChartAnalysisChart = new AnalysisChart();
List<AnalysisData> regionExpertNumberChartDataList = new ArrayList<>();
regionExpertNumberChartAnalysisChart.setChartType(ChartTypeEnum.REGION_EXPERT_NUMBER_CHART);
regionExpertNumberChartAnalysisChart.setDataList(regionExpertNumberChartDataList);
for (String regionCode : liShuiRegionCodeNameMap.keySet()) {
AnalysisData analysisData = new AnalysisData();
String regionName = liShuiRegionCodeNameMap.get(regionCode);
List<ExpertUserFullInfo> expertUserFullInfoList = regionCodeExpertMap.get(regionCode);
int expertCnt = 0;
if (CollectionUtil.isNotEmpty(expertUserFullInfoList)) {
expertCnt = expertUserFullInfoList.size();
}
analysisData.setKey(regionName);
analysisData.setValue(expertCnt);
regionExpertNumberChartDataList.add(analysisData);
}
analysisChartList.add(regionExpertNumberChartAnalysisChart);

// 查询区域的专家id 列表
List<Long> regionDegreeExpertIdList = new ArrayList<>();
if (StringUtils.isNotBlank(queryRegionCode)) {
List<ExpertUserFullInfo> expertUserFullInfoList = regionCodeExpertMap.get(queryRegionCode);
if (CollectionUtil.isNotEmpty(expertUserFullInfoList)) {
regionDegreeExpertIdList = expertUserFullInfoList.stream()
.map(ExpertUserFullInfo::getUserId)
.collect(Collectors.toList());
}
} else {
regionDegreeExpertIdList = evidenceHasBeenSubmittedExpertInfoList.stream()
.map(ExpertUserFullInfo::getUserId)
.collect(Collectors.toList());
}

if (CollectionUtil.isNotEmpty(regionDegreeExpertIdList)) {
// 区域学历分布
List<ExpertDictionary> degreeExpertDictionaryList = iExpertDictionaryService
.listByUserId(regionDegreeExpertIdList, ExpertDictTypeEnum.DEGREE);
Map<String, List<String>> degreeCodeMap = degreeExpertDictionaryList.stream()
.map(ExpertDictionary::getDictionaryCode)
.collect(Collectors.groupingBy(Function.identity()));
AnalysisChart regionExpertEducationChartAnalysisChart =
dashboardChartAssembler.assemblerAnalysisChart(degreeCodeMap, ChartTypeEnum.REGION_EXPERT_EDUCATION_CHART);
analysisChartList.add(regionExpertEducationChartAnalysisChart);

// 区域职称级别分布
List<ExpertDictionary> titleLevelExpertDictionaryList = iExpertDictionaryService
.listByUserId(regionDegreeExpertIdList, ExpertDictTypeEnum.TITLE_LEVEL);
Map<String, List<ExpertDictionary>> titleLevelCodeMap = titleLevelExpertDictionaryList.stream()
.collect(Collectors.groupingBy(ExpertDictionary::getDictionaryCode));
AnalysisChart regionExpertTitleLevelChartAnalysisChart =
dashboardChartAssembler.assemblerAnalysisChart(titleLevelCodeMap, ChartTypeEnum.REGION_EXPERT_TITLE_LEVEL_CHART);
analysisChartList.add(regionExpertTitleLevelChartAnalysisChart);
}

// 评审次数
List<Meeting> normalMeetingList = iMeetingService.list(Wrappers.lambdaQuery(Meeting.class)
.ne(Meeting::getStatus, MeetingStatusEnum.CANCELED.getCode()));
Integer meetingCnt = normalMeetingList.size();

// 各类型评审次数
Map<String, List<Meeting>> meetingTypeMap = normalMeetingList.stream().collect(Collectors.groupingBy(Meeting::getType));
AnalysisChart meetingTypeCntChartAnalysisChart =
dashboardChartAssembler.assemblerAnalysisChart(meetingTypeMap, ChartTypeEnum.MEETING_TYPE_CNT_CHART);
analysisChartList.add(meetingTypeCntChartAnalysisChart);

// 明星专家列表
List<StarExpertBO> starExpertList = new ArrayList<>();
List<MeetingExpertJudge> meetingExpertJudgeList = iMeetingExpertJudgeService.list();
Map<Long, List<MeetingExpertJudge>> expertIdMeetingExpertJudgeMap = meetingExpertJudgeList.stream()
.collect(Collectors.groupingBy(MeetingExpertJudge::getExpertId));
Map<Long, String> expertIdExpertNameMap = evidenceHasBeenSubmittedExpertInfoList.stream()
.collect(Collectors.toMap(ExpertUserFullInfo::getUserId, ExpertUserFullInfo::getExpertName));

for (Long expertId : expertIdMeetingExpertJudgeMap.keySet()) {
String expertName = expertIdExpertNameMap.get(expertId);
List<MeetingExpertJudge> expertMeetingExpertJudgeList = expertIdMeetingExpertJudgeMap.get(expertId);
DoubleSummaryStatistics statistics = expertMeetingExpertJudgeList
.stream().filter(r -> Objects.nonNull(r.getScore()))
.map(MeetingExpertJudge::getScore).mapToDouble(Number::doubleValue).summaryStatistics();
double average = statistics.getAverage();
StarExpertBO starExpertBO = new StarExpertBO();
starExpertBO.setAveragePerformanceScore(average);
starExpertBO.setExpertId(expertId);
starExpertBO.setExpertName(expertName);
starExpertList.add(starExpertBO);
}
starExpertList = starExpertList.stream()
.sorted(Comparator.comparing(StarExpertBO::getAveragePerformanceScore)
.reversed()).collect(Collectors.toList());
if (starExpertList.size() > 5) {
starExpertList = starExpertList.subList(0, 5);
}

// 装配返回类
ExpertDashboardSummaryVO expertDashboardSummaryVO = new ExpertDashboardSummaryVO();
expertDashboardSummaryVO.setMeetingCnt(meetingCnt);
expertDashboardSummaryVO.setStarExpertList(starExpertList);
expertDashboardSummaryVO.setAnalysisChartList(analysisChartList);
return expertDashboardSummaryVO;
}

}


+ 345
- 0
hz-pm-api/src/main/java/com/hz/pm/api/dashboard/manage/ExpertStatisticsManage.java View File

@@ -0,0 +1,345 @@
package com.hz.pm.api.dashboard.manage;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.hz.pm.api.common.helper.RegionCacheHelper;
import com.hz.pm.api.common.model.constant.RegionConst;
import com.hz.pm.api.common.model.entity.DataDTO;
import com.hz.pm.api.dashboard.constant.DashboardConstant;
import com.hz.pm.api.dashboard.model.vo.ExpertStatisticsVO;
import com.hz.pm.api.expert.entity.ExpertIntentionWorkRegion;
import com.hz.pm.api.expert.entity.ExpertUserFullInfo;
import com.hz.pm.api.expert.service.IExpertIntentionWorkRegionService;
import com.hz.pm.api.expert.service.IExpertUserFullInfoService;
import com.hz.pm.api.meta.model.dto.DictionaryDTO;
import com.hz.pm.api.meta.model.dto.TagDTO;
import com.hz.pm.api.meta.model.entity.ExpertDictionary;
import com.hz.pm.api.meta.model.entity.ExpertTag;
import com.hz.pm.api.meta.service.IExpertDictionaryService;
import com.hz.pm.api.meta.service.IExpertTagService;
import com.hz.pm.api.meta.service.IMetaDictionaryService;
import com.hz.pm.api.meta.service.IMetaTagService;
import com.hz.pm.api.sys.model.dto.RegionDTO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ForkJoinPool;
import java.util.stream.Collectors;

/**
* @Classname ExpertStatisticsManage
* @Description
* @Date 2023/12/04 17:44
* @Author PoffyZhang
*/
@Component
@RequiredArgsConstructor
@Slf4j
public class ExpertStatisticsManage {

private final RegionCacheHelper regionCacheHelper;

private final IExpertUserFullInfoService userFullInfoService;

private final IExpertIntentionWorkRegionService expertIntentionWorkRegionService;

private final IExpertTagService expertTagService;

private final IMetaTagService metaTagService;

private final IExpertDictionaryService expertDictionaryService;

private final IMetaDictionaryService metaDictionaryService;

private Integer[] years = new Integer[]{LocalDateTime.now().getYear() - 2,
LocalDateTime.now().getYear() - 1, LocalDateTime.now().getYear(),
LocalDateTime.now().getYear() + 1, LocalDateTime.now().getYear() + 2};

private Integer[] threeYears = new Integer[]{LocalDateTime.now().getYear() - 2,
LocalDateTime.now().getYear() - 1, LocalDateTime.now().getYear()};

private String[] SHENGWEIDU = new String[]{DashboardConstant.Expert.NETWORK_CODE,
DashboardConstant.Expert.DANGZHENG_CODE, DashboardConstant.Expert.FANGAN_CODE,
DashboardConstant.Expert.JISHU_CODE, DashboardConstant.Expert.XINCHUANG_CODE,
DashboardConstant.Expert.RUANYING_CODE};

private String[] SHIWEIDU = new String[]{DashboardConstant.Expert.CAIWU_CODE,
DashboardConstant.Expert.XINXIHUA_CODE, DashboardConstant.Expert.XINCHUANG_OTTHER_CODE};

private String[] TYPES = new String[]{DashboardConstant.Expert.EXPERT_TYPE_INNER,
DashboardConstant.Expert.EXPERT_TYPE_OUT};

private String[] LEVELS = new String[]{DashboardConstant.Expert.EXPERT_LEVEL_ZHENGGAO,
DashboardConstant.Expert.EXPERT_LEVEL_FUGAO, DashboardConstant.Expert.EXPERT_LEVEL_MID,
DashboardConstant.Expert.EXPERT_LEVEL_CHUJI, DashboardConstant.Expert.EXPERT_LEVEL_NULL};

/**
* 专家统计
*
* @param year
* @return
*/
public ExpertStatisticsVO statistics(Integer year) {
List<ExpertUserFullInfo> experts = userFullInfoService.list();
List<ExpertIntentionWorkRegion> intentionWorkRegions = expertIntentionWorkRegionService.list();

List<ExpertTag> expertTags = expertTagService.list();

List<TagDTO> tags = metaTagService.queryAll();

List<DictionaryDTO> dictionaries = metaDictionaryService.queryAll();
Set<String> code = Sets.newHashSet();
Map<String, String> dictionMap = dictionaries.stream().filter(d -> code.add(d.getDictionaryCode()))
.collect(Collectors.toMap(DictionaryDTO::getDictionaryCode, DictionaryDTO::getName));

List<ExpertDictionary> expertDictionaries = expertDictionaryService.list(Wrappers.lambdaQuery(ExpertDictionary.class)
.eq(ExpertDictionary::getExpertInfoField, DashboardConstant.Expert.EXPERT_TYPE));

ExpertStatisticsVO res = new ExpertStatisticsVO();
CompletableFuture.allOf(
CompletableFuture.runAsync(() -> {
//选择的年份去计算的数据
yearCompleteExpert(res, year, experts, intentionWorkRegions, expertTags,
tags, expertDictionaries, dictionMap);
}, ForkJoinPool.commonPool()),
CompletableFuture.runAsync(() -> {
//近三年
threeYearsCompleteExpert(res, experts);
}, ForkJoinPool.commonPool()),
CompletableFuture.runAsync(() -> {
//近一年
lastYearsCompleteExpert(res, experts);
}, ForkJoinPool.commonPool())
).join();

return res;
}

/**
* 近一年
*
* @param res
*/
private void lastYearsCompleteExpert(ExpertStatisticsVO res, List<ExpertUserFullInfo> experts) {
List<ExpertUserFullInfo> lastYear = experts.stream().filter(expert -> {
if (expert.getCreateOn().compareTo(LocalDateTime.now().plusYears(-1)) >= 0 &&
expert.getCreateOn().compareTo(LocalDateTime.now()) <= 0) {
return Boolean.TRUE;
}
return Boolean.FALSE;
}).collect(Collectors.toList());
res.setThisYearAdded(lastYear.size());
}

/**
* 近三年
*
* @param res
*/
private void threeYearsCompleteExpert(ExpertStatisticsVO res, List<ExpertUserFullInfo> experts) {
List<DataDTO> threeYearsAdds = Lists.newArrayList();
for (Integer year : threeYears) {
threeYearsAdds.add(DataDTO.of(year.toString(), year.toString(),
experts.stream().filter(e -> {
if (Objects.nonNull(e.getCreateOn()) && year.equals(e.getCreateOn().getYear())) {
return Boolean.TRUE;
}
return Boolean.FALSE;
}).collect(Collectors.toList()).size()));
}
res.setThreeYearsAdded(threeYearsAdds);
}

/**
* 选择年份或者全部
*
* @param res
* @param year
*/
private void yearCompleteExpert(ExpertStatisticsVO res, Integer year,
List<ExpertUserFullInfo> experts, List<ExpertIntentionWorkRegion> intentionWorkRegions,
List<ExpertTag> expertTags, List<TagDTO> tags, List<ExpertDictionary> expertDictionaries,
Map<String, String> dictionMap) {
res.setTotal(experts.size());

Set<Long> userSet = Sets.newHashSet();
Map<Long, ExpertUserFullInfo> expertMap = experts.stream().filter(e -> userSet.add(e.getUserId()))
.collect(Collectors.toMap(ExpertUserFullInfo::getUserId, e -> e));

List<RegionDTO> regions = regionCacheHelper.listChildren(RegionConst.RC_LS, RegionConst.RL_CITY)
.stream().filter(r -> r.getRegionLevel().equals(RegionConst.RL_COUNTY))
.sorted(Comparator.comparing(RegionDTO::getRegionCode)).collect(Collectors.toList());

//是否要筛选年
experts = experts.stream().filter(e -> {
if (Objects.nonNull(e.getCreateOn()) &&
(Objects.isNull(year) || year.equals(e.getCreateOn().getYear()))) {
return Boolean.TRUE;
}
return Boolean.FALSE;
}).collect(Collectors.toList());

//计算区域专家
computeRegionExperts(res, intentionWorkRegions, expertMap, regions);

//计算专家特长
computeRegionDistribution(res, experts, expertTags, tags);

//计算专家类型
computeTypes(res, experts, expertDictionaries, dictionMap);

//计算专家等级
computeLevels(res, experts, expertDictionaries, dictionMap);
}

/**
* 计算 专家等级
*
* @param res
* @param experts
*/
private void computeLevels(ExpertStatisticsVO res, List<ExpertUserFullInfo> experts,
List<ExpertDictionary> expertDictionaries, Map<String, String> dictionMap) {
List<DataDTO> levels = Lists.newArrayList();

Set<Long> userSets = Sets.newHashSet();
Map<Long, ExpertUserFullInfo> expertUserFullInfoMap = experts.stream()
.filter(u -> userSets.add(u.getUserId()))
.collect(Collectors.toMap(ExpertUserFullInfo::getUserId, e -> e));

Map<String, List<ExpertDictionary>> dictionaryMap = expertDictionaries.stream()
.collect(Collectors.groupingBy(ExpertDictionary::getDictionaryCode));
for (String levelCode : LEVELS) {
int num = 0;
if (dictionaryMap.containsKey(levelCode)) {
List<ExpertDictionary> dictionaries = dictionaryMap.get(levelCode);
num = dictionaries.stream().filter(d -> {
if (expertUserFullInfoMap.containsKey(d.getUserId())) {
return Boolean.TRUE;
}
return Boolean.FALSE;
}).collect(Collectors.toList()).size();
}
levels.add(DataDTO.of(dictionMap.get(levelCode), levelCode, num));
}

res.setLevels(levels);
}

/**
* 计算 专家类型
*
* @param res
* @param experts
*/
private void computeTypes(ExpertStatisticsVO res, List<ExpertUserFullInfo> experts,
List<ExpertDictionary> expertDictionaries, Map<String, String> dictionMap) {
List<DataDTO> types = Lists.newArrayList();

Set<Long> userSets = Sets.newHashSet();
Map<Long, ExpertUserFullInfo> expertUserFullInfoMap = experts.stream()
.filter(u -> userSets.add(u.getUserId()))
.collect(Collectors.toMap(ExpertUserFullInfo::getUserId, e -> e));

Map<String, List<ExpertDictionary>> dictionaryMap = expertDictionaries.stream()
.collect(Collectors.groupingBy(ExpertDictionary::getDictionaryCode));
for (String typeCode : TYPES) {
int num = 0;
if (dictionaryMap.containsKey(typeCode)) {
List<ExpertDictionary> dictionaries = dictionaryMap.get(typeCode);
num = dictionaries.stream().filter(d -> {
if (expertUserFullInfoMap.containsKey(d.getUserId())) {
return Boolean.TRUE;
}
return Boolean.FALSE;
}).collect(Collectors.toList()).size();
}
types.add(DataDTO.of(dictionMap.get(typeCode), typeCode, num));
}

res.setTypes(types);
}

//计算专家特长
private void computeRegionDistribution(ExpertStatisticsVO res, List<ExpertUserFullInfo> experts,
List<ExpertTag> expertTags, List<TagDTO> tags) {
Set<Long> userSets = Sets.newHashSet();
Map<Long, ExpertUserFullInfo> expertUserFullInfoMap = experts.stream()
.filter(u -> userSets.add(u.getUserId()))
.collect(Collectors.toMap(ExpertUserFullInfo::getUserId, e -> e));

Map<String, List<DataDTO>> typeDistribution = Maps.newHashMap();

Map<String, List<ExpertTag>> tagsMap =
expertTags.stream().filter(e -> Objects.nonNull(e.getTagCode()))
.collect(Collectors.groupingBy(ExpertTag::getTagCode));

Set<String> tagSets = Sets.newHashSet();
Map<String, String> tagNameMap = tags.stream().filter(t -> tagSets.add(t.getTagCode()))
.collect(Collectors.toMap(TagDTO::getTagCode, TagDTO::getTagName));

//1.省维度
List<DataDTO> shengWeidu = Lists.newArrayList();
for (String code : SHENGWEIDU) {
shengWeidu.add(getExpertData(expertUserFullInfoMap,
tagsMap, tagNameMap, code));
}

//2.市维度
List<DataDTO> shiWeidu = Lists.newArrayList();
for (String code : SHIWEIDU) {
shiWeidu.add(getExpertData(expertUserFullInfoMap,
tagsMap, tagNameMap, code));
}

typeDistribution.put(DashboardConstant.Expert.DISTRIBUTION_SHENG, shengWeidu);
typeDistribution.put(DashboardConstant.Expert.DISTRIBUTION_SHI, shiWeidu);
res.setTypeDistribution(typeDistribution);
}

/**
* 包装
*
* @param expertUserFullInfoMap
* @param tagsMap
* @param tagNameMap
* @param code
* @return
*/
private static DataDTO getExpertData(Map<Long, ExpertUserFullInfo> expertUserFullInfoMap, Map<String, List<ExpertTag>> tagsMap, Map<String, String> tagNameMap, String code) {
int num = 0;
if (tagsMap.containsKey(code)) {
List<ExpertTag> ets = tagsMap.get(code);
num = ets.stream().filter(e -> {
if (expertUserFullInfoMap.containsKey(e.getUserId())) {
return Boolean.TRUE;
}
return Boolean.FALSE;
}).collect(Collectors.toList()).size();
}
return DataDTO.of(tagNameMap.get(code), code, num);
}

//计算区域专家
private static void computeRegionExperts(ExpertStatisticsVO res, List<ExpertIntentionWorkRegion> intentionWorkRegions, Map<Long, ExpertUserFullInfo> expertMap, List<RegionDTO> regions) {
List<DataDTO> regionExpert = Lists.newArrayList();
for (RegionDTO region : regions) {
regionExpert.add(DataDTO.of(region.getRegionName(), region.getRegionCode(),
intentionWorkRegions.stream().filter(w -> {
if (Objects.nonNull(w) && Objects.nonNull(w.getRegionCode()) &&
w.getRegionCode().equals(region.getRegionCode()) &&
expertMap.containsKey(w.getUserId())) {
return Boolean.TRUE;
}
return Boolean.FALSE;
}).collect(Collectors.toList()).size()));
}
res.setRegionExpert(regionExpert);
}
}

+ 201
- 0
hz-pm-api/src/main/java/com/hz/pm/api/dashboard/manage/MeetingStatisticsManage.java View File

@@ -0,0 +1,201 @@
package com.hz.pm.api.dashboard.manage;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import com.hz.pm.api.common.helper.RegionCacheHelper;
import com.hz.pm.api.common.model.constant.RegionConst;
import com.hz.pm.api.common.model.entity.DataDTO;
import com.hz.pm.api.dashboard.model.vo.MeetingStatisticsVO;
import com.hz.pm.api.ding.constants.DingOrganizationContant;
import com.hz.pm.api.expert.constant.ReviewResultEnum;
import com.hz.pm.api.expert.model.entity.ExpertReview;
import com.hz.pm.api.expert.model.enumeration.ReviewTemplateTypeEnum;
import com.hz.pm.api.expert.service.IExpertReviewService;
import com.hz.pm.api.meeting.entity.domain.Meeting;
import com.hz.pm.api.meeting.service.IMeetingService;
import com.hz.pm.api.organization.model.entity.DingOrganization;
import com.hz.pm.api.organization.service.IDingOrganizationService;
import com.hz.pm.api.projectlib.model.entity.Project;
import com.hz.pm.api.projectlib.service.IProjectService;
import com.hz.pm.api.sys.model.dto.RegionDTO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
* @Classname MeetingStatisticsManage
* @Description
* @Date 2023/12/05 17:44
* @Author PoffyZhang
*/
@Component
@RequiredArgsConstructor
@Slf4j
public class MeetingStatisticsManage {

private final IMeetingService meetingService;

private final IExpertReviewService expertReviewService;

private final RegionCacheHelper regionCacheHelper;

private final IDingOrganizationService dingOrganizationService;

private final IProjectService projectService;

public MeetingStatisticsVO statistics(Integer year) {
MeetingStatisticsVO res = new MeetingStatisticsVO();
List<Meeting> meetings = meetingService.list(Wrappers.lambdaQuery(Meeting.class));
//查出 年份的 会议数据
meetings = meetings.stream().filter(m -> {
if(Objects.nonNull(m.getStartTime()) &&
(Objects.isNull(year) || year.equals(m.getStartTime().getYear()))){
return Boolean.TRUE;
}
return Boolean.FALSE;
}).collect(Collectors.toList());
List<Long> meetingIds = meetings.stream().map(Meeting::getId)
.collect(Collectors.toList());

//会议总数
res.setMeetingTotal(meetings.size());

//评审数
List<ExpertReview> expertReviews = Lists.newArrayList();
Integer reviewsTotal = 0;
if(CollUtil.isNotEmpty(meetingIds)){
expertReviews = expertReviewService.list(Wrappers.lambdaQuery(ExpertReview.class)
.eq(ExpertReview::getIsFinal, Boolean.TRUE)
.in(ExpertReview::getMeetingId,meetingIds));
reviewsTotal = expertReviews.size();
}
//通过的评审
List<ExpertReview> passExpertReviews = expertReviews.stream()
.filter(r -> Objects.nonNull(r.getReviewResult()) &&
r.getReviewResult().equals(ReviewResultEnum.PASSED.getCode()))
.collect(Collectors.toList());
//不通过的评审
List<ExpertReview> notpassExpertReviews = expertReviews.stream()
.filter(r -> Objects.nonNull(r.getReviewResult()) &&
r.getReviewResult().equals(ReviewResultEnum.REFUSED.getCode()))
.collect(Collectors.toList());
res.setPassReview(passExpertReviews.size());
res.setNotPassRate(reviewsTotal.compareTo(0) == 0 ? BigDecimal.ZERO :
BigDecimal.valueOf(notpassExpertReviews.size()).multiply(BigDecimal.valueOf(100)
.divide(BigDecimal.valueOf(reviewsTotal), RoundingMode.HALF_UP)));

//各区域
List<RegionDTO> regions = regionCacheHelper.listChildren(RegionConst.RC_LS, RegionConst.RL_CITY)
.stream().filter(r -> r.getRegionLevel().equals(RegionConst.RL_COUNTY))
.sorted(Comparator.comparing(RegionDTO::getRegionCode)).collect(Collectors.toList());
List<DataDTO> regionMeetngs = Lists.newArrayList();
for(RegionDTO region : regions){
regionMeetngs.add(DataDTO.of(region.getRegionName(),region.getRegionCode(),meetings.stream().filter(m -> {

return Boolean.FALSE;
}).collect(Collectors.toList()).size()));
}
res.setRegionMeetings(regionMeetngs);

//预审 验收 会议
List<DataDTO> meetingTypes = Lists.newArrayList();
meetingTypes.add(DataDTO.of("预审会议", ReviewTemplateTypeEnum.PRELIMINARY_SCHEME_REVIEW.getCode().toString(),
meetings.stream().filter(m -> {
if(StringUtils.isNotBlank(m.getType()) &&
m.getType().equals(ReviewTemplateTypeEnum.PRELIMINARY_SCHEME_REVIEW.getCode()
.toString())){
return Boolean.TRUE;
}
return Boolean.FALSE;
}).collect(Collectors.toList()).size()));
Long yanshouCount = meetings.stream().filter(m -> {
if (StringUtils.isNotBlank(m.getType()) &&
m.getType().equals(ReviewTemplateTypeEnum.ACCEPTANCE_SCHEME_REVIEW.getCode()
.toString())) {
return Boolean.TRUE;
}
return Boolean.FALSE;
}).count();
meetingTypes.add(DataDTO.of("验收会议",ReviewTemplateTypeEnum.ACCEPTANCE_SCHEME_REVIEW.getCode().toString(),
yanshouCount.intValue()));
res.setMeetingTypes(meetingTypes);

//各区县评审 不通过率
List<DataDTO> regionNotpassReview = Lists.newArrayList();
for(RegionDTO region : regions){
DataDTO data = new DataDTO();
data.setCode(region.getRegionCode());
data.setName(region.getRegionName());
//先求出 此区域会议
List<Long> regionMeetingIds = meetings.stream().filter(m -> {

return Boolean.FALSE;
}).map(Meeting::getId).collect(Collectors.toList());

List<ExpertReview> regionReviews = expertReviews.stream().filter(r -> {
if (Objects.nonNull(r.getMeetingId()) &&
regionMeetingIds.contains(r.getMeetingId())) {
return Boolean.TRUE;
}
return Boolean.FALSE;
}).collect(Collectors.toList());
long regionNotpass = regionReviews.stream().filter(r -> Objects.nonNull(r.getReviewResult()) &&
r.getReviewResult().equals(ReviewResultEnum.REFUSED.getCode()))
.count();

data.setRate(CollUtil.isEmpty(regionReviews) ? BigDecimal.ZERO :
BigDecimal.valueOf(regionNotpass).multiply(BigDecimal.valueOf(100))
.divide(BigDecimal.valueOf(regionReviews.size()),BigDecimal.ROUND_CEILING,RoundingMode.HALF_UP));

regionNotpassReview.add(data);
}
res.setNotPassRegionMeetings(regionNotpassReview);

//各部门 不通过项目TOP10
List<DingOrganization> organizations = dingOrganizationService.list(Wrappers.lambdaQuery(DingOrganization.class)
.in(DingOrganization::getTypeCode, Lists.newArrayList(DingOrganizationContant.UNIT_TYPE,
DingOrganizationContant.GOV_TEMPORARY)));
List<Project> projects = projectService.list(Wrappers.lambdaQuery(Project.class)
.eq(Project::getNewest, Boolean.TRUE));

//TOP10
List<ExpertReview> finalExpertReviews = expertReviews;
List<DataDTO> notpassTop10 = organizations.stream()
.map(o -> {
DataDTO data = new DataDTO();
data.setCode(o.getOrganizationCode());
data.setName(o.getOrganizationName());
List<Project> orgProjects = projects.stream().filter(p -> Objects.nonNull(p.getBuildOrgCode()) &&
p.getBuildOrgCode().equals(o.getOrganizationCode()))
.collect(Collectors.toList());
List<String> projectCodes = orgProjects.stream().map(Project::getProjectCode)
.collect(Collectors.toList());
if(CollUtil.isEmpty(projectCodes)){
return data;
}
List<ExpertReview> reviews = finalExpertReviews.stream().filter(r -> Objects.nonNull(r.getProjectCode()) &&
projectCodes.contains(r.getProjectCode())).collect(Collectors.toList());
long orgNotpass = reviews.stream().filter(r -> Objects.nonNull(r.getReviewResult()) &&
r.getReviewResult().equals(ReviewResultEnum.REFUSED.getCode()))
.count();
data.setRate(CollUtil.isEmpty(reviews) ? BigDecimal.ZERO :
BigDecimal.valueOf(orgNotpass).multiply(BigDecimal.valueOf(100))
.divide(BigDecimal.valueOf(reviews.size()),BigDecimal.ROUND_CEILING,RoundingMode.HALF_UP));
return data;
})
.filter(d -> Objects.nonNull(d.getRate()))
.sorted(Comparator.comparing(DataDTO::getRate).reversed())
.limit(10).collect(Collectors.toList());
res.setNotPassTop10(notpassTop10);
return res;
}
}

+ 24
- 0
hz-pm-api/src/main/java/com/hz/pm/api/dashboard/manage/ProjectStatisticsManage.java View File

@@ -0,0 +1,24 @@
package com.hz.pm.api.dashboard.manage;

import com.hz.pm.api.dashboard.model.vo.ProjectStatisticsVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/**
* @Classname ProjectStatisticsManage
* @Description
* @Date 2023/12/05 17:44
* @Author PoffyZhang
*/
@Component
@RequiredArgsConstructor
@Slf4j
public class ProjectStatisticsManage {

public ProjectStatisticsVO statistics(Integer year) {
ProjectStatisticsVO res = new ProjectStatisticsVO();

return res;
}
}

+ 54
- 0
hz-pm-api/src/main/java/com/hz/pm/api/dashboard/model/vo/ProjectStatisticsVO.java View File

@@ -0,0 +1,54 @@
package com.hz.pm.api.dashboard.model.vo;

import com.hz.pm.api.common.model.entity.DataDTO;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.io.Serializable;
import java.util.List;

@Data
@ApiModel(value = "项目统计")
public class ProjectStatisticsVO implements Serializable {
private static final long serialVersionUID = 1L;

@ApiModelProperty("项目计划数")
private Integer planTotal = 0;

@ApiModelProperty("批复项目数")
private Integer approvedTotal = 0;

@ApiModelProperty("在建项目数")
private Integer constructionTotal = 0;

@ApiModelProperty("平均批复周期(月)")
private Integer approvalCycleAvg = 0;

@ApiModelProperty("平均建设周期(月)")
private Integer constructionCycleAvg = 0;

@ApiModelProperty("各阶段项目统计")
private List<DataDTO> progresses;

@ApiModelProperty("近三年平均批复周期")
private List<DataDTO> threeYearsApprovalCycleAvg;

@ApiModelProperty("近三年平均建设周期")
private List<DataDTO> threeYearsConstructionCycleAvg;

@ApiModelProperty("项目分布类型")
private List<DataDTO> projectTypeDistribution;

@ApiModelProperty("金额变更统计TOP10")
private List<DataDTO> amountChangeTop10;

@ApiModelProperty("项目撤销统计TOP10")
private List<DataDTO> revokeTop10;

@ApiModelProperty("项目终止统计TOP10")
private List<DataDTO> terminationTop10;

@ApiModelProperty("项目延期统计TOP10")
private List<DataDTO> delayTop10;
}

+ 4
- 1
hz-pm-api/src/main/java/com/hz/pm/api/fiscal/entity/CompanyFiscalCode.java View File

@@ -1,5 +1,7 @@
package com.hz.pm.api.fiscal.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import lombok.Data;
@@ -17,11 +19,12 @@ import java.time.LocalDateTime;
*/
@Data
@TableName("nd_company_fiscal_code")
@ApiModel(value = "NdCompanyFiscalCode对象", description = "")
@ApiModel(value = "NdCompanyFiscalCode对象")
public class CompanyFiscalCode implements Serializable {

private static final long serialVersionUID = 1L;

@TableId(type = IdType.AUTO)
private Long id;

private String fiscalCode;


+ 3
- 3
hz-pm-api/src/main/java/com/hz/pm/api/user/manage/UserInfoManage.java View File

@@ -437,13 +437,13 @@ public class UserInfoManage {
if (CollUtil.isNotEmpty(userRoleList)) {
List<Long> roleIdList = userRoleList.stream().map(UserRole::getRoleId).collect(Collectors.toList());
List<Role> roleList = iRoleService.list(Wrappers.lambdaQuery(Role.class).in(Role::getId, roleIdList));
userRoleInfoList = roleList.stream().map(r -> {
roleList.forEach(r -> {
UserRoleVO userRoleVO = new UserRoleVO();
userRoleVO.setId(r.getId());
userRoleVO.setName(r.getName());
userRoleVO.setCode(r.getCode());
return userRoleVO;
}).collect(Collectors.toList());
userRoleInfoList.add(userRoleVO);
});
}
resUserDetailVO.setUserRoleInfoList(userRoleInfoList);
UserFullInfoDTO userFullInfo = userInfoHelper.getUserFullInfo(userId);


Loading…
Cancel
Save