<template>
  <div class="app-container">
    <el-button
      style="float: right"
      type="primary"
      icon="el-icon-back"
      @click="$router.go(-1)"
    >
      返回
    </el-button>

    <div class="location-operate">
      <div class="scanner-input">
        <span>料盘码:</span>
        <el-input ref="barCode" placeholder="扫描料盘条形码..." v-model="barCode" clearable/>
      </div>

      <div class="operate">
        <el-button
          type="primary"
          plain
          icon="el-icon-plus"
          size="mini"
          @click="handleIn"
        >入库</el-button>

        <el-button
          type="primary"
          plain
          icon="el-icon-minus"
          size="mini"
          @click="handleOut"
        >出库</el-button>
      </div>
    </div>

    <div class="location-list">
      <div :class="['grid-row', index < 6 ? 'top-rows' : 'bottom-rows']" v-for="(layout,index) in shelfLayoutList">
        <div class="row-title">{{ storey[index] }}</div>
        <div
          :id="'item-'+ location.index"
          :data-index="location.index"
          :class="[location.rid ? 'used' : 'grid-item']"
          v-for="location in layout"
          @click="checkedLocation($event)"
        >
          <el-tooltip
            effect="light"
            v-if="location.rid"
            :content="location.rid"
            placement="top"
          >
            <span>{{ location.label }}</span>
          </el-tooltip>
          <span v-else>{{ location.label }}</span>
        </div>
      </div>
    </div>

  </div>
</template>

<script>
  import { locationListInfo, rackInOutput} from "@/api/shelf/location";
  export default {
    name: "shelf-location",
    data(){
        return{
          barCode: null,
          shelfInfo: [],
          shelfLayoutList: [],
          storey:{
            0: "一层正面",
            1: "一层反面",
            2: "二层正面",
            3: "二层反面",
            4: "三层正面",
            5: "三层反面",
            6: "四层正面",
            7: "五层正面",
          },
          lastSelectedItem: null,
          lastCtrlSelectedItem: null,
          selectedItems: new Set(),
          // 查询参数
          queryParams: {
            shelfId: null,
          },
          ws: null,
          heartbeatInterval: null
        }
    },
    created(){
      this.queryParams.shelfId = this.$route.query.shelfId;
      this.getList();
      this.$nextTick(() => {
        this.$refs.barCode.focus();
      })
      this.connect();
    },
    methods:{
      getList(){
        locationListInfo(this.queryParams).then(res => {
          this.shelfInfo = res.data;
          // 1 正 1-80 反 161-240
          // 2 正 81-160 反 241-320
          // 3 正 321-400 反 401-480
          // 4 正 481-528
          // 5 正 529-576
          this.shelfLayoutList.push(this.shelfInfo.slice(0,80));
          this.shelfLayoutList.push(this.shelfInfo.slice(80,160));
          this.shelfLayoutList.push(this.shelfInfo.slice(160,240));
          this.shelfLayoutList.push(this.shelfInfo.slice(240,320));
          this.shelfLayoutList.push(this.shelfInfo.slice(320,400));
          this.shelfLayoutList.push(this.shelfInfo.slice(400,480));
          this.shelfLayoutList.push(this.shelfInfo.slice(480,528));
          this.shelfLayoutList.push(this.shelfInfo.slice(528));
        });
      },
      //选中位置
      checkedLocation(event){
        if(event.ctrlKey){
          if(!this.lastCtrlSelected){
            const location = this.shelfInfo[event.currentTarget.dataset.index - 1];
            if(location.rid){
              this.lastCtrlSelected = event.currentTarget.id;
              if(this.selectedItems.has(event.currentTarget.id)){
                this.selectedItems.delete(event.currentTarget.id);
              }else{
                this.selectedItems.add(event.currentTarget.id);
              }
              event.currentTarget.classList.toggle('checked');
            }
            return;
          }
          this.breakSelected(this.lastCtrlSelected,event.currentTarget.id);
        }else if (event.shiftKey && this.lastSelectedItem){
          this.keepSelected(this.lastSelectedItem,event.currentTarget.id);
        }else{
          const location = this.shelfInfo[event.currentTarget.dataset.index - 1];
          if(location.rid){
            this.clearSelection();
            this.selectedItems.add(event.currentTarget.id);
            event.currentTarget.classList.add('checked');
            this.lastSelectedItem = event.currentTarget.id;
          }
        }
      },
      // 连续选中
      keepSelected(startId, endId) {
        this.clearSelection();
        const allItems = Array.from(document.querySelectorAll('.used'));
        const startIndex = allItems.findIndex(item => item.id == startId);
        const endIndex = allItems.findIndex(item => item.id == endId);
        if (startIndex === -1 || endIndex === -1) return;
        const minIndex = Math.min(startIndex, endIndex);
        const maxIndex = Math.max(startIndex, endIndex);
        for (let i = minIndex; i <= maxIndex; i++) {
          const itemId = allItems[i].id;
          this.selectedItems.add(itemId);
          allItems[i].classList.toggle('checked');
        }
        this.lastSelectedItem = endId;
      },

      // 断续选中
      breakSelected(startId, endId) {
        const allItems = Array.from(document.querySelectorAll('.used'));
        const startIndex = allItems.findIndex(item => item.id == startId);
        const endIndex = allItems.findIndex(item => item.id == endId);
        if (startIndex === -1 || endIndex === -1) return;
        const minIndex = Math.min(startIndex, endIndex);
        const maxIndex = Math.max(startIndex, endIndex);
        for (let i = minIndex + 1; i <= maxIndex; i++) {
          const itemId = allItems[i].id;
          if(this.selectedItems.has(itemId)){
            this.selectedItems.delete(itemId);
          }else{
            this.selectedItems.add(itemId);
          }
          allItems[i].classList.toggle('checked');
        }
        this.lastCtrlSelected = null;
      },
      // 清除所有选择
      clearSelection() {
        this.selectedItems.forEach(itemId => {
          const item = document.getElementById(itemId);
          if (item) {
            item.classList.remove('checked');
          }
        });
        this.selectedItems.clear();
      },
      // 入库操作需要扫码不需要选位置
      handleIn(){
        if(!this.barCode){
          this.$message.error("请扫描或输入料盘条形码");
          return
        }
        const param = {
          ID: this.generateUUID(),
          OPTYPE: "I",
          SHELF: this.$route.query.shelf,
          COLOR: "1",
          USERNAME: "admin",
          TOTALINFO: [{RID: this.barCode}]
        };
        rackInOutput(JSON.stringify(param));
        this.clearSelection();
      },
      // 出库操作需要选择位置可多选不需要扫码
      handleOut(){
        if(this.selectedItems.size == 0){
          this.$message.error("请选择出库位置");
          return;
        }
        const param = {
          ID: this.generateUUID(),
          OPTYPE: "O",
          SHELF: this.$route.query.shelf,
          COLOR: "1",
          USERNAME: "admin",
          TOTALINFO: []
        }
        this.selectedItems.forEach(id =>{
          const dom = document.getElementById(id);
          const locationInfo = this.shelfInfo[dom.dataset.index - 1];
          param.TOTALINFO.push({RID: locationInfo.rid,LOCATION: locationInfo.location})
        })
        rackInOutput(JSON.stringify(param));
        this.clearSelection();
      },
      //生成uuid
      generateUUID() {
          return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>
            (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
        );
      },
      connect() {
        this.ws = new WebSocket('ws://' + window.location.host + process.env.VUE_APP_BASE_API + '/ws/notifications');
        this.ws.onopen = () => {
          console.log('WebSocket Connected');
          // 连接建立后，开始定期发送心跳
          this.heartbeatInterval = setInterval(() => {
            if (this.ws.readyState === WebSocket.OPEN) {
               this.ws.send(JSON.stringify({ type: 'ping' }));
               console.log("发送心跳")
            }
          }, 30000);
        };
        this.ws.onmessage = (event) => {
          // Add received message to the list
          const message = JSON.parse(event.data);
          if(message && message.shelfId && message.shelfId == this.$route.query.shelfId){
            //入库
            if("I" == message.optype){
              const locationInfo = this.shelfLayoutList.flat().find(location => location.location === message.location);
              locationInfo.rid = message.rid;
            }
            //出库
            if("O" == message.optype){
              const locationInfo = this.shelfLayoutList.flat().find(location => location.location === message.location);
              locationInfo.rid = null;
            }
          }
        };
        this.ws.onerror = (error) => {
          console.error('WebSocket Error:', error);
        };
        this.ws.onclose = () => {
          console.log('WebSocket Closed');
          clearInterval(this.heartbeatInterval);
        };
      },
      disconnect() {
        if (this.ws) {
          this.ws.close();
        }
      }
    },
    beforeDestroy() {
      this.disconnect();
    }
  }
</script>

<style scoped lang="scss">
  .location-operate{
    width: 100%;
    margin-top: 15px;
    span{
      margin-right: 20px;
      font-size: 18px;
      font-weight: 600;
    }
  }

  .scanner-input{
    width: 100%;
    .el-input{
      width: 350px;
    }
  }

  .operate{
    margin-top: 20px;
  }

  .location-list{
    display: grid;
    grid-template-rows: repeat(5, 1fr);
    gap: 12px;
    margin-top: 15px;
  }

  .grid-item {
    background: rgba(255, 255, 255, 0.1);
    border-radius: 8px;
    padding: 15px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    box-shadow: 0 4px 4px rgba(0, 0, 0, 0.2);
    transition: transform 0.3s ease, box-shadow 0.3s ease;
    cursor: pointer;
    overflow: hidden;
    position: relative;
    aspect-ratio: 1/1;
    margin-bottom: 10px;
    user-select: none;
  }

  .grid-item::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: linear-gradient(45deg, rgba(255, 255, 255, 0.1), transparent);
  }

  .grid-row {
    display: grid;
    gap: 3px;
    //height: 120px;
    overflow-x: scroll;
    white-space: nowrap;
  }

  /* 简约风格滚动条 */
  .grid-row::-webkit-scrollbar {
    height: 6px;
  }

  .grid-row::-webkit-scrollbar-track {
    background: transparent;
  }

  .grid-row::-webkit-scrollbar-thumb {
    background: #ccc;
    border-radius: 4px;
  }

  .grid-row::-webkit-scrollbar-thumb:hover {
    background: #aaa;
  }

  .top-rows{
    grid-template-columns: 110px repeat(80, minmax(30px, 1fr));
  }

  .bottom-rows {
    grid-template-columns: 110px repeat(48, minmax(30px, 1fr));
  }

  .row-title {
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 600;
    font-size: 1.2rem;
    user-select: none;
  }

  .free{
    background-color: #FFFFFF;
  }

  .used{
    background: #2ca72d;
    border-radius: 8px;
    padding: 15px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    box-shadow: 0 4px 4px rgba(0, 0, 0, 0.2);
    transition: transform 0.3s ease, box-shadow 0.3s ease;
    cursor: pointer;
    overflow: hidden;
    position: relative;
    aspect-ratio: 1/1;
    margin-bottom: 10px;
    user-select: none;
  }

  .checked {
    background: rgba(24, 144, 255, 1);
    border: 1px solid rgb(24, 112, 214);
  }

</style>
