(feature)(webapp) add filter modify and similar questions (#213)

This commit is contained in:
williamhliu
2023-10-13 18:31:00 +08:00
committed by GitHub
parent ab19b18169
commit 767abc2b90
27 changed files with 799 additions and 795 deletions

View File

@@ -1,20 +1,27 @@
import React, { ReactNode } from 'react';
import { AGG_TYPE_MAP, PREFIX_CLS } from '../../common/constants';
import { ChatContextType, FilterItemType } from '../../common/type';
import { ChatContextType, DateInfoType, EntityInfoType, FilterItemType } from '../../common/type';
import { DatePicker } from 'antd';
import { CheckCircleFilled } from '@ant-design/icons';
import classNames from 'classnames';
import SwicthEntity from './SwitchEntity';
import Loading from './Loading';
import FilterItem from './FilterItem';
import moment from 'moment';
const { RangePicker } = DatePicker;
type Props = {
parseLoading: boolean;
parseInfoOptions: ChatContextType[];
parseTip: string;
currentParseInfo?: ChatContextType;
agentId?: number;
dimensionFilters: FilterItemType[];
dateInfo: DateInfoType;
entityInfo: EntityInfoType;
onSelectParseInfo: (parseInfo: ChatContextType) => void;
onSwitchEntity: (entityId: string) => void;
onFiltersChange: (filters: FilterItemType[]) => void;
onDateInfoChange: (dateRange: any) => void;
};
const MAX_OPTION_VALUES_COUNT = 2;
@@ -24,16 +31,18 @@ const ParseTip: React.FC<Props> = ({
parseInfoOptions,
parseTip,
currentParseInfo,
agentId,
dimensionFilters,
dateInfo,
entityInfo,
onSelectParseInfo,
onSwitchEntity,
onFiltersChange,
onDateInfoChange,
}) => {
const prefixCls = `${PREFIX_CLS}-item`;
const getNode = (tipTitle: ReactNode, tipNode?: ReactNode, parseSucceed?: boolean) => {
const contentContainerClass = classNames(`${prefixCls}-content-container`, {
[`${prefixCls}-content-container-succeed`]: parseSucceed,
});
return (
<div className={`${prefixCls}-parse-tip`}>
<div className={`${prefixCls}-title-bar`}>
@@ -43,7 +52,7 @@ const ParseTip: React.FC<Props> = ({
{!tipNode && <Loading />}
</div>
</div>
{tipNode && <div className={contentContainerClass}>{tipNode}</div>}
{tipNode && <div className={`${prefixCls}-content-container`}>{tipNode}</div>}
</div>
);
};
@@ -60,22 +69,38 @@ const ParseTip: React.FC<Props> = ({
return null;
}
const getTipNode = (parseInfo: ChatContextType, isOptions?: boolean, index?: number) => {
const {
modelName,
dateInfo,
dimensionFilters,
dimensions,
metrics,
aggType,
queryMode,
properties,
entity,
elementMatches,
nativeQuery,
} = parseInfo || {};
const {
modelId,
modelName,
dimensions,
metrics,
aggType,
queryMode,
properties,
entity,
// entityInfo,
elementMatches,
nativeQuery,
} = currentParseInfo || {};
const { startDate, endDate } = dateInfo || {};
const { type } = properties || {};
const entityAlias = entity?.alias?.[0]?.split('.')?.[0];
const entityName = elementMatches?.find(item => item.element?.type === 'ID')?.element.name;
const entityDimensions = entityInfo?.dimensions?.filter(
item =>
!['zyqk_song_id', 'song_name', 'singer_id', 'zyqk_cmpny_id'].includes(item.bizName) &&
!(
entityInfo?.dimensions?.some(dimension => dimension.bizName === 'singer_id') &&
item.bizName === 'singer_name'
) &&
!(
entityInfo?.dimensions?.some(dimension => dimension.bizName === 'zyqk_cmpny_id') &&
item.bizName === 'cmpny_name'
)
);
const getTipNode = () => {
const dimensionItems = dimensions?.filter(item => item.type === 'DIMENSION');
const metric = metrics?.[0];
@@ -90,15 +115,7 @@ const ParseTip: React.FC<Props> = ({
queryMode === 'ENTITY_DETAIL' ? dimensionItems?.concat(metrics || []) : dimensionItems;
return (
<div
className={`${prefixCls}-tip-content`}
onClick={() => {
if (isOptions && currentParseInfo === undefined) {
onSelectParseInfo(parseInfo);
}
}}
>
{index !== undefined && <div>{index + 1}.</div>}
<div className={`${prefixCls}-tip-content`}>
{!!agentType && queryMode !== 'DSL' ? (
<div className={`${prefixCls}-tip-item`}>
{agentType === 'plugin' ? '插件' : '内置'}
@@ -112,37 +129,23 @@ const ParseTip: React.FC<Props> = ({
!!entityName ? (
<div className={`${prefixCls}-tip-item`}>
<div className={`${prefixCls}-tip-item-name`}>{entityAlias}</div>
{!isOptions && (entityAlias === '歌曲' || entityAlias === '艺人') ? (
<SwicthEntity
entityName={entityName}
chatContext={parseInfo}
onSwitchEntity={onSwitchEntity}
/>
) : (
<div className={itemValueClass}>{entityName}</div>
)}
<div className={itemValueClass}>{entityName}</div>
</div>
) : (
<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>
)}
{!queryMode?.includes('ENTITY') && metric && (
<div className={`${prefixCls}-tip-item`}>
<div className={`${prefixCls}-tip-item-name`}></div>
<div className={itemValueClass}>{metric.name}</div>
</div>
)}
{!isOptions && (
<div className={`${prefixCls}-tip-item`}>
<div className={`${prefixCls}-tip-item-name`}></div>
<div className={itemValueClass}>
{startDate === endDate ? startDate : `${startDate} ~ ${endDate}`}
{!queryMode?.includes('ENTITY') &&
metric &&
!dimensions?.some(item => item.bizName?.includes('_id')) && (
<div className={`${prefixCls}-tip-item`}>
<div className={`${prefixCls}-tip-item-name`}></div>
<div className={itemValueClass}>{metric.name}</div>
</div>
</div>
)}
{['METRIC_GROUPBY', 'METRIC_ORDERBY', 'ENTITY_DETAIL', 'DSL'].includes(queryMode) &&
)}
{['METRIC_GROUPBY', 'METRIC_ORDERBY', 'ENTITY_DETAIL', 'DSL'].includes(queryMode!) &&
fields &&
fields.length > 0 && (
<div className={`${prefixCls}-tip-item`}>
@@ -166,7 +169,10 @@ const ParseTip: React.FC<Props> = ({
</div>
)}
{queryMode !== 'ENTITY_ID' &&
entityDimensions &&
entityDimensions?.length > 0 &&
!dimensions?.some(item => item.bizName?.includes('_id')) &&
entityDimensions.some(dimension => dimension.value != null) &&
entityDimensions.map(dimension => (
<div className={`${prefixCls}-tip-item`} key={dimension.itemId}>
<div className={`${prefixCls}-tip-item-name`}>{dimension.name}</div>
@@ -185,49 +191,38 @@ const ParseTip: React.FC<Props> = ({
);
};
const parseInfo = parseInfoOptions[0] || {};
const { modelId, properties, entity, entityInfo, elementMatches, queryMode, dimensionFilters } =
parseInfo || {};
const { type } = properties || {};
const entityAlias = entity?.alias?.[0]?.split('.')?.[0];
const entityName = elementMatches?.find(item => item.element?.type === 'ID')?.element.name;
const entityDimensions = entityInfo?.dimensions?.filter(
item =>
!['zyqk_song_id', 'song_name', 'singer_id', 'zyqk_cmpny_id'].includes(item.bizName) &&
!(
entityInfo?.dimensions?.some(dimension => dimension.bizName === 'singer_id') &&
item.bizName === 'singer_name'
) &&
!(
entityInfo?.dimensions?.some(dimension => dimension.bizName === 'zyqk_cmpny_id') &&
item.bizName === 'cmpny_name'
)
);
const getFilterContent = (filters: any) => {
const itemValueClass = `${prefixCls}-tip-item-value`;
const { startDate, endDate } = dateInfo || {};
return (
<div className={`${prefixCls}-tip-item-filter-content`}>
{filters.map((filter: any) => (
<div className={`${prefixCls}-tip-item-option`} key={filter.name}>
<span>
<span className={`${prefixCls}-tip-item-filter-name`}>{filter.name}</span>
{filter.operator !== '=' && filter.operator !== 'IN' ? ` ${filter.operator} ` : ''}
<div className={`${prefixCls}-tip-item-option`}>
<span className={`${prefixCls}-tip-item-filter-name`}></span>
{dimensions?.some(item => item.bizName?.includes('_id')) ? (
<span className={itemValueClass}>
{startDate === endDate ? startDate : `${startDate} ~ ${endDate}`}
</span>
{/* {queryMode !== 'DSL' && !filter.bizName?.includes('_id') ? ( */}
{!filter.bizName?.includes('_id') ? (
<FilterItem
modelId={modelId}
filters={dimensionFilters}
filter={filter}
onFiltersChange={onFiltersChange}
/>
) : (
<span className={itemValueClass}>{filter.value}</span>
)}
</div>
) : (
<RangePicker
className={`${prefixCls}-range-picker`}
value={[moment(startDate), moment(endDate)]}
onChange={onDateInfoChange}
allowClear={false}
/>
)}
</div>
{filters?.map((filter: any) => (
<FilterItem
modelId={modelId!}
filters={dimensionFilters}
filter={filter}
chatContext={currentParseInfo!}
entityAlias={entityAlias}
agentId={agentId}
onFiltersChange={onFiltersChange}
onSwitchEntity={onSwitchEntity}
key={filter.name}
/>
))}
</div>
);
@@ -244,27 +239,34 @@ const ParseTip: React.FC<Props> = ({
const tipNode = (
<div className={`${prefixCls}-tip`}>
{getTipNode(parseInfo)}
{[
'METRIC_FILTER',
'METRIC_ENTITY',
'ENTITY_DETAIL',
'ENTITY_LIST_FILTER',
'ENTITY_ID',
'DSL',
].includes(queryMode) &&
dimensionFilters &&
dimensionFilters?.length > 0 &&
getFiltersNode()}
{getTipNode()}
{getFiltersNode()}
{(!type || queryMode === 'DSL') && entityAlias && entityAlias !== '厂牌' && entityName && (
<div className={`${prefixCls}-switch-entity-tip`}>
({entityAlias}{entityAlias === '艺人' ? '歌手' : entityAlias}ID切换)
</div>
)}
</div>
);
return getNode(
<div className={`${prefixCls}-title-bar`}>
{(!type || queryMode === 'DSL') && entityAlias && entityAlias !== '厂牌' && entityName && (
<div className={`${prefixCls}-switch-entity-tip`}>
({entityAlias}{entityAlias})
<div>{parseInfoOptions?.length > 1 ? '' : ''}</div>
{parseInfoOptions?.length > 1 && (
<div className={`${prefixCls}-content-options`}>
{parseInfoOptions.map((parseInfo, index) => (
<div
className={`${prefixCls}-content-option ${
parseInfo.id === currentParseInfo?.id ? `${prefixCls}-content-option-active` : ''
}`}
onClick={() => {
onSelectParseInfo(parseInfo);
}}
key={parseInfo.id}
>
{index + 1}
</div>
))}
</div>
)}
</div>,