- architecture.md: 全面重写,对齐 Node.js+MySQL 技术栈, 新增三个模块(隐患随手拍/施工日志/AI分析)到模块列表和架构图, 更新数据流、租户隔离模型、部署架构、安全设计 - h5.md: 补充 6 个新页面 wireframe(3.7~3.14), 更新页面清单(15个页面),API endpoint 前缀 /api → /v1, 更新已知待确认项为已确认状态 - offline.md: 补充 hazards/construction_logs/ai_analyses 三个 IndexedDB store,更新刷新策略表, 补充 6 种离线操作类型(action 类型表) - SPEC.md: 状态升级为"设计完成",版本升至 v0.2.1, 所有待确认项均已确认(部署地址/推送凭证/OSS路径/JWT/台账)
235 lines
5.9 KiB
Markdown
235 lines
5.9 KiB
Markdown
# 离线数据方案
|
||
|
||
> 状态: 设计中(MVP 阶段可简化)
|
||
|
||
---
|
||
|
||
## 1. 背景
|
||
|
||
工地现场网络环境不稳定,H5 移动端可能出现网络中断。需要保证:
|
||
|
||
1. **已加载数据可继续浏览**(设备列表、预警等)
|
||
2. **网络恢复后数据自动同步**
|
||
3. **离线期间的操作不丢失**
|
||
|
||
---
|
||
|
||
## 2. 离线存储策略
|
||
|
||
### 2.1 存储层级
|
||
|
||
| 层级 | 技术 | 容量 | 适用场景 |
|
||
|------|------|------|----------|
|
||
| Memory | JavaScript 变量 | 无限 | 页面运行期间 |
|
||
| LocalStorage | 浏览器本地存储 | ~5MB | 永久存储(小数据) |
|
||
| IndexedDB | 浏览器索引数据库 | ~50MB+ | 结构化数据存储 |
|
||
|
||
**选型**: 以 **IndexedDB** 为主,LocalStorage 辅助。
|
||
|
||
---
|
||
|
||
## 3. 离线缓存设计
|
||
|
||
### 3.1 IndexedDB 表设计
|
||
|
||
```javascript
|
||
// 数据库: SmartProjectDB
|
||
// 版本: 1
|
||
|
||
// 对象存储 1: devices(设备台账)
|
||
{
|
||
store: 'devices',
|
||
keyPath: 'id',
|
||
indexes: ['type', 'status'],
|
||
data: { id, name, type, model, location, status, last_seen }
|
||
}
|
||
|
||
// 对象存储 2: alerts(预警记录)
|
||
{
|
||
store: 'alerts',
|
||
keyPath: 'id',
|
||
indexes: ['status', 'level', 'created_at'],
|
||
data: { id, device_id, device_name, level, message, metric, value, status, created_at }
|
||
}
|
||
|
||
// 对象存储 3: hazards(隐患随手拍)
|
||
{
|
||
store: 'hazards',
|
||
keyPath: 'id',
|
||
indexes: ['status', 'category', 'severity', 'reported_at'],
|
||
data: { id, category, severity, description, photo_count, status,
|
||
reporter_id, reporter_role, reported_at, assignee_id, resolved_at }
|
||
}
|
||
|
||
// 对象存储 4: construction_logs(施工日志)
|
||
{
|
||
store: 'construction_logs',
|
||
keyPath: 'id',
|
||
indexes: ['date', 'author_id'],
|
||
data: { id, date, part, content, workers, equipment, photo_count,
|
||
author_id, author_role, created_at }
|
||
}
|
||
|
||
// 对象存储 5: ai_analyses(AI 智能分析)
|
||
{
|
||
store: 'ai_analyses',
|
||
keyPath: 'id',
|
||
indexes: ['device_id', 'analysis_type', 'triggered_at'],
|
||
data: { id, device_id, device_name, analysis_type, confidence,
|
||
description, triggered_at }
|
||
}
|
||
|
||
// 对象存储 6: sync_queue(离线操作队列)
|
||
{
|
||
store: 'sync_queue',
|
||
keyPath: 'id',
|
||
autoIncrement: true,
|
||
data: { id, action, payload, created_at, status }
|
||
}
|
||
```
|
||
|
||
### 3.2 缓存更新策略
|
||
|
||
| 数据类型 | 更新频率 | 缓存策略 |
|
||
|----------|----------|----------|
|
||
| 设备列表 | 每 5 分钟 | 后台静默更新 |
|
||
| 设备详情 | 每 30 秒 | 页面打开时拉取 + 定时刷新 |
|
||
| 预警列表 | 每 1 分钟 | 后台静默更新 + 新预警推送 |
|
||
| 隐患列表 | 每 2 分钟 | 后台静默更新 |
|
||
| 施工日志列表 | 每 5 分钟 | 后台静默更新 |
|
||
| AI 分析列表 | 每 5 分钟 | 后台静默更新 |
|
||
| 隐患详情 | 实时 | 打开时拉取 |
|
||
| 日志详情 | 实时 | 打开时拉取 |
|
||
| AI 分析详情 | 实时 | 打开时拉取 |
|
||
|
||
**更新流程**:
|
||
```
|
||
用户打开页面
|
||
│
|
||
├─ 有网络 → API 请求 → 更新 IndexedDB → 渲染
|
||
│
|
||
└─ 无网络 → 读取 IndexedDB → 渲染(显示"离线模式")
|
||
```
|
||
|
||
---
|
||
|
||
## 4. 离线操作队列
|
||
|
||
### 4.1 场景
|
||
|
||
用户在离线状态下执行操作(如处理预警、提交隐患、处理日志),操作记录存入 `sync_queue`,网络恢复后自动同步。
|
||
|
||
### 4.2 支持的离线操作类型
|
||
|
||
| action | 说明 | 对应 API |
|
||
|--------|------|----------|
|
||
| `handle_alert` | 处理预警 | POST /v1/alerts/:id/handle |
|
||
| `ignore_alert` | 忽略预警 | POST /v1/alerts/:id/ignore |
|
||
| `create_hazard` | 上报隐患 | POST /v1/hazards |
|
||
| `assign_hazard` | 认领隐患 | POST /v1/hazards/:id/assign |
|
||
| `resolve_hazard` | 处理完成 | POST /v1/hazards/:id/resolve |
|
||
| `create_log` | 新建日志 | POST /v1/logs |
|
||
|
||
### 4.3 同步流程
|
||
|
||
```
|
||
检测到网络恢复(navigator.onLine 事件)
|
||
│
|
||
▼
|
||
读取 sync_queue(status: pending)
|
||
│
|
||
▼
|
||
逐条执行 API 请求
|
||
│
|
||
├─ 成功 → 删除队列记录,更新本地数据
|
||
│
|
||
└─ 失败 → 重试3次,仍失败标记为 failed,用户手动处理
|
||
```
|
||
|
||
### 4.3 队列记录格式
|
||
|
||
```javascript
|
||
{
|
||
id: 1,
|
||
action: 'handle_alert',
|
||
payload: {
|
||
alert_id: 'alert_001',
|
||
action: 'handled',
|
||
note: '已现场确认'
|
||
},
|
||
created_at: '2026-04-14T10:00:00Z',
|
||
status: 'pending', // pending / syncing / failed
|
||
retry_count: 0
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 5. Service Worker
|
||
|
||
### 5.1 职责
|
||
|
||
- 拦截 H5 页面的 HTTP 请求
|
||
- 实现缓存策略(静态资源优先缓存,网络优先等)
|
||
- 离线时返回缓存的页面
|
||
|
||
### 5.2 缓存策略
|
||
|
||
| 资源类型 | 缓存策略 | 说明 |
|
||
|----------|----------|------|
|
||
| HTML | Network First | 始终尝试获取最新 |
|
||
| CSS/JS | Cache First | 优先使用缓存,性能优先 |
|
||
| API 数据 | Network Only | 实时性要求高,不缓存 |
|
||
| 图标/字体 | Cache First | 长期不变 |
|
||
|
||
### 5.3 Service Worker 注册
|
||
|
||
```javascript
|
||
// main.js
|
||
if ('serviceWorker' in navigator) {
|
||
navigator.serviceWorker.register('/sw.js')
|
||
.then(reg => console.log('SW registered'))
|
||
.catch(err => console.error('SW registration failed:', err));
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 6. 网络状态提示
|
||
|
||
页面监听网络状态,给用户明确反馈:
|
||
|
||
```javascript
|
||
// 监听网络状态
|
||
window.addEventListener('online', () => {
|
||
showToast('网络已恢复,正在同步...');
|
||
syncPendingOperations();
|
||
});
|
||
|
||
window.addEventListener('offline', () => {
|
||
showToast('网络已断开,显示离线数据');
|
||
});
|
||
```
|
||
|
||
---
|
||
|
||
## 7. 简化方案(MVP)
|
||
|
||
MVP 阶段可降低离线复杂度:
|
||
|
||
| 方案 | 说明 |
|
||
|------|------|
|
||
| 简单缓存 | 仅在 LocalStorage 缓存用户信息 + 最后设备列表,H5 页面可离线展示 |
|
||
| 无离线操作 | 离线期间禁用操作按钮,提示"网络异常" |
|
||
| 手动刷新 | 网络恢复后用户下拉刷新 |
|
||
|
||
**后续迭代再实现完整离线能力**。
|
||
|
||
---
|
||
|
||
## 8. 待确认
|
||
|
||
- [ ] 是否需要 PWA(可安装到桌面/主屏幕)
|
||
- [ ] IndexedDB 库选型(idb / Dexie.js 还是原生)
|
||
- [ ] 离线数据保留时长策略
|