fix: crm statistics

This commit is contained in:
xingyu4j
2025-10-22 12:29:44 +08:00
parent fc475c128c
commit 7aacec3e69
9 changed files with 278 additions and 188 deletions

View File

@@ -133,7 +133,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
<FormModal @success="handleRefresh" />
<Grid>
<template #toolbar-actions>
<Tabs class="-mt-11 w-full" @change="handleChangeSceneType">
<Tabs class="w-full" @change="handleChangeSceneType">
<Tabs.TabPane tab="我负责的" key="1" />
<Tabs.TabPane tab="我参与的" key="2" />
<Tabs.TabPane tab="下属负责的" key="3" />

View File

@@ -348,7 +348,7 @@ export function useGridColumns(): VxeTableGridOptions['columns'] {
},
{
title: '未回款金额(元)',
field: 'totalReceivablePrice',
field: 'unReceivablePrice',
minWidth: 140,
formatter: ({ row }) => {
return erpPriceInputFormatter(

View File

@@ -167,7 +167,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
<FormModal @success="handleRefresh" />
<Grid>
<template #toolbar-actions>
<Tabs class="-mt-11 w-full" @change="handleChangeSceneType">
<Tabs class="w-full" @change="handleChangeSceneType">
<Tabs.TabPane tab="我负责的" key="1" />
<Tabs.TabPane tab="我参与的" key="2" />
<Tabs.TabPane tab="下属负责的" key="3" />

View File

@@ -4,15 +4,17 @@ import type { EchartsUIType } from '@vben/plugins/echarts';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { CrmStatisticsCustomerApi } from '#/api/crm/statistics/customer';
import { ref } from 'vue';
import { onMounted, ref } from 'vue';
import { Page } from '@vben/common-ui';
import { ContentWrap, Page } from '@vben/common-ui';
import { EchartsUI, useEcharts } from '@vben/plugins/echarts';
import { Tabs } from 'ant-design-vue';
import { useVbenForm } from '#/adapter/form';
import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { getChartDatas, getDatas } from '#/api/crm/statistics/customer';
import { getChartDatas } from '#/api/crm/statistics/customer';
import { $t } from '#/locales';
import { getChartOptions } from './chartOptions';
import { customerSummaryTabs, useGridColumns, useGridFormSchema } from './data';
@@ -21,10 +23,26 @@ const activeTabName = ref('customerSummary');
const chartRef = ref<EchartsUIType>();
const { renderEcharts } = useEcharts(chartRef);
const [Grid, gridApi] = useVbenVxeGrid({
formOptions: {
schema: useGridFormSchema(),
const [QueryForm, formApi] = useVbenForm({
commonConfig: {
// 所有表单项
componentProps: {
class: 'w-full',
},
},
schema: useGridFormSchema(),
// 是否可展开
showCollapseButton: true,
submitButtonOptions: {
content: $t('common.query'),
},
wrapperClass: 'grid-cols-1 md:grid-cols-2',
handleSubmit: async () => {
await handleTabChange(activeTabName.value);
},
});
const [Grid, gridApi] = useVbenVxeGrid({
gridOptions: {
columns: useGridColumns(activeTabName.value),
height: 'auto',
@@ -32,15 +50,6 @@ const [Grid, gridApi] = useVbenVxeGrid({
pagerConfig: {
enabled: false,
},
proxyConfig: {
ajax: {
query: async (_, formValues) => {
const res = await getChartDatas(activeTabName.value, formValues);
await renderEcharts(getChartOptions(activeTabName.value, res));
return getDatas(activeTabName.value, formValues);
},
},
},
rowConfig: {
keyField: 'id',
isHover: true,
@@ -57,28 +66,35 @@ async function handleTabChange(key: any) {
gridApi.setGridOptions({
columns: useGridColumns(key),
});
await gridApi.reload();
const queryParams = await formApi.getValues();
const res = await getChartDatas(activeTabName.value, queryParams);
await renderEcharts(getChartOptions(activeTabName.value, res));
await gridApi.grid.reloadData(res);
}
onMounted(() => {
handleTabChange(activeTabName.value);
});
</script>
<template>
<Page auto-content-height>
<Grid>
<template #toolbar-actions>
<Tabs
v-model:active-key="activeTabName"
class="w-full"
@change="handleTabChange"
>
<Tabs.TabPane
v-for="item in customerSummaryTabs"
:key="item.key"
:tab="item.tab"
:force-render="true"
/>
</Tabs>
<EchartsUI class="mb-20 h-full w-full" ref="chartRef" />
</template>
</Grid>
<ContentWrap>
<QueryForm />
<Tabs
v-model:active-key="activeTabName"
class="w-full"
@change="handleTabChange"
>
<Tabs.TabPane
v-for="item in customerSummaryTabs"
:key="item.key"
:tab="item.tab"
:force-render="true"
/>
</Tabs>
<EchartsUI class="mb-20 h-full w-full" ref="chartRef" />
<Grid />
</ContentWrap>
</Page>
</template>

View File

@@ -1,18 +1,23 @@
<script lang="ts" setup>
import type { EchartsUIType } from '@vben/plugins/echarts';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type {
VxeGridListeners,
VxeTableGridOptions,
} from '#/adapter/vxe-table';
import type { CrmStatisticsFunnelApi } from '#/api/crm/statistics/funnel';
import { ref } from 'vue';
import { reactive, ref } from 'vue';
import { Page } from '@vben/common-ui';
import { ContentWrap, Page } from '@vben/common-ui';
import { EchartsUI, useEcharts } from '@vben/plugins/echarts';
import { Button, ButtonGroup, Tabs } from 'ant-design-vue';
import { useVbenForm } from '#/adapter/form';
import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { getChartDatas, getDatas } from '#/api/crm/statistics/funnel';
import { $t } from '#/locales';
import { getChartOptions } from './chartOptions';
import { customerSummaryTabs, useGridColumns, useGridFormSchema } from './data';
@@ -22,11 +27,39 @@ const chartRef = ref<EchartsUIType>();
const { renderEcharts } = useEcharts(chartRef);
const active = ref(true);
const pagerVO = reactive({
total: 0,
pageNo: 1,
pageSize: 10,
});
const gridEvents: VxeGridListeners = {
async pageChange({ pageSize, currentPage }) {
pagerVO.pageNo = currentPage;
pagerVO.pageSize = pageSize;
await handleTabChange(activeTabName.value);
},
};
const [QueryForm, formApi] = useVbenForm({
commonConfig: {
// 所有表单项
componentProps: {
class: 'w-full',
},
},
schema: useGridFormSchema(),
// 是否可展开
showCollapseButton: true,
submitButtonOptions: {
content: $t('common.query'),
},
wrapperClass: 'grid-cols-1 md:grid-cols-2',
handleSubmit: async () => {
await handleTabChange(activeTabName.value);
},
});
const [Grid, gridApi] = useVbenVxeGrid({
formOptions: {
schema: useGridFormSchema(),
},
gridOptions: {
columns: useGridColumns(activeTabName.value),
height: 'auto',
@@ -34,21 +67,6 @@ const [Grid, gridApi] = useVbenVxeGrid({
pagerConfig: {
enabled: false,
},
proxyConfig: {
ajax: {
query: async ({ page }, formValues) => {
const res = await getChartDatas(activeTabName.value, formValues);
await renderEcharts(
getChartOptions(activeTabName.value, active.value, res),
);
return getDatas(activeTabName.value, {
pageNo: page.currentPage,
pageSize: page.pageSize,
...formValues,
});
},
},
},
rowConfig: {
keyField: 'id',
isHover: true,
@@ -64,60 +82,65 @@ async function handleTabChange(key: any) {
activeTabName.value = key;
gridApi.setGridOptions({
columns: useGridColumns(key),
height: '400px',
keepSource: true,
pagerConfig: {
enabled: activeTabName.value !== 'funnelRef',
enabled: activeTabName.value !== 'funnel',
},
});
await gridApi.reload();
const queryParams = await formApi.getValues();
const res = await getChartDatas(activeTabName.value, queryParams);
await renderEcharts(getChartOptions(activeTabName.value, active.value, res));
const data: any = await getDatas(activeTabName.value, queryParams);
await gridApi.grid.reloadData(
activeTabName.value === 'funnel' ? data : data.list,
);
}
/** 视角切换 */
function handleActive(value: boolean) {
async function handleActive(value: boolean) {
active.value = value;
const queryParams = await formApi.getValues();
renderEcharts(
getChartOptions(
activeTabName.value,
active.value,
gridApi.formApi.getValues(),
),
getChartOptions(activeTabName.value, active.value, queryParams),
);
}
</script>
<template>
<Page auto-content-height>
<Grid>
<template #toolbar-actions>
<Tabs
v-model:active-key="activeTabName"
class="w-full"
@change="handleTabChange"
<ContentWrap>
<QueryForm />
<Tabs
v-model:active-key="activeTabName"
class="w-full"
@change="handleTabChange"
>
<Tabs.TabPane
v-for="item in customerSummaryTabs"
:key="item.key"
:tab="item.tab"
:force-render="true"
/>
</Tabs>
<ButtonGroup>
<Button
:type="active ? 'primary' : 'default'"
v-if="activeTabName === 'funnel'"
@click="handleActive(true)"
>
<Tabs.TabPane
v-for="item in customerSummaryTabs"
:key="item.key"
:tab="item.tab"
:force-render="true"
/>
</Tabs>
<ButtonGroup>
<Button
:type="active ? 'primary' : 'default'"
v-if="activeTabName === 'funnel'"
@click="handleActive(true)"
>
客户视角
</Button>
<Button
:type="active ? 'default' : 'primary'"
v-if="activeTabName === 'funnel'"
@click="handleActive(false)"
>
动态视角
</Button>
</ButtonGroup>
<EchartsUI class="mb-20 h-2/5 w-full" ref="chartRef" />
</template>
</Grid>
客户视角
</Button>
<Button
:type="active ? 'default' : 'primary'"
v-if="activeTabName === 'funnel'"
@click="handleActive(false)"
>
动态视角
</Button>
</ButtonGroup>
<EchartsUI class="mb-20 h-2/5 w-full" ref="chartRef" />
<Grid v-on="gridEvents" />
</ContentWrap>
</Page>
</template>

View File

@@ -6,17 +6,19 @@ import type { CrmStatisticsCustomerApi } from '#/api/crm/statistics/customer';
import { onMounted, ref } from 'vue';
import { Page } from '@vben/common-ui';
import { ContentWrap, Page } from '@vben/common-ui';
import { EchartsUI, useEcharts } from '@vben/plugins/echarts';
import { Tabs } from 'ant-design-vue';
import { useVbenForm } from '#/adapter/form';
import { useVbenVxeGrid } from '#/adapter/vxe-table';
import {
getContractCountPerformance,
getContractPricePerformance,
getReceivablePricePerformance,
} from '#/api/crm/statistics/performance';
import { $t } from '#/locales';
import { getChartOptions } from './chartOptions';
import { customerSummaryTabs, useGridFormSchema } from './data';
@@ -25,13 +27,25 @@ const activeTabName = ref('ContractCountPerformance');
const chartRef = ref<EchartsUIType>();
const { renderEcharts } = useEcharts(chartRef);
const [Grid, gridApi] = useVbenVxeGrid({
formOptions: {
schema: useGridFormSchema(),
handleSubmit: async () => {
await handleTabChange(activeTabName.value);
const [QueryForm, formApi] = useVbenForm({
commonConfig: {
// 所有表单项
componentProps: {
class: 'w-full',
},
},
schema: useGridFormSchema(),
// 是否可展开
showCollapseButton: true,
submitButtonOptions: {
content: $t('common.query'),
},
wrapperClass: 'grid-cols-1 md:grid-cols-2',
handleSubmit: async () => {
await handleTabChange(activeTabName.value);
},
});
const [Grid, gridApi] = useVbenVxeGrid({
gridOptions: {
columns: [],
height: 'auto',
@@ -42,7 +56,6 @@ const [Grid, gridApi] = useVbenVxeGrid({
proxyConfig: {
enabled: false,
},
data: [],
rowConfig: {
keyField: 'id',
isHover: true,
@@ -56,7 +69,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
/** tab 切换 */
async function handleTabChange(key: any) {
activeTabName.value = key;
const params = (await gridApi.formApi.getValues()) as any;
const queryParams = (await formApi.getValues()) as any;
let data: any[] = [];
const columnsData: any[] = [];
let tableData: any[] = [];
@@ -69,7 +82,7 @@ async function handleTabChange(key: any) {
{ title: '环比增长率(%' },
{ title: '同比增长率(%' },
];
data = await getContractCountPerformance(params);
data = await getContractCountPerformance(queryParams);
break;
}
case 'ContractPricePerformance': {
@@ -80,7 +93,7 @@ async function handleTabChange(key: any) {
{ title: '环比增长率(%' },
{ title: '同比增长率(%' },
];
data = await getContractPricePerformance(params);
data = await getContractPricePerformance(queryParams);
break;
}
case 'ReceivablePricePerformance': {
@@ -91,7 +104,7 @@ async function handleTabChange(key: any) {
{ title: '环比增长率(%' },
{ title: '同比增长率(%' },
];
data = await getReceivablePricePerformance(params);
data = await getReceivablePricePerformance(queryParams);
break;
}
default: {
@@ -142,22 +155,22 @@ onMounted(() => {
<template>
<Page auto-content-height>
<Grid>
<template #toolbar-actions>
<Tabs
v-model:active-key="activeTabName"
class="w-full"
@change="handleTabChange"
>
<Tabs.TabPane
v-for="item in customerSummaryTabs"
:key="item.key"
:tab="item.tab"
:force-render="true"
/>
</Tabs>
<EchartsUI class="mb-20 h-full w-full" ref="chartRef" />
</template>
</Grid>
<ContentWrap>
<QueryForm />
<Tabs
v-model:active-key="activeTabName"
class="w-full"
@change="handleTabChange"
>
<Tabs.TabPane
v-for="item in customerSummaryTabs"
:key="item.key"
:tab="item.tab"
:force-render="true"
/>
</Tabs>
<EchartsUI class="mb-20 h-full w-full" ref="chartRef" />
<Grid class="min-h-[400px]" />
</ContentWrap>
</Page>
</template>

View File

@@ -4,15 +4,17 @@ import type { EchartsUIType } from '@vben/plugins/echarts';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { CrmStatisticsCustomerApi } from '#/api/crm/statistics/customer';
import { ref } from 'vue';
import { onMounted, ref } from 'vue';
import { Page } from '@vben/common-ui';
import { ContentWrap, Page } from '@vben/common-ui';
import { EchartsUI, useEcharts } from '@vben/plugins/echarts';
import { Tabs } from 'ant-design-vue';
import { useVbenForm } from '#/adapter/form';
import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { getDatas } from '#/api/crm/statistics/portrait';
import { $t } from '#/locales';
import { getChartOptions } from './chartOptions';
import { customerSummaryTabs, useGridColumns, useGridFormSchema } from './data';
@@ -23,10 +25,25 @@ const rightChartRef = ref<EchartsUIType>();
const { renderEcharts: renderLeftEcharts } = useEcharts(leftChartRef);
const { renderEcharts: renderRightEcharts } = useEcharts(rightChartRef);
const [Grid, gridApi] = useVbenVxeGrid({
formOptions: {
schema: useGridFormSchema(),
const [QueryForm, formApi] = useVbenForm({
commonConfig: {
// 所有表单项
componentProps: {
class: 'w-full',
},
},
schema: useGridFormSchema(),
// 是否可展开
showCollapseButton: true,
submitButtonOptions: {
content: $t('common.query'),
},
wrapperClass: 'grid-cols-1 md:grid-cols-2',
handleSubmit: async () => {
await handleTabChange(activeTabName.value);
},
});
const [Grid, gridApi] = useVbenVxeGrid({
gridOptions: {
columns: useGridColumns(activeTabName.value),
height: 'auto',
@@ -34,20 +51,6 @@ const [Grid, gridApi] = useVbenVxeGrid({
pagerConfig: {
enabled: false,
},
proxyConfig: {
ajax: {
query: async (_, formValues) => {
const res = await getDatas(activeTabName.value, formValues);
await renderLeftEcharts(
getChartOptions(activeTabName.value, res).left,
);
await renderRightEcharts(
getChartOptions(activeTabName.value, res).right,
);
return res;
},
},
},
rowConfig: {
keyField: 'id',
isHover: true,
@@ -64,31 +67,39 @@ async function handleTabChange(key: any) {
gridApi.setGridOptions({
columns: useGridColumns(key),
});
await gridApi.reload();
const queryParams = await formApi.getValues();
const res = await getDatas(activeTabName.value, queryParams);
await renderLeftEcharts(getChartOptions(activeTabName.value, res).left);
await renderRightEcharts(getChartOptions(activeTabName.value, res).right);
await gridApi.grid.reloadData(res);
}
onMounted(() => {
handleTabChange(activeTabName.value);
});
</script>
<template>
<Page auto-content-height>
<Grid>
<template #toolbar-actions>
<Tabs
v-model:active-key="activeTabName"
class="w-full"
@change="handleTabChange"
>
<Tabs.TabPane
v-for="item in customerSummaryTabs"
:key="item.key"
:tab="item.tab"
:force-render="true"
/>
</Tabs>
<div class="mt-5 flex">
<EchartsUI class="m-4 w-1/2" ref="leftChartRef" />
<EchartsUI class="m-4 w-1/2" ref="rightChartRef" />
</div>
</template>
</Grid>
<ContentWrap>
<QueryForm />
<Tabs
v-model:active-key="activeTabName"
class="w-full"
@change="handleTabChange"
>
<Tabs.TabPane
v-for="item in customerSummaryTabs"
:key="item.key"
:tab="item.tab"
:force-render="true"
/>
</Tabs>
<div class="mt-5 flex">
<EchartsUI class="m-4 w-1/2" ref="leftChartRef" />
<EchartsUI class="m-4 w-1/2" ref="rightChartRef" />
</div>
<Grid v-show="activeTabName !== 'area'" />
</ContentWrap>
</Page>
</template>

View File

@@ -4,15 +4,17 @@ import type { EchartsUIType } from '@vben/plugins/echarts';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { CrmStatisticsCustomerApi } from '#/api/crm/statistics/customer';
import { ref } from 'vue';
import { onMounted, ref } from 'vue';
import { Page } from '@vben/common-ui';
import { ContentWrap, Page } from '@vben/common-ui';
import { EchartsUI, useEcharts } from '@vben/plugins/echarts';
import { Tabs } from 'ant-design-vue';
import { useVbenForm } from '#/adapter/form';
import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { getDatas } from '#/api/crm/statistics/customer';
import { $t } from '#/locales';
import { getChartOptions } from './chartOptions';
import { customerSummaryTabs, useGridColumns, useGridFormSchema } from './data';
@@ -21,10 +23,26 @@ const activeTabName = ref('contractPriceRank');
const chartRef = ref<EchartsUIType>();
const { renderEcharts } = useEcharts(chartRef);
const [Grid, gridApi] = useVbenVxeGrid({
formOptions: {
schema: useGridFormSchema(),
const [QueryForm, formApi] = useVbenForm({
commonConfig: {
// 所有表单项
componentProps: {
class: 'w-full',
},
},
schema: useGridFormSchema(),
// 是否可展开
showCollapseButton: true,
submitButtonOptions: {
content: $t('common.query'),
},
wrapperClass: 'grid-cols-1 md:grid-cols-2',
handleSubmit: async () => {
await handleTabChange(activeTabName.value);
},
});
const [Grid, gridApi] = useVbenVxeGrid({
gridOptions: {
columns: useGridColumns(activeTabName.value),
height: 'auto',
@@ -57,28 +75,35 @@ async function handleTabChange(key: any) {
gridApi.setGridOptions({
columns: useGridColumns(key),
});
await gridApi.reload();
const queryParams = await formApi.getValues();
const res = await getDatas(activeTabName.value, queryParams);
await renderEcharts(getChartOptions(activeTabName.value, res));
await gridApi.grid.reloadData(res);
}
onMounted(() => {
handleTabChange(activeTabName.value);
});
</script>
<template>
<Page auto-content-height>
<Grid>
<template #toolbar-actions>
<Tabs
v-model:active-key="activeTabName"
class="w-full"
@change="handleTabChange"
>
<Tabs.TabPane
v-for="item in customerSummaryTabs"
:key="item.key"
:tab="item.tab"
:force-render="true"
/>
</Tabs>
<EchartsUI class="mb-20 h-full w-full" ref="chartRef" />
</template>
</Grid>
<ContentWrap>
<QueryForm />
<Tabs
v-model:active-key="activeTabName"
class="w-full"
@change="handleTabChange"
>
<Tabs.TabPane
v-for="item in customerSummaryTabs"
:key="item.key"
:tab="item.tab"
:force-render="true"
/>
</Tabs>
<EchartsUI class="mb-20 h-full w-full" ref="chartRef" />
<Grid />
</ContentWrap>
</Page>
</template>

View File

@@ -18,6 +18,7 @@ import type { ComposeOption } from 'echarts/core';
import {
BarChart,
FunnelChart,
GaugeChart,
LineChart,
MapChart,
@@ -66,6 +67,7 @@ echarts.use([
TransformComponent,
BarChart,
LineChart,
FunnelChart,
GaugeChart,
LabelLayout,
UniversalTransition,