/** * TalkingQ Platform - 知识库详情页面 * 包含文件管理、标签管理、切片管理、命中测试等功能 * * API预留: * - GET /api/v1/knowledge-bases/:id - 获取知识库详情 * - GET /api/v1/knowledge-bases/:id/files - 获取文件列表 * - POST /api/v1/knowledge-bases/:id/files - 上传文件 * - DELETE /api/v1/knowledge-bases/:id/files/:fileId - 删除文件 * - POST /api/v1/knowledge-bases/:id/files/:fileId/reparse - 重新解析 * - GET /api/v1/knowledge-bases/:id/slices - 获取切片列表 * - PUT /api/v1/knowledge-bases/:id/slices/:sliceId - 更新切片 * - GET /api/v1/knowledge-bases/:id/hit-test - 命中测试 * - GET /api/v1/knowledge-bases/:id/metadata - 获取Metadata统计 */ registerPage('kb-detail', function(container) { // ==================== 状态管理 ==================== const urlParams = new URLSearchParams(window.location.search); const kbId = urlParams.get('id') || 'kb-001'; const initialTab = urlParams.get('tab') || 'files'; let currentTab = initialTab; let selectedFiles = new Set(); let isLoading = true; // ==================== API预留 - 后端接口定义 ==================== /** * 获取知识库详情 * GET /api/v1/knowledge-bases/:id * Response: { id, name, description, type, status, docs, size, tags, createdAt, updatedAt } */ const API_GET_DETAIL = '/api/v1/knowledge-bases/:id'; /** * 获取文件列表 * GET /api/v1/knowledge-bases/:id/files * Query: { page, pageSize, search, status } * Response: { list: [], total, page, pageSize } */ const API_GET_FILES = '/api/v1/knowledge-bases/:id/files'; /** * 上传文件 * POST /api/v1/knowledge-bases/:id/files * FormData: { file, category } * Response: { fileId, fileName, status } */ const API_UPLOAD_FILE = '/api/v1/knowledge-bases/:id/files'; /** * 删除文件 * DELETE /api/v1/knowledge-bases/:id/files/:fileId * Response: { success: true } */ const API_DELETE_FILE = '/api/v1/knowledge-bases/:id/files/:fileId'; /** * 重新解析文件 * POST /api/v1/knowledge-bases/:id/files/:fileId/reparse * Response: { success: true } */ const API_REPARSE_FILE = '/api/v1/knowledge-bases/:id/files/:fileId/reparse'; /** * 获取切片列表 * GET /api/v1/knowledge-bases/:id/slices * Query: { page, pageSize, search, fileId } * Response: { list: [], total, page, pageSize } */ const API_GET_SLICES = '/api/v1/knowledge-bases/:id/slices'; /** * 更新切片 * PUT /api/v1/knowledge-bases/:id/slices/:sliceId * Body: { content: string } * Response: { success: true, chars: number } */ const API_UPDATE_SLICE = '/api/v1/knowledge-bases/:id/slices/:sliceId'; /** * 获取切片历史版本 * GET /api/v1/knowledge-bases/:id/slices/:sliceId/history * Response: { list: [{ version, content, updatedAt, updatedBy }] } */ const API_SLICE_HISTORY = '/api/v1/knowledge-bases/:id/slices/:sliceId/history'; /** * 回滚切片 * POST /api/v1/knowledge-bases/:id/slices/:sliceId/rollback * Body: { version: number } * Response: { success: true } */ const API_ROLLBACK_SLICE = '/api/v1/knowledge-bases/:id/slices/:sliceId/rollback'; /** * 命中测试 * GET /api/v1/knowledge-bases/:id/hit-test * Query: { query, topK, similarityThreshold, mode } * Response: { results: [{ content, source, score, chars, metadata }] } */ const API_HIT_TEST = '/api/v1/knowledge-bases/:id/hit-test'; /** * 获取测试历史 * GET /api/v1/knowledge-bases/:id/test-history * Response: { list: [{ id, time, query, recallCount, avgScore }] } */ const API_TEST_HISTORY = '/api/v1/knowledge-bases/:id/test-history'; /** * 获取Metadata统计 * GET /api/v1/knowledge-bases/:id/metadata * Response: { tags: [], categories: [], formats: [] } */ const API_GET_METADATA = '/api/v1/knowledge-bases/:id/metadata'; /** * 重建索引 * POST /api/v1/knowledge-bases/:id/rebuild * Response: { success: true, taskId } */ const API_REBUILD_INDEX = '/api/v1/knowledge-bases/:id/rebuild'; /** * 删除知识库 * DELETE /api/v1/knowledge-bases/:id * Response: { success: true } */ const API_DELETE_KB = '/api/v1/knowledge-bases/:id'; // ==================== 模拟数据 ==================== const kbData = { id: kbId, name: '儿童科学百科', description: '包含各类儿童科学知识的百科全书,包括物理、化学、生物等基础科学知识', type: 'doc_search', typeName: '文档搜索', tags: ['儿童', '科学', '教育'], docs: 2840, size: '128MB', status: 'ready', createdAt: '2026-05-01 10:00:00', updatedAt: '2026-05-10 14:32:15', }; let kbFiles = [ { id: 'f1', name: '儿童科学百科.pdf', size: '2.5MB', format: 'PDF', dataSize: '2.5MB', status: 'ready', category: '默认类目', indexedAt: '2026-05-10 14:32:15', slices: 128, chars: 45678, parseError: null }, { id: 'f2', name: '科学小实验.docx', size: '1.8MB', format: 'DOCX', dataSize: '1.8MB', status: 'processing', category: '教学类目', indexedAt: '-', slices: 45, chars: 12340, parseError: null }, { id: 'f3', name: '物理入门.xlsx', size: '856KB', format: 'XLSX', dataSize: '856KB', status: 'ready', category: '默认类目', indexedAt: '2026-05-09 10:25:30', slices: 89, chars: 34560, parseError: null }, { id: 'f4', name: '化学元素表.pdf', size: '3.2MB', format: 'PDF', dataSize: '3.2MB', status: 'error', category: '教学类目', indexedAt: '-', slices: 0, chars: 0, parseError: 'PDF解析失败:文件格式损坏' }, { id: 'f5', name: '天文知识.png', size: '5.6MB', format: 'PNG', dataSize: '5.6MB', status: 'ready', category: '默认类目', indexedAt: '2026-05-08 16:45:22', slices: 34, chars: 8900, parseError: null }, { id: 'f6', name: '地理常识.docx', size: '2.1MB', format: 'DOCX', dataSize: '2.1MB', status: 'ready', category: '默认类目', indexedAt: '2026-05-07 11:20:15', slices: 67, chars: 23450, parseError: null }, ]; const mockSlices = [ { id: 's1', content: '光合作用是植物、藻类和某些细菌利用光能将二氧化碳和水转化为有机物并释放氧气的过程。这个过程主要发生在植物叶片的叶绿体中,是地球上最重要的生化反应之一。', source: '儿童科学百科.pdf', chars: 89, score: 0.95, sliceNo: 1, metadata: { title: '第一章 光合作用', author: '张三' } }, { id: 's2', content: '植物通过根部的根毛吸收土壤中的水分和无机盐,这些物质通过维管束运输到叶片。叶片中的气孔吸收空气中的二氧化碳,同时释放氧气和水蒸气。', source: '儿童科学百科.pdf', chars: 76, score: 0.88, sliceNo: 2, metadata: { title: '第一章 光合作用' } }, { id: 's3', content: '叶绿体是植物细胞中进行光合作用的主要场所,含有叶绿素等色素,赋予植物绿色的外观。叶绿体具有双层膜结构,内部有类囊体堆叠形成的基粒。', source: '儿童科学百科.pdf', chars: 68, score: 0.82, sliceNo: 3, metadata: { title: '第一章 光合作用' } }, ]; const testHistory = [ { id: 'h1', time: '2026-05-13 14:30:25', query: '光合作用是什么?', recallCount: 3, avgScore: 0.92 }, { id: 'h2', time: '2026-05-13 10:15:42', query: '植物如何吸收水分?', recallCount: 2, avgScore: 0.85 }, { id: 'h3', time: '2026-05-12 16:45:00', query: '什么是叶绿体?', recallCount: 4, avgScore: 0.78 }, ]; const quickQuestions = [ '什么是光合作用?', '植物如何吸收水分?', '叶绿体的作用是什么?', '光合作用需要什么条件?' ]; // ==================== 工具函数 ==================== function getFileIcon(format) { const icons = { PDF: '📄', DOCX: '📄', DOC: '📄', TXT: '📝', MD: '📋', XLSX: '📊', XLS: '📊', CSV: '📊', PNG: '🖼', JPG: '🖼', JPEG: '🖼', GIF: '🖼', BMP: '🖼', MP4: '🎬', AVI: '🎬', MOV: '🎬', MKV: '🎬', WMV: '🎬' }; return icons[format] || '📁'; } function getTypeIcon(type) { const icons = { doc_search: 'file-text', data_query: 'table', image_qa: 'image', video_search: 'video' }; return icons[type] || 'database'; } function formatTime(timeStr) { if (!timeStr || timeStr === '-') return '-'; return timeStr; } function getStatusBadge(status) { const map = { ready: { label: '解析完成', cls: 'badge-success' }, processing: { label: '解析中', cls: 'badge-warning' }, error: { label: '解析失败', cls: 'badge-danger' }, uploading: { label: '上传中', cls: 'badge-info' }, }; return map[status] || { label: status, cls: 'badge-default' }; } // ==================== 渲染函数 ==================== function renderPage() { container.innerHTML = `
| 文件名 | 格式 | 大小 | 数据量 | 状态 | 所属类目 | 切片数 | 索引时间 | 操作 |
|---|
| 文件名 | ${file?.name || '-'} |
| 文件大小 | ${file?.size || '-'} |
| 数据量 | ${file?.dataSize || '-'} |
| 文件格式 | ${file?.format || '-'} |
| 切片数量 | ${file?.slices || 0} 个 |
| 字符总数 | ${file?.chars?.toLocaleString() || 0} 字符 |
| 状态 | ${getStatusBadge(file?.status).label} |
| 所属类目 | ${file?.category || '-'} |
| 索引时间 | ${formatTime(file?.indexedAt)} |
确定要重新解析文件「${file?.name}」吗?
重新解析将覆盖之前的解析结果。
`, confirmText: '重新解析', onConfirm: () => { // TODO: 调用 API POST /api/v1/knowledge-bases/:id/files/:fileId/reparse const idx = kbFiles.findIndex(f => f.id === fileId); if (idx !== -1) { kbFiles[idx].status = 'processing'; renderPage(); } Toast.success('重新解析任务已启动'); } }); }; window.__moveFile = function(fileId) { Toast.info('移动文件功能'); }; window.__deleteFile = function(fileId) { const file = kbFiles.find(f => f.id === fileId); createModal({ title: '删除文件', content: `确定要删除文件「${file?.name}」吗?
确定要重新解析选中的 ${selectedFiles.size} 个文件吗?
`, confirmText: '重新解析', onConfirm: () => { // TODO: 调用批量重新解析API selectedFiles.forEach(id => { const idx = kbFiles.findIndex(f => f.id === id); if (idx !== -1) kbFiles[idx].status = 'processing'; }); selectedFiles.clear(); renderPage(); Toast.success('重新解析任务已启动'); } }); }; window.__moveSelectedFiles = function() { Toast.info('移动文件功能'); }; window.__deleteSelectedFiles = function() { createModal({ title: '批量删除', content: `确定要删除选中的 ${selectedFiles.size} 个文件吗?
输入问题并点击测试查看结果
确定要重建知识库「${kbData.name}」的全部索引吗?
重建过程中知识库可正常访问,预计需要几分钟时间。
`, confirmText: '重建', onConfirm: () => { // TODO: 调用 API POST /api/v1/knowledge-bases/:id/rebuild Toast.success('索引重建任务已启动'); } }); }; window.__reparseAll = function() { createModal({ title: '重新解析全部', content: `确定要重新解析知识库「${kbData.name}」的全部文件吗?
此操作将重新解析所有文件,请耐心等待。
`, confirmText: '重新解析', onConfirm: () => { Toast.success('重新解析任务已启动'); } }); }; window.__exportKb = function() { Toast.info('导出知识库'); }; window.__deleteKb = function() { createModal({ title: '删除知识库', content: `确定要删除知识库「${kbData.name}」吗?
关联应用将无法继续使用该知识库。