import puppeteer from "puppeteer"; import fs from "fs-extra"; import path from "path"; import FormData from "form-data"; /** * 生成柱状图并上传 * @param {Object} data - 图表数据 * @returns {Promise} - 返回图片URL */ export const generateBarChart = async (data) => { try { console.log("开始生成图表..."); console.log("数据:", data); // 创建临时目录 const tempDir = path.join(process.cwd(), "images"); await fs.ensureDir(tempDir); const tempFilePath = path.join(tempDir, `temp_chart_${Date.now()}.png`); // 获取 plotly.js 的绝对路径 const plotlyPath = path.join( process.cwd(), "src", "public", "js", "plotly-latest.min.js" ); const plotlyContent = await fs.readFile(plotlyPath, "utf-8"); // 创建浏览器实例 const browser = await puppeteer.launch({ headless: "new", args: ["--no-sandbox", "--disable-setuid-sandbox"], }); try { const page = await browser.newPage(); // 准备图表数据 const chartDataset = data.data[0]; const trace = { x: chartDataset.xData, y: chartDataset.yData, type: "bar", marker: { color: "#588CF0", }, line: { color: "#588CF0", }, name: chartDataset.title || "数据", hovertemplate: `${data.xaixs}: %{x}
${data.yaixs}: %{y}
`, }; // 准备布局配置 const layout = { title: { text: chartDataset.title, font: { size: 16, weight: "bold", }, }, xaxis: { title: data.xaixs || "X轴", gridcolor: "rgb(255,255,255)", type: data.xaixs === "机组" ? "category" : undefined, tickcolor: "rgb(255,255,255)", backgroundcolor: "#e5ecf6", }, yaxis: { title: data.yaixs || "Y轴", gridcolor: "rgb(255,255,255)", tickcolor: "rgb(255,255,255)", backgroundcolor: "#e5ecf6", title_standoff: 100, }, margin: { l: 50, r: 50, t: 50, b: 50, }, plot_bgcolor: "#e5ecf6", gridcolor: "#fff", bgcolor: "#e5ecf6", autosize: true, }; // 如果 Y 轴是 "温度偏差",添加两条红色虚线 if (data.yaixs === "温度偏差") { layout.shapes = [ { type: "line", xref: "paper", yref: "y", x0: 0, x1: 1, y0: 5, y1: 5, line: { color: "red", width: 2, dash: "dash", }, hovertext: "上限: 5°C", hoverinfo: "text", }, { type: "line", xref: "paper", yref: "y", x0: 0, x1: 1, y0: -5, y1: -5, line: { color: "red", width: 2, dash: "dash", }, hovertext: "下限: -5°C", hoverinfo: "text", }, ]; layout.hovermode = "x unified"; } // 如果是机组数据,设置刻度值 if (data.xaixs === "机组" || data.xaixs === "机组名称") { layout.xaxis.tickvals = chartDataset.xData; layout.xaxis.ticktext = chartDataset.xData; } // 创建HTML内容 const htmlContent = `
`; // 设置页面内容 await page.setContent(htmlContent, { waitUntil: "networkidle0", }); // 等待图表渲染完成 await page.waitForFunction(() => window.chartRendered === true, { timeout: 60000, }); // 截图并保存到临时文件 const chartElement = await page.$("#chart"); await chartElement.screenshot({ path: tempFilePath, type: "png", }); // 上传图片到服务器 const formData = new FormData(); formData.append("file", fs.createReadStream(tempFilePath)); formData.append("type", "chart"); formData.append("engineCode", data.engineCode); formData.append("analysisTypeCode", data.analysisTypeCode); // const uploadResponse = await axios.post( // "http://192.168.50.233:6900/upload", //minio 地址上传(http://192.168.50.233:6900/upload) // formData, // { // headers: { // ...formData.getHeaders(), // }, // } // ); //删除临时文件; // await fs.remove(tempFilePath); // console.log("图表生成并上传成功:", uploadResponse.data.url); // return uploadResponse.data.url; return formData; } finally { await browser.close(); } } catch (error) { console.error("生成图表失败:", error); throw error; } };