文件
mashangyoujiu/_ai_archive/docs/ORDER_DISPATCH_GUIDE.md

14 KiB

骑手订单分配系统 - 测试与发布指南

📋 概述

本指南详细说明如何测试和发布订单到骑手端,包括完整的操作流程、API接口使用方法和故障排除指南。

🚀 快速开始

1. 运行测试脚本

# 完整测试流程
php test_order_dispatch.php

# 或者通过Web访问
http://your-domain.com/test_order_dispatch.php

2. 查看系统状态

# 查看骑手和订单状态
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 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:订单分配

自动分配

$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
]);

手动分配

$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:骑手接单

获取可接订单

// API: /RiderApi/Order/getAvailableOrders
$orders = $riderController->getAvailableOrders([
    'rider_id' => 3,
    'page' => 1,
    'limit' => 10
]);

接受订单

// API: /RiderApi/Order/acceptOrder
$result = $riderController->acceptOrder([
    'rider_id' => 3,
    'order_id' => $orderId
]);

步骤4:配送流程

订单状态流转

0 - 待分配 → 1 - 已接单 → 2 - 已取餐 → 3 - 配送中 → 4 - 已送达

更新订单状态

// 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. 配送完成
# 运行完整测试
php test_order_dispatch.php full

场景2:手动分配测试

// 指定骑手分配
$dispatch = new \Common\Business\RiderOrderDispatch();
$result = $dispatch->dispatchOrder([
    'bill_id' => 'TEST_20240115001',
    'rider_id' => 3,
    'auto_assign' => false
]);

场景3:高峰期压力测试

// 批量创建订单测试
for ($i = 0; $i < 10; $i++) {
    $test = new OrderDispatchTest();
    $orderId = $test->createTestOrder();
    $test->testOrderDispatch($orderId);
}

场景4:异常情况测试

  • 无可用骑手
  • 骑手拒绝订单
  • 网络异常
  • 位置信息缺失

📱 骑手端集成

移动端接入

1. 初始化配置

// 骑手端配置
const riderConfig = {
    apiBaseUrl: 'http://your-domain.com/RiderApi',
    riderId: 3,
    autoRefresh: true,
    refreshInterval: 30000 // 30秒
};

2. 获取订单列表

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. 接受订单

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. 更新位置和状态

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;
}

🔧 配置说明

骑手配置参数

-- 骑手信息表关键字段
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 '工作结束时间';

系统配置参数

// 配置文件 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)
  • 确认骑手位置信息完整
  • 验证门店和订单位置信息
  • 检查骑手当前订单数量是否达到上限
-- 检查骑手状态
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. 骑手无法接单

问题: 骑手端显示无可接订单 解决方案:

  • 确认骑手认证状态
  • 检查工作时间设置
  • 验证接单偏好配置
  • 确认网络连接正常
// 调试骑手接单条件
$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)
  • 验证坐标范围合理性
// 验证坐标有效性
function validateCoordinates($lat, $lng) {
    return ($lat >= -90 && $lat <= 90) && ($lng >= -180 && $lng <= 180);
}

4. 订单状态同步问题

问题: 订单状态更新不及时或不一致 解决方案:

  • 检查数据库连接
  • 确认事务处理正确
  • 验证缓存更新机制
  • 检查并发处理逻辑

调试工具

1. 日志查看

# 查看系统日志
tail -f Runtime/Logs/Common/24_01_15.log

# 查看错误日志
tail -f Runtime/Logs/Common/24_01_15_error.log

2. 数据库调试

-- 开启SQL日志
SET GLOBAL general_log = 'ON';
SET GLOBAL general_log_file = '/var/log/mysql/mysql.log';

-- 查看慢查询
SHOW PROCESSLIST;

3. 性能监控

// 添加性能监控
$startTime = microtime(true);
// ... 业务逻辑 ...
$endTime = microtime(true);
$executionTime = ($endTime - $startTime) * 1000;
error_log("执行时间: {$executionTime}ms");

📈 性能优化

数据库优化

1. 索引优化

-- 骑手信息表索引
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. 查询优化

// 使用合适的查询条件
$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缓存

// 缓存骑手位置信息
$redis = new Redis();
$redis->setex("rider_location_{$riderId}", 300, json_encode([
    'lat' => $lat,
    'lng' => $lng,
    'update_time' => time()
]));

2. 内存缓存

// 使用静态变量缓存计算结果
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
维护者: 骑手订单分配系统开发团队