简介:
1、微信登录
2、微信用户todolist管理
3、根据todolist发送消息推送
4、根据todolist发送邮件提醒
1、准备工具
- 微信小程序开发工具
下载:
微信开发者工具(稳定版 Stable Build)下载地址与更新日志 | 微信开放文档
2、项目准备
- 注册小程序
小程序
获取到创建项目时使用的AppID
- 项目创建(根据上一步生成的AppID创建项目)
- 云环境创建
环境名称:test。一个小程序最多可以有2个隔离的云环境,通常来说测试环境取名为 test,以后的正式环境可取名为 release。
付费方式:按量付费,具有一定的免费额度。在少量用户时等同于免费。
- 云环境中创建数据库
云开发->数据库->"+"按钮->"todo" 确认
- 小程序打开消息订阅功能(可选,适用于待办事项消息推送)
- 邮箱打开POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务(可选,适用于发送待办事项邮件推送)
设置 - 账户 - 开启 POP3/SMTP 服务
更具提示生成授权码(后续要用)
3、项目结构
-
cloudfunctions/ 云函数目录 (配置项目配置文件project.config.json后产生)
-
getList/ 云函数getList (右键cloudfunctions "新建Node.js" 名称为 getList生成)
-
pushNotify/ 云函数pushNotify 同上 (包含触发器)
-
sendEmail/ 云函数sendEmail 同上
-
updateCheck/ 云函数updateCheck 同上
-
page/ 页面配置目录
-
page/index/ 主页配置目录
-
page/log/ 日志配置目录
-
app.js 应用主逻辑文件(js编程)
-
app.json 应用整体配置文件(json格式,主要环境变量等)
-
index.wxml 应用页面框架(和html页面相同,主要定页面框架)
-
app.wxss 应用渲染(可以理解为css渲染)
注意:
1、page/index/ 目录中同样存在.js .json .wxml .wxss文件和app主目录相同,主要编写逻辑部分,及js文件。其他云函数和页面类似。
2、云函数编辑完成后需要右键 "上传并部署:云端安装依赖..."
3、包含触发器的云函数编辑上传后,需要 右键 "上传触发器"
4、项目源码
本地代码部分
app.js
// app.js
App({
onLaunch () {
// Do something initial when launch.
//初始云化
this.initcloud()
this.globalData = {
// 用于存储待办记录的集合名称
collection: 'todo', // 填写数据库中创建的collection
}
},
// 初始化云开发环境
initcloud() {
wx.cloud.init({
traceUser: true,
// 填写你的云环境id
env: "**********************" // 请填写你云环境的ID 云开发->概览->环境ID(右上角)
})
// 装载云函数操作对象返回方法
this.cloud = () => {
return wx.cloud // 直接返回 wx.cloud
}
},
// 获取云数据库的实例
async database() {
return (await this.cloud()).database()
},
onShow (options) {
// Do something when show.
},
onHide () {
// Do something when hide.
},
onError (msg) {
console.log(msg)
},
globalData: 'I am global data'
})
app.json
{
"pages": [
"pages/index/index",
"pages/logs/logs"
],
"window": {
"navigationBarBackgroundColor": "#6495ED",
"navigationBarTitleText": "Todo-List"
},
"style": "v2",
"sitemapLocation": "sitemap.json",
"useExtendedLib": {
"weui": true
}
}
project.config.json
{
"appid": "****************", // 请填写申请的微信小程序AppId 开发工具->详情->基本信息 或微信小程序主页设置中查找
"compileType": "miniprogram",
"libVersion": "2.32.2",
"packOptions": {
"ignore": [],
"include": []
},
"setting": {
"coverView": true,
"es6": true,
"postcss": true,
"minified": true,
"enhance": true,
"showShadowRootInWxmlPanel": true,
"packNpmRelationList": [],
"babelSetting": {
"ignore": [],
"disablePlugins": [],
"outputPath": ""
},
"condition": false
},
"condition": {},
"editorSetting": {
"tabIndent": "insertSpaces",
"tabSize": 2
},
"cloudfunctionRoot": "cloudfunctions/",
"cloudfunctionTemplateRoot": "cloudfunctionTemplate/"
}
page\index\index.wxml
<view class="container">
<!-- 在container的头部添加新代码 -->
<view class="list-input">
<!-- 输入框本体 -->
<view class="weui-cell weui-cell_input">
<input
value="{{inputedValue}}"
bind:input="keyInput"
class="weui-input"
maxlength="50"
placeholder="请输入待办事项"
/>
</view>
<!-- 分割线 -->
<view class="line"></view>
<!-- 提交按钮 -->
<button
bind:tap="inputSubmit"
class="weui-btn"
type="default"
style="color: gray;"
>提交</button>
</view>
<view class="weui-cells weui-cells_after-title">
<checkbox-group bind:change="checkboxChange">
<label class="weui-cell weui-check__label" wx:for="{{items}}" wx:key="id">
<view class="weui-cell__hd">
<checkbox value="{{item.id}}" checked="{{item.checked}}" />
</view>
<view class="weui-cell__bd">
{{item.content}}
</view>
</label>
</checkbox-group>
</view>
</view>
page\index\index.wxss
.list-input {
padding-top: 30rpx;
padding-bottom: 50rpx;
}
.line {
width: 100%;
height: 3rpx;
background: #ddd;
margin-bottom: 20rpx;
}
page\index\index.js
// pages/index/index.js
Component({
// 页面持有的数据
data:{
// todo-list 数据
items: [],
// 输入框当前内容
inputedValue: "",
},
lifetimes: {
attached() {
getApp().cloud().callFunction({
name: 'getList',
complete: res => {
// console.log('callFunction result: ', res)
this.setData({
items: res.result.data
})
}
})
},
},
methods: {
// 辅助函数,生成一个随机的id
getUUID(randomLength = 12) {
return Math.random().toString().substr(2,randomLength) + Date.now().toString(36)
},
// 监听输入框按键
keyInput(e){
this.setData({
inputedValue: e.detail.value
})
},
// 提交数据
inputSubmit(){
// 设置条目的id
const newID = this.getUUID()
const newItem = {
id: newID,
content: this.data.inputedValue,
checked: false,
// 新增是否订阅数据代码
pushed: false,
}
// 将新条目更新到iteams状态中
// 并将输入框的值清空
let items = JSON.parse(JSON.stringify(this.data.items))
items.unshift(newItem);
this.setData({
items: items,
inputedValue: "",
})
// 将items提交到云数据库
this.uploadData(newItem)
// 订阅服务
this.subscribe()
// 发送邮件服务
console.log('发送邮件!!!')
getApp().cloud().callFunction({
name: 'sendEmail',
data: {
content: newItem.content
},
})
},
// 上传数据到云数据库
async uploadData(item) {
const db = await getApp().database()
db.collection('todo').add({
data: item
})
},
// 更新待办事项的完成状态
checkboxChange(e){
let items = JSON.parse(JSON.stringify(this.data.items))
// 遍历items状态,找到checked状态变化的元素
for (const [index,item] of items.entries()){
if (item.checked !== e.detail.value.includes(item.id)){
// setData 状态修改数据元素的一种方法
const key = `items[${index}].checked`
const checked = !items.checked
this.setData({
// 注意这里要加括号 []
[key]: checked
})
// 调用云函数,更新数据库
getApp().cloud().callFunction({
name: 'updateCheck',
data: {
id: item.id,
checked: checked
}
})
break
}
}
},
// 新增方法
// 向用户申请推送服务
subscribe(){
// 填写你自己的模板id
const templateId = '****************************' // 请填写订阅事件模板ID
// 仅显示了主流程
// 正式环境中,需考虑到用户可能会点击'拒绝','永久拒绝'等情况
// 并弹出对应的反馈,如弹窗等
wx.requestSubscribeMessage({
tmplIds: [templateId],
success (res) {
console.log('订阅成功',res)
},
fail (err) {
console.log('订阅失败',err)
}
})
},
},
})
云函数部分
cloudfunctions\getList\index.js
// 云函数入口文件
const cloud = require('wx-server-sdk')
cloud.init({env: cloud.DYNAMIC_CURRENT_ENV})
// 获取云数据库对象
const db = cloud.database()
// 云函数入口函数
exports.main = async (event,context) => {
// 获取微信用户的 openID
const openID = cloud.getWXContext().OPENID
// 查询当前用户的所有待办数据
const fetchResult = await db.collection('todo').where({
_openid: openID,
checked: false,
}).get()
return fetchResult
}
cloudfunctions\pushNotify\index.js
const cloud = require('wx-server-sdk')
// 初始化 cloud
cloud.init({
// API 调用都保持和云函数当前所在环境一致
// 不加此参数就默认为第一个创建的云环境
env: cloud.DYNAMIC_CURRENT_ENV
})
const db = cloud.database()
const kTableName = 'todo'
// 云函数入口函数
exports.main = async (event, context) => {
try {
// --- 步骤1 ---
// 从云开发数据库中查询等待发送的消息列表
const msgArr = await db
.collection(kTableName)
// 查询条件
.where({
checked: false,
pushed: false,
})
.get()
// --- 步骤2 ---
for (const msgData of msgArr.data) {
// 发送订阅消息
await cloud.openapi.subscribeMessage.send({
touser: msgData._openid, // 要发送用户的openid
page: 'pages/index/index', // 用户通过消息通知点击进入小程序的页面
lang: 'zh_CN',
// 订阅消息模板ID
// 替换为你的模板id!
templateId: '****************************', // 请填写订阅事件模板ID
// 跳转小程序类型:developer为开发版;trial为体验版;formal为正式版;默认为正式版
// 正式版删除此行
miniprogramState: 'developer',
// 要发送的数据,要和模板一致
data: {
// 待办的主题
thing1: {
value: msgData.content === '' ? '无' : sliceBodyStr(msgData.content, 16)
},
// 待办的详情
thing4: {
value: '别忘了待办事项哟'
},
}
})
// --- 步骤3 ---
// 发送成功后将pushed数据状态重置
db
.collection(kTableName)
.doc(msgData._id)
.update({
data: {
pushed: true
},
})
}
// --- 步骤4 ---
return msgArr
} catch (e) {
return e
}
}
// 将太长的文本截短
function sliceBodyStr(str, length) {
if (str.length <= length) {
return str
} else {
return str.slice(0, length) + '...'
}
}
cloudfunctions\pushNotify\config.json (触发器部分)
{
"permissions": {
"openapi": ["subscribeMessage.send"]
},
"triggers": [{
"name": "myTimer",
"type": "timer",
"config": "*/50 * * * * * *"
}]
}
cloudfunctions\sendEmail\index.js
// 云函数入口文件
const cloud = require('wx-server-sdk')
cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV }) // 使用当前云环境
// 引入nodemailer
const nodemailer = require('nodemailer')
// 创建一个SMTP客户端配置
const config = {
host: 'smtp.qq.com', // 邮箱smtp服务,不同厂家地址不一样
port: 465, // 邮箱端口,不同厂家可能不一样
auth: {
user: '这里填写你的邮箱',// 邮箱账户 这里填写你的邮箱
pass: '这里填写你的邮箱授权码' // 邮箱授权码 这里填写你的邮箱授权码
}
};
// 创建一个SMTP客户端对象
var transporter = nodemailer.createTransport(config);
// 云函数入口函数
exports.main = async (event, context) => {
// 创建一个邮件对象
var mail = {
// 发件人,填写发件人邮箱
from: '来露娜 <******@***.***>',
// 主题
subject: 'Weapp [待办清单] 用户反馈',
// 收件人
to: '******@***.***', // 请填写收件人邮箱
// 邮件内容,text或者html格式
text: event.content
};
let res = await transporter.sendMail(mail);
return res;
}
cloudfunctions\updateCheck\index.js
// 云函数入口文件
const cloud = require('wx-server-sdk')
cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV }) // 使用当前云环境
// 获取云数据库
const db = cloud.database()
// 云函数入口函数
exports.main = async (event, context) => {
const openID = cloud.getWXContext().OPENID
try{
return await db.collection('todo').where({
id : event.id,
_openid: openID,
})
.update({
data: {
checked: event.checked
},
})
} catch(e){
console.error(e)
}
}
注意:
1、需要修改如下信息
app.js
// 填写你的云环境id
env: "**********************" // 请填写你云环境的ID 云开发->概览->环境ID(右上角)
project.config.json
"appid": "****************", // 请填写申请的微信小程序AppId 开发工具->详情->基本信息 或微信小程序主页设置中查找
page\index\index.js
// 填写你自己的模板id
const templateId = '****************************' // 请填写订阅事件模板ID
cloudfunctions\pushNotify\index.js
// 替换为你的模板id!
templateId: '****************************', // 请填写订阅事件模板ID
cloudfunctions\sendEmail\index.js
user: '这里填写你的邮箱',// 邮箱账户 这里填写你的邮箱
pass: '这里填写你的邮箱授权码' // 邮箱授权码 这里填写你的邮箱授权码
// 收件人
to: '******@***.***', // 请填写收件人邮箱
2、其余文件均初始化后不用修改
5、项目发布
微信小程序开发工具
上传-> 确认 -> 填写: 版本号、项目备注 -> 上传
上传后显示上传成功
微信小程序管理网页
版本管理(鼠标向下滑动)->开发版本->提交审核->阅读协议->下一步->继续提交->提交审核
审核通过后,提交发布