文件
mashangyoujiu/_ai_archive/docs/订单分配方案.md

14 KiB

骑手端订单智能分配方案

一、现状分析

1.1 现有系统架构

  • 订单表结构: ls_retail_bill_order(主订单)+ ls_rider_order(配送订单)
  • 骑手管理: ls_rider_info(骑手信息)+ 相关统计和收入表
  • 分配方式: 主要依赖手动分配和骑手抢单,缺乏智能化分配

1.2 存在问题

  1. 效率低下: 手动分配耗时,影响配送时效
  2. 分配不均: 缺乏负载均衡,部分骑手过忙,部分闲置
  3. 距离优化不足: 未考虑骑手位置与商家/客户距离
  4. 成本控制薄弱: 没有综合考虑配送成本和收益

二、智能分配策略设计

2.1 分配模式

采用混合分配模式:

  • 智能推荐 + 骑手抢单 + 手动干预

2.2 核心分配算法

2.2.1 骑手筛选条件

-- 可分配骑手筛选条件
SELECT * FROM ls_rider_info 
WHERE status = 1                    -- 正常状态
  AND auth_status = 2               -- 已认证
  AND health_status = 1             -- 健康证通过
  AND work_status IN (1, 2)         -- 在线或忙碌但未达上限
  AND (SELECT COUNT(*) FROM ls_rider_order 
       WHERE rider_id = ls_rider_info.id 
         AND order_status IN (1,2,3,4,5)) < max_orders_per_time  -- 未达最大接单数

2.2.2 距离权重计算

/**
 * 计算骑手到商家的距离权重
 * @param float $rider_lat 骑手纬度
 * @param float $rider_lng 骑手经度  
 * @param float $store_lat 商家纬度
 * @param float $store_lng 商家经度
 * @return float 距离权重分数 (0-100)
 */
function calculateDistanceScore($rider_lat, $rider_lng, $store_lat, $store_lng) {
    $distance = getDistance($rider_lat, $rider_lng, $store_lat, $store_lng);
    
    if ($distance <= 1) return 100;      // 1公里内满分
    if ($distance <= 3) return 80;       // 1-3公里
    if ($distance <= 5) return 60;       // 3-5公里
    if ($distance <= 8) return 40;       // 5-8公里
    if ($distance <= 12) return 20;      // 8-12公里
    return 0;                            // 超过12公里不推荐
}

2.2.3 骑手能力评分

/**
 * 计算骑手综合能力评分
 * @param array $rider 骑手信息
 * @return float 能力评分 (0-100)
 */
function calculateRiderScore($rider) {
    $score = 0;
    
    // 评分权重 (30%)
    $score += ($rider['rating'] / 5) * 30;
    
    // 准时率权重 (25%)
    $score += ($rider['on_time_rate'] / 100) * 25;
    
    // 完成订单数权重 (20%) - 经验值
    $experience_score = min(($rider['completed_orders'] / 1000) * 20, 20);
    $score += $experience_score;
    
    // 当前负载权重 (15%) - 负载越低分数越高
    $current_orders = getCurrentOrderCount($rider['id']);
    $load_score = (1 - ($current_orders / $rider['max_orders_per_time'])) * 15;
    $score += $load_score;
    
    // 在线时长权重 (10%) - 今日在线时长
    $online_hours = getTodayOnlineHours($rider['id']);
    $time_score = min(($online_hours / 8) * 10, 10);
    $score += $time_score;
    
    return $score;
}

2.2.4 订单优先级计算

/**
 * 计算订单优先级
 * @param array $order 订单信息
 * @return int 优先级分数 (1-100)
 */
function calculateOrderPriority($order) {
    $priority = 50; // 基础优先级
    
    // VIP客户 +20
    if ($order['is_vip']) $priority += 20;
    
    // 预约单 +15
    if ($order['order_type'] == 2) $priority += 15;
    
    // 高价值订单 +10
    if ($order['all_money'] > 100) $priority += 10;
    
    // 距离远的订单 +5 (避免无人接单)
    if ($order['distance'] > 5) $priority += 5;
    
    // 等待时间过长 +时间权重
    $wait_minutes = (time() - strtotime($order['add_time'])) / 60;
    if ($wait_minutes > 10) $priority += min($wait_minutes - 10, 20);
    
    return min($priority, 100);
}

2.3 智能分配流程

2.3.1 自动分配流程

1. 新订单产生 → 触发分配任务
2. 筛选可用骑手 → 应用筛选条件
3. 计算匹配度 → 距离 + 能力 + 偏好匹配
4. 排序推荐 → 按综合评分排序
5. 推送通知 → 向前3名骑手推送
6. 等待响应 → 30秒内等待接单
7. 超时处理 → 扩大范围或转手动分配

2.3.2 匹配度计算公式

/**
 * 计算骑手与订单的匹配度
 */
function calculateMatchScore($rider, $order) {
    // 距离权重 40%
    $distance_score = calculateDistanceScore(
        $rider['last_location_lat'], 
        $rider['last_location_lng'],
        $order['store_lat'], 
        $order['store_lng']
    ) * 0.4;
    
    // 骑手能力 35%
    $rider_score = calculateRiderScore($rider) * 0.35;
    
    // 订单偏好匹配 15%
    $preference_score = checkOrderPreference($rider, $order) * 0.15;
    
    // 时间匹配 10%
    $time_score = checkTimePreference($rider, $order) * 0.1;
    
    return $distance_score + $rider_score + $preference_score + $time_score;
}

三、分配策略细化

3.1 分时段策略

  • 早高峰 (7:00-9:00): 优先就近分配,减少等待时间
  • 午高峰 (11:00-13:00): 负载均衡优先,避免骑手过载
  • 晚高峰 (17:00-20:00): 综合考虑距离和能力
  • 其他时段: 标准分配策略

3.2 特殊订单处理

  • VIP订单: 优先分配给高评分骑手
  • 预约订单: 提前30分钟开始分配
  • 紧急订单: 立即分配给最近的可用骑手
  • 大额订单: 分配给经验丰富的骑手

3.3 负载均衡机制

/**
 * 负载均衡调整
 */
function adjustForLoadBalance($candidates) {
    foreach ($candidates as &$candidate) {
        $current_load = getCurrentOrderCount($candidate['rider_id']);
        $max_load = $candidate['max_orders_per_time'];
        $load_ratio = $current_load / $max_load;
        
        // 负载过高降低匹配度
        if ($load_ratio > 0.8) {
            $candidate['match_score'] *= 0.7;
        } elseif ($load_ratio < 0.3) {
            // 负载过低提升匹配度
            $candidate['match_score'] *= 1.2;
        }
    }
    return $candidates;
}

四、技术实现方案

4.1 数据库设计优化

4.1.1 新增配置表

-- 分配规则配置表
CREATE TABLE `ls_allocation_config` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `config_key` varchar(50) NOT NULL COMMENT '配置键',
  `config_value` text NOT NULL COMMENT '配置值(JSON)',
  `description` varchar(255) DEFAULT '' COMMENT '配置描述',
  `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `config_key` (`config_key`)
) COMMENT='订单分配配置表';

-- 分配记录表
CREATE TABLE `ls_allocation_log` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `order_id` int(11) NOT NULL COMMENT '订单ID',
  `allocation_type` tinyint(1) NOT NULL COMMENT '分配类型:1自动2手动3抢单',
  `candidate_riders` text COMMENT '候选骑手列表(JSON)',
  `selected_rider_id` int(11) DEFAULT 0 COMMENT '选中的骑手ID',
  `allocation_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '分配时间',
  `response_time` int(11) DEFAULT 0 COMMENT '响应时间(秒)',
  `allocation_result` tinyint(1) DEFAULT 0 COMMENT '分配结果:0失败1成功',
  `failure_reason` varchar(255) DEFAULT '' COMMENT '失败原因',
  PRIMARY KEY (`id`),
  KEY `order_id` (`order_id`),
  KEY `allocation_time` (`allocation_time`)
) COMMENT='订单分配日志表';

4.1.2 骑手表字段扩展

-- 为ls_rider_info表添加分配相关字段
ALTER TABLE `ls_rider_info` 
ADD COLUMN `allocation_score` decimal(5,2) DEFAULT 0.00 COMMENT '分配评分',
ADD COLUMN `last_allocation_time` datetime DEFAULT NULL COMMENT '最后分配时间',
ADD COLUMN `allocation_count_today` int(11) DEFAULT 0 COMMENT '今日分配次数',
ADD COLUMN `refuse_count_today` int(11) DEFAULT 0 COMMENT '今日拒单次数',
ADD COLUMN `auto_accept_conditions` text COMMENT '自动接单条件(JSON)';

4.2 核心服务类设计

4.2.1 订单分配服务

<?php
/**
 * 订单分配服务类
 */
class OrderAllocationService {
    
    /**
     * 主分配方法
     */
    public function allocateOrder($order_id) {
        $order = $this->getOrderInfo($order_id);
        if (!$order) return false;
        
        // 1. 获取候选骑手
        $candidates = $this->getCandidateRiders($order);
        
        // 2. 计算匹配度
        $scored_candidates = $this->scoreRiders($candidates, $order);
        
        // 3. 负载均衡调整
        $balanced_candidates = $this->adjustForLoadBalance($scored_candidates);
        
        // 4. 排序并选择前N名
        $top_candidates = $this->selectTopCandidates($balanced_candidates, 3);
        
        // 5. 推送通知
        $result = $this->notifyRiders($top_candidates, $order);
        
        // 6. 记录分配日志
        $this->logAllocation($order_id, $top_candidates, $result);
        
        return $result;
    }
    
    /**
     * 获取候选骑手
     */
    private function getCandidateRiders($order) {
        // 实现骑手筛选逻辑
    }
    
    /**
     * 计算骑手评分
     */
    private function scoreRiders($candidates, $order) {
        // 实现评分算法
    }
    
    // ... 其他方法
}

4.2.2 分配任务队列

<?php
/**
 * 分配任务队列处理
 */
class AllocationQueue {
    
    /**
     * 添加分配任务
     */
    public function addTask($order_id, $priority = 'normal') {
        $task = [
            'order_id' => $order_id,
            'priority' => $priority,
            'created_at' => time(),
            'attempts' => 0
        ];
        
        // 添加到Redis队列
        $this->redis->lpush('allocation_queue', json_encode($task));
    }
    
    /**
     * 处理队列任务
     */
    public function processQueue() {
        while (true) {
            $task_data = $this->redis->brpop('allocation_queue', 1);
            if ($task_data) {
                $task = json_decode($task_data[1], true);
                $this->processTask($task);
            }
        }
    }
    
    private function processTask($task) {
        $allocation_service = new OrderAllocationService();
        $result = $allocation_service->allocateOrder($task['order_id']);
        
        if (!$result && $task['attempts'] < 3) {
            // 重试机制
            $task['attempts']++;
            $this->addTask($task['order_id'], 'retry');
        }
    }
}

4.3 API接口设计

4.3.1 自动分配接口

/**
 * 触发自动分配
 * POST /api/allocation/auto
 */
public function autoAllocate() {
    $order_id = I('order_id', 0, 'intval');
    
    if (!$order_id) {
        $this->ajaxReturn(['code' => 400, 'msg' => '订单ID不能为空']);
    }
    
    $allocation_service = new OrderAllocationService();
    $result = $allocation_service->allocateOrder($order_id);
    
    if ($result) {
        $this->ajaxReturn(['code' => 200, 'msg' => '分配成功', 'data' => $result]);
    } else {
        $this->ajaxReturn(['code' => 500, 'msg' => '分配失败']);
    }
}

4.3.2 骑手推荐接口

/**
 * 获取推荐骑手列表
 * GET /api/allocation/recommend
 */
public function getRecommendRiders() {
    $order_id = I('order_id', 0, 'intval');
    $limit = I('limit', 5, 'intval');
    
    $allocation_service = new OrderAllocationService();
    $recommendations = $allocation_service->getRecommendations($order_id, $limit);
    
    $this->ajaxReturn([
        'code' => 200,
        'msg' => '获取成功',
        'data' => $recommendations
    ]);
}

4.4 前端界面优化

4.4.1 智能分配面板

<!-- 订单分配面板 -->
<div class="allocation-panel">
    <div class="order-info">
        <h3>订单 #{{ order.order_no }}</h3>
        <p>商家:{{ order.store_name }}</p>
        <p>距离:{{ order.distance }}km</p>
        <p>配送费:¥{{ order.delivery_fee }}</p>
    </div>
    
    <div class="allocation-options">
        <el-button type="primary" @click="autoAllocate">智能分配</el-button>
        <el-button @click="showRecommendations">查看推荐</el-button>
        <el-button @click="manualAssign">手动分配</el-button>
    </div>
    
    <div class="recommendations" v-if="showRecommendList">
        <h4>推荐骑手</h4>
        <div v-for="rider in recommendations" :key="rider.id" class="rider-card">
            <div class="rider-info">
                <img :src="rider.avatar" class="avatar">
                <div class="details">
                    <h5>{{ rider.name }}</h5>
                    <p>评分:{{ rider.rating }}⭐</p>
                    <p>距离:{{ rider.distance }}km</p>
                    <p>匹配度:{{ rider.match_score }}%</p>
                </div>
            </div>
            <el-button size="mini" @click="assignToRider(rider.id)">分配</el-button>
        </div>
    </div>
</div>

五、实施计划

5.1 第一阶段:基础功能 (2周)

  • 数据库表结构调整
  • 核心分配算法实现
  • 基础API接口开发
  • 简单的管理后台界面

5.2 第二阶段:智能优化 (2周)

  • 机器学习模型训练
  • 实时数据分析
  • 分配效果监控
  • 骑手端推送优化

5.3 第三阶段:完善优化 (1周)

  • 性能优化
  • 异常处理完善
  • 用户体验优化
  • 数据统计分析

六、预期效果

6.1 效率提升

  • 分配时间: 从平均5分钟降低到30秒内
  • 接单率: 提升至85%以上
  • 配送时效: 平均配送时间缩短15%

6.2 成本控制

  • 人工成本: 减少50%的手动分配工作量
  • 配送成本: 通过距离优化降低10%的配送成本
  • 客户满意度: 提升20%的客户满意度

6.3 数据驱动

  • 实时监控: 分配成功率、响应时间等关键指标
  • 智能调优: 基于历史数据持续优化分配算法
  • 预测分析: 预测高峰期订单量,提前调配资源

七、风险控制

7.1 技术风险

  • 算法准确性: 建立A/B测试机制,逐步优化
  • 系统稳定性: 设置降级机制,确保服务可用性
  • 数据安全: 加强位置数据和个人信息保护

7.2 业务风险

  • 骑手适应性: 提供培训和激励机制
  • 客户体验: 建立反馈机制,及时调整策略
  • 成本控制: 设置分配成本上限,避免过度优化

这个方案结合了现有系统的特点,提供了一个渐进式的智能化升级路径,既保证了系统的稳定性,又能显著提升订单分配的效率和准确性。