<script lang="ts" setup>
|
import type { CrmReportApi } from '#/api/crm/report';
|
|
import { computed, onMounted, ref } from 'vue';
|
|
import { Page } from '@vben/common-ui';
|
|
import { Card, Col, DatePicker, Row, Statistic, Table } from 'ant-design-vue';
|
import dayjs from 'dayjs';
|
|
import {
|
getBusinessAnalyze,
|
getContractAnalyze,
|
getCustomerAnalyze,
|
getSalesFunnel,
|
getSalesPerformance,
|
} from '#/api/crm/report';
|
|
defineOptions({ name: 'CrmReportDashboard' });
|
|
const loading = ref(false);
|
const dateRange = ref<[string, string] | null>(null);
|
|
const customerAnalyze = ref<CrmReportApi.CustomerAnalyze>();
|
const businessAnalyze = ref<CrmReportApi.BusinessAnalyze>();
|
const contractAnalyze = ref<CrmReportApi.ContractAnalyze>();
|
const salesFunnel = ref<CrmReportApi.SalesFunnel>();
|
const salesPerformance = ref<CrmReportApi.SalesPerformance>();
|
|
const startTime = computed(() =>
|
dateRange.value?.[0] ? dayjs(dateRange.value[0]).format('YYYY-MM-DD') : undefined,
|
);
|
const endTime = computed(() =>
|
dateRange.value?.[1] ? dayjs(dateRange.value[1]).format('YYYY-MM-DD') : undefined,
|
);
|
|
const performanceColumns = [
|
{ title: '姓名', dataIndex: 'userName', width: 120 },
|
{ title: '部门', dataIndex: 'deptName', width: 150 },
|
{ title: '合同数量', dataIndex: 'contractCount', width: 100 },
|
{ title: '合同金额', dataIndex: 'contractPrice', width: 120, formatter: 'formatAmount2' },
|
{ title: '回款金额', dataIndex: 'receivablePrice', width: 120, formatter: 'formatAmount2' },
|
{ title: '商机数量', dataIndex: 'businessCount', width: 100 },
|
{ title: '商机金额', dataIndex: 'businessPrice', width: 120, formatter: 'formatAmount2' },
|
];
|
|
async function loadData() {
|
loading.value = true;
|
try {
|
const [customer, business, contract, funnel, performance] = await Promise.all([
|
getCustomerAnalyze(startTime.value, endTime.value),
|
getBusinessAnalyze(startTime.value, endTime.value),
|
getContractAnalyze(startTime.value, endTime.value),
|
getSalesFunnel(),
|
getSalesPerformance(startTime.value, endTime.value),
|
]);
|
customerAnalyze.value = customer;
|
businessAnalyze.value = business;
|
contractAnalyze.value = contract;
|
salesFunnel.value = funnel;
|
salesPerformance.value = performance;
|
} finally {
|
loading.value = false;
|
}
|
}
|
|
function handleDateChange() {
|
loadData();
|
}
|
|
onMounted(() => {
|
loadData();
|
});
|
</script>
|
|
<template>
|
<Page auto-content-height>
|
<div class="p-4">
|
<Card title="CRM 数据概览" class="mb-4">
|
<div class="mb-4">
|
<DatePicker.RangePicker
|
v-model:value="dateRange"
|
:placeholder="['开始日期', '结束日期']"
|
format="YYYY-MM-DD"
|
@change="handleDateChange"
|
/>
|
</div>
|
</Card>
|
|
<Row :gutter="16" class="mb-4">
|
<Col :span="6">
|
<Card title="客户分析" :loading="loading">
|
<Statistic title="总客户数" :value="customerAnalyze?.totalCount || 0" />
|
<Statistic title="今日新增" :value="customerAnalyze?.todayCount || 0" class="mt-2" />
|
<Statistic title="成交客户" :value="customerAnalyze?.dealCount || 0" class="mt-2" />
|
<Statistic
|
title="成交率"
|
:value="customerAnalyze?.dealRate || 0"
|
:precision="2"
|
suffix="%"
|
class="mt-2"
|
/>
|
</Card>
|
</Col>
|
<Col :span="6">
|
<Card title="商机分析" :loading="loading">
|
<Statistic title="总商机数" :value="businessAnalyze?.totalCount || 0" />
|
<Statistic title="商机金额" :value="businessAnalyze?.totalPrice || 0" :precision="2" class="mt-2" />
|
<Statistic title="成功商机" :value="businessAnalyze?.successCount || 0" class="mt-2" />
|
<Statistic
|
title="成功率"
|
:value="businessAnalyze?.successRate || 0"
|
:precision="2"
|
suffix="%"
|
class="mt-2"
|
/>
|
</Card>
|
</Col>
|
<Col :span="6">
|
<Card title="合同分析" :loading="loading">
|
<Statistic title="总合同数" :value="contractAnalyze?.totalCount || 0" />
|
<Statistic title="合同金额" :value="contractAnalyze?.totalPrice || 0" :precision="2" class="mt-2" />
|
<Statistic title="审批中" :value="contractAnalyze?.processCount || 0" class="mt-2" />
|
<Statistic
|
title="回款率"
|
:value="contractAnalyze?.receivableRate || 0"
|
:precision="2"
|
suffix="%"
|
class="mt-2"
|
/>
|
</Card>
|
</Col>
|
<Col :span="6">
|
<Card title="待处理" :loading="loading">
|
<Statistic title="客户公海" :value="customerAnalyze?.poolCount || 0" />
|
<Statistic title="锁定客户" :value="customerAnalyze?.lockCount || 0" class="mt-2" />
|
<Statistic title="进行中商机" :value="businessAnalyze?.processingCount || 0" class="mt-2" />
|
<Statistic title="失败商机" :value="businessAnalyze?.failCount || 0" class="mt-2" />
|
</Card>
|
</Col>
|
</Row>
|
|
<Row :gutter="16">
|
<Col :span="12">
|
<Card title="销售漏斗" :loading="loading">
|
<Table
|
:dataSource="salesFunnel?.stages || []"
|
:columns="[
|
{ title: '阶段', dataIndex: 'name', width: 150 },
|
{ title: '数量', dataIndex: 'count', width: 100 },
|
{ title: '金额', dataIndex: 'price', width: 120 },
|
{ title: '转化率', dataIndex: 'conversionRate', width: 100, customRender: ({ text }) => `${text}%` },
|
]"
|
:pagination="false"
|
size="small"
|
rowKey="name"
|
/>
|
</Card>
|
</Col>
|
<Col :span="12">
|
<Card title="销售业绩" :loading="loading">
|
<Table
|
:dataSource="salesPerformance?.items || []"
|
:columns="performanceColumns"
|
:pagination="false"
|
size="small"
|
rowKey="userId"
|
/>
|
</Card>
|
</Col>
|
</Row>
|
</div>
|
</Page>
|
</template>
|