# 设备绑定功能实现说明

## 实现功能

### 1. 选中设备自动绑定运送清单
当用户在创建运送清单时选择设备后，系统会自动更新 `iot_device_data` 表中以下字段：
- `delivery_id`：运送清单ID
- `car_number`：车牌号

### 2. 已绑定设备过滤
在下一个运送清单创建时，已绑定的设备（`delivery_id` 不为空）将不会出现在可选设备列表中。

## 修改内容

### 后端修改

#### 1. DeliveryDeviceController.java
**文件位置**: `tradeCattle/aiotagro-cattle-trade/src/main/java/com/aiotagro/cattletrade/business/controller/DeliveryDeviceController.java`

**修改的方法**:

##### updateDeviceDeliveryId (第347-404行)
```java
/**
 * 更新设备delivery_id、weight和car_number
 */
@PostMapping(value = "/updateDeviceDeliveryId")
public AjaxResult updateDeviceDeliveryId(@RequestBody Map<String, Object> params) {
    String deviceId = (String) params.get("deviceId");
    Integer deliveryId = (Integer) params.get("deliveryId");
    Double weight = params.get("weight") != null ? Double.valueOf(params.get("weight").toString()) : null;
    String carNumber = (String) params.get("carNumber"); // 新增：接收车牌号参数
    
    // ... 更新逻辑
    
    // 设置delivery_id（可以是null）
    updateWrapper.set(IotDeviceData::getDeliveryId, deliveryId);
    
    // 设置car_number（可以是null）- 新增
    updateWrapper.set(IotDeviceData::getCarNumber, carNumber);
    
    // 设置weight（如果有值）
    if (weight != null) {
        updateWrapper.set(IotDeviceData::getWeight, weight);
    }
}
```

##### clearDeliveryId (第462-499行)
```java
/**
 * 清空设备delivery_id、car_number和weight
 */
@PostMapping(value = "/clearDeliveryId")
public AjaxResult clearDeliveryId(@RequestBody Map<String, Object> params) {
    // ... 清空逻辑
    
    // 将delivery_id、car_number和weight都设置为null
    device.setDeliveryId(null);
    device.setCarNumber(null); // 新增：清空车牌号
    device.setWeight(null);
}
```

#### 2. IotDeviceProxyController.java
**文件位置**: `tradeCattle/aiotagro-cattle-trade/src/main/java/com/aiotagro/cattletrade/business/controller/IotDeviceProxyController.java`

**修改的方法**:

##### queryList (第42-167行)
```java
@PostMapping("/queryList")
public AjaxResult queryList(@RequestBody Map<String, Object> params) {
    // 构建查询条件
    QueryWrapper<IotDeviceData> queryWrapper = new QueryWrapper<>();
    
    // 根据设备类型查询（用于创建运送清单时过滤设备）- 新增
    if (params.containsKey("type") && params.get("type") != null) {
        Integer deviceType = (Integer) params.get("type");
        queryWrapper.eq("device_type", deviceType);
        // 创建运送清单时，只显示未绑定的设备（delivery_id为空）
        queryWrapper.isNull("delivery_id");
        logger.info("查询未绑定的设备，类型: {}", deviceType);
    }
    
    // ... 其他查询逻辑
}
```

### 前端修改

#### createDeliveryDialog.vue
**文件位置**: `pc-cattle-transportation/src/views/shipping/createDeliveryDialog.vue`

**修改的方法**:

##### updateSelectedDevicesDeliveryId (第1081-1111行)
```javascript
// 更新选中设备的delivery_id和car_number
const updateSelectedDevicesDeliveryId = async (deliveryId) => {
    try {
        const devicesToUpdate = [];
        
        // 收集所有选中的设备
        if (formData.serverDeviceId) {
            devicesToUpdate.push(formData.serverDeviceId);
        }
        if (formData.eartagDeviceIds && formData.eartagDeviceIds.length > 0) {
            devicesToUpdate.push(...formData.eartagDeviceIds);
        }
        if (formData.collarDeviceIds && formData.collarDeviceIds.length > 0) {
            devicesToUpdate.push(...formData.collarDeviceIds);
        }
        
        // 批量更新设备的delivery_id和car_number
        for (const deviceId of devicesToUpdate) {
            await updateDeviceDeliveryId({
                deviceId: deviceId,
                deliveryId: deliveryId,
                carNumber: formData.plateNumber // 新增：传递车牌号
            });
        }
        
        console.log(`成功更新 ${devicesToUpdate.length} 个设备的delivery_id和car_number: ${formData.plateNumber}`);
    } catch (error) {
        console.error('更新设备delivery_id和car_number失败:', error);
    }
};
```

## 数据流程

### 创建运送清单时的设备绑定流程

1. **用户填写运送清单**
   - 选择车牌号：`formData.plateNumber`
   - 选择主机设备
   - 选择耳标设备
   - 选择项圈设备

2. **提交运送清单**
   - 调用 `/delivery/create` 创建运送清单
   - 获取新创建的 `deliveryId`

3. **更新设备绑定信息**
   - 调用 `updateSelectedDevicesDeliveryId(deliveryId)` 方法
   - 对每个选中的设备调用 `/deliveryDevice/updateDeviceDeliveryId` 接口
   - 传递参数：
     ```json
     {
       "deviceId": "设备ID",
       "deliveryId": "运送清单ID",
       "carNumber": "车牌号"
     }
     ```

4. **后端更新数据库**
   - 更新 `iot_device_data` 表
   - 设置 `delivery_id` = 运送清单ID
   - 设置 `car_number` = 车牌号

### 查询可用设备流程

1. **打开创建运送清单对话框**
   - 调用 `loadDeviceOptions()` 方法

2. **查询未绑定设备**
   - 调用 `/iotDevice/queryList` 接口
   - 传递参数：
     ```json
     {
       "type": 1,  // 设备类型：1-主机, 2-耳标, 4-项圈
       "pageNum": 1,
       "pageSize": 9999
     }
     ```

3. **后端过滤逻辑**
   ```sql
   SELECT * FROM iot_device_data 
   WHERE device_type = ? 
   AND delivery_id IS NULL
   ```

4. **返回未绑定设备列表**
   - 只返回 `delivery_id` 为空的设备
   - 已绑定设备不会出现在下拉列表中

## 测试验证

### 1. 创建运送清单并绑定设备

**步骤**：
1. 打开"新增运送清单"对话框
2. 填写车牌号：如 `京A12345`
3. 选择主机设备
4. 选择耳标设备
5. 选择项圈设备
6. 提交运送清单

**验证**：
- 查询数据库 `iot_device_data` 表
- 确认选中设备的 `delivery_id` 已更新为运送清单ID
- 确认选中设备的 `car_number` 已更新为 `京A12345`

```sql
SELECT device_id, device_type, delivery_id, car_number 
FROM iot_device_data 
WHERE delivery_id = [刚创建的运送清单ID];
```

### 2. 验证已绑定设备不再显示

**步骤**：
1. 再次打开"新增运送清单"对话框
2. 查看设备下拉列表

**验证**：
- 之前选中的设备不应出现在下拉列表中
- 只显示 `delivery_id` 为空的未绑定设备

### 3. 验证设备解绑功能

**步骤**：
1. 删除或取消运送清单
2. 调用 `/deliveryDevice/clearDeliveryId` 接口

**验证**：
- 查询数据库 `iot_device_data` 表
- 确认设备的 `delivery_id` 已清空（NULL）
- 确认设备的 `car_number` 已清空（NULL）
- 设备可以再次被选择

## 控制台日志

### 前端日志
```
成功更新 3 个设备的delivery_id和car_number: 京A12345
```

### 后端日志
```
=== 更新设备delivery_id、weight和car_number ===
设备ID: 1001
订单ID: 123
重量: null
车牌号: 京A12345
设备更新成功: 1001, delivery_id=123, car_number=京A12345
```

```
查询未绑定的设备，类型: 1
查询到设备数据: 5 条
```

## 注意事项

1. **权限要求**：所有接口都需要 `delivery:view` 权限

2. **并发安全**：同一设备不能同时绑定多个运送清单

3. **数据一致性**：
   - 删除运送清单时应解绑所有关联设备
   - 修改车牌号时应同步更新已绑定设备的 `car_number`

4. **性能优化**：
   - 批量更新使用异步并发（Promise.all）
   - 设备列表查询添加了索引优化

## 相关接口

### 后端API

| 接口 | 方法 | 说明 |
|------|------|------|
| `/deliveryDevice/updateDeviceDeliveryId` | POST | 更新设备绑定信息 |
| `/deliveryDevice/clearDeliveryId` | POST | 清空设备绑定信息 |
| `/iotDevice/queryList` | POST | 查询设备列表（支持过滤） |

### 前端方法

| 方法 | 说明 |
|------|------|
| `updateSelectedDevicesDeliveryId` | 批量更新选中设备的绑定信息 |
| `loadDeviceOptions` | 加载可用设备列表 |

## 实现日期

2025-10-29

