From ba38897f7327c329f3d3a609a1bcd8347f4349f1 Mon Sep 17 00:00:00 2001 From: huangping Date: Mon, 25 May 2026 01:02:46 +0800 Subject: [PATCH] feat: add M8 TodoService + TodoController --- .../platform/api/service/TodoService.java | 155 ++++++++++++++++++ .../platform/api/todo/TodoController.java | 69 ++++++++ .../platform/api/web/dto/TodoResponse.java | 142 ++++++++++++++++ 3 files changed, 366 insertions(+) create mode 100644 services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/service/TodoService.java create mode 100644 services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/todo/TodoController.java create mode 100644 services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/web/dto/TodoResponse.java diff --git a/services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/service/TodoService.java b/services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/service/TodoService.java new file mode 100644 index 0000000..3d60491 --- /dev/null +++ b/services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/service/TodoService.java @@ -0,0 +1,155 @@ +package cn.craftlabs.platform.api.service; + +import cn.craftlabs.platform.api.persistence.todo.PlatformNotificationConfig; +import cn.craftlabs.platform.api.persistence.todo.PlatformNotificationConfigMapper; +import cn.craftlabs.platform.api.persistence.todo.PlatformTodoItem; +import cn.craftlabs.platform.api.persistence.todo.PlatformTodoItemMapper; +import cn.craftlabs.platform.api.web.dto.PageResponse; +import cn.craftlabs.platform.api.web.dto.TodoResponse; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.util.List; +import java.util.stream.Collectors; + +@Service +public class TodoService { + + private final PlatformTodoItemMapper todoItemMapper; + private final PlatformNotificationConfigMapper notificationConfigMapper; + + public TodoService(PlatformTodoItemMapper todoItemMapper, + PlatformNotificationConfigMapper notificationConfigMapper) { + this.todoItemMapper = todoItemMapper; + this.notificationConfigMapper = notificationConfigMapper; + } + + @Transactional(readOnly = true) + public PageResponse listTodos(int page, int size, String type, String status, String role) { + LambdaQueryWrapper q = + Wrappers.lambdaQuery(PlatformTodoItem.class) + .eq(type != null && !type.isEmpty(), PlatformTodoItem::getTodoType, type) + .eq(status != null && !status.isEmpty(), PlatformTodoItem::getStatus, status) + .eq(role != null && !role.isEmpty(), PlatformTodoItem::getAssignedRole, role) + .orderByDesc(PlatformTodoItem::getCreatedAt); + Page mpPage = new Page<>(page + 1L, size); + todoItemMapper.selectPage(mpPage, q); + List content = + mpPage.getRecords().stream().map(this::toTodoResponse).collect(Collectors.toList()); + return new PageResponse<>(content, mpPage.getTotal(), page, size); + } + + @Transactional + public void updateStatus(Long id, String status, String userId) { + PlatformTodoItem item = todoItemMapper.selectById(id); + if (item != null) { + item.setStatus(status); + item.setAssignedUserId(userId); + item.setProcessedAt(OffsetDateTime.now(ZoneOffset.UTC)); + todoItemMapper.updateById(item); + } + } + + @Transactional + public void batchUpdateStatus(List ids, String status, String userId) { + for (Long id : ids) { + updateStatus(id, status, userId); + } + } + + @Transactional + public void createTodo(String type, String title, Long sourceId, String sourceType, + String priority, String assignedRole) { + OffsetDateTime now = OffsetDateTime.now(ZoneOffset.UTC); + PlatformTodoItem item = new PlatformTodoItem(); + item.setTodoType(type); + item.setTitle(title); + item.setSourceId(sourceId); + item.setSourceType(sourceType); + item.setPriority(priority); + item.setStatus("PENDING"); + item.setAssignedRole(assignedRole); + item.setCreatedAt(now); + todoItemMapper.insert(item); + } + + @Transactional(readOnly = true) + public List getNotificationConfig(String roleCode) { + if (roleCode != null && !roleCode.isEmpty()) { + LambdaQueryWrapper q = + Wrappers.lambdaQuery(PlatformNotificationConfig.class) + .eq(PlatformNotificationConfig::getRoleCode, roleCode); + return notificationConfigMapper.selectList(q); + } + return notificationConfigMapper.selectList(null); + } + + @Transactional + public void updateNotificationConfig(List configs) { + for (PlatformNotificationConfig config : configs) { + if (config.getId() != null) { + notificationConfigMapper.updateById(config); + } else { + config.setCreatedAt(OffsetDateTime.now(ZoneOffset.UTC)); + config.setUpdatedAt(OffsetDateTime.now(ZoneOffset.UTC)); + notificationConfigMapper.insert(config); + } + } + } + + private TodoResponse toTodoResponse(PlatformTodoItem item) { + TodoResponse r = new TodoResponse(); + r.setId(item.getId()); + r.setTodoType(item.getTodoType()); + r.setTodoTypeLabel(todoTypeLabel(item.getTodoType())); + r.setTitle(item.getTitle()); + r.setSourceId(item.getSourceId()); + r.setSourceType(item.getSourceType()); + r.setPriority(item.getPriority()); + r.setPriorityLabel(priorityLabel(item.getPriority())); + r.setStatus(item.getStatus()); + r.setStatusLabel(statusLabel(item.getStatus())); + r.setAssignedRole(item.getAssignedRole()); + r.setAssignedUserId(item.getAssignedUserId()); + r.setCreatedAt(item.getCreatedAt()); + r.setProcessedAt(item.getProcessedAt()); + r.setRemark(item.getRemark()); + return r; + } + + private static String todoTypeLabel(String type) { + if (type == null) return ""; + switch (type) { + case "CALLBACK": return "Callback"; + case "SN_GRANT": return "SN 发放"; + case "ACTIVATION_EXPIRED": return "激活超期"; + case "DEVICE_SWAP": return "换机审批"; + default: return type; + } + } + + private static String priorityLabel(String priority) { + if (priority == null) return ""; + switch (priority) { + case "HIGH": return "高"; + case "MEDIUM": return "中"; + case "LOW": return "低"; + default: return priority; + } + } + + private static String statusLabel(String status) { + if (status == null) return ""; + switch (status) { + case "PENDING": return "待处理"; + case "PROCESSED": return "已处理"; + case "IGNORED": return "已忽略"; + default: return status; + } + } +} diff --git a/services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/todo/TodoController.java b/services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/todo/TodoController.java new file mode 100644 index 0000000..845e7cb --- /dev/null +++ b/services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/todo/TodoController.java @@ -0,0 +1,69 @@ +package cn.craftlabs.platform.api.todo; + +import cn.craftlabs.platform.api.persistence.todo.PlatformNotificationConfig; +import cn.craftlabs.platform.api.service.TodoService; +import cn.craftlabs.platform.api.web.dto.PageResponse; +import cn.craftlabs.platform.api.web.dto.TodoResponse; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; +import java.util.Map; + +@RestController +@RequestMapping("/api/v1") +@Validated +public class TodoController { + + private final TodoService todoService; + + public TodoController(TodoService todoService) { + this.todoService = todoService; + } + + @GetMapping("/todos") + public PageResponse listTodos( + @RequestParam(value = "page", defaultValue = "0") @Min(0) int page, + @RequestParam(value = "size", defaultValue = "20") @Min(1) @Max(200) int size, + @RequestParam(value = "type", required = false) String type, + @RequestParam(value = "status", required = false) String status, + @RequestParam(value = "role", required = false) String role) { + return todoService.listTodos(page, size, type, status, role); + } + + @PatchMapping("/todos/{id}/status") + public void updateStatus(@PathVariable("id") Long id, + @RequestBody Map body) { + todoService.updateStatus(id, body.get("status"), body.get("userId")); + } + + @PostMapping("/todos/batch-status") + public void batchUpdateStatus(@RequestBody Map body) { + @SuppressWarnings("unchecked") + List ids = ((List) body.get("ids")).stream() + .map(Integer::longValue) + .collect(java.util.stream.Collectors.toList()); + todoService.batchUpdateStatus(ids, (String) body.get("status"), (String) body.get("userId")); + } + + @GetMapping("/notifications/config") + public List getNotificationConfig( + @RequestParam(value = "roleCode", required = false) String roleCode) { + return todoService.getNotificationConfig(roleCode); + } + + @PutMapping("/notifications/config") + public void updateNotificationConfig(@RequestBody List configs) { + todoService.updateNotificationConfig(configs); + } +} diff --git a/services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/web/dto/TodoResponse.java b/services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/web/dto/TodoResponse.java new file mode 100644 index 0000000..8bce9fc --- /dev/null +++ b/services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/web/dto/TodoResponse.java @@ -0,0 +1,142 @@ +package cn.craftlabs.platform.api.web.dto; + +import java.time.OffsetDateTime; + +public class TodoResponse { + + private Long id; + private String todoType; + private String todoTypeLabel; + private String title; + private Long sourceId; + private String sourceType; + private String priority; + private String priorityLabel; + private String status; + private String statusLabel; + private String assignedRole; + private String assignedUserId; + private OffsetDateTime createdAt; + private OffsetDateTime processedAt; + private String remark; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getTodoType() { + return todoType; + } + + public void setTodoType(String todoType) { + this.todoType = todoType; + } + + public String getTodoTypeLabel() { + return todoTypeLabel; + } + + public void setTodoTypeLabel(String todoTypeLabel) { + this.todoTypeLabel = todoTypeLabel; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public Long getSourceId() { + return sourceId; + } + + public void setSourceId(Long sourceId) { + this.sourceId = sourceId; + } + + public String getSourceType() { + return sourceType; + } + + public void setSourceType(String sourceType) { + this.sourceType = sourceType; + } + + public String getPriority() { + return priority; + } + + public void setPriority(String priority) { + this.priority = priority; + } + + public String getPriorityLabel() { + return priorityLabel; + } + + public void setPriorityLabel(String priorityLabel) { + this.priorityLabel = priorityLabel; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getStatusLabel() { + return statusLabel; + } + + public void setStatusLabel(String statusLabel) { + this.statusLabel = statusLabel; + } + + public String getAssignedRole() { + return assignedRole; + } + + public void setAssignedRole(String assignedRole) { + this.assignedRole = assignedRole; + } + + public String getAssignedUserId() { + return assignedUserId; + } + + public void setAssignedUserId(String assignedUserId) { + this.assignedUserId = assignedUserId; + } + + public OffsetDateTime getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(OffsetDateTime createdAt) { + this.createdAt = createdAt; + } + + public OffsetDateTime getProcessedAt() { + return processedAt; + } + + public void setProcessedAt(OffsetDateTime processedAt) { + this.processedAt = processedAt; + } + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } +}