diff --git a/packages/core/client/src/application/Application.tsx b/packages/core/client/src/application/Application.tsx index f62e17ab96..9895892263 100644 --- a/packages/core/client/src/application/Application.tsx +++ b/packages/core/client/src/application/Application.tsx @@ -278,6 +278,7 @@ export class Application { api: this.apiClient, i18n: this.i18n, router: this.router.router, + flowEngine: this.flowEngine, }); this.use(FlowEngineProvider, { engine: this.flowEngine }); this.use(FlowEngineGlobalsContextProvider); diff --git a/packages/core/flow-engine/src/components/settings/wrappers/contextual/StepSettingsDialog.tsx b/packages/core/flow-engine/src/components/settings/wrappers/contextual/StepSettingsDialog.tsx index b8c10acd05..9dcef2fcef 100644 --- a/packages/core/flow-engine/src/components/settings/wrappers/contextual/StepSettingsDialog.tsx +++ b/packages/core/flow-engine/src/components/settings/wrappers/contextual/StepSettingsDialog.tsx @@ -7,13 +7,15 @@ * For more information, please refer to: https://www.nocobase.com/agreement. */ -import { createSchemaField, ISchema } from '@formily/react'; -import { message } from 'antd'; +import { FormButtonGroup } from '@formily/antd-v5'; +import { createForm } from '@formily/core'; +import { createSchemaField, FormProvider, ISchema } from '@formily/react'; +import { toJS } from '@formily/reactive'; +import { Button, message, Space } from 'antd'; import React from 'react'; import { StepSettingsDialogProps } from '../../../../types'; -import { resolveDefaultParams, resolveUiSchema, compileUiSchema, getT } from '../../../../utils'; +import { compileUiSchema, getT, resolveDefaultParams, resolveUiSchema } from '../../../../utils'; import { StepSettingContextProvider, StepSettingContextType, useStepSettingContext } from './StepSettingContext'; -import { toJS } from '@formily/reactive'; const SchemaField = createSchemaField(); @@ -32,8 +34,10 @@ const openStepSettingsDialog = async ({ stepKey, dialogWidth = 600, dialogTitle, + mode = 'dialog', }: StepSettingsDialogProps): Promise => { const t = getT(model); + const message = model.flowEngine.context.message; if (!model) { message.error(t('Invalid model provided')); @@ -127,25 +131,47 @@ const openStepSettingsDialog = async ({ }, }; - // 动态导入FormDialog - let FormDialog; - try { - ({ FormDialog } = await import('@formily/antd-v5')); - } catch (error) { - throw new Error(`${t('Failed to import FormDialog')}: ${error.message}`); - } + const view = model.flowEngine.context[mode]; - // 创建FormDialog - const formDialog = FormDialog( - { - title: dialogTitle || `${t(title)} - ${t('Configuration')}`, - width: dialogWidth, - okText: t('OK'), - cancelText: t('Cancel'), - destroyOnClose: true, - }, - (form) => { - // 创建上下文值 + const form = createForm({ + initialValues: compileUiSchema(scopes, initialValues), + }); + + const currentDialog = view.open({ + title: dialogTitle || t(title), + width: dialogWidth, + destroyOnClose: true, + footer: ( + + + + + ), + content: (currentDialog) => { const contextValue: StepSettingContextType = { model, globals: model.flowEngine?.context || {}, @@ -155,45 +181,22 @@ const openStepSettingsDialog = async ({ flowKey, stepKey, }; - // 编译 formSchema 中的表达式 const compiledFormSchema = compileUiSchema(scopes, formSchema); - return ( - - - + + + + + ); }, - ); - - // 设置保存回调 - formDialog.forConfirm(async (payload, next) => { - try { - // 获取表单当前值 - const currentValues = payload.values; - model.setStepParams(flowKey, stepKey, currentValues); - await model.save(); - message.success(t('Configuration saved')); - next(payload); - } catch (error) { - console.error(t('Error saving configuration'), ':', error); - message.error(t('Error saving configuration, please check console')); - throw error; - } - }); - - formDialog.forCancel(async (payload, next) => next(payload)); - - // 打开对话框 - return formDialog.open({ - initialValues: compileUiSchema(scopes, initialValues), }); }; diff --git a/packages/core/flow-engine/src/components/settings/wrappers/contextual/StepSettingsDrawer.tsx b/packages/core/flow-engine/src/components/settings/wrappers/contextual/StepSettingsDrawer.tsx index 1d0811379e..71c8fcaa30 100644 --- a/packages/core/flow-engine/src/components/settings/wrappers/contextual/StepSettingsDrawer.tsx +++ b/packages/core/flow-engine/src/components/settings/wrappers/contextual/StepSettingsDrawer.tsx @@ -6,17 +6,8 @@ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License. * For more information, please refer to: https://www.nocobase.com/agreement. */ - -import { createSchemaField, ISchema } from '@formily/react'; -import { message, Button, Space } from 'antd'; -import React, { useState } from 'react'; -import { useTranslation } from 'react-i18next'; import { StepSettingsDrawerProps } from '../../../../types'; -import { resolveDefaultParams, resolveUiSchema, compileUiSchema, getT } from '../../../../utils'; -import { StepSettingContextProvider, StepSettingContextType, useStepSettingContext } from './StepSettingContext'; -import { toJS } from '@formily/reactive'; - -const SchemaField = createSchemaField(); +import { openStepSettingsDialog } from './StepSettingsDialog'; /** * StepSettingsDrawer组件 - 使用自定义 Drawer 显示单个步骤的配置界面 @@ -27,230 +18,8 @@ const SchemaField = createSchemaField(); * @param props.drawerTitle 自定义抽屉标题,默认使用step的title * @returns Promise 返回表单提交的值 */ -const openStepSettingsDrawer = async ({ - model, - flowKey, - stepKey, - drawerWidth = 600, - drawerTitle, -}: StepSettingsDrawerProps): Promise => { - const t = getT(model); - - if (!model) { - message.error(t('Invalid model provided')); - throw new Error(t('Invalid model provided')); - } - - // 获取流程和步骤信息 - const flow = model.getFlow(flowKey); - const step = flow?.steps?.[stepKey]; - - if (!flow) { - message.error(t('Flow with key {{flowKey}} not found', { flowKey })); - throw new Error(t('Flow with key {{flowKey}} not found', { flowKey })); - } - - if (!step) { - message.error(t('Step with key {{stepKey}} not found', { stepKey })); - throw new Error(t('Step with key {{stepKey}} not found', { stepKey })); - } - - let title = step.title; - - // 创建参数解析上下文 - const paramsContext = { - model, - globals: model.flowEngine?.context || {}, - app: model.flowEngine?.context?.app, - }; - - const stepUiSchema = step.uiSchema || {}; - let actionDefaultParams = {}; - - // 如果step使用了action,也获取action的uiSchema - let actionUiSchema = {}; - if (step.use) { - const action = model.flowEngine?.getAction?.(step.use); - if (action && action.uiSchema) { - actionUiSchema = action.uiSchema; - } - actionDefaultParams = action.defaultParams || {}; - title = title || action.title; - } - - // 解析动态 uiSchema - const resolvedActionUiSchema = await resolveUiSchema(actionUiSchema, paramsContext); - const resolvedStepUiSchema = await resolveUiSchema(stepUiSchema, paramsContext); - - // 合并uiSchema,确保step的uiSchema优先级更高 - const mergedUiSchema = { ...toJS(resolvedActionUiSchema) }; - Object.entries(toJS(resolvedStepUiSchema)).forEach(([fieldKey, schema]) => { - if (mergedUiSchema[fieldKey]) { - mergedUiSchema[fieldKey] = { ...mergedUiSchema[fieldKey], ...schema }; - } else { - mergedUiSchema[fieldKey] = schema; - } - }); - - // 如果没有可配置的UI Schema,显示提示 - if (Object.keys(mergedUiSchema).length === 0) { - message.info(t('This step has no configurable parameters')); - return {}; - } - - // 获取初始值 - const stepParams = model.getStepParams(flowKey, stepKey) || {}; - - const flowEngine = model.flowEngine; - const scopes = { - useStepSettingContext, - ...flowEngine.flowSettings?.scopes, - }; - - // 解析 defaultParams - const resolvedDefaultParams = await resolveDefaultParams(step.defaultParams, paramsContext); - const resolveActionDefaultParams = await resolveDefaultParams(actionDefaultParams, paramsContext); - const initialValues = { ...toJS(resolveActionDefaultParams), ...toJS(resolvedDefaultParams), ...toJS(stepParams) }; - - // 构建表单Schema - const formSchema: ISchema = { - type: 'object', - properties: { - layout: { - type: 'void', - 'x-component': 'FormLayout', - 'x-component-props': { - layout: 'vertical', - }, - properties: mergedUiSchema, - }, - }, - }; - - // 动态导入Formily组件 - let Form, createForm; - try { - ({ Form } = await import('@formily/antd-v5')); - ({ createForm } = await import('@formily/core')); - } catch (error) { - throw new Error(`${t('Failed to import Formily components')}: ${error.message}`); - } - - // 获取drawer API - const drawer = model.flowEngine?.context?.drawer; - if (!drawer) { - throw new Error(t('Drawer API is not available, please ensure it is used within FlowEngineGlobalsContextProvider')); - } - - return new Promise((resolve) => { - // 用于跟踪Promise状态,避免重复调用resolve - let isResolved = false; - - // 创建表单实例 - const form = createForm({ - initialValues: compileUiSchema(scopes, initialValues), - }); - - // 创建抽屉内容组件 - const DrawerContent: React.FC = () => { - const { t } = useTranslation(); - const [loading, setLoading] = useState(false); - - const handleSubmit = async () => { - try { - setLoading(true); - - // 先获取表单当前值,然后验证 - const currentValues = form.values; - await form.validate(); - - // 保存配置 - model.setStepParams(flowKey, stepKey, currentValues); - await model.save(); - - message.success(t('Configuration saved')); - isResolved = true; - drawerRef.destroy(); - resolve(currentValues); - } catch (error) { - console.error(t('Error saving configuration'), ':', error); - message.error(t('Error saving configuration, please check console')); - } finally { - setLoading(false); - } - }; - - const handleCancel = () => { - if (!isResolved) { - isResolved = true; - resolve(null); - } - drawerRef.destroy(); - }; - - // 创建上下文值 - const contextValue: StepSettingContextType = { - model, - globals: model.flowEngine?.context || {}, - app: model.flowEngine?.context?.app, - step, - flow, - flowKey, - stepKey, - }; - - // 编译 formSchema 中的表达式 - const compiledFormSchema = compileUiSchema(scopes, formSchema); - - return ( -
-
-
- - - -
-
-
- - - - -
-
- ); - }; - - // 打开抽屉 - const drawerRef = drawer.open({ - title: drawerTitle || `${t(title)} - ${t('Configuration')}`, - width: drawerWidth, - content: , - onClose: () => { - // 只有在Promise还未被处理时才reject - if (!isResolved) { - isResolved = true; - resolve(null); - } - }, - }); - }); +const openStepSettingsDrawer = async (options: StepSettingsDrawerProps): Promise => { + return openStepSettingsDialog({ ...options, mode: 'drawer' }); }; export { openStepSettingsDrawer }; diff --git a/packages/core/flow-engine/src/types.ts b/packages/core/flow-engine/src/types.ts index f732200f87..c8c5663ee5 100644 --- a/packages/core/flow-engine/src/types.ts +++ b/packages/core/flow-engine/src/types.ts @@ -263,6 +263,7 @@ export interface StepSettingsDialogProps { stepKey: string; dialogWidth?: number | string; dialogTitle?: string; + mode?: 'dialog' | 'drawer'; // 设置模式,默认为'dialog' } /** diff --git a/packages/core/flow-engine/src/views/DrawerComponent.tsx b/packages/core/flow-engine/src/views/DrawerComponent.tsx index 35d1face3a..37b423d2d8 100644 --- a/packages/core/flow-engine/src/views/DrawerComponent.tsx +++ b/packages/core/flow-engine/src/views/DrawerComponent.tsx @@ -34,6 +34,13 @@ const DrawerComponent = forwardRef(({ afterClose, setVisible(false); config.onClose?.(e); }} + styles={{ + ...config?.styles, + footer: { + textAlign: 'end', + ...config?.styles?.footer, + }, + }} afterOpenChange={(open) => { if (!open) { afterClose?.();