#
Junjie
2025-11-27 9e715c16b49a066e627d150fb2d973a8562db8dc
src/main/webapp/views/watch/console.html
@@ -24,13 +24,22 @@
                  <el-tab-pane label="输送站" name="devp">
                     <devp-card :param="devpParam"></devp-card>
                  </el-tab-pane>
                  <el-tab-pane label="RGV" name="rgv">RGV</el-tab-pane>
                  <el-tab-pane label="RGV" name="rgv">
                     <watch-rgv-card :param="rgvParam"></watch-rgv-card>
                  </el-tab-pane>
                  <el-tab-pane label="地图配置" name="mapSetting">
                     <map-setting-card :param="mapSettingParam"></map-setting-card>
                  </el-tab-pane>
               </el-tabs>
            </div>
            <div id="mapDataId" style="position: relative;" :style="{zoom: mapSettingParam.zoom / 100}">
            <div style="position: absolute;top: 15px;left: 50%;display: flex;">
               <div v-if="levList.length > 1" v-for="(lev,index) in levList" :key="index" style="margin-right: 10px;">
                  <el-button :type="currentLev == lev ? 'primary' : ''" @click="switchLev(lev)" size="mini">{{ lev }}F</el-button>
               </div>
            </div>
            <div id="mapDataId" style="position: relative;margin-top: 50px;" :style="{zoom: mapSettingParam.zoom / 100}">
               <table class="excel-table">
                  <tr v-for="(row,index) in map" :key="index">
                     <td
@@ -56,15 +65,11 @@
                        </div>
                        <div v-else-if="col.type == 'crn'">
                           <div class="crn-item" v-if="getDeviceNo(col.value) != -1" :style="{width: col.width}" :id="'crn-' + getDeviceNo(col.value)" @click="openCrn(getDeviceNo(col.value))">{{getDeviceNo(col.value)}}</div>
                           <div class="track-item" v-if="getTrackSiteNo(col.value) == -1"></div>
                           <div class="track-item" v-else :id="'crnTrackSiteNo-' + getTrackSiteNo(col.value)"></div>
                           <div class="track-item track-crn" v-if="getTrackSiteNo(col.value) == -1"></div>
                           <div class="track-item track-crn" v-else :id="'crnTrackSiteNo-' + getTrackSiteNo(col.value)"></div>
                        </div>
                     </td>
<!--                     <td>-->
<!--                        &lt;!&ndash; 显示行号 &ndash;&gt;-->
<!--                        <div class="item" style="background: none;color: #000;">#{{index+1}}</div>-->
<!--                     </td>-->
                  </tr>
               </table>
            </div>
@@ -75,15 +80,16 @@
      <script src="../../components/WatchCrnCard.js"></script>
      <script src="../../components/DevpCard.js"></script>
      <script src="../../components/MapSettingCard.js"></script>
      <script src="../../components/WatchRgvCard.js"></script>
      <script>
         var app = new Vue({
            el: '#app',
            data: {
               map: [],//地图数据
               crnList: [], //堆垛机集合
               levList: [],
               currentLev: 1,
               systemStatus: true,//系统运行状态
               consoleInterval: null,//定时器存储变量
               crnInitPosition: [],
               rgvPosition: [],
               activateCard: 'crn',
               crnParam: {
@@ -94,6 +100,9 @@
               },
               devpParam: {
                  stationId: 0
               },
               rgvParam: {
                  rgvNo: 0
               }
            },
            created() {
@@ -106,6 +115,7 @@
               init() {
                  this.getMap()
                  this.getSystemRunningStatus() //获取系统运行状态
                  this.getLevList() //获取地图层级列表
                  this.consoleInterval = setInterval(() => {
                     this.getCrnInfo() //获取堆垛机数据
@@ -113,13 +123,28 @@
                     this.getRgvInfo() //获取RGV数据
                  }, 1000)
               },
               getLevList() {
                  let that = this;
                  $.ajax({
                     url: baseUrl + "/basMap/getLevList",
                     headers: {
                        'token': localStorage.getItem('token')
                     },
                     method: "get",
                     success: (res) => {
                        let data = res.data;
                        that.levList = data;
                     }
                  })
               },
               //获取地图数据
               getMap() {
                  let that = this
                  let rowPx = 35;
                  let colPx = 35;
                  $.ajax({
                     url: baseUrl + "/basMap/lev/1/auth",
                     url: baseUrl + "/basMap/lev/" + this.currentLev + "/auth",
                     headers: {
                        'token': localStorage.getItem('token')
                     },
@@ -141,39 +166,21 @@
                              col.width = (col.cellWidth / 30) + "px";
                           })
                        })
                        this.map = mapData;
                        that.map = mapData;
                     }
                  })
               },
               switchLev(lev) {
                  this.currentLev = lev;
                  this.getMap()
               },
               openCrn(id) {
                  this.crnParam.crnNo = id;
                  this.activateCard = 'crn';
               },
               openRgv(id) {
                  this.rgvWindow = true; //打开RGV信息弹窗
                  $(".detailed").empty();
                  $('.detailed').append(id + '号RGV');
                  $.ajax({
                     url: baseUrl + "/console/rgv/detail",
                     headers: {
                        'token': localStorage.getItem('token')
                     },
                     data: {
                        rgvNo: id
                     },
                     method: 'post',
                     success: function(res) {
                        for (var val in res.data) {
                           var find = $("#rgvWindow").find(":input[name='" + val + "']");
                           if (find[0].type === 'text') {
                              find.val(res.data[val]);
                           } else if (find[0].type === 'checkbox') {
                              find.attr("checked", res.data[val] === 'Y');
                           }
                        }
                     }
                  })
                  this.rgvParam.rgvNo = id;
                  this.activateCard = 'rgv';
               },
               openSite(id) {
                  this.devpParam.stationId = id;
@@ -216,40 +223,39 @@
                        if (res.code === 200) {
                           var crns = res.data;
                           if (that.crnInitPosition.length == 0) {
                              let position = []
                              for (var i = 0; i < crns.length; i++) {
                                 var crnEl = $("#crn-" + crns[i].crnId);
                                 position.push({
                                    id: crns[i].crnId,
                                    left: crnEl.offset().left + crnEl.width()
                                 })
                              }
                              that.crnInitPosition = position
                              return;
                           }
                           let crnList = []
                           for (var i = 0; i < crns.length; i++) {
                              var crnEl = $("#crn-" + crns[i].crnId);
                              crnEl.attr("class", "crn-item " + crns[i].crnStatus);
                              if (crns[i].bay < 0 || crns[i].bay === -2) {
                                 crns[i].bay = 1
                              let bay = parseInt(crns[i].bay, 10);
                              if (isNaN(bay) || bay < 1 || bay === -2) {
                                 bay = 1;
                              }
                              let basePosition = 0;
                              that.crnInitPosition.forEach((item) => {
                                 if (item.id == crns[i].crnId) {
                                    basePosition = item.left
                                 }
                              })
                              var offSet = crns[i].offset;
                              let finalOffset = basePosition + offSet;
                              if (finalOffset < basePosition) {
                                 finalOffset = basePosition;
                              // 根据列值定位到当前行的目标单元格,避免随机偏移导致的误差
                              let targetCell = that.getCrnTargetCell(crnEl, bay);
                              if (!targetCell || targetCell.length === 0) {
                                 continue;
                              }
                              if (targetCell.offset() == undefined) {
                                 continue;
                              }
                              if (crnEl.offsetParent().offset() == undefined) {
                                 continue;
                              }
                              let parentLeft = crnEl.offsetParent().offset().left;
                              let cellLeft = targetCell.offset().left - parentLeft;
                              let offsetWithinCell = (targetCell.outerWidth() - crnEl.outerWidth()) / 2;
                              let zoomFactor = that.mapSettingParam.zoom ? (that.mapSettingParam.zoom / 100) : 1;
                              if (zoomFactor <= 0) { zoomFactor = 1; }
                              let finalOffset = (cellLeft + offsetWithinCell) / zoomFactor;
                              if(finalOffset < 0) {
                                 finalOffset = 0;
                              }
                              crnEl.animate({left: finalOffset + 'px'}, 1000);
                              crnList.push({
@@ -257,8 +263,6 @@
                                 crnStatus: crns[i].crnStatus
                              })
                           }
                           that.crnList = crnList;
                        } else if (res.code === 403) {
                           parent.location.href = baseUrl + "/login";
                        } else {
@@ -282,6 +286,9 @@
                              let position = []
                              for (var i = 0; i < rgvs.length; i++) {
                                 var rgvEl = $("#rgv-" + rgvs[i].rgvNo);
                                 if(rgvEl.offset() == undefined) {
                                    continue;
                                 }
                                 position.push({
                                    id: rgvs[i].rgvNo,
                                    trackSiteNo: rgvs[i].trackSiteNo,
@@ -294,47 +301,30 @@
                           for (var i = 0; i < rgvs.length; i++) {
                              var rgvEl = $("#rgv-" + rgvs[i].rgvNo);
                              if (rgvs[i].rgvStatus == 'IDLE') {
                              if (rgvs[i].rgvStatus == 'idle') {
                                 rgvEl.attr("class", "rgv-item");
                              }else if (rgvs[i].rgvStatus == 'WORKING') {
                              }else if (rgvs[i].rgvStatus == 'working') {
                                 rgvEl.attr("class", "rgv-item machine-working");
                              }else if (rgvs[i].rgvStatus == 'waiting') {
                                 rgvEl.attr("class", "rgv-item machine-working");
                              }else {
                                 rgvEl.attr("class", "rgv-item machine-un-auto");
                              }
                              let trackSiteNo = rgvs[i].trackSiteNo;
                              let trackSiteEl = $("#rgvTrackSiteNo-" + trackSiteNo);
                              let flag = false;
                              that.rgvPosition.forEach((item) => {
                                 if (item.id == rgvs[i].rgvNo) {
                                    if (item.trackSiteNo != trackSiteNo) {
                                       flag = true
                                    }
                                 }
                              })
                              if (flag) {
                                 let finalOffset = 0;
                                 let targetPosition = trackSiteEl.parent().parent().position().left;
                                 let rgvPosition = rgvEl.position().left;
                                 let calcResult = targetPosition - rgvPosition
                                 if (calcResult > 0) {
                                    finalOffset = targetPosition + trackSiteEl.width();
                                 }else {
                                    finalOffset = targetPosition;
                                 }
                                 rgvEl.animate({left: finalOffset + "px"}, 500);
                                 let position = []
                                 that.rgvPosition.forEach((item) => {
                                    if (item.id == rgvs[i].rgvNo) {
                                       item.trackSiteNo = trackSiteNo
                                    }
                                    position.push(item)
                                 })
                                 that.rgvPosition = position
                              if(rgvEl.offsetParent().offset() == undefined) {
                                 continue;
                              }
                              let parentLeft = rgvEl.offsetParent().offset().left;
                              let targetPosition = trackSiteEl.parent().parent().offset().left - parentLeft;
                              let rgvPosition = rgvEl.position().left;
                              let zoomFactor = that.mapSettingParam.zoom ? (that.mapSettingParam.zoom / 100) : 1;
                              if (zoomFactor <= 0) { zoomFactor = 1; }
                              let finalOffset = targetPosition / zoomFactor;
                              rgvEl.animate({left: finalOffset + "px"}, 500);
                           }
                        } else if (res.code === 403) {
                           parent.location.href = baseUrl + "/login";
@@ -431,6 +421,38 @@
                     }
                  });
               },
               getCrnTargetCell(crnEl, bay) {
                  if (!crnEl || bay == null) {
                     return null;
                  }
                  let rowEl = crnEl.closest('tr');
                  if (!rowEl || rowEl.length === 0) {
                     return null;
                  }
                  let targetCell = null;
                  let colCounter = 0;
                  let startCount = false;
                  rowEl.find('td').each(function () {
                     // 以当前行中首次出现的track-item为起点进行列计数
                     const isTrackCrn = $(this).find('.track-crn').length > 0;
                     if (!startCount && !isTrackCrn) {
                        return;
                     }
                     let span = parseInt($(this).attr('colspan'), 10);
                     if (isNaN(span) || span < 1) {
                        span = 1;
                     }
                     if (!startCount && isTrackCrn) {
                        startCount = true;
                     }
                     colCounter += span;
                     if (targetCell == null && colCounter >= bay) {
                        targetCell = $(this);
                        return false;
                     }
                  });
                  return targetCell;
               },
               getDeviceNo(obj) {
                  if (this.isJson(obj)) {
                     let data = JSON.parse(obj)