重构知识库相关接口,更新数据结构和命名,移除示例文件,调整组件和视图以支持新命名,优化文档和数据集管理功能。

This commit is contained in:
2026-03-30 17:35:05 +08:00
parent 891f8ed776
commit d9b4a012ee
22 changed files with 1783 additions and 1115 deletions

111
src/api/cid/apis/index.ts Normal file
View File

@@ -0,0 +1,111 @@
import { newService } from '/@/utils/request';
// 接口查询参数
export interface ApiInterfaceQueryParams {
keyword?: string;
platformId?: string;
status?: string;
method?: string;
pageNum: number;
pageSize: number;
}
// 创建接口参数
export interface CreateApiInterfaceParams {
platformId: string | number;
name: string;
code: string;
url: string;
method: string;
status?: string;
authType?: string;
requestConfig?: Record<string, any>;
responseConfig?: Record<string, any>;
limitConfig?: Record<string, any>;
}
// 更新接口参数
export interface UpdateApiInterfaceParams extends Partial<CreateApiInterfaceParams> {
id: string;
}
// 更新接口状态参数
export interface UpdateApiInterfaceStatusParams {
id: string;
status: string;
}
// 接口信息(响应字段)
export interface ApiInterfaceInfo {
id: string;
platformId: string | number;
platformName?: string;
name: string;
code: string;
url: string;
method: string;
status: string;
statusName?: string;
authType?: string;
requestConfig?: Record<string, any>;
responseConfig?: Record<string, any>;
limitConfig?: Record<string, any>;
createdBy?: string;
createdAt?: number;
updatedBy?: string;
updatedAt?: number;
}
// 获取接口列表
export function listApiInterfaces(params: ApiInterfaceQueryParams) {
return newService({
url: '/api/interface/controller/listApiInterfaces',
method: 'get',
params,
});
}
// 获取接口详情
export function getApiInterface(id: string) {
return newService({
url: '/api/interface/controller/getApiInterface',
method: 'get',
params: { id },
});
}
// 创建接口
export function createApiInterface(data: CreateApiInterfaceParams) {
return newService({
url: '/api/interface/controller/createApiInterface',
method: 'post',
data,
});
}
// 修改接口
export function updateApiInterface(data: UpdateApiInterfaceParams) {
return newService({
url: '/api/interface/controller/updateApiInterface',
method: 'put',
data,
});
}
// 更新接口状态
export function updateApiInterfaceStatus(data: UpdateApiInterfaceStatusParams) {
return newService({
url: '/api/interface/controller/updateApiInterfaceStatus',
method: 'put',
data,
});
}
// 删除接口
export function deleteApiInterface(id: string) {
return newService({
url: '/api/interface/controller/deleteApiInterface',
method: 'delete',
params: { id },
});
}

View File

@@ -0,0 +1,130 @@
import { newService } from '/@/utils/request';
// 平台查询参数
export interface DatasourcePlatformQueryParams {
keyword?: string;
status?: string;
pageNum: number;
pageSize: number;
}
// 创建平台参数
export interface CreateDatasourcePlatformParams {
platformCode: string;
platformName: string;
description?: string;
apiBaseUrl: string;
authType: string;
status?: string;
token?: string;
apiKey?: string;
clientId?: string;
clientSecret?: string;
rateLimitPerMinute?: number;
rateLimitPerHour?: number;
concurrencyLimit?: number;
requestTimeoutMs?: number;
maxRetries?: number;
retryDelayMs?: number;
createdBy?: string;
updatedBy?: string;
}
// 更新平台参数
export interface UpdateDatasourcePlatformParams extends Partial<CreateDatasourcePlatformParams> {
id: string;
version?: string;
}
// 更新平台状态参数
export interface UpdateDatasourcePlatformStatusParams {
id: string;
Status: string;
updatedBy?: string;
}
// 平台信息
export interface DatasourcePlatformInfo {
id: string;
platformCode: string;
platformName: string;
description?: string;
status: string;
statusName: string;
apiBaseUrl: string;
authType: string;
authTypeName: string;
rateLimitPerMinute?: number;
rateLimitPerHour?: number;
concurrencyLimit?: number;
requestTimeoutMs?: number;
maxRetries?: number;
retryDelayMs?: number;
createdBy?: string;
createdAt?: number;
updatedBy?: string;
updatedAt?: number;
}
// 获取平台列表
export function listDatasourcePlatforms(params: DatasourcePlatformQueryParams) {
return newService({
url: '/datasource/platform/controller/listDatasourcePlatforms',
method: 'get',
params,
});
}
// 创建平台
export function createDatasourcePlatform(data: CreateDatasourcePlatformParams) {
return newService({
url: '/datasource/platform/controller/createDatasourcePlatform',
method: 'post',
data,
});
}
// 更新平台
export function updateDatasourcePlatform(data: UpdateDatasourcePlatformParams) {
return newService({
url: '/datasource/platform/controller/updateDatasourcePlatform',
method: 'put',
data,
});
}
// 删除平台
export function deleteDatasourcePlatform(id: string) {
return newService({
url: '/datasource/platform/controller/deleteDatasourcePlatform',
method: 'delete',
params: { id },
});
}
// 获取平台详情
export function getDatasourcePlatform(id: string) {
return newService({
url: '/datasource/platform/controller/getDatasourcePlatform',
method: 'get',
params: { id },
});
}
// 根据编码获取平台信息
export function getPlatformByCode(platformCode: string) {
return newService({
url: '/datasource/platform/controller/getPlatformByCode',
method: 'get',
params: { platformCode },
});
}
// 更新平台状态
export function updateDatasourcePlatformStatus(data: UpdateDatasourcePlatformStatusParams) {
return newService({
url: '/datasource/platform/controller/updateDatasourcePlatformStatus',
method: 'put',
data,
});
}

162
src/api/cid/field/index.ts Normal file
View File

@@ -0,0 +1,162 @@
import { newService } from '/@/utils/request';
// 字典映射查询参数
export interface FieldMappingQueryParams {
configName?: string;
vendorName?: string;
apiName?: string;
businessDomain?: string;
isActive?: boolean;
pageNum?: number;
pageSize?: number;
}
// 创建字典映射参数
export interface CreateFieldMappingParams {
configName: string;
vendorName: string;
apiName: string;
apiVersion?: string;
sourceField: string;
sourceFieldType?: string;
sourceFieldDesc?: string;
targetField: string;
targetFieldType?: string;
targetFieldDesc?: string;
transformType?: string;
transformParams?: any;
validationRules?: any;
defaultValue?: string;
isRequired?: boolean;
isActive?: boolean;
priority?: number;
businessDomain?: string;
fieldGroup?: string;
configVersion?: number;
effectiveDate?: string;
expiryDate?: string;
createdBy?: string;
}
// 更新字典映射参数
export interface UpdateFieldMappingParams extends Partial<CreateFieldMappingParams> {
id: string;
}
// 字典映射信息(响应字段)
export interface FieldMappingInfo {
id: string;
configName: string;
vendorName: string;
apiName: string;
apiVersion?: string;
sourceField: string;
sourceFieldType?: string;
sourceFieldDesc?: string;
targetField: string;
targetFieldType?: string;
targetFieldDesc?: string;
transformType?: string;
transformTypeName?: string;
transformParams?: any;
validationRules?: any;
defaultValue?: string;
isRequired?: boolean;
isActive?: boolean;
priority?: number;
businessDomain?: string;
businessDomainName?: string;
fieldGroup?: string;
configVersion?: number;
effectiveDate?: string;
expiryDate?: string;
createdBy?: string;
createdTime?: string;
updatedBy?: string;
updatedTime?: string;
}
// 查询字典映射列表
export function listFieldMappingConfigs(params: FieldMappingQueryParams) {
return newService({
url: '/field/mapping/config/controller/field-mapping-configs',
method: 'get',
params,
});
}
// 创建字典映射
export function createFieldMappingConfig(data: CreateFieldMappingParams) {
return newService({
url: '/field/mapping/config/controller/field-mapping-configs',
method: 'post',
data,
});
}
// 根据ID查询字典映射详情
export function getFieldMappingConfig(id: string) {
return newService({
url: `/field/mapping/config/controller/field-mapping-configs/${id}`,
method: 'get',
});
}
// 根据ID修改字典映射
export function updateFieldMappingConfig(id: string, data: UpdateFieldMappingParams) {
return newService({
url: `/field/mapping/config/controller/field-mapping-configs/${id}`,
method: 'put',
data,
});
}
// 根据ID修改字典映射状态
export function updateFieldMappingConfigStatus(id: string, isActive: boolean) {
return newService({
url: `/field/mapping/config/controller/field-mapping-configs/${id}/status`,
method: 'put',
data: { id, isActive },
});
}
// 根据ID删除字典映射
export function deleteFieldMappingConfig(id: string) {
return newService({
url: `/field/mapping/config/controller/field-mapping-configs/${id}`,
method: 'delete',
});
}
// 根据厂商和接口查询字段映射(过滤过期)
export interface QueryFieldMappingParams {
vendorName: string;
apiName: string;
apiVersion?: string;
isActive?: boolean;
}
export function queryFieldMappingConfigs(params: QueryFieldMappingParams) {
return newService({
url: '/field/mapping/config/controller/field-mapping-configs/query',
method: 'get',
params,
});
}
// 验证字段映射配置的有效性
export interface ValidateFieldMappingParams {
configName: string;
vendorName: string;
apiName: string;
sourceField: string;
targetField: string;
}
export function validateFieldMappingConfig(data: ValidateFieldMappingParams) {
return newService({
url: '/field/mapping/config/controller/field-mapping-configs/validate',
method: 'post',
data,
});
}

View File

@@ -1,113 +0,0 @@
// ⚠️ 示例文件:仅用于接口调用演示,不参与生产运行。
// 知识库接口使用示例
import {
createKnowledgeBase,
CreateDatasetParams,
updateKnowledgeBase,
UpdateDatasetParams
} from '/@/api/knowledge/dataset';
// 示例1创建带描述的知识库
const createKnowledgeBaseWithDescription = async () => {
const params: CreateDatasetParams = {
name: '客服知识库',
description: '包含常见问题和答案的知识库'
};
try {
const response = await createKnowledgeBase(params);
console.log('知识库创建成功:', response.data);
} catch (error) {
console.error('创建失败:', error);
}
};
// 示例2创建仅包含名称的知识库
const createKnowledgeBaseOnly = async () => {
const params: CreateDatasetParams = {
name: '产品知识库'
// description 是可选的,可以不传
};
try {
const response = await createKnowledgeBase(params);
console.log('知识库创建成功:', response.data);
} catch (error) {
console.error('创建失败:', error);
}
};
// 示例3更新知识库名称和描述
const updateKnowledgeBaseInfo = async () => {
const params: UpdateDatasetParams = {
id: '1234567890', // 必传
name: '更新后的知识库名称',
description: '更新后的描述信息'
};
try {
const response = await updateKnowledgeBase(params);
console.log('知识库更新成功:', response.data);
} catch (error) {
console.error('更新失败:', error);
}
};
// 示例4仅更新知识库名称
const updateKnowledgeBaseName = async () => {
const params: UpdateDatasetParams = {
id: '1234567890', // 必传
name: '仅更新名称'
// description 是可选的,可以不传
};
try {
const response = await updateKnowledgeBase(params);
console.log('知识库名称更新成功:', response.data);
} catch (error) {
console.error('更新失败:', error);
}
};
// 在Vue组件中使用
/*
import { ref } from 'vue';
import { ElMessage } from 'element-plus';
import { createKnowledgeBase, CreateDatasetParams } from '/@/api/knowledge/dataset';
export default defineComponent({
setup() {
const formData = ref<CreateDatasetParams>({
name: '',
description: ''
});
const loading = ref(false);
const handleSubmit = async () => {
if (!formData.value.name.trim()) {
ElMessage.error('知识库名称不能为空');
return;
}
loading.value = true;
try {
await createKnowledgeBase(formData.value);
ElMessage.success('知识库创建成功');
// 重置表单或跳转到列表页
formData.value = { name: '', description: '' };
} catch (error) {
ElMessage.error('创建失败,请重试');
} finally {
loading.value = false;
}
};
return {
formData,
loading,
handleSubmit
};
}
});
*/

View File

@@ -1,108 +1,68 @@
import { newService } from '/@/utils/request'; import { newService } from '/@/utils/request';
// 数据集查询参数 // 数据集查询参数
export interface DatasetQueryParams { export interface knowledgeQueryParams {
keyword?: string; keyword?: string;
status?: string;
pageNum: number; pageNum: number;
pageSize: number; pageSize: number;
} }
// 创建知识库参数 // 创建知识库参数
export interface CreateDatasetParams { export interface CreateknowledgeParams {
name: string; // 必传 name: string; // 必传
description?: string; // 可选 description?: string; // 可选
} }
// 更新知识库参数 // 更新知识库参数
export interface UpdateDatasetParams { export interface UpdateknowledgeParams {
id: string; // 必传 id: string; // 必传
name?: string; // 可选 name?: string; // 可选
description?: string; // 可选 description?: string; // 可选
} }
// 数据集信息 // 数据集信息
export interface DatasetInfo { export interface knowledgeInfo {
id?: string; id?: string;
name: string; name: string;
description?: string; description?: string;
type: string; // text, qa, table fileCount?: number;
documentCount?: number; totalSize?: number;
charCount?: number;
status: string; // enable, disable
embeddingModel?: string;
createdAt?: string; createdAt?: string;
updatedAt?: string; updatedAt?: string;
} }
// 获取数据集列表 // 获取知识库列表
export function listDatasets(params: DatasetQueryParams) { export function listknowledges(params: knowledgeQueryParams) {
return newService({ return newService({
url: '/rag-knowledge/knowledge/listKnowledge', url: '/rag-knowledge/dataset/listDataset',
method: 'get', method: 'get',
params, params,
}); });
} }
// 获取数据集详情 // 创建知识库
export function getDataset(id: string) { export function createknowledge(data: CreateknowledgeParams) {
return newService({ return newService({
url: '/knowledge/dataset/detail', url: '/rag-knowledge/dataset/createDataset',
method: 'get',
params: { id },
});
}
// 创建数据集(简化版)
export function createKnowledgeBase(data: CreateDatasetParams) {
return newService({
url: '/rag-knowledge/knowledge/createKnowledge',
method: 'post', method: 'post',
data, data,
}); });
} }
// 创建数据集(完整版) // 更新知识库
export function createDataset(data: DatasetInfo) { export function updateknowledge(data: UpdateknowledgeParams) {
return newService({ return newService({
url: '/knowledge/dataset/create', url: '/rag-knowledge/dataset/updateDataset',
method: 'post',
data,
});
}
// 更新知识库(简化版)
export function updateKnowledgeBase(data: UpdateDatasetParams) {
return newService({
url: '/rag-knowledge/knowledge/updateKnowledge',
method: 'put', method: 'put',
data, data,
}); });
} }
// 更新数据集(完整版) // 删除知识库
export function updateDataset(data: DatasetInfo) { export function deleteknowledge(id: string) {
return newService({ return newService({
url: '/knowledge/dataset/update', url: '/rag-knowledge/dataset/deleteDataset',
method: 'put',
data,
});
}
// 删除数据集
export function deleteDataset(id: string) {
return newService({
url: '/rag-knowledge/knowledge/deleteKnowledge',
method: 'delete', method: 'delete',
params: { id }, params: { id },
}); });
} }
// 更新数据集状态
export function updateDatasetStatus(data: { id: string; status: string }) {
return newService({
url: '/knowledge/dataset/updateStatus',
method: 'put',
data,
});
}

View File

@@ -1,238 +0,0 @@
// ⚠️ 示例文件:仅用于接口调用演示,不参与生产运行。
// 文档接口使用示例
import {
createDocument,
CreateDocumentParams,
updateDocument,
UpdateDocumentParams,
uploadDocument,
deleteDocument,
listDocuments,
DocumentQueryParams
} from '/@/api/knowledge/document';
// 示例1创建文档JSON格式
const createDocumentExample = async () => {
const params: CreateDocumentParams = {
KnowledgeId: 12345, // 知识库ID必传
filePath: '/path/to/document.pdf', // 文件路径,必传
fileSize: 1024000, // 文件大小(字节),必传
format: 'pdf', // 文件格式,必传
title: '产品使用手册' // 文档标题,必传
};
try {
const response = await createDocument(params);
console.log('文档创建成功:', response.data);
return response.data;
} catch (error) {
console.error('创建失败:', error);
throw error;
}
};
// 示例2上传文档FormData格式
const uploadDocumentExample = async (file: File, knowledgeId: string) => {
const formData = new FormData();
formData.append('file', file);
formData.append('datasetId', knowledgeId);
try {
const response = await uploadDocument(formData);
console.log('文档上传成功:', response.data);
return response.data;
} catch (error) {
console.error('上传失败:', error);
throw error;
}
};
// 示例3获取文档列表
const getDocumentList = async (knowledgeId: string) => {
const params: DocumentQueryParams = {
datasetId: knowledgeId,
pageNum: 1,
pageSize: 10,
keyword: '', // 可选搜索关键字
status: '', // 可选状态筛选
fileType: '' // 可选文件类型筛选
};
try {
const response = await listDocuments(params);
console.log('文档列表:', response.data);
return response.data;
} catch (error) {
console.error('获取列表失败:', error);
throw error;
}
};
// 示例4更新文档
const updateDocumentExample = async () => {
const params: UpdateDocumentParams = {
id: '1234567890', // 必传
title: '更新后的文档标题' // 可选,只更新标题
};
try {
const response = await updateDocument(params);
console.log('文档更新成功:', response.data);
return response.data;
} catch (error) {
console.error('更新失败:', error);
throw error;
}
};
// 示例5完整更新文档
const updateDocumentFull = async () => {
const params: UpdateDocumentParams = {
id: '1234567890', // 必传
KnowledgeId: 67890, // 可选
filePath: '/new/path/document.pdf', // 可选
fileSize: 2048000, // 可选
format: 'pdf', // 可选
title: '完全更新的文档' // 可选
};
try {
const response = await updateDocument(params);
console.log('文档完整更新成功:', response.data);
return response.data;
} catch (error) {
console.error('更新失败:', error);
throw error;
}
};
// 示例6删除文档
const deleteDocumentExample = async (documentId: string) => {
try {
await deleteDocument(documentId);
console.log('文档删除成功');
} catch (error) {
console.error('删除失败:', error);
throw error;
}
};
// 在Vue组件中使用
/*
import { ref } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus';
import {
createDocument,
CreateDocumentParams,
uploadDocument,
deleteDocument,
listDocuments,
DocumentQueryParams
} from '/@/api/knowledge/document';
export default defineComponent({
setup() {
const formData = ref<CreateDocumentParams>({
KnowledgeId: 0,
filePath: '',
fileSize: 0,
format: '',
title: ''
});
const loading = ref(false);
const documentList = ref([]);
// 创建文档
const handleCreate = async () => {
// 验证必填字段
if (!formData.value.KnowledgeId || !formData.value.filePath ||
!formData.value.fileSize || !formData.value.format || !formData.value.title) {
ElMessage.error('请填写所有必填字段');
return;
}
loading.value = true;
try {
await createDocument(formData.value);
ElMessage.success('文档创建成功');
// 重置表单
formData.value = {
KnowledgeId: 0,
filePath: '',
fileSize: 0,
format: '',
title: ''
};
// 刷新列表
await getDocuments();
} catch (error) {
ElMessage.error('创建失败,请重试');
} finally {
loading.value = false;
}
};
// 文件上传
const handleFileUpload = async (event: Event, knowledgeId: string) => {
const file = (event.target as HTMLInputElement).files?.[0];
if (!file) return;
const formData = new FormData();
formData.append('file', file);
formData.append('datasetId', knowledgeId);
loading.value = true;
try {
await uploadDocument(formData);
ElMessage.success('文档上传成功');
await getDocuments();
} catch (error) {
ElMessage.error('上传失败,请重试');
} finally {
loading.value = false;
}
};
// 删除文档
const handleDelete = async (id: string) => {
try {
await ElMessageBox.confirm('确定要删除这个文档吗?', '提示', {
type: 'warning',
});
await deleteDocument(id);
ElMessage.success('删除成功');
await getDocuments();
} catch (error) {
if (error !== 'cancel') {
ElMessage.error('删除失败');
}
}
};
// 获取文档列表
const getDocuments = async () => {
try {
const response = await listDocuments({
pageNum: 1,
pageSize: 10
});
documentList.value = response.data.list;
} catch (error) {
console.error('获取列表失败:', error);
}
};
return {
formData,
loading,
documentList,
handleCreate,
handleFileUpload,
handleDelete,
getDocuments
};
}
});
*/

View File

@@ -4,29 +4,27 @@ import { newService } from '/@/utils/request';
export interface DocumentQueryParams { export interface DocumentQueryParams {
keyword?: string; keyword?: string;
datasetId?: string; datasetId?: string;
status?: string;
fileType?: string;
pageNum: number; pageNum: number;
pageSize: number; pageSize: number;
} }
// 创建文档参数 // 创建文档参数
export interface CreateDocumentParams { export interface CreateDocumentParams {
KnowledgeId: number; // 必传 datasetId: string; // 必传
filePath: string; // 必传 filePath: string; // 必传
fileSize: number; // 必传 fileSize: number; // 必传
format: string; // 必传 format: string; // 必传
title: string; // 必传 title: string; // 必传
} }
// 更新文档参数 // 更新文档参数
export interface UpdateDocumentParams { export interface UpdateDocumentParams {
id: string; // 必传 id: string; // 必传
KnowledgeId?: number; // 可选 datasetId?: string;
filePath?: string; // 可选 filePath?: string;
fileSize?: number; // 可选 fileSize?: number;
format?: string; // 可选 format?: string;
title?: string; // 可选 title?: string;
} }
// 文档信息 // 文档信息
@@ -34,35 +32,20 @@ export interface DocumentInfo {
id?: string; id?: string;
name: string; name: string;
datasetId: string; datasetId: string;
datasetName?: string; fileType: string;
fileType: string; // pdf, docx, txt, md, html
fileSize?: number; fileSize?: number;
filePath?: string; filePath?: string;
charCount?: number;
chunkCount?: number; chunkCount?: number;
status: string; // pending, processing, completed, failed parseStatus?: string;
indexStatus?: string; // not_indexed, indexing, indexed, failed enabled?: boolean;
errorMessage?: string;
createdAt?: string; createdAt?: string;
updatedAt?: string; updatedAt?: string;
} }
// 文档分段信息
export interface DocumentChunk {
id: string;
documentId: string;
content: string;
chunkIndex: number;
charCount: number;
tokenCount?: number;
embedding?: number[];
createdAt?: string;
}
// 获取文档列表 // 获取文档列表
export function listDocuments(params: DocumentQueryParams) { export function listDocuments(params: DocumentQueryParams) {
return newService({ return newService({
url: '/knowledge/document/list', url: '/rag-knowledge/document/listDocument',
method: 'get', method: 'get',
params, params,
}); });
@@ -71,16 +54,16 @@ export function listDocuments(params: DocumentQueryParams) {
// 获取文档详情 // 获取文档详情
export function getDocument(id: string) { export function getDocument(id: string) {
return newService({ return newService({
url: '/knowledge/document/detail', url: '/rag-knowledge/document/getDocument',
method: 'get', method: 'get',
params: { id }, params: { id },
}); });
} }
// 创建文档JSON格式 // 创建文档
export function createDocument(data: CreateDocumentParams) { export function createDocument(data: CreateDocumentParams) {
return newService({ return newService({
url: '/knowledge/document/create', url: '/rag-knowledge/document/createDocument',
method: 'post', method: 'post',
data, data,
}); });
@@ -89,16 +72,28 @@ export function createDocument(data: CreateDocumentParams) {
// 更新文档 // 更新文档
export function updateDocument(data: UpdateDocumentParams) { export function updateDocument(data: UpdateDocumentParams) {
return newService({ return newService({
url: '/knowledge/document/update', url: '/rag-knowledge/document/updateDocument',
method: 'put', method: 'put',
data, data,
}); });
} }
// 公共文件上传OSS返回文件路径
export function uploadFile(file: File) {
const formData = new FormData();
formData.append('file', file);
return newService({
url: '/oss/file/uploadFile',
method: 'post',
data: formData,
headers: { 'Content-Type': 'multipart/form-data' },
});
}
// 上传文档 // 上传文档
export function uploadDocument(data: FormData) { export function uploadDocument(data: FormData) {
return newService({ return newService({
url: '/knowledge/document/upload', url: '/rag-knowledge/document/createDocument',
method: 'post', method: 'post',
data, data,
headers: { headers: {
@@ -110,61 +105,16 @@ export function uploadDocument(data: FormData) {
// 删除文档 // 删除文档
export function deleteDocument(id: string) { export function deleteDocument(id: string) {
return newService({ return newService({
url: '/knowledge/document/delete', url: '/rag-knowledge/document/deleteDocument',
method: 'delete', method: 'delete',
params: { id }, params: { id },
}); });
} }
// 批量删除文档 // 获取文件向量化处理进度
export function batchDeleteDocuments(ids: string[]) { export function getDocumentProcess(id: string) {
return newService({ return newService({
url: '/knowledge/document/batchDelete', url: '/rag-knowledge/document/getProcess',
method: 'delete',
data: { ids },
});
}
// 重新处理文档
export function reprocessDocument(id: string) {
return newService({
url: '/knowledge/document/reprocess',
method: 'post',
params: { id },
});
}
// 获取文档分段列表
export function listDocumentChunks(params: { documentId: string; pageNum: number; pageSize: number }) {
return newService({
url: '/knowledge/document/chunks',
method: 'get',
params,
});
}
// 更新文档分段
export function updateDocumentChunk(data: { id: string; content: string }) {
return newService({
url: '/knowledge/document/chunk/update',
method: 'put',
data,
});
}
// 删除文档分段
export function deleteDocumentChunk(id: string) {
return newService({
url: '/knowledge/document/chunk/delete',
method: 'delete',
params: { id },
});
}
// 预览文档内容
export function previewDocument(id: string) {
return newService({
url: '/knowledge/document/preview',
method: 'get', method: 'get',
params: { id }, params: { id },
}); });

View File

@@ -76,7 +76,7 @@ export const lazyImg = (el: any, arr: any) => {
const io = new IntersectionObserver((res) => { const io = new IntersectionObserver((res) => {
res.forEach((v: any) => { res.forEach((v: any) => {
if (v.isIntersecting) { if (v.isIntersecting) {
const { img, key } = v.target.dataset; const { img, key } = v.target.knowledge;
v.target.src = img; v.target.src = img;
v.target.onload = () => { v.target.onload = () => {
io.unobserve(v.target); io.unobserve(v.target);

View File

@@ -0,0 +1,219 @@
<template>
<div class="cid-apis-container">
<el-card shadow="hover">
<div class="system-user-search mb15">
<el-form :model="tableData.param" ref="queryRef" :inline="true" label-width="68px">
<el-form-item label="关键字" prop="keyword">
<el-input
v-model="tableData.param.keyword"
placeholder="请输入接口名称"
clearable
size="default"
style="width: 240px"
@keyup.enter.native="getList"
/>
</el-form-item>
<el-form-item>
<el-button size="default" type="primary" @click="getList">
<el-icon><ele-Search /></el-icon>
查询
</el-button>
<el-button size="default" @click="resetQuery(queryRef)">
<el-icon><ele-Refresh /></el-icon>
重置
</el-button>
<el-button size="default" type="success" @click="onOpenAdd">
<el-icon><ele-FolderAdd /></el-icon>
新增接口
</el-button>
<el-button size="default" type="danger" @click="onRowDel(null)">
<el-icon><ele-Delete /></el-icon>
删除
</el-button>
</el-form-item>
</el-form>
</div>
<el-table :data="tableData.data" style="width: 100%" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column type="index" label="序号" width="60" />
<el-table-column prop="name" label="接口名称" show-overflow-tooltip />
<el-table-column prop="path" label="接口路径" show-overflow-tooltip />
<el-table-column prop="method" label="请求方式" width="100" align="center" />
<el-table-column prop="datasourceName" label="所属平台" show-overflow-tooltip />
<el-table-column prop="status" label="状态" width="100" align="center">
<template #default="scope">
<el-tag :type="scope.row.status === 1 ? 'success' : 'danger'" size="small">
{{ scope.row.status === 1 ? '启用' : '禁用' }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="createdAt" label="创建时间" show-overflow-tooltip />
<el-table-column label="操作" width="180">
<template #default="scope">
<el-button size="small" text type="primary" @click="onOpenEdit(scope.row)">修改</el-button>
<el-button size="small" text type="danger" @click="onRowDel(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="tableData.total > 0"
:total="tableData.total"
v-model:page="tableData.param.pageNum"
v-model:limit="tableData.param.pageSize"
@pagination="getList"
/>
</el-card>
<!-- 新增/编辑弹窗 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" :close-on-click-modal="false">
<el-form ref="formRef" :model="form" :rules="rules" label-width="90px">
<el-form-item label="接口名称" prop="name">
<el-input v-model="form.name" placeholder="请输入接口名称" />
</el-form-item>
<el-form-item label="接口路径" prop="path">
<el-input v-model="form.path" placeholder="请输入接口路径" />
</el-form-item>
<el-form-item label="请求方式" prop="method">
<el-select v-model="form.method" style="width: 100%">
<el-option label="GET" value="GET" />
<el-option label="POST" value="POST" />
<el-option label="PUT" value="PUT" />
<el-option label="DELETE" value="DELETE" />
</el-select>
</el-form-item>
<el-form-item label="所属平台" prop="datasourceId">
<el-input v-model="form.datasourceId" placeholder="请输入所属平台ID" />
</el-form-item>
<el-form-item label="描述" prop="description">
<el-input v-model="form.description" type="textarea" :rows="3" placeholder="请输入描述" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="form.status" style="width: 100%">
<el-option label="启用" :value="1" />
<el-option label="禁用" :value="0" />
</el-select>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="dialog.visible = false">取消</el-button>
<el-button type="primary" @click="onSubmit" :loading="dialog.saving">确定</el-button>
</template>
</el-dialog>
</div>
</template>
<script lang="ts">
export default { name: 'cidApis' };
</script>
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue';
import { ElMessage, ElMessageBox, FormInstance } from 'element-plus';
const queryRef = ref<FormInstance>();
const formRef = ref<FormInstance>();
const ids = ref<string[]>([]);
const tableData = reactive({
data: [] as any[],
total: 0,
param: {
pageNum: 1,
pageSize: 10,
keyword: '',
},
});
const dialog = reactive({
visible: false,
title: '',
saving: false,
});
const form = reactive({
id: '',
name: '',
path: '',
method: 'GET',
datasourceId: '',
description: '',
status: 1,
});
const rules = {
name: [{ required: true, message: '请输入接口名称', trigger: 'blur' }],
path: [{ required: true, message: '请输入接口路径', trigger: 'blur' }],
method: [{ required: true, message: '请选择请求方式', trigger: 'change' }],
};
const getList = () => {
// TODO: 调用列表接口
};
const resetQuery = (formEl: FormInstance | undefined) => {
if (!formEl) return;
formEl.resetFields();
getList();
};
const handleSelectionChange = (selection: any[]) => {
ids.value = selection.map((item) => item.id);
};
const onOpenAdd = () => {
dialog.title = '新增接口';
dialog.visible = true;
form.id = '';
form.name = '';
form.path = '';
form.method = 'GET';
form.datasourceId = '';
form.description = '';
form.status = 1;
};
const onOpenEdit = (row: any) => {
dialog.title = '修改接口';
dialog.visible = true;
form.id = row.id;
form.name = row.name;
form.path = row.path;
form.method = row.method;
form.datasourceId = row.datasourceId;
form.description = row.description;
form.status = row.status;
};
const onSubmit = () => {
if (!formRef.value) return;
formRef.value.validate((valid) => {
if (!valid) return;
dialog.saving = true;
// TODO: 调用新增/编辑接口
dialog.saving = false;
dialog.visible = false;
getList();
});
};
const onRowDel = (row: any) => {
const delIds = row ? [row.id] : ids.value;
if (delIds.length === 0) {
ElMessage.error('请选择要删除的数据');
return;
}
ElMessageBox.confirm(`确定要删除选中的接口吗?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(() => {
// TODO: 调用删除接口
ElMessage.success('删除成功');
getList();
}).catch(() => {});
};
onMounted(() => {
getList();
});
</script>

View File

@@ -0,0 +1,355 @@
<template>
<div class="cid-datasource-container">
<el-card shadow="hover">
<div class="system-user-search mb15">
<el-form :model="tableData.param" ref="queryRef" :inline="true" label-width="68px">
<el-form-item label="关键字" prop="keyword">
<el-input
v-model="tableData.param.keyword"
placeholder="请输入平台名称"
clearable
size="default"
style="width: 240px"
@keyup.enter.native="getList"
/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="tableData.param.status" placeholder="平台状态" clearable size="default" style="width: 160px">
<el-option label="启用" value="ACTIVE" />
<el-option label="禁用" value="INACTIVE" />
</el-select>
</el-form-item>
<el-form-item>
<el-button size="default" type="primary" @click="getList">
<el-icon><ele-Search /></el-icon>
查询
</el-button>
<el-button size="default" @click="resetQuery(queryRef)">
<el-icon><ele-Refresh /></el-icon>
重置
</el-button>
<el-button size="default" type="success" @click="onOpenAdd">
<el-icon><ele-FolderAdd /></el-icon>
新增平台
</el-button>
<el-button size="default" type="danger" @click="onRowDel(null)">
<el-icon><ele-Delete /></el-icon>
删除
</el-button>
</el-form-item>
</el-form>
</div>
<el-table :data="tableData.data" style="width: 100%" v-loading="tableData.loading" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column type="index" label="序号" width="60" />
<el-table-column prop="platformName" label="平台名称" show-overflow-tooltip />
<el-table-column prop="platformCode" label="平台编码" show-overflow-tooltip />
<el-table-column prop="apiBaseUrl" label="接口基础URL" show-overflow-tooltip />
<el-table-column prop="authTypeName" label="认证方式" width="130" show-overflow-tooltip />
<el-table-column prop="rateLimitPerMinute" label="限频(次/分)" width="110" align="center" />
<el-table-column prop="statusName" label="状态" width="90" align="center">
<template #default="scope">
<el-tag :type="scope.row.status === 'ACTIVE' ? 'success' : 'danger'" size="small">
{{ scope.row.status === 'ACTIVE' ? '启用' : '禁用' }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="description" label="描述" show-overflow-tooltip />
<el-table-column label="创建时间" width="160">
<template #default="scope">
{{ scope.row.createdAt ? formatTime(scope.row.createdAt) : '' }}
</template>
</el-table-column>
<el-table-column label="操作" width="150" fixed="right">
<template #default="scope">
<el-button size="small" text type="primary" @click="onOpenEdit(scope.row)">修改</el-button>
<el-button size="small" text type="danger" @click="onRowDel(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="tableData.total > 0"
:total="tableData.total"
v-model:page="tableData.param.pageNum"
v-model:limit="tableData.param.pageSize"
@pagination="getList"
/>
</el-card>
<!-- 新增/编辑弹窗 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="600px" :close-on-click-modal="false">
<el-form ref="formRef" :model="form" :rules="rules" label-width="110px">
<el-form-item label="平台名称" prop="platformName">
<el-input v-model="form.platformName" placeholder="请输入平台名称" />
</el-form-item>
<el-form-item label="平台编码" prop="platformCode">
<el-input v-model="form.platformCode" placeholder="请输入平台编码,如 ALIYUN_API" />
</el-form-item>
<el-form-item label="接口基础URL" prop="apiBaseUrl">
<el-input v-model="form.apiBaseUrl" placeholder="请输入接口基础URL" />
</el-form-item>
<el-form-item label="认证方式" prop="authType">
<el-select v-model="form.authType" placeholder="请选择认证方式" style="width: 100%">
<el-option label="API Key认证" value="API_KEY" />
<el-option label="OAuth2" value="OAUTH2" />
<el-option label="Bearer Token" value="BEARER_TOKEN" />
<el-option label="无认证" value="NONE" />
</el-select>
</el-form-item>
<el-form-item label="API Key" prop="apiKey" v-if="form.authType === 'API_KEY'">
<el-input v-model="form.apiKey" placeholder="请输入 API Key" show-password />
</el-form-item>
<el-form-item label="Token" prop="token" v-if="form.authType === 'BEARER_TOKEN'">
<el-input v-model="form.token" placeholder="请输入 Bearer Token" show-password />
</el-form-item>
<el-form-item label="Client ID" prop="clientId" v-if="form.authType === 'OAUTH2'">
<el-input v-model="form.clientId" placeholder="请输入 Client ID" />
</el-form-item>
<el-form-item label="Client Secret" prop="clientSecret" v-if="form.authType === 'OAUTH2'">
<el-input v-model="form.clientSecret" placeholder="请输入 Client Secret" show-password />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="form.status" style="width: 100%">
<el-option label="启用" value="ACTIVE" />
<el-option label="禁用" value="INACTIVE" />
</el-select>
</el-form-item>
<el-row :gutter="16">
<el-col :span="12">
<el-form-item label="限频(次/分)" prop="rateLimitPerMinute">
<el-input-number v-model="form.rateLimitPerMinute" :min="0" style="width: 100%" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="限频(次/时)" prop="rateLimitPerHour">
<el-input-number v-model="form.rateLimitPerHour" :min="0" style="width: 100%" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="并发限制" prop="concurrencyLimit">
<el-input-number v-model="form.concurrencyLimit" :min="0" style="width: 100%" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="超时(ms)" prop="requestTimeoutMs">
<el-input-number v-model="form.requestTimeoutMs" :min="0" style="width: 100%" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="最大重试次数" prop="maxRetries">
<el-input-number v-model="form.maxRetries" :min="0" style="width: 100%" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="重试延迟(ms)" prop="retryDelayMs">
<el-input-number v-model="form.retryDelayMs" :min="0" style="width: 100%" />
</el-form-item>
</el-col>
</el-row>
<el-form-item label="描述" prop="description">
<el-input v-model="form.description" type="textarea" :rows="3" placeholder="请输入描述" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="dialog.visible = false">取消</el-button>
<el-button type="primary" @click="onSubmit" :loading="dialog.saving">确定</el-button>
</template>
</el-dialog>
</div>
</template>
<script lang="ts">
export default { name: 'cidDatasource' };
</script>
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue';
import { ElMessage, ElMessageBox, FormInstance } from 'element-plus';
import { listDatasourcePlatforms, createDatasourcePlatform, updateDatasourcePlatform, deleteDatasourcePlatform } from '/@/api/cid/datasource';
const queryRef = ref<FormInstance>();
const formRef = ref<FormInstance>();
const ids = ref<string[]>([]);
const tableData = reactive({
data: [] as any[],
total: 0,
loading: false,
param: {
pageNum: 1,
pageSize: 10,
keyword: '',
status: '',
},
});
const dialog = reactive({
visible: false,
title: '',
saving: false,
isEdit: false,
});
const form = reactive({
id: '',
platformName: '',
platformCode: '',
apiBaseUrl: '',
authType: 'API_KEY',
status: 'ACTIVE',
description: '',
token: '',
apiKey: '',
clientId: '',
clientSecret: '',
rateLimitPerMinute: 200,
rateLimitPerHour: 10000,
concurrencyLimit: 50,
requestTimeoutMs: 15000,
maxRetries: 3,
retryDelayMs: 300,
});
const rules = {
platformName: [{ required: true, message: '请输入平台名称', trigger: 'blur' }],
platformCode: [{ required: true, message: '请输入平台编码', trigger: 'blur' }],
apiBaseUrl: [{ required: true, message: '请输入接口基础URL', trigger: 'blur' }],
authType: [{ required: true, message: '请选择认证方式', trigger: 'change' }],
};
const formatTime = (ts: number) => {
if (!ts) return '';
const d = new Date(ts * 1000);
return d.toLocaleString('zh-CN', { hour12: false });
};
const getList = async () => {
tableData.loading = true;
try {
const res = await listDatasourcePlatforms({
pageNum: tableData.param.pageNum,
pageSize: tableData.param.pageSize,
...(tableData.param.keyword ? { keyword: tableData.param.keyword } : {}),
...(tableData.param.status ? { status: tableData.param.status } : {}),
});
tableData.data = res.data?.list || [];
tableData.total = res.data?.total || 0;
} catch (_e) {
ElMessage.error('获取平台列表失败');
} finally {
tableData.loading = false;
}
};
const resetQuery = (formEl: FormInstance | undefined) => {
if (!formEl) return;
formEl.resetFields();
getList();
};
const handleSelectionChange = (selection: any[]) => {
ids.value = selection.map((item) => item.id);
};
const resetForm = () => {
form.id = '';
form.platformName = '';
form.platformCode = '';
form.apiBaseUrl = '';
form.authType = 'API_KEY';
form.status = 'ACTIVE';
form.description = '';
form.token = '';
form.apiKey = '';
form.clientId = '';
form.clientSecret = '';
form.rateLimitPerMinute = 200;
form.rateLimitPerHour = 10000;
form.concurrencyLimit = 50;
form.requestTimeoutMs = 15000;
form.maxRetries = 3;
form.retryDelayMs = 300;
};
const onOpenAdd = () => {
resetForm();
dialog.title = '新增平台';
dialog.isEdit = false;
dialog.visible = true;
};
const onOpenEdit = (row: any) => {
dialog.title = '修改平台';
dialog.isEdit = true;
dialog.visible = true;
form.id = row.id;
form.platformName = row.platformName;
form.platformCode = row.platformCode;
form.apiBaseUrl = row.apiBaseUrl;
form.authType = row.authType;
form.status = row.status;
form.description = row.description || '';
form.token = row.token || '';
form.apiKey = row.apiKey || '';
form.clientId = row.clientId || '';
form.clientSecret = row.clientSecret || '';
form.rateLimitPerMinute = row.rateLimitPerMinute ?? 200;
form.rateLimitPerHour = row.rateLimitPerHour ?? 10000;
form.concurrencyLimit = row.concurrencyLimit ?? 50;
form.requestTimeoutMs = row.requestTimeoutMs ?? 15000;
form.maxRetries = row.maxRetries ?? 3;
form.retryDelayMs = row.retryDelayMs ?? 300;
};
const onSubmit = () => {
if (!formRef.value) return;
formRef.value.validate(async (valid) => {
if (!valid) return;
dialog.saving = true;
try {
if (dialog.isEdit) {
await updateDatasourcePlatform({ ...form });
ElMessage.success('修改成功');
} else {
const { id: _id, ...createParams } = form;
await createDatasourcePlatform(createParams);
ElMessage.success('创建成功');
}
dialog.visible = false;
getList();
} catch (_e) {
ElMessage.error(dialog.isEdit ? '修改失败' : '创建失败');
} finally {
dialog.saving = false;
}
});
};
const onRowDel = (row: any) => {
const delIds = row ? [row.id] : ids.value;
if (delIds.length === 0) {
ElMessage.error('请选择要删除的数据');
return;
}
const msg = row ? `确定要删除平台「${row.platformName}」吗?` : `确定要删除选中的 ${delIds.length} 个平台吗?`;
ElMessageBox.confirm(msg, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(async () => {
try {
for (const id of delIds) {
await deleteDatasourcePlatform(id);
}
ElMessage.success('删除成功');
getList();
} catch (_e) {
ElMessage.error('删除失败');
}
}).catch(() => {});
};
onMounted(() => {
getList();
});
</script>

View File

@@ -0,0 +1,198 @@
<template>
<div class="cid-field-container">
<el-card shadow="hover">
<div class="system-user-search mb15">
<el-form :model="tableData.param" ref="queryRef" :inline="true" label-width="68px">
<el-form-item label="关键字" prop="keyword">
<el-input
v-model="tableData.param.keyword"
placeholder="请输入字段名称"
clearable
size="default"
style="width: 240px"
@keyup.enter.native="getList"
/>
</el-form-item>
<el-form-item>
<el-button size="default" type="primary" @click="getList">
<el-icon><ele-Search /></el-icon>
查询
</el-button>
<el-button size="default" @click="resetQuery(queryRef)">
<el-icon><ele-Refresh /></el-icon>
重置
</el-button>
<el-button size="default" type="success" @click="onOpenAdd">
<el-icon><ele-FolderAdd /></el-icon>
新增映射
</el-button>
<el-button size="default" type="danger" @click="onRowDel(null)">
<el-icon><ele-Delete /></el-icon>
删除
</el-button>
</el-form-item>
</el-form>
</div>
<el-table :data="tableData.data" style="width: 100%" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column type="index" label="序号" width="60" />
<el-table-column prop="sourceField" label="源字段" show-overflow-tooltip />
<el-table-column prop="targetField" label="目标字段" show-overflow-tooltip />
<el-table-column prop="datasourceName" label="所属平台" show-overflow-tooltip />
<el-table-column prop="apiName" label="所属接口" show-overflow-tooltip />
<el-table-column prop="description" label="描述" show-overflow-tooltip />
<el-table-column prop="createdAt" label="创建时间" show-overflow-tooltip />
<el-table-column label="操作" width="180">
<template #default="scope">
<el-button size="small" text type="primary" @click="onOpenEdit(scope.row)">修改</el-button>
<el-button size="small" text type="danger" @click="onRowDel(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="tableData.total > 0"
:total="tableData.total"
v-model:page="tableData.param.pageNum"
v-model:limit="tableData.param.pageSize"
@pagination="getList"
/>
</el-card>
<!-- 新增/编辑弹窗 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" :close-on-click-modal="false">
<el-form ref="formRef" :model="form" :rules="rules" label-width="90px">
<el-form-item label="源字段" prop="sourceField">
<el-input v-model="form.sourceField" placeholder="请输入源字段名" />
</el-form-item>
<el-form-item label="目标字段" prop="targetField">
<el-input v-model="form.targetField" placeholder="请输入目标字段名" />
</el-form-item>
<el-form-item label="所属平台" prop="datasourceId">
<el-input v-model="form.datasourceId" placeholder="请输入所属平台ID" />
</el-form-item>
<el-form-item label="所属接口" prop="apiId">
<el-input v-model="form.apiId" placeholder="请输入所属接口ID" />
</el-form-item>
<el-form-item label="描述" prop="description">
<el-input v-model="form.description" type="textarea" :rows="3" placeholder="请输入描述" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="dialog.visible = false">取消</el-button>
<el-button type="primary" @click="onSubmit" :loading="dialog.saving">确定</el-button>
</template>
</el-dialog>
</div>
</template>
<script lang="ts">
export default { name: 'cidField' };
</script>
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue';
import { ElMessage, ElMessageBox, FormInstance } from 'element-plus';
const queryRef = ref<FormInstance>();
const formRef = ref<FormInstance>();
const ids = ref<string[]>([]);
const tableData = reactive({
data: [] as any[],
total: 0,
param: {
pageNum: 1,
pageSize: 10,
keyword: '',
},
});
const dialog = reactive({
visible: false,
title: '',
saving: false,
});
const form = reactive({
id: '',
sourceField: '',
targetField: '',
datasourceId: '',
apiId: '',
description: '',
});
const rules = {
sourceField: [{ required: true, message: '请输入源字段名', trigger: 'blur' }],
targetField: [{ required: true, message: '请输入目标字段名', trigger: 'blur' }],
};
const getList = () => {
// TODO: 调用列表接口
};
const resetQuery = (formEl: FormInstance | undefined) => {
if (!formEl) return;
formEl.resetFields();
getList();
};
const handleSelectionChange = (selection: any[]) => {
ids.value = selection.map((item) => item.id);
};
const onOpenAdd = () => {
dialog.title = '新增字典映射';
dialog.visible = true;
form.id = '';
form.sourceField = '';
form.targetField = '';
form.datasourceId = '';
form.apiId = '';
form.description = '';
};
const onOpenEdit = (row: any) => {
dialog.title = '修改字典映射';
dialog.visible = true;
form.id = row.id;
form.sourceField = row.sourceField;
form.targetField = row.targetField;
form.datasourceId = row.datasourceId;
form.apiId = row.apiId;
form.description = row.description;
};
const onSubmit = () => {
if (!formRef.value) return;
formRef.value.validate((valid) => {
if (!valid) return;
dialog.saving = true;
// TODO: 调用新增/编辑接口
dialog.saving = false;
dialog.visible = false;
getList();
});
};
const onRowDel = (row: any) => {
const delIds = row ? [row.id] : ids.value;
if (delIds.length === 0) {
ElMessage.error('请选择要删除的数据');
return;
}
ElMessageBox.confirm(`确定要删除选中的字典映射吗?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(() => {
// TODO: 调用删除接口
ElMessage.success('删除成功');
getList();
}).catch(() => {});
};
onMounted(() => {
getList();
});
</script>

View File

@@ -13,9 +13,7 @@
<div class="document-content"> <div class="document-content">
<div class="content-header"> <div class="content-header">
<h2>{{ documentInfo.name }}</h2> <h2>{{ documentInfo.name }}</h2>
<div class="content-meta"> <div class="content-meta">Size{{ formatFileSize(documentInfo.fileSize) }} Uploaded Time{{ documentInfo.createdAt }}</div>
Size{{ formatFileSize(documentInfo.fileSize) }} Uploaded Time{{ documentInfo.createdAt }}
</div>
</div> </div>
<div class="content-body" v-loading="contentLoading"> <div class="content-body" v-loading="contentLoading">
<pre class="document-text">{{ documentContent }}</pre> <pre class="document-text">{{ documentContent }}</pre>
@@ -37,13 +35,7 @@
</el-radio-group> </el-radio-group>
</div> </div>
<div class="toolbar-actions"> <div class="toolbar-actions">
<el-input <el-input v-model="chunkSearch" placeholder="搜索" clearable size="small" style="width: 120px">
v-model="chunkSearch"
placeholder="搜索"
clearable
size="small"
style="width: 120px"
>
<template #prefix> <template #prefix>
<el-icon><ele-Search /></el-icon> <el-icon><ele-Search /></el-icon>
</template> </template>
@@ -59,11 +51,7 @@
<el-checkbox v-model="selectAll" @change="onSelectAllChange">选择所有</el-checkbox> <el-checkbox v-model="selectAll" @change="onSelectAllChange">选择所有</el-checkbox>
</div> </div>
<div <div class="chunk-item" v-for="chunk in filteredChunks" :key="chunk.id">
class="chunk-item"
v-for="chunk in filteredChunks"
:key="chunk.id"
>
<div class="chunk-checkbox"> <div class="chunk-checkbox">
<el-checkbox v-model="chunk.selected" /> <el-checkbox v-model="chunk.selected" />
</div> </div>
@@ -112,8 +100,8 @@ import { ElMessage } from 'element-plus';
const props = defineProps<{ const props = defineProps<{
modelValue: boolean; modelValue: boolean;
datasetId: string; knowledgeId: string;
datasetName: string; knowledgeName: string;
document: any; document: any;
}>(); }>();
@@ -150,9 +138,7 @@ const selectAll = ref(false);
// 过滤后的切片列表 // 过滤后的切片列表
const filteredChunks = computed(() => { const filteredChunks = computed(() => {
if (!chunkSearch.value) return chunkList.value; if (!chunkSearch.value) return chunkList.value;
return chunkList.value.filter((chunk) => return chunkList.value.filter((chunk) => (chunk.content || '').toLowerCase().includes(chunkSearch.value.toLowerCase()));
(chunk.content || '').toLowerCase().includes(chunkSearch.value.toLowerCase())
);
}); });
// 格式化文件大小 // 格式化文件大小
@@ -215,7 +201,7 @@ const getChunkList = async () => {
// 全选变化 // 全选变化
const onSelectAllChange = (val: boolean) => { const onSelectAllChange = (val: boolean) => {
chunkList.value.forEach(chunk => { chunkList.value.forEach((chunk) => {
chunk.selected = val; chunk.selected = val;
}); });
}; };
@@ -231,12 +217,15 @@ const onAddChunk = () => {
}; };
// 监听弹窗打开 // 监听弹窗打开
watch(() => props.modelValue, (val) => { watch(
if (val && props.document) { () => props.modelValue,
getDocumentDetail(); (val) => {
getChunkList(); if (val && props.document) {
getDocumentDetail();
getChunkList();
}
} }
}); );
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">

View File

@@ -1,11 +1,5 @@
<template> <template>
<el-dialog <el-dialog :title="isEdit ? '编辑数据集' : '新增数据集'" v-model="isShowDialog" width="600px" :close-on-click-modal="false" @close="onCancel">
:title="isEdit ? '编辑数据集' : '新增数据集'"
v-model="isShowDialog"
width="600px"
:close-on-click-modal="false"
@close="onCancel"
>
<el-form ref="formRef" :model="ruleForm" :rules="rules" label-width="100px"> <el-form ref="formRef" :model="ruleForm" :rules="rules" label-width="100px">
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="24"> <el-col :span="24">
@@ -67,7 +61,7 @@
<script lang="ts"> <script lang="ts">
export default { export default {
name: 'editDataset', name: 'editknowledge',
}; };
</script> </script>
@@ -75,10 +69,10 @@ export default {
import { ref, reactive } from 'vue'; import { ref, reactive } from 'vue';
import { ElMessage } from 'element-plus'; import { ElMessage } from 'element-plus';
import type { FormInstance, FormRules } from 'element-plus'; import type { FormInstance, FormRules } from 'element-plus';
import { createDataset, updateDataset, getDataset } from '/@/api/knowledge/dataset'; import { createknowledge, updateknowledge, getknowledge } from '/@/api/knowledge/knowledge';
// 定义事件 // 定义事件
const emit = defineEmits(['getDatasetList']); const emit = defineEmits(['getknowledgeList']);
// 表单ref // 表单ref
const formRef = ref<FormInstance>(); const formRef = ref<FormInstance>();
@@ -124,7 +118,7 @@ const openDialog = async (row?: any) => {
if (row) { if (row) {
try { try {
const res: any = await getDataset(row.id); const res: any = await getknowledge(row.id);
const data = res.data || row; const data = res.data || row;
ruleForm.id = data.id || ''; ruleForm.id = data.id || '';
ruleForm.name = data.name || ''; ruleForm.name = data.name || '';
@@ -174,15 +168,15 @@ const onSubmit = async () => {
}; };
if (isEdit.value) { if (isEdit.value) {
await updateDataset(data); await updateknowledge(data);
ElMessage.success('保存成功'); ElMessage.success('保存成功');
} else { } else {
await createDataset(data); await createknowledge(data);
ElMessage.success('创建成功'); ElMessage.success('创建成功');
} }
isShowDialog.value = false; isShowDialog.value = false;
emit('getDatasetList'); emit('getknowledgeList');
} catch (_error) { } catch (_error) {
ElMessage.error(isEdit.value ? '保存失败,请重试' : '创建失败,请重试'); ElMessage.error(isEdit.value ? '保存失败,请重试' : '创建失败,请重试');
} finally { } finally {
@@ -198,5 +192,4 @@ defineExpose({
}); });
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss"></style>
</style>

View File

@@ -1,8 +1,8 @@
<template> <template>
<div class="knowledge-dataset-page"> <div class="knowledge-knowledge-page">
<div class="knowledge-dataset-container"> <div class="knowledge-knowledge-container">
<el-card shadow="hover"> <el-card shadow="hover">
<div class="knowledge-dataset-search mb15"> <div class="knowledge-knowledge-search mb15">
<el-form :inline="true"> <el-form :inline="true">
<el-form-item label="数据集名称"> <el-form-item label="数据集名称">
<el-input size="default" v-model="tableData.param.keyword" placeholder="请输入数据集名称" clearable style="width: 200px" /> <el-input size="default" v-model="tableData.param.keyword" placeholder="请输入数据集名称" clearable style="width: 200px" />
@@ -21,7 +21,7 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button size="default" type="primary" @click="getDatasetList"> <el-button size="default" type="primary" @click="getknowledgeList">
<el-icon><ele-Search /></el-icon> <el-icon><ele-Search /></el-icon>
查询 查询
</el-button> </el-button>
@@ -29,7 +29,7 @@
<el-icon><ele-Refresh /></el-icon> <el-icon><ele-Refresh /></el-icon>
重置 重置
</el-button> </el-button>
<el-button size="default" type="success" @click="onOpenAdd" v-auth="'api/v1/knowledge/dataset/create'"> <el-button size="default" type="success" @click="onOpenAdd" v-auth="'api/v1/knowledge/knowledge/create'">
<el-icon><ele-Plus /></el-icon> <el-icon><ele-Plus /></el-icon>
新增 新增
</el-button> </el-button>
@@ -63,7 +63,7 @@
active-text="" active-text=""
inactive-text="" inactive-text=""
@change="onStatusChange(scope.row)" @change="onStatusChange(scope.row)"
v-auth="'api/v1/knowledge/dataset/updateStatus'" v-auth="'api/v1/knowledge/knowledge/updateStatus'"
/> />
</template> </template>
</el-table-column> </el-table-column>
@@ -71,9 +71,9 @@
<el-table-column prop="updatedAt" label="更新时间" width="170" show-overflow-tooltip /> <el-table-column prop="updatedAt" label="更新时间" width="170" show-overflow-tooltip />
<el-table-column label="操作" width="200" fixed="right" align="center"> <el-table-column label="操作" width="200" fixed="right" align="center">
<template #default="scope"> <template #default="scope">
<el-button size="small" text type="primary" @click="onEdit(scope.row)" v-auth="'api/v1/knowledge/dataset/update'">编辑</el-button> <el-button size="small" text type="primary" @click="onEdit(scope.row)" v-auth="'api/v1/knowledge/knowledge/update'">编辑</el-button>
<el-button size="small" text type="success" @click="onManageDocuments(scope.row)">文档</el-button> <el-button size="small" text type="success" @click="onManageDocuments(scope.row)">文档</el-button>
<el-button size="small" text type="danger" @click="onRowDel(scope.row)" v-auth="'api/v1/knowledge/dataset/delete'">删除</el-button> <el-button size="small" text type="danger" @click="onRowDel(scope.row)" v-auth="'api/v1/knowledge/knowledge/delete'">删除</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@@ -91,13 +91,13 @@
</div> </div>
</el-card> </el-card>
</div> </div>
<EditDataset ref="editDatasetRef" @getDatasetList="getDatasetList" /> <Editknowledge ref="editknowledgeRef" @getknowledgeList="getknowledgeList" />
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
export default { export default {
name: 'knowledgeDataset', name: 'knowledgeknowledge',
}; };
</script> </script>
@@ -105,8 +105,8 @@ export default {
import { ref, reactive, onMounted } from 'vue'; import { ref, reactive, onMounted } from 'vue';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import { ElMessage, ElMessageBox } from 'element-plus'; import { ElMessage, ElMessageBox } from 'element-plus';
import { listDatasets, deleteDataset, updateDatasetStatus } from '/@/api/knowledge/dataset'; import { listknowledges, deleteknowledge, updateknowledgeStatus } from '/@/api/knowledge/knowledge';
import EditDataset from './component/editDataset.vue'; import Editknowledge from './component/editknowledge.vue';
const router = useRouter(); const router = useRouter();
@@ -125,13 +125,13 @@ const tableData = reactive({
}); });
// 编辑弹窗ref // 编辑弹窗ref
const editDatasetRef = ref(); const editknowledgeRef = ref();
// 获取数据集列表 // 获取数据集列表
const getDatasetList = async () => { const getknowledgeList = async () => {
tableData.loading = true; tableData.loading = true;
try { try {
const res: any = await listDatasets(tableData.param); const res: any = await listknowledges(tableData.param);
const list = res.data?.list || []; const list = res.data?.list || [];
tableData.data = list.map((item: any) => ({ tableData.data = list.map((item: any) => ({
...item, ...item,
@@ -190,27 +190,27 @@ const onResetQuery = () => {
tableData.param.type = ''; tableData.param.type = '';
tableData.param.status = undefined; tableData.param.status = undefined;
tableData.param.pageNum = 1; tableData.param.pageNum = 1;
getDatasetList(); getknowledgeList();
}; };
// 打开新增弹窗 // 打开新增弹窗
const onOpenAdd = () => { const onOpenAdd = () => {
editDatasetRef.value.openDialog(); editknowledgeRef.value.openDialog();
}; };
// 打开编辑弹窗 // 打开编辑弹窗
const onEdit = (row: any) => { const onEdit = (row: any) => {
editDatasetRef.value.openDialog(row); editknowledgeRef.value.openDialog(row);
}; };
// 查看详情 // 查看详情
const onViewDetail = (row: any) => { const onViewDetail = (row: any) => {
router.push({ path: '/knowledge/document', query: { datasetId: row.id, datasetName: row.name } }); router.push({ path: '/knowledge/document', query: { knowledgeId: row.id, knowledgeName: row.name } });
}; };
// 管理文档 // 管理文档
const onManageDocuments = (row: any) => { const onManageDocuments = (row: any) => {
router.push({ path: '/knowledge/document', query: { datasetId: row.id, datasetName: row.name } }); router.push({ path: '/knowledge/document', query: { knowledgeId: row.id, knowledgeName: row.name } });
}; };
// 状态切换 // 状态切换
@@ -218,7 +218,7 @@ const onStatusChange = async (row: any) => {
const newStatus = row.statusEnabled ? 'enable' : 'disable'; const newStatus = row.statusEnabled ? 'enable' : 'disable';
const statusText = row.statusEnabled ? '启用' : '禁用'; const statusText = row.statusEnabled ? '启用' : '禁用';
try { try {
await updateDatasetStatus({ id: row.id, status: newStatus }); await updateknowledgeStatus({ id: row.id, status: newStatus });
ElMessage.success(`${statusText}成功`); ElMessage.success(`${statusText}成功`);
} catch (_error) { } catch (_error) {
row.statusEnabled = !row.statusEnabled; row.statusEnabled = !row.statusEnabled;
@@ -232,40 +232,42 @@ const onRowDel = (row: any) => {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning', type: 'warning',
}).then(async () => { })
try { .then(async () => {
await deleteDataset(row.id); try {
ElMessage.success('删除成功'); await deleteknowledge(row.id);
getDatasetList(); ElMessage.success('删除成功');
} catch (_error) { getknowledgeList();
ElMessage.error('删除失败'); } catch (_error) {
} ElMessage.error('删除失败');
}).catch(() => {}); }
})
.catch(() => {});
}; };
// 分页大小改变 // 分页大小改变
const onSizeChange = (size: number) => { const onSizeChange = (size: number) => {
tableData.param.pageSize = size; tableData.param.pageSize = size;
getDatasetList(); getknowledgeList();
}; };
// 当前页改变 // 当前页改变
const onCurrentChange = (page: number) => { const onCurrentChange = (page: number) => {
tableData.param.pageNum = page; tableData.param.pageNum = page;
getDatasetList(); getknowledgeList();
}; };
// 页面加载时获取数据 // 页面加载时获取数据
onMounted(() => { onMounted(() => {
getDatasetList(); getknowledgeList();
}); });
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.knowledge-dataset-page { .knowledge-knowledge-page {
padding: 15px; padding: 15px;
.knowledge-dataset-container { .knowledge-knowledge-container {
.knowledge-dataset-search { .knowledge-knowledge-search {
.el-form-item { .el-form-item {
margin-bottom: 0; margin-bottom: 0;
} }

View File

@@ -1,10 +1,5 @@
<template> <template>
<el-drawer <el-drawer v-model="isShowDrawer" title="文档分段管理" size="70%" :close-on-click-modal="true">
v-model="isShowDrawer"
title="文档分段管理"
size="70%"
:close-on-click-modal="true"
>
<div class="chunks-container" v-loading="loading"> <div class="chunks-container" v-loading="loading">
<div class="chunks-header"> <div class="chunks-header">
<div class="doc-info"> <div class="doc-info">
@@ -12,13 +7,7 @@
<el-tag size="small" type="info"> {{ tableData.total }} 个分段</el-tag> <el-tag size="small" type="info"> {{ tableData.total }} 个分段</el-tag>
</div> </div>
<div class="actions"> <div class="actions">
<el-input <el-input v-model="searchKeyword" placeholder="搜索分段内容" clearable style="width: 200px" @keyup.enter="onSearch">
v-model="searchKeyword"
placeholder="搜索分段内容"
clearable
style="width: 200px"
@keyup.enter="onSearch"
>
<template #append> <template #append>
<el-button @click="onSearch"> <el-button @click="onSearch">
<el-icon><ele-Search /></el-icon> <el-icon><ele-Search /></el-icon>
@@ -29,11 +18,7 @@
</div> </div>
<div class="chunks-list"> <div class="chunks-list">
<div <div class="chunk-item" v-for="chunk in tableData.data" :key="chunk.id">
class="chunk-item"
v-for="chunk in tableData.data"
:key="chunk.id"
>
<div class="chunk-header"> <div class="chunk-header">
<div class="chunk-index"> <div class="chunk-index">
<el-tag size="small"># {{ chunk.chunkIndex + 1 }}</el-tag> <el-tag size="small"># {{ chunk.chunkIndex + 1 }}</el-tag>
@@ -55,12 +40,7 @@
{{ chunk.content }} {{ chunk.content }}
</div> </div>
<div class="chunk-edit" v-else> <div class="chunk-edit" v-else>
<el-input <el-input v-model="chunk.editContent" type="textarea" :rows="6" placeholder="请输入分段内容" />
v-model="chunk.editContent"
type="textarea"
:rows="6"
placeholder="请输入分段内容"
/>
<div class="edit-actions"> <div class="edit-actions">
<el-button size="small" @click="onCancelEdit(chunk)">取消</el-button> <el-button size="small" @click="onCancelEdit(chunk)">取消</el-button>
<el-button size="small" type="primary" @click="onSaveChunk(chunk)" :loading="chunk.saving">保存</el-button> <el-button size="small" type="primary" @click="onSaveChunk(chunk)" :loading="chunk.saving">保存</el-button>
@@ -186,15 +166,17 @@ const onDeleteChunk = (chunk: any) => {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning', type: 'warning',
}).then(async () => { })
try { .then(async () => {
await deleteDocumentChunk(chunk.id); try {
ElMessage.success('删除成功'); await deleteDocumentChunk(chunk.id);
getChunkList(); ElMessage.success('删除成功');
} catch (_error) { getChunkList();
ElMessage.error('删除失败'); } catch (_error) {
} ElMessage.error('删除失败');
}).catch(() => {}); }
})
.catch(() => {});
}; };
// 分页大小改变 // 分页大小改变
@@ -277,7 +259,8 @@ defineExpose({
align-items: center; align-items: center;
gap: 12px; gap: 12px;
.char-count, .token-count { .char-count,
.token-count {
font-size: 12px; font-size: 12px;
color: #909399; color: #909399;
} }

View File

@@ -1,10 +1,5 @@
<template> <template>
<el-drawer <el-drawer v-model="isShowDrawer" title="文档预览" size="60%" :close-on-click-modal="true">
v-model="isShowDrawer"
title="文档预览"
size="60%"
:close-on-click-modal="true"
>
<div class="preview-container" v-loading="loading"> <div class="preview-container" v-loading="loading">
<div class="preview-header"> <div class="preview-header">
<div class="file-info"> <div class="file-info">
@@ -37,7 +32,7 @@
<el-tab-pane label="文档信息" name="info"> <el-tab-pane label="文档信息" name="info">
<el-descriptions :column="2" border> <el-descriptions :column="2" border>
<el-descriptions-item label="文档名称">{{ documentInfo.name }}</el-descriptions-item> <el-descriptions-item label="文档名称">{{ documentInfo.name }}</el-descriptions-item>
<el-descriptions-item label="所属数据集">{{ documentInfo.datasetName }}</el-descriptions-item> <el-descriptions-item label="所属数据集">{{ documentInfo.knowledgeName }}</el-descriptions-item>
<el-descriptions-item label="文件类型">{{ documentInfo.fileType?.toUpperCase() }}</el-descriptions-item> <el-descriptions-item label="文件类型">{{ documentInfo.fileType?.toUpperCase() }}</el-descriptions-item>
<el-descriptions-item label="文件大小">{{ formatFileSize(documentInfo.fileSize) }}</el-descriptions-item> <el-descriptions-item label="文件大小">{{ formatFileSize(documentInfo.fileSize) }}</el-descriptions-item>
<el-descriptions-item label="字符数">{{ documentInfo.charCount }}</el-descriptions-item> <el-descriptions-item label="字符数">{{ documentInfo.charCount }}</el-descriptions-item>
@@ -81,8 +76,8 @@ const activeTab = ref('content');
const documentInfo = reactive({ const documentInfo = reactive({
id: '', id: '',
name: '', name: '',
datasetId: '', knowledgeId: '',
datasetName: '', knowledgeName: '',
fileType: '', fileType: '',
fileSize: 0, fileSize: 0,
filePath: '', filePath: '',
@@ -211,10 +206,7 @@ const openDialog = async (row: any) => {
// 获取文档详情和内容 // 获取文档详情和内容
loading.value = true; loading.value = true;
try { try {
const [detailRes, contentRes] = await Promise.all([ const [detailRes, contentRes] = await Promise.all([getDocument(row.id), previewDocument(row.id)]);
getDocument(row.id),
previewDocument(row.id),
]);
if (detailRes.data) { if (detailRes.data) {
Object.assign(documentInfo, detailRes.data); Object.assign(documentInfo, detailRes.data);

View File

@@ -1,15 +1,9 @@
<template> <template>
<el-dialog <el-dialog title="上传文档" v-model="isShowDialog" width="600px" :close-on-click-modal="false" @close="onCancel">
title="上传文档"
v-model="isShowDialog"
width="600px"
:close-on-click-modal="false"
@close="onCancel"
>
<el-form ref="formRef" :model="ruleForm" :rules="rules" label-width="100px"> <el-form ref="formRef" :model="ruleForm" :rules="rules" label-width="100px">
<el-form-item label="所属数据集" prop="datasetId"> <el-form-item label="所属数据集" prop="knowledgeId">
<el-select v-model="ruleForm.datasetId" placeholder="请选择数据集" clearable style="width: 100%" :disabled="!!currentDatasetId"> <el-select v-model="ruleForm.datasetId" placeholder="请选择数据集" clearable style="width: 100%" :disabled="!!currentknowledgeId">
<el-option v-for="item in datasetOptions" :key="item.id" :label="item.name" :value="item.id" /> <el-option v-for="item in knowledgeOptions" :key="item.id" :label="item.name" :value="item.id" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="上传文件" prop="files"> <el-form-item label="上传文件" prop="files">
@@ -25,13 +19,9 @@
accept=".pdf,.docx,.doc,.txt,.md,.html" accept=".pdf,.docx,.doc,.txt,.md,.html"
> >
<el-icon class="el-icon--upload"><ele-UploadFilled /></el-icon> <el-icon class="el-icon--upload"><ele-UploadFilled /></el-icon>
<div class="el-upload__text"> <div class="el-upload__text">将文件拖到此处<em>点击上传</em></div>
将文件拖到此处<em>点击上传</em>
</div>
<template #tip> <template #tip>
<div class="el-upload__tip"> <div class="el-upload__tip">支持 PDFWordTXTMarkdownHTML 格式单个文件不超过 20MB</div>
支持 PDFWordTXTMarkdownHTML 格式单个文件不超过 20MB
</div>
</template> </template>
</el-upload> </el-upload>
</el-form-item> </el-form-item>
@@ -81,8 +71,8 @@ import { uploadDocument } from '/@/api/knowledge/document';
// 定义props // 定义props
const props = defineProps<{ const props = defineProps<{
datasetOptions: any[]; knowledgeOptions: any[];
currentDatasetId?: string; currentknowledgeId?: string;
}>(); }>();
// 定义事件 // 定义事件
@@ -115,7 +105,7 @@ const rules = reactive<FormRules>({
// 监听当前数据集ID // 监听当前数据集ID
watch( watch(
() => props.currentDatasetId, () => props.currentknowledgeId,
(val) => { (val) => {
if (val) { if (val) {
ruleForm.datasetId = val; ruleForm.datasetId = val;
@@ -126,7 +116,7 @@ watch(
// 重置表单 // 重置表单
const resetForm = () => { const resetForm = () => {
if (!props.currentDatasetId) { if (!props.currentknowledgeId) {
ruleForm.datasetId = ''; ruleForm.datasetId = '';
} }
ruleForm.chunkSize = 500; ruleForm.chunkSize = 500;

View File

@@ -4,10 +4,10 @@
<div class="page-header"> <div class="page-header">
<el-breadcrumb separator=">"> <el-breadcrumb separator=">">
<el-breadcrumb-item> <el-breadcrumb-item>
<span class="back-link" @click="onBackToKnowledge">知识库</span> <span class="back-link" @click="onBackToknowledge">知识库</span>
</el-breadcrumb-item> </el-breadcrumb-item>
<el-breadcrumb-item> <el-breadcrumb-item>
<span class="back-link" @click="onBackToDataset">{{ datasetName }}</span> <span class="back-link" @click="onBackToknowledge">{{ knowledgeName }}</span>
</el-breadcrumb-item> </el-breadcrumb-item>
<el-breadcrumb-item>{{ documentInfo.name }}</el-breadcrumb-item> <el-breadcrumb-item>{{ documentInfo.name }}</el-breadcrumb-item>
</el-breadcrumb> </el-breadcrumb>
@@ -18,9 +18,7 @@
<div class="document-content"> <div class="document-content">
<div class="content-header"> <div class="content-header">
<h2>{{ documentInfo.name }}</h2> <h2>{{ documentInfo.name }}</h2>
<div class="content-meta"> <div class="content-meta">Size{{ formatFileSize(documentInfo.fileSize) }} Uploaded Time{{ documentInfo.createdAt }}</div>
Size{{ formatFileSize(documentInfo.fileSize) }} Uploaded Time{{ documentInfo.createdAt }}
</div>
</div> </div>
<div class="content-body" v-loading="contentLoading"> <div class="content-body" v-loading="contentLoading">
<pre class="document-text">{{ documentContent }}</pre> <pre class="document-text">{{ documentContent }}</pre>
@@ -42,13 +40,7 @@
</el-radio-group> </el-radio-group>
</div> </div>
<div class="toolbar-actions"> <div class="toolbar-actions">
<el-input <el-input v-model="chunkSearch" placeholder="搜索" clearable size="small" style="width: 120px">
v-model="chunkSearch"
placeholder="搜索"
clearable
size="small"
style="width: 120px"
>
<template #prefix> <template #prefix>
<el-icon><ele-Search /></el-icon> <el-icon><ele-Search /></el-icon>
</template> </template>
@@ -64,11 +56,7 @@
<el-checkbox v-model="selectAll" @change="onSelectAllChange">选择所有</el-checkbox> <el-checkbox v-model="selectAll" @change="onSelectAllChange">选择所有</el-checkbox>
</div> </div>
<div <div class="chunk-item" v-for="chunk in filteredChunks" :key="chunk.id">
class="chunk-item"
v-for="chunk in filteredChunks"
:key="chunk.id"
>
<div class="chunk-checkbox"> <div class="chunk-checkbox">
<el-checkbox v-model="chunk.selected" /> <el-checkbox v-model="chunk.selected" />
</div> </div>
@@ -121,8 +109,8 @@ const route = useRoute();
const router = useRouter(); const router = useRouter();
// 路由参数 // 路由参数
const datasetId = ref(''); const knowledgeId = ref('');
const datasetName = ref(''); const knowledgeName = ref('');
const documentId = ref(''); const documentId = ref('');
// 文档信息 // 文档信息
@@ -151,9 +139,7 @@ const selectAll = ref(false);
// 过滤后的切片列表 // 过滤后的切片列表
const filteredChunks = computed(() => { const filteredChunks = computed(() => {
if (!chunkSearch.value) return chunkList.value; if (!chunkSearch.value) return chunkList.value;
return chunkList.value.filter((chunk) => return chunkList.value.filter((chunk) => (chunk.content || '').toLowerCase().includes(chunkSearch.value.toLowerCase()));
(chunk.content || '').toLowerCase().includes(chunkSearch.value.toLowerCase())
);
}); });
// 格式化文件大小 // 格式化文件大小
@@ -171,15 +157,15 @@ const truncateText = (text: string, maxLength: number) => {
}; };
// 返回知识库列表 // 返回知识库列表
const onBackToKnowledge = () => { const onBackToknowledge = () => {
router.push('/knowledge/dataset'); router.push('/knowledge/knowledge');
}; };
// 返回数据集详情 // 返回数据集详情
const onBackToDataset = () => { const onBackToknowledge = () => {
router.push({ router.push({
path: '/knowledge/document', path: '/knowledge/document',
query: { datasetId: datasetId.value, datasetName: datasetName.value }, query: { knowledgeId: knowledgeId.value, knowledgeName: knowledgeName.value },
}); });
}; };
@@ -195,8 +181,7 @@ const getDocumentDetail = async () => {
documentInfo.fileSize = detail.fileSize || 0; documentInfo.fileSize = detail.fileSize || 0;
documentInfo.createdAt = detail.createdAt || ''; documentInfo.createdAt = detail.createdAt || '';
const contentData = contentRes.data; const contentData = contentRes.data;
documentContent.value = documentContent.value = typeof contentData === 'string' ? contentData : contentData?.content || contentData?.text || '';
typeof contentData === 'string' ? contentData : contentData?.content || contentData?.text || '';
} catch (_error) { } catch (_error) {
ElMessage.error('获取文档详情失败'); ElMessage.error('获取文档详情失败');
documentContent.value = ''; documentContent.value = '';
@@ -248,12 +233,12 @@ const onAddChunk = () => {
// 初始化 // 初始化
onMounted(() => { onMounted(() => {
datasetId.value = (route.query.datasetId as string) || ''; knowledgeId.value = (route.query.knowledgeId as string) || '';
datasetName.value = (route.query.datasetName as string) || ''; knowledgeName.value = (route.query.knowledgeName as string) || '';
documentId.value = (route.query.docId as string) || ''; documentId.value = (route.query.docId as string) || '';
if (!documentId.value) { if (!documentId.value) {
ElMessage.warning('缺少文档ID无法查看详情'); ElMessage.warning('缺少文档ID无法查看详情');
onBackToDataset(); onBackToknowledge();
return; return;
} }
getDocumentDetail(); getDocumentDetail();

View File

@@ -3,18 +3,18 @@
<div class="knowledge-document-container"> <div class="knowledge-document-container">
<el-card shadow="hover"> <el-card shadow="hover">
<!-- 面包屑导航 --> <!-- 面包屑导航 -->
<div class="breadcrumb-nav mb15" v-if="currentDataset.id"> <div class="breadcrumb-nav mb15" v-if="currentknowledge.id">
<el-breadcrumb separator="/"> <el-breadcrumb separator="/">
<el-breadcrumb-item :to="{ path: '/knowledge/dataset' }">数据集管理</el-breadcrumb-item> <el-breadcrumb-item :to="{ path: '/knowledge/knowledge' }">数据集管理</el-breadcrumb-item>
<el-breadcrumb-item>{{ currentDataset.name }}</el-breadcrumb-item> <el-breadcrumb-item>{{ currentknowledge.name }}</el-breadcrumb-item>
</el-breadcrumb> </el-breadcrumb>
</div> </div>
<div class="knowledge-document-search mb15"> <div class="knowledge-document-search mb15">
<el-form :inline="true"> <el-form :inline="true">
<el-form-item label="所属数据集" v-if="!currentDataset.id"> <el-form-item label="所属数据集" v-if="!currentknowledge.id">
<el-select size="default" v-model="tableData.param.datasetId" placeholder="请选择数据集" clearable style="width: 180px"> <el-select size="default" v-model="tableData.param.knowledgeId" placeholder="请选择数据集" clearable style="width: 180px">
<el-option v-for="item in datasetOptions" :key="item.id" :label="item.name" :value="item.id" /> <el-option v-for="item in knowledgeOptions" :key="item.id" :label="item.name" :value="item.id" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="文档名称"> <el-form-item label="文档名称">
@@ -50,20 +50,20 @@
<el-icon><ele-Upload /></el-icon> <el-icon><ele-Upload /></el-icon>
上传文档 上传文档
</el-button> </el-button>
<el-button size="default" type="danger" @click="onBatchDelete" :disabled="selectedIds.length === 0" v-auth="'api/v1/knowledge/document/batchDelete'"> <el-button
size="default"
type="danger"
@click="onBatchDelete"
:disabled="selectedIds.length === 0"
v-auth="'api/v1/knowledge/document/batchDelete'"
>
<el-icon><ele-Delete /></el-icon> <el-icon><ele-Delete /></el-icon>
批量删除 批量删除
</el-button> </el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
</div> </div>
<el-table <el-table :data="tableData.data" style="width: 100%" v-loading="tableData.loading" border @selection-change="onSelectionChange">
:data="tableData.data"
style="width: 100%"
v-loading="tableData.loading"
border
@selection-change="onSelectionChange"
>
<el-table-column type="selection" width="50" align="center" /> <el-table-column type="selection" width="50" align="center" />
<el-table-column type="index" label="序号" width="60" align="center" /> <el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="name" label="文档名称" min-width="200" show-overflow-tooltip> <el-table-column prop="name" label="文档名称" min-width="200" show-overflow-tooltip>
@@ -76,7 +76,7 @@
</div> </div>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="datasetName" label="所属数据集" width="150" show-overflow-tooltip v-if="!currentDataset.id" /> <el-table-column prop="knowledgeName" label="所属数据集" width="150" show-overflow-tooltip v-if="!currentknowledge.id" />
<el-table-column prop="fileType" label="文件类型" width="100" align="center"> <el-table-column prop="fileType" label="文件类型" width="100" align="center">
<template #default="scope"> <template #default="scope">
<el-tag size="small">{{ scope.row.fileType?.toUpperCase() }}</el-tag> <el-tag size="small">{{ scope.row.fileType?.toUpperCase() }}</el-tag>
@@ -103,8 +103,18 @@
<el-table-column label="操作" width="200" fixed="right" align="center"> <el-table-column label="操作" width="200" fixed="right" align="center">
<template #default="scope"> <template #default="scope">
<el-button size="small" text type="primary" @click="onPreview(scope.row)">预览</el-button> <el-button size="small" text type="primary" @click="onPreview(scope.row)">预览</el-button>
<el-button size="small" text type="success" @click="onViewChunks(scope.row)" v-auth="'api/v1/knowledge/document/chunks'">分段</el-button> <el-button size="small" text type="success" @click="onViewChunks(scope.row)" v-auth="'api/v1/knowledge/document/chunks'"
<el-button size="small" text type="warning" @click="onReprocess(scope.row)" v-if="scope.row.status === 'failed'" v-auth="'api/v1/knowledge/document/reprocess'">重试</el-button> >分段</el-button
>
<el-button
size="small"
text
type="warning"
@click="onReprocess(scope.row)"
v-if="scope.row.status === 'failed'"
v-auth="'api/v1/knowledge/document/reprocess'"
>重试</el-button
>
<el-button size="small" text type="danger" @click="onRowDel(scope.row)" v-auth="'api/v1/knowledge/document/delete'">删除</el-button> <el-button size="small" text type="danger" @click="onRowDel(scope.row)" v-auth="'api/v1/knowledge/document/delete'">删除</el-button>
</template> </template>
</el-table-column> </el-table-column>
@@ -125,7 +135,12 @@
</div> </div>
<!-- 上传文档弹窗 --> <!-- 上传文档弹窗 -->
<UploadDocument ref="uploadDocumentRef" :datasetOptions="datasetOptions" :currentDatasetId="currentDataset.id" @getDocumentList="getDocumentList" /> <UploadDocument
ref="uploadDocumentRef"
:knowledgeOptions="knowledgeOptions"
:currentknowledgeId="currentknowledge.id"
@getDocumentList="getDocumentList"
/>
<!-- 文档预览弹窗 --> <!-- 文档预览弹窗 -->
<PreviewDocument ref="previewDocumentRef" /> <PreviewDocument ref="previewDocumentRef" />
@@ -146,7 +161,7 @@ import { ref, reactive, onMounted, watch } from 'vue';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import { ElMessage, ElMessageBox } from 'element-plus'; import { ElMessage, ElMessageBox } from 'element-plus';
import { listDocuments, deleteDocument, batchDeleteDocuments, reprocessDocument } from '/@/api/knowledge/document'; import { listDocuments, deleteDocument, batchDeleteDocuments, reprocessDocument } from '/@/api/knowledge/document';
import { listDatasets } from '/@/api/knowledge/dataset'; import { listknowledges } from '/@/api/knowledge/knowledge';
import UploadDocument from './component/uploadDocument.vue'; import UploadDocument from './component/uploadDocument.vue';
import PreviewDocument from './component/previewDocument.vue'; import PreviewDocument from './component/previewDocument.vue';
import DocumentChunks from './component/documentChunks.vue'; import DocumentChunks from './component/documentChunks.vue';
@@ -154,13 +169,13 @@ import DocumentChunks from './component/documentChunks.vue';
const route = useRoute(); const route = useRoute();
// 当前数据集 // 当前数据集
const currentDataset = reactive({ const currentknowledge = reactive({
id: '', id: '',
name: '', name: '',
}); });
// 数据集选项 // 数据集选项
const datasetOptions = ref<any[]>([]); const knowledgeOptions = ref<any[]>([]);
// 选中的文档ID // 选中的文档ID
const selectedIds = ref<string[]>([]); const selectedIds = ref<string[]>([]);
@@ -172,7 +187,7 @@ const tableData = reactive({
loading: false, loading: false,
param: { param: {
keyword: '', keyword: '',
datasetId: '', knowledgeId: '',
fileType: '', fileType: '',
status: undefined as string | undefined, status: undefined as string | undefined,
pageNum: 1, pageNum: 1,
@@ -186,12 +201,12 @@ const previewDocumentRef = ref();
const documentChunksRef = ref(); const documentChunksRef = ref();
// 获取数据集列表 // 获取数据集列表
const getDatasetOptions = async () => { const getknowledgeOptions = async () => {
try { try {
const res: any = await listDatasets({ pageNum: 1, pageSize: 1000 }); const res: any = await listknowledges({ pageNum: 1, pageSize: 1000 });
datasetOptions.value = res.data?.list || []; knowledgeOptions.value = res.data?.list || [];
} catch (_error) { } catch (_error) {
datasetOptions.value = []; knowledgeOptions.value = [];
ElMessage.error('获取数据集列表失败'); ElMessage.error('获取数据集列表失败');
} }
}; };
@@ -201,8 +216,8 @@ const getDocumentList = async () => {
tableData.loading = true; tableData.loading = true;
try { try {
const params = { ...tableData.param }; const params = { ...tableData.param };
if (currentDataset.id) { if (currentknowledge.id) {
params.datasetId = currentDataset.id; params.knowledgeId = currentknowledge.id;
} }
const res: any = await listDocuments(params); const res: any = await listDocuments(params);
tableData.data = res.data?.list || []; tableData.data = res.data?.list || [];
@@ -309,8 +324,8 @@ const getIndexStatusText = (status: string) => {
// 重置查询 // 重置查询
const onResetQuery = () => { const onResetQuery = () => {
tableData.param.keyword = ''; tableData.param.keyword = '';
if (!currentDataset.id) { if (!currentknowledge.id) {
tableData.param.datasetId = ''; tableData.param.knowledgeId = '';
} }
tableData.param.fileType = ''; tableData.param.fileType = '';
tableData.param.status = undefined; tableData.param.status = undefined;
@@ -346,7 +361,7 @@ const onReprocess = async (row: any) => {
// 选择变化 // 选择变化
const onSelectionChange = (selection: any[]) => { const onSelectionChange = (selection: any[]) => {
selectedIds.value = selection.map(item => item.id); selectedIds.value = selection.map((item) => item.id);
}; };
// 批量删除 // 批量删除
@@ -355,15 +370,17 @@ const onBatchDelete = () => {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning', type: 'warning',
}).then(async () => { })
try { .then(async () => {
await batchDeleteDocuments(selectedIds.value); try {
ElMessage.success('删除成功'); await batchDeleteDocuments(selectedIds.value);
getDocumentList(); ElMessage.success('删除成功');
} catch (_error) { getDocumentList();
ElMessage.error('批量删除失败'); } catch (_error) {
} ElMessage.error('批量删除失败');
}).catch(() => {}); }
})
.catch(() => {});
}; };
// 删除文档 // 删除文档
@@ -372,15 +389,17 @@ const onRowDel = (row: any) => {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning', type: 'warning',
}).then(async () => { })
try { .then(async () => {
await deleteDocument(row.id); try {
ElMessage.success('删除成功'); await deleteDocument(row.id);
getDocumentList(); ElMessage.success('删除成功');
} catch (_error) { getDocumentList();
ElMessage.error('删除失败'); } catch (_error) {
} ElMessage.error('删除失败');
}).catch(() => {}); }
})
.catch(() => {});
}; };
// 分页大小改变 // 分页大小改变
@@ -399,13 +418,13 @@ const onCurrentChange = (page: number) => {
watch( watch(
() => route.query, () => route.query,
(query) => { (query) => {
if (query.datasetId) { if (query.knowledgeId) {
currentDataset.id = query.datasetId as string; currentknowledge.id = query.knowledgeId as string;
currentDataset.name = query.datasetName as string || ''; currentknowledge.name = (query.knowledgeName as string) || '';
tableData.param.datasetId = currentDataset.id; tableData.param.knowledgeId = currentknowledge.id;
} else { } else {
currentDataset.id = ''; currentknowledge.id = '';
currentDataset.name = ''; currentknowledge.name = '';
} }
getDocumentList(); getDocumentList();
}, },
@@ -414,7 +433,7 @@ watch(
// 页面加载时获取数据 // 页面加载时获取数据
onMounted(() => { onMounted(() => {
getDatasetOptions(); getknowledgeOptions();
}); });
</script> </script>

View File

@@ -1,25 +1,25 @@
<template> <template>
<div class="knowledge-page"> <div class="knowledge-page">
<!-- 数据集列表页 --> <!-- 数据集列表页 -->
<div class="dataset-list-view" v-if="!currentDataset"> <div class="knowledge-list-view" v-if="!currentknowledge">
<div class="page-header"> <div class="page-header">
<div class="header-left"> <div class="header-left">
<el-icon class="header-icon"><ele-Folder /></el-icon> <el-icon class="header-icon"><ele-Folder /></el-icon>
<span class="header-title">知识库</span> <span class="header-title">知识库</span>
</div> </div>
<el-button type="primary" @click="onAddDataset"> <el-button type="primary" @click="onAddknowledge">
<el-icon><ele-Plus /></el-icon> <el-icon><ele-Plus /></el-icon>
新建知识库 新建知识库
</el-button> </el-button>
</div> </div>
<div class="dataset-cards" v-loading="datasetLoading"> <div class="knowledge-cards" v-loading="knowledgeLoading">
<!-- 数据集卡片 --> <!-- 数据集卡片 -->
<div <div
class="dataset-card" class="knowledge-card"
v-for="item in datasetList" v-for="item in knowledgeList"
:key="item.id" :key="item.id"
@click="onSelectDataset(item)" @click="onSelectknowledge(item)"
@contextmenu.prevent="onCardContextMenu($event, item)" @contextmenu.prevent="onCardContextMenu($event, item)"
> >
<div class="card-icon"> <div class="card-icon">
@@ -33,12 +33,12 @@
<!-- 悬停操作按钮 --> <!-- 悬停操作按钮 -->
<div class="card-actions" @click.stop> <div class="card-actions" @click.stop>
<el-tooltip content="重命名" placement="top"> <el-tooltip content="重命名" placement="top">
<el-button text size="small" @click="onRenameDataset(item)"> <el-button text size="small" @click="onRenameknowledge(item)">
<el-icon><ele-Edit /></el-icon> <el-icon><ele-Edit /></el-icon>
</el-button> </el-button>
</el-tooltip> </el-tooltip>
<el-tooltip content="删除" placement="top"> <el-tooltip content="删除" placement="top">
<el-button text size="small" type="danger" @click="onDeleteDataset(item)"> <el-button text size="small" type="danger" @click="onDeleteknowledge(item)">
<el-icon><ele-Delete /></el-icon> <el-icon><ele-Delete /></el-icon>
</el-button> </el-button>
</el-tooltip> </el-tooltip>
@@ -46,17 +46,17 @@
</div> </div>
<!-- 查看全部卡片 --> <!-- 查看全部卡片 -->
<div class="see-all-card" v-if="datasetList.length > 0"> <div class="see-all-card" v-if="knowledgeList.length > 0">
<span>See All</span> <span>See All</span>
<el-icon><ele-ArrowRight /></el-icon> <el-icon><ele-ArrowRight /></el-icon>
</div> </div>
<el-empty v-if="datasetList.length === 0 && !datasetLoading" description="暂无知识库,点击上方按钮创建" :image-size="100" /> <el-empty v-if="knowledgeList.length === 0 && !knowledgeLoading" description="暂无知识库,点击上方按钮创建" :image-size="100" />
</div> </div>
</div> </div>
<!-- 数据集详情页 --> <!-- 数据集详情页 -->
<div class="dataset-detail-view" v-else> <div class="knowledge-detail-view" v-else>
<!-- 顶部导航 --> <!-- 顶部导航 -->
<div class="detail-header"> <div class="detail-header">
<div class="header-left"> <div class="header-left">
@@ -64,7 +64,7 @@
<el-breadcrumb-item> <el-breadcrumb-item>
<span class="back-link" @click="onBackToList">知识库</span> <span class="back-link" @click="onBackToList">知识库</span>
</el-breadcrumb-item> </el-breadcrumb-item>
<el-breadcrumb-item>{{ currentDataset.name }}</el-breadcrumb-item> <el-breadcrumb-item>{{ currentknowledge.name }}</el-breadcrumb-item>
</el-breadcrumb> </el-breadcrumb>
</div> </div>
</div> </div>
@@ -72,48 +72,32 @@
<div class="detail-body"> <div class="detail-body">
<!-- 左侧信息面板 --> <!-- 左侧信息面板 -->
<div class="info-sidebar"> <div class="info-sidebar">
<div class="dataset-profile"> <div class="knowledge-profile">
<div class="profile-icon"> <div class="profile-icon">
<span class="icon-text">{{ currentDataset.name?.charAt(0)?.toUpperCase() || 'D' }}</span> <span class="icon-text">{{ currentknowledge.name?.charAt(0)?.toUpperCase() || 'D' }}</span>
</div> </div>
<div class="profile-info"> <div class="profile-info">
<div class="profile-name">{{ currentDataset.name }}</div> <div class="profile-name">{{ currentknowledge.name }}</div>
<div class="profile-meta">{{ currentDataset.fileCount || 0 }} 个文件 · {{ formatFileSize(currentDataset.totalSize || 0) }}</div> <div class="profile-meta">{{ currentknowledge.fileCount || 0 }} 个文件 · {{ formatFileSize(currentknowledge.totalSize || 0) }}</div>
<div class="profile-time">创建于 {{ currentDataset.createdAt }}</div> <div class="profile-time">创建于 {{ currentknowledge.createdAt }}</div>
</div> </div>
</div> </div>
<!-- 功能菜单 --> <!-- 功能菜单 -->
<div class="func-menu"> <div class="func-menu">
<div <div class="menu-item" :class="{ active: activeMenu === 'files' }" @click="activeMenu = 'files'">
class="menu-item"
:class="{ active: activeMenu === 'files' }"
@click="activeMenu = 'files'"
>
<el-icon><ele-Document /></el-icon> <el-icon><ele-Document /></el-icon>
<span>文件列表</span> <span>文件列表</span>
</div> </div>
<div <div class="menu-item" :class="{ active: activeMenu === 'search' }" @click="activeMenu = 'search'">
class="menu-item"
:class="{ active: activeMenu === 'search' }"
@click="activeMenu = 'search'"
>
<el-icon><ele-Search /></el-icon> <el-icon><ele-Search /></el-icon>
<span>检索测试</span> <span>检索测试</span>
</div> </div>
<div <div class="menu-item" :class="{ active: activeMenu === 'logs' }" @click="activeMenu = 'logs'">
class="menu-item"
:class="{ active: activeMenu === 'logs' }"
@click="activeMenu = 'logs'"
>
<el-icon><ele-List /></el-icon> <el-icon><ele-List /></el-icon>
<span>日志</span> <span>日志</span>
</div> </div>
<div <div class="menu-item" :class="{ active: activeMenu === 'settings' }" @click="activeMenu = 'settings'">
class="menu-item"
:class="{ active: activeMenu === 'settings' }"
@click="activeMenu = 'settings'"
>
<el-icon><ele-Setting /></el-icon> <el-icon><ele-Setting /></el-icon>
<span>配置</span> <span>配置</span>
</div> </div>
@@ -130,13 +114,7 @@
<span class="subtitle">解析成功后才能问答哦</span> <span class="subtitle">解析成功后才能问答哦</span>
</div> </div>
<div class="header-actions"> <div class="header-actions">
<el-input <el-input v-model="searchKeyword" placeholder="搜索文件" clearable style="width: 200px" @keyup.enter="getFileList">
v-model="searchKeyword"
placeholder="搜索文件"
clearable
style="width: 200px"
@keyup.enter="getFileList"
>
<template #prefix> <template #prefix>
<el-icon><ele-Search /></el-icon> <el-icon><ele-Search /></el-icon>
</template> </template>
@@ -149,51 +127,33 @@
</div> </div>
<div class="file-table" v-loading="fileLoading"> <div class="file-table" v-loading="fileLoading">
<el-table :data="fileList" style="width: 100%" row-key="id" border> <el-table :data="fileList" style="width: 100%" row-key="id" border>
<el-table-column type="selection" width="50" align="center" /> <el-table-column prop="Title" label="名称" min-width="200">
<el-table-column prop="name" label="名称" min-width="200" sortable>
<template #default="scope"> <template #default="scope">
<div class="file-name" @click="onViewDocumentDetail(scope.row)"> <span class="file-link" @click="onViewDocumentDetail(scope.row)" style="cursor: pointer; color: #409eff">{{
<el-icon class="file-icon" :style="{ color: getFileIconColor(scope.row.fileType) }"> scope.row.Title
<ele-Document /> }}</span>
</el-icon>
<span class="file-link">{{ scope.row.name }}</span>
</div>
</template>
</el-table-column>
<el-table-column prop="createdAt" label="上传日期" width="180" sortable />
<el-table-column prop="source" label="来源" width="80" align="center">
<template #default>
<el-icon><ele-Monitor /></el-icon>
</template>
</el-table-column>
<el-table-column prop="enabled" label="启用" width="80" align="center">
<template #default="scope">
<el-switch
v-model="scope.row.enabled"
size="small"
@change="onFileStatusChange(scope.row)"
/>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="chunkCount" label="分块数" width="80" align="center" /> <el-table-column prop="chunkCount" label="分块数" width="80" align="center" />
<el-table-column prop="parseStatus" label="解析" width="100" align="center"> <el-table-column prop="status" label="状态" width="90" align="center">
<template #default="scope"> <template #default="scope">
<el-tag :type="getParseStatusType(scope.row.parseStatus)" size="small"> <el-tag :type="scope.row.status === 1 ? 'success' : 'info'" size="small">
{{ scope.row.parseStatus }} {{ scope.row.status === 1 ? '正常' : '禁用' }}
</el-tag> </el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="动作" width="140" align="center"> <el-table-column prop="vectorStatus" label="向量化" width="100" align="center">
<template #default="scope"> <template #default="scope">
<el-button text size="small" @click="onPreviewFile(scope.row)"> <el-tag :type="scope.row.vectorStatus === 'done' ? 'success' : 'warning'" size="small">
<el-icon><ele-View /></el-icon> {{ scope.row.vectorStatus || '未处理' }}
</el-button> </el-tag>
<el-button text size="small" @click="onDownloadFile(scope.row)"> </template>
<el-icon><ele-Download /></el-icon> </el-table-column>
</el-button> <el-table-column prop="createdAt" label="上传日期" width="180" />
<el-button text size="small" type="danger" @click="onDeleteFile(scope.row)"> <el-table-column label="动作" width="120" align="center">
<el-icon><ele-Delete /></el-icon> <template #default="scope">
</el-button> <el-button text size="small" @click="onPreviewFile(scope.row)">预览</el-button>
<el-button text size="small" type="danger" @click="onDeleteFile(scope.row)">删除</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@@ -205,12 +165,7 @@
<template v-if="activeMenu === 'search'"> <template v-if="activeMenu === 'search'">
<div class="panel-card"> <div class="panel-card">
<h3>检索测试</h3> <h3>检索测试</h3>
<el-input <el-input v-model="searchQuery" type="textarea" :rows="3" placeholder="输入问题进行检索测试..." />
v-model="searchQuery"
type="textarea"
:rows="3"
placeholder="输入问题进行检索测试..."
/>
<el-button type="primary" class="mt15" @click="onSearchTest">测试检索</el-button> <el-button type="primary" class="mt15" @click="onSearchTest">测试检索</el-button>
<div class="search-results mt15" v-if="searchResults.length > 0"> <div class="search-results mt15" v-if="searchResults.length > 0">
<h4>检索结果</h4> <h4>检索结果</h4>
@@ -227,12 +182,7 @@
<div class="panel-card"> <div class="panel-card">
<h3>操作日志</h3> <h3>操作日志</h3>
<el-timeline> <el-timeline>
<el-timeline-item <el-timeline-item v-for="(log, index) in logList" :key="index" :timestamp="log.time" placement="top">
v-for="(log, index) in logList"
:key="index"
:timestamp="log.time"
placement="top"
>
<span>{{ log.content }}</span> <span>{{ log.content }}</span>
</el-timeline-item> </el-timeline-item>
</el-timeline> </el-timeline>
@@ -246,7 +196,7 @@
<h3>数据集配置</h3> <h3>数据集配置</h3>
<el-form label-width="120px" style="max-width: 500px"> <el-form label-width="120px" style="max-width: 500px">
<el-form-item label="数据集名称"> <el-form-item label="数据集名称">
<el-input v-model="currentDataset.name" disabled /> <el-input v-model="currentknowledge.name" disabled />
</el-form-item> </el-form-item>
<el-form-item label="向量模型"> <el-form-item label="向量模型">
<el-select v-model="settingsForm.embeddingModel" style="width: 100%"> <el-select v-model="settingsForm.embeddingModel" style="width: 100%">
@@ -272,33 +222,23 @@
</div> </div>
<!-- 新增/编辑数据集弹窗 --> <!-- 新增/编辑数据集弹窗 -->
<el-dialog <el-dialog :title="knowledgeForm.id ? '编辑知识库' : '新建知识库'" v-model="showknowledgeDialog" width="500px" :close-on-click-modal="false">
:title="datasetForm.id ? '编辑知识库' : '新建知识库'" <el-form ref="knowledgeFormRef" :model="knowledgeForm" :rules="knowledgeRules" label-width="100px">
v-model="showDatasetDialog"
width="500px"
:close-on-click-modal="false"
>
<el-form ref="datasetFormRef" :model="datasetForm" :rules="datasetRules" label-width="100px">
<el-form-item label="名称" prop="name"> <el-form-item label="名称" prop="name">
<el-input v-model="datasetForm.name" placeholder="请输入知识库名称" /> <el-input v-model="knowledgeForm.name" placeholder="请输入知识库名称" />
</el-form-item> </el-form-item>
<el-form-item label="描述" prop="description"> <el-form-item label="描述" prop="description">
<el-input v-model="datasetForm.description" type="textarea" :rows="3" placeholder="请输入描述" /> <el-input v-model="knowledgeForm.description" type="textarea" :rows="3" placeholder="请输入描述" />
</el-form-item> </el-form-item>
</el-form> </el-form>
<template #footer> <template #footer>
<el-button @click="showDatasetDialog = false">取消</el-button> <el-button @click="showknowledgeDialog = false">取消</el-button>
<el-button type="primary" @click="onSaveDataset" :loading="datasetSaving">确定</el-button> <el-button type="primary" @click="onSaveknowledge" :loading="knowledgeSaving">确定</el-button>
</template> </template>
</el-dialog> </el-dialog>
<!-- 上传文件弹窗 --> <!-- 上传文件弹窗 -->
<el-dialog <el-dialog title="上传文件" v-model="showUploadDialog" width="600px" :close-on-click-modal="false">
title="上传文件"
v-model="showUploadDialog"
width="600px"
:close-on-click-modal="false"
>
<el-upload <el-upload
ref="uploadRef" ref="uploadRef"
class="upload-area" class="upload-area"
@@ -327,8 +267,8 @@
<!-- 文档详情弹窗 --> <!-- 文档详情弹窗 -->
<DocumentDetailDialog <DocumentDetailDialog
v-model="showDocumentDetailDialog" v-model="showDocumentDetailDialog"
:datasetId="currentDataset?.id || ''" :knowledgeId="currentknowledge?.id || ''"
:datasetName="currentDataset?.name || ''" :knowledgeName="currentknowledge?.name || ''"
:document="currentDocument" :document="currentDocument"
/> />
</div> </div>
@@ -345,24 +285,37 @@ import { ref, reactive, onMounted } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus'; import { ElMessage, ElMessageBox } from 'element-plus';
import type { FormInstance, FormRules, UploadFile } from 'element-plus'; import type { FormInstance, FormRules, UploadFile } from 'element-plus';
import DocumentDetailDialog from './component/documentDetailDialog.vue'; import DocumentDetailDialog from './component/documentDetailDialog.vue';
import { listDatasets, createKnowledgeBase, updateKnowledgeBase, deleteDataset } from '/@/api/knowledge/dataset'; import { listknowledges, createknowledge, updateknowledge, deleteknowledge } from '/@/api/knowledge/dataset';
import { listDocuments, uploadFile, createDocument, deleteDocument } from '/@/api/knowledge/document';
// 数据集相关 // 数据集相关
const datasetLoading = ref(false); const knowledgeLoading = ref(false);
const datasetList = ref<any[]>([]); const knowledgeList = ref<any[]>([]);
const currentDataset = ref<any>(null); const currentknowledge = ref<any>(null);
const showDatasetDialog = ref(false); const showknowledgeDialog = ref(false);
const datasetSaving = ref(false); const knowledgeSaving = ref(false);
const datasetFormRef = ref<FormInstance>(); const knowledgeFormRef = ref<FormInstance>();
const datasetForm = reactive({ const knowledgeForm = reactive({
id: '', id: '',
name: '', name: '',
description: '', description: '',
}); });
const datasetRules = reactive<FormRules>({ const knowledgeRules = reactive<FormRules>({
name: [{ required: true, message: '请输入知识库名称', trigger: 'blur' }], name: [{ required: true, message: '请输入知识库名称', trigger: 'blur' }],
}); });
// 文件列表含OSS上传结果
interface UploadFileItem {
file: UploadFile;
filePath: string;
fileSize: number;
fileFormat: string;
fileName: string;
uploading: boolean;
error: boolean;
}
const uploadFileItems = ref<UploadFileItem[]>([]);
// 文件相关 // 文件相关
const fileLoading = ref(false); const fileLoading = ref(false);
const fileList = ref<any[]>([]); const fileList = ref<any[]>([]);
@@ -401,7 +354,7 @@ const formatFileSize = (size: number) => {
}; };
// 获取文件图标颜色 // 获取文件图标颜色
const getFileIconColor = (fileType: string) => { const _getFileIconColor = (fileType: string) => {
const colors: Record<string, string> = { const colors: Record<string, string> = {
pdf: '#f56c6c', pdf: '#f56c6c',
docx: '#409eff', docx: '#409eff',
@@ -415,7 +368,7 @@ const getFileIconColor = (fileType: string) => {
}; };
// 获取解析状态类型 // 获取解析状态类型
const getParseStatusType = (status: string) => { const _getParseStatusType = (status: string) => {
const types: Record<string, string> = { const types: Record<string, string> = {
general: 'success', general: 'success',
pending: 'warning', pending: 'warning',
@@ -425,40 +378,40 @@ const getParseStatusType = (status: string) => {
}; };
// 获取数据集列表 // 获取数据集列表
const getDatasetList = async () => { const getknowledgeList = async () => {
datasetLoading.value = true; knowledgeLoading.value = true;
try { try {
const response = await listDatasets({ const response = await listknowledges({
pageNum: 1, pageNum: 1,
pageSize: 100 pageSize: 100,
}); });
datasetList.value = response.data.list || []; knowledgeList.value = response.data.list || [];
} catch (_error) { } catch (_error) {
ElMessage.error('获取知识库列表失败'); ElMessage.error('获取知识库列表失败');
} finally { } finally {
datasetLoading.value = false; knowledgeLoading.value = false;
} }
}; };
// 选择数据集 // 选择数据集
const onSelectDataset = (item: any) => { const onSelectknowledge = (item: any) => {
currentDataset.value = item; currentknowledge.value = item;
activeMenu.value = 'files'; activeMenu.value = 'files';
getFileList(); getFileList();
getLogList(); getLogList();
}; };
// 新增数据集 // 新增数据集
const onAddDataset = () => { const onAddknowledge = () => {
datasetForm.id = ''; knowledgeForm.id = '';
datasetForm.name = ''; knowledgeForm.name = '';
datasetForm.description = ''; knowledgeForm.description = '';
showDatasetDialog.value = true; showknowledgeDialog.value = true;
}; };
// 返回列表 // 返回列表
const onBackToList = () => { const onBackToList = () => {
currentDataset.value = null; currentknowledge.value = null;
}; };
// 右键菜单 // 右键菜单
@@ -467,64 +420,66 @@ const onCardContextMenu = (event: MouseEvent, item: any) => {
}; };
// 重命名数据集 // 重命名数据集
const onRenameDataset = (item: any) => { const onRenameknowledge = (item: any) => {
datasetForm.id = item.id; knowledgeForm.id = item.id;
datasetForm.name = item.name; knowledgeForm.name = item.name;
datasetForm.description = item.description || ''; knowledgeForm.description = item.description || '';
showDatasetDialog.value = true; showknowledgeDialog.value = true;
}; };
// 删除数据集 // 删除数据集
const onDeleteDataset = (item: any) => { const onDeleteknowledge = (item: any) => {
ElMessageBox.confirm(`确定要删除知识库【${item.name}】吗?`, '提示', { ElMessageBox.confirm(`确定要删除知识库【${item.name}】吗?`, '提示', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning', type: 'warning',
}).then(async () => { })
try { .then(async () => {
await deleteDataset(item.id); try {
ElMessage.success('删除成功'); await deleteknowledge(item.id);
if (currentDataset.value?.id === item.id) { ElMessage.success('删除成功');
currentDataset.value = null; if (currentknowledge.value?.id === item.id) {
currentknowledge.value = null;
}
getknowledgeList();
} catch (_error) {
ElMessage.error('删除失败,请重试');
} }
getDatasetList(); })
} catch (_error) { .catch(() => {});
ElMessage.error('删除失败,请重试');
}
}).catch(() => {});
}; };
// 保存数据集 // 保存数据集
const onSaveDataset = async () => { const onSaveknowledge = async () => {
const form = datasetFormRef.value; const form = knowledgeFormRef.value;
if (!form) return; if (!form) return;
form.validate(async (valid: boolean) => { form.validate(async (valid: boolean) => {
if (valid) { if (valid) {
datasetSaving.value = true; knowledgeSaving.value = true;
try { try {
if (datasetForm.id) { if (knowledgeForm.id) {
// 更新知识库 // 更新知识库
await updateKnowledgeBase({ await updateknowledge({
id: datasetForm.id, id: knowledgeForm.id,
name: datasetForm.name, name: knowledgeForm.name,
description: datasetForm.description description: knowledgeForm.description,
}); });
} else { } else {
// 创建知识库 // 创建知识库
await createKnowledgeBase({ await createknowledge({
name: datasetForm.name, name: knowledgeForm.name,
description: datasetForm.description description: knowledgeForm.description,
}); });
} }
ElMessage.success(datasetForm.id ? '保存成功' : '创建成功'); ElMessage.success(knowledgeForm.id ? '保存成功' : '创建成功');
showDatasetDialog.value = false; showknowledgeDialog.value = false;
getDatasetList(); getknowledgeList();
} catch (_error) { } catch (_error) {
ElMessage.error('保存失败,请重试'); ElMessage.error('保存失败,请重试');
} finally { } finally {
datasetSaving.value = false; knowledgeSaving.value = false;
} }
} }
}); });
@@ -532,40 +487,17 @@ const onSaveDataset = async () => {
// 获取文件列表 // 获取文件列表
const getFileList = async () => { const getFileList = async () => {
if (!currentDataset.value) return; if (!currentknowledge.value) return;
fileLoading.value = true; fileLoading.value = true;
try { try {
// 模拟数据 const response = await listDocuments({
fileList.value = [ datasetId: currentknowledge.value.id,
{ ...(searchKeyword.value ? { keyword: searchKeyword.value } : {}),
id: '1', pageNum: 1,
name: '456_product(1).txt', pageSize: 100,
fileType: 'txt', });
createdAt: '21/01/2026 16:53:32', fileList.value = response.data?.list || [];
enabled: true,
chunkCount: 1,
parseStatus: 'general',
},
{
id: '2',
name: '123_speech(1).txt',
fileType: 'txt',
createdAt: '21/01/2026 16:53:26',
enabled: true,
chunkCount: 1,
parseStatus: 'general',
},
{
id: '3',
name: '123_product.txt',
fileType: 'txt',
createdAt: '21/01/2026 14:39:41',
enabled: true,
chunkCount: 1,
parseStatus: 'general',
},
];
} catch (_error) { } catch (_error) {
ElMessage.error('获取文件列表失败'); ElMessage.error('获取文件列表失败');
} finally { } finally {
@@ -575,36 +507,78 @@ const getFileList = async () => {
// 上传文件 // 上传文件
const onUploadFile = () => { const onUploadFile = () => {
uploadFileItems.value = [];
uploadFileList.value = []; uploadFileList.value = [];
showUploadDialog.value = true; showUploadDialog.value = true;
}; };
// 上传文件变化 // 选择文件时立即上传到OSS
const onUploadChange = (file: UploadFile, files: UploadFile[]) => { const onUploadChange = async (file: UploadFile, files: UploadFile[]) => {
uploadFileList.value = files; uploadFileList.value = files;
// 找出新增的文件(还没有对应的 item
const exists = uploadFileItems.value.some((i) => i.file.uid === file.uid);
if (exists || !file.raw) return;
const item: UploadFileItem = {
file,
filePath: '',
fileSize: 0,
fileFormat: '',
fileName: file.name,
uploading: true,
error: false,
};
uploadFileItems.value.push(item);
try {
const ossRes = await uploadFile(file.raw as File);
item.filePath = ossRes.data?.fileURL || '';
item.fileSize = ossRes.data?.fileSize || file.size || 0;
item.fileFormat = ossRes.data?.fileFormat || file.name.split('.').pop() || '';
item.fileName = ossRes.data?.fileName || file.name;
item.uploading = false;
} catch (_e) {
item.uploading = false;
item.error = true;
ElMessage.error(`${file.name} 上传失败`);
}
}; };
// 移除上传文件 // 移除上传文件
const onUploadRemove = (file: UploadFile, files: UploadFile[]) => { const onUploadRemove = (file: UploadFile, files: UploadFile[]) => {
uploadFileList.value = files; uploadFileList.value = files;
uploadFileItems.value = uploadFileItems.value.filter((i) => i.file.uid !== file.uid);
}; };
// 确认上传 // 确认上传所有文件已上传OSS直接创建文档
const onConfirmUpload = async () => { const onConfirmUpload = async () => {
const readyItems = uploadFileItems.value.filter((i) => !i.uploading && !i.error && i.filePath);
if (readyItems.length === 0) {
ElMessage.warning('请等待文件上传完成或移除上传失败的文件');
return;
}
uploading.value = true; uploading.value = true;
try { try {
ElMessage.success(`成功上传 ${uploadFileList.value.length} 个文件`); for (const item of readyItems) {
const ext = item.file.name.split('.').pop() || '';
await createDocument({
datasetId: currentknowledge.value.id,
filePath: item.filePath,
fileSize: item.fileSize || item.file.size || 0,
format: item.fileFormat || ext,
title: item.fileName || item.file.name,
});
}
ElMessage.success(`成功创建 ${readyItems.length} 个文件`);
showUploadDialog.value = false; showUploadDialog.value = false;
getFileList(); getFileList();
} catch (_error) { } catch (_error) {
ElMessage.error('上传失败,请重试'); ElMessage.error('创建文档失败,请重试');
} finally { } finally {
uploading.value = false; uploading.value = false;
} }
}; };
// 文件状态变化 // 文件状态变化
const onFileStatusChange = (row: any) => { const _onFileStatusChange = (row: any) => {
ElMessage.success(row.enabled ? '已启用' : '已禁用'); ElMessage.success(row.enabled ? '已启用' : '已禁用');
}; };
@@ -620,7 +594,7 @@ const onPreviewFile = (row: any) => {
}; };
// 下载文件 // 下载文件
const onDownloadFile = (row: any) => { const _onDownloadFile = (row: any) => {
ElMessage.info(`下载文件: ${row.name}`); ElMessage.info(`下载文件: ${row.name}`);
}; };
@@ -630,10 +604,17 @@ const onDeleteFile = (row: any) => {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning', type: 'warning',
}).then(() => { })
ElMessage.success('删除成功'); .then(async () => {
getFileList(); try {
}).catch(() => {}); await deleteDocument(row.id);
ElMessage.success('删除成功');
getFileList();
} catch (_error) {
ElMessage.error('删除失败,请重试');
}
})
.catch(() => {});
}; };
// 检索测试 // 检索测试
@@ -656,7 +637,7 @@ const getLogList = () => {
{ time: '2026-01-21 16:53:32', content: '上传文件 456_product(1).txt' }, { time: '2026-01-21 16:53:32', content: '上传文件 456_product(1).txt' },
{ time: '2026-01-21 16:53:26', content: '上传文件 123_speech(1).txt' }, { time: '2026-01-21 16:53:26', content: '上传文件 123_speech(1).txt' },
{ time: '2026-01-21 14:39:41', content: '上传文件 123_product.txt' }, { time: '2026-01-21 14:39:41', content: '上传文件 123_product.txt' },
{ time: '2026-01-17 10:00:00', content: '创建知识库 dataset_tenant_1' }, { time: '2026-01-17 10:00:00', content: '创建知识库 knowledge_tenant_1' },
]; ];
}; };
@@ -667,7 +648,7 @@ const onSaveSettings = () => {
// 页面加载 // 页面加载
onMounted(() => { onMounted(() => {
getDatasetList(); getknowledgeList();
}); });
</script> </script>
@@ -678,7 +659,7 @@ onMounted(() => {
box-sizing: border-box; box-sizing: border-box;
// 数据集列表页 // 数据集列表页
.dataset-list-view { .knowledge-list-view {
.page-header { .page-header {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
@@ -703,12 +684,12 @@ onMounted(() => {
} }
} }
.dataset-cards { .knowledge-cards {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
gap: 16px; gap: 16px;
.dataset-card { .knowledge-card {
width: 200px; width: 200px;
padding: 16px; padding: 16px;
background: #fff; background: #fff;
@@ -804,7 +785,7 @@ onMounted(() => {
} }
// 数据集详情页 // 数据集详情页
.dataset-detail-view { .knowledge-detail-view {
height: 100%; height: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -840,7 +821,7 @@ onMounted(() => {
flex-direction: column; flex-direction: column;
background: #fafafa; background: #fafafa;
.dataset-profile { .knowledge-profile {
padding: 20px 16px; padding: 20px 16px;
border-bottom: 1px solid #ebeef5; border-bottom: 1px solid #ebeef5;

View File

@@ -212,7 +212,7 @@ export default defineComponent({
draggable: '.workflow-left-item', draggable: '.workflow-left-item',
forceFallback: true, forceFallback: true,
onEnd: function (evt: any) { onEnd: function (evt: any) {
const { name, icon, id } = evt.clone.dataset; const { name, icon, id } = evt.clone.knowledge;
const { layerX, layerY, clientX, clientY } = evt.originalEvent; const { layerX, layerY, clientX, clientY } = evt.originalEvent;
const el = state.workflowRightRef!; const el = state.workflowRightRef!;
const { x, y, width, height } = el.getBoundingClientRect(); const { x, y, width, height } = el.getBoundingClientRect();
@@ -617,8 +617,8 @@ export default defineComponent({
position: relative; position: relative;
overflow: hidden; overflow: hidden;
height: 100%; height: 100%;
background-image: linear-gradient(90deg, rgb(156 214 255 / 15%) 10%, rgba(0, 0, 0, 0) 10%), background-image:
linear-gradient(rgb(156 214 255 / 15%) 10%, rgba(0, 0, 0, 0) 10%); linear-gradient(90deg, rgb(156 214 255 / 15%) 10%, rgba(0, 0, 0, 0) 10%), linear-gradient(rgb(156 214 255 / 15%) 10%, rgba(0, 0, 0, 0) 10%);
background-size: 10px 10px; background-size: 10px 10px;
.workflow-right-clone { .workflow-right-clone {
position: absolute; position: absolute;

View File

@@ -1,7 +1,7 @@
<template> <template>
<div class="visualizing-demo1"> <div class="visualizing-demo1">
<baidumap src="https://hm.baidu.com/hm.js?d9c8b87d10717013641458b300c552e4"></baidumap> <baidumap src="https://hm.baidu.com/hm.js?d9c8b87d10717013641458b300c552e4"></baidumap>
<baidumap src="https://api.map.baidu.com/api?v=3.0&ak=wsijQt8sLXrCW71YesmispvYHitfG9gv&s=1"></baidumap> <baidumap src="https://api.map.baidu.com/api?v=3.0&ak=wsijQt8sLXrCW71YesmispvYHitfG9gv&s=1"></baidumap>
<!-- 地图 --> <!-- 地图 -->
<div ref="visualizingDemo1" style="height: 100%"></div> <div ref="visualizingDemo1" style="height: 100%"></div>
<div class="visualizing-container"> <div class="visualizing-container">
@@ -117,7 +117,7 @@ interface Demo1State {
export default defineComponent({ export default defineComponent({
name: 'visualizingLinkDemo1', name: 'visualizingLinkDemo1',
components:{baidumap}, components: { baidumap },
setup() { setup() {
const { proxy } = <any>getCurrentInstance(); const { proxy } = <any>getCurrentInstance();
const state = reactive<Demo1State>({ const state = reactive<Demo1State>({
@@ -707,7 +707,7 @@ export default defineComponent({
}, },
}, },
], ],
dataset: { knowledge: {
source: [ source: [
{ status: '已签收', value1: 33, value2: 93 }, { status: '已签收', value1: 33, value2: 93 },
{ status: '配送中', value1: 53, value2: 32 }, { status: '配送中', value1: 53, value2: 32 },