display(); } /** * 获取待分配订单列表 * @return void */ public function getPendingOrders() { $param = I('post.'); $page = isset($param['page']) ? intval($param['page']) : 1; $pageSize = isset($param['page_size']) ? intval($param['page_size']) : 20; $storeId = isset($param['store_id']) ? intval($param['store_id']) : 0; $billOrderModel = D('RetailBillOrder'); $billOnlineModel = D('RetailBillOnline'); // 构建查询条件 $where = [ 'bo.type' => 1, // 商城订单 'bo.pay_state' => 1, // 已支付 'bol.pickup_type' => 2, // 配送订单 'bol.status' => 1, // 未发货 ]; if ($storeId > 0) { $where['bo.store_id'] = $storeId; } // 排除已分配给骑手的订单 $riderOrderModel = D('RiderOrder'); $assignedOrderIds = $riderOrderModel->getColumn(['order_status' => ['neq', -1]], 'bill_id'); if (!empty($assignedOrderIds)) { $where['bo.id'] = ['not in', $assignedOrderIds]; } // 获取订单列表 $orders = $billOrderModel->alias('bo') ->join('ls_retail_bill_online bol ON bo.id = bol.bill_id') ->join('ls_retail_store rs ON bo.store_id = rs.id') ->where($where) ->field('bo.*, bol.pickup_type, bol.status, bol.user_name, bol.user_phone, bol.user_address, rs.store_name, rs.lat as store_lat, rs.lng as store_lng') ->order('bo.add_time DESC') ->page($page, $pageSize) ->select(); $total = $billOrderModel->alias('bo') ->join('ls_retail_bill_online bol ON bo.id = bol.bill_id') ->where($where) ->count(); $result = [ 'list' => $orders ?: [], 'total' => $total, 'page' => $page, 'page_size' => $pageSize ]; $this->ajaxReturn(callBack(statusCode()['success'], '获取待分配订单成功', $result)); } /** * 手动分配订单 * @return void */ public function manualDispatch() { $param = I('post.'); if (empty($param['bill_id'])) { $this->ajaxReturn(callBack(statusCode()['error'], '订单ID不能为空')); } if (empty($param['rider_id'])) { $this->ajaxReturn(callBack(statusCode()['error'], '请选择骑手')); } // 获取订单信息 $billOrderModel = D('RetailBillOrder'); $orderInfo = $billOrderModel->getFind(['id' => $param['bill_id']]); if (empty($orderInfo)) { $this->ajaxReturn(callBack(statusCode()['error'], '订单不存在')); } $riderOrderDispatch = new RiderOrderDispatch(); $dispatchParam = [ 'bill_id' => $param['bill_id'], 'merchant_id' => $orderInfo['merchant_id'], 'store_id' => $orderInfo['store_id'], 'auto_assign' => false, 'rider_id' => $param['rider_id'] ]; $result = $riderOrderDispatch->dispatchOrder($dispatchParam); $this->ajaxReturn($result); } /** * 自动分配订单 * @return void */ public function autoDispatch() { $param = I('post.'); if (empty($param['bill_id'])) { $this->ajaxReturn(callBack(statusCode()['error'], '订单ID不能为空')); } // 获取订单信息 $billOrderModel = D('RetailBillOrder'); $orderInfo = $billOrderModel->getFind(['id' => $param['bill_id']]); if (empty($orderInfo)) { $this->ajaxReturn(callBack(statusCode()['error'], '订单不存在')); } $riderOrderDispatch = new RiderOrderDispatch(); $dispatchParam = [ 'bill_id' => $param['bill_id'], 'merchant_id' => $orderInfo['merchant_id'], 'store_id' => $orderInfo['store_id'], 'auto_assign' => true ]; $result = $riderOrderDispatch->dispatchOrder($dispatchParam); $this->ajaxReturn($result); } /** * 获取可用骑手列表 * @return void */ public function getAvailableRiders() { $param = I('post.'); if (empty($param['bill_id'])) { $this->ajaxReturn(callBack(statusCode()['error'], '订单ID不能为空')); } // 获取订单信息 $billOrderModel = D('RetailBillOrder'); $orderInfo = $billOrderModel->getFind(['id' => $param['bill_id']]); if (empty($orderInfo)) { $this->ajaxReturn(callBack(statusCode()['error'], '订单不存在')); } $riderOrderDispatch = new RiderOrderDispatch(); $dispatchParam = [ 'bill_id' => $param['bill_id'], 'merchant_id' => $orderInfo['merchant_id'], 'store_id' => $orderInfo['store_id'], 'auto_assign' => false ]; $result = $riderOrderDispatch->dispatchOrder($dispatchParam); $this->ajaxReturn($result); } /** * 骑手订单管理页面 * @return void */ public function riderOrders() { $this->display(); } /** * 获取骑手订单列表 * @return void */ public function getRiderOrderList() { $param = I('post.'); $page = isset($param['page']) ? intval($param['page']) : 1; $pageSize = isset($param['page_size']) ? intval($param['page_size']) : 20; $riderId = isset($param['rider_id']) ? intval($param['rider_id']) : 0; $orderStatus = isset($param['order_status']) ? $param['order_status'] : ''; $storeId = isset($param['store_id']) ? intval($param['store_id']) : 0; $riderOrderModel = D('RiderOrder'); // 构建查询条件 $where = []; if ($riderId > 0) { $where['ro.rider_id'] = $riderId; } if ($orderStatus !== '') { $where['ro.order_status'] = $orderStatus; } if ($storeId > 0) { $where['ro.store_id'] = $storeId; } // 获取订单列表 $orders = $riderOrderModel->alias('ro') ->join('ls_rider_info ri ON ro.rider_id = ri.id') ->join('ls_retail_store rs ON ro.store_id = rs.id') ->where($where) ->field('ro.*, ri.real_name as rider_name, ri.phone as rider_phone, rs.store_name') ->order('ro.add_time DESC') ->page($page, $pageSize) ->select(); $total = $riderOrderModel->alias('ro')->where($where)->count(); // 处理订单状态显示 import('Common.Business.OrderStatusUtil'); $statusMap = [ '0' => \Common\Business\OrderStatusUtil::getStatusText('pending'), '1' => \Common\Business\OrderStatusUtil::getStatusText('accepted'), '2' => \Common\Business\OrderStatusUtil::getStatusText('picking_up'), '3' => \Common\Business\OrderStatusUtil::getStatusText('delivering'), '6' => \Common\Business\OrderStatusUtil::getStatusText('completed'), '8' => \Common\Business\OrderStatusUtil::getStatusText('cancelled'), '7' => \Common\Business\OrderStatusUtil::getStatusText('exception') ]; foreach ($orders as &$order) { $order['status_text'] = isset($statusMap[$order['order_status']]) ? $statusMap[$order['order_status']] : '未知'; // 添加配送凭证信息 if ($order['order_status'] == 6) { // 已送达订单 $order['has_receipt'] = !empty($order['delivery_receipt_type']); $order['receipt_type'] = $order['delivery_receipt_type']; $order['receipt_upload_time'] = $order['receipt_upload_time']; } } $result = [ 'list' => $orders ?: [], 'total' => $total, 'page' => $page, 'page_size' => $pageSize ]; $this->ajaxReturn(callBack(statusCode()['success'], '获取骑手订单列表成功', $result)); } /** * 获取骑手列表 * @return void */ public function getRiderList() { $param = I('post.'); $storeId = isset($param['store_id']) ? intval($param['store_id']) : 0; $workStatus = isset($param['work_status']) ? intval($param['work_status']) : -1; $riderInfoModel = D('RiderInfo'); // 构建查询条件 $where = [ 'auth_status' => 2, // 已认证 'status' => 1 // 正常状态 ]; if ($storeId > 0) { $where['store_id'] = $storeId; } if ($workStatus >= 0) { $where['work_status'] = $workStatus; } $riders = $riderInfoModel->getList($where, 'id,real_name,phone,work_status,rating,on_time_rate,max_orders_per_time'); // 获取每个骑手的当前订单数量 $riderOrderModel = D('RiderOrder'); foreach ($riders as &$rider) { import('@.Common.Business.OrderStatusUtil'); $inProgress = \Common\Business\OrderStatusUtil::getInProgressStatuses(); $rider['current_orders'] = $riderOrderModel->getCount([ 'rider_id' => $rider['id'], 'order_status' => ['in', implode(',', $inProgress)] ]); $rider['work_status_text'] = $rider['work_status'] == 1 ? '在线' : '离线'; } $this->ajaxReturn(callBack(statusCode()['success'], '获取骑手列表成功', $riders)); } /** * 批量分配订单 * @return void */ public function batchDispatch() { $param = I('post.'); if (empty($param['bill_ids']) || !is_array($param['bill_ids'])) { $this->ajaxReturn(callBack(statusCode()['error'], '请选择要分配的订单')); } $riderOrderDispatch = new RiderOrderDispatch(); $successCount = 0; $failCount = 0; $errors = []; foreach ($param['bill_ids'] as $billId) { // 获取订单信息 $billOrderModel = D('RetailBillOrder'); $orderInfo = $billOrderModel->getFind(['id' => $billId]); if (empty($orderInfo)) { $failCount++; $errors[] = "订单ID {$billId} 不存在"; continue; } $dispatchParam = [ 'bill_id' => $billId, 'merchant_id' => $orderInfo['merchant_id'], 'store_id' => $orderInfo['store_id'], 'auto_assign' => true ]; $result = $riderOrderDispatch->dispatchOrder($dispatchParam); if ($result['status'] == 1) { $successCount++; } else { $failCount++; $errors[] = "订单ID {$billId}: " . $result['msg']; } } $message = "批量分配完成,成功:{$successCount}个,失败:{$failCount}个"; $this->ajaxReturn(callBack(statusCode()['success'], $message, [ 'success_count' => $successCount, 'fail_count' => $failCount, 'errors' => $errors ])); } /** * 获取订单配送凭证详情 * @return void */ public function getOrderReceiptDetail() { $param = I('post.'); if (empty($param['order_id'])) { $this->ajaxReturn(callBack(statusCode()['error'], '订单ID不能为空')); } $riderOrderModel = D('RiderOrder'); // 获取订单配送凭证信息 $order = $riderOrderModel->alias('ro') ->join('ls_rider_info ri ON ro.rider_id = ri.id') ->join('ls_retail_store rs ON ro.store_id = rs.id') ->where(['ro.id' => $param['order_id']]) ->field('ro.id, ro.order_status, ro.delivery_receipt_type, ro.delivery_receipt_photos, ro.delivery_signature, ro.delivery_receipt_code, ro.delivery_receipt_remark, ro.receipt_upload_time, ro.delivery_time, ro.customer_name, ro.customer_phone, ro.customer_address, ri.real_name as rider_name, ri.phone as rider_phone, rs.store_name') ->find(); if (empty($order)) { $this->ajaxReturn(callBack(statusCode()['error'], '订单不存在')); } if ($order['order_status'] != 6) { $this->ajaxReturn(callBack(statusCode()['error'], '订单未完成配送')); } // 格式化配送凭证数据 $receiptData = [ 'order_id' => $order['id'], 'order_status' => $order['order_status'], 'delivery_time' => $order['delivery_time'], 'receipt_type' => $order['delivery_receipt_type'], 'receipt_type_text' => $this->getReceiptTypeText($order['delivery_receipt_type']), 'receipt_photos' => $order['delivery_receipt_photos'] ? explode(',', $order['delivery_receipt_photos']) : [], 'delivery_signature' => $order['delivery_signature'], 'receipt_code' => $order['delivery_receipt_code'], 'receipt_remark' => $order['delivery_receipt_remark'], 'upload_time' => $order['receipt_upload_time'], 'customer_info' => [ 'name' => $order['customer_name'], 'phone' => $order['customer_phone'], 'address' => $order['customer_address'] ], 'rider_info' => [ 'name' => $order['rider_name'], 'phone' => $order['rider_phone'] ], 'store_name' => $order['store_name'] ]; $this->ajaxReturn(callBack(statusCode()['success'], '获取配送凭证成功', $receiptData)); } /** * 获取凭证类型文本 * @param int $type * @return string */ private function getReceiptTypeText($type) { $typeMap = [ 1 => '照片凭证', 2 => '签名凭证', 3 => '验证码凭证' ]; return isset($typeMap[$type]) ? $typeMap[$type] : '未知类型'; } /** * 订单重新分配 * @return void */ public function reassignOrder() { $param = I('post.'); if (empty($param['rider_order_id'])) { $this->ajaxReturn(callBack(statusCode()['error'], '骑手订单ID不能为空')); } $riderOrderModel = D('RiderOrder'); // 获取骑手订单信息 $riderOrder = $riderOrderModel->getFind(['id' => $param['rider_order_id']]); if (empty($riderOrder)) { $this->ajaxReturn(callBack(statusCode()['error'], '骑手订单不存在')); } // 检查订单状态 if ($riderOrder['order_status'] > 1) { $this->ajaxReturn(callBack(statusCode()['error'], '订单已开始配送,无法重新分配')); } // 取消当前分配 $riderOrderModel->updateOrder(['id' => $param['rider_order_id']], [ 'order_status' => -2, // 已取消 'cancel_time' => date('Y-m-d H:i:s'), 'cancel_reason' => '管理员重新分配', 'updated_at' => date('Y-m-d H:i:s') ]); // 重新分配 $riderOrderDispatch = new RiderOrderDispatch(); $dispatchParam = [ 'bill_id' => $riderOrder['bill_id'], 'merchant_id' => $riderOrder['merchant_id'], 'store_id' => $riderOrder['store_id'], 'auto_assign' => true ]; $result = $riderOrderDispatch->dispatchOrder($dispatchParam); $this->ajaxReturn($result); } /** * 获取订单统计数据 * @return void */ public function getOrderStats() { $param = I('post.'); $storeId = isset($param['store_id']) ? intval($param['store_id']) : 0; $dateRange = isset($param['date_range']) ? $param['date_range'] : 'today'; // 计算日期范围 switch ($dateRange) { case 'today': $startDate = date('Y-m-d 00:00:00'); $endDate = date('Y-m-d 23:59:59'); break; case 'yesterday': $startDate = date('Y-m-d 00:00:00', strtotime('-1 day')); $endDate = date('Y-m-d 23:59:59', strtotime('-1 day')); break; case 'week': $startDate = date('Y-m-d 00:00:00', strtotime('-7 days')); $endDate = date('Y-m-d 23:59:59'); break; case 'month': $startDate = date('Y-m-01 00:00:00'); $endDate = date('Y-m-d 23:59:59'); break; default: $startDate = date('Y-m-d 00:00:00'); $endDate = date('Y-m-d 23:59:59'); } $riderOrderModel = D('RiderOrder'); // 构建基础查询条件 $baseWhere = [ 'add_time' => ['between', [$startDate, $endDate]] ]; if ($storeId > 0) { $baseWhere['store_id'] = $storeId; } // 统计各状态订单数量 $stats = [ 'total_orders' => $riderOrderModel->getCount($baseWhere), 'pending_orders' => $riderOrderModel->getCount(array_merge($baseWhere, ['order_status' => 0])), 'accepted_orders' => $riderOrderModel->getCount(array_merge($baseWhere, ['order_status' => 1])), 'delivering_orders' => $riderOrderModel->getCount(array_merge($baseWhere, ['order_status' => ['in', \Common\Business\OrderStatusUtil::getInTransitStatuses()]])), 'completed_orders' => $riderOrderModel->getCount(array_merge($baseWhere, ['order_status' => 6])), 'exception_orders' => $riderOrderModel->getCount(array_merge($baseWhere, ['order_status' => 7])), 'cancelled_orders' => $riderOrderModel->getCount(array_merge($baseWhere, ['order_status' => 8])), ]; // 计算完成率 $stats['completion_rate'] = $stats['total_orders'] > 0 ? round(($stats['completed_orders'] / $stats['total_orders']) * 100, 2) : 0; // 计算平均配送时间 $avgDeliveryTime = $riderOrderModel->where(array_merge($baseWhere, ['order_status' => 6])) ->avg('TIMESTAMPDIFF(MINUTE, accept_time, delivery_time)'); $stats['avg_delivery_time'] = round($avgDeliveryTime ?: 0, 2); $this->ajaxReturn(callBack(statusCode()['success'], '获取统计数据成功', $stats)); } }