#
Junjie
5 天以前 195b15baf2d6d7cfdb0d928586602f8760863e04
src/main/webapp/views/watch/console2.html
@@ -1,5 +1,6 @@
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>库位地图</title>
@@ -16,933 +17,1025 @@
  <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 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>
    </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;">排:{{drawerLocNoData.row}}</div>
          <div style="margin-top: 5px;">列:{{drawerLocNoData.bay}}</div>
          <div style="margin-top: 5px;">层:{{drawerLocNoData.lev}}</div>
          <div style="margin-top: 5px;">库位号:{{drawerLocNoData.locNo}}</div>
          <div style="margin-top: 5px;">库位状态:{{drawerLocNoData.locSts}}</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>
  </div>
  <script>
    let pixiApp;
    let pixiStageList = [];
    let pixiShuttleMap = new Map();
    let pixiShuttleMoveAdvancePathMap = new Map();
    let pixiShuttleMoveAdvancePathList = [];
    let pixiStaMap = new Map();
    let pixiCrnMap = new Map();
    let pixiShelfMap = new Map();
    let pixiTrackMap = new Map();
    let pixiDevpTextureMap = new Map();
    let crnList = [];
    let objectsContainer;
    let objectsContainer2;
    let graphicsShelf;
    let graphicsDevp;
    let graphicsCrn;
    let graphicsCrnTrack;
    let ws;
  <!--输出操作和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>
  </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;">排:{{drawerLocNoData.row}}</div>
        <div style="margin-top: 5px;">列:{{drawerLocNoData.bay}}</div>
        <div style="margin-top: 5px;">层:{{drawerLocNoData.lev}}</div>
        <div style="margin-top: 5px;">库位号:{{drawerLocNoData.locNo}}</div>
        <div style="margin-top: 5px;">库位状态:{{drawerLocNoData.locSts}}</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: [], //当前项目楼层
      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) {
        }
    var app = new Vue({
      el: '#app',
      data: {
        map: [],
        currentLev: 1,
        floorList: [], //当前项目楼层
        drawer: false,
        drawerLocNo: false,
        drawerLocNoData: null,
        drawerLocDetls: [],
        mapFps: 0,
        currentLevStaList: [],//当前楼层站点list
        drawerSta: false,
        drawerStaData: null,
      },
      drawerLocNo: {
        deep: true,
        handler(val) {
          if (!val) {
            var sprite = pixiStageList[this.drawerLocNoData.x][this.drawerLocNoData.y];
            updateColor(sprite, 0xFFFFFF);//恢复颜色
      mounted() {
        this.init()
        this.createMap()
      },
      watch: {
        map: {
          deep: true,
          handler(val) {
          }
        }
      }
    },
    methods: {
      init(){
        let that = this
        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.initLev()//初始化楼层信息
        setTimeout(() => {
          that.getMap(this.currentLev)
        }, 1000);
        // this.consoleInterval = setInterval(() => {
        //   this.getMap(this.currentLev) //获取实时地图数据
        //   this.getShuttleStateInfo() //获取四向穿梭车信息
        //   this.getLiftStateInfo() //获取提升机信息
        //   this.getSiteInfo() //获取输送站点数据
        //   // this.getCodeData()//获取条码
        // }, 1000)
      },
      initLev(){
        let that = this
        $.ajax({
          url: baseUrl + "/console/map/lev/list",
          headers: {
            'token': localStorage.getItem('token')
          },
          data: {},
          method: 'get',
          success: function(res) {
            if (res.code === 200) {
              that.floorList = res.data;
            } else if (res.code === 403) {
              parent.location.href = baseUrl + "/login";
            } else {
              that.$message({
                message: res.msg,
                type: 'error'
              });
        },
        drawerLocNo: {
          deep: true,
          handler(val) {
            if (!val) {
              var sprite = pixiStageList[this.drawerLocNoData.x][this.drawerLocNoData.y];
              updateColor(sprite, 0xFFFFFF);//恢复颜色
            }
          }
        });
        }
      },
      //获取地图数据
      getMap(lev) {
        let that = this;
      methods: {
        init() {
          let that = this
          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.initLev()//初始化楼层信息
          setTimeout(() => {
            that.getMap(this.currentLev)
          }, 1000);
          this.consoleInterval = setInterval(() => {
            this.getCrnInfo() //获取堆垛机数据
            this.getSiteInfo() //获取输送站点数据
          }, 1000)
        },
        initLev() {
          let that = this
          $.ajax({
              url: baseUrl + "/console/map/" + lev + "/auth",
              headers: {
                  'token': localStorage.getItem('token')
              },
              data: {},
              method: 'get',
              success: function(res) {
                //获取地图数据
                let data = res.data
                that.createMapData(data)
            url: baseUrl + "/console/map/lev/list",
            headers: {
              'token': localStorage.getItem('token')
            },
            data: {},
            method: 'get',
            success: function (res) {
              if (res.code === 200) {
                that.floorList = res.data;
              } else if (res.code === 403) {
                parent.location.href = baseUrl + "/login";
              } else {
                that.$message({
                  message: res.msg,
                  type: 'error'
                });
              }
            }
          });
        },
        //获取地图数据
        getMap(lev) {
          let that = this;
          $.ajax({
            url: baseUrl + "/basMap/lev/" + this.currentLev + "/auth",
            headers: {
              'token': localStorage.getItem('token')
            },
            data: {},
            method: 'get',
            success: function (res) {
              //获取地图数据
              let data = res.data
              let mapData = JSON.parse(data)
              that.createMapData(mapData)
            }
          })
      },
      changeFloor(lev) {
        this.currentLev = lev
        this.currentLevShuttleList = []
        this.reloadMap = true
        this.reloadSta = true
        this.getMap(lev)
        },
        changeFloor(lev) {
          this.currentLev = lev
          this.currentLevShuttleList = []
          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)
        //清空预计路径
        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');
        //加载小车资源
        pixiApp.loader.add('shuttle', '../static/images/sxcar.png');
          // 从Graphics对象创建一个纹理
          // graphicsShelf = pixiApp.renderer.generateTexture(getContainer('shelf'));
          // graphicsDevp = pixiApp.renderer.generateTexture(getContainer('devp'));
          // graphicsCrn = createCrnTexture(40,40);
          graphicsCrnTrack = createTrackTexture(25,25);
        // 从Graphics对象创建一个纹理
          graphicsF = pixiApp.renderer.generateTexture(getContainer(1000));
        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);
        // 创建一个容器来管理大批量的显示对象
        objectsContainer = new PIXI.Container();
        pixiApp.stage.addChild(objectsContainer);
          // 创建一个容器来管理大批量的显示对象
          objectsContainer2 = new PIXI.Container();
          pixiApp.stage.addChild(objectsContainer2);
        // 创建一个容器来管理大批量的显示对象
        objectsContainer2 = new PIXI.Container();
        pixiApp.stage.addChild(objectsContainer2);
          pixiApp.stage.sortableChildren = true;
          objectsContainer.sortableChildren = true;
          objectsContainer2.sortableChildren = true;
          objectsContainer.zIndex = 10;
          objectsContainer2.zIndex = 20;
        // 创建一个容器来管理大批量的显示对象
        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
          //*******************拖动画布*******************
          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;
        //*******************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*******************
              if (touchBlank) {
                // 拖拽画布
                const dx = globalPos.x - mouseDownPoint[0];
                const dy = globalPos.y - mouseDownPoint[1];
                pixiApp.stage.position.set(
                  stageOriginalPos[0] + dx,
                  stageOriginalPos[1] + dy
                );
              }
            }
          );
      },
      createMapData(map) {
        if (this.reloadMap) {
          this.reloadMap = false
          pixiApp.renderer.plugins.interaction.on(
            'pointerup',
            (event) => {
              touchBlank = false;
            }
          );
          //*******************拖动画布*******************
          //*******************缩放画布*******************
          pixiApp.view.addEventListener('wheel', (event) => {
            event.stopPropagation();
            event.preventDefault();
            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 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);
          });
          //*******************缩放画布*******************
          //*******************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) {
          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 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];
              }
            }
          })
          map.forEach((item, index) => {
            for(let idx = 0;idx < item.length;idx++){
              let val = item[idx]
              if (val.value < 0 && (val.value != -999)) {
              let cellWidth = val.cellWidth / 40;
              let cellHeight = val.cellHeight / 8;
              val.width = cellWidth;
              val.height = cellHeight;
              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 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;
              }
            }
          })
          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;
              }
              let sprite = getSprite(val.value, idx * width, index * height, 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);
              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 (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 (sprite == null) {
                continue;
              }
              if (val.value == -999) {
                pixiShuttleLockPathMap.set(val.locNo, sprite);
                objectsContainer3.addChild(sprite);
              }else {
                objectsContainer.addChild(sprite);
              }
              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);
          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;
            let sprite = getSprite(item.data, item.y * width, item.x * height, item, (e) => {
              this.rightEvent(item.x, item.y, e);
              updateColor(sprite, 0x9900ff);
            });
            sprite.position.set(item.posX, item.posY);
            sprite.interactive = true; // 必须要设置才能接收事件
            sprite.buttonMode = true; // 让光标在hover时变为手型指针
            if (item.data == -999) {
              //添加路径元素
              objectsContainer3.addChild(sprite);
            }else {
              //添加元素
              objectsContainer.addChild(sprite);
            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;
            //保存新元素
            pixiStageList[item.x][item.y] = sprite
          });
        }
        this.map = map;
      },
      rightEvent(x, y, e) {
        this.drawerLocNo = true
        this.drawerLocNoData =  {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
              })
            }
            pixiCrnMap.set(parseInt(deviceNo), sprite);
            objectsContainer2.addChild(sprite);
          })
        })
        return diff;
      },
      findShuttleDiffList(list1, list2) {
        //检测集合1里面的小车是否在集合2中有变动
        if (list1.length == 0) {
          return false;//集合为空
        }
        if (list1.length != list2.length) {
          return false;//两个集合长度不一致
        }
          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);
        let flag = false;
        list1.forEach((item,index) => {
          for (var i = 0; i < list2.length; i++) {
            if (item.shuttleNo == list2[i].shuttleNo) {
              flag = true;
          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;
        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;//找不到小车号
          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;
            }
            if (item.moveAdvancePath == null) {
              item.moveAdvancePath = [];
            }
            if (list2[i].moveAdvancePath == null) {
              list2[i].moveAdvancePath = [];
            }
            if (!(item.moveAdvancePath.length == list2[i].moveAdvancePath.length)) {
              return false;//小车预计路径长度不一致
            }
            bayHeightList.push(bayHeight);
          }
        }
        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
          return bayHeightList;
        },
        rightEvent(x, y, e) {
          this.drawerLocNo = true
          this.drawerLocNoData = {
            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
          };
        },
        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/locMap/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)
          }
        },
        setSiteInfo(res) {
          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 (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/locMap/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;//动画执行完成
            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);
            }
          });
        }
      },
      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
        }
      },
      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
            })
            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);
        },
        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;
              }
            }
          })
        }
      },
    }
  })
        },
        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; }
  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);
    }else if (value === 1000) {//满库位
     graphics.beginFill(0xf83333);
   }
    graphics.lineStyle(1, 0xffffff, 1);
    graphics.drawRect(0, 0, width, height);
    graphics.endFill();
                  const taskNo = crns[i].taskNo;
                  if (taskNo != null && taskNo > 0) {
                    sprite.textObj.text = id + "(" + taskNo + ")";
                  } else {
                    sprite.textObj.text = String(id);
                  }
    return graphics;
  }
                  const status = crns[i].crnStatus;
                  const statusColor = getCrnStatusColor(status);
                  updateCrnTextureColor(sprite, statusColor);
  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;
  }
                  let bay = parseInt(crns[i].bay, 10);
                  if (isNaN(bay) || bay < 1 || bay === -2) {
                    bay = 1;
                  }
  function getSprite(value, x, y, item, pointerDownEvent) {
    let sprite;
    if (value == 0) {
      if(item.locSts == 'O') {
        sprite = new PIXI.Sprite(graphics0);
      }else if(item.locSts == 'F') {
        sprite = new PIXI.Sprite(graphicsF);
      }else {
        sprite = new PIXI.Sprite(graphics0);
                  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 {
                console.log(res.msg);
              }
            }
          });
        },
        getSiteInfo() {
          let that = this;
          $.ajax({
            url: baseUrl + "/console/latest/data/station",
            headers: {'token': localStorage.getItem('token')},
            method: 'POST',
            success: function (res) {
              that.setSiteInfo(res);
            }
          });
        },
      }
    } 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 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(0xb6e2e2);
      } else if (type == 'devp') {
        graphics.beginFill(0x00ff7f);
        graphics.visible = true;
      } else if (type == 'crn') {
        graphics.beginFill(0xaaffff);
      }
      if (drawBorder) {
        graphics.lineStyle(1, 0xffffff, 1);
        graphics.drawRect(0, 0, width, height);
      }
      graphics.endFill();
      return graphics;
    }
    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);
      const mid = Math.round(height / 2);
      const y1 = mid - Math.round(gap / 2);
      const y2 = mid + Math.round(gap / 2);
      const tHalf = Math.round(t / 2);
      const topRailTopY = y1 - tHalf;
      const bottomRailTopY = y2 - tHalf;
      g.beginFill(0x666666);
      g.drawRect(0, topRailTopY, width, t);
      g.drawRect(0, bottomRailTopY, width, t);
      g.endFill();
      g.beginFill(0x777777);
      const sTop = topRailTopY + t;
      const sBottom = bottomRailTopY;
      const sHeight = Math.max(1, sBottom - sTop);
      for (let i = 0; i < width; i += 5) {
        g.drawRect(i, sTop, 2, sHeight);
      }
      g.endFill();
      const rt = PIXI.RenderTexture.create({ width: width, height: height });
      pixiApp.renderer.render(g, rt);
      return rt;
    }
    function createCrnTexture(width, height) {
      const g = new PIXI.Graphics();
      const yTop = Math.round(height * 0.1);
      let deviceWidth  = width * 2;
      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 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 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(item, pointerDownEvent) {
      let sprite;
      let value = item.value;
      if (item.type == 'shelf') {
        sprite = createShelfSprite(item.width, item.height);
      } else if (item.type == 'devp') {
        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;
        }
        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 {
        return null;
      }
      sprite.position.set(item.posX, item.posY);
      sprite.interactive = true; // 必须要设置才能接收事件
      sprite.buttonMode = true; // 让光标在hover时变为手型指针
      sprite.on('pointerdown', (e) => {
        pointerDownEvent(e)
      })
      return sprite;
    }
    /**
     * 更新颜色
     */
    function updateColor(sprite, color) {
      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;
    }
    function isJson(str) {
      try {
        JSON.parse(str);
        return true;
      } catch (e) {
        return false;
      }
    }
  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 updateColor(sprite, color) {
    // graphics.clear()
    // graphics.beginFill(color);
    // graphics.drawRect(0, 0, width, height);
    sprite.tint = color;
  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;
    }
  }
</script>
    function getStationId(obj) {
      if (this.isJson(obj)) {
        let data = JSON.parse(obj)
        if (data.stationId == null || data.stationId == undefined) {
          return -1;
        }
        return data.stationId;
      } else {
        return -1;
      }
    }
    function getTrackSiteNo(obj) {
      if (this.isJson(obj)) {
        let data = JSON.parse(obj)
        if (data.trackSiteNo == null || data.trackSiteNo == undefined) {
          return -1;
        }
        return data.trackSiteNo;
      } else {
        return -1;
      }
    }
  </script>
</body>
</html>
</html>