我们来创建一个并行网关的出差申请单,然后写死审批人,不需要在去认领了,act_ru_task表的ASSIGNEE_字段就直接有值了
提交人不需要设置用户,其他审批人 我们选择分配用户
选择固定值,在分配填写 对应的审批人 然后点击保存
保存完之后 点击下载 然后部署
并行网关就是不需要写分支条件,他会自动分配多个任务,当用户提交后,自动分配到 组长和经理接收,然后等主管和大区经理 都审批完成了之后,才会到总经理审批。
我们先来创建出差表
CREATE TABLE `tb_travel` (
`id` varchar(50) NOT NULL COMMENT '主键',
`name` varchar(50) DEFAULT NULL COMMENT '申请单名称',
`day` double DEFAULT NULL COMMENT '出差天数',
`create_by` varchar(50) DEFAULT NULL COMMENT '创建人账号',
`create_by_name` varchar(50) DEFAULT NULL COMMENT '创建人名称',
`instance_id` varchar(50) DEFAULT NULL COMMENT '流程实例id',
`approval_status` varchar(10) DEFAULT NULL COMMENT '审批状态 1:未提交 2:审批中 3:审批通过 ',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='出差表';
package com.dmg.entity;
import java.util.Date;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
/**
* 出差表
*/
@Data
@TableName("tb_travel")
public class Travel {
/**
* 主键
*/
private String id;
/**
* 申请单名称
*/
private String name;
/**
* 出差天数
*/
private Double day;
/**
* 创建人账号
*/
private String createBy;
/**
* 创建人名称
*/
private String createByName;
/**
* 流程实例id
*/
private String instanceId;
/**
* 审批状态 1:未提交 2:审批中 3:审批通过
*/
private String approvalStatus;
/**
* 创建时间
*/
private Date createTime;
}
package com.dmg.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.dmg.entity.Travel;
public interface TravelMapper extends BaseMapper<Travel> {
}
package com.dmg.service;
import com.dmg.vo.req.Req;
public interface TravelService {
public boolean submitApplication(Req req);
public boolean approval(Req req);
}
package com.dmg.service.impl;
@Service
public class TravelServiceImpl implements TravelService {
@Autowired
private TravelMapper travelMapper;
@Autowired
private FlowService flowService;
/**
* 提交出差单
* @param req
*/
@Transactional
@Override
public boolean submitApplication(Req req) {
//从数据库查询当前信息
Travel travel=travelMapper.selectById(req.getId());
if(travel==null){
throw new RuntimeException("出差单不存在");
}
if("3".equals(travel.getApprovalStatus())){
throw new RuntimeException("已审批通过,不能提交");
}
//业务key 用于待办已办 扩展字段 展示使用
//我这里以 流程定义key + 主键 + 申请单名称 的方式命名
String businessKey="cc."+travel.getId()+"."+travel.getName();
//我这里是并行网关 不需要传分支,所以map为null
//如果流程实例为空 启动一个新的流程实例
String instanceId = flowService.startProcessInstance(businessKey, null,travel.getInstanceId());
//保存instanceId到数据库
travel.setInstanceId(instanceId);
//审批状态改为 2:审批中
travel.setApprovalStatus("2");
travelMapper.updateById(travel);
return true;
}
/**
* 审批出差单
* @param req
*/
@Transactional
@Override
public boolean approval(Req req) {
//从数据库查询当前信息
Travel travel=travelMapper.selectById(req.getId());
if(travel==null){
throw new RuntimeException("出差单不存在");
}
//2:审批中
if(!"2".equals(travel.getApprovalStatus())){
throw new RuntimeException("状态不是审批中,不能审批");
}
//我这里没有设置驳回 所以不需要传map
String res = flowService.complete(travel.getInstanceId(), null, travel.getId(), req.getApprovalComments(), req.getApprover());
if("end".equals(res)){
//如果流程已经走完了 那么吧审批状态修改为 3:审批通过
travel.setApprovalStatus("3");
travelMapper.updateById(travel);
}
return true;
}
}
package com.dmg.controller;
@RestController
@RequestMapping("/travel")
public class TravelController {
@Autowired
private TravelService travelService;
/***
* 提交出差单
* @param req
* @return
*/
@PostMapping("submitApplication")
public Result submitApplication(@RequestBody Req req){
return Result.success(travelService.submitApplication(req));
}
/***
* 审批出差单
* @param req
* @return
*/
@PostMapping("approval")
public Result approval(@RequestBody Req req){
return Result.success(travelService.approval(req));
}
}
我们来看下提交申请单后的结果
http://localhost:8080/travel/submitApplication
{
"id":"003"
}
act_ru_task表已经有了2条数据了 并且审批人也有值了
我们在看下审批
http://localhost:8080/travel/approval
{
"id":"003",
"approvalComments":"我同意",
"flag":"true",
"approver":"jingli"
}
经理审批完了 就走到了主管审批
然后我们继续用主管审批,可以看到还有组长审批的任务,说明 并行网关在阻塞所有任务都走完了,才往下走
我想在任务中,看到那些是我要处理的待办信息 该怎么弄呢?
这个时候我们的业务key 就派上用场了,用于扩展一些展示在列表的字段
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.dmg.mapper.QjMapper">
<!--查询我的待办 act_ru_task运行时任务表 act_ru_execution 运行时执行实例表-->
<select id="getMyTask" resultType="com.dmg.vo.TaskVo">
SELECT
a.ID_ taskId,
a.PROC_INST_ID_ procInsId,
a.PROC_DEF_ID_ procDefId,
a.NAME_ taskName,
a.CREATE_TIME_ createTime,
a.EXECUTION_ID_ executionId,
a.ASSIGNEE_ assigneeName,
b.BUSINESS_KEY_ businessKey
FROM
act_ru_task as a
LEFT JOIN act_ru_execution as b on a.PROC_INST_ID_=b.PROC_INST_ID_ and b.BUSINESS_KEY_ is not NULL
WHERE a.ASSIGNEE_=#{assignee}
order by a.CREATE_TIME_ desc
</select>
</mapper>
package com.dmg.mapper;
public interface QjMapper extends BaseMapper<Qj> {
/**
* 分页查询我的待办
* @param page
* @param assignee 用户账号
* @return
*/
IPage<TaskVo>getMyTask(Page<TaskVo>page, @Param("assignee") String assignee);
}
package com.dmg.service;
public interface QjService {
public IPage<TaskVo>getMyTask(int current,int size,String assignee);
}
package com.dmg.controller;
/**
* 任务控制层
*/
@RestController
public class TaskController {
@Autowired
private QjService qjService;
/**
* 分页查询我的待办
*/
@PostMapping("getMyTask")
public Result getMyTask(@RequestBody FlowReq req){
IPage<TaskVo> page = qjService.getMyTask(req.getCurrent()
, req.getSize(),req.getAccount());
return Result.success(page);
}
}
package com.dmg.service.impl;
@Service
public class QjServiceImpl implements QjService {
@Autowired
private QjMapper qjMapper;
@Autowired
private FlowService flowService;
/**
* 分页查询我的待办
* @param current
* @param assignee 用户账号
* @param size
*/
@Override
public IPage<TaskVo> getMyTask(int current, int size, String assignee) {
Page<TaskVo>page=new Page<>(current,size);
IPage<TaskVo> taskPage = qjMapper.getMyTask(page,assignee);
for (TaskVo x : taskPage.getRecords()) {
//解析业务key
String []res=x.getBusinessKey().split("\\.");
//流程定义key
String processDefinitionKey=res[0];
//业务表主键
String businessId=res[1];
//拼接url地址 把路径返回给前端 让前端自己去跳到对应的审批的界面
// TODO: 如果地址 不想写死 可以吧路径放入到数据库中
//TODO 然后查询出来一个map集合 匹配这个流程定义key
//TODO 然后拿到对应的地址 在url=url+id 这样去拼接 不用多个if 判断 因为我这里就2条 我就写死了
String url="";
if("qj".equals(processDefinitionKey)){
//如果当前是请假流程
url="/qingjia/shenpi/"+businessId;
}else if("cc".equals(processDefinitionKey)){
//如果当前是出差流程
url="/chuchai/shenpi/"+businessId;
}
x.setUrl(url);
x.setApplicationName(res[2]);
x.setBusinessId(businessId);
}
return taskPage;
}
}
package com.dmg.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.util.Date;
/**
* 任务
*/
@Data
public class TaskVo {
// 任务编号
private String taskId;
//任务执行编号
private String executionId;
// 任务名称
private String taskName;
//任务执行人名称
private String assigneeName;
//流程定义ID
private String procDefId;
//流程定义key
private String procDefKey;
//流程实例ID
private String procInsId;
//任务创建时间
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
/**
* 是否激活 1正常 2挂起
*/
private String suspensionState;
/**
* 跳转到vue 界面的地址 申请单的审批界面
*/
private String url;
/**
* 申请单名称
*/
private String applicationName;
/**
* 业务表主键
*/
private String businessId;
/**'
* 业务key
*/
private String businessKey;
/**
* 任务审批时间 任务结束时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date endTime;
}
我们来看下结果
http://localhost:8080/getMyTask
{
"current":1,
"size":3,
"account":"wangwu"
}
那我想要看看已经审批过的任务呢?
那就是查询我的已办任务了,我们去历史任务表去查询
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.dmg.mapper.QjMapper">
<!--查询我的已办 肯定是审批过的 所以结束时间不为空 act_hi_taskinst历史任务表 act_hi_procinst历史流程实例表 -->
<select id="getMyDoneTask" resultType="com.dmg.vo.TaskVo">
SELECT
a.ID_ taskId,
a.PROC_INST_ID_ procInsId,
a.PROC_DEF_ID_ procDefId,
a.NAME_ taskName,
a.END_TIME_ endTime,
a.EXECUTION_ID_ executionId,
a.ASSIGNEE_ assigneeName,
b.BUSINESS_KEY_ businessKey
FROM
act_hi_taskinst as a
LEFT JOIN act_hi_procinst as b on a.PROC_INST_ID_=b.PROC_INST_ID_ and b.BUSINESS_KEY_ is not NULL
WHERE a.ASSIGNEE_=#{assignee} and a.END_TIME_ is not null
order by a.END_TIME_ desc
</select>
</mapper>
package com.dmg.mapper;
public interface QjMapper extends BaseMapper<Qj> {
/**
* 分页查询我的已办
* @param page
* @param assignee 用户账号
* @return
*/
IPage<TaskVo>getMyDoneTask(Page<TaskVo>page, @Param("assignee") String assignee);
}
package com.dmg.service.impl;
@Service
public class QjServiceImpl implements QjService {
@Autowired
private QjMapper qjMapper;
@Autowired
private FlowService flowService;
/**
* 分页查询我的已办
* @param current
* @param assignee 用户账号
* @param size
*/
@Override
public IPage<TaskVo> getMyDoneTask(int current, int size, String assignee) {
Page<TaskVo>page=new Page<>(current,size);
IPage<TaskVo> taskPage = qjMapper.getMyDoneTask(page,assignee);
for (TaskVo x : taskPage.getRecords()) {
//解析业务key
String []res=x.getBusinessKey().split("\\.");
//流程定义key
String processDefinitionKey=res[0];
//业务表主键
String businessId=res[1];
//这里的跳转地址 我们就跳转到详情界面就好了
String url="";
if("qj".equals(processDefinitionKey)){
//如果当前是请假流程
url="/qingjia/detail/"+businessId;
}else if("cc".equals(processDefinitionKey)){
//如果当前是出差流程
url="/chuchai/detail/"+businessId;
}
x.setUrl(url);
x.setApplicationName(res[2]);
x.setBusinessId(businessId);
}
return taskPage;
}
}
package com.dmg.service;
public interface QjService {
public IPage<TaskVo>getMyDoneTask(int current,int size,String assignee);
}
package com.dmg.controller;
/**
* 任务控制层
*/
@RestController
public class TaskController {
@Autowired
private QjService qjService;
/**
* 分页查询我的已办
*/
@PostMapping("getMyDoneTask")
public Result getMyDoneTask(@RequestBody FlowReq req){
IPage<TaskVo> page = qjService.getMyDoneTask(req.getCurrent()
, req.getSize(),req.getAccount());
return Result.success(page);
}
}
我们来看下结果
http://localhost:8080/getMyDoneTask
{
"current":1,
"size":3,
"account":"zuzhang"
}