liu
6 天以前 5c124cdf26e4d749eae1e7fc9df366e9a5f4d259
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
import type { EChartsOption } from '@vben/plugins/echarts';
 
import type { CrmSalesTargetApi } from '#/api/crm/salesTarget';
 
/** 达成分析指标 Tab 定义 */
export const ANALYSIS_TABS = [
  { key: 'contract', label: '合同金额', unit: '元' },
  { key: 'receivable', label: '回款金额', unit: '元' },
  { key: 'business', label: '商机金额', unit: '元' },
  { key: 'customer', label: '新增客户', unit: '个' },
  { key: 'contractCount', label: '新增合同', unit: '个' },
] as const;
 
export type AnalysisTabKey = (typeof ANALYSIS_TABS)[number]['key'];
 
type MetricValue = {
  target: number;
  actual: number;
  rate: number | null;
};
 
const METRICS: Record<
  AnalysisTabKey,
  { label: string; unit: string; pick: (item: CrmSalesTargetApi.SalesTarget) => MetricValue }
> = {
  contract: {
    label: '合同金额',
    unit: '元',
    pick: (item) => ({
      target: item.contractTarget ?? 0,
      actual: item.actualContractPrice ?? 0,
      rate: item.contractRate ?? null,
    }),
  },
  receivable: {
    label: '回款金额',
    unit: '元',
    pick: (item) => ({
      target: item.receivableTarget ?? 0,
      actual: item.actualReceivablePrice ?? 0,
      rate: item.receivableRate ?? null,
    }),
  },
  business: {
    label: '商机金额',
    unit: '元',
    pick: (item) => ({
      target: item.businessTarget ?? 0,
      actual: item.actualBusinessPrice ?? 0,
      rate: item.businessRate ?? null,
    }),
  },
  customer: {
    label: '新增客户',
    unit: '个',
    pick: (item) => ({
      target: item.customerTarget ?? 0,
      actual: item.actualCustomerCount ?? 0,
      rate: item.customerRate ?? null,
    }),
  },
  contractCount: {
    label: '新增合同',
    unit: '个',
    pick: (item) => ({
      target: item.contractCountTarget ?? 0,
      actual: item.actualContractCount ?? 0,
      rate: item.contractCountRate ?? null,
    }),
  },
};
 
function formatNumber(value: number | null | undefined): string {
  return value == null ? '-' : value.toLocaleString('zh-CN');
}
 
/** 生成指标对比柱状图(目标 vs 实际)配置 */
export function getChartOptions(
  tabKey: AnalysisTabKey,
  list: CrmSalesTargetApi.SalesTarget[],
): EChartsOption {
  const metric = METRICS[tabKey];
  const valueName = `${metric.label}(${metric.unit})`;
  return {
    dataset: {
      dimensions: ['name', 'target', 'actual', 'rate'],
      source: list.map((item) => {
        const value = metric.pick(item);
        return {
          name: item.name ?? '--',
          target: value.target,
          actual: value.actual,
          rate: value.rate,
        };
      }),
    },
    grid: { left: 20, right: 20, bottom: 20, containLabel: true },
    legend: { top: 10 },
    series: [
      { name: '目标', type: 'bar', barMaxWidth: 24 },
      { name: '实际', type: 'bar', barMaxWidth: 24 },
    ],
    toolbox: {
      feature: {
        saveAsImage: { show: true, name: `${metric.label}达成对比` },
      },
    },
    tooltip: {
      trigger: 'axis',
      axisPointer: { type: 'shadow' },
      formatter: (params: unknown) => {
        const list = params as Array<{
          data: { name: string; target: number; actual: number; rate: number | null };
        }>;
        const row = list[0]?.data;
        if (!row) {
          return '';
        }
        return [
          `<b>${row.name}</b>`,
          `目标:${formatNumber(row.target)}`,
          `实际:${formatNumber(row.actual)}`,
          `达成率:${row.rate == null ? '-' : `${row.rate}%`}`,
        ].join('<br/>');
      },
    },
    xAxis: { type: 'category', name: '目标名称' },
    yAxis: { type: 'value', name: valueName },
  } as EChartsOption;
}