From 763def2de045c08419823e78374e5aaa9544e117 Mon Sep 17 00:00:00 2001 From: WDEP <128273529+WDEP-good@users.noreply.github.com> Date: Mon, 5 May 2025 15:47:18 +0800 Subject: [PATCH] dev_add_show-pie (#2241) Great, thanks! --- .../packages/chat-sdk/src/common/constants.ts | 1 + .../src/components/ChatItem/ExecuteItem.tsx | 8 +- .../src/components/ChatMsg/Bar/index.tsx | 4 +- .../src/components/ChatMsg/Pie/PieChart.tsx | 123 ++++++++++++++++++ .../src/components/ChatMsg/Pie/index.tsx | 88 +++++++++++++ .../src/components/ChatMsg/Pie/style.less | 43 ++++++ .../chat-sdk/src/components/ChatMsg/index.tsx | 28 +++- .../packages/chat-sdk/src/styles/index.less | 2 + 8 files changed, 291 insertions(+), 6 deletions(-) create mode 100644 webapp/packages/chat-sdk/src/components/ChatMsg/Pie/PieChart.tsx create mode 100644 webapp/packages/chat-sdk/src/components/ChatMsg/Pie/index.tsx create mode 100644 webapp/packages/chat-sdk/src/components/ChatMsg/Pie/style.less diff --git a/webapp/packages/chat-sdk/src/common/constants.ts b/webapp/packages/chat-sdk/src/common/constants.ts index 80ab89ed2..f6148f6bb 100644 --- a/webapp/packages/chat-sdk/src/common/constants.ts +++ b/webapp/packages/chat-sdk/src/common/constants.ts @@ -81,6 +81,7 @@ export enum MsgContentTypeEnum { METRIC_TREND = 'METRIC_TREND', METRIC_BAR = 'METRIC_BAR', MARKDOWN = 'MARKDOWN', + METRIC_PIE = 'METRIC_PIE', } export enum ChatContextTypeQueryTypeEnum { diff --git a/webapp/packages/chat-sdk/src/components/ChatItem/ExecuteItem.tsx b/webapp/packages/chat-sdk/src/components/ChatItem/ExecuteItem.tsx index 9832121ae..6500036f5 100644 --- a/webapp/packages/chat-sdk/src/components/ChatItem/ExecuteItem.tsx +++ b/webapp/packages/chat-sdk/src/components/ChatItem/ExecuteItem.tsx @@ -123,9 +123,11 @@ const ExecuteItem: React.FC = ({ )}
- {[MsgContentTypeEnum.METRIC_TREND, MsgContentTypeEnum.METRIC_BAR].includes( - msgContentType as MsgContentTypeEnum - ) && ( + {[ + MsgContentTypeEnum.METRIC_TREND, + MsgContentTypeEnum.METRIC_BAR, + MsgContentTypeEnum.METRIC_PIE, + ].includes(msgContentType as MsgContentTypeEnum) && ( = ({ data, - question, + question="", triggerResize, loading, metricField, diff --git a/webapp/packages/chat-sdk/src/components/ChatMsg/Pie/PieChart.tsx b/webapp/packages/chat-sdk/src/components/ChatMsg/Pie/PieChart.tsx new file mode 100644 index 000000000..05c9fde9b --- /dev/null +++ b/webapp/packages/chat-sdk/src/components/ChatMsg/Pie/PieChart.tsx @@ -0,0 +1,123 @@ +import { PREFIX_CLS, THEME_COLOR_LIST } from '../../../common/constants'; +import { MsgDataType } from '../../../common/type'; +import { formatByDecimalPlaces, getFormattedValue } from '../../../utils/utils'; +import type { ECharts } from 'echarts'; +import * as echarts from 'echarts'; +import { useEffect, useRef } from 'react'; +import { ColumnType } from '../../../common/type'; + +type Props = { + data: MsgDataType; + metricField: ColumnType; + categoryField: ColumnType; + triggerResize?: boolean; +}; + +const PieChart: React.FC = ({ + data, + metricField, + categoryField, + triggerResize, +}) => { + const chartRef = useRef(); + const instanceRef = useRef(); + + const { queryResults } = data; + const categoryColumnName = categoryField?.bizName || ''; + const metricColumnName = metricField?.bizName || ''; + + const renderChart = () => { + let instanceObj: any; + if (!instanceRef.current) { + instanceObj = echarts.init(chartRef.current); + instanceRef.current = instanceObj; + } else { + instanceObj = instanceRef.current; + } + + const data = queryResults || []; + const seriesData = data.map((item, index) => { + const value = item[metricColumnName]; + const name = item[categoryColumnName] !== undefined ? item[categoryColumnName] : '未知'; + return { + name, + value, + itemStyle: { + color: THEME_COLOR_LIST[index % THEME_COLOR_LIST.length], + }, + }; + }); + + instanceObj.setOption({ + tooltip: { + trigger: 'item', + formatter: function (params: any) { + const value = params.value; + return `${params.name}: ${ + metricField.dataFormatType === 'percent' + ? `${formatByDecimalPlaces( + metricField.dataFormat?.needMultiply100 ? +value * 100 : value, + metricField.dataFormat?.decimalPlaces || 2 + )}%` + : getFormattedValue(value) + }`; + }, + }, + legend: { + orient: 'vertical', + left: 'left', + type: 'scroll', + data: seriesData.map(item => item.name), + selectedMode: true, + textStyle: { + color: '#666', + }, + }, + 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: '14', + fontWeight: 'bold', + }, + }, + labelLine: { + show: false, + }, + data: seriesData, + }, + ], + }); + instanceObj.resize(); + }; + + useEffect(() => { + if (queryResults && queryResults.length > 0) { + renderChart(); + } + }, [queryResults, metricField, categoryField]); + + useEffect(() => { + if (triggerResize && instanceRef.current) { + instanceRef.current.resize(); + } + }, [triggerResize]); + + return
; +}; + +export default PieChart; diff --git a/webapp/packages/chat-sdk/src/components/ChatMsg/Pie/index.tsx b/webapp/packages/chat-sdk/src/components/ChatMsg/Pie/index.tsx new file mode 100644 index 000000000..358e48138 --- /dev/null +++ b/webapp/packages/chat-sdk/src/components/ChatMsg/Pie/index.tsx @@ -0,0 +1,88 @@ +import { PREFIX_CLS } from '../../../common/constants'; +import { MsgDataType } from '../../../common/type'; +import { useRef, useState } from 'react'; +import NoPermissionChart from '../NoPermissionChart'; +import { ColumnType } from '../../../common/type'; +import { Spin, Select } from 'antd'; +import PieChart from './PieChart'; +import Bar from '../Bar'; + +type Props = { + data: MsgDataType; + question: string; + triggerResize?: boolean; + loading: boolean; + metricField: ColumnType; + categoryField: ColumnType; + onApplyAuth?: (model: string) => void; +}; + +const metricChartSelectOptions = [ + { + value: 'pie', + label: '饼图', + }, + { + value: 'bar', + label: '柱状图', + }, +]; + +const Pie: React.FC = ({ + data, + question, + triggerResize, + loading, + metricField, + categoryField, + onApplyAuth, +}) => { + const [chartType, setChartType] = useState('pie'); + const { entityInfo } = data; + + if (metricField && !metricField?.authorized) { + return ( + + ); + } + + const prefixCls = `${PREFIX_CLS}-pie`; + + return ( +
+
+ {question} +
+
+