Jiaqi Xia

Merge branch 'feature/nongxinweixinnotice' into 'master'

Feature/nongxinweixinnotice



See merge request !7
1 +package com.tianting.infoloop.mapper;
2 +
3 +import com.tianting.infoloop.inject.MyBaseMapper;
4 +import com.tianting.infoloop.model.db.OrderSubscriptionMessageDb;
5 +import org.apache.ibatis.annotations.Delete;
6 +import org.apache.ibatis.annotations.Param;
7 +
8 +import java.util.List;
9 +
10 +public interface OrderSubscriptionMessageMapper extends MyBaseMapper<OrderSubscriptionMessageDb> {
11 +
12 + /**
13 + * 批量物理删除(绕过逻辑删除)
14 + */
15 + @Delete("<script>" +
16 + "DELETE FROM order_subscription_message " +
17 + "WHERE enterpriseId = #{enterpriseId} " +
18 + "AND id IN " +
19 + "<foreach collection='ids' item='id' open='(' separator=',' close=')'>" +
20 + "#{id}" +
21 + "</foreach>" +
22 + "</script>")
23 + int physicalDeleteByIds(@Param("ids") List<Long> ids, @Param("enterpriseId") int enterpriseId);
24 +}
25 +
1 +package com.tianting.infoloop.model.db;
2 +
3 +import com.baomidou.mybatisplus.annotation.FieldFill;
4 +import com.baomidou.mybatisplus.annotation.IdType;
5 +import com.baomidou.mybatisplus.annotation.TableField;
6 +import com.baomidou.mybatisplus.annotation.TableId;
7 +import com.baomidou.mybatisplus.annotation.TableLogic;
8 +import com.baomidou.mybatisplus.annotation.TableName;
9 +import com.baomidou.mybatisplus.extension.activerecord.Model;
10 +import lombok.Data;
11 +import lombok.EqualsAndHashCode;
12 +import lombok.experimental.Accessors;
13 +
14 +import java.time.LocalDateTime;
15 +
16 +/**
17 + * order subscription message DB
18 + * @TableName order_subscription_message
19 + */
20 +@Data
21 +@Accessors(chain = true)
22 +@EqualsAndHashCode(callSuper = true)
23 +@TableName(value = "meal_order_subscription_messages")
24 +public class OrderSubscriptionMessageDb extends Model<OrderSubscriptionMessageDb> {
25 + /**
26 + * 主键ID
27 + */
28 + @TableId(type = IdType.AUTO)
29 + private Long id;
30 + /**
31 + * 企业ID
32 + */
33 + private Integer enterpriseId;
34 + /**
35 + * 订餐用户ID(dinerId)
36 + */
37 + private Integer dinerId;
38 + /**
39 + * 微信用户OpenID
40 + */
41 + private String openId;
42 + /**
43 + * 订阅消息模板ID
44 + */
45 + private String templateId;
46 + /**
47 + * 跳转路径(小程序 path)
48 + */
49 + private String jumpPath;
50 + /**
51 + * 关联的订餐周期开始时间(精确到秒)
52 + */
53 + private LocalDateTime orderPeriodStartDate;
54 + /**
55 + * 关联的订餐周期结束时间(精确到秒)
56 + */
57 + private LocalDateTime orderPeriodEndDate;
58 + /**
59 + * 授权时间(创建时间)
60 + */
61 + @TableField(fill = FieldFill.INSERT)
62 + private LocalDateTime createdAt;
63 + /**
64 + * 更新时间
65 + */
66 + @TableField(fill = FieldFill.INSERT_UPDATE)
67 + private LocalDateTime updatedAt;
68 + /**
69 + * 授权状态,0-待使用(已授权但未发送),1-已使用(已发送,逻辑删除)
70 + */
71 + @TableLogic
72 + private Boolean isDeleted;
73 +}
74 +
1 +package com.tianting.infoloop.service;
2 +
3 +import com.baomidou.mybatisplus.extension.service.IService;
4 +import com.infoloop.tianting.mealorderservice.CreateOrderSubscriptionMessageRpcRequest;
5 +import com.infoloop.tianting.mealorderservice.GetUserOrderSubscriptionMessageHistoryRpcRequest;
6 +import com.tianting.infoloop.model.db.OrderSubscriptionMessageDb;
7 +
8 +import java.util.List;
9 +
10 +public interface OrderSubscriptionMessageDbService extends IService<OrderSubscriptionMessageDb> {
11 +
12 + OrderSubscriptionMessageDb createOrderSubscriptionMessage(CreateOrderSubscriptionMessageRpcRequest request);
13 +
14 + List<OrderSubscriptionMessageDb> getUserOrderSubscriptionMessageHistory(GetUserOrderSubscriptionMessageHistoryRpcRequest request);
15 +
16 + /**
17 + * 批量逻辑删除授权记录(表示已使用)
18 + * @param ids 要删除的记录ID列表
19 + * @param enterpriseId 企业ID
20 + * @return 受影响的行数
21 + */
22 + int batchDeleteByIds(java.util.List<Long> ids, int enterpriseId);
23 +
24 + /**
25 + * 批量物理删除授权记录
26 + * @param ids 要删除的记录ID列表
27 + * @param enterpriseId 企业ID
28 + * @return 受影响的行数
29 + */
30 + int batchPhysicalDeleteByIds(java.util.List<Long> ids, int enterpriseId);
31 +
32 + /**
33 + * 查询待发送的订阅消息(未删除的记录)
34 + * @param enterpriseId 企业ID
35 + * @return 待发送的订阅消息列表
36 + */
37 + List<OrderSubscriptionMessageDb> queryPendingMessages(int enterpriseId);
38 +}
39 +
1 +package com.tianting.infoloop.service.impl;
2 +
3 +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
4 +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
5 +import com.infoloop.tianting.mealorderservice.CreateOrderSubscriptionMessageRpcRequest;
6 +import com.infoloop.tianting.mealorderservice.GetUserOrderSubscriptionMessageHistoryRpcRequest;
7 +import com.tianting.infoloop.mapper.OrderSubscriptionMessageMapper;
8 +import com.tianting.infoloop.model.db.OrderSubscriptionMessageDb;
9 +import com.tianting.infoloop.service.OrderSubscriptionMessageDbService;
10 +import com.tianting.infoloop.utils.exception.ErrorCodeConstants;
11 +import com.tianting.infoloop.utils.exception.ServiceExceptionUtil;
12 +import lombok.RequiredArgsConstructor;
13 +import lombok.extern.slf4j.Slf4j;
14 +import org.springframework.beans.factory.annotation.Autowired;
15 +import org.springframework.stereotype.Service;
16 +
17 +import java.time.Instant;
18 +import java.time.LocalDateTime;
19 +import java.time.ZoneId;
20 +import java.util.List;
21 +
22 +@Slf4j
23 +@Service
24 +@RequiredArgsConstructor(onConstructor_ = @Autowired)
25 +public class OrderSubscriptionMessageDbServiceImpl extends ServiceImpl<OrderSubscriptionMessageMapper, OrderSubscriptionMessageDb> implements OrderSubscriptionMessageDbService {
26 +
27 + @Override
28 + public OrderSubscriptionMessageDb createOrderSubscriptionMessage(CreateOrderSubscriptionMessageRpcRequest request) {
29 + OrderSubscriptionMessageDb orderSubscriptionMessageDb = new OrderSubscriptionMessageDb();
30 + orderSubscriptionMessageDb.setEnterpriseId(request.getEnterpriseId());
31 + if (request.getDinerId() != 0) {
32 + orderSubscriptionMessageDb.setDinerId(request.getDinerId());
33 + }
34 + orderSubscriptionMessageDb.setOpenId(request.getOpenId());
35 + orderSubscriptionMessageDb.setTemplateId(request.getTemplateId());
36 + if (!request.getJumpPath().isEmpty()) {
37 + orderSubscriptionMessageDb.setJumpPath(request.getJumpPath());
38 + }
39 +
40 + // 转换时间戳为LocalDateTime(精确到秒),与项目中其他时间字段保持一致
41 + LocalDateTime orderPeriodStartDate = Instant.ofEpochMilli(request.getOrderPeriodStartDate())
42 + .atZone(ZoneId.systemDefault())
43 + .toLocalDateTime();
44 + orderSubscriptionMessageDb.setOrderPeriodStartDate(orderPeriodStartDate);
45 +
46 + if (request.getOrderPeriodEndDate() > 0) {
47 + LocalDateTime orderPeriodEndDate = Instant.ofEpochMilli(request.getOrderPeriodEndDate())
48 + .atZone(ZoneId.systemDefault())
49 + .toLocalDateTime();
50 + orderSubscriptionMessageDb.setOrderPeriodEndDate(orderPeriodEndDate);
51 + }
52 +
53 + boolean res = this.save(orderSubscriptionMessageDb);
54 + if (!res) {
55 + log.error("创建订阅消息授权记录失败, request: {}", request);
56 + throw ServiceExceptionUtil.exception(ErrorCodeConstants.ORDER_GEN_FAIL);
57 + }
58 + return orderSubscriptionMessageDb;
59 + }
60 +
61 + @Override
62 + public List<OrderSubscriptionMessageDb> getUserOrderSubscriptionMessageHistory(GetUserOrderSubscriptionMessageHistoryRpcRequest request) {
63 + LambdaQueryWrapper<OrderSubscriptionMessageDb> queryWrapper = new LambdaQueryWrapper<>();
64 + queryWrapper.eq(OrderSubscriptionMessageDb::getEnterpriseId, request.getEnterpriseId());
65 + queryWrapper.eq(OrderSubscriptionMessageDb::getOpenId, request.getOpenId());
66 +
67 + // 如果传入了 orderPeriodStartDate,查询大于等于该值的记录
68 + if (request.getOrderPeriodStartDate() > 0) {
69 + LocalDateTime orderPeriodStartDate = Instant.ofEpochMilli(request.getOrderPeriodStartDate())
70 + .atZone(ZoneId.systemDefault())
71 + .toLocalDateTime();
72 + queryWrapper.ge(OrderSubscriptionMessageDb::getOrderPeriodStartDate, orderPeriodStartDate);
73 + }
74 +
75 + queryWrapper.orderByDesc(OrderSubscriptionMessageDb::getCreatedAt);
76 + return this.list(queryWrapper);
77 + }
78 +
79 + @Override
80 + public int batchDeleteByIds(java.util.List<Long> ids, int enterpriseId) {
81 + if (ids == null || ids.isEmpty()) {
82 + return 0;
83 + }
84 + LambdaQueryWrapper<OrderSubscriptionMessageDb> queryWrapper = new LambdaQueryWrapper<>();
85 + queryWrapper.eq(OrderSubscriptionMessageDb::getEnterpriseId, enterpriseId);
86 + queryWrapper.in(OrderSubscriptionMessageDb::getId, ids);
87 + // 逻辑删除(使用 MyBatis-Plus 的 @TableLogic)
88 + return this.remove(queryWrapper) ? ids.size() : 0;
89 + }
90 +
91 + @Override
92 + public int batchPhysicalDeleteByIds(java.util.List<Long> ids, int enterpriseId) {
93 + if (ids == null || ids.isEmpty()) {
94 + return 0;
95 + }
96 + // 物理删除(使用 Mapper 中的 SQL,绕过逻辑删除)
97 + return this.baseMapper.physicalDeleteByIds(ids, enterpriseId);
98 + }
99 +
100 + @Override
101 + public List<OrderSubscriptionMessageDb> queryPendingMessages(int enterpriseId) {
102 + LambdaQueryWrapper<OrderSubscriptionMessageDb> queryWrapper = new LambdaQueryWrapper<>();
103 + queryWrapper.eq(OrderSubscriptionMessageDb::getEnterpriseId, enterpriseId)
104 + .eq(OrderSubscriptionMessageDb::getIsDeleted, false)
105 + .orderByAsc(OrderSubscriptionMessageDb::getCreatedAt);
106 + return this.list(queryWrapper);
107 + }
108 +}
109 +
...@@ -63,6 +63,13 @@ service MealOrderServiceRpc { ...@@ -63,6 +63,13 @@ service MealOrderServiceRpc {
63 rpc batchCreateDinerMealSuspensionRecords(BatchCreateDinerMealSuspensionRecordsRpcRequest) returns (BatchCreateDinerMealSuspensionRecordsRpcResponse); 63 rpc batchCreateDinerMealSuspensionRecords(BatchCreateDinerMealSuspensionRecordsRpcRequest) returns (BatchCreateDinerMealSuspensionRecordsRpcResponse);
64 rpc updateDinerMealSuspensionRecord(UpdateDinerMealSuspensionRecordRpcRequest) returns (UpdateDinerMealSuspensionRecordRpcResponse); 64 rpc updateDinerMealSuspensionRecord(UpdateDinerMealSuspensionRecordRpcRequest) returns (UpdateDinerMealSuspensionRecordRpcResponse);
65 rpc deleteDinerMealSuspensionRecordsByIds(DeleteDinerMealSuspensionRecordsByIdsRpcRequest) returns (DeleteDinerMealSuspensionRecordsRpcResponse); 65 rpc deleteDinerMealSuspensionRecordsByIds(DeleteDinerMealSuspensionRecordsByIdsRpcRequest) returns (DeleteDinerMealSuspensionRecordsRpcResponse);
66 +
67 + // 订餐订阅消息相关服务
68 + rpc CreateOrderSubscriptionMessage (CreateOrderSubscriptionMessageRpcRequest) returns (CreateOrderSubscriptionMessageRpcResponse) {}
69 + rpc GetUserOrderSubscriptionMessageHistory (GetUserOrderSubscriptionMessageHistoryRpcRequest) returns (GetUserOrderSubscriptionMessageHistoryRpcResponse) {}
70 + rpc BatchDeleteOrderSubscriptionMessagesByIds (BatchDeleteOrderSubscriptionMessagesByIdsRpcRequest) returns (BatchDeleteOrderSubscriptionMessagesByIdsRpcResponse) {}
71 + rpc BatchPhysicalDeleteOrderSubscriptionMessagesByIds (BatchPhysicalDeleteOrderSubscriptionMessagesByIdsRpcRequest) returns (BatchPhysicalDeleteOrderSubscriptionMessagesByIdsRpcResponse) {}
72 + rpc QueryPendingOrderSubscriptionMessages (QueryPendingOrderSubscriptionMessagesRpcRequest) returns (QueryPendingOrderSubscriptionMessagesRpcResponse) {}
66 } 73 }
67 74
68 enum MealOrderOrderMethodEnum { 75 enum MealOrderOrderMethodEnum {
...@@ -955,3 +962,76 @@ message BatchCreateDinerMealSuspensionRecordsRpcResponse { ...@@ -955,3 +962,76 @@ message BatchCreateDinerMealSuspensionRecordsRpcResponse {
955 bool isCreated = 1; 962 bool isCreated = 1;
956 repeated int32 ids = 2; 963 repeated int32 ids = 2;
957 } 964 }
965 +
966 +// 订餐订阅消息相关消息定义
967 +message CreateOrderSubscriptionMessageRpcRequest {
968 + int32 enterpriseId = 1;
969 + int32 dinerId = 2;
970 + string openId = 3;
971 + string templateId = 4;
972 + int64 orderPeriodStartDate = 5; // Unix 时间戳(毫秒),精确到秒
973 + string jumpPath = 6; // 跳转路径(小程序 path),可选
974 + int64 orderPeriodEndDate = 7; // Unix 时间戳(毫秒),精确到秒,可选
975 +}
976 +
977 +message CreateOrderSubscriptionMessageRpcResponse {
978 + int64 id = 1;
979 +}
980 +
981 +message GetUserOrderSubscriptionMessageHistoryRpcRequest {
982 + int32 enterpriseId = 1;
983 + string openId = 2;
984 + int64 orderPeriodStartDate = 3; // Unix 时间戳(毫秒),精确到秒,可选,如果传入则查询大于等于该值的记录
985 +}
986 +
987 +message OrderSubscriptionMessageRpcResponse {
988 + int64 id = 1;
989 + int64 orderPeriodStartDate = 2; // Unix 时间戳(毫秒),精确到秒
990 + int64 createdAt = 3; // Unix 时间戳(毫秒)
991 + bool isDeleted = 4;
992 + string jumpPath = 5; // 跳转路径(小程序 path),可选
993 + int64 orderPeriodEndDate = 6; // Unix 时间戳(毫秒),精确到秒,可选
994 +}
995 +
996 +message GetUserOrderSubscriptionMessageHistoryRpcResponse {
997 + repeated OrderSubscriptionMessageRpcResponse response = 1;
998 +}
999 +
1000 +message BatchDeleteOrderSubscriptionMessagesByIdsRpcRequest {
1001 + int32 enterpriseId = 1;
1002 + repeated int64 ids = 2; // 要删除的记录ID列表
1003 +}
1004 +
1005 +message BatchDeleteOrderSubscriptionMessagesByIdsRpcResponse {
1006 + int32 affectedRows = 1; // 受影响的行数
1007 +}
1008 +
1009 +message BatchPhysicalDeleteOrderSubscriptionMessagesByIdsRpcRequest {
1010 + int32 enterpriseId = 1;
1011 + repeated int64 ids = 2; // 要删除的记录ID列表
1012 +}
1013 +
1014 +message BatchPhysicalDeleteOrderSubscriptionMessagesByIdsRpcResponse {
1015 + int32 affectedRows = 1; // 受影响的行数
1016 +}
1017 +
1018 +// 查询待发送的订阅消息(未删除的记录)
1019 +message QueryPendingOrderSubscriptionMessagesRpcRequest {
1020 + int32 enterpriseId = 1;
1021 +}
1022 +
1023 +message PendingOrderSubscriptionMessageRpcResponse {
1024 + int64 id = 1;
1025 + int32 enterpriseId = 2;
1026 + int32 dinerId = 3;
1027 + string openId = 4;
1028 + string templateId = 5;
1029 + int64 orderPeriodStartDate = 6;
1030 + string jumpPath = 7;
1031 + int64 orderPeriodEndDate = 8;
1032 + int64 createdAt = 9;
1033 +}
1034 +
1035 +message QueryPendingOrderSubscriptionMessagesRpcResponse {
1036 + repeated PendingOrderSubscriptionMessageRpcResponse responses = 1;
1037 +}
......