test-chat-sdk 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.prettierrc.js +24 -0
- package/README.md +46 -0
- package/config/env.js +104 -0
- package/config/getHttpsConfig.js +66 -0
- package/config/jest/babelTransform.js +29 -0
- package/config/jest/cssTransform.js +14 -0
- package/config/jest/fileTransform.js +40 -0
- package/config/modules.js +134 -0
- package/config/paths.js +77 -0
- package/config/webpack/persistentCache/createEnvironmentHash.js +9 -0
- package/config/webpack.config.js +785 -0
- package/config/webpackDevServer.config.js +127 -0
- package/dist/Chat/AgentList/index.d.ts +9 -0
- package/dist/Chat/ChatFooter/index.d.ts +17 -0
- package/dist/Chat/Conversation/index.d.ts +11 -0
- package/dist/Chat/MessageContainer/index.d.ts +19 -0
- package/dist/Chat/MobileAgents/index.d.ts +11 -0
- package/dist/Chat/components/AgentTip/index.d.ts +8 -0
- package/dist/Chat/components/ConversationModal/index.d.ts +10 -0
- package/dist/Chat/components/CopilotAvatar/index.d.ts +2 -0
- package/dist/Chat/components/Message.d.ts +10 -0
- package/dist/Chat/components/RecommendQuestions/index.d.ts +6 -0
- package/dist/Chat/components/Text.d.ts +9 -0
- package/dist/Chat/constants.d.ts +19 -0
- package/dist/Chat/index.d.ts +17 -0
- package/dist/Chat/service.d.ts +11 -0
- package/dist/Chat/type.d.ts +97 -0
- package/dist/Copilot/constants.d.ts +11 -0
- package/dist/Copilot/index.d.ts +13 -0
- package/dist/ShowCase/index.d.ts +8 -0
- package/dist/ShowCase/service.d.ts +2 -0
- package/dist/ShowCase/type.d.ts +11 -0
- package/dist/common/constants.d.ts +58 -0
- package/dist/common/env.d.ts +3 -0
- package/dist/common/type.d.ts +247 -0
- package/dist/components/ChatItem/ExecuteItem.d.ts +25 -0
- package/dist/components/ChatItem/ExpandParseTip.d.ts +20 -0
- package/dist/components/ChatItem/FilterItem.d.ts +17 -0
- package/dist/components/ChatItem/Loading.d.ts +2 -0
- package/dist/components/ChatItem/ParseTip.d.ts +26 -0
- package/dist/components/ChatItem/ParseTipUtils.d.ts +10 -0
- package/dist/components/ChatItem/SimilarQuestionItem.d.ts +10 -0
- package/dist/components/ChatItem/SqlItem.d.ts +17 -0
- package/dist/components/ChatItem/SwitchEntity.d.ts +9 -0
- package/dist/components/ChatItem/Text.d.ts +6 -0
- package/dist/components/ChatItem/Typing.d.ts +2 -0
- package/dist/components/ChatItem/index.d.ts +33 -0
- package/dist/components/ChatMsg/ApplyAuth/index.d.ts +7 -0
- package/dist/components/ChatMsg/Bar/index.d.ts +13 -0
- package/dist/components/ChatMsg/DateOptions/index.d.ts +9 -0
- package/dist/components/ChatMsg/FilterSection/index.d.ts +8 -0
- package/dist/components/ChatMsg/MarkDown/index.d.ts +10 -0
- package/dist/components/ChatMsg/Message/index.d.ts +18 -0
- package/dist/components/ChatMsg/MetricCard/PeriodCompareItem.d.ts +7 -0
- package/dist/components/ChatMsg/MetricCard/index.d.ts +10 -0
- package/dist/components/ChatMsg/MetricTrend/MetricInfo.d.ts +8 -0
- package/dist/components/ChatMsg/MetricTrend/MetricTrendChart.d.ts +14 -0
- package/dist/components/ChatMsg/MetricTrend/MultiMetricsTrendChart.d.ts +12 -0
- package/dist/components/ChatMsg/MetricTrend/index.d.ts +16 -0
- package/dist/components/ChatMsg/NoPermissionChart/index.d.ts +8 -0
- package/dist/components/ChatMsg/Pie/PieChart.d.ts +11 -0
- package/dist/components/ChatMsg/Pie/index.d.ts +14 -0
- package/dist/components/ChatMsg/Table/index.d.ts +12 -0
- package/dist/components/ChatMsg/Text/index.d.ts +9 -0
- package/dist/components/ChatMsg/WebPage/index.d.ts +8 -0
- package/dist/components/ChatMsg/index.d.ts +15 -0
- package/dist/components/DrillDownDimensions/DimensionSection.d.ts +11 -0
- package/dist/components/DrillDownDimensions/index.d.ts +13 -0
- package/dist/components/IconFont/index.d.ts +3 -0
- package/dist/components/MetricOptions/index.d.ts +11 -0
- package/dist/components/RecommendOptions/index.d.ts +9 -0
- package/dist/components/Tools/FeedbackModal.d.ts +9 -0
- package/dist/components/Tools/index.d.ts +12 -0
- package/dist/demo/Chat.d.ts +2 -0
- package/dist/demo/ChatDemo.d.ts +4 -0
- package/dist/demo/CopilotDemo.d.ts +2 -0
- package/dist/hooks/index.d.ts +3 -0
- package/dist/hooks/useComposing.d.ts +5 -0
- package/dist/hooks/useExportByEcharts.d.ts +10 -0
- package/dist/hooks/useMethodRegister.d.ts +4 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.es.js +1 -0
- package/dist/service/axiosInstance.d.ts +3 -0
- package/dist/service/index.d.ts +25 -0
- package/dist/utils/utils.d.ts +45 -0
- package/package.json +214 -0
- package/public/favicon.ico +0 -0
- package/public/index.html +43 -0
- package/public/manifest.json +15 -0
- package/public/robots.txt +3 -0
- package/rollup/rollup.config.mjs +37 -0
- package/rollup/rollup.esm.config.mjs +21 -0
- package/rollup/rollup.umd.config.mjs +30 -0
- package/scripts/build.js +217 -0
- package/scripts/start.js +154 -0
- package/scripts/test.js +52 -0
- package/src/Chat/AgentList/index.tsx +52 -0
- package/src/Chat/AgentList/style.module.less +83 -0
- package/src/Chat/ChatFooter/index.tsx +423 -0
- package/src/Chat/ChatFooter/style.module.less +225 -0
- package/src/Chat/Conversation/index.tsx +236 -0
- package/src/Chat/Conversation/style.module.less +171 -0
- package/src/Chat/MessageContainer/index.tsx +145 -0
- package/src/Chat/MessageContainer/style.module.less +53 -0
- package/src/Chat/MobileAgents/index.tsx +62 -0
- package/src/Chat/MobileAgents/style.module.less +55 -0
- package/src/Chat/components/AgentTip/index.tsx +48 -0
- package/src/Chat/components/AgentTip/style.module.less +44 -0
- package/src/Chat/components/ConversationModal/index.tsx +65 -0
- package/src/Chat/components/CopilotAvatar/index.tsx +8 -0
- package/src/Chat/components/CopilotAvatar/style.module.less +13 -0
- package/src/Chat/components/Message.tsx +38 -0
- package/src/Chat/components/RecommendQuestions/index.tsx +64 -0
- package/src/Chat/components/RecommendQuestions/style.module.less +36 -0
- package/src/Chat/components/Text.tsx +42 -0
- package/src/Chat/components/style.module.less +311 -0
- package/src/Chat/constants.ts +37 -0
- package/src/Chat/index.tsx +526 -0
- package/src/Chat/service.ts +49 -0
- package/src/Chat/style.module.less +119 -0
- package/src/Chat/type.ts +107 -0
- package/src/Copilot/constants.ts +11 -0
- package/src/Copilot/index.tsx +149 -0
- package/src/Copilot/style.module.less +151 -0
- package/src/ShowCase/index.tsx +120 -0
- package/src/ShowCase/service.ts +12 -0
- package/src/ShowCase/style.module.less +46 -0
- package/src/ShowCase/type.ts +14 -0
- package/src/common/constants.ts +93 -0
- package/src/common/env.ts +5 -0
- package/src/common/type.ts +270 -0
- package/src/components/ChatItem/ExecuteItem.tsx +210 -0
- package/src/components/ChatItem/ExpandParseTip.tsx +333 -0
- package/src/components/ChatItem/FilterItem.tsx +209 -0
- package/src/components/ChatItem/Loading.tsx +14 -0
- package/src/components/ChatItem/ParseTip.tsx +322 -0
- package/src/components/ChatItem/ParseTipUtils.tsx +205 -0
- package/src/components/ChatItem/SimilarQuestionItem.tsx +84 -0
- package/src/components/ChatItem/SqlItem.tsx +410 -0
- package/src/components/ChatItem/SwitchEntity.tsx +52 -0
- package/src/components/ChatItem/Text.tsx +17 -0
- package/src/components/ChatItem/Typing.tsx +19 -0
- package/src/components/ChatItem/index.tsx +843 -0
- package/src/components/ChatItem/style.less +670 -0
- package/src/components/ChatMsg/ApplyAuth/index.tsx +30 -0
- package/src/components/ChatMsg/ApplyAuth/style.less +13 -0
- package/src/components/ChatMsg/Bar/index.tsx +208 -0
- package/src/components/ChatMsg/Bar/style.less +60 -0
- package/src/components/ChatMsg/DateOptions/index.tsx +46 -0
- package/src/components/ChatMsg/DateOptions/style.less +43 -0
- package/src/components/ChatMsg/FilterSection/index.tsx +42 -0
- package/src/components/ChatMsg/FilterSection/style.less +37 -0
- package/src/components/ChatMsg/MarkDown/index.tsx +26 -0
- package/src/components/ChatMsg/MarkDown/style.less +9 -0
- package/src/components/ChatMsg/Message/index.tsx +105 -0
- package/src/components/ChatMsg/Message/style.less +119 -0
- package/src/components/ChatMsg/MetricCard/PeriodCompareItem.tsx +29 -0
- package/src/components/ChatMsg/MetricCard/index.tsx +80 -0
- package/src/components/ChatMsg/MetricCard/style.less +126 -0
- package/src/components/ChatMsg/MetricTrend/MetricInfo.tsx +60 -0
- package/src/components/ChatMsg/MetricTrend/MetricTrendChart.tsx +235 -0
- package/src/components/ChatMsg/MetricTrend/MultiMetricsTrendChart.tsx +162 -0
- package/src/components/ChatMsg/MetricTrend/index.tsx +127 -0
- package/src/components/ChatMsg/MetricTrend/style.less +195 -0
- package/src/components/ChatMsg/NoPermissionChart/index.tsx +28 -0
- package/src/components/ChatMsg/NoPermissionChart/style.less +26 -0
- package/src/components/ChatMsg/Pie/PieChart.tsx +120 -0
- package/src/components/ChatMsg/Pie/index.tsx +88 -0
- package/src/components/ChatMsg/Pie/style.less +43 -0
- package/src/components/ChatMsg/Table/index.tsx +103 -0
- package/src/components/ChatMsg/Table/style.less +131 -0
- package/src/components/ChatMsg/Text/index.tsx +70 -0
- package/src/components/ChatMsg/Text/style.less +38 -0
- package/src/components/ChatMsg/WebPage/index.tsx +125 -0
- package/src/components/ChatMsg/index.tsx +428 -0
- package/src/components/ChatMsg/style.less +28 -0
- package/src/components/DrillDownDimensions/DimensionSection.tsx +99 -0
- package/src/components/DrillDownDimensions/index.tsx +76 -0
- package/src/components/DrillDownDimensions/style.less +64 -0
- package/src/components/IconFont/index.tsx +7 -0
- package/src/components/MetricOptions/index.tsx +75 -0
- package/src/components/MetricOptions/style.less +69 -0
- package/src/components/RecommendOptions/index.tsx +126 -0
- package/src/components/RecommendOptions/style.less +24 -0
- package/src/components/Tools/FeedbackModal.tsx +55 -0
- package/src/components/Tools/index.tsx +126 -0
- package/src/components/Tools/style.less +67 -0
- package/src/demo/Chat.tsx +73 -0
- package/src/demo/ChatDemo.tsx +14 -0
- package/src/demo/CopilotDemo.tsx +43 -0
- package/src/demo/style.module.less +19 -0
- package/src/hooks/index.ts +3 -0
- package/src/hooks/useComposing.ts +31 -0
- package/src/hooks/useExportByEcharts.ts +41 -0
- package/src/hooks/useMethodRegister.ts +25 -0
- package/src/index.tsx +44 -0
- package/src/service/axiosInstance.ts +58 -0
- package/src/service/index.ts +174 -0
- package/src/setupProxy.js +18 -0
- package/src/setupTests.ts +5 -0
- package/src/styles/global.less +52 -0
- package/src/styles/index.less +39 -0
- package/src/styles/reboot.less +14 -0
- package/src/styles/variables.less +80 -0
- package/src/typings.d.ts +179 -0
- package/src/utils/utils.ts +346 -0
- package/tsconfig.build.json +20 -0
- package/tsconfig.json +27 -0
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
import React, { ReactNode, useEffect, useState } from 'react';
|
|
2
|
+
import { ChatContextType, DateInfoType, EntityInfoType, FilterItemType } from '../../common/type';
|
|
3
|
+
import { Button, DatePicker, Row, Col } from 'antd';
|
|
4
|
+
import { CheckCircleFilled, CloseCircleFilled, ReloadOutlined } from '@ant-design/icons';
|
|
5
|
+
import Loading from './Loading';
|
|
6
|
+
import FilterItem from './FilterItem';
|
|
7
|
+
import MarkDown from '../ChatMsg/MarkDown';
|
|
8
|
+
import classNames from 'classnames';
|
|
9
|
+
import { isMobile } from '../../utils/utils';
|
|
10
|
+
import dayjs, { Dayjs } from 'dayjs';
|
|
11
|
+
import quarterOfYear from 'dayjs/plugin/quarterOfYear';
|
|
12
|
+
import { prefixCls, getTipNode } from './ParseTipUtils';
|
|
13
|
+
import { getDataSetDetail } from '../../service';
|
|
14
|
+
|
|
15
|
+
import 'dayjs/locale/zh-cn';
|
|
16
|
+
|
|
17
|
+
dayjs.extend(quarterOfYear);
|
|
18
|
+
dayjs.locale('zh-cn');
|
|
19
|
+
|
|
20
|
+
const { RangePicker } = DatePicker;
|
|
21
|
+
|
|
22
|
+
type Props = {
|
|
23
|
+
parseLoading: boolean;
|
|
24
|
+
parseInfoOptions: ChatContextType[];
|
|
25
|
+
parseTip: string;
|
|
26
|
+
currentParseInfo?: ChatContextType;
|
|
27
|
+
agentId?: number;
|
|
28
|
+
dimensionFilters: FilterItemType[];
|
|
29
|
+
dateInfo: DateInfoType;
|
|
30
|
+
entityInfo: EntityInfoType;
|
|
31
|
+
integrateSystem?: string;
|
|
32
|
+
parseTimeCost?: number;
|
|
33
|
+
isDeveloper?: boolean;
|
|
34
|
+
isSimpleMode?: boolean;
|
|
35
|
+
onSelectParseInfo: (parseInfo: ChatContextType) => void;
|
|
36
|
+
onSwitchEntity: (entityId: string) => void;
|
|
37
|
+
onFiltersChange: (filters: FilterItemType[]) => void;
|
|
38
|
+
onDateInfoChange: (dateRange: any) => void;
|
|
39
|
+
onRefresh: (parseInfo?: ChatContextType) => void;
|
|
40
|
+
handlePresetClick: any;
|
|
41
|
+
setSelectedDataSetIds: (ids: number[]) => void;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
type RangeValue = [Dayjs, Dayjs];
|
|
45
|
+
type RangeKeys = '近7日' | '近14日' | '近30日' | '本周' | '本月' | '上月' | '本季度' | '本年';
|
|
46
|
+
|
|
47
|
+
const ParseTip: React.FC<Props> = ({
|
|
48
|
+
isSimpleMode = false,
|
|
49
|
+
parseLoading,
|
|
50
|
+
parseInfoOptions,
|
|
51
|
+
parseTip,
|
|
52
|
+
currentParseInfo,
|
|
53
|
+
agentId,
|
|
54
|
+
dimensionFilters,
|
|
55
|
+
dateInfo,
|
|
56
|
+
entityInfo,
|
|
57
|
+
integrateSystem,
|
|
58
|
+
parseTimeCost,
|
|
59
|
+
isDeveloper,
|
|
60
|
+
onSelectParseInfo,
|
|
61
|
+
onSwitchEntity,
|
|
62
|
+
onFiltersChange,
|
|
63
|
+
onDateInfoChange,
|
|
64
|
+
onRefresh,
|
|
65
|
+
handlePresetClick,
|
|
66
|
+
setSelectedDataSetIds,
|
|
67
|
+
}) => {
|
|
68
|
+
const [availableDataSets, setAvailableDataSets] = useState<any[]>([]);
|
|
69
|
+
const [loadingDataSets, setLoadingDataSets] = useState(false);
|
|
70
|
+
|
|
71
|
+
// 获取候选数据集的详细信息
|
|
72
|
+
useEffect(() => {
|
|
73
|
+
const fetchCandidateDataSets = async () => {
|
|
74
|
+
// 优先使用parseInfoOptions中的所有数据集选项,确保切换后仍然显示所有可用数据集
|
|
75
|
+
const dataSetsFromOptions = parseInfoOptions.map(option => option.dataSet).filter(Boolean);
|
|
76
|
+
|
|
77
|
+
// 获取所有唯一的数据集ID(从parseInfoOptions和currentParseInfo中)
|
|
78
|
+
const allDataSetIds = new Set<number>();
|
|
79
|
+
|
|
80
|
+
// 从parseInfoOptions中添加所有数据集ID
|
|
81
|
+
parseInfoOptions.forEach(option => {
|
|
82
|
+
if (option.dataSet?.id) {
|
|
83
|
+
allDataSetIds.add(option.dataSet.id);
|
|
84
|
+
}
|
|
85
|
+
if (option.dataSetIds) {
|
|
86
|
+
option.dataSetIds.forEach(id => allDataSetIds.add(id));
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// 从currentParseInfo中添加数据集ID
|
|
91
|
+
if (currentParseInfo?.dataSetIds) {
|
|
92
|
+
currentParseInfo.dataSetIds.forEach(id => allDataSetIds.add(id));
|
|
93
|
+
}
|
|
94
|
+
if (currentParseInfo?.dataSet?.id) {
|
|
95
|
+
allDataSetIds.add(currentParseInfo.dataSet.id);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const uniqueDataSetIds = Array.from(allDataSetIds);
|
|
99
|
+
|
|
100
|
+
if (uniqueDataSetIds.length > 0) {
|
|
101
|
+
setLoadingDataSets(true);
|
|
102
|
+
try {
|
|
103
|
+
// 获取所有唯一数据集的详细信息
|
|
104
|
+
const dataSetPromises = uniqueDataSetIds.map(dataSetId =>
|
|
105
|
+
getDataSetDetail(dataSetId).then(response => response.data?.data || response.data)
|
|
106
|
+
);
|
|
107
|
+
const dataSetDetails = await Promise.all(dataSetPromises);
|
|
108
|
+
setAvailableDataSets(dataSetDetails);
|
|
109
|
+
} catch (error) {
|
|
110
|
+
console.error('获取候选数据集信息失败:', error);
|
|
111
|
+
// 如果API调用失败,回退到使用parseInfoOptions中的数据集信息
|
|
112
|
+
setAvailableDataSets(dataSetsFromOptions);
|
|
113
|
+
} finally {
|
|
114
|
+
setLoadingDataSets(false);
|
|
115
|
+
}
|
|
116
|
+
} else {
|
|
117
|
+
// 始终使用parseInfoOptions中的数据集信息,确保显示所有可用数据集
|
|
118
|
+
setAvailableDataSets(dataSetsFromOptions);
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
fetchCandidateDataSets();
|
|
123
|
+
}, [currentParseInfo?.dataSetIds, currentParseInfo?.dataSet?.id, parseInfoOptions]);
|
|
124
|
+
|
|
125
|
+
const ranges: Record<RangeKeys, RangeValue> = {
|
|
126
|
+
近7日: [dayjs().subtract(7, 'day'), dayjs()],
|
|
127
|
+
近14日: [dayjs().subtract(14, 'day'), dayjs()],
|
|
128
|
+
近30日: [dayjs().subtract(30, 'day'), dayjs()],
|
|
129
|
+
本周: [dayjs().startOf('week'), dayjs().endOf('week')],
|
|
130
|
+
本月: [dayjs().startOf('month'), dayjs().endOf('month')],
|
|
131
|
+
上月: [
|
|
132
|
+
dayjs().subtract(1, 'month').startOf('month'),
|
|
133
|
+
dayjs().subtract(1, 'month').endOf('month'),
|
|
134
|
+
],
|
|
135
|
+
本季度: [dayjs().startOf('quarter'), dayjs().endOf('quarter')], // 使用 quarterOfYear 插件
|
|
136
|
+
本年: [dayjs().startOf('year'), dayjs().endOf('year')],
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
const getNode = (tipTitle: ReactNode, tipNode?: ReactNode, failed?: boolean) => {
|
|
140
|
+
return (
|
|
141
|
+
<div className={`${prefixCls}-parse-tip`}>
|
|
142
|
+
<div className={`${prefixCls}-title-bar`}>
|
|
143
|
+
{!failed ? (
|
|
144
|
+
<CheckCircleFilled className={`${prefixCls}-step-icon`} />
|
|
145
|
+
) : (
|
|
146
|
+
<CloseCircleFilled className={`${prefixCls}-step-error-icon`} />
|
|
147
|
+
)}
|
|
148
|
+
<div className={`${prefixCls}-step-title`}>
|
|
149
|
+
{tipTitle}
|
|
150
|
+
{tipNode === undefined && <Loading />}
|
|
151
|
+
</div>
|
|
152
|
+
</div>
|
|
153
|
+
{(tipNode || tipNode === null) && (
|
|
154
|
+
<div
|
|
155
|
+
className={classNames(
|
|
156
|
+
`${prefixCls}-content-container`,
|
|
157
|
+
tipNode === null && `${prefixCls}-empty-content-container`,
|
|
158
|
+
failed && `${prefixCls}-content-container-failed`
|
|
159
|
+
)}
|
|
160
|
+
>
|
|
161
|
+
{tipNode}
|
|
162
|
+
</div>
|
|
163
|
+
)}
|
|
164
|
+
</div>
|
|
165
|
+
);
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
if (parseLoading) {
|
|
169
|
+
return getNode('意图解析中');
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (parseTip) {
|
|
173
|
+
return getNode(
|
|
174
|
+
<>
|
|
175
|
+
意图解析失败
|
|
176
|
+
{!!parseTimeCost && isDeveloper && (
|
|
177
|
+
<span className={`${prefixCls}-title-tip`}>(耗时: {parseTimeCost}ms)</span>
|
|
178
|
+
)}
|
|
179
|
+
</>,
|
|
180
|
+
parseTip,
|
|
181
|
+
true
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (isSimpleMode || parseInfoOptions.length === 0) {
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const {
|
|
190
|
+
modelId,
|
|
191
|
+
queryMode,
|
|
192
|
+
properties,
|
|
193
|
+
entity,
|
|
194
|
+
nativeQuery,
|
|
195
|
+
textInfo = '',
|
|
196
|
+
} = currentParseInfo || {};
|
|
197
|
+
|
|
198
|
+
const entityAlias = entity?.alias?.[0]?.split('.')?.[0];
|
|
199
|
+
|
|
200
|
+
const getFilterContent = (filters: any) => {
|
|
201
|
+
const itemValueClass = `${prefixCls}-tip-item-value`;
|
|
202
|
+
const { startDate, endDate } = dateInfo || {};
|
|
203
|
+
const tipItemOptionClass = classNames(`${prefixCls}-tip-item-option`, {
|
|
204
|
+
[`${prefixCls}-mobile-tip-item-option`]: isMobile,
|
|
205
|
+
});
|
|
206
|
+
return (
|
|
207
|
+
<div className={`${prefixCls}-tip-item-filter-content`}>
|
|
208
|
+
{!!dateInfo && (
|
|
209
|
+
<div className={tipItemOptionClass}>
|
|
210
|
+
<span className={`${prefixCls}-tip-item-filter-name`}>数据时间:</span>
|
|
211
|
+
{nativeQuery ? (
|
|
212
|
+
<span className={itemValueClass}>
|
|
213
|
+
{startDate === endDate ? startDate : `${startDate} ~ ${endDate}`}
|
|
214
|
+
</span>
|
|
215
|
+
) : (
|
|
216
|
+
<RangePicker
|
|
217
|
+
value={[dayjs(startDate), dayjs(endDate)]}
|
|
218
|
+
onChange={onDateInfoChange}
|
|
219
|
+
format="YYYY-MM-DD"
|
|
220
|
+
renderExtraFooter={() => (
|
|
221
|
+
<Row gutter={[28, 28]}>
|
|
222
|
+
{Object.keys(ranges).map(key => (
|
|
223
|
+
<Col key={key}>
|
|
224
|
+
<Button
|
|
225
|
+
size="small"
|
|
226
|
+
onClick={() => handlePresetClick(ranges[key as RangeKeys])}
|
|
227
|
+
>
|
|
228
|
+
{key}
|
|
229
|
+
</Button>
|
|
230
|
+
</Col>
|
|
231
|
+
))}
|
|
232
|
+
</Row>
|
|
233
|
+
)}
|
|
234
|
+
/>
|
|
235
|
+
)}
|
|
236
|
+
</div>
|
|
237
|
+
)}
|
|
238
|
+
{filters?.map((filter: any, index: number) => (
|
|
239
|
+
<FilterItem
|
|
240
|
+
modelId={modelId!}
|
|
241
|
+
filters={filters}
|
|
242
|
+
filter={filter}
|
|
243
|
+
index={index}
|
|
244
|
+
chatContext={currentParseInfo!}
|
|
245
|
+
entityAlias={entityAlias}
|
|
246
|
+
agentId={agentId}
|
|
247
|
+
integrateSystem={integrateSystem}
|
|
248
|
+
onFiltersChange={onFiltersChange}
|
|
249
|
+
onSwitchEntity={onSwitchEntity}
|
|
250
|
+
key={`${filter.name}_${index}`}
|
|
251
|
+
/>
|
|
252
|
+
))}
|
|
253
|
+
</div>
|
|
254
|
+
);
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
const getFiltersNode = () => {
|
|
258
|
+
return (
|
|
259
|
+
<>
|
|
260
|
+
{(!!dateInfo || !!dimensionFilters?.length) && (
|
|
261
|
+
<div className={`${prefixCls}-tip-item`}>
|
|
262
|
+
<div className={`${prefixCls}-tip-item-name`}>筛选条件:</div>
|
|
263
|
+
<div className={`${prefixCls}-tip-item-content`}>
|
|
264
|
+
{getFilterContent(dimensionFilters)}
|
|
265
|
+
</div>
|
|
266
|
+
</div>
|
|
267
|
+
)}
|
|
268
|
+
<Button className={`${prefixCls}-reload`} size="small" onClick={() => onRefresh(currentParseInfo)}>
|
|
269
|
+
<ReloadOutlined />
|
|
270
|
+
重新查询
|
|
271
|
+
</Button>
|
|
272
|
+
</>
|
|
273
|
+
);
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
const { type: agentType } = properties || {};
|
|
277
|
+
|
|
278
|
+
const tipNode = (
|
|
279
|
+
<div className={`${prefixCls}-tip`}>
|
|
280
|
+
{getTipNode({
|
|
281
|
+
parseInfo: currentParseInfo,
|
|
282
|
+
dimensionFilters,
|
|
283
|
+
entityInfo,
|
|
284
|
+
onSwitchDataSet: (selectedDataSet) => {
|
|
285
|
+
// 设置选择的数据集ID并重新调用查询
|
|
286
|
+
if (selectedDataSet.id !== currentParseInfo?.dataSet?.id) {
|
|
287
|
+
// 直接设置数据集ID并重新调用查询
|
|
288
|
+
setSelectedDataSetIds([selectedDataSet.id]);
|
|
289
|
+
// 立即使用新选择的数据集ID刷新查询
|
|
290
|
+
// 先更新状态,然后调用onRefresh
|
|
291
|
+
setTimeout(() => {
|
|
292
|
+
onRefresh({
|
|
293
|
+
...currentParseInfo,
|
|
294
|
+
dataSet: selectedDataSet,
|
|
295
|
+
dataSetIds: [selectedDataSet.id],
|
|
296
|
+
id: currentParseInfo?.id || 0
|
|
297
|
+
} as ChatContextType);
|
|
298
|
+
}, 0);
|
|
299
|
+
}
|
|
300
|
+
},
|
|
301
|
+
availableDataSets: availableDataSets,
|
|
302
|
+
loadingDataSets: loadingDataSets
|
|
303
|
+
})}
|
|
304
|
+
{!(!!agentType && queryMode !== 'LLM_S2SQL') && getFiltersNode()}
|
|
305
|
+
</div>
|
|
306
|
+
);
|
|
307
|
+
|
|
308
|
+
return getNode(
|
|
309
|
+
<div className={`${prefixCls}-title-bar`}>
|
|
310
|
+
<div>
|
|
311
|
+
意图解析
|
|
312
|
+
{!!parseTimeCost && isDeveloper && (
|
|
313
|
+
<span className={`${prefixCls}-title-tip`}>(耗时: {parseTimeCost}ms)</span>
|
|
314
|
+
)}
|
|
315
|
+
</div>
|
|
316
|
+
</div>,
|
|
317
|
+
// isSimpleMode ? <MarkDown markdown={textInfo} /> : queryMode === 'PLAIN_TEXT' ? null : tipNode
|
|
318
|
+
queryMode === 'PLAIN_TEXT' ? null : tipNode
|
|
319
|
+
);
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
export default ParseTip;
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { ChatContextTypeQueryTypeEnum } from '../../common/constants';
|
|
2
|
+
import { AGG_TYPE_MAP, PREFIX_CLS } from '../../common/constants';
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import { Dropdown, Menu } from 'antd';
|
|
5
|
+
|
|
6
|
+
export const MAX_OPTION_VALUES_COUNT = 2;
|
|
7
|
+
|
|
8
|
+
export const prefixCls = `${PREFIX_CLS}-item`;
|
|
9
|
+
|
|
10
|
+
export const getTipNode = ({ parseInfo, dimensionFilters, entityInfo, onSwitchDataSet, availableDataSets, loadingDataSets }) => {
|
|
11
|
+
const {
|
|
12
|
+
dataSet,
|
|
13
|
+
dimensions,
|
|
14
|
+
metrics,
|
|
15
|
+
aggType,
|
|
16
|
+
queryMode,
|
|
17
|
+
queryType,
|
|
18
|
+
properties,
|
|
19
|
+
entity,
|
|
20
|
+
elementMatches,
|
|
21
|
+
} = parseInfo || {};
|
|
22
|
+
const dimensionItems = dimensions?.filter(item => item.type === 'DIMENSION');
|
|
23
|
+
const itemValueClass = `${prefixCls}-tip-item-value`;
|
|
24
|
+
const entityId = dimensionFilters?.length > 0 ? dimensionFilters[0].value : undefined;
|
|
25
|
+
const entityAlias = entity?.alias?.[0]?.split('.')?.[0];
|
|
26
|
+
const entityName = elementMatches?.find(item => item.element?.type === 'ID')?.element.name;
|
|
27
|
+
|
|
28
|
+
const { type: agentType, name: agentName } = properties || {};
|
|
29
|
+
|
|
30
|
+
const fields =
|
|
31
|
+
queryMode === 'TAG_DETAIL' ? dimensionItems?.concat(metrics || []) : dimensionItems;
|
|
32
|
+
|
|
33
|
+
// 处理数据集切换菜单
|
|
34
|
+
const handleDataSetSelect = (selectedDataSet) => {
|
|
35
|
+
if (onSwitchDataSet && selectedDataSet.id !== dataSet?.id) {
|
|
36
|
+
onSwitchDataSet(selectedDataSet);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const renderDataSetMenu = () => {
|
|
41
|
+
if (loadingDataSets) {
|
|
42
|
+
return (
|
|
43
|
+
<Menu>
|
|
44
|
+
<Menu.Item key="loading" disabled>
|
|
45
|
+
<div style={{ padding: '8px 12px', color: '#999' }}>
|
|
46
|
+
加载中...
|
|
47
|
+
</div>
|
|
48
|
+
</Menu.Item>
|
|
49
|
+
</Menu>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (!availableDataSets || availableDataSets.length <= 1) {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const menuItems = availableDataSets
|
|
58
|
+
.map(ds => ({
|
|
59
|
+
key: ds.id,
|
|
60
|
+
label: (
|
|
61
|
+
<div
|
|
62
|
+
onClick={() => handleDataSetSelect(ds)}
|
|
63
|
+
style={{
|
|
64
|
+
padding: '8px 12px',
|
|
65
|
+
cursor: 'pointer',
|
|
66
|
+
backgroundColor: ds.id === dataSet?.id ? '#f0f8ff' : 'transparent',
|
|
67
|
+
fontWeight: ds.id === dataSet?.id ? 'bold' : 'normal',
|
|
68
|
+
color: ds.id === dataSet?.id ? '#1890ff' : '#333'
|
|
69
|
+
}}
|
|
70
|
+
>
|
|
71
|
+
{ds.name}
|
|
72
|
+
{ds.id === dataSet?.id && (
|
|
73
|
+
<span style={{ marginLeft: '8px', color: '#52c41a', fontSize: '12px' }}>
|
|
74
|
+
✓ 当前使用
|
|
75
|
+
</span>
|
|
76
|
+
)}
|
|
77
|
+
</div>
|
|
78
|
+
),
|
|
79
|
+
}));
|
|
80
|
+
|
|
81
|
+
if (menuItems.length === 0) {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return (
|
|
86
|
+
<Menu>
|
|
87
|
+
{menuItems.map(item => (
|
|
88
|
+
<Menu.Item key={item.key}>
|
|
89
|
+
{item.label}
|
|
90
|
+
</Menu.Item>
|
|
91
|
+
))}
|
|
92
|
+
</Menu>
|
|
93
|
+
);
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
return (
|
|
97
|
+
<div className={`${prefixCls}-tip-content`}>
|
|
98
|
+
{!!agentType && queryMode !== 'LLM_S2SQL' ? (
|
|
99
|
+
<div className={`${prefixCls}-tip-item`}>
|
|
100
|
+
将由{agentType === 'plugin' ? '插件' : '内置'}工具
|
|
101
|
+
<span className={itemValueClass}>{agentName}</span>来解答
|
|
102
|
+
</div>
|
|
103
|
+
) : (
|
|
104
|
+
<>
|
|
105
|
+
{(queryMode?.includes('ENTITY') || queryMode === 'LLM_S2SQL') &&
|
|
106
|
+
typeof entityId === 'string' &&
|
|
107
|
+
!!entityAlias &&
|
|
108
|
+
!!entityName ? (
|
|
109
|
+
<div className={`${prefixCls}-tip-item`}>
|
|
110
|
+
<div className={`${prefixCls}-tip-item-name`}>{entityAlias}:</div>
|
|
111
|
+
<div className={itemValueClass}>{entityName}</div>
|
|
112
|
+
</div>
|
|
113
|
+
) : (
|
|
114
|
+
<div className={`${prefixCls}-tip-item`}>
|
|
115
|
+
<div className={`${prefixCls}-tip-item-name`}>数据集:</div>
|
|
116
|
+
<div className={itemValueClass}>
|
|
117
|
+
<Dropdown
|
|
118
|
+
overlay={renderDataSetMenu() || <Menu />}
|
|
119
|
+
placement="bottomLeft"
|
|
120
|
+
trigger={['click']}
|
|
121
|
+
disabled={loadingDataSets || !availableDataSets || availableDataSets.length <= 1}
|
|
122
|
+
>
|
|
123
|
+
<span
|
|
124
|
+
style={{
|
|
125
|
+
cursor: (loadingDataSets || !availableDataSets || availableDataSets.length <= 1) ? 'default' : 'pointer',
|
|
126
|
+
textDecoration: (loadingDataSets || !availableDataSets || availableDataSets.length <= 1) ? 'none' : 'underline'
|
|
127
|
+
}}
|
|
128
|
+
>
|
|
129
|
+
{loadingDataSets ? '加载中...' : dataSet?.name}
|
|
130
|
+
{!loadingDataSets && availableDataSets && availableDataSets.length > 1 && (
|
|
131
|
+
<span style={{ marginLeft: '4px', fontSize: '12px' }}>▼</span>
|
|
132
|
+
)}
|
|
133
|
+
</span>
|
|
134
|
+
</Dropdown>
|
|
135
|
+
</div>
|
|
136
|
+
</div>
|
|
137
|
+
)}
|
|
138
|
+
{(queryType === ChatContextTypeQueryTypeEnum.AGGREGATE ||
|
|
139
|
+
queryType === 'METRIC_TAG' ||
|
|
140
|
+
queryType === 'DETAIL') && (
|
|
141
|
+
<div className={`${prefixCls}-tip-item`}>
|
|
142
|
+
<div className={`${prefixCls}-tip-item-name`}>,可点击切换,查询模式:</div>
|
|
143
|
+
<div className={itemValueClass}>
|
|
144
|
+
{queryType === ChatContextTypeQueryTypeEnum.AGGREGATE || queryType === 'METRIC_TAG'
|
|
145
|
+
? '聚合模式'
|
|
146
|
+
: '明细模式'}
|
|
147
|
+
</div>
|
|
148
|
+
</div>
|
|
149
|
+
)}
|
|
150
|
+
{queryType !== 'DETAIL' &&
|
|
151
|
+
metrics &&
|
|
152
|
+
metrics.length > 0 &&
|
|
153
|
+
!dimensions?.some(item => item.bizName?.includes('_id')) && (
|
|
154
|
+
<div className={`${prefixCls}-tip-item`}>
|
|
155
|
+
<div className={`${prefixCls}-tip-item-name`}>指标:</div>
|
|
156
|
+
<div className={itemValueClass}>
|
|
157
|
+
{metrics.map(metric => metric.name).join('、')}
|
|
158
|
+
</div>
|
|
159
|
+
</div>
|
|
160
|
+
)}
|
|
161
|
+
{[
|
|
162
|
+
'METRIC_GROUPBY',
|
|
163
|
+
'METRIC_ORDERBY',
|
|
164
|
+
'TAG_DETAIL',
|
|
165
|
+
'LLM_S2SQL',
|
|
166
|
+
'METRIC_FILTER',
|
|
167
|
+
].includes(queryMode!) &&
|
|
168
|
+
fields &&
|
|
169
|
+
fields.length > 0 && (
|
|
170
|
+
<div className={`${prefixCls}-tip-item`}>
|
|
171
|
+
<div className={`${prefixCls}-tip-item-name`}>
|
|
172
|
+
{queryType === 'DETAIL' ? '查询字段' : '下钻维度'}:
|
|
173
|
+
</div>
|
|
174
|
+
<div className={itemValueClass}>
|
|
175
|
+
{fields
|
|
176
|
+
.slice(0, MAX_OPTION_VALUES_COUNT)
|
|
177
|
+
.map(field => field.name)
|
|
178
|
+
.join('、')}
|
|
179
|
+
{fields.length > MAX_OPTION_VALUES_COUNT && '...'}
|
|
180
|
+
</div>
|
|
181
|
+
</div>
|
|
182
|
+
)}
|
|
183
|
+
{queryMode !== 'TAG_ID' &&
|
|
184
|
+
!dimensions?.some(item => item.bizName?.includes('_id')) &&
|
|
185
|
+
entityInfo?.dimensions
|
|
186
|
+
?.filter(dimension => dimension.value != null)
|
|
187
|
+
.map(dimension => (
|
|
188
|
+
<div className={`${prefixCls}-tip-item`} key={dimension.itemId}>
|
|
189
|
+
<div className={`${prefixCls}-tip-item-name`}>{dimension.name}:</div>
|
|
190
|
+
<div className={itemValueClass}>{dimension.value}</div>
|
|
191
|
+
</div>
|
|
192
|
+
))}
|
|
193
|
+
{(queryMode === 'METRIC_ORDERBY' || queryMode === 'METRIC_MODEL') &&
|
|
194
|
+
aggType &&
|
|
195
|
+
aggType !== 'NONE' && (
|
|
196
|
+
<div className={`${prefixCls}-tip-item`}>
|
|
197
|
+
<div className={`${prefixCls}-tip-item-name`}>聚合方式:</div>
|
|
198
|
+
<div className={itemValueClass}>{AGG_TYPE_MAP[aggType]}</div>
|
|
199
|
+
</div>
|
|
200
|
+
)}
|
|
201
|
+
</>
|
|
202
|
+
)}
|
|
203
|
+
</div>
|
|
204
|
+
);
|
|
205
|
+
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { CheckCircleFilled, DownOutlined, LoadingOutlined, UpOutlined } from '@ant-design/icons';
|
|
2
|
+
import { PREFIX_CLS } from '../../common/constants';
|
|
3
|
+
import { SimilarQuestionType } from '../../common/type';
|
|
4
|
+
import { useEffect, useState } from 'react';
|
|
5
|
+
import { querySimilarQuestions } from '../../service';
|
|
6
|
+
|
|
7
|
+
type Props = {
|
|
8
|
+
queryId?: number;
|
|
9
|
+
similarQueries?: SimilarQuestionType[];
|
|
10
|
+
defaultExpanded?: boolean;
|
|
11
|
+
onSelectQuestion: (question: SimilarQuestionType) => void;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const SimilarQuestions: React.FC<Props> = ({
|
|
15
|
+
queryId,
|
|
16
|
+
similarQueries,
|
|
17
|
+
defaultExpanded,
|
|
18
|
+
onSelectQuestion,
|
|
19
|
+
}) => {
|
|
20
|
+
const [similarQuestions, setSimilarQuestions] = useState<SimilarQuestionType[]>(
|
|
21
|
+
similarQueries || []
|
|
22
|
+
);
|
|
23
|
+
const [expanded, setExpanded] = useState(defaultExpanded || false);
|
|
24
|
+
const [loading, setLoading] = useState(false);
|
|
25
|
+
|
|
26
|
+
const tipPrefixCls = `${PREFIX_CLS}-item`;
|
|
27
|
+
const prefixCls = `${PREFIX_CLS}-similar-questions`;
|
|
28
|
+
|
|
29
|
+
const initData = async () => {
|
|
30
|
+
setLoading(true);
|
|
31
|
+
const res = await querySimilarQuestions(queryId!);
|
|
32
|
+
setLoading(false);
|
|
33
|
+
setSimilarQuestions(res.data?.similarQueries || []);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
if (expanded && similarQuestions?.length === 0 && queryId) {
|
|
38
|
+
initData();
|
|
39
|
+
}
|
|
40
|
+
}, [expanded, queryId]);
|
|
41
|
+
|
|
42
|
+
const onToggleExpanded = () => {
|
|
43
|
+
setExpanded(!expanded);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<div className={`${tipPrefixCls}-parse-tip`}>
|
|
48
|
+
<div className={`${tipPrefixCls}-title-bar`}>
|
|
49
|
+
<CheckCircleFilled className={`${tipPrefixCls}-step-icon`} />
|
|
50
|
+
<div className={`${tipPrefixCls}-step-title`}>
|
|
51
|
+
推荐相似问题
|
|
52
|
+
<span className={`${prefixCls}-toggle-expand-btn`} onClick={onToggleExpanded}>
|
|
53
|
+
{loading ? <LoadingOutlined /> : expanded ? <UpOutlined /> : <DownOutlined />}
|
|
54
|
+
</span>
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
<div className={prefixCls}>
|
|
58
|
+
{expanded && (
|
|
59
|
+
<div className={`${prefixCls}-content`}>
|
|
60
|
+
{Array.isArray(similarQuestions) && similarQuestions.length > 0 ? (
|
|
61
|
+
similarQuestions?.slice(0, 5).map((question, index) => {
|
|
62
|
+
return (
|
|
63
|
+
<div
|
|
64
|
+
className={`${prefixCls}-question`}
|
|
65
|
+
key={question.queryText}
|
|
66
|
+
onClick={() => {
|
|
67
|
+
onSelectQuestion(question);
|
|
68
|
+
}}
|
|
69
|
+
>
|
|
70
|
+
{index + 1}. {question.queryText}
|
|
71
|
+
</div>
|
|
72
|
+
);
|
|
73
|
+
})
|
|
74
|
+
) : (
|
|
75
|
+
<>暂无推荐</>
|
|
76
|
+
)}
|
|
77
|
+
</div>
|
|
78
|
+
)}
|
|
79
|
+
</div>
|
|
80
|
+
</div>
|
|
81
|
+
);
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export default SimilarQuestions;
|