wanshenmean
2026-03-30 b698e3b2147a46fd4adb168aea5df892236cc0e0
docs: 添加库存3D查看器设计文档

Co-Authored-By: Claude <noreply@anthropic.com>
已添加1个文件
233 ■■■■■ 文件已修改
Code/WMS/docs/superpowers/specs/2026-03-30-stock-chat-3d-design.md 233 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/docs/superpowers/specs/2026-03-30-stock-chat-3d-design.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,233 @@
# åº“å­˜3D查看器 (stockChat) è®¾è®¡æ–‡æ¡£
## 1. æ¦‚è¿°
- **功能名称**:库存3D仓库查看器 (stockChat)
- **文件路径**:`WIDESEA_WMSClient/src/views/stock/stockChat.vue`
- **核心功能**:使用 Three.js + WebGL å®žçŽ°ä»“åº“3D可视化,用户可在3D场景中巡视仓库、查看货位状态、点击货位查看库存详情
- **目标用户**:仓库管理员、调度人员、质检人员
## 2. æŠ€æœ¯é€‰åž‹
| æŠ€æœ¯ | é€‰åž‹ | è¯´æ˜Ž |
|------|------|------|
| 3D引擎 | Three.js | WebGL ä¸»æµåº“,Vue 3 å‹å¥½ |
| æ¸²æŸ“ç­–ç•¥ | InstancedMesh | æ‰¹é‡æ¸²æŸ“大量货位,单次 drawcall |
| çŠ¶æ€ç®¡ç† | Vue 3 Composition API | `ref/reactive` |
| UI组件 | Element Plus | ä¸Žé¡¹ç›®çŽ°æœ‰æŠ€æœ¯æ ˆä¸€è‡´ |
| å®žæ—¶é€šä¿¡ | SignalR | ä¸ŽåŽç«¯ WebSocket é…åˆå®žçŽ°åº“å­˜åŠ¨æ€æ›´æ–° |
## 3. åŠŸèƒ½éœ€æ±‚
### 3.1 æ ¸å¿ƒåŠŸèƒ½
1. **仓库3D布局展示**
   - å…¨éƒ¨è´§ä½å‡æ¸²æŸ“,按状态着色
   - è´§æž¶å¼æŽ’列,包含巷道
   - åœ°é¢ç½‘格背景
2. **多仓库 Tab åˆ‡æ¢**
   - Element Plus Tabs ç»„ä»¶
   - æ¯ä¸ªä»“库独立加载数据
   - Tab åˆ‡æ¢æ—¶é‡ç½®3D场景
3. **货位点击详情弹窗**
   - å…¨å± Dialog å±•示
   - æ˜¾ç¤ºï¼šè´§ä½ä¿¡æ¯ã€åº“存状态、托盘编号、物料明细列表
   - æ”¯æŒæŸ¥çœ‹æ‰¹æ¬¡ã€ä¿è´¨æœŸé¢„è­¦
4. **3D场景交互**
   - é¼ æ ‡æ—‹è½¬ï¼ˆOrbitControls)
   - æ»šè½®ç¼©æ”¾
   - ä¸­é”®å¹³ç§»
   - ç‚¹å‡»è´§ä½é«˜äº® + ç›¸æœºèšç„¦
5. **实时库存状态更新**
   - SignalR ç›‘听库存变化
   - è´§ä½é¢œè‰²åŠ¨æ€æ›´æ–°
6. **筛选过滤**
   - æŒ‰ç‰©æ–™ç±»åž‹/批次/库存状态过滤
   - é«˜äº®æ˜¾ç¤ºåŒ¹é…è´§ä½
7. **状态图例**
   - å³ä¸Šè§’/底部颜色图例
   - è¯´æ˜Žæ¯ç§é¢œè‰²ä»£è¡¨çš„货位状态
### 3.2 è´§ä½çŠ¶æ€é¢œè‰²ç¼–ç 
| çŠ¶æ€ | é¢œè‰² | Hex |
|------|------|-----|
| ç©ºè´§ä½ | æš—灰 | `#4a4a4a` |
| æœ‰åº“å­˜ | è“è‰² | `#409EFF` |
| åº“存紧张 (<10%) | æ©™è‰² | `#E6A23C` |
| å·²æ»¡ | ç»¿è‰² | `#67C23A` |
| é”å®š/冻结 | çº¢è‰² | `#F56C6C` |
| ç¦ç”¨ | æ·±ç° | `#2d2d2d` |
## 4. åŽç«¯ API
### 4.1 æ–°å¢žæŽ¥å£
```
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`: è´§ä½æœ€å¤§å®¹é‡ï¼ˆç”¨äºŽè®¡ç®—填充率)
### 4.2 SignalR å®žæ—¶æŽ¨é€
**Hub è·¯å¾„**:`/stockHub`
**推送事件**:
```javascript
// åº“存变化事件
stockUpdated: { locationId, warehouseId, stockQuantity, stockStatus }
```
## 5. å‰ç«¯æ–‡ä»¶ç»“æž„
```
WIDESEA_WMSClient/src/
├── views/stock/
│   â””── stockChat.vue              # ä¸»é¡µé¢ç»„ä»¶
├── extension/stock/
│   â””── stockChat.js               # ViewGrid æ‰©å±•配置
└── api/
    â””── http.js                    # å¤ç”¨çŽ°æœ‰ http å°è£…
```
## 6. ç»„件结构 (stockChat.vue)
```vue
<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>
```
## 7. Three.js åœºæ™¯è®¾è®¡
### 7.1 åˆå§‹åŒ–流程
1. åˆ›å»º `WebGLRenderer`,挂载到 `canvasContainer`
2. åˆ›å»º `PerspectiveCamera`(透视相机)
3. åˆ›å»º `Scene` åœºæ™¯
4. æ·»åŠ å…‰ç…§ï¼ˆçŽ¯å¢ƒå…‰ + å®šå‘光)
5. åˆ›å»ºåœ°é¢ï¼ˆ`PlaneGeometry` + ç½‘格材质)
6. åˆ›å»ºè´§æž¶è´§ä½ï¼ˆ`InstancedMesh`)
7. æ·»åŠ  `OrbitControls` æŽ§åˆ¶å™¨
8. å¯åŠ¨æ¸²æŸ“å¾ªçŽ¯
### 7.2 è´§ä½å®šä½ç®—法
```
x = (column - maxColumn/2) * CELL_SIZE_X
y = layer * CELL_SIZE_Y
z = (row - maxRow/2) * CELL_SIZE_Z
```
### 7.3 ç‚¹å‡»æ‹¾å–
- ä½¿ç”¨ `Raycaster` è¿›è¡Œå°„线检测
- é€šè¿‡ `instanceId` è¯†åˆ«è¢«ç‚¹å‡»çš„货位实例
- é«˜äº®ï¼šä¸´æ—¶æ›¿æ¢æè´¨é¢œè‰²
### 7.4 ç›¸æœºèšç„¦åŠ¨ç”»
- ä½¿ç”¨ `TWEEN` æˆ–手动插值平滑移动相机
- ç›®æ ‡ä½ç½®ï¼šè´§ä½åæ ‡ + åç§»é‡
## 8. æ€§èƒ½ä¼˜åŒ–
| ç­–ç•¥ | è¯´æ˜Ž |
|------|------|
| InstancedMesh | å•次 drawcall æ¸²æŸ“所有货位 |
| è§†é”¥ä½“剔除 | ç›¸æœºå¤–的货位不渲染 |
| é¢œè‰²ç¼“å­˜ | æè´¨å¤ç”¨ï¼Œé¿å…é¢‘繁创建 |
| requestAnimationFrame | æ¸²æŸ“循环使用 RAF |
| æ•°æ®åˆ†é¡µ | å¤§ä»“库可考虑按区域分片加载 |
## 9. è·¯ç”±æ³¨å†Œ
在 `viewGird.js` ä¸­æ³¨å†Œè·¯ç”±ï¼š
```javascript
{
  path: '/stockChat',
  name: 'stockChat',
  component: () => import('@/views/stock/stockChat.vue')
}
```
## 10. å¾…补充
- [ ] åŽç«¯ `Get3DLayout` API å®žçް
- [ ] SignalR Hub é…ç½®
- [ ] è´§ä½é¢œè‰²ä¸ŽåŽç«¯çŠ¶æ€æžšä¸¾å¯¹é½
- [ ] ç­›é€‰åŠŸèƒ½å…·ä½“å­—æ®µç¡®è®¤