xwt
2025-09-30 e9330bc1e2449b5763097dff4cb896746fda8d4d
pages/QC/LLJ/Add.vue
@@ -82,7 +82,7 @@
          <view class="info-label">备注:</view>
          <input type="text" id="lotNo1" v-model="formData.lotNo1" 
                             placeholder="请输入备注信息" 
                             style="color: red; font-weight: bold;"/>
                             style="color: red; font-weight: bold; background-color: #fff !important; -webkit-user-select: text !important; -moz-user-select: text !important; -ms-user-select: text !important; user-select: text !important; pointer-events: auto !important; opacity: 1 !important; z-index: 1 !important;"/>
      </view>
      <view class="info-block" style="margin-top: 10px;">   
          <view class="info-label">破坏实验数量:</view>
@@ -92,6 +92,7 @@
      <!-- 表单上方操作按钮区 -->
      <view class="top-action-buttons">
         <button class="action-btn" @click="getInspectionItems" v-if="this.current">获取检验项目</button>
         <button class="action-btn" @click="openGlobalBlockHoleDialog" v-if="this.current">堵穴设置</button>
         <button class="action-btn" @click="handleEmergencyRelease" v-if="this.current">紧急放行</button>
         <button class="action-btn" @click="handleWithdraw" v-if="this.current">撤回</button>
      </view>
@@ -146,7 +147,7 @@
            <form>
               <view class="form-group">
                  <label class="form-label">不合格描述:</label>
                  <input class="form-input" type="text" v-model="remarks" />
                  <input class="info-input" type="text" v-model="remarks" placeholder="请输入不合格描述" />
               </view>
            </form>
@@ -156,18 +157,163 @@
      </view>
      
      <view v-if="destructionPopup" class="overlay">
         <view class="popup">
            <h3>破坏实验数量</h3>
            <form>
               <view class="form-group">
                  <label class="form-label">破坏实验数量:</label>
                  <input class="form-input" type="text" v-model="PHSY" placeholder="留空表示清除数量" />
         <view class="popup destruction-popup">
            <h3>破坏实验</h3>
            <!-- 第一步:扫描二维码(无记录时显示) -->
            <view v-if="!hasExistingRecord && !scannedMaterialInfo" class="scan-step">
               <view class="scan-icon">📷</view>
               <view class="scan-title">扫描物料二维码</view>
               <view class="scan-description">请扫描要用于破坏实验的物料条码</view>
               <view class="scan-actions">
                  <button class="scan-btn" @click="scanQRCode">开始扫描</button>
                  <button class="destruction-btn cancel-btn" @click="closeDestructionPopup">返回</button>
               </view>
            </form>
            <div v-if="!isInteger" class="error-message">请输入整数值或留空</div>
            <button class="updateBut" @click="editDestruction">修改</button>
            <button @click="clearDestruction">清除</button>
            <button @click="destructionPopup = !destructionPopup">取消</button>
            </view>
            <!-- 第二步:显示扫描结果和输入数量(无记录时扫描后显示) -->
            <view v-if="!hasExistingRecord && scannedMaterialInfo" class="result-step">
               <view class="scan-success-icon">✅</view>
               <view class="scan-success-title">扫描成功</view>
               <!-- 显示扫描到的物料信息 -->
               <view class="material-info-display">
                  <view class="material-detail">
                     <view class="detail-row">
                        <span class="detail-label">扫描条码:</span>
                        <span class="detail-value barcode-value">{{ scannedMaterialInfo.itemBarcode || scannedMaterialInfo.itemNo }}</span>
                     </view>
                     <view class="detail-row">
                        <span class="detail-label">物料编码:</span>
                        <span class="detail-value">{{ scannedMaterialInfo.itemNo }}</span>
                     </view>
                     <view class="detail-row">
                        <span class="detail-label">物料名称:</span>
                        <span class="detail-value">{{ scannedMaterialInfo.itemName }}</span>
                     </view>
                     <view class="detail-row">
                        <span class="detail-label">规格型号:</span>
                        <span class="detail-value">{{ scannedMaterialInfo.itemModel }}</span>
                     </view>
                     <view class="detail-row">
                        <span class="detail-label">到货单号:</span>
                        <span class="detail-value">{{ scannedMaterialInfo.billNo }}</span>
                     </view>
                     <view class="detail-row">
                        <span class="detail-label">可用数量:</span>
                        <span class="detail-value">{{ scannedMaterialInfo.oldQty }}</span>
                     </view>
                  </view>
               </view>
               <!-- 重新设计的输入区域 -->
               <view class="input-section">
                  <view class="input-title">破坏实验数量</view>
                  <view class="input-container">
                     <view class="input-box" @click="focusInput">
                        <text v-if="destructionQuantity" class="input-value">{{ destructionQuantity }}</text>
                        <text v-else class="input-placeholder">点击输入数量</text>
                     </view>
                  </view>
                  <view v-if="!isInteger && destructionQuantity" class="error-tip">请输入有效的正整数</view>
               </view>
               <!-- 操作按钮 -->
               <view class="destruction-actions">
                  <!-- 无记录时显示:确认、修改、删除、返回 -->
                  <template v-if="!hasExistingRecord">
                     <button class="destruction-btn confirm-btn" @click="confirmDestruction" :disabled="!isInteger || !destructionQuantity">确认</button>
                     <button class="destruction-btn modify-btn" @click="modifyDestruction">修改</button>
                     <button class="destruction-btn delete-btn" @click="deleteDestruction">删除</button>
                     <button class="destruction-btn cancel-btn" @click="resetDestruction">返回</button>
                  </template>
                  <!-- 有记录时显示:修改、删除、返回 -->
                  <template v-else>
                     <button class="destruction-btn modify-btn" @click="modifyDestruction">修改</button>
                     <button class="destruction-btn delete-btn" @click="deleteDestruction">删除</button>
                     <button class="destruction-btn cancel-btn" @click="resetDestruction">返回</button>
                  </template>
               </view>
            </view>
            <!-- 第三步:显示已有记录信息(有记录时显示,复用扫描结果界面) -->
            <view v-if="hasExistingRecord" class="result-step">
               <view class="scan-success-icon">✅</view>
               <view class="scan-success-title">扫描成功</view>
               <!-- 显示扫描到的物料信息 -->
               <view class="material-info-display">
                  <view class="material-detail">
                     <view class="detail-row">
                        <span class="detail-label">扫描条码:</span>
                        <span class="detail-value barcode-value">{{ (scannedMaterialInfo && scannedMaterialInfo.itemBarcode) || (scannedMaterialInfo && scannedMaterialInfo.itemNo) || '' }}</span>
                     </view>
                     <view class="detail-row">
                        <span class="detail-label">物料编码:</span>
                        <span class="detail-value">{{ (scannedMaterialInfo && scannedMaterialInfo.itemNo) || '' }}</span>
                     </view>
                     <view class="detail-row">
                        <span class="detail-label">物料名称:</span>
                        <span class="detail-value">{{ (scannedMaterialInfo && scannedMaterialInfo.itemName) || '' }}</span>
                     </view>
                     <view class="detail-row">
                        <span class="detail-label">规格型号:</span>
                        <span class="detail-value">{{ (scannedMaterialInfo && scannedMaterialInfo.itemModel) || '' }}</span>
                     </view>
                     <view class="detail-row">
                        <span class="detail-label">到货单号:</span>
                        <span class="detail-value">{{ (scannedMaterialInfo && scannedMaterialInfo.billNo) || formData.lotNo }}</span>
                     </view>
                     <view class="detail-row">
                        <span class="detail-label">可用数量:</span>
                        <span class="detail-value">{{ (scannedMaterialInfo && scannedMaterialInfo.oldQty) || '0' }}</span>
                     </view>
                  </view>
               </view>
               <!-- 重新设计的输入区域 -->
               <view class="input-section">
                  <view class="input-title">破坏实验数量</view>
                  <view class="input-container">
                     <view class="input-box" @click="focusInput">
                        <text v-if="destructionQuantity" class="input-value">{{ destructionQuantity }}</text>
                        <text v-else class="input-placeholder">点击输入数量</text>
                     </view>
                  </view>
                  <view v-if="!isInteger && destructionQuantity" class="error-tip">请输入有效的正整数</view>
               </view>
               <!-- 操作按钮 -->
               <view class="destruction-actions">
                  <button class="destruction-btn modify-btn" @click="modifyDestruction">修改</button>
                  <button class="destruction-btn delete-btn" @click="deleteDestruction">删除</button>
                  <button class="destruction-btn cancel-btn" @click="resetDestruction">返回</button>
               </view>
            </view>
         </view>
      </view>
      <!-- 全局堵穴设置对话框 -->
      <view v-if="globalBlockHolePopup" class="overlay">
         <view class="popup global-block-hole-popup">
            <h3>全局堵穴设置</h3>
            <view class="block-hole-content">
               <view class="hole-info">
                  <view class="info-label">检验单号:{{ formData.releaseNo }}</view>
                  <view class="info-label">将应用于所有有开穴数的检验项目</view>
               </view>
               <view class="input-section">
                  <view class="input-label">堵穴数量:</view>
                  <input class="info-input" type="text" v-model="globalBlockHoleInput"
                     placeholder="请输入1,2,3" @input="onGlobalBlockHoleInput" />
                  <view v-if="globalBlockHoleError" class="error-message">{{ globalBlockHoleError }}</view>
               </view>
               <view class="block-hole-actions">
                  <button class="block-hole-btn confirm" @click="confirmGlobalBlockHole"
                     :disabled="!isGlobalBlockHoleValid">确认设置</button>
                  <button class="block-hole-btn cancel" @click="closeGlobalBlockHoleDialog">取消</button>
               </view>
            </view>
         </view>
      </view>
      
@@ -384,6 +530,10 @@
            destructionPopup: false,
            PHSY: '',
            isInteger: true,
            scannedMaterialInfo: null, // 扫描到的物料信息
            destructionQuantity: '', // 破坏实验数量输入
            inputFocus: false, // 输入框焦点状态
            hasExistingRecord: false, // 是否有已存在的破坏实验记录
            attachments: [],
            showAttachmentPopup: false,
            attachmentsLoading: false,
@@ -394,6 +544,12 @@
            previewTitle: '',
            previewItemNo: '',
            previewType: '', // 'text', 'image', 'excel', 'unsupported'
            // 全局堵穴相关数据
            globalBlockHolePopup: false,
            globalBlockHoleInput: '',
            globalBlockHoleError: '',
            isGlobalBlockHoleValid: false,
            
         }
      },
@@ -523,6 +679,7 @@
            this.remarks = this.formData.remarks || this.remarks || '';
            console.log('打开弹窗时的remarks值:', this.remarks);
         },
         // picker 事件处理方法
         onBadreasonChange(e) {
            const index = e.detail.value;
@@ -1334,11 +1491,550 @@
               },
         addDestruction() {
            // 添加破坏实验的逻辑
            this.destructionPopup = !this.destructionPopup;
            // 修复:确保PHSY变量正确初始化
            this.PHSY = this.formData.PHSY || '';
            this.destructionPopup = true;
            // 每次点击都查询是否已有破坏实验记录
            this.checkPhsyRecord();
         },
         // 查询破坏实验记录是否存在
         checkPhsyRecord() {
            uni.showLoading({
               title: '查询破坏实验记录...'
            });
            this.$post({
               url: "/LLJ/CheckPhsyRecord",
               data: {
                  billNo: this.formData.lotNo, // 使用到货单号
                  releaseNo: this.formData.releaseNo // 使用检验单号
               }
            }).then(res => {
               uni.hideLoading();
               if (res.status === 0) {
                  const hasRecord = res.data.exists;
                  if (hasRecord) {
                     // 有记录,显示物料信息,只显示修改、删除、返回按钮
                     this.showExistingRecord();
                  } else {
                     // 无记录,显示扫描界面
                     this.showScanInterface();
                  }
               } else {
                  uni.showToast({
                     title: res.message || '查询失败',
                     icon: 'none'
                  });
                  this.destructionPopup = false;
               }
            }).catch(err => {
               uni.hideLoading();
               console.error('查询破坏实验记录失败:', err);
               uni.showToast({
                  title: '查询失败,请重试',
                  icon: 'none'
               });
               this.destructionPopup = false;
            });
         },
         // 显示已有记录
         showExistingRecord() {
            // 设置已有记录状态
            this.hasExistingRecord = true;
            // 获取破坏实验记录中的物料信息
            this.getPhsyRecordInfo();
         },
         // 获取破坏实验记录信息
         getPhsyRecordInfo() {
            uni.showLoading({
               title: '获取破坏实验记录...'
            });
            this.$post({
               url: "/LLJ/GetPhsyRecordInfo",
               data: {
                  billNo: this.formData.lotNo, // 使用到货单号
                  releaseNo: this.formData.releaseNo // 使用检验单号
               }
            }).then(res => {
               uni.hideLoading();
               if (res.status === 0 && res.data && res.data.tbBillList && res.data.tbBillList.length > 0) {
                  // 获取到破坏实验记录,设置物料信息
                  const record = res.data.tbBillList[0];
                  this.scannedMaterialInfo = {
                     itemBarcode: record.itemBarcode,
                     itemNo: record.itemNo,
                     itemName: record.itemName,
                     itemModel: record.itemModel,
                     billNo: record.billNo,
                     oldQty: record.yqty
                  };
                  // 设置破坏实验数量
                  this.destructionQuantity = record.cqty ? record.cqty.toString() : '';
               } else {
                  // 如果没有获取到详细信息,显示提示
                  uni.showToast({
                     title: '已存在破坏实验记录',
                     icon: 'none',
                     duration: 1500
                  });
               }
            }).catch(err => {
               uni.hideLoading();
               console.error('获取破坏实验记录失败:', err);
               uni.showToast({
                  title: '获取记录失败,请重试',
                  icon: 'none'
               });
            });
         },
         // 显示扫描界面
         showScanInterface() {
            // 设置无记录状态
            this.hasExistingRecord = false;
            // 如果已经有扫描的物料信息,直接显示结果步骤
            if (this.scannedMaterialInfo) {
               // 保持当前扫描信息,不重置
               return;
            }
            // 如果没有扫描信息,重置所有相关数据
            this.scannedMaterialInfo = null;
            this.destructionQuantity = '';
            this.isInteger = true;
         },
         // 扫描二维码
         scanQRCode() {
            // #ifdef APP-PLUS
            // APP环境使用uni.scanCode
            uni.scanCode({
               success: (res) => {
                  console.log('扫描结果:', res.result);
                  this.processQRCodeResult(res.result);
               },
               fail: (err) => {
                  console.error('扫描失败:', err);
                  uni.showToast({
                     title: '扫描失败,请重试',
                     icon: 'none'
                  });
               }
            });
            // #endif
            // #ifdef H5
            // H5环境提示用户手动输入
            uni.showModal({
               title: '二维码扫描',
               content: 'H5环境暂不支持摄像头扫描,请输入二维码内容',
               editable: true,
               placeholderText: '请输入二维码内容',
               success: (res) => {
                  if (res.confirm && res.content) {
                     this.processQRCodeResult(res.content);
                  }
               }
            });
            // #endif
            // #ifdef MP
            // 小程序环境使用wx.scanCode
            wx.scanCode({
               success: (res) => {
                  console.log('扫描结果:', res.result);
                  this.processQRCodeResult(res.result);
               },
               fail: (err) => {
                  console.error('扫描失败:', err);
                  uni.showToast({
                     title: '扫描失败,请重试',
                     icon: 'none'
                  });
               }
            });
            // #endif
         },
         // 处理二维码扫描结果
         processQRCodeResult(qrCodeResult) {
            if (!qrCodeResult) {
               uni.showToast({
                  title: '二维码内容为空',
                  icon: 'none'
               });
               return;
            }
            // 显示加载提示
            uni.showLoading({
               title: '查询物料信息...'
            });
            // 调用后端接口查询物料信息
            this.$post({
               url: "/LLJ/GetMaterialByBarcode",
               data: {
                  itemBarcode: qrCodeResult,
                  currentBillNo: this.formData.lotNo  // 传递当前检验单的到货单号
               }
            }).then(res => {
               uni.hideLoading();
               if (res.status === 0 && res.data && res.data.tbBillList && res.data.tbBillList.length > 0) {
                  // 查询成功,验证物料ID是否与检验单一致
                  const scannedMaterial = res.data.tbBillList[0];
                  // 检查扫描的物料ID是否与当前检验单的物料ID一致
                  if (this.formData.itemId && scannedMaterial.itemId &&
                     this.formData.itemId.toString() !== scannedMaterial.itemId.toString()) {
                     // 物料ID不一致,显示错误信息
                     this.scannedMaterialInfo = null;
                     uni.showModal({
                        title: '物料不匹配',
                        content: '扫秒的条码不为该检验单物料,请重新扫描',
                        showCancel: false
                     });
                     return;
                  }
                  // 物料ID验证通过,显示物料信息
                  this.scannedMaterialInfo = scannedMaterial;
                  // 保存扫描到的条码值,用于后续调用存储过程
                  this.scannedMaterialInfo.itemBarcode = qrCodeResult;
                  uni.showToast({
                     title: '查询成功',
                     icon: 'success'
                  });
               } else {
                  // 查询失败,显示错误信息
                  this.scannedMaterialInfo = null;
                  uni.showModal({
                     title: '查询失败',
                     content: res.message || '未找到对应的物料信息,请检查二维码是否正确',
                     showCancel: false
                  });
               }
            }).catch(err => {
               uni.hideLoading();
               console.error('查询物料信息失败:', err);
               this.scannedMaterialInfo = null;
               uni.showModal({
                  title: '查询失败',
                  content: '网络错误,请检查网络连接后重试',
                  showCancel: false
               });
            });
         },
         // 测试输入
         testInput() {
            this.destructionQuantity = '5';
            this.validateInteger();
            uni.showToast({
               title: '测试输入完成',
               icon: 'success'
            });
         },
         // 点击输入框
         focusInput() {
            // 使用uni-app的输入弹窗
            uni.showModal({
               title: '输入破坏实验数量',
               content: `可用数量: ${this.scannedMaterialInfo.oldQty}`,
               editable: true,
               placeholderText: '请输入数量',
               success: (res) => {
                  if (res.confirm && res.content) {
                     this.destructionQuantity = res.content;
                     this.validateInteger();
                  }
               }
            });
         },
         // 验证输入是否为整数
         validateInteger() {
            if (!this.destructionQuantity) {
               this.isInteger = true;
               return;
            }
            const value = this.destructionQuantity.toString().trim();
            // 只允许正整数
            this.isInteger = /^[1-9]\d*$/.test(value);
         },
         // 确认破坏实验
         confirmDestruction() {
            if (!this.isInteger || !this.destructionQuantity) {
               uni.showToast({
                  title: '请输入有效的整数数量',
                  icon: 'none'
               });
               return;
            }
            // 检查扫描的物料信息是否存在
            if (!this.scannedMaterialInfo) {
               uni.showToast({
                  title: '请先扫描物料二维码',
                  icon: 'none'
               });
               return;
            }
            // 验证破坏实验数量不能大于可用数量
            const destructionQty = parseInt(this.destructionQuantity);
            const availableQty = parseInt(this.scannedMaterialInfo.oldQty);
            if (destructionQty > availableQty) {
               uni.showModal({
                  title: '数量错误',
                  content: `破坏实验数量(${destructionQty})不能大于可用数量(${availableQty}),请重新填写或重新扫码!`,
                  showCancel: false
               });
               return;
            }
            // 显示加载提示
            uni.showLoading({
               title: '调用存储过程中...'
            });
            // 调用破坏实验存储过程
            this.$post({
               url: "/LLJ/CallPhsyUpdateProcedure",
               data: {
                  itemBarcode: this.scannedMaterialInfo.itemBarcode || this.scannedMaterialInfo.itemNo, // 使用扫描的条码
                  yqty: availableQty, // 扫码查询出来的条码数量
                  cqty: destructionQty, // 填写的破坏实验数量
                  billNo: this.scannedMaterialInfo.billNo, // 查询到的到货单号
                  lx: 1, // 操作类型:1新增
                  releaseNo: this.formData.releaseNo, // 检验单号
                  itemId: this.formData.itemId // 检验单的物料ID
               }
            }).then(res => {
               uni.hideLoading();
               // 检查存储过程返回的结果
               if (res.status === 0) {
                  // 存储过程执行成功
                  this.formData.PHSY = this.destructionQuantity;
                  this.destructionPopup = false;
                  this.hasExistingRecord = true; // 设置为有记录状态
                  uni.showToast({
                     title: '破坏实验记录保存成功',
                     icon: 'success',
                     duration: 2000
                  });
                  // 立即重新加载数据确保同步
                  setTimeout(() => {
                     this.init();
                  }, 500);
               } else {
                  // 存储过程执行失败,显示错误信息
                  uni.showModal({
                     title: '操作失败',
                     content: res.message || '破坏实验记录保存失败',
                     showCancel: false
                  });
               }
            }).catch(err => {
               uni.hideLoading();
               console.error('调用存储过程失败:', err);
               uni.showModal({
                  title: '网络错误',
                  content: '调用存储过程失败,请检查网络连接后重试',
                  showCancel: false
               });
            });
         },
         // 修改破坏实验(只修改数量)
         modifyDestruction() {
            // 显示数量输入界面
            uni.showModal({
               title: '修改破坏实验数量',
               content: '请输入新的破坏实验数量',
               editable: true,
               placeholderText: '请输入数量',
               success: (res) => {
                  if (res.confirm && res.content) {
                     const newQuantity = parseInt(res.content);
                     if (isNaN(newQuantity) || newQuantity <= 0) {
                        uni.showToast({
                           title: '请输入有效的正整数',
                           icon: 'none'
                        });
                        return;
                     }
                     // 调用修改存储过程
                     this.callModifyProcedure(newQuantity);
                  }
               }
            });
         },
         // 调用修改存储过程
         callModifyProcedure(newQuantity) {
            uni.showLoading({
               title: '修改中...'
            });
            // 获取当前扫描的物料信息
            const itemBarcode = (this.scannedMaterialInfo && this.scannedMaterialInfo.itemBarcode) ||
                           (this.scannedMaterialInfo && this.scannedMaterialInfo.itemNo) || '';
            const yqty = (this.scannedMaterialInfo && this.scannedMaterialInfo.oldQty) || 0;
            this.$post({
               url: "/LLJ/CallPhsyUpdateProcedure",
               data: {
                  itemBarcode: itemBarcode, // 使用扫描的条码
                  yqty: yqty, // 使用扫码查询出来的条码数量
                  cqty: newQuantity, // 新的破坏实验数量
                  billNo: this.formData.lotNo, // 到货单号
                  lx: 2, // 操作类型:2修改
                  releaseNo: this.formData.releaseNo, // 检验单号
                  itemId: this.formData.itemId // 检验单的物料ID
               }
            }).then(res => {
               uni.hideLoading();
               if (res.status === 0) {
                  // 修改成功
                  this.formData.PHSY = newQuantity.toString();
                  this.PHSY = newQuantity.toString();
                  this.destructionPopup = false;
                  uni.showToast({
                     title: '修改成功',
                     icon: 'success',
                     duration: 2000
                  });
                  // 重新加载数据
                  setTimeout(() => {
                     this.init();
                  }, 500);
               } else {
                  uni.showModal({
                     title: '修改失败',
                     content: res.message || '修改失败',
                     showCancel: false
                  });
               }
            }).catch(err => {
               uni.hideLoading();
               console.error('修改失败:', err);
               uni.showModal({
                  title: '网络错误',
                  content: '修改失败,请检查网络连接后重试',
                  showCancel: false
               });
            });
         },
         // 删除破坏实验
         deleteDestruction() {
            uni.showModal({
               title: '确认删除',
               content: '确定要删除当前的破坏实验记录吗?',
               success: (res) => {
                  if (res.confirm) {
                     // 调用存储过程删除记录
                     this.callDeleteProcedure();
                  }
               }
            });
         },
         // 调用删除存储过程
         callDeleteProcedure() {
            uni.showLoading({
               title: '删除中...'
            });
            // 获取当前扫描的物料信息
            const itemBarcode = (this.scannedMaterialInfo && this.scannedMaterialInfo.itemBarcode) ||
                           (this.scannedMaterialInfo && this.scannedMaterialInfo.itemNo) || '';
            const yqty = (this.scannedMaterialInfo && this.scannedMaterialInfo.oldQty) || 0;
            const cqty = parseFloat(this.destructionQuantity) || 0; // 使用当前记录的破坏数量
            this.$post({
               url: "/LLJ/CallPhsyUpdateProcedure",
               data: {
                  itemBarcode: itemBarcode, // 使用扫描的条码
                  yqty: yqty, // 使用扫码查询出来的条码数量
                  cqty: cqty, // 使用当前记录的破坏数量
                  billNo: this.formData.lotNo, // 到货单号
                  lx: 3, // 操作类型:3删除
                  releaseNo: this.formData.releaseNo, // 检验单号
                  itemId: this.formData.itemId // 检验单的物料ID
               }
            }).then(res => {
               uni.hideLoading();
               if (res.status === 0) {
                  // 删除成功
                  this.scannedMaterialInfo = null;
                  this.destructionQuantity = '';
                  this.isInteger = true;
                  this.formData.PHSY = '';
                  this.PHSY = '';
                  this.hasExistingRecord = false;
                  this.destructionPopup = false;
                  uni.showToast({
                     title: '删除成功',
                     icon: 'success',
                     duration: 2000
                  });
                  // 重新加载数据
                  setTimeout(() => {
                     this.init();
                  }, 500);
               } else {
                  uni.showModal({
                     title: '删除失败',
                     content: res.message || '删除失败',
                     showCancel: false
                  });
               }
            }).catch(err => {
               uni.hideLoading();
               console.error('删除失败:', err);
               uni.showModal({
                  title: '网络错误',
                  content: '删除失败,请检查网络连接后重试',
                  showCancel: false
               });
            });
         },
         // 重置破坏实验(返回上一步)
         resetDestruction() {
            this.scannedMaterialInfo = null;
            this.destructionQuantity = '';
            this.isInteger = true;
            this.hasExistingRecord = false;
            this.destructionPopup = false; // 直接关闭弹窗,返回到表单
         },
         // 关闭破坏实验弹窗
         closeDestructionPopup() {
            this.destructionPopup = false;
            // 重置所有相关数据
            this.scannedMaterialInfo = null;
            this.destructionQuantity = '';
            this.isInteger = true;
         },
         editDestruction() {
            // 验证输入是否为整数或空字符串
            if(this.PHSY === '') {
@@ -1652,7 +2348,7 @@
         showFilePreview(content, fileName) {
            this.previewContent = content;
            this.previewTitle = fileName;
            this.previewItemNo = this.selectedAttachment?.itemNo || '';
            this.previewItemNo = (this.selectedAttachment && this.selectedAttachment.itemNo) || '';
            this.previewType = this.getFileType(fileName);
            this.showFilePreviewPopup = true;
         },
@@ -2009,6 +2705,163 @@
            }
            // #endif
         },
         // 全局堵穴相关方法
         // 检查检验项目是否有穴数
         hasHoleCount(fcheckItem) {
            if (!fcheckItem) return false;
            const match = fcheckItem.match(/[((](\d+)穴[))]/);
            return match ? true : false;
         },
         // 获取穴数
         getHoleCount(fcheckItem) {
            if (!fcheckItem) return 0;
            const match = fcheckItem.match(/[((](\d+)穴[))]/);
            return match ? parseInt(match[1]) : 0;
         },
         // 打开全局堵穴对话框
         openGlobalBlockHoleDialog() {
            console.log('点击堵穴设置按钮');
            console.log('tableData:', this.tableData);
            // 检查是否有有开穴数的检验项目
            const hasHoleItems = this.tableData.some(item => this.hasHoleCount(item.fcheckItem));
            console.log('hasHoleItems:', hasHoleItems);
            if (!hasHoleItems) {
               uni.showModal({
                  title: '提示',
                  content: '当前检验单没有有开穴数的检验项目',
                  showCancel: false
               });
               return;
            }
            this.globalBlockHoleInput = '';
            this.globalBlockHolePopup = true;
            console.log('设置globalBlockHolePopup为true');
            this.validateGlobalBlockHoleInput();
         },
         // 关闭全局堵穴对话框
         closeGlobalBlockHoleDialog() {
            this.globalBlockHolePopup = false;
            this.globalBlockHoleInput = '';
            this.globalBlockHoleError = '';
            this.isGlobalBlockHoleValid = false;
         },
         // 处理全局堵穴输入(保留原方法以防其他地方调用)
         onGlobalBlockHoleInput(e) {
            console.log('输入事件触发:', e);
            // 兼容不同的事件格式
            const value = e.detail ? e.detail.value : e.target ? e.target.value : e;
            console.log('输入值:', value);
            this.globalBlockHoleInput = value;
            this.validateGlobalBlockHoleInput();
         },
         // 验证全局堵穴输入
         validateGlobalBlockHoleInput() {
            const input = this.globalBlockHoleInput.trim();
            if (!input) {
               this.globalBlockHoleError = '';
               this.isGlobalBlockHoleValid = false;
               return;
            }
            // 验证格式:1,2,3 或 1,2,3
            const blockedHoles = input.split(/[,,]/).map(s => s.trim()).filter(s => s);
            // 检查是否都是有效数字
            const isValid = blockedHoles.every(hole => {
               const num = parseInt(hole);
               return !isNaN(num) && num > 0;
            });
            if (!isValid) {
               this.globalBlockHoleError = '请输入有效的穴号,用逗号分隔';
               this.isGlobalBlockHoleValid = false;
               return;
            }
            // 检查是否有重复
            const uniqueHoles = [...new Set(blockedHoles.map(h => parseInt(h)))];
            if (uniqueHoles.length !== blockedHoles.length) {
               this.globalBlockHoleError = '不能输入重复的穴号';
               this.isGlobalBlockHoleValid = false;
               return;
            }
            this.globalBlockHoleError = '';
            this.isGlobalBlockHoleValid = true;
         },
         // 确认全局堵穴
         confirmGlobalBlockHole() {
            if (!this.isGlobalBlockHoleValid) return;
            uni.showLoading({
               title: '设置堵穴中...'
            });
            // 获取所有有开穴数的检验项目
            const holeItems = this.tableData.filter(item => this.hasHoleCount(item.fcheckItem));
            // 批量调用后端接口设置堵穴
            const promises = holeItems.map(item => {
               return this.$post({
                  url: "/LLJ/SetBlockedHoles",
                  data: {
                     releaseNo: this.formData.releaseNo,
                     blockedHoles: this.globalBlockHoleInput,
                     itemId: item.id
                  }
               });
            });
            Promise.all(promises).then(results => {
               uni.hideLoading();
               // 检查所有请求是否成功
               const failedCount = results.filter(res => res.status !== 0).length;
               if (failedCount === 0) {
                  uni.showToast({
                     title: `成功为${holeItems.length}个检验项目设置堵穴`,
                     icon: 'success',
                     duration: 2000
                  });
                  // 立即关闭对话框
                  this.closeGlobalBlockHoleDialog();
                  // 立即重新加载数据确保同步
                  setTimeout(() => {
                     this.init();
                  }, 500);
               } else {
                  uni.showModal({
                     title: '部分设置失败',
                     content: `${failedCount}个检验项目设置失败,请重试`,
                     showCancel: false
                  });
               }
            }).catch(err => {
               uni.hideLoading();
               console.error('全局堵穴设置失败:', err);
               uni.showModal({
                  title: '网络错误',
                  content: '堵穴设置失败,请检查网络连接后重试',
                  showCancel: false
               });
            });
         },
         
      }
   }
@@ -2379,6 +3232,11 @@
      justify-content: center;
      align-items: center;
      z-index: 1000; /* 提高层级,确保在固定按钮上方 */
   }
   /* 全局堵穴设置对话框需要更高的z-index */
   .global-block-hole-popup {
      z-index: 1001;
   }
   /* 弹窗整体美化 */
@@ -2784,4 +3642,677 @@
      flex-direction: column;
      align-items: center;
   }
   /* 扫描按钮样式 */
   .scan-btn {
      background: linear-gradient(135deg, #4CAF50, #45a049);
      color: white;
      border: none;
      border-radius: 8px;
      padding: 12px 20px;
      font-size: 14px;
      font-weight: 600;
      cursor: pointer;
      transition: all 0.3s ease;
      display: flex;
      align-items: center;
      justify-content: center;
      gap: 8px;
      box-shadow: 0 2px 4px rgba(0,0,0,0.1);
   }
   .scan-btn:hover {
      background: linear-gradient(135deg, #45a049, #3d8b40);
      transform: translateY(-1px);
      box-shadow: 0 4px 8px rgba(0,0,0,0.15);
   }
   /* 物料信息显示样式 */
   .material-info-display {
      margin-top: 16px;
      padding: 16px;
      background: linear-gradient(135deg, #f8f9fa, #e9ecef);
      border-radius: 8px;
      border: 1px solid #dee2e6;
      box-shadow: 0 2px 4px rgba(0,0,0,0.05);
   }
   .material-info-display h4 {
      margin: 0 0 12px 0;
      color: #495057;
      font-size: 16px;
      font-weight: 600;
      text-align: center;
   }
   .material-detail {
      display: flex;
      flex-direction: column;
      gap: 8px;
   }
   .detail-row {
      display: flex;
      align-items: center;
      padding: 6px 0;
      border-bottom: 1px solid #e9ecef;
   }
   .detail-row:last-child {
      border-bottom: none;
   }
   .detail-label {
      min-width: 80px;
      font-weight: 600;
      color: #6c757d;
      font-size: 14px;
   }
   .detail-value {
      flex: 1;
      color: #212529;
      font-size: 14px;
      font-weight: 500;
      word-break: break-all;
   }
   .detail-value.barcode-value {
      font-family: 'Courier New', monospace;
      font-weight: 600;
      color: #2c3e50;
      background-color: #f8f9fa;
      padding: 4px 8px;
      border-radius: 4px;
      border: 1px solid #dee2e6;
      font-size: 13px;
      letter-spacing: 0.5px;
   }
   /* 破坏实验弹窗样式 */
   .destruction-popup {
      width: 90vw;
      max-width: 500px;
      min-height: 300px;
   }
   /* 扫描步骤样式 */
   .scan-step {
      text-align: center;
      padding: 40px 20px;
   }
   /* 已有记录步骤样式 */
   .existing-record-step {
      padding: 20px;
      text-align: center;
   }
   .existing-icon {
      font-size: 48px;
      text-align: center;
      margin-bottom: 16px;
   }
   .existing-title {
      font-size: 18px;
      font-weight: 600;
      color: #2c3e50;
      text-align: center;
      margin-bottom: 12px;
   }
   .existing-description {
      font-size: 14px;
      color: #7f8c8d;
      text-align: center;
      margin-bottom: 20px;
   }
   /* 当前破坏实验数量显示 */
   .current-phsy-display {
      margin: 20px 0;
      padding: 16px;
      background: linear-gradient(135deg, #f8f9fa, #e9ecef);
      border-radius: 8px;
      border: 1px solid #dee2e6;
      box-shadow: 0 2px 4px rgba(0,0,0,0.05);
   }
   .phsy-info {
      display: flex;
      align-items: center;
      justify-content: center;
      gap: 8px;
   }
   .phsy-label {
      font-size: 16px;
      font-weight: 600;
      color: #495057;
   }
   .phsy-value {
      font-size: 18px;
      font-weight: 700;
      color: #e74c3c;
      background-color: #fff;
      padding: 4px 12px;
      border-radius: 4px;
      border: 1px solid #e74c3c;
   }
   .scan-icon {
      font-size: 64px;
      margin-bottom: 20px;
      opacity: 0.8;
   }
   .scan-title {
      font-size: 20px;
      font-weight: 600;
      color: #2c3e50;
      margin-bottom: 12px;
   }
   .scan-description {
      font-size: 14px;
      color: #7f8c8d;
      margin-bottom: 30px;
      line-height: 1.5;
   }
   /* 扫描步骤按钮布局 */
   .scan-actions {
      display: flex;
      gap: 12px;
      justify-content: center;
      align-items: center;
   }
   /* 结果步骤样式 */
   .result-step {
      padding: 20px;
   }
   .scan-success-icon {
      font-size: 48px;
      text-align: center;
      margin-bottom: 16px;
   }
   .scan-success-title {
      font-size: 18px;
      font-weight: 600;
      color: #27ae60;
      text-align: center;
      margin-bottom: 20px;
   }
   /* 破坏实验操作按钮样式 */
   .destruction-actions {
      display: flex;
      gap: 8px;
      margin-top: 24px;
      justify-content: center;
      flex-wrap: wrap;
   }
   .destruction-btn {
      padding: 10px 16px;
      border: none;
      border-radius: 8px;
      font-size: 14px;
      font-weight: 600;
      cursor: pointer;
      transition: all 0.3s ease;
      min-width: 80px;
      display: flex;
      align-items: center;
      justify-content: center;
      flex: 1;
      max-width: 120px;
   }
   .destruction-btn.confirm-btn {
      background: linear-gradient(135deg, #27ae60, #2ecc71);
      color: white;
      box-shadow: 0 2px 8px rgba(39, 174, 96, 0.3);
   }
   .destruction-btn.confirm-btn:hover:not(:disabled) {
      background: linear-gradient(135deg, #229954, #27ae60);
      transform: translateY(-1px);
      box-shadow: 0 4px 12px rgba(39, 174, 96, 0.4);
   }
   .destruction-btn.confirm-btn:disabled {
      background: #bdc3c7;
      color: #7f8c8d;
      cursor: not-allowed;
      transform: none;
      box-shadow: none;
   }
   .destruction-btn.cancel-btn {
      background: linear-gradient(135deg, #95a5a6, #7f8c8d);
      color: white;
      box-shadow: 0 2px 8px rgba(149, 165, 166, 0.3);
   }
   .destruction-btn.cancel-btn:hover {
      background: linear-gradient(135deg, #7f8c8d, #6c7b7d);
      transform: translateY(-1px);
      box-shadow: 0 4px 12px rgba(149, 165, 166, 0.4);
   }
   .destruction-btn.modify-btn {
      background: linear-gradient(135deg, #f39c12, #e67e22);
      color: white;
      box-shadow: 0 2px 8px rgba(243, 156, 18, 0.3);
   }
   .destruction-btn.modify-btn:hover {
      background: linear-gradient(135deg, #e67e22, #d35400);
      transform: translateY(-1px);
      box-shadow: 0 4px 12px rgba(243, 156, 18, 0.4);
   }
   .destruction-btn.delete-btn {
      background: linear-gradient(135deg, #e74c3c, #c0392b);
      color: white;
      box-shadow: 0 2px 8px rgba(231, 76, 60, 0.3);
   }
   .destruction-btn.delete-btn:hover {
      background: linear-gradient(135deg, #c0392b, #a93226);
      transform: translateY(-1px);
      box-shadow: 0 4px 12px rgba(231, 76, 60, 0.4);
   }
   /* 表单输入框样式优化 */
   .form-input {
      width: 100%;
      padding: 12px 16px;
      border: 2px solid #e9ecef;
      border-radius: 8px;
      font-size: 16px;
      transition: border-color 0.3s ease;
      box-sizing: border-box;
      background-color: #fff !important;
      color: #333 !important;
      -webkit-appearance: none;
      -moz-appearance: none;
      appearance: none;
      -webkit-user-select: text !important;
      -moz-user-select: text !important;
      -ms-user-select: text !important;
      user-select: text !important;
      pointer-events: auto !important;
      opacity: 1 !important;
      z-index: 1 !important;
   }
   .form-input:focus {
      border-color: #3498db;
      outline: none;
      box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.1);
      background-color: #fff;
   }
   /* 简单输入框样式 - 参考SJ.vue */
   .info-input {
      flex: 1;
      padding: 12px 16px;
      border: 2px solid #ddd;
      border-radius: 6px;
      background-color: white;
      font-size: 16px;
      width: 100%;
      box-sizing: border-box;
      min-height: 44px;
      line-height: 1.4;
   }
   .info-input:focus {
      border-color: #3498db;
      outline: none;
      box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.1);
   }
   /* 输入框包装器 */
   .input-wrapper {
      position: relative;
      width: 100%;
   }
   /* 破坏实验输入框特殊样式 */
   .destruction-input {
      background-color: #fff !important;
      border: 2px solid #e9ecef !important;
      color: #333 !important;
      font-size: 16px !important;
      padding: 12px 16px !important;
      width: 100% !important;
      box-sizing: border-box !important;
      -webkit-user-select: text !important;
      -moz-user-select: text !important;
      -ms-user-select: text !important;
      user-select: text !important;
      -webkit-appearance: none !important;
      -moz-appearance: none !important;
      appearance: none !important;
      pointer-events: auto !important;
      opacity: 1 !important;
      z-index: 1 !important;
   }
   .destruction-input:focus {
      border-color: #3498db !important;
      background-color: #fff !important;
      outline: none !important;
      box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.1) !important;
   }
   .destruction-input:disabled {
      background-color: #f5f5f5 !important;
      color: #999 !important;
      cursor: not-allowed !important;
   }
   /* uni-easyinput 样式 */
   .destruction-input-uni {
      width: 100% !important;
   }
   .destruction-input-uni .uni-easyinput__content {
      border: 2px solid #e9ecef !important;
      border-radius: 8px !important;
      background-color: #fff !important;
   }
   .destruction-input-uni .uni-easyinput__content-input {
      font-size: 16px !important;
      color: #333 !important;
      padding: 12px 16px !important;
   }
   /* 模拟输入框样式 */
   .fake-input {
      width: 100%;
      padding: 12px 16px;
      border: 2px solid #e9ecef;
      border-radius: 8px;
      background-color: #fff;
      font-size: 16px;
      color: #333;
      cursor: pointer;
      transition: border-color 0.3s ease;
      box-sizing: border-box;
      min-height: 44px;
      display: flex;
      align-items: center;
   }
   .fake-input:hover {
      border-color: #3498db;
   }
   .fake-input.error {
      border-color: #e74c3c;
   }
   .fake-input .placeholder {
      color: #999;
   }
   /* 简化的输入框样式 */
   .simple-input {
      width: 100%;
      padding: 12px 16px;
      border: 2px solid #e9ecef;
      border-radius: 8px;
      font-size: 16px;
      color: #333;
      background-color: #fff;
      box-sizing: border-box;
      outline: none;
      -webkit-appearance: none;
      -moz-appearance: none;
      appearance: none;
      -webkit-user-select: text;
      -moz-user-select: text;
      -ms-user-select: text;
      user-select: text;
      -webkit-tap-highlight-color: transparent;
   }
   .simple-input:focus {
      border-color: #3498db;
      -webkit-user-select: text;
      -moz-user-select: text;
      -ms-user-select: text;
      user-select: text;
   }
   /* 重新设计的输入区域样式 */
   .input-section {
      margin: 20px 0;
      padding: 20px;
      background: #f8f9fa;
      border-radius: 12px;
      border: 1px solid #e9ecef;
   }
   .input-title {
      font-size: 16px;
      font-weight: 600;
      color: #2c3e50;
      margin-bottom: 12px;
      text-align: center;
   }
   .input-container {
      display: flex;
      justify-content: center;
      margin-bottom: 8px;
   }
   .input-box {
      width: 200px;
      height: 50px;
      border: 2px solid #3498db;
      border-radius: 8px;
      background-color: #fff;
      display: flex;
      align-items: center;
      justify-content: center;
      cursor: pointer;
      transition: all 0.3s ease;
      box-shadow: 0 2px 4px rgba(0,0,0,0.1);
   }
   .input-box:hover {
      border-color: #2980b9;
      box-shadow: 0 4px 8px rgba(0,0,0,0.15);
      transform: translateY(-1px);
   }
   .input-box:active {
      transform: translateY(0);
      box-shadow: 0 2px 4px rgba(0,0,0,0.1);
   }
   .input-value {
      font-size: 18px;
      font-weight: 600;
      color: #2c3e50;
   }
   .input-placeholder {
      font-size: 16px;
      color: #7f8c8d;
      font-style: italic;
   }
   .error-tip {
      text-align: center;
      color: #e74c3c;
      font-size: 14px;
      margin-top: 8px;
   }
   .form-label {
      display: block;
      font-weight: 600;
      color: #2c3e50;
      margin-bottom: 8px;
      font-size: 14px;
   }
   .form-group {
      margin-bottom: 20px;
   }
   /* 错误信息样式 */
   .error-message {
      color: #e74c3c;
      font-size: 12px;
      margin-top: 4px;
      text-align: center;
   }
   /* 堵穴相关样式 */
   .block-hole-btn {
      background-color: #f39c12;
      color: white;
      padding: 6px 12px;
      border: none;
      border-radius: 4px;
      cursor: pointer;
      font-size: 12px;
      transition: all 0.3s ease;
   }
   .block-hole-btn:hover:not(.disabled) {
      background-color: #e67e22;
      transform: translateY(-1px);
   }
   .block-hole-btn.disabled {
      background-color: #bdc3c7;
      color: #7f8c8d;
      cursor: not-allowed;
   }
   .blocked-info {
      color: #e74c3c;
      font-size: 12px;
      margin-left: 8px;
      font-weight: bold;
   }
   .block-hole-popup,
   .global-block-hole-popup {
      width: 80vw;
      max-width: 500px;
      min-height: 300px;
   }
   .block-hole-content {
      padding: 20px;
   }
   .hole-info {
      margin-bottom: 20px;
      padding: 15px;
      background-color: #f8f9fa;
      border-radius: 8px;
      border: 1px solid #e9ecef;
   }
   .hole-info .info-label {
      font-weight: 600;
      color: #495057;
      margin-bottom: 8px;
      display: block;
   }
   .input-section {
      margin-bottom: 20px;
   }
   .input-label {
      font-weight: 600;
      color: #495057;
      margin-bottom: 8px;
      display: block;
   }
   .block-hole-input {
      width: 100%;
      padding: 12px 16px;
      border: 2px solid #e9ecef;
      border-radius: 8px;
      font-size: 16px;
      transition: border-color 0.3s ease;
      box-sizing: border-box;
      background-color: #fff !important;
      color: #333 !important;
      -webkit-user-select: text !important;
      -moz-user-select: text !important;
      -ms-user-select: text !important;
      user-select: text !important;
      pointer-events: auto !important;
      opacity: 1 !important;
      /* 移除z-index,避免遮挡弹窗 */
   }
   .block-hole-input:focus {
      border-color: #3498db;
      outline: none;
      box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.1);
   }
   .block-hole-actions {
      display: flex;
      gap: 12px;
      justify-content: center;
      margin-top: 20px;
   }
   .block-hole-btn.confirm {
      background: linear-gradient(135deg, #27ae60, #2ecc71);
      color: white;
      padding: 12px 24px;
      min-width: 100px;
   }
   .block-hole-btn.confirm:hover:not(:disabled) {
      background: linear-gradient(135deg, #229954, #27ae60);
   }
   .block-hole-btn.confirm:disabled {
      background: #bdc3c7;
      color: #7f8c8d;
      cursor: not-allowed;
   }
   .block-hole-btn.cancel {
      background: linear-gradient(135deg, #95a5a6, #7f8c8d);
      color: white;
      padding: 12px 24px;
      min-width: 100px;
   }
   .block-hole-btn.cancel:hover {
      background: linear-gradient(135deg, #7f8c8d, #6c7b7d);
   }
   .blocked-holes-info {
      color: #e74c3c;
      font-weight: bold;
      margin-left: 8px;
   }
</style>