| | |
| | | import com.sinata.appointment.constants.SystemSettingKeys; |
| | | import com.sinata.appointment.dto.MiniAppointmentCreateRequest; |
| | | import com.sinata.appointment.dto.MiniAppointmentListVo; |
| | | import com.sinata.appointment.dto.MiniApprovalHistoryRow; |
| | | import com.sinata.appointment.dto.MiniAppointmentVehicleItemRequest; |
| | | import com.sinata.appointment.dto.MiniApprovalDetailVisitorVo; |
| | | import com.sinata.appointment.dto.MiniMyAppointmentDetailVo; |
| | |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.util.StringUtils; |
| | | import org.springframework.context.ApplicationEventPublisher; |
| | | import com.sinata.appointment.service.event.AppointmentApprovedEvent; |
| | | |
| | | @Service |
| | | @RequiredArgsConstructor |
| | |
| | | private final PostApprovalOrchestrationService postApprovalOrchestrationService; |
| | | private final ApprovalFlowViewApplicationService approvalFlowViewApplicationService; |
| | | private final ObjectMapper objectMapper; |
| | | private final ApplicationEventPublisher applicationEventPublisher; |
| | | |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public Long create(MiniAppointmentCreateRequest req) { |
| | |
| | | |
| | | List<String> chain = approvalEngineService.resolveEnabledNodeChain(order); |
| | | if (chain.isEmpty()) { |
| | | postApprovalOrchestrationService.onOrderFullyApproved(appointmentOrderMapper.selectById(order.getId())); |
| | | applicationEventPublisher.publishEvent(new AppointmentApprovedEvent(order.getId())); |
| | | } else { |
| | | ApprovalInstance inst = approvalEngineService.startFlow(order); |
| | | if (inst == null) { |
| | | postApprovalOrchestrationService.onOrderFullyApproved(appointmentOrderMapper.selectById(order.getId())); |
| | | applicationEventPublisher.publishEvent(new AppointmentApprovedEvent(order.getId())); |
| | | } |
| | | } |
| | | return order.getId(); |
| | |
| | | public IPage<MiniAppointmentListVo> pageMine( |
| | | long page, long size, String status, String visitedUserNameKeyword, LocalDate visitDate) { |
| | | MpUser current = miniAuthApplicationService.currentMpUser(); |
| | | LambdaQueryWrapper<ApprovalTask> tq = |
| | | new LambdaQueryWrapper<ApprovalTask>() |
| | | .eq(ApprovalTask::getDelFlag, 0) |
| | | .eq(ApprovalTask::getAssigneeUserId, current.getId()) |
| | | .in( |
| | | ApprovalTask::getTaskStatus, |
| | | ApprovalTaskStatus.APPROVED, |
| | | ApprovalTaskStatus.REJECTED) |
| | | .orderByDesc(ApprovalTask::getUpdateTime) |
| | | .orderByDesc(ApprovalTask::getId); |
| | | if (StringUtils.hasText(status)) { |
| | | tq.eq(ApprovalTask::getTaskStatus, status.trim()); |
| | | Page<MiniApprovalHistoryRow> rowPage = new Page<>(Math.max(1L, page), Math.max(1L, size)); |
| | | IPage<MiniApprovalHistoryRow> pagedRows = |
| | | approvalTaskMapper.pageMiniApprovalHistory( |
| | | rowPage, |
| | | current.getId(), |
| | | trimToNull(status), |
| | | trimToNull(visitedUserNameKeyword), |
| | | visitDate); |
| | | Page<MiniAppointmentListVo> result = |
| | | new Page<>(pagedRows.getCurrent(), pagedRows.getSize(), pagedRows.getTotal()); |
| | | List<MiniApprovalHistoryRow> rows = pagedRows.getRecords(); |
| | | if (rows == null || rows.isEmpty()) { |
| | | result.setRecords(List.of()); |
| | | return result; |
| | | } |
| | | List<ApprovalTask> tasks = approvalTaskMapper.selectList(tq); |
| | | if (tasks.isEmpty()) { |
| | | return new Page<>(page, size); |
| | | } |
| | | |
| | | java.util.LinkedHashMap<Long, ApprovalTask> latestTaskByOrder = new java.util.LinkedHashMap<>(); |
| | | for (ApprovalTask task : tasks) { |
| | | ApprovalInstance inst = approvalInstanceMapper.selectById(task.getInstanceId()); |
| | | if (inst == null || (inst.getDelFlag() != null && inst.getDelFlag() == 1) || inst.getOrderId() == null) { |
| | | continue; |
| | | } |
| | | latestTaskByOrder.putIfAbsent(inst.getOrderId(), task); |
| | | } |
| | | if (latestTaskByOrder.isEmpty()) { |
| | | return new Page<>(page, size); |
| | | } |
| | | |
| | | List<AppointmentOrder> orders = |
| | | appointmentOrderMapper.selectList( |
| | | new LambdaQueryWrapper<AppointmentOrder>() |
| | | .eq(AppointmentOrder::getDelFlag, 0) |
| | | .in(AppointmentOrder::getId, latestTaskByOrder.keySet())); |
| | | java.util.Map<Long, AppointmentOrder> orderMap = |
| | | orders.stream().collect(java.util.stream.Collectors.toMap(AppointmentOrder::getId, x -> x, (a, b) -> a)); |
| | | |
| | | List<MiniAppointmentListVo> all = new java.util.ArrayList<>(); |
| | | for (var e : latestTaskByOrder.entrySet()) { |
| | | AppointmentOrder order = orderMap.get(e.getKey()); |
| | | if (order == null) { |
| | | continue; |
| | | } |
| | | if (StringUtils.hasText(visitedUserNameKeyword)) { |
| | | if (!StringUtils.hasText(order.getVisitedUserName()) |
| | | || !order.getVisitedUserName().contains(visitedUserNameKeyword.trim())) { |
| | | continue; |
| | | } |
| | | } |
| | | if (visitDate != null) { |
| | | if (order.getVisitStartDate() == null |
| | | || order.getVisitEndDate() == null |
| | | || visitDate.isBefore(order.getVisitStartDate()) |
| | | || visitDate.isAfter(order.getVisitEndDate())) { |
| | | continue; |
| | | } |
| | | } |
| | | List<AppointmentOrder> orders = rows.stream().map(this::toOrderSnapshot).toList(); |
| | | Map<Long, String> deptNameMap = loadDeptNameMap(orders); |
| | | Map<String, String> reasonNameMap = loadReasonNameMap(orders); |
| | | List<MiniAppointmentListVo> records = new ArrayList<>(); |
| | | for (MiniApprovalHistoryRow row : rows) { |
| | | AppointmentOrder order = toOrderSnapshot(row); |
| | | MiniAppointmentListVo vo = toListVo(order); |
| | | vo.setStatus(e.getValue().getTaskStatus()); |
| | | all.add(vo); |
| | | vo.setStatus(row.getTaskStatus()); |
| | | vo.setVisitedDeptName(deptNameMap.get(order.getVisitedDeptId())); |
| | | vo.setVisitedUserDisplay(buildVisitedUserDisplay(order.getVisitedUserName(), vo.getVisitedDeptName())); |
| | | vo.setVisitTimeText(buildVisitTimeText(order)); |
| | | vo.setVisitReasonText(buildVisitReasonText(order, reasonNameMap)); |
| | | vo.setAccessAreaText(buildAccessAreaText(order.getPassAccessAreaNames())); |
| | | records.add(vo); |
| | | } |
| | | return slicePage(page, size, all); |
| | | result.setRecords(records); |
| | | return result; |
| | | } |
| | | |
| | | public IPage<MiniVisitRecordListVo> pageVisitRecords( |
| | | long page, long size, String visitorNameKeyword, LocalDate visitDate) { |
| | | MpUser current = miniAuthApplicationService.currentMpUser(); |
| | | List<AppointmentOrder> orders = |
| | | appointmentOrderMapper.selectList( |
| | | new LambdaQueryWrapper<AppointmentOrder>() |
| | | .eq(AppointmentOrder::getDelFlag, 0) |
| | | .eq(AppointmentOrder::getStatus, AppointmentOrderStatus.APPROVED) |
| | | .eq(AppointmentOrder::getVisitedUserId, current.getId())); |
| | | if (orders.isEmpty()) { |
| | | return new Page<>(page, size); |
| | | Page<AppointmentOrder> orderPage = new Page<>(Math.max(1L, page), Math.max(1L, size)); |
| | | IPage<AppointmentOrder> pagedOrders = |
| | | appointmentOrderMapper.pageMiniVisitRecords( |
| | | orderPage, current.getId(), trimToNull(visitorNameKeyword), visitDate); |
| | | Page<MiniVisitRecordListVo> result = |
| | | new Page<>(pagedOrders.getCurrent(), pagedOrders.getSize(), pagedOrders.getTotal()); |
| | | List<AppointmentOrder> orders = pagedOrders.getRecords(); |
| | | if (orders == null || orders.isEmpty()) { |
| | | result.setRecords(List.of()); |
| | | return result; |
| | | } |
| | | List<Long> orderIds = orders.stream().map(AppointmentOrder::getId).filter(Objects::nonNull).toList(); |
| | | List<AppointmentVisitor> visitors = |
| | | appointmentVisitorMapper.selectList( |
| | | new LambdaQueryWrapper<AppointmentVisitor>() |
| | | .eq(AppointmentVisitor::getDelFlag, 0) |
| | | .in(AppointmentVisitor::getOrderId, orderIds) |
| | | .orderByAsc(AppointmentVisitor::getId)); |
| | | Map<Long, List<String>> visitorNamesMap = new java.util.LinkedHashMap<>(); |
| | | for (AppointmentVisitor row : visitors) { |
| | | visitorNamesMap.computeIfAbsent(row.getOrderId(), k -> new java.util.ArrayList<>()); |
| | | if (StringUtils.hasText(row.getName())) { |
| | | visitorNamesMap.get(row.getOrderId()).add(row.getName().trim()); |
| | | } |
| | | } |
| | | |
| | | List<MiniVisitRecordListVo> rows = new java.util.ArrayList<>(); |
| | | Map<Long, List<String>> visitorNamesMap = loadVisitorNamesMap(orders.stream().map(AppointmentOrder::getId).toList()); |
| | | List<MiniVisitRecordListVo> records = new ArrayList<>(); |
| | | for (AppointmentOrder order : orders) { |
| | | List<String> names = visitorNamesMap.getOrDefault(order.getId(), List.of()); |
| | | if (StringUtils.hasText(visitorNameKeyword)) { |
| | | String kw = visitorNameKeyword.trim(); |
| | | boolean hit = false; |
| | | for (String n : names) { |
| | | if (n.contains(kw)) { |
| | | hit = true; |
| | | break; |
| | | } |
| | | } |
| | | if (!hit) { |
| | | continue; |
| | | } |
| | | } |
| | | if (visitDate != null) { |
| | | if (order.getVisitStartDate() == null |
| | | || order.getVisitEndDate() == null |
| | | || visitDate.isBefore(order.getVisitStartDate()) |
| | | || visitDate.isAfter(order.getVisitEndDate())) { |
| | | continue; |
| | | } |
| | | } |
| | | MiniVisitRecordListVo vo = new MiniVisitRecordListVo(); |
| | | vo.setOrderId(order.getId()); |
| | | vo.setOrderNo(order.getOrderNo()); |
| | | vo.setVisitorNames(names); |
| | | vo.setVisitorNames(visitorNamesMap.getOrDefault(order.getId(), List.of())); |
| | | vo.setVisitStartDate(order.getVisitStartDate()); |
| | | vo.setVisitEndDate(order.getVisitEndDate()); |
| | | vo.setVisitTimeMode(order.getVisitTimeMode()); |
| | | vo.setVisitTimeSlot(order.getVisitTimeSlot()); |
| | | vo.setCreateTime(order.getCreateTime()); |
| | | rows.add(vo); |
| | | records.add(vo); |
| | | } |
| | | |
| | | rows.sort( |
| | | java.util.Comparator |
| | | .comparing( |
| | | MiniVisitRecordListVo::getVisitEndDate, |
| | | java.util.Comparator.nullsLast(java.util.Comparator.naturalOrder())) |
| | | .reversed() |
| | | .thenComparing( |
| | | this::singleDaySlotSortWeight, |
| | | java.util.Comparator.reverseOrder()) |
| | | .thenComparing( |
| | | MiniVisitRecordListVo::getCreateTime, |
| | | java.util.Comparator.nullsLast(java.util.Comparator.reverseOrder()))); |
| | | return slicePageVisitRecord(page, size, rows); |
| | | result.setRecords(records); |
| | | return result; |
| | | } |
| | | |
| | | public IPage<MiniAppointmentListVo> pageMyOrders( |
| | | long page, long size, String status, String keyword) { |
| | | MpUser current = miniAuthApplicationService.currentMpUser(); |
| | | List<AppointmentOrder> orders = |
| | | appointmentOrderMapper.selectList( |
| | | new LambdaQueryWrapper<AppointmentOrder>() |
| | | .eq(AppointmentOrder::getDelFlag, 0) |
| | | .eq(AppointmentOrder::getSubmitterId, current.getId()) |
| | | .orderByDesc(AppointmentOrder::getCreateTime) |
| | | .orderByDesc(AppointmentOrder::getId)); |
| | | if (orders.isEmpty()) { |
| | | return new Page<>(page, size); |
| | | Page<AppointmentOrder> orderPage = new Page<>(Math.max(1L, page), Math.max(1L, size)); |
| | | IPage<AppointmentOrder> pagedOrders = |
| | | appointmentOrderMapper.pageMiniMyOrders( |
| | | orderPage, current.getId(), trimToNull(status), trimToNull(keyword)); |
| | | Page<MiniAppointmentListVo> result = |
| | | new Page<>(pagedOrders.getCurrent(), pagedOrders.getSize(), pagedOrders.getTotal()); |
| | | List<AppointmentOrder> orders = pagedOrders.getRecords(); |
| | | if (orders == null || orders.isEmpty()) { |
| | | result.setRecords(List.of()); |
| | | return result; |
| | | } |
| | | |
| | | Map<Long, String> deptNameMap = loadDeptNameMap(orders); |
| | | Map<String, String> reasonNameMap = loadReasonNameMap(orders); |
| | | String normalizedKeyword = trimToNull(keyword); |
| | | String normalizedStatus = trimToNull(status); |
| | | List<MiniAppointmentListVo> rows = new ArrayList<>(); |
| | | List<MiniAppointmentListVo> records = new ArrayList<>(); |
| | | for (AppointmentOrder order : orders) { |
| | | MiniAppointmentListVo vo = toMyOrderListVo(order, deptNameMap, reasonNameMap); |
| | | if (StringUtils.hasText(normalizedStatus) |
| | | && !Objects.equals(normalizedStatus, vo.getDisplayStatus())) { |
| | | continue; |
| | | } |
| | | if (StringUtils.hasText(normalizedKeyword) |
| | | && !containsIgnoreCase(vo.getVisitedUserDisplay(), normalizedKeyword) |
| | | && !containsIgnoreCase(vo.getVisitReasonText(), normalizedKeyword)) { |
| | | continue; |
| | | } |
| | | rows.add(vo); |
| | | records.add(toMyOrderListVo(order, deptNameMap, reasonNameMap)); |
| | | } |
| | | |
| | | rows.sort( |
| | | Comparator.comparing( |
| | | MiniAppointmentListVo::getCreateTime, |
| | | Comparator.nullsLast(Comparator.reverseOrder())) |
| | | .thenComparing( |
| | | MiniAppointmentListVo::getId, |
| | | Comparator.nullsLast(Comparator.reverseOrder()))); |
| | | return slicePage(page, size, rows); |
| | | result.setRecords(records); |
| | | return result; |
| | | } |
| | | |
| | | public List<MiniMyVisitorCodeOrderVo> listMyVisitorCodes() { |
| | |
| | | return vo; |
| | | } |
| | | |
| | | private AppointmentOrder toOrderSnapshot(MiniApprovalHistoryRow row) { |
| | | AppointmentOrder order = new AppointmentOrder(); |
| | | order.setId(row.getId()); |
| | | order.setUuid(row.getUuid()); |
| | | order.setOrderNo(row.getOrderNo()); |
| | | order.setVisitedUserName(row.getVisitedUserName()); |
| | | order.setVisitedDeptId(row.getVisitedDeptId()); |
| | | order.setVisitStartDate(row.getVisitStartDate()); |
| | | order.setVisitEndDate(row.getVisitEndDate()); |
| | | order.setVisitReasonCode(row.getVisitReasonCode()); |
| | | order.setVisitReasonOther(row.getVisitReasonOther()); |
| | | order.setVisitTimeMode(row.getVisitTimeMode()); |
| | | order.setVisitTimeSlot(row.getVisitTimeSlot()); |
| | | order.setPassAccessAreaNames(row.getPassAccessAreaNames()); |
| | | order.setStatus(row.getStatus()); |
| | | order.setCreateTime(row.getCreateTime()); |
| | | return order; |
| | | } |
| | | |
| | | private Map<Long, String> loadDeptNameMap(List<AppointmentOrder> orders) { |
| | | Set<Long> deptIds = |
| | | orders.stream() |
| | |
| | | LinkedHashMap::new)); |
| | | } |
| | | |
| | | private Map<Long, List<String>> loadVisitorNamesMap(List<Long> orderIds) { |
| | | if (orderIds == null || orderIds.isEmpty()) { |
| | | return Map.of(); |
| | | } |
| | | List<AppointmentVisitor> visitors = |
| | | appointmentVisitorMapper.selectList( |
| | | new LambdaQueryWrapper<AppointmentVisitor>() |
| | | .eq(AppointmentVisitor::getDelFlag, 0) |
| | | .in(AppointmentVisitor::getOrderId, orderIds) |
| | | .orderByAsc(AppointmentVisitor::getId)); |
| | | Map<Long, List<String>> result = new LinkedHashMap<>(); |
| | | for (AppointmentVisitor row : visitors) { |
| | | result.computeIfAbsent(row.getOrderId(), k -> new ArrayList<>()); |
| | | if (StringUtils.hasText(row.getName())) { |
| | | result.get(row.getOrderId()).add(row.getName().trim()); |
| | | } |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | private String buildVisitedUserDisplay(String userName, String deptName) { |
| | | String name = trimToNull(userName); |
| | | String dept = trimToNull(deptName); |