fix(crm): 修复回款新增弹窗预填数据被清空

- 将回款表单下游字段清空逻辑从 schema 依赖刷新移到用户选择事件
- 修复从回款计划新增回款时合同、期数、金额等预填数据被清空的问题
- 兼容回款管理、回款计划、客户/合同详情等新增回款入口
- 同步处理 web-antd、web-ele、web-antdv-next
pull/359/MERGE
YunaiV 2026-06-06 22:26:20 +08:00
parent 651a525187
commit 9d2446b6ff
6 changed files with 348 additions and 159 deletions

View File

@ -57,12 +57,19 @@ export function useFormSchema(): VbenFormSchema[] {
label: '客户名称',
component: 'ApiSelect',
rules: 'required',
componentProps: {
componentProps: (_values, form) => ({
api: getCustomerSimpleList,
labelField: 'name',
valueField: 'id',
placeholder: '请选择客户',
},
onChange: () => {
form.setFieldValue('contractId', undefined);
form.setFieldValue('planId', undefined);
form.setFieldValue('price', undefined);
form.setFieldValue('returnTime', undefined);
form.setFieldValue('returnType', undefined);
},
}),
dependencies: {
triggerFields: ['id'],
disabled: (values) => values.id,
@ -76,21 +83,33 @@ export function useFormSchema(): VbenFormSchema[] {
dependencies: {
triggerFields: ['customerId'],
disabled: (values) => !values.customerId || values.id,
async componentProps(values) {
if (values.customerId) {
if (!values.id) {
// 特殊:只有在【新增】时,才清空合同编号
values.contractId = undefined;
}
const contracts = await getContractSimpleList(values.customerId);
async componentProps(values, form) {
if (!values.customerId) {
return {
options: contracts.map((item) => ({
label: item.name,
value: item.id,
})),
placeholder: '请选择合同',
} as any;
options: [],
placeholder: '请选择客户',
};
}
const contracts = await getContractSimpleList(values.customerId);
return {
options: contracts.map((item) => ({
label: item.name,
value: item.id,
})),
placeholder: '请选择合同',
onChange: (value: number) => {
form.setFieldValue('planId', undefined);
form.setFieldValue('returnTime', undefined);
form.setFieldValue('returnType', undefined);
const contract = contracts.find((item) => item.id === value);
form.setFieldValue(
'price',
contract
? contract.totalPrice - contract.totalReceivablePrice
: undefined,
);
},
} as any;
},
},
},
@ -101,28 +120,38 @@ export function useFormSchema(): VbenFormSchema[] {
rules: 'required',
dependencies: {
triggerFields: ['contractId'],
disabled: (values) => !values.contractId,
async componentProps(values) {
if (values.contractId) {
values.planId = undefined;
const plans = await getReceivablePlanSimpleList(
values.customerId,
values.contractId,
);
disabled: (values) => !values.contractId || values.id,
async componentProps(values, form) {
if (!values.contractId) {
return {
options: plans.map((item) => ({
label: item.period,
value: item.id,
})),
placeholder: '请选择回款期数',
onChange: async (value: any) => {
const plan = await getReceivablePlan(value);
values.returnTime = plan?.returnTime;
values.price = plan?.price;
values.returnType = plan?.returnType;
},
} as any;
options: [],
placeholder: '请选择合同',
};
}
const plans = await getReceivablePlanSimpleList(
values.customerId,
values.contractId,
);
return {
options: plans.map((item) => ({
disabled: !!item.receivableId,
label: `${item.period}`,
value: item.id,
})),
placeholder: '请选择回款期数',
onChange: async (value: any) => {
if (!value) {
form.setFieldValue('returnTime', undefined);
form.setFieldValue('price', undefined);
form.setFieldValue('returnType', undefined);
return;
}
const plan = await getReceivablePlan(value);
form.setFieldValue('returnTime', plan?.returnTime);
form.setFieldValue('price', plan?.price);
form.setFieldValue('returnType', plan?.returnType);
},
} as any;
},
},
},

View File

@ -7,6 +7,7 @@ import { useVbenForm, useVbenModal } from '@vben/common-ui';
import { message } from 'ant-design-vue';
import { getContractSimpleList } from '#/api/crm/contract';
import {
createReceivable,
getReceivable,
@ -16,8 +17,20 @@ import { $t } from '#/locales';
import { useFormSchema } from '../data';
type ReceivablePrefillData = Partial<
Pick<
CrmReceivableApi.Receivable,
'contractId' | 'customerId' | 'price' | 'returnType'
>
> & { id?: number };
type ReceivableFormModalData = ReceivablePrefillData & {
plan?: ReceivablePrefillData;
receivable?: Pick<CrmReceivableApi.Receivable, 'id'>;
};
const emit = defineEmits(['success']);
const formData = ref<CrmReceivableApi.Receivable>();
const formData = ref<Partial<CrmReceivableApi.Receivable>>();
const getTitle = computed(() => {
return formData.value?.id
? $t('ui.actionTitle.edit', ['回款'])
@ -36,6 +49,32 @@ const [Form, formApi] = useVbenForm({
showDefaultActions: false,
});
/** 构建新增回款的预填表单 */
async function buildCreateFormData(
plan: ReceivablePrefillData,
): Promise<Partial<CrmReceivableApi.Receivable>> {
const values: Partial<CrmReceivableApi.Receivable> = {
contractId: plan?.contractId,
customerId: plan?.customerId,
};
//
if (plan?.id) {
values.planId = plan.id;
values.price = plan.price;
values.returnType = plan.returnType;
return values;
}
// /
if (values.customerId && values.contractId) {
const contracts = await getContractSimpleList(values.customerId);
const contract = contracts.find((item) => item.id === values.contractId);
if (contract) {
values.price = contract.totalPrice - contract.totalReceivablePrice;
}
}
return values;
}
const [Modal, modalApi] = useVbenModal({
async onConfirm() {
const { valid } = await formApi.validate();
@ -63,31 +102,26 @@ const [Modal, modalApi] = useVbenModal({
return;
}
//
const data = modalApi.getData();
formData.value = undefined;
await formApi.resetForm();
const data = modalApi.getData() as null | ReceivableFormModalData;
if (!data) {
return;
}
const { receivable, plan } = data;
const { receivable } = data;
const plan =
data.plan ?? (data.customerId || data.contractId ? data : undefined);
modalApi.lock();
try {
if (receivable) {
if (receivable?.id) {
formData.value = await getReceivable(receivable.id!);
} else if (plan) {
formData.value = plan.id
? {
planId: plan.id,
price: plan.price,
returnType: plan.returnType,
customerId: plan.customerId,
contractId: plan.contractId,
}
: ({
customerId: plan.customerId,
contractId: plan.contractId,
} as any);
formData.value = await buildCreateFormData(plan);
}
if (formData.value) {
// values
await formApi.setValues(formData.value as any);
}
// values
await formApi.setValues(formData.value as any);
} finally {
modalApi.unlock();
}

View File

@ -57,12 +57,19 @@ export function useFormSchema(): VbenFormSchema[] {
label: '客户名称',
component: 'ApiSelect',
rules: 'required',
componentProps: {
componentProps: (_values, form) => ({
api: getCustomerSimpleList,
labelField: 'name',
valueField: 'id',
placeholder: '请选择客户',
},
onChange: () => {
form.setFieldValue('contractId', undefined);
form.setFieldValue('planId', undefined);
form.setFieldValue('price', undefined);
form.setFieldValue('returnTime', undefined);
form.setFieldValue('returnType', undefined);
},
}),
dependencies: {
triggerFields: ['id'],
disabled: (values) => values.id,
@ -76,21 +83,33 @@ export function useFormSchema(): VbenFormSchema[] {
dependencies: {
triggerFields: ['customerId'],
disabled: (values) => !values.customerId || values.id,
async componentProps(values) {
if (values.customerId) {
if (!values.id) {
// 特殊:只有在【新增】时,才清空合同编号
values.contractId = undefined;
}
const contracts = await getContractSimpleList(values.customerId);
async componentProps(values, form) {
if (!values.customerId) {
return {
options: contracts.map((item) => ({
label: item.name,
value: item.id,
})),
placeholder: '请选择合同',
} as any;
options: [],
placeholder: '请选择客户',
};
}
const contracts = await getContractSimpleList(values.customerId);
return {
options: contracts.map((item) => ({
label: item.name,
value: item.id,
})),
placeholder: '请选择合同',
onChange: (value: number) => {
form.setFieldValue('planId', undefined);
form.setFieldValue('returnTime', undefined);
form.setFieldValue('returnType', undefined);
const contract = contracts.find((item) => item.id === value);
form.setFieldValue(
'price',
contract
? contract.totalPrice - contract.totalReceivablePrice
: undefined,
);
},
} as any;
},
},
},
@ -101,28 +120,38 @@ export function useFormSchema(): VbenFormSchema[] {
rules: 'required',
dependencies: {
triggerFields: ['contractId'],
disabled: (values) => !values.contractId,
async componentProps(values) {
if (values.contractId) {
values.planId = undefined;
const plans = await getReceivablePlanSimpleList(
values.customerId,
values.contractId,
);
disabled: (values) => !values.contractId || values.id,
async componentProps(values, form) {
if (!values.contractId) {
return {
options: plans.map((item) => ({
label: item.period,
value: item.id,
})),
placeholder: '请选择回款期数',
onChange: async (value: any) => {
const plan = await getReceivablePlan(value);
values.returnTime = plan?.returnTime;
values.price = plan?.price;
values.returnType = plan?.returnType;
},
} as any;
options: [],
placeholder: '请选择合同',
};
}
const plans = await getReceivablePlanSimpleList(
values.customerId,
values.contractId,
);
return {
options: plans.map((item) => ({
disabled: !!item.receivableId,
label: `${item.period}`,
value: item.id,
})),
placeholder: '请选择回款期数',
onChange: async (value: any) => {
if (!value) {
form.setFieldValue('returnTime', undefined);
form.setFieldValue('price', undefined);
form.setFieldValue('returnType', undefined);
return;
}
const plan = await getReceivablePlan(value);
form.setFieldValue('returnTime', plan?.returnTime);
form.setFieldValue('price', plan?.price);
form.setFieldValue('returnType', plan?.returnType);
},
} as any;
},
},
},

View File

@ -7,6 +7,7 @@ import { useVbenForm, useVbenModal } from '@vben/common-ui';
import { message } from 'antdv-next';
import { getContractSimpleList } from '#/api/crm/contract';
import {
createReceivable,
getReceivable,
@ -16,8 +17,20 @@ import { $t } from '#/locales';
import { useFormSchema } from '../data';
type ReceivablePrefillData = Partial<
Pick<
CrmReceivableApi.Receivable,
'contractId' | 'customerId' | 'price' | 'returnType'
>
> & { id?: number };
type ReceivableFormModalData = ReceivablePrefillData & {
plan?: ReceivablePrefillData;
receivable?: Pick<CrmReceivableApi.Receivable, 'id'>;
};
const emit = defineEmits(['success']);
const formData = ref<CrmReceivableApi.Receivable>();
const formData = ref<Partial<CrmReceivableApi.Receivable>>();
const getTitle = computed(() => {
return formData.value?.id
? $t('ui.actionTitle.edit', ['回款'])
@ -36,6 +49,32 @@ const [Form, formApi] = useVbenForm({
showDefaultActions: false,
});
/** 构建新增回款的预填表单 */
async function buildCreateFormData(
plan: ReceivablePrefillData,
): Promise<Partial<CrmReceivableApi.Receivable>> {
const values: Partial<CrmReceivableApi.Receivable> = {
contractId: plan?.contractId,
customerId: plan?.customerId,
};
//
if (plan?.id) {
values.planId = plan.id;
values.price = plan.price;
values.returnType = plan.returnType;
return values;
}
// /
if (values.customerId && values.contractId) {
const contracts = await getContractSimpleList(values.customerId);
const contract = contracts.find((item) => item.id === values.contractId);
if (contract) {
values.price = contract.totalPrice - contract.totalReceivablePrice;
}
}
return values;
}
const [Modal, modalApi] = useVbenModal({
async onConfirm() {
const { valid } = await formApi.validate();
@ -63,31 +102,26 @@ const [Modal, modalApi] = useVbenModal({
return;
}
//
const data = modalApi.getData();
formData.value = undefined;
await formApi.resetForm();
const data = modalApi.getData() as null | ReceivableFormModalData;
if (!data) {
return;
}
const { receivable, plan } = data;
const { receivable } = data;
const plan =
data.plan ?? (data.customerId || data.contractId ? data : undefined);
modalApi.lock();
try {
if (receivable) {
if (receivable?.id) {
formData.value = await getReceivable(receivable.id!);
} else if (plan) {
formData.value = plan.id
? {
planId: plan.id,
price: plan.price,
returnType: plan.returnType,
customerId: plan.customerId,
contractId: plan.contractId,
}
: ({
customerId: plan.customerId,
contractId: plan.contractId,
} as any);
formData.value = await buildCreateFormData(plan);
}
if (formData.value) {
// values
await formApi.setValues(formData.value as any);
}
// values
await formApi.setValues(formData.value as any);
} finally {
modalApi.unlock();
}

View File

@ -57,12 +57,19 @@ export function useFormSchema(): VbenFormSchema[] {
label: '客户名称',
component: 'ApiSelect',
rules: 'required',
componentProps: {
componentProps: (_values, form) => ({
api: getCustomerSimpleList,
labelField: 'name',
valueField: 'id',
placeholder: '请选择客户',
},
onChange: () => {
form.setFieldValue('contractId', undefined);
form.setFieldValue('planId', undefined);
form.setFieldValue('price', undefined);
form.setFieldValue('returnTime', undefined);
form.setFieldValue('returnType', undefined);
},
}),
dependencies: {
triggerFields: ['id'],
disabled: (values) => values.id,
@ -76,21 +83,33 @@ export function useFormSchema(): VbenFormSchema[] {
dependencies: {
triggerFields: ['customerId'],
disabled: (values) => !values.customerId || values.id,
async componentProps(values) {
if (values.customerId) {
if (!values.id) {
// 特殊:只有在【新增】时,才清空合同编号
values.contractId = undefined;
}
const contracts = await getContractSimpleList(values.customerId);
async componentProps(values, form) {
if (!values.customerId) {
return {
options: contracts.map((item) => ({
label: item.name,
value: item.id,
})),
placeholder: '请选择合同',
} as any;
options: [],
placeholder: '请选择客户',
};
}
const contracts = await getContractSimpleList(values.customerId);
return {
options: contracts.map((item) => ({
label: item.name,
value: item.id,
})),
placeholder: '请选择合同',
onChange: (value: number) => {
form.setFieldValue('planId', undefined);
form.setFieldValue('returnTime', undefined);
form.setFieldValue('returnType', undefined);
const contract = contracts.find((item) => item.id === value);
form.setFieldValue(
'price',
contract
? contract.totalPrice - contract.totalReceivablePrice
: undefined,
);
},
} as any;
},
},
},
@ -101,28 +120,38 @@ export function useFormSchema(): VbenFormSchema[] {
rules: 'required',
dependencies: {
triggerFields: ['contractId'],
disabled: (values) => !values.contractId,
async componentProps(values) {
if (values.contractId) {
values.planId = undefined;
const plans = await getReceivablePlanSimpleList(
values.customerId,
values.contractId,
);
disabled: (values) => !values.contractId || values.id,
async componentProps(values, form) {
if (!values.contractId) {
return {
options: plans.map((item) => ({
label: item.period,
value: item.id,
})),
placeholder: '请选择回款期数',
onChange: async (value: any) => {
const plan = await getReceivablePlan(value);
values.returnTime = plan?.returnTime;
values.price = plan?.price;
values.returnType = plan?.returnType;
},
} as any;
options: [],
placeholder: '请选择合同',
};
}
const plans = await getReceivablePlanSimpleList(
values.customerId,
values.contractId,
);
return {
options: plans.map((item) => ({
disabled: !!item.receivableId,
label: `${item.period}`,
value: item.id,
})),
placeholder: '请选择回款期数',
onChange: async (value: any) => {
if (!value) {
form.setFieldValue('returnTime', undefined);
form.setFieldValue('price', undefined);
form.setFieldValue('returnType', undefined);
return;
}
const plan = await getReceivablePlan(value);
form.setFieldValue('returnTime', plan?.returnTime);
form.setFieldValue('price', plan?.price);
form.setFieldValue('returnType', plan?.returnType);
},
} as any;
},
},
},

View File

@ -7,6 +7,7 @@ import { useVbenForm, useVbenModal } from '@vben/common-ui';
import { ElMessage } from 'element-plus';
import { getContractSimpleList } from '#/api/crm/contract';
import {
createReceivable,
getReceivable,
@ -16,8 +17,20 @@ import { $t } from '#/locales';
import { useFormSchema } from '../data';
type ReceivablePrefillData = Partial<
Pick<
CrmReceivableApi.Receivable,
'contractId' | 'customerId' | 'price' | 'returnType'
>
> & { id?: number };
type ReceivableFormModalData = ReceivablePrefillData & {
plan?: ReceivablePrefillData;
receivable?: Pick<CrmReceivableApi.Receivable, 'id'>;
};
const emit = defineEmits(['success']);
const formData = ref<CrmReceivableApi.Receivable>();
const formData = ref<Partial<CrmReceivableApi.Receivable>>();
const getTitle = computed(() => {
return formData.value?.id
? $t('ui.actionTitle.edit', ['回款'])
@ -36,6 +49,32 @@ const [Form, formApi] = useVbenForm({
showDefaultActions: false,
});
/** 构建新增回款的预填表单 */
async function buildCreateFormData(
plan: ReceivablePrefillData,
): Promise<Partial<CrmReceivableApi.Receivable>> {
const values: Partial<CrmReceivableApi.Receivable> = {
contractId: plan?.contractId,
customerId: plan?.customerId,
};
//
if (plan?.id) {
values.planId = plan.id;
values.price = plan.price;
values.returnType = plan.returnType;
return values;
}
// /
if (values.customerId && values.contractId) {
const contracts = await getContractSimpleList(values.customerId);
const contract = contracts.find((item) => item.id === values.contractId);
if (contract) {
values.price = contract.totalPrice - contract.totalReceivablePrice;
}
}
return values;
}
const [Modal, modalApi] = useVbenModal({
async onConfirm() {
const { valid } = await formApi.validate();
@ -63,31 +102,26 @@ const [Modal, modalApi] = useVbenModal({
return;
}
//
const data = modalApi.getData();
formData.value = undefined;
await formApi.resetForm();
const data = modalApi.getData() as null | ReceivableFormModalData;
if (!data) {
return;
}
const { receivable, plan } = data;
const { receivable } = data;
const plan =
data.plan ?? (data.customerId || data.contractId ? data : undefined);
modalApi.lock();
try {
if (receivable) {
if (receivable?.id) {
formData.value = await getReceivable(receivable.id!);
} else if (plan) {
formData.value = plan.id
? {
planId: plan.id,
price: plan.price,
returnType: plan.returnType,
customerId: plan.customerId,
contractId: plan.contractId,
}
: ({
customerId: plan.customerId,
contractId: plan.contractId,
} as any);
formData.value = await buildCreateFormData(plan);
}
if (formData.value) {
// values
await formApi.setValues(formData.value as any);
}
// values
await formApi.setValues(formData.value as any);
} finally {
modalApi.unlock();
}