mirror of
https://github.com/tencentmusic/supersonic.git
synced 2025-12-14 22:25:19 +00:00
[feature](webapp) upgrade chat version
This commit is contained in:
@@ -8,10 +8,11 @@ import NoPermissionChart from '../NoPermissionChart';
|
||||
|
||||
type Props = {
|
||||
data: MsgDataType;
|
||||
triggerResize?: boolean;
|
||||
onApplyAuth?: (domain: string) => void;
|
||||
};
|
||||
|
||||
const BarChart: React.FC<Props> = ({ data, onApplyAuth }) => {
|
||||
const BarChart: React.FC<Props> = ({ data, triggerResize, onApplyAuth }) => {
|
||||
const chartRef = useRef<any>();
|
||||
const [instance, setInstance] = useState<ECharts>();
|
||||
|
||||
@@ -133,7 +134,13 @@ const BarChart: React.FC<Props> = ({ data, onApplyAuth }) => {
|
||||
}
|
||||
}, [queryResults]);
|
||||
|
||||
if (!metricColumn?.authorized) {
|
||||
useEffect(() => {
|
||||
if (triggerResize && instance) {
|
||||
instance.resize();
|
||||
}
|
||||
}, [triggerResize]);
|
||||
|
||||
if (metricColumn && !metricColumn?.authorized) {
|
||||
return (
|
||||
<NoPermissionChart
|
||||
domain={entityInfo?.domainInfo.name || ''}
|
||||
|
||||
@@ -1,67 +1,55 @@
|
||||
import { EntityInfoType, ChatContextType } from '../../../common/type';
|
||||
import moment from 'moment';
|
||||
import { PREFIX_CLS } from '../../../common/constants';
|
||||
|
||||
type Props = {
|
||||
position: 'left' | 'right';
|
||||
width?: number | string;
|
||||
height?: number | string;
|
||||
title?: string;
|
||||
followQuestions?: string[];
|
||||
bubbleClassName?: string;
|
||||
noWaterMark?: boolean;
|
||||
chatContext?: ChatContextType;
|
||||
entityInfo?: EntityInfoType;
|
||||
tip?: string;
|
||||
aggregator?: string;
|
||||
noTime?: boolean;
|
||||
children?: React.ReactNode;
|
||||
isMobileMode?: boolean;
|
||||
};
|
||||
|
||||
const Message: React.FC<Props> = ({
|
||||
position,
|
||||
width,
|
||||
height,
|
||||
title,
|
||||
followQuestions,
|
||||
children,
|
||||
bubbleClassName,
|
||||
chatContext,
|
||||
entityInfo,
|
||||
aggregator,
|
||||
noTime,
|
||||
isMobileMode,
|
||||
}) => {
|
||||
const { aggType, dateInfo, filters, metrics, domainName } = chatContext || {};
|
||||
const { dimensionFilters, domainName } = chatContext || {};
|
||||
|
||||
const prefixCls = `${PREFIX_CLS}-message`;
|
||||
|
||||
const timeSection =
|
||||
!noTime && dateInfo?.text ? (
|
||||
dateInfo.text
|
||||
) : (
|
||||
<div>{`近${moment(dateInfo?.endDate).diff(dateInfo?.startDate, 'days') + 1}天`}</div>
|
||||
);
|
||||
const entityInfoList =
|
||||
entityInfo?.dimensions?.filter(dimension => !dimension.bizName.includes('photo')) || [];
|
||||
|
||||
const metricSection =
|
||||
metrics &&
|
||||
metrics.map((metric, index) => {
|
||||
let metricNode = <span className={`${PREFIX_CLS}-metric`}>{metric.name}</span>;
|
||||
return (
|
||||
<>
|
||||
{metricNode}
|
||||
{index < metrics.length - 1 && <span>、</span>}
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
const aggregatorSection = aggregator !== 'tag' && aggType !== 'NONE' && aggType;
|
||||
|
||||
const hasFilterSection = filters && filters.length > 0;
|
||||
const hasFilterSection =
|
||||
dimensionFilters && dimensionFilters.length > 0 && entityInfoList.length === 0;
|
||||
|
||||
const filterSection = hasFilterSection && (
|
||||
<div className={`${prefixCls}-filter-section`}>
|
||||
<div className={`${prefixCls}-field-name`}>筛选条件:</div>
|
||||
<div className={`${prefixCls}-filter-values`}>
|
||||
{filters.map(filterItem => {
|
||||
{dimensionFilters.map(filterItem => {
|
||||
const filterValue =
|
||||
typeof filterItem.value === 'string' ? [filterItem.value] : filterItem.value || [];
|
||||
return (
|
||||
<div className={`${prefixCls}-filter-item`} key={filterItem.name}>
|
||||
{filterItem.name}:{filterItem.value}
|
||||
<div
|
||||
className={`${prefixCls}-filter-item`}
|
||||
key={filterItem.name}
|
||||
title={filterValue.join('、')}
|
||||
>
|
||||
{filterItem.name}:{filterValue.join('、')}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
@@ -69,14 +57,15 @@ const Message: React.FC<Props> = ({
|
||||
</div>
|
||||
);
|
||||
|
||||
const entityInfoList =
|
||||
entityInfo?.dimensions?.filter(dimension => !dimension.bizName.includes('photo')) || [];
|
||||
|
||||
const hasEntityInfoSection =
|
||||
entityInfoList.length > 0 && chatContext && chatContext.dimensions?.length > 0;
|
||||
const leftTitle = title
|
||||
? followQuestions && followQuestions.length > 0
|
||||
? `多轮对话:${[title, ...followQuestions].join(' ← ')}`
|
||||
: `单轮对话:${title}`
|
||||
: '';
|
||||
|
||||
return (
|
||||
<div className={prefixCls}>
|
||||
{domainName && <div className={`${prefixCls}-domain-name`}>{domainName}</div>}
|
||||
<div className={`${prefixCls}-content`}>
|
||||
<div className={`${prefixCls}-body`}>
|
||||
<div
|
||||
@@ -86,31 +75,30 @@ const Message: React.FC<Props> = ({
|
||||
e.stopPropagation();
|
||||
}}
|
||||
>
|
||||
{position === 'left' && chatContext && (
|
||||
<div className={`${prefixCls}-top-bar`}>
|
||||
{domainName}
|
||||
{/* {dimensionSection} */}
|
||||
{timeSection}
|
||||
{metricSection}
|
||||
{aggregatorSection}
|
||||
{/* {tipSection} */}
|
||||
{position === 'left' && title && (
|
||||
<div className={`${prefixCls}-top-bar`} title={leftTitle}>
|
||||
{leftTitle}
|
||||
</div>
|
||||
)}
|
||||
{(hasEntityInfoSection || hasFilterSection) && (
|
||||
{(entityInfoList.length > 0 || hasFilterSection) && (
|
||||
<div className={`${prefixCls}-info-bar`}>
|
||||
{hasEntityInfoSection && (
|
||||
{filterSection}
|
||||
{entityInfoList.length > 0 && (
|
||||
<div className={`${prefixCls}-main-entity-info`}>
|
||||
{entityInfoList.slice(0, 3).map(dimension => {
|
||||
{entityInfoList.slice(0, 4).map(dimension => {
|
||||
return (
|
||||
<div className={`${prefixCls}-info-item`} key={dimension.bizName}>
|
||||
<div className={`${prefixCls}-info-name`}>{dimension.name}:</div>
|
||||
<div className={`${prefixCls}-info-value`}>{dimension.value}</div>
|
||||
{dimension.bizName.includes('photo') ? (
|
||||
<img width={40} height={40} src={dimension.value} alt="" />
|
||||
) : (
|
||||
<div className={`${prefixCls}-info-value`}>{dimension.value}</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
{filterSection}
|
||||
</div>
|
||||
)}
|
||||
<div className={`${prefixCls}-children`}>{children}</div>
|
||||
|
||||
@@ -3,6 +3,13 @@
|
||||
@msg-prefix-cls: ~'@{supersonic-chat-prefix}-message';
|
||||
|
||||
.@{msg-prefix-cls} {
|
||||
&-domain-name {
|
||||
color: var(--text-color);
|
||||
margin-bottom: 2px;
|
||||
margin-left: 4px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
&-content {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
@@ -24,15 +31,14 @@
|
||||
}
|
||||
|
||||
&-top-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
max-width: 100%;
|
||||
padding: 4px 0 8px;
|
||||
overflow-x: auto;
|
||||
color: var(--text-color);
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
color: var(--text-color-third);
|
||||
font-size: 13px;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.03);
|
||||
}
|
||||
|
||||
@@ -44,11 +50,21 @@
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
&-filter-values {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
column-gap: 6px;
|
||||
}
|
||||
|
||||
&-filter-item {
|
||||
padding: 2px 12px;
|
||||
color: var(--text-color-secondary);
|
||||
background-color: #edf2f2;
|
||||
border-radius: 13px;
|
||||
max-width: 200px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&-tip {
|
||||
@@ -58,10 +74,16 @@
|
||||
|
||||
&-info-bar {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
row-gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 20px;
|
||||
column-gap: 20px;
|
||||
color: var(--text-color-secondary);
|
||||
background: rgba(133, 156, 241, 0.1);
|
||||
padding: 4px 12px;
|
||||
width: fit-content;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
&-main-entity-info {
|
||||
@@ -70,6 +92,7 @@
|
||||
align-items: center;
|
||||
font-size: 13px;
|
||||
column-gap: 20px;
|
||||
row-gap: 10px;
|
||||
}
|
||||
|
||||
&-info-item {
|
||||
@@ -77,12 +100,12 @@
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&-info-Name {
|
||||
color: var(--text-color-fourth);
|
||||
&-info-name {
|
||||
color: var(--text-color-third);
|
||||
}
|
||||
|
||||
&-info-value {
|
||||
color: var(--text-color-secondary);
|
||||
color: var(--text-color);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ const MetricCard: React.FC<Props> = ({ data, onApplyAuth }) => {
|
||||
{/* <div className={`${prefixCls}-date-range`}>
|
||||
{startTime === endTime ? startTime : `${startTime} ~ ${endTime}`}
|
||||
</div> */}
|
||||
{!indicatorColumn?.authorized ? (
|
||||
{indicatorColumn && !indicatorColumn?.authorized ? (
|
||||
<ApplyAuth domain={entityInfo?.domainInfo.name || ''} onApplyAuth={onApplyAuth} />
|
||||
) : (
|
||||
<div className={`${prefixCls}-indicator-value`}>
|
||||
|
||||
@@ -19,6 +19,7 @@ type Props = {
|
||||
categoryColumnName: string;
|
||||
metricField: ColumnType;
|
||||
resultList: any[];
|
||||
triggerResize?: boolean;
|
||||
onApplyAuth?: (domain: string) => void;
|
||||
};
|
||||
|
||||
@@ -28,6 +29,7 @@ const MetricTrendChart: React.FC<Props> = ({
|
||||
categoryColumnName,
|
||||
metricField,
|
||||
resultList,
|
||||
triggerResize,
|
||||
onApplyAuth,
|
||||
}) => {
|
||||
const chartRef = useRef<any>();
|
||||
@@ -40,6 +42,7 @@ const MetricTrendChart: React.FC<Props> = ({
|
||||
setInstance(instanceObj);
|
||||
} else {
|
||||
instanceObj = instance;
|
||||
instanceObj.clear();
|
||||
}
|
||||
|
||||
const valueColumnName = metricField.nameEn;
|
||||
@@ -51,13 +54,13 @@ const MetricTrendChart: React.FC<Props> = ({
|
||||
endDate &&
|
||||
(dateColumnName.includes('date') || dateColumnName.includes('month'))
|
||||
? normalizeTrendData(
|
||||
groupDataValue[key],
|
||||
dateColumnName,
|
||||
valueColumnName,
|
||||
startDate,
|
||||
endDate,
|
||||
dateColumnName.includes('month') ? 'months' : 'days'
|
||||
)
|
||||
groupDataValue[key],
|
||||
dateColumnName,
|
||||
valueColumnName,
|
||||
startDate,
|
||||
endDate,
|
||||
dateColumnName.includes('month') ? 'months' : 'days'
|
||||
)
|
||||
: groupDataValue[key].reverse();
|
||||
return result;
|
||||
}, {});
|
||||
@@ -114,8 +117,8 @@ const MetricTrendChart: React.FC<Props> = ({
|
||||
return value === 0
|
||||
? 0
|
||||
: metricField.dataFormatType === 'percent'
|
||||
? `${formatByDecimalPlaces(value, metricField.dataFormat?.decimalPlaces || 2)}%`
|
||||
: getFormattedValue(value);
|
||||
? `${formatByDecimalPlaces(value, metricField.dataFormat?.decimalPlaces || 2)}%`
|
||||
: getFormattedValue(value);
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -135,11 +138,11 @@ const MetricTrendChart: React.FC<Props> = ({
|
||||
item.value === ''
|
||||
? '-'
|
||||
: metricField.dataFormatType === 'percent'
|
||||
? `${formatByDecimalPlaces(
|
||||
? `${formatByDecimalPlaces(
|
||||
item.value,
|
||||
metricField.dataFormat?.decimalPlaces || 2
|
||||
)}%`
|
||||
: getFormattedValue(item.value)
|
||||
: getFormattedValue(item.value)
|
||||
}</span></div>`
|
||||
)
|
||||
.join('');
|
||||
@@ -181,6 +184,12 @@ const MetricTrendChart: React.FC<Props> = ({
|
||||
}
|
||||
}, [resultList, metricField]);
|
||||
|
||||
useEffect(() => {
|
||||
if (triggerResize && instance) {
|
||||
instance.resize();
|
||||
}
|
||||
}, [triggerResize]);
|
||||
|
||||
const prefixCls = `${CLS_PREFIX}-metric-trend`;
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,30 +1,27 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { CLS_PREFIX, DATE_TYPES } from '../../../common/constants';
|
||||
import { ColumnType, MsgDataType } from '../../../common/type';
|
||||
import { groupByColumn, isMobile } from '../../../utils/utils';
|
||||
import { ColumnType, FieldType, MsgDataType } from '../../../common/type';
|
||||
import { isMobile } from '../../../utils/utils';
|
||||
import { queryData } from '../../../service';
|
||||
import MetricTrendChart from './MetricTrendChart';
|
||||
import classNames from 'classnames';
|
||||
import { Spin } from 'antd';
|
||||
import Table from '../Table';
|
||||
import SemanticInfoPopover from '../SemanticInfoPopover';
|
||||
|
||||
type Props = {
|
||||
data: MsgDataType;
|
||||
triggerResize?: boolean;
|
||||
onApplyAuth?: (domain: string) => void;
|
||||
onCheckMetricInfo?: (data: any) => void;
|
||||
};
|
||||
|
||||
const MetricTrend: React.FC<Props> = ({ data, onApplyAuth, onCheckMetricInfo }) => {
|
||||
const MetricTrend: React.FC<Props> = ({ data, triggerResize, onApplyAuth, onCheckMetricInfo }) => {
|
||||
const { queryColumns, queryResults, entityInfo, chatContext } = data;
|
||||
const [columns, setColumns] = useState<ColumnType[]>(queryColumns);
|
||||
const metricFields = columns.filter((column: any) => column.showType === 'NUMBER') || [];
|
||||
const currentMetricField = columns.find((column: any) => column.showType === 'NUMBER');
|
||||
|
||||
const [currentMetricField, setCurrentMetricField] = useState<ColumnType>(metricFields[0]);
|
||||
const [onlyOneDate, setOnlyOneDate] = useState(false);
|
||||
const [trendData, setTrendData] = useState(data);
|
||||
const [activeMetricField, setActiveMetricField] = useState<FieldType>(chatContext.metrics?.[0]);
|
||||
const [dataSource, setDataSource] = useState<any[]>(queryResults);
|
||||
const [mergeMetric, setMergeMetric] = useState(false);
|
||||
const [currentDateOption, setCurrentDateOption] = useState<number>();
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
@@ -35,66 +32,17 @@ const MetricTrend: React.FC<Props> = ({ data, onApplyAuth, onCheckMetricInfo })
|
||||
const categoryColumnName =
|
||||
columns.find((column: any) => column.showType === 'CATEGORY')?.nameEn || '';
|
||||
|
||||
const getColumns = () => {
|
||||
const categoryFieldData = groupByColumn(dataSource, categoryColumnName);
|
||||
const result = [dateField];
|
||||
const columnsValue = Object.keys(categoryFieldData).map(item => ({
|
||||
authorized: currentMetricField.authorized,
|
||||
name: item !== 'undefined' ? item : currentMetricField.name,
|
||||
nameEn: `${item}${currentMetricField.name}`,
|
||||
showType: 'NUMBER',
|
||||
type: 'NUMBER',
|
||||
}));
|
||||
return result.concat(columnsValue);
|
||||
};
|
||||
|
||||
const getResultList = () => {
|
||||
return [
|
||||
{
|
||||
[dateField.nameEn]: dataSource[0][dateField.nameEn],
|
||||
...dataSource.reduce((result, item) => {
|
||||
result[`${item[categoryColumnName]}${currentMetricField.name}`] =
|
||||
item[currentMetricField.nameEn];
|
||||
return result;
|
||||
}, {}),
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setDataSource(queryResults);
|
||||
}, [queryResults]);
|
||||
|
||||
useEffect(() => {
|
||||
let onlyOneDateValue = false;
|
||||
let dataValue = trendData;
|
||||
if (dateColumnName && dataSource.length > 0) {
|
||||
const dateFieldData = groupByColumn(dataSource, dateColumnName);
|
||||
onlyOneDateValue =
|
||||
Object.keys(dateFieldData).length === 1 && Object.keys(dateFieldData)[0] !== undefined;
|
||||
if (onlyOneDateValue) {
|
||||
if (categoryColumnName !== '') {
|
||||
dataValue = {
|
||||
...trendData,
|
||||
queryColumns: getColumns(),
|
||||
queryResults: getResultList(),
|
||||
};
|
||||
} else {
|
||||
setMergeMetric(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
setOnlyOneDate(onlyOneDateValue);
|
||||
setTrendData(dataValue);
|
||||
}, [currentMetricField]);
|
||||
const dateOptions = DATE_TYPES[chatContext?.dateInfo?.period] || DATE_TYPES[0];
|
||||
|
||||
const dateOptions = DATE_TYPES[chatContext.dateInfo?.period] || DATE_TYPES[0];
|
||||
|
||||
const onLoadData = async (value: number) => {
|
||||
const onLoadData = async (value: any) => {
|
||||
setLoading(true);
|
||||
const { data } = await queryData({
|
||||
...chatContext,
|
||||
dateInfo: { ...chatContext.dateInfo, unit: value },
|
||||
...value,
|
||||
});
|
||||
setLoading(false);
|
||||
if (data.code === 200) {
|
||||
@@ -105,20 +53,21 @@ const MetricTrend: React.FC<Props> = ({ data, onApplyAuth, onCheckMetricInfo })
|
||||
|
||||
const selectDateOption = (dateOption: number) => {
|
||||
setCurrentDateOption(dateOption);
|
||||
// const { domainName, dimensions, metrics, aggType, filters } = chatContext || {};
|
||||
// const dimensionSection = dimensions?.join('、') || '';
|
||||
// const metricSection = metrics?.join('、') || '';
|
||||
// const aggregatorSection = aggType || '';
|
||||
// const filterSection = filters
|
||||
// .reduce((result, dimensionName) => {
|
||||
// result = result.concat(dimensionName);
|
||||
// return result;
|
||||
// }, [])
|
||||
// .join('、');
|
||||
onLoadData(dateOption);
|
||||
onLoadData({
|
||||
metrics: [activeMetricField],
|
||||
dateInfo: { ...chatContext?.dateInfo, unit: dateOption },
|
||||
});
|
||||
};
|
||||
|
||||
if (metricFields.length === 0) {
|
||||
const onSwitchMetric = (metricField: FieldType) => {
|
||||
setActiveMetricField(metricField);
|
||||
onLoadData({
|
||||
dateInfo: { ...chatContext.dateInfo, unit: currentDateOption || chatContext.dateInfo.unit },
|
||||
metrics: [metricField],
|
||||
});
|
||||
};
|
||||
|
||||
if (!currentMetricField) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -127,64 +76,66 @@ const MetricTrend: React.FC<Props> = ({ data, onApplyAuth, onCheckMetricInfo })
|
||||
return (
|
||||
<div className={prefixCls}>
|
||||
<div className={`${prefixCls}-charts`}>
|
||||
{!onlyOneDate && (
|
||||
<div className={`${prefixCls}-date-options`}>
|
||||
{dateOptions.map((dateOption: { label: string; value: number }, index: number) => {
|
||||
const dateOptionClass = classNames(`${prefixCls}-date-option`, {
|
||||
[`${prefixCls}-date-active`]: dateOption.value === currentDateOption,
|
||||
[`${prefixCls}-date-mobile`]: isMobile,
|
||||
});
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
key={dateOption.value}
|
||||
className={dateOptionClass}
|
||||
onClick={() => {
|
||||
selectDateOption(dateOption.value);
|
||||
}}
|
||||
>
|
||||
{dateOption.label}
|
||||
{dateOption.value === currentDateOption && (
|
||||
<div className={`${prefixCls}-active-identifier`} />
|
||||
)}
|
||||
</div>
|
||||
{index !== dateOptions.length - 1 && (
|
||||
<div className={`${prefixCls}-date-option-divider`} />
|
||||
<div className={`${prefixCls}-date-options`}>
|
||||
{dateOptions.map((dateOption: { label: string; value: number }, index: number) => {
|
||||
const dateOptionClass = classNames(`${prefixCls}-date-option`, {
|
||||
[`${prefixCls}-date-active`]: dateOption.value === currentDateOption,
|
||||
[`${prefixCls}-date-mobile`]: isMobile,
|
||||
});
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
key={dateOption.value}
|
||||
className={dateOptionClass}
|
||||
onClick={() => {
|
||||
selectDateOption(dateOption.value);
|
||||
}}
|
||||
>
|
||||
{dateOption.label}
|
||||
{dateOption.value === currentDateOption && (
|
||||
<div className={`${prefixCls}-active-identifier`} />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
{metricFields.length > 1 && !mergeMetric && (
|
||||
</div>
|
||||
{index !== dateOptions.length - 1 && (
|
||||
<div className={`${prefixCls}-date-option-divider`} />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
{chatContext.metrics.length > 0 && (
|
||||
<div className={`${prefixCls}-metric-fields`}>
|
||||
{metricFields.map((metricField: ColumnType) => {
|
||||
{chatContext.metrics.map((metricField: FieldType) => {
|
||||
const metricFieldClass = classNames(`${prefixCls}-metric-field`, {
|
||||
[`${prefixCls}-metric-field-active`]:
|
||||
currentMetricField?.nameEn === metricField.nameEn,
|
||||
activeMetricField?.bizName === metricField.bizName &&
|
||||
chatContext.metrics.length > 1,
|
||||
[`${prefixCls}-metric-field-single`]: chatContext.metrics.length === 1,
|
||||
});
|
||||
return (
|
||||
<div
|
||||
className={metricFieldClass}
|
||||
key={metricField.nameEn}
|
||||
key={metricField.bizName}
|
||||
onClick={() => {
|
||||
setCurrentMetricField(metricField);
|
||||
if (chatContext.metrics.length > 1) {
|
||||
onSwitchMetric(metricField);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<SemanticInfoPopover
|
||||
{/* <SemanticInfoPopover
|
||||
classId={chatContext.domainId}
|
||||
uniqueId={metricField.nameEn}
|
||||
uniqueId={metricField.bizName}
|
||||
onDetailBtnClick={onCheckMetricInfo}
|
||||
>
|
||||
{metricField.name}
|
||||
</SemanticInfoPopover>
|
||||
> */}
|
||||
{metricField.name}
|
||||
{/* </SemanticInfoPopover> */}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
{onlyOneDate ? (
|
||||
<Table data={trendData} onApplyAuth={onApplyAuth} />
|
||||
{dataSource?.length === 1 ? (
|
||||
<Table data={data} onApplyAuth={onApplyAuth} />
|
||||
) : (
|
||||
<Spin spinning={loading}>
|
||||
<MetricTrendChart
|
||||
@@ -193,6 +144,7 @@ const MetricTrend: React.FC<Props> = ({ data, onApplyAuth, onCheckMetricInfo })
|
||||
categoryColumnName={categoryColumnName}
|
||||
metricField={currentMetricField}
|
||||
resultList={dataSource}
|
||||
triggerResize={triggerResize}
|
||||
onApplyAuth={onApplyAuth}
|
||||
/>
|
||||
</Spin>
|
||||
|
||||
@@ -81,6 +81,17 @@
|
||||
background-color: var(--chat-blue);
|
||||
}
|
||||
|
||||
&-metric-field-single {
|
||||
padding-left: 0;
|
||||
font-weight: 500;
|
||||
cursor: default;
|
||||
color: var(--text-color-secondary);
|
||||
|
||||
&:hover {
|
||||
color: var(--text-color-secondary);
|
||||
}
|
||||
}
|
||||
|
||||
&-date-options {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -56,14 +56,21 @@ const Table: React.FC<Props> = ({ data, onApplyAuth }) => {
|
||||
}
|
||||
);
|
||||
|
||||
const getRowClassName = (_: any, index: number) => {
|
||||
return index % 2 !== 0 ? `${prefixCls}-even-row` : '';
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={prefixCls}>
|
||||
<AntTable
|
||||
pagination={queryResults.length <= 10 ? false : undefined}
|
||||
size={queryResults.length === 1 ? 'middle' : 'small'}
|
||||
pagination={
|
||||
queryResults.length <= 10 ? false : { defaultPageSize: 10, position: ['bottomCenter'] }
|
||||
}
|
||||
columns={tableColumns}
|
||||
dataSource={queryResults}
|
||||
style={{ width: '100%' }}
|
||||
scroll={{ x: 'max-content' }}
|
||||
rowClassName={getRowClassName}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -16,6 +16,10 @@
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&-even-row {
|
||||
background-color: #fbfbfb;
|
||||
}
|
||||
|
||||
.ant-table-container table > thead > tr:first-child th:first-child {
|
||||
border-top-left-radius: 12px !important;
|
||||
border-bottom-left-radius: 12px !important;
|
||||
|
||||
@@ -7,12 +7,23 @@ import Table from './Table';
|
||||
import { MsgDataType } from '../../common/type';
|
||||
|
||||
type Props = {
|
||||
question: string;
|
||||
followQuestions?: string[];
|
||||
data: MsgDataType;
|
||||
isMobileMode?: boolean;
|
||||
triggerResize?: boolean;
|
||||
onCheckMetricInfo?: (data: any) => void;
|
||||
};
|
||||
|
||||
const ChatMsg: React.FC<Props> = ({ data, onCheckMetricInfo }) => {
|
||||
const { aggregateType, queryColumns, queryResults, chatContext, entityInfo } = data;
|
||||
const ChatMsg: React.FC<Props> = ({
|
||||
question,
|
||||
followQuestions,
|
||||
data,
|
||||
isMobileMode,
|
||||
triggerResize,
|
||||
onCheckMetricInfo,
|
||||
}) => {
|
||||
const { queryColumns, queryResults, chatContext, entityInfo, queryMode } = data;
|
||||
|
||||
if (!queryColumns || !queryResults) {
|
||||
return null;
|
||||
@@ -24,20 +35,30 @@ const ChatMsg: React.FC<Props> = ({ data, onCheckMetricInfo }) => {
|
||||
const metricFields = queryColumns.filter(item => item.showType === 'NUMBER');
|
||||
|
||||
const getMsgContent = () => {
|
||||
if (categoryField.length > 1 || aggregateType === 'tag') {
|
||||
if (
|
||||
categoryField.length > 1 ||
|
||||
queryMode === 'ENTITY_DETAIL' ||
|
||||
queryMode === 'ENTITY_DIMENSION'
|
||||
) {
|
||||
return <Table data={data} />;
|
||||
}
|
||||
if (dateField && metricFields.length > 0) {
|
||||
return <MetricTrend data={data} onCheckMetricInfo={onCheckMetricInfo} />;
|
||||
return (
|
||||
<MetricTrend
|
||||
data={data}
|
||||
triggerResize={triggerResize}
|
||||
onCheckMetricInfo={onCheckMetricInfo}
|
||||
/>
|
||||
);
|
||||
}
|
||||
if (singleData) {
|
||||
return <MetricCard data={data} />;
|
||||
}
|
||||
return <Bar data={data} />;
|
||||
return <Bar data={data} triggerResize={triggerResize} />;
|
||||
};
|
||||
|
||||
let width = '100%';
|
||||
if ((categoryField.length > 1 || aggregateType === 'tag') && !isMobile) {
|
||||
if (categoryField.length > 1 && !isMobile && !isMobileMode) {
|
||||
if (queryColumns.length === 1) {
|
||||
width = '600px';
|
||||
} else if (queryColumns.length === 2) {
|
||||
@@ -50,8 +71,9 @@ const ChatMsg: React.FC<Props> = ({ data, onCheckMetricInfo }) => {
|
||||
position="left"
|
||||
chatContext={chatContext}
|
||||
entityInfo={entityInfo}
|
||||
aggregator={aggregateType}
|
||||
tip={''}
|
||||
title={question}
|
||||
followQuestions={followQuestions}
|
||||
isMobileMode={isMobileMode}
|
||||
width={width}
|
||||
>
|
||||
{getMsgContent()}
|
||||
|
||||
Reference in New Issue
Block a user