WIDESEA_WMSClient/src/views/stock/stockChat.vue| 技术 | 选型 | 说明 |
|---|---|---|
| 3D引擎 | Three.js | WebGL 主流库,Vue 3 友好 |
| 渲染策略 | InstancedMesh | 批量渲染大量货位,单次 drawcall |
| 状态管理 | Vue 3 Composition API | ref/reactive |
| UI组件 | Element Plus | 与项目现有技术栈一致 |
| 实时通信 | SignalR | 与后端 WebSocket 配合实现库存动态更新 |
| 状态 | 颜色 | Hex |
|---|---|---|
| 空货位 | 暗灰 | #4a4a4a |
| 有库存 | 蓝色 | #409EFF |
| 库存紧张 (<10%) | 橙色 | #E6A23C |
| 已满 | 绿色 | #67C23A |
| 锁定/冻结 | 红色 | #F56C6C |
| 禁用 | 深灰 | #2d2d2d |
GET /api/StockInfo/Get3DLayout?warehouseId={id}
响应结构:json { "status": true, "data": { "warehouseId": 1, "warehouseName": "主仓库", "maxRow": 10, "maxColumn": 20, "maxLayer": 5, "locations": [ { "locationId": 1, "locationCode": "A-01-02-03", "row": 1, "column": 2, "layer": 3, "locationStatus": 0, "stockStatus": 2, "stockQuantity": 50, "maxCapacity": 100, "palletCode": "PLT-001", "materielCode": "M001", "materielName": "物料A", "batchNo": "B20260301" } ] } }
说明:
- locationStatus: 0=空, 1=占用, 2=锁定, 3=禁用
- stockStatus: 0=无货, 1=有货, 2=库存紧张, 3=已满
- maxCapacity: 货位最大容量(用于计算填充率)
Hub 路径:/stockHub
推送事件:javascript // 库存变化事件 stockUpdated: { locationId, warehouseId, stockQuantity, stockStatus }
WIDESEA_WMSClient/src/
├── views/stock/
│ └── stockChat.vue # 主页面组件
├── extension/stock/
│ └── stockChat.js # ViewGrid 扩展配置
└── api/
└── http.js # 复用现有 http 封装
<template>
<div class="stock-chat-container">
<!-- 仓库 Tabs -->
<el-tabs v-model="activeWarehouse" @tab-change="onWarehouseChange">
<el-tab-pane
v-for="wh in warehouseList"
:key="wh.warehouseId"
:label="wh.warehouseName"
:name="wh.warehouseId"
/>
</el-tabs>
<!-- 工具栏 -->
<div class="toolbar">
<el-select v-model="filterStatus" placeholder="库存状态筛选" clearable />
<el-select v-model="filterMateriel" placeholder="物料筛选" clearable />
<el-button @click="resetCamera">重置视角</el-button>
</div>
<!-- 3D Canvas -->
<div ref="canvasContainer" class="canvas-container" />
<!-- 状态图例 -->
<div class="legend">
<div v-for="item in legendItems" :key="item.status" class="legend-item">
<span class="color-box" :style="{ background: item.color }" />
<span>{{ item.label }}</span>
</div>
</div>
<!-- 详情弹窗 -->
<el-dialog v-model="detailDialogVisible" title="库存详情" fullscreen>
<!-- 详情内容 -->
</el-dialog>
</div>
</template>
WebGLRenderer,挂载到 canvasContainerPerspectiveCamera(透视相机)Scene 场景PlaneGeometry + 网格材质)InstancedMesh)OrbitControls 控制器x = (column - maxColumn/2) * CELL_SIZE_X
y = layer * CELL_SIZE_Y
z = (row - maxRow/2) * CELL_SIZE_Z
Raycaster 进行射线检测instanceId 识别被点击的货位实例TWEEN 或手动插值平滑移动相机| 策略 | 说明 |
|---|---|
| InstancedMesh | 单次 drawcall 渲染所有货位 |
| 视锥体剔除 | 相机外的货位不渲染 |
| 颜色缓存 | 材质复用,避免频繁创建 |
| requestAnimationFrame | 渲染循环使用 RAF |
| 数据分页 | 大仓库可考虑按区域分片加载 |
在 viewGird.js 中注册路由:javascript { path: '/stockChat', name: 'stockChat', component: () => import('@/views/stock/stockChat.vue') }
Get3DLayout API 实现