DiscountService.php 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678
  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. * 外层折扣字段说明:
  12. * - has_discount: 是否有折扣活动
  13. * - discount_price: 折扣价格(单规格商品直接使用,多规格商品显示最低价)
  14. * - discount: 折扣率(单规格商品直接使用,多规格商品显示最低折扣)
  15. * - discount_amount: 折扣金额(原价-折扣价,仅单规格商品)
  16. * - min_discount_price: 最低折扣价格
  17. * - max_discount_price: 最高折扣价格
  18. * - min_discount: 最低折扣率
  19. * - max_discount: 最高折扣率
  20. * - price_range: 价格区间文本(如:¥99 或 ¥99-199)
  21. */
  22. class DiscountService
  23. {
  24. /**
  25. * 查询当前时间段内的商品折扣信息
  26. * @param array $goodsIds 商品ID数组,为空则查询所有参与折扣的商品
  27. * @param int $limit 限制数量
  28. * @return array
  29. */
  30. public static function getCurrentDiscountGoods($goodsIds = [], $limit = 0)
  31. {
  32. // 第一步:查询当前时间有效的活动ID
  33. $activeActivityIds = self::getActiveActivityIds();
  34. if (empty($activeActivityIds)) {
  35. return [];
  36. }
  37. // 第二步:查询这些活动的SKU数据
  38. $skuData = Db::table('shop_activity_sku')
  39. ->where('activity_id', 'in', $activeActivityIds)
  40. ->where('stocks', '>', 0) // 有折扣库存的商品
  41. ->field([
  42. 'id as activity_sku_id',
  43. 'goods_id',
  44. 'sku_id',
  45. 'activity_id',
  46. 'discount',
  47. 'discount_price',
  48. 'stocks as discount_stocks',
  49. 'sale_quantity'
  50. ])
  51. ->order('discount', 'asc')
  52. ->select();
  53. if (empty($skuData)) {
  54. return [];
  55. }
  56. // 收集所有商品ID和SKU ID
  57. $skuDataArray = collection($skuData)->toArray();
  58. $allGoodsIds = array_unique(array_column($skuDataArray, 'goods_id'));
  59. $allSkuIds = array_filter(array_unique(array_column($skuDataArray, 'sku_id')));
  60. // 如果指定了商品ID,则过滤
  61. if (!empty($goodsIds)) {
  62. $allGoodsIds = array_intersect($allGoodsIds, $goodsIds);
  63. if (empty($allGoodsIds)) {
  64. return [];
  65. }
  66. }
  67. // 第三步:批量查询商品信息
  68. $goodsInfo = Db::table('shop_goods')
  69. ->where('id', 'in', $allGoodsIds)
  70. ->where('status', GoodsEnum::STATUS_ON_SALE) // 已上架的商品
  71. ->column('id,title,sub_title,image,price,market_price,stocks,sales,spec_type', 'id');
  72. // 第四步:批量查询SKU信息(如果有多规格商品)
  73. $skuInfo = [];
  74. if (!empty($allSkuIds)) {
  75. $skuInfo = Db::table('shop_goods_sku')
  76. ->where('id', 'in', $allSkuIds)
  77. ->column('id,price,image', 'id');
  78. }
  79. // 第五步:批量查询活动信息
  80. $activityInfo = Db::table('shop_activity')
  81. ->where('id', 'in', $activeActivityIds)
  82. ->column('id,name,start_time,end_time', 'id');
  83. // 过滤掉不存在的商品
  84. $filteredSkuData = array_filter($skuDataArray, function($item) use ($goodsInfo) {
  85. return isset($goodsInfo[$item['goods_id']]);
  86. });
  87. // 如果设置了限制数量
  88. if ($limit > 0) {
  89. $filteredSkuData = array_slice($filteredSkuData, 0, $limit);
  90. }
  91. // 处理返回数据
  92. $processedData = [];
  93. foreach ($filteredSkuData as $item) {
  94. $goodsId = $item['goods_id'];
  95. $skuId = $item['sku_id'];
  96. $activityId = $item['activity_id'];
  97. // 获取商品信息
  98. $goods = $goodsInfo[$goodsId];
  99. // 如果商品还没有在结果中,初始化
  100. if (!isset($processedData[$goodsId])) {
  101. // 构造商品基础信息
  102. $goodsItem = [
  103. 'goods_id' => $goodsId,
  104. 'title' => $goods['title'],
  105. 'sub_title' => $goods['sub_title'],
  106. 'image' => $goods['image'],
  107. 'original_price' => $goods['price'],
  108. 'market_price' => $goods['market_price'],
  109. 'goods_stocks' => $goods['stocks'],
  110. 'sales' => $goods['sales'],
  111. 'spec_type' => $goods['spec_type'],
  112. 'activity_id' => $activityId,
  113. 'activity_name' => $activityInfo[$activityId]['name'] ?? '',
  114. 'start_time' => $activityInfo[$activityId]['start_time'] ?? null,
  115. 'end_time' => $activityInfo[$activityId]['end_time'] ?? null,
  116. ];
  117. $processedData[$goodsId] = self::initGoodsDiscountStructure($goodsItem);
  118. }
  119. // 添加折扣信息
  120. $discountInfo = [
  121. 'activity_sku_id' => $item['activity_sku_id'],
  122. 'sku_id' => $skuId,
  123. 'discount' => $item['discount'],
  124. 'discount_price' => $item['discount_price'],
  125. 'discount_stocks' => $item['discount_stocks'],
  126. 'sale_quantity' => $item['sale_quantity']
  127. ];
  128. // 如果是多规格商品,添加规格信息
  129. if ($skuId > 0 && isset($skuInfo[$skuId])) {
  130. $discountInfo['sku_price'] = $skuInfo[$skuId]['price'];
  131. $discountInfo['sku_image'] = $skuInfo[$skuId]['image'];
  132. }
  133. $processedData[$goodsId]['discount_info'][] = $discountInfo;
  134. }
  135. // 处理外层折扣价格字段
  136. $processedData = self::processGoodsDiscountData($processedData);
  137. return array_values($processedData);
  138. }
  139. /**
  140. * 查询单个商品的折扣信息和对应的SKU折扣信息
  141. * @param int $goodsId 商品ID
  142. * @return array|null 商品折扣信息,包含所有SKU的折扣详情,如果没有折扣则返回null
  143. */
  144. public static function getGoodsDiscountDetail($goodsId)
  145. {
  146. // 第一步:查询当前时间有效的活动ID
  147. $activeActivityIds = self::getActiveActivityIds();
  148. if (empty($activeActivityIds)) {
  149. return null;
  150. }
  151. // 第二步:查询该商品的SKU折扣数据
  152. $result = Db::table('shop_activity_sku')
  153. ->alias('sku')
  154. ->join('shop_goods goods', 'sku.goods_id = goods.id')
  155. ->join('shop_goods_sku spec', 'sku.sku_id = spec.id', 'left')
  156. ->join(['shop_activity'=> 'activity'], 'sku.activity_id = activity.id')
  157. ->where('sku.goods_id', $goodsId)
  158. ->where('sku.activity_id', 'in', $activeActivityIds)
  159. ->where('goods.status', GoodsEnum::STATUS_ON_SALE) // 已上架的商品
  160. ->where('sku.stocks', '>', 0) // 有折扣库存的商品
  161. ->field([
  162. 'goods.id as goods_id',
  163. 'goods.title',
  164. 'goods.sub_title',
  165. 'goods.image',
  166. 'goods.price as original_price',
  167. 'goods.market_price',
  168. 'goods.stocks as goods_stocks',
  169. 'goods.sales',
  170. 'goods.spec_type',
  171. 'sku.id as activity_sku_id',
  172. 'sku.sku_id',
  173. 'sku.discount',
  174. 'sku.discount_price',
  175. 'sku.stocks as discount_stocks',
  176. 'sku.sale_quantity',
  177. 'activity.id as activity_id',
  178. 'activity.name as activity_name',
  179. 'activity.start_time',
  180. 'activity.end_time',
  181. 'spec.price as sku_price',
  182. 'spec.image as sku_image',
  183. // 'spec.specs as sku_specs'
  184. ])
  185. ->order('sku.discount', 'asc') // 按折扣力度排序,折扣越大越靠前
  186. ->select();
  187. if (empty($result)) {
  188. return null;
  189. }
  190. // 初始化商品折扣结构
  191. $goodsDiscountData = self::initGoodsDiscountStructure($result[0]);
  192. // 处理所有SKU的折扣信息
  193. foreach ($result as $item) {
  194. $skuId = $item['sku_id'];
  195. // 添加折扣信息
  196. $discountInfo = [
  197. 'activity_sku_id' => $item['activity_sku_id'],
  198. 'sku_id' => $skuId,
  199. 'discount' => $item['discount'],
  200. 'discount_price' => $item['discount_price'],
  201. 'discount_stocks' => $item['discount_stocks'],
  202. 'sale_quantity' => $item['sale_quantity']
  203. ];
  204. // 如果是多规格商品,添加规格信息
  205. if ($skuId > 0) {
  206. $discountInfo['sku_price'] = $item['sku_price'];
  207. $discountInfo['sku_image'] = $item['sku_image'];
  208. // $discountInfo['sku_specs'] = $item['sku_specs'];
  209. }
  210. $goodsDiscountData['discount_info'][] = $discountInfo;
  211. }
  212. // 处理外层折扣价格字段
  213. $discountPrices = [];
  214. $discounts = [];
  215. // 收集所有折扣价格和折扣率
  216. foreach ($goodsDiscountData['discount_info'] as $discount) {
  217. $discountPrices[] = $discount['discount_price'];
  218. $discounts[] = $discount['discount'];
  219. }
  220. if (!empty($discountPrices)) {
  221. // 计算最低和最高折扣价格
  222. $goodsDiscountData['min_discount_price'] = min($discountPrices);
  223. $goodsDiscountData['max_discount_price'] = max($discountPrices);
  224. $goodsDiscountData['min_discount'] = min($discounts);
  225. $goodsDiscountData['max_discount'] = max($discounts);
  226. // 单规格商品处理
  227. if ($goodsDiscountData['spec_type'] == 0) {
  228. $goodsDiscountData['discount_price'] = $goodsDiscountData['min_discount_price'];
  229. $goodsDiscountData['discount'] = $goodsDiscountData['min_discount'];
  230. $goodsDiscountData['discount_amount'] = round($goodsDiscountData['original_price'] - $goodsDiscountData['discount_price'], 2);
  231. $goodsDiscountData['price_range'] = '¥' . $goodsDiscountData['discount_price'];
  232. }
  233. // 多规格商品处理
  234. else {
  235. // 设置价格区间
  236. if ($goodsDiscountData['min_discount_price'] == $goodsDiscountData['max_discount_price']) {
  237. $goodsDiscountData['price_range'] = '¥' . $goodsDiscountData['min_discount_price'];
  238. } else {
  239. $goodsDiscountData['price_range'] = '¥' . $goodsDiscountData['min_discount_price'] . '-' . $goodsDiscountData['max_discount_price'];
  240. }
  241. // 对于多规格,使用最低价格作为主要显示价格
  242. $goodsDiscountData['discount_price'] = $goodsDiscountData['min_discount_price'];
  243. $goodsDiscountData['discount'] = $goodsDiscountData['min_discount'];
  244. }
  245. }
  246. $goodsDiscountData['remaining_time'] = self::formatRemainingTime($goodsDiscountData['end_time']);
  247. return $goodsDiscountData;
  248. }
  249. /**
  250. * 限时查询一个当前活动的信息和商品信息 活动信息直接加一个商品数组字段
  251. * @param mixed $activityId
  252. * @return array|bool|Model|string|\PDOStatement|null
  253. */
  254. public static function getCurrentActivity()
  255. {
  256. $currentTime = time();
  257. // 查询活动信息
  258. $activity = Db::table('shop_activity')
  259. // ->where('id', $activityId)
  260. ->where('start_time', '<=', $currentTime)
  261. ->where('end_time', '>=', $currentTime)
  262. ->where('activity_status', ActivityEnum::ACTIVITY_STATUS_ONGOING)
  263. ->where('status', StatusEnum::ENABLED)
  264. ->find();
  265. if (!$activity) {
  266. return null;
  267. }
  268. // 查询该活动下的商品信息
  269. $goods = Db::table('shop_activity_sku')
  270. ->alias('sku')
  271. ->join('shop_goods goods', 'sku.goods_id = goods.id')
  272. ->join('shop_goods_sku spec', 'sku.sku_id = spec.id', 'left')
  273. ->where('sku.activity_id', $activity['id'])
  274. ->where('goods.status', GoodsEnum::STATUS_ON_SALE)
  275. ->where('sku.stocks', '>', 0)
  276. ->field([
  277. 'goods.id as goods_id',
  278. 'goods.title',
  279. 'goods.sub_title',
  280. 'goods.image',
  281. 'goods.price as original_price',
  282. 'goods.market_price',
  283. 'goods.stocks as goods_stocks',
  284. 'goods.sales',
  285. 'goods.spec_type',
  286. 'sku.id as activity_sku_id',
  287. 'sku.sku_id',
  288. 'sku.discount',
  289. 'sku.discount_price',
  290. 'sku.stocks as discount_stocks',
  291. 'sku.sale_quantity',
  292. 'spec.price as sku_price',
  293. 'spec.image as sku_image'
  294. ])
  295. ->order('sku.discount', 'asc')
  296. ->select();
  297. // 处理商品数据
  298. $processedGoods = [];
  299. foreach ($goods as $item) {
  300. $goodsId = $item['goods_id'];
  301. if (!isset($processedGoods[$goodsId])) {
  302. $processedGoods[$goodsId] = self::initGoodsDiscountStructure($item);
  303. }
  304. $discountInfo = [
  305. 'activity_sku_id' => $item['activity_sku_id'],
  306. 'sku_id' => $item['sku_id'],
  307. 'discount' => $item['discount'],
  308. 'discount_price' => $item['discount_price'],
  309. 'discount_stocks' => $item['discount_stocks'],
  310. 'sale_quantity' => $item['sale_quantity']
  311. ];
  312. if ($item['sku_id'] > 0) {
  313. $discountInfo['sku_price'] = $item['sku_price'];
  314. $discountInfo['sku_image'] = $item['sku_image'];
  315. }
  316. $processedGoods[$goodsId]['discount_info'][] = $discountInfo;
  317. }
  318. // 处理外层折扣价格字段
  319. foreach ($processedGoods as &$goodsItem) {
  320. $discountPrices = [];
  321. $discounts = [];
  322. // 收集所有折扣价格和折扣率
  323. foreach ($goodsItem['discount_info'] as $discount) {
  324. $discountPrices[] = $discount['discount_price'];
  325. $discounts[] = $discount['discount'];
  326. }
  327. if (!empty($discountPrices)) {
  328. // 计算最低和最高折扣价格
  329. $goodsItem['min_discount_price'] = min($discountPrices);
  330. $goodsItem['max_discount_price'] = max($discountPrices);
  331. $goodsItem['min_discount'] = min($discounts);
  332. $goodsItem['max_discount'] = max($discounts);
  333. // 单规格商品处理
  334. if ($goodsItem['spec_type'] == 0) {
  335. $goodsItem['discount_price'] = $goodsItem['min_discount_price'];
  336. $goodsItem['discount'] = $goodsItem['min_discount'];
  337. $goodsItem['discount_amount'] = round($goodsItem['original_price'] - $goodsItem['discount_price'], 2);
  338. $goodsItem['price_range'] = '¥' . $goodsItem['discount_price'];
  339. }
  340. // 多规格商品处理
  341. else {
  342. // 设置价格区间
  343. if ($goodsItem['min_discount_price'] == $goodsItem['max_discount_price']) {
  344. $goodsItem['price_range'] = '¥' . $goodsItem['min_discount_price'];
  345. } else {
  346. $goodsItem['price_range'] = '¥' . $goodsItem['min_discount_price'] . '-' . $goodsItem['max_discount_price'];
  347. }
  348. // 对于多规格,使用最低价格作为主要显示价格
  349. $goodsItem['discount_price'] = $goodsItem['min_discount_price'];
  350. $goodsItem['discount'] = $goodsItem['min_discount'];
  351. }
  352. }
  353. }
  354. // 处理图像的
  355. foreach ($processedGoods as &$goodsItem) {
  356. $goodsItem['image'] = cdnurl($goodsItem['image'], true);
  357. }
  358. // 在活动信息中添加商品数组字段
  359. $activity['goods'] = array_values($processedGoods);
  360. return $activity;
  361. }
  362. /**
  363. * 根据商品ID和SKU ID获取折扣信息
  364. * @param int $goodsId 商品ID
  365. * @param int $skuId SKU ID,单规格商品传0
  366. * @return array|null
  367. */
  368. public static function getGoodsDiscountInfo($goodsId, $skuId = 0)
  369. {
  370. $currentTime = time();
  371. // 第一步:查询当前时间有效的活动ID
  372. $activeActivityIds = Db::table('shop_activity')
  373. ->where('start_time', '<=', $currentTime)
  374. ->where('end_time', '>=', $currentTime)
  375. ->where('activity_status', ActivityEnum::ACTIVITY_STATUS_ONGOING)
  376. ->where('status', StatusEnum::ENABLED)
  377. ->column('id');
  378. if (empty($activeActivityIds)) {
  379. return null;
  380. }
  381. // 第二步:查询指定商品的折扣信息
  382. $discountInfo = Db::table('shop_activity_sku')
  383. ->alias('sku')
  384. ->join('shop_activity activity', 'sku.activity_id = activity.id')
  385. ->where('sku.goods_id', $goodsId)
  386. ->where('sku.sku_id', $skuId)
  387. ->where('sku.activity_id', 'in', $activeActivityIds)
  388. ->where('sku.status', StatusEnum::ENABLED)
  389. ->where('sku.stocks', '>', 0)
  390. ->field([
  391. 'sku.id as activity_sku_id',
  392. 'sku.discount',
  393. 'sku.discount_price',
  394. 'sku.stocks as discount_stocks',
  395. 'sku.sale_quantity',
  396. 'activity.id as activity_id',
  397. 'activity.name as activity_name',
  398. 'activity.start_time',
  399. 'activity.end_time'
  400. ])
  401. ->find();
  402. return $discountInfo ?: null;
  403. }
  404. /**
  405. * 批量获取商品的折扣信息(JOIN关联查询版本)
  406. * @param array $goodsIds 商品ID数组
  407. * @return array 键为商品ID,值为折扣信息数组
  408. */
  409. public static function getBatchGoodsDiscountInfo($goodsIds)
  410. {
  411. if (empty($goodsIds)) {
  412. return [];
  413. }
  414. $currentTime = time();
  415. // 直接使用JOIN关联查询,一次性完成时间和状态验证
  416. $result = Db::table('shop_activity_sku')
  417. ->alias('sku')
  418. ->join(['shop_activity' => 'activity'], 'sku.activity_id = activity.id')
  419. ->where('sku.goods_id', 'in', $goodsIds)
  420. ->where('activity.start_time', '<=', $currentTime)
  421. ->where('activity.end_time', '>=', $currentTime)
  422. ->where('activity.activity_status', ActivityEnum::ACTIVITY_STATUS_ONGOING)
  423. ->where('activity.status', StatusEnum::ENABLED)
  424. ->where('sku.status', StatusEnum::ENABLED)
  425. ->where('sku.stocks', '>', 0)
  426. ->field([
  427. 'sku.goods_id',
  428. 'sku.sku_id',
  429. 'sku.activity_id',
  430. 'sku.id as activity_sku_id',
  431. 'sku.discount',
  432. 'sku.discount_price',
  433. 'sku.stocks as discount_stocks',
  434. 'sku.sale_quantity',
  435. 'activity.name as activity_name'
  436. ])
  437. ->order('sku.discount', 'asc')
  438. ->select();
  439. if (empty($result)) {
  440. return [];
  441. }
  442. // 转换为数组并按商品ID分组
  443. $resultArray = collection($result)->toArray();
  444. $discountData = [];
  445. foreach ($resultArray as $item) {
  446. $goodsId = $item['goods_id'];
  447. if (!isset($discountData[$goodsId])) {
  448. $discountData[$goodsId] = [];
  449. }
  450. $discountData[$goodsId][] = $item;
  451. }
  452. return $discountData;
  453. }
  454. /**
  455. * 检查商品是否参与当前折扣活动
  456. * @param int $goodsId 商品ID
  457. * @param int $skuId SKU ID
  458. * @return bool
  459. */
  460. public static function hasActiveDiscount($goodsId, $skuId = 0)
  461. {
  462. $discountInfo = self::getGoodsDiscountInfo($goodsId, $skuId);
  463. return !empty($discountInfo);
  464. }
  465. /**
  466. * 计算折扣后的价格
  467. * @param float $originalPrice 原价
  468. * @param float $discount 折扣(如9.0表示9折)
  469. * @return float
  470. */
  471. public static function calculateDiscountPrice($originalPrice, $discount)
  472. {
  473. return round($originalPrice * $discount / 10, 2);
  474. }
  475. /**
  476. * 获取活动剩余时间(秒)
  477. * @param int $endTime 活动结束时间戳
  478. * @return int
  479. */
  480. public static function getActivityRemainingTime($endTime)
  481. {
  482. return max(0, $endTime - time());
  483. }
  484. /**
  485. * 格式化活动剩余时间
  486. * @param int $endTime 活动结束时间戳
  487. * @return array
  488. */
  489. public static function formatRemainingTime($endTime)
  490. {
  491. $remaining = self::getActivityRemainingTime($endTime);
  492. if ($remaining <= 0) {
  493. return ['days' => 0, 'hours' => 0, 'minutes' => 0, 'seconds' => 0];
  494. }
  495. $days = floor($remaining / 86400);
  496. $hours = floor(($remaining % 86400) / 3600);
  497. $minutes = floor(($remaining % 3600) / 60);
  498. $seconds = $remaining % 60;
  499. return [
  500. 'days' => $days,
  501. 'hours' => $hours,
  502. 'minutes' => $minutes,
  503. 'seconds' => $seconds
  504. ];
  505. }
  506. /**
  507. * 处理商品的折扣价格信息(公共方法)
  508. * @param array $goodsData 商品数据数组
  509. * @return array 处理后的商品数据
  510. */
  511. private static function processGoodsDiscountData($goodsData)
  512. {
  513. foreach ($goodsData as &$goods) {
  514. $discountPrices = [];
  515. $discounts = [];
  516. // 收集所有折扣价格和折扣率
  517. foreach ($goods['discount_info'] as $discount) {
  518. $discountPrices[] = $discount['discount_price'];
  519. $discounts[] = $discount['discount'];
  520. }
  521. if (!empty($discountPrices)) {
  522. // 计算最低和最高折扣价格
  523. $goods['min_discount_price'] = min($discountPrices);
  524. $goods['max_discount_price'] = max($discountPrices);
  525. $goods['min_discount'] = min($discounts);
  526. $goods['max_discount'] = max($discounts);
  527. // 单规格商品处理
  528. if ($goods['spec_type'] == 0) {
  529. $goods['discount_price'] = $goods['min_discount_price'];
  530. $goods['discount'] = $goods['min_discount'];
  531. $goods['discount_amount'] = round($goods['original_price'] - $goods['discount_price'], 2);
  532. $goods['price_range'] = '¥' . $goods['discount_price'];
  533. }
  534. // 多规格商品处理
  535. else {
  536. // 设置价格区间
  537. if ($goods['min_discount_price'] == $goods['max_discount_price']) {
  538. $goods['price_range'] = '¥' . $goods['min_discount_price'];
  539. } else {
  540. $goods['price_range'] = '¥' . $goods['min_discount_price'] . '-' . $goods['max_discount_price'];
  541. }
  542. // 对于多规格,使用最低价格作为主要显示价格
  543. $goods['discount_price'] = $goods['min_discount_price'];
  544. $goods['discount'] = $goods['min_discount'];
  545. }
  546. }
  547. }
  548. return $goodsData;
  549. }
  550. /**
  551. * 获取当前有效的活动ID列表
  552. * @return array
  553. */
  554. private static function getActiveActivityIds()
  555. {
  556. $currentTime = time();
  557. return Db::table('shop_activity')
  558. ->where('start_time', '<=', $currentTime)
  559. ->where('end_time', '>=', $currentTime)
  560. ->where('activity_status', ActivityEnum::ACTIVITY_STATUS_ONGOING)
  561. ->where('status', StatusEnum::ENABLED)
  562. ->column('id');
  563. }
  564. /**
  565. * 初始化商品折扣数据结构
  566. * @param array $item 商品数据
  567. * @return array
  568. */
  569. private static function initGoodsDiscountStructure($item)
  570. {
  571. return [
  572. 'goods_id' => $item['goods_id'],
  573. 'title' => $item['title'],
  574. 'sub_title' => $item['sub_title'],
  575. 'image' => $item['image'],
  576. 'original_price' => $item['original_price'],
  577. 'market_price' => $item['market_price'],
  578. 'goods_stocks' => $item['goods_stocks'],
  579. 'sales' => $item['sales'],
  580. 'spec_type' => $item['spec_type'],
  581. 'activity_id' => $item['activity_id'] ?? null,
  582. 'activity_name' => $item['activity_name'] ?? null,
  583. 'start_time' => $item['start_time'] ?? null,
  584. 'end_time' => $item['end_time'] ?? null,
  585. 'has_discount' => true,
  586. 'discount_info' => [],
  587. // 初始化折扣价格相关字段
  588. 'min_discount_price' => null,
  589. 'max_discount_price' => null,
  590. 'min_discount' => null,
  591. 'max_discount' => null,
  592. 'discount_price' => null,
  593. 'discount' => null,
  594. 'discount_amount' => null,
  595. 'price_range' => ''
  596. ];
  597. }
  598. }