skyouc
6 天以前 cf9211f711be85c8e0c1c739d01c8694d2cf5c51
src/main/webapp/static/js/wrkAnalysis/wrkAnalysis.js
@@ -29,6 +29,13 @@
        return {
            summary: {
                taskCount: 0,
                taskStartTime: null,
                taskStartTime$: "",
                taskEndTime: null,
                taskEndTime$: "",
                taskDurationMs: null,
                avgTaskBeatDurationMs: null,
                avgTaskPerHour: null,
                avgTotalDurationMs: null,
                avgStationDurationMs: null,
                avgCraneDurationMs: null,
@@ -63,7 +70,7 @@
                listLoading: false,
                analyzeLoading: false,
                exportingPdf: false,
                selectedWrkNoMap: {},
                selectedLogIdMap: {},
                analysis: createEmptyAnalysis(),
                analysisReady: false,
                charts: {
@@ -76,8 +83,8 @@
            };
        },
        computed: {
            selectedWrkNos: function () {
                return Object.keys(this.selectedWrkNoMap).map(function (key) {
            selectedLogIds: function () {
                return Object.keys(this.selectedLogIdMap).map(function (key) {
                    return Number(key);
                }).filter(function (value) {
                    return !!value;
@@ -174,7 +181,7 @@
                this.filters = createDefaultFilters();
                this.currentPage = 1;
                this.pageSize = 20;
                this.selectedWrkNoMap = {};
                this.selectedLogIdMap = {};
                this.analysis = createEmptyAnalysis();
                this.analysisReady = false;
                this.disposeCharts();
@@ -197,24 +204,24 @@
                }
                table.clearSelection();
                (this.tableData || []).forEach(function (row) {
                    if (self.selectedWrkNoMap[row.wrkNo]) {
                    if (self.selectedLogIdMap[row.logId]) {
                        table.toggleRowSelection(row, true);
                    }
                });
            },
            syncCurrentPageSelection: function (selection) {
                var nextMap = Object.assign({}, this.selectedWrkNoMap);
                var nextMap = Object.assign({}, this.selectedLogIdMap);
                var selectedMap = {};
                (selection || []).forEach(function (row) {
                    selectedMap[row.wrkNo] = true;
                    selectedMap[row.logId] = true;
                });
                (this.tableData || []).forEach(function (row) {
                    delete nextMap[row.wrkNo];
                    delete nextMap[row.logId];
                });
                Object.keys(selectedMap).forEach(function (key) {
                    nextMap[key] = true;
                });
                this.selectedWrkNoMap = nextMap;
                this.selectedLogIdMap = nextMap;
            },
            runAnalysis: function () {
                var self = this;
@@ -227,11 +234,11 @@
                    deviceType: this.filters.deviceType
                };
                if (this.filters.mode === "TASK") {
                    if (!this.selectedWrkNos.length) {
                    if (!this.selectedLogIds.length) {
                        this.$message.warning("请先勾选要分析的任务");
                        return;
                    }
                    request.wrkNos = this.selectedWrkNos;
                    request.wrkLogIds = this.selectedLogIds;
                    request.timeField = this.filters.timeField;
                } else {
                    if (!this.filters.timeRange || this.filters.timeRange.length !== 2) {
@@ -310,10 +317,15 @@
                    window.html2canvas(visualRoot, this.buildCaptureOptions(visualRoot)),
                    window.html2canvas(detailRoot, this.buildCaptureOptions(detailRoot))
                ]).then(function (results) {
                    var visualAvoidSplitBounds = self.collectAvoidSplitBounds(visualRoot, results[0], [
                        ".quality-banner",
                        ".chart-card"
                    ]);
                    self.appendCanvasSlicesToPdf(pdf, results[0], {
                        margin: 8,
                        startY: 8,
                        addNewPage: false
                        addNewPage: false,
                        avoidSplitBounds: visualAvoidSplitBounds
                    });
                    self.appendDetailTableToPdf(pdf, results[1], detailRoot, detailTable, 8);
                    pdf.save(self.buildPdfFileName());
@@ -354,6 +366,7 @@
                while (renderedHeight < canvas.height) {
                    var currentPageHeightPx = Math.max(1, Math.floor((pageHeight - margin - currentY) * pxPerMm));
                    var sliceHeight = Math.min(currentPageHeightPx, canvas.height - renderedHeight);
                    sliceHeight = this.resolveSliceHeight(renderedHeight, sliceHeight, settings.avoidSplitBounds);
                    pageCanvas.width = canvas.width;
                    pageCanvas.height = sliceHeight;
                    pageContext.fillStyle = "#ffffff";
@@ -388,6 +401,51 @@
                    renderedHeight += sliceHeight;
                    currentY = margin;
                }
            },
            collectAvoidSplitBounds: function (rootElement, rootCanvas, selectors) {
                if (!rootElement || !rootCanvas || !selectors || !selectors.length) {
                    return [];
                }
                var rootRect = rootElement.getBoundingClientRect();
                if (!rootRect.width) {
                    return [];
                }
                var scale = rootCanvas.width / rootRect.width;
                var elements = [];
                selectors.forEach(function (selector) {
                    Array.prototype.push.apply(elements, Array.prototype.slice.call(rootElement.querySelectorAll(selector)));
                });
                return elements.map(function (element) {
                    var rect = element.getBoundingClientRect();
                    return {
                        top: Math.max(0, Math.round((rect.top - rootRect.top) * scale)),
                        bottom: Math.max(0, Math.round((rect.bottom - rootRect.top) * scale))
                    };
                }).filter(function (item) {
                    return item.bottom > item.top;
                }).sort(function (a, b) {
                    return a.top - b.top;
                });
            },
            resolveSliceHeight: function (renderedHeight, desiredHeight, avoidSplitBounds) {
                if (!avoidSplitBounds || !avoidSplitBounds.length) {
                    return desiredHeight;
                }
                var sliceEnd = renderedHeight + desiredHeight;
                var adjustedHeight = desiredHeight;
                avoidSplitBounds.forEach(function (bound) {
                    if (bound.top <= renderedHeight) {
                        return;
                    }
                    if (bound.top >= sliceEnd || bound.bottom <= sliceEnd) {
                        return;
                    }
                    var candidateHeight = bound.top - renderedHeight;
                    if (candidateHeight > 0 && candidateHeight < adjustedHeight) {
                        adjustedHeight = candidateHeight;
                    }
                });
                return adjustedHeight > 0 ? adjustedHeight : desiredHeight;
            },
            appendDetailTableToPdf: function (pdf, rootCanvas, detailRoot, detailTable, margin) {
                var tbody = detailTable && detailTable.tBodies && detailTable.tBodies[0];
@@ -557,7 +615,7 @@
                        }
                    },
                    legend: { data: ["站点耗时", "堆垛机耗时", "总耗时"] },
                    grid: { left: 50, right: 20, top: 40, bottom: 70 },
                    grid: { left: 88, right: 20, top: 40, bottom: 70, containLabel: true },
                    xAxis: {
                        type: "category",
                        data: rows.map(function (item) { return String(item.wrkNo); }),
@@ -599,7 +657,7 @@
                        }
                    },
                    legend: { data: ["平均总耗时", "平均站点耗时", "平均堆垛机耗时"] },
                    grid: { left: 50, right: 20, top: 40, bottom: 70 },
                    grid: { left: 88, right: 20, top: 40, bottom: 70, containLabel: true },
                    xAxis: {
                        type: "category",
                        data: rows.map(function (item) { return item.bucketLabel; }),
@@ -656,10 +714,14 @@
                            return lines.join("<br>");
                        }
                    },
                    grid: { left: 50, right: 20, top: 20, bottom: 40 },
                    grid: { left: 88, right: 20, top: 20, bottom: 68, containLabel: true },
                    xAxis: {
                        type: "category",
                        data: rows.map(function (item) { return item.name; })
                        data: rows.map(function (item) { return item.name; }),
                        axisLabel: {
                            interval: 0,
                            rotate: rows.length > 6 ? 30 : 0
                        }
                    },
                    yAxis: {
                        type: "value",
@@ -743,11 +805,7 @@
                if (!isFinite(num)) {
                    return "0s";
                }
                var text = String(num);
                if (text.indexOf(".") >= 0) {
                    text = text.replace(/0+$/, "").replace(/\.$/, "");
                }
                return text + "s";
                return this.formatDurationBySeconds(num);
            },
            formatDuration: function (value) {
                if (value === null || value === undefined || value === "") {
@@ -760,17 +818,50 @@
                if (ms < 1000) {
                    return Math.round(ms) + " ms";
                }
                var totalSeconds = Math.floor(ms / 1000);
                var hours = Math.floor(totalSeconds / 3600);
                var minutes = Math.floor((totalSeconds % 3600) / 60);
                var seconds = totalSeconds % 60;
                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)) {
                    return "0s";
                }
                var safeSeconds = Math.max(0, totalSeconds);
                if (safeSeconds < 60) {
                    return this.trimTrailingZeros(safeSeconds) + "s";
                }
                var hours = Math.floor(safeSeconds / 3600);
                var minutes = Math.floor((safeSeconds % 3600) / 60);
                var remainSeconds = safeSeconds - hours * 3600 - minutes * 60;
                var secondText = this.trimTrailingZeros(remainSeconds);
                if (hours > 0) {
                    return hours + "h " + this.pad(minutes) + "m " + this.pad(seconds) + "s";
                    return hours + "h" + this.pad(minutes) + "m" + this.padSeconds(secondText) + "s";
                }
                if (minutes > 0) {
                    return minutes + "m " + this.pad(seconds) + "s";
                return minutes + "m" + this.padSeconds(secondText) + "s";
            },
            trimTrailingZeros: function (value) {
                var text = String(Number(Number(value).toFixed(3)));
                if (text.indexOf(".") >= 0) {
                    text = text.replace(/0+$/, "").replace(/\.$/, "");
                }
                return seconds + "s";
                return text;
            },
            padSeconds: function (value) {
                var text = String(value);
                if (text.indexOf(".") >= 0) {
                    var parts = text.split(".");
                    return (parts[0].length < 2 ? "0" + parts[0] : parts[0]) + "." + parts[1];
                }
                return text.length < 2 ? "0" + text : text;
            }
        }
    });