From 34f1e65179910f3c02f0ac6813dbfefb4244d4d7 Mon Sep 17 00:00:00 2001
From: wanshenmean <cathay_xy@163.com>
Date: 星期三, 15 四月 2026 19:23:24 +0800
Subject: [PATCH] feat(同步服务): 添加实例同步功能并优化更新逻辑
---
Code/测试工具/WIDESEAWCS_S7Simulator/.omc/state/mission-state.json | 53 +++++++++++++++++
Code/测试工具/WIDESEAWCS_S7Simulator/.omc/state/idle-notif-cooldown.json | 3 +
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/RobotTaskService.cs | 6 +-
Code/测试工具/WIDESEAWCS_S7Simulator/.omc/state/subagent-tracking.json | 17 +++++
Code/测试工具/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.Application/InstanceSyncService.cs | 22 +++++++
Code/测试工具/WIDESEAWCS_S7Simulator/.omc/state/agent-replay-584f6639-de9a-47e8-a9e4-f92fac6305be.jsonl | 2
Code/测试工具/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.Web/src/views/HomeView.vue | 18 ++++++
Code/测试工具/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.Web/src/api/index.ts | 12 ++++
8 files changed, 129 insertions(+), 4 deletions(-)
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/RobotTaskService.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/RobotTaskService.cs
index f1c12ab..5ff1ed7 100644
--- a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/RobotTaskService.cs
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/RobotTaskService.cs
@@ -225,9 +225,9 @@
CommonConveyorLine conveyorLine = (CommonConveyorLine)device;
DeviceProDTO? devicePro = conveyorLine.DeviceProDTOs.FirstOrDefault(x => x.DeviceProParamName == nameof(ConveyorLineDBNameNew.Barcode) && x.DeviceChildCode == sourceLineNo);
- ConveyorLineTaskCommandNew command = conveyorLine.ReadCustomer<ConveyorLineTaskCommandNew>(sourceLineNo); // 娴嬭瘯鐢�
- //var barcode = conveyorLine.GetValue<ConveyorLineDBNameNew, string>(ConveyorLineDBNameNew.Barcode, sourceLineNo);
- stock.SourcePalletNo = string.IsNullOrEmpty(command.Barcode.Replace("\0", "").ToString()) ? string.Empty : command.Barcode.Replace("\0", "").ToString();
+ //ConveyorLineTaskCommandNew command = conveyorLine.ReadCustomer<ConveyorLineTaskCommandNew>(sourceLineNo); // 娴嬭瘯鐢�
+ var barcode = conveyorLine.GetValue<ConveyorLineDBNameNew, string>(ConveyorLineDBNameNew.Barcode, sourceLineNo);
+ stock.SourcePalletNo = string.IsNullOrEmpty(barcode) ? string.Empty : barcode;
}
}
diff --git "a/Code/\346\265\213\350\257\225\345\267\245\345\205\267/WIDESEAWCS_S7Simulator/.omc/state/agent-replay-584f6639-de9a-47e8-a9e4-f92fac6305be.jsonl" "b/Code/\346\265\213\350\257\225\345\267\245\345\205\267/WIDESEAWCS_S7Simulator/.omc/state/agent-replay-584f6639-de9a-47e8-a9e4-f92fac6305be.jsonl"
new file mode 100644
index 0000000..2531477
--- /dev/null
+++ "b/Code/\346\265\213\350\257\225\345\267\245\345\205\267/WIDESEAWCS_S7Simulator/.omc/state/agent-replay-584f6639-de9a-47e8-a9e4-f92fac6305be.jsonl"
@@ -0,0 +1,2 @@
+{"t":0,"agent":"ae21cf2","agent_type":"explore","event":"agent_start","parent_mode":"none"}
+{"t":0,"agent":"ae21cf2","agent_type":"explore","event":"agent_stop","success":true,"duration_ms":129137}
diff --git "a/Code/\346\265\213\350\257\225\345\267\245\345\205\267/WIDESEAWCS_S7Simulator/.omc/state/idle-notif-cooldown.json" "b/Code/\346\265\213\350\257\225\345\267\245\345\205\267/WIDESEAWCS_S7Simulator/.omc/state/idle-notif-cooldown.json"
new file mode 100644
index 0000000..999c83a
--- /dev/null
+++ "b/Code/\346\265\213\350\257\225\345\267\245\345\205\267/WIDESEAWCS_S7Simulator/.omc/state/idle-notif-cooldown.json"
@@ -0,0 +1,3 @@
+{
+ "lastSentAt": "2026-04-15T07:13:52.473Z"
+}
\ No newline at end of file
diff --git "a/Code/\346\265\213\350\257\225\345\267\245\345\205\267/WIDESEAWCS_S7Simulator/.omc/state/mission-state.json" "b/Code/\346\265\213\350\257\225\345\267\245\345\205\267/WIDESEAWCS_S7Simulator/.omc/state/mission-state.json"
new file mode 100644
index 0000000..3ab59d9
--- /dev/null
+++ "b/Code/\346\265\213\350\257\225\345\267\245\345\205\267/WIDESEAWCS_S7Simulator/.omc/state/mission-state.json"
@@ -0,0 +1,53 @@
+{
+ "updatedAt": "2026-04-15T06:44:32.119Z",
+ "missions": [
+ {
+ "id": "session:584f6639-de9a-47e8-a9e4-f92fac6305be:none",
+ "source": "session",
+ "name": "none",
+ "objective": "Session mission",
+ "createdAt": "2026-04-15T06:42:22.982Z",
+ "updatedAt": "2026-04-15T06:44:32.119Z",
+ "status": "done",
+ "workerCount": 1,
+ "taskCounts": {
+ "total": 1,
+ "pending": 0,
+ "blocked": 0,
+ "inProgress": 0,
+ "completed": 1,
+ "failed": 0
+ },
+ "agents": [
+ {
+ "name": "explore:ae21cf2",
+ "role": "explore",
+ "ownership": "ae21cf28e45f297ff",
+ "status": "done",
+ "currentStep": null,
+ "latestUpdate": "completed",
+ "completedSummary": null,
+ "updatedAt": "2026-04-15T06:44:32.119Z"
+ }
+ ],
+ "timeline": [
+ {
+ "id": "session-start:ae21cf28e45f297ff:2026-04-15T06:42:22.982Z",
+ "at": "2026-04-15T06:42:22.982Z",
+ "kind": "update",
+ "agent": "explore:ae21cf2",
+ "detail": "started explore:ae21cf2",
+ "sourceKey": "session-start:ae21cf28e45f297ff"
+ },
+ {
+ "id": "session-stop:ae21cf28e45f297ff:2026-04-15T06:44:32.119Z",
+ "at": "2026-04-15T06:44:32.119Z",
+ "kind": "completion",
+ "agent": "explore:ae21cf2",
+ "detail": "completed",
+ "sourceKey": "session-stop:ae21cf28e45f297ff"
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git "a/Code/\346\265\213\350\257\225\345\267\245\345\205\267/WIDESEAWCS_S7Simulator/.omc/state/subagent-tracking.json" "b/Code/\346\265\213\350\257\225\345\267\245\345\205\267/WIDESEAWCS_S7Simulator/.omc/state/subagent-tracking.json"
new file mode 100644
index 0000000..36a8077
--- /dev/null
+++ "b/Code/\346\265\213\350\257\225\345\267\245\345\205\267/WIDESEAWCS_S7Simulator/.omc/state/subagent-tracking.json"
@@ -0,0 +1,17 @@
+{
+ "agents": [
+ {
+ "agent_id": "ae21cf28e45f297ff",
+ "agent_type": "explore",
+ "started_at": "2026-04-15T06:42:22.982Z",
+ "parent_mode": "none",
+ "status": "completed",
+ "completed_at": "2026-04-15T06:44:32.119Z",
+ "duration_ms": 129137
+ }
+ ],
+ "total_spawned": 1,
+ "total_completed": 1,
+ "total_failed": 0,
+ "last_updated": "2026-04-15T06:44:32.224Z"
+}
\ No newline at end of file
diff --git "a/Code/\346\265\213\350\257\225\345\267\245\345\205\267/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.Application/InstanceSyncService.cs" "b/Code/\346\265\213\350\257\225\345\267\245\345\205\267/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.Application/InstanceSyncService.cs"
index d23bffd..3315faf 100644
--- "a/Code/\346\265\213\350\257\225\345\267\245\345\205\267/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.Application/InstanceSyncService.cs"
+++ "b/Code/\346\265\213\350\257\225\345\267\245\345\205\267/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.Application/InstanceSyncService.cs"
@@ -116,7 +116,27 @@
// 4.4 鍒涘缓鎴栨洿鏂板疄渚�
if (_instanceManager.InstanceExists(device.DeviceCode))
{
- _logger.LogInformation("瀹炰緥 {DeviceCode} 宸插瓨鍦紝璺宠繃鍒涘缓", device.DeviceCode);
+ // 瀹炰緥宸插瓨鍦紝鏇存柊閰嶇疆
+ var instance = _instanceManager.GetInstance(device.DeviceCode);
+ if (instance != null)
+ {
+ var oldState = instance.GetState();
+ var wasRunning = oldState.Status == InstanceStatus.Running;
+
+ // 鍋滄鏃у疄渚�
+ await _instanceManager.StopInstanceAsync(device.DeviceCode);
+
+ // 鍒犻櫎鏃у疄渚嬶紙淇濈暀閰嶇疆锛�
+ await _instanceManager.DeleteInstanceAsync(device.DeviceCode, deleteConfig: false);
+
+ // 閲嶆柊鍒涘缓瀹炰緥
+ var newInstance = await _instanceManager.CreateInstanceAsync(config);
+ if (wasRunning)
+ {
+ await _instanceManager.StartInstanceAsync(device.DeviceCode);
+ }
+ _logger.LogInformation("宸叉洿鏂板疄渚� {DeviceCode} (绔彛:{Port})", device.DeviceCode, device.DevicePort);
+ }
}
else
{
diff --git "a/Code/\346\265\213\350\257\225\345\267\245\345\205\267/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.Web/src/api/index.ts" "b/Code/\346\265\213\350\257\225\345\267\245\345\205\267/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.Web/src/api/index.ts"
index c45b917..c963cde 100644
--- "a/Code/\346\265\213\350\257\225\345\267\245\345\205\267/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.Web/src/api/index.ts"
+++ "b/Code/\346\265\213\350\257\225\345\267\245\345\205\267/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.Web/src/api/index.ts"
@@ -178,6 +178,18 @@
}
}
+// 閲嶆柊鍚屾瀹炰緥锛堜粠鏁版嵁搴撻噸鏂拌幏鍙栵級
+export async function syncInstances(): Promise<{ message: string; lastSyncTime: string }> {
+ const response = await api.post<{ message: string; lastSyncTime: string }>('/Sync/SyncInstances')
+ return response.data
+}
+
+// 鑾峰彇涓婃鍚屾鏃堕棿
+export async function getLastSyncTime(): Promise<{ lastSyncTime: string | null }> {
+ const response = await api.get<{ lastSyncTime: string | null }>('/Sync/LastSyncTime')
+ return response.data
+}
+
// 鑾峰彇鏈烘鎵嬫湇鍔$杩愯鐘舵�侊紙鍖呭惈澶氬疄渚嬪拰鎺ユ敹娑堟伅鏃ュ織锛�
export async function getRobotClientStatus(): Promise<RobotClientStatusResponse> {
const response = await api.get<RobotClientStatusResponse>('/RobotClients/status')
diff --git "a/Code/\346\265\213\350\257\225\345\267\245\345\205\267/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.Web/src/views/HomeView.vue" "b/Code/\346\265\213\350\257\225\345\267\245\345\205\267/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.Web/src/views/HomeView.vue"
index 06cb505..f16afb0 100644
--- "a/Code/\346\265\213\350\257\225\345\267\245\345\205\267/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.Web/src/views/HomeView.vue"
+++ "b/Code/\346\265\213\350\257\225\345\267\245\345\205\267/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.Web/src/views/HomeView.vue"
@@ -13,6 +13,10 @@
<p class="text-muted">绠$悊鍜岀洃鎺� S7 PLC 妯℃嫙鍣ㄥ疄渚�</p>
</div>
<div class="header-right">
+ <el-button type="default" @click="handleRefresh">
+ <el-icon><Refresh /></el-icon>
+ 閲嶆柊鑾峰彇瀹炰緥
+ </el-button>
<el-button type="primary" class="create-btn" @click="$router.push('/create')">
<el-icon><Plus /></el-icon>
鍒涘缓瀹炰緥
@@ -173,11 +177,14 @@
import { onMounted, onUnmounted, ref } from 'vue'
import { storeToRefs } from 'pinia'
import { useInstancesStore } from '../stores/instances'
+import api from '../api'
+import { syncInstances } from '../api'
import { ElMessage, ElMessageBox } from 'element-plus'
import {
Cpu,
Plus,
Loading,
+ Refresh,
User,
VideoPause,
VideoPlay,
@@ -199,6 +206,17 @@
store.stopAutoRefresh()
})
+async function handleRefresh() {
+ try {
+ await syncInstances()
+ await store.loadInstances()
+ ElMessage.success('宸查噸鏂拌幏鍙栧疄渚嬪垪琛�')
+ } catch (err) {
+ console.error('鍚屾澶辫触:', err)
+ ElMessage.error('鍚屾澶辫触锛岃鏌ョ湅鎺у埗鍙�')
+ }
+}
+
async function handleStart(id: string) {
try {
await ElMessageBox.confirm(`纭畾瑕佸惎鍔ㄥ疄渚� "${id}" 鍚楋紵`, '纭', {
--
Gitblit v1.9.3