1950 行
74 KiB
PHP
1950 行
74 KiB
PHP
<?php
|
||
|
||
namespace RiderApi\Controller;
|
||
|
||
/**
|
||
* 骑手端订单控制器
|
||
*/
|
||
class OrderController extends BaseController
|
||
{
|
||
|
||
/**
|
||
* 获取可接订单列表
|
||
*/
|
||
public function getAvailableOrders()
|
||
{
|
||
$riderId = $this->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' => '上报失败,请重试'));
|
||
}
|
||
}
|
||
}
|