package com.tourguide.modules.user.service; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.tourguide.common.api.PageResponse; import com.tourguide.common.exception.BusinessException; import com.tourguide.modules.user.dto.GuideApplicationResponse; import com.tourguide.modules.user.entity.GuideApplication; import com.tourguide.modules.user.mapper.GuideApplicationMapper; import com.tourguide.modules.system.service.GuideNotificationService; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.stream.Collectors; /** 管理导游入驻申请查询和一次性审核状态流转。 */ @Service public class GuideApplicationService { private static final int PENDING = 0; private static final int APPROVED = 1; private static final int REJECTED = 2; private final GuideApplicationMapper applicationMapper; private final GuideUserService guideUserService; private final GuideNotificationService notificationService; private final GuideAuditSmsService auditSmsService; public GuideApplicationService(GuideApplicationMapper applicationMapper, GuideUserService guideUserService, GuideNotificationService notificationService, GuideAuditSmsService auditSmsService) { this.applicationMapper = applicationMapper; this.guideUserService = guideUserService; this.notificationService = notificationService; this.auditSmsService = auditSmsService; } public PageResponse page(long page, long size, String keyword, Integer auditStatus, LocalDate startDate, LocalDate endDate) { LambdaQueryWrapper query = new LambdaQueryWrapper(); if (StringUtils.hasText(keyword)) { String searchKeyword = keyword.trim(); query.and(wrapper -> wrapper.like(GuideApplication::getApplicationNo, searchKeyword) .or().like(GuideApplication::getRealName, searchKeyword) .or().like(GuideApplication::getMobile, searchKeyword)); } query.eq(auditStatus != null, GuideApplication::getAuditStatus, auditStatus) .ge(startDate != null, GuideApplication::getCreatedAt, startDate == null ? null : startDate.atStartOfDay()) .lt(endDate != null, GuideApplication::getCreatedAt, endDate == null ? null : endDate.plusDays(1).atStartOfDay()) .orderByDesc(GuideApplication::getCreatedAt); Page result = applicationMapper.selectPage(new Page(page, size), query); return new PageResponse( result.getRecords().stream().map(GuideApplicationResponse::from).collect(Collectors.toList()), result.getTotal(), result.getCurrent(), result.getSize()); } public GuideApplicationResponse detail(Long id) { GuideApplication application = applicationMapper.selectById(id); if (application == null) { throw new BusinessException(404, "导游申请不存在"); } return GuideApplicationResponse.from(application); } @Transactional public GuideApplicationResponse audit(Long id, Integer auditStatus, String auditRemark, String auditor) { validateAudit(auditStatus, auditRemark); GuideApplication application = applicationMapper.selectOne(new LambdaQueryWrapper() .eq(GuideApplication::getId, id) .last("FOR UPDATE")); if (application == null) { throw new BusinessException(404, "导游申请不存在"); } if (application.getAuditStatus() == null || application.getAuditStatus() != PENDING) { throw new BusinessException(409, "该申请已审核,请勿重复操作"); } if (auditStatus == APPROVED) guideUserService.createFromApprovedApplication(application); LambdaUpdateWrapper update = new LambdaUpdateWrapper() .eq(GuideApplication::getId, id) .eq(GuideApplication::getAuditStatus, PENDING) .set(GuideApplication::getAuditStatus, auditStatus) .set(GuideApplication::getAuditRemark, normalizeRemark(auditRemark)) .set(GuideApplication::getAuditor, auditor) .set(GuideApplication::getAuditedAt, LocalDateTime.now()); if (applicationMapper.update(null, update) != 1) { throw new BusinessException(409, "该申请已被其他管理员处理"); } com.tourguide.modules.user.entity.GuideUser guide = guideUserService.findByPhone(application.getMobile()); if (guide != null) notificationService.notifyAuditResult(guide.getId(), auditStatus == APPROVED); auditSmsService.send(application.getMobile(), application.getRealName(), auditStatus == APPROVED); return detail(id); } private void validateAudit(Integer auditStatus, String auditRemark) { if (auditStatus == null || (auditStatus != APPROVED && auditStatus != REJECTED)) { throw new BusinessException(400, "审核结果仅支持通过或驳回"); } if (auditStatus == REJECTED && !StringUtils.hasText(auditRemark)) { throw new BusinessException(400, "驳回时必须填写审核备注"); } } private String normalizeRemark(String auditRemark) { return StringUtils.hasText(auditRemark) ? auditRemark.trim() : null; } }