diff --git a/docs/changelog/roadmap.md b/docs/changelog/roadmap.md index 5464011e..f3ab953f 100644 --- a/docs/changelog/roadmap.md +++ b/docs/changelog/roadmap.md @@ -18,10 +18,9 @@ - [ ] 统一图谱数据结构,优化可视化方式 [#298](https://github.com/xerrors/Yuxi-Know/issues/298) - [ ] 集成智能体评估,首先使用命令行来实现,然后考虑放在 UI 里面展示 - [ ] 开发与生产环境隔离,构建生产镜像 -- [ ] 支持 MinerU 2.5 的解析方法 - - [ ] MinerU 处理的结果转义字符没有处理 -- [ ] 文件管理:(1)文件选择的时候会跨数据库;(2)文件校验会算上失败的文件; -- [ ] Tasker 中获取历史任务的时候,仅获取 top100 个 task。 +- [x] 支持 MinerU 2.5 的解析方法 +- [x] 文件管理:(1)文件选择的时候会跨数据库;(2)文件校验会算上失败的文件; +- [x] Tasker 中获取历史任务的时候,仅获取 top100 个 task。 ## Later diff --git a/src/knowledge/manager.py b/src/knowledge/manager.py index de8569fb..429da5e2 100644 --- a/src/knowledge/manager.py +++ b/src/knowledge/manager.py @@ -359,6 +359,8 @@ class KnowledgeBaseManager: for file_info in kb_instance.files_meta.values(): if file_info.get("database_id") != db_id: continue + if file_info.get("status") == "failed": + continue if file_info.get("content_hash") == content_hash: return True diff --git a/web/src/components/FileTable.vue b/web/src/components/FileTable.vue index 4c7f7406..62c36f67 100644 --- a/web/src/components/FileTable.vue +++ b/web/src/components/FileTable.vue @@ -10,12 +10,21 @@ >添加文件
+ - - + />
@@ -134,10 +135,9 @@ import { ClockCircleFilled, DeleteOutlined, PlusOutlined, - ReloadOutlined, DownloadOutlined, } from '@ant-design/icons-vue'; -import { ChevronLast } from 'lucide-vue-next'; +import { ChevronLast, RefreshCcw } from 'lucide-vue-next'; const store = useDatabaseStore(); const userStore = useUserStore(); @@ -403,6 +403,14 @@ import { parseToShanghai } from '@/utils/time'; display: flex; align-items: center; gap: 6px; + + .action-searcher { + width: 120px; + margin-right: 8px; + border-radius: 6px; + padding: 4px 8px; + border: none; + } } .batch-actions-compact { @@ -500,25 +508,27 @@ import { parseToShanghai } from '@/utils/time'; } .panel-action-btn { + display: flex; + align-items: center; + justify-content: center; border-radius: 6px; - border: 1px solid var(--gray-300); - background-color: var(--gray-50); + /* border: 1px solid var(--gray-300); */ + /* background-color: var(--gray-50); */ color: var(--gray-700); transition: all 0.1s ease; + font-size: 12px; + + svg { + height: 16px; + } &.expand { transform: scaleX(-1); } -} -.panel-action-btn.expanded { - width: 30px; - height: 30px; - display: flex; - align-items: center; - justify-content: center; - transform: scaleX(1); - padding: 4px; + &.expanded { + transform: scaleX(1); + } } .panel-action-btn.auto-refresh-btn.ant-btn-primary { @@ -535,19 +545,19 @@ import { parseToShanghai } from '@/utils/time'; .panel-action-btn:hover { background-color: var(--main-5); color: var(--main-color); + border: 1px solid var(--main-color); } -.panel-action-btn.expanded:hover { - background-color: var(--main-5); - border-color: var(--main-color); - color: var(--main-color); -} /* Table row selection styling */ :deep(.ant-table-tbody > tr.ant-table-row-selected > td) { background-color: var(--main-5); } +:deep(.ant-table-tbody > tr.ant-table-row-selected.ant-table-row:hover > td) { + background-color: var(--main-20); +} + :deep(.ant-table-tbody > tr:hover > td) { background-color: var(--main-5); } diff --git a/web/src/stores/database.js b/web/src/stores/database.js index e1febc64..1a07e370 100644 --- a/web/src/stores/database.js +++ b/web/src/stores/database.js @@ -40,6 +40,8 @@ export const useDatabaseStore = defineStore('database', () => { }); let refreshInterval = null; + let autoRefreshSource = null; // Tracks whether auto-refresh was user-triggered or automatic + let autoRefreshManualOverride = false; // Indicates user explicitly disabled auto-refresh // Actions async function getDatabaseInfo(id) { @@ -51,6 +53,7 @@ export const useDatabaseStore = defineStore('database', () => { try { const data = await databaseApi.getDatabaseInfo(db_id); database.value = data; + ensureAutoRefreshForProcessing(data?.files); await loadQueryParams(db_id); } catch (error) { console.error(error); @@ -180,6 +183,40 @@ export const useDatabaseStore = defineStore('database', () => { }); } + const processingStatuses = new Set(['processing', 'waiting']); + + function enableAutoRefresh(source = 'auto') { + if (autoRefreshManualOverride && source === 'auto') { + return; + } + + if (!state.autoRefresh) { + state.autoRefresh = true; + autoRefreshSource = source; + autoRefreshManualOverride = false; + startAutoRefresh(); + return; + } + + if (source === 'auto' && autoRefreshSource !== 'manual') { + autoRefreshSource = 'auto'; + } + } + + function ensureAutoRefreshForProcessing(filesMap) { + const files = Object.values(filesMap || {}); + const hasPending = files.some((file) => file && processingStatuses.has(file.status)); + if (hasPending) { + enableAutoRefresh('auto'); + } else if (autoRefreshSource === 'auto' && state.autoRefresh) { + state.autoRefresh = false; + autoRefreshSource = null; + autoRefreshManualOverride = false; + stopAutoRefresh(); + } + return hasPending; + } + async function addFiles({ items, contentType, params }) { if (items.length === 0) { message.error(contentType === 'file' ? '请先上传文件' : '请输入有效的网页链接'); @@ -191,6 +228,7 @@ export const useDatabaseStore = defineStore('database', () => { const data = await documentApi.addDocuments(databaseId.value, items, { ...params, content_type: contentType }); if (data.status === 'success' || data.status === 'queued') { const itemType = contentType === 'file' ? '文件' : 'URL'; + enableAutoRefresh('auto'); message.success(data.message || `${itemType}已提交处理,请在任务中心查看进度`); if (data.task_id) { taskerStore.registerQueuedTask({ @@ -299,10 +337,15 @@ export const useDatabaseStore = defineStore('database', () => { } function toggleAutoRefresh() { - state.autoRefresh = !state.autoRefresh; - if (state.autoRefresh) { + const nextState = !state.autoRefresh; + state.autoRefresh = nextState; + if (nextState) { + autoRefreshSource = 'manual'; + autoRefreshManualOverride = false; startAutoRefresh(); } else { + autoRefreshManualOverride = true; + autoRefreshSource = null; stopAutoRefresh(); } } diff --git a/web/src/utils/file_utils.js b/web/src/utils/file_utils.js index 97a89262..65fc6855 100644 --- a/web/src/utils/file_utils.js +++ b/web/src/utils/file_utils.js @@ -38,6 +38,10 @@ export const getFileIcon = (filename) => { 'bmp': FileImageFilled, 'svg': FileImageFilled, 'webp': FileImageFilled, + + // HTML文件 + 'html': FileTextFilled, + 'htm': FileTextFilled, } return iconMap[extension] || FileUnknownFilled @@ -79,6 +83,10 @@ export const getFileIconColor = (filename) => { 'bmp': '#722ed1', 'svg': '#722ed1', 'webp': '#722ed1', + + // HTML文件 - 橙色 + 'html': '#fa8c16', + 'htm': '#fa8c16', } return colorMap[extension] || '#8c8c8c' diff --git a/web/src/views/DataBaseInfoView.vue b/web/src/views/DataBaseInfoView.vue index c15455e4..60d62d57 100644 --- a/web/src/views/DataBaseInfoView.vue +++ b/web/src/views/DataBaseInfoView.vue @@ -175,8 +175,15 @@ const toggleGraphMaximize = () => { isGraphMaximized.value = !isGraphMaximized.value; }; +const resetFileSelectionState = () => { + store.selectedRowKeys = []; + store.selectedFile = null; + store.state.fileDetailModalVisible = false; +}; + watch(() => route.params.database_id, async (newId) => { store.databaseId = newId; + resetFileSelectionState(); store.stopAutoRefresh(); await store.getDatabaseInfo(newId); store.startAutoRefresh(); @@ -187,6 +194,7 @@ watch(() => route.params.database_id, async (newId) => { // 组件挂载时启动示例轮播 onMounted(() => { store.databaseId = route.params.database_id; + resetFileSelectionState(); store.getDatabaseInfo(); store.startAutoRefresh(); @@ -549,4 +557,4 @@ const handleMouseUpHorizontal = () => { overflow: hidden; } } - \ No newline at end of file +