From 6bbc9425c7a1d45e71b8f5d17b90b0edfe216e65 Mon Sep 17 00:00:00 2001 From: luoyifan Date: Sun, 22 Jun 2025 16:39:38 +0800 Subject: [PATCH 1/4] =?UTF-8?q?A*=20=E8=B7=AF=E5=BE=84=E8=A7=84=E5=88=92?= =?UTF-8?q?=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/RCS3任务拆解.md | 3 +-- doc/RCS数据库结构.md | 7 +++++-- src/example/example1.js | 40 ++++++++++++++++++++-------------------- 3 files changed, 26 insertions(+), 24 deletions(-) diff --git a/doc/RCS3任务拆解.md b/doc/RCS3任务拆解.md index bafa76c..a020f08 100644 --- a/doc/RCS3任务拆解.md +++ b/doc/RCS3任务拆解.md @@ -111,8 +111,7 @@ CL2 和 CLX 使用的是货叉朝向和方向正负系。比如: 凯乐士CL2使 { type: 'robotRotation', executorId: '机器人编号', - worldRotation: 90 - // 转动身体到世界角度 90 度 + worldRotation: 90 // 转动身体到世界角度 90 度, 世界角度为:上=0°,左=90°,右=270°,下=180° } ``` diff --git a/doc/RCS数据库结构.md b/doc/RCS数据库结构.md index 2c0c1fe..a67df05 100644 --- a/doc/RCS数据库结构.md +++ b/doc/RCS数据库结构.md @@ -3,6 +3,7 @@ drop table if exists rcs_task_biz; create table rcs_task_biz ( biz_task_id bigint not null, + env_id bigint not null comment '环境ID', biz_type varchar(10) not null comment '任务类型' default 'carry', lpn varchar(50) not null comment '托盘ID', priority integer not null comment '任务优先级', @@ -13,9 +14,9 @@ create table rcs_task_biz biz_task_error_info varchar(500) default 'N/A' comment '异常提示信息', biz_task_description varchar(500) default 'N/A' comment '任务描述', biz_task_status varchar(10) default 'pending' comment '任务状态', - create_at timestamp not null comment '创建时间', + create_at timestamp not null comment '创建时间', create_by varchar(50) not null comment '创建人', - update_at timestamp not null comment '更新时间', + update_at timestamp not null comment '更新时间', update_by varchar(50) not null comment '更新人', primary key (biz_task_id) ); @@ -25,6 +26,7 @@ create table rcs_task_plan ( plan_task_id bigint not null comment '规划ID', biz_task_id bigint not null comment '业务任务ID', + env_id bigint not null comment '环境ID', plan_type varchar(10) not null comment '规划类型' default 'carry', executor_id varchar(50) not null comment '执行器ID', seq integer not null comment '规划序号', @@ -46,6 +48,7 @@ create table rcs_task_device device_task_id bigint not null comment '设备任务ID', plan_task_id bigint not null comment '规划ID', biz_task_id bigint not null comment '业务任务ID', + env_id bigint not null comment '环境ID', device_type varchar(50) not null comment '设备类型', device_item_id varchar(50) not null comment '执行器ID', seq integer not null comment '执行序号', diff --git a/src/example/example1.js b/src/example/example1.js index 1f8d2a2..2c72cf1 100644 --- a/src/example/example1.js +++ b/src/example/example1.js @@ -155,6 +155,26 @@ export default { catalogCode: 'f2', t: 'floor', items: [ { + id: 'm1', t: 'measure', v: true, + tf: [[0, 0, 0], [90, 0, 0], [0.1, 0.1, 0.1]], + dt: { in: [], out: [], center: ['m2', 'm4'] } + }, + { + id: 'm2', t: 'measure', v: true, + tf: [[8.4, 0, 0], [90, 0, 0], [0.1, 0.1, 0.1]], + dt: { in: [], out: [], center: ['m1', 'm3'] } + }, + { + id: 'm3', t: 'measure', v: true, + tf: [[8.4, 0, 9], [90, 0, 0], [0.1, 0.1, 0.1]], + dt: { in: [], out: [], center: ['m2', 'm4'] } + }, + { + id: 'm4', t: 'measure', v: true, + tf: [[0, 0, 9], [90, 0, 0], [0.1, 0.1, 0.1]], + dt: { in: [], out: [], center: ['m3', 'm1'] } + }, + { id: 'rack1', t: 'rack', v: true, @@ -182,26 +202,6 @@ export default { } }, { - id: 'm1', t: 'measure', v: true, - tf: [[0, 0, 0], [90, 0, 0], [0.1, 0.1, 0.1]], - dt: { in: [], out: [], center: ['m2', 'm4'] } - }, - { - id: 'm2', t: 'measure', v: true, - tf: [[8.4, 0, 0], [90, 0, 0], [0.1, 0.1, 0.1]], - dt: { in: [], out: [], center: ['m1', 'm3'] } - }, - { - id: 'm3', t: 'measure', v: true, - tf: [[8.4, 0, 9], [90, 0, 0], [0.1, 0.1, 0.1]], - dt: { in: [], out: [], center: ['m2', 'm4'] } - }, - { - id: 'm4', t: 'measure', v: true, - tf: [[0, 0, 9], [90, 0, 0], [0.1, 0.1, 0.1]], - dt: { in: [], out: [], center: ['m3', 'm1'] } - }, - { id: '1', t: 'way', v: true, tf: [[2.7, 0, 2.13], [90, 0, 0], [0.25, 0.25, 0.1]], dt: { From 1e115b884e0bba45838dcbf5b87fa05634b632a6 Mon Sep 17 00:00:00 2001 From: luoyifan Date: Sun, 22 Jun 2025 18:19:22 +0800 Subject: [PATCH 2/4] =?UTF-8?q?LccEnvInfo=20=E7=8E=AF=E5=A2=83=E4=BF=A1?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/RCS数据库结构.md | 17 +++++++++++ src/core/manager/RunManager.ts | 67 ++++++++++++++++++++++++++++++++++++++++++ src/core/manager/WorldModel.ts | 18 +++++++++++- src/editor/ModelMain.vue | 37 +++++++++++++++++++++++ src/types/model.d.ts | 17 +++++++++++ 5 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 src/core/manager/RunManager.ts diff --git a/doc/RCS数据库结构.md b/doc/RCS数据库结构.md index a67df05..806cc37 100644 --- a/doc/RCS数据库结构.md +++ b/doc/RCS数据库结构.md @@ -68,4 +68,21 @@ create table rcs_task_device create index idx_rcs_task_device1 on rcs_task_device (biz_task_id); create index idx_rcs_task_device2 on rcs_task_device (plan_task_id); + +drop table if exists lcc_env_info; +create table lcc_env_info +( + env_id bigint not null comment '环境ID', + world_id varchar(50) not null comment '世界地图ID', + env_name varchar(50) not null comment '环境名称', + is_virtual boolean not null default false comment '是否虚拟环境', + env_payload varchar(3000) not null default 'N/A' comment '环境负载信息', + create_at timestamp not null comment '创建时间', + create_by varchar(50) not null comment '创建人', + update_at timestamp not null comment '更新时间', + update_by varchar(50) not null comment '更新人', + primary key (env_id) +); +create index idx_lcc_env_info_1 on lcc_env_info (world_id); + ``` diff --git a/src/core/manager/RunManager.ts b/src/core/manager/RunManager.ts new file mode 100644 index 0000000..72e167c --- /dev/null +++ b/src/core/manager/RunManager.ts @@ -0,0 +1,67 @@ +import { Request } from '@ease-forge/shared' + +/** + * 运行管理器 + */ +class RunManager { + + // 是否正在运行 + isRunning: boolean = false + + /** + * 获取所有运行环境 + */ + async getAllEnv(worldId: string): Promise> { + // system.invokeServer('') + if (!worldId) { + return Promise.resolve({ success: true, data: [], msg: '' }) + } + const res = await Request.request.post('/api/workbench/EnvController@getAllEnv', { + worldId: worldId + }) + for (const env of res.data) { + // payload 转换为 json 数据 + if (env.env_payload) { + try { + env.env_payload = JSON.parse(env.env_payload) + } catch (e) { + console.error('解析环境负载失败:', e) + env.env_payload = {} + } + } + } + + return res + } + + /** + * 创建运行环境 + * @param worldId 世界ID + * @param envName 运行环境名称 + * @param isVirtual 是否是虚拟环境 + */ + async createEnv(worldId: string, envName: string, isVirtual: boolean) { + throw new Error('Method not implemented.') + } + + /** + * 开始运行 + */ + async run(timeRate: number, envId: number) { + if (this.isRunning) { + await this.stop() + } + + // 启动 websocket 监听等等 + } + + /** + * 停止运行 + */ + async stop() { + // 停止 websocket 监听等等 + } +} + +const runManager = new RunManager() +export default runManager diff --git a/src/core/manager/WorldModel.ts b/src/core/manager/WorldModel.ts index 5dc4972..4f9a839 100644 --- a/src/core/manager/WorldModel.ts +++ b/src/core/manager/WorldModel.ts @@ -30,6 +30,14 @@ export interface WorldModelState { stateManagerId: string // 当前楼层的状态管理器id isDraft: boolean // 是否是草稿数据 + + runState: { + currentEnvId: number, + isLoading: boolean, + isRunning: boolean, + isVirtual: boolean, + timeRate: number, + } } /** @@ -53,7 +61,15 @@ export default class WorldModel { catalogCode: '', // 当前楼层的目录代码 stateManagerId: '', // 当前楼层的状态管理器id, 一般是 项目ID+目录项ID - isDraft: false // 是否是草稿数据, 如果是草稿数据, 则不需要再从服务器加载数据 + isDraft: false, // 是否是草稿数据, 如果是草稿数据, 则不需要再从服务器加载数据 + + runState: { + currentEnvId: 0, + isLoading: false, + isRunning: false, + isVirtual: false, + timeRate: 1, + } }) get gridOption(): IGridHelper { diff --git a/src/editor/ModelMain.vue b/src/editor/ModelMain.vue index c60df39..a1a0ae5 100644 --- a/src/editor/ModelMain.vue +++ b/src/editor/ModelMain.vue @@ -8,6 +8,35 @@ >{{ rootMenu.label }} +
+
+
+ + + +
+
+ + + + + +
+ 启动 + + 停止 + +
@@ -121,6 +150,7 @@ import Logo from '@/assets/images/logo.png' import './ModelMain.less' import EventBus from '@/runtime/EventBus.js' import { useRouter } from 'vue-router' +import runManager from '@/core/manager/RunManager.js' export default { components: { Model2DEditor, Model3DViewer, Split, SplitArea, CatalogDefine }, @@ -158,6 +188,7 @@ export default { } }) }) + this.reloadEnvList() EventBus.on('dataLoadComplete', (data) => { const { stateManager } = data if (stateManager) { @@ -174,6 +205,7 @@ export default { data() { return { Logo, + envList: [], isShowEditor: false, editorHash: 0, currentViewport: null, @@ -245,6 +277,11 @@ export default { methods: { renderIcon, getWidgetBySide, + reloadEnvList() { + runManager.getAllEnv(this.worldModel.state.project_uuid).then(res => { + this.envList = res.data + }) + }, toHome() { system.router.push({ name: 'home' }) }, diff --git a/src/types/model.d.ts b/src/types/model.d.ts index e32ce04..20df69d 100644 --- a/src/types/model.d.ts +++ b/src/types/model.d.ts @@ -460,3 +460,20 @@ interface Cl2If extends EntityIf, Carry, Walk, ForkArm, LiftingArm { */ interface ClxIf extends EntityIf, Carry, Walk, ForkArm, LiftingArm { } + +interface ServerResponse { + success: boolean, + msg: string, + data: T +} + +/** + * 环境信息 + */ +interface EnvInfo { + env_id: string + world_id: string + env_name: string + is_virtual: boolean + env_payload: any +} From c19f6d6fbc0ac3c84a78359d5b8d80aa145d11d8 Mon Sep 17 00:00:00 2001 From: luoyifan Date: Sun, 22 Jun 2025 19:50:20 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E5=BE=AA=E7=8E=AF?= =?UTF-8?q?=E4=BE=9D=E8=B5=96=E9=97=AE=E9=A2=98=E3=80=81=E4=B8=96=E7=95=8C?= =?UTF-8?q?=E6=A8=A1=E5=9E=8B=E5=88=9D=E5=A7=8B=E5=8C=96=E6=97=B6=E6=9C=BA?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/ModelUtils.ts | 3 +- src/core/base/BaseRenderer.ts | 2 + src/core/manager/CodeDropper.ts | 6 +- src/core/manager/ModuleManager.ts | 44 +- src/core/manager/WorldModel.ts | 41 +- src/editor/CatalogDefine.vue | 2 +- src/editor/Model2DEditor.vue | 1 + src/editor/ModelMain.vue | 33 +- src/editor/ModelMainInit.ts | 5 +- src/editor/menus/FileMenu.ts | 181 +++--- src/editor/widgets/modeltree/ModeltreeViewJs.js | 1 + src/main.ts | 2 +- src/modules/agv1/index.ts | 7 +- src/modules/carton/index.ts | 13 +- src/modules/charger/index.ts | 13 +- src/modules/cl2/index.ts | 13 +- src/modules/clx/index.ts | 14 +- src/modules/gstore/index.ts | 13 +- src/modules/measure/MeasureRenderer.ts | 3 + src/modules/measure/index.ts | 15 +- src/modules/pallet/index.ts | 13 +- src/modules/rack/RackRenderer.ts_back | 760 ------------------------ src/modules/rack/index.ts | 13 +- src/modules/shuttle_rack/index.ts | 13 +- src/modules/tote/index.ts | 7 +- src/modules/way/index.ts | 13 +- src/types/global.d.ts | 3 +- 27 files changed, 232 insertions(+), 1002 deletions(-) delete mode 100644 src/modules/rack/RackRenderer.ts_back diff --git a/src/core/ModelUtils.ts b/src/core/ModelUtils.ts index 10c28b8..3ce1871 100644 --- a/src/core/ModelUtils.ts +++ b/src/core/ModelUtils.ts @@ -1,7 +1,6 @@ import * as THREE from 'three' import type Viewport from '@/core/engine/Viewport' import { Vector2 } from 'three/src/math/Vector2' -import EventBus from '@/runtime/EventBus.ts' import Decimal from 'decimal.js' import type { LineLike, Object3DLike } from '@/types/ModelTypes.ts' import axios from 'axios' @@ -9,7 +8,7 @@ import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader' import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader' import { TDSLoader } from 'three/examples/jsm/loaders/TDSLoader' import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader' -import { LineSegments2 } from 'three/examples/jsm/lines/LineSegments2' +import { worldModel } from '@/core/manager/WorldModel.ts' import { LineMaterial } from 'three/examples/jsm/lines/LineMaterial' import { Line2 } from 'three/examples/jsm/lines/Line2' import { LineGeometry } from 'three/examples/jsm/lines/LineGeometry' diff --git a/src/core/base/BaseRenderer.ts b/src/core/base/BaseRenderer.ts index 6dc1650..e8e48d6 100644 --- a/src/core/base/BaseRenderer.ts +++ b/src/core/base/BaseRenderer.ts @@ -7,6 +7,8 @@ import type { LineLike, Object3DLike } from '@/types/ModelTypes.ts' import { MeshWrap } from '@/core/manager/InstanceMeshManager.ts' import { getRenderer } from '@/core/manager/ModuleManager.ts' +debugger + /** * 基本渲染器基类 * 定义了点 / 线如何渲染到 Three.js 场景中. diff --git a/src/core/manager/CodeDropper.ts b/src/core/manager/CodeDropper.ts index d05c009..191b029 100644 --- a/src/core/manager/CodeDropper.ts +++ b/src/core/manager/CodeDropper.ts @@ -42,7 +42,7 @@ export default class CodeDropper extends BaseInteraction { droppedItemCallback: (item: ItemJson, pos: THREE.Vector3, evt: MouseEvent) => boolean } -defineModule({ - name: 'CodeDropper', +const ITEM_NAME = 'CodeDropper' +defineModule(ITEM_NAME, () => ({ interaction: CodeDropper.INSTANCE -}) +})) diff --git a/src/core/manager/ModuleManager.ts b/src/core/manager/ModuleManager.ts index c7328de..92f1a6a 100644 --- a/src/core/manager/ModuleManager.ts +++ b/src/core/manager/ModuleManager.ts @@ -1,17 +1,20 @@ -import * as THREE from 'three' import BaseRenderer from '@/core/base/BaseRenderer' import BaseInteraction from '@/core/base/BaseInteraction' -import BaseEntity from '@/core/base/BaseItemEntity' -import type { PropertySetter } from "@/core/base/PropertyTypes.ts"; +import type { PropertySetter } from '@/core/base/PropertyTypes.ts' // Define the ModuleDefineOption interface export interface ModuleDefineOption { /** - * 物流单元类型名称 + * 渲染器 */ - name: string; renderer?: BaseRenderer; + /** + * 交互管理器 + */ interaction?: BaseInteraction; + /** + * 属性元数据 + */ setter?: PropertySetter; } @@ -22,12 +25,19 @@ window['modules'] = modules /** * 模块管理器 */ -export function defineModule(option: ModuleDefineOption): Promise { - if (modules.has(option.name)) { - throw new Error(`Module with name "${option.name}" is already defined.`) +export function defineModule(name: string, optionFn: () => ModuleDefineOption): Promise { + if (modules.has(name)) { + throw new Error(`Module with name "${name}" is already defined.`) } - modules.set(option.name, option) - return option.renderer?.init() + return new Promise((resolve) => { + if (typeof optionFn !== 'function') { + console.log(`Module "${name}" is not a function, using it directly.`) + debugger + } + const option = optionFn() + modules.set(name, option) + option.renderer?.init().then(resolve) + }) } /** @@ -62,17 +72,5 @@ export function getInteraction(name: string): T { export function getSetter(name: string) { const module = getModuleOption(name) - return module.setter; -} - -/** - * 根据物料类型名称, 获取实体类 - * 如果获取不了 直接抛异常 - */ -export function createEntity(name: string, itemjson: ItemJson, objects: THREE.Object3D[]): T { - const module = getModuleOption(name) - const v = new module.entity() as T - v.setItem(itemjson) - v.setObjects(objects) - return v + return module.setter } diff --git a/src/core/manager/WorldModel.ts b/src/core/manager/WorldModel.ts index 4f9a839..28f9944 100644 --- a/src/core/manager/WorldModel.ts +++ b/src/core/manager/WorldModel.ts @@ -1,18 +1,6 @@ import _, { cloneDeep } from 'lodash' import { reactive, watch } from 'vue' import EventBus from '@/runtime/EventBus' -import Measure from '@/modules/measure' -import Way from '@/modules/way' -import Gstore from '@/modules/gstore' -import Rack from '@/modules/rack' -import ShuttleRack from '@/modules/shuttle_rack' -import Pallet from '@/modules/pallet' -import Tote from '@/modules/tote' -// import Agv1 from '@/modules/agv1' -import Carton from '@/modules/carton' -import Cl2 from '@/modules/cl2' -import Clx from '@/modules/clx' -import Charger from '@/modules/charger' import StateManager from '@/core/manager/StateManager.ts' import { getQueryParams, setQueryParam } from '@/utils/webutils.ts' import localforage from 'localforage' @@ -68,7 +56,7 @@ export default class WorldModel { isLoading: false, isRunning: false, isVirtual: false, - timeRate: 1, + timeRate: 1 } }) @@ -101,18 +89,17 @@ export default class WorldModel { init() { // 观察 this.state.catalogCode 的变化, 如果变化就调用 catalogCodeChange 方法 return Promise.all([ - Measure, - Way, - Gstore, - Rack, - ShuttleRack, - Pallet, - Tote, - Carton, - Cl2, - Clx, - // Agv1, - Charger + import('../../modules/measure'), + import('../../modules/way'), + import('../../modules/gstore'), + import('../../modules/rack'), + import('../../modules/shuttle_rack'), + import('../../modules/pallet'), + import('../../modules/tote'), + import('../../modules/carton'), + import('../../modules/cl2'), + import('../../modules/clx'), + import('../../modules/charger') ]).then(() => { console.log('世界模型初始化完成') @@ -241,3 +228,7 @@ export default class WorldModel { }) } } + +const worldModel = new WorldModel() +debugger +export { worldModel } diff --git a/src/editor/CatalogDefine.vue b/src/editor/CatalogDefine.vue index ad15034..a0dc1e5 100644 --- a/src/editor/CatalogDefine.vue +++ b/src/editor/CatalogDefine.vue @@ -3,6 +3,7 @@ import { computed, createVNode, reactive, useTemplateRef } from "vue"; import { ElButton, ElSpace, ElTree } from "element-plus"; import YvSrcEditor from "@/components/YvSrcEditor.vue"; import DataForm from "@/components/data-form/DataForm.vue"; +import {worldModel} from '@/core/manager/WorldModel.ts' import lodash from "lodash"; defineOptions({ @@ -39,7 +40,6 @@ interface CatalogDefineData { // 内部数据 const data: CatalogDefineData = {}; const tree = useTemplateRef>("treeRef"); -const worldModel = computed(() => window['worldModel']); const catalog = computed>(() => { // state.forceUpdateForCatalog; return worldModel.value?.state?.catalog; diff --git a/src/editor/Model2DEditor.vue b/src/editor/Model2DEditor.vue index a2db3d8..85946bf 100644 --- a/src/editor/Model2DEditor.vue +++ b/src/editor/Model2DEditor.vue @@ -104,6 +104,7 @@ import { renderIcon, setQueryParam } from '@/utils/webutils' import { createVNode, defineComponent, markRaw } from 'vue' import Viewport from '@/core/engine/Viewport' import Constract from '@/core/Constract' +import { worldModel } from '@/core/manager/WorldModel.ts' import EventBus from '@/runtime/EventBus' import SceneHelp from '@/core/engine/SceneHelp' import BulkCopy from './BulkCopy.vue' diff --git a/src/editor/ModelMain.vue b/src/editor/ModelMain.vue index a1a0ae5..be15ba1 100644 --- a/src/editor/ModelMain.vue +++ b/src/editor/ModelMain.vue @@ -9,10 +9,10 @@
-
+
+ v-model="worldModelState.currentEnvId">