import React, { useCallback, useMemo, useEffect, useRef, useState, forwardRef, useImperativeHandle, } from 'react'; import { CnFilter as UICnFilter, formilyCore, CnFilterItem, } from '@cainiaofe/cn-ui-m'; import { calculateWaitComponentList, executeEventWithoutJS, executeObjectExpr, getFormDefaultValue, isArrayNotEmpty, isDesignMode, isEmptyButNotZero, makeFormItemSchema, transProxyToObject, } from '@/common/util/util'; import isEqualWith from 'lodash/isEqualWith'; import isPlainObject from 'lodash/isPlainObject'; import cloneDeep from 'lodash/cloneDeep'; import cloneDeepWith from 'lodash/cloneDeepWith'; import { toJS } from '@formily/reactive'; import { CnFilterDefaultValueFinished, CnFilterOnChange, CnFilterOnSearch, CnPageRequestFinish, emitEvent, onEvent, } from '@/common/util/event-name'; import { __dataSource__, __filterValue__, __formValue__, } from '@/common/util/expr-const'; import isEmpty from 'lodash/isEmpty'; import { ButtonPosition } from '@/type/button-position'; import { getButtonAction } from '@/common/manager/button'; import { dataOriginStatic, dataOriginRequest } from '@/common/util/const'; import { getFormExtraComponents } from '@/common/manager/filter-item'; const { createForm, onFormValuesChange, onFieldReact, onFieldInputValueChange, } = formilyCore || {}; function View(props, ref) { const { config = [], _dataSource, _dataSourceName, _context, forwardedRef, _bindTable, defaultParams, filterStyle, title, events: filterEvents, ...otherProps } = props; const isDesign = isDesignMode(props); const formInstance = useRef(null); const urlParams = _context?.state?.urlParams || {}; const oldSchema = useRef(null); let extraProps = {}; const usedComponentList = []; const filterRef = useRef(null); const { dataOrigin, deferRender } = defaultParams || {}; // 记录默认值请求需要等待哪些组件请求完成 const waitComponentList = useRef([]); const configMap = useRef({}); let defaultDeferRender; if (!isDesign && dataOrigin === dataOriginRequest && !!deferRender) { defaultDeferRender = !!deferRender; } const [defer, setDefer] = useState(defaultDeferRender); const [forceUpdate, setForceUpdate] = useState(); // 缓存默认值,用于重置还原 const cacheDefaultValue = useRef(null); const { afterResetNeedQuery } = filterStyle || {}; useImperativeHandle(ref, () => ({ reset() { formInstance?.current?.filterReset?.(); }, getFormInstance() { return formInstance.current; }, search() { formInstance?.current?.handleSearch?.(); }, })); const getFormValue = useCallback(() => { if (typeof _dataSource === 'object') { return transProxyToObject(_dataSource); } return null; }, []); const componentRequestFinish = useCallback((tempConfig) => { const { name, dataSource } = tempConfig || {}; const defaultValues = cacheDefaultValue.current; const oldLength = waitComponentList.current?.length; if ( isPlainObject(defaultValues) && name && waitComponentList.current?.includes(name) ) { waitComponentList.current = waitComponentList.current.filter( (item) => item !== name, ); const current = defaultValues[name]; if ( typeof current?.value === 'number' && current?.valueType === 'DefaultSelect' ) { const currentConfig = configMap?.current?.[name]; const temp = dataSource?.[current.value]; let realValue = temp?.value; if (currentConfig?.options?.mode === 'multiple') { if (isEmptyButNotZero(realValue)) { realValue = []; } else { realValue = [realValue]; } } defaultValues[name] = realValue; } const newLength = waitComponentList.current.length; if (newLength === 0 && oldLength > 0) { formInstance?.current?.setInitialValues(defaultValues); const table = _context?.$(_bindTable); if (table?.props?.manual === true) { } else { setTimeout(() => { tableLoad(); }); } } } }, []); // 设计态默认值的兼容逻辑 if (isDesign === true) { if (dataOrigin === dataOriginStatic) { const tempDefaultValue = getFormDefaultValue(defaultParams, { urlParamsDataSource: urlParams, state: _context?.state, isDesign, formConfig: config, }); if (isPlainObject(tempDefaultValue)) { formInstance?.current?.setValues?.(tempDefaultValue, 'overwrite'); } } } const getRemoteDefaultValue = () => { const { dataOrigin, requestConfig = {}, afterRequest = {}, } = defaultParams || {}; if (dataOrigin === 'request') { const p = getFormDefaultValue(defaultParams, { urlParamsDataSource: urlParams, state: _context?.state, isDesign, formConfig: config, }); let newFormValue; if (p?.then) { p.then( (result) => { if (isPlainObject(result)) { newFormValue = { ...(result || {}) }; formInstance?.current?.setInitialValues?.( cloneDeep(newFormValue), 'overwrite', ); } setDefer(false); emitEvent(CnFilterDefaultValueFinished, { componentProps: props, formValues: newFormValue, }); }, () => { setDefer(false); emitEvent(CnFilterDefaultValueFinished, { componentProps: props, }); }, ).then((res) => { if (afterRequest?.optType) { const action = getButtonAction({ ...afterRequest, position: ButtonPosition.filterDefaultValueAfterRequestSuccess, }); action?.({ position: ButtonPosition.filterDefaultValueAfterRequestSuccess, urlParamsDataSource: urlParams, recordDataSource: newFormValue, state: _context?.state, buttonConfig: afterRequest, _context, }); } }); } } }; const getStaticDefaultValue = (originalFormValue, extraConfig) => { let result = originalFormValue; if (dataOrigin === dataOriginStatic) { const p = getFormDefaultValue(defaultParams, { urlParamsDataSource: urlParams, state: _context?.state, isDesign, formConfig: config, ...extraConfig, }); if (isPlainObject(p)) { result = { ...(originalFormValue || {}), ...(p || {}) }; } } return result; }; // didMount查询默认值 useEffect(() => { getRemoteDefaultValue(); onEvent(CnPageRequestFinish, () => { setForceUpdate(Date.now()); }); return () => { if (_dataSourceName) { const temp = _context?.state?.[_dataSourceName]; if (isPlainObject(temp) && !isEmpty(temp)) { _context?.setState({ [_dataSourceName]: {}, }); } } }; }, []); 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, }); } emitEvent(CnFilterOnChange, { componentProps: props, payload: form?.values, }); tableForceUpdate(); } }); function handleConfig(list) { if (isArrayNotEmpty(list)) { for (const item of list) { const { events, name, componentName, options, hidden, disabled } = item || {}; if (name) { const fieldName = name; if (isArrayNotEmpty(events)) { for (const event of events) { const { name: eventName, optType, jsFunction, } = event || {}; let hook; if (eventName === 'onFieldValueChange') { hook = onFieldInputValueChange; } if (hook) { if ( optType === 'jsAction' && typeof jsFunction === 'function' ) { hook(fieldName, (field) => { jsFunction.call(null, field, formInstance.current); }); } else { const action = getButtonAction({ ...event, position: ButtonPosition.filterItemEvent, }); if (typeof action === 'function') { const callback = (field) => { action({ buttonConfig: { ...event, position: ButtonPosition.filterItemEvent, options: { ...event, }, }, position: ButtonPosition.filterItemEvent, componentProps: props, state: _context?.state, urlParamsDataSource: urlParams, recordDataSource: { realize: () => { return formInstance?.current?.values; }, }, formInstance: { realize: () => { return formInstance?.current; }, }, _context, field, }); }; hook(fieldName, callback); } } } } } if (hidden !== undefined && hidden !== '' && hidden !== false) { onFieldReact(fieldName, (field, form) => { const objExprArgMap = { [__dataSource__]: _context?.state, [__formValue__]: form?.values, [__filterValue__]: form?.values, }; const isHidden = executeObjectExpr( hidden, objExprArgMap, form?.values || {}, _context?.state, ); if (isHidden === true) { field.hidden = true; } else { field.hidden = false; } }); } if ( disabled !== undefined && disabled !== '' && disabled !== false ) { onFieldReact(fieldName, (field, form) => { const objExprArgMap = { [__dataSource__]: _context?.state, [__formValue__]: form?.values, [__filterValue__]: form?.values, }; field.disabled = executeObjectExpr( disabled, objExprArgMap, form?.values || {}, _context?.state, ); }); } } } } } handleConfig(config); }, }; if (formValue && Object.keys(formValue).length > 0) { if (setInitialValues) { formOptions.initialValues = cloneDeep(formValue); } else { formOptions.values = cloneDeep(formValue); } } return createForm(formOptions); }; if (!formInstance.current) { const formDefaultValue = getFormValue(); const tempResult = calculateWaitComponentList(config, defaultParams); if (isArrayNotEmpty(tempResult.waitComponentList)) { waitComponentList.current = tempResult.waitComponentList; } if (!isEmpty(tempResult.configMap)) { configMap.current = tempResult.configMap; } let staticFormDefaultValue = getStaticDefaultValue(formDefaultValue); if (isArrayNotEmpty(waitComponentList?.current)) { cacheDefaultValue.current = staticFormDefaultValue; staticFormDefaultValue = getStaticDefaultValue(formDefaultValue, { ignoreDefaultSelectFormRequest: true, }); } else if (_dataSourceName && isPlainObject(staticFormDefaultValue)) { if (dataOrigin === dataOriginStatic) { emitEvent(CnFilterDefaultValueFinished, { componentProps: props, formValues: staticFormDefaultValue, }); } _context?.setState({ [_dataSourceName]: staticFormDefaultValue, }); } formInstance.current = generateForm(staticFormDefaultValue, { setInitialValues: true, }); } const onSearch = useCallback((value) => { emitEvent(CnFilterOnSearch, { componentProps: props, payload: value, }); executeEventWithoutJS({ eventType: 'onSearch', events: filterEvents, _context, position: ButtonPosition.filterEvent, urlParamsDataSource: urlParams, recordDataSource: value, }); tableLoad(); }, []); const generateFormItemSchema = (item) => { 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; }, isInCnFilterPro: true, // 当组件请求完成时,调用回调告知表单组件我已请求完成,从而实现下拉框默认勾选第一项操作 componentRequestFinish, customDecoratorComponent: 'CnFilterProItem', }); if (formItem) { return formItem; } }; const tableForceUpdate = useCallback(() => { if (_bindTable && _context) { const table = _context?.$?.(_bindTable); table?.forceUpdate?.(); } }, []); const tableLoad = useCallback(() => { if (_bindTable && _context) { const table = _context.$(_bindTable); table?.load?.(); } }, []); // 自定义的onReset,用于避免触发表格重新查询 const onReset = useCallback(() => { // tableForceUpdate(); }, []); const generateSchema = () => { const tree = { type: 'object', properties: {}, }; const newConfig = cloneDeepWith(config, (value) => { if (React.isValidElement(value)) { return value; } }); // const originalConfigMap = {} // config.forEach((item,index)=>{ // if(item?.name && item?.componentName) { // originalConfigMap[item.name] = { // ...item, // }; // } // }) newConfig.forEach((item, index) => { const { name, componentName } = item || {}; if (name && componentName) { const current = generateFormItemSchema(item); current._name = name; current._componentName = componentName; current._parent = 'root'; if (current) { tree.properties[name] = current; } } }); return tree; }; const generateDom = () => { const result = []; const newConfig = cloneDeepWith(config, (value) => { if (React.isValidElement(value)) { return value; } }); newConfig.forEach((item, index) => { const { name, componentName, label, quick } = item || {}; if (name && componentName) { const current = generateFormItemSchema(item); const CurrentComponent = window.CNUIM?.[componentName]; if (CurrentComponent) { result.push( , ); } } }); return result; }; const dom = generateDom(); // let needCreateNewForm = false; const schema = generateSchema(); // if (schema && oldSchema.current) { // if (!isEqualWith(schema, oldSchema.current,(objValue, othValue)=>{ // if(objValue instanceof Function && othValue instanceof Function) { // return true; // } // })) { // needCreateNewForm = true // } // } // if(needCreateNewForm) { // console.log('new filter pro'); // formInstance.current = generateForm(toJS(formInstance.current?.values)); // } // oldSchema.current = { ...schema }; if (isPlainObject(filterStyle)) { extraProps = { ...extraProps, ...filterStyle, }; } if (!isDesign && defer) { return null; } if (afterResetNeedQuery === false) { extraProps.onReset = onReset; } const formComponents = getFormExtraComponents(usedComponentList); return ( {dom} ); } const CnFilter = forwardRef(View); CnFilter.displayName = 'CnFilter'; export { CnFilter };