06-规则控制系统.md 18.6 KB

规则控制系统

最后更新: 2026-03-16 核心文件: src/views/index.vue

📋 概述

规则控制系统通过动态配置来实现表单字段的显示/隐藏逻辑,是表单系统的核心功能之一。

核心特性

  • 双模式控制: 支持 SHOW(显示)和 HIDE(隐藏)两种规则模式
  • 逻辑运算: 支持 AND(且)和 OR(或)逻辑操作符
  • 级联隐藏: 控制字段被隐藏时,其控制的所有字段也会被隐藏
  • 多规则支持: 单个字段可以同时受多条规则控制
  • 优先级机制: HIDE 规则优先级高于 SHOW 规则

🏗️ 数据结构

rule_list(规则列表)

规则列表位于 formInfo.value['rule_list'],是表单级别配置。

interface Rule {
    field_names: string[];      // 受此规则控制的字段名列表
    mode: 'SHOW' | 'HIDE';      // 规则模式:显示或隐藏
    logical_op: 'AND' | 'OR';   // 逻辑操作符
    expr_list: RuleExpr[];      // 规则表达式列表
    is_invalid?: boolean;       // 规则是否无效(可选)
}

interface RuleExpr {
    field_name: string;         // 控制字段名
    values: string[];           // 匹配值列表
}

规则流程图

┌─────────────────────────────────────────────────────────────┐
│                     规则控制系统架构                         │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  formInfo.rule_list                                         │
│       ↓                                                     │
│  ┌─────────────────────────────────────────────┐           │
│  │ checkRules() - 规则评估入口                  │           │
│  └─────────────────────────────────────────────┘           │
│       ↓                                                     │
│  ┌─────────────────────────────────────────────┐           │
│  │ 1. 收集规则涉及的所有字段                    │           │
│  │ 2. 初始化字段状态(disabled=false)          │           │
│  │ 3. 为每个字段分配规则(x_rules)             │           │
│  │ 4. 合并重复规则                              │           │
│  │ 5. 评估规则并设置 disabled 状态              │           │
│  └─────────────────────────────────────────────┘           │
│       ↓                                                     │
│  ┌─────────────────────────────────────────────┐           │
│  │ evaluateMultipleRules() - 多规则评估        │           │
│  │   ↓                                         │           │
│  │   分离 SHOW/HIDE 规则                        │           │
│  │   ↓                                         │           │
│  │   SHOW 规则: any 满足 = 显示                │           │
│  │   HIDE 规则: any 满足 = 隐藏                │           │
│  │   ↓                                         │           │
│  │   HIDE 优先 → 隐藏                          │           │
│  │   否则 → 根据 SHOW 规则决定                  │           │
│  └─────────────────────────────────────────────┘           │
│       ↓                                                     │
│  ┌─────────────────────────────────────────────┐           │
│  │ handleCascadeHiding() - 级联隐藏            │           │
│  │   如果控制字段被隐藏,其控制的所有字段       │           │
│  │   也会被隐藏                                  │           │
│  └─────────────────────────────────────────────┘           │
│                                                             │
└─────────────────────────────────────────────────────────────┘

🔧 核心函数

1. checkRules()

规则评估的主入口函数,负责初始化和协调整个规则评估流程。

const checkRules = () => {
    const rule_list = formInfo.value['rule_list'] ? [...formInfo.value['rule_list']] : [];

    // 1. 收集所有规则中涉及的字段
    const fieldsInRules = new Set();
    rule_list.forEach(rule => {
        if (rule.field_names && Array.isArray(rule.field_names)) {
            rule.field_names.forEach(fieldName => {
                fieldsInRules.add(fieldName);
            });
        }
    });

    // 2. 初始化字段规则,只重置在规则中出现过的字段
    formData.value.forEach(item => {
        item.x_rules = [];
        if (fieldsInRules.has(item.key) && item.component_props) {
            item.component_props.disabled = false;
        }
    });

    // 3. 收集每个字段的规则
    rule_list.forEach(rule => {
        formData.value.forEach(item => {
            if (rule.field_names?.includes(item.key) && !rule.is_invalid) {
                item.x_rules.push({
                    mode: rule.mode,
                    logical_op: rule.logical_op,
                    expr_list: rule.expr_list,
                });
            }
        });
    });

    // 4. 合并规则
    formData.value.forEach(item => {
        const mergedRules = mergeAndDeduplicate(item.x_rules);
        item.field_rules = mergedRules;
    });

    // 5. 处理规则逻辑 - 支持多条规则
    formData.value.forEach(item => {
        if (item.field_rules && item.field_rules.length > 0 && item.component_props) {
            const finalDisabledState = evaluateMultipleRules(item.field_rules);
            item.component_props.disabled = finalDisabledState;
        }
    });

    // 6. 处理级联隐藏
    handleCascadeHiding();
};

2. evaluateMultipleRules()

评估字段的所有规则,确定最终的显示/隐藏状态。

核心逻辑:

  • SHOW 规则:任一满足即显示(some)
  • HIDE 规则:任一满足即隐藏(some)
  • HIDE 规则优先级更高
const evaluateMultipleRules = (rulesList) => {
    if (!rulesList || rulesList.length === 0) {
        return false; // 没有规则时默认显示
    }

    let showRules = [];
    let hideRules = [];

    // 分离SHOW和HIDE规则
    rulesList.forEach(rule => {
        if (rule.mode === 'SHOW') {
            showRules.push(rule);
        } else if (rule.mode === 'HIDE') {
            hideRules.push(rule);
        }
    });

    // 评估SHOW规则
    let showResult = true; // 默认显示
    if (showRules.length > 0) {
        // 如果有SHOW规则,需要至少一个SHOW规则条件满足才显示
        showResult = showRules.some(rule => evaluateRuleCondition(rule));
    }

    // 评估HIDE规则
    let hideResult = false; // 默认不隐藏
    if (hideRules.length > 0) {
        // 如果有HIDE规则,任何一个HIDE规则条件满足就隐藏
        hideResult = hideRules.some(rule => evaluateRuleCondition(rule));
    }

    // 最终逻辑:HIDE规则优先级更高
    if (hideResult) {
        return true; // 隐藏
    } else {
        return !showResult; // SHOW规则不满足时隐藏
    }
};

3. evaluateRuleCondition()

评估单条规则的条件是否满足。

处理逻辑:

  1. 遍历规则表达式列表
  2. postData.value 获取表单提交值
  3. 处理字符串类型(单选、下拉):清理冒号前缀后匹配
  4. 处理数组类型(多选):使用 lodash intersection 取交集
  5. 根据逻辑操作符(AND/OR)计算最终结果
const evaluateRuleCondition = (fieldRules) => {
    if (!fieldRules || !fieldRules.expr_list || fieldRules.expr_list.length === 0) {
        return false;
    }

    const results = [];

    fieldRules.expr_list.forEach(expr => {
        let form_submission_value = postData.value[expr.field_name];
        const rule_matching_value = expr.values || [];

        // 处理空值情况
        if (form_submission_value === null || form_submission_value === undefined) {
            results.push(false);
            return;
        }

        let matchResult = false;

        if (typeof form_submission_value === 'string') {
            // 处理字符串类型(单选,下拉)
            let cleanValue = form_submission_value;
            if (form_submission_value.indexOf(':') !== -1) {
                cleanValue = form_submission_value.split(':')[0];
            }
            matchResult = rule_matching_value.includes(cleanValue);
        } else if (Array.isArray(form_submission_value)) {
            // 处理数组类型(多选)
            const cleanValues = form_submission_value.map(item => {
                if (typeof item === 'string' && item.includes(':')) {
                    return item.split(':')[0].trim();
                }
                return item;
            });
            matchResult = _.intersection(rule_matching_value, cleanValues).length > 0;
        }

        results.push(matchResult);
    });

    // 根据逻辑操作符计算最终结果
    if (fieldRules.logical_op === 'AND') {
        return results.every(result => result === true);
    } else { // OR
        return results.some(result => result === true);
    }
};

4. handleCascadeHiding()

处理级联隐藏逻辑,确保当控制字段被隐藏时,其控制的所有字段也会被隐藏。

const handleCascadeHiding = () => {
    const rule_list = formInfo.value['rule_list'] || [];

    // 获取所有规则控制字段的映射
    const ruleControlMap = new Map();
    rule_list.forEach(rule => {
        if (rule.expr_list && rule.expr_list.length > 0) {
            const controlField = rule.expr_list[0].field_name;
            if (!ruleControlMap.has(controlField)) {
                ruleControlMap.set(controlField, []);
            }
            ruleControlMap.get(controlField).push({
                field_names: rule.field_names || [],
                mode: rule.mode
            });
        }
    });

    // 检查级联隐藏
    formData.value.forEach(item => {
        if (ruleControlMap.has(item.key) && item.component_props && item.component_props.disabled) {
            // 如果控制字段被隐藏,则隐藏其控制的所有字段
            const controlledRules = ruleControlMap.get(item.key);
            controlledRules.forEach(rule => {
                rule.field_names.forEach(fieldName => {
                    const targetField = formData.value.find(field => field.key === fieldName);
                    if (targetField && targetField.component_props) {
                        targetField.component_props.disabled = true;
                    }
                });
            });
        }
    });
};

🔄 触发机制

规则评估在以下时机触发:

1. 表单初始化时

表单数据加载完成后,调用 checkRules() 初始化所有字段的显示状态。

2. 字段值变化时

当用户修改表单字段值时,通过 @active 事件触发规则重新评估:

<component
    v-for="item in formData"
    :is="item.component_props.tag"
    v-model="postData[item.key]"
    @active="checkRules"
/>

3. 数据结构

  • formData: 表单字段配置数组
  • postData: 表单实际提交的数据
  • formInfo: 表单元数据(包含 rule_list)

📊 实际示例

示例 1:简单 SHOW 规则

场景:只有当"用户类型"选择"企业用户"时,才显示"企业名称"字段。

{
    "rule_list": [
        {
            "field_names": ["company_name"],
            "mode": "SHOW",
            "logical_op": "OR",
            "expr_list": [
                {
                    "field_name": "user_type",
                    "values": ["enterprise"]
                }
            ]
        }
    ]
}

示例 2:HIDE 规则

场景:当"居住类型"选择"租房"时,隐藏"房产证号"字段。

{
    "rule_list": [
        {
            "field_names": ["property_cert_no"],
            "mode": "HIDE",
            "logical_op": "OR",
            "expr_list": [
                {
                    "field_name": "residence_type",
                    "values": ["rent"]
                }
            ]
        }
    ]
}

示例 3:AND 逻辑

场景:同时满足"年龄大于18"且"有收入证明"时,显示"信用卡申请"字段。

{
    "rule_list": [
        {
            "field_names": ["credit_card_application"],
            "mode": "SHOW",
            "logical_op": "AND",
            "expr_list": [
                {
                    "field_name": "age",
                    "values": ["adult", "senior"]
                },
                {
                    "field_name": "income_proof",
                    "values": ["yes"]
                }
            ]
        }
    ]
}

示例 4:OR 逻辑

场景:选择"VIP用户"或"企业用户"任一条件时,显示"专属客服"字段。

{
    "rule_list": [
        {
            "field_names": ["exclusive_service"],
            "mode": "SHOW",
            "logical_op": "OR",
            "expr_list": [
                {
                    "field_name": "user_type",
                    "values": ["vip"]
                },
                {
                    "field_name": "user_type",
                    "values": ["enterprise"]
                }
            ]
        }
    ]
}

示例 5:多规则控制

场景:字段受多条规则控制,HIDE 规则优先。

{
    "rule_list": [
        {
            "field_names": ["special_discount"],
            "mode": "SHOW",
            "logical_op": "OR",
            "expr_list": [
                {
                    "field_name": "membership_level",
                    "values": ["gold", "platinum"]
                }
            ]
        },
        {
            "field_names": ["special_discount"],
            "mode": "HIDE",
            "logical_op": "OR",
            "expr_list": [
                {
                    "field_name": "account_status",
                    "values": ["suspended", "banned"]
                }
            ]
        }
    ]
}

结果:即使满足 VIP 条件,如果账户被暂停,也不会显示特殊折扣字段。

示例 6:级联隐藏

场景

  • 字段 A 控制字段 B 的显示
  • 字段 B 控制字段 C 的显示
  • 当字段 A 被隐藏时,字段 B 和 C 都应该被隐藏
{
    "rule_list": [
        {
            "field_names": ["field_b"],
            "mode": "SHOW",
            "logical_op": "OR",
            "expr_list": [
                {
                    "field_name": "field_a",
                    "values": ["show_b"]
                }
            ]
        },
        {
            "field_names": ["field_c"],
            "mode": "SHOW",
            "logical_op": "OR",
            "expr_list": [
                {
                    "field_name": "field_b",
                    "values": ["show_c"]
                }
            ]
        }
    ]
}

🎯 LangChain Agent 集成要点

自然语言到规则的映射

当用户用自然语言描述规则时,Agent 需要将其转换为规则配置:

用户描述 mode logical_op
"当...时显示" SHOW OR
"只有...才显示" SHOW AND
"当...时隐藏" HIDE OR
"只要...就隐藏" HIDE OR

Prompt 模板

RULE_GENERATION_TEMPLATE = """
你是一个表单规则配置专家。根据用户的自然语言描述,生成规则配置。

用户描述:{user_description}

可用的字段:
{available_fields}

请生成规则配置,格式如下:
```json
{{
    "rule_list": [
        {{
            "field_names": ["受控制的字段名"],
            "mode": "SHOW" | "HIDE",
            "logical_op": "AND" | "OR",
            "expr_list": [
                {{
                    "field_name": "控制字段名",
                    "values": ["值1", "值2"]
                }}
            ]
        }}
    ]
}}

规则说明:

  1. mode: "SHOW" 表示满足条件时显示,"HIDE" 表示满足条件时隐藏
  2. logical_op: "AND" 表示所有条件都要满足,"OR" 表示任一条件满足即可
  3. HIDE 规则优先级高于 SHOW 规则 """ ```

示例对话

用户输入

"当用户类型是企业时,显示企业名称和统一社会信用代码字段"

Agent 输出

{
    "rule_list": [
        {
            "field_names": ["company_name", "credit_code"],
            "mode": "SHOW",
            "logical_op": "OR",
            "expr_list": [
                {
                    "field_name": "user_type",
                    "values": ["enterprise", "company"]
                }
            ]
        }
    ]
}

⚠️ 注意事项

1. 值格式处理

系统会自动处理带冒号的值(如 "option1:选项1"),只匹配冒号前的部分。

2. 空值处理

当控制字段的值为 nullundefined 时,规则匹配结果为 false

3. 多选字段

多选字段(checkbox)的值是数组,使用 lodash intersection 检查是否有交集。

4. 规则优先级

  • HIDE 规则优先级高于 SHOW 规则
  • 同类型规则之间使用 OR 逻辑(任一满足即可)

5. 性能考虑

  • 每次字段值变化都会触发所有规则的重新评估
  • 对于复杂表单,建议优化规则数量和复杂度

🔗 相关文档