From 3a4386261c498d01ddb7dce3bb22cea7db5cc572 Mon Sep 17 00:00:00 2001 From: Timi Date: Mon, 7 Sep 2026 11:38:41 +0800 Subject: [PATCH] add gao user remind --- .../modules/common/mapper/NotifyMapper.java | 5 + .../modules/common/service/NotifyService.java | 8 + .../implement/NotifyServiceImplement.java | 5 + .../gao/mapper/GaoOrderReminderMapper.java | 27 +++ .../api/modules/gao/mapper/GaoUserMapper.java | 6 + .../gao/service/GaoOrderReminderService.java | 14 ++ .../GaoOrderReminderServiceImplement.java | 174 ++++++++++++++++++ .../gao/task/GaoOrderReminderTask.java | 41 +++++ .../gao/vo/GaoOrderReminderCustomer.java | 20 ++ .../gao/GaoOrderReminderMapper.xml | 44 +++++ .../mapper/timi-server/gao/GaoUserMapper.xml | 12 ++ 11 files changed, 356 insertions(+) create mode 100644 src/main/java/com/imyeyu/api/modules/gao/mapper/GaoOrderReminderMapper.java create mode 100644 src/main/java/com/imyeyu/api/modules/gao/service/GaoOrderReminderService.java create mode 100644 src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoOrderReminderServiceImplement.java create mode 100644 src/main/java/com/imyeyu/api/modules/gao/task/GaoOrderReminderTask.java create mode 100644 src/main/java/com/imyeyu/api/modules/gao/vo/GaoOrderReminderCustomer.java create mode 100644 src/main/resources/mapper/timi-server/gao/GaoOrderReminderMapper.xml diff --git a/src/main/java/com/imyeyu/api/modules/common/mapper/NotifyMapper.java b/src/main/java/com/imyeyu/api/modules/common/mapper/NotifyMapper.java index 10ff654..5636f9f 100644 --- a/src/main/java/com/imyeyu/api/modules/common/mapper/NotifyMapper.java +++ b/src/main/java/com/imyeyu/api/modules/common/mapper/NotifyMapper.java @@ -3,6 +3,7 @@ package com.imyeyu.api.modules.common.mapper; import com.imyeyu.api.modules.common.entity.Notify; import com.imyeyu.api.modules.common.vo.NotifyManagementItem; import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; import com.imyeyu.spring.mapper.BaseMapper; import java.util.List; @@ -15,6 +16,10 @@ import java.util.List; */ public interface NotifyMapper extends BaseMapper { + /// 查询业务提醒是否已创建 + @Select("SELECT EXISTS (SELECT 1 FROM `notify` WHERE `biz_type` = #{bizType} AND `biz_reminded_type` = #{bizRemindedType} AND `biz_reminded_id` = #{bizRemindedId} AND `deleted_at` IS NULL)") + boolean existsByBizReminded(@Param("bizType") String bizType, @Param("bizRemindedType") String bizRemindedType, @Param("bizRemindedId") String bizRemindedId); + /// 分页查询管理端通知 /// /// @param userId 管理员用户 ID diff --git a/src/main/java/com/imyeyu/api/modules/common/service/NotifyService.java b/src/main/java/com/imyeyu/api/modules/common/service/NotifyService.java index 4b41082..4b4bd09 100644 --- a/src/main/java/com/imyeyu/api/modules/common/service/NotifyService.java +++ b/src/main/java/com/imyeyu/api/modules/common/service/NotifyService.java @@ -14,6 +14,14 @@ import com.imyeyu.spring.service.BaseService; */ public interface NotifyService extends BaseService { + /// 查询业务提醒是否已创建 + /// + /// @param bizType 业务类型 + /// @param bizRemindedType 被提醒业务类型 + /// @param bizRemindedId 被提醒业务 ID + /// @return true 为已创建 + boolean existsByBizReminded(String bizType, String bizRemindedType, String bizRemindedId); + /// 分页查询当前用户创建的通知 /// /// @param page 分页参数 diff --git a/src/main/java/com/imyeyu/api/modules/common/service/implement/NotifyServiceImplement.java b/src/main/java/com/imyeyu/api/modules/common/service/implement/NotifyServiceImplement.java index 85ae375..fc631bd 100644 --- a/src/main/java/com/imyeyu/api/modules/common/service/implement/NotifyServiceImplement.java +++ b/src/main/java/com/imyeyu/api/modules/common/service/implement/NotifyServiceImplement.java @@ -46,6 +46,11 @@ public class NotifyServiceImplement extends AbstractEntityService selectOrderReceiveCustomers(); + + /// 查询待核销收款客户 + /// + /// @return 收款客户列表 + List selectReceiveVerifyCustomers(); + + /// 查询待核销履约客户 + /// + /// @return 履约客户列表 + List selectFulfillmentVerifyCustomers(); +} diff --git a/src/main/java/com/imyeyu/api/modules/gao/mapper/GaoUserMapper.java b/src/main/java/com/imyeyu/api/modules/gao/mapper/GaoUserMapper.java index 9ad780e..81f9bf9 100644 --- a/src/main/java/com/imyeyu/api/modules/gao/mapper/GaoUserMapper.java +++ b/src/main/java/com/imyeyu/api/modules/gao/mapper/GaoUserMapper.java @@ -15,6 +15,12 @@ import java.util.List; /// @since 2026-07-30 public interface GaoUserMapper extends BaseMapper { + /// 查询门店启用中的店长 + /// + /// @param storeId 门店 ID + /// @return 店长列表 + List selectEnabledStoreManagers(@Param("storeId") String storeId); + List selectByUserIdList(Collection userIdList); List selectRecipientPage(@Param("page") Page page); diff --git a/src/main/java/com/imyeyu/api/modules/gao/service/GaoOrderReminderService.java b/src/main/java/com/imyeyu/api/modules/gao/service/GaoOrderReminderService.java new file mode 100644 index 0000000..ead6e45 --- /dev/null +++ b/src/main/java/com/imyeyu/api/modules/gao/service/GaoOrderReminderService.java @@ -0,0 +1,14 @@ +package com.imyeyu.api.modules.gao.service; + +/// GAO 订单提醒服务 +/// +/// @author Codex +/// @since 2026-09-06 +public interface GaoOrderReminderService { + + /// 发送订单收款提醒 + void sendOrderReceiveReminder(); + + /// 发送核销提醒 + void sendVerifyReminder(); +} diff --git a/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoOrderReminderServiceImplement.java b/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoOrderReminderServiceImplement.java new file mode 100644 index 0000000..0db3907 --- /dev/null +++ b/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoOrderReminderServiceImplement.java @@ -0,0 +1,174 @@ +package com.imyeyu.api.modules.gao.service.implement; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.imyeyu.api.modules.common.entity.Notify; +import com.imyeyu.api.modules.common.entity.NotifyDetail; +import com.imyeyu.api.modules.common.service.NotifyService; +import com.imyeyu.api.modules.gao.entity.GaoUser; +import com.imyeyu.api.modules.gao.mapper.GaoOrderReminderMapper; +import com.imyeyu.api.modules.gao.mapper.GaoUserMapper; +import com.imyeyu.api.modules.gao.service.GaoOrderReminderService; +import com.imyeyu.api.modules.gao.vo.GaoOrderReminderCustomer; +import com.imyeyu.api.modules.user.entity.User; +import com.imyeyu.api.modules.user.service.UserService; +import com.imyeyu.utils.Time; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.time.LocalDate; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +/// GAO 订单提醒服务实现 +/// +/// @author Codex +/// @since 2026-09-06 +@Slf4j +@Service +@RequiredArgsConstructor +public class GaoOrderReminderServiceImplement implements GaoOrderReminderService { + + private static final String NOTIFY_BIZ_TYPE = "GAO_ORDER_REMINDER"; + private static final String SMS_TEMPLATE_ID = "2725097"; + private static final String ZONE_ID = "Asia/Shanghai"; + + private final GaoOrderReminderMapper mapper; + private final GaoUserMapper gaoUserMapper; + private final UserService userService; + private final NotifyService notifyService; + private final ObjectMapper jackson; + + @Override + public void sendOrderReceiveReminder() { + send(mapper.selectOrderReceiveCustomers(), ReminderType.ORDER_RECEIVE); + } + + @Override + public void sendVerifyReminder() { + Map> storeCustomerMap = new LinkedHashMap<>(); + Map> storeActionMap = new LinkedHashMap<>(); + mergeCustomers(storeCustomerMap, storeActionMap, mapper.selectReceiveVerifyCustomers(), "核销收款"); + mergeCustomers(storeCustomerMap, storeActionMap, mapper.selectFulfillmentVerifyCustomers(), "核销履约"); + for (Map.Entry> entry : storeCustomerMap.entrySet()) { + String action = String.join("、", storeActionMap.get(entry.getKey())); + sendStoreReminder(entry.getKey(), new ArrayList<>(entry.getValue().values()), ReminderType.VERIFY.name(), action); + } + } + + private void mergeCustomers(Map> storeCustomerMap, + Map> storeActionMap, List customerList, String action) { + if (customerList == null || customerList.isEmpty()) { + return; + } + for (GaoOrderReminderCustomer customer : customerList) { + storeCustomerMap.computeIfAbsent(customer.getStoreId(), key -> new LinkedHashMap<>()) + .putIfAbsent(customer.getCustomerId(), customer); + storeActionMap.computeIfAbsent(customer.getStoreId(), key -> new LinkedHashSet<>()).add(action); + } + } + + private void send(List customerList, ReminderType reminderType) { + if (customerList == null || customerList.isEmpty()) { + return; + } + Map> storeCustomerMap = customerList.stream() + .collect(Collectors.groupingBy(GaoOrderReminderCustomer::getStoreId, LinkedHashMap::new, Collectors.toList())); + for (Map.Entry> entry : storeCustomerMap.entrySet()) { + sendStoreReminder(entry.getKey(), entry.getValue(), reminderType.name(), reminderType.label); + } + } + + private void sendStoreReminder(String storeId, List customerList, String reminderType, + String action) { + String customerNames = formatCustomerNames(customerList); + String content = "您的客户 %s 的订单需要 %s,请留意订单状态。".formatted(customerNames, action); + List managerList = gaoUserMapper.selectEnabledStoreManagers(storeId); + if (managerList == null || managerList.isEmpty()) { + log.warn("GAO 订单提醒未找到启用中的店长: storeId[{}], reminderType[{}]", storeId, reminderType); + return; + } + List userIdList = managerList.stream().map(GaoUser::getUserId).distinct().toList(); + Map userMap = userService.mapByIdList(userIdList); + for (GaoUser manager : managerList) { + try { + User user = userMap.get(manager.getUserId()); + if (user == null) { + log.warn("GAO 订单提醒跳过不存在的店长用户: storeId[{}], userId[{}]", storeId, manager.getUserId()); + continue; + } + String remindedId = "%s:%s:%s:%s".formatted(LocalDate.now(ZoneId.of(ZONE_ID)), storeId, manager.getUserId(), reminderType); + if (notifyService.existsByBizReminded(NOTIFY_BIZ_TYPE, reminderType, remindedId)) { + continue; + } + long sendAt = Time.now(); + Notify notify = new Notify(); + notify.setBizType(NOTIFY_BIZ_TYPE); + notify.setBizRemindedType(reminderType); + notify.setBizRemindedId(remindedId); + notify.setDetailList(List.of( + createInternalDetail(manager.getUserId(), content, sendAt), + createSmsDetail(user.getPhoneNo(), customerNames, action, content, sendAt) + )); + notifyService.create(notify); + } catch (Exception e) { + log.error("GAO 订单提醒发送失败: storeId[{}], userId[{}], reminderType[{}]", storeId, manager.getUserId(), reminderType, e); + } + } + } + + private NotifyDetail createInternalDetail(String userId, String content, long sendAt) { + NotifyDetail detail = new NotifyDetail(); + detail.setMsgType(NotifyDetail.MsgType.INTERNAL); + detail.setTemplateId(SMS_TEMPLATE_ID); + detail.setSubject("订单状态提醒"); + detail.setContent(content); + detail.setContentType(NotifyDetail.ContentType.TEXT); + detail.setSendTo(userId); + detail.setSendAt(sendAt); + return detail; + } + + private NotifyDetail createSmsDetail(String phoneNo, String customerNames, String action, String content, long sendAt) { + NotifyDetail detail = new NotifyDetail(); + detail.setMsgType(NotifyDetail.MsgType.SMS); + detail.setTemplateId(SMS_TEMPLATE_ID); + detail.setContent(content); + detail.setArgs(jackson.valueToTree(List.of(customerNames, action))); + detail.setSendTo(phoneNo); + detail.setSendAt(sendAt); + return detail; + } + + private String formatCustomerNames(List customerList) { + List nameList = customerList.stream() + .map(GaoOrderReminderCustomer::getCustomerName) + .map(name -> name == null || name.isBlank() ? "未知客户" : name.trim()) + .toList(); + if (customerList.size() <= 2) { + return String.join("、", nameList); + } + return "%s、%s等 %d 位".formatted(nameList.getFirst(), nameList.get(1), customerList.size()); + } + + private enum ReminderType { + + /// 订单收款 + ORDER_RECEIVE("收款"), + + /// 统一核销 + VERIFY("核销收款、核销履约"); + + private final String label; + + ReminderType(String label) { + this.label = label; + } + } +} diff --git a/src/main/java/com/imyeyu/api/modules/gao/task/GaoOrderReminderTask.java b/src/main/java/com/imyeyu/api/modules/gao/task/GaoOrderReminderTask.java new file mode 100644 index 0000000..fd5670a --- /dev/null +++ b/src/main/java/com/imyeyu/api/modules/gao/task/GaoOrderReminderTask.java @@ -0,0 +1,41 @@ +package com.imyeyu.api.modules.gao.task; + +import com.imyeyu.api.modules.gao.service.GaoOrderReminderService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; + +/// GAO 订单提醒定时任务 +/// +/// @author Codex +/// @since 2026-09-06 +@Slf4j +@Service +@RequiredArgsConstructor +public class GaoOrderReminderTask { + + private static final String ZONE_ID = "Asia/Shanghai"; + + private final GaoOrderReminderService service; + + /// 每天早上八点发送订单收款提醒 + @Scheduled(cron = "0 0 8 * * ?", zone = ZONE_ID) + public void sendOrderReceiveReminder() { + execute("订单收款", service::sendOrderReceiveReminder); + } + + /// 每天晚上九点发送核销提醒 + @Scheduled(cron = "0 0 21 * * ?", zone = ZONE_ID) + public void sendVerifyReminder() { + execute("核销", service::sendVerifyReminder); + } + + private void execute(String reminderName, Runnable action) { + try { + action.run(); + } catch (Exception e) { + log.error("GAO {}提醒任务执行失败", reminderName, e); + } + } +} diff --git a/src/main/java/com/imyeyu/api/modules/gao/vo/GaoOrderReminderCustomer.java b/src/main/java/com/imyeyu/api/modules/gao/vo/GaoOrderReminderCustomer.java new file mode 100644 index 0000000..52f9bab --- /dev/null +++ b/src/main/java/com/imyeyu/api/modules/gao/vo/GaoOrderReminderCustomer.java @@ -0,0 +1,20 @@ +package com.imyeyu.api.modules.gao.vo; + +import lombok.Data; + +/// GAO 订单提醒客户 +/// +/// @author Codex +/// @since 2026-09-06 +@Data +public class GaoOrderReminderCustomer { + + /// 门店 ID + private String storeId; + + /// 客户 ID + private String customerId; + + /// 客户名称 + private String customerName; +} diff --git a/src/main/resources/mapper/timi-server/gao/GaoOrderReminderMapper.xml b/src/main/resources/mapper/timi-server/gao/GaoOrderReminderMapper.xml new file mode 100644 index 0000000..e1443e0 --- /dev/null +++ b/src/main/resources/mapper/timi-server/gao/GaoOrderReminderMapper.xml @@ -0,0 +1,44 @@ + + + + + + + + + diff --git a/src/main/resources/mapper/timi-server/gao/GaoUserMapper.xml b/src/main/resources/mapper/timi-server/gao/GaoUserMapper.xml index 18e84a3..04e9ab3 100644 --- a/src/main/resources/mapper/timi-server/gao/GaoUserMapper.xml +++ b/src/main/resources/mapper/timi-server/gao/GaoUserMapper.xml @@ -1,6 +1,18 @@ + +