mirror of
https://github.com/tencentmusic/supersonic.git
synced 2025-12-14 22:25:19 +00:00
(feature)(chat-sdk) trend chart supports switch between line and bar,add second drill-down dimensions,chang queryMode from ENTITY to TAG (#422)
This commit is contained in:
@@ -45,7 +45,7 @@ const Message: React.FC<Props> = ({
|
||||
e.stopPropagation();
|
||||
}}
|
||||
>
|
||||
{(queryMode === 'METRIC_ENTITY' || queryMode === 'ENTITY_DETAIL') &&
|
||||
{(queryMode === 'METRIC_TAG' || queryMode === 'TAG_DETAIL') &&
|
||||
entityInfoList.length > 0 && (
|
||||
<div className={`${prefixCls}-info-bar`}>
|
||||
<div className={`${prefixCls}-main-entity-info`}>
|
||||
@@ -64,7 +64,7 @@ const Message: React.FC<Props> = ({
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{queryMode === 'ENTITY_LIST_FILTER' && (
|
||||
{queryMode === 'TAG_LIST_FILTER' && (
|
||||
<div className={`${prefixCls}-info-bar`}>
|
||||
<div className={`${prefixCls}-main-entity-info`}>
|
||||
<div className={`${prefixCls}-info-item`}>
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
}
|
||||
|
||||
&-filter-item {
|
||||
margin-right: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
@@ -52,11 +53,16 @@
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
&-query-tootip {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
&-indicator {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
justify-content: flex-start;
|
||||
margin: 12px 0;
|
||||
}
|
||||
|
||||
&-date-range {
|
||||
|
||||
@@ -23,6 +23,7 @@ type Props = {
|
||||
resultList: any[];
|
||||
triggerResize?: boolean;
|
||||
onApplyAuth?: (model: string) => void;
|
||||
chartType?: string;
|
||||
};
|
||||
|
||||
const MetricTrendChart: React.FC<Props> = ({
|
||||
@@ -33,6 +34,7 @@ const MetricTrendChart: React.FC<Props> = ({
|
||||
resultList,
|
||||
triggerResize,
|
||||
onApplyAuth,
|
||||
chartType,
|
||||
}) => {
|
||||
const chartRef = useRef<any>();
|
||||
const [instance, setInstance] = useState<ECharts>();
|
||||
@@ -173,7 +175,7 @@ const MetricTrendChart: React.FC<Props> = ({
|
||||
series: sortedGroupKeys.slice(0, 20).map((category, index) => {
|
||||
const data = groupData[category];
|
||||
return {
|
||||
type: 'line',
|
||||
type: chartType,
|
||||
name: categoryColumnName ? category : metricField.name,
|
||||
symbol: 'circle',
|
||||
showSymbol: data.length === 1,
|
||||
@@ -197,7 +199,7 @@ const MetricTrendChart: React.FC<Props> = ({
|
||||
if (metricField.authorized) {
|
||||
renderChart();
|
||||
}
|
||||
}, [resultList, metricField]);
|
||||
}, [resultList, metricField, chartType]);
|
||||
|
||||
useEffect(() => {
|
||||
if (triggerResize && instance) {
|
||||
|
||||
@@ -12,6 +12,7 @@ type Props = {
|
||||
metricFields: ColumnType[];
|
||||
resultList: any[];
|
||||
triggerResize?: boolean;
|
||||
chartType?: string;
|
||||
};
|
||||
|
||||
const MultiMetricsTrendChart: React.FC<Props> = ({
|
||||
@@ -19,6 +20,7 @@ const MultiMetricsTrendChart: React.FC<Props> = ({
|
||||
metricFields,
|
||||
resultList,
|
||||
triggerResize,
|
||||
chartType,
|
||||
}) => {
|
||||
const chartRef = useRef<any>();
|
||||
const [instance, setInstance] = useState<ECharts>();
|
||||
@@ -110,7 +112,7 @@ const MultiMetricsTrendChart: React.FC<Props> = ({
|
||||
},
|
||||
series: metricFields.map((metricField, index) => {
|
||||
return {
|
||||
type: 'line',
|
||||
type: chartType,
|
||||
name: metricField.name,
|
||||
symbol: 'circle',
|
||||
showSymbol: resultList.length === 1,
|
||||
@@ -132,7 +134,7 @@ const MultiMetricsTrendChart: React.FC<Props> = ({
|
||||
|
||||
useEffect(() => {
|
||||
renderChart();
|
||||
}, [resultList]);
|
||||
}, [resultList, chartType]);
|
||||
|
||||
useEffect(() => {
|
||||
if (triggerResize && instance) {
|
||||
|
||||
@@ -2,11 +2,23 @@ import { CLS_PREFIX } from '../../../common/constants';
|
||||
import { DrillDownDimensionType, FieldType, MsgDataType } from '../../../common/type';
|
||||
import { isMobile } from '../../../utils/utils';
|
||||
import MetricTrendChart from './MetricTrendChart';
|
||||
import { Spin } from 'antd';
|
||||
import { Spin, Select } from 'antd';
|
||||
import Table from '../Table';
|
||||
import MetricInfo from './MetricInfo';
|
||||
import DateOptions from '../DateOptions';
|
||||
import MultiMetricsTrendChart from './MultiMetricsTrendChart';
|
||||
import { useState } from 'react';
|
||||
|
||||
const metricChartSelectOptions = [
|
||||
{
|
||||
value: 'line',
|
||||
label: '折线图',
|
||||
},
|
||||
{
|
||||
value: 'bar',
|
||||
label: '柱状图',
|
||||
},
|
||||
];
|
||||
|
||||
type Props = {
|
||||
data: MsgDataType;
|
||||
@@ -32,6 +44,7 @@ const MetricTrend: React.FC<Props> = ({
|
||||
onSelectDateOption,
|
||||
}) => {
|
||||
const { queryColumns, queryResults, aggregateInfo, entityInfo, chatContext } = data;
|
||||
const [chartType, setChartType] = useState('line');
|
||||
|
||||
const dateField: any = queryColumns?.find(
|
||||
(column: any) => column.showType === 'DATE' || column.type === 'DATE'
|
||||
@@ -69,11 +82,21 @@ const MetricTrend: React.FC<Props> = ({
|
||||
drillDownDimension === undefined && (
|
||||
<MetricInfo aggregateInfo={aggregateInfo} currentMetricField={currentMetricField} />
|
||||
)}
|
||||
<DateOptions
|
||||
chatContext={chatContext}
|
||||
currentDateOption={currentDateOption}
|
||||
onSelectDateOption={onSelectDateOption}
|
||||
/>
|
||||
<div className={`${prefixCls}-select-options`}>
|
||||
<DateOptions
|
||||
chatContext={chatContext}
|
||||
currentDateOption={currentDateOption}
|
||||
onSelectDateOption={onSelectDateOption}
|
||||
/>
|
||||
<div>
|
||||
<Select
|
||||
defaultValue="line"
|
||||
bordered={false}
|
||||
options={metricChartSelectOptions}
|
||||
onChange={(value: string) => setChartType(value)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{queryResults?.length === 1 || chartIndex % 2 === 1 ? (
|
||||
<Table data={{ ...data, queryResults }} onApplyAuth={onApplyAuth} />
|
||||
) : metricFields.length > 1 ? (
|
||||
@@ -82,6 +105,7 @@ const MetricTrend: React.FC<Props> = ({
|
||||
metricFields={metricFields}
|
||||
resultList={queryResults}
|
||||
triggerResize={triggerResize}
|
||||
chartType={chartType}
|
||||
/>
|
||||
) : (
|
||||
<MetricTrendChart
|
||||
@@ -92,6 +116,7 @@ const MetricTrend: React.FC<Props> = ({
|
||||
resultList={queryResults}
|
||||
triggerResize={triggerResize}
|
||||
onApplyAuth={onApplyAuth}
|
||||
chartType={chartType}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -56,6 +56,11 @@
|
||||
row-gap: 12px;
|
||||
}
|
||||
|
||||
&-select-options {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
&-indicator {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { formatByDecimalPlaces, getFormattedValue, isMobile } from '../../../utils/utils';
|
||||
import { formatByDecimalPlaces, getFormattedValue } from '../../../utils/utils';
|
||||
import { Table as AntTable } from 'antd';
|
||||
import { MsgDataType } from '../../../common/type';
|
||||
import { CLS_PREFIX } from '../../../common/constants';
|
||||
@@ -9,10 +9,11 @@ import moment from 'moment';
|
||||
type Props = {
|
||||
data: MsgDataType;
|
||||
size?: SizeType;
|
||||
loading?: boolean;
|
||||
onApplyAuth?: (model: string) => void;
|
||||
};
|
||||
|
||||
const Table: React.FC<Props> = ({ data, size, onApplyAuth }) => {
|
||||
const Table: React.FC<Props> = ({ data, size, loading, onApplyAuth }) => {
|
||||
const { entityInfo, queryColumns, queryResults } = data;
|
||||
|
||||
const prefixCls = `${CLS_PREFIX}-table`;
|
||||
@@ -70,19 +71,14 @@ const Table: React.FC<Props> = ({ data, size, onApplyAuth }) => {
|
||||
<div className={prefixCls}>
|
||||
<AntTable
|
||||
pagination={
|
||||
queryResults.length <= 10
|
||||
? false
|
||||
: {
|
||||
defaultPageSize: 10,
|
||||
position: ['bottomCenter'],
|
||||
size: isMobile ? 'small' : 'default',
|
||||
}
|
||||
queryResults.length <= 10 ? false : { defaultPageSize: 10, position: ['bottomCenter'] }
|
||||
}
|
||||
columns={tableColumns}
|
||||
dataSource={dataSource}
|
||||
style={{ width: '100%', overflowX: 'auto', overflowY: 'hidden' }}
|
||||
rowClassName={getRowClassName}
|
||||
size={size}
|
||||
loading={loading}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -27,6 +27,8 @@ const ChatMsg: React.FC<Props> = ({ queryId, data, chartIndex, triggerResize })
|
||||
const [referenceColumn, setReferenceColumn] = useState<ColumnType>();
|
||||
const [dataSource, setDataSource] = useState<any[]>(queryResults);
|
||||
const [drillDownDimension, setDrillDownDimension] = useState<DrillDownDimensionType>();
|
||||
const [secondDrillDownDimension, setSecondDrillDownDimension] =
|
||||
useState<DrillDownDimensionType>();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [defaultMetricField, setDefaultMetricField] = useState<FieldType>();
|
||||
const [activeMetricField, setActiveMetricField] = useState<FieldType>();
|
||||
@@ -48,6 +50,8 @@ const ChatMsg: React.FC<Props> = ({ queryId, data, chartIndex, triggerResize })
|
||||
setActiveMetricField(chatContext?.metrics?.[0]);
|
||||
setDateModeValue(chatContext?.dateInfo?.dateMode);
|
||||
setCurrentDateOption(chatContext?.dateInfo?.unit);
|
||||
setDrillDownDimension(undefined);
|
||||
setSecondDrillDownDimension(undefined);
|
||||
}, [data]);
|
||||
|
||||
if (!queryColumns || !queryResults || !columns) {
|
||||
@@ -75,7 +79,7 @@ const ChatMsg: React.FC<Props> = ({ queryId, data, chartIndex, triggerResize })
|
||||
!isText &&
|
||||
!isMetricCard &&
|
||||
(categoryField.length > 1 ||
|
||||
queryMode === 'ENTITY_DETAIL' ||
|
||||
queryMode === 'TAG_DETAIL' ||
|
||||
queryMode === 'ENTITY_DIMENSION' ||
|
||||
(categoryField.length === 1 && metricFields.length === 0));
|
||||
|
||||
@@ -92,7 +96,12 @@ const ChatMsg: React.FC<Props> = ({ queryId, data, chartIndex, triggerResize })
|
||||
);
|
||||
}
|
||||
if (isTable) {
|
||||
return <Table data={{ ...data, queryColumns: columns, queryResults: dataSource }} />;
|
||||
return (
|
||||
<Table
|
||||
data={{ ...data, queryColumns: columns, queryResults: dataSource }}
|
||||
loading={loading}
|
||||
/>
|
||||
);
|
||||
}
|
||||
if (
|
||||
dateField &&
|
||||
@@ -129,15 +138,21 @@ const ChatMsg: React.FC<Props> = ({ queryId, data, chartIndex, triggerResize })
|
||||
/>
|
||||
);
|
||||
}
|
||||
return <Table data={{ ...data, queryColumns: columns, queryResults: dataSource }} />;
|
||||
return (
|
||||
<Table
|
||||
data={{ ...data, queryColumns: columns, queryResults: dataSource }}
|
||||
loading={loading}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const onLoadData = async (value: any) => {
|
||||
const onLoadData = async (value: any, extraFilter?: any) => {
|
||||
setLoading(true);
|
||||
const res: any = await queryData({
|
||||
...chatContext,
|
||||
...value,
|
||||
queryId,
|
||||
parseId: chatContext.id,
|
||||
...value,
|
||||
});
|
||||
setLoading(false);
|
||||
if (res.code === 200) {
|
||||
@@ -146,7 +161,8 @@ const ChatMsg: React.FC<Props> = ({ queryId, data, chartIndex, triggerResize })
|
||||
}
|
||||
};
|
||||
|
||||
const onSelectDimension = (dimension?: DrillDownDimensionType) => {
|
||||
const onSelectDimension = async (dimension?: DrillDownDimensionType) => {
|
||||
setLoading(true);
|
||||
setDrillDownDimension(dimension);
|
||||
onLoadData({
|
||||
dateInfo: {
|
||||
@@ -161,6 +177,23 @@ const ChatMsg: React.FC<Props> = ({ queryId, data, chartIndex, triggerResize })
|
||||
});
|
||||
};
|
||||
|
||||
const onSelectSecondDimension = (dimension?: DrillDownDimensionType) => {
|
||||
setSecondDrillDownDimension(dimension);
|
||||
onLoadData({
|
||||
dateInfo: {
|
||||
...chatContext.dateInfo,
|
||||
dateMode: dateModeValue,
|
||||
unit: currentDateOption || chatContext.dateInfo.unit,
|
||||
},
|
||||
dimensions: [
|
||||
...(chatContext.dimensions || []),
|
||||
...(drillDownDimension ? [drillDownDimension] : []),
|
||||
...(dimension ? [dimension] : []),
|
||||
],
|
||||
metrics: [activeMetricField || defaultMetricField],
|
||||
});
|
||||
};
|
||||
|
||||
const onSwitchMetric = (metricField?: FieldType) => {
|
||||
setActiveMetricField(metricField);
|
||||
onLoadData({
|
||||
@@ -199,7 +232,7 @@ const ChatMsg: React.FC<Props> = ({ queryId, data, chartIndex, triggerResize })
|
||||
?.name;
|
||||
|
||||
const isEntityMode =
|
||||
(queryMode === 'ENTITY_LIST_FILTER' || queryMode === 'METRIC_ENTITY') &&
|
||||
(queryMode === 'TAG_LIST_FILTER' || queryMode === 'METRIC_TAG') &&
|
||||
typeof entityId === 'string' &&
|
||||
entityName !== undefined;
|
||||
|
||||
@@ -225,12 +258,11 @@ const ChatMsg: React.FC<Props> = ({ queryId, data, chartIndex, triggerResize })
|
||||
<div
|
||||
className={`${prefixCls}-bottom-tools ${
|
||||
isMetricCard ? `${prefixCls}-metric-card-tools` : ''
|
||||
}`}
|
||||
} ${isMobile ? 'mobile' : ''}`}
|
||||
>
|
||||
{isMultipleMetric && (
|
||||
<MetricOptions
|
||||
// metrics={chatContext.metrics}
|
||||
metrics={recommendMetrics}
|
||||
metrics={chatContext.metrics}
|
||||
defaultMetric={defaultMetricField}
|
||||
currentMetric={activeMetricField}
|
||||
onSelectMetric={onSwitchMetric}
|
||||
@@ -241,9 +273,11 @@ const ChatMsg: React.FC<Props> = ({ queryId, data, chartIndex, triggerResize })
|
||||
modelId={chatContext.modelId}
|
||||
metricId={activeMetricField?.id || defaultMetricField?.id}
|
||||
drillDownDimension={drillDownDimension}
|
||||
secondDrillDownDimension={secondDrillDownDimension}
|
||||
originDimensions={chatContext.dimensions}
|
||||
dimensionFilters={chatContext.dimensionFilters}
|
||||
onSelectDimension={onSelectDimension}
|
||||
onSelectSecondDimension={onSelectSecondDimension}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -15,9 +15,13 @@
|
||||
font-size: 14px;
|
||||
margin-top: 12px;
|
||||
margin-bottom: 2px;
|
||||
|
||||
&.mobile {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
}
|
||||
|
||||
&-metric-card-tools {
|
||||
margin-top: 2px;
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user