项目初始化
This commit is contained in:
448
RuoYi-App-master/pages/in/backIn.vue
Normal file
448
RuoYi-App-master/pages/in/backIn.vue
Normal file
@@ -0,0 +1,448 @@
|
||||
<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>
|
||||
727
RuoYi-App-master/pages/in/bindMsg.vue
Normal file
727
RuoYi-App-master/pages/in/bindMsg.vue
Normal file
@@ -0,0 +1,727 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
|
||||
|
||||
|
||||
<view class="input-group">
|
||||
<text class="input-label">{{ $t('inbound.bindMsg.trayCode') }}</text>
|
||||
<uni-easyinput
|
||||
v-model="trayCode"
|
||||
:placeholder="$t('inbound.bindMsg.trayCodePlaceholder')"
|
||||
:clearable="true"
|
||||
@input="handleInput"
|
||||
@clear="handleClear"
|
||||
ref="trayCodeInput"
|
||||
>
|
||||
<template #right>
|
||||
<text class="scan-icon" @click="handleScan">📷</text>
|
||||
</template>
|
||||
</uni-easyinput>
|
||||
</view>
|
||||
|
||||
<view class="input-group">
|
||||
<text class="input-label">{{ $t('inbound.bindMsg.subOrder') }}</text>
|
||||
<uni-easyinput
|
||||
v-model="stockinDetailId"
|
||||
:placeholder="$t('inbound.bindMsg.subOrderPlaceholder')"
|
||||
:clearable="true"
|
||||
@input="handleSubOrderInput"
|
||||
@clear="handleSubOrderClear"
|
||||
ref="subOrderInput"
|
||||
>
|
||||
</uni-easyinput>
|
||||
</view>
|
||||
|
||||
<!-- 子单据数据弹窗 -->
|
||||
<uni-popup ref="subOrderPopup" type="center">
|
||||
<view class="popup-content">
|
||||
<view class="popup-title">{{ $t('inbound.bindMsg.subOrderInfo') }}</view>
|
||||
<view class="popup-body">
|
||||
<view v-if="subOrderInfo" class="info-item">
|
||||
<view class="info-row">
|
||||
<text class="info-label">{{ $t('inbound.bindMsg.warehouse') }}</text>
|
||||
<text class="info-value">{{ subOrderInfo.warehouseName }}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="info-label">{{ $t('inbound.bindMsg.orderNumber') }}</text>
|
||||
<text class="info-value">{{ subOrderInfo.stockinId }}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="info-label">{{ $t('inbound.bindMsg.materialCode') }}</text>
|
||||
<text class="info-value">{{ subOrderInfo.productId }}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="info-label">{{ $t('inbound.bindMsg.materialName') }}</text>
|
||||
<text class="info-value">{{ subOrderInfo.extraField.materialDesc }}</text>
|
||||
</view>
|
||||
<view class="info-row quantity-row">
|
||||
<text class="info-label">{{ $t('inbound.bindMsg.quantity') }}</text>
|
||||
<uni-easyinput
|
||||
v-model="inQuantity"
|
||||
type="number"
|
||||
:maxlength="String(subOrderInfo.quantity).length"
|
||||
:placeholder="$t('inbound.bindMsg.maxQuantity') + subOrderInfo.quantity"
|
||||
@input="handleQuantityInput"
|
||||
class="quantity-input"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else class="no-data">{{ $t('inbound.bindMsg.noData') }}</view>
|
||||
</view>
|
||||
<view class="popup-buttons">
|
||||
<button class="popup-btn confirm-btn" @click="handleBindSubOrder" :disabled="!subOrderInfo || subOrderInfo.quantity <= 0" :class="{'disabled-btn': !subOrderInfo || subOrderInfo.quantity <= 0}">{{ $t('inbound.bindMsg.bind') }}</button>
|
||||
<button class="popup-btn cancel-btn" @click="handleCancelSubOrder">{{ $t('inbound.bindMsg.cancel') }}</button>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
|
||||
|
||||
<view class="table-container" v-if="materialList.length > 0">
|
||||
<uni-table border stripe :emptyText="$t('inbound.bindMsg.noData')">
|
||||
<uni-tr>
|
||||
<uni-th align="center">{{ $t('inbound.bindMsg.warehouseColumn') }}</uni-th>
|
||||
<uni-th align="center">{{ $t('inbound.bindMsg.materialNameColumn') }}</uni-th>
|
||||
<uni-th align="center">{{ $t('inbound.bindMsg.quantityColumn') }}</uni-th>
|
||||
<uni-th align="center">{{ $t('inbound.bindMsg.operationColumn') }}</uni-th>
|
||||
</uni-tr>
|
||||
<uni-tr v-for="(item, index) in materialList" :key="index">
|
||||
<uni-td align="center">{{ item.warehouseName }}</uni-td>
|
||||
<uni-td align="center">{{ item.productName }}</uni-td>
|
||||
<uni-td align="center">{{ item.quantity }}</uni-td>
|
||||
<uni-td align="center">
|
||||
<button class="unbind-btn" @click="handleUnbind(item.stockinDetailId)">{{ $t('inbound.bindMsg.unbind') }}</button>
|
||||
</uni-td>
|
||||
</uni-tr>
|
||||
</uni-table>
|
||||
</view>
|
||||
<view class="button-group" v-if="materialList.length > 0">
|
||||
<button class="confirm-button" @click="handleConfirm">{{ $t('inbound.bindMsg.confirmInbound') }}</button>
|
||||
</view>
|
||||
|
||||
<!-- 货位选择弹出框 -->
|
||||
<uni-popup ref="cargoSpacePopup" type="center">
|
||||
<view class="popup-content">
|
||||
<view class="popup-title">{{ $t('inbound.bindMsg.selectCargoSpace') }}</view>
|
||||
<view class="popup-body">
|
||||
<view class="input-group cargo-space-input">
|
||||
<text class="input-label">{{ $t('inbound.bindMsg.cargoSpace') }}</text>
|
||||
<uni-easyinput
|
||||
v-model="cargoSpaceName"
|
||||
:placeholder="$t('inbound.bindMsg.cargoSpacePlaceholder')"
|
||||
:clearable="true"
|
||||
@input="handleCargoSpaceInput"
|
||||
>
|
||||
<template #right>
|
||||
<button class="recommend-btn" @click="handleRecommendCargoSpace">{{ $t('inbound.bindMsg.recommendCargoSpace') }}</button>
|
||||
</template>
|
||||
</uni-easyinput>
|
||||
</view>
|
||||
<view v-if="cargoSpaceHeight" class="cargo-space-height">
|
||||
<text>{{ $t('inbound.bindMsg.cargoSpaceHeight') }} {{ cargoSpaceHeight }}{{ $t('inbound.bindMsg.meter') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="popup-buttons">
|
||||
<button class="popup-btn confirm-btn" @click="handleConfirmCargoSpace">{{ $t('inbound.bindMsg.confirm') }}</button>
|
||||
<button class="popup-btn cancel-btn" @click="handleCancelCargoSpace">{{ $t('inbound.bindMsg.cancel') }}</button>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getTrayInfo,addInJob,getOrderGoods ,bindTray, unbindTray} from '@/api/in/order.js'
|
||||
import { getBasWarehouList, getCargoSpaceList } from '@/api/bas/bas.js'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
trayCode: '',
|
||||
stockinDetailId: '',
|
||||
subOrderInfo: null,
|
||||
inQuantity:'',
|
||||
materialList: [],
|
||||
// currentWarehouseType: '',
|
||||
cargoSpaceId: '',
|
||||
cargoSpaceName: '',
|
||||
cargoSpaceList: [],
|
||||
cargoSpaceHeight: null,
|
||||
|
||||
}
|
||||
},
|
||||
onReady() {
|
||||
setTimeout(() => {
|
||||
this.$nextTick(() => {
|
||||
this.$refs.trayCodeInput.onFocus()
|
||||
})
|
||||
}, 100)
|
||||
|
||||
|
||||
},
|
||||
methods: {
|
||||
|
||||
// 处理货位选择
|
||||
async handleRecommendCargoSpace() {
|
||||
// try {
|
||||
const response = await getCargoSpaceList({ warehouseId: this.materialList[0].warehouseId, status: 1 })
|
||||
if (response.code === 200 && response.rows.length > 0) {
|
||||
// 获取第一个推荐货位
|
||||
this.cargoSpaceId = response.rows[0].cargoSpaceId
|
||||
this.cargoSpaceName = response.rows[0].cargoSpaceName
|
||||
// 手动触发handleCargoSpaceInput方法获取货位高度信息
|
||||
await this.handleCargoSpaceInput(response.rows[0].cargoSpaceName)
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: this.$t('inbound.bindMsg.noAvailableCargoSpace'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
// } catch (error) {
|
||||
// uni.showToast({
|
||||
// title: '获取推荐货位失败',
|
||||
// icon: 'none'
|
||||
// })
|
||||
// }
|
||||
},
|
||||
// 处理货位选择
|
||||
async handleCargoSpaceInput(value) {
|
||||
if (value) {
|
||||
try {
|
||||
const response = await getCargoSpaceList({ cargoSpaceName: value, warehouseId: this.materialList[0].warehouseId })
|
||||
if (response.code === 200 && response.rows.length > 0) {
|
||||
this.cargoSpaceId = response.rows[0].cargoSpaceId
|
||||
this.cargoSpaceHeight = response.rows[0].cargoHight
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: this.$t('inbound.bindMsg.getCargoSpaceInfoFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
this.cargoSpaceId = ''
|
||||
this.cargoSpaceHeight = null
|
||||
}
|
||||
} catch (error) {
|
||||
uni.showToast({
|
||||
title: this.$t('inbound.bindMsg.getCargoSpaceInfoFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
this.cargoSpaceId = ''
|
||||
this.cargoSpaceHeight = null
|
||||
}
|
||||
} else {
|
||||
this.cargoSpaceId = ''
|
||||
this.cargoSpaceHeight = null
|
||||
}
|
||||
},
|
||||
// 带货位信息提交入库
|
||||
async submitWithCargoSpace() {
|
||||
if (!this.cargoSpaceId) {
|
||||
uni.showToast({
|
||||
title: this.$t('inbound.bindMsg.selectCargoSpace'),
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await addInJob({
|
||||
cargoSpaceId: this.cargoSpaceId,
|
||||
trayCode: this.trayCode,
|
||||
warehouseId: this.materialList[0].warehouseId
|
||||
})
|
||||
|
||||
if (response.code === 200) {
|
||||
uni.showToast({
|
||||
title: this.$t('inbound.bindMsg.inboundSuccess'),
|
||||
icon: 'success'
|
||||
})
|
||||
// 清空数据
|
||||
this.trayCode = ''
|
||||
this.materialList = []
|
||||
this.cargoSpaceId = ''
|
||||
this.cargoSpaceName = ''
|
||||
this.cargoSpaceHeight=''
|
||||
// this.currentWarehouseType = ''
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: response.msg || this.$t('inbound.bindMsg.inboundFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
uni.showToast({
|
||||
title: this.$t('inbound.bindMsg.inboundFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
},
|
||||
// 处理输入事件
|
||||
handleInput(value) {
|
||||
if (value) {
|
||||
this.fetchTrayInfo(value)
|
||||
}
|
||||
},
|
||||
// 处理清除事件
|
||||
handleClear() {
|
||||
this.materialList = []
|
||||
},
|
||||
// 处理扫码事件
|
||||
handleScan() {
|
||||
uni.scanCode({
|
||||
success: (res) => {
|
||||
this.trayCode = res.result
|
||||
this.fetchTrayInfo(res.result)
|
||||
}
|
||||
})
|
||||
},
|
||||
// 获取托盘信息
|
||||
async fetchTrayInfo(trayCode) {
|
||||
try {
|
||||
const response = await getTrayInfo(trayCode)
|
||||
|
||||
if (response.code===200) {
|
||||
|
||||
if(response.data.length>0){
|
||||
this.materialList = response.data
|
||||
}else{
|
||||
this.materialList=[]
|
||||
}
|
||||
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: response.msg || this.$t('inbound.bindMsg.getTrayInfoFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
uni.showToast({
|
||||
title: this.$t('inbound.bindMsg.getTrayInfoFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
},
|
||||
// 处理确认入库事件
|
||||
async handleConfirm() {
|
||||
if (!this.trayCode || this.materialList.length === 0) {
|
||||
uni.showToast({
|
||||
title: this.$t('inbound.bindMsg.scanTrayFirst'),
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
const warehouseType = this.materialList[0].warehouseType
|
||||
|
||||
if (warehouseType === '1') {
|
||||
// 显示货位选择弹出框
|
||||
this.$refs.cargoSpacePopup.open()
|
||||
|
||||
} else {
|
||||
// 非货位类型仓库,直接调用入库接口
|
||||
try {
|
||||
const response = await addInJob({
|
||||
trayCode: this.trayCode,
|
||||
warehouseId: this.materialList[0].warehouseId
|
||||
})
|
||||
|
||||
if (response.code === 200) {
|
||||
uni.showToast({
|
||||
title: this.$t('inbound.bindMsg.inboundSuccess'),
|
||||
icon: 'success'
|
||||
})
|
||||
// 清空数据
|
||||
this.trayCode = ''
|
||||
this.materialList = []
|
||||
this.stockinDetailId=''
|
||||
// this.cargoSpaceId = ''
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: response.msg || this.$t('inbound.bindMsg.inboundFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
uni.showToast({
|
||||
title: this.$t('inbound.bindMsg.inboundFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
// 处理货位选择
|
||||
handleConfirmCargoSpace() {
|
||||
if (!this.cargoSpaceId) {
|
||||
uni.showToast({
|
||||
title: this.$t('inbound.bindMsg.selectCargoSpaceOrScan'),
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
this.$refs.cargoSpacePopup.close()
|
||||
this.submitWithCargoSpace()
|
||||
},
|
||||
// 处理取消货位选择
|
||||
handleCancelCargoSpace() {
|
||||
this.$refs.cargoSpacePopup.close()
|
||||
this.cargoSpaceId = ''
|
||||
this.cargoSpaceName = ''
|
||||
this.cargoSpaceHeight=''
|
||||
},
|
||||
// 处理子单据输入事件
|
||||
async handleSubOrderInput(value) {
|
||||
if (value) {
|
||||
// 调用获取子单据信息
|
||||
|
||||
const goodsResponse = await getOrderGoods({stockinDetailId:value})
|
||||
if (goodsResponse.length===0) {
|
||||
uni.showToast({
|
||||
title: this.$t('inbound.bindMsg.materialNotExistOrNoPermission'),
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
this.subOrderInfo= goodsResponse
|
||||
console.log(this.subOrderInfo)
|
||||
if (this.subOrderInfo) {
|
||||
this.$refs.subOrderPopup.open()
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
// 处理子单据清除事件
|
||||
handleSubOrderClear() {
|
||||
// this.stockinDetailId = ''
|
||||
this.subOrderInfo = null
|
||||
},
|
||||
handleQuantityInput(value) {
|
||||
const numValue = Number(value)
|
||||
if (numValue <= 0) {
|
||||
this.inQuantity = ''
|
||||
uni.showToast({
|
||||
title: this.$t('inbound.bindMsg.quantityGreaterThanZero'),
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
if (numValue > this.subOrderInfo.quantity) {
|
||||
this.inQuantity = String(this.subOrderInfo.quantity)
|
||||
uni.showToast({
|
||||
title: this.$t('inbound.bindMsg.notExceedMaxQuantity'),
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
this.inQuantity = String(numValue)
|
||||
},
|
||||
handleQuantityInput(value) {
|
||||
const numValue = Number(value)
|
||||
if (numValue <= 0) {
|
||||
this.inQuantity = ''
|
||||
uni.showToast({
|
||||
title: this.$t('inbound.bindMsg.quantityGreaterThanZero'),
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
if (numValue > this.subOrderInfo.quantity) {
|
||||
this.inQuantity = String(this.subOrderInfo.quantity)
|
||||
uni.showToast({
|
||||
title: this.$t('inbound.bindMsg.notExceedMaxQuantity'),
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
this.inQuantity = String(numValue)
|
||||
},
|
||||
// 处理绑定子单据事件
|
||||
async handleBindSubOrder() {
|
||||
// 验证必填信息
|
||||
if (!this.trayCode) {
|
||||
uni.showToast({
|
||||
title: this.$t('inbound.bindMsg.enterTrayCode'),
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (!this.inQuantity || Number(this.inQuantity) <= 0) {
|
||||
uni.showToast({
|
||||
title: this.$t('inbound.bindMsg.enterValidQuantity'),
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 确保提交的数量不超过最大可用数量
|
||||
const submitQuantity = Number(this.inQuantity)
|
||||
if (submitQuantity > this.subOrderInfo.quantity && this.subOrderInfo.quantity > 0) {
|
||||
this.inQuantity = String(this.subOrderInfo.quantity)
|
||||
uni.showToast({
|
||||
title: this.$t('inbound.bindMsg.autoAdjustMaxQuantity'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
const response = await bindTray({
|
||||
trayCode: this.trayCode,
|
||||
stockinDetailId: this.stockinDetailId,
|
||||
inQuantity:this.inQuantity
|
||||
})
|
||||
|
||||
if (response.code === 200) {
|
||||
uni.showToast({
|
||||
title: this.$t('inbound.bindMsg.bindSuccess'),
|
||||
icon: 'success'
|
||||
})
|
||||
this.$refs.subOrderPopup.close()
|
||||
this.stockinDetailId = ''
|
||||
this.subOrderInfo = null
|
||||
this.inQuantity=''
|
||||
this.fetchTrayInfo(this.trayCode)
|
||||
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: response.msg || this.$t('inbound.bindMsg.bindFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
},
|
||||
// 处理取消子单据事件
|
||||
handleCancelSubOrder() {
|
||||
if (this.$refs.subOrderPopup) {
|
||||
this.$refs.subOrderPopup.close()
|
||||
}
|
||||
this.stockinDetailId = ''
|
||||
this.subOrderInfo = null
|
||||
this.inQuantity = ''
|
||||
},
|
||||
// 处理解绑事件
|
||||
async handleUnbind(stockinDetailId) {
|
||||
try {
|
||||
const response = await unbindTray({
|
||||
trayCode: this.trayCode,
|
||||
stockinDetailId: stockinDetailId
|
||||
})
|
||||
|
||||
if (response.code === 200) {
|
||||
uni.showToast({
|
||||
title: this.$t('inbound.bindMsg.unbindSuccess'),
|
||||
icon: 'success'
|
||||
})
|
||||
// 刷新托盘信息
|
||||
this.fetchTrayInfo(this.trayCode)
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: response.msg || this.$t('inbound.bindMsg.unbindFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
uni.showToast({
|
||||
title: this.$t('inbound.bindMsg.unbindFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.unbind-btn {
|
||||
background-color: #ff4d4f;
|
||||
color: #ffffff;
|
||||
border: none;
|
||||
border-radius: 4rpx;
|
||||
padding: 10rpx 20rpx;
|
||||
font-size: 24rpx;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.unbind-btn:active {
|
||||
background-color: #cf1322;
|
||||
}
|
||||
|
||||
.container {
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.input-group {
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.input-label {
|
||||
display: block;
|
||||
margin-bottom: 10rpx;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.scan-icon {
|
||||
font-size: 40rpx;
|
||||
padding: 0 20rpx;
|
||||
}
|
||||
|
||||
.table-container {
|
||||
background-color: #ffffff;
|
||||
border-radius: 8rpx;
|
||||
box-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.cargo-space-container {
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.cargo-space-input {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.recommend-btn {
|
||||
background-color: #409eff;
|
||||
color: #ffffff;
|
||||
border-radius: 4rpx;
|
||||
padding: 0 20rpx;
|
||||
height: 60rpx;
|
||||
line-height: 60rpx;
|
||||
font-size: 28rpx;
|
||||
margin-left: 20rpx;
|
||||
}
|
||||
|
||||
.button-group {
|
||||
margin-top: 30rpx;
|
||||
padding: 0 20rpx;
|
||||
}
|
||||
|
||||
.confirm-button {
|
||||
background-color: #409eff;
|
||||
color: #ffffff;
|
||||
border-radius: 8rpx;
|
||||
padding: 20rpx 0;
|
||||
font-size: 32rpx;
|
||||
}
|
||||
|
||||
.popup-content {
|
||||
background-color: #fff;
|
||||
border-radius: 10rpx;
|
||||
padding: 40rpx;
|
||||
width: 85%;
|
||||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.15);
|
||||
max-height: 80vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.popup-title {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
margin-bottom: 40rpx;
|
||||
color: #333;
|
||||
border-bottom: 1px solid #eee;
|
||||
padding-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.popup-body {
|
||||
padding: 20rpx 10rpx;
|
||||
max-height: 60vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.popup-buttons {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
margin-top: 40rpx;
|
||||
padding-top: 20rpx;
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
|
||||
.popup-btn {
|
||||
padding: 20rpx 50rpx;
|
||||
border-radius: 8rpx;
|
||||
font-size: 28rpx;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.confirm-btn {
|
||||
background-color: #007aff;
|
||||
color: #fff;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.confirm-btn:active {
|
||||
background-color: #0062cc;
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
.cancel-btn {
|
||||
background-color: #f2f2f2;
|
||||
color: #666;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.cancel-btn:active {
|
||||
background-color: #e6e6e6;
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
.disabled-btn {
|
||||
background-color: #ccc;
|
||||
color: #fff;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.cargo-space-height {
|
||||
margin-top: 10rpx;
|
||||
padding: 10rpx;
|
||||
color: #666;
|
||||
font-size: 24rpx;
|
||||
background-color: #f8f8f8;
|
||||
border-radius: 6rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
padding: 15rpx;
|
||||
background-color: #f9f9f9;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
|
||||
.info-row {
|
||||
margin-bottom: 15rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
width: 180rpx;
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.info-value {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.quantity-row {
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.quantity-input {
|
||||
width: 200rpx;
|
||||
display: inline-block;
|
||||
background-color: #fff;
|
||||
border-radius: 4rpx;
|
||||
}
|
||||
|
||||
.no-data {
|
||||
text-align: center;
|
||||
padding: 30rpx;
|
||||
color: #999;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
</style>
|
||||
317
RuoYi-App-master/pages/in/bindPro.vue
Normal file
317
RuoYi-App-master/pages/in/bindPro.vue
Normal file
@@ -0,0 +1,317 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<view class="input-group">
|
||||
<uni-easyinput
|
||||
v-model="formData.trayCode"
|
||||
placeholder="请输入或扫码输入托盘条码"
|
||||
:clearable="true"
|
||||
@clear="handleClear"
|
||||
@confirm="handleConfirm"
|
||||
ref="trayCodeInput"
|
||||
auto-focus
|
||||
>
|
||||
<template #right>
|
||||
<text class="scan-icon" @click="handleScan">📷</text>
|
||||
</template>
|
||||
</uni-easyinput>
|
||||
</view>
|
||||
|
||||
<view class="info-group">
|
||||
<view class="info-item">
|
||||
<text class="info-label">物料名称:</text>
|
||||
<text class="info-value">{{productInfo.name}}</text>
|
||||
</view>
|
||||
<!-- <view class="info-item">
|
||||
<text class="info-label">批号:</text>
|
||||
<text class="info-value">{{productInfo.lotNo}}</text>
|
||||
</view> -->
|
||||
<view class="info-item">
|
||||
<text class="info-label">数量:</text>
|
||||
<uni-easyinput
|
||||
v-model="formData.inQuantity"
|
||||
type="number"
|
||||
:maxlength="String(productInfo.quantity).length"
|
||||
:placeholder="'最大可输入' + productInfo.quantity"
|
||||
@input="handleQuantityInput"
|
||||
ref="quantityInput"
|
||||
/>
|
||||
<!-- <text class="info-value" style="margin-left: 10rpx;">/{{productInfo.quantity}}</text> -->
|
||||
</view>
|
||||
</view>
|
||||
<view class="button-group">
|
||||
<button class="bind-button" @click="handleBind" :disabled="productInfo.quantity == 0" :class="{'bind-button-disabled': productInfo.quantity == 0}">绑定托盘</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getOrderGoods, bindTray } from '@/api/in/order.js'
|
||||
|
||||
export default {
|
||||
|
||||
onReady() {
|
||||
setTimeout(() => {
|
||||
this.$nextTick(() => {
|
||||
// console.log(this.$refs.trayCodeInput)
|
||||
this.$refs.trayCodeInput.onFocus()
|
||||
})
|
||||
}, 100)
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
formData: {
|
||||
trayCode: '',
|
||||
stockinDetailId: '',
|
||||
inQuantity:''
|
||||
},
|
||||
productInfo: {
|
||||
name: '',
|
||||
productId:'',
|
||||
quantity: 0
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
async onLoad(options) {
|
||||
if (options.stockinDetailId) {
|
||||
this.formData.stockinDetailId = options.stockinDetailId
|
||||
|
||||
|
||||
try {
|
||||
const response = await getOrderGoods({
|
||||
stockinDetailId: options.stockinDetailId
|
||||
})
|
||||
const product = response[0]
|
||||
console.log(product)
|
||||
// if (product) {
|
||||
this.productInfo = {
|
||||
name: product.extraField.materialDesc || '',
|
||||
productId: product.extraField.productId || '',
|
||||
quantity: product.quantity || 0
|
||||
// }
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取物料信息失败:', error)
|
||||
uni.showToast({
|
||||
title: '获取物料信息失败',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
methods: {
|
||||
|
||||
handleClear() {
|
||||
this.formData.trayCode = ''
|
||||
},
|
||||
handleQuantityInput(value) {
|
||||
const numValue = Number(value)
|
||||
if (numValue <= 0) {
|
||||
this.formData.inQuantity = ''
|
||||
uni.showToast({
|
||||
title: '数量必须大于0',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
if (numValue > this.productInfo.quantity) {
|
||||
this.formData.inQuantity = String(this.productInfo.quantity)
|
||||
uni.showToast({
|
||||
title: '不能超过最大数量',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
this.formData.inQuantity = String(numValue)
|
||||
},
|
||||
handleConfirm() {
|
||||
// 处理确认事件
|
||||
console.log('确认输入:', this.formData)
|
||||
// 将焦点转移到数量输入框
|
||||
this.$refs.quantityInput.focus()
|
||||
},
|
||||
handleScan() {
|
||||
// 调用扫码功能
|
||||
uni.scanCode({
|
||||
success: (res) => {
|
||||
this.formData.trayCode = res.result
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
async handleBind() {
|
||||
// 验证必填信息
|
||||
if (!this.formData.trayCode) {
|
||||
uni.showToast({
|
||||
title: '请输入托盘条码',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
if (!this.formData.inQuantity || Number(this.formData.inQuantity) <= 0) {
|
||||
uni.showToast({
|
||||
title: '请输入大于0的数量',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 确保提交的数量不超过最大可用数量
|
||||
const submitQuantity = Number(this.formData.inQuantity)
|
||||
if (submitQuantity > this.productInfo.quantity) {
|
||||
this.formData.inQuantity = String(this.productInfo.quantity)
|
||||
uni.showToast({
|
||||
title: '已自动调整为最大可用数量',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
|
||||
// try {
|
||||
const response = await bindTray(this.formData)
|
||||
|
||||
console.log(response)
|
||||
|
||||
if (response.code === 200) {
|
||||
uni.showToast({
|
||||
title: '绑定成功',
|
||||
icon: 'success'
|
||||
})
|
||||
// 返回上一页并传递刷新标记
|
||||
setTimeout(() => {
|
||||
const pages = getCurrentPages()
|
||||
const prevPage = pages[pages.length - 2]
|
||||
if (prevPage) {
|
||||
prevPage.$vm.needRefresh = true
|
||||
}
|
||||
uni.navigateBack()
|
||||
}, 1500)
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: response.msg || '绑定失败',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
// } catch (error) {
|
||||
// // console.error('绑定托盘失败:', error)
|
||||
// uni.showToast({
|
||||
// title: '绑定托盘失败',
|
||||
// icon: 'none'
|
||||
// })
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.container {
|
||||
padding: 20rpx;
|
||||
background-color: #f5f7fa;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.input-group {
|
||||
margin-bottom: 20rpx;
|
||||
background-color: #fff;
|
||||
padding: 20rpx;
|
||||
border-radius: 12rpx;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
.scan-icon {
|
||||
font-size: 40rpx;
|
||||
padding: 0 20rpx;
|
||||
color: #409eff;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.scan-icon:active {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.info-group {
|
||||
background-color: #fff;
|
||||
padding: 30rpx;
|
||||
border-radius: 12rpx;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
.info-item {
|
||||
margin-bottom: 24rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.info-item:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
color: #606266;
|
||||
margin-right: 16rpx;
|
||||
font-size: 28rpx;
|
||||
min-width: 140rpx;
|
||||
}
|
||||
|
||||
.info-value {
|
||||
color: #303133;
|
||||
font-weight: 500;
|
||||
font-size: 28rpx;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
:deep(.uni-easyinput__content) {
|
||||
background-color: #f5f7fa;
|
||||
border-radius: 8rpx;
|
||||
border: 2rpx solid #dcdfe6;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
:deep(.uni-easyinput__content-input) {
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
:deep(.is-input-border) {
|
||||
border-color: #dcdfe6 !important;
|
||||
}
|
||||
|
||||
:deep(.uni-easyinput__content:hover) {
|
||||
border-color: #c0c4cc;
|
||||
}
|
||||
|
||||
:deep(.uni-easyinput__content.is-focus) {
|
||||
border-color: #409eff;
|
||||
}
|
||||
|
||||
:deep(.is-disabled) {
|
||||
background-color: #f5f7fa;
|
||||
border-color: #e4e7ed;
|
||||
}
|
||||
|
||||
.button-group {
|
||||
margin-top: 40rpx;
|
||||
padding: 0 20rpx;
|
||||
}
|
||||
|
||||
.bind-button {
|
||||
width: 100%;
|
||||
height: 88rpx;
|
||||
line-height: 88rpx;
|
||||
background: linear-gradient(90deg, #409eff, #007aff);
|
||||
color: #fff;
|
||||
font-size: 32rpx;
|
||||
border-radius: 44rpx;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.bind-button:active {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.bind-button-disabled {
|
||||
background: linear-gradient(90deg, #a0cfff, #8cc5ff);
|
||||
cursor: not-allowed;
|
||||
}
|
||||
</style>
|
||||
436
RuoYi-App-master/pages/in/inorder.vue
Normal file
436
RuoYi-App-master/pages/in/inorder.vue
Normal file
@@ -0,0 +1,436 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<view class="search-box">
|
||||
<uni-easyinput
|
||||
v-model="stockinId"
|
||||
:placeholder="$t('inbound.inorder.searchPlaceholder')"
|
||||
:clearable="true"
|
||||
@clear="handleClear"
|
||||
@confirm="handleSearch"
|
||||
@input="handleSearch"
|
||||
ref="detailIdInput">
|
||||
<template #right>
|
||||
<text class="scan-icon" @click="handleScan">📷</text>
|
||||
</template>
|
||||
</uni-easyinput>
|
||||
</view>
|
||||
<view class="card-list">
|
||||
<view v-if="orderList && orderList.length > 0">
|
||||
<view v-for="(order, index) in orderList" :key="index" class="order-card">
|
||||
<uni-card>
|
||||
<view class="card-content">
|
||||
<view class="order-header" @click="handleOrderClick(order)">
|
||||
<view class="info-row">
|
||||
<text class="label">{{ $t('inbound.inorder.orderNumber') }}</text>
|
||||
<text class="value">{{ order.stockinId }}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="label">{{ $t('inbound.inorder.createTime') }}</text>
|
||||
<text class="value">{{ order.createDate }}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="label">{{ $t('inbound.inorder.supplier') }}</text>
|
||||
<text class="value">{{ order.supplierName }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 展开时显示物料信息 -->
|
||||
<view v-if="order.expanded && order.goodsList" class="goods-list" @click.stop>
|
||||
<view class="goods-title">{{ $t('inbound.inorder.goodsInfo') }}</view>
|
||||
<view class="goods-table">
|
||||
<view class="table-header">
|
||||
<text class="header-cell" style="display: none;">{{ $t('inbound.inorder.productCode') }}</text>
|
||||
<text class="header-cell">{{ $t('inbound.inorder.productName') }}</text>
|
||||
<text class="header-cell">{{ $t('inbound.inorder.planQuantity') }}</text>
|
||||
<text class="header-cell">{{ $t('inbound.inorder.inboundQuantity') }}</text>
|
||||
</view>
|
||||
<view v-for="(goods, goodsIndex) in order.goodsList" :key="goodsIndex" class="table-row">
|
||||
<text class="table-cell" style="display: none;">{{ goods.productId }}</text>
|
||||
<text class="table-cell material-name">{{ goods.extraField.materialDesc }}</text>
|
||||
<text class="table-cell">{{ goods.quantity }}</text>
|
||||
<view class="table-cell">
|
||||
<uni-easyinput
|
||||
v-model="goods.inQuantity"
|
||||
type="number"
|
||||
:maxlength="String(goods.quantity-goods.assignNum).length"
|
||||
:max="goods.quantity-goods.assignNum"
|
||||
@input="handleInQuantityChange(goods)"
|
||||
:min="0"
|
||||
style="width: 180rpx; display: inline-block;"
|
||||
/>
|
||||
</view>
|
||||
<view class="table-cell">
|
||||
<button class="operate-btn" @click.stop="handleInStock(goods)" :class="{'operate-btn-disabled': !isValidQuantity(goods)}">
|
||||
{{ $t('inbound.inorder.inbound') }}
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</uni-card>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else class="no-data">{{ $t('inbound.inorder.noOrderInfo') }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getInOrderList, getInOrderDetail, pkIn } from '@/api/in/order'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
stockinId: "",
|
||||
orderList: [],
|
||||
needRefresh: false
|
||||
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
onReady() {
|
||||
setTimeout(() => {
|
||||
this.$nextTick(() => {
|
||||
this.$refs.detailIdInput.onFocus()
|
||||
})
|
||||
}, 100)
|
||||
},
|
||||
onLoad() {
|
||||
this.getOrderList()
|
||||
},
|
||||
onShow() {
|
||||
if (this.needRefresh) {
|
||||
this.getOrderList()
|
||||
this.needRefresh = false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 获取入库单列表
|
||||
async getOrderList() {
|
||||
try {
|
||||
const response = await getInOrderList({"stockinId":this.stockinId})
|
||||
this.orderList = response.map(order => ({
|
||||
...order,
|
||||
expanded: false,
|
||||
goodsList: null
|
||||
}))
|
||||
} catch (error) {
|
||||
console.error('获取入库单列表失败:', error)
|
||||
uni.showToast({
|
||||
title: this.$t('inbound.inorder.getOrderListFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
},
|
||||
// 获取物品列表
|
||||
async getGoodsList(order) {
|
||||
try {
|
||||
const goodsResponse = await getInOrderDetail({
|
||||
stockinId: order.stockinId,
|
||||
pageSize:100,
|
||||
pageNum:1,
|
||||
status:1
|
||||
})
|
||||
order.goodsList = goodsResponse.rows.map(item => ({
|
||||
...item,
|
||||
inQuantity: item.quantity-item.assignNum
|
||||
}))
|
||||
} catch (error) {
|
||||
console.error('获取物品信息失败:', error)
|
||||
uni.showToast({
|
||||
title: this.$t('inbound.inorder.getItemInfoFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
},
|
||||
// 处理入库单点击
|
||||
async handleOrderClick(order) {
|
||||
// 切换展开状态
|
||||
order.expanded = !order.expanded
|
||||
// 如果展开且还没有加载物品列表,则加载物品列表
|
||||
if (order.expanded && !order.goodsList) {
|
||||
await this.getGoodsList(order)
|
||||
}
|
||||
},
|
||||
// 处理搜索
|
||||
handleSearch(value) {
|
||||
if (value !== undefined) {
|
||||
this.stockinId = value
|
||||
}
|
||||
this.getOrderList()
|
||||
},
|
||||
// 处理清除
|
||||
handleClear() {
|
||||
this.stockinId = ""
|
||||
this.getOrderList()
|
||||
},
|
||||
// 处理扫码
|
||||
handleScan() {
|
||||
uni.scanCode({
|
||||
success: (res) => {
|
||||
this.stockinId = res.result
|
||||
this.getOrderList()
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 验证入库数量是否有效
|
||||
isValidQuantity(goods) {
|
||||
const inQuantity = Number(goods.inQuantity);
|
||||
return inQuantity > 0 && inQuantity <= (goods.quantity - goods.assignNum);
|
||||
},
|
||||
|
||||
// 处理入库数量变化
|
||||
handleInQuantityChange(goods) {
|
||||
const maxQuantity = goods.quantity - goods.assignNum;
|
||||
if (Number(goods.inQuantity) > maxQuantity) {
|
||||
goods.inQuantity = maxQuantity;
|
||||
uni.showToast({
|
||||
title: this.$t('inbound.inorder.exceedInboundQuantity'),
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 处理入库操作
|
||||
async handleInStock(goods) {
|
||||
if (!this.isValidQuantity(goods)) {
|
||||
uni.showToast({
|
||||
title: this.$t('inbound.inorder.enterValidQuantity'),
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
await pkIn({
|
||||
stockinDetailId: goods.stockinDetailId,
|
||||
inQuantity: goods.inQuantity
|
||||
})
|
||||
|
||||
uni.showToast({
|
||||
title: this.$t('inbound.inorder.inboundSuccess'),
|
||||
icon: 'success'
|
||||
})
|
||||
|
||||
// 刷新列表
|
||||
this.getOrderList()
|
||||
} catch (error) {
|
||||
console.error('入库操作失败:', error)
|
||||
uni.showToast({
|
||||
title: this.$t('inbound.inorder.inboundFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.container {
|
||||
padding: 20rpx;
|
||||
background-color: #f8f9fc;
|
||||
}
|
||||
|
||||
.search-box {
|
||||
margin-bottom: 20rpx;
|
||||
position: relative;
|
||||
background-color: #fff;
|
||||
border-radius: 8rpx;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
|
||||
padding: 20rpx;
|
||||
|
||||
:deep(.uni-easyinput__content) {
|
||||
background-color: #f8f9fc;
|
||||
border-radius: 6rpx;
|
||||
border: 2rpx solid #e8e8e8;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:hover, &:focus-within {
|
||||
border-color: #409eff;
|
||||
}
|
||||
}
|
||||
|
||||
.scan-icon {
|
||||
padding: 0 20rpx;
|
||||
font-size: 40rpx;
|
||||
line-height: 70rpx;
|
||||
color: #409eff;
|
||||
cursor: pointer;
|
||||
transition: opacity 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.card-list {
|
||||
.order-card {
|
||||
margin-bottom: 20rpx;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
:deep(.uni-card) {
|
||||
background-color: #fff;
|
||||
border-radius: 8rpx;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
|
||||
border: none;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-2rpx);
|
||||
:deep(.uni-card) {
|
||||
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.card-content {
|
||||
.info-row {
|
||||
display: flex;
|
||||
margin-bottom: 16rpx;
|
||||
align-items: center;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.label {
|
||||
color: #909399;
|
||||
width: 160rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.value {
|
||||
color: #303133;
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.goods-list {
|
||||
margin-top: 20rpx;
|
||||
padding-top: 20rpx;
|
||||
border-top: 2rpx solid #ebeef5;
|
||||
|
||||
.goods-title {
|
||||
font-size: 28rpx;
|
||||
color: #606266;
|
||||
margin-bottom: 16rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.goods-table {
|
||||
width: 100%;
|
||||
border-radius: 6rpx;
|
||||
overflow: hidden;
|
||||
background-color: #f8f9fc;
|
||||
|
||||
.table-header {
|
||||
display: flex;
|
||||
background-color: #f2f3f5;
|
||||
padding: 16rpx;
|
||||
|
||||
.header-cell {
|
||||
flex: 1;
|
||||
color: #606266;
|
||||
font-size: 26rpx;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
|
||||
&:nth-child(1) {
|
||||
flex: 2;
|
||||
}
|
||||
|
||||
&:nth-child(2), &:nth-child(3) {
|
||||
flex: 0.8;
|
||||
}
|
||||
|
||||
&:nth-child(4) {
|
||||
flex: 1.2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.table-row {
|
||||
display: flex;
|
||||
padding: 16rpx;
|
||||
border-bottom: 2rpx solid #ebeef5;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.table-cell {
|
||||
flex: 1;
|
||||
color: #303133;
|
||||
font-size: 26rpx;
|
||||
text-align: center;
|
||||
padding: 0 8rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&:nth-child(1) {
|
||||
flex: 2;
|
||||
}
|
||||
|
||||
&:nth-child(2), &:nth-child(3) {
|
||||
flex: 0.8;
|
||||
}
|
||||
|
||||
&:nth-child(4) {
|
||||
flex: 1.2;
|
||||
}
|
||||
|
||||
&.material-name {
|
||||
overflow: visible;
|
||||
white-space: normal;
|
||||
word-break: break-word;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.operate-btn {
|
||||
background-color: #409eff;
|
||||
color: #fff;
|
||||
border: none;
|
||||
padding: 4rpx 20rpx;
|
||||
border-radius: 4rpx;
|
||||
font-size: 24rpx;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background-color: #66b1ff;
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: #3a8ee6;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.no-goods {
|
||||
text-align: center;
|
||||
color: #909399;
|
||||
font-size: 26rpx;
|
||||
padding: 30rpx 0;
|
||||
}
|
||||
}
|
||||
|
||||
.operate-btn-disabled {
|
||||
background-color: #c0c4cc !important;
|
||||
cursor: not-allowed !important;
|
||||
opacity: 0.6 !important;
|
||||
|
||||
&:hover {
|
||||
background-color: #c0c4cc !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
282
RuoYi-App-master/pages/in/klxin.vue
Normal file
282
RuoYi-App-master/pages/in/klxin.vue
Normal file
@@ -0,0 +1,282 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<view class="input-group">
|
||||
<text class="input-label">料箱条码:</text>
|
||||
<uni-easyinput
|
||||
v-model="formData.trayCode"
|
||||
placeholder="请输入或扫码输入料箱条码"
|
||||
:clearable="true"
|
||||
@clear="handleClear"
|
||||
@confirm="handleConfirm"
|
||||
ref="trayCodeInput"
|
||||
>
|
||||
<template #right>
|
||||
<text class="scan-icon" @click="handleScan">📷</text>
|
||||
</template>
|
||||
</uni-easyinput>
|
||||
</view>
|
||||
<view class="input-group">
|
||||
<text class="input-label">仓库</text>
|
||||
<uni-data-select
|
||||
v-model="formData.warehouseId"
|
||||
:localdata="warehouseList"
|
||||
:clear="false"
|
||||
placeholder="请选择仓库"
|
||||
/>
|
||||
</view>
|
||||
<view class="input-group">
|
||||
<text class="input-label">入口</text>
|
||||
<uni-data-select
|
||||
v-model="formData.entranceId"
|
||||
:localdata="entranceIdList"
|
||||
:clear="false"
|
||||
placeholder="请选择入口"
|
||||
/>
|
||||
</view>
|
||||
<view class="button-group">
|
||||
<button class="submit-button" @click="handleSubmit">空料箱入库</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { emptyBoxIn } from '@/api/in/ktpin.js'
|
||||
import { getBasWarehouList } from '@/api/bas/bas.js'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
formData: {
|
||||
trayCode: '',
|
||||
entranceId: '',
|
||||
warehouseId: ''
|
||||
},
|
||||
entranceIdList: [],
|
||||
warehouseList: []
|
||||
}
|
||||
},
|
||||
onReady() {
|
||||
setTimeout(() => {
|
||||
this.$nextTick(() => {
|
||||
this.$refs.trayCodeInput.onFocus()
|
||||
})
|
||||
}, 100)
|
||||
|
||||
this.getWarehouseList()
|
||||
},
|
||||
watch: {
|
||||
'formData.warehouseId': {
|
||||
handler(newVal) {
|
||||
if (newVal) {
|
||||
this.getEntranceList(newVal)
|
||||
} else {
|
||||
this.entranceIdList = []
|
||||
this.formData.entranceId = ''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
methods: {
|
||||
// 获取仓库列表
|
||||
async getWarehouseList() {
|
||||
try {
|
||||
const response = await getBasWarehouList({warehouseType:'2'})
|
||||
if (response.code === 200) {
|
||||
this.warehouseList = response.rows.map(item => ({
|
||||
value: item.warehouseId,
|
||||
text: item.warehouseName
|
||||
}))
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取仓库列表失败:', error)
|
||||
uni.showToast({
|
||||
title: '获取仓库列表失败',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
// 获取入口列表
|
||||
async getEntranceList(warehouseId) {
|
||||
try {
|
||||
// 这里需要根据实际API调整,暂时模拟不同仓库的入口数据
|
||||
// const response = await getWarehouseEntrances(warehouseId)
|
||||
const mockData = {
|
||||
'02': [
|
||||
{ value: 1, text: '东入口' },
|
||||
{ value: 2, text: '西入口' }
|
||||
],
|
||||
'06': [
|
||||
{ value: 3, text: '南入口' },
|
||||
{ value: 4, text: '北入口' }
|
||||
]
|
||||
}
|
||||
|
||||
this.entranceIdList = mockData[warehouseId] || []
|
||||
this.formData.entranceId = ''
|
||||
|
||||
} catch (error) {
|
||||
console.error('获取入口列表失败:', error)
|
||||
uni.showToast({
|
||||
title: '获取入口列表失败',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
handleClear() {
|
||||
this.formData.trayCode = ''
|
||||
},
|
||||
handleConfirm() {
|
||||
// 处理确认事件
|
||||
},
|
||||
handleScan() {
|
||||
// 调用扫码功能
|
||||
uni.scanCode({
|
||||
success: (res) => {
|
||||
this.formData.trayCode = res.result
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
async handleSubmit() {
|
||||
// 表单验证
|
||||
if (!this.formData.trayCode) {
|
||||
uni.showToast({
|
||||
title: '请扫描或输入托盘条码',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (!this.formData.entranceId) {
|
||||
uni.showToast({
|
||||
title: '请选择入口',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
if (!this.formData.warehouseId) {
|
||||
uni.showToast({
|
||||
title: '请选择仓库',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// try {
|
||||
const response = await emptyBoxIn(this.formData)
|
||||
if (response.code === 200) {
|
||||
uni.showToast({
|
||||
title: '空料箱入库成功',
|
||||
icon: 'success'
|
||||
})
|
||||
// 清空表单
|
||||
this.formData = {
|
||||
trayCode: '',
|
||||
warehouseId:'',
|
||||
entranceId: ''
|
||||
}
|
||||
// 重新聚焦到托盘条码输入框
|
||||
setTimeout(() => {
|
||||
this.$nextTick(() => {
|
||||
this.$refs.trayCodeInput.onFocus()
|
||||
})
|
||||
}, 100)
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: response.msg || '入库操作失败',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
// } catch (error) {
|
||||
// console.error('入库失败:', error)
|
||||
// uni.showToast({
|
||||
// title: '入库失败',
|
||||
// icon: 'none'
|
||||
// })
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.container {
|
||||
padding: 30rpx;
|
||||
background-color: #f8f9fc;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.input-group {
|
||||
margin-bottom: 30rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.input-label {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
width: 160rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
:deep(.uni-easyinput__content) {
|
||||
background-color: #fff;
|
||||
border-radius: 12rpx;
|
||||
border: 2rpx solid #e8e8e8;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:focus-within {
|
||||
border-color: #2979ff;
|
||||
box-shadow: 0 4rpx 16rpx rgba(41, 121, 255, 0.1);
|
||||
transform: translateY(-2rpx);
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.uni-easyinput__content-input) {
|
||||
height: 88rpx;
|
||||
padding: 0 30rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.scan-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 88rpx;
|
||||
height: 88rpx;
|
||||
font-size: 40rpx;
|
||||
color: #2979ff;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.9);
|
||||
}
|
||||
}
|
||||
|
||||
.button-group {
|
||||
padding: 30rpx;
|
||||
margin-top: 20rpx;
|
||||
|
||||
.submit-button {
|
||||
width: 100%;
|
||||
height: 88rpx;
|
||||
line-height: 88rpx;
|
||||
background-color: #2979ff;
|
||||
color: #fff;
|
||||
font-size: 32rpx;
|
||||
border-radius: 12rpx;
|
||||
box-shadow: 0 4rpx 16rpx rgba(41, 121, 255, 0.2);
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.98);
|
||||
box-shadow: 0 2rpx 8rpx rgba(41, 121, 255, 0.2);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
459
RuoYi-App-master/pages/in/ktpin.vue
Normal file
459
RuoYi-App-master/pages/in/ktpin.vue
Normal file
@@ -0,0 +1,459 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<view class="input-group">
|
||||
<text class="input-label">{{ $t('inbound.emptyPalletBox.emptyPallet.trayCode') }}</text>
|
||||
<uni-easyinput
|
||||
v-model="formData.trayCode"
|
||||
:placeholder="$t('inbound.emptyPalletBox.emptyPallet.trayCodePlaceholder')"
|
||||
:clearable="true"
|
||||
@clear="handleClear"
|
||||
@confirm="handleConfirm"
|
||||
ref="trayCodeInput"
|
||||
|
||||
>
|
||||
<template #right>
|
||||
<text class="scan-icon" @click="handleScan">📷</text>
|
||||
</template>
|
||||
</uni-easyinput>
|
||||
</view>
|
||||
<view class="input-group">
|
||||
<text class="input-label">{{ $t('inbound.emptyPalletBox.emptyPallet.warehouse') }}</text>
|
||||
<uni-data-select
|
||||
v-model="formData.warehouseId"
|
||||
:localdata="warehouseList"
|
||||
:clear="false"
|
||||
:placeholder="$t('inbound.emptyPalletBox.emptyPallet.warehousePlaceholder')"
|
||||
@change="handleWarehouseChange"
|
||||
/>
|
||||
</view>
|
||||
<view class="input-group" v-if="currentWarehouseType == '1'">
|
||||
<text class="input-label">{{ $t('inbound.emptyPalletBox.emptyPallet.cargoSpace') }}</text>
|
||||
<view class="cargo-input-group">
|
||||
<uni-easyinput
|
||||
v-model="formData.cargoSpaceName"
|
||||
:placeholder="$t('inbound.emptyPalletBox.emptyPallet.cargoSpacePlaceholder')"
|
||||
:clearable="true"
|
||||
@input="handleCargoSpaceInput"
|
||||
/>
|
||||
<button class="recommend-btn" @click="handleRecommendCargoSpace">{{ $t('inbound.emptyPalletBox.emptyPallet.recommendCargoSpace') }}</button>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="currentWarehouseType == '1' && cargoSpaceHeight" class="cargo-space-info">
|
||||
<text class="cargo-space-height">{{ $t('inbound.emptyPalletBox.emptyPallet.cargoSpaceHeight') }}{{ cargoSpaceHeight }}{{ $t('inbound.emptyPalletBox.emptyPallet.meter') }}</text>
|
||||
</view>
|
||||
<view class="button-group">
|
||||
<button class="submit-button" @click="handleSubmit">{{ $t('inbound.emptyPalletBox.emptyPallet.submit') }}</button>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { emptyTrayIn } from '@/api/in/ktpin.js'
|
||||
import { getBasWarehouList,getCargoSpaceList } from '@/api/bas/bas.js'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
formData: {
|
||||
trayCode: '',
|
||||
warehouseId: '',
|
||||
cargoSpaceId: '',
|
||||
cargoSpaceName:'',
|
||||
|
||||
},
|
||||
warehouseList: [],
|
||||
cargoSpaceId: '',
|
||||
cargoSpaceList: [],
|
||||
currentWarehouseType: null,
|
||||
cargoSpaceHeight:''
|
||||
}
|
||||
},
|
||||
onReady() {
|
||||
setTimeout(() => {
|
||||
this.$nextTick(() => {
|
||||
this.$refs.trayCodeInput.onFocus()
|
||||
})
|
||||
}, 100)
|
||||
|
||||
// 获取仓库列表
|
||||
this.getWarehouseList()
|
||||
},
|
||||
methods: {
|
||||
// 获取仓库列表
|
||||
async getWarehouseList() {
|
||||
try {
|
||||
const response = await getBasWarehouList({
|
||||
pageNum:1,
|
||||
pageSize:100,
|
||||
typeData:['1','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.emptyPalletBox.emptyPallet.getWarehouseListFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
handleClear() {
|
||||
this.formData.trayCode = ''
|
||||
},
|
||||
handleConfirm() {
|
||||
// 处理确认事件
|
||||
},
|
||||
handleScan() {
|
||||
// 调用扫码功能
|
||||
uni.scanCode({
|
||||
success: (res) => {
|
||||
this.formData.trayCode = res.result
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
handleWarehouseChange(warehouseId) {
|
||||
if (!warehouseId) return
|
||||
const selectedWarehouse = this.warehouseList.find(item => item.value === warehouseId)
|
||||
this.currentWarehouseType = selectedWarehouse ? selectedWarehouse.type : null
|
||||
|
||||
},
|
||||
// 处理货位选择
|
||||
async handleRecommendCargoSpace() {
|
||||
// try {
|
||||
const response = await getCargoSpaceList({ warehouseId: this.formData.warehouseId, status: 1 })
|
||||
if (response.code === 200 && response.rows.length > 0) {
|
||||
// 获取第一个推荐货位
|
||||
this.formData.cargoSpaceId = response.rows[0].cargoSpaceId
|
||||
this.formData.cargoSpaceName = response.rows[0].cargoSpaceName
|
||||
// 手动触发handleCargoSpaceInput方法获取货位高度信息
|
||||
await this.handleCargoSpaceInput(response.rows[0].cargoSpaceName)
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: this.$t('inbound.emptyPalletBox.emptyPallet.noAvailableCargoSpace'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
// } catch (error) {
|
||||
// uni.showToast({
|
||||
// title: '获取推荐货位失败',
|
||||
// icon: 'none'
|
||||
// })
|
||||
// }
|
||||
},
|
||||
// 处理货位选择
|
||||
async handleCargoSpaceInput(value) {
|
||||
if (value) {
|
||||
try {
|
||||
const response = await getCargoSpaceList({ cargoSpaceName: value, warehouseId: this.formData.warehouseId })
|
||||
if (response.code === 200 && response.rows.length > 0) {
|
||||
this.formData.cargoSpaceId = response.rows[0].cargoSpaceId
|
||||
this.cargoSpaceHeight = response.rows[0].cargoHight
|
||||
console.log(this.formData.cargoSpaceId)
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: this.$t('inbound.emptyPalletBox.emptyPallet.getCargoSpaceInfoFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
this.formData.cargoSpaceId = ''
|
||||
this.cargoSpaceHeight = null
|
||||
}
|
||||
} catch (error) {
|
||||
uni.showToast({
|
||||
title: this.$t('inbound.emptyPalletBox.emptyPallet.getCargoSpaceInfoFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
this.formData.cargoSpaceId = ''
|
||||
this.cargoSpaceHeight = null
|
||||
}
|
||||
} else {
|
||||
this.formData.cargoSpaceId = ''
|
||||
this.cargoSpaceHeight = null
|
||||
}
|
||||
},
|
||||
async handleSubmit() {
|
||||
if (!this.formData.trayCode) {
|
||||
uni.showToast({
|
||||
title: this.$t('inbound.emptyPalletBox.emptyPallet.enterTrayCode'),
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
if (!this.formData.warehouseId) {
|
||||
uni.showToast({
|
||||
title: this.$t('inbound.emptyPalletBox.emptyPallet.selectWarehouse'),
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
if (this.currentWarehouseType === '1' && (!this.formData.cargoSpaceId || this.formData.cargoSpaceId === null)) {
|
||||
uni.showToast({
|
||||
title: this.$t('inbound.emptyPalletBox.emptyPallet.selectCargoSpace'),
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
await emptyTrayIn(this.formData).then(response => {
|
||||
if (response.code === 200) {
|
||||
uni.showToast({
|
||||
title: this.$t('inbound.emptyPalletBox.emptyPallet.inboundSuccess'),
|
||||
icon: 'success'
|
||||
})
|
||||
// 清空表单
|
||||
this.formData = {
|
||||
trayCode: '',
|
||||
warehouseId: '',
|
||||
cargoSpaceId: '',
|
||||
cargoSpaceName: ''
|
||||
}
|
||||
this.cargoSpaceHeight=''
|
||||
this.currentWarehouseType=null
|
||||
// 重新聚焦到托盘条码输入框
|
||||
setTimeout(() => {
|
||||
this.$nextTick(() => {
|
||||
this.$refs.trayCodeInput.onFocus()
|
||||
})
|
||||
}, 100)
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: response.msg || this.$t('inbound.emptyPalletBox.emptyPallet.inboundOperationFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}).catch(error => {
|
||||
console.error('入库失败:', error)
|
||||
uni.showToast({
|
||||
title: this.$t('inbound.emptyPalletBox.emptyPallet.inboundFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.container {
|
||||
padding: 30rpx;
|
||||
background-color: #f8f9fc;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.input-group {
|
||||
margin-bottom: 30rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.input-label {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
width: 160rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
:deep(.uni-easyinput__content) {
|
||||
background-color: #fff;
|
||||
border-radius: 12rpx;
|
||||
border: 2rpx solid #e8e8e8;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:focus-within {
|
||||
border-color: #2979ff;
|
||||
box-shadow: 0 4rpx 16rpx rgba(41, 121, 255, 0.1);
|
||||
transform: translateY(-2rpx);
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.uni-easyinput__content-input) {
|
||||
height: 88rpx;
|
||||
padding: 0 30rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.scan-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 88rpx;
|
||||
height: 88rpx;
|
||||
font-size: 40rpx;
|
||||
color: #2979ff;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.9);
|
||||
}
|
||||
}
|
||||
|
||||
.button-group {
|
||||
padding: 30rpx;
|
||||
margin-top: 20rpx;
|
||||
|
||||
.submit-button {
|
||||
width: 100%;
|
||||
height: 88rpx;
|
||||
line-height: 88rpx;
|
||||
background-color: #2979ff;
|
||||
color: #fff;
|
||||
font-size: 32rpx;
|
||||
border-radius: 12rpx;
|
||||
box-shadow: 0 4rpx 16rpx rgba(41, 121, 255, 0.2);
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.98);
|
||||
box-shadow: 0 2rpx 8rpx rgba(41, 121, 255, 0.2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.cargo-info {
|
||||
padding: 0 30rpx;
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
|
||||
.cargo-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.cargo-label {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.cargo-value {
|
||||
font-size: 32rpx;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.table-container {
|
||||
margin: 20rpx 30rpx;
|
||||
background-color: #fff;
|
||||
border-radius: 12rpx;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.selected-row {
|
||||
background-color: #e6f0ff !important;
|
||||
}
|
||||
|
||||
:deep(.uni-table-tr) {
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
}
|
||||
|
||||
.cargo-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 20rpx;
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.cargo-item {
|
||||
background-color: #fff;
|
||||
padding: 30rpx 20rpx;
|
||||
text-align: center;
|
||||
border-radius: 12rpx;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
|
||||
transition: all 0.3s ease;
|
||||
cursor: pointer;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
}
|
||||
|
||||
.selected-item {
|
||||
background-color: #e6f0ff;
|
||||
border: 2rpx solid #2979ff;
|
||||
transform: translateY(-2rpx);
|
||||
box-shadow: 0 4rpx 16rpx rgba(41, 121, 255, 0.1);
|
||||
}
|
||||
|
||||
.cargo-input-group {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20rpx;
|
||||
|
||||
:deep(.uni-easyinput__content) {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.recommend-btn {
|
||||
padding: 0 30rpx;
|
||||
height: 88rpx;
|
||||
line-height: 88rpx;
|
||||
background-color: #2979ff;
|
||||
color: #fff;
|
||||
font-size: 28rpx;
|
||||
border-radius: 12rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(41, 121, 255, 0.2);
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
}
|
||||
|
||||
.popup-content {
|
||||
background-color: #fff;
|
||||
border-radius: 12rpx;
|
||||
width: 600rpx;
|
||||
padding: 30rpx;
|
||||
}
|
||||
|
||||
.popup-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
text-align: center;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.popup-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 20rpx;
|
||||
margin-top: 30rpx;
|
||||
|
||||
button {
|
||||
padding: 0 40rpx;
|
||||
height: 80rpx;
|
||||
line-height: 80rpx;
|
||||
font-size: 28rpx;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
|
||||
.cancel-btn {
|
||||
background-color: #f5f5f5;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.confirm-btn {
|
||||
background-color: #2979ff;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
159
RuoYi-App-master/pages/in/menu.vue
Normal file
159
RuoYi-App-master/pages/in/menu.vue
Normal file
@@ -0,0 +1,159 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<view class="function-list">
|
||||
<view class="function-item" @click="navigateTo('/pages/in/qualityCheck')">
|
||||
<view class="icon-box blue">
|
||||
<image src="/static/images/tabbar/tray121.png" mode="aspectFit" class="icon-image" style="width: 40rpx; height: 40rpx;"></image>
|
||||
</view>
|
||||
<view class="function-text">
|
||||
<text class="title">{{ $t('inbound.qualityCheck.title') }}</text>
|
||||
<text class="desc">{{ $t('inbound.qualityCheck.desc') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- <view class="function-item" @click="navigateTo('/pages/in/klxin')">
|
||||
<view class="icon-box blue">
|
||||
<image src="/static/images/tabbar/tray121.png" mode="aspectFit" class="icon-image" style="width: 40rpx; height: 40rpx;"></image>
|
||||
</view>
|
||||
<view class="function-text">
|
||||
<text class="title">空料箱入库</text>
|
||||
<text class="desc">空料箱收货入库</text>
|
||||
</view>
|
||||
</view> -->
|
||||
<view class="function-item" @click="navigateTo('/pages/in/ktpin')">
|
||||
<view class="icon-box blue">
|
||||
<image src="/static/images/tabbar/tray121.png" mode="aspectFit" class="icon-image" style="width: 40rpx; height: 40rpx;"></image>
|
||||
</view>
|
||||
<view class="function-text">
|
||||
<text class="title">{{ $t('inbound.emptyPalletBox.title') }}</text>
|
||||
<text class="desc">{{ $t('inbound.emptyPalletBox.desc') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="function-item" @click="navigateTo('/pages/in/inorder')">
|
||||
<view class="icon-box blue">
|
||||
<image src="/static/images/tabbar/dingdandanjuwenjian-2.png" mode="aspectFit" class="icon-image" style="width: 40rpx; height: 40rpx;"></image>
|
||||
</view>
|
||||
<view class="function-text">
|
||||
<text class="title">{{ $t('inbound.inorder.title') }}</text>
|
||||
<text class="desc">{{ $t('inbound.inorder.desc') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="function-item" @click="navigateTo('/pages/in/bindMsg')">
|
||||
<view class="icon-box blue">
|
||||
<image src="/static/images/tabbar/list.png" mode="aspectFit" class="icon-image" style="width: 40rpx; height: 40rpx;"></image>
|
||||
</view>
|
||||
<view class="function-text">
|
||||
<text class="title">{{ $t('inbound.bindMsg.title') }}</text>
|
||||
<text class="desc">{{ $t('inbound.bindMsg.desc') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="function-item" @click="navigateTo('/pages/in/backIn')">
|
||||
<view class="icon-box blue">
|
||||
<image src="/static/images/tabbar/list.png" mode="aspectFit" class="icon-image" style="width: 40rpx; height: 40rpx;"></image>
|
||||
</view>
|
||||
<view class="function-text">
|
||||
<text class="title">{{ $t('inbound.backIn.title') }}</text>
|
||||
<text class="desc">{{ $t('inbound.backIn.desc') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import tab from '@/plugins/tab'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
methods: {
|
||||
navigateTo(url) {
|
||||
tab.navigateTo(url)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.container {
|
||||
padding: 20rpx;
|
||||
background-color: #f5f7fa;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.function-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24rpx;
|
||||
}
|
||||
|
||||
.function-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: #fff;
|
||||
padding: 32rpx;
|
||||
border-radius: 16rpx;
|
||||
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-4rpx);
|
||||
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
&:active {
|
||||
transform: translateY(0);
|
||||
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
}
|
||||
|
||||
.icon-box {
|
||||
width: 88rpx;
|
||||
height: 88rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
margin-right: 32rpx;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&.blue {
|
||||
background: linear-gradient(135deg, #409eff, #3a8ee6);
|
||||
box-shadow: 0 6rpx 16rpx rgba(64, 158, 255, 0.25);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
transform: rotate(15deg) scale(1.1);
|
||||
}
|
||||
}
|
||||
|
||||
.icon-image {
|
||||
width: 44rpx;
|
||||
height: 44rpx;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
color: #fff;
|
||||
font-size: 44rpx;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.function-text {
|
||||
flex: 1;
|
||||
|
||||
.title {
|
||||
font-size: 34rpx;
|
||||
color: #2c3e50;
|
||||
font-weight: 600;
|
||||
margin-bottom: 10rpx;
|
||||
letter-spacing: 1rpx;
|
||||
}
|
||||
|
||||
.desc {
|
||||
font-size: 26rpx;
|
||||
color: #7f8c8d;
|
||||
letter-spacing: 0.5rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
429
RuoYi-App-master/pages/in/qualityCheck.vue
Normal file
429
RuoYi-App-master/pages/in/qualityCheck.vue
Normal file
@@ -0,0 +1,429 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<!-- 单据列表 -->
|
||||
<view class="order-list" v-if="orderList.length > 0">
|
||||
<uni-card v-for="(item, index) in orderList" :key="index" class="order-card">
|
||||
<view class="order-info" @click="handleOrderClick(item)">
|
||||
<view class="info-row">
|
||||
<text class="label">{{ $t('inbound.qualityCheck.orderNumber') }}</text>
|
||||
<text class="value">{{ item.stockinId }}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="label">{{ $t('inbound.qualityCheck.supplier') }}</text>
|
||||
<text class="value">{{ item.supplierName }}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="label">{{ $t('inbound.qualityCheck.warehouse') }}</text>
|
||||
<text class="value">{{ item.warehouseName }}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="label">{{ $t('inbound.qualityCheck.createTime') }}</text>
|
||||
<text class="value">{{ item.createDate }}</text>
|
||||
</view>
|
||||
<view class="expand-icon" :class="{'expanded': item.isExpanded}">
|
||||
<text>{{ item.isExpanded ? $t('inbound.qualityCheck.collapse') : $t('inbound.qualityCheck.expand') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 物料详情 -->
|
||||
<view class="material-detail" v-if="item.isExpanded && item.materials && item.materials.length > 0">
|
||||
<view class="material-header">
|
||||
<button class="check-all-button" @click="handleCheckAll(index)">{{ $t('inbound.qualityCheck.checkAll') }}</button>
|
||||
</view>
|
||||
<view class="material-list">
|
||||
<view v-for="(material, mIndex) in item.materials" :key="mIndex" class="material-item">
|
||||
<view class="material-row" :class="{'checked': material.stockStatus === '1'}">
|
||||
<!-- <text class="material-code">{{ material.productId }}</text> -->
|
||||
<text class="material-name">{{ material.extraField.materialDesc }}</text>
|
||||
<view class="material-quantity">
|
||||
<text>{{ $t('inbound.qualityCheck.quantity') }}</text>
|
||||
<uni-easyinput
|
||||
v-model="material.quantity"
|
||||
type="number"
|
||||
|
||||
@input="handleQuantityChange(index, mIndex, $event)"
|
||||
style="width: 200rpx; display: inline-block;"
|
||||
/>
|
||||
</view>
|
||||
<text class="material-status" :class="{'status-checked': material.stockStatus == '1'}">
|
||||
{{ material.stockStatus == '1' ? $t('inbound.qualityCheck.checked') : $t('inbound.qualityCheck.unchecked') }}
|
||||
</text>
|
||||
<button class="check-button" @click="handleQualityCheck(index, mIndex)">{{ $t('inbound.qualityCheck.check') }}</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</uni-card>
|
||||
</view>
|
||||
<view v-else class="no-data">
|
||||
<text>{{ $t('inbound.qualityCheck.noOrders') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getQualityCheckOrders, getOrderMaterials,updateReceiveStockinStatus,updateAllReceiveStockinStatus } from '@/api/in/order.js'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
orderList: []
|
||||
}
|
||||
},
|
||||
onReady() {
|
||||
this.fetchOrderList()
|
||||
},
|
||||
methods: {
|
||||
// 获取质检单据列表
|
||||
async fetchOrderList() {
|
||||
try {
|
||||
const response = await getQualityCheckOrders({status:'0'})
|
||||
if (response.code === 200) {
|
||||
this.orderList = response.rows.map(order => ({
|
||||
...order,
|
||||
isExpanded: false,
|
||||
materials: []
|
||||
}))
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: response.msg || this.$t('inbound.qualityCheck.getOrdersFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取单据列表失败:', error)
|
||||
uni.showToast({
|
||||
title: this.$t('inbound.qualityCheck.getOrdersFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
},
|
||||
// 点击单据卡片
|
||||
async handleOrderClick(order) {
|
||||
const index = this.orderList.findIndex(item => item.stockinId === order.stockinId)
|
||||
if (index === -1) return
|
||||
|
||||
// 切换展开状态
|
||||
this.$set(this.orderList[index], 'isExpanded', !this.orderList[index].isExpanded)
|
||||
|
||||
// 如果是展开状态且还没有加载物料信息,则获取物料信息
|
||||
if (this.orderList[index].isExpanded && this.orderList[index].materials.length === 0) {
|
||||
try {
|
||||
const response = await getOrderMaterials({
|
||||
stockinId: order.stockinId,
|
||||
status: '0'
|
||||
})
|
||||
if (response.code === 200) {
|
||||
this.$set(this.orderList[index], 'materials', response.rows)
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: response.msg || this.$t('inbound.qualityCheck.getMaterialsFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取物料信息失败:', error)
|
||||
uni.showToast({
|
||||
title: this.$t('inbound.qualityCheck.getMaterialsFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
// 全部质检
|
||||
async handleCheckAll(index) {
|
||||
const order = this.orderList[index]
|
||||
if (!order.materials || order.materials.length === 0) {
|
||||
uni.showToast({
|
||||
title: this.$t('inbound.qualityCheck.noMaterials'),
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 收集所有未质检物料的信息
|
||||
const materials = order.materials
|
||||
.map(material => ({
|
||||
stockinDetailId: material.stockinDetailId,
|
||||
quantity: material.quantity
|
||||
}))
|
||||
|
||||
if (materials.length === 0) {
|
||||
uni.showToast({
|
||||
title: this.$t('inbound.qualityCheck.allChecked'),
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await updateAllReceiveStockinStatus({
|
||||
stockinGuid: order.stockinGuid,
|
||||
list: materials
|
||||
})
|
||||
|
||||
if (response.code === 200) {
|
||||
uni.showToast({
|
||||
title: this.$t('inbound.qualityCheck.batchCheckSuccess'),
|
||||
icon: 'success'
|
||||
})
|
||||
|
||||
// 重新获取当前单据的物料列表
|
||||
// const materialsResponse = await getOrderMaterials({
|
||||
// stockinId: order.stockinId,
|
||||
// status: '0'
|
||||
// })
|
||||
// if (materialsResponse.code === 200) {
|
||||
// this.$set(this.orderList[index], 'materials', materialsResponse.rows)
|
||||
// }
|
||||
this.fetchOrderList()
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: response.msg || this.$t('inbound.qualityCheck.batchCheckFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('批量质检失败:', error)
|
||||
uni.showToast({
|
||||
title: this.$t('inbound.qualityCheck.batchCheckFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
// 质检操作
|
||||
async handleQualityCheck(index, mIndex) {
|
||||
const material = this.orderList[index].materials[mIndex]
|
||||
const response = await updateReceiveStockinStatus({
|
||||
stockinDetailId: material.stockinDetailId,
|
||||
quantity: material.quantity,
|
||||
stockinGuid:material.stockinGuid,
|
||||
stockStatus: '1'
|
||||
})
|
||||
if (response.code === 200) {
|
||||
uni.showToast({
|
||||
title: `${material.extraField.materialDesc} ${this.$t('inbound.qualityCheck.checkSuccess')}`,
|
||||
icon: 'success'
|
||||
})
|
||||
// 重新获取当前单据的物料列表
|
||||
const materialsResponse = await getOrderMaterials({
|
||||
stockinId: this.orderList[index].stockinId,
|
||||
status: '0'
|
||||
})
|
||||
if (materialsResponse.code === 200) {
|
||||
this.$set(this.orderList[index], 'materials', materialsResponse.rows)
|
||||
}
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: response.msg || this.$t('inbound.qualityCheck.checkFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
// 在methods中添加数量变化处理方法
|
||||
async handleQuantityChange(index, mIndex, value) {
|
||||
const material = this.orderList[index].materials[mIndex]
|
||||
const newQuantity = Number(value)
|
||||
|
||||
// 验证输入值
|
||||
if (isNaN(newQuantity) || newQuantity < 0) {
|
||||
uni.showToast({
|
||||
title: this.$t('inbound.qualityCheck.invalidQuantity'),
|
||||
icon: 'none'
|
||||
})
|
||||
material.quantity = material.quantity
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: 调用后端接口更新数量
|
||||
// 这里可以添加调用后端接口的逻辑
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.container {
|
||||
padding: 20rpx;
|
||||
|
||||
.order-list {
|
||||
.order-card {
|
||||
margin-bottom: 20rpx;
|
||||
background: #fff;
|
||||
border-radius: 12rpx;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
|
||||
|
||||
.order-info {
|
||||
position: relative;
|
||||
padding: 24rpx 100rpx 24rpx 24rpx;
|
||||
|
||||
.info-row {
|
||||
display: flex;
|
||||
margin-bottom: 16rpx;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.label {
|
||||
color: #909399;
|
||||
width: 160rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.value {
|
||||
color: #303133;
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.expand-icon {
|
||||
position: absolute;
|
||||
right: 24rpx;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
color: #409EFF;
|
||||
font-size: 26rpx;
|
||||
padding: 12rpx 20rpx;
|
||||
border-radius: 6rpx;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&.expanded {
|
||||
color: #909399;
|
||||
transform: translateY(-50%) rotate(180deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.material-detail {
|
||||
margin: 0 24rpx 24rpx;
|
||||
transition: all 0.3s ease;
|
||||
max-height: 600rpx;
|
||||
overflow-y: auto;
|
||||
|
||||
.material-header {
|
||||
padding: 20rpx 0;
|
||||
border-bottom: 1px solid #EBEEF5;
|
||||
|
||||
.check-all-button {
|
||||
background-color: #409EFF;
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 4rpx;
|
||||
padding: 12rpx 24rpx;
|
||||
font-size: 26rpx;
|
||||
cursor: pointer;
|
||||
|
||||
&:active {
|
||||
background-color: #3a8ee6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.material-list {
|
||||
.material-item {
|
||||
border-bottom: 1px solid #EBEEF5;
|
||||
|
||||
.material-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 20rpx 0;
|
||||
gap: 20rpx;
|
||||
flex-wrap: nowrap;
|
||||
|
||||
.material-code {
|
||||
color: #909399;
|
||||
font-size: 24rpx;
|
||||
width: 160rpx;
|
||||
}
|
||||
|
||||
.material-name {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
color: #303133;
|
||||
min-width: 200rpx;
|
||||
word-break: break-word;
|
||||
white-space: normal;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.material-quantity {
|
||||
font-size: 26rpx;
|
||||
color: #606266;
|
||||
width: 250rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10rpx;
|
||||
}
|
||||
|
||||
.check-button {
|
||||
background-color: #409EFF;
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 4rpx;
|
||||
padding: 12rpx 24rpx;
|
||||
font-size: 26rpx;
|
||||
cursor: pointer;
|
||||
min-width: 100rpx;
|
||||
|
||||
&:active {
|
||||
background-color: #3a8ee6;
|
||||
}
|
||||
|
||||
&.button-disabled {
|
||||
background-color: #c0c4cc !important;
|
||||
cursor: not-allowed;
|
||||
opacity: 0.7;
|
||||
|
||||
&:active {
|
||||
background-color: #c0c4cc !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.no-data {
|
||||
text-align: center;
|
||||
padding: 60rpx;
|
||||
color: #909399;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.material-row {
|
||||
&.checked {
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
|
||||
.material-status {
|
||||
font-size: 26rpx;
|
||||
padding: 4rpx 12rpx;
|
||||
border-radius: 4rpx;
|
||||
background-color: #e6a23c;
|
||||
color: #fff;
|
||||
|
||||
&.status-checked {
|
||||
background-color: #67c23a;
|
||||
}
|
||||
}
|
||||
|
||||
.check-button {
|
||||
&.button-disabled {
|
||||
background-color: #c0c4cc;
|
||||
cursor: not-allowed;
|
||||
|
||||
&:active {
|
||||
background-color: #c0c4cc;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user