由于客户对于系统里的一些新增数据,例如照片墙、照片等,想实现上级逐级审批通过才可见的效果,于是引入了Acitivity7工作流技术来实现,本文是对实现过程的介绍讲解,由于我是中途交接前同事的这块需求,所以具体实现方式和代码编写我暂时先按前同事的思路简单介绍,不代表我个人看法。
参考文章:
springboot+Activiti7整合实践 (一)_vue2集成activit7-CSDN博客
org.springframework.security.core.userdetails.UsernameNotFoundException,三步解决Activiti7和Security冲突问题_cause: org.springframework.security.core.userdetai-CSDN博客
Activiti7笔记(二)Activiti7一共涉及到25张表,哪些操作会涉及哪些表,每张表的作用是什么_activiti7数据表详细解读-CSDN博客
Activiti7笔记(一)Activiti7是什么,入门流程操作的代码实现-腾讯云开发者社区-腾讯云 (tencent.com)
文章目录
- 一、引入依赖
- 二、修改配置文件
- 三、解决Activity7和Security框架冲突
- 四、启动项目,生成activity的数据库表
- 审批流过程
- 五、画流程图
- 六、部署流程
- 七、发起流程
- 1.示例
- 2.相关代码
- 八、审批过程
- 1.审核通过
- 1.示例
- 2.相关代码
- 2.审批不通过
- 1.相关代码
- 九、业务表相关字段
- 1.任务表
- 2.业务数据表
- 十、业务表数据权限变化
一、引入依赖
<!--activity7工作流-->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter</artifactId>
<version>${activity.starter.version}</version>
<exclusions>
<exclusion>
<!-- 项目引入了mybatis-plus,则需要排除 -->
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.activiti.dependencies</groupId>
<artifactId>activiti-dependencies</artifactId>
<version>${activity.starter.version}</version>
<type>pom</type>
</dependency>
<!-- 生成流程图 -->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-image-generator</artifactId>
<version>${activity.starter.version}</version>
</dependency>
二、修改配置文件
spring:
#activity工作流配置
activiti:
# 自动部署验证设置:true-开启(默认)、false-关闭
check-process-definitions: false
# 保存历史数据
history-level: full
# 检测历史表是否存在
db-history-used: true
# 关闭自动部署
deployment-mode: never-fail
# 对数据库中所有表进行更新操作,如果表不存在,则自动创建
# create_drop:启动时创建表,在关闭时删除表(必须手动关闭引擎,才能删除表)
# drop-create:启动时删除原来的旧表,然后在创建新表(不需要手动关闭引擎)
database-schema-update: true
# 解决频繁查询SQL问题
async-executor-activate: false
db-history-userd
和 history-level
,建议按图中配置,方便查询工作流历史记录
三、解决Activity7和Security框架冲突
场景:由于Activity升级到7版本后,引入了Security来用于权限校验,但是本项目自身已经引入了Security框架,于是发生了冲突
【如果项目用的不是security框架,例如用的shiro,需要在启动项排除,参考:springboot+Activiti7整合实践 (一)_vue2集成activit7-CSDN博客】
-
网上有很多的相关报错和解决办法,【参考:org.springframework.security.core.userdetails.UsernameNotFoundException,三步解决Activiti7和Security冲突问题_cause: org.springframework.security.core.userdetai-CSDN博客】
-
但本项目主要报错的地方是
根据userid获取用户任务列表
这个逻辑,使用activity7原生api方法会报错; -
解决办法(前同事处理的):不去排除冲突,直接另外新写一个方法去查activity7的表,实现上述的逻辑
本项目:
网上其他做法(用的activity原生的api):
从Activiti工作流中检索所有用户任务_在activiti 7中获取流程实例的所有任务_如何在Activiti工作流中的单独实例中强制顺序执行任务 - 腾讯云开发者社区 - 腾讯云 (tencent.com)
四、启动项目,生成activity的数据库表
引入依赖、配置好后,第一次启动会在数据库生成相关的表
具体介绍:Activiti7笔记(二)Activiti7一共涉及到25张表,哪些操作会涉及哪些表,每张表的作用是什么_activiti7数据表详细解读-CSDN博客
本项目主要用到的表:
-
流程部署表 :[ACT_RE_PROCDEF]
每对一个流程图部署后,会记录在该表里(部署过程下面会讲到)
-
历史流程实例表:[ACT_HI_PROCINST]
流程一次从头到尾执行,对应一个流程实例,流程结束时会保留下来
-
运行时流程执行对象表 :[ACT_RU_EXECUTION]
流程实例与执行对象的关系:一个流程实例在执行过程中,如果流程包含分支或聚合,那么执行对象的数量可以多个【至少有2条数据,其中第1条是对应历史流程实例表】。这是因为流程实例在运行过程中可能会产生多个并行的执行路径,每个路径上的任务或活动都可以视为一个执行对象。例如,在一个具有多个分支的审批流程中,不同的审批人可能会同时处理不同的分支任务,这些分支任务就代表了多个执行对象
Activiti工作流学习(二)流程实例、执行对象、任务 - 百度文库 (baidu.com)
这个表里面主要记录的是当前已经执行到哪个节点了,把对应的节点对象记录到这个里面
流程结束后,这张表对应的数据会清除
-
运行时节点人员数据信息表 :[ACT_RU_IDENTITYLINK]
运行时用户关系信息,存储任务节点与参与者的相关信息
也就是只要当前任务有参与者,就会将参与者的信息保存到这个表,多个人参与,保存多个信息 -
**运行时任务节点表:[ACT_RU_TASK] **
一个流程有多个节点,到某一个节点的时候,都会更新这个表,将当前节点的数据更新到这个表
审批流过程
- 部署流程,到
ACT_RE_PROCDEF
表看有没有新增一条对应的数据 - 启动流程实例,执行流程对象(可能多个),到
ACT_HI_PROCINST
和ACT_RU_EXECUTION
表看有没有新增对应数据 - 完成整个流程,过程主要看
ACT_RU_TASK
和ACT_RU_IDENTITYLINK
表的更新情况
五、画流程图
-
IDEA安装插件:
-
在resource下创建一个目录process存放流程图文件
-
右键,新建流程图文件
-
具体画图过程省略,这里介绍画完之后的流程图的重点信息
以2个审批节点的流程图为例(增加、减少节点都需要另外画图部署)
-
定义流程的id和名字(后续代码可以取到)
-
开始节点
-
审批节点
第1个审批节点:
第2个审批节点,同上
-
结束节点
-
二级节点之后的网关
这里二级审批完之后,会出现2种不同的可能走向(审批通过,继续到一级审批节点;审批不通过,直接结束),所以需要加上一个网关
【由于时间较赶等原因,本项目不做回退的实现,所以审核不通过都是直接走向结束节点(一级审批节点通过或不通过都是走向结束节点)】
-
节点之间或节点与网关之间的连接线
重点注意:网关后的线
定义一个条件变量,当SecondJudge=true时(代码赋值),即审核通过,会走向 一级审核 节点,否则走向结束节点,如下图所示
【当二级组织发起审核,但是选择最终审批组织也是二级的时候,审核通过会赋值SecondJudge=false,直接走结束节点】
-
六、部署流程
本项目采用的是通过接口,手动部署的方式【每新建或修改流程图都要调用一次接口来部署(后续打算优化成自动部署或者定时任务调用接口部署)】
@ApiOperation("手动部署照片审核")
@GetMapping("/photo/process/{typeLevel}")
public String auditingPhotoProcessByTypeLevel(@PathVariable("typeLevel") Integer typeLevel, @RequestParam("force") Boolean force) {
return auditingPhotoService.auditingPhotoProcessByTypeLevel(typeLevel,force);
}
/**
* 手动部署
* @param typeLevel 组织等级
* @param force 是否强制部署(当修改了流程图的时候需要传true)
* @return 部署结果
*/
public String auditingPhotoProcessByTypeLevel(Integer typeLevel, Boolean force);
@Override
public String auditingPhotoProcessByTypeLevel(Integer typeLevel, Boolean force) {
switch (typeLevel) {
case 6:
auditingPhotoSixService.process(force);
break;
case 5:
auditingPhotoFiveService.process(force);
break;
case 4:
auditingPhotoFourService.process(force);
break;
case 3:
auditingPhotoThreeService.process(force);
break;
case 2:
auditingPhotoTwoService.process(force);
break;
case 1:
auditingPhotoOneService.process(force);
break;
default:
throw new ServicesException(ResultStatus.ARGS_VALID_ERROR);
}
return typeLevel + "级照片流程部署成功";
}
/**
* 部署流程
* @param force
* @return
*/
public void process(Boolean force);
public void process(Boolean force) {
//判断流程是否已经部署,当force=0时,
if (force == null || force) {
//部署流程
DeploymentBuilder builder = repositoryService.createDeployment();
builder.addClasspathResource(AuditingConstant.BpmnXmlPhotoPathConstant.AUDITING_PHOTO_SIX_XML).disableSchemaValidation();
String id = builder.deploy().getId();
repositoryService.setDeploymentKey(id, AuditingConstant.BpmnIdConstant.AUDITING_PHOTO_SIX_ID);
} else {
//检测流程是否已经部署过
List<ProcessDefinition> definitions = repositoryService.createProcessDefinitionQuery()
.processDefinitionKey(AuditingConstant.BpmnIdConstant.AUDITING_PHOTO_SIX_ID)
.list();
if (!definitions.isEmpty()) {
// 已经部署过流程定义
throw new ServicesException(ResultStatus.AUDITING_PROCESS_DUPLICATE);
} else {
//部署流程
DeploymentBuilder builder = repositoryService.createDeployment();
builder.addClasspathResource(AuditingConstant.BpmnXmlPhotoPathConstant.AUDITING_PHOTO_SIX_XML).disableSchemaValidation();
String id = builder.deploy().getId();
repositoryService.setDeploymentKey(id, AuditingConstant.BpmnIdConstant.AUDITING_PHOTO_SIX_ID);
}
}
}
这里AuditingConstant.BpmnXmlPhotoPathConstant.AUDITING_PHOTO_SIX_XML
是流程图的路径,如下图所示
部署好后,查看数据表 ACT_RE_PROCDEF 即可判断是否成功部署
七、发起流程
前提: 业务表(需要审批的)数据创建 ——> 点击提交审核
如下图的照片墙审核,创建一条新的数据,此时一开始没审核,状态是“草稿”,点击发布后,才会触发审批流程
1.示例
二级组织用户 新增一个照片墙,点击发布(选择审核等级为 上级(一级)组织,即需要经过两个审批节点才截止
【只要是二级发起的,都走的是2个审批节点的流程图,只不过根据结束节点会有不同的走向逻辑,如果这里选择本级(二级)结束,则不论二级通过不通过,都会直接走向结束节点】
点击发布后,会启动一个流程实例,并执行流程对象,见表ACT_HI_PROCINST
和 ACT_RU_EXECUTION
ACT_HI_PROCINST(历史流程实例表):
ACT_RU_EXECUTION(运行时流程执行对象表):
如下图,当二级用户点击发步后,会发起审核,先走到 “二级审核2” 节点,对应上图的第1条数据
2.相关代码
@ApiOperation("发起照片审核")
@ApiImplicitParams({
@ApiImplicitParam(type = "query", name = "taskName", value = "任务名称", required = true),
@ApiImplicitParam(type = "query", name = "priority", value = "优先级", required = true),
@ApiImplicitParam(type = "query", name = "desc", value = "描述", required = true),
@ApiImplicitParam(type = "query", name = "photoWallId", value = "照片墙id", required = true),
@ApiImplicitParam(type = "query", name = "auditingOrganizeId", value = "审核的组织id", required = true)})
@ApiResponses({@ApiResponse(response = ResponseResult.class, message = "1", code = 200),
@ApiResponse(response = ServiceException.class, message = "系统错误,请稍等!", code = 4000)})
@PostMapping("/startPhotoAuditProcess")
public ResponseResult<String> photoStartAuditing(@RequestBody Map<String, Object> map) {
return ResponseResult.success(auditingPhotoService.photoStartAuditing(map));
}
/**
* 启动流程
* @param map
* @return success
*/
public String photoStartAuditing(Map<String,Object> map);
下面代码解释:根据当前用户的组织级别,走不同的实现方法【代码比较臃肿,后续再优化,后面的代码同理】
@Override
@Transactional(rollbackFor = Exception.class)
public String photoStartAuditing(Map<String, Object> map) {
//根据照片墙id查找照片墙,给照片墙设置审核的组织ID
PhotoWall photoWall = photoWallService.selectPhotoWallDetail(map.get("photoWallId") + "");
photoWall.setOrganizeAuditingId(Long.parseLong(map.get("auditingOrganizeId") + ""));
photoWall.setOpinion("");
OrganizeTreeVO userOrganize = iOrganizeService.getUserOrganize();
photoWallService.updatePhotoWallForAuditing(photoWall);
//当前组织的级别
Integer typeLevel = userOrganize.getTypeLevel();
Integer typeLevelSix = 6;
Integer typeLevelFive = 5;
Integer typeLevelFour = 4;
Integer typeLevelThree = 3;
Integer typeLevelTwo = 2;
Integer typeLevelOne = 1;
if (typeLevel.equals(typeLevelSix)) {
auditingPhotoSixService.startAuditProcess(map);
} else if (typeLevel.equals(typeLevelFive)) {
auditingPhotoFiveService.startAuditProcess(map);
} else if (typeLevel.equals(typeLevelFour)) {
auditingPhotoFourService.startAuditProcess(map);
} else if (typeLevel.equals(typeLevelThree)) {
auditingPhotoThreeService.startAuditProcess(map);
} else if (typeLevel.equals(typeLevelTwo)) {
auditingPhotoTwoService.startAuditProcess(map);
} else if (typeLevel.equals(typeLevelOne)) {
auditingPhotoOneService.startAuditProcess(map);
}
return "success";
}
/**
* 启动流程
* @param map
*/
public void startAuditProcess(Map<String,Object> map);
public void startAuditProcess(Map<String, Object> map) {
String id = map.get("photoWallId") + "";
//修改照片墙的状态
PhotoWall photoWall = photoWallService.selectPhotoWallDetail(id);
photoWall.setAuditState(1);
photoWall.setOrganizeAuditingId(Long.parseLong(map.get("auditingOrganizeId") + ""));
Boolean code = photoWallService.updatePhotoWallForAuditing(photoWall);
if (code) {
// 获取当前登录用户的组织信息
OrganizeTreeVO userOrganize = iOrganizeService.getUserOrganize();
//当前组织的级别
Integer typeLevel = userOrganize.getTypeLevel();
//用来封装存储每一级组织的审核人,key是integer,表示不同级的组织,value是个list集合,每一级组织的审核人
HashMap<String, List<SysUser>> auditors = new HashMap<>(10);
//找出每一级审批流人员
activitiService.getAuditors(userOrganize,typeLevel,auditors);
// 设置流程变量
Map<String, Object> variables = new HashMap<>(10);
//获得每级审核的审核人
List<String> firstAuditor = getAuditorsId(auditors.get("1"));
List<String> secondAuditor = getAuditorsId(auditors.get("2"));
//审核人
variables.put("firstAuditor", firstAuditor);
variables.put("secondAuditor", secondAuditor);
String formKey = AuditingConstant.BpmnIdConstant.AUDITING_PHOTO_TWO_ID + ":";
String bussinessKey = formKey + id;
variables.put("bussinessKey", bussinessKey);
// 启动流程实例
runtimeService.startProcessInstanceByKey(AuditingConstant.BpmnIdConstant.AUDITING_PHOTO_TWO_ID, bussinessKey, variables);
//给接下来的每一个审核人都创建一个,在刚发起的时候,是同一级的审核人
List<SysUser> auditorsTypeLevel = auditors.get(typeLevel + "");
//获得和登录用户同一级的审核人的id
List<String> auditorsTypeLevelIds = getAuditorsId(auditorsTypeLevel);
for (int i = 0; i < auditorsTypeLevelIds.size(); i++) {
SysTask sysTask = new SysTask();
sysTask.setTaskName((String) map.get("taskName"));
sysTask.setPriority(Integer.valueOf(map.get("priority") + ""));
sysTask.setDescribe((String) map.get("desc"));
sysTask.setPhotoWallId((String) map.get("photoWallId"));
sysTask.setCreatorName(SecurityUtils.getLoginUser().getUsername());
sysTask.setCreatorId(SecurityUtils.getLoginUser().getUserId());
//审核人的名字 这里要怎么设置啊,审核人的名字和id,用的是候选用户啊
sysTask.setAuditingPeople(auditorsTypeLevel.get(i).getUserName());
//审核人的id
sysTask.setAuditingPeopleid(Long.parseLong(auditorsTypeLevelIds.get(i)));
sysTask.setState(1);
sysTask.setAuditingType(2);
//任务表添加
iSysTaskService.addTask(sysTask);
//审核人的消息
Message message = new Message();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
String date = sdf.format(new Date());
message.setContent("你在" + date + "有一个照片墙的审核");
message.setCreateTime(new Date());
message.setState(1);
message.setUserId(auditorsTypeLevelIds.get(i));
message.setType(1);
messageService.addMessage(message);
}
//登录用户的消息
Message message = new Message();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
String date = sdf.format(new Date());
message.setContent("你在" + date + "发起了一个照片墙审核");
message.setCreateTime(new Date());
message.setState(1);
message.setUserId(SecurityUtils.getLoginUser().getUserId() + "");
message.setType(2);
messageService.addMessage(message);
}
}
上方代码重点:
-
设置变量,启动流程实例
这里把每一级审核人提前都设置好(后续不变)【这里根据业务需求应该也可以设计成后续动态添加】
业务id bussinessKey 规则在此设定,调用最后一行的activity api时候需要传递,同时将其设置到流程变量 variables 中,后续方便读取
-
业务部分
- 修改 照片墙业务表 流程相关字段
- 新增 审核任务业务表
- 发送消息
八、审批过程
现在流程走到第一个审批节点,即 二级审核2
此时,运行时节点人员数据信息表 ACT_RU_IDENTITYLINK,存入二级审核2 节点的 是审核人角色 的 用户,尾号20用户和尾号52用户都是该节点的审批人【该项目里,只要其中一个审批通过,就算通过,反之,一个拒绝就算拒绝】,
且被分配到了任务(同个任务),见表ACT_RU_TASK,如下图
对应业务表 任务表里,也加了2条数据
他们之间通过 BUSINESS_KEY_ 来关联
1.审核通过
审批通过,在activity7框架中,只需要设置SecondJudge变量,然后将task任务完成即可
1.示例
二级组织人员 尾号52用户 创建了一个照片墙,点击发布后,生成本级人员(尾号52和尾号20)的任务,此时52用户进入“我的待办”里(业务表 任务表),找到对应任务,点击审批通过,如下图
2.相关代码
@ApiOperation("照片墙审批通过")
@ApiImplicitParams({
@ApiImplicitParam(type = "query", name = "id", value = "任务id", required = true),
@ApiImplicitParam(type = "query", name = "opinion", value = "建议", required = false)
})
@PostMapping("/auditing/photo/approve/{id}")
public ResponseResult<String> auditingPhotoApprove(@PathVariable Integer id, @RequestParam(required = false) String opinion) {
return ResponseResult.success(auditingPhotoService.auditingPhotoApprove(id, opinion));
}
/**
* 审核通过
* @param id
* @param opinion
* @return success
*/
public String auditingPhotoApprove(Integer id,String opinion);
下面代码解释:
通过照片墙的创建者的组织等级,走不同的审核通过实现类
@Override
@Transactional(rollbackFor = Exception.class)
public String auditingPhotoApprove(Integer id, String opinion) {
//id是任务的id,可以获得照片墙的id
//再去新建表中查询这个照片墙是哪级创建的,
//这个级数直接判断吗,然后去调用哪个类的approve方法?
SysTask sysTask = iSysTaskService.selectTaskById(id);
//通过任务的informatinid来获得照片墙id
String photoId = sysTask.getPhotoWallId();
//根据照片墙的id去查询审核创建者的级别
LambdaQueryWrapper<PhotoWall> lambdaQueryWrapper = new LambdaQueryWrapper<PhotoWall>();
lambdaQueryWrapper.eq(PhotoWall::getPhotoWallId, photoId);
PhotoWall photoWall = photoWallService.getOne(lambdaQueryWrapper);
//获得当前等级
Long organizeId = photoWall.getOrganizeId();
Integer userOrganizeLevel = iOrganizeService.searchOrganizeById(organizeId).getOrganizeLevel();
Integer userOrganizeLevelOne = 1;
Integer userOrganizeLevelTwo = 2;
Integer userOrganizeLevelThree = 3;
Integer userOrganizeLevelFour = 4;
Integer userOrganizeLevelFive = 5;
Integer userOrganizeLevelSix = 6;
//获得审核组织的级别
Long auditingOrganizeId = photoWall.getOrganizeAuditingId();
Integer auditingOrganizeLevel = iOrganizeService.searchOrganizeById(auditingOrganizeId).getOrganizeLevel();
if (userOrganizeLevel.equals(userOrganizeLevelOne)) {
auditingPhotoOneService.approve(id, opinion);
} else if (userOrganizeLevel.equals(userOrganizeLevelTwo)) {
auditingPhotoTwoService.approve(id, opinion, auditingOrganizeLevel);
} else if (userOrganizeLevel.equals(userOrganizeLevelThree)) {
auditingPhotoThreeService.approve(id, opinion, auditingOrganizeLevel);
} else if (userOrganizeLevel.equals(userOrganizeLevelFour)) {
auditingPhotoFourService.approve(id, opinion, auditingOrganizeLevel);
} else if (userOrganizeLevel.equals(userOrganizeLevelFive)) {
auditingPhotoFiveService.approve(id, opinion, auditingOrganizeLevel);
} else if (userOrganizeLevel.equals(userOrganizeLevelSix)) {
auditingPhotoSixService.approve(id, opinion, auditingOrganizeLevel);
}
return "success";
}
/**
* 审核通过
* @param id
* @param opinion
* @param auditingOrganizeLevel
*/
public void approve(Integer id, String opinion,Integer auditingOrganizeLevel);
@Override
public void approve(Integer id, String opinion, Integer auditingOrganizeLevel) {
//获取任务的候选人是登录用户的任务的方法
List<Task> taskList = activitiService.getTaskIdByCandidate(SecurityUtils.getLoginUser().getUserId().toString());
//当前登录用户的组织级别
Integer typeLevel = iOrganizeService.getUserOrganize().getTypeLevel();
//搜索出工作台选的任务id
SysTask sysTask = iSysTaskService.selectTaskById(id);
//通过任务的photoWallId来获得照片墙id
PhotoWall photoWall = photoWallService.selectPhotoWallDetail(sysTask.getPhotoWallId() + "");
String photoWallId = photoWall.getPhotoWallId();
auditingInformTwoApproveService(taskList, photoWallId, typeLevel, photoWall, auditingOrganizeLevel, opinion);
// 获取当前登录用户的组织信息
OrganizeTreeVO userOrganize = iOrganizeService.getUserOrganize();
//用来封装存储每一级组织的审核人,key是integer,表示不同级的组织,value是个list集合,每一级组织的审核人
HashMap<String, List<SysUser>> auditors = new HashMap<>(10);
//找出每一级审批流人员
activitiService.getAuditors(userOrganize,typeLevel,auditors);
List<String> auditorsList = new ArrayList<>();
if(typeLevel.equals(AuditingConstant.Number.TWO)){
auditorsList = getAuditorsId(auditors.get("2"));
}
if (typeLevel == 1) {
auditorsList = getAuditorsId(auditors.get("1"));
}
sysTask.setState(2);
sysTask.setOpinion(opinion);
sysTask.setCompletionTime(new Date());
iSysTaskService.updateTask(sysTask);
Long userId1 = SecurityUtils.getLoginUser().getUserId();
String photoWallId1 = sysTask.getPhotoWallId();
//删除其他用户中关联这个照片墙id的任务
//循环审核人列表
for (String s : auditorsList) {
//当审核人不等于登录用户时,即其他用户
if (!Objects.equals(s, userId1 + "")) {
//搜索出他的全部任务
List<SysTask> sysTaskList = iSysTaskService.selectTaskByAuditorId(Long.parseLong(s));
//循环任务
for (SysTask task : sysTaskList) {
//找出任务中关联的照片墙id等于当前登录用户审核的任务的关联的照片墙id
if (photoWallId1.equals(task.getPhotoWallId())) {
//删除
iSysTaskService.deleteTask(task.getTaskId().intValue());
}
}
}
}
if (typeLevel == 1 || typeLevel.equals(auditingOrganizeLevel)) {
photoWall.setAuditState(2);
photoWallService.updatePhotoWallForAuditing(photoWall);
Message message = new Message();
Date date = new Date();
message.setContent("你的照片墙在" + typeLevel + "级审核通过");
message.setCreateTime(date);
message.setState(1);
String userId = sysTask.getCreatorId() + "";
message.setUserId(userId);
message.setType(2);
message.setTaskId(sysTask.getTaskId().intValue());
messageService.addMessage(message);
return;
}
if (typeLevel.equals(AuditingConstant.Number.TWO)) {
auditorsList = getAuditorsId(auditors.get("1"));
}
for (String s : auditorsList) {
SysTask sysTask1 = new SysTask();
sysTask1.setTaskName(sysTask.getTaskName());
sysTask1.setPriority(sysTask.getPriority());
sysTask1.setDescribe(sysTask.getDescribe());
sysTask1.setPhotoWallId(sysTask.getPhotoWallId());
sysTask1.setCreatorName(SecurityUtils.getLoginUser().getUsername());
sysTask1.setCreatorId(SecurityUtils.getLoginUser().getUserId());
sysTask1.setAuditingPeopleid(Long.parseLong(s));
SysUser sysUser = iSysUserService.selectUserById(Long.parseLong(s));
sysTask1.setAuditingPeople(sysUser.getUserName());
sysTask1.setState(1);
sysTask1.setAuditingType(2);
iSysTaskService.addTask(sysTask1);
sendMessage(s, sysTask);
}
sendMessage(typeLevel, sysTask);
}
private void auditingInformTwoApproveService(List<Task> taskList, String photoWallId, Integer typeLevel, PhotoWall photoWall, Integer auditingOrganizeLevel, String opinion) {
if (!ObjectUtils.isEmpty(taskList)) {
for (Task item : taskList) {
ProcessInstance processInstance = runtimeService
.createProcessInstanceQuery()
.processInstanceId(item.getProcessInstanceId())
.singleResult();
//根据流程实例得到bussinesskey,格式是formkey:id
String a = processInstance.getBusinessKey();
if (StringUtils.isNotBlank(a)) {
String[] b = a.split(":");
String photoId = b[1];
//判断bussinesskey,bussinesskey是任务表中的记录的id,在发起流程的时候会插入任务表,任务表的id也会变成流程变量
if (photoId.equals(photoWallId)) {
if (typeLevel == 2) {
if (typeLevel.equals(auditingOrganizeLevel)) {
taskService.setVariable(item.getId(), "SecondJudge", false);
} else {
taskService.setVariable(item.getId(), "SecondJudge", true);
}
} else if (typeLevel == 1) {
//如果当前审核人是一级组织的,那审核就结束了
photoWall.setAuditState(2);
photoWall.setOpinion(opinion);
photoWallService.updatePhotoWallForAuditing(photoWall);
}
taskService.addComment(item.getId(), item.getProcessInstanceId(), "审核通过");
taskService.complete(item.getId());
break;
}
}
}
}
}
上面代码重点:
-
找到activity的任务表中,当前该用户的所有任务
@Override public List<Task> getTaskIdByCandidate(String userId) { List<ActivitiTaskId> activitiTaskId = activitiMapper.getTaskIdByCandidate(userId); List<String> activitiTaskIds = new ArrayList<>(); for (com.znak.platform.entity.ActivitiTaskId taskId : activitiTaskId) { activitiTaskIds.add(taskId.getTaskId()); } List<Task> taskList = new ArrayList<>(); for (String taskId : activitiTaskIds) { Task task = taskService.createTaskQuery().taskId(taskId).singleResult(); taskList.add(task); } return taskList; }
<select id="getTaskIdByCandidate" resultType="com.znak.platform.entity.ActivitiTaskId"> select distinct TASK_ID_ from ACT_RU_IDENTITYLINK where USER_ID_ = #{userId} and TASK_ID_ != "" </select>
-
根据bussinesskey找到对应的任务,修改变量SecondJudge,并完成任务
这里注意,如果当前是走到一级审批节点了,则走下面的else if逻辑,直接将业务表修改审核通过(不用设置变量,因为没有网关了),如下图
-
业务相关
-
修改业务表的审批流相关字段,同时发送消息,同上
-
然后删除同级别组织人员的 业务表 任务表,新建下一级的人员的业务表 任务表,见代码
-
2.审批不通过
过程和审批通过大致一样
1.相关代码
@ApiOperation("照片审核不通过")
@ApiResponses({@ApiResponse(response = ResponseResult.class, message = "1", code = 200),
@ApiResponse(response = ServiceException.class, message = "系统错误,请稍等!", code = 4000)})
@ApiImplicitParams({
//发起资讯申请相关字段
@ApiImplicitParam(type = "query", name = "id", value = "任务id", required = true),
@ApiImplicitParam(type = "query", name = "opinion", value = "建议", required = false)
})
@PostMapping("/auditing/photo/reject/{id}")
public ResponseResult<String> auditingPhotoReject(@PathVariable Integer id, @RequestParam(required = false) String opinion) {
return ResponseResult.success(auditingPhotoService.auditingPhotoReject(id, opinion));
}
/**
* 审核不通过
* @param id
* @param opinion
* @return success
*/
public String auditingPhotoReject(Integer id,String opinion);
@Override
@Transactional(rollbackFor = Exception.class)
public String auditingPhotoReject(Integer id, String opinion) {
//id是任务的id,可以获得资讯的id
//再去新建表中查询这个资讯是哪级创建的,
//这个级数直接判断吗,然后去调用哪个类的approve方法?
SysTask sysTask = iSysTaskService.selectTaskById(id);
//通过任务的informatinid来获得资讯id
String photoWallId = sysTask.getPhotoWallId();
//根据资讯的id去查询审核创建者的级别
LambdaQueryWrapper<PhotoWall> lambdaQueryWrapper = new LambdaQueryWrapper<PhotoWall>();
lambdaQueryWrapper.eq(PhotoWall::getPhotoWallId, photoWallId);
PhotoWall photoWall = photoWallService.getOne(lambdaQueryWrapper);
//获得当前等级
Long organizeId = photoWall.getOrganizeId();
Integer userOrganizeLevel = iOrganizeService.searchOrganizeById(organizeId).getOrganizeLevel();
Integer userOrganizeLevelOne = 1;
Integer userOrganizeLevelTwo = 2;
Integer userOrganizeLevelThree = 3;
Integer userOrganizeLevelFour = 4;
Integer userOrganizeLevelFive = 5;
Integer userOrganizeLevelSix = 6;
if (userOrganizeLevel.equals(userOrganizeLevelOne)) {
auditingPhotoOneService.rej(id, opinion);
} else if (userOrganizeLevel.equals(userOrganizeLevelTwo)) {
auditingPhotoTwoService.rej(id, opinion);
} else if (userOrganizeLevel.equals(userOrganizeLevelThree)) {
auditingPhotoThreeService.rej(id, opinion);
} else if (userOrganizeLevel.equals(userOrganizeLevelFour)) {
auditingPhotoFourService.rej(id, opinion);
} else if (userOrganizeLevel.equals(userOrganizeLevelFive)) {
auditingPhotoFiveService.rej(id, opinion);
} else if (userOrganizeLevel.equals(userOrganizeLevelSix)) {
auditingPhotoSixService.rej(id, opinion);
}
return "success";
}
/**
* 审核不通过
* @param id
* @param opinion
*/
public void rej(Integer id, String opinion);
public void rej(Integer id, String opinion) {
//获取任务的候选人是登录用户的任务的方法
List<Task> taskList = activitiService.getTaskIdByCandidate(SecurityUtils.getLoginUser().getUserId().toString());
//当前登录用户的组织级别
Integer typeLevel = iOrganizeService.getUserOrganize().getTypeLevel();
//搜索出工作台选的任务id
SysTask sysTask = iSysTaskService.selectTaskById(id);
//通过任务的informatinid来获得资讯id
PhotoWall photoWall = photoWallService.selectPhotoWallDetail(sysTask.getPhotoWallId());
String photoWallId = photoWall.getPhotoWallId();
auditingInformTwoRejService(taskList, photoWallId, typeLevel, photoWall,opinion);
// 获取当前登录用户的组织信息
OrganizeTreeVO userOrganize = iOrganizeService.getUserOrganize();
//用来封装存储每一级组织的审核人,key是integer,表示不同级的组织,value是个list集合,每一级组织的审核人
HashMap<String, List<SysUser>> auditors = new HashMap<>(4);
//找出每一级审批流人员
activitiService.getAuditors(userOrganize,typeLevel,auditors);
//防止四级发起的审核,然后任务到达三级的时候调用此方法,会报错4级审核人找不到
List<String> auditorsList = new ArrayList<>();
Integer typeLevelTwo = 2;
if (typeLevel.equals(typeLevelTwo)) {
auditorsList = getAuditorsId(auditors.get("2"));
}
if (typeLevel == 1) {
auditorsList = getAuditorsId(auditors.get("1"));
}
//这一个等级的组织的审核任务处理,处理上一阶段的任务
//获得当前级别的审核人
sysTask.setState(3);
sysTask.setOpinion(opinion);
sysTask.setCompletionTime(new Date());
iSysTaskService.updateTask(sysTask);
Long userId1 = SecurityUtils.getLoginUser().getUserId();
String photoWallId1 = photoWall.getPhotoWallId();
//删除其他用户中关联这个咨询id的任务
//循环审核人列表
for (String s : auditorsList) {
//当审核人不等于登录用户时,即其他用户
if (!Objects.equals(s, userId1 + "")){
//搜索出他的全部任务
List<SysTask> sysTaskList = iSysTaskService.selectTaskByAuditorId(Long.parseLong(s));
//循环任务
for(SysTask task : sysTaskList){
//找出任务中关联的照片墙id等于当前登录用户审核的任务的关联的照片墙id
if(photoWallId1.equals(task.getPhotoWallId())){
//删除
iSysTaskService.deleteTask(task.getTaskId().intValue());
}
}
}
}
Message message = new Message();
Date date = new Date();
message.setContent("你的照片墙在" + typeLevel + "级审核没有通过");
message.setCreateTime(date);
message.setState(1);
//这个审核的是谁的流程
String userId = sysTask.getCreatorId() + "";
message.setUserId(userId);
message.setType(2);
message.setTaskId(sysTask.getTaskId().intValue());
messageService.addMessage(message);
}
private void auditingInformTwoRejService(List<Task> taskList, String photoWallId, Integer typeLevel, PhotoWall photoWall,String opinion) {
if (!ObjectUtils.isEmpty(taskList)) {
for (Task item : taskList) {
ProcessInstance processInstance = runtimeService
.createProcessInstanceQuery()
.processInstanceId(item.getProcessInstanceId())
.singleResult();
//根据流程实例得到bussinesskey,格式是formkey:id
String a = processInstance.getBusinessKey();
if (StringUtils.isNotBlank(a)) {
String[] b = a.split(":");
String photoId = b[1];
//判断bussinesskey,bussinesskey是任务表中的记录的id,在发起流程的时候会插入任务表,任务表的id也会变成流程变量
if (photoId.equals(photoWallId)) {
//根据当前登录用户的组织级别判断是第几级判断,设置相关的流程变量
if (typeLevel == 2) {
photoWall.setAuditState(4);
photoWall.setOpinion(opinion);
photoWallService.updatePhotoWallForAuditing(photoWall);
taskService.setVariable(item.getId(), "SecondJudge", false);
} else if (typeLevel == 1) {
//如果当前审核人是一级组织的,那审核就结束了
photoWall.setAuditState(4);
photoWall.setOpinion(opinion);
photoWallService.updatePhotoWallForAuditing(photoWall);
}
taskService.addComment(item.getId(), item.getProcessInstanceId(), "审核不通过");
taskService.complete(item.getId());
break;
}
}
}
}
}
上面代码的重点:
-
找到activity的任务表中,当前该用户的所有任务
同上
-
根据bussinesskey找到对应的任务,修改变量SecondJudge,并完成任务
同上
-
业务相关
-
修改业务表的审批流相关字段,同时发送消息,同上
-
然后删除同级别组织人员的 业务表 任务表,见代码
-
九、业务表相关字段
1.任务表
2.业务数据表
以 照片墙 为例
十、业务表数据权限变化
- 审核前,即草稿状态的数据,只能看自己创建的
- 审核通过,本级 到 最终审核组织 之间的用户都可见