DiscountService.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. <?php
  2. namespace app\common\Service;
  3. use think\Db;
  4. use think\Model;
  5. use app\common\Enum\StatusEnum;
  6. use app\common\Enum\ActivityEnum;
  7. use app\common\Enum\GoodsEnum;
  8. /**
  9. * 折扣活动服务类
  10. */
  11. class DiscountService
  12. {
  13. /**
  14. * 查询当前时间段内的商品折扣信息
  15. * @param array $goodsIds 商品ID数组,为空则查询所有参与折扣的商品
  16. * @param int $limit 限制数量
  17. * @return array
  18. */
  19. public static function getCurrentDiscountGoods($goodsIds = [], $limit = 0)
  20. {
  21. $currentTime = time();
  22. // 第一步:查询当前时间有效的活动ID
  23. $activeActivityIds = Db::table('shop_activity')
  24. ->where('start_time', '<=', $currentTime)
  25. ->where('end_time', '>=', $currentTime)
  26. ->where('activity_status', ActivityEnum::ACTIVITY_STATUS_ONGOING)
  27. ->where('status', StatusEnum::ENABLED)
  28. ->column('id');
  29. if (empty($activeActivityIds)) {
  30. return [];
  31. }
  32. // 第二步:查询这些活动的SKU数据
  33. $query = Db::table('shop_activity_sku')
  34. ->alias('sku')
  35. ->join('shop_goods goods', 'sku.goods_id = goods.id')
  36. ->join('shop_goods_sku spec', 'sku.sku_id = spec.id', 'left')
  37. ->join(['shop_activity'=> 'activity'], 'sku.activity_id = activity.id')
  38. ->where('sku.activity_id', 'in', $activeActivityIds)
  39. ->where('goods.status', GoodsEnum::STATUS_ON_SALE) // 已上架的商品
  40. ->where('sku.stocks', '>', 0) // 有折扣库存的商品
  41. ->field([
  42. 'goods.id as goods_id',
  43. 'goods.title',
  44. 'goods.sub_title',
  45. 'goods.image',
  46. 'goods.price as original_price',
  47. 'goods.market_price',
  48. 'goods.stocks as goods_stocks',
  49. 'goods.sales',
  50. 'goods.spec_type',
  51. 'sku.id as activity_sku_id',
  52. 'sku.sku_id',
  53. 'sku.discount',
  54. 'sku.discount_price',
  55. 'sku.stocks as discount_stocks',
  56. 'sku.sale_quantity',
  57. 'activity.id as activity_id',
  58. 'activity.name as activity_name',
  59. 'activity.start_time',
  60. 'activity.end_time',
  61. 'spec.price as sku_price',
  62. 'spec.image as sku_image',
  63. // 'spec.specs as sku_specs'
  64. ]);
  65. // 如果指定了商品ID,则添加条件
  66. if (!empty($goodsIds)) {
  67. $query->where('sku.goods_id', 'in', $goodsIds);
  68. }
  69. // 如果设置了限制数量
  70. if ($limit > 0) {
  71. $query->limit($limit);
  72. }
  73. // 按折扣力度排序,折扣越大越靠前
  74. $query->order('sku.discount', 'asc');
  75. $result = $query->select();
  76. // 处理返回数据
  77. $processedData = [];
  78. foreach ($result as $item) {
  79. $goodsId = $item['goods_id'];
  80. $skuId = $item['sku_id'];
  81. // 如果商品还没有在结果中,初始化
  82. if (!isset($processedData[$goodsId])) {
  83. $processedData[$goodsId] = [
  84. 'goods_id' => $goodsId,
  85. 'title' => $item['title'],
  86. 'sub_title' => $item['sub_title'],
  87. 'image' => $item['image'],
  88. 'original_price' => $item['original_price'],
  89. 'market_price' => $item['market_price'],
  90. 'goods_stocks' => $item['goods_stocks'],
  91. 'sales' => $item['sales'],
  92. 'spec_type' => $item['spec_type'],
  93. 'activity_id' => $item['activity_id'],
  94. 'activity_name' => $item['activity_name'],
  95. 'start_time' => $item['start_time'],
  96. 'end_time' => $item['end_time'],
  97. 'discount_info' => []
  98. ];
  99. }
  100. // 添加折扣信息
  101. $discountInfo = [
  102. 'activity_sku_id' => $item['activity_sku_id'],
  103. 'sku_id' => $skuId,
  104. 'discount' => $item['discount'],
  105. 'discount_price' => $item['discount_price'],
  106. 'discount_stocks' => $item['discount_stocks'],
  107. 'sale_quantity' => $item['sale_quantity']
  108. ];
  109. // 如果是多规格商品,添加规格信息
  110. if ($skuId > 0) {
  111. $discountInfo['sku_price'] = $item['sku_price'];
  112. $discountInfo['sku_image'] = $item['sku_image'];
  113. // $discountInfo['sku_specs'] = $item['sku_specs'];
  114. }
  115. $processedData[$goodsId]['discount_info'][] = $discountInfo;
  116. }
  117. return array_values($processedData);
  118. }
  119. /**
  120. * 根据商品ID和SKU ID获取折扣信息
  121. * @param int $goodsId 商品ID
  122. * @param int $skuId SKU ID,单规格商品传0
  123. * @return array|null
  124. */
  125. public static function getGoodsDiscountInfo($goodsId, $skuId = 0)
  126. {
  127. $currentTime = time();
  128. // 第一步:查询当前时间有效的活动ID
  129. $activeActivityIds = Db::table('shop_activity')
  130. ->where('start_time', '<=', $currentTime)
  131. ->where('end_time', '>=', $currentTime)
  132. ->where('activity_status', ActivityEnum::ACTIVITY_STATUS_ONGOING)
  133. ->where('status', 'normal')
  134. ->column('id');
  135. if (empty($activeActivityIds)) {
  136. return null;
  137. }
  138. // 第二步:查询指定商品的折扣信息
  139. $discountInfo = Db::table('shop_activity_sku_prize')
  140. ->alias('sku')
  141. ->join('shop_activity activity', 'sku.activity_id = activity.id')
  142. ->where('sku.goods_id', $goodsId)
  143. ->where('sku.sku_id', $skuId)
  144. ->where('sku.activity_id', 'in', $activeActivityIds)
  145. ->where('sku.status', 1)
  146. ->where('sku.stocks', '>', 0)
  147. ->field([
  148. 'sku.id as activity_sku_id',
  149. 'sku.discount',
  150. 'sku.discount_price',
  151. 'sku.stocks as discount_stocks',
  152. 'sku.sale_quantity',
  153. 'activity.id as activity_id',
  154. 'activity.name as activity_name',
  155. 'activity.start_time',
  156. 'activity.end_time'
  157. ])
  158. ->find();
  159. return $discountInfo ?: null;
  160. }
  161. /**
  162. * 批量获取商品的折扣信息
  163. * @param array $goodsIds 商品ID数组
  164. * @return array 键为商品ID,值为折扣信息数组
  165. */
  166. public static function getBatchGoodsDiscountInfo($goodsIds)
  167. {
  168. if (empty($goodsIds)) {
  169. return [];
  170. }
  171. $currentTime = time();
  172. // 第一步:查询当前时间有效的活动ID
  173. $activeActivityIds = Db::table('shop_activity')
  174. ->where('start_time', '<=', $currentTime)
  175. ->where('end_time', '>=', $currentTime)
  176. ->where('activity_status', ActivityEnum::ACTIVITY_STATUS_ONGOING)
  177. ->where('status', 'normal')
  178. ->column('id');
  179. if (empty($activeActivityIds)) {
  180. return [];
  181. }
  182. // 第二步:查询指定商品的折扣信息
  183. $result = Db::table('shop_activity_sku_prize')
  184. ->alias('sku')
  185. ->join('shop_activity activity', 'sku.activity_id = activity.id')
  186. ->where('sku.goods_id', 'in', $goodsIds)
  187. ->where('sku.activity_id', 'in', $activeActivityIds)
  188. ->where('sku.status', 1)
  189. ->where('sku.stocks', '>', 0)
  190. ->field([
  191. 'sku.goods_id',
  192. 'sku.sku_id',
  193. 'sku.id as activity_sku_id',
  194. 'sku.discount',
  195. 'sku.discount_price',
  196. 'sku.stocks as discount_stocks',
  197. 'sku.sale_quantity',
  198. 'activity.id as activity_id',
  199. 'activity.name as activity_name'
  200. ])
  201. ->order('sku.discount', 'asc')
  202. ->select();
  203. // 按商品ID分组
  204. $discountData = [];
  205. foreach ($result as $item) {
  206. $goodsId = $item['goods_id'];
  207. if (!isset($discountData[$goodsId])) {
  208. $discountData[$goodsId] = [];
  209. }
  210. $discountData[$goodsId][] = $item;
  211. }
  212. return $discountData;
  213. }
  214. /**
  215. * 检查商品是否参与当前折扣活动
  216. * @param int $goodsId 商品ID
  217. * @param int $skuId SKU ID
  218. * @return bool
  219. */
  220. public static function hasActiveDiscount($goodsId, $skuId = 0)
  221. {
  222. $discountInfo = self::getGoodsDiscountInfo($goodsId, $skuId);
  223. return !empty($discountInfo);
  224. }
  225. /**
  226. * 计算折扣后的价格
  227. * @param float $originalPrice 原价
  228. * @param float $discount 折扣(如9.0表示9折)
  229. * @return float
  230. */
  231. public static function calculateDiscountPrice($originalPrice, $discount)
  232. {
  233. return round($originalPrice * $discount / 10, 2);
  234. }
  235. /**
  236. * 获取活动剩余时间(秒)
  237. * @param int $endTime 活动结束时间戳
  238. * @return int
  239. */
  240. public static function getActivityRemainingTime($endTime)
  241. {
  242. return max(0, $endTime - time());
  243. }
  244. /**
  245. * 格式化活动剩余时间
  246. * @param int $endTime 活动结束时间戳
  247. * @return array
  248. */
  249. public static function formatRemainingTime($endTime)
  250. {
  251. $remaining = self::getActivityRemainingTime($endTime);
  252. if ($remaining <= 0) {
  253. return ['days' => 0, 'hours' => 0, 'minutes' => 0, 'seconds' => 0];
  254. }
  255. $days = floor($remaining / 86400);
  256. $hours = floor(($remaining % 86400) / 3600);
  257. $minutes = floor(($remaining % 3600) / 60);
  258. $seconds = $remaining % 60;
  259. return [
  260. 'days' => $days,
  261. 'hours' => $hours,
  262. 'minutes' => $minutes,
  263. 'seconds' => $seconds
  264. ];
  265. }
  266. }