Because recently want to practice the cloud development ability of small procedures, so the design and development of a simple voting application, welcome interested in learning and communication.
Code repository github.com/luosijie/mi…
Since the mini app [individual developers] does not open the [voting] category, it cannot be previewed online, SO I put some screenshots of the app
Database design
There are three sets used
1. Users
Basically save the user’s userInfo data directly
{
"_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/Q0j4TwGTfTL9lhZHZdYsMx3mjhZZYbbE5OZhUqUefNtsibkhdrSTIdpdhzv34lYHXtafMjuoibJ8JwTj5 VM76CkA/132"
}
Copy the code
Votes (votes)
{
"_id":"21ded5cb5ff5f0530407988a4e8f18a5"./ / the only id
"creator":"o-ZK45EoiyFzvevQyQTSZUV7R64I"./ / the originator
"title":"As da at Aston"./ / title
"desc":"Aston, Aston."./ / description
"startTime":"2021-1-7".// Start date
"endTime":"2021-1-8".// End date
"state":"ing" / / state
}
Copy the code
3. Options
{
"_id":"be7fb3985ff5f05403068303431d580b"./ / the only id
"vote_id":"21ded5cb5ff5f0530407988a4e8f18a5".// The poll id corresponding to the option
"title":"Aston big big big."./ / title
"desc":"Sprinkle it all over the ground, Aston."./ / description
"image":"http://tmp/2jVXjjLScAyNf0dffe2c5fc6479bee73fe954b64a3e7.png"./ / pictures
"users": ["o-ZK45EoiyFzvevQyQTSZUV7R64I"] // The voter for this option
}
Copy the code
Cloud function development
There are six cloud functions written
1. AddRecord Adds a voting record
/** * Add voting record *@param {String} The title title *@param {String} Desc description *@param {String} StartTime Start date *@param {String} EndTime End date *@param {String} Anonymous anonymous *@param {String} Min Allows a small number of votes *@param {String} Max Maximum number of votes allowed *@param {String} Type Voting type: normal. pk *@returns {Object} Contains the vote _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, / / the originator
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'
}
// Aggregate votes: adds a record
const res = await voteCollection.add({
data
})
// Set options: add records
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)
// Returns the result of the vote
return {
success: true.message: 'New vote successfully added'. res } }Copy the code
2. GetRecordDetail Obtains the voting details
/** * to obtain details of the vote *@param {String} _id Indicates the voting id *@return {Object} Voting data */
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
// Find the polling data in the collection
const voteCollection = db.collection('votes')
// aggregate header query
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]
// Determine whether the current vote is initiated
vote.isOwner = vote.creator.OPENID === OPENID
// Find the option data in the collection
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
// Count the number of people who have voted
let votedTotal = 0
vote.options.forEach(e= > {
if (e.users && e.users.length) {
votedTotal += e.users.length
}
})
vote.votedTotal = votedTotal
// Calculates the status of the current vote
if(vote.state ! = ='end') {
/ / not start
if (new Date().getTime() < new Date(vote.startTime).getTime()) {
vote.state = 'pre'
}
// Expired = End
if (new Date().getTime() > new Date(vote.endTime).getTime()) {
vote.state = 'end'}}return {
success: true.data: vote
}
} else {
return {
success: false.message: 'Unable to find voting information'}}}Copy the code
3. Vote The vote operation
/** * vote operation *@param {String} VoteId Indicates the id of a vote@param {String} OptionId Option _id *@return {Object} Voting result */
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
// Get all option data corresponding to the current vote data
const options = db.collection('options')
let voteOptions = await options.where({ vote_id }).get()
voteOptions = voteOptions.data
// Determine whether the user has voted
let curOptionUsers = []
for (let i = 0; i < voteOptions.length; i++) {
// Find all users who voted in the option
const users = voteOptions[i].users
if (users && users.length) {
if (voteOptions[i]._id === _id) {
curOptionUsers = users
}
if (users && users.length) {
// OPENID repeated - indicates that a vote has been cast -> returns directly
if (users.indexOf(OPENID) > -1) {
return {
success: false.message: 'You have already voted.'
}
}
}
}
}
// No vote -> Insert the current user OPENID into the corresponding field
curOptionUsers.push(OPENID)
const res = await options.where({ _id }).update({
data: {
users: curOptionUsers
}
})
return {
success: true.data: res,
message: 'Successful vote'}}Copy the code
4. GetRecordPage Gets my voting record page
/** * Get my voting record page *@param {Number} No page number *@param {Number} The size of pages *@return {Object} List of voting data and totals */
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
// Get interface parameters
const no = event.no
const OPENID = wxContext.OPENID
const voteCollection = db.collection('votes')
// Find the polling data in the collection
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()
// Count the total
const total = await voteCollection.count()
let data = votes.list
// Calculate the voting status
if (data.length) {
data = data.map(e= > {
if(e.state ! = ='end') {
/ / not start
if (new Date().getTime() < new Date(e.startTime).getTime()) {
e.state = 'pre'
}
// Expired = End
if (new Date().getTime() > new Date(e.endTime).getTime()) {
e.state = 'end'}}// Count the number of votes cast
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
}
}
Copy the code
5. Login
/** * register *@param {String} OPENID gets * from cloud.getwxContext ()@return {Object} Use book data */
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()
// Find user data in the collection
const userCollection = db.collection('users')
const users = await userCollection.where({ OPENID: wxContext.OPENID }).get()
let user
if (users && users.data.length) {
// User already exists - assign user data directly
user = users.data[0]}else {
// New user - Inserts user data into the database
user = {
OPENID: wxContext.OPENID, ... event.userInfo }await userCollection.add({
data: user
})
}
// Returns user data - the front-end is used for caching
return {
...user
}
}
Copy the code
6. CheckImage Verifies the image validity
/** * verify the validity of the image *@param {*} Event. fileID Image ID * of wechat cloud storage@return {Number} 0: the verification fails. 1: the verification passes */
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 {
// Download the image according to fileID
const file = await cloud.downloadFile({
fileID
})
const value = file.fileContent
ImgSecCheck is invoked. If the check fails, an error will be thrown
Media {contentType, value}
const result = await cloud.openapi.security.imgSecCheck({
media: {
contentType,
value
}
})
return 1
} catch (err) {
return 0}}Copy the code
The front-end development
The development of the small program uses the MPX framework produced by Didi’s front end team
I’m not going to post any code here because the UI is a little bit simpler
If you are interested, go to github.com/luosijie/mi… To understand