Product.php 44 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136
  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. if( $data['stock_total'] <= 0 ) return json_send(['code'=>'error','msg'=>'请设置库存','data'=>['error'=>'请设置库存']]);
  302. // 获取规格属性
  303. $specAttr = $this->getSpecAttr($attr,$ProductSpec,true);
  304. // 开启事务
  305. DB::beginTransaction();
  306. try {
  307. // 写入
  308. $id = $Model->add($data);
  309. // 提示新增失败
  310. if( !$id ) {
  311. // 回滚
  312. DB::rollBack();
  313. // 提示
  314. return json_send(['code'=>'error','msg'=>'新增失败']);
  315. }
  316. // 组合数据
  317. foreach ($specAttr as $key => $value) {
  318. // 查询结果
  319. $value['id'] = $ProductAttr->upsertByName($value,$id);
  320. // 提示新增失败
  321. if( !$value['id'] ) {
  322. // 回滚
  323. DB::rollBack();
  324. // 提示
  325. return json_send(['code'=>'error','msg'=>'商品属性新增失败']);
  326. }
  327. // 重组
  328. $specAttr[$key] = $value;
  329. }
  330. // 图册
  331. foreach ($photoList as $key => $value) {
  332. // 整理数据
  333. $value = ['sort'=>$key,'thumb'=>$value,'product_id'=>$id,'insert_time'=>time(),'update_time'=>time()];
  334. // 重新整理
  335. $photoList[$key] = $value;
  336. }
  337. // 存在图册
  338. if( $photoList ) {
  339. // 写入失败
  340. $result = $ProductPhoto->query()->insert($photoList);
  341. // 提示新增失败
  342. if( !$result ) {
  343. // 回滚
  344. DB::rollBack();
  345. // 提示
  346. return json_send(['code'=>'error','msg'=>'商品图册写入失败']);
  347. }
  348. }
  349. // 循环SKU
  350. foreach ($skuList as $attrNames => $value) {
  351. // 属性ID值
  352. $value['attr_ids'] = [];
  353. // 规格属性值组合
  354. $value['attr_names']= $attrNames;
  355. // 切割成数据
  356. $names = explode(',',$attrNames);
  357. // 循环处理
  358. foreach ($names as $name) {
  359. foreach ($specAttr as $vv) {
  360. if( $name == $vv['name'] ) {
  361. // 提示新增失败
  362. if( !$vv['id'] ) {
  363. // 回滚
  364. DB::rollBack();
  365. // 提示
  366. return json_send(['code'=>'error','msg'=>'属性SKU匹配失败']);
  367. }
  368. $value['attr_ids'][] = $vv['id'];
  369. }
  370. }
  371. }
  372. // 转成好存储的数据
  373. $value['attr_ids'] = implode(',',$value['attr_ids']);
  374. // 转成好存储的数据
  375. $value['product_id'] = $id;
  376. // 转成好存储的数据
  377. $value['sku_thumb'] = (string)$value['sku_thumb'];
  378. // 转成好存储的数据
  379. $value['stock_total']= $value['stock'];
  380. // 转成好存储的数据
  381. $value['insert_time']= time();
  382. // 转成好存储的数据
  383. $value['update_time']= time();
  384. // SKU结果
  385. $skuList[$attrNames] = $value;
  386. }
  387. // 循环城市范围
  388. foreach ($cityIds as $key => $value) {
  389. // 重组数据
  390. $cityIds[$key] = ['city_id'=>$value,'product_id'=>$id,'insert_time'=>time(),'update_time'=>time()];
  391. }
  392. // 写入城市范围
  393. $ProductCity->query()->insert($cityIds);
  394. // 返回结果
  395. $result = $ProductSkus->insert($skuList);
  396. // 提示新增失败
  397. if( !$result ) {
  398. // 回滚
  399. DB::rollBack();
  400. // 提示
  401. return json_send(['code'=>'error','msg'=>'SKU插入失败']);
  402. }
  403. // 更新内容
  404. $Model->updateDesc($id,$description);
  405. // 提交
  406. DB::commit();
  407. // 记录行为
  408. $this->addAdminHistory(admin('uid'),$Model->getTable(),$id,1,[],$data);
  409. // 告知结果
  410. return json_send(['code'=>'success','msg'=>'新增成功','action'=>'add']);
  411. } catch (\Throwable $th) {
  412. // 回滚
  413. DB::rollBack();
  414. // 提示
  415. return json_send(['code'=>'error','msg'=>'系统异常,写入失败','data'=>$th->getMessage()]);
  416. }
  417. }
  418. // 获取类型数据
  419. $typeList = $ProductType->getList();
  420. $cityList = $City->getCityList();
  421. $businessList = $Business->getList();
  422. $producerList = $Producer->getList();
  423. // 标签列表
  424. $tagData = $WeiBanTags->query()->groupBy('group')->groupBy('name')->get(['group','name'])->toArray();
  425. // 标签列表
  426. $tagList = [];
  427. // 循环数据
  428. foreach ($tagData as $value) {
  429. $tagList[$value['group']][] = $value['name'];
  430. }
  431. // 分配数据
  432. $this->assign('crumbs','新增');
  433. $this->assign('tagList',$tagList);
  434. $this->assign('typeList',$typeList);
  435. $this->assign('cityList',$cityList);
  436. $this->assign('businessList',$businessList);
  437. $this->assign('producerList',$producerList);
  438. // 加载模板
  439. return $this->fetch();
  440. }
  441. /**
  442. * 编辑
  443. *
  444. * */
  445. 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){
  446. // 接收参数
  447. $id = request('id',0);
  448. // 查询数据
  449. $oldData = $Model->where(['id'=>$id])->first();
  450. // 修改
  451. if(request()->isMethod('post')){
  452. // 验证参数
  453. $request->scene('edit')->validate();
  454. // 组合数据
  455. $id = request('id',0);
  456. $data['name'] = request('name','');
  457. $data['thumb'] = request('thumb','');
  458. $data['poster'] = request('poster','');
  459. $data['spec'] = request('spec','');
  460. $data['price'] = request('price',0);
  461. $data['market_price'] = request('market_price',0);
  462. $data['quota'] = request('quota',0);
  463. $data['min_quota'] = request('min_quota',0);
  464. $data['quota_start'] = request('quota_start','');
  465. $data['quota_end'] = request('quota_end','');
  466. $data['puton_time'] = request('puton_time','');
  467. $data['putoff_time'] = request('putoff_time','');
  468. $data['producer_id'] = request('producer_id',0);
  469. $data['business_id'] = request('business_id',0);
  470. $data['stock'] = request('stock',0);
  471. $data['status'] = 1;
  472. $description = request('description','');
  473. $attr = request('attr',[]);
  474. $skuList = request('sku',[]);
  475. $cityIds = request('city_ids',[]);
  476. $photoList = request('photo_list',[]);
  477. $tagScope = request('tag_scope',[]);
  478. $data['tag_scope'] = implode(',',$tagScope);
  479. $tagExclude = request('tag_exclude',[]);
  480. $data['tag_exclude'] = implode(',',$tagExclude);
  481. // 循环
  482. foreach ($photoList as $key => $value) {
  483. if( !$value ) unset($photoList[$key]);
  484. }
  485. $photoList = array_values($photoList);
  486. // 如果没有选择,则意味着全部
  487. $cityIds = $cityIds ? $cityIds : [1];
  488. $data['quota_start'] = $data['quota_start'] ? strtotime($data['quota_start']) : 0;
  489. $data['quota_end'] = $data['quota_end'] ? strtotime($data['quota_end']) : 0;
  490. $data['puton_time'] = $data['puton_time'] ? strtotime($data['puton_time']) : 0;
  491. $data['putoff_time'] = $data['putoff_time'] ? strtotime($data['putoff_time']) : 0;
  492. // 限购提示
  493. if( !$data['thumb'] ) return json_send(['code'=>'error','msg'=>'请上传产品主图','data'=>['error'=>'请上传产品主图']]);
  494. // 限购提示
  495. if( $attr && !$skuList ) return json_send(['code'=>'error','msg'=>'规格属性存在时,请填写SKU','data'=>['error'=>'规格属性存在时,请填写SKU']]);
  496. // 限购提示
  497. if( $data['quota'] && ( !$data['quota_start'] || !$data['quota_end'] )) return json_send(['code'=>'error','msg'=>'限购必填限购时间','data'=>['error'=>'限购必填限购时间']]);
  498. // 限购提示
  499. if( $data['min_quota'] > $data['quota'] ) return json_send(['code'=>'error','msg'=>'起购数量请勿大于限购数量','data'=>['error'=>'起购数量请勿大于限购数量']]);
  500. // SKU存在的时候,判断限购数量
  501. if( $skuList ) {
  502. // 循环处理
  503. foreach ($skuList as $attrNames => $value) {
  504. // SKU限购,所以限购时间也必须填
  505. if( $value['quota'] && ( !$data['quota_start'] || !$data['quota_end'] )) return json_send(['code'=>'error','msg'=>'SKU限购时,请填限购时间','data'=>['error'=>'SKU限购时,请填限购时间']]);
  506. // 限购提示
  507. if( $value['min_quota'] > $value['quota'] ) return json_send(['code'=>'error','msg'=>$attrNames.'起购数量请勿大于限购数量','data'=>['error'=>$attrNames.'起购数量请勿大于限购数量']]);
  508. // 提示起购数量异常,如果总起购数量小于SKU起购数量,提示
  509. if( $value['min_quota'] && $value['min_quota'] < $data['min_quota'] ) return json_send(['code'=>'error','msg'=>'SKU的起购数量不能小于总起购数量','data'=>['error'=>'SKU的起购数量不能小于总起购数量']]);
  510. }
  511. // 限购数量
  512. $quota = array_sum(array_column($skuList,'quota'));
  513. // 提示限购数量异常
  514. if( $data['quota']&& $data['quota'] < $quota ) return json_send(['code'=>'error','msg'=>'总限购数量不能小于SKU的限购数量','data'=>['error'=>'总限购数量不能小于SKU的限购数量']]);
  515. }
  516. // 上下架
  517. if( $data['puton_time'] ) {
  518. // 下架时间必填
  519. if( !$data['putoff_time'] ) return json_send(['code'=>'error','msg'=>'请填写自动下架时间','data'=>['error'=>'自动上架请填写下架时间']]);
  520. // 下架时间必填
  521. if( $data['putoff_time'] <= $data['puton_time'] ) return json_send(['code'=>'error','msg'=>'下架时间请晚于上架时间','data'=>['error'=>'下架时间请晚于上架时间']]);
  522. }
  523. // 总库存
  524. if( $skuList ) $data['stock'] = array_sum(array_column($skuList,'stock'));
  525. // 总库存
  526. $data['stock_total'] = $data['stock'];
  527. // 总库存提醒
  528. if( $data['stock_total'] <= 0 ) return json_send(['code'=>'error','msg'=>'请设置库存','data'=>['error'=>'请设置库存']]);
  529. // 获取规格属性
  530. $specAttr = $this->getSpecAttr($attr,$ProductSpec,true);
  531. // 开启事务
  532. DB::beginTransaction();
  533. try {
  534. // 写入
  535. $result = $Model->edit($id,$data);
  536. // 提示新增失败
  537. if( !$result ) {
  538. // 回滚
  539. DB::rollBack();
  540. // 提示
  541. return json_send(['code'=>'error','msg'=>'修改失败']);
  542. }
  543. // 获取旧图册
  544. $oldPhoto = $ProductPhoto->getListByProductId($id);
  545. // 循环个数
  546. for ($i=0; $i < 4; $i++) {
  547. // 如果存在旧数据与新数据,修改
  548. if( isset($oldPhoto[$i]) && isset($photoList[$i]) ) $ProductPhoto->query()->where([['product_id','=',$id],['sort','=',$i]])->update(['thumb'=>(string)$photoList[$i],'update_time'=>time()]);
  549. // 如果存在旧数据,不存在新数据,删除
  550. if( isset($oldPhoto[$i]) && !isset($photoList[$i]) ) $ProductPhoto->query()->where([['product_id','=',$id],['sort','=',$i]])->delete();
  551. // 如果不存在旧数据,存在新数据,新增
  552. if( !isset($oldPhoto[$i]) && isset($photoList[$i]) ) $ProductPhoto->add(['sort'=>$i,'product_id'=>$id,'thumb'=>(string)$photoList[$i],'insert_time'=>time(),'update_time'=>time()]);
  553. }
  554. // 组合数据
  555. foreach ($specAttr as $key => $value) {
  556. // 查询结果
  557. $value['id'] = $ProductAttr->upsertByName($value,$id);
  558. // 提示新增失败
  559. if( !$value['id'] ) {
  560. // 回滚
  561. DB::rollBack();
  562. // 提示
  563. return json_send(['code'=>'error','msg'=>'商品属性新增失败']);
  564. }
  565. // 重组
  566. $specAttr[$key] = $value;
  567. }
  568. // 如果不在这个属性列表中的数据删除
  569. $ProductAttr->query()->where([['product_id','=',$id]])->whereNotIn('id',array_column($specAttr,'id'))->delete();
  570. // 循环SKU
  571. foreach ($skuList as $attrNames => $value) {
  572. // 属性ID值
  573. $value['attr_ids'] = [];
  574. // 规格属性值组合
  575. $value['attr_names']= $attrNames;
  576. // 切割成数据
  577. $names = explode(',',$attrNames);
  578. // 循环处理
  579. foreach ($names as $name) {
  580. foreach ($specAttr as $vv) {
  581. if( $name == $vv['name'] ) {
  582. // 提示新增失败
  583. if( !$vv['id'] ) {
  584. // 回滚
  585. DB::rollBack();
  586. // 提示
  587. return json_send(['code'=>'error','msg'=>'属性SKU匹配失败']);
  588. }
  589. $value['attr_ids'][] = $vv['id'];
  590. }
  591. }
  592. }
  593. // 转成好存储的数据
  594. $value['attr_ids'] = implode(',',$value['attr_ids']);
  595. // 转成好存储的数据
  596. $value['sku_thumb'] = (string)$value['sku_thumb'];
  597. // 转成好存储的数据
  598. $value['stock_total']= $value['stock'];
  599. // 转成好存储的数据
  600. $value['product_id']= $id;
  601. // 查询
  602. $oldSkuId = $ProductSkus->query()->where([['product_id','=',$id],['attr_ids','=',$value['attr_ids']]])->value('id');
  603. // 判断是否存在ID
  604. $value['id'] = $oldSkuId ? $ProductSkus->edit($oldSkuId,$value) : $ProductSkus->add($value);
  605. // SKU结果
  606. $skuList[$attrNames]= $value;
  607. }
  608. // 如果不在这个属性列表中的数据删除
  609. $ProductSkus->query()->where([['product_id','=',$id]])->whereNotIn('id',array_column($skuList,'id'))->delete();
  610. // 获取之前的城市ID
  611. $oldCityIds = $ProductCity->getListByProductId($id);
  612. // 循环城市范围
  613. foreach ($cityIds as $key => $value) {
  614. // 不存在则新增
  615. if( !in_array($value,$oldCityIds) ) $ProductCity->add(['city_id'=>$value,'product_id'=>$id]);
  616. }
  617. // 不存在的城市删除
  618. $ProductCity->query()->where([['product_id','=',$id]])->whereNotIn('city_id',$cityIds)->delete();
  619. // 更新内容
  620. $Model->updateDesc($id,$description);
  621. // 提交
  622. DB::commit();
  623. // 记录行为
  624. $this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,$oldData,$data);
  625. // 告知结果
  626. return json_send(['code'=>'success','msg'=>'修改成功','action'=>'edit']);
  627. } catch (\Throwable $th) {
  628. // 回滚
  629. DB::rollBack();
  630. // 提示
  631. return json_send(['code'=>'error','msg'=>'系统异常,写入失败','data'=>$th->getMessage() .'=>'.$th->getLine()]);
  632. }
  633. }
  634. // 如果是没有数据
  635. if( !$oldData ) return $this->error('查无数据');
  636. // 产品信息转格式
  637. $oldData = $oldData->toArray();
  638. $oldData['description'] = $Model->getDesc($id);
  639. $oldData['city_ids'] = $ProductCity->getListByProductId($id);
  640. $oldData['tag_scope'] = explode(',',$oldData['tag_scope']);
  641. $oldData['tag_exclude'] = explode(',',$oldData['tag_exclude']);
  642. $photoList = $ProductPhoto->getListByProductId($id);
  643. // 获取产品属性
  644. $attrList = $ProductAttr->getListByProductId($id);
  645. // 规格属性
  646. $specList = [];
  647. // 获取数据
  648. foreach ($attrList as $value) {
  649. $value['active'] = 0;
  650. if( !isset($specList[$value['spec_id']]) ) $specList[$value['spec_id']] = $ProductSpec->getOne($value['spec_id']);
  651. $specList[$value['spec_id']]['attr_list'][] = $value;
  652. }
  653. // 产品类型
  654. $skuList = $ProductSkus->getListByProductId($id);
  655. // 循环处理
  656. foreach ($skuList as $key => $value) {
  657. // 数据解析
  658. $value['attr_ids'] = explode(',',$value['attr_ids']);
  659. // 循环处理
  660. foreach ( $value['attr_ids'] as $k=>$attrId ) {
  661. // 获取ids对应的name
  662. $value['attr_ids'][$k] = $ProductAttr->getValueById($attrId,'name');
  663. }
  664. // 数据合并
  665. $value['attr_ids'] = implode(',',$value['attr_ids']);
  666. // 重组
  667. $skuList[$key] = $value;
  668. }
  669. // 获取类型数据
  670. $typeList = $ProductType->getList();
  671. $cityList = $City->getCityList();
  672. $businessList = $Business->getList();
  673. $producerList = $Producer->getList();
  674. // 标签列表
  675. $tagData = $WeiBanTags->query()->groupBy('group')->groupBy('name')->get(['group','name'])->toArray();
  676. // 标签列表
  677. $tagList = [];
  678. // 循环数据
  679. foreach ($tagData as $value) {
  680. $tagList[$value['group']][] = $value['name'];
  681. }
  682. // 分配数据
  683. $this->assign('tagList',$tagList);
  684. $this->assign('typeList',$typeList);
  685. $this->assign('cityList',$cityList);
  686. $this->assign('businessList',$businessList);
  687. $this->assign('producerList',$producerList);
  688. $this->assign('oldData',$oldData);
  689. $this->assign('photoList',$photoList);
  690. $this->assign('skuList',$skuList);
  691. $this->assign('specList',$specList);
  692. $this->assign('crumbs','修改');
  693. // 加载模板
  694. return $this->fetch();
  695. }
  696. /**
  697. * 编辑
  698. *
  699. * */
  700. 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){
  701. if( request()->isMethod('post') ){
  702. // 验证参数
  703. $request->scene('add')->validate();
  704. // 组合数据
  705. $data['name'] = request('name','');
  706. $data['thumb'] = request('thumb','');
  707. $data['poster'] = request('poster','');
  708. $data['spec'] = request('spec','');
  709. $data['price'] = request('price',0);
  710. $data['market_price'] = request('market_price',0);
  711. $data['producer_id'] = request('producer_id',0);
  712. $data['business_id'] = request('business_id',0);
  713. $data['quota'] = request('quota',0);
  714. $data['min_quota'] = request('min_quota',0);
  715. $data['quota_start'] = request('quota_start','');
  716. $data['quota_end'] = request('quota_end','');
  717. $data['stock'] = request('stock',0);
  718. $data['status'] = 1;
  719. $data['admin_uid'] = admin('uid');
  720. $description = request('description','');
  721. $attr = request('attr',[]);
  722. $skuList = request('sku',[]);
  723. $cityIds = request('city_ids',[]);
  724. $photoList = request('photo_list',[]);
  725. $tagScope = request('tag_scope',[]);
  726. $data['tag_scope'] = implode(',',$tagScope);
  727. $tagExclude = request('tag_exclude',[]);
  728. $data['tag_exclude'] = implode(',',$tagExclude);
  729. // 循环
  730. foreach ($photoList as $key => $value) {
  731. if( !$value ) unset($photoList[$key]);
  732. }
  733. $photoList = array_values($photoList);
  734. // 如果没有选择,则意味着全部
  735. $cityIds = $cityIds ? $cityIds : [1];
  736. $data['quota_start'] = $data['quota_start'] ? strtotime($data['quota_start']) : 0;
  737. $data['quota_end'] = $data['quota_end'] ? strtotime($data['quota_end']) : 0;
  738. // 限购提示
  739. if( !$data['thumb'] ) return json_send(['code'=>'error','msg'=>'请上传产品主图','data'=>['error'=>'请上传产品主图']]);
  740. // 限购提示
  741. if( $attr && !$skuList ) return json_send(['code'=>'error','msg'=>'规格属性存在时,请填写SKU','data'=>['error'=>'规格属性存在时,请填写SKU']]);
  742. // 限购提示
  743. if( $data['quota'] && ( !$data['quota_start'] || !$data['quota_end'] )) return json_send(['code'=>'error','msg'=>'限购必填限购时间','data'=>['error'=>'限购必填限购时间']]);
  744. // 限购提示
  745. if( $data['min_quota'] > $data['quota'] ) return json_send(['code'=>'error','msg'=>'起购数量请勿大于限购数量','data'=>['error'=>'起购数量请勿大于限购数量']]);
  746. // 总库存
  747. if( $skuList ) $data['stock'] = array_sum(array_column($skuList,'stock'));
  748. // SKU存在的时候,判断限购数量
  749. if( $skuList ) {
  750. // 循环处理
  751. foreach ($skuList as $attrNames => $value) {
  752. // SKU限购,所以限购时间也必须填
  753. if( $value['quota'] && ( !$data['quota_start'] || !$data['quota_end'] )) return json_send(['code'=>'error','msg'=>'SKU限购时,请填限购时间','data'=>['error'=>'SKU限购时,请填限购时间']]);
  754. // 限购提示
  755. if( $value['min_quota'] > $value['quota'] ) return json_send(['code'=>'error','msg'=>$attrNames.'起购数量请勿大于限购数量','data'=>['error'=>$attrNames.'起购数量请勿大于限购数量']]);
  756. // 提示起购数量异常,如果总起购数量小于SKU起购数量,提示
  757. if( $value['min_quota'] && $value['min_quota'] < $data['min_quota'] ) return json_send(['code'=>'error','msg'=>'SKU的起购数量不能小于总起购数量','data'=>['error'=>'SKU的起购数量不能小于总起购数量']]);
  758. }
  759. // 限购数量
  760. $quota = array_sum(array_column($skuList,'quota'));
  761. // 提示限购数量异常
  762. if( $data['quota'] && $data['quota'] < $quota ) return json_send(['code'=>'error','msg'=>'总限购数量不能小于SKU的限购数量','data'=>['error'=>'总限购数量不能小于SKU的限购数量']]);
  763. }
  764. // 总库存
  765. $data['stock_total'] = $data['stock'];
  766. // 总库存提醒
  767. if( $data['stock_total'] <= 0 ) return json_send(['code'=>'error','msg'=>'请设置库存','data'=>['error'=>'请设置库存']]);
  768. // 获取规格属性
  769. $specAttr = $this->getSpecAttr($attr,$ProductSpec,true);
  770. // 开启事务
  771. DB::beginTransaction();
  772. try {
  773. // 写入
  774. $id = $Model->add($data);
  775. // 提示新增失败
  776. if( !$id ) {
  777. // 回滚
  778. DB::rollBack();
  779. // 提示
  780. return json_send(['code'=>'error','msg'=>'新增失败']);
  781. }
  782. // 图册
  783. foreach ($photoList as $key => $value) {
  784. // 整理数据
  785. $value = ['sort'=>$key,'thumb'=>$value,'product_id'=>$id,'insert_time'=>time(),'update_time'=>time()];
  786. // 重新整理
  787. $photoList[$key] = $value;
  788. }
  789. // 存在图册
  790. if( $photoList ) {
  791. // 写入失败
  792. $result = $ProductPhoto->query()->insert($photoList);
  793. // 提示新增失败
  794. if( !$result ) {
  795. // 回滚
  796. DB::rollBack();
  797. // 提示
  798. return json_send(['code'=>'error','msg'=>'商品图册写入失败']);
  799. }
  800. }
  801. // 组合数据
  802. foreach ($specAttr as $key => $value) {
  803. // 查询结果
  804. $value['id'] = $ProductAttr->upsertByName($value,$id);
  805. // 提示新增失败
  806. if( !$value['id'] ) {
  807. // 回滚
  808. DB::rollBack();
  809. // 提示
  810. return json_send(['code'=>'error','msg'=>'商品属性新增失败']);
  811. }
  812. // 重组
  813. $specAttr[$key] = $value;
  814. }
  815. // 循环SKU
  816. foreach ($skuList as $attrNames => $value) {
  817. // 属性ID值
  818. $value['attr_ids'] = [];
  819. // 规格属性值组合
  820. $value['attr_names']= $attrNames;
  821. // 切割成数据
  822. $names = explode(',',$attrNames);
  823. // 循环处理
  824. foreach ($names as $name) {
  825. foreach ($specAttr as $vv) {
  826. if( $name == $vv['name'] ) {
  827. // 提示新增失败
  828. if( !$vv['id'] ) {
  829. // 回滚
  830. DB::rollBack();
  831. // 提示
  832. return json_send(['code'=>'error','msg'=>'属性SKU匹配失败']);
  833. }
  834. $value['attr_ids'][] = $vv['id'];
  835. }
  836. }
  837. }
  838. // 转成好存储的数据
  839. $value['attr_ids'] = implode(',',$value['attr_ids']);
  840. // 转成好存储的数据
  841. $value['product_id']= $id;
  842. // 转成好存储的数据
  843. $value['sku_thumb'] = (string) $value['sku_thumb'];
  844. // 转成好存储的数据
  845. $value['stock_total']= $value['stock'];
  846. // 转成好存储的数据
  847. $value['insert_time']= time();
  848. // 转成好存储的数据
  849. $value['update_time']= time();
  850. // SKU结果
  851. $skuList[$attrNames] = $value;
  852. }
  853. // 循环城市范围
  854. foreach ($cityIds as $key => $value) {
  855. // 重组数据
  856. $cityIds[$key] = ['city_id'=>$value,'product_id'=>$id,'insert_time'=>time(),'update_time'=>time()];
  857. }
  858. // 写入城市范围
  859. $ProductCity->query()->insert($cityIds);
  860. // 返回结果
  861. $result = $ProductSkus->insert($skuList);
  862. // 提示新增失败
  863. if( !$result ) {
  864. // 回滚
  865. DB::rollBack();
  866. // 提示
  867. return json_send(['code'=>'error','msg'=>'SKU插入失败']);
  868. }
  869. // 更新内容
  870. $Model->updateDesc($id,$description);
  871. // 提交
  872. DB::commit();
  873. // 记录行为
  874. $this->addAdminHistory(admin('uid'),$Model->getTable(),$id,1,[],$data);
  875. // 告知结果
  876. return json_send(['code'=>'success','msg'=>'新增成功','action'=>'add']);
  877. } catch (\Throwable $th) {
  878. // 回滚
  879. DB::rollBack();
  880. // 提示
  881. return json_send(['code'=>'error','msg'=>'系统异常,写入失败','data'=>$th->getMessage()]);
  882. }
  883. }
  884. // 接收参数
  885. $id = request('id',0);
  886. // 查询数据
  887. $oldData = $Model->where(['id'=>$id])->first();
  888. // 如果是没有数据
  889. if( !$oldData ) return $this->error('查无数据');
  890. // 产品信息转格式
  891. $oldData = $oldData->toArray();
  892. $oldData['description'] = $Model->getDesc($id);
  893. $oldData['city_ids'] = $ProductCity->getListByProductId($id);
  894. $oldData['tag_scope'] = explode(',',$oldData['tag_scope']);
  895. $oldData['tag_exclude'] = explode(',',$oldData['tag_exclude']);
  896. $photoList = $ProductPhoto->getListByProductId($id);
  897. // 获取产品属性
  898. $attrList = $ProductAttr->getListByProductId($id);
  899. // 规格属性
  900. $specList = [];
  901. // 获取数据
  902. foreach ($attrList as $value) {
  903. $value['active'] = 0;
  904. if( !isset($specList[$value['spec_id']]) ) $specList[$value['spec_id']] = $ProductSpec->getOne($value['spec_id']);
  905. $specList[$value['spec_id']]['attr_list'][] = $value;
  906. }
  907. // 产品类型
  908. $skuList = $ProductSkus->getListByProductId($id);
  909. // 循环处理
  910. foreach ($skuList as $key => $value) {
  911. // 数据解析
  912. $value['attr_ids'] = explode(',',$value['attr_ids']);
  913. // 循环处理
  914. foreach ( $value['attr_ids'] as $k=>$attrId ) {
  915. // 获取ids对应的name
  916. $value['attr_ids'][$k] = $ProductAttr->getValueById($attrId,'name');
  917. }
  918. // 数据合并
  919. $value['attr_ids'] = implode(',',$value['attr_ids']);
  920. // 重组
  921. $skuList[$key] = $value;
  922. }
  923. // 标签列表
  924. $tagData = $WeiBanTags->query()->groupBy('group')->groupBy('name')->get(['group','name'])->toArray();
  925. // 标签列表
  926. $tagList = [];
  927. // 循环数据
  928. foreach ($tagData as $value) {
  929. $tagList[$value['group']][] = $value['name'];
  930. }
  931. // 获取类型数据
  932. $typeList = $ProductType->getList();
  933. $cityList = $City->getCityList();
  934. $businessList = $Business->getList();
  935. $producerList = $Producer->getList();
  936. // 分配数据
  937. $this->assign('tagList',$tagList);
  938. $this->assign('typeList',$typeList);
  939. $this->assign('cityList',$cityList);
  940. $this->assign('businessList',$businessList);
  941. $this->assign('producerList',$producerList);
  942. $this->assign('oldData',$oldData);
  943. $this->assign('photoList',$photoList);
  944. $this->assign('skuList',$skuList);
  945. $this->assign('specList',$specList);
  946. $this->assign('crumbs','复制');
  947. // 加载模板
  948. return $this->fetch();
  949. }
  950. /**
  951. * 状态
  952. *
  953. * */
  954. public function set_status( Request $request, Model $Model ){
  955. // 验证参数
  956. $request->scene('set_status')->validate();
  957. // 接收参数
  958. $id = request('id',0);
  959. $status = request('status',0);
  960. // 查询数据
  961. $result = $Model->edit($id,['status'=>$status]);
  962. // 提示新增失败
  963. if( !$result ) return json_send(['code'=>'error','msg'=>'设置失败']);
  964. // 记录行为
  965. $this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,[],['status'=>$status]);
  966. // 告知结果
  967. return json_send(['code'=>'success','msg'=>'设置成功','path'=>'']);
  968. }
  969. /**
  970. * 获取某个类目下的规格
  971. *
  972. */
  973. public function get_spec_html( ProductSpec $ProductSpec){
  974. // 接收参数
  975. $typeId = request('type_id',0);
  976. // 查询数据
  977. $specList = $ProductSpec->getList();
  978. // 循环处理
  979. foreach ($specList as $key => $value) {
  980. if( $value['type_id'] != $typeId ) unset($specList[$key]);
  981. }
  982. // 分配数据
  983. $this->assign('specList',$specList);
  984. // 加载模板
  985. return $this->fetch();
  986. }
  987. /**
  988. * 获取某个类目下的规格
  989. *
  990. */
  991. public function get_sku_html( ProductSpec $ProductSpec,ProductSkus $ProductSkus){
  992. // 接收参数
  993. $attr = request('attr',[]);
  994. $id = request('product_id',0);
  995. // 产品类型
  996. $oldSkus = $id ? $ProductSkus->getListByProductId($id) : [];
  997. // 获取规格属性
  998. $specAttr = $this->getSpecAttr($attr,$ProductSpec);
  999. // 组合SKU
  1000. $brushList = [];
  1001. // 循环规格属性
  1002. foreach ($specAttr as $specId => $value) {
  1003. // 获取SKU组合
  1004. $brushList[$specId] = array_column($value['attr_list'],'name');
  1005. }
  1006. // sku列表
  1007. $skuList = $this->brush([],$brushList);
  1008. // 循环规格属性
  1009. foreach ($skuList as $newKey => $new) {
  1010. // 获取新数据
  1011. $new = ['attr_names'=>$new,'price'=>0,'market_price'=>0,'stock'=>0,'min_quota'=>0,'quota'=>0,'status'=>0,'sku_thumb'=>''];
  1012. // 循环旧的sku
  1013. foreach ($oldSkus as $old) {
  1014. // 如果有相等的规格
  1015. if( $old['attr_names'] == $new['attr_names']) {
  1016. $new['sku_thumb'] = $old['sku_thumb'];
  1017. $new['market_price']= $old['market_price'];
  1018. $new['price'] = $old['price'];
  1019. $new['stock'] = $old['stock'];
  1020. $new['status'] = $old['status'];
  1021. $new['min_quota'] = $old['min_quota'];
  1022. $new['quota'] = $old['quota'];
  1023. }
  1024. }
  1025. $skuList[$newKey] = $new;
  1026. }
  1027. // 分配数据
  1028. $this->assign('specAttr',$specAttr);
  1029. $this->assign('skuList',$skuList);
  1030. // 加载模板
  1031. return $this->fetch();
  1032. }
  1033. /**
  1034. * 获取规格属性
  1035. * @param ProductSpec $ProductSpec
  1036. *
  1037. */
  1038. private function getSpecAttr($attr,$ProductSpec,$onlyList=false){
  1039. // 组合参数
  1040. $specAttr = [];
  1041. // 循环处理数据
  1042. foreach ($attr as $specId => $value) {
  1043. $specAttr[$specId]['spec_id'] = $specId;
  1044. $specAttr[$specId]['spec_name'] = $ProductSpec->getOne($specId,'name');
  1045. $specAttr[$specId]['attr_list'] = [];
  1046. foreach ($value['name'] as $key => $name) {
  1047. // 如果没有名称的,跳过
  1048. if( !$name ) continue;
  1049. // 结果
  1050. $temp = ['id'=>0,'spec_id'=>$specId,'thumb'=>'','name'=>'','remark'=>''];
  1051. // 获取名称
  1052. $temp['name'] = str_ireplace(',','',$name);
  1053. // 获取对应的备注信息
  1054. if( !empty($value['remark'][$key]) ) $temp['remark'] = $value['remark'][$key];
  1055. if( !empty($value['thumb'][$key]) ) $temp['thumb'] = $value['thumb'][$key];
  1056. // 获取对应的数据
  1057. $specAttr[$specId]['attr_list'][]= $temp;
  1058. }
  1059. // 没有属性的规格,移除
  1060. if( !$specAttr[$specId]['attr_list'] ) unset($specAttr[$specId]);
  1061. }
  1062. // 仅获取属性列表
  1063. if( $onlyList ) {
  1064. // 属性列表
  1065. $attrList = [];
  1066. // 判断结果
  1067. foreach ($specAttr as $value) {
  1068. // 获取数据
  1069. array_push($attrList,...$value['attr_list']);
  1070. }
  1071. // 返回结果
  1072. $specAttr = $attrList;
  1073. }
  1074. // 返回结果
  1075. return $specAttr;
  1076. }
  1077. /**
  1078. * 组合SKU
  1079. *
  1080. */
  1081. private function brush($res = [], $arr = []){
  1082. // 获取第一个规格的属性
  1083. if (empty($res)) $res = (array) array_shift($arr);
  1084. // 如果只有一个规格,返回该规格的属性即可
  1085. if (empty($arr)) return $res;
  1086. // 接下来要参与计算的一组属性
  1087. $current = array_shift($arr);
  1088. // 计算的列表
  1089. $last = [];
  1090. // 循环上一次已经算出的集合
  1091. foreach ($res as $attr) {
  1092. foreach ($current as $col_val) {
  1093. $last[] = $attr . ',' . $col_val;
  1094. }
  1095. }
  1096. return $this->brush($last,$arr); # 递归处理, 直到$arr滚到最后一组属性
  1097. }
  1098. /**
  1099. * 排序
  1100. *
  1101. * */
  1102. public function set_sort( Request $request, Model $Model ){
  1103. // 验证参数
  1104. $request->scene('set_sort')->validate();
  1105. // 接收参数
  1106. $id = request('id',0);
  1107. $sort = request('sort',0);
  1108. // 查询数据
  1109. $result = $Model->edit($id,['sort'=>$sort]);
  1110. // 提示新增失败
  1111. if( !$result ) return json_send(['code'=>'error','msg'=>'设置失败']);
  1112. // 记录行为
  1113. $this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,[],['sort'=>$sort]);
  1114. // 告知结果
  1115. return json_send(['code'=>'success','msg'=>'设置成功','path'=>'']);
  1116. }
  1117. }