<template>
|
<up-popup :show="dialogFormVisible" mode="bottom" :round="10" closeable @close="closeDia">
|
<view class="form-popup">
|
<view class="popup-header">
|
<text class="popup-title">{{ operationType === 'add' ? '新增自定义入库' : '编辑自定义入库' }}</text>
|
</view>
|
|
<scroll-view class="popup-content" scroll-y>
|
<view v-if="operationType === 'add'" class="add-btn-section">
|
<u-button type="primary" @click="addProductRow">新增产品</u-button>
|
</view>
|
|
<view v-for="(item, index) in productList" :key="index" class="product-item">
|
<view class="item-header">
|
<text class="item-title">产品 {{ index + 1 }}</text>
|
<u-button v-if="operationType === 'add'" type="error" size="mini" class="delete-btn" @click="removeProductRow(index)">删除</u-button>
|
</view>
|
|
<view class="item-form">
|
<view class="form-field">
|
<text class="field-label required">产品大类</text>
|
<up-input v-model="item.productCategory" placeholder="请输入产品大类" />
|
</view>
|
|
<view class="form-field">
|
<text class="field-label required">规格型号</text>
|
<up-input v-model="item.specificationModel" placeholder="请输入规格型号" />
|
</view>
|
|
<view class="form-field">
|
<text class="field-label required">单位</text>
|
<up-input v-model="item.unit" placeholder="请输入单位" />
|
</view>
|
|
<view class="form-field">
|
<text class="field-label">供应商</text>
|
<up-input v-model="item.supplierName" placeholder="请输入供应商" />
|
</view>
|
|
<view class="form-field">
|
<text class="field-label required">物品类型</text>
|
<up-input v-model="item.itemType" readonly placeholder="请选择物品类型" @click="openItemTypePicker(index)" />
|
</view>
|
|
<view class="form-field">
|
<text class="field-label required">入库数量</text>
|
<up-input v-model="item.inboundNum" type="number" placeholder="请输入入库数量" @blur="calculateTotalPrice(item)" />
|
</view>
|
|
<view class="form-field">
|
<text class="field-label required">入库日期</text>
|
<up-input v-model="item.inboundDate" readonly placeholder="请选择入库日期" @click="openDatePicker(index)" />
|
</view>
|
|
<view class="form-field">
|
<text class="field-label">税率(%)</text>
|
<up-input v-model="item.taxRate" readonly placeholder="请选择税率" @click="openTaxRatePicker(index)" />
|
</view>
|
|
<view class="form-field">
|
<text class="field-label">含税单价(元)</text>
|
<up-input v-model="item.taxInclusiveUnitPrice" type="digit" placeholder="请输入含税单价" @blur="calculateTotalPrice(item)" />
|
</view>
|
|
<view class="form-field">
|
<text class="field-label">含税总价(元)</text>
|
<up-input v-model="item.taxInclusiveTotalPrice" type="digit" placeholder="自动计算" @blur="calculateExclusivePrice(item)" />
|
</view>
|
|
<view class="form-field">
|
<text class="field-label">不含税总价(元)</text>
|
<up-input v-model="item.taxExclusiveTotalPrice" type="digit" placeholder="自动计算" disabled />
|
</view>
|
</view>
|
</view>
|
</scroll-view>
|
|
<view class="popup-footer">
|
<u-button class="btn-cancel" @click="closeDia">取消</u-button>
|
<u-button class="btn-confirm" type="primary" @click="submitForm">确认</u-button>
|
</view>
|
</view>
|
|
<up-action-sheet :show="showItemTypePicker" :actions="itemTypeActions" title="选择物品类型" @select="onItemTypeSelect" @close="showItemTypePicker = false" />
|
<up-action-sheet :show="showTaxRatePicker" :actions="taxRateActions" title="选择税率" @select="onTaxRateSelect" @close="showTaxRatePicker = false" />
|
<up-popup :show="showDatePicker" mode="bottom" @close="showDatePicker = false">
|
<up-datetime-picker :show="true" v-model="dateValue" @confirm="onDateConfirm" @cancel="showDatePicker = false" mode="date" />
|
</up-popup>
|
</up-popup>
|
</template>
|
|
<script setup>
|
import { ref, reactive, toRefs } from 'vue'
|
import useUserStore from '@/store/modules/user'
|
import { formatDateToYMD } from '@/utils/ruoyi'
|
import { addStockInCustom, updateStockInCustom } from '@/api/inventoryManagement/stockIn.js'
|
|
const userStore = useUserStore()
|
const emit = defineEmits(['close', 'success'])
|
|
const operationType = ref('')
|
const dialogFormVisible = ref(false)
|
const productList = ref([])
|
const loading = ref(false)
|
|
const showItemTypePicker = ref(false)
|
const showTaxRatePicker = ref(false)
|
const showDatePicker = ref(false)
|
const dateValue = ref(new Date().getTime())
|
const currentEditIndex = ref(0)
|
|
function formatDateTime(date = new Date(), includeTime = true) {
|
const d = new Date(date)
|
const year = d.getFullYear()
|
const month = String(d.getMonth() + 1).padStart(2, '0')
|
const day = String(d.getDate()).padStart(2, '0')
|
if (!includeTime) return `${year}-${month}-${day}`
|
const hours = String(d.getHours()).padStart(2, '0')
|
const minutes = String(d.getMinutes()).padStart(2, '0')
|
const seconds = String(d.getSeconds()).padStart(2, '0')
|
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
|
}
|
|
function getCurrentDate() {
|
return formatDateTime(new Date(), false)
|
}
|
|
const itemTypeActions = ref([
|
{ name: '物料', value: '物料' },
|
{ name: '原料', value: '原料' },
|
{ name: '成品', value: '成品' },
|
{ name: '其他', value: '其他' }
|
])
|
|
const taxRateActions = ref([
|
{ name: '1%', value: 1 },
|
{ name: '6%', value: 6 },
|
{ name: '13%', value: 13 }
|
])
|
|
const data = reactive({
|
form: {
|
id: null,
|
supplierId: null,
|
supplierName: '',
|
recorderId: userStore.userId,
|
recorderName: userStore.name,
|
entryDate: getCurrentDate(),
|
remark: ''
|
}
|
})
|
const { form } = toRefs(data)
|
|
const addProductRow = () => {
|
productList.value.push({
|
id: null,
|
productCategory: '',
|
specificationModel: '',
|
unit: '',
|
supplierName: form.value.supplierName || '',
|
itemType: '',
|
inboundNum: 0,
|
inboundDate: '',
|
taxRate: null,
|
taxInclusiveUnitPrice: 0,
|
taxInclusiveTotalPrice: 0,
|
taxExclusiveTotalPrice: 0
|
})
|
}
|
|
const removeProductRow = (index) => {
|
productList.value.splice(index, 1)
|
}
|
|
const openItemTypePicker = (index) => {
|
currentEditIndex.value = index
|
showItemTypePicker.value = true
|
}
|
|
const onItemTypeSelect = (item) => {
|
productList.value[currentEditIndex.value].itemType = item.value
|
showItemTypePicker.value = false
|
}
|
|
const openTaxRatePicker = (index) => {
|
currentEditIndex.value = index
|
showTaxRatePicker.value = true
|
}
|
|
const onTaxRateSelect = (item) => {
|
productList.value[currentEditIndex.value].taxRate = item.value
|
calculateExclusivePrice(productList.value[currentEditIndex.value])
|
showTaxRatePicker.value = false
|
}
|
|
const openDatePicker = (index) => {
|
currentEditIndex.value = index
|
showDatePicker.value = true
|
}
|
|
const onDateConfirm = (e) => {
|
productList.value[currentEditIndex.value].inboundDate = formatDateToYMD(e.value)
|
showDatePicker.value = false
|
}
|
|
const calculateTotalPrice = (row) => {
|
const unitPrice = Number(row.taxInclusiveUnitPrice || 0)
|
const quantity = Number(row.inboundNum || 0)
|
row.taxInclusiveTotalPrice = (unitPrice * quantity).toFixed(2)
|
calculateExclusivePrice(row)
|
}
|
|
const calculateExclusivePrice = (row) => {
|
const totalPrice = Number(row.taxInclusiveTotalPrice || 0)
|
const taxRate = Number(row.taxRate || 0)
|
row.taxExclusiveTotalPrice = (totalPrice / (1 + taxRate / 100)).toFixed(2)
|
}
|
|
const submitForm = async () => {
|
try {
|
if (!productList.value.length) {
|
uni.showToast({ title: '请至少添加一条产品数据', icon: 'none' })
|
return
|
}
|
for (let i = 0; i < productList.value.length; i++) {
|
const product = productList.value[i]
|
if (!product.productCategory || !product.specificationModel || !product.unit) {
|
uni.showToast({ title: 第行产品数据未填写完整, icon: 'none' })
|
return
|
}
|
if (!product.itemType) {
|
uni.showToast({ title: 第行请选择物品类型, icon: 'none' })
|
return
|
}
|
if (!product.inboundDate) {
|
uni.showToast({ title: 第行请选择入库日期, icon: 'none' })
|
return
|
}
|
const stock = Number(product?.inboundNum ?? 0)
|
if (!Number.isFinite(stock) || stock <= 0) {
|
uni.showToast({ title: 第行入库数量需大于0, icon: 'none' })
|
return
|
}
|
}
|
const payloadList = productList.value.map(product => ({
|
id: product.id ?? null,
|
inboundNum: Number(product.inboundNum),
|
productCategory: product.productCategory,
|
specificationModel: product.specificationModel,
|
unit: product.unit,
|
supplierName: product.supplierName || form.value.supplierName,
|
itemType: product.itemType,
|
inboundDate: formatDateTime(product.inboundDate, false),
|
taxRate: Number(product.taxRate || 0),
|
taxInclusiveUnitPrice: Number(product.taxInclusiveUnitPrice || 0),
|
taxInclusiveTotalPrice: Number(product.taxInclusiveTotalPrice || 0),
|
taxExclusiveTotalPrice: Number(product.taxExclusiveTotalPrice || 0)
|
}))
|
loading.value = true
|
uni.showLoading({ title: '提交中...', mask: true })
|
if (operationType.value === 'edit') {
|
await updateStockInCustom(payloadList[0])
|
} else {
|
await addStockInCustom(payloadList)
|
}
|
uni.hideLoading()
|
uni.showToast({ title: operationType.value === 'edit' ? '编辑成功' : '新增成功', icon: 'success' })
|
closeDia()
|
emit('success')
|
} catch (error) {
|
console.error('提交失败:', error)
|
uni.hideLoading()
|
uni.showToast({ title: '操作失败,请重试', icon: 'none' })
|
} finally {
|
loading.value = false
|
}
|
}
|
|
const closeDia = () => {
|
dialogFormVisible.value = false
|
productList.value = []
|
emit('close')
|
}
|
|
const openDialog = async (type, row) => {
|
operationType.value = type
|
dialogFormVisible.value = true
|
if (type === 'add') {
|
form.value = {
|
id: null,
|
supplierId: null,
|
supplierName: '',
|
recorderId: userStore.userId,
|
recorderName: userStore.name,
|
entryDate: getCurrentDate(),
|
remark: ''
|
}
|
productList.value = []
|
} else {
|
form.value = {
|
id: row?.id ?? null,
|
supplierId: row?.supplierId ?? null,
|
supplierName: row?.supplierName ?? '',
|
recorderId: userStore.userId,
|
recorderName: userStore.name,
|
entryDate: getCurrentDate(),
|
remark: row?.remark ?? ''
|
}
|
productList.value = [{
|
id: row?.id ?? null,
|
productCategory: row?.productCategory ?? '',
|
specificationModel: row?.specificationModel ?? '',
|
unit: row?.unit ?? '',
|
supplierName: row?.supplierName ?? '',
|
itemType: row?.itemType ?? '',
|
inboundNum: Number(row?.inboundNum ?? row?.inboundQuantity ?? 0),
|
inboundDate: row?.inboundDate ?? row?.createTime ?? '',
|
taxRate: Number(row?.taxRate ?? 0),
|
taxInclusiveUnitPrice: Number(row?.taxInclusiveUnitPrice ?? 0),
|
taxInclusiveTotalPrice: Number(row?.taxInclusiveTotalPrice ?? 0),
|
taxExclusiveTotalPrice: Number(row?.taxExclusiveTotalPrice ?? 0)
|
}]
|
}
|
}
|
|
defineExpose({ openDialog })
|
</script>
|
|
<style scoped lang="scss">
|
.form-popup {
|
height: 80vh;
|
display: flex;
|
flex-direction: column;
|
background: #f5f5f5;
|
}
|
.popup-header {
|
padding: 16px;
|
background: #fff;
|
border-bottom: 1px solid #f0f0f0;
|
}
|
.popup-title {
|
font-size: 18px;
|
font-weight: 600;
|
color: #333;
|
}
|
.popup-content {
|
flex: 1;
|
height: 0;
|
padding: 12px;
|
}
|
.add-btn-section {
|
margin-bottom: 12px;
|
}
|
.product-item {
|
background: #fff;
|
border-radius: 12px;
|
margin-bottom: 12px;
|
overflow: hidden;
|
}
|
.item-header {
|
display: flex;
|
align-items: center;
|
justify-content: space-between;
|
padding: 12px 16px;
|
background: #f8f8f8;
|
border-bottom: 1px solid #f0f0f0;
|
}
|
.item-title {
|
font-size: 16px;
|
font-weight: 600;
|
width: 100%;
|
color: #333;
|
}
|
.item-form {
|
padding: 16px;
|
}
|
.form-field {
|
margin-bottom: 16px;
|
}
|
.field-label {
|
display: block;
|
font-size: 14px;
|
color: #666;
|
margin-bottom: 8px;
|
}
|
.field-label.required::before {
|
content: '*';
|
color: #ff0000;
|
margin-right: 4px;
|
}
|
.popup-footer {
|
display: flex;
|
gap: 12px;
|
padding: 12px 16px;
|
background: #fff;
|
border-top: 1px solid #f0f0f0;
|
}
|
.btn-cancel, .btn-confirm {
|
flex: 1;
|
}
|
.btn-cancel {
|
background: #f5f5f5;
|
color: #666;
|
border: none;
|
}
|
.delete-btn {
|
padding: 2px 8px !important;
|
height: 24px !important;
|
font-size: 11px !important;
|
width: 20px !important;
|
}
|
</style>
|