chore(database): 优化DataBaseInfoView组件,添加批量删除文件进度显示,改进文件选择逻辑,更新样式以提升用户体验

This commit is contained in:
Wenjie Zhang 2025-07-27 00:30:30 +08:00
parent 32c34762d3
commit 6e06102a12
2 changed files with 134 additions and 65 deletions

View File

@ -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 || {};

View File

@ -146,7 +146,7 @@
{{ getSelectedOcrMessage() }}
</span>
<span v-else-if="getSelectedOcrStatus() === 'healthy'" class="ocr-healthy">
OCR服务运行正常
{{ getSelectedOcrMessage() }}
</span>
</div>
</div>
@ -352,7 +352,18 @@
</div>
<div class="batch-actions-compact" v-if="selectedRowKeys.length > 0">
<span>{{ selectedRowKeys.length }} </span>
<div class="batch-info">
<span>{{ selectedRowKeys.length }} </span>
<a-button
type="text"
size="small"
@click="selectAllFailedFiles"
:disabled="state.lock"
title="选择所有失败的文件"
>
选择失败
</a-button>
</div>
<a-button
type="text"
danger
@ -657,6 +668,7 @@ const state = reactive({
refreshInterval: null,
curPage: "files",
batchDeleting: false,
batchDeleteProgress: { current: 0, total: 0 }, //
chunkLoading: false,
autoRefresh: false,
loading: false,
@ -1072,7 +1084,7 @@ const deleteFile = (fileId) => {
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);
// IDID
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);