diff --git a/ui/src/api/API_README.md b/ui/src/api/API_README.md index 80b9da3756c..16bf6d06abe 100644 --- a/ui/src/api/API_README.md +++ b/ui/src/api/API_README.md @@ -183,8 +183,8 @@ v3 编辑表单提交 `{ name, description }`,标题上限 64、更新说明 `system/shared-resources/knowledge/knowledge.ts` 使用 `/system/shared/knowledge`,维护分页、详情、 通用 / Web / 飞书 / 工作流创建、导入、删除、重新向量化、Web 同步、关联问题、分词索引、MCP 配置与三种导出。工作流创建在 Workspace 与 System 共享范围均由同一个 Knowledge API 的 -`postKnowledgeWorkflow` 提交;`workspace/knowledge/workflow.ts` 仅维护已创建知识库的工作流 -画布接口。System 共享范围没有工作空间文件夹、批量接口或独立的知识库工作流 API 文件。复用创建入口 +`postKnowledgeWorkflow` 提交;工作流转换由各范围的 `knowledge.ts` 维护, +`workspace/knowledge/workflow.ts` 仅维护已创建知识库的画布接口。System 共享范围没有工作空间文件夹、批量接口或独立的知识库工作流 API 文件。复用创建入口 和卡片 Action 时使用完整 Workspace / System 资源管理 / System 共享知识库 API 的联合类型,由页面显式传入当前范围的 API。 ### 工具代码生成 @@ -461,13 +461,16 @@ System 共享资源分别保留各自路径下的同名接口,不再重复封 或提交 `work_flow_template` 由服务端下载并覆盖当前工具工作流。模板覆盖后由 View 重新查询详情, 同步默认模型设置、保存时间和图快照;确认取消或请求失败不关闭模板中心。 -### 知识库工作流模板与导出 +### 知识库工作流模板与导入导出 `admin/store.ts` 的 `getStoreKnowledgeList(query)` 查询 `/workspace/store/knowledge_template`, 返回 `KnowledgeWorkflowStoreResponse`,其中 `apps` 使用公共 `WorkflowStoreTemplate[]`。 `putKnowledgeWorkflow` 接受互斥的 `work_flow` 保存载荷或 `work_flow_template` 覆盖载荷,覆盖成功后由 View 重载详情。 `exportKnowledgeWorkflow(knowledgeId, name)` 通过 GET `//workflow/export` 下载 `.kbwf` 文件, 只导出工作流,不调用包含文档的知识库包导出接口。 +`importKnowledgeWorkflow(knowledgeId, file)` 沿用 v2 的 POST `//workflow/import`, +使用 FormData 的 `file` 字段上传 `.kbwf`,由服务端覆盖草稿、处理关联工具与默认模型设置。 +接口结果不作为图数据使用,页面确认覆盖后调用,成功重新查询知识库详情并渲染画布。 ### 工作空间首页 @@ -546,8 +549,28 @@ System 接口由资源管理服务提供;本地开源后端没有对应扩展 两种 System 工具 API 的 `getToolListWithShared` 查询各自 `/tool_list` 并合并 `tools`、`shared_tools`, 供画布的工具菜单及 MCP 选项使用。系统扩展接口需连接支持相应协议的部署进行联调。 +### 知识库工作流转换 + +Workspace、System 资源管理及 System 共享资源的 `knowledge.ts` 提供 +`postTransformWorkflow(knowledgeId, { work_flow })`,沿用 v2 的 POST +`//transform_workflow`,各自使用对应知识库前缀,返回布尔值; +转换页通过可管理范围上下文的 `resourceApi.knowledge` 调用,不固定 Workspace API。 +服务端转换知识库类型并创建工作流, +保留已有文档,已是工作流类型时拒绝重复转换。页面负责确认、loading、成功提示及进入画布。 +默认图复用知识库创建模板,不用保存工作流接口代替转换。 + ### 知识库文档 +`workspace/knowledge/document.ts` 的 `getDocumentDetail(knowledgeId, documentId)` 通过 GET +`//document/` 查询文档详情,支持分段页刷新和直接访问。 +`workspace/knowledge/paragraph.ts` 维护普通 Workspace 文档分段接口,前缀为 +`/workspace//knowledge//document//paragraph`。 +`getParagraphList` 查询完整分段列表,支持 `title`、`content`,服务端按 `position`、创建时间排序; +`postParagraph` 提交 `title`、`content`、`is_active`,返回新增分段,默认插入首位并触发索引。 +响应及载荷类型维护在 `types/paragraph.ts`,通过 `@/api/types` 导入。 +标题最多 256 字符,内容必填且最多 102400 字符;loading、弹窗和成功后刷新由页面维护。 +本次只接入普通 Workspace,不为其他范围推测接口或回退 Workspace。 + 文档地址及飞书导入也维护在 `workspace/knowledge/document.ts`: `postWebDocument` 向 `//document/web` 提交 `WebDocumentImportPayload`,包含 `source_url_list`、`selector` 与 `doc_strategy`。 diff --git a/ui/src/api/admin/system/resource-management/knowledge/knowledge.ts b/ui/src/api/admin/system/resource-management/knowledge/knowledge.ts index ca15dd72fec..bb771bfc33e 100644 --- a/ui/src/api/admin/system/resource-management/knowledge/knowledge.ts +++ b/ui/src/api/admin/system/resource-management/knowledge/knowledge.ts @@ -1,4 +1,5 @@ -import { del, get, getExportFile, put } from '@/api/admin/core/request' +import { del, get, getExportFile, post, put } from '@/api/admin/core/request' +import type LogicFlow from '@logicflow/core' import type { ParamsPage, ResponsePage } from '@/api/admin/core/types' import type { Dict, KnowledgeDetail, KnowledgeItem, KnowledgeGeneratePayload, KnowledgeSyncType } from '@/api/types' @@ -67,7 +68,12 @@ const getKnowledgeMcpConfig = (knowledgeId: string): Promise => /** 提交知识库分词索引任务。 */ const putKnowledgeKeywordIndex = (knowledgeId: string) => put(`${prefix}/${knowledgeId}/tokenize`) +/** 将系统资源管理知识库转换为工作流知识库,保留已有文档。 */ +const postTransformWorkflow = (knowledgeId: string, payload: { work_flow: LogicFlow.GraphConfigData }) => + post<{ work_flow: LogicFlow.GraphConfigData }, boolean>(`${prefix}/${knowledgeId}/transform_workflow`, payload) + export default { + postTransformWorkflow, putKnowledgeKeywordIndex, exportKnowledgeExcel, exportKnowledgeZip, diff --git a/ui/src/api/admin/system/shared-resources/knowledge/knowledge.ts b/ui/src/api/admin/system/shared-resources/knowledge/knowledge.ts index 4424f4ef4b1..1b85869418c 100644 --- a/ui/src/api/admin/system/shared-resources/knowledge/knowledge.ts +++ b/ui/src/api/admin/system/shared-resources/knowledge/knowledge.ts @@ -1,4 +1,5 @@ import { del, get, getExportFile, post, put } from '@/api/admin/core/request' +import type LogicFlow from '@logicflow/core' import type { ParamsPage, ResponsePage } from '@/api/admin/core/types' import type { Dict, @@ -83,7 +84,12 @@ const getKnowledgeMcpConfig = (knowledgeId: string): Promise => /** 提交知识库分词索引任务。 */ const putKnowledgeKeywordIndex = (knowledgeId: string) => put(`${prefix}/${knowledgeId}/tokenize`) +/** 将系统共享知识库转换为工作流知识库,保留已有文档。 */ +const postTransformWorkflow = (knowledgeId: string, payload: { work_flow: LogicFlow.GraphConfigData }) => + post<{ work_flow: LogicFlow.GraphConfigData }, boolean>(`${prefix}/${knowledgeId}/transform_workflow`, payload) + export default { + postTransformWorkflow, deleteKnowledge, exportKnowledge, exportKnowledgeExcel, diff --git a/ui/src/api/admin/workspace/knowledge/document.ts b/ui/src/api/admin/workspace/knowledge/document.ts index 1dd6d473a15..113ce9ee1cd 100644 --- a/ui/src/api/admin/workspace/knowledge/document.ts +++ b/ui/src/api/admin/workspace/knowledge/document.ts @@ -26,6 +26,9 @@ const getPrefix = (knowledgeId: string) => `/workspace/${getWorkspaceId()}/knowl const getDocumentPage = (knowledgeId: string, page: ParamsPage, query?: Dict) => get>(`${getPrefix(knowledgeId)}/${page.currentPage}/${page.pageSize}`, query) +/** 获取单个文档详情,支持直接访问分段页。 */ +const getDocumentDetail = (knowledgeId: string, documentId: string) => get(`${getPrefix(knowledgeId)}/${documentId}`) + /** 批量创建空白文档或导入text文档。 */ const putBatchCreateDocuments = (knowledgeId: string, documents: DocumentQuickCreatePayload[] | DocumentImportPayload[]) => put(`${getPrefix(knowledgeId)}/batch_create`, documents) @@ -171,6 +174,7 @@ const putUnlinkTagDocuments = (knowledgeId: string, tagId: string, documentIds: put(`/workspace/${getWorkspaceId()}/knowledge/${knowledgeId}/tag/${tagId}/docs_delete`, { id_list: documentIds }) export default { + getDocumentDetail, getDocumentTags, postAddDocumentTags, putDeleteDocumentTags, diff --git a/ui/src/api/admin/workspace/knowledge/knowledge.ts b/ui/src/api/admin/workspace/knowledge/knowledge.ts index 197f938d5fe..a7fa8630890 100644 --- a/ui/src/api/admin/workspace/knowledge/knowledge.ts +++ b/ui/src/api/admin/workspace/knowledge/knowledge.ts @@ -1,4 +1,5 @@ import { del, get, getExportFile, post, put } from '../../core/request' +import type LogicFlow from '@logicflow/core' import type { ParamsPage, ResponsePage } from '../../core/types' import type { Dict, @@ -125,6 +126,10 @@ const getKnowledgeMcpConfig = (knowledgeId: string): Promise => /** 提交知识库分词索引任务。 */ const putKnowledgeKeywordIndex = (knowledgeId: string) => put(`${getPrefix()}/${knowledgeId}/tokenize`) +/** 将现有知识库转换为工作流知识库,保留已有文档。 */ +const postTransformWorkflow = (knowledgeId: string, payload: { work_flow: LogicFlow.GraphConfigData }) => + post<{ work_flow: LogicFlow.GraphConfigData }, boolean>(`${getPrefix()}/${knowledgeId}/transform_workflow`, payload) + /** 获取知识库按标签名称分组的标签选项。 */ // TODO @@ -153,4 +158,5 @@ export default { putBatchDeleteKnowledge, putBatchMoveKnowledge, postKnowledgeImport, + postTransformWorkflow, } diff --git a/ui/src/api/admin/workspace/knowledge/paragraph.ts b/ui/src/api/admin/workspace/knowledge/paragraph.ts new file mode 100644 index 00000000000..a3de2304e5f --- /dev/null +++ b/ui/src/api/admin/workspace/knowledge/paragraph.ts @@ -0,0 +1,16 @@ +import { get, post } from '../../core/request' +import type { ParagraphCreatePayload, ParagraphItem, ParagraphQuery } from '@/api/types' +import { getWorkspaceId } from '@/utils/resource-context' + +const getPrefix = (knowledgeId: string, documentId: string) => + `/workspace/${getWorkspaceId()}/knowledge/${knowledgeId}/document/${documentId}/paragraph` + +/** 查询文档的全部分段,按位置排序,支持标题和内容筛选。 */ +const getParagraphList = (knowledgeId: string, documentId: string, query?: ParagraphQuery) => + get(getPrefix(knowledgeId, documentId), { ...query }) + +/** 在文档首位新增分段,由服务端触发索引。 */ +const postParagraph = (knowledgeId: string, documentId: string, payload: ParagraphCreatePayload) => + post(getPrefix(knowledgeId, documentId), payload) + +export default { getParagraphList, postParagraph } diff --git a/ui/src/api/admin/workspace/knowledge/workflow.ts b/ui/src/api/admin/workspace/knowledge/workflow.ts index 44030c1332a..e4f366c3fc8 100644 --- a/ui/src/api/admin/workspace/knowledge/workflow.ts +++ b/ui/src/api/admin/workspace/knowledge/workflow.ts @@ -60,6 +60,13 @@ const postCancelKnowledgeWorkflowAction = (knowledgeId: string, actionId: string /** 导出知识库工作流文件,不包含知识库文档。 */ const exportKnowledgeWorkflow = (knowledgeId: string, name: string) => getExportFile(`${name}.kbwf`, `${getPrefix()}/${knowledgeId}/workflow/export`) +/** 导入知识库工作流文件,覆盖当前草稿并由服务端处理关联工具。 */ +const importKnowledgeWorkflow = (knowledgeId: string, file: File) => { + const payload = new FormData() + payload.append('file', file) + return post(`${getPrefix()}/${knowledgeId}/workflow/import`, payload) +} + /** 获取知识库发布历史,按发布时间倒序返回完整版本快照。 */ const getWorkflowVersions = (knowledgeId: string) => get(`${getPrefix()}/${knowledgeId}/knowledge_version`) @@ -72,6 +79,7 @@ const getKnowledgeExecutionRecordPage = (knowledgeId: string, page: ParamsPage, get>(`${getPrefix()}/${knowledgeId}/action/${page.currentPage}/${page.pageSize}`, query) export default { + importKnowledgeWorkflow, getKnowledgeExecutionRecordPage, getWorkflowVersions, putWorkflowVersion, diff --git a/ui/src/api/types/index.ts b/ui/src/api/types/index.ts index 27d2ffa8fd2..c81acc9f77b 100644 --- a/ui/src/api/types/index.ts +++ b/ui/src/api/types/index.ts @@ -30,4 +30,5 @@ export type * from './state' export type * from './portal' export type * from './document' +export type * from './paragraph' export type * from './chat-log' diff --git a/ui/src/api/types/paragraph.ts b/ui/src/api/types/paragraph.ts new file mode 100644 index 00000000000..95428b62771 --- /dev/null +++ b/ui/src/api/types/paragraph.ts @@ -0,0 +1,22 @@ +/** 文档分段的查询响应与新增载荷。 */ +export interface ParagraphItem { + id: string + document_id: string + title: string | null + content: string + position: number + is_active: boolean + create_time: string + update_time: string +} + +export interface ParagraphQuery { + title?: string + content?: string +} + +export interface ParagraphCreatePayload { + title: string + content: string + is_active: boolean +} diff --git a/ui/src/assets/workflow/workflow-demo.png b/ui/src/assets/workflow/workflow-demo.png new file mode 100644 index 00000000000..10385cb617c Binary files /dev/null and b/ui/src/assets/workflow/workflow-demo.png differ diff --git a/ui/src/components/COMPONENT_README.md b/ui/src/components/COMPONENT_README.md index aa7aa357c37..aae6529931d 100644 --- a/ui/src/components/COMPONENT_README.md +++ b/ui/src/components/COMPONENT_README.md @@ -460,6 +460,8 @@ Dialog、Drawer、Popover、嵌套区域等其他大、小表格均禁止开启 `footer-batch-actions` 插槽,当前选择通过 `selection-change` 返回。组件暴露 `tableRef` 和 `clearSelection()`。操作栏与 `MkViewLayout` 复用 `LayoutBatchFooter`,统一全选、半选、数量和 取消行为;它在主内容滚动区域内吸附于页面底部,不随表格内容滚出可视区域。 +分页表格暂不支持跨页勾选,翻页或切换每页条数时统一清空选择,选择列不配置 `reserve-selection`。 +非分页表格不受此限制,可按数据刷新、搜索和懒加载需求保留选择。 `selectionGroupKey` 可按需开启同组选择,接受字段路径或返回字符串/数字的函数;不传时保持 原生逐行选择。点击复选框时,同步当前 `data` 中同组记录的选中或取消状态,遵守选择列的 @@ -1006,7 +1008,7 @@ Skills 场景传入 `[TOOL_TYPE.SKILL]`,并通过 `title` 指定标题。两 缺少时不挂载授权列表。`closed` 在关闭动画结束、临时状态清理后触发;当前没有对外 `refresh` 事件。 默认“按用户组”,支持名称搜索及查看成员;“按用户”支持姓名、用户名、权限及商业版本角色搜索。 -两者支持跨页选择、单项和批量配置,搜索清空选择;切换标签重新挂载,保存期间禁止切换。 +两者支持当前页选择、单项和批量配置,翻页和搜索清空选择;切换标签重新挂载,保存期间禁止切换。 入口统一提交,成功后关闭配置弹窗并刷新当前列表,失败保留配置。 根目录隐藏“不授权”,已有该值按“查看”展示;包含子资源时传入完整文件夹子树, 按资源所属工作空间筛选可管理的文件夹 ID,无可管理目录时禁用该范围。 diff --git a/ui/src/components/business/resource-authorization-drawer/UserAuthorization.vue b/ui/src/components/business/resource-authorization-drawer/UserAuthorization.vue index 07d44375472..12f3759846e 100644 --- a/ui/src/components/business/resource-authorization-drawer/UserAuthorization.vue +++ b/ui/src/components/business/resource-authorization-drawer/UserAuthorization.vue @@ -22,7 +22,7 @@ const emit = defineEmits<{ configure: [subjectIds: string[], permission?: Resour /* 根目录不提供“不授权”,按“查看”展示接口返回的该权限。 */ const canSelectNotAuth = computed(() => props.permissionOptions.some(({ value }) => value === RESOURCE_PERMISSION.NOT_AUTH)) -/* 查询与跨页选择 */ +/* 查询与当前页选择 */ const { auth } = useStore() const searchPermissionOptions = computed(() => RESOURCE_PERMISSION_OPTIONS.filter(({ value }) => !auth.isCE || value !== RESOURCE_PERMISSION.ROLE)) const searchFields = computed(() => [ @@ -114,7 +114,7 @@ onMounted(() => loadPermissions()) @size-change="loadPermissions" @selection-change="handleSelectionChange" > - + diff --git a/ui/src/components/business/resource-authorization-drawer/user-group/UserGroupAuthorization.vue b/ui/src/components/business/resource-authorization-drawer/user-group/UserGroupAuthorization.vue index df790ce3c92..3cd9fbee50e 100644 --- a/ui/src/components/business/resource-authorization-drawer/user-group/UserGroupAuthorization.vue +++ b/ui/src/components/business/resource-authorization-drawer/user-group/UserGroupAuthorization.vue @@ -22,7 +22,7 @@ const emit = defineEmits<{ configure: [subjectIds: string[], permission?: Resour /* 根目录不提供“不授权”,按“查看”展示接口返回的该权限。 */ const canSelectNotAuth = computed(() => props.permissionOptions.some(({ value }) => value === RESOURCE_PERMISSION.NOT_AUTH)) -/* 查询与跨页选择 */ +/* 查询与当前页选择 */ const searchFields = [{ label: '名称', value: 'name' }] const loading = ref(false) const permissionGroups = ref([]) @@ -116,7 +116,7 @@ onMounted(() => loadPermissions()) @size-change="loadPermissions" @selection-change="handleSelectionChange" > - +