qiangdanxitong/backend/src/main/java/com/designhub/service/TaskStatusNotificationService.java
Your Name 7bb3c953ef feat: 实现任务排队解锁机制
- 新增任务排队解锁功能,确保先发布的任务优先被处理
- 添加系统设置中的任务排队配置(启用开关、每日解锁数、补充解锁数)
- 新增 TaskUnlockStatus 实体和 Mapper
- 新增 TaskUnlockService 处理排队解锁逻辑
- 新增 TaskStatusNotificationService 发送钉钉通知
- 更新 TaskItemService 和 TaskItemController 支持排队状态
- 前端新增 TaskStatusBadge 组件显示排队/抢单状态
- 更新 TaskCard 和 TaskHall 支持排队状态展示
- 添加数据库迁移脚本 V15
2026-01-29 10:36:38 +08:00

268 lines
9.5 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.designhub.entity.*;
import com.designhub.mapper.UserMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashSet;
import java.util.Set;
/**
* 任务状态变更通知服务
* 负责在任务状态变化时通知需求人
*/
@Service
@Slf4j
@RequiredArgsConstructor
public class TaskStatusNotificationService {
private final NotificationService notificationService;
private final UserMapper userMapper;
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
/**
* 通知需求人:任务已解锁(排队中 → 抢单中)
*/
@Async
public void notifyTaskUnlocked(TaskItem item, Task mainTask) {
if (mainTask == null) {
log.warn("通知任务解锁失败:主任务为空");
return;
}
Set<Long> demandUserIds = getDemandUserIds(mainTask);
if (demandUserIds.isEmpty()) {
log.warn("通知任务解锁失败:没有找到需求人");
return;
}
String content = String.format(
"您发布的任务《%s》已完成排队,现已开放设计师抢单。\n" +
"任务编号:%s\n" +
"发布时间:%s\n" +
"设计师正在抢单中,请耐心等待...",
mainTask.getTitle(),
item.getItemNo(),
formatTime(mainTask.getCreateTime())
);
for (Long userId : demandUserIds) {
try {
Notification notification = new Notification();
notification.setReceiverId(userId);
notification.setNotificationType("task_status");
notification.setTitle("📢 任务已开放抢单");
notification.setContent(content);
notification.setRelatedId(item.getId());
notification.setRelatedType("task_item");
notification.setPriority(1); // 普通优先级
notification.setPushDingtalk(1); // 推送钉钉
notificationService.sendNotification(notification);
log.info("已通知需求人 {} 任务 {} 已解锁开放抢单", userId, item.getItemNo());
} catch (Exception e) {
log.error("通知需求人 {} 任务解锁失败: {}", userId, e.getMessage());
}
}
}
/**
* 通知需求人:任务已被接单(抢单中 → 进行中)
*/
@Async
public void notifyTaskGrabbed(TaskItem item, Task mainTask, User designer) {
if (mainTask == null || designer == null) {
log.warn("通知任务接单失败:主任务或设计师信息为空");
return;
}
Set<Long> demandUserIds = getDemandUserIds(mainTask);
if (demandUserIds.isEmpty()) {
return;
}
String content = String.format(
"您发布的任务《%s》已被设计师接单。\n" +
"任务编号:%s\n" +
"接单设计师:%s\n" +
"预计完成:%s\n" +
"如有问题可联系设计师沟通。",
mainTask.getTitle(),
item.getItemNo(),
designer.getRealName(),
item.getDeadline() != null ? formatTime(item.getDeadline()) : "待定"
);
for (Long userId : demandUserIds) {
// 不通知自己(如果设计师就是需求人)
if (userId.equals(designer.getId())) {
continue;
}
try {
Notification notification = new Notification();
notification.setReceiverId(userId);
notification.setNotificationType("task_status");
notification.setTitle("🎉 任务已被接单");
notification.setContent(content);
notification.setRelatedId(item.getId());
notification.setRelatedType("task_item");
notification.setPriority(1);
notification.setPushDingtalk(1);
notificationService.sendNotification(notification);
log.info("已通知需求人 {} 任务 {} 已被 {} 接单", userId, item.getItemNo(), designer.getRealName());
} catch (Exception e) {
log.error("通知需求人 {} 任务接单失败: {}", userId, e.getMessage());
}
}
}
/**
* 通知需求人:任务已完成
*/
@Async
public void notifyTaskCompleted(TaskItem item, Task mainTask, User designer) {
if (mainTask == null || designer == null) {
log.warn("通知任务完成失败:主任务或设计师信息为空");
return;
}
Set<Long> demandUserIds = getDemandUserIds(mainTask);
if (demandUserIds.isEmpty()) {
return;
}
String content = String.format(
"您发布的任务《%s》已完成。\n" +
"任务编号:%s\n" +
"完成设计师:%s\n" +
"完成时间:%s\n" +
"请及时查收并确认交付物。",
mainTask.getTitle(),
item.getItemNo(),
designer.getRealName(),
formatTime(item.getCompleteTime() != null ? item.getCompleteTime() : LocalDateTime.now())
);
for (Long userId : demandUserIds) {
try {
Notification notification = new Notification();
notification.setReceiverId(userId);
notification.setNotificationType("task_status");
notification.setTitle("✅ 任务已完成");
notification.setContent(content);
notification.setRelatedId(item.getId());
notification.setRelatedType("task_item");
notification.setPriority(2); // 重要
notification.setPushDingtalk(1);
notificationService.sendNotification(notification);
log.info("已通知需求人 {} 任务 {} 已完成", userId, item.getItemNo());
} catch (Exception e) {
log.error("通知需求人 {} 任务完成失败: {}", userId, e.getMessage());
}
}
}
/**
* 批量通知任务解锁
*/
@Async
public void batchNotifyTasksUnlocked(java.util.List<TaskItem> items, java.util.Map<Long, Task> taskMap) {
if (items == null || items.isEmpty()) {
return;
}
// 按主任务分组,避免同一任务的多个子任务重复通知
java.util.Map<Long, java.util.List<TaskItem>> groupedByTask = items.stream()
.collect(java.util.stream.Collectors.groupingBy(TaskItem::getTaskId));
for (java.util.Map.Entry<Long, java.util.List<TaskItem>> entry : groupedByTask.entrySet()) {
Long taskId = entry.getKey();
java.util.List<TaskItem> taskItems = entry.getValue();
Task mainTask = taskMap.get(taskId);
if (mainTask == null) {
continue;
}
Set<Long> demandUserIds = getDemandUserIds(mainTask);
if (demandUserIds.isEmpty()) {
continue;
}
// 构建通知内容
String itemNos = taskItems.stream()
.map(TaskItem::getItemNo)
.collect(java.util.stream.Collectors.joining(", "));
String content = String.format(
"您发布的任务《%s》有 %d 个子任务已完成排队,现已开放设计师抢单。\n" +
"子任务编号:%s\n" +
"设计师正在抢单中,请耐心等待...",
mainTask.getTitle(),
taskItems.size(),
itemNos
);
for (Long userId : demandUserIds) {
try {
Notification notification = new Notification();
notification.setReceiverId(userId);
notification.setNotificationType("task_status");
notification.setTitle("📢 任务已开放抢单");
notification.setContent(content);
notification.setRelatedId(taskId);
notification.setRelatedType("task");
notification.setPriority(1);
notification.setPushDingtalk(1);
notificationService.sendNotification(notification);
} catch (Exception e) {
log.error("批量通知任务解锁失败: {}", e.getMessage());
}
}
}
}
/**
* 获取任务的所有需求人(发布者 + 详情填写人 + 一级发起人)
*/
private Set<Long> getDemandUserIds(Task task) {
Set<Long> userIds = new HashSet<>();
// 发布者
if (task.getPublisherId() != null) {
userIds.add(task.getPublisherId());
}
// 详情填写人
if (task.getDetailCompleterId() != null) {
userIds.add(task.getDetailCompleterId());
}
// 一级发起人
if (task.getPrimaryPublisherId() != null) {
userIds.add(task.getPrimaryPublisherId());
}
return userIds;
}
/**
* 格式化时间
*/
private String formatTime(LocalDateTime time) {
if (time == null) {
return "未知";
}
return time.format(DATE_TIME_FORMATTER);
}
}