功能概述 订单状态追踪是生鲜电商系统中的核心功能之一,它允许用户和商家实时了解订单从创建到完成的整个生命周期。对于叮咚买菜这类即时配送的生鲜平台,精准的订单状态追踪尤为重要。 系统架构设计 1.状态机设计 ```mermaid stateDiagram-v2 [*
功能概述
订单状态追踪是生鲜电商系统中的核心功能之一,它允许用户和商家实时了解订单从创建到完成的整个生命周期。对于叮咚买菜这类即时配送的生鲜平台,精准的订单状态追踪尤为重要。
系统架构设计
1. 状态机设计
```mermaid
stateDiagram-v2
[*] --> 待支付
待支付 --> 已取消: 用户取消
待支付 --> 待接单: 支付成功
待接单 --> 待配送: 商家接单
待配送 --> 配送中: 骑手接单
配送中 --> 已完成: 订单送达
配送中 --> 异常中: 配送问题
异常中 --> 待配送: 重新分配骑手
异常中 --> 已取消: 无法配送
```
2. 核心数据表设计
订单状态表(order_status)
```sql
CREATE TABLE order_status (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
order_id BIGINT NOT NULL,
status_code VARCHAR(20) NOT NULL COMMENT 状态编码,
status_name VARCHAR(50) NOT NULL COMMENT 状态名称,
change_time DATETIME NOT NULL COMMENT 状态变更时间,
operator_type TINYINT COMMENT 操作方类型(1用户 2商家 3系统 4骑手),
operator_id BIGINT COMMENT 操作方ID,
remark VARCHAR(255) COMMENT 状态变更备注,
INDEX idx_order_id (order_id)
);
```
订单表(orders)
```sql
CREATE TABLE orders (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
user_id BIGINT NOT NULL,
order_no VARCHAR(32) NOT NULL COMMENT 订单号,
total_amount DECIMAL(10,2) NOT NULL,
pay_amount DECIMAL(10,2) NOT NULL,
current_status VARCHAR(20) NOT NULL COMMENT 当前状态,
create_time DATETIME NOT NULL,
update_time DATETIME NOT NULL,
INDEX idx_order_no (order_no),
INDEX idx_user_id (user_id)
);
```
核心功能实现
1. 状态变更服务
```java
@Service
public class OrderStatusService {
@Autowired
private OrderStatusRepository orderStatusRepository;
@Autowired
private OrderRepository orderRepository;
@Transactional
public void changeStatus(Long orderId, String newStatus,
Integer operatorType, Long operatorId, String remark) {
// 1. 验证订单是否存在
Order order = orderRepository.findById(orderId)
.orElseThrow(() -> new RuntimeException("订单不存在"));
// 2. 验证状态变更是否合法
validateStatusTransition(order.getCurrentStatus(), newStatus);
// 3. 更新订单当前状态
order.setCurrentStatus(newStatus);
order.setUpdateTime(new Date());
orderRepository.save(order);
// 4. 记录状态变更历史
OrderStatus statusRecord = new OrderStatus();
statusRecord.setOrderId(orderId);
statusRecord.setStatusCode(newStatus);
statusRecord.setStatusName(getStatusName(newStatus));
statusRecord.setChangeTime(new Date());
statusRecord.setOperatorType(operatorType);
statusRecord.setOperatorId(operatorId);
statusRecord.setRemark(remark);
orderStatusRepository.save(statusRecord);
// 5. 触发相关通知
triggerNotifications(order, newStatus);
}
private void validateStatusTransition(String currentStatus, String newStatus) {
// 实现状态变更合法性检查
// 例如: 已完成订单不能变更为待接单
}
private String getStatusName(String statusCode) {
// 状态码到名称的映射
Map
statusMap = Map.of(
"PENDING_PAY", "待支付",
"CANCELLED", "已取消",
"ACCEPTED", "待接单",
"PREPARING", "备货中",
"PICKED_UP", "已取货",
"DELIVERING", "配送中",
"COMPLETED", "已完成",
"EXCEPTION", "异常中"
);
return statusMap.getOrDefault(statusCode, "未知状态");
}
private void triggerNotifications(Order order, String newStatus) {
// 根据状态变更触发短信、APP推送等通知
}
}
```
2. 状态追踪查询API
```java
@RestController
@RequestMapping("/api/orders")
public class OrderController {
@Autowired
private OrderStatusService orderStatusService;
@GetMapping("/{orderId}/status-trace")
public ResponseEntity> getOrderStatusTrace(@PathVariable Long orderId) {
List statusRecords = orderStatusService.getStatusHistory(orderId);
List dtos = statusRecords.stream()
.map(this::convertToDTO)
.collect(Collectors.toList());
return ResponseEntity.ok(dtos);
}
private OrderStatusDTO convertToDTO(OrderStatus status) {
OrderStatusDTO dto = new OrderStatusDTO();
dto.setStatusCode(status.getStatusCode());
dto.setStatusName(status.getStatusName());
dto.setChangeTime(status.getChangeTime());
dto.setOperatorType(status.getOperatorType());
dto.setOperatorName(getOperatorName(status.getOperatorType(), status.getOperatorId()));
dto.setRemark(status.getRemark());
return dto;
}
private String getOperatorName(Integer operatorType, Long operatorId) {
// 根据操作方类型和ID获取名称
// 1用户 2商家 3系统 4骑手
switch(operatorType) {
case 1: return "用户" + operatorId;
case 2: return "商家" + operatorId;
case 4: return "骑手" + operatorId;
default: return "系统";
}
}
}
```
3. 实时状态推送(WebSocket实现)
```java
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic");
registry.setApplicationDestinationPrefixes("/app");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws")
.setAllowedOriginPatterns("*")
.withSockJS();
}
}
@Service
public class OrderStatusWebSocketService {
@Autowired
private SimpMessagingTemplate messagingTemplate;
public void notifyStatusChange(Long orderId, String newStatus) {
// 构建通知消息
Map message = new HashMap<>();
message.put("orderId", orderId);
message.put("status", newStatus);
message.put("timestamp", System.currentTimeMillis());
// 发送到特定订单的主题
messagingTemplate.convertAndSend(
"/topic/orders/" + orderId + "/status",
message
);
}
}
```
前端实现要点
1. 订单状态展示组件
```javascript
// React示例
function OrderStatusTimeline({ orderId }) {
const [statusHistory, setStatusHistory] = useState([]);
const [currentStatus, setCurrentStatus] = useState();
useEffect(() => {
// 获取初始状态
fetchOrderStatus(orderId);
// 建立WebSocket连接
const socket = new SockJS(/ws);
const stompClient = Stomp.over(socket);
stompClient.connect({}, frame => {
stompClient.subscribe(`/topic/orders/${orderId}/status`, message => {
const data = JSON.parse(message.body);
fetchOrderStatus(orderId); // 刷新完整状态历史
});
});
return () => socket.close();
}, [orderId]);
const fetchOrderStatus = async (orderId) => {
const response = await fetch(`/api/orders/${orderId}/status-trace`);
const data = await response.json();
setStatusHistory(data);
if (data.length > 0) {
setCurrentStatus(data[data.length - 1].statusCode);
}
};
const getStatusColor = (status) => {
const colors = {
PENDING_PAY: blue,
ACCEPTED: orange,
PREPARING: yellow,
DELIVERING: green,
COMPLETED: green,
CANCELLED: red,
EXCEPTION: red
};
return colors[status] || gray;
};
return (
当前状态:
{getStatusName(currentStatus)}
{statusHistory.map((item, index) => (
key={index}
color={getStatusColor(item.statusCode)}
>
{formatTime(item.changeTime)} - {getStatusName(item.statusCode)}
{item.remark && {item.remark}
}
))}
);
}
```
2. 状态变更通知
```javascript
// 使用Notification API显示状态变更通知
function showStatusNotification(orderId, newStatus) {
const title = `订单 ${orderId} 状态更新`;
const options = {
body: `订单状态已变更为: ${getStatusName(newStatus)}`,
icon: /icon.png,
badge: /badge.png
};
if (!(Notification in window)) {
console.log(浏览器不支持通知);
return;
}
if (Notification.permission === granted) {
new Notification(title, options);
} else if (Notification.permission !== denied) {
Notification.requestPermission().then(permission => {
if (permission === granted) {
new Notification(title, options);
}
});
}
}
```
性能优化考虑
1. 状态变更日志压缩:对于频繁变更的状态(如配送中的位置更新),考虑批量写入或使用单独的轻量级日志表
2. 缓存策略:
- 对热门订单的状态查询结果进行缓存
- 使用Redis缓存当前状态,减少数据库查询
3. 异步处理:
- 状态变更后的通知发送使用异步队列
- 非关键的状态变更记录可以异步写入
4. 数据库优化:
- 对订单状态表进行分表处理(按时间或订单ID范围)
- 使用读写分离架构
测试要点
1. 状态变更合法性测试:验证所有可能的状态转换路径是否符合业务规则
2. 并发测试:模拟多个用户或系统同时修改订单状态的情况
3. 通知可靠性测试:验证各种通知渠道(APP推送、短信、WebSocket)的可靠性
4. 历史记录完整性测试:确保所有状态变更都被正确记录,无遗漏或重复
5. 性能测试:在高并发场景下测试状态查询和变更的性能
扩展功能
1. 预计到达时间(ETA)计算:基于历史数据和实时交通信息计算配送ETA
2. 异常状态自动处理:对于长时间处于异常状态的订单自动触发补偿措施
3. 状态变更分析:分析状态变更模式,优化业务流程
4. 多端同步:确保用户APP、小程序、网页端状态实时同步
通过以上实现,叮咚买菜系统可以提供准确、实时的订单状态追踪功能,提升用户体验和运营效率。