| <!DOCTYPE html> | 
| <html lang="en"> | 
| <head> | 
|   <meta charset="UTF-8"> | 
|   <title>库位地图</title> | 
|   <link rel="stylesheet" href="../static/css/animate.min.css"> | 
|   <link rel="stylesheet" href="../static/vue/element/element.css"> | 
|   <link rel="stylesheet" href="../static/css/console_vue.css"> | 
|   <link rel="stylesheet" href="../static/css/toggle-switch.css"> | 
|   <script type="text/javascript" src="../static/js/jquery/jquery-3.3.1.min.js"></script> | 
|   <script type="text/javascript" src="../static/layui/layui.js"></script> | 
|   <script type="text/javascript" src="../static/js/handlebars/handlebars-v4.5.3.js"></script> | 
|   <script type="text/javascript" src="../static/js/common.js"></script> | 
|   <script type="text/javascript" src="../static/vue/js/vue.min.js"></script> | 
|   <script type="text/javascript" src="../static/vue/element/element.js"></script> | 
|   <script src="../static/js/gsap.min.js"></script> | 
|   <script src="../static/js/pixi-legacy.min.js"></script> | 
|   <style> | 
|     *{ | 
|       margin: 0; | 
|       padding: 0; | 
|     } | 
|   </style> | 
| </head> | 
| <body> | 
| <div id="app"> | 
|   <div id="pixiView"> | 
|   | 
|   </div> | 
|   | 
|   <!--输出操作和FPS--> | 
|   <div style="position: absolute;top: 20px;right: 50px;"> | 
|     <div>FPS:{{mapFps}}</div> | 
|     <el-button @click="drawer = true">操作</el-button> | 
|   </div> | 
|   | 
|   <el-drawer | 
|           title="操作区域" | 
|           :visible.sync="drawer" | 
|           :with-header="true" | 
|           :modal="false" | 
|   > | 
|     <div class="floorBtnBox" v-for="(lev,idx) in floorList"> | 
|       <el-button :style="{background:currentLev === lev ? '#7DCDFF':''}" @click="changeFloor(lev)">{{lev}}F</el-button> | 
|     </div> | 
|     <div> | 
|       <el-button @click="testMove()">测试移动车</el-button> | 
|     </div> | 
|     <div style="margin-top: 10px;"> | 
|       <el-button @click="resetMap()">重置地图</el-button> | 
|     </div> | 
|   </el-drawer> | 
|   | 
|   <el-drawer | 
|           title="库位详情" | 
|           :visible.sync="drawerLocNo" | 
|           :with-header="true" | 
|           :modal="false" | 
|   > | 
|     <div v-if="drawerLocNoData!=null"> | 
|       <div style="margin: 10px;"> | 
|         <div style="margin-top: 5px;">X:{{drawerLocNoData.x}}</div> | 
|         <div style="margin-top: 5px;">Y:{{drawerLocNoData.y}}</div> | 
|         <div style="margin-top: 5px;">Z:{{drawerLocNoData.z}}</div> | 
|         <div style="margin-top: 5px;">库位号:{{drawerLocNoData.locNo}}</div> | 
|       </div> | 
|     </div> | 
|   </el-drawer> | 
|   | 
|   <el-drawer | 
|           title="小车信息" | 
|           :visible.sync="drawerShuttle" | 
|           :with-header="true" | 
|           :modal="false" | 
|   > | 
|     <div v-if="drawerShuttleData!=null"> | 
|       <div style="margin: 10px;"> | 
|         <div style="margin-top: 5px;">小车:{{drawerShuttleData.shuttleNo}}</div> | 
|         <div style="margin-top: 5px;">工作号:{{drawerShuttleData.wrkNo}}</div> | 
|         <div style="margin-top: 5px;">状态:{{drawerShuttleData}}</div> | 
|       </div> | 
|     </div> | 
|   </el-drawer> | 
|   | 
|   <el-drawer | 
|           title="站点信息" | 
|           :visible.sync="drawerSta" | 
|           :with-header="true" | 
|           :modal="false" | 
|   > | 
|     <div v-if="drawerStaData!=null"> | 
|       <div style="margin: 10px;"> | 
|         <div style="margin-top: 5px;">站点:{{drawerStaData.siteId}}</div> | 
|         <div style="margin-top: 5px;">工作号:{{drawerStaData.workNo}}</div> | 
|         <div style="margin-top: 5px;">工作状态:{{drawerStaData.wrkSts}}</div> | 
|         <div style="margin-top: 5px;">工作类型:{{drawerStaData.ioType}}</div> | 
|         <div style="margin-top: 5px;">源站:{{drawerStaData.sourceStaNo}}</div> | 
|         <div style="margin-top: 5px;">目标站:{{drawerStaData.staNo}}</div> | 
|         <div style="margin-top: 5px;">源库位:{{drawerStaData.sourceLocNo}}</div> | 
|         <div style="margin-top: 5px;">目标库位:{{drawerStaData.locNo}}</div> | 
|         <div style="margin-top: 5px;">自动:{{drawerStaData.autoing}}</div> | 
|         <div style="margin-top: 5px;">有物:{{drawerStaData.loading}}</div> | 
|         <div style="margin-top: 5px;">能入:{{drawerStaData.canining}}</div> | 
|         <div style="margin-top: 5px;">能出:{{drawerStaData.canouting}}</div> | 
|         <div style="margin-top: 5px;">能出:{{drawerStaData.canouting}}</div> | 
|       </div> | 
|     </div> | 
|   </el-drawer> | 
|   | 
|   <el-drawer | 
|           title="提升机信息" | 
|           :visible.sync="drawerLift" | 
|           :with-header="true" | 
|           :modal="false" | 
|   > | 
|     <div v-if="drawerLiftData!=null"> | 
|       <div style="margin: 10px;"> | 
|         <div style="margin-top: 5px;">提升机:{{liftList[drawerLiftData-1].liftNo}}</div> | 
|         <div style="margin-top: 5px;">工作号:{{liftList[drawerLiftData-1].taskNo}}</div> | 
|         <div style="margin-top: 5px;">状态:{{liftList[drawerLiftData-1]}}</div> | 
|       </div> | 
|     </div> | 
|   </el-drawer> | 
|   | 
| </div> | 
| <script> | 
|   let width = 25; | 
|   let height = 25; | 
|   let pixiApp; | 
|   let pixiStageList = []; | 
|   let pixiShuttleMap = new Map(); | 
|   let pixiShuttleMoveAdvancePathMap = new Map(); | 
|   let pixiShuttleMoveAdvancePathList = []; | 
|   let pixiShuttleLockPathMap = new Map(); | 
|   let pixiStaMap = new Map(); | 
|   let objectsContainer; | 
|   let objectsContainer2; | 
|   let objectsContainer3; | 
|   let graphics0; | 
|   let graphics3; | 
|   let graphics4; | 
|   let graphics5; | 
|   let graphics9; | 
|   let graphics67; | 
|   let graphicsLock; | 
|   let ws; | 
|   | 
|   var app = new Vue({ | 
|     el: '#app', | 
|     data: { | 
|       map: [], | 
|       currentLev: 1, | 
|       floorList: [1, 2, 3], //当前项目楼层 | 
|       currentLevShuttleList: [],//当前楼层四向穿梭车集合 | 
|       shuttleColorList: [],//四向穿梭车颜色集合 | 
|       drawer: false, | 
|       drawerLocNo: false, | 
|       drawerLocNoData: null, | 
|       drawerLocDetls: [], | 
|       reloadMap: true, | 
|       mapFps: 0, | 
|       drawerShuttle: false, | 
|       drawerShuttleData: null, | 
|       currentLevStaList: [],//当前楼层站点list | 
|       reloadSta: true, | 
|       drawerSta: false, | 
|       drawerStaData: null, | 
|       drawerLift: false, | 
|       drawerLiftData: null, | 
|       liftList: [], | 
|     }, | 
|     mounted() { | 
|       this.init() | 
|       this.createMap() | 
|     }, | 
|     watch: { | 
|       map: { | 
|         deep: true, | 
|         handler(val) { | 
|   | 
|         } | 
|       }, | 
|       drawerLocNo: { | 
|         deep: true, | 
|         handler(val) { | 
|           if (!val) { | 
|             var sprite = pixiStageList[this.drawerLocNoData.x - 1][this.drawerLocNoData.y]; | 
|             updateColor(sprite, 0xFFFFFF);//恢复颜色 | 
|           } | 
|         } | 
|       } | 
|     }, | 
|     methods: { | 
|       init(){ | 
|         ws = new WebSocket("ws://" + window.location.host + baseUrl + "/console/websocket"); | 
|         ws.onopen = this.webSocketOnOpen | 
|         ws.onerror = this.webSocketOnError | 
|         ws.onmessage = this.webSocketOnMessage | 
|         ws.onclose = this.webSocketClose | 
|   | 
|         this.getMap(this.currentLev) | 
|         // this.getSystemRunningStatus() //获取系统运行状态 | 
|   | 
|         this.consoleInterval = setInterval(() => { | 
|           this.getMap(this.currentLev) //获取实时地图数据 | 
|           this.getShuttleStateInfo() //获取四向穿梭车信息 | 
|           this.getLiftStateInfo() //获取提升机信息 | 
|           this.getSiteInfo() //获取输送站点数据 | 
|           // this.getCodeData()//获取条码 | 
|         }, 1000) | 
|   | 
|       }, | 
|       getShuttleStateInfo() { | 
|         this.sendWs(JSON.stringify({ | 
|           "url": "/shuttle/table/shuttle/state", | 
|           "data": {} | 
|         })) | 
|       }, | 
|       setShuttleStateInfo(res) { | 
|         // 四向穿梭车信息表获取 | 
|         let that = this | 
|         if (res.code == 200) { | 
|           let currentLevShuttle = []//当前楼层小车集合 | 
|           res.data.forEach((item,idx) => { | 
|             if (item != null && item.point != undefined && item.point != null) { | 
|               if (item.point.z == that.currentLev) { | 
|                 currentLevShuttle.push(item); | 
|               } | 
|             } | 
|           }) | 
|           that.shuttleList = res.data | 
|           if (that.shuttleColorList.length == 0) { | 
|             let colorList = []//随机小车颜色 | 
|             res.data.forEach((item,idx) => { | 
|               colorList[item.shuttleNo] = that.colorRGB() | 
|             }) | 
|             that.shuttleColorList = colorList | 
|           } | 
|   | 
|           const result = this.findShuttleDiffList(this.currentLevShuttleList, currentLevShuttle); | 
|           if (!result) { | 
|             //小车存在变动,重新渲染全部小车 | 
|             pixiShuttleMap.forEach((shuttle,index) => { | 
|               pixiApp.stage.removeChild(shuttle) | 
|               pixiShuttleMap.delete(index) | 
|             }) | 
|   | 
|             currentLevShuttle.forEach((item,index) => { | 
|               pixiApp.loader.load((loader, resources) => { | 
|                 // 纹理创建小车 | 
|                 const shuttle = new PIXI.Sprite(resources.shuttle.texture); | 
|                 shuttle.width = width | 
|                 shuttle.height = height | 
|                 shuttle.x = (item.wcsPoint.y - 0) * width;//更新坐标x | 
|                 shuttle.y = (item.wcsPoint.x - 1) * height;//更新坐标y | 
|                 shuttle.updateMoveStatus = true;//动画执行完成 | 
|                 shuttle.interactive = true; // 必须要设置才能接收事件 | 
|                 shuttle.buttonMode = true; // 让光标在hover时变为手型指针 | 
|                 shuttle.on('pointerdown', (e) => { | 
|                   this.drawerShuttle = true; | 
|                   this.drawerShuttleData = item; | 
|                 }) | 
|                 pixiApp.stage.addChild(shuttle); | 
|                 pixiShuttleMap.set(item.shuttleNo, shuttle); | 
|               }) | 
|   | 
|               if (item.moveAdvancePath != null && item.moveAdvancePath.length > 0) {//存在预计路径,进行渲染 | 
|                 this.addMoveAdvancePath(item.moveAdvancePath, item.shuttleNo);//添加预计路径 | 
|               } | 
|   | 
|             }) | 
|           }else { | 
|             //小车不存在变动,渲染小车位置 | 
|             currentLevShuttle.forEach((item,index) => { | 
|               this.updateShuttleXY(item) | 
|             }) | 
|   | 
|             const resultPath = this.findShuttlePathDiffList(JSON.parse(JSON.stringify(this.currentLevShuttleList)), JSON.parse(JSON.stringify(currentLevShuttle))); | 
|             if (!resultPath) { | 
|               //预计路径存在变动,渲染路径 | 
|               currentLevShuttle.forEach((item,index) => { | 
|                 //删除预计路径 | 
|                 this.removeMoveAdvancePath(item.shuttleNo); | 
|                 if (item.moveAdvancePath != null && item.moveAdvancePath.length > 0) {//存在预计路径,进行渲染 | 
|                   this.addMoveAdvancePath(item.moveAdvancePath, item.shuttleNo);//添加预计路径 | 
|                 } | 
|               }) | 
|             } | 
|           } | 
|           that.currentLevShuttleList = currentLevShuttle; | 
|         } | 
|       }, | 
|       //获取地图数据 | 
|       getMap(lev) { | 
|         this.sendWs(JSON.stringify({ | 
|           "url": "/console/map/auth", | 
|           "data": lev | 
|         })) | 
|       }, | 
|       setMap(res) { | 
|         //获取地图数据 | 
|         let data = res.data | 
|         let tmp = [] | 
|         for (let i = 1; i < data.length - 1; i++) { | 
|           tmp.push(data[i]) | 
|         } | 
|         this.createMapData(tmp) | 
|       }, | 
|       changeFloor(lev) { | 
|         this.currentLev = lev | 
|         this.currentLevShuttleList = [] | 
|         this.reloadMap = true | 
|         this.reloadSta = true | 
|         this.getMap(lev) | 
|   | 
|         //清空占用路径 | 
|         objectsContainer3.removeChildren(); | 
|         pixiShuttleLockPathMap = new Map(); | 
|   | 
|         //清空预计路径 | 
|         objectsContainer2.removeChildren(); | 
|         pixiShuttleMoveAdvancePathMap = new Map(); | 
|         pixiShuttleMoveAdvancePathList = [] | 
|       }, | 
|       createMap(){ | 
|         //Create a Pixi Application | 
|         pixiApp = new PIXI.Application({ | 
|           // width: 1500, | 
|           // height: 800, | 
|           backgroundColor: 0xF5F7F9FF, | 
|           resizeTo: window | 
|         }); | 
|         //Add the canvas that Pixi automatically created for you to the HTML document | 
|         $("#pixiView").append(pixiApp.view) | 
|   | 
|         //加载小车资源 | 
|         pixiApp.loader.add('shuttle', '../static/images/sxcar.png'); | 
|   | 
|         // 从Graphics对象创建一个纹理 | 
|         graphics0 = pixiApp.renderer.generateTexture(getContainer(0)); | 
|         graphics3 = pixiApp.renderer.generateTexture(getContainer(3)); | 
|         graphics4 = pixiApp.renderer.generateTexture(getContainer(4)); | 
|         graphics5 = pixiApp.renderer.generateTexture(getContainer(5)); | 
|         graphics9 = pixiApp.renderer.generateTexture(getContainer(9)); | 
|         graphics67 = pixiApp.renderer.generateTexture(getContainer(67)); | 
|         graphicsLock = pixiApp.renderer.generateTexture(getContainer(-999)); | 
|   | 
|         // 创建一个容器来管理大批量的显示对象 | 
|         objectsContainer = new PIXI.Container(); | 
|         pixiApp.stage.addChild(objectsContainer); | 
|   | 
|         // 创建一个容器来管理大批量的显示对象 | 
|         objectsContainer2 = new PIXI.Container(); | 
|         pixiApp.stage.addChild(objectsContainer2); | 
|   | 
|         // 创建一个容器来管理大批量的显示对象 | 
|         objectsContainer3 = new PIXI.Container(); | 
|         pixiApp.stage.addChild(objectsContainer3); | 
|   | 
|         //*******************拖动画布******************* | 
|         let stageOriginalPos; | 
|         let mouseDownPoint; | 
|         let touchBlank = false; | 
|         pixiApp.renderer.plugins.interaction.on( | 
|                 'pointerdown', | 
|                 (event) => { | 
|                   const globalPos = event.data.global; | 
|                   // 记录下stage原来的位置 | 
|                   stageOriginalPos = [pixiApp.stage.position._x, pixiApp.stage.position._y]; | 
|                   // 记录下mouse down的位置 | 
|                   mouseDownPoint = [globalPos.x, globalPos.y]; | 
|                   if (!event.target) { | 
|                     // 点到了画布的空白位置 | 
|                     touchBlank = true; | 
|                   } | 
|                 } | 
|         ); | 
|   | 
|         pixiApp.renderer.plugins.interaction.on( | 
|                 'pointermove', | 
|                 (event) => { | 
|                   const globalPos = event.data.global; | 
|   | 
|                   if (touchBlank) { | 
|                     // 拖拽画布 | 
|                     const dx = globalPos.x - mouseDownPoint[0]; | 
|                     const dy = globalPos.y - mouseDownPoint[1]; | 
|                     pixiApp.stage.position.set( | 
|                             stageOriginalPos[0] + dx, | 
|                             stageOriginalPos[1] + dy | 
|                     ); | 
|                   } | 
|                 } | 
|         ); | 
|   | 
|         pixiApp.renderer.plugins.interaction.on( | 
|                 'pointerup', | 
|                 (event) => { | 
|                   touchBlank = false; | 
|                 } | 
|         ); | 
|         //*******************拖动画布******************* | 
|   | 
|         //*******************缩放画布******************* | 
|         pixiApp.view.addEventListener('wheel', (event) => { | 
|           event.stopPropagation(); | 
|           event.preventDefault(); | 
|           // 因为画布是充满视窗的,所以clientX等于mouse point在renderer上的x坐标 | 
|           const globalPos = [event.clientX, event.clientY]; | 
|           const delta = event.deltaY; | 
|           const oldZoom = pixiApp.stage.scale.x; | 
|           let newZoom = oldZoom * 0.999 ** delta; | 
|   | 
|           // const oldStageMatrix = app.stage.localTransform.clone(); | 
|           // const oldStagePos = oldStageMatrix.applyInverse(pointerGlobalPos); | 
|           const oldStagePos = globalPos; | 
|           const dx = oldStagePos[0] * oldZoom - oldStagePos[0] * newZoom; | 
|           const dy = oldStagePos[1] * oldZoom - oldStagePos[1] * newZoom; | 
|   | 
|           pixiApp.stage.setTransform( | 
|                   pixiApp.stage.position.x + dx, | 
|                   pixiApp.stage.position.y + dy, | 
|                   newZoom, | 
|                   newZoom, | 
|                   0, | 
|                   0, | 
|                   0, | 
|                   0, | 
|                   0 | 
|           ); | 
|   | 
|         }); | 
|         //*******************缩放画布******************* | 
|   | 
|         //*******************FPS******************* | 
|         var g_Time=0; | 
|         pixiApp.ticker.add((delta) => { | 
|           var timeNow = (new Date()).getTime(); | 
|           var timeDiff = timeNow - g_Time; | 
|           g_Time = timeNow; | 
|           var fps = 1000 / timeDiff; | 
|           this.mapFps = parseInt(fps) | 
|         }); | 
|         //*******************FPS******************* | 
|   | 
|       }, | 
|       createMapData(map) { | 
|         if (this.reloadMap) { | 
|           this.reloadMap = false | 
|           pixiStageList = [map.length]//初始化列表 | 
|           pixiStaMap = new Map();//重置 | 
|   | 
|           objectsContainer.removeChildren() | 
|           map.forEach((item,index) => { | 
|             pixiStageList[index] = [item.length] | 
|             for (let idx = 0; idx < item.length; idx++) { | 
|               let val = item[idx] | 
|               if (val.value < 0 && (val.value != -999)) { | 
|                 continue; | 
|               } | 
|   | 
|               let sprite = getSprite(val.value, idx * width, index * height, (e) => { | 
|                 if (val.value == 4) { | 
|                   //站点 | 
|                   this.openDrawerSta(val) | 
|                 }else if (val.value == 67) { | 
|                   //提升机 | 
|                   this.openDrawerLift(val) | 
|                 }else{ | 
|                   //库位 | 
|                   this.rightEvent(index + 1, idx, e); | 
|                   updateColor(sprite, 0x9900ff); | 
|                 } | 
|               }); | 
|   | 
|               if (val.value == 4) { | 
|                 // 创建文本对象 | 
|                 const style = new PIXI.TextStyle({ | 
|                   fontFamily: 'Arial', | 
|                   fontSize: 10, | 
|                   fill: '#000000', | 
|                 }); | 
|                 const text = new PIXI.Text(val.data, style); | 
|                 text.anchor.set(0.5); // 设置文本锚点为中心点 | 
|                 text.position.set(sprite.width / 2, sprite.height / 2); // 将文本位置设置为Graphics对象的中心点 | 
|                 // 将文本对象添加到Graphics对象中 | 
|                 sprite.addChild(text); | 
|                 sprite.textObj = text; | 
|                 pixiStaMap.set(parseInt(val.data), sprite);//站点数据添加到map中 | 
|               }else if (val.value == 67) { | 
|                 // 创建提升机文本对象 | 
|                 const style = new PIXI.TextStyle({ | 
|                   fontFamily: 'Arial', | 
|                   fontSize: 10, | 
|                   fill: '#000000', | 
|                 }); | 
|                 const text = new PIXI.Text(val.data, style); | 
|                 text.anchor.set(0.5); // 设置文本锚点为中心点 | 
|                 text.position.set(sprite.width / 2, sprite.height / 2); // 将文本位置设置为Graphics对象的中心点 | 
|                 // 将文本对象添加到Graphics对象中 | 
|                 sprite.addChild(text); | 
|                 sprite.textObj = text; | 
|                 pixiStaMap.set(parseInt(val.data), sprite);//站点数据添加到map中 | 
|               } | 
|   | 
|               if (val.value == -999) { | 
|                 pixiShuttleLockPathMap.set(this.getLocNoByXYZ(index + 1, idx, this.currentLev), sprite); | 
|                 objectsContainer3.addChild(sprite); | 
|               }else { | 
|                 objectsContainer.addChild(sprite); | 
|               } | 
|               pixiStageList[index][idx] = sprite | 
|             } | 
|           }); | 
|   | 
|           //视角居中 | 
|           let containerWidth = (pixiApp.view.width - objectsContainer.width) / 2; | 
|           let containerHeight = (pixiApp.view.height - objectsContainer.height) / 2; | 
|           pixiApp.stage.position.set(containerWidth, containerHeight); | 
|         }else { | 
|           let diff = this.findDiffList(this.map, map); | 
|           diff.forEach((item, index) => { | 
|             //获取old元素 | 
|             let oldSprite = pixiStageList[item.x][item.y] | 
|             if (item.originData == -999) { | 
|               //移除old路径元素 | 
|               objectsContainer3.removeChild(oldSprite); | 
|             }else { | 
|               //移除old元素 | 
|               objectsContainer.removeChild(oldSprite); | 
|             } | 
|   | 
|             let sprite = getSprite(item.data, item.y * width, item.x * height, (e) => { | 
|               this.rightEvent(item.x + 1, item.y, e); | 
|               updateColor(sprite, 0x9900ff); | 
|             }); | 
|   | 
|             if (item.data == -999) { | 
|               //添加路径元素 | 
|               objectsContainer3.addChild(sprite); | 
|             }else { | 
|               //添加元素 | 
|               objectsContainer.addChild(sprite); | 
|             } | 
|   | 
|             //保存新元素 | 
|             pixiStageList[item.x][item.y] = sprite | 
|           }); | 
|         } | 
|   | 
|         this.map = map; | 
|       }, | 
|       rightEvent(x, y, e) { | 
|         this.drawerLocNo = true | 
|         let locNo = this.getLocNoByXYZ(x, y, this.currentLev); | 
|         this.drawerLocNoData =  {x:x, y: y, z: this.currentLev, locNo: locNo}; | 
|       }, | 
|       findDiffList(arr1, arr2) { | 
|         let diff = [] | 
|         arr1.forEach((item,index) => { | 
|           item.forEach((val,idx) => { | 
|             if(val.value != arr2[index][idx].value){ | 
|               diff.push({ | 
|                 x: index, | 
|                 y: idx, | 
|                 data: arr2[index][idx].value, | 
|                 originData: val.value | 
|               }) | 
|             } | 
|           }) | 
|         }) | 
|   | 
|         return diff; | 
|       }, | 
|       findShuttleDiffList(list1, list2) { | 
|         //检测集合1里面的小车是否在集合2中有变动 | 
|         if (list1.length == 0) { | 
|           return false;//集合为空 | 
|         } | 
|         if (list1.length != list2.length) { | 
|           return false;//两个集合长度不一致 | 
|         } | 
|   | 
|         let flag = false; | 
|         list1.forEach((item,index) => { | 
|           for (var i = 0; i < list2.length; i++) { | 
|             if (item.shuttleNo == list2[i].shuttleNo) { | 
|               flag = true; | 
|               break; | 
|             } | 
|           } | 
|         }); | 
|   | 
|         return flag; | 
|       }, | 
|       findShuttlePathDiffList(list1, list2) { | 
|         //检测集合1里面的小车预计路径是否在集合2中有变动 | 
|         if (list1.length == 0) { | 
|           return false;//集合为空 | 
|         } | 
|         if (list1.length != list2.length) { | 
|           return false;//两个集合长度不一致 | 
|         } | 
|   | 
|         for (var index = 0; index < list1.length; index++) { | 
|           let item = list1[index]; | 
|           for (var i = 0; i < list2.length; i++) { | 
|             if (item.shuttleNo != list2[i].shuttleNo) { | 
|               continue;//找不到小车号 | 
|             } | 
|   | 
|             if (item.moveAdvancePath == null) { | 
|               item.moveAdvancePath = []; | 
|             } | 
|   | 
|             if (list2[i].moveAdvancePath == null) { | 
|               list2[i].moveAdvancePath = []; | 
|             } | 
|   | 
|             if (!(item.moveAdvancePath.length == list2[i].moveAdvancePath.length)) { | 
|               return false;//小车预计路径长度不一致 | 
|             } | 
|           } | 
|         } | 
|         return true; | 
|       }, | 
|       checkStaInListDiff(sta, list) { | 
|         //检测站点是否在集合中有变动 | 
|         if (list.length == 0) { | 
|           return false;//集合为空 | 
|         } | 
|   | 
|         let tmp = null; | 
|         for (var i = 0; i < list.length; i++) { | 
|           if (sta.siteId == list[i].siteId) { | 
|             tmp = list[i];//找到相同站点 | 
|             break | 
|           } | 
|         } | 
|   | 
|         if (tmp == null) { | 
|           return false;//没有找到相同站点 | 
|         } | 
|   | 
|         if (sta.siteStatus != tmp.siteStatus) { | 
|           return false;//站点状态不相同 | 
|         } | 
|   | 
|         if (sta.workNo != tmp.workNo) { | 
|           return false;//站点工作号不相同 | 
|         } | 
|   | 
|         return true;//无变化 | 
|       }, | 
|       webSocketOnOpen(e) { | 
|         console.log("open"); | 
|       }, | 
|       webSocketOnError(e) { | 
|         console.log(e); | 
|       }, | 
|       webSocketOnMessage(e) { | 
|         const result = JSON.parse(e.data); | 
|         if (result.url == "/shuttle/table/shuttle/state") { | 
|           this.setShuttleStateInfo(JSON.parse(result.data)) | 
|         }else if (result.url == "/lift/table/lift/state") { | 
|           this.setLiftStateInfo(JSON.parse(result.data)) | 
|         }else if (result.url == "/console/latest/data/site") { | 
|           this.setSiteInfo(JSON.parse(result.data)) | 
|         }else if (result.url == "/console/map/auth") { | 
|           this.setMap(JSON.parse(result.data)) | 
|         }else if (result.url == "/console/barcode/output/site") { | 
|           this.setCodeData(JSON.parse(result.data)) | 
|         } | 
|       }, | 
|       webSocketClose(e) { | 
|         console.log("close"); | 
|       }, | 
|       sendWs(message) { | 
|         if (ws.readyState == WebSocket.OPEN) { | 
|           ws.send(message) | 
|         } | 
|       }, | 
|       colorRGB(){ | 
|         //随机颜色 | 
|         const r = Math.floor(Math.random()*256); | 
|         const g = Math.floor(Math.random()*256); | 
|         const b = Math.floor(Math.random()*256); | 
|         return `rgb(${r},${g},${b})`; | 
|       }, | 
|       updateShuttleXY(item) { | 
|         const shuttle = pixiShuttleMap.get(item.shuttleNo); | 
|         if (shuttle.updateMoveStatus) {//动画执行完成才可继续执行动画 | 
|           shuttle.updateMoveStatus = false;//动画执行中 | 
|           // 计算两点之间的距离1 | 
|           const distance = Math.sqrt(Math.pow((item.wcsPoint.x * width) - shuttle.x, 2) + Math.pow((item.wcsPoint.y * height) - shuttle.y, 2)); | 
|           gsap.killTweensOf(shuttle); // 杀死所有针对".class"的动画 | 
|           gsap.to(shuttle, { | 
|             x: (item.wcsPoint.y - 0) * width, // 目标位置 | 
|             y: (item.wcsPoint.x - 1) * height, // 目标位置 | 
|             duration: 0.2, // 动画持续时间(秒) | 
|             ease: "power1.inOut", // 缓动类型 | 
|             onComplete: () => { | 
|               shuttle.updateMoveStatus = true;//动画执行完成 | 
|             } | 
|           }); | 
|         } | 
|       }, | 
|       getSiteInfo() { | 
|         //获取输送站点数据 | 
|         this.sendWs(JSON.stringify({ | 
|           "url": "/console/latest/data/site", | 
|           "data": {} | 
|         })) | 
|       }, | 
|       setSiteInfo(res) { | 
|         // var test = "{\"msg\":\"操作成功\",\"code\":200,\"data\":[{\"siteId\":\"300\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"301\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"302\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"303\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"304\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"305\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"306\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"307\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"308\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"309\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"310\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"311\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"312\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"313\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"314\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"315\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"316\",\"siteStatus\":\"site-auto-run\",\"workNo\":0},{\"siteId\":\"317\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"318\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"319\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"320\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"321\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"322\",\"siteStatus\":\"site-auto-run\",\"workNo\":0},{\"siteId\":\"323\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"324\",\"siteStatus\":\"site-auto-run\",\"workNo\":0},{\"siteId\":\"325\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"326\",\"siteStatus\":\"site-auto-id\",\"workNo\":5451},{\"siteId\":\"327\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"200\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"328\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"201\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"329\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"202\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"330\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"203\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"331\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"204\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"332\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"205\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"333\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"334\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"335\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"336\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"337\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"338\",\"siteStatus\":\"site-auto-run\",\"workNo\":0},{\"siteId\":\"339\",\"siteStatus\":\"site-auto-run-id\",\"workNo\":5447},{\"siteId\":\"340\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"341\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"342\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"343\",\"siteStatus\":\"site-auto-run\",\"workNo\":0},{\"siteId\":\"344\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"345\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"346\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"100\",\"siteStatus\":\"site-auto-run-id\",\"workNo\":8851},{\"siteId\":\"101\",\"siteStatus\":\"site-auto-run-id\",\"workNo\":8855},{\"siteId\":\"102\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"103\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"104\",\"siteStatus\":\"site-auto-run\",\"workNo\":0},{\"siteId\":\"105\",\"siteStatus\":\"site-auto\",\"workNo\":0}]}"; | 
|         // res = JSON.parse(test) | 
|         //获取输送站点数据 | 
|         if (res.code === 200){ | 
|           var sites = res.data; | 
|           if (this.reloadSta && pixiStaMap.size > 0) { | 
|             //重新渲染所有输送站点 | 
|             this.currentLevStaList = sites; | 
|             this.reloadSta = false; | 
|             sites.forEach((item, index) => { | 
|               let sta = pixiStaMap.get(parseInt(item.siteId)); | 
|               if (sta != undefined) { | 
|                 if (item.workNo > 0) { | 
|                   sta.textObj.text = item.siteId + "(" + item.workNo + ")"; | 
|                 } | 
|   | 
|                 //创建遮罩层 | 
|                 if (item.siteStatus == "site-auto") { | 
|                   //自动状态,移除遮罩层 | 
|                   if (sta.statusObj != null) { | 
|                     objectsContainer.removeChild(sta.statusObj) | 
|                     sta.statusObj = null; | 
|                   } | 
|                 }else if (item.siteStatus == "site-auto-run" || item.siteStatus == "site-auto-run-id") { | 
|                   //自动有物 | 
|                   let graphics = getGraphics(0xfa51f6, width, height, sta.x, sta.y); | 
|                   graphics.addChild(sta.textObj);//继承文字信息 | 
|                   sta.statusObj = graphics; | 
|                   objectsContainer.addChild(graphics); | 
|                 }else if (item.siteStatus == "site-unauto") { | 
|                   //非自动 | 
|                   let graphics = getGraphics(0xb8b8b8, width, height, sta.x, sta.y); | 
|                   graphics.addChild(sta.textObj);//继承文字信息 | 
|                   sta.statusObj = graphics; | 
|                   objectsContainer.addChild(graphics); | 
|                 } | 
|               } | 
|             }); | 
|           } else { | 
|             //检测不相同站点进行局部更新 | 
|             this.currentLevStaList.forEach((item, index) => { | 
|               let result = this.checkStaInListDiff(item, sites); | 
|               if (!result) { | 
|                 //需要更新 | 
|                 let sta = pixiStaMap.get(parseInt(item.siteId)); | 
|                 if (item.workNo > 0) { | 
|                   sta.textObj.text = item.siteId + "(" + item.workNo + ")"; | 
|                 }else { | 
|                   sta.textObj.text = item.siteId; | 
|                 } | 
|   | 
|                 //创建遮罩层 | 
|                 if (item.siteStatus == "site-auto") { | 
|                   //自动状态,移除遮罩层 | 
|                   if (sta.statusObj != null) { | 
|                     objectsContainer.removeChild(sta.statusObj) | 
|                     sta.statusObj = null; | 
|                   } | 
|                 }else if (item.siteStatus == "site-auto-run") { | 
|                   //自动有物 | 
|                   let graphics = getGraphics(0xfa51f6, width, height, sta.x, sta.y); | 
|                   graphics.addChild(sta.textObj);//继承文字信息 | 
|                   sta.statusObj = graphics; | 
|                   objectsContainer.addChild(graphics); | 
|                 }else if (item.siteStatus == "site-unauto") { | 
|                   //非自动 | 
|                   let graphics = getGraphics(0xb8b8b8, width, height, sta.x, sta.y); | 
|                   graphics.addChild(sta.textObj);//继承文字信息 | 
|                   sta.statusObj = graphics; | 
|                   objectsContainer.addChild(graphics); | 
|                 } | 
|               } | 
|             }); | 
|           } | 
|         } else if (res.code === 403){ | 
|           parent.location.href = baseUrl+"/login"; | 
|         }  else { | 
|           console.log(res.msg); | 
|         } | 
|       }, | 
|       openDrawerSta(data) { | 
|         let that = this | 
|         this.drawerSta = true; | 
|         $.ajax({ | 
|           url: baseUrl + "/console/site/detail", | 
|           headers: { | 
|             'token': localStorage.getItem('token') | 
|           }, | 
|           data: { | 
|             siteId: data.data | 
|           }, | 
|           method: 'post', | 
|           success: function(res) { | 
|             //解析数据 | 
|             let siteInfo = res.data; | 
|             if (res.code == 200) { | 
|               that.drawerStaData = siteInfo; | 
|             } | 
|           } | 
|         }) | 
|       }, | 
|       openDrawerLift(data) { | 
|         this.drawerLift = true; | 
|         this.drawerLiftData = parseInt(data.data) | 
|       }, | 
|       getLiftStateInfo() { | 
|         // 提升机信息表获取 | 
|         this.sendWs(JSON.stringify({ | 
|           "url": "/lift/table/lift/state", | 
|           "data": {} | 
|         })) | 
|       }, | 
|       setLiftStateInfo(res) { | 
|         // 提升机信息表获取 | 
|         if (res.code == 200) { | 
|           this.liftList = res.data | 
|         } | 
|       }, | 
|       getLocNoByXYZ(x, y, z) { | 
|         let locNo = ""; | 
|         if (x < 10) { | 
|           locNo += "0" + x; | 
|         }else { | 
|           locNo += x; | 
|         } | 
|   | 
|         if (y < 100) { | 
|           locNo += "0" + y; | 
|         }else if (y < 10) { | 
|           locNo += "00" + y; | 
|         }else { | 
|           locNo += y; | 
|         } | 
|   | 
|         if (z < 10) { | 
|           locNo += "0" + z; | 
|         }else { | 
|           locNo += z; | 
|         } | 
|         return locNo; | 
|       }, | 
|       addMoveAdvancePath(moveAdvancePath, shuttleNo) {//添加预计路径 | 
|         let that = this; | 
|         moveAdvancePath.forEach((path, idx) => { | 
|           let locNo = that.getLocNoByXYZ(path.x, path.y, path.z); | 
|           if (!pixiShuttleMoveAdvancePathMap.has(locNo)) { | 
|             let graphics = getGraphics(0x9966ff, width, height, path.y * width, (path.x - 1) * height); | 
|             let shuttleNos = [shuttleNo]; | 
|             // 创建文本对象 | 
|             const style = new PIXI.TextStyle({ | 
|               fontFamily: 'Arial', | 
|               fontSize: 10, | 
|               fill: '#000000', | 
|             }); | 
|             const text = new PIXI.Text(JSON.stringify(shuttleNos), style); | 
|             text.anchor.set(0.5); // 设置文本锚点为中心点 | 
|             text.position.set(graphics.width / 2, graphics.height / 2); // 将文本位置设置为Graphics对象的中心点 | 
|             // 将文本对象添加到Graphics对象中 | 
|             graphics.addChild(text); | 
|             graphics.textObj = text; | 
|             objectsContainer2.addChild(graphics) | 
|             pixiShuttleMoveAdvancePathMap.set(locNo, { | 
|               path: path, | 
|               sprite: graphics, | 
|               textObj: text, | 
|               shuttleNos: shuttleNos | 
|             }) | 
|   | 
|             if (pixiShuttleMoveAdvancePathList[shuttleNo] == null) { | 
|               let locNos = new Set() | 
|               locNos.add(locNo); | 
|               pixiShuttleMoveAdvancePathList[shuttleNo] = locNos; | 
|             }else { | 
|               pixiShuttleMoveAdvancePathList[shuttleNo].add(locNo); | 
|             } | 
|           }else { | 
|             let pathMap = pixiShuttleMoveAdvancePathMap.get(locNo) | 
|             let shuttleNos = pathMap.shuttleNos; | 
|             shuttleNos.push(shuttleNo); | 
|             pathMap.textObj.text = JSON.stringify(shuttleNos); | 
|             pixiShuttleMoveAdvancePathMap.set(locNo, pathMap); | 
|             if (pixiShuttleMoveAdvancePathList[shuttleNo] == null) { | 
|               let locNos = new Set() | 
|               locNos.add(locNo); | 
|               pixiShuttleMoveAdvancePathList[shuttleNo] = locNos; | 
|             }else { | 
|               pixiShuttleMoveAdvancePathList[shuttleNo].add(locNo); | 
|             } | 
|           } | 
|         }); | 
|       }, | 
|       removeMoveAdvancePath(shuttleNo) {//删除预计路径 | 
|         let locNos = pixiShuttleMoveAdvancePathList[shuttleNo]; | 
|         if (locNos != null) { | 
|           locNos.forEach((locNo,index) => { | 
|             let pathMap = pixiShuttleMoveAdvancePathMap.get(locNo); | 
|             if (pathMap != null) { | 
|               let shuttleNos = pathMap.shuttleNos; | 
|               let shuttleNosNew = []; | 
|               shuttleNos.forEach((shuttle, idx) => { | 
|                 if (shuttle != shuttleNo) { | 
|                   shuttleNosNew.push(shuttle); | 
|                 } | 
|               }); | 
|   | 
|               if (shuttleNosNew.length === 0) { | 
|                 //预计路径没有小车,直接删除路径 | 
|                 objectsContainer2.removeChild(pathMap.sprite); | 
|                 pixiShuttleMoveAdvancePathMap.delete(locNo) | 
|               }else { | 
|                 //预计路径存在其他小车,更新文字信息 | 
|                 pathMap.textObj.text = JSON.stringify(shuttleNosNew); | 
|                 pathMap.shuttleNos = shuttleNosNew; | 
|                 pixiShuttleMoveAdvancePathMap.set(locNo, pathMap); | 
|               } | 
|             } | 
|           }) | 
|         } | 
|       }, | 
|       resetMap() { | 
|         //重置地图 | 
|         let that = this | 
|         $.ajax({ | 
|           url:baseUrl+"/console/map/resetMap/" + this.currentLev, | 
|           headers:{ | 
|             'token': localStorage.getItem('token') | 
|           }, | 
|           data:{}, | 
|           method:'get', | 
|           success:function (res) { | 
|             that.$message({ | 
|               message: that.currentLev + '层地图重置完成', | 
|               type: 'success' | 
|             }); | 
|           } | 
|         }) | 
|       }, | 
|     } | 
|   }) | 
|   | 
|   function getContainer(value) { | 
|     let graphics = new PIXI.Graphics(); | 
|     if (value === 0) { | 
|       graphics.beginFill(0x55aaff); | 
|     } else if (value === 3) {//母轨道 | 
|       graphics.beginFill(0x00ff7f); | 
|       graphics.visible = true; | 
|     } else if (value === 4) {//站点 | 
|       graphics.beginFill(0xffff00); | 
|       graphics.visible = true; | 
|     } else if (value === 5) {//充电桩 | 
|       graphics.beginFill(0xffaa7f); | 
|       graphics.visible = true; | 
|     } else if (value === 9) {//轨迹 | 
|       graphics.beginFill(0xff0000); | 
|     }else if (value === 67) {//提升机 | 
|       graphics.beginFill(0xaaffff); | 
|     }else if (value === -999) {//路径锁定 | 
|       graphics.beginFill(0xf83333); | 
|     } | 
|     graphics.lineStyle(1, 0xffffff, 1); | 
|     graphics.drawRect(0, 0, width, height); | 
|     graphics.endFill(); | 
|   | 
|     return graphics; | 
|   } | 
|   | 
|   function getGraphics(color, width, height, x, y) { | 
|     let graphics = new PIXI.Graphics(); | 
|     graphics.beginFill(color); | 
|     graphics.lineStyle(1, 0xffffff, 1); | 
|     graphics.drawRect(0, 0, width, height); | 
|     graphics.position.set(x, y); | 
|     graphics.endFill(); | 
|     return graphics; | 
|   } | 
|   | 
|   function getSprite(value, x, y, pointerDownEvent) { | 
|     let sprite; | 
|     if (value == 0) { | 
|       sprite = new PIXI.Sprite(graphics0); | 
|     } else if (value == 3) { | 
|       sprite = new PIXI.Sprite(graphics3); | 
|     } else if (value == 4) { | 
|       sprite = new PIXI.Sprite(graphics4); | 
|     } else if (value == 5) { | 
|       sprite = new PIXI.Sprite(graphics5); | 
|     } else if (value == 9) { | 
|       sprite = new PIXI.Sprite(graphics9); | 
|     } else if (value == 67) { | 
|       sprite = new PIXI.Sprite(graphics67); | 
|     } else if (value == -999) { | 
|       sprite = new PIXI.Sprite(graphicsLock); | 
|     } else { | 
|       sprite = new PIXI.Sprite(graphics0); | 
|     } | 
|     sprite.position.set(x, y); | 
|     sprite.interactive = true; // 必须要设置才能接收事件 | 
|     sprite.buttonMode = true; // 让光标在hover时变为手型指针 | 
|   | 
|     sprite.on('pointerdown', (e) => { | 
|       pointerDownEvent(e) | 
|     }) | 
|   | 
|     return sprite; | 
|   } | 
|   | 
|   /** | 
|    * 更新颜色 | 
|    */ | 
|   function updateColor(sprite, color) { | 
|     // graphics.clear() | 
|     // graphics.beginFill(color); | 
|     // graphics.drawRect(0, 0, width, height); | 
|     sprite.tint = color; | 
|   } | 
|   | 
| </script> | 
| </body> | 
| </html> |