这篇是微信小程序前后端快速入门完结篇了,今天利用之前学习过的所有知识做一个新的项目「群登记助手v1.0」小程序。
整体技术架构:小程序原生前端+小程序云开发。
经历了前面教程的学习,大家有了一定的基础,所以本次分享重心主要是带着大家理清楚逻辑相关的云开发处理方案和之前未讲解过的重要组件,之前已经讲解过的重复知识就不会重新再讲解,需要大家利用之前已经学习过的知识来组合今天学习的新知识对接龙小程序进行整体的完善。
接龙小程序使用者角色上会有两种,分别是发起者和参与者。这个接龙是由发起者来让参与者接龙,所以他们两之间的使用逻辑是:
界面如下:
首先数据库设计来看,我们需要三张表:
2. 接龙活动表(solitaire),用于存放发起者接龙活动
3. 接龙信息表(solitaire_info),用于存放参与者接龙信息
难点部分会进行分析讲解,简单部分需自行实现(之前教过的知识点)
由于接龙信息和用户信息分别在两张表中实现,所以这里需要用到联表查询。这个时候就需用到小程序的聚合查询能力。
如我们现在已经有一条活动数据了,那么现在数据库的数据结构应该是这样的:
用户表 users:
lookup({
from: <要连接的集合名>,
localField: <输入记录的要进行相等匹配的字段>,
foreignField: <被连接集合的要进行相等匹配的字段>,
as: <输出的数组字段名>
})
结合以上使用方式,我们使用下lookup连接查询
async queryLookupList(context, params) {
let res = await db.collection('solitaire').aggregate()
.match({
openid: context.OPENID
})
.lookup({
from: 'users',
localField: 'openid',
foreignField: '_openid',
as: 'users',
})
.sort({
date: -1
})
.end()
return res
}
最后查询出来的结果是:
[
{
"_id": "cd045e756110ed09047443683dd70ecf",
"content": "312312",
"date": "2021-08-09 16:53",
"title": "12312",
"type": 1,
"openid": "oyfiv5Z90bqbQ6BJ6A273eP68j-w",
"number": 0,
"users": [
{
"_id": "8937eaa96110ea39039e900278a1529e",
"_openid": "oyfiv5Z90bqbQ6BJ6A273eP68j-w",
"date": "2021-08-09T08:41:29.878Z",
"userInfo": {
"avatarUrl": "https://thirdwx.qlogo.cn/mmopen/vi_32/Q0j4TwGTfTJ9VBHPzRxk4M7bc4xxwXOaw6DpciahEjzeZ4GP0UoSmiaqBMFQznROZlVG5ukvpv8dSXNzl34oaP7g/132",
"city": "Changsha",
"country": "China",
"gender": 1,
"language": "zh_CN",
"nickName": "111陈宇明",
"province": "Hunan"
}
}
]
}
]
由于在实际复杂业务中,聚合查询使用的比较多的,所以再次我们带大家来对聚合查询进行更深入的了解。
聚合是非常强大的数据分析工具,主要用于对记录进行批量处理,可以对记录进行按条件分组、跨集合联表等一系列批量而又复杂操作。类似于Excel整列整列跨字段的运算(如加、减、合并、比较等)、对内嵌的字段可以进行整列拆分、类型变换、组合等。
聚合aggregate和普通数据查询get是两套不同的体系,聚合更偏向于数据的复杂查询。聚合查询和普通数据查询都能对数据库进行查询,两个的很多方法都特别类似,我们可以通过对之前普通查询的理解来理解聚合查询的部分功能,具体查看以下表格对比。
在这里需要注意的是使用聚合查询之前需要先 aggregate() 发起一个聚合操作。以上是普通查询可以做到的,聚合查询也可以做到,接下来是普通查询做不到的。
聚合阶段是聚合管理流水线作业的组成单元,是一个个功能节点,有的可以联表lookup、有的可以组合group、有的可以拆分unwind等等。每个聚合阶段可以使用表达式、操作符对输入文档进行计算综合、均值、拼接、分割、转换格式等操作,操作完成之后会输出给下一个阶段,直到end返回结果。
在这里告诉大家一个小技巧,其实写查询的时候可以在数据库的高级操作区间先写好测试然后再放到函数中去使用,这样可以提高效率。
在这里不需要获取数据库对象,直接通过db就能使用,数据也不需要打印出来,只要使用了结束函数就可以了。
当发起者转发到群里之后,参与者就可以填写接龙信息,当接龙信息填写完成之后,可以在这里给到参与者发送一个订阅消息,告知参与者接龙成功。
这样设计有两个好处:
那么如何给用户发送订阅消息呢?请接着往下看:
第一步,先登录到后台,找到订阅消息菜单->申请订阅消息模版
第二步,进入订阅消息列表页面,点击选用按钮
第三步,进入选用模版库,通过关键词搜索进行查找,消息模版和小程序的类目有关,以“接龙”为例,小程序类目是「预约/报名,笔记」所以搜索到了这两个类目下的消息模版。
第四步,选择自己需要的模版,点击「选用」进入详情页面。模版有很多关键词,只需要勾选自己需要的关键词即可,然后填写下场景说明即可点击提交
第五步,填写完成后,会在我的模版看到刚才申请好的消息模版,复制模版ID即可,到时候然后切换到小程序端进行使用
第六步,找到小程序需要让用户授权的触发方法。如:需求是当用户填写完成接龙资料,让用户授权报名成功提醒,然后发一条报名成功的订阅消息,那么这个时候就需要找到填写信息的方法。如果只是单独先对这个功能进行学习,那么就可以在一个页面写个按钮,然后按钮绑定一个点击事件触发即可。
写在任意测试页面wxml
当前测试页面对应的js
wx.requestSubscribeMessage({
tmplIds: ['模版ID'],
success(res) {
console.log(res)
}
})
第七步,用真机调试,模拟器不支持。点击之后界面会出现授权页面。
以下为我分别点击取消和允许的日志输出。用户可以支持一次调用最多可订阅3条消息。
然后我们再来看下 requestSubscribeMessage 文档中对返回体的解释
对于开发者来说,需要关心的就是是否用户允许来,所以我们需要通过以下方式获取结果,当结果是允许的时候我们插入就发送成功通知给到用户即可。当然我这里指的是用户添加完后发送添加成功通知的业务路径,如果不是需要当前动作完成后发送的话,那么就需要存储一条记录到数据库,等需要用到的时候再去做发送消息模版的动作。
onMsg() {
wx.requestSubscribeMessage({
tmplIds: ['模版ID'],
success(res) {
if(res.模版ID=='accept'){
// 发送消息给到用户
}
}
})
}
第七步,发送模版消息,新建一个发送模版消息的云函数 sendMessage ,然后打开 subscribeMessage. send 文档,可以看到这个方法支持云调用,也就是说官方已经帮开发者封装好了方法使用起来非常简单。
云调用是云开发提供的基于云函数使用小程序开放接口的能力
那么我们就用云调用方法来试试,首先在 sendMessage 的config.json文件配置权限
{
"permissions": {
"openapi": [
"subscribeMessage.send"
]
}
}
然后在js中编写调用发送模版消息的方法,方法参数如下:
我把重要的参数用红色框框标记起来了,看下代码。
// 云函数入口文件
const cloud = require('wx-server-sdk')
cloud.init()
// 云函数入口函数
exports.main = async (event, context) => {
const wxContext = cloud.getWXContext()
const result = await cloud.openapi.subscribeMessage.send({
"touser": wxContext.OPENID, // 发给自己直接从 getWXContext 获取
"templateId":'模版ID',
"page": '目标页面路径',
"lang": 'zh_CN',
"data": {
"thing2": {
"value": '报名接龙2021'
},
"phrase8": {
"value": '报名成功'
},
"thing19": {
"value": '详细点击查看=>'
}
},
"miniprogramState": 'developer'
})
return result
}
注意 data 这个参数需要回到小程序管理后台的消息订阅列表查看订阅模版的详情
这里需要注意每个不同的数据类型都有些限制条件详细可见文档,然后data参数需要和上面的模版内容一对一对应上,方法写完上传并部署即可。
第八步,调用模版消息。
onMsg() {
wx.requestSubscribeMessage({
tmplIds: ['模版ID'],
success(res) {
if (res.XXXXID == 'accept') {
wx.cloud.callFunction({
name: 'sendMessage'
}).then(res => {
console.log(res)
})
}
}
})
}
调用成功后会在微信聊天页面的服务通知中收到模版消息提醒,点击即可进入小程序,效果如下:
使用云函数使用Node.js的node-xlsx模块
npm install node-xlsx
const xlsx = require('node-xlsx')
let row = ['姓名', '电话', '备注']; //表格的属性
let allData = [] //表格内容
// 添加表头
allData.push(row)
// 假数据,真实数据需要从小程序端传递过来或在云函数中云数据库查询出来
allData.push(['陈宇明', '13148123123', ''])
allData.push(['陈X明', '13148123123', '不知道'])
// 生成表格
var buffer = await xlsx.build([{
name: 'mySheetName',
data: allData
}]);
let cloudPath = `xlsx/${Math.floor(Math.random()*1000000000)}.xlsx`
//上传文件返回结果
return await cloud.uploadFile({
cloudPath: cloudPath,
fileContent: buffer, //excel二进制文件
})
当获取到文件ID,在使用 getTempFileURL 用云文件 ID 换取真实链接,然后 downloadFile 下载文件资源到本地,通过 openDocument 新开页面打开文档。
openExcel(){
wx.cloud.callFunction({
name: "excel",
data: {
infos: {} //表格数据
},
complete: res => {
wx.cloud.getTempFileURL({
fileList: [res.result.fileID],
success: res => {
this.setData({
tempFileURL: res.fileList[0].tempFileURL
})
console.log(this.data.tempFileURL)
wx.downloadFile({
url: this.data.tempFileURL,
success: (res) => {
const filePath = res.tempFilePath
console.log(filePath)
wx.openDocument({
filePath: filePath,
showMenu: true,
success: res => {
console.log(res)
}
})
}
})
}
})
}
})
},
当获取到文件ID,在使用 getTempFileURL 用云文件 ID 换取真实链接,然后 setClipboardData 设置系统剪贴板的内容。
getExcelUrl() {
wx.cloud.callFunction({
name: "excel",
data: {
infos: {} //表格数据
},
complete: res => {
wx.cloud.getTempFileURL({
fileList: [res.result.fileID],
success: res => {
this.setData({
tempFileURL: res.fileList[0].tempFileURL
})
wx.setClipboardData({ //复制到粘贴板
data: this.data.tempFileURL,
success(res) {
wx.getClipboardData({
success(res) {
}
})
}
})
}
})
}
})
},
这篇教程相比之前的备忘录教程更像是一道填空题,需要大家利用之前教程学习到的知识进行融合才能实现这个小程序,独立完成这个项目才是检验学习效果的最佳方式。
学习更多小程序云开发知识请关注CRMEB开源项目