package com.mossle.bpm.web; import java.io.InputStream; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import javax.annotation.Resource; import javax.servlet.http.HttpServletResponse; import com.mossle.api.form.FormDTO; import com.mossle.api.humantask.HumanTaskConnector; import com.mossle.api.humantask.HumanTaskConstants; import com.mossle.api.humantask.HumanTaskDTO; import com.mossle.api.keyvalue.KeyValueConnector; import com.mossle.api.keyvalue.Record; import com.mossle.api.notification.NotificationConnector; import com.mossle.api.notification.NotificationDTO; import com.mossle.api.process.ProcessConnector; import com.mossle.api.tenant.TenantHolder; import com.mossle.api.user.UserConnector; import com.mossle.bpm.cmd.CounterSignCmd; import com.mossle.bpm.cmd.FindHistoryGraphCmd; import com.mossle.bpm.cmd.HistoryProcessInstanceDiagramCmd; import com.mossle.bpm.cmd.ProcessDefinitionDiagramCmd; import com.mossle.bpm.cmd.RollbackTaskCmd; import com.mossle.bpm.graph.Graph; import com.mossle.bpm.persistence.domain.BpmCategory; import com.mossle.bpm.persistence.domain.BpmProcess; import com.mossle.bpm.persistence.manager.BpmCategoryManager; import com.mossle.bpm.persistence.manager.BpmProcessManager; import com.mossle.bpm.service.TraceService; import com.mossle.core.auth.CurrentUserHolder; import com.mossle.core.mapper.JsonMapper; import com.mossle.core.page.Page; import com.mossle.spi.process.InternalProcessConnector; import org.activiti.engine.FormService; import org.activiti.engine.HistoryService; import org.activiti.engine.ProcessEngine; import org.activiti.engine.RepositoryService; import org.activiti.engine.TaskService; import org.activiti.engine.form.StartFormData; import org.activiti.engine.form.TaskFormData; import org.activiti.engine.history.HistoricProcessInstance; import org.activiti.engine.history.HistoricTaskInstance; import org.activiti.engine.impl.identity.Authentication; import org.activiti.engine.impl.interceptor.Command; import org.activiti.engine.repository.ProcessDefinition; import org.activiti.engine.runtime.ProcessInstance; import org.apache.commons.io.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; /** * 我的流程 待办流程 已办未结 */ @Controller @RequestMapping("bpm") public class WorkspaceController { private static Logger logger = LoggerFactory .getLogger(WorkspaceController.class); private BpmCategoryManager bpmCategoryManager; private BpmProcessManager bpmProcessManager; private ProcessEngine processEngine; private UserConnector userConnector; private ProcessConnector processConnector; private CurrentUserHolder currentUserHolder; private TraceService traceService; private TenantHolder tenantHolder; private KeyValueConnector keyValueConnector; private JsonMapper jsonMapper = new JsonMapper(); private HumanTaskConnector humanTaskConnector; private NotificationConnector notificationConnector; private InternalProcessConnector internalProcessConnector; private String baseUrl; @RequestMapping("workspace-home") public String home(Model model) { String tenantId = tenantHolder.getTenantId(); String hql = "from BpmCategory where tenantId=? order by priority"; List<BpmCategory> bpmCategories = bpmCategoryManager .find(hql, tenantId); model.addAttribute("bpmCategories", bpmCategories); return "bpm/workspace-home"; } @RequestMapping("workspace-graphProcessDefinition") public void graphProcessDefinition( @RequestParam("bpmProcessId") Long bpmProcessId, HttpServletResponse response) throws Exception { BpmProcess bpmProcess = bpmProcessManager.get(bpmProcessId); String processDefinitionId = bpmProcess.getBpmConfBase() .getProcessDefinitionId(); Command<InputStream> cmd = null; cmd = new ProcessDefinitionDiagramCmd(processDefinitionId); InputStream is = processEngine.getManagementService().executeCommand( cmd); response.setContentType("image/png"); IOUtils.copy(is, response.getOutputStream()); } // ~ ====================================================================== @RequestMapping("workspace-endProcessInstance") public String endProcessInstance( @RequestParam("processInstanceId") String processInstanceId) { Authentication.setAuthenticatedUserId(currentUserHolder.getUserId()); processEngine.getRuntimeService().deleteProcessInstance( processInstanceId, "人工终止"); return "redirect:/bpm/workspace-listRunningProcessInstances.do"; } @RequestMapping("workspace-copyProcessInstance") public String copyProcessInstance( @RequestParam("processInstanceId") String processInstanceId) throws Exception { // 复制流程 // 1. 从历史获取businessKey HistoricProcessInstance historicProcessInstance = processEngine .getHistoryService().createHistoricProcessInstanceQuery() .processInstanceId(processInstanceId).singleResult(); String businessKey = historicProcessInstance.getBusinessKey(); String processDefinitionId = historicProcessInstance .getProcessDefinitionId(); // 2. 从businessKey获取keyvalue Record original = keyValueConnector.findByCode(businessKey); // 3. 找到流程的第一个form FormDTO formDto = this.processConnector .findStartForm(processDefinitionId); List<String> fieldNames = new ArrayList<String>(); if (formDto.isExists()) { String content = formDto.getContent(); logger.debug("content : {}", content); Map<String, Object> formJson = jsonMapper.fromJson( formDto.getContent(), Map.class); List<Map<String, Object>> sections = (List<Map<String, Object>>) formJson .get("sections"); for (Map<String, Object> section : sections) { if (!"grid".equals(section.get("type"))) { continue; } List<Map<String, Object>> fields = (List<Map<String, Object>>) section .get("fields"); for (Map<String, Object> field : fields) { logger.debug("field : {}", field); String type = (String) field.get("type"); String name = (String) field.get("name"); String label = name; if ("label".equals(type)) { continue; } // if (formField != null) { // continue; // } fieldNames.add(name); } } } logger.debug("fieldNames : {}", fieldNames); // 4. 使用第一个form复制数据,后续的审批意见数据之类的不要复制 Record record = keyValueConnector.copyRecord(original, fieldNames); // 5. 跳转到草稿箱 return "redirect:/operation/process-operation-listDrafts.do"; } /** * 流程列表(所有的流程定义即流程模型) * * @return */ @RequestMapping("workspace-listProcessDefinitions") public String listProcessDefinitions(Model model) { String tenantId = tenantHolder.getTenantId(); RepositoryService repositoryService = processEngine .getRepositoryService(); List<ProcessDefinition> processDefinitions = repositoryService .createProcessDefinitionQuery() .processDefinitionTenantId(tenantId).active().list(); model.addAttribute("processDefinitions", processDefinitions); return "bpm/workspace-listProcessDefinitions"; } @RequestMapping("workspace-listRunningProcessInstances") public String listRunningProcessInstances(@ModelAttribute Page page, Model model) { String userId = currentUserHolder.getUserId(); String tenantId = tenantHolder.getTenantId(); page = processConnector.findRunningProcessInstances(userId, tenantId, page); model.addAttribute("page", page); return "bpm/workspace-listRunningProcessInstances"; } /** * 已结流程. * * @return */ @RequestMapping("workspace-listCompletedProcessInstances") public String listCompletedProcessInstances(@ModelAttribute Page page, Model model) { String userId = currentUserHolder.getUserId(); String tenantId = tenantHolder.getTenantId(); page = processConnector.findCompletedProcessInstances(userId, tenantId, page); model.addAttribute("page", page); return "bpm/workspace-listCompletedProcessInstances"; } /** * 用户参与的流程(包含已经完成和未完成) * * @return */ @RequestMapping("workspace-listInvolvedProcessInstances") public String listInvolvedProcessInstances(@ModelAttribute Page page, Model model) { // TODO: finished(), unfinished() String userId = currentUserHolder.getUserId(); String tenantId = tenantHolder.getTenantId(); page = processConnector.findInvolvedProcessInstances(userId, tenantId, page); model.addAttribute("page", page); return "bpm/workspace-listInvolvedProcessInstances"; } /** * 流程跟踪 * * @throws Exception */ @RequestMapping("workspace-graphHistoryProcessInstance") public void graphHistoryProcessInstance( @RequestParam("processInstanceId") String processInstanceId, HttpServletResponse response) throws Exception { Command<InputStream> cmd = new HistoryProcessInstanceDiagramCmd( processInstanceId); InputStream is = processEngine.getManagementService().executeCommand( cmd); response.setContentType("image/png"); int len = 0; byte[] b = new byte[1024]; while ((len = is.read(b, 0, 1024)) != -1) { response.getOutputStream().write(b, 0, len); } } /** * 待办任务(个人任务) * * @return */ @RequestMapping("workspace-listPersonalTasks") public String listPersonalTasks(@ModelAttribute Page page, Model model) { String userId = currentUserHolder.getUserId(); String tenantId = tenantHolder.getTenantId(); page = processConnector.findPersonalTasks(userId, tenantId, page); model.addAttribute("page", page); return "bpm/workspace-listPersonalTasks"; } /** * 代领任务(组任务) * * @return */ @RequestMapping("workspace-listGroupTasks") public String listGroupTasks(@ModelAttribute Page page, Model model) { String userId = currentUserHolder.getUserId(); String tenantId = tenantHolder.getTenantId(); page = processConnector.findGroupTasks(userId, tenantId, page); model.addAttribute("page", page); return "bpm/workspace-listGroupTasks"; } /** * 已办任务(历史任务) * * @return */ @RequestMapping("workspace-listHistoryTasks") public String listHistoryTasks(@ModelAttribute Page page, Model model) { String userId = currentUserHolder.getUserId(); String tenantId = tenantHolder.getTenantId(); page = processConnector.findHistoryTasks(userId, tenantId, page); model.addAttribute("page", page); return "bpm/workspace-listHistoryTasks"; } /** * 代理中的任务(代理人还未完成该任务) * * @return */ @RequestMapping("workspace-listDelegatedTasks") public String listDelegatedTasks(@ModelAttribute Page page, Model model) { String userId = currentUserHolder.getUserId(); String tenantId = tenantHolder.getTenantId(); page = processConnector.findGroupTasks(userId, tenantId, page); model.addAttribute("page", page); return "bpm/workspace-listDelegatedTasks"; } /** * 同时返回已领取和未领取的任务. */ @RequestMapping("workspace-listCandidateOrAssignedTasks") public String listCandidateOrAssignedTasks(@ModelAttribute Page page, Model model) { String userId = currentUserHolder.getUserId(); String tenantId = tenantHolder.getTenantId(); page = processConnector.findCandidateOrAssignedTasks(userId, tenantId, page); model.addAttribute("page", page); return "bpm/workspace-listCandidateOrAssignedTasks"; } // ~ ====================================================================== /** * 发起流程页面(启动一个流程实例)内置流程表单方式 * * @return */ @RequestMapping("workspace-prepareStartProcessInstance") public String prepareStartProcessInstance( @RequestParam("processDefinitionId") String processDefinitionId, Model model) { FormService formService = processEngine.getFormService(); StartFormData startFormData = formService .getStartFormData(processDefinitionId); model.addAttribute("startFormData", startFormData); return "bpm/workspace prepareStartProcessInstance"; } // ~ ====================================================================== /** * 完成任务页面 * * @return */ @RequestMapping("workspace-prepareCompleteTask") public String prepareCompleteTask(@RequestParam("taskId") String taskId, Model model) { FormService formService = processEngine.getFormService(); TaskFormData taskFormData = formService.getTaskFormData(taskId); model.addAttribute("taskFormData", taskFormData); return "bpm/workspace-prepareCompleteTask"; } /** * 认领任务(对应的是在组任务,即从组任务中领取任务) * * @return */ @RequestMapping("workspace-claimTask") public String claimTask(@RequestParam("taskId") String taskId) { String userId = currentUserHolder.getUserId(); TaskService taskService = processEngine.getTaskService(); taskService.claim(taskId, userId); return "redirect:/bpm/workspace-listPersonalTasks.do"; } /** * 任务代理页面 * * @return */ @RequestMapping("workspace-prepareDelegateTask") public String prepareDelegateTask() { return "bpm/workspace-prepareDelegateTask"; } /** * 任务代理 * * @return */ @RequestMapping("workspace-delegateTask") public String delegateTask(@RequestParam("taskId") String taskId, @RequestParam("userId") String userId) { TaskService taskService = processEngine.getTaskService(); taskService.delegateTask(taskId, userId); return "redirect:/bpm/workspace-listPersonalTasks.do"; } /** * TODO 该方法有用到? * * @return */ @RequestMapping("workspace-resolveTask") public String resolveTask(@RequestParam("taskId") String taskId) { TaskService taskService = processEngine.getTaskService(); taskService.resolveTask(taskId); return "redirect:/bpm/workspace-listPersonalTasks.do"; } /** * 查看历史【包含流程跟踪、任务列表(完成和未完成)、流程变量】. */ @RequestMapping("workspace-viewHistory") public String viewHistory( @RequestParam("processInstanceId") String processInstanceId, Model model) { String userId = currentUserHolder.getUserId(); HistoryService historyService = processEngine.getHistoryService(); HistoricProcessInstance historicProcessInstance = historyService .createHistoricProcessInstanceQuery() .processInstanceId(processInstanceId).singleResult(); if (userId.equals(historicProcessInstance.getStartUserId())) { // startForm } List<HistoricTaskInstance> historicTasks = historyService .createHistoricTaskInstanceQuery() .processInstanceId(processInstanceId).list(); // List<HistoricVariableInstance> historicVariableInstances = historyService // .createHistoricVariableInstanceQuery() // .processInstanceId(processInstanceId).list(); model.addAttribute("historicTasks", historicTasks); // 获取流程对应的所有人工任务(目前还没有区分历史) List<HumanTaskDTO> humanTasks = humanTaskConnector .findHumanTasksByProcessInstanceId(processInstanceId); List<HumanTaskDTO> humanTaskDtos = new ArrayList<HumanTaskDTO>(); for (HumanTaskDTO humanTaskDto : humanTasks) { if (humanTaskDto.getParentId() != null) { continue; } humanTaskDtos.add(humanTaskDto); } model.addAttribute("humanTasks", humanTaskDtos); // model.addAttribute("historicVariableInstances", // historicVariableInstances); model.addAttribute("nodeDtos", traceService.traceProcessInstance(processInstanceId)); model.addAttribute("historyActivities", processEngine .getHistoryService().createHistoricActivityInstanceQuery() .processInstanceId(processInstanceId).list()); if (historicProcessInstance.getEndTime() == null) { model.addAttribute("currentActivities", processEngine .getRuntimeService() .getActiveActivityIds(processInstanceId)); } else { model.addAttribute("currentActivities", Collections .singletonList(historicProcessInstance.getEndActivityId())); } Graph graph = processEngine.getManagementService().executeCommand( new FindHistoryGraphCmd(processInstanceId)); model.addAttribute("graph", graph); model.addAttribute("historicProcessInstance", historicProcessInstance); return "bpm/workspace-viewHistory"; } // ~ ==================================国内特色流程==================================== /** * 回退任务 * * @return */ @RequestMapping("workspace-rollback") public String rollback(@RequestParam("taskId") String taskId) { Command<Object> cmd = new RollbackTaskCmd(taskId, null); processEngine.getManagementService().executeCommand(cmd); return "redirect:/bpm/workspace-listPersonalTasks.do"; } /** * 撤销任务 * * @return */ /* * @RequestMapping("workspace-withdraw") public String withdraw(@RequestParam("taskId") String taskId) { * Command<Integer> cmd = new WithdrawTaskCmd(taskId); * * processEngine.getManagementService().executeCommand(cmd); * * return "redirect:/bpm/workspace-listPersonalTasks.do"; } */ /** * 准备加减签. */ @RequestMapping("workspace-changeCounterSign") public String changeCounterSign() { return "bpm/workspace-changeCounterSign"; } /** * 进行加减签. */ @RequestMapping("workspace-saveCounterSign") public String saveCounterSign( @RequestParam("operationType") String operationType, @RequestParam("userId") String userId, @RequestParam("taskId") String taskId) { CounterSignCmd cmd = new CounterSignCmd(operationType, userId, taskId); processEngine.getManagementService().executeCommand(cmd); return "redirect:/bpm/workspace-listPersonalTasks.do"; } /** * 转发已结流程. */ @RequestMapping("workspace-transferProcessInstance") public String transferProcessInstance( @RequestParam("processInstanceId") String processInstanceId, @RequestParam("assignee") String assignee) { String tenantId = tenantHolder.getTenantId(); // 1. 找到历史 HistoricProcessInstance historicProcessInstance = processEngine .getHistoryService().createHistoricProcessInstanceQuery() .processInstanceId(processInstanceId).singleResult(); // 2. 创建一个任务,设置为未读,转发状态 HumanTaskDTO humanTaskDto = humanTaskConnector.createHumanTask(); humanTaskDto.setProcessInstanceId(processInstanceId); humanTaskDto.setPresentationSubject(historicProcessInstance.getName()); humanTaskDto.setAssignee(assignee); humanTaskDto.setTenantId(tenantId); // TODO: 还没有字段 // humanTaskDto.setCopyStatus("unread"); humanTaskDto.setCatalog(HumanTaskConstants.CATALOG_COPY); humanTaskDto.setAction("unread"); humanTaskDto.setBusinessKey(historicProcessInstance.getBusinessKey()); humanTaskDto.setProcessDefinitionId(historicProcessInstance .getProcessDefinitionId()); try { // TODO: 等到流程支持viewFormKey,才能设置。目前做不到 List<HistoricTaskInstance> historicTaskInstances = processEngine .getHistoryService().createHistoricTaskInstanceQuery() .processInstanceId(processInstanceId).list(); HistoricTaskInstance historicTaskInstance = historicTaskInstances .get(0); humanTaskDto.setForm(historicTaskInstance.getFormKey()); humanTaskDto.setName(historicTaskInstance.getName()); } catch (Exception ex) { logger.error(ex.getMessage(), ex); } humanTaskConnector.saveHumanTask(humanTaskDto); // 3. 把任务分配给对应的人员 return "redirect:/bpm/workspace-listCompletedProcessInstances.do"; } /** * 催办. */ @RequestMapping("workspace-remind") public String remind( @RequestParam("processInstanceId") String processInstanceId, @RequestParam("userId") String userId, @RequestParam("comment") String comment) { List<HumanTaskDTO> humanTaskDtos = humanTaskConnector .findHumanTasksByProcessInstanceId(processInstanceId); logger.debug("processInstanceId : {}", processInstanceId); logger.debug("humanTaskDtos : {}", humanTaskDtos); for (HumanTaskDTO humanTaskDto : humanTaskDtos) { if (humanTaskDto.getCompleteTime() != null) { continue; } String assignee = humanTaskDto.getAssignee(); logger.debug("remind {}", assignee); NotificationDTO notificationDto = new NotificationDTO(); notificationDto.setSender(currentUserHolder.getUserId()); notificationDto.setReceiver(assignee); notificationDto.setReceiverType("userid"); notificationDto.getTypes().add("msg"); notificationDto.getTypes().add("email"); notificationDto.setSubject("请尽快办理 " + humanTaskDto.getPresentationSubject()); String url = baseUrl + "/operation/task-operation-viewTaskForm.do?humanTaskId=" + humanTaskDto.getId(); String content = "请尽快办理 " + humanTaskDto.getPresentationSubject() + "<p><a href='" + url + "'>" + url + "</a></p>"; notificationDto.setContent(content); notificationConnector.send(notificationDto, "1"); } return "redirect:/bpm/workspace-listRunningProcessInstances.do"; } /** * 跳过. */ @RequestMapping("workspace-skip") public String skip( @RequestParam("processInstanceId") String processInstanceId, @RequestParam("userId") String userId, @RequestParam("comment") String comment) { List<HumanTaskDTO> humanTaskDtos = humanTaskConnector .findHumanTasksByProcessInstanceId(processInstanceId); logger.debug("processInstanceId : {}", processInstanceId); logger.debug("humanTaskDtos : {}", humanTaskDtos); for (HumanTaskDTO humanTaskDto : humanTaskDtos) { if (humanTaskDto.getCompleteTime() != null) { continue; } String humanTaskId = humanTaskDto.getId(); humanTaskConnector.skip(humanTaskId, currentUserHolder.getUserId(), comment); } return "redirect:/bpm/workspace-listRunningProcessInstances.do"; } /** * 撤销. */ @RequestMapping("workspace-withdraw") public String withdraw( @RequestParam("processInstanceId") String processInstanceId) { logger.debug("processInstanceId : {}", processInstanceId); ProcessInstance processInstance = processEngine.getRuntimeService() .createProcessInstanceQuery() .processInstanceId(processInstanceId).singleResult(); String initiator = ""; String firstUserTaskActivityId = internalProcessConnector .findFirstUserTaskActivityId( processInstance.getProcessDefinitionId(), initiator); logger.debug("firstUserTaskActivityId : {}", firstUserTaskActivityId); List<HistoricTaskInstance> historicTaskInstances = processEngine .getHistoryService().createHistoricTaskInstanceQuery() .processInstanceId(processInstanceId) .taskDefinitionKey(firstUserTaskActivityId).list(); HistoricTaskInstance historicTaskInstance = historicTaskInstances .get(0); String taskId = historicTaskInstance.getId(); HumanTaskDTO humanTaskDto = humanTaskConnector .findHumanTaskByTaskId(taskId); String comment = ""; humanTaskConnector.withdraw(humanTaskDto.getId(), comment); return "redirect:/bpm/workspace-listRunningProcessInstances.do"; } // ~ ====================================================================== @Resource public void setBpmCategoryManager(BpmCategoryManager bpmCategoryManager) { this.bpmCategoryManager = bpmCategoryManager; } @Resource public void setBpmProcessManager(BpmProcessManager bpmProcessManager) { this.bpmProcessManager = bpmProcessManager; } @Resource public void setProcessEngine(ProcessEngine processEngine) { this.processEngine = processEngine; } @Resource public void setUserConnector(UserConnector userConnector) { this.userConnector = userConnector; } @Resource public void setProcessConnector(ProcessConnector processConnector) { this.processConnector = processConnector; } @Resource public void setCurrentUserHolder(CurrentUserHolder currentUserHolder) { this.currentUserHolder = currentUserHolder; } @Resource public void setTraceService(TraceService traceService) { this.traceService = traceService; } @Resource public void setTenantHolder(TenantHolder tenantHolder) { this.tenantHolder = tenantHolder; } @Resource public void setKeyValueConnector(KeyValueConnector keyValueConnector) { this.keyValueConnector = keyValueConnector; } @Resource public void setHumanTaskConnector(HumanTaskConnector humanTaskConnector) { this.humanTaskConnector = humanTaskConnector; } @Resource public void setNotificationConnector( NotificationConnector notificationConnector) { this.notificationConnector = notificationConnector; } @Resource public void setInternalProcessConnector( InternalProcessConnector internalProcessConnector) { this.internalProcessConnector = internalProcessConnector; } @Value("${application.baseUrl}") public void setBaseUrl(String baseUrl) { this.baseUrl = baseUrl; } }