heshaofeng
2025-11-14 5beb11143d51268dc2ee6b4ad5d59f4535e1103e
ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/extension/inbound/extend/Pallet.vue
@@ -12,50 +12,72 @@
  >
  <div class="barcode-scanner-container">
      
      <!-- æ‰˜ç›˜ä¿¡æ¯æ˜¾ç¤º -->
      <div class="tray-info" v-if="trayBarcode">
        <i class="el-icon-s-management"></i> å½“前料箱: {{ trayBarcode }}
       <!--  <el-button
          class="small-button"
          type="text"
          @click="clearTray"
          style="float: right;"
        >
          æ¸…除托盘
        </el-button> -->
      <!-- ä»“库区域选择 - ç´§å‡‘布局 -->
      <div class="location-section compact">
        <el-form :model="form" :rules="rules" ref="locationForm" class="compact-form">
          <el-form-item label="仓库区域" prop="locationType" class="location-select compact-item">
            <el-select
              v-model="form.locationType"
              placeholder="请选择仓库区域"
              clearable
              filterable
              @change="handleLocationChange"
              style="width: 100%"
              :loading="locationLoading"
              size="medium"
            >
              <el-option
                v-for="item in locationTypes"
                :key="item.locationType"
                :label="item.locationTypeDesc"
                :value="item.locationType"
              />
            </el-select>
          </el-form-item>
        </el-form>
      </div>
      
      <!-- æ‰«ç æˆ–手动输入区域 -->
      <div class="input-section">
        <el-card shadow="hover">
          <div slot="header">
            <span><i class="el-icon-scanner"></i> </span>
      <!-- æ‰˜ç›˜ä¿¡æ¯æ˜¾ç¤º - ç´§å‡‘布局 -->
      <div class="tray-info compact" v-if="trayBarcode">
        <i class="el-icon-s-management"></i> å½“前料箱: {{ trayBarcode }}
        <span class="location-info" v-if="form.locationType">
          | ä»“库区域: {{ currentLocationDesc }}
        </span>
      </div>
      <!-- æ‰«ç åŒºåŸŸ - ç´§å‡‘布局 -->
      <div class="input-section compact">
        <el-card shadow="hover" class="compact-card">
          <div slot="header" class="compact-header">
            <span><i class="el-icon-scanner"></i> æ‰«ç åŒºåŸŸ</span>
            <span class="scan-status">
              <span class="scan-indicator"></span>扫码就绪
              <span class="scan-indicator"></span>
              {{ form.locationType ? '扫码就绪' : '请先选择仓库区域' }}
            </span>
          </div>
          
          <!-- æ‰˜ç›˜æ¡ç è¾“å…¥ -->
          <div class="input-wrapper custom-input-group">
    <div class="input-label">料箱码</div>
          <div class="input-wrapper custom-input-group compact-input">
            <div class="input-label">料箱码</div>
            <el-input
              ref="trayInput"
              v-model="trayBarcode"
              placeholder="请扫描或输入料箱码后按回车键"
              clearable
              :disabled="!form.locationType"
              @keyup.enter.native="handleTraySubmit"
              @clear="handleTrayClear"
              @input="handleTrayInput"
                 class="custom-input"
              class="custom-input"
              size="medium"
            >
              <template slot="prepend">
                <span> æ–™ç®±æ¡ç </span>
              </template>
              <template slot="append">
                <el-button 
                  @click="handleTraySubmit"
                  type="primary"
                  icon="el-icon-position"
                  :disabled="!form.locationType || !trayBarcode"
                  size="medium"
                >
                  ç¡®è®¤
                </el-button>
@@ -64,29 +86,28 @@
          </div>
          
          <!-- ç‰©æ–™æ¡ç è¾“å…¥ -->
          <div class="input-wrapper custom-input-group">
          <div class="input-wrapper custom-input-group compact-input">
            <div class="input-label">物料条码</div>
            <el-input
              ref="barcodeInput"
              v-model="barcode"
              placeholder="请扫描或输入物料条码后按回车键"
              clearable
              :disabled="!trayBarcode"
              :disabled="!form.locationType || !trayBarcode"
              @keyup.enter.native="handleBarcodeSubmit"
              @clear="handleClear"
              @input="handleBarcodeInput"
                    class="custom-input"
              class="custom-input"
              size="medium"
            >
              <template slot="prepend">
                <span>物料条码</span>
              </template>
              <template slot="append">
                <el-button 
                  :loading="loading" 
                  @click="handleBarcodeSubmit"
                  type="primary"
                  icon="el-icon-search"
                  :disabled="!trayBarcode"
                  :disabled="!form.locationType || !trayBarcode || !barcode"
                  size="medium"
                >
                  {{ loading ? '查询中...' : '查询' }}
                </el-button>
@@ -94,22 +115,23 @@
            </el-input>
          </div>
          
          <div class="input-tips">
            <p>提示:先输入料箱码,然后输入物料条码</p>
          <div class="input-tips compact-tips">
            <p>提示:请先选择仓库区域,然后输入料箱码,最后输入物料条码</p>
            <p v-if="!form.locationType" class="warning-text">⚠️ è¯·å…ˆé€‰æ‹©ä»“库区域</p>
            <p v-if="form.locationType && !trayBarcode" class="warning-text">⚠️ è¯·å…ˆè¾“入料箱码</p>
          </div>
        
        </el-card>
      </div>
      <!-- åŠ è½½çŠ¶æ€ -->
      <div v-if="loading" class="loading">
      <div v-if="loading" class="loading compact">
        <el-progress :percentage="100" status="success" :show-text="false" />
        <p>正在查询物料信息...</p>
      </div>
      <!-- é”™è¯¯æç¤º -->
      <div v-if="error" class="error-message">
      <div v-if="error" class="error-message compact">
        <el-alert
          :title="error"
          type="error"
@@ -119,66 +141,45 @@
        />
      </div>
      <!-- ç‰©æ–™åˆ—表 -->
      <div class="material-list">
        <el-card shadow="hover">
          <div slot="header">
      <!-- ç‰©æ–™åˆ—表 - å›ºå®šé«˜åº¦å¸¦æ»šåŠ¨æ¡ -->
      <div class="material-list compact">
        <el-card shadow="hover" class="compact-card">
          <div slot="header" class="compact-header">
            <span><i class="el-icon-tickets"></i> ç»„盘数据</span>
            <span class="list-actions">
              <el-tag type="primary">共 {{ materials.length }} æ¡è®°å½•</el-tag>
              <el-tag v-if="trayBarcode" type="success">托盘: {{ trayBarcode }}</el-tag>
    <!--           <el-button
                v-if="materials.length > 0"
                class="small-button clear-all-btn"
                type="danger"
                icon="el-icon-delete"
                @click="clearAllMaterials"
              >
                æ¸…空列表
              </el-button> -->
          <!--     <el-button
                class="small-button clear-all-btn"
                @click="debugMode = !debugMode"
              >
                {{ debugMode ? '隐藏调试' : '显示调试' }}
              </el-button> -->
              <el-tag type="primary" size="small">共 {{ materials.length }} æ¡</el-tag>
              <el-tag type="primary" size="small">未组盘 {{ totalStockCount }}</el-tag>
              <el-tag type="primary" size="small">未入库数量 {{ totalStockSum }}{{ uniqueUnit }}</el-tag>
              <el-tag v-if="trayBarcode" type="success" size="small">托盘: {{ trayBarcode }}</el-tag>
              <el-tag v-if="form.locationType" type="info" size="small">区域: {{ currentLocationDesc }}</el-tag>
            </span>
          </div>
          
          <div v-if="materials.length === 0" class="empty-state">
          <div v-if="materials.length === 0" class="empty-state compact">
            <i class="el-icon-document"></i>
            <p v-if="!trayBarcode">请先输入料箱条码</p>
            <p v-if="!form.locationType">请先选择仓库区域</p>
            <p v-else-if="!trayBarcode">请先输入料箱条码</p>
            <p v-else>暂无物料数据,请扫描或输入物料条码</p>
          </div>
          
          <el-table
            v-else
            :data="materials"
            stripe
            style="width: 100%"
          >
            <el-table-column type="index" label="序号" width="60" align="center"></el-table-column>
              <el-table-column prop="barcode" label="条码" min-width="140"></el-table-column>
            <el-table-column prop="materielCode" label="物料编码" min-width="150"></el-table-column>
            <el-table-column prop="batchNo" label="批次" min-width="150"></el-table-column>
            <el-table-column prop="stockQuantity" label="数量" min-width="130"></el-table-column>
            <el-table-column prop="unit" label="单位" width="80" align="center"></el-table-column>
            <el-table-column prop="supplyCode" label="供应商" min-width="130"></el-table-column>
            <el-table-column prop="warehouseCode" label="仓库" min-width="120"></el-table-column>
     <!--        <el-table-column label="操作" width="100" align="center">
              <template slot-scope="scope">
                <el-button
                  v-if="scope"
                  class="small-button"
                  type="danger"
                  icon="el-icon-delete"
                  circle
                  @click="removeMaterial(scope.$index)"
                ></el-button>
              </template>
            </el-table-column> -->
          </el-table>
          <div class="table-container" v-else>
            <el-table
              :data="materials"
              stripe
              style="width: 100%"
              height="100%"
              size="small"
            >
              <el-table-column type="index" label="序号" width="60" align="center"></el-table-column>
              <el-table-column prop="barcode" label="条码" min-width="140" show-overflow-tooltip></el-table-column>
              <el-table-column prop="materielCode" label="物料编码" min-width="150" show-overflow-tooltip></el-table-column>
              <el-table-column prop="batchNo" label="批次" min-width="150" show-overflow-tooltip></el-table-column>
              <el-table-column prop="stockQuantity" label="数量" min-width="130" align="right"></el-table-column>
              <el-table-column prop="unit" label="单位" width="80" align="center"></el-table-column>
              <el-table-column prop="supplyCode" label="供应商" min-width="130" show-overflow-tooltip></el-table-column>
              <el-table-column prop="warehouseCode" label="仓库" min-width="120" show-overflow-tooltip></el-table-column>
            </el-table>
          </div>
        </el-card>
      </div>
    </div>
@@ -189,7 +190,6 @@
    </div> -->
    </vol-box>
</template>
<script>
import http from '@/api/http.js';
import VolBox from '@/components/basic/VolBox.vue';
@@ -197,6 +197,8 @@
import VolTable from '@/components/basic/VolTable.vue';
import { ElLoading, ElMessage,ElMessageBox  } from 'element-plus';
import { ref, onMounted, onUnmounted } from 'vue'
import InboundOrder from '../../../views/inbound/inboundOrder.vue';
import { th } from 'element-plus/es/locales.mjs';
export default {
  name: 'BarcodeScanner',
@@ -225,6 +227,28 @@
          scanTimer: null,
          manualInputTimer: null,
          scanTarget: 'tray', // å½“前扫码目标: tray æˆ– material
          // åº“存统计相关变量
          totalStockSum: 0,
          totalStockCount: 0,
          uniqueUnit: '',
          sumLoading: false,
          sumError: '',
        // ä»“库区域相关变量
        locationTypes: [],
        locationLoading: false,
        form: {
            locationType: null
        },
    rules: {
      locationType: [
        {
          validator: this.validateLocationType,
          trigger: 'change'
        }
      ]
    }
    }
  },
  computed: {
@@ -232,7 +256,12 @@
      get() { return this.visible; },
      set(newVal) { this.$emit('update:visible', newVal); }
    },
    currentDocNo() { return this.docNo; }
    currentDocNo() { return this.docNo; },
        // å½“前选择的仓库区域描述
    currentLocationDesc() {
        const location = this.locationTypes.find(item => item.locationType === this.form.locationType)
        return location ? location.locationTypeDesc : ''
    }
  },
  watch: {
    visible(newVal, oldVal) {
@@ -244,7 +273,9 @@
      this.resetData();
      this.$nextTick(() => {
        setTimeout(() => {
          this.focusTrayInput();
         // this.focusTrayInput();
            this.initLocationTypes(); // åˆå§‹åŒ–仓库区域
          this.fetchStockStatistics(); // åŠ è½½ç»Ÿè®¡æ•°æ®
        }, 300);
      });
    }
@@ -263,6 +294,7 @@
        this.palletForm = { palletCode: '', barcode: '' };
        this.backData = [];
        this.$refs.palletForm?.reset();
        this.fetchStockStatistics(); // å•据号变了,刷新统计
      }
    }
  },
@@ -274,7 +306,8 @@
        
        // ä½¿ç”¨setTimeout确保DOM完全渲染后再聚焦
        setTimeout(() => {
          this.focusTrayInput();
         // this.focusTrayInput();
                  this.focusLocationSelect();
        }, 300);
      },
      beforeDestroy() {
@@ -283,6 +316,170 @@
         this.clearAllTimers();
      },
      methods: {
         /**
   * è‡ªå®šä¹‰ä»“库区域验证
   * å…è®¸å€¼ä¸º0,因为0是合法的locationType
   */
  validateLocationType(rule, value, callback) {
    // æ£€æŸ¥å€¼æ˜¯å¦ä¸ºnull、undefined或空字符串,但允许数字0
    if (value === null || value === undefined || value === '') {
      callback(new Error('请选择仓库区域'));
    } else {
      // å€¼ä¸º0或其他有效值都通过验证
      callback();
    }
  },
         /**
         * åˆå§‹åŒ–仓库区域数据
         */
        async initLocationTypes() {
            this.locationLoading = true;
            this.error = '';
            try {
                const response = await http.post('/api/LocationInfo/GetLocationTypes');
                if (response.status && Array.isArray(response.data)) {
                    this.locationTypes = response.data;
                    if (this.locationTypes.length === 0) {
                        this.error = '未获取到仓库区域数据';
                    } else {
                        // å¦‚果有默认区域,可以在这里设置
                        // this.form.locationType = this.locationTypes[0].locationType;
                    }
                } else {
                    this.error = '获取仓库区域数据失败';
                }
            } catch (error) {
                console.error('获取仓库区域失败:', error);
                this.error = `获取仓库区域失败: ${error.message || '网络错误'}`;
            } finally {
                this.locationLoading = false;
            }
        },
 /**
 * ä»“库区域变更处理
 */
handleLocationChange(value) {
 console.log('选择仓库区域:', value, '类型:', typeof value, this.currentLocationDesc);
    // ç«‹å³æ¸…除错误信息
    this.error = '';
    // æ‰‹åŠ¨è§¦å‘è¡¨å•éªŒè¯æ›´æ–°
    this.$nextTick(() => {
      if (this.$refs.locationForm) {
        // æ¸…除该字段的验证状态,然后重新验证
        this.$refs.locationForm.clearValidate('locationType');
        // çŸ­æš‚延迟后重新验证,确保DOM已更新
        setTimeout(() => {
          this.$refs.locationForm.validateField('locationType', (errorMsg) => {
            if (!errorMsg && (value === 0 || value)) {
              console.log('仓库区域验证通过:', value);
              // åŒºåŸŸé€‰æ‹©åŽï¼Œè‡ªåŠ¨èšç„¦åˆ°æ‰˜ç›˜è¾“å…¥æ¡†
              this.focusTrayInput();
            }
          });
        }, 100);
    }
  });
},
        // æ–°å¢žï¼šæŸ¥è¯¢åŽç«¯åº“存统计数据(调用之前的 SumQuantity æŽ¥å£ï¼‰
    async fetchStockStatistics() {
      // å•据号为空时不查询
      if (!this.docNo) {
        this.sumError = '单据号为空,无法统计';
        return;
      }
      this.sumLoading = true;
      this.sumError = '';
      try {
        // è°ƒç”¨åŽç«¯ç»Ÿè®¡æŽ¥å£ï¼ˆæ›¿æ¢ä¸ºä½ çš„实际接口路径)
        const response = await http.post('/api/InboundOrder/UnPalletQuantity?orderNo='+this.docNo, {
        });
        // ç»‘定数据(匹配 PalletSumQuantityDTO ç»“构)
        if (response.data) {
          this.totalStockSum = response.data.stockSumQuantity || 0; // æ€»åº“存数量
          this.totalStockCount = response.data.stockCount || 0;     // æ€»åº“存记录数
          this.uniqueUnit = response.data.uniqueUnit || '';               // è®¡é‡å•位
        }
      } catch (err) {
        this.sumError = '统计加载失败';
        this.totalStockSum = 0;
        this.totalStockCount = 0;
        console.error('库存统计查询异常:', err);
      } finally {
        this.sumLoading = false;
      }
    },
/**
 * è¡¨å•验证
 */
async validateForm() {
  return new Promise((resolve) => {
    if (!this.$refs.locationForm) {
      this.error = '表单未初始化';
      this.$message.warning('请先选择仓库区域');
      resolve(false);
      return;
    }
    this.$refs.locationForm.validate((valid) => {
      if (valid) {
        this.error = '';
        resolve(true);
      } else {
        // æ‰‹åŠ¨æ£€æŸ¥locationType,正确处理值为0的情况
        if (this.form.locationType === null || this.form.locationType === undefined || this.form.locationType === '') {
          this.error = '请先选择仓库区域';
          //this.$message.warning('请先选择仓库区域');
        } else {
          // å¦‚果值存在(包括0),但验证不通过,可能是其他验证错误
          this.error = '请检查表单填写是否正确';
        }
        resolve(false);
      }
    });
  });
},
        // èšç„¦åˆ°ä»“库区域选择
        focusLocationSelect() {
            if (this.$refs.locationForm) {
                const selectEl = this.$el.querySelector('.el-select .el-input__inner');
                if (selectEl) {
                    selectEl.focus();
                    this.currentFocus = 'location';
                }
            }
        },
        // èšç„¦åˆ°æ‰˜ç›˜è¾“入框
        focusTrayInput() {
            if (this.$refs.trayInput && this.$refs.trayInput.$el) {
                const inputEl = this.$refs.trayInput.$el.querySelector('input');
                if (inputEl) {
                    inputEl.focus();
                    this.currentFocus = 'tray';
                    this.scanTarget = 'tray';
                }
            }
        },
        // èšç„¦åˆ°ç‰©æ–™è¾“入框
        focusBarcodeInput() {
            if (this.$refs.barcodeInput && this.$refs.barcodeInput.$el) {
                const inputEl = this.$refs.barcodeInput.$el.querySelector('input');
                if (inputEl) {
                    inputEl.focus();
                    this.currentFocus = 'material';
                    this.scanTarget = 'material';
                }
            }
        },
         // é‡ç½®æ‰€æœ‰æ•°æ®
    resetData() {
      console.log('重置弹框数据');
@@ -295,9 +492,20 @@
      this.lastKeyTime = null;
      this.isManualInput = false;
      this.isScanning = false;
      this.currentFocus = 'tray';
      this.currentFocus = 'location';
      this.scanTarget = 'tray';
      this.clearAllTimers();
      this.totalStockSum = 0;
      this.totalStockCount = 0;
      this.sumLoading = false;
      this.sumError = '';
        this.form.locationType = null;
          // æ¸…除表单验证状态
  this.$nextTick(() => {
    if (this.$refs.locationForm) {
      this.$refs.locationForm.clearValidate();
    }
  });
    },
    
    // æ¸…除所有计时器
@@ -319,7 +527,16 @@
      // ä½¿ç”¨setTimeout确保DOM完全渲染后再聚焦
      this.$nextTick(() => {
        setTimeout(() => {
          this.focusTrayInput();
            this.initLocationTypes(); // åˆå§‹åŒ–仓库区域
             // ç¡®ä¿è¡¨å•引用存在后再聚焦
      if (this.$refs.locationForm) {
        this.focusLocationSelect();
      } else {
        // å¦‚果表单引用还不存在,稍后重试
        setTimeout(() => {
          this.focusLocationSelect();
        }, 500);
      }
        }, 300);
      });
    },
@@ -336,7 +553,9 @@
    },
    
    // ç¡®è®¤æŒ‰é’®
    handleConfirm() {
   async  handleConfirm() {
           if (!await this.validateForm()) return;
      if (this.materials.length === 0) {
        this.$message.warning('请至少添加一个物料');
        return;
@@ -348,6 +567,8 @@
      }
      
      const result = {
        locationType: this.form.locationType,
        locationDesc: this.currentLocationDesc,
        trayBarcode: this.trayBarcode,
        materials: this.materials,
        docNo: this.docNo
@@ -357,84 +578,70 @@
      this.$emit('back-success', result);
      this.palletVisible = false;
    },
        // èšç„¦åˆ°æ‰˜ç›˜è¾“入框
        focusTrayInput() {
          if (this.$refs.trayInput && this.$refs.trayInput.$el) {
            const inputEl = this.$refs.trayInput.$el.querySelector('input');
            if (inputEl) {
              inputEl.focus();
              this.currentFocus = 'tray';
              this.scanTarget = 'tray';
            }
          }
        },
        // èšç„¦åˆ°ç‰©æ–™è¾“入框
        focusBarcodeInput() {
          if (this.$refs.barcodeInput && this.$refs.barcodeInput.$el) {
            const inputEl = this.$refs.barcodeInput.$el.querySelector('input');
            if (inputEl) {
              inputEl.focus();
              this.currentFocus = 'material';
              this.scanTarget = 'material';
            }
          }
        },
        // å¤„理托盘输入
    // å¤„理托盘输入
        handleTrayInput() {
          // æ ‡è®°ä¸ºæ‰‹åŠ¨è¾“å…¥æ¨¡å¼
          this.isManualInput = true;
          this.isScanning = false;
          // æ¸…除之前的计时器
          if (this.manualInputTimer) {
            clearTimeout(this.manualInputTimer);
          }
          // è®¾ç½®è®¡æ—¶å™¨ï¼Œå¦‚果一段时间内没有输入,则重置为扫码模式
          this.manualInputTimer = setTimeout(() => {
            this.isManualInput = false;
          }, 1000);
            // æ ‡è®°ä¸ºæ‰‹åŠ¨è¾“å…¥æ¨¡å¼
            this.isManualInput = true;
            this.isScanning = false;
            // æ¸…除之前的计时器
            if (this.manualInputTimer) {
                clearTimeout(this.manualInputTimer);
            }
            // è®¾ç½®è®¡æ—¶å™¨ï¼Œå¦‚果一段时间内没有输入,则重置为扫码模式
            this.manualInputTimer = setTimeout(() => {
                this.isManualInput = false;
            }, 1000);
        },
        
        // å¤„理物料输入
        handleBarcodeInput() {
          // æ ‡è®°ä¸ºæ‰‹åŠ¨è¾“å…¥æ¨¡å¼
          this.isManualInput = true;
          this.isScanning = false;
          // æ¸…除之前的计时器
          if (this.manualInputTimer) {
            clearTimeout(this.manualInputTimer);
          }
          // è®¾ç½®è®¡æ—¶å™¨ï¼Œå¦‚果一段时间内没有输入,则重置为扫码模式
          this.manualInputTimer = setTimeout(() => {
            this.isManualInput = false;
          }, 1000);
        },
        // å¤„理托盘条码提交
        handleTraySubmit() {
          const currentTrayBarcode = this.trayBarcode.trim();
          if (!currentTrayBarcode) {
            this.error = '请输入或扫描托盘条码';
            return;
          }
            // æ ‡è®°ä¸ºæ‰‹åŠ¨è¾“å…¥æ¨¡å¼
            this.isManualInput = true;
            this.isScanning = false;
            // æ¸…除之前的计时器
            if (this.manualInputTimer) {
                clearTimeout(this.manualInputTimer);
            }
            // è®¾ç½®è®¡æ—¶å™¨ï¼Œå¦‚果一段时间内没有输入,则重置为扫码模式
            this.manualInputTimer = setTimeout(() => {
                this.isManualInput = false;
            }, 1000);
        },
       // å¤„理托盘条码提交
async handleTraySubmit() {
  // å…ˆç›´æŽ¥æ£€æŸ¥locationType,避免表单验证的异步问题
  if (!this.form.locationType) {
    this.error = '请先选择仓库区域';
    //this.$message.warning('请先选择仓库区域');
    return;
  }
  // ç„¶åŽå†è¿›è¡Œå®Œæ•´çš„表单验证
  if (!await this.validateForm()) return;
  const currentTrayBarcode = this.trayBarcode.trim();
  if (!currentTrayBarcode) {
    this.error = '请输入或扫描托盘条码';
    return;
  }
          this.error = '';
          // è®¾ç½®æ‰˜ç›˜æ¡ç åŽï¼Œè‡ªåŠ¨èšç„¦åˆ°ç‰©æ–™è¾“å…¥æ¡†
          this.focusBarcodeInput();
          this.$message({
            message: `托盘条码已设置: ${currentTrayBarcode}`,
            type: 'success',
            duration: 2000
          });
        },
  this.error = '';
  // è®¾ç½®æ‰˜ç›˜æ¡ç åŽï¼Œè‡ªåŠ¨èšç„¦åˆ°ç‰©æ–™è¾“å…¥æ¡†
  this.focusBarcodeInput();
  this.$message({
    message: `托盘条码已设置: ${currentTrayBarcode}`,
    type: 'success',
    duration: 2000
  });
},
        
        // æ¸…除托盘
        clearTray() {
@@ -463,6 +670,7 @@
        
        // å¤„理物料条码提交
        async handleBarcodeSubmit() {
                    if (!await this.validateForm()) return;
          const currentBarcode = this.barcode.trim();
          
          if (!this.trayBarcode) {
@@ -506,6 +714,8 @@
          this.materials.push({
            ...item, 
             trayCode: this.trayBarcode,
               locationType: this.form.locationType,
                            locationDesc: this.currentLocationDesc,
               scanTime: this.formatTime(new Date())
          });
        });
@@ -519,7 +729,7 @@
                duration: 2000
              });
         
            this.fetchStockStatistics();
            // æ¸…空物料输入框并保持聚焦
            this.barcode = '';
            this.scanCode = ''; // æ¸…空扫码缓存
@@ -543,7 +753,9 @@
           {
            palletCode: this.trayBarcode,
            orderNo: this.docNo,
            barcodes: barcode
            barcodes: barcode,
            locationTypeDesc:  this.currentLocationDesc,
                    locationType: this.form.locationType // æ·»åŠ ä»“åº“åŒºåŸŸä¿¡æ¯
          } 
        );
        
@@ -564,7 +776,7 @@
 if(!response.status){
   this.error = response.message || '查询条码信息失败,请重试';
 }
        // ç¡®ä¿è¿”回的数据包含所有必需的字段
        return  materialData;
        
      } catch (error) {
@@ -639,6 +851,8 @@
              type: 'success',
              message: '删除成功!'
            });
            this.fetchStockStatistics();
          }).catch(() => {
            // å–消删除
          });
@@ -682,135 +896,299 @@
    .barcode-scanner-container {
      max-width: 1200px;
      margin: 0 auto;
      padding: 20px;
      padding: 10px;
      display: flex;
      flex-direction: column;
      height: 100%;
      gap: 8px;
    }
    /* ç´§å‡‘布局样式 */
    .compact {
      margin-bottom: 0;
    }
    .compact-form {
      margin-bottom: 0;
    }
    .compact-item {
      margin-bottom: 0;
    }
    .compact-card {
      margin-bottom: 0;
    }
    .compact-card >>> .el-card__body {
      padding: 12px;
    }
    .compact-header {
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding: 0 !important;
    }
    .compact-header >>> .el-card__header {
      padding: 8px 12px;
    }
    .compact-input {
      margin: 8px 0;
    }
    .compact-tips {
      margin-top: 8px;
      font-size: 11px;
    }
    /* ä»“库区域选择 - ç´§å‡‘ */
    .location-section.compact {
      margin-bottom: 8px;
    }
    .location-section.compact >>> .el-form-item {
      margin-bottom: 0;
    }
    /* æ‰˜ç›˜ä¿¡æ¯ - ç´§å‡‘ */
    .tray-info.compact {
      padding: 6px 10px;
      margin-bottom: 8px;
      font-size: 13px;
    }
    /* æ‰«ç åŒºåŸŸ - ç´§å‡‘ */
    .input-section.compact {
      margin-bottom: 8px;
      flex-shrink: 0;
    }
    /* ç‰©æ–™åˆ—表 - å›ºå®šé«˜åº¦å¸¦æ»šåЍ */
    .material-list.compact {
      flex: 1;
      min-height: 0; /* é‡è¦ï¼šå…è®¸flex子项收缩 */
      display: flex;
      flex-direction: column;
    }
    .material-list.compact >>> .el-card {
      display: flex;
      flex-direction: column;
      height: 100%;
    }
    .material-list.compact >>> .el-card__body {
      flex: 1;
      display: flex;
      flex-direction: column;
      padding: 0;
      min-height: 0;
    }
    .table-container {
      flex: 1;
      min-height: 0;
      overflow: hidden;
    }
    .material-list.compact >>> .el-table {
      flex: 1;
    }
    .material-list.compact >>> .el-table__body-wrapper {
      overflow-y: auto;
    }
    /* ç´§å‡‘的空状态 */
    .empty-state.compact {
      padding: 20px 0;
      flex: 1;
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
    }
    .empty-state.compact i {
      font-size: 36px;
      margin-bottom: 8px;
    }
    .empty-state.compact p {
      font-size: 13px;
    }
    /* å…¶ä»–原有样式调整 */
    .page-title {
      text-align: center;
      margin-bottom: 30px;
      margin-bottom: 15px;
    }
    .input-section {
      margin-bottom: 30px;
    }
    .scan-status {
      float: right;
      font-size: 12px;
      color: #67C23A;
    }
    .scan-indicator {
      display: inline-block;
      width: 10px;
      height: 10px;
      width: 8px;
      height: 8px;
      border-radius: 50%;
      background-color: #67C23A;
      margin-right: 5px;
      animation: pulse 1.5s infinite;
    }
    @keyframes pulse {
      0% { opacity: 1; }
      50% { opacity: 0.4; }
      100% { opacity: 1; }
    }
    .input-wrapper {
      position: relative;
      margin-bottom: 15px;
    }
    .input-tips {
      margin-top: 10px;
      font-size: 12px;
      margin-top: 6px;
      color: #909399;
    }
    .loading {
      text-align: center;
      margin: 20px 0;
    .warning-text {
        color: #E6A23C;
        font-weight: bold;
    }
    .loading p {
      margin-top: 10px;
    .loading.compact {
      text-align: center;
      margin: 10px 0;
      padding: 5px;
    }
    .loading.compact p {
      margin-top: 5px;
      color: #409EFF;
      font-size: 12px;
    }
    .error-message {
      margin-bottom: 20px;
    .error-message.compact {
      margin: 5px 0;
    }
    .material-list {
      margin-top: 30px;
    .error-message.compact >>> .el-alert {
      padding: 6px 12px;
    }
    .list-actions {
      float: right;
      display: flex;
      align-items: center;
      gap: 4px;
    }
    .list-actions >>> .el-tag {
      height: 24px;
      line-height: 22px;
      padding: 0 6px;
    }
    .clear-all-btn {
      margin-left: 10px;
      margin-left: 8px;
    }
    .empty-state {
      text-align: center;
      padding: 40px 0;
      color: #909399;
    }
    .empty-state i {
      font-size: 48px;
      margin-bottom: 10px;
    }
    .material-code {
      font-family: 'Courier New', monospace;
      font-weight: bold;
      color: #409EFF;
    }
    .tray-info {
      background: #f0f9ff;
      padding: 10px 15px;
      border-radius: 4px;
      margin-bottom: 15px;
      border-left: 4px solid #409EFF;
    .location-info {
        color: #606266;
        font-weight: normal;
    }
    .debug-info {
      background: #f5f7fa;
      padding: 10px;
      padding: 8px;
      border-radius: 4px;
      margin-top: 10px;
      font-size: 12px;
      margin-top: 8px;
      font-size: 11px;
      color: #909399;
    }
    .small-button {
      padding: 7px 9px;
      font-size: 12px;
      padding: 6px 8px;
      font-size: 11px;
    }
.custom-input-group {
  display: flex;
  align-items: center;
  width: 100%;
  margin: 20px 0;
  border: 1px solid #DCDFE6;
  border-radius: 4px;
  overflow: hidden;
  background: #fff;
}
.input-label {
  padding: 0 15px;
  background: #F5F7FA;
  border-right: 1px solid #DCDFE6;
  color: #606266;
  font-size: 14px;
  white-space: nowrap;
  height: 40px;
  line-height: 40px;
  flex-shrink: 0;
}
    /* è¾“入框组样式调整 */
    .custom-input-group {
      display: flex;
      align-items: center;
      width: 100%;
      margin: 8px 0;
      border: 1px solid #DCDFE6;
      border-radius: 4px;
      overflow: hidden;
      background: #fff;
    }
.input-container {
  display: flex;
  flex: 1;
  align-items: center;
}
    .input-label {
      padding: 0 12px;
      background: #F5F7FA;
      border-right: 1px solid #DCDFE6;
      color: #606266;
      font-size: 13px;
      white-space: nowrap;
      height: 36px;
      line-height: 36px;
      flex-shrink: 0;
      min-width: 70px;
      text-align: center;
    }
.custom-input {
  flex: 1;
}
    .input-container {
      display: flex;
      flex: 1;
      align-items: center;
    }
.custom-input ::v-deep .el-input__inner {
  border: none;
  border-radius: 0;
  height: 40px;
  line-height: 40px;
}
    .custom-input {
      flex: 1;
    }
    .custom-input >>> .el-input__inner {
      border: none;
      border-radius: 0;
      height: 36px;
      line-height: 36px;
      font-size: 13px;
    }
    /* å“åº”式调整 */
    @media (max-width: 768px) {
      .barcode-scanner-container {
        padding: 5px;
      }
      .custom-input-group {
        flex-direction: column;
        border: none;
      }
      .input-label {
        width: 100%;
        border-right: none;
        border-bottom: 1px solid #DCDFE6;
        margin-bottom: 5px;
      }
      .input-container {
        width: 100%;
        border: 1px solid #DCDFE6;
        border-radius: 4px;
      }
    }
</style>