add 添加流程办理,流程待办,已办分页查询

This commit is contained in:
songgaoshuai 2023-06-08 12:33:48 +08:00
parent fbbf981b12
commit e69e9d3087
9 changed files with 344 additions and 7 deletions

View File

@ -13,4 +13,6 @@ public interface FlowConstant {
*/ */
String NAMESPACE = "http://b3mn.org/stencilset/bpmn2.0#"; String NAMESPACE = "http://b3mn.org/stencilset/bpmn2.0#";
String MESSAGE_CURRENT_TASK_IS_NULL = "当前任务不存在或你不是任务办理人";
} }

View File

@ -101,7 +101,7 @@ public class ActModelController extends BaseController {
* @param modelId 模型id * @param modelId 模型id
*/ */
@GetMapping("/rest/models/{modelId}/editor/json") @GetMapping("/rest/models/{modelId}/editor/json")
public ObjectNode getModelInfo(@PathVariable String modelId) { public ObjectNode getModelInfo(@NotBlank(message = "模型id不能为空") @PathVariable String modelId) {
return iActModelService.getModelInfo(modelId); return iActModelService.getModelInfo(modelId);
} }

View File

@ -97,7 +97,7 @@ public class ActProcessDefinitionController extends BaseController {
*/ */
@Log(title = "流程定义管理", businessType = BusinessType.UPDATE) @Log(title = "流程定义管理", businessType = BusinessType.UPDATE)
@PutMapping("/updateProcessDefState/{processDefinitionId}") @PutMapping("/updateProcessDefState/{processDefinitionId}")
public R<Void> updateProcDefState(@PathVariable String processDefinitionId) { public R<Void> updateProcDefState(@NotBlank(message = "流程定义id不能为空") @PathVariable String processDefinitionId) {
return toAjax(iActProcessDefinitionService.updateProcessDefState(processDefinitionId)); return toAjax(iActProcessDefinitionService.updateProcessDefState(processDefinitionId));
} }
@ -109,7 +109,8 @@ public class ActProcessDefinitionController extends BaseController {
*/ */
@Log(title = "流程定义管理", businessType = BusinessType.UPDATE) @Log(title = "流程定义管理", businessType = BusinessType.UPDATE)
@PutMapping("/migrationProcessDefinition/{currentProcessDefinitionId}/{fromProcessDefinitionId}") @PutMapping("/migrationProcessDefinition/{currentProcessDefinitionId}/{fromProcessDefinitionId}")
public R<Void> migrationProcessDefinition(@PathVariable String currentProcessDefinitionId, @PathVariable String fromProcessDefinitionId) { public R<Void> migrationProcessDefinition(@NotBlank(message = "当前流程定义id") @PathVariable String currentProcessDefinitionId,
@NotBlank(message = "需要迁移到的流程定义id") @PathVariable String fromProcessDefinitionId) {
return toAjax(iActProcessDefinitionService.migrationProcessDefinition(currentProcessDefinitionId, fromProcessDefinitionId)); return toAjax(iActProcessDefinitionService.migrationProcessDefinition(currentProcessDefinitionId, fromProcessDefinitionId));
} }

View File

@ -2,10 +2,16 @@ package org.dromara.workflow.controller;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.dromara.common.core.domain.R; import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.idempotent.annotation.RepeatSubmit; import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log; import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType; import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.web.core.BaseController;
import org.dromara.workflow.domain.bo.CompleteTaskBo;
import org.dromara.workflow.domain.bo.StartProcessBo; import org.dromara.workflow.domain.bo.StartProcessBo;
import org.dromara.workflow.domain.bo.TaskBo;
import org.dromara.workflow.domain.vo.TaskVo;
import org.dromara.workflow.service.IActTaskService; import org.dromara.workflow.service.IActTaskService;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@ -21,7 +27,7 @@ import java.util.Map;
@RequiredArgsConstructor @RequiredArgsConstructor
@RestController @RestController
@RequestMapping("/workflow/task") @RequestMapping("/workflow/task")
public class ActTaskController { public class ActTaskController extends BaseController {
private final IActTaskService iActTaskService; private final IActTaskService iActTaskService;
@ -38,4 +44,36 @@ public class ActTaskController {
Map<String, Object> map = iActTaskService.startWorkFlow(startProcessBo); Map<String, Object> map = iActTaskService.startWorkFlow(startProcessBo);
return R.ok("提交成功", map); return R.ok("提交成功", map);
} }
/**
* 办理任务
*
* @param completeTaskBo 办理任务参数
*/
@Log(title = "任务管理", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/completeTask")
public R<Void> completeTask(@Validated(AddGroup.class) @RequestBody CompleteTaskBo completeTaskBo) {
return toAjax(iActTaskService.completeTask(completeTaskBo));
}
/**
* 查询当前用户的待办任务
*
* @param taskBo 参数
*/
@GetMapping("/getTaskWaitByPage")
public TableDataInfo<TaskVo> getTaskWaitByPage(TaskBo taskBo) {
return iActTaskService.getTaskWaitByPage(taskBo);
}
/**
* 查询当前用户的已办任务
*
* @param taskBo 参数
*/
@GetMapping("/getTaskFinishByPage")
public TableDataInfo<TaskVo> getTaskFinishByPage(TaskBo taskBo) {
return iActTaskService.getTaskFinishByPage(taskBo);
}
} }

View File

@ -0,0 +1,48 @@
package org.dromara.workflow.domain.bo;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import org.dromara.common.core.validate.AddGroup;
import java.io.Serial;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
/**
* 办理任务请求对象
*
* @author may
*/
@Data
public class CompleteTaskBo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 任务id
*/
@NotBlank(message = "任务id不能为空", groups = {AddGroup.class})
private String taskId;
/**
* 办理意见
*/
private String message;
/**
* 流程变量
*/
private Map<String, Object> variables;
public Map<String, Object> getVariables() {
if (variables == null) {
return new HashMap<>(16);
}
variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue()));
return variables;
}
}

View File

@ -0,0 +1,26 @@
package org.dromara.workflow.domain.bo;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.workflow.common.PageEntity;
import java.io.Serial;
import java.io.Serializable;
/**
* 任务请求对象
*
* @author may
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class TaskBo extends PageEntity implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 任务名称
*/
private String name;
}

View File

@ -0,0 +1,99 @@
package org.dromara.workflow.domain.vo;
import lombok.Data;
import java.util.Date;
/**
* 任务视图
*
* @author may
*/
@Data
public class TaskVo {
/**
* 任务id
*/
private String id;
/**
* 任务名称
*/
private String name;
/**
* 描述
*/
private String description;
/**
* 优先级
*/
private Integer priority;
/**
* 负责此任务的人员的用户id
*/
private String owner;
/**
* 办理人id
*/
private String assignee;
/**
* 流程实例id
*/
private String processInstanceId;
/**
* 执行id
*/
private String executionId;
/**
* 无用
*/
private String taskDefinitionId;
/**
* 流程定义id
*/
private String processDefinitionId;
/**
* 创建时间
*/
private Date createTime;
/**
* 节点id
*/
private String taskDefinitionKey;
/**
* 任务截止日期
*/
private Date dueDate;
/**
* 流程类别
*/
private String category;
/**
* 父级任务id
*/
private String parentTaskId;
/**
* 租户id
*/
private String tenantId;
/**
* 认领时间
*/
private Date claimTime;
}

View File

@ -1,6 +1,10 @@
package org.dromara.workflow.service; package org.dromara.workflow.service;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.workflow.domain.bo.CompleteTaskBo;
import org.dromara.workflow.domain.bo.StartProcessBo; import org.dromara.workflow.domain.bo.StartProcessBo;
import org.dromara.workflow.domain.bo.TaskBo;
import org.dromara.workflow.domain.vo.TaskVo;
import java.util.Map; import java.util.Map;
@ -17,4 +21,29 @@ public interface IActTaskService {
* @return 结果 * @return 结果
*/ */
Map<String, Object> startWorkFlow(StartProcessBo startProcessBo); Map<String, Object> startWorkFlow(StartProcessBo startProcessBo);
/**
* 办理任务
*
* @param completeTaskBo 办理任务参数
* @return 结果
*/
boolean completeTask(CompleteTaskBo completeTaskBo);
/**
* 查询当前用户的待办任务
*
* @param taskBo 参数
* @return 结果
*/
TableDataInfo<TaskVo> getTaskWaitByPage(TaskBo taskBo);
/**
* 查询当前用户的已办任务
*
* @param taskBo 参数
* @return 结果
*/
TableDataInfo<TaskVo> getTaskFinishByPage(TaskBo taskBo);
} }

View File

@ -1,12 +1,19 @@
package org.dromara.workflow.service.impl; package org.dromara.workflow.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.dromara.common.core.domain.dto.RoleDTO;
import org.dromara.common.core.exception.ServiceException; import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.StringUtils; import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper; import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.tenant.helper.TenantHelper; import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.workflow.common.constant.FlowConstant;
import org.dromara.workflow.domain.bo.CompleteTaskBo;
import org.dromara.workflow.domain.bo.StartProcessBo; import org.dromara.workflow.domain.bo.StartProcessBo;
import org.dromara.workflow.domain.bo.TaskBo;
import org.dromara.workflow.domain.vo.TaskVo;
import org.dromara.workflow.service.IActTaskService; import org.dromara.workflow.service.IActTaskService;
import org.flowable.common.engine.impl.identity.Authentication; import org.flowable.common.engine.impl.identity.Authentication;
import org.flowable.engine.HistoryService; import org.flowable.engine.HistoryService;
@ -16,11 +23,16 @@ import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.runtime.ProcessInstance; import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task; import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery; import org.flowable.task.api.TaskQuery;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.task.api.history.HistoricTaskInstanceQuery;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors;
/** /**
* 任务 服务层实现 * 任务 服务层实现
@ -47,9 +59,10 @@ public class ActTaskServiceImpl implements IActTaskService {
throw new ServiceException("启动工作流时必须包含业务ID"); throw new ServiceException("启动工作流时必须包含业务ID");
} }
// 判断当前业务是否启动过流程 // 判断当前业务是否启动过流程
List<HistoricProcessInstance> instanceList = historyService.createHistoricProcessInstanceQuery().processInstanceBusinessKey(startProcessBo.getBusinessKey()).list(); List<HistoricProcessInstance> instanceList = historyService.createHistoricProcessInstanceQuery()
.processInstanceBusinessKey(startProcessBo.getBusinessKey()).processInstanceTenantIdLike(TenantHelper.getTenantId()).list();
TaskQuery taskQuery = taskService.createTaskQuery(); TaskQuery taskQuery = taskService.createTaskQuery();
List<Task> taskResult = taskQuery.processInstanceBusinessKey(startProcessBo.getBusinessKey()).list(); List<Task> taskResult = taskQuery.processInstanceBusinessKey(startProcessBo.getBusinessKey()).taskTenantId(TenantHelper.getTenantId()).list();
if (CollUtil.isNotEmpty(instanceList)) { if (CollUtil.isNotEmpty(instanceList)) {
map.put("processInstanceId", taskResult.get(0).getProcessInstanceId()); map.put("processInstanceId", taskResult.get(0).getProcessInstanceId());
map.put("taskId", taskResult.get(0).getId()); map.put("taskId", taskResult.get(0).getId());
@ -70,7 +83,7 @@ public class ActTaskServiceImpl implements IActTaskService {
// 将流程定义名称 作为 流程实例名称 // 将流程定义名称 作为 流程实例名称
runtimeService.setProcessInstanceName(pi.getProcessInstanceId(), pi.getProcessDefinitionName()); runtimeService.setProcessInstanceName(pi.getProcessInstanceId(), pi.getProcessDefinitionName());
// 申请人执行流程 // 申请人执行流程
List<Task> taskList = taskService.createTaskQuery().processInstanceId(pi.getId()).list(); List<Task> taskList = taskService.createTaskQuery().processInstanceId(pi.getId()).taskTenantId(TenantHelper.getTenantId()).list();
if (taskList.size() > 1) { if (taskList.size() > 1) {
throw new ServiceException("请检查流程第一个环节是否为申请人!"); throw new ServiceException("请检查流程第一个环节是否为申请人!");
} }
@ -80,4 +93,85 @@ public class ActTaskServiceImpl implements IActTaskService {
map.put("taskId", taskList.get(0).getId()); map.put("taskId", taskList.get(0).getId());
return map; return map;
} }
/**
* 办理任务
*
* @param completeTaskBo 办理任务参数
*/
@Override
@Transactional(rollbackFor = Exception.class)
public boolean completeTask(CompleteTaskBo completeTaskBo) {
try {
List<RoleDTO> roles = LoginHelper.getLoginUser().getRoles();
String userId = LoginHelper.getUserId().toString();
TaskQuery taskQuery = taskService.createTaskQuery();
taskQuery.taskId(completeTaskBo.getTaskId())
.taskTenantId(TenantHelper.getTenantId()).taskCandidateOrAssigned(userId);
if (CollUtil.isNotEmpty(roles)) {
List<String> groupIds = roles.stream().map(e -> String.valueOf(e.getRoleId())).collect(Collectors.toList());
taskQuery.taskCandidateGroupIn(groupIds);
}
Task task = taskQuery.singleResult();
if (task == null) {
throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL);
}
//办理任务
taskService.complete(completeTaskBo.getTaskId(), completeTaskBo.getVariables());
//办理意见
taskService.addComment(completeTaskBo.getTaskId(), task.getProcessInstanceId(), StringUtils.isBlank(completeTaskBo.getMessage()) ? "同意" : completeTaskBo.getMessage());
return true;
} catch (Exception e) {
throw new ServiceException(e.getMessage());
}
}
/**
* 查询当前用户的待办任务
*
* @param taskBo 参数
*/
@Override
public TableDataInfo<TaskVo> getTaskWaitByPage(TaskBo taskBo) {
List<RoleDTO> roles = LoginHelper.getLoginUser().getRoles();
String userId = LoginHelper.getUserId().toString();
TaskQuery query = taskService.createTaskQuery();
query.taskTenantId(TenantHelper.getTenantId()).taskCandidateOrAssigned(userId);
if (CollUtil.isNotEmpty(roles)) {
List<String> groupIds = roles.stream().map(e -> String.valueOf(e.getRoleId())).collect(Collectors.toList());
query.taskCandidateGroupIn(groupIds);
}
if (StringUtils.isNotBlank(taskBo.getName())) {
query.taskNameLike(taskBo.getName());
}
List<Task> taskList = query.listPage(taskBo.getPageNum(), taskBo.getPageSize());
List<TaskVo> list = new ArrayList<>();
for (Task task : taskList) {
list.add(BeanUtil.toBean(task, TaskVo.class));
}
long count = query.count();
return new TableDataInfo<>(list, count);
}
/**
* 查询当前用户的已办任务
*
* @param taskBo 参数
*/
@Override
public TableDataInfo<TaskVo> getTaskFinishByPage(TaskBo taskBo) {
String userId = LoginHelper.getUserId().toString();
HistoricTaskInstanceQuery query = historyService.createHistoricTaskInstanceQuery()
.taskAssignee(userId).taskTenantId(TenantHelper.getTenantId()).finished().orderByHistoricTaskInstanceStartTime().asc();
if (StringUtils.isNotBlank(taskBo.getName())) {
query.taskNameLike(taskBo.getName());
}
List<HistoricTaskInstance> taskInstanceList = query.listPage(taskBo.getPageNum(), taskBo.getPageSize());
List<TaskVo> list = new ArrayList<>();
for (HistoricTaskInstance task : taskInstanceList) {
list.add(BeanUtil.toBean(task, TaskVo.class));
}
long count = query.count();
return new TableDataInfo<>(list, count);
}
} }