<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 disabled v-model="fShelf" clearable/>
      </div>
      <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 < 12 ? '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"
            placement="top"
          >
            <div slot="content">
              料架号：{{ location.rid }}<br/>
              物料代码：{{ location.materialCode}}<br/>
              物料名称：{{ location.materialName }}<br/>
              规格型号：{{ location.materialSpecifications }}
            </div>
            <span>{{ location.label }}</span>
          </el-tooltip>
          <span v-else>{{ location.label }}</span>
        </div>
      </div>
    </div>


    <el-dialog
      custom-class="bold-title-dialog"
      title="请选择物料清单"
      :visible.sync="selectMaterialInfoForPurReqOpen"
      width="688px"
      append-to-body
      :close-on-click-modal="false"
      :before-close="materialForPurReqFormBeforeClose"
    >
      <el-form ref="materialForPurReqForm" :inline="true" label-width="68px">
        <el-form-item label="物料代码" prop="materialCode">
          <el-input
            v-model="queryMaterialInfoListParams.materialCode"
            placeholder="请输入物料代码"
            clearable
            size="small"
            @keyup.enter.native="listMaterialInfoListMethod"
          />
        </el-form-item>
        <el-form-item label="物料名称" prop="materialName">
          <el-input
            v-model="queryMaterialInfoListParams.materialName"
            placeholder="请输入产品名称"
            clearable
            size="small"
            @keyup.enter.native="listMaterialInfoListMethod"
          />
        </el-form-item>
        <el-form-item>
          <el-button
            type="primary"
            icon="el-icon-search"
            size="mini"
            @click="listMaterialInfoListMethod"
          >搜索
          </el-button
          >
        </el-form-item>
      </el-form>

      <el-table
        border
        style="width: 100%"
        ref="prodInfoFormTableRef"
        height="550"
        :data="materialInfoList"
        @row-click="materialInfoHandleCellClick"
        :key="Math.random()"
      >
        <el-table-column width="200" prop="materialCode" label="物料代码">
        </el-table-column>
        <el-table-column width="200" prop="materialName" label="物料名称">
        </el-table-column>
        <el-table-column width="200" prop="materialSpecifications" label="规格型号">
        </el-table-column>
      </el-table>

      <pagination
        v-show="materialForPurReqRefTotal > 0"
        :total="materialForPurReqRefTotal"
        :page.sync="queryMaterialInfoListParams.pageNum"
        :limit.sync="queryMaterialInfoListParams.pageSize"
        @pagination="listMaterialInfoListMethod"
      />
    </el-dialog>

    <!-- 出库 -->
    <el-dialog title="入库" :visible.sync="open" width="500px" append-to-body destroy-on-close :close-on-click-modal="false">
      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
        <el-form-item label="料盘码" prop="materialCode">
          <el-input v-model="form.rackCode" placeholder="请输入物料代码" :readOnly="true"/>
        </el-form-item>
        <el-form-item label="物料代码" prop="materialCode">
          <el-input
            v-model="form.materialCode"
            placeholder="请点击选择物料"
            readonly
            @click.native="openMaterialSelectDialog"
          />
        </el-form-item>
        <el-form-item label="物料名称" prop="materialName">
          <el-input v-model="form.materialName" placeholder="请输入名称" :readOnly="true"/>
        </el-form-item>
        <el-form-item label="规格型号" prop="materialSpecifications">
          <el-input v-model="form.materialSpecifications" placeholder="请输入规格型号" :readOnly="true"/>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="submitForm">确 定</el-button>
        <el-button @click="cancel">取 消</el-button>
      </div>
    </el-dialog>

  </div>
</template>

<script>
  import { locationListInfo, rackInOutput} from "@/api/shelf/location";
  import { materialInfoList ,listInfo} from "@/api/material/info";
  export default {
    name: "shelf-location",
    data(){
        return{
          barCode: null,
          shelfInfo: [],
          shelfLayoutList: [],
          storey:{
            0: "一层正面",
            1: "",
            2: "一层反面",
            3: "",
            4: "二层正面",
            5: "",
            6: "二层反面",
            7: "",
            8: "三层正面",
            9: "",
            10: "三层反面",
            11: "",
            12: "四层正面",
            13: "五层正面",
          },
          lastSelectedItem: null,
          lastCtrlSelectedItem: null,
          selectedItems: new Set(),
          // 查询参数
          queryParams: {
            shelfId: null,
          },
          ws: null,
          heartbeatInterval: null,
          form: {
            rackCode: null,
            materialCode: null,
            materialName: null,
            materialSpecifications: null,
            materialId: null
          },
          open: false,
          // 表单校验
          rules: {
            rackCode: [
              { required: true, message: "物料代码不能为空", trigger: "blur" }
            ],
          },
          materialInfoList: [],
          selectMaterialInfoForPurReqOpen: false,
          materialForPurReqRefTotal: 0,
          queryMaterialInfoListParams: {
            status: 1,
            pageNum: 1,
            pageSize: 10,
          },
          // 料盘号
          fShelf: null
        }
    },
    created(){
      this.queryParams.shelfId = this.$route.query.shelfId;
      this.fShelf = this.$route.query.shelf;
      this.getList();
      this.$nextTick(() => {
        this.$refs.barCode.focus();
      })
      this.connect();
    },
    methods:{
      openMaterialSelectDialog() {
        this.selectMaterialInfoForPurReqOpen = true;
        this.listMaterialInfoListMethod(); // 立即加载第一页数据
      },
      materialInfoHandleCellClick(row) {
        this.form.materialId = row.materialInfoId || row.materialId;
        this.form.materialCode = row.materialCode;
        this.form.materialName = row.materialName;
        this.form.materialSpecifications = row.specification || row.materialSpecifications;
        this.selectMaterialInfoForPurReqOpen = false;
      },
      materialForPurReqFormBeforeClose() {
        this.queryMaterialInfoListParams = {
          status: 1,
          pageNum: 1,
          pageSize: 10,
        };
        this.selectMaterialInfoForPurReqOpen = false;
      },
      listMaterialInfoListMethod() {
        listInfo(this.queryMaterialInfoListParams).then((response) => {
          this.materialInfoList = response.rows;
          this.materialForPurReqRefTotal = response.total;
        });
      } ,
      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, 40));
          this.shelfLayoutList.push(this.shelfInfo.slice(40, 80));
          this.shelfLayoutList.push(this.shelfInfo.slice(80,120));
          this.shelfLayoutList.push(this.shelfInfo.slice(120,160));
          this.shelfLayoutList.push(this.shelfInfo.slice(160,200));
          this.shelfLayoutList.push(this.shelfInfo.slice(200,240));
          this.shelfLayoutList.push(this.shelfInfo.slice(240,280));
          this.shelfLayoutList.push(this.shelfInfo.slice(280,320));
          this.shelfLayoutList.push(this.shelfInfo.slice(320,360));
          this.shelfLayoutList.push(this.shelfInfo.slice(360,400));
          this.shelfLayoutList.push(this.shelfInfo.slice(400,440));
          this.shelfLayoutList.push(this.shelfInfo.slice(440,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(){
        this.reset();
        if(!this.barCode){
          this.$message.error("请扫描或输入料盘条形码");
          return
        }
        this.getMaterialInfo();
        this.form.rackCode = this.barCode;
        this.open = true;

      },
      // 出库操作需要选择位置可多选不需要扫码
      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)).then(res =>{
          if(res.code == 200){
            this.msgSuccess("请取物料");
          }
        });
        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;
              locationInfo.materialCode = message.materialCode;
              locationInfo.materialName = message.materialName;
              locationInfo.materialSpecifications = message.materialSpecifications;
            }
            //出库
            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();
        }
      },
      // 表单重置
      reset() {
        this.form = {
          materialCode: null,
          materialId: null,
          materialName: null,
          materialSpecifications: null,
        };
        this.resetForm("form");
      },
      //提交入库
      submitForm(){
        this.form.shelf = this.fShelf;
        const param = {
          inStoreParam: JSON.stringify(
            {
              ID: this.generateUUID(),
              OPTYPE: "I",
              SHELF: this.fShelf,
              COLOR: "1",
              USERNAME: "admin",
              TOTALINFO: [{RID: this.barCode}]
            }
          ),
          relationParam: this.form
        };
        rackInOutput(JSON.stringify(param)).then(res =>{
          if(res.code == 200){
            this.open = false;
            this.barCode = null;
            this.msgSuccess("请放物料");
            this.clearSelection();
            this.$nextTick(() => {
              this.$refs.barCode.focus();
            })
          }
        })
      },
      //取消入库
      cancel(){
        this.reset();
        this.open = false;
      },
      //切换物料代码
      materialCodeChange(val){
        const materialInfo = this.materialInfoList.find(item => item.materialId === val);
        this.form.materialId = val;
        this.form.materialName = materialInfo.materialName;
        this.form.materialSpecifications = materialInfo.materialSpecifications;
      },
      //获取物料信息
      getMaterialInfo(){
        materialInfoList().then(res =>{
          if(res.code == 200){
              this.materialInfoList = res.data;
          }
        })
      }
    },
    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: flex;
    flex-direction: column;
    gap: 0;              // 使用 flex 列布局，手动控制行间距
    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;
    overflow-x: auto;
    white-space: nowrap;
    margin-bottom: 6px;   /* 组内行间距（小） */

    /* 组间分隔：每组第一行（一层反面、二层正面、二层反面、三层正面、三层反面、四层、五层） */
    &:nth-child(3),   /* 一层反面第一行 */
    &:nth-child(5),   /* 二层正面第一行 */
    &:nth-child(7),   /* 二层反面第一行 */
    &:nth-child(9),   /* 三层正面第一行 */
    &:nth-child(11),  /* 三层反面第一行 */
    &:nth-child(13),  /* 四层正面 */
    &:nth-child(14) { /* 五层正面 */
      border-top: 2px solid #dcdfe6;
      padding-top: 12px;
    }
  }

  /* 简约风格滚动条 */
  .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(40, 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>
