| src/main/java/com/zy/asrs/service/impl/WrkAnalysisServiceImpl.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/webapp/static/js/wrkAnalysis/wrkAnalysis.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/webapp/views/wrkAnalysis/wrkAnalysis.html | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/test/java/com/zy/asrs/service/impl/WrkAnalysisServiceImplTest.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
src/main/java/com/zy/asrs/service/impl/WrkAnalysisServiceImpl.java
@@ -16,6 +16,8 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.math.RoundingMode; import java.text.SimpleDateFormat; import java.util.*; import java.util.stream.Collectors; @@ -467,6 +469,7 @@ summary.put("avgTaskBeatDurationMs", list.isEmpty() || taskStartTime == null || taskEndTime == null ? null : durationMs(taskStartTime, taskEndTime) / list.size()); summary.put("avgTaskPerHour", calculateAvgTaskPerHour(list.size(), summary.get("taskDurationMs"))); summary.put("avgTotalDurationMs", average(list, item -> item.getTotalDurationMs() != null, WrkAnalysis::getTotalDurationMs)); summary.put("avgStationDurationMs", average(list, item -> !METRIC_PARTIAL.equals(item.getMetricCompleteness()) && item.getStationDurationMs() != null, WrkAnalysis::getStationDurationMs)); summary.put("avgCraneDurationMs", average(list, item -> !METRIC_PARTIAL.equals(item.getMetricCompleteness()) && item.getCraneDurationMs() != null, WrkAnalysis::getCraneDurationMs)); @@ -842,6 +845,19 @@ return count == 0 ? null : total / count; } private Double calculateAvgTaskPerHour(int taskCount, Object taskDurationMsValue) { if (taskCount <= 0 || !(taskDurationMsValue instanceof Number)) { return null; } long taskDurationMs = ((Number) taskDurationMsValue).longValue(); if (taskDurationMs <= 0L) { return null; } return BigDecimal.valueOf(taskCount * 3600000D / taskDurationMs) .setScale(2, RoundingMode.HALF_UP) .doubleValue(); } private void applyRange(QueryWrapper<WrkMastLog> wrapper, String column, String rawValue) { if (Cools.isEmpty(rawValue) || !rawValue.contains("~")) { return; src/main/webapp/static/js/wrkAnalysis/wrkAnalysis.js
@@ -35,6 +35,7 @@ taskEndTime$: "", taskDurationMs: null, avgTaskBeatDurationMs: null, avgTaskPerHour: null, avgTotalDurationMs: null, avgStationDurationMs: null, avgCraneDurationMs: null, @@ -819,6 +820,16 @@ } return this.formatDurationBySeconds(ms / 1000); }, formatTaskPerHour: function (value) { if (value === null || value === undefined || value === "") { return "--"; } var num = Number(value); if (!isFinite(num)) { return "--"; } return this.trimTrailingZeros(num.toFixed(2)) + " 任务/小时"; }, formatDurationBySeconds: function (seconds) { var totalSeconds = Number(seconds || 0); if (!isFinite(totalSeconds)) { src/main/webapp/views/wrkAnalysis/wrkAnalysis.html
@@ -414,6 +414,11 @@ <div class="summary-sub">总任务总耗时 / 任务数</div> </div> <div class="summary-card"> <div class="summary-label">平均每小时节拍</div> <div class="summary-value">{{ formatTaskPerHour(analysis.summary.avgTaskPerHour) }}</div> <div class="summary-sub">任务数 / 总任务总耗时(小时)</div> </div> <div class="summary-card"> <div class="summary-label">平均总耗时</div> <div class="summary-value">{{ formatDuration(analysis.summary.avgTotalDurationMs) }}</div> <div class="summary-sub">创建到完成的平均耗时</div> src/test/java/com/zy/asrs/service/impl/WrkAnalysisServiceImplTest.java
New file @@ -0,0 +1,73 @@ package com.zy.asrs.service.impl; import com.zy.asrs.entity.WrkAnalysis; import com.zy.asrs.service.BasCrnpErrLogService; import com.zy.asrs.service.BasDualCrnpErrLogService; import com.zy.asrs.service.BasRgvErrLogService; import com.zy.asrs.service.BasStationService; import com.zy.asrs.service.BasWrkStatusService; import com.zy.asrs.service.WrkMastLogService; import com.zy.asrs.service.WrkMastService; import org.junit.jupiter.api.Test; import org.springframework.test.util.ReflectionTestUtils; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Date; import java.util.Map; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; class WrkAnalysisServiceImplTest { @Test @SuppressWarnings("unchecked") void buildAnalysisResult_calculatesAverageTaskPerHour() { BasWrkStatusService basWrkStatusService = mock(BasWrkStatusService.class); when(basWrkStatusService.getById(org.mockito.ArgumentMatchers.any())).thenReturn(null); WrkAnalysisServiceImpl service = new WrkAnalysisServiceImpl( mock(WrkMastLogService.class), mock(BasCrnpErrLogService.class), mock(BasDualCrnpErrLogService.class), mock(BasRgvErrLogService.class), mock(BasStationService.class), basWrkStatusService, mock(WrkMastService.class) ); Map<String, Object> result = ReflectionTestUtils.invokeMethod( service, "buildAnalysisResult", Arrays.asList( analysis(1001, date("2026-03-27 13:00:00"), date("2026-03-27 13:10:00"), 600_000L), analysis(1002, date("2026-03-27 13:15:00"), date("2026-03-27 13:30:00"), 900_000L) ), "finish_time" ); Map<String, Object> summary = (Map<String, Object>) result.get("summary"); assertEquals(4.0d, ((Number) summary.get("avgTaskPerHour")).doubleValue(), 0.0001d); } private WrkAnalysis analysis(int wrkNo, Date appeTime, Date finishTime, long totalDurationMs) { WrkAnalysis item = new WrkAnalysis(); item.setWrkNo(wrkNo); item.setAppeTime(appeTime); item.setFinishTime(finishTime); item.setTotalDurationMs(totalDurationMs); item.setFinalWrkSts(80L); item.setMetricCompleteness("COMPLETE"); return item; } private Date date(String value) { try { return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(value); } catch (ParseException e) { throw new IllegalArgumentException(e); } } }