在activiti中, 對(duì)于正在執(zhí)行的任務(wù), 已經(jīng)執(zhí)行過(guò)得任務(wù), 未執(zhí)行的任務(wù)可以判斷出來(lái), 但是還有一種狀態(tài), 就是任務(wù)已經(jīng)執(zhí)行過(guò)了, 但是因?yàn)楹竺嬉驗(yàn)榱鞒踢x擇關(guān)系又回到了這個(gè)任務(wù)的前面一些任務(wù), 那這個(gè)任務(wù)可能還會(huì)執(zhí)行一遍, 如何判斷任務(wù)的這個(gè)狀態(tài)?
比如下面這個(gè)請(qǐng)假流程圖
當(dāng)執(zhí)行到人事審批這邊, 人事審批拒絕了當(dāng)前申請(qǐng), 開(kāi)始調(diào)整申請(qǐng)任務(wù), 所以人事審批有可能還會(huì)執(zhí)行一次, 這個(gè)已經(jīng)執(zhí)行過(guò), 但是可能還會(huì)執(zhí)行的狀態(tài)改如何判斷?
自己琢磨了一下, 找到了滿足自己的這個(gè)要求的解決方法, 主要就是對(duì)于已經(jīng)執(zhí)行過(guò)的任務(wù)的狀態(tài)進(jìn)行判斷, 比如審批任務(wù), 如果審批不通過(guò), 則會(huì)退回到申請(qǐng)步驟, 所以這個(gè)時(shí)候?qū)徟蝿?wù)是執(zhí)行完成過(guò)一次, 但是可能還會(huì)執(zhí)行一次, 對(duì)于這個(gè)狀態(tài)我判定的思路是這樣的:
首先根據(jù)ProcessInstanceID可以獲得該流程所有的歷史活動(dòng)實(shí)例(ACT_HI_ACTINS表)的, 按時(shí)間排序后進(jìn)行遍歷, 將activityID放入到一個(gè)數(shù)組中, 如果一個(gè)activityId重復(fù)出現(xiàn)了兩次, 則這兩個(gè)activityId中間的則是這種狀態(tài)的, 然后將部分從數(shù)組中移除
代碼
public Map<String, TaskCoordinate> getTaskCoordinates(String processInstanceId) {
log.debug("in get activiti process image function");
try {
// 獲取歷史流程實(shí)例
HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
.processInstanceId(processInstanceId).singleResult();
if (historicProcessInstance == null) {
throw new CustomException("示例" + processInstanceId + "不存在");
}
ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
.getDeployedProcessDefinition(historicProcessInstance.getProcessDefinitionId());
// 獲取流程歷史中已執(zhí)行的節(jié)點(diǎn), 并按照節(jié)點(diǎn)在流程中執(zhí)行先后順序排序
List<HistoricActivityInstance> historicActivityInstances = historyService.createHistoricActivityInstanceQuery()
.processInstanceId(processInstanceId).orderByHistoricActivityInstanceId().asc().list();
// 已執(zhí)行節(jié)點(diǎn)的坐標(biāo)集合
executedCoordinates = new HashMap<>();
// 按任務(wù)的執(zhí)行順序存放taskId
activityIds = new ArrayList<>();
log.debug(">>>>>>>>>>>>>>>>>>>>>獲取已經(jīng)執(zhí)行的節(jié)點(diǎn)ID<<<<<<<<<<<<<<<<<<<<<");
for (HistoricActivityInstance activityInstance : historicActivityInstances) {
// 如果是用戶任務(wù)類(lèi)型
if (StringUtils.equalsIgnoreCase(activityInstance.getActivityType(), "userTask")) {
updateTaskCoordinate(activityInstance, processDefinition);
}
}
return executedCoordinates;
} catch (Exception e) {
log.error("獲取已執(zhí)行任務(wù)坐標(biāo)失敗, message --> {}", e.getMessage());
throw new CustomException("獲取任務(wù)失敗!" + e.getMessage());
}
}
/**
* 更新當(dāng)前活動(dòng)的狀態(tài)級(jí)添加任務(wù)處理信息
*
* @param activityInstance 活動(dòng)示例
* @param taskCoordinate 任務(wù)坐標(biāo)信息
*/
private void updateTaskCoordinate(HistoricActivityInstance activityInstance, TaskCoordinate taskCoordinate) {
// 根據(jù)當(dāng)前任務(wù)是否有結(jié)束時(shí)間來(lái)判斷是否為進(jìn)行中的任務(wù)
if (activityInstance.getEndTime() == null) {
taskCoordinate.setType(TaskCoordinate.TASK_IN_PROCESS);
} else {
taskCoordinate.setType(TaskCoordinate.TASK_COMPLETED);
}
TaskInfo taskInfo = new TaskInfo(activityInstance.getTaskId(), activityInstance.getAssignee(), activityInstance.getEndTime());
taskCoordinate.addTaskInfo(taskInfo);
}
/**
* 更新任務(wù)狀態(tài)
*
* @param activityInstance
* @param processDefinition
*/
private void updateTaskCoordinate(HistoricActivityInstance activityInstance, ProcessDefinitionEntity processDefinition) {
ActivityImpl activity = processDefinition.findActivity(activityInstance.getActivityId());
TaskCoordinate taskCoordinate;
String activityId = activityInstance.getActivityId();
activityIds.add(activityId);
log.debug("activity id list --> {}", activityIds);
if (executedCoordinates.get(activityId) == null) {
// 新建coordinate對(duì)象, 設(shè)置act_id及坐標(biāo)
taskCoordinate = new TaskCoordinate();
taskCoordinate.setNode(activityInstance.getActivityId());
taskCoordinate.setName(activityInstance.getActivityName());
taskCoordinate.setCoordinate(activity.getX(), activity.getY(), activity.getWidth(), activity.getHeight());
// 更新?tīng)顟B(tài)和添加任務(wù)信息
updateTaskCoordinate(activityInstance, taskCoordinate);
executedCoordinates.put(activityId, taskCoordinate);
} else {
// 從map中獲取coordinate對(duì)象
taskCoordinate = executedCoordinates.get(activityId);
// 更新?tīng)顟B(tài)和添加任務(wù)信息
updateTaskCoordinate(activityInstance, taskCoordinate);
executedCoordinates.put(activityId, taskCoordinate);
int preIndex = preIndexOfLastTaskId(activityIds, activityId);
log.debug("preIndex --> {}", preIndex);
if (preIndex != -1) {
// 得到需要設(shè)置狀態(tài)為other的子列表取出來(lái)
List<String> subActivityIds = activityIds.subList(preIndex + 1, activityIds.size() - 1 - 1);
// 將狀態(tài)為other的元素去掉
activityIds = activityIds.subList(0, preIndex + 1);
if (subActivityIds.size() > 0) {
log.info("sub task id list --> ", subActivityIds);
for (String subTaskId : subActivityIds) {
executedCoordinates.get(subTaskId).setType(TaskCoordinate.TASK_OTHER);
}
}
}
}
}
/**
* 得到list最后一個(gè)activityID的前一個(gè)值相同的小標(biāo)
*
* @param list list
* @param lastStr last activity id
* @return
*/
private int preIndexOfLastTaskId(List<String> list, String lastStr) {
return list.subList(0, list.size() - 1 - 1).lastIndexOf(lastStr);
}
javaBean
@Data
public class TaskCoordinate {
public static final Integer TASK_UNEXECUTED = 0; // 未執(zhí)行
public static final Integer TASK_COMPLETED = 1; // 任務(wù)已完成
public static final Integer TASK_IN_PROCESS = 2; // 任務(wù)進(jìn)行中
public static final Integer TASK_OTHER = 3; // 執(zhí)行過(guò), 可能還會(huì)被執(zhí)行
private String node; // 對(duì)應(yīng)activityId
private String name; // 對(duì)應(yīng)activityName
private Integer type; // 任務(wù)類(lèi)型
private List<TaskInfo> taskInfos;
// 坐標(biāo)
private Integer x;
private Integer y;
private Integer width;
private Integer height;
public TaskCoordinate() {
this.taskInfos = new ArrayList<>();
}
public TaskCoordinate(String node, Integer type) {
this.taskInfos = new ArrayList<>();
this.node = node;
this.type = type;
}
/**
* 給當(dāng)前的流程節(jié)點(diǎn)添加一條任務(wù)信息
*
* @param taskInfo
*/
public void addTaskInfo(TaskInfo taskInfo) {
this.taskInfos.add(taskInfo);
}
/**
* 設(shè)置坐標(biāo)
*
* @param x x
* @param y y
* @param width 寬度
* @param height 高度
*/
public void setCoordinate(int x, int y, int width, int height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class TaskInfo {
private String taskId; // 任務(wù)id
private String assignee; // 辦理人
private Date completeTime; // 完成時(shí)間
}
因?yàn)楝F(xiàn)在需求中的場(chǎng)景比較簡(jiǎn)單, 對(duì)于使用并行網(wǎng)關(guān)的情況并沒(méi)有考慮, 對(duì)于復(fù)雜的流程可能還需要改進(jìn)
北大青鳥(niǎo)APTECH成立于1999年。依托北京大學(xué)優(yōu)質(zhì)雄厚的教育資源和背景,秉承“教育改變生活”的發(fā)展理念,致力于培養(yǎng)中國(guó)IT技能型緊缺人才,是大數(shù)據(jù)專(zhuān)業(yè)的國(guó)家
北大青鳥(niǎo)中博軟件學(xué)院創(chuàng)立于2003年,作為華東區(qū)著名互聯(lián)網(wǎng)學(xué)院和江蘇省首批服務(wù)外包人才培訓(xùn)基地,中博成功培育了近30000名軟件工程師走向高薪崗位,合作企業(yè)超4
中公教育集團(tuán)創(chuàng)建于1999年,經(jīng)過(guò)二十年潛心發(fā)展,已由一家北大畢業(yè)生自主創(chuàng)業(yè)的信息技術(shù)與教育服務(wù)機(jī)構(gòu),發(fā)展為教育服務(wù)業(yè)的綜合性企業(yè)集團(tuán),成為集合面授教學(xué)培訓(xùn)、網(wǎng)
達(dá)內(nèi)教育集團(tuán)成立于2002年,是一家由留學(xué)海歸創(chuàng)辦的高端職業(yè)教育培訓(xùn)機(jī)構(gòu),是中國(guó)一站式人才培養(yǎng)平臺(tái)、一站式人才輸送平臺(tái)。2014年4月3日在美國(guó)成功上市,融資1
曾工作于聯(lián)想擔(dān)任系統(tǒng)開(kāi)發(fā)工程師,曾在博彥科技股份有限公司擔(dān)任項(xiàng)目經(jīng)理從事移動(dòng)互聯(lián)網(wǎng)管理及研發(fā)工作,曾創(chuàng)辦藍(lán)懿科技有限責(zé)任公司從事總經(jīng)理職務(wù)負(fù)責(zé)iOS教學(xué)及管理工作。
浪潮集團(tuán)項(xiàng)目經(jīng)理。精通Java與.NET 技術(shù), 熟練的跨平臺(tái)面向?qū)ο箝_(kāi)發(fā)經(jīng)驗(yàn),技術(shù)功底深厚。 授課風(fēng)格 授課風(fēng)格清新自然、條理清晰、主次分明、重點(diǎn)難點(diǎn)突出、引人入勝。
精通HTML5和CSS3;Javascript及主流js庫(kù),具有快速界面開(kāi)發(fā)的能力,對(duì)瀏覽器兼容性、前端性能優(yōu)化等有深入理解。精通網(wǎng)頁(yè)制作和網(wǎng)頁(yè)游戲開(kāi)發(fā)。
具有10 年的Java 企業(yè)應(yīng)用開(kāi)發(fā)經(jīng)驗(yàn)。曾經(jīng)歷任德國(guó)Software AG 技術(shù)顧問(wèn),美國(guó)Dachieve 系統(tǒng)架構(gòu)師,美國(guó)AngelEngineers Inc. 系統(tǒng)架構(gòu)師。