ShopGoodsService.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. <?php
  2. namespace app\common\service;
  3. use app\common\model\GoodsAttensionModel;
  4. use app\common\model\ShopGoodsModel;
  5. use think\Exception;
  6. use think\facade\Db;
  7. use utils\RedisCache;
  8. /**
  9. * 商品服务 by wes
  10. * Class ShopGoodsService
  11. * @package app\common\service
  12. */
  13. class ShopGoodsService
  14. {
  15. protected static $instance = null;
  16. protected $model = null;
  17. public function __construct()
  18. {
  19. $this->model = new ShopGoodsModel();
  20. }
  21. /**
  22. * 静态化入口
  23. * @return static|null
  24. */
  25. public static function make()
  26. {
  27. if(!self::$instance){
  28. self::$instance = new static();
  29. }
  30. return self::$instance;
  31. }
  32. /**
  33. * 获取列表
  34. * @param $map 分组
  35. * @param $pageSize 分页大小
  36. * @param $field 返回字段
  37. * @param $cache 是否缓存数据,默认是
  38. * @return array|mixed
  39. * @throws \think\db\exception\DataNotFoundException
  40. * @throws \think\db\exception\DbException
  41. * @throws \think\db\exception\ModelNotFoundException
  42. */
  43. public function getList($map, $pageSize=10, $field='', $cache=true)
  44. {
  45. $page = request()->post('page', 1);
  46. $cacheKey = "caches:goods:list_{$page}_{$pageSize}_".md5(json_encode($map, 256).$field);
  47. $list = RedisCache::get($cacheKey);
  48. if($list && $cache){
  49. return $list;
  50. }
  51. $where = ['on_sale'=> 1];
  52. $menuId = isset($map['menu_id'])? intval($map['menu_id']) : 0;
  53. if ($menuId>0){
  54. $where['menu_id'] = $menuId;
  55. }
  56. $keywords = isset($map['keywords'])? trim($map['keywords']) : '';
  57. if (!empty($keywords)) {
  58. $where['goods_name|hot_keywords'] = "%{$map['keywords']}%";
  59. }
  60. $field = $field? $field : 'sort,category,goods_sn,goods_name,goods_img,min_original_price as original_price,min_price as price,rebate_score,sales_volume,inventory,attension_count,restrictions_num';
  61. $order = isset($map['sort']) && $map['sort']? $map['sort'] : 'sort desc,goods_id desc';
  62. $list = $this->model->where($where)
  63. ->where(function($query) use($map){
  64. $cls = isset($map['cls'])? trim($map['cls']) : 0;
  65. if (!empty($cls)) {
  66. $query->where('give_vip','>', 0);
  67. }
  68. })
  69. ->field($field)
  70. ->order($order)
  71. ->paginate($pageSize);
  72. $list = $list? $list->toArray():[];
  73. if($list){
  74. RedisCache::set($cacheKey, $list, rand(10,20));
  75. }
  76. return $list;
  77. }
  78. /**
  79. * 获取开奖福袋商品
  80. * @param int $num
  81. * @return array|mixed
  82. * @throws \think\db\exception\DataNotFoundException
  83. * @throws \think\db\exception\DbException
  84. * @throws \think\db\exception\ModelNotFoundException
  85. */
  86. public function getBoxMatchGoods($boxType, $canOpen=1, $num = 30)
  87. {
  88. $cacheKey = "caches:temp:boxGoods:{$boxType}_{$num}_{$canOpen}";
  89. $data = RedisCache::get($cacheKey);
  90. if($data){
  91. return $data;
  92. }
  93. $data = $this->model->where('box_type', $boxType)
  94. ->where('goods_type', 2)
  95. ->where('can_open', $canOpen)
  96. ->field('goods_id,box_type,goods_img,price,goods_name')
  97. ->limit($num)
  98. ->select();
  99. $data = $data? $data->toArray() : [];
  100. if($data){
  101. RedisCache::set($cacheKey, $data, 86400);
  102. }
  103. return $data;
  104. }
  105. /**
  106. * 获取商品详情
  107. * @param $map
  108. * @return array|mixed
  109. * @throws \think\db\exception\DataNotFoundException
  110. * @throws \think\db\exception\DbException
  111. * @throws \think\db\exception\ModelNotFoundException
  112. */
  113. public function getDetail($map)
  114. {
  115. $where = [];
  116. $goodsSn = isset($map['goods_sn'])? trim($map['goods_sn']) : 0;
  117. $goodsId = isset($map['goods_id'])? intval($map['goods_id']) : 0;
  118. if($goodsSn){
  119. $where['goods_sn'] = $goodsSn;
  120. }
  121. if($goodsId){
  122. $where['goods_id'] = $goodsId;
  123. }
  124. $isCache = false;
  125. $cacheKey = "caches:goods:detail_sn{$goodsSn}_g{$goodsId}";
  126. $info = RedisCache::get($cacheKey);
  127. if(empty($info)){
  128. $field = 'menu_id,spec_name,goods_id,category,goods_sn,goods_name,goods_img,goods_img_banner,goods_remark,min_original_price as original_price,min_price as price,note,inventory,rebate_score,sales_volume,restrictions,rush_buy,buynote_template as buyNote,post_template_id,restrictions_num';
  129. $info = $this->model->where($where)->field($field)->withAttr('goods_img_banner', function ($value) {
  130. return json_decode($value, true) ?: [];
  131. })->withAttr('goods_remark', function ($value) {
  132. return htmlspecialchars_decode($value);
  133. })->withAttr('buyNote', function ($value) {
  134. return htmlspecialchars_decode($value);
  135. })->findOrEmpty()->toArray();
  136. }else{
  137. $isCache = true;
  138. }
  139. if($info){
  140. $specRelation = ShopGoodsSpecRelationService::make()->getDataByGoods($info['goods_id']);
  141. $goodsExpress = ExpressDeliveryService::make()->getDataByTemplate($info['post_template_id']);
  142. $goodsSpec = ShopGoodsSpecService::make()->getListByGoods($info['goods_id']);
  143. $info['expressNote'] = $goodsExpress['remake'] ?: '';
  144. $info['spec_relation'] = $specRelation;
  145. $info['goods_spec'] = $goodsSpec;
  146. $attensionCount = RedisCache::get("caches:goods:attension:{$info['goods_id']}");
  147. if($isCache && $attensionCount>0){
  148. $info['attension_count'] = $attensionCount;
  149. }
  150. RedisCache::set($cacheKey, $info, rand(3,5));
  151. }
  152. return $info;
  153. }
  154. /**
  155. * 更新商品浏览量
  156. * @param $goodsId
  157. * @return false
  158. */
  159. public function updateScanCount($goodsId)
  160. {
  161. if($goodsId && $this->model->where(['goods_id'=> $goodsId])->inc('scan_count',1)->update()){
  162. RedisCache::keyDel('caches:goods:list_*');
  163. return true;
  164. }
  165. return false;
  166. }
  167. /**
  168. * 商品收藏
  169. * @param $uid 用户
  170. * @param $goodsId
  171. * @return bool
  172. * @throws Exception
  173. * @throws \think\db\exception\DataNotFoundException
  174. * @throws \think\db\exception\DbException
  175. * @throws \think\db\exception\ModelNotFoundException
  176. */
  177. public function goodsAttension($uid, $goodsId)
  178. {
  179. $info = $this->model->where(['goods_id'=> $goodsId])->field('goods_id,attension_count')->find();
  180. if(!$info){
  181. throw new Exception('商品不存在');
  182. }
  183. // 是否收藏过
  184. if(GoodsAttensionModel::where(['uid'=> $uid,'goods_id'=> $goodsId])->value('id')){
  185. return true;
  186. }else{
  187. $data = [
  188. 'uid'=> $uid,
  189. 'goods_id'=> $goodsId,
  190. 'create_time'=>sr_getcurtime(time())
  191. ];
  192. Db::startTrans();
  193. if(!GoodsAttensionModel::insertGetId($data)){
  194. Db::rollback();
  195. throw new Exception('收藏失败');
  196. }
  197. if(!$this->model->where(['goods_id'=> $goodsId])->inc('attension_count')->update()){
  198. Db::rollback();
  199. throw new Exception('收藏失败');
  200. }
  201. $attenSionCount = isset($info['attension_count'])? $info['attension_count'] : 0;
  202. RedisCache::set("caches:goods:attension:{$goodsId}", $attenSionCount+1, rand(5, 10));
  203. RedisCache::keyDel('caches:goods:list_*');
  204. Db::commit();
  205. return true;
  206. }
  207. }
  208. /**
  209. * 取消收藏
  210. * @param $uid 用户
  211. * @param $goodsId 商品ID
  212. * @return bool
  213. */
  214. public function cancelAttension($uid, $goodsId)
  215. {
  216. if(!GoodsAttensionModel::where(['uid'=> $uid,'goods_id'=> $goodsId])->value('id')){
  217. return true;
  218. }
  219. Db::startTrans();
  220. if(GoodsAttensionModel::where(['uid'=> $uid,'goods_id'=> $goodsId])->delete()){
  221. RedisCache::keyDel('caches:goods:list_*');
  222. if(!$this->model->where(['goods_id'=> $goodsId])->dec('attension_count')->update()){
  223. Db::rollback();
  224. return false;
  225. }
  226. Db::commit();
  227. RedisCache::keyDel("caches:goods:attension:{$goodsId}");
  228. return true;
  229. }else{
  230. Db::rollback();
  231. return false;
  232. }
  233. }
  234. /**
  235. * 是否收藏过该商品
  236. * @param $uid 用户
  237. * @param $goodsId 商品
  238. * @return bool|mixed
  239. */
  240. public function checkAttension($uid, $goodsId)
  241. {
  242. $cacheKey = "caches:goods:attensionUser:u_{$uid}_g{$goodsId}";
  243. if(RedisCache::get($cacheKey)){
  244. return true;
  245. }
  246. $data = GoodsAttensionModel::where(['uid'=> $uid,'goods_id'=> $goodsId])->value('id');
  247. if($data){
  248. RedisCache::set($cacheKey, $data, rand(5, 10));
  249. }
  250. return $data? true : false;
  251. }
  252. /**
  253. * 获取商品缓存信息
  254. * @param $goodsSn
  255. * @param string $field
  256. * @return array|mixed
  257. * @throws \think\db\exception\DataNotFoundException
  258. * @throws \think\db\exception\DbException
  259. * @throws \think\db\exception\ModelNotFoundException
  260. */
  261. public function getCacheInfo($goodsSn, $field='', $cache=true)
  262. {
  263. $cacheKey = "caches:goods:info_sn{$goodsSn}".($field? '_'.md5($field) : '');
  264. $info = RedisCache::get($cacheKey);
  265. if($info && $cache){
  266. return $info;
  267. }
  268. $field = $field? $field : 'a.goods_id,a.goods_sn,a.post_template_id,a.give_vip,a.goods_type,a.restrictions_num,a.rebate_score,a.goods_name,a.category,a.goods_img,a.supplier,s.name as supplier_name';
  269. $info = $this->model->alias('a')
  270. ->leftJoin('shop_supplier s','s.id = a.supplier')
  271. ->where(['a.goods_sn'=> $goodsSn])
  272. ->field($field)
  273. ->find();
  274. $info = $info? $info->toArray() : [];
  275. if($info && $cache){
  276. RedisCache::set($cacheKey, $info, rand(50, 100));
  277. }
  278. return $info;
  279. }
  280. /**
  281. * 获取商品缓存信息
  282. * @param $goodsId
  283. * @param string $field
  284. * @return array|mixed
  285. * @throws \think\db\exception\DataNotFoundException
  286. * @throws \think\db\exception\DbException
  287. * @throws \think\db\exception\ModelNotFoundException
  288. */
  289. public function getCacheInfoById($goodsId, $field='', $cache=true)
  290. {
  291. $cacheKey = "caches:goods:info_id{$goodsId}".($field? '_'.md5($field) : '');
  292. $info = RedisCache::get($cacheKey);
  293. if($info && $cache){
  294. return $info;
  295. }
  296. $field = $field? $field : 'a.goods_id,a.goods_sn,a.price,a.spec_name,a.post_template_id,a.give_vip,a.goods_type,a.restrictions_num,a.rebate_score,a.goods_name,a.category,a.goods_img,a.supplier,s.name as supplier_name';
  297. $info = $this->model->alias('a')
  298. ->leftJoin('shop_supplier s','s.id = a.supplier')
  299. ->where(['a.goods_id'=> $goodsId])
  300. ->field($field)
  301. ->find();
  302. $info = $info? $info->toArray() : [];
  303. if($info && $cache){
  304. RedisCache::set($cacheKey, $info, rand(50, 100));
  305. }
  306. return $info;
  307. }
  308. /**
  309. * 按编号获取商品列表
  310. * @param $snArr 编号数组
  311. * @param string $field
  312. * @return ShopGoodsModel|array|mixed|\think\Model
  313. */
  314. public function getListBySn($snArr, $field='')
  315. {
  316. $cacheKey = "caches:goods:listSn:".md5(json_encode($snArr, 256).$field);
  317. $data = RedisCache::get($cacheKey);
  318. if($data){
  319. return $data;
  320. }
  321. $field = $field? $field : 'goods_type';
  322. $data = $this->model->whereIn('goods_sn', $snArr)->field($field)->findOrEmpty();
  323. if($data){
  324. $data = $data->toArray();
  325. RedisCache::set($cacheKey, $data, rand(5, 10));
  326. }
  327. return $data;
  328. }
  329. /**
  330. * 福袋商品列表
  331. * @param $boxType 福袋类型,多个类型数组
  332. * @param int $pageSize 分页数
  333. * @param bool $cache
  334. * @return array|mixed
  335. * @throws \think\db\exception\DbException
  336. */
  337. public function getBoxGoodsListByType($boxType, $pageSize=10, $cache=true)
  338. {
  339. $key = is_array($boxType)? implode('_', $boxType) : $boxType;
  340. $cacheKey = "caches:boxGoods:box_{$key}";
  341. $data = RedisCache::get($cacheKey);
  342. if($data && $cache){
  343. return $data;
  344. }
  345. $data = $this->model->where(function($query) use($boxType){
  346. if($boxType){
  347. $boxType = is_array($boxType)? $boxType : [$boxType];
  348. $query->whereIn('box_type', $boxType);
  349. }else{
  350. $query->whereIn('box_type', [10,20,30,40]);
  351. }
  352. })
  353. ->withAttr('box_img', function ($val, $data) {
  354. return getWebUrl() . '.' . $val;
  355. })
  356. ->field('goods_id,box_type,goods_img,price,goods_name,goods_sn')
  357. ->order('box_type', 'desc')
  358. ->paginate($pageSize)
  359. ->toArray();
  360. if($data && $cache){
  361. RedisCache::set($cacheKey, $data, rand(5,10));
  362. }
  363. return $data;
  364. }
  365. }