display(); } /** * 获取配送区域列表 */ public function getAreaList() { $page = I('page', 1, 'intval'); $pageSize = I('pageSize', 20, 'intval'); $keyword = I('keyword', '', 'trim'); $status = I('status', '', 'trim'); $city_id = I('city_id', 0, 'intval'); $where = array(); // 关键词搜索 if (!empty($keyword)) { $where['area_name'] = array('like', '%' . $keyword . '%'); } // 状态筛选 if ($status !== '') { $where['status'] = $status; } // 城市筛选 if ($city_id > 0) { $where['city_id'] = $city_id; } $model = M('delivery_area'); $total = $model->where($where)->count(); $list = $model->where($where) ->order('create_time desc') ->page($page, $pageSize) ->select(); // 格式化数据 foreach ($list as &$item) { $item['status_text'] = $this->getStatusText($item['status']); $item['create_time_format'] = date('Y-m-d H:i:s', $item['create_time']); // 获取城市名称 $city = M('city')->where(array('id' => $item['city_id']))->find(); $item['city_name'] = $city ? $city['name'] : ''; // 统计该区域的骑手数量 $item['rider_count'] = M('rider_area')->where(array('area_id' => $item['id']))->count(); // 统计该区域的订单数量(今日) $today_start = strtotime(date('Y-m-d 00:00:00')); $today_end = strtotime(date('Y-m-d 23:59:59')); $item['today_orders'] = M('order')->where(array( 'delivery_area_id' => $item['id'], 'create_time' => array('between', array($today_start, $today_end)) ))->count(); } $this->ajaxReturn(array( 'code' => 0, 'msg' => 'success', 'data' => array( 'list' => $list, 'total' => $total ) )); } /** * 获取区域详情 */ public function getAreaDetail() { $id = I('id', 0, 'intval'); if (empty($id)) { $this->ajaxReturn(array('code' => 1, 'msg' => '参数错误')); } $detail = M('delivery_area')->where(array('id' => $id))->find(); if (empty($detail)) { $this->ajaxReturn(array('code' => 1, 'msg' => '区域不存在')); } // 格式化数据 $detail['status_text'] = $this->getStatusText($detail['status']); $detail['create_time_format'] = date('Y-m-d H:i:s', $detail['create_time']); // 获取城市信息 $city = M('city')->where(array('id' => $detail['city_id']))->find(); $detail['city_info'] = $city; // 解析区域坐标 if (!empty($detail['coordinates'])) { $detail['coordinate_list'] = json_decode($detail['coordinates'], true); } else { $detail['coordinate_list'] = array(); } // 获取区域统计 $stats = $this->getSingleAreaStats($id); $detail['stats'] = $stats; $this->ajaxReturn(array( 'code' => 0, 'msg' => 'success', 'data' => $detail )); } /** * 添加/编辑配送区域 */ public function saveArea() { $id = I('id', 0, 'intval'); $data = array( 'area_name' => I('area_name', '', 'trim'), 'city_id' => I('city_id', 0, 'intval'), 'coordinates' => I('coordinates', '', 'trim'), 'center_lat' => I('center_lat', 0, 'floatval'), 'center_lng' => I('center_lng', 0, 'floatval'), 'radius' => I('radius', 0, 'floatval'), 'delivery_fee' => I('delivery_fee', 0, 'floatval'), 'min_order_amount' => I('min_order_amount', 0, 'floatval'), 'description' => I('description', '', 'trim'), 'status' => I('status', 1, 'intval') ); // 数据验证 if (empty($data['area_name'])) { $this->ajaxReturn(array('code' => 1, 'msg' => '区域名称不能为空')); } if ($data['city_id'] <= 0) { $this->ajaxReturn(array('code' => 1, 'msg' => '请选择城市')); } if (empty($data['coordinates'])) { $this->ajaxReturn(array('code' => 1, 'msg' => '区域坐标不能为空')); } $model = M('delivery_area'); if ($id > 0) { // 编辑 $data['update_time'] = time(); $result = $model->where(array('id' => $id))->save($data); } else { // 添加 $data['create_time'] = time(); $data['update_time'] = time(); $result = $model->add($data); } if ($result !== false) { $this->ajaxReturn(array('code' => 0, 'msg' => '操作成功')); } else { $this->ajaxReturn(array('code' => 1, 'msg' => '操作失败')); } } /** * 删除配送区域 */ public function deleteArea() { $id = I('id', 0, 'intval'); if (empty($id)) { $this->ajaxReturn(array('code' => 1, 'msg' => '参数错误')); } // 检查是否有骑手绑定 $riderCount = M('rider_area')->where(array('area_id' => $id))->count(); if ($riderCount > 0) { $this->ajaxReturn(array('code' => 1, 'msg' => '该区域已有骑手绑定,无法删除')); } $result = M('delivery_area')->where(array('id' => $id))->delete(); if ($result) { $this->ajaxReturn(array('code' => 0, 'msg' => '删除成功')); } else { $this->ajaxReturn(array('code' => 1, 'msg' => '删除失败')); } } /** * 启用/禁用区域 */ public function toggleStatus() { $id = I('id', 0, 'intval'); $status = I('status', 0, 'intval'); if (empty($id)) { $this->ajaxReturn(array('code' => 1, 'msg' => '参数错误')); } $result = M('delivery_area')->where(array('id' => $id))->save(array( 'status' => $status, 'update_time' => time() )); if ($result !== false) { $this->ajaxReturn(array('code' => 0, 'msg' => '操作成功')); } else { $this->ajaxReturn(array('code' => 1, 'msg' => '操作失败')); } } /** * 获取骑手区域分配列表 */ public function getRiderAreaList() { $page = I('page', 1, 'intval'); $pageSize = I('pageSize', 20, 'intval'); $keyword = I('keyword', '', 'trim'); $area_id = I('area_id', 0, 'intval'); $where = array(); // 关键词搜索 if (!empty($keyword)) { $where['_string'] = "(u.nickname LIKE '%{$keyword}%' OR u.phone LIKE '%{$keyword}%')"; } // 区域筛选 if ($area_id > 0) { $where['ra.area_id'] = $area_id; } $model = M('rider_area'); $total = $model->alias('ra') ->join('ls_users u ON ra.rider_id = u.id') ->join('ls_delivery_area da ON ra.area_id = da.id') ->where($where) ->count(); $list = $model->alias('ra') ->field('ra.*, u.nickname, u.phone, u.avatar, da.area_name') ->join('ls_users u ON ra.rider_id = u.id') ->join('ls_delivery_area da ON ra.area_id = da.id') ->where($where) ->order('ra.create_time desc') ->page($page, $pageSize) ->select(); // 格式化数据 foreach ($list as &$item) { $item['create_time_format'] = date('Y-m-d H:i:s', $item['create_time']); // 统计该骑手在该区域的订单数量 $item['order_count'] = M('order')->where(array( 'rider_id' => $item['rider_id'], 'delivery_area_id' => $item['area_id'] ))->count(); } $this->ajaxReturn(array( 'code' => 0, 'msg' => 'success', 'data' => array( 'list' => $list, 'total' => $total ) )); } /** * 分配骑手到区域 */ public function assignRiderToArea() { $rider_id = I('rider_id', 0, 'intval'); $area_ids = I('area_ids', '', 'trim'); if ($rider_id <= 0) { $this->ajaxReturn(array('code' => 1, 'msg' => '请选择骑手')); } if (empty($area_ids)) { $this->ajaxReturn(array('code' => 1, 'msg' => '请选择配送区域')); } $area_id_array = explode(',', $area_ids); // 先删除该骑手的所有区域分配 M('rider_area')->where(array('rider_id' => $rider_id))->delete(); // 重新分配区域 $success_count = 0; foreach ($area_id_array as $area_id) { $area_id = intval($area_id); if ($area_id <= 0) continue; $data = array( 'rider_id' => $rider_id, 'area_id' => $area_id, 'create_time' => time() ); $result = M('rider_area')->add($data); if ($result) { $success_count++; } } $this->ajaxReturn(array( 'code' => 0, 'msg' => "分配成功,共分配{$success_count}个区域" )); } /** * 移除骑手区域分配 */ public function removeRiderArea() { $id = I('id', 0, 'intval'); if (empty($id)) { $this->ajaxReturn(array('code' => 1, 'msg' => '参数错误')); } $result = M('rider_area')->where(array('id' => $id))->delete(); if ($result) { $this->ajaxReturn(array('code' => 0, 'msg' => '移除成功')); } else { $this->ajaxReturn(array('code' => 1, 'msg' => '移除失败')); } } /** * 获取区域热力图数据 */ public function getHeatmapData() { $area_id = I('area_id', 0, 'intval'); $date = I('date', date('Y-m-d'), 'trim'); $start_time = strtotime($date . ' 00:00:00'); $end_time = strtotime($date . ' 23:59:59'); $where = array( 'create_time' => array('between', array($start_time, $end_time)) ); if ($area_id > 0) { $where['delivery_area_id'] = $area_id; } // 获取订单分布数据 $orders = M('order')->field('pickup_lat, pickup_lng, delivery_lat, delivery_lng') ->where($where) ->select(); $heatmap_data = array(); foreach ($orders as $order) { // 取餐点 if (!empty($order['pickup_lat']) && !empty($order['pickup_lng'])) { $heatmap_data[] = array( 'lat' => floatval($order['pickup_lat']), 'lng' => floatval($order['pickup_lng']), 'type' => 'pickup', 'weight' => 1 ); } // 配送点 if (!empty($order['delivery_lat']) && !empty($order['delivery_lng'])) { $heatmap_data[] = array( 'lat' => floatval($order['delivery_lat']), 'lng' => floatval($order['delivery_lng']), 'type' => 'delivery', 'weight' => 1 ); } } $this->ajaxReturn(array( 'code' => 0, 'msg' => 'success', 'data' => $heatmap_data )); } /** * 导出区域数据 */ public function exportArea() { $keyword = I('keyword', '', 'trim'); $status = I('status', '', 'trim'); $city_id = I('city_id', 0, 'intval'); $where = array(); if (!empty($keyword)) { $where['area_name'] = array('like', '%' . $keyword . '%'); } if ($status !== '') { $where['status'] = $status; } if ($city_id > 0) { $where['city_id'] = $city_id; } $list = M('delivery_area')->where($where)->order('create_time desc')->select(); // 导出Excel vendor('PHPExcel.PHPExcel'); $objPHPExcel = new \PHPExcel(); $objPHPExcel->setActiveSheetIndex(0); $objActSheet = $objPHPExcel->getActiveSheet(); // 设置表头 $objActSheet->setCellValue('A1', '区域ID'); $objActSheet->setCellValue('B1', '区域名称'); $objActSheet->setCellValue('C1', '城市'); $objActSheet->setCellValue('D1', '中心坐标'); $objActSheet->setCellValue('E1', '配送半径'); $objActSheet->setCellValue('F1', '配送费'); $objActSheet->setCellValue('G1', '最低起送金额'); $objActSheet->setCellValue('H1', '状态'); $objActSheet->setCellValue('I1', '骑手数量'); $objActSheet->setCellValue('J1', '创建时间'); // 填充数据 $row = 2; foreach ($list as $item) { $city = M('city')->where(array('id' => $item['city_id']))->find(); $rider_count = M('rider_area')->where(array('area_id' => $item['id']))->count(); $objActSheet->setCellValue('A' . $row, $item['id']); $objActSheet->setCellValue('B' . $row, $item['area_name']); $objActSheet->setCellValue('C' . $row, $city ? $city['name'] : ''); $objActSheet->setCellValue('D' . $row, $item['center_lat'] . ',' . $item['center_lng']); $objActSheet->setCellValue('E' . $row, $item['radius'] . 'km'); $objActSheet->setCellValue('F' . $row, $item['delivery_fee']); $objActSheet->setCellValue('G' . $row, $item['min_order_amount']); $objActSheet->setCellValue('H' . $row, $this->getStatusText($item['status'])); $objActSheet->setCellValue('I' . $row, $rider_count); $objActSheet->setCellValue('J' . $row, date('Y-m-d H:i:s', $item['create_time'])); $row++; } $filename = '配送区域_' . date('YmdHis') . '.xlsx'; header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); header('Content-Disposition: attachment;filename="' . $filename . '"'); header('Cache-Control: max-age=0'); $objWriter = \PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007'); $objWriter->save('php://output'); exit; } /** * 获取区域统计数据 */ public function getAreaStats() { $city_id = I('city_id', 0, 'intval'); $where = array(); if ($city_id > 0) { $where['city_id'] = $city_id; } $model = M('delivery_area'); $stats = array( 'total_count' => $model->where($where)->count(), 'active_count' => $model->where(array_merge($where, array('status' => 1)))->count(), 'inactive_count' => $model->where(array_merge($where, array('status' => 0)))->count() ); // 统计骑手分配情况 $stats['total_riders'] = M('rider_area')->alias('ra') ->join('ls_delivery_area da ON ra.area_id = da.id') ->where($where) ->count('DISTINCT ra.rider_id'); // 统计今日订单 $today_start = strtotime(date('Y-m-d 00:00:00')); $today_end = strtotime(date('Y-m-d 23:59:59')); $stats['today_orders'] = M('order')->alias('o') ->join('ls_delivery_area da ON o.delivery_area_id = da.id') ->where(array_merge($where, array( 'o.create_time' => array('between', array($today_start, $today_end)) ))) ->count(); $this->ajaxReturn(array( 'code' => 0, 'msg' => 'success', 'data' => $stats )); } /** * 获取单个区域统计数据 */ private function getSingleAreaStats($area_id) { $stats = array(); // 骑手数量 $stats['rider_count'] = M('rider_area')->where(array('area_id' => $area_id))->count(); // 今日订单 $today_start = strtotime(date('Y-m-d 00:00:00')); $today_end = strtotime(date('Y-m-d 23:59:59')); $stats['today_orders'] = M('order')->where(array( 'delivery_area_id' => $area_id, 'create_time' => array('between', array($today_start, $today_end)) ))->count(); // 本月订单 $month_start = strtotime(date('Y-m-01 00:00:00')); $month_end = strtotime(date('Y-m-t 23:59:59')); $stats['month_orders'] = M('order')->where(array( 'delivery_area_id' => $area_id, 'create_time' => array('between', array($month_start, $month_end)) ))->count(); // 平均配送时间 $stats['avg_delivery_time'] = M('order')->where(array( 'delivery_area_id' => $area_id, 'status' => 'completed' ))->avg('delivery_duration') / 60; // 转换为分钟 return $stats; } /** * 获取状态文本 */ private function getStatusText($status) { $statusMap = array( 0 => '已禁用', 1 => '已启用' ); return isset($statusMap[$status]) ? $statusMap[$status] : '未知'; } } ?>