微信小程式:需求將一個類似報表的頁面點選下載匯出問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>