Product.php 46 KB

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