@jnrs/lingshu-smart 2.2.24 → 2.2.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +689 -0
- package/README.md +1 -1
- package/dist/components/index.js +388 -384
- package/dist/components/preview/index.vue.d.ts +10 -1
- package/dist/controller/AppController.d.ts +5 -0
- package/dist/{index-2zNqeRBi.js → index-tpebqVjC.js} +6980 -6231
- package/dist/index.js +1 -1
- package/dist/json/cases.json +553 -449
- package/dist/playground/ViewPageDemo.vue.d.ts +8 -2
- package/dist/playground/mockWebSocketData.d.ts +0 -4
- package/dist/types/app.types.d.ts +2 -0
- package/dist/types/components/config.types.d.ts +1 -0
- package/dist/types/enums.d.ts +0 -5
- package/dist/types/models/config.types.d.ts +14 -1
- package/dist/types/models/operating.types.d.ts +12 -1
- package/dist/ui/abstract/ModelAbs.d.ts +2 -0
- package/dist/ui/components/Entrance.d.ts +4 -12
- package/dist/ui/models/DoubleJointRobot.d.ts +6 -3
- package/dist/ui/models/Rgv.d.ts +32 -0
- package/dist/ui/models/SingleJointRobot.d.ts +4 -1
- package/dist/ui/utils/attr.d.ts +5 -0
- package/package.json +2 -2
- package/AGENTIC.md +0 -1043
package/AGENTS.md
ADDED
|
@@ -0,0 +1,689 @@
|
|
|
1
|
+
# @jnrs/lingshu-smart API 文档
|
|
2
|
+
|
|
3
|
+
## ✨ 介绍
|
|
4
|
+
|
|
5
|
+
巨能前端 2D 数字孪生系统,即「灵枢智造」。提供 2D 数字孪生编辑器和运行看板功能,基于 LeaferJS 引擎构建。
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 🚀 Vue 模块使用说明(Playground 示例)
|
|
10
|
+
|
|
11
|
+
工程内 `src/playground/` 提供了两个最小集成示例,分别对应**编辑模式**与**预览/运行模式**。业务侧接入时,可直接参考这两个文件的结构。
|
|
12
|
+
|
|
13
|
+
| 文件 | 组件 | 场景 |
|
|
14
|
+
| ------------------ | --------------------- | --------------------------------- |
|
|
15
|
+
| `EditPageDemo.vue` | `LingshuSmartEditor` | 方案可视化编辑 |
|
|
16
|
+
| `ViewPageDemo.vue` | `LingshuSmartPreview` | 方案运行看板 + WebSocket 实时驱动 |
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
### EditPageDemo.vue — 编辑器模式
|
|
21
|
+
|
|
22
|
+
**职责:** 加载方案列表、保存方案、跳转预览、退出编辑页。编辑器内部自行管理画布与图层,业务层只需实现 `actions` 回调。
|
|
23
|
+
|
|
24
|
+
**核心结构:**
|
|
25
|
+
|
|
26
|
+
```vue
|
|
27
|
+
<script setup lang="ts">
|
|
28
|
+
import type { ICase } from '@/types'
|
|
29
|
+
import LingshuSmartEditor from '@/components/editor/index.vue'
|
|
30
|
+
|
|
31
|
+
const loadCases = async (requestId?: string): Promise<ICase[]> => {
|
|
32
|
+
const res = await fetch(`/json/cases.json?requestId=${requestId}`)
|
|
33
|
+
const data = await res.json()
|
|
34
|
+
return data.data
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const saveCases = (data?: ICase[]) => {
|
|
38
|
+
/* 持久化到后端 */
|
|
39
|
+
}
|
|
40
|
+
const handlePreview = (currentCase?: ICase) => {
|
|
41
|
+
window.open(`/preview/${currentCase?.uuid}`)
|
|
42
|
+
}
|
|
43
|
+
const handleExit = () => {
|
|
44
|
+
/* 退出逻辑 */
|
|
45
|
+
}
|
|
46
|
+
</script>
|
|
47
|
+
|
|
48
|
+
<template>
|
|
49
|
+
<LingshuSmartEditor :actions="{ loadCases, saveCases, handlePreview, handleExit }" />
|
|
50
|
+
</template>
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**EditorActions 回调说明:**
|
|
54
|
+
|
|
55
|
+
| 回调 | 类型 | 触发时机 | 说明 |
|
|
56
|
+
| --------------- | ----------------------------------- | --------------------------- | --------------------------------------------------- |
|
|
57
|
+
| `loadCases` | `(id?: string) => Promise<ICase[]>` | 编辑器初始化 / 方案管理弹窗 | **必填**。返回方案列表,组件内部写入 `useDataStore` |
|
|
58
|
+
| `saveCases` | `(cases?: ICase[]) => void` | 点击保存按钮 | 将当前全部方案提交后端 |
|
|
59
|
+
| `handlePreview` | `(currentCase?: ICase) => void` | 点击预览按钮 | 通常跳转至预览页并携带 `uuid` |
|
|
60
|
+
| `handleExit` | `() => void` | 点击退出按钮 | 返回上一页或关闭窗口 |
|
|
61
|
+
|
|
62
|
+
**注意:** 编辑模式不涉及 `onMessage` / `operating`。设备运转动画仅在预览看板中通过 WebSocket 驱动。
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
### ViewPageDemo.vue — 预览/运行模式
|
|
67
|
+
|
|
68
|
+
**职责:** 加载并展示指定方案、响应用户交互、接收 WebSocket 消息并驱动设备动画。
|
|
69
|
+
|
|
70
|
+
**核心结构:**
|
|
71
|
+
|
|
72
|
+
```vue
|
|
73
|
+
<script setup lang="ts">
|
|
74
|
+
import { ref, computed, onMounted } from 'vue'
|
|
75
|
+
import type { ICase, ILayer, ILayerOperating, InteractiveUi } from '@/types'
|
|
76
|
+
import { EnumModel } from '@/types'
|
|
77
|
+
import { transRuntimeToPixel } from '@/utils'
|
|
78
|
+
import LingshuSmartPreview from '@/components/preview/index.vue'
|
|
79
|
+
|
|
80
|
+
const lingshuSmartPreviewRef = ref()
|
|
81
|
+
const currentCaseId = ref('')
|
|
82
|
+
|
|
83
|
+
const currentCase = computed(() => lingshuSmartPreviewRef.value?.currentCase)
|
|
84
|
+
|
|
85
|
+
const loadCases = async (requestId?: string): Promise<ICase[]> => {
|
|
86
|
+
/* 同编辑器 */
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// 交互事件(可选)
|
|
90
|
+
const onTap = (layer: ILayer, data: InteractiveUi) => {
|
|
91
|
+
/* 左键点击 */
|
|
92
|
+
}
|
|
93
|
+
const onMenuTap = (layer: ILayer, data: InteractiveUi) => {
|
|
94
|
+
/* 右键点击 */
|
|
95
|
+
}
|
|
96
|
+
const onDragEnd = (layer: ILayer, data: InteractiveUi) => {
|
|
97
|
+
/* 拖拽结束 */
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// 驱动设备运转 — 转发至预览组件 expose 的方法
|
|
101
|
+
const operating = (data: ILayerOperating) => {
|
|
102
|
+
lingshuSmartPreviewRef.value?.operating(data)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// WebSocket 消息入口 — 见下文「onMessage 编写指南」
|
|
106
|
+
const onMessage = (rawMessage: any) => {
|
|
107
|
+
/* ... */
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
onMounted(() => {
|
|
111
|
+
// 从 URL 解析方案 UUID,例如 /preview/abc-123
|
|
112
|
+
const VIEW_PATH = '/preview/'
|
|
113
|
+
if (location.pathname.includes(VIEW_PATH)) {
|
|
114
|
+
currentCaseId.value = location.pathname.split(VIEW_PATH)[1]
|
|
115
|
+
}
|
|
116
|
+
})
|
|
117
|
+
</script>
|
|
118
|
+
|
|
119
|
+
<template>
|
|
120
|
+
<LingshuSmartPreview
|
|
121
|
+
ref="lingshuSmartPreviewRef"
|
|
122
|
+
:case-uuid="currentCaseId"
|
|
123
|
+
:actions="{ loadCases, onTap, onMenuTap, onDragEnd }"
|
|
124
|
+
/>
|
|
125
|
+
</template>
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
**PreviewActions 回调说明:**
|
|
129
|
+
|
|
130
|
+
| 回调 | 类型 | 触发时机 | 说明 |
|
|
131
|
+
| ----------- | ----------------------------------- | ---------------------- | --------------------------------------- |
|
|
132
|
+
| `loadCases` | `(id?: string) => Promise<ICase[]>` | 方案列表为空时自动调用 | **必填**。与编辑器共用同一数据源 |
|
|
133
|
+
| `onTap` | `(layer, data) => void` | 左键点击设备/子组件 | `layer` 为父图层,`data` 为实际点击目标 |
|
|
134
|
+
| `onMenuTap` | `(layer, data) => void` | 右键点击 | 可用于弹出上下文菜单 |
|
|
135
|
+
| `onDragEnd` | `(layer, data) => void` | 拖拽结束 | 预览模式下部分设备支持拖拽 |
|
|
136
|
+
|
|
137
|
+
**Preview 组件 expose:**
|
|
138
|
+
|
|
139
|
+
| 属性/方法 | 类型 | 说明 |
|
|
140
|
+
| ------------- | --------------------------------- | -------------------- |
|
|
141
|
+
| `currentCase` | `ICase \| null` | 当前加载的方案 |
|
|
142
|
+
| `operating` | `(data: ILayerOperating) => void` | 驱动指定设备运转动画 |
|
|
143
|
+
|
|
144
|
+
**Props:**
|
|
145
|
+
|
|
146
|
+
| 属性 | 类型 | 默认值 | 说明 |
|
|
147
|
+
| --------------- | ---------------- | --------- | --------------------------- |
|
|
148
|
+
| `caseUuid` | `string` | — | **必填**。要展示的方案 UUID |
|
|
149
|
+
| `actions` | `PreviewActions` | `{}` | 事件与数据加载回调 |
|
|
150
|
+
| `appHittable` | `boolean` | `true` | 画布是否可交互 |
|
|
151
|
+
| `appFill` | `string` | `#424242` | 容器背景色 |
|
|
152
|
+
| `hideSceneFill` | `boolean` | `false` | 是否隐藏场景背景 |
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## 📡 onMessage 编写指南
|
|
157
|
+
|
|
158
|
+
预览看板通过 WebSocket(或 SSE、轮询等)接收后端推送,在 `onMessage` 中将原始消息**转换为 `ILayerOperating`**,再调用 `operating()` 驱动画布。
|
|
159
|
+
|
|
160
|
+
### 数据流
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
WebSocket 原始消息
|
|
164
|
+
→ onMessage 校验 & 解析
|
|
165
|
+
→ 按 payload.type 分支映射
|
|
166
|
+
→ operating(ILayerOperating)
|
|
167
|
+
→ AppController.businessMap 匹配 `${className}_${id}`
|
|
168
|
+
→ 对应 ModelAbs.handleOperation → 子组件动画
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### 消息格式约定
|
|
172
|
+
|
|
173
|
+
参考 `src/playground/mockWebSocketData.ts`,推荐外层结构:
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
interface WebSocketMessage {
|
|
177
|
+
traceId: string // 链路追踪 ID
|
|
178
|
+
type: 'update' // 消息类型,目前仅处理 'update'
|
|
179
|
+
payload: Payload // 业务载荷,内含 payload.type 标识设备/资源
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
**入口校验模板:**
|
|
184
|
+
|
|
185
|
+
```typescript
|
|
186
|
+
const onMessage = (rawMessage: any) => {
|
|
187
|
+
if (!rawMessage?.type || !rawMessage?.payload) {
|
|
188
|
+
console.warn('无效的 WebSocket 消息格式', rawMessage)
|
|
189
|
+
return
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const { type, payload } = rawMessage
|
|
193
|
+
|
|
194
|
+
if (type === 'update') {
|
|
195
|
+
switch (payload.type) {
|
|
196
|
+
case 'Resource':
|
|
197
|
+
/* 资源增删 */ break
|
|
198
|
+
case 'MachineTool':
|
|
199
|
+
/* 机床状态 */ break
|
|
200
|
+
case 'ResourceStore':
|
|
201
|
+
/* 资源库/随行托 */ break
|
|
202
|
+
case 'SingleJointRobot':
|
|
203
|
+
/* 单关节机器人 */ break
|
|
204
|
+
case 'DoubleJointRobot':
|
|
205
|
+
/* 双关节机器人 */ break
|
|
206
|
+
case 'Rgv':
|
|
207
|
+
/* RGV */ break
|
|
208
|
+
case 'LoadingStation':
|
|
209
|
+
/* 装载站 */ break
|
|
210
|
+
case 'MarkingMachine':
|
|
211
|
+
/* 打标机 */ break
|
|
212
|
+
case 'CleaningMachine':
|
|
213
|
+
/* 清洗机 */ break
|
|
214
|
+
case 'Rail':
|
|
215
|
+
/* 轨道拖链 */ break
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### 匹配规则(重要)
|
|
222
|
+
|
|
223
|
+
`operating()` 通过 `className + id` 定位画布上的设备:
|
|
224
|
+
|
|
225
|
+
- `id` 作为前后端对于设备的唯一识别字段
|
|
226
|
+
- `rawData` 为后端接口返回的原始数据 payload,其中包含 id 属性,如果设备注册了交互事件,则该对象会存在于回调函数的返回值中,供“点击设备后弹窗展示设备详情”等业务需求使用
|
|
227
|
+
- `className` 使用 `EnumModel` 枚举值,例如 `EnumModel.MACHINE_TOOL`
|
|
228
|
+
- 资源增删时,`addType` / `removeType` 为目标设备的 `className`,`addId` / `removeId` 为目标设备 `id`
|
|
229
|
+
|
|
230
|
+
匹配失败时控制台输出:`模型操作失败: 模型未匹配到`。
|
|
231
|
+
|
|
232
|
+
### 各业务场景映射示例
|
|
233
|
+
|
|
234
|
+
#### 1. 资源增删(`payload.type === 'Resource'`)
|
|
235
|
+
|
|
236
|
+
Resource 不在编辑器中进行维护,是根据业务数据动态添加或删除的一类 UI 图形,如“托盘”、“刀具”。
|
|
237
|
+
同一消息可同时包含新增与移除操作。
|
|
238
|
+
|
|
239
|
+
```typescript
|
|
240
|
+
// 新增资源到设备工位
|
|
241
|
+
if (payload.addType && payload.addId) {
|
|
242
|
+
operating({
|
|
243
|
+
className: payload.addType, // 如 EnumModel.MACHINE_TOOL
|
|
244
|
+
id: payload.addId,
|
|
245
|
+
rawData: payload,
|
|
246
|
+
resource: {
|
|
247
|
+
handleType: 'add',
|
|
248
|
+
resourceType: payload.resourceType, // EnumResourceType.PALLET | TOOL
|
|
249
|
+
name: payload.name,
|
|
250
|
+
color: payload.status === 3 ? 'green' : '#424242',
|
|
251
|
+
index: payload.addSiteNumber, // 工位槽索引
|
|
252
|
+
rawData: payload
|
|
253
|
+
}
|
|
254
|
+
})
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// 从设备工位移除资源
|
|
258
|
+
if (payload.removeType && payload.removeId) {
|
|
259
|
+
operating({
|
|
260
|
+
className: payload.removeType,
|
|
261
|
+
id: payload.removeId,
|
|
262
|
+
rawData: payload,
|
|
263
|
+
resource: {
|
|
264
|
+
handleType: 'remove',
|
|
265
|
+
resourceType: payload.resourceType,
|
|
266
|
+
index: payload.removeSiteNumber,
|
|
267
|
+
rawData: payload
|
|
268
|
+
}
|
|
269
|
+
})
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
#### 2. 机床(`payload.type === 'MachineTool'`)
|
|
274
|
+
|
|
275
|
+
```typescript
|
|
276
|
+
operating({
|
|
277
|
+
className: EnumModel.MACHINE_TOOL,
|
|
278
|
+
id: payload.id,
|
|
279
|
+
rawData: payload,
|
|
280
|
+
light: {
|
|
281
|
+
color: payload.status === 2 ? 'green' : '#424242',
|
|
282
|
+
blinking: payload.status !== 2,
|
|
283
|
+
rotating: payload.status === 2
|
|
284
|
+
},
|
|
285
|
+
progress: {
|
|
286
|
+
percent: payload.percent, // 0 ~ 1
|
|
287
|
+
textContent: payload.status === 2 ? '运行中' : '待机中'
|
|
288
|
+
},
|
|
289
|
+
entrance: {
|
|
290
|
+
isIn: payload.isIn,
|
|
291
|
+
isOut: payload.isOut
|
|
292
|
+
},
|
|
293
|
+
stationRotatable: payload.stationRotatable // false 横向 / true 纵向
|
|
294
|
+
})
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
#### 3. 资源库 / 随行托(`payload.type === 'ResourceStore'`)
|
|
298
|
+
|
|
299
|
+
```typescript
|
|
300
|
+
operating({
|
|
301
|
+
className: EnumModel.RESOURCE_STORE,
|
|
302
|
+
id: payload.id,
|
|
303
|
+
rawData: payload,
|
|
304
|
+
light: {
|
|
305
|
+
color: payload.status === 2 ? 'green' : '#424242',
|
|
306
|
+
blinking: payload.status === 2
|
|
307
|
+
},
|
|
308
|
+
x: transRuntimeToPixel(payload.x, 1, 'width') // 沿轨道移动时需转换
|
|
309
|
+
})
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
#### 4. 单关节机器人(`payload.type === 'SingleJointRobot'`)
|
|
313
|
+
|
|
314
|
+
```typescript
|
|
315
|
+
operating({
|
|
316
|
+
className: EnumModel.SINGLE_JOINT_ROBOT,
|
|
317
|
+
id: payload.id,
|
|
318
|
+
rawData: payload,
|
|
319
|
+
light: {
|
|
320
|
+
color: payload.status === 2 ? 'green' : '#424242',
|
|
321
|
+
blinking: payload.status === 2
|
|
322
|
+
},
|
|
323
|
+
x: transRuntimeToPixel(payload.x, 1, 'width'),
|
|
324
|
+
j1: payload.j1, // 一级关节角度(度)
|
|
325
|
+
currentFixture: payload.currentFixture // EnumResourceType.PALLET | TOOL
|
|
326
|
+
})
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
#### 5. 双关节机器人(`payload.type === 'DoubleJointRobot'`)
|
|
330
|
+
|
|
331
|
+
```typescript
|
|
332
|
+
operating({
|
|
333
|
+
className: EnumModel.DOUBLE_JOINT_ROBOT,
|
|
334
|
+
id: payload.id,
|
|
335
|
+
rawData: payload,
|
|
336
|
+
light: {
|
|
337
|
+
color: payload.status === 0 ? '#f30' : '#424242'
|
|
338
|
+
},
|
|
339
|
+
currentFixture: payload.currentFixture,
|
|
340
|
+
x: transRuntimeToPixel(payload.x, 1, 'width'),
|
|
341
|
+
j1: payload.j1,
|
|
342
|
+
j2: payload.j2
|
|
343
|
+
})
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
#### 6. 装载站(`payload.type === 'LoadingStation'`)
|
|
347
|
+
|
|
348
|
+
```typescript
|
|
349
|
+
operating({
|
|
350
|
+
className: EnumModel.LOADING_STATION,
|
|
351
|
+
id: payload.id,
|
|
352
|
+
rawData: payload,
|
|
353
|
+
light: { color: payload.status === 2 ? 'green' : '#424242', blinking: payload.status === 2 },
|
|
354
|
+
progress: { percent: payload.percent, textContent: payload.textContent },
|
|
355
|
+
entrance: { isIn: payload.isIn, isOut: payload.isOut },
|
|
356
|
+
stationRotatable: payload.stationRotatable
|
|
357
|
+
})
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
#### 7. 打标机(`payload.type === 'MarkingMachine'`)
|
|
361
|
+
|
|
362
|
+
```typescript
|
|
363
|
+
operating({
|
|
364
|
+
className: EnumModel.MARKING_MACHINE,
|
|
365
|
+
id: payload.id,
|
|
366
|
+
rawData: payload,
|
|
367
|
+
light: { color: payload.lightColor, blinking: payload.blinking },
|
|
368
|
+
progress: { percent: payload.percent, textContent: payload.textContent },
|
|
369
|
+
entrance: { isIn: payload.isIn, isOut: payload.isOut },
|
|
370
|
+
laserSiteNumberArray: payload.laserSiteNumberArray // { site, active }[]
|
|
371
|
+
})
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
#### 8. 清洗机(`payload.type === 'CleaningMachine'`)
|
|
375
|
+
|
|
376
|
+
```typescript
|
|
377
|
+
operating({
|
|
378
|
+
className: EnumModel.CLEANING_MACHINE,
|
|
379
|
+
id: payload.id,
|
|
380
|
+
rawData: payload,
|
|
381
|
+
light: { color: payload.lightColor, blinking: payload.blinking },
|
|
382
|
+
progress: { percent: payload.percent, textContent: payload.textContent },
|
|
383
|
+
entrance: { isIn: payload.isIn, isOut: payload.isOut }
|
|
384
|
+
})
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
#### 9. RGV(`payload.type === 'Rgv'`)
|
|
388
|
+
|
|
389
|
+
```typescript
|
|
390
|
+
operating({
|
|
391
|
+
className: EnumModel.RGV,
|
|
392
|
+
id: payload.id,
|
|
393
|
+
rawData: payload,
|
|
394
|
+
light: { color: payload.lightColor, blinking: payload.blinking },
|
|
395
|
+
x: transRuntimeToPixel(payload.x, 1, 'width'),
|
|
396
|
+
j1: payload.j1, // 旋转角度
|
|
397
|
+
forkXY: payload.forkXY, // 货叉横向移动比例 0~1
|
|
398
|
+
forkZ: payload.forkZ // 货叉升降比例 0~1
|
|
399
|
+
})
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
#### 10. 轨道拖链(`payload.type === 'Rail'`)
|
|
403
|
+
|
|
404
|
+
```typescript
|
|
405
|
+
operating({
|
|
406
|
+
className: EnumModel.RAIL,
|
|
407
|
+
id: payload.id, // 轨道图层 id
|
|
408
|
+
rawData: payload,
|
|
409
|
+
x: payload.x, // 拖链位置(像素,无需 runtime 转换)
|
|
410
|
+
botId: payload.botId // 关联的移动设备 rawData.id
|
|
411
|
+
})
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
### 运行时坐标转换
|
|
415
|
+
|
|
416
|
+
后端推送的 `x` / `y` 通常为**物理/runtime 坐标**(如毫米),画布使用**像素坐标**。转换公式:
|
|
417
|
+
|
|
418
|
+
```typescript
|
|
419
|
+
import { transRuntimeToPixel } from '@jnrs/lingshu-smart'
|
|
420
|
+
|
|
421
|
+
// 宽方向:pixel = runtimeVal * (scene.width / scene.runtime_width)
|
|
422
|
+
const pixelX = transRuntimeToPixel(payload.x, 1, 'width')
|
|
423
|
+
const pixelY = transRuntimeToPixel(payload.y, 1, 'height')
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
**前提:** 方案 `IScene` 中需配置 `runtime_width` / `runtime_height`。该函数读取 `useEditorStore().scene`,预览页需确保场景数据已加载。
|
|
427
|
+
|
|
428
|
+
### WebSocket 接入示例
|
|
429
|
+
|
|
430
|
+
```typescript
|
|
431
|
+
onMounted(() => {
|
|
432
|
+
const ws = new WebSocket('wss://your-server/ws')
|
|
433
|
+
ws.onmessage = (event) => {
|
|
434
|
+
try {
|
|
435
|
+
onMessage(JSON.parse(event.data))
|
|
436
|
+
} catch (e) {
|
|
437
|
+
console.error('WebSocket 消息解析失败', e)
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
})
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
本地调试可复用 `mockWebSocketData.ts` 中的 `firstBatchMessages` / `secondBatchMessages`。
|
|
444
|
+
|
|
445
|
+
---
|
|
446
|
+
|
|
447
|
+
## 📊 ILayerOperating 类型参考
|
|
448
|
+
|
|
449
|
+
`ILayerOperating` 是设备层运转状态的**联合类型**,用于 `operating()` 入参。所有子类型均继承基类 `IModelOperating`,并通过 `className` 字段区分具体设备。
|
|
450
|
+
|
|
451
|
+
### 基类 IModelOperating
|
|
452
|
+
|
|
453
|
+
| 属性 | 类型 | 必填 | 说明 |
|
|
454
|
+
| ----------- | -------------------- | ---- | ----------------------------------- |
|
|
455
|
+
| `id` | `string` | ✓ | 业务设备 ID,对应图层 `rawData.id` |
|
|
456
|
+
| `className` | `EnumModel` | ✓ | 设备类型枚举,用于 businessMap 匹配 |
|
|
457
|
+
| `rawData` | `IRowData` | ✓ | 原始业务数据,建议传入完整 payload |
|
|
458
|
+
| `resource` | `IResourceOperating` | — | 工位槽资源增删(多设备共用) |
|
|
459
|
+
|
|
460
|
+
### 联合类型 ILayerOperating
|
|
461
|
+
|
|
462
|
+
```typescript
|
|
463
|
+
type ILayerOperating =
|
|
464
|
+
| IMachineToolOperating
|
|
465
|
+
| ILoadingStationOperating
|
|
466
|
+
| IMarkingMachineOperating
|
|
467
|
+
| ICleaningMachineOperating
|
|
468
|
+
| ISingleJointRobotOperating
|
|
469
|
+
| IDoubleJointRobotOperating
|
|
470
|
+
| IRGVOperating
|
|
471
|
+
| IRailOperating
|
|
472
|
+
| IResourceStoreOperating
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
### 子类型一览
|
|
476
|
+
|
|
477
|
+
| 类型 | className | 特有属性 | 子组件能力 | 典型 payload.type |
|
|
478
|
+
| ---------------------------- | -------------------- | ------------------------------------------------------------------ | -------------------------------------------------- | ------------------ |
|
|
479
|
+
| `IMachineToolOperating` | `MACHINE_TOOL` | `light?`, `progress?`, `entrance?`, `stationRotatable?` | 状态灯(含旋转)、进度条、出入口、工位槽 | `MachineTool` |
|
|
480
|
+
| `ILoadingStationOperating` | `LOADING_STATION` | `light?`, `progress?`, `entrance?`, `stationRotatable?` | 状态灯(无旋转)、进度条、出入口、工位槽 | `LoadingStation` |
|
|
481
|
+
| `IMarkingMachineOperating` | `MARKING_MACHINE` | `light?`, `progress?`, `entrance?`, `laserSiteNumberArray?` | 状态灯、进度条、出入口、工位槽、激光工位指示 | `MarkingMachine` |
|
|
482
|
+
| `ICleaningMachineOperating` | `CLEANING_MACHINE` | `light?`, `progress?`, `entrance?` | 状态灯、进度条、出入口、工位槽 | `CleaningMachine` |
|
|
483
|
+
| `ISingleJointRobotOperating` | `SINGLE_JOINT_ROBOT` | `light?`, `x?`, `y?`, `j1?`, `currentFixture?`, `resource?` | 双状态灯、轨道位移、关节旋转、夹具切换、双工位槽 | `SingleJointRobot` |
|
|
484
|
+
| `IDoubleJointRobotOperating` | `DOUBLE_JOINT_ROBOT` | `light?`, `x?`, `y?`, `j1?`, `j2?`, `currentFixture?`, `resource?` | 双状态灯、轨道位移、双关节旋转、夹具切换、双工位槽 | `DoubleJointRobot` |
|
|
485
|
+
| `IRGVOperating` | `RGV` | `light?`, `x?`, `j1?`, `forkXY?`, `forkZ?`, `resource?` | 双状态灯、轨道位移、旋转、货叉 XY/Z、双工位槽 | `Rgv` |
|
|
486
|
+
| `IRailOperating` | `RAIL` | `x?`, `botId?` | 拖链动画(关联 botId 的设备移动时拖链跟随) | `Rail` |
|
|
487
|
+
| `IResourceStoreOperating` | `RESOURCE_STORE` | `light?`, `x?`, `resource?` | 状态灯、轨道位移、托盘/刀具工位槽 | `ResourceStore` |
|
|
488
|
+
|
|
489
|
+
### 子类型字段详情
|
|
490
|
+
|
|
491
|
+
#### IMachineToolOperating
|
|
492
|
+
|
|
493
|
+
| 属性 | 类型 | 说明 |
|
|
494
|
+
| ------------------ | -------------------- | --------------------------------------- |
|
|
495
|
+
| `light` | `ILightOperating` | 支持 `rotating`(运行中旋转灯效) |
|
|
496
|
+
| `progress` | `IProgressOperating` | 加工进度 0~1 |
|
|
497
|
+
| `entrance` | `IEntranceOperating` | 物料入口/出口动画 |
|
|
498
|
+
| `stationRotatable` | `boolean` | 工位容器方向:`false` 横向,`true` 纵向 |
|
|
499
|
+
| `resource` | `IResourceOperating` | 托盘等资源增删 |
|
|
500
|
+
|
|
501
|
+
#### ILoadingStationOperating
|
|
502
|
+
|
|
503
|
+
| 属性 | 类型 | 说明 |
|
|
504
|
+
| ------------------ | ----------------------------------- | -------------- |
|
|
505
|
+
| `light` | `Omit<ILightOperating, 'rotating'>` | 不支持旋转灯效 |
|
|
506
|
+
| `progress` | `IProgressOperating` | 装载进度 |
|
|
507
|
+
| `entrance` | `IEntranceOperating` | 出入口状态 |
|
|
508
|
+
| `stationRotatable` | `boolean` | 工位容器方向 |
|
|
509
|
+
| `resource` | `IResourceOperating` | 工位槽资源 |
|
|
510
|
+
|
|
511
|
+
#### IMarkingMachineOperating
|
|
512
|
+
|
|
513
|
+
| 属性 | 类型 | 说明 |
|
|
514
|
+
| ---------------------- | ----------------------------------- | ------------------ |
|
|
515
|
+
| `light` | `Omit<ILightOperating, 'rotating'>` | 状态灯 |
|
|
516
|
+
| `progress` | `IProgressOperating` | 打标进度 |
|
|
517
|
+
| `entrance` | `IEntranceOperating` | 出入口 |
|
|
518
|
+
| `laserSiteNumberArray` | `ILaserSiteState[]` | 各激光工位打标状态 |
|
|
519
|
+
| `resource` | `IResourceOperating` | 工位槽资源 |
|
|
520
|
+
|
|
521
|
+
**ILaserSiteState:**
|
|
522
|
+
|
|
523
|
+
| 属性 | 类型 | 说明 |
|
|
524
|
+
| -------- | --------- | ------------ |
|
|
525
|
+
| `site` | `number` | 工位序号 |
|
|
526
|
+
| `active` | `boolean` | 是否正在打标 |
|
|
527
|
+
|
|
528
|
+
#### ICleaningMachineOperating
|
|
529
|
+
|
|
530
|
+
| 属性 | 类型 | 说明 |
|
|
531
|
+
| ---------- | ----------------------------------- | ---------- |
|
|
532
|
+
| `light` | `Omit<ILightOperating, 'rotating'>` | 状态灯 |
|
|
533
|
+
| `progress` | `IProgressOperating` | 清洗进度 |
|
|
534
|
+
| `entrance` | `IEntranceOperating` | 出入口 |
|
|
535
|
+
| `resource` | `IResourceOperating` | 工位槽资源 |
|
|
536
|
+
|
|
537
|
+
#### ISingleJointRobotOperating
|
|
538
|
+
|
|
539
|
+
| 属性 | 类型 | 说明 |
|
|
540
|
+
| ---------------- | -------------------- | --------------------------- |
|
|
541
|
+
| `light` | `ILightOperating` | 双灯同步更新 |
|
|
542
|
+
| `x` | `number` | 沿轨道水平位移(像素) |
|
|
543
|
+
| `y` | `number` | 垂直位移(像素) |
|
|
544
|
+
| `j1` | `number` | 一级关节角度(度) |
|
|
545
|
+
| `currentFixture` | `EnumResourceType` | 当前夹具:`Pallet` / `Tool` |
|
|
546
|
+
| `resource` | `IResourceOperating` | 托盘/刀具工位槽 |
|
|
547
|
+
|
|
548
|
+
#### IDoubleJointRobotOperating
|
|
549
|
+
|
|
550
|
+
| 属性 | 类型 | 说明 |
|
|
551
|
+
| ---------------- | -------------------- | ---------------------- |
|
|
552
|
+
| `light` | `ILightOperating` | 双灯同步更新 |
|
|
553
|
+
| `x` | `number` | 沿轨道水平位移(像素) |
|
|
554
|
+
| `y` | `number` | 垂直位移(像素) |
|
|
555
|
+
| `j1` | `number` | 一级关节角度(度) |
|
|
556
|
+
| `j2` | `number` | 二级关节角度(度) |
|
|
557
|
+
| `currentFixture` | `EnumResourceType` | 当前夹具类型 |
|
|
558
|
+
| `resource` | `IResourceOperating` | 托盘/刀具工位槽 |
|
|
559
|
+
|
|
560
|
+
#### IRGVOperating
|
|
561
|
+
|
|
562
|
+
| 属性 | 类型 | 说明 |
|
|
563
|
+
| ---------- | -------------------- | -------------------- |
|
|
564
|
+
| `light` | `ILightOperating` | 双灯同步更新 |
|
|
565
|
+
| `x` | `number` | 沿轨道位移(像素) |
|
|
566
|
+
| `j1` | `number` | 车体旋转角度(度) |
|
|
567
|
+
| `forkXY` | `number` | 货叉横向移动比例 0~1 |
|
|
568
|
+
| `forkZ` | `number` | 货叉升降比例 0~1 |
|
|
569
|
+
| `resource` | `IResourceOperating` | 托盘/刀具工位槽 |
|
|
570
|
+
|
|
571
|
+
#### IRailOperating
|
|
572
|
+
|
|
573
|
+
| 属性 | 类型 | 说明 |
|
|
574
|
+
| ------- | -------- | --------------------------- |
|
|
575
|
+
| `x` | `number` | 拖链延伸位置(像素) |
|
|
576
|
+
| `botId` | `string` | 关联移动设备的 `rawData.id` |
|
|
577
|
+
|
|
578
|
+
#### IResourceStoreOperating
|
|
579
|
+
|
|
580
|
+
| 属性 | 类型 | 说明 |
|
|
581
|
+
| ---------- | -------------------- | ------------------------------ |
|
|
582
|
+
| `light` | `ILightOperating` | 状态灯 |
|
|
583
|
+
| `x` | `number` | 沿轨道位移(像素,随行托场景) |
|
|
584
|
+
| `resource` | `IResourceOperating` | 托盘/刀具工位槽增删 |
|
|
585
|
+
|
|
586
|
+
### 子组件运转类型(IComponentOperating)
|
|
587
|
+
|
|
588
|
+
被 `ILayerOperating` 各字段引用的子组件操作类型,定义于 `src/types/components/operating.types.ts`:
|
|
589
|
+
|
|
590
|
+
| 类型 | 用途 | 字段 |
|
|
591
|
+
| -------------------- | ---------- | ---------------------------------------------------------------------------------------- |
|
|
592
|
+
| `ILightOperating` | 状态灯 | `color`(必填), `blinking?`, `rotating?` |
|
|
593
|
+
| `IProgressOperating` | 进度条 | `percent`(0~1), `textContent` |
|
|
594
|
+
| `IEntranceOperating` | 出入口 | `isIn`, `isOut` |
|
|
595
|
+
| `IResourceOperating` | 工位槽资源 | `resourceType`, `index`, `handleType`(`'add'\|'remove'`), `rawData`, `name?`, `color?` |
|
|
596
|
+
|
|
597
|
+
---
|
|
598
|
+
|
|
599
|
+
## 📦 模块总览
|
|
600
|
+
|
|
601
|
+
| 模块路径 | 说明 |
|
|
602
|
+
| -------------------------------- | ------------------------------ |
|
|
603
|
+
| `@jnrs/lingshu-smart` | 主模块,包含类型定义和工具函数 |
|
|
604
|
+
| `@jnrs/lingshu-smart/components` | Vue 组件库(编辑器、预览器) |
|
|
605
|
+
| `@jnrs/lingshu-smart/locales` | 国际化配置 |
|
|
606
|
+
|
|
607
|
+
---
|
|
608
|
+
|
|
609
|
+
## 📋 API 详情
|
|
610
|
+
|
|
611
|
+
### @jnrs/lingshu-smart 主模块
|
|
612
|
+
|
|
613
|
+
#### 枚举 (Enums)
|
|
614
|
+
|
|
615
|
+
**EnumModel — 设备类型**
|
|
616
|
+
|
|
617
|
+
| 枚举值 | 说明 |
|
|
618
|
+
| -------------------- | ------------ |
|
|
619
|
+
| `SINGLE_JOINT_ROBOT` | 单关节机器人 |
|
|
620
|
+
| `DOUBLE_JOINT_ROBOT` | 双关节机器人 |
|
|
621
|
+
| `RGV` | RGV |
|
|
622
|
+
| `MACHINE_TOOL` | 机床 |
|
|
623
|
+
| `MARKING_MACHINE` | 打标机 |
|
|
624
|
+
| `CLEANING_MACHINE` | 清洗机 |
|
|
625
|
+
| `LOADING_STATION` | 装载站 |
|
|
626
|
+
| `RAIL` | 轨道 |
|
|
627
|
+
| `RESOURCE_STORE` | 资源库 |
|
|
628
|
+
|
|
629
|
+
**EnumResourceType — 资源类型**
|
|
630
|
+
|
|
631
|
+
| 枚举值 | 说明 |
|
|
632
|
+
| -------- | ---- |
|
|
633
|
+
| `PALLET` | 托盘 |
|
|
634
|
+
| `TOOL` | 刀具 |
|
|
635
|
+
|
|
636
|
+
#### 核心类型
|
|
637
|
+
|
|
638
|
+
**IScene — 场景配置**
|
|
639
|
+
|
|
640
|
+
| 属性 | 类型 | 必填 | 说明 |
|
|
641
|
+
| ---------------- | ----------------- | ---- | ------------------------------------ |
|
|
642
|
+
| `width` | `number` | ✓ | 场景宽度(像素) |
|
|
643
|
+
| `height` | `number` | ✓ | 场景高度(像素) |
|
|
644
|
+
| `runtime_width` | `number` | — | 运行时宽度(物理单位,用于坐标转换) |
|
|
645
|
+
| `runtime_height` | `number` | — | 运行时高度 |
|
|
646
|
+
| `zoomType` | `'fit' \| number` | ✓ | 缩放:`'fit'` 自适应或具体数值 |
|
|
647
|
+
| `fill` | `FillConfig` | — | 背景填充 |
|
|
648
|
+
| `texture` | `string` | — | 纹理 URL |
|
|
649
|
+
|
|
650
|
+
**ICase — 方案**
|
|
651
|
+
|
|
652
|
+
| 属性 | 类型 | 必填 | 说明 |
|
|
653
|
+
| ---------- | ---------- | ---- | -------- |
|
|
654
|
+
| `uuid` | `string` | ✓ | 唯一标识 |
|
|
655
|
+
| `isActive` | `boolean` | ✓ | 是否激活 |
|
|
656
|
+
| `title` | `string` | ✓ | 标题 |
|
|
657
|
+
| `scene` | `IScene` | ✓ | 场景 |
|
|
658
|
+
| `layers` | `ILayer[]` | ✓ | 图层列表 |
|
|
659
|
+
|
|
660
|
+
#### 工具函数
|
|
661
|
+
|
|
662
|
+
| 函数 | 说明 |
|
|
663
|
+
| ---------------------------------------------------------- | ---------------------------------------------------- |
|
|
664
|
+
| `numberLoopGenerator(start, end, shouldLoop?)` | 数字生成器 |
|
|
665
|
+
| `linearIncrease(x, y, n, rate, callback)` | n 秒内线性递增 |
|
|
666
|
+
| `transPercentAndPixel(val, size, precision?, getPercent?)` | 百分比 ↔ 像素 |
|
|
667
|
+
| `transFraction(val, size)` | 百分比转小数 |
|
|
668
|
+
| `transRuntimeToPixel(val, precision?, type?)` | 运行时坐标 → 像素(依赖 scene.runtime_width/height) |
|
|
669
|
+
|
|
670
|
+
---
|
|
671
|
+
|
|
672
|
+
## 📝 注意事项
|
|
673
|
+
|
|
674
|
+
1. **编辑器 vs 预览:** 编辑模式配置 `EditorActions`;预览模式配置 `PreviewActions` + `onMessage` → `operating`
|
|
675
|
+
2. **ID 匹配:** `operating` 的 `id` 必须与方案图层 `rawData.id` 一致,否则静默失败(在前端层面该值即为编辑器组件中业务数据配置中必填项 id 的值,需根据后端预先提供的设备 id 在编辑器中进行配置)
|
|
676
|
+
3. **坐标系:** 轨道类设备的 `x` 通常需 `transRuntimeToPixel` 转换;`IRailOperating.x` 直接使用像素
|
|
677
|
+
4. **资源消息:** `Resource` 类型不对应独立图层,通过目标设备的 `resource` 字段操作工位槽
|
|
678
|
+
5. **引擎生命周期:** 组件卸载时自动 `destroyContainer`;手动集成需自行销毁
|
|
679
|
+
6. **类型安全:** 所有 API 均导出 TypeScript 类型,推荐 `import type { ILayerOperating, EnumModel } from '@jnrs/lingshu-smart'`
|
|
680
|
+
|
|
681
|
+
---
|
|
682
|
+
|
|
683
|
+
## 🛠 技术栈
|
|
684
|
+
|
|
685
|
+
- Vue 3 + TypeScript + Pinia
|
|
686
|
+
- LeaferJS 2D 图形引擎
|
|
687
|
+
- Element Plus UI
|
|
688
|
+
|
|
689
|
+
---
|
package/README.md
CHANGED