| | |
| | | import com.sinata.appointment.dto.ApprovalFlowGroupVo; |
| | | import com.sinata.appointment.dto.ApprovalFlowNodeVo; |
| | | import com.sinata.appointment.dto.ApprovalFlowTaskUserVo; |
| | | import com.sinata.appointment.dto.MiniVisitedUserVo; |
| | | import com.sinata.appointment.entity.AppointmentOrder; |
| | | import com.sinata.appointment.entity.ApprovalInstance; |
| | | import com.sinata.appointment.entity.ApprovalTask; |
| | | import com.sinata.appointment.entity.BizApprovalNodeConfig; |
| | | import com.sinata.appointment.entity.MpPassLocalUnit; |
| | | import com.sinata.appointment.entity.MpStaffGroup; |
| | | import com.sinata.appointment.entity.MpUser; |
| | | import com.sinata.appointment.entity.SysDept; |
| | |
| | | import com.sinata.appointment.mapper.ApprovalInstanceMapper; |
| | | import com.sinata.appointment.mapper.ApprovalTaskMapper; |
| | | import com.sinata.appointment.mapper.BizApprovalNodeConfigMapper; |
| | | import com.sinata.appointment.mapper.MpPassLocalUnitMapper; |
| | | import com.sinata.appointment.mapper.MpStaffGroupMapper; |
| | | import com.sinata.appointment.mapper.MpUserMapper; |
| | | import com.sinata.appointment.mapper.SysDeptMapper; |
| | |
| | | import java.util.Map; |
| | | import java.util.Objects; |
| | | import java.util.Set; |
| | | import java.util.stream.Collectors; |
| | | import lombok.RequiredArgsConstructor; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.util.StringUtils; |
| | |
| | | public class ApprovalFlowViewApplicationService { |
| | | |
| | | private static final TypeReference<List<String>> STRING_LIST_TYPE = new TypeReference<>() {}; |
| | | private static final TypeReference<List<Long>> LONG_LIST_TYPE = new TypeReference<>() {}; |
| | | |
| | | private final ApprovalInstanceMapper approvalInstanceMapper; |
| | | private final ApprovalTaskMapper approvalTaskMapper; |
| | |
| | | private final MpUserMapper mpUserMapper; |
| | | private final SysDeptMapper sysDeptMapper; |
| | | private final MpStaffGroupMapper mpStaffGroupMapper; |
| | | private final MpPassLocalUnitMapper mpPassLocalUnitMapper; |
| | | private final ObjectMapper objectMapper; |
| | | |
| | | public List<ApprovalFlowNodeVo> treeByOrderId(Long orderId) { |
| | |
| | | Map<Long, String> deptNameMap = loadDeptNameMap(tasks); |
| | | Map<Long, String> staffGroupNameMap = loadStaffGroupNameMap(tasks); |
| | | List<String> localUnitNames = parseStringList(order == null ? null : order.getPassLocalUnitNames()); |
| | | Map<Long, String> localUnitNameMap = loadLocalUnitNameMap(order, tasks); |
| | | |
| | | LinkedHashMap<String, LinkedHashMap<String, List<ApprovalTask>>> byNode = new LinkedHashMap<>(); |
| | | for (ApprovalTask t : tasks) { |
| | |
| | | List<ApprovalTask> groupTasks = groupEntry.getValue(); |
| | | ApprovalFlowGroupVo g = new ApprovalFlowGroupVo(); |
| | | g.setGroupKey(groupKey); |
| | | GroupMeta meta = resolveGroupMeta(nodeCode, groupKey, deptNameMap, staffGroupNameMap, localUnitNames, tmpIdx); |
| | | GroupMeta meta = |
| | | resolveGroupMeta( |
| | | nodeCode, |
| | | groupKey, |
| | | deptNameMap, |
| | | staffGroupNameMap, |
| | | localUnitNames, |
| | | localUnitNameMap, |
| | | tmpIdx); |
| | | if ("TEMP_GROUP".equals(meta.groupType())) { |
| | | tmpIdx++; |
| | | } |
| | |
| | | u.setTaskStatus(t.getTaskStatus()); |
| | | u.setComment(t.getComment()); |
| | | u.setActionTime(t.getUpdateTime()); |
| | | u.setNoticeUsers(loadNoticeUsers(t.getNoticeIds(), userMap, deptNameMap)); |
| | | g.getUsers().add(u); |
| | | } |
| | | nodeVo.getGroups().add(g); |
| | |
| | | return out; |
| | | } |
| | | |
| | | private Map<Long, String> loadLocalUnitNameMap(AppointmentOrder order, List<ApprovalTask> tasks) { |
| | | Set<Long> unitIds = new LinkedHashSet<>(); |
| | | for (ApprovalTask task : tasks) { |
| | | Long unitId = parseTailId(task.getGroupKey(), ":UNIT:"); |
| | | if (unitId != null && unitId > 0) { |
| | | unitIds.add(unitId); |
| | | } |
| | | } |
| | | if (unitIds.isEmpty()) { |
| | | return Map.of(); |
| | | } |
| | | |
| | | Map<Long, String> out = new LinkedHashMap<>(); |
| | | if (order != null) { |
| | | List<Long> orderUnitIds = parseLongList(order.getPassLocalUnitIds()); |
| | | List<String> orderUnitNames = parseStringList(order.getPassLocalUnitNames()); |
| | | int size = Math.min(orderUnitIds.size(), orderUnitNames.size()); |
| | | for (int i = 0; i < size; i++) { |
| | | Long unitId = orderUnitIds.get(i); |
| | | String unitName = orderUnitNames.get(i); |
| | | if (unitId != null && unitId > 0 && StringUtils.hasText(unitName)) { |
| | | out.put(unitId, unitName); |
| | | } |
| | | } |
| | | } |
| | | |
| | | Set<Long> missingIds = |
| | | unitIds.stream() |
| | | .filter(id -> !out.containsKey(id)) |
| | | .collect(Collectors.toCollection(LinkedHashSet::new)); |
| | | if (missingIds.isEmpty()) { |
| | | return out; |
| | | } |
| | | List<MpPassLocalUnit> rows = |
| | | mpPassLocalUnitMapper.selectList( |
| | | new LambdaQueryWrapper<MpPassLocalUnit>() |
| | | .eq(MpPassLocalUnit::getDelFlag, 0) |
| | | .in(MpPassLocalUnit::getId, missingIds)); |
| | | for (MpPassLocalUnit row : rows) { |
| | | if (row.getId() != null && StringUtils.hasText(row.getUnitName())) { |
| | | out.put(row.getId(), row.getUnitName()); |
| | | } |
| | | } |
| | | return out; |
| | | } |
| | | |
| | | private GroupMeta resolveGroupMeta( |
| | | String nodeCode, |
| | | String groupKey, |
| | | Map<Long, String> deptNameMap, |
| | | Map<Long, String> staffGroupNameMap, |
| | | List<String> localUnitNames, |
| | | Map<Long, String> localUnitNameMap, |
| | | int tmpIdx) { |
| | | if (!ApprovalNodeCode.LEVEL3_LOCAL_DEPT_LEADER.equals(nodeCode)) { |
| | | return new GroupMeta("DEFAULT", "审批人"); |
| | | } |
| | | Long localUnitId = parseTailId(groupKey, ":UNIT:"); |
| | | if (localUnitId != null) { |
| | | String name = localUnitNameMap.getOrDefault(localUnitId, "属地#" + localUnitId); |
| | | return new GroupMeta("TEMP_GROUP", name); |
| | | } |
| | | Long deptId = parseTailId(groupKey, ":DEPT:"); |
| | | if (deptId != null) { |
| | |
| | | } |
| | | } |
| | | |
| | | private List<Long> parseLongList(String json) { |
| | | if (!StringUtils.hasText(json)) { |
| | | return List.of(); |
| | | } |
| | | try { |
| | | List<Long> rows = objectMapper.readValue(json, LONG_LIST_TYPE); |
| | | if (rows == null) { |
| | | return List.of(); |
| | | } |
| | | List<Long> out = new ArrayList<>(); |
| | | for (Long row : rows) { |
| | | if (row != null && row > 0) { |
| | | out.add(row); |
| | | } |
| | | } |
| | | return out; |
| | | } catch (Exception ex) { |
| | | return List.of(); |
| | | } |
| | | } |
| | | |
| | | private List<MiniVisitedUserVo> loadNoticeUsers( |
| | | String noticeIds, Map<Long, MpUser> existingUserMap, Map<Long, String> existingDeptNameMap) { |
| | | List<Long> ids = parseCommaSeparatedIds(noticeIds); |
| | | if (ids.isEmpty()) { |
| | | return List.of(); |
| | | } |
| | | Map<Long, MpUser> userMap = existingUserMap; |
| | | LinkedHashSet<Long> missingIds = ids.stream() |
| | | .filter(id -> !existingUserMap.containsKey(id)) |
| | | .collect(Collectors.toCollection(LinkedHashSet::new)); |
| | | if (!missingIds.isEmpty()) { |
| | | List<MpUser> extraUsers = |
| | | mpUserMapper.selectList( |
| | | new LambdaQueryWrapper<MpUser>() |
| | | .eq(MpUser::getDelFlag, 0) |
| | | .in(MpUser::getId, missingIds)); |
| | | userMap = new LinkedHashMap<>(existingUserMap); |
| | | for (MpUser extraUser : extraUsers) { |
| | | userMap.put(extraUser.getId(), extraUser); |
| | | } |
| | | } |
| | | |
| | | Map<Long, String> deptNameMap = existingDeptNameMap; |
| | | LinkedHashSet<Long> missingDeptIds = ids.stream() |
| | | .map(userMap::get) |
| | | .filter(Objects::nonNull) |
| | | .map(MpUser::getDeptId) |
| | | .filter(Objects::nonNull) |
| | | .filter(id -> id > 0 && !existingDeptNameMap.containsKey(id)) |
| | | .collect(Collectors.toCollection(LinkedHashSet::new)); |
| | | if (!missingDeptIds.isEmpty()) { |
| | | deptNameMap = new LinkedHashMap<>(existingDeptNameMap); |
| | | List<SysDept> depts = |
| | | sysDeptMapper.selectList( |
| | | new LambdaQueryWrapper<SysDept>() |
| | | .eq(SysDept::getDelFlag, 0) |
| | | .in(SysDept::getId, missingDeptIds)); |
| | | for (SysDept dept : depts) { |
| | | deptNameMap.put(dept.getId(), dept.getDeptName()); |
| | | } |
| | | } |
| | | |
| | | List<MiniVisitedUserVo> result = new ArrayList<>(); |
| | | for (Long id : ids) { |
| | | MpUser user = userMap.get(id); |
| | | if (user == null) { |
| | | continue; |
| | | } |
| | | MiniVisitedUserVo vo = new MiniVisitedUserVo(); |
| | | vo.setId(user.getId()); |
| | | vo.setRealName(resolveUserName(user)); |
| | | vo.setDeptName(user.getDeptId() == null ? null : deptNameMap.get(user.getDeptId())); |
| | | result.add(vo); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | private List<Long> parseCommaSeparatedIds(String raw) { |
| | | if (!StringUtils.hasText(raw)) { |
| | | return List.of(); |
| | | } |
| | | LinkedHashSet<Long> out = new LinkedHashSet<>(); |
| | | for (String part : raw.split(",")) { |
| | | if (!StringUtils.hasText(part)) { |
| | | continue; |
| | | } |
| | | try { |
| | | long id = Long.parseLong(part.trim()); |
| | | if (id > 0) { |
| | | out.add(id); |
| | | } |
| | | } catch (NumberFormatException ignored) { |
| | | } |
| | | } |
| | | return new ArrayList<>(out); |
| | | } |
| | | |
| | | private String calcNodeStatus(List<ApprovalFlowGroupVo> groups) { |
| | | if (groups.isEmpty()) { |
| | | return ApprovalTaskStatus.WAITING; |
| | | } |
| | | boolean hasRejected = false; |
| | | boolean hasCancelled = false; |
| | | boolean hasPending = false; |
| | | boolean hasWaiting = false; |
| | | for (ApprovalFlowGroupVo g : groups) { |
| | | String s = g.getGroupStatus(); |
| | | if (ApprovalTaskStatus.REJECTED.equals(s)) { |
| | | hasRejected = true; |
| | | } else if (ApprovalTaskStatus.CANCELLED.equals(s)) { |
| | | hasCancelled = true; |
| | | } else if (ApprovalTaskStatus.PENDING.equals(s)) { |
| | | hasPending = true; |
| | | } else if (ApprovalTaskStatus.WAITING.equals(s)) { |
| | |
| | | } |
| | | if (hasRejected) { |
| | | return ApprovalTaskStatus.REJECTED; |
| | | } |
| | | if (hasCancelled) { |
| | | return ApprovalTaskStatus.CANCELLED; |
| | | } |
| | | if (hasPending) { |
| | | return ApprovalTaskStatus.PENDING; |
| | |
| | | return ApprovalTaskStatus.WAITING; |
| | | } |
| | | boolean hasRejected = false; |
| | | boolean hasCancelled = false; |
| | | boolean hasPending = false; |
| | | boolean hasWaiting = false; |
| | | for (ApprovalTask t : tasks) { |
| | | if (ApprovalTaskStatus.REJECTED.equals(t.getTaskStatus())) { |
| | | hasRejected = true; |
| | | } else if (ApprovalTaskStatus.CANCELLED.equals(t.getTaskStatus())) { |
| | | hasCancelled = true; |
| | | } else if (ApprovalTaskStatus.PENDING.equals(t.getTaskStatus())) { |
| | | hasPending = true; |
| | | } else if (ApprovalTaskStatus.WAITING.equals(t.getTaskStatus())) { |
| | |
| | | if (hasRejected) { |
| | | return ApprovalTaskStatus.REJECTED; |
| | | } |
| | | if (hasCancelled) { |
| | | return ApprovalTaskStatus.CANCELLED; |
| | | } |
| | | if (hasPending) { |
| | | return ApprovalTaskStatus.PENDING; |
| | | } |