632 行
14 KiB
Markdown
632 行
14 KiB
Markdown
# 骑手订单分配系统 - 测试与发布指南
|
||
|
||
## 📋 概述
|
||
|
||
本指南详细说明如何测试和发布订单到骑手端,包括完整的操作流程、API接口使用方法和故障排除指南。
|
||
|
||
## 🚀 快速开始
|
||
|
||
### 1. 运行测试脚本
|
||
|
||
```bash
|
||
# 完整测试流程
|
||
php test_order_dispatch.php
|
||
|
||
# 或者通过Web访问
|
||
http://your-domain.com/test_order_dispatch.php
|
||
```
|
||
|
||
### 2. 查看系统状态
|
||
|
||
```bash
|
||
# 查看骑手和订单状态
|
||
php test_order_dispatch.php status
|
||
|
||
# 或者Web访问
|
||
http://your-domain.com/test_order_dispatch.php?action=status
|
||
```
|
||
|
||
## 📊 系统架构
|
||
|
||
### 核心组件
|
||
|
||
1. **订单分配引擎** (`RiderOrderDispatch.class.php`)
|
||
- 自动分配算法
|
||
- 骑手评分计算
|
||
- 距离和时间优化
|
||
|
||
2. **骑手端API** (`RiderApi\Controller\OrderController.class.php`)
|
||
- 获取可接订单
|
||
- 接受/拒绝订单
|
||
- 订单状态更新
|
||
|
||
3. **订单管理** (`RiderOrderController.class.php`)
|
||
- 订单列表查询
|
||
- 状态流转控制
|
||
- 配送流程管理
|
||
|
||
## 🔄 完整测试流程
|
||
|
||
### 步骤1:创建测试订单
|
||
|
||
```php
|
||
// 使用测试脚本创建订单
|
||
php test_order_dispatch.php create
|
||
|
||
// 或者手动创建
|
||
$orderData = [
|
||
'bill_id' => 'TEST_' . date('YmdHis') . rand(1000, 9999),
|
||
'order_no' => 'RO' . date('YmdHis') . rand(1000, 9999),
|
||
'merchant_id' => 1,
|
||
'store_id' => 1,
|
||
'customer_name' => '测试客户',
|
||
'customer_phone' => '13800138000',
|
||
'delivery_address' => '测试地址',
|
||
'delivery_lat' => 39.9042,
|
||
'delivery_lng' => 116.4074,
|
||
'order_amount' => 58.50,
|
||
'delivery_fee' => 8.00,
|
||
'total_amount' => 66.50,
|
||
'order_type' => 1,
|
||
'order_status' => 0, // 待分配
|
||
'add_time' => date('Y-m-d H:i:s')
|
||
];
|
||
```
|
||
|
||
### 步骤2:订单分配
|
||
|
||
#### 自动分配
|
||
```php
|
||
$dispatch = new \Common\Business\RiderOrderDispatch();
|
||
$result = $dispatch->dispatchOrder([
|
||
'bill_id' => $orderData['bill_id'],
|
||
'merchant_id' => $orderData['merchant_id'],
|
||
'store_id' => $orderData['store_id'],
|
||
'auto_assign' => true
|
||
]);
|
||
```
|
||
|
||
#### 手动分配
|
||
```php
|
||
$result = $dispatch->dispatchOrder([
|
||
'bill_id' => $orderData['bill_id'],
|
||
'merchant_id' => $orderData['merchant_id'],
|
||
'store_id' => $orderData['store_id'],
|
||
'rider_id' => 3, // 指定骑手ID
|
||
'auto_assign' => false
|
||
]);
|
||
```
|
||
|
||
### 步骤3:骑手接单
|
||
|
||
#### 获取可接订单
|
||
```php
|
||
// API: /RiderApi/Order/getAvailableOrders
|
||
$orders = $riderController->getAvailableOrders([
|
||
'rider_id' => 3,
|
||
'page' => 1,
|
||
'limit' => 10
|
||
]);
|
||
```
|
||
|
||
#### 接受订单
|
||
```php
|
||
// API: /RiderApi/Order/acceptOrder
|
||
$result = $riderController->acceptOrder([
|
||
'rider_id' => 3,
|
||
'order_id' => $orderId
|
||
]);
|
||
```
|
||
|
||
### 步骤4:配送流程
|
||
|
||
#### 订单状态流转
|
||
```
|
||
0 - 待分配 → 1 - 已接单 → 2 - 已取餐 → 3 - 配送中 → 4 - 已送达
|
||
```
|
||
|
||
#### 更新订单状态
|
||
```php
|
||
// API: /RiderApi/Order/updateOrderStatus
|
||
$result = $riderController->updateOrderStatus([
|
||
'rider_id' => 3,
|
||
'order_id' => $orderId,
|
||
'status' => 2, // 已取餐
|
||
'lat' => 39.9042,
|
||
'lng' => 116.4074
|
||
]);
|
||
```
|
||
|
||
## 🔌 API接口详解
|
||
|
||
### 骑手端核心API
|
||
|
||
#### 1. 获取可接订单列表
|
||
```
|
||
GET /RiderApi/Order/getAvailableOrders
|
||
参数:
|
||
- rider_id: 骑手ID
|
||
- page: 页码 (默认1)
|
||
- limit: 每页数量 (默认10)
|
||
|
||
返回:
|
||
{
|
||
"status": 1,
|
||
"msg": "获取成功",
|
||
"data": {
|
||
"list": [...],
|
||
"total": 5,
|
||
"page": 1,
|
||
"limit": 10
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 2. 接受订单
|
||
```
|
||
POST /RiderApi/Order/acceptOrder
|
||
参数:
|
||
- rider_id: 骑手ID
|
||
- order_id: 订单ID
|
||
|
||
返回:
|
||
{
|
||
"status": 1,
|
||
"msg": "接单成功",
|
||
"data": {
|
||
"order_id": 123,
|
||
"accept_time": "2024-01-15 14:30:00"
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 3. 更新订单状态
|
||
```
|
||
POST /RiderApi/Order/updateOrderStatus
|
||
参数:
|
||
- rider_id: 骑手ID
|
||
- order_id: 订单ID
|
||
- status: 新状态 (1-4)
|
||
- lat: 当前纬度 (可选)
|
||
- lng: 当前经度 (可选)
|
||
|
||
返回:
|
||
{
|
||
"status": 1,
|
||
"msg": "状态更新成功",
|
||
"data": {
|
||
"order_id": 123,
|
||
"new_status": 2,
|
||
"update_time": "2024-01-15 14:35:00"
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 4. 获取当前订单
|
||
```
|
||
GET /RiderApi/Order/getCurrentOrder
|
||
参数:
|
||
- rider_id: 骑手ID
|
||
|
||
返回:
|
||
{
|
||
"status": 1,
|
||
"msg": "获取成功",
|
||
"data": {
|
||
"order_id": 123,
|
||
"order_no": "RO20240115001",
|
||
"status": 2,
|
||
"customer_info": {...},
|
||
"delivery_info": {...}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 管理端API
|
||
|
||
#### 1. 订单分配
|
||
```
|
||
POST /Admin/RiderOrder/dispatchOrder
|
||
参数:
|
||
- bill_id: 订单编号
|
||
- merchant_id: 商户ID
|
||
- store_id: 门店ID
|
||
- rider_id: 骑手ID (可选,用于手动分配)
|
||
- auto_assign: 是否自动分配 (true/false)
|
||
|
||
返回:
|
||
{
|
||
"status": 1,
|
||
"msg": "分配成功",
|
||
"data": {
|
||
"order_id": 123,
|
||
"rider_id": 3,
|
||
"rider_name": "张三",
|
||
"assign_time": "2024-01-15 14:25:00"
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 2. 获取可用骑手
|
||
```
|
||
POST /Admin/RiderOrder/getAvailableRiders
|
||
参数:
|
||
- merchant_id: 商户ID
|
||
- store_id: 门店ID
|
||
- order_lat: 订单纬度
|
||
- order_lng: 订单经度
|
||
|
||
返回:
|
||
{
|
||
"status": 1,
|
||
"msg": "获取成功",
|
||
"data": [
|
||
{
|
||
"id": 3,
|
||
"rider_name": "张三",
|
||
"phone": "13800138000",
|
||
"distance": 1.2,
|
||
"score": 85.5,
|
||
"current_orders": 1,
|
||
"max_orders": 3
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
## 🧪 测试场景
|
||
|
||
### 场景1:正常订单流程测试
|
||
|
||
1. **创建订单** → 2. **自动分配** → 3. **骑手接单** → 4. **配送完成**
|
||
|
||
```bash
|
||
# 运行完整测试
|
||
php test_order_dispatch.php full
|
||
```
|
||
|
||
### 场景2:手动分配测试
|
||
|
||
```php
|
||
// 指定骑手分配
|
||
$dispatch = new \Common\Business\RiderOrderDispatch();
|
||
$result = $dispatch->dispatchOrder([
|
||
'bill_id' => 'TEST_20240115001',
|
||
'rider_id' => 3,
|
||
'auto_assign' => false
|
||
]);
|
||
```
|
||
|
||
### 场景3:高峰期压力测试
|
||
|
||
```php
|
||
// 批量创建订单测试
|
||
for ($i = 0; $i < 10; $i++) {
|
||
$test = new OrderDispatchTest();
|
||
$orderId = $test->createTestOrder();
|
||
$test->testOrderDispatch($orderId);
|
||
}
|
||
```
|
||
|
||
### 场景4:异常情况测试
|
||
|
||
- 无可用骑手
|
||
- 骑手拒绝订单
|
||
- 网络异常
|
||
- 位置信息缺失
|
||
|
||
## 📱 骑手端集成
|
||
|
||
### 移动端接入
|
||
|
||
#### 1. 初始化配置
|
||
```javascript
|
||
// 骑手端配置
|
||
const riderConfig = {
|
||
apiBaseUrl: 'http://your-domain.com/RiderApi',
|
||
riderId: 3,
|
||
autoRefresh: true,
|
||
refreshInterval: 30000 // 30秒
|
||
};
|
||
```
|
||
|
||
#### 2. 获取订单列表
|
||
```javascript
|
||
async function getAvailableOrders() {
|
||
const response = await fetch(`${riderConfig.apiBaseUrl}/Order/getAvailableOrders`, {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify({
|
||
rider_id: riderConfig.riderId,
|
||
page: 1,
|
||
limit: 10
|
||
})
|
||
});
|
||
|
||
const result = await response.json();
|
||
return result;
|
||
}
|
||
```
|
||
|
||
#### 3. 接受订单
|
||
```javascript
|
||
async function acceptOrder(orderId) {
|
||
const response = await fetch(`${riderConfig.apiBaseUrl}/Order/acceptOrder`, {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify({
|
||
rider_id: riderConfig.riderId,
|
||
order_id: orderId
|
||
})
|
||
});
|
||
|
||
const result = await response.json();
|
||
return result;
|
||
}
|
||
```
|
||
|
||
#### 4. 更新位置和状态
|
||
```javascript
|
||
async function updateOrderStatus(orderId, status, location) {
|
||
const response = await fetch(`${riderConfig.apiBaseUrl}/Order/updateOrderStatus`, {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify({
|
||
rider_id: riderConfig.riderId,
|
||
order_id: orderId,
|
||
status: status,
|
||
lat: location.lat,
|
||
lng: location.lng
|
||
})
|
||
});
|
||
|
||
const result = await response.json();
|
||
return result;
|
||
}
|
||
```
|
||
|
||
## 🔧 配置说明
|
||
|
||
### 骑手配置参数
|
||
|
||
```sql
|
||
-- 骑手信息表关键字段
|
||
ALTER TABLE ls_rider_info ADD COLUMN max_orders_per_time INT DEFAULT 3 COMMENT '同时接单上限';
|
||
ALTER TABLE ls_rider_info ADD COLUMN auto_accept_orders TINYINT DEFAULT 0 COMMENT '是否自动接单';
|
||
ALTER TABLE ls_rider_info ADD COLUMN min_delivery_fee DECIMAL(10,2) DEFAULT 0 COMMENT '最低配送费';
|
||
ALTER TABLE ls_rider_info ADD COLUMN max_delivery_distance DECIMAL(10,2) DEFAULT 10 COMMENT '最大配送距离(km)';
|
||
ALTER TABLE ls_rider_info ADD COLUMN work_start_time TIME DEFAULT '08:00:00' COMMENT '工作开始时间';
|
||
ALTER TABLE ls_rider_info ADD COLUMN work_end_time TIME DEFAULT '22:00:00' COMMENT '工作结束时间';
|
||
```
|
||
|
||
### 系统配置参数
|
||
|
||
```php
|
||
// 配置文件 Application/Common/Conf/config.php
|
||
'RIDER_SYSTEM' => [
|
||
'AUTO_DISPATCH_ENABLED' => true, // 启用自动分配
|
||
'MAX_DISPATCH_DISTANCE' => 10, // 最大分配距离(km)
|
||
'DISPATCH_TIMEOUT' => 300, // 分配超时时间(秒)
|
||
'RIDER_RESPONSE_TIMEOUT' => 60, // 骑手响应超时(秒)
|
||
'MAX_RETRY_COUNT' => 3, // 最大重试次数
|
||
'SCORE_WEIGHTS' => [ // 评分权重
|
||
'distance' => 0.4, // 距离权重
|
||
'rating' => 0.3, // 评分权重
|
||
'on_time_rate' => 0.2, // 准时率权重
|
||
'order_count' => 0.1 // 订单数权重
|
||
]
|
||
]
|
||
```
|
||
|
||
## 🚨 故障排除
|
||
|
||
### 常见问题
|
||
|
||
#### 1. 订单分配失败
|
||
**问题**: 订单创建后无法分配给骑手
|
||
**解决方案**:
|
||
- 检查骑手状态 (`work_status = 1` 且 `auth_status = 2`)
|
||
- 确认骑手位置信息完整
|
||
- 验证门店和订单位置信息
|
||
- 检查骑手当前订单数量是否达到上限
|
||
|
||
```sql
|
||
-- 检查骑手状态
|
||
SELECT id, rider_name, work_status, auth_status, current_orders, max_orders_per_time
|
||
FROM ls_rider_info
|
||
WHERE status = 1;
|
||
|
||
-- 检查订单信息
|
||
SELECT id, bill_id, order_status, delivery_lat, delivery_lng, store_lat, store_lng
|
||
FROM ls_rider_order
|
||
WHERE order_status = 0;
|
||
```
|
||
|
||
#### 2. 骑手无法接单
|
||
**问题**: 骑手端显示无可接订单
|
||
**解决方案**:
|
||
- 确认骑手认证状态
|
||
- 检查工作时间设置
|
||
- 验证接单偏好配置
|
||
- 确认网络连接正常
|
||
|
||
```php
|
||
// 调试骑手接单条件
|
||
$riderInfo = M('rider_info')->find($riderId);
|
||
var_dump([
|
||
'work_status' => $riderInfo['work_status'],
|
||
'auth_status' => $riderInfo['auth_status'],
|
||
'current_time' => date('H:i:s'),
|
||
'work_start_time' => $riderInfo['work_start_time'],
|
||
'work_end_time' => $riderInfo['work_end_time']
|
||
]);
|
||
```
|
||
|
||
#### 3. 位置信息异常
|
||
**问题**: 距离计算错误或位置信息缺失
|
||
**解决方案**:
|
||
- 检查GPS坐标格式 (纬度在前,经度在后)
|
||
- 确认坐标系统一致性 (建议使用WGS84)
|
||
- 验证坐标范围合理性
|
||
|
||
```php
|
||
// 验证坐标有效性
|
||
function validateCoordinates($lat, $lng) {
|
||
return ($lat >= -90 && $lat <= 90) && ($lng >= -180 && $lng <= 180);
|
||
}
|
||
```
|
||
|
||
#### 4. 订单状态同步问题
|
||
**问题**: 订单状态更新不及时或不一致
|
||
**解决方案**:
|
||
- 检查数据库连接
|
||
- 确认事务处理正确
|
||
- 验证缓存更新机制
|
||
- 检查并发处理逻辑
|
||
|
||
### 调试工具
|
||
|
||
#### 1. 日志查看
|
||
```bash
|
||
# 查看系统日志
|
||
tail -f Runtime/Logs/Common/24_01_15.log
|
||
|
||
# 查看错误日志
|
||
tail -f Runtime/Logs/Common/24_01_15_error.log
|
||
```
|
||
|
||
#### 2. 数据库调试
|
||
```sql
|
||
-- 开启SQL日志
|
||
SET GLOBAL general_log = 'ON';
|
||
SET GLOBAL general_log_file = '/var/log/mysql/mysql.log';
|
||
|
||
-- 查看慢查询
|
||
SHOW PROCESSLIST;
|
||
```
|
||
|
||
#### 3. 性能监控
|
||
```php
|
||
// 添加性能监控
|
||
$startTime = microtime(true);
|
||
// ... 业务逻辑 ...
|
||
$endTime = microtime(true);
|
||
$executionTime = ($endTime - $startTime) * 1000;
|
||
error_log("执行时间: {$executionTime}ms");
|
||
```
|
||
|
||
## 📈 性能优化
|
||
|
||
### 数据库优化
|
||
|
||
#### 1. 索引优化
|
||
```sql
|
||
-- 骑手信息表索引
|
||
ALTER TABLE ls_rider_info ADD INDEX idx_work_status (work_status, auth_status, status);
|
||
ALTER TABLE ls_rider_info ADD INDEX idx_location (lat, lng);
|
||
|
||
-- 订单表索引
|
||
ALTER TABLE ls_rider_order ADD INDEX idx_status_time (order_status, add_time);
|
||
ALTER TABLE ls_rider_order ADD INDEX idx_rider_status (rider_id, order_status);
|
||
ALTER TABLE ls_rider_order ADD INDEX idx_location (delivery_lat, delivery_lng);
|
||
```
|
||
|
||
#### 2. 查询优化
|
||
```php
|
||
// 使用合适的查询条件
|
||
$riders = M('rider_info')
|
||
->field('id, rider_name, lat, lng, current_orders, max_orders_per_time')
|
||
->where([
|
||
'work_status' => 1,
|
||
'auth_status' => 2,
|
||
'status' => 1,
|
||
'merchant_id' => $merchantId
|
||
])
|
||
->limit(50) // 限制查询数量
|
||
->select();
|
||
```
|
||
|
||
### 缓存策略
|
||
|
||
#### 1. Redis缓存
|
||
```php
|
||
// 缓存骑手位置信息
|
||
$redis = new Redis();
|
||
$redis->setex("rider_location_{$riderId}", 300, json_encode([
|
||
'lat' => $lat,
|
||
'lng' => $lng,
|
||
'update_time' => time()
|
||
]));
|
||
```
|
||
|
||
#### 2. 内存缓存
|
||
```php
|
||
// 使用静态变量缓存计算结果
|
||
class RiderOrderDispatch {
|
||
private static $distanceCache = [];
|
||
|
||
private function calculateDistance($lat1, $lng1, $lat2, $lng2) {
|
||
$key = "{$lat1},{$lng1},{$lat2},{$lng2}";
|
||
if (!isset(self::$distanceCache[$key])) {
|
||
self::$distanceCache[$key] = $this->haversineDistance($lat1, $lng1, $lat2, $lng2);
|
||
}
|
||
return self::$distanceCache[$key];
|
||
}
|
||
}
|
||
```
|
||
|
||
## 📋 部署清单
|
||
|
||
### 生产环境部署
|
||
|
||
#### 1. 环境检查
|
||
- [ ] PHP 版本 >= 5.6
|
||
- [ ] MySQL 版本 >= 5.7
|
||
- [ ] Redis 服务正常
|
||
- [ ] 网络连接稳定
|
||
- [ ] SSL证书配置
|
||
|
||
#### 2. 数据库准备
|
||
- [ ] 执行数据库迁移脚本
|
||
- [ ] 创建必要的索引
|
||
- [ ] 配置数据库连接池
|
||
- [ ] 设置备份策略
|
||
|
||
#### 3. 配置文件
|
||
- [ ] 更新数据库配置
|
||
- [ ] 设置Redis连接
|
||
- [ ] 配置日志级别
|
||
- [ ] 设置错误报告
|
||
|
||
#### 4. 测试验证
|
||
- [ ] 运行单元测试
|
||
- [ ] 执行集成测试
|
||
- [ ] 进行压力测试
|
||
- [ ] 验证API接口
|
||
|
||
#### 5. 监控告警
|
||
- [ ] 配置系统监控
|
||
- [ ] 设置错误告警
|
||
- [ ] 建立日志分析
|
||
- [ ] 制定应急预案
|
||
|
||
## 📞 技术支持
|
||
|
||
如果在使用过程中遇到问题,请按以下步骤排查:
|
||
|
||
1. **查看日志文件** - 检查系统和错误日志
|
||
2. **运行测试脚本** - 使用 `test_order_dispatch.php` 验证功能
|
||
3. **检查配置** - 确认数据库和系统配置正确
|
||
4. **联系技术支持** - 提供详细的错误信息和日志
|
||
|
||
---
|
||
|
||
**最后更新**: 2024年1月15日
|
||
**版本**: v1.0.0
|
||
**维护者**: 骑手订单分配系统开发团队 |