大家好,我是在加班的码农刘工。最近在使用芋道源码yudao-cloud开发一个系统,刚好需要使用工作流来实现审批和驳回的业务。
需求
实现一个公司绩效评分功能。员工自己填写每个月的绩效,填好后提交给领导打分审核。
工作流介绍
由于使用的是 yudao-cloud 进行的二开,框架内本身已经封装好了工作流的服务,功能介绍如下:
如何使用
首先需要把bpm服务启动,然后走一遍过程,才能清晰的知道该工作流是怎么样的业务流程。接下来是使用的步骤:
1、启动该服务之前需要先导入对应的sql。
2、运行 BpmServerApplication 类,启动工作流服务。
然后访问前端的 BPM 菜单,确认功能是否生效。如下图所示:
3、也可以看下官方的 审批接入业务表单,当然直接看我这个也不会误入歧途。
找到工作流程->流程管理->流程模型->新建流程
这里的标识是唯一的 最好在后端写一个常量或者枚举,也可以写在字典里,会有用到的地方。流程名称可随便写。
这里创建好以后还需要操作3个步骤
4、修改流程、设计流程、发布流程。
修改流程:
----流程分类:可以去随便去分类创建一个,再回来选择。
----表单类型:我这里主讲的是 业务表单,流程表单可以看看 官方流程表单。
----表单提交路由和表单查看地址:这两个别有用途啊,不过我的需求用不到。表单提交路由可以把创建表单的页面路由进行填写,查看则是详情的地址。具体可查看 官方业务表单。
----我的填写如下,然后确定。
设计流程:
开始和结束节点是必须的,直接按住拖拽即可。拖拽后点击可以可以直接连线。
点击审批节点,填写名称,选择审批人(我这里选择了用户,也可以选择部门或其它)
设计好以后保存模型,回到列表点击发布流程,这里流程就创建好了。
需求实现
1、我这里分为三张表:绩效表、绩效明细表、绩效审批表
// 绩效表
CREATE TABLE `system_performance` (
`performance_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`year_months` varchar(20) NOT NULL COMMENT '年月',
`status` int(11) NOT NULL COMMENT '状态:0-保存 1-待评分 2-已评分',
// 省略创建/修改时间,创建/修改人,deleted,tenant_id
PRIMARY KEY (`performance_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=45 DEFAULT CHARSET=utf8mb4 COMMENT='绩效表';
// 绩效明细表
CREATE TABLE `system_performance_score` (
`score_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`performance_id` bigint(20) NOT NULL COMMENT '绩效表ID',
`task_type` int(11) DEFAULT NULL COMMENT '任务类型:0-岗位任务 1-临时任务 2-目标任务',
`task_name` varchar(60) DEFAULT NULL COMMENT '任务标题',
`task_detail` text COMMENT '任务明细',
`deadline` date DEFAULT NULL COMMENT '截止日期',
`score` int(11) DEFAULT NULL COMMENT '分值',
`self_score` int(11) DEFAULT NULL COMMENT '自评分',
`leader_score` int(11) DEFAULT NULL COMMENT 'leader评分',
`self_comment` varchar(200) DEFAULT NULL COMMENT '自评语',
`leader_comment` varchar(200) DEFAULT NULL COMMENT 'leader语',
`process_instance_type` varchar(100) DEFAULT NULL COMMENT '流程类型',
`process_instance_id` varchar(100) DEFAULT NULL COMMENT '流程实例的编号',
`status` tinyint(4) DEFAULT NULL COMMENT '流程结果 0-保存 1-审核中 2-审批通过 3-审批不通过',
`present_user_id` bigint(20) DEFAULT NULL COMMENT '当前审批人',
`present_nickname` varchar(255) DEFAULT NULL COMMENT '当前审批人昵称',
// 省略创建/修改时间,创建/修改人,deleted,tenant_id
PRIMARY KEY (`score_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=69 DEFAULT CHARSET=utf8mb4 COMMENT='绩效明细表';
// 绩效审批表
CREATE TABLE `system_performance_approve` (
`approve_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`score_id` bigint(20) NOT NULL COMMENT '绩效明细ID',
`process_instance_id` varchar(100) DEFAULT NULL COMMENT '流程实例的编号',
`status` tinyint(4) DEFAULT NULL COMMENT '审批结果 1-审核中 2-审批通过 3-审批不通过',
// 省略创建/修改时间,创建/修改人,deleted,tenant_id
PRIMARY KEY (`approve_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='绩效审批表';
此处省略生成后端代码的过程
2、system引入bpm依赖
这里需要定义bpm的api,关于Feign服务调用可以看我的另一篇文章
3、提交接口的service实现类
@Override
@Transactional(rollbackFor = Exception.class)
public Long createPerformance(Long userId, PerformanceSaveReqVO createReqVO) {
// 插入
PerformanceDO performance = BeanUtils.toBean(createReqVO, PerformanceDO.class);
performanceMapper.insert(performance);
// 插入明细表
createPerformanceScoreList(userId, performance.getStatus(), performance.getPerformanceId(), createReqVO.getPerformanceScores());
// 返回
return performance.getPerformanceId();
}
// 提交明细表
private void createPerformanceScoreList(Long userId, Integer status, Long performanceId, List<PerformanceScoreDO> list) {
list.forEach(o -> o.setPerformanceId(performanceId));
performanceScoreMapper.insertBatch(list);
// 确认为提交时创建流程
if (status.equals(PerformanceEnum.STATUS_TYPE_2.getCode())) {
createPerformanceScoreFlow(userId, list);
}
}
/**
* 创建流程
*
* @param userId
* @param performanceScoreDOList
*/
private void createPerformanceScoreFlow(Long userId, List<PerformanceScoreDO> performanceScoreDOList) {
for (PerformanceScoreDO scoreDO : performanceScoreDOList) {
// 发起 BPM 流程
Map<String, Object> processInstanceVariables = new HashMap<>();
// setProcessDefinitionKey 流程实例的唯一标识test_performance
String processInstanceId = processInstanceApi.createProcessInstance(userId,
new BpmProcessInstanceCreateReqDTO().setProcessDefinitionKey(scoreDO.getProcessInstanceType())
.setVariables(processInstanceVariables).setBusinessKey(String.valueOf(scoreDO.getScoreId()))
).getCheckedData();
scoreDO.setProcessInstanceId(processInstanceId);
// 获取流程当前节点的审批人,该方法需要在bpm模块定义
CommonResult<String> apiTaskResult = processInstanceApi.getApiTaskListByProcessInstanceId(processInstanceId);
if (apiTaskResult.getData() != null) {
scoreDO.setPresentUserId(Long.valueOf(apiTaskResult.getData()));
AdminUserDO adminUserDO = userMapper.selectById(scoreDO.getPresentUserId());
scoreDO.setPresentNickname(adminUserDO.getNickname());
}
// todo 此处还需要创建审批
}
performanceScoreMapper.updateBatch(performanceScoreDOList);
}
4、审批接口
由于我个人的业务牵扯到较多的模块,代码贴了反而会更复杂,所以就省略了
@Transactional(rollbackFor = Exception.class)
@Override
public Boolean approvePerformanceScoreStatus(PerformanceUpdateStatusReqVO updateReqVO) {
// 由于我个人的业务牵扯到较多的模块,代码贴了反而会更复杂,所以就省略了
// todo 调用审批接口,审批是否通过
// todo 更新绩效表信息
}
5、bpm的Feign接口定义
@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory =
@Tag(name = "RPC 服务 - 流程实例")
public interface BpmProcessInstanceApi {
String PREFIX = ApiConstants.PREFIX + "/process-instance";
@PostMapping(PREFIX + "/create")
@Operation(summary = "创建流程实例(提供给内部),返回实例编号")
@Parameter(name = "userId", description = "用户编号", required = true, example = "1")
CommonResult<String> createProcessInstance(@RequestParam("userId") Long userId,
@Valid @RequestBody BpmProcessInstanceCreateReqDTO reqDTO);
// 该接口的实现可参考BpmTaskController里的getTaskListByProcessInstanceId接口
@PostMapping(PREFIX + "/getApiTaskListByProcessInstanceId")
@Operation(summary = "获得指定流程实例的流程任务列表(获取审批人)")
@Parameter(name = "userId", description = "用户编号", required = true, example = "1")
CommonResult<String> getApiTaskListByProcessInstanceId(@RequestParam("processInstanceId") String processInstanceId);
// 该接口的实现可参考BpmTaskController里的approveTask接口
@PostMapping(PREFIX + "/approve")
@Operation(summary = "审批通过任务")
public CommonResult<Boolean> approveTask(@RequestParam("userId") Long userId,
@RequestParam("processInstanceId") Long processInstanceId,
@RequestParam("reason") Long reason);
// 该接口的实现可参考BpmTaskController里的rejectTask接口
@PostMapping(PREFIX + "/reject")
@Operation(summary = "审批拒绝任务")
public CommonResult<Boolean> rejectTask(@RequestParam("userId") Long userId,
@RequestParam("processInstanceId") Long processInstanceId,
@RequestParam("reason") Long reason);
}
好了,到此业务表单接入工作流完成。
总结
本篇文章主要讲实现的思路,帮大家尽少的踩坑。毕竟我真的是反复掉了好多次坑,有疑问的朋友也可以在评论区提问或交流。
下一篇文章再见!!!