|
|
@@ -3,6 +3,7 @@ package com.vber.workflow.service.impl;
|
|
|
import cn.hutool.core.bean.BeanUtil;
|
|
|
import cn.hutool.core.collection.CollUtil;
|
|
|
import cn.hutool.core.convert.Convert;
|
|
|
+import cn.hutool.core.lang.Dict;
|
|
|
import cn.hutool.core.util.ObjectUtil;
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
|
|
@@ -19,6 +20,7 @@ import com.vber.common.core.utils.StringUtils;
|
|
|
import com.vber.common.core.utils.ValidatorUtils;
|
|
|
import com.vber.common.core.validate.AddGroup;
|
|
|
import com.vber.common.core.validate.EditGroup;
|
|
|
+import com.vber.common.json.utils.JsonUtils;
|
|
|
import com.vber.common.mybatis.core.page.PageQuery;
|
|
|
import com.vber.common.mybatis.core.page.TableDataInfo;
|
|
|
import com.vber.common.satoken.utils.LoginHelper;
|
|
|
@@ -42,14 +44,12 @@ import org.dromara.warm.flow.core.dto.FlowParams;
|
|
|
import org.dromara.warm.flow.core.entity.*;
|
|
|
import org.dromara.warm.flow.core.enums.NodeType;
|
|
|
import org.dromara.warm.flow.core.enums.SkipType;
|
|
|
+import org.dromara.warm.flow.core.enums.UserType;
|
|
|
import org.dromara.warm.flow.core.service.*;
|
|
|
import org.dromara.warm.flow.core.utils.ExpressionUtil;
|
|
|
import org.dromara.warm.flow.core.utils.MapUtil;
|
|
|
import org.dromara.warm.flow.orm.entity.*;
|
|
|
-import org.dromara.warm.flow.orm.mapper.FlowHisTaskMapper;
|
|
|
-import org.dromara.warm.flow.orm.mapper.FlowInstanceMapper;
|
|
|
-import org.dromara.warm.flow.orm.mapper.FlowNodeMapper;
|
|
|
-import org.dromara.warm.flow.orm.mapper.FlowTaskMapper;
|
|
|
+import org.dromara.warm.flow.orm.mapper.*;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
|
@@ -61,7 +61,7 @@ import static com.vber.workflow.common.constant.FlowConstant.*;
|
|
|
/**
|
|
|
* 任务 服务层实现
|
|
|
*
|
|
|
- * @author may
|
|
|
+ * @author Iwb
|
|
|
*/
|
|
|
@ConditionalOnEnable
|
|
|
@Slf4j
|
|
|
@@ -85,6 +85,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
|
|
private final IFlwTaskAssigneeService flwTaskAssigneeService;
|
|
|
private final IFlwCommonService flwCommonService;
|
|
|
private final IFlwNodeExtService flwNodeExtService;
|
|
|
+ private final FlowDefinitionMapper flowDefinitionMapper;
|
|
|
|
|
|
/**
|
|
|
* 启动任务
|
|
|
@@ -102,7 +103,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
|
|
Map<String, Object> variables = startProcessBo.getVariables();
|
|
|
// 流程发起人
|
|
|
variables.put(INITIATOR, LoginHelper.getUserIdStr());
|
|
|
- // 发起人组织机构id
|
|
|
+ // 发起人部门id
|
|
|
variables.put(INITIATOR_ORG_ID, LoginHelper.getOrgId());
|
|
|
// 业务id
|
|
|
variables.put(BUSINESS_ID, businessId);
|
|
|
@@ -118,6 +119,12 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
|
|
dto.setTaskId(taskList.get(0).getId());
|
|
|
return dto;
|
|
|
}
|
|
|
+ // 将流程定义内的扩展参数设置到变量中
|
|
|
+ Definition definition = FlowEngine.defService().getPublishByFlowCode(startProcessBo.getFlowCode());
|
|
|
+ Dict dict = JsonUtils.parseMap(definition.getExt());
|
|
|
+ boolean autoPass = !ObjectUtil.isNull(dict) && dict.getBool(FlowConstant.AUTO_PASS);
|
|
|
+ variables.put(FlowConstant.AUTO_PASS, autoPass);
|
|
|
+
|
|
|
FlowParams flowParams = FlowParams.build()
|
|
|
.flowCode(startProcessBo.getFlowCode())
|
|
|
.variable(startProcessBo.getVariables())
|
|
|
@@ -155,11 +162,12 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
|
|
// 获取抄送人
|
|
|
List<FlowCopyBo> flowCopyList = completeTaskBo.getFlowCopyList();
|
|
|
// 设置抄送人
|
|
|
- completeTaskBo.getVariables().put(FlowConstant.FLOW_COPY_LIST, flowCopyList);
|
|
|
+ Map<String, Object> variables = completeTaskBo.getVariables();
|
|
|
+ variables.put(FlowConstant.FLOW_COPY_LIST, flowCopyList);
|
|
|
// 消息类型
|
|
|
- completeTaskBo.getVariables().put(FlowConstant.MESSAGE_TYPE, messageType);
|
|
|
+ variables.put(FlowConstant.MESSAGE_TYPE, messageType);
|
|
|
// 消息通知
|
|
|
- completeTaskBo.getVariables().put(FlowConstant.MESSAGE_NOTICE, notice);
|
|
|
+ variables.put(FlowConstant.MESSAGE_NOTICE, notice);
|
|
|
|
|
|
|
|
|
FlowTask flowTask = flowTaskMapper.selectById(taskId);
|
|
|
@@ -169,23 +177,23 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
|
|
Instance ins = insService.getById(flowTask.getInstanceId());
|
|
|
// 检查流程状态是否为草稿、已撤销或已退回状态,若是则执行流程提交监听
|
|
|
if (BusinessStatusEnum.isDraftOrCancelOrBack(ins.getFlowStatus())) {
|
|
|
- completeTaskBo.getVariables().put(FlowConstant.SUBMIT, true);
|
|
|
+ variables.put(FlowConstant.SUBMIT, true);
|
|
|
}
|
|
|
// 设置弹窗处理人
|
|
|
Map<String, Object> assigneeMap = setPopAssigneeMap(completeTaskBo.getAssigneeMap(), ins.getVariableMap());
|
|
|
if (CollUtil.isNotEmpty(assigneeMap)) {
|
|
|
- completeTaskBo.getVariables().putAll(assigneeMap);
|
|
|
+ variables.putAll(assigneeMap);
|
|
|
}
|
|
|
// 构建流程参数,包括变量、跳转类型、消息、处理人、权限等信息
|
|
|
FlowParams flowParams = FlowParams.build()
|
|
|
- .variable(completeTaskBo.getVariables())
|
|
|
+ .variable(variables)
|
|
|
.skipType(SkipType.PASS.getKey())
|
|
|
.message(completeTaskBo.getMessage())
|
|
|
.flowStatus(BusinessStatusEnum.WAITING.getStatus())
|
|
|
.hisStatus(TaskStatusEnum.PASS.getStatus())
|
|
|
.hisTaskExt(completeTaskBo.getFileId());
|
|
|
- // 执行任务跳转,并根据返回的处理人设置下一步处理人
|
|
|
- taskService.skip(taskId, flowParams);
|
|
|
+ Boolean autoPass = Convert.toBool(variables.getOrDefault(AUTO_PASS, false));
|
|
|
+ skipTask(taskId, flowParams, flowTask.getInstanceId(), autoPass);
|
|
|
return true;
|
|
|
} catch (Exception e) {
|
|
|
log.error(e.getMessage(), e);
|
|
|
@@ -193,6 +201,43 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 流程办理
|
|
|
+ *
|
|
|
+ * @param taskId 任务ID
|
|
|
+ * @param flowParams 参数
|
|
|
+ * @param instanceId 实例ID
|
|
|
+ * @param autoPass 自动审批
|
|
|
+ */
|
|
|
+ private void skipTask(Long taskId, FlowParams flowParams, Long instanceId, Boolean autoPass) {
|
|
|
+ // 执行任务跳转,并根据返回的处理人设置下一步处理人
|
|
|
+ taskService.skip(taskId, flowParams);
|
|
|
+ List<FlowTask> flowTaskList = selectByInstId(instanceId);
|
|
|
+ if (CollUtil.isEmpty(flowTaskList)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ List<User> userList = FlowEngine.userService()
|
|
|
+ .getByAssociateds(StreamUtils.toList(flowTaskList, FlowTask::getId));
|
|
|
+ if (CollUtil.isEmpty(userList)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ for (FlowTask task : flowTaskList) {
|
|
|
+ if (!task.getId().equals(taskId) && autoPass) {
|
|
|
+ List<User> users = StreamUtils.filter(userList, e -> ObjectUtil.equals(task.getId(), e.getAssociated()) && ObjectUtil.equal(e.getProcessedBy(), LoginHelper.getUserIdStr()));
|
|
|
+ if (CollUtil.isEmpty(users)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ flowParams.
|
|
|
+ message("流程引擎自动审批!").
|
|
|
+ variable(Map.of(
|
|
|
+ FlowConstant.SUBMIT, false,
|
|
|
+ FlowConstant.FLOW_COPY_LIST, Collections.emptyList(),
|
|
|
+ FlowConstant.MESSAGE_NOTICE, StringUtils.EMPTY));
|
|
|
+ skipTask(task.getId(), flowParams, instanceId, true);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 设置弹窗处理人
|
|
|
*
|
|
|
@@ -215,7 +260,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
|
|
List<String> variableUserIds = Arrays.asList(userIds.split(StringUtils.SEPARATOR));
|
|
|
hashSet.addAll(popUserIds);
|
|
|
hashSet.addAll(variableUserIds);
|
|
|
- map.put(entry.getKey(), String.join(StringUtils.SEPARATOR, hashSet));
|
|
|
+ map.put(entry.getKey(), StringUtils.joinComma(hashSet));
|
|
|
}
|
|
|
} else {
|
|
|
map.put(entry.getKey(), entry.getValue());
|
|
|
@@ -236,7 +281,9 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
|
|
return;
|
|
|
}
|
|
|
// 添加抄送人记录
|
|
|
- FlowHisTask flowHisTask = flowHisTaskMapper.selectList(new LambdaQueryWrapper<>(FlowHisTask.class).eq(FlowHisTask::getTaskId, task.getId())).get(0);
|
|
|
+ FlowHisTask flowHisTask = flowHisTaskMapper.selectList(
|
|
|
+ new LambdaQueryWrapper<>(FlowHisTask.class)
|
|
|
+ .eq(FlowHisTask::getTaskId, task.getId())).get(0);
|
|
|
FlowNode flowNode = new FlowNode();
|
|
|
flowNode.setNodeCode(flowHisTask.getTargetNodeCode());
|
|
|
flowNode.setNodeName(flowHisTask.getTargetNodeName());
|
|
|
@@ -256,9 +303,8 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
|
|
List<User> userList = StreamUtils.toList(flowCopyList, x ->
|
|
|
new FlowUser()
|
|
|
.setType(TaskAssigneeType.COPY.getCode())
|
|
|
- .setProcessedBy(String.valueOf(x.getUserId()))
|
|
|
- .setAssociated(taskId)
|
|
|
- );
|
|
|
+ .setProcessedBy(Convert.toStr(x.getUserId()))
|
|
|
+ .setAssociated(taskId));
|
|
|
// 批量保存抄送人员
|
|
|
FlowEngine.userService().saveBatch(userList);
|
|
|
}
|
|
|
@@ -320,8 +366,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
|
|
if (CollUtil.isEmpty(taskList)) {
|
|
|
return;
|
|
|
}
|
|
|
- List<User> associatedUsers = FlowEngine.userService()
|
|
|
- .getByAssociateds(StreamUtils.toList(taskList, FlowTaskVo::getId));
|
|
|
+ List<User> associatedUsers = FlowEngine.userService().getByAssociateds(StreamUtils.toList(taskList, FlowTaskVo::getId));
|
|
|
Map<Long, List<User>> taskUserMap = StreamUtils.groupByKey(associatedUsers, User::getAssociated);
|
|
|
// 组装用户数据回任务列表
|
|
|
for (FlowTaskVo task : taskList) {
|
|
|
@@ -418,22 +463,28 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
|
|
/**
|
|
|
* 获取可驳回的前置节点
|
|
|
*
|
|
|
- * @param definitionId 流程定义id
|
|
|
- * @param nowNodeCode 当前节点
|
|
|
+ * @param taskId 任务id
|
|
|
+ * @param nowNodeCode 当前节点
|
|
|
*/
|
|
|
@Override
|
|
|
- public List<Node> getBackTaskNode(Long definitionId, String nowNodeCode) {
|
|
|
- List<Node> nodeCodes = nodeService.getByNodeCodes(Collections.singletonList(nowNodeCode), definitionId);
|
|
|
+ public List<Node> getBackTaskNode(Long taskId, String nowNodeCode) {
|
|
|
+ FlowTask task = flowTaskMapper.selectById(taskId);
|
|
|
+ List<Node> nodeCodes = nodeService.getByNodeCodes(Collections.singletonList(nowNodeCode), task.getDefinitionId());
|
|
|
if (!CollUtil.isNotEmpty(nodeCodes)) {
|
|
|
return nodeCodes;
|
|
|
}
|
|
|
+ List<User> userList = FlowEngine.userService()
|
|
|
+ .getByAssociateds(Collections.singletonList(task.getId()), UserType.DEPUTE.getKey());
|
|
|
+ if (CollUtil.isNotEmpty(userList)) {
|
|
|
+ return nodeCodes;
|
|
|
+ }
|
|
|
//判断是否配置了固定驳回节点
|
|
|
Node node = nodeCodes.get(0);
|
|
|
if (StringUtils.isNotBlank(node.getAnyNodeSkip())) {
|
|
|
- return nodeService.getByNodeCodes(Collections.singletonList(node.getAnyNodeSkip()), definitionId);
|
|
|
+ return nodeService.getByNodeCodes(Collections.singletonList(node.getAnyNodeSkip()), task.getDefinitionId());
|
|
|
}
|
|
|
//获取可驳回的前置节点
|
|
|
- List<Node> nodes = nodeService.previousNodeList(definitionId, nowNodeCode);
|
|
|
+ List<Node> nodes = nodeService.previousNodeList(task.getDefinitionId(), nowNodeCode);
|
|
|
if (CollUtil.isNotEmpty(nodes)) {
|
|
|
return StreamUtils.filter(nodes, e -> NodeType.BETWEEN.getKey().equals(e.getNodeType()));
|
|
|
}
|
|
|
@@ -477,8 +528,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
|
|
*/
|
|
|
@Override
|
|
|
public List<FlowTask> selectByIdList(List<Long> taskIdList) {
|
|
|
- return flowTaskMapper.selectList(new LambdaQueryWrapper<>(FlowTask.class)
|
|
|
- .in(FlowTask::getId, taskIdList));
|
|
|
+ return flowTaskMapper.selectList(new LambdaQueryWrapper<>(FlowTask.class).in(FlowTask::getId, taskIdList));
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -535,17 +585,14 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
|
|
//办理人变量替换
|
|
|
ExpressionUtil.evalVariable(buildNextTaskList, FlowParams.build().variable(mergeVariable));
|
|
|
for (FlowNode flowNode : nextFlowNodes) {
|
|
|
- Optional<Task> first = buildNextTaskList.stream()
|
|
|
- .filter(t -> t.getNodeCode().equals(flowNode.getNodeCode()))
|
|
|
- .findFirst();
|
|
|
- first.ifPresent(t -> {
|
|
|
- if (CollUtil.isNotEmpty(t.getPermissionList())) {
|
|
|
- List<UserDTO> users = flwTaskAssigneeService.fetchUsersByStorageIds(String.join(StringUtils.SEPARATOR, t.getPermissionList()));
|
|
|
- if (CollUtil.isNotEmpty(users)) {
|
|
|
- flowNode.setPermissionFlag(StreamUtils.join(users, e -> String.valueOf(e.getUserId())));
|
|
|
- }
|
|
|
+ Task first = StreamUtils.findFirst(buildNextTaskList, t -> t.getNodeCode().equals(flowNode.getNodeCode()));
|
|
|
+ if (ObjectUtil.isNotNull(first) && CollUtil.isNotEmpty(first.getPermissionList())) {
|
|
|
+ List<UserDTO> users = flwTaskAssigneeService.fetchUsersByStorageIds(StringUtils.joinComma(first.getPermissionList()));
|
|
|
+ if (CollUtil.isNotEmpty(users)) {
|
|
|
+ flowNode.setPermissionFlag(StreamUtils.join(users, e -> Convert.toStr(e.getUserId())));
|
|
|
}
|
|
|
- });
|
|
|
+ }
|
|
|
+
|
|
|
}
|
|
|
}
|
|
|
return nextFlowNodes;
|
|
|
@@ -559,8 +606,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
|
|
*/
|
|
|
@Override
|
|
|
public FlowHisTask selectHisTaskById(Long taskId) {
|
|
|
- return flowHisTaskMapper.selectOne(new LambdaQueryWrapper<>(FlowHisTask.class)
|
|
|
- .eq(FlowHisTask::getId, taskId));
|
|
|
+ return flowHisTaskMapper.selectOne(new LambdaQueryWrapper<>(FlowHisTask.class).eq(FlowHisTask::getId, taskId));
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -570,8 +616,29 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
|
|
*/
|
|
|
@Override
|
|
|
public List<FlowTask> selectByInstId(Long instanceId) {
|
|
|
- return flowTaskMapper.selectList(new LambdaQueryWrapper<>(FlowTask.class)
|
|
|
- .eq(FlowTask::getInstanceId, instanceId));
|
|
|
+ return flowTaskMapper.selectList(new LambdaQueryWrapper<>(FlowTask.class).eq(FlowTask::getInstanceId, instanceId));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 按照实例id查询任务
|
|
|
+ *
|
|
|
+ * @param instanceIds 流程实例id
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public List<FlowTask> selectByInstIds(List<Long> instanceIds) {
|
|
|
+ return flowTaskMapper.selectList(new LambdaQueryWrapper<>(FlowTask.class).in(FlowTask::getInstanceId, instanceIds));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 判断流程是否已结束(即该流程实例下是否还有未完成的任务)
|
|
|
+ *
|
|
|
+ * @param instanceId 流程实例ID
|
|
|
+ * @return true 表示任务已全部结束;false 表示仍有任务存在
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public boolean isTaskEnd(Long instanceId) {
|
|
|
+ boolean exists = flowTaskMapper.exists(new LambdaQueryWrapper<FlowTask>().eq(FlowTask::getInstanceId, instanceId));
|
|
|
+ return !exists;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -583,8 +650,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
|
|
@Override
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
public boolean taskOperation(TaskOperationBo bo, String taskOperation) {
|
|
|
- FlowParams flowParams = FlowParams.build()
|
|
|
- .message(bo.getMessage());
|
|
|
+ FlowParams flowParams = FlowParams.build().message(bo.getMessage());
|
|
|
if (LoginHelper.isSuperAdmin() || LoginHelper.isTenantAdmin()) {
|
|
|
flowParams.ignore(true);
|
|
|
}
|
|
|
@@ -667,8 +733,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
|
|
new FlowUser()
|
|
|
.setType(TaskAssigneeType.APPROVER.getCode())
|
|
|
.setProcessedBy(userId)
|
|
|
- .setAssociated(flowTask.getId())
|
|
|
- );
|
|
|
+ .setAssociated(flowTask.getId()));
|
|
|
if (CollUtil.isNotEmpty(userList)) {
|
|
|
FlowEngine.userService().saveBatch(userList);
|
|
|
}
|
|
|
@@ -708,4 +773,28 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
|
|
.eq(FlowNode::getDefinitionId, definitionId));
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 催办任务
|
|
|
+ *
|
|
|
+ * @param bo 参数
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public boolean urgeTask(FlowUrgeTaskBo bo) {
|
|
|
+ try {
|
|
|
+ if (CollUtil.isEmpty(bo.getTaskIdList())) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ List<UserDTO> userList = this.currentTaskAllUser(bo.getTaskIdList());
|
|
|
+ if (CollUtil.isEmpty(userList)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ List<String> messageType = bo.getMessageType();
|
|
|
+ String message = bo.getMessage();
|
|
|
+ flwCommonService.sendMessage(messageType, message, "单据审批提醒", userList);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error(e.getMessage(), e);
|
|
|
+ throw new ServiceException(e.getMessage());
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
}
|