feat: 完成API详细设计+数据库表结构(隐患/施工日志/AI分析)

- docs/api.md: 补充隐患随手拍(5个端点)、施工日志(3个端点)、AI分析(2个端点)
- docs/database.md: 全面重写,MySQL+project_id隔离,新增projects/hazards/construction_logs/ai_analysis_results四张表
- SPEC.md: 更新至v0.2.1
This commit is contained in:
2026-04-14 16:44:21 +08:00
parent 8f035f96fe
commit ba5d65d438
3 changed files with 651 additions and 54 deletions

View File

@@ -452,7 +452,466 @@ GET /oss/download-url
---
## 7. 待确认
## 7. 隐患随手拍接口
### 7.1 上报隐患
```
POST /v1/hazards
```
**请求体**:
```json
{
"category": "fall",
"severity": "general",
"description": "A区2楼临边防护缺失",
"photos": ["reports/2026/04/hazard_001_1.jpg", "reports/2026/04/hazard_001_2.jpg"],
"gps_lat": 34.7652,
"gps_lng": 113.6241
}
```
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| category | string | 是 | 隐患类别代码 |
| severity | string | 是 | 严重程度: `general` / `serious` / `major` |
| description | string | 是 | 隐患描述2~500字 |
| photos | string[] | 否 | 照片 OSS object_key 列表(先调用 5.1 获取上传凭证) |
| gps_lat | decimal | 否 | GPS 纬度 |
| gps_lng | decimal | 否 | GPS 经度 |
**自动填充**(无需传入,后台从 JWT Token 解析):
- `reporter_id` — 上报人用户 ID
- `reporter_role` — 上报人身份
- `project_id` — 所属项目 ID中间件注入
- `status``pending`
- `reported_at` → 当前服务器时间
**响应** (201):
```json
{
"code": 0,
"message": "success",
"data": {
"id": "hazard_001",
"status": "pending",
"reported_at": "2026-04-14T14:30:00Z"
}
}
```
---
### 7.2 隐患列表
```
GET /v1/hazards
```
**Query 参数**:
| 参数 | 类型 | 说明 |
|------|------|------|
| status | string | 状态: `pending` / `assigned` / `resolved` / 空(全部) |
| category | string | 隐患类别代码 / 空(全部) |
| severity | string | 严重程度: `general` / `serious` / `major` / 空(全部) |
| start_date | date | 筛选开始日期 YYYY-MM-DD |
| end_date | date | 筛选结束日期 YYYY-MM-DD |
| page | int | 页码,默认 1 |
| page_size | int | 每页数量,默认 20最大 100 |
**响应** (200):
```json
{
"code": 0,
"message": "success",
"data": {
"total": 25,
"page": 1,
"page_size": 20,
"items": [
{
"id": "hazard_001",
"category": "fall",
"category_name": "高处坠落",
"severity": "general",
"severity_name": "一般",
"description": "A区2楼临边防护缺失",
"photo_count": 2,
"gps_lat": 34.7652,
"gps_lng": 113.6241,
"status": "pending",
"reporter": {
"id": 3,
"username": "zhangsan",
"role": "安全员"
},
"reporter_role": "安全员",
"reported_at": "2026-04-14T14:30:00Z",
"assignee": null,
"resolved_at": null
}
]
}
}
```
**说明**:
- 自动按 `project_id` 过滤(中间件注入)
- 结果按 `reported_at` 倒序
---
### 7.3 隐患详情
```
GET /v1/hazards/:id
```
**响应** (200):
```json
{
"code": 0,
"message": "success",
"data": {
"id": "hazard_001",
"category": "fall",
"category_name": "高处坠落",
"severity": "general",
"severity_name": "一般",
"description": "A区2楼临边防护缺失",
"photos": [
"https://jesxion-ai-studio.oss-cn-beijing.aliyuncs.com/reports/2026/04/hazard_001_1.jpg?Signature=...",
"https://jesxion-ai-studio.oss-cn-beijing.aliyuncs.com/reports/2026/04/hazard_001_2.jpg?Signature=..."
],
"gps_lat": 34.7652,
"gps_lng": 113.6241,
"status": "assigned",
"reporter": {
"id": 3,
"username": "zhangsan",
"role": "安全员"
},
"reported_at": "2026-04-14T14:30:00Z",
"assignee": {
"id": 5,
"username": "lisi",
"role": "安全负责人"
},
"assigned_at": "2026-04-14T15:00:00Z",
"resolved_at": null,
"resolve_note": null
}
}
```
**说明**:
- 照片返回完整预签名下载 URL有效 1 小时)
- `resolve_note``resolved` 状态时有值
---
### 7.4 认领隐患
```
POST /v1/hazards/:id/assign
```
**前置条件**: 隐患状态为 `pending`
**请求体**: 空对象 `{}`(操作人从 JWT Token 解析)
**自动填充**:
- `assignee_id` — 认领人用户 ID
- `assignee_role` — 认领人身份
- `status``assigned`
- `assigned_at` → 当前服务器时间
**响应** (200):
```json
{
"code": 0,
"message": "success",
"data": {
"id": "hazard_001",
"status": "assigned",
"assigned_at": "2026-04-14T15:00:00Z"
}
}
```
**错误**:
- `400` 隐患状态不是 `pending`(已认领或已处理)
---
### 7.5 处理完成
```
POST /v1/hazards/:id/resolve
```
**前置条件**: 隐患状态为 `assigned`
**请求体**:
```json
{
"note": "已重新安装防护栏"
}
```
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| note | string | 否 | 处理说明0~500字 |
**自动填充**:
- `resolver_id` — 处理人用户 ID
- `resolver_role` — 处理人身份
- `status``resolved`
- `resolved_at` → 当前服务器时间
**响应** (200):
```json
{
"code": 0,
"message": "success",
"data": {
"id": "hazard_001",
"status": "resolved",
"resolved_at": "2026-04-14T16:00:00Z"
}
}
```
**错误**:
- `400` 隐患状态不是 `assigned`(未认领或已处理)
---
## 8. 施工日志接口
### 8.1 新建日志
```
POST /v1/logs
```
**请求体**:
```json
{
"date": "2026-04-14",
"part": "A区主体结构",
"content": "3层混凝土浇筑钢筋绑扎",
"workers": 28,
"equipment": ["tower_crane", "elevator"],
"photos": ["logs/2026/04/log_001_1.jpg"],
"safety_note": "临边作业已挂安全网",
"note": "下午2点停电1小时"
}
```
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| date | date | 是 | 日志日期 YYYY-MM-DD |
| part | string | 是 | 施工部位2~100字 |
| content | text | 是 | 作业内容2~2000字 |
| workers | int | 是 | 人员出勤人数1~9999 |
| equipment | string[] | 否 | 设备运行类型: `tower_crane` / `elevator` |
| photos | string[] | 否 | 现场照片 OSS object_key 列表 |
| safety_note | text | 否 | 安全问题描述0~1000字 |
| note | text | 否 | 备注0~500字 |
**自动填充**:
- `author_id` — 撰写人用户 ID
- `author_role` — 撰写人身份
- `project_id` — 所属项目 ID
- `created_at` → 当前服务器时间
**响应** (201):
```json
{
"code": 0,
"message": "success",
"data": {
"id": "log_001",
"created_at": "2026-04-14T17:00:00Z"
}
}
```
---
### 8.2 日志列表
```
GET /v1/logs
```
**Query 参数**:
| 参数 | 类型 | 说明 |
|------|------|------|
| start_date | date | 筛选开始日期 YYYY-MM-DD |
| end_date | date | 筛选结束日期 YYYY-MM-DD |
| page | int | 页码,默认 1 |
| page_size | int | 每页数量,默认 20最大 100 |
**响应** (200):
```json
{
"code": 0,
"message": "success",
"data": {
"total": 30,
"page": 1,
"page_size": 20,
"items": [
{
"id": "log_001",
"date": "2026-04-14",
"part": "A区主体结构",
"content": "3层混凝土浇筑钢筋绑扎...",
"workers": 28,
"equipment": ["tower_crane", "elevator"],
"photo_count": 1,
"safety_note": "临边作业已挂安全网",
"author": {
"id": 3,
"username": "zhangsan",
"role": "安全员"
},
"created_at": "2026-04-14T17:00:00Z"
}
]
}
}
```
**说明**:
- 自动按 `project_id` 过滤
- `content` 列表页截断至 200 字
- 结果按 `date` 倒序
---
### 8.3 日志详情
```
GET /v1/logs/:id
```
**响应** (200):
```json
{
"code": 0,
"message": "success",
"data": {
"id": "log_001",
"date": "2026-04-14",
"part": "A区主体结构",
"content": "3层混凝土浇筑钢筋绑扎",
"workers": 28,
"equipment": ["tower_crane", "elevator"],
"equipment_names": ["塔吊", "升降机"],
"photos": [
"https://jesxion-ai-studio.oss-cn-beijing.aliyuncs.com/logs/2026/04/log_001_1.jpg?Signature=..."
],
"safety_note": "临边作业已挂安全网",
"note": "下午2点停电1小时",
"author": {
"id": 3,
"username": "zhangsan",
"role": "安全员"
},
"created_at": "2026-04-14T17:00:00Z"
}
}
```
**说明**:
- 照片返回完整预签名下载 URL有效 1 小时)
- `equipment_names` 为中文设备名称数组
---
## 9. AI 智能分析接口
### 9.1 分析结果列表
```
GET /v1/ai/analyses
```
**Query 参数**:
| 参数 | 类型 | 说明 |
|------|------|------|
| device_id | string | 设备ID / 空(全部) |
| analysis_type | string | 分析类型: `personnel_safety` / `equipment_anomaly` / `environmental_risk` / 空(全部) |
| start_date | datetime | 筛选开始时间 ISO8601 |
| end_date | datetime | 筛选结束时间 ISO8601 |
| page | int | 页码,默认 1 |
| page_size | int | 每页数量,默认 20最大 100 |
**响应** (200):
```json
{
"code": 0,
"message": "success",
"data": {
"total": 15,
"page": 1,
"page_size": 20,
"items": [
{
"id": "ai_001",
"device_id": "device_001",
"device_name": "1号塔吊",
"analysis_type": "personnel_safety",
"analysis_type_name": "人员安全",
"confidence": 0.92,
"description": "检测到人员靠近吊装区域,触发区域入侵告警",
"triggered_at": "2026-04-14T10:25:00Z"
}
]
}
}
```
**说明**:
- 自动按 `project_id` 过滤(中间件注入)
- 结果按 `triggered_at` 倒序
- `confidence` 为 0.00~1.00 小数
---
### 9.2 分析结果详情
```
GET /v1/ai/analyses/:id
```
**响应** (200):
```json
{
"code": 0,
"message": "success",
"data": {
"id": "ai_001",
"device_id": "device_001",
"device_name": "1号塔吊",
"analysis_type": "personnel_safety",
"analysis_type_name": "人员安全",
"confidence": 0.92,
"description": "检测到人员靠近吊装区域,触发区域入侵告警",
"suggestion": "建议立即疏散人员,后续加强吊装区域围挡和警示标志",
"triggered_at": "2026-04-14T10:25:00Z",
"created_at": "2026-04-14T10:25:05Z"
}
}
```
---
## 10. 待确认
- [x] 预警推送机制 → 轮询(前端每 30s
- [x] JWT 有效期 → 7 天

View File

@@ -1,52 +1,80 @@
# 数据库表结构设计
> 状态: 设计中MVP 版本SQLite
> 状态: 设计中MVP 版本,MySQL 8.0
---
## 0. 租户隔离模型
> 所有表通过 `project_id` 字段实现项目级逻辑租户隔离。API 中间件在每个请求中自动注入当前用户的 `project_id` 条件,数据查询均以此过滤。
| 表名 | 用途 |
|------|------|
| `users` | 用户属于项目 |
| `devices` | 设备属于项目 |
| `device_realtime` | 设备实时数据,属于项目 |
| `device_history` | 设备历史数据,属于项目 |
| `alert_records` | 预警记录,属于项目 |
| `hazards` | 隐患随手拍,属于项目 |
| `construction_logs` | 施工日志,属于项目 |
| `ai_analysis_results` | AI 分析结果,属于项目 |
| `oss_files` | OSS 文件索引,属于项目 |
---
## 1. ER 图概述
```
users ─────────┐
1:N
user_device_access (N:M)
devices ───────┤
├──── 1:N ──── device_realtime (最新状态)
├──── 1:N ──── device_history (历史数据)
└──── 1:N ──── alert_records (预警记录)
users ──── project_id ──── projects
┌─────────────────┼─────────────────┐
│ │ │
▼ ▼
devices ──────── alert_records hazards
│ │
├──── 1:N ──── device_realtime
├──── 1:N ──── device_history
└──── 1:N ──── ai_analysis_results
alert_records ────── N:1 ──── users (处理人)
oss_files ──────────────────────────────────────────────────┐
(其他模块按需关联) │
construction_logs
oss_files (关联各模块)
```
---
## 2. 表结构
### 2.0 projects项目表
| 字段 | 类型 | 约束 | 说明 |
|------|------|------|------|
| id | INT | PRIMARY KEY AUTO_INCREMENT | 项目ID |
| name | VARCHAR(128) | NOT NULL | 项目名称 |
| location | VARCHAR(256) | | 项目地址 |
| status | VARCHAR(32) | DEFAULT 'active' | 状态: active / archived |
| created_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | 创建时间 |
---
### 2.1 users用户表
| 字段 | 类型 | 约束 | 说明 |
|------|------|------|------|
| id | SERIAL | PRIMARY KEY | 自增ID |
| id | INT | PRIMARY KEY AUTO_INCREMENT | 用户ID |
| project_id | INT | FOREIGN KEY → projects(id) | 所属项目 |
| username | VARCHAR(64) | UNIQUE NOT NULL | 用户名 |
| password_hash | VARCHAR(256) | NOT NULL | bcrypt 密码哈希 |
| role | VARCHAR(32) | NOT NULL DEFAULT 'viewer' | 角色: admin / operator / viewer |
| role | VARCHAR(32) | NOT NULL | 身份: 项目经理 / 安全负责人 / 安全员 |
| real_name | VARCHAR(128) | | 真实姓名 |
| phone | VARCHAR(32) | | 手机号 |
| is_active | BOOLEAN | DEFAULT true | 是否启用 |
| created_at | TIMESTAMP | DEFAULT NOW() | 创建时间 |
| updated_at | TIMESTAMP | DEFAULT NOW() | 更新时间 |
| created_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | 创建时间 |
| updated_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 更新时间 |
**索引**:
- `idx_users_project_id` ON (`project_id`)
- `idx_users_username` ON (`username`)
---
@@ -56,6 +84,7 @@ oss_files ───────────────────────
| 字段 | 类型 | 约束 | 说明 |
|------|------|------|------|
| id | VARCHAR(64) | PRIMARY KEY | 设备ID对接已有API的设备编号 |
| project_id | INT | FOREIGN KEY → projects(id) | 所属项目 |
| name | VARCHAR(128) | NOT NULL | 设备名称,如 "1号塔吊" |
| type | VARCHAR(32) | NOT NULL | 类型: `tower_crane` / `elevator` |
| model | VARCHAR(128) | | 设备型号,如 "QTZ500" |
@@ -64,11 +93,12 @@ oss_files ───────────────────────
| 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() | 更新时间 |
| config | JSON | DEFAULT '{}' | 设备配置 |
| created_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | 创建时间 |
| updated_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 更新时间 |
**索引**:
- `idx_devices_project_id` ON (`project_id`)
- `idx_devices_type` ON (`type`)
- `idx_devices_status` ON (`status`)
@@ -78,12 +108,13 @@ oss_files ───────────────────────
| 字段 | 类型 | 约束 | 说明 |
|------|------|------|------|
| id | SERIAL | PRIMARY KEY | 自增ID |
| id | INT | PRIMARY KEY AUTO_INCREMENT | 自增ID |
| project_id | INT | FOREIGN KEY → projects(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() | 写入时间 |
| raw_data | JSON | NOT NULL | 原始数据快照 |
| parsed_data | JSON | NOT NULL | 解析后的结构化数据 |
| created_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | 写入时间 |
**索引**:
- `idx_realtime_device_id` ON (`device_id`)
@@ -97,18 +128,18 @@ oss_files ───────────────────────
| 字段 | 类型 | 约束 | 说明 |
|------|------|------|------|
| id | BIGSERIAL | PRIMARY KEY | 自增ID |
| id | BIGINT | PRIMARY KEY AUTO_INCREMENT | 自增ID |
| project_id | INT | FOREIGN KEY → projects(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() | 写入时间 |
| created_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | 写入时间 |
**索引**:
- `idx_history_device_time` ON (`device_id`, `timestamp` DESC)
- `idx_history_project_device_time` ON (`project_id`, `device_id`, `timestamp` DESC)
- `idx_history_metric` ON (`metric_name`)
- **分区**: 按月分区(`timestamp`按设备ID + 时间范围查询
> 为节省存储空间,历史数据可定期归档到 OSS冷存储DB 仅保留近3个月数据。
@@ -119,19 +150,21 @@ oss_files ───────────────────────
| 字段 | 类型 | 约束 | 说明 |
|------|------|------|------|
| id | VARCHAR(64) | PRIMARY KEY | 预警IDUUID |
| project_id | INT | FOREIGN KEY → projects(id) | 所属项目 |
| 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 | 预警消息(设备 API 提供) |
| message | VARCHAR(512) | NOT NULL | 预警消息 |
| value | DECIMAL(18,4) | NOT NULL | 触发时的实际值 |
| status | VARCHAR(32) | DEFAULT 'unread' | 状态: unread / handled / ignored |
| handled_by | INTEGER | FOREIGN KEY → users(id) | 处理人 |
| handled_by | INT | FOREIGN KEY → users(id) | 处理人 |
| handle_note | TEXT | | 处理备注 |
| created_at | TIMESTAMP | DEFAULT NOW() | 创建时间 |
| created_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | 创建时间 |
| handled_at | TIMESTAMP | | 处理时间 |
**索引**:
- `idx_alerts_project_id` ON (`project_id`)
- `idx_alerts_device` ON (`device_id`)
- `idx_alerts_status` ON (`status`)
- `idx_alerts_level` ON (`level`)
@@ -143,22 +176,105 @@ oss_files ───────────────────────
| 字段 | 类型 | 约束 | 说明 |
|------|------|------|------|
| id | SERIAL | PRIMARY KEY | 自增ID |
| id | INT | PRIMARY KEY AUTO_INCREMENT | 自增ID |
| project_id | INT | FOREIGN KEY → projects(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 | | 过期时间(临时文件) |
| category | VARCHAR(64) | | 分类: hazard / log / ai |
| uploaded_by | INT | FOREIGN KEY → users(id) | 上传人 |
| uploaded_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | 上传时间 |
**索引**:
- `idx_oss_project_id` ON (`project_id`)
- `idx_oss_category` ON (`category`)
- `idx_oss_uploaded_by` ON (`uploaded_by`)
---
### 2.7 hazards隐患随手拍表
| 字段 | 类型 | 约束 | 说明 |
|------|------|------|------|
| id | VARCHAR(64) | PRIMARY KEY | 隐患IDUUID |
| project_id | INT | FOREIGN KEY → projects(id) | 所属项目 |
| category | VARCHAR(32) | NOT NULL | 隐患类别代码 |
| severity | VARCHAR(32) | NOT NULL | 严重程度: general / serious / major |
| description | TEXT | NOT NULL | 隐患描述 |
| photos | JSON | | 照片 OSS object_key 列表 |
| gps_lat | DECIMAL(10,6) | | GPS 纬度 |
| gps_lng | DECIMAL(10,6) | | GPS 经度 |
| status | VARCHAR(32) | DEFAULT 'pending' | 状态: pending / assigned / resolved |
| reporter_id | INT | FOREIGN KEY → users(id) | 上报人 |
| reporter_role | VARCHAR(32) | | 上报人身份 |
| reported_at | TIMESTAMP | | 上报时间 |
| assignee_id | INT | FOREIGN KEY → users(id) | 认领人 |
| assignee_role | VARCHAR(32) | | 认领人身份 |
| assigned_at | TIMESTAMP | | 认领时间 |
| resolver_id | INT | FOREIGN KEY → users(id) | 处理人 |
| resolver_role | VARCHAR(32) | | 处理人身份 |
| resolve_note | TEXT | | 处理说明 |
| resolved_at | TIMESTAMP | | 处理完成时间 |
| created_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | 创建时间 |
**索引**:
- `idx_hazards_project_id` ON (`project_id`)
- `idx_hazards_status` ON (`status`)
- `idx_hazards_category` ON (`category`)
- `idx_hazards_severity` ON (`severity`)
- `idx_hazards_reported_at` ON (`reported_at` DESC)
---
### 2.8 construction_logs施工日志表
| 字段 | 类型 | 约束 | 说明 |
|------|------|------|------|
| id | VARCHAR(64) | PRIMARY KEY | 日志IDUUID |
| project_id | INT | FOREIGN KEY → projects(id) | 所属项目 |
| date | DATE | NOT NULL | 日志日期 |
| part | VARCHAR(128) | NOT NULL | 施工部位 |
| content | TEXT | NOT NULL | 作业内容 |
| workers | INT | NOT NULL | 人员出勤人数 |
| equipment | JSON | | 设备运行类型数组 |
| photos | JSON | | 现场照片 OSS object_key 列表 |
| safety_note | TEXT | | 安全问题描述 |
| note | TEXT | | 备注 |
| author_id | INT | FOREIGN KEY → users(id) | 撰写人 |
| author_role | VARCHAR(32) | | 撰写人身份 |
| created_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | 创建时间 |
**索引**:
- `idx_logs_project_id` ON (`project_id`)
- `idx_logs_date` ON (`date` DESC)
- `idx_logs_author_id` ON (`author_id`)
---
### 2.9 ai_analysis_resultsAI 智能分析结果表)
| 字段 | 类型 | 约束 | 说明 |
|------|------|------|------|
| id | VARCHAR(64) | PRIMARY KEY | 分析IDUUID |
| project_id | INT | FOREIGN KEY → projects(id) | 所属项目 |
| device_id | VARCHAR(64) | FOREIGN KEY → devices(id) | 关联设备 |
| device_name | VARCHAR(128) | | 设备名称(冗余) |
| analysis_type | VARCHAR(64) | NOT NULL | 分析类型 |
| confidence | DECIMAL(5,4) | | 置信度 0.0000~1.0000 |
| description | TEXT | NOT NULL | AI 分析描述 |
| suggestion | TEXT | | 建议措施 |
| triggered_at | TIMESTAMP | NOT NULL | 触发时间 |
| created_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | 记录创建时间 |
**索引**:
- `idx_ai_project_id` ON (`project_id`)
- `idx_ai_device_id` ON (`device_id`)
- `idx_ai_type` ON (`analysis_type`)
- `idx_ai_triggered_at` ON (`triggered_at` DESC)
---
## 3. 初始数据
### 3.1 超级管理员
@@ -167,27 +283,49 @@ oss_files ───────────────────────
|----------|----------|------|
| admin | (首次部署时设置) | admin |
### 3.2 隐患类别字典(写入代码枚举,非数据库表)
| 代码 | 名称 |
|------|------|
| fall | 高处坠落 |
| object_strike | 物体打击 |
| mechanical | 机械伤害 |
| electric | 触电 |
| collapse | 坍塌 |
| fire | 火灾 |
| lifting | 起重伤害 |
| vehicle | 车辆伤害 |
| blasting | 放炮 |
| drowning | 淹溺 |
| burn | 灼烫 |
| construction | 现场临建设施 |
| other | 其他伤害 |
### 3.3 AI 分析类型字典
| 代码 | 名称 |
|------|------|
| personnel_safety | 人员安全 |
| equipment_anomaly | 设备异常 |
| environmental_risk | 环境风险 |
---
## 4. 数据库初始化
MVP 阶段使用 SQLite`schema.sql` 定义建表语句,启动时自动初始化
MVP 阶段使用 MySQL 8.0`schema.sql` 定义建表语句:
```bash
# 手动初始化(可选,生产环境自动执行)
sqlite3 smart_project.db < schema.sql
# 或通过 Python 脚本
python -m src.db.init_db
```sql
-- 手动初始化
mysql -u root -p smart_project < schema.sql
```
> SQLite 无需迁移工具,每次表结构变更手动更新 `schema.sql` 并重启服务即可
> 每次表结构变更手动更新 `schema.sql` 并重启服务。
---
## 5. 待确认
- [x] 数据库 → MySQL 8.0MVP
- [x] OSS Bucket → `jesxion-ai-studio`(开发测试阶段)
- [x] 数据库 → SQLiteMVP
- [ ] 设备 API 协议格式(塔吊/升降机数据字段)— 厂家文档后续提供
- [ ] 多租户隔离方案MVP 单租户,后续扩展)