352 lines
9.8 KiB
Markdown
Raw Normal View History

# API 接口文档
> 充电柜矩阵系统(PMS)接口规范。PC 管理端与 H5 用户端共用同一套 API。
## 基础信息
- **测试环境**:`https://test.anzhizhichong.com/pms/api/`
- **正式环境**:`https://app.anzhizhichong.com/pms/api/`
- **认证方式**:Bearer Token(JWT)
- **响应格式**:`{ "code": 0, "data": ..., "message": "ok" }`
## 统一端点清单
| 方法 | 路径 | 说明 | 权限 |
|------|------|------|------|
| POST | `/api/auth/login` | 登录 | 免认证 |
| GET | `/api/auth/logout` | 登出 | 需认证 |
| GET | `/api/auth/me` | 当前用户信息 | 需认证 |
| GET | `/api/dashboard` | 仪表盘数据 | 需认证 |
| GET | `/api/cabinets` | 设备列表(含 RSSI) | `device:view` |
| POST | `/api/cabinets` | 批量创建柜子 | `device:create` |
| GET | `/api/cabinets/:id` | 设备详情(含仓板+仓体) | `device:view` |
| PUT | `/api/cabinets/:id` | 更新柜子 | `device:edit` |
| DELETE | `/api/cabinets/:id` | 删除柜子 | `device:delete` |
| GET | `/api/cabinets/abstract/:abstract_id` | 扫码查设备(免认证) | 免认证 |
| GET | `/api/cabinets/scan/:abstract_id` | 扫码验证(需认证) | 需认证 |
| GET | `/api/cabinets/filter` | 设备列表(管理端) | 需认证 |
| GET | `/api/cabinets/realtime-status` | 设备实时状态 | 需认证 |
| GET | `/api/compartments/:id` | 仓体/通道详情 | 需认证 |
| POST | `/api/charge/start` | 开始充电 | `charge:start` |
| POST | `/api/charge/stop` | 停止充电 | `charge:stop` |
| POST | `/api/door/open` | 开门 | `device:door:unlock` |
| GET | `/api/organizations` | 组织列表 | `org:view` |
| POST | `/api/organizations` | 创建组织 | `org:create` |
| GET | `/api/organizations/:org_id/projects` | 项目列表 | 需认证 |
| GET | `/api/charge-records` | 充电记录 | `charge_record:view` |
| GET | `/api/energy-stats/summary` | 能耗统计 | 需认证 |
---
## 认证接口
### POST /api/auth/login
**请求:**
```json
{
"phone": "13800138000",
"password": "admin123"
}
```
**响应:**
```json
{
"code": 0,
"data": {
"token": "eyJ0eXAi...",
"user": {
"id": 1,
"name": "管理员",
"phone": "13800138000",
"role_level": 2,
"organization_id": null,
"permissions": ["device:view", "device:create", "..."]
}
},
"message": "登录成功"
}
```
**角色等级:** 1=普通用户,2=超级管理员
---
## H5 专用接口
### GET /api/dashboard
H5 首页仪表盘数据。支持 `org_id` 参数按组织过滤。
**响应:**
```json
{
"code": 0,
"data": {
"online_cabinets": 68,
"charging_count": 214,
"idle_channels": 722,
"fault_channels": 0,
"full_count": 0,
"today_charge_count": 0,
"today_energy_kwh": 0,
"today_charge_hours": 0,
"alerts": [],
"projects": [
{ "id": 1, "name": "无锡太湖新城换电站", "cabinet_count": 2, "charging": 16, "idle": 56, "fault": 0 }
]
}
}
```
### GET /api/cabinets
设备列表,支持 `project_id` 和 `org_id` 过滤。响应包含实时 RSSI。
**响应字段:**
```json
{
"id": 1,
"abstract_id": "10-00000001",
"name": "太湖新城换电柜A",
"status": 1,
"project_id": 1,
"rssi": 85,
"channel_count": 36,
"idle_count": 30,
"charging_count": 6,
"full_count": 0,
"fault_count": 0
}
```
### GET /api/cabinets/abstract/:abstract_id
扫码入口,免认证。通过二维码中的抽象ID查找设备。
**响应:**
```json
{
"code": 0,
"data": {
"id": 1,
"abstract_id": "10-00000001",
"imei": "864720562557021",
"iccid": "8986012520983901841",
"name": "太湖新城换电柜A",
"status": 1,
"cabin_boards": [
{
"id": 1,
"board_id": 1,
"status": 0,
"compartments": [
{ "id": 1, "channel_id": 1, "status": 0 }
]
}
]
}
}
```
### GET /api/compartments/:id
仓体/通道详情,含实时 BMS 数据和充电记录。
**响应字段:**
- `voltage` — mV(整数)
- `current` — mA(整数)
- `power` — mW(整数)
- `energy` — Wh(整数)
- `soc` — %(0-100)
- `soh` — %(0-100)
- `cell_voltages` — mV 数组
### POST /api/charge/start
**请求:** `{ "compartment_id": 123 }`
### POST /api/charge/stop
**请求:** `{ "compartment_id": 123 }`
### POST /api/door/open
**请求:** `{ "compartment_id": 123 }`
### GET /api/cabinets/scan/:abstract_id
扫码验证,需认证。验证当前用户是否有权访问该设备。
---
## 数据单位规范
**核心原则:所有数值字段使用整数存储,禁止浮点类型 (f32/f64/DECIMAL/FLOAT)**
| 字段 | 类型 | 单位 | 说明 |
|------|------|------|------|
| `energy` | i64 | **Wh** | 充电量,不存小数 |
| `voltage` | i64 | **mV** | 电池组总电压 |
| `current` | i64 | **mA** | 电流,正=充电 负=放电 |
| `power` | i64 | **mW** | 功率 |
| `soc` / `soh` | i64 | **%** | 电量百分比 / 健康度 |
| `max_temperature` | i64 | **0.1°C** | 25.3°C → `253` |
| `rssi` | i64 | **dBm** | 信号强度 |
**温度转换:** 前端显示时除以10加小数点(25.3°C → `253`)
---
## TCP 设备通讯协议
### 通信规则
- TCP 长连接,无需 PING 包
- 空闲 1 分钟上报,充电 15 秒上报
- 超时 5000ms
- JSON 去空格回车省流量,LF 处理粘包
- `dev_id`:IMEI(10进制),`sub_device_id`:485 ID
- `msg_id`:自增会话 ID
- 全局通道号:`dev_id-sub_device_id-通道号`(如 `123456789012345-01-6`)
### 签名机制
- 设备首次连接调 `auth_str` 接口获取8位安全码(仅一次)
- `sign = SHA256(dev_id + auth_str + timestamp).substring(56, 63)`
- 时间戳秒级,平台校验±60秒
### 指令清单
| 动作 | 方向 | id格式 | 说明 |
|------|------|--------|------|
| `login` | 设备→平台 | 无 | 登录(含sign+timestamp) |
| `auth_str` | 设备→平台 | 无 | 获取安全码(仅首次) |
| `status_post` | 设备→平台 | 无 | 定时上报(rssi+status字典) |
| `pow_fail` | 设备→平台 | 无 | 电源掉电上报 |
| `bat_in` | 设备→平台 | `IMEI-仓控板-通道` | 电池插入 |
| `bat_out` | 设备→平台 | `IMEI-仓控板-通道` | 电池拔出 |
| `on` | **双向** | `IMEI-仓控板-通道` | 开始充电 |
| `off` | **双向** | `IMEI-仓控板-通道` | 停止供电 |
| `open` | 平台→设备 | `IMEI` | 开门 |
| `pow_on` | 平台→设备 | `IMEI` | 接触器合闸 |
| `pow_off` | 平台→设备 | `IMEI` | 接触器分闸 |
| `reset` | 平台→设备 | `IMEI` 或 `IMEI-仓控板` | 重启整柜或仓控板 |
### 指令详情
#### login(设备→平台)
```json
{"act":"login","msg_id":1,"dev_id":"123456789012345","sign":"abc12345","timestamp":1719800000,"h_ver":"1.0.0","s_ver":"1.0.0"}
// 响应:{"suc":1,"msg_id":1,"cell":6}
```
#### auth_str(设备→平台)
```json
{"act":"auth_str","msg_id":2,"dev_id":"123456789012345","ccid":"89860000000000000000"}
// 响应:{"suc":1,"msg_id":2,"data":{"auth_str":"abcd1234"}}
```
#### status_post(设备→平台)
```json
{"act":"status_post","msg_id":10,"dev_id":"123456789012345","rssi":85,
"status":{"123456789012345-01":"000100020003000400050006"}}
// 响应:{"suc":1,"msg_id":10}
```
#### bat_in / bat_out(设备→平台)
```json
{"act":"bat_in","msg_id":20,"id":"123456789012345-01-6","bms":{"soc":45,"voltage":52.3}}
{"act":"bat_out","msg_id":21,"id":"123456789012345-01-6"}
```
#### on / off(双向)
```json
// 平台→设备:开始充电
{"act":"on","msg_id":30,"id":"123456789012345-01-6"}
// 设备→平台:充电开始确认
{"act":"on","msg_id":30,"id":"123456789012345-01-6"}
```
#### open(平台→设备)
```json
{"act":"open","msg_id":40,"id":"123456789012345"}
// 错误码63 = 门锁故障
```
#### reset(平台→设备)
```json
// 重启整柜
{"act":"reset","msg_id":60,"id":"123456789012345"}
// 重启仓控板
{"act":"reset","msg_id":61,"id":"123456789012345-01"}
```
### 充电结束原因
| 平台收到 | 判断原因 |
|---------|---------|
| `off` (设备→平台) | `normal` — 正常充满 |
| `off` (平台→设备) | `user_stop` — 用户手动停止 |
| `bat_out` | `normal` — 电池拔出 |
| `bat_in` (通道已有电池) | `forced` — 新电池插入强制结束 |
| 超时未响应 | `timeout` — 通信超时 |
---
## Redis 实时状态存储
### 层级结构
```
device:{imei} # 设备级 Hash
├─ online = "1" # 在线标记(TTL 300秒)
├─ rssi = "85" # 信号强度
├─ pow_fail_dc = "0/1" # 直流停电
└─ device:{imei}:board:{board_idx} # 板级 Hash
├─ status_hex = "00010002..." # 原始hex状态
└─ device:{imei}:board:{board_idx}:ch:{0-5} # 通道级 Hash
├─ on = "0/1" # 充电中
├─ full = "0/1" # 充满
├─ fault = "0/1" # 故障
└─ hex = "00010002" # 原始hex
```
### BMS 字段
| 字段 | 类型 | 单位 | 说明 |
|------|------|------|------|
| `soc` | i64 | % | 电池电量百分比 |
| `soh` | i64 | % | 电池健康度百分比 |
| `voltage` | i64 | mV | 电池组总电压 |
| `current` | i64 | mA | 电流 |
| `power` | i64 | mW | 功率 |
| `energy` | i64 | Wh | 累计充电量 |
| `cell_voltages` | i64[] | mV | 单体电芯电压数组 |
---
## 权限码列表
| 权限码 | 说明 |
|--------|------|
| `device:view` | 查看设备 |
| `device:create` | 创建设备 |
| `device:edit` | 编辑设备 |
| `device:delete` | 删除设备 |
| `device:door:unlock` | 开门 |
| `charge:start` | 开始充电 |
| `charge:stop` | 停止充电 |
| `charge_record:view` | 查看充电记录 |
| `org:view` | 查看组织 |
| `org:create` | 创建组织 |
| `org:edit` | 编辑组织 |