From a42c95b399fc0d9162e714d5cd5156c53fff2cc6 Mon Sep 17 00:00:00 2001
From: Junjie <fallin.jie@qq.com>
Date: 星期日, 22 三月 2026 18:12:28 +0800
Subject: [PATCH] #
---
src/main/webapp/static/js/wrkAnalysis/wrkAnalysis.js | 325 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 312 insertions(+), 13 deletions(-)
diff --git a/src/main/webapp/static/js/wrkAnalysis/wrkAnalysis.js b/src/main/webapp/static/js/wrkAnalysis/wrkAnalysis.js
index 0214de8..b1904c5 100644
--- a/src/main/webapp/static/js/wrkAnalysis/wrkAnalysis.js
+++ b/src/main/webapp/static/js/wrkAnalysis/wrkAnalysis.js
@@ -62,6 +62,7 @@
pageTotal: 0,
listLoading: false,
analyzeLoading: false,
+ exportingPdf: false,
selectedWrkNoMap: {},
analysis: createEmptyAnalysis(),
analysisReady: false,
@@ -269,6 +270,247 @@
}
});
},
+ exportAnalysisPdf: function () {
+ var self = this;
+ if (!this.analysisReady) {
+ this.$message.warning("璇峰厛鎵ц鍒嗘瀽锛屽啀瀵煎嚭PDF");
+ return;
+ }
+ if (!window.html2canvas || !window.jspdf || !window.jspdf.jsPDF) {
+ this.$message.error("PDF瀵煎嚭缁勪欢鍔犺浇澶辫触");
+ return;
+ }
+ this.exportingPdf = true;
+ this.$nextTick(function () {
+ self.resizeCharts();
+ window.setTimeout(function () {
+ self.generatePdf();
+ }, 300);
+ });
+ },
+ generatePdf: function () {
+ var self = this;
+ var visualRoot = this.$refs.analysisVisualRoot;
+ var detailRoot = this.$refs.exportDetailRoot;
+ var detailTable = this.$refs.exportDetailTable;
+ var cleanup = function () {
+ self.exportingPdf = false;
+ self.$nextTick(function () {
+ self.resizeCharts();
+ });
+ };
+ if (!visualRoot || !detailRoot || !detailTable) {
+ this.$message.error("鏈壘鍒板彲瀵煎嚭鐨勫垎鏋愬尯鍩�");
+ cleanup();
+ return;
+ }
+ var jsPDF = window.jspdf.jsPDF;
+ var pdf = new jsPDF("p", "mm", "a4");
+ Promise.all([
+ window.html2canvas(visualRoot, this.buildCaptureOptions(visualRoot)),
+ window.html2canvas(detailRoot, this.buildCaptureOptions(detailRoot))
+ ]).then(function (results) {
+ self.appendCanvasSlicesToPdf(pdf, results[0], {
+ margin: 8,
+ startY: 8,
+ addNewPage: false
+ });
+ self.appendDetailTableToPdf(pdf, results[1], detailRoot, detailTable, 8);
+ pdf.save(self.buildPdfFileName());
+ self.$message.success("PDF瀵煎嚭鎴愬姛");
+ cleanup();
+ }).catch(function (error) {
+ console.error(error);
+ self.$message.error("PDF瀵煎嚭澶辫触");
+ cleanup();
+ });
+ },
+ buildCaptureOptions: function (target) {
+ return {
+ scale: 2,
+ useCORS: true,
+ backgroundColor: "#ffffff",
+ logging: false,
+ scrollX: 0,
+ scrollY: -window.scrollY,
+ width: target.scrollWidth,
+ height: target.scrollHeight,
+ windowWidth: Math.max(document.documentElement.clientWidth, target.scrollWidth),
+ windowHeight: Math.max(document.documentElement.clientHeight, target.scrollHeight)
+ };
+ },
+ appendCanvasSlicesToPdf: function (pdf, canvas, options) {
+ var settings = options || {};
+ var pageWidth = pdf.internal.pageSize.getWidth();
+ var pageHeight = pdf.internal.pageSize.getHeight();
+ var margin = settings.margin == null ? 8 : settings.margin;
+ var startY = settings.startY == null ? margin : settings.startY;
+ var usableWidth = pageWidth - margin * 2;
+ var pxPerMm = canvas.width / usableWidth;
+ var renderedHeight = 0;
+ var currentY = startY;
+ var pageCanvas = document.createElement("canvas");
+ var pageContext = pageCanvas.getContext("2d");
+ while (renderedHeight < canvas.height) {
+ var currentPageHeightPx = Math.max(1, Math.floor((pageHeight - margin - currentY) * pxPerMm));
+ var sliceHeight = Math.min(currentPageHeightPx, canvas.height - renderedHeight);
+ pageCanvas.width = canvas.width;
+ pageCanvas.height = sliceHeight;
+ pageContext.fillStyle = "#ffffff";
+ pageContext.fillRect(0, 0, pageCanvas.width, pageCanvas.height);
+ pageContext.drawImage(
+ canvas,
+ 0,
+ renderedHeight,
+ canvas.width,
+ sliceHeight,
+ 0,
+ 0,
+ pageCanvas.width,
+ pageCanvas.height
+ );
+ if (renderedHeight === 0 && settings.addNewPage) {
+ pdf.addPage();
+ } else if (renderedHeight > 0) {
+ pdf.addPage();
+ currentY = margin;
+ }
+ pdf.addImage(
+ pageCanvas.toDataURL("image/jpeg", 0.95),
+ "JPEG",
+ margin,
+ currentY,
+ usableWidth,
+ sliceHeight / pxPerMm,
+ undefined,
+ "FAST"
+ );
+ renderedHeight += sliceHeight;
+ currentY = margin;
+ }
+ },
+ appendDetailTableToPdf: function (pdf, rootCanvas, detailRoot, detailTable, margin) {
+ var tbody = detailTable && detailTable.tBodies && detailTable.tBodies[0];
+ var rows = tbody ? Array.prototype.slice.call(tbody.rows) : [];
+ if (!rows.length) {
+ return;
+ }
+ var pageWidth = pdf.internal.pageSize.getWidth();
+ var pageHeight = pdf.internal.pageSize.getHeight();
+ var usableWidth = pageWidth - margin * 2;
+ var usableHeight = pageHeight - margin * 2;
+ var rootRect = detailRoot.getBoundingClientRect();
+ var tableRect = detailTable.getBoundingClientRect();
+ var scale = rootCanvas.width / rootRect.width;
+ var pxPerMm = rootCanvas.width / usableWidth;
+ var pageHeightPx = Math.max(1, Math.floor(usableHeight * pxPerMm));
+ var titleHeightPx = Math.max(0, Math.round((tableRect.top - rootRect.top) * scale));
+ var headerHeightPx = Math.max(1, Math.round(detailTable.tHead.getBoundingClientRect().height * scale));
+ var rowBounds = rows.map(function (row) {
+ var rect = row.getBoundingClientRect();
+ return {
+ top: Math.round((rect.top - tableRect.top) * scale),
+ bottom: Math.round((rect.bottom - tableRect.top) * scale)
+ };
+ });
+ var firstPage = true;
+ var startIndex = 0;
+ while (startIndex < rowBounds.length) {
+ var bodyCapacityPx = pageHeightPx - headerHeightPx - (firstPage ? titleHeightPx : 0);
+ var endIndex = this.findLastFittingRowIndex(rowBounds, startIndex, bodyCapacityPx);
+ var pageCanvas = this.createDetailPageCanvas(
+ rootCanvas,
+ titleHeightPx,
+ headerHeightPx,
+ rowBounds[startIndex].top,
+ rowBounds[endIndex].bottom,
+ firstPage
+ );
+ pdf.addPage();
+ pdf.addImage(
+ pageCanvas.toDataURL("image/jpeg", 0.95),
+ "JPEG",
+ margin,
+ margin,
+ usableWidth,
+ pageCanvas.height / pxPerMm,
+ undefined,
+ "FAST"
+ );
+ firstPage = false;
+ startIndex = endIndex + 1;
+ }
+ },
+ findLastFittingRowIndex: function (rowBounds, startIndex, bodyCapacityPx) {
+ var lastIndex = startIndex;
+ for (var i = startIndex; i < rowBounds.length; i++) {
+ if (rowBounds[i].bottom - rowBounds[startIndex].top > bodyCapacityPx) {
+ break;
+ }
+ lastIndex = i;
+ }
+ return lastIndex;
+ },
+ createDetailPageCanvas: function (rootCanvas, titleHeightPx, headerHeightPx, bodyStartPx, bodyEndPx, includeTitle) {
+ var width = rootCanvas.width;
+ var titleHeight = includeTitle ? titleHeightPx : 0;
+ var bodyHeight = Math.max(1, bodyEndPx - bodyStartPx);
+ var pageCanvas = document.createElement("canvas");
+ var pageContext = pageCanvas.getContext("2d");
+ pageCanvas.width = width;
+ pageCanvas.height = titleHeight + headerHeightPx + bodyHeight;
+ pageContext.fillStyle = "#ffffff";
+ pageContext.fillRect(0, 0, pageCanvas.width, pageCanvas.height);
+ var offsetY = 0;
+ if (titleHeight > 0) {
+ pageContext.drawImage(
+ rootCanvas,
+ 0,
+ 0,
+ width,
+ titleHeight,
+ 0,
+ 0,
+ width,
+ titleHeight
+ );
+ offsetY += titleHeight;
+ }
+ pageContext.drawImage(
+ rootCanvas,
+ 0,
+ titleHeightPx,
+ width,
+ headerHeightPx,
+ 0,
+ offsetY,
+ width,
+ headerHeightPx
+ );
+ offsetY += headerHeightPx;
+ pageContext.drawImage(
+ rootCanvas,
+ 0,
+ titleHeightPx + bodyStartPx,
+ width,
+ bodyHeight,
+ 0,
+ offsetY,
+ width,
+ bodyHeight
+ );
+ return pageCanvas;
+ },
+ buildPdfFileName: function () {
+ var now = new Date();
+ return "浠诲姟鎵ц鍒嗘瀽_" +
+ now.getFullYear() +
+ this.pad(now.getMonth() + 1) +
+ this.pad(now.getDate()) + "_" +
+ this.pad(now.getHours()) +
+ this.pad(now.getMinutes()) +
+ this.pad(now.getSeconds()) + ".pdf";
+ },
updateCharts: function () {
if (!this.analysisReady) {
this.disposeCharts();
@@ -298,9 +540,22 @@
if (!this.charts.duration) {
return;
}
+ var self = this;
var rows = this.analysis.durationCompare || [];
this.charts.duration.setOption({
- tooltip: { trigger: "axis" },
+ tooltip: {
+ trigger: "axis",
+ formatter: function (params) {
+ if (!params || !params.length) {
+ return "";
+ }
+ var lines = [params[0].axisValue];
+ params.forEach(function (item) {
+ lines.push(item.marker + item.seriesName + ": " + self.formatChartSeconds(item.value));
+ });
+ return lines.join("<br>");
+ }
+ },
legend: { data: ["绔欑偣鑰楁椂", "鍫嗗灈鏈鸿�楁椂", "鎬昏�楁椂"] },
grid: { left: 50, right: 20, top: 40, bottom: 70 },
xAxis: {
@@ -312,14 +567,14 @@
type: "value",
axisLabel: {
formatter: function (value) {
- return Math.round((value || 0) / 1000) + "s";
+ return self.formatChartSeconds(value);
}
}
},
series: [
- { name: "绔欑偣鑰楁椂", type: "bar", barMaxWidth: 28, data: rows.map(function (item) { return item.stationDurationMs || 0; }) },
- { name: "鍫嗗灈鏈鸿�楁椂", type: "bar", barMaxWidth: 28, data: rows.map(function (item) { return item.craneDurationMs || 0; }) },
- { name: "鎬昏�楁椂", type: "bar", barMaxWidth: 28, data: rows.map(function (item) { return item.totalDurationMs || 0; }) }
+ { name: "绔欑偣鑰楁椂", type: "bar", barMaxWidth: 28, data: rows.map(function (item) { return self.toChartSeconds(item.stationDurationMs); }) },
+ { name: "鍫嗗灈鏈鸿�楁椂", type: "bar", barMaxWidth: 28, data: rows.map(function (item) { return self.toChartSeconds(item.craneDurationMs); }) },
+ { name: "鎬昏�楁椂", type: "bar", barMaxWidth: 28, data: rows.map(function (item) { return self.toChartSeconds(item.totalDurationMs); }) }
]
}, true);
},
@@ -327,9 +582,22 @@
if (!this.charts.trend) {
return;
}
+ var self = this;
var rows = this.analysis.trend || [];
this.charts.trend.setOption({
- tooltip: { trigger: "axis" },
+ tooltip: {
+ trigger: "axis",
+ formatter: function (params) {
+ if (!params || !params.length) {
+ return "";
+ }
+ var lines = [params[0].axisValue];
+ params.forEach(function (item) {
+ lines.push(item.marker + item.seriesName + ": " + self.formatChartSeconds(item.value));
+ });
+ return lines.join("<br>");
+ }
+ },
legend: { data: ["骞冲潎鎬昏�楁椂", "骞冲潎绔欑偣鑰楁椂", "骞冲潎鍫嗗灈鏈鸿�楁椂"] },
grid: { left: 50, right: 20, top: 40, bottom: 70 },
xAxis: {
@@ -341,14 +609,14 @@
type: "value",
axisLabel: {
formatter: function (value) {
- return Math.round((value || 0) / 1000) + "s";
+ return self.formatChartSeconds(value);
}
}
},
series: [
- { name: "骞冲潎鎬昏�楁椂", type: "line", smooth: true, data: rows.map(function (item) { return item.avgTotalDurationMs || 0; }) },
- { name: "骞冲潎绔欑偣鑰楁椂", type: "line", smooth: true, data: rows.map(function (item) { return item.avgStationDurationMs || 0; }) },
- { name: "骞冲潎鍫嗗灈鏈鸿�楁椂", type: "line", smooth: true, data: rows.map(function (item) { return item.avgCraneDurationMs || 0; }) }
+ { name: "骞冲潎鎬昏�楁椂", type: "line", smooth: true, data: rows.map(function (item) { return self.toChartSeconds(item.avgTotalDurationMs); }) },
+ { name: "骞冲潎绔欑偣鑰楁椂", type: "line", smooth: true, data: rows.map(function (item) { return self.toChartSeconds(item.avgStationDurationMs); }) },
+ { name: "骞冲潎鍫嗗灈鏈鸿�楁椂", type: "line", smooth: true, data: rows.map(function (item) { return self.toChartSeconds(item.avgCraneDurationMs); }) }
]
}, true);
},
@@ -372,9 +640,22 @@
if (!this.charts.faultDuration) {
return;
}
+ var self = this;
var rows = this.analysis.faultDuration || [];
this.charts.faultDuration.setOption({
- tooltip: { trigger: "axis" },
+ tooltip: {
+ trigger: "axis",
+ formatter: function (params) {
+ if (!params || !params.length) {
+ return "";
+ }
+ var lines = [params[0].axisValue];
+ params.forEach(function (item) {
+ lines.push(item.marker + item.seriesName + ": " + self.formatChartSeconds(item.value));
+ });
+ return lines.join("<br>");
+ }
+ },
grid: { left: 50, right: 20, top: 20, bottom: 40 },
xAxis: {
type: "category",
@@ -384,7 +665,7 @@
type: "value",
axisLabel: {
formatter: function (value) {
- return Math.round((value || 0) / 1000) + "s";
+ return self.formatChartSeconds(value);
}
}
},
@@ -392,7 +673,7 @@
name: "鏁呴殰鑰楁椂",
type: "bar",
barMaxWidth: 36,
- data: rows.map(function (item) { return item.value || 0; })
+ data: rows.map(function (item) { return self.toChartSeconds(item.value); })
}]
}, true);
},
@@ -450,6 +731,24 @@
}
return num.toLocaleString("zh-CN");
},
+ toChartSeconds: function (value) {
+ var num = Number(value || 0);
+ if (!isFinite(num)) {
+ return 0;
+ }
+ return Number((num / 1000).toFixed(3));
+ },
+ formatChartSeconds: function (value) {
+ var num = Number(value || 0);
+ if (!isFinite(num)) {
+ return "0s";
+ }
+ var text = String(num);
+ if (text.indexOf(".") >= 0) {
+ text = text.replace(/0+$/, "").replace(/\.$/, "");
+ }
+ return text + "s";
+ },
formatDuration: function (value) {
if (value === null || value === undefined || value === "") {
return "--";
--
Gitblit v1.9.1