display(); } /** * 获取概览统计数据 */ public function getOverviewStats() { $timeRange = I('timeRange', 'today', 'trim'); $startDate = I('startDate', '', 'trim'); $endDate = I('endDate', '', 'trim'); try { $dateCondition = $this->getDateCondition($timeRange, $startDate, $endDate); $prevDateCondition = $this->getPrevDateCondition($timeRange, $startDate, $endDate); $orderModel = M('rider_order'); // 当前期间统计 $currentStats = $this->calculatePeriodStats($orderModel, $dateCondition); // 上一期间统计(用于计算变化率) $prevStats = $this->calculatePeriodStats($orderModel, $prevDateCondition); // 计算变化率 $orderChange = $this->calculateChangeRate($currentStats['totalOrders'], $prevStats['totalOrders']); $revenueChange = $this->calculateChangeRate($currentStats['totalRevenue'], $prevStats['totalRevenue']); $timeChange = $this->calculateChangeRate($currentStats['avgDeliveryTime'], $prevStats['avgDeliveryTime'], true); $completionChange = $this->calculateChangeRate($currentStats['completionRate'], $prevStats['completionRate']); $result = array( 'totalOrders' => $currentStats['totalOrders'], 'orderChange' => $orderChange, 'totalRevenue' => $currentStats['totalRevenue'], 'revenueChange' => $revenueChange, 'avgDeliveryTime' => $currentStats['avgDeliveryTime'], 'timeChange' => $timeChange, 'completionRate' => $currentStats['completionRate'], 'completionChange' => $completionChange ); $this->ajaxReturn(array( 'code' => 200, 'msg' => '获取成功', 'data' => $result )); } catch (Exception $e) { $this->ajaxReturn(array( 'code' => 500, 'msg' => '获取失败:' . $e->getMessage() )); } } /** * 获取订单趋势数据 */ public function getOrderTrend() { $timeRange = I('timeRange', 'week', 'trim'); $startDate = I('startDate', '', 'trim'); $endDate = I('endDate', '', 'trim'); try { $dateCondition = $this->getDateCondition($timeRange, $startDate, $endDate); $orderModel = M('rider_order'); $trendData = array(); $labels = array(); if ($timeRange === 'week') { // 最近7天的数据 for ($i = 6; $i >= 0; $i--) { $date = date('Y-m-d', strtotime("-{$i} days")); $count = $orderModel->where(array('add_time' => array('like', $date . '%')))->count(); $trendData[] = intval($count); $labels[] = date('m-d', strtotime($date)); } } elseif ($timeRange === 'month') { // 最近30天,按周统计 for ($i = 3; $i >= 0; $i--) { $startWeek = date('Y-m-d', strtotime("-" . (($i + 1) * 7) . " days")); $endWeek = date('Y-m-d', strtotime("-" . ($i * 7) . " days")); $count = $orderModel->where(array( 'add_time' => array('between', array($startWeek, $endWeek)) ))->count(); $trendData[] = intval($count); $labels[] = date('m-d', strtotime($startWeek)) . '~' . date('m-d', strtotime($endWeek)); } } else { // 自定义时间范围,按天统计 $start = strtotime($startDate); $end = strtotime($endDate); $days = ($end - $start) / (24 * 3600) + 1; for ($i = 0; $i < $days; $i++) { $date = date('Y-m-d', $start + $i * 24 * 3600); $count = $orderModel->where(array('add_time' => array('like', $date . '%')))->count(); $trendData[] = intval($count); $labels[] = date('m-d', strtotime($date)); } } $this->ajaxReturn(array( 'code' => 200, 'msg' => '获取成功', 'data' => array( 'labels' => $labels, 'data' => $trendData ) )); } catch (Exception $e) { $this->ajaxReturn(array( 'code' => 500, 'msg' => '获取失败:' . $e->getMessage() )); } } /** * 获取收入趋势数据 */ public function getRevenueTrend() { $timeRange = I('timeRange', 'week', 'trim'); $startDate = I('startDate', '', 'trim'); $endDate = I('endDate', '', 'trim'); try { $dateCondition = $this->getDateCondition($timeRange, $startDate, $endDate); $orderModel = M('rider_order'); $trendData = array(); $labels = array(); if ($timeRange === 'week') { // 最近7天的数据 for ($i = 6; $i >= 0; $i--) { $date = date('Y-m-d', strtotime("-{$i} days")); $revenue = $orderModel ->where(array( 'order_status' => 6, 'delivery_time' => array('like', $date . '%') )) ->sum('delivery_fee'); $trendData[] = floatval($revenue); $labels[] = date('m-d', strtotime($date)); } } elseif ($timeRange === 'month') { // 最近30天,按周统计 for ($i = 3; $i >= 0; $i--) { $startWeek = date('Y-m-d', strtotime("-" . (($i + 1) * 7) . " days")); $endWeek = date('Y-m-d', strtotime("-" . ($i * 7) . " days")); $revenue = $orderModel ->where(array( 'order_status' => 6, 'delivery_time' => array('between', array($startWeek, $endWeek)) )) ->sum('delivery_fee'); $trendData[] = floatval($revenue); $labels[] = date('m-d', strtotime($startWeek)) . '~' . date('m-d', strtotime($endWeek)); } } $this->ajaxReturn(array( 'code' => 200, 'msg' => '获取成功', 'data' => array( 'labels' => $labels, 'data' => $trendData ) )); } catch (Exception $e) { $this->ajaxReturn(array( 'code' => 500, 'msg' => '获取失败:' . $e->getMessage() )); } } /** * 获取订单状态分布 */ public function getOrderStatusDistribution() { $timeRange = I('timeRange', 'today', 'trim'); $startDate = I('startDate', '', 'trim'); $endDate = I('endDate', '', 'trim'); try { $dateCondition = $this->getDateCondition($timeRange, $startDate, $endDate); $orderModel = M('rider_order'); import('Common.Business.OrderStatusUtil'); $statusList = array('pending', 'accepted', 'picking_up', 'delivering', 'completed', 'cancelled'); $statusData = array(); foreach ($statusList as $status) { $condition = $dateCondition; $cond = \Common\Business\OrderStatusUtil::getStatusCondition($status); if (!is_null($cond)) { $condition['order_status'] = $cond; } $count = $orderModel->where($condition)->count(); $statusData[] = array( 'name' => \Common\Business\OrderStatusUtil::getStatusText($status), 'value' => intval($count) ); } $this->ajaxReturn(array( 'code' => 200, 'msg' => '获取成功', 'data' => $statusData )); } catch (Exception $e) { $this->ajaxReturn(array( 'code' => 500, 'msg' => '获取失败:' . $e->getMessage() )); } } /** * 获取骑手排行榜 */ public function getRiderRanking() { $timeRange = I('timeRange', 'today', 'trim'); $startDate = I('startDate', '', 'trim'); $endDate = I('endDate', '', 'trim'); $limit = I('limit', 10, 'intval'); try { $dateCondition = $this->getDateCondition($timeRange, $startDate, $endDate); $sql = "SELECT r.id, r.rider_name AS name, r.rider_phone AS phone, r.rider_avatar AS avatar, r.rating, COUNT(o.id) as total_orders, SUM(o.delivery_fee) as total_revenue, AVG(TIMESTAMPDIFF(MINUTE, o.accept_time, o.delivery_time)) as avg_delivery_time, SUM(o.distance) as total_distance, (COUNT(CASE WHEN o.order_status = 6 THEN 1 END) * 100.0 / COUNT(o.id)) as completion_rate FROM ls_rider_info r LEFT JOIN ls_rider_order o ON r.id = o.rider_id"; if (!empty($dateCondition)) { $sql .= " AND " . $this->buildWhereString($this->aliasConditions($dateCondition, 'o')); } $sql .= " GROUP BY r.id HAVING total_orders > 0 ORDER BY total_orders DESC LIMIT {$limit}"; $riderStats = M()->query($sql); // 处理数据 foreach ($riderStats as &$rider) { $rider['total_orders'] = intval($rider['total_orders']); $rider['total_revenue'] = floatval($rider['total_revenue']); $rider['avg_delivery_time'] = intval($rider['avg_delivery_time']); $rider['total_distance'] = floatval($rider['total_distance']); $rider['completion_rate'] = floatval($rider['completion_rate']); $rider['rating'] = floatval($rider['rating']); $rider['avatar'] = $rider['avatar'] ?: ''; } $this->ajaxReturn(array( 'code' => 200, 'msg' => '获取成功', 'data' => $riderStats ?: array() )); } catch (Exception $e) { $this->ajaxReturn(array( 'code' => 500, 'msg' => '获取失败:' . $e->getMessage() )); } } /** * 获取配送时段分析 */ public function getTimeSlotAnalysis() { $timeRange = I('timeRange', 'today', 'trim'); $startDate = I('startDate', '', 'trim'); $endDate = I('endDate', '', 'trim'); try { $dateCondition = $this->getDateCondition($timeRange, $startDate, $endDate); $orderModel = M('rider_order'); $timeSlots = array( '8-10' => array(8, 10), '10-12' => array(10, 12), '12-14' => array(12, 14), '14-16' => array(14, 16), '16-18' => array(16, 18), '18-20' => array(18, 20), '20-22' => array(20, 22) ); $slotData = array(); $labels = array(); foreach ($timeSlots as $label => $hours) { $condition = $dateCondition; $condition['_string'] = "HOUR(add_time) >= {$hours[0]} AND HOUR(add_time) < {$hours[1]}"; $count = $orderModel->where($condition)->count(); $slotData[] = intval($count); $labels[] = $label; } $this->ajaxReturn(array( 'code' => 200, 'msg' => '获取成功', 'data' => array( 'labels' => $labels, 'data' => $slotData ) )); } catch (Exception $e) { $this->ajaxReturn(array( 'code' => 500, 'msg' => '获取失败:' . $e->getMessage() )); } } /** * 获取骑手详细统计 */ public function getRiderDetailStats() { $timeRange = I('timeRange', 'today', 'trim'); $startDate = I('startDate', '', 'trim'); $endDate = I('endDate', '', 'trim'); $page = I('page', 1, 'intval'); $pageSize = I('pageSize', 20, 'intval'); try { $dateCondition = $this->getDateCondition($timeRange, $startDate, $endDate); $sql = "SELECT r.id, r.rider_name AS name, r.rider_phone AS phone, r.rider_avatar AS avatar, r.rating, COUNT(o.id) as total_orders, SUM(o.delivery_fee) as total_revenue, AVG(TIMESTAMPDIFF(MINUTE, o.accept_time, o.delivery_time)) as avg_delivery_time, SUM(o.distance) as total_distance, (COUNT(CASE WHEN o.order_status = 6 THEN 1 END) * 100.0 / COUNT(o.id)) as completion_rate, 0 as online_hours FROM ls_rider_info r LEFT JOIN ls_rider_order o ON r.id = o.rider_id"; if (!empty($dateCondition)) { $sql .= " AND " . $this->buildWhereString($this->aliasConditions($dateCondition, 'o')); } $sql .= " GROUP BY r.id ORDER BY total_orders DESC"; // 获取总数 $countSql = "SELECT COUNT(*) as total FROM ({$sql}) as temp"; $totalResult = M()->query($countSql); $totalCount = $totalResult[0]['total']; // 分页 $offset = ($page - 1) * $pageSize; $sql .= " LIMIT {$offset}, {$pageSize}"; $riderStats = M()->query($sql); // 处理数据 foreach ($riderStats as &$rider) { $rider['total_orders'] = intval($rider['total_orders']); $rider['total_revenue'] = floatval($rider['total_revenue']); $rider['avg_delivery_time'] = intval($rider['avg_delivery_time']); $rider['total_distance'] = floatval($rider['total_distance']); $rider['completion_rate'] = floatval($rider['completion_rate']); $rider['rating'] = floatval($rider['rating']); $rider['online_hours'] = intval($rider['online_hours']); $rider['avatar'] = $rider['avatar'] ?: ''; } $this->ajaxReturn(array( 'code' => 200, 'msg' => '获取成功', 'data' => array( 'list' => $riderStats ?: array(), 'totalCount' => $totalCount, 'currentPage' => $page, 'pageSize' => $pageSize ) )); } catch (Exception $e) { $this->ajaxReturn(array( 'code' => 500, 'msg' => '获取失败:' . $e->getMessage() )); } } /** * 根据时间范围获取日期条件 */ private function getDateCondition($timeRange, $startDate = '', $endDate = '') { $condition = array(); switch ($timeRange) { case 'today': $condition['add_time'] = array('like', date('Y-m-d') . '%'); break; case 'yesterday': $condition['add_time'] = array('like', date('Y-m-d', strtotime('-1 day')) . '%'); break; case 'week': $condition['add_time'] = array('egt', date('Y-m-d', strtotime('-7 days'))); break; case 'month': $condition['add_time'] = array('egt', date('Y-m-d', strtotime('-30 days'))); break; case 'custom': if (!empty($startDate) && !empty($endDate)) { $condition['add_time'] = array('between', array($startDate, $endDate)); } break; } return $condition; } /** * 获取上一期间的日期条件 */ private function getPrevDateCondition($timeRange, $startDate = '', $endDate = '') { $condition = array(); switch ($timeRange) { case 'today': $condition['add_time'] = array('like', date('Y-m-d', strtotime('-1 day')) . '%'); break; case 'yesterday': $condition['add_time'] = array('like', date('Y-m-d', strtotime('-2 days')) . '%'); break; case 'week': $condition['add_time'] = array('between', array( date('Y-m-d', strtotime('-14 days')), date('Y-m-d', strtotime('-7 days')) )); break; case 'month': $condition['add_time'] = array('between', array( date('Y-m-d', strtotime('-60 days')), date('Y-m-d', strtotime('-30 days')) )); break; } return $condition; } /** * 计算期间统计数据 */ private function calculatePeriodStats($orderModel, $dateCondition) { // 总订单数 $totalOrders = $orderModel->where($dateCondition)->count(); // 总收入 $revenueCondition = array_merge($dateCondition, array('order_status' => 6)); $totalRevenue = $orderModel->where($revenueCondition)->sum('delivery_fee'); // 平均配送时间 $avgDeliveryTime = $orderModel ->where($revenueCondition) ->avg('TIMESTAMPDIFF(MINUTE, accept_time, delivery_time)'); // 完成率 $completedOrders = $orderModel->where($revenueCondition)->count(); $completionRate = $totalOrders > 0 ? ($completedOrders / $totalOrders) * 100 : 0; return array( 'totalOrders' => intval($totalOrders), 'totalRevenue' => floatval($totalRevenue), 'avgDeliveryTime' => intval($avgDeliveryTime), 'completionRate' => floatval($completionRate) ); } /** * 计算变化率 */ private function calculateChangeRate($current, $previous, $reverse = false) { if ($previous == 0) { return $current > 0 ? 100 : 0; } $rate = (($current - $previous) / $previous) * 100; // 对于时间类指标,减少是好的 if ($reverse) { $rate = -$rate; } return round($rate, 1); } /** * 构建WHERE字符串 */ private function buildWhereString($conditions) { $whereArray = array(); foreach ($conditions as $field => $value) { if (is_array($value)) { if ($value[0] === 'like') { $whereArray[] = "{$field} LIKE '{$value[1]}'"; } elseif ($value[0] === 'between') { $whereArray[] = "{$field} BETWEEN '{$value[1][0]}' AND '{$value[1][1]}'"; } elseif ($value[0] === 'egt') { $whereArray[] = "{$field} >= '{$value[1]}'"; } } else { $whereArray[] = "{$field} = '{$value}'"; } } return implode(' AND ', $whereArray); } /** * 为条件键添加表别名前缀 */ private function aliasConditions($conditions, $alias) { $result = array(); foreach ($conditions as $field => $value) { $prefixed = $alias . '.' . $field; $result[$prefixed] = $value; } return $result; } /** * 获取状态文本 */ private function getStatusText($status) { $statusTexts = array( 'pending' => '待分配', 'accepted' => '已接单', 'picking_up' => '取货中', 'delivering' => '配送中', 'completed' => '已完成', 'cancelled' => '已取消' ); return isset($statusTexts[$status]) ? $statusTexts[$status] : '未知'; } } ?>