package cn.iocoder.yudao.module.mes.service.dv.metering; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.module.infra.api.config.ConfigApi; import cn.iocoder.yudao.module.mes.dal.dataobject.dv.metering.MesDvMeteringDO; import cn.iocoder.yudao.module.mes.dal.mysql.dv.metering.MesDvMeteringMapper; import cn.iocoder.yudao.module.mes.dal.redis.dv.metering.MesDvMeteringRemindRedisDAO; import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi; import cn.iocoder.yudao.module.system.api.notify.dto.NotifySendSingleToUserReqDTO; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import java.time.LocalDate; import java.util.HashMap; import java.util.List; import java.util.Map; /** * MES 计量器具到期提醒 Service 实现类 * * @author 超级管理员 */ @Slf4j @Service public class MesDvMeteringRemindServiceImpl implements MesDvMeteringRemindService { /** * 提醒天数配置 KEY(infra_config) */ private static final String REMIND_DAYS_CONFIG_KEY = "mes.dv-metering.remind-days"; /** * 提醒天数默认值 */ private static final int DEFAULT_REMIND_DAYS = 30; /** * 到期提醒站内信模板编号 */ private static final String REMIND_TEMPLATE_CODE = "mes_metering_expire_remind"; @Resource private MesDvMeteringMapper meteringMapper; @Resource private MesDvMeteringRemindRedisDAO meteringRemindRedisDAO; @Resource private ConfigApi configApi; @Resource private NotifyMessageSendApi notifyMessageSendApi; @Override public void sendExpireRemind() { try { // 1. 抢当天扫描门闩,避免多实例/多次并发重复扫描 LocalDate today = LocalDate.now(); if (!meteringRemindRedisDAO.tryAcquireScanLock(today)) { return; } // 2. 读取提醒天数(默认 30) int remindDays = getRemindDays(); // 3. 查询 [today, today + remindDays] 到期的器具 List list = meteringMapper.selectListByNextCheckDateBetween( today, today.plusDays(remindDays)); // 4. 逐台发送站内信(按器具 + 到期日去重) for (MesDvMeteringDO metering : list) { if (metering.getChargeUserId() == null || metering.getNextCheckDate() == null) { continue; } if (!meteringRemindRedisDAO.tryMarkReminded(metering.getId(), metering.getNextCheckDate())) { continue; } sendRemindMessage(metering); } } catch (Exception ex) { // best-effort:提醒失败不影响列表查询 log.error("[sendExpireRemind][发送计量器具到期提醒失败]", ex); } } private int getRemindDays() { String value = configApi.getConfigValueByKey(REMIND_DAYS_CONFIG_KEY); if (StrUtil.isBlank(value)) { return DEFAULT_REMIND_DAYS; } try { return Integer.parseInt(value.trim()); } catch (NumberFormatException ex) { log.warn("[getRemindDays][配置 {} 的值 {} 非法,使用默认值 {}]", REMIND_DAYS_CONFIG_KEY, value, DEFAULT_REMIND_DAYS); return DEFAULT_REMIND_DAYS; } } private void sendRemindMessage(MesDvMeteringDO metering) { Map params = new HashMap<>(); params.put("meteringCode", metering.getCode()); params.put("meteringName", metering.getName()); params.put("nextCheckDate", metering.getNextCheckDate().toString()); NotifySendSingleToUserReqDTO reqDTO = new NotifySendSingleToUserReqDTO() .setUserId(metering.getChargeUserId()) .setTemplateCode(REMIND_TEMPLATE_CODE) .setTemplateParams(params); notifyMessageSendApi.sendSingleMessageToAdmin(reqDTO); } }