- NotificationService添加DingTalkService和UserMapper依赖 - 实现asyncPushToDingtalk方法,支持发送个人工作通知 - 自动检查用户是否绑定钉钉ID - 构建Markdown格式的通知内容 - 异步发送,不影响主流程性能
323 lines
12 KiB
Java
323 lines
12 KiB
Java
package com.designhub.service;
|
||
|
||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||
import com.designhub.entity.Notification;
|
||
import com.designhub.entity.User;
|
||
import com.designhub.mapper.NotificationMapper;
|
||
import com.designhub.mapper.UserMapper;
|
||
import lombok.RequiredArgsConstructor;
|
||
import lombok.extern.slf4j.Slf4j;
|
||
import org.springframework.beans.factory.annotation.Autowired;
|
||
import org.springframework.scheduling.annotation.Async;
|
||
import org.springframework.stereotype.Service;
|
||
import org.springframework.transaction.annotation.Transactional;
|
||
|
||
import java.time.LocalDateTime;
|
||
import java.util.Collections;
|
||
import java.util.List;
|
||
|
||
/**
|
||
* 通知消息Service
|
||
*/
|
||
@Slf4j
|
||
@Service
|
||
@RequiredArgsConstructor
|
||
public class NotificationService {
|
||
|
||
private final NotificationMapper notificationMapper;
|
||
private final UserMapper userMapper;
|
||
|
||
@Autowired(required = false)
|
||
private DingTalkService dingTalkService;
|
||
|
||
/**
|
||
* 将优先级字符串转换为整数
|
||
* low -> 0, normal -> 1, high -> 2, urgent -> 3
|
||
*/
|
||
private Integer convertPriorityToInt(String priority) {
|
||
if (priority == null) return 1; // 默认普通
|
||
return switch (priority.toLowerCase()) {
|
||
case "low" -> 0;
|
||
case "normal" -> 1;
|
||
case "high" -> 2;
|
||
case "urgent" -> 3;
|
||
default -> 1; // 默认普通
|
||
};
|
||
}
|
||
|
||
/**
|
||
* 发送通知
|
||
*/
|
||
@Transactional(rollbackFor = Exception.class)
|
||
public Notification sendNotification(Notification notification) {
|
||
if (notification.getIsRead() == null) {
|
||
notification.setIsRead(0);
|
||
}
|
||
if (notification.getPriority() == null) {
|
||
notification.setPriority(1); // 默认普通
|
||
}
|
||
if (notification.getPushDingtalk() == null) {
|
||
notification.setPushDingtalk(0);
|
||
}
|
||
|
||
notificationMapper.insert(notification);
|
||
log.info("发送通知成功: receiverId={}, title={}", notification.getReceiverId(), notification.getTitle());
|
||
|
||
// TODO: 如果开启了钉钉推送,这里可以异步推送
|
||
if (notification.getPushDingtalk() == 1) {
|
||
asyncPushToDingtalk(notification);
|
||
}
|
||
|
||
return notification;
|
||
}
|
||
|
||
/**
|
||
* 批量发送通知
|
||
*/
|
||
@Transactional(rollbackFor = Exception.class)
|
||
public void batchSendNotification(List<Long> receiverIds, String title, String content,
|
||
String notificationType, String relatedType, Long relatedId) {
|
||
for (Long receiverId : receiverIds) {
|
||
Notification notification = new Notification();
|
||
notification.setReceiverId(receiverId);
|
||
notification.setTitle(title);
|
||
notification.setContent(content);
|
||
notification.setNotificationType(notificationType);
|
||
notification.setRelatedType(relatedType);
|
||
notification.setRelatedId(relatedId);
|
||
notification.setIsRead(0);
|
||
notification.setPriority(1); // 普通
|
||
notificationMapper.insert(notification);
|
||
}
|
||
log.info("批量发送通知成功: count={}", receiverIds.size());
|
||
}
|
||
|
||
/**
|
||
* 获取用户通知列表(分页)
|
||
*/
|
||
public Page<Notification> getUserNotifications(Long receiverId, Integer pageNum, Integer pageSize, Boolean unreadOnly) {
|
||
Page<Notification> page = new Page<>(pageNum, pageSize);
|
||
LambdaQueryWrapper<Notification> queryWrapper = new LambdaQueryWrapper<>();
|
||
queryWrapper.eq(Notification::getReceiverId, receiverId);
|
||
|
||
if (unreadOnly != null && unreadOnly) {
|
||
queryWrapper.eq(Notification::getIsRead, 0);
|
||
}
|
||
|
||
queryWrapper.orderByDesc(Notification::getCreateTime);
|
||
return notificationMapper.selectPage(page, queryWrapper);
|
||
}
|
||
|
||
/**
|
||
* 标记为已读
|
||
*/
|
||
@Transactional(rollbackFor = Exception.class)
|
||
public boolean markAsRead(Long notificationId, Long receiverId) {
|
||
Notification notification = notificationMapper.selectById(notificationId);
|
||
if (notification != null && notification.getReceiverId().equals(receiverId)) {
|
||
notification.setIsRead(1);
|
||
notification.setReadTime(LocalDateTime.now());
|
||
notificationMapper.updateById(notification);
|
||
log.info("标记通知已读: id={}", notificationId);
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* 批量标记为已读
|
||
*/
|
||
@Transactional(rollbackFor = Exception.class)
|
||
public int markAllAsRead(Long receiverId) {
|
||
int count = notificationMapper.markAllAsRead(receiverId);
|
||
log.info("批量标记通知已读: receiverId={}, count={}", receiverId, count);
|
||
return count;
|
||
}
|
||
|
||
/**
|
||
* 获取未读数量
|
||
*/
|
||
public long getUnreadCount(Long receiverId) {
|
||
return notificationMapper.selectCount(
|
||
new LambdaQueryWrapper<Notification>()
|
||
.eq(Notification::getReceiverId, receiverId)
|
||
.eq(Notification::getIsRead, 0)
|
||
);
|
||
}
|
||
|
||
/**
|
||
* 删除通知
|
||
*/
|
||
@Transactional(rollbackFor = Exception.class)
|
||
public boolean deleteNotification(Long notificationId, Long receiverId) {
|
||
Notification notification = notificationMapper.selectById(notificationId);
|
||
if (notification != null && notification.getReceiverId().equals(receiverId)) {
|
||
notificationMapper.deleteById(notificationId);
|
||
log.info("删除通知: id={}", notificationId);
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* 异步推送到钉钉
|
||
*/
|
||
@Async
|
||
private void asyncPushToDingtalk(Notification notification) {
|
||
try {
|
||
// 检查钉钉服务是否可用
|
||
if (dingTalkService == null) {
|
||
log.warn("钉钉服务未启用,跳过推送");
|
||
return;
|
||
}
|
||
|
||
// 检查是否启用了钉钉通知功能
|
||
if (!dingTalkService.isFeatureEnabled("notification")) {
|
||
log.info("钉钉通知功能未启用,跳过推送: notificationId={}", notification.getId());
|
||
return;
|
||
}
|
||
|
||
// 获取接收者信息
|
||
User receiver = userMapper.selectById(notification.getReceiverId());
|
||
if (receiver == null) {
|
||
log.warn("接收者不存在,跳过钉钉推送: receiverId={}", notification.getReceiverId());
|
||
return;
|
||
}
|
||
|
||
// 检查用户是否绑定了钉钉ID
|
||
if (receiver.getDingUserId() == null || receiver.getDingUserId().isEmpty()) {
|
||
log.info("用户未绑定钉钉ID,跳过推送: userId={}, username={}",
|
||
receiver.getId(), receiver.getUsername());
|
||
return;
|
||
}
|
||
|
||
// 构建钉钉消息内容
|
||
String title = notification.getTitle();
|
||
String content = buildDingTalkContent(notification);
|
||
|
||
// 发送工作通知(个人消息)
|
||
boolean success = dingTalkService.sendWorkNotification(
|
||
Collections.singletonList(receiver.getDingUserId()),
|
||
title,
|
||
content
|
||
);
|
||
|
||
if (success) {
|
||
log.info("钉钉个人通知发送成功: notificationId={}, receiverId={}, dingUserId={}",
|
||
notification.getId(), receiver.getId(), receiver.getDingUserId());
|
||
} else {
|
||
log.warn("钉钉个人通知发送失败: notificationId={}, receiverId={}",
|
||
notification.getId(), receiver.getId());
|
||
}
|
||
|
||
} catch (Exception e) {
|
||
log.error("推送钉钉通知异常: notificationId={}", notification.getId(), e);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 构建钉钉消息内容(Markdown格式)
|
||
*/
|
||
private String buildDingTalkContent(Notification notification) {
|
||
StringBuilder content = new StringBuilder();
|
||
content.append("### ").append(notification.getTitle()).append("\n\n");
|
||
content.append(notification.getContent()).append("\n\n");
|
||
|
||
// 根据通知类型添加不同的提示
|
||
if ("task".equals(notification.getNotificationType())) {
|
||
content.append("> 📋 任务相关通知\n\n");
|
||
} else if ("review".equals(notification.getNotificationType())) {
|
||
content.append("> ⭐ 评审相关通知\n\n");
|
||
} else if ("score".equals(notification.getNotificationType())) {
|
||
content.append("> 💰 积分相关通知\n\n");
|
||
} else if ("system".equals(notification.getNotificationType())) {
|
||
content.append("> 🔔 系统通知\n\n");
|
||
}
|
||
|
||
content.append("---\n\n");
|
||
content.append("请登录系统查看详情");
|
||
|
||
return content.toString();
|
||
}
|
||
|
||
// ==================== 便捷方法 ====================
|
||
|
||
/**
|
||
* 发送任务通知
|
||
*/
|
||
public void sendTaskNotification(Long receiverId, Long taskId, String title, String content) {
|
||
Notification notification = new Notification();
|
||
notification.setReceiverId(receiverId);
|
||
notification.setNotificationType("task");
|
||
notification.setRelatedType("task");
|
||
notification.setRelatedId(taskId);
|
||
notification.setTitle(title);
|
||
notification.setContent(content);
|
||
notification.setLinkUrl("/tasks/" + taskId);
|
||
notification.setPushDingtalk(1); // 任务通知默认推送钉钉
|
||
sendNotification(notification);
|
||
}
|
||
|
||
/**
|
||
* 发送积分通知
|
||
*/
|
||
public void sendScoreNotification(Long receiverId, String title, String content) {
|
||
Notification notification = new Notification();
|
||
notification.setReceiverId(receiverId);
|
||
notification.setNotificationType("score");
|
||
notification.setRelatedType("score");
|
||
notification.setTitle(title);
|
||
notification.setContent(content);
|
||
notification.setLinkUrl("/my-score");
|
||
sendNotification(notification);
|
||
}
|
||
|
||
/**
|
||
* 发送评审通知
|
||
*/
|
||
public void sendReviewNotification(Long receiverId, Long taskId, String title, String content) {
|
||
Notification notification = new Notification();
|
||
notification.setReceiverId(receiverId);
|
||
notification.setNotificationType("review");
|
||
notification.setRelatedType("task");
|
||
notification.setRelatedId(taskId);
|
||
notification.setTitle(title);
|
||
notification.setContent(content);
|
||
notification.setLinkUrl("/tasks/" + taskId);
|
||
notification.setPriority(2); // 高
|
||
notification.setPushDingtalk(1);
|
||
sendNotification(notification);
|
||
}
|
||
|
||
/**
|
||
* 发送系统通知
|
||
*/
|
||
public void sendSystemNotification(Long receiverId, String title, String content, String priority) {
|
||
Notification notification = new Notification();
|
||
notification.setReceiverId(receiverId);
|
||
notification.setNotificationType("system");
|
||
notification.setRelatedType("system");
|
||
notification.setTitle(title);
|
||
notification.setContent(content);
|
||
notification.setPriority(priority != null ? convertPriorityToInt(priority) : 1); // 默认普通
|
||
sendNotification(notification);
|
||
}
|
||
|
||
/**
|
||
* 发送通用通知(便捷方法)
|
||
*/
|
||
public void sendNotification(Long receiverId, String title, String content, String relatedType, Long relatedId) {
|
||
Notification notification = new Notification();
|
||
notification.setReceiverId(receiverId);
|
||
notification.setNotificationType(relatedType);
|
||
notification.setRelatedType(relatedType);
|
||
notification.setRelatedId(relatedId);
|
||
notification.setTitle(title);
|
||
notification.setContent(content);
|
||
notification.setPriority(1); // 普通
|
||
sendNotification(notification);
|
||
}
|
||
}
|
||
|