1. 项目概述
作为一名经历过多次疫情封控的程序员,我深知一个高效的居家健康监测系统对个人和社会的重要性。去年我指导了一位学生的毕业设计,开发了一套基于微信小程序的疫情居家检测管理系统,这个项目获得了学校优秀毕业设计的荣誉。今天我就把这个项目的完整实现过程分享给大家,希望能为有类似需求的开发者提供参考。
这个系统的核心价值在于:通过微信这个国民级应用平台,实现疫情信息的实时同步、个人健康数据的便捷上报、智能风险评估以及防控知识的精准推送。相比传统的纸质登记或单一功能App,我们的方案具有以下优势:
- 零安装成本:直接使用微信小程序,无需额外下载安装
- 极低的使用门槛:界面简洁,操作符合微信用户习惯
- 实时数据同步:疫情动态和个人健康数据都能及时更新
- 智能分析预警:基于规则引擎的风险评估模型
2. 系统架构设计
2.1 技术选型考量
在技术栈选择上,我们主要考虑了以下几个因素:
前端技术:
- 微信小程序原生开发:相比uniapp等跨平台方案,原生开发能获得更好的性能和兼容性
- WXML+WXSS+JS:标准的小程序开发语言组合
- ECharts for WeChat:用于疫情数据可视化展示
后端技术:
- Node.js + Koa2:轻量级后端框架,适合快速开发
- MySQL 8.0:关系型数据库,存储结构化数据
- Redis:缓存热点数据,提升系统响应速度
云服务:
- 腾讯云开发(TCB):提供一站式后端服务,包括数据库、存储和云函数
- 腾讯云API网关:管理后端接口
提示:选择腾讯云系产品是因为它们与微信生态有深度整合,在鉴权、支付等环节可以省去很多适配工作。
2.2 系统模块划分
整个系统分为以下核心模块:
- 用户管理模块:处理注册登录、个人信息维护
- 疫情数据模块:聚合展示官方疫情统计数据
- 健康上报模块:记录用户每日健康状态
- 风险评估模块:基于规则引擎分析感染风险
- 消息通知模块:推送重要疫情通知和个人风险预警
- 知识库模块:提供权威防疫指南
- 管理后台模块:供管理员查看数据统计和用户管理
3. 数据库详细设计
3.1 核心表结构
我们设计了符合第三范式的数据库结构,主要包含以下表:
用户表(users)
sql复制CREATE TABLE `users` (
`user_id` int(11) NOT NULL AUTO_INCREMENT,
`openid` varchar(32) NOT NULL COMMENT '微信openid',
`nickname` varchar(50) DEFAULT NULL,
`avatar_url` varchar(255) DEFAULT NULL,
`phone` varchar(20) DEFAULT NULL,
`gender` tinyint(1) DEFAULT '0' COMMENT '0-未知 1-男 2-女',
`age` tinyint(3) DEFAULT NULL,
`region_code` varchar(12) DEFAULT NULL COMMENT '行政区划代码',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`user_id`),
UNIQUE KEY `idx_openid` (`openid`),
KEY `idx_region` (`region_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
健康记录表(health_records)
sql复制CREATE TABLE `health_records` (
`record_id` bigint(20) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`report_date` date NOT NULL COMMENT '上报日期',
`temperature` decimal(3,1) DEFAULT NULL COMMENT '体温',
`symptoms` varchar(255) DEFAULT NULL COMMENT '症状,逗号分隔',
`is_contact` tinyint(1) DEFAULT '0' COMMENT '是否接触过确诊/疑似病例',
`health_status` tinyint(1) DEFAULT '1' COMMENT '1-健康 2-疑似 3-确诊',
`location` varchar(255) DEFAULT NULL COMMENT '地理位置',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`record_id`),
UNIQUE KEY `idx_user_date` (`user_id`,`report_date`),
KEY `idx_date_status` (`report_date`,`health_status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
3.2 关键设计决策
-
微信openid处理:我们没有存储用户的微信账号密码,而是使用微信登录获取openid作为唯一标识,符合最小权限原则。
-
健康记录设计:采用"用户ID+日期"的联合唯一索引,确保每人每天只能上报一次健康状态。
-
地区数据存储:使用国家标准的行政区划代码,便于与官方疫情数据对接。
-
症状字段设计:使用逗号分隔的字符串存储多种症状,平衡了查询效率和灵活性。
4. 核心功能实现
4.1 微信登录集成
小程序端实现微信登录的代码示例:
javascript复制// pages/login/login.js
Page({
handleLogin: function() {
wx.login({
success: res => {
if (res.code) {
wx.getUserProfile({
desc: '用于完善会员资料',
success: userRes => {
this.loginWithCode(res.code, userRes.userInfo)
}
})
}
}
})
},
loginWithCode: function(code, userInfo) {
wx.request({
url: 'https://yourdomain.com/api/login',
method: 'POST',
data: {
code: code,
nickName: userInfo.nickName,
avatarUrl: userInfo.avatarUrl
},
success: res => {
// 登录成功处理
}
})
}
})
后端处理登录的Node.js代码:
javascript复制// controllers/auth.js
const jwt = require('jsonwebtoken')
const axios = require('axios')
async function wechatLogin(ctx) {
const { code, nickName, avatarUrl } = ctx.request.body
// 调用微信接口获取openid
const appid = 'your_appid'
const secret = 'your_secret'
const url = `https://api.weixin.qq.com/sns/jscode2session?appid=${appid}&secret=${secret}&js_code=${code}&grant_type=authorization_code`
const response = await axios.get(url)
const { openid } = response.data
// 查找或创建用户
let user = await User.findOne({ where: { openid } })
if (!user) {
user = await User.create({
openid,
nickname: nickName,
avatar_url: avatarUrl
})
}
// 生成JWT token
const token = jwt.sign(
{ userId: user.user_id },
process.env.JWT_SECRET,
{ expiresIn: '7d' }
)
ctx.body = { token, user }
}
4.2 健康上报功能实现
健康上报界面需要考虑用户体验和数据有效性:
- 体温输入校验:
javascript复制// 校验体温输入
function validateTemperature(temp) {
const value = parseFloat(temp)
if (isNaN(value)) return false
return value >= 35 && value <= 42
}
- 症状多选组件:
xml复制<!-- pages/report/report.wxml -->
<view class="symptom-section">
<text>症状选择(可多选)</text>
<checkbox-group bindchange="onSymptomChange">
<label wx:for="{{symptomList}}" wx:key="id">
<checkbox value="{{item.id}}" checked="{{item.checked}}"/>{{item.name}}
</label>
</checkbox-group>
</view>
- 地理位置获取:
javascript复制// 获取用户当前位置
async function getLocation() {
return new Promise((resolve, reject) => {
wx.getLocation({
type: 'gcj02',
success: resolve,
fail: reject
})
})
}
4.3 风险评估引擎
我们设计了一个基于规则引擎的风险评估模型:
javascript复制// services/riskAssessment.js
class RiskEngine {
constructor() {
this.rules = [
{
name: '高温风险',
condition: (record) => record.temperature >= 37.3,
score: 20
},
{
name: '接触风险',
condition: (record) => record.is_contact,
score: 30
},
// 更多规则...
]
}
evaluate(record) {
let totalScore = 0
const triggeredRules = []
this.rules.forEach(rule => {
if (rule.condition(record)) {
totalScore += rule.score
triggeredRules.push(rule.name)
}
})
let riskLevel = '低风险'
if (totalScore >= 50) riskLevel = '高风险'
else if (totalScore >= 30) riskLevel = '中风险'
return {
score: totalScore,
level: riskLevel,
rules: triggeredRules
}
}
}
5. 关键问题与解决方案
5.1 数据实时性保障
疫情数据需要及时更新,我们采用了以下策略:
- 定时任务拉取官方数据:
javascript复制// 每天8点、12点、18点同步疫情数据
const schedule = require('node-schedule')
schedule.scheduleJob('0 8,12,18 * * *', async () => {
await syncEpidemicData()
})
async function syncEpidemicData() {
const data = await fetchOfficialData()
await EpidemicData.bulkCreate(data, {
updateOnDuplicate: ['confirmed', 'suspected', 'cured', 'dead']
})
}
- WebSocket实时推送:
javascript复制// 当有重要疫情更新时实时推送
function broadcastEpidemicUpdate(data) {
wss.clients.forEach(client => {
if (client.readyState === WebSocket.OPEN) {
client.send(JSON.stringify({
type: 'epidemic_update',
data
}))
}
})
}
5.2 高并发处理
考虑到疫情高峰期可能出现的并发压力,我们做了以下优化:
- Redis缓存热点数据:
javascript复制async function getEpidemicData(regionCode) {
const cacheKey = `epidemic:${regionCode}`
let data = await redis.get(cacheKey)
if (!data) {
data = await EpidemicData.findOne({ where: { regionCode } })
await redis.setex(cacheKey, 3600, JSON.stringify(data)) // 缓存1小时
} else {
data = JSON.parse(data)
}
return data
}
- 数据库读写分离:
javascript复制// 配置MySQL读写分离
const db = new Sequelize('database', null, null, {
dialect: 'mysql',
replication: {
read: [
{ host: 'read1.example.com' },
{ host: 'read2.example.com' }
],
write: { host: 'write.example.com' }
}
})
6. 管理后台实现
6.1 数据可视化
使用ECharts实现疫情数据可视化:
javascript复制// 初始化疫情地图
function initEpidemicMap(canvasId, data) {
const chart = echarts.init(document.getElementById(canvasId))
const option = {
tooltip: {
trigger: 'item',
formatter: params => {
return `${params.name}<br/>
确诊: ${params.data.value || 0}<br/>
疑似: ${params.data.suspected || 0}`
}
},
visualMap: {
min: 0,
max: 100,
text: ['高', '低'],
inRange: {
color: ['#e0f3f8', '#abd9e9', '#74add1', '#4575b4', '#313695']
}
},
series: [{
name: '疫情数据',
type: 'map',
map: 'china',
roam: true,
emphasis: {
label: { show: true }
},
data: data
}]
}
chart.setOption(option)
return chart
}
6.2 用户管理功能
实现用户分页查询和筛选:
javascript复制// 获取用户列表
async function getUserList(params) {
const { page = 1, pageSize = 10, regionCode, riskLevel } = params
const where = {}
if (regionCode) where.region_code = regionCode
if (riskLevel) {
where.user_id = {
[Op.in]: Sequelize.literal(`(
SELECT user_id FROM health_records
WHERE risk_level = '${riskLevel}'
GROUP BY user_id
)`)
}
}
return User.findAndCountAll({
where,
offset: (page - 1) * pageSize,
limit: pageSize,
include: [{
model: HealthRecord,
as: 'latestRecord',
required: false,
separate: true,
limit: 1,
order: [['report_date', 'DESC']]
}]
})
}
7. 项目部署与运维
7.1 小程序发布流程
- 开发环境配置:
bash复制# 安装依赖
npm install
# 开发环境启动
npm run dev
# 构建生产环境
npm run build
- 小程序审核要点:
- 确保所有表单都有明确的隐私政策提示
- 健康类目需要提供相关资质证明
- 内容审核确保疫情信息准确无误
7.2 服务器部署方案
使用Docker容器化部署:
dockerfile复制# Dockerfile
FROM node:14-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install --production
COPY . .
EXPOSE 3000
CMD ["npm", "start"]
使用docker-compose编排服务:
yaml复制version: '3'
services:
app:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- DB_HOST=mysql
depends_on:
- mysql
- redis
mysql:
image: mysql:8.0
environment:
- MYSQL_ROOT_PASSWORD=yourpassword
- MYSQL_DATABASE=epidemic
volumes:
- mysql_data:/var/lib/mysql
redis:
image: redis:alpine
volumes:
- redis_data:/data
volumes:
mysql_data:
redis_data:
8. 项目总结与反思
这个项目从技术角度实现了预期目标,但在实际推广使用过程中也发现了一些可以改进的地方:
- 用户体验优化:
- 增加健康上报的提醒功能,提高用户依从性
- 优化风险评估模型的准确性,减少误报
- 添加家庭组功能,方便为家人上报健康状态
- 技术架构改进:
- 引入消息队列处理异步任务,提高系统响应速度
- 考虑使用时序数据库存储健康记录,优化时间序列查询
- 实现分布式追踪,方便排查性能瓶颈
- 数据安全增强:
- 实施数据脱敏处理,保护用户隐私
- 增加操作日志审计功能
- 定期进行安全漏洞扫描
这个项目让我深刻体会到,一个好的技术方案不仅要有扎实的技术实现,更需要从用户实际需求出发,在易用性、稳定性和安全性之间找到平衡点。特别是在处理健康数据这类敏感信息时,必须把数据安全和用户隐私放在首位。