feat(admin): Implement System Knowledge Base management module

Features:

- Backend: SystemKbService with full CRUD (knowledge bases + documents)

- Backend: 8 RESTful API endpoints (list/detail/create/update/delete/upload/download)

- Backend: OSS storage integration (system/knowledge-bases/{kbId}/{docId})

- Backend: RAG engine integration (document parsing, chunking, vectorization)

- Frontend: SystemKbListPage with card-based layout

- Frontend: SystemKbDetailPage with document management table

- Frontend: Master-Detail UX pattern for better user experience

- Document upload (single/batch), download (preserving original filename), delete

Technical:

- Database migration for system_knowledge_bases and system_kb_documents tables

- OSSAdapter.getSignedUrl with Content-Disposition for original filename

- Reuse RAG engine from common/rag for document processing

Tested: Local environment verified, all features working
This commit is contained in:
2026-01-28 21:57:44 +08:00
parent 3a4aa9123c
commit 0d9e6b9922
28 changed files with 2827 additions and 247 deletions

View File

@@ -91,10 +91,18 @@ export class OSSAdapter implements StorageAdapter {
try {
const normalizedKey = this.normalizeKey(key)
// 使用 put 方法上传 Buffer适合 < 30MB 文件)
const result = await this.client.put(normalizedKey, buffer)
// 根据文件扩展名设置 Content-Type
const contentType = this.getMimeType(normalizedKey)
console.log(`[OSSAdapter] Upload success: ${normalizedKey}, size=${buffer.length}`)
// 使用 put 方法上传 Buffer适合 < 30MB 文件)
// 必须设置正确的 headers否则二进制文件可能损坏
const result = await this.client.put(normalizedKey, buffer, {
headers: {
'Content-Type': contentType,
},
})
console.log(`[OSSAdapter] Upload success: ${normalizedKey}, size=${buffer.length}, contentType=${contentType}`)
// 返回签名URL假设是私有Bucket
return this.getSignedUrl(normalizedKey)
@@ -104,6 +112,37 @@ export class OSSAdapter implements StorageAdapter {
}
}
/**
* 根据文件扩展名获取 MIME 类型
*/
private getMimeType(key: string): string {
const ext = key.toLowerCase().split('.').pop()
const mimeTypes: Record<string, string> = {
// 文档类型
pdf: 'application/pdf',
doc: 'application/msword',
docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
xls: 'application/vnd.ms-excel',
xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
ppt: 'application/vnd.ms-powerpoint',
pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
txt: 'text/plain',
md: 'text/markdown',
// 图片类型
jpg: 'image/jpeg',
jpeg: 'image/jpeg',
png: 'image/png',
gif: 'image/gif',
webp: 'image/webp',
svg: 'image/svg+xml',
// 其他
json: 'application/json',
xml: 'application/xml',
zip: 'application/zip',
}
return mimeTypes[ext || ''] || 'application/octet-stream'
}
/**
* 流式上传(适合大文件 > 30MB
*