From 6e06102a12fa43c295a6e8f64bdc4d1169a64747 Mon Sep 17 00:00:00 2001 From: Wenjie Zhang Date: Sun, 27 Jul 2025 00:30:30 +0800 Subject: [PATCH] =?UTF-8?q?chore(database):=20=E4=BC=98=E5=8C=96DataBaseIn?= =?UTF-8?q?foView=E7=BB=84=E4=BB=B6=EF=BC=8C=E6=B7=BB=E5=8A=A0=E6=89=B9?= =?UTF-8?q?=E9=87=8F=E5=88=A0=E9=99=A4=E6=96=87=E4=BB=B6=E8=BF=9B=E5=BA=A6?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=EF=BC=8C=E6=94=B9=E8=BF=9B=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E9=80=89=E6=8B=A9=E9=80=BB=E8=BE=91=EF=BC=8C=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E6=A0=B7=E5=BC=8F=E4=BB=A5=E6=8F=90=E5=8D=87=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E4=BD=93=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/src/components/AgentChatComponent.vue | 14 +- web/src/views/DataBaseInfoView.vue | 185 +++++++++++++++------- 2 files changed, 134 insertions(+), 65 deletions(-) diff --git a/web/src/components/AgentChatComponent.vue b/web/src/components/AgentChatComponent.vue index 265b09e8..c3a11631 100644 --- a/web/src/components/AgentChatComponent.vue +++ b/web/src/components/AgentChatComponent.vue @@ -1256,15 +1256,15 @@ const mergeMessageChunk = (chunks) => { if (chunks.length === 0) return null; // 以第一个chunk为基础 - for (const c of chunks) { - if (c.additional_kwargs?.tool_calls) { - console.warn("chunks", toRaw(c)) - break; - } - } + // for (const c of chunks) { + // if (c.additional_kwargs?.tool_calls) { + // console.warn("chunks", toRaw(c)) + // break; + // } + // } // 深拷贝第一个chunk作为结果 const result = JSON.parse(JSON.stringify(chunks[0])); - console.debug("result", toRaw(result)) + // console.debug("result", toRaw(result)) result.content = result.content || ''; result.additional_kwargs = result.additional_kwargs || {}; diff --git a/web/src/views/DataBaseInfoView.vue b/web/src/views/DataBaseInfoView.vue index eda100d8..87ca5363 100644 --- a/web/src/views/DataBaseInfoView.vue +++ b/web/src/views/DataBaseInfoView.vue @@ -146,7 +146,7 @@ ⚠️ {{ getSelectedOcrMessage() }} - ✅ OCR服务运行正常 + ✅ {{ getSelectedOcrMessage() }} @@ -352,7 +352,18 @@
- {{ selectedRowKeys.length }} 项 +
+ {{ selectedRowKeys.length }} 项 + + 选择失败 + +
{ return documentApi.deleteDocument(databaseId.value, fileId) .then(data => { console.log(data) - message.success(data.message || '删除成功') + // message.success(data.message || '删除成功') getDatabaseInfo() }) .catch(error => { @@ -1110,44 +1122,75 @@ const handleBatchDelete = () => { } const files = database.value.files || {}; - const fileCount = selectedRowKeys.value.length; + const validFileIds = selectedRowKeys.value.filter(fileId => { + const file = files[fileId]; + return file && !(file.status === 'processing' || file.status === 'waiting'); + }); + + if (validFileIds.length === 0) { + message.info('没有可删除的文件'); + return; + } Modal.confirm({ title: '批量删除文件', - content: `确定要删除选中的 ${fileCount} 个文件吗?`, + content: `确定要删除选中的 ${validFileIds.length} 个文件吗?`, okText: '确认', cancelText: '取消', onOk: async () => { state.batchDeleting = true; + state.batchDeleteProgress.current = 0; + state.batchDeleteProgress.total = validFileIds.length; + + let successCount = 0; + let failureCount = 0; + + // 显示初始进度 + let progressMessage = message.loading(`正在删除文件 0/${validFileIds.length}`, 0); + try { - const promises = selectedRowKeys.value - .filter(fileId => { - const file = files[fileId]; - return !(file.status === 'processing' || file.status === 'waiting'); - }) - .map(fileId => - deleteFile(fileId) - ); + // 逐个删除文件以显示进度 + for (let i = 0; i < validFileIds.length; i++) { + const fileId = validFileIds[i]; + try { + await deleteFile(fileId); + successCount++; + } catch (error) { + console.error(`删除文件 ${fileId} 失败:`, error); + failureCount++; + } - const results = await Promise.allSettled(promises); + // 更新进度 + state.batchDeleteProgress.current = i + 1; + progressMessage?.(); - const succeeded = results.filter(r => r.status === 'fulfilled').length; - const failed = results.filter(r => r.status === 'rejected').length; - - if (succeeded > 0) { - message.success(`成功删除 ${succeeded} 个文件`); + // 显示当前进度,如果不是最后一个文件 + if (i + 1 < validFileIds.length) { + progressMessage = message.loading(`正在删除文件 ${i + 1}/${validFileIds.length}`, 0); + } } - if (failed > 0) { - message.error(`${failed} 个文件删除失败`); + + // 显示最终结果 + progressMessage?.(); + + if (successCount > 0 && failureCount === 0) { + message.success(`成功删除 ${successCount} 个文件`); + } else if (successCount > 0 && failureCount > 0) { + message.warning(`成功删除 ${successCount} 个文件,${failureCount} 个文件删除失败`); + } else if (failureCount > 0) { + message.error(`${failureCount} 个文件删除失败`); } selectedRowKeys.value = []; // 清空选择 getDatabaseInfo(); // 刷新列表状态 } catch (error) { + progressMessage?.(); console.error('批量删除出错:', error); message.error('批量删除过程中发生错误'); } finally { state.batchDeleting = false; + state.batchDeleteProgress.current = 0; + state.batchDeleteProgress.total = 0; } }, }); @@ -1216,13 +1259,13 @@ watch(() => route.params.database_id, async (newId) => { // 监听数据库信息变化,重置过滤条件 watch(() => database.value, () => { - // 当数据库信息更新时,重置过滤条件和分页 + // 当数据库信息更新时,重置过滤条件和选中状态 filenameFilter.value = ''; - paginationCompact.value.current = 1; selectedRowKeys.value = []; // 重置排序状态 sortState.value.field = null; sortState.value.order = null; + // 分页重置由 filteredFiles 计算属性自动处理 }, { deep: true }); @@ -1328,7 +1371,7 @@ const handleKeyDown = (e) => { if (e.key === 'Escape' && filenameFilter.value) { filenameFilter.value = ''; selectedRowKeys.value = []; - paginationCompact.value.current = 1; + // 分页重置由 filteredFiles 计算属性自动处理 } }; @@ -1604,6 +1647,16 @@ const filteredFiles = computed(() => { }); } + // 同步分页状态 - 确保当前页码在有效范围内 + const totalPages = Math.ceil(filtered.length / paginationCompact.value.pageSize); + if (totalPages > 0 && paginationCompact.value.current > totalPages) { + // 如果当前页超出范围,调整到最后一页 + paginationCompact.value.current = totalPages; + } else if (filtered.length === 0) { + // 如果没有数据,重置到第一页 + paginationCompact.value.current = 1; + } + return filtered; }); @@ -1627,15 +1680,18 @@ const paginationCompact = ref({ showTotal: (total) => `${total}`, size: 'small', showQuickJumper: false, + onChange: (page, pageSize) => { + paginationCompact.value.current = page; + paginationCompact.value.pageSize = pageSize; + // 清空选中的行,因为分页后选中的行可能不在当前视图中 + selectedRowKeys.value = []; + }, }); // 监听过滤后的文件列表变化,更新分页总数 watch(filteredFiles, (newFiles) => { paginationCompact.value.total = newFiles.length; - // 如果当前页超出范围,重置到第一页 - if (paginationCompact.value.current > Math.ceil(newFiles.length / paginationCompact.value.pageSize)) { - paginationCompact.value.current = 1; - } + // filteredFiles 计算属性已经处理了分页范围检查,这里不需要重复处理 }, { immediate: true }); // 行选择改变处理 @@ -1649,49 +1705,43 @@ const getCheckboxProps = (record) => ({ }); // 排序事件处理 -const handleTableChange = (pagination, filters, sorter) => { +const handleTableChange = (_, __, sorter) => { // 处理排序 if (sorter && sorter.field) { sortState.value.field = sorter.field; sortState.value.order = sorter.order; + // 清空选中的行,因为排序后选中的行可能不在当前视图中 + selectedRowKeys.value = []; + // 不再强制重置到第一页,让 filteredFiles 计算属性自动处理分页调整 } - - // 处理分页 - if (pagination) { - paginationCompact.value.current = pagination.current; - paginationCompact.value.pageSize = pagination.pageSize; - } - - // 如果是排序操作,重置分页到第一页 - if (sorter && sorter.field) { - paginationCompact.value.current = 1; - } - - // 清空选中的行,因为排序或分页后选中的行可能不在当前视图中 - selectedRowKeys.value = []; }; // 过滤相关方法 -const onFilterSearch = (value) => { - filenameFilter.value = value; - // 重置分页到第一页 - paginationCompact.value.current = 1; - // 清空选中的行,因为过滤后选中的行可能不在当前视图中 - selectedRowKeys.value = []; - // 重置排序状态 - sortState.value.field = null; - sortState.value.order = null; -}; - const onFilterChange = (e) => { filenameFilter.value = e.target.value; - // 重置分页到第一页 - paginationCompact.value.current = 1; // 清空选中的行,因为过滤后选中的行可能不在当前视图中 selectedRowKeys.value = []; // 重置排序状态 sortState.value.field = null; sortState.value.order = null; + // 分页调整由 filteredFiles 计算属性自动处理 +}; + +// 选择所有失败的文件 +const selectAllFailedFiles = () => { + const failedFiles = filteredFiles.value + .filter(file => file.status === 'failed') + .map(file => file.file_id); + + // 合并当前选中的文件ID和失败的文件ID,去重 + const newSelectedKeys = [...new Set([...selectedRowKeys.value, ...failedFiles])]; + selectedRowKeys.value = newSelectedKeys; + + if (failedFiles.length > 0) { + message.success(`已选择 ${failedFiles.length} 个失败的文件`); + } else { + message.info('当前没有失败的文件'); + } }; // 计算是否可以批量删除 @@ -2486,11 +2536,29 @@ const getFileIconColor = (filename) => { margin-bottom: 4px; flex-shrink: 0; + .batch-info { + display: flex; + align-items: center; + gap: 8px; + } + span { font-size: 11px; font-weight: 500; color: var(--gray-700); } + + .ant-btn { + font-size: 11px; + padding: 0 6px; + height: 22px; + border-radius: 3px; + + &:hover { + background-color: var(--main-light-4); + color: var(--main-color); + } + } } .my-table-compact { @@ -2745,8 +2813,8 @@ const getFileIconColor = (filename) => { } .panel-action-btn { - width: 32px; - height: 32px; + width: 30px; + height: 30px; display: flex; align-items: center; justify-content: center; @@ -2756,6 +2824,7 @@ const getFileIconColor = (filename) => { transition: all 0.1s ease; color: var(--gray-700); transform: scaleX(-1); + padding: 4px; &:hover { background-color: var(--main-light-5);