|
| 1 | +# 标题表达式交互式UI设计 |
| 2 | + |
| 3 | +## 1. 需求概述 |
| 4 | + |
| 5 | +将节点标题表达式的配置从"直接编写Groovy脚本"改为"交互式可视化配置",同时保留高级用户直接编写脚本的能力。 |
| 6 | + |
| 7 | +### 核心功能 |
| 8 | +- 文字内容用户直接输入 |
| 9 | +- 变量(request属性)通过选择方式插入 |
| 10 | +- 复杂场景可开启"高级配置"直接编辑Groovy脚本 |
| 11 | +- 支持重置配置回到初始状态 |
| 12 | + |
| 13 | +### 设计原则 |
| 14 | +- **所有标题本质都是Groovy脚本**,只是提供不同的配置方式 |
| 15 | +- **普通模式**:通过UI交互选择变量插入 |
| 16 | +- **高级模式**:直接编写Groovy代码 |
| 17 | +- 高级模式下无法解析回可视化,预览区域显示提示 |
| 18 | +- 通过固定注释区分标题配置 |
| 19 | + |
| 20 | +--- |
| 21 | + |
| 22 | +## 2. request对象设计 |
| 23 | + |
| 24 | +### 2.1 Java对象结构 |
| 25 | + |
| 26 | +统一提供 `TitleGroovyRequest` 对象给所有Groovy脚本使用: |
| 27 | + |
| 28 | +```java |
| 29 | +public class TitleGroovyRequest { |
| 30 | + // 操作人信息 |
| 31 | + private String operatorName; // 当前操作人姓名 |
| 32 | + private Integer operatorId; // 当前操作人ID |
| 33 | + private Boolean isFlowManager; // 是否流程管理员 |
| 34 | + |
| 35 | + // 流程信息 |
| 36 | + private String workflowTitle; // 流程标题 |
| 37 | + private String workflowCode; // 流程编码 |
| 38 | + |
| 39 | + // 节点信息 |
| 40 | + private String nodeName; // 当前节点名称 |
| 41 | + private String nodeType; // 当前节点类型 |
| 42 | + |
| 43 | + // 创建人信息 |
| 44 | + private String creatorName; // 流程创建人姓名 |
| 45 | + |
| 46 | + // 表单数据 |
| 47 | + private Map<String, Object> formData; // 表单字段值 |
| 48 | + |
| 49 | + // 流程编号 |
| 50 | + private String workCode; // 流程编号 |
| 51 | + |
| 52 | + // Getters |
| 53 | + public String getOperatorName(); |
| 54 | + public Integer getOperatorId(); |
| 55 | + public Boolean getIsFlowManager(); |
| 56 | + public String getWorkflowTitle(); |
| 57 | + public String getWorkflowCode(); |
| 58 | + public String getNodeName(); |
| 59 | + public String getNodeType(); |
| 60 | + public String getCreatorName(); |
| 61 | + public Object getFormData(String key); |
| 62 | + public String getWorkCode(); |
| 63 | +} |
| 64 | +``` |
| 65 | + |
| 66 | +### 2.2 可用变量列表 |
| 67 | + |
| 68 | +| 变量路径 | 说明 | 示例 | |
| 69 | +|---------|------|------| |
| 70 | +| `request.operatorName` | 当前操作人姓名 | "张三" | |
| 71 | +| `request.operatorId` | 当前操作人ID | 1001 | |
| 72 | +| `request.isFlowManager` | 是否流程管理员 | true/false | |
| 73 | +| `request.workflowTitle` | 流程标题 | "请假审批" | |
| 74 | +| `request.workflowCode` | 流程编码 | "LEAVE_001" | |
| 75 | +| `request.nodeName` | 当前节点名称 | "部门审批" | |
| 76 | +| `request.nodeType` | 当前节点类型 | "approval" | |
| 77 | +| `request.creatorName` | 流程创建人 | "李四" | |
| 78 | +| `request.formData("字段名")` | 表单字段值 | 任意 | |
| 79 | +| `request.workCode` | 流程编号 | "WORK_20260226" | |
| 80 | + |
| 81 | +--- |
| 82 | + |
| 83 | +## 3. 语法规范 |
| 84 | + |
| 85 | +### 3.1 用户界面显示语法(预览/输入) |
| 86 | + |
| 87 | +使用 `${}` 包裹变量: |
| 88 | + |
| 89 | +``` |
| 90 | +${request.operatorName} |
| 91 | +${request.formData("amount")} |
| 92 | +${request.workflowTitle} |
| 93 | +``` |
| 94 | + |
| 95 | +**完整示例:** |
| 96 | +``` |
| 97 | +你好,${request.operatorName},有一笔 ${request.formData("amount")} 元的审批 |
| 98 | +``` |
| 99 | + |
| 100 | +### 3.2 实际Groovy脚本语法 |
| 101 | + |
| 102 | +```groovy |
| 103 | +return "你好," + request.getOperatorName() + ",有一笔 " + request.getFormData("amount") + " 元的审批" |
| 104 | +``` |
| 105 | + |
| 106 | +### 3.3 语法转换规则 |
| 107 | + |
| 108 | +| 界面语法 | Groovy语法 | |
| 109 | +|---------|-----------| |
| 110 | +| `${request.operatorName}` | `request.getOperatorName()` | |
| 111 | +| `${request.formData("key")}` | `request.getFormData("key")` | |
| 112 | +| `${request.workflowTitle}` | `request.getWorkflowTitle()` | |
| 113 | + |
| 114 | +### 3.4 通过注释区分标题配置 |
| 115 | + |
| 116 | +在Groovy脚本中添加固定注释来标识这是标题配置: |
| 117 | + |
| 118 | +```groovy |
| 119 | +// @TITLE |
| 120 | +return "审批:" + request.getOperatorName() |
| 121 | +``` |
| 122 | + |
| 123 | +系统通过检测 `// @TITLE` 注释来识别标题表达式配置。 |
| 124 | + |
| 125 | +--- |
| 126 | + |
| 127 | +## 4. 界面设计 |
| 128 | + |
| 129 | +### 4.1 界面清单 |
| 130 | + |
| 131 | +| 界面 | 用途 | 位置 | |
| 132 | +|------|------|------| |
| 133 | +| 节点属性面板 | 展示标题内容 + 编辑按钮 | 节点属性面板中 | |
| 134 | +| 标题配置面板 | 点击编辑后的配置界面 | 弹框 | |
| 135 | +| 变量选择器 | 插入request变量 | 弹框 | |
| 136 | +| 高级配置 | Groovy代码编辑 | 弹框 | |
| 137 | + |
| 138 | +### 4.2 节点属性面板 |
| 139 | + |
| 140 | +``` |
| 141 | +┌─────────────────────────────────────┐ |
| 142 | +│ 节点标题 │ |
| 143 | +├─────────────────────────────────────┤ |
| 144 | +│ 当前:部门经理审批 [编辑] │ |
| 145 | +└─────────────────────────────────────┘ |
| 146 | +``` |
| 147 | + |
| 148 | +- 展示当前配置的标题内容 |
| 149 | +- 点击"编辑"按钮进入标题配置面板 |
| 150 | + |
| 151 | +### 4.3 标题配置面板 |
| 152 | + |
| 153 | +#### 普通模式 |
| 154 | +``` |
| 155 | +┌─────────────────────────────────────────────────────────┐ |
| 156 | +│ 标题配置 │ |
| 157 | +├─────────────────────────────────────────────────────────┤ |
| 158 | +│ 预览 │ |
| 159 | +│ 你好,${request.operatorName},有一笔${request.formData("amount")}元的审批 |
| 160 | +│ ───────────────────────────────────────────────────── │ |
| 161 | +│ [插入变量] [高级配置] │ |
| 162 | +│ ───────────────────────────────────────────────────── │ |
| 163 | +│ 内容 │ |
| 164 | +│ ┌─────────────────────────────────────────────────────┐│ |
| 165 | +│ │ 你好,${request.operatorName},有一笔${request.formData("amount")}元的审批 |
| 166 | +│ └─────────────────────────────────────────────────────┘│ |
| 167 | +│ 使用 ${request.xxx} 插入变量,点击上方按钮插入 │ |
| 168 | +│ ───────────────────────────────────────────────────── │ |
| 169 | +│ [取消] [确定] │ |
| 170 | +└─────────────────────────────────────────────────────────┘ |
| 171 | +``` |
| 172 | + |
| 173 | +#### 高级模式 |
| 174 | +``` |
| 175 | +┌─────────────────────────────────────────────────────────┐ |
| 176 | +│ 标题配置 │ |
| 177 | +├─────────────────────────────────────────────────────────┤ |
| 178 | +│ 预览 │ |
| 179 | +│ ⚠ 用户自定义配置,无法预览 │ |
| 180 | +│ ───────────────────────────────────────────────────── │ |
| 181 | +│ [重置] [高级配置] │ |
| 182 | +│ ───────────────────────────────────────────────────── │ |
| 183 | +│ 内容 │ |
| 184 | +│ ┌─────────────────────────────────────────────────────┐│ |
| 185 | +│ │ // @TITLE ││ |
| 186 | +│ │ return "审批:" + request.getOperatorName() ││ |
| 187 | +│ └─────────────────────────────────────────────────────┘│ |
| 188 | +│ ───────────────────────────────────────────────────── │ |
| 189 | +│ [取消] [确定] │ |
| 190 | +└─────────────────────────────────────────────────────────┘ |
| 191 | +``` |
| 192 | + |
| 193 | +**关键设计说明:** |
| 194 | +- 高级模式下预览区域显示"⚠ 用户自定义配置,无法预览"提示 |
| 195 | +- 高级模式下"高级配置"按钮变为"重置"按钮 |
| 196 | +- 点击"重置"可清除高级配置,回到普通模式 |
| 197 | + |
| 198 | +### 4.4 变量选择器(弹框) |
| 199 | + |
| 200 | +``` |
| 201 | +┌─────────────────────────────┐ |
| 202 | +│ 选择变量 │ |
| 203 | +├─────────────────────────────┤ |
| 204 | +│ ┌─────────────────────────┐│ |
| 205 | +│ │ 🔍 搜索变量... ││ |
| 206 | +│ └─────────────────────────┘│ |
| 207 | +│ ▶ 操作人相关 │ |
| 208 | +│ ● request.operatorName - 当前操作人姓名 |
| 209 | +│ ● request.operatorId - 当前操作人ID |
| 210 | +│ ● request.creatorName - 流程创建人 |
| 211 | +│ |
| 212 | +│ ▶ 流程相关 │ |
| 213 | +│ ● request.workflowTitle - 流程标题 |
| 214 | +│ ● request.workflowCode - 流程编码 |
| 215 | +│ ● request.nodeName - 当前节点名称 |
| 216 | +│ ● request.nodeType - 当前节点类型 |
| 217 | +│ |
| 218 | +│ ▶ 表单函数 │ |
| 219 | +│ ● request.formData("key") - 获取表单字段值 |
| 220 | +│ |
| 221 | +│ ▶ 流程编号 │ |
| 222 | +│ ● request.workCode - 流程编号 |
| 223 | +└─────────────────────────────┘ |
| 224 | +``` |
| 225 | + |
| 226 | +--- |
| 227 | + |
| 228 | +## 5. 实现方案 |
| 229 | + |
| 230 | +### 5.1 涉及文件 |
| 231 | + |
| 232 | +**后端(Java):** |
| 233 | +- 创建 `TitleRequest` 对象封装所需数据 |
| 234 | + |
| 235 | +**前端(frontend):** |
| 236 | +- `packages/flow-pc/flow-pc-design/src/components/design-editor/node-components/strategy/node-title.tsx` - 修改现有组件 |
| 237 | +- 新增 `VariablePicker.tsx` - 变量选择器 |
| 238 | + |
| 239 | +### 5.2 核心逻辑 |
| 240 | + |
| 241 | +1. **界面显示**:使用 `${request.xxx}` 语法显示和输入 |
| 242 | +2. **保存转换**:将 `${request.xxx}` 转换为 `request.getXxx()` 或 `request.getFormData("xxx")` |
| 243 | +3. **加载识别**:通过 `// @TITLE` 注释识别标题配置 |
| 244 | +4. **预览**:直接替换 `${request.xxx}` 为实际值(在有数据时) |
| 245 | + |
| 246 | +--- |
| 247 | + |
| 248 | +## 6. 设计文件位置 |
| 249 | + |
| 250 | +`designs/title-expression-ui/` |
0 commit comments