pan
2025-11-12 ca4a0e7ffc11dc6f4c19b75f625444b06768ea15
ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/views/outbound/PickingConfirm.vue
@@ -48,6 +48,14 @@
                  :disabled="!currentLockInfo"
                />
              </el-form-item>
              <!-- ç‰©æ–™ä¿¡æ¯æ˜¾ç¤º -->
              <el-form-item label="物料编码" v-if="currentMaterialInfo">
                <el-input v-model="currentMaterialInfo.materielCode" readonly />
              </el-form-item>
              <el-form-item label="物料名称" v-if="currentMaterialInfo">
                <el-input v-model="currentMaterialInfo.materielName" readonly />
              </el-form-item>
            </el-form>
            <div class="current-info" v-if="currentPallet">
@@ -141,6 +149,7 @@
      },
      currentPallet: null,
      currentLockInfo: null,
      currentMaterialInfo: null, // æ–°å¢žï¼šå½“前物料信息
      pickedList: [],
      pickedColumns: [
        { field: 'barcode', title: '物料条码', width: 150 },
@@ -153,7 +162,8 @@
        { field: 'action', title: '操作', width: 80, slot: true }
      ],
      splitVisible: false,
      maxPickQuantity: 0
      maxPickQuantity: 0,
      allLockInfos: [] // æ–°å¢žï¼šä¿å­˜æ‰€æœ‰é”å®šä¿¡æ¯ï¼Œç”¨äºŽæ¡ç åŒ¹é…
    }
  },
  computed: {
@@ -174,7 +184,7 @@
      if (!orderId) return
      try {
        const result = await this.http.post(`api/OutboundOrder/GetById?id=${orderId}`)
        const result = await this.http.get(`api/OutboundOrder/GetById?id=${orderId}`)
        if (result.status) {
          this.orderInfo = result.data
        }
@@ -195,7 +205,7 @@
        )
        if (result.status) {
          this.currentPallet = result.data
          this.loadPalletLockInfo()
          await this.loadPalletLockInfo()
          this.$message.success(`托盘 ${this.scanForm.palletCode} è¯†åˆ«æˆåŠŸ`)
        } else {
          this.$message.error(result.message)
@@ -212,42 +222,148 @@
        const result = await this.http.get(
          `api/OutboundPicking/GetPalletLockInfos?palletCode=${this.currentPallet.palletCode}`
        )
        if (result.status && result.data.length > 0) {
          this.currentLockInfo = result.data[0]
          this.maxPickQuantity = this.currentLockInfo.assignQuantity - this.currentLockInfo.pickedQty
        if (result.status) {
          this.allLockInfos = result.data
          // é»˜è®¤é€‰æ‹©ç¬¬ä¸€ä¸ªé”å®šä¿¡æ¯
          if (this.allLockInfos.length > 0) {
            this.currentLockInfo = this.allLockInfos[0]
            this.currentMaterialInfo = {
              materielCode: this.currentLockInfo.materielCode,
              materielName: this.currentLockInfo.materielName
            }
            this.maxPickQuantity = this.currentLockInfo.assignQuantity - this.currentLockInfo.pickedQty
          }
        }
      } catch (error) {
        console.error('加载锁定信息失败:', error)
      }
    },
    // æ ¹æ®æ¡ç æŸ¥æ‰¾å¯¹åº”的锁定信息和物料信息
    findLockInfoByBarcode(barcode) {
      if (!this.allLockInfos || this.allLockInfos.length === 0) {
        return null
      }
      // é¦–先精确匹配当前条码
      let lockInfo = this.allLockInfos.find(x => x.currentBarcode === barcode)
      if (lockInfo) {
        return lockInfo
      }
      // å¦‚果没有精确匹配,查找该条码对应的物料是否在锁定信息中
      // è¿™é‡Œéœ€è¦è°ƒç”¨åŽç«¯æŽ¥å£éªŒè¯æ¡ç å¯¹åº”的物料
      return null
    },
    async handleBarcodeScan() {
      // å®žçŽ°æ‰«ç ç¡®è®¤é€»è¾‘
      if (!this.scanForm.barcode) {
        this.$message.warning('请输入物料条码')
        return
      }
      if (!this.currentPallet) {
        this.$message.warning('请先扫描托盘条码')
        return
      }
      if (this.scanForm.quantity <= 0) {
        this.$message.warning('请输入有效的拣选数量')
        return
      }
      try {
        // éªŒè¯æ¡ç å¹¶èŽ·å–ç‰©æ–™ä¿¡æ¯
        const materialInfo = await this.validateBarcode(this.scanForm.barcode)
        if (!materialInfo) {
          this.$message.error('无效的物料条码')
          return
        }
        // æŸ¥æ‰¾å¯¹åº”的锁定信息
        const targetLockInfo = this.findLockInfoByBarcodeAndMaterial(this.scanForm.barcode, materialInfo.materielCode)
        if (!targetLockInfo) {
          this.$message.error('该物料条码不在当前托盘的锁定信息中')
          return
        }
        // æ£€æŸ¥æ‹£é€‰æ•°é‡
        const availableQuantity = targetLockInfo.assignQuantity - targetLockInfo.pickedQty
        if (this.scanForm.quantity > availableQuantity) {
          this.$message.error(`拣选数量超过可用数量,剩余可拣选:${availableQuantity}`)
          return
        }
        // å‡†å¤‡è¯·æ±‚数据
        const request = {
          orderDetailId: targetLockInfo.orderDetailId,
          barcode: this.scanForm.barcode,
          quantity: this.scanForm.quantity,
          materielCode: materialInfo.materielCode, // ä¼ é€’物料编码
          pickQuantity: this.scanForm.quantity,
          locationCode: this.currentPallet.locationCode,
          palletCode: this.currentPallet.palletCode,
          orderId: this.orderInfo.id
          stockId: targetLockInfo.stockId,
          outStockLockInfoId: targetLockInfo.id // ä¼ é€’锁定信息ID
        }
        const result = await this.http.post('api/OutboundPicking/ConfirmPicking', request)
        if (result.status) {
          this.$message.success('拣选确认成功')
          // é‡ç½®è¡¨å•
          this.scanForm.barcode = ''
          this.scanForm.quantity = 1
          this.loadPickedHistory()
          this.currentMaterialInfo = null
          // åˆ·æ–°æ•°æ®
          this.loadOrderInfo()
          this.loadPickedHistory()
          this.loadPalletLockInfo()
        } else {
          this.$message.error(result.message)
        }
      } catch (error) {
        this.$message.error('拣选确认失败')
        this.$message.error('拣选确认失败: ' + (error.message || '未知错误'))
      }
    },
    // æ ¹æ®æ¡ç å’Œç‰©æ–™ç¼–码查找锁定信息
    findLockInfoByBarcodeAndMaterial(barcode, materielCode) {
      if (!this.allLockInfos || this.allLockInfos.length === 0) {
        return null
      }
      // é¦–先尝试精确匹配条码
      let lockInfo = this.allLockInfos.find(x =>
        x.currentBarcode === barcode && x.materielCode === materielCode
      )
      if (lockInfo) {
        return lockInfo
      }
      // å¦‚果精确匹配失败,只匹配物料编码(允许从同一物料的不同条码拣选)
      lockInfo = this.allLockInfos.find(x =>
        x.materielCode === materielCode &&
        (x.assignQuantity - x.pickedQty) > 0
      )
      return lockInfo
    },
    // éªŒè¯æ¡ç å¹¶èŽ·å–ç‰©æ–™ä¿¡æ¯
    async validateBarcode(barcode) {
      try {
        const result = await this.http.get(`api/OutboundPicking/ValidateBarcode?barcode=${barcode}`)
        if (result.status) {
          return result.data
        } else {
          this.$message.error(result.message)
          return null
        }
      } catch (error) {
        this.$message.error('条码验证失败')
        return null
      }
    },
@@ -261,7 +377,8 @@
        const result = await this.http.post('api/BackToStock/GenerateBackToStockTask', {
          palletCode: this.currentPallet.palletCode,
          currentLocation: '拣选位'
          currentLocation: '拣选位',
          operator: '当前用户'
        })
        if (result.status) {
@@ -311,6 +428,8 @@
    resetCurrentPallet() {
      this.currentPallet = null
      this.currentLockInfo = null
      this.currentMaterialInfo = null
      this.allLockInfos = []
      this.scanForm.palletCode = ''
    },
@@ -351,4 +470,49 @@
    this.loadPickedHistory()
  }
}
</script>
</script>
<style scoped>
.picking-confirm {
  padding: 20px;
}
.page-header {
  margin-bottom: 20px;
}
.title {
  font-size: 18px;
  font-weight: bold;
}
.scan-section {
  margin-bottom: 20px;
}
.action-buttons {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.action-buttons .el-button {
  width: 100%;
}
.current-info {
  margin-top: 15px;
  padding: 10px;
  background-color: #f5f7fa;
  border-radius: 4px;
}
.current-info p {
  margin: 5px 0;
  font-size: 14px;
}
.summary-info {
  margin-bottom: 15px;
}
</style>