diff --git a/packages/core/client/src/block-provider/hooks/useFormEvents.ts b/packages/core/client/src/block-provider/hooks/useFormEvents.ts index 69bb12eff4..95b698d1f4 100644 --- a/packages/core/client/src/block-provider/hooks/useFormEvents.ts +++ b/packages/core/client/src/block-provider/hooks/useFormEvents.ts @@ -35,9 +35,15 @@ export function useFormEvents({ form }) { }, }, ], - // state: { - // isSubmitting: 'isSubmitting', - // }, + states: { + values: { + name: 'values', + title: '表单值', + type: 'object', + properties: fieldsMap, + value: form.values, + }, + }, actions: [ { name: 'reset', diff --git a/packages/core/client/src/event-flow/EventFlowPlugin.tsx b/packages/core/client/src/event-flow/EventFlowPlugin.tsx index 3f12b64914..fd5eb47237 100644 --- a/packages/core/client/src/event-flow/EventFlowPlugin.tsx +++ b/packages/core/client/src/event-flow/EventFlowPlugin.tsx @@ -53,9 +53,10 @@ export class EventFlowPlugin extends Plugin { } // 运行时注册事件 register(events: EventSetting[]) { - events?.forEach((event) => { - this.on(event); - }); + console.log('todo register', events); + // events?.forEach((event) => { + // this.on(event); + // }); } // 触发事件 async emit({ name, eventName, uid, params }: { name: string; eventName: string; uid?: string; params?: any }) { diff --git a/packages/core/client/src/event-flow/EventSettingItem/ActionsSetting/Actions.tsx b/packages/core/client/src/event-flow/EventSettingItem/ActionsSetting/Actions.tsx index ebe25d1607..e49e1d634b 100644 --- a/packages/core/client/src/event-flow/EventSettingItem/ActionsSetting/Actions.tsx +++ b/packages/core/client/src/event-flow/EventSettingItem/ActionsSetting/Actions.tsx @@ -14,6 +14,7 @@ import React, { useCallback, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { withDynamicSchemaProps } from '../../../hoc/withDynamicSchemaProps'; import { Action } from './Action'; +import { ArrayBase } from '@formily/antd-v5'; interface LinkageRuleActionGroupProps { type: 'button' | 'field' | 'style'; diff --git a/packages/core/client/src/event-flow/EventSettingItem/ActionsSetting/components/LinkageHeader.tsx b/packages/core/client/src/event-flow/EventSettingItem/ActionsSetting/components/LinkageHeader.tsx deleted file mode 100644 index ea576a4118..0000000000 --- a/packages/core/client/src/event-flow/EventSettingItem/ActionsSetting/components/LinkageHeader.tsx +++ /dev/null @@ -1,281 +0,0 @@ -/** - * This file is part of the NocoBase (R) project. - * Copyright (c) 2020-2024 NocoBase Co., Ltd. - * Authors: NocoBase Team. - * - * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License. - * For more information, please refer to: https://www.nocobase.com/agreement. - */ - -import { CopyOutlined } from '@ant-design/icons'; -import { ArrayBase } from '@formily/antd-v5'; -import { ArrayField } from '@formily/core'; -import { ISchema, RecursionField, observer, useField, useFieldSchema } from '@formily/react'; -import { toArr } from '@formily/shared'; -import { Badge, Card, Collapse, CollapsePanelProps, CollapseProps, Empty, Input } from 'antd'; -import { cloneDeep } from 'lodash'; -import React, { Fragment, useEffect, useState } from 'react'; -import { useTranslation } from 'react-i18next'; -import { useToken } from '../../../../style'; -import { arrayCollapseItemStyle } from './LinkageHeader.style'; - -const LinkageRulesTitle = (props) => { - const array = ArrayBase.useArray(); - const index = ArrayBase.useIndex(props.index); - const { t } = useTranslation(); - const value = array?.field?.value[index]; - return
动作 {index + 1}
; - // return ( - // { - // 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> & { - CollapsePanel?: React.FC>; -}; - -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(); - const dataSource = Array.isArray(field.value) ? field.value : []; - const [activeKeys, setActiveKeys] = useState( - 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 ; - } - return addition; - }, null); - }; - const renderEmpty = () => { - if (dataSource.length) return; - return ( - - - - ); - }; - - const renderItems = () => { - if (!dataSource || dataSource.length === 0) { - return null; - } - return ( - 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 ( - field.value?.[index]}> - { - if (!isIndexComponent(schema)) return false; - return true; - }} - onlyRenderProperties - /> - {errors.length ? ( - - {header} - - ) : ( - - )} - - ); - }; - - const extra = ( - - { - if (!isOperationComponent(schema)) return false; - return true; - }} - onlyRenderProperties - /> - {panelProps?.extra} - - ); - - const content = ( - { - if (isIndexComponent(schema)) return false; - if (isOperationComponent(schema)) return false; - return true; - }} - /> - ); - return ( - - - {content} - - - ); - })} - - ); - }; - return ( - { - setActiveKeys(insertActiveKeys(activeKeys, index)); - }} - > - {/* {renderEmpty()} */} - {renderItems()} - {renderAddition()} - - ); - }, - { displayName: 'ArrayCollapse' }, -); - -const CollapsePanel: React.FC> = ({ children }) => { - return {children}; -}; - -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 ( - { - 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'; diff --git a/packages/core/client/src/event-flow/EventSettingItem/ActionsSetting/hooks/useFilterOptions.ts b/packages/core/client/src/event-flow/EventSettingItem/ActionsSetting/hooks/useFilterOptions.ts new file mode 100644 index 0000000000..fd060cbd46 --- /dev/null +++ b/packages/core/client/src/event-flow/EventSettingItem/ActionsSetting/hooks/useFilterOptions.ts @@ -0,0 +1,104 @@ +/** + * This file is part of the NocoBase (R) project. + * Copyright (c) 2020-2024 NocoBase Co., Ltd. + * Authors: NocoBase Team. + * + * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License. + * For more information, please refer to: https://www.nocobase.com/agreement. + */ + +import { useDataSourceManager } from '../../../../data-source/data-source'; +import { useEvent } from '../../../hooks/useEvent'; +import { EventParam, EventSetting, EventDefinition } from '../../../types'; + +const useCurrentEventParams: (event?: EventSetting['event']) => { + [key: string]: EventParam; +} = (event) => { + const { definitions } = useEvent(); + const definition = definitions?.find((d) => d.name === event?.definition && d.uid === event.uid); + const eventParams = definition?.events?.find((e) => e.name === event?.event)?.params; + return eventParams; +}; + +const useStateDefine = ({ definitions }: { definitions: EventDefinition[] }) => { + const stateDefine = definitions.filter((item) => item.uid && item.states); + const stateDefineOptions = {}; + stateDefine.forEach((definition) => { + stateDefineOptions[definition.uid] = { + name: definition.uid, + title: `${definition.title}-${definition.uid}`, + type: 'object', + properties: definition.states, + }; + }); + + return { stateDefineOptions }; +}; + +export const useFilterOptions = (recordValues: EventSetting) => { + const selectedEvent: EventSetting['event'] = recordValues?.['event']; + const currentEventParamsDefine = useCurrentEventParams(selectedEvent); + const { definitions } = useEvent(); + const { stateDefineOptions } = useStateDefine({ definitions }); + + const options: EventParam[] = [ + { + name: '_eventParams', + title: '事件参数', + type: 'object', + properties: currentEventParamsDefine, + }, + { + name: '_state', + title: '组件数据', + type: 'object', + properties: stateDefineOptions, + }, + // { + // name: '_system', + // title: '系统参数', + // type: 'object', + // properties: {}, + // }, + ]; + const dm = useDataSourceManager(); + + const getOption = (opt: EventParam) => { + if (opt.type === 'object' && opt.properties) { + return { + name: opt.name, + title: opt.title, + children: Object.keys(opt.properties).map((key) => + getOption({ + ...opt.properties[key], + name: key, + }), + ), + }; + } + if (opt.type === 'array' && opt.items) { + //TODO: 处理数组 + return { + name: opt.name, + title: opt.title, + children: [], + }; + } + const fieldInterface = dm?.collectionFieldInterfaceManager.getFieldInterface(opt?.interface || opt.type); + const { nested, children, operators } = fieldInterface?.filterable || {}; + const res = { + name: opt.name, + type: opt.type, + // target: opt.target, + title: opt?.uiSchema?.title || opt.title || opt.name, + schema: opt?.uiSchema, + interface: opt.interface, + operators: + operators?.filter?.((operator) => { + return !operator?.visible || operator.visible(opt); + }) || [], + }; + return res; + }; + return options.map((opt) => getOption(opt)); +}; diff --git a/packages/core/client/src/event-flow/EventSettingItem/ActionsSetting/hooks/useVariableOptions.tsx b/packages/core/client/src/event-flow/EventSettingItem/ActionsSetting/hooks/useVariableOptions.tsx new file mode 100644 index 0000000000..5e71730317 --- /dev/null +++ b/packages/core/client/src/event-flow/EventSettingItem/ActionsSetting/hooks/useVariableOptions.tsx @@ -0,0 +1,47 @@ +/** + * This file is part of the NocoBase (R) project. + * Copyright (c) 2020-2024 NocoBase Co., Ltd. + * Authors: NocoBase Team. + * + * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License. + * For more information, please refer to: https://www.nocobase.com/agreement. + */ + +import { useCompile } from '@nocobase/client'; +import { useMemo } from 'react'; +import { useEvent } from '../../../hooks/useEvent'; +import { EventParam } from '../../../types'; + +export const useVariableOptions = () => { + const { definitions } = useEvent(); + const compile = useCompile(); + const opts = useMemo(() => { + const options = []; + const state2Variables = (state: EventParam) => { + const children = []; + if (state.properties) { + Object.keys(state.properties).forEach((key) => { + children.push(state2Variables(state.properties[key])); + }); + } + return { + label: compile(state?.uiSchema?.title || state.title), + value: state.name, + children: children, + }; + }; + options.push({ + label: '组件数据', + value: '$_state', + children: definitions + .filter((def) => def.uid && def.states) + .map((def) => ({ + label: `${def?.title}-${def.uid}`, + value: `${def.uid}`, + children: Object.keys(def.states).map((key) => state2Variables({ name: `${key}`, ...def.states[key] })), + })), + }); + return options; + }, [definitions, compile]); + return opts; +}; diff --git a/packages/core/client/src/event-flow/EventSettingItem/ActionsSetting/index.tsx b/packages/core/client/src/event-flow/EventSettingItem/ActionsSetting/index.tsx index 29e84dc9d5..fa1d4cef0f 100644 --- a/packages/core/client/src/event-flow/EventSettingItem/ActionsSetting/index.tsx +++ b/packages/core/client/src/event-flow/EventSettingItem/ActionsSetting/index.tsx @@ -21,23 +21,44 @@ import { DynamicComponentProps } from '../../../schema-component/antd/filter/Dyn import { FilterContext } from '../../../schema-component/antd/filter/context'; import { VariableInput, getShouldChange } from '../../../schema-settings/VariableInput/VariableInput'; import { Actions } from './Actions'; -import { EnableLinkage } from './components/EnableLinkage'; -import { ArrayCollapse } from './components/LinkageHeader'; import { FormProvider, createSchemaField } from '@formily/react'; -import { Filter } from '../Filter2'; +import { ArrayCollapse } from '../components/LinkageHeader'; +import { Filter } from '../Filter'; +import { ArrayBase } from '@formily/antd-v5'; +import { useFilterOptions } from './hooks/useFilterOptions'; +import { EventDefinition, EventSetting } from '../../types'; +import { useVariableOptions } from './hooks/useVariableOptions'; +import { uniqBy } from 'lodash'; export interface Props { dynamicComponent: any; + definitions: EventDefinition[]; } export const ActionsSetting = withDynamicSchemaProps( observer((props: Props) => { const fieldSchema = useFieldSchema(); - const { options, defaultValues, collectionName, form, variables, localVariables, record, dynamicComponent } = - useProps(props); // 新版 UISchema(1.0 之后)中已经废弃了 useProps,这里之所以继续保留是为了兼容旧版的 UISchema + const array = ArrayBase.useArray(); + const recordValues = ArrayBase.useRecord(); + const index = ArrayBase.useIndex(); + const { + definitions, + options, + defaultValues, + collectionName, + form, + variables, + localVariables, + record, + dynamicComponent, + } = props; const { getAllCollectionsInheritChain } = useCollectionManager_deprecated(); const parentRecordData = useCollectionParentRecordData(); + const filterOptions = useFilterOptions(recordValues); + const variableOptions = useVariableOptions(); + console.log('variableOptions', variableOptions); + const components = useMemo(() => ({ ArrayCollapse, Filter }), []); const schema = useMemo( () => ({ @@ -50,6 +71,10 @@ export const ActionsSetting = withDynamicSchemaProps( 'x-decorator': 'FormItem', 'x-component-props': { accordion: true, + titleRender: (item: any, index: number) => { + return `动作 ${index + 1}`; + }, + showEmpty: false, }, items: { type: 'object', @@ -77,7 +102,7 @@ export const ActionsSetting = withDynamicSchemaProps( 'x-component': 'Filter', 'x-use-component-props': () => { return { - options, + options: filterOptions, className: css` position: relative; width: 100%; @@ -100,6 +125,10 @@ export const ActionsSetting = withDynamicSchemaProps( localVariables, getAllCollectionsInheritChain, })} + returnScope={(scope) => { + // console.log('scope', [...scope, ...variableOptions]); + return uniqBy([...scope, ...variableOptions], 'key'); + }} /> ); }, @@ -161,6 +190,7 @@ export const ActionsSetting = withDynamicSchemaProps( props, record, variables, + filterOptions, ], ); const value = useMemo( @@ -168,22 +198,22 @@ export const ActionsSetting = withDynamicSchemaProps( [dynamicComponent, fieldSchema, options], ); - // return ; + return ; - return ( - // 这里使用 SubFormProvider 包裹,是为了让子表格的联动规则中 “当前对象” 的配置显示正确 - // - - - - - - - - - - // - ); + // return ( + // // 这里使用 SubFormProvider 包裹,是为了让子表格的联动规则中 “当前对象” 的配置显示正确 + // // + // + // + // + // + // + // + // + // + // + // // + // ); }), { displayName: 'ActionsSetting' }, ); diff --git a/packages/core/client/src/event-flow/EventSettingItem/EventsSetting/EventSelect.tsx b/packages/core/client/src/event-flow/EventSettingItem/EventSelect.tsx similarity index 59% rename from packages/core/client/src/event-flow/EventSettingItem/EventsSetting/EventSelect.tsx rename to packages/core/client/src/event-flow/EventSettingItem/EventSelect.tsx index 24e719607f..bcae2337be 100644 --- a/packages/core/client/src/event-flow/EventSettingItem/EventsSetting/EventSelect.tsx +++ b/packages/core/client/src/event-flow/EventSettingItem/EventSelect.tsx @@ -7,19 +7,19 @@ * For more information, please refer to: https://www.nocobase.com/agreement. */ -import React from 'react'; +import React, { useMemo } from 'react'; import { useControllableValue } from 'ahooks'; import { Card, Space, TreeSelect } from 'antd'; -import { EventDefinition } from '../../types'; +import { EventDefinition, EventSetting } from '../types'; export default function EventSelect(props: { - definitions: EventDefinition[]; - value: any; - onChange: (v: any) => void; + definitions?: EventDefinition[]; + value?: EventSetting['event']; + onChange?: (v: EventSetting['event']) => void; className?: string; }) { const { definitions, className } = props; - const [state, setState] = useControllableValue(props, { + const [state, setState] = useControllableValue(props, { defaultValue: undefined, }); @@ -29,21 +29,32 @@ export default function EventSelect(props: { selectable: false, children: module?.events?.map((event) => ({ - value: module.name + '.' + event.name, + value: `${module.name}.${event.name}${module.uid ? `.${module.uid}` : ''}`, title: event.title, })) || [], })); treeData = treeData?.filter((item) => item.children.length > 0); + const selectedEvent = useMemo(() => { + if (!state) return undefined; + return `${state.definition}.${state.event}${state.uid ? `.${state.uid}` : ''}`; + }, [state]); + return ( { - setState(value); + console.log('value', value); + const [definition, event, uid] = (value as any).split('.'); + setState({ + definition, + event, + uid, + }); }} treeData={treeData} className={className} diff --git a/packages/core/client/src/event-flow/EventSettingItem/EventsSetting/components/EnableLinkage.tsx b/packages/core/client/src/event-flow/EventSettingItem/EventsSetting/components/EnableLinkage.tsx deleted file mode 100644 index 6915d094be..0000000000 --- a/packages/core/client/src/event-flow/EventSettingItem/EventsSetting/components/EnableLinkage.tsx +++ /dev/null @@ -1,44 +0,0 @@ -/** - * This file is part of the NocoBase (R) project. - * Copyright (c) 2020-2024 NocoBase Co., Ltd. - * Authors: NocoBase Team. - * - * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License. - * For more information, please refer to: https://www.nocobase.com/agreement. - */ - -import { ArrayBase } from '@formily/antd-v5'; -import { Switch } from 'antd'; -import React from 'react'; -import { useTranslation } from 'react-i18next'; - -export const EnableLinkage = React.forwardRef((props: any, ref) => { - const array = ArrayBase.useArray(); - const index = ArrayBase.useIndex(props.index); - const { t } = useTranslation(); - - return ( - { - e.stopPropagation(); - array.field.value.splice(index, 1, { ...array?.field?.value[index], disabled: !checked }); - }} - onClick={(checked, e) => { - e.stopPropagation(); - }} - /> - ); -}); -EnableLinkage.displayName = 'EnableLinkage'; diff --git a/packages/core/client/src/event-flow/EventSettingItem/EventsSetting/index.tsx b/packages/core/client/src/event-flow/EventSettingItem/EventsSetting/index.tsx deleted file mode 100644 index b9f90612a9..0000000000 --- a/packages/core/client/src/event-flow/EventSettingItem/EventsSetting/index.tsx +++ /dev/null @@ -1,139 +0,0 @@ -/** - * This file is part of the NocoBase (R) project. - * Copyright (c) 2020-2024 NocoBase Co., Ltd. - * Authors: NocoBase Team. - * - * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License. - * For more information, please refer to: https://www.nocobase.com/agreement. - */ -import { css } from '@emotion/css'; -import { observer, useFieldSchema } from '@formily/react'; -import React, { useMemo } from 'react'; -import { withDynamicSchemaProps } from '../../../hoc/withDynamicSchemaProps'; -import { InputNumber, SchemaComponent, useProps } from '../../../schema-component'; -import { ArrayCollapse } from './components/LinkageHeader'; -import { FormProvider, createSchemaField } from '@formily/react'; -import { ActionsSetting } from '../ActionsSetting'; -import EventSelect from './EventSelect'; -export interface Props { - dynamicComponent: any; -} - -export const EventsSetting = withDynamicSchemaProps( - observer((props: Props) => { - const components = useMemo(() => ({ ArrayCollapse, ActionsSetting, EventSelect }), []); - const { definitions } = useProps(props); - - const schema = useMemo( - () => ({ - type: 'object', - properties: { - events: { - type: 'array', - // default: defaultValues, - 'x-component': 'ArrayCollapse', - 'x-decorator': 'FormItem', - 'x-component-props': { - accordion: true, - }, - items: { - type: 'object', - 'x-component': 'ArrayCollapse.CollapsePanel', - 'x-component-props': { - // extra: , - }, - 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 ; - // return ( - // // 这里使用 SubFormProvider 包裹,是为了让子表格的联动规则中 “当前对象” 的配置显示正确 - // // - // - // - // - // - // - // - // - // - // - // // - // ); - }), - { displayName: 'Evets' }, -); diff --git a/packages/core/client/src/event-flow/EventSettingItem/Filter2/DynamicComponent.tsx b/packages/core/client/src/event-flow/EventSettingItem/Filter/DynamicComponent.tsx similarity index 100% rename from packages/core/client/src/event-flow/EventSettingItem/Filter2/DynamicComponent.tsx rename to packages/core/client/src/event-flow/EventSettingItem/Filter/DynamicComponent.tsx diff --git a/packages/core/client/src/event-flow/EventSettingItem/Filter2/Filter.Action.Designer.tsx b/packages/core/client/src/event-flow/EventSettingItem/Filter/Filter.Action.Designer.tsx similarity index 100% rename from packages/core/client/src/event-flow/EventSettingItem/Filter2/Filter.Action.Designer.tsx rename to packages/core/client/src/event-flow/EventSettingItem/Filter/Filter.Action.Designer.tsx diff --git a/packages/core/client/src/event-flow/EventSettingItem/Filter2/Filter.tsx b/packages/core/client/src/event-flow/EventSettingItem/Filter/Filter.tsx similarity index 92% rename from packages/core/client/src/event-flow/EventSettingItem/Filter2/Filter.tsx rename to packages/core/client/src/event-flow/EventSettingItem/Filter/Filter.tsx index 033e857398..9acf486547 100644 --- a/packages/core/client/src/event-flow/EventSettingItem/Filter2/Filter.tsx +++ b/packages/core/client/src/event-flow/EventSettingItem/Filter/Filter.tsx @@ -18,6 +18,7 @@ import { FilterAction } from './FilterAction'; import { FilterGroup } from './FilterGroup'; import { SaveDefaultValue } from './SaveDefaultValue'; import { FilterContext, FilterContextProps } from './context'; +import { ArrayBase } from '@formily/antd-v5'; const useDef = (options: UseRequestOptions) => { const field = useField(); @@ -35,9 +36,8 @@ export interface FilterProps extends Omit { const { useDataSource = useDef } = props; - console.log('Filter111', props); // 新版 UISchema(1.0 之后)中已经废弃了 useProps,这里之所以继续保留是为了兼容旧版的 UISchema - const { options, dynamicComponent, className, collectionName } = useProps(props); + const { options, dynamicComponent, className, collectionName } = props; const field = useField(); const fieldSchema: any = useFieldSchema(); @@ -46,6 +46,10 @@ export const Filter: any = withDynamicSchemaProps( field.dataSource = data?.data || []; }, }); + const array = ArrayBase.useArray(); + const index = ArrayBase.useIndex(); + console.log('array', array); + console.log('index', index); useEffect(() => { if (fieldSchema.defaultValue) { @@ -64,6 +68,7 @@ export const Filter: any = withDynamicSchemaProps( collectionName, }} > + {index} diff --git a/packages/core/client/src/event-flow/EventSettingItem/Filter2/FilterAction.tsx b/packages/core/client/src/event-flow/EventSettingItem/Filter/FilterAction.tsx similarity index 100% rename from packages/core/client/src/event-flow/EventSettingItem/Filter2/FilterAction.tsx rename to packages/core/client/src/event-flow/EventSettingItem/Filter/FilterAction.tsx diff --git a/packages/core/client/src/event-flow/EventSettingItem/Filter2/FilterGroup.tsx b/packages/core/client/src/event-flow/EventSettingItem/Filter/FilterGroup.tsx similarity index 100% rename from packages/core/client/src/event-flow/EventSettingItem/Filter2/FilterGroup.tsx rename to packages/core/client/src/event-flow/EventSettingItem/Filter/FilterGroup.tsx diff --git a/packages/core/client/src/event-flow/EventSettingItem/Filter2/FilterItem.tsx b/packages/core/client/src/event-flow/EventSettingItem/Filter/FilterItem.tsx similarity index 100% rename from packages/core/client/src/event-flow/EventSettingItem/Filter2/FilterItem.tsx rename to packages/core/client/src/event-flow/EventSettingItem/Filter/FilterItem.tsx diff --git a/packages/core/client/src/event-flow/EventSettingItem/Filter2/FilterItems.tsx b/packages/core/client/src/event-flow/EventSettingItem/Filter/FilterItems.tsx similarity index 100% rename from packages/core/client/src/event-flow/EventSettingItem/Filter2/FilterItems.tsx rename to packages/core/client/src/event-flow/EventSettingItem/Filter/FilterItems.tsx diff --git a/packages/core/client/src/event-flow/EventSettingItem/Filter2/SaveDefaultValue.tsx b/packages/core/client/src/event-flow/EventSettingItem/Filter/SaveDefaultValue.tsx similarity index 96% rename from packages/core/client/src/event-flow/EventSettingItem/Filter2/SaveDefaultValue.tsx rename to packages/core/client/src/event-flow/EventSettingItem/Filter/SaveDefaultValue.tsx index 9e83a6f8e2..984ea86463 100644 --- a/packages/core/client/src/event-flow/EventSettingItem/Filter2/SaveDefaultValue.tsx +++ b/packages/core/client/src/event-flow/EventSettingItem/Filter/SaveDefaultValue.tsx @@ -43,7 +43,7 @@ export const SaveDefaultValue = (props) => { }); dn.refresh(); filterSchema.default = defaultValue; - console.log('filterSchema', defaultValue); + // console.log('filterSchema', defaultValue); }} > {t('Save conditions')} diff --git a/packages/core/client/src/event-flow/EventSettingItem/Filter2/context.ts b/packages/core/client/src/event-flow/EventSettingItem/Filter/context.ts similarity index 100% rename from packages/core/client/src/event-flow/EventSettingItem/Filter2/context.ts rename to packages/core/client/src/event-flow/EventSettingItem/Filter/context.ts diff --git a/packages/core/client/src/event-flow/EventSettingItem/Filter2/index.en-US.md b/packages/core/client/src/event-flow/EventSettingItem/Filter/index.en-US.md similarity index 100% rename from packages/core/client/src/event-flow/EventSettingItem/Filter2/index.en-US.md rename to packages/core/client/src/event-flow/EventSettingItem/Filter/index.en-US.md diff --git a/packages/core/client/src/event-flow/EventSettingItem/Filter2/index.md b/packages/core/client/src/event-flow/EventSettingItem/Filter/index.md similarity index 100% rename from packages/core/client/src/event-flow/EventSettingItem/Filter2/index.md rename to packages/core/client/src/event-flow/EventSettingItem/Filter/index.md diff --git a/packages/core/client/src/event-flow/EventSettingItem/Filter2/index.ts b/packages/core/client/src/event-flow/EventSettingItem/Filter/index.ts similarity index 100% rename from packages/core/client/src/event-flow/EventSettingItem/Filter2/index.ts rename to packages/core/client/src/event-flow/EventSettingItem/Filter/index.ts diff --git a/packages/core/client/src/event-flow/EventSettingItem/Filter2/useFilterActionProps.ts b/packages/core/client/src/event-flow/EventSettingItem/Filter/useFilterActionProps.ts similarity index 100% rename from packages/core/client/src/event-flow/EventSettingItem/Filter2/useFilterActionProps.ts rename to packages/core/client/src/event-flow/EventSettingItem/Filter/useFilterActionProps.ts diff --git a/packages/core/client/src/event-flow/EventSettingItem/Filter2/useOperators.ts b/packages/core/client/src/event-flow/EventSettingItem/Filter/useOperators.ts similarity index 100% rename from packages/core/client/src/event-flow/EventSettingItem/Filter2/useOperators.ts rename to packages/core/client/src/event-flow/EventSettingItem/Filter/useOperators.ts diff --git a/packages/core/client/src/event-flow/EventSettingItem/Filter2/useValues.ts b/packages/core/client/src/event-flow/EventSettingItem/Filter/useValues.ts similarity index 100% rename from packages/core/client/src/event-flow/EventSettingItem/Filter2/useValues.ts rename to packages/core/client/src/event-flow/EventSettingItem/Filter/useValues.ts diff --git a/packages/core/client/src/event-flow/EventSettingItem/ActionsSetting/components/EnableLinkage.tsx b/packages/core/client/src/event-flow/EventSettingItem/components/EnableLinkage.tsx similarity index 100% rename from packages/core/client/src/event-flow/EventSettingItem/ActionsSetting/components/EnableLinkage.tsx rename to packages/core/client/src/event-flow/EventSettingItem/components/EnableLinkage.tsx diff --git a/packages/core/client/src/event-flow/EventSettingItem/ActionsSetting/components/LinkageHeader.style.ts b/packages/core/client/src/event-flow/EventSettingItem/components/LinkageHeader.style.ts similarity index 100% rename from packages/core/client/src/event-flow/EventSettingItem/ActionsSetting/components/LinkageHeader.style.ts rename to packages/core/client/src/event-flow/EventSettingItem/components/LinkageHeader.style.ts diff --git a/packages/core/client/src/event-flow/EventSettingItem/EventsSetting/components/LinkageHeader.tsx b/packages/core/client/src/event-flow/EventSettingItem/components/LinkageHeader.tsx similarity index 81% rename from packages/core/client/src/event-flow/EventSettingItem/EventsSetting/components/LinkageHeader.tsx rename to packages/core/client/src/event-flow/EventSettingItem/components/LinkageHeader.tsx index 9eccb04742..05e15ae6de 100644 --- a/packages/core/client/src/event-flow/EventSettingItem/EventsSetting/components/LinkageHeader.tsx +++ b/packages/core/client/src/event-flow/EventSettingItem/components/LinkageHeader.tsx @@ -16,38 +16,13 @@ import { Badge, Card, Collapse, CollapsePanelProps, CollapseProps, Empty, Input import { cloneDeep } from 'lodash'; import React, { Fragment, useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { useToken } from '../../../../style'; +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
{`事件 ${index + 1}`}
; - // return ( - // { - // 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; + titleRender?: (item: any, index: number) => React.ReactNode; + showEmpty?: boolean; } type ComposedArrayCollapse = React.FC> & { CollapsePanel?: React.FC>; @@ -103,6 +78,7 @@ const insertActiveKeys = (activeKeys: number[], index: number) => { export const ArrayCollapse: ComposedArrayCollapse = observer( (props: IArrayCollapseProps) => { + const { titleRender, showEmpty = true } = props; const field = useField(); const dataSource = Array.isArray(field.value) ? field.value : []; const [activeKeys, setActiveKeys] = useState( @@ -124,6 +100,7 @@ export const ArrayCollapse: ComposedArrayCollapse = observer( return addition; }, null); }; + const renderEmpty = () => { if (dataSource.length) return; return ( @@ -144,8 +121,7 @@ export const ArrayCollapse: ComposedArrayCollapse = observer( onChange={(keys: string[]) => setActiveKeys(toArr(keys).map(Number))} className={props.className} style={arrayCollapseItemStyle} - > - {dataSource.map((item, index) => { + items={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'); @@ -172,13 +148,12 @@ export const ArrayCollapse: ComposedArrayCollapse = observer( {header} - ) : ( - - )} + ) : titleRender ? ( + titleRender(item, index) + ) : null} ); }; - const extra = ( { - if (isIndexComponent(schema)) return false; - if (isOperationComponent(schema)) return false; - return true; - }} - /> - ); - return ( - - - {content} - - + + { + if (isIndexComponent(schema)) return false; + if (isOperationComponent(schema)) return false; + return true; + }} + /> + ); + + return { + forceRender: true, + key: index, + label: header(), + extra: extra, + children: content, + }; })} - + /> ); }; return ( @@ -222,7 +200,7 @@ export const ArrayCollapse: ComposedArrayCollapse = observer( setActiveKeys(insertActiveKeys(activeKeys, index)); }} > - {renderEmpty()} + {showEmpty && renderEmpty()} {renderItems()} {renderAddition()} diff --git a/packages/core/client/src/event-flow/EventSettingItem/EventsSetting/components/LinkageHeader.style.ts b/packages/core/client/src/event-flow/EventSettingItem/hooks/useFilterOptions.ts similarity index 80% rename from packages/core/client/src/event-flow/EventSettingItem/EventsSetting/components/LinkageHeader.style.ts rename to packages/core/client/src/event-flow/EventSettingItem/hooks/useFilterOptions.ts index 2b4e0122cf..7689383a73 100644 --- a/packages/core/client/src/event-flow/EventSettingItem/EventsSetting/components/LinkageHeader.style.ts +++ b/packages/core/client/src/event-flow/EventSettingItem/hooks/useFilterOptions.ts @@ -7,6 +7,6 @@ * For more information, please refer to: https://www.nocobase.com/agreement. */ -export const arrayCollapseItemStyle = { - marginBottom: 10, +export const useFilterOptions = () => { + return { filterOptions: [] }; }; diff --git a/packages/core/client/src/event-flow/EventSettingItem/index.tsx b/packages/core/client/src/event-flow/EventSettingItem/index.tsx index ecdacd0ecc..9c92238ecd 100644 --- a/packages/core/client/src/event-flow/EventSettingItem/index.tsx +++ b/packages/core/client/src/event-flow/EventSettingItem/index.tsx @@ -21,12 +21,17 @@ import { useFormBlockType, useRecord, } from '@nocobase/client'; -import React from 'react'; +import React, { useMemo } from 'react'; import { ISchema, useField } from '@formily/react'; import { SchemaSettingsKey, useEvent } from '..'; import { useFieldSchema } from '@formily/react'; import { useLinkageCollectionFieldOptions } from './ActionsSetting/action-hooks'; -import { EventsSetting } from './EventsSetting'; +import { ActionsSetting } from './ActionsSetting'; +import EventSelect from './EventSelect'; +import { ArrayCollapse } from './components/LinkageHeader'; +import { css } from '@emotion/css'; +import { useFilterOptions } from './hooks/useFilterOptions'; +import { FormItem, FormLayout } from '@formily/antd-v5'; // packages/core/client/src/schema-settings/SchemaSettings.tsx export const EventSettingItem = (props) => { @@ -38,7 +43,6 @@ export const EventSettingItem = (props) => { const { definitions, register } = useEvent(); const { dn } = useDesignable(); const fieldSchema = useFieldSchema(); - console.log('definitions', definitions); const { readPretty, Component, afterSubmit } = props; const collectionName = 't_aierml1wni1'; const options = useLinkageCollectionFilterOptions(collectionName); @@ -52,7 +56,7 @@ export const EventSettingItem = (props) => { return ( { title: '事件配置', properties: { events: { - 'x-component': EventsSetting, - 'x-use-component-props': () => { - return { - definitions, - options, - defaultValues: undefined, - linkageOptions, - category: 'default', - elementType: 'field', - collectionName, - form, - variables, - localVariables, - record, - formBlockType, - }; + type: 'array', + // default: defaultValues, + 'x-component': 'ArrayCollapse', + 'x-decorator': 'FormItem', + 'x-component-props': { + accordion: true, + titleRender: (item: any, index: number) => { + return `事件 ${index + 1}`; + }, + }, + items: { + type: 'object', + 'x-component': 'ArrayCollapse.CollapsePanel', + 'x-component-props': { + // extra: , + }, + properties: { + layout: { + type: 'void', + 'x-component': 'FormLayout', + 'x-component-props': { + labelStyle: { + marginTop: '4px', + }, + labelCol: 8, + wrapperCol: 16, + }, + properties: { + eventTitle: { + 'x-component': 'h4', + 'x-content': '{{ t("触发事件") }}', + }, + event: { + 'x-component': EventSelect, + 'x-component-props': { + definitions, + className: css` + margin-bottom: 12px; + `, + }, + }, + actionTitle: { + 'x-component': 'h4', + 'x-content': '{{ t("执行动作") }}', + }, + actions: { + type: 'void', + 'x-component': ActionsSetting, + 'x-use-component-props': () => { + return { + definitions, + options, + linkageOptions, + category: 'default', + elementType: 'field', + collectionName, + form, + variables, + localVariables, + record, + formBlockType, + }; + }, + }, + }, + }, + remove: { + type: 'void', + 'x-component': 'ArrayCollapse.Remove', + }, + }, + }, + properties: { + add: { + type: 'void', + title: '{{ t("Add events") }}', + 'x-component': 'ArrayCollapse.Addition', + }, }, }, }, } as ISchema } onSubmit={({ events }) => { - console.log('onSubmit', events); - fieldSchema[SchemaSettingsKey] = events; - dn.emit('patch', { - schema: { - 'x-uid': fieldSchema['x-uid'], - [SchemaSettingsKey]: events, - }, - }); - register(events); - dn.refresh(); + console.log('todo onSubmit', JSON.parse(JSON.stringify(events))); + // fieldSchema[SchemaSettingsKey] = events; + // dn.emit('patch', { + // schema: { + // 'x-uid': fieldSchema['x-uid'], + // [SchemaSettingsKey]: events, + // }, + // }); + // register(events); + // dn.refresh(); }} /> ); diff --git a/packages/core/client/src/event-flow/types/index.ts b/packages/core/client/src/event-flow/types/index.ts index 013982865c..97b5be6107 100644 --- a/packages/core/client/src/event-flow/types/index.ts +++ b/packages/core/client/src/event-flow/types/index.ts @@ -20,6 +20,8 @@ export interface EventParam { [key: string]: EventParam; }; items?: EventParam; + interface?: string; + uiSchema?: any; } /** 事件动作 */ @@ -42,6 +44,7 @@ export interface EventEvent { params?: { [key: string]: EventParam; }; + value?: any; } /** 事件定义 */ @@ -60,7 +63,11 @@ export interface EventDefinition { /** 事件设置 */ export interface EventSetting { - event: string; + event: { + definition: string; + event: string; + uid?: string; + }; /** 标识同一类型组件的不同实例 */ uid?: string; condition: string;