修复了提示信息不显示中文人名的问题
This commit is contained in:
parent
b5b50bf0cb
commit
55d8ad26c0
@ -63,22 +63,35 @@ user-mapping:
|
||||
|
||||
## API接口
|
||||
|
||||
### 测试禅道任务连接
|
||||
### 测试禅道项目状态(推荐)
|
||||
```
|
||||
GET /api/reminder/zentao/status/test/{groupId}
|
||||
```
|
||||
**功能**: 测试禅道连接,同时获取任务和BUG数据
|
||||
|
||||
### 手动触发禅道项目状态提醒(推荐)
|
||||
```
|
||||
POST /api/reminder/zentao/status/reminder/{groupId}
|
||||
```
|
||||
**功能**: 发送统一的项目状态提醒,包含任务和BUG
|
||||
|
||||
### 测试禅道任务连接(兼容性)
|
||||
```
|
||||
GET /api/reminder/zentao/test/{groupId}
|
||||
```
|
||||
|
||||
### 手动触发禅道任务提醒
|
||||
### 手动触发禅道任务提醒(兼容性)
|
||||
```
|
||||
POST /api/reminder/zentao/reminder/{groupId}
|
||||
```
|
||||
**注意**: 现在也会包含BUG信息
|
||||
|
||||
### 测试禅道BUG连接
|
||||
### 测试禅道BUG连接(单独测试)
|
||||
```
|
||||
GET /api/reminder/zentao/bugs/test/{groupId}
|
||||
```
|
||||
|
||||
### 手动触发禅道BUG提醒
|
||||
### 手动触发禅道BUG提醒(单独发送)
|
||||
```
|
||||
POST /api/reminder/zentao/bugs/reminder/{groupId}
|
||||
```
|
||||
@ -91,27 +104,38 @@ POST /api/reminder/groups/{groupId}/evening
|
||||
|
||||
## 消息格式
|
||||
|
||||
### 任务提醒消息格式
|
||||
### 项目状态提醒消息格式(推荐)
|
||||
|
||||
系统会发送包含以下信息的详细任务提醒:
|
||||
系统会发送包含以下信息的统一项目状态提醒:
|
||||
|
||||
- 📊 任务统计(总数、过期数、涉及人员)
|
||||
- 👥 按人员分组的任务列表
|
||||
- 🔴 过期任务标识
|
||||
- ⚪ 其他状态任务标识
|
||||
- 📋 任务优先级和截止日期
|
||||
- 🔗 禅道系统访问链接
|
||||
|
||||
### BUG提醒消息格式
|
||||
|
||||
系统会发送包含以下信息的详细BUG提醒:
|
||||
|
||||
- 📊 BUG统计(总数、过期数、涉及人员)
|
||||
- 👥 按人员分组的BUG列表
|
||||
- 🔴 过期BUG标识
|
||||
- 📊 项目概况(任务和BUG的总数、过期数)
|
||||
- 👥 按人员分组的工作项列表(任务+BUG)
|
||||
- 🔴 过期事项标识
|
||||
- ⚪ 未完成任务标识
|
||||
- 🐛 未解决BUG标识
|
||||
- 📋 BUG严重程度和截止日期
|
||||
- 🔗 禅道系统访问链接
|
||||
- 📋 任务优先级和BUG严重程度
|
||||
- 📅 截止日期信息
|
||||
|
||||
**示例消息**:
|
||||
```
|
||||
**禅道项目状态提醒**
|
||||
项目: [2025-06-08]一站式平台
|
||||
|
||||
📊 项目概况
|
||||
未完成任务: 2个,已过期: 2个
|
||||
未解决BUG: 1个
|
||||
|
||||
邓启辰 (3个事项)
|
||||
- 🔴 [任务238] 测试任务2 (2025-05-28)
|
||||
- 🔴 [任务236] 测试任务 (2025-05-28)
|
||||
- 🐛 [BUG911] 测试BUG [一般] (2025-05-29)
|
||||
|
||||
请及时登录禅道系统更新状态
|
||||
```
|
||||
|
||||
### 单独提醒消息格式(兼容性)
|
||||
|
||||
如果使用单独的任务或BUG提醒接口,消息格式保持原样。
|
||||
|
||||
## 使用步骤
|
||||
|
||||
|
||||
@ -339,4 +339,77 @@ public class TaskReminderController {
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试禅道项目状态(任务+BUG)
|
||||
*/
|
||||
@GetMapping("/zentao/status/test/{groupId}")
|
||||
public ResponseEntity<Map<String, Object>> testZentaoProjectStatus(@PathVariable String groupId) {
|
||||
Map<String, Object> response = new HashMap<>();
|
||||
|
||||
try {
|
||||
TaskReminderConfig.Group group = taskReminderConfig.getGroupById(groupId);
|
||||
if (group == null) {
|
||||
response.put("success", false);
|
||||
response.put("message", "群组不存在:" + groupId);
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
if (!"zentao".equals(group.getTaskSystem())) {
|
||||
response.put("success", false);
|
||||
response.put("message", "该群组不是禅道类型");
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
List<ZentaoTask> tasks = zentaoTaskReminderService.getTasksForTesting(group);
|
||||
List<ZentaoBug> bugs = zentaoTaskReminderService.getBugsForTesting(group);
|
||||
|
||||
response.put("success", true);
|
||||
response.put("message", "禅道项目状态API连接成功");
|
||||
response.put("taskCount", tasks.size());
|
||||
response.put("bugCount", bugs.size());
|
||||
response.put("tasks", tasks);
|
||||
response.put("bugs", bugs);
|
||||
} catch (Exception e) {
|
||||
logger.error("测试禅道项目状态失败: {}", groupId, e);
|
||||
response.put("success", false);
|
||||
response.put("message", "测试禅道项目状态失败:" + e.getMessage());
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 手动触发禅道项目状态提醒(任务+BUG统一通知)
|
||||
*/
|
||||
@PostMapping("/zentao/status/reminder/{groupId}")
|
||||
public ResponseEntity<Map<String, Object>> sendZentaoProjectStatusReminder(@PathVariable String groupId) {
|
||||
Map<String, Object> response = new HashMap<>();
|
||||
|
||||
try {
|
||||
TaskReminderConfig.Group group = taskReminderConfig.getGroupById(groupId);
|
||||
if (group == null) {
|
||||
response.put("success", false);
|
||||
response.put("message", "群组不存在:" + groupId);
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
if (!"zentao".equals(group.getTaskSystem())) {
|
||||
response.put("success", false);
|
||||
response.put("message", "该群组不是禅道类型");
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
// 使用现有的sendTaskReminder方法,它现在已经包含了任务和BUG
|
||||
zentaoTaskReminderService.sendTaskReminder(group);
|
||||
response.put("success", true);
|
||||
response.put("message", "禅道项目状态提醒已发送(包含任务和BUG)");
|
||||
} catch (Exception e) {
|
||||
logger.error("发送禅道项目状态提醒失败: {}", groupId, e);
|
||||
response.put("success", false);
|
||||
response.put("message", "发送禅道项目状态提醒失败:" + e.getMessage());
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,6 +13,7 @@ import org.springframework.stereotype.Service;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
@ -38,11 +39,11 @@ public class ZentaoTaskReminderService {
|
||||
private WechatWebhookService wechatWebhookService;
|
||||
|
||||
/**
|
||||
* 发送禅道任务提醒
|
||||
* 发送禅道项目状态提醒(包含任务和BUG)
|
||||
*/
|
||||
public void sendTaskReminder(TaskReminderConfig.Group group) {
|
||||
try {
|
||||
logger.info("Starting Zentao task reminder for group: {}", group.getId());
|
||||
logger.info("Starting Zentao project status reminder for group: {}", group.getId());
|
||||
|
||||
// 首先检查项目是否存在
|
||||
ProjectInfo projectInfo;
|
||||
@ -62,30 +63,28 @@ public class ZentaoTaskReminderService {
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取未完成任务
|
||||
// 获取未完成任务和未解决BUG
|
||||
List<ZentaoTask> incompleteTasks = zentaoApiService.getIncompleteTasks(group);
|
||||
if (incompleteTasks.isEmpty()) {
|
||||
logger.info("No incomplete tasks found for group: {}", group.getId());
|
||||
sendNoTasksMessage(group, projectInfo);
|
||||
List<ZentaoBug> unresolvedBugs = zentaoApiService.getUnresolvedBugs(group);
|
||||
|
||||
// 如果任务和BUG都为空,发送无事项消息
|
||||
if (incompleteTasks.isEmpty() && unresolvedBugs.isEmpty()) {
|
||||
logger.info("No incomplete tasks or unresolved bugs found for group: {}", group.getId());
|
||||
sendNoItemsMessage(group, projectInfo);
|
||||
return;
|
||||
}
|
||||
|
||||
// 按负责人分组
|
||||
Map<String, List<ZentaoTask>> tasksByAssignee = incompleteTasks.stream()
|
||||
.filter(task -> task.getAssignedTo() != null && !task.getAssignedTo().isEmpty())
|
||||
.collect(Collectors.groupingBy(ZentaoTask::getAssignedTo));
|
||||
|
||||
// 生成提醒消息并收集@人手机号
|
||||
// 生成统一的项目状态提醒消息
|
||||
List<String> mentionedMobiles = new ArrayList<>();
|
||||
String message = buildTaskReminderMessage(group, tasksByAssignee, incompleteTasks, projectInfo, mentionedMobiles);
|
||||
String message = buildProjectStatusMessage(group, incompleteTasks, unresolvedBugs, projectInfo, mentionedMobiles);
|
||||
|
||||
// 发送带@人的消息
|
||||
wechatWebhookService.sendMessageWithMentions(group.getWebhook().getUrl(), message, mentionedMobiles);
|
||||
|
||||
logger.info("Zentao task reminder sent successfully for group: {}", group.getId());
|
||||
logger.info("Zentao project status reminder sent successfully for group: {}", group.getId());
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("Error sending Zentao task reminder for group: {}", group.getId(), e);
|
||||
logger.error("Error sending Zentao project status reminder for group: {}", group.getId(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -142,7 +141,147 @@ public class ZentaoTaskReminderService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建任务提醒消息
|
||||
* 构建统一的项目状态提醒消息(包含任务和BUG)
|
||||
*/
|
||||
private String buildProjectStatusMessage(TaskReminderConfig.Group group,
|
||||
List<ZentaoTask> incompleteTasks,
|
||||
List<ZentaoBug> unresolvedBugs,
|
||||
ProjectInfo projectInfo,
|
||||
List<String> mentionedMobiles) {
|
||||
StringBuilder message = new StringBuilder();
|
||||
|
||||
// 消息头部
|
||||
message.append("**禅道项目状态提醒**\n");
|
||||
message.append("项目: ").append(projectInfo.getName()).append("\n\n");
|
||||
|
||||
// 统计信息
|
||||
long overdueTasks = incompleteTasks.stream().filter(ZentaoTask::isOverdue).count();
|
||||
long overdueBugs = unresolvedBugs.stream().filter(ZentaoBug::isOverdue).count();
|
||||
|
||||
message.append("📊 **项目概况**\n");
|
||||
message.append("未完成任务: ").append(incompleteTasks.size()).append("个");
|
||||
if (overdueTasks > 0) {
|
||||
message.append(",已过期: ").append(overdueTasks).append("个");
|
||||
}
|
||||
message.append("\n");
|
||||
|
||||
message.append("未解决BUG: ").append(unresolvedBugs.size()).append("个");
|
||||
if (overdueBugs > 0) {
|
||||
message.append(",已过期: ").append(overdueBugs).append("个");
|
||||
}
|
||||
message.append("\n\n");
|
||||
|
||||
// 按负责人合并任务和BUG
|
||||
Map<String, ProjectItems> itemsByAssignee = mergeTasksAndBugs(incompleteTasks, unresolvedBugs);
|
||||
|
||||
// 生成每个人的工作项详情
|
||||
for (Map.Entry<String, ProjectItems> entry : itemsByAssignee.entrySet()) {
|
||||
String assignedTo = entry.getKey();
|
||||
ProjectItems items = entry.getValue();
|
||||
|
||||
// 用用户名匹配手机号
|
||||
String phone = userMappingService.getPhoneByRealName(group, assignedTo);
|
||||
if (phone != null) {
|
||||
mentionedMobiles.add(phone);
|
||||
}
|
||||
|
||||
// 显示真实姓名
|
||||
String displayName = getDisplayName(items, assignedTo);
|
||||
int totalItems = items.tasks.size() + items.bugs.size();
|
||||
message.append(displayName).append(" (").append(totalItems).append("个事项)\n");
|
||||
|
||||
// 显示任务
|
||||
for (ZentaoTask task : items.tasks) {
|
||||
String statusIcon = task.isOverdue() ? "🔴" : "⚪";
|
||||
message.append("- ").append(statusIcon).append(" [任务").append(task.getId()).append("] ")
|
||||
.append(task.getName());
|
||||
if (task.getDeadline() != null && !task.getDeadline().isEmpty() &&
|
||||
!"0000-00-00".equals(task.getDeadline())) {
|
||||
message.append(" (").append(task.getDeadline()).append(")");
|
||||
}
|
||||
message.append("\n");
|
||||
}
|
||||
|
||||
// 显示BUG
|
||||
for (ZentaoBug bug : items.bugs) {
|
||||
String statusIcon = bug.isOverdue() ? "🔴" : "🐛";
|
||||
message.append("- ").append(statusIcon).append(" [BUG").append(bug.getId()).append("] ")
|
||||
.append(bug.getTitle());
|
||||
if (bug.getSeverity() != null && !bug.getSeverity().isEmpty()) {
|
||||
message.append(" [").append(bug.getSeverityDesc()).append("]");
|
||||
}
|
||||
if (bug.getDeadline() != null && !bug.getDeadline().isEmpty() &&
|
||||
!"0000-00-00".equals(bug.getDeadline())) {
|
||||
message.append(" (").append(bug.getDeadline()).append(")");
|
||||
}
|
||||
message.append("\n");
|
||||
}
|
||||
message.append("\n");
|
||||
}
|
||||
|
||||
// 提示信息
|
||||
message.append("请及时登录禅道系统更新状态");
|
||||
|
||||
return message.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并任务和BUG按负责人分组
|
||||
*/
|
||||
private Map<String, ProjectItems> mergeTasksAndBugs(List<ZentaoTask> tasks, List<ZentaoBug> bugs) {
|
||||
Map<String, ProjectItems> result = new HashMap<>();
|
||||
|
||||
// 添加任务
|
||||
for (ZentaoTask task : tasks) {
|
||||
if (task.getAssignedTo() != null && !task.getAssignedTo().isEmpty()) {
|
||||
result.computeIfAbsent(task.getAssignedTo(), k -> new ProjectItems()).tasks.add(task);
|
||||
}
|
||||
}
|
||||
|
||||
// 添加BUG
|
||||
for (ZentaoBug bug : bugs) {
|
||||
if (bug.getAssignedTo() != null && !bug.getAssignedTo().isEmpty()) {
|
||||
result.computeIfAbsent(bug.getAssignedTo(), k -> new ProjectItems()).bugs.add(bug);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取显示名称(优先使用真实姓名)
|
||||
*/
|
||||
private String getDisplayName(ProjectItems items, String assignedTo) {
|
||||
// 从任务中获取真实姓名
|
||||
if (!items.tasks.isEmpty()) {
|
||||
String realName = items.tasks.get(0).getAssignedToRealName();
|
||||
if (realName != null && !realName.isEmpty()) {
|
||||
return realName;
|
||||
}
|
||||
}
|
||||
|
||||
// 从BUG中获取真实姓名
|
||||
if (!items.bugs.isEmpty()) {
|
||||
String realName = items.bugs.get(0).getAssignedToRealName();
|
||||
if (realName != null && !realName.isEmpty()) {
|
||||
return realName;
|
||||
}
|
||||
}
|
||||
|
||||
// 默认返回用户名
|
||||
return assignedTo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 项目工作项容器类
|
||||
*/
|
||||
private static class ProjectItems {
|
||||
List<ZentaoTask> tasks = new ArrayList<>();
|
||||
List<ZentaoBug> bugs = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建任务提醒消息(保留原方法以兼容性)
|
||||
*/
|
||||
private String buildTaskReminderMessage(TaskReminderConfig.Group group,
|
||||
Map<String, List<ZentaoTask>> tasksByAssignee,
|
||||
@ -287,7 +426,23 @@ public class ZentaoTaskReminderService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送无任务消息
|
||||
* 发送无事项消息(既没有任务也没有BUG)
|
||||
*/
|
||||
private void sendNoItemsMessage(TaskReminderConfig.Group group, ProjectInfo projectInfo) {
|
||||
StringBuilder message = new StringBuilder();
|
||||
message.append("**禅道项目状态提醒**\n");
|
||||
message.append("项目: ").append(projectInfo.getName()).append("\n\n");
|
||||
message.append("🎉 恭喜!当前项目没有未完成的任务和未解决的BUG。");
|
||||
|
||||
try {
|
||||
wechatWebhookService.sendMessage(group.getWebhook().getUrl(), message.toString());
|
||||
} catch (Exception e) {
|
||||
logger.error("Error sending no items message for group: {}", group.getId(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送无任务消息(保留原方法以兼容性)
|
||||
*/
|
||||
private void sendNoTasksMessage(TaskReminderConfig.Group group, ProjectInfo projectInfo) {
|
||||
StringBuilder message = new StringBuilder();
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
# 禅道BUG提醒功能测试指南
|
||||
# 禅道统一项目状态提醒功能测试指南
|
||||
|
||||
## 新增功能概述
|
||||
## 功能概述
|
||||
|
||||
已成功为禅道任务提醒系统添加了BUG延期通知功能,现在系统支持:
|
||||
已成功实现禅道统一项目状态提醒功能,现在系统支持:
|
||||
|
||||
1. **任务延期通知** - 原有功能
|
||||
2. **BUG延期通知** - 新增功能
|
||||
1. **统一项目状态提醒** - 一个通知包含任务和BUG(推荐)
|
||||
2. **单独任务提醒** - 仅任务通知(兼容性)
|
||||
3. **单独BUG提醒** - 仅BUG通知(兼容性)
|
||||
|
||||
## 新增的API接口
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user