From 24467a71ed018fb2306e8d8c6b46c8a62f917b06 Mon Sep 17 00:00:00 2001 From: "zangch@mesnac.com" Date: Thu, 22 Jan 2026 09:45:38 +0800 Subject: [PATCH] =?UTF-8?q?change(report):=20=E5=AE=8C=E5=96=84board?= =?UTF-8?q?=E7=9A=84=E7=BB=B4=E4=BF=AE=E5=B9=B3=E5=9D=87=E5=93=8D=E5=BA=94?= =?UTF-8?q?=E6=97=B6=E9=97=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 明确年累计为上一自然年(上一年1月1日到12月31日,非滚动12个月) - 明确月累计为本自然月(当月1日至月末) - 明确日累计为当天(00:00-23:59) - 更新质量追溯为近7天含当天按产品统计合格率 - 添加全量历史数据查询说明(工单、维修、保养、巡检、设备状态、故障来源) - 补充近30天故障趋势查询说明 - 优化SQL查询注释,明确数据来源与处理逻辑 - 添加安全类型转换保护,避免空指针异常 - 标准化返回格式,确保前端数据稳定性 --- .../api/controller/SAPPortController.java | 2 + aucma-report/boardAPIComplete.md | 42 ++++++++--------- .../service/impl/Board4ServiceImpl.java | 46 +++++++++++++++++++ .../service/impl/Board5ServiceImpl.java | 44 ++++++++++++++++++ .../resources/mapper/report/Board4Mapper.xml | 16 +++---- .../resources/mapper/report/Board5Mapper.xml | 20 ++++---- 6 files changed, 132 insertions(+), 38 deletions(-) diff --git a/aucma-api/src/main/java/com/aucma/api/controller/SAPPortController.java b/aucma-api/src/main/java/com/aucma/api/controller/SAPPortController.java index 0c45dac..b6bb0ea 100644 --- a/aucma-api/src/main/java/com/aucma/api/controller/SAPPortController.java +++ b/aucma-api/src/main/java/com/aucma/api/controller/SAPPortController.java @@ -37,6 +37,8 @@ public class SAPPortController extends BaseController { @Autowired private ISAPPutStorageService storageService; + + /** * 获取SAP物料主数据 * @param paramMap diff --git a/aucma-report/boardAPIComplete.md b/aucma-report/boardAPIComplete.md index f24a668..e3d0e2c 100644 --- a/aucma-report/boardAPIComplete.md +++ b/aucma-report/boardAPIComplete.md @@ -243,15 +243,15 @@ public class Board4DeviceProductionVo { #### 4.2.1 日累计产量(BASE_DEVICE_PARAM_VAL) ```sql -SELECT NVL(SUM(TO_NUMBER(PARAM_VALUE)), 0) +SELECT NVL(SUM(TO_NUMBER(PARAM_VALUE)), 0) -- 汇总当天实际产出数量 FROM ( SELECT DEVICE_CODE, PARAM_VALUE, - ROW_NUMBER() OVER (PARTITION BY DEVICE_CODE ORDER BY COLLECT_TIME DESC) AS RN + ROW_NUMBER() OVER (PARTITION BY DEVICE_CODE ORDER BY COLLECT_TIME DESC) AS RN -- 每台设备取最新记录 FROM BASE_DEVICE_PARAM_VAL - WHERE PARAM_NAME = '机台状态-实际产出数量' - AND TO_CHAR(COLLECT_TIME, 'YYYY-MM-DD') = TO_CHAR(SYSDATE, 'YYYY-MM-DD') + WHERE PARAM_NAME = '机台状态-实际产出数量' -- 固定参数名称 + AND TO_CHAR(COLLECT_TIME, 'YYYY-MM-DD') = TO_CHAR(SYSDATE, 'YYYY-MM-DD') -- 当天数据 ) -WHERE RN = 1 +WHERE RN = 1 -- 仅保留最新一条 ``` **业务逻辑说明**: @@ -262,35 +262,35 @@ WHERE RN = 1 #### 4.2.2 维修分析(按设备聚合) ```sql -SELECT d.DEVICE_NAME AS deviceName, - COUNT(*) AS repairCount, - ROUND(COUNT(*) * 100.0 / NULLIF((SELECT COUNT(*) FROM DMS_BILLS_FAULT_INSTANCE WHERE IS_FLAG = 1), 0), 0) AS percent +SELECT d.DEVICE_NAME AS deviceName, -- 设备名称 + COUNT(*) AS repairCount, -- 设备故障次数 + ROUND(COUNT(*) * 100.0 / NULLIF((SELECT COUNT(*) FROM DMS_BILLS_FAULT_INSTANCE WHERE IS_FLAG = 1), 0), 0) AS percent -- 次数占比 FROM DMS_BILLS_FAULT_INSTANCE f -LEFT JOIN BASE_DEVICELEDGER d ON f.DEVICE_ID = d.OBJ_ID -WHERE f.IS_FLAG = 1 AND f.DEVICE_ID IS NOT NULL -GROUP BY d.OBJ_ID, d.DEVICE_NAME -ORDER BY repairCount DESC +LEFT JOIN BASE_DEVICELEDGER d ON f.DEVICE_ID = d.OBJ_ID -- 关联设备台账 +WHERE f.IS_FLAG = 1 AND f.DEVICE_ID IS NOT NULL -- 只统计有效故障 +GROUP BY d.OBJ_ID, d.DEVICE_NAME -- 按设备聚合 +ORDER BY repairCount DESC -- 按次数降序 ``` #### 4.2.3 设备产量列表 ```sql -SELECT d.DEVICE_NAME AS deviceName, - NVL(TO_NUMBER(p.PARAM_VALUE), 0) AS production +SELECT d.DEVICE_NAME AS deviceName, -- 设备名称 + NVL(TO_NUMBER(p.PARAM_VALUE), 0) AS production -- 当天实际产出 FROM BASE_DEVICELEDGER d LEFT JOIN ( SELECT DEVICE_CODE, PARAM_VALUE FROM ( SELECT DEVICE_CODE, PARAM_VALUE, - ROW_NUMBER() OVER (PARTITION BY DEVICE_CODE ORDER BY COLLECT_TIME DESC) AS RN + ROW_NUMBER() OVER (PARTITION BY DEVICE_CODE ORDER BY COLLECT_TIME DESC) AS RN -- 每台设备最新记录 FROM BASE_DEVICE_PARAM_VAL - WHERE PARAM_NAME = '机台状态-实际产出数量' - AND TO_CHAR(COLLECT_TIME, 'YYYY-MM-DD') = TO_CHAR(SYSDATE, 'YYYY-MM-DD') + WHERE PARAM_NAME = '机台状态-实际产出数量' -- 固定参数名称 + AND TO_CHAR(COLLECT_TIME, 'YYYY-MM-DD') = TO_CHAR(SYSDATE, 'YYYY-MM-DD') -- 当天数据 ) - WHERE RN = 1 -) p ON d.DEVICE_CODE = p.DEVICE_CODE -WHERE d.IS_FLAG = 0 AND d.DEVICE_TYPE = '1' -ORDER BY production DESC + WHERE RN = 1 -- 仅保留最新一条 +) p ON d.DEVICE_CODE = p.DEVICE_CODE -- 关联设备编码 +WHERE d.IS_FLAG = 0 AND d.DEVICE_TYPE = '1' -- 仅生产设备 +ORDER BY production DESC -- 按产量降序 ``` **业务逻辑说明**: diff --git a/aucma-report/src/main/java/com/aucma/report/service/impl/Board4ServiceImpl.java b/aucma-report/src/main/java/com/aucma/report/service/impl/Board4ServiceImpl.java index 616a46c..3f57f25 100644 --- a/aucma-report/src/main/java/com/aucma/report/service/impl/Board4ServiceImpl.java +++ b/aucma-report/src/main/java/com/aucma/report/service/impl/Board4ServiceImpl.java @@ -24,13 +24,21 @@ public class Board4ServiceImpl implements IBoard4Service { /** * 获取产量统计(年累计、月累计、日累计) + * 年累计取“上一自然年”工单完成量汇总(上一年1月1日到12月31日,非滚动12个月), + * 月累计取“本自然月”工单完成量汇总(本月1日至月末), + * 日累计取“当天”每台设备最新“机台状态-实际产出数量”的汇总(当天00:00-23:59) */ @Override public Board4ProductionTotalVo getProductionTotal() { + // 初始化返回对象,避免前端空指针 Board4ProductionTotalVo vo = new Board4ProductionTotalVo(); + // 年累计:去年完成数量总和 Long yearTotal = board4Mapper.selectYearProductionTotal(); + // 月累计:当月完成数量总和 Long monthTotal = board4Mapper.selectMonthProductionTotal(); + // 日累计:当天每台设备最新产出数量汇总 Long dayTotal = board4Mapper.selectDayProductionTotal(); + // 空值保护并赋值 vo.setYearTotal(yearTotal != null ? yearTotal : 0L); vo.setMonthTotal(monthTotal != null ? monthTotal : 0L); vo.setDayTotal(dayTotal != null ? dayTotal : 0L); @@ -39,23 +47,31 @@ public class Board4ServiceImpl implements IBoard4Service { /** * 获取今日工单统计(计划数、完成数、差异数、完成率) + * 差异数=计划数-完成数,完成率为百分比数值字符串,不包含“%” */ @Override public Board4OrderStatisticsVo getOrderStatistics() { + // 初始化返回对象 Board4OrderStatisticsVo vo = new Board4OrderStatisticsVo(); + // 查询今日工单统计(计划/完成) HashMap stats = board4Mapper.selectTodayOrderStatistics(); if (stats != null) { + // 安全转换计划数与完成数 Long planCount = getLongValue(stats.get("PLAN_COUNT")); Long completeCount = getLongValue(stats.get("COMPLETE_COUNT")); + // 设置基础字段 vo.setPlanCount(planCount); vo.setCompleteCount(completeCount); + // 差异=计划-完成 vo.setDiffCount(planCount - completeCount); + // 完成率=完成/计划(四舍五入),返回不带“%” if (planCount > 0) { vo.setCompleteRate(String.valueOf(Math.round(completeCount * 100.0 / planCount))); } else { vo.setCompleteRate("0"); } } else { + // 无数据时返回0,保证前端稳定 vo.setPlanCount(0L); vo.setCompleteCount(0L); vo.setDiffCount(0L); @@ -66,31 +82,39 @@ public class Board4ServiceImpl implements IBoard4Service { /** * 获取今日工单进度列表 + * 进度为百分比字符串,包含“%” */ @Override public List getOrderProgressList() { + // 查询今日工单列表并计算进度 List list = board4Mapper.selectTodayOrderProgressList(); return list != null ? list : new ArrayList<>(); } /** * 获取设备状态统计 + * 设备状态来自台账表,按DEVICE_STATUS统计;维修次数来自故障实例表 */ @Override public Board4DeviceStatusVo getDeviceStatus() { + // 初始化返回对象 Board4DeviceStatusVo vo = new Board4DeviceStatusVo(); + // 查询设备状态分布 HashMap stats = board4Mapper.selectDeviceStatusStatistics(); if (stats != null) { + // 正常/告警/停机/总数 vo.setNormalCount(getLongValue(stats.get("NORMAL_COUNT"))); vo.setAlarmCount(getLongValue(stats.get("ALARM_COUNT"))); vo.setStopCount(getLongValue(stats.get("STOP_COUNT"))); vo.setTotalCount(getLongValue(stats.get("TOTAL_COUNT"))); } else { + // 无数据时默认0 vo.setNormalCount(0L); vo.setAlarmCount(0L); vo.setStopCount(0L); vo.setTotalCount(0L); } + // 总维修次数统计 Long repairCount = board4Mapper.selectTotalRepairCount(); vo.setRepairCount(repairCount != null ? repairCount : 0L); return vo; @@ -98,17 +122,22 @@ public class Board4ServiceImpl implements IBoard4Service { /** * 获取最新报警信息 + * 取报警表最新一条记录,时间格式为HH24:MI:SS */ @Override public Board4AlarmInfoVo getAlarmInfo() { + // 初始化返回对象 Board4AlarmInfoVo vo = new Board4AlarmInfoVo(); + // 查询最新报警记录 HashMap info = board4Mapper.selectLatestAlarmInfo(); if (info != null && !info.isEmpty()) { + // 有报警:填充设备、原因、时间 vo.setHasAlarm(true); vo.setDeviceName(getStringValue(info.get("DEVICE_NAME"))); vo.setAlarmReason(getStringValue(info.get("ALARM_REASON"))); vo.setAlarmTime(getStringValue(info.get("ALARM_TIME"))); } else { + // 无报警:hasAlarm=false,其余置空 vo.setHasAlarm(false); vo.setDeviceName(""); vo.setAlarmReason(""); @@ -119,33 +148,42 @@ public class Board4ServiceImpl implements IBoard4Service { /** * 获取维修分析列表(按设备聚合) + * 统计每台设备故障次数并计算占比,结果按次数降序取TOP10 */ @Override public List getRepairAnalysisList() { + // 查询维修分析TOP10 List list = board4Mapper.selectRepairAnalysisByDevice(); return list != null ? list : new ArrayList<>(); } /** * 获取报修趋势列表 + * 按小时统计当天报修次数(当天00:00-23:59) */ @Override public List getRepairTrendList() { + // 查询当天小时维度的报修数量 List list = board4Mapper.selectRepairTrendList(); return list != null ? list : new ArrayList<>(); } /** * 获取质量统计 + * TREATMENT_MEASURE=3为合格,=1为返修 */ @Override public Board4QualityStatisticsVo getQualityStatistics() { + // 初始化返回对象 Board4QualityStatisticsVo vo = new Board4QualityStatisticsVo(); + // 查询当天质量统计 HashMap stats = board4Mapper.selectQualityStatistics(); if (stats != null) { + // 合格/不合格数 vo.setQualifiedCount(getLongValue(stats.get("QUALIFIED_COUNT"))); vo.setUnqualifiedCount(getLongValue(stats.get("UNQUALIFIED_COUNT"))); } else { + // 无数据默认0 vo.setQualifiedCount(0L); vo.setUnqualifiedCount(0L); } @@ -154,18 +192,22 @@ public class Board4ServiceImpl implements IBoard4Service { /** * 获取质量追溯列表 + * 近7天按产品统计合格率(包含当天),按合格率降序取TOP10 */ @Override public List getQualityTraceList() { + // 查询近7天质量追溯TOP10 List list = board4Mapper.selectQualityTraceList(); return list != null ? list : new ArrayList<>(); } /** * 获取设备分析/产量列表 + * 仅统计有效生产设备,取当天每台设备最新实际产出数量 */ @Override public List getDeviceProductionList() { + // 查询当天设备产量列表 List list = board4Mapper.selectDeviceProductionAnalysis(); return list != null ? list : new ArrayList<>(); } @@ -174,12 +216,15 @@ public class Board4ServiceImpl implements IBoard4Service { * 安全获取Long值 */ private Long getLongValue(Object obj) { + // 空值保护 if (obj == null) { return 0L; } + // 数值类型直接转换 if (obj instanceof Number) { return ((Number) obj).longValue(); } + // 字符串安全解析 try { return Long.parseLong(obj.toString()); } catch (NumberFormatException e) { @@ -191,6 +236,7 @@ public class Board4ServiceImpl implements IBoard4Service { * 安全获取String值 */ private String getStringValue(Object obj) { + // 空值返回空字符串 if (obj == null) { return ""; } diff --git a/aucma-report/src/main/java/com/aucma/report/service/impl/Board5ServiceImpl.java b/aucma-report/src/main/java/com/aucma/report/service/impl/Board5ServiceImpl.java index faa8f9f..b2285e9 100644 --- a/aucma-report/src/main/java/com/aucma/report/service/impl/Board5ServiceImpl.java +++ b/aucma-report/src/main/java/com/aucma/report/service/impl/Board5ServiceImpl.java @@ -27,21 +27,27 @@ public class Board5ServiceImpl implements IBoard5Service { */ @Override public Board5OrderWorkStatisticsVo getOrderWorkStatistics() { + // 初始化返回对象 Board5OrderWorkStatisticsVo vo = new Board5OrderWorkStatisticsVo(); + // 查询工单统计数据 HashMap stats = board5Mapper.selectOrderWorkStatistics(); if (stats != null) { + // 安全转换各统计数 Long totalCount = getLongValue(stats.get("TOTAL_COUNT")); Long completeCount = getLongValue(stats.get("COMPLETE_COUNT")); Long stopCount = getLongValue(stats.get("STOP_COUNT")); + // 设置统计结果 vo.setTotalCount(totalCount); vo.setCompleteCount(completeCount); vo.setStopCount(stopCount); + // 完成率=完成/总数,返回不带“%” if (totalCount > 0) { vo.setCompleteRate(String.valueOf(Math.round(completeCount * 100.0 / totalCount))); } else { vo.setCompleteRate("0"); } } else { + // 无数据时返回0 vo.setTotalCount(0L); vo.setCompleteCount(0L); vo.setStopCount(0L); @@ -52,15 +58,20 @@ public class Board5ServiceImpl implements IBoard5Service { /** * 获取维修时间统计(平均响应时间、平均维修时间) + * 时间口径为全量历史,不限定日期范围 */ @Override public Board5RepairTimeStatisticsVo getRepairTimeStatistics() { + // 初始化返回对象 Board5RepairTimeStatisticsVo vo = new Board5RepairTimeStatisticsVo(); + // 查询平均响应/维修时间 HashMap stats = board5Mapper.selectRepairTimeStatistics(); if (stats != null) { + // 直接返回字符串,避免精度丢失 vo.setAvgResponseTime(getStringValue(stats.get("AVG_RESPONSE_TIME"))); vo.setAvgRepairTime(getStringValue(stats.get("AVG_REPAIR_TIME"))); } else { + // 无数据时返回0 vo.setAvgResponseTime("0"); vo.setAvgRepairTime("0"); } @@ -69,24 +80,30 @@ public class Board5ServiceImpl implements IBoard5Service { /** * 获取保养执行情况统计 + * 时间口径为全量历史,不限定日期范围 */ @Override public Board5MaintStatisticsVo getMaintStatistics() { + // 初始化返回对象 Board5MaintStatisticsVo vo = new Board5MaintStatisticsVo(); + // 查询保养统计 HashMap stats = board5Mapper.selectMaintStatistics(); if (stats != null) { + // 安全转换各状态数量 Long planCount = getLongValue(stats.get("PLAN_COUNT")); Long completeCount = getLongValue(stats.get("COMPLETE_COUNT")); Long waitingCount = getLongValue(stats.get("WAITING_COUNT")); Long doingCount = getLongValue(stats.get("DOING_COUNT")); Long verifyCount = getLongValue(stats.get("VERIFY_COUNT")); + // 设置数量字段 vo.setPlanCount(planCount); vo.setCompleteCount(completeCount); vo.setWaitingCount(waitingCount); vo.setDoingCount(doingCount); vo.setVerifyCount(verifyCount); + // 计算各状态比例,返回不带“%” if (planCount > 0) { vo.setWaitingRate(String.valueOf(Math.round(waitingCount * 100.0 / planCount))); vo.setDoingRate(String.valueOf(Math.round(doingCount * 100.0 / planCount))); @@ -99,6 +116,7 @@ public class Board5ServiceImpl implements IBoard5Service { vo.setCompleteRate("0"); } } else { + // 无数据默认0 vo.setPlanCount(0L); vo.setCompleteCount(0L); vo.setWaitingCount(0L); @@ -114,15 +132,21 @@ public class Board5ServiceImpl implements IBoard5Service { /** * 获取巡检执行情况统计 + * 时间口径为全量历史,不限定日期范围 */ @Override public Board5InspectStatisticsVo getInspectStatistics() { + // 初始化返回对象 Board5InspectStatisticsVo vo = new Board5InspectStatisticsVo(); + // 查询巡检统计 HashMap stats = board5Mapper.selectInspectStatistics(); if (stats != null) { + // 安全转换应检/已检数量 Long deviceCount = getLongValue(stats.get("DEVICE_COUNT")); Long completeCount = getLongValue(stats.get("COMPLETE_COUNT")); + // 设置应检数量 vo.setDeviceCount(deviceCount); + // 完成率=已检/应检 if (deviceCount > 0) { vo.setCompleteRate(String.valueOf(Math.round(completeCount * 100.0 / deviceCount))); } else { @@ -137,18 +161,23 @@ public class Board5ServiceImpl implements IBoard5Service { /** * 获取设备状态分布 + * 统计有效设备全量,不限定日期范围 */ @Override public Board5DeviceStatusDistributionVo getDeviceStatusDistribution() { + // 初始化返回对象 Board5DeviceStatusDistributionVo vo = new Board5DeviceStatusDistributionVo(); + // 查询设备状态分布 HashMap stats = board5Mapper.selectDeviceStatusDistribution(); if (stats != null) { + // 安全转换各状态数量 Long totalCount = getLongValue(stats.get("TOTAL_COUNT")); Long normalCount = getLongValue(stats.get("NORMAL_COUNT")); Long abnormalCount = getLongValue(stats.get("ABNORMAL_COUNT")); Long scrapCount = getLongValue(stats.get("SCRAP_COUNT")); Long experimentCount = getLongValue(stats.get("EXPERIMENT_COUNT")); + // 计算分布比例,返回不带“%” if (totalCount > 0) { vo.setExperimentPercent(Math.round(experimentCount * 100.0 / totalCount)); vo.setUncheckedPercent(Math.round(scrapCount * 100.0 / totalCount)); @@ -171,17 +200,22 @@ public class Board5ServiceImpl implements IBoard5Service { /** * 获取故障来源分布 + * 时间口径为全量历史,不限定日期范围 */ @Override public Board5FaultSourceDistributionVo getFaultSourceDistribution() { + // 初始化返回对象 Board5FaultSourceDistributionVo vo = new Board5FaultSourceDistributionVo(); + // 查询故障来源统计 HashMap stats = board5Mapper.selectFaultSourceDistribution(); if (stats != null) { + // 安全转换各来源数量 Long totalCount = getLongValue(stats.get("TOTAL_COUNT")); Long maintainCount = getLongValue(stats.get("MAINTAIN_COUNT")); Long runningCount = getLongValue(stats.get("RUNNING_COUNT")); Long naturalCount = getLongValue(stats.get("NATURAL_COUNT")); + // 计算来源比例,返回不带“%” if (totalCount > 0) { vo.setMaintainPercent(Math.round(maintainCount * 100.0 / totalCount)); vo.setRunningPercent(Math.round(runningCount * 100.0 / totalCount)); @@ -201,26 +235,32 @@ public class Board5ServiceImpl implements IBoard5Service { /** * 获取故障数量曲线 + * 近30天(含今天),按自然日统计 */ @Override public List getFaultTrendList() { + // 查询近30天故障数量 List list = board5Mapper.selectFaultTrendList(); return list != null ? list : new ArrayList<>(); } /** * 获取产量机台TOP5 + * 当天(00:00-23:59)按最新工艺参数统计 */ @Override public List getProductionTop5() { + // 查询TOP5产量机台 List list = board5Mapper.selectProductionTop5(); if (list == null || list.isEmpty()) { return new ArrayList<>(); } + // 查询最大产量用于比例计算 Long maxProduction = board5Mapper.selectMaxProduction(); if (maxProduction == null || maxProduction == 0) { maxProduction = 1L; } + // 逐条计算百分比 for (Board5ProductionTopVo vo : list) { if (vo.getProduction() != null && vo.getProduction() > 0) { vo.setPercent(Math.round(vo.getProduction() * 100.0 / maxProduction)); @@ -235,12 +275,15 @@ public class Board5ServiceImpl implements IBoard5Service { * 安全获取Long值 */ private Long getLongValue(Object obj) { + // 空值保护 if (obj == null) { return 0L; } + // 数值类型直接转换 if (obj instanceof Number) { return ((Number) obj).longValue(); } + // 字符串安全解析 try { return Long.parseLong(obj.toString()); } catch (NumberFormatException e) { @@ -252,6 +295,7 @@ public class Board5ServiceImpl implements IBoard5Service { * 安全获取String值 */ private String getStringValue(Object obj) { + // 空值返回字符串0 if (obj == null) { return "0"; } diff --git a/aucma-report/src/main/resources/mapper/report/Board4Mapper.xml b/aucma-report/src/main/resources/mapper/report/Board4Mapper.xml index 04c77c5..7a1ed27 100644 --- a/aucma-report/src/main/resources/mapper/report/Board4Mapper.xml +++ b/aucma-report/src/main/resources/mapper/report/Board4Mapper.xml @@ -4,21 +4,21 @@ "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> - + - + - + @@ -34,7 +34,7 @@ WHERE RN = 1 - + - + - + - + - + @@ -15,7 +15,7 @@ WHERE IS_FLAG = 0 - + @@ -25,10 +25,12 @@ FROM DMS_BILLS_FAULT_INSTANCE WHERE IS_FLAG = '1' AND REAL_BEGIN_TIME IS NOT NULL + AND REAL_END_TIME IS NOT NULL -- 确保完成时间存在 + AND BILLS_STATUS IN ('2', '5') -- 仅计算已完成工单 AND APPLY_TIME IS NOT NULL - + - + @@ -51,7 +53,7 @@ FROM DUAL - + @@ -65,7 +67,7 @@ WHERE IS_FLAG = 0 - + - + - + - +