Appearance
培训视频
1. 何为效能
即风险防控。
基于流程与业务运转,用于监控当前业务流程是否有在时间期限内进行工作。
会给需要监控的流程设定预警或超期时间,若办理时间触及设定时间,则给用户发送及时办理提醒。
场景还原:
2023-02-28给张三4个工作日,第2天提醒张三只剩2个工作日(功能预警计算且发短信提醒),第5天提醒张三已经超期(功能超期计算和发短信提醒超期),
张三请假但没人接手要求停止计算时间,也可能其他原因(功能暂缓),回来上班后(功能取消暂缓),以上是根据场景方便理解效能功能
2. 后台管理模块
2.1. 工作时间
配置字段说明:
开始时间:该工作时间方案开始执行日期
截止时间:该工作时间方案停止执行日期
上午/下午开始/结束时刻:这四项填写单位为分钟,每日从 0 点开始起算。
例如:上午开始时刻为 480,意为早上 8 点上班(8*60)。
工作时间总长 420,意为,一天的工作时间为 7 小时(7*60)
录入说明:
- 上午上班,下午请假:下午2个时刻都填写上午结束时刻,例如510,960,960,960
- 上午请假,下午上班:上午2个时刻都填写下午开始时刻,例如960,960,960,1050
- 总时长为0:工作时长为0,需到节假日配置去设置
2.2. 节假日配置
点击每个月右上角的【设置】按钮,可对每月的节假日日期进行配置与修改。
操作简单,不做赘述。
2.3. 效能方案配置
只有【是否接入效能】为是的流程会显示。
每个流程可以有很多种方案,但只有一个有效,即只有一个的【是否启动】为开启状态。
2.3.1. 表单配置
可对流程以及流程节点进行详细的效能配置。
- 预警时间、超期时间
配置单位为分钟。例如:预警时间2520
,意为预警天数为 6 天(60min * 7h * 6d
)
- 条件表达式
因为一个流程对应多个业务,不同的业务有可能需要走不同的效能。所以当同一流程的不同业务需要走不同的效能配置时,就需要用到条件表达式。
条件表达式的编写使用规则,请看 【4. 表达式】 项。
2.4. 风险等级管理
主要为等级详细内容。
- 发送频率:消息提醒发送频率
第一次发送
检测到且符合预警条件就发送 --预警:>=预警时间 and <超期时间
检测到且符合超期条件就发送 --超期:>=超期
第二次发送 1. 若第一次是上午发送 --第二次下午及以后的第一个工作时间发送(例如,第一次的下午放假,那就下个工作日的早上,如果还放假,那就下个工作日的下午)
- 若第一次是下午 --第二次是下一个工作日的早上或下午(早上放假则就下午再发送)
风险等级:预警、超期、抄送
等级类型:这一项其实对应的是风险短信发送模板代码
效能提供给短信模板的字段信息配置方法为 ${ 字段名 }
,例:
字段名 | 注释 |
---|---|
realName | 用户真实姓名 |
bizName | 业务名称 |
flowName | 流程名称 |
nodeName | 环节名称 |
deadLine | 流程到期时间 |
nodeDeadLine | 环节到期时间 |
diffTimeCn | 剩余/超期时间 |
条件表达式单词:NOW_DATE系统当前时间,OVERDUE_DATE超期时间,WARNING_DATE预警时间
条件表达式:用于判断什么时候发送消息提醒。如果表达式为空,则默认一到时间节点就发送消息。
风险等级的条件表达式使用规则请看 【4. 表达式】 项。
例如:
0 < ':OVERDUE_DATE' - ':NOW_DATE' <= 1440
,表示超期一天之内的,消息提醒配置内容。
':OVERDUE_DATE' - ':NOW_DATE' > 1440
,表示为超期一天后,消息提醒的配置内容。
其中,1440
单位为分钟(60 * 24
),表示一天的时间。
当风险等级,等级类型一样的时,非空表达式与空表达式同时成立,这个时候只会按非空表达式发送,空表达式的不再发送,不然用户会同时收到多条一样的短信
2.5. 抄送人管理
配置入口在效能方案配置里配置,主要用于,风控消息提醒抄送人的配置。
可对每个流程和流程中的节点进行抄送人的配置。
当前只支持选择指定用户,暂不支持角色选择、部门选择。后续可优化。
2.6. 效能日志
效能操作日志。
不做赘述。
3. HTTP 调用接口
3.0. HTTP 请求代码示例
调用注意事项:
- 调用方式皆为
POST
ContentType
类型为application/json
- 参数以
json
字符串格式传入
请求代码示例:
java
/**
* 发送http请求
*
* @param url 请求地址
* @param param 请求参数
* @return 请求响应
* @throws Exception 抛出异常
*/
public static String httPost(String url, Object param) throws Exception {
return httpPostWithNoHandle(
url,
null,
null,
param,
ContentType.APPLICATION_JSON.getMimeType(),
ContentType.APPLICATION_JSON.getCharset().toString(),
false);
}
/**
* 不处理异常的http post 请求
*
* @param url 请求地址
* @param token token
* @param headers 请求头
* @param params 请求参数
* @param contentType contentType类型
* @param encoding contentEncoding类型
* @param isReturnEmpty 是否返回空值
* @return 返回结果
* @throws Exception 抛出异常
*/
public static String httpPostWithNoHandle(String url,
String token,
JSONObject headers,
Object params,
String contentType,
String encoding,
boolean isReturnEmpty) throws Exception {
HttpPost httpPost = new HttpPost(getUrl(url));
//如果 headers 不为空 循环遍历JSONObject,添加请求头
if (headers != null) {
for (String str : headers.keySet()) {
httpPost.addHeader(str, headers.get(str).toString());
}
}
//token
if (StringUtil.isNotEmpty(token)) {
httpPost.setHeader(Constants.AUTHORIZATION, token);
}
//创建http客户端
CloseableHttpClient client = HttpClients.createDefault();
if (params != null) {
/*params是需要序列化的对象*/
String s = JSONObject.toJSONString(params);
//使用二进制数据将序列化好的 gson数据转换成 二进制流
ByteArrayEntity byteArrayEntity = new ByteArrayEntity(s.getBytes(encoding));
byteArrayEntity.setContentEncoding(encoding);
byteArrayEntity.setContentType(contentType);
httpPost.setEntity(byteArrayEntity);
}
HttpResponse resp = client.execute(httpPost);
if (ActionResultCode.Success.getCode().equals(resp.getStatusLine().getStatusCode())) {
return EntityUtils.toString(resp.getEntity(), SystemConstant.UTF_8);
}
//返回响应回来的数据
return isReturnEmpty ? null : resp.toString();
}
3.1. 设置效能所需数据
接口:
http://xxx:xxx/api/efficacy/setBizParam
类型:post
入参:
json
{
"bizType": "业务类型",
"bizId": "业务id",
"bizName": "业务名称",
"flowTaskId": "流程任务id",
"paramJson": "参数JSON,以key-value形式存储"
}
入参示例:
json
{
"bizType": "0101",
"bizId": "24eea52ee5wf48b4a957dadf19af8b48",
"bizName": "海籍调查成果确认测试类型",
"flowTaskId": "24eea52ee52f48b4a957dadf19af8b40",
"paramJson": "{\"SFTJBS_TD\": 1}"
}
接口调用测试用例:
java
@PostMapping("/setBizParam")
@ApiOperation(value = "设置效能所需参数")
public ActionResult<Object> setBizParam(@RequestBody EffParametersEntity parametersEntity) throws Exception {
return ActionResult.success(httPost("http://172.16.112.92:8881/api/efficacy/setBizParam", parametersEntity));
}
【注:需要与效能初始化接口配置使用。】
3.2. 效能初始化
接口:发起流程的时候调用, 产生与流程任务对应效能任务和第一个节点效能实例化
http://xxx:xxx/api/efficacy/init
类型:post
入参:
json
{
"flowEngineId": "流程引擎id",
"flowTaskId": "流程任务id",
"flowTaskName": "流程名称",
"startDate": "开始日期",
"flowNodeList": [
{
"nextNodeId": "流程节点id",
"nextNodeCode": "流程节点code",
"nextNodeName": "流程节点名称",
"nextCustomNodeCode": "流程节点自定义编码"
}
]
}
示例:
json
{
"flowEngineId": "94507d5ec3984d9a868b2778cb99ded2",
"flowTaskId": "24eea52ee52f48b4a957dadf19af8b40",
"flowTaskName": "海籍调查成果确认测试流程",
"startDate": "2022-06-27 09:01:47",
"flowNodeList": [
{
"nextNodeId": "4rlMS21",
"nextNodeCode": "testCode",
"nextNodeName": "派件",
"nextCustomNodeCode": "PAI_JIAN"
}
]
}
接口调用测试用例:
java
@PostMapping("/init")
@ApiOperation(value = "效能初始化")
public ActionResult<Object> init(@RequestBody EffParamModel model) throws Exception {
return ActionResult.success(httPost("http://172.16.112.92:8881/api/efficacy/init", model));
}
【注:需要与设置效能参数接口配合使用。初始化参数默认过期时间为一天。】
3.3. 节点效能初始化
接口:节点流转调用,用于计算流转出去的下个节点开始算效能
http://xxx:xxx/api/efficacy/initNode
类型:post
入参:
json
{
"flowTaskId": "流程任务id",
"flowNodeList": [
{
"nextNodeId": "流程节点id",
"nextNodeCode": "流程节点code",
"nextNodeName": "流程节点名称",
"nextCustomNodeCode": "流程节点自定义编码",
"currentNodeId": "前一个节点id"
}
]
}
示例:
json
{
"flowTaskId": "24eea52ee52f48b4a957dadf19af8b40",
"flowNodeList": [
{
"nextNodeId": "NZwMS21",
"nextNodeCode": "testCode2",
"nextNodeName": "红笑天/181047",
"nextCustomNodeCode": "twoNode",
"currentNodeId": "4rlMS21"
}
]
}
接口调用测试用例:
java
@PostMapping("/initNode")
@ApiOperation(value = "效能节点初始化")
public ActionResult<Object> initNode(@RequestBody EffNodeParam model) throws Exception {
return ActionResult.success(httPost("http://172.16.112.92:8881/api/efficacy/initNode", model));
}
3.4. 暂缓效能
接口:相等于暂停键的功能,适用场景例如当用户请假没有人接手的时候,起到暂停计算效能的作用
http://xxx:xxx/api/efficacy/pauseCal
类型:post
入参:
json
{
"flowTaskId": "流程任务id"
}
接口调用测试用例:
java
@PostMapping("/pauseCal")
@ApiOperation(value = "效能暂缓")
public ActionResult<Object> pauseCal(@RequestBody EffPauseModel model) throws Exception {
return ActionResult.success(httPost("http://172.16.112.92:8881/api/efficacy/pauseCal", model));
}
3.5. 取消暂缓效能
接口:取消暂停的功能,恢复继续计算效能
http://xxx:xxx/api/efficacy/cancelPauseCal
类型:post
入参:
json
{
"flowTaskId": "流程任务id"
}
接口调用测试用例:
java
@PostMapping("/cancelPauseCal")
@ApiOperation(value = "取消效能暂缓")
public ActionResult<Object> cancelPauseCal(@RequestBody EffPauseModel model) throws Exception {
return ActionResult.success(httPost("http://172.16.112.92:8881/api/efficacy/cancelPauseCal", model));
}
3.6. 效能删除
接口:当流程被删除的时候,也需删除效能的时候可以使用
http://xxx:xxx/api/efficacy/deleteEfficacy
类型:post
入参:
json
flowTaskIds: [
"xxx",
"xxx"
]
接口调用测试用例:
java
@PostMapping("/deleteEfficacy")
@ApiOperation(value = "删除效能")
public ActionResult<Object> deleteEfficacy(@RequestBody EffDelModel model) throws Exception {
return ActionResult.success(httPost("http://172.16.112.92:8881/api/efficacy/deleteEfficacy", model));
}
3.7. 撤回到开始节点效能处理
接口:驳回到初始化节点的时候使用,将已经产生的节点效能记录结束
http://xxx:xxx/api/efficacy/revokeToStart
类型:post
入参:
json
{
"flowTaskId": "流程任务id"
}
接口调用测试用例:
java
@PostMapping("/revokeToStart")
@ApiOperation(value = "撤回到开始节点效能处理")
public ActionResult<Object> revokeToStart(@RequestBody EffRevokeModel model) throws Exception {
return ActionResult.success(httPost("http://172.16.112.92:8881/api/efficacy/revokeToStart", model));
}
3.8. 效能终止
接口:与效能删除的区别是,删除是真删除不再显示,终止是类似禁用,流程可再显示
http://xxx:xxx/api/efficacy/stop
类型:post
入参:
json
{
"flowTaskId": "流程任务id"
}
接口调用测试用例:
java
@PostMapping("/stop")
@ApiOperation(value = "效能终止")
public ActionResult<Object> stop(@RequestBody EffStopModel model) throws Exception {
return ActionResult.success(httPost("http://172.16.112.92:8881/api/efficacy/stop", model));
}
3.9. 效能计算(定时器调用)
接口:计算非结束和非挂起的效能记录的是否预警,是否超期,已花费时间
http://xxx:xxx/api/efficacy/stop
类型:post
入参:无
接口调用测试用例:
java
@PostMapping("/calculate")
@ApiOperation(value = "效能计算")
public ActionResult<Object> calculate() throws Exception {
return ActionResult.success(httPost("http://172.16.112.92:8881/api/efficacy/calculate", null));
}
4. 表达式
其中涉及到了条件表达式的编写规则,以及后台代码表达式解析器的扩展。
4.1. 使用规则
4.1.1. 一般规则
变量需要以
':
开头,以'
结尾,也就是说需要用':'
包裹起来,比如,变量PD
表示为:':PD'
数字不需要使用单引号,但字符串需要使用单引号,时间表示格式例如:
'2022-02-09 00:00:00'
逻辑语法支持
+
,-
,*
,/
,<
,>
,<=
,>=
,==
,!=
,%
,mod
【取模等同于%
】,++
,--
,&&
,||
,and
,or
,like
举几个例子:
java
// 示例1,下面的表达式等同于 ===> "':PX'==23 or ':PE'=='ddd'"
String express1 = "':PX'==23 || ':PE'=='ddd'";
// 示例2
String express2 = "':PD'-':PX'<=5 and ':PE' like 'ddd'";
// 示例3
String express3 = "':PD'+':PX'!=10 && ':PE'!='aaa'";
4.1.2. 风险等级配置特殊规则
- 当前时间规定变量:
':NOW_DATE'
- 预警时间规定变量:
':WARNING_DATE'
- 超期时间规定变量:
':OVERDUE_DATE'
- 时间对比都是以分钟计。如:
':WARNING_DATE' - ':NOW_DATE' < 1440
(24 * 60 = 1440)
4.2. 表达式解析器
条件表达式解析器采用约定大于配置思想,对表达式有一定的使用规则。
解析引擎使用的是阿里开发的QLExpress
组件,优点包括线程安全、高效执行等。
4.2.1. 表达式编写规则
4.2.1.1. 一般规则
变量需要以
':
开头,以'
结尾,也就是说需要用':'
包裹起来,比如,变量PD
表示为:':PD'
数字不需要使用单引号,但字符串需要使用单引号,时间表示格式例如:
'2022-02-09 00:00:00'
逻辑语法支持
+
,-
,*
,/
,<
,>
,<=
,>=
,==
,!=
,%
,mod
【取模等同于%
】,++
,--
,&&
,||
,and
,or
,like
举几个例子:
java
// 示例1,下面的表达式等同于 ===> "':PX'==23 or ':PE'=='ddd'"
String express1 = "':PX'==23 || ':PE'=='ddd'";
// 示例2
String express2 = "':PD'-':PX'<=5 and ':PE' like 'ddd'";
// 示例3
String express3 = "':PD'+':PX'!=10 && ':PE'!='aaa'";
4.2.1.2. 风险等级配置特殊规则
- 当前时间规定变量:
':NOW_DATE'
- 预警时间规定变量:
':WARNING_DATE'
- 超期时间规定变量:
':OVERDUE_DATE'
- 时间对比都是以分钟计。如:
':WARNING_DATE' - ':NOW_DATE' < 1440 (24 * 60 = 1440)
4.2.2. 使用示例
数值类型与字符串类型使用:
java
SimpleDateFormat df = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
Date time = df.parse("2022/6/13 15:25:58");
String express = "':PD'+':PX'!=10 and ':PE'=='ddd' and ':TIME' > ':CURR_DATE'";
Map<String, Object> map = new HashMap<>();
map.put("PD", 6);
map.put("PX", 2);
map.put("PE", "DDD");
map.put("TIME", time);
map.put("CURR_DATE", new Date());
// 结果为false
System.out.println(Expression.boolExecute(express, map));
注意:
- 日期类型如果要做加减法操作必须转换为数值类型(时间戳、年、月、日、时、分、秒等),日期类型不能直接做加减法。需要如何计算请使用者根据自身情况自定义。
4.2.3. 参数传递规则
条件表达式解析器类:Expression
逻辑判断结果输出类:
java
/**
* 根据条件表达式和对应参数进行条件判断
*
* @param express 条件表达式
* @param paramMap 参数列表,key为参数名称,value为参数值
* @return 判断结果
* @throws Exception 抛出异常
*/
static Boolean boolExecute(String express, Map<String, Object> paramMap) throws Exception
4.2.4. 扩展操作符
编写示例:
java
// 对 '=' 这个操作符进行重写
@ExExpressReplaceOperator("=")
public class StrEqualsOperator extends Operator {
@Override
public Object executeInner(Object[] objects) {
// ... 操作符运算逻辑
}
}
// 扩展新增 '*.' 这个操作符
@ExExpressAddOperator("*.")
public class StrEqualsOperator extends Operator {
@Override
public Object executeInner(Object[] objects) {
// ... 操作符运算逻辑
}
}