Cart.php 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. <?php
  2. /**
  3. *
  4. * @copyright ©2020 点小铺
  5. * @author hanj
  6. * @link: https://dyuit.com
  7. * Created by VSCode
  8. */
  9. namespace app\api\model;
  10. use think\Cache;
  11. use app\api\model\Goods as GoodsModel;
  12. use app\common\library\helper;
  13. use app\common\service\wechat\wow\Shoping as WowService;
  14. /**
  15. * 购物车管理
  16. * Class Cart
  17. * @package app\api\model
  18. */
  19. class Cart
  20. {
  21. /* @var string $error 错误信息 */
  22. public $error = '';
  23. /* @var \think\Model|\think\Collection $user 用户信息 */
  24. private $user;
  25. /* @var int $user_id 用户id */
  26. private $user_id;
  27. /* @var int $wxapp_id 小程序商城id */
  28. private $wxapp_id;
  29. /* @var array $cart 购物车列表 */
  30. private $cart = [];
  31. /* @var bool $clear 是否清空购物车 */
  32. private $clear = false;
  33. /**
  34. * 构造方法
  35. * Cart constructor.
  36. * @param \think\Model|\think\Collection $user
  37. */
  38. public function __construct($user)
  39. {
  40. $this->user = $user;
  41. $this->user_id = $this->user['user_id'];
  42. $this->wxapp_id = $this->user['wxapp_id'];
  43. $this->cart = Cache::get('cart_' . $this->user_id) ?: [];
  44. }
  45. /**
  46. * 购物车列表 (含商品信息)
  47. * @return array
  48. * @param string $cartIds 请求参数
  49. * @throws \think\Exception
  50. * @throws \think\db\exception\DataNotFoundException
  51. * @throws \think\db\exception\ModelNotFoundException
  52. * @throws \think\exception\DbException
  53. */
  54. public function getList($cartIds)
  55. {
  56. // 获取购物车商品列表
  57. return $this->getOrderGoodsList($cartIds);
  58. }
  59. /**
  60. * 获取购物车列表
  61. * @param string|null $cartIds 购物车索引集 (为null时则获取全部)
  62. * @return array
  63. */
  64. public function getCartList($cartIds = null)
  65. {
  66. if (empty($cartIds)) return $this->cart;
  67. $cartList = [];
  68. $indexArr = (strpos($cartIds, ',') !== false) ? explode(',', $cartIds) : [$cartIds];
  69. foreach ($indexArr as $index) {
  70. isset($this->cart[$index]) && $cartList[$index] = $this->cart[$index];
  71. }
  72. return $cartList;
  73. }
  74. /**
  75. * 获取购物车中的商品列表
  76. * @param $cartIds
  77. * @return array|bool
  78. * @throws \think\Exception
  79. * @throws \think\db\exception\DataNotFoundException
  80. * @throws \think\db\exception\ModelNotFoundException
  81. * @throws \think\exception\DbException
  82. */
  83. private function getOrderGoodsList($cartIds)
  84. {
  85. // 购物车商品列表
  86. $goodsList = [];
  87. // 获取购物车列表
  88. $cartList = $this->getCartList($cartIds);
  89. if (empty($cartList)) {
  90. $this->setError('当前购物车没有商品');
  91. return $goodsList;
  92. }
  93. // 购物车中所有商品id集
  94. $goodsIds = array_unique(helper::getArrayColumn($cartList, 'goods_id'));
  95. // 获取并格式化商品数据
  96. $sourceData = (new GoodsModel)->getListByIds($goodsIds);
  97. $sourceData = helper::arrayColumn2Key($sourceData, 'goods_id');
  98. // 格式化购物车数据列表
  99. foreach ($cartList as $key => $item) {
  100. // 判断商品不存在则自动删除
  101. if (!isset($sourceData[$item['goods_id']])) {
  102. $this->delete($key);
  103. continue;
  104. }
  105. /* @var GoodsModel $goods 商品信息 */
  106. $goods = clone $sourceData[$item['goods_id']];
  107. // 判断商品是否已删除
  108. if ($goods['is_delete']) {
  109. $this->delete($key);
  110. continue;
  111. }
  112. // 商品sku信息
  113. $goods['goods_sku'] = GoodsModel::getGoodsSku($goods, $item['goods_sku_id']);
  114. $goods['goods_sku_id'] = $item['goods_sku_id'];
  115. $goods['spec_sku_id'] = $goods['goods_sku']['spec_sku_id'];
  116. // 商品sku不存在则自动删除
  117. if (empty($goods['goods_sku'])) {
  118. $this->delete($key);
  119. continue;
  120. }
  121. // 商品单价
  122. $goods['goods_price'] = $goods['goods_sku']['goods_price'];
  123. // 购买数量
  124. $goods['total_num'] = $item['goods_num'];
  125. // 商品总价
  126. $goods['total_price'] = bcmul($goods['goods_price'], $item['goods_num'], 2);
  127. $goodsList[] = $goods->hidden(['category', 'content', 'image', 'sku']);
  128. }
  129. return $goodsList;
  130. }
  131. /**
  132. * 加入购物车
  133. * @param int $goodsId 商品id
  134. * @param int $goodsNum 加入购物车的数量
  135. * @param string $goodsSkuId 商品sku索引
  136. * @return bool
  137. * @throws \app\common\exception\BaseException
  138. * @throws \think\exception\DbException
  139. */
  140. public function add($goodsId, $goodsNum, $goodsSkuId)
  141. {
  142. // 购物车商品索引
  143. $index = "{$goodsId}_{$goodsSkuId}";
  144. // 加入购物车后的商品数量
  145. $cartGoodsNum = $goodsNum + (isset($this->cart[$index]) ? $this->cart[$index]['goods_num'] : 0);
  146. // 获取商品信息
  147. $goods = GoodsModel::detail($goodsId);
  148. // 验证商品能否加入
  149. if (!$this->checkGoods($goods, $goodsSkuId, $cartGoodsNum)) {
  150. return false;
  151. }
  152. // 将商品同步到好物圈
  153. if (!$this->isExistGoodsId($goodsId)) {
  154. (new WowService($this->wxapp_id))->add($this->user, [$goods]);
  155. }
  156. // 记录到购物车列表
  157. $this->cart[$index] = [
  158. 'goods_id' => $goodsId,
  159. 'goods_num' => $cartGoodsNum,
  160. 'goods_sku_id' => $goodsSkuId,
  161. 'create_time' => time()
  162. ];
  163. return true;
  164. }
  165. /**
  166. * 验证购物车中是否存在某商品
  167. * @param $goodsId
  168. * @return bool
  169. */
  170. private function isExistGoodsId($goodsId)
  171. {
  172. foreach ($this->cart as $item) {
  173. if ($item['goods_id'] == $goodsId) return true;
  174. }
  175. return false;
  176. }
  177. /**
  178. * 验证商品是否可以购买
  179. * @param GoodsModel $goods 商品信息
  180. * @param string $goodsSkuId 商品sku索引
  181. * @param $cartGoodsNum
  182. * @return bool
  183. */
  184. private function checkGoods($goods, $goodsSkuId, $cartGoodsNum)
  185. {
  186. // 判断商品是否下架
  187. if (!$goods || $goods['is_delete'] || $goods['goods_status']['value'] != 10) {
  188. $this->setError('很抱歉,商品信息不存在或已下架');
  189. return false;
  190. }
  191. // 商品sku信息
  192. $goods['goods_sku'] = GoodsModel::getGoodsSku($goods, $goodsSkuId);
  193. // 判断商品库存
  194. if ($cartGoodsNum > $goods['goods_sku']['stock_num']) {
  195. $this->setError('很抱歉,商品库存不足');
  196. return false;
  197. }
  198. return true;
  199. }
  200. /**
  201. * 减少购物车中某商品数量
  202. * @param int $goodsId
  203. * @param string $goodsSkuId
  204. */
  205. public function sub($goodsId, $goodsSkuId)
  206. {
  207. $index = "{$goodsId}_{$goodsSkuId}";
  208. $this->cart[$index]['goods_num'] > 1 && $this->cart[$index]['goods_num']--;
  209. }
  210. /**
  211. * 删除购物车中指定商品
  212. * @param string $cartIds (支持字符串ID集)
  213. */
  214. public function delete($cartIds)
  215. {
  216. $indexArr = strpos($cartIds, ',') !== false ? explode(',', $cartIds) : [$cartIds];
  217. foreach ($indexArr as $index) {
  218. if (isset($this->cart[$index])) unset($this->cart[$index]);
  219. }
  220. }
  221. /**
  222. * 获取当前用户购物车商品总数量(含件数)
  223. * @return int
  224. */
  225. public function getTotalNum()
  226. {
  227. return helper::getArrayColumnSum($this->cart, 'goods_num');
  228. }
  229. /**
  230. * 获取当前用户购物车商品总数量(不含件数)
  231. * @return int
  232. */
  233. public function getGoodsNum()
  234. {
  235. return count($this->cart);
  236. }
  237. /**
  238. * 析构方法
  239. * 将cart数据保存到缓存文件
  240. */
  241. public function __destruct()
  242. {
  243. $this->clear !== true && Cache::set('cart_' . $this->user_id, $this->cart, 86400 * 15);
  244. }
  245. /**
  246. * 清空当前用户购物车
  247. * @param null $cartIds
  248. */
  249. public function clearAll($cartIds = null)
  250. {
  251. if (empty($cartIds)) {
  252. $this->clear = true;
  253. Cache::rm('cart_' . $this->user_id);
  254. } else {
  255. $this->delete($cartIds);
  256. }
  257. }
  258. /**
  259. * 设置错误信息
  260. * @param $error
  261. */
  262. private function setError($error)
  263. {
  264. empty($this->error) && $this->error = $error;
  265. }
  266. /**
  267. * 获取错误信息
  268. * @return string
  269. */
  270. public function getError()
  271. {
  272. return $this->error;
  273. }
  274. }