448 lines
9.9 KiB
Vue
448 lines
9.9 KiB
Vue
<template>
|
||
<view class="container">
|
||
<view class="input-group">
|
||
<text class="input-label">{{ $t('inbound.backIn.rackCode') }}</text>
|
||
<uni-easyinput
|
||
v-model="rackCode"
|
||
:placeholder="$t('inbound.backIn.rackCodePlaceholder')"
|
||
:clearable="true"
|
||
@input="handleInput"
|
||
@clear="handleClear"
|
||
ref="rackCodeInput">
|
||
|
||
<template #right>
|
||
<text class="scan-icon" @click="handleScan">📷</text>
|
||
</template>
|
||
</uni-easyinput>
|
||
</view>
|
||
|
||
<view class="loading-container" v-if="loading">
|
||
<uni-load-more status="loading" :content-text="{contentdown: $t('inbound.backIn.loading'),contentrefresh: $t('inbound.backIn.loading'),contentnomore: $t('common.noData')}"></uni-load-more>
|
||
</view>
|
||
|
||
<view class="card-container" v-if="materialList.length > 0">
|
||
<uni-card v-for="(item, index) in materialList" :key="index" class="material-card">
|
||
<view class="card-content">
|
||
<view class="info-row">
|
||
<text class="label">{{ $t('inbound.backIn.materialCode') }}</text>
|
||
<text class="value">{{ item.productId }}</text>
|
||
</view>
|
||
<view class="info-row">
|
||
<text class="label">{{ $t('inbound.backIn.materialName') }}</text>
|
||
<text class="value">{{ item.productName }}</text>
|
||
</view>
|
||
<view class="info-row">
|
||
<text class="label">{{ $t('inbound.backIn.quantity') }}</text>
|
||
<uni-easyinput
|
||
v-model="item.editQuantity"
|
||
type="number"
|
||
:placeholder="String(item.quantity)"
|
||
class="quantity-input"
|
||
@input="handleQuantityChange(index)"
|
||
/>
|
||
</view>
|
||
</view>
|
||
</uni-card>
|
||
</view>
|
||
|
||
<view class="empty-state" v-if="!loading && materialList.length === 0 && rackCode">
|
||
<text>{{ $t('inbound.backIn.noMaterialInfo') }}</text>
|
||
</view>
|
||
|
||
<view class="button-container" v-if="materialList.length > 0">
|
||
<button class="submit-button" @click="handleSubmit">{{ $t('inbound.backIn.submit') }}</button>
|
||
</view>
|
||
|
||
<!-- 仓库选择弹窗 -->
|
||
<uni-popup ref="warehousePopup" type="center">
|
||
<view class="popup-content">
|
||
<view class="popup-title">{{ $t('inbound.backIn.selectWarehouse') }}</view>
|
||
<view class="popup-body">
|
||
<uni-data-select
|
||
v-model="selectedWarehouseId"
|
||
:localdata="warehouseList"
|
||
:clear="false"
|
||
:placeholder="$t('inbound.backIn.warehousePlaceholder')"
|
||
/>
|
||
</view>
|
||
<view class="popup-footer">
|
||
<button class="cancel-button" @click="closeWarehousePopup">{{ $t('inbound.backIn.cancel') }}</button>
|
||
<button class="confirm-button" @click="confirmSubmit">{{ $t('inbound.backIn.confirm') }}</button>
|
||
</view>
|
||
</view>
|
||
</uni-popup>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import { getContainerDetails, agvRequest } from '@/api/in/order.js'
|
||
import { getBasWarehouList } from '@/api/bas/bas.js'
|
||
|
||
export default {
|
||
data() {
|
||
return {
|
||
rackCode: '',
|
||
materialList: [],
|
||
loading: false,
|
||
submitting: false,
|
||
warehouseList: [],
|
||
selectedWarehouseId: '',
|
||
preparedSubmitData: null
|
||
}
|
||
},
|
||
onReady() {
|
||
setTimeout(() => {
|
||
this.$nextTick(() => {
|
||
this.$refs.rackCodeInput.onFocus()
|
||
})
|
||
}, 100)
|
||
|
||
// 获取仓库列表
|
||
this.getWarehouseList()
|
||
},
|
||
methods: {
|
||
// 获取仓库列表
|
||
async getWarehouseList() {
|
||
try {
|
||
const response = await getBasWarehouList({
|
||
pageNum: 1,
|
||
pageSize: 100,
|
||
typeData: ['2']
|
||
})
|
||
if (response.code === 200) {
|
||
this.warehouseList = response.rows.map(item => ({
|
||
value: item.warehouseId,
|
||
text: item.warehouseName,
|
||
type: item.warehouseType
|
||
}))
|
||
}
|
||
} catch (error) {
|
||
console.error('获取仓库列表失败:', error)
|
||
uni.showToast({
|
||
title: this.$t('inbound.backIn.getWarehouseListFailed'),
|
||
icon: 'none'
|
||
})
|
||
}
|
||
},
|
||
// 处理输入事件
|
||
handleInput(value) {
|
||
if (value) {
|
||
this.fetchRackInfo(value)
|
||
}
|
||
},
|
||
// 处理清除事件
|
||
handleClear() {
|
||
this.materialList = []
|
||
},
|
||
// 处理扫码事件
|
||
handleScan() {
|
||
uni.scanCode({
|
||
success: (res) => {
|
||
this.rackCode = res.result
|
||
this.fetchRackInfo(res.result)
|
||
}
|
||
})
|
||
},
|
||
// 获取料架信息
|
||
async fetchRackInfo(rackCode) {
|
||
this.loading = true
|
||
try {
|
||
const response = await getContainerDetails({
|
||
"containerId":rackCode,
|
||
"pageNum":1,
|
||
"pageSize":100
|
||
})
|
||
|
||
if (response.code === 200) {
|
||
if (response.rows && response.rows.length > 0) {
|
||
this.materialList = response.rows.map(item => {
|
||
return {
|
||
...item,
|
||
editQuantity: String(item.quantity)
|
||
}
|
||
})
|
||
} else {
|
||
this.materialList = []
|
||
uni.showToast({
|
||
title: this.$t('inbound.backIn.noMaterialInfo'),
|
||
icon: 'none'
|
||
})
|
||
}
|
||
} else {
|
||
this.materialList = []
|
||
uni.showToast({
|
||
title: response.msg || this.$t('inbound.backIn.getRackInfoFailed'),
|
||
icon: 'none'
|
||
})
|
||
}
|
||
} catch (error) {
|
||
this.materialList = []
|
||
uni.showToast({
|
||
title: this.$t('inbound.backIn.getRackInfoFailed'),
|
||
icon: 'none'
|
||
})
|
||
} finally {
|
||
this.loading = false
|
||
}
|
||
},
|
||
// 处理数量变更
|
||
handleQuantityChange(index) {
|
||
// 确保输入的是有效数字
|
||
const value = this.materialList[index].editQuantity
|
||
if (value === '' || isNaN(Number(value))) {
|
||
this.materialList[index].editQuantity = '0'
|
||
}
|
||
},
|
||
// 打开仓库选择弹窗
|
||
openWarehousePopup() {
|
||
this.$refs.warehousePopup.open()
|
||
},
|
||
// 关闭仓库选择弹窗
|
||
closeWarehousePopup() {
|
||
this.$refs.warehousePopup.close()
|
||
this.submitting = false
|
||
},
|
||
// 处理提交
|
||
async handleSubmit() {
|
||
if (this.submitting) return
|
||
|
||
if (this.materialList.length === 0) {
|
||
uni.showToast({
|
||
title: this.$t('inbound.backIn.noSubmitMaterial'),
|
||
icon: 'none'
|
||
})
|
||
return
|
||
}
|
||
if(!this.rackCode){
|
||
uni.showToast({
|
||
title: this.$t('inbound.backIn.enterRackCode'),
|
||
icon: 'none'
|
||
})
|
||
return
|
||
}
|
||
|
||
// 验证输入
|
||
let isValid = true
|
||
this.materialList.forEach(item => {
|
||
if (item.editQuantity === '' || isNaN(Number(item.editQuantity)) || Number(item.editQuantity) < 0) {
|
||
isValid = false
|
||
}
|
||
})
|
||
|
||
if (!isValid) {
|
||
uni.showToast({
|
||
title: this.$t('inbound.backIn.enterValidQuantity'),
|
||
icon: 'none'
|
||
})
|
||
return
|
||
}
|
||
|
||
this.submitting = true
|
||
|
||
// 准备提交数据
|
||
const submitData = this.materialList.map(item => {
|
||
return {
|
||
id: item.id,
|
||
productId: item.productId,
|
||
quantity: Number(item.editQuantity)
|
||
}
|
||
})
|
||
|
||
// 检查是否有数量不为0的物料
|
||
const hasNonZeroQuantity = submitData.some(item => item.quantity > 0)
|
||
|
||
if (hasNonZeroQuantity) {
|
||
// 保存提交数据,打开仓库选择弹窗
|
||
this.preparedSubmitData = submitData
|
||
this.openWarehousePopup()
|
||
} else {
|
||
// 直接提交
|
||
await this.submitData(submitData)
|
||
}
|
||
},
|
||
// 确认提交(选择仓库后)
|
||
async confirmSubmit() {
|
||
if (!this.selectedWarehouseId) {
|
||
uni.showToast({
|
||
title: this.$t('inbound.backIn.selectWarehouse'),
|
||
icon: 'none'
|
||
})
|
||
return
|
||
}
|
||
|
||
this.closeWarehousePopup()
|
||
await this.submitData(this.preparedSubmitData, this.selectedWarehouseId)
|
||
},
|
||
// 提交数据
|
||
async submitData(submitData, warehouseId = null) {
|
||
try {
|
||
const requestData = {
|
||
"details": submitData,
|
||
"containerId": this.rackCode
|
||
}
|
||
|
||
// 如果有仓库ID,添加到请求数据中
|
||
if (warehouseId) {
|
||
requestData.spare1 = warehouseId
|
||
}
|
||
|
||
const response = await agvRequest(requestData)
|
||
|
||
if (response.code === 200) {
|
||
uni.showToast({
|
||
title: this.$t('inbound.backIn.submitSuccess'),
|
||
icon: 'success'
|
||
})
|
||
|
||
// 更新本地数据
|
||
this.materialList.forEach(item => {
|
||
item.quantity = Number(item.editQuantity)
|
||
})
|
||
} else {
|
||
uni.showToast({
|
||
title: response.msg || this.$t('inbound.backIn.submitFailed'),
|
||
icon: 'none'
|
||
})
|
||
}
|
||
} catch (error) {
|
||
uni.showToast({
|
||
title: this.$t('inbound.backIn.submitFailed'),
|
||
icon: 'none'
|
||
})
|
||
console.error(error)
|
||
} finally {
|
||
this.submitting = false
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss">
|
||
.container {
|
||
padding: 20rpx;
|
||
background-color: #f8f9fc;
|
||
}
|
||
|
||
.input-group {
|
||
margin-bottom: 20rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.input-label {
|
||
width: 180rpx;
|
||
font-size: 28rpx;
|
||
}
|
||
|
||
.scan-icon {
|
||
font-size: 40rpx;
|
||
padding: 0 20rpx;
|
||
}
|
||
|
||
.card-container {
|
||
margin-top: 30rpx;
|
||
}
|
||
|
||
.material-card {
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.card-content {
|
||
padding: 10rpx;
|
||
}
|
||
|
||
.info-row {
|
||
display: flex;
|
||
margin-bottom: 15rpx;
|
||
}
|
||
|
||
.label {
|
||
width: 180rpx;
|
||
font-size: 28rpx;
|
||
color: #666;
|
||
}
|
||
|
||
.value {
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.empty-state {
|
||
margin-top: 100rpx;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
color: #999;
|
||
font-size: 28rpx;
|
||
}
|
||
|
||
.loading-container {
|
||
margin-top: 50rpx;
|
||
display: flex;
|
||
justify-content: center;
|
||
}
|
||
|
||
.quantity-input {
|
||
flex: 1;
|
||
margin-left: 10rpx;
|
||
}
|
||
|
||
.button-container {
|
||
margin-top: 50rpx;
|
||
padding: 0 30rpx;
|
||
}
|
||
|
||
.submit-button {
|
||
background-color: #007aff;
|
||
color: #fff;
|
||
border-radius: 8rpx;
|
||
font-size: 32rpx;
|
||
height: 80rpx;
|
||
line-height: 80rpx;
|
||
}
|
||
|
||
/* 弹窗样式 */
|
||
.popup-content {
|
||
width: 600rpx;
|
||
background-color: #fff;
|
||
border-radius: 16rpx;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.popup-title {
|
||
font-size: 32rpx;
|
||
font-weight: bold;
|
||
padding: 30rpx;
|
||
text-align: center;
|
||
border-bottom: 1rpx solid #eee;
|
||
}
|
||
|
||
.popup-body {
|
||
padding: 30rpx;
|
||
}
|
||
|
||
.popup-footer {
|
||
display: flex;
|
||
border-top: 1rpx solid #eee;
|
||
}
|
||
|
||
.cancel-button, .confirm-button {
|
||
flex: 1;
|
||
height: 80rpx;
|
||
line-height: 80rpx;
|
||
text-align: center;
|
||
font-size: 28rpx;
|
||
}
|
||
|
||
.cancel-button {
|
||
background-color: #f2f2f2;
|
||
color: #666;
|
||
}
|
||
|
||
.confirm-button {
|
||
background-color: #007aff;
|
||
color: #fff;
|
||
}
|
||
</style> |