@huyooo/ai-chat-frontend-react 0.2.14 → 0.2.16
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/dist/index.css +0 -1
- package/dist/index.js +1 -5418
- package/package.json +4 -5
- package/dist/index.css.map +0 -1
- package/dist/index.js.map +0 -1
- package/src/adapter.ts +0 -68
- package/src/components/ChatPanel.tsx +0 -553
- package/src/components/common/ConfirmDialog.css +0 -136
- package/src/components/common/ConfirmDialog.tsx +0 -91
- package/src/components/common/CopyButton.css +0 -22
- package/src/components/common/CopyButton.tsx +0 -46
- package/src/components/common/IndexingSettings.css +0 -207
- package/src/components/common/IndexingSettings.tsx +0 -398
- package/src/components/common/SettingsPanel.css +0 -337
- package/src/components/common/SettingsPanel.tsx +0 -215
- package/src/components/common/Toast.css +0 -50
- package/src/components/common/Toast.tsx +0 -38
- package/src/components/common/ToggleSwitch.css +0 -52
- package/src/components/common/ToggleSwitch.tsx +0 -20
- package/src/components/header/ChatHeader.css +0 -285
- package/src/components/header/ChatHeader.tsx +0 -376
- package/src/components/input/AtFilePicker.css +0 -147
- package/src/components/input/AtFilePicker.tsx +0 -519
- package/src/components/input/ChatInput.css +0 -283
- package/src/components/input/ChatInput.tsx +0 -575
- package/src/components/input/DropdownSelector.css +0 -231
- package/src/components/input/DropdownSelector.tsx +0 -333
- package/src/components/input/ImagePreviewModal.css +0 -124
- package/src/components/input/ImagePreviewModal.tsx +0 -118
- package/src/components/input/at-views/AtBranchView.tsx +0 -34
- package/src/components/input/at-views/AtBrowserView.tsx +0 -34
- package/src/components/input/at-views/AtChatsView.tsx +0 -34
- package/src/components/input/at-views/AtDocsView.tsx +0 -34
- package/src/components/input/at-views/AtFilesView.tsx +0 -168
- package/src/components/input/at-views/AtTerminalsView.tsx +0 -34
- package/src/components/input/at-views/AtViewStyles.css +0 -143
- package/src/components/input/at-views/index.ts +0 -9
- package/src/components/message/ContentRenderer.css +0 -9
- package/src/components/message/MessageBubble.css +0 -193
- package/src/components/message/MessageBubble.tsx +0 -240
- package/src/components/message/PartsRenderer.css +0 -12
- package/src/components/message/PartsRenderer.tsx +0 -168
- package/src/components/message/WelcomeMessage.css +0 -221
- package/src/components/message/WelcomeMessage.tsx +0 -93
- package/src/components/message/parts/CollapsibleCard.css +0 -80
- package/src/components/message/parts/CollapsibleCard.tsx +0 -80
- package/src/components/message/parts/ErrorPart.css +0 -9
- package/src/components/message/parts/ErrorPart.tsx +0 -40
- package/src/components/message/parts/ImagePart.css +0 -49
- package/src/components/message/parts/ImagePart.tsx +0 -54
- package/src/components/message/parts/SearchPart.css +0 -44
- package/src/components/message/parts/SearchPart.tsx +0 -63
- package/src/components/message/parts/TextPart.css +0 -579
- package/src/components/message/parts/TextPart.tsx +0 -213
- package/src/components/message/parts/ThinkingPart.css +0 -9
- package/src/components/message/parts/ThinkingPart.tsx +0 -48
- package/src/components/message/parts/ToolCallPart.css +0 -246
- package/src/components/message/parts/ToolCallPart.tsx +0 -289
- package/src/components/message/parts/ToolResultPart.css +0 -67
- package/src/components/message/parts/index.ts +0 -13
- package/src/components/message/parts/visual-predicate.ts +0 -43
- package/src/components/message/parts/visual-render.ts +0 -19
- package/src/components/message/parts/visual.ts +0 -12
- package/src/components/message/welcome-types.ts +0 -46
- package/src/context/AutoRunConfigContext.tsx +0 -13
- package/src/context/ChatAdapterContext.tsx +0 -8
- package/src/context/ChatInputContext.tsx +0 -40
- package/src/context/RenderersContext.tsx +0 -35
- package/src/hooks/useChat.ts +0 -1569
- package/src/hooks/useImageUpload.ts +0 -345
- package/src/hooks/useVoiceInput.ts +0 -454
- package/src/hooks/useVoiceToTextInput.ts +0 -87
- package/src/index.ts +0 -151
- package/src/styles.css +0 -330
- package/src/types/index.ts +0 -196
- package/src/utils/fileIcon.ts +0 -49
|
@@ -1,398 +0,0 @@
|
|
|
1
|
-
import { useState, useEffect, useCallback, useRef } from 'react'
|
|
2
|
-
import { Icon } from '@iconify/react'
|
|
3
|
-
import { ConfirmDialog } from './ConfirmDialog'
|
|
4
|
-
import './IndexingSettings.css'
|
|
5
|
-
|
|
6
|
-
export function IndexingSettings() {
|
|
7
|
-
// 索引状态
|
|
8
|
-
const [indexedFiles, setIndexedFiles] = useState(0)
|
|
9
|
-
const [isIndexing, setIsIndexing] = useState(false)
|
|
10
|
-
const [currentFile, setCurrentFile] = useState<string | null>(null)
|
|
11
|
-
const [progressPercentage, setProgressPercentage] = useState(100)
|
|
12
|
-
const [progressIndexed, setProgressIndexed] = useState(0)
|
|
13
|
-
const [progressTotal, setProgressTotal] = useState(0)
|
|
14
|
-
const [currentStage, setCurrentStage] = useState<'scanning' | 'parsing' | 'embedding' | 'storing' | 'done' | null>(null)
|
|
15
|
-
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false)
|
|
16
|
-
const [indexSize, setIndexSize] = useState('0 B')
|
|
17
|
-
const [lastUpdated, setLastUpdated] = useState<string | null>(null)
|
|
18
|
-
const cancelIndexingRef = useRef(false)
|
|
19
|
-
|
|
20
|
-
/** 格式化文件大小 */
|
|
21
|
-
const formatSize = useCallback((bytes: number): string => {
|
|
22
|
-
if (bytes < 1024) return `${bytes} B`
|
|
23
|
-
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`
|
|
24
|
-
if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`
|
|
25
|
-
return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`
|
|
26
|
-
}, [])
|
|
27
|
-
|
|
28
|
-
/** 格式化日期 */
|
|
29
|
-
const formatDate = useCallback((date: Date): string => {
|
|
30
|
-
const now = new Date()
|
|
31
|
-
const diff = now.getTime() - date.getTime()
|
|
32
|
-
const days = Math.floor(diff / (1000 * 60 * 60 * 24))
|
|
33
|
-
|
|
34
|
-
if (days === 0) {
|
|
35
|
-
const hours = Math.floor(diff / (1000 * 60 * 60))
|
|
36
|
-
if (hours === 0) {
|
|
37
|
-
const minutes = Math.floor(diff / (1000 * 60))
|
|
38
|
-
return minutes <= 1 ? '刚刚' : `${minutes} 分钟前`
|
|
39
|
-
}
|
|
40
|
-
return `${hours} 小时前`
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
if (days === 1) return '昨天'
|
|
44
|
-
if (days < 7) return `${days} 天前`
|
|
45
|
-
if (days < 30) return `${Math.floor(days / 7)} 周前`
|
|
46
|
-
if (days < 365) return `${Math.floor(days / 30)} 个月前`
|
|
47
|
-
return date.toLocaleDateString('zh-CN', { year: 'numeric', month: 'short', day: 'numeric' })
|
|
48
|
-
}, [])
|
|
49
|
-
|
|
50
|
-
/** 获取索引统计信息 */
|
|
51
|
-
const fetchIndexStats = useCallback(async () => {
|
|
52
|
-
try {
|
|
53
|
-
const bridge = (window as any).aiChatBridge
|
|
54
|
-
if (bridge?.getIndexStats) {
|
|
55
|
-
const stats = await bridge.getIndexStats()
|
|
56
|
-
setIndexedFiles(stats.totalDocuments || 0)
|
|
57
|
-
setIndexSize(formatSize(stats.indexSize || 0))
|
|
58
|
-
setLastUpdated(stats.lastUpdated ? formatDate(new Date(stats.lastUpdated)) : null)
|
|
59
|
-
} else {
|
|
60
|
-
// Bridge 方法未实现,显示默认值
|
|
61
|
-
setIndexedFiles(0)
|
|
62
|
-
setIndexSize('0 B')
|
|
63
|
-
setLastUpdated(null)
|
|
64
|
-
console.warn('getIndexStats 方法未在 bridge 中实现')
|
|
65
|
-
}
|
|
66
|
-
} catch (error) {
|
|
67
|
-
console.error('获取索引统计失败:', error)
|
|
68
|
-
// 出错时显示默认值
|
|
69
|
-
setIndexedFiles(0)
|
|
70
|
-
setIndexSize('0 B')
|
|
71
|
-
setLastUpdated(null)
|
|
72
|
-
}
|
|
73
|
-
}, [formatSize, formatDate])
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
// 进度监听器清理函数引用
|
|
77
|
-
const progressCleanupRef = useRef<(() => void) | null>(null)
|
|
78
|
-
|
|
79
|
-
/** 设置进度监听器 */
|
|
80
|
-
const setupProgressListener = useCallback(() => {
|
|
81
|
-
// 如果已有监听器,先清理
|
|
82
|
-
if (progressCleanupRef.current) {
|
|
83
|
-
progressCleanupRef.current()
|
|
84
|
-
progressCleanupRef.current = null
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const bridge = (window as any).aiChatBridge
|
|
88
|
-
if (!bridge?.onIndexProgress) {
|
|
89
|
-
return
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// 订阅进度更新(始终监听,即使没有主动触发索引)
|
|
93
|
-
progressCleanupRef.current = bridge.onIndexProgress((progress: {
|
|
94
|
-
indexed: number
|
|
95
|
-
total: number
|
|
96
|
-
currentFile?: string
|
|
97
|
-
stage: string
|
|
98
|
-
error?: string
|
|
99
|
-
}) => {
|
|
100
|
-
if (progress.error) {
|
|
101
|
-
console.error('索引错误:', progress.error)
|
|
102
|
-
setIsIndexing(false)
|
|
103
|
-
setCurrentFile(null)
|
|
104
|
-
return
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
if (progress.stage === 'cancelled') {
|
|
108
|
-
setIsIndexing(false)
|
|
109
|
-
setCurrentStage(null)
|
|
110
|
-
setCurrentFile(null)
|
|
111
|
-
cancelIndexingRef.current = true
|
|
112
|
-
return
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// 如果收到进度更新,说明正在索引
|
|
116
|
-
if (progress.stage !== 'done') {
|
|
117
|
-
setIsIndexing(true)
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// 更新阶段
|
|
121
|
-
setCurrentStage(progress.stage as 'scanning' | 'parsing' | 'embedding' | 'storing' | 'done' | null)
|
|
122
|
-
|
|
123
|
-
// 扫描阶段:total 为 0,使用 indexed 表示已扫描的文件数
|
|
124
|
-
if (progress.stage === 'scanning') {
|
|
125
|
-
setProgressIndexed(progress.indexed)
|
|
126
|
-
setProgressTotal(0)
|
|
127
|
-
setProgressPercentage(0) // 扫描阶段不显示百分比
|
|
128
|
-
} else {
|
|
129
|
-
setProgressIndexed(progress.indexed)
|
|
130
|
-
setProgressTotal(progress.total)
|
|
131
|
-
setProgressPercentage(progress.total > 0
|
|
132
|
-
? Math.round((progress.indexed / progress.total) * 100)
|
|
133
|
-
: 0)
|
|
134
|
-
}
|
|
135
|
-
setCurrentFile(progress.currentFile || null)
|
|
136
|
-
|
|
137
|
-
if (progress.stage === 'done') {
|
|
138
|
-
setIsIndexing(false)
|
|
139
|
-
setCurrentStage(null)
|
|
140
|
-
setCurrentFile(null)
|
|
141
|
-
// 同步完成后刷新统计
|
|
142
|
-
fetchIndexStats()
|
|
143
|
-
}
|
|
144
|
-
})
|
|
145
|
-
}, [fetchIndexStats])
|
|
146
|
-
|
|
147
|
-
/** 检查索引状态并恢复进度显示 */
|
|
148
|
-
const checkIndexStatus = useCallback(async () => {
|
|
149
|
-
const bridge = (window as any).aiChatBridge
|
|
150
|
-
if (!bridge?.getIndexStatus) {
|
|
151
|
-
return
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
try {
|
|
155
|
-
const status = await bridge.getIndexStatus()
|
|
156
|
-
if (status.isIndexing && status.lastProgress) {
|
|
157
|
-
// 如果有正在进行的索引任务,恢复进度显示
|
|
158
|
-
setIsIndexing(true)
|
|
159
|
-
const progress = status.lastProgress
|
|
160
|
-
|
|
161
|
-
// 恢复进度状态
|
|
162
|
-
setCurrentStage(progress.stage as 'scanning' | 'parsing' | 'embedding' | 'storing' | 'done' | null)
|
|
163
|
-
|
|
164
|
-
if (progress.stage === 'scanning') {
|
|
165
|
-
setProgressIndexed(progress.indexed)
|
|
166
|
-
setProgressTotal(0)
|
|
167
|
-
setProgressPercentage(0)
|
|
168
|
-
} else {
|
|
169
|
-
setProgressIndexed(progress.indexed)
|
|
170
|
-
setProgressTotal(progress.total)
|
|
171
|
-
setProgressPercentage(progress.total > 0
|
|
172
|
-
? Math.round((progress.indexed / progress.total) * 100)
|
|
173
|
-
: 0)
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
setCurrentFile(progress.currentFile || null)
|
|
177
|
-
}
|
|
178
|
-
} catch (error) {
|
|
179
|
-
console.error('检查索引状态失败:', error)
|
|
180
|
-
}
|
|
181
|
-
}, [])
|
|
182
|
-
|
|
183
|
-
/** 同步索引 */
|
|
184
|
-
const handleSync = useCallback(async () => {
|
|
185
|
-
if (isIndexing) return
|
|
186
|
-
|
|
187
|
-
const bridge = (window as any).aiChatBridge
|
|
188
|
-
if (!bridge?.syncIndex) {
|
|
189
|
-
console.error('syncIndex 方法未在 bridge 中实现')
|
|
190
|
-
return
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// 确保进度监听器已设置
|
|
194
|
-
if (!progressCleanupRef.current) {
|
|
195
|
-
setupProgressListener()
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
setIsIndexing(true)
|
|
199
|
-
cancelIndexingRef.current = false
|
|
200
|
-
setProgressPercentage(0)
|
|
201
|
-
setProgressIndexed(0)
|
|
202
|
-
setProgressTotal(0)
|
|
203
|
-
setCurrentStage(null)
|
|
204
|
-
setCurrentFile(null)
|
|
205
|
-
|
|
206
|
-
try {
|
|
207
|
-
await bridge.syncIndex()
|
|
208
|
-
} catch (error) {
|
|
209
|
-
if (!cancelIndexingRef.current) {
|
|
210
|
-
console.error('同步索引失败:', error)
|
|
211
|
-
}
|
|
212
|
-
setIsIndexing(false)
|
|
213
|
-
setCurrentFile(null)
|
|
214
|
-
}
|
|
215
|
-
}, [isIndexing, setupProgressListener])
|
|
216
|
-
|
|
217
|
-
/** 取消索引 */
|
|
218
|
-
const handleCancelIndex = useCallback(async () => {
|
|
219
|
-
cancelIndexingRef.current = true
|
|
220
|
-
setIsIndexing(false)
|
|
221
|
-
setCurrentFile(null)
|
|
222
|
-
|
|
223
|
-
const bridge = (window as any).aiChatBridge
|
|
224
|
-
if (bridge?.cancelIndex) {
|
|
225
|
-
try {
|
|
226
|
-
await bridge.cancelIndex()
|
|
227
|
-
} catch (error) {
|
|
228
|
-
console.error('取消索引失败:', error)
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
}, [])
|
|
232
|
-
|
|
233
|
-
/** 删除索引 */
|
|
234
|
-
const handleDeleteIndex = useCallback(async () => {
|
|
235
|
-
if (isIndexing) return
|
|
236
|
-
|
|
237
|
-
setShowDeleteConfirm(false)
|
|
238
|
-
|
|
239
|
-
const bridge = (window as any).aiChatBridge
|
|
240
|
-
if (!bridge?.deleteIndex) {
|
|
241
|
-
console.error('deleteIndex 方法未在 bridge 中实现')
|
|
242
|
-
return
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
try {
|
|
246
|
-
await bridge.deleteIndex()
|
|
247
|
-
|
|
248
|
-
// 刷新统计
|
|
249
|
-
await fetchIndexStats()
|
|
250
|
-
} catch (error) {
|
|
251
|
-
console.error('删除索引失败:', error)
|
|
252
|
-
}
|
|
253
|
-
}, [isIndexing, fetchIndexStats])
|
|
254
|
-
|
|
255
|
-
// 组件挂载时获取统计信息、注册监听器、检查索引状态并设置进度监听
|
|
256
|
-
useEffect(() => {
|
|
257
|
-
const init = async () => {
|
|
258
|
-
const bridge = (window as any).aiChatBridge
|
|
259
|
-
|
|
260
|
-
// 注册索引进度监听器
|
|
261
|
-
if (bridge?.registerIndexListener) {
|
|
262
|
-
try {
|
|
263
|
-
await bridge.registerIndexListener()
|
|
264
|
-
} catch (error) {
|
|
265
|
-
console.error('注册索引进度监听器失败:', error)
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
await fetchIndexStats()
|
|
270
|
-
setupProgressListener()
|
|
271
|
-
await checkIndexStatus()
|
|
272
|
-
}
|
|
273
|
-
init()
|
|
274
|
-
}, [fetchIndexStats, setupProgressListener, checkIndexStatus])
|
|
275
|
-
|
|
276
|
-
// 组件卸载时清理进度监听器
|
|
277
|
-
useEffect(() => {
|
|
278
|
-
return () => {
|
|
279
|
-
const bridge = (window as any).aiChatBridge
|
|
280
|
-
|
|
281
|
-
// 注销索引进度监听器
|
|
282
|
-
if (bridge?.unregisterIndexListener) {
|
|
283
|
-
try {
|
|
284
|
-
bridge.unregisterIndexListener()
|
|
285
|
-
} catch (error) {
|
|
286
|
-
console.error('注销索引进度监听器失败:', error)
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
if (progressCleanupRef.current) {
|
|
291
|
-
progressCleanupRef.current()
|
|
292
|
-
progressCleanupRef.current = null
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
}, [])
|
|
296
|
-
|
|
297
|
-
return (
|
|
298
|
-
<div className="indexing-settings">
|
|
299
|
-
{/* 代码库索引部分 */}
|
|
300
|
-
<div className="setting-item indexing-section">
|
|
301
|
-
<div className="setting-info">
|
|
302
|
-
<div className="setting-label">代码库索引</div>
|
|
303
|
-
<p className="setting-description">
|
|
304
|
-
嵌入代码库以改进上下文理解和知识。所有数据(嵌入向量、元数据和代码)都存储在本地。
|
|
305
|
-
</p>
|
|
306
|
-
<div className="indexing-content">
|
|
307
|
-
{/* 进度条 */}
|
|
308
|
-
<div className="progress-container">
|
|
309
|
-
<div className="progress-bar">
|
|
310
|
-
<div
|
|
311
|
-
className="progress-fill"
|
|
312
|
-
style={{ width: `${progressPercentage}%` }}
|
|
313
|
-
></div>
|
|
314
|
-
</div>
|
|
315
|
-
<div className="progress-text">
|
|
316
|
-
{isIndexing ? (
|
|
317
|
-
currentStage === 'scanning' ? (
|
|
318
|
-
<span>正在扫描文件... (已扫描 {progressIndexed.toLocaleString()} 个文件)</span>
|
|
319
|
-
) : (
|
|
320
|
-
<span>{progressPercentage}% ({progressIndexed}/{progressTotal})</span>
|
|
321
|
-
)
|
|
322
|
-
) : (
|
|
323
|
-
<span>{indexedFiles.toLocaleString()} 个文件</span>
|
|
324
|
-
)}
|
|
325
|
-
</div>
|
|
326
|
-
</div>
|
|
327
|
-
|
|
328
|
-
{/* 统计信息 */}
|
|
329
|
-
{!isIndexing && indexedFiles > 0 && (
|
|
330
|
-
<div className="stats-info">
|
|
331
|
-
<div className="stat-item">
|
|
332
|
-
<Icon icon="lucide:database" width={14} />
|
|
333
|
-
<span>索引大小: {indexSize}</span>
|
|
334
|
-
</div>
|
|
335
|
-
{lastUpdated && (
|
|
336
|
-
<div className="stat-item">
|
|
337
|
-
<Icon icon="lucide:clock" width={14} />
|
|
338
|
-
<span>最后更新: {lastUpdated}</span>
|
|
339
|
-
</div>
|
|
340
|
-
)}
|
|
341
|
-
</div>
|
|
342
|
-
)}
|
|
343
|
-
|
|
344
|
-
{/* 当前文件信息 */}
|
|
345
|
-
{isIndexing && currentFile && (
|
|
346
|
-
<div className="current-file">
|
|
347
|
-
<Icon icon="lucide:file-text" width={14} />
|
|
348
|
-
<span className="file-path">{currentFile}</span>
|
|
349
|
-
</div>
|
|
350
|
-
)}
|
|
351
|
-
|
|
352
|
-
{/* 操作按钮 */}
|
|
353
|
-
<div className="action-buttons">
|
|
354
|
-
{!isIndexing ? (
|
|
355
|
-
<button
|
|
356
|
-
className="edit-btn"
|
|
357
|
-
onClick={handleSync}
|
|
358
|
-
>
|
|
359
|
-
<Icon icon="lucide:refresh-cw" width={16} />
|
|
360
|
-
<span>同步</span>
|
|
361
|
-
</button>
|
|
362
|
-
) : (
|
|
363
|
-
<button
|
|
364
|
-
className="edit-btn"
|
|
365
|
-
onClick={handleCancelIndex}
|
|
366
|
-
>
|
|
367
|
-
<Icon icon="lucide:x" width={16} />
|
|
368
|
-
<span>取消</span>
|
|
369
|
-
</button>
|
|
370
|
-
)}
|
|
371
|
-
<button
|
|
372
|
-
className="edit-btn delete-btn"
|
|
373
|
-
disabled={isIndexing}
|
|
374
|
-
onClick={() => setShowDeleteConfirm(true)}
|
|
375
|
-
>
|
|
376
|
-
<Icon icon="lucide:trash-2" width={16} />
|
|
377
|
-
<span>删除索引</span>
|
|
378
|
-
</button>
|
|
379
|
-
</div>
|
|
380
|
-
</div>
|
|
381
|
-
</div>
|
|
382
|
-
</div>
|
|
383
|
-
|
|
384
|
-
{/* 删除确认对话框 */}
|
|
385
|
-
<ConfirmDialog
|
|
386
|
-
visible={showDeleteConfirm}
|
|
387
|
-
type="danger"
|
|
388
|
-
title="删除索引"
|
|
389
|
-
message={`确定要删除所有索引吗?\n\n这将删除 ${indexedFiles.toLocaleString()} 个文件的索引数据(${indexSize}),此操作无法撤销。`}
|
|
390
|
-
confirmText="删除"
|
|
391
|
-
cancelText="取消"
|
|
392
|
-
onConfirm={handleDeleteIndex}
|
|
393
|
-
onCancel={() => setShowDeleteConfirm(false)}
|
|
394
|
-
/>
|
|
395
|
-
</div>
|
|
396
|
-
)
|
|
397
|
-
}
|
|
398
|
-
|