文件
mashangyoujiu/Application/Admin/Controller/RiderManageController.class.php

561 行
20 KiB
PHP

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