# 工作流接入使用说明
# 一、后端接入准备说明
# 1.工作流接入方案
工作流接入方案分为两中: (1)、引入中台指定jar包,中台封装好指定接口调用以及解析返回结果(推荐,这里只介绍该步骤)
(2)、自行调用指定接口,自行解析参数(不推荐);
# 2.项目引入工作流Jar请求以及解析包
<dependency>
<groupId>com.hhh.cloud.framework</groupId>
<artifactId>hhh-activiti-feign</artifactId>
<version>2.1.0-SNAPSHOT</version>
</dependency>
启动类添加feign客户端注解
/**
*启动类
*/
@SpringBootApplication
@EnableFeignClients
.....
public class BotApplication {
public static void main(String[] args) {
SpringApplication.run(BotApplication.class, args);
}
}
配置文件中配置工作流服务URL
#工作流服务URL
hhh.activiti.server.url=http://192.169.0.220:5001/activiti/
# 连接超时时间
feign.client.config.default.connectTimeout = 5000
# 读超时时间
feign.client.config.default.readTimeout = 10000
# 二、流程配置
# 1.流程设计
登陆企业端后台
(1)、新增推送配置:流程中心——推送配置——新增

(2)、新增业务配置:流程中心——业务配置——新增

(3)、流程设计:流程中心——流程设计——新增


# 三、后端接入代码
# 1.查询任务节点/处理记录
以中台为例
表单状态actStatus: 0-保存 1-审批中 2-驳回 10-审批通过 20-作废(建议将该字段添加到表单数据库中)
流程状态processStatus:0未开启 1流程开启 2流程中 10流程结束(建议将该字段添加到表单数据库中)
//注入工作流请求服务类
@Autowired
private IActivitiService activitiService;
/**
*
* 查询任务节点以及处理记录
* @param dto——id 表单数据ID (只有流程启动后才必填)
* @param dto——processBusinessId 业务配置里面的业务标识 (只有流程未启动时才必填)
* @param dto——processTaskId 流程任务ID (流程启动后必填)
* @param dto——processVariables 流程自定义条件变量(流程用了自定义变量时必填)
* @return
*/
ProcessNodeRecord processNodeRecord = activitiService.findProcessNodeRecordByParam(ProcessInfoFindDTO dto);
方法参数属性:
| 字段 | 属性 | 必填 | 描述 |
|---|---|---|---|
| id | string | 流程启动后,提交任务必填(processStatus=2) | 表单数据主键32~36位 |
| processTaskId | string | 流程启动后是必填 | 流程任务ID |
| processBusinessId | string | 必填 | 业务标识,填写业务配置时系统自动生成 |
| processVariables | HashMap | 有自定义条件变量时,必填 | 自定义条件变量 |
| processUnitId | string | 选填 | 跨企业选人处理流程(处理人策略:”全员“、“其他”生效(其他暂定填角色组编号)) |
| processEndTime | String | 选填 | yyyy-MM-dd hh:mm:ss 截止时间,优先使用该值,不存在时再读取“流程设计”里面的”超时天数“ |
ProcessNodeRecord实体属性:
| 字段 | 属性 | 描述 |
|---|---|---|
| taskRecordList | List<TaskRecordModel> | 任务处理记录 |
| processNodeList | List<ProcessNode> | 任务节点数据,下一步任务处理节点 |
| rejectModelList | List<RejectModel> | 驳回选项数据,可驳回的选项,以及节点 |
| isRecallAppro | int | 当前账号能否撤回审批操作 |
TaskRecordModel实体属性:
| 字段 | 属性 | 描述 |
|---|---|---|
| processInstanceId | String | 流程实例ID |
| taskName | String | 任务名称 |
| createTime | Date | 开始时间(yyyy-MM-dd hh:mm:ss) |
| dealTime | Date | 处理时间(yyyy-MM-dd hh:mm:ss) |
| dealUserName | String | 处理人姓名 |
| result | String | 处理结果 |
| opinion | String | 处理意见 |
| status | String | 处理状态:0未处理,1已处理 |
ProcessNode实体属性:(树状结构)
| 字段 | 属性 | 描述 |
|---|---|---|
| nodeId | String | 节点ID |
| nodeDouc | String | 节点编码 |
| nodeName | String | 节点名称 |
| lineName | String | 连线名称 |
| type | String | 类型user:任务节点(需要选择任务处理人);exclusive:条件节点(子节点childerNodes是单选框数据);parallel:并行节点;end:结束节点 |
| conditionExp | String | 条件表达式 |
| userVariable | String | 处理人的键 |
| isMultiInstance | String | 是否会签任务(处理人是否多选) 1是 0否 |
| canChooseHandler | String | 是否能够修改处理人 0否 1能 |
| processUserList | List<ProcessUserDTO> | 默认处理人实体 ucId:账号ID;ucCode:账号Code;ucName:名称;unitId:企业ID |
| userTreeBean | List<UserTreeBean> | 处理人选择树 |
| childerNodes | List<ProcessNode> | 子节点数据 |
RejectModel实体属性:
| 字段 | 属性 | 描述 |
|---|---|---|
| rejectType | int | 驳回类型ID(相当于主键) |
| rejectName | String | 驳回名称 |
| nodeList | List<NodeSimple> | 可驳回的节点列表;NodeSimple属性nodeId(节点ID)、nodeName(节点名称) |
UserTreeBean实体属性:
| 字段 | 属性 | 描述 |
|---|---|---|
| id | String | 主键;nodeType=person时,id是账号ID |
| text | String | 显示名称 |
| nodeType | List<NodeSimple> | 可驳回的节点列表;NodeSimple属性nodeId(节点ID)、nodeName(节点 |
| nodeType | String | org:组织接口 manage:部门 person:人员等,只有“person”才能被选择,其他用于展示 |
| children | List<UserTreeBean> | 子节点 |
| parentId、state、url、icon、fullCode | String | 忽略 |
案例
1、Controler
@RestController
@RequestMapping("/leave")
public class ZtLeaveController {
@Autowired
private IZtLeaveService ztLeaveService;
/**
*查询首任务节点/下一步任务节点、人员下拉选项以及处理记录
*@param ztLeaveDTO.getId():表单数据ID,表单数据未生成时,可以为空
*/
@PostMapping("/findProcessInfo")
public Result findProcessInfo(@RequestBody @Valid ZtLeaveDTO ztLeaveDTO) {
return Result.ok(ztLeaveService.findProcessNodeRecord(ztLeaveDTO));
}
}
2、Service
@Service("ztLeaveService")
public class ZtLeaveServiceImpl extends ServiceImpl<ZtLeaveMapper, ZtLeave> implements IZtLeaveService {
@Autowired
private IActivitiService activitiService;
//请假申请的业务配置ID(建协云ACTIVITI模块:ACTIVITI/业务配置的businessId)
@Value("${hhh.activiti.leave.business.id}")
private String BUSINESS_ID;
@Override
public ProcessNodeRecord findProcessNodeRecord(ZtLeaveDTO ztLeaveDTO) {
HashMap<String, Object> processVariables = new HashMap<>();
processVariables.put("duration",Double.valueOf(ztLeaveDTO.getDuration()));//自定义条件变量:请假时长(小时),Double类型
return activitiService.findProcessNodeRecordByParam(ztLeaveDTO.getId(), BUSINESS_ID,processVariables);
}
}
# 2.流程启动/任务提交
//流程启动/任务提交/驳回
ProcessResult result = activitiService.runActiviti(ProcessDTO processDTO);
ProcessDTO实体属性(流程启动):
| 字段 | 属性 | 是否必填 | 描述 |
|---|---|---|---|
| processStatus | int | 必填,指定processStatus=1 | 1流程启动; |
| processBusinessId | String | 必填 | 业务配置主键,填写业务配置时系统自动生成 |
| processDataId | String | 必填 | 表单数据主键,32~36位 |
| processTitle | String | 必填 | 推送标题 |
| processComment | String | 必填 | 处理意见 |
| processNodeList | List<ProcessNodeDTO> | 必填 | 节点数据,由前端提供;从ProcessNode实体属性中获取 |
| processVariables | HashMap<String,Object> | 不必填 | 键值对,自定义条件变量 |
| processEndTime | String | 选填 | yyyy-MM-dd hh:mm:ss 截止时间,优先使用该值,不存在时再读取“流程设计”里面的”超时天数“ |
ProcessNodeDTO实体属性:
| 字段 | 属性 | 是否必填 | 描述 |
|---|---|---|---|
| nodeName | int | 必填 | 节点名称(从ProcessNode实体属性中获取) |
| lineName | String | 必填 | 连线名称(从ProcessNode实体属性中获取) |
| conditionExp | String | 必填 | 条件表达式(从ProcessNode实体属性中获取) |
| userVariable | String | 必填 | 处理人的键(从ProcessNode实体属性中获取) |
| isMultiInstance | String | 必填 | 是否会签任务(处理人是否多选) 1是 0否(从ProcessNode实体属性中获取) |
| defaultHandlerId | String | 必填 | 处理人ID |
ProcessDTO实体属性(任务提交):
| 字段 | 属性 | 是否必填 | 描述 |
|---|---|---|---|
| processStatus | int | 必填,指定processStatus=2 | 2任务提交 |
| processBusinessId | String | 必填 | 业务配置主键,填写业务配置时系统自动生成 |
| processTaskId | String | 必填 | 流程任务ID |
| processDataId | String | 必填 | 表单数据主键,32~36位 |
| processComment | String | 必填 | 处理意见 |
| processNodeList | List<ProcessNodeDTO> | 必填 | 节点数据,由前端提供;从ProcessNode实体属性中获取 |
| processVariables | HashMap<String,Object> | 选填 | 键值对,自定义条件变量 |
ProcessDTO实体属性(任务驳回):
| 字段 | 属性 | 是否必填 | 描述 |
|---|---|---|---|
| processStatus | int | 必填,指定processStatus=2 | 2任务提交 |
| processBusinessId | String | 必填 | 业务配置主键,填写业务配置时系统自动生成 |
| processTaskId | String | 必填 | 流程任务ID |
| processDataId | String | 必填 | 表单数据主键,32~36位 |
| processComment | String | 必填 | 处理意见 |
| processType | int | 必填,指定processType=1 | 1驳回 |
| processRejectNodeId | String | 必填 | 节点ID,RejectModel实体属性nodeList的nodeId |
ProcessResult实体属性(返回值):
| 字段 | 属性 | 描述 |
|---|---|---|
| processDataId | String | 表单数据主键 |
| processActStatus | int | 业务表单状态: 1-审批中 2-驳回 10-审批通过 |
| processStatus | 枚举ProcessStatusEnum | 当前流程状态NOTSTAETED:未启动;START:启动;RUNNING:流程中;END流程结束 |
| lastTaskNode | TaskNodeInfo | 当前处理的任务节点信息 |
| nextTaskNode | List<TaskNodeInfo> | 待处理的任务节点信息 |
TaskNodeInfo实体属性:
| 字段 | 属性 | 描述 |
|---|---|---|
| nodeDouc | String | 节点编码 |
| nodeName | String | 节点名称 |
| processUserList | List<ProcessUserDTO> | 处理人list |
//流程启动/任务提交/驳回案例
1、Controler
@RestController
@RequestMapping("/leave")
public class ZtLeaveController {
@Autowired
private IZtLeaveService ztLeaveService;
@PostMapping("/saveLeave")
public Result saveLeave(@RequestBody @Valid ZtLeaveAddDTO dto) throws Exception {
return Result.ok(ztLeaveService.saveLeave(dto));
}
}
//继承流程所需要的ProcessDTO
public class ZtLeaveAddDTO extends ProcessDTO {
...//表单所需字段
}
2、Service
@Service("ztLeaveService")
public class ZtLeaveServiceImpl extends ServiceImpl<ZtLeaveMapper, ZtLeave> implements IZtLeaveService {
@Autowired
private IActivitiService activitiService;
//请假申请的业务配置ID(建协云ACTIVITI模块:ACTIVITI/业务配置的businessId)
@Value("${hhh.activiti.leave.business.id}")
private String BUSINESS_ID;
//流程开启
@Override
@Transactional(rollbackFor = RuntimeException.class)
public ZtLeave saveLeave(ZtLeaveAddDTO dto){
ZtLeave ztLeave = new ZtLeave();
BeanUtils.copyProperties(dto,ztLeave);
ztLeave.setId(CommonUtil.GUID());
baseMapper.insert(ztLeave);
//工作流代码
//dto.getProcessStatus==1时,开启流程;
dto.setProcessDataId(ztLeave.getId());
dto.setProcessBusinessId(BUSINESS_ID);
dto.setProcessTitle("王某的请假申请");
dto.getProcessVariables().put("duration",Double.valueOf(ztLeave.getDuration()));
ProcessResult result = activitiService.runActiviti(dto);
//修改表单数据状态
if(result != null){
ztLeave.setActStatus(result.getProcessActStatus());//表单状态
ztLeave.setProcessStatus(result.getProcessStatus().getValue());//审核中
baseMapper.updateById(ztLeave);
}
return ztLeave;
}
//流程提交、驳回
@Override
@Transactional(rollbackFor = RuntimeException.class)
public ZtLeave updateLeave(ZtLeaveUpdateDTO updateDTO){//dto同样继承ProcessDTO
ZtLeave ztLeave = baseMapper.selectById(updateDTO.getId());
//工作流代码
//dto.getProcessStatus==2 时,任务提交;
//dto.getProcessStatus==2 并且dto.getProcessType=1 时,任务驳回
dto.setProcessDataId(ztLeave.getId());
dto.setProcessBusinessId(BUSINESS_ID);
dto.getProcessVariables().put("duration",Double.valueOf(ztLeave.getDuration()));
ProcessResult result = activitiService.runActiviti(dto);
//修改表单数据状态
if(result != null){
ztLeave.setActStatus(result.getProcessActStatus());//表单状态
ztLeave.setProcessStatus(result.getProcessStatus().getValue());//流程状态
baseMapper.updateById(ztLeave);
}
return ztLeave;
}
}
# 3.流程作废
温馨提示:只有当前任务处理人是创建人,才能作废(驳回到发起人节点时,才能作废)
//流程作废
ProcessResult result = activitiService.cancelProcess(CommonProcessDataIdDTO dto);
方法入参(CommonProcessDataIdDTO)
| 字段 | 属性 | 是否必填 | 描述 |
|---|---|---|---|
| processDataId | String | 必填 | 表单数据主键 |
ProcessResult实体属性(返回值):
| 字段 | 属性 | 描述 |
|---|---|---|
| processDataId | String | 表单数据主键 |
| processActStatus | int | 返回:20作废 |
| processStatus | 枚举ProcessStatusEnum | 返回固定值:NOTSTAETED:未启动 |
//流程作废
1、Controler
@RestController
@RequestMapping("/leave")
public class ZtLeaveController {
@Autowired
private IZtLeaveService ztLeaveService;
@RequestMapping("/cancelProcess")
public Result cancelProcess (@RequestBody @Valid ZtBusinessDTO dto) throws Exception{
return Result.ok(ztLeaveService.cancelProcess(dto.getId()));
}
}
2、Service
@Service("ztLeaveService")
public class ZtLeaveServiceImpl extends ServiceImpl<ZtLeaveMapper, ZtLeave> implements IZtLeaveService {
@Autowired
private IActivitiService activitiService;
@Override
@Transactional(rollbackFor = RuntimeException.class)
public int cancelProcess(String id) throws Exception{
ZtLeave saveEntity = baseMapper.selectById(id);
if (saveEntity == null) {
throw new BusinessException("没有找到对应的通用审批记录!");
}
ProcessResult result = activitiService.cancelProcess(id);
//更新表单状态
saveEntity.setActStatus(result.getProcessActStatus());
saveEntity.setProcessStatus(result.getProcessStatus().getValue());
return baseMapper.updateById(saveEntity);
}
}
# 4.流程审批操作回撤
温馨提示:只有当前当前审批人才能审批回撤
//流程审批操作回撤
ProcessResult result = activitiService.recallAppro(CommonProcessDataIdDTO dto);
方法入参(CommonProcessDataIdDTO)
| 字段 | 属性 | 是否必填 | 描述 |
|---|---|---|---|
| processDataId | String | 必填 | 表单数据主键 |
//案例——流程审批操作回撤
1、Controler
@RestController
@RequestMapping("/leave")
public class ZtLeaveController {
@Autowired
private IZtLeaveService ztLeaveService;
@RequestMapping("/recallAppro")
public Result recallAppro (@RequestBody JSONObject jsonObject) {
String id = jsonObject.getString("id");
return Result.ok(ztInoutFileCommonService.recallAppro(id));
}
}
2、Service
@Service("ztLeaveService")
public class ZtLeaveServiceImpl extends ServiceImpl<ZtLeaveMapper, ZtLeave> implements IZtLeaveService {
@Autowired
private IActivitiService activitiService;
@Override
public ProcessResult recallAppro(String id) {
return activitiService.recallAppro(id);
}
# 5. 根据业务id查询绑定所有流程
//根据业务id查询绑定所有流程
List<ProcessProcdef> result=activiService.findProcessProcdefByBusinessId(String processProcdefId);
方法入参
| 字段 | 属性 | 是否必填 | 描述 |
|---|---|---|---|
| processProcdefId | String | 必填 | 业务id即业务标识(businessId) |
//案例——根据业务id查询绑定所有流程
@Service("ztLeaveService")
public class ZtLeaveServiceImpl extends ServiceImpl<ZtLeaveMapper, ZtLeave> implements IZtLeaveService {
@Autowired
private IActivitiService activitiService;
//请假申请的业务配置ID(建协云ACTIVITI模块:ACTIVITI/业务配置的businessId)
@Value("${hhh.activiti.leave.business.id}")
private String BUSINESS_ID;
@Override
public List<ProcessProcdef> findProcessProcdefByBusinessId() {
return activitiService.findProcessProcdefByBusinessId(BUSINESS_ID);
}
ProcessProcdef实体属性(返回值)
| 字段 | 属性 | 描述 |
|---|---|---|
| processProcdefId | String | 流程主键 |
| processProcdefName | String | 流程名称 |
# 四、常见问题
# 1.模型(流程图)设计基本遵循规则
流程图请遵循以“开始——发起人——审批人——结束”为基础,开启流程默认跳过第一步(发起人节 点),直达“审批人”节点
# 2.条件网关设置条件(流程图中“线”)
”条件网关“后面连接的”线“必须设置“跳转条件”, 非“条件网关”后面连接的”线“最好别设置条件
# 3. 启动报错或运行时报错一
报错提示Unknown property used in expression: ${code==1};流程图中“条件网关”后面的“线”没有设置条件,或者流程提交的时候,没有回传参数: conditionExp
# 4. 启动报错或运行时报错二
报错提示Unknown property used in expression: ${dhhjzskwne};流程图中“条件网关”后面的“线”没有设置条件,或者任务提交时,没有设置处理人