0%

小程序开发-几句话推荐

小程序开发-几句话推荐

项目设计

项目来源

展哥更新了-字醒app
几行字

技术选型

uniapp + 微信云开发, uniapp 只开发微信端, 微信云开发省去搭建后端项目的繁琐。

数据库设计

按照非关系型数据库设计,可以参考
Mongodb 数据库表格设计原则
数据库ER图基础概念整理
表设计

云数据库跟 mongodb很相似,云函数只有两个集合, item 和 user

item 集合
"publish": "-1/1", // 发布状态

1
2
3
4
5
6
7
8
9
10
{
"_id": "",
"author":"",
"content": "",
"createTime": "",
"updateTime": "",
"publish": "-1/1",

}

user集合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"_id": "",
"collects": [
{ "item._id": "author": "", "content": "" },
{}
],
"likes": [
{ "item._id": "author": "", "content": "" },
{}
],
"openid": "",
"firstlogin": ""
}

难点

uniapp

uniapp 的熟悉度

uniapp 和 Vue 的 熟悉程度还是不够,磕磕碰碰的,尤其是对接 微信云开发这段,而且官方文档也有省略。

uniapp 插件使用

使用到一个uniapp的插件mescroll
看了好久,不是很明白,上手了发现它封装的很好,我使用了它给的一个例子就写完了。

Vue

Vue 中写节流函数

这里提供一个Vue 中写节流函数的写法

1
2
3
4
5
6
7
import { throttle } from '@/utils/utils.js'	

export default{
methods:{
handleClickLove: throttle(function(){}, 1000)
}
}

云开发

对接云函数

参考1
官方文档

在 user.likes 数组中 删除对应的 id

请注意这个方法在微信云数据库的控制台测试的时候是报异常的,只能在云函数中使用
Command.pull

1
2
3
4
5
6
7
8
9
10
11
12
13
const db = cloud.database()
const _ = db.command
// 中间省略
// 下面是查询语句
await db.collection('user')
.where({ openid })
.update({
data: {
likes: _.pull({
"_id": _.eq(recommend._id)
})
}
})

随机集合中的几个数据

因为 mongodb 和 云数据库都是 nosql 类型的数据库, 所以概念上类似
当你想遇到不会的 sql 语法,查一下 mongodb 是如何实现的,然后再找找看微信的文档

MongoDB 聚合
mongodb-random-query
Collection.aggregate

1
2
3
4
5
6
7
8
const db = cloud.database()
const _ = db.command
// 中间省略
// 下面是查询语句
await db.collection('item')
.aggregate()
.sample({ size:1 })
.end()

后台管理系统请求

每隔2小时获取新微信请求 token

微信文档-获取接口调用凭据,
需要APPID和APPSECRET

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
const axios = require("axios");
const { APPID, APPSECRET } = require("../config");
const logger = require("./log4j");
const fs = require("fs");
const path = require("path");
const URL = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${APPID}&secret=${APPSECRET}`;
const fName = path.resolve(__dirname, "./accessToken.json");

// 请求并更新 accessToken
const updateAccessToken = async () => {
return axios
.get(URL)
.then(({ data }) => {
const { access_token } = data;
if (access_token) {
fs.writeFileSync(
fName,
JSON.stringify({
access_token,
createTime: new Date(),
})
);
} else {
throw new Error("access token 请求不成功");
}
})
.catch(async (err) => {
logger.error(err);
await updateAccessToken();
});
};

// 从文件中读 accessToken
const getAccessToken = async () => {
try {
// const readRes = fs.readFileSync(fName, "utf-8");
const readObj = JSON.parse(fs.readFileSync(fName, "utf-8"));
const createTime = new Date(readObj.createTime).getTime();
const nowTime = new Date().getTime();
// accessToken 过期
if ((nowTime - createTime) / (3600 * 1000) >= 2) {
await updateAccessToken();
await getAccessToken();
}
return readObj.access_token;
} catch (error) {
logger.error(error);

await updateAccessToken();
await getAccessToken();
}
};
// 定时任务更新 accessToken
setInterval(async () => {
await updateAccessToken();
}, 7200 * 1000);

module.exports = getAccessToken;


通过HTTP API 访问 云数据库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
// axios 实例
const instance = axios.create({
baseURL: "https://api.weixin.qq.com/tcb",
timeout: 5000,
});
instance.interceptors.response.use(async (res) => {
let { errcode } = res.data;
// 请求成功返回的数据 { errcode:0, data:{}}
if (errcode === 0) {
return res.data;
} else {
return Promise.reject(res.data);
}
});
// 云开发的环境id
const env = "";

// 以下是获取 http api 例子
// 通过查询拿到全部数据

// 微信文档,https://developers.weixin.qq.com/minigame/dev/wxcloud/reference-http-api/database/databaseQuery.html
router.get("/getAll", async function (ctx, next) {
try {

const { page, skipIndex } = pager(ctx.request.query);
const { flag, author, content, publish } = ctx.request.query;
// POST https://api.weixin.qq.com/tcb/databasequery?access_token=ACCESS_TOKEN
// 需要拿到 三个参数,accessToken,env,query ( 数据查询语句 )
// 1. 拿到 accessToken
let accessToken = await getAccessToken();
// https://api.weixin.qq.com/tcb/ + url(databasequery)
const url = "databasequery";
// 3. 拼接 query 语句,我并没有选择模板字符串, 而是选择了字符串拼接
let query = "";
if (author) query += '"author": "' + author + '"';
if (content)
query +=
',"content": db.RegExp({ "regexp": "' + content + '" ,options: "i" }) ';
if (publish !== 0) query += ',"publish": ' + publish;
// 我这里需要两种根据条件选择两种语句
const querySql = `db.collection('item').limit(${page.pageSize}).skip(${skipIndex}).get()`;
const querySqlWithParm = `db.collection('item').where({${query}}).limit(${page.pageSize}).skip(${skipIndex}).get()`;
const sql = flag ? querySqlWithParm : querySql;

let res = await instance.post(
url,
{
env,
query: sql,
},
{
params: {
access_token: accessToken,
},
}
);
// result.data 是 字符串,需要转成对象
const result = {
data: res.data.map((e) => {
e = JSON.parse(e);
e.createTime = new Date(e.createTime.$date);
e.updateTime = new Date(e.updateTime.$date);
return e;
}),
pager: { total: res.pager.Total },
};
ctx.body = succResp(result);
} catch (error) {
error(error);
ctx.body = failRespMsg(CODE.QUOTE_GETALL, CODE.QUOTE_GETALL_M);
}
});

小程序功能预览以及二维码

功能预览



小程序二维码