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';
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 {
id?: number; // 付款单编号
no: string; // 付款单号
supplierId: number; // 供应商编号
supplierName?: string; // 供应商名称
paymentTime: Date; // 付款时间
totalPrice: number; // 合计金额,单位:元
discountPrice: number; // 优惠金额
paymentPrice: number; // 实际付款金额
status: number; // 状态
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 {
no?: string;
paymentTime?: [string, string];
supplierId?: number;
creator?: string;
financeUserId?: number;
accountId?: number;
status?: number;
remark?: string;
bizNo?: string;
}
/** 付款单状态更新参数 */

View File

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

View File

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

View File

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