@cainiaofe/cn-ui-lowcode
Version:
1,503 lines (1,455 loc) • 56 kB
JavaScript
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