Goods.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2017~2024 https://www.yiovo.com All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
  8. // +----------------------------------------------------------------------
  9. // | Author: 萤火科技 <admin@yiovo.com>
  10. // +----------------------------------------------------------------------
  11. declare (strict_types=1);
  12. namespace app\common\model;
  13. use cores\BaseModel;
  14. use think\model\relation\BelongsTo;
  15. use think\model\relation\HasMany;
  16. use think\Paginator;
  17. use think\model\Collection;
  18. use think\model\relation\HasOne;
  19. use app\store\model\GoodsCategoryRel as GoodsCategoryRelModel;
  20. use app\common\library\helper;
  21. use app\common\enum\goods\Status as GoodsStatusEnum;
  22. use app\common\enum\order\DeliveryType as DeliveryTypeEnum;
  23. /**
  24. * 商品模型
  25. * Class Goods
  26. * @package app\common\model
  27. */
  28. class Goods extends BaseModel
  29. {
  30. // 定义表名
  31. protected $name = 'goods';
  32. // 定义主键
  33. protected $pk = 'goods_id';
  34. // 追加字段
  35. protected $append = ['goods_sales'];
  36. /**
  37. * 关联模型:主图视频文件
  38. * @return HasOne
  39. */
  40. public function video(): HasOne
  41. {
  42. return $this->hasOne('UploadFile', 'file_id', 'video_id');
  43. }
  44. /**
  45. * 关联模型:主图视频封面图片文件
  46. * @return HasOne
  47. */
  48. public function videoCover(): HasOne
  49. {
  50. return $this->hasOne('UploadFile', 'file_id', 'video_cover_id');
  51. }
  52. /**
  53. * 计算显示销量 (初始销量 + 实际销量)
  54. * @param $value
  55. * @param $data
  56. * @return mixed
  57. */
  58. public function getGoodsSalesAttr($value, $data)
  59. {
  60. return $data['sales_initial'] + $data['sales_actual'];
  61. }
  62. /**
  63. * 商品详情:HTML实体转换回普通字符
  64. * @param $value
  65. * @return string
  66. */
  67. public function getContentAttr($value): string
  68. {
  69. return htmlspecialchars_decode($value);
  70. }
  71. /**
  72. * 获取器:单独设置折扣的配置
  73. * @param $json
  74. * @return mixed
  75. */
  76. public function getAloneGradeEquityAttr($json)
  77. {
  78. return helper::jsonDecode($json);
  79. }
  80. /**
  81. * 获取器:商品配送方式
  82. * 如果配送方式为空,默认返回所有配送方式(用于后台商品管理时默认选中)
  83. * @param $json
  84. * @return mixed
  85. */
  86. public function getDeliveryTypeAttr($json)
  87. {
  88. $values = helper::jsonDecode($json);
  89. return $values ?: array_keys(DeliveryTypeEnum::data());
  90. }
  91. /**
  92. * 修改器:单独设置折扣的配置
  93. * @param $data
  94. * @return false|string
  95. */
  96. public function setAloneGradeEquityAttr($data)
  97. {
  98. return helper::jsonEncode($data);
  99. }
  100. /**
  101. * 修改器:商品配送方式
  102. * @param $data
  103. * @return false|string
  104. */
  105. public function setDeliveryTypeAttr($data)
  106. {
  107. return helper::jsonEncode($data);
  108. }
  109. /**
  110. * 关联商品规格表
  111. * @return HasMany
  112. */
  113. public function skuList(): HasMany
  114. {
  115. return $this->hasMany('GoodsSku')->order(['id' => 'asc']);
  116. }
  117. /**
  118. * 关联商品规格关系表
  119. * @return HasMany
  120. */
  121. public function specRel(): HasMany
  122. {
  123. return $this->hasMany('GoodsSpecRel');
  124. }
  125. /**
  126. * 关联商品图片表
  127. * @return HasMany
  128. */
  129. public function images(): HasMany
  130. {
  131. return $this->hasMany('GoodsImage')->order(['id']);
  132. }
  133. /**
  134. * 关联运费模板表
  135. * @return BelongsTo
  136. */
  137. public function delivery(): BelongsTo
  138. {
  139. return $this->BelongsTo('Delivery');
  140. }
  141. /**
  142. * 关联订单评价表
  143. * @return HasMany
  144. */
  145. public function commentData(): HasMany
  146. {
  147. return $this->hasMany('Comment');
  148. }
  149. /**
  150. * 获取商品列表
  151. * @param array $param 查询条件
  152. * @param int $listRows 分页数量
  153. * @return mixed
  154. * @throws \think\db\exception\DbException
  155. */
  156. public function getList(array $param = [], int $listRows = 15)
  157. {
  158. // 筛选条件
  159. $query = $this->getQueryFilter($param);
  160. // 设置显示的销量 goods_sales
  161. $query->field(['(sales_initial + sales_actual) as goods_sales']);
  162. // 排序条件
  163. $sort = $this->setQuerySort($param);
  164. // 执行查询
  165. $list = $query->with(['images.file'])
  166. ->alias($this->name)
  167. ->field($this->getAliasFields($this->name, ['content']))
  168. ->where('is_delete', '=', 0)
  169. ->order($sort)
  170. ->paginate($listRows);
  171. // 整理列表数据并返回
  172. return $this->setGoodsListData($list);
  173. }
  174. /**
  175. * 检索排序条件
  176. * @param array $param
  177. * @return array|string[]
  178. */
  179. private function setQuerySort(array $param = []): array
  180. {
  181. $params = $this->setQueryDefaultValue($param, [
  182. 'sortType' => 'all', // 排序类型 (all默认 sales销量 price价格)
  183. 'sortPrice' => false, // 价格排序 (true高到低 false低到高)
  184. ]);
  185. // 排序规则
  186. $sort = [];
  187. if ($params['sortType'] === 'all') {
  188. $sort = ['sort' => 'asc'];
  189. } elseif ($params['sortType'] === 'sales') {
  190. $sort = ['goods_sales' => 'desc'];
  191. } elseif ($params['sortType'] === 'price') {
  192. $sort = $params['sortPrice'] ? ['goods_price_max' => 'desc'] : ['goods_price_min' => 'asc'];
  193. }
  194. return array_merge($sort, [$this->getPk() => 'desc']);
  195. }
  196. /**
  197. * 检索查询条件
  198. * @param array $param
  199. * @return \think\db\BaseQuery
  200. */
  201. private function getQueryFilter(array $param): \think\db\BaseQuery
  202. {
  203. // 商品列表获取条件
  204. $params = $this->setQueryDefaultValue($param, [
  205. 'listType' => 'all', // 列表模式 (全部:all 出售中:on_sale 已下架:off_sale 已售罄:sold_out)
  206. 'categoryId' => null, // 商品分类ID
  207. 'goodsName' => null, // 商品名称
  208. 'goodsNo' => null, // 商品编码
  209. 'status' => 0, // 商品状态(0全部 10上架 20下架)
  210. ]);
  211. // 实例化新查询对象
  212. $query = $this->getNewQuery();
  213. // 筛选条件
  214. $filter = [];
  215. // 列表模式
  216. if ($params['listType'] === 'on_sale') {
  217. $filter[] = ['status', '=', GoodsStatusEnum::ON_SALE]; // 出售中
  218. } elseif ($params['listType'] === 'off_sale') {
  219. $filter[] = ['status', '=', GoodsStatusEnum::OFF_SALE]; // 已下架
  220. } elseif ($params['listType'] === 'sold_out') {
  221. $filter[] = ['stock_total', '=', 0]; // 已售罄
  222. }
  223. // 商品状态
  224. $params['status'] > 0 && $filter[] = ['status', '=', (int)$params['status']];
  225. // 商品分类
  226. if ($params['categoryId'] > 0) {
  227. // 关联商品与分类关系记录表
  228. $GoodsCategoryRelName = (new GoodsCategoryRelModel)->getName();
  229. $query->join($GoodsCategoryRelName, "{$GoodsCategoryRelName}.goods_id = {$this->name}.goods_id");
  230. // 设置分类ID条件
  231. $query->where('goods_category_rel.category_id', '=', (int)$params['categoryId']);
  232. }
  233. // 商品名称
  234. !empty($params['goodsName']) && $filter[] = ['goods_name', 'like', "%{$params['goodsName']}%"];
  235. // 商品编码
  236. !empty($params['goodsNo']) && $filter[] = ['goods_no', 'like', "%{$params['goodsNo']}%"];
  237. // 实例化新查询对象
  238. return $query->where($filter);
  239. }
  240. /**
  241. * 设置商品展示的数据
  242. * @param Collection|Paginator $list 商品列表
  243. * @param callable|null $callback 回调函数
  244. * @return mixed
  245. */
  246. protected function setGoodsListData($list, callable $callback = null)
  247. {
  248. if ($list->isEmpty()) return $list;
  249. // 遍历商品列表整理数据
  250. foreach ($list as &$goods) {
  251. $goods = $this->setGoodsData($goods, $callback);
  252. }
  253. return $list;
  254. }
  255. /**
  256. * 整理商品数据
  257. * @param Collection|static $goodsInfo
  258. * @param callable|null $callback
  259. * @return mixed
  260. */
  261. protected function setGoodsData($goodsInfo, callable $callback = null)
  262. {
  263. // 商品图片列表
  264. $goodsInfo['goods_images'] = helper::getArrayColumn($goodsInfo['images'], 'file');
  265. // 商品主图
  266. $goodsInfo['goods_image'] = current($goodsInfo['goods_images'])['preview_url'];
  267. // 商品销量(实际显示=初始虚拟销量+实际销量)
  268. $goodsInfo['goods_sales'] = $goodsInfo['sales_initial'] + $goodsInfo['sales_actual'];
  269. // 回调函数
  270. is_callable($callback) && call_user_func($callback, $goodsInfo);
  271. return $goodsInfo;
  272. }
  273. /**
  274. * 根据商品id集获取商品列表
  275. * @param array $goodsIds
  276. * @param null $status
  277. * @return array|mixed
  278. */
  279. public function getListByIds(array $goodsIds, $status = null)
  280. {
  281. // 筛选条件
  282. $filter = [['goods_id', 'in', $goodsIds]];
  283. // 商品状态
  284. $status > 0 && $filter[] = ['status', '=', $status];
  285. // 获取商品列表数据
  286. $data = $this->withoutField(['content'])
  287. ->with(['images.file'])
  288. ->where($filter)
  289. ->where('is_delete', '=', 0)
  290. ->orderRaw('field(goods_id, ' . implode(',', $goodsIds) . ')')
  291. ->select();
  292. // 整理列表数据并返回
  293. return $this->setGoodsListData($data);
  294. }
  295. /**
  296. * 获取商品记录
  297. * @param int $goodsId
  298. * @param array $with
  299. * @return static|array|null
  300. */
  301. public static function detail(int $goodsId, array $with = [])
  302. {
  303. return static::get($goodsId, $with);
  304. }
  305. }