SeckillActivity.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. <?php
  2. namespace addons\Seckill\common\models;
  3. use addons\Seckill\common\enums\SeckillEnum;
  4. use addons\Seckill\common\logic\ActivityLogic;
  5. use common\enums\AddonsEnum;
  6. use common\enums\RedisKeyEnum;
  7. use common\enums\StatusEnum;
  8. use common\logic\common\GoodsLogic;
  9. use common\models\goods\Goods;
  10. use common\models\goods\GoodsAttr;
  11. use common\models\goods\GoodsMarketing;
  12. use Yii;
  13. /**
  14. * This is the model class for table "{{%addons_seckill_activity}}".
  15. *
  16. * @property int $id
  17. * @property int $mall_id
  18. * @property string $title 活动标题
  19. * @property int $goods_id 商品ID
  20. * @property int $attr_id 商品规格ID
  21. * @property int $begin_time 开始时间
  22. * @property int $end_time 结束时间
  23. * @property int $hot_time 预热开始时间
  24. * @property int $stock 库存
  25. * @property int $sale_nums 已售数量
  26. * @property float $price 秒杀售价
  27. * @property int $activity_status 1未开始;2进行中;3已结束
  28. * @property int $status 状态[-1:删除;0:禁用;1启用]
  29. * @property int $created_at
  30. * @property int $updated_at
  31. */
  32. class SeckillActivity extends \common\models\base\BaseActiveRecord
  33. {
  34. //活动状态
  35. const ACTIVITY_STATUS_WAIT = 1;
  36. const ACTIVITY_STATUS_ING = 2;
  37. const ACTIVITY_STATUS_END = 3;
  38. /**
  39. * {@inheritdoc}
  40. */
  41. public static function tableName()
  42. {
  43. return '{{%addons_seckill_activity}}';
  44. }
  45. /**
  46. * {@inheritdoc}
  47. */
  48. public function rules()
  49. {
  50. return [
  51. [['mall_id', 'goods_id', 'begin_time', 'end_time', 'hot_time', 'stock', 'sale_nums', 'activity_status', 'status', 'created_at', 'updated_at','attr_id', 'limit_nums'], 'integer'],
  52. [['price'], 'number'],
  53. [['title'], 'string', 'max' => 128],
  54. ];
  55. }
  56. /**
  57. * {@inheritdoc}
  58. */
  59. public function attributeLabels()
  60. {
  61. return [
  62. 'id' => 'ID',
  63. 'mall_id' => 'Mall ID',
  64. 'title' => 'Title',
  65. 'goods_id' => 'Goods ID',
  66. 'goods_code' => 'Goods Code',
  67. 'begin_time' => 'Begin Time',
  68. 'end_time' => 'End Time',
  69. 'hot_time' => 'Hot Time',
  70. 'stock' => 'Stock',
  71. 'sale_nums' => 'Sale Nums',
  72. 'limit_nums' => '每人限购数',
  73. 'price' => 'Price',
  74. 'activity_status' => 'Activity Status',
  75. 'status' => 'Status',
  76. 'created_at' => 'Created At',
  77. 'updated_at' => 'Updated At',
  78. ];
  79. }
  80. /**
  81. * 活动状态
  82. * @param $status
  83. * @return array|mixed
  84. */
  85. public static function getActivityStatusMap(int $status=null)
  86. {
  87. $map = [
  88. self::ACTIVITY_STATUS_WAIT => '未开始',
  89. self::ACTIVITY_STATUS_ING => '进行中',
  90. self::ACTIVITY_STATUS_END => '已结束',
  91. ];
  92. if (null !== $status) {
  93. $map = $map[$status];
  94. }
  95. return $map;
  96. }
  97. public static function setData(int $mall_id, array $data)
  98. {
  99. $update_stock = false;
  100. if (!empty($data['id'])) {
  101. $model = self::findOne(['mall_id' => $mall_id, 'status' => [StatusEnum::ENABLED, StatusEnum::DISABLED], 'id' => $data['id']]);
  102. if (empty($model)) {
  103. self::$static_error = '活动数据异常';
  104. return false;
  105. }
  106. if($model->activity_status != self::ACTIVITY_STATUS_WAIT && $model->stock != $data['stock']){
  107. //活动
  108. self::$static_error = '活动已开始|结束,不允许修改库存';
  109. return false;
  110. }
  111. if($model->stock != $data['stock']){
  112. $update_stock = true;
  113. }
  114. } else {
  115. $model = new self();
  116. $model->loadDefaultValues();
  117. $model->status = StatusEnum::ENABLED;
  118. $model->activity_status = self::checkActivityStatus($data['begin_time'],$data['end_time']);
  119. $model->mall_id = $mall_id;
  120. unset($data['id']);
  121. $update_stock = true;
  122. }
  123. $goods = Goods::findOne(['mall_id' => $mall_id, 'status' => StatusEnum::ENABLED, 'id' => $data['goods_id']]);
  124. if(!$goods){
  125. self::$static_error = '商品不存在';
  126. return false;
  127. }
  128. //查询规格信息
  129. $attrData = GoodsAttr::findOne([
  130. 'id' => $data['attr_id'],
  131. 'goods_id' => $data['goods_id'],
  132. 'status' => StatusEnum::ENABLED,
  133. ]);
  134. if(empty($attrData)){
  135. throw new \ErrorException('商品不存在或已删除');
  136. }
  137. $oldGoodsId = $model->goods_id;
  138. foreach ($data as $key => $val) {
  139. $model->$key = $val;
  140. }
  141. if (!$model->save()) {
  142. self::$static_error = '保存数据失败:' . $model->getErrorMessage();
  143. return false;
  144. }
  145. self::delCache($model['id']);
  146. // 如果旧商品ID不为空且与新商品ID不同,则更新商品营销信息
  147. $goodsMarketing = GoodsMarketing::findOne([
  148. 'goods_id' => $oldGoodsId,
  149. 'mall_id' => $mall_id,
  150. 'marketing_id' => $model->id,
  151. 'marketing_type' => SeckillEnum::ADDONS_NAME,
  152. 'status' => StatusEnum::ENABLED,
  153. ]);
  154. if (!empty($oldGoodsId) && $oldGoodsId != $data['goods_id'] && !empty($goodsMarketing)) {
  155. $goodsMarketing->goods_id = $data['goods_id'];
  156. $goodsMarketing->save();
  157. } else {
  158. // 新增商品营销信息
  159. $param = [
  160. 'goods_id' => $data['goods_id'],
  161. 'mall_id' => $mall_id,
  162. 'marketing_id' => $model->id,
  163. 'marketing_type' => SeckillEnum::ADDONS_NAME,
  164. ];
  165. GoodsMarketing::setData($param);
  166. }
  167. if($update_stock){
  168. ActivityLogic::setStock($model->id,$model->stock,true);
  169. }
  170. return $model;
  171. }
  172. public static function getCacheKey($activity_id)
  173. {
  174. $cache_key = RedisKeyEnum::suffix(RedisKeyEnum::SECKILL_ACTIVITY, $activity_id, true);
  175. return $cache_key;
  176. }
  177. public static function delCache($activity_id)
  178. {
  179. $cache = Yii::$app->cache;
  180. $cache_key = self::getCacheKey($activity_id);
  181. $cache->delete($cache_key);
  182. }
  183. /**
  184. * 获取活动信息
  185. * @param $activity_id
  186. * @return array|mixed|null|\yii\db\ActiveRecord
  187. */
  188. public static function getActivityByCache($activity_id)
  189. {
  190. //活动时间一到,需要修改此处缓存
  191. $cache = Yii::$app->cache;
  192. $cache_key = self::getCacheKey($activity_id);
  193. $activity = $cache->get($cache_key);
  194. if(!$activity){
  195. $activity = self::find()->where(['id' => $activity_id,'status' => StatusEnum::ENABLED])->asArray()->one();
  196. if(!$activity){
  197. $activity = null;
  198. }else{
  199. //获取商品信息
  200. $goods = GoodsLogic::GetDetail($activity['mall_id'], ['goods_id' => $activity['goods_id']], []);
  201. $goods['goods_source'] = SeckillEnum::ADDONS_NAME;
  202. foreach ($goods['attr'] as $sku){
  203. if($sku['id']==$activity['attr_id']){
  204. $goods['original_price'] = $sku['original_price'];
  205. break;
  206. }
  207. }
  208. $attrs = array_column($goods['attr'],null,'id');
  209. unset($goods['attr']);
  210. $my_attr = $attrs[$activity['attr_id']];
  211. $goods['price'] = $my_attr['price'] > 0 ? $my_attr['price'] : $goods['price'];
  212. $goods['seckill_price'] = $activity['price'];
  213. //修改规格信息
  214. $my_attr['stock'] = ($activity['stock'] - $activity['sale_nums']) > 0 ? $activity['stock'] - $activity['sale_nums'] : 0;
  215. $goods['stock'] = $my_attr['stock'];
  216. $my_attr['price'] = $activity['price'];
  217. $goods['attr'][] = $my_attr;
  218. $sign_ids = explode(':',$my_attr['sign_id']);
  219. if($goods['attr_groups']){
  220. $attr_groups = json_decode($goods['attr_groups'],true);
  221. foreach($attr_groups as $key => $val){
  222. foreach($val['attr_list'] as $k => $v){
  223. if(!in_array($v['attr_id'],$sign_ids)){
  224. unset($val['attr_list'][$k]);
  225. }
  226. }
  227. $val['attr_list'] = array_values($val['attr_list']);
  228. $attr_groups[$key] = $val;
  229. }
  230. $goods['attr_groups'] = json_encode(array_values($attr_groups));
  231. }
  232. $activity['goods'] = $goods;
  233. $activity['activity_status'] = self::checkActivityStatus($activity['begin_time'],$activity['end_time']);
  234. }
  235. $cache->set($cache_key,$activity,600);
  236. }
  237. return $activity;
  238. }
  239. public static function checkActivityStatus($begin_time,$end_time)
  240. {
  241. $now = time();
  242. if($now < $begin_time){
  243. //未开始
  244. $activity_status = self::ACTIVITY_STATUS_WAIT;
  245. }elseif($now >=$begin_time && $now <= $end_time){
  246. //进行中
  247. $activity_status = self::ACTIVITY_STATUS_ING;
  248. }else{
  249. //结束
  250. $activity_status = self::ACTIVITY_STATUS_END;
  251. }
  252. return $activity_status;
  253. }
  254. public static function getActiveListByDiy($mall_id,$post){
  255. $time = time();
  256. $where[] = ['mall_id' => $mall_id];
  257. $where[] = ['status' => StatusEnum::ENABLED];
  258. $where[] = ['>=','end_time' ,$time];
  259. if (!empty($post['keyword'])) {
  260. $goods_list = Goods::lists(['where' => [['mall_id' => $mall_id], ['like', 'goods_name', trim($post['keyword'])], ['status' => StatusEnum::ENABLED]],
  261. 'select' => 'id,cover_pic,goods_name,sales_num,virtual_sales,,price,original_price,subtitle','index'=>'id']);
  262. $goods_id_arr = array_column($goods_list, 'id');
  263. $where[] = ['goods_id' => $goods_id_arr];
  264. }
  265. $params['where'] = $where;
  266. $params['order'] = 'id DESC';
  267. $params['limit'] = 10;
  268. $params['select']='id,goods_id,created_at';
  269. $list = SeckillActivity::listPage($params,false,true);
  270. if(!empty($list['list'])){
  271. if(!isset($goods_list)){
  272. $goods_ids = array_column($list['list'],'goods_id');
  273. $goods_list = Goods::lists(['where' => [['mall_id' => $mall_id], ['id'=>$goods_ids], ['status' => StatusEnum::ENABLED]],
  274. 'select' => 'id,cover_pic,goods_name,sales_num,virtual_sales,price,original_price,subtitle','index'=>'id']);
  275. }
  276. foreach ($list['list'] as &$item){
  277. $item['more_params'] = '?proId='.$item['goods_id'].'&marketing_type=Seckill&params={"activity_id":'.$item['id'].'}';
  278. $item['activity_id'] = $item['id'];
  279. $item['id'] = $item['goods_id'];
  280. $item['img'] = '';
  281. $item['title'] = '';
  282. $item['sales_num'] = 0;
  283. $item['price'] = '';
  284. $item['original_price'] = '';
  285. $item['subtitle'] = '';
  286. if(isset($goods_list)&&isset($goods_list[$item['goods_id']])){
  287. $item['img'] = $goods_list[$item['goods_id']]['cover_pic'];
  288. $item['title'] = $goods_list[$item['goods_id']]['goods_name'];
  289. $item['price'] = $goods_list[$item['goods_id']]['price'];
  290. $item['original_price'] = $goods_list[$item['goods_id']]['original_price'];
  291. $item['subtitle'] = $goods_list[$item['goods_id']]['subtitle'];
  292. $item['sales_num'] = $goods_list[$item['goods_id']]['sales_num']+$goods_list[$item['goods_id']]['virtual_sales'];
  293. }
  294. // unset($item['goods_id']);
  295. }
  296. }
  297. return $list;
  298. }
  299. }