Files
asd-backend/static/js/afterbody.js
Milky0217 7eb8d1b5c2 refactor: 重构报表生成逻辑,改进代码结构
- 重构 afterbody.js 为模块化结构 (WeatherReport IIFE)
- 优化 HTML 构建和 PDF 生成流程
- 添加更健壮的数据处理函数
- 改进错误处理和调试日志
2026-04-18 13:23:42 +08:00

301 lines
12 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const WeatherReport = (function () {
const BASE_WIND_COUNT = 10;
const SPOT_CHECK_COUNT = 5;
const AREA_TYPE_MAP = {
urban: "城市",
rural: "农村",
};
const SUITABILITY_MAP = {
a: "不利于污染物的扩散和稀释,适宜于进行无组织排放监测",
b: "较不利于污染物的扩散和稀释,较适宜于进行无组织排放监测",
c: "有利于污染物的扩散和稀释,较不适宜于进行无组织排放监测",
d: "很有利于污染物的扩散和稀释,不适宜于进行无组织排放监测",
wind0: "静风",
overall0: "取消监测或改期",
};
function formatDate(dateStr) {
const d = new Date(dateStr);
const y = d.getFullYear();
const m = String(d.getMonth() + 1).padStart(2, "0");
const day = String(d.getDate()).padStart(2, "0");
return `${y}-${m}-${day}`;
}
function getSuitabilityText(value, type) {
const normalized = String(value).toLowerCase();
if (type === "wind" && normalized === "0") return SUITABILITY_MAP.wind0;
if (type === "overall" && normalized === "0") return SUITABILITY_MAP.overall0;
return SUITABILITY_MAP[normalized] || value;
}
function formatTime(hours, min) {
return `${hours}:${String(min).padStart(2, "0")}`;
}
function joinWithComma(arr, start, end) {
return arr.slice(start, end).map((v) => v ?? "").join("");
}
function buildReportHTML(data) {
const staticPrefix = window.staticPrefix || '/static';
const timeStr = `${formatDate(data.date)} ${formatTime(data.hours, data.min)}`;
const version = data.version || "unknown";
let html = `<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>总体适宜度测量报表</title>
<link rel="stylesheet" href="${staticPrefix}/css/report.css">
</head>
<body>
<div class="report-container">
<h1>总体适宜度测量报表</h1>
<div class="data-grid">
<div class="data-row-long">
<div class="data-label">文件编号:</div>
<div class="data-value">${data.id}</div>
</div>
<div class="data-row-long">
<div class="data-label">检测类型:</div>
<div class="data-value">${data.inspectionType || "-"}</div>
</div>
<div class="data-row-long">
<div class="data-label">委托单号:</div>
<div class="data-value">${data.assignmentNumber || "-"}</div>
</div>
<div class="data-row-long">
<div class="data-label">项目名称:</div>
<div class="data-value">${data.title || "-"}</div>
</div>
<div class="data-row-long">
<div class="data-label">经纬度:</div>
<div class="data-value">E ${data.longitude || "-"}, N ${data.latitude || "-"}</div>
</div>
<div class="data-row-long">
<div class="data-label">测试时间:</div>
<div class="data-value">${timeStr}</div>
</div>
</div>
<div class="divider"></div>
<div class="data-grid">
<div class="data-row">
<div class="data-label">日期序数:</div>
<div class="data-value">${data.daySinceJanFirst}</div>
</div>
<div class="data-row">
<div class="data-label">太阳倾角:</div>
<div class="data-value">${Number(data.solarDeclination).toFixed(2)}°</div>
</div>
<div class="data-row">
<div class="data-label">太阳高度角:</div>
<div class="data-value">${Number(data.sunAltitude).toFixed(2)}°</div>
</div>
<div class="data-row">
<div class="data-label">总云量:</div>
<div class="data-value">${data.overallCloudiness}</div>
</div>
<div class="data-row">
<div class="data-label">低云量:</div>
<div class="data-value">${data.lowCloudiness}</div>
</div>
<div class="data-row">
<div class="data-label">辐射等级:</div>
<div class="data-value">${data.solarRadiationLevel}</div>
</div>
<div class="data-row">
<div class="data-label">平均风速:</div>
<div class="data-value">${data.averageWindSpeed}m/s</div>
</div>
<div class="data-row">
<div class="data-label">风速适宜度:</div>
<div class="data-value">${data.windSpeedSuitability}</div>
</div>`;
if (data.hasMeasuredWindSpeed === true) {
html += `
<div class="data-row">
<div class="data-label">实测风速:</div>
<div class="data-value">${data.measuredWindSpeed} m/s</div>
</div>
<div class="data-row">
<div class="data-label">转换风速:</div>
<div class="data-value">${data.convertedWindSpeed} m/s</div>
</div>`;
} else {
html += `
<div class="data-row">
<div class="data-label">区域类型:</div>
<div class="data-value">${AREA_TYPE_MAP[data.areaType] || data.areaType || "-"}</div>
</div>
<div class="data-row">
<div class="data-label">测点高度:</div>
<div class="data-value">${data.pointHeight} m</div>
</div>
<div class="data-row">
<div class="data-label">点位风速:</div>
<div class="data-value">${data.pointWindSpeed} m/s</div>
</div>
<div class="data-row">
<div class="data-label">推算风速:</div>
<div class="data-value">${data.calculatedWindSpeed} m/s</div>
</div>`;
}
html += `
<div class="data-row">
<div class="data-label">平均风向:</div>
<div class="data-value">${data.averageWindDirection}°</div>
</div>
<div class="data-row">
<div class="data-label">风向标准差:</div>
<div class="data-value">${data.windDirectionStandardDeviation}°</div>
</div>
<div class="data-row">
<div class="data-label">风向适宜度:</div>
<div class="data-value">${data.windDirectionSuitability}</div>
</div>
<div class="data-row">
<div class="data-label">大气稳定度:</div>
<div class="data-value">${data.atmosphericStability}</div>
</div>
<div class="data-row">
<div class="data-label">稳定度适宜度:</div>
<div class="data-value">${data.suitabilityDegree}</div>
</div>
<div class="data-row">
<div class="data-label">总体适宜度:</div>
<div class="data-value">${getSuitabilityText(data.overallSuitability, "overall")}</div>
</div>
</div>
<div class="divider"></div>
<div class="data-grid">
<div class="data-row-long">
<div class="data-label">十次风速值:</div>
<div class="data-value">
<div class="ten-values">${joinWithComma(data.windSpeed, 0, BASE_WIND_COUNT)}</div>
</div>
</div>
<div class="data-row-long">
<div class="data-label">十次风向值:</div>
<div class="data-value">
<div class="ten-values">${joinWithComma(data.windDirection, 0, BASE_WIND_COUNT)}</div>
</div>
</div>
</div>`;
if (data.hasSpotCheckWindSpeed) {
html += `
<div class="data-grid spot-check-values">
<div class="data-row-long">
<div class="data-label">抽测风速值:</div>
<div class="data-value">
<div class="ten-values">${joinWithComma(data.windSpeed, BASE_WIND_COUNT, BASE_WIND_COUNT + SPOT_CHECK_COUNT)}</div>
</div>
</div>
<div class="data-row-long">
<div class="data-label">抽测风向值:</div>
<div class="data-value">
<div class="ten-values">${joinWithComma(data.windDirection, BASE_WIND_COUNT, BASE_WIND_COUNT + SPOT_CHECK_COUNT)}</div>
</div>
</div>
</div>`;
}
html += `
<div class="data-row-long">
<div class="data-label">是否有抽测风速:${data.hasSpotCheckWindSpeed ? "是" : "否"}</div>
</div>
<div class="divider"></div>
<div class="footer">----报表结束 version:${version}----</div>
</div>
</body>
</html>`;
return html;
}
function downloadPDF(htmlContent, filename) {
const options = {
margin: 10,
filename: filename,
image: { type: "jpeg", quality: 0.99 },
html2canvas: { scale: 2 },
jsPDF: { unit: "mm", format: "a4", orientation: "portrait" },
};
html2pdf().set(options).from(htmlContent).save();
}
function init() {
if (typeof window.weatherData === "undefined") {
console.error("错误window.weatherData 未定义");
return;
}
const data = window.weatherData;
console.log("【调试】从后端获取的 weatherData:", data);
console.log("【调试】inspectionType:", data.inspectionType);
console.log("【调试】assignmentNumber:", data.assignmentNumber);
console.log("【调试】title:", data.title);
const versionEl = document.querySelector(".version");
if (versionEl) {
versionEl.textContent = `版本号: ${data.version || "default"}`;
}
const html = buildReportHTML(data);
const filename = `${data.id}-${data.version || "unknown"}.pdf`;
downloadPDF(html, filename);
}
document.addEventListener("DOMContentLoaded", function () {
if (typeof renderMathInElement === "function") {
renderMathInElement(document.body, {
delimiters: [
{ left: "$$", right: "$$", display: true },
{ left: "$", right: "$", display: false },
],
throwOnError: false,
});
}
init();
});
function toggleFormula(element) {
const content = element.nextElementSibling;
const isHidden = content.style.display === "none";
content.style.display = isHidden ? "block" : "none";
element.textContent = element.textContent.includes("▶")
? element.textContent.replace("▶", "▼")
: element.textContent.replace("▼", "▶");
}
function showNotification(message, type = "success") {
const notification = document.getElementById("notification");
if (!notification) return;
notification.textContent = message;
notification.className = `notification ${type}`;
notification.style.display = "block";
setTimeout(() => {
notification.style.display = "none";
}, 3000);
}
return {
buildReportHTML,
downloadPDF,
init,
toggleFormula,
showNotification,
};
})();