import template from "art-template"; import fs from "fs"; import puppeteer from "puppeteer"; import lodash from "lodash"; import { Data } from "../../../lib/components/index.js"; const _path = process.cwd(); //html模板 const html = {}; //浏览器 let browser = ""; //截图数达到时重启浏览器 避免生成速度越来越慢 let restartNum = 20; //截图次数 let renderNum = 0; //锁住 let lock = false; //截图中 let shoting = []; /** * 渲染生成图片,调试命令 npm run debug,window会直接打开无头浏览器 * * 原始html文件路径:/resources/app/type/type.html,文件夹名要和html名一致 * * 生成html文件路径:/data/html/app/type/save_id.html * * 模板生成art-template文档 http://aui.github.io/art-template/zh-cn/docs/ * * @param app 应用名称 * @param type 方法名 * @param data 前端参数,必传 data.save_id 用来区分模板 * @param imgType 图片类型 jpeg,png(清晰一点,大小更大) */ async function render1(app = "", type = "", data = {}, imgType = "jpeg") { if (lodash.isUndefined(data._res_path)) { data._res_path = `../../../../../plugins/xiaoyao-cvs-plugin/resources/`; } if (lodash.isUndefined(data._sys_res_path)) { data._sys_res_path = `../../../../../plugins/xiaoyao-cvs-plugin/resources/`; } let tplKey = `${app}.${type}`; let saveId = data.save_id || type; let tplFile = `${_path}/plugins/xiaoyao-cvs-plugin/resources/${app}/${type}.html`; Data.createDir(_path + `/data/`, `html/plugin_xiaoyao-cvs-plugin/${app}/${type}`); let savePath = _path + `/data/html/plugin_xiaoyao-cvs-plugin/${app}/${type}/${saveId}.html`; return await doRender(app, type, data, imgType, { tplKey, tplFile, savePath, saveId, }); } async function doRender(app, type, data, imgType, renderCfg) { let { tplKey, tplFile, savePath, saveId } = renderCfg; if (global.debugView === "web-debug") { // debug下保存当前页面的渲染数据,方便模板编写与调试 // 由于只用于调试,开发者只关注自己当时开发的文件即可,暂不考虑app及plugin的命名冲突 let saveDir = _path + "/data/ViewData/"; if (!fs.existsSync(saveDir)) { fs.mkdirSync(saveDir); } let file = saveDir + type + ".json"; data._app = app; fs.writeFileSync(file, JSON.stringify(data)); Bot.logger.mark(`${type}-tplFile:${tplFile}`); Bot.logger.mark(`${type}-savePath:${savePath}`); } if (!html[tplKey] || global.debugView) { html[tplKey] = fs.readFileSync(tplFile, "utf8"); } //替换模板 let tmpHtml = template.render(html[tplKey], data); //保存模板 fs.writeFileSync(savePath, tmpHtml); if (!(await browserInit())) { return false; } let base64 = ""; let start = Date.now(); try { shoting.push(saveId); //图片渲染 const page = await browser.newPage(); await page.goto("file://" + savePath); let body = await page.$("#container"); let randData = { type: imgType, encoding: "base64", } if(imgType == "jpeg"){ randData.quality = 100; } if(imgType == "png"){ randData.omitBackground=true; } base64 = await body.screenshot(randData); if (!global.debugView) { page.close().catch((err) => Bot.logger.error(err)); } shoting.pop(); } catch (error) { Bot.logger.error(`图片生成失败:${type}:${error}`); //重启浏览器 if (browser) { await browser.close().catch((err) => Bot.logger.error(err)); } browser = ""; base64 = ""; return false; } if (!base64) { Bot.logger.error(`图片生成为空:${type}`); return false; } renderNum++; Bot.logger.mark(`图片生成 ${type}:${Date.now() - start}ms 次数:${renderNum}`); if (typeof test != "undefined") { return `图片base64:${type}`; } //截图超过重启数时,自动关闭重启浏览器,避免生成速度越来越慢 if (renderNum % restartNum == 0) { if (shoting.length <= 0) { setTimeout(async function () { browser.removeAllListeners("disconnected"); await browser.close().catch((err) => Bot.logger.error(err)); browser = ""; Bot.logger.mark("puppeteer 关闭重启"); }, 100); } } return base64; } async function browserInit() { if (browser) { return browser; } if (lock) { return false; } lock = true; Bot.logger.mark("puppeteer 启动中。。"); //初始化puppeteer browser = await puppeteer .launch({ // executablePath:'',//chromium其他路径 headless: global.debugView === "debug" ? false : true, args: [ "--disable-gpu", "--disable-dev-shm-usage", "--disable-setuid-sandbox", "--no-first-run", "--no-sandbox", "--no-zygote", "--single-process", ], }) .catch((err) => { Bot.logger.error(err); if(String(err).includes("correct Chromium")){ Bot.logger.error("没有正确安装Chromium,可以尝试执行安装命令:node ./node_modules/puppeteer/install.js"); } }); lock = false; if (browser) { Bot.logger.mark("puppeteer 启动成功"); //监听Chromium实例是否断开 browser.on("disconnected", function (e) { Bot.logger.error("Chromium实例关闭或崩溃!"); browser = ""; }); return browser; } else { Bot.logger.error("puppeteer 启动失败"); return false; } } export { render1, browserInit, renderNum };