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",
|
||||
"npmClient": "yarn",
|
||||
"useWorkspaces": true,
|
||||
"npmClientArgs": [
|
||||
"--ignore-engines"
|
||||
],
|
||||
"npmClientArgs": ["--ignore-engines"],
|
||||
"command": {
|
||||
"version": {
|
||||
"forcePublish": true,
|
||||
|
@ -44,8 +44,14 @@ import type { CollectionFieldInterfaceFactory } from '../data-source';
|
||||
import { OpenModeProvider } from '../modules/popup/OpenModeProvider';
|
||||
import { AppSchemaComponentProvider } from './AppSchemaComponentProvider';
|
||||
import type { Plugin } from './Plugin';
|
||||
import { getOperators } from './globalOperators';
|
||||
import type { RequireJS } from './utils/requirejs';
|
||||
|
||||
type JsonLogic = {
|
||||
addOperation: (name: string, fn?: any) => void;
|
||||
rmOperation: (name: string) => void;
|
||||
};
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
define: RequireJS['define'];
|
||||
@ -100,7 +106,7 @@ export class Application {
|
||||
public dataSourceManager: DataSourceManager;
|
||||
public name: string;
|
||||
public globalVars: Record<string, any> = {};
|
||||
|
||||
public jsonLogic: JsonLogic;
|
||||
loading = true;
|
||||
maintained = false;
|
||||
maintaining = false;
|
||||
@ -155,6 +161,7 @@ export class Application {
|
||||
this.apiClient.auth.locale = lng;
|
||||
});
|
||||
this.initListeners();
|
||||
this.jsonLogic = getOperators();
|
||||
}
|
||||
|
||||
private initListeners() {
|
||||
@ -488,4 +495,11 @@ export class Application {
|
||||
getGlobalVar(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 */
|
||||
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
/*
|
||||
Using a Universal Module Loader that should be browser, require, and AMD friendly
|
||||
http://ricostacruz.com/cheatsheets/umdjs.html
|
||||
*/
|
||||
export function getJsonLogic() {
|
||||
export function getOperators() {
|
||||
'use strict';
|
||||
/* globals console:false */
|
||||
|
||||
@ -359,12 +357,12 @@ export function getJsonLogic() {
|
||||
return !!value;
|
||||
};
|
||||
|
||||
jsonLogic.get_operator = function (logic) {
|
||||
jsonLogic.getOperator = function (logic) {
|
||||
return Object.keys(logic)[0];
|
||||
};
|
||||
|
||||
jsonLogic.get_values = function (logic) {
|
||||
return logic[jsonLogic.get_operator(logic)];
|
||||
jsonLogic.getValues = function (logic) {
|
||||
return logic[jsonLogic.getOperator(logic)];
|
||||
};
|
||||
|
||||
jsonLogic.apply = function (logic, data) {
|
||||
@ -379,7 +377,7 @@ export function getJsonLogic() {
|
||||
return logic;
|
||||
}
|
||||
|
||||
var op = jsonLogic.get_operator(logic);
|
||||
var op = jsonLogic.getOperator(logic);
|
||||
var values = logic[op];
|
||||
var i;
|
||||
var current;
|
||||
@ -543,7 +541,7 @@ export function getJsonLogic() {
|
||||
var collection = [];
|
||||
|
||||
if (jsonLogic.is_logic(logic)) {
|
||||
var op = jsonLogic.get_operator(logic);
|
||||
var op = jsonLogic.getOperator(logic);
|
||||
var values = logic[op];
|
||||
|
||||
if (!Array.isArray(values)) {
|
||||
@ -564,11 +562,11 @@ export function getJsonLogic() {
|
||||
return arrayUnique(collection);
|
||||
};
|
||||
|
||||
jsonLogic.add_operation = function (name, code) {
|
||||
jsonLogic.addOperation = function (name, code) {
|
||||
operations[name] = code;
|
||||
};
|
||||
|
||||
jsonLogic.rm_operation = function (name) {
|
||||
jsonLogic.rmOperation = function (name) {
|
||||
delete operations[name];
|
||||
};
|
||||
|
||||
@ -593,8 +591,8 @@ export function getJsonLogic() {
|
||||
|
||||
if (jsonLogic.is_logic(pattern)) {
|
||||
if (jsonLogic.is_logic(rule)) {
|
||||
var pattern_op = jsonLogic.get_operator(pattern);
|
||||
var rule_op = jsonLogic.get_operator(rule);
|
||||
var pattern_op = jsonLogic.getOperator(pattern);
|
||||
var rule_op = jsonLogic.getOperator(rule);
|
||||
|
||||
if (pattern_op === '@' || pattern_op === rule_op) {
|
||||
// echo "\nOperators match, go deeper\n";
|
@ -47,6 +47,7 @@ import { ActionContextProvider } from './context';
|
||||
import { useGetAriaLabelOfAction } from './hooks/useGetAriaLabelOfAction';
|
||||
import { ActionContextProps, ActionProps, ComposedAction } from './types';
|
||||
import { linkageAction, setInitialActionState } from './utils';
|
||||
import { useApp } from '../../../application';
|
||||
|
||||
const useA = () => {
|
||||
return {
|
||||
@ -95,7 +96,7 @@ export const Action: ComposedAction = withDynamicSchemaProps(
|
||||
const { setSubmitted } = useActionContext();
|
||||
const { getAriaLabel } = useGetAriaLabelOfAction(title);
|
||||
const parentRecordData = useCollectionParentRecordData();
|
||||
|
||||
const app = useApp();
|
||||
useEffect(() => {
|
||||
if (field.stateOfLinkageRules) {
|
||||
setInitialActionState(field);
|
||||
@ -105,13 +106,16 @@ export const Action: ComposedAction = withDynamicSchemaProps(
|
||||
.filter((k) => !k.disabled)
|
||||
.forEach((v) => {
|
||||
v.actions?.forEach((h) => {
|
||||
linkageAction({
|
||||
linkageAction(
|
||||
{
|
||||
operator: h.operator,
|
||||
field,
|
||||
condition: v.condition,
|
||||
variables,
|
||||
localVariables,
|
||||
});
|
||||
},
|
||||
app.jsonLogic,
|
||||
);
|
||||
});
|
||||
});
|
||||
}, [field, linkageRules, localVariables, variables]);
|
||||
|
@ -80,25 +80,28 @@ export const requestSettingsSchema: ISchema = {
|
||||
},
|
||||
};
|
||||
|
||||
export const linkageAction = async ({
|
||||
export const linkageAction = async (
|
||||
{
|
||||
operator,
|
||||
field,
|
||||
condition,
|
||||
variables,
|
||||
localVariables,
|
||||
}: {
|
||||
}: {
|
||||
operator;
|
||||
field;
|
||||
condition;
|
||||
variables: VariablesContextType;
|
||||
localVariables: VariableOption[];
|
||||
}) => {
|
||||
},
|
||||
jsonLogic: any,
|
||||
) => {
|
||||
const disableResult = field?.stateOfLinkageRules?.disabled || [false];
|
||||
const displayResult = field?.stateOfLinkageRules?.display || ['visible'];
|
||||
|
||||
switch (operator) {
|
||||
case ActionType.Visible:
|
||||
if (await conditionAnalyses({ ruleGroup: condition, variables, localVariables })) {
|
||||
if (await conditionAnalyses({ ruleGroup: condition, variables, localVariables }, jsonLogic)) {
|
||||
displayResult.push(operator);
|
||||
field.data = field.data || {};
|
||||
field.data.hidden = false;
|
||||
@ -110,7 +113,7 @@ export const linkageAction = async ({
|
||||
field.display = last(displayResult);
|
||||
break;
|
||||
case ActionType.Hidden:
|
||||
if (await conditionAnalyses({ ruleGroup: condition, variables, localVariables })) {
|
||||
if (await conditionAnalyses({ ruleGroup: condition, variables, localVariables }, jsonLogic)) {
|
||||
field.data = field.data || {};
|
||||
field.data.hidden = true;
|
||||
} else {
|
||||
@ -119,7 +122,7 @@ export const linkageAction = async ({
|
||||
}
|
||||
break;
|
||||
case ActionType.Disabled:
|
||||
if (await conditionAnalyses({ ruleGroup: condition, variables, localVariables })) {
|
||||
if (await conditionAnalyses({ ruleGroup: condition, variables, localVariables }, jsonLogic)) {
|
||||
disableResult.push(true);
|
||||
}
|
||||
field.stateOfLinkageRules = {
|
||||
@ -130,7 +133,7 @@ export const linkageAction = async ({
|
||||
field.componentProps['disabled'] = last(disableResult);
|
||||
break;
|
||||
case ActionType.Active:
|
||||
if (await conditionAnalyses({ ruleGroup: condition, variables, localVariables })) {
|
||||
if (await conditionAnalyses({ ruleGroup: condition, variables, localVariables }, jsonLogic)) {
|
||||
disableResult.push(false);
|
||||
} else {
|
||||
disableResult.push(!!field.componentProps?.['disabled']);
|
||||
|
@ -16,6 +16,7 @@ import { forEachLinkageRule } from '../../../../schema-settings/LinkageRules/for
|
||||
import useLocalVariables from '../../../../variables/hooks/useLocalVariables';
|
||||
import useVariables from '../../../../variables/hooks/useVariables';
|
||||
import { useSubFormValue } from '../../association-field/hooks';
|
||||
import { useApp } from '../../../../application';
|
||||
import { isSubMode } from '../../association-field/util';
|
||||
|
||||
const isSubFormOrSubTableField = (fieldSchema: Schema) => {
|
||||
@ -45,6 +46,7 @@ export const useLinkageRulesForSubTableOrSubForm = () => {
|
||||
const variables = useVariables();
|
||||
|
||||
const linkageRules = getLinkageRules(schemaOfSubTableOrSubForm);
|
||||
const app = useApp();
|
||||
|
||||
useEffect(() => {
|
||||
if (!isSubFormOrSubTableField(fieldSchema)) {
|
||||
@ -77,7 +79,8 @@ export const useLinkageRulesForSubTableOrSubForm = () => {
|
||||
forEachLinkageRule(linkageRules, (action, rule) => {
|
||||
if (action.targetFields?.includes(fieldSchema.name)) {
|
||||
disposes.push(
|
||||
bindLinkageRulesToFiled({
|
||||
bindLinkageRulesToFiled(
|
||||
{
|
||||
field,
|
||||
linkageRules,
|
||||
formValues: formValue,
|
||||
@ -86,7 +89,9 @@ export const useLinkageRulesForSubTableOrSubForm = () => {
|
||||
rule,
|
||||
variables,
|
||||
variableNameOfLeftCondition: '$iteration',
|
||||
}),
|
||||
},
|
||||
app.jsonLogic,
|
||||
),
|
||||
);
|
||||
}
|
||||
});
|
||||
|
@ -27,6 +27,7 @@ import { useToken } from '../../../style';
|
||||
import { useLocalVariables, useVariables } from '../../../variables';
|
||||
import { useProps } from '../../hooks/useProps';
|
||||
import { useFormBlockHeight } from './hook';
|
||||
import { useApp } from '../../../application';
|
||||
|
||||
export interface FormProps extends IFormLayoutProps {
|
||||
form?: FormilyForm;
|
||||
@ -136,6 +137,7 @@ const WithForm = (props: WithFormProps) => {
|
||||
const localVariables = useLocalVariables({ currentForm: form });
|
||||
const { templateFinished } = useTemplateBlockContext();
|
||||
const { loading } = useDataBlockRequest() || {};
|
||||
const app = useApp();
|
||||
const linkageRules: any[] =
|
||||
(getLinkageRules(fieldSchema) || fieldSchema.parent?.['x-linkage-rules'])?.filter((k) => !k.disabled) || [];
|
||||
|
||||
@ -175,7 +177,8 @@ const WithForm = (props: WithFormProps) => {
|
||||
// 之前使用的 `onFieldReact` 有问题,没有办法被取消监听,所以这里用 `onFieldInit` 和 `reaction` 代替
|
||||
onFieldInit(`*(${fields})`, (field: any, form) => {
|
||||
disposes.push(
|
||||
bindLinkageRulesToFiled({
|
||||
bindLinkageRulesToFiled(
|
||||
{
|
||||
field,
|
||||
linkageRules,
|
||||
formValues: form.values,
|
||||
@ -183,7 +186,9 @@ const WithForm = (props: WithFormProps) => {
|
||||
action,
|
||||
rule,
|
||||
variables,
|
||||
}),
|
||||
},
|
||||
app.jsonLogic,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ import { VariableOption, VariablesContextType } from '../../../variables/types';
|
||||
import { isVariable } from '../../../variables/utils/isVariable';
|
||||
import { transformVariableValue } from '../../../variables/utils/transformVariableValue';
|
||||
import { inferPickerType } from '../../antd/date-picker/util';
|
||||
import { getJsonLogic } from '../../common/utils/logic';
|
||||
|
||||
type VariablesCtx = {
|
||||
/** 当前登录的用户 */
|
||||
$user?: Record<string, any>;
|
||||
@ -76,12 +76,13 @@ function getAllKeys(obj) {
|
||||
return keys;
|
||||
}
|
||||
|
||||
export const conditionAnalyses = async ({
|
||||
export const conditionAnalyses = async (
|
||||
{
|
||||
ruleGroup,
|
||||
variables,
|
||||
localVariables,
|
||||
variableNameOfLeftCondition,
|
||||
}: {
|
||||
}: {
|
||||
ruleGroup;
|
||||
variables: VariablesContextType;
|
||||
localVariables: VariableOption[];
|
||||
@ -90,17 +91,19 @@ export const conditionAnalyses = async ({
|
||||
* @default '$nForm'
|
||||
*/
|
||||
variableNameOfLeftCondition?: string;
|
||||
}) => {
|
||||
},
|
||||
jsonLogic: any,
|
||||
) => {
|
||||
const type = Object.keys(ruleGroup)[0] || '$and';
|
||||
const conditions = ruleGroup[type];
|
||||
|
||||
let results = conditions.map(async (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 operator = jsonlogic?.key;
|
||||
const logicCalculation = getInnermostKeyAndValue(condition);
|
||||
const operator = logicCalculation?.key;
|
||||
|
||||
if (!operator) {
|
||||
return true;
|
||||
@ -113,12 +116,11 @@ export const conditionAnalyses = async ({
|
||||
})
|
||||
.then(({ value }) => value);
|
||||
|
||||
const parsingResult = isVariable(jsonlogic?.value)
|
||||
? [variables.parseVariable(jsonlogic?.value, localVariables).then(({ value }) => value), targetValue]
|
||||
: [jsonlogic?.value, targetValue];
|
||||
const parsingResult = isVariable(logicCalculation?.value)
|
||||
? [variables.parseVariable(logicCalculation?.value, localVariables).then(({ value }) => value), targetValue]
|
||||
: [logicCalculation?.value, targetValue];
|
||||
|
||||
try {
|
||||
const jsonLogic = getJsonLogic();
|
||||
const [value, targetValue] = await Promise.all(parsingResult);
|
||||
const targetCollectionField = await variables.getCollectionField(targetVariableName, localVariables);
|
||||
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 { parseVariables } from '../../schema-component/common/utils/uitls';
|
||||
import { useLocalVariables, useVariables } from '../../variables';
|
||||
import { useApp } from '../../application';
|
||||
|
||||
export function useAclCheck(actionPath) {
|
||||
const aclCheck = useAclCheckFn();
|
||||
@ -73,6 +74,7 @@ const InternalCreateRecordAction = (props: any, ref) => {
|
||||
const { openPopup } = usePopupUtils();
|
||||
const treeRecordData = useTreeParentRecord();
|
||||
const cm = useCollectionManager();
|
||||
const app = useApp();
|
||||
|
||||
useEffect(() => {
|
||||
field.stateOfLinkageRules = {};
|
||||
@ -80,13 +82,16 @@ const InternalCreateRecordAction = (props: any, ref) => {
|
||||
.filter((k) => !k.disabled)
|
||||
.forEach((v) => {
|
||||
v.actions?.forEach((h) => {
|
||||
linkageAction({
|
||||
linkageAction(
|
||||
{
|
||||
operator: h.operator,
|
||||
field,
|
||||
condition: v.condition,
|
||||
variables,
|
||||
localVariables,
|
||||
});
|
||||
},
|
||||
app.jsonLogic,
|
||||
);
|
||||
});
|
||||
});
|
||||
}, [field, linkageRules, localVariables, variables]);
|
||||
@ -143,7 +148,6 @@ export const CreateAction = observer(
|
||||
const form = useForm();
|
||||
const variables = useVariables();
|
||||
const aclCheck = useAclCheckFn();
|
||||
|
||||
const enableChildren = fieldSchema['x-enable-children'] || [];
|
||||
const allowAddToCurrent = fieldSchema?.['x-allow-add-to-current'];
|
||||
const linkageFromForm = fieldSchema?.['x-component-props']?.['linkageFromForm'];
|
||||
@ -176,6 +180,7 @@ export const CreateAction = observer(
|
||||
const compile = useCompile();
|
||||
const { designable } = useDesignable();
|
||||
const icon = props.icon || null;
|
||||
const app = useApp();
|
||||
const menuItems = useMemo<MenuProps['items']>(() => {
|
||||
return inheritsCollections.map((option) => ({
|
||||
key: option.name,
|
||||
@ -196,13 +201,16 @@ export const CreateAction = observer(
|
||||
.filter((k) => !k.disabled)
|
||||
.forEach((v) => {
|
||||
v.actions?.forEach((h) => {
|
||||
linkageAction({
|
||||
linkageAction(
|
||||
{
|
||||
operator: h.operator,
|
||||
field,
|
||||
condition: v.condition,
|
||||
variables,
|
||||
localVariables,
|
||||
});
|
||||
},
|
||||
app.jsonLogic,
|
||||
);
|
||||
});
|
||||
});
|
||||
}, [field, linkageRules, localVariables, variables]);
|
||||
|
@ -39,7 +39,8 @@ interface Props {
|
||||
variableNameOfLeftCondition?: string;
|
||||
}
|
||||
|
||||
export function bindLinkageRulesToFiled({
|
||||
export function bindLinkageRulesToFiled(
|
||||
{
|
||||
field,
|
||||
linkageRules,
|
||||
formValues,
|
||||
@ -48,7 +49,7 @@ export function bindLinkageRulesToFiled({
|
||||
rule,
|
||||
variables,
|
||||
variableNameOfLeftCondition,
|
||||
}: {
|
||||
}: {
|
||||
field: any;
|
||||
linkageRules: any[];
|
||||
formValues: any;
|
||||
@ -61,7 +62,9 @@ export function bindLinkageRulesToFiled({
|
||||
* @default '$nForm'
|
||||
*/
|
||||
variableNameOfLeftCondition?: string;
|
||||
}) {
|
||||
},
|
||||
jsonLogic: any,
|
||||
) {
|
||||
field['initStateOfLinkageRules'] = {
|
||||
display: field.initStateOfLinkageRules?.display || getTempFieldState(true, field.display),
|
||||
required: field.initStateOfLinkageRules?.required || getTempFieldState(true, field.required || false),
|
||||
@ -89,7 +92,7 @@ export function bindLinkageRulesToFiled({
|
||||
.join(',');
|
||||
return result;
|
||||
},
|
||||
getSubscriber({ action, field, rule, variables, localVariables, variableNameOfLeftCondition }),
|
||||
getSubscriber({ action, field, rule, variables, localVariables, variableNameOfLeftCondition }, jsonLogic),
|
||||
{ fireImmediately: true, equals: _.isEqual },
|
||||
);
|
||||
}
|
||||
@ -176,14 +179,15 @@ function getVariableValue(variableString: string, localVariables: VariableOption
|
||||
return getValuesByPath(ctx, getPath(variableString));
|
||||
}
|
||||
|
||||
function getSubscriber({
|
||||
function getSubscriber(
|
||||
{
|
||||
action,
|
||||
field,
|
||||
rule,
|
||||
variables,
|
||||
localVariables,
|
||||
variableNameOfLeftCondition,
|
||||
}: {
|
||||
}: {
|
||||
action: any;
|
||||
field: any;
|
||||
rule: any;
|
||||
@ -194,10 +198,13 @@ function getSubscriber({
|
||||
* @default '$nForm'
|
||||
*/
|
||||
variableNameOfLeftCondition?: string;
|
||||
}): (value: string, oldValue: string) => void {
|
||||
},
|
||||
jsonLogic,
|
||||
): (value: string, oldValue: string) => void {
|
||||
return () => {
|
||||
// 当条件改变触发 reaction 时,会同步收集字段状态,并保存到 field.stateOfLinkageRules 中
|
||||
collectFieldStateOfLinkageRules({
|
||||
collectFieldStateOfLinkageRules(
|
||||
{
|
||||
operator: action.operator,
|
||||
value: action.value,
|
||||
field,
|
||||
@ -205,7 +212,9 @@ function getSubscriber({
|
||||
variables,
|
||||
localVariables,
|
||||
variableNameOfLeftCondition,
|
||||
});
|
||||
},
|
||||
jsonLogic,
|
||||
);
|
||||
|
||||
// 当条件改变时,有可能会触发多个 reaction,所以这里需要延迟一下,确保所有的 reaction 都执行完毕后,
|
||||
// 再从 field.stateOfLinkageRules 中取值,因为此时 field.stateOfLinkageRules 中的值才是全的。
|
||||
@ -286,15 +295,10 @@ function getFieldNameByOperator(operator: ActionType) {
|
||||
}
|
||||
}
|
||||
|
||||
export const collectFieldStateOfLinkageRules = ({
|
||||
operator,
|
||||
value,
|
||||
field,
|
||||
condition,
|
||||
variables,
|
||||
localVariables,
|
||||
variableNameOfLeftCondition,
|
||||
}: Props) => {
|
||||
export const collectFieldStateOfLinkageRules = (
|
||||
{ operator, value, field, condition, variables, localVariables, variableNameOfLeftCondition }: Props,
|
||||
jsonLogic: any,
|
||||
) => {
|
||||
const requiredResult = field?.stateOfLinkageRules?.required || [field?.initStateOfLinkageRules?.required];
|
||||
const displayResult = field?.stateOfLinkageRules?.display || [field?.initStateOfLinkageRules?.display];
|
||||
const patternResult = field?.stateOfLinkageRules?.pattern || [field?.initStateOfLinkageRules?.pattern];
|
||||
@ -304,14 +308,14 @@ export const collectFieldStateOfLinkageRules = ({
|
||||
|
||||
switch (operator) {
|
||||
case ActionType.Required:
|
||||
requiredResult.push(getTempFieldState(conditionAnalyses(paramsToGetConditionResult), true));
|
||||
requiredResult.push(getTempFieldState(conditionAnalyses(paramsToGetConditionResult, jsonLogic), true));
|
||||
field.stateOfLinkageRules = {
|
||||
...field.stateOfLinkageRules,
|
||||
required: requiredResult,
|
||||
};
|
||||
break;
|
||||
case ActionType.InRequired:
|
||||
requiredResult.push(getTempFieldState(conditionAnalyses(paramsToGetConditionResult), false));
|
||||
requiredResult.push(getTempFieldState(conditionAnalyses(paramsToGetConditionResult, jsonLogic), false));
|
||||
field.stateOfLinkageRules = {
|
||||
...field.stateOfLinkageRules,
|
||||
required: requiredResult,
|
||||
@ -320,7 +324,7 @@ export const collectFieldStateOfLinkageRules = ({
|
||||
case ActionType.Visible:
|
||||
case ActionType.None:
|
||||
case ActionType.Hidden:
|
||||
displayResult.push(getTempFieldState(conditionAnalyses(paramsToGetConditionResult), operator));
|
||||
displayResult.push(getTempFieldState(conditionAnalyses(paramsToGetConditionResult, jsonLogic), operator));
|
||||
field.stateOfLinkageRules = {
|
||||
...field.stateOfLinkageRules,
|
||||
display: displayResult,
|
||||
@ -329,7 +333,7 @@ export const collectFieldStateOfLinkageRules = ({
|
||||
case ActionType.Editable:
|
||||
case ActionType.ReadOnly:
|
||||
case ActionType.ReadPretty:
|
||||
patternResult.push(getTempFieldState(conditionAnalyses(paramsToGetConditionResult), operator));
|
||||
patternResult.push(getTempFieldState(conditionAnalyses(paramsToGetConditionResult, jsonLogic), operator));
|
||||
field.stateOfLinkageRules = {
|
||||
...field.stateOfLinkageRules,
|
||||
pattern: patternResult,
|
||||
@ -364,7 +368,7 @@ export const collectFieldStateOfLinkageRules = ({
|
||||
if (isConditionEmpty(condition)) {
|
||||
valueResult.push(getTempFieldState(true, getValue()));
|
||||
} else {
|
||||
valueResult.push(getTempFieldState(conditionAnalyses(paramsToGetConditionResult), getValue()));
|
||||
valueResult.push(getTempFieldState(conditionAnalyses(paramsToGetConditionResult, jsonLogic), getValue()));
|
||||
}
|
||||
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 = (
|
||||
await Promise.all(
|
||||
rules
|
||||
.filter((k) => !k.disabled)
|
||||
.map(async (rule) => {
|
||||
if (await conditionAnalyses({ ruleGroup: rule.condition, variables, localVariables })) {
|
||||
if (await conditionAnalyses({ ruleGroup: rule.condition, variables, localVariables }, jsonLogic)) {
|
||||
return rule;
|
||||
} else return null;
|
||||
}),
|
||||
@ -40,15 +40,15 @@ const getSatisfiedActions = async ({ rules, variables, localVariables }) => {
|
||||
return satisfiedRules.map((rule) => rule.actions).flat();
|
||||
};
|
||||
|
||||
const getSatisfiedValues = async ({ rules, variables, localVariables }) => {
|
||||
return (await getSatisfiedActions({ rules, variables, localVariables })).map((action) => ({
|
||||
const getSatisfiedValues = async ({ rules, variables, localVariables }, jsonLogic) => {
|
||||
return (await getSatisfiedActions({ rules, variables, localVariables }, jsonLogic)).map((action) => ({
|
||||
...action,
|
||||
value: getActionValue(action.operator, action.value),
|
||||
}));
|
||||
};
|
||||
|
||||
export const getSatisfiedValueMap = async ({ rules, variables, localVariables }) => {
|
||||
const values = await getSatisfiedValues({ rules, variables, localVariables });
|
||||
export const getSatisfiedValueMap = async ({ rules, variables, localVariables }, jsonLogic) => {
|
||||
const values = await getSatisfiedValues({ rules, variables, localVariables }, jsonLogic);
|
||||
const valueMap = values.reduce((a, v) => ({ ...a, [v.operator]: v.value }), {});
|
||||
return valueMap;
|
||||
};
|
||||
|
@ -15,7 +15,7 @@ import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { useLocalVariables, useVariables } from '../../variables';
|
||||
import { getSatisfiedValueMap } from './compute-rules';
|
||||
import { LinkageRuleCategory, LinkageRuleDataKeyMap } from './type';
|
||||
|
||||
import { useApp } from '../../application';
|
||||
export function useSatisfiedActionValues({
|
||||
formValues,
|
||||
category = 'default',
|
||||
@ -35,10 +35,11 @@ export function useSatisfiedActionValues({
|
||||
const localVariables = useLocalVariables({ currentForm: { values: formValues } as any });
|
||||
const localSchema = schema ?? fieldSchema;
|
||||
const styleRules = rules ?? localSchema[LinkageRuleDataKeyMap[category]];
|
||||
const app = useApp();
|
||||
|
||||
const compute = useCallback(() => {
|
||||
if (styleRules && formValues) {
|
||||
getSatisfiedValueMap({ rules: styleRules, variables, localVariables })
|
||||
getSatisfiedValueMap({ rules: styleRules, variables, localVariables }, app.jsonLogic)
|
||||
.then((valueMap) => {
|
||||
if (!isEmpty(valueMap)) {
|
||||
setValueMap(valueMap);
|
||||
|
@ -121,9 +121,11 @@ const RuleTypes = {
|
||||
number: t('Number', { ns: NAMESPACE }),
|
||||
lowercase: t('Lowercase 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: {
|
||||
@ -154,14 +156,14 @@ const RuleTypes = {
|
||||
{ value: 'number', label: `{{t("Number", { ns: "${NAMESPACE}" })}}` },
|
||||
{ value: 'lowercase', label: `{{t("Lowercase 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,
|
||||
default: ['number'],
|
||||
'x-validator': {
|
||||
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: {
|
||||
|
@ -301,7 +301,7 @@ const CHAR_SETS = {
|
||||
lowercase: 'abcdefghijklmnopqrstuvwxyz',
|
||||
uppercase: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
|
||||
// 符号只保留常用且安全的符号,有需要的可以自己加比如[]{}|;:,.<>放在链接或者文件名里容易出问题的字符
|
||||
symbol: '!@#$%^&*_-+'
|
||||
symbol: '!@#$%^&*_-+',
|
||||
} as const;
|
||||
|
||||
interface RandomCharOptions {
|
||||
@ -317,21 +317,16 @@ sequencePatterns.register('randomChar', {
|
||||
if (!options?.charsets || options.charsets.length === 0) {
|
||||
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 null;
|
||||
},
|
||||
|
||||
generate(instance: any, options: RandomCharOptions) {
|
||||
const {
|
||||
length = 6,
|
||||
charsets = ['number']
|
||||
} = options;
|
||||
const { length = 6, charsets = ['number'] } = options;
|
||||
|
||||
const chars = [...new Set(
|
||||
charsets.reduce((acc, charset) => acc + CHAR_SETS[charset], '')
|
||||
)];
|
||||
const chars = [...new Set(charsets.reduce((acc, charset) => acc + CHAR_SETS[charset], ''))];
|
||||
|
||||
const getRandomChar = () => {
|
||||
const randomIndex = Math.floor(Math.random() * chars.length);
|
||||
@ -352,20 +347,27 @@ sequencePatterns.register('randomChar', {
|
||||
},
|
||||
|
||||
getMatcher(options: RandomCharOptions) {
|
||||
const pattern = [...new Set(
|
||||
const pattern = [
|
||||
...new Set(
|
||||
(options.charsets || ['number']).reduce((acc, charset) => {
|
||||
switch (charset) {
|
||||
case 'number': return acc + '0-9';
|
||||
case 'lowercase': return acc + 'a-z';
|
||||
case 'uppercase': return acc + 'A-Z';
|
||||
case 'symbol': return acc + CHAR_SETS.symbol.replace('-', '').replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&') + '-';
|
||||
default: return acc;
|
||||
case 'number':
|
||||
return acc + '0-9';
|
||||
case 'lowercase':
|
||||
return acc + 'a-z';
|
||||
case 'uppercase':
|
||||
return acc + 'A-Z';
|
||||
case 'symbol':
|
||||
return acc + CHAR_SETS.symbol.replace('-', '').replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&') + '-';
|
||||
default:
|
||||
return acc;
|
||||
}
|
||||
}, '')
|
||||
)].join('');
|
||||
}, ''),
|
||||
),
|
||||
].join('');
|
||||
|
||||
return `[${pattern}]{${options.length || 6}}`;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
interface PatternConfig {
|
||||
|
Loading…
x
Reference in New Issue
Block a user