From 52b61fce22f188e37a88c20740e005ff109637a7 Mon Sep 17 00:00:00 2001
From: hsy <1029150275@qq.com>
Date: 星期一, 17 八月 2026 15:02:27 +0800
Subject: [PATCH] dos: 新增表:mes_pro_task_pause_record

---
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/dv/metering/MesDvMeteringRemindServiceImpl.java |  104 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 104 insertions(+), 0 deletions(-)

diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/dv/metering/MesDvMeteringRemindServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/dv/metering/MesDvMeteringRemindServiceImpl.java
new file mode 100644
index 0000000..2c8416c
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/dv/metering/MesDvMeteringRemindServiceImpl.java
@@ -0,0 +1,104 @@
+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锛坕nfra_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<MesDvMeteringDO> 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<String, Object> 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);
+    }
+
+}

--
Gitblit v1.9.3