AdminWorkflowServiceImpl.java
package org.darkroomlibrary.service.impl;
import org.darkroomlibrary.web.response.ApiResponse;
import org.darkroomlibrary.service.AdminWorkflowService;
import org.darkroomlibrary.mapper.AdminWorkflowMapper;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@Service
public class AdminWorkflowServiceImpl implements AdminWorkflowService {
@Resource
private AdminWorkflowMapper adminWorkflowMapper;
@Override
public ApiResponse<Map<String, Object>> auditStatus() {
Map<String, Object> result = new LinkedHashMap<>();
List<Map<String, Object>> cards = new ArrayList<>();
List<Map<String, Object>> groups = new ArrayList<>();
Map<String, Object> counts = adminWorkflowMapper.countWorkflowStatuses();
long messagePending = number(counts, "messagePending");
long messageReplied = number(counts, "messageReplied");
long activeBorrow = number(counts, "activeBorrow");
long overdueBorrow = number(counts, "overdueBorrow");
long notifiedReservation = number(counts, "notifiedReservation");
long failedNotification = number(counts, "failedNotification");
long pendingReviewReport = number(counts, "pendingReviewReport");
long pendingProcurement = number(counts, "pendingProcurement");
long activeProcurement = number(counts, "activeProcurement");
long inTransitLogistics = number(counts, "inTransitLogistics");
long disabledUsers = number(counts, "disabledUsers");
long mutedUsers = number(counts, "mutedUsers");
cards.add(card("待回复留言", messagePending, "留言管理", "warning"));
cards.add(card("待审举报", pendingReviewReport, "内容审核", "warning"));
cards.add(card("待采购", pendingProcurement, "采购协作", "warning"));
cards.add(card("物流在途", inTransitLogistics, "物流进度", "primary"));
cards.add(card("逾期借阅", overdueBorrow, "流通审核", "danger"));
cards.add(card("已通知预约", notifiedReservation, "预约履约", "primary"));
cards.add(card("失败通知", failedNotification, "补偿任务", "danger"));
groups.add(group("留言处理状态", "读者留言是否已经由管理员回复。",
item("待回复", messagePending, "warning"),
item("已回复", messageReplied, "success")));
groups.add(group("用户状态审核", "关注账号可登录状态和发言状态。",
item("正常账号", number(counts, "activeUsers"), "success"),
item("冻结账号", disabledUsers, "danger"),
item("禁言账号", mutedUsers, "warning")));
groups.add(group("借阅状态跟踪", "馆员需要优先处理逾期和在借记录。",
item("借阅中", activeBorrow, "warning"),
item("已归还", number(counts, "returnedBorrow"), "success"),
item("逾期未还", overdueBorrow, "danger")));
groups.add(group("预约状态流转", "预约队列从等待、通知到履约或释放。",
item("等待中", number(counts, "waitingReservation"), "info"),
item("已通知", notifiedReservation, "primary"),
item("已借阅", number(counts, "borrowedReservation"), "success"),
item("已取消", number(counts, "canceledReservation"), "info"),
item("已过期", number(counts, "expiredReservation"), "warning")));
groups.add(group("通知补偿状态", "邮件发送失败时进入补偿任务,避免阻塞主流程。",
item("待发送", number(counts, "pendingNotification"), "warning"),
item("已发送", number(counts, "sentNotification"), "success"),
item("失败重试", failedNotification, "danger")));
groups.add(group("内容互动状态", "书评、点赞与回复形成读者互动闭环。",
item("书评数", number(counts, "reviewCount"), "primary"),
item("点赞数", number(counts, "reviewLikeCount"), "success"),
item("回复数", number(counts, "reviewReplyCount"), "info"),
item("待审举报", pendingReviewReport, "warning")));
groups.add(group("采购物流状态", "管理员创建采购需求,采购员处理采购,物流员同步入库进度。",
item("待采购", pendingProcurement, "warning"),
item("采购中", activeProcurement, "primary"),
item("已入库", number(counts, "warehousedProcurement"), "success"),
item("已完成", number(counts, "completedProcurement"), "success")));
result.put("cards", cards);
result.put("groups", groups);
return ApiResponse.success(result);
}
@Override
public ApiResponse<Map<String, Object>> backendFlow() {
Map<String, Object> result = new LinkedHashMap<>();
List<Map<String, Object>> stages = new ArrayList<>();
stages.add(stage("接入校验", "Controller",
"参数校验、白名单、角色保护和登录数学验证码先拦截明显无效请求。",
"账号登录", "邮箱验证码", "角色保护"));
stages.add(stage("业务编排", "Service",
"核心业务规则集中在 Service 层,借书、还书、续借、预约都在事务内完成。",
"借阅配额", "预约队列", "罚款计算"));
stages.add(stage("数据一致性", "Mapper / MySQL",
"库存扣减、还书更新和预约履约使用数据库条件更新,避免库存负数和重复处理。",
"条件扣库存", "状态流转", "唯一约束"));
stages.add(stage("事件与通知", "Domain Event",
"还书后发布预约通知事件,邮件失败时保留补偿任务,不影响主交易。",
"BookReturnedEvent", "到期提醒", "预约到货"));
stages.add(stage("可降级中间件", "Redis / RabbitMQ",
"Redis 和 MQ 只增强性能与通知投递;异常时核心事务继续,缓存转本地兜底,通知留在数据库任务中补偿。",
"缓存降级", "提交后审计", "通知补偿"));
stages.add(stage("后台审核", "Admin",
"后台集中查看用户、留言、书评举报、借阅、预约和通知补偿状态,优先处理异常项。",
"冻结用户", "回复留言", "书评举报", "处理逾期"));
stages.add(stage("采购物流闭环", "Procurement",
"管理员创建采购需求,采购员推进采购并对接物流,物流员入库后自动补充馆藏库存。",
"采购单", "协作消息", "物流入库", "库存补充"));
result.put("stages", stages);
result.put("status", auditStatus().getData());
return ApiResponse.success(result);
}
private long number(Map<String, Object> values, String key) {
Object value = values.get(key);
if (value == null) {
value = values.entrySet().stream()
.filter(entry -> entry.getKey().equalsIgnoreCase(key))
.map(Map.Entry::getValue)
.findFirst()
.orElse(null);
}
return value instanceof Number ? ((Number) value).longValue() : 0L;
}
private Map<String, Object> card(String label, long value, String module, String type) {
Map<String, Object> card = new LinkedHashMap<>();
card.put("label", label);
card.put("value", value);
card.put("module", module);
card.put("type", type);
return card;
}
@SafeVarargs
private final Map<String, Object> group(String title, String description, Map<String, Object>... items) {
Map<String, Object> group = new LinkedHashMap<>();
group.put("title", title);
group.put("description", description);
group.put("items", List.of(items));
return group;
}
private Map<String, Object> item(String label, long value, String type) {
Map<String, Object> item = new LinkedHashMap<>();
item.put("label", label);
item.put("value", value);
item.put("type", type);
return item;
}
private Map<String, Object> stage(String title, String layer, String description, String... points) {
Map<String, Object> stage = new LinkedHashMap<>();
stage.put("title", title);
stage.put("layer", layer);
stage.put("description", description);
stage.put("points", List.of(points));
return stage;
}
}