mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-05-05 13:39:24 +08:00
feat: support extending frontend filter operators (#6085)
* feat: operator extension * fix: bug * refactor: code improve * fix: jsonLogic --------- Co-authored-by: chenos <chenlinxh@gmail.com>
This commit is contained in:
parent
3df4c0944d
commit
583ef1b98a
@ -2,9 +2,7 @@
|
|||||||
"version": "1.6.0-alpha.25",
|
"version": "1.6.0-alpha.25",
|
||||||
"npmClient": "yarn",
|
"npmClient": "yarn",
|
||||||
"useWorkspaces": true,
|
"useWorkspaces": true,
|
||||||
"npmClientArgs": [
|
"npmClientArgs": ["--ignore-engines"],
|
||||||
"--ignore-engines"
|
|
||||||
],
|
|
||||||
"command": {
|
"command": {
|
||||||
"version": {
|
"version": {
|
||||||
"forcePublish": true,
|
"forcePublish": true,
|
||||||
|
@ -44,8 +44,14 @@ import type { CollectionFieldInterfaceFactory } from '../data-source';
|
|||||||
import { OpenModeProvider } from '../modules/popup/OpenModeProvider';
|
import { OpenModeProvider } from '../modules/popup/OpenModeProvider';
|
||||||
import { AppSchemaComponentProvider } from './AppSchemaComponentProvider';
|
import { AppSchemaComponentProvider } from './AppSchemaComponentProvider';
|
||||||
import type { Plugin } from './Plugin';
|
import type { Plugin } from './Plugin';
|
||||||
|
import { getOperators } from './globalOperators';
|
||||||
import type { RequireJS } from './utils/requirejs';
|
import type { RequireJS } from './utils/requirejs';
|
||||||
|
|
||||||
|
type JsonLogic = {
|
||||||
|
addOperation: (name: string, fn?: any) => void;
|
||||||
|
rmOperation: (name: string) => void;
|
||||||
|
};
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
define: RequireJS['define'];
|
define: RequireJS['define'];
|
||||||
@ -100,7 +106,7 @@ export class Application {
|
|||||||
public dataSourceManager: DataSourceManager;
|
public dataSourceManager: DataSourceManager;
|
||||||
public name: string;
|
public name: string;
|
||||||
public globalVars: Record<string, any> = {};
|
public globalVars: Record<string, any> = {};
|
||||||
|
public jsonLogic: JsonLogic;
|
||||||
loading = true;
|
loading = true;
|
||||||
maintained = false;
|
maintained = false;
|
||||||
maintaining = false;
|
maintaining = false;
|
||||||
@ -155,6 +161,7 @@ export class Application {
|
|||||||
this.apiClient.auth.locale = lng;
|
this.apiClient.auth.locale = lng;
|
||||||
});
|
});
|
||||||
this.initListeners();
|
this.initListeners();
|
||||||
|
this.jsonLogic = getOperators();
|
||||||
}
|
}
|
||||||
|
|
||||||
private initListeners() {
|
private initListeners() {
|
||||||
@ -488,4 +495,11 @@ export class Application {
|
|||||||
getGlobalVar(key) {
|
getGlobalVar(key) {
|
||||||
return get(this.globalVars, key);
|
return get(this.globalVars, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
registerOperators(key, operator) {
|
||||||
|
this.jsonLogic[key] = operator;
|
||||||
|
}
|
||||||
|
getOperator(key) {
|
||||||
|
return this.jsonLogic[key];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,13 +9,11 @@
|
|||||||
|
|
||||||
/* globals define,module */
|
/* globals define,module */
|
||||||
|
|
||||||
import dayjs from 'dayjs';
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Using a Universal Module Loader that should be browser, require, and AMD friendly
|
Using a Universal Module Loader that should be browser, require, and AMD friendly
|
||||||
http://ricostacruz.com/cheatsheets/umdjs.html
|
http://ricostacruz.com/cheatsheets/umdjs.html
|
||||||
*/
|
*/
|
||||||
export function getJsonLogic() {
|
export function getOperators() {
|
||||||
'use strict';
|
'use strict';
|
||||||
/* globals console:false */
|
/* globals console:false */
|
||||||
|
|
||||||
@ -307,11 +305,11 @@ export function getJsonLogic() {
|
|||||||
},
|
},
|
||||||
missing: function () {
|
missing: function () {
|
||||||
/*
|
/*
|
||||||
Missing can receive many keys as many arguments, like {"missing:[1,2]}
|
Missing can receive many keys as many arguments, like {"missing:[1,2]}
|
||||||
Missing can also receive *one* argument that is an array of keys,
|
Missing can also receive *one* argument that is an array of keys,
|
||||||
which typically happens if it's actually acting on the output of another command
|
which typically happens if it's actually acting on the output of another command
|
||||||
(like 'if' or 'merge')
|
(like 'if' or 'merge')
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var missing = [];
|
var missing = [];
|
||||||
var keys = Array.isArray(arguments[0]) ? arguments[0] : arguments;
|
var keys = Array.isArray(arguments[0]) ? arguments[0] : arguments;
|
||||||
@ -348,10 +346,10 @@ export function getJsonLogic() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This helper will defer to the JsonLogic spec as a tie-breaker when different language interpreters define different behavior for the truthiness of primitives. E.g., PHP considers empty arrays to be falsy, but Javascript considers them to be truthy. JsonLogic, as an ecosystem, needs one consistent answer.
|
This helper will defer to the JsonLogic spec as a tie-breaker when different language interpreters define different behavior for the truthiness of primitives. E.g., PHP considers empty arrays to be falsy, but Javascript considers them to be truthy. JsonLogic, as an ecosystem, needs one consistent answer.
|
||||||
|
|
||||||
Spec and rationale here: http://jsonlogic.com/truthy
|
Spec and rationale here: http://jsonlogic.com/truthy
|
||||||
*/
|
*/
|
||||||
jsonLogic.truthy = function (value) {
|
jsonLogic.truthy = function (value) {
|
||||||
if (Array.isArray(value) && value.length === 0) {
|
if (Array.isArray(value) && value.length === 0) {
|
||||||
return false;
|
return false;
|
||||||
@ -359,12 +357,12 @@ export function getJsonLogic() {
|
|||||||
return !!value;
|
return !!value;
|
||||||
};
|
};
|
||||||
|
|
||||||
jsonLogic.get_operator = function (logic) {
|
jsonLogic.getOperator = function (logic) {
|
||||||
return Object.keys(logic)[0];
|
return Object.keys(logic)[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
jsonLogic.get_values = function (logic) {
|
jsonLogic.getValues = function (logic) {
|
||||||
return logic[jsonLogic.get_operator(logic)];
|
return logic[jsonLogic.getOperator(logic)];
|
||||||
};
|
};
|
||||||
|
|
||||||
jsonLogic.apply = function (logic, data) {
|
jsonLogic.apply = function (logic, data) {
|
||||||
@ -379,7 +377,7 @@ export function getJsonLogic() {
|
|||||||
return logic;
|
return logic;
|
||||||
}
|
}
|
||||||
|
|
||||||
var op = jsonLogic.get_operator(logic);
|
var op = jsonLogic.getOperator(logic);
|
||||||
var values = logic[op];
|
var values = logic[op];
|
||||||
var i;
|
var i;
|
||||||
var current;
|
var current;
|
||||||
@ -395,18 +393,18 @@ export function getJsonLogic() {
|
|||||||
// 'if', 'and', and 'or' violate the normal rule of depth-first calculating consequents, let each manage recursion as needed.
|
// 'if', 'and', and 'or' violate the normal rule of depth-first calculating consequents, let each manage recursion as needed.
|
||||||
if (op === 'if' || op == '?:') {
|
if (op === 'if' || op == '?:') {
|
||||||
/* 'if' should be called with a odd number of parameters, 3 or greater
|
/* 'if' should be called with a odd number of parameters, 3 or greater
|
||||||
This works on the pattern:
|
This works on the pattern:
|
||||||
if( 0 ){ 1 }else{ 2 };
|
if( 0 ){ 1 }else{ 2 };
|
||||||
if( 0 ){ 1 }else if( 2 ){ 3 }else{ 4 };
|
if( 0 ){ 1 }else if( 2 ){ 3 }else{ 4 };
|
||||||
if( 0 ){ 1 }else if( 2 ){ 3 }else if( 4 ){ 5 }else{ 6 };
|
if( 0 ){ 1 }else if( 2 ){ 3 }else if( 4 ){ 5 }else{ 6 };
|
||||||
|
|
||||||
The implementation is:
|
The implementation is:
|
||||||
For pairs of values (0,1 then 2,3 then 4,5 etc)
|
For pairs of values (0,1 then 2,3 then 4,5 etc)
|
||||||
If the first evaluates truthy, evaluate and return the second
|
If the first evaluates truthy, evaluate and return the second
|
||||||
If the first evaluates falsy, jump to the next pair (e.g, 0,1 to 2,3)
|
If the first evaluates falsy, jump to the next pair (e.g, 0,1 to 2,3)
|
||||||
given one parameter, evaluate and return it. (it's an Else and all the If/ElseIf were false)
|
given one parameter, evaluate and return it. (it's an Else and all the If/ElseIf were false)
|
||||||
given 0 parameters, return NULL (not great practice, but there was no Else)
|
given 0 parameters, return NULL (not great practice, but there was no Else)
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < values.length - 1; i += 2) {
|
for (i = 0; i < values.length - 1; i += 2) {
|
||||||
if (jsonLogic.truthy(jsonLogic.apply(values[i], data))) {
|
if (jsonLogic.truthy(jsonLogic.apply(values[i], data))) {
|
||||||
return jsonLogic.apply(values[i + 1], data);
|
return jsonLogic.apply(values[i + 1], data);
|
||||||
@ -543,7 +541,7 @@ export function getJsonLogic() {
|
|||||||
var collection = [];
|
var collection = [];
|
||||||
|
|
||||||
if (jsonLogic.is_logic(logic)) {
|
if (jsonLogic.is_logic(logic)) {
|
||||||
var op = jsonLogic.get_operator(logic);
|
var op = jsonLogic.getOperator(logic);
|
||||||
var values = logic[op];
|
var values = logic[op];
|
||||||
|
|
||||||
if (!Array.isArray(values)) {
|
if (!Array.isArray(values)) {
|
||||||
@ -564,11 +562,11 @@ export function getJsonLogic() {
|
|||||||
return arrayUnique(collection);
|
return arrayUnique(collection);
|
||||||
};
|
};
|
||||||
|
|
||||||
jsonLogic.add_operation = function (name, code) {
|
jsonLogic.addOperation = function (name, code) {
|
||||||
operations[name] = code;
|
operations[name] = code;
|
||||||
};
|
};
|
||||||
|
|
||||||
jsonLogic.rm_operation = function (name) {
|
jsonLogic.rmOperation = function (name) {
|
||||||
delete operations[name];
|
delete operations[name];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -593,8 +591,8 @@ export function getJsonLogic() {
|
|||||||
|
|
||||||
if (jsonLogic.is_logic(pattern)) {
|
if (jsonLogic.is_logic(pattern)) {
|
||||||
if (jsonLogic.is_logic(rule)) {
|
if (jsonLogic.is_logic(rule)) {
|
||||||
var pattern_op = jsonLogic.get_operator(pattern);
|
var pattern_op = jsonLogic.getOperator(pattern);
|
||||||
var rule_op = jsonLogic.get_operator(rule);
|
var rule_op = jsonLogic.getOperator(rule);
|
||||||
|
|
||||||
if (pattern_op === '@' || pattern_op === rule_op) {
|
if (pattern_op === '@' || pattern_op === rule_op) {
|
||||||
// echo "\nOperators match, go deeper\n";
|
// echo "\nOperators match, go deeper\n";
|
||||||
@ -610,8 +608,8 @@ export function getJsonLogic() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
Note, array order MATTERS, because we're using this array test logic to consider arguments, where order can matter. (e.g., + is commutative, but '-' or 'if' or 'var' are NOT)
|
Note, array order MATTERS, because we're using this array test logic to consider arguments, where order can matter. (e.g., + is commutative, but '-' or 'if' or 'var' are NOT)
|
||||||
*/
|
*/
|
||||||
for (var i = 0; i < pattern.length; i += 1) {
|
for (var i = 0; i < pattern.length; i += 1) {
|
||||||
// If any fail, we fail
|
// If any fail, we fail
|
||||||
if (!jsonLogic.rule_like(rule[i], pattern[i])) {
|
if (!jsonLogic.rule_like(rule[i], pattern[i])) {
|
@ -47,6 +47,7 @@ import { ActionContextProvider } from './context';
|
|||||||
import { useGetAriaLabelOfAction } from './hooks/useGetAriaLabelOfAction';
|
import { useGetAriaLabelOfAction } from './hooks/useGetAriaLabelOfAction';
|
||||||
import { ActionContextProps, ActionProps, ComposedAction } from './types';
|
import { ActionContextProps, ActionProps, ComposedAction } from './types';
|
||||||
import { linkageAction, setInitialActionState } from './utils';
|
import { linkageAction, setInitialActionState } from './utils';
|
||||||
|
import { useApp } from '../../../application';
|
||||||
|
|
||||||
const useA = () => {
|
const useA = () => {
|
||||||
return {
|
return {
|
||||||
@ -95,7 +96,7 @@ export const Action: ComposedAction = withDynamicSchemaProps(
|
|||||||
const { setSubmitted } = useActionContext();
|
const { setSubmitted } = useActionContext();
|
||||||
const { getAriaLabel } = useGetAriaLabelOfAction(title);
|
const { getAriaLabel } = useGetAriaLabelOfAction(title);
|
||||||
const parentRecordData = useCollectionParentRecordData();
|
const parentRecordData = useCollectionParentRecordData();
|
||||||
|
const app = useApp();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (field.stateOfLinkageRules) {
|
if (field.stateOfLinkageRules) {
|
||||||
setInitialActionState(field);
|
setInitialActionState(field);
|
||||||
@ -105,13 +106,16 @@ export const Action: ComposedAction = withDynamicSchemaProps(
|
|||||||
.filter((k) => !k.disabled)
|
.filter((k) => !k.disabled)
|
||||||
.forEach((v) => {
|
.forEach((v) => {
|
||||||
v.actions?.forEach((h) => {
|
v.actions?.forEach((h) => {
|
||||||
linkageAction({
|
linkageAction(
|
||||||
operator: h.operator,
|
{
|
||||||
field,
|
operator: h.operator,
|
||||||
condition: v.condition,
|
field,
|
||||||
variables,
|
condition: v.condition,
|
||||||
localVariables,
|
variables,
|
||||||
});
|
localVariables,
|
||||||
|
},
|
||||||
|
app.jsonLogic,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}, [field, linkageRules, localVariables, variables]);
|
}, [field, linkageRules, localVariables, variables]);
|
||||||
|
@ -80,25 +80,28 @@ export const requestSettingsSchema: ISchema = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const linkageAction = async ({
|
export const linkageAction = async (
|
||||||
operator,
|
{
|
||||||
field,
|
operator,
|
||||||
condition,
|
field,
|
||||||
variables,
|
condition,
|
||||||
localVariables,
|
variables,
|
||||||
}: {
|
localVariables,
|
||||||
operator;
|
}: {
|
||||||
field;
|
operator;
|
||||||
condition;
|
field;
|
||||||
variables: VariablesContextType;
|
condition;
|
||||||
localVariables: VariableOption[];
|
variables: VariablesContextType;
|
||||||
}) => {
|
localVariables: VariableOption[];
|
||||||
|
},
|
||||||
|
jsonLogic: any,
|
||||||
|
) => {
|
||||||
const disableResult = field?.stateOfLinkageRules?.disabled || [false];
|
const disableResult = field?.stateOfLinkageRules?.disabled || [false];
|
||||||
const displayResult = field?.stateOfLinkageRules?.display || ['visible'];
|
const displayResult = field?.stateOfLinkageRules?.display || ['visible'];
|
||||||
|
|
||||||
switch (operator) {
|
switch (operator) {
|
||||||
case ActionType.Visible:
|
case ActionType.Visible:
|
||||||
if (await conditionAnalyses({ ruleGroup: condition, variables, localVariables })) {
|
if (await conditionAnalyses({ ruleGroup: condition, variables, localVariables }, jsonLogic)) {
|
||||||
displayResult.push(operator);
|
displayResult.push(operator);
|
||||||
field.data = field.data || {};
|
field.data = field.data || {};
|
||||||
field.data.hidden = false;
|
field.data.hidden = false;
|
||||||
@ -110,7 +113,7 @@ export const linkageAction = async ({
|
|||||||
field.display = last(displayResult);
|
field.display = last(displayResult);
|
||||||
break;
|
break;
|
||||||
case ActionType.Hidden:
|
case ActionType.Hidden:
|
||||||
if (await conditionAnalyses({ ruleGroup: condition, variables, localVariables })) {
|
if (await conditionAnalyses({ ruleGroup: condition, variables, localVariables }, jsonLogic)) {
|
||||||
field.data = field.data || {};
|
field.data = field.data || {};
|
||||||
field.data.hidden = true;
|
field.data.hidden = true;
|
||||||
} else {
|
} else {
|
||||||
@ -119,7 +122,7 @@ export const linkageAction = async ({
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ActionType.Disabled:
|
case ActionType.Disabled:
|
||||||
if (await conditionAnalyses({ ruleGroup: condition, variables, localVariables })) {
|
if (await conditionAnalyses({ ruleGroup: condition, variables, localVariables }, jsonLogic)) {
|
||||||
disableResult.push(true);
|
disableResult.push(true);
|
||||||
}
|
}
|
||||||
field.stateOfLinkageRules = {
|
field.stateOfLinkageRules = {
|
||||||
@ -130,7 +133,7 @@ export const linkageAction = async ({
|
|||||||
field.componentProps['disabled'] = last(disableResult);
|
field.componentProps['disabled'] = last(disableResult);
|
||||||
break;
|
break;
|
||||||
case ActionType.Active:
|
case ActionType.Active:
|
||||||
if (await conditionAnalyses({ ruleGroup: condition, variables, localVariables })) {
|
if (await conditionAnalyses({ ruleGroup: condition, variables, localVariables }, jsonLogic)) {
|
||||||
disableResult.push(false);
|
disableResult.push(false);
|
||||||
} else {
|
} else {
|
||||||
disableResult.push(!!field.componentProps?.['disabled']);
|
disableResult.push(!!field.componentProps?.['disabled']);
|
||||||
|
@ -16,6 +16,7 @@ import { forEachLinkageRule } from '../../../../schema-settings/LinkageRules/for
|
|||||||
import useLocalVariables from '../../../../variables/hooks/useLocalVariables';
|
import useLocalVariables from '../../../../variables/hooks/useLocalVariables';
|
||||||
import useVariables from '../../../../variables/hooks/useVariables';
|
import useVariables from '../../../../variables/hooks/useVariables';
|
||||||
import { useSubFormValue } from '../../association-field/hooks';
|
import { useSubFormValue } from '../../association-field/hooks';
|
||||||
|
import { useApp } from '../../../../application';
|
||||||
import { isSubMode } from '../../association-field/util';
|
import { isSubMode } from '../../association-field/util';
|
||||||
|
|
||||||
const isSubFormOrSubTableField = (fieldSchema: Schema) => {
|
const isSubFormOrSubTableField = (fieldSchema: Schema) => {
|
||||||
@ -45,6 +46,7 @@ export const useLinkageRulesForSubTableOrSubForm = () => {
|
|||||||
const variables = useVariables();
|
const variables = useVariables();
|
||||||
|
|
||||||
const linkageRules = getLinkageRules(schemaOfSubTableOrSubForm);
|
const linkageRules = getLinkageRules(schemaOfSubTableOrSubForm);
|
||||||
|
const app = useApp();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isSubFormOrSubTableField(fieldSchema)) {
|
if (!isSubFormOrSubTableField(fieldSchema)) {
|
||||||
@ -77,16 +79,19 @@ export const useLinkageRulesForSubTableOrSubForm = () => {
|
|||||||
forEachLinkageRule(linkageRules, (action, rule) => {
|
forEachLinkageRule(linkageRules, (action, rule) => {
|
||||||
if (action.targetFields?.includes(fieldSchema.name)) {
|
if (action.targetFields?.includes(fieldSchema.name)) {
|
||||||
disposes.push(
|
disposes.push(
|
||||||
bindLinkageRulesToFiled({
|
bindLinkageRulesToFiled(
|
||||||
field,
|
{
|
||||||
linkageRules,
|
field,
|
||||||
formValues: formValue,
|
linkageRules,
|
||||||
localVariables,
|
formValues: formValue,
|
||||||
action,
|
localVariables,
|
||||||
rule,
|
action,
|
||||||
variables,
|
rule,
|
||||||
variableNameOfLeftCondition: '$iteration',
|
variables,
|
||||||
}),
|
variableNameOfLeftCondition: '$iteration',
|
||||||
|
},
|
||||||
|
app.jsonLogic,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -27,6 +27,7 @@ import { useToken } from '../../../style';
|
|||||||
import { useLocalVariables, useVariables } from '../../../variables';
|
import { useLocalVariables, useVariables } from '../../../variables';
|
||||||
import { useProps } from '../../hooks/useProps';
|
import { useProps } from '../../hooks/useProps';
|
||||||
import { useFormBlockHeight } from './hook';
|
import { useFormBlockHeight } from './hook';
|
||||||
|
import { useApp } from '../../../application';
|
||||||
|
|
||||||
export interface FormProps extends IFormLayoutProps {
|
export interface FormProps extends IFormLayoutProps {
|
||||||
form?: FormilyForm;
|
form?: FormilyForm;
|
||||||
@ -136,6 +137,7 @@ const WithForm = (props: WithFormProps) => {
|
|||||||
const localVariables = useLocalVariables({ currentForm: form });
|
const localVariables = useLocalVariables({ currentForm: form });
|
||||||
const { templateFinished } = useTemplateBlockContext();
|
const { templateFinished } = useTemplateBlockContext();
|
||||||
const { loading } = useDataBlockRequest() || {};
|
const { loading } = useDataBlockRequest() || {};
|
||||||
|
const app = useApp();
|
||||||
const linkageRules: any[] =
|
const linkageRules: any[] =
|
||||||
(getLinkageRules(fieldSchema) || fieldSchema.parent?.['x-linkage-rules'])?.filter((k) => !k.disabled) || [];
|
(getLinkageRules(fieldSchema) || fieldSchema.parent?.['x-linkage-rules'])?.filter((k) => !k.disabled) || [];
|
||||||
|
|
||||||
@ -175,15 +177,18 @@ const WithForm = (props: WithFormProps) => {
|
|||||||
// 之前使用的 `onFieldReact` 有问题,没有办法被取消监听,所以这里用 `onFieldInit` 和 `reaction` 代替
|
// 之前使用的 `onFieldReact` 有问题,没有办法被取消监听,所以这里用 `onFieldInit` 和 `reaction` 代替
|
||||||
onFieldInit(`*(${fields})`, (field: any, form) => {
|
onFieldInit(`*(${fields})`, (field: any, form) => {
|
||||||
disposes.push(
|
disposes.push(
|
||||||
bindLinkageRulesToFiled({
|
bindLinkageRulesToFiled(
|
||||||
field,
|
{
|
||||||
linkageRules,
|
field,
|
||||||
formValues: form.values,
|
linkageRules,
|
||||||
localVariables,
|
formValues: form.values,
|
||||||
action,
|
localVariables,
|
||||||
rule,
|
action,
|
||||||
variables,
|
rule,
|
||||||
}),
|
variables,
|
||||||
|
},
|
||||||
|
app.jsonLogic,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ import { VariableOption, VariablesContextType } from '../../../variables/types';
|
|||||||
import { isVariable } from '../../../variables/utils/isVariable';
|
import { isVariable } from '../../../variables/utils/isVariable';
|
||||||
import { transformVariableValue } from '../../../variables/utils/transformVariableValue';
|
import { transformVariableValue } from '../../../variables/utils/transformVariableValue';
|
||||||
import { inferPickerType } from '../../antd/date-picker/util';
|
import { inferPickerType } from '../../antd/date-picker/util';
|
||||||
import { getJsonLogic } from '../../common/utils/logic';
|
|
||||||
type VariablesCtx = {
|
type VariablesCtx = {
|
||||||
/** 当前登录的用户 */
|
/** 当前登录的用户 */
|
||||||
$user?: Record<string, any>;
|
$user?: Record<string, any>;
|
||||||
@ -76,31 +76,34 @@ function getAllKeys(obj) {
|
|||||||
return keys;
|
return keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const conditionAnalyses = async ({
|
export const conditionAnalyses = async (
|
||||||
ruleGroup,
|
{
|
||||||
variables,
|
ruleGroup,
|
||||||
localVariables,
|
variables,
|
||||||
variableNameOfLeftCondition,
|
localVariables,
|
||||||
}: {
|
variableNameOfLeftCondition,
|
||||||
ruleGroup;
|
}: {
|
||||||
variables: VariablesContextType;
|
ruleGroup;
|
||||||
localVariables: VariableOption[];
|
variables: VariablesContextType;
|
||||||
/**
|
localVariables: VariableOption[];
|
||||||
* used to parse the variable name of the left condition value
|
/**
|
||||||
* @default '$nForm'
|
* used to parse the variable name of the left condition value
|
||||||
*/
|
* @default '$nForm'
|
||||||
variableNameOfLeftCondition?: string;
|
*/
|
||||||
}) => {
|
variableNameOfLeftCondition?: string;
|
||||||
|
},
|
||||||
|
jsonLogic: any,
|
||||||
|
) => {
|
||||||
const type = Object.keys(ruleGroup)[0] || '$and';
|
const type = Object.keys(ruleGroup)[0] || '$and';
|
||||||
const conditions = ruleGroup[type];
|
const conditions = ruleGroup[type];
|
||||||
|
|
||||||
let results = conditions.map(async (condition) => {
|
let results = conditions.map(async (condition) => {
|
||||||
if ('$and' in condition || '$or' in condition) {
|
if ('$and' in condition || '$or' in condition) {
|
||||||
return await conditionAnalyses({ ruleGroup: condition, variables, localVariables });
|
return await conditionAnalyses({ ruleGroup: condition, variables, localVariables }, jsonLogic);
|
||||||
}
|
}
|
||||||
|
|
||||||
const jsonlogic = getInnermostKeyAndValue(condition);
|
const logicCalculation = getInnermostKeyAndValue(condition);
|
||||||
const operator = jsonlogic?.key;
|
const operator = logicCalculation?.key;
|
||||||
|
|
||||||
if (!operator) {
|
if (!operator) {
|
||||||
return true;
|
return true;
|
||||||
@ -113,12 +116,11 @@ export const conditionAnalyses = async ({
|
|||||||
})
|
})
|
||||||
.then(({ value }) => value);
|
.then(({ value }) => value);
|
||||||
|
|
||||||
const parsingResult = isVariable(jsonlogic?.value)
|
const parsingResult = isVariable(logicCalculation?.value)
|
||||||
? [variables.parseVariable(jsonlogic?.value, localVariables).then(({ value }) => value), targetValue]
|
? [variables.parseVariable(logicCalculation?.value, localVariables).then(({ value }) => value), targetValue]
|
||||||
: [jsonlogic?.value, targetValue];
|
: [logicCalculation?.value, targetValue];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const jsonLogic = getJsonLogic();
|
|
||||||
const [value, targetValue] = await Promise.all(parsingResult);
|
const [value, targetValue] = await Promise.all(parsingResult);
|
||||||
const targetCollectionField = await variables.getCollectionField(targetVariableName, localVariables);
|
const targetCollectionField = await variables.getCollectionField(targetVariableName, localVariables);
|
||||||
let currentInputValue = transformVariableValue(targetValue, { targetCollectionField });
|
let currentInputValue = transformVariableValue(targetValue, { targetCollectionField });
|
||||||
|
@ -22,6 +22,7 @@ import { linkageAction } from '../../schema-component/antd/action/utils';
|
|||||||
import { usePopupUtils } from '../../schema-component/antd/page/pagePopupUtils';
|
import { usePopupUtils } from '../../schema-component/antd/page/pagePopupUtils';
|
||||||
import { parseVariables } from '../../schema-component/common/utils/uitls';
|
import { parseVariables } from '../../schema-component/common/utils/uitls';
|
||||||
import { useLocalVariables, useVariables } from '../../variables';
|
import { useLocalVariables, useVariables } from '../../variables';
|
||||||
|
import { useApp } from '../../application';
|
||||||
|
|
||||||
export function useAclCheck(actionPath) {
|
export function useAclCheck(actionPath) {
|
||||||
const aclCheck = useAclCheckFn();
|
const aclCheck = useAclCheckFn();
|
||||||
@ -73,6 +74,7 @@ const InternalCreateRecordAction = (props: any, ref) => {
|
|||||||
const { openPopup } = usePopupUtils();
|
const { openPopup } = usePopupUtils();
|
||||||
const treeRecordData = useTreeParentRecord();
|
const treeRecordData = useTreeParentRecord();
|
||||||
const cm = useCollectionManager();
|
const cm = useCollectionManager();
|
||||||
|
const app = useApp();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
field.stateOfLinkageRules = {};
|
field.stateOfLinkageRules = {};
|
||||||
@ -80,13 +82,16 @@ const InternalCreateRecordAction = (props: any, ref) => {
|
|||||||
.filter((k) => !k.disabled)
|
.filter((k) => !k.disabled)
|
||||||
.forEach((v) => {
|
.forEach((v) => {
|
||||||
v.actions?.forEach((h) => {
|
v.actions?.forEach((h) => {
|
||||||
linkageAction({
|
linkageAction(
|
||||||
operator: h.operator,
|
{
|
||||||
field,
|
operator: h.operator,
|
||||||
condition: v.condition,
|
field,
|
||||||
variables,
|
condition: v.condition,
|
||||||
localVariables,
|
variables,
|
||||||
});
|
localVariables,
|
||||||
|
},
|
||||||
|
app.jsonLogic,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}, [field, linkageRules, localVariables, variables]);
|
}, [field, linkageRules, localVariables, variables]);
|
||||||
@ -143,7 +148,6 @@ export const CreateAction = observer(
|
|||||||
const form = useForm();
|
const form = useForm();
|
||||||
const variables = useVariables();
|
const variables = useVariables();
|
||||||
const aclCheck = useAclCheckFn();
|
const aclCheck = useAclCheckFn();
|
||||||
|
|
||||||
const enableChildren = fieldSchema['x-enable-children'] || [];
|
const enableChildren = fieldSchema['x-enable-children'] || [];
|
||||||
const allowAddToCurrent = fieldSchema?.['x-allow-add-to-current'];
|
const allowAddToCurrent = fieldSchema?.['x-allow-add-to-current'];
|
||||||
const linkageFromForm = fieldSchema?.['x-component-props']?.['linkageFromForm'];
|
const linkageFromForm = fieldSchema?.['x-component-props']?.['linkageFromForm'];
|
||||||
@ -176,6 +180,7 @@ export const CreateAction = observer(
|
|||||||
const compile = useCompile();
|
const compile = useCompile();
|
||||||
const { designable } = useDesignable();
|
const { designable } = useDesignable();
|
||||||
const icon = props.icon || null;
|
const icon = props.icon || null;
|
||||||
|
const app = useApp();
|
||||||
const menuItems = useMemo<MenuProps['items']>(() => {
|
const menuItems = useMemo<MenuProps['items']>(() => {
|
||||||
return inheritsCollections.map((option) => ({
|
return inheritsCollections.map((option) => ({
|
||||||
key: option.name,
|
key: option.name,
|
||||||
@ -196,13 +201,16 @@ export const CreateAction = observer(
|
|||||||
.filter((k) => !k.disabled)
|
.filter((k) => !k.disabled)
|
||||||
.forEach((v) => {
|
.forEach((v) => {
|
||||||
v.actions?.forEach((h) => {
|
v.actions?.forEach((h) => {
|
||||||
linkageAction({
|
linkageAction(
|
||||||
operator: h.operator,
|
{
|
||||||
field,
|
operator: h.operator,
|
||||||
condition: v.condition,
|
field,
|
||||||
variables,
|
condition: v.condition,
|
||||||
localVariables,
|
variables,
|
||||||
});
|
localVariables,
|
||||||
|
},
|
||||||
|
app.jsonLogic,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}, [field, linkageRules, localVariables, variables]);
|
}, [field, linkageRules, localVariables, variables]);
|
||||||
|
@ -39,29 +39,32 @@ interface Props {
|
|||||||
variableNameOfLeftCondition?: string;
|
variableNameOfLeftCondition?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function bindLinkageRulesToFiled({
|
export function bindLinkageRulesToFiled(
|
||||||
field,
|
{
|
||||||
linkageRules,
|
field,
|
||||||
formValues,
|
linkageRules,
|
||||||
localVariables,
|
formValues,
|
||||||
action,
|
localVariables,
|
||||||
rule,
|
action,
|
||||||
variables,
|
rule,
|
||||||
variableNameOfLeftCondition,
|
variables,
|
||||||
}: {
|
variableNameOfLeftCondition,
|
||||||
field: any;
|
}: {
|
||||||
linkageRules: any[];
|
field: any;
|
||||||
formValues: any;
|
linkageRules: any[];
|
||||||
localVariables: VariableOption[];
|
formValues: any;
|
||||||
action: any;
|
localVariables: VariableOption[];
|
||||||
rule: any;
|
action: any;
|
||||||
variables: VariablesContextType;
|
rule: any;
|
||||||
/**
|
variables: VariablesContextType;
|
||||||
* used to parse the variable name of the left condition value
|
/**
|
||||||
* @default '$nForm'
|
* used to parse the variable name of the left condition value
|
||||||
*/
|
* @default '$nForm'
|
||||||
variableNameOfLeftCondition?: string;
|
*/
|
||||||
}) {
|
variableNameOfLeftCondition?: string;
|
||||||
|
},
|
||||||
|
jsonLogic: any,
|
||||||
|
) {
|
||||||
field['initStateOfLinkageRules'] = {
|
field['initStateOfLinkageRules'] = {
|
||||||
display: field.initStateOfLinkageRules?.display || getTempFieldState(true, field.display),
|
display: field.initStateOfLinkageRules?.display || getTempFieldState(true, field.display),
|
||||||
required: field.initStateOfLinkageRules?.required || getTempFieldState(true, field.required || false),
|
required: field.initStateOfLinkageRules?.required || getTempFieldState(true, field.required || false),
|
||||||
@ -89,7 +92,7 @@ export function bindLinkageRulesToFiled({
|
|||||||
.join(',');
|
.join(',');
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
getSubscriber({ action, field, rule, variables, localVariables, variableNameOfLeftCondition }),
|
getSubscriber({ action, field, rule, variables, localVariables, variableNameOfLeftCondition }, jsonLogic),
|
||||||
{ fireImmediately: true, equals: _.isEqual },
|
{ fireImmediately: true, equals: _.isEqual },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -176,36 +179,42 @@ function getVariableValue(variableString: string, localVariables: VariableOption
|
|||||||
return getValuesByPath(ctx, getPath(variableString));
|
return getValuesByPath(ctx, getPath(variableString));
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSubscriber({
|
function getSubscriber(
|
||||||
action,
|
{
|
||||||
field,
|
action,
|
||||||
rule,
|
field,
|
||||||
variables,
|
rule,
|
||||||
localVariables,
|
variables,
|
||||||
variableNameOfLeftCondition,
|
localVariables,
|
||||||
}: {
|
variableNameOfLeftCondition,
|
||||||
action: any;
|
}: {
|
||||||
field: any;
|
action: any;
|
||||||
rule: any;
|
field: any;
|
||||||
variables: VariablesContextType;
|
rule: any;
|
||||||
localVariables: VariableOption[];
|
variables: VariablesContextType;
|
||||||
/**
|
localVariables: VariableOption[];
|
||||||
* used to parse the variable name of the left condition value
|
/**
|
||||||
* @default '$nForm'
|
* used to parse the variable name of the left condition value
|
||||||
*/
|
* @default '$nForm'
|
||||||
variableNameOfLeftCondition?: string;
|
*/
|
||||||
}): (value: string, oldValue: string) => void {
|
variableNameOfLeftCondition?: string;
|
||||||
|
},
|
||||||
|
jsonLogic,
|
||||||
|
): (value: string, oldValue: string) => void {
|
||||||
return () => {
|
return () => {
|
||||||
// 当条件改变触发 reaction 时,会同步收集字段状态,并保存到 field.stateOfLinkageRules 中
|
// 当条件改变触发 reaction 时,会同步收集字段状态,并保存到 field.stateOfLinkageRules 中
|
||||||
collectFieldStateOfLinkageRules({
|
collectFieldStateOfLinkageRules(
|
||||||
operator: action.operator,
|
{
|
||||||
value: action.value,
|
operator: action.operator,
|
||||||
field,
|
value: action.value,
|
||||||
condition: rule.condition,
|
field,
|
||||||
variables,
|
condition: rule.condition,
|
||||||
localVariables,
|
variables,
|
||||||
variableNameOfLeftCondition,
|
localVariables,
|
||||||
});
|
variableNameOfLeftCondition,
|
||||||
|
},
|
||||||
|
jsonLogic,
|
||||||
|
);
|
||||||
|
|
||||||
// 当条件改变时,有可能会触发多个 reaction,所以这里需要延迟一下,确保所有的 reaction 都执行完毕后,
|
// 当条件改变时,有可能会触发多个 reaction,所以这里需要延迟一下,确保所有的 reaction 都执行完毕后,
|
||||||
// 再从 field.stateOfLinkageRules 中取值,因为此时 field.stateOfLinkageRules 中的值才是全的。
|
// 再从 field.stateOfLinkageRules 中取值,因为此时 field.stateOfLinkageRules 中的值才是全的。
|
||||||
@ -286,15 +295,10 @@ function getFieldNameByOperator(operator: ActionType) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const collectFieldStateOfLinkageRules = ({
|
export const collectFieldStateOfLinkageRules = (
|
||||||
operator,
|
{ operator, value, field, condition, variables, localVariables, variableNameOfLeftCondition }: Props,
|
||||||
value,
|
jsonLogic: any,
|
||||||
field,
|
) => {
|
||||||
condition,
|
|
||||||
variables,
|
|
||||||
localVariables,
|
|
||||||
variableNameOfLeftCondition,
|
|
||||||
}: Props) => {
|
|
||||||
const requiredResult = field?.stateOfLinkageRules?.required || [field?.initStateOfLinkageRules?.required];
|
const requiredResult = field?.stateOfLinkageRules?.required || [field?.initStateOfLinkageRules?.required];
|
||||||
const displayResult = field?.stateOfLinkageRules?.display || [field?.initStateOfLinkageRules?.display];
|
const displayResult = field?.stateOfLinkageRules?.display || [field?.initStateOfLinkageRules?.display];
|
||||||
const patternResult = field?.stateOfLinkageRules?.pattern || [field?.initStateOfLinkageRules?.pattern];
|
const patternResult = field?.stateOfLinkageRules?.pattern || [field?.initStateOfLinkageRules?.pattern];
|
||||||
@ -304,14 +308,14 @@ export const collectFieldStateOfLinkageRules = ({
|
|||||||
|
|
||||||
switch (operator) {
|
switch (operator) {
|
||||||
case ActionType.Required:
|
case ActionType.Required:
|
||||||
requiredResult.push(getTempFieldState(conditionAnalyses(paramsToGetConditionResult), true));
|
requiredResult.push(getTempFieldState(conditionAnalyses(paramsToGetConditionResult, jsonLogic), true));
|
||||||
field.stateOfLinkageRules = {
|
field.stateOfLinkageRules = {
|
||||||
...field.stateOfLinkageRules,
|
...field.stateOfLinkageRules,
|
||||||
required: requiredResult,
|
required: requiredResult,
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
case ActionType.InRequired:
|
case ActionType.InRequired:
|
||||||
requiredResult.push(getTempFieldState(conditionAnalyses(paramsToGetConditionResult), false));
|
requiredResult.push(getTempFieldState(conditionAnalyses(paramsToGetConditionResult, jsonLogic), false));
|
||||||
field.stateOfLinkageRules = {
|
field.stateOfLinkageRules = {
|
||||||
...field.stateOfLinkageRules,
|
...field.stateOfLinkageRules,
|
||||||
required: requiredResult,
|
required: requiredResult,
|
||||||
@ -320,7 +324,7 @@ export const collectFieldStateOfLinkageRules = ({
|
|||||||
case ActionType.Visible:
|
case ActionType.Visible:
|
||||||
case ActionType.None:
|
case ActionType.None:
|
||||||
case ActionType.Hidden:
|
case ActionType.Hidden:
|
||||||
displayResult.push(getTempFieldState(conditionAnalyses(paramsToGetConditionResult), operator));
|
displayResult.push(getTempFieldState(conditionAnalyses(paramsToGetConditionResult, jsonLogic), operator));
|
||||||
field.stateOfLinkageRules = {
|
field.stateOfLinkageRules = {
|
||||||
...field.stateOfLinkageRules,
|
...field.stateOfLinkageRules,
|
||||||
display: displayResult,
|
display: displayResult,
|
||||||
@ -329,7 +333,7 @@ export const collectFieldStateOfLinkageRules = ({
|
|||||||
case ActionType.Editable:
|
case ActionType.Editable:
|
||||||
case ActionType.ReadOnly:
|
case ActionType.ReadOnly:
|
||||||
case ActionType.ReadPretty:
|
case ActionType.ReadPretty:
|
||||||
patternResult.push(getTempFieldState(conditionAnalyses(paramsToGetConditionResult), operator));
|
patternResult.push(getTempFieldState(conditionAnalyses(paramsToGetConditionResult, jsonLogic), operator));
|
||||||
field.stateOfLinkageRules = {
|
field.stateOfLinkageRules = {
|
||||||
...field.stateOfLinkageRules,
|
...field.stateOfLinkageRules,
|
||||||
pattern: patternResult,
|
pattern: patternResult,
|
||||||
@ -364,7 +368,7 @@ export const collectFieldStateOfLinkageRules = ({
|
|||||||
if (isConditionEmpty(condition)) {
|
if (isConditionEmpty(condition)) {
|
||||||
valueResult.push(getTempFieldState(true, getValue()));
|
valueResult.push(getTempFieldState(true, getValue()));
|
||||||
} else {
|
} else {
|
||||||
valueResult.push(getTempFieldState(conditionAnalyses(paramsToGetConditionResult), getValue()));
|
valueResult.push(getTempFieldState(conditionAnalyses(paramsToGetConditionResult, jsonLogic), getValue()));
|
||||||
}
|
}
|
||||||
field.stateOfLinkageRules = {
|
field.stateOfLinkageRules = {
|
||||||
...field.stateOfLinkageRules,
|
...field.stateOfLinkageRules,
|
||||||
|
@ -25,13 +25,13 @@ const getActionValue = (operator, value) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getSatisfiedActions = async ({ rules, variables, localVariables }) => {
|
const getSatisfiedActions = async ({ rules, variables, localVariables }, jsonLogic) => {
|
||||||
const satisfiedRules = (
|
const satisfiedRules = (
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
rules
|
rules
|
||||||
.filter((k) => !k.disabled)
|
.filter((k) => !k.disabled)
|
||||||
.map(async (rule) => {
|
.map(async (rule) => {
|
||||||
if (await conditionAnalyses({ ruleGroup: rule.condition, variables, localVariables })) {
|
if (await conditionAnalyses({ ruleGroup: rule.condition, variables, localVariables }, jsonLogic)) {
|
||||||
return rule;
|
return rule;
|
||||||
} else return null;
|
} else return null;
|
||||||
}),
|
}),
|
||||||
@ -40,15 +40,15 @@ const getSatisfiedActions = async ({ rules, variables, localVariables }) => {
|
|||||||
return satisfiedRules.map((rule) => rule.actions).flat();
|
return satisfiedRules.map((rule) => rule.actions).flat();
|
||||||
};
|
};
|
||||||
|
|
||||||
const getSatisfiedValues = async ({ rules, variables, localVariables }) => {
|
const getSatisfiedValues = async ({ rules, variables, localVariables }, jsonLogic) => {
|
||||||
return (await getSatisfiedActions({ rules, variables, localVariables })).map((action) => ({
|
return (await getSatisfiedActions({ rules, variables, localVariables }, jsonLogic)).map((action) => ({
|
||||||
...action,
|
...action,
|
||||||
value: getActionValue(action.operator, action.value),
|
value: getActionValue(action.operator, action.value),
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getSatisfiedValueMap = async ({ rules, variables, localVariables }) => {
|
export const getSatisfiedValueMap = async ({ rules, variables, localVariables }, jsonLogic) => {
|
||||||
const values = await getSatisfiedValues({ rules, variables, localVariables });
|
const values = await getSatisfiedValues({ rules, variables, localVariables }, jsonLogic);
|
||||||
const valueMap = values.reduce((a, v) => ({ ...a, [v.operator]: v.value }), {});
|
const valueMap = values.reduce((a, v) => ({ ...a, [v.operator]: v.value }), {});
|
||||||
return valueMap;
|
return valueMap;
|
||||||
};
|
};
|
||||||
|
@ -15,7 +15,7 @@ import React, { useCallback, useEffect, useState } from 'react';
|
|||||||
import { useLocalVariables, useVariables } from '../../variables';
|
import { useLocalVariables, useVariables } from '../../variables';
|
||||||
import { getSatisfiedValueMap } from './compute-rules';
|
import { getSatisfiedValueMap } from './compute-rules';
|
||||||
import { LinkageRuleCategory, LinkageRuleDataKeyMap } from './type';
|
import { LinkageRuleCategory, LinkageRuleDataKeyMap } from './type';
|
||||||
|
import { useApp } from '../../application';
|
||||||
export function useSatisfiedActionValues({
|
export function useSatisfiedActionValues({
|
||||||
formValues,
|
formValues,
|
||||||
category = 'default',
|
category = 'default',
|
||||||
@ -35,10 +35,11 @@ export function useSatisfiedActionValues({
|
|||||||
const localVariables = useLocalVariables({ currentForm: { values: formValues } as any });
|
const localVariables = useLocalVariables({ currentForm: { values: formValues } as any });
|
||||||
const localSchema = schema ?? fieldSchema;
|
const localSchema = schema ?? fieldSchema;
|
||||||
const styleRules = rules ?? localSchema[LinkageRuleDataKeyMap[category]];
|
const styleRules = rules ?? localSchema[LinkageRuleDataKeyMap[category]];
|
||||||
|
const app = useApp();
|
||||||
|
|
||||||
const compute = useCallback(() => {
|
const compute = useCallback(() => {
|
||||||
if (styleRules && formValues) {
|
if (styleRules && formValues) {
|
||||||
getSatisfiedValueMap({ rules: styleRules, variables, localVariables })
|
getSatisfiedValueMap({ rules: styleRules, variables, localVariables }, app.jsonLogic)
|
||||||
.then((valueMap) => {
|
.then((valueMap) => {
|
||||||
if (!isEmpty(valueMap)) {
|
if (!isEmpty(valueMap)) {
|
||||||
setValueMap(valueMap);
|
setValueMap(valueMap);
|
||||||
|
@ -121,9 +121,11 @@ const RuleTypes = {
|
|||||||
number: t('Number', { ns: NAMESPACE }),
|
number: t('Number', { ns: NAMESPACE }),
|
||||||
lowercase: t('Lowercase letters', { ns: NAMESPACE }),
|
lowercase: t('Lowercase letters', { ns: NAMESPACE }),
|
||||||
uppercase: t('Uppercase letters', { ns: NAMESPACE }),
|
uppercase: t('Uppercase letters', { ns: NAMESPACE }),
|
||||||
symbol: t('Symbols', { ns: NAMESPACE })
|
symbol: t('Symbols', { ns: NAMESPACE }),
|
||||||
};
|
};
|
||||||
return <code>{value?.map(charset => charsetLabels[charset]).join(', ') || t('Number', { ns: NAMESPACE })}</code>;
|
return (
|
||||||
|
<code>{value?.map((charset) => charsetLabels[charset]).join(', ') || t('Number', { ns: NAMESPACE })}</code>
|
||||||
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
fieldset: {
|
fieldset: {
|
||||||
@ -154,14 +156,14 @@ const RuleTypes = {
|
|||||||
{ value: 'number', label: `{{t("Number", { ns: "${NAMESPACE}" })}}` },
|
{ value: 'number', label: `{{t("Number", { ns: "${NAMESPACE}" })}}` },
|
||||||
{ value: 'lowercase', label: `{{t("Lowercase letters", { ns: "${NAMESPACE}" })}}` },
|
{ value: 'lowercase', label: `{{t("Lowercase letters", { ns: "${NAMESPACE}" })}}` },
|
||||||
{ value: 'uppercase', label: `{{t("Uppercase letters", { ns: "${NAMESPACE}" })}}` },
|
{ value: 'uppercase', label: `{{t("Uppercase letters", { ns: "${NAMESPACE}" })}}` },
|
||||||
{ value: 'symbol', label: `{{t("Symbols", { ns: "${NAMESPACE}" })}}` }
|
{ value: 'symbol', label: `{{t("Symbols", { ns: "${NAMESPACE}" })}}` },
|
||||||
],
|
],
|
||||||
required: true,
|
required: true,
|
||||||
default: ['number'],
|
default: ['number'],
|
||||||
'x-validator': {
|
'x-validator': {
|
||||||
minItems: 1,
|
minItems: 1,
|
||||||
message: `{{t("At least one character set should be selected", { ns: "${NAMESPACE}" })}}`
|
message: `{{t("At least one character set should be selected", { ns: "${NAMESPACE}" })}}`,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
defaults: {
|
defaults: {
|
||||||
|
@ -301,7 +301,7 @@ const CHAR_SETS = {
|
|||||||
lowercase: 'abcdefghijklmnopqrstuvwxyz',
|
lowercase: 'abcdefghijklmnopqrstuvwxyz',
|
||||||
uppercase: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
|
uppercase: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
|
||||||
// 符号只保留常用且安全的符号,有需要的可以自己加比如[]{}|;:,.<>放在链接或者文件名里容易出问题的字符
|
// 符号只保留常用且安全的符号,有需要的可以自己加比如[]{}|;:,.<>放在链接或者文件名里容易出问题的字符
|
||||||
symbol: '!@#$%^&*_-+'
|
symbol: '!@#$%^&*_-+',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
interface RandomCharOptions {
|
interface RandomCharOptions {
|
||||||
@ -317,21 +317,16 @@ sequencePatterns.register('randomChar', {
|
|||||||
if (!options?.charsets || options.charsets.length === 0) {
|
if (!options?.charsets || options.charsets.length === 0) {
|
||||||
return 'At least one character set should be selected';
|
return 'At least one character set should be selected';
|
||||||
}
|
}
|
||||||
if (options.charsets.some(charset => !CHAR_SETS[charset])) {
|
if (options.charsets.some((charset) => !CHAR_SETS[charset])) {
|
||||||
return 'Invalid charset selected';
|
return 'Invalid charset selected';
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
|
||||||
generate(instance: any, options: RandomCharOptions) {
|
|
||||||
const {
|
|
||||||
length = 6,
|
|
||||||
charsets = ['number']
|
|
||||||
} = options;
|
|
||||||
|
|
||||||
const chars = [...new Set(
|
generate(instance: any, options: RandomCharOptions) {
|
||||||
charsets.reduce((acc, charset) => acc + CHAR_SETS[charset], '')
|
const { length = 6, charsets = ['number'] } = options;
|
||||||
)];
|
|
||||||
|
const chars = [...new Set(charsets.reduce((acc, charset) => acc + CHAR_SETS[charset], ''))];
|
||||||
|
|
||||||
const getRandomChar = () => {
|
const getRandomChar = () => {
|
||||||
const randomIndex = Math.floor(Math.random() * chars.length);
|
const randomIndex = Math.floor(Math.random() * chars.length);
|
||||||
@ -352,20 +347,27 @@ sequencePatterns.register('randomChar', {
|
|||||||
},
|
},
|
||||||
|
|
||||||
getMatcher(options: RandomCharOptions) {
|
getMatcher(options: RandomCharOptions) {
|
||||||
const pattern = [...new Set(
|
const pattern = [
|
||||||
(options.charsets || ['number']).reduce((acc, charset) => {
|
...new Set(
|
||||||
switch (charset) {
|
(options.charsets || ['number']).reduce((acc, charset) => {
|
||||||
case 'number': return acc + '0-9';
|
switch (charset) {
|
||||||
case 'lowercase': return acc + 'a-z';
|
case 'number':
|
||||||
case 'uppercase': return acc + 'A-Z';
|
return acc + '0-9';
|
||||||
case 'symbol': return acc + CHAR_SETS.symbol.replace('-', '').replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&') + '-';
|
case 'lowercase':
|
||||||
default: return acc;
|
return acc + 'a-z';
|
||||||
}
|
case 'uppercase':
|
||||||
}, '')
|
return acc + 'A-Z';
|
||||||
)].join('');
|
case 'symbol':
|
||||||
|
return acc + CHAR_SETS.symbol.replace('-', '').replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&') + '-';
|
||||||
|
default:
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
}, ''),
|
||||||
|
),
|
||||||
|
].join('');
|
||||||
|
|
||||||
return `[${pattern}]{${options.length || 6}}`;
|
return `[${pattern}]{${options.length || 6}}`;
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
interface PatternConfig {
|
interface PatternConfig {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user