| | |
| | | import com.sinata.appointment.constants.QrcodeTicketStatus; |
| | | import com.sinata.appointment.constants.SystemSettingKeys; |
| | | import com.sinata.appointment.dto.MiniAppointmentCreateRequest; |
| | | import com.sinata.appointment.dto.MiniAppointmentCreateResultVo; |
| | | import com.sinata.appointment.dto.MiniAppointmentListVo; |
| | | import com.sinata.appointment.dto.MiniApprovalHistoryRow; |
| | | import com.sinata.appointment.dto.MiniAppointmentVehicleItemRequest; |
| | |
| | | import com.sinata.appointment.dto.MiniMyAppointmentDetailVo; |
| | | import com.sinata.appointment.dto.MiniMyVisitorCodeOrderVo; |
| | | import com.sinata.appointment.dto.MiniMyVisitorCodeTicketVo; |
| | | import com.sinata.appointment.dto.MiniSharedAppointmentDetailVo; |
| | | import com.sinata.appointment.dto.MiniVisitRecordListVo; |
| | | import com.sinata.appointment.dto.ApprovalFlowNodeVo; |
| | | import com.sinata.appointment.entity.AppointmentOrder; |
| | |
| | | import java.util.Set; |
| | | import java.util.function.Function; |
| | | import java.util.stream.Collectors; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import lombok.RequiredArgsConstructor; |
| | | 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; |
| | | import com.sinata.appointment.service.event.AppointmentApproversNotifyEvent; |
| | | |
| | | @Slf4j |
| | | @Service |
| | | @RequiredArgsConstructor |
| | | public class MiniAppointmentApplicationService { |
| | |
| | | private final ApprovalEngineService approvalEngineService; |
| | | private final PostApprovalOrchestrationService postApprovalOrchestrationService; |
| | | private final ApprovalFlowViewApplicationService approvalFlowViewApplicationService; |
| | | private final SensitiveWordFilterService sensitiveWordFilterService; |
| | | private final IntegrationHikvisionService integrationHikvisionService; |
| | | private final ObjectMapper objectMapper; |
| | | private final ApplicationEventPublisher applicationEventPublisher; |
| | | |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public Long create(MiniAppointmentCreateRequest req) { |
| | | public MiniAppointmentCreateResultVo create(MiniAppointmentCreateRequest req) { |
| | | MpUser current = miniAuthApplicationService.currentMpUser(); |
| | | FieldRequiredContext required = loadFieldRequiredContext(); |
| | | MpUser visited = loadVisitedUser(req.getVisitedUserId()); |
| | |
| | | order.setVisitedUserName(StringUtils.hasText(visited.getNickName()) ? visited.getNickName() : "员工"); |
| | | order.setVisitedDeptId(visited.getDeptId()); |
| | | order.setVisitReasonCode(req.getVisitReasonCode().trim()); |
| | | order.setVisitReasonOther(trimToNull(req.getVisitReasonOther())); |
| | | order.setVisitReasonOther(sensitiveWordFilterService.filter(trimToNull(req.getVisitReasonOther()))); |
| | | order.setVisitorOrg(resolveVisitorOrg(visitorMap.values())); |
| | | order.setVisitTimeMode(mode); |
| | | order.setVisitTimeSlot( |
| | |
| | | order.setPersonEntryFlag(personEntry); |
| | | order.setVehicleEntryFlag(vehicleEntry); |
| | | order.setSubmitterId(current.getId()); |
| | | order.setSubmitterVisibleFlag(1); |
| | | order.setHolidayFlag(holidayFlag); |
| | | order.setStatus(AppointmentOrderStatus.PENDING_APPROVAL); |
| | | appointmentOrderMapper.insert(order); |
| | |
| | | ApprovalInstance inst = approvalEngineService.startFlow(order); |
| | | if (inst == null) { |
| | | applicationEventPublisher.publishEvent(new AppointmentApprovedEvent(order.getId())); |
| | | } else { |
| | | applicationEventPublisher.publishEvent( |
| | | new AppointmentApproversNotifyEvent(order.getId(), inst.getId())); |
| | | } |
| | | } |
| | | return order.getId(); |
| | | MiniAppointmentCreateResultVo result = new MiniAppointmentCreateResultVo(); |
| | | result.setId(order.getId()); |
| | | result.setUuid(order.getUuid()); |
| | | return result; |
| | | } |
| | | |
| | | @Transactional(rollbackFor = Exception.class) |
| | |
| | | ApprovalInstance latestInst = loadLatestInstanceByOrderId(order.getId()); |
| | | if (latestInst != null |
| | | && ApprovalInstanceStatus.IN_PROGRESS.equals(latestInst.getStatus())) { |
| | | approvalEngineService.rejectInstance(latestInst, CANCEL_REASON_BY_SUBMITTER); |
| | | approvalEngineService.cancelInstance(latestInst, CANCEL_REASON_BY_SUBMITTER); |
| | | } |
| | | |
| | | order.setStatus(AppointmentOrderStatus.CANCELLED); |
| | | order.setRejectReason(CANCEL_REASON_BY_SUBMITTER); |
| | | appointmentOrderMapper.updateById(order); |
| | | expireUnusedTicketsByOrderId(order.getId()); |
| | | } |
| | | |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void deleteMyOrderRecord(Long orderId, String uuid) { |
| | | if (orderId == null || orderId <= 0) { |
| | | throw new BizException(BizErrorCode.ORDER_NOT_FOUND, "预约单不存在"); |
| | | } |
| | | MpUser current = miniAuthApplicationService.currentMpUser(); |
| | | AppointmentOrder order = appointmentOrderMapper.selectById(orderId); |
| | | if (order == null || (order.getDelFlag() != null && order.getDelFlag() == 1)) { |
| | | throw new BizException(BizErrorCode.ORDER_NOT_FOUND, "预约单不存在"); |
| | | } |
| | | UuidAssert.match(order, uuid); |
| | | if (!Objects.equals(order.getSubmitterId(), current.getId())) { |
| | | throw new BizException(BizErrorCode.AUTH_FORBIDDEN, "仅预约发起人可删除"); |
| | | } |
| | | if (!isDeletableStatus(order.getStatus(), resolveDisplayStatus(order))) { |
| | | throw new BizException(BizErrorCode.ORDER_STATE_INVALID, "当前状态不可删除"); |
| | | } |
| | | order.setSubmitterVisibleFlag(0); |
| | | appointmentOrderMapper.updateById(order); |
| | | } |
| | | |
| | | public IPage<MiniAppointmentListVo> pageMine( |
| | |
| | | List<AppointmentOrder> orders = rows.stream().map(this::toOrderSnapshot).toList(); |
| | | Map<Long, String> deptNameMap = loadDeptNameMap(orders); |
| | | Map<String, String> reasonNameMap = loadReasonNameMap(orders); |
| | | List<Long> orderIds = orders.stream().map(AppointmentOrder::getId).filter(Objects::nonNull).toList(); |
| | | Map<Long, String> visitorDisplayMap = loadVisitorDisplayMapByOrderIds(orderIds); |
| | | Map<Long, String> plateTextMap = loadPlateTextMapByOrderIds(orderIds); |
| | | List<MiniAppointmentListVo> records = new ArrayList<>(); |
| | | for (MiniApprovalHistoryRow row : rows) { |
| | | AppointmentOrder order = toOrderSnapshot(row); |
| | |
| | | vo.setVisitTimeText(buildVisitTimeText(order)); |
| | | vo.setVisitReasonText(buildVisitReasonText(order, reasonNameMap)); |
| | | vo.setAccessAreaText(buildAccessAreaText(order.getPassAccessAreaNames())); |
| | | vo.setVisitorDisplayText(visitorDisplayMap.get(order.getId())); |
| | | vo.setPlateNoText(plateTextMap.get(order.getId())); |
| | | records.add(vo); |
| | | } |
| | | result.setRecords(records); |
| | |
| | | } |
| | | |
| | | public IPage<MiniVisitRecordListVo> pageVisitRecords( |
| | | long page, long size, String visitorNameKeyword, LocalDate visitDate) { |
| | | long page, long size, boolean futureOnly, String visitorNameKeyword, LocalDate visitDate) { |
| | | MpUser current = miniAuthApplicationService.currentMpUser(); |
| | | Page<AppointmentOrder> orderPage = new Page<>(Math.max(1L, page), Math.max(1L, size)); |
| | | IPage<AppointmentOrder> pagedOrders = |
| | | appointmentOrderMapper.pageMiniVisitRecords( |
| | | orderPage, current.getId(), trimToNull(visitorNameKeyword), visitDate); |
| | | orderPage, current.getId(), futureOnly, trimToNull(visitorNameKeyword), visitDate); |
| | | Page<MiniVisitRecordListVo> result = |
| | | new Page<>(pagedOrders.getCurrent(), pagedOrders.getSize(), pagedOrders.getTotal()); |
| | | List<AppointmentOrder> orders = pagedOrders.getRecords(); |
| | |
| | | result.setRecords(List.of()); |
| | | return result; |
| | | } |
| | | Map<String, String> reasonNameMap = loadReasonNameMap(orders); |
| | | List<Long> orderIds = orders.stream().map(AppointmentOrder::getId).filter(Objects::nonNull).toList(); |
| | | Map<Long, List<String>> visitorNamesMap = loadVisitorNamesMap(orders.stream().map(AppointmentOrder::getId).toList()); |
| | | Map<Long, String> visitorDisplayMap = loadVisitorDisplayMapByOrderIds(orderIds); |
| | | Map<Long, String> plateTextMap = loadPlateTextMapByOrderIds(orderIds); |
| | | List<MiniVisitRecordListVo> records = new ArrayList<>(); |
| | | for (AppointmentOrder order : orders) { |
| | | MiniVisitRecordListVo vo = new MiniVisitRecordListVo(); |
| | | vo.setOrderId(order.getId()); |
| | | vo.setOrderNo(order.getOrderNo()); |
| | | vo.setVisitorNames(visitorNamesMap.getOrDefault(order.getId(), List.of())); |
| | | vo.setVisitorDisplayText(visitorDisplayMap.get(order.getId())); |
| | | vo.setPlateNoText(plateTextMap.get(order.getId())); |
| | | vo.setVisitReasonText(buildVisitReasonText(order, reasonNameMap)); |
| | | vo.setVisitStartDate(order.getVisitStartDate()); |
| | | vo.setVisitEndDate(order.getVisitEndDate()); |
| | | vo.setVisitTimeMode(order.getVisitTimeMode()); |
| | |
| | | .eq(AppointmentOrder::getStatus, AppointmentOrderStatus.APPROVED) |
| | | .orderByDesc(AppointmentOrder::getVisitStartDate) |
| | | .orderByDesc(AppointmentOrder::getId)); |
| | | return buildVisitorCodeOrders(orders, true); |
| | | } |
| | | |
| | | public MiniSharedAppointmentDetailVo detailSharedOrder(String uuid) { |
| | | AppointmentOrder order = loadApprovedOrderByUuid(uuid); |
| | | String deptName = loadDeptName(order.getVisitedDeptId()); |
| | | MiniSharedAppointmentDetailVo vo = new MiniSharedAppointmentDetailVo(); |
| | | vo.setOrderId(order.getId()); |
| | | vo.setOrderUuid(order.getUuid()); |
| | | vo.setVisitedUserDisplay(buildVisitedUserDisplay(order.getVisitedUserName(), deptName)); |
| | | vo.setAccessAreaText(buildAccessAreaText(order.getPassAccessAreaNames())); |
| | | vo.setVisitTimeText(buildVisitTimeText(order)); |
| | | return vo; |
| | | } |
| | | |
| | | public MiniMyVisitorCodeOrderVo getSharedVisitorCodes(String uuid) { |
| | | AppointmentOrder order = loadApprovedOrderByUuid(uuid); |
| | | List<MiniMyVisitorCodeOrderVo> rows = buildVisitorCodeOrders(List.of(order), false); |
| | | if (rows.isEmpty()) { |
| | | MiniMyVisitorCodeOrderVo vo = new MiniMyVisitorCodeOrderVo(); |
| | | vo.setOrderId(order.getId()); |
| | | vo.setOrderUuid(order.getUuid()); |
| | | vo.setVisitedUserDisplay(buildVisitedUserDisplay(order.getVisitedUserName(), loadDeptName(order.getVisitedDeptId()))); |
| | | vo.setAccessAreaText(buildAccessAreaText(order.getPassAccessAreaNames())); |
| | | vo.setVisitTimeText(buildVisitTimeText(order)); |
| | | vo.setQrCodes(List.of()); |
| | | return vo; |
| | | } |
| | | return rows.get(0); |
| | | } |
| | | |
| | | public MiniMyVisitorCodeOrderVo getSharedVisitorCodeByTicketUuid(String ticketUuid) { |
| | | QrcodeTicket ticket = loadTicketByUuid(ticketUuid); |
| | | AppointmentOrder order = loadApprovedOrderById(ticket.getOrderId()); |
| | | String deptName = loadDeptName(order.getVisitedDeptId()); |
| | | |
| | | MiniMyVisitorCodeOrderVo vo = new MiniMyVisitorCodeOrderVo(); |
| | | vo.setOrderId(order.getId()); |
| | | vo.setOrderUuid(order.getUuid()); |
| | | vo.setVisitedUserDisplay(buildVisitedUserDisplay(order.getVisitedUserName(), deptName)); |
| | | vo.setAccessAreaText(buildAccessAreaText(order.getPassAccessAreaNames())); |
| | | vo.setVisitTimeText(buildVisitTimeText(order)); |
| | | vo.setValidStartTime(ticket.getGenerateTime()); |
| | | vo.setValidEndTime(ticket.getExpireTime()); |
| | | |
| | | if (!QrcodeTicketStatus.UNUSED.equals(ticket.getTicketStatus())) { |
| | | vo.setQrCodes(List.of()); |
| | | return vo; |
| | | } |
| | | |
| | | Map<Long, MpVisitor> visitorMap = |
| | | loadMpVisitorMap( |
| | | ticket.getMpVisitorId() == null |
| | | ? Set.of() |
| | | : Set.of(ticket.getMpVisitorId())); |
| | | List<AppointmentVisitor> orderVisitors = |
| | | loadOrderVisitorRows(List.of(order.getId())).getOrDefault(order.getId(), List.of()); |
| | | vo.setQrCodes(List.of(toMyVisitorCodeTicketVo(ticket, orderVisitors, visitorMap))); |
| | | return vo; |
| | | } |
| | | |
| | | private List<MiniMyVisitorCodeOrderVo> buildVisitorCodeOrders( |
| | | List<AppointmentOrder> orders, boolean futureOnly) { |
| | | if (orders.isEmpty()) { |
| | | return List.of(); |
| | | } |
| | | |
| | | LocalDateTime now = LocalDateTime.now(); |
| | | List<AppointmentOrder> eligibleOrders = |
| | | orders.stream() |
| | | .filter(order -> resolveVisitStartAt(order).isAfter(now)) |
| | | .toList(); |
| | | List<AppointmentOrder> eligibleOrders = orders; |
| | | if (futureOnly) { |
| | | LocalDateTime now = LocalDateTime.now(); |
| | | eligibleOrders = |
| | | orders.stream() |
| | | .filter(order -> resolveVisitStartAt(order).isAfter(now)) |
| | | .toList(); |
| | | } |
| | | if (eligibleOrders.isEmpty()) { |
| | | return List.of(); |
| | | } |
| | |
| | | return result; |
| | | } |
| | | |
| | | private AppointmentOrder loadApprovedOrderByUuid(String uuid) { |
| | | String normalizedUuid = trimToNull(uuid); |
| | | if (!StringUtils.hasText(normalizedUuid)) { |
| | | throw new BizException(BizErrorCode.ORDER_NOT_FOUND, "预约单不存在"); |
| | | } |
| | | AppointmentOrder order = |
| | | appointmentOrderMapper.selectOne( |
| | | new LambdaQueryWrapper<AppointmentOrder>() |
| | | .eq(AppointmentOrder::getDelFlag, 0) |
| | | .eq(AppointmentOrder::getUuid, normalizedUuid) |
| | | .eq(AppointmentOrder::getStatus, AppointmentOrderStatus.APPROVED) |
| | | .last("limit 1")); |
| | | if (order == null) { |
| | | throw new BizException(BizErrorCode.ORDER_NOT_FOUND, "预约单不存在"); |
| | | } |
| | | return order; |
| | | } |
| | | |
| | | private AppointmentOrder loadApprovedOrderById(Long orderId) { |
| | | if (orderId == null || orderId <= 0) { |
| | | throw new BizException(BizErrorCode.ORDER_NOT_FOUND, "预约单不存在"); |
| | | } |
| | | AppointmentOrder order = |
| | | appointmentOrderMapper.selectOne( |
| | | new LambdaQueryWrapper<AppointmentOrder>() |
| | | .eq(AppointmentOrder::getDelFlag, 0) |
| | | .eq(AppointmentOrder::getId, orderId) |
| | | .eq(AppointmentOrder::getStatus, AppointmentOrderStatus.APPROVED) |
| | | .last("limit 1")); |
| | | if (order == null) { |
| | | throw new BizException(BizErrorCode.ORDER_NOT_FOUND, "预约单不存在"); |
| | | } |
| | | return order; |
| | | } |
| | | |
| | | private QrcodeTicket loadTicketByUuid(String ticketUuid) { |
| | | String normalizedTicketUuid = trimToNull(ticketUuid); |
| | | if (!StringUtils.hasText(normalizedTicketUuid)) { |
| | | throw new BizException(BizErrorCode.ORDER_NOT_FOUND, "访客码不存在"); |
| | | } |
| | | QrcodeTicket ticket = |
| | | qrcodeTicketMapper.selectOne( |
| | | new LambdaQueryWrapper<QrcodeTicket>() |
| | | .eq(QrcodeTicket::getDelFlag, 0) |
| | | .eq(QrcodeTicket::getUuid, normalizedTicketUuid) |
| | | .last("limit 1")); |
| | | if (ticket == null) { |
| | | throw new BizException(BizErrorCode.ORDER_NOT_FOUND, "访客码不存在"); |
| | | } |
| | | return ticket; |
| | | } |
| | | |
| | | public MiniMyAppointmentDetailVo detailMyOrder(Long orderId, String uuid) { |
| | | if (orderId == null || orderId <= 0) { |
| | | throw new BizException(BizErrorCode.ORDER_NOT_FOUND, "预约单不存在"); |
| | | } |
| | | MpUser current = miniAuthApplicationService.currentMpUser(); |
| | | AppointmentOrder order = appointmentOrderMapper.selectById(orderId); |
| | | if (order == null || (order.getDelFlag() != null && order.getDelFlag() == 1)) { |
| | | AppointmentOrder order = appointmentOrderMapper.selectMiniVisibleOrderById(orderId, current.getId()); |
| | | if (order == null) { |
| | | throw new BizException(BizErrorCode.ORDER_NOT_FOUND, "预约单不存在"); |
| | | } |
| | | UuidAssert.match(order, uuid); |
| | | if (!Objects.equals(order.getSubmitterId(), current.getId())) { |
| | | throw new BizException(BizErrorCode.AUTH_FORBIDDEN, "无权查看该预约详情"); |
| | | } |
| | | |
| | | String deptName = loadDeptName(order.getVisitedDeptId()); |
| | | String reasonName = loadReasonName(order.getVisitReasonCode()); |
| | | String displayStatus = resolveDisplayStatus(order); |
| | | |
| | | MiniMyAppointmentDetailVo vo = new MiniMyAppointmentDetailVo(); |
| | | vo.setOrderId(order.getId()); |
| | | vo.setOrderUuid(order.getUuid()); |
| | | vo.setOrderNo(order.getOrderNo()); |
| | | vo.setStatus(order.getStatus()); |
| | | vo.setDisplayStatus(resolveDisplayStatus(order)); |
| | | vo.setDisplayStatus(displayStatus); |
| | | vo.setStatusText(resolveOrderStatusText(order)); |
| | | vo.setCancelable(isCancelableStatus(order.getStatus())); |
| | | vo.setDeletable(isDeletableStatus(order.getStatus(), displayStatus)); |
| | | vo.setVisitedUserId(order.getVisitedUserId()); |
| | | vo.setVisitedUserName(order.getVisitedUserName()); |
| | | vo.setVisitedDeptName(deptName); |
| | |
| | | vo.setAccessAreaText(buildAccessAreaText(order.getPassAccessAreaNames())); |
| | | vo.setVisitTypeText(buildVisitTypeText(order)); |
| | | vo.setVisitReasonText(buildVisitReasonText(order, reasonName == null ? Map.of() : Map.of(trimToNull(order.getVisitReasonCode()), reasonName))); |
| | | vo.setVisitReasonCode(order.getVisitReasonCode()); |
| | | vo.setVisitReasonOther(order.getVisitReasonOther()); |
| | | vo.setVisitTimeText(buildVisitTimeText(order)); |
| | | vo.setVisitTimeMode(order.getVisitTimeMode()); |
| | | vo.setVisitTimeSlot(order.getVisitTimeSlot()); |
| | | vo.setVisitStartDate(order.getVisitStartDate()); |
| | | vo.setVisitEndDate(order.getVisitEndDate()); |
| | | vo.setPersonEntry(order.getPersonEntryFlag() == null || Boolean.TRUE.equals(order.getPersonEntryFlag())); |
| | | vo.setVehicleEntry(Boolean.TRUE.equals(order.getVehicleEntryFlag())); |
| | | vo.setCreateTime(order.getCreateTime()); |
| | | vo.setVisitors(loadOrderVisitors(order.getId())); |
| | | vo.setRebookVisitors(loadRebookVisitors(order.getId())); |
| | | vo.setRebookVehicles(loadRebookVehicles(order.getId())); |
| | | List<ApprovalFlowNodeVo> flowTree = approvalFlowViewApplicationService.treeByOrderId(order.getId()); |
| | | vo.setFlowTree(flowTree == null ? List.of() : flowTree); |
| | | return vo; |
| | |
| | | if (!StringUtils.hasText(c)) { |
| | | throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "拜访事由不能为空"); |
| | | } |
| | | String txt = trimToNull(other); |
| | | if (!StringUtils.hasText(txt)) { |
| | | throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "请输入事由说明"); |
| | | } |
| | | if (txt.length() > 15) { |
| | | throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "事由说明不能超过15个字"); |
| | | } |
| | | if (AppointmentBizConstants.VISIT_REASON_OTHER.equalsIgnoreCase(c)) { |
| | | String txt = trimToNull(other); |
| | | if (!StringUtils.hasText(txt)) { |
| | | throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "选择其他时须填写自定义内容"); |
| | | } |
| | | if (txt.length() > 255) { |
| | | throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "自定义内容不能超过255字"); |
| | | } |
| | | return; |
| | | } |
| | | Long cnt = |
| | |
| | | vo.setVisitStartDate(row.getVisitStartDate()); |
| | | vo.setVisitEndDate(row.getVisitEndDate()); |
| | | vo.setVisitReasonCode(row.getVisitReasonCode()); |
| | | vo.setVisitReasonOther(row.getVisitReasonOther()); |
| | | vo.setCreateTime(row.getCreateTime()); |
| | | return vo; |
| | | } |
| | |
| | | return StringUtils.hasText(dept) ? dept : "-"; |
| | | } |
| | | |
| | | private Map<Long, String> loadVisitorDisplayMapByOrderIds(List<Long> orderIds) { |
| | | if (orderIds == null || orderIds.isEmpty()) { |
| | | return Map.of(); |
| | | } |
| | | List<AppointmentVisitor> rows = |
| | | appointmentVisitorMapper.selectList( |
| | | new LambdaQueryWrapper<AppointmentVisitor>() |
| | | .eq(AppointmentVisitor::getDelFlag, 0) |
| | | .in(AppointmentVisitor::getOrderId, orderIds) |
| | | .orderByAsc(AppointmentVisitor::getId)); |
| | | Set<Long> visitorIds = |
| | | rows.stream() |
| | | .map(AppointmentVisitor::getMpVisitorId) |
| | | .filter(Objects::nonNull) |
| | | .collect(Collectors.toCollection(LinkedHashSet::new)); |
| | | Map<Long, String> companyMap = loadMpVisitorCompanyMap(visitorIds); |
| | | Map<Long, List<String>> grouped = new LinkedHashMap<>(); |
| | | for (AppointmentVisitor row : rows) { |
| | | if (row.getOrderId() == null) { |
| | | continue; |
| | | } |
| | | String name = trimToNull(row.getName()); |
| | | if (!StringUtils.hasText(name)) { |
| | | continue; |
| | | } |
| | | String company = companyMap.get(row.getMpVisitorId()); |
| | | String display = StringUtils.hasText(company) ? name + "(" + company + ")" : name; |
| | | grouped.computeIfAbsent(row.getOrderId(), key -> new ArrayList<>()).add(display); |
| | | } |
| | | Map<Long, String> result = new LinkedHashMap<>(); |
| | | for (Map.Entry<Long, List<String>> entry : grouped.entrySet()) { |
| | | String text = entry.getValue().stream().distinct().collect(Collectors.joining("、")); |
| | | if (StringUtils.hasText(text)) { |
| | | result.put(entry.getKey(), text); |
| | | } |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | private Map<Long, String> loadMpVisitorCompanyMap(Set<Long> visitorIds) { |
| | | if (visitorIds == null || visitorIds.isEmpty()) { |
| | | return Map.of(); |
| | | } |
| | | List<MpVisitor> rows = |
| | | mpVisitorMapper.selectList( |
| | | new LambdaQueryWrapper<MpVisitor>() |
| | | .eq(MpVisitor::getDelFlag, 0) |
| | | .in(MpVisitor::getId, visitorIds)); |
| | | Map<Long, String> result = new LinkedHashMap<>(); |
| | | for (MpVisitor row : rows) { |
| | | result.put(row.getId(), trimToNull(row.getVisitorCompany())); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | private Map<Long, String> loadPlateTextMapByOrderIds(List<Long> orderIds) { |
| | | if (orderIds == null || orderIds.isEmpty()) { |
| | | return Map.of(); |
| | | } |
| | | List<AppointmentVehicle> rows = |
| | | appointmentVehicleMapper.selectList( |
| | | new LambdaQueryWrapper<AppointmentVehicle>() |
| | | .eq(AppointmentVehicle::getDelFlag, 0) |
| | | .in(AppointmentVehicle::getOrderId, orderIds) |
| | | .orderByAsc(AppointmentVehicle::getId)); |
| | | Map<Long, List<String>> grouped = new LinkedHashMap<>(); |
| | | for (AppointmentVehicle row : rows) { |
| | | if (row.getOrderId() == null) { |
| | | continue; |
| | | } |
| | | String plateNo = trimToNull(row.getPlateNo()); |
| | | if (!StringUtils.hasText(plateNo)) { |
| | | continue; |
| | | } |
| | | grouped.computeIfAbsent(row.getOrderId(), key -> new ArrayList<>()).add(plateNo); |
| | | } |
| | | Map<Long, String> result = new LinkedHashMap<>(); |
| | | for (Map.Entry<Long, List<String>> entry : grouped.entrySet()) { |
| | | String text = entry.getValue().stream().distinct().collect(Collectors.joining("、")); |
| | | if (StringUtils.hasText(text)) { |
| | | result.put(entry.getKey(), text); |
| | | } |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | private String resolveOrderStatusText(AppointmentOrder row) { |
| | | return switch (trimToNull(row.getStatus())) { |
| | | case AppointmentOrderStatus.PENDING_APPROVAL -> "审批中"; |
| | |
| | | return DISPLAY_STATUS_INVALID; |
| | | } |
| | | |
| | | private boolean isDeletableStatus(String status, String displayStatus) { |
| | | if (AppointmentOrderStatus.CANCELLED.equals(status)) { |
| | | return true; |
| | | } |
| | | return DISPLAY_STATUS_INVALID.equals(displayStatus); |
| | | } |
| | | |
| | | private String buildVisitTimeText(AppointmentOrder row) { |
| | | if (AppointmentBizConstants.TIME_MODE_SINGLE.equals(row.getVisitTimeMode())) { |
| | | String slotLabel = switch (trimToNull(row.getVisitTimeSlot())) { |
| | | case AppointmentBizConstants.TIME_SLOT_ALL_DAY -> "全天"; |
| | | case AppointmentBizConstants.TIME_SLOT_AM -> "上午"; |
| | | case AppointmentBizConstants.TIME_SLOT_PM -> "下午"; |
| | | case AppointmentBizConstants.TIME_SLOT_ALL_DAY -> "00:00-23:59"; |
| | | case AppointmentBizConstants.TIME_SLOT_AM -> "00:00-11:59"; |
| | | case AppointmentBizConstants.TIME_SLOT_PM -> "12:00-23:59"; |
| | | default -> ""; |
| | | }; |
| | | if (row.getVisitStartDate() == null) { |
| | |
| | | } |
| | | |
| | | private String buildVisitReasonText(AppointmentOrder row, Map<String, String> reasonNameMap) { |
| | | if (AppointmentBizConstants.VISIT_REASON_OTHER.equalsIgnoreCase(trimToNull(row.getVisitReasonCode()))) { |
| | | String other = trimToNull(row.getVisitReasonOther()); |
| | | return StringUtils.hasText(other) ? "其他-" + other : "其他"; |
| | | } |
| | | String reasonName = reasonNameMap.get(trimToNull(row.getVisitReasonCode())); |
| | | return StringUtils.hasText(reasonName) ? reasonName : trimToNull(row.getVisitReasonCode()); |
| | | } |
| | |
| | | } |
| | | |
| | | private LocalDateTime resolveVisitStartAt(AppointmentOrder row) { |
| | | LocalDate date = row.getVisitStartDate() != null ? row.getVisitStartDate() : row.getVisitEndDate(); |
| | | LocalDate date = row.getVisitEndDate() != null ? row.getVisitEndDate() : row.getVisitStartDate(); |
| | | if (date == null) { |
| | | return LocalDateTime.MIN; |
| | | } |
| | | if (!AppointmentBizConstants.TIME_MODE_SINGLE.equals(row.getVisitTimeMode())) { |
| | | return LocalDateTime.of(date, LocalTime.MIN); |
| | | return LocalDateTime.of(date, LocalTime.MAX); |
| | | } |
| | | return switch (trimToNull(row.getVisitTimeSlot())) { |
| | | case AppointmentBizConstants.TIME_SLOT_PM -> LocalDateTime.of(date, LocalTime.of(12, 0)); |
| | | default -> LocalDateTime.of(date, LocalTime.MIN); |
| | | case AppointmentBizConstants.TIME_SLOT_AM -> LocalDateTime.of(date, LocalTime.of(12, 0)); |
| | | default -> LocalDateTime.of(date, LocalTime.MAX); |
| | | }; |
| | | } |
| | | |
| | |
| | | vo.setTicketId(ticket.getId()); |
| | | vo.setTicketUuid(ticket.getUuid()); |
| | | vo.setMpVisitorId(ticket.getMpVisitorId()); |
| | | vo.setPayload(ticket.getPayload()); |
| | | vo.setPayload(integrationHikvisionService.encryptQrcodePayload(ticket.getPayload())); |
| | | vo.setGenerateTime(ticket.getGenerateTime()); |
| | | vo.setExpireTime(ticket.getExpireTime()); |
| | | vo.setVisitorName(resolveVisitorName(ticket.getMpVisitorId(), orderVisitors, visitorMap)); |
| | |
| | | return result; |
| | | } |
| | | |
| | | private List<MiniMyAppointmentDetailVo.RebookVisitorItem> loadRebookVisitors(Long orderId) { |
| | | List<AppointmentVisitor> rows = |
| | | appointmentVisitorMapper.selectList( |
| | | new LambdaQueryWrapper<AppointmentVisitor>() |
| | | .eq(AppointmentVisitor::getDelFlag, 0) |
| | | .eq(AppointmentVisitor::getOrderId, orderId) |
| | | .orderByAsc(AppointmentVisitor::getId)); |
| | | if (rows.isEmpty()) { |
| | | return List.of(); |
| | | } |
| | | List<Long> visitorIds = |
| | | rows.stream() |
| | | .map(AppointmentVisitor::getMpVisitorId) |
| | | .filter(Objects::nonNull) |
| | | .toList(); |
| | | Map<Long, MpVisitor> visitorMap = loadVisitorMap(visitorIds); |
| | | List<MiniMyAppointmentDetailVo.RebookVisitorItem> result = new ArrayList<>(); |
| | | for (AppointmentVisitor row : rows) { |
| | | MpVisitor visitor = visitorMap.get(row.getMpVisitorId()); |
| | | MiniMyAppointmentDetailVo.RebookVisitorItem item = new MiniMyAppointmentDetailVo.RebookVisitorItem(); |
| | | item.setVisitorId(row.getMpVisitorId()); |
| | | item.setVisitorUuid(visitor == null ? null : visitor.getUuid()); |
| | | item.setName(firstNonBlank(row.getName(), visitor == null ? null : visitor.getVisitorName(), "-")); |
| | | item.setGender(visitor == null ? null : visitor.getGender()); |
| | | item.setCompanyName(visitor == null ? null : trimToNull(visitor.getVisitorCompany())); |
| | | item.setMobileMasked( |
| | | MobileMaskUtil.mask( |
| | | firstNonBlank( |
| | | row.getMobile(), |
| | | visitor == null ? null : visitor.getVisitorMobile(), |
| | | null))); |
| | | String idCardPlain = |
| | | StringUtils.hasText(row.getIdCardCipher()) |
| | | ? SensitiveDataUtil.decryptIdCard(row.getIdCardCipher()) |
| | | : (visitor != null && StringUtils.hasText(visitor.getIdCardCipher()) |
| | | ? SensitiveDataUtil.decryptIdCard(visitor.getIdCardCipher()) |
| | | : null); |
| | | item.setIdCardMasked( |
| | | StringUtils.hasText(idCardPlain) |
| | | ? SensitiveDataUtil.maskIdCard(idCardPlain) |
| | | : null); |
| | | result.add(item); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | private List<MiniMyAppointmentDetailVo.RebookVehicleItem> loadRebookVehicles(Long orderId) { |
| | | List<AppointmentVehicle> rows = |
| | | appointmentVehicleMapper.selectList( |
| | | new LambdaQueryWrapper<AppointmentVehicle>() |
| | | .eq(AppointmentVehicle::getDelFlag, 0) |
| | | .eq(AppointmentVehicle::getOrderId, orderId) |
| | | .orderByAsc(AppointmentVehicle::getId)); |
| | | if (rows.isEmpty()) { |
| | | return List.of(); |
| | | } |
| | | List<MiniMyAppointmentDetailVo.RebookVehicleItem> result = new ArrayList<>(); |
| | | for (AppointmentVehicle row : rows) { |
| | | MiniMyAppointmentDetailVo.RebookVehicleItem item = new MiniMyAppointmentDetailVo.RebookVehicleItem(); |
| | | item.setPlateNo(trimToNull(row.getPlateNo())); |
| | | item.setDriverVisitorId(row.getDriverVisitorId()); |
| | | item.setDriverName(trimToNull(row.getDriverName())); |
| | | result.add(item); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | private Map<Long, MpVisitor> loadVisitorMap(List<Long> visitorIds) { |
| | | if (visitorIds.isEmpty()) { |
| | | return Map.of(); |