@@ -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; | |||
/** | |||
* <p> | |||
* DataDTO | |||
* </p> | |||
* | |||
* @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; | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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<ExpertUserFullInfo> experts) { | |||
List<ExpertStatisticsVO.ExpertData> threeYearsAdds = Lists.newArrayList(); | |||
List<DataDTO> 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<ExpertUserFullInfo> experts, | |||
List<ExpertDictionary> expertDictionaries,Map<String, String> dictionMap) { | |||
List<ExpertStatisticsVO.ExpertData> levels = Lists.newArrayList(); | |||
List<DataDTO> levels = Lists.newArrayList(); | |||
Set<Long> userSets = Sets.newHashSet(); | |||
Map<Long, ExpertUserFullInfo> expertUserFullInfoMap = experts.stream() | |||
@@ -216,7 +217,7 @@ public class ExpertStatisticsManage { | |||
Map<String, List<ExpertDictionary>> 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<ExpertDictionary> dictionaries = dictionaryMap.get(levelCode); | |||
expertData.setNum(dictionaries.stream().filter(d -> { | |||
@@ -241,7 +242,7 @@ public class ExpertStatisticsManage { | |||
*/ | |||
private void computeTypes(ExpertStatisticsVO res, List<ExpertUserFullInfo> experts, | |||
List<ExpertDictionary> expertDictionaries,Map<String, String> dictionMap) { | |||
List<ExpertStatisticsVO.ExpertData> types = Lists.newArrayList(); | |||
List<DataDTO> types = Lists.newArrayList(); | |||
Set<Long> userSets = Sets.newHashSet(); | |||
Map<Long, ExpertUserFullInfo> expertUserFullInfoMap = experts.stream() | |||
@@ -251,7 +252,7 @@ public class ExpertStatisticsManage { | |||
Map<String, List<ExpertDictionary>> 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<ExpertDictionary> 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<String,List<ExpertStatisticsVO.ExpertData>> typeDistribution = Maps.newHashMap(); | |||
Map<String,List<DataDTO>> typeDistribution = Maps.newHashMap(); | |||
Map<String, List<ExpertTag>> 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<ExpertStatisticsVO.ExpertData> shengWeidu = Lists.newArrayList(); | |||
List<DataDTO> shengWeidu = Lists.newArrayList(); | |||
for(String code : SHENGWEIDU){ | |||
shengWeidu.add(getExpertData(expertUserFullInfoMap, | |||
tagsMap, tagNameMap, code)); | |||
} | |||
//2.市维度 | |||
List<ExpertStatisticsVO.ExpertData> shiWeidu = Lists.newArrayList(); | |||
List<DataDTO> 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<Long, ExpertUserFullInfo> expertUserFullInfoMap, Map<String, List<ExpertTag>> tagsMap, Map<String, String> tagNameMap, String code) { | |||
ExpertStatisticsVO.ExpertData data = new ExpertStatisticsVO.ExpertData(); | |||
private static DataDTO getExpertData(Map<Long, ExpertUserFullInfo> expertUserFullInfoMap, Map<String, List<ExpertTag>> tagsMap, Map<String, String> 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<ExpertIntentionWorkRegion> intentionWorkRegions, Map<Long, ExpertUserFullInfo> expertMap, List<RegionDTO> regions) { | |||
List<ExpertStatisticsVO.ExpertData> regionExpert = Lists.newArrayList(); | |||
List<DataDTO> 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 -> { | |||
@@ -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<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){ | |||
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<DataDTO> 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<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 -> { | |||
if (StringUtils.isNotBlank(m.getRegionCode()) && | |||
m.getRegionCode().equals(region.getRegionCode())) { | |||
return Boolean.TRUE; | |||
} | |||
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)){ | |||
data.setRate(BigDecimal.ZERO); | |||
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; | |||
}) | |||
.sorted(Comparator.comparing(DataDTO::getRate).reversed()) | |||
.limit(10).collect(Collectors.toList()); | |||
res.setNotPassTop10(notpassTop10); | |||
return res; | |||
} | |||
} |
@@ -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<ExpertData> regionExpert; | |||
private List<DataDTO> regionExpert; | |||
@ApiModelProperty("近三年专家数") | |||
private List<ExpertData> threeYearsAdded; | |||
private List<DataDTO> threeYearsAdded; | |||
@ApiModelProperty("专家类型分布") | |||
private Map<String,List<ExpertData>> typeDistribution; | |||
private Map<String,List<DataDTO>> typeDistribution; | |||
@ApiModelProperty("专家类型") | |||
private List<ExpertData> types; | |||
private List<DataDTO> types; | |||
@ApiModelProperty("专家等级") | |||
private List<ExpertData> levels; | |||
@Data | |||
public static class ExpertData { | |||
@ApiModelProperty("名称") | |||
private String name; | |||
@ApiModelProperty("编码") | |||
private String code; | |||
@ApiModelProperty("数量") | |||
private Integer num = 0; | |||
} | |||
private List<DataDTO> levels; | |||
} |
@@ -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<DataDTO> regionMeetings; | |||
@ApiModelProperty("预审/验收 会议情况") | |||
private List<DataDTO> meetingTypes; | |||
@ApiModelProperty("各区县不通过率") | |||
private List<DataDTO> notPassRegionMeetings; | |||
@ApiModelProperty("各部门不通过top10") | |||
private List<DataDTO> notPassTop10; | |||
} |