From eae16006fa471717f093fe92cf8f4aaf3ec07a8f Mon Sep 17 00:00:00 2001 From: PoffyZhang <99775271@qq.com> Date: Wed, 6 Dec 2023 14:54:30 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AF=84=E5=AE=A1=E4=BC=9A=E8=AE=AE=E6=8A=A5?= =?UTF-8?q?=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pmapi/common/model/entity/DataDTO.java | 33 ++++ .../dashboard/controller/StatisticsController.java | 9 + .../dashboard/manage/ExpertStatisticsManage.java | 27 +-- .../dashboard/manage/MeetingStatisticsManage.java | 216 +++++++++++++++++++++ .../dashboard/model/vo/ExpertStatisticsVO.java | 23 +-- .../dashboard/model/vo/MeetingStatisticsVO.java | 36 ++++ 6 files changed, 314 insertions(+), 30 deletions(-) create mode 100644 pmapi/src/main/java/com/ningdatech/pmapi/common/model/entity/DataDTO.java create mode 100644 pmapi/src/main/java/com/ningdatech/pmapi/dashboard/manage/MeetingStatisticsManage.java create mode 100644 pmapi/src/main/java/com/ningdatech/pmapi/dashboard/model/vo/MeetingStatisticsVO.java diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/common/model/entity/DataDTO.java b/pmapi/src/main/java/com/ningdatech/pmapi/common/model/entity/DataDTO.java new file mode 100644 index 0000000..b5086fa --- /dev/null +++ b/pmapi/src/main/java/com/ningdatech/pmapi/common/model/entity/DataDTO.java @@ -0,0 +1,33 @@ +package com.ningdatech.pmapi.common.model.entity; + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import java.math.BigDecimal; + +/** + *

+ * DataDTO + *

+ * + * @author ZPF + * @since 16:40 2023/12/05 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class DataDTO { + + @ApiModelProperty("编号") + private String code; + + @ApiModelProperty("名称") + private String name; + + @ApiModelProperty("数量") + private Integer num; + + @ApiModelProperty("比例") + private BigDecimal rate; +} diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/dashboard/controller/StatisticsController.java b/pmapi/src/main/java/com/ningdatech/pmapi/dashboard/controller/StatisticsController.java index 82130e7..72aaa14 100644 --- a/pmapi/src/main/java/com/ningdatech/pmapi/dashboard/controller/StatisticsController.java +++ b/pmapi/src/main/java/com/ningdatech/pmapi/dashboard/controller/StatisticsController.java @@ -2,6 +2,7 @@ package com.ningdatech.pmapi.dashboard.controller; import com.ningdatech.pmapi.dashboard.manage.ExpertStatisticsManage; import com.ningdatech.pmapi.dashboard.manage.FundStatisticsManage; +import com.ningdatech.pmapi.dashboard.manage.MeetingStatisticsManage; import com.ningdatech.pmapi.dashboard.model.vo.*; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; @@ -24,6 +25,8 @@ public class StatisticsController { private final ExpertStatisticsManage expertStatisticsManage; + private final MeetingStatisticsManage meetingStatisticsManage; + @GetMapping("/fund") @ApiOperation("项目资金统计") public FundStatisticsVO fund(@RequestParam(required = false) Integer year) { @@ -35,4 +38,10 @@ public class StatisticsController { public ExpertStatisticsVO expert(@RequestParam(required = false) Integer year) { return expertStatisticsManage.statistics(year); } + + @GetMapping("/meeting") + @ApiOperation("评审会议统计") + public MeetingStatisticsVO meeting(@RequestParam(required = false) Integer year) { + return meetingStatisticsManage.statistics(year); + } } diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/dashboard/manage/ExpertStatisticsManage.java b/pmapi/src/main/java/com/ningdatech/pmapi/dashboard/manage/ExpertStatisticsManage.java index 0e2f01d..e42257a 100644 --- a/pmapi/src/main/java/com/ningdatech/pmapi/dashboard/manage/ExpertStatisticsManage.java +++ b/pmapi/src/main/java/com/ningdatech/pmapi/dashboard/manage/ExpertStatisticsManage.java @@ -6,6 +6,7 @@ import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.ningdatech.pmapi.common.constant.RegionConst; import com.ningdatech.pmapi.common.helper.RegionCacheHelper; +import com.ningdatech.pmapi.common.model.entity.DataDTO; import com.ningdatech.pmapi.dashboard.constant.DashboardConstant; import com.ningdatech.pmapi.dashboard.model.vo.ExpertStatisticsVO; import com.ningdatech.pmapi.expert.constant.ExpertUserInfoStepEnum; @@ -142,9 +143,9 @@ public class ExpertStatisticsManage { * @param res */ private void threeYearsCompleteExpert(ExpertStatisticsVO res,List experts) { - List threeYearsAdds = Lists.newArrayList(); + List threeYearsAdds = Lists.newArrayList(); for (Integer year : threeYears){ - ExpertStatisticsVO.ExpertData expert = new ExpertStatisticsVO.ExpertData(); + DataDTO expert = new DataDTO(); expert.setName(year.toString()); expert.setCode(year.toString()); expert.setNum(experts.stream().filter(e -> { @@ -206,7 +207,7 @@ public class ExpertStatisticsManage { */ private void computeLevels(ExpertStatisticsVO res, List experts, List expertDictionaries,Map dictionMap) { - List levels = Lists.newArrayList(); + List levels = Lists.newArrayList(); Set userSets = Sets.newHashSet(); Map expertUserFullInfoMap = experts.stream() @@ -216,7 +217,7 @@ public class ExpertStatisticsManage { Map> dictionaryMap = expertDictionaries.stream() .collect(Collectors.groupingBy(ExpertDictionary::getDictionaryCode)); for(String levelCode : LEVELS){ - ExpertStatisticsVO.ExpertData expertData = new ExpertStatisticsVO.ExpertData(); + DataDTO expertData = new DataDTO(); if(dictionaryMap.containsKey(levelCode)){ List dictionaries = dictionaryMap.get(levelCode); expertData.setNum(dictionaries.stream().filter(d -> { @@ -241,7 +242,7 @@ public class ExpertStatisticsManage { */ private void computeTypes(ExpertStatisticsVO res, List experts, List expertDictionaries,Map dictionMap) { - List types = Lists.newArrayList(); + List types = Lists.newArrayList(); Set userSets = Sets.newHashSet(); Map expertUserFullInfoMap = experts.stream() @@ -251,7 +252,7 @@ public class ExpertStatisticsManage { Map> dictionaryMap = expertDictionaries.stream() .collect(Collectors.groupingBy(ExpertDictionary::getDictionaryCode)); for(String typeCode : TYPES){ - ExpertStatisticsVO.ExpertData expertData = new ExpertStatisticsVO.ExpertData(); + DataDTO expertData = new DataDTO(); if(dictionaryMap.containsKey(typeCode)){ List dictionaries = dictionaryMap.get(typeCode); expertData.setNum(dictionaries.stream().filter(d -> { @@ -277,7 +278,7 @@ public class ExpertStatisticsManage { .filter(u -> userSets.add(u.getUserId())) .collect(Collectors.toMap(ExpertUserFullInfo::getUserId, e -> e)); - Map> typeDistribution = Maps.newHashMap(); + Map> typeDistribution = Maps.newHashMap(); Map> tagsMap = expertTags.stream().filter(e -> Objects.nonNull(e.getTagCode())) @@ -288,14 +289,14 @@ public class ExpertStatisticsManage { .collect(Collectors.toMap(TagDTO::getTagCode, TagDTO::getTagName)); //1.省维度 - List shengWeidu = Lists.newArrayList(); + List shengWeidu = Lists.newArrayList(); for(String code : SHENGWEIDU){ shengWeidu.add(getExpertData(expertUserFullInfoMap, tagsMap, tagNameMap, code)); } //2.市维度 - List shiWeidu = Lists.newArrayList(); + List shiWeidu = Lists.newArrayList(); for(String code : SHIWEIDU){ shiWeidu.add(getExpertData(expertUserFullInfoMap, tagsMap, tagNameMap, code)); @@ -314,8 +315,8 @@ public class ExpertStatisticsManage { * @param code * @return */ - private static ExpertStatisticsVO.ExpertData getExpertData(Map expertUserFullInfoMap, Map> tagsMap, Map tagNameMap, String code) { - ExpertStatisticsVO.ExpertData data = new ExpertStatisticsVO.ExpertData(); + private static DataDTO getExpertData(Map expertUserFullInfoMap, Map> tagsMap, Map tagNameMap, String code) { + DataDTO data = new DataDTO(); data.setCode(code); data.setName(tagNameMap.get(code)); if(tagsMap.containsKey(code)){ @@ -332,9 +333,9 @@ public class ExpertStatisticsManage { //计算区域专家 private static void computeRegionExperts(ExpertStatisticsVO res, List intentionWorkRegions, Map expertMap, List regions) { - List regionExpert = Lists.newArrayList(); + List regionExpert = Lists.newArrayList(); for(RegionDTO region : regions){ - ExpertStatisticsVO.ExpertData expertData = new ExpertStatisticsVO.ExpertData(); + DataDTO expertData = new DataDTO(); expertData.setName(region.getRegionName()); expertData.setCode(region.getRegionCode()); expertData.setNum(intentionWorkRegions.stream().filter(w -> { diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/dashboard/manage/MeetingStatisticsManage.java b/pmapi/src/main/java/com/ningdatech/pmapi/dashboard/manage/MeetingStatisticsManage.java new file mode 100644 index 0000000..b91f21f --- /dev/null +++ b/pmapi/src/main/java/com/ningdatech/pmapi/dashboard/manage/MeetingStatisticsManage.java @@ -0,0 +1,216 @@ +package com.ningdatech.pmapi.dashboard.manage; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.google.common.collect.Lists; +import com.ningdatech.pmapi.common.constant.RegionConst; +import com.ningdatech.pmapi.common.helper.RegionCacheHelper; +import com.ningdatech.pmapi.common.model.entity.DataDTO; +import com.ningdatech.pmapi.dashboard.model.vo.MeetingStatisticsVO; +import com.ningdatech.pmapi.ding.constants.DingOrganizationContant; +import com.ningdatech.pmapi.expert.constant.ReviewResultEnum; +import com.ningdatech.pmapi.expert.model.entity.ExpertReview; +import com.ningdatech.pmapi.expert.model.enumeration.ReviewTemplateTypeEnum; +import com.ningdatech.pmapi.expert.service.IExpertReviewService; +import com.ningdatech.pmapi.meeting.entity.domain.Meeting; +import com.ningdatech.pmapi.meeting.service.IMeetingService; +import com.ningdatech.pmapi.organization.model.entity.DingOrganization; +import com.ningdatech.pmapi.organization.service.IDingOrganizationService; +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.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 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 meetingIds = meetings.stream().map(Meeting::getId) + .collect(Collectors.toList()); + + //会议总数 + res.setMeetingTotal(meetings.size()); + + //评审数 + List 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 passExpertReviews = expertReviews.stream() + .filter(r -> Objects.nonNull(r.getReviewResult()) && + r.getReviewResult().equals(ReviewResultEnum.PASSED.getCode())) + .collect(Collectors.toList()); + //不通过的评审 + List 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 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 regionMeetngs = Lists.newArrayList(); + for(RegionDTO region : regions){ + DataDTO data = new DataDTO(); + data.setCode(region.getRegionCode()); + data.setName(region.getRegionName()); + data.setNum(meetings.stream().filter(m -> { + if(StringUtils.isNotBlank(m.getRegionCode()) && + m.getRegionCode().equals(region.getRegionCode())){ + return Boolean.TRUE; + } + return Boolean.FALSE; + }).collect(Collectors.toList()).size()); + regionMeetngs.add(data); + } + res.setRegionMeetings(regionMeetngs); + + //预审 验收 会议 + List meetingTypes = Lists.newArrayList(); + DataDTO yushen = new DataDTO(); + yushen.setCode(ReviewTemplateTypeEnum.PRELIMINARY_SCHEME_REVIEW.getCode().toString()); + yushen.setName("预审会议"); + yushen.setNum(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()); + meetingTypes.add(yushen); + DataDTO yanshou = new DataDTO(); + yanshou.setCode(ReviewTemplateTypeEnum.ACCEPTANCE_SCHEME_REVIEW.getCode().toString()); + yanshou.setName("验收会议"); + 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(); + yanshou.setNum(yanshouCount.intValue()); + meetingTypes.add(yanshou); + res.setMeetingTypes(meetingTypes); + + //各区县评审 不通过率 + List regionNotpassReview = Lists.newArrayList(); + for(RegionDTO region : regions){ + DataDTO data = new DataDTO(); + data.setCode(region.getRegionCode()); + data.setName(region.getRegionName()); + //先求出 此区域会议 + List regionMeetingIds = meetings.stream().filter(m -> { + if (StringUtils.isNotBlank(m.getRegionCode()) && + m.getRegionCode().equals(region.getRegionCode())) { + return Boolean.TRUE; + } + return Boolean.FALSE; + }).map(Meeting::getId).collect(Collectors.toList()); + + List 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 organizations = dingOrganizationService.list(Wrappers.lambdaQuery(DingOrganization.class) + .in(DingOrganization::getTypeCode, Lists.newArrayList(DingOrganizationContant.UNIT_TYPE, + DingOrganizationContant.GOV_TEMPORARY))); + List projects = projectService.list(Wrappers.lambdaQuery(Project.class) + .eq(Project::getNewest, Boolean.TRUE)); + + //TOP10 + List finalExpertReviews = expertReviews; + List notpassTop10 = organizations.stream() + .map(o -> { + DataDTO data = new DataDTO(); + data.setCode(o.getOrganizationCode()); + data.setName(o.getOrganizationName()); + List orgProjects = projects.stream().filter(p -> Objects.nonNull(p.getBuildOrgCode()) && + p.getBuildOrgCode().equals(o.getOrganizationCode())) + .collect(Collectors.toList()); + List projectCodes = orgProjects.stream().map(Project::getProjectCode) + .collect(Collectors.toList()); + if(CollUtil.isEmpty(projectCodes)){ + data.setRate(BigDecimal.ZERO); + return data; + } + List 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; + }) + .sorted(Comparator.comparing(DataDTO::getRate).reversed()) + .limit(10).collect(Collectors.toList()); + res.setNotPassTop10(notpassTop10); + return res; + } +} diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/dashboard/model/vo/ExpertStatisticsVO.java b/pmapi/src/main/java/com/ningdatech/pmapi/dashboard/model/vo/ExpertStatisticsVO.java index 259f7a9..bf139a0 100644 --- a/pmapi/src/main/java/com/ningdatech/pmapi/dashboard/model/vo/ExpertStatisticsVO.java +++ b/pmapi/src/main/java/com/ningdatech/pmapi/dashboard/model/vo/ExpertStatisticsVO.java @@ -1,5 +1,6 @@ package com.ningdatech.pmapi.dashboard.model.vo; +import com.ningdatech.pmapi.common.model.entity.DataDTO; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @@ -23,29 +24,17 @@ public class ExpertStatisticsVO implements Serializable { private Integer active = 0; @ApiModelProperty("各区县专家数") - private List regionExpert; + private List regionExpert; @ApiModelProperty("近三年专家数") - private List threeYearsAdded; + private List threeYearsAdded; @ApiModelProperty("专家类型分布") - private Map> typeDistribution; + private Map> typeDistribution; @ApiModelProperty("专家类型") - private List types; + private List types; @ApiModelProperty("专家等级") - private List levels; - - @Data - public static class ExpertData { - @ApiModelProperty("名称") - private String name; - - @ApiModelProperty("编码") - private String code; - - @ApiModelProperty("数量") - private Integer num = 0; - } + private List levels; } \ No newline at end of file diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/dashboard/model/vo/MeetingStatisticsVO.java b/pmapi/src/main/java/com/ningdatech/pmapi/dashboard/model/vo/MeetingStatisticsVO.java new file mode 100644 index 0000000..f9b196f --- /dev/null +++ b/pmapi/src/main/java/com/ningdatech/pmapi/dashboard/model/vo/MeetingStatisticsVO.java @@ -0,0 +1,36 @@ +package com.ningdatech.pmapi.dashboard.model.vo; + +import com.ningdatech.pmapi.common.model.entity.DataDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.List; + +@Data +@ApiModel(value = "评审会议统计", description = "") +public class MeetingStatisticsVO implements Serializable { + private static final long serialVersionUID = 1L; + + @ApiModelProperty("评审召开总数") + private Integer meetingTotal = 0; + + @ApiModelProperty("评审通过数") + private Integer passReview = 0; + + @ApiModelProperty("评审不通过率") + private BigDecimal notPassRate = BigDecimal.ZERO; + + @ApiModelProperty("各区县召开总数") + private List regionMeetings; + + @ApiModelProperty("预审/验收 会议情况") + private List meetingTypes; + + @ApiModelProperty("各区县不通过率") + private List notPassRegionMeetings; + + @ApiModelProperty("各部门不通过top10") + private List notPassTop10; +} \ No newline at end of file