feat(pkb): Complete PKB module frontend migration with V3 design

Summary:
- Implement PKB Dashboard and Workspace pages based on V3 prototype
- Add single-layer header with integrated Tab navigation
- Implement 3 work modes: Full Text, Deep Read, Batch Processing
- Integrate Ant Design X Chat component for AI conversations
- Create BatchModeComplete with template selection and document processing
- Add compact work mode selector with dropdown design

Backend:
- Migrate PKB controllers and services to /modules/pkb structure
- Register v2 API routes at /api/v2/pkb/knowledge
- Maintain dual API routes for backward compatibility

Technical details:
- Use Zustand for state management
- Handle SSE streaming responses for AI chat
- Support document selection for Deep Read mode
- Implement batch processing with progress tracking

Known issues:
- Batch processing API integration pending
- Knowledge assets page navigation needs optimization

Status: Frontend functional, pending refinement
This commit is contained in:
2026-01-06 22:15:42 +08:00
parent b31255031e
commit 5a17d096a7
226 changed files with 14899 additions and 224 deletions

View File

@@ -0,0 +1,217 @@
/**
* PKB个人知识库 APIv2版本
* 更新API路径为 /api/v2/pkb/knowledge
*/
import axios from 'axios';
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || 'http://localhost:3000';
const api = axios.create({
baseURL: `${API_BASE_URL}/api/v2/pkb/knowledge`,
timeout: 30000,
headers: {
'Content-Type': 'application/json',
},
});
/**
* 知识库类型定义
*/
export interface KnowledgeBase {
id: string;
userId: string;
name: string;
description?: string;
difyDatasetId: string;
fileCount: number;
totalSizeBytes: number;
createdAt: string;
updatedAt: string;
_count?: {
documents: number;
};
}
export interface Document {
id: string;
kbId: string;
userId: string;
filename: string;
fileType: string;
fileSizeBytes: number;
fileUrl: string;
difyDocumentId: string;
status: 'uploading' | 'parsing' | 'indexing' | 'completed' | 'error';
progress: number;
errorMessage?: string;
segmentsCount?: number;
tokensCount?: number;
uploadedAt: string;
processedAt?: string;
}
export interface CreateKnowledgeBaseRequest {
name: string;
description?: string;
}
export interface UpdateKnowledgeBaseRequest {
name?: string;
description?: string;
}
export interface KnowledgeBaseStats {
totalDocuments: number;
completedDocuments: number;
processingDocuments: number;
errorDocuments: number;
totalSizeBytes: number;
totalTokens: number;
}
/**
* 知识库管理API
*/
export const knowledgeBaseApi = {
/**
* 获取知识库列表
*/
async getList(): Promise<KnowledgeBase[]> {
const response = await api.get('/knowledge-bases');
return response.data.data;
},
/**
* 获取知识库详情
*/
async getById(id: string): Promise<KnowledgeBase> {
const response = await api.get(`/knowledge-bases/${id}`);
return response.data.data;
},
/**
* 创建知识库
*/
async create(data: CreateKnowledgeBaseRequest): Promise<KnowledgeBase> {
const response = await api.post('/knowledge-bases', data);
return response.data.data;
},
/**
* 更新知识库
*/
async update(id: string, data: UpdateKnowledgeBaseRequest): Promise<KnowledgeBase> {
const response = await api.put(`/knowledge-bases/${id}`, data);
return response.data.data;
},
/**
* 删除知识库
*/
async delete(id: string): Promise<void> {
await api.delete(`/knowledge-bases/${id}`);
},
/**
* 获取知识库统计信息
*/
async getStats(id: string): Promise<KnowledgeBaseStats> {
const response = await api.get(`/knowledge-bases/${id}/stats`);
return response.data.data;
},
/**
* 检索知识库RAG
*/
async search(id: string, query: string, topK: number = 3): Promise<any> {
const response = await api.get(`/knowledge-bases/${id}/search`, {
params: { query, top_k: topK },
});
return response.data.data;
},
};
/**
* 文档管理API
*/
export const documentApi = {
/**
* 获取文档列表
*/
async getList(kbId: string): Promise<Document[]> {
const response = await api.get(`/knowledge-bases/${kbId}/documents`);
return response.data.data;
},
/**
* 获取文档详情
*/
async getById(id: string): Promise<Document> {
const response = await api.get(`/documents/${id}`);
return response.data.data;
},
/**
* 上传文档
*/
async upload(kbId: string, file: File, onProgress?: (progress: number) => void): Promise<Document> {
const formData = new FormData();
formData.append('file', file);
const response = await api.post(`/knowledge-bases/${kbId}/documents`, formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
onUploadProgress: (progressEvent) => {
if (progressEvent.total && onProgress) {
const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total);
onProgress(percentCompleted);
}
},
});
return response.data.data;
},
/**
* 删除文档
*/
async delete(id: string): Promise<void> {
await api.delete(`/documents/${id}`);
},
/**
* 重新处理文档
*/
async reprocess(id: string): Promise<void> {
await api.post(`/documents/${id}/reprocess`);
},
/**
* 获取文档全文(用于逐篇精读模式)
*/
async getFullText(id: string): Promise<any> {
const response = await api.get(`/documents/${id}/full-text`);
return response.data;
},
};
/**
* 文档选择API用于全文阅读模式
*/
export const documentSelectionApi = {
/**
* 获取知识库的文档选择结果
*/
async getSelection(kbId: string, maxFiles?: number, maxTokens?: number): Promise<any> {
const params = new URLSearchParams();
if (maxFiles) params.append('max_files', maxFiles.toString());
if (maxTokens) params.append('max_tokens', maxTokens.toString());
const url = `/knowledge-bases/${kbId}/document-selection${params.toString() ? '?' + params.toString() : ''}`;
const response = await api.get(url);
return response.data.data;
},
};