ProductService.php 64 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611
  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: ywl
  5. * Date: 2017/4/14
  6. * Time: 11:38
  7. */
  8. namespace App\Web\Services;
  9. use App\Common\Facades\UploadFileFacade;
  10. use App\Common\Services\PinYinService;
  11. use App\Exceptions\ApiException;
  12. use App\Services\CommonUserBaseService;
  13. use App\Web\Facades\WebFacade;
  14. use App\Web\Models\ProductModel;
  15. use App\Web\Models\ProductTagModel;
  16. use App\Web\Models\ProductTagRelationModel;
  17. use App\Web\Models\ProductTypeModel;
  18. use App\Web\Models\ProductTypeRelationModel;
  19. use Illuminate\Support\Facades\DB;
  20. class ProductService extends CommonUserBaseService
  21. {
  22. protected $cache = true;
  23. protected $cacheBucket = 'Product:';
  24. protected $productTypeModel;
  25. protected $productTypeRelationModel;
  26. protected $productTagModel;
  27. protected $productTagRelationModel;
  28. /**
  29. * ProductService construct
  30. * @param ProductModel $model
  31. * @param ProductTypeModel $productTypeModel
  32. * @param ProductTagRelationModel $productTagRelationModel
  33. * @param ProductTagModel $productTagModel
  34. * @param ProductTypeRelationModel $productTypeRelationModel
  35. * */
  36. public function __construct(ProductModel $model,
  37. ProductTypeModel $productTypeModel,
  38. ProductTagRelationModel $productTagRelationModel,
  39. ProductTagModel $productTagModel,
  40. ProductTypeRelationModel $productTypeRelationModel
  41. ){
  42. $this->model=$model;
  43. $this->productTypeModel=$productTypeModel;
  44. $this->productTypeRelationModel=$productTypeRelationModel;
  45. $this->productTagModel=$productTagModel;
  46. $this->productTagRelationModel=$productTagRelationModel;
  47. }
  48. /**
  49. * 获取产品类型列表
  50. * */
  51. public function getProductTypeList($params){
  52. $retData= $this->productTypeModel->getProductTypeList($params);
  53. if(!empty($retData['data'])){
  54. $typeIds=array_column($retData['data'],'id');
  55. $productCounts=$this->productTypeRelationModel->getProductTypeCount($typeIds);
  56. foreach ($retData['data'] as &$productItem){
  57. $productItem['product_count'] = $productCounts[$productItem['id']] ?? 0;
  58. $productItem['expand_content'] = empty($productItem['expand_content'])?[]:json_decode($productItem['expand_content'],true);
  59. }
  60. }
  61. return $retData;
  62. }
  63. public function getTreeProductList($params){
  64. $list= $this->productTypeModel->getTreeProductList($params);
  65. if(!empty($list)){
  66. $typeIds=array_column($list,'id');
  67. $productCounts=$this->productTypeRelationModel->getProductTypeCount($typeIds);
  68. $pCountData=[];
  69. $descData=array_reverse($list);
  70. foreach ($descData as $descProductItem){
  71. $tempCount= $productCounts[$descProductItem['id']] ?? 0;
  72. if(empty($pCountData[$descProductItem['p_id']])){
  73. $pCountData[$descProductItem['p_id']]=$tempCount;
  74. }else{
  75. $pCountData[$descProductItem['p_id']]=$pCountData[$descProductItem['p_id']]+$tempCount;
  76. }
  77. if(!empty($tempCount)&&!empty($pCountData[$descProductItem['id']])){
  78. $pCountData[$descProductItem['id']]=$pCountData[$descProductItem['id']]+$tempCount;
  79. }
  80. }
  81. foreach ($list as &$productItem){
  82. $productItem['product_count'] = $productCounts[$productItem['id']] ?? 0;
  83. $productItem['expand_content'] = empty($productItem['expand_content'])?[]:json_decode($productItem['expand_content'],true);
  84. $productItem['expand_array'] = $this->transformArrayToKeyValue($productItem['expand_content']);
  85. if(!empty($pCountData[$productItem['id']])){
  86. $productItem['product_count']=$pCountData[$productItem['id']];
  87. }
  88. }
  89. }
  90. $list=listToTree($list,0,'id','p_id','children');
  91. return $list;
  92. }
  93. public function transformArrayToKeyValue($array) {
  94. $result = [];
  95. foreach ($array as $item) {
  96. if (isset($item['key']) && isset($item['value'])) {
  97. $result[$item['key']] = $item['value'];
  98. }
  99. }
  100. return $result;
  101. }
  102. public function sortTypes($types){
  103. $retData= $this->productTypeModel->sortTypes($types);
  104. return $retData;
  105. }
  106. /**
  107. * 根据Admin类型id 获取产品列表
  108. * */
  109. public function getAdminProductByTypeIds($params) {
  110. $retData= $this->model->getAdminProductData($params);
  111. if(!empty($retData['data'])) {
  112. $newestProductIds=array_column($retData['data'],'id');
  113. $newestTypeAndTagData=$this->getTypeAndTagDataByProductId($newestProductIds);
  114. foreach ($retData['data'] as &$productItem){
  115. if(!empty($newestTypeAndTagData[$productItem['id']]['type_items'])){
  116. $productItem['type_items']=$newestTypeAndTagData[$productItem['id']]['type_items'];
  117. }else{
  118. $productItem['type_items']=[];
  119. }
  120. if(!empty($newestTypeAndTagData[$productItem['id']]['tag_items'])){
  121. $productItem['tag_items']=$newestTypeAndTagData[$productItem['id']]['tag_items'];
  122. }else{
  123. $productItem['tag_items']=[];
  124. }
  125. }
  126. }
  127. return $retData;
  128. }
  129. /**
  130. * 根据类型id 获取产品列表
  131. * */
  132. public function getProductByTypeIds($params) {
  133. $retData= $this->model->getProductByTypeIds($params);
  134. if(!empty($retData['data'])) {
  135. $newestProductIds=array_column($retData['data'],'id');
  136. $newestTypeAndTagData=$this->getTypeAndTagDataByProductId($newestProductIds);
  137. foreach ($retData['data'] as &$productItem){
  138. if(!empty($newestTypeAndTagData[$productItem['id']]['type_items'])){
  139. $productItem['type_items']=$newestTypeAndTagData[$productItem['id']]['type_items'];
  140. }else{
  141. $productItem['type_items']=[];
  142. }
  143. if(!empty($newestTypeAndTagData[$productItem['id']]['tag_items'])){
  144. $productItem['tag_items']=$newestTypeAndTagData[$productItem['id']]['tag_items'];
  145. }else{
  146. $productItem['tag_items']=[];
  147. }
  148. }
  149. }
  150. return $retData;
  151. }
  152. /**
  153. * 根据标签id 获取产品列表
  154. * */
  155. public function getProductByTagIds($params){
  156. $retData= $this->productTagRelationModel->getProductByTagIds($params);
  157. return $retData;
  158. }
  159. public function getProductIdByTagIds($params){
  160. $retData= $this->productTagRelationModel->getProductIdByTagIds($params);
  161. return $retData;
  162. }
  163. /**
  164. * 产品类型保存
  165. * */
  166. public function saveProductType($params){
  167. $saveData=[];
  168. $nowTime=nowTime();
  169. $saveData['update_time']=$nowTime;
  170. $userId=$this->getAuthUserId();
  171. if (!empty($params['seo_data'])) {
  172. $urlaUnique = WebFacade::checkUrlaUnique($params['seo_data']['urla'], $params['seo_id']);
  173. if (!$urlaUnique) {
  174. throw new ApiException(10019, ['name' => $params['seo_data']['urla']]);
  175. }
  176. }
  177. if(!empty($params['id'])){
  178. $saveData['id']=$params['id'];
  179. if(isset($params['type_name'])){
  180. $nameUnique =$this->productTypeModel->checkTypeNameUnique($params['type_name'],$params['id']);
  181. if (!$nameUnique) {
  182. throw new ApiException(10018, ['name' => $params['type_name']]);
  183. }
  184. $saveData['type_name']=$params['type_name'];
  185. }
  186. if(isset($params['description'])){
  187. $saveData['description']=empty($params['description'])?'':$params['description'];
  188. }
  189. if(isset($params['p_id'])){
  190. $saveData['p_id']=empty($params['p_id'])?0:$params['p_id'];
  191. }
  192. if(isset($params['status'])){
  193. $saveData['status']=$params['status'];
  194. }
  195. if(isset($params['sort'])){
  196. $saveData['sort']=$params['sort'];
  197. }
  198. if(isset($params['expand_content'])){
  199. $saveData['expand_content']=!empty($params['expand_content'])?json_encode($params['expand_content']):'';
  200. }
  201. }else{
  202. $nameUnique =$this->productTypeModel->checkTypeNameUnique($params['type_name']);
  203. if (!$nameUnique) {
  204. throw new ApiException(10018, ['name' => $params['type_name']]);
  205. }
  206. $saveData['user_id']=$userId;
  207. $saveData['type_name']=$params['type_name'];
  208. $saveData['description']=empty($params['description'])?'':$params['description'];
  209. $saveData['expand_content']=!empty($params['expand_content'])?json_encode($params['expand_content']):'';
  210. $saveData['sort']=empty($params['sort'])?0:$params['sort'];
  211. $saveData['p_id']=empty($params['p_id'])?0:$params['p_id'];
  212. $saveData['create_time']=$nowTime;
  213. }
  214. $id = $this->productTypeModel->saveTypeData($saveData);
  215. $parentId = empty($params['parent_id']) ?0:$params['parent_id'];
  216. if ($parentId) {
  217. $relations = $this->productTypeRelationModel->getByTypeId($parentId);
  218. $productIds = array_column($relations, 'product_id');
  219. $this->productTypeRelationModel->deleteByTypeId($parentId);
  220. $this->productTypeRelationModel->addByTypeId($id,$productIds,$userId);
  221. }
  222. if (!empty($id) && isset($params['seo_data'])) {
  223. $seoParams = [
  224. 'relation_table' => WebService::RELATION_TABLE_PRODUCT_TYPE,
  225. 'relation_id' => $id,
  226. 'urla' => $params['seo_data']['urla'],
  227. 'seo_title' => $params['seo_data']['seo_title'],
  228. 'seo_keyword' => $params['seo_data']['seo_keyword'],
  229. 'seo_describe' => $params['seo_data']['seo_describe']
  230. ];
  231. if (empty($params['seo_id'])) {
  232. $seoParams['user_id'] = $userId;
  233. $urlaId = WebFacade::saveSeoData($seoParams);
  234. $this->productTypeModel->newInstance()->where('id','=',$id)->update(['seo_id' => $urlaId]);
  235. } else {
  236. $seoParams['id'] = $params['seo_id'];
  237. $urlaId = WebFacade::saveSeoData($seoParams);
  238. }
  239. $allPath=$this->getProductAllPath($id);
  240. if($allPath){
  241. $this->productTypeModel->where('id', $id)->update(['path'=>$allPath['path'],'path_name'=>$allPath['path_name']]);
  242. $this->updateSubAllPath($id);
  243. }
  244. }
  245. if(!empty($saveData['status'])&&$saveData['status']==2){
  246. //移除对应seo
  247. $delSeoParams=[];
  248. $delSeoParams['relation_table']=WebService::RELATION_TABLE_PRODUCT_TYPE;
  249. $delSeoParams['relation_id']=$id;
  250. $ret = WebFacade::delSeoByRelation($delSeoParams);
  251. }
  252. //更新所有页面缓存
  253. WebFacade::clearPageCache('urla:');
  254. return $id;
  255. }
  256. /**
  257. * 获取功能/菜单的全路径
  258. * */
  259. public function getProductAllPath($id){
  260. $ret=['path'=>'','path_name'=>''];
  261. $info= $this->productTypeModel->alias('a')
  262. ->leftJoin($this->productTypeModel->getTable().' as b', 'a.p_id', '=', 'b.id')
  263. ->where('a.id',$id)
  264. ->where('a.status',0)
  265. ->selectRaw("b.id as p_id,b.type_name as 'p_name',a.id,a.type_name")
  266. ->first();
  267. if($info){
  268. $info=$info->toArray();
  269. if(!empty($info['p_id'])){
  270. $pRet=$this->getProductAllPath($info['p_id']);
  271. $ret['path']=$pRet['path'].','.$info['id'];
  272. $ret['path_name']=$pRet['path_name'].','.$info['type_name'];
  273. }else{
  274. $ret['path']= $info['id'];
  275. $ret['path_name']= $info['type_name'];
  276. }
  277. }
  278. return $ret;
  279. }
  280. /**
  281. * 更新子集的全路径
  282. * */
  283. public function updateSubAllPath($id){
  284. if($id>0){
  285. $list= $this->productTypeModel->alias('a')
  286. ->where('a.p_id',$id)
  287. ->where('a.status',0)
  288. ->get();
  289. if(!empty($list)){
  290. $list=$list->toArray();
  291. foreach ($list as $value){
  292. $allPath=$this->getProductAllPath($value['id']);
  293. if($allPath){
  294. $this->productTypeModel->where('id', $value['id'])->update(['path'=>$allPath['path'],'path_name'=>$allPath['path_name']]);
  295. $this->updateSubAllPath($value['id']);
  296. }
  297. }
  298. }
  299. }
  300. }
  301. /**
  302. * 保存产品类型关系
  303. * */
  304. public function typeRelationSave($params){
  305. $userId=$this->getAuthUserId();
  306. $ret = $this->productTypeRelationModel->typeRelationSave($params,$userId);
  307. //更新所有页面缓存
  308. WebFacade::clearPageCache('urla:');
  309. return $ret;
  310. }
  311. /**
  312. * 根据产品类型 保存产品关系
  313. * */
  314. public function addRelationByTypeId($typeId,$productIds){
  315. $userId=$this->getAuthUserId();
  316. $ret = $this->productTypeRelationModel->addByTypeId($typeId,$productIds,$userId);
  317. //更新所有页面缓存
  318. WebFacade::clearPageCache('urla:');
  319. return $ret;
  320. }
  321. /**
  322. * 根据类型id及产品id 删除关联关系
  323. * */
  324. public function delTypeRelation($typeId, $productId)
  325. {
  326. $ret = $this->productTypeRelationModel->delTypeRelation($typeId, $productId);
  327. //更新所有页面缓存
  328. WebFacade::clearPageCache('urla:');
  329. return $ret;
  330. }
  331. /**
  332. * 获取产品标签列表
  333. * */
  334. public function getProductTagList($params){
  335. $retData= $this->productTagModel->getProductTagList($params);
  336. if(!empty($retData['data'])){
  337. $tagIds=array_column($retData['data'],'id');
  338. $productCounts=$this->productTagRelationModel->getProductTagCount($tagIds);
  339. foreach ($retData['data'] as &$productItem){
  340. $productItem['product_count'] = $productCounts[$productItem['id']] ?? 0;
  341. }
  342. }
  343. return $retData;
  344. }
  345. /**
  346. * 产品标签保存
  347. * */
  348. public function saveProductTag($params){
  349. $saveData=[];
  350. $nowTime=nowTime();
  351. $saveData['update_time']=$nowTime;
  352. $userId=$this->getAuthUserId();
  353. if (!empty($params['seo_data'])) {
  354. $urlaUnique = WebFacade::checkUrlaUnique($params['seo_data']['urla'], $params['seo_id']);
  355. if (!$urlaUnique) {
  356. throw new ApiException(10019, ['name' => $params['seo_data']['urla']]);
  357. }
  358. }
  359. if(!empty($params['id'])){
  360. $saveData['id']=$params['id'];
  361. if(isset($params['tag_name'])){
  362. $nameUnique =$this->productTagModel->checkTagNameUnique($params['tag_name'],$params['id']);
  363. if (!$nameUnique) {
  364. throw new ApiException(10018, ['name' => $params['tag_name']]);
  365. }
  366. $saveData['tag_name']=$params['tag_name'];
  367. }
  368. if(isset($params['status'])){
  369. $saveData['status']=$params['status'];
  370. }
  371. if(isset($params['sort'])){
  372. $saveData['sort']=$params['sort'];
  373. }
  374. if(isset($params['is_hot'])){
  375. $saveData['is_hot']=$params['is_hot'];
  376. }
  377. if(isset($params['type'])){
  378. $saveData['type']=empty($params['type'])?0:$params['type'];
  379. }
  380. }else{
  381. $nameUnique =$this->productTagModel->checkTagNameUnique($params['tag_name']);
  382. if (!$nameUnique) {
  383. throw new ApiException(10018, ['name' => $params['tag_name']]);
  384. }
  385. $saveData['user_id']=$userId;
  386. $saveData['tag_name']=$params['tag_name'];
  387. $saveData['type']=empty($params['type'])?0:$params['type'];
  388. $saveData['sort']=empty($params['sort'])?0:$params['sort'];
  389. $saveData['create_time']=$nowTime;
  390. }
  391. $id = $this->productTagModel->saveTagData($saveData);
  392. if (!empty($id) && isset($params['seo_data'])) {
  393. $seoParams = [
  394. 'relation_table' => WebService::RELATION_TABLE_PRODUCT_TAG,
  395. 'relation_id' => $id,
  396. 'urla' => $params['seo_data']['urla'],
  397. 'seo_title' => $params['seo_data']['seo_title'],
  398. 'seo_keyword' => $params['seo_data']['seo_keyword'],
  399. 'seo_describe' => $params['seo_data']['seo_describe']
  400. ];
  401. if (empty($params['seo_id'])) {
  402. $seoParams['user_id'] = $userId;
  403. $urlaId = WebFacade::saveSeoData($seoParams);
  404. $this->productTagModel->newInstance()->where('id','=',$id)->update(['seo_id' => $urlaId]);
  405. } else {
  406. $seoParams['id'] = $params['seo_id'];
  407. $urlaId = WebFacade::saveSeoData($seoParams);
  408. }
  409. if(!empty($saveData['status'])&&$saveData['status']==2){
  410. //移除对应seo
  411. $delSeoParams=[];
  412. $delSeoParams['relation_table']=WebService::RELATION_TABLE_PRODUCT_TAG;
  413. $delSeoParams['relation_id']=$id;
  414. $ret = WebFacade::delSeoByRelation($delSeoParams);
  415. }
  416. }
  417. return $id;
  418. }
  419. /**
  420. * 保存产品标签关系
  421. * */
  422. public function tagRelationSave($params){
  423. $userId=$this->getAuthUserId();
  424. $ret = $this->productTagRelationModel->tagRelationSave($params,$userId);
  425. //更新所有页面缓存
  426. WebFacade::clearPageCache('urla:');
  427. return $ret;
  428. }
  429. /**
  430. * 根据产品标签 保存产品关系
  431. * */
  432. public function addRelationByTagId($tagId,$productIds){
  433. $userId=$this->getAuthUserId();
  434. $ret = $this->productTagRelationModel->addByTagId($tagId,$productIds,$userId);
  435. //更新所有页面缓存
  436. WebFacade::clearPageCache('urla:');
  437. return $ret;
  438. }
  439. /**
  440. * 根据标签id及产品id 删除关联关系
  441. * */
  442. public function delTagRelation($tagId, $productId)
  443. {
  444. $ret = $this->productTagRelationModel->delTagRelation($tagId, $productId);
  445. //更新所有页面缓存
  446. WebFacade::clearPageCache('urla:');
  447. return $ret;
  448. }
  449. /**
  450. * 保存产品数据
  451. * */
  452. public function saveProduct($params){
  453. $saveData=$this->buildProductData($params);
  454. // dd($saveData);
  455. $userId=$this->getAuthUserId();
  456. $typeIds = empty($params['type_ids']) ? []: $params['type_ids'];
  457. $tagIds = empty($params['tag_ids']) ? []: $params['tag_ids'];
  458. $seoData=empty($params['seo_data'])?[]:$params['seo_data'];
  459. $urlaId=empty($saveData['seo_id'])?0:$saveData['seo_id'];
  460. if(!empty($seoData)){
  461. $urlaUnique = WebFacade::checkUrlaUnique($seoData['urla'],$urlaId);
  462. if (!$urlaUnique) {
  463. throw new ApiException(10019, ['name' => $seoData['urla']]);
  464. }
  465. }
  466. $id = $this->model->saveProductData($saveData);
  467. if(!empty($id)){
  468. if(isset($params['seo_data'])){
  469. $seoParams=[];
  470. $seoParams['relation_table']=WebService::RELATION_TABLE_PRODUCT;
  471. $seoParams['relation_id']=$id;
  472. $seoParams['urla']=$seoData['urla'];
  473. $seoParams['seo_title']=$seoData['seo_title'];
  474. $seoParams['seo_keyword']=$seoData['seo_keyword'];
  475. $seoParams['seo_describe']=$seoData['seo_describe'];
  476. if(empty($urlaId)){
  477. $seoParams['user_id']=$userId;
  478. $urlaId = WebFacade::saveSeoData($seoParams);
  479. $this->model->newInstance()->where('id','=',$id)->update(['seo_id'=>$urlaId]);
  480. }else{
  481. // dd($seoParams);
  482. $seoParams['id']=$urlaId;
  483. $urlaId= WebFacade::saveSeoData($seoParams);
  484. }
  485. }
  486. if(isset($params['type_ids'])){
  487. $productTypeParams=[];
  488. $productTypeParams['product_id']=$id;
  489. $productTypeParams['type_ids']=$typeIds;
  490. $this->productTypeRelationModel->typeRelationSave($productTypeParams,$userId);
  491. }
  492. if(isset($params['tag_ids'])){
  493. $productTagParams=[];
  494. $productTagParams['product_id']=$id;
  495. $productTagParams['tag_ids']=$tagIds;
  496. $this->productTagRelationModel->tagRelationSave($productTagParams,$userId);
  497. }
  498. // 获取是否需要修改排序数据
  499. if (isset($saveData['sort'])) {
  500. $getData = $this->model->selectRaw('id')
  501. ->where('sort', '=', $saveData['sort'])
  502. ->where('id', '<>', $id)->first();
  503. if (!empty($getData['id'])) {
  504. $this->model->where('sort','>=',$saveData['sort'])
  505. ->where('id', '<>', $id)
  506. ->update(['sort' => DB::raw('sort + 1')]);
  507. }
  508. }
  509. if(!empty($params['id'])&&!empty($params['virtual_view'])){
  510. $this->updatePv($params['id'],$params['virtual_view']);
  511. }
  512. if(!empty($saveData['status'])&&$saveData['status']==2){
  513. //移除对应seo
  514. $delSeoParams=[];
  515. $delSeoParams['relation_table']=WebService::RELATION_TABLE_PRODUCT;
  516. $delSeoParams['relation_id']=$id;
  517. $ret = WebFacade::delSeoByRelation($delSeoParams);
  518. }
  519. }
  520. //更新所有页面缓存
  521. WebFacade::clearPageCache('urla:');
  522. return $id;
  523. }
  524. /**
  525. * 构造虚拟阅读量
  526. * */
  527. public function productUvFactory(){
  528. $page=1;
  529. $total=0;
  530. do{
  531. $where=[];
  532. $where['page_size']=500;
  533. $where['page']=$page;
  534. $where['status']=0;
  535. $where['lt_total_view']=1000;
  536. $productData= $this->model->getProductList($where,'a.id,a.virtual_view,a.total_view');
  537. if(!empty($productData)&&!empty($productData['data'])){
  538. $total=$productData['total'];
  539. $data=$productData['data'];
  540. $updateUvStr='';
  541. // 规则:小于1千数随记增加 150以内位数
  542. foreach ($data as $item){
  543. $value=0;
  544. if($item['total_view']<1000){
  545. $value= mt_rand(0, 150);
  546. }
  547. /* if($item['total_view']<1000){
  548. $value= mt_rand(0, 150);
  549. }else if($item['total_view']<5000){
  550. $value= mt_rand(0, 99);
  551. }else{
  552. $value= mt_rand(0, 9);
  553. }*/
  554. $this->upProductPv($item['id'],$value);
  555. }
  556. }
  557. $page++;
  558. }while($total>($page*500));
  559. WebFacade::clearPageCache('urla:');
  560. }
  561. /**
  562. * 产品推荐设置
  563. * */
  564. public function recommendSet($params){
  565. $id=empty($params['id'])?0:$params['id'];
  566. $isRecommend=empty($params['is_recommend'])?0:$params['is_recommend'];
  567. $ret= $this->model->where('id', '=', $id)
  568. ->update(['is_recommend' => $isRecommend,'update_time'=>nowTime()]);
  569. //更新所有页面缓存
  570. WebFacade::clearPageCache('urla:');
  571. return $id;
  572. }
  573. /**
  574. * 构建产品保存数据
  575. * */
  576. private function buildProductData($params){
  577. $saveData=[];
  578. $userId=$this->getAuthUserId();
  579. $nowTime=nowTime();
  580. $saveData['update_time']=$nowTime;
  581. if(!empty($params['id'])){
  582. $saveData['id']=$params['id'];
  583. if (isset($params['seo_id'])) {
  584. $saveData['seo_id'] = $params['seo_id'];
  585. }
  586. if(isset($params['pub_date'])){
  587. $saveData['pub_date']=empty($params['pub_date'])?null:$params['pub_date'];;
  588. }
  589. if(isset($params['title'])){
  590. $nameUnique =$this->model->checkNameUnique($params['title'],$params['id']);
  591. if (!$nameUnique) {
  592. throw new ApiException(10018, ['name' => $params['title']]);
  593. }
  594. $saveData['title']=empty($params['title'])?'':$params['title'];
  595. }
  596. if(isset($params['content'])){
  597. $saveData['content']=empty($params['content'])?'':$params['content'];
  598. }
  599. if(isset($params['brand'])){
  600. $saveData['brand']=empty($params['brand'])?'':$params['brand'];
  601. }
  602. if(isset($params['model_nb'])){
  603. $saveData['model_nb']=empty($params['model_nb'])?'':$params['model_nb'];
  604. }
  605. if(isset($params['package'])){
  606. $saveData['package']=empty($params['package'])?'':$params['package'];
  607. }
  608. if(isset($params['sku'])){
  609. $saveData['sku']=empty($params['sku'])?'':$params['sku'];
  610. }
  611. if(isset($params['spec'])){
  612. $saveData['spec']=empty($params['spec'])?'':json_encode($params['spec']) ;
  613. }
  614. if(isset($params['description'])){
  615. $saveData['description']=empty($params['description'])?'':$params['description'];
  616. }
  617. if(isset($params['image_url'])){
  618. $saveData['image_url']=empty($params['image_url'])?'':$params['image_url'];
  619. }
  620. if(isset($params['image_alt'])){
  621. $saveData['image_alt']=empty($params['image_alt'])?'':$params['image_alt'];
  622. }
  623. if(isset($params['main_image'])){
  624. $saveData['main_image']=empty($params['main_image'])?'':$params['main_image'];
  625. }
  626. if(isset($params['main_image_alt'])){
  627. $saveData['main_image_alt']=empty($params['main_image_alt'])?'':$params['main_image_alt'];
  628. }
  629. if(isset($params['download_url'])){
  630. $saveData['download_url']=empty($params['download_url'])?'':json_encode($params['download_url']);
  631. }
  632. if(isset($params['sub_image_urls'])){
  633. $saveData['sub_image_urls']=empty($params['sub_image_urls'])?'':json_encode($params['sub_image_urls']);
  634. }
  635. if(isset($params['gallery_imgs'])){
  636. $saveData['gallery_imgs']=empty($params['gallery_imgs'])?'':json_encode($params['gallery_imgs']);
  637. }
  638. if(isset($params['size_imgs'])){
  639. $saveData['size_imgs']=empty($params['size_imgs'])?'':json_encode($params['size_imgs']);
  640. }
  641. if(isset($params['sort'])){
  642. $saveData['sort']=empty($params['sort'])?0:$params['sort'];
  643. }
  644. if(isset($params['is_top'])){
  645. $saveData['is_top']=empty($params['is_top'])?0:$params['is_top'];
  646. }
  647. if(isset($params['status'])){
  648. $saveData['status']=$params['status'];
  649. }
  650. if(isset($params['score'])){
  651. $saveData['score']=empty($params['score'])?0:$params['score'];
  652. }
  653. if(isset($params['expand_content'])) {
  654. $saveData['expand_content'] = empty($params['expand_content'])?'':json_encode($params['expand_content']);
  655. }
  656. }else{
  657. $nameUnique =$this->model->checkNameUnique($params['title']);
  658. if (!$nameUnique) {
  659. throw new ApiException(10018, ['name' => $params['title']]);
  660. }
  661. if(empty($params['title'])){
  662. throw new ApiException(11002);
  663. }
  664. if(isset($params['status'])){
  665. $saveData['status']=$params['status'];
  666. }
  667. $saveData['user_id']=$userId;
  668. $saveData['pub_date']=empty($params['pub_date'])?null:$params['pub_date'];
  669. $saveData['title']=empty($params['title'])?'':$params['title'];
  670. $saveData['content']=empty($params['content'])?'':$params['content'];
  671. $saveData['brand']=empty($params['brand'])?'':$params['brand'];
  672. $saveData['model_nb']=empty($params['model_nb'])?'':$params['model_nb'];
  673. $saveData['package']=empty($params['package'])?'':$params['package'];
  674. $saveData['sku']=empty($params['sku'])?'':$params['sku'];
  675. $saveData['spec']=empty($params['spec'])?'':json_encode($params['spec']) ;
  676. $saveData['description']=empty($params['description'])?'':$params['description'];
  677. $saveData['image_url']=empty($params['image_url'])?'':$params['image_url'];
  678. $saveData['image_alt']=empty($params['image_alt'])?'':$params['image_alt'];
  679. $saveData['main_image']=empty($params['main_image'])?'':$params['main_image'];
  680. $saveData['main_image_alt']=empty($params['main_image_alt'])?'':$params['main_image_alt'];
  681. $saveData['sub_image_urls']=empty($params['sub_image_urls'])?'':json_encode($params['sub_image_urls']);
  682. $saveData['gallery_imgs']=empty($params['gallery_imgs'])?'':json_encode($params['gallery_imgs']);
  683. $saveData['size_imgs']=empty($params['size_imgs'])?'':json_encode($params['size_imgs']);
  684. $saveData['virtual_view']=empty($params['virtual_view'])?0:$params['virtual_view'];
  685. $saveData['total_view']=$saveData['virtual_view'];
  686. $saveData['download_url']=empty($params['download_url'])?'':json_encode($params['download_url']);
  687. $saveData['expand_content'] = empty($params['expand_content'])?'':json_encode($params['expand_content']);
  688. $saveData['sort']=empty($params['sort'])?0:$params['sort'];
  689. $saveData['create_time']=$nowTime;
  690. $saveData['score']=empty($params['score'])?0:$params['score'];
  691. }
  692. return $saveData;
  693. }
  694. public function updatePv($id,$newVirtualView){
  695. $virtualView = $this->getFieldById('virtual_view', $id);
  696. // 确保 $newVirtualView 是数值类型
  697. $newVirtualView = (float)$newVirtualView;
  698. // 确保 $virtualView 是数值类型
  699. $virtualView = (float)$virtualView;
  700. // 计算差值
  701. $value = $newVirtualView - $virtualView;
  702. // 执行更新操作
  703. $ret = $this->model->where('id', '=', $id)->increment('total_view', $value);
  704. $ret = $this->model->where('id', '=', $id)->increment('virtual_view', $value);
  705. WebFacade::clearPageCache('urla:');
  706. return $ret;
  707. }
  708. /**
  709. * 更新产品浏览量
  710. * */
  711. public function upProductPv($productId, $value=1) {
  712. if($value>1){
  713. $ret= $this->model->where('id','=',$productId)->increment('total_view',$value);
  714. $ret= $this->model->where('id','=',$productId)->increment('virtual_view',$value);
  715. }else{
  716. $totalView = $this->getFieldById('total_view', $productId);
  717. $value = (($value * -1) > $totalView) ? ($totalView * -1) : $value;
  718. $ret= $this->model->where('id','=',$productId)->increment('total_view',$value);
  719. }
  720. return $ret;
  721. }
  722. /**
  723. * 产品列表
  724. * */
  725. public function getProductList($params){
  726. $ret=$this->model->getProductList($params);
  727. $pageListData=empty($ret['data'])?[]:$ret['data'];
  728. if(!empty($pageListData)){
  729. $ids=array_column($pageListData,'seo_id');
  730. $seoList=[];
  731. if(!empty($ids)){
  732. $seoList=WebFacade:: getSeoListByIds($ids);
  733. if(!empty($seoList)){
  734. $seoList=mapByKey($seoList,'id');
  735. }
  736. }
  737. foreach ($pageListData as &$pageItem){
  738. $pageItem['seo_data']=empty($seoList[$pageItem['seo_id']])?[]:$seoList[$pageItem['seo_id']];
  739. $pageItem['expand_content']=empty($pageItem['expand_content'])?[]:json_decode($pageItem['expand_content'],true);
  740. }
  741. }
  742. $ret['data']=$pageListData;
  743. return $ret;
  744. }
  745. /**
  746. * 获取产品详情
  747. * */
  748. public function getProductInfo($params){
  749. $productInfo= $this->model->getProductInfo($params);
  750. if(!empty($productInfo)){
  751. if(!empty($productInfo['seo_id'])){
  752. $productInfo['seo_data']=WebFacade::getSeoInfo(['id'=>$productInfo['seo_id']]);
  753. }else{
  754. $productInfo['seo_data'] = [
  755. 'seo_describe' => '',
  756. 'seo_keyword' => '',
  757. 'seo_title' => '',
  758. 'urla' => ''
  759. ];
  760. }
  761. $productInfo['spec']=empty($productInfo['spec'])?[]:json_decode($productInfo['spec'],true);
  762. $productInfo['type_ids']=$this->productTypeRelationModel->getTypeIds($productInfo['id']);
  763. $productInfo['tag_ids']=$this->productTagRelationModel->getTagIds($productInfo['id']);
  764. $productInfo['expand_content']=empty($productInfo['expand_content'])?[]:json_decode($productInfo['expand_content'],true);
  765. if(!empty($productInfo['download_url'])){
  766. $productInfo['download_url']= json_decode($productInfo['download_url'],true);
  767. }else{
  768. $productInfo['download_url']=[];
  769. }
  770. if(!empty($productInfo['sub_image_urls'])){
  771. $productInfo['sub_image_urls']= json_decode($productInfo['sub_image_urls'],true);
  772. }else{
  773. $productInfo['sub_image_urls']=[];
  774. }
  775. if(!empty($productInfo['gallery_imgs'])){
  776. $productInfo['gallery_imgs']= json_decode($productInfo['gallery_imgs'],true);
  777. }else{
  778. $productInfo['gallery_imgs']=[];
  779. }
  780. if(!empty($productInfo['size_imgs'])){
  781. $productInfo['size_imgs']= json_decode($productInfo['size_imgs'],true);
  782. }else{
  783. $productInfo['size_imgs']=[];
  784. }
  785. }
  786. return $productInfo;
  787. }
  788. /**
  789. * 获取产品分类未关联的产品
  790. * */
  791. public function getUnrelatedProductByTypeIds($params){
  792. $ret=$this->model->getUnrelatedProductByTypeIds($params);
  793. return $ret;
  794. }
  795. /**
  796. * 获取产品标签未关联的产品
  797. * */
  798. public function getUnrelatedProductByTagIds($params){
  799. $ret=$this->model->getUnrelatedProductByTagId($params);
  800. return $ret;
  801. }
  802. public function getProductByTypeAndChildIds($typeIds)
  803. {
  804. $dataIds = $this->productTypeModel->getProductTypeChild($typeIds);
  805. $ids = array_column($dataIds, 'id');
  806. if (!empty($ids)) {
  807. return array_unique(array_merge($typeIds, $ids));
  808. } else {
  809. return $typeIds;
  810. }
  811. }
  812. /**
  813. * 获取已发布的连接
  814. * */
  815. public function getPublishProductList($params,$fields='',$data_type='') {
  816. if(empty($fields)) {
  817. $fields='a.id,a.pub_date,a.title,a.description,a.main_image,a.sub_image_urls,a.main_image_alt,a.image_url,a.image_alt,a.brand,a.model_nb,a.package,a.spec,'.
  818. 'a.score,a.is_top,a.is_recommend,a.download_url,a.expand_content,a.total_view,b.urla';
  819. }
  820. $ids=[];
  821. if(!empty($params['type_ids'])) {
  822. $params['type_ids'] = $this->getProductByTypeAndChildIds($params['type_ids']);
  823. $typeProductList=$this->getProductByTypeIds(['type_id'=>$params['type_ids'],'page_size'=>99999,'page'=>1]);
  824. if(!empty($typeProductList['data'])){
  825. $ids=array_column($typeProductList['data'],'id');
  826. }
  827. }
  828. if(!empty($params['tag_ids'])) {
  829. $tagProductList=$this->getProductIdByTagIds(['tag_id'=>$params['tag_ids']]);
  830. if(!empty($tagProductList)){
  831. $tagReIds=array_column($tagProductList,'id');
  832. //dd($ids,$tagReIds,$data_type);
  833. if (!empty($ids) && !empty($data_type) && $data_type === 'intersect') {
  834. $ids = array_intersect($ids,$tagReIds);
  835. } else {
  836. $ids = array_unique(array_merge($ids,$tagReIds));
  837. }
  838. /*if(!empty($ids)){
  839. $ids=array_merge($ids,$tagReIds);
  840. }*/
  841. }
  842. }
  843. if(!empty($ids) || ((empty($params['type_ids']) || $params['type_ids'] == 0) && (empty($params['tag_ids']) || $params['tag_ids'] == 0))){
  844. $params['ids']=$ids;
  845. } else {
  846. return [
  847. 'data' => [],
  848. 'current_page' => $params['page'],
  849. 'per_page' => $params['page_size'],
  850. 'total' => 0,
  851. 'last_page' => 0,
  852. 'from' => null,
  853. 'to' => null,
  854. ];
  855. }
  856. $productList=$this->model->getPublishProductList($params,$fields);
  857. if(!empty($params['is_paginate'])) {
  858. $productListData=$productList['data'];
  859. } else {
  860. $productListData=$productList;
  861. }
  862. $productIds=array_column($productListData,'id');
  863. if($productIds){
  864. $newestTypeAndTagData=$this->getTypeAndTagDataByProductId($productIds);
  865. foreach ($productListData as &$productItem){
  866. if(!empty($newestTypeAndTagData[$productItem['id']]['type_items'])){
  867. $productItem['type_items']=$newestTypeAndTagData[$productItem['id']]['type_items'];
  868. }else{
  869. $productItem['type_items']=[];
  870. }
  871. if(!empty($newestTypeAndTagData[$productItem['id']]['tag_items'])){
  872. $productItem['tag_items']=$newestTypeAndTagData[$productItem['id']]['tag_items'];
  873. }else{
  874. $productItem['tag_items']=[];
  875. }
  876. if(!empty($productItem['spec'])){
  877. $productItem['spec']=json_decode($productItem['spec'],true);
  878. }else{
  879. $productItem['spec']=[];
  880. }
  881. $productItem['sub_image_urls']=empty($productItem['sub_image_urls'])?[]:json_decode($productItem['sub_image_urls'],true);
  882. $productItem['expand_content']=empty($productItem['expand_content'])?[]:json_decode($productItem['expand_content'],true);
  883. $productItem['expand_content'] = mapByKey($productItem['expand_content'],'key');
  884. }
  885. if(!empty($params['is_paginate'])){
  886. $productList['data']=$productListData;
  887. }else{
  888. $productList=$productListData;
  889. }
  890. }
  891. return $productList;
  892. }
  893. /**
  894. * 获取产品详情渲染数据
  895. * */
  896. public function getProductRenderData($params) {
  897. $productInfo= $this->model->getProductInfo($params);
  898. if(!empty($productInfo)){
  899. $newestTypeAndTagData=$this->getTypeAndTagDataByProductId([$productInfo['id']]);
  900. if(!empty($newestTypeAndTagData[$productInfo['id']]['type_items'])) {
  901. $productInfo['type_items']=$newestTypeAndTagData[$productInfo['id']]['type_items'];
  902. } else {
  903. $productInfo['type_items']=[];
  904. }
  905. if(!empty($newestTypeAndTagData[$productInfo['id']]['tag_items'])){
  906. $productInfo['tag_items']=$newestTypeAndTagData[$productInfo['id']]['tag_items'];
  907. }else{
  908. $productInfo['tag_items']=[];
  909. }
  910. if(!empty($productInfo['spec'])){
  911. $productInfo['spec']=json_decode($productInfo['spec'],true);
  912. }else{
  913. $productInfo['spec']=[];
  914. }
  915. if(!empty($productInfo['sub_image_urls'])){
  916. $productInfo['sub_image_urls']=json_decode($productInfo['sub_image_urls'],true);
  917. }else{
  918. $productInfo['sub_image_urls']=[];
  919. }
  920. if(!empty($productInfo['gallery_imgs'])){
  921. $productInfo['gallery_imgs']=json_decode($productInfo['gallery_imgs'],true);
  922. }else{
  923. $productInfo['gallery_imgs']=[];
  924. }
  925. if(!empty($productInfo['size_imgs'])){
  926. $productInfo['size_imgs']=json_decode($productInfo['size_imgs'],true);
  927. }else{
  928. $productInfo['size_imgs']=[];
  929. }
  930. if(!empty($productInfo['download_url'])){
  931. $productInfo['download_url']=json_decode($productInfo['download_url'],true);
  932. }else{
  933. $productInfo['download_url']=[];
  934. }
  935. $productInfo['expand_content']=empty($productInfo['expand_content'])?[]:json_decode($productInfo['expand_content'],true);
  936. $productInfo['expand_content'] = mapByKey($productInfo['expand_content'],'key');
  937. }
  938. return $productInfo;
  939. }
  940. /**
  941. * 获取产品列表页渲染数据
  942. * */
  943. public function getProductRecentlyData($params=[]){
  944. $data=[
  945. 'product_type_list'=>[],//所有已发布的产品分类
  946. 'product_tag_list'=>[],//所有正常标签
  947. ];
  948. $typeParams=[];
  949. $typeParams['status']=0;
  950. $typeParams['page_size']=9999;
  951. $data['product_type_list']=$this->getProductTypeList($typeParams);
  952. $tagParams=[];
  953. $tagParams['status']=0;
  954. $tagParams['page_size']=9999;
  955. $data['product_tag_list']=$this->getProductTagList($tagParams);
  956. return $data;
  957. }
  958. /**
  959. * 获取产品列表页渲染数据
  960. * */
  961. public function getProductTagData(){
  962. $tagParams=[];
  963. $tagParams['status']=0;
  964. $tagParams['page_size']=9999;
  965. $data=$this->getProductTagList($tagParams);
  966. return $data;
  967. }
  968. /**
  969. * 获取类型详情
  970. * */
  971. public function getProductTypeRenderInfo($params=[]){
  972. $typeWhere=[];
  973. $typeWhere['status']=0;
  974. $typeWhere['id']=empty($params['id'])?0:$params['id'];
  975. $typeInfo=$this->productTypeModel->getProductTypeInfo($typeWhere);
  976. return $typeInfo;
  977. }
  978. /**
  979. * 获取标签详情
  980. * */
  981. public function getProductTagRenderInfo($params=[]){
  982. $tagWhere=[];
  983. $tagWhere['status']=0;
  984. $tagWhere['id']=empty($params['tag_id'])?0:$params['tag_id'];
  985. $tagInfo=$this->productTagModel->getProductTagInfo($tagWhere);
  986. return $tagInfo;
  987. }
  988. /**
  989. * 获取相关商品
  990. * */
  991. public function getRelevanceList($params){
  992. $newestListParams=[];
  993. $newestListParams['page_size']=empty($params['relevance_page_size'])?5:$params['relevance_page_size'];
  994. $newestListParams['sort']['is_top']=1;
  995. $newestListParams['sort']['pub_date']=1;
  996. $newestListParams['type_ids']=empty($params['type_ids'])?[]:$params['type_ids'];
  997. $newestList=$this->getPublishProductList($newestListParams);
  998. return $newestList;
  999. }
  1000. /**
  1001. * 热门产品列表
  1002. * */
  1003. public function getHotList($params){
  1004. $hotListParams=[];
  1005. $hotListParams['page_size']=empty($params['hot_news_size'])?4:$params['hot_news_size'];
  1006. $hotListParams['sort']['is_hot']=1;
  1007. $hotListParams['sort']['pub_date']=1;
  1008. $hotList=$this->getPublishProductList($hotListParams);
  1009. return $hotList;
  1010. }
  1011. /**
  1012. * 推荐产品列表
  1013. * */
  1014. public function getRecommendList($params){
  1015. $recommendListParams=[];
  1016. $recommendListParams['page_size']=empty($params['recommend_news_size'])?4:$params['recommend_news_size'];
  1017. $recommendListParams['sort']['is_recommend']=1;
  1018. $recommendListParams['sort']['pub_date']=1;
  1019. $recommendList=$this->getPublishProductList($recommendListParams);
  1020. return $recommendList;
  1021. }
  1022. /**
  1023. * 根据产品id获取产品类型及产品标签数据
  1024. * */
  1025. public function getTypeAndTagDataByProductId($newestProductIds){
  1026. $resultData=[];
  1027. $newestTypeData=$this->productTypeRelationModel->getTypeListByProductIds($newestProductIds);
  1028. foreach ($newestTypeData as $typeItem) {
  1029. if (!empty($typeItem['expand_content'])) {
  1030. $typeItem['expand_content'] = json_decode($typeItem['expand_content'],true);
  1031. $typeItem['expand_content'] = mapByKey($typeItem['expand_content'],'key');
  1032. }
  1033. $resultData[$typeItem['product_id']]['type_items'][]=$typeItem;
  1034. }
  1035. $newestTagData=$this->productTagRelationModel->getTagListByProductIds($newestProductIds);
  1036. foreach ($newestTagData as $tagItem){
  1037. $resultData[$tagItem['product_id']]['tag_items'][]=$tagItem;
  1038. }
  1039. return $resultData;
  1040. }
  1041. /**
  1042. * 根据类型id获取产品
  1043. * */
  1044. public function getPublishProductListByTypeId($params){
  1045. $fields='a.id,a.pub_date,a.title,a.description,a.image_url,a.image_alt,a.is_top,a.is_recommend,a.download_url,a.total_view,b.type_id,c.urla';
  1046. $ret=$this->model->getPublishProductListByTypeId($params,$fields);
  1047. $productData=empty($ret['data'])?[]:$ret['data'];
  1048. if(!empty($productData)){
  1049. $newestProductIds=array_column($productData,'id');
  1050. $newestTypeAndTagData=$this->getTypeAndTagDataByProductId($newestProductIds);
  1051. foreach ($productData as &$productItem){
  1052. if(!empty($newestTypeAndTagData[$productItem['id']]['type_items'])){
  1053. $productItem['type_items']=$newestTypeAndTagData[$productItem['id']]['type_items'];
  1054. }else{
  1055. $productItem['type_items']=[];
  1056. }
  1057. if(!empty($newestTypeAndTagData[$productItem['id']]['tag_items'])){
  1058. $productItem['tag_items']=$newestTypeAndTagData[$productItem['id']]['tag_items'];
  1059. }else{
  1060. $productItem['tag_items']=[];
  1061. }
  1062. }
  1063. $ret['data']=$productData;
  1064. }
  1065. return $ret;
  1066. }
  1067. /**
  1068. * 根据标签id获取产品
  1069. * */
  1070. public function getPublishProductListByTagId($params){
  1071. $fields='a.id,a.pub_date,a.title,a.description,a.image_url,a.image_alt,a.is_top,a.is_recommend,a.download_url,a.total_view,b.tag_id,c.urla';
  1072. $ret=$this->model->getPublishProductListByTagId($params,$fields);
  1073. $productData=empty($ret['data'])?[]:$ret['data'];
  1074. if(!empty($productData)){
  1075. $newestProductIds=array_column($productData,'id');
  1076. $newestTypeAndTagData=$this->getTypeAndTagDataByProductId($newestProductIds);
  1077. foreach ($productData as &$productItem){
  1078. if(!empty($newestTypeAndTagData[$productItem['id']]['type_items'])){
  1079. $productItem['type_items']=$newestTypeAndTagData[$productItem['id']]['type_items'];
  1080. }else{
  1081. $productItem['type_items']=[];
  1082. }
  1083. if(!empty($newestTypeAndTagData[$productItem['id']]['tag_items'])){
  1084. $productItem['tag_items']=$newestTypeAndTagData[$productItem['id']]['tag_items'];
  1085. }else{
  1086. $productItem['tag_items']=[];
  1087. }
  1088. }
  1089. $ret['data']=$productData;
  1090. }
  1091. return $ret;
  1092. }
  1093. /**
  1094. * 搜索获取已发布的产品
  1095. * */
  1096. public function getSearchProductList($params){
  1097. if(empty($fields)){
  1098. $fields='a.id,a.title,b.urla';
  1099. }
  1100. $productList=$this->model->getPublishProductList($params,$fields);
  1101. return $productList;
  1102. }
  1103. /**
  1104. * 新闻排序
  1105. */
  1106. public function changeProductSort($productId, $sort)
  1107. {
  1108. $data = [];
  1109. $getData = $this->findOneById($productId, 'id,sort');
  1110. if ($sort == 0) { // 置顶
  1111. $sortData = $this->findOneBy([
  1112. 'sort' => $sort,
  1113. 'id' => ['<>', $productId]
  1114. ], 'id');
  1115. if (empty($sortData['id'])) {
  1116. throw new ApiException(1004, ['msg' => '当前已经是最高一行']);
  1117. }
  1118. if ($getData['sort'] == 0) {
  1119. $this->incrementBy([
  1120. 'id' => ['<>', $productId],
  1121. ], 'sort');
  1122. } else {
  1123. $this->incrementBy([
  1124. 'id' => ['<', $productId],
  1125. ], 'sort');
  1126. }
  1127. $upData['sort']= $sort;
  1128. } elseif ($sort == '-1') { // 上移
  1129. $upSortData = $this->model->where('sort', '<', $getData['sort'])
  1130. ->orderBy('sort', 'desc')->first();
  1131. if (empty($upSortData)) {
  1132. throw new ApiException(1004, ['msg' => '当前已经是最高一行']);
  1133. } else {
  1134. $upData = $upSortData->toArray();
  1135. }
  1136. } elseif ($sort == '+1') { // 下移
  1137. $downSortData = $this->model->where('sort', '>', $getData['sort'])
  1138. ->orderBy('sort', 'asc')->first();
  1139. if (empty($downSortData)) {
  1140. throw new ApiException(1004, ['msg' => '当前已经是最后一行']);
  1141. } else {
  1142. $upData = $downSortData->toArray();
  1143. }
  1144. }
  1145. $data['sort'] = $upData['sort'];
  1146. $this->updateBy([
  1147. 'sort' => $data['sort']
  1148. ], [
  1149. 'sort' => $getData['sort']
  1150. ]);
  1151. $is_top=0;
  1152. if($data['sort']==0){
  1153. $is_top=1;
  1154. }
  1155. $rst = $this->update($productId, [
  1156. 'sort' => $data['sort'],
  1157. 'is_top'=>$is_top
  1158. ]);
  1159. //更新所有页面缓存
  1160. WebFacade::clearPageCache('urla:');
  1161. return $rst;
  1162. }
  1163. public function getProductByIds($ids) {
  1164. $pageListData=$this->model->getProductByIds($ids);
  1165. if(!empty($pageListData)){
  1166. $ids=array_column($pageListData,'seo_id');
  1167. $seoList=[];
  1168. if(!empty($ids)){
  1169. $seoList=WebFacade:: getSeoListByIds($ids);
  1170. if(!empty($seoList)){
  1171. $seoList=mapByKey($seoList,'id');
  1172. }
  1173. }
  1174. foreach ($pageListData as &$pageItem){
  1175. $pageItem['type_items'] = [];
  1176. if (!empty($pageItem['type_ids'])) {
  1177. foreach ($pageItem['type_ids'] as $typeId) {
  1178. $type_info = $this->productTypeModel->getProductTypeInfo(["id"=>$typeId]);
  1179. if (!empty($type_info['expand_content'])) {
  1180. $type_info['expand_content'] = json_decode($type_info['expand_content'],true);
  1181. $type_info['expand_content'] = mapByKey($type_info['expand_content'],'key');
  1182. }
  1183. $pageItem['type_items'][] = $type_info;
  1184. }
  1185. }
  1186. $pageItem['seo_data']=empty($seoList[$pageItem['seo_id']])?[]:$seoList[$pageItem['seo_id']];
  1187. }
  1188. }
  1189. return $pageListData;
  1190. }
  1191. public function productCenterSync($params)
  1192. {
  1193. set_time_limit(1200);
  1194. ignore_user_abort(true);
  1195. $data = empty($params['list']) ? [] : $params['list'];
  1196. $productTypeData = $params['product_type_data'];
  1197. $productTagData = $params['product_tag_data'];
  1198. $isReplaceOss = $params['is_replace_oss'] ?? true;
  1199. $syncRet = ['succeed' => 0, 'error' => 0];
  1200. $userId = $this->getAuthUserId();
  1201. $productTypeSyncRe = $this->saveSyncProductTypeData($productTypeData, $userId);
  1202. $productTagSyncRe = $this->saveSyncProductTagData($productTagData, $userId);
  1203. $productData = array_column($data, 'product_data');
  1204. $productNameList = array_column($productData, 'name');
  1205. $productNameList = array_unique($productNameList);
  1206. $yetProductData = $this->model->newInstance()->alias('a')
  1207. ->where('a.status', '=', 0)
  1208. ->whereIn('a.title', $productNameList)
  1209. ->selectRaw('a.id,a.title AS name')
  1210. ->get();
  1211. if (!empty($yetProductData)) {
  1212. $yetProductData = $yetProductData->toArray();
  1213. $yetProductData = mapByKey($yetProductData, 'name');
  1214. } else {
  1215. $yetProductData = [];
  1216. }
  1217. foreach ($productData as $item) {
  1218. if (!empty($yetProductData[$item['name']])) {
  1219. $syncRet['error'] = ++$syncRet['error'];
  1220. continue;
  1221. }
  1222. $productItem = [];
  1223. $productItem['title'] = $item['name'];
  1224. if($isReplaceOss && !empty($item['image_url'])){
  1225. $item['image_url'] = UploadFileFacade::uploadRemoteImg($item['image_url']);
  1226. }
  1227. $productItem['image_url'] = $item['image_url'];
  1228. $productItem['image_alt'] = $item['image_alt'];
  1229. $productItem['main_image'] = $item['image_url'];
  1230. $productItem['main_image_alt'] = $item['image_alt'];
  1231. $productItem['brand'] = $item['brand_name'];
  1232. $productItem['model_nb'] = $item['goods_sn'];
  1233. if($isReplaceOss && !empty($item['content'])) {
  1234. $item['content'] = preg_replace_callback(
  1235. '/https?:\/\/[^\s^\"]*/',
  1236. function ($matches) {
  1237. return UploadFileFacade::uploadRemoteImg($matches[0]);
  1238. },
  1239. $item['content']
  1240. );
  1241. }
  1242. $productItem['content'] = $item['content'];
  1243. if($isReplaceOss && !empty($item['sub_image_urls'])) {
  1244. foreach ($item['sub_image_urls'] as &$subImage) {
  1245. $subImage['url'] = UploadFileFacade::uploadRemoteImg($subImage['url']);
  1246. }
  1247. }
  1248. $productItem['sub_image_urls'] = !empty($item['sub_image_urls']) ? json_encode($item['sub_image_urls'], true) : '';
  1249. $productItem['description'] = $item['description'];
  1250. $productItem['sort'] = $item['sort'];
  1251. $productItem['re_price'] = $item['re_price'];
  1252. $productItem['market_price'] = $item['market_price'];
  1253. $productItem['currency'] = $item['currency'];
  1254. if($isReplaceOss && !empty($item['file_url'])){
  1255. $item['file_url'] = UploadFileFacade::uploadRemoteImg($item['file_url']);
  1256. }
  1257. $productItem['download_url'] = $item['file_url'];
  1258. $productItem['user_id'] = $userId;
  1259. $productItem['create_time'] = nowTime();
  1260. $productItem['update_time'] = nowTime();
  1261. $productItem['pub_date'] = nowTime();
  1262. $newProductId = $this->model->insertGetId($productItem);
  1263. $this->addWebSeo($newProductId, $userId, $item['name'],
  1264. WebService::RELATION_TABLE_PRODUCT, $this->model);
  1265. if (!empty($item['cat_id']) && !empty($productTypeSyncRe[$item['cat_id']])) {
  1266. //分类处理
  1267. $this->productTypeRelationModel->addByProductId($newProductId, [$productTypeSyncRe[$item['cat_id']]]);
  1268. }
  1269. //分类标签
  1270. if (!empty($productTagSyncRe[$item['id']])) {
  1271. $this->productTagRelationModel->addByProductId($newProductId, $productTagSyncRe[$item['id']]);
  1272. }
  1273. $syncRet['succeed'] = ++$syncRet['succeed'];
  1274. }
  1275. $messageTitle = '产品中心同步商品至' . config('app.name') . '完成';
  1276. $messageContent = '成功同步商品:' . $syncRet['succeed'];
  1277. if (!empty($syncRet['error'])) {
  1278. $messageContent .= ';' . '商品名称重复导入失败:' . $syncRet['error'];
  1279. }
  1280. $syncRet['message'] = $messageTitle.$messageContent;
  1281. return $syncRet;
  1282. }
  1283. /**
  1284. * 保存同步产品类型数据
  1285. * */
  1286. public function saveSyncProductTypeData($productTypeData, $userId)
  1287. {
  1288. $productTypeSyncRe = [];
  1289. $syncProductTypeSourceData = [];
  1290. // 同步产品类型数据
  1291. foreach ($productTypeData as $subItem) {
  1292. if (empty($syncProductTypeSourceData[$subItem['id']])) {
  1293. $tempItem = [];
  1294. $tempItem['type_name'] = $subItem['type_name'];
  1295. $tempItem['parent_name'] = $subItem['parent_name'] ?? '';
  1296. $tempItem['grand_name'] = $subItem['grand_name'] ?? '';
  1297. $tempItem['level'] = $subItem['level'];
  1298. $tempItem['user_id'] = $userId;
  1299. $syncProductTypeSourceData[$subItem['id']] = $tempItem;
  1300. }
  1301. }
  1302. $nameList = array_column($syncProductTypeSourceData, 'type_name');
  1303. $yetData = [];
  1304. $insertData = [];
  1305. if (!empty($nameList)) {
  1306. $yetData = $this->productTypeModel->alias('a')
  1307. ->leftJoin('product_type as b', 'a.p_id', '=', 'b.id')
  1308. ->leftJoin('product_type as c', 'b.p_id', '=', 'c.id')
  1309. ->where('a.status', '=', 0)
  1310. ->whereIn('a.type_name', $nameList)
  1311. ->selectRaw('a.*,b.type_name AS parent_name,c.type_name AS grand_name')
  1312. ->get()->toArray();
  1313. }
  1314. if (!empty($yetData)) {
  1315. $yetData = mapByKey($yetData, 'type_name');
  1316. foreach ($syncProductTypeSourceData as $typeId => $item) {
  1317. if (!empty($yetData[$item['type_name']]) &&
  1318. $yetData[$item['type_name']]['parent_name'] == $item['parent_name'] &&
  1319. $yetData[$item['type_name']]['grand_name'] == $item['grand_name']
  1320. ) {
  1321. $productTypeSyncRe[$typeId] = $yetData[$item['type_name']]['id'];
  1322. } else {
  1323. $insertData[] = $item;
  1324. }
  1325. }
  1326. } else {
  1327. $insertData = $syncProductTypeSourceData;
  1328. }
  1329. foreach ($insertData as $typeId => $item) {
  1330. if ($item['level'] == 1) {
  1331. $newId = $this->insertProductType($userId, 0, 1, '', $item['type_name']);
  1332. } else if ($item['level'] == 2) {
  1333. $pId = $this->insertProductType($userId, 0, 1, '', $item['parent_name']);
  1334. $newId = $this->insertProductType($userId, $pId, 2, $pId, $item['type_name']);
  1335. } else if ($item['level'] == 3) {
  1336. $gId = $this->insertProductType($userId, 0, 1, '', $item['grand_name']);
  1337. $pId = $this->insertProductType($userId, $gId, 2, $gId, $item['parent_name']);
  1338. $newId = $this->insertProductType($userId, $pId, 3, $gId.','.$pId, $item['type_name']);
  1339. } else {
  1340. $newId = $this->insertProductType($userId, 0, 1, '', $item['type_name']);
  1341. }
  1342. $productTypeSyncRe[$typeId] = $newId;
  1343. }
  1344. return $productTypeSyncRe;
  1345. }
  1346. /**
  1347. * 插入产品分类
  1348. * @param $userId
  1349. * @param $parentId
  1350. * @param $level
  1351. * @param $path
  1352. * @param $name
  1353. * @return mixed
  1354. */
  1355. public function insertProductType($userId, $parentId, $level, $path, $name)
  1356. {
  1357. $old = $this->productTypeModel->alias('a')
  1358. ->where('a.status', '=', 0)
  1359. ->where('a.type_name', '=', $name)
  1360. ->where('a.level', '=', $level)
  1361. ->where('a.p_id', '=', $parentId)
  1362. ->first();
  1363. if(!empty($old)) {
  1364. $old = $old->toArray();
  1365. $id = $old['id'];
  1366. } else {
  1367. $insertItem = [];
  1368. $insertItem['user_id'] = $userId;
  1369. $insertItem['p_id'] = $parentId;
  1370. $insertItem['level'] = $level;
  1371. $insertItem['path'] = $path;
  1372. $insertItem['path_name'] = $name;
  1373. $insertItem['description'] = $name;
  1374. $insertItem['type_name'] = $name;
  1375. $insertItem['create_time'] = nowTime();
  1376. $insertItem['update_time'] = nowTime();
  1377. $id = $this->productTypeModel->insertGetId($insertItem);
  1378. //添加SEO信息
  1379. $this->addWebSeo($id, $userId, $name,
  1380. WebService::RELATION_TABLE_PRODUCT_TYPE, $this->productTypeModel);
  1381. }
  1382. return $id;
  1383. }
  1384. /**
  1385. * 保存同步产品标签数据
  1386. * */
  1387. public function saveSyncProductTagData($productTagData, $userId)
  1388. {
  1389. $productTagSyncRe = [];
  1390. $syncProductTagSourceData = [];
  1391. // 同步产品标签数据
  1392. $nameList = [];
  1393. foreach ($productTagData as $goodId => $tagItem) {
  1394. foreach ($tagItem as $subItem) {
  1395. if (empty($syncProductTagSourceData[$goodId][$subItem['id']])) {
  1396. $tempItem = [];
  1397. $tempItem['tag_name'] = $subItem['tag_name'];
  1398. $tempItem['user_id'] = $userId;
  1399. $syncProductTagSourceData[$goodId][$subItem['id']] = $tempItem;
  1400. $nameList[] = $subItem['tag_name'];
  1401. }
  1402. }
  1403. }
  1404. $yetData = [];
  1405. if (!empty($nameList)) {
  1406. $nameList = array_unique($nameList);
  1407. $yetData = $this->productTagModel->alias('a')
  1408. ->where('a.status', '<', 2)
  1409. ->whereIn('a.tag_name', $nameList)->get()->toArray();
  1410. }
  1411. if (!empty($yetData)) {
  1412. $yetData = mapByKey($yetData, 'tag_name');
  1413. }
  1414. foreach ($syncProductTagSourceData as $goodId => $item) {
  1415. foreach ($item as $subItem) {
  1416. $item['user_id'] = $userId;
  1417. if (!empty($yetData[$subItem['tag_name']])) {
  1418. $productTagSyncRe[$goodId][] = $yetData[$subItem['tag_name']]['id'];
  1419. } else {
  1420. $newId = $this->productTagModel->insertGetId($subItem);
  1421. $this->addWebSeo($newId, $userId, $subItem['tag_name'],
  1422. WebService::RELATION_TABLE_PRODUCT_TAG, $this->productTagModel);
  1423. $yetData[$subItem['tag_name']] = $subItem;
  1424. $yetData[$subItem['tag_name']]['id'] = $newId;
  1425. $productTagSyncRe[$goodId][] = $newId;
  1426. }
  1427. }
  1428. }
  1429. return $productTagSyncRe;
  1430. }
  1431. public function addWebSeo($id, $userId, $sourceName, $table, $model)
  1432. {
  1433. $py = app()->make(PinYinService::class);
  1434. $name = strtolower($py->getAllPY($sourceName));
  1435. $nameUrl = preg_replace('/[^a-zA-Z0-9_u4e00-u9fa5]/', '-', $name);
  1436. $seoParams = [];
  1437. $seoParams['relation_table'] = $table;
  1438. $seoParams['relation_id'] = $id;
  1439. if (strlen($nameUrl) > 200) {
  1440. $nameUrl = substr($nameUrl, 0, 200);
  1441. }
  1442. $urlEx = WebFacade::checkUrlaUnique($nameUrl);
  1443. if (!$urlEx) {
  1444. $nameUrl .= '-' . strtolower(uniqid());
  1445. }
  1446. $seoParams['urla'] = $nameUrl;
  1447. $seoParams['seo_title'] = substr($sourceName, 0, 255);
  1448. $seoParams['seo_keyword'] = substr($sourceName, 0, 255);
  1449. $seoParams['seo_describe'] = substr($sourceName, 0, 255);
  1450. $seoParams['user_id'] = $userId;
  1451. $urlaId = WebFacade::saveSeoData($seoParams);
  1452. $model->newInstance()->where('id', '=', $id)->update(['seo_id' => $urlaId]);
  1453. }
  1454. /**
  1455. * 批量修改类型
  1456. * @param $params
  1457. * @return true
  1458. */
  1459. public function typePluralEdit($params)
  1460. {
  1461. $userId = $this->getAuthUserId();
  1462. $ret = 1;
  1463. foreach ($params['ids'] as $v) {
  1464. $ret = $this->productTypeRelationModel->addByProductId($v, $params['type_ids'], $userId);
  1465. }
  1466. return $ret;
  1467. }
  1468. /**
  1469. * 批量修改标签
  1470. * @param $params
  1471. * @return true
  1472. */
  1473. public function tagPluralEdit($params)
  1474. {
  1475. $userId = $this->getAuthUserId();
  1476. $ret = 1;
  1477. foreach ($params['ids'] as $v) {
  1478. $ret = $this->productTagRelationModel->addByProductId($v, $params['tag_ids'], $userId);
  1479. }
  1480. return $ret;
  1481. }
  1482. /**
  1483. * 批量删除
  1484. * @param $params
  1485. * @return mixed
  1486. */
  1487. public function batchDelete($params)
  1488. {
  1489. $ids = $params['ids'];
  1490. $rst = $this->model->whereIn('id', $ids)->update(['status' => 2]);
  1491. //删除处理
  1492. if ($rst) {
  1493. $this->productTypeRelationModel->deleteByProductId($ids);
  1494. $this->productTagRelationModel->deleteByProductId($ids);
  1495. }
  1496. return $rst;
  1497. }
  1498. /**
  1499. * 批量修改状态
  1500. * @param $params
  1501. * @return mixed
  1502. */
  1503. public function batchStatus($params)
  1504. {
  1505. $ids = $params['ids'];
  1506. $status = $params['status'];
  1507. $rst = $this->model->whereIn('id', $ids)->update(['status' => $status]);
  1508. return $rst;
  1509. }
  1510. }