ThemeService.php 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | likeshop100%开源免费商用商城系统
  4. // +----------------------------------------------------------------------
  5. // | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
  6. // | 开源版本可自由商用,可去除界面版权logo
  7. // | 商业版本务必购买商业授权,以免引起法律纠纷
  8. // | 禁止对系统程序代码以任何目的,任何形式的再发布
  9. // | gitee下载:https://gitee.com/likeshop_gitee
  10. // | github下载:https://github.com/likeshop-github
  11. // | 访问官网:https://www.likeshop.cn
  12. // | 访问社区:https://home.likeshop.cn
  13. // | 访问手册:http://doc.likeshop.cn
  14. // | 微信公众号:likeshop技术社区
  15. // | likeshop团队 版权所有 拥有最终解释权
  16. // +----------------------------------------------------------------------
  17. // | author: likeshopTeam
  18. // +----------------------------------------------------------------------
  19. namespace app\common\service;
  20. use app\common\{enum\ActivityEnum,
  21. enum\GoodsEnum,
  22. enum\LiveEnum,
  23. enum\PresellEnum,
  24. enum\SeckillEnum,
  25. enum\TeamEnum,
  26. model\Cart,
  27. model\CouponList,
  28. model\Goods,
  29. model\GoodsItem,
  30. model\Order,
  31. model\Coupon,
  32. enum\CouponEnum,
  33. model\Presell,
  34. model\PresellGoods,
  35. model\PresellGoodsItem,
  36. model\SeckillActivity,
  37. model\SeckillGoodsItem,
  38. model\ShopNotice,
  39. enum\ThemePageEnum,
  40. model\GoodsCategoryIndex,
  41. model\TeamActivity,
  42. model\TeamGoodsItem};
  43. use function JmesPath\search;
  44. /**
  45. * 主题功能类
  46. * Class ThemeService
  47. * @package app\common\service
  48. */
  49. class ThemeService
  50. {
  51. public static array $params = [];
  52. /**
  53. * @notes 替换组件内容
  54. * @param array $content
  55. * @return array
  56. * @author cjhao
  57. * @date 2021/8/19 18:52
  58. */
  59. public static function getModuleData(array $content,array $config = []):array
  60. {
  61. self::$params = $config;
  62. $isDistribution = self::$params['is_distribution'] ?? false; //是否分销
  63. $isVerifier = self::$params['is_verifier'] ?? false; //是否核销员
  64. $source = self::$params['source'] ?? 'shop'; //后台组件替换或商城组件替换
  65. $userId = self::$params['user_id'] ?? '';
  66. $moduleList = array_column($content,'name');
  67. outFileLog($moduleList,'moduledata','$moduleList');
  68. foreach ($moduleList as $moduleKey => $moduleName) {
  69. outFileLog($moduleName,'moduledata','$moduleName');
  70. //需要拼接数据的组件
  71. switch ($moduleName) {
  72. //商品组件
  73. case ThemePageEnum::GOODS:
  74. $goods_type = $content[$moduleKey]['content']['goods_type'] ?? 2;
  75. //商品分类
  76. $limit = false;
  77. if(2 == $goods_type){
  78. if('admin' == $source){
  79. $content[$moduleKey]['content']['data'] = [];
  80. break;
  81. }
  82. $categoryId = $content[$moduleKey]['content']['category']['id'] ?? 0;
  83. $limit = $content[$moduleKey]['content']['category']['num'] ?? false;
  84. $goodsIds = GoodsCategoryIndex::where(['category_id'=>$categoryId])->column('goods_id');
  85. }else{
  86. $goodsIds = array_column($content[$moduleKey]['content']['data'], 'id');
  87. }
  88. //如果id都是空,直接返回数组
  89. if (empty($goodsIds)) {
  90. $content[$moduleKey]['content']['data'] = [];
  91. break;
  92. // $goods_info = Goods::where(['status'=>1])->field('id')->select()->toArray();
  93. // $goods_id_arr = array_column($goods_info,'id');
  94. // $goodsIds = array_rand($goods_id_arr,1);
  95. }
  96. //todo 商品需要根据顺序排序
  97. $orderField = implode(',', $goodsIds);
  98. $goodsList = Goods::where(['id' => $goodsIds,'status'=>GoodsEnum::STATUS_SELL])
  99. ->field('id,name,image,virtual_sales_num+sales_num as sales_num,min_price as sell_price,min_lineation_price as lineation_price,0 as is_multi_gauge')
  100. ->orderRaw("field(id,$orderField)")
  101. ->limit($limit)
  102. ->order('sort desc')
  103. ->select()
  104. ->toArray();
  105. outFileLog($goodsList,'moduledata','$moduleName-GOODS');
  106. foreach($goodsList as &$gv){
  107. $goods_item_count = GoodsItem::where(['goods_id'=>$gv['id']])->count();
  108. if($goods_item_count > 1){
  109. $gv['is_multi_gauge'] = 1;
  110. }else{
  111. $gv['is_multi_gauge'] = 0;
  112. }
  113. }
  114. //是否显示划线加
  115. $showPrice = ConfigService::get('goods_set', 'show_price', 1);
  116. if(0 == $showPrice){
  117. foreach ($goodsList as $goodsKey => $goodsVal){
  118. $goodsList[$goodsKey]['lineation_price'] = 0;
  119. }
  120. }
  121. $content[$moduleKey]['content']['data'] = $goodsList;
  122. break;
  123. //选项卡组件 todo 选项卡的data是多维数据
  124. case ThemePageEnum::TABS:
  125. $dataList = $content[$moduleKey]['content']['data'];
  126. foreach ($dataList as $dataKey => $dataVal){
  127. $goods_type = $dataVal['goods_type'] ?? 1;
  128. $limit = false;
  129. if(2 == $goods_type){
  130. if('admin' == $source){
  131. $content[$moduleKey]['content']['data'][$dataKey]['data'] = [];
  132. break;
  133. }
  134. $categoryId = $dataVal['category']['id'] ?? 0;
  135. $limit = $dataVal['category']['num'] ?? false;
  136. $goodsIds = GoodsCategoryIndex::where(['category_id'=>$categoryId])->column('goods_id');
  137. }else{
  138. $goodsIds = array_column($dataVal['data'], 'id');
  139. }
  140. //如果id都是空,直接返回数组
  141. if (empty($goodsIds)) {
  142. $content[$moduleKey]['content']['data'][$dataKey]['data'] = [];
  143. break;
  144. // $goods_info = Goods::where(['status'=>1])->field('id')->select()->toArray();
  145. // $goods_id_arr = array_column($goods_info,'id');
  146. // $goodsIds = array_rand($goods_id_arr,1);
  147. }
  148. //todo 商品需要根据顺序排序
  149. $orderField = implode(',', $goodsIds);
  150. $goodsList = Goods::where(['id' => $goodsIds,'status'=>GoodsEnum::STATUS_SELL])
  151. ->field('id,name,image,virtual_sales_num+sales_num as sales_num,min_price as sell_price,min_lineation_price as lineation_price,0 as is_multi_gauge')
  152. ->orderRaw("field(id,$orderField)")
  153. ->limit($limit)
  154. ->select()
  155. ->toArray();
  156. outFileLog($goodsList,'moduledata','$moduleName-TABS');
  157. foreach($goodsList as &$gv){
  158. $goods_item_count = GoodsItem::where(['goods_id'=>$gv['id']])->count();
  159. if($goods_item_count > 1){
  160. $gv['is_multi_gauge'] = 1;
  161. }else{
  162. $gv['is_multi_gauge'] = 0;
  163. }
  164. }
  165. //是否显示划线加
  166. $showPrice = ConfigService::get('goods_set', 'show_price', 1);
  167. if(0 == $showPrice){
  168. foreach ($goodsList as $goodsKey => $goodsVal){
  169. $goodsList[$goodsKey]['lineation_price'] = 0;
  170. }
  171. }
  172. $content[$moduleKey]['content']['data'][$dataKey]['data'] = $goodsList;
  173. }
  174. break;
  175. //优惠券组件
  176. case ThemePageEnum::COUPON:
  177. $couponIds = array_column($content[$moduleKey]['content']['data'], 'id');
  178. //如果id都是空,直接返回数组
  179. if (empty($couponIds)) {
  180. $content[$moduleKey]['content']['data'] = [];
  181. break;
  182. }
  183. //todo 优惠券需要根据顺序排序
  184. $orderField = implode(',', $couponIds);
  185. $couponList = Coupon::where(['id' => $couponIds,'status'=>[CouponEnum::COUPON_STATUS_NOT,CouponEnum::COUPON_STATUS_CONDUCT]])
  186. ->append([ 'use_type', 'discount_content', 'status_desc', 'condition' ])
  187. ->field('id,name,money,discount_ratio,condition_type,get_num_type,condition_money,use_goods_type,get_num,status')
  188. ->orderRaw("field(id,$orderField)")
  189. ->select();
  190. $myCouponIds = [];
  191. if($couponList && $userId){
  192. $myCouponIds = CouponList::where(['user_id'=>$userId,'status'=>CouponEnum::USE_STATUS_NOT])
  193. ->column('coupon_id');
  194. }
  195. $list = [];
  196. foreach ($couponList as $coupon) {
  197. //是否已领取
  198. $isReceive = 0;
  199. if(in_array($coupon->id,$myCouponIds)){
  200. $isReceive = 1;
  201. }
  202. $isAvailable = 0;
  203. //是否可领取
  204. switch ($coupon->get_num_type) {
  205. case CouponEnum::GET_NUM_TYPE_LIMIT:
  206. $total = CouponList::where(['coupon_id' => $coupon->id])
  207. ->where(['user_id' => $userId])
  208. ->count();
  209. $isAvailable = $total >= $coupon->get_num ? 1 : 0;
  210. break;
  211. case CouponEnum::GET_NUM_TYPE_DAY:
  212. $total = CouponList::where(['coupon_id' => $coupon->id])
  213. ->where(['user_id' =>$userId])
  214. ->where('create_time', '>=', TimeService::today()[0])
  215. ->where('create_time', '<=', TimeService::today()[1])
  216. ->count();
  217. $isAvailable = $total >= $coupon->get_num ? 1 : 0;
  218. break;
  219. }
  220. $coupon->is_receive = $isReceive;
  221. $coupon->is_available = $isAvailable;
  222. $list[] = $coupon->toArray();
  223. }
  224. outFileLog($list,'moduledata','$moduleName-COUPON');
  225. $content[$moduleKey]['content']['data'] = $list;
  226. break;
  227. //公告组件
  228. case ThemePageEnum::NOTICE:
  229. $limit = $content[$moduleKey]['content']['num'] ?? 1;//默认拿一条
  230. $noticeList = ShopNotice::field('id,name')
  231. ->where(['status'=>1])
  232. ->limit($limit)
  233. ->order('sort asc,id desc')
  234. ->select()
  235. ->toArray();
  236. $content[$moduleKey]['content']['data'] = $noticeList;
  237. outFileLog($noticeList,'moduledata','$moduleName-NOTICE');
  238. break;
  239. //会员中心-我的服务组件、微页面-导航组件
  240. case ThemePageEnum::USERSERVE:
  241. case ThemePageEnum::NAVIGATION:
  242. if('admin' == $source){
  243. break;
  244. }
  245. $linksData = $content[$moduleKey]['content']['data'];
  246. foreach ($linksData as $linkKey => $link){
  247. // 非分销用户,屏蔽分销菜单,index == 17时分销菜单,
  248. if(false === $isDistribution && isset($link['link']['index']) && 17 == $link['link']['index']){
  249. unset($linksData[$linkKey]);
  250. }
  251. //非核销用户,屏蔽分销菜单
  252. if(false === $isVerifier && isset($link['link']['index']) && 19 == $link['link']['index']){
  253. unset($linksData[$linkKey]);
  254. }
  255. }
  256. $content[$moduleKey]['content']['data'] = array_values($linksData);
  257. break;
  258. //商品拼团
  259. case ThemePageEnum::SPELLGROUP:
  260. if('admin' == $source){
  261. break;
  262. }
  263. $dataType = $content[$moduleKey]['content']['data_type'];
  264. $data = $content[$moduleKey]['content']['data'];
  265. $limit = false;
  266. $where = [];
  267. if(1 == $dataType) {
  268. //获取数量
  269. $limit = $content[$moduleKey]['content']['num'];
  270. $orderField = 'TA.id desc';
  271. }else{
  272. if(empty($data)){
  273. break;
  274. }
  275. $goods_ids = array_column($data,'goods_id');
  276. $where = ['goods_id'=>$goods_ids];
  277. $goodsIds = implode(',',array_column($data,'goods_id'));
  278. $orderField = "field(goods_id,$goodsIds)";
  279. }
  280. $goodsList = TeamActivity::alias('TA')
  281. ->join('team_goods TG','TA.id = TG.team_id')
  282. ->join('goods G','TG.goods_id = G.id')
  283. ->where([
  284. ['TA.status','=',TeamEnum::TEAM_STATUS_CONDUCT],
  285. ['start_time', '<=', time()],
  286. ['end_time', '>=', time()],
  287. ])
  288. ->where($where)
  289. ->field('TA.id as activity_id,TG.id,goods_id,goods_snap,min_team_price,people_num,G.image')
  290. ->limit($limit)
  291. ->orderRaw($orderField)
  292. ->select()
  293. ->toArray();
  294. outFileLog($goodsList,'moduledata','$moduleName-SPELLGROUP');
  295. if(empty($goodsList)){
  296. $content[$moduleKey]['content']['data'] = [];
  297. break;
  298. }
  299. foreach($goodsList as &$gv){
  300. $goods_item_count = GoodsItem::where(['goods_id'=>$gv['id']])->count();
  301. if($goods_item_count > 1){
  302. $gv['is_multi_gauge'] = 1;
  303. }else{
  304. $gv['is_multi_gauge'] = 0;
  305. }
  306. }
  307. $activityIds = array_column($goodsList,'activity_id');
  308. $goodsIds = array_column($goodsList,'goods_id');
  309. $salesList = TeamGoodsItem::where(['team_id'=>$activityIds,'goods_id'=>$goodsIds])
  310. ->group('goods_id')
  311. ->column('sum(sales_volume)','goods_id');
  312. $data = [];
  313. foreach ($goodsList as $goods){
  314. $goods_snap = json_decode($goods['goods_snap'],true);
  315. $data[] = [
  316. 'id' => $goods['id'],
  317. 'activity_id' => $goods['activity_id'],
  318. 'activity_type' => ActivityEnum::TEAM,
  319. 'goods_id' => $goods['goods_id'],
  320. 'name' => $goods_snap['name'],
  321. 'image' => FileService::getFileUrl($goods['image']),
  322. 'people_num' => $goods['people_num'],
  323. 'sell_price' => $goods_snap['min_price'],
  324. 'activity_price' => $goods['min_team_price'],
  325. 'activity_sales' => $salesList[$goods['goods_id']] ?? 0,
  326. ];
  327. }
  328. $content[$moduleKey]['content']['data'] = $data;
  329. break;
  330. //商品秒杀
  331. case ThemePageEnum::SECKILL:
  332. if('admin' == $source){
  333. break;
  334. }
  335. $dataType = $content[$moduleKey]['content']['data_type'];
  336. $data = $content[$moduleKey]['content']['data'];
  337. $limit = false;
  338. $where = [];
  339. //自动获取商品
  340. if(1 == $dataType) {
  341. //获取数量
  342. $limit = $content[$moduleKey]['content']['num'];
  343. $orderField = 'SA.id desc';
  344. }else{
  345. if(empty($data)){
  346. break;
  347. }
  348. $goods_ids = array_column($data,'goods_id');
  349. $where = ['goods_id'=>$goods_ids];
  350. $goodsIds = implode(',',array_column($data,'goods_id'));
  351. $orderField = "field(goods_id,$goodsIds)";
  352. }
  353. $goodsList = SeckillActivity::alias('SA')
  354. ->join('seckill_goods SG','SA.id = SG.seckill_id')
  355. ->join('goods G','SG.goods_id = G.id')
  356. ->where([
  357. ['SA.status','=',SeckillEnum::SECKILL_STATUS_CONDUCT],
  358. ['start_time', '<=', time()],
  359. ['end_time', '>=', time()],
  360. ])
  361. ->where($where)
  362. ->field('SA.id as activity_id,SG.id,goods_id,goods_snap,min_seckill_price,G.image')
  363. ->limit($limit)
  364. ->orderRaw($orderField)
  365. ->select()
  366. ->toArray();
  367. if(empty($goodsList)){
  368. $content[$moduleKey]['content']['data'] = [];
  369. break;
  370. }
  371. outFileLog($goodsList,'moduledata','$moduleName-SECKILL');
  372. foreach($goodsList as &$gv){
  373. $goods_item_count = GoodsItem::where(['goods_id'=>$gv['id']])->count();
  374. if($goods_item_count > 1){
  375. $gv['is_multi_gauge'] = 1;
  376. }else{
  377. $gv['is_multi_gauge'] = 0;
  378. }
  379. }
  380. //销量
  381. $activityIds = array_column($goodsList,'activity_id');
  382. $goodsIds = array_column($goodsList,'goods_id');
  383. $salesList = SeckillGoodsItem::where(['seckill_id'=>$activityIds,'goods_id'=>$goodsIds])
  384. ->group('goods_id')
  385. ->column('sum(sales_volume)','goods_id');
  386. $data = [];
  387. foreach ($goodsList as $goods){
  388. $goodsSnap = json_decode($goods['goods_snap'],true);
  389. $data[] = [
  390. 'id' => $goods['id'],
  391. 'activity_id' => $goods['activity_id'],
  392. 'activity_type' => ActivityEnum::SECKILL,
  393. 'goods_id' => $goods['goods_id'],
  394. 'name' => $goodsSnap['name'],
  395. 'image' => FileService::getFileUrl($goods['image']),
  396. 'sell_price' => $goodsSnap['min_price'],
  397. 'activity_price' => $goods['min_seckill_price'],
  398. 'activity_sales' => $salesList[$goods['goods_id']] ?? 0,
  399. ];
  400. }
  401. $content[$moduleKey]['content']['data'] = $data;
  402. break;
  403. // 预售
  404. case ThemePageEnum::PRESELL:
  405. if('admin' == $source){
  406. break;
  407. }
  408. $dataType = $content[$moduleKey]['content']['data_type'];
  409. $data = $content[$moduleKey]['content']['data'];
  410. $limit = false;
  411. $where = [];
  412. //自动获取商品
  413. if(1 == $dataType) {
  414. //获取数量
  415. $limit = $content[$moduleKey]['content']['num'];
  416. $orderField = 'pg.id desc';
  417. }else{
  418. if(empty($data)){
  419. break;
  420. }
  421. $goods_ids = array_column($data,'goods_id');
  422. $where = ['pg.goods_id'=>$goods_ids];
  423. $goodsIds = implode(',',array_column($data,'goods_id'));
  424. $orderField = "field(goods_id,$goodsIds)";
  425. }
  426. $lists = PresellGoods::alias('pg')
  427. ->join('presell p', 'p.id=pg.presell_id')
  428. ->where('p.status', PresellEnum::STATUS_START)
  429. ->where('p.start_time', '<=', time())
  430. ->where('p.end_time', '>=', time())
  431. ->where($where)
  432. ->limit($limit)
  433. ->orderRaw($orderField)
  434. ->field([
  435. 'pg.id',
  436. 'p.id as presell_id', 'p.name', 'p.type',
  437. 'p.start_time', 'p.end_time', 'p.remark',
  438. 'p.send_type', 'p.send_type_day', 'p.buy_limit', 'p.buy_limit_num',
  439. 'p.status',
  440. 'pg.goods_id',
  441. 'pg.content',
  442. 'pg.min_price',
  443. 'pg.virtual_sale',
  444. ])
  445. ->with([
  446. 'items' => function ($query) {
  447. $query->field([ 'presell_goods_id', 'sale_nums' ]);
  448. }
  449. ])
  450. ->select()
  451. ->toArray();
  452. $data = [];
  453. outFileLog($goodsList,'moduledata','$moduleName-PRESELL');
  454. foreach ($lists as $presell) {
  455. $data[] = [
  456. 'id' => $presell['goods_id'],
  457. 'activity_id' => $presell['presell_id'],
  458. 'activity_type' => ActivityEnum::PRESELL,
  459. 'goods_id' => $presell['goods_id'],
  460. 'name' => $presell['content']['name'],
  461. 'image' => FileService::getFileUrl($presell['content']['image']),
  462. 'sell_price' => $presell['content']['min_price'],
  463. 'activity_price' => $presell['min_price'],
  464. 'activity_sales' => array_sum(array_column($presell['items'], 'sale_nums')) + ($presell['virtual_sale']),
  465. ];
  466. }
  467. $content[$moduleKey]['content']['data'] = $data;
  468. break;
  469. //商品推荐
  470. case ThemePageEnum::GOODSRECOM:
  471. $show = $content[$moduleKey]['show'];
  472. if('admin' == $source || 0 == $show){
  473. break;
  474. }
  475. outFileLog($show,'moduledata','$moduleName-GOODSRECOM');
  476. $content[$moduleKey]['content']['data'] = self::recommend();
  477. break;
  478. //小程序直播
  479. case ThemePageEnum::MNPLIVE:
  480. if('admin' == $source){
  481. break;
  482. }
  483. $num = $content[$moduleKey]['content']['num'] ?? 1;
  484. $result = WeChatService::getLiveRoom(0,$num);
  485. if (!is_array($result)) {
  486. break;
  487. }
  488. $data = [];
  489. foreach ($result['room_info'] as $item) {
  490. $data[] = [
  491. 'name' => $item['name'],
  492. 'room_id' => $item['roomid'],
  493. 'cover_img' => $item['cover_img'],
  494. 'anchor_name' => $item['anchor_name'],
  495. 'status' => $item['live_status'],
  496. 'live_status' => LiveEnum::getLiveStatus($item['live_status']),
  497. 'goods' => count($item['goods']),
  498. 'start_time' => date('Y-m-d H:i:s', $item['start_time']),
  499. 'end_time' => date('Y-m-d H:i:s', $item['end_time'])
  500. ];
  501. }
  502. $content[$moduleKey]['content']['data'] = $data;
  503. break;
  504. }
  505. }
  506. return $content;
  507. }
  508. public static function getPCModuleData(array $content,array $config = []):array
  509. {
  510. self::$params = $config;
  511. $isDistribution = self::$params['is_distribution'] ?? false; //是否分销
  512. $isVerifier = self::$params['is_verifier'] ?? false; //是否核销员
  513. $source = self::$params['source'] ?? 'shop'; //后台组件替换或商城组件替换
  514. $userId = self::$params['user_id'] ?? '';
  515. $moduleList = array_column($content,'name');
  516. foreach ($moduleList as $moduleKey => $moduleName){
  517. //需要拼接数据的组件
  518. switch ($moduleName) {
  519. case ThemePageEnum::GOODS:
  520. $goods_type = $content[$moduleKey]['content']['goods_type'] ?? 2;
  521. //商品分类
  522. $limit = false;
  523. if(2 == $goods_type){
  524. if('admin' == $source){
  525. $content[$moduleKey]['content']['data'] = [];
  526. break;
  527. }
  528. $categoryId = $content[$moduleKey]['content']['category']['id'] ?? 0;
  529. $limit = $content[$moduleKey]['content']['category']['num'] ?? false;
  530. $goodsIds = GoodsCategoryIndex::where(['category_id'=>$categoryId])->column('goods_id');
  531. }else{
  532. $goodsIds = array_column($content[$moduleKey]['content']['data'], 'id');
  533. }
  534. //如果id都是空,直接返回数组
  535. if (empty($goodsIds)) {
  536. $content[$moduleKey]['content']['data'] = [];
  537. break;
  538. }
  539. //todo 商品需要根据顺序排序
  540. $orderField = implode(',', $goodsIds);
  541. $goodsList = Goods::where(['id' => $goodsIds,'status'=>GoodsEnum::STATUS_SELL])
  542. ->field('id,name,image,virtual_sales_num+sales_num as sales_num,min_price as sell_price,min_lineation_price as lineation_price')
  543. ->orderRaw("field(id,$orderField)")
  544. ->limit($limit)
  545. ->select()
  546. ->toArray();
  547. //是否显示划线加
  548. $showPrice = ConfigService::get('goods_set', 'show_price', 1);
  549. if(0 == $showPrice){
  550. foreach ($goodsList as $goodsKey => $goodsVal){
  551. $goodsList[$goodsKey]['lineation_price'] = 0;
  552. }
  553. }
  554. $content[$moduleKey]['content']['data'] = $goodsList;
  555. break;
  556. case ThemePageEnum::SECKILL:
  557. if('admin' == $source){
  558. break;
  559. }
  560. $dataType = $content[$moduleKey]['content']['data_type'];
  561. $data = $content[$moduleKey]['content']['data'];
  562. $limit = false;
  563. $where = [];
  564. //自动获取商品
  565. if(1 == $dataType) {
  566. //获取数量
  567. $limit = $content[$moduleKey]['content']['num'];
  568. $orderField = 'SA.id desc';
  569. }else{
  570. if(empty($data)){
  571. break;
  572. }
  573. $goods_ids = array_column($data,'goods_id');
  574. $where = ['goods_id'=>$goods_ids];
  575. $goodsIds = implode(',',array_column($data,'goods_id'));
  576. $orderField = "field(goods_id,$goodsIds)";
  577. }
  578. $goodsList = SeckillActivity::alias('SA')
  579. ->join('seckill_goods SG','SA.id = SG.seckill_id')
  580. ->where([
  581. ['status','=',SeckillEnum::SECKILL_STATUS_CONDUCT],
  582. ['start_time', '<=', time()],
  583. ['end_time', '>=', time()],
  584. ])
  585. ->where($where)
  586. ->field('SA.id as activity_id,SG.id,goods_id,goods_snap,min_seckill_price')
  587. ->limit($limit)
  588. ->orderRaw($orderField)
  589. ->select()
  590. ->toArray();
  591. if(empty($goodsList)){
  592. $content[$moduleKey]['content']['data'] = [];
  593. break;
  594. }
  595. //销量
  596. $activityIds = array_column($goodsList,'activity_id');
  597. $goodsIds = array_column($goodsList,'goods_id');
  598. $salesList = SeckillGoodsItem::where(['seckill_id'=>$activityIds,'goods_id'=>$goodsIds])
  599. ->group('goods_id')
  600. ->column('sum(sales_volume)','goods_id');
  601. $data = [];
  602. foreach ($goodsList as $goods){
  603. $goodsSnap = json_decode($goods['goods_snap'],true);
  604. $data[] = [
  605. 'id' => $goods['id'],
  606. 'activity_id' => $goods['activity_id'],
  607. 'activity_type' => ActivityEnum::SECKILL,
  608. 'goods_id' => $goods['goods_id'],
  609. 'name' => $goodsSnap['name'],
  610. 'image' => FileService::getFileUrl($goodsSnap['image']),
  611. 'sell_price' => $goodsSnap['min_price'],
  612. 'activity_price' => $goods['min_seckill_price'],
  613. 'activity_sales' => $salesList[$goods['goods_id']] ?? 0,
  614. ];
  615. }
  616. $content[$moduleKey]['content']['data'] = $data;
  617. break;
  618. }
  619. }
  620. return $content;
  621. }
  622. /**
  623. * @notes 获取推荐商品
  624. * @param string $orderRaw 推荐商品排序;默认按销量和排序,传空则随机排序
  625. * @return array $type 页面类型
  626. * @return array $goodsIds 排除的商品id
  627. * @author cjhao
  628. * @date 2021/8/23 11:07
  629. */
  630. public static function recommend(string $orderRaw = 'virtual_sales_num+sales_num desc,sort desc',int $type=0,array $goodsIds = []):array
  631. {
  632. $pageType = self::$params['page_type'] ?? $type; //页面类型
  633. $goodsList = [];
  634. $categoryIds = [];
  635. $notGoodsIds = self::$params['goods_id'] ?? $goodsIds;
  636. //如果传空,则使用随机排序
  637. if(empty($orderRaw)){
  638. $orderRaw = 'rand()';
  639. }
  640. //获取推荐商品:
  641. switch ($pageType){
  642. case ThemePageEnum::TYPE_GOODS_DETAIL://商品详情推荐商品
  643. $goodsId = self::$params['goods_id'] ?? '';
  644. $categoryIds = GoodsCategoryIndex::where(['goods_id'=>$goodsId])->column('category_id');
  645. break;
  646. case ThemePageEnum::TYPE_CART: //购物车推荐商品
  647. $userId = self::$params['user_id'] ?? '';
  648. //购物车商品的分类
  649. $cartList = Cart::alias('C')
  650. ->join('goods_category_index GCI','C.goods_id = GCI.goods_id')
  651. ->where(['user_id'=>$userId])
  652. ->column('C.goods_id,category_id');
  653. $notGoodsIds = array_unique(array_column($cartList,'goods_id'));
  654. $categoryIds = array_unique(array_column($cartList,'category_id'));
  655. if(empty($notGoodsIds) || empty($categoryIds)){
  656. $goods_info = Goods::alias('g')->leftJoin('goods_category_index gci','g.id=gci.goods_id')->field('g.id,gci.category_id')->where('g.status = 1')->select()->toArray();
  657. $key_Arr = array_keys($goods_info);
  658. $gc_key = array_rand($key_Arr,1);
  659. $goods_card_info = $goods_info[$gc_key];
  660. $notGoodsIds[] = $goods_card_info['id'];
  661. if((count($goods_card_info['category_id'])>1)){
  662. $key_Arr1 = array_keys($goods_card_info['category_id']);
  663. $gc_key1 = array_rand($key_Arr1,1);
  664. $categoryIds[]=$goods_card_info['category_id'][$gc_key1];
  665. }else{
  666. $categoryIds[]=$goods_card_info['category_id'][0];
  667. }
  668. }
  669. break;
  670. case ThemePageEnum::TYPE_MEMBER_CENTRE://个人中心推荐商品
  671. $userId = self::$params['user_id'] ?? '';
  672. //订单商品的分类
  673. $orderList = Order::alias('O')
  674. ->join('order_goods OG','O.id = OG.order_id')
  675. ->join('goods_category_index GCI','OG.goods_id = GCI.goods_id')
  676. ->where(['user_id'=>$userId])
  677. ->column('OG.goods_id,category_id');
  678. $notGoodsIds = array_unique(array_column($orderList,'goods_id'));
  679. $categoryIds = array_unique(array_column($orderList,'category_id'));
  680. break;
  681. }
  682. if($categoryIds){
  683. $where[] = ['status','=',GoodsEnum::STATUS_SELL];
  684. $where[] = ['category_id','in',$categoryIds];
  685. if($notGoodsIds){
  686. $where[] = ['G.id','not in',$notGoodsIds];
  687. }
  688. //找到推荐商品
  689. $goodsList = Goods::alias('G')
  690. ->join('goods_category_index GCI','G.id = GCI.goods_id')
  691. ->where($where)
  692. ->field('G.id,name,image,min_price as sell_price,min_lineation_price as lineation_price')
  693. ->group("G.id")
  694. ->orderRaw($orderRaw)
  695. ->limit(9)
  696. ->select()->toarray();
  697. //是否显示划线加
  698. $showPrice = ConfigService::get('goods_set', 'show_price', 1);
  699. if(0 == $showPrice){
  700. foreach ($goodsList as $goodsKey => $goodsVal){
  701. $goodsList[$goodsKey]['lineation_price'] = 0;
  702. }
  703. }
  704. }
  705. if(empty($goodsList)){
  706. $goodsList = [];
  707. $goodsLists = Goods::alias('G')
  708. ->join('goods_category_index GCI','G.id = GCI.goods_id')
  709. ->where('G.status = 1')
  710. ->field('G.id,name,image,min_price as sell_price,min_lineation_price as lineation_price')
  711. ->group("G.id")
  712. ->orderRaw($orderRaw)
  713. ->limit(20)
  714. ->select()->toarray();
  715. $key_Arr = array_keys($goodsLists);
  716. if(count($goodsLists)>4){
  717. $gc_key = array_rand($key_Arr,4);
  718. }else{
  719. $gc_key = $key_Arr;
  720. }
  721. foreach ($goodsLists as $k=>$v){
  722. foreach($gc_key as $gk=>$gv){
  723. if($k==$gk){
  724. $goodsList[]=$v;
  725. }
  726. }
  727. }
  728. }
  729. return $goodsList;
  730. }
  731. }