diff --git a/ruoyi-modules/hwmom-mes/src/main/java/org/dromara/mes/controller/ProdReportController.java b/ruoyi-modules/hwmom-mes/src/main/java/org/dromara/mes/controller/ProdReportController.java index 831efd34..437a37c6 100644 --- a/ruoyi-modules/hwmom-mes/src/main/java/org/dromara/mes/controller/ProdReportController.java +++ b/ruoyi-modules/hwmom-mes/src/main/java/org/dromara/mes/controller/ProdReportController.java @@ -192,4 +192,22 @@ public class ProdReportController extends BaseController { return R.ok(vos); } + /** + * 工序工单统计(按工序聚合):完成数量、未完成数量与完成率 + */ + @GetMapping("/processWorkOrderStats") + public R>> processWorkOrderStats(@RequestParam(required = false) Map hashMap) { + List> vos = prodReportService.processWorkOrderStats(hashMap); + return R.ok(vos); + } + + /** + * 工序下的计划子节点查询:按 plan_code + process_id 过滤,关联明细表 + */ + @GetMapping("/planProcessChildren") + public R>> planProcessChildren(@RequestParam(required = false) Map hashMap) { + List> vos = prodReportService.planProcessDetailChildren(hashMap); + return R.ok(vos); + } + } diff --git a/ruoyi-modules/hwmom-mes/src/main/java/org/dromara/mes/domain/vo/ProcessProgressVo.java b/ruoyi-modules/hwmom-mes/src/main/java/org/dromara/mes/domain/vo/ProcessProgressVo.java index 832e24b5..601d850a 100644 --- a/ruoyi-modules/hwmom-mes/src/main/java/org/dromara/mes/domain/vo/ProcessProgressVo.java +++ b/ruoyi-modules/hwmom-mes/src/main/java/org/dromara/mes/domain/vo/ProcessProgressVo.java @@ -23,6 +23,7 @@ public class ProcessProgressVo implements Serializable { * 产品订单ID(用于批量查询结果分组) */ private Long productOrderId; + private String planCode; /** * 工序ID @@ -98,4 +99,22 @@ public class ProcessProgressVo implements Serializable { * 实际结束时间 */ private LocalDateTime realEndTime; + + /** + * 物料名称(来自计划表关联的物料) + */ + private String materialName; + + /** + * 物料编码(来自计划表关联的物料) + */ + private String materialCode; + + // public String getPlanCode() { + // return planCode; + // } + + // public void setPlanCode(String planCode) { + // this.planCode = planCode; + // } } \ No newline at end of file diff --git a/ruoyi-modules/hwmom-mes/src/main/java/org/dromara/mes/mapper/ProdReportMapper.java b/ruoyi-modules/hwmom-mes/src/main/java/org/dromara/mes/mapper/ProdReportMapper.java index 24cb9413..88376a8a 100644 --- a/ruoyi-modules/hwmom-mes/src/main/java/org/dromara/mes/mapper/ProdReportMapper.java +++ b/ruoyi-modules/hwmom-mes/src/main/java/org/dromara/mes/mapper/ProdReportMapper.java @@ -124,22 +124,40 @@ public interface ProdReportMapper { Long wipTrackingReportCount(@Param("map") Map hashMap); /** - * 获取订单的工序进度详情(单订单) + * 工序下的计划子节点查询:按 plan_code + process_id 过滤,关联明细表 */ - List getOrderProcessProgress(@Param("productOrderId") Long productOrderId, @Param("planTableName") String planTableName); + List> getPlanProcessDetailChildren(@Param("planCode") String planCode, + @Param("processId") Long processId, + @Param("detailTableName") String detailTableName, + @Param("planTableName") String planTableName, + @Param("tenantId") String tenantId); /** - * 批量获取订单的工序进度详情(避免N+1,一次查询一个工序表) - * @param productOrderIds 订单ID列表 + * 获取计划的工序进度详情(单计划,按planCode) + */ + List getPlanProcessProgress(@Param("planCode") String planCode, + @Param("planTableName") String planTableName); + + /** + * 批量获取计划的工序进度详情(按planCode批量) + * @param planCodes 计划编码列表 * @param planTableName 工序表名(prod_plan_info_2/_3/_4) + * @param tenantId 租户ID(可选) * @return 工序进度明细 */ - List getOrdersProcessProgressBatch(@Param("productOrderIds") List productOrderIds, - @Param("planTableName") String planTableName, - @Param("tenantId") String tenantId); + List getPlansProcessProgressBatch(@Param("planCodes") List planCodes, + @Param("planTableName") String planTableName, + @Param("tenantId") String tenantId); // 新增:小时产量统计(按结束时间小时分桶) List> hourlyOutputByHour(@Param("map") Map hashMap, @Param("detailTableName") String detailTableName, @Param("planTableName") String planTableName); + + /** + * 工序工单统计(按工序聚合) + * 返回各工序的未开工、在制未完成、延期未完成、完成率等指标 + */ + List> processWorkOrderStats(@Param("map") Map hashMap, + @Param("planTableName") String planTableName); } diff --git a/ruoyi-modules/hwmom-mes/src/main/java/org/dromara/mes/service/IProdReportService.java b/ruoyi-modules/hwmom-mes/src/main/java/org/dromara/mes/service/IProdReportService.java index 133f0e54..4f03c98f 100644 --- a/ruoyi-modules/hwmom-mes/src/main/java/org/dromara/mes/service/IProdReportService.java +++ b/ruoyi-modules/hwmom-mes/src/main/java/org/dromara/mes/service/IProdReportService.java @@ -136,4 +136,18 @@ public interface IProdReportService { */ List> hourlyOutputByHour(Map hashMap); + /** + * 工序工单统计(按工序聚合):完成数量、未完成数量与完成率 + * @param hashMap 查询条件:beginDate/endDate、processId、machineId、shiftId、classTeamId、materialName + * @return 各工序聚合统计列表 + */ + List> processWorkOrderStats(Map hashMap); + + /** + * 工序下的计划子节点查询:按 plan_code + process_id 过滤,关联明细表 + * @param hashMap 查询条件:planCode、processId + * @return 计划明细子节点列表 + */ + List> planProcessDetailChildren(Map hashMap); + } diff --git a/ruoyi-modules/hwmom-mes/src/main/java/org/dromara/mes/service/impl/ProdReportServiceImpl.java b/ruoyi-modules/hwmom-mes/src/main/java/org/dromara/mes/service/impl/ProdReportServiceImpl.java index 4378a870..5586c5b3 100644 --- a/ruoyi-modules/hwmom-mes/src/main/java/org/dromara/mes/service/impl/ProdReportServiceImpl.java +++ b/ruoyi-modules/hwmom-mes/src/main/java/org/dromara/mes/service/impl/ProdReportServiceImpl.java @@ -172,7 +172,7 @@ public class ProdReportServiceImpl implements IProdReportService { // 新增辅助方法用于安全解析 processId private Long parseProcessId(Object processIdObj) { if (processIdObj == null) { - return null; // 或者根据业务需要返回默认值如 16L + return null; } try { @@ -208,6 +208,14 @@ public class ProdReportServiceImpl implements IProdReportService { */ @Override public TableDataInfo wipTrackingReportList(Map hashMap, PageQuery pageQuery) { + // 注入租户范围,确保仅查询当前租户数据 + try { + String tenantId = LoginHelper.getTenantId(); + if (tenantId != null && !tenantId.isEmpty()) { + hashMap.put("tenantId", tenantId); + } + } catch (Exception ignore) { + } // 使用优化后的SQL查询,大部分计算已在数据库层完成 // 关闭自动 count,避免对复杂 CTE SQL 的解析失败 Page mpPage = pageQuery.build(); @@ -237,6 +245,15 @@ public class ProdReportServiceImpl implements IProdReportService { */ @Override public List wipTrackingReportList(Map hashMap) { + // 注入租户范围,确保仅查询当前租户数据 + try { + String tenantId = LoginHelper.getTenantId(); + if (tenantId != null && !tenantId.isEmpty()) { + hashMap.put("tenantId", tenantId); + } + } catch (Exception ignore) { + } + // 使用优化后的SQL查询,大部分计算已在数据库层完成 List list = prodReportMapper.wipTrackingReportList(hashMap); @@ -255,28 +272,28 @@ public class ProdReportServiceImpl implements IProdReportService { return; } - // 批量获取所有订单的工序进度信息 - Map> orderProcessMap = new HashMap<>(); + // 批量获取所有计划的工序进度信息(按planCode维度) + Map> planProcessMap = new HashMap<>(); try { - // 收集所有需要查询的订单ID - List orderIds = reportList.stream() - .map(WipTrackingReportVo::getProductOrderId) - .filter(Objects::nonNull) + // 收集所有需要查询的计划编码 + List planCodes = reportList.stream() + .map(WipTrackingReportVo::getPlanCode) + .filter(code -> code != null && !code.isEmpty()) .distinct() .collect(Collectors.toList()); - if (orderIds.isEmpty()) { + if (planCodes.isEmpty()) { return; } - // 批量查询各个工序表的进度信息 - batchQueryProcessProgress(orderIds, orderProcessMap); + // 批量查询各个工序表的进度信息(按计划编码) + batchQueryProcessProgress(planCodes, planProcessMap); // 为每个报表项设置工序进度信息 for (WipTrackingReportVo vo : reportList) { - if (vo.getProductOrderId() != null) { - List processProgress = orderProcessMap.get(vo.getProductOrderId()); + if (vo.getPlanCode() != null && !vo.getPlanCode().isEmpty()) { + List processProgress = planProcessMap.get(vo.getPlanCode()); if (processProgress != null && !processProgress.isEmpty()) { vo.setProcessProgressList(processProgress); // 基于实际工序进度微调计算结果 @@ -288,7 +305,7 @@ public class ProdReportServiceImpl implements IProdReportService { } } catch (Exception e) { - System.out.println("批量获取工序进度信息失败: " + e.getMessage()); + System.out.println("批量获取工序进度信息失败(按planCode): " + e.getMessage()); // 降级处理:为每个订单单独查询 fallbackToIndividualQuery(reportList); } @@ -299,18 +316,18 @@ public class ProdReportServiceImpl implements IProdReportService { * @param orderIds 订单ID列表 * @param orderProcessMap 结果映射 */ - private void batchQueryProcessProgress(List orderIds, Map> orderProcessMap) { + private void batchQueryProcessProgress(List planCodes, Map> planProcessMap) { // 查询半制品工序进度(prod_plan_info_2) - queryProcessProgressByTable(orderIds, "prod_plan_info_2", orderProcessMap); + queryProcessProgressByTable(planCodes, "prod_plan_info_2", planProcessMap); // 查询成型工序进度(prod_plan_info_3) - queryProcessProgressByTable(orderIds, "prod_plan_info_3", orderProcessMap); + queryProcessProgressByTable(planCodes, "prod_plan_info_3", planProcessMap); // 查询硫化工序进度(prod_plan_info_4) - queryProcessProgressByTable(orderIds, "prod_plan_info_4", orderProcessMap); + queryProcessProgressByTable(planCodes, "prod_plan_info_4", planProcessMap); - // 对每个订单的工序进度进行排序 - orderProcessMap.values().forEach(processList -> + // 对每个计划的工序进度进行排序 + planProcessMap.values().forEach(processList -> processList.sort((a, b) -> { if (a.getProcessOrder() == null) return 1; if (b.getProcessOrder() == null) return -1; @@ -325,23 +342,23 @@ public class ProdReportServiceImpl implements IProdReportService { * @param tableName 表名 * @param orderProcessMap 结果映射 */ - private void queryProcessProgressByTable(List orderIds, String tableName, Map> orderProcessMap) { + private void queryProcessProgressByTable(List planCodes, String tableName, Map> planProcessMap) { try { - // 使用批量查询避免 N+1:一次性查询该工序表下所有订单的工序进度 - // 返回结果中包含 productOrderId 字段,便于在此处进行分组 + // 使用批量查询避免 N+1:一次性查询该工序表下所有计划的工序进度 + // 返回结果中包含 planCode 字段,便于在此处进行分组 String tenantId = LoginHelper.getTenantId(); - List batchResults = prodReportMapper.getOrdersProcessProgressBatch(orderIds, tableName, tenantId); + List batchResults = prodReportMapper.getPlansProcessProgressBatch(planCodes, tableName, tenantId); if (batchResults != null && !batchResults.isEmpty()) { for (ProcessProgressVo progress : batchResults) { - Long orderId = progress.getProductOrderId(); - if (orderId != null) { - orderProcessMap.computeIfAbsent(orderId, k -> new ArrayList<>()).add(progress); + String planCode = progress.getPlanCode(); + if (planCode != null && !planCode.isEmpty()) { + planProcessMap.computeIfAbsent(planCode, k -> new ArrayList<>()).add(progress); } } } } catch (Exception e) { // 记录失败但不中断整体处理,后续会有降级策略 - System.out.println("批量查询表 " + tableName + " 的工序进度失败: " + e.getMessage()); + System.out.println("批量查询表 " + tableName + " 的工序进度失败(按planCode): " + e.getMessage()); } } @@ -388,7 +405,7 @@ public class ProdReportServiceImpl implements IProdReportService { vo.setRemainingProcesses(remainingProcesses); } catch (Exception e) { - System.out.println("微调进度计算失败,订单ID: " + vo.getProductOrderId() + ", 错误: " + e.getMessage()); + System.out.println("微调进度计算失败,计划编码: " + vo.getPlanCode() + ", 错误: " + e.getMessage()); } } @@ -398,13 +415,13 @@ public class ProdReportServiceImpl implements IProdReportService { */ private void fallbackToIndividualQuery(List reportList) { for (WipTrackingReportVo vo : reportList) { - if (vo.getProductOrderId() != null) { + if (vo.getPlanCode() != null && !vo.getPlanCode().isEmpty()) { try { - List processProgress = getAllOrderProcessProgressOptimized(vo.getProductOrderId()); + List processProgress = getAllPlanProcessProgressOptimized(vo.getPlanCode()); vo.setProcessProgressList(processProgress); adjustProgressCalculation(vo, processProgress); } catch (Exception e) { - System.out.println("单独查询订单工序进度失败,订单ID: " + vo.getProductOrderId()); + System.out.println("单独查询计划工序进度失败,计划编码: " + vo.getPlanCode()); vo.setProcessProgressList(new ArrayList<>()); } } @@ -412,40 +429,47 @@ public class ProdReportServiceImpl implements IProdReportService { } /** - * 获取订单的所有工序进度详情(优化版本) - * @param productOrderId 产品订单ID + * 工序下的计划子节点查询:按 plan_code + process_id 过滤,关联明细表 + */ + @Override + public List> planProcessDetailChildren(Map hashMap) { + Long processId = parseProcessId(hashMap.get("processId")); + String detailTable = getPlanDetailTableNameByProcessId(processId); + String planTable = getPlanInfoTableNameByProcessId(processId); + String planCode = String.valueOf(hashMap.get("planCode")); + String tenantId = LoginHelper.getTenantId(); + return prodReportMapper.getPlanProcessDetailChildren(planCode, processId, detailTable, planTable, tenantId); + } + + /** + * 获取计划的所有工序进度详情(优化版本,按planCode) + * @param planCode 计划编码 * @return 工序进度列表 */ - private List getAllOrderProcessProgressOptimized(Long productOrderId) { + private List getAllPlanProcessProgressOptimized(String planCode) { List allProcessProgress = new java.util.ArrayList<>(); try { - // 1. 获取订单信息 - var orderInfo = prodOrderInfoMapper.selectById(productOrderId); - if (orderInfo == null) { - return allProcessProgress; - } + // 不依赖 prod_order_info,直接查询三个计划表 + String[] planTables = { + DatabaseConstants.TABLE_NAME_PROD_PLAN_INFO_PREFIX + "_2", + DatabaseConstants.TABLE_NAME_PROD_PLAN_INFO_PREFIX + "_3", + DatabaseConstants.TABLE_NAME_PROD_PLAN_INFO_PREFIX + "_4" + }; - // 2. 根据派工类型确定需要查询的工序表 - List processIds = determineProcessIds(orderInfo); - - // 3. 并行查询各工序表以提高性能 - for (Long processId : processIds) { + for (String planTableName : planTables) { try { - String planTableName = getPlanInfoTableNameByProcessId(processId); - if (planTableName != null) { - List processProgress = prodReportMapper.getOrderProcessProgress(productOrderId, planTableName); - if (processProgress != null && !processProgress.isEmpty()) { - allProcessProgress.addAll(processProgress); - } + List processProgress = prodReportMapper.getPlanProcessProgress(planCode, planTableName); + if (processProgress != null && !processProgress.isEmpty()) { + allProcessProgress.addAll(processProgress); } } catch (Exception e) { // 记录日志但不中断处理 - System.out.println("查询工序进度失败,订单ID: " + productOrderId + ", 工序ID: " + processId + ", 错误: " + e.getMessage()); + System.out.println("查询工序进度失败,计划编码: " + planCode + ", 表: " + planTableName + ", 错误: " + e.getMessage()); } } - // 4. 按工序顺序排序 + // 按工序顺序排序 allProcessProgress.sort((a, b) -> { if (a.getProcessOrder() == null) return 1; if (b.getProcessOrder() == null) return -1; @@ -453,7 +477,7 @@ public class ProdReportServiceImpl implements IProdReportService { }); } catch (Exception e) { - System.out.println("获取订单工序进度失败,订单ID: " + productOrderId + ", 错误: " + e.getMessage()); + System.out.println("获取计划工序进度失败,计划编码: " + planCode + ", 错误: " + e.getMessage()); } return allProcessProgress; @@ -595,4 +619,15 @@ public class ProdReportServiceImpl implements IProdReportService { } + /** + * 工序工单统计(按工序聚合):完成数量、未完成数量与完成率 + * 兼容传入的 processId,用于选择对应的计划表 + */ + @Override + public List> processWorkOrderStats(Map hashMap) { + Long processId = parseProcessId(hashMap.get("processId")); + String planTable = getPlanInfoTableNameByProcessId(processId); + return prodReportMapper.processWorkOrderStats(hashMap, planTable); + } + } diff --git a/ruoyi-modules/hwmom-mes/src/main/resources/mapper/mes/ProdReportMapper.xml b/ruoyi-modules/hwmom-mes/src/main/resources/mapper/mes/ProdReportMapper.xml index 4d251a72..b7e77067 100644 --- a/ruoyi-modules/hwmom-mes/src/main/resources/mapper/mes/ProdReportMapper.xml +++ b/ruoyi-modules/hwmom-mes/src/main/resources/mapper/mes/ProdReportMapper.xml @@ -1,4 +1,4 @@ - + @@ -295,21 +295,28 @@ ORDER BY ppd.real_begin_time DESC, ppi.plan_id DESC - + - + - - SELECT + p.plan_code AS planCode, p.process_id AS processId, ISNULL(pr.process_name, '未知工序') AS processName, ISNULL(p.process_order, 0) AS processOrder, @@ -491,34 +576,29 @@ CAST(ISNULL(p.plan_amount, 0) AS DECIMAL(18,2)) AS planAmount, CAST(ISNULL(p.complete_amount, 0) AS DECIMAL(18,2)) AS completeAmount, CAST(ISNULL(p.plan_amount, 0) - ISNULL(p.complete_amount, 0) AS DECIMAL(18,2)) AS remainingAmount, - -- 工序进度百分比 CAST( - CASE - WHEN ISNULL(p.plan_amount, 0) > 0 - THEN (CAST(ISNULL(p.complete_amount, 0) AS DECIMAL(18,6)) / CAST(p.plan_amount AS DECIMAL(18,6))) * 100 - ELSE 0 + CASE WHEN ISNULL(p.plan_amount, 0) > 0 + THEN (CAST(ISNULL(p.complete_amount, 0) AS DECIMAL(18,6)) / CAST(p.plan_amount AS DECIMAL(18,6))) * 100 + ELSE 0 END AS DECIMAL(10,2)) AS processProgress, - -- 计划开始时间和结束时间 p.plan_begin_time AS planBeginTime, p.plan_end_time AS planEndTime, p.real_begin_time AS realBeginTime, - p.real_end_time AS realEndTime + p.real_end_time AS realEndTime, + bmi.material_name AS materialName, + bmi.material_code AS materialCode FROM ${planTableName} p LEFT JOIN prod_base_process_info pr ON pr.process_id = p.process_id - WHERE p.product_order_id = #{productOrderId} + LEFT JOIN base_material_info bmi ON bmi.material_id = p.material_id + WHERE p.plan_code = #{planCode} ORDER BY p.process_order - - - SELECT - p.product_order_id AS productOrderId, + p.plan_code AS planCode, p.process_id AS processId, ISNULL(pr.process_name, '未知工序') AS processName, ISNULL(p.process_order, 0) AS processOrder, @@ -536,24 +616,49 @@ CAST(ISNULL(p.complete_amount, 0) AS DECIMAL(18,2)) AS completeAmount, CAST(ISNULL(p.plan_amount, 0) - ISNULL(p.complete_amount, 0) AS DECIMAL(18,2)) AS remainingAmount, CAST( - CASE - WHEN ISNULL(p.plan_amount, 0) > 0 - THEN (CAST(ISNULL(p.complete_amount, 0) AS DECIMAL(18,6)) / CAST(p.plan_amount AS DECIMAL(18,6))) * 100 - ELSE 0 + CASE WHEN ISNULL(p.plan_amount, 0) > 0 + THEN (CAST(ISNULL(p.complete_amount, 0) AS DECIMAL(18,6)) / CAST(p.plan_amount AS DECIMAL(18,6))) * 100 + ELSE 0 END AS DECIMAL(10,2)) AS processProgress, p.plan_begin_time AS planBeginTime, p.plan_end_time AS planEndTime, p.real_begin_time AS realBeginTime, - p.real_end_time AS realEndTime + p.real_end_time AS realEndTime, + bmi.material_name AS materialName, + bmi.material_code AS materialCode FROM ${planTableName} p LEFT JOIN prod_base_process_info pr ON pr.process_id = p.process_id - WHERE p.product_order_id IN - - #{id} + LEFT JOIN base_material_info bmi ON bmi.material_id = p.material_id + WHERE p.plan_code IN + + #{code} AND p.tenant_id = #{tenantId} - ORDER BY p.product_order_id, p.process_order + ORDER BY p.plan_code, p.process_order + + + + @@ -597,4 +702,59 @@ ORDER BY productionDate, DATEPART(HOUR, t.create_time) + + +