where('activity_id', 'in', $activeActivityIds) ->where('stocks', '>', 0) // 有折扣库存的商品 ->field([ 'id as activity_sku_id', 'goods_id', 'sku_id', 'activity_id', 'discount', 'discount_price', 'stocks as discount_stocks', 'sale_quantity' ]) ->order('discount', 'asc') ->select(); if (empty($skuData)) { return []; } // 收集所有商品ID和SKU ID $skuDataArray = collection($skuData)->toArray(); $allGoodsIds = array_unique(array_column($skuDataArray, 'goods_id')); $allSkuIds = array_filter(array_unique(array_column($skuDataArray, 'sku_id'))); // 如果指定了商品ID,则过滤 if (!empty($goodsIds)) { $allGoodsIds = array_intersect($allGoodsIds, $goodsIds); if (empty($allGoodsIds)) { return []; } } // 第三步:批量查询商品信息 $goodsInfo = Db::table('shop_goods') ->where('id', 'in', $allGoodsIds) ->where('status', GoodsEnum::STATUS_ON_SALE) // 已上架的商品 ->column('id,title,sub_title,image,price,market_price,stocks,sales,spec_type', 'id'); // 第四步:批量查询SKU信息(如果有多规格商品) $skuInfo = []; if (!empty($allSkuIds)) { $skuInfo = Db::table('shop_goods_sku') ->where('id', 'in', $allSkuIds) ->column('id,price,image', 'id'); } // 第五步:批量查询活动信息 $activityInfo = Db::table('shop_activity') ->where('id', 'in', $activeActivityIds) ->column('id,name,start_time,end_time', 'id'); // 过滤掉不存在的商品 $filteredSkuData = array_filter($skuDataArray, function($item) use ($goodsInfo) { return isset($goodsInfo[$item['goods_id']]); }); // 如果设置了限制数量 if ($limit > 0) { $filteredSkuData = array_slice($filteredSkuData, 0, $limit); } // 处理返回数据 $processedData = []; foreach ($filteredSkuData as $item) { $goodsId = $item['goods_id']; $skuId = $item['sku_id']; $activityId = $item['activity_id']; // 获取商品信息 $goods = $goodsInfo[$goodsId]; // 如果商品还没有在结果中,初始化 if (!isset($processedData[$goodsId])) { // 构造商品基础信息 $goodsItem = [ 'goods_id' => $goodsId, 'title' => $goods['title'], 'sub_title' => $goods['sub_title'], 'image' => $goods['image'], 'original_price' => $goods['price'], 'market_price' => $goods['market_price'], 'goods_stocks' => $goods['stocks'], 'sales' => $goods['sales'], 'spec_type' => $goods['spec_type'], 'activity_id' => $activityId, 'activity_name' => $activityInfo[$activityId]['name'] ?? '', 'start_time' => $activityInfo[$activityId]['start_time'] ?? null, 'end_time' => $activityInfo[$activityId]['end_time'] ?? null, ]; $processedData[$goodsId] = self::initGoodsDiscountStructure($goodsItem); } // 添加折扣信息 $discountInfo = [ 'activity_sku_id' => $item['activity_sku_id'], 'sku_id' => $skuId, 'discount' => $item['discount'], 'discount_price' => $item['discount_price'], 'discount_stocks' => $item['discount_stocks'], 'sale_quantity' => $item['sale_quantity'] ]; // 如果是多规格商品,添加规格信息 if ($skuId > 0 && isset($skuInfo[$skuId])) { $discountInfo['sku_price'] = $skuInfo[$skuId]['price']; $discountInfo['sku_image'] = $skuInfo[$skuId]['image']; } $processedData[$goodsId]['discount_info'][] = $discountInfo; } // 处理外层折扣价格字段 $processedData = self::processGoodsDiscountData($processedData); return array_values($processedData); } /** * 新出一个方法 通过传入商品id 数组 查询 shop_activity 表中的 goods_ids 来查询是否有在进行中的 活动 * @param mixed $goodsIds * @return mixed|string|null */ public static function getActivityByGoodsIds($goodsIds = []) { if (empty($goodsIds)) { return null; } // 获取所有进行中的活动 $activities = Db::table('shop_activity') ->where('start_time', '<=', time()) ->where('end_time', '>=', time()) ->where('activity_status', ActivityEnum::ACTIVITY_STATUS_ONGOING) ->select(); // 在PHP中过滤匹配的活动 foreach ($activities as $activity) { if (empty($activity['goods_ids'])) { continue; } // 解析JSON数组 $activityGoodsIds = json_decode($activity['goods_ids'], true); if (!is_array($activityGoodsIds)) { continue; } // 检查是否有商品ID匹配 $intersection = array_intersect($goodsIds, $activityGoodsIds); if (!empty($intersection)) { return $activity; } } return null; } /** * 获取商品ID与活动的映射关系 * @param array $goodsIds 商品ID数组 * @return array 返回商品ID与活动信息的映射关系 */ public static function getGoodsActivityMapping($goodsIds = []) { if (empty($goodsIds)) { return []; } // 获取所有进行中的活动 $activities = Db::table('shop_activity') ->where('start_time', '<=', time()) ->where('end_time', '>=', time()) ->where('activity_status', ActivityEnum::ACTIVITY_STATUS_ONGOING) ->select(); $goodsActivityMapping = []; // 为每个商品ID初始化空的活动信息 foreach ($goodsIds as $goodsId) { $goodsActivityMapping[$goodsId] = null; } // 在PHP中匹配商品与活动 foreach ($activities as $activity) { if (empty($activity['goods_ids'])) { continue; } // 解析JSON数组 $activityGoodsIds = json_decode($activity['goods_ids'], true); if (!is_array($activityGoodsIds)) { continue; } // 为匹配的商品ID设置活动信息 foreach ($activityGoodsIds as $activityGoodsId) { if (in_array($activityGoodsId, $goodsIds)) { $goodsActivityMapping[$activityGoodsId] = $activity; } } } return $goodsActivityMapping; } /** * 查询单个商品是否参与正在进行的活动 * @param int $goodsId 商品ID * @return array|null 返回活动信息,如果没有参与活动则返回null * * 使用示例: * $goodsId = 47; * $activity = DiscountService::getGoodsActivity($goodsId); * if ($activity) { * echo "商品参与活动:" . $activity['activity_name']; * echo "活动ID:" . $activity['id']; * echo "活动类型:" . $activity['activity_type']; * } else { * echo "商品未参与任何活动"; * } */ public static function getGoodsActivity($goodsId) { if (empty($goodsId)) { return null; } // 获取所有进行中的活动 $activities = Db::table('shop_activity') ->where('start_time', '<=', time()) ->where('end_time', '>=', time()) ->where('activity_status', ActivityEnum::ACTIVITY_STATUS_ONGOING) ->select(); // 在PHP中查找匹配的活动 foreach ($activities as $activity) { if (empty($activity['goods_ids'])) { continue; } // 解析JSON数组 $activityGoodsIds = json_decode($activity['goods_ids'], true); if (!is_array($activityGoodsIds)) { continue; } // 检查商品ID是否在活动的商品列表中 if (in_array($goodsId, $activityGoodsIds)) { return $activity; } } return null; } /** * 检查单个商品是否参与正在进行的活动(简化版本,只返回true/false) * @param int $goodsId 商品ID * @return bool 是否参与活动 * * 使用示例: * $goodsId = 47; * if (DiscountService::hasActivity($goodsId)) { * echo "商品正在参与活动"; * } else { * echo "商品未参与活动"; * } */ public static function hasActivity($goodsId) { return self::getGoodsActivity($goodsId) !== null; } /** * 查询单个商品的折扣信息和对应的SKU折扣信息 * @param int $goodsId 商品ID * @return array|null 商品折扣信息,包含所有SKU的折扣详情,如果没有折扣则返回null */ public static function getGoodsDiscountDetail($goodsId) { // 第一步:查询当前时间有效的活动ID $activeActivityIds = self::getActiveActivityIds(); if (empty($activeActivityIds)) { return null; } // 第二步:查询该商品的SKU折扣数据 $result = Db::table('shop_activity_sku') ->alias('sku') ->join('shop_goods goods', 'sku.goods_id = goods.id') ->join('shop_goods_sku spec', 'sku.sku_id = spec.id', 'left') ->join(['shop_activity'=> 'activity'], 'sku.activity_id = activity.id') ->where('sku.goods_id', $goodsId) ->where('sku.activity_id', 'in', $activeActivityIds) ->where('goods.status', GoodsEnum::STATUS_ON_SALE) // 已上架的商品 ->where('sku.stocks', '>', 0) // 有折扣库存的商品 ->field([ 'goods.id as goods_id', 'goods.title', 'goods.sub_title', 'goods.image', 'goods.price as original_price', 'goods.market_price', 'goods.stocks as goods_stocks', 'goods.sales', 'goods.spec_type', 'sku.id as activity_sku_id', 'sku.sku_id', 'sku.discount', 'sku.discount_price', 'sku.stocks as discount_stocks', 'sku.sale_quantity', 'activity.id as activity_id', 'activity.name as activity_name', 'activity.start_time', 'activity.end_time', 'spec.price as sku_price', 'spec.image as sku_image', // 'spec.specs as sku_specs' ]) ->order('sku.discount', 'asc') // 按折扣力度排序,折扣越大越靠前 ->select(); if (empty($result)) { return null; } // 初始化商品折扣结构 $goodsDiscountData = self::initGoodsDiscountStructure($result[0]); // 处理所有SKU的折扣信息 foreach ($result as $item) { $skuId = $item['sku_id']; // 添加折扣信息 $discountInfo = [ 'activity_sku_id' => $item['activity_sku_id'], 'sku_id' => $skuId, 'discount' => $item['discount'], 'discount_price' => $item['discount_price'], 'discount_stocks' => $item['discount_stocks'], 'sale_quantity' => $item['sale_quantity'] ]; // 如果是多规格商品,添加规格信息 if ($skuId > 0) { $discountInfo['sku_price'] = $item['sku_price']; $discountInfo['sku_image'] = $item['sku_image']; // $discountInfo['sku_specs'] = $item['sku_specs']; } $goodsDiscountData['discount_info'][] = $discountInfo; } // 处理外层折扣价格字段 $discountPrices = []; $discounts = []; // 收集所有折扣价格和折扣率 foreach ($goodsDiscountData['discount_info'] as $discount) { $discountPrices[] = $discount['discount_price']; $discounts[] = $discount['discount']; } if (!empty($discountPrices)) { // 计算最低和最高折扣价格 $goodsDiscountData['min_discount_price'] = min($discountPrices); $goodsDiscountData['max_discount_price'] = max($discountPrices); $goodsDiscountData['min_discount'] = min($discounts); $goodsDiscountData['max_discount'] = max($discounts); // 单规格商品处理 if ($goodsDiscountData['spec_type'] == 0) { $goodsDiscountData['discount_price'] = $goodsDiscountData['min_discount_price']; $goodsDiscountData['discount'] = $goodsDiscountData['min_discount']; $goodsDiscountData['discount_amount'] = round($goodsDiscountData['original_price'] - $goodsDiscountData['discount_price'], 2); $goodsDiscountData['price_range'] = '¥' . $goodsDiscountData['discount_price']; } // 多规格商品处理 else { // 设置价格区间 if ($goodsDiscountData['min_discount_price'] == $goodsDiscountData['max_discount_price']) { $goodsDiscountData['price_range'] = '¥' . $goodsDiscountData['min_discount_price']; } else { $goodsDiscountData['price_range'] = '¥' . $goodsDiscountData['min_discount_price'] . '-' . $goodsDiscountData['max_discount_price']; } // 对于多规格,使用最低价格作为主要显示价格 $goodsDiscountData['discount_price'] = $goodsDiscountData['min_discount_price']; $goodsDiscountData['discount'] = $goodsDiscountData['min_discount']; } } $goodsDiscountData['remaining_time'] = self::formatRemainingTime($goodsDiscountData['end_time']); return $goodsDiscountData; } /** * 限时查询一个当前活动的信息和商品信息 活动信息直接加一个商品数组字段 * @param mixed $activityId * @return array|bool|Model|string|\PDOStatement|null */ public static function getCurrentActivity() { $currentTime = time(); // 查询活动信息 $activity = Db::table('shop_activity') // ->where('id', $activityId) ->where('start_time', '<=', $currentTime) ->where('end_time', '>=', $currentTime) ->where('activity_status', ActivityEnum::ACTIVITY_STATUS_ONGOING) ->where('status', StatusEnum::ENABLED) ->find(); if (!$activity) { return null; } // 查询该活动下的商品信息 $goods = Db::table('shop_activity_sku') ->alias('sku') ->join('shop_goods goods', 'sku.goods_id = goods.id') ->join('shop_goods_sku spec', 'sku.sku_id = spec.id', 'left') ->where('sku.activity_id', $activity['id']) ->where('goods.status', GoodsEnum::STATUS_ON_SALE) ->where('sku.stocks', '>', 0) ->field([ 'goods.id as goods_id', 'goods.title', 'goods.sub_title', 'goods.image', 'goods.price as original_price', 'goods.market_price', 'goods.stocks as goods_stocks', 'goods.sales', 'goods.spec_type', 'sku.id as activity_sku_id', 'sku.sku_id', 'sku.discount', 'sku.discount_price', 'sku.stocks as discount_stocks', 'sku.sale_quantity', 'spec.price as sku_price', 'spec.image as sku_image' ]) ->order('sku.discount', 'asc') ->select(); // 处理商品数据 $processedGoods = []; foreach ($goods as $item) { $goodsId = $item['goods_id']; if (!isset($processedGoods[$goodsId])) { $processedGoods[$goodsId] = self::initGoodsDiscountStructure($item); } $discountInfo = [ 'activity_sku_id' => $item['activity_sku_id'], 'sku_id' => $item['sku_id'], 'discount' => $item['discount'], 'discount_price' => $item['discount_price'], 'discount_stocks' => $item['discount_stocks'], 'sale_quantity' => $item['sale_quantity'] ]; if ($item['sku_id'] > 0) { $discountInfo['sku_price'] = $item['sku_price']; $discountInfo['sku_image'] = $item['sku_image']; } $processedGoods[$goodsId]['discount_info'][] = $discountInfo; } // 处理外层折扣价格字段 foreach ($processedGoods as &$goodsItem) { $discountPrices = []; $discounts = []; // 收集所有折扣价格和折扣率 foreach ($goodsItem['discount_info'] as $discount) { $discountPrices[] = $discount['discount_price']; $discounts[] = $discount['discount']; } if (!empty($discountPrices)) { // 计算最低和最高折扣价格 $goodsItem['min_discount_price'] = min($discountPrices); $goodsItem['max_discount_price'] = max($discountPrices); $goodsItem['min_discount'] = min($discounts); $goodsItem['max_discount'] = max($discounts); // 单规格商品处理 if ($goodsItem['spec_type'] == 0) { $goodsItem['discount_price'] = $goodsItem['min_discount_price']; $goodsItem['discount'] = $goodsItem['min_discount']; $goodsItem['discount_amount'] = max(0, round($goodsItem['original_price'] - $goodsItem['discount_price'], 2)); $goodsItem['price_range'] = '¥' . $goodsItem['discount_price']; } // 多规格商品处理 else { // 设置价格区间 if ($goodsItem['min_discount_price'] == $goodsItem['max_discount_price']) { $goodsItem['price_range'] = '¥' . $goodsItem['min_discount_price']; } else { $goodsItem['price_range'] = '¥' . $goodsItem['min_discount_price'] . '-' . $goodsItem['max_discount_price']; } // 对于多规格,使用最低价格作为主要显示价格 $goodsItem['discount_price'] = $goodsItem['min_discount_price']; $goodsItem['discount'] = $goodsItem['min_discount']; } } } // 处理图像的 foreach ($processedGoods as &$goodsItem) { $goodsItem['image'] = cdnurl($goodsItem['image'], true); } // 在活动信息中添加商品数组字段 $activity['goods'] = array_values($processedGoods); return $activity; } /** * 根据商品ID和SKU ID获取折扣信息 * @param int $goodsId 商品ID * @param int $skuId SKU ID,单规格商品传0 * @return array|null */ public static function getGoodsDiscountInfo($goodsId, $skuId = 0) { $currentTime = time(); // 第一步:查询当前时间有效的活动ID $activeActivityIds = Db::table('shop_activity') ->where('start_time', '<=', $currentTime) ->where('end_time', '>=', $currentTime) ->where('activity_status', ActivityEnum::ACTIVITY_STATUS_ONGOING) ->where('status', StatusEnum::ENABLED) ->column('id'); if (empty($activeActivityIds)) { return null; } // 第二步:查询指定商品的折扣信息 $discountInfo = Db::table('shop_activity_sku') ->alias('sku') ->join('shop_activity activity', 'sku.activity_id = activity.id') ->where('sku.goods_id', $goodsId) ->where('sku.sku_id', $skuId) ->where('sku.activity_id', 'in', $activeActivityIds) ->where('sku.status', StatusEnum::ENABLED) ->where('sku.stocks', '>', 0) ->field([ 'sku.id as activity_sku_id', 'sku.discount', 'sku.discount_price', 'sku.stocks as discount_stocks', 'sku.sale_quantity', 'activity.id as activity_id', 'activity.name as activity_name', 'activity.start_time', 'activity.end_time' ]) ->find(); return $discountInfo ?: null; } /** * 批量获取商品的折扣信息(JOIN关联查询版本) * @param array $goodsIds 商品ID数组 * @return array 键为商品ID,值为折扣信息数组 */ public static function getBatchGoodsDiscountInfo($goodsIds) { if (empty($goodsIds)) { return []; } $currentTime = time(); // 直接使用JOIN关联查询,一次性完成时间和状态验证 $result = Db::table('shop_activity_sku') ->alias('sku') ->join(['shop_activity' => 'activity'], 'sku.activity_id = activity.id') ->where('sku.goods_id', 'in', $goodsIds) ->where('activity.start_time', '<=', $currentTime) ->where('activity.end_time', '>=', $currentTime) ->where('activity.activity_status', ActivityEnum::ACTIVITY_STATUS_ONGOING) ->where('activity.status', StatusEnum::ENABLED) ->where('sku.status', StatusEnum::ENABLED) ->where('sku.stocks', '>', 0) ->field([ 'sku.goods_id', 'sku.sku_id', 'sku.activity_id', 'sku.id as activity_sku_id', 'sku.discount', 'sku.discount_price', 'sku.stocks as discount_stocks', 'sku.sale_quantity', 'activity.name as activity_name' ]) ->order('sku.discount', 'asc') ->select(); if (empty($result)) { return []; } // 转换为数组并按商品ID分组 $resultArray = collection($result)->toArray(); $discountData = []; foreach ($resultArray as $item) { $goodsId = $item['goods_id']; if (!isset($discountData[$goodsId])) { $discountData[$goodsId] = []; } $discountData[$goodsId][] = $item; } return $discountData; } /** * 检查商品是否参与当前折扣活动 * @param int $goodsId 商品ID * @param int $skuId SKU ID * @return bool */ public static function hasActiveDiscount($goodsId, $skuId = 0) { $discountInfo = self::getGoodsDiscountInfo($goodsId, $skuId); return !empty($discountInfo); } /** * 计算折扣后的价格 * @param float $originalPrice 原价 * @param float $discount 折扣(如9.0表示9折) * @return float */ public static function calculateDiscountPrice($originalPrice, $discount) { return round($originalPrice * $discount / 10, 2); } /** * 获取活动剩余时间(秒) * @param int $endTime 活动结束时间戳 * @return int */ public static function getActivityRemainingTime($endTime) { return max(0, $endTime - time()); } /** * 格式化活动剩余时间 * @param int $endTime 活动结束时间戳 * @return array */ public static function formatRemainingTime($endTime) { $remaining = self::getActivityRemainingTime($endTime); if ($remaining <= 0) { return ['days' => 0, 'hours' => 0, 'minutes' => 0, 'seconds' => 0]; } $days = floor($remaining / 86400); $hours = floor(($remaining % 86400) / 3600); $minutes = floor(($remaining % 3600) / 60); $seconds = $remaining % 60; return [ 'days' => $days, 'hours' => $hours, 'minutes' => $minutes, 'seconds' => $seconds ]; } /** * 处理商品的折扣价格信息(公共方法) * @param array $goodsData 商品数据数组 * @return array 处理后的商品数据 */ private static function processGoodsDiscountData($goodsData) { foreach ($goodsData as &$goods) { $discountPrices = []; $discounts = []; // 收集所有折扣价格和折扣率 foreach ($goods['discount_info'] as $discount) { $discountPrices[] = $discount['discount_price']; $discounts[] = $discount['discount']; } if (!empty($discountPrices)) { // 计算最低和最高折扣价格 $goods['min_discount_price'] = min($discountPrices); $goods['max_discount_price'] = max($discountPrices); $goods['min_discount'] = min($discounts); $goods['max_discount'] = max($discounts); // 单规格商品处理 if ($goods['spec_type'] == 0) { $goods['discount_price'] = $goods['min_discount_price']; $goods['discount'] = $goods['min_discount']; $goods['discount_amount'] = round($goods['original_price'] - $goods['discount_price'], 2); $goods['price_range'] = '¥' . $goods['discount_price']; } // 多规格商品处理 else { // 设置价格区间 if ($goods['min_discount_price'] == $goods['max_discount_price']) { $goods['price_range'] = '¥' . $goods['min_discount_price']; } else { $goods['price_range'] = '¥' . $goods['min_discount_price'] . '-' . $goods['max_discount_price']; } // 对于多规格,使用最低价格作为主要显示价格 $goods['discount_price'] = $goods['min_discount_price']; $goods['discount'] = $goods['min_discount']; } } } return $goodsData; } /** * 获取当前有效的活动ID列表 * @return array */ private static function getActiveActivityIds() { $currentTime = time(); return Db::table('shop_activity') ->where('start_time', '<=', $currentTime) ->where('end_time', '>=', $currentTime) ->where('activity_status', ActivityEnum::ACTIVITY_STATUS_ONGOING) ->where('status', StatusEnum::ENABLED) ->column('id'); } /** * 初始化商品折扣数据结构 * @param array $item 商品数据 * @return array */ private static function initGoodsDiscountStructure($item) { return [ 'goods_id' => $item['goods_id'], 'title' => $item['title'], 'sub_title' => $item['sub_title'], 'image' => $item['image'], 'original_price' => $item['original_price'], 'market_price' => $item['market_price'], 'goods_stocks' => $item['goods_stocks'], 'sales' => $item['sales'], 'spec_type' => $item['spec_type'], 'activity_id' => $item['activity_id'] ?? null, 'activity_name' => $item['activity_name'] ?? null, 'start_time' => $item['start_time'] ?? null, 'end_time' => $item['end_time'] ?? null, 'has_discount' => true, 'discount_info' => [], // 初始化折扣价格相关字段 'min_discount_price' => null, 'max_discount_price' => null, 'min_discount' => null, 'max_discount' => null, 'discount_price' => null, 'discount' => null, 'discount_amount' => null, 'price_range' => '' ]; } }