之前和小伙伴完成的一個公眾號,記錄一下大概的開發(fā)過程吧
微信授權(quán)部分
我們用的是企業(yè)微信號,因為當(dāng)時企業(yè)微信的官方文檔更新不夠及時,有部分api的請求參數(shù)是錯誤的,所以耽誤了不少時間。
第一步
請求微信的api首先需要拿到一個accessToken,而這個token是通過corpid和corpsecret來拿到的
corpid:每個企業(yè)都擁有唯一的corpid,獲取此信息可在管理后臺“我的企業(yè)”-“企業(yè)信息”下查看(需要有管理員權(quán)限)
userid: 每個成員都有唯一的userid,即所謂“帳號”。在管理后臺->“通訊錄”->點(diǎn)進(jìn)某個成員的詳情頁,可以看到
這個token的過期時間默認(rèn)是7200s,保存token的方法有很多種,比如說使用redis,或者直接放在文件中,我這使用的是guard_dog
npm install guard_dog --save
const guard_dog = require('guard_dog')
guard_dog.init('ACCESS_TOKEN', (handler) => {
request.get({
uri: 'https://qyapi.weixin.qq.com/cgi-bin/gettoken?',
json: true,
qs: {
'corpid': config.corpId,
'corpsecret': config.corpSecret
}
}, (err, res, body) => {
if (err) {
console.log(err)
return
}
if (body.errcode) {
return
}
handler(body.access_token, body.expires_in)
})
})
第二步
配置可信域名,具體參考官方文檔
配置完可信域名后,需要構(gòu)造如下的連接來獲得code參數(shù)
https://open.weixin.qq.com/connect/oauth2/authorize?appid=CORPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&agentid=AGENTID&state=STATE#wechat_redirect
用戶點(diǎn)擊后,頁面將跳轉(zhuǎn)至 redirect_uri?code=CODE&state=STATE
第三步
獲得code參數(shù)后,就可以根據(jù)code獲取用戶信息
guard_dog.get('ACCESS_TOKEN', (data) => {
const tokenParams = {
'access_token': data,
'code': code
}
let tokenUrl = 'https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?' + qs.stringify(tokenParams)
request(tokenUrl, function (err, response, body) {
let userTicket = body.split('"')[17]
const userParams = {
'access_token': data
}
let userUrl = 'https://qyapi.weixin.qq.com/cgi-bin/user/getuserdetail?' + qs.stringify(userParams)
let options = {
url: userUrl,
method: "POST",
json: true,
headers: {
"content-type": "application/json",
},
body: {
"user_ticket": userTicket
}
}
request(options, function (err, response, bodyData) {
getBody(bodyData)
.then(user => {
res.json({
status: 200,
user
})
})
})
})
})
實時聊天部分
主要使用了socket來實現(xiàn)
npm install socket.io --save
const socket = require('socket.io')
const server = http.createServer(app).listen(4000)
const io = socket(server)
io.on('connection', function (socket) {
console.log('connected')
socket.on('joinRoom', function (room) {
socket.join(room)
socket.on('sendData', function (data) {
io.sockets.in(room).emit('receiveData', data)
})
})
})
基本會議功能
如 加入會議/創(chuàng)建會議等等..
大部分都是一些對數(shù)據(jù)庫的增刪改查,創(chuàng)建會議時會自動分配一個五位數(shù)的隨機(jī)會議號
function radomNumber () {
let number = ''
for (let i = 0; i < 5; i++) {
number += Math.floor(Math.random() * 10)
}
return number
}
在這里,因為涉及到與數(shù)據(jù)庫的交互,所以要注意異步問題
async number(req, res) {
let result = ''
let number = radomNumber()
while (1) {
result = await Conference.find({number: number})
if (JSON.stringify(result) === '[]') {
res.json({
number
})
return
} else {
number = radomNumber()
}
}
}
有一個掃描二維碼可以進(jìn)入會議的功能,實現(xiàn)的邏輯就是通過url生成一個二維碼返回給前端,用到了qrcode這個npm包
npm install qrcode --save
const QRCode = require('qrcode')
getQRCode(req, res) {
QRCode.toDataURL(req.body.url, function (err, url) {
res.json({
status: 200,
result: url
})
})
}
活動部分功能
主要實現(xiàn)了四個活動功能,投票,抽獎,評分,紅包
投票功能
Vote
.update({_id: req.body._id, "options.name": req.body.name},
{$inc:{"options.$.people":1}})
.then(() => {
res.json({
status: 200,
result: 'Success!'
})
})
.catch(err => {
console.error(err)
if (err.json) {
err.message = err.json.message
}
if (!returned) {
res.status(500).json({
status: 500,
result: err.message
})
}
})
抽獎功能
Conference
.findOne({number: req.body.number})
.then(conference => {
let winner = Math.floor(Math.random() * (conference.people))
Lottery
.update({_id: req.body._id},
{$set:{luckyDog: conference.userList[winner].name, isBegin: true}})
.then(() => {
res.json({
status: 200,
result: 'Success!'
})
})
})
評分功能
Rate
.update(
{_id:req.body._id},
{$inc: {totalScore: req.body.score, totalPeople: 1}})
.then(() => {
res.json({
status: 200,
result: 'Success!'
})
})
紅包功能
因為涉及到支付功能的話需要進(jìn)行企業(yè)認(rèn)證,所以采用了模擬紅包的方法來實現(xiàn)
首先是一個紅包算法
function red (rpAmount, ppCount) {
let rpResult=[]
let rpRnds = []
let rpRndSum = 0
for(let i=0;i<ppCount;i++){
let rnd = Math.random();
rpRndSum += rnd;
rpRnds.push(rnd);
}
rpRnds.forEach((rnd)=>{rpResult.push(parseFloat((rpAmount*rnd/rpRndSum).toFixed(2)))})
return rpResult
}
rpAmount是總金額,ppCount是紅包個數(shù)
以10個紅包,一百元為例:
先生成10個0-1之間的隨機(jī)數(shù),加入到rpRnds這個數(shù)組中,然后對這個數(shù)組中的每個數(shù)都進(jìn)行運(yùn)算:rpAmount*rnd/rpRndSum
(rpRndSum為這十個數(shù)的總和)
這樣就可以得到較為隨機(jī)的紅包金額
Red
.findOne({_id: req.body._id})
.then(red => {
if (red.index > red.people - 1) {
res.json({
money: null
})
} else {
Red
.update({_id: req.body._id},
{$push:{luckyDogs: {username:req.body.username, money:red.money[red.index]}},
$inc:{index: 1}})
.then(() => {
res.json({
money: red.money[red.index],
index: red.index
})
})
}
})