From 93414e8ee25852aca467213402585d0e65c08a4a Mon Sep 17 00:00:00 2001
From: wenminjie <1036699586@qq.com>
Date: 星期二, 04 八月 2026 16:15:20 +0800
Subject: [PATCH] 二期后端

---
 talent-card-server/src/main/java/com/talentcard/server/service/ServiceAppointmentAdminService.java |   79 ++++++++++++++++++++++++++++++++++++---
 1 files changed, 72 insertions(+), 7 deletions(-)

diff --git a/talent-card-server/src/main/java/com/talentcard/server/service/ServiceAppointmentAdminService.java b/talent-card-server/src/main/java/com/talentcard/server/service/ServiceAppointmentAdminService.java
index f3388b8..d7d7b04 100644
--- a/talent-card-server/src/main/java/com/talentcard/server/service/ServiceAppointmentAdminService.java
+++ b/talent-card-server/src/main/java/com/talentcard/server/service/ServiceAppointmentAdminService.java
@@ -20,8 +20,10 @@
 import com.talentcard.server.common.SensitiveDataCrypto;
 import com.talentcard.server.entity.ChildInformation;
 import com.talentcard.server.entity.ServiceApplication;
+import com.talentcard.server.entity.ServiceApplicationOperationLog;
 import com.talentcard.server.mapper.ChildInformationMapper;
 import com.talentcard.server.mapper.ServiceApplicationMapper;
+import com.talentcard.server.mapper.ServiceApplicationOperationLogMapper;
 import org.apache.poi.ss.usermodel.CellStyle;
 import org.apache.poi.ss.usermodel.FillPatternType;
 import org.apache.poi.ss.usermodel.IndexedColors;
@@ -39,27 +41,31 @@
 
     private final ServiceApplicationMapper applicationMapper;
     private final ChildInformationMapper childInformationMapper;
+    private final ServiceApplicationOperationLogMapper operationLogMapper;
     private final SensitiveDataCrypto sensitiveDataCrypto;
 
     public ServiceAppointmentAdminService(
             ServiceApplicationMapper applicationMapper,
             ChildInformationMapper childInformationMapper,
+            ServiceApplicationOperationLogMapper operationLogMapper,
             SensitiveDataCrypto sensitiveDataCrypto
     ) {
         this.applicationMapper = applicationMapper;
         this.childInformationMapper = childInformationMapper;
+        this.operationLogMapper = operationLogMapper;
         this.sensitiveDataCrypto = sensitiveDataCrypto;
     }
 
     @Transactional(readOnly = true)
-    public PageResult<Map<String, Object>> page(String applicationType, String keyword, String serviceKeyword,
+    public PageResult<Map<String, Object>> page(String applicationType, String keyword, String applicantName,
+                                                String applicantMobile, String serviceKeyword,
                                                 String cardLevel, String status, String submittedStart,
                                                 String submittedEnd, int page, int size) {
         int safePage = Math.max(page, 1);
         int safeSize = Math.min(Math.max(size, 1), 100);
-        QueryWrapper<ServiceApplication> countWrapper = filter(applicationType, keyword, serviceKeyword, cardLevel, status, submittedStart, submittedEnd);
+        QueryWrapper<ServiceApplication> countWrapper = filter(applicationType, keyword, applicantName, applicantMobile, serviceKeyword, cardLevel, status, submittedStart, submittedEnd);
         Long total = applicationMapper.selectCount(countWrapper);
-        QueryWrapper<ServiceApplication> pageWrapper = filter(applicationType, keyword, serviceKeyword, cardLevel, status, submittedStart, submittedEnd)
+        QueryWrapper<ServiceApplication> pageWrapper = filter(applicationType, keyword, applicantName, applicantMobile, serviceKeyword, cardLevel, status, submittedStart, submittedEnd)
                 .orderByDesc("submitted_at", "id")
                 .last("limit " + safeSize + " offset " + ((safePage - 1) * safeSize));
         List<Map<String, Object>> records = applicationMapper.selectList(pageWrapper).stream()
@@ -73,6 +79,16 @@
         ServiceApplication application = application(id);
         return detailView(application);
     }
+
+    @Transactional(readOnly = true)
+    public List<Map<String, Object>> operationLogs(Long id) {
+        application(id);
+        return operationLogMapper.selectList(new QueryWrapper<ServiceApplicationOperationLog>()
+                        .eq("application_id", id)
+                        .orderByAsc("created_at", "id"))
+                .stream().map(this::operationLogView).toList();
+    }
+
 
     @Transactional
     public Map<String, Object> updateStatus(Long id, ServiceAppointmentStatusUpdateRequest request, Long operatorId) {
@@ -98,14 +114,29 @@
         if (updated != 1) {
             throw new BusinessException(ErrorCode.CONFLICT, "预约申请状态已变化,请刷新后重试");
         }
+        ServiceApplicationOperationLog log = new ServiceApplicationOperationLog();
+        log.setApplicationId(current.getId());
+        log.setApplicationNo(current.getApplicationNo());
+        log.setOperationType("STATUS_UPDATE");
+        log.setBeforeStatus(current.getStatus());
+        log.setAfterStatus(nextStatus);
+        log.setOperatorType("ADMIN");
+        log.setOperatorId(operatorId);
+        log.setOperatorName(handlerName);
+        log.setRemark(remark.isBlank() ? null : remark);
+        log.setCreatedAt(LocalDateTime.now());
+        if (operationLogMapper.insert(log) != 1) {
+            throw new BusinessException(ErrorCode.INTERNAL_ERROR, "预约申请操作日志保存失败");
+        }
         syncChildAudit(current, nextStatus, remark);
         return detail(id);
     }
 
     @Transactional(readOnly = true)
-    public byte[] exportExcel(String applicationType, String keyword, String serviceKeyword,
+    public byte[] exportExcel(String applicationType, String keyword, String applicantName,
+                              String applicantMobile, String serviceKeyword,
                               String cardLevel, String status, String submittedStart, String submittedEnd) {
-        QueryWrapper<ServiceApplication> wrapper = filter(applicationType, keyword, serviceKeyword, cardLevel, status, submittedStart, submittedEnd)
+        QueryWrapper<ServiceApplication> wrapper = filter(applicationType, keyword, applicantName, applicantMobile, serviceKeyword, cardLevel, status, submittedStart, submittedEnd)
                 .orderByDesc("submitted_at", "id");
         List<ServiceApplication> applications = applicationMapper.selectList(wrapper);
         String[] headers = {
@@ -142,7 +173,8 @@
         }
     }
 
-    private QueryWrapper<ServiceApplication> filter(String applicationType, String keyword, String serviceKeyword,
+    private QueryWrapper<ServiceApplication> filter(String applicationType, String keyword, String applicantName,
+                                                    String applicantMobile, String serviceKeyword,
                                                     String cardLevel, String status, String submittedStart, String submittedEnd) {
         QueryWrapper<ServiceApplication> wrapper = new QueryWrapper<ServiceApplication>().eq("deleted", 0);
         String type = normalizeFilterType(applicationType);
@@ -160,6 +192,20 @@
                     .or().like("applicant_mobile", like)
                     .or().like("spouse_name", like)
                     .or().like("child_name", like));
+        }
+        String name = clean(applicantName);
+        if (!name.isBlank()) {
+            wrapper.and(query -> query.like("talent_name", name)
+                    .or().like("applicant_name", name)
+                    .or().like("spouse_name", name)
+                    .or().like("child_name", name));
+        }
+        String mobile = clean(applicantMobile);
+        if (!mobile.isBlank()) {
+            wrapper.and(query -> query.like("talent_mobile", mobile)
+                    .or().like("applicant_mobile", mobile)
+                    .or().like("spouse_mobile", mobile)
+                    .or().like("contact_mobile", mobile));
         }
         String service = clean(serviceKeyword);
         if (!service.isBlank()) {
@@ -201,6 +247,7 @@
         result.put("appointmentContent", appointmentContent(application));
         result.put("appointmentTime", first(application.getExpectedTime(), "以专员通知为准"));
         result.put("applicantName", participantName(application));
+        result.put("applicantMobile", sensitiveDataCrypto.decrypt(first(application.getApplicantMobile(), application.getSpouseMobile(), application.getTalentMobile())));
         result.put("submittedAt", application.getSubmittedAt());
         result.put("handledAt", application.getHandledAt());
         result.put("handlerName", application.getHandlerName());
@@ -247,6 +294,24 @@
         result.put("child", child);
         return result;
     }
+
+    private Map<String, Object> operationLogView(ServiceApplicationOperationLog log) {
+        Map<String, Object> result = new LinkedHashMap<>();
+        result.put("id", log.getId());
+        result.put("applicationId", log.getApplicationId());
+        result.put("applicationNo", log.getApplicationNo());
+        result.put("operationType", log.getOperationType());
+        result.put("operationTypeText", "SUBMIT".equals(log.getOperationType()) ? "提交申请" : "状态更新");
+        result.put("beforeStatus", log.getBeforeStatus());
+        result.put("afterStatus", log.getAfterStatus());
+        result.put("operatorType", log.getOperatorType());
+        result.put("operatorId", log.getOperatorId());
+        result.put("operatorName", log.getOperatorName());
+        result.put("remark", log.getRemark());
+        result.put("createdAt", log.getCreatedAt());
+        return result;
+    }
+
 
     private List<String> exportValues(int index, ServiceApplication application) {
         return List.of(
@@ -404,4 +469,4 @@
     private String clean(String value) {
         return value == null ? "" : value.trim();
     }
-}
\ No newline at end of file
+}

--
Gitblit v1.7.1