UNPKG

@cainiaofe/cn-ui-lowcode

Version:
1,503 lines (1,455 loc) 56 kB
import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState, } from 'react'; import { CnButton, CnDynamicForm, CnForm as UICnForm, CnFormTab, CnPageFooter, createCnFormStepInstance, formilyCore, formilyReact, } from '@cainiaofe/cn-ui'; import { componentMap, getFormExtraComponents, } from '@/common/manager/filter-item'; import { toJS } from '@formily/reactive'; import { calculateTextExprValue, calculateWaitComponentList, executeEventWithoutJS, executeFunction, executeObjectExpr, getAllRunTimeBizComponentMap, getArrayTableCurrentRowByField2, getLastListCurrentRowByField, getFormDefaultValue, getRealizeValue, getRunTimeItem, isArrayNotEmpty, isDesignMode, isEmptyButNotZero, isRecursionComponent, makeFormItemSchema, renderIcon, transProxyToObject, } from '@/common/util/util'; import isPlainObject from 'lodash/isPlainObject'; // import isEqual from 'lodash/isEqual'; import isEqualWith from 'lodash/isEqualWith'; import cloneDeep from 'lodash/cloneDeep'; import cloneDeepWith from 'lodash/cloneDeepWith'; import { getButtonAction, getItem as getButtonItem, } from '@/common/manager/button'; import { ButtonPosition } from '@/common/manager/position/button-position'; import { columnSuffix, dataOriginStatic } from '@/common/util/const'; import get from 'lodash/get'; import merge from 'lodash/merge'; import isNaN from 'lodash/isNaN'; import isFunction from 'lodash/isFunction'; import isUndefined from 'lodash/isUndefined'; import uniq from 'lodash/uniq'; import './view.scss'; import { getRealResponse, handleResultProcessFunc, makeRequest, transRequestConfigToRemote, } from '@/common/util/request'; import { __arrayTableCurrentRow__, __dataSource__, __extraParam__, __filterValue__, __formValue__, __stateValueOfSplit__, } from '@/common/util/expr-const'; import isEmpty from 'lodash/isEmpty'; import { generateEffects } from '@alife/reactions-builder'; import { _getFormValues } from '@/common/util/biz-component-prop-name'; import { useFooterAutoWidth } from '@/common/hook/useFooterAutoWidth'; const CnCard = 'CnCard'; const CnCardSubCard = 'CnCardSubCard'; const CnFormStepItem = 'CnFormStepItem'; const CnFormTabItem = 'CnFormTabItem'; const CnFormGrid = 'CnFormGrid'; const Compose = 'Compose'; const { createForm, onFormValuesChange, onFieldValueChange, onFieldReact, onFieldInputValueChange, onFieldChange, onFieldInitialValueChange, onFieldInit } = formilyCore || {}; const { Observer } = formilyReact || {}; // const { observer } = formilyReact const dynamic_form_effects = 'dynamic_form_effects'; export const CnForm = forwardRef((props, ref) => { const cacheFormTabInstance = useRef({}); const { config: originalConfig, formInstance: parentFormInstance, _context, _dataSourceName, _dataSource, onCreateForm, formStyle, isCnForm, buttons = [], defaultParams, dynamicConfig = {}, dynamicFormConfig = {}, cnFormStepConfig, handleProps, _nodeId, events, __bizExtendConfig__, beta, } = props; let usedComponentList = []; if(__bizExtendConfig__?.shouldToGenereateSchemaByConfigChange) { usedComponentList = useGetUsedComponentList(); } const footerId = `form-footer-${_nodeId}`; const containerId = `form-${_nodeId}`; useFooterAutoWidth({ footerId, containerId, }); const { cols, readOnly: formReadOnly, labelAlign, isAnchorForm, headingLevel, mode, } = formStyle || {}; const [forceUpdate, setForceUpdate] = useState(false); const isFormReadOnly = executeObjectExpr( formReadOnly, { [__formValue__]: {}, [__filterValue__]: {}, [__dataSource__]: _context?.state, [__extraParam__]: { openDialogMode: get( _context?.state?.valueOf, `${_dataSourceName}${__stateValueOfSplit__}openDialogMode`, ), }, }, {}, _context?.state, ); // 记录默认值请求需要等待哪些组件请求完成 const waitComponentList = useRef([]); const waitComponentMap = useRef({}); const configMap = useRef({}); const isDesign = isDesignMode(props); const formInstance = useRef(null); const initialValueUtil = useInitialValue(formInstance); const formStepInstance = useMemo(() => { const { current = 0 } = cnFormStepConfig || {}; const defaultCurrent = calculateTextExprValue(current, { recordDataSource: {}, state: _context?.state, }); return createCnFormStepInstance?.(defaultCurrent || 0); }, []); const formTabInstance = useMemo(() => { return CnFormTab?.createCnFormTab?.(); }, []); const formRef = useRef(null); const urlParams = _context?.state?.urlParams || {}; const oldSchema = useRef(null); const oldConfig = useRef(null); const oldFormReadOnly = useRef(isFormReadOnly); let firstFormStep; let isFormStep = false; let isFormTab = false; let firstFormTabIndex = 0; if (isArrayNotEmpty(originalConfig)) { for (const index in originalConfig) { const item = originalConfig[index]; if (item?.componentName === CnFormStepItem) { firstFormStep = item; isFormStep = true; break; } else if (item?.componentName === CnFormTabItem) { isFormTab = true; firstFormTabIndex = +index; break; } } } const [config, setConfig] = useState(originalConfig); useEffect(()=>{ if(beta) { const equal = isEqualWith(originalConfig, config, (objValue, othValue) => { if (objValue instanceof Function && othValue instanceof Function) { return true; } }) if(!equal) { setConfig(originalConfig) } } },[originalConfig]) if (isFunction(defaultParams?.dataOrigin)) { defaultParams.dataOrigin = executeFunction( defaultParams.dataOrigin, {}, _context?.state, ); } const { deferRender, dataOrigin } = defaultParams || {}; const [defer, setDefer] = useState( deferRender === true && dataOrigin === 'request', ); const getFormValue = useCallback(() => { if (typeof _dataSource === 'object') { return transProxyToObject(_dataSource); } return null; }, []); const componentRequestFinish = useCallback((tempConfig) => { const { name, dataSource } = tempConfig || {}; if ( name && isArrayNotEmpty(dataSource) && waitComponentList.current?.includes(name) ) { waitComponentList.current = waitComponentList.current.filter( (item) => item !== name, ); const currentConfig = configMap?.current?.[name]; const current = waitComponentMap?.current?.[name]; const temp = dataSource?.[current.value]; let realValue = temp?.value; if (currentConfig?.options?.mode === 'multiple') { if (isEmptyButNotZero(realValue)) { realValue = []; } else { realValue = [realValue]; } } formInstance?.current?.setInitialValues({ [name]: realValue, }); } }, []); // 设计态默认值的兼容逻辑 if (isDesign === true) { if (dataOrigin === dataOriginStatic) { let tempDefaultValue = getFormDefaultValue(defaultParams, { urlParamsDataSource: urlParams, state: _context?.state, isDesign, formConfig: config, }); if (isArrayNotEmpty(config)) { config.forEach((item) => { if (item?.name && item?.componentName) { if (item.componentName === 'CnArraySubAreaCard') { if (!isPlainObject(tempDefaultValue)) { tempDefaultValue = {}; } if (!tempDefaultValue[item.name]) { tempDefaultValue[item.name] = [{}]; } } } }); } if (isPlainObject(tempDefaultValue)) { formInstance?.current?.setValues?.(tempDefaultValue, 'overwrite'); } } } useImperativeHandle(ref, () => ({ load() { getRemoteDefaultValue(); }, getFormInstance() { return formInstance.current; }, getFormRef() { return formRef?.current; }, reRender() { reRender(); }, })); const registerDynamicFormEffects = useCallback((effectConfig) => { const { ins, dynamic } = effectConfig || {}; if ( ins && dynamic?.active === true && Array.isArray(dynamic?.reactions) && dynamic?.reactions.length > 0 ) { ins.removeEffects(dynamic_form_effects); ins.addEffects(dynamic_form_effects, () => { generateEffects(dynamic?.reactions, { state: _context?.state }); }); ins?.onInit?.(); } }, []); useEffect(() => { const { requestConfig } = dynamicConfig || {}; if (isPlainObject(requestConfig) && requestConfig.url) { makeRequest({ buttonConfig: { options: { requestConfig, }, }, state: _context?.state, needSuccessToast: false, isDesign, urlParamsDataSource: urlParams, }).then((res) => { if (res) { const newRes = getRealResponse(res); const { success, data } = newRes || {}; if (success && Array.isArray(data) && data.length > 0) { setConfig(data); } } getRemoteDefaultValue({ setInitialValue: true }); }); } else { getRemoteDefaultValue({ setInitialValue: true }); } return () => { if (_dataSourceName) { const temp = _context?.state?.[_dataSourceName]; if (isPlainObject(temp) && !isEmpty(temp)) { _context?.setState({ [_dataSourceName]: {}, }); } } }; }, []); useEffect(() => { if (!dynamicConfig?.requestConfig?.url && isDesign) { setConfig(originalConfig); } }, dynamicConfig?.requestConfig?.url); const getRemoteDefaultValue = (rconfig) => { const { setInitialValue } = rconfig || {}; const { dataOrigin, requestConfig = {}, afterRequest = {}, } = defaultParams || {}; const formValue = formInstance?.current?.values; if (dataOrigin === 'request') { const p = getFormDefaultValue(defaultParams, { urlParamsDataSource: urlParams, state: _context?.state, isDesign, formConfig: config, getExtraParam: () => { return { openDialogMode: get( _context?.state?.valueOf, `${_dataSourceName}${__stateValueOfSplit__}openDialogMode`, ), }; }, }); let newFormValue; if (isPlainObject(p)) { newFormValue = { ...(formValue || {}), ...(p || {}) }; formInstance?.current?.setInitialValues?.( cloneDeep(newFormValue), 'overwrite', ); } else if (p?.then) { p.then( (result) => { if (isPlainObject(result)) { newFormValue = { ...(result || {}) }; formInstance?.current?.setInitialValues?.( cloneDeep(newFormValue), 'overwrite', ); formInstance?.current?.setValues?.(newFormValue, 'overwrite'); } setDefer(false); if (setInitialValue) { executeEventWithoutJS({ eventType: 'onDefaultValueFinished', events, _context, position: ButtonPosition.formEvent, recordDataSource: {}, formInstance: formInstance.current, }); } }, () => { setDefer(false); if (setInitialValue) { executeEventWithoutJS({ eventType: 'onDefaultValueFinished', events, _context, position: ButtonPosition.formEvent, recordDataSource: {}, formInstance: formInstance.current, }); } }, ).then((res) => { if (dataOrigin === 'request' && requestConfig?.url) { if (afterRequest?.optType) { const action = getButtonAction({ ...afterRequest, position: ButtonPosition.formDefaultValueAfterRequestSuccess, }); action?.({ position: ButtonPosition.formDefaultValueAfterRequestSuccess, urlParamsDataSource: urlParams, recordDataSource: newFormValue, state: _context?.state, buttonConfig: afterRequest, _context, }); } } }); } } }; const generateForm = (formValue, otherConfig) => { const { setInitialValues } = otherConfig || {}; const formOptions = { effects() { onFormValuesChange((form) => { if (form.values) { const temp = cloneDeep(toJS(form.values)); if (_dataSourceName && temp) { _context?.setState({ [_dataSourceName]: temp, }); } } }); function handleButtons(buttonList, parentName) { if (Array.isArray(buttonList) && buttonList.length > 0) { for (const item of buttonList) { const { primaryKey, hidden, disabled, optType } = item || {}; if (primaryKey && parentName) { let buttonName = `${parentName}.*.${primaryKey}`; // 树表格兼容逻辑 const secondButtonName = `${parentName}.*.children.*.${primaryKey}`; const isArrayTableAdd = optType === 'arrayTableAdd' || optType === 'arraySubAreaCardAdd'; if (isArrayTableAdd) { buttonName = `${parentName}.${primaryKey}`; } if (hidden !== undefined && hidden !== '' && hidden !== false) { onFieldReact(buttonName, (field, form) => { const objExprArgMap = { [__dataSource__]: _context?.state, [__formValue__]: form?.values, }; const { index } = field; let currentRow = {}; if (typeof index === 'number') { const temp = field?.query?.(parentName)?.value?.(); if (temp && temp[index]) { currentRow = temp[index]; } } objExprArgMap[__arrayTableCurrentRow__] = currentRow; field.hidden = executeObjectExpr( hidden, objExprArgMap, currentRow, _context?.state, index, form?.values || {}, ); }); onFieldReact(secondButtonName, (field, form) => { const objExprArgMap = { [__dataSource__]: _context?.state, [__formValue__]: form?.values, }; let currentRow = {}; const { index } = field; if (field?.path?.segments?.length === 5) { const path = field.path.segments.slice(0, 4); const tempRow = field?.form?.getValuesIn?.(path); if (isPlainObject(tempRow)) { currentRow = tempRow; } } objExprArgMap[__arrayTableCurrentRow__] = currentRow; field.hidden = executeObjectExpr( hidden, objExprArgMap, currentRow, _context?.state, index, form?.values || {}, ); }); } if ( disabled !== undefined && disabled !== '' && disabled !== false ) { onFieldReact(buttonName, (field, form) => { const objExprArgMap = { [__dataSource__]: _context?.state, [__formValue__]: form?.values, }; const { index } = field; let currentRow = {}; if (typeof index === 'number') { const temp = field?.query?.(parentName)?.value?.(); if (temp && temp[index]) { currentRow = temp[index]; } } objExprArgMap[__arrayTableCurrentRow__] = currentRow; if (isArrayTableAdd) { field.disabled = executeObjectExpr( disabled, objExprArgMap, currentRow, _context?.state, index, form?.values || {}, ); } else { field.setComponentProps({ disabled: executeObjectExpr( disabled, objExprArgMap, currentRow, _context?.state, index, form?.values || {}, ), }); } }); } } } } } function handleConfig(list, parentName, extraConfig) { if (isArrayNotEmpty(list)) { const { parentComponentName, ancestorRecursionCompName } = extraConfig || {}; // 父组件是Compose组件 const isCompose = parentComponentName === Compose; for (const item of list) { const { events, name, componentName, options, hidden, disabled, readOnly, notSubmitWhenHidden, arrayTableColumnHidden, } = item || {}; let fieldName = name; if (name) { if (parentName) { if (isCompose) { fieldName = `${parentName}.${name}`; } else { fieldName = `${parentName}.*.${name}`; } } if (Array.isArray(events) && events.length > 0) { for (const event of events) { const { name: eventName, optType, jsFunction, flowList, } = event || {}; let hook; if (eventName === 'onFieldValueChange') { hook = onFieldValueChange; } else if (eventName === 'onFieldInputValueChange') { hook = onFieldInputValueChange; } else if (eventName === 'onBlur') { hook = onFieldChange; } else if (eventName === 'onFieldReact') { hook = onFieldReact; } else if (eventName === 'onFieldInitialValueChange') { hook = onFieldInitialValueChange; } else if (eventName === 'onFieldInit') { hook = onFieldInit; } if (hook) { if ( optType === 'jsAction' && typeof jsFunction === 'function' ) { if (eventName === 'onBlur') { hook(fieldName, ['active'], (field) => { if ( field?.mounted === true && field?.active === false ) { jsFunction.call( null, field, formInstance.current, ); } }); } else { hook(fieldName, (field) => { jsFunction.call(null, field, formInstance.current); }); } } else { const action = getButtonAction({ ...event, position: ButtonPosition.formItemEvent, }); if (typeof action === 'function') { const callback = (field) => { action({ buttonConfig: { ...event, position: ButtonPosition.formItemEvent, options: { ...event, }, }, parentComponentName, position: ButtonPosition.formItemEvent, componentProps: props, state: _context?.state, urlParamsDataSource: getUrlParams(), recordDataSource: { realize: () => { return formInstance?.current?.values; }, }, formInstance: { realize: () => { return formInstance?.current; }, }, _context, formRef: { realize: () => { return formRef?.current; }, }, field, }); }; if (eventName === 'onBlur') { hook(fieldName, ['active'], (field) => { if ( field?.visited === true && field?.active === false ) { callback(field); } }); } else { hook(fieldName, callback); } } } } } } if (hidden !== undefined && hidden !== '' && hidden !== false) { onFieldReact(fieldName, (field, form) => { const objExprArgMap = { [__dataSource__]: _context?.state, [__formValue__]: form?.values, [__filterValue__]: form?.values, [__extraParam__]: { openDialogMode: get( _context?.state?.valueOf, `${_dataSourceName}${__stateValueOfSplit__}openDialogMode`, ), }, }; let currentRow = {}; if (parentName && !isCompose) { const { path, index } = field; if (typeof index === 'number' && isNaN(index) === false) { const temp = field?.query?.(parentName)?.value?.(); if (temp && temp[index]) { currentRow = temp[index]; } } else { const parentPath = path?.parent(); if (parentPath) { currentRow = form?.getValuesIn?.(parentPath); } } objExprArgMap[__arrayTableCurrentRow__] = currentRow; } const isHidden = executeObjectExpr( hidden, objExprArgMap, form?.values || {}, _context?.state, currentRow, ); if (isHidden === true) { if (notSubmitWhenHidden === true) { field.display = 'none'; } else { field.hidden = isHidden; } } else { field.hidden = isHidden; field.display = 'visible'; } if (parentName && !isCompose) { const { group } = hidden || {}; if ( group !== __arrayTableCurrentRow__ && typeof hidden !== 'function' ) { if (isHidden) { field .query(`..${name}${columnSuffix}`) .take((target) => { target.hidden = true; }); } else { field .query(`..${name}${columnSuffix}`) .take((target) => { target.hidden = false; }); } } } }); } if ( arrayTableColumnHidden !== undefined && arrayTableColumnHidden !== '' && arrayTableColumnHidden !== false ) { onFieldReact( `${parentName}.${name}${columnSuffix}`, (field, form) => { const objExprArgMap = { [__dataSource__]: _context?.state, [__formValue__]: form?.values, [__filterValue__]: form?.values, }; field.hidden = executeObjectExpr( arrayTableColumnHidden, objExprArgMap, form?.values || {}, _context?.state, ); }, ); } if ( disabled !== undefined && disabled !== '' && disabled !== false ) { onFieldReact(fieldName, (field, form) => { const objExprArgMap = { [__dataSource__]: _context?.state, [__formValue__]: form?.values, [__filterValue__]: form?.values, [__extraParam__]: { openDialogMode: get( _context?.state?.valueOf, `${_dataSourceName}${__stateValueOfSplit__}openDialogMode`, ), }, }; let currentRow = {}; if (parentName) { if(!isCompose) { currentRow = getArrayTableCurrentRowByField2(field) || {} objExprArgMap[__arrayTableCurrentRow__] = currentRow; } else { currentRow = getLastListCurrentRowByField(field, ancestorRecursionCompName); objExprArgMap[__arrayTableCurrentRow__] = currentRow; } } field.disabled = executeObjectExpr( disabled, objExprArgMap, form?.values || {}, _context?.state, currentRow, ); }); } if (readOnly !== undefined && readOnly !== '') { onFieldReact(fieldName, (field, form) => { const objExprArgMap = { [__dataSource__]: _context?.state, [__formValue__]: form?.values, [__filterValue__]: form?.values, [__extraParam__]: { openDialogMode: get( _context?.state?.valueOf, `${_dataSourceName}${__stateValueOfSplit__}openDialogMode`, ), }, }; let currentRow = {}; if (parentName && !isCompose) { const { index } = field; if (typeof index === 'number') { const temp = field?.query?.(parentName)?.value?.(); if (temp && temp[index]) { currentRow = temp[index]; } } objExprArgMap[__arrayTableCurrentRow__] = currentRow; } field.readOnly = executeObjectExpr( readOnly, objExprArgMap, form?.values || {}, _context?.state, currentRow, ); }); } } if (isArrayNotEmpty(options?.config)) { if (isRecursionComponent(componentName)) { handleConfig(options?.config, fieldName, { parentComponentName: componentName, ancestorRecursionCompName: name }); handleButtons(options?.buttons, fieldName); } else if (componentName === Compose) { handleConfig(options?.config, fieldName, { parentComponentName: componentName, ancestorRecursionCompName, }); } } } } } handleConfig(config); }, }; if (formValue && Object.keys(formValue).length > 0) { formOptions.values = cloneDeep(formValue); if (setInitialValues) { if(__bizExtendConfig__?.openDidMountInitialValue) { initialValueUtil.setInitialValue(cloneDeep(formValue)); } else { formOptions.initialValues = cloneDeep(formValue); } } } if (isFormReadOnly) { formOptions.readOnly = isFormReadOnly; } const result = createForm(formOptions); onCreateForm && onCreateForm(result, formStepInstance, isFormStep); registerDynamicFormEffects({ ins: result, dynamic: dynamicFormConfig, }); return result; }; if (!formInstance.current) { if (parentFormInstance) { formInstance.current = parentFormInstance; } else { let formDefaultValue = getFormValue(); const tempResult = calculateWaitComponentList(config, defaultParams); if (isArrayNotEmpty(tempResult.waitComponentList)) { waitComponentList.current = tempResult.waitComponentList; } if (!isEmpty(tempResult.configMap)) { configMap.current = tempResult.configMap; } if (!isEmpty(tempResult.waitComponentMap)) { waitComponentMap.current = tempResult.waitComponentMap; } if (dataOrigin === dataOriginStatic) { const p = getFormDefaultValue(defaultParams, { urlParamsDataSource: urlParams, state: _context?.state, isDesign, formConfig: config, ignoreDefaultSelectFormRequest: true, }); if (isPlainObject(p)) { formDefaultValue = { ...(formDefaultValue || {}), ...(p || {}) }; if (_dataSourceName) { _context?.setState({ [_dataSourceName]: { ...formDefaultValue }, }); } } } formInstance.current = generateForm(formDefaultValue, { setInitialValues: true, }); if (dataOrigin === dataOriginStatic) { executeEventWithoutJS({ eventType: 'onDefaultValueFinished', events, _context, position: ButtonPosition.formEvent, recordDataSource: {}, formInstance: formInstance.current, }); } } } const generateFormItemSchema = (item, index) => { const formValue = toJS(formInstance.current?.values); const formItem = makeFormItemSchema({ formValue, formItemConfig: item, isDesign, urlParams, state: _context?.state, usedComponentList, formProps: props, _context, formInstance: formInstance?.current, getFormInstance: () => { return formInstance.current; }, formStepInstance, // 当组件请求完成时,调用回调告知表单组件我已请求完成,从而实现下拉框默认勾选第一项操作 componentRequestFinish, index, }); if (formItem) { return formItem; } }; const generateSchema = () => { if (isArrayNotEmpty(config)) { if (isFormStep) { return generateMultipleFormSchema(config); } else if (isFormTab) { if (firstFormTabIndex === 0) { return generateMultipleFormSchema(config); } else { const normalFormConfig = config.slice(0, firstFormTabIndex); const multipleFormConfig = config.slice(firstFormTabIndex); const formTabSchema = generateMultipleFormSchema(multipleFormConfig); const normalFormSchema = generateNormalFormSchema(normalFormConfig); if (formTabSchema?.properties?.root && normalFormConfig) { normalFormSchema.properties.root = formTabSchema.properties.root; } return normalFormSchema; } } else { return generateNormalFormSchema(config); } } }; const generateNormalFormSchema = (tempFormConfig) => { let defaultParent = 'root'; const tree = { root: { type: 'object', properties: { [`root_${CnFormGrid}`]: { type: 'void', 'x-component': CnFormGrid, 'x-component-props': { cols, }, properties: {}, }, }, _componentName: 'root', _name: 'root', }, }; if (Array.isArray(tempFormConfig) && tempFormConfig.length > 0) { const newConfig = cloneDeepWith(tempFormConfig, (value) => { if (React.isValidElement(value)) { return value; } }); newConfig.forEach((item, index = {}) => { const { name, componentName } = item; const componentDefine = getRunTimeItem(componentMap, componentName); const { isFormContainer } = componentDefine || {}; const parent = tree[defaultParent]; if (isFormContainer) { if (componentName === CnCard) { tree[name] = generateFormItemSchema(item); tree[name]._parent = 'root'; } else if (componentName === CnCardSubCard) { if ( parent?._componentName === CnCard || parent?._componentName === 'root' ) { tree[name] = generateFormItemSchema(item); if (tree[name]) { tree[name]._parent = defaultParent; } } else if (parent?._componentName === CnCardSubCard) { const temp = parent?._parent || 'root'; tree[name] = generateFormItemSchema(item); if (tree[name]) { tree[name]._parent = tree[temp]._name || 'root'; } } } defaultParent = name; } else { tree[name] = generateFormItemSchema(item, index); if (tree[name]) { tree[name]._parent = defaultParent; } } if (tree[name]) { tree[name]._name = name; tree[name]._componentName = componentName; } if (tree[name]?._parent) { const parentSchema = tree[tree[name]._parent]; if (parentSchema?._componentName === CnCardSubCard) { const { _name } = parentSchema; const formGrid = parentSchema.properties[`${_name}_${CnFormGrid}`]; if (formGrid?.properties) { formGrid.properties[name] = tree[name]; } } else if ( parentSchema?._componentName === 'root' && !isFormContainer ) { const formGrid = parentSchema.properties[`root_${CnFormGrid}`]; if (formGrid?.properties) { formGrid.properties[name] = tree[name]; } } else if (parentSchema?._componentName === CnCard) { if (componentName === CnCardSubCard) { const subCardCols = parentSchema?.['x-component-props']?.subCardCols; if (subCardCols) { const { _name } = parentSchema; const formGrid = parentSchema.properties[`${_name}_subCard_${CnFormGrid}`]; if (formGrid?.properties) { formGrid.properties[name] = tree[name]; } } else { parentSchema.properties[name] = tree[name]; } } else { const { _name } = parentSchema; const formGrid = parentSchema.properties[`${_name}_${CnFormGrid}`]; if (formGrid?.properties) { formGrid.properties[name] = tree[name]; } } } else if (parentSchema?.properties) { parentSchema.properties[name] = tree[name]; } } }); } return tree.root; }; // 获取分步表单中的Tab schema片段 const getFormTabSchemaInStep = (tempConfig, index) => { if (isArrayNotEmpty(tempConfig)) { const tempList = []; const tempNameList = []; const first = tempConfig[index] || {}; const { componentName, name } = first || {}; if (componentName === CnFormTabItem && name) { if (!cacheFormTabInstance.current?.[name]) { cacheFormTabInstance.current[name] = CnFormTab?.createCnFormTab?.(); } for (let i = index; i < tempConfig.length; i++) { const item = tempConfig[i]; const { componentName } = item || {}; if (componentName === CnFormStepItem) { break; } else { tempNameList.push(item?.name); tempList.push(item); } } if (isArrayNotEmpty(tempList)) { const tempResult = generateMultipleFormSchema(tempList, { isInFormStep: true, }); const tempTabSchema = { type: 'void', 'x-component': 'CnFormTab', 'x-component-props': { formTab: cacheFormTabInstance.current?.[name], }, properties: tempResult?.properties?.root?.properties, _componentName: 'CnFormTab', _name: name, }; return { TabSchema: tempTabSchema, TabFieldList: tempNameList, }; } } } }; const generateMultipleFormSchema = (tempFormConfig, extraConfig) => { const { isInFormStep } = extraConfig || {}; let containerComponentName; let containerComponentProps; // 缓存步骤表单里出现Tab表单时,已生成schema的Tab表单项。 let cacheTabItems = []; // 缓存步骤表单里出现Tab表单时,Tab表单的schema。 let cacheTabSchema; if (isFormStep) { const { shape } = firstFormStep?.options || {}; containerComponentName = 'CnFormStep'; containerComponentProps = { cnFormStepInstance: formStepInstance, shape, }; } else if (isFormTab) { containerComponentName = 'CnFormTab'; containerComponentProps = { formTab: formTabInstance, }; } const tree = { type: 'object', properties: { root: { type: 'void', 'x-component': containerComponentName, 'x-component-props': containerComponentProps, properties: {}, _componentName: 'root', _name: 'root', }, }, }; const newConfig = cloneDeepWith(tempFormConfig, (value) => { if (React.isValidElement(value)) { return value; } }); const originalConfigMap = {}; tempFormConfig.forEach((item, index) => { if (item?.name && item?.componentName) { const tempComponentDefine = getRunTimeItem( componentMap, item.componentName, ); originalConfigMap[item.name] = { ...item, isFormContainer: tempComponentDefine?.isFormContainer, allowParentList: tempComponentDefine?.allowParentList, }; } }); const newConfigMap = {}; newConfig.forEach((item, index) => { const parentList = newConfig.slice(0, index).reverse(); const { name, componentName } = item; if (name && componentName) { if (cacheTabItems.includes(name)) { return; } const current = generateFormItemSchema(item); current._name = name; current._componentName = componentName; const currentAllowParentList = originalConfigMap[name]?.allowParentList || []; const currentIsFormContainer = originalConfigMap[name]?.isFormContainer; if ( isInFormStep !== true && currentIsFormContainer && componentName === CnFormTabItem && isFormStep ) { const { TabSchema, TabFieldList } = getFormTabSchemaInStep(newConfig, index) || {}; if (isArrayNotEmpty(TabFieldList)) { cacheTabItems = TabFieldList; } if (TabSchema) { cacheTabSchema = TabSchema; } } for (const item2 of parentList) { if (item2?.name && item2?.componentName) { const tempParent = originalConfigMap[item2.name]; if (tempParent?.isFormContainer) { if ( !currentIsFormContainer || (currentIsFormContainer && currentAllowParentList.includes(item2.componentName)) ) { if (currentIsFormContainer) { if (isPlainObject(newConfigMap[item2.name]?.properties)) { newConfigMap[item2.name].properties[name] = current; } } else if ( isPlainObject( newConfigMap[item2.name]?.properties?.[ `${item2.name}_${CnFormGrid}` ]?.properties, ) ) { newConfigMap[item2.name].properties[ `${item2.name}_${CnFormGrid}` ].properties[name] = current; } current._parent = item2.name; break; } else if ( componentName === CnFormTabItem && isFormStep && cacheTabSchema ) { if (isPlainObject(newConfigMap[item2.name]?.properties)) { newConfigMap[item2.name].properties[name] = cacheTabSchema; current._parent = item2.name; cacheTabItems = []; cacheTabSchema = undefined; } } } } } if (!current._parent) { current._parent = 'root'; if ( componentName === CnFormStepItem || componentName === CnFormTabItem ) { tree.properties.root.properties[name] = current; } } newConfigMap[name] = current; } }); return tree; }; const getUrlParams = () => { return _context?.state?.urlParams || {}; }; const getButtons = () => { if (isCnForm) { const formValue = formInstance?.current?.values; const state = _context?.state; const rightButtons = []; const leftButtons = []; buttons?.forEach((item, index) => { const { btnPosition, iconType, primaryKey, optType, options = {}, children, type, hidden, disabled, ...rest } = item; const isHidden = executeObjectExpr( hidden, { [__filterValue__]: formValue || {}, [__formValue__]: formValue || {}, [__dataSource__]: state, [__extraParam__]: { currentFormStep: formStepInstance?.current, }, }, formValue || {}, state, ); if (isDesign) { } else { if ( optType === 'previousStep' && formStepInstance?.allowBack !== true ) { return null; } if (optType === 'nextStep' && formStepInstance?.allowNext !== true) { return null; } if ( isFormStep && optType === 'submit' && formStepInstance?.allowNext === true ) { return null; } } if (isHidden) { return null; } const isDisabled = executeObjectExpr( disabled, { [__filterValue__]: formValue || {}, [__formValue__]: formValue || {}, [__dataSource__]: state, }, formValue || {}, state, ); const action = getButtonAction({ ...item, position: ButtonPosition.form, }); const componentDefine = getRunTimeItem({}, optType); const getRenderDom = getButtonItem( ButtonPosition.form, optType, 'getRenderDom', ); const btnProps = { type, disabled: isDisabled, }; if (mode !== 'block') { btnProps.size = 'large'; } let needShowLoading; if (optType === 'submit') { needShowLoading = true; } else if (optType === 'flowAction') { const hasSubmitAction = options?.flowList?.find?.( (item) => item?.optType === 'submit', ); if (hasSubmitAction) { needShowLoading = true; } } if (needShowLoading) { btnProps.loading = formInstance?.current?.submitting; } if (componentDefine?.component) { const component = getRealizeValue(componentDefine.component); if (component) { let comProps = { children, ...btnProps, buttonConfig: item, _context, [_getFormValues]: () => { return formInstance?.current?.values; }, } if (btnPosition === 'left') { leftButtons.push(React.createElement(component, comProps)); } else { rightButtons.push(React.createElement(component, comProps)); } return; } } else if (typeof getRenderDom === 'function') { const renderDom = executeFunction(getRenderDom, { _context, buttonConfig: item, state: _context?.state, urlParamsDataSource: getUrlParams(), recordDataSource: { realize: () => { return formInstance?.current?.values; }, }, }); if (btnPosition === 'left') { leftButtons.push(renderDom); } else { rightButtons.push(renderDom); } return; } if (action) { btnProps.onClick = action.bind(this, { componentProps: props, buttonConfig: item, position: ButtonPosition.form, state: _context?.state, urlParamsDataSource: getUrlParams(), recordDataSource: { realize: () => { return formInstance?.current?.values; }, }, formInstance: { realize: () => { return formInstance?.current; }, }, _context, dialogRef: props?.dialogRef, formStepInstance, isFormStep, isFormTab, getExtraParam: () => { return { openDialogMode: get( _context?.state?.valueOf, `${_dataSourceName}${__stateValueOfSplit__}openDialogMode`, ), }; }, }); } const dom = ( <CnButton {...btnProps} mobileProps={{ fullWidth: true, size: 'large', }} > {renderIcon(iconType)} {children} </CnButton> ); if (btnPosition === 'right') { rightButtons.push(dom); } else if (b