riderId; $rider = $this->riderInfo; $lat = $this->getRequestParam('lat', 0); $lng = $this->getRequestParam('lng', 0); $page = $this->getRequestParam('page', 1); $limit = $this->getRequestParam('limit', 30); if (!$rider || $rider['status'] != 1) { $this->ajaxReturn(array('code' => 0, 'msg' => '骑手状态异常')); } if ($rider['auth_status'] != 2) { $this->ajaxReturn(array('code' => 0, 'msg' => '请先完成实名认证')); } // 获取待接单的订单 $orderModel = M('rider_order'); $where = array( 'ro.order_status' => 0, // 待接单 'ro.rider_id' => 0 ); // 如果骑手绑定了店铺,则只显示该店铺的订单 if (isset($rider['store_id']) && intval($rider['store_id']) > 0) { $where['ro.store_id'] = intval($rider['store_id']); } $offset = ($page - 1) * $limit; $list = $orderModel->alias('ro') ->join('LEFT JOIN ls_retail_bill_order bo ON ro.bill_id = bo.id') ->field('ro.*, bo.all_money as order_amount') ->where($where) ->order('ro.add_time DESC') ->limit($offset, $limit) ->select(); $total = $orderModel->alias('ro')->where($where)->count(); // 计算距离(简化处理) foreach ($list as &$item) { if ($lat && $lng && $item['store_lat'] && $item['store_lng']) { $item['distance_to_store'] = $this->calculateDistance($lat, $lng, $item['store_lat'], $item['store_lng']); } else { $item['distance_to_store'] = 0; } // 确保order_amount字段存在,如果没有则设为0 if (!isset($item['order_amount']) || $item['order_amount'] === null) { $item['order_amount'] = '0.00'; } } $this->ajaxReturn(array( 'code' => 1, 'msg' => '获取成功', 'data' => array( 'list' => $list, 'total' => $total, 'page' => $page, 'limit' => $limit ) )); } /** * 接受订单 */ public function acceptOrder() { $riderId = $this->riderId; $rider = $this->riderInfo; $contentType = ''; if (isset($_SERVER['CONTENT_TYPE'])) { $contentType = $_SERVER['CONTENT_TYPE']; } // 使用统一的参数处理方法 $orderId = intval($this->getRequestParam('order_id', 0)); if (empty($orderId)) { $this->ajaxReturn(array('code' => 0, 'msg' => '订单ID不能为空')); } if (!$rider || $rider['status'] != 1) { $this->ajaxReturn(array('code' => 0, 'msg' => '骑手状态异常')); } if ($rider['work_status'] != 1) { $this->ajaxReturn(array('code' => 0, 'msg' => '请先上线')); } // 检查订单状态 $orderModel = M('rider_order'); $order = $orderModel->find($orderId); if (!$order) { $this->ajaxReturn(array('code' => 0, 'msg' => '订单不存在')); } if ($order['order_status'] != 0) { $this->ajaxReturn(array('code' => 0, 'msg' => '订单已被接取')); } // 生成取餐码 $pickupCode = $this->generatePickupCode(); // 更新订单状态 $data = array( 'rider_id' => $riderId, 'order_status' => 1, // 已接单 'accept_time' => date('Y-m-d H:i:s'), 'update_time' => date('Y-m-d H:i:s'), 'pickup_code' => $pickupCode ); $result = $orderModel->where(array('id' => $orderId))->save($data); if ($result !== false) { $riderModel = M('rider_info'); // 更新骑手状态为忙碌 $riderModel->where(array('id' => $riderId))->save(array('work_status' => 2)); // 同步原始订单状态为已发货 if (!empty($order['bill_id'])) { $billOnlineModel = M('retail_bill_online'); $billOnline = $billOnlineModel->where(array('bill_id' => $order['bill_id']))->find(); if ($billOnline && $billOnline['status'] != 2 && $billOnline['status'] != 3) { // 如果订单状态不是已发货也不是已完成,则更新为已发货 $billOnlineModel->where(array('bill_id' => $order['bill_id']))->save(array( 'status' => 2, // 已发货 'send_time' => date('Y-m-d H:i:s'), 'update_time' => date('Y-m-d H:i:s') )); } } $this->ajaxReturn(array( 'code' => 1, 'msg' => '接单成功', 'data' => array( 'order_id' => $orderId, 'order_no' => $order['order_no'], 'pickup_code' => $pickupCode ) )); } else { $this->ajaxReturn(array('code' => 0, 'msg' => '接单失败')); } } /** * 自动接单核心逻辑 */ public function autoAcceptOrder() { $riderId = $this->riderId; $rider = $this->riderInfo; if (!$rider || $rider['status'] != 1) { $this->ajaxReturn(array('code' => 0, 'msg' => '骑手状态异常')); } if ($rider['work_status'] != 1) { $this->ajaxReturn(array('code' => 0, 'msg' => '请先上线')); } // 检查是否开启自动接单 if ($rider['auto_accept_order'] != 1) { $this->ajaxReturn(array('code' => 0, 'msg' => '未开启自动接单')); } // 检查当前时间是否在自动接单时间段内 $currentTime = date('H:i'); $currentWeekday = date('w') ?: 7; // 0为周日,转换为7 $startTime = $rider['auto_accept_start_time'] ?: '00:00'; $endTime = $rider['auto_accept_end_time'] ?: '23:59'; // 从工作时间表获取工作日设置 $workTimeModel = M('rider_work_time'); $workTimes = $workTimeModel->where(array('rider_id' => $rider['rider_id']))->select(); $workDays = array(); if ($workTimes) { foreach ($workTimes as $workTime) { if ($workTime['is_work'] == 1) { // 将数据库中的week_day(0-6)转换为标准格式(1-7) $workDays[] = $workTime['week_day'] == 0 ? 7 : $workTime['week_day']; } } } // 如果没有设置工作时间,默认全周工作 if (empty($workDays)) { $workDays = array(1, 2, 3, 4, 5, 6, 7); } if (!in_array($currentWeekday, $workDays)) { $this->ajaxReturn(array('code' => 0, 'msg' => '当前不在自动接单工作日内')); } if ($currentTime < $startTime || $currentTime > $endTime) { $this->ajaxReturn(array('code' => 0, 'msg' => '当前不在自动接单时间段内')); } // 检查当前接单数量是否已达上限 $orderModel = M('rider_order'); $currentOrderCount = $orderModel->where(array( 'rider_id' => $riderId, 'order_status' => array('in', '1,2,3,4,5') // 已接单到配送中 ))->count(); $maxOrders = intval($rider['max_orders_per_time']) ?: 3; if ($currentOrderCount >= $maxOrders) { $this->ajaxReturn(array('code' => 0, 'msg' => '当前接单数量已达上限')); } // 获取符合条件的订单 $suitableOrders = $this->getSuitableOrders($rider); if (empty($suitableOrders)) { $this->ajaxReturn(array('code' => 0, 'msg' => '暂无符合条件的订单')); } // 自动接单(选择第一个符合条件的订单) $order = $suitableOrders[0]; $orderId = $order['id']; // 更新订单状态 $data = array( 'rider_id' => $riderId, 'order_status' => 1, // 已接单 'accept_time' => date('Y-m-d H:i:s'), 'update_time' => date('Y-m-d H:i:s'), 'auto_accepted' => 1 // 标记为自动接单 ); $result = $orderModel->where(array('id' => $orderId))->save($data); if ($result !== false) { $riderModel = M('rider_info'); // 更新骑手状态为忙碌 $riderModel->where(array('id' => $riderId))->save(array('work_status' => 2)); // 同步原始订单状态为已发货 if (!empty($order['bill_id'])) { $billOnlineModel = M('retail_bill_online'); $billOnline = $billOnlineModel->where(array('bill_id' => $order['bill_id']))->find(); if ($billOnline && $billOnline['status'] != 2 && $billOnline['status'] != 3) { // 如果订单状态不是已发货也不是已完成,则更新为已发货 $billOnlineModel->where(array('bill_id' => $order['bill_id']))->save(array( 'status' => 2, // 已发货 'send_time' => date('Y-m-d H:i:s'), 'update_time' => date('Y-m-d H:i:s') )); } } $this->ajaxReturn(array( 'code' => 1, 'msg' => '自动接单成功', 'data' => array( 'order_id' => $orderId, 'order_no' => $order['order_no'], 'delivery_fee' => $order['delivery_fee'], 'distance' => $order['distance_to_store'] ) )); } else { $this->ajaxReturn(array('code' => 0, 'msg' => '自动接单失败')); } } /** * 获取符合自动接单条件的订单 */ private function getSuitableOrders($rider) { $riderId = $rider['id']; $lat = $rider['current_lat'] ?: 0; $lng = $rider['current_lng'] ?: 0; // 基础查询条件 $orderModel = M('rider_order'); $where = array( 'order_status' => 0, // 待接单 'rider_id' => 0 ); // 如果骑手绑定了店铺,则只获取该店铺的订单 if (isset($rider['store_id']) && intval($rider['store_id']) > 0) { $where['store_id'] = intval($rider['store_id']); } // 获取所有待接单订单 $orders = $orderModel->where($where)->order('add_time DESC')->select(); $suitableOrders = array(); foreach ($orders as $order) { // 检查配送费是否符合要求 $minDeliveryFee = floatval($rider['min_delivery_fee']) ?: 0; if ($order['delivery_fee'] < $minDeliveryFee) { continue; } // 检查距离是否符合要求 if ($lat && $lng && $order['store_lat'] && $order['store_lng']) { $distance = $this->calculateDistance($lat, $lng, $order['store_lat'], $order['store_lng']); $order['distance_to_store'] = $distance; $maxDistance = floatval($rider['max_distance']) ?: 50; if ($distance > $maxDistance) { continue; } } else { $order['distance_to_store'] = 0; } // 检查订单类型是否符合要求 $acceptOrderTypes = $rider['accept_order_types'] ? explode(',', $rider['accept_order_types']) : array('1', '2', '3'); if (!in_array($order['order_type'], $acceptOrderTypes)) { continue; } // 检查商家评分是否符合要求 if ($rider['reject_low_rating_store'] == 1) { $minStoreRating = floatval($rider['min_store_rating']) ?: 0; if ($order['store_rating'] < $minStoreRating) { continue; } } $suitableOrders[] = $order; } // 按距离排序,优先接近的订单 usort($suitableOrders, function ($a, $b) { if ($a['distance_to_store'] == $b['distance_to_store']) { return 0; } return ($a['distance_to_store'] < $b['distance_to_store']) ? -1 : 1; }); return $suitableOrders; } /** * 获取骑手当前订单 */ public function getCurrentOrder() { $riderId = $this->riderId; $orderModel = M('rider_order'); $order = $orderModel->where(array( 'rider_id' => $riderId, 'order_status' => array('in', '1,2,3,4,5') // 已接单到配送中 ))->find(); if (!$order) { $this->ajaxReturn(array( 'code' => 1, 'msg' => '暂无进行中的订单', 'data' => null )); } $this->ajaxReturn(array( 'code' => 1, 'msg' => '获取成功', 'data' => $order )); } /** * 更新订单状态 */ public function updateOrderStatus() { $riderId = $this->riderId; // 初始化变量 $orderId = 0; $status = 0; $lat = 0; $lng = 0; // 使用统一的参数处理方法 $orderId = intval($this->getRequestParam('order_id', 0)); $statusParam = $this->getRequestParam('status', ''); $lat = floatval($this->getRequestParam('lat', 0)); $lng = floatval($this->getRequestParam('lng', 0)); // 获取送达时的额外参数 $params = $this->getRequestParam('params', array()); if (is_string($params)) { $params = json_decode($params, true) ?: array(); } // 处理状态参数,支持字符串和数字 $status = $this->convertStatusToNumber($statusParam); if (empty($orderId)) { $this->ajaxReturn(array('code' => 0, 'msg' => '订单ID不能为空')); } if ($status === false || ($status === 0 && empty($statusParam))) { $this->ajaxReturn(array('code' => 0, 'msg' => '状态参数无效')); } // 检查订单归属 $orderModel = M('rider_order'); $order = $orderModel->where(array('id' => $orderId, 'rider_id' => $riderId))->find(); if (!$order || $order['rider_id'] != $riderId) { $this->ajaxReturn(array('code' => 0, 'msg' => '订单不存在或无权限')); } // 检查订单是否已取消 $currentStatus = intval($order['order_status']); if ($currentStatus == 8) { // 订单已取消,恢复骑手为在线状态 $riderModel = M('rider_info'); $riderModel->where(array('id' => $riderId))->save(array('work_status' => 1)); $this->ajaxReturn(array( 'code' => -1, // 特殊错误码表示订单已取消 'msg' => '该订单已被取消,无法继续操作', 'data' => array( 'order_id' => $orderId, 'cancel_reason' => $order['cancel_reason'] ?: '订单已取消', 'cancel_time' => $order['cancel_time'] ) )); } // 检查订单状态流转是否合法 if (!$this->isValidStatusTransition($currentStatus, $status)) { $statusNames = array( 0 => '待接单', 1 => '已接单', 2 => '前往商家', 3 => '已到店', 4 => '已取餐', 5 => '配送中', 6 => '已送达', 7 => '异常', 8 => '已取消' ); $currentStatusName = isset($statusNames[$currentStatus]) ? $statusNames[$currentStatus] : '未知'; $targetStatusName = isset($statusNames[$status]) ? $statusNames[$status] : '未知'; $this->ajaxReturn(array( 'code' => 0, 'msg' => "订单当前状态为【{$currentStatusName}】,无法变更为【{$targetStatusName}】" )); } $data = array( 'order_status' => $status, 'update_time' => date('Y-m-d H:i:s') ); $statusMsg = ''; switch ($status) { case 2: // 前往商家 $statusMsg = '前往商家'; break; case 3: // 已到店 $data['arrive_store_time'] = date('Y-m-d H:i:s'); $statusMsg = '已到店'; break; case 4: // 已取餐 // 设置取餐时间 if (isset($params['pickup_time']) && !empty($params['pickup_time'])) { $data['pickup_time'] = date('Y-m-d H:i:s', strtotime($params['pickup_time'])); } else { $data['pickup_time'] = date('Y-m-d H:i:s'); } // 处理取餐照片 if (isset($params['pickup_photos']) && !empty($params['pickup_photos'])) { if (is_array($params['pickup_photos'])) { $data['pickup_photos'] = implode(',', $params['pickup_photos']); } else { $data['pickup_photos'] = $params['pickup_photos']; } } // 处理商品核对信息 if (isset($params['goods_checked']) && !empty($params['goods_checked'])) { $checkedGoods = array(); if (is_array($params['goods_checked'])) { foreach ($params['goods_checked'] as $goods) { if (isset($goods['id']) && isset($goods['checked'])) { $checkedGoods[] = array( 'id' => $goods['id'], 'checked' => $goods['checked'] ? 1 : 0 ); } } } if (!empty($checkedGoods)) { $data['goods_check_result'] = json_encode($checkedGoods); } } $statusMsg = '已取餐'; break; case 5: // 配送中 $statusMsg = '配送中'; break; case 6: // 已送达 // 设置送达时间 if (isset($params['delivery_time']) && !empty($params['delivery_time'])) { $data['delivery_time'] = date('Y-m-d H:i:s', strtotime($params['delivery_time'])); } else { $data['delivery_time'] = date('Y-m-d H:i:s'); } // 处理送达照片 if (isset($params['delivery_photos']) && !empty($params['delivery_photos'])) { if (is_array($params['delivery_photos'])) { $data['delivery_receipt_photos'] = implode(',', $params['delivery_photos']); } else { $data['delivery_receipt_photos'] = $params['delivery_photos']; } } // 处理送达方式和备注 if (isset($params['delivery_method']) && !empty($params['delivery_method'])) { $deliveryMethods = array( 'hand_delivery' => '面对面交付', 'contactless' => '无接触配送', 'doorman' => '交给门卫/前台' ); $methodText = isset($deliveryMethods[$params['delivery_method']]) ? $deliveryMethods[$params['delivery_method']] : $params['delivery_method']; $data['delivery_receipt_remark'] = $methodText; } // 处理支付方式(货到付款) if (isset($params['payment_method']) && !empty($params['payment_method'])) { $paymentMethods = array( 'cash' => '现金支付', 'wechat' => '微信支付', 'alipay' => '支付宝支付', 'card' => '刷卡支付' ); $paymentText = isset($paymentMethods[$params['payment_method']]) ? $paymentMethods[$params['payment_method']] : $params['payment_method']; // 如果有支付方式,添加到备注中 if (!empty($data['delivery_receipt_remark'])) { $data['delivery_receipt_remark'] .= ',' . $paymentText; } else { $data['delivery_receipt_remark'] = $paymentText; } } // 处理支付确认状态 if (isset($params['payment_confirmed'])) { $paymentStatus = $params['payment_confirmed'] ? '已收款' : '未收款'; if (!empty($data['delivery_receipt_remark'])) { $data['delivery_receipt_remark'] .= ',' . $paymentStatus; } else { $data['delivery_receipt_remark'] = $paymentStatus; } } // 设置凭证上传时间 if (!empty($data['delivery_receipt_photos']) || !empty($data['delivery_receipt_remark'])) { $data['receipt_upload_time'] = date('Y-m-d H:i:s'); } $statusMsg = '已送达'; // 更新骑手统计 $this->updateRiderStats($riderId, $order); // 更新骑手状态为在线 $riderModel = M('rider_info'); $riderModel->where(array('id' => $riderId))->save(array('work_status' => 1)); // 同步原始订单状态为已完成 if (!empty($order['bill_id'])) { $billOnlineModel = M('retail_bill_online'); $billOnline = $billOnlineModel->where(array('bill_id' => $order['bill_id']))->find(); if ($billOnline && $billOnline['status'] != 3) { // 将原始订单状态更新为已收货(status=3) $billOnlineModel->where(array('bill_id' => $order['bill_id']))->save(array( 'status' => 3, // 已收货/已完成 'receipt_time' => !empty($data['delivery_time']) ? $data['delivery_time'] : date('Y-m-d H:i:s'), 'update_time' => date('Y-m-d H:i:s') )); } } break; default: $this->ajaxReturn(array('code' => 0, 'msg' => '无效的状态')); } $result = $orderModel->where(array('id' => $orderId))->save($data); if ($result !== false) { // 更新骑手位置 $updateLat = $lat; $updateLng = $lng; // 如果是送达状态,优先使用送达位置 if ($status == 6 && isset($params['delivery_latitude']) && isset($params['delivery_longitude'])) { $updateLat = floatval($params['delivery_latitude']); $updateLng = floatval($params['delivery_longitude']); } if ($updateLat && $updateLng) { $this->updateRiderLocation($riderId, $updateLat, $updateLng); } $this->ajaxReturn(array( 'code' => 1, 'msg' => $statusMsg . '成功' )); } else { $this->ajaxReturn(array( 'code' => 0, 'msg' => '状态更新失败' )); } } /** * 上传送达照片 */ public function uploadDeliveryPhoto() { $riderId = $this->riderId; // 检查Content-Type并解析参数 $contentType = ''; if (isset($_SERVER['CONTENT_TYPE'])) { $contentType = $_SERVER['CONTENT_TYPE']; } // 初始化变量 $orderId = 0; // 使用统一的参数处理方法 $orderId = intval($this->getRequestParam('order_id', 0)); $photo = trim($this->getRequestParam('photo', '')); if (empty($orderId)) { $this->ajaxReturn(array('code' => 0, 'msg' => '订单ID不能为空')); } if (empty($photo)) { $this->ajaxReturn(array('code' => 0, 'msg' => '照片不能为空')); } // 检查订单归属 $orderModel = M('rider_order'); $order = $orderModel->where(array('id' => $orderId, 'rider_id' => $riderId))->find(); if (!$order || $order['rider_id'] != $riderId) { $this->ajaxReturn(array('code' => 0, 'msg' => '订单不存在或无权限')); } $data = array( 'delivery_photo' => $photo ); $result = $orderModel->where(array('id' => $orderId))->save($data); if ($result !== false) { $this->ajaxReturn(array( 'code' => 1, 'msg' => '照片上传成功' )); } else { $this->ajaxReturn(array('code' => 0, 'msg' => '上传失败')); } } /** * 获取订单历史 */ public function getOrderHistory() { $riderId = $this->riderId; $page = $this->getRequestParam('page', 1); $pageSize = $this->getRequestParam('page_size', 10); // 修改参数名为page_size $status = $this->getRequestParam('status', ''); $where = array('rider_id' => $riderId); if ($status !== '') { // 处理不同的状态值 if ($status === 'ongoing') { // 进行中的订单状态 $where['order_status'] = array('in', array('accepted', 'to_merchant', 'arrived', 'picked_up', 'delivering')); } else { $where['order_status'] = $status; } } $orderModel = M('rider_order'); $offset = ($page - 1) * $pageSize; $orders = $orderModel->where($where) ->order('add_time DESC') ->limit($offset, $pageSize) ->select(); // 格式化订单数据 if ($orders) { foreach ($orders as &$order) { // 确保必要字段存在 $order['id'] = isset($order['id']) ? $order['id'] : ''; $order['order_no'] = isset($order['order_no']) ? $order['order_no'] : ''; $order['create_time'] = isset($order['add_time']) ? $order['add_time'] : ''; $order['status'] = isset($order['order_status']) ? $order['order_status'] : ''; $order['merchant_name'] = isset($order['merchant_name']) ? $order['merchant_name'] : ''; $order['merchant_address'] = isset($order['merchant_address']) ? $order['merchant_address'] : ''; $order['delivery_name'] = isset($order['delivery_name']) ? $order['delivery_name'] : ''; $order['delivery_phone'] = isset($order['delivery_phone']) ? $order['delivery_phone'] : ''; $order['delivery_address'] = isset($order['delivery_address']) ? $order['delivery_address'] : ''; $order['delivery_fee'] = isset($order['delivery_fee']) ? $order['delivery_fee'] : 0; $order['distance'] = isset($order['distance']) ? $order['distance'] : 0; $order['cancel_reason'] = isset($order['cancel_reason']) ? $order['cancel_reason'] : ''; } } $total = $orderModel->where($where)->count(); $this->ajaxReturn(array( 'code' => 1, // 修改为code 'msg' => '获取成功', 'data' => array( 'list' => $orders ? $orders : array(), // 修改为list 'total' => $total, 'page' => $page, 'page_size' => $pageSize ) )); } /** * 计算两点间距离(简化版) */ private function calculateDistance($lat1, $lng1, $lat2, $lng2) { $earthRadius = 6371; // 地球半径,单位:公里 $lat1Rad = deg2rad($lat1); $lng1Rad = deg2rad($lng1); $lat2Rad = deg2rad($lat2); $lng2Rad = deg2rad($lng2); $deltaLat = $lat2Rad - $lat1Rad; $deltaLng = $lng2Rad - $lng1Rad; $a = sin($deltaLat / 2) * sin($deltaLat / 2) + cos($lat1Rad) * cos($lat2Rad) * sin($deltaLng / 2) * sin($deltaLng / 2); $c = 2 * atan2(sqrt($a), sqrt(1 - $a)); return round($earthRadius * $c, 2); } /** * 更新骑手位置 */ private function updateRiderLocation($riderId, $lat, $lng) { $locationModel = M('rider_location'); $data = array( 'rider_id' => $riderId, 'lat' => $lat, 'lng' => $lng, 'add_time' => date('Y-m-d H:i:s') ); $locationModel->add($data); // 更新骑手表中的最后位置 $riderModel = M('rider_info'); $riderModel->where(array('id' => $riderId))->save(array( 'last_location_lat' => $lat, 'last_location_lng' => $lng )); } /** * 更新骑手统计 */ private function updateRiderStats($riderId, $order) { $riderModel = M('rider_info'); // 更新总订单数和完成订单数 $riderModel->where(array('id' => $riderId))->setInc('total_orders'); $riderModel->where(array('id' => $riderId))->setInc('completed_orders'); // 添加收入记录 $incomeModel = M('rider_income'); $incomeData = array( 'rider_id' => $riderId, 'order_id' => $order['id'], 'income_type' => 1, // 配送费 'amount' => $order['delivery_fee'], 'description' => '订单配送费', 'status' => 1, // 已结算 'settle_time' => date('Y-m-d H:i:s'), 'add_time' => date('Y-m-d H:i:s') ); $incomeModel->add($incomeData); // 获取当前余额 $currentRider = $riderModel->field('balance, frozen_balance')->find($riderId); $balanceBefore = floatval($currentRider['balance']); $frozenBefore = floatval($currentRider['frozen_balance']); // 更新骑手余额 $riderModel->where(array('id' => $riderId))->setInc('balance', $order['delivery_fee']); // 记录余额变动日志 $balanceLog = array( 'rider_id' => $riderId, 'type' => 'income_settle', 'amount' => $order['delivery_fee'], 'balance_before' => $balanceBefore, 'balance_after' => $balanceBefore + $order['delivery_fee'], 'frozen_before' => $frozenBefore, 'frozen_after' => $frozenBefore, 'description' => '订单完成,配送费结算到余额', 'related_id' => $order['id'], 'operator_id' => 0, // 系统操作 'add_time' => date('Y-m-d H:i:s') ); M('rider_balance_log')->add($balanceLog); } /** * 获取订单详情 */ public function getOrderDetail() { $riderId = $this->riderId; $rider = $this->riderInfo; // 获取订单ID参数 $orderId = $this->getRequestParam('order_id', 0); if (empty($orderId)) { $this->ajaxReturn(array('code' => 0, 'msg' => '订单ID不能为空')); } if (!$rider || $rider['status'] != 1) { $this->ajaxReturn(array('code' => 0, 'msg' => '骑手状态异常')); } try { $orderModel = M('rider_order'); // 查询订单基本信息,关联获取订单金额 $order = $orderModel->alias('ro') ->join('LEFT JOIN ls_retail_bill_order bo ON ro.bill_id = bo.id') ->field('ro.*, bo.all_money as order_amount') ->where(array('ro.id' => $orderId)) ->find(); if (!$order) { $this->ajaxReturn(array('code' => 0, 'msg' => '订单不存在')); } // 检查订单权限(只有分配给该骑手的订单或待接单的订单才能查看) if ($order['rider_id'] != 0 && $order['rider_id'] != $riderId) { $this->ajaxReturn(array('code' => 0, 'msg' => '无权限查看此订单')); } // 如果订单已取消,添加特殊提示 if ($order['order_status'] == 8) { $order['is_cancelled'] = true; $order['cancel_warning'] = '该订单已被取消'; } // 获取骑手信息 if ($order['rider_id']) { $riderInfo = M('rider_info')->where(array('id' => $order['rider_id']))->find(); if ($riderInfo) { $order['rider'] = array( 'id' => $riderInfo['id'], 'name' => $riderInfo['rider_name'], 'phone' => $riderInfo['rider_phone'], 'avatar' => $riderInfo['rider_avatar'] ?: '', 'rating' => floatval($riderInfo['rating'] ?: 0) ); } else { $order['rider'] = null; } } else { $order['rider'] = null; } // 获取商户信息 if ($order['merchant_id']) { $merchant = M('retail_merchant')->where(array('id' => $order['merchant_id']))->find(); if ($merchant) { $order['merchant'] = array( 'id' => $merchant['id'], 'name' => $merchant['name'] ?: $order['store_name'], 'address' => $merchant['address'] ?: $order['store_address'], 'phone' => $merchant['mobile'] ?: $order['store_phone'], 'lat' => $order['store_lat'], 'lng' => $order['store_lng'] ); } else { // 如果商户信息不存在,使用订单中的商户信息 $order['merchant'] = array( 'id' => $order['merchant_id'], 'name' => $order['store_name'], 'address' => $order['store_address'], 'phone' => $order['store_phone'], 'lat' => $order['store_lat'], 'lng' => $order['store_lng'] ); } } else { $order['merchant'] = array( 'id' => 0, 'name' => $order['store_name'], 'address' => $order['store_address'], 'phone' => $order['store_phone'], 'lat' => $order['store_lat'], 'lng' => $order['store_lng'] ); } // 获取客户信息 $order['customer'] = array( 'name' => $order['customer_name'], 'phone' => $order['customer_phone'], 'address' => $order['customer_address'], 'lat' => $order['customer_lat'], 'lng' => $order['customer_lng'], 'remark' => $order['customer_remark'] ); // 获取原始订单信息(商品详情等) if ($order['bill_id']) { $billOrder = M('retail_bill_order')->where(array('id' => $order['bill_id']))->find(); if ($billOrder) { $order['original_order'] = $billOrder; // 获取在线订单信息 $onlineOrder = M('retail_bill_online')->where(array('bill_id' => $order['bill_id']))->find(); if ($onlineOrder) { $order['online_order'] = $onlineOrder; } } } // 获取商品列表 $order['goods_list'] = array(); if ($order['bill_id']) { $sellModel = M('retail_sell'); $goodsList = $sellModel->alias('rs') ->join('LEFT JOIN ls_retail_goods g ON rs.goods_id = g.id') ->field('rs.*, g.goods_name, g.goods_image') ->where(array( 'rs.bill_id' => $order['bill_id'], 'rs.sell_type' => 1 // 1为销售,2为退款 )) ->select(); if ($goodsList) { foreach ($goodsList as $goods) { // 处理规格信息 - 优化规格显示逻辑 $spec = ''; // 首先尝试从关联的商品表获取规格信息 if (!empty($goods['sku_json_info'])) { $skuInfo = json_decode($goods['sku_json_info'], true); if (is_array($skuInfo)) { // 尝试多个可能的规格字段 if (isset($skuInfo['sku_name']) && !empty($skuInfo['sku_name'])) { $spec = $skuInfo['sku_name']; } elseif (isset($skuInfo['specifications']) && !empty($skuInfo['specifications'])) { $spec = $skuInfo['specifications']; } elseif (isset($skuInfo['spec']) && !empty($skuInfo['spec'])) { $spec = $skuInfo['spec']; } } } // 如果还是没有规格信息,尝试从商品表获取 if (empty($spec) && !empty($goods['specifications'])) { $spec = $goods['specifications']; } // 如果规格为空,根据商品类型设置默认规格 if (empty($spec)) { $spec = '标准装'; } $order['goods_list'][] = array( 'id' => $goods['goods_id'], 'name' => $goods['goods_name'] ?: '', 'spec' => $spec, 'quantity' => floatval($goods['num']), 'price' => floatval($goods['price']), 'image' => $goods['goods_image'] ?: '' ); } } } // 格式化数据 $order['delivery_fee'] = floatval($order['delivery_fee']); $order['distance'] = floatval($order['distance']); // 商家到客户的配送距离 $order['estimated_time'] = intval($order['estimated_time']); $order['order_amount'] = isset($order['order_amount']) && $order['order_amount'] !== null ? floatval($order['order_amount']) : 0.00; // 添加订单总金额字段 $order['total_amount'] = 0.00; if ($order['bill_id'] && isset($order['original_order']) && $order['original_order']) { $order['total_amount'] = floatval($order['original_order']['all_money']); } // 计算骑手当前位置到客户地址的距离 $order['distance_to_customer'] = $this->calculateRiderToCustomerDistance($riderId, $order); // 生成配送记录 $order['delivery_logs'] = $this->generateDeliveryLogs($order); // 订单状态文本映射 $statusMap = array( 0 => '待接单', 1 => '已接单', 2 => '前往商家', 3 => '已到店', 4 => '已取餐', 5 => '配送中', 6 => '已送达', 7 => '异常', 8 => '已取消' ); $order['status_text'] = isset($statusMap[$order['order_status']]) ? $statusMap[$order['order_status']] : '未知状态'; // 时间格式化 $order['add_time_formatted'] = $order['add_time'] ? date('Y-m-d H:i:s', strtotime($order['add_time'])) : ''; $order['accept_time_formatted'] = $order['accept_time'] ? date('Y-m-d H:i:s', strtotime($order['accept_time'])) : ''; $order['delivery_time_formatted'] = $order['delivery_time'] ? date('Y-m-d H:i:s', strtotime($order['delivery_time'])) : ''; $this->ajaxReturn(array( 'code' => 1, 'msg' => '获取成功', 'data' => $order )); } catch (\Exception $e) { $this->ajaxReturn(array( 'code' => 0, 'msg' => '获取失败:' . $e->getMessage() )); } } /** * 计算骑手当前位置到客户地址的距离 * @param int $riderId 骑手ID * @param array $order 订单信息 * @return float 距离(公里) */ private function calculateRiderToCustomerDistance($riderId, $order) { try { // 获取骑手最新位置 $riderLocationModel = M('rider_location'); $riderLocation = $riderLocationModel->where(array('rider_id' => $riderId)) ->order('add_time DESC') ->find(); if (!$riderLocation || !$order['customer_lat'] || !$order['customer_lng']) { return 0.00; // 如果没有位置信息,返回0 } // 使用地图API计算路线距离(骑行路线),失败时回退到直线距离 $deliveryFeeService = new \Retail\Service\DeliveryFeeService($order['merchant_id']); $distance = $deliveryFeeService->calculateRouteDistance( $riderLocation['lat'], $riderLocation['lng'], $order['customer_lat'], $order['customer_lng'], 'bicycling' // 骑行路线 ); return round($distance, 2); } catch (\Exception $e) { // 计算失败时返回0 return 0.00; } } /** * 生成配送记录 * @param array $order 订单信息 * @return array 配送记录数组 */ private function generateDeliveryLogs($order) { $logs = array(); // 根据订单状态和时间字段生成配送记录 $statusLogs = array( array( 'status' => 1, 'time_field' => 'accept_time', 'content' => '已接单', 'description' => '骑手已接受订单' ), array( 'status' => 2, 'time_field' => 'going_time', // 前往商家时间(可能需要从其他地方获取) 'content' => '前往商家', 'description' => '骑手正在前往商家' ), array( 'status' => 3, 'time_field' => 'arrive_store_time', 'content' => '已到店', 'description' => '骑手已到达商家' ), array( 'status' => 4, 'time_field' => 'pickup_time', 'content' => '已取餐', 'description' => '骑手已取餐,离开商家' ), array( 'status' => 5, 'time_field' => 'start_delivery_time', // 开始配送时间(可能需要从其他地方获取) 'content' => '配送中', 'description' => '骑手正在配送,前往客户位置' ), array( 'status' => 6, 'time_field' => 'delivery_time', 'content' => '已送达', 'description' => '订单已成功送达客户' ), array( 'status' => 8, 'time_field' => 'cancel_time', 'content' => '已取消', 'description' => '订单已取消' ) ); // 遍历状态日志,生成实际的配送记录 foreach ($statusLogs as $statusLog) { // 检查是否有对应的时间字段 $timeField = $statusLog['time_field']; $time = null; // 特殊处理一些时间字段 if ($timeField === 'going_time') { // 前往商家时间可能需要从位置记录或其他地方获取 // 暂时跳过,或者使用接单时间作为估算 if (!empty($order['accept_time'])) { $time = date('Y-m-d H:i:s', strtotime($order['accept_time']) + 60); // 接单后1分钟 } } elseif ($timeField === 'start_delivery_time') { // 开始配送时间,使用取餐时间作为估算 if (!empty($order['pickup_time'])) { $time = date('Y-m-d H:i:s', strtotime($order['pickup_time']) + 60); // 取餐后1分钟 } } elseif (isset($order[$timeField]) && !empty($order[$timeField])) { $time = $order[$timeField]; } // 如果有时间记录,或者是当前状态,则添加到日志中 if ($time || $order['order_status'] == $statusLog['status']) { $log = array( 'status' => $statusLog['status'], 'content' => $statusLog['content'], 'description' => $statusLog['description'], 'time' => $time ?: date('Y-m-d H:i:s'), // 如果没有时间,使用当前时间 'is_current' => $order['order_status'] == $statusLog['status'], 'is_completed' => false // 先设为false,后面统一处理 ); // 添加取消原因 if ($statusLog['status'] == 8 && !empty($order['cancel_reason'])) { $log['description'] = '订单已取消:' . $order['cancel_reason']; } $logs[] = $log; } } // 按状态顺序排序(按配送流程顺序) usort($logs, function ($a, $b) { // 首先按状态排序,确保配送流程顺序正确 if ($a['status'] != $b['status']) { return $a['status'] - $b['status']; } // 状态相同时按时间排序 return strtotime($a['time']) - strtotime($b['time']); }); // 标记已完成的步骤(当前状态及之前的所有状态都标记为已完成) $currentOrderStatus = $order['order_status']; foreach ($logs as &$log) { // 如果是取消状态(8),只有取消状态本身标记为完成 if ($currentOrderStatus == 8) { $log['is_completed'] = $log['status'] == 8; } else { // 正常流程:当前状态及之前的状态都标记为已完成 // 状态流程:1(已接单) → 2(前往商家) → 3(已到店) → 4(已取餐) → 5(配送中) → 6(已送达) $log['is_completed'] = $log['status'] <= $currentOrderStatus && $log['status'] != 8; } } return $logs; } /** * 生成取餐码 * @return string */ private function generatePickupCode() { // 生成6位数字取餐码 $code = ''; for ($i = 0; $i < 6; $i++) { $code .= mt_rand(0, 9); } // 检查是否重复,如果重复则重新生成 $orderModel = M('rider_order'); $exists = $orderModel->where(array('pickup_code' => $code))->find(); if ($exists) { return $this->generatePickupCode(); // 递归重新生成 } return $code; } /** * 上报异常问题 */ public function reportProblem() { $riderId = $this->riderId; $rider = $this->riderInfo; if (!$rider || $rider['status'] != 1) { $this->ajaxReturn(array('code' => 0, 'msg' => '骑手状态异常')); } // 获取请求参数 $orderId = intval($this->getRequestParam('order_id', 0)); $problemType = trim($this->getRequestParam('problem_type', '')); $problemDescription = trim($this->getRequestParam('problem_description', '')); $evidencePhotos = trim($this->getRequestParam('evidence_photos', '')); $contactPhone = trim($this->getRequestParam('contact_phone', '')); $submitTime = trim($this->getRequestParam('submit_time', '')); // 参数验证 if (empty($orderId)) { $this->ajaxReturn(array('code' => 0, 'msg' => '订单ID不能为空')); } if (empty($problemType)) { $this->ajaxReturn(array('code' => 0, 'msg' => '问题类型不能为空')); } if (empty($contactPhone)) { $this->ajaxReturn(array('code' => 0, 'msg' => '联系电话不能为空')); } // 问题类型验证 $allowedTypes = array( 'missing_items', 'wrong_items', 'damaged_package', 'quality_issue', 'merchant_delay', 'address_error', 'customer_unreachable', 'weather_issue', 'vehicle_breakdown', 'other' ); if (!in_array($problemType, $allowedTypes)) { $this->ajaxReturn(array('code' => 0, 'msg' => '无效的问题类型')); } // 手机号格式验证 if (!preg_match('/^1[3-9]\d{9}$/', $contactPhone)) { $this->ajaxReturn(array('code' => 0, 'msg' => '手机号格式不正确')); } // 描述长度验证 if (!empty($problemDescription) && mb_strlen($problemDescription, 'UTF-8') > 500) { $this->ajaxReturn(array('code' => 0, 'msg' => '问题描述不能超过500字符')); } // 验证订单权限 $orderModel = M('rider_order'); $order = $orderModel->where(array('id' => $orderId, 'rider_id' => $riderId))->find(); if (!$order) { $this->ajaxReturn(array('code' => 0, 'msg' => '订单不存在或无权限操作')); } // 检查订单状态是否允许上报异常 $allowedStatuses = array(1, 2, 3, 4, 5); // 已接单到配送中的状态 if (!in_array($order['order_status'], $allowedStatuses)) { $this->ajaxReturn(array('code' => 0, 'msg' => '当前订单状态不允许上报异常')); } // 根据问题类型设置优先级 $priorityMap = array( 'quality_issue' => 4, // 紧急 - 食品安全问题 'damaged_package' => 3, // 高 - 包装破损 'weather_issue' => 3, // 高 - 恶劣天气 'vehicle_breakdown' => 3, // 高 - 车辆故障 'customer_unreachable' => 2, // 中 - 客户联系不上 'address_error' => 2, // 中 - 地址错误 'merchant_delay' => 2, // 中 - 商家出餐慢 'missing_items' => 2, // 中 - 商品缺失 'wrong_items' => 2, // 中 - 商品错误 'other' => 1 // 低 - 其他问题 ); $priority = isset($priorityMap[$problemType]) ? $priorityMap[$problemType] : 1; $currentTime = date('Y-m-d H:i:s'); // 处理提交时间格式 $formattedSubmitTime = $currentTime; if (!empty($submitTime)) { // 如果是ISO格式时间,转换为MySQL格式 if (strpos($submitTime, 'T') !== false) { $timestamp = strtotime($submitTime); if ($timestamp !== false) { $formattedSubmitTime = date('Y-m-d H:i:s', $timestamp); } } else { $formattedSubmitTime = $submitTime; } } // 构建报告数据 $reportData = array( 'order_id' => $orderId, 'rider_id' => $riderId, 'problem_type' => $problemType, 'problem_description' => $problemDescription, 'evidence_photos' => $evidencePhotos, 'contact_phone' => $contactPhone, 'status' => 0, // 待处理 'priority' => $priority, 'source' => 'rider_app', 'ip_address' => $this->getClientIP(), 'user_agent' => isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '', 'submit_time' => $formattedSubmitTime, 'add_time' => $currentTime, 'update_time' => $currentTime ); try { // 保存异常报告 $reportModel = M('rider_problem_report'); $reportId = $reportModel->add($reportData); if (!$reportId) { $this->ajaxReturn(array('code' => 0, 'msg' => '保存异常报告失败')); } // 记录跟进日志 $followModel = M('rider_problem_follow'); $followData = array( 'report_id' => $reportId, 'operator_id' => $riderId, 'operator_type' => 1, // 骑手 'action_type' => 'submit', 'content' => '骑手提交异常报告:' . $problemType . ($problemDescription ? "。详细描述:{$problemDescription}" : ''), 'attachments' => $evidencePhotos, // 添加附件字段 'add_time' => $currentTime ); $followModel->add($followData); // 根据异常类型更新订单状态 $this->updateOrderStatusByProblem($orderId, $problemType, $currentTime); // 发送通知给客服(这里可以集成消息队列、短信、邮件等) $this->notifyCustomerService($reportId, $reportData); $this->ajaxReturn(array( 'code' => 1, 'msg' => '异常报告提交成功', 'data' => array( 'report_id' => $reportId, 'status' => 0, 'submit_time' => $currentTime ) )); } catch (\Exception $e) { $this->ajaxReturn(array('code' => 0, 'msg' => '提交失败:' . $e->getMessage())); } } /** * 发送通知给客服 */ private function notifyCustomerService($reportId, $reportData) { // 获取问题类型中文名称 $problemTypeNames = array( 'missing_items' => '商品缺失', 'wrong_items' => '商品错误', 'damaged_package' => '包装破损', 'quality_issue' => '餐品质量问题', 'merchant_delay' => '商家出餐慢', 'address_error' => '地址错误', 'customer_unreachable' => '客户联系不上', 'weather_issue' => '恶劣天气', 'vehicle_breakdown' => '车辆故障', 'other' => '其他问题' ); $problemTypeName = isset($problemTypeNames[$reportData['problem_type']]) ? $problemTypeNames[$reportData['problem_type']] : '未知问题'; // 构建通知消息 $messageData = array( 'title' => '新的异常报告', 'content' => "骑手上报了新的异常问题:{$problemTypeName}", 'type' => 'problem_report', 'data' => json_encode(array( 'report_id' => $reportId, 'order_id' => $reportData['order_id'], 'problem_type' => $reportData['problem_type'], 'priority' => $reportData['priority'], 'contact_phone' => $reportData['contact_phone'] )), 'status' => 0, // 未读 'add_time' => date('Y-m-d H:i:s') ); // 保存到系统消息表(如果存在的话) try { $notificationModel = M('system_notification'); if ($notificationModel) { $notificationModel->add($messageData); } } catch (\Exception $e) { // 忽略通知发送失败的错误 } // 如果是紧急问题,可以在这里添加更多通知方式 if ($reportData['priority'] >= 3) { // 紧急问题的特殊处理 // 例如:发送短信、推送通知等 } } /** * 获取客户端IP地址 */ private function getClientIP() { if (isset($_SERVER['HTTP_X_FORWARDED_FOR']) && $_SERVER['HTTP_X_FORWARDED_FOR']) { $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; } elseif (isset($_SERVER['HTTP_X_REAL_IP']) && $_SERVER['HTTP_X_REAL_IP']) { $ip = $_SERVER['HTTP_X_REAL_IP']; } elseif (isset($_SERVER['REMOTE_ADDR'])) { $ip = $_SERVER['REMOTE_ADDR']; } else { $ip = ''; } // 如果是多个IP,取第一个 if (strpos($ip, ',') !== false) { $ip = explode(',', $ip)[0]; } return trim($ip); } /** * 根据异常类型更新订单状态 */ private function updateOrderStatusByProblem($orderId, $problemType, $currentTime) { $orderModel = M('rider_order'); // 获取问题类型对应的中文名称 $problemTypeNames = array( 'missing_items' => '商品缺失', 'wrong_items' => '商品错误', 'damaged_package' => '包装破损', 'quality_issue' => '餐品质量问题', 'merchant_delay' => '商家出餐慢', 'address_error' => '地址错误', 'customer_unreachable' => '客户联系不上', 'weather_issue' => '恶劣天气', 'vehicle_breakdown' => '车辆故障', 'other' => '其他问题' ); $problemName = isset($problemTypeNames[$problemType]) ? $problemTypeNames[$problemType] : $problemType; // 获取当前订单信息 $currentOrder = $orderModel->where(array('id' => $orderId))->find(); $oldStatus = $currentOrder ? $currentOrder['order_status'] : null; // 根据不同异常类型设置不同的订单状态和处理方式 switch ($problemType) { case 'quality_issue': case 'damaged_package': // 食品安全和包装问题 - 设为异常状态,需要立即处理 $orderModel->where(array('id' => $orderId))->save(array( 'order_status' => 7, // 异常状态 'exception_reason' => "骑手上报异常:{$problemName}", 'update_time' => $currentTime )); $this->logOrderStatusChange($orderId, $problemType, $problemName, $oldStatus, 7); break; case 'weather_issue': case 'vehicle_breakdown': // 天气和车辆问题 - 设为异常状态,可能需要重新分配 $orderModel->where(array('id' => $orderId))->save(array( 'order_status' => 7, // 异常状态 'exception_reason' => "骑手上报异常:{$problemName}", 'update_time' => $currentTime )); $this->logOrderStatusChange($orderId, $problemType, $problemName, $oldStatus, 7); break; case 'missing_items': case 'wrong_items': // 商品问题 - 保持当前状态,等待商家处理 $orderModel->where(array('id' => $orderId))->save(array( 'exception_reason' => "骑手上报异常:{$problemName}", 'update_time' => $currentTime )); $this->logOrderStatusChange($orderId, $problemType, $problemName, $oldStatus, $oldStatus); break; case 'merchant_delay': // 商家出餐慢 - 保持当前状态,记录异常原因 $orderModel->where(array('id' => $orderId))->save(array( 'exception_reason' => "骑手上报异常:{$problemName}", 'update_time' => $currentTime )); $this->logOrderStatusChange($orderId, $problemType, $problemName, $oldStatus, $oldStatus); break; case 'address_error': case 'customer_unreachable': // 地址和联系问题 - 保持配送中状态,等待客服协调 $orderModel->where(array('id' => $orderId))->save(array( 'exception_reason' => "骑手上报异常:{$problemName}", 'update_time' => $currentTime )); $this->logOrderStatusChange($orderId, $problemType, $problemName, $oldStatus, $oldStatus); break; case 'other': default: // 其他问题 - 记录异常原因,保持当前状态 $orderModel->where(array('id' => $orderId))->save(array( 'exception_reason' => "骑手上报异常:{$problemName}", 'update_time' => $currentTime )); $this->logOrderStatusChange($orderId, $problemType, $problemName, $oldStatus, $oldStatus); break; } } /** * 记录订单状态变更日志 */ private function logOrderStatusChange($orderId, $problemType, $problemName, $oldStatus = null, $newStatus = null) { try { // 如果有订单状态同步日志表,记录变更 $syncLogModel = M('rider_order_sync_log'); if ($syncLogModel) { $logData = array( 'bill_id' => 0, // 这里可以根据需要填入相关的bill_id 'rider_order_id' => $orderId, 'rider_id' => $this->riderId, 'operation_type' => 'report_problem', 'old_status' => $oldStatus, 'new_status' => $newStatus, 'sync_result' => 1, 'error_msg' => '', 'request_data' => json_encode(array( 'problem_type' => $problemType, 'problem_name' => $problemName, 'action' => 'report_exception' )), 'response_data' => json_encode(array('success' => true)), 'sync_time' => date('Y-m-d H:i:s'), 'retry_count' => 0, 'add_time' => date('Y-m-d H:i:s'), 'update_time' => date('Y-m-d H:i:s') ); $syncLogModel->add($logData); } } catch (\Exception $e) { // 忽略日志记录失败的错误 } } /** * 将状态字符串转换为数字 */ private function convertStatusToNumber($statusParam) { // 如果已经是数字,直接返回 if (is_numeric($statusParam)) { return intval($statusParam); } // 字符串状态映射表 $statusMap = array( 'pending' => 0, // 待接单 'accepted' => 1, // 已接单 'to_merchant' => 2, // 前往商家 'arrived' => 3, // 已到店 'picked' => 4, // 已取餐 'delivering' => 5, // 配送中 'delivered' => 6, // 已送达 'exception' => 7, // 异常 'cancelled' => 8, // 已取消 // 兼容其他可能的字符串格式 'arrived_store' => 3, 'picked_up' => 4, 'delivery' => 5, 'arrived_customer' => 6, 'completed' => 6, 'finished' => 6 ); // 转换为小写进行匹配 $statusKey = strtolower(trim($statusParam)); if (isset($statusMap[$statusKey])) { return $statusMap[$statusKey]; } // 如果无法识别,返回0(待接单状态) return 0; } /** * 检查订单状态流转是否合法 */ private function isValidStatusTransition($currentStatus, $targetStatus) { // 定义合法的状态流转规则(允许跳跃状态) $validTransitions = array( 0 => array(1, 8), // 待接单 -> 已接单、已取消 1 => array(2, 3, 4, 5, 6, 7, 8), // 已接单 -> 可以跳到任何后续状态 2 => array(3, 4, 5, 6, 7, 8), // 前往商家 -> 可以跳到任何后续状态 3 => array(4, 5, 6, 7, 8), // 已到店 -> 可以跳到任何后续状态 4 => array(5, 6, 7, 8), // 已取餐 -> 可以跳到任何后续状态 5 => array(6, 7, 8), // 配送中 -> 已送达、异常、已取消 6 => array(), // 已送达 -> 无法变更(终态) 7 => array(8), // 异常 -> 只能取消 8 => array() // 已取消 -> 无法变更(终态) ); // 检查当前状态是否存在于规则中 if (!isset($validTransitions[$currentStatus])) { return false; } // 检查目标状态是否在允许的转换列表中 return in_array($targetStatus, $validTransitions[$currentStatus]); } /** * 上报商家出餐慢 */ public function reportSlow() { $riderId = $this->riderId; $rider = $this->riderInfo; if (!$rider || $rider['status'] != 1) { $this->ajaxReturn(array('code' => 0, 'msg' => '骑手状态异常')); } // 获取请求参数 $orderId = $this->getRequestParam('order_id', 0); $slowReason = $this->getRequestParam('slow_reason', ''); $description = $this->getRequestParam('description', ''); $evidencePhotos = $this->getRequestParam('evidence_photos', ''); $expectedReadyTime = $this->getRequestParam('expected_ready_time', ''); $riderLat = $this->getRequestParam('rider_lat', 0); $riderLng = $this->getRequestParam('rider_lng', 0); $allowBeforeArrive = $this->getRequestParam('allow_before_arrive', false); $effectiveArriveTime = $this->getRequestParam('effective_arrive_time', ''); // 参数验证 if (!$orderId) { $this->ajaxReturn(array('code' => 0, 'msg' => '订单ID不能为空')); } // 验证订单是否存在且属于当前骑手 $orderModel = M('rider_order'); $order = $orderModel->where(array( 'id' => $orderId, 'rider_id' => $riderId ))->find(); if (!$order) { $this->ajaxReturn(array('code' => 0, 'msg' => '订单不存在或无权限')); } // 检查订单是否已取消 if ($order['order_status'] == 8) { // 订单已取消,恢复骑手为在线状态 $riderModel = M('rider_info'); $riderModel->where(array('id' => $riderId))->save(array('work_status' => 1)); $this->ajaxReturn(array( 'code' => -1, // 特殊错误码表示订单已取消 'msg' => '该订单已被取消,无法继续操作', 'data' => array( 'order_id' => $orderId, 'cancel_reason' => $order['cancel_reason'] ?: '订单已取消', 'cancel_time' => $order['cancel_time'] ) )); } // 检查订单状态 $allowedStatuses = [3]; // 默认只允许已到店状态(3) // 如果前端传递了 allow_before_arrive 参数,放宽状态限制 if ($allowBeforeArrive) { $allowedStatuses = [1, 2, 3, 4, 5]; // 1:已接单, 2:前往商家, 3:已到店, 4:已取餐, 5:配送中 } if (!in_array($order['order_status'], $allowedStatuses)) { $statusText = ''; $errorMsg = ''; switch ($order['order_status']) { case 0: $statusText = '待接单'; $errorMsg = '订单尚未接单,无法上报出餐慢。请先接单后再上报。'; break; case 1: $statusText = '已接单'; break; case 2: $statusText = '前往商家'; break; case 3: $statusText = '已到店'; break; case 4: $statusText = '已取餐'; break; case 5: $statusText = '配送中'; break; case 6: $statusText = '已送达'; $errorMsg = '订单已送达,无法上报出餐慢。'; break; case 7: $statusText = '异常'; $errorMsg = '订单状态异常,无法上报出餐慢。'; break; case 8: $statusText = '已取消'; $errorMsg = '订单已取消,无法上报出餐慢。'; break; default: $statusText = '未知状态'; $errorMsg = '订单状态异常,无法上报出餐慢。'; } if (!$errorMsg) { $errorMsg = "当前订单状态({$statusText})不允许上报出餐慢"; } $this->ajaxReturn(array('code' => 0, 'msg' => $errorMsg)); } // 检查是否已经上报过 $reportModel = M('rider_merchant_slow_report'); $existReport = $reportModel->where(array( 'order_id' => $orderId, 'rider_id' => $riderId ))->find(); if ($existReport) { $this->ajaxReturn(array('code' => 0, 'msg' => '该订单已上报过出餐慢')); } // 计算等待时长 $reportTime = time(); // 优先使用前端传递的有效到达时间,否则使用订单的到店时间 if ($effectiveArriveTime) { $arriveTime = strtotime($effectiveArriveTime); } else if ($order['arrive_store_time']) { $arriveTime = strtotime($order['arrive_store_time']); } else { // 如果都没有,使用当前时间作为基准(等待时长为0) $arriveTime = $reportTime; } $waitDuration = max(0, round(($reportTime - $arriveTime) / 60)); // 分钟,最小为0 // 准备插入数据 $reportData = array( 'order_id' => $orderId, 'rider_id' => $riderId, 'merchant_id' => $order['merchant_id'], 'store_id' => $order['store_id'], 'report_time' => date('Y-m-d H:i:s', $reportTime), 'arrive_time' => $effectiveArriveTime ? date('Y-m-d H:i:s', strtotime($effectiveArriveTime)) : $order['arrive_store_time'], 'expected_ready_time' => $expectedReadyTime, 'wait_duration' => $waitDuration, 'slow_reason' => $slowReason, 'description' => $description, 'evidence_photos' => $evidencePhotos, 'rider_location_lat' => $riderLat, 'rider_location_lng' => $riderLng, 'status' => 0, // 待处理 'ip_address' => get_client_ip(), 'add_time' => date('Y-m-d H:i:s'), 'update_time' => date('Y-m-d H:i:s') ); // 开启事务 $reportModel->startTrans(); try { // 插入出餐慢记录 $reportId = $reportModel->add($reportData); if (!$reportId) { throw new \Exception('插入出餐慢记录失败'); } // 同时在问题上报表中也记录一条 $problemModel = M('rider_problem_report'); $problemData = array( 'order_id' => $orderId, 'rider_id' => $riderId, 'problem_type' => 'merchant_delay', 'problem_description' => "商家出餐慢,等待时长:{$waitDuration}分钟。" . ($description ? "详细描述:{$description}" : ''), 'evidence_photos' => $evidencePhotos, 'contact_phone' => $rider['rider_phone'], 'status' => 0, 'priority' => 2, // 中等优先级 'source' => 'rider_app', 'ip_address' => get_client_ip(), 'submit_time' => date('Y-m-d H:i:s'), 'add_time' => date('Y-m-d H:i:s') ); $problemId = $problemModel->add($problemData); if (!$problemId) { throw new \Exception('插入问题记录失败'); } // 记录跟进日志 $followModel = M('rider_problem_follow'); $followData = array( 'report_id' => $problemId, 'operator_id' => $riderId, 'operator_type' => 1, // 骑手 'action_type' => 'submit', 'content' => "骑手上报商家出餐慢,等待时长:{$waitDuration}分钟" . ($description ? "。详细描述:{$description}" : ''), 'attachments' => $evidencePhotos, // 添加附件字段 'add_time' => date('Y-m-d H:i:s') ); $followModel->add($followData); // 提交事务 $reportModel->commit(); // 返回成功响应 $this->ajaxReturn(array( 'code' => 1, 'msg' => '上报成功', 'data' => array( 'report_id' => $reportId, 'wait_duration' => $waitDuration, 'report_time' => date('Y-m-d H:i:s') ) )); } catch (\Exception $e) { // 回滚事务 $reportModel->rollback(); // 记录错误日志 \Think\Log::record('上报出餐慢失败:' . $e->getMessage(), \Think\Log::ERR); $this->ajaxReturn(array('code' => 0, 'msg' => '上报失败,请重试')); } } }