feat: add M8 TodoService + TodoController

This commit is contained in:
2026-05-25 01:02:46 +08:00
parent fa2a50e755
commit ba38897f73
3 changed files with 366 additions and 0 deletions
@@ -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<TodoResponse> listTodos(int page, int size, String type, String status, String role) {
LambdaQueryWrapper<PlatformTodoItem> 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<PlatformTodoItem> mpPage = new Page<>(page + 1L, size);
todoItemMapper.selectPage(mpPage, q);
List<TodoResponse> 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<Long> 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<PlatformNotificationConfig> getNotificationConfig(String roleCode) {
if (roleCode != null && !roleCode.isEmpty()) {
LambdaQueryWrapper<PlatformNotificationConfig> q =
Wrappers.lambdaQuery(PlatformNotificationConfig.class)
.eq(PlatformNotificationConfig::getRoleCode, roleCode);
return notificationConfigMapper.selectList(q);
}
return notificationConfigMapper.selectList(null);
}
@Transactional
public void updateNotificationConfig(List<PlatformNotificationConfig> 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;
}
}
}
@@ -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<TodoResponse> 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<String, String> body) {
todoService.updateStatus(id, body.get("status"), body.get("userId"));
}
@PostMapping("/todos/batch-status")
public void batchUpdateStatus(@RequestBody Map<String, Object> body) {
@SuppressWarnings("unchecked")
List<Long> ids = ((List<Integer>) 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<PlatformNotificationConfig> getNotificationConfig(
@RequestParam(value = "roleCode", required = false) String roleCode) {
return todoService.getNotificationConfig(roleCode);
}
@PutMapping("/notifications/config")
public void updateNotificationConfig(@RequestBody List<PlatformNotificationConfig> configs) {
todoService.updateNotificationConfig(configs);
}
}
@@ -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;
}
}