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()
评估单条规则的条件是否满足。
处理逻辑:
- 遍历规则表达式列表
- 从
postData.value获取表单提交值 - 处理字符串类型(单选、下拉):清理冒号前缀后匹配
- 处理数组类型(多选):使用 lodash intersection 取交集
- 根据逻辑操作符(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"]
}}
]
}}
]
}}
规则说明:
- mode: "SHOW" 表示满足条件时显示,"HIDE" 表示满足条件时隐藏
- logical_op: "AND" 表示所有条件都要满足,"OR" 表示任一条件满足即可
- 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. 空值处理
当控制字段的值为 null 或 undefined 时,规则匹配结果为 false。
3. 多选字段
多选字段(checkbox)的值是数组,使用 lodash intersection 检查是否有交集。
4. 规则优先级
- HIDE 规则优先级高于 SHOW 规则
- 同类型规则之间使用 OR 逻辑(任一满足即可)
5. 性能考虑
- 每次字段值变化都会触发所有规则的重新评估
- 对于复杂表单,建议优化规则数量和复杂度