【小程序】小程序云开发实现一个投票应用

代码仓库 https://github.com/luosijie/m...

由于小程序【个人开发者】不开放【投票】类目,所以就不能在线预览了,我放几张应用的截图

【小程序】小程序云开发实现一个投票应用

数据库设计

总共用到了3个集合

1. users (用户集合)

基本上直接保存用用户的userInfo数据

{

"_id":"023ce9555ff068de0314b5521c313ee6",

"OPENID":"oZK45EoiyFzv...7R64I",

"nickName":"LSJ",

"gender":1,

"language":"zh_CN",

"city":"Xiamen",

"province":

"Fujian",

"country":"China",

"avatarUrl":"https://thirdwx.qlogo.cn/mmopen/vi_32/Q0j4TwGTfTL9lhZHZdYsMx3mjhZZYbbE5OZhUqUefNtsibkhdrSTIdpdhzv34lYHXtafMjuoibJ8JwTj5VM76CkA/132"

}

2. votes (投票集合)

{

"_id":"21ded5cb5ff5f0530407988a4e8f18a5", // 唯一id

"creator":"o-ZK45EoiyFzvevQyQTSZUV7R64I", // 发起人

"title":"阿斯顿大的as da", // 标题

"desc":"阿斯顿阿斯顿", // 描述

"startTime":"2021-1-7", // 开始日期

"endTime":"2021-1-8", // 结束日期

"state":"ing" // 状态

}

3. options (选项集合)

{

"_id":"be7fb3985ff5f05403068303431d580b", // 唯一id

"vote_id":"21ded5cb5ff5f0530407988a4e8f18a5", // 选项对应的投票_id

"title":"阿斯顿大的大的", // 标题

"desc":"撒打算的洒大地上阿斯顿", // 描述

"image":"http://tmp/2jVXjjLScAyNf0dffe2c5fc6479bee73fe954b64a3e7.png", // 配图

"users":["o-ZK45EoiyFzvevQyQTSZUV7R64I"] // 该选项的投票者

}

云函数开发

总共写了6个云函数

1. addRecord 新增投票记录

/**

* 新增投票记录

* @param {String} title 标题

* @param {String} desc 描述

* @param {String} startTime 开始日期

* @param {String} endTime 结束日期

* @param {String} anonymous 匿名

* @param {String} min 允许小投票数

* @param {String} max 允许最大投票数

* @param {String} type 投票类型:normal; pk

* @returns {Object} 包含投票_id

*/

const cloud = require('wx-server-sdk')

cloud.init({

env: cloud.DYNAMIC_CURRENT_ENV

})

const db = cloud.database()

exports.main = async (event, context) => {

const wxContext = cloud.getWXContext()

const voteCollection = db.collection('votes')

const data = {

creator: wxContext.OPENID, // 发起人

title: event.title,

desc: event.desc,

startTime: event.startTime,

endTime: event.endTime,

anonymous: event.anonymous,

min: event.min,

max: event.max,

type: event.type,

state: 'ing'

}

// 集合投票votes:新增记录

const res = await voteCollection.add({

data

})

// 集合选项options: 新增记录

const options = event.options

const optionCollection = db.collection('options')

const optionPromise = options.map( ele => {

const option = {

vote_id: res._id,

...ele

}

return optionCollection.add({

data: option

})

})

let resOptions = await Promise.all(optionPromise)

resOptions = resOptions.map(e => e._id)

// 返回投票结果

return {

success: true,

message: '新增投票成功',

...res

}

}

2.getRecordDetail 获取投票详情

/**

* 获取投票详情

* @param {String} _id 投票_id

* @return {Object} 投票数据

*/

const cloud = require('wx-server-sdk')

cloud.init({

env: cloud.DYNAMIC_CURRENT_ENV

})

const db = cloud.database()

exports.main = async (event, context) => {

const _id = event._id

const OPENID = cloud.getWXContext().OPENID

// 查找集合中的投票数据

const voteCollection = db.collection('votes')

// 聚合联表查询

const voteQuery = await voteCollection

.aggregate()

.match({ _id })

.lookup({

from: 'users',

localField: 'creator',

foreignField: 'OPENID',

as: 'creator'

})

.end()

let vote = {}

if (voteQuery && voteQuery.list.length) {

vote = voteQuery.list[0]

vote.creator = vote.creator[0]

// 判断是否当前投票的发起人

vote.isOwner = vote.creator.OPENID === OPENID

// 查找集合中的选项数据

const optionsCollection = db.collection('options')

const optionsQuary = await optionsCollection

.aggregate()

.match({ vote_id: _id })

.lookup({

from: 'users',

localField: 'users',

foreignField: 'OPENID',

as: 'users'

})

.end()

vote.options = optionsQuary.list

// 统计已经投票的人数

let votedTotal = 0

vote.options.forEach(e => {

if (e.users && e.users.length) {

votedTotal += e.users.length

}

})

vote.votedTotal = votedTotal

// 计算当前投票的状态

if (vote.state !== 'end') {

// 未开始

if (new Date().getTime() < new Date(vote.startTime).getTime()) {

vote.state = 'pre'

}

// 已过期 = 已结束

if (new Date().getTime() > new Date(vote.endTime).getTime()) {

vote.state = 'end'

}

}

return {

success: true,

data: vote

}

} else {

return {

success: false,

message: '找不到投票信息'

}

}

}

3. vote 投票操作

/**

* 投票操作

* @param {String} voteId 投票_id

* @param {String} optionId 选项_id

* @return {Object} 投票结果

*/

const cloud = require('wx-server-sdk')

cloud.init({

env: cloud.DYNAMIC_CURRENT_ENV

})

const db = cloud.database()

exports.main = async (event, context) => {

const _id = event.optionId

const vote_id = event.voteId

const OPENID = cloud.getWXContext().OPENID

// 获取当前投票数据对应的所有选项数据

const options = db.collection('options')

let voteOptions = await options.where({ vote_id }).get()

voteOptions = voteOptions.data

// 判断用户是否投过票

let curOptionUsers = []

for (let i = 0; i < voteOptions.length; i++) {

// 找到选项中所有投过票的用户

const users = voteOptions[i].users

if (users && users.length) {

if (voteOptions[i]._id === _id) {

curOptionUsers = users

}

if (users && users.length) {

// OPENID重复-说明已经投过票->直接返回

if (users.indexOf(OPENID) > -1) {

return {

success: false,

message: '您已经投过票了'

}

}

}

}

}

// 没有投票->将当前用户OPENID插入到对应的字段

curOptionUsers.push(OPENID)

const res = await options.where({ _id }).update({

data: {

users: curOptionUsers

}

})

return {

success: true,

data: res,

message: '投票成功'

}

}

4. getRecordPage 获取我的投票记录分页

/**

* 获取我的投票记录分页

* @param {Number} no 页码

* @param {Number} size 页数

* @return {Object} 投票数据列表和总数

*/

const cloud = require('wx-server-sdk')

cloud.init({

env: cloud.DYNAMIC_CURRENT_ENV

})

const db = cloud.database()

exports.main = async (event, context) => {

const wxContext = cloud.getWXContext()

const size = event.size

//获取接口参数

const no = event.no

const OPENID = wxContext.OPENID

const voteCollection = db.collection('votes')

// 查找集合中的投票数据

const votes = await voteCollection.aggregate()

.match({

creator: OPENID

})

.lookup({

from: 'options',

localField: '_id',

foreignField: 'vote_id',

as: 'options'

})

.sort({

_id: -1

})

.skip((no - 1) * size)

.limit(size)

.end()

// 计算总数

const total = await voteCollection.count()

let data = votes.list

// 计算投票状态

if (data.length) {

data = data.map(e => {

if (e.state !== 'end') {

// 未开始

if (new Date().getTime() < new Date(e.startTime).getTime()) {

e.state = 'pre'

}

// 已过期 = 已结束

if (new Date().getTime() > new Date(e.endTime).getTime()) {

e.state = 'end'

}

}

// 统计已投票人数

let votedTotal = 0

const options = e.options

options.forEach(o => {

if (o.users && o.users.length) {

votedTotal += o.users.length

}

})

delete e.options

return {

...e,

votedTotal

}

})

}

return {

total,

data

}

}

5. login 登录注册

/**

* 登录注册

* @param {String} OPENID 从cloud.getWXContext()中获取

* @return {Object} 用书数据

*/

const cloud = require('wx-server-sdk')

cloud.init({

env: cloud.DYNAMIC_CURRENT_ENV

})

const db = cloud.database()

exports.main = async (event, context) => {

const wxContext = cloud.getWXContext()

// 查找集合中的用户数据

const userCollection = db.collection('users')

const users = await userCollection.where({ OPENID: wxContext.OPENID }).get()

let user

if (users && users.data.length) {

// 用户已经存在-直接赋值用户数据

user = users.data[0]

} else {

// 新用户-向数据库插入用户数据

user = {

OPENID: wxContext.OPENID,

...event.userInfo

}

await userCollection.add({

data: user

})

}

// 返回用户数据-前端用来缓存

return {

...user

}

}

6. checkImage 校验图片合法性

/**

* 校验图片合法性

* @param {*} event.fileID 微信云存储的图片ID

* @return {Number} 0:校验失败;1:校验通过

*/

const cloud = require('wx-server-sdk')

cloud.init({

env: cloud.DYNAMIC_CURRENT_ENV

})

exports.main = async (event, context) => {

const contentType = 'image/png'

const fileID = event.fileID

try {

// 根据fileID下载图片

const file = await cloud.downloadFile({

fileID

})

const value = file.fileContent

// 调用 imgSecCheck 借口,校验不通过接口会抛错

// 必要参数 media { contentType, value }

const result = await cloud.openapi.security.imgSecCheck({

media: {

contentType,

value

}

})

return 1

} catch (err) {

return 0

}

}

前端开发

这次小程序端的开发

采用的是 滴滴前端团队出品的 mpx 框架

因为UI比较简单

这里就不贴代码了

感兴趣的欢迎前往 https://github.com/luosijie/m... 了解

谢谢阅读!

以上是 【小程序】小程序云开发实现一个投票应用 的全部内容, 来源链接: utcz.com/a/102105.html

回到顶部