Active.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. <?php
  2. /**
  3. *
  4. * @copyright ©2020 点小铺
  5. * @author hanj
  6. * @link: https://dyuit.com
  7. * Created by VSCode
  8. */
  9. namespace app\api\service\sharp;
  10. use app\api\service\Basics;
  11. use app\api\model\Goods as GoodsModel;
  12. use app\api\model\sharp\Goods as SharpGoodsModel;
  13. use app\api\model\sharp\Active as ActiveModel;
  14. use app\api\model\sharp\ActiveTime as ActiveTimeModel;
  15. use app\api\model\sharp\ActiveGoods as ActiveGoodsModel;
  16. use app\common\enum\sharp\GoodsStatus as GoodsStatusEnum;
  17. use app\common\enum\sharp\ActiveStatus as ActiveStatusEnum;
  18. use app\common\library\helper;
  19. /**
  20. * 秒杀活动服务类
  21. * Class Active
  22. * @package app\api\service\sharp
  23. */
  24. class Active extends Basics
  25. {
  26. private $ActiveModel;
  27. private $ActiveTimeModel;
  28. /**
  29. * 构造方法
  30. * Active constructor.
  31. */
  32. public function __construct()
  33. {
  34. $this->ActiveModel = new ActiveModel;
  35. $this->ActiveTimeModel = new ActiveTimeModel;
  36. }
  37. /**
  38. * 获取秒杀活动会场首页数据
  39. * @return array
  40. * @throws \think\db\exception\DataNotFoundException
  41. * @throws \think\db\exception\ModelNotFoundException
  42. * @throws \think\exception\DbException
  43. */
  44. public function getHallIndex()
  45. {
  46. // 获取秒杀首页顶部菜单
  47. $tabbar = $this->getActiveTabbar();
  48. if (empty($tabbar)) return ['tabbar' => [], 'goodsList' => []];
  49. // 获取活动商品
  50. $goodsList = $this->getGoodsListByActiveTimeId($tabbar[0]['active_time_id']);
  51. return compact('tabbar', 'goodsList');
  52. }
  53. /**
  54. * 获取秒杀活动组件数据
  55. * @param array $goodsParm
  56. * @return array
  57. * @throws \think\db\exception\DataNotFoundException
  58. * @throws \think\db\exception\ModelNotFoundException
  59. * @throws \think\exception\DbException
  60. */
  61. public function getSharpModular($goodsParm = [])
  62. {
  63. // 获取秒杀活动列表
  64. $tabbar = $this->getActiveTabbar();
  65. if (empty($tabbar)) return ['active' => null, 'goodsList' => []];
  66. return [
  67. // 秒杀活动
  68. 'active' => $tabbar[0],
  69. // 活动商品列表
  70. 'goodsList' => $this->getGoodsListByActiveTimeId($tabbar[0]['active_time_id'], $goodsParm),
  71. ];
  72. }
  73. /**
  74. * 根据活动场次ID获取商品列表
  75. * @param int $activeTimeId
  76. * @param array $goodsParm
  77. * @return false|\PDOStatement|string|\think\Collection
  78. */
  79. public function getGoodsListByActiveTimeId($activeTimeId, $goodsParm = [])
  80. {
  81. return ActiveGoodsModel::getGoodsListByActiveTimeId($activeTimeId, $goodsParm);
  82. }
  83. /**
  84. * 获取活动商品详情
  85. * @param $activeTimeId
  86. * @param $sharpGoodsId
  87. * @return array|bool
  88. * @throws \think\exception\DbException
  89. */
  90. public function getyActiveGoodsDetail($activeTimeId, $sharpGoodsId)
  91. {
  92. // 活动详情
  93. $active = $this->getGoodsActive($activeTimeId, $sharpGoodsId);
  94. if (empty($active)) return false;
  95. // 商品详情
  96. $model = new ActiveGoodsModel;
  97. $goods = $model->getGoodsActiveDetail($active, $sharpGoodsId, true);
  98. if (empty($goods)) {
  99. $this->error = $model->getError();
  100. return false;
  101. }
  102. // 商品多规格信息
  103. $goods['goods_multi_spec'] = (new SharpGoodsModel)->getSpecData($goods, $goods['sku']);
  104. return compact('active', 'goods');
  105. }
  106. /**
  107. * 获取订单提交的商品列表
  108. * @param $activeTimeId
  109. * @param $sharpGoodsId
  110. * @param $goodsSkuId
  111. * @param $goodsNum
  112. * @return array|bool
  113. * @throws \think\exception\DbException
  114. */
  115. public function getCheckoutGoodsList($activeTimeId, $sharpGoodsId, $goodsSkuId, $goodsNum)
  116. {
  117. // 活动详情
  118. $active = $this->getGoodsActive($activeTimeId, $sharpGoodsId);
  119. if (empty($active)) return false;
  120. // 商品详情
  121. $model = new ActiveGoodsModel;
  122. $goods = $model->getGoodsActiveDetail($active, $sharpGoodsId, false);
  123. if (empty($goods)) return false;
  124. // 商品sku信息
  125. $goods['goods_sku'] = GoodsModel::getGoodsSku($goods, $goodsSkuId);
  126. // 商品列表
  127. $goodsList = [$goods->hidden(['category', 'content', 'image', 'sku'])];
  128. foreach ($goodsList as &$item) {
  129. // 商品价格
  130. $item['goods_price'] = $item['goods_sku']['seckill_price'];
  131. $item['line_price'] = $item['goods_sku']['original_price'];
  132. // 商品id
  133. $item['spec_sku_id'] = $item['goods_sku']['spec_sku_id'];
  134. $item['goods_source_id'] = $item['sharp_goods_id'];
  135. // 商品购买数量
  136. $item['total_num'] = $goodsNum;
  137. // 商品购买总金额
  138. $item['total_price'] = helper::bcmul($item['goods_price'], $goodsNum);
  139. }
  140. return $goodsList;
  141. }
  142. /**
  143. * 活动详情
  144. * @param $activeTimeId
  145. * @param $sharpGoodsId
  146. * @return array|bool
  147. */
  148. private function getGoodsActive($activeTimeId, $sharpGoodsId)
  149. {
  150. // 获取活动商品的关联信息
  151. $model = $this->getActiveGoods($activeTimeId, $sharpGoodsId);
  152. if (empty($model) || !($model['active']['status'] && $model['active_time']['status'])) {
  153. $this->error = '很抱歉,该活动不存在或已结束';
  154. return false;
  155. }
  156. // 整理数据
  157. $startTime = $model['active']['active_date'] + ($model->active_time->getData('active_time') * 60 * 60);
  158. $endTime = $startTime + (1 * 60 * 60);
  159. $activeStatus = $this->getActivcGoodsStatus($startTime, $endTime);
  160. $data = [
  161. 'active_id' => $model['active_id'],
  162. 'active_time_id' => $model['active_time_id'],
  163. 'active_time' => $model['active_time']['active_time'],
  164. 'sales_actual' => $model['sales_actual'],
  165. 'start_time' => $this->onFormatTime($startTime),
  166. 'end_time' => $this->onFormatTime($endTime),
  167. 'active_status' => $activeStatus,
  168. 'count_down_time' => $this->getGoodsActiveCountDownTime($activeStatus, $startTime, $endTime),
  169. 'wxapp_id' => $model['wxapp_id'],
  170. ];
  171. return $data;
  172. }
  173. /**
  174. * 获取活动商品的关联信息
  175. * @param $activeTimeId
  176. * @param $sharpGoodsId
  177. * @return mixed
  178. */
  179. public function getActiveGoods($activeTimeId, $sharpGoodsId)
  180. {
  181. static $data = [];
  182. if (!isset($data["{$activeTimeId}_{$sharpGoodsId}"])) {
  183. $model = ActiveGoodsModel::getGoodsActive($activeTimeId, $sharpGoodsId);
  184. !empty($model) && $data["{$activeTimeId}_{$sharpGoodsId}"] = $model;
  185. }
  186. return $data["{$activeTimeId}_{$sharpGoodsId}"];
  187. }
  188. /**
  189. * 活动商品倒计时
  190. * @param $activeStatus
  191. * @param $startTime
  192. * @param $endTime
  193. * @return bool|false|string
  194. */
  195. private function getGoodsActiveCountDownTime($activeStatus, $startTime, $endTime)
  196. {
  197. if ($activeStatus == GoodsStatusEnum::STATE_BEGIN) {
  198. return $this->onFormatTime($startTime);
  199. }
  200. if ($activeStatus == GoodsStatusEnum::STATE_SOON) {
  201. return $this->onFormatTime($endTime);
  202. }
  203. return false;
  204. }
  205. /**
  206. * 活动商品状态
  207. * @param $startTime
  208. * @param $endTime
  209. * @return int
  210. */
  211. private function getActivcGoodsStatus($startTime, $endTime)
  212. {
  213. $nowTime = time();
  214. if ($nowTime < $startTime) {
  215. return GoodsStatusEnum::STATE_SOON;
  216. }
  217. if ($nowTime >= $startTime && $nowTime < $endTime) {
  218. return GoodsStatusEnum::STATE_BEGIN;
  219. }
  220. return GoodsStatusEnum::STATE_END;
  221. }
  222. /**
  223. * 获取秒杀首页顶部菜单
  224. * @return array
  225. * @throws \think\db\exception\DataNotFoundException
  226. * @throws \think\db\exception\ModelNotFoundException
  227. * @throws \think\exception\DbException
  228. */
  229. private function getActiveTabbar()
  230. {
  231. // 当天的活动
  232. $todyActive = $this->ActiveModel->getNowActive();
  233. $data = [];
  234. if (!empty($todyActive)) {
  235. // 当前进行中的活动
  236. $data[] = $this->getBeginActive($todyActive);
  237. // 获取即将开始的活动
  238. $data = array_merge($data, $this->getSoonActive($todyActive));
  239. }
  240. // 获取预告的活动
  241. $data[] = $this->getNoticeActive();
  242. return array_values(array_filter($data));
  243. }
  244. /**
  245. * 获取当前进行中的活动
  246. * @param $todyActive
  247. * @return array
  248. * @throws \think\db\exception\DataNotFoundException
  249. * @throws \think\db\exception\ModelNotFoundException
  250. * @throws \think\exception\DbException
  251. */
  252. private function getBeginActive($todyActive)
  253. {
  254. // 当前的时间点
  255. $model = $this->ActiveTimeModel->getNowActiveTime($todyActive['active_id']);
  256. if (empty($model)) return [];
  257. // 整理数据
  258. $startTime = $todyActive['active_date'] + ($model->getData('active_time') * 60 * 60);
  259. $endTime = $startTime + (1 * 60 * 60);
  260. return [
  261. 'active_id' => $todyActive['active_id'],
  262. 'active_time_id' => $model['active_time_id'],
  263. 'active_time' => $model['active_time'],
  264. 'start_time' => $this->onFormatTime($startTime),
  265. 'end_time' => $this->onFormatTime($endTime),
  266. 'count_down_time' => $this->onFormatTime($endTime),
  267. 'status' => ActiveStatusEnum::ACTIVE_STATE_BEGIN,
  268. 'status_text' => '已开抢',
  269. 'status_text2' => '正在疯抢',
  270. 'sharp_modular_text' => '正在疯抢',
  271. ];
  272. }
  273. /**
  274. * 获取即将开始的活动
  275. * @param $todyActive
  276. * @return array
  277. * @throws \think\db\exception\DataNotFoundException
  278. * @throws \think\db\exception\ModelNotFoundException
  279. * @throws \think\exception\DbException
  280. */
  281. private function getSoonActive($todyActive)
  282. {
  283. // 当前的时间点
  284. $list = $this->ActiveTimeModel->getNextActiveTimes($todyActive['active_id']);
  285. if (empty($list) || $list->isEmpty()) return [];
  286. // 整理数据
  287. $data = [];
  288. foreach ($list as $item) {
  289. $startTime = $todyActive['active_date'] + ($item->getData('active_time') * 60 * 60);
  290. $endTime = $startTime + (1 * 60 * 60);
  291. $data[] = [
  292. 'active_id' => $todyActive['active_id'],
  293. 'active_time_id' => $item['active_time_id'],
  294. 'active_time' => $item['active_time'],
  295. 'start_time' => $this->onFormatTime($startTime),
  296. 'end_time' => $this->onFormatTime($endTime),
  297. 'count_down_time' => $this->onFormatTime($startTime),
  298. 'status' => ActiveStatusEnum::ACTIVE_STATE_SOON,
  299. 'status_text' => '即将开抢',
  300. 'status_text2' => '即将开抢',
  301. 'sharp_modular_text' => "{$item['active_time']} 场预告",
  302. ];
  303. }
  304. return $data;
  305. }
  306. /**
  307. * 获取预告的活动
  308. * @throws \think\db\exception\DataNotFoundException
  309. * @throws \think\db\exception\ModelNotFoundException
  310. * @throws \think\exception\DbException
  311. */
  312. private function getNoticeActive()
  313. {
  314. // 下一场活动
  315. $nextActive = $this->ActiveModel->getNextActive();
  316. if (empty($nextActive)) return [];
  317. // 第一个时间点
  318. $model = $this->ActiveTimeModel->getRecentActiveTime($nextActive['active_id']);
  319. if (empty($model)) return [];
  320. // 整理数据
  321. $startTime = $nextActive['active_date'] + ($model->getData('active_time') * 60 * 60);
  322. $endTime = $startTime + (1 * 60 * 60);
  323. return [
  324. 'active_id' => $nextActive['active_id'],
  325. 'active_time_id' => $model['active_time_id'],
  326. 'active_time' => $model['active_time'],
  327. 'start_time' => $this->onFormatTime($startTime),
  328. 'end_time' => $this->onFormatTime($endTime),
  329. 'count_down_time' => $this->onFormatTime($startTime),
  330. 'status' => ActiveStatusEnum::ACTIVE_STATE_NOTICE,
  331. 'status_text' => '预告',
  332. 'status_text2' => $this->onFormatTime($startTime) . ' 开始',
  333. 'sharp_modular_text' => $this->onFormatTime($startTime) . ' 开始',
  334. ];
  335. }
  336. /**
  337. * 将时间戳格式化为日期时间
  338. * @param $timeStamp
  339. * @return false|string
  340. */
  341. private function onFormatTime($timeStamp)
  342. {
  343. return date('Y-m-d H:i', $timeStamp);
  344. }
  345. }