qiangdanxitong/backend/src/main/java/com/designhub/service/NotificationService.java
Your Name 80241a394d fix: 完善所有通知场景的钉钉推送
- NotificationService: sendScoreNotification/sendSystemNotification/batchSendNotification 添加钉钉推送
- TaskService: 补充任务提交/审核通过/审核驳回/任务取消的通知
- 确保所有个人通知都能推送到钉钉工作通知
2026-01-05 00:23:45 +08:00

358 lines
14 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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) {
batchSendNotification(receiverIds, title, content, notificationType, relatedType, relatedId, true);
}
/**
* 批量发送通知(可选钉钉推送)
*/
@Transactional(rollbackFor = Exception.class)
public void batchSendNotification(List<Long> receiverIds, String title, String content,
String notificationType, String relatedType, Long relatedId,
boolean pushDingtalk) {
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); // 普通
notification.setPushDingtalk(pushDingtalk ? 1 : 0);
notificationMapper.insert(notification);
// 如果开启了钉钉推送,异步推送
if (pushDingtalk) {
asyncPushToDingtalk(notification);
}
}
log.info("批量发送通知成功: count={}, pushDingtalk={}", receiverIds.size(), pushDingtalk);
}
/**
* 获取用户通知列表(分页)
*/
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()) {
// 尝试通过手机号自动获取并绑定
if (org.springframework.util.StringUtils.hasText(receiver.getPhone())) {
String dingUserId = dingTalkService.getUserIdByMobile(receiver.getPhone());
if (dingUserId != null) {
receiver.setDingUserId(dingUserId);
userMapper.updateById(receiver);
log.info("通过手机号自动绑定钉钉ID: userId={}, phone={}, dingUserId={}",
receiver.getId(), receiver.getPhone(), dingUserId);
} else {
log.info("用户未绑定钉钉ID且无法通过手机号获取,跳过推送: userId={}, phone={}",
receiver.getId(), receiver.getPhone());
return;
}
} else {
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");
notification.setPushDingtalk(1); // 积分通知推送钉钉
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); // 默认普通
notification.setPushDingtalk(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); // 普通
notification.setPushDingtalk(1); // 默认推送到钉钉
sendNotification(notification);
}
}