@gientech/modual 1.2.8 → 1.2.9-fix
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/README.md +593 -79
- package/USAGE.md +56 -0
- package/dist/README.md +593 -79
- package/dist/assets/GientechStreamReader-C21-q_Qv.js +449 -0
- package/dist/assets/chevron-down-DjLtKwcs.js +280 -0
- package/dist/assets/databse.svg +6 -0
- package/dist/assets/graph.svg +4 -0
- package/dist/assets/homeBg.png +0 -0
- package/dist/assets/index-BMz4lcjQ.js +1 -0
- package/dist/assets/index-C3Viu8Oj.js +1 -0
- package/dist/assets/index-C9GlPyHu.js +13 -0
- package/dist/assets/index-CRbX3ZA1.js +1 -0
- package/dist/assets/index-CTwzi_v2.js +21 -0
- package/dist/assets/index-DQlLDleQ.js +11 -0
- package/dist/assets/index-DRU1P9R0.js +1150 -0
- package/dist/assets/index-Dqej68NT.js +585 -0
- package/dist/assets/index-ECprhahs.js +157 -0
- package/dist/assets/index-i7qcZOwY.js +1088 -0
- package/dist/assets/knowledge.svg +4 -0
- package/dist/assets/left.jpg +0 -0
- package/dist/assets/logoImg.png +0 -0
- package/dist/assets/{plus-omCUN0e3.js → plus-CvJRSbOe.js} +1 -1
- package/dist/assets/sensitive.svg +5 -0
- package/dist/assets/style.css +1 -1
- package/dist/assets/style3.css +1 -1
- package/dist/assets/worker-BbpylX7l.js +13 -0
- package/dist/assets/{x-vPcWt3fC.js → x-DKPeLdlu.js} +1 -1
- package/dist/assistantConfig.d.ts +31 -0
- package/dist/assistantConfig.js +1 -0
- package/dist/chat.d.ts +25 -1
- package/dist/chat.js +563 -369
- package/dist/database.js +2 -2
- package/dist/databaseId.js +1 -11
- package/dist/databaseTable.js +2 -2
- package/dist/index.d.ts +85 -0
- package/dist/index.js +1 -0
- package/dist/modelManage.js +1 -1
- package/dist/package.json +13 -1
- package/dist/sensitive.js +1 -1
- package/dist/streamFilesReader.d.ts +3 -0
- package/dist/streamFilesReader.js +1 -442
- package/doc_assets//346/226/271/346/241/210//344/274/230/345/214/226/346/226/271/346/241/210-/345/244/232/344/274/232/350/257/235SSE/350/277/236/346/216/245/347/256/241/347/220/206.md +504 -0
- package/package.json +125 -99
- package/package.json.demo-backup +109 -0
- package/scripts/README.md +133 -133
- package/scripts/build-demo.js +88 -88
- package/scripts/demo-selector.js +216 -216
- package/scripts/preview-demo.js +130 -130
- package/scripts/run-demo.bat +34 -34
- package/src/assets/img/close.png +0 -0
- package/src/assets/img/database.png +0 -0
- package/src/assets/img/downLoad.png +0 -0
- package/src/assets/img/graphIcon.png +0 -0
- package/src/assets/img/pdf.png +0 -0
- package/src/assets/img/singleQa.png +0 -0
- package/src/assets/img/webSearch.png +0 -0
- package/src/examples/ConversationAssistantPage/index.tsx +37 -0
- package/src/examples/Demo/index.tsx +12 -0
- package/src/examples/chat/components/DrawerGraphPreview.tsx +78 -0
- package/src/examples/chat/index.tsx +112 -99
- package/src/examples/chat/logo03.png +0 -0
- package/src/examples/gientechStreamFilesReader/index.tsx +4 -69
- package/src/lib_enter.ts +11 -6
- package/src/modules/assistantConfig/assets/databse.svg +6 -0
- package/src/modules/assistantConfig/assets/empty.png +0 -0
- package/src/modules/assistantConfig/assets/graph.svg +4 -0
- package/src/modules/assistantConfig/assets/knowledge.svg +4 -0
- package/src/modules/assistantConfig/assets/sensitive.svg +5 -0
- package/src/modules/assistantConfig/components/Database.tsx +144 -0
- package/src/modules/assistantConfig/components/Graph.tsx +156 -0
- package/src/modules/assistantConfig/components/Knowledge.tsx +266 -0
- package/src/modules/assistantConfig/components/NotFoundContent.tsx +21 -0
- package/src/modules/assistantConfig/components/Paragraph.tsx +51 -0
- package/src/modules/assistantConfig/components/ParamsItem.tsx +39 -0
- package/src/modules/assistantConfig/components/ResourceBinderItem.tsx +132 -0
- package/src/modules/assistantConfig/components/SearchableSelector.tsx +500 -0
- package/src/modules/assistantConfig/components/Sensitive.tsx +179 -0
- package/src/modules/assistantConfig/components/SliderInput.tsx +65 -0
- package/src/modules/assistantConfig/constants.tsx +74 -0
- package/src/modules/assistantConfig/index.tsx +700 -0
- package/src/modules/assistantConfig/server.ts +262 -0
- package/src/modules/chat/Conversations/List.tsx +76 -9
- package/src/modules/chat/Conversations/index.tsx +37 -19
- package/src/modules/chat/ReferenceBar.tsx +592 -0
- package/src/modules/chat/constants.tsx +29 -6
- package/src/modules/chat/data.txt +82 -0
- package/src/modules/chat/index.tsx +357 -113
- package/src/modules/chat/referenceCom/DeleteModal.tsx +75 -0
- package/src/modules/chat/referenceCom/DrawerContent.tsx +136 -0
- package/src/modules/chat/referenceCom/DrawerDatabase.tsx +110 -0
- package/src/modules/chat/referenceCom/DrawerGraphPreview.tsx +86 -0
- package/src/modules/chat/referenceCom/DrawerPreview.tsx +73 -0
- package/src/modules/chat/referenceCom/DrawerTitle.tsx +26 -0
- package/src/modules/chat/referenceCom/RenameModal.tsx +86 -0
- package/src/modules/chat/referenceCom/TagCom.tsx +30 -0
- package/src/modules/chat/style.less +3 -0
- package/src/modules/chat/utils/index.ts +326 -0
- package/src/modules/database/CreateModal.tsx +1 -1
- package/src/modules/headlessChat/index.tsx +1 -3
- package/src/modules/nodegraph/index.tsx +1 -0
- package/src/modules/search/components/ResultContent.tsx +2 -2
- package/src/modules/streamFilesReader/GientechStreamReader.tsx +436 -367
- package/src/modules/streamFilesReader/index.tsx +1 -1
- package/src/utils/gientechCommon/components/AppLoading.tsx +10 -10
- package/src/utils/gientechCommon/components/Messages/GientechNewChatWelcome.tsx +312 -27
- package/src/utils/gientechCommon/hooks/AichatUseController.tsx +84 -6
- package/src/utils/testconfigs/index.ts +7 -1
- package/stats.html +1 -1
- package/vite.config.ts +69 -20
- package/dist/assets/_commonjsHelpers-gnU0ypJ3.js +0 -1
- package/dist/assets/circle-alert-g2Y6zAjt.js +0 -6
- package/dist/assets/index-97TKgPKE.js +0 -1284
- package/dist/assets/index-CEK88UzR.js +0 -26
- package/dist/assets/index-DIm7RgkM.js +0 -1709
- package/dist/assets/styled-components.browser.esm-DPkS13KC.js +0 -2
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// 导出 GientechStreamReader 组件和类型
|
|
2
|
-
export { default as GientechStreamReader } from './GientechStreamReader';
|
|
2
|
+
export { default as GientechStreamReader, registerPDFWorker } from './GientechStreamReader';
|
|
3
3
|
export type { GientechStreamReaderProps } from './GientechStreamReader';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useEffect, useState } from 'react';
|
|
2
2
|
|
|
3
|
-
export default function AppLoading() {
|
|
3
|
+
export default function AppLoading({ title, subtitle }: { title?: string; subtitle?: string }) {
|
|
4
4
|
const [progress, setProgress] = useState(0);
|
|
5
5
|
|
|
6
6
|
useEffect(() => {
|
|
@@ -33,8 +33,10 @@ export default function AppLoading() {
|
|
|
33
33
|
</defs>
|
|
34
34
|
</svg>
|
|
35
35
|
</div> */}
|
|
36
|
-
<div className="mt-6 text-2xl font-semibold text-[#222222] tracking-wide"
|
|
37
|
-
|
|
36
|
+
<div className="mt-6 text-2xl font-semibold text-[#222222] tracking-wide">
|
|
37
|
+
{title || '小鲸智能会话助手'}
|
|
38
|
+
</div>
|
|
39
|
+
<div className="mt-2 text-sm text-[#555555]">{subtitle || '让智能对话更简单'}</div>
|
|
38
40
|
</div>
|
|
39
41
|
|
|
40
42
|
{/* 进度条 */}
|
|
@@ -45,17 +47,15 @@ export default function AppLoading() {
|
|
|
45
47
|
style={{ width: `${Math.min(progress, 100)}%` }}
|
|
46
48
|
/>
|
|
47
49
|
</div>
|
|
48
|
-
<div className="absolute -right-2 top-5 text-sm text-[#555555]">
|
|
50
|
+
<div className="absolute -right-2 top-5 text-sm text-[#555555]">
|
|
51
|
+
{Math.min(Math.round(progress), 100)}%
|
|
52
|
+
</div>
|
|
49
53
|
</div>
|
|
50
54
|
|
|
51
55
|
{/* 加载提示 */}
|
|
52
56
|
<div className="mt-8 flex flex-col items-center gap-2">
|
|
53
|
-
<div className="text-sm text-[#555555] animate-pulse">
|
|
54
|
-
|
|
55
|
-
</div>
|
|
56
|
-
<div className="text-xs text-[#888888]">
|
|
57
|
-
首次加载可能需要一些时间,请耐心等待
|
|
58
|
-
</div>
|
|
57
|
+
<div className="text-sm text-[#555555] animate-pulse">正在初始化应用</div>
|
|
58
|
+
<div className="text-xs text-[#888888]">首次加载可能需要一些时间,请耐心等待</div>
|
|
59
59
|
</div>
|
|
60
60
|
</div>
|
|
61
61
|
);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { Popover } from 'antd';
|
|
1
|
+
import { useEffect, useMemo, useState, useRef } from 'react';
|
|
2
|
+
import { Popover, Input } from 'antd';
|
|
3
|
+
import { Search, X, ChevronLeft, ChevronRight } from 'lucide-react';
|
|
3
4
|
import { type Styles, defaultTheme } from '@mxmweb/zui';
|
|
4
5
|
import { uid } from 'uid';
|
|
5
6
|
import defaultWeLogo from './defaultWeLogo.svg';
|
|
@@ -48,14 +49,81 @@ const createWelcomeStyles = (colors: any, classId: string) => {
|
|
|
48
49
|
box-shadow: inset 0 0 0 1px ${c.border};
|
|
49
50
|
}
|
|
50
51
|
.g-welcome-${classId} .g-welcome-pagination-btn {
|
|
52
|
+
background: transparent;
|
|
53
|
+
border: none;
|
|
54
|
+
color: ${c.disabled};
|
|
55
|
+
padding: 6px 10px;
|
|
56
|
+
border-radius: 9999px;
|
|
57
|
+
transition: all 0.2s;
|
|
58
|
+
font-size: 14px;
|
|
59
|
+
line-height: 1;
|
|
60
|
+
min-width: 32px;
|
|
61
|
+
height: 32px;
|
|
62
|
+
display: inline-flex;
|
|
63
|
+
align-items: center;
|
|
64
|
+
justify-content: center;
|
|
65
|
+
}
|
|
66
|
+
.g-welcome-${classId} .g-welcome-pagination-btn:hover:not(:disabled) {
|
|
67
|
+
color: ${c.text};
|
|
68
|
+
background-color: ${c.border}33;
|
|
69
|
+
}
|
|
70
|
+
.g-welcome-${classId} .g-welcome-pagination-btn.active {
|
|
51
71
|
color: ${c.primary};
|
|
72
|
+
background: radial-gradient(100% 100% at 50% 50%, ${c.primary}10 0%, ${c.primary}08 100%);
|
|
73
|
+
box-shadow: 0 2px 10px ${c.primary}12, inset 0 0 0 1px ${c.primary}1A;
|
|
52
74
|
}
|
|
53
75
|
.g-welcome-${classId} .g-welcome-pagination-btn:disabled {
|
|
54
76
|
color: ${c.disabled};
|
|
55
77
|
cursor: not-allowed;
|
|
78
|
+
background: transparent;
|
|
56
79
|
}
|
|
57
80
|
.g-welcome-${classId} .g-welcome-pagination-text {
|
|
81
|
+
color: ${c.disabled};
|
|
82
|
+
font-size: 14px;
|
|
83
|
+
padding: 0 8px;
|
|
84
|
+
}
|
|
85
|
+
.g-welcome-${classId} .g-welcome-pagination-dot {
|
|
86
|
+
width: 6px;
|
|
87
|
+
height: 6px;
|
|
88
|
+
border-radius: 50%;
|
|
89
|
+
background-color: ${c.border};
|
|
90
|
+
transition: all 0.2s;
|
|
91
|
+
}
|
|
92
|
+
.g-welcome-${classId} .g-welcome-pagination-dot.active {
|
|
93
|
+
background-color: ${c.primary};
|
|
94
|
+
width: 20px;
|
|
95
|
+
border-radius: 3px;
|
|
96
|
+
}
|
|
97
|
+
.g-welcome-${classId} .g-welcome-search-btn {
|
|
98
|
+
background-color: #ffffff;
|
|
99
|
+
border: 1px solid ${c.border};
|
|
58
100
|
color: ${c.text};
|
|
101
|
+
padding: 8px 8px;
|
|
102
|
+
border-radius: 100%;
|
|
103
|
+
cursor: pointer;
|
|
104
|
+
transition: all 0.2s;
|
|
105
|
+
display: flex;
|
|
106
|
+
align-items: center;
|
|
107
|
+
gap: 6px;
|
|
108
|
+
font-size: 14px;
|
|
109
|
+
box-shadow: 0 1px 2px rgba(31,35,41,0.04);
|
|
110
|
+
}
|
|
111
|
+
.g-welcome-${classId} .g-welcome-search-btn:hover {
|
|
112
|
+
border-color: ${c.primary};
|
|
113
|
+
color: ${c.primary};
|
|
114
|
+
box-shadow: 0 2px 6px rgba(31,35,41,0.08);
|
|
115
|
+
}
|
|
116
|
+
.g-welcome-${classId} .g-welcome-search-input {
|
|
117
|
+
border: 1px solid ${c.border};
|
|
118
|
+
border-radius: 9999px;
|
|
119
|
+
transition: all 0.2s;
|
|
120
|
+
height: 40px;
|
|
121
|
+
padding: 0 14px;
|
|
122
|
+
}
|
|
123
|
+
.g-welcome-${classId} .g-welcome-search-input:focus,
|
|
124
|
+
.g-welcome-${classId} .g-welcome-search-input:hover {
|
|
125
|
+
border-color: ${c.primary};
|
|
126
|
+
box-shadow: 0 0 0 2px ${c.primary}1A;
|
|
59
127
|
}
|
|
60
128
|
`;
|
|
61
129
|
}
|
|
@@ -162,10 +230,22 @@ interface GientechNewChatWelcomeProps {
|
|
|
162
230
|
function GientechNewChatWelcome(props: GientechNewChatWelcomeProps) {
|
|
163
231
|
const { assistantList, eventsEmit, styles, selectedId, onSelectAssistant, productLogo } = props;
|
|
164
232
|
const [currentPage, setCurrentPage] = useState(1);
|
|
165
|
-
const
|
|
233
|
+
const [searchVisible, setSearchVisible] = useState(false);
|
|
234
|
+
const [searchKeyword, setSearchKeyword] = useState('');
|
|
235
|
+
// 搜索框打开时每页显示6个,否则显示12个
|
|
236
|
+
const pageSize = (searchVisible || searchKeyword.trim()) ? 6 : 12;
|
|
166
237
|
|
|
167
238
|
// 只在 selectedId 变化时触发事件,且去重
|
|
168
239
|
const prevSelectedId = useRef<string | undefined>();
|
|
240
|
+
// 标记是否是选择助手导致的搜索关键词清空
|
|
241
|
+
const isClearingSearchForSelection = useRef(false);
|
|
242
|
+
// 记录选择助手时的目标页面,用于防止被重置
|
|
243
|
+
const targetPageForSelection = useRef<number | null>(null);
|
|
244
|
+
// 记录是否已经为当前 selectedId 设置了目标页面,避免重复设置
|
|
245
|
+
const hasSetPageForSelectedId = useRef<string | null>(null);
|
|
246
|
+
// 记录上一次的搜索关键词,用于判断是否真正变化
|
|
247
|
+
const prevSearchKeyword = useRef<string>('');
|
|
248
|
+
|
|
169
249
|
useEffect(() => {
|
|
170
250
|
if (selectedId && prevSelectedId.current !== selectedId) {
|
|
171
251
|
eventsEmit?.('conversation:new_assistant_change', { assistantId: selectedId });
|
|
@@ -199,39 +279,146 @@ function GientechNewChatWelcome(props: GientechNewChatWelcomeProps) {
|
|
|
199
279
|
return JSON.parse(selectAssistant?.configJson || '{}');
|
|
200
280
|
}, [selectAssistant]);
|
|
201
281
|
|
|
282
|
+
// 搜索过滤逻辑
|
|
283
|
+
const filteredAssistants = useMemo(() => {
|
|
284
|
+
if (!searchKeyword.trim()) {
|
|
285
|
+
return assistantList || [];
|
|
286
|
+
}
|
|
287
|
+
const keyword = searchKeyword.toLowerCase().trim();
|
|
288
|
+
return (assistantList || []).filter(assistant => {
|
|
289
|
+
const name = assistant.name?.toLowerCase() || '';
|
|
290
|
+
// 也可以搜索配置中的信息
|
|
291
|
+
try {
|
|
292
|
+
const cfg = JSON.parse(assistant.configJson || '{}');
|
|
293
|
+
const configName = cfg.config_name?.toLowerCase() || '';
|
|
294
|
+
return name.includes(keyword) || configName.includes(keyword);
|
|
295
|
+
} catch {
|
|
296
|
+
return name.includes(keyword);
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
}, [assistantList, searchKeyword]);
|
|
300
|
+
|
|
202
301
|
// 分页逻辑
|
|
203
|
-
const totalPages = Math.ceil((
|
|
204
|
-
const currentAssistants =
|
|
302
|
+
const totalPages = Math.ceil((filteredAssistants?.length || 0) / pageSize);
|
|
303
|
+
const currentAssistants = filteredAssistants?.slice((currentPage - 1) * pageSize, currentPage * pageSize) || [];
|
|
304
|
+
|
|
305
|
+
// 当选中助手时,自动跳转到对应页面(只在 selectedId 变化时执行)
|
|
306
|
+
useEffect(() => {
|
|
307
|
+
if (selectedId && selectedId !== hasSetPageForSelectedId.current) {
|
|
308
|
+
// 如果正在清空搜索(选择助手导致的),已经有目标页面了,不重复计算
|
|
309
|
+
if (isClearingSearchForSelection.current && targetPageForSelection.current !== null) {
|
|
310
|
+
hasSetPageForSelectedId.current = selectedId;
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
// 如果有搜索关键词,基于过滤后的列表跳转;否则基于完整列表跳转
|
|
314
|
+
const targetList = searchKeyword.trim() ? filteredAssistants : assistantList;
|
|
315
|
+
if (targetList && targetList.length > 0) {
|
|
316
|
+
const selectedIndex = targetList.findIndex(a => a.id === selectedId);
|
|
317
|
+
if (selectedIndex !== -1) {
|
|
318
|
+
const targetPage = Math.floor(selectedIndex / pageSize) + 1;
|
|
319
|
+
setCurrentPage(targetPage);
|
|
320
|
+
hasSetPageForSelectedId.current = selectedId;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}, [selectedId, assistantList, filteredAssistants, pageSize, searchKeyword]);
|
|
205
325
|
|
|
206
|
-
//
|
|
326
|
+
// 当搜索关键词变化时,重置到第一页(但选择助手导致的清空除外)
|
|
207
327
|
useEffect(() => {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
328
|
+
// 如果搜索关键词没有真正变化,不执行任何操作
|
|
329
|
+
if (searchKeyword === prevSearchKeyword.current) {
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// 如果是选择助手导致的搜索关键词清空,跳转到目标页面并清除标记
|
|
334
|
+
if (isClearingSearchForSelection.current && targetPageForSelection.current !== null) {
|
|
335
|
+
setCurrentPage(targetPageForSelection.current);
|
|
336
|
+
isClearingSearchForSelection.current = false;
|
|
337
|
+
targetPageForSelection.current = null;
|
|
338
|
+
prevSearchKeyword.current = searchKeyword;
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// 如果已经为 selectedId 设置了页面(说明是选择助手导致的),不重置页面
|
|
343
|
+
if (hasSetPageForSelectedId.current === selectedId) {
|
|
344
|
+
prevSearchKeyword.current = searchKeyword;
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// 用户主动输入搜索关键词时,重置到第一页,并清除已设置的页面标记
|
|
349
|
+
if (!isClearingSearchForSelection.current) {
|
|
350
|
+
// 如果用户主动输入搜索关键词,清除已设置的页面标记,允许重新计算
|
|
351
|
+
if (searchKeyword.trim()) {
|
|
352
|
+
hasSetPageForSelectedId.current = null;
|
|
213
353
|
}
|
|
354
|
+
setCurrentPage(1);
|
|
214
355
|
}
|
|
215
|
-
|
|
356
|
+
|
|
357
|
+
prevSearchKeyword.current = searchKeyword;
|
|
358
|
+
}, [searchKeyword, selectedId]);
|
|
359
|
+
|
|
360
|
+
// 当过滤结果变化时,如果当前页超出总页数,自动调整到最后一页
|
|
361
|
+
useEffect(() => {
|
|
362
|
+
if (totalPages > 0 && currentPage > totalPages) {
|
|
363
|
+
setCurrentPage(totalPages);
|
|
364
|
+
}
|
|
365
|
+
}, [totalPages, currentPage]);
|
|
216
366
|
|
|
217
367
|
const prologue = selectAssistantConfig.prologue || '您好,欢迎使用小鲸智能问答';
|
|
218
368
|
const prologueTypewriter = useTypewriter(prologue, [selectedId], 30);
|
|
219
369
|
|
|
220
370
|
return (
|
|
221
|
-
<div className={`flex flex-col items-center justify-center h-full w-full g-welcome-${classId}`}>
|
|
371
|
+
<div className={`flex flex-col relative items-center justify-center h-full w-full g-welcome-${classId}`}>
|
|
222
372
|
{/* 产品Logo */}
|
|
223
373
|
<img
|
|
224
374
|
src={productLogo || (defaultWeLogo as unknown as string)}
|
|
225
375
|
alt="logo"
|
|
226
376
|
className="mb-4"
|
|
227
|
-
style={{ width:
|
|
377
|
+
style={{ width: 68, height: 68 }}
|
|
228
378
|
/>
|
|
229
379
|
<div className="text-3xl font-bold mb-2 g-welcome-title">{prologueTypewriter}</div>
|
|
230
|
-
<div className="text-sm text-gray-500 mb-20">请选择一个智能助手,开始你的智能问答之旅</div>
|
|
231
380
|
{!selectedId && <div className="flex mb-2 g-welcome-subtitle">请选择一个智能助手</div>}
|
|
232
|
-
|
|
381
|
+
|
|
382
|
+
<div
|
|
383
|
+
style={{
|
|
384
|
+
maxWidth: '1200px',
|
|
385
|
+
}}
|
|
386
|
+
className="flex mt-8 flex-wrap gap-3
|
|
387
|
+
max-w-[1200px] px-8 w-full mx-auto justify-center mb-4">
|
|
388
|
+
{/* 搜索按钮/输入框 - 永远渲染为第一个元素 */}
|
|
389
|
+
{!searchVisible ? (
|
|
390
|
+
<button type="button" className="g-welcome-search-btn" onClick={() => setSearchVisible(true)}>
|
|
391
|
+
<Search size={16} />
|
|
392
|
+
</button>
|
|
393
|
+
) : (
|
|
394
|
+
<div className="flex items-center gap-2 px-5 w-full" style={{ flexBasis: '100%' }}>
|
|
395
|
+
<Input
|
|
396
|
+
className="g-welcome-search-input w-full"
|
|
397
|
+
placeholder="搜索助手名称"
|
|
398
|
+
prefix={<Search size={16} />}
|
|
399
|
+
suffix={
|
|
400
|
+
<button
|
|
401
|
+
type="button"
|
|
402
|
+
onClick={() => {
|
|
403
|
+
setSearchVisible(false);
|
|
404
|
+
setSearchKeyword('');
|
|
405
|
+
}}
|
|
406
|
+
style={{ background: 'transparent', border: 'none', cursor: 'pointer' }}
|
|
407
|
+
>
|
|
408
|
+
<X size={14} />
|
|
409
|
+
</button>
|
|
410
|
+
}
|
|
411
|
+
value={searchKeyword}
|
|
412
|
+
onChange={(e) => setSearchKeyword(e.target.value)}
|
|
413
|
+
autoFocus
|
|
414
|
+
/>
|
|
415
|
+
</div>
|
|
416
|
+
)}
|
|
417
|
+
|
|
418
|
+
{/* 助手列表或空状态 */}
|
|
233
419
|
{currentAssistants && currentAssistants.length > 0 ? (
|
|
234
|
-
|
|
420
|
+
<>
|
|
421
|
+
{currentAssistants.map(assistant => {
|
|
235
422
|
const isActive = selectedId === assistant.id;
|
|
236
423
|
// 图标解析:优先 assistant.icon,其次配置中的 icon/avatar/logo,最后使用默认
|
|
237
424
|
let iconSrc: string | undefined = assistant.icon;
|
|
@@ -250,8 +437,40 @@ function GientechNewChatWelcome(props: GientechNewChatWelcomeProps) {
|
|
|
250
437
|
placement="bottom"
|
|
251
438
|
>
|
|
252
439
|
<button
|
|
440
|
+
type="button"
|
|
253
441
|
className={`g-welcome-btn px-3 cursor-pointer rounded-full border font-medium min-w-[160px] text-sm transition-all flex items-center gap-2 ${isActive ? 'active' : ''}`}
|
|
254
|
-
onClick={() =>
|
|
442
|
+
onClick={() => {
|
|
443
|
+
onSelectAssistant?.(assistant.id);
|
|
444
|
+
|
|
445
|
+
// 计算目标页面:如果在搜索中,基于完整列表(因为搜索会被清空);否则基于当前列表
|
|
446
|
+
const isInSearch = searchVisible || searchKeyword.trim();
|
|
447
|
+
const targetList = isInSearch ? assistantList : (searchKeyword.trim() ? filteredAssistants : assistantList);
|
|
448
|
+
const selectedIndex = targetList.findIndex(a => a.id === assistant.id);
|
|
449
|
+
|
|
450
|
+
if (selectedIndex !== -1) {
|
|
451
|
+
// 如果在搜索中,清空后 pageSize 会变成 12;否则使用当前的 pageSize
|
|
452
|
+
const targetPageSize = isInSearch ? 12 : pageSize;
|
|
453
|
+
const targetPage = Math.floor(selectedIndex / targetPageSize) + 1;
|
|
454
|
+
|
|
455
|
+
// 立即跳转到目标页面
|
|
456
|
+
setCurrentPage(targetPage);
|
|
457
|
+
// 标记已经为当前 selectedId 设置了页面
|
|
458
|
+
hasSetPageForSelectedId.current = assistant.id;
|
|
459
|
+
|
|
460
|
+
// 若在搜索视图中选择了助手,需要清空搜索
|
|
461
|
+
if (isInSearch) {
|
|
462
|
+
// 保存目标页面,用于在搜索关键词清空时跳转
|
|
463
|
+
targetPageForSelection.current = targetPage;
|
|
464
|
+
// 设置标记,表示这是选择助手导致的清空
|
|
465
|
+
isClearingSearchForSelection.current = true;
|
|
466
|
+
// 延迟清空搜索,确保跳转逻辑先执行
|
|
467
|
+
setTimeout(() => {
|
|
468
|
+
setSearchKeyword('');
|
|
469
|
+
setSearchVisible(false);
|
|
470
|
+
}, 100);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
}}
|
|
255
474
|
title={assistant.name}
|
|
256
475
|
>
|
|
257
476
|
<span className="icon-badge">
|
|
@@ -261,30 +480,96 @@ function GientechNewChatWelcome(props: GientechNewChatWelcomeProps) {
|
|
|
261
480
|
</button>
|
|
262
481
|
</Popover>
|
|
263
482
|
);
|
|
264
|
-
|
|
483
|
+
})}
|
|
484
|
+
</>
|
|
265
485
|
) : (
|
|
266
486
|
<div className="g-welcome-subtitle">暂无可用助手</div>
|
|
267
487
|
)}
|
|
268
488
|
</div>
|
|
269
489
|
{/* 分页控制 */}
|
|
270
490
|
{totalPages > 1 && (
|
|
271
|
-
<div className="flex items-center gap-
|
|
491
|
+
<div className="flex items-center gap-2">
|
|
272
492
|
<button
|
|
273
|
-
|
|
493
|
+
type="button"
|
|
494
|
+
className="g-welcome-pagination-btn"
|
|
274
495
|
onClick={() => setCurrentPage(p => Math.max(1, p - 1))}
|
|
275
496
|
disabled={currentPage === 1}
|
|
276
497
|
>
|
|
277
|
-
|
|
498
|
+
<ChevronLeft size={16} />
|
|
278
499
|
</button>
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
500
|
+
|
|
501
|
+
{/* 页码显示 */}
|
|
502
|
+
<div className="flex items-center gap-1">
|
|
503
|
+
{(() => {
|
|
504
|
+
const pages: (number | string)[] = [];
|
|
505
|
+
const maxVisible = 7; // 最多显示7个页码
|
|
506
|
+
|
|
507
|
+
if (totalPages <= maxVisible) {
|
|
508
|
+
// 如果总页数少于等于7,显示所有页码
|
|
509
|
+
for (let i = 1; i <= totalPages; i++) {
|
|
510
|
+
pages.push(i);
|
|
511
|
+
}
|
|
512
|
+
} else {
|
|
513
|
+
// 总是显示第一页
|
|
514
|
+
pages.push(1);
|
|
515
|
+
|
|
516
|
+
if (currentPage <= 4) {
|
|
517
|
+
// 当前页在前4页,显示 1 2 3 4 5 ... totalPages
|
|
518
|
+
for (let i = 2; i <= 5; i++) {
|
|
519
|
+
pages.push(i);
|
|
520
|
+
}
|
|
521
|
+
pages.push('...');
|
|
522
|
+
pages.push(totalPages);
|
|
523
|
+
} else if (currentPage >= totalPages - 3) {
|
|
524
|
+
// 当前页在后4页,显示 1 ... totalPages-4 totalPages-3 totalPages-2 totalPages-1 totalPages
|
|
525
|
+
pages.push('...');
|
|
526
|
+
for (let i = totalPages - 4; i <= totalPages; i++) {
|
|
527
|
+
pages.push(i);
|
|
528
|
+
}
|
|
529
|
+
} else {
|
|
530
|
+
// 当前页在中间,显示 1 ... currentPage-1 currentPage currentPage+1 ... totalPages
|
|
531
|
+
pages.push('...');
|
|
532
|
+
for (let i = currentPage - 1; i <= currentPage + 1; i++) {
|
|
533
|
+
pages.push(i);
|
|
534
|
+
}
|
|
535
|
+
pages.push('...');
|
|
536
|
+
pages.push(totalPages);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
return pages.map((page, index) => {
|
|
541
|
+
if (page === '...') {
|
|
542
|
+
return (
|
|
543
|
+
<span key={`ellipsis-${index}`} className="g-welcome-pagination-text px-1">
|
|
544
|
+
...
|
|
545
|
+
</span>
|
|
546
|
+
);
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
const pageNum = page as number;
|
|
550
|
+
const isActive = currentPage === pageNum;
|
|
551
|
+
|
|
552
|
+
return (
|
|
553
|
+
<button
|
|
554
|
+
type="button"
|
|
555
|
+
key={pageNum}
|
|
556
|
+
className={`g-welcome-pagination-btn ${isActive ? 'active' : ''}`}
|
|
557
|
+
onClick={() => setCurrentPage(pageNum)}
|
|
558
|
+
>
|
|
559
|
+
{pageNum}
|
|
560
|
+
</button>
|
|
561
|
+
);
|
|
562
|
+
});
|
|
563
|
+
})()}
|
|
564
|
+
</div>
|
|
565
|
+
|
|
282
566
|
<button
|
|
283
|
-
|
|
567
|
+
type="button"
|
|
568
|
+
className="g-welcome-pagination-btn"
|
|
284
569
|
onClick={() => setCurrentPage(p => Math.min(totalPages, p + 1))}
|
|
285
570
|
disabled={currentPage === totalPages}
|
|
286
571
|
>
|
|
287
|
-
|
|
572
|
+
<ChevronRight size={16} />
|
|
288
573
|
</button>
|
|
289
574
|
</div>
|
|
290
575
|
)}
|