feat: crm contact detail

This commit is contained in:
xingyu4j
2025-06-04 22:30:25 +08:00
parent 070274de15
commit a0281ef742
10 changed files with 740 additions and 79 deletions

View File

@@ -2,11 +2,12 @@
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { CrmBusinessApi } from '#/api/crm/business';
import { ref } from 'vue';
import { useRouter } from 'vue-router';
import { useVbenModal } from '@vben/common-ui';
import { Button } from 'ant-design-vue';
import { Button, message } from 'ant-design-vue';
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
import { getBusinessPageByCustomer } from '#/api/crm/business';
@@ -28,6 +29,11 @@ const [FormModal, formModalApi] = useVbenModal({
destroyOnClose: true,
});
const checkedRows = ref<CrmBusinessApi.Business[]>([]);
function setCheckedRows({ records }: { records: CrmBusinessApi.Business[] }) {
checkedRows.value = records;
}
/** 刷新表格 */
function onRefresh() {
gridApi.query();
@@ -50,22 +56,20 @@ function handleCustomerDetail(row: CrmBusinessApi.Business) {
const [Modal, modalApi] = useVbenModal({
async onConfirm() {
// const { valid } = await formApi.validate();
// if (!valid) {
// return;
// }
// modalApi.lock();
// //
// const data = (await formApi.getValues()) as CrmBusinessApi.Business;
// try {
// await (formData.value?.id ? updateBusiness(data) : createBusiness(data));
// //
// await modalApi.close();
emit('success');
// message.success($t('ui.actionMessage.operationSuccess'));
// } finally {
// modalApi.unlock();
// }
if (checkedRows.value.length === 0) {
message.error('请先选择商机后操作!');
return;
}
modalApi.lock();
//
try {
const businessIds = checkedRows.value.map((item) => item.id);
//
await modalApi.close();
emit('success', businessIds, checkedRows.value);
} finally {
modalApi.unlock();
}
},
async onOpenChange(isOpen: boolean) {
if (!isOpen) {
@@ -120,6 +124,10 @@ const [Grid, gridApi] = useVbenVxeGrid({
search: true,
},
} as VxeTableGridOptions<CrmBusinessApi.Business>,
gridEvents: {
checkboxAll: setCheckedRows,
checkboxChange: setCheckedRows,
},
});
</script>

View File

@@ -1,6 +1,7 @@
<script lang="ts" setup>
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { CrmBusinessApi } from '#/api/crm/business';
import type { CrmContactApi } from '#/api/crm/contact';
import { ref } from 'vue';
import { useRouter } from 'vue-router';
@@ -10,13 +11,16 @@ import { confirm, useVbenModal } from '@vben/common-ui';
import { Button, message } from 'ant-design-vue';
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
import { getBusinessPage } from '#/api/crm/business';
import {
getBusinessPageByContact,
getBusinessPageByCustomer,
} from '#/api/crm/business';
import { createContactBusinessList } from '#/api/crm/contact';
import { BizTypeEnum } from '#/api/crm/permission';
import { $t } from '#/locales';
import { useDetailListColumns } from '../data';
import DetailForm from './detail-form.vue';
import ListModal from './detail-list-modal.vue';
import Form from './form.vue';
const props = defineProps<{
@@ -33,8 +37,8 @@ const [FormModal, formModalApi] = useVbenModal({
destroyOnClose: true,
});
const [DetailFormModal, detailFormModalApi] = useVbenModal({
connectedComponent: DetailForm,
const [DetailListModal, detailListModalApi] = useVbenModal({
connectedComponent: ListModal,
destroyOnClose: true,
});
@@ -56,7 +60,7 @@ function handleCreate() {
}
function handleCreateBusiness() {
detailFormModalApi.setData({ customerId: props.customerId }).open();
detailListModalApi.setData({ customerId: props.customerId }).open();
}
async function handleDeleteContactBusinessList() {
@@ -98,6 +102,15 @@ function handleCustomerDetail(row: CrmBusinessApi.Business) {
push({ name: 'CrmCustomerDetail', params: { id: row.customerId } });
}
async function handleCreateContactBusinessList(businessIds: number[]) {
const data = {
contactId: props.bizId,
businessIds,
} as CrmContactApi.ContactBusinessReq;
await createContactBusinessList(data);
onRefresh();
}
const [Grid, gridApi] = useVbenVxeGrid({
gridOptions: {
columns: useDetailListColumns(),
@@ -107,14 +120,14 @@ const [Grid, gridApi] = useVbenVxeGrid({
ajax: {
query: async ({ page }, formValues) => {
if (props.bizType === BizTypeEnum.CRM_CUSTOMER) {
return await getBusinessPage({
return await getBusinessPageByCustomer({
page: page.currentPage,
pageSize: page.pageSize,
customerId: props.customerId,
...formValues,
});
} else if (props.bizType === BizTypeEnum.CRM_CONTACT) {
return await getBusinessPage({
return await getBusinessPageByContact({
page: page.currentPage,
pageSize: page.pageSize,
contactId: props.contactId,
@@ -144,7 +157,10 @@ const [Grid, gridApi] = useVbenVxeGrid({
<template>
<div>
<FormModal @success="onRefresh" />
<DetailFormModal :customer-id="customerId" @success="onRefresh" />
<DetailListModal
:customer-id="customerId"
@success="handleCreateContactBusinessList"
/>
<Grid>
<template #toolbar-tools>
<TableAction

View File

@@ -21,6 +21,10 @@ const BusinessDetailsInfo = defineAsyncComponent(
() => import('./detail-info.vue'),
);
const ContactDetailsList = defineAsyncComponent(
() => import('#/views/crm/contact/modules/detail-list.vue'),
);
const FollowUp = defineAsyncComponent(
() => import('#/views/crm/followup/index.vue'),
);
@@ -162,7 +166,12 @@ onMounted(async () => {
<FollowUp :biz-id="businessId" :biz-type="BizTypeEnum.CRM_BUSINESS" />
</Tabs.TabPane>
<Tabs.TabPane tab="联系人" key="3" :force-render="true">
<div>联系人</div>
<ContactDetailsList
:biz-id="businessId"
:biz-type="BizTypeEnum.CRM_BUSINESS"
:business-id="business.id"
:customer-id="business.customerId"
/>
</Tabs.TabPane>
<Tabs.TabPane tab="产品" key="4" :force-render="true">
<div>产品</div>