# 智慧酒店 App 接口对接方案

## 1. 对接原则

### 1.1 核心原则

- **View 层不变**：所有 UI 代码已完成，对接时只修改 Cubit 及以下层
- **统一调用链**：Cubit → Service → Repository → DioRequest，不允许 Cubit 直接调用 Repository
- **BO 模型统一**：所有数据模型定义在 `models/bo/`，State 中的内联模型需迁移
- **错误统一处理**：Service 层处理业务错误，网络错误由拦截器自动处理
- **loading/error 状态**：每个 State 必须包含 `isLoading` 和 `error` 字段

### 1.2 代码模板

#### Repository 模板

```dart
// lib/repositories/xxx_repository.dart
import '../utils/http/response_model.dart';
import '../utils/http/dio_request.dart';
import '../models/bo/xxx_bo.dart';

class XxxRepository {
  // GET 请求 - 返回列表
  Future<ResponseModel<List<XxxBO>>> getList() {
    return DioRequest.instance.get<List<XxxBO>>(
      '/api/xxx',
      fromJsonT: (data) {
        final list = data as List<dynamic>;
        return list.map((e) => XxxBO.fromJson(e as Map<String, dynamic>)).toList();
      },
    );
  }

  // GET 请求 - 返回单个对象
  Future<ResponseModel<XxxBO>> getDetail(String id) {
    return DioRequest.instance.get<XxxBO>(
      '/api/xxx/$id',
      fromJsonT: (data) => XxxBO.fromJson(data as Map<String, dynamic>),
    );
  }

  // POST 请求
  Future<ResponseModel> create(Map<String, dynamic> params) {
    return DioRequest.instance.post('/api/xxx', data: params);
  }

  // PUT 请求
  Future<ResponseModel> update(String id, Map<String, dynamic> params) {
    return DioRequest.instance.put('/api/xxx/$id', data: params);
  }
}
```

#### Service 模板

```dart
// lib/services/xxx_service.dart
import '../repositories/xxx_repository.dart';
import '../models/bo/xxx_bo.dart';

class XxxService {
  final XxxRepository _repository;

  XxxService({required XxxRepository repository}) : _repository = repository;

  Future<List<XxxBO>> getList() async {
    final result = await _repository.getList();
    if (result.success && result.data != null) {
      return result.data!;
    }
    throw Exception(result.msg);
  }

  Future<XxxBO> getDetail(String id) async {
    final result = await _repository.getDetail(id);
    if (result.success && result.data != null) {
      return result.data!;
    }
    throw Exception(result.msg);
  }
}
```

#### Cubit 改造模板（从 Mock 到真实 API）

```dart
// 改造前（Mock）
class XxxCubit extends Cubit<XxxState> {
  XxxCubit() : super(const XxxState()) {
    _initMockData();  // 硬编码数据
  }
  void _initMockData() { /* emit mock data */ }
}

// 改造后（真实 API）
class XxxCubit extends Cubit<XxxState> {
  final XxxService _service;

  XxxCubit({required XxxService service})
      : _service = service,
        super(const XxxState()) {
    loadData();
  }

  Future<void> loadData() async {
    emit(state.copyWith(isLoading: true, error: null));
    try {
      final data = await _service.getList();
      emit(state.copyWith(isLoading: false, dataList: data));
    } catch (e) {
      emit(state.copyWith(isLoading: false, error: e.toString()));
    }
  }
}
```

---

## 2. BO 模型定义

### 2.1 文件清单

按模块组织，每个文件包含该模块所有 BO 类，每个 BO 类对应一个 State 类，并且继承 `Equatable`。
 

### 2.2 定义模版

#### xxx_bo.dart

```dart
import 'package:equatable/equatable.dart';

class xxxBO extends Equatable {
  final String id;
  final String title;
  final String deviceInfo;
  final String alarmTime;
  final String processTime;
  final String status;       // "pending" | "processed" | "falseAlarm"
  final String level;        // "高警" | "中警" | "低警"
  final String urgency;      // "紧急" | "一般"

  const xxxBO({
    required this.id,
    required this.title,
    required this.deviceInfo,
    required this.alarmTime,
    required this.processTime,
    required this.status,
    required this.level,
    required this.urgency,
  });

  factory xxxBO.fromJson(Map<String, dynamic> json) {
    return xxxBO(
      id: json['id'] as String,
      title: json['title'] as String,
      deviceInfo: json['deviceInfo'] as String? ?? '',
      alarmTime: json['alarmTime'] as String? ?? '',
      processTime: json['processTime'] as String? ?? '',
      status: json['status'] as String? ?? 'pending',
      level: json['level'] as String? ?? '',
      urgency: json['urgency'] as String? ?? '',
    );
  }

  @override
  List<Object?> get props => [id, title, deviceInfo, alarmTime, processTime, status, level, urgency];
}

```


---

## 3. API 接口清单

### 3.1 接口总览

| 页面序号 | 方法 | 路径 | 状态 | 所属模块 | 要求描述 |
|------|------|------|------|---------|
| 登录页 |POST | /app/auth/login/password | 已对接 | 用户模块 | 
| 告警 |GET | /app/alert/dashboard | 已对接 | 设备告警看板 | 
| 告警详情 |GET | /app/alert/detail | 已对接 | 告警详情 | 
| 告警详情-确认处理 |POST | /app/alert/handle | 已对接 | 告警详情 | 在告警详情页面点击 确认处理 按钮，调用该接口。需要做下防重复提交，处理过程中不可点。处理完成之后弹出操作成功/操作失败提示。成功之后按钮不可再点击 |
| 设备控制 |GET | /app/device/control/detail | 已对接 | 设备控制 | |
| 设备控制 |POST | /app/device/control/powerOn | 已对接 | 设备控制-远程送电 | 需要做下防重复提交，处理过程中不可点。处理完成之后弹出操作成功/操作失败提示 |
| 设备控制 |POST | /app/device/control/powerOff | 已对接 | 设备控制-远程断电 | 需要做下防重复提交，处理过程中不可点。处理完成之后弹出操作成功/操作失败提示|


| 设备拓扑 |GET | /app/device/topology | 未对接 | 设备拓扑 | 相关页面：InspectionTopologyView |


 

### 3.2 接口详细定义

#### 登录

**POST  /app/auth/login/password**
```
请求体:
{
  "username": "string", // 用户名
  "password": "string", // 密码
  "clientId": "string", // 客户端ID 可选
  "grantType": "string", // 授权类型 可选
  "tenantId": "string", // 租户ID 可选
  "code": "string", // 授权码 可选
  "uuid": "string" // 唯一标识 可选
}

响应 data:
{
  "code": 0,
  "msg": "string",
  "data": {
    "scope": "string",
    "openid": "string",
    "access_token": "string",
    "refresh_token": "string",
    "expire_in": 0,
    "refresh_expire_in": 0,
    "client_id": "string"
  }
}
```
 
#### 设备告警看板

**GET  /app/alert/dashboard**
```
请求体:
{
  
}

响应 data:
{
  "code": 0,
  "msg": "string",
  "data": {
    "total": 0,
    "statistics": {
      "highAlertCount": 0, // 高警待处理数量
      "mediumAlertCount": 0, // 中警待处理数量
      "onlineDeviceCount": 0 // 在线设备数量
    },
    "alerts": [  //告警信息列表
      {
        "alertId": 0, // 告警ID
        "alertNo": "string",
        "alertTitle": "string", // 告警标题
        "alertLevel": "string", // 告警级别编码
        "alertLevelText": "string", // 告警级别中文描述
        "alertStatus": "string",// 告警状态编码（0=待处理，1=处理中，2=已处理，3=忽略，4=误报）
        "alertCategory": "string", // 预警分类（temperature=温度 current=电流 voltage=电压 power=用电 device=设备）
        "roomName": "string", // 所属房间名称
        "deviceName": "string",// 告警设备名称
        "alertValue": "string",
        "thresholdValue": "string",
        "alertContent": "string",
        "voltage": "string", // 告警时电压（V）
        "current": "string", // 告警时电流（A）
        "temperature": "string", // 告警时温度（℃）
        "waitingDuration": 0, // 告警持续时长（分钟）
        "waitingDurationDesc": "string", // 告警持续时长的中文描述
        "alertTime": "string"
      }
    ],
    "devices": [ // 设备巡检列表
      {
        "deviceId": 0, // 设备ID
        "deviceName": "string", // 设备名称
        "deviceTypeIcon": "string",
        "deviceTypeName": "string",
        "runStatus": "string",
        "runStatusText": "string", // 运行状态中文描述
        "roomName": "string", // 所属房间名称
        "temperature": "string", // 告警时温度（℃）
        "voltage": "string", // 设备当前电压（V）
        "power": "string", // 设备当前功率（kW）
        "current": "string", // 设备当前电流（A）
        "onlineStatus": "string", // 在线状态（0=离线，1=在线）
        "lastHeartbeat": "string",
        "deviceTypeIcon": "string", // 设备类型图标标识

      }
    ]
  }
}

```


#### 告警详情

**GET  /app/alert/detail**
```
请求体:
{
  "alertId": 0 // 告警ID
}

响应 data:
{
  "code": 0,
  "msg": "string",
  "data": {
    "alertBasicInfo": { // 告警基本信息
      "alertId": 0,
      "alertTitle": "string", // 告警标题（如"温度异常告警"）
      "alertLevel": "string",
      "alertLevelText": "string",
      "alertStatus": "string",
      "alertDeviceLocation": "string",
      "alertCount": 0,
      "alertTime": "string",
      "alertIcon": "string"
    },
    "trendChart": { // 趋势图
      "chartTitle": "string",
      "chartDate": "string",
      "unit": "string",
      "dataPoints": [
        {
          "time": "string",
          "value": 0,
          "recordId": 0
        }
      ],
      "yaxisMax": 0,
      "yaxisMin": 0
    },
    "alertDetailInfo": { // 
      "thresholdSetting": "string", // 预设阈值描述（如"温度>80°C触发"）
      "duration": "string", // 持续时长文本（如"2小时37分钟"）
      "durationMinutes": 0, // 持续时长（分钟）
      "peakRecord": "string", // 峰值记录（如"88.2℃(15:02)"）
      "linkageAction": "string", // 联动动作描述（如"自动断电保护"）
      "alertValue": "string", // 告警触发值
      "alertContent": "string" // 告警内容详情
    }
  }
}
```


#### 告警详情-确认处理

**POST  /app/alert/handle**
```
请求体:
{
  "alertId": 0 // 告警ID
}

响应 data:
{
  "code": 0,
  "msg": "string",
  "data": {
    "success": true
  }
}
```

#### 设备控制

**GET  /app/device/control/detail**
```
请求体:
{
  "deviceId": 0 // 设备ID
}

响应 data:
{
  "code": 0,
  "msg": "string",
  "data": {
    "deviceBasicInfo": { // 设备基本信息
      "deviceId": 0,
      "deviceName": "string",
      "deviceCode": "string",
      "roomName": "string",
      "deviceTypeIcon": "string",
      "onlineStatus": "string"
    },
    "realtimeParams": { // 实时电气参数
      "voltage": "string",
      "current": "string",
      "activePower": "string",
      "deviceTemperature": "string"
    },
    "trendChart": { // 趋势图表数据
      "chartTitle": "string",
      "unit": "string",
      "dataPoints": [
        {
          "time": "string",
          "power": 0,
          "temperature": 0
        }
      ],
      "yaxisMax": 0,
      "yaxisMin": 0
    }
  }
}
```

#### 设备控制-远程送电

**POST  /app/device/control/powerOn**
```
请求体:
{
  "deviceId": 0 // 设备ID
}

响应 data:
{
  "code": 0,
  "msg": "string",
  "data": {
    "success": true,
    "affectedDeviceCount": 0
  }
}
```


#### 设备控制-远程断电

**POST  /app/device/control/powerOff**
```
请求体:
{
  "deviceId": 0 // 设备ID
}

响应 data:
{
  "code": 0,
  "msg": "string",
  "data": {
    "success": true,
    "affectedDeviceCount": 0
  }
}
```


#### 设备拓扑

**POST  /app/device/topology**
```
请求体:
{
  "deviceId": 0 // 设备ID
}

响应 data:
{
  "code": 0,
  "msg": "string",
  "data": {
    "deviceInfo": {
      "deviceId": 0,
      "deviceName": "string",
      "deviceCode": "string",
      "locationText": "string"
    },
    "treeNodes": [
      {
        "deviceId": 0,
        "deviceName": "string",
        "deviceType": "string",
        "icon": "string",
        "status": "string",
        "statusText": "string",
        "deviceCode": "string"
      }
    ]
  }
}
```



























---
   


## 6. 注意事项

1. **Cubit 构造函数变更会破坏 View 层**：所有 `BlocProvider(create: (_) => XxxCubit())` 需要改为 `BlocProvider(create: (_) => XxxCubit(service: xxxService))`，AI 需同步修改 View 文件。

2. **State 中不需要 `isLoading/error` 的页面**：部分页面（如 `abnormal_cubit.dart`）的 State 没有 `isLoading` 字段，需要先添加，否则 loading 状态无法管理。

3. **路由参数传递**：某些页面通过路由参数获取 id（如 `AbnormalDetailRoute(id: xxx)`），Cubit 需要通过构造函数接收该 id 以调用 API。

4. **`Equatable` 缺失**：部分 State 类（如 `AbnormalListState`、`DeviceState`）没有 `extends Equatable`，需要补充。