评论

#小程序云开发挑战赛#-素拓百分百-许一世不嵩手

该小程序用于浙水院发布活动,自动统计学生素拓分

1.背景

我校的素拓分统计流程十分繁琐,除了可以借助报名工具供学生报名活动外,其他素拓分统计操作几乎全部由人工完成,效率低下,出错率较高,在学生学业繁重的形势下,我校亟需诞生一个从活动发布到统计学分的自动化高效平台。

为此,本次项目设计一个基于微信小程序云开发的素拓分管理系统,可以实现线上发布活动,自动统计报名名单,通过扫码签到、签退方式验证学生是否完成活动和自动为学生统计加分等,致力于减轻我校素拓分统计人员的负担。

2. 功能介绍

2.1 用户模块

小程序分为三种用户:普通学生用户、活动发布者和系统管理员。用户登录小程序默认为普通用户,系统管理员可将普通用户设置为活动发布者,也可以将活动发布者撤销权限为普通用户。

2.2 发布活动

活动发布者和系统管理员可以发布活动。编辑活动未发布退出后,会保存草稿;编辑完成后,可以预览活动发布;待活动编辑无误后,可发布活动。活动发布后,由于采用集合监听形式,其他用户能实时接收活动数据。

集合监听代码如下:
onChangeasync (snapshot) => {
        console.log("监听活动表", snapshot)
        // 遍历,正在进行的活动(根据AcStartTime>now,AcNum>0),存入this.data
        // 1. 获取当前网络时间
        let now = await asyncWx.cloudFunction({
          name"getNetworkTime"
        })
        console.log("当前网络时间", now)
        // 查找所有存活的活动
        let AllList = snapshot.docs.filter((v) =>
          (v.rest == 'infinite' || v.rest > 0) && parseInt(v.activityObj.AcStartTime) > parseInt(now)
        )
        console.log("所有存活的活动", AllList)
        // 分类存活的所有活动
        let categoryArr = [];
        // 第一层为 全部活动
        categoryArr.unshift(AllList.reverse())
        this.data.tabs.forEach((v1, i) => {
          if (i > 0) {
            categoryArr[i] = AllList.filter(v2 => {
              return v2.activityObj.AcScoreType == v1
            }).reverse()
          }
        })
        // 存入缓存
        wx.setStorageSync('liveActivities', AllList)
        // 为页面赋值
        this.setData({ categoryArr })
        wx.hideLoading({
          success(res) => { },
        })
  },

2.3 生成打卡码

活动发布后,可以生成签到码和签退码,用户扫描二维码会跳转到打卡页面,生成二维码代码如下:

云函数代码:
exports.main = async (event, context) => {
  try {
    const result = await await cloud.openapi.wxacode.get({
      path:event.path,
      width:320
    })
    let qrName = `QR_${new Date().getTime()}.jpg`
    const file = await cloud.uploadFile({
      cloudPath: qrName,
      fileContent: result.buffer,
    })
    return file
  } catch (err) {
    return err
  }
}

js代码:
let signInQR = await asyncWx.cloudFunction({
        name"createQRCode",
        data: {
          path"pages/verify/verify?type=signIn&AcId=" + id 
        }
 })

2.4 打卡验证

根据二维码参数,验证是签到还是签退,代码如下:

async clockIn() {
    wx.showLoading({
      title: '加载中...',
      mask: true
    })

    if (openid == "") {
      wx.hideLoading({
        success: (res) => { },
      })
      asyncWx.showToast({ title: "尚未登录!" })
      return;
    }
    // 验证用户资料是否完善
    if (JSON.stringify(userBaseInfo) == "{}") {
      wx.hideLoading({
        success: (res) => { },
      })
      asyncWx.showToast({ title: "尚未完善资料!" })
      return;
    }
    // 验证用户是否在指定地点
    // 获取自身位置
    // 1. 判断是否授权
    try {
      let res = await asyncWx.authorize("scope.userLocation")
      if (res !== false) {
        let location = await asyncWx.authorizeByType("getLocation")
        console.log("当前位置是:", location)
        let longitudeNow = location.longitude;
        let latitudeNow = location.latitude;
        // 打卡位置
        let { latitude, longitude } = this.data.clockInLocation
        console.log("打卡地点位置为", latitude, longitude)
        // 计算距离
        let dis = distance(latitudeNow, longitudeNow, latitude, longitude)
        console.log(dis)
        if (dis > 200) {  
          wx.hideLoading({
            success: (res) => { },
          })
          await asyncWx.showModal({ content: "超出打卡范围,请导航移至打卡范围200米以内" })
          return;
        }
      } else {
        wx.hideLoading({
          success: (res) => { },
        })
        return;
      }
    } catch (e) {
      wx.hideLoading({
        success: (res) => { },
      })
      console.log(e)
      return;
    }
    //通过了上面开始操作数据库
    // 数据库操作用到的数据
    console.log("AcId", AcId, "openid", openid, "type"type)

    if (type == "signIn") {  //如果是签到
      console.log("签到")

      //  获取网路当前时间
      let nowTime = await asyncWx.cloudFunction({
        name: "getNetworkTime"
      })
      console.log("当前网络时间", nowTime)
      if (nowTime > this.data.AcStartTime) {  //如果超时
        // 修改STF_Participate用户状态为fail
        let updateRes1 = await asyncWx.cloudFunction({
          name: "databaseOperate",
          data: {
            type"updateAttribute1",
            collection: "STF_Participate",
            myWhere: {
              AcId
            },
            field: "participateUsers",
            attribute: openid,
            attributeValue: "fail"
          }
        })
        // 修改STF_Users参加的活动状态为fail
        let updateRes2 = await asyncWx.cloudFunction({
          name: "databaseOperate",
          data: {
            type"updateAttribute1",
            collection: "STF_Users",
            myWhere: {
              _openid: openid
            },
            field: "userJoinActivities",
            attribute: AcId,
            attributeValue: "fail"
          }
        })
        // 修改按钮状态
        this.setData({
          btnValue:"已失效",
          isBtnDisabled:true
        })
        wx.hideLoading({
          success: (res) => { },
        })
        await asyncWx.showModal({ content: "签到超时,活动实效!" })
        return;
      } else {
        // 修改STF_Participate用户状态为signIn
        let updateRes1 = await asyncWx.cloudFunction({
          name: "databaseOperate",
          data: {
            type"updateAttribute1",
            collection: "STF_Participate",
            myWhere: {
              AcId
            },
            field: "participateUsers",
            attribute: openid,
            attributeValue: "signIn"
          }
        })
         // 修改按钮状态
         this.setData({
          btnValue:"已签到",
          isBtnDisabled:true
        })
        wx.hideLoading({
          success: (res) => { },
        })
        await asyncWx.showModal({ content: "签到成功!" })
        return;
      }

    }

    if (type == "signOut") {  //如果是签退
      console.log("签退")

      //  获取网路当前时间
      let nowTime = await asyncWx.cloudFunction({
        name: "getNetworkTime"
      })
      console.log("当前网络时间", nowTime)
      if (nowTime > this.data.AcEndTime) { //如果超时
        // 修改STF_Participate用户状态为fail
        let updateRes1 = await asyncWx.cloudFunction({
          name: "databaseOperate",
          data: {
            type"updateAttribute1",
            collection: "STF_Participate",
            myWhere: {
              AcId
            },
            field: "participateUsers",
            attribute: openid,
            attributeValue: "fail"
          }
        })
        // 修改STF_Users参加的活动状态为fail
        let updateRes2 = await asyncWx.cloudFunction({
          name: "databaseOperate",
          data: {
            type"updateAttribute1",
            collection: "STF_Users",
            myWhere: {
              _openid: openid
            },
            field: "userJoinActivities",
            attribute: AcId,
            attributeValue: "fail"
          }
        })
         // 修改按钮状态
         this.setData({
          btnValue:"已失效",
          isBtnDisabled:true
        })
        wx.hideLoading({
          success: (res) => { },
        })
        await asyncWx.showModal({ content: "签退超时,活动实效!" })
        return;
      } else {
        // 修改STF_Participate用户状态为finished
        let updateRes1 = await asyncWx.cloudFunction({
          name: "databaseOperate",
          data: {
            type"updateAttribute1",
            collection: "STF_Participate",
            myWhere: {
              AcId
            },
            field: "participateUsers",
            attribute: openid,
            attributeValue: "finished"
          }
        })
        // 修改STF_Users参加的活动状态为finished,同时加上学分
        // 根据学分做出相对的加分
        let scoreType = "";
        switch (activityObj.AcScoreType) {
          case "德育分":
            scoreType = "dScore"
            break;
          case "智育分":
            scoreType = "zScore"
            break;
          case "劳育分":
            scoreType = "lScore"
            break
          case "体育分":
            scoreType = "tScore"
            break
          case "美育分":
            scoreType = "mScore"
            break
          default:
            scoreType = "vScore"
            break
        }

        let updateRes2 = await db.collection("STF_Users").where({
          _openid: openid
        }).update({
          data: {
            userJoinActivities: {
              [AcId]: "finished",
            },
            scoreList: {
              [scoreType]: _.inc(parseFloat(activityObj.AcScoreNum))
            }
          }
        })
         // 修改按钮状态
         this.setData({
          btnValue:"已完成",
          isBtnDisabled:true
        })
        wx.hideLoading({
          success: (res) => { },
        })
        await asyncWx.showModal({ content: "签退成功,活动完成!" })
        return;
      }
    }
  }

2.5 导出名单

这里云函数需要安装node-xlsx类库,代码如下:

// 云函数入口文件
const cloud = require('wx-server-sdk')

cloud.init({
  env:cloud.DYNAMIC_CURRENT_ENV
})
// 重点:一定要 npm install node-xlsx
//操作excel用的类库
const xlsx = require('node-xlsx');

// 云函数入口函数

exports.main = async(event, context) => {  
  try {
    
    //1 处理excel表格名
    let excelName = event.excelName;
    excelName += `_${new Date().getTime()}` 
    excelName += '.xlsx'

   //2 把数据保存到excel里
    var buffer = await xlsx.build([{
      name: event.excelName,
      data: event.data
    }]);
    //4,把excel文件保存到云存储里, 不用success,会直接返回fileID
    return await cloud.uploadFile({
      cloudPath: excelName,
      fileContent: buffer, //excel二进制文件
    })

  } catch (e) {
    console.error(e)
    return e
  }
}

3. 视频演示

视频链接:https://v.qq.com/x/page/y31511jj6pt.html?






最后一次编辑于  2020-09-13  
点赞 0
收藏
评论

2 个评论

  • 守一
    守一
    2020-09-25

    我们团队想要开发一个小程序,可以合作吗?如可以合作,欢迎加微信:mfj-1991-rsf

    2020-09-25
    赞同
    回复
  • 青寒
    青寒
    2020-09-21

    额,以前还不知道这个简称,素质拓展么

    2020-09-21
    赞同
    回复
登录 后发表内容