mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-05-09 07:29:24 +08:00
feat: adjust dir and support event array
This commit is contained in:
parent
7b19f3e44a
commit
1d02eb1e8b
@ -0,0 +1,79 @@
|
||||
/**
|
||||
* 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 { ArrayField as ArrayFieldModel, VoidField } from '@formily/core';
|
||||
import { ArrayField, ObjectField, observer, useField } from '@formily/react';
|
||||
import { Space, TreeSelect } from 'antd';
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { withDynamicSchemaProps } from '../../../hoc/withDynamicSchemaProps';
|
||||
import {
|
||||
FormButtonLinkageRuleAction,
|
||||
FormFieldLinkageRuleAction,
|
||||
FormStyleLinkageRuleAction,
|
||||
} from './LinkageRuleAction';
|
||||
import { RemoveActionContext } from './context';
|
||||
import { useControllableValue } from 'ahooks';
|
||||
|
||||
const ActionSelect = (props) => {
|
||||
const { t } = useTranslation();
|
||||
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 (
|
||||
<TreeSelect
|
||||
value={state}
|
||||
dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
|
||||
placeholder="Please select"
|
||||
allowClear
|
||||
treeDefaultExpandAll
|
||||
onChange={(value) => {
|
||||
setState(value);
|
||||
}}
|
||||
treeData={treeData}
|
||||
className={className}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const Action = observer(
|
||||
(props: any): any => {
|
||||
const { linkageOptions, category, elementType } = props;
|
||||
const field = useField<ArrayFieldModel>();
|
||||
const type = category === 'default' ? elementType : category;
|
||||
const componentMap: {
|
||||
[key: string]: any;
|
||||
} = {
|
||||
button: FormButtonLinkageRuleAction,
|
||||
field: FormFieldLinkageRuleAction,
|
||||
style: FormStyleLinkageRuleAction,
|
||||
};
|
||||
return field?.value?.map((item, index) => {
|
||||
return (
|
||||
<RemoveActionContext.Provider key={index} value={() => field.remove(index)}>
|
||||
<ObjectField name={index} component={[ActionSelect, { ...props, options: linkageOptions }]} />
|
||||
</RemoveActionContext.Provider>
|
||||
);
|
||||
});
|
||||
},
|
||||
{ displayName: 'LinkageRuleActions' },
|
||||
);
|
@ -0,0 +1,54 @@
|
||||
/**
|
||||
* 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 { ArrayField as ArrayFieldModel, VoidField } from '@formily/core';
|
||||
import { ArrayField, ObjectField, observer, useField } from '@formily/react';
|
||||
import { Space } from 'antd';
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { withDynamicSchemaProps } from '../../../hoc/withDynamicSchemaProps';
|
||||
import { Action } from './Action';
|
||||
|
||||
interface LinkageRuleActionGroupProps {
|
||||
type: 'button' | 'field' | 'style';
|
||||
linkageOptions: any;
|
||||
collectionName: string;
|
||||
}
|
||||
|
||||
export const Actions = withDynamicSchemaProps(
|
||||
(props: LinkageRuleActionGroupProps) => {
|
||||
const { t } = useTranslation();
|
||||
const field = useField<VoidField>();
|
||||
const { category, elementType, linkageOptions, collectionName } = props;
|
||||
|
||||
const components = useMemo(
|
||||
() => [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 (
|
||||
<div style={style}>
|
||||
<ArrayField name={'actions'} component={components} disabled={false} />
|
||||
<Space size={16} style={spaceStyle}>
|
||||
<a onClick={onClick}>{t('添加动作')}</a>
|
||||
</Space>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
{ displayName: 'Actions' },
|
||||
);
|
@ -0,0 +1,281 @@
|
||||
/**
|
||||
* 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';
|
@ -20,19 +20,18 @@ import { SubFormProvider } from '../../../schema-component/antd/association-fiel
|
||||
import { DynamicComponentProps } from '../../../schema-component/antd/filter/DynamicComponent';
|
||||
import { FilterContext } from '../../../schema-component/antd/filter/context';
|
||||
import { VariableInput, getShouldChange } from '../../../schema-settings/VariableInput/VariableInput';
|
||||
import { LinkageRuleActionGroup } from './LinkageRuleActionGroup';
|
||||
import { Actions } from './Actions';
|
||||
import { EnableLinkage } from './components/EnableLinkage';
|
||||
import { ArrayCollapse } from './components/LinkageHeader';
|
||||
import { FormProvider, createSchemaField } from '@formily/react';
|
||||
import { Filter } from '../filter';
|
||||
import { Filter } from '../Filter2';
|
||||
|
||||
export interface Props {
|
||||
dynamicComponent: any;
|
||||
}
|
||||
|
||||
export const FormLinkageRules = withDynamicSchemaProps(
|
||||
export const ActionsSetting = withDynamicSchemaProps(
|
||||
observer((props: Props) => {
|
||||
console.log('FormLinkageRules22', props);
|
||||
const fieldSchema = useFieldSchema();
|
||||
const { options, defaultValues, collectionName, form, variables, localVariables, record, dynamicComponent } =
|
||||
useProps(props); // 新版 UISchema(1.0 之后)中已经废弃了 useProps,这里之所以继续保留是为了兼容旧版的 UISchema
|
||||
@ -70,7 +69,7 @@ export const FormLinkageRules = withDynamicSchemaProps(
|
||||
wrapperCol: 16,
|
||||
},
|
||||
properties: {
|
||||
conditions: {
|
||||
conditionsTitle: {
|
||||
'x-component': 'h4',
|
||||
'x-content': '{{ t("Condition") }}',
|
||||
},
|
||||
@ -106,13 +105,13 @@ export const FormLinkageRules = withDynamicSchemaProps(
|
||||
},
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
actionsTitle: {
|
||||
'x-component': 'h4',
|
||||
'x-content': '{{ t("Properties") }}',
|
||||
'x-content': '{{ t("动作") }}',
|
||||
},
|
||||
action: {
|
||||
actions: {
|
||||
type: 'void',
|
||||
'x-component': (_props) => <LinkageRuleActionGroup {..._props} {...props} />,
|
||||
'x-component': (_props) => <Actions {..._props} {...props} />,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -173,7 +172,7 @@ export const FormLinkageRules = withDynamicSchemaProps(
|
||||
|
||||
return (
|
||||
// 这里使用 SubFormProvider 包裹,是为了让子表格的联动规则中 “当前对象” 的配置显示正确
|
||||
<FormProvider form={form}>
|
||||
// <FormProvider form={form}>
|
||||
<SubFormProvider value={{ value: null, collection: { name: collectionName } as any }}>
|
||||
<RecordProvider record={record} parent={parentRecordData}>
|
||||
<FilterContext.Provider value={value}>
|
||||
@ -183,8 +182,8 @@ export const FormLinkageRules = withDynamicSchemaProps(
|
||||
</FilterContext.Provider>
|
||||
</RecordProvider>
|
||||
</SubFormProvider>
|
||||
</FormProvider>
|
||||
// </FormProvider>
|
||||
);
|
||||
}),
|
||||
{ displayName: 'FormLinkageRules' },
|
||||
{ displayName: 'ActionsSetting' },
|
||||
);
|
@ -10,24 +10,30 @@
|
||||
import React from 'react';
|
||||
import { useControllableValue } from 'ahooks';
|
||||
import { Card, Space, TreeSelect } from 'antd';
|
||||
import { EventDefinition } from '../types';
|
||||
import { EventDefinition } from '../../types';
|
||||
|
||||
export default function EventSelect(props: { modules: EventDefinition[]; value: any; onChange: (v: any) => void }) {
|
||||
const { modules, onChange } = props;
|
||||
const [state, setState] = useControllableValue<Array<any>>(props, {
|
||||
export default function EventSelect(props: {
|
||||
definitions: EventDefinition[];
|
||||
value: any;
|
||||
onChange: (v: any) => void;
|
||||
className?: string;
|
||||
}) {
|
||||
const { definitions, className } = props;
|
||||
const [state, setState] = useControllableValue<String>(props, {
|
||||
defaultValue: undefined,
|
||||
});
|
||||
|
||||
let treeData = modules?.map((module) => ({
|
||||
let treeData = definitions?.map((module) => ({
|
||||
value: module.name,
|
||||
title: module.title,
|
||||
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);
|
||||
treeData = treeData?.filter((item) => item.children.length > 0);
|
||||
|
||||
return (
|
||||
<TreeSelect
|
||||
@ -40,6 +46,7 @@ export default function EventSelect(props: { modules: EventDefinition[]; value:
|
||||
setState(value);
|
||||
}}
|
||||
treeData={treeData}
|
||||
className={className}
|
||||
/>
|
||||
);
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
/**
|
||||
* 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';
|
@ -0,0 +1,12 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export const arrayCollapseItemStyle = {
|
||||
marginBottom: 10,
|
||||
};
|
@ -24,25 +24,26 @@ const LinkageRulesTitle = (props) => {
|
||||
const index = ArrayBase.useIndex(props.index);
|
||||
const { t } = useTranslation();
|
||||
const value = array?.field?.value[index];
|
||||
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();
|
||||
}}
|
||||
/>
|
||||
);
|
||||
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 {
|
||||
@ -133,6 +134,9 @@ export const ArrayCollapse: ComposedArrayCollapse = observer(
|
||||
};
|
||||
|
||||
const renderItems = () => {
|
||||
if (!dataSource || dataSource.length === 0) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<Collapse
|
||||
{...props}
|
@ -0,0 +1,139 @@
|
||||
/**
|
||||
* 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' },
|
||||
);
|
@ -54,7 +54,6 @@ export const Filter: any = withDynamicSchemaProps(
|
||||
}, [fieldSchema.defaultValue]);
|
||||
return (
|
||||
<div className={className}>
|
||||
1111
|
||||
<FilterContext.Provider
|
||||
value={{
|
||||
field,
|
@ -1,84 +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 { ArrayField as ArrayFieldModel, VoidField } from '@formily/core';
|
||||
import { ArrayField, ObjectField, observer, useField } from '@formily/react';
|
||||
import { Space } from 'antd';
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { withDynamicSchemaProps } from '../../../hoc/withDynamicSchemaProps';
|
||||
import { useProps } from '../../../schema-component/hooks/useProps';
|
||||
import {
|
||||
FormButtonLinkageRuleAction,
|
||||
FormFieldLinkageRuleAction,
|
||||
FormStyleLinkageRuleAction,
|
||||
} from './LinkageRuleAction';
|
||||
import { RemoveActionContext } from './context';
|
||||
export const LinkageRuleActions = observer(
|
||||
(props: any): any => {
|
||||
const { linkageOptions, category, elementType } = props;
|
||||
const field = useField<ArrayFieldModel>();
|
||||
const type = category === 'default' ? elementType : category;
|
||||
const componentMap: {
|
||||
[key in LinkageRuleActionGroupProps['type']]: any;
|
||||
} = {
|
||||
button: FormButtonLinkageRuleAction,
|
||||
field: FormFieldLinkageRuleAction,
|
||||
style: FormStyleLinkageRuleAction,
|
||||
};
|
||||
return field?.value?.map((item, index) => {
|
||||
return (
|
||||
<RemoveActionContext.Provider key={index} value={() => field.remove(index)}>
|
||||
<ObjectField name={index} component={[componentMap[type], { ...props, options: linkageOptions }]} />
|
||||
</RemoveActionContext.Provider>
|
||||
);
|
||||
});
|
||||
},
|
||||
{ displayName: 'LinkageRuleActions' },
|
||||
);
|
||||
|
||||
export interface LinkageRuleActionGroupProps {
|
||||
type: 'button' | 'field' | 'style';
|
||||
linkageOptions: any;
|
||||
collectionName: string;
|
||||
}
|
||||
|
||||
export const LinkageRuleActionGroup = withDynamicSchemaProps(
|
||||
(props: LinkageRuleActionGroupProps) => {
|
||||
const { t } = useTranslation();
|
||||
const field = useField<VoidField>();
|
||||
const logic = 'actions';
|
||||
|
||||
// 新版 UISchema(1.0 之后)中已经废弃了 useProps,这里之所以继续保留是为了兼容旧版的 UISchema
|
||||
const { category, elementType, linkageOptions, collectionName } = useProps(props);
|
||||
const style = useMemo(() => ({ marginLeft: 10 }), []);
|
||||
const components = useMemo(
|
||||
() => [LinkageRuleActions, { category, elementType, linkageOptions, collectionName }],
|
||||
[collectionName, linkageOptions, category, elementType],
|
||||
);
|
||||
const spaceStyle = useMemo(() => ({ marginTop: 8, marginBottom: 8 }), []);
|
||||
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 (
|
||||
<div style={style}>
|
||||
<ArrayField name={logic} component={components} disabled={false} />
|
||||
<Space size={16} style={spaceStyle}>
|
||||
<a onClick={onClick}>{t('Add property')}</a>
|
||||
</Space>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
{ displayName: 'LinkageRuleActionGroup' },
|
||||
);
|
@ -11,7 +11,7 @@ import React from 'react';
|
||||
import { useControllableValue } from 'ahooks';
|
||||
import { Card, Space, Button, Tag, Tooltip, Select, TreeSelect } from 'antd';
|
||||
import { CloseOutlined, PlusOutlined, SettingFilled } from '@ant-design/icons';
|
||||
import { EventDefinition } from '../types';
|
||||
import { EventDefinition } from '../../types';
|
||||
|
||||
export default function ActionsInput(props: { modules: EventDefinition[]; value: any; onChange: (v: any) => void }) {
|
||||
const { modules } = props;
|
@ -1,11 +1,11 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
// /**
|
||||
// * 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 React, { useMemo } from 'react';
|
||||
import { useControllableValue } from 'ahooks';
|
||||
@ -14,10 +14,11 @@ import EventSelect from './EventSelect';
|
||||
import ConditionInput from './ConditionInput';
|
||||
import ActionsInput from './ActionsInput';
|
||||
import { CloseOutlined, PlusOutlined } from '@ant-design/icons';
|
||||
import { EventSetting } from '../types';
|
||||
import { EventSetting } from '../../types';
|
||||
import { FormLinkageRules } from './LinkageRules';
|
||||
import { createForm } from '@formily/core';
|
||||
import options from './options.json';
|
||||
import options from '../options.json';
|
||||
import { onFormValuesChange, onFormInit } from '@formily/core';
|
||||
|
||||
const EventCard = (props) => {
|
||||
const { modules, onDelete } = props;
|
||||
@ -33,6 +34,11 @@ const EventCard = (props) => {
|
||||
() =>
|
||||
createForm({
|
||||
initialValues: { rules: [] },
|
||||
effects() {
|
||||
onFormValuesChange((form) => {
|
||||
console.log('onFormValuesChange', JSON.parse(JSON.stringify(form.values)));
|
||||
});
|
||||
},
|
||||
}),
|
||||
[],
|
||||
);
|
||||
@ -53,7 +59,7 @@ const EventCard = (props) => {
|
||||
<ActionsInput modules={modules} value={state.actions} onChange={(v) => setState({ ...state, actions: v })} />
|
||||
</Form.Item> */}
|
||||
<FormLinkageRules
|
||||
category="default"
|
||||
// category="default"
|
||||
collectionName="t_aierml1wni1"
|
||||
elementType="field"
|
||||
defaultValues={[]}
|
||||
@ -63,9 +69,12 @@ const EventCard = (props) => {
|
||||
localVariables={[]}
|
||||
options={options}
|
||||
variables={{}}
|
||||
value={{ rules: [] }}
|
||||
record={{
|
||||
__collectionName: 't_aierml1wni1',
|
||||
// value={{ rules: [] }}
|
||||
// record={{
|
||||
// __collectionName: 't_aierml1wni1',
|
||||
// }}
|
||||
onChange={(v) => {
|
||||
console.log('onChange', v);
|
||||
}}
|
||||
/>
|
||||
</Card>
|
@ -14,14 +14,22 @@ import {
|
||||
useApp,
|
||||
usePlugin,
|
||||
useSchemaSettings,
|
||||
useLinkageCollectionFilterOptions,
|
||||
useFormBlockContext,
|
||||
useVariables,
|
||||
useLocalVariables,
|
||||
useFormBlockType,
|
||||
useRecord,
|
||||
} from '@nocobase/client';
|
||||
import React from 'react';
|
||||
import { ISchema, useField } from '@formily/react';
|
||||
import EventSettings from './EventSetting';
|
||||
import { SchemaSettingsKey, useEvent } from '..';
|
||||
import { useFieldSchema } from '@formily/react';
|
||||
import { useLinkageCollectionFieldOptions } from './ActionsSetting/action-hooks';
|
||||
import { EventsSetting } from './EventsSetting';
|
||||
|
||||
export const EventSettingItem = () => {
|
||||
// packages/core/client/src/schema-settings/SchemaSettings.tsx
|
||||
export const EventSettingItem = (props) => {
|
||||
// const field = useField();
|
||||
const filed = useField();
|
||||
const schema = useFieldSchema();
|
||||
@ -31,10 +39,20 @@ export const EventSettingItem = () => {
|
||||
const { dn } = useDesignable();
|
||||
const fieldSchema = useFieldSchema();
|
||||
console.log('definitions', definitions);
|
||||
const { readPretty, Component, afterSubmit } = props;
|
||||
const collectionName = 't_aierml1wni1';
|
||||
const options = useLinkageCollectionFilterOptions(collectionName);
|
||||
const linkageOptions = useLinkageCollectionFieldOptions(collectionName, readPretty);
|
||||
const { form } = useFormBlockContext();
|
||||
const variables = useVariables();
|
||||
const localVariables = useLocalVariables();
|
||||
const { type: formBlockType } = useFormBlockType();
|
||||
const record = useRecord();
|
||||
|
||||
return (
|
||||
<SchemaSettingsModalItem
|
||||
title={'Event Setting'}
|
||||
components={{ EventSettings }}
|
||||
components={{ EventsSetting }}
|
||||
initialValues={{}}
|
||||
scope={{}}
|
||||
width={1000}
|
||||
@ -44,12 +62,22 @@ export const EventSettingItem = () => {
|
||||
title: '事件配置',
|
||||
properties: {
|
||||
events: {
|
||||
type: 'array',
|
||||
default: fieldSchema?.[SchemaSettingsKey] || [],
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'EventSettings',
|
||||
'x-component-props': {
|
||||
modules: definitions,
|
||||
'x-component': EventsSetting,
|
||||
'x-use-component-props': () => {
|
||||
return {
|
||||
definitions,
|
||||
options,
|
||||
defaultValues: undefined,
|
||||
linkageOptions,
|
||||
category: 'default',
|
||||
elementType: 'field',
|
||||
collectionName,
|
||||
form,
|
||||
variables,
|
||||
localVariables,
|
||||
record,
|
||||
formBlockType,
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -30,6 +30,7 @@ export interface Props {
|
||||
|
||||
export const FormLinkageRules = withDynamicSchemaProps(
|
||||
observer((props: Props) => {
|
||||
console.log('FormLinkageRules', props);
|
||||
const fieldSchema = useFieldSchema();
|
||||
const { options, defaultValues, collectionName, form, variables, localVariables, record, dynamicComponent } =
|
||||
useProps(props); // 新版 UISchema(1.0 之后)中已经废弃了 useProps,这里之所以继续保留是为了兼容旧版的 UISchema
|
||||
|
Loading…
x
Reference in New Issue
Block a user