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 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 getUserNotifications(Long receiverId, Integer pageNum, Integer pageSize, Boolean unreadOnly) { Page page = new Page<>(pageNum, pageSize); LambdaQueryWrapper 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() .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); } }