1212
1313### 设计原则
1414- ** 所有标题本质都是Groovy脚本** ,只是提供不同的配置方式
15- - ** 普通模式** :通过UI交互选择变量插入
15+ - ** 普通模式** :通过UI交互选择变量插入,显示中文格式
1616- ** 高级模式** :直接编写Groovy代码
1717- 高级模式下无法解析回可视化,预览区域显示提示
1818- 通过固定注释区分标题配置
@@ -63,55 +63,90 @@ public class TitleGroovyRequest {
6363}
6464```
6565
66- ### 2.2 可用变量列表
66+ ---
67+
68+ ## 3. 变量映射类设计(核心)
69+
70+ ### 3.1 映射类结构
71+
72+ 创建 ` GroovyVariableMapping ` 映射类,统一处理变量显示和转换(作为公共对象使用):
73+
74+ ``` java
75+ public class GroovyVariableMapping {
76+ private String label; // 中文显示名称:如"当前操作人"
77+ private String value; // 变量展示名:如"request.operatorName"
78+ private String expression; // 用户界面表达式:如"request.getOperatorName()"
79+ private String tag; // 分组,例如表单、流程、操作人等
80+ private int order; // 展示的数据顺序
81+ }
82+ ```
83+
84+ ### 3.2 预定义变量映射
85+
86+ | label(中文显示) | value(变量名) | expression(Groovy语法) | tag(分组) |
87+ | -----------------| ---------------| ----------------------| ----------|
88+ | 当前操作人 | request.operatorName | request.getOperatorName() | 操作人相关 |
89+ | 当前操作人ID | request.operatorId | request.getOperatorId() | 操作人相关 |
90+ | 是否管理员 | request.isFlowManager | request.getIsFlowManager() | 操作人相关 |
91+ | 流程创建人 | request.creatorName | request.getCreatorName() | 操作人相关 |
92+ | 流程标题 | request.workflowTitle | request.getWorkflowTitle() | 流程相关 |
93+ | 流程编码 | request.workflowCode | request.getWorkflowCode() | 流程相关 |
94+ | 当前节点 | request.nodeName | request.getNodeName() | 流程相关 |
95+ | 节点类型 | request.nodeType | request.getNodeType() | 流程相关 |
96+ | 流程编号 | request.workCode | request.getWorkCode() | 流程编号 |
6797
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" |
98+ ### 3.3 表单字段映射
99+
100+ 表单字段需要动态从 ` FlowFromMeta.fields ` 获取:
101+
102+ ``` java
103+ // 从FlowFromMeta动态构建
104+ for (FlowFormFieldMeta field : flowFromMeta. getFields()) {
105+ GroovyVariableMapping mapping = new GroovyVariableMapping ();
106+ mapping. setLabel(field. getName()); // 如"请假天数"
107+ mapping. setValue(" request.formData(\" " + field. getCode() + " \" )" ); // 如request.formData("days")
108+ mapping. setExpression(" request.getFormData(\" " + field. getCode() + " \" )" ); // 如request.getFormData("days")
109+ mapping. setTag(" 表单字段(当前表单)" );
110+ mapping. setOrder(100 + index);
111+ }
112+ ```
80113
81114---
82115
83- ## 3 . 语法规范
116+ ## 4 . 语法规范
84117
85- ### 3 .1 用户界面显示语法(预览/输入)
118+ ### 4 .1 用户界面显示语法
86119
87- 使用 ` ${} ` 包裹变量 :
120+ 在界面显示和编辑时, 使用 ` ${中文标签 } ` 格式 :
88121
89122```
90- ${request.operatorName }
91- ${request.formData("amount") }
92- ${request.workflowTitle }
123+ ${当前操作人 }
124+ ${请假天数 }
125+ ${流程标题 }
93126```
94127
95128** 完整示例:**
96129```
97- 你好,${request.operatorName },有一笔 ${request.formData("amount")} 元的审批
130+ 你好,${当前操作人 },有一笔${请假天数} 元的审批
98131```
99132
100- ### 3 .2 实际Groovy脚本语法
133+ ### 4 .2 实际Groovy脚本语法
101134
102135``` groovy
103- return "你好," + request.getOperatorName() + ",有一笔 " + request.getFormData("amount ") + " 元的审批"
136+ return "你好," + request.getOperatorName() + ",有一笔 " + request.getFormData("days ") + " 元的审批"
104137```
105138
106- ### 3 .3 语法转换规则
139+ ### 4 .3 语法转换规则
107140
108- | 界面语法 | Groovy语法 |
109- | ---------| -----------|
110- | ` ${request.operatorName} ` | ` request.getOperatorName() ` |
111- | ` ${request.formData("key")} ` | ` request.getFormData("key") ` |
112- | ` ${request.workflowTitle} ` | ` request.getWorkflowTitle() ` |
141+ 通过 GroovyVariableMapping 映射类进行转换:
113142
114- ### 3.4 通过注释区分标题配置
143+ | label(界面显示) | value(变量名) | expression(Groovy语法) |
144+ | -----------------| ---------------| ----------------------|
145+ | 当前操作人 | request.operatorName | request.getOperatorName() |
146+ | 请假天数 | request.formData("days") | request.getFormData("days") |
147+ | 流程标题 | request.workflowTitle | request.getWorkflowTitle() |
148+
149+ ### 4.4 通过注释区分标题配置
115150
116151在Groovy脚本中添加固定注释来标识这是标题配置:
117152
@@ -124,47 +159,47 @@ return "审批:" + request.getOperatorName()
124159
125160---
126161
127- ## 4 . 界面设计
162+ ## 5 . 界面设计
128163
129- ### 4 .1 界面清单
164+ ### 5 .1 界面清单
130165
131166| 界面 | 用途 | 位置 |
132167| ------| ------| ------|
133168| 节点属性面板 | 展示标题内容 + 编辑按钮 | 节点属性面板中 |
134169| 标题配置面板 | 点击编辑后的配置界面 | 弹框 |
135- | 变量选择器 | 插入request变量 | 弹框 |
170+ | 变量选择器 | 插入变量(使用映射类数据) | 弹框 |
136171| 高级配置 | Groovy代码编辑 | 弹框 |
137172
138- ### 4 .2 节点属性面板
173+ ### 5 .2 节点属性面板
139174
140175```
141176┌─────────────────────────────────────┐
142177│ 节点标题 │
143178├─────────────────────────────────────┤
144- │ 当前:部门经理审批 [编辑] │
179+ │ ${当前操作人}的审批 [编辑] │
145180└─────────────────────────────────────┘
146181```
147182
148- - 展示当前配置的标题内容
183+ - 展示当前配置的标题内容(使用 ` ${label} ` 格式)
149184- 点击"编辑"按钮进入标题配置面板
150185
151- ### 4 .3 标题配置面板
186+ ### 5 .3 标题配置面板
152187
153188#### 普通模式
154189```
155190┌─────────────────────────────────────────────────────────┐
156191│ 标题配置 │
157192├─────────────────────────────────────────────────────────┤
158193│ 预览 │
159- │ 你好,${request.operatorName },有一笔${request.formData("amount") }元的审批
194+ │ 你好,${当前操作人 },有一笔${请假天数 }元的审批
160195│ ───────────────────────────────────────────────────── │
161196│ [插入变量] [高级配置] │
162197│ ───────────────────────────────────────────────────── │
163198│ 内容 │
164199│ ┌─────────────────────────────────────────────────────┐│
165- │ │ 你好,${request.operatorName },有一笔${request.formData("amount") }元的审批
200+ │ │ 你好,${当前操作人 },有一笔${请假天数 }元的审批 ││
166201│ └─────────────────────────────────────────────────────┘│
167- │ 使用 ${request.xxx} 插入变量,点击上方按钮插入 │
202+ │ 点击上方按钮插入变量,或直接输入文字内容 │
168203│ ───────────────────────────────────────────────────── │
169204│ [取消] [确定] │
170205└─────────────────────────────────────────────────────────┘
@@ -195,7 +230,7 @@ return "审批:" + request.getOperatorName()
195230- 高级模式下"高级配置"按钮变为"重置"按钮
196231- 点击"重置"可清除高级配置,回到普通模式
197232
198- ### 4 .4 变量选择器(弹框)
233+ ### 5 .4 变量选择器(弹框)
199234
200235```
201236┌─────────────────────────────┐
@@ -205,46 +240,153 @@ return "审批:" + request.getOperatorName()
205240│ │ 🔍 搜索变量... ││
206241│ └─────────────────────────┘│
207242│ ▶ 操作人相关 │
208- │ ● request.operatorName - 当前操作人姓名
209- │ ● request.operatorId - 当前操作人ID
210- │ ● request.creatorName - 流程创建人
243+ │ ● 当前操作人姓名 request.operatorName
244+ │ ● 当前操作人ID request.operatorId
245+ │ ● 是否管理员 request.isFlowManager
246+ │ ● 流程创建人 request.creatorName
211247│
212248│ ▶ 流程相关 │
213- │ ● request.workflowTitle - 流程标题
214- │ ● request.workflowCode - 流程编码
215- │ ● request.nodeName - 当前节点名称
216- │ ● request.nodeType - 当前节点类型
249+ │ ● 流程标题 request.workflowTitle
250+ │ ● 流程编码 request.workflowCode
251+ │ ● 当前节点 request.nodeName
252+ │ ● 节点类型 request.nodeType
217253│
218- │ ▶ 表单函数 │
219- │ ● request.formData("key") - 获取表单字段值
254+ │ ▶ 表单字段(当前表单) │
255+ │ ● 请假天数 request.formData("days")
256+ │ ● 请假原因 request.formData("reason")
257+ │ ● 审批金额 request.formData("amount")
258+ │ ● 更多字段... 动态加载当前表单字段
220259│
221260│ ▶ 流程编号 │
222- │ ● request.workCode - 流程编号
261+ │ ● 流程编号 request.workCode
223262└─────────────────────────────┘
224263```
225264
265+ ** 显示规则:**
266+ - 左侧:label(中文显示名称),如"当前操作人姓名"
267+ - 右侧:value(变量名),如"request.operatorName"
268+
226269---
227270
228- ## 5 . 实现方案
271+ ## 6 . 实现方案
229272
230- ### 5 .1 涉及文件
273+ ### 6 .1 涉及文件
231274
232275** 后端(Java):**
233- - 创建 ` TitleRequest ` 对象封装所需数据
276+ - 创建 ` TitleGroovyRequest ` 对象封装所需数据
277+ - 创建 ` TitleVariableMapping ` 映射类(用于变量选择和语法转换)
278+
279+ ** 前端(TypeScript):**
280+ - 修改 ` node-title.tsx ` - 节点标题组件
281+ - 新增 ` VariablePicker.tsx ` - 变量选择器组件
282+
283+ ### 6.2 核心逻辑
234284
235- ** 前端(frontend):**
236- - ` packages/flow-pc/flow-pc-design/src/components/design-editor/node-components/strategy/node-title.tsx ` - 修改现有组件
237- - 新增 ` VariablePicker.tsx ` - 变量选择器
285+ #### 6.2.1 变量映射服务
238286
239- ### 5.2 核心逻辑
287+ ``` typescript
288+ // 前端:GroovyVariableMapping 公共对象
289+ interface GroovyVariableMapping {
290+ label: string ; // 中文显示名称:如"当前操作人"
291+ value: string ; // 变量展示名:如"request.operatorName"
292+ expression: string ; // 用户界面表达式:如"request.getOperatorName()"
293+ tag: string ; // 分组:如"操作人相关"
294+ order: number ; // 排序
295+ }
296+
297+ // 预定义变量映射
298+ const VARIABLE_MAPPINGS: GroovyVariableMapping [] = [
299+ { label: ' 当前操作人' , value: ' request.operatorName' , expression: ' request.getOperatorName()' , tag: ' 操作人相关' , order: 1 },
300+ { label: ' 当前操作人ID' , value: ' request.operatorId' , expression: ' request.getOperatorId()' , tag: ' 操作人相关' , order: 2 },
301+ // ...其他预定义变量
302+ ];
303+
304+ // 获取表单字段映射(动态)
305+ function getFormFieldMappings(fields : FlowFormFieldMeta []): GroovyVariableMapping [] {
306+ return fields .map ((field , index ) => ({
307+ label: field .name ,
308+ value: ' request.formData("' + field .code + ' ")' ,
309+ expression: ' request.getFormData("' + field .code + ' ")' ,
310+ tag: ' 表单字段(当前表单)' ,
311+ order: 100 + index
312+ }));
313+ }
314+ ```
315+
316+ #### 6.2.2 界面显示 → Groovy语法转换
317+
318+ ``` typescript
319+ function toGroovySyntax(content : string , mappings : GroovyVariableMapping []): string {
320+ let result = content ;
321+ for (const mapping of mappings ) {
322+ // 将界面显示的label替换为Groovy expression
323+ result = result .split (mapping .label ).join (' ${' + mapping .expression + ' }' );
324+ }
325+ // 添加 @TITLE 注释,并转换为Groovy字符串拼接
326+ return ' // @TITLE\n return "' + result + ' "' ;
327+ }
328+ ```
329+
330+ #### 6.2.3 Groovy语法 → 界面显示转换
331+
332+ ``` typescript
333+ function toLabelExpression(groovyCode : string , mappings : GroovyVariableMapping []): string {
334+ let result = groovyCode ;
335+ // 移除 return " 和 "
336+ result = result .replace (/ ^ . * return\s + "([^ "] * )". * $ / , ' $1' );
337+ // 替换 + 拼接为直接量
338+ result = result .replace (/ "\s * \+ \s * "/ g , ' ' );
339+ // 将 ${expression} 替换为 label
340+ for (const mapping of mappings ) {
341+ result = result .replaceAll (' ${' + mapping .expression + ' }' , mapping .label );
342+ }
343+ return result ;
344+ }
345+ ```
240346
241- 1 . ** 界面显示** :使用 ` ${request.xxx} ` 语法显示和输入
242- 2 . ** 保存转换** :将 ` ${request.xxx} ` 转换为 ` request.getXxx() ` 或 ` request.getFormData("xxx") `
243- 3 . ** 加载识别** :通过 ` // @TITLE ` 注释识别标题配置
244- 4 . ** 预览** :直接替换 ` ${request.xxx} ` 为实际值(在有数据时)
347+ #### 6.2.4 变量选择器数据源
348+
349+ ``` typescript
350+ // 合并预定义变量 + 动态表单字段
351+ function getVariablePickerData(flowFromMeta ? : FlowFromMeta ): GroovyVariableMapping [] {
352+ const variables = [... VARIABLE_MAPPINGS ];
353+
354+ // 添加表单字段(如果有)
355+ if (flowFromMeta ?.fields ) {
356+ variables .push (... getFormFieldMappings (flowFromMeta .fields ));
357+ }
358+
359+ // 按tag和order排序
360+ return variables .sort ((a , b ) => {
361+ if (a .tag !== b .tag ) return a .tag .localeCompare (b .tag );
362+ return a .order - b .order ;
363+ });
364+ }
365+ ```
366+
367+ ### 6.3 数据流
368+
369+ ```
370+ ┌─────────────────┐ ┌──────────────────────┐ ┌─────────────────┐
371+ │ 用户界面输入 │────▶│ GroovyVariableMapping │────▶│ Groovy脚本 │
372+ │ 当前操作人 │ │ 映射类 │ │ request.getXxx()│
373+ └─────────────────┘ └──────────────────────┘ └─────────────────┘
374+ │
375+ ▼
376+ ┌──────────────────┐
377+ │ 变量选择器 │
378+ │ 数据源 │
379+ └──────────────────┘
380+ │
381+ ▼
382+ ┌──────────────────┐
383+ │ FlowFromMeta │
384+ │ 动态获取字段 │
385+ └──────────────────┘
386+ ```
245387
246388---
247389
248- ## 6 . 设计文件位置
390+ ## 7 . 设计文件位置
249391
250392` designs/title-expression-ui/ `
0 commit comments