目标:基于以下 API 生成 Vue 3 + Element Plus 的知识库管理前端页面。 技术栈:Vue 3 Composition API + TypeScript + Element Plus + Axios。 接口 Base URL:
/knowledge-base
本项目是 AI 医疗开放平台,后端采用可插拔引擎架构(KnowledgeEngineFactory → DifyKnowledgeEngine),前端通过 /knowledge-base 控制器调用 Dify 知识库 API。
前端 Vue 页面
→ /knowledge-base Controller(OpenPlatform 模块)
→ KnowledgeEngineFactory.getEngine("dify")
→ DifyKnowledgeEngine(OkHttp → Dify REST API)
所有接口返回 com.emoon.common.core.domain.R<T> 格式:
interface ApiResponse<T> {
code: number // 200=成功
msg: string // 提示信息
data: T // 业务数据
}
// 分页接口(Admin 端)
interface TableDataInfo<T> {
rows: T[]
total: number
}
Axios 拦截器应统一处理 code !== 200 的错误,弹出 msg 提示。
所有 API 请求需带 4 个签名 Header(由 Axios 拦截器统一添加):
headers = {
'X-Emoon-Timestamp': Date.now().toString(), // 毫秒时间戳
'X-Emoon-Request-Id': crypto.randomUUID(), // UUID
'X-Emoon-Public-Key': projectStore.publicKey, // 项目公钥
'X-Emoon-Sign': md5(requestId + '&' + timestamp + '&' + payload + '&' + privateKey).toLowerCase()
}
签名算法:MD5(requestId + "&" + timestamp + "&" + payload + "&" + privateKey)
| # | 方法 | 路径 | 说明 |
|---|---|---|---|
| 1 | GET | /knowledge-base/list-from-dify |
分页列表 |
| 2 | GET | /knowledge-base/detail |
详情 |
| 3 | POST | /knowledge-base/create |
创建 |
| 4 | PUT | /knowledge-base/update |
更新 |
| 5 | DELETE | /knowledge-base/delete |
删除 |
GET /knowledge-base/list-from-dify?engineConfig=xxx&page=1&limit=20&keyword=
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| engineConfig | String | 是 | 引擎配置 JSON |
| page | int | 否 | 页码,默认 1 |
| limit | int | 否 | 每页条数,默认 20 |
| keyword | String | 否 | 按名称模糊搜索 |
| includeAll | boolean | 否 | 是否包含所有知识库,默认 false |
| tagIds | String[] | 否 | 按标签 ID 筛选 |
// 响应 data:
{
"data": [{
"id": "c42e2a6e-...",
"name": "中医舌诊知识库",
"description": "舌象诊断相关文献",
"provider": "vendor",
"permission": "only_me",
"indexingTechnique": "high_quality",
"appCount": 0,
"documentCount": 0,
"wordCount": 0,
"createdBy": "...",
"authorName": "admin",
"createdAt": 1741267200,
"updatedAt": 1741267200,
"embeddingModel": "text-embedding-3-small",
"embeddingModelProvider": "openai",
"embeddingAvailable": true,
"docForm": "text_model",
"tags": [{ "id": "...", "name": "中医" }],
"retrievalModelDict": {
"searchMethod": "semantic_search",
"rerankingEnable": false,
"topK": 3,
"scoreThresholdEnabled": false
},
"enableApi": true,
"isPublished": false,
"totalDocuments": 0
}],
"hasMore": false,
"limit": 20,
"total": 1,
"page": 1
}
GET /knowledge-base/detail?datasetId=xxx&engineConfig=xxx
响应 data 为 KnowledgeDatasetInfo 对象(字段同上)。
POST /knowledge-base/create
Content-Type: application/json
{
"name": "中医舌诊知识库",
"description": "舌象诊断相关文献和病例",
"engineConfig": "{\"baseUrl\":\"http://...\",\"secretKey\":\"app-xxx\"}",
"indexingTechnique": "high_quality",
"permission": "only_me",
"embeddingModel": "bge-large-zh-v1.5",
"embeddingModelProvider": "huggingface",
"retrievalModel": {
"searchMethod": "semantic_search",
"rerankingEnable": true,
"rerankingProviderName": "cohere",
"rerankingModelName": "rerank-multilingual-v3.0",
"topK": 5,
"scoreThresholdEnabled": true,
"scoreThreshold": 0.5
}
}
响应 data 为创建后的 KnowledgeDatasetInfo。
PUT /knowledge-base/update
Content-Type: application/json
{
"datasetId": "c42e2a6e-...",
"name": "中医舌诊知识库(更新)",
"description": "更新后的描述",
"engineConfig": "{\"baseUrl\":\"...\",\"secretKey\":\"...\"}"
}
DELETE /knowledge-base/delete?datasetId=xxx&engineConfig=xxx
| # | 方法 | 路径 | 说明 |
|---|---|---|---|
| 6 | GET | /knowledge-base/document/list |
文档分页列表 |
| 7 | GET | /knowledge-base/document/detail |
文档详情 |
| 8 | DELETE | /knowledge-base/document/delete |
删除文档 |
| 9 | POST | /knowledge-base/document/upload |
上传文件创建文档 |
| 10 | POST | /knowledge-base/document/update-by-file |
上传文件更新文档 |
| 11 | GET | /knowledge-base/document/download |
获取下载 URL |
| 12 | GET | /knowledge-base/document/indexing-status |
索引进度轮询 |
GET /knowledge-base/document/list?datasetId=xxx&engineConfig=xxx&page=1&limit=20&keyword=&status=
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| datasetId | String | 是 | 知识库 ID |
| engineConfig | String | 是 | 引擎配置 JSON |
| page | int | 否 | 默认 1 |
| limit | int | 否 | 默认 20,上限 100 |
| keyword | String | 否 | 按文档名称搜索 |
| status | String | 否 | queuing/indexing/paused/error/available/disabled/archived |
// 响应 data:
{
"data": [{
"id": "a8e0e5b5-...",
"position": 1,
"name": "guide.txt",
"dataSourceType": "upload_file",
"createdFrom": "api",
"createdBy": "...",
"createdAt": 1741267200,
"tokens": 512,
"indexingStatus": "completed",
"error": null,
"enabled": true,
"archived": false,
"displayStatus": "available",
"wordCount": 350,
"hitCount": 0,
"docForm": "text_model",
"docMetadata": []
}],
"hasMore": false,
"limit": 20,
"total": 1,
"page": 1
}
GET /knowledge-base/document/detail?datasetId=xxx&documentId=xxx&engineConfig=xxx&metadata=all
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| metadata | String | 否 | all=全部 / only=仅id+docType+docMetadata / without=除docMetadata外 |
响应额外包含:
{
"docLanguage": "English",
"docType": null,
"completedAt": 1741267260,
"updatedAt": 1741267260,
"indexingLatency": 60,
"segmentCount": 5,
"averageSegmentLength": 70,
"summaryIndexStatus": null,
"needSummary": false,
"datasetProcessRule": { "id": "...", "mode": "custom" },
"documentProcessRule": {
"mode": "custom",
"rules": {
"preProcessingRules": [],
"segmentation": { "separator": "###", "maxTokens": 500, "chunkOverlap": 50 }
}
}
}
DELETE /knowledge-base/document/delete?datasetId=xxx&documentId=xxx&engineConfig=xxx
POST /knowledge-base/document/upload
Content-Type: multipart/form-data
file: (binary)
datasetId: xxx
engineConfig: xxx
indexingTechnique: high_quality (可选)
docForm: text_model (可选)
docLanguage: Chinese (可选)
processRuleJson: {"mode":"automatic"} (可选)
retrievalModelJson: {"searchMethod":"semantic_search",...} (可选)
embeddingModel: bge-large-zh-v1.5 (可选)
embeddingModelProvider: huggingface (可选)
// 响应 data:
{
"document": { "id": "...", "name": "...", "indexingStatus": "waiting", ... },
"batch": "20250306150245647595"
}
重要:返回的 batch 用于轮询索引进度(见 4.2.6)。
POST /knowledge-base/document/update-by-file
Content-Type: multipart/form-data
file: (binary)
datasetId: xxx
documentId: xxx
engineConfig: xxx
// ...其他可选参数同上传
响应格式同 4.2.4(document + batch)。
GET /knowledge-base/document/download?datasetId=xxx&documentId=xxx&engineConfig=xxx
// 响应 data:
{ "url": "https://cdn.dify.ai/..." }
GET /knowledge-base/document/indexing-status?datasetId=xxx&batch=xxx&engineConfig=xxx
// 响应 data:
{
"data": [{
"id": "a8e0e5b5-...",
"indexingStatus": "completed",
"processingStartedAt": 1741267200,
"parsingCompletedAt": 1741267200,
"cleaningCompletedAt": 1741267200,
"splittingCompletedAt": 1741267200,
"completedAt": 1741267200,
"pausedAt": null,
"error": null,
"stoppedAt": null,
"completedSegments": 5,
"totalSegments": 5
}]
}
轮询逻辑:
状态推进:waiting → parsing → cleaning → splitting → indexing → completed
- 每 2 秒轮询一次
- indexingStatus === 'completed' → 停止轮询,刷新文档列表
- indexingStatus === 'error' → 停止轮询,显示 error 内容
| # | 方法 | 路径 | 说明 |
|---|---|---|---|
| 13 | GET | /knowledge-base/segment/list |
分段分页列表 |
| 14 | GET | /knowledge-base/segment/detail |
分段详情 |
| 15 | POST | /knowledge-base/segment/create |
添加分段 |
| 16 | GET | /knowledge-base/segment/child-chunks |
子分段列表 |
GET /knowledge-base/segment/list?datasetId=xxx&documentId=xxx&engineConfig=xxx&page=1&limit=20&keyword=&status=
// 响应 data:
{
"data": [{
"id": "f3d1c7be-...",
"position": 1,
"documentId": "a8e0e5b5-...",
"content": "Dify is an open-source LLM app development platform.",
"signContent": "",
"answer": "",
"wordCount": 9,
"tokens": 12,
"keywords": ["dify", "platform", "llm"],
"indexNodeId": "...",
"indexNodeHash": "...",
"hitCount": 0,
"enabled": true,
"status": "completed",
"createdBy": "...",
"createdAt": 1741267200,
"updatedAt": 1741267200,
"childChunks": [],
"attachments": [],
"summary": null
}],
"docForm": "text_model",
"total": 1,
"hasMore": false,
"limit": 20,
"page": 1
}
GET /knowledge-base/segment/detail?datasetId=xxx&documentId=xxx&segmentId=xxx&engineConfig=xxx
// 响应 data:
{
"data": { /* KnowledgeSegmentInfo 单个对象 */ },
"docForm": "text_model"
}
POST /knowledge-base/segment/create
Content-Type: application/json
{
"datasetId": "xxx",
"documentId": "xxx",
"engineConfig": "xxx",
"segments": [
{
"content": "分段文本内容",
"answer": "QA 模式的答案(可选)",
"keywords": ["关键词1", "关键词2"],
"attachmentIds": ["附件ID1"]
}
]
}
响应同 segment/list 结构(data + docForm)。
GET /knowledge-base/segment/child-chunks?datasetId=xxx&documentId=xxx&segmentId=xxx&engineConfig=xxx&page=1&limit=20&keyword=
// 响应 data:
{
"data": [{
"id": "d7e8f9a0-...",
"segmentId": "f3d1c7be-...",
"content": "Dify is an open-source platform.",
"position": 1,
"wordCount": 6,
"type": "automatic",
"createdAt": 1741267200,
"updatedAt": 1741267200
}],
"total": 1,
"totalPages": 1,
"page": 1,
"limit": 20
}
| # | 方法 | 路径 | 说明 |
|---|---|---|---|
| 17 | POST | /knowledge-base/retrieve |
检索知识库 |
POST /knowledge-base/retrieve
Content-Type: application/json
{
"query": "舌苔发白是什么原因",
"datasetIds": ["c42e2a6e-...", "d53f3b7f-..."],
"engineConfig": "xxx"
}
// 响应 data:
{
"records": [
{
"content": "舌苔发白多见于寒证...",
"score": 0.95,
"documentName": "舌诊入门.pdf",
"datasetName": "中医舌诊知识库"
}
]
}
建议创建以下 Vue 页面(路由 /knowledge-base 下):
views/knowledge/DatasetList.vueviews/knowledge/DatasetDetail.vueviews/knowledge/DocumentList.vue/knowledge-base/:datasetId/documentswaiting(灰) → parsing → cleaning → splitting → indexing(蓝) → completed(绿) / error(红) / paused(黄)indexing-status 直到完成views/knowledge/DocumentDetail.vueviews/knowledge/SegmentList.vue/knowledge-base/:datasetId/documents/:documentId/segmentsviews/knowledge/Retrieve.vue// stores/knowledge.ts (Pinia)
interface KnowledgeStore {
engineConfig: string // 由智能体配置传入
currentDatasetId: string | null // 当前选中知识库
currentDataset: KnowledgeDatasetInfo | null
pollingTimer: ReturnType<typeof setInterval> | null
}
索引进度轮询:上传文档后,每 2s 轮询 /document/indexing-status,使用 batch 参数。格式化各阶段耗时(processingStartedAt → parsingCompletedAt → ... → completedAt)。
时间格式化:所有时间戳为 Unix 秒,需 new Date(timestamp * 1000).toLocaleString()。
错误处理:删除操作弹出二次确认,后端抛 404 时("文档不存在"/"分段不存在")给出友好提示。
引擎配置传递:所有 API 都需带 engineConfig 参数(JSON String),由前端从上级页面(智能体配置)获取并全局存储。
分段关键词:以 Tag 标签形式展示,添加分段时支持 Tag 输入。
文件上传:使用 <el-upload> 组件,支持拖拽,限制文件大小(建议 15MB),显示上传进度。
在 types/knowledge.d.ts 中定义以下 interface:
KnowledgeDatasetInfo — 知识库信息KnowledgeDocumentInfo — 文档信息KnowledgeSegmentInfo — 分段信息KnowledgeChildChunkInfo — 子分段信息KnowledgeRetrievalModel — 检索模型配置KnowledgeProcessRule — 处理规则KnowledgeIndexingStatusInfo — 索引进度PageResult<T> — 通用分页结果 { data: T[], hasMore: boolean, limit: number, total: number, page: number }ApiResponse<T> — 统一响应 { code: number, msg: string, data: T }