diff --git a/README.md b/README.md
index c73c3889aa1d3c1d503f3601995ef77aa9f5bea5..73ca2c47fbe5f4bed91ebcdced0cfc7a0588ea0d 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,149 @@
## 同乘码
+ 同乘码作为一个开源的微信小程序项目,希望帮助大家及时发现是否与确诊/疑似新冠病例同行,可查询,可订阅,订阅之后基于事件及时而精准地推送病例信息,基于小程序·云开发技术进行开发,简洁易用友好。
+
详细说明:
[https://segmentfault.com/a/1190000021762607](https://segmentfault.com/a/1190000021762607)
-## 主要功能:
+## 1 主要功能:

-## 实现方案
+## 2 实现方案
客户端使用原生小程序开发, 服务端全部使用云开发

+
+
+
+## 3 特性
+
+1. 基于WeUI开发的UI,界面简洁友好
+2. 基于缓存+存储的查询,高性能
+3. 基于小程序云开发,无服务化,部署更简单
+4. 基于微信疫情同行订阅消息,接收更及时
+5. 基于用户上去上报+外部数据源实时推送,来源更全更灵活
+
+
+
+## 4 部署方式
+
+### 4.1下载
+
+下载源码
+
+```shell
+git clone https://gitee.com/tencent_cloud_development/tcb-hackthon-ncov2019confirm.git
+```
+
+### 4.2 配置
+
+修改appid
+
+project.config.json里修改appid
+
+```json
+{
+ // ...
+ "appid": "自己的appid"
+ // ...
+}
+```
+
+微信开发者工具导入项目,开通“云开发”,新建云开发环境,得到evn_id,并配置`config`/`config.js`
+
+```json
+{
+ "env": "xxx", // 新建的云开发环境的id,注意是id不是name
+ "traceUser": true // 是否追踪用户 true / false
+}
+```
+
+
+
+云开发控制台 - 数据库 - 新建集合
+
+- admin
+- member
+- report
+- roomInfo
+- traffic
+
+集合结构如下:
+
+**admin**集合
+
+| field | type |
+| ------ | ------ |
+| openId | string |
+
+**member**集合
+
+| field | type |
+| -------- | ------ |
+| opendId | string |
+| roomId | string |
+| src | string |
+| status | number |
+| userInfo | object |
+
+**report**集合
+
+| field | type |
+| ------ | ------ |
+| date | string |
+| name | string |
+| phone | string |
+| review | number |
+| roomId | string |
+| rtype | string |
+
+**roomInfo**集合
+
+| field | type |
+| --------- | ------ |
+| date | string |
+| key | string |
+| typeName | string |
+| typeValue | string |
+| wxacode | string |
+
+**traffic**集合
+
+| field | type |
+| ----------- | ------ |
+| created_at | string |
+| source | string |
+| t_date | string |
+| t_end | string |
+| t_memo | string |
+| t_no | string |
+| t_no_sub | string |
+| t_pos_end | string |
+| t_pos_start | string |
+| t_start | string |
+| t_type | string |
+| updated_at | string |
+| verified | number |
+| who | string |
+
+新建后,修改权限为“**所有用户可读,仅创建者可读写**”!!!
+
+### 4.3 部署云函数
+
+login`云函数目录,右键 - 上传并部署
+
+`openapi`云函数目录,右键 - 上传并部署
+
+`sendmsg`云函数目录,右键 - 上传并部署
+
+### 4.4 订阅消息模板配置
+
+- 订阅消息模板的申请方法:在https://mp.weixin.qq.com/上申请自定义的推送模板,“功能” - “订阅消息” - “添加”, 注意参数的格式要一致;
+
+- 订阅消息模板的设置方法:cloudfunctions - sendmsg - index.js - templateId 参数配置为自定义的订阅消息模板ID即可;
+
+### 4.5 完成部署
+
+Ctrl + S,即可看到项目Running起来啦!
+
diff --git a/miniprogram/app.js b/miniprogram/app.js
index dcabdeb6b3d480ca34dc653074b9ab938a517c5c..e9c64ba2306e5dff5232ae469085a59a8c38fb3b 100644
--- a/miniprogram/app.js
+++ b/miniprogram/app.js
@@ -1,7 +1,10 @@
//app.js
+import {
+ config
+} from './config/config.js'
App({
- onLaunch: function () {
-
+ onLaunch: function() {
+
if (!wx.cloud) {
console.error('请使用 2.2.3 或以上的基础库以使用云能力')
} else {
@@ -11,8 +14,8 @@ App({
// 此处请填入环境 ID, 环境 ID 可打开云控制台查看
// 如不填则使用默认环境(第一个创建的环境)
// env: 'release-2cwn8',
- env: 'test-juk88',
- traceUser: true,
+ env: config.env,
+ traceUser: config.traceUser,
})
}
@@ -36,6 +39,6 @@ App({
})
}
})
-
+
}
-})
+})
\ No newline at end of file
diff --git a/miniprogram/config/config.js b/miniprogram/config/config.js
new file mode 100644
index 0000000000000000000000000000000000000000..004d789ec567b0b93407acd120d58a36702030e5
--- /dev/null
+++ b/miniprogram/config/config.js
@@ -0,0 +1,8 @@
+const config = {
+ env: 'test-juk88',
+ traceUser: true
+}
+
+module.exports = {
+ config
+}
\ No newline at end of file
diff --git a/miniprogram/pages/focus/focus.js b/miniprogram/pages/focus/focus.js
index 50e52d5743e1da43e4af511dbb880cca5ff9a108..b725edfcce1339be3077254fd0f861627f50d0e1 100644
--- a/miniprogram/pages/focus/focus.js
+++ b/miniprogram/pages/focus/focus.js
@@ -27,6 +27,7 @@ Page({
isAdmin: false
},
+ // 获取我的订阅
showMine: function() {
var self = this
console.log("show openid", app.globalData.openid)
@@ -73,9 +74,7 @@ Page({
* 生命周期函数--监听页面加载
*/
onLoad: function(options) {
- this.setData({
- isAdmin: ['ogacd5D7Jmu1tiLuUdGfbGVOPNic', 'ogacd5OZFhnml16yxrG8h1iE26iQ'].indexOf(app.globalData.openid) > -1
- })
+ this.checkAdmin()
},
/**
@@ -125,5 +124,20 @@ Page({
*/
onShareAppMessage: function() {
+ },
+
+ // 判断是否为管理员
+ checkAdmin() {
+ db.collection('admin').where({
+ openId: app.globalData.openid
+ }).get().then(res => {
+ if (res.errMsg === 'collection.get:ok' && res.data.length > 0) {
+ this.setData({
+ isAdmin: true
+ })
+ }
+ }).catch(err => {
+ console.log(err)
+ })
}
})
\ No newline at end of file
diff --git a/miniprogram/pages/index/index.js b/miniprogram/pages/index/index.js
index 0b5fcd230ab436c7c0a33f060689cf1af4002d6e..49ef9b03e6e74c4f00d6aa6e8076b1799f996afc 100644
--- a/miniprogram/pages/index/index.js
+++ b/miniprogram/pages/index/index.js
@@ -1,13 +1,9 @@
//index.js
+const util = require('../../util/tools.js')
const app = getApp()
const db = wx.cloud.database()
const _ = db.command
-function getDateStr() {
- var dd = new Date()
- return dd.getFullYear().toString() + '-' + (dd.getMonth() + 1).toString() + '-' + dd.getDate().toString()
-}
-
Page({
data: {
formData: {},
@@ -53,7 +49,7 @@ Page({
// })
db.collection("report").where({}).get()
- var ddstr = getDateStr()
+ var ddstr = util.getDateStr()
this.setData({
date: ddstr
})
@@ -150,64 +146,59 @@ Page({
showCancel: false
})
} else {
- // 从公开数据源查询
- let key = ''
- switch (this.data.formData.typeName) {
- case "airplane":
- key = '飞机'
- break
- case "train":
- key = '火车'
- break
- case "car":
- key = _.in(['出租车', '公交车'])
- break
- default:
- break
- }
- let date = this.data.formData.date.split('-')
- let items = []
- items.push(date[0])
- date[1][0] === '0' ? items.push(date[1].slice(1)) : items.push(date[1])
- date[2][0] === '0' ? items.push(date[2].slice(1)) : items.push(date[2])
- date = items.join('/')
- console.log({
- t_type: key,
- t_no: this.data.formData.typeValue,
- t_date: date
- })
- db.collection('traffic').where({
- t_type: key,
- t_no: this.data.formData.typeValue,
- t_date: date
- }).get({
- success: res => {
- console.log(res)
- if (res.errMsg === 'collection.get:ok' && res.data.length > 0) {
- wx.showModal({
- title: '查询结果',
- content: self.data.typeName + self.data.formData.typeValue + '存在新冠病例,请注意安全,及时隔离!',
- showCancel: false
- })
- } else {
- // 安全
- if (!danger) {
- wx.showModal({
- title: '查询结果',
- content: '恭喜你!' + self.data.typeName + self.data.formData.typeValue + '安全,请关注后续信息',
- showCancel: false
- })
- }
- }
- }
- })
+ this.checkFromOpenSource()
}
},
- error: console.log
+ fail: console.error
+ })
+ } else {
+ this.checkFromOpenSource()
+ }
+ },
+ fail: console.error
+ })
+ },
+
+ checkFromOpenSource() {
+ const self = this
+ // 从公开数据源查询
+ let key = ''
+ switch (this.data.formData.typeName) {
+ case "airplane":
+ key = '飞机'
+ break
+ case "train":
+ key = '火车'
+ break
+ case "car":
+ key = _.in(['出租车', '公交车'])
+ break
+ default:
+ break
+ }
+ let date = util.translateDate(this.data.formData.date)
+ db.collection('traffic').where({
+ t_type: key,
+ t_no: this.data.formData.typeValue,
+ t_date: date
+ }).get({
+ success: res => {
+ if (res.errMsg === 'collection.get:ok' && res.data.length > 0) {
+ wx.showModal({
+ title: '查询结果',
+ content: self.data.typeName + self.data.formData.typeValue + '存在新冠病例,请注意安全,及时隔离!',
+ showCancel: false
+ })
+ } else {
+ // 安全
+ wx.showModal({
+ title: '查询结果',
+ content: '恭喜你!' + self.data.typeName + self.data.formData.typeValue + '安全,请关注后续信息',
+ showCancel: false
})
}
},
- error: console.log
+ fail: console.error
})
},
diff --git a/miniprogram/pages/report/report.js b/miniprogram/pages/report/report.js
index d87892741f0ec7c923e0ec03c75609bd587c67f7..cd005a38a0cdfd107c2101faa727caab99d69d6d 100644
--- a/miniprogram/pages/report/report.js
+++ b/miniprogram/pages/report/report.js
@@ -1,12 +1,7 @@
// miniprogram/pages/report/report.js
-
+const util = require('../../util/tools.js')
const db = wx.cloud.database()
-function getDateStr() {
- var dd = new Date()
- return dd.getFullYear().toString() + '-' + (dd.getMonth() + 1).toString() + '-' + dd.getDate().toString()
-}
-
Page({
/**
@@ -33,6 +28,7 @@ Page({
this.data.roomId = options.roomId
},
+ // 提交表单上报疫情
submitForm: function(e) {
let vals = e.detail.value
if (!vals.rtype) {
@@ -68,7 +64,7 @@ Page({
icon: 'none',
})
vals.roomId = this.data.roomId
- vals.date = getDateStr()
+ vals.date = util.getDateStr()
vals.review = 0
db.collection("report").add({
@@ -84,6 +80,7 @@ Page({
})
},
+ // 病例类型变化处理
onTypeChange: function(e) {
var radioItems = this.data.radioItems;
for (var i = 0, len = radioItems.length; i < len; ++i) {
diff --git a/miniprogram/pages/report/report.wxml b/miniprogram/pages/report/report.wxml
index b98a3b15d304526e7c50f68fc949322464530fd9..54e69ad18fec10fc0a72e732a51f5cdb946c12de 100644
--- a/miniprogram/pages/report/report.wxml
+++ b/miniprogram/pages/report/report.wxml
@@ -53,8 +53,8 @@
-
- 提交信息后, 平台先会审核信息, 有可能会主动联系您, 感谢您的配合与支持!
+
+ 备注:提交信息后, 平台先会审核信息, 有可能会主动联系您, 感谢您的配合与支持!
\ No newline at end of file
diff --git a/miniprogram/pages/room/room.js b/miniprogram/pages/room/room.js
index 4cb04b2d6efa2ee2d9cb044ede06938b93e39721..91be5920e34f3162a1ad20928a3b98d01adee2a8 100644
--- a/miniprogram/pages/room/room.js
+++ b/miniprogram/pages/room/room.js
@@ -1,4 +1,3 @@
-
//index.js
const app = getApp()
const db = wx.cloud.database()
@@ -29,9 +28,9 @@ Page({
/**
* 生命周期函数--监听页面加载
*/
- onLoad: function (options) {
+ onLoad: function(options) {
var roomId = options.roomId
- if(!roomId){
+ if (!roomId) {
console.error("missing room id", options)
return
}
@@ -43,8 +42,8 @@ Page({
// wait openid ready
var self = this
var openId = app.globalData.openid
- if(!openId){
- setTimeout(function(){
+ if (!openId) {
+ setTimeout(function() {
self.onLoad(options)
}, 500)
return
@@ -52,8 +51,8 @@ Page({
// 初始化页面
self.initRoom(roomId)
-
-
+
+
// 检查是否有权限
// 获取用户信息
@@ -72,14 +71,14 @@ Page({
}
})
}
- if(!res.authSetting['scope.subscribeMessage']){
+ if (!res.authSetting['scope.subscribeMessage']) {
//开启订阅
wx.showModal({
content: '请同意订阅消息',
- complete: ()=>{
+ complete: () => {
wx.requestSubscribeMessage({
tmplIds: [tmpId],
- success: res =>{
+ success: res => {
console.log('scope.subscribeMessage done')
},
fail: console.error
@@ -91,8 +90,9 @@ Page({
})
},
- onJoinRoom: function(e){
- if(!e.detail.userInfo){
+ // 加入同行者时处理
+ onJoinRoom: function(e) {
+ if (!e.detail.userInfo) {
wx.showToast({
title: '请同意获取信息',
icon: 'none',
@@ -107,10 +107,10 @@ Page({
//开启订阅
wx.showModal({
content: '请同意订阅消息',
- complete: ()=>{
+ complete: () => {
wx.requestSubscribeMessage({
tmplIds: [tmpId],
- success: res =>{
+ success: res => {
console.log('scope.subscribeMessage done')
},
fail: console.error
@@ -120,14 +120,15 @@ Page({
wx.requestSubscribeMessage({
tmplIds: [tmpId],
- success: res =>{
+ success: res => {
console.log('scope.subscribeMessage done')
},
fail: console.error
})
},
- joinRoom: function(){
+ // 加入同行者
+ joinRoom: function() {
var roomId = this.data.roomId
var openId = app.globalData.openid
var self = this
@@ -140,7 +141,7 @@ Page({
src: self.data.userInfo.avatarUrl,
userInfo: self.data.userInfo,
},
- success: function(e){
+ success: function(e) {
console.log("join succ", e)
self.onShow() // 刷新一次页面数据
},
@@ -151,11 +152,13 @@ Page({
/**
* 生命周期函数--监听页面隐藏
*/
- initRoom: function (roomId) {
+ initRoom: function(roomId) {
console.log('init room', roomId)
var self = this
- db.collection('roomInfo').where({_id: roomId}).get({
- success: function(e){
+ db.collection('roomInfo').where({
+ _id: roomId
+ }).get({
+ success: function(e) {
console.log("room info", e.data[0])
self.setData({
room: {
@@ -167,7 +170,7 @@ Page({
}
})
},
- fail: function(e){
+ fail: function(e) {
wx.showToast({
title: '信息不存在',
})
@@ -178,28 +181,32 @@ Page({
/**
* 生命周期函数--监听页面初次渲染完成
*/
- onReady: function () {
- },
+ onReady: function() {},
/**
* 生命周期函数--监听页面显示
*/
- onShow: function () {
+ onShow: function() {
var roomId = this.data.roomId
var self = this
- db.collection("member").where({roomId: roomId, status: 0}).count({
+ db.collection("member").where({
+ roomId: roomId,
+ status: 0
+ }).count({
success: res => {
self.setData({
memberNum: res.total,
})
- },
+ },
fail: console.error,
})
- db.collection("report").where({roomId: roomId}).count({
+ db.collection("report").where({
+ roomId: roomId
+ }).count({
success: res => {
- if(res.total > 0){
+ if (res.total > 0) {
self.setData({
reportText: "共有" + res.total + "例报告",
})
@@ -210,7 +217,8 @@ Page({
},
- showWXCode: function(){
+ // 显示二维码
+ showWXCode: function() {
wx.previewImage({
current: this.data.room.wxacode, // 当前显示图片的http链接
urls: [this.data.room.wxacode] // 需要预览的图片http链接列表
@@ -220,36 +228,39 @@ Page({
/**
* 页面上拉触底事件的处理函数
*/
- onReachBottom: function () {
+ onReachBottom: function() {
},
/**
* 用户点击右上角分享
*/
- onShareAppMessage: function () {
+ onShareAppMessage: function() {
},
- exitRoom: function(){
+ // 退出同行者
+ exitRoom: function() {
var self = this
wx.showModal({
content: '退出后将无法收到后续的订阅消息',
success: res => {
- if(res.confirm){
+ if (res.confirm) {
console.log("start exit", self.data.room.id, app.globalData.openid)
db.collection("member").where({
roomId: self.data.room.id,
- openId: app.globalData.openid,
+ openId: app.globalData.openid,
}).update({
- data: {status: 1},
- success: res =>{
+ data: {
+ status: 1
+ },
+ success: res => {
wx.showToast({
title: '退出成功',
duration: 2000,
})
-
+
setTimeout(function() {
wx.switchTab({
url: '/pages/focus/focus',
diff --git a/miniprogram/util/tools.js b/miniprogram/util/tools.js
new file mode 100644
index 0000000000000000000000000000000000000000..c703d32f15c6ca93b372a9e5941c69d6b3e11e53
--- /dev/null
+++ b/miniprogram/util/tools.js
@@ -0,0 +1,18 @@
+let getDateStr = function() {
+ var dd = new Date()
+ return dd.getFullYear().toString() + '-' + (dd.getMonth() + 1).toString() + '-' + dd.getDate().toString()
+}
+
+let translateDate = function(ds) {
+ const date = ds.split('-')
+ let items = []
+ items.push(date[0])
+ date[1][0] === '0' ? items.push(date[1].slice(1)) : items.push(date[1])
+ date[2][0] === '0' ? items.push(date[2].slice(1)) : items.push(date[2])
+ return items.join('/')
+}
+
+module.exports = {
+ getDateStr,
+ translateDate
+}