pages/sockroom/sockroom.vue
@@ -1,18 +1,24 @@
<template>
   <view class="sockpage">
      <view class="column">
         <!-- 托盘编码栏(对应后端barcode) -->
         <view class="form-card">
            <view class="form-row">
               <view class="label">
                  <text class="required">*</text>托盘编码:
               </view>
               <view class="picker-wrap" @click="scan" hover-class="picker-hover">
               <view class="picker-wrap" hover-class="picker-hover">
                  <view class="input-box">
                     <text class="input-placeholder" v-if="!barcode">点击扫码录入</text>
                     <text class="input-value" v-else>{{barcode}}</text>
                     <input
                     id="pdacode"
                     type="text"
                     ref="barcodeInput"
                     v-model="barcode"
                     placeholder="请扫码(12位以下为托盘码)"
                     :focus="focusState"
                     @focus="focusFn"
                     @blur="focusState = false"
                     />
                  </view>
                  <view class="scan-icon">📷</view>
               </view>
            </view>
         </view>
@@ -44,8 +50,9 @@
                     class="material-input" 
                     type="text" 
                     v-model="matList.model"
                     placeholder="请输入卷号"
                     placeholder="请扫码或输入卷号"
                     placeholder-class="input-placeholder"
                     ref="modelInput"
                  />
               </view>
               <view class="material-item">
@@ -54,8 +61,9 @@
                     class="material-input" 
                     type="text" 
                     v-model="matList.batch"
                     placeholder="请输入箱号"
                     placeholder="请扫码或输入箱号"
                     placeholder-class="input-placeholder"
                     ref="batchInput"
                  />
               </view>
               <view class="material-item">
@@ -74,7 +82,7 @@
                     class="material-input" 
                     type="number" 
                     v-model="matList.rollExtent"
                     placeholder="请输入长度(m)"
                     placeholder="请输入长度"
                     placeholder-class="input-placeholder"
                  />
               </view>
@@ -84,7 +92,7 @@
                     class="material-input" 
                     type="number" 
                     v-model="matList.weight"
                     placeholder="请输入净重(kg)"
                     placeholder="请输入净重"
                     placeholder-class="input-placeholder"
                  />
               </view>
@@ -94,7 +102,7 @@
                     class="material-input" 
                     type="number" 
                     v-model="matList.roughWeight"
                     placeholder="请输入毛重(kg)"
                     placeholder="请输入毛重"
                     placeholder-class="input-placeholder"
                  />
               </view>
@@ -113,7 +121,7 @@
         
         <!-- 操作按钮组 -->
         <view class="btn-group">
            <button class="operate-btn scan-btn" @click="scantwo">扫货物码</button>
            <button class="operate-btn scan-btn" @click="startScan">开始扫码</button>
            <button class="operate-btn submit-btn" @click="submit">成品入库</button>
         </view>
      </view>
@@ -131,8 +139,18 @@
      // 页面加载时 mode 为空,调用接口后才填充数据
      this.POSTinfo(); 
   },
   mounted() {
      this.setupScanListener();
   },
   beforeDestroy() {
      this.removeScanListener();
   },
   data() {
      return {
         focusState: false,
         baseUrl: '',
         barcodeNum:'',
         barcode: '', // 托盘码
@@ -149,16 +167,21 @@
            anfme: 1.0, // 默认值1.0
            rollExtent: '', // 卷长度
            joint: 0, // 接头
            cutting: 2, // 默认“否”
            qualified: 0, // 默认“否”
            cutting: 2,
            qualified: 0,
            modelFront: '', // 分切前箱编号
            batchFront: '' ,// 分切前卷号
         },
         // 关键1:初始化 mode 为空数组 → 页面加载时箱型无数据
         // 初始化 mode 为空数组 → 页面加载时箱型无数据
         mode: [], 
         index_mode: 0,
         index_num: 0,
         submitData: {} // 最终提交给后端的数据
         submitData: {} ,// 最终提交给后端的数据
         scanBuffer: '', // 添加扫码缓冲区
         scanTimeout: null, // 扫码超时定时器
         isScanning: false, // 扫码状态标志
         scanMode: 'tray', // 扫码模式: tray-托盘码, material-物料码
         lastFillTarget: null // 记录上次填充的目标
      }
   },
   methods: {
@@ -179,14 +202,218 @@
            }
         })
      },
      // 设置扫码监听
      setupScanListener() {
         // 移除之前的监听
         this.removeScanListener();
         // 监听键盘输入事件
         document.addEventListener('keydown', this.handleKeyDown);
      },
      // 移除监听
      removeScanListener() {
         document.removeEventListener('keydown', this.handleKeyDown);
         if (this.scanTimeout) {
            clearTimeout(this.scanTimeout);
         }
      },
      // 键盘事件处理
      handleKeyDown(e) {
         // 排除功能键(F1-F12等)
         if (e.key.length > 1 && !['Enter', 'Tab'].includes(e.key)) {
            return;
         }
         // PDA扫码通常以回车结束
         if (e.key === 'Enter') {
            e.preventDefault(); // 阻止默认行为
            this.processScanCode();
         } else {
            // 累积扫码字符(排除Shift等修饰键)
            if (!e.ctrlKey && !e.altKey && !e.metaKey && e.key.length === 1) {
               this.scanBuffer += e.key;
               // 重置超时定时器
               if (this.scanTimeout) {
                  clearTimeout(this.scanTimeout);
               }
               // 设置超时(假设扫码间隔超过200ms表示一次扫码完成)
               this.scanTimeout = setTimeout(() => {
                  this.processScanCode();
               }, 200);
            }
         }
      },
      // 处理扫码结果
      processScanCode() {
         if (!this.scanBuffer) return;
         const scanResult = this.scanBuffer.trim();
         this.scanBuffer = '';
         // 判断扫码长度决定填充位置
         if (scanResult.length <= 12) {
            // 12位以下填充到托盘编码
            this.barcode = scanResult;
            this.lastFillTarget = 'tray';
            uni.showToast({
               title: '托盘码已填充',
               icon: 'success',
               duration: 1000
            });
         } else {
            // 12位以上填充到物料信息
            this.autoFillMaterialInfo(scanResult);
            this.lastFillTarget = 'material';
            uni.showToast({
               title: '物料码已填充',
               icon: 'success',
               duration: 1000
            });
         }
         // 清除定时器
         if (this.scanTimeout) {
            clearTimeout(this.scanTimeout);
            this.scanTimeout = null;
         }
         // 自动失焦
         setTimeout(() => {
            this.focusState = false;
         }, 100);
      },
      // 自动填充物料信息
      autoFillMaterialInfo(code) {
         // 尝试解析二维码内容
         if (code.includes('卷号:') && code.includes('箱号:')) {
            // 如果是带格式的二维码
            const parseResult = this.parseQrCodeText(code);
            this.matList = { ...this.matList, ...parseResult };
            console.log('解析后的物料信息:', parseResult);
         } else {
            // 如果是纯数字/条码,智能填充
            this.smartFillMaterialFields(code);
         }
      },
      // 智能填充物料字段
      smartFillMaterialFields(code) {
         // 根据业务逻辑判断,这里假设长条码可能是卷号或箱号
         // 如果卷号为空,优先填充卷号
         if (!this.matList.model) {
            this.matList.model = code;
         }
         // 如果卷号已有值但箱号为空,填充箱号
         else if (!this.matList.batch) {
            this.matList.batch = code;
         }
         // 如果两者都有值,提示用户
         else {
            uni.showModal({
               title: '提示',
               content: `扫描到长条码: ${code}\n请选择填充位置:`,
               showCancel: true,
               cancelText: '卷号',
               confirmText: '箱号',
               success: (res) => {
                  if (res.confirm) {
                     this.matList.batch = code;
                  } else if (res.cancel) {
                     this.matList.model = code;
                  }
               }
            });
         }
      },
      // 解析二维码文本(用于扫货物码功能)
      parseQrCodeText(qrText) {
         const result = {};
         const lines = qrText.split('\n');
         lines.forEach(line => {
            if (line.includes('卷号:')) {
               result.model = line.split('卷号:')[1]?.trim() || '';
            }
            if (line.includes('箱号:')) {
               result.batch = line.split('箱号:')[1]?.trim() || '';
            }
            if (line.includes('规格:')) {
               result.matnr = line.split('规格:')[1]?.trim() || '';
            }
            // 可以根据需要添加更多字段的解析
         });
         return result;
      },
      // 手动开始扫码
      startScan() {
         // 清空当前值并聚焦
         this.scanBuffer = '';
         this.$nextTick(() => {
            this.focusState = true;
            // 延迟确保input已聚焦
            setTimeout(() => {
               const input = document.getElementById('pdacode');
               if (input) {
                  input.focus();
                  input.select();
               }
            }, 100);
         });
      },
      // 修改focusFn
      focusFn() {
         this.focusState = true;
         this.scanBuffer = ''; // 聚焦时清空缓冲区
      },
      // 保留原有的扫货物码功能
      scantwo() {
         uni.scanCode({
            autoDecodeCharSet: true,
            scanType: ['qrCode', 'barCode'],
            success: (res) => {
               const qrResult = res.result.trim();
               this.autoFillMaterialInfo(qrResult);
               uni.showToast({
                  title: '物料信息扫码成功',
                  icon: 'success',
                  duration: 2000
               });
            },
            fail: (err) => {
               console.log('扫码失败:', err);
               uni.showToast({
                  title: '扫码失败或取消',
                  icon: 'none'
               });
            }
         });
      },
      modePickerChange(e) {
         this.index_mode = e.detail.value;
         this.boxType = this.mode[this.index_mode]; // 同步到boxType
      },
      numPickerChange(e) {
         this.index_num = e.detail.value
         this.index_num = e.detail.value;
      },
      // 关键2:修改重置方法 → 清空 mode 及相关状态
      // 修改重置方法
      resetForm() {
         this.barcodeNum = '';
         this.barcode = ''; 
@@ -194,9 +421,11 @@
         this.index_mode = 0; 
         this.index_num = 0; 
         this.submitData = {}; 
         // 清空 mode 数组 → 箱型选择器恢复无数据状态
         this.mode = [];
         // 重置物料信息(保留默认值)
         this.lastFillTarget = null;
         this.scanBuffer = '';
         // 重置物料信息
         this.matList = {
            matnr: '',
            maktx: '',
@@ -213,129 +442,68 @@
            modelFront: '',
            batchFront: ''
         };
         // 可选:重置后重新请求箱型数据(根据需求选择)
         // this.POSTinfo();
      },
      submit(){
          // 校验必填项
          if(!this.barcode) return uni.showToast({title: '请扫描托盘编码', icon: 'none'})
          if(!this.boxType) return uni.showToast({title: '请选择箱型', icon: 'none'})
          if(!this.matList.model || !this.matList.batch) return uni.showToast({title: '请填写卷号/箱号', icon: 'none'})
          // 数据类型转换
          const matItem = {
              ...this.matList,
              weight: this.matList.weight ? Number(this.matList.weight) : null,
              roughWeight: this.matList.roughWeight ? Number(this.matList.roughWeight) : null,
              rollExtent: this.matList.rollExtent ? Number(this.matList.rollExtent) : null,
              joint: this.matList.joint ? Number(this.matList.joint) : 0,
              anfme: 1.0,
              cutting: 2,
              qualified: 0
          }
          // 组装提交数据
          this.submitData = {
              barcode: this.barcode,
              palletizingNo: this.palletizingNo,
              boxType: this.boxType,
              matList: [matItem]
          }
          console.log('修正类型后的提交数据:', this.submitData)
          // 提交请求
          uni.request({
              url: this.baseUrl + '/mobile/truss/comd/auth/v2',
              method: 'POST',
              header: {'Content-Type': 'application/json'},
              data: this.submitData,
              success: (res) => {
                  console.log('后端返回:', res)
                  uni.showToast({title:'提交成功',icon: 'success'})
                  // 提交成功后重置所有数据
                  this.resetForm();
                  // 可选:重置后重新拉取箱型数据,方便下次操作
                  // setTimeout(() => {
                  //     this.POSTinfo();
                  // }, 300);
              },
              fail: (err) => {
                  console.error('请求失败详情:', err)
                  uni.showToast({title:'提交失败',icon: 'none'})
              },
              complete: (res) => {
                  console.log('请求完成状态:', res)
              }
          })
      },
      scan(){
         uni.scanCode({
            autoDecodeCharSet: true,
            scanType: ['barCode'],
            onlyFromCamera: true,
            continuousScan: false,
            camera: 'back',
            timeout: 5000,
      submit() {
         // 校验必填项
         if (!this.barcode) {
            uni.showToast({title: '请扫描托盘编码', icon: 'none'});
            return;
         }
         if (!this.boxType) {
            uni.showToast({title: '请选择箱型', icon: 'none'});
            return;
         }
         if (!this.matList.model || !this.matList.batch) {
            uni.showToast({title: '请填写卷号和箱号', icon: 'none'});
            return;
         }
         // 数据类型转换
         const matItem = {
            ...this.matList,
            weight: this.matList.weight ? Number(this.matList.weight) : null,
            roughWeight: this.matList.roughWeight ? Number(this.matList.roughWeight) : null,
            rollExtent: this.matList.rollExtent ? Number(this.matList.rollExtent) : null,
            joint: this.matList.joint ? Number(this.matList.joint) : 0,
            anfme: 1.0,
            cutting: 2,
            qualified: 0
         };
         // 组装提交数据
         this.submitData = {
            barcode: this.barcode,
            palletizingNo: this.palletizingNo,
            boxType: this.boxType,
            matList: [matItem]
         };
         console.log('提交数据:', this.submitData);
         // 提交请求
         uni.request({
            url: this.baseUrl + '/mobile/truss/comd/auth/v2',
            method: 'POST',
            header: {'Content-Type': 'application/json'},
            data: this.submitData,
            success: (res) => {
               this.barcodeNum = res.result
               this.barcode = res.result
               uni.showToast({title: `托盘编码扫码成功`,icon: 'success'})
               console.log('后端返回:', res);
               if (res.data && res.data.code === 200) {
                  uni.showToast({title: '提交成功', icon: 'success'});
                  this.resetForm();
               } else {
                  uni.showToast({title: res.data.message || '提交失败', icon: 'none'});
               }
            },
            fail: (err) => {
               uni.showToast({title: '扫码失败或取消',icon: 'none'})
            }
         })
      },
      parseQrCodeText(text) {
         const result = {};
         const regMap = {
            model: /卷号:(.+)/,
            batch: /箱号:(.+)/,
            matnr: /规格:(.+)/,
            rollExtent: /长度:(.+?)\s*m/,
            weight: /净重:(.+?)\s*kg/,
            roughWeight: /毛重:(.+?)\s*kg/,
            joint: /接头:(.+?)\s*个/
         };
         Object.keys(regMap).forEach(key => {
            const match = text.match(regMap[key]);
            if (match && match[1]) {
               result[key] = match[1].trim();
               console.error('请求失败详情:', err);
               uni.showToast({title: '网络请求失败', icon: 'none'});
            }
         });
         return result;
      },
      scantwo(){
         uni.scanCode({
            autoDecodeCharSet:true,
            scanType: ['qrCode'],
            success: (res) => {
               const qrResult = res.result.trim();
               this.barcodeNum = qrResult;
               let parseResult = {};
               try {
                  parseResult = JSON.parse(qrResult);
                  parseResult = {
                     model: parseResult.卷号 || '',
                     batch: parseResult.箱号 || '',
                     matnr: parseResult.规格 || '',
                     rollExtent: (parseResult.长度 || '').replace(/\s*m/g, '') || '',
                     weight: (parseResult.净重 || '').replace(/\s*kg/g, '') || '',
                     roughWeight: (parseResult.毛重 || '').replace(/\s*kg/g, '') || '',
                     joint: (parseResult.接头 || '').replace(/\s*个/g, '') || ''
                  };
               } catch (e) {
                  parseResult = this.parseQrCodeText(qrResult);
               }
               this.matList = { ...this.matList, ...parseResult };
               uni.showToast({title: `物料信息扫码成功`,icon: 'success'});
            },
            fail: (err) => {
               uni.showToast({title: '扫码失败或取消',icon: 'none'})
            }
         })
      }
   }
}
@@ -426,11 +594,6 @@
.input-box:focus-within {
   border-color: #f97316;
}
/* 占位符样式 */
.input-placeholder {
   color: #9ca3af;
}
/* 输入值样式 */