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
This commit is contained in:
katherinehhh 2023-05-29 11:22:04 +08:00 committed by GitHub
parent 4296db5859
commit c0f9c8116a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 71 additions and 9 deletions

View File

@ -203,7 +203,7 @@ export const useCollectionFilterOptions = (collectionName: string) => {
export const useLinkageCollectionFilterOptions = (collectionName: string) => { export const useLinkageCollectionFilterOptions = (collectionName: string) => {
const { getCollectionFields, getInterface } = useCollectionManager(); const { getCollectionFields, getInterface } = useCollectionManager();
const fields = getCollectionFields(collectionName).filter((v) => !['o2m', 'm2m'].includes(v.interface)); const fields = getCollectionFields(collectionName);
const field2option = (field, depth) => { const field2option = (field, depth) => {
if (!field.interface) { if (!field.interface) {
return; return;
@ -233,7 +233,12 @@ export const useLinkageCollectionFilterOptions = (collectionName: string) => {
option['children'] = children; option['children'] = children;
} }
if (nested) { 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); const options = getOptions(targetFields, depth + 1).filter(Boolean);
option['children'] = option['children'] || []; option['children'] = option['children'] || [];
option['children'].push(...options); option['children'].push(...options);

View File

@ -35,6 +35,9 @@ http://ricostacruz.com/cheatsheets/umdjs.html
} }
return a; return a;
} }
function areArraysEqual(arr1, arr2) {
return JSON.stringify(arr1) === JSON.stringify(arr2);
}
var jsonLogic = {}; var jsonLogic = {};
var operations = { var operations = {
@ -42,9 +45,18 @@ http://ricostacruz.com/cheatsheets/umdjs.html
return a === b; return a === b;
}, },
$match: function (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); return JSON.stringify(a) === JSON.stringify(b);
}, },
$eq: function (a, 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; return a === b;
}, },
$ne: function (a, b) { $ne: function (a, b) {
@ -54,12 +66,14 @@ http://ricostacruz.com/cheatsheets/umdjs.html
return a !== b; return a !== b;
}, },
$gt: function (a, b) { $gt: function (a, b) {
if (Array.isArray(a)) return a.some((k) => k > b);
return a > b; return a > b;
}, },
$gte: function (a, b) { $gte: function (a, b) {
return a >= b; return a >= b;
}, },
$lt: function (a, b, c) { $lt: function (a, b, c) {
if (Array.isArray(a)) return a.some((k) => k < b);
return c === undefined ? a < b : a < b && b < c; return c === undefined ? a < b : a < b && b < c;
}, },
$lte: function (a, b, c) { $lte: function (a, b, c) {
@ -72,6 +86,7 @@ http://ricostacruz.com/cheatsheets/umdjs.html
return jsonLogic.truthy(a); return jsonLogic.truthy(a);
}, },
$empty: function (a) { $empty: function (a) {
if (Array.isArray(a)) return a.some((k) => !jsonLogic.truthy(k));
return !jsonLogic.truthy(a); return !jsonLogic.truthy(a);
}, },
$notExists: function (a) { $notExists: function (a) {
@ -86,6 +101,9 @@ http://ricostacruz.com/cheatsheets/umdjs.html
}, },
$in: function (a, b) { $in: function (a, b) {
if (!b || typeof b.indexOf === 'undefined') return false; 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; return b.indexOf(a) !== -1;
}, },
$notIn: function (a, b) { $notIn: function (a, b) {
@ -94,22 +112,30 @@ http://ricostacruz.com/cheatsheets/umdjs.html
}, },
$includes: function (a, b) { $includes: function (a, b) {
if (!a || typeof a.indexOf === 'undefined') return false; if (!a || typeof a.indexOf === 'undefined') return false;
if (Array.isArray(a)) return a.some((element) => element?.includes(b));
return a.indexOf(b) !== -1; return a.indexOf(b) !== -1;
}, },
$notIncludes: function (a, b) { $notIncludes: function (a, b) {
if (!a || typeof a.indexOf === 'undefined') return false; if (!a || typeof a.indexOf === 'undefined') return false;
if (Array.isArray(a)) return !a.some((element) => element.includes(b));
return !(a.indexOf(b) !== -1); return !(a.indexOf(b) !== -1);
}, },
$anyOf: function (a, b) { $anyOf: function (a, b) {
if (a.length === 0) { if (a.length === 0) {
return false; 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) { $noneOf: function (a, b) {
if (a.length === 0) { if (a.length === 0) {
return true; 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)); return b.some((item) => !a.includes(item));
}, },
$notMatch: function (a, b) { $notMatch: function (a, b) {
@ -125,9 +151,11 @@ http://ricostacruz.com/cheatsheets/umdjs.html
return false; return false;
}, },
$isTruly: function (a) { $isTruly: function (a) {
if (Array.isArray(a)) return a.some((k) => k === true || k === 1);
return a === true || a === 1; return a === true || a === 1;
}, },
$isFalsy: function (a) { $isFalsy: function (a) {
if (Array.isArray(a)) return a.some((k) => !jsonLogic.truthy(k));
return !jsonLogic.truthy(a); return !jsonLogic.truthy(a);
}, },
cat: function () { cat: function () {

View File

@ -1,5 +1,5 @@
import flat from 'flat'; import flat from 'flat';
import _, { every, findIndex, some } from 'lodash'; import _, { every, findIndex, some, isArray } from 'lodash';
import moment from 'moment'; import moment from 'moment';
import { useCurrentUserContext } from '../../../user'; import { useCurrentUserContext } from '../../../user';
import jsonLogic from '../../common/utils/logic'; import jsonLogic from '../../common/utils/logic';
@ -57,11 +57,25 @@ function getInnermostKeyAndValue(obj) {
return null; 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 getValue = (str: string, values) => {
const regex = /{{(.*?)}}/; const regex = /{{(.*?)}}/;
const matches = str?.match?.(regex); const matches = str?.match?.(regex);
if (matches) { if (matches) {
return getVariableValue(str, flat(values)); return getVariableValue(str, values);
} else { } else {
return str; return str;
} }
@ -69,7 +83,14 @@ const getValue = (str: string, values) => {
const getVariableValue = (str, values) => { const getVariableValue = (str, values) => {
const regex = /{{[^.]+\.([^}]+)}}/; const regex = /{{[^.]+\.([^}]+)}}/;
const match = regex.exec(str); 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 getTargetField = (obj) => {
const keys = getAllKeys(obj); const keys = getAllKeys(obj);
@ -110,9 +131,17 @@ export const conditionAnalyse = (rules, values) => {
return true; return true;
} }
try { try {
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 currentValue = targetField.length > 1 ? flat(values)?.[targetField.join('.')] : values?.[targetField[0]];
const result = jsonLogic.apply({ [operator]: [currentValue, value] }); const result = jsonLogic.apply({ [operator]: [currentValue, value] });
return result; return result;
}
} catch (error) { } catch (error) {
console.error(error); console.error(error);
} }