3 天以前 83e1b4d0e661f11a407fd6ea86e906b9b87b7180
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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
package cn.iocoder.yudao.module.bpm.service.oa;
 
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.OaNoticePageReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.OaNoticeSaveReqVO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.OaNoticeDO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.OaNoticeReadDO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.OaNoticeUserDO;
import cn.iocoder.yudao.module.bpm.dal.mysql.oa.OaNoticeMapper;
import cn.iocoder.yudao.module.bpm.dal.mysql.oa.OaNoticeReadMapper;
import cn.iocoder.yudao.module.bpm.dal.mysql.oa.OaNoticeUserMapper;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.module.bpm.enums.oa.OaNoticeSendScopeEnum;
import cn.iocoder.yudao.module.bpm.enums.oa.OaNoticeStatusEnum;
import cn.iocoder.yudao.module.system.dal.mysql.notify.NotifyMessageMapper;
import cn.iocoder.yudao.module.system.service.notify.NotifySendService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
 
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
 
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.OA_NOTICE_NOT_EXISTS;
 
/**
 * OA 通知公告 Service 实现类
 */
@Service
@Slf4j
public class OaNoticeServiceImpl implements OaNoticeService {
 
    @Resource
    private OaNoticeMapper oaNoticeMapper;
 
    @Resource
    private OaNoticeUserMapper oaNoticeUserMapper;
 
    @Resource
    private OaNoticeReadMapper oaNoticeReadMapper;
 
    @Resource
    private NotifySendService notifySendService;
 
    @Resource
    private AdminUserService adminUserService;
 
    @Resource
    private NotifyMessageMapper notifyMessageMapper;
 
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createNotice(Long userId, OaNoticeSaveReqVO createReqVO) {
        // 创建通知公告
        OaNoticeDO notice = BeanUtils.toBean(createReqVO, OaNoticeDO.class);
        notice.setPublishUserId(userId);
        if (OaNoticeStatusEnum.PUBLISHED.getStatus().equals(createReqVO.getStatus())) {
            notice.setPublishTime(LocalDateTime.now());
        }
        oaNoticeMapper.insert(notice);
 
        // 指定人写入关联表
        if (OaNoticeSendScopeEnum.SPECIFIED.getScope().equals(createReqVO.getSendScope())
                && CollUtil.isNotEmpty(createReqVO.getUserIds())) {
            saveNoticeUsers(notice.getId(), createReqVO.getUserIds());
        }
 
        // 已发布则发送系统通知
        if (OaNoticeStatusEnum.PUBLISHED.getStatus().equals(notice.getStatus())) {
            sendPublishNotify(notice);
        }
 
        return notice.getId();
    }
 
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateNotice(OaNoticeSaveReqVO updateReqVO) {
        // 校验是否存在
        OaNoticeDO oldNotice = validateNoticeExists(updateReqVO.getId());
 
        // 更新通知公告
        OaNoticeDO updateObj = BeanUtils.toBean(updateReqVO, OaNoticeDO.class);
        // 从未发布变为已发布时,设置发布时间
        if (!OaNoticeStatusEnum.PUBLISHED.getStatus().equals(oldNotice.getStatus())
                && OaNoticeStatusEnum.PUBLISHED.getStatus().equals(updateReqVO.getStatus())) {
            updateObj.setPublishTime(LocalDateTime.now());
        }
        oaNoticeMapper.updateById(updateObj);
 
        // 更新指定人关联
        oaNoticeUserMapper.deleteByNoticeId(updateReqVO.getId());
        if (OaNoticeSendScopeEnum.SPECIFIED.getScope().equals(updateReqVO.getSendScope())
                && CollUtil.isNotEmpty(updateReqVO.getUserIds())) {
            saveNoticeUsers(updateReqVO.getId(), updateReqVO.getUserIds());
        }
 
        // 新发布时发送系统通知
        if (!OaNoticeStatusEnum.PUBLISHED.getStatus().equals(oldNotice.getStatus())
                && OaNoticeStatusEnum.PUBLISHED.getStatus().equals(updateReqVO.getStatus())) {
            sendPublishNotify(updateObj);
        }
 
        // 撤销时删除已发送的系统通知
        if (OaNoticeStatusEnum.REVOKED.getStatus().equals(updateReqVO.getStatus())
                && OaNoticeStatusEnum.PUBLISHED.getStatus().equals(oldNotice.getStatus())) {
            notifyMessageMapper.deleteByTemplateCodeAndNoticeId(
                    "oa-notice-publish", updateReqVO.getId());
        }
    }
 
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteNotice(Long id) {
        validateNoticeExists(id);
        oaNoticeMapper.deleteById(id);
        oaNoticeUserMapper.deleteByNoticeId(id);
    }
 
    @Override
    public PageResult<OaNoticeDO> getNoticePage(Long userId, OaNoticePageReqVO reqVO) {
        // 构建可见的通知ID集合
        Set<Long> visibleIds = buildVisibleNoticeIds(userId);
        if (visibleIds != null && visibleIds.isEmpty()) {
            return PageResult.empty();
        }
        return oaNoticeMapper.selectPage(reqVO, visibleIds);
    }
 
    @Override
    public OaNoticeDO getNotice(Long id, Long userId) {
        OaNoticeDO notice = validateNoticeExists(id);
        // 标记已读
        markAsRead(id, userId);
        return notice;
    }
 
    @Override
    public Long getUnreadCount(Long userId) {
        // 获取所有已发布且当前用户可见的公告ID
        Set<Long> visibleIds = buildVisibleNoticeIds(userId);
        if (CollUtil.isEmpty(visibleIds)) {
            return 0L;
        }
        List<Long> visibleIdList = new ArrayList<>(visibleIds);
        return oaNoticeReadMapper.selectUnreadCountByUserId(userId, visibleIdList);
    }
 
    /**
     * 构建当前用户可见的通知公告ID集合
     *
     * @param userId 当前用户ID
     * @return null表示全部可见,空集合表示无可看
     */
    private Set<Long> buildVisibleNoticeIds(Long userId) {
        // 所有通知所有人公告ID
        List<OaNoticeDO> allPublishedNotices = oaNoticeMapper.selectList(
                new cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX<OaNoticeDO>()
                        .eq(OaNoticeDO::getSendScope, OaNoticeSendScopeEnum.ALL.getScope()));
        Set<Long> allNoticeIds = allPublishedNotices.stream()
                .map(OaNoticeDO::getId).collect(Collectors.toSet());
 
        // 指定人能看到的本用户相关公告ID
        List<OaNoticeDO> specifiedNotices = oaNoticeMapper.selectList(
                new cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX<OaNoticeDO>()
                        .eq(OaNoticeDO::getSendScope, OaNoticeSendScopeEnum.SPECIFIED.getScope()));
        for (OaNoticeDO notice : specifiedNotices) {
            // 创建者可见
            if (userId.equals(notice.getPublishUserId())) {
                allNoticeIds.add(notice.getId());
                continue;
            }
            // 被指定用户可见
            Long count = oaNoticeUserMapper.selectCount(
                    new cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX<OaNoticeUserDO>()
                            .eq(OaNoticeUserDO::getNoticeId, notice.getId())
                            .eq(OaNoticeUserDO::getUserId, userId));
            if (count > 0) {
                allNoticeIds.add(notice.getId());
            }
        }
 
        return allNoticeIds;
    }
 
    /**
     * 标记已读
     */
    private void markAsRead(Long noticeId, Long userId) {
        OaNoticeReadDO existing = oaNoticeReadMapper.selectByNoticeIdAndUserId(noticeId, userId);
        if (existing == null) {
            OaNoticeReadDO readRecord = new OaNoticeReadDO();
            readRecord.setNoticeId(noticeId);
            readRecord.setUserId(userId);
            readRecord.setReadTime(LocalDateTime.now());
            oaNoticeReadMapper.insert(readRecord);
        }
    }
 
    /**
     * 保存指定人关联
     */
    private void saveNoticeUsers(Long noticeId, List<Long> userIds) {
        List<OaNoticeUserDO> userList = userIds.stream().map(uid -> {
            OaNoticeUserDO user = new OaNoticeUserDO();
            user.setNoticeId(noticeId);
            user.setUserId(uid);
            return user;
        }).collect(Collectors.toList());
        oaNoticeUserMapper.insertBatch(userList);
    }
 
    /**
     * 发送发布通知给目标用户
     */
    private void sendPublishNotify(OaNoticeDO notice) {
        Map<String, Object> templateParams = new HashMap<>();
        templateParams.put("title", notice.getTitle());
        templateParams.put("content", notice.getContent());
        templateParams.put("noticeId", notice.getId());
        List<Long> targetUserIds;
        if (OaNoticeSendScopeEnum.ALL.getScope().equals(notice.getSendScope())) {
            // 通知所有人:查询所有启用的管理员用户
            targetUserIds = adminUserService.getUserListByStatus(CommonStatusEnum.ENABLE.getStatus())
                    .stream().map(cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO::getId)
                    .collect(Collectors.toList());
        } else {
            // 指定人
            targetUserIds = oaNoticeUserMapper.selectListByNoticeId(notice.getId()).stream()
                    .map(OaNoticeUserDO::getUserId)
                    .collect(Collectors.toList());
        }
        for (Long userId : targetUserIds) {
            try {
                notifySendService.sendSingleNotifyToAdmin(userId, "oa-notice-publish", templateParams);
            } catch (Exception e) {
                log.warn("发送通知公告[{}]给用户[{}]失败", notice.getId(), userId, e);
            }
        }
    }
 
    private OaNoticeDO validateNoticeExists(Long id) {
        OaNoticeDO notice = oaNoticeMapper.selectById(id);
        if (notice == null) {
            throw exception(OA_NOTICE_NOT_EXISTS);
        }
        return notice;
    }
 
}