[mini-blog][v2.1.0]博客小程序簽到功能實現
- 2020 年 3 月 11 日
- 筆記
昨天抽空將mini-blog的簽到功能基本上實現了,這裡分享下。
很早之前就想實現簽到功能,昨天終於花時間去變現了,先來看下效果圖。
效果

個人中心
的排版進行了一定的改造,將關於個人相關的信息整合,留些位置給到簽到。

截圖1
簽到頁還是常規的日曆組件,為了保證一頁填滿,加了一個廣告組件。

截圖2
後端實現

頁面樣式定好之後,就看怎麼設計了,首先是數據庫,在雲數據庫中我又新增了三個集合。
首先是mini_member
,用於記錄會員相關的匯總數據,以openId
作為唯一索引,其中也預留了一些屬性,比如積分,未讀消息等,用於後期的功能迭代中。
{ "openId": "oyMiZ5aClPsDJ_2LqWNXWXMolyhs", "continueSignedCount": 1,//連續簽到數量 "lastSignedDate": "2020-03-05",//最近簽到日 "level": 1,//會員等級(預留) "totalPoints": 1,//總的積分(預留) "totalSignedCount": 1,//總的簽到數 "unreadMessgeCount": 0,//未讀消息(預留) "modifyTime": 1583410585920 }
然後是兩張明細表,mini_point_detail
和mini_sign_detail
,用於記錄用戶的簽到明細和積分明細。
基本上這三個集合可以基本滿足簽到+積分的一些簡單功能了。
接着就是雲函數的編寫了,在這裡我也新增了一個雲函數memberService
,用於處理會員維度相關的操作。
這次核心的方法就是簽到,要操作的集合還是比較多的,除了要操作上面新增的三個集合之外,還要加一個mini_subcribute
,用於接入簽到提醒的訂閱消息。核心代碼如下:
async function addSign(event) { console.info("addSign") try { let memberInfos = await db.collection('mini_member').where({ openId: event.info.openId }).get(); const tasks = [] let date = new Date().toFormat("YYYY-MM-DD") if (memberInfos.data.length === 0) { let task1 = db.collection('mini_member').add({ data: { openId: event.info.openId, totalSignedCount: 1,//累計簽到數 continueSignedCount: 1,//持續簽到 totalPoints: 1,//積分 lastSignedDate: date,//最後一次簽到日期 level: 1,//會員等級(預留) unreadMessgeCount: 0,//未讀消息(預留) modifyTime: new Date().getTime() } }) tasks.push(task1) } else { let continueSignedCount = 1 let memberInfo = memberInfos.data[0] if (new Date().addDays(-1).toFormat("YYYY-MM-DD") == memberInfo.lastSignedDate) { continueSignedCount = memberInfo.continueSignedCount + 1 } let task2 = db.collection('mini_member').doc(memberInfo._id).update({ data: { totalSignedCount: _.inc(1), continueSignedCount: continueSignedCount, totalPoints: _.inc(1), lastSignedDate: date, modifyTime: new Date().getTime() } }); tasks.push(task2) } //簽到明細 let date1 = new Date().toFormat("YYYY-M-D").split("-") let task3 = db.collection('mini_sign_detail').add({ data: { openId: event.info.openId, year: date1[0], month: date1[1], day: date1[2], createTime: new Date().getTime() } }) tasks.push(task3) //如果統一訂閱簽到通知 if (event.info.accept == 'accept') { let task4 = await db.collection("mini_subcribute").add({ data: { templateId: event.info.templateId, openId: event.info.openId, timestamp: new Date().getTime() } }); tasks.push(task4) } //積分明細 let task5 = db.collection('mini_point_detail').add({ data: { openId: event.info.openId, operateType: 0,//0:獲得 1:使用 2:過期 count: 1, desc: "簽到得積分", date: (new Date()).toFormat("YYYY-MM-DD HH:MI:SS"), createTime: new Date().getTime() } }) tasks.push(task5) await Promise.all(tasks) return true } catch (e) { console.error(e) return false } }
當然這裡還是不夠嚴謹的,理論上最好使用事務「雲開發目前已經支持了,後面我優化下」,保證這幾個集合的數據一致性。
其他用於界面展示的數據,可以繞過雲函數,直接在小程序端查詢雲數據庫即可,代碼較簡單,簡單的查詢。
交互實現

在前端交互上,本着不重複造輪子的目的,找了個開源日曆組件「wx_calendar
」,樣式上基本能接受,功能也滿足,所以直接拿來用了。詳細的文檔可以看下他的github,文檔還是比較詳細的。
主要在初始化日曆組件之後,需要獲取歷史已經簽到的明細,來渲染選中狀態:
/** * 日曆組件渲染之後 */ afterCalendarRender: async function (e) { let year=util.getYear(new Date()) let month=util.getMonth(new Date()) let res = await api.getSignedDetail(app.globalData.appid, year.toString(), month.toString()) console.info(res) let toSet = []; res.result.forEach(function (item) { let set = { year: item.year, month: item.month, day: item.day } toSet.push(set) }) this.calendar.setSelectedDays(toSet); }
另外就是在用戶點擊簽到前,喚起下訂閱消息授權,接受提醒則每天可以定時提醒用戶簽到。
/** * 簽到 */ bindSignFn: function (e) { let that = this let tempalteId = 'J-MZ6Zrd08TobUgWPbjQcnJt9BHbc9M-nOOxirC8nWA' wx.requestSubscribeMessage({ tmplIds: [tempalteId], success(res) { console.info(res) that.submitSign(res[tempalteId], tempalteId,that).then((res) => { console.info(res) }) }, fail(res) { console.info(res) wx.showToast({ title: '程序有一點點小異常,操作失敗啦', icon: 'none', duration: 1500 }) } }) },
最後

簽到功能已經發版上線拉,有興趣的小夥伴可以體驗下哦。
至於一些細節上交互和實現可以直接獲取源碼查看,有好的建議也歡迎留言。
下個迭代將完善積分模塊,增加一些積分獲取的渠道,同時想下有什麼福利可以利用積分系統來分享給大家。