feat:【antd】【erp 系统】finance/payment 的迁移 2/4(form 部分)

This commit is contained in:
YunaiV
2025-10-05 10:19:22 +08:00
parent 386919030d
commit af29a0e29b
4 changed files with 93 additions and 91 deletions

View File

@@ -3,22 +3,53 @@ import type { PageParam, PageResult } from '@vben/request';
import { requestClient } from '#/api/request'; import { requestClient } from '#/api/request';
namespace ErpFinancePaymentApi { namespace ErpFinancePaymentApi {
/** 付款单项 */
export interface FinancePaymentItem {
id?: number;
row_id?: number; // 前端使用的临时ID
bizId: number; // 业务ID
bizType: number; // 业务类型
bizNo: string; // 业务编号
totalPrice: number; // 应付金额
paidPrice: number; // 已付金额
paymentPrice: number; // 本次付款
remark?: string; // 备注
}
/** 付款单信息 */ /** 付款单信息 */
export interface FinancePayment { export interface FinancePayment {
id?: number; // 付款单编号 id?: number; // 付款单编号
no: string; // 付款单号 no: string; // 付款单号
supplierId: number; // 供应商编号 supplierId: number; // 供应商编号
supplierName?: string; // 供应商名称
paymentTime: Date; // 付款时间 paymentTime: Date; // 付款时间
totalPrice: number; // 合计金额,单位:元 totalPrice: number; // 合计金额,单位:元
discountPrice: number; // 优惠金额
paymentPrice: number; // 实际付款金额
status: number; // 状态 status: number; // 状态
remark: string; // 备注 remark: string; // 备注
fileUrl?: string; // 附件
accountId?: number; // 付款账户
accountName?: string; // 账户名称
financeUserId?: number; // 财务人员
financeUserName?: string; // 财务人员姓名
creator?: string; // 创建人
creatorName?: string; // 创建人姓名
items?: FinancePaymentItem[]; // 付款明细
bizNo?: string; // 业务单号
} }
/** 付款单分页查询参数 */ /** 付款单分页查询参数 */
export interface FinancePaymentPageParams extends PageParam { export interface FinancePaymentPageParams extends PageParam {
no?: string; no?: string;
paymentTime?: [string, string];
supplierId?: number; supplierId?: number;
creator?: string;
financeUserId?: number;
accountId?: number;
status?: number; status?: number;
remark?: string;
bizNo?: string;
} }
/** 付款单状态更新参数 */ /** 付款单状态更新参数 */

View File

@@ -63,15 +63,19 @@ const [Form, formApi] = useVbenForm({
schema: useFormSchema(formType.value), schema: useFormSchema(formType.value),
showDefaultActions: false, showDefaultActions: false,
handleValuesChange: (values, changedFields) => { handleValuesChange: (values, changedFields) => {
// 目的:同步到 item-form 组件,触发整体的价格计算 if (formData.value) {
if (formData.value && changedFields.includes('discountPrice')) { if (changedFields.includes('supplierId')) {
formData.value.discountPrice = values.discountPrice; formData.value.supplierId = values.supplierId;
// 重新计算实际付款 }
formData.value.paymentPrice = // 目的:同步到 item-form 组件,触发整体的价格计算
formData.value.totalPrice - values.discountPrice; if (changedFields.includes('discountPrice')) {
formApi.setValues({ formData.value.discountPrice = values.discountPrice;
paymentPrice: formData.value.paymentPrice, formData.value.paymentPrice =
}); formData.value.totalPrice - values.discountPrice;
formApi.setValues({
paymentPrice: formData.value.paymentPrice,
});
}
} }
}, },
}); });
@@ -164,15 +168,13 @@ const [Modal, modalApi] = useVbenModal({
> >
<Form class="mx-3"> <Form class="mx-3">
<template #items> <template #items>
<div class="space-y-4"> <ItemForm
<ItemForm ref="itemFormRef"
ref="itemFormRef" :items="formData?.items ?? []"
:items="formData?.items ?? []" :supplier-id="formData?.supplierId"
:supplier-id="formData?.supplierId" :disabled="formType === 'detail'"
:disabled="formType === 'detail'" @update:items="handleUpdateItems"
@update:items="handleUpdateItems" />
/>
</div>
</template> </template>
</Form> </Form>
</Modal> </Modal>

View File

@@ -13,6 +13,8 @@ import { Input, InputNumber, message } from 'ant-design-vue';
import { TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; import { TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
import { useFormItemColumns } from '../data'; import { useFormItemColumns } from '../data';
import PurchaseInSelect from './purchase-in-select.vue';
import SaleReturnSelect from './sale-return-select.vue';
interface Props { interface Props {
items?: ErpFinancePaymentApi.FinancePaymentItem[]; items?: ErpFinancePaymentApi.FinancePaymentItem[];
@@ -22,6 +24,7 @@ interface Props {
const props = withDefaults(defineProps<Props>(), { const props = withDefaults(defineProps<Props>(), {
items: () => [], items: () => [],
supplierId: undefined,
disabled: false, disabled: false,
}); });
@@ -52,10 +55,9 @@ const [Grid, gridApi] = useVbenVxeGrid({
gridOptions: { gridOptions: {
columns: useFormItemColumns(tableData.value), columns: useFormItemColumns(tableData.value),
data: tableData.value, data: tableData.value,
minHeight: 200, minHeight: 250,
autoResize: true, autoResize: true,
border: true, border: true,
showOverflow: true,
rowConfig: { rowConfig: {
keyField: 'row_id', keyField: 'row_id',
isHover: true, isHover: true,
@@ -66,16 +68,6 @@ const [Grid, gridApi] = useVbenVxeGrid({
toolbarConfig: { toolbarConfig: {
enabled: false, enabled: false,
}, },
editConfig: {
trigger: 'click',
mode: 'cell',
},
editRules: {
paymentPrice: [
{ required: true, message: '本次付款不能为空' },
{ type: 'number', min: 0, message: '本次付款不能小于0' },
],
},
}, },
}); });
@@ -90,17 +82,15 @@ watch(
tableData.value = [...items]; tableData.value = [...items];
await nextTick(); // 特殊:保证 gridApi 已经初始化 await nextTick(); // 特殊:保证 gridApi 已经初始化
await gridApi.grid.reloadData(tableData.value); await gridApi.grid.reloadData(tableData.value);
// 更新表格列配置
const columns = useFormItemColumns(tableData.value);
await gridApi.grid.reloadColumn(columns);
},
{
immediate: true,
}, },
{ immediate: true, deep: true },
); );
/** 初始化行数据 */
const initRow = (item: any) => {
if (!item.row_id) {
item.row_id = Date.now() + Math.random();
}
};
/** 添加采购入库单 */ /** 添加采购入库单 */
const purchaseInSelectRef = ref(); const purchaseInSelectRef = ref();
const handleOpenPurchaseIn = () => { const handleOpenPurchaseIn = () => {
@@ -114,14 +104,13 @@ const handleOpenPurchaseIn = () => {
const handleAddPurchaseIn = (rows: ErpPurchaseInApi.PurchaseIn[]) => { const handleAddPurchaseIn = (rows: ErpPurchaseInApi.PurchaseIn[]) => {
rows.forEach((row) => { rows.forEach((row) => {
const newItem: ErpFinancePaymentApi.FinancePaymentItem = { const newItem: ErpFinancePaymentApi.FinancePaymentItem = {
row_id: Date.now() + Math.random(),
bizId: row.id, bizId: row.id,
bizType: ErpBizType.PURCHASE_IN, bizType: ErpBizType.PURCHASE_IN,
bizNo: row.no, bizNo: row.no,
totalPrice: row.totalPrice, totalPrice: row.totalPrice,
paidPrice: row.paymentPrice, paidPrice: row.paymentPrice,
paymentPrice: row.totalPrice - row.paymentPrice, paymentPrice: row.totalPrice - row.paymentPrice,
remark: '', remark: undefined,
}; };
tableData.value.push(newItem); tableData.value.push(newItem);
}); });
@@ -141,14 +130,13 @@ const handleOpenSaleReturn = () => {
const handleAddSaleReturn = (rows: ErpPurchaseReturnApi.PurchaseReturn[]) => { const handleAddSaleReturn = (rows: ErpPurchaseReturnApi.PurchaseReturn[]) => {
rows.forEach((row) => { rows.forEach((row) => {
const newItem: ErpFinancePaymentApi.FinancePaymentItem = { const newItem: ErpFinancePaymentApi.FinancePaymentItem = {
row_id: Date.now() + Math.random(),
bizId: row.id, bizId: row.id,
bizType: ErpBizType.PURCHASE_RETURN, bizType: ErpBizType.PURCHASE_RETURN,
bizNo: row.no, bizNo: row.no,
totalPrice: -row.totalPrice, totalPrice: -row.totalPrice,
paidPrice: -row.refundPrice, paidPrice: -row.refundPrice,
paymentPrice: -row.totalPrice + row.refundPrice, paymentPrice: -row.totalPrice + row.refundPrice,
remark: '', remark: undefined,
}; };
tableData.value.push(newItem); tableData.value.push(newItem);
}); });
@@ -157,7 +145,9 @@ const handleAddSaleReturn = (rows: ErpPurchaseReturnApi.PurchaseReturn[]) => {
/** 删除行 */ /** 删除行 */
const handleDelete = async (row: any) => { const handleDelete = async (row: any) => {
const index = tableData.value.findIndex((item) => item.row_id === row.row_id); const index = tableData.value.findIndex(
(item) => item.bizId === row.bizId && item.bizType === row.bizType,
);
if (index !== -1) { if (index !== -1) {
tableData.value.splice(index, 1); tableData.value.splice(index, 1);
emitUpdate(); emitUpdate();
@@ -169,23 +159,18 @@ const emitUpdate = () => {
emit('update:items', [...tableData.value]); emit('update:items', [...tableData.value]);
}; };
/** 单元格编辑完成事件 */ // TODO @AI增加一个 handleRowChange 方法;
const handleEditClosed = async ({ row, column }: any) => {
if (column.property === 'paymentPrice') { // TODO @芋艿:待定!
// 重新计算价格 /** 初始化行数据 */
emitUpdate(); const initRow = (item: any) => {
if (!item.row_id) {
item.row_id = Date.now() + Math.random();
} }
}; };
/** 表格事件 */
const gridEvents = {
editClosed: handleEditClosed,
cellClick: ({ column }: any) => {
if (column.title === '操作') {}
},
};
/** 校验表单 */ /** 校验表单 */
// TODO @AI一条有问题就直接 throw
const validate = async () => { const validate = async () => {
const errors: string[] = []; const errors: string[] = [];
@@ -253,16 +238,20 @@ defineExpose({ validate });
<div class="text-muted-foreground flex justify-between text-sm"> <div class="text-muted-foreground flex justify-between text-sm">
<span class="text-foreground font-medium">合计</span> <span class="text-foreground font-medium">合计</span>
<div class="flex space-x-4"> <div class="flex space-x-4">
<span>合计付款: <span>
{{ erpPriceInputFormatter(summaries.totalPrice) }}</span> 合计付款{{ erpPriceInputFormatter(summaries.totalPrice) }}
<span>已付金额: {{ erpPriceInputFormatter(summaries.paidPrice) }}</span> </span>
<span>本次付款: <span>
{{ erpPriceInputFormatter(summaries.paymentPrice) }}</span> 已付金额{{ erpPriceInputFormatter(summaries.paidPrice) }}
</span>
<span>
本次付款
{{ erpPriceInputFormatter(summaries.paymentPrice) }}
</span>
</div> </div>
</div> </div>
</div> </div>
<!-- TODO @AI换成 TableAction -->
<!-- 添加按钮放在底部 -->
<div v-if="!disabled" class="mt-4 flex justify-center space-x-2"> <div v-if="!disabled" class="mt-4 flex justify-center space-x-2">
<a-button type="primary" @click="handleOpenPurchaseIn"> <a-button type="primary" @click="handleOpenPurchaseIn">
+ 添加采购入库单 + 添加采购入库单

View File

@@ -94,6 +94,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
{ {
field: 'unPaymentPrice', field: 'unPaymentPrice',
title: '未付金额', title: '未付金额',
// TODO @AI芋艿后续统一改
formatter: ({ row }) => { formatter: ({ row }) => {
const unPaymentPrice = row.totalPrice - row.paymentPrice; const unPaymentPrice = row.totalPrice - row.paymentPrice;
return `${unPaymentPrice?.toFixed(2) || '0.00'}`; return `${unPaymentPrice?.toFixed(2) || '0.00'}`;
@@ -154,43 +155,23 @@ const [Grid, gridApi] = useVbenVxeGrid({
/** 打开弹窗 */ /** 打开弹窗 */
const openModal = (id: number) => { const openModal = (id: number) => {
// 重置数据
supplierId.value = id; supplierId.value = id;
open.value = true; open.value = true;
selectedRows.value = []; selectedRows.value = [];
// 重置表单并设置供应商ID // 查询列表
gridApi.formApi?.resetForm(); gridApi.formApi?.resetForm();
gridApi.formApi?.setValues({ supplierId: id }); gridApi.formApi?.setValues({ supplierId: id });
// 延迟查询,确保表单值已设置 gridApi.query();
setTimeout(() => {
gridApi.query();
}, 100);
}; };
/** 确认选择 */ /** 确认选择采购入库单 */
const handleOk = () => { const handleOk = () => {
if (selectedRows.value.length === 0) { if (selectedRows.value.length === 0) {
message.warning('请选择要添加的采购入库单'); message.warning('请选择要添加的采购入库单');
return; return;
} }
emit('success', selectedRows.value);
// 过滤已全部付款的单据
const validRows = selectedRows.value.filter((row) => {
const unPaymentPrice = row.totalPrice - row.paymentPrice;
return unPaymentPrice > 0;
});
if (validRows.length === 0) {
message.warning('所选的入库单已全部付款,无需再付款');
return;
}
if (validRows.length < selectedRows.value.length) {
message.warning(
`已过滤${selectedRows.value.length - validRows.length}个已全部付款的入库单`,
);
}
emit('success', validRows);
open.value = false; open.value = false;
}; };
@@ -199,14 +180,13 @@ defineExpose({ open: openModal });
<template> <template>
<Modal <Modal
class="!w-[70vw]" class="!w-[50vw]"
v-model:open="open" v-model:open="open"
title="选择采购入库单" title="选择采购入库单"
@ok="handleOk" @ok="handleOk"
:width="1000"
> >
<Grid <Grid
class="max-h-[500px]" class="max-h-[600px]"
table-title="采购入库单列表(仅展示可付款的单据)" table-title="采购入库单列表(仅展示可付款的单据)"
/> />
</Modal> </Modal>