node-xlsx 生成并下载有超链接的excel文件
需求:将微信小程序云数据库中的数据导出为excel文件,文件按团队分为不同的sheet页,首页汇总每个sheet页的数据总数,并可点击跳转至对应的sheet页。下载时可选择今年某月份进行下载对应的数据。get到如上需求,记录一下完成时遇到的问题。问题1:如何生成并下载excel文件?思路:在云函数端通过 node-xlsx 生成excel文件流,通过cloud.uploadFile 将本地资源上传
需求:将微信小程序云数据库中的数据导出为excel文件,文件按团队分为不同的sheet页,首页汇总每个sheet页的数据总数,并可点击跳转至对应的sheet页。下载时可选择今年某月份进行下载对应的数据。
get到如上需求,记录一下完成时遇到的问题。
问题1:如何生成并下载excel文件?
思路:在云函数端通过 node-xlsx 生成excel文件流,通过 cloud.uploadFile 将本地资源上传至云存储空间,在小程序端通过 cloud.downloadFile 从云存储空间下载文件。
云函数端:
...
async downloadExcel(event, context, db) {
//获取数据
let info = await db.collection('数据库表名').get();
let dataCVS = `excel.xlsx`;
let alldata = [];
let row = ['name', 'time','team'];
alldata.push(row); //将此行数据添加到一个向表格中存数据的数组中
for (let key = 0; key<info.data.length; key++) {
let arr = [];
row.forEach(item=>{
arr.push(info.data[key][item]);
})
alldata.push(arr)
}
var buffer = await xlsx.build(build);
//将表格存入到存储库中并返回文件ID
return await cloud.uploadFile({
cloudPath: dataCVS,
fileContent: buffer, //excel二进制文件
})
}
小程序端:
downloadExcel() {
wx.cloud.callFunction({
name: 'downloadExcel'
success: res => {
wx.cloud.getTempFileURL({
//获取文件下载地址
fileList: [res.result.fileID],
success: res => {
wx.downloadFile({
url: res.fileList[0].tempFileURL,
filePath: wx.env.USER_DATA_PATH + '/数据.xlsx', //本地文件路径
success(res) {
let data = res.filePath;
wx.openDocument({ //打开文档
filePath: data,
showMenu: true
});
},
fail(res) {
console.log(res);
}
});
},
fail(res) {}
});
},
fail(res) {}
});
}
问题2:如何导出不同的sheet页?
解决:build时,数组的长度是多少则生成多少个sheet页。
例:
import xlsx from 'node-xlsx';
const data1 = [[1, 2, 3], [true, false, null, 'sheetjs'], ['baz', null, 'qux']];
const data2 = [[1, 2, 3], ['foo', 'bar', new Date('2014-02-19T14:30Z'), '0.3'], ['baz', null, 'qux']];
var buffer = xlsx.build([{name: "sheet1", data: data1},{name: "sheet2", data: data2}]);
问题3:如何实现点击首页汇总信息的不同单元格跳转至对应的sheet页?
思路:官方文档只提供了跳转外部链接和跳转同一页单元格的实例,那如何链接跳转至其他sheet页呢?在excel中,可以用 hyperlink 这个超链接函数实现跳转至其他工作表(sheet页),excel中的用法是 hyperlink("#表格名称!单元格",引用目标),在 node-xlsx 中超链接函数也叫 hyperlink,那用法是否也是如此呢?试试将单元格元素的 l 的target 写为 "#其他sheet页名称!A1",点击跳转,果然跳转指向其他sheet页的A1单元格。
例:
...
let indexPage = [
['团队', '数量']
];
let build = alldata.map((item, index) => {
indexPage.push([{
t: "s", //单元格类型string
v: sheets[index], //值
l: {
Target: `#${sheets[index]}!A1` //跳转
}
}, item.length])
item.unshift(row)
return {
name: sheets[index], //对应的sheet页名称
data: item
}
})
build.unshift({
name: '汇总',
data: indexPage
})
var buffer = await xlsx.build(build);
...
问题4:下载所有数据时,总数远远少于数据库中的数据量?
原因:统计集合记录数或统计查询语句对应的结果记录数,小程序端与云函数端的表现会有如下差异:
- 小程序端:如果没有指定 limit,则默认且最多取 20 条记录。
- 云函数端:如果没有指定 limit,则默认且最多取 100 条记录。
解决:官方提供了解决样例(如下),更多查看这部分的官方文档。
const cloud = require('wx-server-sdk')
cloud.init({
env: cloud.DYNAMIC_CURRENT_ENV
})
const db = cloud.database()
const MAX_LIMIT = 100
exports.main = async (event, context) => {
// 先取出集合记录总数
const countResult = await db.collection('todos').count()
const total = countResult.total
// 计算需分几次取
const batchTimes = Math.ceil(total / 100)
// 承载所有读操作的 promise 的数组
const tasks = []
for (let i = 0; i < batchTimes; i++) {
const promise = db.collection('todos').skip(i * MAX_LIMIT).limit(MAX_LIMIT).get()
tasks.push(promise)
}
// 等待所有
return (await Promise.all(tasks)).reduce((acc, cur) => {
return {
data: acc.data.concat(cur.data),
errMsg: acc.errMsg,
}
})
}
问题5:点击不同的月份,即传参不同,下载下来的excel文件未变化,或有时变化?
思考:
- 参数未传递过去或是异步导致未及时获取到最新参数?经过验证,接收到了每次传递的参数,排除。
- 获取的数据库数据不是最新的?经过验证,排除。
- 上传上去的文件未更新?因为想到我每次上传上去的文件名是一样的,但官方文档明明说:将本地资源上传至云存储空间,如果上传至同一路径则是覆盖 呀?查了查,发现了相似的问题讨论:地址,看来应该是上传后同名文件未覆盖的。
解决:将文件名改为时间戳(不过我自己是把文件名改为对应的月份,这样最多只有12个此文件,因为数据不会经常下载,每次下载间隔时间长,会得到最新文件,所以一般不会有问题),试试,每次下载的文件是对应的数据了。但这种方式不是很好,若有朋友有更好的方法,希望可以提供呀。
更多推荐
所有评论(0)