mirror of
https://github.com/tencentmusic/supersonic.git
synced 2025-12-10 11:07:06 +00:00
[improvement](webapp) optimize drill down dimensions (#84)
This commit is contained in:
@@ -42,7 +42,7 @@ export const THEME_COLOR_LIST = [
|
|||||||
|
|
||||||
export const PARSE_ERROR_TIP = '智能助理不太懂您说什么呐,回去一定补充知识';
|
export const PARSE_ERROR_TIP = '智能助理不太懂您说什么呐,回去一定补充知识';
|
||||||
|
|
||||||
export const SEARCH_EXCEPTION_TIP = '查询出错啦,智能助理还不够聪明,请您换个表达再试试';
|
export const SEARCH_EXCEPTION_TIP = '查询出错啦,数据库可能出现异常或者负载繁忙,请联系管理员或者稍后重试';
|
||||||
|
|
||||||
export const MSG_VALID_TIP = {
|
export const MSG_VALID_TIP = {
|
||||||
[MsgValidTypeEnum.SEARCH_EXCEPTION]: '数据查询异常',
|
[MsgValidTypeEnum.SEARCH_EXCEPTION]: '数据查询异常',
|
||||||
|
|||||||
@@ -173,7 +173,7 @@ export enum SemanticTypeEnum {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const SEMANTIC_TYPE_MAP = {
|
export const SEMANTIC_TYPE_MAP = {
|
||||||
[SemanticTypeEnum.DOMAIN]: '主题域',
|
[SemanticTypeEnum.DOMAIN]: '数据模型',
|
||||||
[SemanticTypeEnum.DIMENSION]: '维度',
|
[SemanticTypeEnum.DIMENSION]: '维度',
|
||||||
[SemanticTypeEnum.METRIC]: '指标',
|
[SemanticTypeEnum.METRIC]: '指标',
|
||||||
[SemanticTypeEnum.VALUE]: '维度值',
|
[SemanticTypeEnum.VALUE]: '维度值',
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ const ParseTip: React.FC<Props> = ({
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className={`${prefixCls}-tip-item`}>
|
<div className={`${prefixCls}-tip-item`}>
|
||||||
<div className={`${prefixCls}-tip-item-name`}>主题域:</div>
|
<div className={`${prefixCls}-tip-item-name`}>数据模型:</div>
|
||||||
<div className={itemValueClass}>{modelName}</div>
|
<div className={itemValueClass}>{modelName}</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,37 +1,24 @@
|
|||||||
import { CHART_BLUE_COLOR, CHART_SECONDARY_COLOR, PREFIX_CLS } from '../../../common/constants';
|
import { CHART_BLUE_COLOR, CHART_SECONDARY_COLOR, PREFIX_CLS } from '../../../common/constants';
|
||||||
import { DrillDownDimensionType, MsgDataType } from '../../../common/type';
|
import { MsgDataType } from '../../../common/type';
|
||||||
import { getChartLightenColor, getFormattedValue } from '../../../utils/utils';
|
import { getChartLightenColor, getFormattedValue } from '../../../utils/utils';
|
||||||
import type { ECharts } from 'echarts';
|
import type { ECharts } from 'echarts';
|
||||||
import * as echarts from 'echarts';
|
import * as echarts from 'echarts';
|
||||||
import React, { useEffect, useRef, useState } from 'react';
|
import React, { useEffect, useRef, useState } from 'react';
|
||||||
import NoPermissionChart from '../NoPermissionChart';
|
import NoPermissionChart from '../NoPermissionChart';
|
||||||
import DrillDownDimensions from '../../DrillDownDimensions';
|
|
||||||
import { Spin } from 'antd';
|
import { Spin } from 'antd';
|
||||||
import FilterSection from '../FilterSection';
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
data: MsgDataType;
|
data: MsgDataType;
|
||||||
triggerResize?: boolean;
|
triggerResize?: boolean;
|
||||||
drillDownDimension?: DrillDownDimensionType;
|
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
onSelectDimension: (dimension?: DrillDownDimensionType) => void;
|
|
||||||
onApplyAuth?: (model: string) => void;
|
onApplyAuth?: (model: string) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const BarChart: React.FC<Props> = ({
|
const BarChart: React.FC<Props> = ({ data, triggerResize, loading, onApplyAuth }) => {
|
||||||
data,
|
|
||||||
triggerResize,
|
|
||||||
drillDownDimension,
|
|
||||||
loading,
|
|
||||||
onSelectDimension,
|
|
||||||
onApplyAuth,
|
|
||||||
}) => {
|
|
||||||
const chartRef = useRef<any>();
|
const chartRef = useRef<any>();
|
||||||
const [instance, setInstance] = useState<ECharts>();
|
const [instance, setInstance] = useState<ECharts>();
|
||||||
|
|
||||||
const { queryColumns, queryResults, entityInfo, chatContext, queryMode } = data;
|
const { queryColumns, queryResults, entityInfo } = data;
|
||||||
|
|
||||||
const { dateInfo, dimensionFilters } = chatContext || {};
|
|
||||||
|
|
||||||
const categoryColumnName =
|
const categoryColumnName =
|
||||||
queryColumns?.find(column => column.showType === 'CATEGORY')?.nameEn || '';
|
queryColumns?.find(column => column.showType === 'CATEGORY')?.nameEn || '';
|
||||||
@@ -159,48 +146,16 @@ const BarChart: React.FC<Props> = ({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// const hasFilterSection = dimensionFilters?.length > 0;
|
|
||||||
|
|
||||||
const prefixCls = `${PREFIX_CLS}-bar`;
|
const prefixCls = `${PREFIX_CLS}-bar`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className={`${prefixCls}-top-bar`}>
|
<div className={`${prefixCls}-top-bar`}>
|
||||||
<div className={`${prefixCls}-indicator-name`}>{metricColumn?.name}</div>
|
<div className={`${prefixCls}-indicator-name`}>{metricColumn?.name}</div>
|
||||||
{drillDownDimension && (
|
|
||||||
<div className={`${prefixCls}-filter-section-wrapper`}>
|
|
||||||
(
|
|
||||||
<div className={`${prefixCls}-filter-section`}>
|
|
||||||
{/* <FilterSection chatContext={chatContext} entityInfo={entityInfo} /> */}
|
|
||||||
{drillDownDimension && (
|
|
||||||
<div className={`${prefixCls}-filter-item`}>
|
|
||||||
<div className={`${prefixCls}-filter-item-label`}>下钻维度:</div>
|
|
||||||
<div className={`${prefixCls}-filter-item-value`}>{drillDownDimension.name}</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
{/* {dateInfo && (
|
|
||||||
<div className={`${prefixCls}-date-range`}>
|
|
||||||
{dateInfo.startDate === dateInfo.endDate
|
|
||||||
? dateInfo.startDate
|
|
||||||
: `${dateInfo.startDate} ~ ${dateInfo.endDate}`}
|
|
||||||
</div>
|
|
||||||
)} */}
|
|
||||||
<Spin spinning={loading}>
|
<Spin spinning={loading}>
|
||||||
<div className={`${prefixCls}-chart`} ref={chartRef} />
|
<div className={`${prefixCls}-chart`} ref={chartRef} />
|
||||||
</Spin>
|
</Spin>
|
||||||
{queryMode.includes('METRIC') && (
|
|
||||||
<DrillDownDimensions
|
|
||||||
modelId={chatContext.modelId}
|
|
||||||
drillDownDimension={drillDownDimension}
|
|
||||||
dimensionFilters={chatContext.dimensionFilters}
|
|
||||||
onSelectDimension={onSelectDimension}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
import classNames from 'classnames';
|
||||||
|
import { CLS_PREFIX, DATE_TYPES } from '../../../common/constants';
|
||||||
|
import { isMobile } from '../../../utils/utils';
|
||||||
|
import { ChatContextType } from '../../../common/type';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
chatContext: ChatContextType;
|
||||||
|
currentDateOption?: number;
|
||||||
|
onSelectDateOption: (value: number) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const DateOptions: React.FC<Props> = ({ chatContext, currentDateOption, onSelectDateOption }) => {
|
||||||
|
const prefixCls = `${CLS_PREFIX}-date-options`;
|
||||||
|
|
||||||
|
const dateOptions = DATE_TYPES[chatContext?.dateInfo?.period] || DATE_TYPES.DAY;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={prefixCls}>
|
||||||
|
{dateOptions.map((dateOption: { label: string; value: number }, index: number) => {
|
||||||
|
const dateOptionClass = classNames(`${prefixCls}-item`, {
|
||||||
|
[`${prefixCls}-date-active`]: dateOption.value === currentDateOption,
|
||||||
|
[`${prefixCls}-date-mobile`]: isMobile,
|
||||||
|
});
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
key={dateOption.value}
|
||||||
|
className={dateOptionClass}
|
||||||
|
onClick={() => {
|
||||||
|
onSelectDateOption(dateOption.value);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{dateOption.label}
|
||||||
|
{dateOption.value === currentDateOption && (
|
||||||
|
<div className={`${prefixCls}-active-identifier`} />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{index !== dateOptions.length - 1 && <div className={`${prefixCls}-item-divider`} />}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DateOptions;
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
@import '../../../styles/index.less';
|
||||||
|
|
||||||
|
@date-options-prefix-cls: ~'@{supersonic-chat-prefix}-date-options';
|
||||||
|
|
||||||
|
.@{date-options-prefix-cls} {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
column-gap: 20px;
|
||||||
|
font-size: 14px;
|
||||||
|
|
||||||
|
&-item {
|
||||||
|
position: relative;
|
||||||
|
color: var(--text-color-secondary);
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: var(--chat-blue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-date-active {
|
||||||
|
color: var(--chat-blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
&-date-mobile {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-active-identifier {
|
||||||
|
position: absolute;
|
||||||
|
bottom: -6px;
|
||||||
|
width: 100%;
|
||||||
|
height: 4px;
|
||||||
|
background-color: var(--chat-blue);
|
||||||
|
border-radius: 4px 4px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-item-divider {
|
||||||
|
width: 1px;
|
||||||
|
height: 16px;
|
||||||
|
background-color: var(--text-color-fifth);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -68,7 +68,7 @@ const Message: React.FC<Props> = ({
|
|||||||
<div className={`${prefixCls}-info-bar`}>
|
<div className={`${prefixCls}-info-bar`}>
|
||||||
<div className={`${prefixCls}-main-entity-info`}>
|
<div className={`${prefixCls}-main-entity-info`}>
|
||||||
<div className={`${prefixCls}-info-item`}>
|
<div className={`${prefixCls}-info-item`}>
|
||||||
<div className={`${prefixCls}-info-name`}>主题域:</div>
|
<div className={`${prefixCls}-info-name`}>数据模型:</div>
|
||||||
<div className={`${prefixCls}-info-value`}>{modelName}</div>
|
<div className={`${prefixCls}-info-value`}>{modelName}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={`${prefixCls}-info-item`}>
|
<div className={`${prefixCls}-info-item`}>
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import { PREFIX_CLS } from '../../../common/constants';
|
import { PREFIX_CLS } from '../../../common/constants';
|
||||||
import { formatByDecimalPlaces, formatMetric, formatNumberWithCN } from '../../../utils/utils';
|
import { formatByDecimalPlaces, formatMetric, formatNumberWithCN } from '../../../utils/utils';
|
||||||
import ApplyAuth from '../ApplyAuth';
|
import ApplyAuth from '../ApplyAuth';
|
||||||
import { DrillDownDimensionType, MsgDataType } from '../../../common/type';
|
import { MsgDataType } from '../../../common/type';
|
||||||
import PeriodCompareItem from './PeriodCompareItem';
|
import PeriodCompareItem from './PeriodCompareItem';
|
||||||
import DrillDownDimensions from '../../DrillDownDimensions';
|
|
||||||
import { Spin } from 'antd';
|
import { Spin } from 'antd';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { SwapOutlined } from '@ant-design/icons';
|
import { SwapOutlined } from '@ant-design/icons';
|
||||||
@@ -11,20 +10,12 @@ import { useState } from 'react';
|
|||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
data: MsgDataType;
|
data: MsgDataType;
|
||||||
drillDownDimension?: DrillDownDimensionType;
|
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
onSelectDimension: (dimension?: DrillDownDimensionType) => void;
|
|
||||||
onApplyAuth?: (model: string) => void;
|
onApplyAuth?: (model: string) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const MetricCard: React.FC<Props> = ({
|
const MetricCard: React.FC<Props> = ({ data, loading, onApplyAuth }) => {
|
||||||
data,
|
const { queryMode, queryColumns, queryResults, entityInfo, aggregateInfo } = data;
|
||||||
drillDownDimension,
|
|
||||||
loading,
|
|
||||||
onSelectDimension,
|
|
||||||
onApplyAuth,
|
|
||||||
}) => {
|
|
||||||
const { queryMode, queryColumns, queryResults, entityInfo, aggregateInfo, chatContext } = data;
|
|
||||||
|
|
||||||
const { metricInfos } = aggregateInfo || {};
|
const { metricInfos } = aggregateInfo || {};
|
||||||
|
|
||||||
@@ -57,20 +48,6 @@ const MetricCard: React.FC<Props> = ({
|
|||||||
) : (
|
) : (
|
||||||
<div style={{ height: 10 }} />
|
<div style={{ height: 10 }} />
|
||||||
)}
|
)}
|
||||||
{drillDownDimension && (
|
|
||||||
<div className={`${prefixCls}-filter-section-wrapper`}>
|
|
||||||
(
|
|
||||||
<div className={`${prefixCls}-filter-section`}>
|
|
||||||
{drillDownDimension && (
|
|
||||||
<div className={`${prefixCls}-filter-item`}>
|
|
||||||
<div className={`${prefixCls}-filter-item-label`}>下钻维度:</div>
|
|
||||||
<div className={`${prefixCls}-filter-item-value`}>{drillDownDimension.name}</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
<Spin spinning={loading}>
|
<Spin spinning={loading}>
|
||||||
<div className={indicatorClass}>
|
<div className={indicatorClass}>
|
||||||
@@ -104,16 +81,6 @@ const MetricCard: React.FC<Props> = ({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</Spin>
|
</Spin>
|
||||||
{queryMode.includes('METRIC') && (
|
|
||||||
<div className={`${prefixCls}-drill-down-dimensions`}>
|
|
||||||
<DrillDownDimensions
|
|
||||||
modelId={chatContext?.modelId}
|
|
||||||
dimensionFilters={chatContext?.dimensionFilters}
|
|
||||||
drillDownDimension={drillDownDimension}
|
|
||||||
onSelectDimension={onSelectDimension}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,150 +1,48 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { CLS_PREFIX } from '../../../common/constants';
|
||||||
import { CLS_PREFIX, DATE_TYPES } from '../../../common/constants';
|
import { FieldType, MsgDataType } from '../../../common/type';
|
||||||
import { ColumnType, DrillDownDimensionType, FieldType, MsgDataType } from '../../../common/type';
|
|
||||||
import { isMobile } from '../../../utils/utils';
|
import { isMobile } from '../../../utils/utils';
|
||||||
import { queryData } from '../../../service';
|
|
||||||
import MetricTrendChart from './MetricTrendChart';
|
import MetricTrendChart from './MetricTrendChart';
|
||||||
import classNames from 'classnames';
|
|
||||||
import { Spin } from 'antd';
|
import { Spin } from 'antd';
|
||||||
import Table from '../Table';
|
import Table from '../Table';
|
||||||
import DrillDownDimensions from '../../DrillDownDimensions';
|
|
||||||
import MetricInfo from './MetricInfo';
|
import MetricInfo from './MetricInfo';
|
||||||
import MetricOptions from '../../MetricOptions';
|
import DateOptions from '../DateOptions';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
data: MsgDataType;
|
data: MsgDataType;
|
||||||
chartIndex: number;
|
chartIndex: number;
|
||||||
triggerResize?: boolean;
|
triggerResize?: boolean;
|
||||||
|
loading: boolean;
|
||||||
|
activeMetricField?: FieldType;
|
||||||
|
currentDateOption?: number;
|
||||||
onApplyAuth?: (model: string) => void;
|
onApplyAuth?: (model: string) => void;
|
||||||
|
onSelectDateOption: (value: number) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const MetricTrend: React.FC<Props> = ({ data, chartIndex, triggerResize, onApplyAuth }) => {
|
const MetricTrend: React.FC<Props> = ({
|
||||||
const { entityInfo, chatContext, queryMode } = data;
|
data,
|
||||||
const { dateInfo, dimensionFilters, elementMatches } = chatContext || {};
|
chartIndex,
|
||||||
const { dateMode, unit } = dateInfo || {};
|
triggerResize,
|
||||||
const dateOptions = DATE_TYPES[chatContext?.dateInfo?.period] || DATE_TYPES.DAY;
|
loading,
|
||||||
|
activeMetricField,
|
||||||
|
currentDateOption,
|
||||||
|
onApplyAuth,
|
||||||
|
onSelectDateOption,
|
||||||
|
}) => {
|
||||||
|
const { queryColumns, queryResults, aggregateInfo, entityInfo, chatContext } = data;
|
||||||
|
|
||||||
const [columns, setColumns] = useState<ColumnType[]>([]);
|
const dateField: any = queryColumns?.find(
|
||||||
const [defaultMetricField, setDefaultMetricField] = useState<FieldType>();
|
|
||||||
const [activeMetricField, setActiveMetricField] = useState<FieldType>();
|
|
||||||
const [dataSource, setDataSource] = useState<any[]>([]);
|
|
||||||
const [currentDateOption, setCurrentDateOption] = useState<number>();
|
|
||||||
const [dimensions, setDimensions] = useState<FieldType[]>();
|
|
||||||
const [drillDownDimension, setDrillDownDimension] = useState<DrillDownDimensionType>();
|
|
||||||
const [aggregateInfoValue, setAggregateInfoValue] = useState<any>();
|
|
||||||
const [dateModeValue, setDateModeValue] = useState<any>();
|
|
||||||
const [loading, setLoading] = useState(false);
|
|
||||||
|
|
||||||
const dateField: any = columns.find(
|
|
||||||
(column: any) => column.showType === 'DATE' || column.type === 'DATE'
|
(column: any) => column.showType === 'DATE' || column.type === 'DATE'
|
||||||
);
|
);
|
||||||
const dateColumnName = dateField?.nameEn || '';
|
const dateColumnName = dateField?.nameEn || '';
|
||||||
const categoryColumnName =
|
const categoryColumnName =
|
||||||
columns.find((column: any) => column.showType === 'CATEGORY')?.nameEn || '';
|
queryColumns?.find((column: any) => column.showType === 'CATEGORY')?.nameEn || '';
|
||||||
|
|
||||||
const entityId = dimensionFilters?.length > 0 ? dimensionFilters[0].value : undefined;
|
const currentMetricField = queryColumns?.find((column: any) => column.showType === 'NUMBER');
|
||||||
const entityName = elementMatches?.find((item: any) => item.element?.type === 'ID')?.element
|
|
||||||
?.name;
|
|
||||||
|
|
||||||
const isEntityMode =
|
|
||||||
(queryMode === 'ENTITY_LIST_FILTER' || queryMode === 'METRIC_ENTITY') &&
|
|
||||||
typeof entityId === 'string' &&
|
|
||||||
entityName !== undefined;
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const { queryColumns, queryResults, chatContext, aggregateInfo } = data;
|
|
||||||
|
|
||||||
const initialDateOption = dateOptions.find((option: any) => {
|
|
||||||
return dateMode === 'RECENT' && option.value === unit;
|
|
||||||
})?.value;
|
|
||||||
|
|
||||||
setColumns(queryColumns || []);
|
|
||||||
const metricField = chatContext?.metrics?.[0];
|
|
||||||
setDefaultMetricField(metricField);
|
|
||||||
setActiveMetricField(metricField);
|
|
||||||
setDataSource(queryResults);
|
|
||||||
setCurrentDateOption(initialDateOption);
|
|
||||||
setDimensions(chatContext?.dimensions);
|
|
||||||
setDrillDownDimension(undefined);
|
|
||||||
setAggregateInfoValue(aggregateInfo);
|
|
||||||
setDateModeValue(chatContext?.dateInfo?.dateMode);
|
|
||||||
}, [data]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (queryMode === 'METRIC_GROUPBY') {
|
|
||||||
const dimensionValue = chatContext?.dimensions?.find(
|
|
||||||
dimension => dimension.type === 'DIMENSION'
|
|
||||||
);
|
|
||||||
setDrillDownDimension(dimensionValue);
|
|
||||||
setDimensions(
|
|
||||||
chatContext?.dimensions?.filter(dimension => dimension.id !== dimensionValue?.id)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const onLoadData = async (value: any) => {
|
|
||||||
setLoading(true);
|
|
||||||
const { data } = await queryData({
|
|
||||||
...chatContext,
|
|
||||||
...value,
|
|
||||||
});
|
|
||||||
setLoading(false);
|
|
||||||
if (data.code === 200) {
|
|
||||||
setColumns(data.data?.queryColumns || []);
|
|
||||||
setDataSource(data.data?.queryResults || []);
|
|
||||||
setAggregateInfoValue(data.data?.aggregateInfo);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const selectDateOption = (dateOption: number) => {
|
|
||||||
setCurrentDateOption(dateOption);
|
|
||||||
setDateModeValue('RECENT');
|
|
||||||
onLoadData({
|
|
||||||
metrics: [activeMetricField],
|
|
||||||
dimensions: drillDownDimension ? [...(dimensions || []), drillDownDimension] : undefined,
|
|
||||||
dateInfo: {
|
|
||||||
...chatContext?.dateInfo,
|
|
||||||
dateMode: 'RECENT',
|
|
||||||
unit: dateOption,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const onSwitchMetric = (metricField?: FieldType) => {
|
|
||||||
setActiveMetricField(metricField);
|
|
||||||
onLoadData({
|
|
||||||
dateInfo: {
|
|
||||||
...chatContext.dateInfo,
|
|
||||||
dateMode: dateModeValue,
|
|
||||||
unit: currentDateOption || chatContext.dateInfo.unit,
|
|
||||||
},
|
|
||||||
dimensions: drillDownDimension ? [...(dimensions || []), drillDownDimension] : undefined,
|
|
||||||
metrics: [metricField || defaultMetricField],
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const onSelectDimension = (dimension?: DrillDownDimensionType) => {
|
|
||||||
setDrillDownDimension(dimension);
|
|
||||||
onLoadData({
|
|
||||||
dateInfo: {
|
|
||||||
...chatContext.dateInfo,
|
|
||||||
dateMode: dateModeValue,
|
|
||||||
unit: currentDateOption || chatContext.dateInfo.unit,
|
|
||||||
},
|
|
||||||
metrics: [activeMetricField],
|
|
||||||
dimensions: dimension === undefined ? undefined : [...(dimensions || []), dimension],
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const currentMetricField = columns.find((column: any) => column.showType === 'NUMBER');
|
|
||||||
|
|
||||||
if (!currentMetricField) {
|
if (!currentMetricField) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isMultipleMetric = chatContext?.metrics?.length > 1;
|
|
||||||
const existDrillDownDimension = queryMode.includes('METRIC') && !isEntityMode;
|
|
||||||
|
|
||||||
const prefixCls = `${CLS_PREFIX}-metric-trend`;
|
const prefixCls = `${CLS_PREFIX}-metric-trend`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -157,92 +55,31 @@ const MetricTrend: React.FC<Props> = ({ data, chartIndex, triggerResize, onApply
|
|||||||
>
|
>
|
||||||
{activeMetricField?.name}
|
{activeMetricField?.name}
|
||||||
</div>
|
</div>
|
||||||
{drillDownDimension && (
|
|
||||||
<div className={`${prefixCls}-filter-section-wrapper`}>
|
|
||||||
(
|
|
||||||
<div className={`${prefixCls}-filter-section`}>
|
|
||||||
{drillDownDimension && (
|
|
||||||
<div className={`${prefixCls}-filter-item`}>
|
|
||||||
<div className={`${prefixCls}-filter-item-label`}>下钻维度:</div>
|
|
||||||
<div className={`${prefixCls}-filter-item-value`}>
|
|
||||||
{drillDownDimension.name}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
<Spin spinning={loading}>
|
<Spin spinning={loading}>
|
||||||
<div className={`${prefixCls}-content`}>
|
<div className={`${prefixCls}-content`}>
|
||||||
{!isMobile && aggregateInfoValue?.metricInfos?.length > 0 && (
|
{!isMobile && aggregateInfo?.metricInfos?.length > 0 && (
|
||||||
<MetricInfo
|
<MetricInfo aggregateInfo={aggregateInfo} currentMetricField={currentMetricField} />
|
||||||
aggregateInfo={aggregateInfoValue}
|
|
||||||
currentMetricField={currentMetricField}
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
<div className={`${prefixCls}-date-options`}>
|
<DateOptions
|
||||||
{dateOptions.map((dateOption: { label: string; value: number }, index: number) => {
|
chatContext={chatContext}
|
||||||
const dateOptionClass = classNames(`${prefixCls}-date-option`, {
|
currentDateOption={currentDateOption}
|
||||||
[`${prefixCls}-date-active`]: dateOption.value === currentDateOption,
|
onSelectDateOption={onSelectDateOption}
|
||||||
[`${prefixCls}-date-mobile`]: isMobile,
|
/>
|
||||||
});
|
{queryResults?.length === 1 || chartIndex % 2 === 1 ? (
|
||||||
return (
|
<Table data={{ ...data, queryResults }} onApplyAuth={onApplyAuth} />
|
||||||
<>
|
|
||||||
<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>
|
|
||||||
{dataSource?.length === 1 || chartIndex % 2 === 1 ? (
|
|
||||||
<Table data={{ ...data, queryResults: dataSource }} onApplyAuth={onApplyAuth} />
|
|
||||||
) : (
|
) : (
|
||||||
<MetricTrendChart
|
<MetricTrendChart
|
||||||
model={entityInfo?.modelInfo.name}
|
model={entityInfo?.modelInfo.name}
|
||||||
dateColumnName={dateColumnName}
|
dateColumnName={dateColumnName}
|
||||||
categoryColumnName={categoryColumnName}
|
categoryColumnName={categoryColumnName}
|
||||||
metricField={currentMetricField}
|
metricField={currentMetricField}
|
||||||
resultList={dataSource}
|
resultList={queryResults}
|
||||||
triggerResize={triggerResize}
|
triggerResize={triggerResize}
|
||||||
onApplyAuth={onApplyAuth}
|
onApplyAuth={onApplyAuth}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{(isMultipleMetric || existDrillDownDimension) && (
|
|
||||||
<div className={`${prefixCls}-bottom-tools`}>
|
|
||||||
{isMultipleMetric && (
|
|
||||||
<MetricOptions
|
|
||||||
metrics={chatContext.metrics}
|
|
||||||
defaultMetric={defaultMetricField}
|
|
||||||
currentMetric={activeMetricField}
|
|
||||||
onSelectMetric={onSwitchMetric}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{existDrillDownDimension && (
|
|
||||||
<DrillDownDimensions
|
|
||||||
modelId={chatContext.modelId}
|
|
||||||
drillDownDimension={drillDownDimension}
|
|
||||||
dimensionFilters={chatContext.dimensionFilters}
|
|
||||||
onSelectDimension={onSelectDimension}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Spin>
|
</Spin>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -139,53 +139,6 @@
|
|||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&-date-options {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
column-gap: 20px;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-date-option {
|
|
||||||
position: relative;
|
|
||||||
color: var(--text-color-secondary);
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: var(--chat-blue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&-date-option-active {
|
|
||||||
color: var(--chat-blue);
|
|
||||||
}
|
|
||||||
|
|
||||||
&-date-option-mobile {
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-bottom-tools {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
column-gap: 20px;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-active-identifier {
|
|
||||||
position: absolute;
|
|
||||||
bottom: -6px;
|
|
||||||
width: 100%;
|
|
||||||
height: 4px;
|
|
||||||
background-color: var(--chat-blue);
|
|
||||||
border-radius: 4px 4px 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-date-option-divider {
|
|
||||||
width: 1px;
|
|
||||||
height: 16px;
|
|
||||||
background-color: var(--text-color-fifth);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.@{metric-info-prefix-cls} {
|
.@{metric-info-prefix-cls} {
|
||||||
|
|||||||
@@ -11,6 +11,39 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&-filter-section-wrapper {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
color: var(--text-color-third);
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-filter-section {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 13px;
|
||||||
|
column-gap: 12px;
|
||||||
|
color: var(--text-color-third);
|
||||||
|
}
|
||||||
|
|
||||||
|
&-filter-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-filter-item-label {
|
||||||
|
color: var(--text-color-third);
|
||||||
|
}
|
||||||
|
|
||||||
|
&-filter-item-value {
|
||||||
|
color: var(--text-color);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-drill-down-dimensions {
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
table {
|
table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,12 +2,14 @@ import Bar from './Bar';
|
|||||||
import MetricCard from './MetricCard';
|
import MetricCard from './MetricCard';
|
||||||
import MetricTrend from './MetricTrend';
|
import MetricTrend from './MetricTrend';
|
||||||
import Table from './Table';
|
import Table from './Table';
|
||||||
import { ColumnType, DrillDownDimensionType, MsgDataType } from '../../common/type';
|
import { ColumnType, DrillDownDimensionType, FieldType, MsgDataType } from '../../common/type';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { queryData } from '../../service';
|
import { queryData } from '../../service';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { PREFIX_CLS } from '../../common/constants';
|
import { PREFIX_CLS } from '../../common/constants';
|
||||||
import Text from './Text';
|
import Text from './Text';
|
||||||
|
import DrillDownDimensions from '../DrillDownDimensions';
|
||||||
|
import MetricOptions from '../MetricOptions';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
data: MsgDataType;
|
data: MsgDataType;
|
||||||
@@ -16,14 +18,18 @@ type Props = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const ChatMsg: React.FC<Props> = ({ data, chartIndex, triggerResize }) => {
|
const ChatMsg: React.FC<Props> = ({ data, chartIndex, triggerResize }) => {
|
||||||
const { queryColumns, queryResults, chatContext, queryMode } = data;
|
const { queryColumns, queryResults, chatContext, queryMode } = data || {};
|
||||||
|
const { dimensionFilters, elementMatches } = chatContext || {};
|
||||||
|
|
||||||
const [columns, setColumns] = useState<ColumnType[]>();
|
const [columns, setColumns] = useState<ColumnType[]>();
|
||||||
const [referenceColumn, setReferenceColumn] = useState<ColumnType>();
|
const [referenceColumn, setReferenceColumn] = useState<ColumnType>();
|
||||||
const [dataSource, setDataSource] = useState<any[]>(queryResults);
|
const [dataSource, setDataSource] = useState<any[]>(queryResults);
|
||||||
|
|
||||||
const [drillDownDimension, setDrillDownDimension] = useState<DrillDownDimensionType>();
|
const [drillDownDimension, setDrillDownDimension] = useState<DrillDownDimensionType>();
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [defaultMetricField, setDefaultMetricField] = useState<FieldType>();
|
||||||
|
const [activeMetricField, setActiveMetricField] = useState<FieldType>();
|
||||||
|
const [dateModeValue, setDateModeValue] = useState<any>();
|
||||||
|
const [currentDateOption, setCurrentDateOption] = useState<number>();
|
||||||
|
|
||||||
const prefixCls = `${PREFIX_CLS}-chat-msg`;
|
const prefixCls = `${PREFIX_CLS}-chat-msg`;
|
||||||
|
|
||||||
@@ -36,7 +42,11 @@ const ChatMsg: React.FC<Props> = ({ data, chartIndex, triggerResize }) => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
updateColummns(queryColumns);
|
updateColummns(queryColumns);
|
||||||
setDataSource(queryResults);
|
setDataSource(queryResults);
|
||||||
}, [queryColumns, queryResults]);
|
setDefaultMetricField(chatContext?.metrics?.[0]);
|
||||||
|
setActiveMetricField(chatContext?.metrics?.[0]);
|
||||||
|
setDateModeValue(chatContext?.dateInfo?.dateMode);
|
||||||
|
setCurrentDateOption(chatContext?.dateInfo?.unit);
|
||||||
|
}, [data]);
|
||||||
|
|
||||||
if (!queryColumns || !queryResults || !columns) {
|
if (!queryColumns || !queryResults || !columns) {
|
||||||
return null;
|
return null;
|
||||||
@@ -69,6 +79,52 @@ const ChatMsg: React.FC<Props> = ({ data, chartIndex, triggerResize }) => {
|
|||||||
queryMode === 'ENTITY_DIMENSION' ||
|
queryMode === 'ENTITY_DIMENSION' ||
|
||||||
(categoryField.length === 1 && metricFields.length === 0));
|
(categoryField.length === 1 && metricFields.length === 0));
|
||||||
|
|
||||||
|
const getMsgContent = () => {
|
||||||
|
if (isText) {
|
||||||
|
return <Text columns={columns} referenceColumn={referenceColumn} dataSource={dataSource} />;
|
||||||
|
}
|
||||||
|
if (isMetricCard) {
|
||||||
|
return (
|
||||||
|
<MetricCard
|
||||||
|
data={{ ...data, queryColumns: columns, queryResults: dataSource }}
|
||||||
|
loading={loading}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (isTable) {
|
||||||
|
return <Table data={{ ...data, queryColumns: columns, queryResults: dataSource }} />;
|
||||||
|
}
|
||||||
|
if (dateField && metricFields.length > 0) {
|
||||||
|
if (!dataSource.every(item => item[dateField.nameEn] === dataSource[0][dateField.nameEn])) {
|
||||||
|
return (
|
||||||
|
<MetricTrend
|
||||||
|
data={{
|
||||||
|
...data,
|
||||||
|
queryColumns: columns,
|
||||||
|
queryResults: dataSource,
|
||||||
|
}}
|
||||||
|
loading={loading}
|
||||||
|
chartIndex={chartIndex}
|
||||||
|
triggerResize={triggerResize}
|
||||||
|
activeMetricField={activeMetricField}
|
||||||
|
currentDateOption={currentDateOption}
|
||||||
|
onSelectDateOption={selectDateOption}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (categoryField?.length > 0 && metricFields?.length > 0) {
|
||||||
|
return (
|
||||||
|
<Bar
|
||||||
|
data={{ ...data, queryColumns: columns, queryResults: dataSource }}
|
||||||
|
triggerResize={triggerResize}
|
||||||
|
loading={loading}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return <Table data={{ ...data, queryColumns: columns, queryResults: dataSource }} />;
|
||||||
|
};
|
||||||
|
|
||||||
const onLoadData = async (value: any) => {
|
const onLoadData = async (value: any) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const { data } = await queryData({
|
const { data } = await queryData({
|
||||||
@@ -85,58 +141,94 @@ const ChatMsg: React.FC<Props> = ({ data, chartIndex, triggerResize }) => {
|
|||||||
const onSelectDimension = (dimension?: DrillDownDimensionType) => {
|
const onSelectDimension = (dimension?: DrillDownDimensionType) => {
|
||||||
setDrillDownDimension(dimension);
|
setDrillDownDimension(dimension);
|
||||||
onLoadData({
|
onLoadData({
|
||||||
dimensions:
|
dateInfo: {
|
||||||
dimension === undefined ? undefined : [...(chatContext.dimensions || []), dimension],
|
...chatContext.dateInfo,
|
||||||
|
dateMode: dateModeValue,
|
||||||
|
unit: currentDateOption || chatContext.dateInfo.unit,
|
||||||
|
},
|
||||||
|
dimensions: dimension
|
||||||
|
? [...(chatContext.dimensions || []), dimension]
|
||||||
|
: chatContext.dimensions,
|
||||||
|
metrics: [activeMetricField || defaultMetricField],
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const getMsgContent = () => {
|
const onSwitchMetric = (metricField?: FieldType) => {
|
||||||
if (isText) {
|
setActiveMetricField(metricField);
|
||||||
return <Text columns={columns} referenceColumn={referenceColumn} dataSource={dataSource} />;
|
onLoadData({
|
||||||
}
|
dateInfo: {
|
||||||
if (isMetricCard) {
|
...chatContext.dateInfo,
|
||||||
return (
|
dateMode: dateModeValue,
|
||||||
<MetricCard
|
unit: currentDateOption || chatContext.dateInfo.unit,
|
||||||
data={{ ...data, queryColumns: columns, queryResults: dataSource }}
|
},
|
||||||
loading={loading}
|
dimensions: drillDownDimension
|
||||||
drillDownDimension={drillDownDimension}
|
? [...(chatContext.dimensions || []), drillDownDimension]
|
||||||
onSelectDimension={onSelectDimension}
|
: chatContext.dimensions,
|
||||||
/>
|
metrics: [metricField || defaultMetricField],
|
||||||
);
|
});
|
||||||
}
|
};
|
||||||
if (isTable) {
|
|
||||||
return <Table data={{ ...data, queryColumns: columns, queryResults: dataSource }} />;
|
const selectDateOption = (dateOption: number) => {
|
||||||
}
|
setCurrentDateOption(dateOption);
|
||||||
if (dateField && metricFields.length > 0) {
|
setDateModeValue('RECENT');
|
||||||
if (!dataSource.every(item => item[dateField.nameEn] === dataSource[0][dateField.nameEn])) {
|
onLoadData({
|
||||||
return (
|
metrics: [activeMetricField || defaultMetricField],
|
||||||
<MetricTrend
|
dimensions: drillDownDimension
|
||||||
data={{ ...data, queryColumns: columns, queryResults: dataSource }}
|
? [...(chatContext.dimensions || []), drillDownDimension]
|
||||||
chartIndex={chartIndex}
|
: chatContext.dimensions,
|
||||||
triggerResize={triggerResize}
|
dateInfo: {
|
||||||
/>
|
...chatContext?.dateInfo,
|
||||||
);
|
dateMode: 'RECENT',
|
||||||
}
|
unit: dateOption,
|
||||||
}
|
},
|
||||||
if (categoryField?.length > 0 && metricFields?.length > 0) {
|
});
|
||||||
return (
|
|
||||||
<Bar
|
|
||||||
data={{ ...data, queryColumns: columns, queryResults: dataSource }}
|
|
||||||
triggerResize={triggerResize}
|
|
||||||
loading={loading}
|
|
||||||
drillDownDimension={drillDownDimension}
|
|
||||||
onSelectDimension={onSelectDimension}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return <Table data={{ ...data, queryColumns: columns, queryResults: dataSource }} />;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const chartMsgClass = classNames({ [prefixCls]: !isTable });
|
const chartMsgClass = classNames({ [prefixCls]: !isTable });
|
||||||
|
|
||||||
|
const entityId = dimensionFilters?.length > 0 ? dimensionFilters[0].value : undefined;
|
||||||
|
const entityName = elementMatches?.find((item: any) => item.element?.type === 'ID')?.element
|
||||||
|
?.name;
|
||||||
|
|
||||||
|
const isEntityMode =
|
||||||
|
(queryMode === 'ENTITY_LIST_FILTER' || queryMode === 'METRIC_ENTITY') &&
|
||||||
|
typeof entityId === 'string' &&
|
||||||
|
entityName !== undefined;
|
||||||
|
|
||||||
|
const existDrillDownDimension = queryMode.includes('METRIC') && !isText && !isEntityMode;
|
||||||
|
|
||||||
|
const isMultipleMetric = existDrillDownDimension && chatContext?.metrics?.length > 1;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={chartMsgClass}>
|
<div className={chartMsgClass}>
|
||||||
{dataSource?.length === 0 ? <div>暂无数据,如有疑问请联系管理员</div> : getMsgContent()}
|
{dataSource?.length === 0 ? (
|
||||||
|
<div>暂无数据,如有疑问请联系管理员</div>
|
||||||
|
) : (
|
||||||
|
<div>
|
||||||
|
{getMsgContent()}
|
||||||
|
{(isMultipleMetric || existDrillDownDimension) && (
|
||||||
|
<div className={`${prefixCls}-bottom-tools`}>
|
||||||
|
{isMultipleMetric && (
|
||||||
|
<MetricOptions
|
||||||
|
metrics={chatContext.metrics}
|
||||||
|
defaultMetric={defaultMetricField}
|
||||||
|
currentMetric={activeMetricField}
|
||||||
|
onSelectMetric={onSwitchMetric}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{existDrillDownDimension && (
|
||||||
|
<DrillDownDimensions
|
||||||
|
modelId={chatContext.modelId}
|
||||||
|
drillDownDimension={drillDownDimension}
|
||||||
|
originDimensions={chatContext.dimensions}
|
||||||
|
dimensionFilters={chatContext.dimensionFilters}
|
||||||
|
onSelectDimension={onSelectDimension}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,4 +7,12 @@
|
|||||||
border: 1px solid var(--border-color-base);
|
border: 1px solid var(--border-color-base);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
background: #f5f8fb;
|
background: #f5f8fb;
|
||||||
|
|
||||||
|
&-bottom-tools {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
column-gap: 20px;
|
||||||
|
font-size: 14px;
|
||||||
|
margin-top: 6px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -10,6 +10,7 @@ type Props = {
|
|||||||
modelId: number;
|
modelId: number;
|
||||||
drillDownDimension?: DrillDownDimensionType;
|
drillDownDimension?: DrillDownDimensionType;
|
||||||
isMetricCard?: boolean;
|
isMetricCard?: boolean;
|
||||||
|
originDimensions?: DrillDownDimensionType[];
|
||||||
dimensionFilters?: FilterItemType[];
|
dimensionFilters?: FilterItemType[];
|
||||||
onSelectDimension: (dimension?: DrillDownDimensionType) => void;
|
onSelectDimension: (dimension?: DrillDownDimensionType) => void;
|
||||||
};
|
};
|
||||||
@@ -20,6 +21,7 @@ const DrillDownDimensions: React.FC<Props> = ({
|
|||||||
modelId,
|
modelId,
|
||||||
drillDownDimension,
|
drillDownDimension,
|
||||||
isMetricCard,
|
isMetricCard,
|
||||||
|
originDimensions,
|
||||||
dimensionFilters,
|
dimensionFilters,
|
||||||
onSelectDimension,
|
onSelectDimension,
|
||||||
}) => {
|
}) => {
|
||||||
@@ -33,7 +35,11 @@ const DrillDownDimensions: React.FC<Props> = ({
|
|||||||
const res = await queryDrillDownDimensions(modelId);
|
const res = await queryDrillDownDimensions(modelId);
|
||||||
setDimensions(
|
setDimensions(
|
||||||
res.data.data.dimensions
|
res.data.data.dimensions
|
||||||
.filter(dimension => !dimensionFilters?.some(filter => filter.name === dimension.name))
|
.filter(
|
||||||
|
dimension =>
|
||||||
|
!dimensionFilters?.some(filter => filter.name === dimension.name) &&
|
||||||
|
(!originDimensions || !originDimensions.some(item => item.id === dimension.id))
|
||||||
|
)
|
||||||
.slice(0, MAX_DIMENSION_COUNT)
|
.slice(0, MAX_DIMENSION_COUNT)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { createFromIconfontCN } from '@ant-design/icons';
|
import { createFromIconfontCN } from '@ant-design/icons';
|
||||||
|
|
||||||
const IconFont = createFromIconfontCN({
|
const IconFont = createFromIconfontCN({
|
||||||
scriptUrl: '//at.alicdn.com/t/c/font_4120566_sz2crkuyuj.js',
|
scriptUrl: '//at.alicdn.com/t/c/font_4120566_x5c4www9bqm.js',
|
||||||
});
|
});
|
||||||
|
|
||||||
export default IconFont;
|
export default IconFont;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import axios from './axiosInstance';
|
import axios from './axiosInstance';
|
||||||
import { ChatContextType, DrillDownDimensionType, HistoryType, MsgDataType, ParseDataType, SearchRecommendItem } from '../common/type';
|
import { ChatContextType, DrillDownDimensionType, HistoryType, MsgDataType, ParseDataType, SearchRecommendItem } from '../common/type';
|
||||||
|
|
||||||
const DEFAULT_CHAT_ID = 0;
|
const DEFAULT_CHAT_ID = 12009993;
|
||||||
|
|
||||||
const prefix = '/api';
|
const prefix = '/api';
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,8 @@
|
|||||||
|
|
||||||
@import "../components/ChatMsg/FilterSection/style.less";
|
@import "../components/ChatMsg/FilterSection/style.less";
|
||||||
|
|
||||||
|
@import "../components/ChatMsg/DateOptions/style.less";
|
||||||
|
|
||||||
@import "../components/ChatMsg/Text/style.less";
|
@import "../components/ChatMsg/Text/style.less";
|
||||||
|
|
||||||
@import '../components/ChatItem/style.less';
|
@import '../components/ChatItem/style.less';
|
||||||
|
|||||||
@@ -46,7 +46,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
margin: 16px 0 0;
|
margin: 16px 0 1px;
|
||||||
row-gap: 8px;
|
row-gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user