From 04102f7237efefa744090ed7c25f7b5d0807b679 Mon Sep 17 00:00:00 2001
From: quanwei <419654421@qq.com>
Date: Thu, 05 Feb 2026 18:11:57 +0800
Subject: [PATCH] 完成运营中心提现和运营中心权限管理
---
admin/app/api/model/supplier/Supplier.php | 384 ++++++++++++++++++++++++++++++++++++++++++++++--------
1 files changed, 327 insertions(+), 57 deletions(-)
diff --git a/admin/app/api/model/supplier/Supplier.php b/admin/app/api/model/supplier/Supplier.php
index 22997d6..200dd39 100644
--- a/admin/app/api/model/supplier/Supplier.php
+++ b/admin/app/api/model/supplier/Supplier.php
@@ -115,8 +115,9 @@
->order($sort)
->paginate($param);
$product_model = new ProductModel();
- foreach ($list as $key => &$v) {
+ foreach ($list as &$v) {
$productList = $product_model->with(['image.file'])
+ ->where('is_gift_pack', '=', 0)
->where([
'shop_supplier_id' => $v['shop_supplier_id'],
'product_status' => 10,
@@ -205,52 +206,268 @@
}
/**
- * 获取团贯商户列表(用于移动端团购组件)
+ * 获取团购商户列表(用于移动端团购组件)
* @param array $param 查询参数
* @return \think\Paginator
*/
public function getGroupBuyList($param)
{
+ // 获取用户经纬度(用于计算距离)
+ $user_latitude = isset($param['latitude']) ? floatval($param['latitude']) : 0;
+ $user_longitude = isset($param['longitude']) ? floatval($param['longitude']) : 0;
+
// 排序规则
$sort = [];
- if (isset($param['sortType'])) {
- if ($param['sortType'] === 'all') {
- $sort = ['s.create_time' => 'desc'];
- } else if ($param['sortType'] === 'sales') {
- $sort = ['product_sales' => 'desc'];
- } else if ($param['sortType'] === 'score') {
- $sort = ['server_score' => 'desc'];
- }
+ $sortType = isset($param['sortType']) ? $param['sortType'] : 'all';
+
+ // 初始化排序标志
+ $needDistanceSort = false;
+ $needPriceSort = false;
+ $needDistanceFilter = false;
+ $needPriceFilter = false;
+ $needCouponFilter = false;
+ $needTopRankedFilter = false;
+
+ if ($sortType === 'distance') {
+ // 使用子查询计算距离并排序
+ $sort = ['avg_price' => 'asc']; // 临时字段,实际使用子查询
+ $needDistanceSort = true;
+ } else if ($sortType === 'price_low' || $sortType === 'price_asc') {
+ // 使用子查询计算人均价格并升序排序
+ $sort = ['avg_price' => 'asc'];
+ $needPriceSort = true;
+ $priceSortOrder = 'asc';
+ } else if ($sortType === 'price_high' || $sortType === 'price_desc') {
+ // 使用子查询计算人均价格并降序排序
+ $sort = ['avg_price' => 'desc'];
+ $needPriceSort = true;
+ $priceSortOrder = 'desc';
+ } else if ($sortType === 'score') {
+ $sort = ['server_score' => 'desc'];
+ $needDistanceSort = false;
} else {
$sort = ['s.create_time' => 'desc'];
+ $needDistanceSort = false;
}
+
$model = $this;
-
+
// 分类筛选
if (isset($param['category_id']) && $param['category_id']) {
$model = $model->where('category_id', '=', $param['category_id']);
}
-
+
// 城市商户筛选
if (!empty($param['city_supplier_ids'])) {
$supplier_ids = is_array($param['city_supplier_ids']) ? $param['city_supplier_ids'] : explode(',', $param['city_supplier_ids']);
$model = $model->whereIn('shop_supplier_id', $supplier_ids);
}
-
+
+ // 最高减价筛选(仅看有券)
+ if (isset($param['has_coupon']) && $param['has_coupon'] == 1) {
+ $needCouponFilter = true;
+ }
+
+ // 好评榜筛选(前10名)
+ if (isset($param['top_ranked']) && $param['top_ranked'] == 1) {
+ $needTopRankedFilter = true;
+ }
+
+ // 最低评分筛选
+ $minScore = isset($param['min_score']) ? floatval($param['min_score']) : 0;
+ // 只在明确设置了评分限制时才进行筛选
+ if (isset($param['min_score']) && $minScore > 0) {
+ $model = $model->where('server_score', '>=', $minScore);
+ }
+
+ // 价格范围筛选 - 改为前置筛选,使用子查询
+ $priceMin = isset($param['price_min']) ? floatval($param['price_min']) : 0;
+ $priceMax = isset($param['price_max']) ? floatval($param['price_max']) : -1;
+ // 只有当价格参数有效时才进行筛选
+ if ((isset($param['price_min']) && $priceMin > 0) || (isset($param['price_max']) && $priceMax > 0)) {
+ $needPriceFilter = true;
+ }
+
+ // 最大距离筛选
+ $maxDistance = isset($param['max_distance']) ? floatval($param['max_distance']) : 0;
+ // 只在明确设置了距离限制时才进行筛选
+ if (isset($param['max_distance']) && $maxDistance > 0) {
+ $needDistanceFilter = true;
+ }
+
// 获取用户经纬度(用于计算距离)
$user_latitude = isset($param['latitude']) ? floatval($param['latitude']) : 0;
$user_longitude = isset($param['longitude']) ? floatval($param['longitude']) : 0;
-
- // 查询列表数据
- $list = $model->alias('s')
+
+ // 构建基础查询
+ $baseQuery = $model->alias('s')
->with(['logo', 'category'])
+ ->where('s.supplier_type',20)
->where('s.is_delete', '=', '0')
- ->where('s.is_recycle', '=', 0)
- //->where('s.supplier_type', '=', 20)
- ->field("s.shop_supplier_id,s.supplier_type,s.name as supplier_name,s.fav_count,logo_id,category_id,server_score,product_sales,address,link_phone,longitude,latitude,supplier_type")
- ->order($sort)
- ->paginate($param);
-
+ ->where('s.is_recycle', '=', 0);
+
+ // 添加评分排名子查询(用于好评榜筛选)
+ if ($needTopRankedFilter) {
+ // 先获取按评分排序的商户列表,获取前N名的ID
+ $rankSubQuery = $this->alias('s')
+ ->field('shop_supplier_id')
+ ->where('s.is_delete', '=', '0')
+ ->where('s.is_recycle', '=', 0);
+
+ // 应用分类筛选
+ if (isset($param['category_id']) && $param['category_id']) {
+ $rankSubQuery = $rankSubQuery->where('category_id', '=', $param['category_id']);
+ }
+
+ // 应用城市商户筛选
+ if (!empty($param['city_supplier_ids'])) {
+ $supplier_ids = is_array($param['city_supplier_ids']) ? $param['city_supplier_ids'] : explode(',', $param['city_supplier_ids']);
+ $rankSubQuery = $rankSubQuery->whereIn('shop_supplier_id', $supplier_ids);
+ }
+
+ $rankSubQuery = $rankSubQuery
+ ->order(['server_score' => 'desc', 'product_sales' => 'desc', 'create_time' => 'asc'])
+ ->limit(10) // 好评榜前10
+ ->buildSql();
+
+ // 在基础查询中添加对排名子查询的限制
+ $baseQuery = $baseQuery->join([$rankSubQuery => 'rank_top'], 's.shop_supplier_id = rank_top.shop_supplier_id', 'INNER');
+ }
+
+ // 添加优惠券筛选子查询
+ if ($needCouponFilter) {
+ // 检查是否存在全平台通用优惠券(shop_supplier_id = 0)
+ $platformCouponCount = \app\common\model\plus\coupon\Coupon::where('shop_supplier_id', '=', 0)
+ ->where('is_delete', '=', 0)
+ ->where(function ($query) {
+ // 领取后生效的优惠券
+ $query->whereOr('expire_type', '=', 10);
+ // 或者固定时间且未过期的优惠券
+ $query->whereOr(function ($q) {
+ $q->where('expire_type', '=', 20)
+ ->where('end_time', '>=', time() - 86400);
+ });
+ })
+ ->where(function ($query) {
+ // 数量不限制或者还有剩余
+ $query->whereOr('total_num', '=', -1);
+ $query->whereOr(function ($q) {
+ $q->whereRaw('receive_num < total_num');
+ });
+ })
+ ->count();
+
+ $hasPlatformCoupons = $platformCouponCount > 0;
+
+ if ($hasPlatformCoupons) {
+ // 如果存在全平台通用优惠券,则所有商户都符合条件,不需要额外筛选
+ // 保持baseQuery不变,所有商户都能通过筛选
+ } else {
+ // 如果没有全平台通用优惠券,则只筛选有自己专属优惠券或参与其他商户优惠券活动的商户
+ // 注意:商户可以参加其他商户发起的优惠券活动,因此需要更精确的逻辑
+
+ // 创建子查询获取所有有有效优惠券的商户(包括自己发起的和其他商户发起但本商户参与的)
+ $couponSubQuery = \app\common\model\plus\coupon\Coupon::alias('c')
+ ->field('DISTINCT shop_supplier_id')
+ ->where('c.is_delete', '=', 0)
+ ->where(function ($query) {
+ // 领取后生效的优惠券
+ $query->whereOr('expire_type', '=', 10);
+ // 或者固定时间且未过期的优惠券
+ $query->whereOr(function ($q) {
+ $q->where('expire_type', '=', 20)
+ ->where('end_time', '>=', time() - 86400);
+ });
+ })
+ ->where(function ($query) {
+ // 数量不限制或者还有剩余
+ $query->whereOr('total_num', '=', -1);
+ $query->whereOr(function ($q) {
+ $q->whereRaw('receive_num < total_num');
+ });
+ })
+ ->buildSql();
+
+ // 在基础查询中添加对优惠券子查询的限制
+ $baseQuery = $baseQuery->join([$couponSubQuery => 'coupon_valid'], 's.shop_supplier_id = coupon_valid.shop_supplier_id', 'INNER');
+ }
+ }
+
+ // 查询列表数据
+ if ($needPriceSort || $needPriceFilter) {
+ // 使用子查询计算人均价格并排序或筛选
+ $subQuery = \app\common\model\order\Order::alias('o')
+ ->field('shop_supplier_id, AVG(pay_price) as avg_price')
+ ->where('pay_status', '=', 20) // 已支付
+ ->where('order_status', '=', 30) // 已完成
+ ->where('is_delete', '=', 0)
+ ->group('shop_supplier_id')
+ ->buildSql();
+
+ // 添加评论数量子查询
+ $commentSubQuery = \app\common\model\product\Comment::alias('c')
+ ->field('shop_supplier_id, COUNT(*) as comment_count')
+ ->where('status', '=', 1) // 已审核通过的评论
+ ->where('is_delete', '=', 0)
+ ->group('shop_supplier_id')
+ ->buildSql();
+
+ $listRaw = $baseQuery
+ ->join([$subQuery => 'avg_sub'], 's.shop_supplier_id = avg_sub.shop_supplier_id', 'LEFT')
+ ->join([$commentSubQuery => 'comment_count_sub'], 's.shop_supplier_id = comment_count_sub.shop_supplier_id', 'LEFT')
+ ->field("s.shop_supplier_id,s.supplier_type,s.name as supplier_name,s.fav_count,logo_id,category_id,server_score,product_sales,address,link_phone,longitude,latitude,supplier_type,
+ COALESCE(avg_sub.avg_price, 0) as avg_price,
+ COALESCE(comment_count_sub.comment_count, 0) as comment_count")
+ ->with(['logo', 'category']);
+
+ // 添加价格范围筛选条件
+ if ($needPriceFilter) {
+ if ($priceMin > 0) {
+ $listRaw = $listRaw->where('avg_sub.avg_price', '>=', $priceMin);
+ }
+ if ($priceMax > 0) {
+ $listRaw = $listRaw->where('avg_sub.avg_price', '<=', $priceMax);
+ }
+ }
+
+ $listRaw = $listRaw->order('avg_sub.avg_price ' . ($priceSortOrder ?? 'desc') . ', s.create_time desc')
+ ->paginate($param);
+ } else if ($needDistanceSort) {
+ // 添加评论数量子查询
+ $commentSubQuery = \app\common\model\product\Comment::alias('c')
+ ->field('shop_supplier_id, COUNT(*) as comment_count')
+ ->where('status', '=', 1) // 已审核通过的评论
+ ->where('is_delete', '=', 0)
+ ->group('shop_supplier_id')
+ ->buildSql();
+
+ // 使用子查询计算距离并排序(需要数据库支持地理函数)
+ $listRaw = $baseQuery
+ ->join([$commentSubQuery => 'comment_count_sub'], 's.shop_supplier_id = comment_count_sub.shop_supplier_id', 'LEFT')
+ ->field("s.shop_supplier_id,s.supplier_type,s.name as supplier_name,s.fav_count,logo_id,category_id,server_score,product_sales,address,link_phone,longitude,latitude,supplier_type,
+ IF(s.latitude > 0 AND s.longitude > 0, " . $user_latitude . ", 99999) as dist_sort,
+ COALESCE(comment_count_sub.comment_count, 0) as comment_count")
+ ->with(['logo', 'category'])
+ ->order('dist_sort asc, s.create_time desc')
+ ->paginate($param);
+ } else {
+ // 添加评论数量子查询
+ $commentSubQuery = \app\common\model\product\Comment::alias('c')
+ ->field('shop_supplier_id, COUNT(*) as comment_count')
+ ->where('status', '=', 1) // 已审核通过的评论
+ ->where('is_delete', '=', 0)
+ ->group('shop_supplier_id')
+ ->buildSql();
+
+ // 普通查询
+ $listRaw = $baseQuery
+ ->join([$commentSubQuery => 'comment_count_sub'], 's.shop_supplier_id = comment_count_sub.shop_supplier_id', 'LEFT')
+ ->field("s.shop_supplier_id,s.supplier_type,s.name as supplier_name,s.fav_count,logo_id,category_id,server_score,product_sales,address,link_phone,longitude,latitude,supplier_type,
+ COALESCE(comment_count_sub.comment_count, 0) as comment_count")
+ ->order($sort)
+ ->paginate($param);
+ }
+
// 计算评分排名:先查询所有符合条件商户的评分
$rankModel = $this;
if (isset($param['category_id']) && $param['category_id']) {
@@ -264,25 +481,25 @@
$allSuppliers = $rankModel
->where('is_delete', '=', '0')
->where('is_recycle', '=', 0)
- //->where('supplier_type', '=', 20)
+ ->where('supplier_type', '=', 20)
->field('shop_supplier_id,server_score,product_sales')
->order(['server_score' => 'desc', 'product_sales' => 'desc', 'create_time' => 'asc'])
->select()
->toArray();
-
+
// 构建评分排名映射表
$rankMap = [];
foreach ($allSuppliers as $index => $supplier) {
$rankMap[$supplier['shop_supplier_id']] = $index + 1;
}
-
+
// 获取商品模型
$product_model = new ProductModel();
-
- // 将集合转为数组,避免间接修改警告
- $listData = $list->toArray();
-
- foreach ($listData['data'] as $key => &$v) {
+
+ // 将集合转为数组
+ $listData = $listRaw->toArray();
+
+ foreach ($listData['data'] as &$v) {
// 获取商户的团购商品列表(最多3个)
$productList = $product_model->with(['image.file'])
->where([
@@ -295,17 +512,17 @@
->limit($param['product_num'])
->field('product_id,product_price,product_name,sales_initial,sales_actual,line_price')
->select();
-
+
// 格式化商品数据
$v['productList'] = [];
foreach ($productList as $product) {
// 计算该商品可用的最高优惠券减价
$product_reduce = $this->calculateProductReducePrice(
- $v['shop_supplier_id'],
+ $v['shop_supplier_id'],
$product['product_id'],
$product['product_price']
);
-
+
$v['productList'][] = [
'product_id' => $product['product_id'],
'product_name' => $product['product_name'],
@@ -315,27 +532,29 @@
'reduce_price' => $product_reduce, // 根据优惠券计算商品减价
];
}
-
- // 计算人均消费:根据商户历史订单计算
- $average_price = $this->calculateAverageConsumption($v['shop_supplier_id']);
-
+
+ // 使用子查询返回的人均价格(如果存在)
+ $average_price = isset($v['avg_price']) && $v['avg_price'] > 0
+ ? round($v['avg_price'], 2)
+ : $this->calculateAverageConsumption($v['shop_supplier_id']);
+
// 计算与用户的距离
$distance = $this->calculateDistance(
- $user_latitude,
- $user_longitude,
- floatval($v['latitude']),
+ $user_latitude,
+ $user_longitude,
+ floatval($v['latitude']),
floatval($v['longitude'])
);
-
+
// 计算最高减价:根据商户优惠券
$max_reduce_price = $this->calculateMaxReducePrice($v['shop_supplier_id']);
-
+
// 商户信息格式化
$v['logo_image'] = isset($v['logo']) ? $v['logo']['file_path'] : '';
$v['category_name'] = isset($v['category']) ? $v['category']['name'] : '';
$v['latitude'] = (float)$v['latitude'];
$v['longitude'] = (float)$v['longitude'];
-
+
// 模拟团购数据(根据实际业务调整)
$v['server_score'] = $v['server_score'] ?: 4.8;
$v['server_score_text'] = '';
@@ -347,19 +566,49 @@
$v['server_score_text'] = ' 超赞';
}
$v['comment'] = $v['fav_count'] ?: 0;
+ $v['comment_count'] = isset($v['comment_count']) ? $v['comment_count'] : 0; // 评论数量
$v['average_price'] = $average_price; // 人均消费,根据历史订单计算
$v['distance'] = $distance; // 距离,根据经纬度计算
$v['max_reduce_price'] = $max_reduce_price; // 最高减价,根据优惠券计算
// 根据评分获取排名
$v['ranking'] = isset($rankMap[$v['shop_supplier_id']]) ? $rankMap[$v['shop_supplier_id']] : 999;
-
+ // 存储距离的数值用于排序
+ $v['distance_value'] = $this->parseDistanceValue($distance);
+
unset($v['logo']);
unset($v['category']);
}
-
+
+ // 后置筛选 - 现在只需要处理不需要子查询的筛选
+ $filteredData = [];
+ foreach ($listData['data'] as $item) {
+ // 距离筛选
+ if (isset($needDistanceFilter) && $needDistanceFilter === true) {
+ $distanceKm = $item['distance_value'];
+ if ($distanceKm > $maxDistance) continue;
+ }
+
+ $filteredData[] = $item;
+ }
+
+ $listData['data'] = $filteredData;
+
+ // 距离排序仍然在PHP中处理(因为距离计算涉及复杂公式)
+ if ($needDistanceSort) {
+ usort($listData['data'], function($a, $b) {
+ return $a['distance_value'] <=> $b['distance_value'];
+ });
+ // 重新分页
+ $page = isset($param['page']) ? intval($param['page']) : 1;
+ $pageSize = isset($param['list_rows']) ? intval($param['list_rows']) : 10;
+ $offset = ($page - 1) * $pageSize;
+ $listData['total'] = count($listData['data']);
+ $listData['data'] = array_slice($listData['data'], $offset, $pageSize);
+ }
+
// 更新分页数据
$list = $listData;
-
+
return $list;
}
@@ -377,31 +626,31 @@
->where('is_delete', '=', 0)
->field('order_id, pay_price, user_id')
->select();
-
+
if ($orderModel->isEmpty()) {
// 没有订单,返回默认值
return 0;
}
-
+
// 计算总金额和总人数(去重用户)
$totalAmount = 0;
$userIds = [];
-
+
foreach ($orderModel as $order) {
$totalAmount += $order['pay_price'];
$userIds[] = $order['user_id'];
}
-
+
// 去重用户数量
$uniqueUsers = array_unique($userIds);
$userCount = count($uniqueUsers);
-
+
// 计算人均消费
if ($userCount > 0) {
$averagePrice = round($totalAmount / $userCount, 2);
return $averagePrice > 0 ? $averagePrice : 0;
}
-
+
return 0;
}
@@ -419,27 +668,27 @@
if (empty($lat1) || empty($lon1) || empty($lat2) || empty($lon2)) {
return '--';
}
-
+
// 地球半径(千米)
$earthRadius = 6371;
-
+
// 将角度转为弧度
$lat1Rad = deg2rad($lat1);
$lon1Rad = deg2rad($lon1);
$lat2Rad = deg2rad($lat2);
$lon2Rad = deg2rad($lon2);
-
+
// 计算纬度和经度的差值
$latDiff = $lat2Rad - $lat1Rad;
$lonDiff = $lon2Rad - $lon1Rad;
-
+
// Haversine公式计算距离
$a = sin($latDiff / 2) * sin($latDiff / 2) +
cos($lat1Rad) * cos($lat2Rad) *
sin($lonDiff / 2) * sin($lonDiff / 2);
$c = 2 * atan2(sqrt($a), sqrt(1 - $a));
$distance = $earthRadius * $c;
-
+
// 格式化距离
if ($distance < 1) {
// 小于1千米,显示为米
@@ -454,6 +703,27 @@
}
/**
+ * 解析距离字符串返回数值(用于排序)
+ * @param string $distanceStr 距离字符串(如:"1.2km" 或 "500m")
+ * @return float 距离数值(千米)
+ */
+ private function parseDistanceValue($distanceStr)
+ {
+ if (empty($distanceStr) || $distanceStr === '--') {
+ return 99999;
+ }
+
+ $value = 0;
+ if (strpos($distanceStr, 'km') !== false) {
+ $value = floatval(str_replace('km', '', $distanceStr));
+ } else if (strpos($distanceStr, 'm') !== false) {
+ $value = floatval(str_replace('m', '', $distanceStr)) / 1000;
+ }
+
+ return $value;
+ }
+
+ /**
* 计算商户的最高减价(根据优惠券)
* @param int $shop_supplier_id 商户ID
* @return float 最高减价金额
--
Gitblit v1.9.2