longz
2026-05-28 aa67b3cb0fe26fab576f7710c978ff3594426cca
backend/src/main/java/com/sinata/appointment/service/AppointmentApplicationService.java
@@ -21,6 +21,7 @@
import com.sinata.appointment.entity.BizVisitReason;
import com.sinata.appointment.entity.MpUser;
import com.sinata.appointment.entity.MpVisitor;
import com.sinata.appointment.entity.MpPassAccessArea;
import com.sinata.appointment.entity.SysDept;
import com.sinata.appointment.exception.BizException;
import com.sinata.appointment.constants.BizErrorCode;
@@ -32,6 +33,7 @@
import com.sinata.appointment.mapper.BizVisitReasonMapper;
import com.sinata.appointment.mapper.MpUserMapper;
import com.sinata.appointment.mapper.MpVisitorMapper;
import com.sinata.appointment.mapper.MpPassAccessAreaMapper;
import com.sinata.appointment.mapper.SysDeptMapper;
import com.sinata.appointment.util.MobileMaskUtil;
import com.sinata.appointment.util.SensitiveDataUtil;
@@ -71,6 +73,7 @@
    private final BizVisitReasonMapper bizVisitReasonMapper;
    private final MpUserMapper mpUserMapper;
    private final MpVisitorMapper mpVisitorMapper;
    private final MpPassAccessAreaMapper mpPassAccessAreaMapper;
    private final SysDeptMapper sysDeptMapper;
    private final ObjectMapper objectMapper;
@@ -79,6 +82,7 @@
            long size,
            String visitedUserName,
            Long visitedDeptId,
            Long accessAreaId,
            String accessArea,
            String localUnit,
            LocalDate visitDateStart,
@@ -87,12 +91,14 @@
            String approvalStatus,
            String visitorKeyword,
            String visitReasonCode) {
        List<Long> accessAreaIds = resolveAccessAreaFilterIds(accessAreaId);
        Page<AppointmentOrder> orderPage = new Page<>(Math.max(1L, page), Math.max(1L, size));
        IPage<AppointmentOrder> pagedOrders =
                appointmentOrderMapper.pageAdminOrders(
                        orderPage,
                        trimToNull(visitedUserName),
                        visitedDeptId,
                        accessAreaIds,
                        trimToNull(accessArea),
                        trimToNull(localUnit),
                        visitDateStart,
@@ -107,6 +113,7 @@
    public byte[] exportExcel(
            String visitedUserName,
            Long visitedDeptId,
            Long accessAreaId,
            String accessArea,
            String localUnit,
            LocalDate visitDateStart,
@@ -115,6 +122,7 @@
            String approvalStatus,
            String visitorKeyword,
            String visitReasonCode) {
        List<Long> accessAreaIds = resolveAccessAreaFilterIds(accessAreaId);
        long pageNo = 1L;
        long pageSize = 200L;
        List<AppointmentAdminExportRow> rows = new ArrayList<>();
@@ -125,6 +133,7 @@
                            orderPage,
                            trimToNull(visitedUserName),
                            visitedDeptId,
                            accessAreaIds,
                            trimToNull(accessArea),
                            trimToNull(localUnit),
                            visitDateStart,
@@ -174,6 +183,7 @@
        Map<Long, MpVisitor> visitorMap = loadVisitorMap(visitorRows);
        Map<Long, String> plateMap = loadVisitorPlateMap(id);
        ApprovalInstance approvalInstance = loadLatestInstance(id);
        MpUser submitter = loadSubmitter(order.getSubmitterId());
        AppointmentAdminDetailVo vo = new AppointmentAdminDetailVo();
        vo.setId(order.getId());
@@ -186,6 +196,8 @@
        vo.setLocalUnitText(defaultText(buildJsonNameText(order.getPassLocalUnitNames())));
        vo.setPlateNoText(defaultText(loadOrderPlateText(id)));
        vo.setVisitReasonText(defaultText(buildVisitReasonText(order, reasonNameMap)));
        vo.setVisitTimeMode(trimToNull(order.getVisitTimeMode()));
        vo.setVisitTimeSlot(trimToNull(order.getVisitTimeSlot()));
        vo.setVisitStartText(defaultText(resolveVisitStartText(order)));
        vo.setVisitEndText(defaultText(resolveVisitEndText(order)));
        String displayStatusCode = resolveDisplayStatus(order);
@@ -194,6 +206,9 @@
        String approvalStatusCode = resolveApprovalStatusCode(order, approvalInstance);
        vo.setApprovalStatusCode(approvalStatusCode);
        vo.setApprovalStatusText(resolveApprovalStatusText(approvalStatusCode));
        vo.setSubmitterName(defaultText(resolveSubmitterName(submitter)));
        vo.setSubmitterMobile(defaultText(trimToNull(submitter == null ? null : submitter.getMobile())));
        vo.setSubmitTime(order.getCreateTime() == null ? "-" : order.getCreateTime().format(DATE_TIME_FORMATTER));
        vo.setVisitors(buildDetailVisitors(visitorRows, visitorMap, plateMap));
        return vo;
    }
@@ -216,6 +231,8 @@
            return page;
        }
        AdminPageData pageData = loadAdminPageData(orders);
        List<Long> orderIds = orders.stream().map(AppointmentOrder::getId).filter(Objects::nonNull).toList();
        Map<Long, String> orderPlateTextMap = loadOrderPlateTextMap(orderIds);
        List<AppointmentAdminListVo> records = new ArrayList<>();
        for (AppointmentOrder order : orders) {
            records.add(
@@ -224,7 +241,8 @@
                            pageData.deptNameMap().get(order.getVisitedDeptId()),
                            pageData.reasonNameMap(),
                            pageData.visitorRowsMap().get(order.getId()),
                            pageData.approvalInstanceMap().get(order.getId())));
                            pageData.approvalInstanceMap().get(order.getId()),
                            orderPlateTextMap.get(order.getId())));
        }
        page.setRecords(records);
        return page;
@@ -257,6 +275,19 @@
                                .eq(MpVisitor::getDelFlag, 0)
                                .in(MpVisitor::getId, visitorIds));
        return visitors.stream().collect(Collectors.toMap(MpVisitor::getId, v -> v, (a, b) -> a, LinkedHashMap::new));
    }
    private MpUser loadSubmitter(Long submitterId) {
        if (submitterId == null) {
            return null;
        }
        List<MpUser> rows =
                mpUserMapper.selectList(
                        new LambdaQueryWrapper<MpUser>()
                                .eq(MpUser::getDelFlag, 0)
                                .eq(MpUser::getId, submitterId)
                                .last("limit 1"));
        return rows.isEmpty() ? null : rows.get(0);
    }
    private Map<Long, String> loadVisitorPlateMap(Long orderId) {
@@ -309,6 +340,34 @@
                .map(String::trim)
                .distinct()
                .collect(Collectors.joining("、"));
    }
    private Map<Long, String> loadOrderPlateTextMap(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));
        if (rows == null || rows.isEmpty()) {
            return Map.of();
        }
        Map<Long, LinkedHashSet<String>> grouped = new LinkedHashMap<>();
        for (AppointmentVehicle row : rows) {
            if (row.getOrderId() == null || !StringUtils.hasText(row.getPlateNo())) {
                continue;
            }
            grouped.computeIfAbsent(row.getOrderId(), key -> new LinkedHashSet<>());
            grouped.get(row.getOrderId()).add(row.getPlateNo().trim());
        }
        Map<Long, String> result = new LinkedHashMap<>();
        for (Map.Entry<Long, LinkedHashSet<String>> entry : grouped.entrySet()) {
            result.put(entry.getKey(), String.join("、", entry.getValue()));
        }
        return result;
    }
    private Map<Long, List<AppointmentVisitor>> loadVisitorRows(List<Long> orderIds) {
@@ -399,7 +458,8 @@
            String deptName,
            Map<String, String> reasonNameMap,
            List<AppointmentVisitor> visitorRows,
            ApprovalInstance approvalInstance) {
            ApprovalInstance approvalInstance,
            String orderPlateText) {
        AppointmentAdminListVo vo = new AppointmentAdminListVo();
        vo.setId(order.getId());
        vo.setUuid(order.getUuid());
@@ -409,7 +469,7 @@
        vo.setVisitedDeptName(defaultText(trimToNull(deptName)));
        vo.setAccessAreaText(defaultText(buildJsonNameText(order.getPassAccessAreaNames())));
        vo.setLocalUnitText(defaultText(buildJsonNameText(order.getPassLocalUnitNames())));
        vo.setPlateNoText(defaultText(joinUniqueTexts(visitorRows, AppointmentVisitor::getPlateNo)));
        vo.setPlateNoText(defaultText(firstNonBlank(orderPlateText, joinUniqueTexts(visitorRows, AppointmentVisitor::getPlateNo), null)));
        vo.setVisitReasonText(defaultText(buildVisitReasonText(order, reasonNameMap)));
        vo.setVisitTimeText(defaultText(buildVisitTimeText(order)));
        vo.setVisitorNamesText(defaultText(joinUniqueTexts(visitorRows, AppointmentVisitor::getName)));
@@ -446,25 +506,25 @@
        List<AppointmentAdminExportRow> result = new ArrayList<>();
        for (AppointmentOrder order : orders) {
            List<AppointmentVisitor> visitors = visitorRowsMap.get(order.getId());
            AppointmentAdminListVo summary =
                    toAdminListVo(
                            order,
                            null,
                            reasonNameMap,
                            visitorRowsMap.get(order.getId()),
                            approvalInstanceMap.get(order.getId()));
                            visitors,
                            approvalInstanceMap.get(order.getId()),
                            loadOrderPlateText(order.getId()));
            Map<String, String> nodeApproverNames =
                    approvalNameMap.getOrDefault(order.getId(), Map.of());
            MpUser submitter = submitterMap.get(order.getSubmitterId());
            List<AppointmentVisitor> visitors = visitorRowsMap.get(order.getId());
            Map<Long, String> orderPlateMap = visitorPlateMap.getOrDefault(order.getId(), Map.of());
            if (visitors == null || visitors.isEmpty()) {
                result.add(buildExportRow(summary, order, null, null, Map.of(), nodeApproverNames, submitter));
                result.add(buildExportRow(summary, order, null, visitorMap, orderPlateMap, nodeApproverNames, submitter));
                continue;
            }
            Map<Long, String> orderPlateMap = visitorPlateMap.getOrDefault(order.getId(), Map.of());
            for (AppointmentVisitor visitorRow : visitors) {
                MpVisitor visitor = visitorMap.get(visitorRow.getMpVisitorId());
                result.add(buildExportRow(summary, order, visitorRow, visitor, orderPlateMap, nodeApproverNames, submitter));
                result.add(buildExportRow(summary, order, visitorRow, visitorMap, orderPlateMap, nodeApproverNames, submitter));
            }
        }
        return result;
@@ -474,7 +534,7 @@
            AppointmentAdminListVo summary,
            AppointmentOrder order,
            AppointmentVisitor visitorRow,
            MpVisitor visitor,
            Map<Long, MpVisitor> visitorMap,
            Map<Long, String> orderPlateMap,
            Map<String, String> nodeApproverNames,
            MpUser submitter) {
@@ -483,31 +543,35 @@
        row.setVisitedUserName(summary.getVisitedUserName());
        row.setAccessAreaText(summary.getAccessAreaText());
        row.setLocalUnitText(summary.getLocalUnitText());
        row.setPlateNoText(
                defaultText(
                        firstNonBlank(
                                visitorRow == null ? null : visitorRow.getPlateNo(),
                                visitorRow == null ? null : orderPlateMap.get(visitorRow.getMpVisitorId()),
                                summary.getPlateNoText())));
        row.setPlateNoText(defaultText(summary.getPlateNoText()));
        row.setVisitReasonText(summary.getVisitReasonText());
        row.setVisitTimeText(summary.getVisitTimeText());
        row.setDisplayStatusText(summary.getDisplayStatusText());
        row.setVisitorLabel(defaultText(visitorRow == null ? null : trimToNull(visitorRow.getName())));
        row.setVisitorName(
                defaultText(
        MpVisitor visitor = visitorRow == null ? null : visitorMap.get(visitorRow.getMpVisitorId());
        String visitorName =
                trimToNull(
                        firstNonBlank(
                                visitorRow == null ? null : visitorRow.getName(),
                                visitor == null ? null : visitor.getVisitorName(),
                                null)));
        row.setIdCardText(defaultText(resolveIdCardMasked(visitorRow, visitor)));
                                null));
        row.setVisitorLabel(defaultText(visitorName));
        row.setVisitorName(defaultText(visitorName));
        row.setIdCardText(defaultText(trimToNull(resolveIdCardMasked(visitorRow, visitor))));
        row.setMobileText(
                defaultText(
                        MobileMaskUtil.mask(
                                firstNonBlank(
                                        visitorRow == null ? null : visitorRow.getMobile(),
                                        visitor == null ? null : visitor.getVisitorMobile(),
                                        null))));
        row.setCompanyName(defaultText(visitor == null ? null : trimToNull(visitor.getVisitorCompany())));
                        trimToNull(
                                MobileMaskUtil.mask(
                                        firstNonBlank(
                                                visitorRow == null ? null : visitorRow.getMobile(),
                                                visitor == null ? null : visitor.getVisitorMobile(),
                                                null)))));
        row.setCompanyName(defaultText(trimToNull(visitor == null ? null : visitor.getVisitorCompany())));
        if (visitorRow != null && visitorRow.getMpVisitorId() != null) {
            String visitorPlateText = trimToNull(orderPlateMap.get(visitorRow.getMpVisitorId()));
            if (StringUtils.hasText(visitorPlateText)) {
                row.setPlateNoText(visitorPlateText);
            }
        }
        row.setHandlerApproverNames(defaultText(nodeApproverNames.get(ApprovalNodeCode.LEVEL1_HANDLER)));
        row.setDeptLeaderApproverNames(defaultText(nodeApproverNames.get(ApprovalNodeCode.LEVEL2_DEPT_LEADER)));
        row.setVisitDeptApproverNames(defaultText(nodeApproverNames.get(ApprovalNodeCode.LEVEL4_VISIT_DEPT)));
@@ -724,7 +788,7 @@
        }
        if ("OTHER".equalsIgnoreCase(code)) {
            String other = trimToNull(row.getVisitReasonOther());
            return StringUtils.hasText(other) ? "其他-" + other : "其他";
            return StringUtils.hasText(other) ? other : "其他";
        }
        String reasonName = reasonNameMap.get(code);
        return StringUtils.hasText(reasonName) ? reasonName : code;
@@ -861,8 +925,50 @@
        return StringUtils.hasText(trimmed) ? trimmed : null;
    }
    private List<Long> resolveAccessAreaFilterIds(Long accessAreaId) {
        if (accessAreaId == null) {
            return List.of();
        }
        List<MpPassAccessArea> allRows =
                mpPassAccessAreaMapper.selectList(
                        new LambdaQueryWrapper<MpPassAccessArea>()
                                .eq(MpPassAccessArea::getDelFlag, 0));
        if (allRows == null || allRows.isEmpty()) {
            return List.of(accessAreaId);
        }
        Map<Long, List<Long>> childrenByPid = new LinkedHashMap<>();
        for (MpPassAccessArea row : allRows) {
            if (row.getId() == null) {
                continue;
            }
            Long pid = row.getPid() == null ? 0L : row.getPid();
            childrenByPid.computeIfAbsent(pid, key -> new ArrayList<>()).add(row.getId());
        }
        LinkedHashSet<Long> idSet = new LinkedHashSet<>();
        ArrayList<Long> queue = new ArrayList<>();
        queue.add(accessAreaId);
        for (int i = 0; i < queue.size(); i++) {
            Long current = queue.get(i);
            if (current == null || !idSet.add(current)) {
                continue;
            }
            List<Long> children = childrenByPid.get(current);
            if (children != null && !children.isEmpty()) {
                queue.addAll(children);
            }
        }
        return idSet.isEmpty() ? List.of(accessAreaId) : new ArrayList<>(idSet);
    }
    private static String defaultText(String value) {
        return StringUtils.hasText(value) ? value : "-";
    }
    private String resolveSubmitterName(MpUser submitter) {
        if (submitter == null) {
            return null;
        }
        return firstNonBlank(submitter.getNickName(), submitter.getMobile());
    }
    @SafeVarargs
@@ -883,4 +989,11 @@
            Map<Long, ApprovalInstance> approvalInstanceMap,
            Map<Long, String> deptNameMap,
            Map<String, String> reasonNameMap) {}
    private enum VisitorFieldType {
        NAME,
        ID_CARD,
        MOBILE,
        COMPANY
    }
}