WxShopGoodsController.php 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996
  1. <?php
  2. namespace App\Admin\Controllers\Shop;
  3. use App\Admin\Actions\Extensions\Shop\ShopContactButton;
  4. use App\Admin\Actions\Grid\GoodsTransferAction;
  5. use App\Admin\Renderable\QuestionRender;
  6. use App\Lib\Uploads\UploadHandler;
  7. use App\Models\Shop\WxShopCart;
  8. use App\Models\Shop\WxShopContact;
  9. use App\Models\User\WxUser;
  10. use App\Models\WxQuestion;
  11. use App\Wen\Utils\AdminUtils;
  12. use App\Wen\Utils\FieldUtils;
  13. use App\Wen\Utils\Settings;
  14. use App\Wen\Utils\UserUtils;
  15. use DateTime;
  16. use Dcat\Admin\Actions\Action;
  17. use Dcat\Admin\Admin;
  18. use Dcat\Admin\Form;
  19. use Dcat\Admin\Form\NestedForm;
  20. use Dcat\Admin\Grid;
  21. use Dcat\Admin\Http\JsonResponse;
  22. use Dcat\Admin\Show;
  23. use Dcat\Admin\Http\Controllers\AdminController;
  24. use App\Models\Shop\WxShopClassify;
  25. use App\Models\Shop\WxShopGoods;
  26. use App\Models\Shop\WxShopGoodsProduct;
  27. use App\Models\Shop\WxShopService;
  28. use Dcat\Admin\Widgets\Tooltip;
  29. use Illuminate\Http\Request;
  30. use Illuminate\Support\Facades\DB;
  31. class WxShopGoodsController extends AdminController
  32. {
  33. public function goods(Request $request)
  34. {
  35. $q = $request->get('q');
  36. $admin_user = Admin::user();
  37. if($admin_user->isAdministrator()){
  38. return WxShopGoods::where('name', 'like', "%$q%")->paginate(null, ['id', 'name as text']);
  39. }else{
  40. if(_empty_($admin_user->uid)){
  41. return WxShopGoods::where('name', 'like', "%$q%")->paginate(null, ['id', 'name as text']);
  42. }else{
  43. return WxShopGoods::where('user_id', $admin_user->uid)->where('name', 'like', "%$q%")->paginate(null, ['id', 'name as text']);
  44. }
  45. }
  46. }
  47. /**
  48. * Make a grid builder.
  49. *
  50. * @return Grid
  51. */
  52. protected function grid()
  53. {
  54. $admin_user = Admin::user();
  55. $classfyids = WxShopClassify::where('depth', 3)->pluck('name', 'id')->toArray();
  56. $classfyids[0] = '未分类';
  57. $app_coin_name = Settings::get('app_coin_name', '硬币');
  58. return Grid::make(new WxShopGoods(), function (Grid $grid) use ($classfyids, $app_coin_name, $admin_user){
  59. global $__MINI_GLOBAL_IS_ADMIN_SUPER__;
  60. $grid->simplePaginate();
  61. if(!$admin_user->isAdministrator()){
  62. if(_empty_($admin_user->uid)){
  63. $grid->model()->where('id', '<', -1);
  64. }else{
  65. $grid->model()->where('user_id', $admin_user->uid);
  66. }
  67. }
  68. $grid->quickSearch(['id', 'name'])->placeholder('搜索商品ID,名字...');
  69. $grid->model()->orderBy('id', 'desc');
  70. $grid->column('id')->sortable();
  71. $grid->column('user', '商家')->display(function ($v){
  72. if(_empty_($v)){
  73. return '系统自营';
  74. }
  75. return '<a href="'.admin_url('/users?id='.$v->id).'" target="_blank"><img src="'.$v->user_avatar.'" style="width: 30px; height: 30px;margin-right: 10px; border-radius: 50%;">'.$v->user_name. '</a>';
  76. });
  77. $grid->column('name')->limit(20);
  78. $grid->column('type')->using(FieldUtils::getShopGoodTypes())->sortable();
  79. // $grid->column('pic');
  80. // $grid->column('tag');
  81. // $grid->column('intro');
  82. $grid->column('vip_price')->display(function ($v) use ($app_coin_name){
  83. if($this->credit_type == 1){
  84. return '¥'.$v;
  85. }else{
  86. return $v.$app_coin_name;
  87. }
  88. })->sortable();
  89. $grid->column('price')->display(function ($v) use ($app_coin_name){
  90. if($this->credit_type == 1){
  91. return '¥'.$v;
  92. }else{
  93. return $v.$app_coin_name;
  94. }
  95. })->sortable();
  96. // $grid->column('content');
  97. $grid->column('views')->sortable()->editable();
  98. $grid->column('buys')->sortable()->editable();
  99. $grid->column('can_purchase_times', '限购次数')->sortable()->editable();
  100. $grid->column('rest_stock', '剩余库存')->display(function (){
  101. return WxShopGoodsProduct::where('goods_id', $this->id)->sum('stock');
  102. });
  103. // $grid->column('sku');
  104. // $grid->column('service_id');
  105. $grid->column('sort')->editable();
  106. // $grid->column('is_inspiration','灵感')->switch()->sortable();
  107. $grid->column('state')->switch()->sortable();
  108. if($__MINI_GLOBAL_IS_ADMIN_SUPER__){
  109. $grid->column('classify_id')->sortable()->select($classfyids);
  110. $grid->column('collect_from_url')->display(function ($v){
  111. if(_empty_($v)){
  112. return '';
  113. }
  114. return '<a href="'.$v.'" target="_blank">链接</a>';
  115. });
  116. }
  117. // $grid->column('created_at');
  118. // $grid->column('updated_at')->sortable();
  119. $grid->filter(function (Grid\Filter $filter) use ($classfyids){
  120. $filter->equal('id');
  121. $filter->equal('type')->multipleSelect(FieldUtils::getShopGoodTypes());
  122. // $filter->equal('classify_id')->multipleSelect($classfyids);
  123. $filter->like('name');
  124. $filter->equal('classify_id')->multipleSelect($classfyids);
  125. });
  126. $grid->batchActions(function ($batch) {
  127. $batch->add(new GoodsTransferAction());
  128. });
  129. global $__MINI_GLOBAL_IS_ADMIN_SUPER__;
  130. if($__MINI_GLOBAL_IS_ADMIN_SUPER__){
  131. $grid->tools([
  132. new ShopContactButton(),
  133. ]);
  134. }
  135. });
  136. }
  137. /**
  138. * Make a show builder.
  139. *
  140. * @param mixed $id
  141. *
  142. * @return Show
  143. */
  144. protected function detail($id)
  145. {
  146. return Show::make($id, new WxShopGoods(), function (Show $show) {
  147. $show->field('id');
  148. $show->field('name');
  149. $show->field('type');
  150. // $show->field('pic');
  151. // $show->field('tag');
  152. $show->field('intro');
  153. $show->field('vip_price');
  154. $show->field('price');
  155. $show->field('credit_type');
  156. $show->field('content');
  157. $show->field('views');
  158. $show->field('buys');
  159. $show->field('sort');
  160. $show->field('sku');
  161. $show->field('guest_present');
  162. $show->field('service_time_start');
  163. $show->field('service_time_end');
  164. $show->field('url');
  165. $show->field('download_version');
  166. $show->field('question_id');
  167. $show->field('can_purchase_times');
  168. $show->field('users_ledger');
  169. $show->field('classify_id');
  170. // $show->field('service_id');
  171. $show->field('state');
  172. $show->field('collect_from_url');
  173. $show->field('last_sales_at');
  174. $show->field('created_at');
  175. $show->field('updated_at');
  176. });
  177. }
  178. /**
  179. * Make a form builder.
  180. *
  181. * @return Form
  182. */
  183. protected function form()
  184. {
  185. $app_coin_name = Settings::get('app_coin_name', '硬币');
  186. return Form::make(new WxShopGoods(), function (Form $form) use ($app_coin_name){
  187. global $__MINI_GLOBAL_IS_ADMIN_SUPER__,$__MINI_GLOBAL_CURRENT_USER_ID__;
  188. $modle = $form->model();
  189. $res11 = __system__paycode__tip__(11);
  190. Tooltip::make('.mini_global_admin_open_not_support_tip')
  191. ->bottom()
  192. ->title($res11['tip']);
  193. $form->display('id');
  194. $form->text('name','商品名称')->required();
  195. if($form->isCreating()){
  196. $form->radio('credit_type', '货币')->options([ 0=> $app_coin_name, 1 => '余额/人民币'])->default(1)->required();
  197. }else{
  198. $form->html(function () use ($modle, $app_coin_name){
  199. return '<div style="background-color: powderblue;color: #414750;padding: 10px;border-radius: 5px;">编辑模式不可更改货币类型,当前商品货币为:<span style="color: red;">'.($modle->credit_type == 1 ? '余额/人民币' : $app_coin_name).'</span></div>';
  200. }, '');
  201. }
  202. $form->text('vip_price','商品VIP价格')->required();
  203. $form->text('price','商品价格')->required();
  204. $form->textarea('intro','商品介绍');
  205. $options = AdminUtils::get_admin_user_shop_classifys();
  206. if(_empty_($options)){
  207. $form->html(function () use ($modle, $app_coin_name, $__MINI_GLOBAL_IS_ADMIN_SUPER__){
  208. if($__MINI_GLOBAL_IS_ADMIN_SUPER__){
  209. return '<div style="background-color: transparent;color: #414750;padding: 10px;border-radius: 5px;color: red;">!!! 当前没有第三层级的商品分类,无法新增商品</div>';
  210. }else{
  211. return '<div style="background-color: transparent;color: #414750;padding: 10px;border-radius: 5px;color: red;">!!! 当前后台账号无绑定的店铺id,无法新增商品,可联系超级管理员将你的后台账号角色变更为:商城管理员(标识:enterprise_admin)</div>';
  212. }
  213. }, '');
  214. }else{
  215. $form->select('classify_id','商品分类')->options($options);
  216. }
  217. if($__MINI_GLOBAL_IS_ADMIN_SUPER__){
  218. $form->tags('tag','话题')
  219. ->options(['上新','活动','折扣','预售','会员','推荐','特价','京东','淘宝','拼多多', '抖音', '限时', '性价比', '虚拟物品'])
  220. ->help('使用,隔开 建议添加1~3个话题');
  221. }
  222. $form->multipleSelect('service_id','服务')
  223. ->options(WxShopService::pluck('name','id'));
  224. $form->multipleImage('pic', '图片')->uniqueName()->url('files/uploads')->uniqueName()
  225. ->autoUpload()->sortable();
  226. $sku_params = [];
  227. $form->sku('sku', json_encode($sku_params))->display(true)->customFormat(function ($value) use ($form){
  228. if($value){
  229. // 这里是给sku喂数据, 数据格式为
  230. $data = (new WxShopGoods())->where('id',$form->getKey())->value('sku');
  231. if($data){
  232. if($form->isEditing()){
  233. $goods_id = $form->model()->id;
  234. $data = json_decode($data, true);
  235. if($data){
  236. $sku_arr = $data['sku'];
  237. $attrs_arr = $data['attrs'];
  238. if($sku_arr){
  239. for ($i = 0; $i < count($sku_arr); $i++){
  240. $attr_arr = [];
  241. foreach (array_keys($sku_arr[0]) as $key){
  242. if($key == 'pic' || $key == 'stock' || $key == 'vip_price' || $key == 'price'){
  243. continue;
  244. }
  245. $attr_arr[] = $key;
  246. }
  247. $attr_key = '';
  248. if($attr_arr){
  249. foreach ($attr_arr as $attr){
  250. if(!_empty_($attr_key)){
  251. $attr_key .= '_';
  252. }
  253. $attr_key .= $sku_arr[$i][$attr];
  254. }
  255. }
  256. $stock = WxShopGoodsProduct::where('goods_id', $goods_id)->where('param_value', $attr_key )->value('stock');
  257. $data['sku'][$i]['stock'] = $stock;
  258. }
  259. }
  260. }
  261. }
  262. }
  263. return json_encode($data);
  264. }
  265. return null;
  266. });
  267. $form->radio('type')->default(0)->options(FieldUtils::getShopGoodTypes())->when(0, function (Form $form) use ($sku_params) {
  268. })->when(1, function (Form $form){
  269. $form->url('url')->help('普通商品留空,淘客链接填在这里,存在链接的商品无法被购买');
  270. })->when(2, function (Form $form) use ($res11, $modle){
  271. if($form->isCreating()){
  272. $form->textarea('paid_content1', '虚拟付费内容')->help($res11['text'].'用户支付的订单中包含虚拟物品时,订单会增加一个按钮[查看虚拟物品],如果该次订单全部都是虚拟物品,则会自动改变订单为【已发货】状态');
  273. }else{
  274. $form->textarea('paid_content1', '虚拟付费内容')->help($res11['text'].'用户支付的订单中包含虚拟物品时,订单会增加一个按钮[查看虚拟物品],如果该次订单全部都是虚拟物品,则会自动改变订单为【已发货】状态')->value($modle->paid_content);
  275. }
  276. })->when(3, function (Form $form) use ($res11){
  277. $form->url('download_url')->help($res11['text'].'https://开头可访问地址');
  278. $form->text('download_version')->help('编辑修改版本号后,会通知已经购买过的用户');
  279. })->when(4, function (Form $form) use ($res11, $modle){
  280. $form->html(function (){
  281. return '<div style="background-color: powderblue;color: #414750;padding: 10px;border-radius: 5px;">卡密一行一个,每次用户购买后,若卡密全部消耗完毕,则会发送消息提示管理员,并下架该商品</div>';
  282. }, '');
  283. if($form->isCreating()) {
  284. $form->textarea('paid_content2', '卡密')->help($res11['text'] . '用户支付的订单中包含虚拟物品时,订单会增加一个按钮[查看卡密],如果该次订单全部都是虚拟物品,则会自动改变订单为【已发货】状态');
  285. }else{
  286. $form->textarea('paid_content2', '卡密')->help($res11['text'] . '用户支付的订单中包含虚拟物品时,订单会增加一个按钮[查看卡密],如果该次订单全部都是虚拟物品,则会自动改变订单为【已发货】状态')->value($modle->paid_content);
  287. }
  288. })->when(5, function (Form $form) use ($res11, $modle, $__MINI_GLOBAL_CURRENT_USER_ID__,$__MINI_GLOBAL_IS_ADMIN_SUPER__){
  289. if($__MINI_GLOBAL_IS_ADMIN_SUPER__){
  290. $arr = WxShopContact::pluck('address_name', 'id');
  291. }else{
  292. $arr = WxShopContact::where('user_id', $__MINI_GLOBAL_CURRENT_USER_ID__)->pluck('address_name', 'id');
  293. }
  294. $form->select('contact_id')->options($arr)->help('若没有地址可选,请去前端【我->左侧栏->管理店铺->经营地址->去添加】');
  295. $form->text('scanners')->help('输入员工在前端的uid,多个用英文逗号隔开');
  296. })->required();
  297. if(__system_is_model_enable('laradocs', 'dcat-neditor')){
  298. $form->neditor('content');
  299. }else{
  300. $form->editor('content');
  301. }
  302. if($__MINI_GLOBAL_IS_ADMIN_SUPER__){
  303. $form->multipleSelectTable('question_id')
  304. ->title('帮助问题库')
  305. ->max(1)
  306. ->from(QuestionRender::make())
  307. ->model(WxQuestion::class, 'id', 'title', 'selectTable:WxShopGoodsController:question_id');
  308. }
  309. $form->number('can_purchase_times')->help('若每人限购一次,已经购买的用户不会在商品详情页显示[加入购物车]')->default(0);
  310. $res23 = __system__paycode__tip__(23);
  311. Tooltip::make('.mini_global_admin_open_not_support_tip')
  312. ->bottom()
  313. ->title($res23['tip']);
  314. $users_ledger_flag = false;
  315. if(!$__MINI_GLOBAL_IS_ADMIN_SUPER__){
  316. $users_ledger_flag = true;
  317. }else{
  318. $users_ledger_flag = true;
  319. }
  320. if($users_ledger_flag){
  321. $form->html(function () use ($res23){
  322. return '<div style="background-color: powderblue;color: #414750;padding: 10px;border-radius: 5px;">'.$res23['text'].'注意:
  323. <br>1、是根据订单价格分账,所以请自己计算好利润,用户下单后,分账用户获得的分账会进入冻结中,在确认收货后,会自动解冻。
  324. <br>2、请勿随意设置百分比,因为我们所有商品都是自营,用户分账剩下的才是平台所得,如果你设置分账总和超过100,那么平台会亏损
  325. <br>3、若用户退款,则冻结的余额会被删除</div>';
  326. }, '');
  327. $form->table('users_ledger','分账用户', function (NestedForm $table) {
  328. $table->select('user_id', '用户')->options(function ($id) {
  329. if($id){
  330. $user = \App\Models\User\WxUser::find($id);
  331. if ($user) {
  332. return [$user->id => $user->user_name];
  333. }
  334. }
  335. })->ajax('select/users')->required();
  336. $table->rate('rate', '百分比');
  337. });
  338. $form->divider();
  339. }
  340. $form->text('guest_present')->help('填嘉宾的用户id,用英文逗号隔开');
  341. // $form->multipleSelect('guest_present')->options(function ($ids) {
  342. // if($ids){
  343. // $res = [];
  344. // foreach ($ids as $id){
  345. // $user = \App\Models\User\WxUser::find($id);
  346. // if ($user) {
  347. // $res[$user->id] = $user->user_name;
  348. // }
  349. // }
  350. // return $res;
  351. // }
  352. // })->ajax('select/users')->help('在商品详情页可以展示几个用户');
  353. $form->divider();
  354. $form->html(function () use ($res23){
  355. return '<div style="background-color: powderblue;color: #414750;padding: 10px;border-radius: 5px;">时间仅仅起提示作用,为用户展示您的服务时间,无实际作用,一般与核销一同使用</div>';
  356. }, '');
  357. $form->dateRange('service_date_start', 'service_date_end', '服务日期')->help('如果您的服务日期是每天,则留空,如果不是日期范围,而是具体的某一天,则只用配置开始日期');
  358. $form->timeRange('service_time_start', 'service_time_end', '服务时间')->help('如果您的服务时间是全天,则留空');
  359. $form->divider();
  360. if($__MINI_GLOBAL_IS_ADMIN_SUPER__){
  361. $form->text('views')->default(0);
  362. $form->text('buys')->default(0);
  363. $form->number('sort');
  364. }
  365. // $form->switch('is_inspiration');
  366. $form->switch('state')->default(1);
  367. $form->datetime('last_sales_at')->default('2099-01-01 00:00:00');
  368. if ($form->isEditing()) {
  369. $id = $form->getKey();
  370. $form->action('shop/save_goods/'.$id);
  371. }else{
  372. $form->action('shop/add_goods');
  373. }
  374. });
  375. }
  376. function isValidDateTime($dateTime) {
  377. $format = 'Y-m-d H:i:s';
  378. $d = DateTime::createFromFormat($format, $dateTime);
  379. return $d && $d->format($format) == $dateTime;
  380. }
  381. public function safe_add(Request $request){
  382. global $__MINI_GLOBAL_IS_ADMIN_SUPER__;
  383. $__MINI_GLOBAL_IS_ADMIN_SUPER__ = true;
  384. $collect_from_url = _empty_default_($request->collect_from_url, '');
  385. if(_empty_($collect_from_url)){
  386. return JsonResponse::make()->warning('未提交collect_from_url字段值');
  387. }
  388. $exists = WxShopGoods::where('collect_from_url', $collect_from_url)->first();
  389. if($exists){
  390. return JsonResponse::make()->warning('collect_from_url已经存在对应的商品,商品id为:'.$exists->id);
  391. }
  392. return $this->add($request);
  393. }
  394. public function add(Request $request){
  395. global $__MINI_GLOBAL_IS_ADMIN_SUPER__,$__MINI_GLOBAL_CURRENT_USER_ID__;
  396. $input = $request->all();
  397. $collect_from_url = _empty_default_($request->collect_from_url, '');
  398. if(_empty_($input['last_sales_at'])){
  399. $input['last_sales_at'] = '2099-01-01 00:00:00';
  400. }
  401. if($this->isValidDateTime($input['last_sales_at'])){
  402. }else{
  403. $input['last_sales_at'] = '2099-01-01 00:00:00';
  404. }
  405. if($input['type'] == 2 || $input['type'] == 4){
  406. if($input['type'] == 2){
  407. $input['paid_content'] = $input['paid_content1'];
  408. }else if($input['type'] == 4){
  409. $input['paid_content'] = $input['paid_content2'];
  410. }
  411. }else{
  412. $input['paid_content'] = '';
  413. }
  414. foreach (['service_date_start','service_date_end','service_time_start','service_time_end'] as $key){
  415. if(_empty_($input[$key])){
  416. $input[$key] = null;
  417. }
  418. }
  419. if($input['service_date_end']){
  420. if($input['service_date_start'] >= $input['service_date_end']){
  421. $input['service_date_end'] = null;
  422. $input['service_date_start'] = null;
  423. }
  424. }
  425. if(_empty_($input['service_date_start'])){
  426. $input['service_date_end'] = null;
  427. }
  428. if(_empty_($input['service_time_start']) || $input['service_time_start'] > $input['service_time_end']){
  429. $input['service_time_end'] = null;
  430. $input['service_time_start'] = null;
  431. }
  432. $guest_present = _empty_default_($input['guest_present'], '');
  433. if(is_string($guest_present)){
  434. $guest_present = explode(',', $guest_present);
  435. }
  436. if(is_array($guest_present)){
  437. $guest_present = array_values($guest_present);
  438. if($guest_present){
  439. if(_empty_(end($guest_present))){
  440. array_pop($guest_present);
  441. }
  442. foreach ($guest_present as $gid){
  443. if(!(WxUser::where('id', $gid)->exists())){
  444. return JsonResponse::make()->error('您配置的嘉宾不存在');
  445. }
  446. }
  447. }else{
  448. $guest_present = [];
  449. }
  450. }else{
  451. $guest_present = [];
  452. }
  453. if(_empty_($guest_present)){
  454. $guest_present = [];
  455. }
  456. if($input['type'] == 5){
  457. if(_empty_(_array_key($input, 'contact_id', 0))){
  458. return JsonResponse::make()->error('核销类商品必须添加经营地址');
  459. }
  460. if(!$__MINI_GLOBAL_IS_ADMIN_SUPER__){
  461. if(WxShopContact::where('id', $input['contact_id'])->value('user_id') != $__MINI_GLOBAL_CURRENT_USER_ID__){
  462. return JsonResponse::make()->error('您添加的经营地址不属于您');
  463. }
  464. }
  465. if(!_empty_(_array_key($input, 'scanners', ''))){
  466. $input['scanners'] = trim($input['scanners'], ',');
  467. $scanners_arr = explode(',', $input['scanners']);
  468. foreach ($scanners_arr as $scanner){
  469. if(!(WxUser::where('id', $scanner)->exists())){
  470. return JsonResponse::make()->error('您添加的核销员,uid为'.$scanner.'实际不存在');
  471. }
  472. }
  473. }
  474. }else{
  475. $input['contact_id'] = null;
  476. $input['scanners'] = '';
  477. }
  478. if($__MINI_GLOBAL_IS_ADMIN_SUPER__){
  479. $tag = $input['tag'];
  480. unset($tag[count($tag)-1]);
  481. }else{
  482. $tag = [];
  483. }
  484. $service = $input['service_id'];
  485. unset($service[count($service)-1]);
  486. $options = AdminUtils::get_admin_user_shop_classifys();
  487. if(_empty_($options)){
  488. if($__MINI_GLOBAL_IS_ADMIN_SUPER__){
  489. return JsonResponse::make()->error('当前没有第3层级的商品分类,无法新增商品');
  490. }else{
  491. return JsonResponse::make()->error('当前后台账号无绑定的店铺,无法新增商品');
  492. }
  493. }else if(!in_array(_array_key($input, 'classify_id', 0), array_keys($options))){
  494. return JsonResponse::make()->error('店铺的经营分类未包含当前所选的商品分类');
  495. }
  496. if(!$__MINI_GLOBAL_IS_ADMIN_SUPER__){
  497. $shop = AdminUtils::get_admin_shop();
  498. if($shop->margin_rest < $shop->margin_least){
  499. return JsonResponse::make()->error('您店铺的保证金不足,无法发布新商品');
  500. }
  501. }
  502. $users_ledger_flag = false;
  503. if(!$__MINI_GLOBAL_IS_ADMIN_SUPER__){
  504. $users_ledger_flag = true;
  505. }else{
  506. $users_ledger_flag = true;
  507. }
  508. if($users_ledger_flag){
  509. $users_ledger = AdminUtils::_table_data($request->input('users_ledger'));
  510. }else{
  511. $users_ledger = '[]';
  512. }
  513. $credit_type = $input['credit_type'] == 1 ? 1 : 0;
  514. DB::beginTransaction();
  515. try {
  516. // todo:
  517. $GoodsModel = new WxShopGoods();
  518. $GoodsModel->type = $input['type'];
  519. if(!$__MINI_GLOBAL_IS_ADMIN_SUPER__){
  520. if($__MINI_GLOBAL_CURRENT_USER_ID__ > 0){
  521. $GoodsModel->user_id = $__MINI_GLOBAL_CURRENT_USER_ID__;
  522. $GoodsModel->shop_id = WxUser::where('id', $__MINI_GLOBAL_CURRENT_USER_ID__)->value('shop_id');
  523. }
  524. }
  525. $GoodsModel->name = $input['name'];
  526. $GoodsModel->pic = $input['pic'];
  527. $GoodsModel->vip_price = $credit_type == 1 ? $input['vip_price'] : (int)$input['vip_price'];
  528. $GoodsModel->price = $credit_type == 1 ? $input['price'] : (int)$input['price'];
  529. $GoodsModel->credit_type = $credit_type;
  530. $GoodsModel->classify_id = $input['classify_id'];
  531. $GoodsModel->content = $input['content'];
  532. $GoodsModel->views = $__MINI_GLOBAL_IS_ADMIN_SUPER__ ? ($input['views'] ?: 0) : 0;
  533. $GoodsModel->buys = $__MINI_GLOBAL_IS_ADMIN_SUPER__ ? ($input['buys'] ?: 0 ) : 0;
  534. $GoodsModel->state = $input['state'];
  535. $GoodsModel->sku = $input['sku'];
  536. $GoodsModel->contact_id = $input['contact_id'];
  537. $GoodsModel->scanners = $input['scanners'];
  538. $GoodsModel->url = $input['url'];
  539. $GoodsModel->download_version = $input['download_version'];
  540. $GoodsModel->download_url = $input['download_url'];
  541. $GoodsModel->question_id = $__MINI_GLOBAL_IS_ADMIN_SUPER__ ? $input['question_id'] : 0;
  542. $GoodsModel->can_purchase_times = $input['type'] == 1 ? 0 : $input['can_purchase_times'];
  543. $GoodsModel->paid_content = $input['paid_content'];
  544. $GoodsModel->intro = $input['intro'];
  545. $GoodsModel->service_id = json_encode($service);
  546. if($users_ledger){
  547. $GoodsModel->users_ledger = $users_ledger;
  548. }
  549. $GoodsModel->tag = json_encode($tag);
  550. $GoodsModel->last_sales_at = $input['last_sales_at'];
  551. if($guest_present){
  552. $GoodsModel->guest_present = implode(',', $guest_present);
  553. }
  554. if(!_empty_($input['service_date_start'])){
  555. $GoodsModel->service_date_start = $input['service_date_start'];
  556. }
  557. if(!_empty_($input['service_date_end'])){
  558. $GoodsModel->service_date_end = $input['service_date_end'];
  559. }
  560. if(!_empty_($input['service_time_start'])){
  561. $GoodsModel->service_time_start = $input['service_time_start'];
  562. }
  563. if(!_empty_($input['service_time_end'])){
  564. $GoodsModel->service_time_end = $input['service_time_end'];
  565. }
  566. if($collect_from_url){
  567. $GoodsModel->collect_from_url = $collect_from_url;
  568. }
  569. $GoodsModel->save();
  570. $goods_id = $GoodsModel->id;
  571. // 保存产品
  572. $params = json_decode($input['sku'],true);
  573. $sku = $params['sku'];
  574. $attrs = $params['attrs'];
  575. $attrsArr = array_values($attrs);
  576. $attrsArr = $this->brush([],$attrsArr);
  577. $productData = [];
  578. foreach ($attrsArr as $k=>$v){
  579. if($credit_type == 1){
  580. if(_empty_($sku[$k]['vip_price']) || _empty_($sku[$k]['price'])){
  581. DB::rollBack();
  582. return JsonResponse::make()->error('SKU未设置价格!');
  583. }
  584. }else{
  585. if(_empty_((int)$sku[$k]['vip_price']) || _empty_((int)$sku[$k]['price'])){
  586. DB::rollBack();
  587. return JsonResponse::make()->error('SKU未设置价格!');
  588. }
  589. }
  590. $productData[] = [
  591. 'goods_id' => $goods_id,
  592. 'vip_price'=>$credit_type == 1 ? $sku[$k]['vip_price'] : (int)$sku[$k]['vip_price'],
  593. 'price'=>$credit_type == 1 ? $sku[$k]['price'] : (int)$sku[$k]['price'],
  594. 'stock'=>$sku[$k]['stock'],
  595. 'pic'=>$sku[$k]['pic'] ?? $input['pic'],
  596. 'param_value'=>$v,
  597. 'created_at'=>date('Y-m-d H:i:s'),
  598. 'credit_type' => $credit_type
  599. ];
  600. }
  601. (new WxShopGoodsProduct())->batchAdd($productData);
  602. DB::commit();
  603. return JsonResponse::make()->success('成功!')->redirect('shop/goods');
  604. } catch (\Exception $e) {
  605. DB::rollBack();
  606. _logger_(__file__, __line__, $e->getMessage());
  607. return JsonResponse::make()->error('保存出错!');
  608. }
  609. }
  610. public function delte_goods_product($goods_id){
  611. $product_ids = WxShopGoodsProduct::where('goods_id',$goods_id)->pluck('id')->toArray();
  612. if(_empty_($product_ids)){
  613. $product_ids = [];
  614. }
  615. $app_luck_draw = Settings::get('app_luck_draw', []);
  616. if($app_luck_draw){
  617. $luck_draw_flag = false;
  618. $luck_dray_names = [];
  619. $app_luck_draw_new = [];
  620. $app_luck_draw_disable = [];
  621. for ($i = 0; $i < count($app_luck_draw); $i ++){
  622. if($app_luck_draw[$i]['type'] == 3){
  623. if(in_array(_array_key($app_luck_draw[$i], 'product', 0), $product_ids)){
  624. $luck_draw_flag = true;
  625. $luck_dray_names[] = $app_luck_draw[$i]['name'];
  626. $app_luck_draw[$i]['product'] = '';
  627. $app_luck_draw_disable[] = $app_luck_draw[$i];
  628. continue;
  629. }
  630. }
  631. $app_luck_draw_new[] = $app_luck_draw[$i];
  632. }
  633. if($luck_draw_flag){
  634. Settings::set('app_luck_draw', json_encode($app_luck_draw_new), true);
  635. UserUtils::assistant_notice('admin', '你配置的抽奖转盘中,存在商品规格['.implode(',',$luck_dray_names).']失效,原因是你修改了原商品,需要你在后台重新配置,原配置请看下方提示, 点击可前往<a href="/pagesB/luckdraw/luckdraw">抽奖页面</a>');
  636. foreach ($app_luck_draw_disable as $item){
  637. UserUtils::assistant_notice('admin', 'id: '.$item['id'].'<br/>'. '图片:'.$item['img'].'<br/>'. '奖项名称:'.$item['name'].'<br/>'. '权重:'.$item['weight'].'<br/>'. '奖励类型:'.$item['type'].'<br/>'. '奖励数量:'.$item['num']);
  638. }
  639. }
  640. }
  641. WxShopGoodsProduct::where('goods_id',$goods_id)->delete();
  642. WxShopCart::where('goods_id', $goods_id)->where('state', 0)->update(['state'=>3]);
  643. }
  644. public function safe_save(Request $request,$goods_id){
  645. global $__MINI_GLOBAL_IS_ADMIN_SUPER__;
  646. $__MINI_GLOBAL_IS_ADMIN_SUPER__ = true;
  647. return $this->save($request, $goods_id);
  648. }
  649. public function save(Request $request,$goods_id){
  650. global $__MINI_GLOBAL_IS_ADMIN_SUPER__,$__MINI_GLOBAL_CURRENT_USER_ID__;
  651. $input = $request->all();
  652. if(_empty_($input['last_sales_at'])){
  653. $input['last_sales_at'] = '2099-01-01 00:00:00';
  654. }
  655. if($this->isValidDateTime($input['last_sales_at'])){
  656. }else{
  657. $input['last_sales_at'] = '2099-01-01 00:00:00';
  658. }
  659. if($input['type'] == 2 || $input['type'] == 4){
  660. if($input['type'] == 2){
  661. $input['paid_content'] = $input['paid_content1'];
  662. }else if($input['type'] == 4){
  663. $input['paid_content'] = $input['paid_content2'];
  664. }
  665. }else{
  666. $input['paid_content'] = '';
  667. }
  668. foreach (['service_date_start','service_date_end','service_time_start','service_time_end'] as $key){
  669. if(_empty_($input[$key])){
  670. $input[$key] = null;
  671. }
  672. }
  673. if($input['service_date_end']){
  674. if($input['service_date_start'] >= $input['service_date_end']){
  675. $input['service_date_end'] = null;
  676. $input['service_date_start'] = null;
  677. }
  678. }
  679. if(_empty_($input['service_date_start'])){
  680. $input['service_date_end'] = null;
  681. }
  682. if(_empty_($input['service_time_start']) || $input['service_time_start'] > $input['service_time_end']){
  683. $input['service_time_end'] = null;
  684. $input['service_time_start'] = null;
  685. }
  686. $guest_present = _empty_default_($input['guest_present'], []);
  687. if(is_string($guest_present)){
  688. $guest_present = explode(',', $guest_present);
  689. }
  690. if(is_array($guest_present)){
  691. $guest_present = array_values($guest_present);
  692. if($guest_present){
  693. if(_empty_(end($guest_present))){
  694. array_pop($guest_present);
  695. }
  696. foreach ($guest_present as $gid){
  697. if(!(WxUser::where('id', $gid)->exists())){
  698. return JsonResponse::make()->error('您配置的嘉宾不存在');
  699. }
  700. }
  701. }else{
  702. $guest_present = [];
  703. }
  704. }else{
  705. $guest_present = [];
  706. }
  707. if(_empty_($guest_present)){
  708. $guest_present = [];
  709. }
  710. if($input['type'] == 5){
  711. if(_empty_(_array_key($input, 'contact_id', 0))){
  712. return JsonResponse::make()->error('核销类商品必须添加经营地址');
  713. }
  714. if(!$__MINI_GLOBAL_IS_ADMIN_SUPER__){
  715. if(WxShopContact::where('id', $input['contact_id'])->value('user_id') != $__MINI_GLOBAL_CURRENT_USER_ID__){
  716. return JsonResponse::make()->error('您添加的经营地址不属于您');
  717. }
  718. }
  719. if(!_empty_(_array_key($input, 'scanners', ''))){
  720. $scanners_arr = explode(',', $input['scanners']);
  721. foreach ($scanners_arr as $scanner){
  722. if(!(WxUser::where('id', $scanner)->exists())){
  723. return JsonResponse::make()->error('您添加的核销员,uid为'.$scanner.'实际不存在');
  724. }
  725. }
  726. }
  727. }else{
  728. $input['contact_id'] = null;
  729. }
  730. $options = AdminUtils::get_admin_user_shop_classifys();
  731. if(_empty_($options)){
  732. if($__MINI_GLOBAL_IS_ADMIN_SUPER__){
  733. return JsonResponse::make()->error('当前没有第3层级的商品分类,无法新增商品');
  734. }else{
  735. return JsonResponse::make()->error('当前后台账号无绑定的店铺,无法新增商品');
  736. }
  737. }else if(!in_array($input['classify_id'], array_keys($options))){
  738. return JsonResponse::make()->error('店铺的经营分类未包含当前所选的商品分类');
  739. }
  740. if($request['_method']){
  741. if($__MINI_GLOBAL_IS_ADMIN_SUPER__){
  742. $tag = $input['tag'];
  743. unset($tag[count($tag)-1]);
  744. }else{
  745. $tag = [];
  746. }
  747. $users_ledger_flag = false;
  748. if(!$__MINI_GLOBAL_IS_ADMIN_SUPER__){
  749. $users_ledger_flag = true;
  750. }else{
  751. $users_ledger_flag = true;
  752. }
  753. if($users_ledger_flag){
  754. $users_ledger = AdminUtils::_table_data(_array_key($input, 'users_ledger', []));
  755. }else{
  756. $users_ledger = '[]';
  757. }
  758. DB::beginTransaction();
  759. $WxShopGoods = WxShopGoods::find($goods_id);
  760. $credit_type = $WxShopGoods->credit_type;
  761. if(!$__MINI_GLOBAL_IS_ADMIN_SUPER__){
  762. if($__MINI_GLOBAL_CURRENT_USER_ID__ != $WxShopGoods->user_id){
  763. return JsonResponse::make()->error('你不是当前商品的发布者');
  764. }
  765. }
  766. try {
  767. // todo:
  768. // 删除原有产品
  769. $this->delte_goods_product($goods_id);
  770. $updates = [
  771. 'type' => $input['type'],
  772. 'name'=>$input['name'],
  773. 'pic'=>$input['pic'],
  774. 'vip_price'=>$input['vip_price'],
  775. 'price'=>$input['price'],
  776. 'intro'=>$input['intro'],
  777. 'content'=>$input['content'],
  778. 'paid_content'=>$input['paid_content'],
  779. 'state'=>$input['state'],
  780. 'sku'=>$input['sku'],
  781. 'contact_id' => $input['contact_id'],
  782. 'scanners' => $input['scanners'],
  783. 'url'=>$input['url'],
  784. 'download_version'=>$input['download_version'],
  785. 'download_url'=>$input['download_url'],
  786. 'question_id'=>$__MINI_GLOBAL_IS_ADMIN_SUPER__ ? $input['question_id'] : 0,
  787. 'can_purchase_times'=>$input['can_purchase_times'],
  788. 'tag'=> json_encode($tag),
  789. 'classify_id'=>$input['classify_id'],
  790. 'service_id'=>$input['service_id'],
  791. 'users_ledger' => $users_ledger,
  792. 'last_sales_at' => $input['last_sales_at'],
  793. ];
  794. if($__MINI_GLOBAL_IS_ADMIN_SUPER__){
  795. $updates['views'] = $input['views'];
  796. $updates['buys'] = $input['buys'];
  797. }
  798. if($guest_present){
  799. $updates['guest_present'] = implode(',', $guest_present);
  800. }
  801. if(!_empty_($input['service_date_start'])){
  802. $updates['service_date_start'] = $input['service_date_start'];
  803. }
  804. if(!_empty_($input['service_date_end'])){
  805. $updates['service_date_end'] = $input['service_date_end'];
  806. }
  807. if(!_empty_($input['service_time_start'])){
  808. $updates['service_time_start'] = $input['service_time_start'];
  809. }
  810. if(!_empty_($input['service_time_end'])){
  811. $updates['service_time_end'] = $input['service_time_end'];
  812. }
  813. // 更新商品
  814. (new WxShopGoods())->where('id',$goods_id)
  815. ->update($updates);
  816. $params = json_decode($input['sku'],true);
  817. $sku = $params['sku'];
  818. $attrs = $params['attrs'];
  819. $attrsArr = array_values($attrs);
  820. $attrsArr = $this->brush([],$attrsArr);
  821. $productData = [];
  822. foreach ($attrsArr as $k=>$v){
  823. if(_empty_($sku[$k]['vip_price']) || _empty_($sku[$k]['price'])){
  824. DB::rollBack();
  825. return JsonResponse::make()->error('SKU未设置价格!');
  826. }
  827. $productData[] = [
  828. 'goods_id' => $goods_id,
  829. 'vip_price'=>$sku[$k]['vip_price'],
  830. 'price'=>$sku[$k]['price'],
  831. 'stock'=>$sku[$k]['stock'],
  832. 'pic'=>$sku[$k]['pic'],
  833. 'param_value'=>$v,
  834. 'created_at'=>date('Y-m-d H:i:s'),
  835. 'credit_type' => $credit_type
  836. ];
  837. }
  838. (new WxShopGoodsProduct())->batchAdd($productData);
  839. DB::commit();
  840. return JsonResponse::make()->success('成功!')->redirect('shop/goods');
  841. } catch (\Exception $e) {
  842. DB::rollBack();
  843. _logger_(__file__, __line__, $e->getMessage());
  844. return JsonResponse::make()->error('保存失败!');
  845. }
  846. }
  847. }
  848. public function brush($res = [], $arr = [])
  849. {
  850. if (_empty_($res)) $res = (array)array_shift($arr);
  851. if (_empty_($arr)) return $res;
  852. $current = array_shift($arr); # 接下来要参与计算的一组属性
  853. $last = [];
  854. foreach ($res as $row => $row_val) { # 循环上一次已经算出的集合
  855. foreach ($current as $col => $col_val) {
  856. $last[] = $row_val . '_' . $col_val;
  857. }
  858. }
  859. return $this->brush($last,$arr); # 递归处理, 直到$arr滚到最后一组属性
  860. }
  861. /**
  862. * 上传商品规格图片
  863. *
  864. * @param Request $request
  865. *
  866. * @return string[]
  867. */
  868. public function skuImage(Request $request)
  869. {
  870. if ($request->hasFile('file')) {
  871. $file = $request->file('file');
  872. $path = UploadHandler::handle($file);
  873. return ['url' => $path['url']];
  874. // // 返回格式
  875. // $disk = Storage::disk('cosv5');
  876. // $url = 'sku';
  877. // $res = $disk->put($url, $file);
  878. // return ['url' => config('filesystems.disks.cosv5.cdn') .'/'. $res];
  879. }
  880. return [];
  881. }
  882. }