feat: 添加任务发布到大厅时的钉钉群机器人通知

问题:
- 任务审核通过并发布到大厅时,没有触发钉钉群机器人通知
- 设计师无法第一时间知道有新任务可接单

修复内容:
1. TaskApprovalService.approveReceivingLevel()
   - 接单部门负责人审核通过时
   - 如果未指定设计师(发布到大厅)
   - 自动发送钉钉群机器人消息
   - 包含任务标题、编号、积分、品牌等信息

2. TaskItemService.approveTaskGroup()
   - 子任务组审核通过时
   - 如果未指定设计师(发布到大厅)
   - 自动发送钉钉群机器人消息
   - 包含主任务标题、子任务组信息、任务列表

3. 通知内容:
   - 标题:🎯 新任务发布 / 🎯 新子任务组发布
   - 详细信息:任务编号、积分、品牌、类目、平台等
   - 行动提示:💡 赶快去任务大厅抢单吧!

4. 错误处理:
   - 通知发送失败不影响主流程
   - 记录错误日志便于排查

影响范围:
- 每次任务发布到大厅时,接单部门群会收到通知
- 提高设计师接单效率
- 通知发送失败不会影响任务正常流转
This commit is contained in:
Your Name 2026-01-03 11:35:36 +08:00
parent 371cfd5b2a
commit fdda2e5878
4 changed files with 119 additions and 5 deletions

View File

@ -41,6 +41,7 @@ public class TaskApprovalService {
private final TaskService taskService;
private final ConfigService configService;
private final ObjectMapper objectMapper;
private final DingTalkService dingTalkService;
/**
* 需求部门负责人审核通过
@ -258,11 +259,36 @@ public class TaskApprovalService {
// 如果指定了接收人,发送通知
if (assignedReceiverId != null) {
// TODO: 通知指定的设计师
log.info("任务【{}】已指定给设计师", task.getTitle());
} else {
// TODO: 通知任务大厅(所有接单部门成员)
log.info("任务【{}】已发布到任务大厅", task.getTitle());
// 任务发布到大厅,发送钉钉群机器人通知
try {
String title = "🎯 新任务发布";
StringBuilder content = new StringBuilder();
content.append("**任务标题:**").append(task.getTitle()).append("\n\n");
content.append("**任务编号:**").append(task.getTaskNo()).append("\n\n");
content.append("**积分:**").append(task.getScore()).append(" 分\n\n");
if (task.getBrandName() != null) {
content.append("**品牌:**").append(task.getBrandName()).append("\n\n");
}
if (task.getCategoryName() != null) {
content.append("**类目:**").append(task.getCategoryName()).append("\n\n");
}
if (task.getPlatformName() != null) {
content.append("**平台:**").append(task.getPlatformName()).append("\n\n");
}
content.append("**状态:**待接单\n\n");
content.append("---\n\n");
content.append("💡 赶快去任务大厅抢单吧!");
dingTalkService.sendRobotMessage(title, content.toString());
log.info("任务【{}】已发布到任务大厅,已发送钉钉群通知", task.getTitle());
} catch (Exception e) {
log.error("发送钉钉群通知失败:taskId={}", taskId, e);
// 通知发送失败不影响主流程
}
}
log.info("接单部门负责人审核通过,任务ID:{},审核人:{},指定接收人:{}",

View File

@ -33,6 +33,7 @@ public class TaskItemService {
private final DepartmentMapper departmentMapper;
private final UserService userService;
private final NotificationService notificationService;
private final DingTalkService dingTalkService;
/**
* 获取可接单的子任务列表
@ -466,7 +467,31 @@ public class TaskItemService {
taskItemMapper.updateById(item);
}
log.info("第 {} 组 {} 个子任务已发布到任务大厅", groupNo, groupItems.size());
// 发送钉钉群机器人通知
try {
String title = "🎯 新子任务组发布";
StringBuilder content = new StringBuilder();
content.append("**主任务:**").append(mainTask.getTitle()).append("\n\n");
content.append("**子任务组:**第 ").append(groupNo).append(" 组\n\n");
content.append("**子任务数量:**").append(groupItems.size()).append(" 个\n\n");
// 列出子任务类型
content.append("**任务类型:**\n\n");
for (TaskItem item : groupItems) {
content.append("- ").append(item.getItemNo())
.append("(积分:").append(item.getTotalScore()).append(")\n\n");
}
content.append("**状态:**待接单\n\n");
content.append("---\n\n");
content.append("💡 赶快去任务大厅抢单吧!");
dingTalkService.sendRobotMessage(title, content.toString());
log.info("第 {} 组 {} 个子任务已发布到任务大厅,已发送钉钉群通知", groupNo, groupItems.size());
} catch (Exception e) {
log.error("发送钉钉群通知失败:taskId={}, groupNo={}", taskId, groupNo, e);
// 通知发送失败不影响主流程
}
}
}

View File

@ -56,6 +56,14 @@ export interface Task {
platformName?: string
publisherName?: string
publisherDeptName?: string
// 子任务统计(流水线任务)
subTaskTotal?: number
subTaskCompleted?: number
subTaskInProgress?: number
subTaskPending?: number
subTasks?: TaskItem[]
// 标记字段(前端使用)
isSubTask?: boolean
}
// 任务子项(流水线任务)

View File

@ -1479,7 +1479,20 @@
<span class="icon">
<Icon name="user" size="sm" color="#31f08b" />
</span>
<span>接单人: {{ task.receiverName || '--' }}</span>
<span>处理人: {{ task.receiverName || '待接单' }}</span>
</div>
<!-- 子任务进度(流水线任务) -->
<div v-if="task.isPipeline === 1 && task.subTaskTotal" class="detail-item subtask-progress">
<span class="icon">
<Icon name="layers" size="sm" color="#31f08b" />
</span>
<span class="subtask-stats">
子任务:
<span class="stat completed">已完成 {{ task.subTaskCompleted || 0 }}</span>
<span class="stat in-progress">进行中 {{ task.subTaskInProgress || 0 }}</span>
<span class="stat pending">待接单 {{ task.subTaskPending || 0 }}</span>
<span class="stat total">/ 共 {{ task.subTaskTotal }}</span>
</span>
</div>
<div v-if="task.brandName" class="detail-item">
<span class="icon">
@ -4072,6 +4085,48 @@ onUnmounted(() => {
text-overflow: clip;
}
}
// 子任务进度样式
&.subtask-progress {
grid-column: 1 / -1;
.subtask-stats {
display: flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
white-space: normal;
overflow: visible;
.stat {
padding: 2px 8px;
border-radius: 4px;
font-size: 12px;
font-weight: 500;
white-space: nowrap;
&.completed {
background: rgba(82, 196, 26, 0.1);
color: #52c41a;
}
&.in-progress {
background: rgba(24, 144, 255, 0.1);
color: #1890ff;
}
&.pending {
background: rgba(250, 173, 20, 0.1);
color: #faad14;
}
&.total {
color: #999;
padding: 0;
}
}
}
}
}
// 任务操作