diff --git a/apps/web/src/pages/PluginCRUDPage.tsx b/apps/web/src/pages/PluginCRUDPage.tsx index 4e79360..ec0f3f2 100644 --- a/apps/web/src/pages/PluginCRUDPage.tsx +++ b/apps/web/src/pages/PluginCRUDPage.tsx @@ -773,9 +773,14 @@ export default function PluginCRUDPage({ name={field.name} label={field.display_name || field.name} rules={ - field.required - ? [{ required: true, message: `请输入${field.display_name || field.name}` }] - : [] + [ + ...(field.required + ? [{ required: true, message: `请输入${field.display_name || field.name}` }] + : []), + ...(field.validation?.pattern + ? [{ pattern: new RegExp(field.validation.pattern), message: field.validation.message || '格式不正确' }] + : []), + ] } valuePropName={field.field_type === 'boolean' ? 'checked' : 'value'} > diff --git a/apps/web/src/utils/exprEvaluator.ts b/apps/web/src/utils/exprEvaluator.ts index 45a451d..d62b5d4 100644 --- a/apps/web/src/utils/exprEvaluator.ts +++ b/apps/web/src/utils/exprEvaluator.ts @@ -11,7 +11,7 @@ */ interface ExprNode { - type: 'eq' | 'and' | 'or' | 'not'; + type: 'eq' | 'neq' | 'and' | 'or' | 'not'; field?: string; value?: string; left?: ExprNode; @@ -49,6 +49,16 @@ function tokenize(input: string): string[] { i += 2; continue; } + if (input[i] === '&' && input[i + 1] === '&') { + tokens.push('&&'); + i += 2; + continue; + } + if (input[i] === '|' && input[i + 1] === '|') { + tokens.push('||'); + i += 2; + continue; + } let j = i; while ( j < input.length && @@ -81,12 +91,12 @@ function parseAtom(tokens: string[]): ExprNode | null { if (op !== '==' && op !== '!=') return null; const rawValue = tokens.shift() || ''; const value = rawValue.replace(/^'(.*)'$/, '$1'); - return { type: 'eq', field, value }; + return { type: op === '!=' ? 'neq' : 'eq', field, value }; } function parseAnd(tokens: string[]): ExprNode | null { let left = parseAtom(tokens); - while (tokens[0] === 'AND') { + while (tokens[0] === 'AND' || tokens[0] === '&&') { tokens.shift(); const right = parseAtom(tokens); if (left && right) { @@ -98,7 +108,7 @@ function parseAnd(tokens: string[]): ExprNode | null { function parseOr(tokens: string[]): ExprNode | null { let left = parseAnd(tokens); - while (tokens[0] === 'OR') { + while (tokens[0] === 'OR' || tokens[0] === '||') { tokens.shift(); const right = parseAnd(tokens); if (left && right) { @@ -117,6 +127,8 @@ export function evaluateExpr(node: ExprNode, values: Record): b switch (node.type) { case 'eq': return String(values[node.field!] ?? '') === node.value; + case 'neq': + return String(values[node.field!] ?? '') !== node.value; case 'and': return evaluateExpr(node.left!, values) && evaluateExpr(node.right!, values); case 'or':