feat(flow): 增加流程节点进行中状态展示功能

- 在ProcessInstanceServiceImpl中新增continueNodeSet处理逻辑
- 扩展NodeFormatUtil以支持JXZ状态节点展示
- 优化流程可视化展示效果,区分已完成和进行中节点
This commit is contained in:
claudecode committed 2025-10-26 21:32:12 +08:00
1 parent 14cdf670f2
commit 6f9d41b624
2 files changed
+663 -764

No files matched your search

@@ -53,7 +53,7 @@ import java.util.stream.Collectors;
* <p>
* 该类是流程实例管理的核心服务,负责处理流程实例的完整生命周期,主要功能包括: 1. 流程实例的启动、结束等生命周期管理 2. 待办任务、已办任务的查询 3.
* 我发起的流程、抄送给我的流程查询 4. 流程节点的格式化显示 5. 流程详情查询
*
* <p>
* 该服务整合了Flowable引擎和业务数据,为前端提供统一的流程操作接口
* </p>
*
@@ -65,516 +65,448 @@ import java.util.stream.Collectors;
@RequiredArgsConstructor
public class ProcessInstanceServiceImpl implements IProcessInstanceService {
private final RemoteUserService userService;
private final TaskService taskService;
private final RuntimeService runtimeService;
private final HistoryService historyService;
private final IProcessInstanceRecordService processInstanceRecordService;
private final IProcessCopyService processCopyService;
private final IProcessService processService;
private final IProcessNodeRecordService processNodeRecordService;
private final ObjectMapper objectMapper;
/**
* 启动流程
* <p>
* 根据流程定义启动一个新的流程实例。该方法会: 1. 获取当前登录用户作为流程发起人 2. 设置流程发起人信息到流程变量中 3. 调用Flowable引擎启动流程
* </p>
* @param processInstanceParamDto 流程启动参数,包含: - flowId: 流程定义ID - paramMap: 流程变量
* @return R 启动结果,包含流程实例ID等信息
*/
@Override
public R startProcessInstance(ProcessInstanceParamDto processInstanceParamDto) {
// 获取当前登录用户
PigxUser user = SecurityUtils.getUser();
// 设置流程发起人ID
processInstanceParamDto.setStartUserId(String.valueOf(user.getId()));
Map<String, Object> paramMap = processInstanceParamDto.getParamMap();
// 将发起人信息作为root变量存入流程,用于流程节点的权限判断
Dict rootUser = Dict.create()
.set("id", user.getId())
.set("name", user.getUsername())
.set("type", NodeUserTypeEnum.USER.getKey());
paramMap.put("root", CollUtil.newArrayList(rootUser));
// 调用引擎启动流程
Authentication.setAuthenticatedUserId(processInstanceParamDto.getStartUserId());
ProcessInstance processInstance = runtimeService.startProcessInstanceByKeyAndTenantId(
processInstanceParamDto.getFlowId(), processInstanceParamDto.getParamMap(),
TenantContextHolder.getTenantId().toString());
String processInstanceId = processInstance.getProcessInstanceId();
return R.ok(processInstanceId);
}
/**
* 查询当前登录用户的待办任务
* <p>
* 查询分配给当前用户的待办任务列表,并补充以下信息: 1. 流程实例的详细信息(流程名称、分组等) 2. 流程发起人信息(姓名、头像等) 3. 流程启动时间
* </p>
* @param taskQueryParamDto 查询参数,支持分页和条件过滤
* @return R 包含分页后的待办任务列表
*/
@Override
public R queryMineTask(TaskQueryParamDto taskQueryParamDto) {
taskQueryParamDto.setAssign(SecurityUtils.getUser().getId().toString());
String assign = taskQueryParamDto.getAssign();
List<TaskDto> taskDtoList = new ArrayList<>();
int pageIndex = taskQueryParamDto.getCurrent() - 1;
int pageSize = taskQueryParamDto.getSize();
Page<TaskDto> pageResultDto = new Page<>();
TaskQuery taskQuery = taskService.createTaskQuery().taskAssignee(assign).orderByTaskCreateTime().desc();
if (StrUtil.isNotBlank(taskQueryParamDto.getProcessName())) {
List<ProcessInstance> processInstanceList = runtimeService.createProcessInstanceQuery()
.processDefinitionName(taskQueryParamDto.getProcessName())
.processInstanceTenantId(TenantContextHolder.getTenantId().toString())
.list();
if (CollUtil.isNotEmpty(processInstanceList)) {
taskQuery.processInstanceIdIn(
processInstanceList.stream().map(ProcessInstance::getProcessInstanceId).toList());
}
}
if (ArrayUtil.isNotEmpty(taskQueryParamDto.getTaskTime())) {
ZoneId zoneId = ZoneId.systemDefault();
ZonedDateTime zonedBeforeDateTime = taskQueryParamDto.getTaskTime()[0].atZone(zoneId);
ZonedDateTime zonedAfterDateTime = taskQueryParamDto.getTaskTime()[1].atZone(zoneId);
Date beforeDate = Date.from(zonedBeforeDateTime.toInstant());
Date afterDate = Date.from(zonedAfterDateTime.toInstant());
taskQuery.taskCreatedBefore(afterDate).taskCreatedAfter(beforeDate);
}
taskQuery.listPage(pageIndex * pageSize, pageSize).forEach(task -> {
String taskId = task.getId();
String processInstanceId = task.getProcessInstanceId();
log.debug("(taskId) {} processInstanceId={} executrionId={}", task.getName(), processInstanceId,
task.getExecutionId());
String taskDefinitionKey = task.getTaskDefinitionKey();
String processDefinitionId = task.getProcessDefinitionId();
String flowId = NodeUtil.getFlowId(processDefinitionId);
TaskDto taskDto = new TaskDto();
taskDto.setFlowId(flowId);
taskDto.setTaskCreateTime(task.getCreateTime());
taskDto.setNodeId(taskDefinitionKey);
taskDto.setProcessInstanceId(processInstanceId);
taskDto.setTaskId(taskId);
taskDto.setAssign(task.getAssignee());
taskDto.setTaskName(task.getName());
taskDtoList.add(taskDto);
});
long count = taskQuery.count();
log.debug("当前有 {} 个任务:", count);
pageResultDto.setTotal(count);
pageResultDto.setRecords(taskDtoList);
if (CollUtil.isEmpty(taskDtoList)) {
return R.ok();
}
Set<String> processInstanceIdSet = taskDtoList.stream()
.map(TaskDto::getProcessInstanceId)
.collect(Collectors.toSet());
// 流程实例记录
List<ProcessInstanceRecord> processInstanceRecordList = processInstanceRecordService.lambdaQuery()
.in(ProcessInstanceRecord::getProcessInstanceId, processInstanceIdSet)
.list();
// 发起人
List<Long> collect = processInstanceRecordList.stream().map(ProcessInstanceRecord::getUserId).toList();
List<SysUser> startUserList = userService.getUserById(collect).getData();
List<TaskDto> taskNewDtoList = new ArrayList<>();
for (TaskDto record : taskDtoList) {
ProcessInstanceRecord processInstanceRecord = processInstanceRecordList.stream()
.filter(w -> StrUtil.equals(w.getProcessInstanceId(), record.getProcessInstanceId()))
.findAny()
.orElse(null);
if (processInstanceRecord != null) {
record.setProcessName(processInstanceRecord.getName());
SysUser startUser = startUserList.stream()
.filter(w -> w.getUserId().longValue() == processInstanceRecord.getUserId())
.findAny()
.orElse(null);
record.setRootUserId(processInstanceRecord.getUserId());
record.setGroupName(processInstanceRecord.getGroupName());
record.setRootUserName(startUser.getUsername());
record.setRootUserAvatarUrl(startUser.getAvatar());
record.setStartTime(processInstanceRecord.getCreateTime());
taskNewDtoList.add(record);
}
}
pageResultDto.setRecords(taskNewDtoList);
return R.ok(pageResultDto);
}
/**
* 查询已办任务
* <p>
* 查询当前用户已经完成的任务列表,包括: 1. 用户已审批的任务 2. 补充流程实例信息、发起人信息等
* </p>
* @param taskQueryParamDto 查询参数,支持分页和时间范围过滤
* @return R 包含分页后的已办任务列表
*/
@Override
public R queryMineEndTask(TaskQueryParamDto taskQueryParamDto) {
taskQueryParamDto.setAssign(SecurityUtils.getUser().getId().toString());
HistoricActivityInstanceQuery historicActivityInstanceQuery = historyService
.createHistoricActivityInstanceQuery();
HistoricActivityInstanceQuery activityInstanceQuery = historicActivityInstanceQuery
.taskAssignee(taskQueryParamDto.getAssign())
.finished()
.orderByHistoricActivityInstanceEndTime()
.desc();
if (ArrayUtil.isNotEmpty(taskQueryParamDto.getTaskTime())) {
ZoneId zoneId = ZoneId.systemDefault();
ZonedDateTime zonedBeforeDateTime = taskQueryParamDto.getTaskTime()[0].atZone(zoneId);
ZonedDateTime zonedAfterDateTime = taskQueryParamDto.getTaskTime()[1].atZone(zoneId);
Date beforeDate = Date.from(zonedBeforeDateTime.toInstant());
Date afterDate = Date.from(zonedAfterDateTime.toInstant());
activityInstanceQuery.finishedBefore(afterDate).finishedAfter(beforeDate);
}
List<HistoricActivityInstance> list = activityInstanceQuery
.listPage((taskQueryParamDto.getCurrent() - 1) * taskQueryParamDto.getSize(), taskQueryParamDto.getSize());
long count = activityInstanceQuery.count();
List<TaskDto> taskDtoList = new ArrayList<>();
for (HistoricActivityInstance historicActivityInstance : list) {
String activityId = historicActivityInstance.getActivityId();
String activityName = historicActivityInstance.getActivityName();
String executionId = historicActivityInstance.getExecutionId();
String taskId = historicActivityInstance.getTaskId();
Date startTime = historicActivityInstance.getStartTime();
Date endTime = historicActivityInstance.getEndTime();
Long durationInMillis = historicActivityInstance.getDurationInMillis();
String processInstanceId = historicActivityInstance.getProcessInstanceId();
String processDefinitionId = historicActivityInstance.getProcessDefinitionId();
// 流程id
String flowId = NodeUtil.getFlowId(processDefinitionId);
TaskDto taskDto = new TaskDto();
taskDto.setFlowId(flowId);
taskDto.setTaskCreateTime(startTime);
taskDto.setTaskEndTime(endTime);
taskDto.setNodeId(activityId);
taskDto.setExecutionId(executionId);
taskDto.setProcessInstanceId(processInstanceId);
taskDto.setDurationInMillis(durationInMillis);
taskDto.setTaskId(taskId);
taskDto.setAssign(historicActivityInstance.getAssignee());
taskDto.setTaskName(activityName);
taskDtoList.add(taskDto);
}
Page<TaskDto> pageResultDto = new Page<>();
pageResultDto.setTotal(count);
pageResultDto.setRecords(taskDtoList);
List<TaskDto> records = pageResultDto.getRecords();
if (CollUtil.isEmpty(records)) {
return R.ok(pageResultDto);
}
Set<String> processInstanceIdSet = records.stream()
.map(TaskDto::getProcessInstanceId)
.collect(Collectors.toSet());
// 流程实例记录
List<ProcessInstanceRecord> processInstanceRecordList = processInstanceRecordService.lambdaQuery()
.in(ProcessInstanceRecord::getProcessInstanceId, processInstanceIdSet)
.list();
// 发起人
List<Long> collect = processInstanceRecordList.stream().map(ProcessInstanceRecord::getUserId).toList();
List<SysUser> startUserList = userService.getUserById(collect).getData();
List<TaskDto> taskNewDtoList = new ArrayList<>();
for (TaskDto record : records) {
ProcessInstanceRecord processInstanceRecord = processInstanceRecordList.stream()
.filter(w -> StrUtil.equals(w.getProcessInstanceId(), record.getProcessInstanceId()))
.findAny()
.orElse(null);
if (processInstanceRecord != null) {
record.setProcessName(processInstanceRecord.getName());
SysUser startUser = startUserList.stream()
.filter(w -> w.getUserId().longValue() == processInstanceRecord.getUserId())
.findAny()
.orElse(null);
record.setRootUserId(processInstanceRecord.getUserId());
record.setGroupName(processInstanceRecord.getGroupName());
record.setRootUserName(startUser.getName());
record.setRootUserAvatarUrl(startUser.getAvatar());
record.setTaskId(record.getTaskId());
record.setStartTime(processInstanceRecord.getCreateTime());
taskNewDtoList.add(record);
}
}
pageResultDto.setRecords(taskNewDtoList);
return R.ok(pageResultDto);
}
/**
* 结束流程实例
* <p>
* 手动结束一个流程实例,通常用于: 1. 流程审批完成,正常结束 2. 流程被终止或取消
*
* 该方法会更新流程实例记录的结束时间、状态和结束原因
* </p>
* @param processInstanceParamDto 流程实例参数,包含: - processInstanceId: 流程实例ID - paramMap:
* 可能包含approve_condition等结束原因
* @return R 操作结果
*/
@Override
public R end(ProcessInstanceParamDto processInstanceParamDto) {
// 从参数中提取审批条件,用于判断流程结束原因(通过/拒绝)
Optional<Boolean> objectOptional = processInstanceParamDto.getParamMap()
.keySet()
.stream()
.filter(key -> key.contains("approve_condition"))
.reduce((first, second) -> second)
.map(key -> MapUtil.getBool(processInstanceParamDto.getParamMap(), key, true));
// 构建更新条件
LambdaUpdateChainWrapper<ProcessInstanceRecord> lambdaUpdateChainWrapper = processInstanceRecordService
.lambdaUpdate()
.set(ProcessInstanceRecord::getEndTime, new Date())
.set(ProcessInstanceRecord::getStatus, NodeStatusEnum.YJS.getCode());
// 如果有审批结果,设置结束原因
objectOptional
.ifPresent(aBoolean -> lambdaUpdateChainWrapper.set(ProcessInstanceRecord::getFinishReason, aBoolean));
// 执行更新
lambdaUpdateChainWrapper
.eq(ProcessInstanceRecord::getProcessInstanceId, processInstanceParamDto.getProcessInstanceId())
.update(new ProcessInstanceRecord());
return R.ok();
}
/**
* 查询我发起的流程
* <p>
* 查询当前用户发起的所有流程实例,支持: 1. 按状态过滤(进行中、已完成等) 2. 按时间范围过滤 3. 分页查询
* </p>
* @param taskQueryParamDto 查询条件,包含状态、时间范围、分页参数
* @return R 包含分页后的流程实例列表
*/
@Override
public R queryMineStarted(TaskQueryParamDto taskQueryParamDto) {
long userId = SecurityUtils.getUser().getId();
Page<ProcessInstanceRecord> instanceRecordPage = processInstanceRecordService.lambdaQuery()
.eq(ProcessInstanceRecord::getUserId, userId)
.eq(ProcessInstanceRecord::getStatus, taskQueryParamDto.getStatus())
.between(ArrayUtil.isNotEmpty(taskQueryParamDto.getTaskTime()), ProcessInstanceRecord::getCreateTime,
ArrayUtil.isNotEmpty(taskQueryParamDto.getTaskTime()) ? taskQueryParamDto.getTaskTime()[0] : null,
ArrayUtil.isNotEmpty(taskQueryParamDto.getTaskTime()) ? taskQueryParamDto.getTaskTime()[1] : null)
.orderByDesc(ProcessInstanceRecord::getCreateTime)
.page(new Page<>(taskQueryParamDto.getCurrent(), taskQueryParamDto.getSize()));
return R.ok(instanceRecordPage);
}
/**
* 查询抄送给我的流程
* <p>
* 查询抄送给当前用户的流程列表。抄送功能允许流程参与者将流程信息 通知给其他相关人员,被抄送人可以查看流程但不参与审批
* </p>
* @param taskQueryParamDto 查询参数,支持时间范围过滤和分页
* @return R 包含分页后的抄送记录,包括发起人信息
*/
@Override
public R queryMineCC(TaskQueryParamDto taskQueryParamDto) {
long userId = SecurityUtils.getUser().getId();
Page<ProcessCopy> page = processCopyService.lambdaQuery()
.eq(ProcessCopy::getUserId, userId)
.between(ArrayUtil.isNotEmpty(taskQueryParamDto.getTaskTime()), ProcessCopy::getCreateTime,
ArrayUtil.isNotEmpty(taskQueryParamDto.getTaskTime()) ? taskQueryParamDto.getTaskTime()[0] : null,
ArrayUtil.isNotEmpty(taskQueryParamDto.getTaskTime()) ? taskQueryParamDto.getTaskTime()[1] : null)
.orderByDesc(ProcessCopy::getNodeTime)
.page(new Page<>(taskQueryParamDto.getCurrent(), taskQueryParamDto.getSize()));
List<ProcessCopy> records = page.getRecords();
List<ProcessCopyVo> processCopyVoList = BeanUtil.copyToList(records, ProcessCopyVo.class);
if (CollUtil.isNotEmpty(records)) {
// 发起人
List<Long> userIdList = records.stream().map(ProcessCopy::getStartUserId).toList();
List<SysUser> startUserList = userService.getUserById(userIdList).getData();
for (ProcessCopyVo record : processCopyVoList) {
SysUser startUser = startUserList.stream()
.filter(w -> w.getUserId().longValue() == record.getStartUserId())
.findAny()
.orElse(null);
record.setStartUserName(startUser.getUsername());
}
}
Page p = BeanUtil.copyProperties(page, Page.class);
p.setRecords(processCopyVoList);
return R.ok(p);
}
/**
* 格式化流程显示
* <p>
* 将流程定义数据格式化为前端可展示的节点结构,主要功能: 1. 解析流程定义的JSON数据 2. 标记已完成的节点 3. 根据流程变量计算条件节点的显示状态 4.
* 处理节点权限和表单权限
*
* 该方法用于流程图的可视化展示
* </p>
* @param nodeFormatParamVo 格式化参数,包含: - flowId: 流程定义ID - processInstanceId: 流程实例ID -
* taskId: 任务ID(可选) - paramMap: 流程变量
* @return R 包含格式化后的节点列表
*/
@SneakyThrows
@Override
public R formatStartNodeShow(NodeFormatParamVo nodeFormatParamVo) {
String flowId = nodeFormatParamVo.getFlowId();
String processInstanceId = nodeFormatParamVo.getProcessInstanceId();
if (StrUtil.isAllBlank(flowId, processInstanceId)) {
return R.ok(new ArrayList<>());
}
if (StrUtil.isBlankIfStr(flowId) && StrUtil.isNotBlank(processInstanceId)) {
ProcessInstanceRecord processInstanceRecord = processInstanceRecordService.lambdaQuery()
.eq(ProcessInstanceRecord::getProcessInstanceId, processInstanceId)
.one();
flowId = processInstanceRecord.getFlowId();
}
Map<String, Object> paramMap = nodeFormatParamVo.getParamMap();
if (StrUtil.isNotBlank(nodeFormatParamVo.getTaskId())) {
VariableQueryParamDto variableQueryParamDto = new VariableQueryParamDto();
variableQueryParamDto.setTaskId(nodeFormatParamVo.getTaskId());
Map<String, Object> variables;
List<String> keyList = variableQueryParamDto.getKeyList();
if (CollUtil.isEmpty(keyList)) {
TaskQuery taskQuery = taskService.createTaskQuery();
Task task = taskQuery.taskId(variableQueryParamDto.getTaskId()).singleResult();
if (task == null) {
return R.failed("任务不存在");
}
variables = runtimeService.getVariables(task.getExecutionId());
}
else {
variables = taskService.getVariables(variableQueryParamDto.getTaskId(), keyList);
}
paramMap.putAll(variables);
}
Set<String> completeNodeSet = new HashSet<>();
if (StrUtil.isNotBlank(processInstanceId)) {
List<ProcessNodeRecord> processNodeRecordList = processNodeRecordService.lambdaQuery()
.eq(ProcessNodeRecord::getProcessInstanceId, processInstanceId)
.eq(ProcessNodeRecord::getStatus, NodeStatusEnum.YJS.getCode())
.list();
Set<String> collect = processNodeRecordList.stream()
.map(ProcessNodeRecord::getNodeId)
.collect(Collectors.toSet());
completeNodeSet.addAll(collect);
}
Process oaForms = processService.getByFlowId(flowId);
String process = oaForms.getProcess();
Node nodeDto = objectMapper.readValue(process, new TypeReference<>() {
});
List<NodeVo> processNodeShowDtos = NodeFormatUtil.formatProcessNodeShow(nodeDto, completeNodeSet,
new HashSet<>(), processInstanceId, paramMap);
return R.ok(processNodeShowDtos);
}
/**
* 流程详情
* <p>
* 查询流程实例的详细信息,包括: 1. 流程定义信息(流程结构) 2. 表单项定义 3. 表单数据(用户填写的数据) 4. 表单权限配置 5. 流程状态信息
*
* 该方法主要用于流程详情页面的数据展示
* </p>
* @param processInstanceId 流程实例ID
* @return R 包含流程详情的Dict对象
* @throws Exception 当解析JSON数据失败时抛出异常
*/
@SneakyThrows
@Override
public R detail(String processInstanceId) {
ProcessInstanceRecord processInstanceRecord = processInstanceRecordService.lambdaQuery()
.eq(ProcessInstanceRecord::getProcessInstanceId, processInstanceId)
.one();
Process oaForms = processService.getByFlowId(processInstanceRecord.getFlowId());
if (oaForms == null) {
return R.failed("流程不存在");
}
// 发起人变量数据
String formData = processInstanceRecord.getFormData();
String process = oaForms.getProcess();
Node nodeDto = objectMapper.readValue(process, Node.class);
Map<String, String> formPerms1 = nodeDto.getFormPerms();
Dict set = Dict.create()
.set(ProcessInstanceRecord.Fields.processInstanceId, processInstanceId)
.set(ProcessInstanceRecord.Fields.status, processInstanceRecord.getStatus())
.set("process", oaForms.getProcess())
.set("formItems", oaForms.getFormItems())
.set("formData", formData)
.set("formData", formData)
.set("formConfig", oaForms.getFormConfig())
.set("formPerms", formPerms1);
return R.ok(set);
}
private final RemoteUserService userService;
private final TaskService taskService;
private final RuntimeService runtimeService;
private final HistoryService historyService;
private final IProcessInstanceRecordService processInstanceRecordService;
private final IProcessCopyService processCopyService;
private final IProcessService processService;
private final IProcessNodeRecordService processNodeRecordService;
private final ObjectMapper objectMapper;
/**
* 启动流程
* <p>
* 根据流程定义启动一个新的流程实例。该方法会: 1. 获取当前登录用户作为流程发起人 2. 设置流程发起人信息到流程变量中 3. 调用Flowable引擎启动流程
* </p>
*
* @param processInstanceParamDto 流程启动参数,包含: - flowId: 流程定义ID - paramMap: 流程变量
* @return R 启动结果,包含流程实例ID等信息
*/
@Override
public R startProcessInstance(ProcessInstanceParamDto processInstanceParamDto) {
// 获取当前登录用户
PigxUser user = SecurityUtils.getUser();
// 设置流程发起人ID
processInstanceParamDto.setStartUserId(String.valueOf(user.getId()));
Map<String, Object> paramMap = processInstanceParamDto.getParamMap();
// 将发起人信息作为root变量存入流程,用于流程节点的权限判断
Dict rootUser = Dict.create().set("id", user.getId()).set("name", user.getUsername()).set("type", NodeUserTypeEnum.USER.getKey());
paramMap.put("root", CollUtil.newArrayList(rootUser));
// 调用引擎启动流程
Authentication.setAuthenticatedUserId(processInstanceParamDto.getStartUserId());
ProcessInstance processInstance = runtimeService.startProcessInstanceByKeyAndTenantId(processInstanceParamDto.getFlowId(), processInstanceParamDto.getParamMap(), TenantContextHolder.getTenantId().toString());
String processInstanceId = processInstance.getProcessInstanceId();
return R.ok(processInstanceId);
}
/**
* 查询当前登录用户的待办任务
* <p>
* 查询分配给当前用户的待办任务列表,并补充以下信息: 1. 流程实例的详细信息(流程名称、分组等) 2. 流程发起人信息(姓名、头像等) 3. 流程启动时间
* </p>
*
* @param taskQueryParamDto 查询参数,支持分页和条件过滤
* @return R 包含分页后的待办任务列表
*/
@Override
public R queryMineTask(TaskQueryParamDto taskQueryParamDto) {
taskQueryParamDto.setAssign(SecurityUtils.getUser().getId().toString());
String assign = taskQueryParamDto.getAssign();
List<TaskDto> taskDtoList = new ArrayList<>();
int pageIndex = taskQueryParamDto.getCurrent() - 1;
int pageSize = taskQueryParamDto.getSize();
Page<TaskDto> pageResultDto = new Page<>();
TaskQuery taskQuery = taskService.createTaskQuery().taskAssignee(assign).orderByTaskCreateTime().desc();
if (StrUtil.isNotBlank(taskQueryParamDto.getProcessName())) {
List<ProcessInstance> processInstanceList = runtimeService.createProcessInstanceQuery().processDefinitionName(taskQueryParamDto.getProcessName()).processInstanceTenantId(TenantContextHolder.getTenantId().toString()).list();
if (CollUtil.isNotEmpty(processInstanceList)) {
taskQuery.processInstanceIdIn(processInstanceList.stream().map(ProcessInstance::getProcessInstanceId).toList());
}
}
if (ArrayUtil.isNotEmpty(taskQueryParamDto.getTaskTime())) {
ZoneId zoneId = ZoneId.systemDefault();
ZonedDateTime zonedBeforeDateTime = taskQueryParamDto.getTaskTime()[0].atZone(zoneId);
ZonedDateTime zonedAfterDateTime = taskQueryParamDto.getTaskTime()[1].atZone(zoneId);
Date beforeDate = Date.from(zonedBeforeDateTime.toInstant());
Date afterDate = Date.from(zonedAfterDateTime.toInstant());
taskQuery.taskCreatedBefore(afterDate).taskCreatedAfter(beforeDate);
}
taskQuery.listPage(pageIndex * pageSize, pageSize).forEach(task -> {
String taskId = task.getId();
String processInstanceId = task.getProcessInstanceId();
log.debug("(taskId) {} processInstanceId={} executrionId={}", task.getName(), processInstanceId, task.getExecutionId());
String taskDefinitionKey = task.getTaskDefinitionKey();
String processDefinitionId = task.getProcessDefinitionId();
String flowId = NodeUtil.getFlowId(processDefinitionId);
TaskDto taskDto = new TaskDto();
taskDto.setFlowId(flowId);
taskDto.setTaskCreateTime(task.getCreateTime());
taskDto.setNodeId(taskDefinitionKey);
taskDto.setProcessInstanceId(processInstanceId);
taskDto.setTaskId(taskId);
taskDto.setAssign(task.getAssignee());
taskDto.setTaskName(task.getName());
taskDtoList.add(taskDto);
});
long count = taskQuery.count();
log.debug("当前有 {} 个任务:", count);
pageResultDto.setTotal(count);
pageResultDto.setRecords(taskDtoList);
if (CollUtil.isEmpty(taskDtoList)) {
return R.ok();
}
Set<String> processInstanceIdSet = taskDtoList.stream().map(TaskDto::getProcessInstanceId).collect(Collectors.toSet());
// 流程实例记录
List<ProcessInstanceRecord> processInstanceRecordList = processInstanceRecordService.lambdaQuery().in(ProcessInstanceRecord::getProcessInstanceId, processInstanceIdSet).list();
// 发起人
List<Long> collect = processInstanceRecordList.stream().map(ProcessInstanceRecord::getUserId).toList();
List<SysUser> startUserList = userService.getUserById(collect).getData();
List<TaskDto> taskNewDtoList = new ArrayList<>();
for (TaskDto record : taskDtoList) {
ProcessInstanceRecord processInstanceRecord = processInstanceRecordList.stream().filter(w -> StrUtil.equals(w.getProcessInstanceId(), record.getProcessInstanceId())).findAny().orElse(null);
if (processInstanceRecord != null) {
record.setProcessName(processInstanceRecord.getName());
SysUser startUser = startUserList.stream().filter(w -> w.getUserId().longValue() == processInstanceRecord.getUserId()).findAny().orElse(null);
record.setRootUserId(processInstanceRecord.getUserId());
record.setGroupName(processInstanceRecord.getGroupName());
record.setRootUserName(startUser.getUsername());
record.setRootUserAvatarUrl(startUser.getAvatar());
record.setStartTime(processInstanceRecord.getCreateTime());
taskNewDtoList.add(record);
}
}
pageResultDto.setRecords(taskNewDtoList);
return R.ok(pageResultDto);
}
/**
* 查询已办任务
* <p>
* 查询当前用户已经完成的任务列表,包括: 1. 用户已审批的任务 2. 补充流程实例信息、发起人信息等
* </p>
*
* @param taskQueryParamDto 查询参数,支持分页和时间范围过滤
* @return R 包含分页后的已办任务列表
*/
@Override
public R queryMineEndTask(TaskQueryParamDto taskQueryParamDto) {
taskQueryParamDto.setAssign(SecurityUtils.getUser().getId().toString());
HistoricActivityInstanceQuery historicActivityInstanceQuery = historyService.createHistoricActivityInstanceQuery();
HistoricActivityInstanceQuery activityInstanceQuery = historicActivityInstanceQuery.taskAssignee(taskQueryParamDto.getAssign()).finished().orderByHistoricActivityInstanceEndTime().desc();
if (ArrayUtil.isNotEmpty(taskQueryParamDto.getTaskTime())) {
ZoneId zoneId = ZoneId.systemDefault();
ZonedDateTime zonedBeforeDateTime = taskQueryParamDto.getTaskTime()[0].atZone(zoneId);
ZonedDateTime zonedAfterDateTime = taskQueryParamDto.getTaskTime()[1].atZone(zoneId);
Date beforeDate = Date.from(zonedBeforeDateTime.toInstant());
Date afterDate = Date.from(zonedAfterDateTime.toInstant());
activityInstanceQuery.finishedBefore(afterDate).finishedAfter(beforeDate);
}
List<HistoricActivityInstance> list = activityInstanceQuery.listPage((taskQueryParamDto.getCurrent() - 1) * taskQueryParamDto.getSize(), taskQueryParamDto.getSize());
long count = activityInstanceQuery.count();
List<TaskDto> taskDtoList = new ArrayList<>();
for (HistoricActivityInstance historicActivityInstance : list) {
String activityId = historicActivityInstance.getActivityId();
String activityName = historicActivityInstance.getActivityName();
String executionId = historicActivityInstance.getExecutionId();
String taskId = historicActivityInstance.getTaskId();
Date startTime = historicActivityInstance.getStartTime();
Date endTime = historicActivityInstance.getEndTime();
Long durationInMillis = historicActivityInstance.getDurationInMillis();
String processInstanceId = historicActivityInstance.getProcessInstanceId();
String processDefinitionId = historicActivityInstance.getProcessDefinitionId();
// 流程id
String flowId = NodeUtil.getFlowId(processDefinitionId);
TaskDto taskDto = new TaskDto();
taskDto.setFlowId(flowId);
taskDto.setTaskCreateTime(startTime);
taskDto.setTaskEndTime(endTime);
taskDto.setNodeId(activityId);
taskDto.setExecutionId(executionId);
taskDto.setProcessInstanceId(processInstanceId);
taskDto.setDurationInMillis(durationInMillis);
taskDto.setTaskId(taskId);
taskDto.setAssign(historicActivityInstance.getAssignee());
taskDto.setTaskName(activityName);
taskDtoList.add(taskDto);
}
Page<TaskDto> pageResultDto = new Page<>();
pageResultDto.setTotal(count);
pageResultDto.setRecords(taskDtoList);
List<TaskDto> records = pageResultDto.getRecords();
if (CollUtil.isEmpty(records)) {
return R.ok(pageResultDto);
}
Set<String> processInstanceIdSet = records.stream().map(TaskDto::getProcessInstanceId).collect(Collectors.toSet());
// 流程实例记录
List<ProcessInstanceRecord> processInstanceRecordList = processInstanceRecordService.lambdaQuery().in(ProcessInstanceRecord::getProcessInstanceId, processInstanceIdSet).list();
// 发起人
List<Long> collect = processInstanceRecordList.stream().map(ProcessInstanceRecord::getUserId).toList();
List<SysUser> startUserList = userService.getUserById(collect).getData();
List<TaskDto> taskNewDtoList = new ArrayList<>();
for (TaskDto record : records) {
ProcessInstanceRecord processInstanceRecord = processInstanceRecordList.stream().filter(w -> StrUtil.equals(w.getProcessInstanceId(), record.getProcessInstanceId())).findAny().orElse(null);
if (processInstanceRecord != null) {
record.setProcessName(processInstanceRecord.getName());
SysUser startUser = startUserList.stream().filter(w -> w.getUserId().longValue() == processInstanceRecord.getUserId()).findAny().orElse(null);
record.setRootUserId(processInstanceRecord.getUserId());
record.setGroupName(processInstanceRecord.getGroupName());
record.setRootUserName(startUser.getName());
record.setRootUserAvatarUrl(startUser.getAvatar());
record.setTaskId(record.getTaskId());
record.setStartTime(processInstanceRecord.getCreateTime());
taskNewDtoList.add(record);
}
}
pageResultDto.setRecords(taskNewDtoList);
return R.ok(pageResultDto);
}
/**
* 结束流程实例
* <p>
* 手动结束一个流程实例,通常用于: 1. 流程审批完成,正常结束 2. 流程被终止或取消
* <p>
* 该方法会更新流程实例记录的结束时间、状态和结束原因
* </p>
*
* @param processInstanceParamDto 流程实例参数,包含: - processInstanceId: 流程实例ID - paramMap:
* 可能包含approve_condition等结束原因
* @return R 操作结果
*/
@Override
public R end(ProcessInstanceParamDto processInstanceParamDto) {
// 从参数中提取审批条件,用于判断流程结束原因(通过/拒绝)
Optional<Boolean> objectOptional = processInstanceParamDto.getParamMap().keySet().stream().filter(key -> key.contains("approve_condition")).reduce((first, second) -> second).map(key -> MapUtil.getBool(processInstanceParamDto.getParamMap(), key, true));
// 构建更新条件
LambdaUpdateChainWrapper<ProcessInstanceRecord> lambdaUpdateChainWrapper = processInstanceRecordService.lambdaUpdate().set(ProcessInstanceRecord::getEndTime, new Date()).set(ProcessInstanceRecord::getStatus, NodeStatusEnum.YJS.getCode());
// 如果有审批结果,设置结束原因
objectOptional.ifPresent(aBoolean -> lambdaUpdateChainWrapper.set(ProcessInstanceRecord::getFinishReason, aBoolean));
// 执行更新
lambdaUpdateChainWrapper.eq(ProcessInstanceRecord::getProcessInstanceId, processInstanceParamDto.getProcessInstanceId()).update(new ProcessInstanceRecord());
return R.ok();
}
/**
* 查询我发起的流程
* <p>
* 查询当前用户发起的所有流程实例,支持: 1. 按状态过滤(进行中、已完成等) 2. 按时间范围过滤 3. 分页查询
* </p>
*
* @param taskQueryParamDto 查询条件,包含状态、时间范围、分页参数
* @return R 包含分页后的流程实例列表
*/
@Override
public R queryMineStarted(TaskQueryParamDto taskQueryParamDto) {
long userId = SecurityUtils.getUser().getId();
Page<ProcessInstanceRecord> instanceRecordPage = processInstanceRecordService.lambdaQuery().eq(ProcessInstanceRecord::getUserId, userId).eq(ProcessInstanceRecord::getStatus, taskQueryParamDto.getStatus()).between(ArrayUtil.isNotEmpty(taskQueryParamDto.getTaskTime()), ProcessInstanceRecord::getCreateTime, ArrayUtil.isNotEmpty(taskQueryParamDto.getTaskTime()) ? taskQueryParamDto.getTaskTime()[0] : null, ArrayUtil.isNotEmpty(taskQueryParamDto.getTaskTime()) ? taskQueryParamDto.getTaskTime()[1] : null).orderByDesc(ProcessInstanceRecord::getCreateTime).page(new Page<>(taskQueryParamDto.getCurrent(), taskQueryParamDto.getSize()));
return R.ok(instanceRecordPage);
}
/**
* 查询抄送给我的流程
* <p>
* 查询抄送给当前用户的流程列表。抄送功能允许流程参与者将流程信息 通知给其他相关人员,被抄送人可以查看流程但不参与审批
* </p>
*
* @param taskQueryParamDto 查询参数,支持时间范围过滤和分页
* @return R 包含分页后的抄送记录,包括发起人信息
*/
@Override
public R queryMineCC(TaskQueryParamDto taskQueryParamDto) {
long userId = SecurityUtils.getUser().getId();
Page<ProcessCopy> page = processCopyService.lambdaQuery().eq(ProcessCopy::getUserId, userId).between(ArrayUtil.isNotEmpty(taskQueryParamDto.getTaskTime()), ProcessCopy::getCreateTime, ArrayUtil.isNotEmpty(taskQueryParamDto.getTaskTime()) ? taskQueryParamDto.getTaskTime()[0] : null, ArrayUtil.isNotEmpty(taskQueryParamDto.getTaskTime()) ? taskQueryParamDto.getTaskTime()[1] : null).orderByDesc(ProcessCopy::getNodeTime).page(new Page<>(taskQueryParamDto.getCurrent(), taskQueryParamDto.getSize()));
List<ProcessCopy> records = page.getRecords();
List<ProcessCopyVo> processCopyVoList = BeanUtil.copyToList(records, ProcessCopyVo.class);
if (CollUtil.isNotEmpty(records)) {
// 发起人
List<Long> userIdList = records.stream().map(ProcessCopy::getStartUserId).toList();
List<SysUser> startUserList = userService.getUserById(userIdList).getData();
for (ProcessCopyVo record : processCopyVoList) {
SysUser startUser = startUserList.stream().filter(w -> w.getUserId().longValue() == record.getStartUserId()).findAny().orElse(null);
record.setStartUserName(startUser.getUsername());
}
}
Page p = BeanUtil.copyProperties(page, Page.class);
p.setRecords(processCopyVoList);
return R.ok(p);
}
/**
* 格式化流程显示
* <p>
* 将流程定义数据格式化为前端可展示的节点结构,主要功能: 1. 解析流程定义的JSON数据 2. 标记已完成的节点 3. 根据流程变量计算条件节点的显示状态 4.
* 处理节点权限和表单权限
* <p>
* 该方法用于流程图的可视化展示
* </p>
*
* @param nodeFormatParamVo 格式化参数,包含: - flowId: 流程定义ID - processInstanceId: 流程实例ID -
* taskId: 任务ID(可选) - paramMap: 流程变量
* @return R 包含格式化后的节点列表
*/
@SneakyThrows
@Override
public R formatStartNodeShow(NodeFormatParamVo nodeFormatParamVo) {
String flowId = nodeFormatParamVo.getFlowId();
String processInstanceId = nodeFormatParamVo.getProcessInstanceId();
if (StrUtil.isAllBlank(flowId, processInstanceId)) {
return R.ok(new ArrayList<>());
}
if (StrUtil.isBlankIfStr(flowId) && StrUtil.isNotBlank(processInstanceId)) {
ProcessInstanceRecord processInstanceRecord = processInstanceRecordService.lambdaQuery().eq(ProcessInstanceRecord::getProcessInstanceId, processInstanceId).one();
flowId = processInstanceRecord.getFlowId();
}
Map<String, Object> paramMap = nodeFormatParamVo.getParamMap();
if (StrUtil.isNotBlank(nodeFormatParamVo.getTaskId())) {
VariableQueryParamDto variableQueryParamDto = new VariableQueryParamDto();
variableQueryParamDto.setTaskId(nodeFormatParamVo.getTaskId());
Map<String, Object> variables;
List<String> keyList = variableQueryParamDto.getKeyList();
if (CollUtil.isEmpty(keyList)) {
TaskQuery taskQuery = taskService.createTaskQuery();
Task task = taskQuery.taskId(variableQueryParamDto.getTaskId()).singleResult();
if (task == null) {
return R.failed("任务不存在");
}
variables = runtimeService.getVariables(task.getExecutionId());
} else {
variables = taskService.getVariables(variableQueryParamDto.getTaskId(), keyList);
}
paramMap.putAll(variables);
}
Set<String> completeNodeSet = new HashSet<>();
Set<String> continueNodeSet = new HashSet<>();
if (StrUtil.isNotBlank(processInstanceId)) {
List<ProcessNodeRecord> processNodeRecordList = processNodeRecordService.lambdaQuery().eq(ProcessNodeRecord::getProcessInstanceId, processInstanceId).eq(ProcessNodeRecord::getStatus, NodeStatusEnum.YJS.getCode()).list();
Set<String> collect = processNodeRecordList.stream().map(ProcessNodeRecord::getNodeId).collect(Collectors.toSet());
List<ProcessNodeRecord> jxzNodeRecordList = processNodeRecordService.lambdaQuery().eq(ProcessNodeRecord::getProcessInstanceId, processInstanceId).eq(ProcessNodeRecord::getStatus, NodeStatusEnum.JXZ.getCode()).list();
Set<String> jxzCollect = jxzNodeRecordList.stream().map(ProcessNodeRecord::getNodeId).collect(Collectors.toSet());
continueNodeSet.addAll(jxzCollect);
completeNodeSet.addAll(collect);
}
Process oaForms = processService.getByFlowId(flowId);
String process = oaForms.getProcess();
Node nodeDto = objectMapper.readValue(process, new TypeReference<>() {
});
List<NodeVo> processNodeShowDtos = NodeFormatUtil.formatProcessNodeShow(nodeDto, completeNodeSet, continueNodeSet, processInstanceId, paramMap);
return R.ok(processNodeShowDtos);
}
/**
* 流程详情
* <p>
* 查询流程实例的详细信息,包括: 1. 流程定义信息(流程结构) 2. 表单项定义 3. 表单数据(用户填写的数据) 4. 表单权限配置 5. 流程状态信息
* <p>
* 该方法主要用于流程详情页面的数据展示
* </p>
*
* @param processInstanceId 流程实例ID
* @return R 包含流程详情的Dict对象
* @throws Exception 当解析JSON数据失败时抛出异常
*/
@SneakyThrows
@Override
public R detail(String processInstanceId) {
ProcessInstanceRecord processInstanceRecord = processInstanceRecordService.lambdaQuery().eq(ProcessInstanceRecord::getProcessInstanceId, processInstanceId).one();
Process oaForms = processService.getByFlowId(processInstanceRecord.getFlowId());
if (oaForms == null) {
return R.failed("流程不存在");
}
// 发起人变量数据
String formData = processInstanceRecord.getFormData();
String process = oaForms.getProcess();
Node nodeDto = objectMapper.readValue(process, Node.class);
Map<String, String> formPerms1 = nodeDto.getFormPerms();
Dict set = Dict.create().set(ProcessInstanceRecord.Fields.processInstanceId, processInstanceId).set(ProcessInstanceRecord.Fields.status, processInstanceRecord.getStatus()).set("process", oaForms.getProcess()).set("formItems", oaForms.getFormItems()).set("formData", formData).set("formData", formData).set("formConfig", oaForms.getFormConfig()).set("formPerms", formPerms1);
return R.ok(set);
}
}
@@ -42,305 +42,272 @@ import java.util.stream.Collectors;
*/
public class NodeFormatUtil {
/**
* 格式化流程节点为可视化展示结构
* <p>
* 递归处理流程节点树,生成包含节点状态、执行人信息的展示数据。 支持处理各种节点类型,包括审批节点、抄送节点、网关节点等。
* @param node 当前处理的节点对象
* @param completeNodeSet 已完成的节点ID集合
* @param continueNodeSet 进行中的节点ID集合
* @param processInstanceId 流程实例ID,用于查询历史数据,可为null
* @param paramMap 流程变量Map,包含表单数据和执行人选择信息
* @return 格式化后的节点展示对象列表
*/
@SneakyThrows
public static List<NodeVo> formatProcessNodeShow(Node node, Set<String> completeNodeSet,
Set<String> continueNodeSet, String processInstanceId, Map<String, Object> paramMap) {
List<NodeVo> list = new ArrayList<>();
/**
* 格式化流程节点为可视化展示结构
* <p>
* 递归处理流程节点树,生成包含节点状态、执行人信息的展示数据。 支持处理各种节点类型,包括审批节点、抄送节点、网关节点等。
*
* @param node 当前处理的节点对象
* @param completeNodeSet 已完成的节点ID集合
* @param continueNodeSet 进行中的节点ID集合
* @param processInstanceId 流程实例ID,用于查询历史数据,可为null
* @param paramMap 流程变量Map,包含表单数据和执行人选择信息
* @return 格式化后的节点展示对象列表
*/
@SneakyThrows
public static List<NodeVo> formatProcessNodeShow(Node node, Set<String> completeNodeSet, Set<String> continueNodeSet, String processInstanceId, Map<String, Object> paramMap) {
List<NodeVo> list = new ArrayList<>();
if (!NodeUtil.isNode(node)) {
return list;
}
if (!NodeUtil.isNode(node)) {
return list;
}
String name = node.getName();
Integer type = node.getType();
String name = node.getName();
Integer type = node.getType();
// SELF_SELECT
// SELF_SELECT
NodeVo nodeVo = new NodeVo();
nodeVo.setId(node.getId());
nodeVo.setName(name);
nodeVo.setType(type);
nodeVo.setStatus(NodeStatusEnum.WKS.getCode());
if (completeNodeSet.contains(node.getId())) {
nodeVo.setStatus(NodeStatusEnum.YJS.getCode());
NodeVo nodeVo = new NodeVo();
nodeVo.setId(node.getId());
nodeVo.setName(name);
nodeVo.setType(type);
nodeVo.setStatus(NodeStatusEnum.WKS.getCode());
if (completeNodeSet.contains(node.getId())) {
nodeVo.setStatus(NodeStatusEnum.YJS.getCode());
}
if (continueNodeSet.contains(node.getId())) {
nodeVo.setStatus(NodeStatusEnum.JXZ.getCode());
}
if (continueNodeSet.contains(node.getId())) {
nodeVo.setStatus(NodeStatusEnum.JXZ.getCode());
}
}
{
nodeVo.setPlaceholder(node.getPlaceHolder());
}
nodeVo.setPlaceholder(node.getPlaceHolder());
List<UserVo> userVoList = new ArrayList<>();
if (type == NodeTypeEnum.APPROVAL.getValue().intValue()) {
List<UserVo> userVoList = new ArrayList<>();
if (type == NodeTypeEnum.APPROVAL.getValue().intValue()) {
Integer assignedType = node.getAssignedType();
Integer assignedType = node.getAssignedType();
boolean selfSelect = assignedType == ProcessInstanceConstant.AssignedTypeClass.SELF_SELECT;
nodeVo.setSelectUser(selfSelect);
if (selfSelect) {
nodeVo.setMultiple(node.getMultiple());
}
boolean selfSelect = assignedType == ProcessInstanceConstant.AssignedTypeClass.SELF_SELECT;
nodeVo.setSelectUser(selfSelect);
if (selfSelect) {
nodeVo.setMultiple(node.getMultiple());
}
// 用户列表
if (StrUtil.isNotBlank(processInstanceId)) {
IProcessNodeRecordAssignUserService processNodeRecordAssignUserService = SpringUtil
.getBean(IProcessNodeRecordAssignUserService.class);
List<ProcessNodeRecordAssignUser> processNodeRecordAssignUserList = processNodeRecordAssignUserService
.lambdaQuery()
.eq(ProcessNodeRecordAssignUser::getNodeId, node.getId())
.eq(ProcessNodeRecordAssignUser::getProcessInstanceId, processInstanceId)
.orderByAsc(ProcessNodeRecordAssignUser::getCreateTime)
.list();
Map<String, List<ProcessNodeRecordAssignUser>> map = processNodeRecordAssignUserList.stream()
.collect(Collectors.groupingBy(ProcessNodeRecordAssignUser::getTaskId));
// 用户列表
if (StrUtil.isNotBlank(processInstanceId)) {
IProcessNodeRecordAssignUserService processNodeRecordAssignUserService = SpringUtil.getBean(IProcessNodeRecordAssignUserService.class);
List<ProcessNodeRecordAssignUser> processNodeRecordAssignUserList = processNodeRecordAssignUserService.lambdaQuery().eq(ProcessNodeRecordAssignUser::getNodeId, node.getId()).eq(ProcessNodeRecordAssignUser::getProcessInstanceId, processInstanceId).orderByAsc(ProcessNodeRecordAssignUser::getCreateTime).list();
Map<String, List<ProcessNodeRecordAssignUser>> map = processNodeRecordAssignUserList.stream().collect(Collectors.groupingBy(ProcessNodeRecordAssignUser::getTaskId));
for (Map.Entry<String, List<ProcessNodeRecordAssignUser>> entry : map.entrySet()) {
List<ProcessNodeRecordAssignUser> value = entry.getValue();
List<UserVo> collect = value.stream().map(w -> {
UserVo userVo = buildUser(w.getUserId());
if (userVo == null) {
return null;
}
for (Map.Entry<String, List<ProcessNodeRecordAssignUser>> entry : map.entrySet()) {
List<ProcessNodeRecordAssignUser> value = entry.getValue();
List<UserVo> collect = value.stream().map(w -> {
UserVo userVo = buildUser(w.getUserId());
if (userVo == null) {
return null;
}
userVo.setShowTime(w.getEndTime());
userVo.setApproveDesc(w.getApproveDesc());
userVo.setStatus(w.getStatus());
userVo.setOperType(w.getTaskType());
return userVo;
}).filter(Objects::nonNull).toList();
userVoList.addAll(collect);
}
userVo.setShowTime(w.getEndTime());
userVo.setApproveDesc(w.getApproveDesc());
userVo.setStatus(w.getStatus());
userVo.setOperType(w.getTaskType());
return userVo;
}).filter(Objects::nonNull).toList();
userVoList.addAll(collect);
}
if (processNodeRecordAssignUserList.isEmpty()) {
if (assignedType == ProcessInstanceConstant.AssignedTypeClass.SELF) {
// 发起人自己
userVoList.addAll(CollUtil.newArrayList(buildRootUser(processInstanceId)));
}
if (assignedType == ProcessInstanceConstant.AssignedTypeClass.SELF_SELECT) {
// 发起人自选
Object variable = paramMap.get(StrUtil.format("{}_assignee_select", node.getId()));
if (processNodeRecordAssignUserList.isEmpty()) {
if (assignedType == ProcessInstanceConstant.AssignedTypeClass.SELF) {
// 发起人自己
userVoList.addAll(CollUtil.newArrayList(buildRootUser(processInstanceId)));
}
if (assignedType == ProcessInstanceConstant.AssignedTypeClass.SELF_SELECT) {
// 发起人自选
Object variable = paramMap.get(StrUtil.format("{}_assignee_select", node.getId()));
ObjectMapper objectMapper = SpringUtil.getBean(ObjectMapper.class);
List<NodeUser> nodeUserDtos = objectMapper.readValue(objectMapper.writeValueAsString(variable),
new TypeReference<>() {
});
ObjectMapper objectMapper = SpringUtil.getBean(ObjectMapper.class);
List<NodeUser> nodeUserDtos = objectMapper.readValue(objectMapper.writeValueAsString(variable), new TypeReference<>() {
});
if (CollUtil.isNotEmpty(nodeUserDtos)) {
List<Long> collect = nodeUserDtos.stream().map(NodeUser::getId).toList();
for (Long aLong : collect) {
UserVo userVo = buildUser(aLong);
userVoList.addAll(CollUtil.newArrayList(userVo));
}
}
if (CollUtil.isNotEmpty(nodeUserDtos)) {
List<Long> collect = nodeUserDtos.stream().map(NodeUser::getId).toList();
for (Long aLong : collect) {
UserVo userVo = buildUser(aLong);
userVoList.addAll(CollUtil.newArrayList(userVo));
}
}
}
}
}
}
}
else if (assignedType == ProcessInstanceConstant.AssignedTypeClass.USER) {
// 指定用户
} else if (assignedType == ProcessInstanceConstant.AssignedTypeClass.USER) {
// 指定用户
List<NodeUser> nodeUserList = node.getNodeUserList();
List<UserVo> tempList = buildUser(nodeUserList);
userVoList.addAll(tempList);
List<NodeUser> nodeUserList = node.getNodeUserList();
List<UserVo> tempList = buildUser(nodeUserList);
userVoList.addAll(tempList);
}
else if (assignedType == ProcessInstanceConstant.AssignedTypeClass.FORM_USER) {
// 表单人员
String formUser = node.getFormUserId();
} else if (assignedType == ProcessInstanceConstant.AssignedTypeClass.FORM_USER) {
// 表单人员
String formUser = node.getFormUserId();
Object o = paramMap.get(formUser);
if (o != null) {
ObjectMapper objectMapper = SpringUtil.getBean(ObjectMapper.class);
String jsonString = objectMapper.writeValueAsString(o);
if (StrUtil.isNotBlank(jsonString)) {
List<NodeUser> nodeUserDtoList = objectMapper.readValue(jsonString, new TypeReference<>() {
});
List<Long> userIdList = nodeUserDtoList.stream().map(NodeUser::getId).toList();
for (Long aLong : userIdList) {
userVoList.addAll(CollUtil.newArrayList(buildUser(aLong)));
}
}
}
Object o = paramMap.get(formUser);
if (o != null) {
ObjectMapper objectMapper = SpringUtil.getBean(ObjectMapper.class);
String jsonString = objectMapper.writeValueAsString(o);
if (StrUtil.isNotBlank(jsonString)) {
List<NodeUser> nodeUserDtoList = objectMapper.readValue(jsonString, new TypeReference<>() {
});
List<Long> userIdList = nodeUserDtoList.stream().map(NodeUser::getId).toList();
for (Long aLong : userIdList) {
userVoList.addAll(CollUtil.newArrayList(buildUser(aLong)));
}
}
}
}
else if (assignedType == ProcessInstanceConstant.AssignedTypeClass.SELF) {
// 发起人自己
userVoList.addAll(CollUtil.newArrayList(buildUser(SecurityUtils.getUser().getId())));
}
} else if (assignedType == ProcessInstanceConstant.AssignedTypeClass.SELF) {
// 发起人自己
userVoList.addAll(CollUtil.newArrayList(buildUser(SecurityUtils.getUser().getId())));
} else if (assignedType == ProcessInstanceConstant.AssignedTypeClass.EXPRESSION) {
// 表达式
// Object result = getExpressionValue(paramMap, node.getAssignExpress());
// List<UserVo> userVos = Convert.toList(Long.class, result)
// .stream()
// .map(NodeFormatUtil::buildUser)
// .toList();
// userVoList.addAll(userVos);
}
else if (assignedType == ProcessInstanceConstant.AssignedTypeClass.EXPRESSION) {
// 表达式
// Object result = getExpressionValue(paramMap, node.getAssignExpress());
// List<UserVo> userVos = Convert.toList(Long.class, result)
// .stream()
// .map(NodeFormatUtil::buildUser)
// .toList();
// userVoList.addAll(userVos);
}
} else if (Objects.equals(node.getType(), NodeTypeEnum.ROOT.getValue())) {
// 发起节点
if (StrUtil.isBlank(processInstanceId)) {
UserVo userVo = buildUser(SecurityUtils.getUser().getId());
userVoList.addAll(CollUtil.newArrayList(userVo));
} else {
}
else if (Objects.equals(node.getType(), NodeTypeEnum.ROOT.getValue())) {
// 发起节点
if (StrUtil.isBlank(processInstanceId)) {
UserVo userVo = buildUser(SecurityUtils.getUser().getId());
userVoList.addAll(CollUtil.newArrayList(userVo));
}
else {
IProcessInstanceRecordService processInstanceRecordService = SpringUtil.getBean(IProcessInstanceRecordService.class);
ProcessInstanceRecord processInstanceRecord = processInstanceRecordService.lambdaQuery().eq(ProcessInstanceRecord::getProcessInstanceId, processInstanceId).one();
IProcessInstanceRecordService processInstanceRecordService = SpringUtil
.getBean(IProcessInstanceRecordService.class);
ProcessInstanceRecord processInstanceRecord = processInstanceRecordService.lambdaQuery()
.eq(ProcessInstanceRecord::getProcessInstanceId, processInstanceId)
.one();
UserVo userVo = buildRootUser(processInstanceId);
userVo.setShowTime(processInstanceRecord.getCreateTime());
userVo.setStatus(NodeStatusEnum.YJS.getCode());
userVoList.addAll(CollUtil.newArrayList(userVo));
UserVo userVo = buildRootUser(processInstanceId);
userVo.setShowTime(processInstanceRecord.getCreateTime());
userVo.setStatus(NodeStatusEnum.YJS.getCode());
userVoList.addAll(CollUtil.newArrayList(userVo));
}
} else if (Objects.equals(node.getType(), NodeTypeEnum.CC.getValue())) {
// 抄送节点
}
}
else if (Objects.equals(node.getType(), NodeTypeEnum.CC.getValue())) {
// 抄送节点
List<NodeUser> nodeUserList = node.getNodeUserList();
List<NodeUser> nodeUserList = node.getNodeUserList();
List<UserVo> tempList = buildUser(nodeUserList);
userVoList.addAll(tempList);
List<UserVo> tempList = buildUser(nodeUserList);
userVoList.addAll(tempList);
}
}
// 根据userVo 的ID 去重userVoList
nodeVo.setUserVoList(CollUtil.distinct(userVoList, UserVo::getId, true));
// 根据userVo 的ID 去重userVoList
nodeVo.setUserVoList(CollUtil.distinct(userVoList, UserVo::getId, true));
List<NodeVo> branchList = new ArrayList<>();
List<NodeVo> branchList = new ArrayList<>();
if (type == NodeTypeEnum.EXCLUSIVE_GATEWAY.getValue().intValue() || type == NodeTypeEnum.PARALLEL_GATEWAY.getValue().intValue()) {
// 条件分支
List<Node> branchs = node.getConditionNodes();
if (type == NodeTypeEnum.EXCLUSIVE_GATEWAY.getValue().intValue()
|| type == NodeTypeEnum.PARALLEL_GATEWAY.getValue().intValue()) {
// 条件分支
List<Node> branchs = node.getConditionNodes();
for (Node branch : branchs) {
Node children = branch.getChildren();
List<NodeVo> processNodeShowDtos = formatProcessNodeShow(children, completeNodeSet, continueNodeSet, processInstanceId, paramMap);
for (Node branch : branchs) {
Node children = branch.getChildren();
List<NodeVo> processNodeShowDtos = formatProcessNodeShow(children, completeNodeSet, continueNodeSet,
processInstanceId, paramMap);
NodeVo p = new NodeVo();
p.setChildren(processNodeShowDtos);
NodeVo p = new NodeVo();
p.setChildren(processNodeShowDtos);
p.setPlaceholder(branch.getPlaceHolder());
branchList.add(p);
}
}
nodeVo.setBranch(branchList);
p.setPlaceholder(branch.getPlaceHolder());
branchList.add(p);
}
}
nodeVo.setBranch(branchList);
list.add(nodeVo);
list.add(nodeVo);
List<NodeVo> next = formatProcessNodeShow(node.getChildren(), completeNodeSet, continueNodeSet, processInstanceId, paramMap);
list.addAll(next);
List<NodeVo> next = formatProcessNodeShow(node.getChildren(), completeNodeSet, continueNodeSet,
processInstanceId, paramMap);
list.addAll(next);
return list;
}
return list;
}
/**
* 根据流程实例ID构建发起人用户信息
* <p>
* 查询流程实例记录,获取发起人的用户ID,并构建用户展示对象。 主要用于展示流程的发起人信息。
*
* @param processInstanceId 流程实例ID
* @return 发起人的用户展示对象
*/
private static UserVo buildRootUser(String processInstanceId) {
/**
* 根据流程实例ID构建发起人用户信息
* <p>
* 查询流程实例记录,获取发起人的用户ID,并构建用户展示对象。 主要用于展示流程的发起人信息。
* @param processInstanceId 流程实例ID
* @return 发起人的用户展示对象
*/
private static UserVo buildRootUser(String processInstanceId) {
IProcessInstanceRecordService processInstanceRecordService = SpringUtil.getBean(IProcessInstanceRecordService.class);
ProcessInstanceRecord processInstanceRecord = processInstanceRecordService.lambdaQuery().eq(ProcessInstanceRecord::getProcessInstanceId, processInstanceId).one();
Long userId = processInstanceRecord.getUserId();
return buildUser(userId);
}
IProcessInstanceRecordService processInstanceRecordService = SpringUtil
.getBean(IProcessInstanceRecordService.class);
ProcessInstanceRecord processInstanceRecord = processInstanceRecordService.lambdaQuery()
.eq(ProcessInstanceRecord::getProcessInstanceId, processInstanceId)
.one();
Long userId = processInstanceRecord.getUserId();
return buildUser(userId);
}
/**
* 根据用户ID构建用户展示信息
* <p>
* 通过远程服务获取用户详细信息,并构建用户展示对象。 如果用户不存在或为空执行人ID,返回特殊处理的对象。
*
* @param userId 用户ID
* @return 用户展示对象,如果用户不存在则返回null
*/
private static UserVo buildUser(long userId) {
if (ProcessInstanceConstant.DEFAULT_EMPTY_ASSIGN == userId) {
return UserVo.builder().id(userId).build();
}
/**
* 根据用户ID构建用户展示信息
* <p>
* 通过远程服务获取用户详细信息,并构建用户展示对象。 如果用户不存在或为空执行人ID,返回特殊处理的对象。
* @param userId 用户ID
* @return 用户展示对象,如果用户不存在则返回null
*/
private static UserVo buildUser(long userId) {
if (ProcessInstanceConstant.DEFAULT_EMPTY_ASSIGN == userId) {
return UserVo.builder().id(userId).build();
}
RemoteUserService userService = SpringUtil.getBean(RemoteUserService.class);
SysUser user = RetOps.of(userService.getUserById(CollUtil.newArrayList(userId))).getData().map(sysUsers -> sysUsers.isEmpty() ? null : sysUsers.get(0)).orElse(null);
if (user == null) {
return null;
}
RemoteUserService userService = SpringUtil.getBean(RemoteUserService.class);
SysUser user = RetOps.of(userService.getUserById(CollUtil.newArrayList(userId)))
.getData()
.map(sysUsers -> sysUsers.isEmpty() ? null : sysUsers.get(0))
.orElse(null);
if (user == null) {
return null;
}
return UserVo.builder().id(userId).name(user.getName()).avatar(user.getAvatar()).build();
}
return UserVo.builder().id(userId).name(user.getName()).avatar(user.getAvatar()).build();
}
/**
* 批量构建用户展示信息
* <p>
* 根据节点用户配置列表,批量获取用户信息并构建展示对象。 支持处理用户类型和部门类型: - 用户类型:直接获取用户信息 - 部门类型:获取部门下的所有用户
*
* @param nodeUserList 节点用户配置列表,包含用户ID和部门ID
* @return 用户展示对象列表
*/
private static List<UserVo> buildUser(List<NodeUser> nodeUserList) {
List<UserVo> userVoList = new ArrayList<>();
// 用户id
List<Long> userIdList = nodeUserList.stream().filter(w -> StrUtil.equals(w.getType(), NodeUserTypeEnum.USER.getKey())).map(w -> Convert.toLong(w.getId())).toList();
// 部门id
List<Long> deptIdList = nodeUserList.stream().filter(w -> StrUtil.equals(w.getType(), NodeUserTypeEnum.DEPT.getKey())).map(w -> Convert.toLong(w.getId())).toList();
/**
* 批量构建用户展示信息
* <p>
* 根据节点用户配置列表,批量获取用户信息并构建展示对象。 支持处理用户类型和部门类型: - 用户类型:直接获取用户信息 - 部门类型:获取部门下的所有用户
* @param nodeUserList 节点用户配置列表,包含用户ID和部门ID
* @return 用户展示对象列表
*/
private static List<UserVo> buildUser(List<NodeUser> nodeUserList) {
List<UserVo> userVoList = new ArrayList<>();
// 用户id
List<Long> userIdList = nodeUserList.stream()
.filter(w -> StrUtil.equals(w.getType(), NodeUserTypeEnum.USER.getKey()))
.map(w -> Convert.toLong(w.getId()))
.toList();
// 部门id
List<Long> deptIdList = nodeUserList.stream()
.filter(w -> StrUtil.equals(w.getType(), NodeUserTypeEnum.DEPT.getKey()))
.map(w -> Convert.toLong(w.getId()))
.toList();
if (CollUtil.isNotEmpty(deptIdList)) {
if (CollUtil.isNotEmpty(deptIdList)) {
IRemoteService iRemoteService = SpringUtil.getBean(IRemoteService.class);
IRemoteService iRemoteService = SpringUtil.getBean(IRemoteService.class);
List<Long> data = iRemoteService.queryUserIdListByDepIdList(deptIdList).getData();
List<Long> data = iRemoteService.queryUserIdListByDepIdList(deptIdList).getData();
if (CollUtil.isNotEmpty(data)) {
for (long datum : data) {
if (!userIdList.contains(datum)) {
userIdList.add(datum);
}
}
}
}
{
for (Long aLong : userIdList) {
userVoList.addAll(CollUtil.newArrayList(buildUser(aLong)));
}
}
return userVoList;
}
if (CollUtil.isNotEmpty(data)) {
for (long datum : data) {
if (!userIdList.contains(datum)) {
userIdList.add(datum);
}
}
}
}
{
for (Long aLong : userIdList) {
userVoList.addAll(CollUtil.newArrayList(buildUser(aLong)));
}
}
return userVoList;
}
}