[improvement] Enhanced date button, added shortcut TAB (#1387)

This commit is contained in:
open
2024-07-10 14:04:50 +08:00
committed by GitHub
parent 8ef5ce8b76
commit 62e70f5cb7
3 changed files with 16179 additions and 12951 deletions

View File

@@ -1,14 +1,16 @@
import React, { ReactNode } from 'react'; import React, { ReactNode } from 'react';
import { AGG_TYPE_MAP, PREFIX_CLS } from '../../common/constants'; import { AGG_TYPE_MAP, PREFIX_CLS } from '../../common/constants';
import { ChatContextType, DateInfoType, EntityInfoType, FilterItemType } from '../../common/type'; import { ChatContextType, DateInfoType, EntityInfoType, FilterItemType } from '../../common/type';
import { Button, DatePicker } from 'antd'; import { Button, DatePicker, Row, Col } from 'antd';
import { CheckCircleFilled, ReloadOutlined } from '@ant-design/icons'; import { CheckCircleFilled, ReloadOutlined } from '@ant-design/icons';
import Loading from './Loading'; import Loading from './Loading';
import FilterItem from './FilterItem'; import FilterItem from './FilterItem';
import MarkDown from '../ChatMsg/MarkDown'; import MarkDown from '../ChatMsg/MarkDown';
import classNames from 'classnames'; import classNames from 'classnames';
import { isMobile } from '../../utils/utils'; import { isMobile } from '../../utils/utils';
import dayjs from 'dayjs'; import dayjs, { Dayjs } from 'dayjs';
import quarterOfYear from 'dayjs/plugin/quarterOfYear';
dayjs.extend(quarterOfYear);
const { RangePicker } = DatePicker; const { RangePicker } = DatePicker;
@@ -30,10 +32,16 @@ type Props = {
onFiltersChange: (filters: FilterItemType[]) => void; onFiltersChange: (filters: FilterItemType[]) => void;
onDateInfoChange: (dateRange: any) => void; onDateInfoChange: (dateRange: any) => void;
onRefresh: () => void; onRefresh: () => void;
handlePresetClick: any;
}; };
const MAX_OPTION_VALUES_COUNT = 2; const MAX_OPTION_VALUES_COUNT = 2;
type RangeValue = [Dayjs, Dayjs];
type RangeKeys = '近7日' | '近14日' | '近30日' | '本周' | '本月' | '上月' | '本季度' | '本年';
const ParseTip: React.FC<Props> = ({ const ParseTip: React.FC<Props> = ({
parseLoading, parseLoading,
parseInfoOptions, parseInfoOptions,
@@ -52,7 +60,18 @@ const ParseTip: React.FC<Props> = ({
onFiltersChange, onFiltersChange,
onDateInfoChange, onDateInfoChange,
onRefresh, onRefresh,
handlePresetClick
}) => { }) => {
const ranges: Record<RangeKeys, RangeValue> = {
'近7日': [dayjs().subtract(7, 'day'), dayjs()],
'近14日': [dayjs().subtract(14, 'day'), dayjs()],
'近30日': [dayjs().subtract(30, 'day'), dayjs()],
'本周': [dayjs().startOf('week'), dayjs().endOf('week')],
'本月': [dayjs().startOf('month'), dayjs().endOf('month')],
'上月': [dayjs().subtract(1, 'month').startOf('month'), dayjs().subtract(1, 'month').endOf('month')],
'本季度': [dayjs().startOf('quarter'), dayjs().endOf('quarter')], // 使用 quarterOfYear 插件
'本年': [dayjs().startOf('year'), dayjs().endOf('year')],
};
const prefixCls = `${PREFIX_CLS}-item`; const prefixCls = `${PREFIX_CLS}-item`;
const getNode = (tipTitle: ReactNode, tipNode?: ReactNode) => { const getNode = (tipTitle: ReactNode, tipNode?: ReactNode) => {
return ( return (
@@ -66,9 +85,8 @@ const ParseTip: React.FC<Props> = ({
</div> </div>
{(tipNode || tipNode === null) && ( {(tipNode || tipNode === null) && (
<div <div
className={`${prefixCls}-content-container ${ className={`${prefixCls}-content-container ${tipNode === null ? `${prefixCls}-empty-content-container` : ''
tipNode === null ? `${prefixCls}-empty-content-container` : '' }`}
}`}
> >
{tipNode} {tipNode}
</div> </div>
@@ -149,9 +167,9 @@ const ParseTip: React.FC<Props> = ({
) : ( ) : (
<> <>
{(queryMode?.includes('ENTITY') || queryMode === 'LLM_S2SQL') && {(queryMode?.includes('ENTITY') || queryMode === 'LLM_S2SQL') &&
typeof entityId === 'string' && typeof entityId === 'string' &&
!!entityAlias && !!entityAlias &&
!!entityName ? ( !!entityName ? (
<div className={`${prefixCls}-tip-item`}> <div className={`${prefixCls}-tip-item`}>
<div className={`${prefixCls}-tip-item-name`}>{entityAlias}</div> <div className={`${prefixCls}-tip-item-name`}>{entityAlias}</div>
<div className={itemValueClass}>{entityName}</div> <div className={itemValueClass}>{entityName}</div>
@@ -241,9 +259,30 @@ const ParseTip: React.FC<Props> = ({
<RangePicker <RangePicker
value={[dayjs(startDate), dayjs(endDate)]} value={[dayjs(startDate), dayjs(endDate)]}
onChange={onDateInfoChange} onChange={onDateInfoChange}
getPopupContainer={trigger => trigger.parentNode as HTMLElement} format="YYYY/MM/DD"
allowClear={false} renderExtraFooter={() => (
<Row gutter={[28, 28]}>
{Object.keys(ranges).map((key) => (
<Col key={key}>
<label
style={{
backgroundColor: '#F0FDFF',
borderColor: '#33BDFC',
color: '#33BDFC',
borderWidth: 1,
borderStyle: 'solid',
cursor: 'pointer'
}}
onClick={() => handlePresetClick(ranges[key as RangeKeys])}>
{key}
</label>
</Col>
))}
</Row>
)}
/> />
)} )}
</div> </div>
{filters?.map((filter: any, index: number) => ( {filters?.map((filter: any, index: number) => (
@@ -304,9 +343,8 @@ const ParseTip: React.FC<Props> = ({
<div className={`${prefixCls}-content-options`}> <div className={`${prefixCls}-content-options`}>
{parseInfoOptions.map((parseInfo, index) => ( {parseInfoOptions.map((parseInfo, index) => (
<div <div
className={`${prefixCls}-content-option ${ className={`${prefixCls}-content-option ${parseInfo.id === currentParseInfo?.id ? `${prefixCls}-content-option-active` : ''
parseInfo.id === currentParseInfo?.id ? `${prefixCls}-content-option-active` : '' }`}
}`}
onClick={() => { onClick={() => {
onSelectParseInfo(parseInfo); onSelectParseInfo(parseInfo);
}} }}

View File

@@ -19,8 +19,7 @@ import classNames from 'classnames';
import Tools from '../Tools'; import Tools from '../Tools';
import SqlItem from './SqlItem'; import SqlItem from './SqlItem';
import SimilarQuestionItem from './SimilarQuestionItem'; import SimilarQuestionItem from './SimilarQuestionItem';
import dayjs from 'dayjs'; import dayjs, { Dayjs } from 'dayjs';
type Props = { type Props = {
msg: string; msg: string;
conversationId?: number; conversationId?: number;
@@ -235,16 +234,37 @@ const ChatItem: React.FC<Props> = ({
setDimensionFilters(dimensionFilters); setDimensionFilters(dimensionFilters);
}; };
const onDateInfoChange = (dateRange: any) => { type RangeValue = [Dayjs, Dayjs];
const [selectedRange, setSelectedRange] = useState<RangeValue | null>(null);
const onDateInfoChange = (dates: [Dayjs | null, Dayjs | null] | null) => {
if (dates && dates[0] && dates[1]) {
const [start, end] = dates;
setSelectedRange([start, end] as RangeValue);
setDateInfo({
...(dateInfo || {}),
startDate: dayjs(start).format('YYYY-MM-DD'),
endDate: dayjs(end).format('YYYY-MM-DD'),
dateMode: 'BETWEEN',
unit: 0,
});
} else {
setSelectedRange(null);
}
};
const handlePresetClick = (range: RangeValue) => {
setSelectedRange(range);
setDateInfo({ setDateInfo({
...(dateInfo || {}), ...(dateInfo || {}),
startDate: dayjs(dateRange[0]).format('YYYY-MM-DD'), startDate: dayjs(range[0]).format('YYYY-MM-DD'),
endDate: dayjs(dateRange[1]).format('YYYY-MM-DD'), endDate: dayjs(range[1]).format('YYYY-MM-DD'),
dateMode: 'BETWEEN', dateMode: 'BETWEEN',
unit: 0, unit: 0,
}); });
}; };
const onRefresh = async () => { const onRefresh = async () => {
setEntitySwitchLoading(true); setEntitySwitchLoading(true);
const { dimensions, metrics, id, queryId } = parseInfo || {}; const { dimensions, metrics, id, queryId } = parseInfo || {};
@@ -341,6 +361,7 @@ const ChatItem: React.FC<Props> = ({
onFiltersChange={onFiltersChange} onFiltersChange={onFiltersChange}
onDateInfoChange={onDateInfoChange} onDateInfoChange={onDateInfoChange}
onRefresh={onRefresh} onRefresh={onRefresh}
handlePresetClick={handlePresetClick}
/> />
{executeMode && ( {executeMode && (
<> <>

29035
webapp/pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff