From 937f99a139bedbacdf15e25cfd55aa592f56082c Mon Sep 17 00:00:00 2001
From: longz <longzhaoz@qq.com>
Date: 星期二, 02 六月 2026 15:01:59 +0800
Subject: [PATCH] feat(appointment): 添加访客预约系统敏感词库功能

---
 backend/src/main/java/com/sinata/appointment/service/IntegrationWechatService.java |  251 ++++++++++++++++++++++++++++++-------------------
 1 files changed, 153 insertions(+), 98 deletions(-)

diff --git a/backend/src/main/java/com/sinata/appointment/service/IntegrationWechatService.java b/backend/src/main/java/com/sinata/appointment/service/IntegrationWechatService.java
index 09fad61..778babf 100644
--- a/backend/src/main/java/com/sinata/appointment/service/IntegrationWechatService.java
+++ b/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(

--
Gitblit v1.7.1