微信小程序之导出页面为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>
posted @   whitebang  阅读(210)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
点击右上角即可分享
微信分享提示