Product.php 45 KB

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