一、功能概述
订单状态追踪是生鲜电商系统的核心功能之一,能够让用户实时了解订单从下单到配送完成的整个流程,提升用户体验和信任度。
二、系统架构设计
1. 前端实现
- 订单详情页:展示订单当前状态和历史状态变更记录
- 状态时间轴:可视化展示订单流程节点
- 实时推送:通过WebSocket或长轮询实现状态变更实时通知
- 地图追踪:集成地图API展示配送员实时位置(可选)
2. 后端实现
- 状态机设计:定义订单状态流转规则
- 事件驱动架构:通过事件总线处理状态变更
- 分布式追踪:确保微服务架构下状态变更的可追溯性
- API接口:提供查询订单状态的RESTful/GraphQL接口
3. 数据库设计
```sql
CREATE TABLE order_status (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
order_id BIGINT NOT NULL,
status VARCHAR(20) NOT NULL, -- 如: PENDING, PROCESSING, SHIPPED, DELIVERED等
status_desc VARCHAR(255),
create_time DATETIME NOT NULL,
operator_id BIGINT, -- 操作人ID(系统或人工)
operator_type VARCHAR(10), -- SYSTEM/USER
FOREIGN KEY (order_id) REFERENCES orders(id)
);
CREATE TABLE order_status_log (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
order_id BIGINT NOT NULL,
from_status VARCHAR(20),
to_status VARCHAR(20),
change_time DATETIME NOT NULL,
change_reason VARCHAR(255),
operator_id BIGINT,
operator_type VARCHAR(10),
FOREIGN KEY (order_id) REFERENCES orders(id)
);
```
三、核心状态定义
1. 待支付(PENDING_PAYMENT)
2. 已支付待处理(PAID)
3. 仓库处理中(PROCESSING)
4. 分拣完成(PICKED)
5. 配送中(SHIPPED)
6. 已送达(DELIVERED)
7. 已取消(CANCELLED)
8. 异常订单(EXCEPTION)
四、状态变更流程实现
1. 状态机配置
```java
public enum OrderStatus {
PENDING_PAYMENT("待支付"),
PAID("已支付"),
PROCESSING("处理中"),
PICKED("已分拣"),
SHIPPED("配送中"),
DELIVERED("已送达"),
CANCELLED("已取消"),
EXCEPTION("异常");
// 定义状态流转规则
private static final Map> TRANSITION_RULES = Map.of(
"PENDING_PAYMENT", List.of("PAID", "CANCELLED"),
"PAID", List.of("PROCESSING", "CANCELLED"),
"PROCESSING", List.of("PICKED", "EXCEPTION"),
"PICKED", List.of("SHIPPED", "EXCEPTION"),
"SHIPPED", List.of("DELIVERED", "EXCEPTION"),
"EXCEPTION", List.of("PROCESSING", "CANCELLED")
);
public static boolean canTransition(String fromStatus, String toStatus) {
return TRANSITION_RULES.getOrDefault(fromStatus, Collections.emptyList())
.contains(toStatus);
}
}
```
2. 状态变更服务
```java
@Service
@RequiredArgsConstructor
public class OrderStatusService {
private final OrderStatusLogRepository logRepository;
private final OrderRepository orderRepository;
private final EventPublisher eventPublisher;
@Transactional
public void changeStatus(Long orderId, String newStatus, String operatorType, Long operatorId, String reason) {
Order order = orderRepository.findById(orderId)
.orElseThrow(() -> new RuntimeException("订单不存在"));
String currentStatus = order.getStatus();
// 验证状态流转是否合法
if (!OrderStatus.canTransition(currentStatus, newStatus)) {
throw new IllegalStateException("非法状态流转: " + currentStatus + " -> " + newStatus);
}
// 记录状态变更日志
OrderStatusLog log = new OrderStatusLog(
orderId, currentStatus, newStatus,
LocalDateTime.now(), reason, operatorId, operatorType
);
logRepository.save(log);
// 更新订单状态
order.setStatus(newStatus);
orderRepository.save(order);
// 发布状态变更事件
OrderStatusChangedEvent event = new OrderStatusChangedEvent(
orderId, newStatus, LocalDateTime.now()
);
eventPublisher.publish(event);
}
}
```
五、实时通知实现
1. WebSocket实现方案
```java
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws/order-status")
.setAllowedOriginPatterns("*")
.withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic");
registry.setApplicationDestinationPrefixes("/app");
}
}
@Service
public class OrderStatusNotificationService {
@Autowired
private SimpMessagingTemplate messagingTemplate;
@EventListener
public void handleOrderStatusChanged(OrderStatusChangedEvent event) {
// 通知用户
messagingTemplate.convertAndSendToUser(
String.valueOf(event.getOrderId()),
"/queue/order-status",
event
);
// 广播更新(可选)
messagingTemplate.convertAndSend(
"/topic/order-status/" + event.getOrderId(),
event
);
}
}
```
2. 前端WebSocket连接
```javascript
const socket = new SockJS(/ws/order-status);
const stompClient = Stomp.over(socket);
stompClient.connect({}, function(frame) {
// 订阅个人订单状态更新
stompClient.subscribe(`/user/queue/order-status`, function(message) {
const event = JSON.parse(message.body);
updateOrderStatusUI(event);
});
// 订阅特定订单状态更新(可选)
const orderId = 12345; // 实际从页面获取
stompClient.subscribe(`/topic/order-status/${orderId}`, function(message) {
const event = JSON.parse(message.body);
updateOrderStatusUI(event);
});
});
```
六、异常处理与补偿机制
1. 状态变更失败处理:
- 数据库事务回滚
- 死信队列处理失败事件
- 人工干预入口
2. 状态不一致修复:
- 定时任务扫描异常状态订单
- 状态重算服务
- 操作日志审计
七、性能优化考虑
1. 状态查询缓存:
- 对热门订单状态使用Redis缓存
- 设置合理的缓存过期时间
2. 数据库优化:
- 对order_status表按order_id和create_time建立索引
- 考虑分表策略(按时间或订单ID范围)
3. 消息队列削峰:
- 状态变更事件通过消息队列异步处理
- 消费者端批量处理
八、测试策略
1. 单元测试:
- 状态机规则验证
- 状态变更服务边界条件测试
2. 集成测试:
- 状态变更全流程测试
- 通知系统集成测试
3. 性能测试:
- 高并发状态变更测试
- 长连接稳定性测试
4. 用户体验测试:
- 不同网络条件下通知到达率
- 状态显示准确性验证
九、部署与监控
1. 监控指标:
- 状态变更成功率
- 通知送达率
- 状态查询响应时间
2. 告警规则:
- 状态变更失败率阈值
- 通知延迟超过阈值
- 状态不一致数量突增
3. 日志收集:
- 完整的状态变更操作日志
- 通知发送日志
- 错误日志集中管理
通过以上方案实现,叮咚买菜系统可以提供准确、实时、可靠的订单状态追踪功能,显著提升用户体验和平台信任度。