diff --git a/src/main/java/com/zeodao/reminder/config/TaskReminderConfig.java b/src/main/java/com/zeodao/reminder/config/TaskReminderConfig.java index e7b5a37..7c775c4 100644 --- a/src/main/java/com/zeodao/reminder/config/TaskReminderConfig.java +++ b/src/main/java/com/zeodao/reminder/config/TaskReminderConfig.java @@ -157,6 +157,7 @@ public class TaskReminderConfig { public static class Schedule { private String time; + private String type = "text"; // 默认为文本类型 private String message; public String getTime() { @@ -167,6 +168,14 @@ public class TaskReminderConfig { this.time = time; } + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + public String getMessage() { return message; } diff --git a/src/main/java/com/zeodao/reminder/controller/TaskReminderController.java b/src/main/java/com/zeodao/reminder/controller/TaskReminderController.java index 10dedf9..14381d1 100644 --- a/src/main/java/com/zeodao/reminder/controller/TaskReminderController.java +++ b/src/main/java/com/zeodao/reminder/controller/TaskReminderController.java @@ -161,6 +161,26 @@ public class TaskReminderController { return ResponseEntity.ok(response); } + /** + * 手动触发逾期任务提醒 + */ + @PostMapping("/overdue-reminder") + public ResponseEntity> triggerOverdueReminder() { + Map response = new HashMap<>(); + + try { + taskReminderService.sendAllOverdueReminders(); + response.put("success", true); + response.put("message", "所有群组逾期任务提醒已触发"); + } catch (Exception e) { + logger.error("触发逾期任务提醒失败", e); + response.put("success", false); + response.put("message", "触发逾期任务提醒失败:" + e.getMessage()); + } + + return ResponseEntity.ok(response); + } + /** * 手动触发指定群组的提醒 */ diff --git a/src/main/java/com/zeodao/reminder/enums/ScheduleType.java b/src/main/java/com/zeodao/reminder/enums/ScheduleType.java new file mode 100644 index 0000000..1676108 --- /dev/null +++ b/src/main/java/com/zeodao/reminder/enums/ScheduleType.java @@ -0,0 +1,67 @@ +package com.zeodao.reminder.enums; + +/** + * 提醒类型枚举 + * + * @author Zeodao + * @version 2.0.0 + */ +public enum ScheduleType { + + /** + * 早上提醒 + */ + MORNING("morning", "早上提醒"), + + /** + * 晚上提醒 + */ + EVENING("evening", "晚上提醒"), + + /** + * 逾期任务提醒 + */ + OVERDUE_REMINDER("overdue-reminder", "逾期任务提醒"); + + private final String code; + private final String description; + + ScheduleType(String code, String description) { + this.code = code; + this.description = description; + } + + public String getCode() { + return code; + } + + public String getDescription() { + return description; + } + + /** + * 根据代码获取枚举 + */ + public static ScheduleType fromCode(String code) { + for (ScheduleType type : values()) { + if (type.code.equals(code)) { + return type; + } + } + return null; + } + + /** + * 判断是否为文本提醒类型 + */ + public boolean isTextReminder() { + return this == MORNING || this == EVENING; + } + + /** + * 判断是否为逾期提醒类型 + */ + public boolean isOverdueReminder() { + return this == OVERDUE_REMINDER; + } +} diff --git a/src/main/java/com/zeodao/reminder/enums/TaskSystemType.java b/src/main/java/com/zeodao/reminder/enums/TaskSystemType.java new file mode 100644 index 0000000..1869e21 --- /dev/null +++ b/src/main/java/com/zeodao/reminder/enums/TaskSystemType.java @@ -0,0 +1,68 @@ +package com.zeodao.reminder.enums; + +/** + * 任务系统类型枚举 + * + * @author Zeodao + * @version 2.0.0 + */ +public enum TaskSystemType { + + /** + * 禅道 + */ + ZENTAO("zentao", "禅道"), + + /** + * 智能表格 + */ + SMARTSHEET("smartsheet", "智能表格"), + + /** + * Jira + */ + JIRA("jira", "Jira"), + + /** + * Trello + */ + TRELLO("trello", "Trello"), + + /** + * Asana + */ + ASANA("asana", "Asana"), + + /** + * Notion + */ + NOTION("notion", "Notion"); + + private final String code; + private final String description; + + TaskSystemType(String code, String description) { + this.code = code; + this.description = description; + } + + public String getCode() { + return code; + } + + public String getDescription() { + return description; + } + + /** + * 根据代码获取枚举 + */ + public static TaskSystemType fromCode(String code) { + for (TaskSystemType type : values()) { + if (type.code.equals(code)) { + return type; + } + } + return null; + } +} diff --git a/src/main/java/com/zeodao/reminder/service/TaskReminderService.java b/src/main/java/com/zeodao/reminder/service/TaskReminderService.java index 7ec48d7..b8adf14 100644 --- a/src/main/java/com/zeodao/reminder/service/TaskReminderService.java +++ b/src/main/java/com/zeodao/reminder/service/TaskReminderService.java @@ -1,6 +1,10 @@ package com.zeodao.reminder.service; import com.zeodao.reminder.config.TaskReminderConfig; +import com.zeodao.reminder.enums.ScheduleType; +import com.zeodao.reminder.enums.TaskSystemType; +import com.zeodao.reminder.strategy.ReminderHandler; +import com.zeodao.reminder.strategy.ReminderHandlerFactory; import com.zeodao.reminder.util.HolidayUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -32,7 +36,7 @@ public class TaskReminderService { private TaskReminderConfig taskReminderConfig; @Autowired - private ZentaoTaskReminderService zentaoTaskReminderService; + private ReminderHandlerFactory reminderHandlerFactory; /** * 发送指定群组和时间段的任务提醒 @@ -62,20 +66,27 @@ public class TaskReminderService { logger.info("开始发送任务提醒 - 群组: {}, 类型: {}", group.getName(), scheduleType); - // 根据任务系统类型选择不同的提醒方式 - if ("zentao".equals(group.getTaskSystem())) { - // 发送禅道任务提醒 - zentaoTaskReminderService.sendTaskReminder(group); - } else { - // 发送传统的文本提醒 - String message = wechatWebhookService.createTaskReminderMessage(groupId, schedule.getMessage(), scheduleType + "提醒"); - boolean success = wechatWebhookService.sendMarkdownMessage(groupId, message); + // 转换字符串类型为枚举类型 + ScheduleType scheduleTypeEnum = ScheduleType.fromCode(scheduleType); + TaskSystemType taskSystemTypeEnum = TaskSystemType.fromCode(group.getTaskSystem()); - if (success) { - logger.info("任务提醒发送成功 - 群组: {}, 类型: {}", group.getName(), scheduleType); - } else { - logger.error("任务提醒发送失败 - 群组: {}, 类型: {}", group.getName(), scheduleType); - } + if (scheduleTypeEnum == null) { + logger.error("无效的提醒类型: {}", scheduleType); + return; + } + + if (taskSystemTypeEnum == null) { + logger.error("无效的任务系统类型: {}", group.getTaskSystem()); + return; + } + + // 使用策略模式选择合适的处理器 + ReminderHandler handler = reminderHandlerFactory.getHandler(scheduleTypeEnum, taskSystemTypeEnum); + if (handler != null) { + handler.handleReminder(group, scheduleTypeEnum, schedule); + } else { + logger.error("未找到合适的提醒处理器 - 群组: {}, 类型: {}, 任务系统: {}", + group.getName(), scheduleTypeEnum.getDescription(), taskSystemTypeEnum.getDescription()); } } @@ -103,6 +114,18 @@ public class TaskReminderService { } } + /** + * 发送所有启用群组的逾期任务提醒 + */ + public void sendAllOverdueReminders() { + List enabledGroups = taskReminderConfig.getEnabledGroups(); + for (TaskReminderConfig.Group group : enabledGroups) { + if (group.getSchedules().containsKey("overdue-reminder")) { + sendReminder(group.getId(), "overdue-reminder"); + } + } + } + /** * 兼容旧版本的方法 */ diff --git a/src/main/java/com/zeodao/reminder/strategy/ReminderHandler.java b/src/main/java/com/zeodao/reminder/strategy/ReminderHandler.java new file mode 100644 index 0000000..1ace8ab --- /dev/null +++ b/src/main/java/com/zeodao/reminder/strategy/ReminderHandler.java @@ -0,0 +1,33 @@ +package com.zeodao.reminder.strategy; + +import com.zeodao.reminder.config.TaskReminderConfig; +import com.zeodao.reminder.enums.ScheduleType; +import com.zeodao.reminder.enums.TaskSystemType; + +/** + * 提醒处理器接口 + * 使用策略模式处理不同类型的提醒 + * + * @author Zeodao + * @version 2.0.0 + */ +public interface ReminderHandler { + + /** + * 判断是否支持处理指定的提醒类型 + * + * @param scheduleType 提醒类型 + * @param taskSystemType 任务系统类型 + * @return 是否支持 + */ + boolean supports(ScheduleType scheduleType, TaskSystemType taskSystemType); + + /** + * 处理提醒 + * + * @param group 群组配置 + * @param scheduleType 提醒类型 + * @param schedule 提醒配置 + */ + void handleReminder(TaskReminderConfig.Group group, ScheduleType scheduleType, TaskReminderConfig.Schedule schedule); +} diff --git a/src/main/java/com/zeodao/reminder/strategy/ReminderHandlerFactory.java b/src/main/java/com/zeodao/reminder/strategy/ReminderHandlerFactory.java new file mode 100644 index 0000000..6c47a91 --- /dev/null +++ b/src/main/java/com/zeodao/reminder/strategy/ReminderHandlerFactory.java @@ -0,0 +1,66 @@ +package com.zeodao.reminder.strategy; + +import com.zeodao.reminder.enums.ScheduleType; +import com.zeodao.reminder.enums.TaskSystemType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * 提醒处理器工厂 + * 根据提醒类型和任务系统选择合适的处理器 + * + * @author Zeodao + * @version 2.0.0 + */ +@Component +public class ReminderHandlerFactory { + + private static final Logger logger = LoggerFactory.getLogger(ReminderHandlerFactory.class); + + @Autowired + private List reminderHandlers; + + /** + * 获取合适的提醒处理器 + * + * @param scheduleType 提醒类型 + * @param taskSystemType 任务系统类型 + * @return 提醒处理器,如果没有找到则返回null + */ + public ReminderHandler getHandler(ScheduleType scheduleType, TaskSystemType taskSystemType) { + for (ReminderHandler handler : reminderHandlers) { + if (handler.supports(scheduleType, taskSystemType)) { + logger.debug("找到处理器: {} 用于处理 scheduleType={}, taskSystemType={}", + handler.getClass().getSimpleName(), scheduleType.getDescription(), taskSystemType.getDescription()); + return handler; + } + } + + logger.warn("未找到合适的处理器 - scheduleType: {}, taskSystemType: {}", + scheduleType.getDescription(), taskSystemType.getDescription()); + return null; + } + + /** + * 获取合适的提醒处理器(字符串参数版本,用于兼容) + * + * @param scheduleTypeCode 提醒类型代码 + * @param taskSystemCode 任务系统类型代码 + * @return 提醒处理器,如果没有找到则返回null + */ + public ReminderHandler getHandler(String scheduleTypeCode, String taskSystemCode) { + ScheduleType scheduleType = ScheduleType.fromCode(scheduleTypeCode); + TaskSystemType taskSystemType = TaskSystemType.fromCode(taskSystemCode); + + if (scheduleType == null || taskSystemType == null) { + logger.warn("无效的类型代码 - scheduleTypeCode: {}, taskSystemCode: {}", scheduleTypeCode, taskSystemCode); + return null; + } + + return getHandler(scheduleType, taskSystemType); + } +} diff --git a/src/main/java/com/zeodao/reminder/strategy/TextReminderHandler.java b/src/main/java/com/zeodao/reminder/strategy/TextReminderHandler.java new file mode 100644 index 0000000..6916b73 --- /dev/null +++ b/src/main/java/com/zeodao/reminder/strategy/TextReminderHandler.java @@ -0,0 +1,53 @@ +package com.zeodao.reminder.strategy; + +import com.zeodao.reminder.config.TaskReminderConfig; +import com.zeodao.reminder.enums.ScheduleType; +import com.zeodao.reminder.enums.TaskSystemType; +import com.zeodao.reminder.service.WechatWebhookService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * 文本提醒处理器 + * 处理 morning 和 evening 类型的文本提醒 + * + * @author Zeodao + * @version 2.0.0 + */ +@Component +public class TextReminderHandler implements ReminderHandler { + + private static final Logger logger = LoggerFactory.getLogger(TextReminderHandler.class); + + @Autowired + private WechatWebhookService wechatWebhookService; + + @Override + public boolean supports(ScheduleType scheduleType, TaskSystemType taskSystemType) { + // 支持所有任务系统的文本提醒类型 + return scheduleType.isTextReminder(); + } + + @Override + public void handleReminder(TaskReminderConfig.Group group, ScheduleType scheduleType, TaskReminderConfig.Schedule schedule) { + logger.info("处理文本提醒 - 群组: {}, 类型: {}", group.getName(), scheduleType.getDescription()); + + // 生成带格式的提醒消息 + String message = wechatWebhookService.createTaskReminderMessage( + group.getId(), + schedule.getMessage(), + scheduleType.getDescription() + ); + + // 发送消息 + boolean success = wechatWebhookService.sendMarkdownMessage(group.getId(), message); + + if (success) { + logger.info("文本提醒发送成功 - 群组: {}, 类型: {}", group.getName(), scheduleType.getDescription()); + } else { + logger.error("文本提醒发送失败 - 群组: {}, 类型: {}", group.getName(), scheduleType.getDescription()); + } + } +} diff --git a/src/main/java/com/zeodao/reminder/strategy/ZentaoOverdueReminderHandler.java b/src/main/java/com/zeodao/reminder/strategy/ZentaoOverdueReminderHandler.java new file mode 100644 index 0000000..cc9d33d --- /dev/null +++ b/src/main/java/com/zeodao/reminder/strategy/ZentaoOverdueReminderHandler.java @@ -0,0 +1,45 @@ +package com.zeodao.reminder.strategy; + +import com.zeodao.reminder.config.TaskReminderConfig; +import com.zeodao.reminder.enums.ScheduleType; +import com.zeodao.reminder.enums.TaskSystemType; +import com.zeodao.reminder.service.ZentaoTaskReminderService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * 禅道逾期任务提醒处理器 + * 处理禅道系统的 overdue-reminder 类型提醒 + * + * @author Zeodao + * @version 2.0.0 + */ +@Component +public class ZentaoOverdueReminderHandler implements ReminderHandler { + + private static final Logger logger = LoggerFactory.getLogger(ZentaoOverdueReminderHandler.class); + + @Autowired + private ZentaoTaskReminderService zentaoTaskReminderService; + + @Override + public boolean supports(ScheduleType scheduleType, TaskSystemType taskSystemType) { + // 只支持禅道系统的逾期提醒 + return scheduleType.isOverdueReminder() && taskSystemType == TaskSystemType.ZENTAO; + } + + @Override + public void handleReminder(TaskReminderConfig.Group group, ScheduleType scheduleType, TaskReminderConfig.Schedule schedule) { + logger.info("处理禅道逾期任务提醒 - 群组: {}", group.getName()); + + try { + // 发送禅道任务状态统计提醒(包含任务和BUG详情) + zentaoTaskReminderService.sendTaskReminder(group); + logger.info("禅道逾期任务提醒发送成功 - 群组: {}", group.getName()); + } catch (Exception e) { + logger.error("禅道逾期任务提醒发送失败 - 群组: {}", group.getName(), e); + } + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 557d73a..3828798 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -40,6 +40,9 @@ task: evening: time: "0 30 17 * * MON-FRI" # 工作日下午5:30 message: "下班前提醒:请大家登录禅道系统,及时更新今日任务的完成状态和进度,为明天的工作安排做好准备!" + overdue-reminder: + time: "0 0 10 * * MON-FRI" # 工作日上午10点 + message: "禅道逾期任务提醒" # 这个消息会被系统动态生成,包含具体的任务和BUG统计信息 enabled: true # 智能表格团队群 diff --git a/src/test/java/com/zeodao/reminder/strategy/ReminderHandlerFactoryTest.java b/src/test/java/com/zeodao/reminder/strategy/ReminderHandlerFactoryTest.java new file mode 100644 index 0000000..8924811 --- /dev/null +++ b/src/test/java/com/zeodao/reminder/strategy/ReminderHandlerFactoryTest.java @@ -0,0 +1,65 @@ +package com.zeodao.reminder.strategy; + +import com.zeodao.reminder.enums.ScheduleType; +import com.zeodao.reminder.enums.TaskSystemType; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * 提醒处理器工厂测试 + * + * @author Zeodao + * @version 2.0.0 + */ +@SpringBootTest +public class ReminderHandlerFactoryTest { + + @Autowired + private ReminderHandlerFactory reminderHandlerFactory; + + @Test + public void testGetTextReminderHandler() { + // 测试文本提醒处理器 + ReminderHandler handler = reminderHandlerFactory.getHandler(ScheduleType.MORNING, TaskSystemType.ZENTAO); + assertNotNull(handler); + assertTrue(handler instanceof TextReminderHandler); + + handler = reminderHandlerFactory.getHandler(ScheduleType.EVENING, TaskSystemType.SMARTSHEET); + assertNotNull(handler); + assertTrue(handler instanceof TextReminderHandler); + } + + @Test + public void testGetZentaoOverdueReminderHandler() { + // 测试禅道逾期提醒处理器 + ReminderHandler handler = reminderHandlerFactory.getHandler(ScheduleType.OVERDUE_REMINDER, TaskSystemType.ZENTAO); + assertNotNull(handler); + assertTrue(handler instanceof ZentaoOverdueReminderHandler); + } + + @Test + public void testUnsupportedCombination() { + // 测试不支持的组合 + ReminderHandler handler = reminderHandlerFactory.getHandler(ScheduleType.OVERDUE_REMINDER, TaskSystemType.SMARTSHEET); + assertNull(handler); + } + + @Test + public void testStringParameterVersion() { + // 测试字符串参数版本 + ReminderHandler handler = reminderHandlerFactory.getHandler("morning", "zentao"); + assertNotNull(handler); + assertTrue(handler instanceof TextReminderHandler); + + handler = reminderHandlerFactory.getHandler("overdue-reminder", "zentao"); + assertNotNull(handler); + assertTrue(handler instanceof ZentaoOverdueReminderHandler); + + // 测试无效代码 + handler = reminderHandlerFactory.getHandler("unknown-type", "zentao"); + assertNull(handler); + } +}