diff --git a/packages/core/client/src/collection-manager/action-hooks.ts b/packages/core/client/src/collection-manager/action-hooks.ts index 7c4b363f3..c38c3038b 100644 --- a/packages/core/client/src/collection-manager/action-hooks.ts +++ b/packages/core/client/src/collection-manager/action-hooks.ts @@ -126,6 +126,7 @@ export const useCollectionFilterOptions = (collectionName: string) => { operators?.filter?.((operator) => { return !operator?.visible || operator.visible(field); }) || [], + interface: field.interface, }; if (field.target && depth > 2) { return; diff --git a/packages/core/client/src/locale/en_US.ts b/packages/core/client/src/locale/en_US.ts index 07d713859..a262ec961 100644 --- a/packages/core/client/src/locale/en_US.ts +++ b/packages/core/client/src/locale/en_US.ts @@ -52,6 +52,7 @@ export default { "Value":"Value", "Disabled":"Disabled", "Enabled":"Enabled", + "Empty":"Empty", "Linkage rule":"Linkage rule", "Linkage rules":"Linkage rules", "Condition":"Condition", diff --git a/packages/core/client/src/locale/ja_JP.ts b/packages/core/client/src/locale/ja_JP.ts index c4aeb858d..de94da9e9 100644 --- a/packages/core/client/src/locale/ja_JP.ts +++ b/packages/core/client/src/locale/ja_JP.ts @@ -58,6 +58,7 @@ export default { "Value":"フィールド値", "Disabled":"無効化", "Enabled":"有効化", + "Empty":"くうきち", "Linkage rule":"連動規則", "Linkage rules":"連動規則", "Condition":"条件#ジョウケン#", diff --git a/packages/core/client/src/locale/zh_CN.ts b/packages/core/client/src/locale/zh_CN.ts index 79ae12ee7..e70e20541 100644 --- a/packages/core/client/src/locale/zh_CN.ts +++ b/packages/core/client/src/locale/zh_CN.ts @@ -50,6 +50,7 @@ export default { "Value":"字段值", "Disabled":"禁用", "Enabled":"启用", + "Empty":"赋空值", "Linkage rule":"联动规则", "Linkage rules":"联动规则", "Condition":"条件", diff --git a/packages/core/client/src/schema-component/antd/action/Action.tsx b/packages/core/client/src/schema-component/antd/action/Action.tsx index 62a447e51..b010ac814 100644 --- a/packages/core/client/src/schema-component/antd/action/Action.tsx +++ b/packages/core/client/src/schema-component/antd/action/Action.tsx @@ -2,13 +2,14 @@ import { css } from '@emotion/css'; import { observer, RecursionField, useField, useFieldSchema, useForm } from '@formily/react'; import { Button, Modal, Popover } from 'antd'; import classnames from 'classnames'; -import React, { useState, useEffect } from 'react'; +import React, { useEffect, useState } from 'react'; import { useActionContext } from '../..'; +import { useDesignable } from '../../'; import { Icon } from '../../../icon'; +import { useRecord } from '../../../record-provider'; import { SortableItem } from '../../common'; import { useCompile, useComponent, useDesigner } from '../../hooks'; import { useProps } from '../../hooks/useProps'; -import { useRecord } from '../../../record-provider'; import ActionContainer from './Action.Container'; import { ActionDesigner } from './Action.Designer'; import { ActionDrawer } from './Action.Drawer'; @@ -18,7 +19,6 @@ import { ActionPage } from './Action.Page'; import { ActionContext } from './context'; import { useA } from './hooks'; import { ComposedAction } from './types'; -import { useDesignable } from '../../'; import { linkageAction } from './utils'; export const actionDesignerCss = css` @@ -96,15 +96,17 @@ export const Action: ComposedAction = observer((props: any) => { const disabled = form.disabled || field.disabled; const openSize = fieldSchema?.['x-component-props']?.['openSize']; const linkageRules = fieldSchema?.['x-linkage-rules'] || []; - const { designable, } = useDesignable(); - const tarComponent=useComponent(component)||component; + const { designable } = useDesignable(); + const tarComponent = useComponent(component) || component; useEffect(() => { field.linkageProperty = {}; - linkageRules.map((v) => { - return v.actions?.map((h) => { - linkageAction(h.operator, field, v.condition, values); + linkageRules + .filter((k) => !k.disabled) + .map((v) => { + return v.actions?.map((h) => { + linkageAction(h.operator, field, v.condition, values); + }); }); - }); }, [linkageRules, values]); const renderButton = () => ( { const { form } = props; const fieldSchema = useFieldSchema(); const { setFormValueChanged } = useActionContext(); - const linkageRules = getLinkageRules(fieldSchema) || fieldSchema.parent?.['x-linkage-rules'] || []; + const linkageRules = + (getLinkageRules(fieldSchema) || fieldSchema.parent?.['x-linkage-rules'])?.filter((k) => !k.disabled) || []; useEffect(() => { const id = uid(); form.addEffects(id, () => { @@ -100,7 +101,9 @@ const WithForm = (props) => { }; }); onFieldChange(`*(${fields})`, ['value', 'required', 'pattern', 'display'], (field: any) => { - field.linkageProperty = {}; + field.linkageProperty = { + display: field.linkageProperty?.display, + }; }); } }); diff --git a/packages/core/client/src/schema-component/antd/form-v2/utils.tsx b/packages/core/client/src/schema-component/antd/form-v2/utils.tsx index 9ee11e240..67df5a7f2 100644 --- a/packages/core/client/src/schema-component/antd/form-v2/utils.tsx +++ b/packages/core/client/src/schema-component/antd/form-v2/utils.tsx @@ -1,47 +1,13 @@ -import { last, get } from 'lodash'; -import * as functions from '@formulajs/formulajs'; +import { last, cloneDeep } from 'lodash'; import { conditionAnalyse } from '../../common/utils/uitls'; import { ActionType } from '../../../schema-settings/LinkageRules/type'; - -function now() { - return new Date(); -} - -const fnNames = Object.keys(functions).filter((key) => key !== 'default'); -const fns = fnNames.map((key) => functions[key]); -function formula(expression: string, scope = {}) { - try { - const fn = new Function(...fnNames, ...Object.keys(scope), `return ${expression}`); - const result = fn(...fns, ...Object.values(scope)); - if (typeof result === 'number') { - if (Number.isNaN(result) || !Number.isFinite(result)) { - return null; - } - return functions.ROUND(result, 9); - } - if (typeof result === 'function') { - return result(); - } - return result; - } catch (error) { - return undefined; - } -} - -export function evaluate(expression: string, scope = {}) { - const mergeScope = { ...scope, now }; - const exp = expression.trim().replace(/{{\s*([^{}]+)\s*}}/g, (_, v) => { - const item: any = get(scope, v); - const key = v.replace(/\.(\d+)/g, '["$1"]'); - return ` ${typeof item === 'function' ? item() : key} `; - }); - return formula(exp, mergeScope); -} +import evaluators from '@nocobase/evaluators/client'; export const linkageMergeAction = ({ operator, value }, field, condition, values) => { const requiredResult = field?.linkageProperty?.required || [field?.initProperty?.required || false]; const displayResult = field?.linkageProperty?.display || [field?.initProperty?.display]; const patternResult = field?.linkageProperty?.pattern || [field?.initProperty?.pattern]; const valueResult = field?.linkageProperty?.value || [field.value || field?.initProperty?.value]; + const { evaluate } = evaluators.get('formula.js'); switch (operator) { case ActionType.Required: @@ -91,17 +57,23 @@ export const linkageMergeAction = ({ operator, value }, field, condition, values case ActionType.Value: if (conditionAnalyse(condition, values)) { if (value?.mode === 'express') { - const result = evaluate(value.result || value.value, values); - valueResult.push(result); - } else { + const scope = cloneDeep(values); + try { + const result = evaluate(value.result || value.value, { ...scope, now: () => new Date().toString() }); + valueResult.push(result); + } catch (error) { + } + } else if (value?.mode === 'constant') { valueResult.push(value?.value || value); + } else { + valueResult.push(null); } } field.linkageProperty = { ...field.linkageProperty, value: valueResult, }; - setTimeout(() => (field.value = last(valueResult) === undefined ? field.value : last(valueResult))); + field.value = last(valueResult) === undefined ? field.value : last(valueResult); break; default: return null; diff --git a/packages/core/client/src/schema-component/common/utils/logic.js b/packages/core/client/src/schema-component/common/utils/logic.js index 5f2efddd2..57236334d 100644 --- a/packages/core/client/src/schema-component/common/utils/logic.js +++ b/packages/core/client/src/schema-component/common/utils/logic.js @@ -39,7 +39,10 @@ http://ricostacruz.com/cheatsheets/umdjs.html var jsonLogic = {}; var operations = { $is: function (a, b) { - return a == b; + return a === b; + }, + $match: function (a, b) { + return JSON.stringify(a) === JSON.stringify(b); }, $eq: function (a, b) { return a === b; @@ -87,10 +90,16 @@ http://ricostacruz.com/cheatsheets/umdjs.html if (!a || typeof a.indexOf === 'undefined') return false; return a.indexOf(b) !== -1; }, - $notIncludes:function (a, b) { + $notIncludes: function (a, b) { if (!a || typeof a.indexOf === 'undefined') return false; return !(a.indexOf(b) !== -1); }, + $isTruly: function (a) { + return a === true || a === 1; + }, + $isFalsy: function (a) { + return !jsonLogic.truthy(a); + }, cat: function () { return Array.prototype.join.call(arguments, ''); }, diff --git a/packages/core/client/src/schema-component/common/utils/uitls.tsx b/packages/core/client/src/schema-component/common/utils/uitls.tsx index 6bb2287cc..c0b3b9818 100644 --- a/packages/core/client/src/schema-component/common/utils/uitls.tsx +++ b/packages/core/client/src/schema-component/common/utils/uitls.tsx @@ -1,30 +1,21 @@ -import { every, some, get } from 'lodash'; +import { every, some, findIndex } from 'lodash'; import flat from 'flat'; import jsonLogic from '../../common/utils/logic'; -function getDeepestProperty(obj) { - let deepest = { - operator: null, - value: null, - }; - let deepestLevel = 0; - function traverse(obj, level) { - for (const key in obj) { - if (obj.hasOwnProperty(key)) { - if (typeof obj[key] === 'object') { - traverse(obj[key], level + 1); - } else { - if (level > deepestLevel) { - deepestLevel = level; - deepest.operator = key; - deepest.value = obj[key]; - } - } +function getInnermostKeyAndValue(obj) { + if (typeof obj !== 'object' || obj === null) { + return null; + } + for (const key in obj) { + if (Object.prototype.hasOwnProperty.call(obj, key)) { + if (Object.prototype.toString.call(obj[key]) === '[object Object]' && obj[key] !== null) { + return getInnermostKeyAndValue(obj[key]); + } else { + return { key, value: obj[key] }; } } } - traverse(obj, 1); - return deepest; + return null; } const getValue = (str, values) => { const regex = /{{(.*?)}}/; @@ -40,20 +31,47 @@ const getVariableValue = (str, values) => { const match = regex.exec(str); return values[match?.[1]]; }; +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; +}; + +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; +} export const conditionAnalyse = (rules, values) => { const type = Object.keys(rules)[0] || '$and'; const conditions = rules[type]; const results = conditions.map((c) => { - const jsonlogic = getDeepestProperty(c); - const operator = jsonlogic.operator; - const value = getValue(jsonlogic.value, values); - const targetField = Object.keys(flat(c))[0]?.replace?.(`.${operator}`, ''); + const jsonlogic = getInnermostKeyAndValue(c); + const operator = jsonlogic?.key; + const value = getValue(jsonlogic?.value, values); + const targetField = getTargetField(c); if (!operator) { return true; } try { - const result = jsonLogic.apply({ [operator]: [flat(values)?.[targetField], value] }); + const currentValue = targetField.length > 1 ? flat(values)?.[targetField.join('.')] : values?.[targetField[0]]; + const result = jsonLogic.apply({ [operator]: [currentValue, value] }); return result; } catch (error) { console.error(error); diff --git a/packages/core/client/src/schema-settings/LinkageRules/LinkageRuleAction.tsx b/packages/core/client/src/schema-settings/LinkageRules/LinkageRuleAction.tsx index e252f58fb..afe3618dd 100644 --- a/packages/core/client/src/schema-settings/LinkageRules/LinkageRuleAction.tsx +++ b/packages/core/client/src/schema-settings/LinkageRules/LinkageRuleAction.tsx @@ -1,12 +1,13 @@ import { CloseCircleOutlined } from '@ant-design/icons'; import { css } from '@emotion/css'; -import { observer } from '@formily/react'; +import { observer, useField } from '@formily/react'; import { TreeSelect } from '@formily/antd'; -import { Select, Space } from 'antd'; +import { Select, Space } from 'antd'; import React, { useContext, useState } from 'react'; import { useTranslation } from 'react-i18next'; +import { uid } from '@formily/shared'; import { useCompile } from '../..'; -import { RemoveActionContext } from './context'; +import { RemoveActionContext, LinkageLogicContext } from './context'; import { DynamicComponent } from './DynamicComponent'; import { useValues } from './useValues'; import { ActionType } from './type'; @@ -28,60 +29,61 @@ export const FormFieldLinkageRuleAction = observer((props: any) => { operators, } = useValues(options); return ( -
- - +
+ { - console.log(value) - setDataIndex(value); - }} - placeholder={t('Select Field')} - /> - { + setOperator(value); + }} + placeholder={t('action')} + /> + {[ActionType.Value].includes(operator) && ( + + )} + {!props.disabled && ( + + remove()} style={{ color: '#bfbfbf' }} /> + + )} + +
+ ); }); diff --git a/packages/core/client/src/schema-settings/LinkageRules/ValueDynamicComponent.tsx b/packages/core/client/src/schema-settings/LinkageRules/ValueDynamicComponent.tsx index 4f29d14dc..1c1c82cd1 100644 --- a/packages/core/client/src/schema-settings/LinkageRules/ValueDynamicComponent.tsx +++ b/packages/core/client/src/schema-settings/LinkageRules/ValueDynamicComponent.tsx @@ -1,25 +1,37 @@ import React, { useState } from 'react'; import { Input, Select } from 'antd'; +import { css } from '@emotion/css'; import { useTranslation } from 'react-i18next'; import { DynamicComponent } from './DynamicComponent'; -const { Option } = Select; import { Variable } from '.././../schema-component'; import { useVariableOptions } from './Variables'; +const { Option } = Select; + export const ValueDynamicComponent = (props) => { const { fieldValue, schema, setValue, collectionName } = props; const [mode, setMode] = useState(fieldValue?.mode || 'constant'); const { t } = useTranslation(); const scope = useVariableOptions(collectionName); return ( - - { + setMode(value); + setValue({ + mode: value, + }); + }} + > + -
- {mode === 'constant' ? ( - React.createElement(DynamicComponent, { + {mode === 'constant' ? ( +
+ {React.createElement(DynamicComponent, { value: fieldValue?.value || fieldValue, schema, onChange(value) { @@ -28,8 +40,10 @@ export const ValueDynamicComponent = (props) => { value, }); }, - }) - ) : ( + })} +
+ ) : mode === 'express' ? ( +
{ @@ -43,8 +57,16 @@ export const ValueDynamicComponent = (props) => { scope={scope} style={{ minWidth: 460, marginRight: 15 }} /> - )} -
+ <> + + {t('Syntax references')}: + + + Formula.js + + +
+ ) : null}
); }; diff --git a/packages/core/client/src/schema-settings/LinkageRules/Variables.tsx b/packages/core/client/src/schema-settings/LinkageRules/Variables.tsx index 042a47ac9..db9a79c5f 100644 --- a/packages/core/client/src/schema-settings/LinkageRules/Variables.tsx +++ b/packages/core/client/src/schema-settings/LinkageRules/Variables.tsx @@ -17,9 +17,12 @@ const supportsType = [ 'checkboxGroup', 'select', 'multipleSelect', + 'formula', 'oho', 'obo', 'm2o', + 'o2m', + 'm2m', ]; const useVariableTypes = (currentCollection) => { const { getCollectionFields, getInterface, getCollection } = useCollectionManager(); @@ -45,10 +48,10 @@ const useVariableTypes = (currentCollection) => { schema: field?.uiSchema, value: field.name, }; - if (field.target && depth > 2) { + if (field.target && depth > 1) { return; } - if (depth > 2) { + if (depth > 1) { return option; } if (children?.length) { diff --git a/packages/core/client/src/schema-settings/LinkageRules/components/EnableLinkage.tsx b/packages/core/client/src/schema-settings/LinkageRules/components/EnableLinkage.tsx new file mode 100644 index 000000000..54a91a996 --- /dev/null +++ b/packages/core/client/src/schema-settings/LinkageRules/components/EnableLinkage.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import { Switch } from 'antd'; +import { ArrayBase } from '@formily/antd'; + +export const EnableLinkage = React.forwardRef((props: any, ref) => { + const array = ArrayBase.useArray(); + const index = ArrayBase.useIndex(props.index); + return ( + { + e.stopPropagation(); + array.field.value.splice(index, 1, { ...array?.field?.value[index], disabled: !checked }); + }} + onClick={(checked, e) => { + e.stopPropagation(); + }} + /> + ); +}); diff --git a/packages/core/client/src/schema-settings/LinkageRules/components/LinkageHeader.tsx b/packages/core/client/src/schema-settings/LinkageRules/components/LinkageHeader.tsx new file mode 100644 index 000000000..e6666264d --- /dev/null +++ b/packages/core/client/src/schema-settings/LinkageRules/components/LinkageHeader.tsx @@ -0,0 +1,262 @@ +import React, { Fragment, useState, useEffect } from 'react'; +import { Badge, Card, Collapse, CollapsePanelProps, CollapseProps, Empty, Input } from 'antd'; +import { ArrayField } from '@formily/core'; +import { RecursionField, useField, useFieldSchema, observer, ISchema } from '@formily/react'; +import { toArr } from '@formily/shared'; +import cls from 'classnames'; +import { CopyOutlined } from '@ant-design/icons'; +import { clone } from 'lodash'; +import { ArrayBase, ArrayBaseMixins } from '@formily/antd'; +import { useTranslation } from 'react-i18next'; + +const LinkageRulesTitle = (props) => { + const array = ArrayBase.useArray(); + const index = ArrayBase.useIndex(props.index); + const { t } = useTranslation(); + const value = array?.field?.value[index]; + 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> & + ArrayBaseMixins & { + 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(); + const prefixCls = 'ant-formily-array-collapse'; + 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 = () => { + return ( + setActiveKeys(toArr(keys).map(Number))} + className={cls(`${prefixCls}-item`, props.className)} + > + {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()} + + ); +}); + +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 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 = clone(array?.field?.value[index]); + array.field.push(value); + if (props.onClick) { + props.onClick(e); + } + }} + /> + ); +}); diff --git a/packages/core/client/src/schema-settings/LinkageRules/context.ts b/packages/core/client/src/schema-settings/LinkageRules/context.ts index 77349c388..4ca6cf3d0 100644 --- a/packages/core/client/src/schema-settings/LinkageRules/context.ts +++ b/packages/core/client/src/schema-settings/LinkageRules/context.ts @@ -12,4 +12,4 @@ export interface FilterContextProps { export const RemoveActionContext = createContext(null); export const FilterContext = createContext(null); -export const FilterLogicContext = createContext(null); \ No newline at end of file +export const LinkageLogicContext = createContext(null); \ No newline at end of file diff --git a/packages/core/client/src/schema-settings/LinkageRules/index.tsx b/packages/core/client/src/schema-settings/LinkageRules/index.tsx index 9cec347c3..d6a7b1914 100644 --- a/packages/core/client/src/schema-settings/LinkageRules/index.tsx +++ b/packages/core/client/src/schema-settings/LinkageRules/index.tsx @@ -5,6 +5,8 @@ import { SchemaComponent } from '../../schema-component'; import { FilterContext } from '../../schema-component/antd/filter/context'; import { FilterDynamicComponent } from './FilterDynamicComponent'; import { LinkageRuleActionGroup } from './LinkageRuleActionGroup'; +import { ArrayCollapse } from './components/LinkageHeader'; +import { EnableLinkage } from './components/EnableLinkage'; export const FormLinkageRules = observer((props: any) => { const fieldSchema = useFieldSchema(); @@ -13,6 +15,7 @@ export const FormLinkageRules = observer((props: any) => { return ( { type: 'object', 'x-component': 'ArrayCollapse.CollapsePanel', 'x-component-props': { - header: '{{ t("Linkage rule") }}', + extra: [], }, properties: { - index: { - type: 'void', - 'x-component': 'ArrayCollapse.Index', - }, layout: { type: 'void', 'x-component': 'FormLayout', @@ -91,6 +90,10 @@ export const FormLinkageRules = observer((props: any) => { type: 'void', 'x-component': 'ArrayCollapse.MoveDown', }, + copy: { + type: 'void', + 'x-component': 'ArrayCollapse.Copy', + }, }, }, properties: { diff --git a/packages/core/client/src/schema-settings/LinkageRules/useValues.ts b/packages/core/client/src/schema-settings/LinkageRules/useValues.ts index 66ce3880a..c277354fb 100644 --- a/packages/core/client/src/schema-settings/LinkageRules/useValues.ts +++ b/packages/core/client/src/schema-settings/LinkageRules/useValues.ts @@ -1,6 +1,6 @@ import { useField } from '@formily/react'; -import { useContext, useEffect } from 'react'; -import { FilterLogicContext } from './context'; +import { useEffect, useContext } from 'react'; +import { LinkageLogicContext } from './context'; const findOption = (dataIndex = [], options) => { let items = options; @@ -17,11 +17,11 @@ const findOption = (dataIndex = [], options) => { export const useValues = (options) => { const field = useField(); - const logic = useContext(FilterLogicContext); + const logic = useContext(LinkageLogicContext); const value2data = () => { - field.data = { ...field.initialValue }; - const dataIndex = field.initialValue?.targetFields; + field.data = { ...(field.initialValue || field.value) }; + const dataIndex = field.data?.targetFields; const option = (dataIndex && findOption(dataIndex, options)) || {}; const operators = option?.operators || []; field.data.operators = operators; @@ -36,9 +36,6 @@ export const useValues = (options) => { field.data = field.data || {}; const operators = option?.operators; field.data.operators = operators?.filter((v) => { - // if (dataIndex.length > 1) { - // return v.value !== 'value'; - // } return true; }); field.data.schema = option?.schema; diff --git a/packages/core/client/src/schema-settings/SchemaSettings.tsx b/packages/core/client/src/schema-settings/SchemaSettings.tsx index 000cd8847..3b2172fea 100644 --- a/packages/core/client/src/schema-settings/SchemaSettings.tsx +++ b/packages/core/client/src/schema-settings/SchemaSettings.tsx @@ -960,7 +960,9 @@ SchemaSettings.LinkageRules = (props) => { 'x-component': FormLinkageRules, 'x-component-props': { useProps: () => { - const options = useCollectionFilterOptions(collectionName); + const options = useCollectionFilterOptions(collectionName).filter( + (v) => !['o2m', 'm2m'].includes(v.interface), + ); return { options, defaultValues: gridSchema?.['x-linkage-rules'] || fieldSchema?.['x-linkage-rules'], diff --git a/packages/core/evaluators/src/utils/index.ts b/packages/core/evaluators/src/utils/index.ts index 829a1cdb4..feca86d55 100644 --- a/packages/core/evaluators/src/utils/index.ts +++ b/packages/core/evaluators/src/utils/index.ts @@ -15,7 +15,7 @@ function appendArrayColumn(scope, key) { if (Array.isArray(data) && !isIndex && !data[path]) { data[path] = data.map(item => item[path]); } - data = data[path]; + data = data?.[path]; } }