Product.php 45 KB

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