一、功能概述
订单状态追踪是生鲜电商系统的核心功能之一,能够让用户实时了解订单从下单到配送完成的整个生命周期,提升用户体验和信任度。
二、订单状态设计
典型订单状态流转
1. 待支付:用户下单但未完成支付
2. 已支付:支付成功,等待仓库处理
3. 拣货中:仓库开始分拣商品
4. 分拣完成:商品已分拣完毕
5. 配送中:骑手已接单并开始配送
6. 已送达:订单成功送达用户手中
7. 已取消:订单在某个环节被取消
8. 异常订单:如缺货、配送失败等特殊情况
三、系统架构实现
1. 数据库设计
```sql
CREATE TABLE order_status (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
order_id BIGINT NOT NULL COMMENT 订单ID,
status VARCHAR(20) NOT NULL COMMENT 订单状态,
status_desc VARCHAR(100) COMMENT 状态描述,
create_time DATETIME NOT NULL COMMENT 状态变更时间,
operator VARCHAR(50) COMMENT 操作人(系统/人工),
location VARCHAR(100) COMMENT 位置信息(配送中时使用),
FOREIGN KEY (order_id) REFERENCES orders(id)
);
CREATE TABLE order_status_history (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
order_id BIGINT NOT NULL,
from_status VARCHAR(20) COMMENT 原状态,
to_status VARCHAR(20) COMMENT 新状态,
change_time DATETIME NOT NULL,
operator VARCHAR(50),
remark VARCHAR(255),
FOREIGN KEY (order_id) REFERENCES orders(id)
);
```
2. 后端服务实现
状态变更服务
```java
@Service
public class OrderStatusService {
@Autowired
private OrderStatusRepository orderStatusRepository;
@Autowired
private OrderStatusHistoryRepository historyRepository;
@Transactional
public void updateOrderStatus(Long orderId, String newStatus, String operator, String remark) {
// 1. 获取当前订单状态
OrderStatus currentStatus = orderStatusRepository.findTopByOrderIdOrderByCreateTimeDesc(orderId);
// 2. 记录状态变更历史
OrderStatusHistory history = new OrderStatusHistory();
history.setOrderId(orderId);
history.setFromStatus(currentStatus != null ? currentStatus.getStatus() : null);
history.setToStatus(newStatus);
history.setChangeTime(LocalDateTime.now());
history.setOperator(operator);
history.setRemark(remark);
historyRepository.save(history);
// 3. 更新当前状态
OrderStatus status = new OrderStatus();
status.setOrderId(orderId);
status.setStatus(newStatus);
status.setStatusDesc(getStatusDescription(newStatus));
status.setCreateTime(LocalDateTime.now());
status.setOperator(operator);
// 根据状态设置额外信息
if ("DELIVERING".equals(newStatus)) {
// 如果是配送中,设置骑手位置信息
status.setLocation(getRiderLocation(orderId));
}
orderStatusRepository.save(status);
}
private String getStatusDescription(String status) {
// 状态描述映射
Map
descMap = new HashMap<>();
descMap.put("PENDING_PAYMENT", "待支付");
descMap.put("PAID", "已支付");
descMap.put("PICKING", "拣货中");
// 其他状态描述...
return descMap.getOrDefault(status, "未知状态");
}
}
```
3. 实时位置追踪实现
骑手位置上报
```java
@RestController
@RequestMapping("/api/rider")
public class RiderLocationController {
@Autowired
private OrderStatusService orderStatusService;
@PostMapping("/location")
public ResponseEntity<?> updateLocation(
@RequestParam Long orderId,
@RequestParam Double latitude,
@RequestParam Double longitude) {
// 更新订单状态中的位置信息
orderStatusService.updateRiderLocation(orderId, latitude, longitude);
return ResponseEntity.ok().build();
}
}
```
WebSocket实时推送
```java
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws").setAllowedOriginPatterns("*").withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic");
registry.setApplicationDestinationPrefixes("/app");
}
}
@Service
public class OrderStatusPushService {
@Autowired
private SimpMessagingTemplate messagingTemplate;
public void pushStatusUpdate(Long orderId, String status) {
// 构建推送消息
Map message = new HashMap<>();
message.put("orderId", orderId);
message.put("status", status);
message.put("timestamp", System.currentTimeMillis());
// 推送给特定用户(通过订单ID关联用户)
messagingTemplate.convertAndSend("/topic/orders/" + orderId, message);
}
}
```
四、前端实现方案
1. 订单状态展示组件
```javascript
function OrderStatusTracker({ orderId }) {
const [status, setStatus] = useState(null);
const [history, setHistory] = useState([]);
useEffect(() => {
// 初始化时获取订单状态
fetchOrderStatus(orderId);
// 订阅WebSocket消息
const stompClient = Stomp.over(new SockJS(/ws));
stompClient.connect({}, () => {
stompClient.subscribe(`/topic/orders/${orderId}`, (message) => {
const data = JSON.parse(message.body);
setStatus(data.status);
// 可以选择刷新历史记录或仅更新当前状态
});
});
return () => {
// 组件卸载时断开连接
if (stompClient) {
stompClient.disconnect();
}
};
}, [orderId]);
const fetchOrderStatus = (id) => {
// 调用API获取订单状态和历史
api.get(`/orders/${id}/status`).then(response => {
setStatus(response.data.currentStatus);
setHistory(response.data.history);
});
};
return (
订单状态
{status ? getStatusLabel(status) : 加载中...}
状态历史
{history.map((item, index) => (
{formatTime(item.changeTime)}
{getStatusLabel(item.toStatus)}
{item.remark && ({item.remark})}
))}
{status === DELIVERING &&
}
);
}
```
2. 配送地图组件
```javascript
function RiderLocationMap({ orderId }) {
const [location, setLocation] = useState(null);
useEffect(() => {
// 定期获取骑手位置
const interval = setInterval(() => {
api.get(`/orders/${orderId}/rider-location`).then(response => {
setLocation(response.data);
});
}, 5000); // 每5秒更新一次
return () => clearInterval(interval);
}, [orderId]);
return (
{location ? (
) : (
正在获取骑手位置...
)}
);
}
```
五、关键技术点
1. 状态变更原子性:使用数据库事务确保状态变更和历史记录的同步
2. 实时推送:结合WebSocket实现状态变更的实时通知
3. 位置追踪:
- 骑手端定期上报位置
- 前端定期拉取最新位置
- 可考虑使用WebSocket替代定期拉取以减少延迟
4. 状态机验证:实现状态变更的合法性检查,防止无效状态跳转
5. 性能优化:
- 对高频更新的状态(如位置)使用单独的轻量级存储
- 实现状态变更的缓存机制
六、扩展功能
1. 预计送达时间计算:基于历史数据和实时交通情况动态调整
2. 异常状态处理:自动识别并处理配送延迟、商品缺货等异常情况
3. 多端同步:确保APP、小程序、网页端状态同步
4. 通知系统:状态变更时推送短信、APP消息或邮件通知
5. 数据分析:收集状态变更数据用于优化配送流程
七、测试要点
1. 状态流转测试:验证所有可能的状态跳转路径
2. 并发测试:模拟多系统同时修改订单状态的场景
3. 性能测试:高并发下状态查询和更新的响应时间
4. 异常测试:网络中断、系统故障等情况下的状态恢复
5. 用户体验测试:状态展示的清晰度和实时性
通过以上实现方案,可以构建一个高效、可靠的订单状态追踪系统,显著提升叮咚买菜用户的购物体验。