| | |
| | | import { ref, reactive, onMounted, onUnmounted, watch, getCurrentInstance } from 'vue' |
| | | import * as THREE from 'three' |
| | | import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js' |
| | | import * as signalR from '@microsoft/signalr' |
| | | |
| | | const { proxy } = getCurrentInstance() |
| | | |
| | | // SignalR 连接 |
| | | let connection = null |
| | | |
| | | // 颜色常量 |
| | | const COLOR_MAP = { |
| | |
| | | let locationMesh = null |
| | | let locationData = [] |
| | | let animationId = null |
| | | |
| | | // SignalR 初始化 |
| | | function initSignalR() { |
| | | proxy.http.post('api/User/GetCurrentUserInfo').then((result) => { |
| | | connection = new signalR.HubConnectionBuilder() |
| | | .withAutomaticReconnect() |
| | | .withUrl(`${proxy.http.ipAddress}stockHub?userName=${result.data.userName}`) |
| | | .build(); |
| | | |
| | | connection.start().catch((err) => console.log('SignalR连接失败:', err)); |
| | | |
| | | connection.on('StockUpdated', (update) => { |
| | | // 更新对应货位的数据 |
| | | const idx = locationData.findIndex(x => x.locationId === update.locationId); |
| | | if (idx !== -1) { |
| | | locationData[idx].stockQuantity = update.stockQuantity; |
| | | locationData[idx].stockStatus = update.stockStatus; |
| | | // 重新渲染单个货位颜色 |
| | | updateInstanceColor(idx, update.stockStatus); |
| | | } |
| | | }); |
| | | }); |
| | | } |
| | | |
| | | // 更新单个货位颜色 |
| | | function updateInstanceColor(instanceId, stockStatus) { |
| | | if (!locationMesh) return; |
| | | const loc = locationData[instanceId]; |
| | | if (!loc) return; |
| | | const color = getLocationColor(loc); |
| | | locationMesh.setColorAt(instanceId, new THREE.Color(color)); |
| | | locationMesh.instanceColor.needsUpdate = true; |
| | | } |
| | | |
| | | // 获取货位颜色 |
| | | function getLocationColor(location) { |
| | |
| | | try { |
| | | const res = await proxy.http.get(`/api/StockInfo/Get3DLayout?warehouseId=${warehouseId}`) |
| | | if (res.Status && res.Data) { |
| | | locationData = res.Data |
| | | // 提取物料编号和批次列表 |
| | | const codes = new Set() |
| | | const batches = new Set() |
| | | res.Data.forEach(loc => { |
| | | if (loc.materielCode) codes.add(loc.materielCode) |
| | | if (loc.batchNo) batches.add(loc.batchNo) |
| | | }) |
| | | materielCodeList.value = Array.from(codes) |
| | | batchNoList.value = Array.from(batches) |
| | | const data = res.Data |
| | | locationData = data.Locations || [] |
| | | // 使用后端返回的筛选列表 |
| | | materielCodeList.value = data.MaterielCodeList || [] |
| | | batchNoList.value = data.BatchNoList || [] |
| | | // 渲染货位 |
| | | renderLocations() |
| | | } |
| | |
| | | onMounted(() => { |
| | | initThreeJS() |
| | | loadWarehouseList() |
| | | initSignalR() |
| | | window.addEventListener('resize', onWindowResize) |
| | | }) |
| | | |
| | |
| | | if (renderer) { |
| | | renderer.dispose() |
| | | } |
| | | if (connection) { |
| | | connection.stop() |
| | | } |
| | | }) |
| | | </script> |
| | | |