feat: clean code

This commit is contained in:
Jian Lu 2025-02-10 21:13:21 +08:00
parent 2f7660837d
commit 8ae3957578
12 changed files with 347 additions and 167 deletions

View File

@ -92,15 +92,33 @@ export function useFormEvents({ form }) {
}, },
}, },
fn: (params) => { fn: (params) => {
form.setFieldState(params.fieldName, params.fieldState); console.log('设置字段状态', params);
// form.setFieldState(params.fieldName, params.fieldState);
}, },
}, },
{ {
name: 'setValues', name: 'setValues',
title: '设置表单值', title: '设置表单值',
description: '设置表单值', description: '设置表单值',
params: {
name: {
name: 'name',
title: '字段名',
type: 'string',
description: '字段名',
},
value: {
name: 'value',
title: '字段值',
type: 'string',
},
},
fn: (params) => { fn: (params) => {
form.setValues(params.values); console.log('设置表单值', params);
form.setValues({
...form.values,
[params.name]: params.value,
});
}, },
}, },
], ],
@ -114,8 +132,8 @@ export function useFormEvents({ form }) {
event: 'valueChange', event: 'valueChange',
}, },
params: { params: {
// fieldName: payload?.props?.name, fieldName: payload?.props?.name,
// fieldValue: payload?.inputValue, fieldValue: payload?.inputValue,
values: form.values, // 用全量值代替某个值的改变,不太好传递动态的值类型 values: form.values, // 用全量值代替某个值的改变,不太好传递动态的值类型
}, },
}); });

View File

@ -8,13 +8,17 @@
*/ */
import { Plugin } from '../application/Plugin'; import { Plugin } from '../application/Plugin';
import { EventActionSetting, EventSetting, PluginName } from './types'; import { EventActionSetting, EventParamKey, EventSetting, SystemParamKey, StateParamKey, 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 { ISchema } from '@formily/react';
import { getPageSchema } from './utils'; import { getConditionResult, getFieldValuesInCondition, getPageSchema } from './utils';
import { conditionAnalyses } from '../schema-component/common/utils/uitls';
import { VariableOption } from '../variables/types';
import { VariablesContextType } from '../variables/types';
import { parse, str2moment } from '@nocobase/utils/client';
export class EventFlowPlugin extends Plugin { export class EventFlowPlugin extends Plugin {
static name = PluginName; static name = PluginName;
@ -43,11 +47,16 @@ 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 && a.pageUid === b.pageUid; return a.name === b.name && a.pageUid === b.pageUid && a.blockUid === b.blockUid;
} }
static getEventUniqueKey(event: EventSetting['event']) { static getEventUniqueKey(event: EventSetting['event']) {
return `${event.definition}.${event.event}`; return `${event.pageUid}.${event.blockUid}.${event.definition}.${event.event}`;
}
static parseEventUniqueKey(key: string) {
const [pageUid, blockUid, definition, event] = key?.split('.') || [];
return { pageUid, blockUid, definition, event };
} }
/** /**
@ -55,20 +64,16 @@ export class EventFlowPlugin extends Plugin {
* @param definition * @param definition
* @param fieldSchema schema * @param fieldSchema schema
*/ */
define(definition: EventDefinition | EventDefinition[], fieldSchema?: ISchema) { define(definitions: EventDefinition[]) {
const uid = fieldSchema?.['x-uid'];
const pageSchema = getPageSchema(fieldSchema);
const pageUid = pageSchema?.['x-uid'];
if (!definition) {
return;
}
const definitions = Array.isArray(definition) ? definition : [definition];
definitions.forEach((item) => { definitions.forEach((item) => {
item.uid = uid; const exist = this.definitions.find((def) => EventFlowPlugin.isEqual(def, item));
item.pageUid = pageUid; if (exist) {
Object.assign(exist, item);
} else {
this.definitions.push(item);
}
}); });
this.definitions.push(...definitions); console.log('definitions', this.definitions);
this.definitions = uniqBy(this.definitions, (item) => item.name + item.uid);
} }
// 移除定义事件 // 移除定义事件
// removeDefinition(definition: EventDefinition | EventDefinition[]) { // removeDefinition(definition: EventDefinition | EventDefinition[]) {
@ -89,28 +94,62 @@ export class EventFlowPlugin extends Plugin {
* @param p.event * @param p.event
* @param p.params * @param p.params
*/ */
async emit(p: { event: EventSetting['event']; params?: any }) { async emit(p: {
console.log('emit', p); event: EventSetting['event'];
const event = this.events.get(EventFlowPlugin.getEventUniqueKey(p.event)); params?: any;
if (event) { variables: VariablesContextType;
const condition = event.condition; localVariables: VariableOption[];
const isCondition = false; }) {
// todo 条件判断 const rules = this.events.get(EventFlowPlugin.getEventUniqueKey(p.event))?.rules;
if (!isCondition) { const getParsedValue = (expression: string) => {
return; const template = parse(expression);
} return template(p.variables);
event.actions.forEach((act: EventActionSetting) => { };
const definition = this.definitions.find((def) => def.name === act.definition); if (rules) {
const action = definition?.actions?.find((action) => action.name === act.action); for (const rule of rules) {
// todo 获取action的参数 const condition = rule.condition;
const actionParams = act.params; const conditionValues = {
if (action) { [EventParamKey]: p.params,
action.fn(actionParams); [StateParamKey]: {},
[SystemParamKey]: {},
};
console.log('conditionValues', condition, p, conditionValues);
// const isConditionPass = getConditionResult({ condition, values: conditionValues });
const isConditionPass = await conditionAnalyses({
ruleGroup: condition,
variables: p.variables,
localVariables: [
...p.localVariables,
{
name: '$eventValues',
ctx: conditionValues,
},
],
variableNameOfLeftCondition: '$eventValues',
});
console.log('isConditionPass', isConditionPass);
if (isConditionPass) {
rule.actions.forEach((act: EventActionSetting) => {
const definition = this.definitions.find((def) => def.name === act.action.definition);
const action = definition?.actions?.find((action) => action.name === act.action.action);
// todo 获取action的参数
const actionParams = {};
act.params?.forEach((param) => {
actionParams[param.name] = getParsedValue(param.value);
});
console.log('执行动作3', act, action, actionParams);
if (action) {
action.fn(actionParams);
}
});
} }
}); }
} }
} }
on(event: EventSetting) { on(event: EventSetting) {
if (!event.event) {
return;
}
this.events.set(EventFlowPlugin.getEventUniqueKey(event.event), event); this.events.set(EventFlowPlugin.getEventUniqueKey(event.event), event);
} }
} }

View File

@ -12,10 +12,14 @@ import { EventActionSetting } from '../../types';
import { useEvent } from '../../hooks/useEvent'; import { useEvent } from '../../hooks/useEvent';
import React from 'react'; import React from 'react';
export function ActionParamSelect(props: { action: EventActionSetting }) { export function ActionParamSelect(props: { action: EventActionSetting['action'] }) {
const { action, ...rest } = props; const { action, ...rest } = props;
const { definitions } = useEvent(); const { definitions } = useEvent();
const params = definitions.find((x) => x.uid === action?.uid)?.actions?.find((x) => x.name === action.event)?.params; const definition = definitions.find(
(x) => x.name === action?.definition && x.blockUid === action?.blockUid && x.pageUid === action?.pageUid,
);
const actionDef = definition?.actions?.find((x) => x.name === action.action);
const params = actionDef?.params;
const options = Object.keys(params || {}).map((key) => ({ const options = Object.keys(params || {}).map((key) => ({
name: key, name: key,
label: params[key]?.title, label: params[key]?.title,

View File

@ -9,33 +9,52 @@
import { observer } from '@formily/react'; import { observer } from '@formily/react';
import { Cascader } from 'antd'; import { Cascader } from 'antd';
import React from 'react'; import React, { useMemo } from 'react';
import { useActionOptions } from '../hooks/useActionOptions';
import { EventActionSetting } from '../../types'; import { EventActionSetting } from '../../types';
import { useEvent } from '../../hooks/useEvent';
import { useControllableValue } from 'ahooks';
export const ActionSelect = observer((props: any) => { export const ActionSelect = observer((props: any) => {
const options = useActionOptions(); const { definitions } = useEvent();
const [state, setState] = useControllableValue<EventActionSetting['action']>(props, {
defaultValue: undefined,
});
let treeData = definitions?.map((definition) => ({
value: `${definition.name}.${definition.blockUid}`,
label: definition.title + '-' + definition.blockUid,
children:
definition?.actions?.map((action) => ({
value: `${definition.pageUid || ''}.${definition.blockUid || ''}.${definition.name}.${action.name}`,
label: action.title,
})) || [],
}));
treeData = treeData?.filter((item) => item.children.length > 0);
const { onChange, value, ...rest } = props; const { onChange, value, ...rest } = props;
const _onChange = (value: any, selectedOptions: any) => {
const v = value[1]; const selectedAction = useMemo(() => {
if (v) { if (!state) return undefined;
const res: EventActionSetting = { return [
definition: v.split('.')[0], `${state.definition}.${state.blockUid}`,
event: v.split('.')[1], `${state.pageUid || ''}.${state.blockUid || ''}.${state.definition}.${state.action}`,
uid: v.split('.')[2], ];
}; }, [state]);
onChange?.(res);
} else {
onChange?.(undefined);
}
};
const _value = value ? [value.definition, `${value.definition}.${value.event}.${value.uid}`] : [];
return ( return (
<Cascader <Cascader
placeholder="请选择动作" placeholder="请选择动作"
options={options} options={treeData}
onChange={_onChange} onChange={(value: any, selectedOptions: any) => {
value={_value} const v = value[1];
if (v) {
const [pageUid, blockUid, definition, action] = v.split('.');
setState({ pageUid, blockUid, definition, action });
} else {
setState(undefined);
}
}}
value={selectedAction}
style={{ minWidth: 300 }} style={{ minWidth: 300 }}
{...rest} {...rest}
/> />

View File

@ -0,0 +1,17 @@
/**
* 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, { createContext } from 'react';
export const eventContext = createContext<{ pageUid: string }>({ pageUid: '' });
export const EventProvider = (props: { pageUid: string; children: React.ReactNode }) => {
const { pageUid } = props;
return <eventContext.Provider value={{ pageUid }}>{props.children}</eventContext.Provider>;
};

View File

@ -10,7 +10,7 @@
import React, { useMemo } 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, EventSetting } from '../types'; import { EventDefinition, EventSetting } from '../../types';
export default function EventSelect(props: { export default function EventSelect(props: {
definitions?: EventDefinition[]; definitions?: EventDefinition[];
@ -25,11 +25,11 @@ export default function EventSelect(props: {
let treeData = definitions?.map((module) => ({ let treeData = definitions?.map((module) => ({
value: module.name, value: module.name,
title: module.title + ' - ' + module.uid, title: module.title + ' - ' + module.blockUid,
selectable: false, selectable: false,
children: children:
module?.events?.map((event) => ({ module?.events?.map((event) => ({
value: `${module.name}.${event.name}${module.uid ? `.${module.uid}` : ''}`, value: `${module.pageUid || ''}.${module.blockUid || ''}.${module.name}.${event.name}`,
title: event.title, title: event.title,
})) || [], })) || [],
})); }));
@ -37,7 +37,7 @@ export default function EventSelect(props: {
const selectedEvent = useMemo(() => { const selectedEvent = useMemo(() => {
if (!state) return undefined; if (!state) return undefined;
return `${state.definition}.${state.event}${state.uid ? `.${state.uid}` : ''}`; return `${state.pageUid || ''}.${state.blockUid || ''}.${state.definition}.${state.event}`;
}, [state]); }, [state]);
return ( return (
@ -48,12 +48,16 @@ export default function EventSelect(props: {
allowClear allowClear
treeDefaultExpandAll treeDefaultExpandAll
onChange={(value) => { onChange={(value) => {
console.log('value', value); if (!value) {
const [definition, event, uid] = (value as any).split('.'); setState(undefined);
return;
}
const [pageUid, blockUid, definition, event] = value?.split('.') || [];
setState({ setState({
pageUid,
blockUid,
definition, definition,
event, event,
uid,
}); });
}} }}
treeData={treeData} treeData={treeData}

View File

@ -1,27 +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 { 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;
}

View File

@ -9,56 +9,58 @@
import { useDataSourceManager } from '../../../data-source/data-source'; import { useDataSourceManager } from '../../../data-source/data-source';
import { useEvent } from '../../hooks/useEvent'; import { useEvent } from '../../hooks/useEvent';
import { EventParam, EventSetting, EventDefinition } from '../../types'; import { EventParam, EventSetting, EventDefinition, EventParamKey, StateParamKey, SystemParamKey } from '../../types';
const useCurrentEventParams: (event?: EventSetting['event']) => { const useCurrentEventParams = (event?: EventSetting['event']) => {
[key: string]: EventParam;
} = (event) => {
const { definitions } = useEvent(); const { definitions } = useEvent();
const definition = definitions?.find((d) => d.name === event?.definition && d.uid === event.uid); const definition = definitions?.find(
(d) => d.name === event?.definition && d.pageUid === event.pageUid && d.blockUid === event.blockUid,
);
const eventParams = definition?.events?.find((e) => e.name === event?.event)?.params; const eventParams = definition?.events?.find((e) => e.name === event?.event)?.params;
return eventParams; return eventParams;
}; };
const useStateDefine = ({ definitions }: { definitions: EventDefinition[] }) => { const useStateDefine = () => {
const stateDefine = definitions.filter((item) => item.uid && item.states); const { definitions } = useEvent();
const stateDefineOptions = {}; const stateDefineOptions = {};
stateDefine.forEach((definition) => { definitions
stateDefineOptions[definition.uid] = { .filter((item) => item.states && item.blockUid) // 必须为区块的数据
name: definition.uid, .forEach((definition) => {
title: `${definition.title}-${definition.uid}`, stateDefineOptions[definition.blockUid] = {
type: 'object', name: definition.blockUid,
properties: definition.states, title: `${definition.title}-${definition.blockUid}`,
}; type: 'object',
}); properties: definition.states,
};
});
return { stateDefineOptions }; return { stateDefineOptions };
}; };
export const useFilterOptions = (event?: EventSetting['event']) => { export const useFilterOptions = (event?: EventSetting['event']) => {
const currentEventParamsDefine = useCurrentEventParams(event); const currentEventParamsDefine: EventParam[] = useCurrentEventParams(event);
const { definitions } = useEvent(); const { stateDefineOptions } = useStateDefine();
const { stateDefineOptions } = useStateDefine({ definitions }); console.log('useFilterOptions', event, currentEventParamsDefine, stateDefineOptions);
const options: EventParam[] = [ const options: EventParam[] = [
{ {
name: '_eventParams', name: EventParamKey,
title: '事件参数', title: '事件参数',
type: 'object', type: 'object',
properties: currentEventParamsDefine, properties: currentEventParamsDefine,
}, },
{ {
name: '_state', name: StateParamKey,
title: '组件数据', title: '组件数据',
type: 'object', type: 'object',
properties: stateDefineOptions, properties: stateDefineOptions,
}, },
// { {
// name: '_system', name: SystemParamKey,
// title: '系统参数', title: '应用数据',
// type: 'object', type: 'object',
// properties: {}, properties: {},
// }, },
]; ];
const dm = useDataSourceManager(); const dm = useDataSourceManager();

View File

@ -21,13 +21,14 @@ import {
useFormBlockType, useFormBlockType,
useRecord, useRecord,
Filter, Filter,
getPageSchema,
} from '@nocobase/client'; } from '@nocobase/client';
import React, { useEffect, useMemo } from 'react'; import React, { useEffect, 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 EventSelect from './EventSelect'; import EventSelect from './components/EventSelect';
import { ArrayCollapse } from './components/LinkageHeader'; import { ArrayCollapse } from './components/LinkageHeader';
import { css } from '@emotion/css'; import { css } from '@emotion/css';
import { FormItem, FormLayout } from '@formily/antd-v5'; import { FormItem, FormLayout } from '@formily/antd-v5';
@ -37,6 +38,7 @@ import { ActionParamSelect } from './components/ActionParamSelect';
import ConditionSelect from './components/ConditionSelect'; import ConditionSelect from './components/ConditionSelect';
import { Space } from 'antd'; import { Space } from 'antd';
import { ActionParamValueInput } from './components/ActionParamValueInput'; import { ActionParamValueInput } from './components/ActionParamValueInput';
import { EventProvider } from './components/EventProvider';
// packages/core/client/src/schema-settings/SchemaSettings.tsx // packages/core/client/src/schema-settings/SchemaSettings.tsx
export const EventSettingItem = (props) => { export const EventSettingItem = (props) => {
@ -47,6 +49,7 @@ export const EventSettingItem = (props) => {
const { definitions, register } = useEvent(); const { definitions, register } = useEvent();
const { dn } = useDesignable(); const { dn } = useDesignable();
const fieldSchema = useFieldSchema(); const fieldSchema = useFieldSchema();
const pageUid = getPageSchema(fieldSchema)?.['x-uid'];
return ( return (
<SchemaSettingsModalItem <SchemaSettingsModalItem
@ -80,7 +83,10 @@ export const EventSettingItem = (props) => {
type: 'array', type: 'array',
// default: defaultValues, // default: defaultValues,
'x-component': 'ArrayCollapse', 'x-component': 'ArrayCollapse',
'x-decorator': 'FormItem', 'x-decorator': EventProvider,
'x-decorator-props': {
pageUid,
},
'x-component-props': { 'x-component-props': {
accordion: true, accordion: true,
titleRender: (item: any, index: number) => { titleRender: (item: any, index: number) => {
@ -101,6 +107,7 @@ export const EventSettingItem = (props) => {
definitions, definitions,
className: css` className: css`
margin-bottom: 12px; margin-bottom: 12px;
width: 100%;
`, `,
}, },
}, },
@ -109,23 +116,6 @@ export const EventSettingItem = (props) => {
'x-content': '{{ t("执行规则") }}', 'x-content': '{{ t("执行规则") }}',
}, },
actionsBlock: rulesSchema, actionsBlock: rulesSchema,
// actionsBlock: {
// type: 'void',
// 'x-component': ActionsSetting,
// 'x-use-component-props': () => {
// return {
// options,
// linkageOptions,
// category: 'default',
// elementType: 'field',
// collectionName,
// // form,
// variables,
// localVariables,
// formBlockType,
// };
// },
// },
remove: { remove: {
type: 'void', type: 'void',
'x-component': 'ArrayCollapse.Remove', 'x-component': 'ArrayCollapse.Remove',

View File

@ -9,20 +9,32 @@
import { EventDefinition, EventSetting } from '../types'; import { EventDefinition, EventSetting } from '../types';
import { useFieldSchema } from '@formily/react'; import { useFieldSchema } from '@formily/react';
import { getPageSchema, useApp, usePlugin, useSchemaSettings } from '@nocobase/client'; import { getPageSchema, useApp, useLocalVariables, usePlugin, useVariables, useSchemaSettings } from '@nocobase/client';
import React from 'react'; import React, { useContext } from 'react';
import { ISchema, useField } from '@formily/react'; import { ISchema, useField } from '@formily/react';
import { EventFlowPlugin } from '..'; import { EventFlowPlugin } from '..';
import { useMemoizedFn } from 'ahooks'; import { useMemoizedFn } from 'ahooks';
import { eventContext } from '../EventSettingItem/components/EventProvider';
export const useEvent = () => { export const useEvent = () => {
const fieldSchema = useFieldSchema(); const fieldSchema = useFieldSchema();
const uid = fieldSchema?.['x-uid']; const context = useContext(eventContext);
const pageUid = getPageSchema(fieldSchema)?.['x-uid']; const pageUid = context.pageUid || getPageSchema(fieldSchema)?.['x-uid'];
const blockUid = fieldSchema?.['x-uid'];
const eventFlowPlugin: EventFlowPlugin = usePlugin(EventFlowPlugin.name) as any; const eventFlowPlugin: EventFlowPlugin = usePlugin(EventFlowPlugin.name) as any;
const variables = useVariables();
const localVariables = useLocalVariables({ currentForm: null });
const define = useMemoizedFn((definition: EventDefinition[] | EventDefinition) => { const define = useMemoizedFn((definition: EventDefinition[] | EventDefinition) => {
eventFlowPlugin?.define(definition, fieldSchema); if (!definition) {
return;
}
const definitions = Array.isArray(definition) ? definition : [definition];
definitions.forEach((item) => {
item.pageUid = pageUid;
item.blockUid = blockUid;
});
eventFlowPlugin?.define(definitions);
}); });
const register = useMemoizedFn((events: EventSetting[]) => { const register = useMemoizedFn((events: EventSetting[]) => {
@ -33,14 +45,19 @@ export const useEvent = () => {
await eventFlowPlugin?.emit({ await eventFlowPlugin?.emit({
event: { event: {
...p.event, ...p.event,
uid: uid, pageUid,
blockUid,
}, },
params: p.params, params: p.params,
variables,
localVariables,
}); });
}); });
console.log('event pageUid', pageUid);
return { return {
definitions: eventFlowPlugin?.definitions.filter((item) => item.pageUid === pageUid || !item.pageUid || !pageUid), definitions: eventFlowPlugin?.definitions.filter((item) => item.pageUid === pageUid || !item.pageUid),
// 定义事件 // 定义事件
define, define,
// 移除事件 // 移除事件

View File

@ -10,7 +10,9 @@
export const PluginName = 'event'; export const PluginName = 'event';
export const SchemaSettingsKey = 'x-event-settings'; export const SchemaSettingsKey = 'x-event-settings';
export const SchemaDefinitionsKey = 'x-event-definitions'; export const SchemaDefinitionsKey = 'x-event-definitions';
export const EventParamKey = '$eventParams';
export const StateParamKey = '_state';
export const SystemParamKey = '_system';
export interface EventParam { export interface EventParam {
name?: string; // 在item 情况下没有name https://json-schema.org/understanding-json-schema/reference/array name?: string; // 在item 情况下没有name https://json-schema.org/understanding-json-schema/reference/array
title?: string; title?: string;
@ -26,41 +28,52 @@ export interface EventParam {
/** 事件动作 */ /** 事件动作 */
export interface EventAction { export interface EventAction {
/** 动作名称 英文,全局唯一 */
name: string; name: string;
/** 动作标题 */
title: string; title: string;
/** 动作描述 */
description?: string; description?: string;
params?: { /** 动作参数 */
[key: string]: EventParam; params?: EventParam[];
}; /** 动作返回值 */
return?: EventParam;
/** 动作执行函数 */
fn: (params?: any) => void; fn: (params?: any) => void;
} }
/** 事件事件 */ /** 具体事件定义 */
export interface EventEvent { export interface EventEvent {
/** 事件名称 英文,全局唯一 */
name: string; name: string;
/** 事件标题 */
title: string; title: string;
uid?: string; /** 事件描述 */
description?: string; description?: string;
params?: { /** 事件参数, 可以配置多个参数 */
[key: string]: EventParam; params?: EventParam[];
};
value?: any;
} }
/** 事件定义 */ /** 事件模块定义 */
export interface EventDefinition { export interface EventDefinition {
/** 定义名称 英文,全局唯一 */
name: string; name: string;
/** 标识同一类型组件的不同实例 */ /** 定义所属页面uid, 系统级别定义该字段为 'app' */
uid?: string;
/** 标识所属页面 */
pageUid?: string; pageUid?: string;
/** 定义所属区块uid系统级别定义该字段为空 */
blockUid?: string;
/** 定义标题 */
title: string; title: string;
/** 定义描述 */
description?: string; description?: string;
/** 事件 */
events?: EventEvent[]; events?: EventEvent[];
/** 动作 */
actions?: EventAction[];
/** 区块内暴露的数据 */
states?: { states?: {
[key: string]: EventParam; [key: string]: EventParam;
}; };
actions?: EventAction[];
} }
/** 事件设置 */ /** 事件设置 */
@ -68,17 +81,23 @@ export interface EventSetting {
event: { event: {
definition: string; definition: string;
event: string; event: string;
uid?: string; pageUid?: string;
blockUid?: string;
}; };
rules?: Array<{
condition: string;
actions: Array<EventActionSetting>;
}>;
/** 标识同一类型组件的不同实例 */ /** 标识同一类型组件的不同实例 */
// uid?: string; // uid?: string;
condition: string;
actions: Array<EventActionSetting>;
} }
export interface EventActionSetting { export interface EventActionSetting {
definition: string; action: {
action: string; definition: string;
uid?: string; action: string;
pageUid?: string;
blockUid?: string;
};
params?: Array<EventActionSettingParams>; params?: Array<EventActionSettingParams>;
} }
export interface EventActionSettingParams { export interface EventActionSettingParams {

View File

@ -8,6 +8,8 @@
*/ */
import { ISchema } from '@formily/react'; import { ISchema } from '@formily/react';
import { every, findIndex, some } from 'lodash';
import { getValuesByPath, uid } from '@nocobase/utils/client';
export const getPageSchema = (schema: any) => { export const getPageSchema = (schema: any) => {
if (schema?.['x-component'] === 'Page') { if (schema?.['x-component'] === 'Page') {
@ -18,3 +20,79 @@ export const getPageSchema = (schema: any) => {
} }
return undefined; return undefined;
}; };
function getAllKeys(obj) {
const keys = [];
function traverse(o) {
Object.keys(o)
.sort()
.forEach(function (key) {
keys.push(key);
if (o[key] && typeof o[key] === 'object') {
traverse(o[key]);
}
});
}
traverse(obj);
return keys;
}
const getTargetField = (obj) => {
const keys = getAllKeys(obj);
const index = findIndex(keys, (key, index, keys) => {
if (key.includes('$') && index > 0) {
return true;
}
});
const result = keys.slice(0, index);
return result;
};
export function getFieldValuesInCondition({ linkageRules, formValues }) {
return linkageRules.map((rule) => {
const run = (condition) => {
const type = Object.keys(condition)[0] || '$and';
const conditions = condition[type];
return conditions
.map((condition) => {
if ('$and' in condition || '$or' in condition) {
return run(condition);
}
const path = getTargetField(condition).join('.');
return getValuesByPath(formValues, path);
})
.filter(Boolean);
};
return run(rule.condition);
});
}
export function getConditionResult({ condition, values }) {
const run = (condition) => {
const type = Object.keys(condition)[0] || '$and';
const conditions = condition[type];
const ress = conditions.map((condition) => {
if ('$and' in condition || '$or' in condition) {
return run(condition);
}
const path = getTargetField(condition).join('.');
console.log('path', path, values);
const v = getValuesByPath(values, path);
console.log('v', v);
return v;
});
if (type === '$and') {
return every(ress, Boolean);
}
if (type === '$or') {
return some(ress, Boolean);
}
};
return run(condition);
}