#
Junjie
15 小时以前 2b8a06fad6cc62d8d46307626489b68c4f8f065d
#
1个文件已添加
3个文件已修改
105 ■■■■■ 已修改文件
src/main/java/com/zy/asrs/service/impl/WrkAnalysisServiceImpl.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/static/js/wrkAnalysis/wrkAnalysis.js 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/views/wrkAnalysis/wrkAnalysis.html 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/test/java/com/zy/asrs/service/impl/WrkAnalysisServiceImplTest.java 73 ●●●●● 补丁 | 查看 | 原始文档 | 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);
        }
    }
}