package com.tcm.training.admin.member.service; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.tcm.training.admin.app.notice.service.AppSystemNoticeDispatchCommand; import com.tcm.training.admin.app.notice.service.AppSystemNoticeDispatchService; import com.tcm.training.admin.app.notice.service.AppSystemNoticeType; import com.tcm.training.admin.member.entity.AppUser; import com.tcm.training.admin.member.mapper.UserMapper; import com.tcm.training.admin.system.entity.SystemSettings; import com.tcm.training.admin.system.mapper.SystemSettingsMapper; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; /** * 会员到期提醒分发服务。 */ @Service public class MemberExpireRemindDispatchService { private final UserMapper userMapper; private final SystemSettingsMapper systemSettingsMapper; private final AppSystemNoticeDispatchService appSystemNoticeDispatchService; /** * 注入会员到期提醒分发所需依赖。 */ public MemberExpireRemindDispatchService(UserMapper userMapper, SystemSettingsMapper systemSettingsMapper, AppSystemNoticeDispatchService appSystemNoticeDispatchService) { this.userMapper = userMapper; this.systemSettingsMapper = systemSettingsMapper; this.appSystemNoticeDispatchService = appSystemNoticeDispatchService; } /** * 定时扫描即将到期的会员,并按系统设置发放提醒通知。 */ @Scheduled(fixedDelayString = "${app.member.expire-remind-interval-ms:3600000}") public void dispatchMemberExpireReminds() { Integer remindDays = resolveRemindDays(); if (remindDays == null || remindDays.intValue() < 0) { return; } LocalDateTime now = LocalDateTime.now(); LocalDateTime deadline = now.plusDays(remindDays.longValue()); List users = userMapper.selectList(new LambdaQueryWrapper() .eq(AppUser::getDeleted, 0) .eq(AppUser::getStatus, 1) .isNotNull(AppUser::getMemberExpireAt) .ge(AppUser::getMemberExpireAt, now) .le(AppUser::getMemberExpireAt, deadline) .orderByAsc(AppUser::getMemberExpireAt) .orderByAsc(AppUser::getId)); for (AppUser user : users) { dispatchMemberExpireNotice(user, now); } } /** * 为单个即将到期会员发放系统通知。 */ private void dispatchMemberExpireNotice(AppUser user, LocalDateTime now) { if (user == null || user.getId() == null || user.getMemberExpireAt() == null) { return; } long days = ChronoUnit.DAYS.between(now.toLocalDate(), user.getMemberExpireAt().toLocalDate()); AppSystemNoticeDispatchCommand command = new AppSystemNoticeDispatchCommand(); command.setAppUserId(user.getId()); command.setNoticeTypeCode(AppSystemNoticeType.MEMBER_EXPIRE_REMIND); command.setTitle("会员到期提醒"); command.setContent("您的会员有效期将于" + user.getMemberExpireAt().toLocalDate() + "到期"); // 这里把到期时间编码进引用类型,保证同一到期批次只提醒一次。 command.setReferenceType("MEMBER_EXPIRE_" + user.getMemberExpireAt().toLocalDate()); command.setReferenceId(user.getId()); command.setRequireUserSetting(Boolean.FALSE); Map payload = new LinkedHashMap(); payload.put("expireAt", String.valueOf(user.getMemberExpireAt())); payload.put("remainingDays", String.valueOf(days)); command.setPayload(payload); appSystemNoticeDispatchService.createAndPush(command); } /** * 获取系统配置的会员到期提醒天数。 */ private Integer resolveRemindDays() { SystemSettings settings = systemSettingsMapper.selectOne(new LambdaQueryWrapper() .eq(SystemSettings::getDeleted, 0) .orderByDesc(SystemSettings::getId) .last("limit 1")); return settings == null ? null : settings.getMemberExpireRemindDays(); } }