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 };