From b6e85fdc5612ef6e9d7073af56df5076b87c31d7 Mon Sep 17 00:00:00 2001 From: luoyifan Date: Wed, 2 Jul 2025 23:43:18 +0800 Subject: [PATCH] =?UTF-8?q?LccMqttManager=20/=20EnvManager=20=E8=84=B1?= =?UTF-8?q?=E7=A6=BB=20viewport=20=E4=B9=9F=E8=83=BD=E8=BF=90=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/engine/Viewport.ts | 4 -- src/core/manager/EnvManager.ts | 80 +++---------------------------- src/core/manager/LccMqttManager.ts | 9 ++-- src/core/manager/WorldModel.ts | 10 +++- src/core/manager/amr/AmrMessageManager.ts | 42 ++++++++-------- src/core/script/LCCScript.ts | 71 +++++++++++++++++++++------ src/core/script/ModelManager.ts | 5 -- src/core/script/RCSScript.ts | 6 --- src/editor/ModelMain.vue | 6 +-- src/types/LCC.d.ts | 16 ++++++- 10 files changed, 113 insertions(+), 136 deletions(-) diff --git a/src/core/engine/Viewport.ts b/src/core/engine/Viewport.ts index fb7e04c..488b9a5 100644 --- a/src/core/engine/Viewport.ts +++ b/src/core/engine/Viewport.ts @@ -52,8 +52,6 @@ export default class Viewport { interactionManager = new InteractionManager() modelManager = new ModelManager() runtimeManager = new RuntimeManager() - lccMqttManager = new LccMqttManager() - envManager = new EnvManager() // 状态管理器 stateManager: StateManager @@ -68,8 +66,6 @@ export default class Viewport { markRaw(this.interactionManager), markRaw(this.modelManager), markRaw(this.runtimeManager), - markRaw(this.envManager), - markRaw(this.lccMqttManager) ] registerFrameTimerCallBack: Map void> = new Map() diff --git a/src/core/manager/EnvManager.ts b/src/core/manager/EnvManager.ts index f424762..192e2ac 100644 --- a/src/core/manager/EnvManager.ts +++ b/src/core/manager/EnvManager.ts @@ -9,71 +9,9 @@ import { AmrMsg } from '@/core/manager/amr/AmrMessageDefine' export default class EnvManager { private viewport: Viewport - private amrMessageManager: AmrMessageManager = null + private amrMessageManager: AmrMessageManager = new AmrMessageManager() public client: mqtt.MqttClient = null - init(viewport: Viewport): void { - this.viewport = viewport - if (!this.amrMessageManager) { - this.amrMessageManager = new AmrMessageManager() - } - this.amrMessageManager.viewport = viewport - } - - // 从后台读取所有车 - async loadExecutors() { - const res = await Request.request.post('/api/workbench/EnvController@getAllExecutor', { - projectUuid: worldModel.state.project_uuid, - catalogCode: worldModel.state.catalogCode, - envId: worldModel.state.runState.currentEnvId - }) - for (const row of res.data) { - const executor_id = row.executor_id - const payload = JSON.parse(row.virtual_executor_payload) - // 车所在的标记位置,及方向 11_4:RIGHT - const [wayPointId, direction] = _.split(row.virtual_location_at, ':') - - const point = Model.find(wayPointId) - if (!point) { - console.error(`Waypoint with ID ${wayPointId} not found for executor ${executor_id}.`) - continue - } - - const item = _.cloneDeep(payload) - item.id = executor_id - item.tf[0] = _.cloneDeep(point.tf[0]) - switch (_.toLower(direction)) { - // right=0/left=180/up=90/down=-90 - case 'right': - item.tf[1][1] = 0 // 右侧 - break - case 'left': - item.tf[1][1] = 180 // 左侧 - break - case 'down': - item.tf[1][1] = -90 // 下方 - break - case 'up': - item.tf[1][1] = 90 // 上方 - break - } - Model.createExecutor(item) - } - } - - appendExecutor(id) { - const obj = this.viewport.entityManager.findObjectById(id) - const item = this.viewport.entityManager.findItemById(id) - if (item.t == 'cl2' && obj.userData.t === 'cl2') { - debugger - - const cl2 = obj as Cl23dObject - cl2.onMqttConnect(item, this.client) - // this.client.subscribe(['/wcs_server/' + cl2.id], { qos: 0 }) - // this.client.publish('/agv_robot/status', JSON.stringify(m20020), { retain: true }) - } - } - onMqttConnect = (packet: IConnackPacket) => { console.log('Connected') } @@ -86,7 +24,6 @@ export default class EnvManager { } else { } - } onMqttError = (error: Error | ErrorWithReasonCode) => { @@ -102,10 +39,6 @@ export default class EnvManager { system.showErrorDialog('WorldModel is not opened, cannot start EnvManager.') return } - if (!this.viewport) { - system.showErrorDialog('Viewport is not initialized, cannot start EnvManager.') - return - } if (!worldModel.state.runState.currentEnvId) { system.showErrorDialog('Current environment ID is not set, cannot start EnvManager.') return @@ -129,8 +62,8 @@ export default class EnvManager { worldModel.state.runState.isLoading = true worldModel.state.runState.currentEnv = Object.freeze(env) try { - await LCC.projectStart() - await this.loadExecutors() + await LCC.serverStart() + await LCC.loadExecutor() await LCC.loadInv() this.client = mqtt.connect(env.envConfig.mqtt.websocket, { @@ -144,7 +77,7 @@ export default class EnvManager { keepalive: 60 }) - this.viewport.lccMqttManager.start(env.envConfig.frontendMqtt) + await worldModel.lccMqttManager.start(env.envConfig.frontendMqtt) this.client.on('connect', this.onMqttConnect) this.client.on('message', this.onMqttMessage) this.client.on('error', this.onMqttError) @@ -159,8 +92,8 @@ export default class EnvManager { async stop() { system.showLoading() try { - if (LCC) { - await LCC.projectStop() + if (window['LCC']) { + await LCC.serverStop() } worldModel.state.runState.isRunning = false if (this.client) { @@ -214,7 +147,6 @@ export default class EnvManager { * 卸载资源 */ dispose(): void { - this.viewport = null this.stop() } } diff --git a/src/core/manager/LccMqttManager.ts b/src/core/manager/LccMqttManager.ts index a2a369a..91a9fdd 100644 --- a/src/core/manager/LccMqttManager.ts +++ b/src/core/manager/LccMqttManager.ts @@ -20,15 +20,12 @@ enum ConnectionStatus { ERROR = 'error' } -// 定义LCC MQTT管理器类 +/** + * 服务端将变化数据推送给客户端的管理器类 + */ export default class LccMqttManager { private client: mqtt.MqttClient | null = null private handlers: Map = new Map() - private viewport: Viewport - - init(viewport: Viewport): void { - this.viewport = viewport - } // 状态管理 public state = reactive({ diff --git a/src/core/manager/WorldModel.ts b/src/core/manager/WorldModel.ts index e2b857c..2a520ca 100644 --- a/src/core/manager/WorldModel.ts +++ b/src/core/manager/WorldModel.ts @@ -5,6 +5,10 @@ import EventBus from '@/runtime/EventBus' import StateManager from '@/core/manager/StateManager.ts' import { getQueryParams, setQueryParam } from '@/utils/webutils.ts' import localforage from 'localforage' +import LccMqttManager from '@/core/manager/LccMqttManager.ts' +import EnvManager from '@/core/manager/EnvManager.ts' +import RCSScript from '@/core/script/RCSScript.ts' +import LCCScript from '@/core/script/LCCScript.ts' export interface WorldModelState { isOpened: boolean // 是否已打开世界模型 @@ -36,6 +40,8 @@ export interface WorldModelState { */ export default class WorldModel { currentStateManager: StateManager + lccMqttManager = new LccMqttManager() + envManager = new EnvManager() /** * 世界模型双向绑定的状态数据 @@ -56,7 +62,7 @@ export default class WorldModel { isDraft: false, // 是否是草稿数据, 如果是草稿数据, 则不需要再从服务器加载数据 runState: { - currentEnvId: 0, + currentEnvId: null, isLoading: false, isRunning: false, isVirtual: false, @@ -220,4 +226,6 @@ export default class WorldModel { const worldModel = new WorldModel() window['worldModel'] = worldModel +window['RCS'] = new RCSScript() +window['LCC'] = new LCCScript() export { worldModel } diff --git a/src/core/manager/amr/AmrMessageManager.ts b/src/core/manager/amr/AmrMessageManager.ts index 04be1a8..8328bd6 100644 --- a/src/core/manager/amr/AmrMessageManager.ts +++ b/src/core/manager/amr/AmrMessageManager.ts @@ -1,61 +1,63 @@ -import {AmrMsg, AmrMsg10010, AmrMsg10050, AmrMsg10060, AmrMsg10110, AmrMsg10120, AmrMsg20050} from "@/core/manager/amr/AmrMessageDefine"; -import Cl23dObject from "@/modules/cl2/Cl23dObject"; -import Viewport from "@/core/engine/Viewport"; +import { AmrMsg, AmrMsg10010, AmrMsg10050, AmrMsg10060, AmrMsg10110, AmrMsg10120, AmrMsg20050 } from '@/core/manager/amr/AmrMessageDefine' +import Cl23dObject from '@/modules/cl2/Cl23dObject' +import Viewport from '@/core/engine/Viewport' export default class AmrMessageManager { - public viewport: Viewport + public get viewport(): Viewport { + return window['viewport'] + } handleMessage(topic, amrMsg: AmrMsg) { - const vehicleId = parseInt(topic.replace("/wcs_server/", "")) - const amrItem = this.viewport.entityManager.findObjectById(vehicleId + "") as Cl23dObject + const vehicleId = parseInt(topic.replace('/wcs_server/', '')) + const amrItem = this.viewport.entityManager.findObjectById(vehicleId + '') as Cl23dObject switch (amrMsg.id) { // AMR作业指令 10010 case 10010: amrItem.handle10010Message(amrMsg.content as AmrMsg10010) - break; + break // 停止/解除 10040 case 10040: - break; + break // 电文应答 10050 case 10050: amrItem.handle10050Message(amrMsg as AmrMsg) - break; + break // 配置信息 10060 case 10060: amrItem.handle10060Message(amrMsg as AmrMsg) - break; + break // 旋转货架 10080 case 10080: - break; + break // 旋转车身 10081 case 10081: - break; + break // 控制卷帘门 10082 case 10082: - break; + break // 心跳 10100 case 10100: - break; + break // 状态查询 10110 case 10110: amrItem.handle10110Message(amrMsg as AmrMsg) - break; + break // 取消已下发小车任务 10120 case 10120: amrItem.handle10120Message(amrMsg as AmrMsg) - break; + break // 设置小车坐标 10200 case 10200: - break; + break // 等待就绪 19997 case 19997: - break; + break } if (amrMsg.id != 10050 && amrMsg.id != 10100) { - const seqNo = amrMsg.content.SeqNo; - amrItem.sendAck(seqNo, vehicleId); + const seqNo = amrMsg.content.SeqNo + amrItem.sendAck(seqNo, vehicleId) } } } diff --git a/src/core/script/LCCScript.ts b/src/core/script/LCCScript.ts index 06de97d..5fb5ee1 100644 --- a/src/core/script/LCCScript.ts +++ b/src/core/script/LCCScript.ts @@ -6,43 +6,35 @@ import { Request } from '@ease-forge/shared' * LCC 物流控制中心客户端 API 实现 */ export default class LCCScript implements LCC { - private readonly viewport: Viewport - - constructor(viewport: Viewport) { - this.viewport = viewport - } - async getAllProjects(): Promise> { - return Request.request.post('/api/workbench/LccController@getAllProjects', { - }) + return Request.request.post('/api/workbench/LccController@getAllProjects', {}) } - async projectStart(): Promise> { + async serverStart(): Promise> { if (!worldModel.state.project_uuid || !worldModel.state.runState.currentEnvId) { return Promise.reject(new Error('Project UUID or Environment ID is not set.')) } - return Request.request.post('/api/workbench/LccController@projectStart', { + return Request.request.post('/api/workbench/LccController@serverStart', { projectUUID: worldModel.state.project_uuid, envId: worldModel.state.runState.currentEnvId }) } - async projectStop(): Promise> { + async serverStop(): Promise> { if (!worldModel.state.project_uuid || !worldModel.state.runState.currentEnvId) { return Promise.reject(new Error('Project UUID or Environment ID is not set.')) } - return Request.request.post('/api/workbench/LccController@projectStop', { + return Request.request.post('/api/workbench/LccController@serverStop', { projectUUID: worldModel.state.project_uuid, envId: worldModel.state.runState.currentEnvId }) } - // 从后台读取所有库存 async loadInv(): Promise> { - const res = await Request.request.post('/api/workbench/LccController@getAllInv', { + const res = await Request.request.post('/api/workbench/LccController@loadInv', { projectUuid: worldModel.state.project_uuid, catalogCode: worldModel.state.catalogCode, envId: worldModel.state.runState.currentEnvId @@ -55,8 +47,57 @@ export default class LCCScript implements LCC { const lpn = row.lpn // : "LPN1" const rack = row.rack // : "rack1" const container_type = row.container_type // : "pallet" - Model.createInv(container_type, lpn, rack, bay, level, cell) + if (window['Model']) { + Model.createInv(container_type, lpn, rack, bay, level, cell) + } } return res.data } + + // 从后台读取所有车 + async loadExecutor(): Promise> { + const res = await Request.request.post('/api/workbench/LccController@loadExecutor', { + projectUuid: worldModel.state.project_uuid, + envId: worldModel.state.runState.currentEnvId + }) + + for (const row of res.data) { + const executor_id = row.executor_id + const payload = JSON.parse(row.virtual_executor_payload) + // 车所在的标记位置,及方向 11_4:RIGHT + const [wayPointId, direction] = _.split(row.virtual_location_at, ':') + + if (window['Model']) { + const point = Model.find(wayPointId) + if (!point) { + console.error(`Waypoint with ID ${wayPointId} not found for executor ${executor_id}.`) + continue + } + + const item = _.cloneDeep(payload) + item.id = executor_id + item.tf[0] = _.cloneDeep(point.tf[0]) + switch (_.toLower(direction)) { + // right=0/left=180/up=90/down=-90 + case 'right': + item.tf[1][1] = 0 // 右侧 + break + case 'left': + item.tf[1][1] = 180 // 左侧 + break + case 'down': + item.tf[1][1] = -90 // 下方 + break + case 'up': + item.tf[1][1] = 90 // 上方 + break + } + if (row.virtual_floor_code === worldModel.state.catalogCode) { + Model.createExecutor(item) + } + } + } + + return res.data + } } diff --git a/src/core/script/ModelManager.ts b/src/core/script/ModelManager.ts index 9a7c3c9..85a54f2 100644 --- a/src/core/script/ModelManager.ts +++ b/src/core/script/ModelManager.ts @@ -7,8 +7,6 @@ import TaskManager from '../manager/TaskManager.ts' import Cl2Entity from '@/modules/cl2/Cl2Entity.ts' import ClxEntity from '@/modules/clx/ClxEntity.ts' import { getRenderer } from '@/core/manager/ModuleManager.ts' -import RCSScript from '@/core/script/RCSScript.ts' -import LCCScript from '@/core/script/LCCScript.ts' export default class ModelManager implements IControls, Model { private viewport: Viewport @@ -67,9 +65,6 @@ export default class ModelManager implements IControls, Model { window['executestring'] = this.executestring.bind(this) window['logger'] = this.logger window['msg'] = this.msg - - window['RCS'] = new RCSScript(this.viewport) - window['LCC'] = new LCCScript(this.viewport) } find(entityId: string): ItemJson { diff --git a/src/core/script/RCSScript.ts b/src/core/script/RCSScript.ts index 60bd97e..baaf374 100644 --- a/src/core/script/RCSScript.ts +++ b/src/core/script/RCSScript.ts @@ -3,12 +3,6 @@ import { Request } from '@ease-forge/shared' import { worldModel } from '@/core/manager/WorldModel.ts' export default class RCSScript implements RCS { - private readonly viewport: Viewport - - constructor(viewport: Viewport) { - this.viewport = viewport - } - agvMove(agvId: string, targetWayPointId: string, targetDirection: '' | LLCDirection = '', option: AgvOptions = {}): Promise> { return Request.request.post('/api/workbench/RcsController@agvMove', { projectUUID: worldModel.state.project_uuid, diff --git a/src/editor/ModelMain.vue b/src/editor/ModelMain.vue index 5c10c22..4759006 100644 --- a/src/editor/ModelMain.vue +++ b/src/editor/ModelMain.vue @@ -13,7 +13,7 @@
-