From c0f9c8116ac0c778ce1a071ec3af30eb8e2c3f18 Mon Sep 17 00:00:00 2001 From: katherinehhh Date: Mon, 29 May 2023 11:22:04 +0800 Subject: [PATCH] refactor(linkage-rule): linkage rules condition support toMany association fields (#1924) * refactor: linkage rule support to many association field * refactor: linkage rule support toMany * fix: support toMany association field * fix: support toMany association field * fix: operator support toMany association field * refactor: useLinkageCollectionFilterOptions --- .../src/collection-manager/action-hooks.ts | 9 +++- .../schema-component/common/utils/logic.js | 30 +++++++++++++- .../schema-component/common/utils/uitls.tsx | 41 ++++++++++++++++--- 3 files changed, 71 insertions(+), 9 deletions(-) diff --git a/packages/core/client/src/collection-manager/action-hooks.ts b/packages/core/client/src/collection-manager/action-hooks.ts index 817842a9a..1f7e1f9b1 100644 --- a/packages/core/client/src/collection-manager/action-hooks.ts +++ b/packages/core/client/src/collection-manager/action-hooks.ts @@ -203,7 +203,7 @@ export const useCollectionFilterOptions = (collectionName: string) => { export const useLinkageCollectionFilterOptions = (collectionName: string) => { const { getCollectionFields, getInterface } = useCollectionManager(); - const fields = getCollectionFields(collectionName).filter((v) => !['o2m', 'm2m'].includes(v.interface)); + const fields = getCollectionFields(collectionName); const field2option = (field, depth) => { if (!field.interface) { return; @@ -233,7 +233,12 @@ export const useLinkageCollectionFilterOptions = (collectionName: string) => { option['children'] = children; } if (nested) { - const targetFields = getCollectionFields(field.target).filter((v) => !['o2m', 'm2m'].includes(v.interface)); + const targetFields = getCollectionFields(field.target).filter((v) => { + if (['hasMany', 'belongsToMany'].includes(field.type)) { + return !['hasOne', 'hasMany', 'belongsTo', 'belongsToMany'].includes(v.type); + } + return !['hasMany', 'belongsToMany'].includes(v.type); + }); const options = getOptions(targetFields, depth + 1).filter(Boolean); option['children'] = option['children'] || []; option['children'].push(...options); 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 4810709ba..59f29fe15 100644 --- a/packages/core/client/src/schema-component/common/utils/logic.js +++ b/packages/core/client/src/schema-component/common/utils/logic.js @@ -35,6 +35,9 @@ http://ricostacruz.com/cheatsheets/umdjs.html } return a; } + function areArraysEqual(arr1, arr2) { + return JSON.stringify(arr1) === JSON.stringify(arr2); + } var jsonLogic = {}; var operations = { @@ -42,9 +45,18 @@ http://ricostacruz.com/cheatsheets/umdjs.html return a === b; }, $match: function (a, b) { + if (Array.isArray(a) && Array.isArray(b) && a.some((element) => Array.isArray(element))) { + return a.some( + (subArray) => subArray?.length === b.length && subArray?.every((element, index) => element === b[index]), + ); + } return JSON.stringify(a) === JSON.stringify(b); }, $eq: function (a, b) { + if (Array.isArray(a) && Array.isArray(b)) return areArraysEqual(a, b); + if (Array.isArray(a)) { + return a.includes(b); + } return a === b; }, $ne: function (a, b) { @@ -54,12 +66,14 @@ http://ricostacruz.com/cheatsheets/umdjs.html return a !== b; }, $gt: function (a, b) { + if (Array.isArray(a)) return a.some((k) => k > b); return a > b; }, $gte: function (a, b) { return a >= b; }, $lt: function (a, b, c) { + if (Array.isArray(a)) return a.some((k) => k < b); return c === undefined ? a < b : a < b && b < c; }, $lte: function (a, b, c) { @@ -72,6 +86,7 @@ http://ricostacruz.com/cheatsheets/umdjs.html return jsonLogic.truthy(a); }, $empty: function (a) { + if (Array.isArray(a)) return a.some((k) => !jsonLogic.truthy(k)); return !jsonLogic.truthy(a); }, $notExists: function (a) { @@ -86,6 +101,9 @@ http://ricostacruz.com/cheatsheets/umdjs.html }, $in: function (a, b) { if (!b || typeof b.indexOf === 'undefined') return false; + if (Array.isArray(a) && Array.isArray(b)) { + return b.some((elementB) => a.includes(elementB)); + } return b.indexOf(a) !== -1; }, $notIn: function (a, b) { @@ -94,22 +112,30 @@ http://ricostacruz.com/cheatsheets/umdjs.html }, $includes: function (a, b) { if (!a || typeof a.indexOf === 'undefined') return false; + if (Array.isArray(a)) return a.some((element) => element?.includes(b)); return a.indexOf(b) !== -1; }, $notIncludes: function (a, b) { if (!a || typeof a.indexOf === 'undefined') return false; + if (Array.isArray(a)) return !a.some((element) => element.includes(b)); return !(a.indexOf(b) !== -1); }, $anyOf: function (a, b) { if (a.length === 0) { return false; } - return b.every((item) => a.includes(item)); + if (Array.isArray(a) && Array.isArray(b) && a.some((element) => Array.isArray(element))) { + return a.some((subArray) => subArray.some((element) => b.includes(element))); + } + return a.some((element) => b.includes(element)); }, $noneOf: function (a, b) { if (a.length === 0) { return true; } + if (Array.isArray(a) && Array.isArray(b) && a.some((element) => Array.isArray(element))) { + return a.some((subArray) => subArray.every((element) => !b.some((bElement) => element.includes(bElement)))); + } return b.some((item) => !a.includes(item)); }, $notMatch: function (a, b) { @@ -125,9 +151,11 @@ http://ricostacruz.com/cheatsheets/umdjs.html return false; }, $isTruly: function (a) { + if (Array.isArray(a)) return a.some((k) => k === true || k === 1); return a === true || a === 1; }, $isFalsy: function (a) { + if (Array.isArray(a)) return a.some((k) => !jsonLogic.truthy(k)); return !jsonLogic.truthy(a); }, cat: function () { 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 bf9288f80..34600060f 100644 --- a/packages/core/client/src/schema-component/common/utils/uitls.tsx +++ b/packages/core/client/src/schema-component/common/utils/uitls.tsx @@ -1,5 +1,5 @@ import flat from 'flat'; -import _, { every, findIndex, some } from 'lodash'; +import _, { every, findIndex, some, isArray } from 'lodash'; import moment from 'moment'; import { useCurrentUserContext } from '../../../user'; import jsonLogic from '../../common/utils/logic'; @@ -57,11 +57,25 @@ function getInnermostKeyAndValue(obj) { return null; } +const getFieldValue = (fieldPath, values) => { + const v = fieldPath[0]; + const h = fieldPath[1]; + const regex = new RegExp('^' + v + '\\..+\\.' + h + '$'); // 构建匹配的正则表达式 + const matchedValues = []; + const data = flat.flatten(values, { maxDepth: 3 }); + for (var key in data) { + if (regex.test(key)) { + matchedValues.push(data[key]); + } + } + return matchedValues; +}; + const getValue = (str: string, values) => { const regex = /{{(.*?)}}/; const matches = str?.match?.(regex); if (matches) { - return getVariableValue(str, flat(values)); + return getVariableValue(str, values); } else { return str; } @@ -69,7 +83,14 @@ const getValue = (str: string, values) => { const getVariableValue = (str, values) => { const regex = /{{[^.]+\.([^}]+)}}/; const match = regex.exec(str); - return values[match?.[1]]; + const targetField = match?.[1]?.split('.') || []; + const isArrayField = isArray(values[targetField[0]]); + if (isArrayField && targetField.length > 1) { + //对多关系字段 + return getFieldValue(targetField, values); + } else { + return flat(values)[match?.[1]]; + } }; const getTargetField = (obj) => { const keys = getAllKeys(obj); @@ -110,9 +131,17 @@ export const conditionAnalyse = (rules, values) => { return true; } try { - const currentValue = targetField.length > 1 ? flat(values)?.[targetField.join('.')] : values?.[targetField[0]]; - const result = jsonLogic.apply({ [operator]: [currentValue, value] }); - return result; + const isArrayField = isArray(values[targetField[0]]); + if (isArrayField && targetField.length > 1) { + //对多关系字段比较 + const currentValue = getFieldValue(targetField, values); + const result = jsonLogic.apply({ [operator]: [currentValue, value] }); + return result; + } else { + 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); }