使用场景
使用了云开发的数据库时,客户的订单信息在云数据库里,需要导出信息打印快递单号发货,这个时候就需要本篇文章的技术了。
其实,导出订单信息只是导出云数据库字段信息的一个分支,要从云数据库里导出其他数据集的数据按照本篇文章的操作同理。
解决思路
- 采用小程序端触发云函数执行导出订单代码段
- 云函数中读取所有的待发货订单信息,并拦截掉已经停发的订单区域,不进行载入表格
- 组织好xlsx文件中每一行要存放的数据内容
- 调用第三方JS包,将上述组织好的数据注入buffer变量内存中
- 调用cloud.uploadFile()上传函数,将数据上传至指定路径的云存储中
- 向前端返回整个导出函数对每个数据进行的执行情况
开发准备
- 微信开发者工具
- 云数据库里留有客户订单信息的数据集
- 创建相应的云函数,并配置好云函数的JS第三方包
开发过程
小程序端
触发云函数执行,并将返回的云文件fileID传值给下载函数获取下载链接
/**
* 通过云函数导出订单
* //把数据保存到excel里,并把excel保存到云存储
* 参数:导出订单的查询条件
*/
savaExcel() {
let that = this
//显示提示
wx.showLoading({
title: '正在导出订单',
icon: 'loading'
})
//调用云函数 导出订单
wx.cloud.callFunction({
name: "excel",
data: {
action: 'exportOrders'
},
success(res) {
// console.log("保存成功", res)
//调用获取云文件临时下载链接函数,传入数据包含生成的云文件fileID //返回的云端数据包括被拦截的订单,但是将 链接压入数据头部,故下标为0
that.getFileUrl(res)
},
fail(res) {
// console.log("保存失败", res)
wx.showToast({
icon: 'none', //不填默认为success 只能显示8个汉字
title: '导出订单失败,请稍后重试。错误信息:' + res,
duration: 6000
})
}
})
},
获取云文件下载地址,并在成功回调的函数里调用复制文本函数。注意:获取到的下载链接时效只有24小时。24小时后需要重新获取公网下载地址。
/**
* //获取云存储文件下载地址,这个地址有效期一天
* 传入上个函数 返回的云数据
*/
getFileUrl(cloudResult) {
let that = this,
fileID = cloudResult.result[0].fileID; //返回的云端数据包括被拦截的订单,但是将 链接压入数据头部,故下标为0
wx.cloud.getTempFileURL({
fileList: [fileID],
success: res => {
// get temp file URL
// console.log("文件下载链接", res.fileList[0].tempFileURL)
//隐藏提示
wx.hideLoading();
that.setData({
fileUrl: res.fileList[0].tempFileURL,
historyorders: cloudResult.result //为了优化视觉体验,所以到这里才传入相关的值
})
that.copyFileUrl() //链接生成成功调用复制按钮
},
fail: err => {
// handle error
}
})
},
复制下载链接地址
为什么要复制?因为在小程序里直接下载下来打开后只能看看,没有办法发给指定的人,并且下载的文件是在微信定义的临时文件夹里,受10M大小的限制的。在这种情况下,只好将复制到的链接拿到浏览器里去打开,并下载文件。
/**
* //复制excel文件下载链接
*/
copyFileUrl() {
let that = this
wx.setClipboardData({
data: that.data.fileUrl,
success(res) {
wx.getClipboardData({
success(res) {
// console.log("复制成功", res.data) // data
wx.showToast({
title: '链接复制成功',
})
}
})
}
})
},
云函数端
初始化云函数环境。注意:声明云数据库全局操作变量,要在云函数初始化cloud之后才可以进行声明,否则会报错。
// 云函数入口文件
const cloud = require('wx-server-sdk')
const app = require('tcb-admin-node');
//操作excel用的类库
const xlsx = require('node-xlsx');
// 初始化 cloud
cloud.init({
env: process.env.Env //云函数环境切换 process.env.配置的变量名
})
//操作云数据库使用的变量 要在初始化 cloud 之后再进行声明
const db = cloud.database();
const _ = db.command //数据库的command命令
const $ = _.aggregate //聚合使用声明符
/**
* 触发相应动作
* action 要触发运行的代码片段//
* formId 用户触发能发 模板的Id
*/
// 云函数入口函数
exports.main = async (event, context) => {
//输出操作者的日志到控制台上
console.log('操作者openid=> ' + event.userInfo.openId)
switch (event.action) {
case 'exportOrders': { //导出订单
return exportOrders(event)
}
} //switch 大括号结束
生成excel文件函数。对于待发货的订单,在保存数据的时候将某个字段设为标记字段,通过查询相应标记值获取待发订单数据即可。注意:云函数中单次数据获取的上限是100,如果待发货超出这个数量,要进行分批次获取。以下demo中没有写分批次获取的代码,需要请自行修改。 拦截停发区域的方法,其实就是字符串判断,对于符合拦截字符串进行拦截即可。
/**
* 导出订单
* 所查询的 待发货条件 与批量导出订单 所查询的条件要保持一致
*
* 前端页面 客户个人的 待发货查询条件也要与此保持一致 出了客户自己的openid查询条件外 都要保持一致
* courierNumber: _.or(_.eq(null),_.eq('')), //字段不存在的为待发货 客服修改过后可能导致 该字段成为'' 故增加这个选择 与批量发货条件保持一致
* 前端页面的位置是 pages/tabBar/queryorder/queryorder
*
*
* var province = ["广东", "北京", "浙江", "福建", "湖北", "上海", "江苏", "天津", "河北", "山西", "内蒙古", "辽宁", "吉林", "黑龙江", "安徽", "江西", "山东", "河南", "湖南", "广西", "海南", "重庆", "四川", "贵州", "云南", "西藏", "陕西", "甘肃", "青海", "宁夏", "新疆", "台湾", "香港", "澳门"];
*/
async function exportOrders(event) {
try {
const tasks = [] //用来存储所有要返回的数据
let stopAreaTemp = await db.collection('control').where({
_id: 'fissionCode'
}).field({
stopArea:true //只返回 停发区域字段数值
}).get()
// console.log(stopAreaTemp.data[0].stopArea) //获取停发区域数组
// return
const stopArea = stopAreaTemp.data[0].stopArea
//0,按照查询条件,读取订单数据
let temp = await db.collection('Shopping').where(
queryConditions_steamQuantity
)
.orderBy('specifications', 'desc').get()
let orderdata = temp.data
//0.5,构造导出时间 以便文件命名 Date.now()是时间戳
let curDate = new Date();
let time = `${curDate.getFullYear()}年${curDate.getMonth() +1}月${curDate.getDate()}日${curDate.getHours() + 8}-${curDate.getMinutes()}-${curDate.getSeconds()}`;
/构造明文下单日期代码结束///
//1,定义excel文件名 商品名+导出的时间.xlsx
let fileName = `微信小程序-${time}.xlsx`
//2,定义存储数据的
let alldata = []
let row = ['业务单号', '收件人', '收件人电话', '收件人地址', '备注', '客户留言', '物流公司(请填写物流公司名称,没填则为百世快递)','百熟内部留言','订单日期'] //表头属性 即表格第一行的 名称 ,备注即为 商品名+商品规格
alldata.push(row)
//从第二行开始写入数据
for (let key in orderdata) { //注意要与数据表里的字段名字相同字相同 key 从0 到orderdata 的长度。orderdata[key].quantity 单条数据里的 购买数量 用它循环几次
///*拦截停发区域代码块 *****///
let judge = await stopAreaJudge(orderdata[key].address, stopArea) //进入判断拦截地址的函数 被拦截则返回1
if (judge==1){
//拦截输出的代码块///
let arr = [] //清空arr,重新拼凑一行数据
arr.push(orderdata[key]._id) //业务单号
arr.push(orderdata[key].consignee)
arr.push(orderdata[key].tel)
arr.push(orderdata[key].address)
arr.push(orderdata[key].specifications) //备注 商品名+商品规格 productSpecifications
arr.push(orderdata[key].message) //客户留言
arr.push('') //发快递的占位空格
arr.push(orderdata[key].orderRemarks) //百熟内部留言
arr.push(orderdata[key].time) //订单日期
tasks.push(arr) //一行数据完结了,写入缓存 将拦截的订单写入一会儿要返回的变量里
continue //继续开始下次循环
}
///*********************** */
正常发货时的 组织数据
for (let i=0;i< orderdata[key].quantity;i++){ //数量比较多的,就多循环几次,这样快递按行打单的就没有问题了
let arr = [] //清空arr,重新拼凑一行数据
arr.push(orderdata[key]._id+'-'+i) //只有一件的时候 业务单号-0
arr.push(orderdata[key].consignee)
arr.push(orderdata[key].tel)
arr.push(orderdata[key].address)
arr.push(orderdata[key].specifications) //备注 商品名+商品规格 productSpecifications
arr.push(orderdata[key].message) //客户留言
arr.push('') //发快递的占位空格
arr.push(orderdata[key].orderRemarks) //百熟内部留言
arr.push(orderdata[key].time) //订单日期
alldata.push(arr) //一行数据完结了,写入缓存
}
} //for (let key in orderdata) {}结束
//3,把数据保存到excel里
var buffer = await xlsx.build([{
name: "mySheetName",
data: alldata
}])
//4,把excel文件保存到云存储里,并返回 云端文件路径
const promise = await cloud.uploadFile({
cloudPath: '商品订单/' + fileName, //文件夹不存在则会自动创建
fileContent: buffer, //excel二进制文件
})
tasks.unshift(promise) //从头部压入云端路径
//格式化一下 要返回的数据 云端文件路径 与 停发区域的订单信息
// 等待所有数据添加完成
let result = await Promise.all(tasks).then(res => {
return res
}).catch(function (err) {
return '导出订单,返回任务过程发生错误' + err
})
// console.log(result)
return result
} catch (e) {
console.error('导出订单错误信息:'+e)
return e
}
}
***********导出订单************** */
是否停发区域字符串判断函数,注意stopArea数组变量是由上一个函数传递来的。
/**
* 包裹一个函数方法,拿来判断是否停发区域
* 传入参数 地址,停发区变量数组
* 返回参数 有停发区域时 1
*/
async function stopAreaJudge(address,stopArea) {
///* 判断有没有 停发区域的订单 **
for (var i = 0; i < stopArea.length; i++) {
if (address.substr(0, 9).indexOf(stopArea[i].slice(0, 2)) > -1) {
return 1
}
}
}
总结
本篇文章介绍了整个订单信息导出实现的过程,其实不仅仅是导出订单信息,只要是在云数据库里的数据,按照本篇文章介绍的技术方法,全部可以导出。不过,要注意导出时候的极限值,云函数中读取的数量是100上限,超出的话要进行分批次读取。
感谢CSDN,感谢原力计划,本来不打算写这篇文章的,看见另一篇被选入热门了,就把这一篇补充一下了。本篇文章是《亿级电商微信小程序流量,如何优雅的使用云开发进行订单发货?》的前序,有了订单信息才能进行发货嘛。
欢迎大家收藏关注,我将不定期分享微信小程序云开发中遇到的问题以及技巧分享,让大家可以避免重复走我走过的坑。