From 86777f585ebb72f87a3612eb68a29609f758d0c7 Mon Sep 17 00:00:00 2001 From: Jesxion Date: Tue, 14 Apr 2026 11:25:17 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=88=9D=E5=A7=8B=E5=8C=96=E8=AE=BE?= =?UTF-8?q?=E8=AE=A1=E6=96=87=E6=A1=A3=E8=8D=89=E7=A8=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - SPEC.md: 项目概览与文档索引 - docs/architecture.md: 系统架构设计 - docs/api.md: 后台 API 接口设计 - docs/database.md: 数据库表结构设计 - docs/h5.md: H5 页面结构与交互设计 - docs/offline.md: 离线数据方案 状态: 设计中,待设备API协议确认后细化 --- SPEC.md | 48 +++++++ docs/api.md | 294 ++++++++++++++++++++++++++++++++++++++++++ docs/architecture.md | 139 ++++++++++++++++++++ docs/database.md | 194 ++++++++++++++++++++++++++++ docs/h5.md | 299 +++++++++++++++++++++++++++++++++++++++++++ docs/offline.md | 191 +++++++++++++++++++++++++++ 6 files changed, 1165 insertions(+) create mode 100644 SPEC.md create mode 100644 docs/api.md create mode 100644 docs/architecture.md create mode 100644 docs/database.md create mode 100644 docs/h5.md create mode 100644 docs/offline.md diff --git a/SPEC.md b/SPEC.md new file mode 100644 index 0000000..9192641 --- /dev/null +++ b/SPEC.md @@ -0,0 +1,48 @@ +# 郑州智慧工地管理系统 - 产品设计规格书 + +> 版本: v0.1.0 draft +> 状态: 设计中 +> 仓库: https://git.jesxion.com/jesxion/smart-project + +--- + +## 文档索引 + +| 文档 | 说明 | +|------|------| +| [architecture.md](./architecture.md) | 系统架构设计 | +| [api.md](./api.md) | 后台 API 接口设计 | +| [database.md](./database.md) | 数据库表结构设计 | +| [h5.md](./h5.md) | H5 页面结构与交互设计 | +| [offline.md](./offline.md) | 离线数据方案 | + +--- + +## 项目概述 + +### 背景 + +郑州智慧工地项目面向施工现场安全管理的数字化升级需求,提供塔吊、升降机等特种设备的实时监测与预警功能。 + +### 核心功能 + +- **设备监控**:塔吊、升降机实时数据接入(来自已有 API) +- **预警管理**:设备异常实时推送与记录 +- **H5 移动端**:移动端随时查看设备状态、接收预警 +- **数据持久化**:监测数据与预警记录云端存储 + +### 技术栈 + +| 层级 | 技术选型 | +|------|----------| +| 后台 API | Python / FastAPI(或 Flask) | +| H5 前端 | 原生 HTML/CSS/JS,无框架依赖 | +| 数据库 | PostgreSQL / SQLite(MVP 阶段) | +| 文件存储 | 阿里云 OSS | +| 设备数据 | 已有第三方 API(塔吊/升降机) | + +### 文档更新记录 + +| 日期 | 版本 | 更新内容 | +|------|------|----------| +| 2026-04-14 | v0.1.0 | 初始化草稿,架构设计 | diff --git a/docs/api.md b/docs/api.md new file mode 100644 index 0000000..a3f0f1f --- /dev/null +++ b/docs/api.md @@ -0,0 +1,294 @@ +# 后台 API 接口设计 + +> 状态: 设计中(待设备 API 协议确认后细化) + +--- + +## 1. API 概览 + +- **Base URL**: `https://api.example.com/v1` +- **认证**: `Authorization: Bearer ` +- **数据格式**: JSON +- **字符编码**: UTF-8 + +--- + +## 2. 认证接口 + +### 2.1 登录 + +``` +POST /auth/login +``` + +**请求体**: +```json +{ + "username": "string", + "password": "string" +} +``` + +**响应** (200): +```json +{ + "token": "eyJhbGciOiJIUzI1NiIs...", + "expires_at": "2026-04-15T11:00:00Z", + "user": { + "id": 1, + "username": "admin", + "role": "admin" + } +} +``` + +--- + +## 3. 设备接口 + +### 3.1 获取设备台账列表 + +``` +GET /devices +``` + +**Query 参数**: +| 参数 | 类型 | 说明 | +|------|------|------| +| type | string | 设备类型: `tower_crane` / `elevator` / 空(全部) | +| status | string | 在线状态: `online` / `offline` / 空(全部) | +| page | int | 页码,默认 1 | +| page_size | int | 每页数量,默认 20 | + +**响应** (200): +```json +{ + "total": 100, + "page": 1, + "page_size": 20, + "items": [ + { + "id": "device_001", + "name": "1号塔吊", + "type": "tower_crane", + "model": "QTZ500", + "location": "A区施工现场", + "status": "online", + "last_seen": "2026-04-14T10:30:00Z", + "install_date": "2026-01-15" + } + ] +} +``` + +### 3.2 获取设备实时数据 + +``` +GET /devices/{device_id}/realtime +``` + +**响应** (200): +```json +{ + "device_id": "device_001", + "timestamp": "2026-04-14T10:30:00Z", + "data": { + // 塔吊 + "load": 45.2, // 当前载重 (kN) + "range": 30.5, // 回转幅度 (m) + "height": 85.0, // 起升高度 (m) + "wind_speed": 5.2, // 风速 (m/s) + "torque": 320.5, // 力矩 (kN·m) + "angle": 120.5, // 回转角度 (°) + // 升降机 + "speed": 1.2, // 升降速度 (m/s) + "floor": 12, // 当前楼层 + "door_status": "closed" + } +} +``` + +### 3.3 获取设备历史数据 + +``` +GET /devices/{device_id}/history +``` + +**Query 参数**: +| 参数 | 类型 | 说明 | +|------|------|------| +| start | datetime | 开始时间 ISO8601 | +| end | datetime | 结束时间 ISO8601 | +| metric | string | 指标字段名(可选,默认全量) | +| page | int | 页码 | +| page_size | int | 每页数量,默认 100 | + +**响应** (200): +```json +{ + "device_id": "device_001", + "total": 1000, + "items": [ + { + "timestamp": "2026-04-14T10:00:00Z", + "load": 44.8, + "range": 30.2, + "height": 84.8 + } + ] +} +``` + +--- + +## 4. 预警接口 + +### 4.1 获取预警列表 + +``` +GET /alerts +``` + +**Query 参数**: +| 参数 | 类型 | 说明 | +|------|------|------| +| device_id | string | 设备ID(可选) | +| level | string | 预警级别: `warning` / `danger` / 空(全部) | +| status | string | 处理状态: `unread` / `handled` / `ignored` / 空(全部) | +| page | int | 页码 | +| page_size | int | 每页数量,默认 20 | + +**响应** (200): +```json +{ + "total": 50, + "unread_count": 3, + "items": [ + { + "id": "alert_001", + "device_id": "device_001", + "device_name": "1号塔吊", + "level": "danger", + "message": "载重超限: 当前45.2kN,超过额定值40kN", + "metric": "load", + "value": 45.2, + "threshold": 40.0, + "created_at": "2026-04-14T10:25:00Z", + "status": "unread" + } + ] +} +``` + +### 4.2 获取预警详情 + +``` +GET /alerts/{alert_id} +``` + +### 4.3 处理预警 + +``` +POST /alerts/{alert_id}/handle +``` + +**请求体**: +```json +{ + "action": "handled", + "note": "已现场确认,正常作业" +} +``` + +### 4.4 忽略预警 + +``` +POST /alerts/{alert_id}/ignore +``` + +--- + +## 5. OSS 文件接口 + +### 5.1 获取上传凭证(预签名 URL) + +``` +POST /oss/upload-token +``` + +**请求体**: +```json +{ + "filename": "report_2026_04.pdf", + "content_type": "application/pdf" +} +``` + +**响应** (200): +```json +{ + "upload_url": "https://bucket.oss-cn-beijing.aliyuncs.com/...", + "object_key": "reports/2026/04/report_xxx.pdf", + "expires_at": "2026-04-14T11:00:00Z" +} +``` + +### 5.2 获取文件下载链接 + +``` +GET /oss/download-url +``` + +**Query 参数**: +| 参数 | 类型 | 说明 | +|------|------|------| +| object_key | string | OSS 对象路径 | + +**响应** (200): +```json +{ + "download_url": "https://bucket.oss-cn-beijing.aliyuncs.com/...?Signature=...", + "expires_at": "2026-04-14T12:00:00Z" +} +``` + +--- + +## 6. 通用响应格式 + +**成功**: +```json +{ + "code": 0, + "message": "success", + "data": {} +} +``` + +**错误**: +```json +{ + "code": 1001, + "message": "设备不存在", + "detail": "device_id: device_999 不在系统中" +} +``` + +**HTTP 状态码**: +| 状态码 | 说明 | +|--------|------| +| 200 | 成功 | +| 400 | 参数错误 | +| 401 | 未认证 | +| 403 | 无权限 | +| 404 | 资源不存在 | +| 500 | 服务器内部错误 | + +--- + +## 7. 待确认 + +- [ ] 设备 API 协议格式(塔吊/升降机数据字段) +- [ ] JWT Secret 如何管理 +- [ ] 预警推送机制(轮询 vs WebSocket) +- [ ] OSS bucket 名称和目录结构 diff --git a/docs/architecture.md b/docs/architecture.md new file mode 100644 index 0000000..ae52645 --- /dev/null +++ b/docs/architecture.md @@ -0,0 +1,139 @@ +# 系统架构设计 + +> 状态: 设计中 + +--- + +## 1. 系统架构图 + +``` + ┌─────────────────────────────────────────┐ + │ 阿里云 OSS │ + │ (文件存储: 证书/报告/日志) │ + └───────────────┬─────────────────────────┘ + │ upload + ▼ +┌──────────┐ ┌─────────────────────────┐ ┌──────────────┐ +│ 已有API │───▶│ 后台 API 服务 │◀───│ H5 客户端 │ +│ (塔吊/ │ │ Python / FastAPI │ │ (移动端浏览器)│ +│ 升降机) │ │ │ │ │ +└──────────┘ │ ┌───────────────────┐ │ └──────────────┘ + │ │ 设备数据接入层 │ │ ▲ + │ │ 预警引擎 │ │ │ polling / websocket + │ │ OSS 文件管理 │ │ + │ │ REST API │ │ + │ └───────────────────┘ │ │ + └────────────┬────────────┘ │ + │ │ + ▼ │ + ┌─────────────────────────┐ │ + │ PostgreSQL │ │ + │ (设备台账/预警记录/ │◀────────────┘ + │ 用户/OSS文件索引) │ + └─────────────────────────┘ +``` + +--- + +## 2. 模块划分 + +### 2.1 后台 API 服务 + +**职责**:数据聚合层,统一对接已有设备 API,屏蔽异构数据源差异,对 H5 提供标准化 REST API。 + +| 模块 | 说明 | +|------|------| +| `device_adapter` | 设备 API 适配器:塔吊协议解析、升降机协议解析 | +| `monitor` | 设备状态监控:定时轮询已有 API,写入本地 DB | +| `alert_engine` | 预警引擎:阈值判断、预警生成、通知分发 | +| `file_mgr` | OSS 文件管理:上传、下载、索引 | +| `api_routes` | REST API 路由:设备台账、实时数据、历史查询、预警、OSS | + +### 2.2 H5 客户端 + +**职责**:移动端展示与操作界面,基于响应式 H5 开发,适配手机浏览器。 + +| 模块 | 说明 | +|------|------| +| `dashboard` | 首页仪表盘:设备总数、在线/离线、告警统计 | +| `device_list` | 设备列表:塔吊/升降机分类展示 | +| `device_detail` | 设备详情:实时数据面板、历史曲线 | +| `alert_list` | 预警列表:未读/已处理筛选 | +| `alert_detail` | 预警详情:处理/忽略操作 | +| `profile` | 个人中心:账号信息、通知设置 | + +--- + +## 3. 数据流向 + +### 3.1 设备数据采集 + +``` +已有设备 API + │ (定时轮询: 每 30s 或设备主动推送) + ▼ +device_adapter (协议解析) + │ + ▼ +monitor (写入 DB + 触发预警判断) + │ + ├──────────────────┐ + ▼ ▼ +PostgreSQL alert_engine +(设备状态表) (阈值判断) + │ + ▼ + alert_records (预警记录表) + │ + ▼ + 通知分发 (站内/OSS记录) +``` + +### 3.2 H5 数据请求 + +``` +H5 浏览器 + │ GET /api/devices + │ GET /api/devices/{id}/realtime + │ GET /api/alerts + ▼ +api_routes (FastAPI) + │ + ├──────────────┐ + ▼ ▼ +PostgreSQL OSS +(结构化数据) (文件URL) +``` + +--- + +## 4. 部署架构 + +MVP 阶段采用轻量部署: + +| 组件 | 部署方式 | +|------|----------| +| 后台 API | 阿里云函数计算(FC)或轻量服务器 | +| PostgreSQL | 阿里云 RDS 或轻量服务器自建 | +| OSS | 阿里云 OSS 标准存储 | + +--- + +## 5. 安全设计 + +| 措施 | 说明 | +|------|------| +| HTTPS | 全链路 HTTPS,证书由阿里云管理 | +| Token 认证 | H5 API 请求携带 JWT Token | +| CORS | 限制允许的 H5 域名 | +| OSS 鉴权 | H5 通过后台签发临时 URL 访问 OSS 文件 | +| 输入校验 | FastAPI Pydantic 模型全量参数校验 | + +--- + +## 6. 待细化 + +- [ ] 设备 API 协议细节(目前尚未获取,需跟进沟通) +- [ ] 预警阈值配置方案(管理员界面 or 配置文件) +- [ ] 实时通知方案(WebSocket / SSE / 轮询) +- [ ] 多租户隔离方案(目前 MVP 单租户设计) diff --git a/docs/database.md b/docs/database.md new file mode 100644 index 0000000..249813c --- /dev/null +++ b/docs/database.md @@ -0,0 +1,194 @@ +# 数据库表结构设计 + +> 状态: 设计中(MVP 版本,PostgreSQL) + +--- + +## 1. ER 图概述 + +``` +users ─────────┐ + │ 1:N + ▼ + user_device_access (N:M) + │ + ▼ +devices ───────┤ + │ + ├──── 1:N ──── device_realtime (最新状态) + │ + ├──── 1:N ──── device_history (历史数据) + │ + └──── 1:N ──── alert_records (预警记录) + +alert_records ────── N:1 ──── users (处理人) + +oss_files ──────────────────────────────────────────────────┐ + │ + (其他模块按需关联) │ +``` + +--- + +## 2. 表结构 + +### 2.1 users(用户表) + +| 字段 | 类型 | 约束 | 说明 | +|------|------|------|------| +| id | SERIAL | PRIMARY KEY | 自增ID | +| username | VARCHAR(64) | UNIQUE NOT NULL | 用户名 | +| password_hash | VARCHAR(256) | NOT NULL | bcrypt 密码哈希 | +| role | VARCHAR(32) | NOT NULL DEFAULT 'viewer' | 角色: admin / operator / viewer | +| real_name | VARCHAR(128) | | 真实姓名 | +| phone | VARCHAR(32) | | 手机号 | +| is_active | BOOLEAN | DEFAULT true | 是否启用 | +| created_at | TIMESTAMP | DEFAULT NOW() | 创建时间 | +| updated_at | TIMESTAMP | DEFAULT NOW() | 更新时间 | + +**索引**: +- `idx_users_username` ON (`username`) + +--- + +### 2.2 devices(设备台账表) + +| 字段 | 类型 | 约束 | 说明 | +|------|------|------|------| +| id | VARCHAR(64) | PRIMARY KEY | 设备ID(对接已有API的设备编号) | +| name | VARCHAR(128) | NOT NULL | 设备名称,如 "1号塔吊" | +| type | VARCHAR(32) | NOT NULL | 类型: `tower_crane` / `elevator` | +| model | VARCHAR(128) | | 设备型号,如 "QTZ500" | +| manufacturer | VARCHAR(128) | | 制造商 | +| location | VARCHAR(256) | | 安装位置,如 "A区施工现场" | +| install_date | DATE | | 安装日期 | +| status | VARCHAR(32) | DEFAULT 'offline' | 在线状态: online / offline | +| last_seen | TIMESTAMP | | 最后在线时间 | +| config | JSONB | DEFAULT '{}' | 设备配置(预警阈值等) | +| created_at | TIMESTAMP | DEFAULT NOW() | 创建时间 | +| updated_at | TIMESTAMP | DEFAULT NOW() | 更新时间 | + +**索引**: +- `idx_devices_type` ON (`type`) +- `idx_devices_status` ON (`status`) + +--- + +### 2.3 device_realtime(设备实时状态) + +| 字段 | 类型 | 约束 | 说明 | +|------|------|------|------| +| id | SERIAL | PRIMARY KEY | 自增ID | +| device_id | VARCHAR(64) | FOREIGN KEY → devices(id) | 设备ID | +| timestamp | TIMESTAMP | NOT NULL | 数据时间戳 | +| raw_data | JSONB | NOT NULL | 原始数据快照 | +| parsed_data | JSONB | NOT NULL | 解析后的结构化数据 | +| created_at | TIMESTAMP | DEFAULT NOW() | 写入时间 | + +**索引**: +- `idx_realtime_device_id` ON (`device_id`) +- `idx_realtime_timestamp` ON (`timestamp` DESC) + +> 每次设备数据更新时,UPSERT 写入此表,仅保留最新一条记录。 + +--- + +### 2.4 device_history(设备历史数据) + +| 字段 | 类型 | 约束 | 说明 | +|------|------|------|------| +| id | BIGSERIAL | PRIMARY KEY | 自增ID | +| device_id | VARCHAR(64) | FOREIGN KEY → devices(id) | 设备ID | +| timestamp | TIMESTAMP | NOT NULL | 数据时间戳 | +| metric_name | VARCHAR(64) | NOT NULL | 指标名: load / range / height 等 | +| metric_value | DECIMAL(18,4) | NOT NULL | 指标值 | +| unit | VARCHAR(32) | | 单位: kN / m / m/s 等 | +| created_at | TIMESTAMP | DEFAULT NOW() | 写入时间 | + +**索引**: +- `idx_history_device_time` ON (`device_id`, `timestamp` DESC) +- `idx_history_metric` ON (`metric_name`) +- **分区**: 按月分区(`timestamp`),按设备ID + 时间范围查询 + +> 为节省存储空间,历史数据可定期归档到 OSS(冷存储),DB 仅保留近3个月数据。 + +--- + +### 2.5 alert_records(预警记录表) + +| 字段 | 类型 | 约束 | 说明 | +|------|------|------|------| +| id | VARCHAR(64) | PRIMARY KEY | 预警ID(UUID) | +| device_id | VARCHAR(64) | FOREIGN KEY → devices(id) | 设备ID | +| device_name | VARCHAR(128) | | 冗余存储,查询方便 | +| level | VARCHAR(32) | NOT NULL | 级别: warning / danger | +| metric | VARCHAR(64) | NOT NULL | 触发指标: load / wind_speed 等 | +| message | VARCHAR(512) | NOT NULL | 预警消息 | +| value | DECIMAL(18,4) | NOT NULL | 触发值 | +| threshold | DECIMAL(18,4) | NOT NULL | 阈值 | +| status | VARCHAR(32) | DEFAULT 'unread' | 状态: unread / handled / ignored | +| handled_by | INTEGER | FOREIGN KEY → users(id) | 处理人 | +| handle_note | TEXT | | 处理备注 | +| created_at | TIMESTAMP | DEFAULT NOW() | 创建时间 | +| handled_at | TIMESTAMP | | 处理时间 | + +**索引**: +- `idx_alerts_device` ON (`device_id`) +- `idx_alerts_status` ON (`status`) +- `idx_alerts_level` ON (`level`) +- `idx_alerts_created` ON (`created_at` DESC) + +--- + +### 2.6 oss_files(OSS 文件索引表) + +| 字段 | 类型 | 约束 | 说明 | +|------|------|------|------| +| id | SERIAL | PRIMARY KEY | 自增ID | +| object_key | VARCHAR(512) | UNIQUE NOT NULL | OSS 对象路径 | +| filename | VARCHAR(256) | NOT NULL | 原始文件名 | +| content_type | VARCHAR(128) | | MIME 类型 | +| size | BIGINT | | 文件大小(字节) | +| category | VARCHAR(64) | | 分类: report / certificate / log | +| uploaded_by | INTEGER | FOREIGN KEY → users(id) | 上传人 | +| uploaded_at | TIMESTAMP | DEFAULT NOW() | 上传时间 | +| expires_at | TIMESTAMP | | 过期时间(临时文件) | + +**索引**: +- `idx_oss_category` ON (`category`) +- `idx_oss_uploaded_by` ON (`uploaded_by`) + +--- + +## 3. 初始数据 + +### 3.1 超级管理员 + +| username | password | role | +|----------|----------|------| +| admin | (首次部署时设置) | admin | + +--- + +## 4. 迁移工具 + +使用 **Alembic** 管理数据库迁移: + +```bash +# 初始化 +alembic init alembic + +# 生成迁移脚本 +alembic revision --autogenerate -m "init schema" + +# 执行迁移 +alembic upgrade head +``` + +--- + +## 5. 待确认 + +- [ ] 设备历史数据保留策略(多久归档到 OSS) +- [ ] 多租户隔离方案(MVP 单租户,后续扩展) +- [ ] 预警阈值配置(存 DB 还是配置文件) diff --git a/docs/h5.md b/docs/h5.md new file mode 100644 index 0000000..cc288dd --- /dev/null +++ b/docs/h5.md @@ -0,0 +1,299 @@ +# H5 页面结构与交互设计 + +> 状态: 设计中 + +--- + +## 1. 技术选型 + +| 项目 | 选型 | +|------|------| +| 页面渲染 | 原生 HTML5 + CSS3 + Vanilla JS | +| UI 框架 | 无,响应式布局手工实现 | +| 图表 | ECharts(CDN 引入) | +| 字体图标 | 阿里巴巴矢量图标库(iconfont) | +| 构建 | 无构建步骤,单 HTML 文件按模块拆分 | + +**设计原则**: +- 移动端优先(适配 375px ~ 414px 宽度) +- 低依赖,不依赖任何 JS 框架 +- 离线可缓存核心资产(Service Worker) + +--- + +## 2. 页面清单 + +| 页面 | 路由 | 说明 | +|------|------|------| +| 登录 | `/login.html` | 账号密码登录 | +| 首页仪表盘 | `/index.html` | 设备统计、预警统计、快捷入口 | +| 设备列表 | `/devices.html` | 塔吊/升降机分类列表 | +| 设备详情 | `/device.html?id=xxx` | 实时数据 + 历史曲线 | +| 预警列表 | `/alerts.html` | 预警推送列表 | +| 预警详情 | `/alert.html?id=xxx` | 预警详情 + 处理操作 | +| 个人中心 | `/profile.html` | 个人信息、设置 | + +--- + +## 3. 页面结构 + +### 3.1 首页仪表盘 `/index.html` + +``` +┌──────────────────────────────────────┐ +│ ☰ 郑州智慧工地 [👤 个人中心] │ ← 顶栏 +├──────────────────────────────────────┤ +│ │ +│ ┌────────────┐ ┌────────────┐ │ +│ │ 塔吊 │ │ 升降机 │ │ ← 设备数量卡片 +│ │ 12 台 │ │ 8 台 │ │ +│ │ 12 在线 │ │ 8 在线 │ │ +│ └────────────┘ └────────────┘ │ +│ │ +│ ┌──────────────────────────────┐ │ +│ │ 今日预警 │ │ ← 预警统计卡片 +│ │ 危险 2 警告 5 │ │ +│ └──────────────────────────────┘ │ +│ │ +│ 最新预警 │ +│ ┌──────────────────────────────┐ │ +│ │ 🔴 1号塔吊 载重超限 │ │ ← 预警列表(最新5条) +│ │ 10:25 │ │ +│ ├──────────────────────────────┤ │ +│ │ 🟡 3号升降机 风速过大 │ │ +│ │ 10:20 │ │ +│ └──────────────────────────────┘ │ +│ │ +│ [查看全部预警] │ +│ │ +└──────────────────────────────────────┘ +``` + +### 3.2 设备列表 `/devices.html` + +``` +┌──────────────────────────────────────┐ +│ ☰ 设备列表 [筛选 ▼] │ +├──────────────────────────────────────┤ +│ [全部] [塔吊] [升降机] │ ← Tab 切换 +├──────────────────────────────────────┤ +│ │ +│ ┌──────────────────────────────┐ │ +│ │ 🏗️ 1号塔吊 🟢 在线 │ │ ← 设备卡片 +│ │ QTZ500 | A区施工现场 │ │ +│ │ 最后在线: 10:30 │ │ +│ └──────────────────────────────┘ │ +│ │ +│ ┌──────────────────────────────┐ │ +│ │ 🏗️ 2号塔吊 ⚫ 离线 │ │ +│ │ QTZ500 | B区施工现场 │ │ +│ │ 最后离线: 04-13 18:00 │ │ +│ └──────────────────────────────┘ │ +│ │ +└──────────────────────────────────────┘ +``` + +### 3.3 设备详情 `/device.html` + +``` +┌──────────────────────────────────────┐ +│ ← 返回 1号塔吊 │ +├──────────────────────────────────────┤ +│ │ +│ ┌──────────────────────────────┐ │ +│ │ 实时数据面板 │ │ ← 关键指标卡片 +│ │ 载重 幅度 起升高度 │ │ +│ │ 45.2kN 30.5m 85.0m │ │ +│ │ │ │ +│ │ 风速 力矩 回转角度 │ │ +│ │ 5.2m/s 320.5 120.5° │ │ +│ │ │ │ +│ │ ⚠️ 载重超限 │ │ ← 告警状态 +│ └──────────────────────────────┘ │ +│ │ +│ 历史趋势(最近24小时) │ +│ ┌──────────────────────────────┐ │ +│ │ 📈 ECharts 折线图 │ │ ← ECharts 图表 +│ │ 载重 / 幅度 / 风速 曲线 │ │ +│ └──────────────────────────────┘ │ +│ │ +│ [ 刷新 ] │ +│ │ +└──────────────────────────────────────┘ +``` + +### 3.4 预警列表 `/alerts.html` + +``` +┌──────────────────────────────────────┐ +│ 预警中心 [筛选 ▼] │ +├──────────────────────────────────────┤ +│ [全部] [危险] [警告] [已处理] │ ← Tab 筛选 +├──────────────────────────────────────┤ +│ │ +│ ┌──────────────────────────────┐ │ +│ │ 🔴 载重超限 │ │ ← 危险预警(红色) +│ │ 1号塔吊 | 2026-04-14 10:25 │ │ +│ │ 当前45.2kN,超过额定40kN │ │ +│ └──────────────────────────────┘ │ +│ │ +│ ┌──────────────────────────────┐ │ +│ │ 🟡 风速过大 │ │ ← 警告预警(黄色) +│ │ 3号升降机 | 2026-04-14 10:20 │ │ +│ │ 当前8.5m/s,超过阈值6m/s │ │ +│ └──────────────────────────────┘ │ +│ │ +└──────────────────────────────────────┘ +``` + +### 3.5 预警详情 `/alert.html` + +``` +┌──────────────────────────────────────┐ +│ ← 返回 预警详情 │ +├──────────────────────────────────────┤ +│ │ +│ 🔴 危险 │ +│ │ +│ 载重超限 │ +│ │ +│ 设备: 1号塔吊(QTZ500) │ +│ 位置: A区施工现场 │ +│ 时间: 2026-04-14 10:25:00 │ +│ │ +│ 当前载重: 45.2 kN │ +│ 额定载重: 40.0 kN(阈值) │ +│ 超限幅度: 13% │ +│ │ +│ ┌──────────────────────────────┐ │ +│ │ 处理方式: │ │ +│ │ │ │ +│ │ [确认处理] [忽略] │ │ ← 操作按钮 +│ │ │ │ +│ │ 备注: ____________________ │ │ +│ │ │ │ +│ │ [提交] │ │ +│ └──────────────────────────────┘ │ +│ │ +└──────────────────────────────────────┘ +``` + +### 3.6 个人中心 `/profile.html` + +``` +┌──────────────────────────────────────┐ +│ ← 返回 个人中心 │ +├──────────────────────────────────────┤ +│ │ +│ ┌──────────┐ │ +│ │ 👤 │ │ +│ └──────────┘ │ +│ 张三(管理员) │ +│ 138****1234 │ +│ │ +│ ┌──────────────────────────────┐ │ +│ │ 📊 预警接收设置 │ │ +│ │ [ ] 危险预警推送 │ │ +│ │ [ ] 警告预警推送 │ │ +│ │ [x] 短信通知 │ │ +│ └──────────────────────────────┘ │ +│ │ +│ ┌──────────────────────────────┐ │ +│ │ 🔔 消息推送设置 │ │ +│ └──────────────────────────────┘ │ +│ │ +│ ┌──────────────────────────────┐ │ +│ │ 🔐 修改密码 │ │ +│ └──────────────────────────────┘ │ +│ │ +│ [退出登录] │ +│ │ +└──────────────────────────────────────┘ +``` + +--- + +## 4. 页面交互 + +### 4.1 API 请求 + +所有页面通过 `fetch` 调用后台 API,基础封装: + +```javascript +// api.js +const API_BASE = '/v1'; + +async function api(endpoint, options = {}) { + const token = localStorage.getItem('token'); + const resp = await fetch(API_BASE + endpoint, { + ...options, + headers: { + 'Content-Type': 'application/json', + 'Authorization': token ? `Bearer ${token}` : '', + ...options.headers, + } + }); + if (resp.status === 401) { + location.href = '/login.html'; + return; + } + const json = await resp.json(); + if (json.code !== 0) { + alert(json.message); + return; + } + return json.data; +} +``` + +### 4.2 数据加载流程 + +``` +页面加载 + │ + ▼ +检查登录状态(localStorage.token) + │ + ├─ 无 token → 跳转 login.html + │ + └─ 有 token → API 请求 + │ + ├─ 成功 → 渲染页面 + │ + └─ 失败 → 显示错误提示 +``` + +### 4.3 实时数据刷新 + +- **策略**: 首次加载后,每 **30 秒**自动刷新实时数据 +- **实现**: `setInterval` 定时调用 `GET /devices/{id}/realtime` +- **优化**: 仅在设备详情页刷新,其他页面用户主动下拉刷新 + +### 4.4 离线缓存 + +使用 **Service Worker** 缓存静态资源: + +```javascript +// 缓存策略:Network First, Fallback to Cache +// 缓存内容:HTML / CSS / JS / iconfont 字体 +``` + +--- + +## 5. 响应式断点 + +| 断点 | 宽度 | 适配 | +|------|------|------| +| mobile-s | 320px ~ 374px | 小屏手机 | +| mobile-l | 375px ~ 413px | 主流手机 | +| tablet | 768px ~ 1023px | 平板 | +| desktop | 1024px+ | 桌面端 | + +--- + +## 6. 待确认 + +- [ ] 预警推送机制(轮询 vs WebSocket) +- [ ] 登录 Session 管理方案(JWT 有效期) +- [ ] 是否有扫码登录需求 +- [ ] 报表导出(H5 直接拉 OSS 预签名 URL) diff --git a/docs/offline.md b/docs/offline.md new file mode 100644 index 0000000..a797898 --- /dev/null +++ b/docs/offline.md @@ -0,0 +1,191 @@ +# 离线数据方案 + +> 状态: 设计中(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, status, created_at } +} + +// 对象存储 3: sync_queue(离线操作队列) +{ + store: 'sync_queue', + keyPath: 'id', + autoIncrement: true, + data: { id, action, payload, created_at, status } +} +``` + +### 3.2 缓存更新策略 + +| 数据类型 | 更新频率 | 缓存策略 | +|----------|----------|----------| +| 设备列表 | 每 5 分钟 | 后台静默更新 | +| 设备详情 | 每 30 秒 | 页面打开时拉取 + 定时刷新 | +| 预警列表 | 每 1 分钟 | 后台静默更新 + 新预警推送 | +| 预警详情 | 实时 | 打开时拉取 | + +**更新流程**: +``` +用户打开页面 + │ + ├─ 有网络 → API 请求 → 更新 IndexedDB → 渲染 + │ + └─ 无网络 → 读取 IndexedDB → 渲染(显示"离线模式") +``` + +--- + +## 4. 离线操作队列 + +### 4.1 场景 + +用户在离线状态下执行操作(如处理预警、提交备注),操作记录存入 `sync_queue`,网络恢复后自动同步。 + +### 4.2 同步流程 + +``` +检测到网络恢复(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 还是原生) +- [ ] 离线数据保留时长策略