前言
初學(xué)小程序,每天起床第一件事不是去看文檔,而是打開(kāi)班群接龍打卡信息,填寫(xiě)ex表(苦逼的大二狗每天群通知99+),所以萌生了寫(xiě)一款讓學(xué)生報(bào)備信息的小程序。本來(lái)只是簡(jiǎn)單寫(xiě)了一個(gè)上報(bào)表單的程序,但是寫(xiě)完了之后又覺(jué)得好像缺了點(diǎn)什么,所以功能越寫(xiě)越多,項(xiàng)目不斷重構(gòu),里面很多東西都是現(xiàn)學(xué)現(xiàn)用,陸陸續(xù)續(xù)寫(xiě)了10天左右,算是一滴都不剩了。。不對(duì),是差不多寫(xiě)得沒(méi)想法了,項(xiàng)目包含了一整套前后端的交互,由于很多數(shù)據(jù)前期和后期設(shè)計(jì)理念不一樣,簡(jiǎn)稱自己打自己臉,所以會(huì)有很多不完善的地方,希望大家輕噴。。。 (* ゜ェ゜ *) 廢話不多說(shuō),現(xiàn)在主要講一下該項(xiàng)目的設(shè)計(jì)思路和一些功能的實(shí)現(xiàn)思路。
技術(shù)棧
- 微信小程序
- 云開(kāi)發(fā)
- vant
- colorui
- echarts微信小程序版本
功能設(shè)計(jì)
首頁(yè)
首頁(yè)長(zhǎng)這樣,由一個(gè)謠言的輪播(數(shù)據(jù)來(lái)源丁香園)和一個(gè)本校學(xué)生寒假分布地圖等等組成,學(xué)生上報(bào)數(shù)據(jù)之后地圖相應(yīng)的省份的人數(shù)便會(huì)更新。
地圖的數(shù)據(jù)存在云數(shù)據(jù)庫(kù)中,單獨(dú)由一份表來(lái)維護(hù),每個(gè)省份都是一個(gè)記錄。
{
"_id": "上海",
"name": "上海", //省名
"value": 87.0 //該省份存在本校學(xué)生的人數(shù)
}
地圖的數(shù)據(jù)從云函數(shù)getArea獲取后返回到前臺(tái)頁(yè)面,進(jìn)行地圖的初始化,具體的例子可以參考微信小程序版echarts的map,也可以直接看我的源碼,這里說(shuō)一下里面的一些坑,由于繪畫(huà)地圖要引入中國(guó)地圖的json數(shù)據(jù)(目錄下的mapData),而小程序版本的echarts的例子中只有河南地圖的json數(shù)據(jù),因此需要去echarts這里來(lái)復(fù)制中國(guó)地圖的json代碼,粘貼至目錄下的mapData中的json段落,才可以繪制中國(guó)的地圖(其余地圖也同理)。當(dāng)初簡(jiǎn)直被坑得不要不要的。因?yàn)榈貓D數(shù)據(jù)是異步獲取的,所以地圖的初始化在獲取數(shù)據(jù)后進(jìn)行。
this.ecComponent = this.selectComponent('#mychart-dom-bar');
wx.cloud.callFunction({
name: 'getArea'
}).then((res)=>{
let result = res.result
let option = initOption(result)
this.ecComponent.init((canvas, width, height) => {
// 獲取組件的 canvas、width、height 后的回調(diào)函數(shù)
// 在這里初始化圖表
const chart = echarts.init(canvas, null, {
width: width,
height: height
});
chart.setOption(option)
// 將圖表實(shí)例綁定到 this 上,可以在其他成員函數(shù)(如 dispose)中訪問(wèn)
this.chart = chart;
return chart;
});
})
卡片式的輪播來(lái)自于colorui,這是一個(gè)微信小程序的css庫(kù),將對(duì)應(yīng)的class名稱添加進(jìn)去即可。
數(shù)據(jù)上報(bào)頁(yè)面
學(xué)生填寫(xiě)自己的姓名學(xué)號(hào)手機(jī),選擇自己所在的學(xué)院班級(jí)(由于精力有限只做了幾個(gè)學(xué)院),添加自己所在的城市,選擇是否發(fā)熱后就可上報(bào)數(shù)據(jù)。
用戶數(shù)據(jù)存在云數(shù)據(jù)庫(kù)中,單獨(dú)由一份表維護(hù),每個(gè)用戶是一個(gè)記錄
//一份用戶數(shù)據(jù)例子
{
"passCity": [
"北京市-北京市-東城區(qū)" //目前所在地
],
"openId": "oLuLy5MxC_dnd0eZhDVESsoMRln0", //用戶唯一標(biāo)識(shí)
"isHot": 1.0, //1無(wú)發(fā)熱 2有發(fā)熱
"admin": true, //是否為管理員
"classId": 1.0, //班級(jí)所在id
"isCommited": 1.0, //是否提交過(guò)了
"name": "馬化騰", //名字
"phone": "18074815679", //號(hào)碼
"studentId": "1233545" //學(xué)號(hào)
}
第一次上報(bào)前會(huì)申請(qǐng)獲取用戶的信信息以存入數(shù)據(jù)庫(kù),用戶微信的openId作為用戶的唯一標(biāo)識(shí),如果用戶已經(jīng)存在數(shù)據(jù)庫(kù)了就返回相應(yīng)的用戶數(shù)據(jù),如果不存在則初始化用戶數(shù)據(jù)存入數(shù)據(jù)庫(kù)中。
// login
const cloud = require('wx-server-sdk')
cloud.init({
// API 調(diào)用都保持和云函數(shù)當(dāng)前所在環(huán)境一致
env: cloud.DYNAMIC_CURRENT_ENV
})
const db = cloud.database().collection('user')
// 云函數(shù)入口函數(shù)
exports.main = async (event, context) => {
const {OPENID} = cloud.getWXContext()
let result = await db.where({
openId: OPENID
}).get()
//如果在數(shù)據(jù)庫(kù)沒(méi)找到該用戶,則初始化數(shù)據(jù)后存入數(shù)據(jù)庫(kù)
if(!result.data.length){
Object.assign(event.user, event.userInfo)
event.user.isPut = false
event.user.isHot = 0
event.user.passCity = []
await db.add({
data:event.user
})
}
return result
}
用戶填寫(xiě)完信息后會(huì)觸發(fā)兩個(gè)云函數(shù)的調(diào)用,一個(gè)是更新用戶的數(shù)據(jù),將用戶加入相應(yīng)的班級(jí),另一個(gè)是更新地圖數(shù)據(jù),將用戶的所在的省份的學(xué)生人數(shù)加一。
//updateArea
exports.main = async(event, context) => {
const {
OPENID
} = cloud.getWXContext()
// 如果已經(jīng)提交過(guò)了的學(xué)生再提交的話,就把上一次保存地區(qū)的人數(shù)減1
if (event.isCommited) {
let oldCity = await db.collection('user').where({
openId: event.userInfo.openId
}).get()
oldCity = oldCity.data[0].passCity[0].substr(0, 2)
//因?yàn)閺V西省還有內(nèi)蒙古之類的自治區(qū)的名字是不好控制的,所以使用模糊匹配
await db.collection('area').where({
name: db.RegExp({
regexp: oldCity,
options: 's',
})
}).update({
data: {
value: _.inc(-1)
}
})
}
//因?yàn)閺V西省還有內(nèi)蒙古之類的自治區(qū)的名字是不好控制的,所以使用模糊匹配
await db.collection('area').where({
name: db.RegExp({
regexp: event.citys[0],
options: 's',
})
}).update({
data: {
value: _.inc(1)
}
})
return 'ok'
}
///updataUser
exports.main = async (event, context) => {
const {
OPENID
} = cloud.getWXContext()
const { name, phone, citys, isHot, studentId, classId} = event
//第一次提交時(shí)會(huì)提交所屬的班級(jí),將該學(xué)生的信息存到相應(yīng)班級(jí)的表中
if (classId){
await db.collection('class').where({
classId
}).update({
data:{
commitedStudents:_.push({
name,
phone,
citys,
isHot: isHot - 0
})
}
})
}
await db.collection('user').where({
openId: OPENID
}).update({
data: {
name,
studentId,
phone,
classId,
passCity: citys,
isHot: isHot - 0,
isCommited:1,
isPut:true}
})
return 'ok'
}
管理員頁(yè)面
管理員頁(yè)面可以查看全校哪位學(xué)生在湖北,哪位學(xué)生有發(fā)熱跡象,也可以查看某個(gè)班級(jí)的提交情況,班級(jí)學(xué)生列表。進(jìn)入此頁(yè)面需要權(quán)限驗(yàn)證,即用戶的openId對(duì)應(yīng)的記錄下有admin:true字段,需要開(kāi)發(fā)者手動(dòng)在數(shù)據(jù)庫(kù)中用戶添加此字段即可授予管理員權(quán)限。
//驗(yàn)證權(quán)限云函數(shù)
const cloud = require('wx-server-sdk')
cloud.init({
// API 調(diào)用都保持和云函數(shù)當(dāng)前所在環(huán)境一致
env: cloud.DYNAMIC_CURRENT_ENV
})
const db = cloud.database()
// 云函數(shù)入口函數(shù)
exports.main = async (event, context) => {
const wxContext = cloud.getWXContext()
const OPENID = wxContext.OPENID || event.OPENID
let user = await db.collection('user').where({
openId: OPENID
}).get()
user = user.data[0]
if(!user.admin){
return 'error'
}
return 'ok'
}
班級(jí)數(shù)據(jù)存在云數(shù)據(jù)庫(kù)中,單獨(dú)由一份表維護(hù),每個(gè)班級(jí)是一個(gè)記錄
{
"classId": 9, //班級(jí)id
"name": "16經(jīng)濟(jì)一", //班級(jí)名字
"student_sum": 50, //班級(jí)總?cè)藬?shù)
"commitedStudents": [] //已經(jīng)提交信息了的學(xué)生,每個(gè)學(xué)生是個(gè)對(duì)象
}
如何啟動(dòng)本項(xiàng)目
- git clone git@github.com:Akakiiiiii/students-system.git
- cd students-system
- cd cloudfunctions
- npm i
- 使用微信開(kāi)發(fā)工具導(dǎo)入該小程序,填寫(xiě)自己的appId
- 打開(kāi)項(xiàng)目后進(jìn)入云開(kāi)發(fā)->數(shù)據(jù)庫(kù),創(chuàng)造三個(gè)表,分別是area,user,class,并分別導(dǎo)入項(xiàng)目json文件夾下的json文件,area表單導(dǎo)入名字帶area的json文件,以此類推。(init代表僅僅初始化表單,沒(méi)有數(shù)據(jù)。沒(méi)有init的就是有數(shù)據(jù)的,假設(shè)你想看效果就導(dǎo)入名字不帶init的)
- 最后在微信開(kāi)發(fā)者工具上傳所有云函數(shù)即可,選擇云端安裝依賴,即可跑起該項(xiàng)目。
完整項(xiàng)目請(qǐng)查看
github地址:https://github.com/Akakiiiiii/students-system
如果對(duì)您有幫助,希望可以得到一枚您的Star~。(〃'▽'〃)
有任何可以改進(jìn)的地方希望您可以花費(fèi)一些時(shí)間開(kāi)啟一個(gè)Issue或者直接PR~。φ(>ω<)