2026-03-05 16:52:12 +08:00
|
|
|
|
<template>
|
2026-03-06 14:46:40 +08:00
|
|
|
|
<el-drawer
|
|
|
|
|
|
v-model="dialogVisible"
|
|
|
|
|
|
:title="dialogTitle"
|
|
|
|
|
|
direction="rtl"
|
|
|
|
|
|
size="100%"
|
|
|
|
|
|
:close-on-press-escape="true"
|
|
|
|
|
|
:destroy-on-close="true"
|
|
|
|
|
|
:append-to-body="true"
|
|
|
|
|
|
class="mobile-form-drawer"
|
|
|
|
|
|
>
|
|
|
|
|
|
<div class="mobile-form" v-loading="formLoading">
|
|
|
|
|
|
<el-form
|
|
|
|
|
|
ref="formRef"
|
|
|
|
|
|
:model="formData"
|
|
|
|
|
|
:rules="formRules"
|
|
|
|
|
|
label-position="top"
|
|
|
|
|
|
:disabled="disabled"
|
|
|
|
|
|
>
|
|
|
|
|
|
<!-- 基本信息 -->
|
|
|
|
|
|
<div class="mobile-form__section">
|
|
|
|
|
|
<div class="mobile-form__section-title">基本信息</div>
|
2026-03-05 16:52:12 +08:00
|
|
|
|
<el-form-item label="出库单号" prop="no">
|
|
|
|
|
|
<el-input disabled v-model="formData.no" placeholder="保存时自动生成" />
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="出库时间" prop="outTime">
|
2026-03-06 14:46:40 +08:00
|
|
|
|
<el-date-picker v-model="formData.outTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="选择出库时间" style="width: 100%" />
|
2026-03-05 16:52:12 +08:00
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="关联明细" prop="stockRecordIds">
|
|
|
|
|
|
<el-input v-model="formData.stockRecordText" readonly>
|
|
|
|
|
|
<template #append>
|
|
|
|
|
|
<el-button @click="openStockRecordList">
|
|
|
|
|
|
<Icon icon="ep:search" /> 选择
|
|
|
|
|
|
</el-button>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-input>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="仓库" prop="warehouseId">
|
2026-03-06 14:46:40 +08:00
|
|
|
|
<el-select v-model="formData.warehouseId" clearable filterable placeholder="请选择仓库" style="width: 100%">
|
|
|
|
|
|
<el-option v-for="item in warehouseList" :key="item.id" :label="item.name" :value="item.id" />
|
2026-03-05 16:52:12 +08:00
|
|
|
|
</el-select>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="客户" prop="customerId">
|
2026-03-06 14:46:40 +08:00
|
|
|
|
<el-select v-model="formData.customerId" clearable filterable placeholder="请选择客户" style="width: 100%">
|
|
|
|
|
|
<el-option v-for="item in customerList" :key="item.id" :label="item.name" :value="item.id" />
|
2026-03-05 16:52:12 +08:00
|
|
|
|
</el-select>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="销售人员" prop="saleUserId">
|
2026-03-06 14:46:40 +08:00
|
|
|
|
<el-select v-model="formData.saleUserId" clearable filterable placeholder="请选择销售人员" style="width: 100%">
|
|
|
|
|
|
<el-option v-for="item in userList" :key="item.id" :label="item.nickname" :value="item.id" />
|
2026-03-05 16:52:12 +08:00
|
|
|
|
</el-select>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="备注" prop="remark">
|
2026-03-06 14:46:40 +08:00
|
|
|
|
<el-input type="textarea" v-model="formData.remark" :rows="2" placeholder="请输入备注" />
|
2026-03-05 16:52:12 +08:00
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="附件" prop="fileUrl">
|
|
|
|
|
|
<UploadFile :is-show-tip="false" v-model="formData.fileUrl" :limit="1" />
|
|
|
|
|
|
</el-form-item>
|
2026-03-06 14:46:40 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 出库产品清单 -->
|
|
|
|
|
|
<div class="mobile-form__section">
|
|
|
|
|
|
<div class="mobile-form__section-title">出库产品清单</div>
|
|
|
|
|
|
<SaleOutwarehouseItemForm ref="itemFormRef" :items="formData.items" :disabled="disabled" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 价格信息 -->
|
|
|
|
|
|
<div class="mobile-form__section">
|
|
|
|
|
|
<div class="mobile-form__section-title">价格信息</div>
|
2026-03-05 16:52:12 +08:00
|
|
|
|
<el-form-item label="优惠率(%)" prop="discountPercent">
|
2026-03-06 14:46:40 +08:00
|
|
|
|
<el-input-number v-model="formData.discountPercent" controls-position="right" :min="0" :precision="2" placeholder="请输入优惠率" style="width: 100%" />
|
2026-03-05 16:52:12 +08:00
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="收款优惠" prop="discountPrice">
|
2026-03-06 14:46:40 +08:00
|
|
|
|
<el-input disabled v-model="formData.discountPrice" :formatter="erpPriceInputFormatter" />
|
2026-03-05 16:52:12 +08:00
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="优惠后金额">
|
2026-03-06 14:46:40 +08:00
|
|
|
|
<el-input disabled :model-value="formData.totalPrice - formData.otherPrice" :formatter="erpPriceInputFormatter" />
|
2026-03-05 16:52:12 +08:00
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="其它费用" prop="otherPrice">
|
2026-03-06 14:46:40 +08:00
|
|
|
|
<el-input-number v-model="formData.otherPrice" controls-position="right" :min="0" :precision="2" placeholder="请输入其它费用" style="width: 100%" />
|
2026-03-05 16:52:12 +08:00
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="结算账户" prop="accountId">
|
2026-03-06 14:46:40 +08:00
|
|
|
|
<el-select v-model="formData.accountId" clearable filterable placeholder="请选择结算账户" style="width: 100%">
|
|
|
|
|
|
<el-option v-for="item in accountList" :key="item.id" :label="item.name" :value="item.id" />
|
2026-03-05 16:52:12 +08:00
|
|
|
|
</el-select>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="应收金额">
|
|
|
|
|
|
<el-input disabled v-model="formData.totalPrice" :formatter="erpPriceInputFormatter" />
|
|
|
|
|
|
</el-form-item>
|
2026-03-06 14:46:40 +08:00
|
|
|
|
<el-form-item label="总金额(反算单价)">
|
|
|
|
|
|
<el-input-number v-model="formData.reverseCalculationAmount" :min="0" :precision="4" style="width: 100%" placeholder="输入总金额反算单价" @change="handleReverseCalculation" />
|
2026-03-05 16:52:12 +08:00
|
|
|
|
</el-form-item>
|
2026-03-06 14:46:40 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</el-form>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 底部按钮 -->
|
2026-03-05 16:52:12 +08:00
|
|
|
|
<template #footer>
|
2026-03-06 14:46:40 +08:00
|
|
|
|
<div class="mobile-form__footer">
|
|
|
|
|
|
<el-button @click="dialogVisible = false" style="flex:1">取 消</el-button>
|
|
|
|
|
|
<el-button type="primary" @click="submitForm" :disabled="formLoading" v-if="!disabled" style="flex:2">
|
|
|
|
|
|
确 定
|
|
|
|
|
|
</el-button>
|
|
|
|
|
|
</div>
|
2026-03-05 16:52:12 +08:00
|
|
|
|
</template>
|
2026-03-06 14:46:40 +08:00
|
|
|
|
</el-drawer>
|
2026-03-05 16:52:12 +08:00
|
|
|
|
|
|
|
|
|
|
<!-- 库存批次选择弹窗 -->
|
|
|
|
|
|
<StockBatchSelectionDialog ref="stockBatchSelectionRef" @success="handleBatchSelectionChange" />
|
|
|
|
|
|
</template>
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
|
|
|
import { SaleOutwarehouseApi, SaleOutwarehouseVO } from '@/api/erp/sale/outwarehouse'
|
|
|
|
|
|
import SaleOutwarehouseItemForm from './components/SaleOutwarehouseItemForm.vue'
|
|
|
|
|
|
import { CustomerApi, CustomerVO } from '@/api/erp/sale/customer'
|
|
|
|
|
|
import { AccountApi, AccountVO } from '@/api/erp/finance/account'
|
|
|
|
|
|
import { erpPriceInputFormatter, erpPriceMultiply } from '@/utils'
|
|
|
|
|
|
import * as UserApi from '@/api/system/user'
|
|
|
|
|
|
import { WarehouseApi, WarehouseVO } from '@/api/erp/stock/warehouse'
|
|
|
|
|
|
import { StockApi } from '@/api/erp/stock/stock/index'
|
|
|
|
|
|
import { ProductApi } from '@/api/erp/product/product'
|
|
|
|
|
|
import StockBatchSelectionDialog from './components/StockBatchSelectionDialog.vue'
|
|
|
|
|
|
import dayjs from 'dayjs'
|
|
|
|
|
|
|
|
|
|
|
|
/** ERP 销售出库表单 */
|
|
|
|
|
|
defineOptions({ name: 'SaleOutwarehouseForm' })
|
|
|
|
|
|
|
|
|
|
|
|
const { t } = useI18n() // 国际化
|
|
|
|
|
|
const message = useMessage() // 消息弹窗
|
|
|
|
|
|
|
|
|
|
|
|
const dialogVisible = ref(false) // 弹窗的是否展示
|
|
|
|
|
|
const dialogTitle = ref('') // 弹窗的标题
|
|
|
|
|
|
const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
|
|
|
|
|
|
const formType = ref('') // 表单的类型:create - 新增;update - 修改;detail - 详情
|
|
|
|
|
|
const formData = ref({
|
|
|
|
|
|
id: undefined,
|
|
|
|
|
|
customerId: undefined,
|
|
|
|
|
|
accountId: undefined,
|
|
|
|
|
|
saleUserId: undefined,
|
|
|
|
|
|
outTime: undefined,
|
|
|
|
|
|
warehouseId: undefined,
|
|
|
|
|
|
remark: undefined,
|
|
|
|
|
|
fileUrl: '',
|
|
|
|
|
|
discountPercent: 0,
|
|
|
|
|
|
discountPrice: 0,
|
|
|
|
|
|
totalPrice: 0,
|
|
|
|
|
|
otherPrice: 0,
|
|
|
|
|
|
items: [],
|
|
|
|
|
|
no: undefined, // 出库单号,后端返回
|
|
|
|
|
|
stockRecordIds: [], // 关联的批次ID
|
|
|
|
|
|
stockRecordText: '', // 关联的批次显示文本
|
|
|
|
|
|
reverseCalculationAmount: undefined // 总金额反算字段
|
|
|
|
|
|
})
|
|
|
|
|
|
const formRules = reactive({
|
|
|
|
|
|
customerId: [{ required: true, message: '客户不能为空', trigger: 'blur' }],
|
|
|
|
|
|
// 移除仓库的必填验证,因为可能从多个仓库出库
|
|
|
|
|
|
outTime: [{ required: true, message: '出库时间不能为空', trigger: 'blur' }],
|
|
|
|
|
|
accountId: [{ required: true, message: '结算账户不能为空', trigger: 'blur' }]
|
|
|
|
|
|
})
|
|
|
|
|
|
const disabled = computed(() => formType.value === 'detail')
|
|
|
|
|
|
const formRef = ref() // 表单 Ref
|
|
|
|
|
|
const customerList = ref<CustomerVO[]>([]) // 客户列表
|
|
|
|
|
|
const accountList = ref<AccountVO[]>([]) // 账户列表
|
|
|
|
|
|
const userList = ref<UserApi.UserVO[]>([]) // 用户列表
|
|
|
|
|
|
const warehouseList = ref<WarehouseVO[]>([]) // 仓库列表
|
|
|
|
|
|
|
|
|
|
|
|
/** 子表的表单 */
|
|
|
|
|
|
const subTabsName = ref('item')
|
|
|
|
|
|
const itemFormRef = ref()
|
|
|
|
|
|
|
|
|
|
|
|
/** 打开【库存批次选择】弹窗 */
|
|
|
|
|
|
const stockBatchSelectionRef = ref() // 库存批次选择 Ref
|
|
|
|
|
|
const openStockRecordList = () => {
|
|
|
|
|
|
// 传入已选择的批次ID,用于在列表中标记已选择的记录
|
|
|
|
|
|
const existingBatchIds = formData.value.items
|
|
|
|
|
|
.filter(item => item.batchId)
|
|
|
|
|
|
.map(item => item.batchId)
|
|
|
|
|
|
|
|
|
|
|
|
stockBatchSelectionRef.value.open(existingBatchIds)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** 处理库存批次选择事件 */
|
|
|
|
|
|
const handleBatchSelectionChange = async (batches: any[]) => {
|
|
|
|
|
|
// 设置关联信息
|
|
|
|
|
|
formData.value.stockRecordIds = batches.map(batch => batch.id)
|
|
|
|
|
|
formData.value.stockRecordText = `已选择 ${batches.length} 个批次`
|
|
|
|
|
|
|
|
|
|
|
|
// 将选择的批次添加到出库单项,但避免重复添加
|
|
|
|
|
|
const existingBatchIds = formData.value.items
|
|
|
|
|
|
.filter(item => item.batchId)
|
|
|
|
|
|
.map(item => item.batchId)
|
|
|
|
|
|
|
|
|
|
|
|
// 过滤出未添加过的批次
|
|
|
|
|
|
const newBatches = batches.filter(batch => !existingBatchIds.includes(batch.id))
|
|
|
|
|
|
|
|
|
|
|
|
if (newBatches.length === 0) {
|
|
|
|
|
|
message.warning('所选批次已全部添加,请勿重复添加')
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 将新的批次添加到出库单项,并获取产品详细信息
|
|
|
|
|
|
const newItems = []
|
|
|
|
|
|
for (const batch of newBatches) {
|
|
|
|
|
|
let productInfo = null
|
|
|
|
|
|
let stockCount = 0
|
|
|
|
|
|
|
|
|
|
|
|
// 如果批次有产品ID,获取产品详细信息
|
|
|
|
|
|
if (batch.productId) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
productInfo = await ProductApi.getProduct(batch.productId)
|
|
|
|
|
|
// 获取库存数量
|
|
|
|
|
|
if (formData.value.warehouseId) {
|
|
|
|
|
|
stockCount = await StockApi.getStockCount(batch.productId, formData.value.warehouseId)
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('获取产品信息失败:', error)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const newItem = {
|
|
|
|
|
|
id: undefined,
|
|
|
|
|
|
warehouseId: formData.value.warehouseId || 1,
|
|
|
|
|
|
productId: batch.productId || undefined,
|
|
|
|
|
|
productName: productInfo?.name || batch.productName || `批次: ${batch.workOrderCode}`,
|
|
|
|
|
|
productUnitId: productInfo?.unitId || undefined,
|
|
|
|
|
|
productUnitName: productInfo?.unitName || '吨',
|
|
|
|
|
|
productBarCode: productInfo?.barCode || batch.workOrderCode,
|
|
|
|
|
|
productPrice: productInfo?.salePrice || 0,
|
|
|
|
|
|
count: batch.weight || 0, // 使用批次重量作为数量
|
|
|
|
|
|
stockCount: stockCount || 0, // 实际库存或批次重量
|
|
|
|
|
|
totalProductPrice: 0, // 需要计算
|
|
|
|
|
|
taxPercent: 0,
|
|
|
|
|
|
taxPrice: 0,
|
|
|
|
|
|
totalPrice: 0, // 需要计算
|
|
|
|
|
|
remark: `甜菊糖糖苷: ${batch.steviaGlycosidesPercent || 0}%`,
|
|
|
|
|
|
batchId: batch.id, // 关联的批次ID
|
|
|
|
|
|
batchCode: batch.workOrderCode // 批次编号
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
newItems.push(newItem)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 添加到现有项中
|
|
|
|
|
|
formData.value.items = [...formData.value.items, ...newItems]
|
|
|
|
|
|
|
|
|
|
|
|
// 提示用户
|
|
|
|
|
|
if (newItems.length < batches.length) {
|
|
|
|
|
|
message.success(`已添加 ${newItems.length} 个新批次,${batches.length - newItems.length} 个批次已存在`)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
message.success(`已添加 ${newItems.length} 个批次`)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** 添加产品按钮 - 直接添加产品,不通过库存明细选择 */
|
|
|
|
|
|
const addProductDirectly = () => {
|
|
|
|
|
|
// 创建一个新的出库单项
|
|
|
|
|
|
const newItem = {
|
|
|
|
|
|
id: undefined,
|
|
|
|
|
|
warehouseId: formData.value.warehouseId, // 使用表单中选择的仓库
|
|
|
|
|
|
productId: undefined,
|
|
|
|
|
|
productName: '',
|
|
|
|
|
|
productUnitId: undefined,
|
|
|
|
|
|
productUnitName: '',
|
|
|
|
|
|
productBarCode: '',
|
|
|
|
|
|
productPrice: 0,
|
|
|
|
|
|
count: 1, // 默认数量为1
|
|
|
|
|
|
stockCount: 0,
|
|
|
|
|
|
totalProductPrice: 0,
|
|
|
|
|
|
taxPercent: 0,
|
|
|
|
|
|
taxPrice: 0,
|
|
|
|
|
|
totalPrice: 0,
|
|
|
|
|
|
remark: '',
|
|
|
|
|
|
stockRecordId: undefined // 不关联库存明细
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 添加到现有项中
|
|
|
|
|
|
formData.value.items = [...formData.value.items, newItem]
|
|
|
|
|
|
|
|
|
|
|
|
// 提示用户
|
|
|
|
|
|
message.success('已添加新产品行,请选择产品和设置数量')
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** 加载库存 */
|
|
|
|
|
|
const setStockCount = async (row: any) => {
|
|
|
|
|
|
if (!row.productId || !row.warehouseId) {
|
|
|
|
|
|
row.stockCount = 0
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
try {
|
|
|
|
|
|
// 使用产品ID和仓库ID获取具体仓库的库存
|
|
|
|
|
|
const count = await StockApi.getStockCount(row.productId, row.warehouseId)
|
|
|
|
|
|
row.stockCount = count || 0
|
|
|
|
|
|
console.log(`获取到产品${row.productId}在仓库${row.warehouseId}的库存: ${count}`)
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('获取库存失败:', error)
|
|
|
|
|
|
row.stockCount = 0
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** 反算单价功能 */
|
|
|
|
|
|
const handleReverseCalculation = () => {
|
|
|
|
|
|
const targetAmount = formData.value.reverseCalculationAmount
|
|
|
|
|
|
if (!targetAmount || targetAmount <= 0) {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const items = formData.value.items
|
|
|
|
|
|
if (!items || items.length === 0) {
|
|
|
|
|
|
message.warning('请先添加产品明细')
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 过滤出有数量的产品
|
|
|
|
|
|
const validItems = items.filter(item => item.count && item.count > 0)
|
|
|
|
|
|
if (validItems.length === 0) {
|
|
|
|
|
|
message.warning('请先设置产品数量')
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 计算目标净额(扣除优惠和其他费用)
|
|
|
|
|
|
const discountAmount = formData.value.discountPercent ?
|
|
|
|
|
|
erpPriceMultiply(targetAmount, formData.value.discountPercent / 100.0) : 0
|
|
|
|
|
|
const netAmount = targetAmount - discountAmount - (formData.value.otherPrice || 0)
|
|
|
|
|
|
|
|
|
|
|
|
if (netAmount <= 0) {
|
|
|
|
|
|
message.warning('扣除优惠和其他费用后金额不能为负数')
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 计算总权重(数量 * (1 + 税率))
|
|
|
|
|
|
let totalWeight = 0
|
|
|
|
|
|
validItems.forEach(item => {
|
|
|
|
|
|
const taxMultiplier = 1 + (item.taxPercent || 0) / 100.0
|
|
|
|
|
|
totalWeight += item.count * taxMultiplier
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
if (totalWeight === 0) {
|
|
|
|
|
|
message.warning('计算权重为零,请检查数量和税率设置')
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 按权重分配金额并反算单价
|
|
|
|
|
|
validItems.forEach(item => {
|
|
|
|
|
|
const taxMultiplier = 1 + (item.taxPercent || 0) / 100.0
|
|
|
|
|
|
const itemWeight = item.count * taxMultiplier
|
|
|
|
|
|
const itemTotalPrice = erpPriceMultiply(netAmount, itemWeight / totalWeight)
|
|
|
|
|
|
|
|
|
|
|
|
// 反算含税单价
|
|
|
|
|
|
const unitPriceWithTax = itemTotalPrice / item.count
|
|
|
|
|
|
// 计算不含税单价
|
|
|
|
|
|
item.productPrice = unitPriceWithTax / taxMultiplier
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
message.success(`已按总金额 ${targetAmount} 反算各产品单价`)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** 计算 discountPrice、totalPrice 价格 */
|
|
|
|
|
|
watch(
|
|
|
|
|
|
() => formData.value,
|
|
|
|
|
|
(val) => {
|
|
|
|
|
|
if (!val) {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
// 确保items存在且是数组
|
|
|
|
|
|
if (!val.items || !Array.isArray(val.items)) {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
// 计算
|
|
|
|
|
|
const totalPrice = val.items.reduce((prev, curr) => prev + (curr.totalPrice || 0), 0)
|
|
|
|
|
|
const discountPrice =
|
|
|
|
|
|
val.discountPercent != null ? erpPriceMultiply(totalPrice, val.discountPercent / 100.0) : 0
|
|
|
|
|
|
formData.value.discountPrice = discountPrice
|
|
|
|
|
|
formData.value.totalPrice = totalPrice - discountPrice + (val.otherPrice || 0)
|
|
|
|
|
|
},
|
|
|
|
|
|
{ deep: true }
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
/** 打开弹窗 */
|
|
|
|
|
|
const open = async (type: string, id?: number) => {
|
|
|
|
|
|
dialogVisible.value = true
|
|
|
|
|
|
dialogTitle.value = t('action.' + type)
|
|
|
|
|
|
formType.value = type
|
|
|
|
|
|
resetForm()
|
|
|
|
|
|
// 新增时默认时间为此刻
|
|
|
|
|
|
if (!id) {
|
|
|
|
|
|
formData.value.outTime = dayjs().format('YYYY-MM-DD HH:mm:ss')
|
|
|
|
|
|
}
|
|
|
|
|
|
// 修改时,设置数据
|
|
|
|
|
|
if (id) {
|
|
|
|
|
|
formLoading.value = true
|
|
|
|
|
|
try {
|
|
|
|
|
|
const data = await SaleOutwarehouseApi.getSaleOutwarehouse(id)
|
|
|
|
|
|
// 处理后端返回的itemList字段,转换为前端使用的items字段
|
|
|
|
|
|
if (data.itemList && Array.isArray(data.itemList)) {
|
|
|
|
|
|
data.items = data.itemList
|
|
|
|
|
|
delete data.itemList
|
|
|
|
|
|
}
|
|
|
|
|
|
formData.value = data
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
formLoading.value = false
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// 加载客户列表
|
|
|
|
|
|
customerList.value = await CustomerApi.getCustomerSimpleList()
|
|
|
|
|
|
// 加载用户列表
|
|
|
|
|
|
userList.value = await UserApi.getSimpleUserList()
|
|
|
|
|
|
// 加载账户列表
|
|
|
|
|
|
accountList.value = await AccountApi.getAccountSimpleList()
|
|
|
|
|
|
const defaultAccount = accountList.value.find((item) => item.defaultStatus)
|
|
|
|
|
|
if (defaultAccount) {
|
|
|
|
|
|
formData.value.accountId = defaultAccount.id
|
|
|
|
|
|
}
|
|
|
|
|
|
// 加载仓库列表
|
|
|
|
|
|
warehouseList.value = await WarehouseApi.getWarehouseSimpleList()
|
|
|
|
|
|
const defaultWarehouse = warehouseList.value.find((item) => item.defaultStatus)
|
|
|
|
|
|
if (defaultWarehouse) {
|
|
|
|
|
|
formData.value.warehouseId = defaultWarehouse.id
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
|
|
|
|
|
|
|
|
|
|
|
|
/** 提交表单 */
|
|
|
|
|
|
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
|
|
|
|
|
|
const submitForm = async () => {
|
|
|
|
|
|
// 校验表单
|
|
|
|
|
|
await formRef.value.validate()
|
|
|
|
|
|
await itemFormRef.value.validate()
|
|
|
|
|
|
// 提交请求
|
|
|
|
|
|
formLoading.value = true
|
|
|
|
|
|
try {
|
|
|
|
|
|
const data = formData.value as unknown as SaleOutwarehouseVO
|
|
|
|
|
|
|
|
|
|
|
|
// 确保 outTime 是字符串格式
|
|
|
|
|
|
if (data.outTime) {
|
|
|
|
|
|
if (typeof data.outTime !== 'string') {
|
|
|
|
|
|
data.outTime = dayjs(data.outTime).format('YYYY-MM-DD HH:mm:ss')
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
data.outTime = dayjs().format('YYYY-MM-DD HH:mm:ss')
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
console.log('提交的出库时间:', data.outTime, typeof data.outTime)
|
|
|
|
|
|
|
|
|
|
|
|
if (formType.value === 'create') {
|
|
|
|
|
|
await SaleOutwarehouseApi.createSaleOutwarehouse(data)
|
|
|
|
|
|
message.success(t('common.createSuccess'))
|
|
|
|
|
|
} else {
|
|
|
|
|
|
await SaleOutwarehouseApi.updateSaleOutwarehouse(data)
|
|
|
|
|
|
message.success(t('common.updateSuccess'))
|
|
|
|
|
|
}
|
|
|
|
|
|
dialogVisible.value = false
|
|
|
|
|
|
// 发送操作成功的事件
|
|
|
|
|
|
emit('success')
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
formLoading.value = false
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** 重置表单 */
|
|
|
|
|
|
const resetForm = () => {
|
|
|
|
|
|
formData.value = {
|
|
|
|
|
|
id: undefined,
|
|
|
|
|
|
customerId: undefined,
|
|
|
|
|
|
accountId: undefined,
|
|
|
|
|
|
saleUserId: undefined,
|
|
|
|
|
|
outTime: undefined,
|
|
|
|
|
|
warehouseId: undefined,
|
|
|
|
|
|
remark: undefined,
|
|
|
|
|
|
fileUrl: undefined,
|
|
|
|
|
|
discountPercent: 0,
|
|
|
|
|
|
discountPrice: 0,
|
|
|
|
|
|
totalPrice: 0,
|
|
|
|
|
|
otherPrice: 0,
|
|
|
|
|
|
items: [],
|
|
|
|
|
|
stockRecordIds: [], // 关联的批次ID
|
|
|
|
|
|
stockRecordText: '', // 关联的批次显示文本
|
|
|
|
|
|
reverseCalculationAmount: undefined // 总金额反算字段
|
|
|
|
|
|
}
|
|
|
|
|
|
formRef.value?.resetFields()
|
|
|
|
|
|
}
|
|
|
|
|
|
</script>
|
2026-03-06 14:46:40 +08:00
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
|
.mobile-form {
|
|
|
|
|
|
padding: 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.mobile-form__section {
|
|
|
|
|
|
background: #fff;
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
padding: 14px;
|
|
|
|
|
|
margin-bottom: 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.mobile-form__section-title {
|
|
|
|
|
|
font-size: 15px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
color: #303133;
|
|
|
|
|
|
margin-bottom: 12px;
|
|
|
|
|
|
padding-bottom: 8px;
|
|
|
|
|
|
border-bottom: 1px solid #f0f0f0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.mobile-form__footer {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
gap: 12px;
|
|
|
|
|
|
padding: 0 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|