由于客戶對于系統里的一些新增數據,例如照片墻、照片等,想實現上級逐級審批通過才可見的效果,于是引入了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);
@Overridepublic 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查找照片墻,給照片墻設置審核的組織IDPhotoWall 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 + "");//獲得和登錄用戶同一級的審核人的idList<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());//審核人的idsysTask.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來獲得照片墻idString 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();//搜索出工作臺選的任務idSysTask sysTask = iSysTaskService.selectTaskById(id);//通過任務的photoWallId來獲得照片墻idPhotoWall 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等于當前登錄用戶審核的任務的關聯的照片墻idif (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:idString 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_IDENTITYLINKwhere 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來獲得資訊idString 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();//搜索出工作臺選的任務idSysTask sysTask = iSysTaskService.selectTaskById(id);//通過任務的informatinid來獲得資訊idPhotoWall 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等于當前登錄用戶審核的任務的關聯的照片墻idif(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:idString 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.業務數據表
以 照片墻 為例
十、業務表數據權限變化
- 審核前,即草稿狀態的數據,只能看自己創建的
- 審核通過,本級 到 最終審核組織 之間的用戶都可見