longz
2026-04-21 c4db0a4526f61758272c92396aa788d84f098102
backend/src/main/java/com/sinata/appointment/service/MiniAppointmentApplicationService.java
@@ -15,6 +15,7 @@
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;
@@ -67,6 +68,8 @@
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
@@ -96,6 +99,7 @@
    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) {
@@ -179,11 +183,11 @@
        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();
@@ -222,190 +226,94 @@
    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;
            records.add(toMyOrderListVo(order, deptNameMap, reasonNameMap));
            }
            if (StringUtils.hasText(normalizedKeyword)
                    && !containsIgnoreCase(vo.getVisitedUserDisplay(), normalizedKeyword)
                    && !containsIgnoreCase(vo.getVisitReasonText(), normalizedKeyword)) {
                continue;
            }
            rows.add(vo);
        }
        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() {
@@ -809,6 +717,25 @@
        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()
@@ -852,6 +779,26 @@
                                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);