<template>
|
<view class="add-stock-page">
|
<PageHeader title="新增库存" @back="goBack" />
|
|
<scroll-view scroll-y class="content-scroll">
|
<view class="form-section">
|
<view class="form-row">
|
<text class="form-label required">产品名称</text>
|
<view class="selector-trigger" @click="openProductSelector">
|
<text class="selector-text" :class="{ placeholder: !form.productName }">
|
{{ form.productName || '请选择产品' }}
|
</text>
|
<up-icon name="arrow-right" size="16" color="#999"></up-icon>
|
</view>
|
</view>
|
<view class="form-row">
|
<text class="form-label">规格</text>
|
<up-input v-model="form.productModelName" disabled placeholder="请选择产品后自动带出" />
|
</view>
|
<view class="form-row">
|
<text class="form-label">单位</text>
|
<up-input v-model="form.unit" disabled placeholder="请选择产品后自动带出" />
|
</view>
|
</view>
|
|
<!-- 合格库存时显示过磅相关字段 -->
|
<view v-if="isQualified" class="form-section">
|
<view class="section-title">过磅信息</view>
|
<view class="form-row">
|
<text class="form-label">车牌号</text>
|
<up-input v-model="form.licensePlateNo" placeholder="请输入车牌号" />
|
</view>
|
<view class="form-row">
|
<text class="form-label">毛重(吨)</text>
|
<up-input
|
v-model="form.grossWeight"
|
type="number"
|
placeholder="请输入毛重"
|
/>
|
</view>
|
<view class="form-row">
|
<text class="form-label">皮重(吨)</text>
|
<up-input
|
v-model="form.tareWeight"
|
type="number"
|
placeholder="请输入皮重"
|
/>
|
</view>
|
<view class="form-row">
|
<text class="form-label">净重(吨)</text>
|
<up-input
|
v-model="form.netWeight"
|
type="number"
|
disabled
|
placeholder="自动计算"
|
/>
|
</view>
|
<view class="form-row">
|
<text class="form-label">过磅日期</text>
|
<view class="selector-trigger" @click="openWeighingDatePicker">
|
<text class="selector-text" :class="{ placeholder: !form.weighingDate }">
|
{{ form.weighingDate || '请选择过磅日期' }}
|
</text>
|
<up-icon name="calendar" size="16" color="#999"></up-icon>
|
</view>
|
</view>
|
<view class="form-row">
|
<text class="form-label">过磅员</text>
|
<up-input v-model="form.weighingOperator" placeholder="请输入过磅员" />
|
</view>
|
</view>
|
|
<view class="form-section">
|
<!-- <view class="form-row">
|
<text class="form-label required">数量</text>
|
<up-input v-model="form.qualitity" type="number" placeholder="请输入数量" />
|
</view> -->
|
<view class="form-row">
|
<text class="form-label">备注</text>
|
<up-input v-model="form.remark" type="textarea" placeholder="选填" />
|
</view>
|
</view>
|
</scroll-view>
|
|
<!-- 提交按钮 -->
|
<view class="bottom-bar">
|
<view class="btn-submit" @click="handleSubmit">提交</view>
|
</view>
|
|
<!-- 产品选择弹窗(简化版 ProductSelectDialog) -->
|
<up-popup :show="showProductPopup" mode="bottom" @close="showProductPopup = false">
|
<view class="product-popup">
|
<view class="popup-header">
|
<text class="popup-title">选择产品</text>
|
</view>
|
<view class="popup-search">
|
<up-input
|
v-model="productQuery.productName"
|
placeholder="产品大类"
|
clearable
|
/>
|
<up-input
|
v-model="productQuery.model"
|
placeholder="型号名称"
|
clearable
|
/>
|
<view class="popup-search-btn" @click="loadProductList">搜索</view>
|
</view>
|
<scroll-view scroll-y class="product-list">
|
<view
|
v-for="item in productList"
|
:key="item.id"
|
class="product-item"
|
@click="selectProduct(item)"
|
>
|
<view class="product-name-row">
|
<text class="product-name">{{ item.productName }}</text>
|
<text class="product-unit">{{ item.unit }}</text>
|
</view>
|
<view class="product-model">型号:{{ item.model }}</view>
|
</view>
|
<view v-if="!productLoading && productList.length === 0" class="no-data">
|
暂无数据
|
</view>
|
</scroll-view>
|
</view>
|
</up-popup>
|
|
<!-- 过磅日期选择器 -->
|
<up-popup :show="showWeighingDatePicker" mode="bottom" @close="showWeighingDatePicker = false">
|
<up-datetime-picker
|
:show="true"
|
v-model="weighingDateValue"
|
mode="datetime"
|
@confirm="onWeighingDateConfirm"
|
@cancel="showWeighingDatePicker = false"
|
/>
|
</up-popup>
|
</view>
|
</template>
|
|
<script setup>
|
import { ref, reactive, computed, watch } from 'vue'
|
import { onLoad } from '@dcloudio/uni-app'
|
import dayjs from 'dayjs'
|
import PageHeader from '@/components/PageHeader.vue'
|
import { createStockInventory } from '@/api/inventoryManagement/stockInventory.js'
|
import { createStockUnInventory } from '@/api/inventoryManagement/stockUninventory.js'
|
import { productModelList } from '@/api/basicData/productModel.js'
|
|
const form = reactive({
|
productId: undefined,
|
productModelId: undefined,
|
productName: '',
|
productModelName: '',
|
unit: '',
|
productType: undefined,
|
licensePlateNo: '',
|
grossWeight: '',
|
tareWeight: '',
|
netWeight: '',
|
weighingDate: '',
|
weighingOperator: '',
|
qualitity: '',
|
remark: ''
|
})
|
|
const type = ref('0') // 0 合格库存,1 不合格库存
|
const isQualified = computed(() => type.value === '0')
|
|
const showProductPopup = ref(false)
|
const productQuery = reactive({
|
productName: '',
|
model: ''
|
})
|
const productList = ref([])
|
const productLoading = ref(false)
|
|
const showWeighingDatePicker = ref(false)
|
const weighingDateValue = ref(Date.now())
|
|
onLoad((options) => {
|
if (options && options.type != null) {
|
type.value = options.type
|
}
|
})
|
|
const openProductSelector = () => {
|
showProductPopup.value = true
|
if (productList.value.length === 0) {
|
loadProductList()
|
}
|
}
|
|
const loadProductList = () => {
|
productLoading.value = true
|
productModelList({
|
productName: productQuery.productName || '',
|
model: productQuery.model || '',
|
current: 1,
|
size: 20
|
})
|
.then(res => {
|
const data = res?.records || res?.data?.records || []
|
const list = Array.isArray(data) ? data : []
|
// 过滤耗材:耗材不允许在“产品库存”入库
|
productList.value = list.filter(item => {
|
const parentName = item?.parentName || item?.parent?.name || ''
|
return parentName !== '耗材'
|
})
|
})
|
.finally(() => {
|
productLoading.value = false
|
})
|
}
|
|
const selectProduct = (item) => {
|
const parentName = item?.parentName || item?.parent?.name || ''
|
if (parentName === '耗材') {
|
uni.showToast({ title: '耗材请到耗材库存入库', icon: 'none' })
|
return
|
}
|
form.productId = item.productId || item.id
|
form.productModelId = item.id
|
form.productName = item.productName
|
form.productModelName = item.model
|
form.unit = item.unit
|
form.productType = item.productType
|
showProductPopup.value = false
|
}
|
|
// 净重 = 毛重 - 皮重
|
const computeNetWeight = () => {
|
const gross = Number(form.grossWeight)
|
const tare = Number(form.tareWeight)
|
if (!isNaN(gross) && !isNaN(tare)) {
|
const net = Number((gross - tare).toFixed(2))
|
form.netWeight = net > 0 ? net : 0
|
} else {
|
form.netWeight = ''
|
}
|
}
|
|
// 监听毛重、皮重变化,自动计算净重
|
watch(
|
() => [form.grossWeight, form.tareWeight],
|
() => {
|
computeNetWeight()
|
}
|
)
|
|
const openWeighingDatePicker = () => {
|
weighingDateValue.value = form.weighingDate
|
? dayjs(form.weighingDate, 'YYYY-MM-DD HH:mm:ss').valueOf()
|
: Date.now()
|
showWeighingDatePicker.value = true
|
}
|
|
const onWeighingDateConfirm = (e) => {
|
const ts = e?.value ?? weighingDateValue.value
|
form.weighingDate = dayjs(ts).format('YYYY-MM-DD HH:mm:ss')
|
showWeighingDatePicker.value = false
|
}
|
|
const handleSubmit = () => {
|
if (!form.productName || !form.productModelId) {
|
uni.showToast({ title: '请选择产品', icon: 'none' })
|
return
|
}
|
// if (!form.qualitity || Number(form.qualitity) <= 0) {
|
// uni.showToast({ title: '请输入数量', icon: 'none' })
|
// return
|
// }
|
const payload = {
|
productId: form.productId,
|
productModelId: form.productModelId,
|
productName: form.productName,
|
productModelName: form.productModelName,
|
unit: form.unit,
|
productType: form.productType,
|
licensePlateNo: form.licensePlateNo,
|
grossWeight: form.grossWeight,
|
tareWeight: form.tareWeight,
|
netWeight: form.netWeight,
|
weighingDate: form.weighingDate,
|
weighingOperator: form.weighingOperator,
|
remark: form.remark
|
}
|
const api = isQualified.value ? createStockInventory : createStockUnInventory
|
api(payload)
|
.then(() => {
|
uni.showToast({ title: '新增成功', icon: 'success' })
|
setTimeout(() => {
|
uni.navigateBack()
|
}, 400)
|
})
|
.catch(() => {
|
uni.showToast({ title: '新增失败', icon: 'none' })
|
})
|
}
|
|
const goBack = () => uni.navigateBack()
|
</script>
|
|
<style lang="scss" scoped>
|
.add-stock-page {
|
min-height: 100vh;
|
background: #f5f5f5;
|
padding-bottom: 100rpx;
|
}
|
.content-scroll {
|
height: calc(100vh - 100rpx);
|
}
|
.form-section {
|
background: #fff;
|
margin: 24rpx;
|
padding: 24rpx;
|
border-radius: 16rpx;
|
}
|
.section-title {
|
font-size: 28rpx;
|
font-weight: 500;
|
color: #333;
|
margin-bottom: 12rpx;
|
}
|
.form-row {
|
margin-bottom: 24rpx;
|
}
|
.form-label {
|
display: block;
|
font-size: 26rpx;
|
color: #666;
|
margin-bottom: 12rpx;
|
}
|
.form-label.required::after {
|
content: '*';
|
color: #f56c6c;
|
margin-left: 6rpx;
|
}
|
.selector-trigger {
|
display: flex;
|
align-items: center;
|
justify-content: space-between;
|
padding: 20rpx 24rpx;
|
background: #f5f5f5;
|
border-radius: 12rpx;
|
}
|
.selector-text {
|
font-size: 28rpx;
|
color: #333;
|
}
|
.selector-text.placeholder {
|
color: #999;
|
}
|
.bottom-bar {
|
position: fixed;
|
left: 0;
|
right: 0;
|
bottom: 0;
|
padding: 16rpx 24rpx calc(16rpx + env(safe-area-inset-bottom));
|
background: #fff;
|
box-shadow: 0 -4rpx 16rpx rgba(0, 0, 0, 0.04);
|
}
|
.btn-submit {
|
height: 88rpx;
|
border-radius: 999rpx;
|
background: #2979ff;
|
color: #fff;
|
font-size: 30rpx;
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
}
|
.product-popup {
|
background: #fff;
|
border-radius: 24rpx 24rpx 0 0;
|
padding-bottom: env(safe-area-inset-bottom);
|
}
|
.popup-header {
|
padding: 24rpx;
|
border-bottom: 1rpx solid #eee;
|
}
|
.popup-title {
|
font-size: 30rpx;
|
font-weight: 500;
|
color: #333;
|
}
|
.popup-search {
|
padding: 16rpx 24rpx;
|
display: flex;
|
flex-direction: column;
|
gap: 12rpx;
|
}
|
.popup-search-btn {
|
margin-top: 8rpx;
|
align-self: flex-end;
|
padding: 12rpx 32rpx;
|
border-radius: 999rpx;
|
background: #2979ff;
|
color: #fff;
|
font-size: 26rpx;
|
}
|
.product-list {
|
max-height: 600rpx;
|
padding: 0 24rpx 24rpx;
|
}
|
.product-item {
|
padding: 20rpx 0;
|
border-bottom: 1rpx solid #f0f0f0;
|
}
|
.product-name-row {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
margin-bottom: 8rpx;
|
}
|
.product-name {
|
font-size: 28rpx;
|
color: #333;
|
}
|
.product-unit {
|
font-size: 24rpx;
|
color: #999;
|
}
|
.product-model {
|
font-size: 24rpx;
|
color: #666;
|
}
|
.no-data {
|
text-align: center;
|
padding: 40rpx 0;
|
color: #999;
|
font-size: 26rpx;
|
}
|
</style>
|