Product.php 42 KB

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