微信小程序之导出页面为doc文件
微信小程序:需求将一个类似报表的页面点击下载导出问xxx.doc文件。
1.写入文件导出
由于微信小程序的限制;将导出的功能放到node服务上。使用fs直接将html文本模板写入doc文件后返回下载地址
// 生成下载文件,并返回名称
app.post('/getFile', (req, res) => {
const data = req.body;
const name = data.name;
const html = data.html;
fs.writeFile('./public/' + name, html, (err) => {
if (err) throw err;
res.json({ data: name });
});
});
// 文件下载路由
app.get('/download/:filename', function (req, res) {
const filename = req.params.filename;
res.download(path.join(__dirname, 'public') + '/' + filename, filename);
});
app.get('/', (req, res) => {
res.send({ data: '服务启动成功!' });
});
2.html模板内容:区分页面中的元素
1.模板,带有表格样式
let template = '
<!DOCTYPE html><html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style>
table{border-collapse:collapse;border:1px solid #000;font-family:FangSong_GB2312}th{border:1px solid #000;font-size:18px;font-family:FangSong_GB2312}td{border:1px solid #000;font-size:18px;font-family:FangSong_GB2312}h1{font-size:80px;font-family:STZhongsong;letter-spacing:20px;text-align:center}h2{font-weight:700;font-family:FangSong_GB2312;font-size:30px;border:none!important}.subtitle h2{font-size:30px;color:red;font-family:STZhongsong;border:none!important}.title_bg h2{border:none!important}.report_moudle_header_title{border:none!important;font-size:18px!important;font-family:FangSong_GB2312}h3{font-weight:700;font-family:FangSong_GB2312;font-size:18px;text-indent:2em}p{font-size:18px;text-indent:2em;font-family:FangSong_GB2312}.module_text{font-family:FangSong_GB2312;line-height:38px}.article-analyis—title{font-size:16px;font-weight:700}
</style>
</head><body>
'
2.普通样式文本
直接拼接即可
template += "<div><h3>测试标题</h3></div>"
3.表格数据
也是直接拼接
template += <table class="table"
style="width: 100%; border-collapse: collapse; border-spacing: 0; border: 1px solid #e9e9e9;">
<thead>
<tr>
<th style="border: 1px solid #e9e9e9; background: #f7f7f7;">序号</th>
<th style="border: 1px solid #e9e9e9; background: #f7f7f7;">名称1</th>
<th style="border: 1px solid #e9e9e9; background: #f7f7f7;">名称2</th>
</tr>
</thead>
<tbody>
${p.data
.map(
(q, index) => `
<tr>
<td style="border: 1px solid #e9e9e9;">${
index + 1
}</td>
<td style="border: 1px solid #e9e9e9;">${
q.name
}</td>
<td style="border: 1px solid #e9e9e9;">${
q.value
}</td>
</tr>
`
)
.join('')}
</tbody>
</table>"
4.echarts图表
使用的lime-echart,地址:https://ext.dcloud.net.cn/plugin?id=4899 / https://gitee.com/liangei/lime-echart
修改组件方法,增加echarts图表导出图片功能
//位置 myapp\src\uni_modules\lime-echart\components\l-echart\l-echart.vue
通过provider和inject实现导出图片命名。cacheBase64存放图片地址,cId图片需要的命名
inject: ['cacheBase64', 'cId'],
...
async init()方法最后加入:
setTimeout(() => {
const canvasId = config.canvas.canvasId;
uni
.createSelectorQuery()
.in(this)
.select('#' + canvasId)
.fields(
{
size: true,
node: true,
},
(res) => {
const canvas = res.node;
//canvas转图片
uni.canvasToTempFilePath(
{
canvasId: canvasId,
canvas: canvas,
success: (res) => {
//图片转base64
uni.getFileSystemManager().readFile({
filePath: res.tempFilePath,
encoding: 'base64', // 编码格式
success: (res) => {
if (this.cId) {
//数据存入base64中
this.$set(
this.cacheBase64,
this.cId,
'data:image/png;base64,' + res.data
);
}
},
fail: function (err) {
console.error(err);
},
});
},
},
this
);
}
)
.exec();
}, 2000);
将所有需要的图片base64拼接入模板中:
template += `<div style="text-align: center;width: 100%">
<img
src="${this.cacheBase64[c.type]}"
style="width:100%;max-width: 800px">
<br>
</div>`
5.带有复杂样式效果的div
由于这个div的样式有很多before,after等样式效果。最后决定将效果渲染出来后再截图。使用puppeteer在node服务器上实现
安装puppeteer:使用puppeteer+独立安装liunx-chrome的方式
npm i puppeteer --ignore-scripts
下载linux-chrome,并将解压后的文件夹放入服务器上
# linux: https://cdn.npmmirror.com/binaries/chromium-browser-snapshots/Linux_x64/1271307/chrome-linux.zip
安装puppeteer服务器需要用到的其他包:
sudo apt-get install ca-certificates fonts-liberation libappindicator3-1 libasound2 libatk-bridge2.0-0 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgbm1 libgcc1 libglib2.0-0 libgtk-3-0 libnspr4 libnss3 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 lsb-release wget xdg-utils -y
将安装包解压到服务器上后,在该目录下使用操作:
1.将SIMSUN.TTC(window系统自带的宋体字体C:windows/fonts)文件复制到/usr/local/share/fonts目录下(linux导出存在乱码,这个是中文字体);
2.修改chrome权限:chmod -R 777 chrome-linux/chrome
chmod -R 777 /usr/node/htmldocxjs/chrome-linux/chrome_crashpad_handler
nodejs服务代码
// 测试时间线图
app.post('/transform/image', function (req, response) {
const data = req.body.data;
getColumnTImeLine(data).then((res) => {
//读取转为base64,后返回到前端
fs.readFile(res, 'base64', (err, data) => {
if (err) {
console.error(err);
response.send({ data: err });
return;
}
response.send({ data: data });
});
});
});
const puppeteer = require('puppeteer');
async function getColumnTImeLine(data) {
return new Promise(async (resolve, reject) => {
const brower = await puppeteer.launch({
executablePath: '**pathtochrom**/chrome-linux/chrome',
args: [
'--font-family=simsun',
'--disable-gpu',
'--disable-dev-shm-usage',
'--disable-setuid-sandbox',
'--no-first-run',
'--no-sandbox',
'--no-zygote',
'--single-process',
],
});
const page = await brower.newPage();
await page.setViewport({
width: 800,
height: 1500,
});
if (!data) {
}
//根据data生成html模板
const htmlContent = ``;
await page.setContent(htmlContent);
await page.screenshot({
path: path.join(__dirname, 'public') + '/test.png',
});
//返回生成图片的地址
resolve(path.join(__dirname, 'public') + '/test.png');
await brower.close();
});
}
//将返回的base64存入内存中
self.$set(
self.cacheBase64,
`${cId}`,
'data:image/png;base64,' + res.data.data
);
最后页面导出的时候将该组件替换img+base64代码放入模板中
6.添加结尾 ,后将文件通过步骤1进行html转doc文件。
template += </body></html>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人