mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-05-07 22:49:26 +08:00
feat: support action add
This commit is contained in:
parent
e973756d5a
commit
c86d084f5a
@ -7,10 +7,10 @@
|
|||||||
* For more information, please refer to: https://www.nocobase.com/agreement.
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ArrayField as ArrayFieldModel, VoidField } from '@formily/core';
|
import { ArrayField as ArrayFieldModel, VoidField, ObjectField as ObjectFieldModel } from '@formily/core';
|
||||||
import { ArrayField, ObjectField, observer, useField } from '@formily/react';
|
import { ArrayField, ObjectField, observer, useField } from '@formily/react';
|
||||||
import { Space, TreeSelect } from 'antd';
|
import { Button, Cascader, Input, Space, TreeSelect } from 'antd';
|
||||||
import React, { useCallback, useMemo } from 'react';
|
import React, { useCallback, useContext, useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { withDynamicSchemaProps } from '../../../hoc/withDynamicSchemaProps';
|
import { withDynamicSchemaProps } from '../../../hoc/withDynamicSchemaProps';
|
||||||
import {
|
import {
|
||||||
@ -20,40 +20,64 @@ import {
|
|||||||
} from './LinkageRuleAction';
|
} from './LinkageRuleAction';
|
||||||
import { RemoveActionContext } from './context';
|
import { RemoveActionContext } from './context';
|
||||||
import { useControllableValue } from 'ahooks';
|
import { useControllableValue } from 'ahooks';
|
||||||
|
import { CloseCircleOutlined } from '@ant-design/icons';
|
||||||
|
import { useActionOptions } from './hooks/useActionOptions';
|
||||||
|
|
||||||
const ActionSelect = (props) => {
|
const ActionParams = observer((props) => {
|
||||||
const { t } = useTranslation();
|
const field = useField<ArrayFieldModel>();
|
||||||
const { definitions, className } = props;
|
|
||||||
const [state, setState] = useControllableValue<String>(props, {
|
|
||||||
defaultValue: undefined,
|
|
||||||
});
|
|
||||||
let treeData = definitions?.map((module) => ({
|
|
||||||
value: module.name,
|
|
||||||
title: module.title + ' - ' + module.uid,
|
|
||||||
selectable: false,
|
|
||||||
children:
|
|
||||||
module?.events?.map((event) => ({
|
|
||||||
value: module.name + '.' + event.name,
|
|
||||||
title: event.title,
|
|
||||||
})) || [],
|
|
||||||
}));
|
|
||||||
treeData = treeData?.filter((item) => item.children.length > 0);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TreeSelect
|
<div>
|
||||||
value={state}
|
{field?.value?.map((item, index) => (
|
||||||
dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
|
<div key={index}>
|
||||||
placeholder="Please select"
|
<Input />
|
||||||
allowClear
|
</div>
|
||||||
treeDefaultExpandAll
|
))}
|
||||||
onChange={(value) => {
|
</div>
|
||||||
setState(value);
|
|
||||||
}}
|
|
||||||
treeData={treeData}
|
|
||||||
className={className}
|
|
||||||
/>
|
|
||||||
);
|
);
|
||||||
};
|
});
|
||||||
|
|
||||||
|
export const ActionRow = observer(
|
||||||
|
(props: any): any => {
|
||||||
|
const { onRemove } = props;
|
||||||
|
const options = useActionOptions();
|
||||||
|
const field = useField<any>();
|
||||||
|
const onClick = useCallback(() => {
|
||||||
|
console.log('field2', field);
|
||||||
|
// const f = field.query('.params').take() as ObjectFieldModel;
|
||||||
|
// field.val = field.data || {};
|
||||||
|
// field.data.params = field.data.params || [];
|
||||||
|
// field.data.params.push({});
|
||||||
|
// const items = f.value || [];
|
||||||
|
// items.push({});
|
||||||
|
// f.value = items;
|
||||||
|
// f.initialValue = items;
|
||||||
|
}, [field]);
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Space>
|
||||||
|
<Cascader
|
||||||
|
// value={state}
|
||||||
|
options={options}
|
||||||
|
onChange={(value) => {
|
||||||
|
console.log('value', value);
|
||||||
|
// setState(value);
|
||||||
|
}}
|
||||||
|
></Cascader>
|
||||||
|
<div>
|
||||||
|
<ArrayField name={'params'} component={[ActionParams, {}]} disabled={false} />
|
||||||
|
<Button onClick={onClick}>添加参数</Button>
|
||||||
|
</div>
|
||||||
|
{!props.disabled && (
|
||||||
|
<a role="button" aria-label="icon-close">
|
||||||
|
<CloseCircleOutlined onClick={onRemove} style={{ color: '#bfbfbf' }} />
|
||||||
|
</a>
|
||||||
|
)}
|
||||||
|
</Space>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
{ displayName: 'ActionRow' },
|
||||||
|
);
|
||||||
|
|
||||||
export const Action = observer(
|
export const Action = observer(
|
||||||
(props: any): any => {
|
(props: any): any => {
|
||||||
@ -67,13 +91,16 @@ export const Action = observer(
|
|||||||
field: FormFieldLinkageRuleAction,
|
field: FormFieldLinkageRuleAction,
|
||||||
style: FormStyleLinkageRuleAction,
|
style: FormStyleLinkageRuleAction,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// console.log('field?.value', field.value);
|
||||||
|
|
||||||
return field?.value?.map((item, index) => {
|
return field?.value?.map((item, index) => {
|
||||||
return (
|
return (
|
||||||
<RemoveActionContext.Provider key={index} value={() => field.remove(index)}>
|
<RemoveActionContext.Provider key={index} value={() => field.remove(index)}>
|
||||||
<ObjectField name={index} component={[ActionSelect, { ...props, options: linkageOptions }]} />
|
<ObjectField name={index} component={[ActionRow]} />
|
||||||
</RemoveActionContext.Provider>
|
</RemoveActionContext.Provider>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
{ displayName: 'LinkageRuleActions' },
|
{ displayName: 'Action' },
|
||||||
);
|
);
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
/**
|
||||||
|
* 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 { Field, ObjectField, observer, useField } from '@formily/react';
|
||||||
|
import { Button, Input, Space } from 'antd';
|
||||||
|
import React from 'react';
|
||||||
|
import { ArrayField as ArrayFieldModel } from '@formily/core';
|
||||||
|
import { CloseCircleOutlined } from '@ant-design/icons';
|
||||||
|
|
||||||
|
const ActionParams = observer((props: any) => {
|
||||||
|
return (
|
||||||
|
<Space>
|
||||||
|
<Field name="name" component={[Input]} />
|
||||||
|
<span>等于</span>
|
||||||
|
<Field name="value" component={[Input]} />
|
||||||
|
{!props.disabled && (
|
||||||
|
<a role="button" aria-label="icon-close">
|
||||||
|
<CloseCircleOutlined onClick={props.onRemove} style={{ color: '#bfbfbf' }} />
|
||||||
|
</a>
|
||||||
|
)}
|
||||||
|
</Space>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
export const ActionParamsField = observer((props: { action: string }) => {
|
||||||
|
const field = useField<ArrayFieldModel>();
|
||||||
|
const { action } = props;
|
||||||
|
console.log('ActionParamsField action', props);
|
||||||
|
return (
|
||||||
|
<Space direction="vertical">
|
||||||
|
{field?.value?.map((item, index) => (
|
||||||
|
<ObjectField key={index} name={index} component={[ActionParams, { onRemove: () => field.remove(index) }]} />
|
||||||
|
))}
|
||||||
|
<Button type="link" onClick={() => field.push({})}>
|
||||||
|
添加参数
|
||||||
|
</Button>
|
||||||
|
</Space>
|
||||||
|
);
|
||||||
|
});
|
@ -8,13 +8,15 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { ArrayField as ArrayFieldModel, VoidField } from '@formily/core';
|
import { ArrayField as ArrayFieldModel, VoidField } from '@formily/core';
|
||||||
import { ArrayField, ObjectField, observer, useField } from '@formily/react';
|
import { ArrayField, ObjectField, observer, useField, Field } from '@formily/react';
|
||||||
import { Space } from 'antd';
|
import { Space, Button, Cascader } from 'antd';
|
||||||
import React, { useCallback, useMemo } from 'react';
|
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 { ArrayBase } from '@formily/antd-v5';
|
import { ArrayBase } from '@formily/antd-v5';
|
||||||
|
import { useActionOptions } from './hooks/useActionOptions';
|
||||||
|
import { CloseCircleOutlined } from '@ant-design/icons';
|
||||||
|
import { ActionParamsField } from './ActionParams';
|
||||||
|
|
||||||
interface LinkageRuleActionGroupProps {
|
interface LinkageRuleActionGroupProps {
|
||||||
type: 'button' | 'field' | 'style';
|
type: 'button' | 'field' | 'style';
|
||||||
@ -22,34 +24,48 @@ interface LinkageRuleActionGroupProps {
|
|||||||
collectionName: string;
|
collectionName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Actions = withDynamicSchemaProps(
|
const Action = observer(
|
||||||
(props: LinkageRuleActionGroupProps) => {
|
(props: any): any => {
|
||||||
const { t } = useTranslation();
|
const { onRemove } = props;
|
||||||
const field = useField<VoidField>();
|
const options = useActionOptions();
|
||||||
const { category, elementType, linkageOptions, collectionName } = props;
|
const field = useField<any>();
|
||||||
|
field.onFieldChange = (field) => {
|
||||||
const components = useMemo(
|
console.log('field', field);
|
||||||
() => [Action, { category, elementType, linkageOptions, collectionName }],
|
};
|
||||||
[collectionName, linkageOptions, category, elementType],
|
|
||||||
);
|
|
||||||
const spaceStyle = useMemo(() => ({ marginTop: 8, marginBottom: 8 }), []);
|
|
||||||
const style = useMemo(() => ({ marginLeft: 10 }), []);
|
|
||||||
const onClick = useCallback(() => {
|
|
||||||
const f = field.query('.actions').take() as ArrayFieldModel;
|
|
||||||
const items = f.value || [];
|
|
||||||
items.push({});
|
|
||||||
f.value = items;
|
|
||||||
f.initialValue = items;
|
|
||||||
}, [field]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={style}>
|
<Space align="start">
|
||||||
<ArrayField name={'actions'} component={components} disabled={false} />
|
<Field name="action" component={[Cascader, { options, placeholder: '选择动作' }]} />
|
||||||
<Space size={16} style={spaceStyle}>
|
<ArrayField name={'params'} component={[ActionParamsField, { action: field.value.action?.value }]} />
|
||||||
<a onClick={onClick}>{t('添加动作')}</a>
|
{!props.disabled && (
|
||||||
</Space>
|
<a role="button" aria-label="icon-close">
|
||||||
</div>
|
<CloseCircleOutlined onClick={onRemove} style={{ color: '#bfbfbf' }} />
|
||||||
|
</a>
|
||||||
|
)}
|
||||||
|
</Space>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
{ displayName: 'ActionRow' },
|
||||||
|
);
|
||||||
|
|
||||||
|
const Actions = withDynamicSchemaProps(
|
||||||
|
observer((props: LinkageRuleActionGroupProps) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const field = useField<ArrayFieldModel>();
|
||||||
|
return (
|
||||||
|
<Space style={{ paddingLeft: 10 }} direction="vertical">
|
||||||
|
{field?.value?.map((item, index) => {
|
||||||
|
return <ObjectField key={index} name={index} component={[Action, { onRemove: () => field.remove(index) }]} />;
|
||||||
|
})}
|
||||||
|
<a onClick={() => field.push({})}>{t('添加动作')}</a>
|
||||||
|
</Space>
|
||||||
|
);
|
||||||
|
}),
|
||||||
{ displayName: 'Actions' },
|
{ displayName: 'Actions' },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const ActionsField = withDynamicSchemaProps(
|
||||||
|
observer((props: LinkageRuleActionGroupProps) => {
|
||||||
|
return <ArrayField name={'actions'} component={[Actions]} />;
|
||||||
|
}),
|
||||||
|
{ displayName: 'ActionsField' },
|
||||||
|
);
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
/**
|
||||||
|
* 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 { useEvent } from '../../../hooks/useEvent';
|
||||||
|
|
||||||
|
export function useActionOptions() {
|
||||||
|
const { definitions } = useEvent();
|
||||||
|
|
||||||
|
let treeData = definitions?.map((module) => ({
|
||||||
|
value: module.name,
|
||||||
|
label: module.title + ' - ' + module.uid,
|
||||||
|
children:
|
||||||
|
module?.actions?.map((event) => ({
|
||||||
|
value: `${module.name}.${event.name}${module.uid ? `.${module.uid}` : ''}`,
|
||||||
|
label: event.title,
|
||||||
|
})) || [],
|
||||||
|
}));
|
||||||
|
treeData = treeData?.filter((item) => item.children.length > 0);
|
||||||
|
|
||||||
|
return treeData;
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
/**
|
||||||
|
* 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 { useEvent } from '../../../hooks/useEvent';
|
||||||
|
|
||||||
|
export function useActionOptions() {
|
||||||
|
const { definitions } = useEvent();
|
||||||
|
|
||||||
|
let treeData = definitions?.map((module) => ({
|
||||||
|
value: module.name,
|
||||||
|
label: module.title + ' - ' + module.uid,
|
||||||
|
children:
|
||||||
|
module?.actions?.map((event) => ({
|
||||||
|
value: `${module.name}.${event.name}${module.uid ? `.${module.uid}` : ''}`,
|
||||||
|
label: event.title,
|
||||||
|
})) || [],
|
||||||
|
}));
|
||||||
|
treeData = treeData?.filter((item) => item.children.length > 0);
|
||||||
|
|
||||||
|
return treeData;
|
||||||
|
}
|
@ -20,7 +20,7 @@ import { SubFormProvider } from '../../../schema-component/antd/association-fiel
|
|||||||
import { DynamicComponentProps } from '../../../schema-component/antd/filter/DynamicComponent';
|
import { DynamicComponentProps } from '../../../schema-component/antd/filter/DynamicComponent';
|
||||||
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 { ActionsField } from './Actions';
|
||||||
import { FormProvider, createSchemaField } from '@formily/react';
|
import { FormProvider, createSchemaField } from '@formily/react';
|
||||||
import { ArrayCollapse } from '../components/LinkageHeader';
|
import { ArrayCollapse } from '../components/LinkageHeader';
|
||||||
import { Filter } from '../Filter';
|
import { Filter } from '../Filter';
|
||||||
@ -126,7 +126,6 @@ export const ActionsSetting = withDynamicSchemaProps(
|
|||||||
getAllCollectionsInheritChain,
|
getAllCollectionsInheritChain,
|
||||||
})}
|
})}
|
||||||
returnScope={(scope) => {
|
returnScope={(scope) => {
|
||||||
// console.log('scope', [...scope, ...variableOptions]);
|
|
||||||
return uniqBy([...scope, ...variableOptions], 'key');
|
return uniqBy([...scope, ...variableOptions], 'key');
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@ -140,7 +139,7 @@ export const ActionsSetting = withDynamicSchemaProps(
|
|||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-component': (_props) => <Actions {..._props} {...props} />,
|
'x-component': ActionsField,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user