Product.php 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129
  1. <?php namespace App\Http\Controllers\Admin;
  2. use App\Http\Requests\Admin\Product as Request;
  3. use App\Models\AdminHistory;
  4. use App\Models\Business;
  5. use App\Models\City;
  6. use App\Models\OrdersProduct;
  7. use App\Models\Producer;
  8. use App\Models\Product as Model;
  9. use Illuminate\Support\Carbon;
  10. use App\Models\Product\Spec as ProductSpec;
  11. use App\Models\Product\Type as ProductType;
  12. use App\Models\Product\Attr as ProductAttr;
  13. use App\Models\Product\Skus as ProductSkus;
  14. use App\Models\Product\City as ProductCity;
  15. use App\Models\ProductPhoto;
  16. use Illuminate\Support\Facades\DB;
  17. use App\Models\WeiBan\Tags as WeiBanTags;
  18. use Intervention\Image\Facades\Image;
  19. use Intervention\Image\Gd\Font;
  20. use App\Facades\Servers\WechatMini\Mini;
  21. /**
  22. * 产品管理
  23. *
  24. * @author 刘相欣
  25. *
  26. */
  27. class Product extends Auth{
  28. protected function _initialize(){
  29. parent::_initialize();
  30. $this->assign('breadcrumb1','基础信息');
  31. $this->assign('breadcrumb2','产品管理');
  32. }
  33. /**
  34. * 首页列表
  35. *
  36. * */
  37. public function index(Model $Model,City $City,ProductCity $ProductCity,OrdersProduct $OrdersProduct,AdminHistory $AdminHistory,Business $Business){
  38. // 接受参数
  39. $code = request('product_code','');
  40. $name = request('name','');
  41. $status = request('status');
  42. $startTime = request('start_time','');
  43. $businessId = request('business_id','');
  44. $cityIds = request('city_ids',[]);
  45. // 编码转ID
  46. $id = $code ? $Model->codeToId($code) : 0;
  47. // 查询条件
  48. $map = [];
  49. // 是否有城市
  50. $whereIn = $cityIds ? $cityIds : [];
  51. // 编码ID
  52. if( $id ) $map[] = ['product.id','=',$id];
  53. if( $businessId ) $map[] = ['product.business_id','=',$businessId];
  54. if( $name ) $map[] = ['product.name','like','%'.$name.'%'];
  55. if( $startTime ) $map[] = ['product.insert_time','>=',Carbon::createFromFormat('Y-m-d',$startTime)->startOfDay()->getTimestamp()];
  56. if( $startTime ) $map[] = ['product.insert_time','<=',Carbon::createFromFormat('Y-m-d',$startTime)->endOfDay()->getTimestamp()];
  57. if( !is_null($status) ) $map[] = ['product.status','=',$status];
  58. $session = session('userRule');
  59. if ($session){
  60. $map[] = ['product.company_id','=',$session['company_id']];
  61. if ($session['business_id']){
  62. $map[] = ['product.business_id','=',$session['business_id']];
  63. }
  64. if ($session['menu_type'] == 1 && $session['data_type'] == 2){
  65. $shopIds = Business::query()->where('leader_uid',$session['admin_uid'])->pluck('id')->toArray();
  66. }
  67. }
  68. // 查询数据
  69. $list = $Model->query();
  70. if( $whereIn ) $list = $list->join('product_city','product_city.product_id','=','product.id')->whereIn('product_city.city_id',$whereIn);
  71. if(isset($shopIds)) $list = $list->whereIn('product.business_id',$shopIds);
  72. $list = $list->groupBy('product.id')
  73. ->where($map)
  74. ->orderBy('product.sort')
  75. ->orderByDesc('product.id')
  76. ->select(['product.*'])
  77. ->paginate(request('limit',config('page_num',10)))->appends(request()->all());
  78. // 统计销量
  79. $salesList = $OrdersProduct->query()->where([['status','<>',4]])->whereIn('product_id',array_column($list->items(),'id'))->groupBy('product_id')->select([DB::raw('sum(`buy_num`) as sales_total'),'product_id'])->pluck('sales_total','product_id')->toArray();
  80. // 循环处理数据
  81. foreach ($list as $key => $value) {
  82. // 判断总库存
  83. if( !$value['stock_total'] ) {
  84. // 以首次添加时的为准
  85. $value['stock_total']= (int) $AdminHistory->query()->where([['table_name','=','product'],['primary_id','=',$value['id']],['notes_type','=',1],['column_name','=','stock']])->orderBy('update_time')->value('after_value');
  86. // 修改库存
  87. $Model->edit($value['id'],['stock_total'=>$value['stock_total']]);
  88. }
  89. // id转编号
  90. $value['product_code'] = $Model->idToCode($value['id']);
  91. $value['business_name']= Business::query()->where('id',$value['business_id'])->value('name');
  92. // id转编号
  93. $cityName = [];
  94. // 获取城市列表
  95. $cityIds = $ProductCity->query()->where([['product_id','=',$value['id']]])->pluck('city_id');
  96. // 如果有的话
  97. if( $cityIds ) {
  98. // 返回结果
  99. foreach ($cityIds as $cityId) {
  100. // 城市ID
  101. if( $cityId == 1 ) continue;
  102. // 获取城市名
  103. $cityName[] = $City->getOne($cityId,'name');
  104. }
  105. }
  106. // 销量统计
  107. $value['sales_total'] = isset($salesList[$value['id']])?$salesList[$value['id']]:0;
  108. // 城市
  109. $value['city_name'] = implode('、',$cityName);
  110. // 重组
  111. $list[$key] = $value;
  112. }
  113. // 获取列表
  114. $cityList = $City->getCityList();
  115. $businessList = $Business->getList();
  116. // 分配数据
  117. $this->assign('empty', '<tr><td colspan="20">~~暂无数据</td></tr>');
  118. $this->assign('cityList',$cityList);
  119. $this->assign('businessList',$businessList);
  120. $this->assign('list', $list);
  121. // 加载模板
  122. return $this->fetch();
  123. }
  124. /**
  125. * 获取小程序海报
  126. *
  127. */
  128. public function get_poster(Model $Model){
  129. // 接收参数
  130. $id = request('id',0);
  131. // // 查询用户
  132. $oldData = $Model->where(['id'=>$id])->first();
  133. // // 错误告知
  134. if( !$oldData ) return $this->error('查无数据');
  135. // url有效期
  136. $urlLink = '';//$this->getUrlLink($id);
  137. // 获取分享海报图片
  138. $result = $this->getShareImage('id='.$id,$oldData);
  139. // 错误提示
  140. if( isset($result['error']) ) return $this->error($result['error']);
  141. // 分配数据
  142. $this->assign('image',$result);
  143. $this->assign('urlLink',$urlLink);
  144. $this->assign('oldData',$oldData);
  145. $this->assign('crumbs','海报');
  146. // 加载模板
  147. return $this->fetch();
  148. }
  149. /**
  150. * 获取小程序链接
  151. *
  152. */
  153. private function getUrlLink($id){
  154. // 结果数据
  155. $link = cache('admin:product:urllink:product_id'.$id);
  156. // 不存在数据
  157. if ( is_null($link) ) {
  158. // 从数据库获取数据
  159. $link = Mini::getUrlLink('pages/product/index','product_id='.$id);
  160. // 存起来
  161. cache(['admin:product:urllink:product_id'.$id=>$link],$link ? now()->addDays(23) : now()->addMinutes(3));
  162. }
  163. // 返回结果
  164. return $link;
  165. }
  166. /**
  167. * 获取分享海报图片
  168. * @param int $scene 场景值
  169. *
  170. */
  171. private function getShareImage($scene,$oldData){
  172. // 尝试执行
  173. try {
  174. // 加载图片
  175. $image = Image::make(public_path('uploads/images/poster/').'product.png');
  176. // 产品缩略图
  177. $thumb = Image::make(path_compat($oldData['thumb']))->resize(1000,1000);
  178. // 设置文字样式(字体、大小、颜色等)
  179. $fontPath = public_path().'/fonts/msyh14.ttf';// 指定字体文件路径
  180. // 生成小程序二维码
  181. $qrcode = Mini::getUnlimit($scene,['page'=>'pages/product/index','width'=>280,'is_hyaline'=>true]);
  182. // 错误提示
  183. if( isset($qrcode['error']) ) return $qrcode;
  184. // 加载图片
  185. $qrcode = Image::make($qrcode)->resize(250,250);
  186. // 插入图片
  187. $image->insert($thumb,'top-center',0,130);
  188. // 插入图片
  189. $image->insert($qrcode,'bottom-left',120,120);
  190. // 给图片写入文字
  191. $image->text('¥'.$oldData['price'], 360,1280,function (Font $font) use ($fontPath) {
  192. $font->file($fontPath); // 字体文件地址
  193. $font->size(88); // 字体大小
  194. $font->color('#333333');
  195. $font->align('left');
  196. });
  197. // 给图片写入文字
  198. $image->text($oldData['name'], 120,1380,function (Font $font) use ($fontPath) {
  199. $font->file($fontPath); // 字体文件地址
  200. $font->size(48); // 字体大小
  201. $font->color('#333333');
  202. $font->align('left');
  203. });
  204. // 转码成字符串
  205. $image = $image->encode('jpg', 90)->__toString();
  206. // 转base64
  207. $base64 = 'data:image/jpg;base64,' . base64_encode($image);
  208. // 返回结果
  209. return $base64;
  210. } catch (\Throwable $th) {
  211. // 错误提示
  212. return ['error'=>$th->getMessage()];
  213. }
  214. }
  215. /**
  216. * 添加
  217. *
  218. * */
  219. public function add(Request $request, Model $Model, WeiBanTags $WeiBanTags, ProductPhoto $ProductPhoto, Producer $Producer, Business $Business, ProductType $ProductType, ProductSpec $ProductSpec, ProductAttr $ProductAttr, ProductSkus $ProductSkus, City $City, ProductCity $ProductCity){
  220. if( request()->isMethod('post') ){
  221. // 验证参数
  222. $request->scene('add')->validate();
  223. // 组合数据
  224. $data['name'] = request('name','');
  225. $data['thumb'] = request('thumb','');
  226. $data['poster'] = request('poster','');
  227. $data['spec'] = request('spec','');
  228. $data['price'] = request('price',0);
  229. $data['market_price'] = request('market_price',0);
  230. $data['producer_id'] = request('producer_id',0);
  231. $data['business_id'] = request('business_id',0);
  232. $data['quota'] = request('quota',0);
  233. $data['min_quota'] = request('min_quota',0);
  234. $data['quota_start'] = request('quota_start','');
  235. $data['quota_end'] = request('quota_end','');
  236. $data['puton_time'] = request('puton_time','');
  237. $data['putoff_time'] = request('putoff_time','');
  238. $data['stock'] = request('stock',0);
  239. $data['status'] = 1;
  240. $data['admin_uid'] = admin('uid');
  241. $description = request('description','');
  242. $attr = request('attr',[]);
  243. $skuList = request('sku',[]);
  244. $cityIds = request('city_ids',[]);
  245. $photoList = request('photo_list',[]);
  246. $tagScope = request('tag_scope',[]);
  247. $data['tag_scope'] = implode(',',$tagScope);
  248. $tagExclude = request('tag_exclude',[]);
  249. $data['tag_exclude'] = implode(',',$tagExclude);
  250. $session = session('userRule');
  251. if ($session){
  252. $data['company_id'] = $session['company_id'];
  253. }
  254. // 循环
  255. foreach ($photoList as $key => $value) {
  256. if( !$value ) unset($photoList[$key]);
  257. }
  258. $photoList = array_values($photoList);
  259. // 如果没有选择,则意味着全部
  260. $cityIds = $cityIds ? $cityIds : [1];
  261. $data['quota_start'] = $data['quota_start'] ? strtotime($data['quota_start']) : 0;
  262. $data['quota_end'] = $data['quota_end'] ? strtotime($data['quota_end']) : 0;
  263. $data['puton_time'] = $data['puton_time'] ? strtotime($data['puton_time']) : 0;
  264. $data['putoff_time'] = $data['putoff_time'] ? strtotime($data['putoff_time']) : 0;
  265. // 限购提示
  266. if( !$data['thumb'] ) return json_send(['code'=>'error','msg'=>'请上传产品主图','data'=>['error'=>'请上传产品主图']]);
  267. // 限购提示
  268. if( $attr && !$skuList ) return json_send(['code'=>'error','msg'=>'规格属性存在时,请填写SKU','data'=>['error'=>'规格属性存在时,请填写SKU']]);
  269. // 限购提示
  270. if( $data['quota'] && ( !$data['quota_start'] || !$data['quota_end'] )) return json_send(['code'=>'error','msg'=>'限购必填限购时间','data'=>['error'=>'限购必填限购时间']]);
  271. // 限购提示
  272. if( $data['min_quota'] > $data['quota'] ) return json_send(['code'=>'error','msg'=>'起购数量请勿大于限购数量','data'=>['error'=>'起购数量请勿大于限购数量']]);
  273. // SKU存在的时候,判断限购数量
  274. if( $skuList ) {
  275. // 循环处理
  276. foreach ($skuList as $attrNames => $value) {
  277. // SKU限购,所以限购时间也必须填
  278. if( $value['quota'] && ( !$data['quota_start'] || !$data['quota_end'] )) return json_send(['code'=>'error','msg'=>'SKU限购时,请填限购时间','data'=>['error'=>'SKU限购时,请填限购时间']]);
  279. // 限购提示
  280. if( $value['min_quota'] > $value['quota'] ) return json_send(['code'=>'error','msg'=>$attrNames.'起购数量请勿大于限购数量','data'=>['error'=>$attrNames.'起购数量请勿大于限购数量']]);
  281. // 提示起购数量异常,如果总起购数量小于SKU起购数量,提示
  282. if( $value['min_quota'] && $value['min_quota'] < $data['min_quota'] ) return json_send(['code'=>'error','msg'=>'SKU的起购数量不能小于总起购数量','data'=>['error'=>'SKU的起购数量不能小于总起购数量']]);
  283. }
  284. // 限购数量
  285. $quota = array_sum(array_column($skuList,'quota'));
  286. // 提示限购数量异常
  287. if( $data['quota']&& $data['quota'] < $quota ) return json_send(['code'=>'error','msg'=>'总限购数量不能小于SKU的限购数量','data'=>['error'=>'总限购数量不能小于SKU的限购数量']]);
  288. }
  289. // 上下架
  290. if( $data['puton_time'] ) {
  291. // 下架时间必填
  292. if( !$data['putoff_time'] ) return json_send(['code'=>'error','msg'=>'请填写自动下架时间','data'=>['error'=>'自动上架请填写下架时间']]);
  293. // 下架时间必填
  294. if( $data['putoff_time'] <= $data['puton_time'] ) return json_send(['code'=>'error','msg'=>'下架时间请晚于上架时间','data'=>['error'=>'下架时间请晚于上架时间']]);
  295. }
  296. // 总库存
  297. if( $skuList ) $data['stock'] = array_sum(array_column($skuList,'stock'));
  298. // 总库存
  299. $data['stock_total'] = $data['stock'];
  300. // 获取规格属性
  301. $specAttr = $this->getSpecAttr($attr,$ProductSpec,true);
  302. // 开启事务
  303. DB::beginTransaction();
  304. try {
  305. // 写入
  306. $id = $Model->add($data);
  307. // 提示新增失败
  308. if( !$id ) {
  309. // 回滚
  310. DB::rollBack();
  311. // 提示
  312. return json_send(['code'=>'error','msg'=>'新增失败']);
  313. }
  314. // 组合数据
  315. foreach ($specAttr as $key => $value) {
  316. // 查询结果
  317. $value['id'] = $ProductAttr->upsertByName($value,$id);
  318. // 提示新增失败
  319. if( !$value['id'] ) {
  320. // 回滚
  321. DB::rollBack();
  322. // 提示
  323. return json_send(['code'=>'error','msg'=>'商品属性新增失败']);
  324. }
  325. // 重组
  326. $specAttr[$key] = $value;
  327. }
  328. // 图册
  329. foreach ($photoList as $key => $value) {
  330. // 整理数据
  331. $value = ['sort'=>$key,'thumb'=>$value,'product_id'=>$id,'insert_time'=>time(),'update_time'=>time()];
  332. // 重新整理
  333. $photoList[$key] = $value;
  334. }
  335. // 存在图册
  336. if( $photoList ) {
  337. // 写入失败
  338. $result = $ProductPhoto->query()->insert($photoList);
  339. // 提示新增失败
  340. if( !$result ) {
  341. // 回滚
  342. DB::rollBack();
  343. // 提示
  344. return json_send(['code'=>'error','msg'=>'商品图册写入失败']);
  345. }
  346. }
  347. // 循环SKU
  348. foreach ($skuList as $attrNames => $value) {
  349. // 属性ID值
  350. $value['attr_ids'] = [];
  351. // 规格属性值组合
  352. $value['attr_names']= $attrNames;
  353. // 切割成数据
  354. $names = explode(',',$attrNames);
  355. // 循环处理
  356. foreach ($names as $name) {
  357. foreach ($specAttr as $vv) {
  358. if( $name == $vv['name'] ) {
  359. // 提示新增失败
  360. if( !$vv['id'] ) {
  361. // 回滚
  362. DB::rollBack();
  363. // 提示
  364. return json_send(['code'=>'error','msg'=>'属性SKU匹配失败']);
  365. }
  366. $value['attr_ids'][] = $vv['id'];
  367. }
  368. }
  369. }
  370. // 转成好存储的数据
  371. $value['attr_ids'] = implode(',',$value['attr_ids']);
  372. // 转成好存储的数据
  373. $value['product_id'] = $id;
  374. // 转成好存储的数据
  375. $value['sku_thumb'] = (string)$value['sku_thumb'];
  376. // 转成好存储的数据
  377. $value['stock_total']= $value['stock'];
  378. // 转成好存储的数据
  379. $value['insert_time']= time();
  380. // 转成好存储的数据
  381. $value['update_time']= time();
  382. // SKU结果
  383. $skuList[$attrNames] = $value;
  384. }
  385. // 循环城市范围
  386. foreach ($cityIds as $key => $value) {
  387. // 重组数据
  388. $cityIds[$key] = ['city_id'=>$value,'product_id'=>$id,'insert_time'=>time(),'update_time'=>time()];
  389. }
  390. // 写入城市范围
  391. $ProductCity->query()->insert($cityIds);
  392. // 返回结果
  393. $result = $ProductSkus->insert($skuList);
  394. // 提示新增失败
  395. if( !$result ) {
  396. // 回滚
  397. DB::rollBack();
  398. // 提示
  399. return json_send(['code'=>'error','msg'=>'SKU插入失败']);
  400. }
  401. // 更新内容
  402. $Model->updateDesc($id,$description);
  403. // 提交
  404. DB::commit();
  405. // 记录行为
  406. $this->addAdminHistory(admin('uid'),$Model->getTable(),$id,1,[],$data);
  407. // 告知结果
  408. return json_send(['code'=>'success','msg'=>'新增成功','action'=>'add']);
  409. } catch (\Throwable $th) {
  410. // 回滚
  411. DB::rollBack();
  412. // 提示
  413. return json_send(['code'=>'error','msg'=>'系统异常,写入失败','data'=>$th->getMessage()]);
  414. }
  415. }
  416. // 获取类型数据
  417. $typeList = $ProductType->getList();
  418. $cityList = $City->getCityList();
  419. $businessList = $Business->getList();
  420. $producerList = $Producer->getList();
  421. // 标签列表
  422. $tagData = $WeiBanTags->query()->groupBy('group')->groupBy('name')->get(['group','name'])->toArray();
  423. // 标签列表
  424. $tagList = [];
  425. // 循环数据
  426. foreach ($tagData as $value) {
  427. $tagList[$value['group']][] = $value['name'];
  428. }
  429. // 分配数据
  430. $this->assign('crumbs','新增');
  431. $this->assign('tagList',$tagList);
  432. $this->assign('typeList',$typeList);
  433. $this->assign('cityList',$cityList);
  434. $this->assign('businessList',$businessList);
  435. $this->assign('producerList',$producerList);
  436. // 加载模板
  437. return $this->fetch();
  438. }
  439. /**
  440. * 编辑
  441. *
  442. * */
  443. public function edit(Request $request, Model $Model, WeiBanTags $WeiBanTags, ProductPhoto $ProductPhoto, Producer $Producer, Business $Business, ProductType $ProductType, ProductSpec $ProductSpec, ProductAttr $ProductAttr, ProductSkus $ProductSkus, City $City, ProductCity $ProductCity){
  444. if(request()->isMethod('post')){
  445. // 验证参数
  446. $request->scene('edit')->validate();
  447. // 组合数据
  448. $id = request('id',0);
  449. $data['name'] = request('name','');
  450. $data['thumb'] = request('thumb','');
  451. $data['poster'] = request('poster','');
  452. $data['spec'] = request('spec','');
  453. $data['price'] = request('price',0);
  454. $data['market_price'] = request('market_price',0);
  455. $data['quota'] = request('quota',0);
  456. $data['min_quota'] = request('min_quota',0);
  457. $data['quota_start'] = request('quota_start','');
  458. $data['quota_end'] = request('quota_end','');
  459. $data['puton_time'] = request('puton_time','');
  460. $data['putoff_time'] = request('putoff_time','');
  461. $data['producer_id'] = request('producer_id',0);
  462. $data['business_id'] = request('business_id',0);
  463. $data['stock'] = request('stock',0);
  464. $data['status'] = 1;
  465. $description = request('description','');
  466. $attr = request('attr',[]);
  467. $skuList = request('sku',[]);
  468. $cityIds = request('city_ids',[]);
  469. $photoList = request('photo_list',[]);
  470. $tagScope = request('tag_scope',[]);
  471. $data['tag_scope'] = implode(',',$tagScope);
  472. $tagExclude = request('tag_exclude',[]);
  473. $data['tag_exclude'] = implode(',',$tagExclude);
  474. // 循环
  475. foreach ($photoList as $key => $value) {
  476. if( !$value ) unset($photoList[$key]);
  477. }
  478. $photoList = array_values($photoList);
  479. // 如果没有选择,则意味着全部
  480. $cityIds = $cityIds ? $cityIds : [1];
  481. $data['quota_start'] = $data['quota_start'] ? strtotime($data['quota_start']) : 0;
  482. $data['quota_end'] = $data['quota_end'] ? strtotime($data['quota_end']) : 0;
  483. $data['puton_time'] = $data['puton_time'] ? strtotime($data['puton_time']) : 0;
  484. $data['putoff_time'] = $data['putoff_time'] ? strtotime($data['putoff_time']) : 0;
  485. // 限购提示
  486. if( !$data['thumb'] ) return json_send(['code'=>'error','msg'=>'请上传产品主图','data'=>['error'=>'请上传产品主图']]);
  487. // 限购提示
  488. if( $attr && !$skuList ) return json_send(['code'=>'error','msg'=>'规格属性存在时,请填写SKU','data'=>['error'=>'规格属性存在时,请填写SKU']]);
  489. // 限购提示
  490. if( $data['quota'] && ( !$data['quota_start'] || !$data['quota_end'] )) return json_send(['code'=>'error','msg'=>'限购必填限购时间','data'=>['error'=>'限购必填限购时间']]);
  491. // 限购提示
  492. if( $data['min_quota'] > $data['quota'] ) return json_send(['code'=>'error','msg'=>'起购数量请勿大于限购数量','data'=>['error'=>'起购数量请勿大于限购数量']]);
  493. // SKU存在的时候,判断限购数量
  494. if( $skuList ) {
  495. // 循环处理
  496. foreach ($skuList as $attrNames => $value) {
  497. // SKU限购,所以限购时间也必须填
  498. if( $value['quota'] && ( !$data['quota_start'] || !$data['quota_end'] )) return json_send(['code'=>'error','msg'=>'SKU限购时,请填限购时间','data'=>['error'=>'SKU限购时,请填限购时间']]);
  499. // 限购提示
  500. if( $value['min_quota'] > $value['quota'] ) return json_send(['code'=>'error','msg'=>$attrNames.'起购数量请勿大于限购数量','data'=>['error'=>$attrNames.'起购数量请勿大于限购数量']]);
  501. // 提示起购数量异常,如果总起购数量小于SKU起购数量,提示
  502. if( $value['min_quota'] && $value['min_quota'] < $data['min_quota'] ) return json_send(['code'=>'error','msg'=>'SKU的起购数量不能小于总起购数量','data'=>['error'=>'SKU的起购数量不能小于总起购数量']]);
  503. }
  504. // 限购数量
  505. $quota = array_sum(array_column($skuList,'quota'));
  506. // 提示限购数量异常
  507. if( $data['quota']&& $data['quota'] < $quota ) return json_send(['code'=>'error','msg'=>'总限购数量不能小于SKU的限购数量','data'=>['error'=>'总限购数量不能小于SKU的限购数量']]);
  508. }
  509. // 上下架
  510. if( $data['puton_time'] ) {
  511. // 下架时间必填
  512. if( !$data['putoff_time'] ) return json_send(['code'=>'error','msg'=>'请填写自动下架时间','data'=>['error'=>'自动上架请填写下架时间']]);
  513. // 下架时间必填
  514. if( $data['putoff_time'] <= $data['puton_time'] ) return json_send(['code'=>'error','msg'=>'下架时间请晚于上架时间','data'=>['error'=>'下架时间请晚于上架时间']]);
  515. }
  516. // 总库存
  517. if( $skuList ) $data['stock'] = array_sum(array_column($skuList,'stock'));
  518. // 总库存
  519. $data['stock_total'] = $data['stock'];
  520. // 获取规格属性
  521. $specAttr = $this->getSpecAttr($attr,$ProductSpec,true);
  522. // 开启事务
  523. DB::beginTransaction();
  524. try {
  525. // 写入
  526. $result = $Model->edit($id,$data);
  527. // 提示新增失败
  528. if( !$result ) {
  529. // 回滚
  530. DB::rollBack();
  531. // 提示
  532. return json_send(['code'=>'error','msg'=>'修改失败']);
  533. }
  534. // 获取旧图册
  535. $oldPhoto = $ProductPhoto->getListByProductId($id);
  536. // 循环个数
  537. for ($i=0; $i < 4; $i++) {
  538. // 如果存在旧数据与新数据,修改
  539. if( isset($oldPhoto[$i]) && isset($photoList[$i]) ) $ProductPhoto->query()->where([['product_id','=',$id],['sort','=',$i]])->update(['thumb'=>(string)$photoList[$i],'update_time'=>time()]);
  540. // 如果存在旧数据,不存在新数据,删除
  541. if( isset($oldPhoto[$i]) && !isset($photoList[$i]) ) $ProductPhoto->query()->where([['product_id','=',$id],['sort','=',$i]])->delete();
  542. // 如果不存在旧数据,存在新数据,新增
  543. if( !isset($oldPhoto[$i]) && isset($photoList[$i]) ) $ProductPhoto->add(['sort'=>$i,'product_id'=>$id,'thumb'=>(string)$photoList[$i],'insert_time'=>time(),'update_time'=>time()]);
  544. }
  545. // 组合数据
  546. foreach ($specAttr as $key => $value) {
  547. // 查询结果
  548. $value['id'] = $ProductAttr->upsertByName($value,$id);
  549. // 提示新增失败
  550. if( !$value['id'] ) {
  551. // 回滚
  552. DB::rollBack();
  553. // 提示
  554. return json_send(['code'=>'error','msg'=>'商品属性新增失败']);
  555. }
  556. // 重组
  557. $specAttr[$key] = $value;
  558. }
  559. // 如果不在这个属性列表中的数据删除
  560. $ProductAttr->query()->where([['product_id','=',$id]])->whereNotIn('id',array_column($specAttr,'id'))->delete();
  561. // 循环SKU
  562. foreach ($skuList as $attrNames => $value) {
  563. // 属性ID值
  564. $value['attr_ids'] = [];
  565. // 规格属性值组合
  566. $value['attr_names']= $attrNames;
  567. // 切割成数据
  568. $names = explode(',',$attrNames);
  569. // 循环处理
  570. foreach ($names as $name) {
  571. foreach ($specAttr as $vv) {
  572. if( $name == $vv['name'] ) {
  573. // 提示新增失败
  574. if( !$vv['id'] ) {
  575. // 回滚
  576. DB::rollBack();
  577. // 提示
  578. return json_send(['code'=>'error','msg'=>'属性SKU匹配失败']);
  579. }
  580. $value['attr_ids'][] = $vv['id'];
  581. }
  582. }
  583. }
  584. // 转成好存储的数据
  585. $value['attr_ids'] = implode(',',$value['attr_ids']);
  586. // 转成好存储的数据
  587. $value['sku_thumb'] = (string)$value['sku_thumb'];
  588. // 转成好存储的数据
  589. $value['stock_total']= $value['stock'];
  590. // 转成好存储的数据
  591. $value['product_id']= $id;
  592. // 查询
  593. $oldSkuId = $ProductSkus->query()->where([['product_id','=',$id],['attr_ids','=',$value['attr_ids']]])->value('id');
  594. // 判断是否存在ID
  595. $value['id'] = $oldSkuId ? $ProductSkus->edit($oldSkuId,$value) : $ProductSkus->add($value);
  596. // SKU结果
  597. $skuList[$attrNames]= $value;
  598. }
  599. // 如果不在这个属性列表中的数据删除
  600. $ProductSkus->query()->where([['product_id','=',$id]])->whereNotIn('id',array_column($skuList,'id'))->delete();
  601. // 获取之前的城市ID
  602. $oldCityIds = $ProductCity->getListByProductId($id);
  603. // 循环城市范围
  604. foreach ($cityIds as $key => $value) {
  605. // 不存在则新增
  606. if( !in_array($value,$oldCityIds) ) $ProductCity->add(['city_id'=>$value,'product_id'=>$id]);
  607. }
  608. // 不存在的城市删除
  609. $ProductCity->query()->where([['product_id','=',$id]])->whereNotIn('city_id',$cityIds)->delete();
  610. // 更新内容
  611. $Model->updateDesc($id,$description);
  612. // 提交
  613. DB::commit();
  614. // 记录行为
  615. $this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,[],$data);
  616. // 告知结果
  617. return json_send(['code'=>'success','msg'=>'修改成功','action'=>'edit']);
  618. } catch (\Throwable $th) {
  619. // 回滚
  620. DB::rollBack();
  621. // 提示
  622. return json_send(['code'=>'error','msg'=>'系统异常,写入失败','data'=>$th->getMessage() .'=>'.$th->getLine()]);
  623. }
  624. }
  625. // 接收参数
  626. $id = request('id',0);
  627. // 查询数据
  628. $oldData = $Model->where(['id'=>$id])->first();
  629. // 如果是没有数据
  630. if( !$oldData ) return $this->error('查无数据');
  631. // 产品信息转格式
  632. $oldData = $oldData->toArray();
  633. $oldData['description'] = $Model->getDesc($id);
  634. $oldData['city_ids'] = $ProductCity->getListByProductId($id);
  635. $oldData['tag_scope'] = explode(',',$oldData['tag_scope']);
  636. $oldData['tag_exclude'] = explode(',',$oldData['tag_exclude']);
  637. $photoList = $ProductPhoto->getListByProductId($id);
  638. // 获取产品属性
  639. $attrList = $ProductAttr->getListByProductId($id);
  640. // 规格属性
  641. $specList = [];
  642. // 获取数据
  643. foreach ($attrList as $value) {
  644. $value['active'] = 0;
  645. if( !isset($specList[$value['spec_id']]) ) $specList[$value['spec_id']] = $ProductSpec->getOne($value['spec_id']);
  646. $specList[$value['spec_id']]['attr_list'][] = $value;
  647. }
  648. // 产品类型
  649. $skuList = $ProductSkus->getListByProductId($id);
  650. // 循环处理
  651. foreach ($skuList as $key => $value) {
  652. // 数据解析
  653. $value['attr_ids'] = explode(',',$value['attr_ids']);
  654. // 循环处理
  655. foreach ( $value['attr_ids'] as $k=>$attrId ) {
  656. // 获取ids对应的name
  657. $value['attr_ids'][$k] = $ProductAttr->getValueById($attrId,'name');
  658. }
  659. // 数据合并
  660. $value['attr_ids'] = implode(',',$value['attr_ids']);
  661. // 重组
  662. $skuList[$key] = $value;
  663. }
  664. // 获取类型数据
  665. $typeList = $ProductType->getList();
  666. $cityList = $City->getCityList();
  667. $businessList = $Business->getList();
  668. $producerList = $Producer->getList();
  669. // 标签列表
  670. $tagData = $WeiBanTags->query()->groupBy('group')->groupBy('name')->get(['group','name'])->toArray();
  671. // 标签列表
  672. $tagList = [];
  673. // 循环数据
  674. foreach ($tagData as $value) {
  675. $tagList[$value['group']][] = $value['name'];
  676. }
  677. // 分配数据
  678. $this->assign('tagList',$tagList);
  679. $this->assign('typeList',$typeList);
  680. $this->assign('cityList',$cityList);
  681. $this->assign('businessList',$businessList);
  682. $this->assign('producerList',$producerList);
  683. $this->assign('oldData',$oldData);
  684. $this->assign('photoList',$photoList);
  685. $this->assign('skuList',$skuList);
  686. $this->assign('specList',$specList);
  687. $this->assign('crumbs','修改');
  688. // 加载模板
  689. return $this->fetch();
  690. }
  691. /**
  692. * 编辑
  693. *
  694. * */
  695. public function copy(Request $request, Model $Model, WeiBanTags $WeiBanTags, ProductPhoto $ProductPhoto, Producer $Producer, Business $Business, ProductType $ProductType, ProductSpec $ProductSpec, ProductAttr $ProductAttr, ProductSkus $ProductSkus, City $City, ProductCity $ProductCity){
  696. if( request()->isMethod('post') ){
  697. // 验证参数
  698. $request->scene('add')->validate();
  699. // 组合数据
  700. $data['name'] = request('name','');
  701. $data['thumb'] = request('thumb','');
  702. $data['poster'] = request('poster','');
  703. $data['spec'] = request('spec','');
  704. $data['price'] = request('price',0);
  705. $data['market_price'] = request('market_price',0);
  706. $data['producer_id'] = request('producer_id',0);
  707. $data['business_id'] = request('business_id',0);
  708. $data['quota'] = request('quota',0);
  709. $data['min_quota'] = request('min_quota',0);
  710. $data['quota_start'] = request('quota_start','');
  711. $data['quota_end'] = request('quota_end','');
  712. $data['stock'] = request('stock',0);
  713. $data['status'] = 1;
  714. $data['admin_uid'] = admin('uid');
  715. $description = request('description','');
  716. $attr = request('attr',[]);
  717. $skuList = request('sku',[]);
  718. $cityIds = request('city_ids',[]);
  719. $photoList = request('photo_list',[]);
  720. $tagScope = request('tag_scope',[]);
  721. $data['tag_scope'] = implode(',',$tagScope);
  722. $tagExclude = request('tag_exclude',[]);
  723. $data['tag_exclude'] = implode(',',$tagExclude);
  724. // 循环
  725. foreach ($photoList as $key => $value) {
  726. if( !$value ) unset($photoList[$key]);
  727. }
  728. $photoList = array_values($photoList);
  729. // 如果没有选择,则意味着全部
  730. $cityIds = $cityIds ? $cityIds : [1];
  731. $data['quota_start'] = $data['quota_start'] ? strtotime($data['quota_start']) : 0;
  732. $data['quota_end'] = $data['quota_end'] ? strtotime($data['quota_end']) : 0;
  733. // 限购提示
  734. if( !$data['thumb'] ) return json_send(['code'=>'error','msg'=>'请上传产品主图','data'=>['error'=>'请上传产品主图']]);
  735. // 限购提示
  736. if( $attr && !$skuList ) return json_send(['code'=>'error','msg'=>'规格属性存在时,请填写SKU','data'=>['error'=>'规格属性存在时,请填写SKU']]);
  737. // 限购提示
  738. if( $data['quota'] && ( !$data['quota_start'] || !$data['quota_end'] )) return json_send(['code'=>'error','msg'=>'限购必填限购时间','data'=>['error'=>'限购必填限购时间']]);
  739. // 限购提示
  740. if( $data['min_quota'] > $data['quota'] ) return json_send(['code'=>'error','msg'=>'起购数量请勿大于限购数量','data'=>['error'=>'起购数量请勿大于限购数量']]);
  741. // 总库存
  742. if( $skuList ) $data['stock'] = array_sum(array_column($skuList,'stock'));
  743. // SKU存在的时候,判断限购数量
  744. if( $skuList ) {
  745. // 循环处理
  746. foreach ($skuList as $attrNames => $value) {
  747. // SKU限购,所以限购时间也必须填
  748. if( $value['quota'] && ( !$data['quota_start'] || !$data['quota_end'] )) return json_send(['code'=>'error','msg'=>'SKU限购时,请填限购时间','data'=>['error'=>'SKU限购时,请填限购时间']]);
  749. // 限购提示
  750. if( $value['min_quota'] > $value['quota'] ) return json_send(['code'=>'error','msg'=>$attrNames.'起购数量请勿大于限购数量','data'=>['error'=>$attrNames.'起购数量请勿大于限购数量']]);
  751. // 提示起购数量异常,如果总起购数量小于SKU起购数量,提示
  752. if( $value['min_quota'] && $value['min_quota'] < $data['min_quota'] ) return json_send(['code'=>'error','msg'=>'SKU的起购数量不能小于总起购数量','data'=>['error'=>'SKU的起购数量不能小于总起购数量']]);
  753. }
  754. // 限购数量
  755. $quota = array_sum(array_column($skuList,'quota'));
  756. // 提示限购数量异常
  757. if( $data['quota'] && $data['quota'] < $quota ) return json_send(['code'=>'error','msg'=>'总限购数量不能小于SKU的限购数量','data'=>['error'=>'总限购数量不能小于SKU的限购数量']]);
  758. }
  759. // 总库存
  760. $data['stock_total'] = $data['stock'];
  761. // 获取规格属性
  762. $specAttr = $this->getSpecAttr($attr,$ProductSpec,true);
  763. // 开启事务
  764. DB::beginTransaction();
  765. try {
  766. // 写入
  767. $id = $Model->add($data);
  768. // 提示新增失败
  769. if( !$id ) {
  770. // 回滚
  771. DB::rollBack();
  772. // 提示
  773. return json_send(['code'=>'error','msg'=>'新增失败']);
  774. }
  775. // 图册
  776. foreach ($photoList as $key => $value) {
  777. // 整理数据
  778. $value = ['sort'=>$key,'thumb'=>$value,'product_id'=>$id,'insert_time'=>time(),'update_time'=>time()];
  779. // 重新整理
  780. $photoList[$key] = $value;
  781. }
  782. // 存在图册
  783. if( $photoList ) {
  784. // 写入失败
  785. $result = $ProductPhoto->query()->insert($photoList);
  786. // 提示新增失败
  787. if( !$result ) {
  788. // 回滚
  789. DB::rollBack();
  790. // 提示
  791. return json_send(['code'=>'error','msg'=>'商品图册写入失败']);
  792. }
  793. }
  794. // 组合数据
  795. foreach ($specAttr as $key => $value) {
  796. // 查询结果
  797. $value['id'] = $ProductAttr->upsertByName($value,$id);
  798. // 提示新增失败
  799. if( !$value['id'] ) {
  800. // 回滚
  801. DB::rollBack();
  802. // 提示
  803. return json_send(['code'=>'error','msg'=>'商品属性新增失败']);
  804. }
  805. // 重组
  806. $specAttr[$key] = $value;
  807. }
  808. // 循环SKU
  809. foreach ($skuList as $attrNames => $value) {
  810. // 属性ID值
  811. $value['attr_ids'] = [];
  812. // 规格属性值组合
  813. $value['attr_names']= $attrNames;
  814. // 切割成数据
  815. $names = explode(',',$attrNames);
  816. // 循环处理
  817. foreach ($names as $name) {
  818. foreach ($specAttr as $vv) {
  819. if( $name == $vv['name'] ) {
  820. // 提示新增失败
  821. if( !$vv['id'] ) {
  822. // 回滚
  823. DB::rollBack();
  824. // 提示
  825. return json_send(['code'=>'error','msg'=>'属性SKU匹配失败']);
  826. }
  827. $value['attr_ids'][] = $vv['id'];
  828. }
  829. }
  830. }
  831. // 转成好存储的数据
  832. $value['attr_ids'] = implode(',',$value['attr_ids']);
  833. // 转成好存储的数据
  834. $value['product_id']= $id;
  835. // 转成好存储的数据
  836. $value['sku_thumb'] = (string) $value['sku_thumb'];
  837. // 转成好存储的数据
  838. $value['stock_total']= $value['stock'];
  839. // 转成好存储的数据
  840. $value['insert_time']= time();
  841. // 转成好存储的数据
  842. $value['update_time']= time();
  843. // SKU结果
  844. $skuList[$attrNames] = $value;
  845. }
  846. // 循环城市范围
  847. foreach ($cityIds as $key => $value) {
  848. // 重组数据
  849. $cityIds[$key] = ['city_id'=>$value,'product_id'=>$id,'insert_time'=>time(),'update_time'=>time()];
  850. }
  851. // 写入城市范围
  852. $ProductCity->query()->insert($cityIds);
  853. // 返回结果
  854. $result = $ProductSkus->insert($skuList);
  855. // 提示新增失败
  856. if( !$result ) {
  857. // 回滚
  858. DB::rollBack();
  859. // 提示
  860. return json_send(['code'=>'error','msg'=>'SKU插入失败']);
  861. }
  862. // 更新内容
  863. $Model->updateDesc($id,$description);
  864. // 提交
  865. DB::commit();
  866. // 记录行为
  867. $this->addAdminHistory(admin('uid'),$Model->getTable(),$id,1,[],$data);
  868. // 告知结果
  869. return json_send(['code'=>'success','msg'=>'新增成功','action'=>'add']);
  870. } catch (\Throwable $th) {
  871. // 回滚
  872. DB::rollBack();
  873. // 提示
  874. return json_send(['code'=>'error','msg'=>'系统异常,写入失败','data'=>$th->getMessage()]);
  875. }
  876. }
  877. // 接收参数
  878. $id = request('id',0);
  879. // 查询数据
  880. $oldData = $Model->where(['id'=>$id])->first();
  881. // 如果是没有数据
  882. if( !$oldData ) return $this->error('查无数据');
  883. // 产品信息转格式
  884. $oldData = $oldData->toArray();
  885. $oldData['description'] = $Model->getDesc($id);
  886. $oldData['city_ids'] = $ProductCity->getListByProductId($id);
  887. $oldData['tag_scope'] = explode(',',$oldData['tag_scope']);
  888. $oldData['tag_exclude'] = explode(',',$oldData['tag_exclude']);
  889. $photoList = $ProductPhoto->getListByProductId($id);
  890. // 获取产品属性
  891. $attrList = $ProductAttr->getListByProductId($id);
  892. // 规格属性
  893. $specList = [];
  894. // 获取数据
  895. foreach ($attrList as $value) {
  896. $value['active'] = 0;
  897. if( !isset($specList[$value['spec_id']]) ) $specList[$value['spec_id']] = $ProductSpec->getOne($value['spec_id']);
  898. $specList[$value['spec_id']]['attr_list'][] = $value;
  899. }
  900. // 产品类型
  901. $skuList = $ProductSkus->getListByProductId($id);
  902. // 循环处理
  903. foreach ($skuList as $key => $value) {
  904. // 数据解析
  905. $value['attr_ids'] = explode(',',$value['attr_ids']);
  906. // 循环处理
  907. foreach ( $value['attr_ids'] as $k=>$attrId ) {
  908. // 获取ids对应的name
  909. $value['attr_ids'][$k] = $ProductAttr->getValueById($attrId,'name');
  910. }
  911. // 数据合并
  912. $value['attr_ids'] = implode(',',$value['attr_ids']);
  913. // 重组
  914. $skuList[$key] = $value;
  915. }
  916. // 标签列表
  917. $tagData = $WeiBanTags->query()->groupBy('group')->groupBy('name')->get(['group','name'])->toArray();
  918. // 标签列表
  919. $tagList = [];
  920. // 循环数据
  921. foreach ($tagData as $value) {
  922. $tagList[$value['group']][] = $value['name'];
  923. }
  924. // 获取类型数据
  925. $typeList = $ProductType->getList();
  926. $cityList = $City->getCityList();
  927. $businessList = $Business->getList();
  928. $producerList = $Producer->getList();
  929. // 分配数据
  930. $this->assign('tagList',$tagList);
  931. $this->assign('typeList',$typeList);
  932. $this->assign('cityList',$cityList);
  933. $this->assign('businessList',$businessList);
  934. $this->assign('producerList',$producerList);
  935. $this->assign('oldData',$oldData);
  936. $this->assign('photoList',$photoList);
  937. $this->assign('skuList',$skuList);
  938. $this->assign('specList',$specList);
  939. $this->assign('crumbs','复制');
  940. // 加载模板
  941. return $this->fetch();
  942. }
  943. /**
  944. * 状态
  945. *
  946. * */
  947. public function set_status( Request $request, Model $Model ){
  948. // 验证参数
  949. $request->scene('set_status')->validate();
  950. // 接收参数
  951. $id = request('id',0);
  952. $status = request('status',0);
  953. // 查询数据
  954. $result = $Model->edit($id,['status'=>$status]);
  955. // 提示新增失败
  956. if( !$result ) return json_send(['code'=>'error','msg'=>'设置失败']);
  957. // 记录行为
  958. $this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,[],['status'=>$status]);
  959. // 告知结果
  960. return json_send(['code'=>'success','msg'=>'设置成功','path'=>'']);
  961. }
  962. /**
  963. * 获取某个类目下的规格
  964. *
  965. */
  966. public function get_spec_html( ProductSpec $ProductSpec){
  967. // 接收参数
  968. $typeId = request('type_id',0);
  969. // 查询数据
  970. $specList = $ProductSpec->getList();
  971. // 循环处理
  972. foreach ($specList as $key => $value) {
  973. if( $value['type_id'] != $typeId ) unset($specList[$key]);
  974. }
  975. // 分配数据
  976. $this->assign('specList',$specList);
  977. // 加载模板
  978. return $this->fetch();
  979. }
  980. /**
  981. * 获取某个类目下的规格
  982. *
  983. */
  984. public function get_sku_html( ProductSpec $ProductSpec,ProductSkus $ProductSkus){
  985. // 接收参数
  986. $attr = request('attr',[]);
  987. $id = request('product_id',0);
  988. // 产品类型
  989. $oldSkus = $id ? $ProductSkus->getListByProductId($id) : [];
  990. // 获取规格属性
  991. $specAttr = $this->getSpecAttr($attr,$ProductSpec);
  992. // 组合SKU
  993. $brushList = [];
  994. // 循环规格属性
  995. foreach ($specAttr as $specId => $value) {
  996. // 获取SKU组合
  997. $brushList[$specId] = array_column($value['attr_list'],'name');
  998. }
  999. // sku列表
  1000. $skuList = $this->brush([],$brushList);
  1001. // 循环规格属性
  1002. foreach ($skuList as $newKey => $new) {
  1003. // 获取新数据
  1004. $new = ['attr_names'=>$new,'price'=>0,'market_price'=>0,'stock'=>0,'min_quota'=>0,'quota'=>0,'status'=>0,'sku_thumb'=>''];
  1005. // 循环旧的sku
  1006. foreach ($oldSkus as $old) {
  1007. // 如果有相等的规格
  1008. if( $old['attr_names'] == $new['attr_names']) {
  1009. $new['sku_thumb'] = $old['sku_thumb'];
  1010. $new['market_price']= $old['market_price'];
  1011. $new['price'] = $old['price'];
  1012. $new['stock'] = $old['stock'];
  1013. $new['status'] = $old['status'];
  1014. $new['min_quota'] = $old['min_quota'];
  1015. $new['quota'] = $old['quota'];
  1016. }
  1017. }
  1018. $skuList[$newKey] = $new;
  1019. }
  1020. // 分配数据
  1021. $this->assign('specAttr',$specAttr);
  1022. $this->assign('skuList',$skuList);
  1023. // 加载模板
  1024. return $this->fetch();
  1025. }
  1026. /**
  1027. * 获取规格属性
  1028. * @param ProductSpec $ProductSpec
  1029. *
  1030. */
  1031. private function getSpecAttr($attr,$ProductSpec,$onlyList=false){
  1032. // 组合参数
  1033. $specAttr = [];
  1034. // 循环处理数据
  1035. foreach ($attr as $specId => $value) {
  1036. $specAttr[$specId]['spec_id'] = $specId;
  1037. $specAttr[$specId]['spec_name'] = $ProductSpec->getOne($specId,'name');
  1038. $specAttr[$specId]['attr_list'] = [];
  1039. foreach ($value['name'] as $key => $name) {
  1040. // 如果没有名称的,跳过
  1041. if( !$name ) continue;
  1042. // 结果
  1043. $temp = ['id'=>0,'spec_id'=>$specId,'thumb'=>'','name'=>'','remark'=>''];
  1044. // 获取名称
  1045. $temp['name'] = str_ireplace(',','',$name);
  1046. // 获取对应的备注信息
  1047. if( !empty($value['remark'][$key]) ) $temp['remark'] = $value['remark'][$key];
  1048. if( !empty($value['thumb'][$key]) ) $temp['thumb'] = $value['thumb'][$key];
  1049. // 获取对应的数据
  1050. $specAttr[$specId]['attr_list'][]= $temp;
  1051. }
  1052. // 没有属性的规格,移除
  1053. if( !$specAttr[$specId]['attr_list'] ) unset($specAttr[$specId]);
  1054. }
  1055. // 仅获取属性列表
  1056. if( $onlyList ) {
  1057. // 属性列表
  1058. $attrList = [];
  1059. // 判断结果
  1060. foreach ($specAttr as $value) {
  1061. // 获取数据
  1062. array_push($attrList,...$value['attr_list']);
  1063. }
  1064. // 返回结果
  1065. $specAttr = $attrList;
  1066. }
  1067. // 返回结果
  1068. return $specAttr;
  1069. }
  1070. /**
  1071. * 组合SKU
  1072. *
  1073. */
  1074. private function brush($res = [], $arr = []){
  1075. // 获取第一个规格的属性
  1076. if (empty($res)) $res = (array) array_shift($arr);
  1077. // 如果只有一个规格,返回该规格的属性即可
  1078. if (empty($arr)) return $res;
  1079. // 接下来要参与计算的一组属性
  1080. $current = array_shift($arr);
  1081. // 计算的列表
  1082. $last = [];
  1083. // 循环上一次已经算出的集合
  1084. foreach ($res as $attr) {
  1085. foreach ($current as $col_val) {
  1086. $last[] = $attr . ',' . $col_val;
  1087. }
  1088. }
  1089. return $this->brush($last,$arr); # 递归处理, 直到$arr滚到最后一组属性
  1090. }
  1091. /**
  1092. * 排序
  1093. *
  1094. * */
  1095. public function set_sort( Request $request, Model $Model ){
  1096. // 验证参数
  1097. $request->scene('set_sort')->validate();
  1098. // 接收参数
  1099. $id = request('id',0);
  1100. $sort = request('sort',0);
  1101. // 查询数据
  1102. $result = $Model->edit($id,['sort'=>$sort]);
  1103. // 提示新增失败
  1104. if( !$result ) return json_send(['code'=>'error','msg'=>'设置失败']);
  1105. // 记录行为
  1106. $this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,[],['sort'=>$sort]);
  1107. // 告知结果
  1108. return json_send(['code'=>'success','msg'=>'设置成功','path'=>'']);
  1109. }
  1110. }