longz
2026-06-02 937f99a139bedbacdf15e25cfd55aa592f56082c
backend/src/main/java/com/sinata/appointment/service/IntegrationWechatService.java
@@ -19,6 +19,7 @@
import java.util.Map;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
@@ -47,109 +48,164 @@
    private final ApprovalTaskMapper approvalTaskMapper;
    private final BizVisitReasonMapper bizVisitReasonMapper;
    @Async
    public void notifyApprovalFinalResult(AppointmentOrder order, boolean approved) {
        if (order == null || order.getSubmitterId() == null) {
            return;
        }
        MpUser submitter =
                mpUserMapper.selectOne(
                        new LambdaQueryWrapper<MpUser>()
                                .eq(MpUser::getDelFlag, 0)
                                .eq(MpUser::getId, order.getSubmitterId())
                                .last("limit 1"));
        if (submitter == null || !StringUtils.hasText(submitter.getOpenId())) {
            log.info(
                    "Skip mini subscribe notify, submitter not found or openId empty. submitterId={} orderNo={}",
                    order.getSubmitterId(),
                    order.getOrderNo());
            return;
        }
        Map<String, String> templateData = new LinkedHashMap<>();
        templateData.put("thing1", approved ? "审核通过" : "审核未通过");
        templateData.put("thing2", abbreviate(resolveSubmitterName(submitter), 20));
        templateData.put("time3", buildVisitTemplateTimeValue(order));
        templateData.put("thing4", abbreviate(buildVisitReasonText(order), 20));
        wechatMiniGateway.sendSubscribeMessage(
                submitter.getOpenId(), APPROVAL_RESULT_TEMPLATE_ID, APPROVAL_RESULT_PAGE, templateData);
        log.info(
                "Mini subscribe notify sent submitterId={} orderNo={} result={}",
                order.getSubmitterId(),
                order.getOrderNo(),
                approved ? AppointmentOrderStatus.APPROVED : AppointmentOrderStatus.REJECTED);
    }
    public void notifyApprovalNoticeUsers(
            AppointmentOrder order, boolean approved, java.util.Collection<MpUser> noticeUsers, int visitorCount) {
        if (order == null || noticeUsers == null || noticeUsers.isEmpty()) {
            return;
        }
        Map<String, String> templateData = new LinkedHashMap<>();
        templateData.put("thing6", buildVisitorCountText(visitorCount));
        templateData.put("time18", buildVisitTemplateTimeValue(order));
        templateData.put("thing20", abbreviate(buildNoticeBusinessTypeText(order, approved), 20));
        for (MpUser noticeUser : noticeUsers) {
            if (noticeUser == null || !StringUtils.hasText(noticeUser.getOpenId())) {
                continue;
        try {
            if (order == null || order.getSubmitterId() == null) {
                log.info("Mini subscribe final result skipped, order or submitter empty. orderId={}",
                        order == null ? null : order.getId());
                return;
            }
            wechatMiniGateway.sendSubscribeMessage(
                    noticeUser.getOpenId(), NOTICE_RESULT_TEMPLATE_ID, APPROVAL_RESULT_PAGE, templateData);
            log.info(
                    "Mini subscribe notice sent noticeUserId={} orderNo={} result={}",
                    noticeUser.getId(),
                    order.getOrderNo(),
                    approved ? AppointmentOrderStatus.APPROVED : AppointmentOrderStatus.REJECTED);
        }
    }
    public void notifyCurrentApprovers(AppointmentOrder order, Long instanceId) {
        if (order == null || instanceId == null) {
            return;
        }
        java.util.List<ApprovalTask> pendingTasks =
                approvalTaskMapper.selectList(
                        new LambdaQueryWrapper<ApprovalTask>()
                                .eq(ApprovalTask::getDelFlag, 0)
                                .eq(ApprovalTask::getInstanceId, instanceId)
                                .eq(ApprovalTask::getTaskStatus, ApprovalTaskStatus.PENDING)
                                .orderByAsc(ApprovalTask::getId));
        if (pendingTasks.isEmpty()) {
            return;
        }
        java.util.LinkedHashMap<Long, java.util.LinkedHashSet<String>> userNodeNames = new java.util.LinkedHashMap<>();
        for (ApprovalTask task : pendingTasks) {
            if (task.getAssigneeUserId() == null) {
                continue;
            }
            userNodeNames.computeIfAbsent(task.getAssigneeUserId(), key -> new java.util.LinkedHashSet<>());
            userNodeNames.get(task.getAssigneeUserId()).add(resolveNodeName(task.getNodeCode()));
        }
        if (userNodeNames.isEmpty()) {
            return;
        }
        java.util.List<MpUser> users =
                mpUserMapper.selectList(
                        new LambdaQueryWrapper<MpUser>()
                                .eq(MpUser::getDelFlag, 0)
                                .in(MpUser::getId, userNodeNames.keySet()));
        java.util.Map<Long, MpUser> userMap = new java.util.LinkedHashMap<>();
        for (MpUser user : users) {
            userMap.putIfAbsent(user.getId(), user);
        }
        for (java.util.Map.Entry<Long, java.util.LinkedHashSet<String>> entry : userNodeNames.entrySet()) {
            MpUser user = userMap.get(entry.getKey());
            if (user == null || !StringUtils.hasText(user.getOpenId())) {
                continue;
            MpUser submitter =
                    mpUserMapper.selectOne(
                            new LambdaQueryWrapper<MpUser>()
                                    .eq(MpUser::getDelFlag, 0)
                                    .eq(MpUser::getId, order.getSubmitterId())
                                    .last("limit 1"));
            if (submitter == null || !StringUtils.hasText(submitter.getOpenId())) {
                log.info(
                        "Mini subscribe final result skipped, submitter not found or openId empty. submitterId={} orderNo={}",
                        order.getSubmitterId(),
                        order.getOrderNo());
                return;
            }
            Map<String, String> templateData = new LinkedHashMap<>();
            templateData.put("thing1", abbreviate(buildTodoTaskName(order), 20));
            templateData.put("thing3", abbreviate(String.join("、", entry.getValue()), 20));
            templateData.put("thing1", approved ? "审核通过" : "审核未通过");
            templateData.put("thing2", abbreviate(resolveSubmitterName(submitter), 20));
            templateData.put("time3", buildVisitTemplateTimeValue(order));
            templateData.put("thing4", abbreviate(buildVisitReasonText(order), 20));
            wechatMiniGateway.sendSubscribeMessage(
                    user.getOpenId(), APPROVAL_TODO_TEMPLATE_ID, APPROVAL_TODO_PAGE, templateData);
                    submitter.getOpenId(), APPROVAL_RESULT_TEMPLATE_ID, APPROVAL_RESULT_PAGE, templateData);
            log.info(
                    "Mini subscribe todo notify sent approverId={} orderNo={} stages={}",
                    user.getId(),
                    "Mini subscribe final result success. submitterId={} orderNo={} result={}",
                    order.getSubmitterId(),
                    order.getOrderNo(),
                    entry.getValue());
                    approved ? AppointmentOrderStatus.APPROVED : AppointmentOrderStatus.REJECTED);
        } catch (Exception ex) {
            log.warn("Mini subscribe final result failed. orderId={} orderNo={}",
                    order == null ? null : order.getId(), order == null ? null : order.getOrderNo(), ex);
        }
    }
    @Async
    public void notifyApprovalNoticeUsers(
            AppointmentOrder order, boolean approved, java.util.Collection<MpUser> noticeUsers, int visitorCount) {
        try {
            if (order == null || noticeUsers == null || noticeUsers.isEmpty()) {
                log.info("Mini subscribe notice skipped, order or notice users empty. orderId={}",
                        order == null ? null : order.getId());
                return;
            }
            Map<String, String> templateData = new LinkedHashMap<>();
            templateData.put("thing6", buildVisitorCountText(visitorCount));
            templateData.put("time18", buildVisitTemplateTimeValue(order));
            templateData.put("thing20", abbreviate(buildNoticeBusinessTypeText(order, approved), 20));
            int successCount = 0;
            int skippedCount = 0;
            int failedCount = 0;
            for (MpUser noticeUser : noticeUsers) {
                if (noticeUser == null || !StringUtils.hasText(noticeUser.getOpenId())) {
                    skippedCount++;
                    continue;
                }
                try {
                    wechatMiniGateway.sendSubscribeMessage(
                            noticeUser.getOpenId(), NOTICE_RESULT_TEMPLATE_ID, APPROVAL_RESULT_PAGE, templateData);
                    successCount++;
                    log.info(
                            "Mini subscribe notice success. noticeUserId={} orderNo={} result={}",
                            noticeUser.getId(),
                            order.getOrderNo(),
                            approved ? AppointmentOrderStatus.APPROVED : AppointmentOrderStatus.REJECTED);
                } catch (Exception ex) {
                    failedCount++;
                    log.warn("Mini subscribe notice failed. noticeUserId={} orderId={} orderNo={}",
                            noticeUser.getId(), order.getId(), order.getOrderNo(), ex);
                }
            }
            log.info("Mini subscribe notice completed. orderId={} orderNo={} success={} skipped={} failed={}",
                    order.getId(), order.getOrderNo(), successCount, skippedCount, failedCount);
        } catch (Exception ex) {
            log.warn("Mini subscribe notice batch failed. orderId={} orderNo={}",
                    order == null ? null : order.getId(), order == null ? null : order.getOrderNo(), ex);
        }
    }
    @Async
    public void notifyCurrentApprovers(AppointmentOrder order, Long instanceId) {
        try {
            if (order == null || instanceId == null) {
                log.info("Mini subscribe todo skipped, order or instance empty. orderId={} instanceId={}",
                        order == null ? null : order.getId(), instanceId);
                return;
            }
            java.util.List<ApprovalTask> pendingTasks =
                    approvalTaskMapper.selectList(
                            new LambdaQueryWrapper<ApprovalTask>()
                                    .eq(ApprovalTask::getDelFlag, 0)
                                    .eq(ApprovalTask::getInstanceId, instanceId)
                                    .eq(ApprovalTask::getTaskStatus, ApprovalTaskStatus.PENDING)
                                    .orderByAsc(ApprovalTask::getId));
            if (pendingTasks.isEmpty()) {
                log.info("Mini subscribe todo skipped, no pending tasks. orderId={} instanceId={}",
                        order.getId(), instanceId);
                return;
            }
            java.util.LinkedHashMap<Long, java.util.LinkedHashSet<String>> userNodeNames =
                    new java.util.LinkedHashMap<>();
            for (ApprovalTask task : pendingTasks) {
                if (task.getAssigneeUserId() == null) {
                    continue;
                }
                userNodeNames.computeIfAbsent(task.getAssigneeUserId(), key -> new java.util.LinkedHashSet<>());
                userNodeNames.get(task.getAssigneeUserId()).add(resolveNodeName(task.getNodeCode()));
            }
            if (userNodeNames.isEmpty()) {
                log.info("Mini subscribe todo skipped, no assignee users. orderId={} instanceId={}",
                        order.getId(), instanceId);
                return;
            }
            java.util.List<MpUser> users =
                    mpUserMapper.selectList(
                            new LambdaQueryWrapper<MpUser>()
                                    .eq(MpUser::getDelFlag, 0)
                                    .in(MpUser::getId, userNodeNames.keySet()));
            java.util.Map<Long, MpUser> userMap = new java.util.LinkedHashMap<>();
            for (MpUser user : users) {
                userMap.putIfAbsent(user.getId(), user);
            }
            int successCount = 0;
            int skippedCount = 0;
            int failedCount = 0;
            for (java.util.Map.Entry<Long, java.util.LinkedHashSet<String>> entry : userNodeNames.entrySet()) {
                MpUser user = userMap.get(entry.getKey());
                if (user == null || !StringUtils.hasText(user.getOpenId())) {
                    skippedCount++;
                    continue;
                }
                Map<String, String> templateData = new LinkedHashMap<>();
                templateData.put("thing1", abbreviate(buildTodoTaskName(order), 20));
                templateData.put("thing3", abbreviate(String.join("、", entry.getValue()), 20));
                try {
                    wechatMiniGateway.sendSubscribeMessage(
                            user.getOpenId(), APPROVAL_TODO_TEMPLATE_ID, APPROVAL_TODO_PAGE, templateData);
                    successCount++;
                    log.info(
                            "Mini subscribe todo success. approverId={} orderNo={} stages={}",
                            user.getId(),
                            order.getOrderNo(),
                            entry.getValue());
                } catch (Exception ex) {
                    failedCount++;
                    log.warn("Mini subscribe todo failed. approverId={} orderId={} orderNo={} stages={}",
                            user.getId(), order.getId(), order.getOrderNo(), entry.getValue(), ex);
                }
            }
            log.info("Mini subscribe todo completed. orderId={} orderNo={} success={} skipped={} failed={}",
                    order.getId(), order.getOrderNo(), successCount, skippedCount, failedCount);
        } catch (Exception ex) {
            log.warn("Mini subscribe todo batch failed. orderId={} instanceId={}",
                    order == null ? null : order.getId(), instanceId, ex);
        }
    }
@@ -206,8 +262,7 @@
            return "拜访";
        }
        if (AppointmentBizConstants.VISIT_REASON_OTHER.equalsIgnoreCase(reasonCode)) {
            String other = safeTrim(order.getVisitReasonOther());
            return StringUtils.hasText(other) ? "其他:" + other : "其他";
            return "其他";
        }
        BizVisitReason reason =
                bizVisitReasonMapper.selectOne(