fix: add register logic

This commit is contained in:
Jian Lu 2025-02-05 15:06:29 +08:00
parent 70a1f6b05d
commit 2f7660837d
12 changed files with 138 additions and 248 deletions

View File

@ -11,7 +11,7 @@ import { useEvent } from '../../event-flow';
import { useCollection } from '../../data-source/collection/CollectionProvider'; import { useCollection } from '../../data-source/collection/CollectionProvider';
export function useFormEvents({ form }) { export function useFormEvents({ form }) {
const { define, emit, removeDefinition } = useEvent(); const { define, emit } = useEvent();
const collection = useCollection(); const collection = useCollection();
const fields = collection?.fields || []; const fields = collection?.fields || [];
const fieldsMap = fields.reduce((acc, field) => { const fieldsMap = fields.reduce((acc, field) => {
@ -107,12 +107,12 @@ export function useFormEvents({ form }) {
}; };
form.subscribe(({ type, payload, ...args }) => { form.subscribe(({ type, payload, ...args }) => {
// console.log('type', type, payload, args);
// 表格重置后代表着添加成功
if (type === 'onFieldInputValueChange') { if (type === 'onFieldInputValueChange') {
emit({ emit({
name: inter.name, event: {
eventName: 'valueChange', definition: inter.name,
event: 'valueChange',
},
params: { params: {
// fieldName: payload?.props?.name, // fieldName: payload?.props?.name,
// fieldValue: payload?.inputValue, // fieldValue: payload?.inputValue,

View File

@ -55,10 +55,22 @@ export function useSubmitEvents() {
}); });
return { return {
emitBeforeSubmit: async (values: any) => { emitBeforeSubmit: async (values: any) => {
await emit({ name: 'formSubmit', eventName: 'beforeSubmit', params: { values } }); await emit({
event: {
definition: 'formSubmit',
event: 'beforeSubmit',
},
params: { values },
});
}, },
emitAfterSubmit: async (values: any) => { emitAfterSubmit: async (values: any) => {
await emit({ name: 'formSubmit', eventName: 'afterSubmit', params: { values } }); await emit({
event: {
definition: 'formSubmit',
event: 'afterSubmit',
},
params: { values },
});
}, },
}; };
} }

View File

@ -8,11 +8,13 @@
*/ */
import { Plugin } from '../application/Plugin'; import { Plugin } from '../application/Plugin';
import { EventSetting, PluginName } from './types'; import { EventActionSetting, EventSetting, PluginName } from './types';
import { EventSettingItem } from './EventSettingItem'; import { EventSettingItem } from './EventSettingItem';
import { uniqBy } from 'lodash'; import { uniqBy } from 'lodash';
import { EventFlowProvider } from './EventFlowProvider'; import { EventFlowProvider } from './EventFlowProvider';
import { EventDefinition } from './types'; import { EventDefinition } from './types';
import { ISchema } from '@formily/react';
import { getPageSchema } from './utils';
export class EventFlowPlugin extends Plugin { export class EventFlowPlugin extends Plugin {
static name = PluginName; static name = PluginName;
@ -41,58 +43,74 @@ export class EventFlowPlugin extends Plugin {
} }
static isEqual(a: EventDefinition, b: EventDefinition) { static isEqual(a: EventDefinition, b: EventDefinition) {
return a.name === b.name && a.uid === b.uid; return a.name === b.name && a.uid === b.uid && a.pageUid === b.pageUid;
} }
// 定义事件 static getEventUniqueKey(event: EventSetting['event']) {
define(definition: EventDefinition | EventDefinition[]) { return `${event.definition}.${event.event}`;
}
/**
*
* @param definition
* @param fieldSchema schema
*/
define(definition: EventDefinition | EventDefinition[], fieldSchema?: ISchema) {
const uid = fieldSchema?.['x-uid'];
const pageSchema = getPageSchema(fieldSchema);
const pageUid = pageSchema?.['x-uid'];
if (!definition) { if (!definition) {
return; return;
} }
if (Array.isArray(definition)) { const definitions = Array.isArray(definition) ? definition : [definition];
this.definitions.push(...definition); definitions.forEach((item) => {
} else { item.uid = uid;
this.definitions.push(definition); item.pageUid = pageUid;
} });
this.definitions.push(...definitions);
this.definitions = uniqBy(this.definitions, (item) => item.name + item.uid); this.definitions = uniqBy(this.definitions, (item) => item.name + item.uid);
} }
// 移除定义事件 // 移除定义事件
removeDefinition(definition: EventDefinition | EventDefinition[]) { // removeDefinition(definition: EventDefinition | EventDefinition[]) {
if (!definition) { // if (!definition) {
return; // return;
} // }
if (Array.isArray(definition)) { // const definitions = Array.isArray(definition) ? definition : [definition];
this.definitions = this.definitions.filter((item) => !definition.some((d) => EventFlowPlugin.isEqual(item, d))); // this.definitions = this.definitions.filter((item) => !definitions.some((d) => EventFlowPlugin.isEqual(item, d)));
} else { // }
this.definitions = this.definitions.filter((item) => !EventFlowPlugin.isEqual(item, definition));
}
}
// 运行时注册事件 // 运行时注册事件
register(events: EventSetting[]) { register(events: EventSetting[]) {
console.log('todo register', events); events?.forEach((event) => {
// events?.forEach((event) => { this.on(event);
// this.on(event); });
// });
} }
// 触发事件 /**
async emit({ name, eventName, uid, params }: { name: string; eventName: string; uid?: string; params?: any }) { *
// console.log('emit', name, eventName, params); * @param p.event
// const event = this.events.find((event) => event.event === `${name}.${eventName}`); * @param p.params
// if (event) { */
// event.actions.forEach((action) => { async emit(p: { event: EventSetting['event']; params?: any }) {
// const actionModuleName = action.split('.')[0]; console.log('emit', p);
// const actionName = action.split('.')[1]; const event = this.events.get(EventFlowPlugin.getEventUniqueKey(p.event));
// const module = this.definitions.find((definition) => definition.name === name); if (event) {
// const moduleAction = this.definitions const condition = event.condition;
// .find((module) => module.name === actionModuleName) const isCondition = false;
// ?.actions?.find((action) => action.name === actionName); // todo 条件判断
// if (moduleAction) { if (!isCondition) {
// moduleAction?.fn(params); return;
// } }
// }); event.actions.forEach((act: EventActionSetting) => {
// } const definition = this.definitions.find((def) => def.name === act.definition);
const action = definition?.actions?.find((action) => action.name === act.action);
// todo 获取action的参数
const actionParams = act.params;
if (action) {
action.fn(actionParams);
}
});
}
} }
on(event: EventSetting) { on(event: EventSetting) {
this.events.set(event.event, event); this.events.set(EventFlowPlugin.getEventUniqueKey(event.event), event);
} }
} }

View File

@ -64,155 +64,3 @@ export interface Props {
dynamicComponent: any; dynamicComponent: any;
definitions: EventDefinition[]; definitions: EventDefinition[];
} }
export const ActionsSetting = withDynamicSchemaProps(
observer((props: Props) => {
const fieldSchema = useFieldSchema();
const array = ArrayBase.useArray();
const recordValues = ArrayBase.useRecord();
const index = ArrayBase.useIndex();
const { options, defaultValues, collectionName, variables, localVariables, record, dynamicComponent } = props;
const { getAllCollectionsInheritChain } = useCollectionManager_deprecated();
const parentRecordData = useCollectionParentRecordData();
const { form } = useFormBlockContext();
const variableOptions = useVariableOptions();
console.log('variableOptions', variableOptions);
const components = useMemo(
() => ({
ArrayCollapse,
Filter,
Space,
ActionParamSelect,
ActionSelect,
ConditionSelect,
}),
[],
);
const schema = useMemo(
() => ({
type: 'object',
properties: {
rules: {
type: 'array',
// default: defaultValues,
'x-component': 'ArrayCollapse',
'x-decorator': 'FormItem',
'x-component-props': {
accordion: true,
titleRender: (item: any, index: number) => {
return `动作 ${index + 1}`;
},
showEmpty: false,
},
items: {
type: 'object',
'x-component': 'ArrayCollapse.CollapsePanel',
'x-component-props': {
// extra: <EnableLinkage />,
},
properties: {
layout: {
type: 'void',
'x-component': 'FormLayout',
'x-component-props': {
labelStyle: {
marginTop: '6px',
},
labelCol: 8,
wrapperCol: 16,
},
properties: {
conditionsTitle: {
'x-component': 'h4',
'x-content': '{{ t("Condition") }}',
},
condition: {
'x-component': 'ConditionSelect',
'x-reactions': {
dependencies: ['...event'],
fulfill: {
state: {
'componentProps.options3': '{{$deps[0]}}',
},
},
},
},
actionsTitle: {
'x-component': 'h4',
'x-content': '{{ t("动作") }}',
},
actionsBlock: actionsSchema,
},
},
remove: {
type: 'void',
'x-component': 'ArrayCollapse.Remove',
},
},
},
properties: {
add: {
type: 'void',
title: '{{ t("添加规则") }}',
'x-component': 'ArrayCollapse.Addition',
'x-reactions': {
dependencies: ['rules'],
fulfill: {
state: {
// disabled: '{{$deps[0].length >= 3}}',
},
},
},
},
},
},
},
}),
[
collectionName,
defaultValues,
form,
getAllCollectionsInheritChain,
localVariables,
options,
props,
record,
variables,
],
);
const value = useMemo(
() => ({ field: options, fieldSchema, dynamicComponent, options: options || [] }),
[dynamicComponent, fieldSchema, options],
);
return (
<SchemaComponent
components={components}
schema={schema}
scope={{
emptyParams: (field, target) => {
const params = field.query('.params').take(1);
params.value = [];
},
}}
/>
);
// 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: 'ActionsSetting' },
);

View File

@ -22,6 +22,5 @@ export function ActionParamSelect(props: { action: EventActionSetting }) {
value: params[key]?.name || key, value: params[key]?.name || key,
...params[key], ...params[key],
})); }));
console.log('ActionParamSelect', props);
return <Select options={options} {...rest} style={{ minWidth: 150 }}></Select>; return <Select options={options} {...rest} style={{ minWidth: 150 }}></Select>;
} }

View File

@ -27,26 +27,22 @@ export const ActionParamValueInput = (props) => {
// return <CollectionField value={value} onChange={onChange} />; // return <CollectionField value={value} onChange={onChange} />;
// }, []); // }, []);
console.log('ActionParamValueInput props', props);
return ( return (
<div> <VariableInput
<VariableInput {...props}
{...props} // form={form}
// form={form} // record={record}
// record={record} shouldChange={getShouldChange({
shouldChange={getShouldChange({ // collectionField,
// collectionField, // variables,
// variables, // localVariables,
// localVariables, // getAllCollectionsInheritChain,
// getAllCollectionsInheritChain, })}
})} renderSchemaComponent={renderSchemaComponent}
renderSchemaComponent={renderSchemaComponent} // returnScope={(scope) => {
// returnScope={(scope) => { // return uniqBy([...scope, ...variableOptions], 'key');
// return uniqBy([...scope, ...variableOptions], 'key'); // }}
// }} style={{ minWidth: 200 }}
style={{ minWidth: 200 }} />
/>
</div>
); );
}; };

View File

@ -25,7 +25,6 @@ import { useUpdateEffect } from 'ahooks';
export default function ConditionSelect(props: { event?: EventSetting['event']; onChange?: any }) { export default function ConditionSelect(props: { event?: EventSetting['event']; onChange?: any }) {
const filterOptions = useFilterOptions(props.event); const filterOptions = useFilterOptions(props.event);
const variableOptions = useVariableOptions(); const variableOptions = useVariableOptions();
console.log('filterOptions', filterOptions, props);
const field = useField<ObjectField>(); const field = useField<ObjectField>();
useUpdateEffect(() => { useUpdateEffect(() => {
// 当 event 变化时,清空 condition // 当 event 变化时,清空 condition

View File

@ -27,7 +27,6 @@ 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 { ActionsSetting } from './ActionsSetting';
import EventSelect from './EventSelect'; import EventSelect from './EventSelect';
import { ArrayCollapse } from './components/LinkageHeader'; import { ArrayCollapse } from './components/LinkageHeader';
import { css } from '@emotion/css'; import { css } from '@emotion/css';
@ -43,20 +42,11 @@ import { ActionParamValueInput } from './components/ActionParamValueInput';
export const EventSettingItem = (props) => { export const EventSettingItem = (props) => {
// const field = useField(); // const field = useField();
const filed = useField(); const filed = useField();
const schema = useFieldSchema();
const { patch } = useDesignable(); const { patch } = useDesignable();
const app = useApp(); const app = useApp();
const { definitions, register } = useEvent(); const { definitions, register } = useEvent();
const { dn } = useDesignable(); const { dn } = useDesignable();
const fieldSchema = useFieldSchema(); const fieldSchema = useFieldSchema();
const { readPretty, Component, afterSubmit } = props;
const collectionName = 't_aierml1wni1';
const options = useLinkageCollectionFilterOptions(collectionName);
const linkageOptions = useLinkageCollectionFieldOptions(collectionName, readPretty);
const ff = useFormBlockContext();
const variables = useVariables();
const localVariables = useLocalVariables();
const { type: formBlockType } = useFormBlockType();
return ( return (
<SchemaSettingsModalItem <SchemaSettingsModalItem
@ -73,7 +63,7 @@ export const EventSettingItem = (props) => {
ConditionSelect, ConditionSelect,
ActionParamValueInput, ActionParamValueInput,
}} }}
initialValues={{ events: schema[SchemaSettingsKey] }} initialValues={{ events: fieldSchema[SchemaSettingsKey] }}
scope={{ scope={{
emptyParams: (field, target) => { emptyParams: (field, target) => {
const params = field.query('.params').take(1); const params = field.query('.params').take(1);

View File

@ -9,7 +9,7 @@
import { EventDefinition, EventSetting } from '../types'; import { EventDefinition, EventSetting } from '../types';
import { useFieldSchema } from '@formily/react'; import { useFieldSchema } from '@formily/react';
import { useApp, usePlugin, useSchemaSettings } from '@nocobase/client'; import { getPageSchema, useApp, usePlugin, useSchemaSettings } from '@nocobase/client';
import React from 'react'; import React from 'react';
import { ISchema, useField } from '@formily/react'; import { ISchema, useField } from '@formily/react';
import { EventFlowPlugin } from '..'; import { EventFlowPlugin } from '..';
@ -18,33 +18,33 @@ import { useMemoizedFn } from 'ahooks';
export const useEvent = () => { export const useEvent = () => {
const fieldSchema = useFieldSchema(); const fieldSchema = useFieldSchema();
const uid = fieldSchema?.['x-uid']; const uid = fieldSchema?.['x-uid'];
const pageUid = getPageSchema(fieldSchema)?.['x-uid'];
const eventFlowPlugin: EventFlowPlugin = usePlugin(EventFlowPlugin.name) as any; const eventFlowPlugin: EventFlowPlugin = usePlugin(EventFlowPlugin.name) as any;
const define = useMemoizedFn((definition: EventDefinition[] | EventDefinition) => { const define = useMemoizedFn((definition: EventDefinition[] | EventDefinition) => {
if (Array.isArray(definition)) { eventFlowPlugin?.define(definition, fieldSchema);
definition.forEach((item) => {
item.uid = uid;
});
} else if (definition) {
definition.uid = uid;
}
eventFlowPlugin?.define(definition);
}); });
const register = useMemoizedFn((events: EventSetting[]) => { const register = useMemoizedFn((events: EventSetting[]) => {
eventFlowPlugin?.register(events); eventFlowPlugin?.register(events);
}); });
const emit = useMemoizedFn(async ({ name, eventName, params }: { name: string; eventName: string; params?: any }) => { const emit = useMemoizedFn(async (p: { event: EventSetting['event']; params?: any }) => {
await eventFlowPlugin?.emit({ name, eventName, uid, params }); await eventFlowPlugin?.emit({
event: {
...p.event,
uid: uid,
},
params: p.params,
});
}); });
return { return {
definitions: eventFlowPlugin?.definitions, definitions: eventFlowPlugin?.definitions.filter((item) => item.pageUid === pageUid || !item.pageUid || !pageUid),
// 定义事件 // 定义事件
define, define,
// 移除事件 // 移除事件
removeDefinition: eventFlowPlugin?.removeDefinition, // removeDefinition: eventFlowPlugin?.removeDefinition,
// 运行时事件注册 // 运行时事件注册
register, register,
// 触发事件 // 触发事件

View File

@ -52,6 +52,8 @@ export interface EventDefinition {
name: string; name: string;
/** 标识同一类型组件的不同实例 */ /** 标识同一类型组件的不同实例 */
uid?: string; uid?: string;
/** 标识所属页面 */
pageUid?: string;
title: string; title: string;
description?: string; description?: string;
events?: EventEvent[]; events?: EventEvent[];
@ -69,7 +71,7 @@ export interface EventSetting {
uid?: string; uid?: string;
}; };
/** 标识同一类型组件的不同实例 */ /** 标识同一类型组件的不同实例 */
uid?: string; // uid?: string;
condition: string; condition: string;
actions: Array<EventActionSetting>; actions: Array<EventActionSetting>;
} }

View File

@ -0,0 +1,20 @@
/**
* 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 { ISchema } from '@formily/react';
export const getPageSchema = (schema: any) => {
if (schema?.['x-component'] === 'Page') {
return schema;
}
if (schema?.parent) {
return getPageSchema(schema?.parent);
}
return undefined;
};

View File

@ -52,7 +52,13 @@ export function useCreateFormBlockEventsDefine() {
console.log('type', type, payload, args); console.log('type', type, payload, args);
// 表格重置后代表着添加成功 // 表格重置后代表着添加成功
if (type === 'onFormReset') { if (type === 'onFormReset') {
emit(inter.name, 'onSubmit', payload); emit({
event: {
definition: inter.name,
event: 'onSubmit',
},
params: payload,
});
} }
}); });