Răsfoiți Sursa

pms 瑞恒设备利用率

zhangcl 14 ore în urmă
părinte
comite
c62a34c32f

+ 1 - 0
yudao-module-pms/yudao-module-pms-api/src/main/java/cn/iocoder/yudao/module/pms/enums/ErrorCodeConstant.java

@@ -95,4 +95,5 @@ public interface ErrorCodeConstant{
     ErrorCode IOT_RD_DAILY_REPORT_NOT_EXISTS = new ErrorCode(270, "瑞都日报不存在");
     ErrorCode IOT_RD_DAILY_REPORT_ITEM_NOT_EXISTS = new ErrorCode(271, "瑞都日报 (工作量)明细不存在");
     ErrorCode IOT_DAILY_REPORT_TIME_NOT_EXISTS = new ErrorCode(272, "未传递创建时间查询参数");
+    ErrorCode IOT_DAILY_REPORT_DEPT_NOT_EXISTS = new ErrorCode(273, "未选择项目部");
 }

+ 280 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/stat/IotStaticController.java

@@ -1,6 +1,7 @@
 package cn.iocoder.yudao.module.pms.controller.admin.stat;
 
 import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.iocoder.yudao.framework.common.exception.ErrorCode;
 import cn.iocoder.yudao.framework.common.exception.ServiceException;
@@ -24,6 +25,8 @@ import cn.iocoder.yudao.module.pms.controller.admin.iotrydailyreport.vo.IotRyDai
 import cn.iocoder.yudao.module.pms.controller.admin.iotrydailyreport.vo.IotRyDailyReportTaskCountVO;
 import cn.iocoder.yudao.module.pms.controller.admin.maintain.vo.IotMaintainPageReqVO;
 import cn.iocoder.yudao.module.pms.controller.admin.stat.vo.OrderVo;
+import cn.iocoder.yudao.module.pms.controller.admin.stat.vo.ProjectUtilizationRateVo;
+import cn.iocoder.yudao.module.pms.controller.admin.stat.vo.TeamUtilizationRateVo;
 import cn.iocoder.yudao.module.pms.controller.admin.stat.vo.YearTotalGas;
 import cn.iocoder.yudao.module.pms.controller.admin.vo.DeviceVO;
 import cn.iocoder.yudao.module.pms.controller.admin.vo.IotDevicePageReqVO;
@@ -36,6 +39,7 @@ import cn.iocoder.yudao.module.pms.dal.dataobject.inspect.IotInspectPlanDO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotcountdata.IotCountDataDO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotmainworkorder.IotMainWorkOrderDO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotoutbound.IotOutboundDO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotrhdailyreport.IotRhDailyReportDO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotsapstock.IotSapStockDO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.maintain.IotMaintainDO;
 import cn.iocoder.yudao.module.pms.dal.mysql.IotDeviceMapper;
@@ -60,6 +64,7 @@ import cn.iocoder.yudao.module.pms.service.maintain.IotMaintainService;
 import cn.iocoder.yudao.module.system.api.dept.DeptApi;
 import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
+import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptListReqVO;
 import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
 import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO;
 import cn.iocoder.yudao.module.system.service.dept.DeptService;
@@ -83,17 +88,22 @@ import javax.annotation.security.PermitAll;
 import javax.validation.Valid;
 import java.io.Serializable;
 import java.math.BigDecimal;
+import java.math.RoundingMode;
 import java.sql.Timestamp;
 import java.text.DecimalFormat;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
+import java.time.temporal.ChronoUnit;
 import java.util.*;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.stream.Collectors;
 
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*;
+import static cn.iocoder.yudao.module.pms.enums.ErrorCodeConstant.IOT_DAILY_REPORT_DEPT_NOT_EXISTS;
+import static cn.iocoder.yudao.module.pms.enums.ErrorCodeConstant.IOT_DAILY_REPORT_TIME_NOT_EXISTS;
 
 @Tag(name = "统计接口")
 @RestController
@@ -1421,5 +1431,275 @@ public class IotStaticController {
         ImmutableMap<String, Serializable> yearResult = ImmutableMap.of("name", "年累完井数~~en**annualFinished", "data", yearData);
         return success(ImmutableMap.of("xAxis", xAxis, "series", ImmutableList.of(dailyResult, monthResult, yearResult)));
     }
+
+    /**
+     * 瑞恒 设备利用率 按项目部统计
+     * @return
+     */
+    @GetMapping("/rh/device/utilizationRate")
+    @PermitAll
+    public CommonResult<List<ProjectUtilizationRateVo>> utilizationRate(IotRhDailyReportPageReqVO reqVO) {
+        if (ObjUtil.isEmpty(reqVO.getCreateTime())) {
+            throw exception(IOT_DAILY_REPORT_TIME_NOT_EXISTS);
+        }
+        if (reqVO.getCreateTime().length < 2) {
+            throw exception(IOT_DAILY_REPORT_TIME_NOT_EXISTS);
+        }
+        // 各项目部的设备利用率集合
+        List<ProjectUtilizationRateVo> rates = new ArrayList<>();
+        // 查询瑞恒 157l 所有项目部
+        Set<Long> childDeptIds = deptService.getChildDeptIdListFromCache(157l);
+        Map<Long, DeptDO> allDeptPair = deptService.getDeptMap(childDeptIds);
+        Set<String> projectDeptNames = new HashSet<>();
+        Set<Long> projectDeptIds = new HashSet<>();
+        // key项目部id   value项目部名称
+        Map<Long, String> projectPair = new HashMap<>();
+        // key项目部id   value项目部包含的队伍id集合
+        Map<Long, Set<Long>> projectTeamPair = new HashMap<>();
+        if (CollUtil.isNotEmpty(allDeptPair)) {
+            allDeptPair.forEach((deptId, dept) -> {
+                if (dept.getName().contains("项目部") ) {
+                    projectDeptIds.add(deptId);
+                    projectDeptNames.add(dept.getName());
+                    projectPair.put(deptId, dept.getName());
+                }
+            });
+            // 遍历所有部门
+            allDeptPair.forEach((deptId, dept) -> {
+                // 找出每个项目部下的队伍
+                if (projectPair.containsKey(dept.getParentId())) {
+                    // 获得当前部门的上级项目部
+                    projectPair.forEach((projectDeptId, projectDept) -> {
+                        if (projectDeptId.equals(dept.getParentId())) {
+                            if (projectTeamPair.containsKey(projectDeptId)) {
+                                Set<Long> teamIds = projectTeamPair.get(projectDeptId);
+                                teamIds.add(deptId);
+                                projectTeamPair.put(projectDeptId, teamIds);
+                            } else {
+                                Set<Long> teamIds = new HashSet<>();
+                                teamIds.add(deptId);
+                                projectTeamPair.put(projectDeptId, teamIds);
+                            }
+                        }
+                    });
+                }
+            });
+        }
+        // 查询出指定时间区间内 已经填写的日报数量
+        List<IotRhDailyReportDO> dailyReports = iotRhDailyReportMapper.dailyReports(reqVO);
+        // key项目部id     value项目部包含的队伍指定时间区域内日报数量
+        Map<Long, Integer> projectReportPair = new HashMap<>();
+        if (CollUtil.isNotEmpty(dailyReports)) {
+            // 整理出每个项目部下的队伍填报的日报数量
+            dailyReports.forEach(report -> {
+                if (CollUtil.isNotEmpty(projectTeamPair)) {
+                    projectTeamPair.forEach((projectDeptId, teamDeptIds) -> {
+                        if (teamDeptIds.contains(report.getDeptId())) {
+                            if (projectReportPair.containsKey(projectDeptId)) {
+                                Integer tempCount = projectReportPair.get(projectDeptId);
+                                projectReportPair.put(projectDeptId, ++tempCount);
+                            } else {
+                                projectReportPair.put(projectDeptId, 1);
+                            }
+                        }
+                    });
+                }
+
+            });
+            // 计算指定时间区间内包含的天数
+            long daysCount;
+            if (ObjUtil.isNotEmpty(reqVO.getCreateTime()) && reqVO.getCreateTime().length >= 2) {
+                LocalDateTime start = reqVO.getCreateTime()[0];
+                LocalDateTime end = reqVO.getCreateTime()[1];
+
+                if (ObjUtil.isNotEmpty(start) && ObjUtil.isNotEmpty(end) && !end.isBefore(start)) {
+                    // 使用ChronoUnit.DAYS.between计算天数差,并+1包含首尾两天
+                    daysCount = ChronoUnit.DAYS.between(
+                            start.toLocalDate(),
+                            end.toLocalDate()
+                    ) + 1;
+                } else {
+                    daysCount = 0L;
+                }
+            } else {
+                daysCount = 0L;
+            }
+            // 计算每个项目部的设备利用率
+            if (CollUtil.isNotEmpty(projectTeamPair)) {
+
+                projectTeamPair.forEach((projectDeptId, teamIds) -> {
+                    ProjectUtilizationRateVo rateVo = new ProjectUtilizationRateVo();
+                    rateVo.setProjectDeptId(projectDeptId);
+                    if (projectPair.containsKey(projectDeptId)) {
+                        rateVo.setProjectDeptName(projectPair.get(projectDeptId));
+                    }
+                    // 遍历每个项目部 获取每个项目部下队伍数量
+                    Integer currentTeamNum = teamIds.size();
+                    rateVo.setTeamCount(currentTeamNum);
+                    rateVo.setCumulativeDays(currentTeamNum * daysCount);
+                    // 匹配出当前项目部下 日报数量
+                    if (projectReportPair.containsKey(projectDeptId)) {
+                        Integer reportCount = projectReportPair.getOrDefault(projectDeptId, 0);
+                        rateVo.setConstructionDays(reportCount);
+                        // 当前项目部 设备利用率 公式 reportCount/(currentTeamNum*daysCount)
+                        // 计算设备利用率(处理除数为0的情况)
+                        double rate = 0.0;
+                        if (currentTeamNum > 0 && daysCount > 0) {
+                            rate = new BigDecimal((double) reportCount / (currentTeamNum * daysCount))
+                                    .setScale(4, RoundingMode.HALF_UP)  // 保留4位小数,四舍五入
+                                    .doubleValue();;
+                        }
+                        rateVo.setUtilizationRate(rate); // 存储计算结果
+                    }
+                    rates.add(rateVo);
+                });
+            }
+        }
+        rates.sort(Comparator.comparingDouble(ProjectUtilizationRateVo::getUtilizationRate).reversed());
+        return success(rates);
+    }
+
+    /**
+     * 瑞恒 设备利用率 按 队伍 统计
+     * @return
+     */
+    @GetMapping("/rh/device/teamUtilizationRate")
+    @PermitAll
+    public CommonResult<List<TeamUtilizationRateVo>> teamUtilizationRate(IotRhDailyReportPageReqVO reqVO) {
+        if (ObjUtil.isEmpty(reqVO.getCreateTime())) {
+            throw exception(IOT_DAILY_REPORT_TIME_NOT_EXISTS);
+        }
+        if (reqVO.getCreateTime().length < 2) {
+            throw exception(IOT_DAILY_REPORT_TIME_NOT_EXISTS);
+        }
+        // 必须传递 项目部id 查询队伍数据
+        if (ObjUtil.isEmpty(reqVO.getDeptId())) {
+            throw exception(IOT_DAILY_REPORT_DEPT_NOT_EXISTS);
+        }
+
+        // 指定项目部的各队伍设备利用率集合
+        List<TeamUtilizationRateVo> rates = new ArrayList<>();
+
+        // 查询指定项目部下的 队伍集合
+        DeptListReqVO deptReqVO = new DeptListReqVO();
+        deptReqVO.setDeptId(reqVO.getDeptId());
+        List<DeptDO> projectTeams = deptService.getDeptListByParentId(deptReqVO);
+        // 指定项目部下的 队伍id集合
+        Set<Long> projectTeamIds = new HashSet<>();
+        if (CollUtil.isNotEmpty(projectTeams)) {
+            projectTeams.forEach(team -> {
+                projectTeamIds.add(team.getId());
+            });
+        }
+
+        Map<Long, DeptDO> allDeptPair = deptService.getDeptMap(projectTeamIds);
+
+        Set<String> projectDeptNames = new HashSet<>();
+        Set<Long> projectDeptIds = new HashSet<>();
+        // key项目部id   value项目部名称
+        Map<Long, String> projectPair = new HashMap<>();
+        // key队伍id   value队伍名称
+        Map<Long, String> teamPair = new HashMap<>();
+        // key项目部id   value项目部包含的队伍id集合
+        Map<Long, Set<Long>> projectTeamPair = new HashMap<>();
+        // key队伍id   value队伍日报数量
+        Map<Long, Long> teamReportCountPair = new HashMap<>();
+        if (CollUtil.isNotEmpty(allDeptPair)) {
+            allDeptPair.forEach((deptId, dept) -> {
+                if (dept.getName().contains("项目部") ) {
+                    projectDeptIds.add(deptId);
+                    projectDeptNames.add(dept.getName());
+                    projectPair.put(deptId, dept.getName());
+                }
+                teamPair.put(deptId, dept.getName());
+            });
+            // 遍历所有部门
+            allDeptPair.forEach((deptId, dept) -> {
+                // 找出每个项目部下的队伍
+                if (projectPair.containsKey(dept.getParentId())) {
+                    // 获得当前部门的上级项目部
+                    projectPair.forEach((projectDeptId, projectDept) -> {
+                        if (projectDeptId.equals(dept.getParentId())) {
+                            if (projectTeamPair.containsKey(projectDeptId)) {
+                                Set<Long> teamIds = projectTeamPair.get(projectDeptId);
+                                teamIds.add(deptId);
+                                projectTeamPair.put(projectDeptId, teamIds);
+                            } else {
+                                Set<Long> teamIds = new HashSet<>();
+                                teamIds.add(deptId);
+                                projectTeamPair.put(projectDeptId, teamIds);
+                            }
+                        }
+                    });
+                }
+            });
+        }
+        if (CollUtil.isNotEmpty(projectTeamIds)) {
+            // 查询出指定时间区间内 指定队伍id集合 已经填写的日报数量
+            reqVO.setDeptIds(projectTeamIds);
+            List<IotRhDailyReportDO> dailyReports = iotRhDailyReportMapper.dailyReports(reqVO);
+            // 筛选出每个队伍的日报
+            if (CollUtil.isNotEmpty(dailyReports)) {
+                // 整理出每个项队伍填报的日报数量
+                dailyReports.forEach(report -> {
+                    if (teamReportCountPair.containsKey(report.getDeptId())) {
+                        Long tempCount = teamReportCountPair.get(report.getDeptId());
+                        teamReportCountPair.put(report.getDeptId(), ++tempCount);
+                    } else {
+                        teamReportCountPair.put(report.getDeptId(), 1l);
+                    }
+                });
+                // 计算指定时间区间内包含的天数
+                long daysCount;
+                if (ObjUtil.isNotEmpty(reqVO.getCreateTime()) && reqVO.getCreateTime().length >= 2) {
+                    LocalDateTime start = reqVO.getCreateTime()[0];
+                    LocalDateTime end = reqVO.getCreateTime()[1];
+
+                    if (ObjUtil.isNotEmpty(start) && ObjUtil.isNotEmpty(end) && !end.isBefore(start)) {
+                        // 使用ChronoUnit.DAYS.between计算天数差,并+1包含首尾两天
+                        daysCount = ChronoUnit.DAYS.between(
+                                start.toLocalDate(),
+                                end.toLocalDate()
+                        ) + 1;
+                    } else {
+                        daysCount = 0L;
+                    }
+                } else {
+                    daysCount = 0L;
+                }
+                // 计算每个队伍的设备利用率
+                if (CollUtil.isNotEmpty(projectTeamIds)) {
+                    projectTeamIds.forEach(teamId -> {
+                        TeamUtilizationRateVo rateVo = new TeamUtilizationRateVo();
+                        rateVo.setProjectDeptId(reqVO.getDeptId());
+                        rateVo.setTeamId(teamId);
+                        rateVo.setCumulativeDays(daysCount);
+                        if (teamPair.containsKey(teamId)) {
+                            rateVo.setTeamName(teamPair.get(teamId));
+                        }
+                        // 匹配出当前小队 日报数量
+                        Long reportCount = 0l;
+                        if (teamReportCountPair.containsKey(teamId)) {
+                            reportCount = teamReportCountPair.getOrDefault(teamId, 0l);
+                            rateVo.setConstructionDays(reportCount);
+                        }
+                        // 当前小队 设备利用率 公式 reportCount/daysCount
+                        // 计算设备利用率(处理除数为0的情况)
+                        double rate = 0.0;
+                        if (reportCount > 0 && daysCount > 0) {
+                            rate = new BigDecimal((double) reportCount /  daysCount)
+                                    .setScale(4, RoundingMode.HALF_UP)  // 保留4位小数,四舍五入
+                                    .doubleValue();;
+                        }
+                        rateVo.setUtilizationRate(rate); // 存储计算结果
+                        rates.add(rateVo);
+                    });
+                }
+            }
+        }
+        rates.sort(Comparator.comparingDouble(TeamUtilizationRateVo::getUtilizationRate).reversed());
+        return success(rates);
+    }
+
 }
 

+ 37 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/stat/vo/ProjectUtilizationRateVo.java

@@ -0,0 +1,37 @@
+package cn.iocoder.yudao.module.pms.controller.admin.stat.vo;
+
+import lombok.Data;
+import lombok.ToString;
+
+/**
+ * 项目部维度 设备利用率
+ */
+@Data
+@ToString(callSuper = true)
+public class ProjectUtilizationRateVo {
+    /**
+     * 项目部id
+     */
+    private Long projectDeptId;
+    /**
+     * 项目部名称
+     */
+    private String projectDeptName;
+    /**
+     * 施工队伍数
+     */
+    private Integer teamCount;
+    /**
+     * 累计天数
+     */
+    private Long cumulativeDays;
+    /**
+     * 施工天数
+     */
+    private Integer constructionDays;
+
+    /**
+     * 设备利用率
+     */
+    private Double utilizationRate;
+}

+ 41 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/stat/vo/TeamUtilizationRateVo.java

@@ -0,0 +1,41 @@
+package cn.iocoder.yudao.module.pms.controller.admin.stat.vo;
+
+import lombok.Data;
+import lombok.ToString;
+
+/**
+ * 队伍维度 设备利用率
+ */
+@Data
+@ToString(callSuper = true)
+public class TeamUtilizationRateVo {
+    /**
+     * 项目部id
+     */
+    private Long projectDeptId;
+    /**
+     * 项目部名称
+     */
+    private String projectDeptName;
+    /**
+     * 施工队伍id
+     */
+    private Long teamId;
+    /**
+     * 施工队伍名称
+     */
+    private String teamName;
+    /**
+     * 累计天数
+     */
+    private Long cumulativeDays;
+    /**
+     * 施工天数
+     */
+    private Long constructionDays;
+
+    /**
+     * 设备利用率
+     */
+    private Double utilizationRate;
+}

+ 1 - 1
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/iotrhdailyreport/IotRhDailyReportMapper.java

@@ -89,7 +89,7 @@ public interface IotRhDailyReportMapper extends BaseMapperX<IotRhDailyReportDO>
 
     default List<IotRhDailyReportDO> dailyReports(IotRhDailyReportPageReqVO reqVO) {
         return selectList(new LambdaQueryWrapperX<IotRhDailyReportDO>()
-                .eqIfPresent(IotRhDailyReportDO::getDeptId, reqVO.getDeptId())
+                .inIfPresent(IotRhDailyReportDO::getDeptId, reqVO.getDeptIds())
                 .eqIfPresent(IotRhDailyReportDO::getProjectId, reqVO.getProjectId())
                 .eqIfPresent(IotRhDailyReportDO::getTaskId, reqVO.getTaskId())
                 .eqIfPresent(IotRhDailyReportDO::getProjectClassification, reqVO.getProjectClassification())

+ 8 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dept/DeptService.java

@@ -60,6 +60,14 @@ public interface DeptService {
      */
     List<DeptDO> getDeptList(DeptListReqVO reqVO);
 
+    /**
+     * 根据父部门id 筛选部门列表
+     *
+     * @param reqVO 筛选条件请求 VO
+     * @return 部门列表
+     */
+    List<DeptDO> getDeptListByParentId(DeptListReqVO reqVO);
+
     /**
      * 忽略租户 查询所有部门列表
      *

+ 7 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dept/DeptServiceImpl.java

@@ -258,6 +258,13 @@ public class DeptServiceImpl implements DeptService {
         return list;
     }
 
+    @Override
+    public List<DeptDO> getDeptListByParentId(DeptListReqVO reqVO) {
+        List<Long> deptIds = new ArrayList<>();
+        deptIds.add(reqVO.getDeptId());
+        return deptMapper.selectListByParentId(deptIds);
+    }
+
     @Override
     public List<DeptDO> ignoredTenantDepts(DeptListReqVO reqVO) {
         return deptMapper.allDepts();