GPT帮实现了EasyRule简易规则引擎代码生成界面

829 阅读9分钟

一、背景介绍

最近在学习开源规则引擎EasyRule,然后发现目前没有合适的规则引擎界面,于是我准备用大模型来帮助我做一个EasyRule规则引擎可视化的UI配置界面,没想到大模型非常轻松的帮助我做了一个UI可视化配置界面,真的太强大了,一步步调教后,效果非常不错,如下所示:

非Vue版:

Vue.js版本:

二、如何做的

2.1、让大模型学习知识

1、首先我们访问ChatGPT,目前ChatGPT是每天有免费的使用的额度的,所以完全可以每天用用GPT,首先我把EasyRule这个开源项目下的ReadMe文档中的使用示例给了他,让他给我写篇文章,与我对它说

这个是开源项目easy rule规则引擎的使用说明的例子:First, define your rule..
Either in a declarative way using annotations:

@Rule(name = "weather rule", description = "if it rains then take an umbrella")
public class WeatherRule {

    @Condition
    public boolean itRains(@Fact("rain") boolean rain) {
        return rain;
    }
    
    @Action
    public void takeAnUmbrella() {
        System.out.println("It rains, take an umbrella!");
    }
}

Or in a programmatic way with a fluent API:

Rule weatherRule = new RuleBuilder()
        .name("weather rule")
        .description("if it rains then take an umbrella")
        .when(facts -> facts.get("rain").equals(true))
        .then(facts -> System.out.println("It rains, take an umbrella!"))
        .build();

Or using an Expression Language:

Rule weatherRule = new MVELRule()
        .name("weather rule")
        .description("if it rains then take an umbrella")
        .when("rain == true")
        .then("System.out.println(\"It rains, take an umbrella!\");");

Or using a rule descriptor:

Like in the following weather-rule.yml example file:

name: "weather rule"
description: "if it rains then take an umbrella"
condition: "rain == true"
actions:
  - "System.out.println(\"It rains, take an umbrella!\");"

MVELRuleFactory ruleFactory = new MVELRuleFactory(new YamlRuleDefinitionReader());
Rule weatherRule = ruleFactory.createRule(new FileReader("weather-rule.yml"));

2. Then, fire it!

public class Test {
    public static void main(String[] args) {
        // define facts
        Facts facts = new Facts();
        facts.put("rain", true);

        // define rules
        Rule weatherRule = ...
        Rules rules = new Rules();
        rules.register(weatherRule);

        // fire rules on known facts
        RulesEngine rulesEngine = new DefaultRulesEngine();
        rulesEngine.fire(rules, facts);
    }
}

This is the hello world of Easy Rules. 
You can find other examples like the Shop, Airco or WebApp tutorials in the wiki.
。而我想基于这个例子给其他没有接触过的人将明白,并通过文章的形式让大家学会如何使用.
请你基于我的目标和例子,给我写篇文章

这样在这个聊天历史中,大模型就具备了这个知识和上下文。

2.2、第1次给大模型提出需求

接下来我问它这句话:

好,我想开发个easyrule的可视化的前端配置界面,在配置界面中可以配置这个规则的相关内容,通过简单的方式设置规则,然后生成对应的easyrule后端java的配置,你看看帮我实现下吧。前端用HTML文件和JS文件就行,不用vue和react,同时不要返回后端代码,只返回前端的,前端有某个按钮,单击生成,可以出现代码弹窗

然后大模型的第一次返回结果如下:

你可以使用纯 HTML 和 JavaScript 来创建一个简单的可视化配置界面。在这个界面中,用户可以输入规则的名称、描述、条件、动作,然后点击按钮生成相应的 Easy Rules Java 代码。生成的代码将显示在一个弹窗中,用户可以直接复制使用。

下面是实现这个功能的 HTML 和 JavaScript 代码:

1. HTML 代码(index.html)

html复制代码<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Easy Rules 可视化配置</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            padding: 20px;
        }
        label {
            display: block;
            margin: 10px 0 5px;
        }
        input[type="text"], textarea {
            width: 100%;
            padding: 8px;
            margin-bottom: 10px;
        }
        button {
            padding: 10px 20px;
            background-color: #4CAF50;
            color: white;
            border: none;
            cursor: pointer;
        }
        button:hover {
            background-color: #45a049;
        }
        /* 弹窗样式 */
        #codeModal {
            display: none;
            position: fixed;
            left: 50%;
            top: 50%;
            transform: translate(-50%, -50%);
            padding: 20px;
            background-color: white;
            border: 2px solid #333;
            z-index: 1000;
        }
        #codeModal pre {
            white-space: pre-wrap;
            word-wrap: break-word;
            background-color: #f4f4f4;
            padding: 15px;
            border: 1px solid #ddd;
        }
        #closeModal {
            margin-top: 10px;
            padding: 8px;
            background-color: #f44336;
            color: white;
            border: none;
            cursor: pointer;
        }
    </style>
</head>
<body>

<h2>Easy Rules 可视化配置界面</h2>

<!-- 表单部分 -->
<form id="ruleForm">
    <label for="name">规则名称:</label>
    <input type="text" id="name" placeholder="请输入规则名称">

    <label for="description">规则描述:</label>
    <input type="text" id="description" placeholder="请输入规则描述">

    <label for="condition">条件 (e.g., "rain == true"):</label>
    <input type="text" id="condition" placeholder="请输入条件">

    <label for="action">动作 (e.g., "System.out.println('Take an umbrella!')"):</label>
    <textarea id="action" rows="4" placeholder="请输入Java动作代码"></textarea>

    <button type="button" id="generateCode">生成代码</button>
</form>

<!-- 弹窗部分 -->
<div id="codeModal">
    <h3>生成的 Java 规则代码:</h3>
    <pre id="generatedCode"></pre>
    <button id="closeModal">关闭</button>
</div>

<script src="script.js"></script>

</body>
</html>

2. JavaScript 代码(script.js)

javascript复制代码// 获取表单元素
const nameInput = document.getElementById('name');
const descriptionInput = document.getElementById('description');
const conditionInput = document.getElementById('condition');
const actionInput = document.getElementById('action');

// 获取按钮和弹窗相关元素
const generateButton = document.getElementById('generateCode');
const codeModal = document.getElementById('codeModal');
const generatedCodePre = document.getElementById('generatedCode');
const closeModalButton = document.getElementById('closeModal');

// 点击生成按钮时生成代码并显示弹窗
generateButton.addEventListener('click', function () {
    // 获取输入的值
    const ruleName = nameInput.value;
    const ruleDescription = descriptionInput.value;
    const ruleCondition = conditionInput.value;
    const ruleAction = actionInput.value;

    // 生成规则的 Java 代码
    const generatedCode = `
@Rule(name = "${ruleName}", description = "${ruleDescription}")
public class GeneratedRule {

    @Condition
    public boolean evaluate(@Fact("fact") Object fact) {
        return ${ruleCondition};
    }

    @Action
    public void execute() {
        ${ruleAction};
    }
}
`;

    // 将生成的代码放入弹窗
    generatedCodePre.textContent = generatedCode;

    // 显示弹窗
    codeModal.style.display = 'block';
});

// 关闭弹窗
closeModalButton.addEventListener('click', function () {
    codeModal.style.display = 'none';
});

3. 功能说明

a. 输入部分

用户可以在页面上输入以下内容:

  • 规则名称
  • 规则描述
  • 规则条件(例如 rain == true
  • 动作(例如 System.out.println("It rains, take an umbrella!");

b. 生成规则代码

点击“生成代码”按钮后,会生成如下格式的 Java 规则代码并在弹窗中显示:

java复制代码@Rule(name = "yourRuleName", description = "yourRuleDescription")
public class GeneratedRule {

    @Condition
    public boolean evaluate(@Fact("fact") Object fact) {
        return yourCondition;
    }

    @Action
    public void execute() {
        yourAction;
    }
}

c. 弹窗显示

生成的代码会通过弹窗展示,用户可以直接复制。点击“关闭”按钮可以隐藏弹窗。

4. 使用说明

  1. index.html 文件和 script.js 文件保存在同一目录下。
  2. 用浏览器打开 index.html 文件,就可以看到可视化配置界面。
  3. 输入规则的相关信息后,点击“生成代码”按钮,系统会自动生成对应的 Java 规则代码并弹窗显示,方便用户复制。

5. 扩展建议

  • 代码导出:可以添加一个按钮将生成的代码导出为文件,方便后续使用。
  • 表单验证:可以加入输入校验,确保用户输入正确的 Java 表达式。
  • 多种生成方式:扩展代码生成方式,如 YAML、流式 API 等。

这样一个简单、直观的前端界面,能有效帮助用户无需编写代码就能快速生成 Easy Rules 规则代码,并且可以直接复制到后端项目中使用。

经过了第一次的运行后,效果如下:

2.3、第2次给大模型提出需求

接下来我问它这句话:

太棒了,我想把条件那块做成类似QueryBuilder的效果,不需要用户自己手动输入条件,而是选择的方式,你看看修改下

于是大模型的又返回了新的结果:

为了让条件部分更加友好,可以将条件输入变成类似 QueryBuilder 的形式,让用户通过选择字段、运算符和输入值来生成条件,而不是手动输入条件表达式。下面我会通过修改前端的 index.htmlscript.js,实现这个效果。

1. 修改思路

  • 条件部分 将由三个部分组成:
    1. 字段选择:用户可以选择预定义的字段(例如 raintemperature 等)。
    2. 运算符选择:用户可以选择运算符(例如 ==, !=, >, < 等)。
    3. 值输入:用户可以输入具体的值(例如 true30 等)。
  • 当用户选择完字段、运算符和输入值后,系统将根据这些信息自动生成条件。

2. 修改后的 HTML 代码

html复制代码<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Easy Rules 可视化配置</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            padding: 20px;
        }
        label {
            display: block;
            margin: 10px 0 5px;
        }
        input[type="text"], textarea, select {
            width: 100%;
            padding: 8px;
            margin-bottom: 10px;
        }
        button {
            padding: 10px 20px;
            background-color: #4CAF50;
            color: white;
            border: none;
            cursor: pointer;
        }
        button:hover {
            background-color: #45a049;
        }
        /* 弹窗样式 */
        #codeModal {
            display: none;
            position: fixed;
            left: 50%;
            top: 50%;
            transform: translate(-50%, -50%);
            padding: 20px;
            background-color: white;
            border: 2px solid #333;
            z-index: 1000;
        }
        #codeModal pre {
            white-space: pre-wrap;
            word-wrap: break-word;
            background-color: #f4f4f4;
            padding: 15px;
            border: 1px solid #ddd;
        }
        #closeModal {
            margin-top: 10px;
            padding: 8px;
            background-color: #f44336;
            color: white;
            border: none;
            cursor: pointer;
        }
    </style>
</head>
<body>

<h2>Easy Rules 可视化配置界面</h2>

<!-- 表单部分 -->
<form id="ruleForm">
    <label for="name">规则名称:</label>
    <input type="text" id="name" placeholder="请输入规则名称">

    <label for="description">规则描述:</label>
    <input type="text" id="description" placeholder="请输入规则描述">

    <!-- 条件部分:字段、运算符、值 -->
    <label for="field">条件字段:</label>
    <select id="field">
        <option value="rain">rain</option>
        <option value="temperature">temperature</option>
        <option value="humidity">humidity</option>
    </select>

    <label for="operator">运算符:</label>
    <select id="operator">
        <option value="==">等于 (==)</option>
        <option value="!=">不等于 (!=)</option>
        <option value=">">大于 (>)</option>
        <option value="<">小于 (<)</option>
        <option value=">=">大于等于 (>=)</option>
        <option value="<=">小于等于 (<=)</option>
    </select>

    <label for="value">条件值:</label>
    <input type="text" id="value" placeholder="请输入条件值">

    <label for="action">动作 (e.g., "System.out.println('Take an umbrella!')"):</label>
    <textarea id="action" rows="4" placeholder="请输入Java动作代码"></textarea>

    <button type="button" id="generateCode">生成代码</button>
</form>

<!-- 弹窗部分 -->
<div id="codeModal">
    <h3>生成的 Java 规则代码:</h3>
    <pre id="generatedCode"></pre>
    <button id="closeModal">关闭</button>
</div>

<script src="script.js"></script>

</body>
</html>

3. 修改后的 JavaScript 代码(script.js)

javascript复制代码// 获取表单元素
const nameInput = document.getElementById('name');
const descriptionInput = document.getElementById('description');
const fieldInput = document.getElementById('field');
const operatorInput = document.getElementById('operator');
const valueInput = document.getElementById('value');
const actionInput = document.getElementById('action');

// 获取按钮和弹窗相关元素
const generateButton = document.getElementById('generateCode');
const codeModal = document.getElementById('codeModal');
const generatedCodePre = document.getElementById('generatedCode');
const closeModalButton = document.getElementById('closeModal');

// 点击生成按钮时生成代码并显示弹窗
generateButton.addEventListener('click', function () {
    // 获取输入的值
    const ruleName = nameInput.value;
    const ruleDescription = descriptionInput.value;
    const field = fieldInput.value;
    const operator = operatorInput.value;
    const value = valueInput.value;
    const ruleAction = actionInput.value;

    // 生成条件表达式
    const condition = `${field} ${operator} ${value}`;

    // 生成规则的 Java 代码
    const generatedCode = `
@Rule(name = "${ruleName}", description = "${ruleDescription}")
public class GeneratedRule {

    @Condition
    public boolean evaluate(@Fact("fact") Object fact) {
        return ${condition};
    }

    @Action
    public void execute() {
        ${ruleAction};
    }
}
`;

    // 将生成的代码放入弹窗
    generatedCodePre.textContent = generatedCode;

    // 显示弹窗
    codeModal.style.display = 'block';
});

// 关闭弹窗
closeModalButton.addEventListener('click', function () {
    codeModal.style.display = 'none';
});

4. 功能说明

a. 条件输入部分

用户不再手动输入条件,而是通过选择来生成条件:

  • 字段选择:通过下拉菜单选择字段(如 rain, temperature, humidity 等)。
  • 运算符选择:通过下拉菜单选择条件运算符(如 ==, !=, >, < 等)。
  • 值输入:用户手动输入条件值(如 true, 30 等)。

例如,如果用户选择了 rain == true,系统会自动生成相应的条件表达式 rain == true

b. 生成规则代码

生成的 Java 代码示例:

java复制代码@Rule(name = "yourRuleName", description = "yourRuleDescription")
public class GeneratedRule {

    @Condition
    public boolean evaluate(@Fact("fact") Object fact) {
        return rain == true;
    }

    @Action
    public void execute() {
        System.out.println("Take an umbrella!");
    }
}

c. 弹窗显示

生成的代码会通过弹窗显示,用户可以直接复制并使用。点击“关闭”按钮后弹窗消失。

5. 使用说明

  1. index.htmlscript.js 文件保存在同一目录中。
  2. 使用浏览器打开 index.html
  3. 用户可以通过选择字段、运算符和输入值来生成条件,点击“生成代码”按钮后,自动生成对应的 Easy Rules Java 代码并通过弹窗显示。

6. 扩展建议

  • 字段列表扩展:可以动态加载可用字段,支持自定义字段。
  • 多条件支持:添加多条件支持,如 "AND" 和 "OR" 组合条件。
  • 保存和导出功能:允许用户保存生成的规则为文件。

通过这样的方式,用户能够更加直观地创建条件,不需要手动输入 Java 表达式,大大简化了规则配置的复杂度。

我们看下第二次的效果:

2.4、第3次给大模型提出需求

接下来我问它这句话:

太强了,我想让这个界面变的好看一点,请你优化下CSS的样式,尤其是下拉框的样式,同时条件字段、运算符、条件值需要在一行显示。且支持多个条件进行并且的方式选择,从而形成条件组,在给我处理下吧

于是大模型的又返回了新的结果:

为了让界面变得更加美观,并且支持多个条件的组合(使用 "并且" 的方式),我将对 CSS 进行优化,尤其是 下拉框的样式表单布局,同时实现多条件支持。这样用户可以选择多个条件来生成复杂的规则。

修改思路

  1. CSS 优化:下拉框美化,按钮样式调整,布局改进。
  2. 条件组:每个条件的字段、运算符和值在一行显示,并可以通过点击按钮添加更多条件。
  3. 多条件支持:使用“并且”的方式将条件组合起来生成规则。

1. 修改后的 HTML 代码

html复制代码<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Easy Rules 可视化配置</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            padding: 20px;
            background-color: #f7f7f7;
        }
        h2 {
            color: #333;
        }
        label {
            display: block;
            margin: 10px 0 5px;
            font-weight: bold;
        }
        .rule-group {
            margin-bottom: 20px;
            background-color: #fff;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
        }
        .condition-row {
            display: flex;
            align-items: center;
            justify-content: space-between;
            margin-bottom: 10px;
        }
        select, input[type="text"], textarea {
            padding: 8px;
            border: 1px solid #ddd;
            border-radius: 4px;
            font-size: 14px;
        }
        select {
            -webkit-appearance: none;
            -moz-appearance: none;
            appearance: none;
            background-color: #fff;
            background-image: url('data:image/svg+xml;charset=US-ASCII,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 4 5"><path fill="none" stroke="%23000" stroke-width=".8" d="M2 0L0 2h4zm0 5L0 3h4z"/></svg>');
            background-repeat: no-repeat;
            background-position: right 10px center;
            background-size: 8px 10px;
            padding-right: 20px;
        }
        button {
            padding: 10px 20px;
            background-color: #4CAF50;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 14px;
        }
        button:hover {
            background-color: #45a049;
        }
        .add-condition-btn {
            margin-left: 10px;
            background-color: #008CBA;
        }
        .remove-condition-btn {
            margin-left: 10px;
            background-color: #f44336;
        }
        /* 弹窗样式 */
        #codeModal {
            display: none;
            position: fixed;
            left: 50%;
            top: 50%;
            transform: translate(-50%, -50%);
            padding: 20px;
            background-color: white;
            border: 2px solid #333;
            z-index: 1000;
            width: 60%;
            border-radius: 8px;
        }
        #codeModal pre {
            white-space: pre-wrap;
            word-wrap: break-word;
            background-color: #f4f4f4;
            padding: 15px;
            border: 1px solid #ddd;
            border-radius: 4px;
        }
        #closeModal {
            margin-top: 10px;
            padding: 8px;
            background-color: #f44336;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
        }
    </style>
</head>
<body>

<h2>Easy Rules 可视化配置界面</h2>

<!-- 表单部分 -->
<div class="rule-group">
    <form id="ruleForm">
        <label for="name">规则名称:</label>
        <input type="text" id="name" placeholder="请输入规则名称">

        <label for="description">规则描述:</label>
        <input type="text" id="description" placeholder="请输入规则描述">

        <div id="conditions">
            <!-- 动态添加条件组 -->
            <div class="condition-row">
                <select class="field">
                    <option value="rain">rain</option>
                    <option value="temperature">temperature</option>
                    <option value="humidity">humidity</option>
                </select>

                <select class="operator">
                    <option value="==">等于 (==)</option>
                    <option value="!=">不等于 (!=)</option>
                    <option value=">">大于 (>)</option>
                    <option value="<">小于 (<)</option>
                    <option value=">=">大于等于 (>=)</option>
                    <option value="<=">小于等于 (<=)</option>
                </select>

                <input type="text" class="value" placeholder="请输入条件值">
                <button type="button" class="add-condition-btn">添加条件</button>
            </div>
        </div>

        <label for="action">动作 (e.g., "System.out.println('Take an umbrella!')"):</label>
        <textarea id="action" rows="4" placeholder="请输入Java动作代码"></textarea>

        <button type="button" id="generateCode">生成代码</button>
    </form>
</div>

<!-- 弹窗部分 -->
<div id="codeModal">
    <h3>生成的 Java 规则代码:</h3>
    <pre id="generatedCode"></pre>
    <button id="closeModal">关闭</button>
</div>

<script src="script.js"></script>

</body>
</html>

2. 修改后的 JavaScript 代码(script.js)

javascript复制代码// 获取表单元素
const nameInput = document.getElementById('name');
const descriptionInput = document.getElementById('description');
const conditionsDiv = document.getElementById('conditions');
const actionInput = document.getElementById('action');

// 获取按钮和弹窗相关元素
const generateButton = document.getElementById('generateCode');
const codeModal = document.getElementById('codeModal');
const generatedCodePre = document.getElementById('generatedCode');
const closeModalButton = document.getElementById('closeModal');

// 添加条件按钮功能
conditionsDiv.addEventListener('click', function (e) {
    if (e.target.classList.contains('add-condition-btn')) {
        // 创建新的条件行
        const conditionRow = document.createElement('div');
        conditionRow.classList.add('condition-row');
        conditionRow.innerHTML = `
            <select class="field">
                <option value="rain">rain</option>
                <option value="temperature">temperature</option>
                <option value="humidity">humidity</option>
            </select>

            <select class="operator">
                <option value="==">等于 (==)</option>
                <option value="!=">不等于 (!=)</option>
                <option value=">">大于 (>)</option>
                <option value="<">小于 (<)</option>
                <option value=">=">大于等于 (>=)</option>
                <option value="<=">小于等于 (<=)</option>
            </select>

            <input type="text" class="value" placeholder="请输入条件值">
            <button type="button" class="remove-condition-btn">删除条件</button>
        `;
        conditionsDiv.appendChild(conditionRow);
    }

    // 删除条件按钮功能
    if (e.target.classList.contains('remove-condition-btn')) {
        e.target.parentElement.remove();
    }
});

// 点击生成按钮时生成代码并显示弹窗
generateButton.addEventListener('click', function () {
    const ruleName = nameInput.value;
    const ruleDescription = descriptionInput.value;
    const ruleAction = actionInput.value;

    // 获取所有条件
    const conditionRows = document.querySelectorAll('.condition-row');
    let conditions = [];
    conditionRows.forEach(row => {
        const field = row.querySelector('.field').value;
        const operator = row.querySelector('.operator').value;
        const value = row.querySelector('.value').value;
        conditions.push(`${field} ${operator} ${value}`);
    });

    // 将条件用 "&&" 连接起来
    const conditionExpression = conditions.join(' && ');

    // 生成规则的 Java 代码
    const generatedCode = `
@Rule(name = "${ruleName}", description = "${ruleDescription}")
public class GeneratedRule {

    @Condition
    public boolean evaluate(@Fact("fact") Object fact) {
        return ${conditionExpression};
    }

    @Action
    public void execute() {
        ${ruleAction};
    }
}
`;

    // 将生成的代码放入弹窗
    generatedCodePre.textContent = generatedCode;

    // 显示弹窗
     codeModal.style.display = 'block';
    });

// 关闭弹窗
closeModalButton.addEventListener('click', function () {
    codeModal.style.display = 'none';
});

3. 功能说明

a. 条件组布局

每个条件组(字段、运算符、值)现在会在同一行显示,用户可以通过点击“添加条件”按钮新增一个条件组,也可以通过“删除条件”按钮移除不需要的条件。

b. 美化的下拉框

下拉框使用了简单的 CSS 样式优化,添加了自定义的下拉箭头和调整了整体的视觉风格,确保看起来更现代。

c. 多条件支持

通过 "并且"(&& 方式将所有条件组合在一起。如果用户创建了多个条件,系统会自动将它们组合到条件表达式中。例如:

java复制代码return rain == true && temperature > 20;

d. 生成 Java 规则代码

生成的代码如下所示:

java复制代码@Rule(name = "yourRuleName", description = "yourRuleDescription")
public class GeneratedRule {

    @Condition
    public boolean evaluate(@Fact("fact") Object fact) {
        return rain == true && temperature > 20;
    }

    @Action
    public void execute() {
        System.out.println("Take an umbrella!");
    }
}

e. 弹窗展示生成的代码

用户点击“生成代码”后,弹窗会显示生成的 Java 代码。用户可以通过“关闭”按钮关闭弹窗。

4. 扩展建议

  • 条件组扩展:支持不同的逻辑组合(如 "或者" 组合条件)。
  • 复杂条件支持:可以让用户在生成的条件表达式中插入括号,形成更复杂的逻辑表达式。
  • 动作配置扩展:可以支持多种动作(如多行代码)或者条件触发不同动作。
  • 保存配置:可以添加保存配置的功能,将用户配置的条件组和规则保存为文件或者发送到后端进行处理。

通过这个优化后的界面,用户可以更直观、灵活地配置规则,并且代码生成过程也更加自动化和用户友好。

我们再来看看第三次的UI结果:

这样我们就有了可以操作的代码了。

三、最后

然后我们在跟大模型持续沟通下UI、交互、细节,最终就形成了如下样式界面:

单击生成代码后,可以生成EasyRule的代码:

这里面能做的还有非常多,比如添加条件组等等。感兴趣的小伙伴可以去尝试下。

我这里最终我自己优化后的代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Easy Rules 可视化配置</title>
    <style>
        /* 基本布局 */
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            margin: 0;
            padding: 0;
            background-color: #f0f0f0;
        }

        /* 页面标题 */
        h2 {
            color: #333;
            font-size: 24px;
            margin-bottom: 20px;
            text-align: center;
        }

        /* 规则组容器 */
        .rule-group {
            max-width: 1200px;
            margin: 0 auto;
            background-color: #ffffff;
            padding: 20px;
            border-radius: 10px;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
        }

        /* 表单标签 */
        label {
            display: block;
            margin: 10px 0 5px;
            font-size: 16px;
            color: #555;
        }

        /* 输入框和下拉菜单 */
        input[type="text"],
        textarea,
        select {
            width: 100%;
            padding: 10px;
            border: 1px solid #ccc;
            border-radius: 0px;
            box-sizing: border-box;
            font-size: 14px;
          
            background-color: #fff;
        }

        input[type="text"] {
            width: 500px;
            display: inline-block;
            margin-right: 10px;
        }

        textarea {
            resize: vertical;
        }

        /* 美化下拉框 */
        select {
            appearance: none;
            background-color: #ffffff;
            background-image: url('data:image/svg+xml;charset=US-ASCII,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 4 5"><path fill="none" stroke="%23000" stroke-width=".8" d="M2 0L0 2h4zm0 5L0 3h4z"/></svg>');
            background-repeat: no-repeat;
            background-position: right 10px center;
            background-size: 12px 12px;
            padding-right: 40px;
            border: 1px solid #ccc;
        }

        /* 按钮 */
        button {
            padding: 10px 24px;
            font-size: 14px;
            border: none;
            border-radius: 6px;
            cursor: pointer;
            width: 200px;
            transition: background-color 0.3s ease, transform 0.3s ease;
        }

        button:hover {
            opacity: 0.9;
            transform: scale(1.02);
        }

        /* 添加条件按钮 */
        .add-condition-btn {
            background-color: #007bff;
            color: #fff;
        }

        .add-condition-btn:hover {
            background-color: #0056b3;
        }

        /* 删除条件按钮 */
        .remove-condition-btn {
            background-color: #dc3545;
            color: #fff;
        }

        .remove-condition-btn:hover {
            background-color: #c82333;
        }

        /* 条件行 */
        .condition-row {
            display: flex;
            align-items: center;
            justify-content: space-between;
            margin-bottom: 15px;
            padding: 15px;
            background-color: #f9f9f9;
            border: 1px solid #ddd;
            border-radius: 6px;
            box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
        }

        .condition-row select, 
        .condition-row input[type="text"] {
            margin-right: 10px;
            flex: 1;
        }

        /* 逻辑操作符选择 */
        .logical-operator {
            width: auto;
            margin: 0 10px;
        }

        /* 弹窗 */
        #codeModal {
            display: none;
            position: fixed;
            left: 50%;
            top: 50%;
            transform: translate(-50%, -50%);
            background-color: #ffffff;
            padding: 20px;
            border: 2px solid #333;
            border-radius: 10px;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
            z-index: 1000;
            width: 70%;
            max-width: 900px;
        }

        #codeModal h3 {
            margin-top: 0;
            color: #333;
            font-size: 18px;
        }

        #codeModal pre {
            white-space: pre-wrap;
            word-wrap: break-word;
            background-color: #f4f4f4;
            padding: 15px;
            border: 1px solid #ddd;
            border-radius: 6px;
            overflow-x: auto;
            max-height: 300px;
            overflow-y: auto;
        }

        #closeModal {
            margin-top: 15px;
            padding: 10px 20px;
            background-color: #dc3545;
            color: white;
            border: none;
            border-radius: 6px;
            cursor: pointer;
        }

        #closeModal:hover {
            background-color: #c82333;
        }

        /* 规则名称和描述对齐 */
        .form-group {
            display: flex;
            justify-content: space-between;
            gap: 10px;
            margin-bottom:10px;

        }
        #generateCode{

            background-color: #4CAF50;
        }

    </style>
</head>
<body>

<h2>Easy Rules 可视化配置界面</h2>

<!-- 表单部分 -->
<div class="rule-group">
    <form id="ruleForm">
        <div class="form-group">
            <div>
                <label for="name">规则名称:</label>
                <input type="text" id="name" placeholder="请输入规则名称">
            </div>
            <div>
                <label for="description">规则描述:</label>
                <input type="text" id="description" placeholder="请输入规则描述">
            </div>
        </div>

        <div id="conditions">
            <!-- 动态添加条件组 -->
            <div class="condition-row">
                <select class="field">
                    <option value="userRiskScore">用户风险评分</option>
                    <option value="transactionFrequency">交易频率</option>
                    <option value="averageTransactionAmount">平均交易金额</option>
                    <option value="recentTransactionAmount">最近交易金额</option>
                    <option value="transactionVolume">交易量</option>
                    <option value="accountAge">账户年龄</option>
                    <option value="deviceId">设备ID</option>
                    <option value="loginFrequency">登录频率</option>
                    <option value="suspiciousActivity">可疑活动</option>
                    <option value="transactionLocation">交易地点</option>
                </select>

                <select class="operator">
                    <option value="==">等于 (==)</option>
                    <option value="!=">不等于 (!=)</option>
                    <option value=">">大于 (>)</option>
                    <option value="<">小于 (<)</option>
                    <option value=">=">大于等于 (>=)</option>
                    <option value="<=">小于等于 (<=)</option>
                </select>

                <input type="text" class="value" placeholder="请输入条件值">
                <select class="logical-operator">
                    <option value="&&">AND</option>
                    <option value="||">OR</option>
                </select>
                <button type="button" class="add-condition-btn">添加条件</button>
            </div>
        </div>

        <label for="action">动作 (e.g., "System.out.println('Take an umbrella!')"):</label>
        <textarea id="action" rows="4" placeholder="请输入Java动作代码"></textarea>

        <button type="button" id="generateCode">生成代码</button>
    </form>
</div>

<!-- 弹窗部分 -->
<div id="codeModal">
    <h3>生成的 Java 规则代码:</h3>
    <pre id="generatedCode"></pre>
    <button id="closeModal">关闭</button>
</div>

<script>
    // 获取表单元素
    const nameInput = document.getElementById('name');
    const descriptionInput = document.getElementById('description');
    const conditionsDiv = document.getElementById('conditions');
    const actionInput = document.getElementById('action');

    // 获取按钮和弹窗相关元素
    const generateButton = document.getElementById('generateCode');
    const codeModal = document.getElementById('codeModal');
    const generatedCodePre = document.getElementById('generatedCode');
    const closeModalButton = document.getElementById('closeModal');

    // 添加
    // 添加条件按钮功能
    conditionsDiv.addEventListener('click', function (e) {
        if (e.target.classList.contains('add-condition-btn')) {
            // 创建新的条件行
            const conditionRow = document.createElement('div');
            conditionRow.classList.add('condition-row');
            conditionRow.innerHTML = `
                <select class="field">
                    <option value="userRiskScore">用户风险评分</option>
                    <option value="transactionFrequency">交易频率</option>
                    <option value="averageTransactionAmount">平均交易金额</option>
                    <option value="recentTransactionAmount">最近交易金额</option>
                    <option value="transactionVolume">交易量</option>
                    <option value="accountAge">账户年龄</option>
                    <option value="deviceId">设备ID</option>
                    <option value="loginFrequency">登录频率</option>
                    <option value="suspiciousActivity">可疑活动</option>
                    <option value="transactionLocation">交易地点</option>
                </select>

                <select class="operator">
                    <option value="==">等于 (==)</option>
                    <option value="!=">不等于 (!=)</option>
                    <option value=">">大于 (>)</option>
                    <option value="<">小于 (<)</option>
                    <option value=">=">大于等于 (>=)</option>
                    <option value="<=">小于等于 (<=)</option>
                </select>

                <input type="text" class="value" placeholder="请输入条件值">
                <select class="logical-operator">
                    <option value="&&">AND</option>
                    <option value="||">OR</option>
                </select>
                <button type="button" class="remove-condition-btn">删除条件</button>
            `;
            conditionsDiv.appendChild(conditionRow);
        }

        // 删除条件按钮功能
        if (e.target.classList.contains('remove-condition-btn')) {
            e.target.parentElement.remove();
        }
    });

    // 点击生成按钮时生成代码并显示弹窗
    generateButton.addEventListener('click', function () {
        const ruleName = nameInput.value;
        const ruleDescription = descriptionInput.value;
        const ruleAction = actionInput.value;

        // 获取所有条件
        const conditionRows = document.querySelectorAll('.condition-row');
        let conditions = [];
        conditionRows.forEach((row, index) => {
            const field = row.querySelector('.field').value;
            const operator = row.querySelector('.operator').value;
            const value = row.querySelector('.value').value;
            const logicalOperator = index < conditionRows.length - 1 ? row.querySelector('.logical-operator').value : '';
            conditions.push(`${field} ${operator} ${value} ${logicalOperator}`);
        });

        // 将条件用逻辑操作符连接起来
        const conditionExpression = conditions.join(' ').trim();

        // 生成规则的 Java 代码
        const generatedCode = `
@Rule(name = "${ruleName}", description = "${ruleDescription}")
public class GeneratedRule {

    @Condition
    public boolean evaluate(@Fact("fact") Object fact) {
        return ${conditionExpression};
    }

    @Action
    public void execute() {
        ${ruleAction};
    }
}
`;

        // 将生成的代码放入弹窗
        generatedCodePre.textContent = generatedCode;

        // 显示弹窗
        codeModal.style.display = 'block';
    });

    // 关闭弹窗
    closeModalButton.addEventListener('click', function () {
        codeModal.style.display = 'none';
    });

</script>


</body>
</html>

后来又让AI给我生成了Vue.js版本的界面,如下所示:

代码如下所示:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Easy Rules 可视化配置</title>
    <!-- 引入样式 -->
    <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
    <!-- import Vue before Element -->
    <script src="https://unpkg.com/vue@2/dist/vue.js"></script>
    <!-- import JavaScript -->
    <script src="https://unpkg.com/element-ui/lib/index.js"></script>
    <style>
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            margin: 0;
            padding: 0;
            background-color: #f0f0f0;
        }

        h2 {
            color: #333;
            font-size: 24px;
            margin-bottom: 20px;
            text-align: center;
        }

        .rule-group {
            max-width: 1200px;
            margin: 0 auto;
            background-color: #ffffff;
            padding: 20px;
            border-radius: 10px;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
        }

        .condition-row {
            display: flex;
            align-items: center;
            margin-bottom: 15px;
            padding: 15px;
            background-color: #f9f9f9;
            border: 1px solid #ddd;
            border-radius: 6px;
            box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
            gap: 10px;
        }

        .condition-row > * {
            flex: 1;
            min-width: 0;
        }

        .condition-row el-select,
        .condition-row el-input {
            margin-right: 10px;
        }

        .dialog-footer {
            text-align: right;
        }

        .add-button {
            margin-bottom: 20px;
        }
    </style>
</head>
<body>

<div id="app" class="rule-group">
    <h2>Easy Rules 可视化配置界面</h2>

    <el-form :model="form" label-width="120px">
        <el-form-item label="规则名称">
            <el-input v-model="form.name" placeholder="请输入规则名称"></el-input>
        </el-form-item>
        <el-form-item label="规则描述">
            <el-input v-model="form.description" placeholder="请输入规则描述"></el-input>
        </el-form-item>

        <el-form-item label="添加选择">
           <div v-for="(condition, index) in conditions" :key="index" class="condition-row">
            <el-select v-model="condition.field" placeholder="选择字段">
                <el-option v-for="option in fieldOptions" :key="option.value" :label="option.label" :value="option.value"></el-option>
            </el-select>

            <el-select v-model="condition.operator" placeholder="选择操作符">
                <el-option v-for="option in operatorOptions" :key="option.value" :label="option.label" :value="option.value"></el-option>
            </el-select>

            <el-input v-model="condition.value" placeholder="请输入条件值" style="width: 200px;"></el-input>

            <el-select v-model="condition.logicalOperator" placeholder="选择逻辑操作符" v-if="index < conditions.length - 1">
                <el-option v-for="option in logicalOperatorOptions" :key="option.value" :label="option.label" :value="option.value"></el-option>
            </el-select>

            <el-button @click="removeCondition(index)" type="danger">删除条件</el-button>
        </div>


        </el-form-item>


       
      

        <el-form-item label="动作">
            <el-input type="textarea" v-model="form.action" placeholder="请输入Java动作代码" rows="4"></el-input>
        </el-form-item>

        <el-form-item>
            <el-button @click="generateCode" type="success">生成代码</el-button>
              <el-button @click="addCondition" class="add-button" type="primary">添加条件</el-button>
        </el-form-item>
    </el-form>

    <el-dialog title="生成的 Java 规则代码" :visible.sync="showModal" width="70%">
        <pre>{{ generatedCode }}</pre>
        <span slot="footer" class="dialog-footer">
            <el-button @click="showModal = false">关闭</el-button>
        </span>
    </el-dialog>
</div>

<script>
    new Vue({
        el: '#app',
        data() {
            return {
                form: {
                    name: '',
                    description: '',
                    action: ''
                },
                conditions: [
                    { field: '', operator: '', value: '', logicalOperator: '' }
                ],
                showModal: false,
                generatedCode: '',
                fieldOptions: [
                    { value: 'userRiskScore', label: '用户风险评分' },
                    { value: 'transactionFrequency', label: '交易频率' },
                    { value: 'averageTransactionAmount', label: '平均交易金额' },
                    { value: 'recentTransactionAmount', label: '最近交易金额' },
                    { value: 'transactionVolume', label: '交易量' },
                    { value: 'accountAge', label: '账户年龄' },
                    { value: 'deviceId', label: '设备ID' },
                    { value: 'loginFrequency', label: '登录频率' },
                    { value: 'suspiciousActivity', label: '可疑活动' },
                    { value: 'transactionLocation', label: '交易地点' }
                ],
                operatorOptions: [
                    { value: '==', label: '等于 (==)' },
                    { value: '!=', label: '不等于 (!=)' },
                    { value: '>', label: '大于 (>)' },
                    { value: '<', label: '小于 (<)' },
                    { value: '>=', label: '大于等于 (>=)' },
                    { value: '<=', label: '小于等于 (<=)' }
                ],
                logicalOperatorOptions: [
                    { value: '&&', label: 'AND' },
                    { value: '||', label: 'OR' }
                ]
            };
        },
        methods: {
            addCondition() {
                this.conditions.push({ field: '', operator: '', value: '', logicalOperator: '' });
            },
            removeCondition(index) {
                this.conditions.splice(index, 1);
            },
            generateCode() {
                const conditions = this.conditions.map((condition, index) => {
                    const logicalOperator = index < this.conditions.length - 1 ? condition.logicalOperator : '';
                    return `${condition.field} ${condition.operator} ${condition.value} ${logicalOperator}`;
                }).join(' ').trim();

                this.generatedCode = `
@Rule(name = "${this.form.name}", description = "${this.form.description}")
public class GeneratedRule {

    @Condition
    public boolean evaluate(@Fact("fact") Object fact) {
        return ${conditions};
    }

    @Action
    public void execute() {
        ${this.form.action};
    }
}
                `;

                this.showModal = true;
            }
        }
    });
</script>

</body>
</html>

通过这个界面也是想让学习规则引擎的小伙伴理解下规则引擎。

欢迎和我一起沟通交流。