diff --git a/web/src/components/ChatSidebarComponent.vue b/web/src/components/ChatSidebarComponent.vue index 91996731..5422bf86 100644 --- a/web/src/components/ChatSidebarComponent.vue +++ b/web/src/components/ChatSidebarComponent.vue @@ -33,11 +33,11 @@ diff --git a/web/src/components/FileTable.vue b/web/src/components/FileTable.vue index 2d276983..57904a94 100644 --- a/web/src/components/FileTable.vue +++ b/web/src/components/FileTable.vue @@ -1,54 +1,88 @@ @@ -260,14 +295,11 @@ import { FolderFilled, FolderOpenFilled, FileTextFilled, - PlusOutlined, - FolderAddOutlined, - ReloadOutlined, } from '@ant-design/icons-vue'; import { Trash2, Download, - RefreshCw, + RotateCw, ChevronLast, Ellipsis, FolderPlus, @@ -276,11 +308,36 @@ import { FileCheck, Plus, Database, + FileUp, + FolderUp, + Search, + Filter, + ArrowUpDown, + ChevronDown, } from 'lucide-vue-next'; const store = useDatabaseStore(); const userStore = useUserStore(); +const sortField = ref('filename'); +const sortOptions = [ + { label: '文件名', value: 'filename' }, + { label: '创建时间', value: 'created_at' }, + { label: '状态', value: 'status' }, +]; + +const handleSortMenuClick = (e) => { + sortField.value = e.key; +}; + +const handleStatusMenuClick = (e) => { + if (e.key === 'all') { + statusFilter.value = null; + } else { + statusFilter.value = e.key; + } +}; + // Status text mapping const getStatusText = (status) => { const map = { @@ -613,7 +670,21 @@ const buildFileTree = (fileList) => { nodes.sort((a, b) => { if (a.is_folder && !b.is_folder) return -1; if (!a.is_folder && b.is_folder) return 1; - return (a.filename || '').localeCompare(b.filename || ''); + + if (sortField.value === 'filename') { + return (a.filename || '').localeCompare(b.filename || ''); + } else if (sortField.value === 'created_at') { + return new Date(b.created_at || 0) - new Date(a.created_at || 0); + } else if (sortField.value === 'status') { + const statusOrder = { + 'done': 1, 'indexed': 1, + 'processing': 2, 'indexing': 2, 'parsing': 2, + 'waiting': 3, 'uploaded': 3, 'parsed': 3, + 'failed': 4, 'error_indexing': 4, 'error_parsing': 4 + }; + return (statusOrder[a.status] || 5) - (statusOrder[b.status] || 5); + } + return 0; }); nodes.forEach(node => { if (node.children) sortNodes(node.children); @@ -692,15 +763,15 @@ const canBatchIndex = computed(() => { return selectedRowKeys.value.some(key => { const file = filteredFiles.value.find(f => f.file_id === key); return file && !lock.value && ( - file.status === 'parsed' || - file.status === 'error_indexing' || + file.status === 'parsed' || + file.status === 'error_indexing' || (!isLightRAG.value && (file.status === 'done' || file.status === 'indexed')) ); }); }); -const showAddFilesModal = () => { - emit('showAddFilesModal'); +const showAddFilesModal = (options = {}) => { + emit('showAddFilesModal', options); }; const handleRefresh = () => { @@ -779,8 +850,8 @@ const handleBatchIndex = async () => { const validKeys = selectedRowKeys.value.filter(key => { const file = files.value.find(f => f.file_id === key); return file && ( - file.status === 'parsed' || - file.status === 'error_indexing' || + file.status === 'parsed' || + file.status === 'error_indexing' || (!isLightRAG.value && (file.status === 'done' || file.status === 'indexed')) ); }); @@ -978,29 +1049,10 @@ import ChunkParamsConfig from '@/components/ChunkParamsConfig.vue'; display: flex; justify-content: space-between; align-items: center; - margin-bottom: 4px; flex-shrink: 0; - padding: 4px 4px; + padding: 8px 8px; } -.search-container { - display: flex; - align-items: center; - - button { - padding: 0 8px; - - svg { - width: 16px; - height: 16px; - } - } - - button:hover { - background-color: var(--gray-50); - color: var(--main-color); - } -} .panel-actions { display: flex; @@ -1225,14 +1277,29 @@ import ChunkParamsConfig from '@/components/ChunkParamsConfig.vue'; :deep(.drop-over-folder) { background-color: var(--primary-50) !important; - outline: 2px dashed var(--main-color); - outline-offset: -2px; - z-index: 10; + outline: 2px dashed var(--main-color); + outline-offset: -2px; + z-index: 10; - td { - background-color: transparent !important; + td { + background-color: transparent !important; + } + } + + .upload-btn-group { + display: flex; + align-items: center; + gap: 8px; + + .upload-btn { + height: 28px; + font-size: 13px; + display: flex; + align-items: center; + justify-content: center; + gap: 4px; + } } -}