From 5a5d2f17da8c2436803ceb891df16deb1ffa5bb8 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 27 Dec 2025 12:49:14 +0800 Subject: [PATCH 1/6] =?UTF-8?q?feat=EF=BC=9A=E3=80=90bpm=E3=80=91=E3=80=90?= =?UTF-8?q?antd/ele=E3=80=91=E4=B8=9A=E5=8A=A1=E8=A1=A8=E5=8D=95=EF=BC=8C?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E9=87=8D=E6=96=B0=E5=8F=91=E8=B5=B7=E6=B5=81?= =?UTF-8?q?=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web-antd/src/api/bpm/model/index.ts | 1 + .../src/views/bpm/oa/leave/create.vue | 39 ++++++++++++++++++- apps/web-antd/src/views/bpm/oa/leave/data.ts | 2 +- .../web-antd/src/views/bpm/oa/leave/index.vue | 19 ++++++++- .../src/views/bpm/processInstance/index.vue | 33 +++++++++++----- apps/web-ele/src/api/bpm/model/index.ts | 1 + .../src/views/bpm/processInstance/index.vue | 33 +++++++++++----- 7 files changed, 106 insertions(+), 22 deletions(-) diff --git a/apps/web-antd/src/api/bpm/model/index.ts b/apps/web-antd/src/api/bpm/model/index.ts index 545a73c03..e0c033a44 100644 --- a/apps/web-antd/src/api/bpm/model/index.ts +++ b/apps/web-antd/src/api/bpm/model/index.ts @@ -30,6 +30,7 @@ export namespace BpmModelApi { deploymentTime: number; suspensionState: number; formType?: number; + formCustomCreatePath?: string; formCustomViewPath?: string; formFields?: string[]; } diff --git a/apps/web-antd/src/views/bpm/oa/leave/create.vue b/apps/web-antd/src/views/bpm/oa/leave/create.vue index 19917d107..fd7a11105 100644 --- a/apps/web-antd/src/views/bpm/oa/leave/create.vue +++ b/apps/web-antd/src/views/bpm/oa/leave/create.vue @@ -3,6 +3,7 @@ import type { BpmOALeaveApi } from '#/api/bpm/oa/leave'; import type { BpmProcessInstanceApi } from '#/api/bpm/processInstance'; import { computed, onMounted, ref, watch } from 'vue'; +import { useRoute } from 'vue-router'; import { confirm, Page, useVbenForm } from '@vben/common-ui'; import { BpmCandidateStrategyEnum, BpmNodeIdEnum } from '@vben/constants'; @@ -13,7 +14,7 @@ import { Button, Card, message, Space } from 'ant-design-vue'; import dayjs from 'dayjs'; import { getProcessDefinition } from '#/api/bpm/definition'; -import { createLeave, updateLeave } from '#/api/bpm/oa/leave'; +import { createLeave, getLeave, updateLeave } from '#/api/bpm/oa/leave'; import { getApprovalDetail as getApprovalDetailApi } from '#/api/bpm/processInstance'; import { $t } from '#/locales'; import { router } from '#/router'; @@ -22,6 +23,7 @@ import ProcessInstanceTimeline from '#/views/bpm/processInstance/detail/modules/ import { useFormSchema } from './data'; const { closeCurrentTab } = useTabs(); +const { query } = useRoute(); const formLoading = ref(false); // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 @@ -35,7 +37,7 @@ const processDefinitionId = ref(''); const formData = ref(); const getTitle = computed(() => { return formData.value?.id - ? $t('ui.actionTitle.edit', ['请假']) + ? '重新发起请假' : $t('ui.actionTitle.create', ['请假']); }); @@ -157,6 +159,34 @@ function selectUserConfirm(id: string, userList: any[]) { startUserSelectAssignees.value[id] = userList?.map((item: any) => item.id); } +/** 获取请假数据,用于重新发起时自动填充 */ +async function getDetail(id: number) { + try { + formLoading.value = true; + const data = await getLeave(id); + if (!data) { + message.error('重新发起请假失败,原因:请假数据不存在'); + return; + } + formData.value = { + ...formData.value, + id: data.id, + type: data.type, + reason: data.reason, + startTime: data.startTime, + endTime: data.endTime, + } as BpmOALeaveApi.Leave; + await formApi.setValues({ + type: data.type, + reason: data.reason, + startTime: data.startTime, + endTime: data.endTime, + }); + } finally { + formLoading.value = false; + } +} + /** 审批相关:预测流程节点会因为输入的参数值而产生新的预测结果值,所以需重新预测一次, formData.value可改成实际业务中的特定字段 */ watch( formData.value as object, @@ -190,6 +220,11 @@ onMounted(async () => { processDefinitionId.value = processDefinitionDetail.id; startUserSelectTasks.value = processDefinitionDetail.startUserSelectTasks; + // 如果是重新发起,则加载请假数据 + if (query.id) { + await getDetail(Number(query.id)); + } + await getApprovalDetail(); }); diff --git a/apps/web-antd/src/views/bpm/oa/leave/data.ts b/apps/web-antd/src/views/bpm/oa/leave/data.ts index 79140ef2f..9570f422d 100644 --- a/apps/web-antd/src/views/bpm/oa/leave/data.ts +++ b/apps/web-antd/src/views/bpm/oa/leave/data.ts @@ -168,7 +168,7 @@ export function useGridColumns(): VxeTableGridOptions['columns'] { }, { title: '操作', - width: 220, + width: 240, fixed: 'right', slots: { default: 'actions' }, }, diff --git a/apps/web-antd/src/views/bpm/oa/leave/index.vue b/apps/web-antd/src/views/bpm/oa/leave/index.vue index fae7f7c4a..70748c819 100644 --- a/apps/web-antd/src/views/bpm/oa/leave/index.vue +++ b/apps/web-antd/src/views/bpm/oa/leave/index.vue @@ -33,6 +33,16 @@ function handleCreate() { }); } +/** 重新发起请假 */ +function handleReCreate(row: BpmOALeaveApi.Leave) { + router.push({ + name: 'OALeaveCreate', + query: { + id: row.id, + }, + }); +} + /** 取消请假 */ function handleCancel(row: BpmOALeaveApi.Leave) { prompt({ @@ -161,9 +171,16 @@ const [Grid, gridApi] = useVbenVxeGrid({ type: 'link', danger: true, icon: ACTION_ICON.DELETE, - ifShow: row.result === BpmProcessInstanceStatus.RUNNING, + ifShow: row.status === BpmProcessInstanceStatus.RUNNING, onClick: handleCancel.bind(null, row), }, + { + label: '重新发起', + type: 'link', + icon: ACTION_ICON.ADD, + ifShow: row.status !== BpmProcessInstanceStatus.RUNNING, + onClick: handleReCreate.bind(null, row), + }, ]" /> diff --git a/apps/web-antd/src/views/bpm/processInstance/index.vue b/apps/web-antd/src/views/bpm/processInstance/index.vue index 44c05463d..ddb721467 100644 --- a/apps/web-antd/src/views/bpm/processInstance/index.vue +++ b/apps/web-antd/src/views/bpm/processInstance/index.vue @@ -5,7 +5,11 @@ import type { BpmProcessInstanceApi } from '#/api/bpm/processInstance'; import { h } from 'vue'; import { DocAlert, Page, prompt } from '@vben/common-ui'; -import { BpmProcessInstanceStatus, DICT_TYPE } from '@vben/constants'; +import { + BpmModelFormType, + BpmProcessInstanceStatus, + DICT_TYPE, +} from '@vben/constants'; import { Button, message, Textarea } from 'ant-design-vue'; @@ -37,23 +41,34 @@ function handleDetail(row: BpmProcessInstanceApi.ProcessInstance) { } /** 重新发起流程 */ -async function handleCreate(row: BpmProcessInstanceApi.ProcessInstance) { - // 如果是【业务表单】,不支持重新发起 +async function handleCreate(row?: BpmProcessInstanceApi.ProcessInstance) { if (row?.id) { const processDefinitionDetail = await getProcessDefinition( row.processDefinitionId, ); - if (processDefinitionDetail.formType === 20) { - message.error( - '重新发起流程失败,原因:该流程使用业务表单,不支持重新发起', - ); + if (processDefinitionDetail?.formType === BpmModelFormType.CUSTOM) { + if (!processDefinitionDetail.formCustomCreatePath) { + message.error('未配置业务表单的提交路由,无法重新发起'); + return; + } + await router.push({ + path: processDefinitionDetail.formCustomCreatePath, + query: { + id: row.businessKey, + }, + }); + return; + } else if (processDefinitionDetail?.formType === BpmModelFormType.NORMAL) { + await router.push({ + name: 'BpmProcessInstanceCreate', + query: { processInstanceId: row.id }, + }); return; } } - // 跳转发起流程界面 await router.push({ name: 'BpmProcessInstanceCreate', - query: { processInstanceId: row?.id }, + query: row?.id ? { processInstanceId: row.id } : {}, }); } diff --git a/apps/web-ele/src/api/bpm/model/index.ts b/apps/web-ele/src/api/bpm/model/index.ts index 545a73c03..e0c033a44 100644 --- a/apps/web-ele/src/api/bpm/model/index.ts +++ b/apps/web-ele/src/api/bpm/model/index.ts @@ -30,6 +30,7 @@ export namespace BpmModelApi { deploymentTime: number; suspensionState: number; formType?: number; + formCustomCreatePath?: string; formCustomViewPath?: string; formFields?: string[]; } diff --git a/apps/web-ele/src/views/bpm/processInstance/index.vue b/apps/web-ele/src/views/bpm/processInstance/index.vue index 52936bcbc..b4d85896d 100644 --- a/apps/web-ele/src/views/bpm/processInstance/index.vue +++ b/apps/web-ele/src/views/bpm/processInstance/index.vue @@ -5,7 +5,11 @@ import type { BpmProcessInstanceApi } from '#/api/bpm/processInstance'; import { h } from 'vue'; import { DocAlert, Page, prompt } from '@vben/common-ui'; -import { BpmProcessInstanceStatus, DICT_TYPE } from '@vben/constants'; +import { + BpmModelFormType, + BpmProcessInstanceStatus, + DICT_TYPE, +} from '@vben/constants'; import { ElButton, ElInput, ElMessage } from 'element-plus'; @@ -37,23 +41,34 @@ function handleDetail(row: BpmProcessInstanceApi.ProcessInstance) { } /** 重新发起流程 */ -async function handleCreate(row: BpmProcessInstanceApi.ProcessInstance) { - // 如果是【业务表单】,不支持重新发起 +async function handleCreate(row?: BpmProcessInstanceApi.ProcessInstance) { if (row?.id) { const processDefinitionDetail = await getProcessDefinition( row.processDefinitionId, ); - if (processDefinitionDetail.formType === 20) { - ElMessage.error( - '重新发起流程失败,原因:该流程使用业务表单,不支持重新发起', - ); + if (processDefinitionDetail?.formType === BpmModelFormType.CUSTOM) { + if (!processDefinitionDetail.formCustomCreatePath) { + ElMessage.error('未配置业务表单的提交路由,无法重新发起'); + return; + } + await router.push({ + path: processDefinitionDetail.formCustomCreatePath, + query: { + id: row.businessKey, + }, + }); + return; + } else if (processDefinitionDetail?.formType === BpmModelFormType.NORMAL) { + await router.push({ + name: 'BpmProcessInstanceCreate', + query: { processInstanceId: row.id }, + }); return; } } - // 跳转发起流程界面 await router.push({ name: 'BpmProcessInstanceCreate', - query: { processInstanceId: row?.id }, + query: row?.id ? { processInstanceId: row.id } : {}, }); } From 9ef218f93076e0552bb10bcbc2c0d28d1d85fca7 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 27 Dec 2025 17:02:11 +0800 Subject: [PATCH 2/6] =?UTF-8?q?refactor:=20=E3=80=90crm=E3=80=91=E3=80=90a?= =?UTF-8?q?ntd/ele=E3=80=91=E6=8F=90=E5=8F=96=E5=9B=BE=E8=A1=A8=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E7=94=9F=E6=88=90=E5=87=BD=E6=95=B0=EF=BC=8C=E7=BB=9F?= =?UTF-8?q?=E4=B8=80=20legend/grid/tooltip=20=E5=A4=84=E7=90=86=EF=BC=8C?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E9=A5=BC=E5=9B=BE=E9=9D=A2=E6=9D=BF=E7=94=9F?= =?UTF-8?q?=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../crm/statistics/customer/chartOptions.ts | 154 +++---- .../crm/statistics/funnel/chartOptions.ts | 62 +-- .../statistics/performance/chartOptions.ts | 55 +-- .../crm/statistics/portrait/chartOptions.ts | 425 +++++------------- .../views/crm/statistics/rank/chartOptions.ts | 120 ++--- .../crm/statistics/customer/chartOptions.ts | 148 +++--- .../crm/statistics/funnel/chartOptions.ts | 62 +-- .../statistics/performance/chartOptions.ts | 55 +-- .../crm/statistics/portrait/chartOptions.ts | 425 +++++------------- .../views/crm/statistics/rank/chartOptions.ts | 120 ++--- 10 files changed, 535 insertions(+), 1091 deletions(-) diff --git a/apps/web-antd/src/views/crm/statistics/customer/chartOptions.ts b/apps/web-antd/src/views/crm/statistics/customer/chartOptions.ts index deecbd370..1c3781293 100644 --- a/apps/web-antd/src/views/crm/statistics/customer/chartOptions.ts +++ b/apps/web-antd/src/views/crm/statistics/customer/chartOptions.ts @@ -1,17 +1,34 @@ import { DICT_TYPE } from '@vben/constants'; import { getDictLabel } from '@vben/hooks'; +const getLegend = (extra: Record = {}) => ({ + top: 10, + ...extra, +}); + +const getGrid = (extra: Record = {}) => ({ + left: 20, + right: 20, + bottom: 20, + containLabel: true, + ...extra, +}); + +const getTooltip = (extra: Record = {}) => ({ + trigger: 'axis', + axisPointer: { + type: 'shadow', + }, + ...extra, +}); + export function getChartOptions(activeTabName: any, res: any): any { switch (activeTabName) { + // 客户转化率分析 case 'conversionStat': { return { - grid: { - left: 20, - right: 40, // 让 X 轴右侧显示完整 - bottom: 20, - containLabel: true, - }, - legend: {}, + grid: getGrid(), + legend: getLegend(), series: [ { name: '客户转化率', @@ -21,9 +38,9 @@ export function getChartOptions(activeTabName: any, res: any): any { name: item.time, value: item.customerCreateCount ? ( - (item.customerDealCount / item.customerCreateCount) * - 100 - ).toFixed(2) + (item.customerDealCount / item.customerCreateCount) * + 100 + ).toFixed(2) : 0, }; }), @@ -40,12 +57,7 @@ export function getChartOptions(activeTabName: any, res: any): any { saveAsImage: { show: true, name: '客户转化率分析' }, // 保存为图片 }, }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow', - }, - }, + tooltip: getTooltip(), yAxis: { type: 'value', name: '转化率(%)', @@ -59,14 +71,13 @@ export function getChartOptions(activeTabName: any, res: any): any { } case 'customerSummary': { return { - grid: { - bottom: '5%', - containLabel: true, + grid: getGrid({ + bottom: '8%', left: '5%', right: '5%', - top: '5 %', - }, - legend: {}, + top: 80, + }), + legend: getLegend(), series: [ { name: '新增客户数', @@ -92,12 +103,7 @@ export function getChartOptions(activeTabName: any, res: any): any { saveAsImage: { show: true, name: '客户总量分析' }, // 保存为图片 }, }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow', - }, - }, + tooltip: getTooltip(), yAxis: [ { type: 'value', @@ -134,13 +140,8 @@ export function getChartOptions(activeTabName: any, res: any): any { }; }); return { - grid: { - left: 20, - right: 40, // 让 X 轴右侧显示完整 - bottom: 20, - containLabel: true, - }, - legend: {}, + grid: getGrid(), + legend: getLegend(), series: [ { name: '成交周期(天)', @@ -166,12 +167,7 @@ export function getChartOptions(activeTabName: any, res: any): any { saveAsImage: { show: true, name: '成交周期分析' }, // 保存为图片 }, }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow', - }, - }, + tooltip: getTooltip(), yAxis: [ { type: 'value', @@ -208,13 +204,8 @@ export function getChartOptions(activeTabName: any, res: any): any { }; }); return { - grid: { - left: 20, - right: 40, // 让 X 轴右侧显示完整 - bottom: 20, - containLabel: true, - }, - legend: {}, + grid: getGrid(), + legend: getLegend(), series: [ { name: '成交周期(天)', @@ -240,12 +231,7 @@ export function getChartOptions(activeTabName: any, res: any): any { saveAsImage: { show: true, name: '成交周期分析' }, // 保存为图片 }, }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow', - }, - }, + tooltip: getTooltip(), yAxis: [ { type: 'value', @@ -277,13 +263,8 @@ export function getChartOptions(activeTabName: any, res: any): any { const customerDealCycleByDate = res.customerDealCycleByDate; const customerDealCycleByUser = res.customerDealCycleByUser; return { - grid: { - left: 20, - right: 40, // 让 X 轴右侧显示完整 - bottom: 20, - containLabel: true, - }, - legend: {}, + grid: getGrid(), + legend: getLegend(), series: [ { name: '成交周期(天)', @@ -309,12 +290,7 @@ export function getChartOptions(activeTabName: any, res: any): any { saveAsImage: { show: true, name: '成交周期分析' }, // 保存为图片 }, }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow', - }, - }, + tooltip: getTooltip(), yAxis: [ { type: 'value', @@ -342,15 +318,13 @@ export function getChartOptions(activeTabName: any, res: any): any { }, }; } + // 客户跟进次数分析 case 'followUpSummary': { return { - grid: { - left: 20, + grid: getGrid({ right: 30, // 让 X 轴右侧显示完整 - bottom: 20, - containLabel: true, - }, - legend: {}, + }), + legend: getLegend(), series: [ { name: '跟进客户数', @@ -376,12 +350,7 @@ export function getChartOptions(activeTabName: any, res: any): any { saveAsImage: { show: true, name: '客户跟进次数分析' }, // 保存为图片 }, }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow', - }, - }, + tooltip: getTooltip(), yAxis: [ { type: 'value', @@ -412,20 +381,21 @@ export function getChartOptions(activeTabName: any, res: any): any { }, }; } + // 客户跟进方式分析 case 'followUpType': { return { title: { text: '客户跟进方式分析', left: 'center', }, - legend: { - orient: 'vertical', + legend: getLegend({ left: 'left', - }, - tooltip: { + }), + tooltip: getTooltip({ trigger: 'item', + axisPointer: undefined, formatter: '{b} : {c}% ', - }, + }), toolbox: { feature: { saveAsImage: { show: true, name: '客户跟进方式分析' }, // 保存为图片 @@ -458,13 +428,8 @@ export function getChartOptions(activeTabName: any, res: any): any { } case 'poolSummary': { return { - grid: { - left: 20, - right: 40, // 让 X 轴右侧显示完整 - bottom: 20, - containLabel: true, - }, - legend: {}, + grid: getGrid(), + legend: getLegend(), series: [ { name: '进入公海客户数', @@ -490,12 +455,7 @@ export function getChartOptions(activeTabName: any, res: any): any { saveAsImage: { show: true, name: '公海客户分析' }, // 保存为图片 }, }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow', - }, - }, + tooltip: getTooltip(), yAxis: [ { type: 'value', diff --git a/apps/web-antd/src/views/crm/statistics/funnel/chartOptions.ts b/apps/web-antd/src/views/crm/statistics/funnel/chartOptions.ts index e86953f4c..e7ce47511 100644 --- a/apps/web-antd/src/views/crm/statistics/funnel/chartOptions.ts +++ b/apps/web-antd/src/views/crm/statistics/funnel/chartOptions.ts @@ -1,5 +1,26 @@ import { erpCalculatePercentage } from '@vben/utils'; +const getLegend = (extra: Record = {}) => ({ + top: 10, + ...extra, +}); + +const getGrid = (extra: Record = {}) => ({ + left: 20, + right: 20, + bottom: 20, + containLabel: true, + ...extra, +}); + +const getTooltip = (extra: Record = {}) => ({ + trigger: 'axis', + axisPointer: { + type: 'shadow', + }, + ...extra, +}); + export function getChartOptions( activeTabName: any, active: boolean, @@ -9,26 +30,19 @@ export function getChartOptions( case 'businessInversionRateSummary': { return { color: ['#6ca2ff', '#6ac9d7', '#ff7474'], - tooltip: { - trigger: 'axis', - axisPointer: { - // 坐标轴指示器,坐标轴触发有效 - type: 'shadow', // 默认为直线,可选为:'line' | 'shadow' - }, - }, - legend: { + tooltip: getTooltip(), + legend: getLegend({ data: ['赢单转化率', '商机总数', '赢单商机数'], bottom: '0px', itemWidth: 14, - }, - grid: { + }), + grid: getGrid({ top: '40px', left: '40px', right: '40px', bottom: '40px', - containLabel: true, borderColor: '#fff', - }, + }), xAxis: [ { type: 'category', @@ -117,13 +131,11 @@ export function getChartOptions( } case 'businessSummary': { return { - grid: { + grid: getGrid({ left: 30, right: 30, // 让 X 轴右侧显示完整 - bottom: 20, - containLabel: true, - }, - legend: {}, + }), + legend: getLegend(), series: [ { name: '新增商机数量', @@ -149,12 +161,7 @@ export function getChartOptions( saveAsImage: { show: true, name: '新增商机分析' }, // 保存为图片 }, }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow', - }, - }, + tooltip: getTooltip(), yAxis: [ { type: 'value', @@ -211,10 +218,11 @@ export function getChartOptions( title: { text: '销售漏斗', }, - tooltip: { + tooltip: getTooltip({ trigger: 'item', + axisPointer: undefined, formatter: '{a}
{b}', - }, + }), toolbox: { feature: { dataView: { readOnly: false }, @@ -222,9 +230,9 @@ export function getChartOptions( saveAsImage: {}, }, }, - legend: { + legend: getLegend({ data: ['客户', '商机', '赢单'], - }, + }), series: [ { name: '销售漏斗', diff --git a/apps/web-antd/src/views/crm/statistics/performance/chartOptions.ts b/apps/web-antd/src/views/crm/statistics/performance/chartOptions.ts index 329b4d7ff..073c625e4 100644 --- a/apps/web-antd/src/views/crm/statistics/performance/chartOptions.ts +++ b/apps/web-antd/src/views/crm/statistics/performance/chartOptions.ts @@ -1,14 +1,30 @@ +const getLegend = (extra: Record = {}) => ({ + top: 10, + ...extra, +}); + +const getGrid = (extra: Record = {}) => ({ + left: 20, + right: 20, + bottom: 20, + containLabel: true, + ...extra, +}); + +const getTooltip = (extra: Record = {}) => ({ + trigger: 'axis', + axisPointer: { + type: 'shadow', + }, + ...extra, +}); + export function getChartOptions(activeTabName: any, res: any): any { switch (activeTabName) { case 'ContractCountPerformance': { return { - grid: { - left: 20, - right: 20, - bottom: 20, - containLabel: true, - }, - legend: {}, + grid: getGrid(), + legend: getLegend(), series: [ { name: '当月合同数量(个)', @@ -65,12 +81,7 @@ export function getChartOptions(activeTabName: any, res: any): any { saveAsImage: { show: true, name: '客户总量分析' }, // 保存为图片 }, }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow', - }, - }, + tooltip: getTooltip(), yAxis: [ { type: 'value', @@ -131,13 +142,8 @@ export function getChartOptions(activeTabName: any, res: any): any { } case 'ContractPricePerformance': { return { - grid: { - left: 20, - right: 20, - bottom: 20, - containLabel: true, - }, - legend: {}, + grid: getGrid(), + legend: getLegend(), series: [ { name: '当月合同金额(元)', @@ -260,13 +266,8 @@ export function getChartOptions(activeTabName: any, res: any): any { } case 'ReceivablePricePerformance': { return { - grid: { - left: 20, - right: 20, - bottom: 20, - containLabel: true, - }, - legend: {}, + grid: getGrid(), + legend: getLegend(), series: [ { name: '当月回款金额(元)', diff --git a/apps/web-antd/src/views/crm/statistics/portrait/chartOptions.ts b/apps/web-antd/src/views/crm/statistics/portrait/chartOptions.ts index b63ea2513..7088c22c4 100644 --- a/apps/web-antd/src/views/crm/statistics/portrait/chartOptions.ts +++ b/apps/web-antd/src/views/crm/statistics/portrait/chartOptions.ts @@ -13,6 +13,71 @@ function areaReplace(areaName: string) { .replace('省', ''); } +const getPieTooltip = (extra: Record = {}) => ({ + trigger: 'item', + ...extra, +}); + +const getPieLegend = (extra: Record = {}) => ({ + orient: 'vertical', + left: 'left', + ...extra, +}); + +const getPieSeries = (name: string, data: any[]) => ({ + name, + type: 'pie', + radius: ['40%', '70%'], + avoidLabelOverlap: false, + itemStyle: { + borderRadius: 10, + borderColor: '#fff', + borderWidth: 2, + }, + label: { + show: false, + position: 'center', + }, + emphasis: { + label: { + show: true, + fontSize: 40, + fontWeight: 'bold', + }, + }, + labelLine: { + show: false, + }, + data, +}); + +const getPiePanel = ({ + data, + legendExtra, + seriesName, + title, + tooltipExtra, +}: { + data: any[]; + legendExtra?: Record; + seriesName: string; + title: string; + tooltipExtra?: Record; +}) => ({ + title: { + text: title, + left: 'center', + }, + tooltip: getPieTooltip(tooltipExtra), + legend: getPieLegend(legendExtra), + toolbox: { + feature: { + saveAsImage: { show: true, name: title }, + }, + }, + series: [getPieSeries(seriesName, data)], +}); + export function getChartOptions(activeTabName: any, res: any): any { switch (activeTabName) { case 'area': { @@ -111,326 +176,62 @@ export function getChartOptions(activeTabName: any, res: any): any { } case 'industry': { return { - left: { - title: { - text: '全部客户', - left: 'center', - }, - tooltip: { - trigger: 'item', - }, - legend: { - orient: 'vertical', - left: 'left', - }, - toolbox: { - feature: { - saveAsImage: { show: true, name: '全部客户' }, // 保存为图片 - }, - }, - series: [ - { - name: '全部客户', - type: 'pie', - radius: ['40%', '70%'], - avoidLabelOverlap: false, - itemStyle: { - borderRadius: 10, - borderColor: '#fff', - borderWidth: 2, - }, - label: { - show: false, - position: 'center', - }, - emphasis: { - label: { - show: true, - fontSize: 40, - fontWeight: 'bold', - }, - }, - labelLine: { - show: false, - }, - data: res.map((r: any) => { - return { - name: getDictLabel( - DICT_TYPE.CRM_CUSTOMER_INDUSTRY, - r.industryId, - ), - value: r.customerCount, - }; - }), - }, - ], - }, - right: { - title: { - text: '成交客户', - left: 'center', - }, - tooltip: { - trigger: 'item', - }, - legend: { - orient: 'vertical', - left: 'left', - }, - toolbox: { - feature: { - saveAsImage: { show: true, name: '成交客户' }, // 保存为图片 - }, - }, - series: [ - { - name: '成交客户', - type: 'pie', - radius: ['40%', '70%'], - avoidLabelOverlap: false, - itemStyle: { - borderRadius: 10, - borderColor: '#fff', - borderWidth: 2, - }, - label: { - show: false, - position: 'center', - }, - emphasis: { - label: { - show: true, - fontSize: 40, - fontWeight: 'bold', - }, - }, - labelLine: { - show: false, - }, - data: res.map((r: any) => { - return { - name: getDictLabel( - DICT_TYPE.CRM_CUSTOMER_INDUSTRY, - r.industryId, - ), - value: r.dealCount, - }; - }), - }, - ], - }, + left: getPiePanel({ + title: '全部客户', + seriesName: '全部客户', + data: res.map((r: any) => ({ + name: getDictLabel(DICT_TYPE.CRM_CUSTOMER_INDUSTRY, r.industryId), + value: r.customerCount, + })), + }), + right: getPiePanel({ + title: '成交客户', + seriesName: '成交客户', + data: res.map((r: any) => ({ + name: getDictLabel(DICT_TYPE.CRM_CUSTOMER_INDUSTRY, r.industryId), + value: r.dealCount, + })), + }), }; } case 'level': { return { - left: { - title: { - text: '全部客户', - left: 'center', - }, - tooltip: { - trigger: 'item', - }, - legend: { - orient: 'vertical', - left: 'left', - }, - toolbox: { - feature: { - saveAsImage: { show: true, name: '全部客户' }, // 保存为图片 - }, - }, - series: [ - { - name: '全部客户', - type: 'pie', - radius: ['40%', '70%'], - avoidLabelOverlap: false, - itemStyle: { - borderRadius: 10, - borderColor: '#fff', - borderWidth: 2, - }, - label: { - show: false, - position: 'center', - }, - emphasis: { - label: { - show: true, - fontSize: 40, - fontWeight: 'bold', - }, - }, - labelLine: { - show: false, - }, - data: res.map((r: any) => { - return { - name: getDictLabel(DICT_TYPE.CRM_CUSTOMER_LEVEL, r.level), - value: r.customerCount, - }; - }), - }, - ], - }, - right: { - title: { - text: '成交客户', - left: 'center', - }, - tooltip: { - trigger: 'item', - }, - legend: { - orient: 'vertical', - left: 'left', - }, - toolbox: { - feature: { - saveAsImage: { show: true, name: '成交客户' }, // 保存为图片 - }, - }, - series: [ - { - name: '成交客户', - type: 'pie', - radius: ['40%', '70%'], - avoidLabelOverlap: false, - itemStyle: { - borderRadius: 10, - borderColor: '#fff', - borderWidth: 2, - }, - label: { - show: false, - position: 'center', - }, - emphasis: { - label: { - show: true, - fontSize: 40, - fontWeight: 'bold', - }, - }, - labelLine: { - show: false, - }, - data: res.map((r: any) => { - return { - name: getDictLabel(DICT_TYPE.CRM_CUSTOMER_LEVEL, r.level), - value: r.dealCount, - }; - }), - }, - ], - }, + left: getPiePanel({ + title: '全部客户', + seriesName: '全部客户', + data: res.map((r: any) => ({ + name: getDictLabel(DICT_TYPE.CRM_CUSTOMER_LEVEL, r.level), + value: r.customerCount, + })), + }), + right: getPiePanel({ + title: '成交客户', + seriesName: '成交客户', + data: res.map((r: any) => ({ + name: getDictLabel(DICT_TYPE.CRM_CUSTOMER_LEVEL, r.level), + value: r.dealCount, + })), + }), }; } case 'source': { return { - left: { - title: { - text: '全部客户', - left: 'center', - }, - tooltip: { - trigger: 'item', - }, - legend: { - orient: 'vertical', - left: 'left', - }, - toolbox: { - feature: { - saveAsImage: { show: true, name: '全部客户' }, // 保存为图片 - }, - }, - series: [ - { - name: '全部客户', - type: 'pie', - radius: ['40%', '70%'], - avoidLabelOverlap: false, - itemStyle: { - borderRadius: 10, - borderColor: '#fff', - borderWidth: 2, - }, - label: { - show: false, - position: 'center', - }, - emphasis: { - label: { - show: true, - fontSize: 40, - fontWeight: 'bold', - }, - }, - labelLine: { - show: false, - }, - data: res.map((r: any) => { - return { - name: getDictLabel(DICT_TYPE.CRM_CUSTOMER_SOURCE, r.source), - value: r.customerCount, - }; - }), - }, - ], - }, - right: { - title: { - text: '成交客户', - left: 'center', - }, - tooltip: { - trigger: 'item', - }, - legend: { - orient: 'vertical', - left: 'left', - }, - toolbox: { - feature: { - saveAsImage: { show: true, name: '成交客户' }, // 保存为图片 - }, - }, - series: [ - { - name: '成交客户', - type: 'pie', - radius: ['40%', '70%'], - avoidLabelOverlap: false, - itemStyle: { - borderRadius: 10, - borderColor: '#fff', - borderWidth: 2, - }, - label: { - show: false, - position: 'center', - }, - emphasis: { - label: { - show: true, - fontSize: 40, - fontWeight: 'bold', - }, - }, - labelLine: { - show: false, - }, - data: res.map((r: any) => { - return { - name: getDictLabel(DICT_TYPE.CRM_CUSTOMER_SOURCE, r.source), - value: r.dealCount, - }; - }), - }, - ], - }, + left: getPiePanel({ + title: '全部客户', + seriesName: '全部客户', + data: res.map((r: any) => ({ + name: getDictLabel(DICT_TYPE.CRM_CUSTOMER_SOURCE, r.source), + value: r.customerCount, + })), + }), + right: getPiePanel({ + title: '成交客户', + seriesName: '成交客户', + data: res.map((r: any) => ({ + name: getDictLabel(DICT_TYPE.CRM_CUSTOMER_SOURCE, r.source), + value: r.dealCount, + })), + }), }; } default: { diff --git a/apps/web-antd/src/views/crm/statistics/rank/chartOptions.ts b/apps/web-antd/src/views/crm/statistics/rank/chartOptions.ts index a6c36e958..aceffbc65 100644 --- a/apps/web-antd/src/views/crm/statistics/rank/chartOptions.ts +++ b/apps/web-antd/src/views/crm/statistics/rank/chartOptions.ts @@ -1,5 +1,25 @@ import { cloneDeep } from '@vben/utils'; +const getLegend = (extra: Record = {}) => ({ + top: 10, + ...extra, +}); + +const getGrid = (extra: Record = {}) => ({ + left: 20, + right: 20, + bottom: 20, + containLabel: true, + ...extra, +}); + +const getTooltip = () => ({ + trigger: 'axis', + axisPointer: { + type: 'shadow', + }, +}); + export function getChartOptions(activeTabName: any, res: any): any { switch (activeTabName) { case 'contactCountRank': { @@ -8,15 +28,8 @@ export function getChartOptions(activeTabName: any, res: any): any { dimensions: ['nickname', 'count'], source: cloneDeep(res).toReversed(), }, - grid: { - left: 20, - right: 20, - bottom: 20, - containLabel: true, - }, - legend: { - top: 50, - }, + grid: getGrid(), + legend: getLegend(), series: [ { name: '新增联系人数排行', @@ -34,12 +47,7 @@ export function getChartOptions(activeTabName: any, res: any): any { saveAsImage: { show: true, name: '新增联系人数排行' }, // 保存为图片 }, }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow', - }, - }, + tooltip: getTooltip(), xAxis: { type: 'value', name: '新增联系人数(个)', @@ -56,15 +64,8 @@ export function getChartOptions(activeTabName: any, res: any): any { dimensions: ['nickname', 'count'], source: cloneDeep(res).toReversed(), }, - grid: { - left: 20, - right: 20, - bottom: 20, - containLabel: true, - }, - legend: { - top: 50, - }, + grid: getGrid(), + legend: getLegend(), series: [ { name: '签约合同排行', @@ -82,12 +83,7 @@ export function getChartOptions(activeTabName: any, res: any): any { saveAsImage: { show: true, name: '签约合同排行' }, // 保存为图片 }, }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow', - }, - }, + tooltip: getTooltip(), xAxis: { type: 'value', name: '签约合同数(个)', @@ -104,15 +100,8 @@ export function getChartOptions(activeTabName: any, res: any): any { dimensions: ['nickname', 'count'], source: cloneDeep(res).toReversed(), }, - grid: { - left: 20, - right: 20, - bottom: 20, - containLabel: true, - }, - legend: { - top: 50, - }, + grid: getGrid(), + legend: getLegend(), series: [ { name: '合同金额排行', @@ -130,12 +119,7 @@ export function getChartOptions(activeTabName: any, res: any): any { saveAsImage: { show: true, name: '合同金额排行' }, // 保存为图片 }, }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow', - }, - }, + tooltip: getTooltip(), xAxis: { type: 'value', name: '合同金额(元)', @@ -152,15 +136,8 @@ export function getChartOptions(activeTabName: any, res: any): any { dimensions: ['nickname', 'count'], source: cloneDeep(res).toReversed(), }, - grid: { - left: 20, - right: 20, - bottom: 20, - containLabel: true, - }, - legend: { - top: 50, - }, + grid: getGrid(), + legend: getLegend(), series: [ { name: '新增客户数排行', @@ -178,12 +155,7 @@ export function getChartOptions(activeTabName: any, res: any): any { saveAsImage: { show: true, name: '新增客户数排行' }, // 保存为图片 }, }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow', - }, - }, + tooltip: getTooltip(), xAxis: { type: 'value', name: '新增客户数(个)', @@ -226,12 +198,7 @@ export function getChartOptions(activeTabName: any, res: any): any { saveAsImage: { show: true, name: '跟进次数排行' }, // 保存为图片 }, }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow', - }, - }, + tooltip: getTooltip(), xAxis: { type: 'value', name: '跟进次数(次)', @@ -274,12 +241,7 @@ export function getChartOptions(activeTabName: any, res: any): any { saveAsImage: { show: true, name: '跟进客户数排行' }, // 保存为图片 }, }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow', - }, - }, + tooltip: getTooltip(), xAxis: { type: 'value', name: '跟进客户数(个)', @@ -322,12 +284,7 @@ export function getChartOptions(activeTabName: any, res: any): any { saveAsImage: { show: true, name: '产品销量排行' }, // 保存为图片 }, }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow', - }, - }, + tooltip: getTooltip(), xAxis: { type: 'value', name: '产品销量', @@ -370,12 +327,7 @@ export function getChartOptions(activeTabName: any, res: any): any { saveAsImage: { show: true, name: '回款金额排行' }, // 保存为图片 }, }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow', - }, - }, + tooltip: getTooltip(), xAxis: { type: 'value', name: '回款金额(元)', diff --git a/apps/web-ele/src/views/crm/statistics/customer/chartOptions.ts b/apps/web-ele/src/views/crm/statistics/customer/chartOptions.ts index deecbd370..383833832 100644 --- a/apps/web-ele/src/views/crm/statistics/customer/chartOptions.ts +++ b/apps/web-ele/src/views/crm/statistics/customer/chartOptions.ts @@ -1,17 +1,34 @@ import { DICT_TYPE } from '@vben/constants'; import { getDictLabel } from '@vben/hooks'; +const getLegend = (extra: Record = {}) => ({ + top: 10, + ...extra, +}); + +const getGrid = (extra: Record = {}) => ({ + left: 20, + right: 20, + bottom: 20, + containLabel: true, + ...extra, +}); + +const getTooltip = (extra: Record = {}) => ({ + trigger: 'axis', + axisPointer: { + type: 'shadow', + }, + ...extra, +}); + export function getChartOptions(activeTabName: any, res: any): any { switch (activeTabName) { + // 客户转化率分析 case 'conversionStat': { return { - grid: { - left: 20, - right: 40, // 让 X 轴右侧显示完整 - bottom: 20, - containLabel: true, - }, - legend: {}, + grid: getGrid(), + legend: getLegend(), series: [ { name: '客户转化率', @@ -40,12 +57,7 @@ export function getChartOptions(activeTabName: any, res: any): any { saveAsImage: { show: true, name: '客户转化率分析' }, // 保存为图片 }, }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow', - }, - }, + tooltip: getTooltip(), yAxis: { type: 'value', name: '转化率(%)', @@ -59,14 +71,13 @@ export function getChartOptions(activeTabName: any, res: any): any { } case 'customerSummary': { return { - grid: { - bottom: '5%', - containLabel: true, + grid: getGrid({ + bottom: '8%', left: '5%', right: '5%', - top: '5 %', - }, - legend: {}, + top: 80, + }), + legend: getLegend(), series: [ { name: '新增客户数', @@ -92,12 +103,7 @@ export function getChartOptions(activeTabName: any, res: any): any { saveAsImage: { show: true, name: '客户总量分析' }, // 保存为图片 }, }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow', - }, - }, + tooltip: getTooltip(), yAxis: [ { type: 'value', @@ -134,13 +140,8 @@ export function getChartOptions(activeTabName: any, res: any): any { }; }); return { - grid: { - left: 20, - right: 40, // 让 X 轴右侧显示完整 - bottom: 20, - containLabel: true, - }, - legend: {}, + grid: getGrid(), + legend: getLegend(), series: [ { name: '成交周期(天)', @@ -166,12 +167,7 @@ export function getChartOptions(activeTabName: any, res: any): any { saveAsImage: { show: true, name: '成交周期分析' }, // 保存为图片 }, }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow', - }, - }, + tooltip: getTooltip(), yAxis: [ { type: 'value', @@ -208,13 +204,8 @@ export function getChartOptions(activeTabName: any, res: any): any { }; }); return { - grid: { - left: 20, - right: 40, // 让 X 轴右侧显示完整 - bottom: 20, - containLabel: true, - }, - legend: {}, + grid: getGrid(), + legend: getLegend(), series: [ { name: '成交周期(天)', @@ -240,12 +231,7 @@ export function getChartOptions(activeTabName: any, res: any): any { saveAsImage: { show: true, name: '成交周期分析' }, // 保存为图片 }, }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow', - }, - }, + tooltip: getTooltip(), yAxis: [ { type: 'value', @@ -277,13 +263,8 @@ export function getChartOptions(activeTabName: any, res: any): any { const customerDealCycleByDate = res.customerDealCycleByDate; const customerDealCycleByUser = res.customerDealCycleByUser; return { - grid: { - left: 20, - right: 40, // 让 X 轴右侧显示完整 - bottom: 20, - containLabel: true, - }, - legend: {}, + grid: getGrid(), + legend: getLegend(), series: [ { name: '成交周期(天)', @@ -309,12 +290,7 @@ export function getChartOptions(activeTabName: any, res: any): any { saveAsImage: { show: true, name: '成交周期分析' }, // 保存为图片 }, }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow', - }, - }, + tooltip: getTooltip(), yAxis: [ { type: 'value', @@ -342,15 +318,13 @@ export function getChartOptions(activeTabName: any, res: any): any { }, }; } + // 客户跟进次数分析 case 'followUpSummary': { return { - grid: { - left: 20, + grid: getGrid({ right: 30, // 让 X 轴右侧显示完整 - bottom: 20, - containLabel: true, - }, - legend: {}, + }), + legend: getLegend(), series: [ { name: '跟进客户数', @@ -376,12 +350,7 @@ export function getChartOptions(activeTabName: any, res: any): any { saveAsImage: { show: true, name: '客户跟进次数分析' }, // 保存为图片 }, }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow', - }, - }, + tooltip: getTooltip(), yAxis: [ { type: 'value', @@ -412,20 +381,21 @@ export function getChartOptions(activeTabName: any, res: any): any { }, }; } + // 客户跟进方式分析 case 'followUpType': { return { title: { text: '客户跟进方式分析', left: 'center', }, - legend: { - orient: 'vertical', + legend: getLegend({ left: 'left', - }, - tooltip: { + }), + tooltip: getTooltip({ trigger: 'item', + axisPointer: undefined, formatter: '{b} : {c}% ', - }, + }), toolbox: { feature: { saveAsImage: { show: true, name: '客户跟进方式分析' }, // 保存为图片 @@ -458,13 +428,8 @@ export function getChartOptions(activeTabName: any, res: any): any { } case 'poolSummary': { return { - grid: { - left: 20, - right: 40, // 让 X 轴右侧显示完整 - bottom: 20, - containLabel: true, - }, - legend: {}, + grid: getGrid(), + legend: getLegend(), series: [ { name: '进入公海客户数', @@ -490,12 +455,7 @@ export function getChartOptions(activeTabName: any, res: any): any { saveAsImage: { show: true, name: '公海客户分析' }, // 保存为图片 }, }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow', - }, - }, + tooltip: getTooltip(), yAxis: [ { type: 'value', diff --git a/apps/web-ele/src/views/crm/statistics/funnel/chartOptions.ts b/apps/web-ele/src/views/crm/statistics/funnel/chartOptions.ts index e86953f4c..e7ce47511 100644 --- a/apps/web-ele/src/views/crm/statistics/funnel/chartOptions.ts +++ b/apps/web-ele/src/views/crm/statistics/funnel/chartOptions.ts @@ -1,5 +1,26 @@ import { erpCalculatePercentage } from '@vben/utils'; +const getLegend = (extra: Record = {}) => ({ + top: 10, + ...extra, +}); + +const getGrid = (extra: Record = {}) => ({ + left: 20, + right: 20, + bottom: 20, + containLabel: true, + ...extra, +}); + +const getTooltip = (extra: Record = {}) => ({ + trigger: 'axis', + axisPointer: { + type: 'shadow', + }, + ...extra, +}); + export function getChartOptions( activeTabName: any, active: boolean, @@ -9,26 +30,19 @@ export function getChartOptions( case 'businessInversionRateSummary': { return { color: ['#6ca2ff', '#6ac9d7', '#ff7474'], - tooltip: { - trigger: 'axis', - axisPointer: { - // 坐标轴指示器,坐标轴触发有效 - type: 'shadow', // 默认为直线,可选为:'line' | 'shadow' - }, - }, - legend: { + tooltip: getTooltip(), + legend: getLegend({ data: ['赢单转化率', '商机总数', '赢单商机数'], bottom: '0px', itemWidth: 14, - }, - grid: { + }), + grid: getGrid({ top: '40px', left: '40px', right: '40px', bottom: '40px', - containLabel: true, borderColor: '#fff', - }, + }), xAxis: [ { type: 'category', @@ -117,13 +131,11 @@ export function getChartOptions( } case 'businessSummary': { return { - grid: { + grid: getGrid({ left: 30, right: 30, // 让 X 轴右侧显示完整 - bottom: 20, - containLabel: true, - }, - legend: {}, + }), + legend: getLegend(), series: [ { name: '新增商机数量', @@ -149,12 +161,7 @@ export function getChartOptions( saveAsImage: { show: true, name: '新增商机分析' }, // 保存为图片 }, }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow', - }, - }, + tooltip: getTooltip(), yAxis: [ { type: 'value', @@ -211,10 +218,11 @@ export function getChartOptions( title: { text: '销售漏斗', }, - tooltip: { + tooltip: getTooltip({ trigger: 'item', + axisPointer: undefined, formatter: '{a}
{b}', - }, + }), toolbox: { feature: { dataView: { readOnly: false }, @@ -222,9 +230,9 @@ export function getChartOptions( saveAsImage: {}, }, }, - legend: { + legend: getLegend({ data: ['客户', '商机', '赢单'], - }, + }), series: [ { name: '销售漏斗', diff --git a/apps/web-ele/src/views/crm/statistics/performance/chartOptions.ts b/apps/web-ele/src/views/crm/statistics/performance/chartOptions.ts index 329b4d7ff..073c625e4 100644 --- a/apps/web-ele/src/views/crm/statistics/performance/chartOptions.ts +++ b/apps/web-ele/src/views/crm/statistics/performance/chartOptions.ts @@ -1,14 +1,30 @@ +const getLegend = (extra: Record = {}) => ({ + top: 10, + ...extra, +}); + +const getGrid = (extra: Record = {}) => ({ + left: 20, + right: 20, + bottom: 20, + containLabel: true, + ...extra, +}); + +const getTooltip = (extra: Record = {}) => ({ + trigger: 'axis', + axisPointer: { + type: 'shadow', + }, + ...extra, +}); + export function getChartOptions(activeTabName: any, res: any): any { switch (activeTabName) { case 'ContractCountPerformance': { return { - grid: { - left: 20, - right: 20, - bottom: 20, - containLabel: true, - }, - legend: {}, + grid: getGrid(), + legend: getLegend(), series: [ { name: '当月合同数量(个)', @@ -65,12 +81,7 @@ export function getChartOptions(activeTabName: any, res: any): any { saveAsImage: { show: true, name: '客户总量分析' }, // 保存为图片 }, }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow', - }, - }, + tooltip: getTooltip(), yAxis: [ { type: 'value', @@ -131,13 +142,8 @@ export function getChartOptions(activeTabName: any, res: any): any { } case 'ContractPricePerformance': { return { - grid: { - left: 20, - right: 20, - bottom: 20, - containLabel: true, - }, - legend: {}, + grid: getGrid(), + legend: getLegend(), series: [ { name: '当月合同金额(元)', @@ -260,13 +266,8 @@ export function getChartOptions(activeTabName: any, res: any): any { } case 'ReceivablePricePerformance': { return { - grid: { - left: 20, - right: 20, - bottom: 20, - containLabel: true, - }, - legend: {}, + grid: getGrid(), + legend: getLegend(), series: [ { name: '当月回款金额(元)', diff --git a/apps/web-ele/src/views/crm/statistics/portrait/chartOptions.ts b/apps/web-ele/src/views/crm/statistics/portrait/chartOptions.ts index b63ea2513..7088c22c4 100644 --- a/apps/web-ele/src/views/crm/statistics/portrait/chartOptions.ts +++ b/apps/web-ele/src/views/crm/statistics/portrait/chartOptions.ts @@ -13,6 +13,71 @@ function areaReplace(areaName: string) { .replace('省', ''); } +const getPieTooltip = (extra: Record = {}) => ({ + trigger: 'item', + ...extra, +}); + +const getPieLegend = (extra: Record = {}) => ({ + orient: 'vertical', + left: 'left', + ...extra, +}); + +const getPieSeries = (name: string, data: any[]) => ({ + name, + type: 'pie', + radius: ['40%', '70%'], + avoidLabelOverlap: false, + itemStyle: { + borderRadius: 10, + borderColor: '#fff', + borderWidth: 2, + }, + label: { + show: false, + position: 'center', + }, + emphasis: { + label: { + show: true, + fontSize: 40, + fontWeight: 'bold', + }, + }, + labelLine: { + show: false, + }, + data, +}); + +const getPiePanel = ({ + data, + legendExtra, + seriesName, + title, + tooltipExtra, +}: { + data: any[]; + legendExtra?: Record; + seriesName: string; + title: string; + tooltipExtra?: Record; +}) => ({ + title: { + text: title, + left: 'center', + }, + tooltip: getPieTooltip(tooltipExtra), + legend: getPieLegend(legendExtra), + toolbox: { + feature: { + saveAsImage: { show: true, name: title }, + }, + }, + series: [getPieSeries(seriesName, data)], +}); + export function getChartOptions(activeTabName: any, res: any): any { switch (activeTabName) { case 'area': { @@ -111,326 +176,62 @@ export function getChartOptions(activeTabName: any, res: any): any { } case 'industry': { return { - left: { - title: { - text: '全部客户', - left: 'center', - }, - tooltip: { - trigger: 'item', - }, - legend: { - orient: 'vertical', - left: 'left', - }, - toolbox: { - feature: { - saveAsImage: { show: true, name: '全部客户' }, // 保存为图片 - }, - }, - series: [ - { - name: '全部客户', - type: 'pie', - radius: ['40%', '70%'], - avoidLabelOverlap: false, - itemStyle: { - borderRadius: 10, - borderColor: '#fff', - borderWidth: 2, - }, - label: { - show: false, - position: 'center', - }, - emphasis: { - label: { - show: true, - fontSize: 40, - fontWeight: 'bold', - }, - }, - labelLine: { - show: false, - }, - data: res.map((r: any) => { - return { - name: getDictLabel( - DICT_TYPE.CRM_CUSTOMER_INDUSTRY, - r.industryId, - ), - value: r.customerCount, - }; - }), - }, - ], - }, - right: { - title: { - text: '成交客户', - left: 'center', - }, - tooltip: { - trigger: 'item', - }, - legend: { - orient: 'vertical', - left: 'left', - }, - toolbox: { - feature: { - saveAsImage: { show: true, name: '成交客户' }, // 保存为图片 - }, - }, - series: [ - { - name: '成交客户', - type: 'pie', - radius: ['40%', '70%'], - avoidLabelOverlap: false, - itemStyle: { - borderRadius: 10, - borderColor: '#fff', - borderWidth: 2, - }, - label: { - show: false, - position: 'center', - }, - emphasis: { - label: { - show: true, - fontSize: 40, - fontWeight: 'bold', - }, - }, - labelLine: { - show: false, - }, - data: res.map((r: any) => { - return { - name: getDictLabel( - DICT_TYPE.CRM_CUSTOMER_INDUSTRY, - r.industryId, - ), - value: r.dealCount, - }; - }), - }, - ], - }, + left: getPiePanel({ + title: '全部客户', + seriesName: '全部客户', + data: res.map((r: any) => ({ + name: getDictLabel(DICT_TYPE.CRM_CUSTOMER_INDUSTRY, r.industryId), + value: r.customerCount, + })), + }), + right: getPiePanel({ + title: '成交客户', + seriesName: '成交客户', + data: res.map((r: any) => ({ + name: getDictLabel(DICT_TYPE.CRM_CUSTOMER_INDUSTRY, r.industryId), + value: r.dealCount, + })), + }), }; } case 'level': { return { - left: { - title: { - text: '全部客户', - left: 'center', - }, - tooltip: { - trigger: 'item', - }, - legend: { - orient: 'vertical', - left: 'left', - }, - toolbox: { - feature: { - saveAsImage: { show: true, name: '全部客户' }, // 保存为图片 - }, - }, - series: [ - { - name: '全部客户', - type: 'pie', - radius: ['40%', '70%'], - avoidLabelOverlap: false, - itemStyle: { - borderRadius: 10, - borderColor: '#fff', - borderWidth: 2, - }, - label: { - show: false, - position: 'center', - }, - emphasis: { - label: { - show: true, - fontSize: 40, - fontWeight: 'bold', - }, - }, - labelLine: { - show: false, - }, - data: res.map((r: any) => { - return { - name: getDictLabel(DICT_TYPE.CRM_CUSTOMER_LEVEL, r.level), - value: r.customerCount, - }; - }), - }, - ], - }, - right: { - title: { - text: '成交客户', - left: 'center', - }, - tooltip: { - trigger: 'item', - }, - legend: { - orient: 'vertical', - left: 'left', - }, - toolbox: { - feature: { - saveAsImage: { show: true, name: '成交客户' }, // 保存为图片 - }, - }, - series: [ - { - name: '成交客户', - type: 'pie', - radius: ['40%', '70%'], - avoidLabelOverlap: false, - itemStyle: { - borderRadius: 10, - borderColor: '#fff', - borderWidth: 2, - }, - label: { - show: false, - position: 'center', - }, - emphasis: { - label: { - show: true, - fontSize: 40, - fontWeight: 'bold', - }, - }, - labelLine: { - show: false, - }, - data: res.map((r: any) => { - return { - name: getDictLabel(DICT_TYPE.CRM_CUSTOMER_LEVEL, r.level), - value: r.dealCount, - }; - }), - }, - ], - }, + left: getPiePanel({ + title: '全部客户', + seriesName: '全部客户', + data: res.map((r: any) => ({ + name: getDictLabel(DICT_TYPE.CRM_CUSTOMER_LEVEL, r.level), + value: r.customerCount, + })), + }), + right: getPiePanel({ + title: '成交客户', + seriesName: '成交客户', + data: res.map((r: any) => ({ + name: getDictLabel(DICT_TYPE.CRM_CUSTOMER_LEVEL, r.level), + value: r.dealCount, + })), + }), }; } case 'source': { return { - left: { - title: { - text: '全部客户', - left: 'center', - }, - tooltip: { - trigger: 'item', - }, - legend: { - orient: 'vertical', - left: 'left', - }, - toolbox: { - feature: { - saveAsImage: { show: true, name: '全部客户' }, // 保存为图片 - }, - }, - series: [ - { - name: '全部客户', - type: 'pie', - radius: ['40%', '70%'], - avoidLabelOverlap: false, - itemStyle: { - borderRadius: 10, - borderColor: '#fff', - borderWidth: 2, - }, - label: { - show: false, - position: 'center', - }, - emphasis: { - label: { - show: true, - fontSize: 40, - fontWeight: 'bold', - }, - }, - labelLine: { - show: false, - }, - data: res.map((r: any) => { - return { - name: getDictLabel(DICT_TYPE.CRM_CUSTOMER_SOURCE, r.source), - value: r.customerCount, - }; - }), - }, - ], - }, - right: { - title: { - text: '成交客户', - left: 'center', - }, - tooltip: { - trigger: 'item', - }, - legend: { - orient: 'vertical', - left: 'left', - }, - toolbox: { - feature: { - saveAsImage: { show: true, name: '成交客户' }, // 保存为图片 - }, - }, - series: [ - { - name: '成交客户', - type: 'pie', - radius: ['40%', '70%'], - avoidLabelOverlap: false, - itemStyle: { - borderRadius: 10, - borderColor: '#fff', - borderWidth: 2, - }, - label: { - show: false, - position: 'center', - }, - emphasis: { - label: { - show: true, - fontSize: 40, - fontWeight: 'bold', - }, - }, - labelLine: { - show: false, - }, - data: res.map((r: any) => { - return { - name: getDictLabel(DICT_TYPE.CRM_CUSTOMER_SOURCE, r.source), - value: r.dealCount, - }; - }), - }, - ], - }, + left: getPiePanel({ + title: '全部客户', + seriesName: '全部客户', + data: res.map((r: any) => ({ + name: getDictLabel(DICT_TYPE.CRM_CUSTOMER_SOURCE, r.source), + value: r.customerCount, + })), + }), + right: getPiePanel({ + title: '成交客户', + seriesName: '成交客户', + data: res.map((r: any) => ({ + name: getDictLabel(DICT_TYPE.CRM_CUSTOMER_SOURCE, r.source), + value: r.dealCount, + })), + }), }; } default: { diff --git a/apps/web-ele/src/views/crm/statistics/rank/chartOptions.ts b/apps/web-ele/src/views/crm/statistics/rank/chartOptions.ts index a6c36e958..aceffbc65 100644 --- a/apps/web-ele/src/views/crm/statistics/rank/chartOptions.ts +++ b/apps/web-ele/src/views/crm/statistics/rank/chartOptions.ts @@ -1,5 +1,25 @@ import { cloneDeep } from '@vben/utils'; +const getLegend = (extra: Record = {}) => ({ + top: 10, + ...extra, +}); + +const getGrid = (extra: Record = {}) => ({ + left: 20, + right: 20, + bottom: 20, + containLabel: true, + ...extra, +}); + +const getTooltip = () => ({ + trigger: 'axis', + axisPointer: { + type: 'shadow', + }, +}); + export function getChartOptions(activeTabName: any, res: any): any { switch (activeTabName) { case 'contactCountRank': { @@ -8,15 +28,8 @@ export function getChartOptions(activeTabName: any, res: any): any { dimensions: ['nickname', 'count'], source: cloneDeep(res).toReversed(), }, - grid: { - left: 20, - right: 20, - bottom: 20, - containLabel: true, - }, - legend: { - top: 50, - }, + grid: getGrid(), + legend: getLegend(), series: [ { name: '新增联系人数排行', @@ -34,12 +47,7 @@ export function getChartOptions(activeTabName: any, res: any): any { saveAsImage: { show: true, name: '新增联系人数排行' }, // 保存为图片 }, }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow', - }, - }, + tooltip: getTooltip(), xAxis: { type: 'value', name: '新增联系人数(个)', @@ -56,15 +64,8 @@ export function getChartOptions(activeTabName: any, res: any): any { dimensions: ['nickname', 'count'], source: cloneDeep(res).toReversed(), }, - grid: { - left: 20, - right: 20, - bottom: 20, - containLabel: true, - }, - legend: { - top: 50, - }, + grid: getGrid(), + legend: getLegend(), series: [ { name: '签约合同排行', @@ -82,12 +83,7 @@ export function getChartOptions(activeTabName: any, res: any): any { saveAsImage: { show: true, name: '签约合同排行' }, // 保存为图片 }, }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow', - }, - }, + tooltip: getTooltip(), xAxis: { type: 'value', name: '签约合同数(个)', @@ -104,15 +100,8 @@ export function getChartOptions(activeTabName: any, res: any): any { dimensions: ['nickname', 'count'], source: cloneDeep(res).toReversed(), }, - grid: { - left: 20, - right: 20, - bottom: 20, - containLabel: true, - }, - legend: { - top: 50, - }, + grid: getGrid(), + legend: getLegend(), series: [ { name: '合同金额排行', @@ -130,12 +119,7 @@ export function getChartOptions(activeTabName: any, res: any): any { saveAsImage: { show: true, name: '合同金额排行' }, // 保存为图片 }, }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow', - }, - }, + tooltip: getTooltip(), xAxis: { type: 'value', name: '合同金额(元)', @@ -152,15 +136,8 @@ export function getChartOptions(activeTabName: any, res: any): any { dimensions: ['nickname', 'count'], source: cloneDeep(res).toReversed(), }, - grid: { - left: 20, - right: 20, - bottom: 20, - containLabel: true, - }, - legend: { - top: 50, - }, + grid: getGrid(), + legend: getLegend(), series: [ { name: '新增客户数排行', @@ -178,12 +155,7 @@ export function getChartOptions(activeTabName: any, res: any): any { saveAsImage: { show: true, name: '新增客户数排行' }, // 保存为图片 }, }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow', - }, - }, + tooltip: getTooltip(), xAxis: { type: 'value', name: '新增客户数(个)', @@ -226,12 +198,7 @@ export function getChartOptions(activeTabName: any, res: any): any { saveAsImage: { show: true, name: '跟进次数排行' }, // 保存为图片 }, }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow', - }, - }, + tooltip: getTooltip(), xAxis: { type: 'value', name: '跟进次数(次)', @@ -274,12 +241,7 @@ export function getChartOptions(activeTabName: any, res: any): any { saveAsImage: { show: true, name: '跟进客户数排行' }, // 保存为图片 }, }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow', - }, - }, + tooltip: getTooltip(), xAxis: { type: 'value', name: '跟进客户数(个)', @@ -322,12 +284,7 @@ export function getChartOptions(activeTabName: any, res: any): any { saveAsImage: { show: true, name: '产品销量排行' }, // 保存为图片 }, }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow', - }, - }, + tooltip: getTooltip(), xAxis: { type: 'value', name: '产品销量', @@ -370,12 +327,7 @@ export function getChartOptions(activeTabName: any, res: any): any { saveAsImage: { show: true, name: '回款金额排行' }, // 保存为图片 }, }, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow', - }, - }, + tooltip: getTooltip(), xAxis: { type: 'value', name: '回款金额(元)', From 826a1b355ae016829e5e6944c466f2cee7b3225a Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 27 Dec 2025 17:06:15 +0800 Subject: [PATCH 3/6] =?UTF-8?q?feat=EF=BC=9A=E3=80=90antd/ele=E3=80=91?= =?UTF-8?q?=E5=AF=B9=E9=BD=90=E4=B8=A4=E4=BE=A7=E7=9A=84=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/views/crm/statistics/customer/chartOptions.ts | 6 +++--- apps/web-antd/src/views/mp/material/index.vue | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/web-antd/src/views/crm/statistics/customer/chartOptions.ts b/apps/web-antd/src/views/crm/statistics/customer/chartOptions.ts index 1c3781293..383833832 100644 --- a/apps/web-antd/src/views/crm/statistics/customer/chartOptions.ts +++ b/apps/web-antd/src/views/crm/statistics/customer/chartOptions.ts @@ -38,9 +38,9 @@ export function getChartOptions(activeTabName: any, res: any): any { name: item.time, value: item.customerCreateCount ? ( - (item.customerDealCount / item.customerCreateCount) * - 100 - ).toFixed(2) + (item.customerDealCount / item.customerCreateCount) * + 100 + ).toFixed(2) : 0, }; }), diff --git a/apps/web-antd/src/views/mp/material/index.vue b/apps/web-antd/src/views/mp/material/index.vue index 9e0fa6394..ade8c6e9b 100644 --- a/apps/web-antd/src/views/mp/material/index.vue +++ b/apps/web-antd/src/views/mp/material/index.vue @@ -7,6 +7,7 @@ import { provide, ref } from 'vue'; import { useAccess } from '@vben/access'; import { confirm, DocAlert, Page } from '@vben/common-ui'; import { IconifyIcon } from '@vben/icons'; +import { $t } from '@vben/locales'; import { Button, message, Tabs } from 'ant-design-vue'; @@ -23,7 +24,6 @@ import { import { UploadType } from './modules/upload'; import UploadFile from './modules/UploadFile.vue'; import UploadVideo from './modules/UploadVideo.vue'; -import {$t} from '@vben/locales'; defineOptions({ name: 'MpMaterial' }); @@ -106,7 +106,7 @@ async function onTabChange() { }, cellConfig: { height: type.value === UploadType.Image ? 220 : undefined, - } + }, }); await gridApi.reload(); } From 304f2442eb15bc294c3ae6a4004821b2d6bad378 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 27 Dec 2025 17:13:40 +0800 Subject: [PATCH 4/6] =?UTF-8?q?feat=EF=BC=9A=E3=80=90antd/ele=E3=80=91?= =?UTF-8?q?=E3=80=90infra=E3=80=91=E7=BB=9F=E4=B8=80=20cron-tab=20?= =?UTF-8?q?=E7=9A=84=E5=B0=81=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/cron-tab/cron-tab.vue | 235 +--------------- apps/web-ele/src/components/cron-tab/types.ts | 266 ++++++++++++++++++ 2 files changed, 277 insertions(+), 224 deletions(-) create mode 100644 apps/web-ele/src/components/cron-tab/types.ts diff --git a/apps/web-ele/src/components/cron-tab/cron-tab.vue b/apps/web-ele/src/components/cron-tab/cron-tab.vue index f34d05f17..5b19025cd 100644 --- a/apps/web-ele/src/components/cron-tab/cron-tab.vue +++ b/apps/web-ele/src/components/cron-tab/cron-tab.vue @@ -1,6 +1,8 @@