1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
package com.mes.interaction.vehicle.flow;
 
import com.mes.device.entity.DeviceConfig;
import com.mes.device.service.DeviceInteractionService;
import com.mes.device.vo.DevicePlcVO;
import com.mes.interaction.DeviceInteraction;
import com.mes.interaction.base.InteractionContext;
import com.mes.interaction.base.InteractionResult;
import com.mes.interaction.vehicle.coordination.VehicleCoordinationService;
import com.mes.interaction.vehicle.coordination.VehicleStatusManager;
import com.mes.interaction.vehicle.model.VehicleState;
import com.mes.interaction.vehicle.model.VehiclePosition;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
 
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
/**
 * 大车设备交互实现(增强版)
 * 集成多车协调和状态管理功能
 * 
 * @author mes
 * @since 2025-01-XX
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class LoadVehicleInteraction implements DeviceInteraction {
 
    private final DeviceInteractionService deviceInteractionService;
    
    @Autowired
    private VehicleCoordinationService coordinationService;
    
    @Autowired
    private VehicleStatusManager statusManager;
 
    @Override
    public String getDeviceType() {
        return DeviceConfig.DeviceType.LOAD_VEHICLE;
    }
 
    @Override
    public InteractionResult execute(InteractionContext context) {
        try {
            // 前置条件验证
            if (context.getCurrentDevice() == null) {
                return InteractionResult.fail("设备配置不存在");
            }
 
            DeviceConfig currentDevice = context.getCurrentDevice();
            String deviceId = currentDevice.getDeviceId();
 
            // 1. 检查车辆状态(如果设备已指定)
            if (deviceId != null) {
                if (!statusManager.isVehicleAvailable(deviceId)) {
                    com.mes.interaction.vehicle.model.VehicleStatus status = 
                        statusManager.getVehicleStatus(deviceId);
                    String stateMsg = status != null ? status.getState().name() : "未知";
                    return InteractionResult.fail(
                        String.format("车辆 %s (%s) 当前状态为 %s,无法执行操作", 
                            currentDevice.getDeviceName(), deviceId, stateMsg));
                }
            }
 
            // 2. 如果没有指定设备,尝试从设备组中选择可用车辆
            DeviceConfig selectedDevice = currentDevice;
            Long groupId = extractGroupId(context);
            if (groupId != null && (deviceId == null || !statusManager.isVehicleAvailable(deviceId))) {
                DeviceConfig availableVehicle = coordinationService.selectAvailableVehicle(groupId);
                if (availableVehicle != null) {
                    selectedDevice = availableVehicle;
                    log.info("从设备组 {} 中选择可用车辆: {}", groupId, availableVehicle.getDeviceName());
                } else if (deviceId == null) {
                    // 没有可用车辆,返回等待结果
                    return InteractionResult.waitResult(
                        "设备组中没有可用的大车设备,等待车辆空闲", null);
                }
            }
 
            // 3. 验证玻璃ID
            List<String> glassIds = context.getParameters().getGlassIds();
            if (CollectionUtils.isEmpty(glassIds)) {
                return InteractionResult.waitResult("未提供玻璃ID,等待输入", null);
            }
 
            // 验证玻璃ID格式
            for (String glassId : glassIds) {
                if (glassId == null || glassId.trim().isEmpty()) {
                    return InteractionResult.fail("玻璃ID不能为空");
                }
            }
 
            // 4. 标记车辆为执行中
            String selectedDeviceId = selectedDevice.getDeviceId();
            statusManager.updateVehicleStatus(
                selectedDeviceId, 
                selectedDevice.getDeviceName(), 
                VehicleState.EXECUTING);
 
            try {
                // 5. 构建PLC写入参数
                Map<String, Object> params = new HashMap<>();
                params.put("glassIds", glassIds);
                params.put("positionCode", context.getParameters().getPositionCode());
                params.put("positionValue", context.getParameters().getPositionValue());
                params.put("triggerRequest", true);
 
                // 6. 执行实际的PLC写入操作
                DevicePlcVO.OperationResult plcResult = deviceInteractionService.executeOperation(
                        selectedDevice.getId(), 
                        "feedGlass", 
                        params
                );
 
                // 7. 检查PLC写入结果
                if (plcResult == null || !Boolean.TRUE.equals(plcResult.getSuccess())) {
                    String errorMsg = plcResult != null ? plcResult.getMessage() : "PLC写入操作返回空结果";
                    
                    // 执行失败,恢复为空闲状态
                    statusManager.updateVehicleStatus(selectedDeviceId, VehicleState.IDLE);
                    
                    return InteractionResult.fail("PLC写入失败: " + errorMsg);
                }
 
                // 8. 更新车辆位置信息(如果有)
                if (context.getParameters().getPositionCode() != null || 
                    context.getParameters().getPositionValue() != null) {
                    com.mes.interaction.vehicle.model.VehicleStatus vehicleStatus = 
                        statusManager.getOrCreateVehicleStatus(
                            selectedDeviceId, 
                            selectedDevice.getDeviceName());
                    VehiclePosition position = new VehiclePosition(
                        context.getParameters().getPositionCode(),
                        context.getParameters().getPositionValue());
                    vehicleStatus.setCurrentPosition(position);
                }
 
                // 9. 执行大车设备操作(数据流转)
                List<String> copied = new ArrayList<>(glassIds);
                context.setLoadedGlassIds(copied);
                context.getSharedData().put("glassesFromVehicle", copied);
                context.getSharedData().put("loadVehicleTime", System.currentTimeMillis());
                context.getSharedData().put("selectedVehicleId", selectedDeviceId);
                context.getSharedData().put("selectedVehicleName", selectedDevice.getDeviceName());
 
                // 10. 后置条件检查
                if (context.getLoadedGlassIds().isEmpty()) {
                    statusManager.updateVehicleStatus(selectedDeviceId, VehicleState.IDLE);
                    return InteractionResult.fail("大车设备操作失败:玻璃ID列表为空");
                }
 
                // 11. 构建返回数据
                Map<String, Object> data = new HashMap<>();
                data.put("loaded", copied);
                data.put("glassCount", copied.size());
                data.put("deviceId", selectedDevice.getId());
                data.put("deviceCode", selectedDevice.getDeviceCode());
                data.put("deviceName", selectedDevice.getDeviceName());
                data.put("deviceIdString", selectedDeviceId);
                data.put("plcResult", plcResult.getMessage());
                
                // 注意:这里不立即恢复为空闲状态,因为实际执行可能需要时间
                // 真正的状态恢复应该在任务完成后通过回调或状态查询来更新
                // 或者可以通过异步任务在后台监控PLC状态,确认完成后再恢复
                
                log.info("大车设备交互执行成功: deviceId={}, deviceName={}, glassCount={}", 
                    selectedDeviceId, selectedDevice.getDeviceName(), copied.size());
                
                return InteractionResult.success(data);
                
            } catch (Exception e) {
                // 发生异常时,恢复为空闲状态
                statusManager.updateVehicleStatus(selectedDeviceId, VehicleState.ERROR);
                log.error("大车设备交互执行异常: deviceId={}", selectedDeviceId, e);
                throw e;
            }
            
        } catch (Exception e) {
            return InteractionResult.fail("大车设备交互执行异常: " + e.getMessage());
        }
    }
 
    /**
     * 从上下文中提取设备组ID
     */
    private Long extractGroupId(InteractionContext context) {
        // 尝试从共享数据中获取
        Map<String, Object> sharedData = context.getSharedData();
        if (sharedData != null) {
            Object groupIdObj = sharedData.get("groupId");
            if (groupIdObj instanceof Number) {
                return ((Number) groupIdObj).longValue();
            } else if (groupIdObj instanceof String) {
                try {
                    return Long.parseLong((String) groupIdObj);
                } catch (NumberFormatException ignored) {
                }
            }
        }
        
        // 尝试从任务参数中获取
        if (context.getParameters() != null && context.getParameters().getExtra() != null) {
            Object groupIdObj = context.getParameters().getExtra().get("groupId");
            if (groupIdObj instanceof Number) {
                return ((Number) groupIdObj).longValue();
            }
        }
        
        return null;
    }
 
    @Override
    public boolean supportsOperation(String operation) {
        // 支持所有操作,但主要关注 feedGlass
        return true;
    }
}