“mitao”
2026-04-24 b620af46945757c8c578a9f8d3ef472e40544d70
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package com.tcm.training.admin.system.service;
 
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
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.app.notice.entity.AppUserActivityNotice;
import com.tcm.training.admin.app.notice.mapper.AppUserActivityNoticeMapper;
import com.tcm.training.admin.member.entity.AppUser;
import com.tcm.training.admin.member.mapper.UserMapper;
import com.tcm.training.admin.system.event.ActivityNoticeCreatedEvent;
import com.tcm.training.admin.system.entity.ActivityNotice;
import com.tcm.training.admin.system.mapper.ActivityNoticeMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.event.TransactionalEventListener;
 
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
 
/**
 * 活动通知分发服务。
 */
@Service
public class ActivityNoticeDispatchService {
 
    private static final Logger log = LoggerFactory.getLogger(ActivityNoticeDispatchService.class);
 
    private static final int USER_STATUS_ENABLED = 1;
    private static final int USER_DELETED_NO = 0;
    private static final int RECORD_DELETED_NO = 0;
    private static final int RECORD_DELETED_YES = 1;
    private static final long PAGE_SIZE = 500L;
 
    private final UserMapper userMapper;
    private final AppUserActivityNoticeMapper appUserActivityNoticeMapper;
    private final ActivityNoticeMapper activityNoticeMapper;
    private final AppSystemNoticeDispatchService appSystemNoticeDispatchService;
 
    /**
     * 注入活动通知分发所需依赖。
     */
    public ActivityNoticeDispatchService(UserMapper userMapper,
                                         AppUserActivityNoticeMapper appUserActivityNoticeMapper,
                                         ActivityNoticeMapper activityNoticeMapper,
                                         AppSystemNoticeDispatchService appSystemNoticeDispatchService) {
        this.userMapper = userMapper;
        this.appUserActivityNoticeMapper = appUserActivityNoticeMapper;
        this.activityNoticeMapper = activityNoticeMapper;
        this.appSystemNoticeDispatchService = appSystemNoticeDispatchService;
    }
 
    /**
     * 在活动通知创建提交成功后异步为用户分发通知记录。
     */
    @Async("activityNoticeTaskExecutor")
    @TransactionalEventListener
    public void handleActivityNoticeCreated(ActivityNoticeCreatedEvent event) {
        if (event == null || event.getActivityNoticeId() == null) {
            return;
        }
        ActivityNotice activityNotice = activityNoticeMapper.selectOne(new LambdaQueryWrapper<ActivityNotice>()
                .eq(ActivityNotice::getId, event.getActivityNoticeId())
                .eq(ActivityNotice::getDeleted, RECORD_DELETED_NO)
                .last("limit 1"));
        if (activityNotice == null) {
            return;
        }
        long currentPage = 1L;
        while (true) {
            Page<AppUser> page = userMapper.selectPage(
                    new Page<AppUser>(currentPage, PAGE_SIZE),
                    new LambdaQueryWrapper<AppUser>()
                            .eq(AppUser::getDeleted, USER_DELETED_NO)
                            .eq(AppUser::getStatus, USER_STATUS_ENABLED)
                            .orderByAsc(AppUser::getId)
            );
            List<AppUser> users = page.getRecords();
            if (users == null || users.isEmpty()) {
                break;
            }
            for (AppUser user : users) {
                distributeToUser(user, activityNotice);
            }
            if (page.getCurrent() >= page.getPages()) {
                break;
            }
            currentPage++;
        }
    }
 
    /**
     * 为单个 APP 用户分发活动通知,单用户失败不影响整批分发。
     */
    private void distributeToUser(AppUser user, ActivityNotice activityNotice) {
        if (user == null || user.getId() == null || activityNotice == null || activityNotice.getId() == null) {
            return;
        }
        try {
            boolean exists = appUserActivityNoticeMapper.selectCount(new LambdaQueryWrapper<AppUserActivityNotice>()
                    .eq(AppUserActivityNotice::getAppUserId, user.getId())
                    .eq(AppUserActivityNotice::getActivityNoticeId, activityNotice.getId())
                    .eq(AppUserActivityNotice::getDeleted, RECORD_DELETED_NO)) > 0;
            if (!exists) {
                AppUserActivityNotice record = new AppUserActivityNotice();
                record.setAppUserId(user.getId());
                record.setActivityNoticeId(activityNotice.getId());
                record.setDeleted(RECORD_DELETED_NO);
                appUserActivityNoticeMapper.insert(record);
            }
            // 活动通知发布后同时写入统一系统通知表,并按双开关规则尝试极光推送。
            appSystemNoticeDispatchService.createAndPush(buildActivityNoticeCommand(user.getId(), activityNotice));
        } catch (Exception ex) {
            log.error("activity notice distribute failed, activityNoticeId={}, appUserId={}",
                    activityNotice.getId(), user.getId(), ex);
        }
    }
 
    /**
     * 构建活动通知统一发放命令。
     */
    private AppSystemNoticeDispatchCommand buildActivityNoticeCommand(Long appUserId, ActivityNotice activityNotice) {
        AppSystemNoticeDispatchCommand command = new AppSystemNoticeDispatchCommand();
        command.setAppUserId(appUserId);
        command.setNoticeTypeCode(AppSystemNoticeType.ACTIVITY_NOTICE);
        command.setTitle(activityNotice.getTitle());
        command.setContent(activityNotice.getTitle());
        command.setReferenceType("ACTIVITY_NOTICE");
        command.setReferenceId(activityNotice.getId());
        command.setRequireUserSetting(Boolean.TRUE);
        Map<String, String> payload = new LinkedHashMap<String, String>();
        payload.put("activityNoticeId", String.valueOf(activityNotice.getId()));
        payload.put("title", activityNotice.getTitle());
        command.setPayload(payload);
        return command;
    }
 
    /**
     * 在后台删除活动通知时同步隐藏用户侧对应记录。
     */
    public void hideDistributedRecords(Long activityNoticeId) {
        if (activityNoticeId == null) {
            return;
        }
        appUserActivityNoticeMapper.update(
                null,
                new LambdaUpdateWrapper<AppUserActivityNotice>()
                        .eq(AppUserActivityNotice::getActivityNoticeId, activityNoticeId)
                        .eq(AppUserActivityNotice::getDeleted, RECORD_DELETED_NO)
                        .set(AppUserActivityNotice::getDeleted, RECORD_DELETED_YES)
        );
    }
}