#
Junjie
5 天以前 82c36e2b434fa7a1c16b0448aa4cf1483107f79c
src/main/webapp/views/watch/console2.html
@@ -55,16 +55,6 @@
      </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;">
@@ -85,32 +75,27 @@
      </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 pixiStaMap = new Map();
    let pixiCrnMap = new Map();
    let pixiRgvMap = new Map();
    let pixiShelfMap = new Map();
    let pixiTrackMap = new Map();
    let pixiDevpTextureMap = new Map();
    let crnList = [];
    let rgvList = [];
    let objectsContainer;
    let objectsContainer2;
    let graphicsShelf;
    let graphicsDevp;
    let graphicsCrn;
    let graphicsCrnTrack;
    let graphicsRgvTrack;
    let graphicsRgv;
    let ws;
    var app = new Vue({
@@ -119,23 +104,14 @@
        map: [],
        currentLev: 1,
        floorList: [], //当前项目楼层
        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()
@@ -173,13 +149,11 @@
            that.getMap(this.currentLev)
          }, 1000);
          // this.consoleInterval = setInterval(() => {
          //   this.getMap(this.currentLev) //获取实时地图数据
          //   this.getShuttleStateInfo() //获取四向穿梭车信息
          //   this.getLiftStateInfo() //获取提升机信息
          //   this.getSiteInfo() //获取输送站点数据
          //   // this.getCodeData()//获取条码
          // }, 1000)
          this.consoleInterval = setInterval(() => {
            this.getCrnInfo() //获取堆垛机数据
            this.getSiteInfo() //获取输送站点数据
            this.getRgvInfo() //获取Rgv数据
          }, 1000)
        },
        initLev() {
@@ -226,8 +200,6 @@
        changeFloor(lev) {
          this.currentLev = lev
          this.currentLevShuttleList = []
          this.reloadMap = true
          this.reloadSta = true
          this.getMap(lev)
          //清空预计路径
@@ -250,10 +222,8 @@
          pixiApp.loader.add('shuttle', '../static/images/sxcar.png');
          // 从Graphics对象创建一个纹理
          graphicsShelf = pixiApp.renderer.generateTexture(getContainer('shelf'));
          graphicsDevp = pixiApp.renderer.generateTexture(getContainer('devp'));
          graphicsCrn = pixiApp.renderer.generateTexture(getContainer('crn'));
          graphicsCrnTrack = createTrackTexture();
          graphicsCrnTrack = createTrackTexture(25,25);
          graphicsRgvTrack = createTrackTexture(25,25);
          // 创建一个容器来管理大批量的显示对象
          objectsContainer = new PIXI.Container();
@@ -262,6 +232,12 @@
          // 创建一个容器来管理大批量的显示对象
          objectsContainer2 = new PIXI.Container();
          pixiApp.stage.addChild(objectsContainer2);
          pixiApp.stage.sortableChildren = true;
          objectsContainer.sortableChildren = true;
          objectsContainer2.sortableChildren = true;
          objectsContainer.zIndex = 10;
          objectsContainer2.zIndex = 20;
          //*******************拖动画布*******************
          let stageOriginalPos;
@@ -311,29 +287,16 @@
          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 sx = event.clientX;
            const sy = event.clientY;
            const oldZoom = pixiApp.stage.scale.x;
            const delta = event.deltaY;
            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
            );
            const worldX = (sx - pixiApp.stage.position.x) / oldZoom;
            const worldY = (sy - pixiApp.stage.position.y) / oldZoom;
            const newPosX = sx - worldX * newZoom;
            const newPosY = sy - worldY * newZoom;
            pixiApp.stage.setTransform(newPosX, newPosY, newZoom, newZoom, 0, 0, 0, 0, 0);
          });
          //*******************缩放画布*******************
@@ -351,114 +314,251 @@
        },
        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]
          pixiStageList = [map.length]//初始化列表
          pixiStaMap = new Map();//重置
          objectsContainer.removeChildren()
                // 跳过合并单元格的占位符
                if (val.type === 'merge') {
                  continue;
                }
                if (val.type == undefined || val.type === 'none') {
                  continue;
                }
                // 计算合并单元格的实际宽高
                let cellWidth = val.colSpan ? val.colSpan * width : width;
                let cellHeight = val.rowSpan ? val.rowSpan * height : height;
                let sprite = getSpriteWithSize(val.value, idx * width, index * height, cellWidth, cellHeight, val, (e) => {
                  // if (val.value == 4) {
                  //   //站点
                  //   this.openDrawerSta(val)
                  // } else if (val.value == 67) {
                  //   //提升机
                  //   this.openDrawerLift(val)
                  // } else {
                  //   //库位
                  //   this.rightEvent(index, idx, e);
                  //   updateColor(sprite, 0x9900ff);
                  // }
                });
                if (sprite == null) {
                  continue;
                }
                // 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中
                // }
                objectsContainer.addChild(sprite);
                pixiStageList[index][idx] = sprite
          let bayHeightList = this.initHeight(map);
          let bayWidthList = this.initWidth(map)
          map.forEach((item, index) => {
            for(let idx = 0;idx < item.length;idx++){
              let val = item[idx];
              if(val.cellHeight == undefined || val.cellHeight === ''){
                val.cellHeight = bayHeightList[index];
              }
            });
              if(val.cellWidth == undefined || val.cellWidth === ''){
                val.cellWidth = bayWidthList[idx];
              }
            }
          })
            //视角居中
            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 (!oldSprite) return; // 跳过不存在的元素
          map.forEach((item, index) => {
            for(let idx = 0;idx < item.length;idx++){
              let val = item[idx]
              let cellWidth = val.cellWidth / 40;
              let cellHeight = val.cellHeight / 8;
              //移除old元素
              objectsContainer.removeChild(oldSprite);
              val.width = cellWidth;
              val.height = cellHeight;
              // 计算合并单元格的实际宽高
              let cellWidth = item.colSpan ? item.colSpan * width : width;
              let cellHeight = item.rowSpan ? item.rowSpan * height : height;
              let mergeHeight = cellHeight;
              if(val.rowSpan  > 1) {
                for(let i = 1;i < val.rowSpan;i++){
                  let nextMerge = map[index + i][idx];
                  if(nextMerge.type != 'merge'){
                    continue;
                  }
                  let mergeCellHeight = nextMerge.cellHeight / 8;
                  mergeHeight += mergeCellHeight;
                }
                val.height = mergeHeight;
              }
              let sprite = getSpriteWithSize(item.data, item.y * width, item.x * height, cellWidth, cellHeight, item, (e) => {
                this.rightEvent(item.x, item.y, e);
                updateColor(sprite, 0x9900ff);
              });
              let mergeWidth = cellWidth;
              if(val.colSpan  > 1) {
                for(let i = 1;i < val.colSpan;i++){
                  let nextMerge = map[index][idx + i];
                  if (!nextMerge) { continue; }
                  let mergeCellWidth = nextMerge.cellWidth / 40;
                  mergeWidth += mergeCellWidth;
                  nextMerge.isMergedPart = true;
                }
                val.width = mergeWidth;
              }
            }
          })
              //添加元素
              objectsContainer.addChild(sprite);
              //保存新元素
              pixiStageList[item.x][item.y] = sprite
            });
          const rowHeightScaled = bayHeightList.map(h => (h != null && h !== -1) ? (h / 8) : (height));
          let yOffsets = [];
          let yCursor = 0;
          for (let r = 0; r < map.length; r++) {
            yOffsets[r] = yCursor;
            yCursor += (rowHeightScaled[r] || 0);
          }
          map.forEach((row, rowIndex) => {
            let xCursor = 0;
            let anchorX = 0;
            for (let colIndex = 0; colIndex < row.length; colIndex++) {
              let val = row[colIndex];
              let cellWidth = val.width;
              let cellHeight = val.height;
              if (val.isMergedPart) {
                val.posX = anchorX;
                val.posY = yOffsets[rowIndex];
                continue;
              }
              val.posX = xCursor;
              val.posY = yOffsets[rowIndex];
              anchorX = xCursor;
              if (val.colSpan > 1) {
                for (let i = 1; i < val.colSpan; i++) {
                  const next = row[colIndex + i];
                  if (!next) { break; }
                  next.posX = anchorX;
                  next.posY = yOffsets[rowIndex];
                }
              }
              xCursor += cellWidth;
            }
          })
          map.forEach((item, index) => {
            pixiStageList[index] = [item.length]
            for (let idx = 0; idx < item.length; idx++) {
              let val = item[idx]
              // 跳过合并单元格的占位符
              if (val.type === 'merge') {
                continue;
              }
              if (val.type == undefined || val.type === 'none') {
                continue;
              }
              let sprite = getSprite(val, (e) => {
                // if (val.value == 4) {
                //   //站点
                //   this.openDrawerSta(val)
                // } else {
                //   //库位
                //   this.rightEvent(index, idx, e);
                //   updateColor(sprite, 0x9900ff);
                // }
              });
              if (sprite == null) {
                continue;
              }
              objectsContainer.addChild(sprite);
              pixiStageList[index][idx] = sprite
            }
          });
          crnList.forEach((item) => {
            if(graphicsCrn == null) {
              graphicsCrn = createCrnTexture(item.width * 0.9,item.height * 0.9);
            }
            let sprite = new PIXI.Sprite(graphicsCrn);
            const deviceNo = getDeviceNo(item.value);
            const taskNo = getTaskNo(item.value);
            const style = new PIXI.TextStyle({ fontFamily: 'Arial', fontSize: 12, fill: '#ffffff', stroke: '#000000', strokeThickness: 2 });
            const txt = taskNo > 0 ? (deviceNo + "(" + taskNo + ")") : String(deviceNo);
            const text = new PIXI.Text(txt, style);
            text.anchor.set(0.5);
            text.position.set(sprite.width / 2, sprite.height / 2);
            sprite.addChild(text);
            sprite.textObj = text;
            sprite.zIndex = 1;
            sprite.position.set(item.posX, item.posY);
            sprite.interactive = true; // 必须要设置才能接收事件
            sprite.buttonMode = true; // 让光标在hover时变为手型指针
            let rowIndexForCrn = 0;
            for (let r = 0; r < map.length; r++) {
              if (map[r].length > 0) {
                const rowY = map[r][0].posY;
                if (Math.abs(rowY - item.posY) < 0.5) {
                  rowIndexForCrn = r;
                  break;
                }
              }
            }
            sprite.rowIndex = rowIndexForCrn;
            pixiCrnMap.set(parseInt(deviceNo), sprite);
            objectsContainer2.addChild(sprite);
          })
          rgvList.forEach((item) => {
            if(graphicsRgv == null) {
              graphicsRgv = createRgvTexture(item.width * 0.9,item.height * 0.9);
            }
            let sprite = new PIXI.Sprite(graphicsRgv);
            const deviceNo = getDeviceNo(item.value);
            const taskNo = getTaskNo(item.value);
            const style = new PIXI.TextStyle({ fontFamily: 'Arial', fontSize: 12, fill: '#ffffff', stroke: '#000000', strokeThickness: 2 });
            const txt = taskNo > 0 ? (deviceNo + "(" + taskNo + ")") : String(deviceNo);
            const text = new PIXI.Text(txt, style);
            text.anchor.set(0.5);
            text.position.set(sprite.width / 2, sprite.height / 2);
            sprite.addChild(text);
            sprite.textObj = text;
            sprite.zIndex = 1;
            sprite.position.set(item.posX, item.posY);
            sprite.interactive = true; // 必须要设置才能接收事件
            sprite.buttonMode = true; // 让光标在hover时变为手型指针
            pixiRgvMap.set(parseInt(deviceNo), sprite);
            objectsContainer2.addChild(sprite);
          })
          const b1 = objectsContainer.getLocalBounds();
          const b2 = objectsContainer2.getLocalBounds();
          const minX = Math.min(b1.x, b2.x);
          const minY = Math.min(b1.y, b2.y);
          const maxX = Math.max(b1.x + b1.width, b2.x + b2.width);
          const maxY = Math.max(b1.y + b1.height, b2.y + b2.height);
          const contentW = Math.max(0, maxX - minX);
          const contentH = Math.max(0, maxY - minY);
          const vw = pixiApp.view.width;
          const vh = pixiApp.view.height;
          let scale = Math.min(vw / contentW, vh / contentH) * 0.95;
          if (!isFinite(scale) || scale <= 0) { scale = 1; }
          const posX = (vw - contentW * scale) / 2 - minX * scale;
          const posY = (vh - contentH * scale) / 2 - minY * scale;
          pixiApp.stage.setTransform(posX, posY, scale, scale, 0, 0, 0, 0, 0);
          this.map = map;
        },
        initWidth(map) {
          let maxRow = map.length;
          let maxBay = map[0].length;
          let bayWidthList = [];
          for(let bay = 0;bay < maxBay;bay++){
            let bayWidth = -1;
            for(let row = 0;row < maxRow;row++){
              let val = map[row][bay];
              if (val.cellWidth == undefined || val.cellWidth === '') {
                continue;
              }
              bayWidth = Math.max(bayWidth, val.cellWidth);
              break;
            }
            bayWidthList.push(bayWidth);
          }
          return bayWidthList;
        },
        initHeight(map) {
          let maxRow = map.length;
          let maxBay = map[0].length;
          let bayHeightList = [];
          for(let row = 0;row < maxRow;row++){
            let bayHeight = -1;
            for(let bay = 0;bay < maxBay;bay++){
              let val = map[row][bay];
              if (val.cellHeight == undefined || val.cellHeight === '') {
                continue;
              }
              bayHeight = Math.max(bayHeight, val.cellHeight);
              break;
            }
            bayHeightList.push(bayHeight);
          }
          return bayHeightList;
        },
        rightEvent(x, y, e) {
          this.drawerLocNo = true
@@ -466,104 +566,6 @@
            x: x, y: y, z: this.currentLev, locNo: this.map[x][y].locNo,
            locSts: this.map[x][y].locSts, row: this.map[x][y].row, bay: this.map[x][y].bay, lev: this.currentLev
          };
        },
        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,
                  locSts: val.locSts
                })
              }
            })
          })
          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");
@@ -595,118 +597,49 @@
            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);
          let sites = Array.isArray(res) ? res : (res && res.code === 200 ? res.data : null);
          if (res && !Array.isArray(res)) {
            if (res.code === 403) { parent.location.href = baseUrl + "/login"; return; }
            if (res.code !== 200) { console.log(res.msg); return; }
          }
          if (!sites) { return; }
          this.currentLevStaList = sites;
          sites.forEach((item) => {
            let id = item.siteId != null ? item.siteId : item.stationId;
            let status = item.siteStatus != null ? item.siteStatus : item.stationStatus;
            let workNo = item.workNo != null ? item.workNo : item.taskNo;
            if (id == null) { return; }
            let sta = pixiStaMap.get(parseInt(id));
            if (sta == undefined) { return; }
            if (workNo != null && workNo > 0) {
              sta.textObj.text = id + "(" + workNo + ")";
            } else {
              sta.textObj.text = String(id);
            }
            if (sta.statusObj) {
              objectsContainer.removeChild(sta.statusObj);
              sta.statusObj = null;
              if (sta.textObj.parent !== sta) {
                sta.addChild(sta.textObj);
                sta.textObj.position.set(sta.width / 2, sta.height / 2);
              }
            }
            if (status === "site-auto") {
              updateColor(sta, 0x78ff81);
            } else if (status === "site-auto-run" || status === "site-auto-run-id") {
              updateColor(sta, 0xfa51f6);
            } else if (status === "site-unauto") {
              updateColor(sta, 0xb8b8b8);
            } else if (status === "machine-pakin") {
              updateColor(sta, 0x30bffc);
            } else if (status === "machine-pakout") {
              updateColor(sta, 0x97b400);
            } else {
              updateColor(sta, 0xb8b8b8);
            }
          });
        },
        openDrawerSta(data) {
          let that = this
@@ -729,111 +662,204 @@
            }
          })
        },
        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
          }
        },
        addMoveAdvancePath(moveAdvancePath, shuttleNo) {//添加预计路径
          let that = this;
          moveAdvancePath.forEach((path, idx) => {
            let locNo = this.map[path.x, path.y];
            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
              })
        getCrnInfo() {
          let that = this
          //获取堆垛机数据
          $.ajax({
            url: baseUrl + "/console/latest/data/crn",
            headers: {'token': localStorage.getItem('token')},
            method: 'POST',
            success: function (res) {
              if (res.code === 200) {
                var crns = res.data;
                for (var i = 0; i < crns.length; i++) {
                  const id = parseInt(crns[i].crnId);
                  const sprite = pixiCrnMap.get(id);
                  if (!sprite) { continue; }
              if (pixiShuttleMoveAdvancePathList[shuttleNo] == null) {
                let locNos = new Set()
                locNos.add(locNo);
                pixiShuttleMoveAdvancePathList[shuttleNo] = locNos;
                  const taskNo = crns[i].taskNo;
                  if (taskNo != null && taskNo > 0) {
                    sprite.textObj.text = id + "(" + taskNo + ")";
                  } else {
                    sprite.textObj.text = String(id);
                  }
                  const status = crns[i].crnStatus;
                  const statusColor = getCrnStatusColor(status);
                  updateCrnTextureColor(sprite, statusColor);
                  let bay = parseInt(crns[i].bay, 10);
                  if (isNaN(bay) || bay < 1 || bay === -2) {
                    bay = 1;
                  }
                  let rowIndex = (sprite.rowIndex != null) ? sprite.rowIndex : -1;
                  if (rowIndex === -1) {
                    for (let r = 0; r < that.map.length; r++) {
                      if (that.map[r].length > 0) {
                        const rowY = that.map[r][0].posY;
                        if (Math.abs(rowY - sprite.y) < 0.5) {
                          rowIndex = r;
                          break;
                        }
                      }
                    }
                    if (rowIndex === -1) { rowIndex = 0; }
                  }
                  let targetCell = null;
                  let crnCount = 0;
                  for (let c = 0; c < that.map[rowIndex].length; c++) {
                    const cell = that.map[rowIndex][c];
                    if (cell && cell.type === 'crn') {
                      crnCount++;
                      if (crnCount === bay) {
                        targetCell = cell;
                        break;
                      }
                    }
                  }
                  if (!targetCell) {
                    for (let c = that.map[rowIndex].length - 1; c >= 0; c--) {
                      const cell = that.map[rowIndex][c];
                      if (cell && cell.type === 'crn') {
                        targetCell = cell;
                        break;
                      }
                    }
                  }
                  if (!targetCell) { continue; }
                  const targetX = targetCell.posX + (targetCell.width - sprite.width) / 2;
                  gsap.killTweensOf(sprite);
                  gsap.to(sprite, { x: targetX, duration: 0.5, ease: "power1.inOut" });
                }
              } else if (res.code === 403) {
                parent.location.href = baseUrl + "/login";
              } 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);
                console.log(res.msg);
              }
            }
          });
        },
        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);
                  }
                });
        getSiteInfo() {
          let that = this;
          $.ajax({
            url: baseUrl + "/console/latest/data/station",
            headers: {'token': localStorage.getItem('token')},
            method: 'POST',
            success: function (res) {
              that.setSiteInfo(res);
            }
          });
        },
        getRgvInfo() {
          let that = this
          //获取RGV数据
          $.ajax({
            url: baseUrl + "/console/latest/data/rgv",
            headers: {'token': localStorage.getItem('token')},
            method: 'POST',
            success: function (res) {
              if (res.code === 200) {
                const rgvs = res.data;
                for (let i = 0; i < rgvs.length; i++) {
                  const id = parseInt(rgvs[i].rgvNo, 10);
                  const sprite = pixiRgvMap.get(id);
                  if (!sprite) { continue; }
                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);
                  const taskNo = rgvs[i].taskNo;
                  if (sprite.textObj) {
                    if (taskNo != null && taskNo > 0) {
                      sprite.textObj.text = id + "(" + taskNo + ")";
                    } else {
                      sprite.textObj.text = String(id);
                    }
                  }
                  const statusColor = getRgvStatusColor(rgvs[i].rgvStatus);
                  updateRgvTextureColor(sprite, statusColor);
                  let trackSiteNo = parseInt(rgvs[i].trackSiteNo, 10);
                  if (!trackSiteNo || trackSiteNo <= 0) { continue; }
                  let rowIndex = -1;
                  for (let r = 0; r < that.map.length; r++) {
                    if (that.map[r].length > 0) {
                      const rowY = that.map[r][0].posY;
                      if (Math.abs(rowY - sprite.y) < 0.5) {
                        rowIndex = r;
                        break;
                      }
                    }
                  }
                  if (rowIndex === -1) { rowIndex = 0; }
                  let targetCell = null;
                  for (let c = 0; c < that.map[rowIndex].length; c++) {
                    const cell = that.map[rowIndex][c];
                    if (!cell || cell.type !== 'rgv') { continue; }
                    const ts = getTrackSiteNo(cell.value);
                    if (ts === trackSiteNo) {
                      targetCell = cell;
                      break;
                    }
                  }
                  if (!targetCell) {
                    for (let c = that.map[rowIndex].length - 1; c >= 0; c--) {
                      const cell = that.map[rowIndex][c];
                      if (cell && cell.type === 'rgv') {
                        targetCell = cell;
                        break;
                      }
                    }
                  }
                  if (!targetCell) { continue; }
                  const targetX = targetCell.posX + (targetCell.width - sprite.width) / 2;
                  gsap.killTweensOf(sprite);
                  gsap.to(sprite, { x: targetX, duration: 0.5, ease: "power1.inOut" });
                }
              } else if (res.code === 403) {
                parent.location.href = baseUrl + "/login";
              } else {
                console.log(res.msg);
              }
            })
          }
            }
          });
        },
      }
    })
    function getContainer(type) {
    function createShelfSprite(width, height) {
      let idx = width + "-" + height;
      let texture = pixiShelfMap.get(idx);
      if (texture == undefined) {
        let graphics = getContainer('shelf', width, height);
        texture = pixiApp.renderer.generateTexture(graphics);
        pixiShelfMap.set(idx, texture);
      }
      return new PIXI.Sprite(texture);
    }
    function createTrackSprite(width, height) {
      let idx = width + "-" + height;
      let texture = pixiTrackMap.get(idx);
      if (texture == undefined) {
        texture = createTrackTexture(width, height);
        pixiTrackMap.set(idx, texture);
      }
      return new PIXI.Sprite(texture);
    }
    function getContainer(type, width, height) {
      let graphics = new PIXI.Graphics();
      let drawBorder = true;
      if (type == 'shelf') {
        graphics.beginFill(0x55aaff);
        graphics.beginFill(0xb6e2e2);
      } else if (type == 'devp') {
        graphics.beginFill(0xffff00);
        graphics.beginFill(0x00ff7f);
        graphics.visible = true;
      } else if (type == 'crn') {
        graphics.beginFill(0xaaffff);
@@ -847,7 +873,7 @@
      return graphics;
    }
    function createTrackTexture() {
    function createTrackTexture(width, height) {
      const g = new PIXI.Graphics();
      const t = Math.max(2, Math.round(height * 0.08));
      const gap = Math.round(height * 0.30);
@@ -874,33 +900,179 @@
      return rt;
    }
    function getContainerWithSize(value, w, h) {
      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);
      } else if (value === 1000) {//满库位
        graphics.beginFill(0xf83333);
      }
      graphics.lineStyle(1, 0xffffff, 1);
      graphics.drawRect(0, 0, w, h);
      graphics.endFill();
    function createCrnTexture(width, height) {
      const g = new PIXI.Graphics();
      const yTop = Math.round(height * 0.1);
      let deviceWidth  = width * 2;
      return graphics;
      g.beginFill(0x999999);
      g.drawRect(2, yTop, 3, height - yTop - 2);
      g.drawRect(deviceWidth - 5, yTop, 3, height - yTop - 2);
      g.endFill();
      g.beginFill(0x999999);
      g.drawRect(0, yTop, deviceWidth, 3);
      g.endFill();
      const cabW = Math.round(deviceWidth * 0.68);
      const cabH = Math.round(height * 0.38);
      const cabX = Math.round((deviceWidth - cabW) / 2);
      const cabY = Math.round(height * 0.52 - cabH / 2);
      g.beginFill(0x245a9a);
      g.drawRect(cabX, cabY, cabW, cabH);
      g.endFill();
      const winW = Math.round(cabW * 0.6);
      const winH = Math.round(cabH * 0.45);
      const winX = cabX + Math.round((cabW - winW) / 2);
      const winY = cabY + Math.round((cabH - winH) / 2);
      g.beginFill(0xd0e8ff);
      g.drawRect(winX, winY, winW, winH);
      g.endFill();
      const forkW = Math.round(deviceWidth * 0.8);
      const forkH = Math.max(2, Math.round(height * 0.08));
      const forkX = Math.round((deviceWidth - forkW) / 2);
      const forkY = cabY + cabH;
      g.beginFill(0x666666);
      g.drawRect(forkX, forkY, forkW, forkH);
      g.endFill();
      const rt = PIXI.RenderTexture.create({ width: deviceWidth, height: height });
      pixiApp.renderer.render(g, rt);
      return rt;
    }
    function createCrnTextureColoredDevice(deviceWidth, height, color) {
      const g = new PIXI.Graphics();
      const yTop = Math.round(height * 0.1);
      g.beginFill(0x999999);
      g.drawRect(2, yTop, 3, height - yTop - 2);
      g.drawRect(deviceWidth - 5, yTop, 3, height - yTop - 2);
      g.endFill();
      g.beginFill(0x999999);
      g.drawRect(0, yTop, deviceWidth, 3);
      g.endFill();
      const cabW = Math.round(deviceWidth * 0.68);
      const cabH = Math.round(height * 0.38);
      const cabX = Math.round((deviceWidth - cabW) / 2);
      const cabY = Math.round(height * 0.52 - cabH / 2);
      g.beginFill(color);
      g.drawRect(cabX, cabY, cabW, cabH);
      g.endFill();
      const winW = Math.round(cabW * 0.6);
      const winH = Math.round(cabH * 0.45);
      const winX = cabX + Math.round((cabW - winW) / 2);
      const winY = cabY + Math.round((cabH - winH) / 2);
      g.beginFill(0xd0e8ff);
      g.drawRect(winX, winY, winW, winH);
      g.endFill();
      const forkW = Math.round(deviceWidth * 0.8);
      const forkH = Math.max(2, Math.round(height * 0.08));
      const forkX = Math.round((deviceWidth - forkW) / 2);
      const forkY = cabY + cabH;
      g.beginFill(0x666666);
      g.drawRect(forkX, forkY, forkW, forkH);
      g.endFill();
      const rt = PIXI.RenderTexture.create({ width: deviceWidth, height: height });
      pixiApp.renderer.render(g, rt);
      return rt;
    }
    function createDevpTextureColoredRect(width, height, color) {
      const g = new PIXI.Graphics();
      g.beginFill(color);
      g.lineStyle(1, 0xffffff, 1);
      g.drawRect(0, 0, width, height);
      g.endFill();
      const rt = PIXI.RenderTexture.create({ width: width, height: height });
      pixiApp.renderer.render(g, rt);
      return rt;
    }
    function createRgvTexture(width, height) {
      const g = new PIXI.Graphics();
      const bodyW = Math.round(width * 0.8);
      const bodyH = Math.round(height * 0.55);
      const bodyX = Math.round((width - bodyW) / 2);
      const bodyY = Math.round((height - bodyH) / 2);
      g.beginFill(0x245a9a);
      g.drawRect(bodyX, bodyY, bodyW, bodyH);
      g.endFill();
      const winW = Math.round(bodyW * 0.55);
      const winH = Math.round(bodyH * 0.45);
      const winX = bodyX + Math.round((bodyW - winW) / 2);
      const winY = bodyY + Math.round((bodyH - winH) / 2);
      g.beginFill(0xd0e8ff);
      g.drawRect(winX, winY, winW, winH);
      g.endFill();
      const wheelW = Math.max(2, Math.round(width * 0.12));
      const wheelH = Math.max(2, Math.round(height * 0.1));
      const wheelY = bodyY + bodyH;
      const wheelGap = Math.round((width - wheelW * 2) / 3);
      const wheelX1 = wheelGap;
      const wheelX2 = width - wheelGap - wheelW;
      g.beginFill(0x333333);
      g.drawRect(wheelX1, wheelY - Math.round(wheelH / 2), wheelW, wheelH);
      g.drawRect(wheelX2, wheelY - Math.round(wheelH / 2), wheelW, wheelH);
      g.endFill();
      const rt = PIXI.RenderTexture.create({ width: width, height: height });
      pixiApp.renderer.render(g, rt);
      return rt;
    }
    function createRgvTextureColoredDevice(width, height, color) {
      const g = new PIXI.Graphics();
      const bodyW = Math.round(width * 0.8);
      const bodyH = Math.round(height * 0.55);
      const bodyX = Math.round((width - bodyW) / 2);
      const bodyY = Math.round((height - bodyH) / 2);
      g.beginFill(color);
      g.drawRect(bodyX, bodyY, bodyW, bodyH);
      g.endFill();
      const winW = Math.round(bodyW * 0.55);
      const winH = Math.round(bodyH * 0.45);
      const winX = bodyX + Math.round((bodyW - winW) / 2);
      const winY = bodyY + Math.round((bodyH - winH) / 2);
      g.beginFill(0xd0e8ff);
      g.drawRect(winX, winY, winW, winH);
      g.endFill();
      const wheelW = Math.max(2, Math.round(width * 0.12));
      const wheelH = Math.max(2, Math.round(height * 0.1));
      const wheelY = bodyY + bodyH;
      const wheelGap = Math.round((width - wheelW * 2) / 3);
      const wheelX1 = wheelGap;
      const wheelX2 = width - wheelGap - wheelW;
      g.beginFill(0x333333);
      g.drawRect(wheelX1, wheelY - Math.round(wheelH / 2), wheelW, wheelH);
      g.drawRect(wheelX2, wheelY - Math.round(wheelH / 2), wheelW, wheelH);
      g.endFill();
      const rt = PIXI.RenderTexture.create({ width: width, height: height });
      pixiApp.renderer.render(g, rt);
      return rt;
    }
    function updateRgvTextureColor(sprite, color) {
      const tex = createRgvTextureColoredDevice(sprite.width, sprite.height, color);
      sprite.texture = tex;
    }
    function updateCrnTextureColor(sprite, color) {
      const tex = createCrnTextureColoredDevice(sprite.width, sprite.height, color);
      sprite.texture = tex;
    }
    function getCrnStatusColor(status) {
      if (status === "machine-auto") { return 0x21BA45; }
      if (status === "machine-un-auto") { return 0xBBBBBB; }
      if (status === "machine-error") { return 0xDB2828; }
      if (status === "machine-pakin") { return 0x30bffc; }
      if (status === "machine-pakout") { return 0x97b400; }
      return 0xBBBBBB;
    }
    function getRgvStatusColor(status) {
      if (status === "idle") { return 0x21BA45; }
      if (status === "working") { return 0xffd60b; }
      if (status === "waiting") { return 0xffd60b; }
      if (status === "fetching") { return 0xffd60b; }
      if (status === "putting") { return 0xffd60b; }
      return 0xb8b8b8;
    }
    function getGraphics(color, width, height, x, y) {
@@ -913,51 +1085,50 @@
      return graphics;
    }
    function getSprite(value, x, y, item, pointerDownEvent) {
    function getSprite(item, pointerDownEvent) {
      let sprite;
      console.log(item.type);
      let value = item.value;
      if (item.type == 'shelf') {
        sprite = new PIXI.Sprite(graphicsShelf);
        sprite = createShelfSprite(item.width, item.height);
      } else if (item.type == 'devp') {
        sprite = new PIXI.Sprite(graphicsDevp);
      } else if (item.type == 'crn') {
        if (getDeviceNo(value) == -1) {
          sprite = new PIXI.Sprite(graphicsCrnTrack);
        } else {
          sprite = new PIXI.Sprite(graphicsCrn);
        const graphics = getContainer('devp', item.width, item.height);
        const texture = pixiApp.renderer.generateTexture(graphics);
        sprite = new PIXI.Sprite(texture);
        sprite._kind = 'devp';
        let siteId = getStationId(value);
        if (siteId === -1) {
          siteId = item.data;
        }
      } else if (item.type == 'crnTrack') {
        sprite = new PIXI.Sprite(graphicsCrnTrack);
        const style = new PIXI.TextStyle({ fontFamily: 'Arial', fontSize: 10, fill: '#ffffff', stroke: '#000000', strokeThickness: 2 });
        const text = new PIXI.Text(String(siteId), style);
        text.anchor.set(0.5);
        text.position.set(sprite.width / 2, sprite.height / 2);
        sprite.addChild(text);
        sprite.textObj = text;
        if (siteId != null && siteId !== -1) {
          pixiStaMap.set(parseInt(siteId), sprite);
        }
      } else if (item.type == 'crn') {
        sprite = createTrackSprite(item.width, item.height);
        sprite.zIndex = 0;
        if(getDeviceNo(value) > 0){
          crnList.push(item);
        }
      } else if (item.type == 'rgv') {
        sprite = createTrackSprite(item.width, item.height);
        sprite.zIndex = 0;
        if(getDeviceNo(value) > 0){
          rgvList.push(item);
        }
      } else {
        return null;
      }
      sprite.position.set(x, y);
      sprite.position.set(item.posX, item.posY);
      sprite.interactive = true; // 必须要设置才能接收事件
      sprite.buttonMode = true; // 让光标在hover时变为手型指针
      sprite.on('pointerdown', (e) => {
        pointerDownEvent(e)
      })
      return sprite;
    }
    function getSpriteWithSize(value, x, y, w, h, item, pointerDownEvent) {
      let sprite;
      // 如果是标准尺寸,使用缓存的纹理
      if (w === width && h === height) {
        return getSprite(value, x, y, item, pointerDownEvent);
      }
      // 合并单元格需要动态创建纹理
      let graphics = getContainerWithSize(value, w, h);
      let texture = pixiApp.renderer.generateTexture(graphics);
      sprite = new PIXI.Sprite(texture);
      sprite.position.set(x, y);
      sprite.interactive = true;
      sprite.buttonMode = true;
      sprite.on('pointerdown', (e) => {
        pointerDownEvent(e)
@@ -970,9 +1141,21 @@
     * 更新颜色
     */
    function updateColor(sprite, color) {
      // graphics.clear()
      // graphics.beginFill(color);
      // graphics.drawRect(0, 0, width, height);
      if (sprite && sprite._kind === 'devp') {
        const key = sprite.width + '-' + sprite.height + '-' + color;
        let texture = pixiDevpTextureMap.get(key);
        if (!texture) {
          texture = createDevpTextureColoredRect(Math.round(sprite.width), Math.round(sprite.height), color);
          pixiDevpTextureMap.set(key, texture);
        }
        const textObj = sprite.textObj;
        sprite.texture = texture;
        if (textObj) {
          if (textObj.parent !== sprite) { sprite.addChild(textObj); }
          textObj.position.set(sprite.width / 2, sprite.height / 2);
        }
        return;
      }
      sprite.tint = color;
    }
@@ -985,17 +1168,29 @@
      }
    }
    function getDeviceNo(obj) {
      if (this.isJson(obj)) {
        let data = JSON.parse(obj)
        if (data.deviceNo == null || data.deviceNo == undefined) {
          return -1;
        }
        return data.deviceNo;
      } else {
  function getDeviceNo(obj) {
    if (this.isJson(obj)) {
      let data = JSON.parse(obj)
      if (data.deviceNo == null || data.deviceNo == undefined) {
        return -1;
      }
      return data.deviceNo;
    } else {
      return -1;
    }
  }
  function getTaskNo(obj) {
    if (this.isJson(obj)) {
      let data = JSON.parse(obj)
      if (data.taskNo == null || data.taskNo == undefined) {
        return -1;
      }
      return data.taskNo;
    } else {
      return -1;
    }
  }
    function getStationId(obj) {
      if (this.isJson(obj)) {