437 lines
9.3 KiB
Vue
437 lines
9.3 KiB
Vue
<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>
|