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
+