Goods.php 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2017~2021 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 app\common\enum\goods\GoodsType;
  14. use think\model\relation\BelongsTo;
  15. use think\Paginator;
  16. use think\model\Collection;
  17. use app\common\library\helper;
  18. use app\store\model\GoodsCategoryRel as GoodsCategoryRelModel;
  19. use app\common\enum\goods\Status as GoodsStatusEnum;
  20. use app\common\model\chef\ChefAreas as RegionModel;
  21. use app\common\model\store\Setting as SettingModel;
  22. use app\api\service\User as UserService;
  23. use think\facade\Db;
  24. /**
  25. * 商品模型
  26. * Class Goods
  27. * @package app\common\model
  28. */
  29. class Goods extends BaseModel
  30. {
  31. // 定义表名
  32. protected $name = 'goods';
  33. // 定义主键
  34. protected $pk = 'goods_id';
  35. // 追加字段
  36. protected $append = ['goods_sales','province_text','city_text','region_text', 'category_name','cascader'];
  37. const PACKAGETYPE = 30;
  38. // const UNIT = [
  39. // 1 => '件',
  40. // 2 => '盒',
  41. // 3 => '包',
  42. // 4 => '份',
  43. // 5 => '箱',
  44. // 6 => '袋',
  45. // 7 => '斤',
  46. // 8 => '桶',
  47. // 9 => '瓶',
  48. // 10 => '罐',
  49. // 11 => '个',
  50. // ];
  51. /**
  52. * 省市区id集
  53. * @param $value
  54. * @param $data
  55. * @return array
  56. */
  57. public function getCascaderAttr($value, $data)
  58. {
  59. return [$data['province_id']??0, $data['city_id']??0, $data['region_id']??0];
  60. }
  61. /**
  62. * 计算显示销量 (初始销量 + 实际销量 + 门店销量)
  63. * @param $value
  64. * @param $data
  65. * @return mixed
  66. */
  67. public function getGoodsSalesAttr($value, $data)
  68. {
  69. return ($data['sales_initial']??0) + ($data['sales_actual']??0) + ($data['sales_shops']??0);
  70. }
  71. /**
  72. * Notes:产地:省份
  73. * Author: zhangs
  74. * DateTime: 2021/9/24 14:20
  75. * @param $value
  76. * @param $data
  77. * @return mixed
  78. */
  79. public function getProvinceTextAttr($value, $data)
  80. {
  81. if (empty($data['province_id'])) return '';
  82. return RegionModel::getNameById($data['province_id'] ?? 0);
  83. }
  84. /**
  85. * Notes:产地:城市
  86. * Author: zhangs
  87. * DateTime: 2021/9/24 14:21
  88. * @param $value
  89. * @param $data
  90. * @return mixed
  91. */
  92. public function getCityTextAttr($value, $data)
  93. {
  94. if (empty($data['city_id'])) return '';
  95. return RegionModel::getNameById($data['city_id'] ?? 0);
  96. }
  97. /**
  98. * Notes:产地:地区
  99. * Author: zhangs
  100. * DateTime: 2021/9/24 14:21
  101. * @param $value
  102. * @param $data
  103. * @return mixed
  104. */
  105. public function getRegionTextAttr($value, $data)
  106. {
  107. if (empty($data['region_id'])) return '';
  108. return RegionModel::getNameById($data['region_id'] ?? 0);
  109. }
  110. /**
  111. * Notes:商品分类名称
  112. * Author: zhangs
  113. * DateTime: 2021/9/24 16:41
  114. * @param $value
  115. * @param $data
  116. * @return string
  117. */
  118. public function getCategoryNameAttr($value, $data)
  119. {
  120. if(isset($data['goods_id'])){
  121. $category_ids = GoodsCategoryRel::where('goods_id', '=', $data['goods_id'])->column('category_id');
  122. if (empty($category_ids)) {
  123. return '';
  124. }
  125. $names = Category::whereIn('category_id', $category_ids)->column('name');
  126. return $names ? implode(',', $names) : '';
  127. }
  128. }
  129. /**
  130. * 商品详情:HTML实体转换回普通字符
  131. * @param $value
  132. * @return string
  133. */
  134. public function getContentAttr($value)
  135. {
  136. return htmlspecialchars_decode($value);
  137. }
  138. /**
  139. * 获取器:单独设置折扣的配置
  140. * @param $json
  141. * @return mixed
  142. */
  143. public function getAloneGradeEquityAttr($json)
  144. {
  145. return helper::jsonDecode($json);
  146. }
  147. /**
  148. * 修改器:单独设置折扣的配置
  149. * @param $data
  150. * @return mixed
  151. */
  152. public function setAloneGradeEquityAttr($data)
  153. {
  154. return helper::jsonEncode($data);
  155. }
  156. /**
  157. * 关联商品规格表
  158. * @return \think\model\relation\HasMany
  159. */
  160. public function skuList()
  161. {
  162. return $this->hasMany('GoodsSku')->order(['id' => 'asc']);
  163. }
  164. /**
  165. *
  166. * @return \think\model\relation\HasMany
  167. * @author: zjwhust
  168. * @Time: 2021/12/28 15:43
  169. */
  170. public function category()
  171. {
  172. return $this->hasOne('GoodsCategoryRel','goods_id','goods_id');
  173. }
  174. /**
  175. * 关联商品规格关系表
  176. * @return \think\model\relation\HasMany
  177. */
  178. public function specRel()
  179. {
  180. return $this->hasMany('GoodsSpecRel');
  181. }
  182. /**
  183. * 关联商品图片表
  184. * @return \think\model\relation\HasMany
  185. */
  186. public function images()
  187. {
  188. return $this->hasMany('GoodsImage')->order(['id']);
  189. }
  190. /**
  191. * 关联运费模板表
  192. * @return BelongsTo
  193. */
  194. public function delivery()
  195. {
  196. return $this->belongsTo('Delivery');
  197. }
  198. /**
  199. * 关联订单评价表
  200. * @return \think\model\relation\HasMany
  201. */
  202. public function commentData()
  203. {
  204. return $this->hasMany('Comment');
  205. }
  206. /**
  207. * 关联供应商表/商铺
  208. * @return BelongsTo
  209. */
  210. public function provider()
  211. {
  212. return $this->belongsTo(Provider::class, 'provider_id', 'provider_id');
  213. }
  214. /**
  215. * 获取商品列表
  216. * @param array $param 查询条件
  217. * @param int $listRows 分页数量
  218. * @param bool $showVip 会员商品列表
  219. * @return mixed
  220. * @throws \think\db\exception\DbException
  221. */
  222. public function getList(array $param = [], int $listRows = 15,bool $showVip = false)
  223. {
  224. // 筛选条件
  225. $query = $this->getQueryFilter($param);
  226. // 设置显示的销量 goods_sales
  227. // 购买数*1.5+加入购物车数+收藏数*0.8)之和排倒序
  228. $query->field(['(sales_initial + sales_actual) as online_sales','(sales_initial + sales_actual + sales_shops) as goods_sales','(shops_stock_total+stock_total) as goods_stocks','(collect_num*0.8+cart_num+(sales_initial+sales_actual)*1.5) as common_sort']);
  229. // 排序条件
  230. //$sort = $this->setQuerySort($param);
  231. $sort = $this->setQuerySortZq($param);
  232. //dd($sort);
  233. // 执行查询
  234. $list = $query->with(['images.file','provider'])
  235. ->alias($this->name);
  236. if ($showVip){
  237. $list = $list->whereExists('select id from yoshop_member_goods where goods_id=goods.goods_id and status=0');
  238. }
  239. $list = $list->field($this->getAliasFields($this->name, ['content']))
  240. ->where('is_delete', '=', 0)
  241. ->order($sort)
  242. ->paginate($listRows);
  243. // 整理列表数据并返回
  244. return $this->setGoodsListData($list);
  245. }
  246. /**
  247. * 获取商品列表
  248. * @param array $param 查询条件
  249. * @param int $listRows 分页数量
  250. * @param bool $showVip 会员商品列表
  251. * @param bool $enableExchange 我能兑换
  252. * @param string $userPonitsMoney 我能兑换
  253. * @return mixed
  254. * @throws \think\db\exception\DbException
  255. */
  256. public function getListFront(array $param = [], int $listRows = 15,bool $showVip = false,$enableExchange = false)
  257. {
  258. // 筛选条件
  259. $query = $this->getQueryFilter($param);
  260. // 设置显示的销量 goods_sales
  261. // 购买数*1.5+加入购物车数+收藏数*0.8)之和排倒序
  262. $query->field(['(sales_initial + sales_actual) as online_sales','(sales_initial + sales_actual + sales_shops) as goods_sales','(shops_stock_total+stock_total) as goods_stocks','(collect_num*0.8+cart_num+(sales_initial+sales_actual)*1.5) as common_sort']);
  263. // 排序条件
  264. //$sort = $this->setQuerySort($param);
  265. $sort = $this->setQuerySortZq($param);
  266. //dd($sort);
  267. // 执行查询
  268. $list = $query->with(['images.file','provider'])
  269. ->alias($this->name);
  270. if ($showVip){
  271. $list = $list->whereExists('select id from yoshop_member_goods where goods_id=goods.goods_id and status=0');
  272. }
  273. if ($enableExchange){
  274. $user = UserService::getCurrentLoginUser();
  275. $rate = SettingModel::getItem('points_rate')['points_2_money'];
  276. //dd($rate);
  277. $pointsToMoney = bcdiv(strval($user['accumulate_points']), $rate, 2);
  278. $list = $list->where('goods_price_min','<',$pointsToMoney);
  279. }
  280. $list = $list->field($this->getAliasFields($this->name, ['content']))
  281. ->where('is_delete', '=', 0)
  282. ->where('is_show', '=', 1)
  283. ->order($sort)
  284. ->paginate($listRows);
  285. // 整理列表数据并返回
  286. return $this->setGoodsListData($list);
  287. }
  288. /**
  289. * 检索排序条件
  290. * @param array $param
  291. * @return array|string[]
  292. */
  293. private function setQuerySort(array $param = [])
  294. {
  295. $params = $this->setQueryDefaultValue($param, [
  296. 'sortType' => 'all', // 排序类型
  297. 'sortPrice' => false, // 价格排序 (true高到低 false低到高)
  298. ]);
  299. // 排序规则
  300. $sort = [];
  301. if ($params['sortType'] === 'all') {
  302. $sort = ['common_sort' => 'desc'];
  303. } elseif ($params['sortType'] === 'sales') {
  304. $sort = ['goods_sales' => 'desc'];
  305. } elseif ($params['sortType'] === 'price') {
  306. $sort = $params['sortPrice'] ? ['goods_price_max' => 'desc'] : ['goods_price_min' => 'asc'];
  307. } elseif ($params['sortType'] == 'create_time') { // 按上架时间倒序
  308. $sort = ['create_time' => 'desc'];
  309. }
  310. return array_merge($sort, [$this->getPk() => 'desc']);
  311. }
  312. /**
  313. * 检索排序条件
  314. * @param array $param
  315. * @return array|string[]
  316. */
  317. private function setQuerySortZq(array $param = [])
  318. {
  319. $params = $this->setQueryDefaultValue($param, [
  320. 'sortStyle' => 'all', // 排序类型
  321. 'sortSort' => false, // 价格排序 (true高到低 false低到高)
  322. ]);
  323. // 排序规则
  324. $sort = [];
  325. $sortSort = ($params['sortSort'] == 'false' || !$params['sortSort'])?false:true;
  326. if ($params['sortStyle'] == 'all') {//综合
  327. $sort = $sortSort ?['goods_sales' => 'desc']:['goods_sales' => 'asc'];
  328. } elseif ($params['sortStyle'] == 'sales') {
  329. $sort = $sortSort ?['goods_sales' => 'desc']:['goods_sales' => 'asc'];
  330. } elseif ($params['sortStyle'] == 'price') {
  331. $sort = $sortSort ? ['goods_price_max' => 'desc'] : ['goods_price_min' => 'asc'];
  332. } elseif ($params['sortStyle'] == 'create_time') { // 按上架时间倒序
  333. $sort = $sortSort ? ['create_time' => 'desc'] : ['create_time' => 'asc'];
  334. }
  335. return array_merge($sort, [$this->getPk() => 'desc']);
  336. }
  337. /**
  338. * 检索查询条件
  339. * @param array $param
  340. * @return \think\db\BaseQuery
  341. */
  342. private function getQueryFilter(array $param)
  343. {
  344. // 商品列表获取条件
  345. $params = $this->setQueryDefaultValue($param, [
  346. 'listType' => 'all', // 列表模式 (全部:all 出售中:on_sale 已下架:off_sale 已售罄:sold_out)
  347. 'categoryId' => null, // 分类ID集
  348. 'goodsName' => null, // 商品名称
  349. 'goodsNo' => null, // 商品编码
  350. 'status' => 0, // 商品状态(0全部 10上架 20下架)
  351. 'have_stock' => 0, // 是否查找有库存商品
  352. 'stock_status' => -1, // 库存状态 0-预警 1-正常
  353. 'spec_type'=>0
  354. ]);
  355. // 实例化新查询对象
  356. $query = $this->getNewQuery();
  357. // 筛选条件
  358. $filter = [];
  359. // 列表模式
  360. if ($params['listType'] === 'on_sale') {
  361. $filter[] = ['status', '=', GoodsStatusEnum::ON_SALE]; // 出售中
  362. } elseif ($params['listType'] === 'off_sale') {
  363. $filter[] = ['status', '=', GoodsStatusEnum::OFF_SALE]; // 已下架
  364. } elseif ($params['listType'] === 'sold_out') {
  365. $filter[] = ['stock_total', '=', 0]; // 已售罄
  366. }
  367. if(!empty($params['not_goods_id_arr'])){
  368. $filter[] = ['goods.goods_id','not in',$params['not_goods_id_arr']];
  369. }
  370. if(!empty($params['spec_type'])){
  371. $filter[] = ['spec_type','=',$params['spec_type']];
  372. }
  373. if(isset($params['goods_id_arr'])){
  374. $filter[] = ['goods_id','in',$params['goods_id_arr']];
  375. }
  376. // 起止时间
  377. if (!empty($params['betweenTime'])) {
  378. $times = between_time($params['betweenTime']);
  379. $filter[] = ['goods.create_time', '>=', $times['start_time']];
  380. $filter[] = ['goods.create_time', '<', $times['end_time'] + 86400];
  381. }
  382. if (isset($params['stock_status']) && $params['stock_status'] != -1) { // 库存预警
  383. $filter[] = ['status', '=', GoodsStatusEnum::ON_SALE]; // 出售中
  384. $filterSku[] = ['stock_num', 'exp', Db::raw('< `alarm_stock_num`')];
  385. $goodsIds = GoodsSku::where($filterSku)->column('goods_id');
  386. if ($params['stock_status'] == 1) {
  387. if (!empty($goodsIds)) {
  388. $filter[] = ['goods_id', 'not in', $goodsIds];
  389. }
  390. } else {
  391. $filter[] = ['goods_id', 'in', $goodsIds];
  392. }
  393. }
  394. // 商品状态
  395. $params['status'] > 0 && $filter[] = ['status', '=', (int)$params['status']];
  396. $params['have_stock'] > 0 && $filter[] = ['stock_total', '>', 0]; // 有库存
  397. // 商品分类
  398. if ($params['categoryId'] > 0) {
  399. // 关联商品与分类关系记录表
  400. $GoodsCategoryRelName = (new GoodsCategoryRelModel)->getName();
  401. $query->join($GoodsCategoryRelName, "{$GoodsCategoryRelName}.goods_id = {$this->name}.goods_id");
  402. // 设置分类ID条件
  403. $query->where('goods_category_rel.category_id', '=', (int)$params['categoryId']);
  404. }
  405. // 商品名称
  406. !empty($params['goodsName']) && $filter[] = ['goods_name', 'like', "%{$params['goodsName']}%"];
  407. // 商品编码
  408. !empty($params['goodsNo']) && $filter[] = ['goods_no', 'like', "%{$params['goodsNo']}%"];
  409. //普通商品还是赠品
  410. //in_array($params['goods_type'],[10,20]) && $filter[] = ['goods_type','=',$params['goods_type']];
  411. if(isset($params['goods_type']) && ($params['goods_type'] == GoodsType::GIFT || $params['goods_type'] == GoodsType::NORMAL)){
  412. $filter[] = ['goods_type','=',$params['goods_type']];
  413. $filter[] = ['stock_total','>',0];
  414. }elseif(isset($params['goods_type']) && $params['goods_type'] == 90){
  415. //需要单规格的商品或赠品
  416. $filter[] = ['goods_type','<',GoodsType::MULTI];
  417. $filter[] = ['stock_total','>',0];
  418. }elseif(isset($params['goods_type']) && $params['goods_type'] == GoodsType::EXCHANGE){
  419. //积分兑换商品
  420. $filter[] = ['goods_type','=',GoodsType::EXCHANGE];
  421. $filter[] = ['stock_total','>',0];
  422. }else{
  423. if (isset($params['is_backend']) && $params['is_backend'] == 1){
  424. }else{
  425. $filter[] = ['goods_type','<>',GoodsType::GIFT];
  426. }
  427. }
  428. // // 是否显示在商品列表
  429. // $filter[] = ['display', '=', 1]; // 可以显示的
  430. // 实例化新查询对象
  431. return $query->where($filter);
  432. }
  433. /**
  434. * 设置商品展示的数据
  435. * @param Collection|Paginator $list 商品列表
  436. * @param callable|null $callback 回调函数
  437. * @return mixed
  438. */
  439. protected function setGoodsListData($list, callable $callback = null)
  440. {
  441. if ($list->isEmpty()) return $list;
  442. // 遍历商品列表整理数据
  443. foreach ($list as &$goods) {
  444. $goods = $this->setGoodsData($goods, $callback);
  445. }
  446. return $list;
  447. }
  448. /**
  449. * 设置商品展示的结算价格列表
  450. * @param Collection|Paginator $list 商品列表
  451. * @param callable|null $callback 回调函数
  452. * @return mixed
  453. */
  454. protected function setGoodsListDataFinance($list, callable $callback = null)
  455. {
  456. if ($list->isEmpty()) return $list;
  457. // 遍历商品列表整理数据
  458. foreach ($list as &$goods) {
  459. $goods = $this->setGoodsData($goods, $callback);
  460. $goodsArr = $goods->toArray();
  461. $clearing_price_arr = array_column($goodsArr['skues'],'clearing_price');
  462. //dd($clearing_price_arr);
  463. if (count($clearing_price_arr) == 0){
  464. $goods['clearing_price_range'] = '';
  465. } elseif (count($clearing_price_arr) == 1){
  466. $goods['clearing_price_range'] = (string)$clearing_price_arr[0];
  467. }else{
  468. $clearing_price_arr = array_unique($clearing_price_arr);
  469. asort($clearing_price_arr);
  470. $clearing_price_arr = array_values($clearing_price_arr);
  471. $goods['clearing_price_range'] = $clearing_price_arr[0].'~'.$clearing_price_arr[count($clearing_price_arr)-1];
  472. }
  473. $rate_arr = array_column($goodsArr['skues'],'platform_rate');
  474. if (count($rate_arr) == 0){
  475. $goods['platform_rate_range'] = '';
  476. } elseif (count($rate_arr) == 1){
  477. $goods['platform_rate_range'] = (string)$rate_arr[0];
  478. }else{
  479. $rate_arr = array_unique($rate_arr);
  480. asort($rate_arr);
  481. $rate_arr = array_values($rate_arr);
  482. $goods['platform_rate_range'] = $rate_arr[0].'~'.$rate_arr[count($rate_arr)-1];
  483. }
  484. }
  485. return $list;
  486. }
  487. /**
  488. * 整理商品数据
  489. * @param Collection|static $goodsInfo
  490. * @param callable|null $callback
  491. * @return mixed
  492. */
  493. protected function setGoodsData($goodsInfo, callable $callback = null)
  494. {
  495. // 商品图片列表
  496. $goodsInfo['goods_images'] = helper::getArrayColumn($goodsInfo['images'], 'file');
  497. $goodsImages = [];
  498. if (!empty($goodsInfo['goods_images'])) {
  499. foreach ($goodsInfo['goods_images'] as $item) {
  500. $item = $item->toArray();
  501. $item['preview_url'] = config('chef.sso_domain_text').$item['file_path'];
  502. $item['external_url'] = config('chef.sso_domain_text').$item['file_path'];
  503. $goodsImages[] = $item;
  504. }
  505. }
  506. $goodsInfo['goods_images'] = $goodsImages;
  507. // 商品主图
  508. $goodsInfo['goods_image'] = current($goodsInfo['goods_images'])['preview_url'];
  509. // 商品主图 生成海报用
  510. $goodsInfo['goods_image_text'] = current($goodsInfo['goods_images'])['preview_url'];
  511. // 商品销量(实际显示=初始虚拟销量+实际销量)
  512. $goodsInfo['goods_sales'] = $goodsInfo['sales_initial'] + $goodsInfo['sales_actual'];
  513. // 商品库存(总库存=线上库存+门店库存)
  514. $goodsInfo['goods_stocks'] = $goodsInfo['stock_total'] + $goodsInfo['shops_stock_total'];
  515. // 回调函数
  516. is_callable($callback) && call_user_func($callback, $goodsInfo);
  517. return $goodsInfo->hidden(array_merge($this->hidden, ['specRel', 'images']));
  518. }
  519. /**
  520. * 根据商品id集获取商品列表
  521. * @param array $goodsIds
  522. * @param null $status
  523. * @return array|mixed
  524. */
  525. public function getListByIds(array $goodsIds, $status = null)
  526. {
  527. if (empty($goodsIds)) {
  528. return [];
  529. }
  530. // 筛选条件
  531. $filter = [['goods_id', 'in', $goodsIds]];
  532. // 商品状态
  533. $status > 0 && $filter[] = ['status', '=', $status];
  534. // 获取商品列表数据
  535. $data = $this
  536. // ->withoutField(['content'])
  537. ->with(['images.file','category'])
  538. ->where($filter)
  539. ->where('is_delete', '=', 0)
  540. ->orderRaw('field(goods_id, ' . implode(',', $goodsIds) . ')')
  541. ->select();
  542. // 整理列表数据并返回
  543. return $this->setGoodsListData($data);
  544. }
  545. /**
  546. * 商品多规格信息
  547. * @param \think\Collection $specRel
  548. * @param \think\Collection $skuData
  549. * @return array
  550. */
  551. public function getManySpecData($specRel, $skuData)
  552. {
  553. // spec_attr
  554. $specAttrData = [];
  555. foreach ($specRel as $item) {
  556. if (!isset($specAttrData[$item['spec_id']])) {
  557. $specAttrData[$item['spec_id']] = [
  558. 'group_id' => $item['spec']['spec_id'],
  559. 'name' => $item['spec']['spec_name'],
  560. 'spec_items' => [],
  561. ];
  562. }
  563. $specAttrData[$item['spec_id']]['spec_items'][] = [
  564. 'item_id' => $item['spec_value_id'],
  565. 'spec_value' => $item['spec_value'],
  566. ];
  567. }
  568. // spec_list
  569. $specListData = [];
  570. foreach ($skuData as $item) {
  571. $image = (isset($item['images']) && !empty($item['images'])) ? $item['images'] : ['file_id' => 0, 'external_url' => ''];
  572. $specListData[] = [
  573. 'id' => $item['id'],
  574. 'goods_sku_id' => $item['goods_sku_id'],
  575. 'rows' => [],
  576. 'form' => [
  577. 'image_id' => $image['file_id'],
  578. 'image_path' => $image['external_url'],
  579. 'goods_sku_no' => $item['goods_sku_no'],
  580. 'goods_price' => $item['goods_price'],
  581. 'goods_weight' => $item['goods_weight'],
  582. 'line_price' => $item['line_price'],
  583. 'stock_num' => $item['stock_num'],
  584. ],
  585. ];
  586. }
  587. return ['spec_attr' => array_values($specAttrData), 'spec_list' => $specListData];
  588. }
  589. /**
  590. * 获取商品记录
  591. * @param int $goodsId
  592. * @param array $with
  593. * @return static
  594. */
  595. public static function detail(int $goodsId, array $with = [])
  596. {
  597. return static::get($goodsId, $with);
  598. }
  599. /**
  600. * 累积收藏数
  601. * @param int $goodsId 商品ID
  602. * @param int $num 递增的数量
  603. * @return mixed
  604. */
  605. public static function setIncByField(int $goodsId, $field = '', int $num = 1)
  606. {
  607. return (new static)->setInc([['goods_id', '=', $goodsId]], $field, $num);
  608. }
  609. /**
  610. * 累积收藏数
  611. * @param int $goodsId 商品ID
  612. * @param int $num 递减的数量
  613. * @return mixed
  614. */
  615. public static function setDecByField(int $goodsId, $field = '', int $num = 1)
  616. {
  617. return (new static)->setDec([['goods_id', '=', $goodsId]], $field, $num);
  618. }
  619. // /**
  620. // * 指定的商品规格信息
  621. // * @param static $goods 商品详情
  622. // * @param string $goodsSkuId
  623. // * @return array|bool
  624. // */
  625. // public static function getGoodsSku(self $goods, string $goodsSkuId)
  626. // {
  627. // // 获取指定的sku
  628. // $goodsSku = [];
  629. // foreach ($goods['skuList'] as $item) {
  630. // if ($item['goods_sku_id'] == $goodsSkuId) {
  631. // $goodsSku = $item;
  632. // break;
  633. // }
  634. // }
  635. // if (empty($goodsSku)) {
  636. // return false;
  637. // }
  638. // // 多规格文字内容
  639. // $goodsSku['goods_attr'] = '';
  640. // if ($goods['spec_type'] == 20) {
  641. // $specRelData = helper::arrayColumn2Key($goods['spec_rel'], 'spec_value_id');
  642. // $attrs = explode('_', $goodsSku['goods_sku_id']);
  643. // foreach ($attrs as $specValueId) {
  644. // $goodsSku['goods_attr'] .= $specRelData[$specValueId]['spec']['spec_name'] . ':'
  645. // . $specRelData[$specValueId]['spec_value'] . '; ';
  646. // }
  647. // }
  648. // return $goodsSku;
  649. // }
  650. public function getCostsList(array $param = [], int $listRows = 15)
  651. {
  652. // 筛选条件
  653. $query = $this->getQueryFilter($param);
  654. // 排序条件
  655. //$sort = $this->setQuerySort($param);
  656. // 执行查询
  657. $list = $query->with(['provider','skues'])
  658. ->alias($this->name)
  659. ->field($this->getAliasFields($this->name, ['content']))
  660. ->where('is_delete', '=', 0)
  661. ->paginate($listRows);
  662. // 整理列表数据并返回
  663. return $this->setGoodsListDataFinance($list);
  664. }
  665. /**
  666. * 关联供应商表/商铺
  667. * @return \think\model\relation\HasMany
  668. */
  669. public function skues()
  670. {
  671. return $this->hasMany(\app\store\model\GoodsSku::class, 'goods_id', 'goods_id')->field('id,goods_id,clearing_price,platform_rate,goods_props');
  672. }
  673. /**
  674. * 导出提现列表
  675. * @param array $param
  676. * @author: zq
  677. * @Time: 2021/10/15 13:51
  678. */
  679. public function listExport(array $param)
  680. {
  681. //$ids = $param['goods_id'];
  682. $data['header'] = ['商品序号', '商品编码', '商品名称', '供应商名称', '商品分类','售价', '结算价'];
  683. $data['filename'] = '财务成本管理列表导出';
  684. $data['data'] = [];
  685. $query = $this->getQueryFilter($param);
  686. $listI = $query->with(['provider','skues'])
  687. ->alias($this->name)
  688. ->field($this->getAliasFields($this->name, ['content']))
  689. ->where('is_delete', '=', 0)->select();
  690. //->whereIn('goods_id',$ids)
  691. //->paginate(500);
  692. // 整理列表数据并返回
  693. $list = $this->setGoodsListDataFinance($listI);
  694. /* $list = $listPage->toArray();
  695. dd($listPage);*/
  696. foreach ($list as $arr){
  697. $new_list['goods_id'] = $arr['goods_id'];
  698. $new_list['goods_no'] = $arr['goods_no'];
  699. $new_list['goods_name'] = $arr['goods_name'];
  700. $new_list['provider'] = $arr['provider']['provider_name'];
  701. $new_list['category_name'] = $arr['category_name'];
  702. $new_list['goods_prices'] = $arr['goods_price_min'].'~'.$arr['goods_price_max'];
  703. $new_list['clearing_price_range'] = $arr['clearing_price_range'];
  704. $data['data'][] = $new_list;
  705. }
  706. return $data;
  707. }
  708. /**
  709. * 获取商品列表
  710. * @param array $param 查询条件
  711. * @return mixed
  712. * @throws \think\db\exception\DbException
  713. */
  714. public function getListNoPage()
  715. {
  716. $param['sortType'] = 'create_time';
  717. $param['listType'] = 'all';
  718. $param['status'] = 10;
  719. // 筛选条件
  720. $query = $this->getQueryFilter($param);
  721. // 设置显示的销量 goods_sales
  722. // 购买数*1.5+加入购物车数+收藏数*0.8)之和排倒序
  723. $query->field(['(sales_initial + sales_actual + sales_shops) as goods_sales']);
  724. // 排序条件
  725. $sort = $this->setQuerySortZq($param);
  726. // 执行查询
  727. return $query->with(['images.file'])
  728. ->alias($this->name)
  729. ->field($this->getAliasFields($this->name, ['content']))
  730. ->where('status', '=', 10)
  731. ->where('is_delete', '=', 0)
  732. ->order($sort)
  733. ->select();
  734. /* return $list;
  735. dd($list->toArray());
  736. // 整理列表数据并返回
  737. return $this->setGoodsListData($list);*/
  738. }
  739. }