/** * This file is part of the NocoBase (R) project. * Copyright (c) 2020-2024 NocoBase Co., Ltd. * Authors: NocoBase Team. * * 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 { Alert, Form, Input, InputNumber, Select, Switch } from 'antd'; import React, { useCallback, useEffect, useState } from 'react'; import { FlowRuntimeContext } from '../../../../flowContext'; import { useFlowModelById } from '../../../../hooks'; import { FlowModel } from '../../../../models'; import { resolveDefaultParams, setupRuntimeContextSteps, shouldHideStepInSettings } from '../../../../utils'; import { observer } from '../../../../reactive'; const { Item: FormItem } = Form; // 创建两个组件版本,一个使用props传递的model,一个使用hook获取model interface ModelProvidedProps { model: FlowModel; flowKey: string; } interface ModelByIdProps { uid: string; flowKey: string; modelClassName: string; } type FlowSettingsProps = ModelProvidedProps | ModelByIdProps; // 判断是否是通过ID获取模型的props const isModelByIdProps = (props: FlowSettingsProps): props is ModelByIdProps => { return 'uid' in props && 'modelClassName' in props && Boolean(props.uid) && Boolean(props.modelClassName); }; /** * FlowSettings组件 - 单个流程的详细配置表单(embedded版本) * * 特点: * - 实时保存到model * - 适用于嵌入式配置界面 * * 支持两种使用方式: * 1. 直接提供model: * 2. 通过uid和modelClassName获取model: */ const FlowSettings: React.FC = (props) => { if (isModelByIdProps(props)) { return ; } else { return ; } }; // 使用传入的model const FlowSettingsWithModel: React.FC = observer(({ model, flowKey }) => { if (!model) { return ; } return ; }); // 通过useModelById hook获取model const FlowSettingsWithModelById: React.FC = observer(({ uid, flowKey, modelClassName }) => { const model = useFlowModelById(uid, modelClassName); if (!model) { return ; } return ; }); // 提取核心渲染逻辑到一个共享组件 interface FlowSettingsContentProps { model: FlowModel; flowKey: string; } const FlowSettingsContent: React.FC = observer(({ model, flowKey }) => { const [form] = Form.useForm(); // 获取流程定义 const flows = model.getFlows(); const flow = flows.get(flowKey); const [configurableSteps, setConfigurableSteps] = useState<{ stepKey: string; step: any; uiSchema: any }[]>([]); // 获取可配置的步骤(支持动态 hideInSettings) useEffect(() => { let mounted = true; const buildConfigurableSteps = async () => { const steps: { stepKey: string; step: any; uiSchema: any }[] = []; for (const [stepKey, actionStep] of Object.entries(flow?.steps || {})) { if (await shouldHideStepInSettings(model, flow, actionStep as any)) { continue; } // 从step获取uiSchema(如果存在) const stepUiSchema = actionStep.uiSchema || {}; // 如果step使用了action,也获取action的uiSchema let actionUiSchema = {}; if (actionStep.use) { const action = model.flowEngine?.getAction?.(actionStep.use); if (action && action.uiSchema) { actionUiSchema = action.uiSchema; } } // 合并uiSchema,确保step的uiSchema优先级更高 const mergedUiSchema = { ...actionUiSchema }; // 将stepUiSchema中的字段合并到mergedUiSchema Object.entries(stepUiSchema).forEach(([fieldKey, schema]) => { if (mergedUiSchema[fieldKey]) { mergedUiSchema[fieldKey] = { ...mergedUiSchema[fieldKey], ...schema }; } else { mergedUiSchema[fieldKey] = schema; } }); // 如果没有可配置的UI Schema,跳过 if (Object.keys(mergedUiSchema).length === 0) { continue; } steps.push({ stepKey, step: actionStep, uiSchema: mergedUiSchema }); } if (mounted) { setConfigurableSteps(steps); } }; buildConfigurableSteps(); return () => { mounted = false; }; }, [model, flow]); // 获取当前流程的参数 - 从model中获取实际参数 const getCurrentParams = useCallback(async () => { const params = {}; // 从model中获取每个步骤的参数,如果为空则使用默认参数 for (const { stepKey, step } of configurableSteps) { const stepParams = model.getStepParams(flowKey, stepKey) || {}; const flowRuntimeContext = new FlowRuntimeContext(model, flowKey, 'settings'); const flow = model.getFlow(flowKey); setupRuntimeContextSteps(flowRuntimeContext, flow?.steps || {}, model, flowKey); // 解析 defaultParams const resolvedDefaultParams = await resolveDefaultParams(step.defaultParams, flowRuntimeContext); // 合并默认参数和当前参数,当前参数优先 const mergedParams = { ...resolvedDefaultParams, ...stepParams }; if (Object.keys(mergedParams).length > 0) { params[stepKey] = mergedParams; } } return params; }, [model, flowKey, configurableSteps]); // 初始化表单值 useEffect(() => { const loadParams = async () => { try { const currentParams = await getCurrentParams(); form.setFieldsValue(currentParams); } catch (error) { console.error('Error loading default params:', error); } }; loadParams(); }, [flowKey, form, getCurrentParams]); // 处理表单值变化 - 实时保存 const handleValuesChange = useCallback( (changedValues: any, allValues: any) => { // 实时保存到model Object.entries(allValues).forEach(([stepKey, stepValues]: [string, any]) => { if (stepValues && typeof stepValues === 'object') { // 使用setStepParams保存步骤参数 model.setStepParams(flowKey, stepKey, stepValues); } }); }, [model, flowKey], ); if (!flow) { return ; } if (configurableSteps.length === 0) { return ; } // 渲染表单字段 const renderFormFields = () => { return configurableSteps.map(({ stepKey, uiSchema }) => { return Object.entries(uiSchema).map(([fieldKey, schema]: [string, any]) => { const fieldName = `${stepKey}.${fieldKey}`; // 根据schema类型渲染不同的组件 const renderField = () => { switch (schema['x-component']) { case 'Select': return ( ); } }; return ( {renderField()} ); }); }); }; return (
{renderFormFields()}
); }); export { FlowSettings };