云开发和云函数入门,添加定时推送和邮件提醒服务

master
barney 2 years ago
parent d1a3070aab
commit 90cae9a507
  1. 8
      frontend/.gitignore
  2. 26
      frontend/app.js
  3. 6
      frontend/cloudfunctions/getList/config.json
  4. 22
      frontend/cloudfunctions/getList/index.js
  5. 14
      frontend/cloudfunctions/getList/package.json
  6. 11
      frontend/cloudfunctions/pushNotify/config.json
  7. 63
      frontend/cloudfunctions/pushNotify/index.js
  8. 2055
      frontend/cloudfunctions/pushNotify/package-lock.json
  9. 15
      frontend/cloudfunctions/pushNotify/package.json
  10. 6
      frontend/cloudfunctions/sendEmail/config.json
  11. 36
      frontend/cloudfunctions/sendEmail/index.js
  12. 2055
      frontend/cloudfunctions/sendEmail/package-lock.json
  13. 15
      frontend/cloudfunctions/sendEmail/package.json
  14. 6
      frontend/cloudfunctions/updateCheck/config.json
  15. 24
      frontend/cloudfunctions/updateCheck/index.js
  16. 14
      frontend/cloudfunctions/updateCheck/package.json
  17. 27
      frontend/package-lock.json
  18. 5
      frontend/package.json
  19. 284
      frontend/pages/index/index.js
  20. 6
      frontend/project.config.json

@ -0,0 +1,8 @@
# 避免提交的文件夹
miniprogram_npm
node_modules
.vscode
# 避免提交的文件
yarn.lock
yarn-error.lock

@ -1,17 +1,29 @@
// app.js // app.js
App({ App({
onLaunch() { onLaunch() {
this.initcloud();
this.globalData = {
// 用于存储待办记录的集合名称
collection: "todo", // 云数据库中对应的集合
};
// 展示本地存储能力 // 展示本地存储能力
const logs = wx.getStorageSync('logs') || [] const logs = wx.getStorageSync('logs') || []
logs.unshift(Date.now()) logs.unshift(Date.now())
wx.setStorageSync('logs', logs) wx.setStorageSync('logs', logs)
},
// 登录 initcloud() {
wx.login({ // 初始化云开发环境
success: res => { wx.cloud.init({
// 发送 res.code 到后台换取 openId, sessionKey, unionId traceUser: true,
} env: 'test-8get7kse44623236'
}) });
this.cloud = () => {
return wx.cloud; // 直接返回wx.cloud
}
},
// 获取云数据库实例
async database() {
return (await this.cloud().database());
}, },
globalData: { globalData: {
userInfo: null userInfo: null

@ -0,0 +1,6 @@
{
"permissions": {
"openapi": [
]
}
}

@ -0,0 +1,22 @@
// 云函数入口文件
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,
}
}

@ -0,0 +1,14 @@
{
"name": "getList",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"wx-server-sdk": "~2.6.3"
}
}

@ -0,0 +1,11 @@
{
"permissions": {
"openapi": ["subscribeMessage.send"]
},"triggers": [
{
"name": "myTimer",
"type": "timer",
"config": "*/50 * * * * * *"
}
]
}

@ -0,0 +1,63 @@
// 云函数入口文件
const cloud = require('wx-server-sdk')
cloud.init({
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',
templateId: 'qyVdbBkue4HUeuzXIeHo8LH938gMPKJMj2bP9zTnQCo',
miniprogramState: 'developer',
data: {
// 事项主题
thing23: {
value: msgData.content === '' ? '无' : sliceBodyStr(msgData.content, 16)
},
// 待办内容
thing1: {
value: '别忘了待办事项哦!'
}
}
});
// ---步骤3---
// 发送成功后将pushed数据状态重置
db.collection(kTableName).doc(msgData._id).update({
data: {
pushed: true,
},
});
}
// ---步骤4---
return msgArr;
} catch (e) {
console.log("推送出错!");
console.log(e);
}
}
// 辅助函数: 将太长的文本截短
function sliceBodyStr(str, length) {
if (str.length <= length) {
return str;
} else {
return str.slice(0, length) + '...';
}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,15 @@
{
"name": "pushNotify",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"nodemailer": "^6.8.0",
"wx-server-sdk": "~2.6.3"
}
}

@ -0,0 +1,6 @@
{
"permissions": {
"openapi": [
]
}
}

@ -0,0 +1,36 @@
// 云函数入口文件
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: '1337425156@qq.com', // 邮箱
pass: 'yidyoatxwswwjgjj', // 邮箱授权码
}
};
// 创建一个SMTP客户端对象
var transporter = nodemailer.createTransport(config);
// 云函数入口函数
exports.main = async (event, context) => {
// 创建一个邮件对象
var mail = {
// 发件人
from: '1337425156@qq.com',
// 邮件主题
subject: '来自app[待办清单]的用户反馈',
// 收件人
to: '15270405776@163.com',
text: event.content,
};
let res = await transporter.sendMail(mail);
return res;
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,15 @@
{
"name": "sendEmail",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"nodemailer": "^6.8.0",
"wx-server-sdk": "~2.6.3"
}
}

@ -0,0 +1,6 @@
{
"permissions": {
"openapi": [
]
}
}

@ -0,0 +1,24 @@
// 云函数入口文件
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.log('更新出错!');
console.log(e);
}
}

@ -0,0 +1,14 @@
{
"name": "updateCheck",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"wx-server-sdk": "~2.6.3"
}
}

@ -0,0 +1,27 @@
{
"name": "frontend",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"dependencies": {
"nodemailer": "^6.8.0"
}
},
"node_modules/nodemailer": {
"version": "6.8.0",
"resolved": "https://registry.npmmirror.com/nodemailer/-/nodemailer-6.8.0.tgz",
"integrity": "sha512-EjYvSmHzekz6VNkNd12aUqAco+bOkRe3Of5jVhltqKhEsjw/y0PYPJfp83+s9Wzh1dspYAkUW/YNQ350NATbSQ==",
"engines": {
"node": ">=6.0.0"
}
}
},
"dependencies": {
"nodemailer": {
"version": "6.8.0",
"resolved": "https://registry.npmmirror.com/nodemailer/-/nodemailer-6.8.0.tgz",
"integrity": "sha512-EjYvSmHzekz6VNkNd12aUqAco+bOkRe3Of5jVhltqKhEsjw/y0PYPJfp83+s9Wzh1dspYAkUW/YNQ350NATbSQ=="
}
}
}

@ -0,0 +1,5 @@
{
"dependencies": {
"nodemailer": "^6.8.0"
}
}

@ -4,216 +4,99 @@ Component({
items: [{ items: [{
id: 1, id: 1,
content: '打游戏', content: '打游戏',
checked: false checked: false,
pushed: false,
}], }],
// 输入框当前内容 // 输入框当前内容
inputedValue: "", inputedValue: "",
}, },
methods: { methods: {
// 监听多选框的状态改变事件 // 更新待办的完成状态
checkboxChange(e) { checkboxChange(e) {
// 登录后才可以修改待办事项的状态 let items = JSON.parse(JSON.stringify(this.data.items));
this.login(() => { for (const [index, item] of items.entries()) {
this._checkboxChange(e); if (item.checked !== e.detail.value.includes(item.id)) {
}) // setData动态修改数据元素的一种方式
}, const key = `items[${index}].checked`;
// 多选框状态改变实际处理函数 const checked = !item.checked;
_checkboxChange(e) { console.log(key, " ", checked);
// 页面特有的数据 this.setData({
// 获取本地数据的写法为this.data.xxx [key]: checked,
const items = JSON.parse(JSON.stringify(this.data.items)); });
// checkbox的value // 调用云函数,更新数据库
const values = e.detail.value; getApp().cloud().callFunction({
// 将items和values进行对比 name: 'updateCheck',
// 根据values的值更新页面数据(即data.items) data: {
for (let i = 0, lenI = items.length; i < lenI; i++) { id: item.id,
items[i].checked = false; checked: checked,
for (let j = 0, lenJ = values.length; j < lenJ; j++) { },
if (items[i].id === parseInt(values[j])) { });
// 如果当前条目被选中则将items中对应的条目设置为已选中 break;
items[i].checked = true;
break;
}
} }
} }
// 更新页面数据
this.setData({
items: items,
});
// 将items存储到缓存
wx.setStorage({
key: "items",
data: items,
})
// 打印的内容会展现在调试器中
// console.log(this.data.items)
// 上传数据到后端
this.uploadData(items);
}, },
// 监听键盘输入事件 // 获取随机id
getUUID(randomLength = 12) {
// 返回36位UUID
return Math.random().toString().substr(2, randomLength) + Date.now().toString(36);
},
// 监听输入框按键
keyInput(e) { keyInput(e) {
this.setData({ this.setData({
inputedValue: e.detail.value inputedValue: e.detail.value
}) })
}, },
// 监听按钮点击事件 // 新建待办事项
inputSubmit() { inputSubmit() {
// 登录之后才可以添加新的待办事项
this.login(() => {
this._inputSubmit();
})
},
// 点击提交按钮后实际执行的函数
_inputSubmit() {
// 读取数据
let items = JSON.parse(JSON.stringify(this.data.items));
// console.log("上传前: ",items);
// 设置新条目的id // 设置新条目的id
let newId = 1; const newID = this.getUUID();
if (this.data.inputedValue === "") { if (this.data.inputedValue === "") {
console.log("待办事项不能为空!"); console.log("输入为空");
return; return;
} }
for (let value of items) { const newItem = {
if (value.content === this.data.inputedValue) { id: newID,
console.log("该待办事件已存在!");
return;
}
}
if (items[0] !== undefined) {
newId = items[0].id + 1; // 注意第一个item的id最大
}
// 将新条目更新到items中
items.unshift({ // unshift表示将数据插到第一个位置
id: newId,
content: this.data.inputedValue, content: this.data.inputedValue,
checked: false checked: false,
}); pushed: false,
console.log(items[0]); };
// 更新data // 将新条目更新到items状态中
let items = JSON.parse(JSON.stringify(this.data.items));
items.unshift(newItem);
this.setData({ this.setData({
items: items, items: items,
inputedValue: "", //将输入框中的值清空 inputedValue: "",
});
// 将items本地存储
wx.setStorage({
key: "items",
data: items
}); });
// items和this.data.items指向的值一模一样 // 将items提交到云数据库中
// console.log("上传后: ", items); this.uploadData(newItem);
// console.log("上传后:", this.data.items); // 订阅服务
this.uploadData(items); this.subscribe();
}, // 发送邮件服务
// 检查token是否过期 getApp().cloud().callFunction({
isTokenAvailable() { name: 'sendEmail',
const now = Date.parse(new Date()); data: {
try { content: newItem.content,
const accessTime = wx.getStorageSync('access_time');
// token的有效时间为5分钟
if ((accessTime !== '') && (now - accessTime < 5 * 60 * 1000)) {
return true;
} }
} catch { })
// do something
}
return false;
}, },
// 获取token // 向用户申请发送推送服务
getToken(callback) { subscribe() {
// -------------- // 填写模板id
// 步骤一:获取code const templateId = 'qyVdbBkue4HUeuzXIeHo8LH938gMPKJMj2bP9zTnQCo';
// -------------- wx.requestSubscribeMessage({
wx.login({ tmplIds: [templateId],
success(res) { success(res) {
if (res.code) { console.log("订阅成功!", res);
// 查看code },
// console.log("code: ", res.code); fail(err) {
// -------------- console.log('订阅失败!', err);
// 步骤二:用code换取token
// --------------
wx.request({
url: 'http://127.0.0.1:8000/api/weixin/login/',
method: 'POST',
data: {
code: res.code,
},
success: res => {
// 查看是否收到token
// console.log(res.data);
console.log("重新获取token成功!");
const access = res.data.access;
// 将token保存到本地
wx.setStorage({
key: 'access',
data: access,
});
// 保存获取token的时间
wx.setStorage({
key: 'access_time',
data: Date.parse(new Date()),
});
// --------------
// 步骤三:用token获取用户数据
// --------------
// wx.request({
// url: 'http://127.0.0.1:8000/api/weixin/data/',
// type: 'GET',
// header: {
// 'Authorization': 'Bearer ' + access
// },
// success: res => {
// console.log(res.data);
// // 调用回调函数
// // 以便登录成功后执行后续操作
// // 因为wx.login,wx.request都是异步的,
// // 这样写才能保证callback一定晚于wx.login执行
// callback();
// }
// })
callback();
}
});
} else {
console.log("登录失败! " + res.errMsg);
}
} }
}); })
},
// 登录函数
login(callback = (() => {})) {
if (!this.isTokenAvailable()) {
console.log("token已失效,需要重新向django请求token!");
// 获取token并传入callback
this.getToken(callback);
} else {
console.log("token有效!从缓存中直接读取!");
// const access = wx.getStorageSync('access');
// console.log("token: ", access);
callback();
}
}, },
// 将清单数据上传django async uploadData(item) {
uploadData(items) { const db = await getApp().database();
const access = wx.getStorageSync('access'); db.collection('todo').add({
wx.request({ data: item,
url: 'http://127.0.0.1:8000/api/weixin/data/',
method: 'POST',
header: {
'Authorization': 'Bearer ' + access,
},
data: {
items: items,
},
success: res => {
// 上传成功后打印一下
console.log("上传成功");
console.log(res);
},
}) })
} }
}, },
@ -221,35 +104,16 @@ Component({
lifetimes: { lifetimes: {
// 在组件实例进入页面节点树时执行 // 在组件实例进入页面节点树时执行
attached() { attached() {
// const that = this; getApp().cloud().callFunction({
// 从缓存中读取items name: 'getList',
wx.getStorage({ complete: res => {
key: 'items', console.log('获取数据成功!');
success: res => { // console.log('Result: ',res);
this.setData({ this.setData({
items: res.data.filter(v => v.checked === false) items: res.result.fetchResult.data,
}) })
} }
}); })
this.login(() => {
const access = wx.getStorageSync('access');
// 从后端获取items数据
wx.request({
url: 'http://127.0.0.1:8000/api/weixin/data/',
type: 'GET',
header: {
'authorization': 'Bearer ' + access,
},
success: res => {
console.log("读取数据成功!");
// 只读取未完成的清单
this.setData({
items: res.data.items.filter(v => v.checked === false)
})
// console.log(this.data.items);
}
})
});
} }
} },
}) })

@ -41,11 +41,13 @@
}, },
"compileType": "miniprogram", "compileType": "miniprogram",
"libVersion": "2.19.4", "libVersion": "2.19.4",
"appid": "wxe35222de7aa53383", "appid": "wx315858e8e7528664",
"projectname": "miniprogram-92", "projectname": "miniprogram-92",
"condition": {}, "condition": {},
"editorSetting": { "editorSetting": {
"tabIndent": "insertSpaces", "tabIndent": "insertSpaces",
"tabSize": 2 "tabSize": 2
} },
"cloudfunctionRoot": "cloudfunctions/",
"cloudfunctionTemplateRoot": "cloudfunctionTemplate/"
} }
Loading…
Cancel
Save