mirror of
https://github.com/tencentmusic/supersonic.git
synced 2025-12-11 12:07:42 +00:00
[improvement] Enhanced date button, added shortcut TAB (#1387)
This commit is contained in:
@@ -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);
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -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
29035
webapp/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user