用Node.js和express完成的實時會議系統(tǒng)微信公眾號后臺

之前和小伙伴完成的一個公眾號,記錄一下大概的開發(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
              })
            })
        }
      })
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容