Merge remote-tracking branch 'origin/feature/bpm' into feature/bpm

# Conflicts:
#	sql/mysql/bpm_update.sql
#	yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java
This commit is contained in:
YunaiV 2024-10-12 19:40:22 +08:00
commit c05f9fe98e
16 changed files with 93 additions and 53 deletions

14
sql/mysql/bpm_update.sql Normal file
View File

@ -0,0 +1,14 @@
-- ----------------------------
-- 流程抄送表新加流程活动编号
-- ----------------------------
ALTER TABLE `bpm_process_instance_copy`
ADD COLUMN `activity_id` varchar(64) NULL COMMENT '流程活动编号' AFTER `category`,
MODIFY COLUMN `task_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '任务编号' AFTER `category`;
ALTER TABLE `bpm_process_definition_info`
ADD COLUMN `model_type` tinyint NOT NULL DEFAULT 10 COMMENT '流程模型的类型' AFTER `model_id`,
ADD COLUMN `simple_model` json NULL COMMENT 'SIMPLE 设计器模型数据' AFTER `form_custom_view_path`,
ADD COLUMN `visible` bit(1) NOT NULL DEFAULT 1 COMMENT '是否可见' AFTER `simple_model`;
ALTER TABLE `bpm_process_instance_copy`
ADD COLUMN `reason` varchar(256) NULL COMMENT '抄送意见' AFTER `task_name`;

View File

@ -210,6 +210,14 @@ public class BpmTaskController {
return success(true);
}
@PutMapping("/copy")
@Operation(summary = "抄送任务")
@PreAuthorize("@ss.hasPermission('bpm:task:update')")
public CommonResult<Boolean> copyTask(@Valid @RequestBody BpmTaskCopyReqVO reqVO) {
taskService.copyTask(getLoginUserId(), reqVO);
return success(true);
}
@GetMapping("/list-by-parent-task-id")
@Operation(summary = "获得指定父级任务的子任务列表") // 目前用于减签的时候获得子任务列表
@Parameter(name = "parentTaskId", description = "父级任务编号", required = true)

View File

@ -19,9 +19,9 @@ public class BpmProcessInstanceCopyRespVO {
@Schema(description = "流程实例编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "A233")
private String processInstanceId;
@Schema(description = "流程实例的名称")
@Schema(description = "流程实例的名称",requiredMode = Schema.RequiredMode.REQUIRED, example = "测试")
private String processInstanceName;
@Schema(description = "流程实例的发起时间")
@Schema(description = "流程实例的发起时间",requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime processInstanceStartTime;
@Schema(description = "抄送的节点的活动编号")
@ -31,12 +31,14 @@ public class BpmProcessInstanceCopyRespVO {
@Schema(description = "发起抄送的任务名称")
private String taskName;
@Schema(description = "抄送人")
@Schema(description = "抄送人", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private String creator;
@Schema(description = "抄送人昵称")
private String creatorName;
@Schema(description = "抄送人意见")
private String reason;
@Schema(description = "抄送时间")
@Schema(description = "抄送时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime;
}

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance;
import cn.iocoder.yudao.module.bpm.controller.admin.base.user.UserSimpleBaseVO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@ -42,24 +43,7 @@ public class BpmApprovalDetailRespVO {
private List<ApprovalTaskInfo> tasks;
@Schema(description = "候选人用户列表")
// TODO @jasoncandidateUserList => candidateUsers保持和 tasks 的命名风格一致哈
private List<User> candidateUserList; // 用于未运行任务节点
}
// TODO @jason可以替换成 UserSimpleBaseVO简化下
@Schema(description = "用户信息")
@Data
public static class User {
@Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long id;
@Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿")
private String nickname;
@Schema(description = "用户头像", example = "https://www.iocoder.cn/1.png")
private String avatar;
private List<UserSimpleBaseVO> candidateUsers; // 用于未运行任务节点
}
@ -71,10 +55,10 @@ public class BpmApprovalDetailRespVO {
private String id;
@Schema(description = "任务所属人", example = "1024")
private User ownerUser;
private UserSimpleBaseVO ownerUser;
@Schema(description = "任务分配人", example = "2048")
private User assigneeUser;
private UserSimpleBaseVO assigneeUser;
@Schema(description = "任务状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Integer status; // 参见 BpmTaskStatusEnum 枚举

View File

@ -66,6 +66,8 @@ public class BpmProcessInstanceRespVO {
private Long id;
@Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿")
private String nickname;
@Schema(description = "用户头像", example = "https://www.iocoder.cn/1.png")
private String avatar;
@Schema(description = "部门编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long deptId;

View File

@ -19,7 +19,7 @@ public class BpmTaskApproveReqVO {
@NotEmpty(message = "审批意见不能为空")
private String reason;
@Schema(description = "抄送的用户编号数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "1,2")
@Schema(description = "抄送的用户编号数组", example = "1,2")
private Collection<Long> copyUserIds;
@Schema(description = "变量实例(动态表单)", requiredMode = Schema.RequiredMode.REQUIRED)

View File

@ -0,0 +1,23 @@
package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotEmpty;
import lombok.Data;
import java.util.Collection;
@Schema(description = "管理后台 - 抄送流程任务的 Request VO")
@Data
public class BpmTaskCopyReqVO {
@Schema(description = "任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@NotEmpty(message = "任务编号不能为空")
private String id;
@Schema(description = "抄送的用户编号数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1,2]")
@NotEmpty(message = "抄送用户不能为空")
private Collection<Long> copyUserIds;
@Schema(description = "抄送意见", example = "帮忙看看!")
private String reason;
}

View File

@ -74,4 +74,9 @@ public class BpmProcessInstanceCopyDO extends BaseDO {
*/
private Long userId;
/**
* 抄送意见
*/
private String reason;
}

View File

@ -102,8 +102,7 @@ public class BpmTaskCandidateInvoker {
String param = BpmnModelUtils.parseCandidateParam(execution.getCurrentFlowElement());
// 1.1 计算任务的候选人
Set<Long> userIds = getCandidateStrategy(strategy).calculateUsers(execution, param);
removeDisableUsers(userIds);
// 1.2 移除被禁用的用户
// 1.2 移除被禁用的用户 TODO @芋艿 calculateUsers 方法中默认已经移除了被禁用的用户, 这里还需要移除被禁用的用户吗?
removeDisableUsers(userIds);
// 2. 候选人为空时根据审批人为空的配置补充

View File

@ -59,6 +59,8 @@ public class BpmTaskCandidateStartUserDeptLeaderMultiStrategy extends BpmTaskCan
}
Set<Long> users = getMultiLevelDeptLeaderIds(toList(dept.getId()), Integer.valueOf(param)); // 参数是部门的层级
// TODO @jason这里 removeDisableUsers 的原因是啥呀
// TODO @芋艿 calculateUsers(execution, param) calculateUsers(startUserId, processInstance, activityId, param) 现在这两个方法, 默认都移除了被禁用的用户
// TODO @芋艿 因为被禁用的用户是不能审批任务 在这里移除是不是好一点 代码可以重用
removeDisableUsers(users);
return users;
}

View File

@ -15,7 +15,7 @@ import static cn.iocoder.yudao.module.bpm.framework.flowable.core.listener.BpmCo
/**
* 处理抄送用户的 {@link JavaDelegate} 的实现类
*
* <p>
* 目前只有快搭模式的抄送节点使用
*
* @author jason
@ -40,7 +40,7 @@ public class BpmCopyTaskDelegate implements JavaDelegate {
}
// 2. 执行抄送
FlowElement currentFlowElement = execution.getCurrentFlowElement();
processInstanceCopyService.createProcessInstanceCopy(userIds, execution.getProcessInstanceId(),
processInstanceCopyService.createProcessInstanceCopy(userIds, null, execution.getProcessInstanceId(),
currentFlowElement.getId(), null, currentFlowElement.getName());
}

View File

@ -18,21 +18,23 @@ public interface BpmProcessInstanceCopyService {
* 流程实例的抄送
*
* @param userIds 抄送的用户编号
* @param reason 抄送意见
* @param taskId 流程任务编号
*/
void createProcessInstanceCopy(Collection<Long> userIds, String taskId);
void createProcessInstanceCopy(Collection<Long> userIds, String reason, String taskId);
/**
* 流程实例的抄送
*
* @param userIds 抄送的用户编号
* @param reason 抄送意见
* @param processInstanceId 流程编号
* @param activityId 流程活动编号 id (对应 BPMN XML 节点 Id)
* // TODO 芋艿这个 taskId 是不是可以不要了
* @param taskId 任务编号
* @param taskName 任务名称
*/
void createProcessInstanceCopy(Collection<Long> userIds, String processInstanceId, String activityId, String taskId, String taskName);
void createProcessInstanceCopy(Collection<Long> userIds, String reason, String processInstanceId, String activityId,
String taskId, String taskName);
/**
* 获得抄送的流程的分页
@ -43,14 +45,5 @@ public interface BpmProcessInstanceCopyService {
*/
PageResult<BpmProcessInstanceCopyDO> getProcessInstanceCopyPage(Long userId,
BpmProcessInstanceCopyPageReqVO pageReqVO);
// TODO @芋艿重点在 review
/**
* 通过流程实例和流程活动编号获取抄送人的 Id
*
* @param processInstanceId 流程实例 Id
* @param activityId 流程活动编号 Id
* @return 抄送人 Ids
*/
Set<Long> getCopyUserIds(String processInstanceId, String activityId);
}

View File

@ -49,17 +49,18 @@ public class BpmProcessInstanceCopyServiceImpl implements BpmProcessInstanceCopy
private BpmProcessDefinitionService processDefinitionService;
@Override
public void createProcessInstanceCopy(Collection<Long> userIds, String taskId) {
public void createProcessInstanceCopy(Collection<Long> userIds, String reason, String taskId) {
Task task = taskService.getTask(taskId);
if (ObjectUtil.isNull(task)) {
throw exception(ErrorCodeConstants.TASK_NOT_EXISTS);
}
String processInstanceId = task.getProcessInstanceId();
createProcessInstanceCopy(userIds, processInstanceId, task.getTaskDefinitionKey(), task.getId(), task.getName());
createProcessInstanceCopy(userIds, reason, processInstanceId, task.getTaskDefinitionKey(), task.getId(), task.getName());
}
@Override
public void createProcessInstanceCopy(Collection<Long> userIds, String processInstanceId, String activityId, String taskId, String taskName) {
public void createProcessInstanceCopy(Collection<Long> userIds, String reason, String processInstanceId, String activityId,
String taskId, String taskName) {
// 1.1 校验流程实例存在
ProcessInstance processInstance = processInstanceService.getProcessInstance(processInstanceId);
if (processInstance == null) {
@ -74,7 +75,7 @@ public class BpmProcessInstanceCopyServiceImpl implements BpmProcessInstanceCopy
// 2. 创建抄送流程
List<BpmProcessInstanceCopyDO> copyList = convertList(userIds, userId -> new BpmProcessInstanceCopyDO()
.setUserId(userId).setStartUserId(Long.valueOf(processInstance.getStartUserId()))
.setUserId(userId).setReason(reason).setStartUserId(Long.valueOf(processInstance.getStartUserId()))
.setProcessInstanceId(processInstanceId).setProcessInstanceName(processInstance.getName())
.setCategory(processDefinition.getCategory()).setActivityId(activityId)
.setTaskId(taskId).setTaskName(taskName));
@ -87,10 +88,4 @@ public class BpmProcessInstanceCopyServiceImpl implements BpmProcessInstanceCopy
return processInstanceCopyMapper.selectPage(userId, pageReqVO);
}
@Override
public Set<Long> getCopyUserIds(String processInstanceId, String activityId) {
return CollectionUtils.convertSet(processInstanceCopyMapper.selectListByProcessInstanceIdAndActivityId(processInstanceId, activityId),
BpmProcessInstanceCopyDO::getUserId);
}
}

View File

@ -202,6 +202,14 @@ public interface BpmTaskService {
*/
void deleteSignTask(Long userId, BpmTaskSignDeleteReqVO reqVO);
/**
* 抄送任务
*
* @param userId 用户编号
* @param reqVO 通过请求
*/
void copyTask(Long userId, @Valid BpmTaskCopyReqVO reqVO);
// ========== Event 事件相关方法 ==========
/**

View File

@ -354,7 +354,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
// 2. 抄送用户
if (CollUtil.isNotEmpty(reqVO.getCopyUserIds())) {
processInstanceCopyService.createProcessInstanceCopy(reqVO.getCopyUserIds(), reqVO.getId());
processInstanceCopyService.createProcessInstanceCopy(reqVO.getCopyUserIds(), null, reqVO.getId());
}
// 情况一被委派的任务不调用 complete 去完成任务
@ -868,6 +868,11 @@ public class BpmTaskServiceImpl implements BpmTaskService {
handleParentTaskIfSign(task.getParentTaskId());
}
@Override
public void copyTask(Long userId, BpmTaskCopyReqVO reqVO) {
processInstanceCopyService.createProcessInstanceCopy(reqVO.getCopyUserIds(), reqVO.getReason(), reqVO.getId());
}
/**
* 校验任务是否能被减签
*