mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-05-09 23:49:27 +08:00
feat: event filter support
This commit is contained in:
parent
1d02eb1e8b
commit
e973756d5a
@ -35,9 +35,15 @@ export function useFormEvents({ form }) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
// state: {
|
states: {
|
||||||
// isSubmitting: 'isSubmitting',
|
values: {
|
||||||
// },
|
name: 'values',
|
||||||
|
title: '表单值',
|
||||||
|
type: 'object',
|
||||||
|
properties: fieldsMap,
|
||||||
|
value: form.values,
|
||||||
|
},
|
||||||
|
},
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
name: 'reset',
|
name: 'reset',
|
||||||
|
@ -53,9 +53,10 @@ export class EventFlowPlugin extends Plugin {
|
|||||||
}
|
}
|
||||||
// 运行时注册事件
|
// 运行时注册事件
|
||||||
register(events: EventSetting[]) {
|
register(events: EventSetting[]) {
|
||||||
events?.forEach((event) => {
|
console.log('todo register', events);
|
||||||
this.on(event);
|
// events?.forEach((event) => {
|
||||||
});
|
// this.on(event);
|
||||||
|
// });
|
||||||
}
|
}
|
||||||
// 触发事件
|
// 触发事件
|
||||||
async emit({ name, eventName, uid, params }: { name: string; eventName: string; uid?: string; params?: any }) {
|
async emit({ name, eventName, uid, params }: { name: string; eventName: string; uid?: string; params?: any }) {
|
||||||
|
@ -14,6 +14,7 @@ import React, { useCallback, useMemo } from 'react';
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { withDynamicSchemaProps } from '../../../hoc/withDynamicSchemaProps';
|
import { withDynamicSchemaProps } from '../../../hoc/withDynamicSchemaProps';
|
||||||
import { Action } from './Action';
|
import { Action } from './Action';
|
||||||
|
import { ArrayBase } from '@formily/antd-v5';
|
||||||
|
|
||||||
interface LinkageRuleActionGroupProps {
|
interface LinkageRuleActionGroupProps {
|
||||||
type: 'button' | 'field' | 'style';
|
type: 'button' | 'field' | 'style';
|
||||||
|
@ -1,281 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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 { CopyOutlined } from '@ant-design/icons';
|
|
||||||
import { ArrayBase } from '@formily/antd-v5';
|
|
||||||
import { ArrayField } from '@formily/core';
|
|
||||||
import { ISchema, RecursionField, observer, useField, useFieldSchema } from '@formily/react';
|
|
||||||
import { toArr } from '@formily/shared';
|
|
||||||
import { Badge, Card, Collapse, CollapsePanelProps, CollapseProps, Empty, Input } from 'antd';
|
|
||||||
import { cloneDeep } from 'lodash';
|
|
||||||
import React, { Fragment, useEffect, useState } from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { useToken } from '../../../../style';
|
|
||||||
import { arrayCollapseItemStyle } from './LinkageHeader.style';
|
|
||||||
|
|
||||||
const LinkageRulesTitle = (props) => {
|
|
||||||
const array = ArrayBase.useArray();
|
|
||||||
const index = ArrayBase.useIndex(props.index);
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const value = array?.field?.value[index];
|
|
||||||
return <div>动作 {index + 1}</div>;
|
|
||||||
// return (
|
|
||||||
// <Input.TextArea
|
|
||||||
// value={value.title}
|
|
||||||
// defaultValue={t('Linkage rule')}
|
|
||||||
// onChange={(ev) => {
|
|
||||||
// ev.stopPropagation();
|
|
||||||
// array.field.value.splice(index, 1, { ...value, title: ev.target.value });
|
|
||||||
// }}
|
|
||||||
// onBlur={(ev) => {
|
|
||||||
// ev.stopPropagation();
|
|
||||||
// array.field.value.splice(index, 1, { ...value, title: ev.target.value });
|
|
||||||
// }}
|
|
||||||
// autoSize
|
|
||||||
// style={{ width: '70%', border: 'none' }}
|
|
||||||
// onClick={(e) => {
|
|
||||||
// e.stopPropagation();
|
|
||||||
// }}
|
|
||||||
// />
|
|
||||||
// );
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface IArrayCollapseProps extends CollapseProps {
|
|
||||||
defaultOpenPanelCount?: number;
|
|
||||||
}
|
|
||||||
type ComposedArrayCollapse = React.FC<React.PropsWithChildren<IArrayCollapseProps>> & {
|
|
||||||
CollapsePanel?: React.FC<React.PropsWithChildren<CollapsePanelProps>>;
|
|
||||||
};
|
|
||||||
|
|
||||||
const isAdditionComponent = (schema: ISchema) => {
|
|
||||||
return schema['x-component']?.indexOf?.('Addition') > -1;
|
|
||||||
};
|
|
||||||
|
|
||||||
const isIndexComponent = (schema: ISchema) => {
|
|
||||||
return schema['x-component']?.indexOf?.('Index') > -1;
|
|
||||||
};
|
|
||||||
|
|
||||||
const isRemoveComponent = (schema: ISchema) => {
|
|
||||||
return schema['x-component']?.indexOf?.('Remove') > -1;
|
|
||||||
};
|
|
||||||
|
|
||||||
const isMoveUpComponent = (schema: ISchema) => {
|
|
||||||
return schema['x-component']?.indexOf?.('MoveUp') > -1;
|
|
||||||
};
|
|
||||||
|
|
||||||
const isMoveDownComponent = (schema: ISchema) => {
|
|
||||||
return schema['x-component']?.indexOf?.('MoveDown') > -1;
|
|
||||||
};
|
|
||||||
const isCopyComponent = (schema: ISchema) => {
|
|
||||||
return schema['x-component']?.indexOf?.('Copy') > -1;
|
|
||||||
};
|
|
||||||
const isOperationComponent = (schema: ISchema) => {
|
|
||||||
return (
|
|
||||||
isAdditionComponent(schema) ||
|
|
||||||
isRemoveComponent(schema) ||
|
|
||||||
isMoveDownComponent(schema) ||
|
|
||||||
isMoveUpComponent(schema) ||
|
|
||||||
isCopyComponent(schema)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const range = (count: number) => Array.from({ length: count }).map((_, i) => i);
|
|
||||||
|
|
||||||
const takeDefaultActiveKeys = (dataSourceLength: number, defaultOpenPanelCount: number) => {
|
|
||||||
if (dataSourceLength < defaultOpenPanelCount) return range(dataSourceLength);
|
|
||||||
return range(defaultOpenPanelCount);
|
|
||||||
};
|
|
||||||
|
|
||||||
const insertActiveKeys = (activeKeys: number[], index: number) => {
|
|
||||||
if (activeKeys.length <= index) return activeKeys.concat(index);
|
|
||||||
return activeKeys.reduce((buf, key) => {
|
|
||||||
if (key < index) return buf.concat(key);
|
|
||||||
if (key === index) return buf.concat([key, key + 1]);
|
|
||||||
return buf.concat(key + 1);
|
|
||||||
}, []);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const ArrayCollapse: ComposedArrayCollapse = observer(
|
|
||||||
(props: IArrayCollapseProps) => {
|
|
||||||
const field = useField<ArrayField>();
|
|
||||||
const dataSource = Array.isArray(field.value) ? field.value : [];
|
|
||||||
const [activeKeys, setActiveKeys] = useState<number[]>(
|
|
||||||
takeDefaultActiveKeys(dataSource.length, props.defaultOpenPanelCount),
|
|
||||||
);
|
|
||||||
const schema = useFieldSchema();
|
|
||||||
useEffect(() => {
|
|
||||||
if (!field.modified && dataSource.length) {
|
|
||||||
setActiveKeys(takeDefaultActiveKeys(dataSource.length, props.defaultOpenPanelCount));
|
|
||||||
}
|
|
||||||
}, [dataSource.length, field]);
|
|
||||||
if (!schema) throw new Error('can not found schema object');
|
|
||||||
|
|
||||||
const renderAddition = () => {
|
|
||||||
return schema.reduceProperties((addition, schema, key) => {
|
|
||||||
if (isAdditionComponent(schema)) {
|
|
||||||
return <RecursionField schema={schema} name={key} />;
|
|
||||||
}
|
|
||||||
return addition;
|
|
||||||
}, null);
|
|
||||||
};
|
|
||||||
const renderEmpty = () => {
|
|
||||||
if (dataSource.length) return;
|
|
||||||
return (
|
|
||||||
<Card className={props.className} style={arrayCollapseItemStyle}>
|
|
||||||
<Empty />
|
|
||||||
</Card>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const renderItems = () => {
|
|
||||||
if (!dataSource || dataSource.length === 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<Collapse
|
|
||||||
{...props}
|
|
||||||
activeKey={activeKeys}
|
|
||||||
onChange={(keys: string[]) => setActiveKeys(toArr(keys).map(Number))}
|
|
||||||
className={props.className}
|
|
||||||
style={arrayCollapseItemStyle}
|
|
||||||
>
|
|
||||||
{dataSource.map((item, index) => {
|
|
||||||
const items = Array.isArray(schema.items) ? schema.items[index] || schema.items[0] : schema.items;
|
|
||||||
|
|
||||||
const panelProps = field.query(`${field.address}.${index}`).get('componentProps');
|
|
||||||
const props: CollapsePanelProps = items['x-component-props'];
|
|
||||||
const header = () => {
|
|
||||||
const header = `${panelProps?.header || props.header || field.title}`;
|
|
||||||
const path = field.address.concat(index);
|
|
||||||
const errors = field.form.queryFeedbacks({
|
|
||||||
type: 'error',
|
|
||||||
address: `${path}.**`,
|
|
||||||
});
|
|
||||||
return (
|
|
||||||
<ArrayBase.Item index={index} record={() => field.value?.[index]}>
|
|
||||||
<RecursionField
|
|
||||||
schema={items}
|
|
||||||
name={index}
|
|
||||||
filterProperties={(schema) => {
|
|
||||||
if (!isIndexComponent(schema)) return false;
|
|
||||||
return true;
|
|
||||||
}}
|
|
||||||
onlyRenderProperties
|
|
||||||
/>
|
|
||||||
{errors.length ? (
|
|
||||||
<Badge size="small" className="errors-badge" count={errors.length}>
|
|
||||||
{header}
|
|
||||||
</Badge>
|
|
||||||
) : (
|
|
||||||
<LinkageRulesTitle item={item.initialValue || item} index={index} />
|
|
||||||
)}
|
|
||||||
</ArrayBase.Item>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const extra = (
|
|
||||||
<ArrayBase.Item index={index} record={item}>
|
|
||||||
<RecursionField
|
|
||||||
schema={items}
|
|
||||||
name={index}
|
|
||||||
filterProperties={(schema) => {
|
|
||||||
if (!isOperationComponent(schema)) return false;
|
|
||||||
return true;
|
|
||||||
}}
|
|
||||||
onlyRenderProperties
|
|
||||||
/>
|
|
||||||
{panelProps?.extra}
|
|
||||||
</ArrayBase.Item>
|
|
||||||
);
|
|
||||||
|
|
||||||
const content = (
|
|
||||||
<RecursionField
|
|
||||||
schema={items}
|
|
||||||
name={index}
|
|
||||||
filterProperties={(schema) => {
|
|
||||||
if (isIndexComponent(schema)) return false;
|
|
||||||
if (isOperationComponent(schema)) return false;
|
|
||||||
return true;
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
return (
|
|
||||||
<Collapse.Panel {...props} {...panelProps} forceRender key={index} header={header()} extra={extra}>
|
|
||||||
<ArrayBase.Item index={index} key={index} record={item}>
|
|
||||||
{content}
|
|
||||||
</ArrayBase.Item>
|
|
||||||
</Collapse.Panel>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Collapse>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<ArrayBase
|
|
||||||
onAdd={(index) => {
|
|
||||||
setActiveKeys(insertActiveKeys(activeKeys, index));
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{/* {renderEmpty()} */}
|
|
||||||
{renderItems()}
|
|
||||||
{renderAddition()}
|
|
||||||
</ArrayBase>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
{ displayName: 'ArrayCollapse' },
|
|
||||||
);
|
|
||||||
|
|
||||||
const CollapsePanel: React.FC<React.PropsWithChildren<CollapsePanelProps>> = ({ children }) => {
|
|
||||||
return <Fragment>{children}</Fragment>;
|
|
||||||
};
|
|
||||||
|
|
||||||
CollapsePanel.displayName = 'CollapsePanel';
|
|
||||||
|
|
||||||
ArrayCollapse.defaultProps = {
|
|
||||||
defaultOpenPanelCount: 5,
|
|
||||||
};
|
|
||||||
ArrayCollapse.displayName = 'ArrayCollapse';
|
|
||||||
ArrayCollapse.CollapsePanel = CollapsePanel;
|
|
||||||
|
|
||||||
ArrayBase.mixin(ArrayCollapse);
|
|
||||||
|
|
||||||
export default ArrayCollapse;
|
|
||||||
|
|
||||||
//@ts-ignore
|
|
||||||
ArrayCollapse.Copy = React.forwardRef((props: any, ref) => {
|
|
||||||
const { token } = useToken();
|
|
||||||
const self = useField();
|
|
||||||
const array = ArrayBase.useArray();
|
|
||||||
const index = ArrayBase.useIndex(props.index);
|
|
||||||
if (!array) return null;
|
|
||||||
if (array.field?.pattern !== 'editable') return null;
|
|
||||||
return (
|
|
||||||
<CopyOutlined
|
|
||||||
{...props}
|
|
||||||
style={{
|
|
||||||
transition: 'all 0.25s ease-in-out',
|
|
||||||
color: token.colorText,
|
|
||||||
fontSize: token.fontSizeLG,
|
|
||||||
marginLeft: 6,
|
|
||||||
}}
|
|
||||||
ref={ref}
|
|
||||||
onClick={(e) => {
|
|
||||||
if (self?.disabled) return;
|
|
||||||
e.stopPropagation();
|
|
||||||
if (array.props?.disabled) return;
|
|
||||||
const value = cloneDeep(array?.field?.value[index]);
|
|
||||||
array.field.push(value);
|
|
||||||
if (props.onClick) {
|
|
||||||
props.onClick(e);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
(ArrayCollapse as any).Copy.displayName = 'ArrayCollapse.Copy';
|
|
@ -0,0 +1,104 @@
|
|||||||
|
/**
|
||||||
|
* 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 { useDataSourceManager } from '../../../../data-source/data-source';
|
||||||
|
import { useEvent } from '../../../hooks/useEvent';
|
||||||
|
import { EventParam, EventSetting, EventDefinition } from '../../../types';
|
||||||
|
|
||||||
|
const useCurrentEventParams: (event?: EventSetting['event']) => {
|
||||||
|
[key: string]: EventParam;
|
||||||
|
} = (event) => {
|
||||||
|
const { definitions } = useEvent();
|
||||||
|
const definition = definitions?.find((d) => d.name === event?.definition && d.uid === event.uid);
|
||||||
|
const eventParams = definition?.events?.find((e) => e.name === event?.event)?.params;
|
||||||
|
return eventParams;
|
||||||
|
};
|
||||||
|
|
||||||
|
const useStateDefine = ({ definitions }: { definitions: EventDefinition[] }) => {
|
||||||
|
const stateDefine = definitions.filter((item) => item.uid && item.states);
|
||||||
|
const stateDefineOptions = {};
|
||||||
|
stateDefine.forEach((definition) => {
|
||||||
|
stateDefineOptions[definition.uid] = {
|
||||||
|
name: definition.uid,
|
||||||
|
title: `${definition.title}-${definition.uid}`,
|
||||||
|
type: 'object',
|
||||||
|
properties: definition.states,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return { stateDefineOptions };
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useFilterOptions = (recordValues: EventSetting) => {
|
||||||
|
const selectedEvent: EventSetting['event'] = recordValues?.['event'];
|
||||||
|
const currentEventParamsDefine = useCurrentEventParams(selectedEvent);
|
||||||
|
const { definitions } = useEvent();
|
||||||
|
const { stateDefineOptions } = useStateDefine({ definitions });
|
||||||
|
|
||||||
|
const options: EventParam[] = [
|
||||||
|
{
|
||||||
|
name: '_eventParams',
|
||||||
|
title: '事件参数',
|
||||||
|
type: 'object',
|
||||||
|
properties: currentEventParamsDefine,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '_state',
|
||||||
|
title: '组件数据',
|
||||||
|
type: 'object',
|
||||||
|
properties: stateDefineOptions,
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// name: '_system',
|
||||||
|
// title: '系统参数',
|
||||||
|
// type: 'object',
|
||||||
|
// properties: {},
|
||||||
|
// },
|
||||||
|
];
|
||||||
|
const dm = useDataSourceManager();
|
||||||
|
|
||||||
|
const getOption = (opt: EventParam) => {
|
||||||
|
if (opt.type === 'object' && opt.properties) {
|
||||||
|
return {
|
||||||
|
name: opt.name,
|
||||||
|
title: opt.title,
|
||||||
|
children: Object.keys(opt.properties).map((key) =>
|
||||||
|
getOption({
|
||||||
|
...opt.properties[key],
|
||||||
|
name: key,
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (opt.type === 'array' && opt.items) {
|
||||||
|
//TODO: 处理数组
|
||||||
|
return {
|
||||||
|
name: opt.name,
|
||||||
|
title: opt.title,
|
||||||
|
children: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const fieldInterface = dm?.collectionFieldInterfaceManager.getFieldInterface(opt?.interface || opt.type);
|
||||||
|
const { nested, children, operators } = fieldInterface?.filterable || {};
|
||||||
|
const res = {
|
||||||
|
name: opt.name,
|
||||||
|
type: opt.type,
|
||||||
|
// target: opt.target,
|
||||||
|
title: opt?.uiSchema?.title || opt.title || opt.name,
|
||||||
|
schema: opt?.uiSchema,
|
||||||
|
interface: opt.interface,
|
||||||
|
operators:
|
||||||
|
operators?.filter?.((operator) => {
|
||||||
|
return !operator?.visible || operator.visible(opt);
|
||||||
|
}) || [],
|
||||||
|
};
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
return options.map((opt) => getOption(opt));
|
||||||
|
};
|
@ -0,0 +1,47 @@
|
|||||||
|
/**
|
||||||
|
* 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 { useCompile } from '@nocobase/client';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
import { useEvent } from '../../../hooks/useEvent';
|
||||||
|
import { EventParam } from '../../../types';
|
||||||
|
|
||||||
|
export const useVariableOptions = () => {
|
||||||
|
const { definitions } = useEvent();
|
||||||
|
const compile = useCompile();
|
||||||
|
const opts = useMemo(() => {
|
||||||
|
const options = [];
|
||||||
|
const state2Variables = (state: EventParam) => {
|
||||||
|
const children = [];
|
||||||
|
if (state.properties) {
|
||||||
|
Object.keys(state.properties).forEach((key) => {
|
||||||
|
children.push(state2Variables(state.properties[key]));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
label: compile(state?.uiSchema?.title || state.title),
|
||||||
|
value: state.name,
|
||||||
|
children: children,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
options.push({
|
||||||
|
label: '组件数据',
|
||||||
|
value: '$_state',
|
||||||
|
children: definitions
|
||||||
|
.filter((def) => def.uid && def.states)
|
||||||
|
.map((def) => ({
|
||||||
|
label: `${def?.title}-${def.uid}`,
|
||||||
|
value: `${def.uid}`,
|
||||||
|
children: Object.keys(def.states).map((key) => state2Variables({ name: `${key}`, ...def.states[key] })),
|
||||||
|
})),
|
||||||
|
});
|
||||||
|
return options;
|
||||||
|
}, [definitions, compile]);
|
||||||
|
return opts;
|
||||||
|
};
|
@ -21,23 +21,44 @@ import { DynamicComponentProps } from '../../../schema-component/antd/filter/Dyn
|
|||||||
import { FilterContext } from '../../../schema-component/antd/filter/context';
|
import { FilterContext } from '../../../schema-component/antd/filter/context';
|
||||||
import { VariableInput, getShouldChange } from '../../../schema-settings/VariableInput/VariableInput';
|
import { VariableInput, getShouldChange } from '../../../schema-settings/VariableInput/VariableInput';
|
||||||
import { Actions } from './Actions';
|
import { Actions } from './Actions';
|
||||||
import { EnableLinkage } from './components/EnableLinkage';
|
|
||||||
import { ArrayCollapse } from './components/LinkageHeader';
|
|
||||||
import { FormProvider, createSchemaField } from '@formily/react';
|
import { FormProvider, createSchemaField } from '@formily/react';
|
||||||
import { Filter } from '../Filter2';
|
import { ArrayCollapse } from '../components/LinkageHeader';
|
||||||
|
import { Filter } from '../Filter';
|
||||||
|
import { ArrayBase } from '@formily/antd-v5';
|
||||||
|
import { useFilterOptions } from './hooks/useFilterOptions';
|
||||||
|
import { EventDefinition, EventSetting } from '../../types';
|
||||||
|
import { useVariableOptions } from './hooks/useVariableOptions';
|
||||||
|
import { uniqBy } from 'lodash';
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
dynamicComponent: any;
|
dynamicComponent: any;
|
||||||
|
definitions: EventDefinition[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ActionsSetting = withDynamicSchemaProps(
|
export const ActionsSetting = withDynamicSchemaProps(
|
||||||
observer((props: Props) => {
|
observer((props: Props) => {
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
const { options, defaultValues, collectionName, form, variables, localVariables, record, dynamicComponent } =
|
const array = ArrayBase.useArray();
|
||||||
useProps(props); // 新版 UISchema(1.0 之后)中已经废弃了 useProps,这里之所以继续保留是为了兼容旧版的 UISchema
|
const recordValues = ArrayBase.useRecord();
|
||||||
|
const index = ArrayBase.useIndex();
|
||||||
|
const {
|
||||||
|
definitions,
|
||||||
|
options,
|
||||||
|
defaultValues,
|
||||||
|
collectionName,
|
||||||
|
form,
|
||||||
|
variables,
|
||||||
|
localVariables,
|
||||||
|
record,
|
||||||
|
dynamicComponent,
|
||||||
|
} = props;
|
||||||
const { getAllCollectionsInheritChain } = useCollectionManager_deprecated();
|
const { getAllCollectionsInheritChain } = useCollectionManager_deprecated();
|
||||||
const parentRecordData = useCollectionParentRecordData();
|
const parentRecordData = useCollectionParentRecordData();
|
||||||
|
|
||||||
|
const filterOptions = useFilterOptions(recordValues);
|
||||||
|
const variableOptions = useVariableOptions();
|
||||||
|
console.log('variableOptions', variableOptions);
|
||||||
|
|
||||||
const components = useMemo(() => ({ ArrayCollapse, Filter }), []);
|
const components = useMemo(() => ({ ArrayCollapse, Filter }), []);
|
||||||
const schema = useMemo(
|
const schema = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
@ -50,6 +71,10 @@ export const ActionsSetting = withDynamicSchemaProps(
|
|||||||
'x-decorator': 'FormItem',
|
'x-decorator': 'FormItem',
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
accordion: true,
|
accordion: true,
|
||||||
|
titleRender: (item: any, index: number) => {
|
||||||
|
return `动作 ${index + 1}`;
|
||||||
|
},
|
||||||
|
showEmpty: false,
|
||||||
},
|
},
|
||||||
items: {
|
items: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
@ -77,7 +102,7 @@ export const ActionsSetting = withDynamicSchemaProps(
|
|||||||
'x-component': 'Filter',
|
'x-component': 'Filter',
|
||||||
'x-use-component-props': () => {
|
'x-use-component-props': () => {
|
||||||
return {
|
return {
|
||||||
options,
|
options: filterOptions,
|
||||||
className: css`
|
className: css`
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -100,6 +125,10 @@ export const ActionsSetting = withDynamicSchemaProps(
|
|||||||
localVariables,
|
localVariables,
|
||||||
getAllCollectionsInheritChain,
|
getAllCollectionsInheritChain,
|
||||||
})}
|
})}
|
||||||
|
returnScope={(scope) => {
|
||||||
|
// console.log('scope', [...scope, ...variableOptions]);
|
||||||
|
return uniqBy([...scope, ...variableOptions], 'key');
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -161,6 +190,7 @@ export const ActionsSetting = withDynamicSchemaProps(
|
|||||||
props,
|
props,
|
||||||
record,
|
record,
|
||||||
variables,
|
variables,
|
||||||
|
filterOptions,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
const value = useMemo(
|
const value = useMemo(
|
||||||
@ -168,22 +198,22 @@ export const ActionsSetting = withDynamicSchemaProps(
|
|||||||
[dynamicComponent, fieldSchema, options],
|
[dynamicComponent, fieldSchema, options],
|
||||||
);
|
);
|
||||||
|
|
||||||
// return <SchemaComponent components={components} schema={schema} />;
|
return <SchemaComponent components={components} schema={schema} />;
|
||||||
|
|
||||||
return (
|
// return (
|
||||||
// 这里使用 SubFormProvider 包裹,是为了让子表格的联动规则中 “当前对象” 的配置显示正确
|
// // 这里使用 SubFormProvider 包裹,是为了让子表格的联动规则中 “当前对象” 的配置显示正确
|
||||||
// <FormProvider form={form}>
|
// // <FormProvider form={form}>
|
||||||
<SubFormProvider value={{ value: null, collection: { name: collectionName } as any }}>
|
// <SubFormProvider value={{ value: null, collection: { name: collectionName } as any }}>
|
||||||
<RecordProvider record={record} parent={parentRecordData}>
|
// <RecordProvider record={record} parent={parentRecordData}>
|
||||||
<FilterContext.Provider value={value}>
|
// <FilterContext.Provider value={value}>
|
||||||
<CollectionProvider name={collectionName}>
|
// <CollectionProvider name={collectionName}>
|
||||||
<SchemaComponent components={components} schema={schema} />
|
// <SchemaComponent components={components} schema={schema} />
|
||||||
</CollectionProvider>
|
// </CollectionProvider>
|
||||||
</FilterContext.Provider>
|
// </FilterContext.Provider>
|
||||||
</RecordProvider>
|
// </RecordProvider>
|
||||||
</SubFormProvider>
|
// </SubFormProvider>
|
||||||
// </FormProvider>
|
// // </FormProvider>
|
||||||
);
|
// );
|
||||||
}),
|
}),
|
||||||
{ displayName: 'ActionsSetting' },
|
{ displayName: 'ActionsSetting' },
|
||||||
);
|
);
|
||||||
|
@ -7,19 +7,19 @@
|
|||||||
* For more information, please refer to: https://www.nocobase.com/agreement.
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import { useControllableValue } from 'ahooks';
|
import { useControllableValue } from 'ahooks';
|
||||||
import { Card, Space, TreeSelect } from 'antd';
|
import { Card, Space, TreeSelect } from 'antd';
|
||||||
import { EventDefinition } from '../../types';
|
import { EventDefinition, EventSetting } from '../types';
|
||||||
|
|
||||||
export default function EventSelect(props: {
|
export default function EventSelect(props: {
|
||||||
definitions: EventDefinition[];
|
definitions?: EventDefinition[];
|
||||||
value: any;
|
value?: EventSetting['event'];
|
||||||
onChange: (v: any) => void;
|
onChange?: (v: EventSetting['event']) => void;
|
||||||
className?: string;
|
className?: string;
|
||||||
}) {
|
}) {
|
||||||
const { definitions, className } = props;
|
const { definitions, className } = props;
|
||||||
const [state, setState] = useControllableValue<String>(props, {
|
const [state, setState] = useControllableValue<EventSetting['event']>(props, {
|
||||||
defaultValue: undefined,
|
defaultValue: undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -29,21 +29,32 @@ export default function EventSelect(props: {
|
|||||||
selectable: false,
|
selectable: false,
|
||||||
children:
|
children:
|
||||||
module?.events?.map((event) => ({
|
module?.events?.map((event) => ({
|
||||||
value: module.name + '.' + event.name,
|
value: `${module.name}.${event.name}${module.uid ? `.${module.uid}` : ''}`,
|
||||||
title: event.title,
|
title: event.title,
|
||||||
})) || [],
|
})) || [],
|
||||||
}));
|
}));
|
||||||
treeData = treeData?.filter((item) => item.children.length > 0);
|
treeData = treeData?.filter((item) => item.children.length > 0);
|
||||||
|
|
||||||
|
const selectedEvent = useMemo(() => {
|
||||||
|
if (!state) return undefined;
|
||||||
|
return `${state.definition}.${state.event}${state.uid ? `.${state.uid}` : ''}`;
|
||||||
|
}, [state]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TreeSelect
|
<TreeSelect
|
||||||
value={state}
|
value={selectedEvent}
|
||||||
dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
|
dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
|
||||||
placeholder="Please select"
|
placeholder="Please select"
|
||||||
allowClear
|
allowClear
|
||||||
treeDefaultExpandAll
|
treeDefaultExpandAll
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
setState(value);
|
console.log('value', value);
|
||||||
|
const [definition, event, uid] = (value as any).split('.');
|
||||||
|
setState({
|
||||||
|
definition,
|
||||||
|
event,
|
||||||
|
uid,
|
||||||
|
});
|
||||||
}}
|
}}
|
||||||
treeData={treeData}
|
treeData={treeData}
|
||||||
className={className}
|
className={className}
|
@ -1,44 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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 { ArrayBase } from '@formily/antd-v5';
|
|
||||||
import { Switch } from 'antd';
|
|
||||||
import React from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
|
|
||||||
export const EnableLinkage = React.forwardRef((props: any, ref) => {
|
|
||||||
const array = ArrayBase.useArray();
|
|
||||||
const index = ArrayBase.useIndex(props.index);
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Switch
|
|
||||||
{...props}
|
|
||||||
checkedChildren={t('On')}
|
|
||||||
unCheckedChildren={t('Off')}
|
|
||||||
checked={!array?.field?.value[index].disabled}
|
|
||||||
size={'small'}
|
|
||||||
style={{
|
|
||||||
transition: 'all 0.25s ease-in-out',
|
|
||||||
color: 'rgba(0, 0, 0, 0.8)',
|
|
||||||
fontSize: 16,
|
|
||||||
marginLeft: 6,
|
|
||||||
marginBottom: 3,
|
|
||||||
}}
|
|
||||||
onChange={(checked, e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
array.field.value.splice(index, 1, { ...array?.field?.value[index], disabled: !checked });
|
|
||||||
}}
|
|
||||||
onClick={(checked, e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
EnableLinkage.displayName = 'EnableLinkage';
|
|
@ -1,139 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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 { css } from '@emotion/css';
|
|
||||||
import { observer, useFieldSchema } from '@formily/react';
|
|
||||||
import React, { useMemo } from 'react';
|
|
||||||
import { withDynamicSchemaProps } from '../../../hoc/withDynamicSchemaProps';
|
|
||||||
import { InputNumber, SchemaComponent, useProps } from '../../../schema-component';
|
|
||||||
import { ArrayCollapse } from './components/LinkageHeader';
|
|
||||||
import { FormProvider, createSchemaField } from '@formily/react';
|
|
||||||
import { ActionsSetting } from '../ActionsSetting';
|
|
||||||
import EventSelect from './EventSelect';
|
|
||||||
export interface Props {
|
|
||||||
dynamicComponent: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const EventsSetting = withDynamicSchemaProps(
|
|
||||||
observer((props: Props) => {
|
|
||||||
const components = useMemo(() => ({ ArrayCollapse, ActionsSetting, EventSelect }), []);
|
|
||||||
const { definitions } = useProps(props);
|
|
||||||
|
|
||||||
const schema = useMemo(
|
|
||||||
() => ({
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
events: {
|
|
||||||
type: 'array',
|
|
||||||
// default: defaultValues,
|
|
||||||
'x-component': 'ArrayCollapse',
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component-props': {
|
|
||||||
accordion: true,
|
|
||||||
},
|
|
||||||
items: {
|
|
||||||
type: 'object',
|
|
||||||
'x-component': 'ArrayCollapse.CollapsePanel',
|
|
||||||
'x-component-props': {
|
|
||||||
// extra: <EnableLinkage />,
|
|
||||||
},
|
|
||||||
properties: {
|
|
||||||
layout: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'FormLayout',
|
|
||||||
'x-component-props': {
|
|
||||||
labelStyle: {
|
|
||||||
marginTop: '4px',
|
|
||||||
},
|
|
||||||
labelCol: 8,
|
|
||||||
wrapperCol: 16,
|
|
||||||
},
|
|
||||||
properties: {
|
|
||||||
eventTitle: {
|
|
||||||
'x-component': 'h4',
|
|
||||||
'x-content': '{{ t("触发事件") }}',
|
|
||||||
},
|
|
||||||
event: {
|
|
||||||
'x-component': EventSelect,
|
|
||||||
'x-component-props': {
|
|
||||||
definitions,
|
|
||||||
className: css`
|
|
||||||
margin-bottom: 12px;
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
actionTitle: {
|
|
||||||
'x-component': 'h4',
|
|
||||||
'x-content': '{{ t("执行动作") }}',
|
|
||||||
},
|
|
||||||
actions: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': ActionsSetting,
|
|
||||||
'x-component-props': {
|
|
||||||
...props,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
remove: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'ArrayCollapse.Remove',
|
|
||||||
},
|
|
||||||
// moveUp: {
|
|
||||||
// type: 'void',
|
|
||||||
// 'x-component': 'ArrayCollapse.MoveUp',
|
|
||||||
// },
|
|
||||||
// moveDown: {
|
|
||||||
// type: 'void',
|
|
||||||
// 'x-component': 'ArrayCollapse.MoveDown',
|
|
||||||
// },
|
|
||||||
// copy: {
|
|
||||||
// type: 'void',
|
|
||||||
// 'x-component': 'ArrayCollapse.Copy',
|
|
||||||
// },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
properties: {
|
|
||||||
add: {
|
|
||||||
type: 'void',
|
|
||||||
title: '{{ t("Add events") }}',
|
|
||||||
'x-component': 'ArrayCollapse.Addition',
|
|
||||||
'x-reactions': {
|
|
||||||
dependencies: ['rules'],
|
|
||||||
fulfill: {
|
|
||||||
state: {
|
|
||||||
// disabled: '{{$deps[0].length >= 3}}',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
|
|
||||||
return <SchemaComponent components={components} schema={schema} />;
|
|
||||||
// return (
|
|
||||||
// // 这里使用 SubFormProvider 包裹,是为了让子表格的联动规则中 “当前对象” 的配置显示正确
|
|
||||||
// // <FormProvider form={form}>
|
|
||||||
// <SubFormProvider value={{ value: null, collection: { name: collectionName } as any }}>
|
|
||||||
// <RecordProvider record={record} parent={parentRecordData}>
|
|
||||||
// <FilterContext.Provider value={value}>
|
|
||||||
// <CollectionProvider name={collectionName}>
|
|
||||||
// <SchemaComponent components={components} schema={schema} />
|
|
||||||
// </CollectionProvider>
|
|
||||||
// </FilterContext.Provider>
|
|
||||||
// </RecordProvider>
|
|
||||||
// </SubFormProvider>
|
|
||||||
// // </FormProvider>
|
|
||||||
// );
|
|
||||||
}),
|
|
||||||
{ displayName: 'Evets' },
|
|
||||||
);
|
|
@ -18,6 +18,7 @@ import { FilterAction } from './FilterAction';
|
|||||||
import { FilterGroup } from './FilterGroup';
|
import { FilterGroup } from './FilterGroup';
|
||||||
import { SaveDefaultValue } from './SaveDefaultValue';
|
import { SaveDefaultValue } from './SaveDefaultValue';
|
||||||
import { FilterContext, FilterContextProps } from './context';
|
import { FilterContext, FilterContextProps } from './context';
|
||||||
|
import { ArrayBase } from '@formily/antd-v5';
|
||||||
|
|
||||||
const useDef = (options: UseRequestOptions) => {
|
const useDef = (options: UseRequestOptions) => {
|
||||||
const field = useField<ObjectFieldModel>();
|
const field = useField<ObjectFieldModel>();
|
||||||
@ -35,9 +36,8 @@ export interface FilterProps extends Omit<FilterContextProps, 'field' | 'fieldSc
|
|||||||
export const Filter: any = withDynamicSchemaProps(
|
export const Filter: any = withDynamicSchemaProps(
|
||||||
observer((props: any) => {
|
observer((props: any) => {
|
||||||
const { useDataSource = useDef } = props;
|
const { useDataSource = useDef } = props;
|
||||||
console.log('Filter111', props);
|
|
||||||
// 新版 UISchema(1.0 之后)中已经废弃了 useProps,这里之所以继续保留是为了兼容旧版的 UISchema
|
// 新版 UISchema(1.0 之后)中已经废弃了 useProps,这里之所以继续保留是为了兼容旧版的 UISchema
|
||||||
const { options, dynamicComponent, className, collectionName } = useProps(props);
|
const { options, dynamicComponent, className, collectionName } = props;
|
||||||
|
|
||||||
const field = useField<ObjectFieldModel>();
|
const field = useField<ObjectFieldModel>();
|
||||||
const fieldSchema: any = useFieldSchema();
|
const fieldSchema: any = useFieldSchema();
|
||||||
@ -46,6 +46,10 @@ export const Filter: any = withDynamicSchemaProps(
|
|||||||
field.dataSource = data?.data || [];
|
field.dataSource = data?.data || [];
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
const array = ArrayBase.useArray();
|
||||||
|
const index = ArrayBase.useIndex();
|
||||||
|
console.log('array', array);
|
||||||
|
console.log('index', index);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (fieldSchema.defaultValue) {
|
if (fieldSchema.defaultValue) {
|
||||||
@ -64,6 +68,7 @@ export const Filter: any = withDynamicSchemaProps(
|
|||||||
collectionName,
|
collectionName,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
{index}
|
||||||
<FilterGroup {...props} bordered={false} />
|
<FilterGroup {...props} bordered={false} />
|
||||||
</FilterContext.Provider>
|
</FilterContext.Provider>
|
||||||
</div>
|
</div>
|
@ -43,7 +43,7 @@ export const SaveDefaultValue = (props) => {
|
|||||||
});
|
});
|
||||||
dn.refresh();
|
dn.refresh();
|
||||||
filterSchema.default = defaultValue;
|
filterSchema.default = defaultValue;
|
||||||
console.log('filterSchema', defaultValue);
|
// console.log('filterSchema', defaultValue);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t('Save conditions')}
|
{t('Save conditions')}
|
@ -16,38 +16,13 @@ import { Badge, Card, Collapse, CollapsePanelProps, CollapseProps, Empty, Input
|
|||||||
import { cloneDeep } from 'lodash';
|
import { cloneDeep } from 'lodash';
|
||||||
import React, { Fragment, useEffect, useState } from 'react';
|
import React, { Fragment, useEffect, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useToken } from '../../../../style';
|
import { useToken } from '../../../style';
|
||||||
import { arrayCollapseItemStyle } from './LinkageHeader.style';
|
import { arrayCollapseItemStyle } from './LinkageHeader.style';
|
||||||
|
|
||||||
const LinkageRulesTitle = (props) => {
|
|
||||||
const array = ArrayBase.useArray();
|
|
||||||
const index = ArrayBase.useIndex(props.index);
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const value = array?.field?.value[index];
|
|
||||||
return <div>{`事件 ${index + 1}`}</div>;
|
|
||||||
// return (
|
|
||||||
// <Input.TextArea
|
|
||||||
// value={value.title}
|
|
||||||
// defaultValue={t('Linkage rule')}
|
|
||||||
// onChange={(ev) => {
|
|
||||||
// ev.stopPropagation();
|
|
||||||
// array.field.value.splice(index, 1, { ...value, title: ev.target.value });
|
|
||||||
// }}
|
|
||||||
// onBlur={(ev) => {
|
|
||||||
// ev.stopPropagation();
|
|
||||||
// array.field.value.splice(index, 1, { ...value, title: ev.target.value });
|
|
||||||
// }}
|
|
||||||
// autoSize
|
|
||||||
// style={{ width: '70%', border: 'none' }}
|
|
||||||
// onClick={(e) => {
|
|
||||||
// e.stopPropagation();
|
|
||||||
// }}
|
|
||||||
// />
|
|
||||||
// );
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface IArrayCollapseProps extends CollapseProps {
|
export interface IArrayCollapseProps extends CollapseProps {
|
||||||
defaultOpenPanelCount?: number;
|
defaultOpenPanelCount?: number;
|
||||||
|
titleRender?: (item: any, index: number) => React.ReactNode;
|
||||||
|
showEmpty?: boolean;
|
||||||
}
|
}
|
||||||
type ComposedArrayCollapse = React.FC<React.PropsWithChildren<IArrayCollapseProps>> & {
|
type ComposedArrayCollapse = React.FC<React.PropsWithChildren<IArrayCollapseProps>> & {
|
||||||
CollapsePanel?: React.FC<React.PropsWithChildren<CollapsePanelProps>>;
|
CollapsePanel?: React.FC<React.PropsWithChildren<CollapsePanelProps>>;
|
||||||
@ -103,6 +78,7 @@ const insertActiveKeys = (activeKeys: number[], index: number) => {
|
|||||||
|
|
||||||
export const ArrayCollapse: ComposedArrayCollapse = observer(
|
export const ArrayCollapse: ComposedArrayCollapse = observer(
|
||||||
(props: IArrayCollapseProps) => {
|
(props: IArrayCollapseProps) => {
|
||||||
|
const { titleRender, showEmpty = true } = props;
|
||||||
const field = useField<ArrayField>();
|
const field = useField<ArrayField>();
|
||||||
const dataSource = Array.isArray(field.value) ? field.value : [];
|
const dataSource = Array.isArray(field.value) ? field.value : [];
|
||||||
const [activeKeys, setActiveKeys] = useState<number[]>(
|
const [activeKeys, setActiveKeys] = useState<number[]>(
|
||||||
@ -124,6 +100,7 @@ export const ArrayCollapse: ComposedArrayCollapse = observer(
|
|||||||
return addition;
|
return addition;
|
||||||
}, null);
|
}, null);
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderEmpty = () => {
|
const renderEmpty = () => {
|
||||||
if (dataSource.length) return;
|
if (dataSource.length) return;
|
||||||
return (
|
return (
|
||||||
@ -144,8 +121,7 @@ export const ArrayCollapse: ComposedArrayCollapse = observer(
|
|||||||
onChange={(keys: string[]) => setActiveKeys(toArr(keys).map(Number))}
|
onChange={(keys: string[]) => setActiveKeys(toArr(keys).map(Number))}
|
||||||
className={props.className}
|
className={props.className}
|
||||||
style={arrayCollapseItemStyle}
|
style={arrayCollapseItemStyle}
|
||||||
>
|
items={dataSource.map((item, index) => {
|
||||||
{dataSource.map((item, index) => {
|
|
||||||
const items = Array.isArray(schema.items) ? schema.items[index] || schema.items[0] : schema.items;
|
const items = Array.isArray(schema.items) ? schema.items[index] || schema.items[0] : schema.items;
|
||||||
|
|
||||||
const panelProps = field.query(`${field.address}.${index}`).get('componentProps');
|
const panelProps = field.query(`${field.address}.${index}`).get('componentProps');
|
||||||
@ -172,13 +148,12 @@ export const ArrayCollapse: ComposedArrayCollapse = observer(
|
|||||||
<Badge size="small" className="errors-badge" count={errors.length}>
|
<Badge size="small" className="errors-badge" count={errors.length}>
|
||||||
{header}
|
{header}
|
||||||
</Badge>
|
</Badge>
|
||||||
) : (
|
) : titleRender ? (
|
||||||
<LinkageRulesTitle item={item.initialValue || item} index={index} />
|
titleRender(item, index)
|
||||||
)}
|
) : null}
|
||||||
</ArrayBase.Item>
|
</ArrayBase.Item>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const extra = (
|
const extra = (
|
||||||
<ArrayBase.Item index={index} record={item}>
|
<ArrayBase.Item index={index} record={item}>
|
||||||
<RecursionField
|
<RecursionField
|
||||||
@ -195,25 +170,28 @@ export const ArrayCollapse: ComposedArrayCollapse = observer(
|
|||||||
);
|
);
|
||||||
|
|
||||||
const content = (
|
const content = (
|
||||||
<RecursionField
|
<ArrayBase.Item index={index} key={index} record={item}>
|
||||||
schema={items}
|
<RecursionField
|
||||||
name={index}
|
schema={items}
|
||||||
filterProperties={(schema) => {
|
name={index}
|
||||||
if (isIndexComponent(schema)) return false;
|
filterProperties={(schema) => {
|
||||||
if (isOperationComponent(schema)) return false;
|
if (isIndexComponent(schema)) return false;
|
||||||
return true;
|
if (isOperationComponent(schema)) return false;
|
||||||
}}
|
return true;
|
||||||
/>
|
}}
|
||||||
);
|
/>
|
||||||
return (
|
</ArrayBase.Item>
|
||||||
<Collapse.Panel {...props} {...panelProps} forceRender key={index} header={header()} extra={extra}>
|
|
||||||
<ArrayBase.Item index={index} key={index} record={item}>
|
|
||||||
{content}
|
|
||||||
</ArrayBase.Item>
|
|
||||||
</Collapse.Panel>
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
forceRender: true,
|
||||||
|
key: index,
|
||||||
|
label: header(),
|
||||||
|
extra: extra,
|
||||||
|
children: content,
|
||||||
|
};
|
||||||
})}
|
})}
|
||||||
</Collapse>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
@ -222,7 +200,7 @@ export const ArrayCollapse: ComposedArrayCollapse = observer(
|
|||||||
setActiveKeys(insertActiveKeys(activeKeys, index));
|
setActiveKeys(insertActiveKeys(activeKeys, index));
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{renderEmpty()}
|
{showEmpty && renderEmpty()}
|
||||||
{renderItems()}
|
{renderItems()}
|
||||||
{renderAddition()}
|
{renderAddition()}
|
||||||
</ArrayBase>
|
</ArrayBase>
|
@ -7,6 +7,6 @@
|
|||||||
* For more information, please refer to: https://www.nocobase.com/agreement.
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const arrayCollapseItemStyle = {
|
export const useFilterOptions = () => {
|
||||||
marginBottom: 10,
|
return { filterOptions: [] };
|
||||||
};
|
};
|
@ -21,12 +21,17 @@ import {
|
|||||||
useFormBlockType,
|
useFormBlockType,
|
||||||
useRecord,
|
useRecord,
|
||||||
} from '@nocobase/client';
|
} from '@nocobase/client';
|
||||||
import React from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import { ISchema, useField } from '@formily/react';
|
import { ISchema, useField } from '@formily/react';
|
||||||
import { SchemaSettingsKey, useEvent } from '..';
|
import { SchemaSettingsKey, useEvent } from '..';
|
||||||
import { useFieldSchema } from '@formily/react';
|
import { useFieldSchema } from '@formily/react';
|
||||||
import { useLinkageCollectionFieldOptions } from './ActionsSetting/action-hooks';
|
import { useLinkageCollectionFieldOptions } from './ActionsSetting/action-hooks';
|
||||||
import { EventsSetting } from './EventsSetting';
|
import { ActionsSetting } from './ActionsSetting';
|
||||||
|
import EventSelect from './EventSelect';
|
||||||
|
import { ArrayCollapse } from './components/LinkageHeader';
|
||||||
|
import { css } from '@emotion/css';
|
||||||
|
import { useFilterOptions } from './hooks/useFilterOptions';
|
||||||
|
import { FormItem, FormLayout } from '@formily/antd-v5';
|
||||||
|
|
||||||
// packages/core/client/src/schema-settings/SchemaSettings.tsx
|
// packages/core/client/src/schema-settings/SchemaSettings.tsx
|
||||||
export const EventSettingItem = (props) => {
|
export const EventSettingItem = (props) => {
|
||||||
@ -38,7 +43,6 @@ export const EventSettingItem = (props) => {
|
|||||||
const { definitions, register } = useEvent();
|
const { definitions, register } = useEvent();
|
||||||
const { dn } = useDesignable();
|
const { dn } = useDesignable();
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
console.log('definitions', definitions);
|
|
||||||
const { readPretty, Component, afterSubmit } = props;
|
const { readPretty, Component, afterSubmit } = props;
|
||||||
const collectionName = 't_aierml1wni1';
|
const collectionName = 't_aierml1wni1';
|
||||||
const options = useLinkageCollectionFilterOptions(collectionName);
|
const options = useLinkageCollectionFilterOptions(collectionName);
|
||||||
@ -52,7 +56,7 @@ export const EventSettingItem = (props) => {
|
|||||||
return (
|
return (
|
||||||
<SchemaSettingsModalItem
|
<SchemaSettingsModalItem
|
||||||
title={'Event Setting'}
|
title={'Event Setting'}
|
||||||
components={{ EventsSetting }}
|
components={{ ArrayCollapse, ActionsSetting, EventSelect, FormLayout }}
|
||||||
initialValues={{}}
|
initialValues={{}}
|
||||||
scope={{}}
|
scope={{}}
|
||||||
width={1000}
|
width={1000}
|
||||||
@ -62,38 +66,100 @@ export const EventSettingItem = (props) => {
|
|||||||
title: '事件配置',
|
title: '事件配置',
|
||||||
properties: {
|
properties: {
|
||||||
events: {
|
events: {
|
||||||
'x-component': EventsSetting,
|
type: 'array',
|
||||||
'x-use-component-props': () => {
|
// default: defaultValues,
|
||||||
return {
|
'x-component': 'ArrayCollapse',
|
||||||
definitions,
|
'x-decorator': 'FormItem',
|
||||||
options,
|
'x-component-props': {
|
||||||
defaultValues: undefined,
|
accordion: true,
|
||||||
linkageOptions,
|
titleRender: (item: any, index: number) => {
|
||||||
category: 'default',
|
return `事件 ${index + 1}`;
|
||||||
elementType: 'field',
|
},
|
||||||
collectionName,
|
},
|
||||||
form,
|
items: {
|
||||||
variables,
|
type: 'object',
|
||||||
localVariables,
|
'x-component': 'ArrayCollapse.CollapsePanel',
|
||||||
record,
|
'x-component-props': {
|
||||||
formBlockType,
|
// extra: <EnableLinkage />,
|
||||||
};
|
},
|
||||||
|
properties: {
|
||||||
|
layout: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'FormLayout',
|
||||||
|
'x-component-props': {
|
||||||
|
labelStyle: {
|
||||||
|
marginTop: '4px',
|
||||||
|
},
|
||||||
|
labelCol: 8,
|
||||||
|
wrapperCol: 16,
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
eventTitle: {
|
||||||
|
'x-component': 'h4',
|
||||||
|
'x-content': '{{ t("触发事件") }}',
|
||||||
|
},
|
||||||
|
event: {
|
||||||
|
'x-component': EventSelect,
|
||||||
|
'x-component-props': {
|
||||||
|
definitions,
|
||||||
|
className: css`
|
||||||
|
margin-bottom: 12px;
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
actionTitle: {
|
||||||
|
'x-component': 'h4',
|
||||||
|
'x-content': '{{ t("执行动作") }}',
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': ActionsSetting,
|
||||||
|
'x-use-component-props': () => {
|
||||||
|
return {
|
||||||
|
definitions,
|
||||||
|
options,
|
||||||
|
linkageOptions,
|
||||||
|
category: 'default',
|
||||||
|
elementType: 'field',
|
||||||
|
collectionName,
|
||||||
|
form,
|
||||||
|
variables,
|
||||||
|
localVariables,
|
||||||
|
record,
|
||||||
|
formBlockType,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
remove: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'ArrayCollapse.Remove',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
add: {
|
||||||
|
type: 'void',
|
||||||
|
title: '{{ t("Add events") }}',
|
||||||
|
'x-component': 'ArrayCollapse.Addition',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
} as ISchema
|
} as ISchema
|
||||||
}
|
}
|
||||||
onSubmit={({ events }) => {
|
onSubmit={({ events }) => {
|
||||||
console.log('onSubmit', events);
|
console.log('todo onSubmit', JSON.parse(JSON.stringify(events)));
|
||||||
fieldSchema[SchemaSettingsKey] = events;
|
// fieldSchema[SchemaSettingsKey] = events;
|
||||||
dn.emit('patch', {
|
// dn.emit('patch', {
|
||||||
schema: {
|
// schema: {
|
||||||
'x-uid': fieldSchema['x-uid'],
|
// 'x-uid': fieldSchema['x-uid'],
|
||||||
[SchemaSettingsKey]: events,
|
// [SchemaSettingsKey]: events,
|
||||||
},
|
// },
|
||||||
});
|
// });
|
||||||
register(events);
|
// register(events);
|
||||||
dn.refresh();
|
// dn.refresh();
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -20,6 +20,8 @@ export interface EventParam {
|
|||||||
[key: string]: EventParam;
|
[key: string]: EventParam;
|
||||||
};
|
};
|
||||||
items?: EventParam;
|
items?: EventParam;
|
||||||
|
interface?: string;
|
||||||
|
uiSchema?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 事件动作 */
|
/** 事件动作 */
|
||||||
@ -42,6 +44,7 @@ export interface EventEvent {
|
|||||||
params?: {
|
params?: {
|
||||||
[key: string]: EventParam;
|
[key: string]: EventParam;
|
||||||
};
|
};
|
||||||
|
value?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 事件定义 */
|
/** 事件定义 */
|
||||||
@ -60,7 +63,11 @@ export interface EventDefinition {
|
|||||||
|
|
||||||
/** 事件设置 */
|
/** 事件设置 */
|
||||||
export interface EventSetting {
|
export interface EventSetting {
|
||||||
event: string;
|
event: {
|
||||||
|
definition: string;
|
||||||
|
event: string;
|
||||||
|
uid?: string;
|
||||||
|
};
|
||||||
/** 标识同一类型组件的不同实例 */
|
/** 标识同一类型组件的不同实例 */
|
||||||
uid?: string;
|
uid?: string;
|
||||||
condition: string;
|
condition: string;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user