package com.dawnpro.wcp.process.service.impl;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.impl.RepositoryServiceImpl;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.persistence.entity.TaskEntity;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.impl.pvm.process.ProcessDefinitionImpl;
import org.activiti.engine.impl.pvm.process.TransitionImpl;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.dawnpro.dpframework.component.common.BaseService;
import com.dawnpro.dpframework.component.security.pojo.Staff;
import com.dawnpro.dpframework.component.workflow.exception.WorkFlowException;
import com.dawnpro.wcp.process.service.WcpProcessService;
/**
* @author zhang.wensen1.outs
* @version 2020-9-22
*/
@Service("wcpProcessService")
@Transactional
public class WcpProcessServiceImpl extends BaseService implements WcpProcessService {
private static final Logger log = LoggerFactory.getLogger(WcpProcessServiceImpl.class);
@Autowired
private TaskService taskService;
@Autowired
private HistoryService historyService;
@Autowired
private RepositoryService repositoryService;
@Autowired
private RuntimeService runtimeService;
/**
* 撤回工單
*
* @param proInsId
*/
@Override
public void withdrawTask(String proInsId,String taskKey) {
try {
// 根據流程id查詢代辦任務中流程信息
List<Task> taskList = taskService.createTaskQuery().processInstanceId(proInsId).list();
if (taskList == null || taskList.size()<=0) {
log.error("流程未啓動或已執行完成,無法撤回");
throw new WorkFlowException("流程未啓動或已執行完成,無法撤回", "WorkFlowImpl.startFlow.empty");
}
Task task = null;
for(Task item : taskList) {
if (item.getTaskDefinitionKey().equals(taskKey)) {
task = item;
}
}
if (task == null) {
log.error("流程未啓動或已執行完成,無法撤回");
throw new WorkFlowException("流程未啓動或已執行完成,無法撤回", "WorkFlowImpl.startFlow.empty");
}
Staff staff = super.getOperatorStaff();
String userId = staff.getStaffId()+"";
List<HistoricTaskInstance> htiList = historyService.createHistoricTaskInstanceQuery().processInstanceId(proInsId)
.finished()
.orderByTaskCreateTime()
.desc()
.list();
//判斷上一節點處理人是否爲當前用戶
HistoricTaskInstance hisTask = null;
if(htiList != null && htiList.size()>0) {
HistoricTaskInstance hisTaskObj = htiList.get(0);
if(userId.equals(hisTaskObj.getAssignee())) {
hisTask = hisTaskObj;
}
}
if(null==hisTask || !userId.equals(hisTask.getAssignee())) {
throw new WorkFlowException("該任務非當前用戶提交,無法撤回","WorkFlowImpl.startFlow.empty");
}
// 取回流程接點 當前任務id 取回任務id
callBackProcess(task.getId(), hisTask.getId());
// 刪除歷史流程走向記錄
historyService.deleteHistoricTaskInstance(hisTask.getId());
historyService.deleteHistoricTaskInstance(task.getId());
} catch (Exception e) {
log.error(e + "");
e.printStackTrace();
throw new WorkFlowException("內部服務報錯,請聯繫管理員", "WorkFlowImpl.startFlow.empty");
}
}
/**
* 取回流程
*
* @param taskId 當前任務ID
* @param activityId 取回節點ID
* @throws Exception
*/
public void callBackProcess(String taskId, String activityId) throws Exception {
if (StringUtils.isEmpty(activityId)) {
throw new Exception("目標節點ID爲空!");
}
// 查找所有並行任務節點,同時取回
List<Task> taskList = findTaskListByKey(findProcessInstanceByTaskId(taskId).getId(),
findTaskById(taskId).getTaskDefinitionKey());
for (Task task : taskList) {
commitProcess(task.getId(), null, activityId);
}
}
/**
* 根據任務ID獲取對應的流程實例
*
* @param taskId
* 任務ID
* @return
* @throws Exception
*/
public ProcessInstance findProcessInstanceByTaskId(String taskId)
throws Exception {
// 找到流程實例
ProcessInstance processInstance = runtimeService
.createProcessInstanceQuery().processInstanceId(
findTaskById(taskId).getProcessInstanceId())
.singleResult();
if (processInstance == null) {
throw new Exception("流程實例未找到!");
}
return processInstance;
}
/**
* 根據任務ID獲得任務實例
*
* @param taskId
* 任務ID
* @return
* @throws Exception
*/
private TaskEntity findTaskById(String taskId) throws Exception {
TaskEntity task = (TaskEntity) taskService.createTaskQuery().taskId(
taskId).singleResult();
if (task == null) {
throw new Exception("任務實例未找到!");
}
return task;
}
/**
* 根據流程實例ID和任務key值查詢所有同級任務集合
*
* @param processInstanceId
* @param key
* @return
*/
private List<Task> findTaskListByKey(String processInstanceId, String key) {
return taskService.createTaskQuery().processInstanceId(
processInstanceId).taskDefinitionKey(key).list();
}
/**
* 提交流程/流程轉向
* @param taskId
* 當前任務ID
* @param variables
* 流程變量
* @param activityId
* 流程轉向執行任務節點ID<br>
* 此參數爲空,默認爲提交操作
* @throws Exception
*/
private void commitProcess(String taskId, Map<String, Object> variables,
String activityId) throws Exception {
if (variables == null) {
variables = new HashMap<String, Object>();
}
// 跳轉節點爲空,默認提交操作
if (StringUtils.isEmpty(activityId)) {
taskService.complete(taskId, variables);
} else {// 流程轉向操作
turnTransition(taskId, activityId, variables);
}
}
/**
* 流程轉向操作
*
* @param taskId
* 當前任務ID
* @param activityId
* 目標節點任務ID
* @param variables
* 流程變量
* @throws Exception
*/
private void turnTransition(String taskId, String activityId,
Map<String, Object> variables) throws Exception {
// 當前節點
ActivityImpl currActivity = findActivitiImpl(taskId, null);
// 清空當前流向
List<PvmTransition> oriPvmTransitionList = clearTransition(currActivity);
// 創建新流向
TransitionImpl newTransition = currActivity.createOutgoingTransition();
// 目標節點
ActivityImpl pointActivity = findActivitiImpl(taskId, activityId);
// 設置新流向的目標節點
newTransition.setDestination(pointActivity);
// 執行轉向任務
taskService.complete(taskId, variables);
// 刪除目標節點新流入
pointActivity.getIncomingTransitions().remove(newTransition);
// 還原以前流向
restoreTransition(currActivity, oriPvmTransitionList);
}
/**
* 根據任務ID和節點ID獲取活動節點 <br>
*
* @param taskId
* 任務ID
* @param activityId
* 活動節點ID <br>
* 如果爲null或"",則默認查詢當前活動節點 <br>
* 如果爲"end",則查詢結束節點 <br>
*
* @return
* @throws Exception
*/
private ActivityImpl findActivitiImpl(String taskId, String activityId)
throws Exception {
// 取得流程定義
ProcessDefinitionEntity processDefinition = findProcessDefinitionEntityByTaskId(taskId);
// 獲取當前活動節點ID
if (StringUtils.isEmpty(activityId)) {
activityId = findTaskById(taskId).getTaskDefinitionKey();
}else{
HistoricTaskInstance currTask = historyService
.createHistoricTaskInstanceQuery().taskId(activityId)
.singleResult();
activityId = currTask.getTaskDefinitionKey();
}
// 根據流程定義,獲取該流程實例的結束節點
if (activityId.toUpperCase().equals("END")) {
for (ActivityImpl activityImpl : processDefinition.getActivities()) {
List<PvmTransition> pvmTransitionList = activityImpl
.getOutgoingTransitions();
if (pvmTransitionList.isEmpty()) {
return activityImpl;
}
}
}
// 根據節點ID,獲取對應的活動節點
ActivityImpl activityImpl = ((ProcessDefinitionImpl) processDefinition)
.findActivity(activityId);
return activityImpl;
}
/**
* 根據任務ID獲取流程定義
*
* @param taskId
* 任務ID
* @return
* @throws Exception
*/
public ProcessDefinitionEntity findProcessDefinitionEntityByTaskId(
String taskId) throws Exception {
// 取得流程定義
ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
.getDeployedProcessDefinition(findTaskById(taskId)
.getProcessDefinitionId());
if (processDefinition == null) {
throw new Exception("流程定義未找到!");
}
return processDefinition;
}
/**
* 清空指定活動節點流向
*
* @param activityImpl
* 活動節點
* @return 節點流向集合
*/
private List<PvmTransition> clearTransition(ActivityImpl activityImpl) {
// 存儲當前節點所有流向臨時變量
List<PvmTransition> oriPvmTransitionList = new ArrayList<PvmTransition>();
// 獲取當前節點所有流向,存儲到臨時變量,然後清空
List<PvmTransition> pvmTransitionList = activityImpl
.getOutgoingTransitions();
for (PvmTransition pvmTransition : pvmTransitionList) {
oriPvmTransitionList.add(pvmTransition);
}
pvmTransitionList.clear();
return oriPvmTransitionList;
}
/**
* 還原指定活動節點流向
*
* @param activityImpl
* 活動節點
* @param oriPvmTransitionList
* 原有節點流向集合
*/
private void restoreTransition(ActivityImpl activityImpl,
List<PvmTransition> oriPvmTransitionList) {
// 清空現有流向
List<PvmTransition> pvmTransitionList = activityImpl
.getOutgoingTransitions();
pvmTransitionList.clear();
// 還原以前流向
for (PvmTransition pvmTransition : oriPvmTransitionList) {
pvmTransitionList.add(pvmTransition);
}
}
}