FlashSale.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  1. <?php
  2. namespace app\admin\controller\unishop\market;
  3. use addons\unishop\extend\Redis;
  4. use app\admin\model\unishop\FlashProduct;
  5. use app\admin\model\unishop\OrderExtend;
  6. use app\admin\model\unishop\OrderProduct;
  7. use app\common\controller\Backend;
  8. use think\Db;
  9. use think\Exception;
  10. use think\exception\PDOException;
  11. use think\exception\ValidateException;
  12. use think\Hook;
  13. /**
  14. * 秒杀管理
  15. *
  16. * @icon fa fa-circle-o
  17. */
  18. class FlashSale extends Backend
  19. {
  20. /**
  21. * Multi方法可批量修改的字段
  22. */
  23. protected $multiFields = 'switch';
  24. /**
  25. * 是否开启Validate验证
  26. */
  27. protected $modelValidate = true;
  28. /**
  29. * 是否开启模型场景验证
  30. */
  31. protected $modelSceneValidate = true;
  32. /**
  33. * FlashSale模型对象
  34. * @var \app\admin\model\unishop\FlashSale
  35. */
  36. protected $model = null;
  37. public function _initialize()
  38. {
  39. parent::_initialize();
  40. $this->model = new \app\admin\model\unishop\FlashSale;
  41. $this->view->assign("statusList", $this->model->getStatusList());
  42. }
  43. /**
  44. * 查看
  45. */
  46. public function index()
  47. {
  48. //设置过滤方法
  49. $this->request->filter(['strip_tags']);
  50. if ($this->request->isAjax()) {
  51. //如果发送的来源是Selectpage,则转发到Selectpage
  52. if ($this->request->request('keyField')) {
  53. return $this->selectpage();
  54. }
  55. list($where, $sort, $order, $offset, $limit) = $this->buildparams();
  56. $total = $this->model
  57. ->where($where)
  58. ->count();
  59. $list = $this->model
  60. ->with([
  61. 'product'
  62. ])
  63. ->where($where)
  64. ->order($sort, $order)
  65. ->limit($offset, $limit)
  66. ->select();
  67. $list = collection($list)->toArray();
  68. $result = array("total" => $total, "rows" => $list);
  69. return json($result);
  70. }
  71. return $this->view->fetch();
  72. }
  73. /**
  74. * 添加
  75. */
  76. public function add()
  77. {
  78. if ($this->request->isPost()) {
  79. $params = $this->request->post("row/a");
  80. if ($params) {
  81. $params = $this->preExcludeFields($params);
  82. if ($this->dataLimit && $this->dataLimitFieldAutoFill) {
  83. $params[$this->dataLimitField] = $this->auth->id;
  84. }
  85. //Db::startTrans();
  86. $this->model->startTrans();
  87. try {
  88. //是否采用模型验证
  89. if ($this->modelValidate) {
  90. $name = str_replace("\\model\\", "\\validate\\", get_class($this->model));
  91. $validate = is_bool($this->modelValidate) ? ($this->modelSceneValidate ? $name . '.add' : $name) : $this->modelValidate;
  92. $this->model->validateFailException(true)->validate($validate);
  93. }
  94. $params['starttime'] = strtotime($params['starttime']);
  95. $params['endtime'] = strtotime($params['endtime']);
  96. $this->model->allowField(true)->save($params);
  97. $products = [];
  98. if (isset($params['product'])) {
  99. $time = time();
  100. $redis = new Redis();
  101. foreach ($params['product'] as $item) {
  102. array_push($products, [
  103. 'flash_id' => $this->model->id,
  104. 'product_id' => $item['id'],
  105. 'number' => $item['number'],
  106. 'introduction' => $item['introduction'],
  107. 'createtime' => $time,
  108. 'updatetime' => $time,
  109. ]);
  110. // 是否上架
  111. if ($params['switch'] == \app\admin\model\unishop\FlashSale::SWITCH_YES) {
  112. $redis->handler->hMSet('flash_sale_' . $this->model->id . '_' . $item['id'], [
  113. 'flash_id' => $this->model->id,
  114. 'product_id' => $item['id'],
  115. 'id' => 0, // 新增的时候没有flash_product_id. 这个值无关紧要
  116. 'number' => $item['number'],
  117. 'sold' => 0, // 出售0个
  118. 'switch' => 1, // 默认全部上架
  119. 'starttime' => $params['starttime'],
  120. 'endtime' => $params['endtime'],
  121. ]);
  122. }
  123. }
  124. }
  125. if (empty($products)) {
  126. throw new ValidateException(__('Add at least one product'));
  127. }
  128. $flashProduct = new FlashProduct();
  129. $flashProduct->insertAll($products);
  130. //Db::commit();
  131. $this->model->commit();
  132. $this->success();
  133. } catch (ValidateException $e) {
  134. //Db::rollback();
  135. $this->model->rollback();
  136. $this->error($e->getMessage());
  137. } catch (PDOException $e) {
  138. //Db::rollback();
  139. $this->model->rollback();
  140. $this->error($e->getMessage());
  141. } catch (Exception $e) {
  142. //Db::rollback();
  143. $this->model->rollback();
  144. $this->error($e->getMessage());
  145. }
  146. $this->error(__('No rows were inserted'));
  147. }
  148. $this->error(__('Parameter %s can not be empty', ''));
  149. }
  150. return $this->view->fetch();
  151. }
  152. /**
  153. * 编辑
  154. */
  155. public function edit($ids = null)
  156. {
  157. $row = $this->model->get($ids);
  158. if (!$row) {
  159. $this->error(__('No Results were found'));
  160. }
  161. $adminIds = $this->getDataLimitAdminIds();
  162. if (is_array($adminIds)) {
  163. if (!in_array($row[$this->dataLimitField], $adminIds)) {
  164. $this->error(__('You have no permission'));
  165. }
  166. }
  167. if ($this->request->isPost()) {
  168. $params = $this->request->post("row/a");
  169. if ($row['status'] == \app\admin\model\unishop\FlashSale::STATUS_YES) {
  170. $this->error(__('Activity filed,can not change'));
  171. }
  172. if ($params) {
  173. $params = $this->preExcludeFields($params);
  174. $result = false;
  175. //Db::startTrans();
  176. $this->model->startTrans();
  177. try {
  178. if (isset($params['switch']) && $params['switch'] == \app\admin\model\unishop\FlashSale::SWITCH_YES) {
  179. Redis::available();
  180. }
  181. $row->checkItCanEdit();
  182. //是否采用模型验证
  183. if ($this->modelValidate) {
  184. $name = str_replace("\\model\\", "\\validate\\", get_class($this->model));
  185. $validate = is_bool($this->modelValidate) ? ($this->modelSceneValidate ? $name . '.edit' : $name) : $this->modelValidate;
  186. $row->validateFailException(true)->validate($validate);
  187. }
  188. $result = $row->allowField(true)->save($params);
  189. $products = [];
  190. if (isset($params['product'])) {
  191. $time = time();
  192. foreach ($params['product'] as $item) {
  193. array_push($products, [
  194. 'flash_id' => $row['id'],
  195. 'product_id' => $item['id'],
  196. 'number' => $item['number'],
  197. 'introduction' => $item['introduction'],
  198. 'createtime' => $time,
  199. 'updatetime' => $time,
  200. ]);
  201. }
  202. }
  203. if (empty($products)) {
  204. throw new ValidateException(__('Add at least one product'));
  205. }
  206. $flashProduct = new FlashProduct();
  207. $flashProduct->where(['flash_id' => $row['id']])->delete();
  208. $flashProduct->insertAll($products);
  209. //Db::commit();
  210. $this->model->commit();
  211. } catch (ValidateException $e) {
  212. //Db::rollback();
  213. $this->model->rollback();
  214. $this->error($e->getMessage());
  215. } catch (PDOException $e) {
  216. //Db::rollback();
  217. $this->model->rollback();
  218. $this->error($e->getMessage());
  219. } catch (Exception $e) {
  220. //Db::rollback();
  221. $this->model->rollback();
  222. $this->error($e->getMessage());
  223. }
  224. if ($result !== false) {
  225. $this->success();
  226. } else {
  227. $this->error(__('No rows were updated'));
  228. }
  229. }
  230. $this->error(__('Parameter %s can not be empty', ''));
  231. }
  232. $this->view->assign("row", $row);
  233. return $this->view->fetch();
  234. }
  235. /**
  236. * 真实删除
  237. */
  238. public function destroy($ids = "")
  239. {
  240. $pk = $this->model->getPk();
  241. $adminIds = $this->getDataLimitAdminIds();
  242. if (is_array($adminIds)) {
  243. $this->model->where($this->dataLimitField, 'in', $adminIds);
  244. }
  245. if ($ids) {
  246. $this->model->where($pk, 'in', $ids);
  247. }
  248. $count = 0;
  249. Db::startTrans();
  250. try {
  251. $list = $this->model->onlyTrashed()->select();
  252. foreach ($list as $k => $v) {
  253. FlashProduct::destroy(['flash_id' => $v->id]);
  254. $count += $v->delete(true);
  255. }
  256. Db::commit();
  257. } catch (PDOException $e) {
  258. Db::rollback();
  259. $this->error($e->getMessage());
  260. } catch (Exception $e) {
  261. Db::rollback();
  262. $this->error($e->getMessage());
  263. }
  264. if ($count) {
  265. $this->success();
  266. } else {
  267. $this->error(__('No rows were deleted'));
  268. }
  269. $this->error(__('Parameter %s can not be empty', 'ids'));
  270. }
  271. /**
  272. * 归档结束
  273. */
  274. public function done($ids = null)
  275. {
  276. Db::startTrans();
  277. try {
  278. $row = $this->model->get($ids, [
  279. 'product' => function ($query) { // flashProduct
  280. // 悲观锁
  281. $query->lock(true)->with(['product']); //product
  282. }
  283. ]);
  284. if (!$row) {
  285. throw new Exception(__('No Results were found'));
  286. }
  287. if ($row['status'] == \app\admin\model\unishop\FlashSale::STATUS_YES) {
  288. throw new Exception(__('Activity filed,can not change'));
  289. }
  290. $orderExtent = new OrderProduct();
  291. $orders = $orderExtent->where(['flash_id' => $ids])
  292. ->field('number,spec,product_id')->select();
  293. if (!$orders) {
  294. throw new Exception(__('No one buys'));
  295. }
  296. $productList = [];
  297. foreach ($orders as $key => $order) {
  298. if ($order['spec'] == '' || !$order['spec'] || empty($order['spec']) || is_null($order['spec'])) {
  299. // 没有规格的商品
  300. if (isset($productList[$order['product_id']])) {
  301. $productList[$order['product_id']] += $order['number'];
  302. } else {
  303. $productList[$order['product_id']] = $order['number'];
  304. }
  305. } else {
  306. // 有规格的商品
  307. if (!isset($productList[$order['product_id']])) {
  308. $productList[$order['product_id']] = [];
  309. }
  310. if (!isset($productList[$order['product_id']][$order['spec']])) {
  311. $productList[$order['product_id']][$order['spec']] = $order['number'];
  312. } else {
  313. $productList[$order['product_id']][$order['spec']] += $order['number'];
  314. }
  315. }
  316. }
  317. $products = $specNumber = [];
  318. foreach ($productList as $product_id => $value) {
  319. foreach ($row['product'] as $flashProduct) {
  320. if ($flashProduct['product_id'] == $product_id) {
  321. if (is_array($value)) {
  322. // 有规格 (这里循环的是同一个商品不同的规格)
  323. foreach ($value as $spec => $number) {
  324. $products[] = $flashProduct['product']->getData();
  325. $specNumber[$spec] = $number;
  326. }
  327. } else {
  328. // 无规格
  329. $products[] = $flashProduct['product']->getData();
  330. $specNumber[] = $value;
  331. }
  332. }
  333. }
  334. }
  335. // 让秒杀下架
  336. $row->status = \app\admin\model\unishop\FlashSale::STATUS_YES;
  337. $row->switch = \app\admin\model\unishop\FlashSale::SWITCH_NO;
  338. $row->save();
  339. $this->model->activityFiled($products, $specNumber);
  340. // 删除redis数据
  341. $redis = new Redis();
  342. foreach ($products as $product) {
  343. $redis->handler->del('flash_sale_' . $ids . '_' . $product['id']);
  344. }
  345. Db::commit();
  346. $this->success(__('Success'));
  347. } catch (Exception $e) {
  348. Db::rollback();
  349. $this->error($e->getMessage());
  350. }
  351. }
  352. /**
  353. * 秒杀的产品列表
  354. */
  355. public function product()
  356. {
  357. $flashId = $this->request->request('flash_id');
  358. $flashProductModel = new FlashProduct();
  359. $products = $flashProductModel
  360. ->with([
  361. 'product' => function ($query) {
  362. $query->with('category')->field(['id', 'title', 'category_id', 'image', 'stock']);
  363. }
  364. ])
  365. ->where(['flash_id' => $flashId])
  366. ->select();
  367. $list = [];
  368. foreach ($products as $key => $item) {
  369. $list[$key]['flash_product_id'] = $item['id'];
  370. $list[$key]['id'] = $item['product_id'];
  371. $list[$key]['product_id'] = $item['product_id'];
  372. $list[$key]['title'] = $item['product']['title'];
  373. $list[$key]['image'] = $item['product']['image'];
  374. $list[$key]['stock'] = $item['product']['stock'];
  375. $list[$key]['sold'] = $item['sold'];
  376. $list[$key]['switch'] = $item['switch'];
  377. $list[$key]['category'] = $item['product']['category'];
  378. $list[$key]['number'] = $item['number'];
  379. $list[$key]['introduction'] = $item['introduction'];
  380. }
  381. $result = array("total" => count($list), "rows" => $list);
  382. return json($result);
  383. }
  384. /**
  385. * 批量更新
  386. */
  387. public function multi($ids = "")
  388. {
  389. $ids = $ids ? $ids : $this->request->param("ids");
  390. if ($ids) {
  391. if ($this->request->has('params')) {
  392. parse_str($this->request->post("params"), $values);
  393. $values = array_intersect_key($values, array_flip(is_array($this->multiFields) ? $this->multiFields : explode(',', $this->multiFields)));
  394. if ($values || $this->auth->isSuperAdmin()) {
  395. $adminIds = $this->getDataLimitAdminIds();
  396. if (is_array($adminIds)) {
  397. $this->model->where($this->dataLimitField, 'in', $adminIds);
  398. }
  399. $count = 0;
  400. Db::startTrans();
  401. try {
  402. Redis::available();
  403. $list = $this->model->with(['product'])->where($this->model->getPk(), 'in', $ids)->select();
  404. $redis = new Redis();
  405. foreach ($list as $index => $item) {
  406. if ($item['status'] == \app\admin\model\unishop\FlashSale::STATUS_YES) {
  407. throw new Exception(__('Activity filed,can not change'));
  408. }
  409. foreach ($item['product'] as $product) {
  410. // 上架
  411. if ($values['switch'] == \app\admin\model\unishop\FlashSale::SWITCH_YES) {
  412. $redis->handler->hMSet('flash_sale_' . $product['flash_id'] . '_' . $product['product_id'], [
  413. 'flash_id' => $product['flash_id'],
  414. 'product_id' => $product['product_id'],
  415. 'id' => $product['id'],
  416. 'number' => $product['number'],
  417. 'sold' => $product['sold'],
  418. 'switch' => $product['switch'],
  419. 'starttime' => $item['starttime'],
  420. 'endtime' => $item['endtime'],
  421. ]);
  422. } else {
  423. // 下架
  424. $redis->handler->del('flash_sale_' . $product['flash_id'] . '_' . $product['product_id']);
  425. }
  426. }
  427. $count += $item->allowField(true)->isUpdate(true)->save($values);
  428. }
  429. Db::commit();
  430. } catch (PDOException $e) {
  431. Db::rollback();
  432. $this->error($e->getMessage());
  433. } catch (Exception $e) {
  434. Db::rollback();
  435. $this->error($e->getMessage());
  436. }
  437. if ($count) {
  438. $this->success();
  439. } else {
  440. $this->error(__('No rows were updated'));
  441. }
  442. } else {
  443. $this->error(__('You have no permission'));
  444. }
  445. }
  446. }
  447. $this->error(__('Parameter %s can not be empty', 'ids'));
  448. }
  449. }