style: 更新文件管理功能,支持HTML文件图标和颜色,优化文件选择状态管理

This commit is contained in:
Wenjie Zhang 2025-10-25 16:01:50 +08:00
parent 66abbc986b
commit fdc4f174a9
6 changed files with 106 additions and 36 deletions

View File

@ -18,10 +18,9 @@
- [ ] 统一图谱数据结构,优化可视化方式 [#298](https://github.com/xerrors/Yuxi-Know/issues/298) <Badge type="info" text="0.4" />
- [ ] 集成智能体评估,首先使用命令行来实现,然后考虑放在 UI 里面展示
- [ ] 开发与生产环境隔离,构建生产镜像 <Badge type="info" text="0.4" />
- [ ] 支持 MinerU 2.5 的解析方法 <Badge type="info" text="0.3.5" />
- [ ] MinerU 处理的结果转义字符没有处理
- [ ] 文件管理1文件选择的时候会跨数据库2文件校验会算上失败的文件
- [ ] Tasker 中获取历史任务的时候,仅获取 top100 个 task。
- [x] 支持 MinerU 2.5 的解析方法 <Badge type="info" text="0.3.5" />
- [x] 文件管理1文件选择的时候会跨数据库2文件校验会算上失败的文件
- [x] Tasker 中获取历史任务的时候,仅获取 top100 个 task。
## Later

View File

@ -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

View File

@ -10,12 +10,21 @@
>添加文件</a-button>
</div>
<div class="panel-actions">
<a-input
v-model:value="filenameFilter"
placeholder="搜索文件名"
size="small"
class="action-searcher"
allow-clear
@change="onFilterChange"
/>
<a-button
type="text"
@click="handleRefresh"
:loading="refreshing"
:icon="h(ReloadOutlined)"
:icon="h(RefreshCcw)"
title="刷新"
class="panel-action-btn"
/>
<!-- <a-button
@click="toggleAutoRefresh"
@ -26,22 +35,14 @@
>
Auto
</a-button> -->
<a-input
v-model:value="filenameFilter"
placeholder="搜索文件名"
size="small"
style="width: 120px; margin-right: 8px; border-radius: 6px; padding: 4px 8px;"
allow-clear
@change="onFilterChange"
/>
<!-- <a-button
<a-button
type="text"
@click="toggleRightPanel"
:icon="h(ChevronLast)"
title="切换右侧面板"
class="panel-action-btn expand"
:class="{ 'expanded': props.rightPanelVisible }"
/> -->
/>
</div>
</div>
@ -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);
}

View File

@ -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();
}
}

View File

@ -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'

View File

@ -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;
}
}
</style>
</style>