| sql/mysql/mes_safety_statistics_init.sql | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/safety/MesSafetyStatisticsController.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/safety/vo/statistics/MesSafetyHazardExcelVO.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/safety/vo/statistics/MesSafetyStatisticsReqVO.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/safety/vo/statistics/MesSafetyStatisticsRespVO.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/safety/MesSafetyStatisticsService.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/safety/MesSafetyStatisticsServiceImpl.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
sql/mysql/mes_safety_statistics_init.sql
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,38 @@ -- ===================================================================== -- å®å ¨ç产模å ââ 䏿ï¼å®å ¨æ°æ®ç»è®¡åæ -- -- å®ä½ï¼ææ¶é´æ®µä¸è½¦é´çéï¼è¾åºéæ£/ä½ä¸ç¥¨/å¹è®/è¯ä¹¦å个维度çåç»ç»è®¡ï¼ -- å¹¶æ¯æéæ£æç»å¯¼åº Excelã䏿°å¢ä¸å¡è¡¨ã -- -- ä¸ãå®å ¨çæ¿ãçåºå«ï¼ -- çæ¿ = 宿¶å ¨å±æ¦è§ï¼ä¸å¯çéãä¸å¯¼åº -- ç»è®¡åæ = 坿宿¶é´èå´ä¸è½¦é´ï¼åºåç»æ¥è¡¨ï¼å¯å¯¼åº -- -- å 容ï¼èåãç»è®¡åæã -- -- ç¹æ§ï¼å¯é夿§è¡ -- ===================================================================== DELETE FROM system_role_menu WHERE menu_id BETWEEN 1065963 AND 1065970; DELETE FROM system_menu WHERE id BETWEEN 1065963 AND 1065970; INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1065963, 'ç»è®¡åæ', '', 2, 8, 1065910, 'statistics', 'ep:trend-charts', 'safety/statistics/index', 'SafetyStatistics', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0'), (1065964, 'ç»è®¡æ¥è¯¢', 'mes:safety-statistics:query', 3, 1, 1065963, '', '', NULL, NULL, 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0'), (1065965, 'æ¥è¡¨å¯¼åº', 'mes:safety-statistics:export', 3, 2, 1065963, '', '', NULL, NULL, 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0'); INSERT INTO system_role_menu (role_id, menu_id, creator, create_time, updater, update_time, deleted) SELECT 1, m.id, '1', NOW(), '1', NOW(), b'0' FROM system_menu m WHERE m.id BETWEEN 1065963 AND 1065970; -- --------------------------------------------------------------------- -- éªè¯ï¼å®å ¨ç产ç®å½ä¸ç宿´èåç»æ -- --------------------------------------------------------------------- SELECT id, parent_id, name, path, component, permission, type, sort FROM system_menu WHERE id BETWEEN 1065910 AND 1065970 ORDER BY sort, id; yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/safety/MesSafetyStatisticsController.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,145 @@ package cn.iocoder.yudao.module.mes.controller.admin.safety; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; import cn.iocoder.yudao.module.mes.controller.admin.safety.vo.statistics.MesSafetyHazardExcelVO; import cn.iocoder.yudao.module.mes.controller.admin.safety.vo.statistics.MesSafetyStatisticsReqVO; import cn.iocoder.yudao.module.mes.controller.admin.safety.vo.statistics.MesSafetyStatisticsRespVO; import cn.iocoder.yudao.module.mes.dal.dataobject.md.workstation.MesMdWorkshopDO; import cn.iocoder.yudao.module.mes.dal.dataobject.safety.MesSafetyHazardDO; import cn.iocoder.yudao.module.mes.dal.mysql.md.workstation.MesMdWorkshopMapper; import cn.iocoder.yudao.module.mes.dal.mysql.safety.MesSafetyHazardMapper; import cn.iocoder.yudao.module.mes.service.safety.MesSafetyStatisticsService; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; import jakarta.servlet.http.HttpServletResponse; import jakarta.validation.Valid; import org.springframework.security.access.prepost.PreAuthorize; 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.RestController; import java.io.IOException; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.*; import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; /** * å®å ¨ç产 - ç»è®¡åæ Controller * * @author è¶ çº§ç®¡çå */ @Tag(name = "管çåå° - å®å ¨ç产-ç»è®¡åæ") @RestController @RequestMapping("/mes/safety/statistics") @Validated public class MesSafetyStatisticsController { @Resource private MesSafetyStatisticsService statisticsService; @Resource private MesSafetyHazardMapper hazardMapper; @Resource private MesMdWorkshopMapper workshopMapper; @Resource private AdminUserApi adminUserApi; /** 鿣ççº§ææ¬ */ private static final String[] HAZARD_LEVEL_NAMES = {null, "ä¸è¬éæ£", "é大鿣"}; /** éæ£æ¥æºææ¬ */ private static final String[] HAZARD_SOURCE_NAMES = {null, "æ¥å¸¸ææ¥", "ä¸é¡¹æ£æ¥", "ä¸çº§æ£æ¥", "å工䏿¥", "å ¶ä»"}; @GetMapping("/report") @Operation(summary = "è·å¾å®å ¨ç产ç»è®¡æ¥è¡¨") @PreAuthorize("@ss.hasPermission('mes:safety-statistics:query')") public CommonResult<MesSafetyStatisticsRespVO> getReport(@Valid MesSafetyStatisticsReqVO reqVO) { return success(statisticsService.getStatistics(reqVO)); } @GetMapping("/export-hazard") @Operation(summary = "导åºéæ£æç»æ¥è¡¨") @PreAuthorize("@ss.hasPermission('mes:safety-statistics:export')") public void exportHazard(@Valid MesSafetyStatisticsReqVO reqVO, HttpServletResponse response) throws IOException { List<MesSafetyHazardDO> list = hazardMapper.selectAllList().stream() .filter(h -> inRange(h.getCreateTime(), reqVO)) .filter(h -> reqVO.getWorkshopId() == null || Objects.equals(h.getWorkshopId(), reqVO.getWorkshopId())) .collect(Collectors.toList()); // åå ¸ä¸å ³èåç§°å¨å¯¼åºåè½¬ä¸ºä¸æï¼ä¸å¡äººåå¯ç´æ¥æ¥ç Map<Long, String> workshopNameMap = workshopMapper.selectList().stream() .collect(Collectors.toMap(MesMdWorkshopDO::getId, MesMdWorkshopDO::getName, (a, b) -> a)); Set<Long> userIds = list.stream().map(MesSafetyHazardDO::getChargeUserId) .filter(Objects::nonNull).collect(Collectors.toSet()); Map<Long, AdminUserRespDTO> userMap = userIds.isEmpty() ? Collections.emptyMap() : adminUserApi.getUserMap(userIds); LocalDate today = LocalDate.now(); List<MesSafetyHazardExcelVO> excelList = new ArrayList<>(list.size()); for (MesSafetyHazardDO hazard : list) { MesSafetyHazardExcelVO vo = BeanUtils.toBean(hazard, MesSafetyHazardExcelVO.class); vo.setHazardLevelName(dictName(HAZARD_LEVEL_NAMES, hazard.getHazardLevel())); vo.setSourceName(dictName(HAZARD_SOURCE_NAMES, hazard.getSource())); vo.setWorkshopName(workshopNameMap.get(hazard.getWorkshopId())); vo.setStatusName(hazardStatusName(hazard.getStatus())); AdminUserRespDTO charge = hazard.getChargeUserId() == null ? null : userMap.get(hazard.getChargeUserId()); vo.setChargeUserName(charge == null ? null : charge.getNickname()); boolean overdue = hazard.getDeadline() != null && !MesSafetyHazardDO.STATUS_CLOSED.equals(hazard.getStatus()) && hazard.getDeadline().isBefore(today); vo.setOverdueText(overdue ? "æ¯" : "å¦"); excelList.add(vo); } ExcelUtils.write(response, "鿣æç».xlsx", "鿣æç»", MesSafetyHazardExcelVO.class, excelList); } // ==================== å·¥å · ==================== private String dictName(String[] names, Integer value) { if (value == null || value < 0 || value >= names.length) { return null; } return names[value]; } private String hazardStatusName(Integer status) { if (status == null) { return null; } return switch (status) { case 0 -> "å¾ æ´æ¹"; case 10 -> "æ´æ¹ä¸"; case 20 -> "å¾ éªæ¶"; case 30 -> "å·²éç¯"; default -> "æªç¥"; }; } private boolean inRange(LocalDateTime createTime, MesSafetyStatisticsReqVO reqVO) { if (reqVO.getStartDate() == null && reqVO.getEndDate() == null) { return true; } if (createTime == null) { return false; } if (reqVO.getStartDate() != null && createTime.isBefore(reqVO.getStartDate().atStartOfDay())) { return false; } return reqVO.getEndDate() == null || !createTime.isAfter(reqVO.getEndDate().atTime(23, 59, 59)); } } yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/safety/vo/statistics/MesSafetyHazardExcelVO.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,91 @@ package cn.iocoder.yudao.module.mes.controller.admin.safety.vo.statistics; import cn.idev.excel.annotation.ExcelProperty; import cn.idev.excel.annotation.write.style.ColumnWidth; import lombok.Data; import java.math.BigDecimal; import java.time.LocalDate; /** * å®å ¨ç产 - 鿣æç»å¯¼åº Excel VO * * åå ¸å¼å¨å¯¼åºåå·²è½¬ä¸ºä¸æææ¬ï¼ä¾¿äºä¸å¡äººåç´æ¥æ¥ç * * @author è¶ çº§ç®¡çå */ @Data public class MesSafetyHazardExcelVO { @ExcelProperty("鿣ç¼ç ") @ColumnWidth(20) private String code; @ExcelProperty("鿣åç§°") @ColumnWidth(30) private String name; @ExcelProperty("鿣ç级") @ColumnWidth(12) private String hazardLevelName; @ExcelProperty("éæ£æ¥æº") @ColumnWidth(14) private String sourceName; @ExcelProperty("æå±è½¦é´") @ColumnWidth(16) private String workshopName; @ExcelProperty("å ·ä½ä½ç½®") @ColumnWidth(24) private String location; @ExcelProperty("鿣æè¿°") @ColumnWidth(40) private String description; @ExcelProperty("åç°æ¥æ") @ColumnWidth(14) private LocalDate foundDate; @ExcelProperty("æ´æ¹è´£ä»»äºº") @ColumnWidth(14) private String chargeUserName; @ExcelProperty("æ´æ¹æé") @ColumnWidth(14) private LocalDate deadline; @ExcelProperty("ç¶æ") @ColumnWidth(12) private String statusName; @ExcelProperty("æ¯å¦è¶ æ") @ColumnWidth(12) private String overdueText; @ExcelProperty("æ´æ¹æªæ½") @ColumnWidth(40) private String measure; @ExcelProperty("æ´æ¹å®ææ¥æ") @ColumnWidth(16) private LocalDate finishDate; @ExcelProperty("éªæ¶æè§") @ColumnWidth(30) private String checkResult; @ExcelProperty("夿³¨") @ColumnWidth(24) private String remark; /** * å ä½å段ï¼é¿å EasyExcel å¯¹æ æ°æ®è¡¨å¤´æ¥é */ @ExcelProperty("") @ColumnWidth(2) private BigDecimal placeholder; } yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/safety/vo/statistics/MesSafetyStatisticsReqVO.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,26 @@ package cn.iocoder.yudao.module.mes.controller.admin.safety.vo.statistics; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import org.springframework.format.annotation.DateTimeFormat; import java.time.LocalDate; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY; @Schema(description = "管çåå° - å®å ¨ç产ç»è®¡åæ Request VO") @Data public class MesSafetyStatisticsReqVO { @Schema(description = "ç»è®¡èµ·å§æ¥æï¼æå建æ¶é´è¿æ»¤ï¼", example = "2026-01-01") @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY) private LocalDate startDate; @Schema(description = "ç»è®¡ç»ææ¥æ", example = "2026-12-31") @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY) private LocalDate endDate; @Schema(description = "车é´ç¼å·ï¼å¯éï¼ä¸ºç©ºåç»è®¡å ¨é¨ï¼", example = "7") private Long workshopId; } yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/safety/vo/statistics/MesSafetyStatisticsRespVO.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,103 @@ package cn.iocoder.yudao.module.mes.controller.admin.safety.vo.statistics; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.math.BigDecimal; import java.util.List; /** * å®å ¨ç产 - ç»è®¡åæ Response VO * * ææ¶é´æ®µç»è®¡éæ£ãä½ä¸ç¥¨ãå¹è®ãè¯ä¹¦å个维度 * * @author è¶ çº§ç®¡çå */ @Schema(description = "管çåå° - å®å ¨ç产ç»è®¡åæ Response VO") @Data public class MesSafetyStatisticsRespVO { @Schema(description = "æ±æ»ææ ") private Summary summary; @Schema(description = "鿣æè½¦é´ç»è®¡") private List<GroupStat> hazardByWorkshop; @Schema(description = "鿣æç级ç»è®¡") private List<GroupStat> hazardByLevel; @Schema(description = "éæ£ææ¥æºç»è®¡") private List<GroupStat> hazardBySource; @Schema(description = "ä½ä¸ç¥¨æç±»åç»è®¡") private List<GroupStat> ticketByType; @Schema(description = "ä½ä¸ç¥¨æç¶æç»è®¡") private List<GroupStat> ticketByStatus; @Schema(description = "å¹è®æç±»åç»è®¡") private List<GroupStat> trainingByType; @Schema(description = "è¯ä¹¦æç±»åç»è®¡") private List<GroupStat> certificateByType; // ==================== å é¨ç±» ==================== @Schema(description = "æ±æ»ææ ") @Data public static class Summary { @Schema(description = "éæ£æ»æ°") private Long hazardTotal; @Schema(description = "鿣已éç¯æ°") private Long hazardClosed; @Schema(description = "鿣éç¯çï¼%ï¼") private BigDecimal hazardClosedRate; @Schema(description = "éæ£è¶ ææ°") private Long hazardOverdue; @Schema(description = "ä½ä¸ç¥¨æ»æ°") private Long ticketTotal; @Schema(description = "ä½ä¸ç¥¨å·²å½æ¡£æ°") private Long ticketArchived; @Schema(description = "ä½ä¸ç¥¨å·²é©³åæ°") private Long ticketRejected; @Schema(description = "å¹è®åºæ¬¡") private Long trainingTotal; @Schema(description = "累计åè®äººæ¬¡") private Long trainingAttendee; @Schema(description = "å¹è®å¹³åå") private BigDecimal trainingAvgScore; @Schema(description = "è¯ä¹¦æ»æ°") private Long certificateTotal; @Schema(description = "è¯ä¹¦å·²è¿ææ°") private Long certificateExpired; } @Schema(description = "åç»ç»è®¡é¡¹") @Data public static class GroupStat { @Schema(description = "åç»åç§°", example = "é 纸车é´") private String name; @Schema(description = "åç»ç¼ç ï¼è½¦é´/ç±»å/ç级çåå§å¼ï¼", example = "7") private Integer code; @Schema(description = "æ»æ°é") private Long total; @Schema(description = "已宿æ°éï¼éæ£=å·²éç¯ï¼ä½ä¸ç¥¨=已彿¡£ï¼å ¶ä»å¯ä¸ºç©ºï¼") private Long finished; @Schema(description = "宿çï¼%ï¼") private BigDecimal finishRate; @Schema(description = "累计åè®äººæ¬¡ï¼ä» å¹è®ç»´åº¦ï¼") private Long attendeeTotal; @Schema(description = "å¹³ååï¼ä» å¹è®ç»´åº¦ï¼") private BigDecimal avgScore; } } yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/safety/MesSafetyStatisticsService.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,18 @@ package cn.iocoder.yudao.module.mes.service.safety; import cn.iocoder.yudao.module.mes.controller.admin.safety.vo.statistics.MesSafetyStatisticsReqVO; import cn.iocoder.yudao.module.mes.controller.admin.safety.vo.statistics.MesSafetyStatisticsRespVO; /** * å®å ¨ç产 - ç»è®¡åæ Service æ¥å£ * * @author è¶ çº§ç®¡çå */ public interface MesSafetyStatisticsService { /** * ææ¶é´æ®µä¸è½¦é´ç»´åº¦ç»è®¡æ°æ® */ MesSafetyStatisticsRespVO getStatistics(MesSafetyStatisticsReqVO reqVO); } yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/safety/MesSafetyStatisticsServiceImpl.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,240 @@ package cn.iocoder.yudao.module.mes.service.safety; import cn.iocoder.yudao.module.mes.controller.admin.safety.vo.statistics.MesSafetyStatisticsReqVO; import cn.iocoder.yudao.module.mes.controller.admin.safety.vo.statistics.MesSafetyStatisticsRespVO; import cn.iocoder.yudao.module.mes.controller.admin.safety.vo.statistics.MesSafetyStatisticsRespVO.GroupStat; import cn.iocoder.yudao.module.mes.controller.admin.safety.vo.statistics.MesSafetyStatisticsRespVO.Summary; import cn.iocoder.yudao.module.mes.dal.dataobject.md.workstation.MesMdWorkshopDO; import cn.iocoder.yudao.module.mes.dal.dataobject.safety.*; import cn.iocoder.yudao.module.mes.dal.mysql.md.workstation.MesMdWorkshopMapper; import cn.iocoder.yudao.module.mes.dal.mysql.safety.*; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import java.math.BigDecimal; import java.math.RoundingMode; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.*; import java.util.stream.Collectors; /** * å®å ¨ç产 - ç»è®¡åæ Service å®ç° * * æ°æ®è§æ¨¡è¾å°ï¼éç¨å ¨éæ¥è¯¢ + å åè¿æ»¤åç»ï¼ä¾¿äºçµæ´»ç»åç鿡件 * * @author è¶ çº§ç®¡çå */ @Service @Validated public class MesSafetyStatisticsServiceImpl implements MesSafetyStatisticsService { @Resource private MesSafetyHazardMapper hazardMapper; @Resource private MesSafetyWorkTicketMapper ticketMapper; @Resource private MesSafetyTrainingMapper trainingMapper; @Resource private MesSafetyCertificateMapper certificateMapper; @Resource private MesMdWorkshopMapper workshopMapper; /** åå ¸æ ç¾ï¼ä¸ SQL ä¸ system_dict_data ä¿æä¸è´ï¼ */ private static final String[] HAZARD_LEVEL_NAMES = {null, "ä¸è¬éæ£", "é大鿣"}; private static final String[] HAZARD_SOURCE_NAMES = {null, "æ¥å¸¸ææ¥", "ä¸é¡¹æ£æ¥", "ä¸çº§æ£æ¥", "å工䏿¥", "å ¶ä»"}; private static final String[] TICKET_TYPE_NAMES = {null, "å¨ç«ä½ä¸", "åé空é´ä½ä¸", "é«å¤ä½ä¸", "åè£ ä½ä¸", "临æ¶ç¨çµä½ä¸", "æè·¯ä½ä¸", "ç²æ¿æ½å µä½ä¸", "è®¾å¤æ£ä¿®ä½ä¸"}; private static final String[] TICKET_STATUS_NAMES = {null, null, null, null, null, null, null, null, null, null, "å·²æ¹å"}; // ä» å ä½ï¼å®é ç¨ switch private static final String[] TRAINING_TYPE_NAMES = {null, "ä¸çº§å®å ¨æè²", "ä¸é¡¹å¹è®", "å¤è®", "æ¥å¸¸å®å ¨æè²", "å ¶ä»"}; private static final String[] CERT_TYPE_NAMES = {null, "ç¹ç§ä½ä¸æä½è¯", "å®å ¨ç®¡ç人åè¯", "主è¦è´è´£äººè¯", "å ¶ä»èµæ ¼è¯"}; @Override public MesSafetyStatisticsRespVO getStatistics(MesSafetyStatisticsReqVO reqVO) { LocalDate today = LocalDate.now(); MesSafetyStatisticsRespVO vo = new MesSafetyStatisticsRespVO(); // 车é´åç§°æ å° Map<Long, String> workshopNameMap = workshopMapper.selectList().stream() .collect(Collectors.toMap(MesMdWorkshopDO::getId, MesMdWorkshopDO::getName, (a, b) -> a)); // ========== 鿣 ========== List<MesSafetyHazardDO> hazards = hazardMapper.selectAllList().stream() .filter(h -> inRange(h.getCreateTime(), reqVO)) .filter(h -> matchWorkshop(h.getWorkshopId(), reqVO)) .collect(Collectors.toList()); Summary summary = new Summary(); long hazardClosed = hazards.stream() .filter(h -> MesSafetyHazardDO.STATUS_CLOSED.equals(h.getStatus())).count(); long hazardOverdue = hazards.stream() .filter(h -> h.getDeadline() != null && !MesSafetyHazardDO.STATUS_CLOSED.equals(h.getStatus()) && h.getDeadline().isBefore(today)) .count(); summary.setHazardTotal((long) hazards.size()); summary.setHazardClosed(hazardClosed); summary.setHazardOverdue(hazardOverdue); summary.setHazardClosedRate(rate(hazardClosed, hazards.size())); // 鿣æè½¦é´ Map<Long, List<MesSafetyHazardDO>> byWorkshop = hazards.stream() .filter(h -> h.getWorkshopId() != null) .collect(Collectors.groupingBy(MesSafetyHazardDO::getWorkshopId)); vo.setHazardByWorkshop(byWorkshop.entrySet().stream() .map(e -> buildStat(workshopNameMap.getOrDefault(e.getKey(), "æªç¥è½¦é´"), e.getKey().intValue(), e.getValue(), h -> MesSafetyHazardDO.STATUS_CLOSED.equals(h.getStatus()))) .sorted(Comparator.comparing(GroupStat::getTotal).reversed()) .collect(Collectors.toList())); // 鿣æç级 vo.setHazardByLevel(groupByInteger(hazards, MesSafetyHazardDO::getHazardLevel, HAZARD_LEVEL_NAMES, h -> MesSafetyHazardDO.STATUS_CLOSED.equals(h.getStatus()))); // éæ£ææ¥æº vo.setHazardBySource(groupByInteger(hazards, MesSafetyHazardDO::getSource, HAZARD_SOURCE_NAMES, h -> MesSafetyHazardDO.STATUS_CLOSED.equals(h.getStatus()))); // ========== ä½ä¸ç¥¨ ========== List<MesSafetyWorkTicketDO> tickets = ticketMapper.selectAllList().stream() .filter(t -> inRange(t.getCreateTime(), reqVO)) .filter(t -> matchWorkshop(t.getWorkshopId(), reqVO)) .collect(Collectors.toList()); long ticketArchived = tickets.stream() .filter(t -> MesSafetyWorkTicketDO.STATUS_ARCHIVED.equals(t.getStatus())).count(); long ticketRejected = tickets.stream() .filter(t -> MesSafetyWorkTicketDO.STATUS_REJECTED.equals(t.getStatus())).count(); summary.setTicketTotal((long) tickets.size()); summary.setTicketArchived(ticketArchived); summary.setTicketRejected(ticketRejected); vo.setTicketByType(groupByInteger(tickets, MesSafetyWorkTicketDO::getTicketType, TICKET_TYPE_NAMES, t -> MesSafetyWorkTicketDO.STATUS_ARCHIVED.equals(t.getStatus()))); vo.setTicketByStatus(groupByInteger(tickets, MesSafetyWorkTicketDO::getStatus, null, t -> MesSafetyWorkTicketDO.STATUS_ARCHIVED.equals(t.getStatus()))); // ========== å¹è® ========== List<MesSafetyTrainingDO> trainings = trainingMapper.selectAllList().stream() .filter(t -> inRange(t.getCreateTime(), reqVO)) .collect(Collectors.toList()); long attendeeTotal = trainings.stream() .mapToLong(t -> t.getAttendeeCount() == null ? 0 : t.getAttendeeCount()).sum(); BigDecimal scoreSum = BigDecimal.ZERO; int scoredCount = 0; for (MesSafetyTrainingDO t : trainings) { if (t.getAvgScore() != null) { scoreSum = scoreSum.add(t.getAvgScore()); scoredCount++; } } summary.setTrainingTotal((long) trainings.size()); summary.setTrainingAttendee(attendeeTotal); summary.setTrainingAvgScore(scoredCount > 0 ? scoreSum.divide(BigDecimal.valueOf(scoredCount), 1, RoundingMode.HALF_UP) : null); vo.setTrainingByType(groupByInteger(trainings, MesSafetyTrainingDO::getTrainingType, TRAINING_TYPE_NAMES, t -> MesSafetyTrainingDO.STATUS_FINISHED.equals(t.getStatus()))); // ========== è¯ä¹¦ ========== List<MesSafetyCertificateDO> certificates = certificateMapper.selectAllList().stream() .filter(c -> inRange(c.getCreateTime(), reqVO)) .collect(Collectors.toList()); long certExpired = certificates.stream() .filter(c -> c.getExpireDate() != null && c.getExpireDate().isBefore(today)) .count(); summary.setCertificateTotal((long) certificates.size()); summary.setCertificateExpired(certExpired); vo.setCertificateByType(groupByInteger(certificates, MesSafetyCertificateDO::getCertType, CERT_TYPE_NAMES, c -> MesSafetyCertificateDO.STATUS_VALID.equals(c.getStatus()))); vo.setSummary(summary); return vo; } // ==================== å·¥å · ==================== /** * éç¨åç»ç»è®¡ï¼æ Integer åæ®µåç»ï¼è¾åºåç§°/æ°é/已宿/宿ç */ private <T> List<GroupStat> groupByInteger(List<T> list, java.util.function.Function<T, Integer> keyFn, String[] nameArray, java.util.function.Predicate<T> finishedFn) { Map<Integer, List<T>> grouped = list.stream() .filter(item -> keyFn.apply(item) != null) .collect(Collectors.groupingBy(keyFn)); return grouped.entrySet().stream() .map(e -> { Integer key = e.getKey(); String name = resolveName(key, nameArray); return buildStat(name, key, e.getValue(), finishedFn); }) .sorted(Comparator.comparing(GroupStat::getTotal).reversed()) .collect(Collectors.toList()); } private String resolveName(Integer key, String[] nameArray) { if (nameArray != null && key >= 0 && key < nameArray.length && nameArray[key] != null) { return nameArray[key]; } // ç¶æç±»åå ¸æ²¡æéç¨åç§°æ°ç»ï¼ç´æ¥æå·²ç¥å¼æ å° return switch (key) { case 0 -> "å¾ å¤ç"; case 10 -> "å¤çä¸"; case 20 -> "已宿"; case 30 -> "已彿¡£"; case 90 -> "已驳å"; default -> "å ¶ä»(" + key + ")"; }; } private <T> GroupStat buildStat(String name, Integer code, List<T> items, java.util.function.Predicate<T> finishedFn) { GroupStat stat = new GroupStat(); stat.setName(name); stat.setCode(code); stat.setTotal((long) items.size()); long finished = items.stream().filter(finishedFn).count(); stat.setFinished(finished); stat.setFinishRate(rate(finished, items.size())); return stat; } private BigDecimal rate(long part, long total) { if (total <= 0) { return BigDecimal.ZERO; } return BigDecimal.valueOf(part * 100.0 / total).setScale(1, RoundingMode.HALF_UP); } /** * æ¶é´èå´è¿æ»¤ï¼æå建æ¶é´ï¼å«é¦å°¾ä¸¤å¤©ï¼ */ private boolean inRange(LocalDateTime createTime, MesSafetyStatisticsReqVO reqVO) { if (reqVO.getStartDate() == null && reqVO.getEndDate() == null) { return true; } if (createTime == null) { return false; } if (reqVO.getStartDate() != null && createTime.isBefore(reqVO.getStartDate().atStartOfDay())) { return false; } if (reqVO.getEndDate() != null && createTime.isAfter(reqVO.getEndDate().atTime(23, 59, 59))) { return false; } return true; } private boolean matchWorkshop(Long workshopId, MesSafetyStatisticsReqVO reqVO) { return reqVO.getWorkshopId() == null || Objects.equals(workshopId, reqVO.getWorkshopId()); } }