From 8f3a85044b6e4b56a8dd0b104ca023933f1f129c Mon Sep 17 00:00:00 2001
From: huang <1532065656@qq.com>
Date: 星期三, 03 十二月 2025 16:58:36 +0800
Subject: [PATCH] 统一卧转立扫码、卧转立、大车、大理片笼的定时器逻辑和步骤状态;添加设备拓扑图清除数据、联机状态切换按钮,
---
mes-web/src/views/plcTest/components/MultiDeviceTest/ExecutionMonitor.vue | 4
mes-processes/mes-plcSend/src/main/java/com/mes/service/impl/PlcDynamicDataServiceImpl.java | 5
mes-processes/mes-plcSend/src/main/java/com/mes/interaction/vehicle/handler/LoadVehicleLogicHandler.java | 289 ++++++++----
mes-web/src/views/plcTest/MultiDeviceWorkbench.vue | 11
mes-processes/mes-plcSend/src/main/java/com/mes/interaction/workstation/transfer/handler/HorizontalTransferLogicHandler.java | 206 +++++++-
mes-web/src/views/plcTest/components/DeviceGroup/GroupTopology.vue | 203 ++++++++
mes-processes/mes-plcSend/src/main/java/com/mes/interaction/workstation/base/WorkstationBaseHandler.java | 4
mes-web/src/views/device/components/DeviceLogicConfig/LoadVehicleConfig.vue | 27
mes-processes/mes-plcSend/src/main/java/com/mes/interaction/workstation/scanner/handler/HorizontalScannerLogicHandler.java | 6
mes-processes/mes-plcSend/src/main/java/com/mes/task/service/TaskExecutionEngine.java | 456 ++++++++++++++----
mes-processes/mes-plcSend/src/main/java/com/mes/interaction/workstation/config/WorkstationLogicConfig.java | 5
mes-processes/mes-plcSend/src/main/java/com/mes/device/entity/GlassInfo.java | 4
mes-web/src/views/device/components/DeviceLogicConfig/WorkstationTransferConfig.vue | 50 -
mes-processes/mes-plcSend/src/main/java/com/mes/task/service/impl/TaskStatusNotificationServiceImpl.java | 1
mes-web/src/views/plcTest/components/MultiDeviceTest/TaskOrchestration.vue | 84 ---
15 files changed, 964 insertions(+), 391 deletions(-)
diff --git a/mes-processes/mes-plcSend/src/main/java/com/mes/device/entity/GlassInfo.java b/mes-processes/mes-plcSend/src/main/java/com/mes/device/entity/GlassInfo.java
index 754420b..bae1225 100644
--- a/mes-processes/mes-plcSend/src/main/java/com/mes/device/entity/GlassInfo.java
+++ b/mes-processes/mes-plcSend/src/main/java/com/mes/device/entity/GlassInfo.java
@@ -61,6 +61,10 @@
@TableField("description")
private String description;
+ @ApiModelProperty(value = "浜х嚎缂栧彿")
+ @TableField("work_line")
+ private Integer workLine;
+
@ApiModelProperty(value = "鍒涘缓鏃堕棿")
@TableField(value = "created_time", fill = FieldFill.INSERT)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
diff --git a/mes-processes/mes-plcSend/src/main/java/com/mes/interaction/vehicle/handler/LoadVehicleLogicHandler.java b/mes-processes/mes-plcSend/src/main/java/com/mes/interaction/vehicle/handler/LoadVehicleLogicHandler.java
index 2599607..62569ad 100644
--- a/mes-processes/mes-plcSend/src/main/java/com/mes/interaction/vehicle/handler/LoadVehicleLogicHandler.java
+++ b/mes-processes/mes-plcSend/src/main/java/com/mes/interaction/vehicle/handler/LoadVehicleLogicHandler.java
@@ -1,10 +1,12 @@
package com.mes.interaction.vehicle.handler;
import com.mes.device.entity.DeviceConfig;
+import com.mes.device.entity.DeviceStatus;
import com.mes.device.service.DeviceConfigService;
import com.mes.device.service.DeviceGroupRelationService;
import com.mes.device.service.DevicePlcOperationService;
import com.mes.device.service.GlassInfoService;
+import com.mes.device.service.DeviceStatusService;
import com.mes.device.vo.DeviceGroupVO;
import com.mes.device.vo.DevicePlcVO;
import com.mes.interaction.BaseDeviceLogicHandler;
@@ -49,6 +51,9 @@
@Autowired(required = false)
private DeviceGroupRelationService deviceGroupRelationService;
+
+ @Autowired(required = false)
+ private DeviceStatusService deviceStatusService;
@Autowired(required = false)
private PlcDynamicDataService plcDynamicDataService;
@@ -189,6 +194,9 @@
case "stopTaskMonitor":
result = handleStopTaskMonitor(deviceConfig);
break;
+ case "setOnlineState":
+ result = handleSetOnlineState(deviceConfig, params, logicParams);
+ break;
default:
log.warn("涓嶆敮鎸佺殑鎿嶄綔绫诲瀷: {}", operation);
result = DevicePlcVO.OperationResult.builder()
@@ -221,8 +229,14 @@
* 鍒ゆ柇鎿嶄綔鏄惁闇�瑕佺姸鎬佹鏌�
*/
private boolean needsStateCheck(String operation) {
- // 鎵�鏈夋搷浣滈兘闇�瑕佹鏌ョ姸鎬侊紝闄や簡鏌ヨ绫绘搷浣�
- return !"query".equals(operation) && !"status".equals(operation);
+ // 鎵�鏈夋搷浣滈兘闇�瑕佹鏌ョ姸鎬侊紝闄や簡鏌ヨ绫绘搷浣滃拰鐗瑰畾鍐呴儴妫�鏌�
+ if ("query".equals(operation) || "status".equals(operation)) {
+ return false;
+ }
+ if ("checkMesConfirm".equals(operation)) {
+ return false;
+ }
+ return true;
}
/**
@@ -302,23 +316,7 @@
// 浠庨�昏緫鍙傛暟涓幏鍙栭厤缃紙浠� extraParams.deviceLogic 璇诲彇锛�
Integer vehicleCapacity = getLogicParam(logicParams, "vehicleCapacity", 6000);
- // 浼樺厛浣跨敤杩愯鏃跺弬鏁颁腑鐨刧lassIntervalMs锛堜粠浠诲姟鍙傛暟浼犲叆锛夛紝濡傛灉娌℃湁鍒欎娇鐢ㄨ澶囬厤缃殑
- Integer glassIntervalMs = null;
- if (params.containsKey("glassIntervalMs") && params.get("glassIntervalMs") != null) {
- Object intervalObj = params.get("glassIntervalMs");
- if (intervalObj instanceof Number) {
- glassIntervalMs = ((Number) intervalObj).intValue();
- } else if (intervalObj instanceof String) {
- try {
- glassIntervalMs = Integer.parseInt((String) intervalObj);
- } catch (NumberFormatException e) {
- // 蹇界暐
- }
- }
- }
- if (glassIntervalMs == null) {
- glassIntervalMs = getLogicParam(logicParams, "glassIntervalMs", 1000);
- }
+ Integer glassGap = getLogicParam(logicParams, "glassGap", 200); // 鐜荤拑涔嬮棿鐨勭墿鐞嗛棿闅旓紙mm锛夛紝榛樿200mm
Boolean autoFeed = getLogicParam(logicParams, "autoFeed", true);
Integer maxRetryCount = getLogicParam(logicParams, "maxRetryCount", 5);
@@ -335,7 +333,7 @@
Integer positionValue = (Integer) params.get("positionValue");
Boolean triggerRequest = (Boolean) params.getOrDefault("triggerRequest", autoFeed);
- List<GlassInfo> plannedGlasses = planGlassLoading(glassInfos, vehicleCapacity,
+ List<GlassInfo> plannedGlasses = planGlassLoading(glassInfos, vehicleCapacity, glassGap,
deviceConfig.getDeviceId());
if (plannedGlasses == null) {
// 鐜荤拑娌℃湁闀垮害鏃惰繑鍥瀗ull琛ㄧず閿欒
@@ -371,17 +369,21 @@
}
payload.put("plcGlassCount", plcSlots);
- // 鍐欏叆浣嶇疆淇℃伅
+ // 鍐欏叆浣嶇疆淇℃伅锛歅LC渚ф湡鏈涚殑鏄� MES 缂栧彿锛堝1001/1002锛夛紝鑰屼笉鏄綅缃槧灏勫悗鐨勬牸瀛愬��
+ Integer plcPosition = null;
if (positionValue != null) {
- payload.put("inPosition", positionValue);
+ // 濡傛灉璋冪敤鏂圭洿鎺ヤ紶浜嗘暟鍊硷紝鍒欒涓鸿繖鏄疢ES缂栧彿锛岀洿鎺ュ啓鍏�
+ plcPosition = positionValue;
} else if (positionCode != null) {
- // 浠庝綅缃槧灏勪腑鑾峰彇浣嶇疆鍊�
- @SuppressWarnings("unchecked")
- Map<String, Integer> positionMapping = getLogicParam(logicParams, "positionMapping", new HashMap<>());
- Integer mappedValue = positionMapping.get(positionCode);
- if (mappedValue != null) {
- payload.put("inPosition", mappedValue);
+ // 灏濊瘯灏嗕綅缃唬鐮佽В鏋愪负鏁板瓧锛堜緥濡� "900" -> 900锛�
+ try {
+ plcPosition = Integer.parseInt(positionCode.trim());
+ } catch (NumberFormatException ignore) {
+ // 闈炴暟瀛楃紪鐮佹椂锛屼笉鍐欏叆inPosition锛岀敱PLC鎴栧悗缁�昏緫鑷澶勭悊
}
+ }
+ if (plcPosition != null) {
+ payload.put("inPosition", plcPosition);
}
// 鑷姩瑙﹀彂璇锋眰瀛�
@@ -401,11 +403,7 @@
DevicePlcVO.OperationResult result = devicePlcOperationService.writeFields(
deviceConfig.getId(), payload, operationName);
- // 娉ㄦ剰锛歡lassIntervalMs 鐨勭瓑寰呭簲璇ュ湪鎵规涔嬮棿锛堝湪TaskExecutionEngine涓鐞嗭級锛�
- // 鑰屼笉鏄湪杩欓噷绛夊緟锛屽洜涓鸿繖閲岀瓑寰呬細闃诲澶ц溅鐨勬甯歌鐜荤拑娴佺▼
- // 濡傛灉闇�瑕佸湪鍐欏叆鍚庣瓑寰咃紝搴旇鍦ㄦ壒娆′箣闂寸瓑寰咃紝璁╁ぇ杞︽湁鏃堕棿澶勭悊褰撳墠鎵规鐨勭幓鐠�
-
- // 濡傛灉鎵ц鎴愬姛锛屾洿鏂颁綅缃俊鎭埌鐘舵�侊紝骞跺惎鍔ㄧ姸鎬佺洃鎺�
+ // 濡傛灉鎵ц鎴愬姛锛屾洿鏂颁綅缃俊鎭埌鐘舵��
if (Boolean.TRUE.equals(result.getSuccess())) {
VehicleStatus status = statusManager.getOrCreateVehicleStatus(
deviceConfig.getDeviceId(), deviceConfig.getDeviceName());
@@ -413,9 +411,16 @@
VehiclePosition position = new VehiclePosition(positionCode, positionValue);
status.setCurrentPosition(position);
}
-
- // 鍚姩鑷姩鐘舵�佺洃鎺э紝褰� state=1 鏃惰嚜鍔ㄥ崗璋冨崸杞珛璁惧
- startStateMonitoring(deviceConfig, logicParams);
+
+ // 浠呭湪鈥滈潪澶氳澶囦换鍔♀�濆満鏅笅锛屾墠鍚姩澶ц溅鑷韩鐨勮嚜鍔ㄧ姸鎬佺洃鎺у拰 MES 浠诲姟鐩戞帶
+ boolean inMultiDeviceTask = params != null && params.containsKey("_taskContext");
+ if (!inMultiDeviceTask) {
+ // 鍚姩鑷姩鐘舵�佺洃鎺э紝褰� state=1 鏃惰嚜鍔ㄥ崗璋冨崸杞珛璁惧
+ startStateMonitoring(deviceConfig, logicParams);
+
+ // 浠� PLC/MES 鍒涘缓姝e紡浠诲姟骞跺惎鍔ㄧ洃鎺х殑閫昏緫锛屼繚鐣欑粰鐙珛 MES 鍦烘櫙浣跨敤
+ // 澶氳澶囦换鍔″満鏅笅锛岃繖閮ㄥ垎浜ょ敱 TaskExecutionEngine 缁熶竴缂栨帓
+ }
}
return result;
@@ -470,6 +475,7 @@
Map<String, Object> payload = new HashMap<>();
payload.put("plcRequest", 0);
payload.put("plcReport", 0);
+ payload.put("onlineState", Boolean.TRUE);
log.info("澶ц溅璁惧閲嶇疆: deviceId={}", deviceConfig.getId());
@@ -484,8 +490,65 @@
statusManager.clearVehicleTask(deviceConfig.getDeviceId());
statusManager.updateVehicleStatus(deviceConfig.getDeviceId(), VehicleState.IDLE);
stopStateMonitoring(deviceConfig.getDeviceId());
+ updateDeviceOnlineStatus(deviceConfig, true);
}
+ return result;
+ }
+
+ /**
+ * 璁剧疆鑱旀満鐘舵��
+ * @param deviceConfig 璁惧閰嶇疆
+ * @param params 鍙傛暟锛屽彲鍖呭惈 onlineState锛�1=鑱旀満锛�0=鑴辨満锛�
+ * @param logicParams 閫昏緫鍙傛暟
+ * @return 鎿嶄綔缁撴灉
+ */
+ private DevicePlcVO.OperationResult handleSetOnlineState(
+ DeviceConfig deviceConfig,
+ Map<String, Object> params,
+ Map<String, Object> logicParams) {
+
+ // 浠庡弬鏁颁腑鑾峰彇鑱旀満鐘舵�佸�硷紝榛樿涓簍rue锛堣仈鏈猴級
+ boolean onlineState = true;
+ if (params != null && params.containsKey("onlineState")) {
+ Object stateObj = params.get("onlineState");
+ if (stateObj instanceof Boolean) {
+ onlineState = (Boolean) stateObj;
+ } else if (stateObj instanceof Number) {
+ onlineState = ((Number) stateObj).intValue() != 0;
+ } else if (stateObj instanceof String) {
+ try {
+ String str = ((String) stateObj).trim();
+ if ("true".equalsIgnoreCase(str)) {
+ onlineState = true;
+ } else if ("false".equalsIgnoreCase(str)) {
+ onlineState = false;
+ } else {
+ onlineState = Integer.parseInt(str) != 0;
+ }
+ } catch (NumberFormatException e) {
+ log.warn("瑙f瀽onlineState澶辫触锛屼娇鐢ㄩ粯璁ゅ�紅rue: deviceId={}, value={}",
+ deviceConfig.getId(), stateObj);
+ }
+ }
+ }
+
+ Map<String, Object> payload = new HashMap<>();
+ payload.put("onlineState", onlineState);
+
+ String stateText = onlineState ? "鑱旀満" : "鑴辨満";
+ log.info("澶ц溅璁惧璁剧疆鑱旀満鐘舵��: deviceId={}, onlineState={} ({})",
+ deviceConfig.getId(), onlineState, stateText);
+
+ DevicePlcVO.OperationResult result = devicePlcOperationService.writeFields(
+ deviceConfig.getId(),
+ payload,
+ "澶ц溅璁惧-璁剧疆鑱旀満鐘舵��(" + stateText + ")"
+ );
+
+ if (Boolean.TRUE.equals(result.getSuccess())) {
+ updateDeviceOnlineStatus(deviceConfig, onlineState);
+ }
return result;
}
@@ -512,6 +575,7 @@
payload.put("plcGlassCount", 0);
payload.put("plcRequest", 0);
payload.put("plcReport", 0);
+ payload.put("onlineState", Boolean.TRUE);
if (params != null && params.containsKey("positionValue")) {
payload.put("inPosition", params.get("positionValue"));
@@ -532,9 +596,23 @@
statusManager.clearVehicleTask(deviceConfig.getDeviceId());
statusManager.updateVehicleStatus(deviceConfig.getDeviceId(), VehicleState.IDLE);
stopStateMonitoring(deviceConfig.getDeviceId());
+ updateDeviceOnlineStatus(deviceConfig, true);
}
return result;
+ }
+
+ private void updateDeviceOnlineStatus(DeviceConfig deviceConfig, boolean online) {
+ if (deviceStatusService == null || deviceConfig == null || deviceConfig.getId() == null) {
+ return;
+ }
+ try {
+ String status = online ? DeviceStatus.Status.ONLINE : DeviceStatus.Status.OFFLINE;
+ deviceStatusService.updateDeviceOnlineStatus(deviceConfig.getId(), status);
+ } catch (Exception e) {
+ log.warn("鍚屾璁惧鍦ㄧ嚎鐘舵�佸埌鏁版嵁搴撳け璐�: deviceId={}, online={}, error={}",
+ deviceConfig.getDeviceId(), online, e.getMessage());
+ }
}
private List<String> resolveGlassSlotFields(Map<String, Object> logicParams, int fallbackCount) {
@@ -572,9 +650,9 @@
return "杞﹁締瀹归噺(vehicleCapacity)蹇呴』澶т簬0";
}
- Integer glassIntervalMs = getLogicParam(logicParams, "glassIntervalMs", null);
- if (glassIntervalMs != null && glassIntervalMs < 0) {
- return "鐜荤拑闂撮殧鏃堕棿(glassIntervalMs)涓嶈兘涓鸿礋鏁�";
+ Integer glassGap = getLogicParam(logicParams, "glassGap", null);
+ if (glassGap != null && glassGap < 0) {
+ return "鐜荤拑闂撮殧(glassGap)涓嶈兘涓鸿礋鏁�";
}
return null; // 楠岃瘉閫氳繃
@@ -584,7 +662,7 @@
public String getDefaultLogicParams() {
Map<String, Object> defaultParams = new HashMap<>();
defaultParams.put("vehicleCapacity", 6000);
- defaultParams.put("glassIntervalMs", 1000);
+ defaultParams.put("glassGap", 200); // 鐜荤拑涔嬮棿鐨勭墿鐞嗛棿闅旓紙mm锛夛紝榛樿200mm
defaultParams.put("autoFeed", true);
defaultParams.put("maxRetryCount", 5);
defaultParams.put("defaultGlassLength", 2000);
@@ -687,16 +765,19 @@
/**
* 瑙勫垝鐜荤拑瑁呰浇
* @param source 婧愮幓鐠冨垪琛�
- * @param vehicleCapacity 杞﹁締瀹归噺
+ * @param vehicleCapacity 杞﹁締瀹归噺锛坢m锛�
+ * @param glassGap 鐜荤拑涔嬮棿鐨勭墿鐞嗛棿闅旓紙mm锛夛紝榛樿200mm
* @param deviceId 璁惧ID锛堢敤浜庢棩蹇楋級
* @return 瑙勫垝鍚庣殑鐜荤拑鍒楄〃锛屽鏋滅幓鐠冩病鏈夐暱搴﹀垯杩斿洖null锛堢敤浜庢祴璇昅ES绋嬪簭锛�
*/
private List<GlassInfo> planGlassLoading(List<GlassInfo> source,
int vehicleCapacity,
+ int glassGap,
String deviceId) {
List<GlassInfo> planned = new ArrayList<>();
int usedLength = 0;
int capacity = Math.max(vehicleCapacity, 1);
+ int gap = Math.max(glassGap, 0); // 纭繚闂撮殧涓嶄负璐熸暟
for (GlassInfo info : source) {
Integer glassLength = info.getLength();
@@ -711,17 +792,26 @@
int length = glassLength;
if (planned.isEmpty()) {
+ // 绗竴鍧楃幓鐠冿紝涓嶉渶瑕侀棿闅�
planned.add(info.withLength(length));
usedLength = length;
continue;
}
- if (usedLength + length <= capacity) {
+
+ // 鍚庣画鐜荤拑闇�瑕佽�冭檻闂撮殭锛氱幓鐠冮暱搴� + 闂撮殭
+ int requiredLength = length + gap;
+ if (usedLength + requiredLength <= capacity) {
planned.add(info.withLength(length));
- usedLength += length;
+ usedLength += requiredLength; // 鍖呭惈闂撮殭
} else {
+ // 瑁呬笉涓嬩簡锛屽仠姝㈡坊鍔�
break;
}
}
+
+ log.debug("鐜荤拑瑁呰浇瑙勫垝: deviceId={}, total={}, planned={}, usedLength={}, capacity={}, glassGap={}",
+ deviceId, source.size(), planned.size(), usedLength, capacity, gap);
+
return planned;
}
@@ -1626,65 +1716,80 @@
log.info("宸茬粰MES姹囨姤({}浠诲姟): deviceId={}, glassId={}",
taskType, deviceConfig.getDeviceId(), taskInfo.glassId);
- // 绛夊緟MES纭
- waitForMesConfirm(deviceConfig, serializer, taskInfo, logicParams);
-
+ // 澶氳澶囦换鍔″満鏅笅锛屼笉鍦ㄨ繖閲岄樆濉炵瓑寰匨ES纭锛岀敱浠诲姟寮曟搸瀹氭椂璋冪敤checkMesConfirm
} catch (Exception e) {
log.error("缁橫ES姹囨姤寮傚父: deviceId={}", deviceConfig.getDeviceId(), e);
}
}
/**
- * 绛夊緟MES纭
+ * 妫�鏌ES纭鐘舵�侊紙渚涗换鍔″紩鎿庡懆鏈熸�ц皟鐢級
+ * 杩斿洖OperationResult.data涓殑 completed 鏍囧織琛ㄧず鏄惁宸茬‘璁ゅ畬鎴�
*/
- private void waitForMesConfirm(DeviceConfig deviceConfig,
- EnhancedS7Serializer serializer,
- MesTaskInfo taskInfo,
- Map<String, Object> logicParams) {
-
+ public DevicePlcVO.OperationResult checkMesConfirm(DeviceConfig deviceConfig,
+ Map<String, Object> logicParams) {
+ if (plcDynamicDataService == null || s7SerializerProvider == null) {
+ return DevicePlcVO.OperationResult.builder()
+ .success(false)
+ .message("PlcDynamicDataService鎴朣7SerializerProvider鏈敞鍏�")
+ .build();
+ }
+ EnhancedS7Serializer serializer = s7SerializerProvider.getSerializer(deviceConfig);
+ if (serializer == null) {
+ return DevicePlcVO.OperationResult.builder()
+ .success(false)
+ .message("鑾峰彇PLC搴忓垪鍖栧櫒澶辫触")
+ .build();
+ }
+
+ Map<String, Object> data = new HashMap<>();
try {
- // 璇诲彇纭瀛楋紙鍋囪瀛楁鍚嶄负mesConfirm锛�
- Integer maxWaitTime = getLogicParam(logicParams, "mesConfirmTimeoutMs", 30000); // 榛樿30绉�
- long startTime = System.currentTimeMillis();
-
- while (System.currentTimeMillis() - startTime < maxWaitTime) {
- Object confirmValue = plcDynamicDataService.readPlcField(
- deviceConfig, "mesConfirm", serializer);
- Integer confirm = parseInteger(confirmValue);
-
- if (confirm != null && confirm == 1) {
- // MES宸茬‘璁わ紝娓呯┖state鍜屾眹鎶ュ瓧
- clearTaskStates(deviceConfig, serializer);
-
- // 浠诲姟瀹屾垚锛屾仮澶嶄负绌洪棽鐘舵��
- statusManager.updateVehicleStatus(
- deviceConfig.getDeviceId(), VehicleState.IDLE);
- statusManager.clearVehicleTask(deviceConfig.getDeviceId());
-
- // 绉婚櫎浠诲姟
- currentTasks.remove(deviceConfig.getDeviceId());
-
- // 鍋滄浠诲姟鐩戞帶
- handleStopTaskMonitor(deviceConfig);
-
- // 鎭㈠plcRequest=1锛堝彲浠ユ帴鏀舵柊浠诲姟锛�
- Map<String, Object> payload = new HashMap<>();
- payload.put("plcRequest", 1);
- plcDynamicDataService.writePlcData(deviceConfig, payload, serializer);
-
- log.info("MES浠诲姟宸插畬鎴�: deviceId={}, glassId={}",
- deviceConfig.getDeviceId(), taskInfo.glassId);
- return;
- }
-
- Thread.sleep(500); // 绛夊緟500ms鍚庨噸璇�
+ Object confirmValue = plcDynamicDataService.readPlcField(
+ deviceConfig, "mesConfirm", serializer);
+ Integer confirm = parseInteger(confirmValue);
+ boolean completed = confirm != null && confirm == 1;
+ data.put("completed", completed);
+
+ if (completed) {
+ // MES宸茬‘璁わ紝娓呯┖state鍜屾眹鎶ュ瓧
+ clearTaskStates(deviceConfig, serializer);
+
+ // 浠诲姟瀹屾垚锛屾仮澶嶄负绌洪棽鐘舵��
+ statusManager.updateVehicleStatus(
+ deviceConfig.getDeviceId(), VehicleState.IDLE);
+ statusManager.clearVehicleTask(deviceConfig.getDeviceId());
+
+ // 绉婚櫎浠诲姟璁板綍锛堝鏋滄湁锛�
+ currentTasks.remove(deviceConfig.getDeviceId());
+
+ // 鍋滄浠诲姟鐩戞帶
+ handleStopTaskMonitor(deviceConfig);
+
+ // 鎭㈠plcRequest=1锛堝彲浠ユ帴鏀舵柊浠诲姟锛�
+ Map<String, Object> payload = new HashMap<>();
+ payload.put("plcRequest", 1);
+ plcDynamicDataService.writePlcData(deviceConfig, payload, serializer);
+
+ log.info("MES浠诲姟宸茬‘璁ゅ畬鎴�: deviceId={}", deviceConfig.getDeviceId());
+ return DevicePlcVO.OperationResult.builder()
+ .success(true)
+ .message("MES浠诲姟宸茬‘璁ゅ畬鎴�")
+ .data(data)
+ .build();
}
-
- log.warn("绛夊緟MES纭瓒呮椂: deviceId={}, glassId={}",
- deviceConfig.getDeviceId(), taskInfo.glassId);
-
+
+ return DevicePlcVO.OperationResult.builder()
+ .success(true)
+ .message("绛夊緟MES纭涓�")
+ .data(data)
+ .build();
} catch (Exception e) {
- log.error("绛夊緟MES纭寮傚父: deviceId={}", deviceConfig.getDeviceId(), e);
+ log.error("妫�鏌ES纭鐘舵�佸紓甯�: deviceId={}", deviceConfig.getDeviceId(), e);
+ return DevicePlcVO.OperationResult.builder()
+ .success(false)
+ .message("妫�鏌ES纭鐘舵�佸紓甯�: " + e.getMessage())
+ .data(data)
+ .build();
}
}
diff --git a/mes-processes/mes-plcSend/src/main/java/com/mes/interaction/workstation/base/WorkstationBaseHandler.java b/mes-processes/mes-plcSend/src/main/java/com/mes/interaction/workstation/base/WorkstationBaseHandler.java
index 509e405..96c37b7 100644
--- a/mes-processes/mes-plcSend/src/main/java/com/mes/interaction/workstation/base/WorkstationBaseHandler.java
+++ b/mes-processes/mes-plcSend/src/main/java/com/mes/interaction/workstation/base/WorkstationBaseHandler.java
@@ -38,6 +38,7 @@
config.setScanIntervalMs(getLogicParam(logicParams, "scanIntervalMs", 10_000));
config.setTransferDelayMs(getLogicParam(logicParams, "transferDelayMs", 30_000));
config.setVehicleCapacity(getLogicParam(logicParams, "vehicleCapacity", 6000));
+ config.setGlassGap(getLogicParam(logicParams, "glassGap", 200));
return config;
}
@@ -68,10 +69,11 @@
defaults.put("scanIntervalMs", 10_000);
defaults.put("transferDelayMs", 30_000);
defaults.put("vehicleCapacity", 6_000);
+ defaults.put("glassGap", 200);
try {
return objectMapper.writeValueAsString(defaults);
} catch (JsonProcessingException e) {
- return "{\"scanIntervalMs\":10000,\"transferDelayMs\":30000,\"vehicleCapacity\":6000}";
+ return "{\"scanIntervalMs\":10000,\"transferDelayMs\":30000,\"vehicleCapacity\":6000,\"glassGap\":200}";
}
}
}
diff --git a/mes-processes/mes-plcSend/src/main/java/com/mes/interaction/workstation/config/WorkstationLogicConfig.java b/mes-processes/mes-plcSend/src/main/java/com/mes/interaction/workstation/config/WorkstationLogicConfig.java
index 0bbfd9a..990be5a 100644
--- a/mes-processes/mes-plcSend/src/main/java/com/mes/interaction/workstation/config/WorkstationLogicConfig.java
+++ b/mes-processes/mes-plcSend/src/main/java/com/mes/interaction/workstation/config/WorkstationLogicConfig.java
@@ -23,5 +23,10 @@
* 鍙杞界殑鏈�澶у搴︼紙mm锛�
*/
private Integer vehicleCapacity = 6_000;
+
+ /**
+ * 鐜荤拑涔嬮棿鐨勭墿鐞嗛棿闅旓紙mm锛�
+ */
+ private Integer glassGap = 200;
}
diff --git a/mes-processes/mes-plcSend/src/main/java/com/mes/interaction/workstation/scanner/handler/HorizontalScannerLogicHandler.java b/mes-processes/mes-plcSend/src/main/java/com/mes/interaction/workstation/scanner/handler/HorizontalScannerLogicHandler.java
index 71ad7f1..7e25e57 100644
--- a/mes-processes/mes-plcSend/src/main/java/com/mes/interaction/workstation/scanner/handler/HorizontalScannerLogicHandler.java
+++ b/mes-processes/mes-plcSend/src/main/java/com/mes/interaction/workstation/scanner/handler/HorizontalScannerLogicHandler.java
@@ -112,6 +112,8 @@
if (mesData == null || mesData.isEmpty()) {
log.error("绛夊緟MES鍐欏叆鐜荤拑淇℃伅瓒呮椂: deviceId={}, timeout={}ms",
deviceConfig.getId(), config.getScanIntervalMs());
+ // 瓒呮椂涔熻娓呯┖plcRequest
+ clearPlcRequestFields(deviceConfig, serializer);
return buildResult(deviceConfig, "scanOnce", false,
String.format("绛夊緟MES鍐欏叆鐜荤拑淇℃伅瓒呮椂(%dms)", config.getScanIntervalMs()), null);
}
@@ -119,6 +121,8 @@
// 3. 璇诲彇MES鍥炲啓鐨勭幓鐠冧俊鎭�
String glassId = parseString(mesData.get("mesGlassId"));
if (!StringUtils.hasText(glassId)) {
+ // MES鏈彁渚涚幓鐠僆D涔熻娓呯┖plcRequest
+ clearPlcRequestFields(deviceConfig, serializer);
return buildResult(deviceConfig, "scanOnce", false, "MES鍐欏尯鏈彁渚涚幓鐠僆D", null);
}
// 璇诲彇MES灏哄鏁版嵁锛歮esWidth=琛ㄥ锛宮esHeight=闀�
@@ -276,7 +280,7 @@
}
glassInfo.setStatus(GlassInfo.Status.PENDING);
if (workLine != null) {
- glassInfo.setDescription("workLine=" + workLine);
+ glassInfo.setWorkLine(workLine);
}
Date now = new Date();
glassInfo.setCreatedTime(now);
diff --git a/mes-processes/mes-plcSend/src/main/java/com/mes/interaction/workstation/transfer/handler/HorizontalTransferLogicHandler.java b/mes-processes/mes-plcSend/src/main/java/com/mes/interaction/workstation/transfer/handler/HorizontalTransferLogicHandler.java
index c942e41..b5d7d50 100644
--- a/mes-processes/mes-plcSend/src/main/java/com/mes/interaction/workstation/transfer/handler/HorizontalTransferLogicHandler.java
+++ b/mes-processes/mes-plcSend/src/main/java/com/mes/interaction/workstation/transfer/handler/HorizontalTransferLogicHandler.java
@@ -16,9 +16,8 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
-import org.springframework.util.StringUtils;
-import javax.annotation.PreDestroy;
+import javax.annotation.PreDestroy;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.*;
@@ -92,6 +91,8 @@
return handleStopMonitor(deviceConfig);
case "clearBuffer":
return handleClearBuffer(deviceConfig);
+ case "clearPlc":
+ return handleClearPlc(deviceConfig);
default:
return buildResult(deviceConfig, operation, false,
"涓嶆敮鎸佺殑鎿嶄綔: " + operation);
@@ -124,46 +125,66 @@
try {
// 1. 浠庢暟鎹簱鏌ヨ鏈�杩戞壂鐮佺殑鐜荤拑淇℃伅锛堟渶杩�1鍒嗛挓鍐呯殑璁板綍锛�
List<GlassInfo> recentGlasses = queryRecentScannedGlasses(deviceConfig, logicParams);
- if (recentGlasses.isEmpty()) {
- return buildResult(deviceConfig, "checkAndProcess", true,
- "鏆傛棤寰呭鐞嗙殑鐜荤拑淇℃伅");
+ boolean hasNewGlass = false;
+
+ if (!recentGlasses.isEmpty()) {
+ log.info("鏌ヨ鍒版渶杩戞壂鐮佺殑鐜荤拑: deviceId={}, count={}",
+ deviceId, recentGlasses.size());
+
+ // 2. 鏇存柊缂撳啿闃熷垪锛涗粎鍦ㄦ湁鈥滄柊鐜荤拑鈥濆姞鍏ョ紦鍐叉椂鎵嶆洿鏂版渶鍚庢壂鐮佹椂闂�
+ hasNewGlass = updateBuffer(deviceId, recentGlasses);
+ if (hasNewGlass) {
+ lastScanTime
+ .computeIfAbsent(deviceId, k -> new AtomicLong())
+ .set(System.currentTimeMillis());
+ }
+ } else {
+ log.debug("鏈煡璇㈠埌鏈�杩戞壂鐮佺殑鐜荤拑: deviceId={}", deviceId);
}
- log.info("鏌ヨ鍒版渶杩戞壂鐮佺殑鐜荤拑: deviceId={}, count={}",
- deviceId, recentGlasses.size());
-
- // 2. 鏇存柊缂撳啿闃熷垪锛涗粎鍦ㄦ湁鈥滄柊鐜荤拑鈥濆姞鍏ョ紦鍐叉椂鎵嶆洿鏂版渶鍚庢壂鐮佹椂闂�
- boolean hasNewGlass = updateBuffer(deviceId, recentGlasses);
- if (hasNewGlass) {
- lastScanTime
- .computeIfAbsent(deviceId, k -> new AtomicLong())
- .set(System.currentTimeMillis());
- }
-
- // 3. 妫�鏌ユ槸鍚﹂渶瑕佺珛鍗冲鐞嗭紙瀹归噺宸叉弧鎴�30s鍐呮棤鏂扮幓鐠冿級
+ // 3. 妫�鏌ョ紦鍐查槦鍒楋紙鍗充娇鏌ヨ涓嶅埌鏂扮幓鐠冿紝缂撳啿涓彲鑳借繕鏈夊緟澶勭悊鐨勭幓鐠冿級
List<GlassBufferItem> buffer = glassBuffer.get(deviceId);
if (buffer == null || buffer.isEmpty()) {
+ // 缂撳啿涓虹┖涓旀棤鏂扮幓鐠冿紝杩斿洖绌虹姸鎬�
return buildResult(deviceConfig, "checkAndProcess", true,
- "缂撳啿闃熷垪涓虹┖");
+ "缂撳啿闃熷垪涓虹┖锛屾棤寰呭鐞嗙幓鐠�");
}
// 4. 鍒ゆ柇鏄惁婊¤冻澶勭悊鏉′欢
boolean shouldProcess = shouldProcessBatch(deviceId, buffer, config);
if (!shouldProcess) {
- return buildResult(deviceConfig, "checkAndProcess", true,
- "绛夊緟鏇村鐜荤拑鎴�30s瓒呮椂");
+ // 鏈弧瓒冲鐞嗘潯浠讹細鏋勯�犲甫鏈夌瓑寰呰繘搴︾殑鎻愮ず淇℃伅锛屼究浜庡墠绔睍绀�
+ String waitMessage;
+ AtomicLong lastTime = lastScanTime.get(deviceId);
+ Integer delayMs = config.getTransferDelayMs();
+ if (lastTime != null && delayMs != null && delayMs > 0) {
+ long elapsedMs = System.currentTimeMillis() - lastTime.get();
+ if (elapsedMs < 0) {
+ elapsedMs = 0;
+ }
+ long totalMs = delayMs;
+ long elapsedSec = elapsedMs / 1000;
+ long totalSec = totalMs / 1000;
+ waitMessage = String.format("绛夊緟鏇村鐜荤拑鎴栬秴鏃惰Е鍙戞壒娆″鐞� (宸茬瓑寰� %d/%d 绉�)",
+ elapsedSec, totalSec);
+ } else {
+ // 娌℃湁鏈夋晥鐨勬渶鍚庢壂鐮佹椂闂存垨閰嶇疆锛岄��鍥炲埌鍥哄畾鎻愮ず
+ waitMessage = "绛夊緟鏇村鐜荤拑鎴�30s瓒呮椂";
+ }
+ return buildResult(deviceConfig, "checkAndProcess", true, waitMessage);
}
- // 5. 瀹归噺鍒ゆ柇鍜屾壒娆$粍瑁�
- List<GlassInfo> batch = assembleBatch(buffer, config.getVehicleCapacity());
+ // 5. 瀹归噺鍒ゆ柇鍜屾壒娆$粍瑁咃紙鑰冭檻鐜荤拑闂撮殭锛�
+ Integer glassGap = getLogicParam(logicParams, "glassGap", 200); // 鐜荤拑涔嬮棿鐨勭墿鐞嗛棿闅旓紙mm锛夛紝榛樿200mm
+ List<GlassInfo> batch = assembleBatch(buffer, config.getVehicleCapacity(), glassGap);
if (batch.isEmpty()) {
return buildResult(deviceConfig, "checkAndProcess", false,
"鏃犳硶缁勮鏈夋晥鎵规锛堝閲忎笉瓒筹級");
}
- // 6. 鍐欏叆PLC
+ // 6. 鍐欏叆PLC锛堝皾璇曚粠浠诲姟鍙傛暟涓幏鍙栧崸杞珛缂栧彿锛�
DevicePlcVO.OperationResult writeResult = writeBatchToPlc(
- deviceConfig, batch, serializer, logicParams);
+ deviceConfig, batch, serializer, logicParams, params);
if (!Boolean.TRUE.equals(writeResult.getSuccess())) {
return writeResult;
@@ -198,9 +219,23 @@
batch.stream().map(GlassInfo::getGlassId).collect(Collectors.toList()),
GlassInfo.Status.PROCESSED);
- String msg = String.format("鎵规宸插啓鍏LC: glassCount=%d, glassIds=%s",
- batch.size(),
- batch.stream().map(GlassInfo::getGlassId).collect(Collectors.joining(",")));
+ // 8. 妫�鏌ョ紦鍐叉槸鍚︿负绌猴紝濡傛灉涓虹┖涓旀棤鏂扮幓鐠冿紝鏍囪涓哄畬鎴�
+ List<GlassBufferItem> remainingBuffer = glassBuffer.get(deviceId);
+ boolean bufferEmpty = remainingBuffer == null || remainingBuffer.isEmpty();
+ boolean noNewGlass = !hasNewGlass;
+
+ String msg;
+ if (bufferEmpty && noNewGlass) {
+ // 缂撳啿宸叉竻绌轰笖鏃犳柊鐜荤拑锛屼换鍔″畬鎴�
+ msg = String.format("鎵规宸插啓鍏LC: glassCount=%d, glassIds=%s, 缂撳啿宸叉竻绌猴紝浠诲姟瀹屾垚",
+ batch.size(),
+ batch.stream().map(GlassInfo::getGlassId).collect(Collectors.joining(",")));
+ } else {
+ // 缂撳啿杩樻湁鐜荤拑鎴栧彲鑳芥湁鏂扮幓鐠冿紝缁х画杩愯
+ msg = String.format("鎵规宸插啓鍏LC: glassCount=%d, glassIds=%s",
+ batch.size(),
+ batch.stream().map(GlassInfo::getGlassId).collect(Collectors.joining(",")));
+ }
return buildResult(deviceConfig, "checkAndProcess", true, msg);
} catch (Exception e) {
@@ -223,8 +258,8 @@
}
try {
- // 浠庨厤缃腑鑾峰彇workLine锛岀敤浜庤繃婊�
- String workLine = getLogicParam(logicParams, "workLine", null);
+ // 浠庨厤缃腑鑾峰彇workLine锛岀敤浜庤繃婊わ紙閰嶇疆涓槸Integer绫诲瀷锛�
+ Integer workLine = getLogicParam(logicParams, "workLine", null);
// 鏌ヨ鏈�杩�2鍒嗛挓鍐呯殑鐜荤拑璁板綍锛堟墿澶ф椂闂寸獥鍙o紝纭繚涓嶉仐婕忥級
Date twoMinutesAgo = new Date(System.currentTimeMillis() - 120000);
@@ -235,9 +270,9 @@
.orderByDesc(GlassInfo::getCreatedTime)
.last("LIMIT 20"); // 闄愬埗鏌ヨ鏁伴噺锛岄伩鍏嶈繃澶�
- // 濡傛灉閰嶇疆浜唚orkLine锛屽垯杩囨护description
- if (workLine != null && !workLine.isEmpty()) {
- wrapper.like(GlassInfo::getDescription, "workLine=" + workLine);
+ // 濡傛灉閰嶇疆浜唚orkLine锛屽垯杩囨护work_line瀛楁
+ if (workLine != null) {
+ wrapper.eq(GlassInfo::getWorkLine, workLine);
}
List<GlassInfo> recentGlasses = glassInfoMapper.selectList(wrapper);
@@ -280,17 +315,21 @@
/**
* 鍒ゆ柇鏄惁搴旇澶勭悊鎵规
+ * 娉ㄦ剰锛氳繖閲屽彧鍋氱矖鐣ュ垽鏂紝绮剧‘鐨勫閲忚绠楋紙鍚棿闅欙級鍦╝ssembleBatch涓畬鎴�
*/
private boolean shouldProcessBatch(String deviceId,
List<GlassBufferItem> buffer,
WorkstationLogicConfig config) {
// 鏉′欢1锛氱紦鍐查槦鍒楀凡婊★紙杈惧埌瀹归噺闄愬埗锛�
+ // 绮楃暐璁$畻锛氭墍鏈夌幓鐠冮暱搴︿箣鍜岋紙涓嶈�冭檻闂撮殭锛屽洜涓洪棿闅欐槸鍔ㄦ�佺殑锛�
int totalLength = buffer.stream()
.mapToInt(item -> item.glassInfo.getGlassLength() != null ?
item.glassInfo.getGlassLength() : 0)
.sum();
- if (totalLength >= config.getVehicleCapacity()) {
- log.info("缂撳啿闃熷垪瀹归噺宸叉弧锛岃Е鍙戞壒娆″鐞�: deviceId={}, totalLength={}, capacity={}",
+ // 绮楃暐鍒ゆ柇锛氬鏋滄�婚暱搴︽帴杩戝閲忥紙鐣欎竴浜涗綑閲忕粰闂撮殭锛夛紝灏辫Е鍙戝鐞�
+ // 绮剧‘鍒ゆ柇浼氬湪assembleBatch涓畬鎴�
+ if (totalLength >= config.getVehicleCapacity() * 0.8) { // 80%闃堝�硷紝鐣欎綑閲忕粰闂撮殭
+ log.info("缂撳啿闃熷垪瀹归噺鎺ヨ繎婊¤浇锛岃Е鍙戞壒娆″鐞�: deviceId={}, totalLength={}, capacity={}",
deviceId, totalLength, config.getVehicleCapacity());
return true;
}
@@ -310,25 +349,50 @@
}
/**
- * 缁勮鎵规锛堝閲忓垽鏂級
+ * 缁勮鎵规锛堝閲忓垽鏂紝鑰冭檻鐜荤拑闂撮殭锛�
+ * @param buffer 缂撳啿闃熷垪
+ * @param vehicleCapacity 杞﹁締瀹归噺锛坢m锛�
+ * @param glassGap 鐜荤拑涔嬮棿鐨勭墿鐞嗛棿闅旓紙mm锛夛紝榛樿200mm
+ * @return 缁勮濂界殑鎵规鍒楄〃
*/
private List<GlassInfo> assembleBatch(List<GlassBufferItem> buffer,
- int vehicleCapacity) {
+ int vehicleCapacity,
+ int glassGap) {
List<GlassInfo> batch = new ArrayList<>();
int usedLength = 0;
+ int gap = Math.max(glassGap, 0); // 纭繚闂撮殧涓嶄负璐熸暟
for (GlassBufferItem item : buffer) {
GlassInfo glass = item.glassInfo;
int glassLength = glass.getGlassLength() != null ?
glass.getGlassLength() : 0;
- if (usedLength + glassLength <= vehicleCapacity && batch.size() < 6) {
- batch.add(glass);
- usedLength += glassLength;
+ if (glassLength <= 0) {
+ continue; // 璺宠繃鏃犳晥闀垮害鐨勭幓鐠�
+ }
+
+ if (batch.isEmpty()) {
+ // 绗竴鍧楃幓鐠冿紝涓嶉渶瑕侀棿闅�
+ if (glassLength <= vehicleCapacity && batch.size() < 6) {
+ batch.add(glass);
+ usedLength = glassLength;
+ } else {
+ break; // 绗竴鍧楀氨瑁呬笉涓�
+ }
} else {
- break;
+ // 鍚庣画鐜荤拑闇�瑕佽�冭檻闂撮殭锛氱幓鐠冮暱搴� + 闂撮殭
+ int requiredLength = glassLength + gap;
+ if (usedLength + requiredLength <= vehicleCapacity && batch.size() < 6) {
+ batch.add(glass);
+ usedLength += requiredLength; // 鍖呭惈闂撮殭
+ } else {
+ break; // 瑁呬笉涓嬩簡
+ }
}
}
+
+ log.debug("鎵规缁勮瀹屾垚: batchSize={}, usedLength={}, capacity={}, glassGap={}",
+ batch.size(), usedLength, vehicleCapacity, gap);
return batch;
}
@@ -340,7 +404,8 @@
DeviceConfig deviceConfig,
List<GlassInfo> batch,
EnhancedS7Serializer serializer,
- Map<String, Object> logicParams) {
+ Map<String, Object> logicParams,
+ Map<String, Object> params) {
Map<String, Object> payload = new HashMap<>();
@@ -354,10 +419,33 @@
// 鍐欏叆鐜荤拑鏁伴噺
payload.put("plcGlassCount", count);
- // 鍐欏叆浣嶇疆淇℃伅锛堝鏋滄湁閰嶇疆锛�
- Integer inPosition = getLogicParam(logicParams, "inPosition", null);
+ // 鍐欏叆鍗ц浆绔嬬紪鍙凤紙浼樺厛浠庝换鍔″弬鏁拌幏鍙栵紝鍏舵浠庤澶囬厤缃幏鍙栵級
+ Integer inPosition = null;
+ if (params != null) {
+ try {
+ Object ctxObj = params.get("_taskContext");
+ if (ctxObj instanceof com.mes.task.model.TaskExecutionContext) {
+ com.mes.task.model.TaskExecutionContext ctx =
+ (com.mes.task.model.TaskExecutionContext) ctxObj;
+ Object positionObj = ctx.getParameters().getExtra() != null
+ ? ctx.getParameters().getExtra().get("inPosition") : null;
+ if (positionObj instanceof Number) {
+ inPosition = ((Number) positionObj).intValue();
+ }
+ }
+ } catch (Exception e) {
+ log.debug("浠庝换鍔″弬鏁拌幏鍙栧崸杞珛缂栧彿澶辫触: deviceId={}", deviceConfig.getId(), e);
+ }
+ }
+ // 濡傛灉浠诲姟鍙傛暟涓病鏈夛紝浠庤澶囬厤缃腑鑾峰彇
+ if (inPosition == null) {
+ inPosition = getLogicParam(logicParams, "inPosition", null);
+ }
if (inPosition != null) {
payload.put("inPosition", inPosition);
+ log.info("鍐欏叆鍗ц浆绔嬬紪鍙�: deviceId={}, inPosition={}", deviceConfig.getId(), inPosition);
+ } else {
+ log.debug("鏈厤缃崸杞珛缂栧彿锛岃烦杩囧啓鍏�: deviceId={}", deviceConfig.getId());
}
// 鍐欏叆璇锋眰瀛楋紙瑙﹀彂澶ц溅锛�
@@ -365,8 +453,8 @@
try {
plcDynamicDataService.writePlcData(deviceConfig, payload, serializer);
- log.info("鎵规宸插啓鍏LC: deviceId={}, glassCount={}",
- deviceConfig.getId(), count);
+ log.info("鎵规宸插啓鍏LC: deviceId={}, glassCount={}, inPosition={}",
+ deviceConfig.getId(), count, inPosition);
return buildResult(deviceConfig, "writeBatchToPlc", true,
"鎵规鍐欏叆鎴愬姛");
} catch (Exception e) {
@@ -450,6 +538,34 @@
log.info("宸叉竻绌虹紦鍐查槦鍒�: deviceId={}", deviceId);
return buildResult(deviceConfig, "clearBuffer", true, "缂撳啿闃熷垪宸叉竻绌�");
}
+
+ /**
+ * 娓呯┖PLC鐩稿叧瀛楁锛堜緵娴嬭瘯椤甸潰涓�閿竻绌轰娇鐢級
+ */
+ private DevicePlcVO.OperationResult handleClearPlc(DeviceConfig deviceConfig) {
+ try {
+ EnhancedS7Serializer serializer = s7SerializerProvider.getSerializer(deviceConfig);
+ if (serializer == null) {
+ return buildResult(deviceConfig, "clearPlc", false, "鑾峰彇PLC搴忓垪鍖栧櫒澶辫触");
+ }
+
+ Map<String, Object> payload = new HashMap<>();
+ // 鏍规嵁鍗ц浆绔嬩富浣撳啓鍏ョ殑瀛楁杩涜娓呯┖
+ for (int i = 1; i <= 6; i++) {
+ payload.put("plcGlassId" + i, "");
+ }
+ payload.put("plcGlassCount", 0);
+ payload.put("plcRequest", 0);
+ payload.put("inPosition", 0);
+
+ plcDynamicDataService.writePlcData(deviceConfig, payload, serializer);
+ log.info("鍗ц浆绔嬩富浣撴竻绌篜LC瀛楁瀹屾垚: deviceId={}", deviceConfig.getId());
+ return buildResult(deviceConfig, "clearPlc", true, "宸叉竻绌哄崸杞珛涓讳綋PLC瀛楁");
+ } catch (Exception e) {
+ log.error("鍗ц浆绔嬩富浣撴竻绌篜LC澶辫触: deviceId={}", deviceConfig.getId(), e);
+ return buildResult(deviceConfig, "clearPlc", false, "娓呯┖PLC澶辫触: " + e.getMessage());
+ }
+ }
/**
* 鏋勫缓鎿嶄綔缁撴灉
diff --git a/mes-processes/mes-plcSend/src/main/java/com/mes/service/impl/PlcDynamicDataServiceImpl.java b/mes-processes/mes-plcSend/src/main/java/com/mes/service/impl/PlcDynamicDataServiceImpl.java
index b906dbd..8831206 100644
--- a/mes-processes/mes-plcSend/src/main/java/com/mes/service/impl/PlcDynamicDataServiceImpl.java
+++ b/mes-processes/mes-plcSend/src/main/java/com/mes/service/impl/PlcDynamicDataServiceImpl.java
@@ -570,7 +570,10 @@
lowerName.startsWith("plcglassid")) {
return EDataType.STRING;
}
-
+ // 鑱旀満鐘舵�佺瓑甯冨皵鏍囪
+ if (lowerName.contains("online")) {
+ return EDataType.BOOL;
+ }
// 榛樿杩斿洖UINT16
return EDataType.UINT16;
}
diff --git a/mes-processes/mes-plcSend/src/main/java/com/mes/task/service/TaskExecutionEngine.java b/mes-processes/mes-plcSend/src/main/java/com/mes/task/service/TaskExecutionEngine.java
index 2156e46..627c88e 100644
--- a/mes-processes/mes-plcSend/src/main/java/com/mes/task/service/TaskExecutionEngine.java
+++ b/mes-processes/mes-plcSend/src/main/java/com/mes/task/service/TaskExecutionEngine.java
@@ -148,7 +148,7 @@
for (DeviceConfig device : devices) {
String deviceType = device.getDeviceType();
- log.info("澶勭悊璁惧: deviceId={}, deviceType={}, deviceName={}, WORKSTATION_SCANNER甯搁噺={}, equals={}",
+ log.debug("澶勭悊璁惧: deviceId={}, deviceType={}, deviceName={}, WORKSTATION_SCANNER甯搁噺={}, equals={}",
device.getId(), deviceType, device.getDeviceName(),
DeviceConfig.DeviceType.WORKSTATION_SCANNER,
DeviceConfig.DeviceType.WORKSTATION_SCANNER.equals(deviceType));
@@ -157,25 +157,20 @@
|| (deviceType != null && (deviceType.contains("鎵爜") || deviceType.contains("SCANNER")));
boolean isLargeGlass = DeviceConfig.DeviceType.LARGE_GLASS.equals(deviceType);
boolean isTransfer = DeviceConfig.DeviceType.WORKSTATION_TRANSFER.equals(deviceType);
- log.info("璁惧绫诲瀷鍒ゆ柇: deviceId={}, isLoadVehicle={}, isScanner={}, isLargeGlass={}, isTransfer={}",
+ log.debug("璁惧绫诲瀷鍒ゆ柇: deviceId={}, isLoadVehicle={}, isScanner={}, isLargeGlass={}, isTransfer={}",
device.getId(), isLoadVehicle, isScanner, isLargeGlass, isTransfer);
// 1. 鍗ц浆绔嬫壂鐮佽澶囷細鍚姩瀹氭椂鍣ㄦ壂鎻忥紙姣�10绉掑鐞嗕竴涓幓鐠僆D锛�
if (isScanner) {
- log.info("妫�娴嬪埌鎵爜璁惧锛屽噯澶囧惎鍔ㄥ畾鏃跺櫒: deviceId={}, deviceType={}, deviceName={}",
+ log.debug("妫�娴嬪埌鎵爜璁惧锛屽噯澶囧惎鍔ㄥ畾鏃跺櫒: deviceId={}, deviceType={}, deviceName={}",
device.getId(), device.getDeviceType(), device.getDeviceName());
TaskStepDetail step = createStepRecord(task, device, currentOrder);
- // 璁剧疆姝ラ涓鸿繍琛岀姸鎬侊紝骞惰缃紑濮嬫椂闂�
- step.setStatus(TaskStepDetail.Status.RUNNING.name());
- step.setStartTime(new Date());
- taskStepDetailMapper.updateById(step);
- notificationService.notifyStepUpdate(task.getTaskId(), step);
ScheduledFuture<?> scannerTask = startScannerTimer(task, step, device, context);
if (scannerTask != null) {
registerScheduledTask(task.getTaskId(), scannerTask);
stepSummaries.add(createStepSummary(device.getDeviceName(), true, "瀹氭椂鍣ㄥ凡鍚姩锛屾瘡10绉掓壂鎻忎竴娆�"));
- log.info("鎵爜璁惧瀹氭椂鍣ㄥ惎鍔ㄦ垚鍔�: deviceId={}, taskId={}", device.getId(), task.getTaskId());
+ log.debug("鎵爜璁惧瀹氭椂鍣ㄥ惎鍔ㄦ垚鍔�: deviceId={}, taskId={}", device.getId(), task.getTaskId());
} else {
log.warn("鎵爜璁惧瀹氭椂鍣ㄥ惎鍔ㄥけ璐ワ紝glassIds鍙兘涓虹┖: deviceId={}, taskId={}, contextParams={}",
device.getId(), task.getTaskId(), context.getParameters());
@@ -190,20 +185,15 @@
// 2. 鍗ц浆绔嬭澶囷細鍚姩瀹氭椂鍣ㄥ畾鏈熸鏌ュ苟澶勭悊锛堜腑杞澶囷級
if (isTransfer) {
- log.info("妫�娴嬪埌鍗ц浆绔嬭澶囷紝鍑嗗鍚姩瀹氭椂鍣�: deviceId={}, deviceType={}, deviceName={}",
+ log.debug("妫�娴嬪埌鍗ц浆绔嬭澶囷紝鍑嗗鍚姩瀹氭椂鍣�: deviceId={}, deviceType={}, deviceName={}",
device.getId(), device.getDeviceType(), device.getDeviceName());
TaskStepDetail step = createStepRecord(task, device, currentOrder);
- // 璁剧疆姝ラ涓鸿繍琛岀姸鎬侊紝骞惰缃紑濮嬫椂闂�
- step.setStatus(TaskStepDetail.Status.RUNNING.name());
- step.setStartTime(new Date());
- taskStepDetailMapper.updateById(step);
- notificationService.notifyStepUpdate(task.getTaskId(), step);
ScheduledFuture<?> transferTask = startTransferTimer(task, step, device, context);
if (transferTask != null) {
registerScheduledTask(task.getTaskId(), transferTask);
stepSummaries.add(createStepSummary(device.getDeviceName(), true, "瀹氭椂鍣ㄥ凡鍚姩锛屽畾鏈熸鏌ュ苟澶勭悊鐜荤拑鎵规"));
- log.info("鍗ц浆绔嬭澶囧畾鏃跺櫒鍚姩鎴愬姛: deviceId={}, taskId={}", device.getId(), task.getTaskId());
+ log.debug("鍗ц浆绔嬭澶囧畾鏃跺櫒鍚姩鎴愬姛: deviceId={}, taskId={}", device.getId(), task.getTaskId());
} else {
log.warn("鍗ц浆绔嬭澶囧畾鏃跺櫒鍚姩澶辫触: deviceId={}, taskId={}", device.getId(), task.getTaskId());
stepSummaries.add(createStepSummary(device.getDeviceName(), false, "鍚姩瀹氭椂鍣ㄥけ璐�"));
@@ -221,11 +211,6 @@
boolean isInboundVehicle = currentLoadVehicleIndex == 1; // 绗竴涓ぇ杞︽槸杩涚墖澶ц溅
TaskStepDetail step = createStepRecord(task, device, currentOrder);
- // 璁剧疆姝ラ涓鸿繍琛岀姸鎬侊紝骞惰缃紑濮嬫椂闂�
- step.setStatus(TaskStepDetail.Status.RUNNING.name());
- step.setStartTime(new Date());
- taskStepDetailMapper.updateById(step);
- notificationService.notifyStepUpdate(task.getTaskId(), step);
ScheduledFuture<?> vehicleTask;
if (isInboundVehicle) {
@@ -260,11 +245,6 @@
// 4. 澶х悊鐗囩璁惧锛氬惎鍔ㄥ畾鏃跺櫒閫昏緫澶勭悊锛堜笉娑夊強PLC浜や簰锛屽彧璐熻矗閫昏緫澶勭悊锛�
if (isLargeGlass) {
TaskStepDetail step = createStepRecord(task, device, currentOrder);
- // 璁剧疆姝ラ涓鸿繍琛岀姸鎬侊紝骞惰缃紑濮嬫椂闂�
- step.setStatus(TaskStepDetail.Status.RUNNING.name());
- step.setStartTime(new Date());
- taskStepDetailMapper.updateById(step);
- notificationService.notifyStepUpdate(task.getTaskId(), step);
ScheduledFuture<?> largeGlassTask = startLargeGlassTimer(task, step, device, context);
if (largeGlassTask != null) {
@@ -296,7 +276,7 @@
// 瀹氭椂鍣ㄤ細鍦ㄥ悗鍙版寔缁繍琛岋紝鐩村埌鎵嬪姩鍋滄鎴栬秴鏃�
boolean hasScheduledTasks = !CollectionUtils.isEmpty(taskScheduledTasks.get(task.getTaskId()));
if (hasScheduledTasks) {
- log.info("浠诲姟宸插惎鍔ㄦ墍鏈夊畾鏃跺櫒锛屼繚鎸佽繍琛岀姸鎬�: taskId={}, scheduledTasksCount={}",
+ log.debug("浠诲姟宸插惎鍔ㄦ墍鏈夊畾鏃跺櫒锛屼繚鎸佽繍琛岀姸鎬�: taskId={}, scheduledTasksCount={}",
task.getTaskId(), taskScheduledTasks.get(task.getTaskId()).size());
// 浠诲姟淇濇寔 RUNNING 鐘舵�侊紝瀹氭椂鍣ㄥ湪鍚庡彴杩愯
// 涓嶆洿鏂颁换鍔$姸鎬佷负 COMPLETED锛岃浠诲姟鎸佺画杩愯
@@ -376,7 +356,7 @@
try {
TaskParameters params = context.getParameters();
List<String> glassIds = params.getGlassIds();
- log.info("鍗ц浆绔嬫壂鐮佸畾鏃跺櫒鍒濆鍖�: taskId={}, deviceId={}, glassIds={}, glassIdsSize={}, isEmpty={}",
+ log.debug("鍗ц浆绔嬫壂鐮佸畾鏃跺櫒鍒濆鍖�: taskId={}, deviceId={}, glassIds={}, glassIdsSize={}, isEmpty={}",
task.getTaskId(), device.getId(), glassIds,
glassIds != null ? glassIds.size() : 0,
CollectionUtils.isEmpty(glassIds));
@@ -391,19 +371,22 @@
AtomicInteger successCount = new AtomicInteger(0);
AtomicInteger failCount = new AtomicInteger(0);
- final long CYCLE_INTERVAL_MS = 10_000; // 10绉掗棿闅�
+ // 浠庤澶囬厤缃腑鑾峰彇鎵爜闂撮殧锛岄粯璁�10绉�
+ Map<String, Object> logicParams = parseLogicParams(device);
+ Integer scanIntervalMs = getLogicParam(logicParams, "scanIntervalMs", 10_000);
- log.info("鍚姩鍗ц浆绔嬫壂鐮佸畾鏃跺櫒: taskId={}, deviceId={}, glassCount={}, interval={}s, glassIds={}",
- task.getTaskId(), device.getId(), glassIds.size(), CYCLE_INTERVAL_MS / 1000, glassIds);
+ log.debug("鍚姩鍗ц浆绔嬫壂鐮佸畾鏃跺櫒: taskId={}, deviceId={}, glassCount={}, interval={}ms, glassIds={}",
+ task.getTaskId(), device.getId(), glassIds.size(), scanIntervalMs, glassIds);
// 鍚姩瀹氭椂浠诲姟
ScheduledFuture<?> future = scheduledExecutor.scheduleWithFixedDelay(() -> {
try {
if (isTaskCancelled(context)) {
- log.info("浠诲姟宸插彇娑堬紝鍋滄鍗ц浆绔嬫壂鐮佸畾鏃跺櫒: taskId={}, deviceId={}",
+ log.debug("浠诲姟宸插彇娑堬紝鍋滄鍗ц浆绔嬫壂鐮佸畾鏃跺櫒: taskId={}, deviceId={}",
task.getTaskId(), device.getId());
return;
}
+ ensureStepRunning(step, task.getTaskId());
// 妫�鏌ユ槸鍚﹂渶瑕佹殏鍋�
if (shouldPauseScanner(context)) {
log.debug("鍗ц浆绔嬫壂鐮佸畾鏃跺櫒鏆傚仠: taskId={}, deviceId={}", task.getTaskId(), device.getId());
@@ -413,9 +396,25 @@
// 妫�鏌ユ槸鍚﹁繕鏈夊緟澶勭悊鐨勭幓鐠僆D
String glassId = glassIdQueue.poll();
if (glassId == null) {
- log.info("鍗ц浆绔嬫壂鐮佸畾鏃跺櫒瀹屾垚: taskId={}, deviceId={}, processed={}/{}, success={}, fail={}",
+ log.debug("鍗ц浆绔嬫壂鐮佸畾鏃跺櫒瀹屾垚: taskId={}, deviceId={}, processed={}/{}, success={}, fail={}",
task.getTaskId(), device.getId(), processedCount.get(), glassIds.size(),
successCount.get(), failCount.get());
+
+ // 娓呯┖plcRequest鍜宲lcGlassId锛堢‘淇漃LC鐘舵�佹竻鐞嗭級
+ try {
+ DeviceLogicHandler handler = handlerFactory.getHandler(device.getDeviceType());
+ if (handler != null) {
+ Map<String, Object> clearParams = new HashMap<>();
+ clearParams.put("_taskContext", context);
+ handler.execute(device, "clearPlc", clearParams);
+ log.debug("鍗ц浆绔嬫壂鐮佸畾鏃跺櫒瀹屾垚锛屽凡娓呯┖PLC璇锋眰瀛楁: taskId={}, deviceId={}",
+ task.getTaskId(), device.getId());
+ }
+ } catch (Exception e) {
+ log.warn("鍗ц浆绔嬫壂鐮佸畾鏃跺櫒瀹屾垚鏃舵竻绌篜LC澶辫触: taskId={}, deviceId={}, error={}",
+ task.getTaskId(), device.getId(), e.getMessage());
+ }
+
// 鑻ヤ箣鍓嶆湭鍑虹幇澶辫触锛屽啀灏嗙姸鎬佺疆涓哄畬鎴�
boolean alreadyFailed = TaskStepDetail.Status.FAILED.name().equals(step.getStatus());
if (!alreadyFailed) {
@@ -426,6 +425,8 @@
}
taskStepDetailMapper.updateById(step);
notificationService.notifyStepUpdate(task.getTaskId(), step);
+ // 鎵爜璁惧瀹屾垚鍚庡皾璇曡嚜鍔ㄦ敹灏炬暣涓换鍔�
+ checkAndCompleteTaskIfDone(step.getTaskId());
}
deviceCoordinationService.syncDeviceStatus(device,
DeviceCoordinationService.DeviceStatus.COMPLETED, context);
@@ -433,32 +434,31 @@
}
int currentIndex = processedCount.incrementAndGet();
- log.info("鍗ц浆绔嬫壂鐮佸畾鏃跺櫒澶勭悊绗瑊}/{}涓幓鐠�: taskId={}, deviceId={}, glassId={}",
+ log.debug("鍗ц浆绔嬫壂鐮佸畾鏃跺櫒澶勭悊绗瑊}/{}涓幓鐠�: taskId={}, deviceId={}, glassId={}",
currentIndex, glassIds.size(), task.getTaskId(), device.getId(), glassId);
// 鎵ц鍗曟鎵弿
Map<String, Object> scanParams = new HashMap<>();
scanParams.put("glassId", glassId);
scanParams.put("_taskContext", context);
- log.info("鍗ц浆绔嬫壂鐮佸畾鏃跺櫒鍑嗗鎵ц: taskId={}, deviceId={}, glassId={}, scanParams={}",
+ log.debug("鍗ц浆绔嬫壂鐮佸畾鏃跺櫒鍑嗗鎵ц: taskId={}, deviceId={}, glassId={}, scanParams={}",
task.getTaskId(), device.getId(), glassId, scanParams);
DeviceLogicHandler handler = handlerFactory.getHandler(device.getDeviceType());
if (handler != null) {
- // 灏唋ogicParams鍚堝苟鍒皊canParams涓�
- Map<String, Object> logicParams = parseLogicParams(device);
+ // 灏唋ogicParams鍚堝苟鍒皊canParams涓紙浣跨敤宸插畾涔夌殑logicParams鍙橀噺锛�
if (logicParams != null && !logicParams.isEmpty()) {
scanParams.put("_logicParams", logicParams);
}
- log.info("鍗ц浆绔嬫壂鐮佸畾鏃跺櫒璋冪敤handler.execute: taskId={}, deviceId={}, glassId={}, operation=scanOnce, scanParamsKeys={}, scanParams={}",
+ log.debug("鍗ц浆绔嬫壂鐮佸畾鏃跺櫒璋冪敤handler.execute: taskId={}, deviceId={}, glassId={}, operation=scanOnce, scanParamsKeys={}, scanParams={}",
task.getTaskId(), device.getId(), glassId, scanParams.keySet(), scanParams);
DevicePlcVO.OperationResult result = handler.execute(device, "scanOnce", scanParams);
- log.info("鍗ц浆绔嬫壂鐮佸畾鏃跺櫒handler.execute杩斿洖: taskId={}, deviceId={}, glassId={}, success={}",
+ log.debug("鍗ц浆绔嬫壂鐮佸畾鏃跺櫒handler.execute杩斿洖: taskId={}, deviceId={}, glassId={}, success={}",
task.getTaskId(), device.getId(), glassId, result.getSuccess());
if (Boolean.TRUE.equals(result.getSuccess())) {
successCount.incrementAndGet();
- log.info("鍗ц浆绔嬫壂鐮佸畾鏃跺櫒澶勭悊鎴愬姛: taskId={}, deviceId={}, glassId={}",
+ log.debug("鍗ц浆绔嬫壂鐮佸畾鏃跺櫒澶勭悊鎴愬姛: taskId={}, deviceId={}, glassId={}",
task.getTaskId(), device.getId(), glassId);
} else {
failCount.incrementAndGet();
@@ -466,9 +466,10 @@
task.getTaskId(), device.getId(), glassId, result.getMessage());
}
- // 鏇存柊姝ラ鐘舵��
- updateStepStatus(step, result);
- // 閫氱煡姝ラ鏇存柊锛堣鍓嶇瀹炴椂鐪嬪埌姝ラ鐘舵�侊級
+ // 鏇存柊姝ラ鐘舵�侊紙鏄剧ず杩涘害锛屼繚鎸丷UNNING鐘舵�佺洿鍒版墍鏈夌幓鐠冨鐞嗗畬鎴愶級
+ updateStepStatusForScanner(step, result, currentIndex, glassIds.size(),
+ successCount.get(), failCount.get());
+ // 閫氱煡姝ラ鏇存柊锛堣鍓嶇瀹炴椂鐪嬪埌姝ラ鐘舵�佸拰杩涘害锛�
notificationService.notifyStepUpdate(task.getTaskId(), step);
boolean opSuccess = Boolean.TRUE.equals(result.getSuccess());
updateTaskProgress(task, step.getStepOrder(), opSuccess);
@@ -481,7 +482,7 @@
log.error("鍗ц浆绔嬫壂鐮佸畾鏃跺櫒鎵ц寮傚父: taskId={}, deviceId={}", task.getTaskId(), device.getId(), e);
failCount.incrementAndGet();
}
- }, 0, CYCLE_INTERVAL_MS, TimeUnit.MILLISECONDS);
+ }, 0, scanIntervalMs, TimeUnit.MILLISECONDS);
deviceCoordinationService.syncDeviceStatus(device,
DeviceCoordinationService.DeviceStatus.RUNNING, context);
@@ -504,17 +505,18 @@
Map<String, Object> logicParams = parseLogicParams(device);
Integer monitorIntervalMs = getLogicParam(logicParams, "monitorIntervalMs", 5_000);
- log.info("鍚姩鍗ц浆绔嬭澶囧畾鏃跺櫒: taskId={}, deviceId={}, interval={}ms",
+ log.debug("鍚姩鍗ц浆绔嬭澶囧畾鏃跺櫒: taskId={}, deviceId={}, interval={}ms",
task.getTaskId(), device.getId(), monitorIntervalMs);
// 鍚姩瀹氭椂浠诲姟
ScheduledFuture<?> future = scheduledExecutor.scheduleWithFixedDelay(() -> {
try {
if (isTaskCancelled(context)) {
- log.info("浠诲姟宸插彇娑堬紝鍋滄鍗ц浆绔嬭澶囧畾鏃跺櫒: taskId={}, deviceId={}",
+ log.debug("浠诲姟宸插彇娑堬紝鍋滄鍗ц浆绔嬭澶囧畾鏃跺櫒: taskId={}, deviceId={}",
task.getTaskId(), device.getId());
return;
}
+ ensureStepRunning(step, task.getTaskId());
// 鏋勫缓鍙傛暟
Map<String, Object> params = new HashMap<>();
params.put("_taskContext", context);
@@ -536,10 +538,10 @@
if (opSuccess) {
String message = result.getMessage();
if (message != null && message.contains("鎵规宸插啓鍏LC")) {
- log.info("鍗ц浆绔嬭澶囧畾鏃跺櫒鎵ц鎴愬姛锛堝凡鍐欏叆PLC锛�: taskId={}, deviceId={}, message={}",
+ log.debug("鍗ц浆绔嬭澶囧畾鏃跺櫒鎵ц鎴愬姛锛堝凡鍐欏叆PLC锛�: taskId={}, deviceId={}, message={}",
task.getTaskId(), device.getId(), message);
} else {
- log.debug("鍗ц浆绔嬭澶囧畾鏃跺櫒绛夊緟涓�: taskId={}, deviceId={}, message={}",
+ log.debug("鍗ц浆绔嬭澶囧畾鏃跺櫒绛夊緟涓�: taskId={}, deviceId={}, message={}",
task.getTaskId(), device.getId(), message);
}
} else {
@@ -574,17 +576,18 @@
final long MONITOR_INTERVAL_MS = 2_000; // 2绉掔洃鎺т竴娆�
final AtomicInteger lastProcessedCount = new AtomicInteger(0);
- log.info("鍚姩杩涚墖澶ц溅璁惧瀹氭椂鍣�: taskId={}, deviceId={}, interval={}s",
+ log.debug("鍚姩杩涚墖澶ц溅璁惧瀹氭椂鍣�: taskId={}, deviceId={}, interval={}s",
task.getTaskId(), device.getId(), MONITOR_INTERVAL_MS / 1000);
// 鍚姩瀹氭椂浠诲姟
ScheduledFuture<?> future = scheduledExecutor.scheduleWithFixedDelay(() -> {
try {
if (isTaskCancelled(context)) {
- log.info("浠诲姟宸插彇娑堬紝鍋滄杩涚墖澶ц溅瀹氭椂鍣�: taskId={}, deviceId={}",
+ log.debug("浠诲姟宸插彇娑堬紝鍋滄杩涚墖澶ц溅瀹氭椂鍣�: taskId={}, deviceId={}",
task.getTaskId(), device.getId());
return;
}
+ ensureStepRunning(step, task.getTaskId());
// 妫�鏌ユ槸鍚︽湁鍗ц浆绔嬩富浣撳凡杈撳嚭銆佸噯澶囦笂澶ц溅鐨勭幓鐠冧俊鎭�
List<String> readyGlassIds = getTransferReadyGlassIds(context);
if (CollectionUtils.isEmpty(readyGlassIds)) {
@@ -600,7 +603,7 @@
return;
}
- log.info("杩涚墖澶ц溅璁惧瀹氭椂鍣ㄦ娴嬪埌鍗ц浆绔嬭緭鍑虹殑鐜荤拑淇℃伅: taskId={}, deviceId={}, glassCount={}",
+ log.debug("杩涚墖澶ц溅璁惧瀹氭椂鍣ㄦ娴嬪埌鍗ц浆绔嬭緭鍑虹殑鐜荤拑淇℃伅: taskId={}, deviceId={}, glassCount={}",
task.getTaskId(), device.getId(), currentCount);
// 妫�鏌ュ閲�
@@ -615,10 +618,11 @@
if (logicParams != null && !logicParams.isEmpty()) {
checkParams.put("_logicParams", logicParams);
}
- DevicePlcVO.OperationResult result = handler.execute(device, "feedGlass", checkParams);
+ // 绗竴姝ワ細鍐欏叆澶ц溅涓婃枡璇锋眰
+ DevicePlcVO.OperationResult feedResult = handler.execute(device, "feedGlass", checkParams);
- if (Boolean.TRUE.equals(result.getSuccess())) {
- log.info("杩涚墖澶ц溅璁惧瀹氭椂鍣ㄦ墽琛屾垚鍔�: taskId={}, deviceId={}, glassCount={}",
+ if (Boolean.TRUE.equals(feedResult.getSuccess())) {
+ log.debug("杩涚墖澶ц溅璁惧瀹氭椂鍣ㄦ墽琛屾垚鍔�: taskId={}, deviceId={}, glassCount={}",
task.getTaskId(), device.getId(), readyGlassIds.size());
// 灏嗗凡瑁呰浇鐨勭幓鐠僆D淇濆瓨鍒板叡浜暟鎹腑锛堜緵澶х悊鐗囩浣跨敤锛�
setLoadedGlassIds(context, new ArrayList<>(readyGlassIds));
@@ -630,17 +634,36 @@
} else {
// 瑁呬笉涓嬶紝璁板綍瀹归噺涓嶈冻锛堟槸鍚﹂渶瑕佸奖鍝嶆壂鐮佺敱宸ヨ壓鍐嶅喅瀹氾級
log.warn("杩涚墖澶ц溅璁惧瀹氭椂鍣ㄥ閲忎笉瓒�: taskId={}, deviceId={}, message={}",
- task.getTaskId(), device.getId(), result.getMessage());
+ task.getTaskId(), device.getId(), feedResult.getMessage());
lastProcessedCount.set(currentCount); // 璁板綍褰撳墠鏁伴噺锛岄伩鍏嶉噸澶嶆鏌�
}
- // 鏇存柊姝ラ鐘舵��
- updateStepStatus(step, result);
- boolean opSuccess = Boolean.TRUE.equals(result.getSuccess());
- updateTaskProgress(task, step.getStepOrder(), opSuccess);
- if (!opSuccess) {
- deviceCoordinationService.syncDeviceStatus(device,
- DeviceCoordinationService.DeviceStatus.FAILED, context);
+ // 绗簩姝ワ細妫�鏌ES纭鐘舵�侊紙濡傛灉澶ц溅澶勭悊鍣ㄦ敮鎸佺殑璇濓級
+ DevicePlcVO.OperationResult mesResult = null;
+ try {
+ mesResult = handler.execute(device, "checkMesConfirm", Collections.emptyMap());
+ } catch (Exception e) {
+ log.warn("杩涚墖澶ц溅璁惧妫�鏌ES纭鐘舵�佸紓甯�: taskId={}, deviceId={}, error={}",
+ task.getTaskId(), device.getId(), e.getMessage());
+ }
+
+ // 鏇存柊姝ラ鐘舵�侊紙澶ц溅璁惧淇濇寔RUNNING锛岀洿鍒癕ES纭瀹屾垚鎴栦换鍔″彇娑堬級
+ if (mesResult != null) {
+ updateStepStatusForVehicle(step, mesResult);
+ boolean opSuccess = Boolean.TRUE.equals(mesResult.getSuccess());
+ updateTaskProgress(task, step.getStepOrder(), opSuccess);
+ if (!opSuccess) {
+ deviceCoordinationService.syncDeviceStatus(device,
+ DeviceCoordinationService.DeviceStatus.FAILED, context);
+ }
+ } else {
+ updateStepStatusForVehicle(step, feedResult);
+ boolean opSuccess = Boolean.TRUE.equals(feedResult.getSuccess());
+ updateTaskProgress(task, step.getStepOrder(), opSuccess);
+ if (!opSuccess) {
+ deviceCoordinationService.syncDeviceStatus(device,
+ DeviceCoordinationService.DeviceStatus.FAILED, context);
+ }
}
}
} catch (Exception e) {
@@ -667,17 +690,18 @@
try {
final long MONITOR_INTERVAL_MS = 2_000; // 2绉掔洃鎺т竴娆�
- log.info("鍚姩鍑虹墖澶ц溅璁惧瀹氭椂鍣�: taskId={}, deviceId={}, interval={}s",
+ log.debug("鍚姩鍑虹墖澶ц溅璁惧瀹氭椂鍣�: taskId={}, deviceId={}, interval={}s",
task.getTaskId(), device.getId(), MONITOR_INTERVAL_MS / 1000);
// 鍚姩瀹氭椂浠诲姟
ScheduledFuture<?> future = scheduledExecutor.scheduleWithFixedDelay(() -> {
try {
if (isTaskCancelled(context)) {
- log.info("浠诲姟宸插彇娑堬紝鍋滄鍑虹墖澶ц溅瀹氭椂鍣�: taskId={}, deviceId={}",
+ log.debug("浠诲姟宸插彇娑堬紝鍋滄鍑虹墖澶ц溅瀹氭椂鍣�: taskId={}, deviceId={}",
task.getTaskId(), device.getId());
return;
}
+ ensureStepRunning(step, task.getTaskId());
// 妫�鏌ユ槸鍚︽湁宸插鐞嗙殑鐜荤拑淇℃伅锛堜粠澶х悊鐗囩鏉ョ殑锛�
List<String> processedGlassIds = getProcessedGlassIds(context);
if (CollectionUtils.isEmpty(processedGlassIds)) {
@@ -686,7 +710,7 @@
return;
}
- log.info("鍑虹墖澶ц溅璁惧瀹氭椂鍣ㄦ娴嬪埌宸插鐞嗙殑鐜荤拑淇℃伅: taskId={}, deviceId={}, glassCount={}",
+ log.debug("鍑虹墖澶ц溅璁惧瀹氭椂鍣ㄦ娴嬪埌宸插鐞嗙殑鐜荤拑淇℃伅: taskId={}, deviceId={}, glassCount={}",
task.getTaskId(), device.getId(), processedGlassIds.size());
// 鎵ц鍑虹墖鎿嶄綔
@@ -701,25 +725,45 @@
if (logicParams != null && !logicParams.isEmpty()) {
checkParams.put("_logicParams", logicParams);
}
- DevicePlcVO.OperationResult result = handler.execute(device, "feedGlass", checkParams);
+ // 绗竴姝ワ細鍐欏叆澶ц溅鍑虹墖璇锋眰
+ DevicePlcVO.OperationResult feedResult = handler.execute(device, "feedGlass", checkParams);
- if (Boolean.TRUE.equals(result.getSuccess())) {
- log.info("鍑虹墖澶ц溅璁惧瀹氭椂鍣ㄦ墽琛屾垚鍔�: taskId={}, deviceId={}, glassCount={}",
+ if (Boolean.TRUE.equals(feedResult.getSuccess())) {
+ log.debug("鍑虹墖澶ц溅璁惧瀹氭椂鍣ㄦ墽琛屾垚鍔�: taskId={}, deviceId={}, glassCount={}",
task.getTaskId(), device.getId(), processedGlassIds.size());
// 娓呯┖宸插鐞嗙殑鐜荤拑ID鍒楄〃锛堝凡澶勭悊锛�
clearProcessedGlassIds(context);
} else {
log.debug("鍑虹墖澶ц溅璁惧瀹氭椂鍣ㄦ墽琛屽け璐�: taskId={}, deviceId={}, message={}",
- task.getTaskId(), device.getId(), result.getMessage());
+ task.getTaskId(), device.getId(), feedResult.getMessage());
}
- // 鏇存柊姝ラ鐘舵��
- updateStepStatus(step, result);
- boolean opSuccess = Boolean.TRUE.equals(result.getSuccess());
- updateTaskProgress(task, step.getStepOrder(), opSuccess);
- if (!opSuccess) {
- deviceCoordinationService.syncDeviceStatus(device,
- DeviceCoordinationService.DeviceStatus.FAILED, context);
+ // 绗簩姝ワ細妫�鏌ES纭鐘舵�侊紙濡傛灉澶ц溅澶勭悊鍣ㄦ敮鎸佺殑璇濓級
+ DevicePlcVO.OperationResult mesResult = null;
+ try {
+ mesResult = handler.execute(device, "checkMesConfirm", Collections.emptyMap());
+ } catch (Exception e) {
+ log.warn("鍑虹墖澶ц溅璁惧妫�鏌ES纭鐘舵�佸紓甯�: taskId={}, deviceId={}, error={}",
+ task.getTaskId(), device.getId(), e.getMessage());
+ }
+
+ // 鏇存柊姝ラ鐘舵�侊紙澶ц溅璁惧淇濇寔RUNNING锛岀洿鍒癕ES纭瀹屾垚鎴栦换鍔″彇娑堬級
+ if (mesResult != null) {
+ updateStepStatusForVehicle(step, mesResult);
+ boolean opSuccess = Boolean.TRUE.equals(mesResult.getSuccess());
+ updateTaskProgress(task, step.getStepOrder(), opSuccess);
+ if (!opSuccess) {
+ deviceCoordinationService.syncDeviceStatus(device,
+ DeviceCoordinationService.DeviceStatus.FAILED, context);
+ }
+ } else {
+ updateStepStatusForVehicle(step, feedResult);
+ boolean opSuccess = Boolean.TRUE.equals(feedResult.getSuccess());
+ updateTaskProgress(task, step.getStepOrder(), opSuccess);
+ if (!opSuccess) {
+ deviceCoordinationService.syncDeviceStatus(device,
+ DeviceCoordinationService.DeviceStatus.FAILED, context);
+ }
}
}
} catch (Exception e) {
@@ -749,17 +793,18 @@
Integer processTimeSeconds = getLogicParam(logicParams, "processTimeSeconds", 30);
final long PROCESS_TIME_MS = processTimeSeconds * 1000;
- log.info("鍚姩澶х悊鐗囩璁惧瀹氭椂鍣�: taskId={}, deviceId={}, processTime={}s",
+ log.debug("鍚姩澶х悊鐗囩璁惧瀹氭椂鍣�: taskId={}, deviceId={}, processTime={}s",
task.getTaskId(), device.getId(), processTimeSeconds);
// 鍚姩瀹氭椂浠诲姟
ScheduledFuture<?> future = scheduledExecutor.scheduleWithFixedDelay(() -> {
try {
if (isTaskCancelled(context)) {
- log.info("浠诲姟宸插彇娑堬紝鍋滄澶х悊鐗囩瀹氭椂鍣�: taskId={}, deviceId={}",
+ log.debug("浠诲姟宸插彇娑堬紝鍋滄澶х悊鐗囩瀹氭椂鍣�: taskId={}, deviceId={}",
task.getTaskId(), device.getId());
return;
}
+ ensureStepRunning(step, task.getTaskId());
// 妫�鏌ユ槸鍚︽湁宸茶杞界殑鐜荤拑淇℃伅锛堜粠杩涚墖澶ц溅鏉ョ殑锛�
List<String> loadedGlassIds = getLoadedGlassIds(context);
if (CollectionUtils.isEmpty(loadedGlassIds)) {
@@ -773,7 +818,7 @@
if (processStartTime == null) {
// 绗竴娆℃娴嬪埌鐜荤拑锛岃褰曞紑濮嬪鐞嗘椂闂�
setProcessStartTime(context, System.currentTimeMillis());
- log.info("澶х悊鐗囩璁惧寮�濮嬪鐞�: taskId={}, deviceId={}, glassCount={}, processTime={}s",
+ log.debug("澶х悊鐗囩璁惧寮�濮嬪鐞�: taskId={}, deviceId={}, glassCount={}, processTime={}s",
task.getTaskId(), device.getId(), loadedGlassIds.size(), processTimeSeconds);
return;
}
@@ -787,7 +832,7 @@
}
// 澶勭悊鏃堕棿宸插埌锛屽畬鎴愪换鍔℃眹鎶�
- log.info("澶х悊鐗囩璁惧澶勭悊瀹屾垚: taskId={}, deviceId={}, glassCount={}, processTime={}s",
+ log.debug("澶х悊鐗囩璁惧澶勭悊瀹屾垚: taskId={}, deviceId={}, glassCount={}, processTime={}s",
task.getTaskId(), device.getId(), loadedGlassIds.size(), processTimeSeconds);
// 灏嗗凡澶勭悊鐨勭幓鐠僆D杞Щ鍒板凡澶勭悊鍒楄〃锛堜緵鍑虹墖澶ц溅浣跨敤锛�
@@ -800,6 +845,8 @@
step.setErrorMessage(null);
step.setOutputData(toJson(Collections.singletonMap("glassIds", loadedGlassIds)));
taskStepDetailMapper.updateById(step);
+ // 澶х悊鐗囩瀹屾垚鍚庡皾璇曡嚜鍔ㄦ敹灏炬暣涓换鍔�
+ checkAndCompleteTaskIfDone(step.getTaskId());
} catch (Exception e) {
log.error("澶х悊鐗囩璁惧瀹氭椂鍣ㄦ墽琛屽紓甯�: taskId={}, deviceId={}", task.getTaskId(), device.getId(), e);
@@ -1024,7 +1071,7 @@
future.cancel(false);
}
}
- log.info("宸插仠姝换鍔$殑鎵�鏈夊畾鏃跺櫒: taskId={}, count={}", taskId, futures.size());
+ log.debug("宸插仠姝换鍔$殑鎵�鏈夊畾鏃跺櫒: taskId={}, count={}", taskId, futures.size());
}
runningTaskContexts.remove(taskId);
}
@@ -1040,7 +1087,7 @@
long timeoutMs = timeoutMinutes * 60 * 1000;
long deadline = System.currentTimeMillis() + timeoutMs;
- log.info("绛夊緟瀹氭椂鍣ㄤ换鍔″畬鎴�: taskId={}, timeout={}鍒嗛挓", taskId, timeoutMinutes);
+ log.debug("绛夊緟瀹氭椂鍣ㄤ换鍔″畬鎴�: taskId={}, timeout={}鍒嗛挓", taskId, timeoutMinutes);
while (System.currentTimeMillis() < deadline) {
List<ScheduledFuture<?>> futures = taskScheduledTasks.get(taskId);
@@ -1069,7 +1116,54 @@
}
}
- log.info("瀹氭椂鍣ㄤ换鍔$瓑寰呭畬鎴�: taskId={}", taskId);
+ log.debug("瀹氭椂鍣ㄤ换鍔$瓑寰呭畬鎴�: taskId={}", taskId);
+ }
+
+ /**
+ * 褰撴煇涓楠ゅ彲鑳藉畬鎴愭椂锛屾鏌ヤ换鍔℃槸鍚︽墍鏈夋楠ら兘宸插畬鎴愶紝濡傛灉鏄垯鑷姩灏嗕换鍔℃爣璁颁负宸插畬鎴�
+ */
+ private void checkAndCompleteTaskIfDone(String taskId) {
+ if (taskId == null) {
+ return;
+ }
+ try {
+ MultiDeviceTask task = multiDeviceTaskMapper.selectOne(
+ Wrappers.<MultiDeviceTask>lambdaQuery()
+ .eq(MultiDeviceTask::getTaskId, taskId)
+ );
+ if (task == null) {
+ return;
+ }
+ // 浠呭湪浠诲姟浠嶄负RUNNING鏃舵墠灏濊瘯鑷姩鏀跺熬
+ if (!MultiDeviceTask.Status.RUNNING.name().equals(task.getStatus())) {
+ return;
+ }
+
+ int totalSteps = task.getTotalSteps() != null ? task.getTotalSteps() : 0;
+ if (totalSteps <= 0) {
+ return;
+ }
+
+ int completedSteps = countCompletedSteps(taskId);
+ if (completedSteps < totalSteps) {
+ return;
+ }
+
+ // 鎵�鏈夋楠ら兘宸插畬鎴愶紝鏀跺熬浠诲姟
+ task.setStatus(MultiDeviceTask.Status.COMPLETED.name());
+ task.setEndTime(new Date());
+ multiDeviceTaskMapper.updateById(task);
+
+ // 鍋滄鎵�鏈夊畾鏃跺櫒
+ stopScheduledTasks(taskId);
+
+ // 閫氱煡浠诲姟瀹屾垚
+ notificationService.notifyTaskStatus(task);
+
+ log.info("鎵�鏈夋楠ゅ凡瀹屾垚锛岃嚜鍔ㄥ皢浠诲姟鏍囪涓哄凡瀹屾垚: taskId={}, totalSteps={}", taskId, totalSteps);
+ } catch (Exception e) {
+ log.warn("妫�鏌ュ苟鑷姩瀹屾垚浠诲姟澶辫触: taskId={}", taskId, e);
+ }
}
/**
@@ -1105,6 +1199,135 @@
}
/**
+ * 纭繚姝ラ杩涘叆RUNNING鐘舵�侊紙浠呭湪绗竴娆$湡姝f墽琛屽墠璋冪敤锛�
+ */
+ private void ensureStepRunning(TaskStepDetail step, String taskId) {
+ if (step == null) {
+ return;
+ }
+ if (!TaskStepDetail.Status.RUNNING.name().equals(step.getStatus())) {
+ step.setStatus(TaskStepDetail.Status.RUNNING.name());
+ if (step.getStartTime() == null) {
+ step.setStartTime(new Date());
+ }
+ taskStepDetailMapper.updateById(step);
+ notificationService.notifyStepUpdate(taskId, step);
+ }
+ }
+
+ /**
+ * 鏇存柊鎵爜璁惧姝ラ鐘舵�侊紙鏄剧ず杩涘害锛屼繚鎸丷UNNING鐘舵�佺洿鍒版墍鏈夌幓鐠冨鐞嗗畬鎴愶級
+ */
+ private void updateStepStatusForScanner(TaskStepDetail step, DevicePlcVO.OperationResult result,
+ int currentIndex, int totalCount,
+ int successCount, int failCount) {
+ if (step == null || result == null) {
+ return;
+ }
+
+ boolean success = Boolean.TRUE.equals(result.getSuccess());
+
+ // 淇濇寔RUNNING鐘舵�侊紝鐩村埌鎵�鏈夌幓鐠冨鐞嗗畬鎴愶紙鍦ㄥ畾鏃跺櫒瀹屾垚鏃跺啀璁剧疆涓篊OMPLETED锛�
+ step.setStatus(TaskStepDetail.Status.RUNNING.name());
+
+ // 鏇存柊鏃堕棿鍜岃�楁椂锛屽墠绔彲浠ュ疄鏃剁湅鍒版墽琛岃�楁椂
+ Date now = new Date();
+ if (step.getStartTime() == null) {
+ step.setStartTime(now);
+ }
+ if (step.getStartTime() != null) {
+ step.setDurationMs(now.getTime() - step.getStartTime().getTime());
+ }
+
+ // 鏇存柊杩涘害淇℃伅
+ String progressMessage = String.format("姝e湪澶勭悊 %d/%d (鎴愬姛:%d, 澶辫触:%d)",
+ currentIndex, totalCount, successCount, failCount);
+
+ if (success) {
+ // 鎴愬姛鏃舵樉绀鸿繘搴﹀拰鎴愬姛娑堟伅
+ String resultMessage = result.getMessage();
+ if (StringUtils.hasText(resultMessage)) {
+ step.setSuccessMessage(progressMessage + " - " + resultMessage);
+ } else {
+ step.setSuccessMessage(progressMessage);
+ }
+ step.setErrorMessage(null);
+ } else {
+ // 澶辫触鏃舵樉绀鸿繘搴﹀拰閿欒娑堟伅
+ String errorMessage = result.getMessage();
+ step.setErrorMessage(progressMessage + " - " + (StringUtils.hasText(errorMessage) ? errorMessage : "澶勭悊澶辫触"));
+ step.setSuccessMessage(null);
+ }
+
+ step.setOutputData(toJson(result));
+ taskStepDetailMapper.updateById(step);
+ }
+
+ /**
+ * 鏇存柊澶ц溅璁惧姝ラ鐘舵�侊紙淇濇寔RUNNING锛岀洿鍒版墜鍔ㄥ仠姝㈡垨浠诲姟鍙栨秷锛涘け璐ユ椂鏍囪涓篎AILED锛�
+ */
+ private void updateStepStatusForVehicle(TaskStepDetail step, DevicePlcVO.OperationResult result) {
+ if (step == null || result == null) {
+ return;
+ }
+ boolean success = Boolean.TRUE.equals(result.getSuccess());
+ boolean completed = false;
+ if (result.getData() != null && result.getData().get("completed") != null) {
+ Object flag = result.getData().get("completed");
+ if (flag instanceof Boolean) {
+ completed = (Boolean) flag;
+ } else {
+ completed = "true".equalsIgnoreCase(String.valueOf(flag));
+ }
+ }
+ Date now = new Date();
+
+ // 鍒濆鍖栧紑濮嬫椂闂�
+ if (step.getStartTime() == null) {
+ step.setStartTime(now);
+ }
+
+ if (success && !completed) {
+ // 鎴愬姛浣嗘湭瀹屾垚锛氫繚鎸丷UNNING鐘舵�侊紝浠呮洿鏂版彁绀轰俊鎭拰鑰楁椂
+ step.setStatus(TaskStepDetail.Status.RUNNING.name());
+ String message = result.getMessage();
+ step.setSuccessMessage(StringUtils.hasText(message) ? message : "澶ц溅璁惧杩愯涓�");
+ step.setErrorMessage(null);
+ if (step.getStartTime() != null) {
+ step.setDurationMs(now.getTime() - step.getStartTime().getTime());
+ }
+ } else if (success && completed) {
+ // 鎴愬姛涓擬ES宸茬‘璁ゅ畬鎴愶細鏍囪涓篊OMPLETED骞惰褰曠粨鏉熸椂闂�
+ step.setStatus(TaskStepDetail.Status.COMPLETED.name());
+ String message = result.getMessage();
+ step.setSuccessMessage(StringUtils.hasText(message) ? message : "澶ц溅璁惧浠诲姟宸插畬鎴�");
+ step.setErrorMessage(null);
+ if (step.getEndTime() == null) {
+ step.setEndTime(now);
+ }
+ if (step.getStartTime() != null && step.getEndTime() != null) {
+ step.setDurationMs(step.getEndTime().getTime() - step.getStartTime().getTime());
+ }
+ // 灏濊瘯鑷姩鏀跺熬鏁翠釜浠诲姟
+ checkAndCompleteTaskIfDone(step.getTaskId());
+ } else {
+ // 澶辫触锛氭爣璁颁负FAILED骞惰褰曠粨鏉熸椂闂�
+ step.setStatus(TaskStepDetail.Status.FAILED.name());
+ String message = result.getMessage();
+ step.setErrorMessage(message);
+ if (step.getEndTime() == null) {
+ step.setEndTime(now);
+ }
+ if (step.getStartTime() != null && step.getEndTime() != null) {
+ step.setDurationMs(step.getEndTime().getTime() - step.getStartTime().getTime());
+ }
+ }
+
+ step.setOutputData(toJson(result));
+ taskStepDetailMapper.updateById(step);
+ }
+
+ /**
* 鏇存柊鍗ц浆绔嬭澶囨楠ょ姸鎬侊紙鍖哄垎绛夊緟涓拰鐪熸瀹屾垚锛�
*/
private void updateStepStatusForTransfer(TaskStepDetail step, DevicePlcVO.OperationResult result) {
@@ -1114,8 +1337,12 @@
boolean success = Boolean.TRUE.equals(result.getSuccess());
String message = result.getMessage();
- // 鍒ゆ柇鏄惁鐪熸瀹屾垚锛堝彧鏈夊啓鍏LC鎵嶇畻瀹屾垚锛�
- boolean isRealCompleted = success && message != null && message.contains("鎵规宸插啓鍏LC");
+ // 鍒ゆ柇鏄惁鐪熸瀹屾垚锛�
+ // 1. 鍐欏叆PLC鎴愬姛
+ // 2. 涓旂紦鍐插凡娓呯┖锛堣〃绀烘墍鏈夌幓鐠冨凡澶勭悊瀹岋紝鏃犳柊鐜荤拑锛�
+ boolean isRealCompleted = success && message != null
+ && message.contains("鎵规宸插啓鍏LC")
+ && message.contains("缂撳啿宸叉竻绌猴紝浠诲姟瀹屾垚");
if (isRealCompleted) {
// 鐪熸瀹屾垚锛氳缃负瀹屾垚鐘舵�侊紝骞惰缃粨鏉熸椂闂�
@@ -1123,6 +1350,23 @@
step.setSuccessMessage(message);
if (step.getEndTime() == null) {
step.setEndTime(new Date());
+ }
+ // 璁$畻鑰楁椂
+ if (step.getStartTime() != null && step.getEndTime() != null) {
+ step.setDurationMs(step.getEndTime().getTime() - step.getStartTime().getTime());
+ }
+ log.debug("鍗ц浆绔嬭澶囨楠ゅ凡瀹屾垚: stepId={}, durationMs={}", step.getId(), step.getDurationMs());
+ // 鍗ц浆绔嬩富浣撳畬鎴愬悗灏濊瘯鑷姩鏀跺熬鏁翠釜浠诲姟
+ checkAndCompleteTaskIfDone(step.getTaskId());
+ } else if (success && message != null && message.contains("鎵规宸插啓鍏LC")) {
+ // 鍐欏叆PLC鎴愬姛浣嗙紦鍐茶繕鏈夌幓鐠冿紙杞︽弧鎯呭喌锛夛紝缁х画杩愯
+ if (!TaskStepDetail.Status.RUNNING.name().equals(step.getStatus())) {
+ step.setStatus(TaskStepDetail.Status.RUNNING.name());
+ }
+ step.setSuccessMessage(message);
+ // 纭繚寮�濮嬫椂闂村凡璁剧疆
+ if (step.getStartTime() == null) {
+ step.setStartTime(new Date());
}
} else if (success) {
// 绛夊緟涓細淇濇寔杩愯鐘舵�侊紝鍙洿鏂版秷鎭�
@@ -1140,6 +1384,10 @@
step.setErrorMessage(message);
if (step.getEndTime() == null) {
step.setEndTime(new Date());
+ }
+ // 璁$畻鑰楁椂
+ if (step.getStartTime() != null && step.getEndTime() != null) {
+ step.setDurationMs(step.getEndTime().getTime() - step.getStartTime().getTime());
}
}
@@ -1368,7 +1616,7 @@
}
/**
- * 鍒嗘壒鎵ц澶ц溅璁惧鐜荤拑涓婃枡锛堝綋鐜荤拑ID鏁伴噺瓒呰繃6涓笖璁剧疆浜嗗崟鐗囬棿闅旀椂锛�
+ * 鍒嗘壒鎵ц澶ц溅璁惧鐜荤拑涓婃枡锛堝綋鐜荤拑ID鏁伴噺瓒呰繃6涓椂锛�
*/
private StepResult executeLoadVehicleWithBatches(MultiDeviceTask task,
DeviceConfig device,
@@ -1376,13 +1624,12 @@
TaskExecutionContext context,
List<Map<String, Object>> stepSummaries) {
List<String> allGlassIds = context.getParameters().getGlassIds();
- Integer glassIntervalMs = context.getParameters().getGlassIntervalMs();
int batchSize = 6; // 姣忔壒鏈�澶�6涓幓鐠僆D
// 鍒嗘壒澶勭悊
int totalBatches = (allGlassIds.size() + batchSize - 1) / batchSize;
- log.info("澶ц溅璁惧鍒嗘壒涓婃枡: deviceId={}, totalGlassIds={}, batchSize={}, totalBatches={}, glassIntervalMs={}",
- device.getId(), allGlassIds.size(), batchSize, totalBatches, glassIntervalMs);
+ log.debug("澶ц溅璁惧鍒嗘壒涓婃枡: deviceId={}, totalGlassIds={}, batchSize={}, totalBatches={}",
+ device.getId(), allGlassIds.size(), batchSize, totalBatches);
for (int batchIndex = 0; batchIndex < totalBatches; batchIndex++) {
int startIndex = batchIndex * batchSize;
@@ -1392,7 +1639,6 @@
// 鍒涘缓涓存椂鍙傛暟锛屽彧鍖呭惈褰撳墠鎵规鐨勭幓鐠僆D
TaskParameters batchParams = new TaskParameters();
batchParams.setGlassIds(new ArrayList<>(batchGlassIds));
- batchParams.setGlassIntervalMs(glassIntervalMs);
batchParams.setPositionCode(context.getParameters().getPositionCode());
batchParams.setPositionValue(context.getParameters().getPositionValue());
@@ -1413,20 +1659,8 @@
return stepResult;
}
- log.info("澶ц溅璁惧鍒嗘壒涓婃枡鎴愬姛: deviceId={}, batchIndex={}/{}, glassIds={}",
+ log.debug("澶ц溅璁惧鍒嗘壒涓婃枡鎴愬姛: deviceId={}, batchIndex={}/{}, glassIds={}",
device.getId(), batchIndex + 1, totalBatches, batchGlassIds);
-
- // 濡傛灉涓嶆槸鏈�鍚庝竴鎵癸紝绛夊緟闂撮殧锛堟ā鎷熺幓鐠冩瘡鐗囪繍鍔ㄧ殑鏃堕棿锛�
- // 杩欎釜绛夊緟璁╁ぇ杞︽湁鏃堕棿澶勭悊褰撳墠鎵规鐨勭幓鐠冿紝鐒跺悗鍐嶄紶閫掍笅涓�鎵�
- if (batchIndex < totalBatches - 1 && glassIntervalMs != null && glassIntervalMs > 0) {
- try {
- log.info("绛夊緟鍗曠墖闂撮殧锛堟ā鎷熺幓鐠冭繍鍔ㄦ椂闂达級: glassIntervalMs={}ms, 澶ц溅鍙湪姝ゆ湡闂寸户缁鐜荤拑", glassIntervalMs);
- Thread.sleep(glassIntervalMs);
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- return StepResult.failure(device.getDeviceName(), "绛夊緟鍗曠墖闂撮殧鏃惰涓柇");
- }
- }
}
// 鏇存柊涓婁笅鏂囦腑鐨勫凡鍔犺浇鐜荤拑ID
@@ -1487,7 +1721,7 @@
Map<String, Object> params = buildOperationParams(device, context);
// 灏哻ontext寮曠敤鏀惧叆params锛屼緵璁惧澶勭悊鍣ㄤ娇鐢紙鐢ㄤ簬璁惧鍗忚皟锛�
params.put("_taskContext", context);
- log.info("executeStepWithRetry鏋勫缓鍙傛暟: deviceId={}, deviceType={}, operation={}, paramsKeys={}, params={}",
+ log.debug("executeStepWithRetry鏋勫缓鍙傛暟: deviceId={}, deviceType={}, operation={}, paramsKeys={}, params={}",
device.getId(), device.getDeviceType(), determineOperation(device, params), params.keySet(), params);
step.setInputData(toJson(params));
taskStepDetailMapper.updateById(step);
@@ -1503,7 +1737,7 @@
if (retryAttempt > 0) {
// 閲嶈瘯鍓嶇瓑寰�
long waitTime = retryPolicy.calculateRetryInterval(retryAttempt);
- log.info("姝ラ鎵ц閲嶈瘯: deviceId={}, operation={}, retryAttempt={}/{}, waitTime={}ms",
+ log.debug("姝ラ鎵ц閲嶈瘯: deviceId={}, operation={}, retryAttempt={}/{}, waitTime={}ms",
device.getId(), operation, retryAttempt, retryPolicy.getMaxRetryCount(), waitTime);
Thread.sleep(waitTime);
@@ -1697,7 +1931,7 @@
try {
if (retryAttempt > 0) {
long waitTime = retryPolicy.calculateRetryInterval(retryAttempt);
- log.info("浜や簰姝ラ鎵ц閲嶈瘯: deviceId={}, retryAttempt={}/{}, waitTime={}ms",
+ log.debug("浜や簰姝ラ鎵ц閲嶈瘯: deviceId={}, retryAttempt={}/{}, waitTime={}ms",
device.getId(), retryAttempt, retryPolicy.getMaxRetryCount(), waitTime);
Thread.sleep(waitTime);
@@ -1914,10 +2148,6 @@
if (taskParams.getPositionValue() != null) {
params.put("positionValue", taskParams.getPositionValue());
}
- // 浼犻�掑崟鐗囬棿闅旈厤缃紝濡傛灉浠诲姟鍙傛暟涓湁璁剧疆锛屼紭鍏堜娇鐢ㄤ换鍔″弬鏁扮殑锛屽惁鍒欎娇鐢ㄨ澶囬厤缃殑
- if (taskParams.getGlassIntervalMs() != null) {
- params.put("glassIntervalMs", taskParams.getGlassIntervalMs());
- }
params.put("triggerRequest", true);
break;
case DeviceConfig.DeviceType.LARGE_GLASS:
@@ -1935,13 +2165,13 @@
case DeviceConfig.DeviceType.WORKSTATION_SCANNER:
// 鍗ц浆绔嬫壂鐮佽澶囷細浠庝换鍔″弬鏁颁腑鑾峰彇鐜荤拑ID鍒楄〃锛屽彇绗竴涓綔涓哄綋鍓嶈娴嬭瘯鐨勭幓鐠僆D
// 娉ㄦ剰锛氭壂鐮佽澶囬�氬父閫氳繃瀹氭椂鍣ㄦ墽琛岋紝浣嗗鏋滈�氳繃executeStep鎵ц锛屼篃闇�瑕佷紶閫抔lassId
- log.info("buildOperationParams澶勭悊鎵爜璁惧: deviceId={}, taskParams.glassIds={}, isEmpty={}",
+ log.debug("buildOperationParams澶勭悊鎵爜璁惧: deviceId={}, taskParams.glassIds={}, isEmpty={}",
device.getId(), taskParams.getGlassIds(),
CollectionUtils.isEmpty(taskParams.getGlassIds()));
if (!CollectionUtils.isEmpty(taskParams.getGlassIds())) {
params.put("glassId", taskParams.getGlassIds().get(0));
params.put("glassIds", new ArrayList<>(taskParams.getGlassIds()));
- log.info("buildOperationParams涓烘壂鐮佽澶囨坊鍔爂lassId: deviceId={}, glassId={}, glassIdsSize={}",
+ log.debug("buildOperationParams涓烘壂鐮佽澶囨坊鍔爂lassId: deviceId={}, glassId={}, glassIdsSize={}",
device.getId(), taskParams.getGlassIds().get(0), taskParams.getGlassIds().size());
} else {
log.warn("buildOperationParams鎵爜璁惧glassIds涓虹┖: deviceId={}, taskParams.glassIds={}, taskParams={}",
@@ -2017,7 +2247,7 @@
if (!CollectionUtils.isEmpty(scannerGlassIds)) {
context.getParameters().setGlassIds(new ArrayList<>(scannerGlassIds));
context.setLoadedGlassIds(new ArrayList<>(scannerGlassIds));
- log.info("鍗ц浆绔嬫壂鐮佽幏鍙栧埌鐜荤拑ID: {}", scannerGlassIds);
+ log.debug("鍗ц浆绔嬫壂鐮佽幏鍙栧埌鐜荤拑ID: {}", scannerGlassIds);
} else {
log.warn("鍗ц浆绔嬫壂鐮佹湭鑾峰彇鍒扮幓鐠僆D锛屽悗缁澶囧彲鑳芥棤娉曟墽琛�");
}
diff --git a/mes-processes/mes-plcSend/src/main/java/com/mes/task/service/impl/TaskStatusNotificationServiceImpl.java b/mes-processes/mes-plcSend/src/main/java/com/mes/task/service/impl/TaskStatusNotificationServiceImpl.java
index 451e98a..917dd24 100644
--- a/mes-processes/mes-plcSend/src/main/java/com/mes/task/service/impl/TaskStatusNotificationServiceImpl.java
+++ b/mes-processes/mes-plcSend/src/main/java/com/mes/task/service/impl/TaskStatusNotificationServiceImpl.java
@@ -306,6 +306,7 @@
data.put("durationMs", step.getDurationMs() != null ? step.getDurationMs() : 0);
data.put("retryCount", step.getRetryCount() != null ? step.getRetryCount() : 0);
data.put("errorMessage", step.getErrorMessage() != null ? step.getErrorMessage() : "");
+ data.put("successMessage", step.getSuccessMessage() != null ? step.getSuccessMessage() : "");
return data;
}
diff --git a/mes-web/src/views/device/components/DeviceLogicConfig/LoadVehicleConfig.vue b/mes-web/src/views/device/components/DeviceLogicConfig/LoadVehicleConfig.vue
index 3bdf568..554bb78 100644
--- a/mes-web/src/views/device/components/DeviceLogicConfig/LoadVehicleConfig.vue
+++ b/mes-web/src/views/device/components/DeviceLogicConfig/LoadVehicleConfig.vue
@@ -32,16 +32,16 @@
<el-row :gutter="20">
<el-col :span="12">
- <el-form-item label="鐜荤拑闂撮殧(绉�)">
+ <el-form-item label="鐜荤拑闂撮殭(mm)">
<el-input-number
- v-model="glassIntervalSeconds"
- :min="0.1"
- :max="10"
- :step="0.1"
- :precision="1"
+ v-model="config.glassGap"
+ :min="0"
+ :max="1000"
+ :step="10"
style="width: 100%;"
+ @change="emitConfigUpdate"
/>
- <span class="form-tip">鐜荤拑涓婃枡闂撮殧鏃堕棿锛堢锛�</span>
+ <span class="form-tip">澶氬潡鐜荤拑涔嬮棿鐨勭墿鐞嗛棿闅旂┖闅欙紝榛樿200mm</span>
</el-form-item>
</el-col>
<el-col :span="12">
@@ -173,7 +173,7 @@
>
<el-input
v-model="item.key"
- placeholder="浣嶇疆浠g爜锛堝900/901锛�"
+ placeholder="浣嶇疆浠g爜锛堝1001/1002锛�"
size="small"
style="width: 150px; margin-right: 10px;"
@change="handlePositionKeyChange(index)"
@@ -221,7 +221,7 @@
const config = ref({
vehicleCapacity: 6000,
vehicleSpeed: 1.0,
- glassIntervalMs: 1000,
+ glassGap: 200,
defaultGlassLength: 2000,
homePosition: 0,
minRange: 1,
@@ -270,7 +270,6 @@
syncPositionListFromConfig()
// 鏃堕棿瀛楁锛堢锛�- 鐢ㄤ簬鍓嶇鏄剧ず鍜岃緭鍏�
-const glassIntervalSeconds = ref(1.0)
const idleMonitorIntervalSeconds = ref(2.0)
const taskMonitorIntervalSeconds = ref(1.0)
const mesConfirmTimeoutSeconds = ref(30)
@@ -282,7 +281,7 @@
config.value = {
vehicleCapacity: newVal.vehicleCapacity ?? 6000,
vehicleSpeed: newVal.vehicleSpeed ?? 1.0,
- glassIntervalMs: newVal.glassIntervalMs ?? 1000,
+ glassGap: newVal.glassGap ?? 200,
defaultGlassLength: newVal.defaultGlassLength ?? 2000,
homePosition: newVal.homePosition ?? 0,
minRange: newVal.minRange ?? 1,
@@ -295,7 +294,6 @@
positionMapping: newVal.positionMapping || {}
}
// 灏嗘绉掕浆鎹负绉掔敤浜庢樉绀�
- glassIntervalSeconds.value = (config.value.glassIntervalMs ?? 1000) / 1000
idleMonitorIntervalSeconds.value = (config.value.idleMonitorIntervalMs ?? 2000) / 1000
taskMonitorIntervalSeconds.value = (config.value.taskMonitorIntervalMs ?? 1000) / 1000
mesConfirmTimeoutSeconds.value = (config.value.mesConfirmTimeoutMs ?? 30000) / 1000
@@ -305,11 +303,6 @@
}, { immediate: true, deep: true })
// 鐩戝惉绉掑瓧娈靛彉鍖栵紝杞崲涓烘绉掑苟鏇存柊config
-watch(glassIntervalSeconds, (val) => {
- config.value.glassIntervalMs = Math.round(val * 1000)
- emitConfigUpdate()
-})
-
watch(idleMonitorIntervalSeconds, (val) => {
config.value.idleMonitorIntervalMs = Math.round(val * 1000)
emitConfigUpdate()
diff --git a/mes-web/src/views/device/components/DeviceLogicConfig/WorkstationTransferConfig.vue b/mes-web/src/views/device/components/DeviceLogicConfig/WorkstationTransferConfig.vue
index a765d95..8c7756a 100644
--- a/mes-web/src/views/device/components/DeviceLogicConfig/WorkstationTransferConfig.vue
+++ b/mes-web/src/views/device/components/DeviceLogicConfig/WorkstationTransferConfig.vue
@@ -2,18 +2,6 @@
<div class="workstation-transfer-config">
<el-row :gutter="20">
<el-col :span="12">
- <el-form-item label="鎵爜闂撮殧(绉�)">
- <el-input-number
- v-model="scanIntervalSeconds"
- :min="1"
- :max="60"
- :step="1"
- style="width: 100%;"
- />
- <span class="form-tip">瀹氭椂鏌ヨ鏈�杩戞壂鐮佺幓鐠冪殑鏃堕棿闂撮殧锛岄粯璁�10绉�</span>
- </el-form-item>
- </el-col>
- <el-col :span="12">
<el-form-item label="缂撳啿鍒ゅ畾鏃堕棿(绉�)">
<el-input-number
v-model="transferDelaySeconds"
@@ -40,6 +28,21 @@
<span class="form-tip">鍙杞界殑鏈�澶у搴︼紙姣背锛夛紝榛樿6000mm</span>
</el-form-item>
</el-col>
+ <el-col :span="12">
+ <el-form-item label="鐜荤拑闂撮殭(mm)">
+ <el-input-number
+ v-model="config.glassGap"
+ :min="0"
+ :max="1000"
+ :step="10"
+ style="width: 100%;"
+ />
+ <span class="form-tip">澶氬潡鐜荤拑涔嬮棿鐨勭墿鐞嗛棿闅旂┖闅欙紝榛樿200mm</span>
+ </el-form-item>
+ </el-col>
+ </el-row>
+
+ <el-row :gutter="20">
<el-col :span="12">
<el-form-item label="鐩戞帶闂撮殧(绉�)">
<el-input-number
@@ -68,7 +71,7 @@
</el-form-item>
</el-col>
<el-col :span="12">
- <el-form-item label="浣嶇疆鍊�(鏍�)">
+ <el-form-item label="鍗ц浆绔嬬紪鍙�">
<el-input-number
v-model="config.inPosition"
:min="0"
@@ -76,7 +79,7 @@
:step="1"
style="width: 100%;"
/>
- <span class="form-tip">鍐欏叆PLC鐨刬nPosition鍊硷紙鏍煎瓙锛�</span>
+ <span class="form-tip">鍐欏叆PLC鐨刬nPosition瀛楁锛岃〃绀哄崸杞珛缂栧彿</span>
</el-form-item>
</el-col>
</el-row>
@@ -97,16 +100,15 @@
// 閰嶇疆鏁版嵁
const config = ref({
- scanIntervalMs: 10000,
transferDelayMs: 30000,
vehicleCapacity: 6000,
+ glassGap: 200,
monitorIntervalMs: 10000,
workLine: null,
inPosition: null
})
// 鏃堕棿瀛楁锛堢锛�- 鐢ㄤ簬鍓嶇鏄剧ず鍜岃緭鍏�
-const scanIntervalSeconds = ref(10)
const transferDelaySeconds = ref(30)
const monitorIntervalSeconds = ref(10)
@@ -114,31 +116,20 @@
watch(() => props.modelValue, (newVal) => {
if (newVal && Object.keys(newVal).length > 0) {
config.value = {
- scanIntervalMs: newVal.scanIntervalMs ?? 10000,
transferDelayMs: newVal.transferDelayMs ?? 30000,
vehicleCapacity: newVal.vehicleCapacity ?? 6000,
- monitorIntervalMs: newVal.monitorIntervalMs ?? newVal.scanIntervalMs ?? 10000,
+ glassGap: newVal.glassGap ?? 200,
+ monitorIntervalMs: newVal.monitorIntervalMs ?? 10000,
workLine: newVal.workLine ?? null,
inPosition: newVal.inPosition ?? null
}
// 灏嗘绉掕浆鎹负绉掔敤浜庢樉绀�
- scanIntervalSeconds.value = (config.value.scanIntervalMs ?? 10000) / 1000
transferDelaySeconds.value = (config.value.transferDelayMs ?? 30000) / 1000
monitorIntervalSeconds.value = (config.value.monitorIntervalMs ?? 10000) / 1000
}
}, { immediate: true, deep: true })
// 鐩戝惉绉掑瓧娈靛彉鍖栵紝杞崲涓烘绉掑苟鏇存柊config
-watch(scanIntervalSeconds, (val) => {
- config.value.scanIntervalMs = Math.round(val * 1000)
- // 濡傛灉monitorIntervalMs鏈缃紝鍒欎娇鐢╯canIntervalMs
- if (!props.modelValue?.monitorIntervalMs) {
- config.value.monitorIntervalMs = config.value.scanIntervalMs
- monitorIntervalSeconds.value = val
- }
- emit('update:modelValue', { ...config.value })
-})
-
watch(transferDelaySeconds, (val) => {
config.value.transferDelayMs = Math.round(val * 1000)
emit('update:modelValue', { ...config.value })
@@ -152,6 +143,7 @@
// 鐩戝惉config鍏朵粬瀛楁鍙樺寲锛屽悓姝ュ埌鐖剁粍浠�
watch(() => [
config.value.vehicleCapacity,
+ config.value.glassGap,
config.value.workLine,
config.value.inPosition
], () => {
diff --git a/mes-web/src/views/plcTest/MultiDeviceWorkbench.vue b/mes-web/src/views/plcTest/MultiDeviceWorkbench.vue
index 1c2dd81..11fa3ef 100644
--- a/mes-web/src/views/plcTest/MultiDeviceWorkbench.vue
+++ b/mes-web/src/views/plcTest/MultiDeviceWorkbench.vue
@@ -3,11 +3,6 @@
<div class="main-grid">
<div class="left-panel">
<GroupList @select="handleGroupSelect" />
- <GroupTopology
- v-if="selectedGroup"
- :group="selectedGroup"
- class="topology-panel"
- />
</div>
<div class="right-panel">
<el-tabs v-model="activeTab" type="card" class="workbench-tabs">
@@ -42,7 +37,6 @@
<script setup>
import { computed, ref, watch } from 'vue'
import GroupList from './components/DeviceGroup/GroupList.vue'
-import GroupTopology from './components/DeviceGroup/GroupTopology.vue'
import TaskOrchestration from './components/MultiDeviceTest/TaskOrchestration.vue'
import ExecutionMonitor from './components/MultiDeviceTest/ExecutionMonitor.vue'
import ResultAnalysis from './components/MultiDeviceTest/ResultAnalysis.vue'
@@ -118,11 +112,6 @@
display: flex;
flex-direction: column;
gap: 24px;
-}
-
-.topology-panel {
- flex: 1;
- min-height: 300px;
}
.right-panel {
diff --git a/mes-web/src/views/plcTest/components/DeviceGroup/GroupTopology.vue b/mes-web/src/views/plcTest/components/DeviceGroup/GroupTopology.vue
index 8729075..b9a5872 100644
--- a/mes-web/src/views/plcTest/components/DeviceGroup/GroupTopology.vue
+++ b/mes-web/src/views/plcTest/components/DeviceGroup/GroupTopology.vue
@@ -44,9 +44,19 @@
<div class="node-name">{{ device.deviceName || device.deviceCode }}</div>
<div class="node-type">{{ getDeviceTypeLabel(device.deviceType) }}</div>
<div class="node-status">
- <el-tag :type="getStatusType(device.status)" size="small">
- {{ getStatusLabel(device.status) }}
+ <el-tag :type="getStatusType(getDeviceStatus(device))" size="small">
+ {{ getStatusLabel(getDeviceStatus(device)) }}
</el-tag>
+ </div>
+ <div class="node-actions">
+ <el-button
+ size="small"
+ text
+ @click.stop="clearPlc(device)"
+ :loading="clearingDeviceId === (device.deviceId || device.id)"
+ >
+ 娓呯┖ PLC
+ </el-button>
</div>
</div>
</div>
@@ -91,9 +101,28 @@
{{ getDeviceTypeLabel(selectedDevice.deviceType) }}
</el-descriptions-item>
<el-descriptions-item label="鐘舵��">
- <el-tag :type="getStatusType(selectedDevice.status)">
- {{ getStatusLabel(selectedDevice.status) }}
- </el-tag>
+ <div class="status-control">
+ <el-tag :type="getStatusType(getDeviceStatus(selectedDevice))">
+ {{ getStatusLabel(getDeviceStatus(selectedDevice)) }}
+ </el-tag>
+ <el-switch
+ v-if="isLoadVehicleDevice(selectedDevice)"
+ :model-value="Boolean(selectedDevice.onlineState)"
+ active-text="鑱旀満"
+ inactive-text="鑴辨満"
+ :loading="togglingDeviceId === (selectedDevice.deviceId || selectedDevice.id)"
+ size="small"
+ @change="(val) => toggleOnlineState(selectedDevice, val)"
+ />
+ <el-button
+ size="small"
+ text
+ @click="clearPlc(selectedDevice)"
+ :loading="clearingDeviceId === (selectedDevice.deviceId || selectedDevice.id)"
+ >
+ 娓呯┖ PLC
+ </el-button>
+ </div>
</el-descriptions-item>
<el-descriptions-item label="PLC IP" v-if="selectedDevice.plcIp">
{{ selectedDevice.plcIp }}
@@ -115,7 +144,7 @@
</template>
<script setup>
-import { computed, ref, watch } from 'vue'
+import { computed, ref, watch, onMounted, onUnmounted } from 'vue'
import { ElMessage } from 'element-plus'
import {
Refresh,
@@ -127,7 +156,7 @@
Box,
Folder
} from '@element-plus/icons-vue'
-import { deviceGroupApi } from '@/api/device/deviceManagement'
+import { deviceGroupApi, deviceInteractionApi } from '@/api/device/deviceManagement'
const props = defineProps({
group: {
@@ -140,6 +169,10 @@
const devices = ref([])
const layoutMode = ref('horizontal') // 'horizontal' | 'vertical'
const selectedDevice = ref(null)
+const togglingDeviceId = ref(null)
+const clearingDeviceId = ref(null)
+const refreshIntervalMs = 5000
+let refreshTimer = null
const fetchDevices = async () => {
if (!props.group) {
@@ -163,11 +196,14 @@
? rawList.data
: []
// 鎸夋墽琛岄『搴忔帓搴�
- devices.value = deviceList.sort((a, b) => {
- const orderA = a.executionOrder || a.order || 0
- const orderB = b.executionOrder || b.order || 0
- return orderA - orderB
- })
+ devices.value = deviceList
+ .map((device) => normalizeDevice(device))
+ .sort((a, b) => {
+ const orderA = a.executionOrder || a.order || 0
+ const orderB = b.executionOrder || b.order || 0
+ return orderA - orderB
+ })
+ syncSelectedDevice()
} catch (error) {
ElMessage.error(error?.message || '鍔犺浇璁惧鍒楄〃澶辫触')
devices.value = []
@@ -178,6 +214,21 @@
const handleRefresh = () => {
fetchDevices()
+}
+
+const stopAutoRefresh = () => {
+ if (refreshTimer) {
+ clearInterval(refreshTimer)
+ refreshTimer = null
+ }
+}
+
+const startAutoRefresh = () => {
+ stopAutoRefresh()
+ if (!props.group) return
+ refreshTimer = setInterval(() => {
+ fetchDevices()
+ }, refreshIntervalMs)
}
const toggleLayout = () => {
@@ -250,13 +301,129 @@
() => {
fetchDevices()
selectedDevice.value = null
+ startAutoRefresh()
},
{ immediate: true }
)
+onMounted(() => {
+ startAutoRefresh()
+})
+
+onUnmounted(() => {
+ stopAutoRefresh()
+})
+
// 鐐瑰嚮鑺傜偣閫夋嫨璁惧
const handleNodeClick = (device) => {
selectedDevice.value = device
+}
+
+const syncSelectedDevice = () => {
+ if (!selectedDevice.value) return
+ const deviceId = selectedDevice.value.deviceId || selectedDevice.value.id
+ if (!deviceId) return
+ const updated = devices.value.find(
+ (item) => (item.deviceId || item.id) === deviceId
+ )
+ if (updated) {
+ selectedDevice.value = updated
+ }
+}
+
+const isLoadVehicleDevice = (device) => {
+ if (!device || !device.deviceType) return false
+ const type = device.deviceType.toUpperCase()
+ return type.includes('VEHICLE') || type.includes('澶ц溅')
+}
+
+const normalizeDevice = (device) => {
+ if (!device) return device
+ const normalized = { ...device }
+ if (normalized.onlineState !== undefined) {
+ normalized.onlineState = toBoolean(normalized.onlineState)
+ } else if (normalized.isOnline === true || normalized.isOnline === false) {
+ normalized.onlineState = normalized.isOnline
+ } else if (normalized.status) {
+ normalized.onlineState = String(normalized.status).toUpperCase() === 'ONLINE'
+ }
+ if (isLoadVehicleDevice(normalized) && normalized.onlineState !== undefined) {
+ normalized.status = normalized.onlineState ? 'ONLINE' : 'OFFLINE'
+ }
+ return normalized
+}
+
+const toBoolean = (value) => {
+ if (value === true || value === false) return value
+ if (typeof value === 'number') return value !== 0
+ const str = String(value).trim().toLowerCase()
+ if (str === 'true' || str === '1') return true
+ if (str === 'false' || str === '0') return false
+ return Boolean(value)
+}
+
+const getDeviceStatus = (device) => {
+ if (!device) return 'UNKNOWN'
+ if (isLoadVehicleDevice(device) && device.onlineState !== undefined) {
+ return device.onlineState ? 'ONLINE' : 'OFFLINE'
+ }
+ if (device.isOnline === true || device.isOnline === false) {
+ return device.isOnline ? 'ONLINE' : 'OFFLINE'
+ }
+ if (device.status) return device.status
+ if (device.deviceStatus) return device.deviceStatus
+ return 'UNKNOWN'
+}
+
+const toggleOnlineState = async (device, value) => {
+ if (!device) return
+ const deviceId = device.deviceId || device.id
+ if (!deviceId) {
+ ElMessage.warning('璁惧ID涓嶅瓨鍦紝鏃犳硶璁剧疆鑱旀満鐘舵��')
+ return
+ }
+ try {
+ togglingDeviceId.value = deviceId
+ await deviceInteractionApi.executeOperation({
+ deviceId,
+ operation: 'setOnlineState',
+ params: {
+ onlineState: value
+ }
+ })
+ device.onlineState = value
+ device.status = value ? 'ONLINE' : 'OFFLINE'
+ if (selectedDevice.value && (selectedDevice.value.deviceId === deviceId || selectedDevice.value.id === deviceId)) {
+ selectedDevice.value.onlineState = device.onlineState
+ selectedDevice.value.status = device.status
+ }
+ ElMessage.success(`宸插皢 ${device.deviceName || device.deviceCode} 璁剧疆涓�${value ? '鑱旀満' : '鑴辨満'}`)
+ } catch (error) {
+ ElMessage.error(error?.message || '璁剧疆鑱旀満鐘舵�佸け璐�')
+ } finally {
+ togglingDeviceId.value = null
+ }
+}
+
+const clearPlc = async (device) => {
+ if (!device) return
+ const deviceId = device.deviceId || device.id
+ if (!deviceId) {
+ ElMessage.warning('璁惧ID涓嶅瓨鍦紝鏃犳硶娓呯┖PLC')
+ return
+ }
+ try {
+ clearingDeviceId.value = deviceId
+ await deviceInteractionApi.executeOperation({
+ deviceId,
+ operation: 'clearPlc'
+ })
+ ElMessage.success(`宸叉竻绌� ${device.deviceName || device.deviceCode} 鐨凱LC鏁版嵁`)
+ } catch (error) {
+ ElMessage.error(error?.message || '娓呯┖PLC澶辫触')
+ } finally {
+ clearingDeviceId.value = null
+ }
}
defineExpose({
@@ -422,6 +589,12 @@
justify-content: center;
}
+.node-actions {
+ margin-top: 6px;
+ display: flex;
+ justify-content: center;
+}
+
.node-order {
position: absolute;
top: -8px;
@@ -447,6 +620,12 @@
justify-content: center;
}
+.status-control {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+}
+
/* 姘村钩甯冨眬锛氱澶村湪鑺傜偣鍙充晶 */
.topology-node-wrapper.layout-horizontal .node-arrow {
margin-left: 20px;
diff --git a/mes-web/src/views/plcTest/components/MultiDeviceTest/ExecutionMonitor.vue b/mes-web/src/views/plcTest/components/MultiDeviceTest/ExecutionMonitor.vue
index a221de2..d475c11 100644
--- a/mes-web/src/views/plcTest/components/MultiDeviceTest/ExecutionMonitor.vue
+++ b/mes-web/src/views/plcTest/components/MultiDeviceTest/ExecutionMonitor.vue
@@ -128,6 +128,9 @@
<div class="step-desc" v-if="step.retryCount > 0">
閲嶈瘯娆℃暟锛歿{ step.retryCount }}
</div>
+ <div class="step-desc" v-if="step.successMessage">
+ 鎻愮ず锛歿{ step.successMessage }}
+ </div>
<div class="step-desc error-message" v-if="step.errorMessage">
<el-icon><Warning /></el-icon>
閿欒锛歿{ step.errorMessage }}
@@ -367,6 +370,7 @@
endTime: data.endTime ? new Date(data.endTime) : existingStep.endTime,
durationMs: data.durationMs !== undefined ? data.durationMs : existingStep.durationMs,
retryCount: data.retryCount !== undefined ? data.retryCount : existingStep.retryCount,
+ successMessage: data.successMessage !== undefined ? data.successMessage : existingStep.successMessage,
errorMessage: data.errorMessage || existingStep.errorMessage
}
} else if (data.stepOrder !== undefined) {
diff --git a/mes-web/src/views/plcTest/components/MultiDeviceTest/TaskOrchestration.vue b/mes-web/src/views/plcTest/components/MultiDeviceTest/TaskOrchestration.vue
index 0d7d3a7..107603c 100644
--- a/mes-web/src/views/plcTest/components/MultiDeviceTest/TaskOrchestration.vue
+++ b/mes-web/src/views/plcTest/components/MultiDeviceTest/TaskOrchestration.vue
@@ -31,7 +31,7 @@
v-model="glassIdsInput"
type="textarea"
:rows="4"
- placeholder="鍙�夛細濡傛灉杈撳叆鐜荤拑ID锛屽皢浣跨敤杈撳叆鐨処D杩涜娴嬭瘯锛堜唬鏇垮崸杞珛鎵爜锛夛紱濡傛灉涓嶈緭鍏ワ紝灏嗕粠鏁版嵁搴撹鍙栨渶杩戞壂鐮佺殑鐜荤拑ID杩涜娴嬭瘯"
+ placeholder="鍙�夛細杈撳叆鐜荤拑ID锛屽皢浣跨敤杈撳叆鐨処D杩涜娴嬭瘯"
show-word-limit
:maxlength="5000"
/>
@@ -40,54 +40,14 @@
<span v-else>鏈緭鍏ョ幓鐠僆D锛堟甯告ā寮忥細灏嗕粠鏁版嵁搴撹鍙栨渶杩戞壂鐮佺殑鐜荤拑ID锛�</span>
</div>
</el-form-item>
-
- <el-divider content-position="left">鎵ц閰嶇疆</el-divider>
-
- <el-form-item label="鍗曠墖闂撮殧 (绉�)">
- <el-input-number
- v-model="form.glassIntervalSeconds"
- :min="0"
- :max="60"
- :step="0.1"
- :precision="1"
- placeholder="姣忎釜鐜荤拑ID涔嬮棿鐨勯棿闅旀椂闂�"
- />
- <div class="form-tip">澶氫釜鐜荤拑ID鏃讹紝姣忎釜鐜荤拑ID浼犻�掍箣闂寸殑闂撮殧鏃堕棿锛堢锛夛紝鐢ㄤ簬妯℃嫙鐜荤拑姣忕墖杩愬姩鐨勬椂闂淬��0琛ㄧず涓�娆℃�у叏閮ㄤ紶閫�</div>
- </el-form-item>
-
- <el-form-item label="鎵ц闂撮殧 (ms)">
- <el-input-number
- v-model="form.executionInterval"
- :min="100"
- :max="10000"
- :step="100"
- placeholder="璁惧鎿嶄綔闂撮殧鏃堕棿"
- />
- <div class="form-tip">姣忎釜璁惧鎿嶄綔涔嬮棿鐨勯棿闅旀椂闂达紙姣锛�</div>
- </el-form-item>
-
- <el-form-item label="瓒呮椂鏃堕棿 (鍒嗛挓)">
- <el-input-number
- v-model="form.timeoutMinutes"
- :min="1"
- :max="60"
- :step="1"
- placeholder="浠诲姟瓒呮椂鏃堕棿"
- />
- <div class="form-tip">浠诲姟鎵ц鐨勬渶澶ц秴鏃舵椂闂�</div>
- </el-form-item>
-
- <el-form-item label="閲嶈瘯娆℃暟">
- <el-input-number
- v-model="form.retryCount"
- :min="0"
- :max="10"
- :step="1"
- placeholder="澶辫触閲嶈瘯娆℃暟"
- />
- <div class="form-tip">璁惧鎿嶄綔澶辫触鏃剁殑鏈�澶ч噸璇曟鏁�</div>
- </el-form-item>
</el-form>
+
+ <!-- 璁惧缁勬嫇鎵戝浘 -->
+ <GroupTopology
+ v-if="group"
+ :group="group"
+ class="topology-section"
+ />
</div>
</template>
@@ -97,6 +57,7 @@
import { Delete, Promotion } from '@element-plus/icons-vue'
import { multiDeviceTaskApi } from '@/api/device/multiDeviceTask'
import { deviceGroupApi, deviceInteractionApi } from '@/api/device/deviceManagement'
+import GroupTopology from '../DeviceGroup/GroupTopology.vue'
const props = defineProps({
group: {
@@ -107,12 +68,7 @@
const emit = defineEmits(['task-started'])
//閰嶇疆榛樿鍊�
-const form = reactive({
- glassIntervalSeconds: 10, // 鍗曠墖闂撮殧锛岄粯璁�10绉�
- executionInterval: 1000,
- timeoutMinutes: 1,
- retryCount: 3
-})
+const form = reactive({})
const formRef = ref(null)
@@ -231,22 +187,8 @@
// 鏋勫缓浠诲姟鍙傛暟
// 濡傛灉杈撳叆浜嗙幓鐠僆D锛屼娇鐢ㄨ緭鍏ョ殑锛涘鏋滄病鏈夎緭鍏ワ紝glassIds涓虹┖鏁扮粍锛屽悗绔細浠庢暟鎹簱璇诲彇
- // 灏嗙杞崲涓烘绉掍紶缁欏悗绔�
- const glassIntervalMs = form.glassIntervalSeconds != null && form.glassIntervalSeconds !== undefined
- ? Math.round(form.glassIntervalSeconds * 1000)
- : 1000
const parameters = {
- glassIds: glassIds.value.length > 0 ? glassIds.value : [],
- glassIntervalMs: glassIntervalMs,
- executionInterval: form.executionInterval || 1000
- }
-
- // 璁惧鐗瑰畾閰嶇疆宸茬Щ闄わ紝濡傛湁闇�瑕佸彲鍦ㄦ鎵╁睍
- if (form.timeoutMinutes) {
- parameters.timeoutMinutes = form.timeoutMinutes
- }
- if (form.retryCount !== null) {
- parameters.retryCount = form.retryCount
+ glassIds: glassIds.value.length > 0 ? glassIds.value : []
}
// 寮傛鍚姩浠诲姟锛岀珛鍗宠繑鍥烇紝涓嶉樆濉�
@@ -362,5 +304,9 @@
margin-top: 4px;
line-height: 1.4;
}
+
+.topology-section {
+ margin-top: 24px;
+}
</style>
--
Gitblit v1.8.0