diff --git a/ui/src/components/COMPONENT_README.md b/ui/src/components/COMPONENT_README.md index 8853ea593c3..ef210d90b5a 100644 --- a/ui/src/components/COMPONENT_README.md +++ b/ui/src/components/COMPONENT_README.md @@ -762,6 +762,17 @@ JSON 专用输入框,通过 `v-model` 接收并回传解析后的 JSON 值, 表单配置加载、字段联动请求与 Tree 懒加载的 loading 由组件在请求前开启,并在 `finally` 中释放; 不向 API 请求方法传递 loading,动态请求脚本也不再通过 `extra.loading` 获取状态。 +动态表单 `Tree` 字段使用 `MkTable` 展示文档与文件夹,复用原生复选列、全选和父子选择联动。 +保留 `text_field`、`value_field`、`childrenField` 映射,选中值仍为原始节点对象数组; +已导入节点自动选中且不可取消,`disabled` 节点不可选择。懒加载先查询根目录,展开时通过 +原有工具数据源接口提交 `current_node` 查询子节点;非懒加载使用 `option_list`。 + +动态表单 `LocalFileUpload` 字段复用 `MkDragUpload` 的多文件模式,将 +`file_type_list`、`file_size_limit`、`file_count_limit` 映射为格式、大小和数量限制。 +上传适配兼容上层返回的 Promise 或 `{ request, abort }`,响应支持地址字符串或 `{ data: 地址 }`; +文件夹选择、进度、失败重试、取消和成功文件删除由 `MkDragUpload` 维护,文件值采用 +`DragUploadFile[]`,失败状态为 `fail`。 + `MkDynamicsForm` 根据字段配置渲染动态表单,统一维护字段值、默认值、显隐规则和表单校验; `MkDynamicsFormConstructor` 用于新增或编辑单个字段配置。该组件族位于 `components` 直属目录, 使用方必须从 `@/components/mk-dynamics-form` 手动导入,不安装为 Vue 插件,也不全局注册其内部 diff --git a/ui/src/components/mk-dynamics-form/items/tree/Tree.vue b/ui/src/components/mk-dynamics-form/items/tree/Tree.vue index d4d0dc45181..1e8b0d28d59 100644 --- a/ui/src/components/mk-dynamics-form/items/tree/Tree.vue +++ b/ui/src/components/mk-dynamics-form/items/tree/Tree.vue @@ -1,149 +1,167 @@ - - - - - - - - - - - - - - - - - - - - - - {{ node.label }} - - - - - - + + + + + + + + + + {{ row[textField] }} + + + + diff --git a/ui/src/components/mk-dynamics-form/items/upload/LocalFileUpload.vue b/ui/src/components/mk-dynamics-form/items/upload/LocalFileUpload.vue index 1c040a881c1..6359644eb23 100644 --- a/ui/src/components/mk-dynamics-form/items/upload/LocalFileUpload.vue +++ b/ui/src/components/mk-dynamics-form/items/upload/LocalFileUpload.vue @@ -1,274 +1,57 @@ - - - - - - - - - 将文件拖到此处,或 - 点击上传 - 选择文件夹 - - - 单次上传最多 {{ fileCountLimit }} 个文件, 每个文件最大 {{ fileSizeLimit }} MB - 支持格式:{{ formats }} - - - - - 已完成 {{ successCount }} / {{ fileArray.length }} 个文件 - - - 上传中 - - - - 失败 {{ errorCount }} 个文件 - - - 重试 - - - - - 全部成功 - - - - - - - - - - - {{ item && item?.name }} - - - {{ formatFileSize((item.size * item.percentage) / 100) }} / - {{ formatFileSize(item.size) || '0K' }} - - {{ formatFileSize(item && item?.size) || '0K' }} - - - {{ item.errMsg }} - - - - - - - - - - - - - - - - - - + diff --git a/ui/src/views/VIEW_README.md b/ui/src/views/VIEW_README.md index ca89b111b11..267840b44c2 100644 --- a/ui/src/views/VIEW_README.md +++ b/ui/src/views/VIEW_README.md @@ -1117,7 +1117,8 @@ Web、飞书和工作流知识库的非共享文档页在标题栏组合 Web 和飞书使用全屏底部 Drawer,分别通过地址表单和飞书 `MkTable` 懒加载目录表格进入文档处理策略; 策略复用 `DocumentStrategyForm`,使用组件默认策略,不回显知识库策略,上一步保留草稿。 Web 抽屉只接收完整 Document API 与知识库 ID,地址和选择器初始为空; -飞书抽屉额外接收文件夹 Token,工作流抽屉只接收知识库 ID 和图数据;所有导入组件均不接收 `KnowledgeDetail`。 +飞书抽屉额外接收文件夹 Token,工作流抽屉只通过 Prop 接收知识库 ID,图数据在打开时通过 +`open(workflow)` 传入并保存在抽屉本地;所有导入组件均不接收 `KnowledgeDetail`。 Web 地址按行去空白、去重并校验 HTTP/HTTPS;空选择器提交 `body`。 飞书按 `meta.folder_token` 查询目录并读取全部分页,已导入文档勾选且不可重复导入; 表格使用原生 `type="selection"` 选择列和名称列,表头全选覆盖当前已加载节点; diff --git a/ui/src/views/knowledge-detail/library/document/import-document/ButtonImportDocument.vue b/ui/src/views/knowledge-detail/library/document/import-document/ButtonImportDocument.vue index 60376231f08..09220699cf4 100644 --- a/ui/src/views/knowledge-detail/library/document/import-document/ButtonImportDocument.vue +++ b/ui/src/views/knowledge-detail/library/document/import-document/ButtonImportDocument.vue @@ -1,5 +1,5 @@ @@ -52,12 +47,28 @@ function handleOpenImport() { 导入文档 - + + diff --git a/ui/src/views/knowledge-detail/library/document/import-document/WorkflowImportDocumentDrawer.vue b/ui/src/views/knowledge-detail/library/document/import-document/WorkflowImportDocumentDrawer.vue index 4d69488da4f..416005faf21 100644 --- a/ui/src/views/knowledge-detail/library/document/import-document/WorkflowImportDocumentDrawer.vue +++ b/ui/src/views/knowledge-detail/library/document/import-document/WorkflowImportDocumentDrawer.vue @@ -14,7 +14,7 @@ import Result from '@/views/workflow/knowledge/debug/action/Result.vue' import { MsgWarning } from '@/utils/message' defineOptions({ name: 'WorkflowImportDocumentDrawer' }) -const props = defineProps<{ knowledgeId: string; workflow?: LogicFlow.GraphConfigData }>() +const props = defineProps<{ knowledgeId: string }>() const emit = defineEmits<{ refresh: []; closed: [] }>() /* 复用工作流 Action,上传适配保留进度、取消和上传中保护。 */ @@ -43,18 +43,25 @@ provide('delFile', FileApi.deleteFile) type ActionStep = 'data_source' | 'knowledge_base' | 'result' const actionComponents: Record = { data_source: DataSource, knowledge_base: KnowledgeBase, result: Result } const visible = ref(false) +const currentWorkflow = ref(null) const loading = ref(false) const active = ref('data_source') +const activeStep = computed(() => ({ data_source: 0, knowledge_base: 1, result: 2 })[active.value]) const actionKey = ref(0) const actionId = ref() const formPayload = ref({ data_source: {}, knowledge_base: {} }) const actionRef = useTemplateRef<{ validate: () => Promise; getData: () => Dict }>('actionRef') -const hasKnowledgeBaseInput = computed(() => { - const node = props.workflow?.nodes?.find((node) => node.type === WorkflowNodeType.KnowledgeBase) - return ((node?.properties?.user_input_field_list as FormField[] | undefined)?.length ?? 0) > 0 -}) +const knowledgeBaseNode = computed(() => currentWorkflow.value?.nodes?.find((node) => node.type === WorkflowNodeType.KnowledgeBase)) +const hasKnowledgeBaseInput = computed( + () => ((knowledgeBaseNode.value?.properties?.user_input_field_list as FormField[] | undefined)?.length ?? 0) > 0, +) +const userInputTitle = computed(() => knowledgeBaseNode.value?.properties?.user_input_config?.title || '用户输入') +const showNext = computed(() => hasKnowledgeBaseInput.value && active.value === 'data_source') +const showPrev = computed(() => hasKnowledgeBaseInput.value && active.value === 'knowledge_base') +const showImport = computed(() => (hasKnowledgeBaseInput.value ? active.value === 'knowledge_base' : active.value === 'data_source')) const busy = computed(() => loading.value || uploadingCount.value > 0) -function open() { +function open(workflow?: LogicFlow.GraphConfigData) { + currentWorkflow.value = workflow ?? null visible.value = true } function getActionData() { @@ -127,22 +134,22 @@ defineExpose({ open }) - + @@ -152,23 +159,15 @@ defineExpose({ open }) 取消 - 继续导入 + 继续导入 - 上一步 - - 下一步 + 上一步 + + 下一步 - - 导入 - + 开始导入 - 完成 + 前往文档 diff --git a/ui/src/views/workflow/knowledge/debug/DebugDrawer.vue b/ui/src/views/workflow/knowledge/debug/DebugDrawer.vue index 7a9bb256797..32218eb7dfb 100644 --- a/ui/src/views/workflow/knowledge/debug/DebugDrawer.vue +++ b/ui/src/views/workflow/knowledge/debug/DebugDrawer.vue @@ -1,10 +1,14 @@ - - - - + + + - - 继续导入 - 上一步 - 下一步 - 导入 - 完成 - + + 取消 + + 继续导入 + + 上一步 + + 下一步 + + 开始导入 + + 前往文档 diff --git a/ui/src/views/workflow/knowledge/debug/action/DataSource.vue b/ui/src/views/workflow/knowledge/debug/action/DataSource.vue index 0606e31bcaf..1cc9fed27c1 100644 --- a/ui/src/views/workflow/knowledge/debug/action/DataSource.vue +++ b/ui/src/views/workflow/knowledge/debug/action/DataSource.vue @@ -1,6 +1,5 @@ @@ -108,24 +108,23 @@ defineExpose({ validate, getData }) require-asterisk-position="right" > - 选择数据源 - - - + 选择数据源 + + + - + {{ node.properties.stepName }} - - + + diff --git a/ui/src/views/workflow/knowledge/debug/action/KnowledgeBase.vue b/ui/src/views/workflow/knowledge/debug/action/KnowledgeBase.vue index fc4a81b607a..e548d82d94a 100644 --- a/ui/src/views/workflow/knowledge/debug/action/KnowledgeBase.vue +++ b/ui/src/views/workflow/knowledge/debug/action/KnowledgeBase.vue @@ -38,7 +38,7 @@ defineExpose({ validate, getData }) - {{ chatTitle }} + {{ chatTitle }} diff --git a/ui/src/views/workflow/knowledge/debug/action/Result.vue b/ui/src/views/workflow/knowledge/debug/action/Result.vue index 08936be67c9..759f083eea9 100644 --- a/ui/src/views/workflow/knowledge/debug/action/Result.vue +++ b/ui/src/views/workflow/knowledge/debug/action/Result.vue @@ -15,7 +15,9 @@ const POLL_INTERVAL = 2000 const knowledgeAction = ref() const state = computed(() => knowledgeAction.value?.state ?? 'PENDING') -const detail = computed(() => (knowledgeAction.value ? (Object.values(knowledgeAction.value.details) as ExecutionNodeDetail[]) : [])) +const detail = computed(() => + knowledgeAction.value ? (Object.values(knowledgeAction.value.details) as ExecutionNodeDetail[]) : [], +) let pollingTimer: ReturnType | null = null @@ -53,7 +55,7 @@ onUnmounted(stopPolling) - 执行详情 + 执行结果
- 将文件拖到此处,或 - 点击上传 - 选择文件夹 -
单次上传最多 {{ fileCountLimit }} 个文件, 每个文件最大 {{ fileSizeLimit }} MB
支持格式:{{ formats }}
{{ item && item?.name }}