# 工作流接入使用说明

# 一、后端接入准备说明

# 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)、新增推送配置:流程中心——推送配置——新增

img

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

img

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

img

img

# 三、后端接入代码

# 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 忽略
案例
1Controler
    
@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));
    }
}

2Service

@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 表单数据主键
processTaskName String 下一任务名称
processUserNames 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
//流程启动/任务提交/驳回案例
1Controler   
@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 {
    
   ...//表单所需字段
}

2Service
@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 表单数据主键
processTaskName String 下一任务名称
processUserNames String 下一任务处理人名称;多个用逗号分隔
processActStatus int 返回:20作废
processStatus 枚举ProcessStatusEnum 返回固定值:NOTSTAETED:未启动
//流程作废
1Controler   
@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()));
    }
}


2Service
@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 必填 表单数据主键
//案例——流程审批操作回撤
1Controler   
@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));
    }
}


2Service
@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};流程图中“条件网关”后面的“线”没有设置条件,或者任务提交时,没有设置处理人