diff --git a/src/pages/stock/in.vue b/src/pages/stock/in.vue index eee09c1..a2d25de 100644 --- a/src/pages/stock/in.vue +++ b/src/pages/stock/in.vue @@ -1,45 +1,121 @@ @@ -50,55 +126,131 @@ import productApi from '@/api/product' export default { data() { return { + categoryId: '', + categories: [], productList: [], - selectedProduct: null, - quantity: '', - remark: '', + page: 1, + pageSize: 50, + loading: false, + + // 已选择的商品 + selectedItems: [], + + // 弹窗相关 + showPopup: false, + currentProduct: {}, + inputQuantity: 1, + inputRemark: '', + + // 提交状态 submitting: false } }, + computed: { + totalQuantity() { + return this.selectedItems.reduce((sum, item) => sum + item.quantity, 0) + } + }, onLoad() { + this.loadCategories() this.getProducts() }, methods: { - async getProducts() { + async loadCategories() { try { - const res = await productApi.getProducts({ page: 1, pageSize: 100 }) - if (res.code === 0) { - this.productList = res.data.records || [] - } + const categories = await productApi.getCategories() + this.categories = categories || [] } catch (e) { - uni.showToast({ title: '加载商品失败', icon: 'none' }) + console.error(e) } }, - onProductChange(e) { - this.selectedProduct = this.productList[e.detail.value] + async getProducts() { + this.loading = true + try { + const res = await productApi.getProducts({ + categoryId: this.categoryId, + page: this.page, + pageSize: this.pageSize + }) + this.productList = res.records || [] + } catch (e) { + uni.showToast({ title: '加载失败', icon: 'none' }) + } finally { + this.loading = false + } }, - async submit() { - if (!this.selectedProduct) { - uni.showToast({ title: '请选择商品', icon: 'none' }) + selectCategory(id) { + this.categoryId = id + this.page = 1 + this.getProducts() + }, + openQuantityPopup(product) { + this.currentProduct = product + this.inputQuantity = 1 + this.inputRemark = '' + this.showPopup = true + }, + closePopup() { + this.showPopup = false + }, + qtyMinus() { + if (this.inputQuantity > 1) { + this.inputQuantity-- + } + }, + qtyPlus() { + this.inputQuantity++ + }, + confirmAdd() { + if (this.inputQuantity <= 0) { + uni.showToast({ title: '请输入有效数量', icon: 'none' }) return } - if (!this.quantity || this.quantity <= 0) { - uni.showToast({ title: '请输入有效数量', icon: 'none' }) + + // 检查是否已存在,存在则累加 + const existsIndex = this.selectedItems.findIndex( + item => item.productId === this.currentProduct.productId + ) + + if (existsIndex > -1) { + this.selectedItems[existsIndex].quantity += parseInt(this.inputQuantity) + this.selectedItems[existsIndex].remark = this.inputRemark || this.selectedItems[existsIndex].remark + } else { + this.selectedItems.push({ + productId: this.currentProduct.productId, + productName: this.currentProduct.name, + quantity: parseInt(this.inputQuantity), + remark: this.inputRemark + }) + } + + this.closePopup() + uni.showToast({ title: '已添加', icon: 'success' }) + }, + removeItem(index) { + this.selectedItems.splice(index, 1) + }, + async submit() { + if (this.selectedItems.length === 0) { + uni.showToast({ title: '请先添加商品', icon: 'none' }) return } this.submitting = true try { - const res = await stockApi.stockIn({ - productId: this.selectedProduct.productId, - quantity: parseInt(this.quantity), - remark: this.remark - }) - if (res.code === 0) { - uni.showToast({ title: '入库成功', icon: 'success' }) - setTimeout(() => { - uni.navigateBack() - }, 1500) - } else { - uni.showToast({ title: res.message || '入库失败', icon: 'none' }) + // 逐个入库 + for (const item of this.selectedItems) { + await stockApi.stockIn({ + productId: item.productId, + quantity: item.quantity, + remark: item.remark || '' + }) } + + uni.showToast({ title: '入库成功', icon: 'success' }) + setTimeout(() => { + uni.navigateBack() + }, 1500) } catch (e) { uni.showToast({ title: '入库失败', icon: 'none' }) } finally { @@ -109,54 +261,346 @@ export default { } - + +.popup-content { + position: fixed; + bottom: 0; + left: 0; + right: 0; + background: #fff; + border-radius: 32rpx 32rpx 0 0; + padding: 40rpx 30rpx; + padding-bottom: calc(40rpx + env(safe-area-inset-bottom)); + z-index: 101; +} + +.popup-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 30rpx; +} + +.popup-title { + font-size: 32rpx; + font-weight: bold; + color: #333; +} + +.popup-close { + font-size: 48rpx; + color: #999; + padding: 10rpx; +} + +.popup-spec { + font-size: 26rpx; + color: #666; + margin-bottom: 30rpx; +} + +.popup-qty { + display: flex; + align-items: center; + margin-bottom: 30rpx; +} + +.qty-label { + font-size: 28rpx; + color: #333; + width: 160rpx; +} + +.qty-input-wrapper { + display: flex; + align-items: center; + background: #f5f5f5; + border-radius: 12rpx; +} + +.qty-minus, .qty-plus { + width: 80rpx; + height: 80rpx; + display: flex; + align-items: center; + justify-content: center; + font-size: 40rpx; + color: #667eea; +} + +.qty-input { + width: 120rpx; + height: 80rpx; + text-align: center; + font-size: 32rpx; + background: transparent; + border-left: 1rpx solid #eee; + border-right: 1rpx solid #eee; +} + +.popup-remark { + margin-bottom: 30rpx; +} + +.remark-label { + font-size: 28rpx; + color: #333; + display: block; + margin-bottom: 16rpx; +} + +.remark-input { + width: 100%; + height: 80rpx; + background: #f5f5f5; + border-radius: 12rpx; + padding: 0 20rpx; + font-size: 28rpx; + box-sizing: border-box; +} + +.popup-footer { + display: flex; + gap: 20rpx; +} + +.popup-btn { + flex: 1; + height: 88rpx; + line-height: 88rpx; + border-radius: 44rpx; + font-size: 30rpx; + font-weight: bold; +} + +.popup-btn.cancel { + background: #f5f5f5; + color: #666; +} + +.popup-btn.confirm { + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: #fff; + box-shadow: 0 8rpx 30rpx rgba(102, 126, 234, 0.4); +} + \ No newline at end of file