应急演练系统 - 数据存储与认证方案
一、当前系统现状
现状分析
- 数据存储:使用浏览器 localStorage,数据保存在用户本地
- 认证机制:无认证,任何人扫码即可使用
- 数据共享:无法多人协同,数据无法汇总
- 数据安全:清除浏览器缓存即丢失数据
二、数据存储方案设计
方案一:云端数据库存储(推荐)
技术架构
┌─────────────┐
│ 手机端H5 │ ──扫码登录──> ┌──────────────┐
│ (前端) │ │ 后端API服务 │
└─────────────┘ │ (Node.js/ │
│ Python) │
│ └──────────────┘
│ │
│ HTTPS请求 │
│ │
▼ ▼
┌─────────────┐ ┌──────────────┐
│ 云存储OSS │ │ 云数据库 │
│ (图片/音频) │ │ (MySQL/ │
└─────────────┘ │ MongoDB) │
└──────────────┘
数据库设计
-- 演练基本信息表
CREATE TABLE drills (
id INT PRIMARY KEY AUTO_INCREMENT,
drill_name VARCHAR(200),
drill_type VARCHAR(50),
location VARCHAR(200),
gps_lat DECIMAL(10,6),
gps_lng DECIMAL(10,6),
start_time DATETIME,
end_time DATETIME,
status VARCHAR(20),
created_by INT,
created_at TIMESTAMP
);
-- 参演队伍表
CREATE TABLE teams (
id INT PRIMARY KEY AUTO_INCREMENT,
drill_id INT,
team_name VARCHAR(100),
team_type VARCHAR(50),
team_size INT,
equipment TEXT,
arrival_time DATETIME,
FOREIGN KEY (drill_id) REFERENCES drills(id)
);
-- 现场采集记录表
CREATE TABLE field_records (
id INT PRIMARY KEY AUTO_INCREMENT,
drill_id INT,
record_type VARCHAR(50),
content TEXT,
voice_url VARCHAR(500),
photos JSON,
recorder_id INT,
record_time DATETIME,
FOREIGN KEY (drill_id) REFERENCES drills(id)
);
-- 专家点评表
CREATE TABLE expert_reviews (
id INT PRIMARY KEY AUTO_INCREMENT,
drill_id INT,
expert_id INT,
rating VARCHAR(20),
comments TEXT,
suggestions TEXT,
review_time DATETIME,
FOREIGN KEY (drill_id) REFERENCES drills(id)
);
-- 用户表
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50),
phone VARCHAR(20),
role VARCHAR(20),
unit VARCHAR(100),
created_at TIMESTAMP
);
✓ 优点
- 数据集中管理,永久保存
- 支持多人协同采集
- 实时数据同步
- 便于统计分析
- 支持数据导出
⚠ 注意事项
- 需要服务器和域名
- 需要开发后端API
- 依赖网络连接
- 需要运维维护
方案二:混合存储(本地+云端)
工作原理
- 在线模式:数据实时上传到云端
- 离线模式:数据暂存本地 localStorage
- 自动同步:网络恢复后自动上传本地数据
- 冲突处理:以服务器时间戳为准
// 混合存储示例代码
class DataSync {
async saveRecord(data) {
// 先保存到本地
this.saveToLocal(data);
// 尝试上传到云端
if (navigator.onLine) {
try {
await this.uploadToCloud(data);
this.markAsSynced(data.id);
} catch (error) {
console.log('离线模式,稍后同步');
}
}
}
async syncPendingData() {
const pending = this.getUnsyncedData();
for (let data of pending) {
await this.uploadToCloud(data);
this.markAsSynced(data.id);
}
}
}
// 监听网络状态
window.addEventListener('online', () => {
dataSync.syncPendingData();
});
✓ 优点
- 支持离线使用
- 数据不丢失
- 用户体验好
- 适合网络不稳定场景
⚠ 注意事项
- 需要处理同步冲突
- 本地存储有容量限制
- 实现复杂度较高
方案三:轻量级方案(腾讯云开发/Firebase)
使用云开发服务
- 腾讯云开发:微信小程序云开发,无需后端
- 阿里云 Serverless:函数计算 + 表格存储
- Firebase:Google 提供的 BaaS 服务
// 腾讯云开发示例
const db = wx.cloud.database();
// 保存采集记录
async function saveRecord(data) {
return await db.collection('drill_records').add({
data: {
...data,
createTime: new Date()
}
});
}
// 查询记录
async function getRecords(drillId) {
return await db.collection('drill_records')
.where({ drillId })
.orderBy('createTime', 'desc')
.get();
}
三、认证方案设计
方案一:手机号验证码登录(推荐)
流程设计
- 用户扫码进入系统
- 输入手机号,点击"获取验证码"
- 收到短信验证码,输入验证
- 验证通过,生成 JWT Token
- 后续请求携带 Token 访问
// 登录流程示例
// 1. 发送验证码
POST /api/auth/send-code
{
"phone": "13800138000"
}
// 2. 验证登录
POST /api/auth/login
{
"phone": "13800138000",
"code": "123456"
}
// 返回
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"id": 1,
"phone": "13800138000",
"role": "collector",
"name": "张三"
}
}
// 3. 后续请求携带 Token
GET /api/drills/123
Headers: {
"Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
方案二:扫码自动登录
流程设计
- 管理员创建演练,生成专属二维码
- 二维码包含:演练ID + 临时Token + 角色信息
- 用户扫码自动登录,无需输入账号密码
- Token 有效期:演练期间有效
// 二维码内容示例
https://drill.example.com/join?
drillId=12345&
token=abc123def456&
role=collector&
expires=1737590400
// 扫码后自动登录
GET /api/auth/qrcode-login?token=abc123def456
// 返回用户信息
{
"drillId": 12345,
"role": "collector",
"permissions": ["record", "photo", "voice"]
}
方案三:微信授权登录
流程设计
- 用户扫码进入微信小程序
- 点击"微信授权登录"
- 获取微信 openid 作为唯一标识
- 首次登录补充手机号和姓名
// 微信授权登录
wx.login({
success: (res) => {
// 发送 code 到后端
fetch('/api/auth/wechat-login', {
method: 'POST',
body: JSON.stringify({ code: res.code })
});
}
});
// 后端换取 openid
const result = await axios.get(
`https://api.weixin.qq.com/sns/jscode2session?
appid=${appId}&
secret=${appSecret}&
js_code=${code}&
grant_type=authorization_code`
);
// 返回 openid,作为用户唯一标识
✓ 优点
- 微信生态内流畅
- 无需额外注册
- 用户信任度高
- 可获取用户头像昵称
四、权限管理设计
| 角色 |
权限 |
说明 |
| 系统管理员 |
全部权限 |
创建演练、分配角色、查看所有数据、导出报告 |
| 演练指挥员 |
查看、导出 |
实时查看演练数据、导出演练报告 |
| 信息采集员 |
录入、查看 |
录入现场信息、上传照片、查看自己的记录 |
| 专家评审员 |
查看、点评 |
查看演练数据、提交专家点评意见 |
| 参演人员 |
仅查看 |
查看演练基本信息和自己队伍的信息 |
// 权限控制中间件
function checkPermission(requiredRole) {
return (req, res, next) => {
const user = req.user;
const roleLevel = {
'admin': 5,
'commander': 4,
'collector': 3,
'expert': 3,
'participant': 1
};
if (roleLevel[user.role] >= roleLevel[requiredRole]) {
next();
} else {
res.status(403).json({ error: '权限不足' });
}
};
}
// 使用示例
app.post('/api/drills',
authenticate,
checkPermission('admin'),
createDrill
);
五、推荐方案
🎯 综合推荐方案
数据存储:混合存储(本地+云端)
- 云端数据库:阿里云 RDS MySQL / 腾讯云 MySQL
- 文件存储:阿里云 OSS / 腾讯云 COS
- 本地缓存:localStorage + IndexedDB
- 同步策略:在线实时上传,离线自动缓存
认证方案:手机号验证码 + 扫码快捷登录
- 首次登录:手机号验证码,建立账号
- 后续使用:扫演练专属二维码,自动登录
- Token 管理:JWT Token,7天有效期
- 安全加固:HTTPS + Token 刷新机制
技术栈建议
- 前端:微信小程序 / H5(Vue.js)
- 后端:Node.js (Express) / Python (Flask)
- 数据库:MySQL + Redis(缓存)
- 云服务:阿里云 / 腾讯云
- 短信服务:阿里云短信 / 腾讯云短信
成本估算(按月)
- 云服务器(2核4G):约 100-200 元/月
- 云数据库(1核2G):约 50-100 元/月
- 对象存储(100GB):约 10-20 元/月
- 短信服务(1000条):约 30-50 元/月
- 总计:约 200-400 元/月
六、实施步骤
第一阶段:基础功能(2周)
- 搭建后端 API 服务
- 实现手机号验证码登录
- 完成数据库设计和创建
- 前端对接后端 API
第二阶段:核心功能(2周)
- 实现扫码快捷登录
- 完成离线缓存和同步
- 实现文件上传(图片、音频)
- 完成权限控制
第三阶段:优化完善(1周)
- 性能优化和压力测试
- 安全加固(SQL注入、XSS防护)
- 用户体验优化
- 部署上线
七、安全建议
- 数据传输:全站 HTTPS 加密
- 数据存储:敏感信息加密存储
- 防刷机制:验证码 60秒限制,IP 限流
- Token 安全:定期刷新,异常登录检测
- SQL 注入:使用参数化查询
- XSS 防护:输入过滤,输出转义
- 数据备份:每日自动备份数据库
- 日志审计:记录关键操作日志