From df17196b3f13e6d031400823d5137ede76d79770 Mon Sep 17 00:00:00 2001 From: vine_liutk <961510893@qq.com> Date: Sat, 11 Dec 2021 18:52:28 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E5=86=B2=E7=AA=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Admin/Actions/Show/AfterSaleFinance.php | 82 +++++ app/Admin/Actions/Show/AfterSaleShipping.php | 82 +++++ app/Admin/Actions/Show/AfterSaleVerify.php | 32 ++ app/Admin/Controllers/AfterSaleController.php | 178 ++++++++++ app/Admin/Forms/AddSku.php | 12 + app/Admin/Forms/AfterSaleVerify.php | 92 ++++++ app/Admin/Forms/DisableUser.php | 13 +- app/Admin/Forms/SettingSpuSpecs.php | 5 + app/Admin/Forms/SkuGift.php | 10 + app/Admin/Forms/SkuVerify.php | 10 + app/Admin/Forms/SkuVerifyBatch.php | 11 + app/Admin/Repositories/AfterSale.php | 16 + app/Admin/routes.php | 3 + .../Http/Controllers/AfterSaleController.php | 164 ++++++++++ .../Http/Controllers/Auth/LoginController.php | 1 + .../Http/Resources/AfterSaleLogResource.php | 24 ++ .../Api/Http/Resources/AfterSaleResource.php | 30 ++ .../Resources/AfterSaleSimpleResource.php | 25 ++ app/Endpoint/Api/routes.php | 9 + app/Models/AfterSale.php | 139 ++++++++ app/Models/AfterSaleLog.php | 25 ++ app/Models/OrderProduct.php | 5 + app/Models/User.php | 8 + app/Services/AfterSaleService.php | 307 ++++++++++++++++++ ..._12_10_144920_create_after_sales_table.php | 43 +++ ...10_144939_create_after_sale_logs_table.php | 35 ++ database/seeders/AdminPermissionSeeder.php | 21 +- dcat_admin_ide_helper.php | 104 +++--- resources/lang/zh_CN/after-sale.php | 41 +++ resources/views/admin/show/timeline.blade.php | 47 +++ 30 files changed, 1527 insertions(+), 47 deletions(-) create mode 100644 app/Admin/Actions/Show/AfterSaleFinance.php create mode 100644 app/Admin/Actions/Show/AfterSaleShipping.php create mode 100644 app/Admin/Actions/Show/AfterSaleVerify.php create mode 100644 app/Admin/Controllers/AfterSaleController.php create mode 100644 app/Admin/Forms/AfterSaleVerify.php create mode 100644 app/Admin/Repositories/AfterSale.php create mode 100644 app/Endpoint/Api/Http/Controllers/AfterSaleController.php create mode 100644 app/Endpoint/Api/Http/Resources/AfterSaleLogResource.php create mode 100644 app/Endpoint/Api/Http/Resources/AfterSaleResource.php create mode 100644 app/Endpoint/Api/Http/Resources/AfterSaleSimpleResource.php create mode 100644 app/Models/AfterSale.php create mode 100644 app/Models/AfterSaleLog.php create mode 100644 app/Services/AfterSaleService.php create mode 100644 database/migrations/2021_12_10_144920_create_after_sales_table.php create mode 100644 database/migrations/2021_12_10_144939_create_after_sale_logs_table.php create mode 100644 resources/lang/zh_CN/after-sale.php create mode 100644 resources/views/admin/show/timeline.blade.php diff --git a/app/Admin/Actions/Show/AfterSaleFinance.php b/app/Admin/Actions/Show/AfterSaleFinance.php new file mode 100644 index 00000000..cc0048dd --- /dev/null +++ b/app/Admin/Actions/Show/AfterSaleFinance.php @@ -0,0 +1,82 @@ + 打款'; + + /** + * 按钮样式定义,默认 btn btn-white waves-effect + * + * @var string + */ + protected $style = 'btn btn-sm btn-danger'; + + /** + * 权限判断,如不需要可以删除此方法 + * + * @param Model|Authenticatable|HasPermissions|null $user + * + * @return bool + */ + protected function authorize($user): bool + { + return $user->can('dcat.admin.after_sales.finance'); + } + + /** + * 处理请求,如果不需要接口处理,请直接删除这个方法 + * + * @param Request $request + * + * @return Response + */ + public function handle(Request $request) + { + // 获取主键 + $key = $this->getKey(); + + $afterSaleService = new AfterSaleService(); + try { + DB::beginTransaction(); + $afterSale = AfterSale::where('state', AfterSale::STATE_FINANCE)->findOrFail($key); + $afterSaleService->finance($afterSale); + DB::commit(); + } catch (Throwable $th) { + DB::rollBack(); + report($th); + return $this->response()->error('操作失败:'.$th->getMessage()); + } + + return $this->response() + ->success(__('admin.update_succeeded')) + ->refresh(); + } + + public function html() + { + return parent::html().'  '; + } + + /** + * 确认弹窗信息,如不需要可以删除此方法 + * + * @return string|array|void + */ + public function confirm() + { + return ['是否确认打款?', '该操作不可逆,打款后退款金额将原路退还。']; + } +} diff --git a/app/Admin/Actions/Show/AfterSaleShipping.php b/app/Admin/Actions/Show/AfterSaleShipping.php new file mode 100644 index 00000000..fca46404 --- /dev/null +++ b/app/Admin/Actions/Show/AfterSaleShipping.php @@ -0,0 +1,82 @@ + 确认收货'; + + /** + * 按钮样式定义,默认 btn btn-white waves-effect + * + * @var string + */ + protected $style = 'btn btn-sm btn-success'; + + /** + * 权限判断,如不需要可以删除此方法 + * + * @param Model|Authenticatable|HasPermissions|null $user + * + * @return bool + */ + protected function authorize($user): bool + { + return $user->can('dcat.admin.after_sales.shipping'); + } + + /** + * 处理请求,如果不需要接口处理,请直接删除这个方法 + * + * @param Request $request + * + * @return Response + */ + public function handle(Request $request) + { + // 获取主键 + $key = $this->getKey(); + + $afterSaleService = new AfterSaleService(); + try { + DB::beginTransaction(); + $afterSale = AfterSale::where('state', AfterSale::STATE_SHIPPING)->findOrFail($key); + $afterSaleService->shipping($afterSale); + DB::commit(); + } catch (Throwable $th) { + DB::rollBack(); + report($th); + return $this->response()->error('操作失败:'.$th->getMessage()); + } + + return $this->response() + ->success(__('admin.update_succeeded')) + ->refresh(); + } + + public function html() + { + return parent::html().'  '; + } + + /** + * 确认弹窗信息,如不需要可以删除此方法 + * + * @return string|array|void + */ + public function confirm() + { + return ['是否确认收货?', '该操作不可逆,确认后将进入打款流程。']; + } +} diff --git a/app/Admin/Actions/Show/AfterSaleVerify.php b/app/Admin/Actions/Show/AfterSaleVerify.php new file mode 100644 index 00000000..0a572394 --- /dev/null +++ b/app/Admin/Actions/Show/AfterSaleVerify.php @@ -0,0 +1,32 @@ + 审核'; + + /** + * 按钮样式定义,默认 btn btn-white waves-effect + * + * @var string + */ + protected $style = 'btn-success'; + + public function render() + { + $form = AfterSaleVerifyForm::make()->payload(['id'=>$this->getKey()]); + return Modal::make() + ->lg() + ->title($this->title) + ->body($form) + ->button("style}\">{$this->title}  "); + } +} diff --git a/app/Admin/Controllers/AfterSaleController.php b/app/Admin/Controllers/AfterSaleController.php new file mode 100644 index 00000000..725016de --- /dev/null +++ b/app/Admin/Controllers/AfterSaleController.php @@ -0,0 +1,178 @@ +column('id')->sortable(); + $grid->column('user.phone'); + $grid->column('order.sn'); + $grid->column('sn'); + $grid->column('orderProduct.name'); + $grid->column('num'); + $grid->column('amount'); + $grid->column('type')->using([ + AfterSaleModel::TYPE_REFUND_AND_RETURN => '退款退货', + AfterSaleModel::TYPE_REFUND => '退款', + AfterSaleModel::TYPE_CHANGE => '换货', + AfterSaleModel::TYPE_FILL => '漏发', + ])->label(); + $grid->column('state')->using([ + AfterSaleModel::STATE_APPLY=>'待补充资料', + AfterSaleModel::STATE_VERIFY=>'待审核', + AfterSaleModel::STATE_AGREE=>'待确认', + AfterSaleModel::STATE_SHIPPING=>'待收货', + AfterSaleModel::STATE_FINANCE=>'待打款', + AfterSaleModel::STATE_FINISH=>'已完成', + AfterSaleModel::STATE_CANCEL=>'已取消', + ])->dot([ + AfterSaleModel::STATE_APPLY=>'warning', + AfterSaleModel::STATE_VERIFY=>'danger', + AfterSaleModel::STATE_AGREE=>'warning', + AfterSaleModel::STATE_SHIPPING=>'primary', + AfterSaleModel::STATE_FINANCE=>'primary', + AfterSaleModel::STATE_FINISH=>'success', + ]); + // $grid->column('remarks'); + // $grid->column('tracking_number'); + $grid->column('created_at'); + $grid->column('updated_at')->sortable(); + $grid->model()->orderBy('created_at', 'desc'); + + $grid->actions(function (Grid\Displayers\Actions $actions) { + $actions->disableView(false); + }); + + $grid->filter(function (Grid\Filter $filter) { + $filter->panel(); + $filter->equal('state')->select([ + AfterSaleModel::STATE_APPLY=>'待补充资料', + AfterSaleModel::STATE_VERIFY=>'待审核', + AfterSaleModel::STATE_AGREE=>'待确认', + AfterSaleModel::STATE_SHIPPING=>'待收货', + AfterSaleModel::STATE_FINANCE=>'待打款', + AfterSaleModel::STATE_FINISH=>'已完成', + AfterSaleModel::STATE_CANCEL=>'已取消', + ])->width(3); + $filter->equal('user.phone')->width(3); + $filter->equal('order.sn')->width(3); + $filter->equal('sn')->width(3); + }); + }); + } + + /** + * Make a show builder. + * + * @param mixed $id + * + * @return Show + */ + protected function detail($id) + { + return function (Row $row) use ($id) { + $row->column(4, function ($column) use ($id) { + $builder = AfterSale::with(['user', 'order', 'orderProduct']); + $column->row(Show::make($id, $builder, function (Show $show) { + $show->field('id'); + $show->field('sn'); + $show->field('order.sn'); + $show->field('order_product.name'); + $show->field('num'); + $show->field('type')->using([ + AfterSaleModel::TYPE_REFUND_AND_RETURN => '退款退货', + AfterSaleModel::TYPE_REFUND => '退款', + AfterSaleModel::TYPE_CHANGE => '换货', + AfterSaleModel::TYPE_FILL => '漏发', + ])->label(); + $show->field('state')->using([ + AfterSaleModel::STATE_APPLY=>'待补充资料', + AfterSaleModel::STATE_VERIFY=>'待审核', + AfterSaleModel::STATE_AGREE=>'待确认', + AfterSaleModel::STATE_SHIPPING=>'待收货', + AfterSaleModel::STATE_FINANCE=>'待打款', + AfterSaleModel::STATE_FINISH=>'已完成', + AfterSaleModel::STATE_CANCEL=>'已取消', + ])->dot([ + AfterSaleModel::STATE_APPLY=>'warning', + AfterSaleModel::STATE_VERIFY=>'danger', + AfterSaleModel::STATE_AGREE=>'warning', + AfterSaleModel::STATE_SHIPPING=>'primary', + AfterSaleModel::STATE_FINANCE=>'primary', + AfterSaleModel::STATE_FINISH=>'success', + ]); + // $show->field('order_product.cover')->image(); + $show->field('created_at'); + $show->field('updated_at'); + $show->panel() + ->tools(function (Show\Tools $tools) use ($show) { + $tools->disableEdit(); + $tools->disableDelete(); + if ($show->model()->state == AfterSaleModel::STATE_VERIFY) { + $tools->append(new AfterSaleVerify()); + } + if ($show->model()->state == AfterSaleModel::STATE_SHIPPING) { + $tools->append(new AfterSaleShipping()); + } + if ($show->model()->state == AfterSaleModel::STATE_FINANCE) { + $tools->append(new AfterSaleFinance()); + } + }); + })); + }); + $row->column(8, function ($column) use ($id) { + $logs = AfterSaleLog::where('after_sale_id', $id)->latest('id')->get(); + $title = '售后明细'; + $column->row(admin_view('admin.show.timeline', compact('title', 'logs'))); + }); + }; + } + + /** + * Make a form builder. + * + * @return Form + */ + protected function form() + { + return Form::make(new AfterSale(), function (Form $form) { + $form->display('id'); + $form->text('user_id'); + $form->text('order_id'); + $form->text('sn'); + $form->text('order_product_id'); + $form->text('num'); + $form->text('amount'); + $form->text('type'); + $form->text('state'); + $form->text('description'); + $form->text('images'); + $form->text('remarks'); + $form->text('tracking_number'); + + $form->display('created_at'); + $form->display('updated_at'); + }); + } +} diff --git a/app/Admin/Forms/AddSku.php b/app/Admin/Forms/AddSku.php index cfa6e09c..ba888fb4 100644 --- a/app/Admin/Forms/AddSku.php +++ b/app/Admin/Forms/AddSku.php @@ -15,6 +15,18 @@ class AddSku extends Form implements LazyRenderable { use LazyWidget; + /** + * 权限判断,如不需要可以删除此方法 + * + * @param Model|Authenticatable|HasPermissions|null $user + * + * @return bool + */ + protected function authorize($user): bool + { + return $user->can('dcat.admin.product_spus.add_sku'); + } + /** * Handle the form request. * diff --git a/app/Admin/Forms/AfterSaleVerify.php b/app/Admin/Forms/AfterSaleVerify.php new file mode 100644 index 00000000..4097fbd9 --- /dev/null +++ b/app/Admin/Forms/AfterSaleVerify.php @@ -0,0 +1,92 @@ +can('dcat.admin.after_sales.verify'); + } + + /** + * Handle the form request. + * + * @param array $input + * + * @return mixed + */ + public function handle(array $input) + { + $afterSaleService = new AfterSaleService(); + try { + DB::beginTransaction(); + $afterSale = AfterSale::where('state', AfterSale::STATE_VERIFY)->findOrFail($this->payload['id']); + if ($input['state'] == 3) {//审核通过 + $afterSaleService->verify($afterSale, $input['remarks3']); + } elseif ($input['state'] == 1) {//需要补充资料 + $afterSaleService->backApply($afterSale, $input['remarks1']); + } + DB::commit(); + } catch (Throwable $th) { + DB::rollBack(); + report($th); + return $this->response()->error('操作失败:'.$th->getMessage()); + } + + return $this->response() + ->success(__('admin.update_succeeded')) + ->refresh(); + } + + /** + * Build a form here. + */ + public function form() + { + $id = $this->payload['id'] ?? 0; + $afterSale = AfterSale::findOrFail($id); + $this->currency('amount')->symbol('¥')->value($afterSale->amount); + $this->radio('state') + ->when(3, function (Form $form) use ($afterSale) { + $defaultRemarks = ''; + switch ($afterSale->type) { + case 1: + $defaultRemarks = '同意退款退货';//需要用户确认并填入回寄单号 + break; + case 2: + $defaultRemarks = '同意退款,等待财务打款审核。'; + break; + case 3: + $defaultRemarks = '同意换货';//需要用户确认并填入回寄单号 + break; + case 4: + $defaultRemarks = '同意补货, 新的订单号:';//需要用户收到补货后确认,可后台关闭 + } + $this->text('remarks3')->value($defaultRemarks); + }) + ->when(1, function (Form $form) { + $this->text('remarks1')->value('需要补充资料'); + })->options([ + 3=>'审核通过', + 1=>'需要补充资料', + ])->default(3); + } +} diff --git a/app/Admin/Forms/DisableUser.php b/app/Admin/Forms/DisableUser.php index ccfb3caa..5905ade7 100644 --- a/app/Admin/Forms/DisableUser.php +++ b/app/Admin/Forms/DisableUser.php @@ -13,6 +13,16 @@ class DisableUser extends Form implements LazyRenderable { use LazyWidget; + /** + * @param Model|Authenticatable|HasPermissions|null $user + * + * @return bool + */ + protected function authorize($user): bool + { + return $user->can('dcat.admin.users.disable'); + } + /** * Handle the form request. * @@ -23,9 +33,10 @@ class DisableUser extends Form implements LazyRenderable public function handle(array $input) { $id = $this->payload['id'] ?? 0; - $user = User::findOrFail($id); + try { DB::beginTransaction(); + $user = User::findOrFail($id); $user->disable($input['status_remark']); DB::commit(); } catch (Throwable $th) { diff --git a/app/Admin/Forms/SettingSpuSpecs.php b/app/Admin/Forms/SettingSpuSpecs.php index 15eaaefd..6522787e 100644 --- a/app/Admin/Forms/SettingSpuSpecs.php +++ b/app/Admin/Forms/SettingSpuSpecs.php @@ -13,6 +13,11 @@ class SettingSpuSpecs extends Form implements LazyRenderable { use LazyWidget; + protected function authorize($user): bool + { + return $user->can('dcat.admin.product_spus.setting_specs'); + } + /** * Handle the form request. * diff --git a/app/Admin/Forms/SkuGift.php b/app/Admin/Forms/SkuGift.php index 4bdfece6..f2e634b9 100644 --- a/app/Admin/Forms/SkuGift.php +++ b/app/Admin/Forms/SkuGift.php @@ -15,6 +15,16 @@ class SkuGift extends Form implements LazyRenderable { use LazyWidget; + /** + * @param Model|Authenticatable|HasPermissions|null $user + * + * @return bool + */ + protected function authorize($user): bool + { + return $user->can('dcat.admin.product_skus.sku_gift'); + } + /** * Handle the form request. * diff --git a/app/Admin/Forms/SkuVerify.php b/app/Admin/Forms/SkuVerify.php index 9828d7f3..290d1f48 100644 --- a/app/Admin/Forms/SkuVerify.php +++ b/app/Admin/Forms/SkuVerify.php @@ -14,6 +14,16 @@ class SkuVerify extends Form implements LazyRenderable { use LazyWidget; + /** + * @param Model|Authenticatable|HasPermissions|null $user + * + * @return bool + */ + protected function authorize($user): bool + { + return $user->can('dcat.admin.product_sku_verifies.verify'); + } + /** * Handle the form request. * diff --git a/app/Admin/Forms/SkuVerifyBatch.php b/app/Admin/Forms/SkuVerifyBatch.php index 72de582a..c3b2aed6 100644 --- a/app/Admin/Forms/SkuVerifyBatch.php +++ b/app/Admin/Forms/SkuVerifyBatch.php @@ -14,6 +14,17 @@ class SkuVerifyBatch extends Form implements LazyRenderable { use LazyWidget; + /** + * 是否有权限判断. + * + * @param Model|Authenticatable|HasPermissions|null $user + * @return bool + */ + protected function authorize($user): bool + { + return $user->can('dcat.admin.product_sku_verifies.batch_verify'); + } + /** * Handle the form request. * diff --git a/app/Admin/Repositories/AfterSale.php b/app/Admin/Repositories/AfterSale.php new file mode 100644 index 00000000..4a775a1e --- /dev/null +++ b/app/Admin/Repositories/AfterSale.php @@ -0,0 +1,16 @@ +names('coupon_task_logs'); + $router->get('after-sales', 'AfterSaleController@index')->name('after_sales.index'); + $router->get('after-sales/{after_sale}', 'AfterSaleController@show')->name('after_sales.show'); + $router->resource('users', 'UserController'); $router->resource('vips', 'VipController'); diff --git a/app/Endpoint/Api/Http/Controllers/AfterSaleController.php b/app/Endpoint/Api/Http/Controllers/AfterSaleController.php new file mode 100644 index 00000000..53113db9 --- /dev/null +++ b/app/Endpoint/Api/Http/Controllers/AfterSaleController.php @@ -0,0 +1,164 @@ +with(['order', 'orderProduct']); + $query->where('user_id', $request->user()->id); + + if ($request->filled('doing')) { + $doing = (bool) $request->query('doing'); + if ($doing) {//获取正在处理中的订单 + $query->where('state', '<', AfterSale::STATE_FINISH)->latest('updated_at'); + } else {//获取已完成+已取消的售后订单 + $query->where('state', '>=', AfterSale::STATE_FINISH)->latest(); + } + } else {//获取全部申请记录 + $query->latest(); + } + + $afterSales = $query->simplePaginate(PaginatorHelper::resolvePerPage('per_page', 20, 50)); + + return AfterSaleSimpleResource::collection($afterSales); + } + + /** + * 提交审核 + * + * @param Request $request + * @return void + */ + public function store(Request $request, AfterSaleService $afterSaleService) + { + $input = $request->validate([ + 'order_product_id' => ['bail', 'required', 'integer'], + 'num' => ['bail', 'required', 'integer', 'min:1'], + 'type' => ['bail', 'required', 'integer', 'min:1', 'max:4'], + 'description' => ['bail', 'required', 'string', 'max:255'], + 'images' => ['bail', 'required', 'array', 'max:6'], + ]); + try { + DB::beginTransaction(); + + $orderProduct = OrderProduct::where('user_id', $request->user()->id)->findOrFail($input['order_product_id']); + $afterSale = $afterSaleService->create($request->user(), $orderProduct, $input['type'], $input['num'], $input); + + DB::commit(); + } catch (Throwable $th) { + DB::rollBack(); + report($th); + throw new BizException('申请失败,请稍后再试'); + } + + return AfterSaleResource::make($afterSale); + } + + /** + * 售后订单详情 + * + * @param [type] $id + * @param Request $request + * @return void + */ + public function show($id, Request $request) + { + $afterSale = $request->user()->afterSales()->find($id); + return AfterSaleResource::make($afterSale); + } + + /** + * 补充资料 + * + * @param Request $request + * @return void + */ + public function update($id, Request $request, AfterSaleService $afterSaleService) + { + $afterSale = $request->user()->afterSales()->where('state', '=', AfterSale::STATE_APPLY)->findOrFail($id); + $input = $request->validate([ + 'type' => ['bail', 'required', 'integer', 'min:1', 'max:4'], + 'description' => ['bail', 'required', 'string', 'max:255'], + 'images' => ['bail', 'required', 'array', 'max:6'], + ]); + + try { + DB::beginTransaction(); + + $afterSale = $afterSaleService->apply($afterSale, $input); + + DB::commit(); + } catch (Throwable $th) { + DB::rollBack(); + report($th); + throw new BizException('提交失败,请稍后再试'); + } + return AfterSaleResource::make($afterSale); + } + + /** + * 客户同意 + * + * @param Request $request + * @return void + */ + public function agree($id, Request $request) + { + $afterSale = $request->user()->afterSales()->where('state', '=', AfterSale::STATE_AGREE)->findOrFail($id); + $input = $request->validate([ + 'tracking_number' => ['bail', 'string', 'max:255'], + ]); + + //如果是 + if (in_array($afterSale->type, [AfterSale::TYPE_REFUND_AND_RETURN, AfterSale::TYPE_CHANGE]) && (!isset($input['tracking_number']) || empty($input['tracking_number']))) { + throw new BizException('请填写物流单号'); + } + try { + DB::beginTransaction(); + $afterSaleService = new AfterSaleService(); + $afterSale = $afterSaleService->agree($afterSale, $input); + DB::commit(); + } catch (Throwable $th) { + DB::rollBack(); + report($th); + throw new BizException('提交失败,请稍后再试'); + } + return AfterSaleResource::make($afterSale); + } + + /** + * 取消申请 + * + * @param Request $request + * @return void + */ + public function cancel($id, Request $request) + { + $afterSale = $request->user()->afterSales()->where('state', '<', 4)->findOrFail($id); + + $afterSale->update( + ['state'=> AfterSale::STATE_CANCEL, 'remarks'=>'用户取消售后申请'] + ); + + return AfterSaleResource::make($afterSale); + } +} diff --git a/app/Endpoint/Api/Http/Controllers/Auth/LoginController.php b/app/Endpoint/Api/Http/Controllers/Auth/LoginController.php index 6b1f1819..b702a154 100644 --- a/app/Endpoint/Api/Http/Controllers/Auth/LoginController.php +++ b/app/Endpoint/Api/Http/Controllers/Auth/LoginController.php @@ -18,6 +18,7 @@ class LoginController extends Controller */ public function __invoke(LoginRequest $request) { + throw new BizException(__('Incorrect account or password')); $user = User::where('phone', $request->input('phone'))->first(); if (! $user?->verifyPassword($request->input('password'))) { diff --git a/app/Endpoint/Api/Http/Resources/AfterSaleLogResource.php b/app/Endpoint/Api/Http/Resources/AfterSaleLogResource.php new file mode 100644 index 00000000..aba638d1 --- /dev/null +++ b/app/Endpoint/Api/Http/Resources/AfterSaleLogResource.php @@ -0,0 +1,24 @@ + $this->id, + 'name' =>$this->name, + 'desc' => $this->desc, + 'created_at' => $this->created_at->toDateTimeString(), + ]; + } +} diff --git a/app/Endpoint/Api/Http/Resources/AfterSaleResource.php b/app/Endpoint/Api/Http/Resources/AfterSaleResource.php new file mode 100644 index 00000000..38bee6a7 --- /dev/null +++ b/app/Endpoint/Api/Http/Resources/AfterSaleResource.php @@ -0,0 +1,30 @@ + $this->id, + 'order_sn' => $this->order->sn, + 'order_product'=>'', + 'state' => $this->state, + 'type' => $this->type, + 'images' => $this->images, + 'description' => $this->description, + 'remarks' => $this->remarks, + 'created_at' => $this->created_at->toDateTimeString(), + // 'logs' => AfterSaleLogResource::make($this->whenLoaded('logs')), + ]; + } +} diff --git a/app/Endpoint/Api/Http/Resources/AfterSaleSimpleResource.php b/app/Endpoint/Api/Http/Resources/AfterSaleSimpleResource.php new file mode 100644 index 00000000..8734444b --- /dev/null +++ b/app/Endpoint/Api/Http/Resources/AfterSaleSimpleResource.php @@ -0,0 +1,25 @@ + $this->id, + 'order_sn' => $this->whenLoaded('order')?->sn, + 'order_product'=>'', + 'state' => $this->state, + 'remarks' => $this->remarks, + ]; + } +} diff --git a/app/Endpoint/Api/routes.php b/app/Endpoint/Api/routes.php index 2c725ed1..492a8c78 100644 --- a/app/Endpoint/Api/routes.php +++ b/app/Endpoint/Api/routes.php @@ -3,6 +3,7 @@ use App\Endpoint\Api\Http\Controllers\Account\ChangePasswordController; use App\Endpoint\Api\Http\Controllers\Account\UserController; use App\Endpoint\Api\Http\Controllers\AdController; +use App\Endpoint\Api\Http\Controllers\AfterSaleController; use App\Endpoint\Api\Http\Controllers\Auth\LoginController; use App\Endpoint\Api\Http\Controllers\Auth\LogoutController; use App\Endpoint\Api\Http\Controllers\Auth\RegisterController; @@ -71,5 +72,13 @@ Route::group([ Route::put('shopping-cart-items/{shopping_cart_item}', [ShoppingCartItemController::class, 'update']); Route::apiResource('shipping-addresses', ShippingAddressController::class); + + //售后订单 + Route::get('after-sales', [AfterSaleController::class, 'index']); + Route::post('after-sales', [AfterSaleController::class, 'store']); + Route::get('after-sales/{after_sales}', [AfterSaleController::class, 'show']); + Route::put('after-sales/{after_sales}', [AfterSaleController::class, 'update']); + Route::put('after-sales/{after_sales}/agree', [AfterSaleController::class, 'agree']); + Route::delete('after-sales/{after_sales}', [AfterSaleController::class, 'cancel']); }); }); diff --git a/app/Models/AfterSale.php b/app/Models/AfterSale.php new file mode 100644 index 00000000..4f18eb2d --- /dev/null +++ b/app/Models/AfterSale.php @@ -0,0 +1,139 @@ + JsonArray::class, + 'amount' => Price::class, + ]; + + protected $fillable = [ + 'user_id', + 'order_id', + 'order_product_id', + 'num', + 'amount', + 'type', + 'state', + 'description', + 'images', + 'remarks', + ]; + + public function user() + { + return $this->belongsTo(User::class, 'user_id'); + } + + public function order() + { + return $this->belongsTo(Order::class, 'order_id'); + } + + public function orderProduct() + { + return $this->belongsTo(OrderProduct::class, 'order_product_id'); + } + + public function logs() + { + return $this->hasMany(AfterSaleLog::class, 'after_sale_id'); + } + + /** + * 设置申请售后时的录入操作日志 + * + * @param array $attributes + * @param self|null $inviter + * @return self + */ + public static function create(array $attributes = [], ?self $inviter = null): self + { + $afterSale = static::query()->create($attributes); + + $afterSale->createApplyLog(); + + return $afterSale; + } + + /** + * 申请日志 + * + * @return void + */ + protected function createApplyLog() + { + $this->logs()->create([ + 'after_sale_id' => $this->id, + 'name' => '售后申请', + 'desc' => '申请理由:'.$this->description, + 'images'=> $this->images, + ]); + } + + /** + * 取消日志 + * + * @return void + */ + protected function createCancelLog() + { + $this->logs()->create([ + 'after_sale_id' => $this->id, + 'name' => '取消申请', + 'desc' => '用户取消售后申请', + ]); + } + + /** + * {@inheritdoc} + */ + protected static function booted() + { + parent::saving(function ($afterSale) { + // 如果自动创建sn + if ($afterSale->sn === null) { + $afterSale->sn = self::createSn(); + } + //如果取消订单 + if ($afterSale->state == self::STATE_CANCEL) { + $afterSale->createCancelLog(); + } + }); + } + + /** + * 创建售后单号 + * + * @return void + */ + protected static function createSn() + { + return 'AS'.now()->format('YmdHisu').strtoupper(Str::random(2)); + } +} diff --git a/app/Models/AfterSaleLog.php b/app/Models/AfterSaleLog.php new file mode 100644 index 00000000..a90340e3 --- /dev/null +++ b/app/Models/AfterSaleLog.php @@ -0,0 +1,25 @@ + JsonArray::class, + ]; + + protected $fillable = [ + 'name', + 'desc', + 'after_sale_id', + 'images', + ]; +} diff --git a/app/Models/OrderProduct.php b/app/Models/OrderProduct.php index bd8848f3..58d55ebc 100644 --- a/app/Models/OrderProduct.php +++ b/app/Models/OrderProduct.php @@ -2,10 +2,15 @@ namespace App\Models; +use App\Casts\Price; use Illuminate\Database\Eloquent\Model; class OrderProduct extends Model { + protected $casts = [ + 'total_amount'=>Price::class, + ]; + /** * @var array */ diff --git a/app/Models/User.php b/app/Models/User.php index f7723485..4fdd6348 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -120,6 +120,14 @@ class User extends Model implements AuthorizableContract, AuthenticatableContrac return false; } + /** + * 属于此用户的售后订单 + */ + public function afterSales() + { + return $this->hasMany(AfterSale::class); + } + /** * 禁用用户 * diff --git a/app/Services/AfterSaleService.php b/app/Services/AfterSaleService.php new file mode 100644 index 00000000..e20aab24 --- /dev/null +++ b/app/Services/AfterSaleService.php @@ -0,0 +1,307 @@ +id)->where('state', '<', AfterSale::STATE_FINISH)->exists()) { + throw new BizException('该订单商品已申请售后'); + } + //校验申请数量不能超过订单商品数量 + if ($num > $orderProduct->quantity) { + throw new BizException('申请售后的数量不能大于订单商品数量'); + } + + switch ($type) { + case in_array($type, [3, 4])://换货,漏发退款金额为0 + $amount = 0; + break; + default: + // dd(bcmul(bcdiv(10, 3, 2), 3, 2));如果数量相等,则直接取总额 + $amount = ($num == $orderProduct->quantity) ? $orderProduct->total_amount : bcmul(bcdiv($orderProduct->total_amount, $orderProduct->quantity, 2), $num, 2); + break; + } + $afterSale = AfterSale::create(array_merge($params, [ + 'user_id' => $user->id, + 'order_id' => $orderProduct->order_id, + 'amount' => $amount, + 'state' => AfterSale::STATE_VERIFY, + ])); + return $afterSale; + } + + /** + * 是否待审核 + * + * @param AfterSale $afterSale + * @return boolean + */ + protected function isWaitVerify(AfterSale $afterSale) + { + return $afterSale->state == $afterSale::STATE_VERIFY; + } + + /** + * 是否待补充资料 + * + * @param AfterSale $afterSale + * @return boolean + */ + protected function isWaitApply(AfterSale $afterSale) + { + return $afterSale->state == $afterSale::STATE_APPLY; + } + + /** + * 是否待确认 + * + * @param AfterSale $afterSale + * @return boolean + */ + protected function isWaitAgree(AfterSale $afterSale) + { + return $afterSale->state == $afterSale::STATE_AGREE; + } + + /** + * 是否待确认收货 + * + * @param AfterSale $afterSale + * @return boolean + */ + protected function isWaitShipping(AfterSale $afterSale) + { + return $afterSale->state == $afterSale::STATE_SHIPPING; + } + + /** + * 是否待打款 + * + * @param AfterSale $afterSale + * @return boolean + */ + protected function isWaitFinance(AfterSale $afterSale) + { + return $afterSale->state == $afterSale::STATE_FINANCE; + } + + /** + * 补充资料申请 + * + * @param [AfterSale] $afterSale + * @param array $params + * @return AfterSale + */ + public function apply(AfterSale $afterSale, array $params): AfterSale + { + if ($this->isWaitApply($afterSale)) { + $afterSale->update(array_merge($params, [ + 'state' => AfterSale::STATE_VERIFY, + ])); + + AfterSaleLog::create([ + 'after_sale_id' => $afterSale->id, + 'name' => '补充资料', + 'desc' => $afterSale->description, + 'images' => $afterSale->images, + ]); + return $afterSale; + } else { + throw new BizException('售后订单状态异常,请稍后再试'); + } + } + + /** + * 审核通过 + * + * @param AfterSale $afterSale + * @param string $remarks + * @return void + */ + public function verify(AfterSale $afterSale, string $remarks) + { + if ($this->isWaitVerify($afterSale)) { + switch ($afterSale->type) { + case AfterSale::TYPE_REFUND_AND_RETURN: + $afterSale->update([ + 'state' => $afterSale::STATE_AGREE, + 'remarks' => $remarks, + ]); + AfterSaleLog::create([ + 'after_sale_id' => $afterSale->id, + 'name' => '客服审核', + 'desc' => $remarks, + ]); + break; + case AfterSale::TYPE_REFUND: + $afterSale->update([ + 'state' => $afterSale::STATE_AGREE, + 'remarks' => $remarks, + ]); + AfterSaleLog::create([ + 'after_sale_id' => $afterSale->id, + 'name' => '客服审核', + 'desc' => $remarks, + ]); + break; + case AfterSale::TYPE_CHANGE: + $afterSale->update([ + 'state' => $afterSale::STATE_AGREE, + 'remarks' => $remarks, + ]); + AfterSaleLog::create([ + 'after_sale_id' => $afterSale->id, + 'name' => '客服审核', + 'desc' => $remarks, + ]); + break; + case AfterSale::TYPE_FILL: + $afterSale->update([ + 'state' => $afterSale::STATE_AGREE, + 'remarks' => $remarks, + ]); + AfterSaleLog::create([ + 'after_sale_id' => $afterSale->id, + 'name' => '客服审核', + 'desc' => $remarks, + ]); + break; + } + } else { + throw new BizException('该售后订单状态异常'); + } + } + + /** + * 补充资料 + * + * @param AfterSale $afterSale + * @param string $remarks + * @return void + */ + public function backApply(AfterSale $afterSale, string $remarks) + { + if ($this->isWaitVerify($afterSale)) { + $afterSale->update([ + 'state' => $afterSale::STATE_APPLY, + 'remarks' => $remarks, + ]); + AfterSaleLog::create([ + 'after_sale_id' => $afterSale->id, + 'name' => '客服审核', + 'desc' => $remarks, + ]); + } else { + throw new BizException('该售后订单状态异常'); + } + } + + public function agree(AfterSale $afterSale, array $params, $remarks = '用户已同意客服审核结果') + { + if ($this->isWaitAgree($afterSale)) { + switch ($afterSale->type) { + case AfterSale::TYPE_REFUND: + if (isset($params['tracking_number'])) { + unset($params['tracking_number']); + } + break; + case AfterSale::TYPE_FILL: + if (isset($params['tracking_number'])) { + unset($params['tracking_number']); + } + break; + default: + break; + } + + $afterSale->update(array_merge($params, [ + 'remarks' => $remarks, + ])); + AfterSaleLog::create([ + 'after_sale_id' => $afterSale->id, + 'name' => '客户确认', + 'desc' => $remarks, + ]); + } else { + throw new BizException('售后订单状态异常,请稍后再试'); + } + } + + /** + * 物流确认收货 + * + * @param AfterSale $afterSale + * @param string $remarks + * @return void + */ + public function shipping(AfterSale $afterSale, $remarks ='物流确认收货') + { + if ($this->isWaitShipping($afterSale)) { + $afterSale->update([ + 'state' => $afterSale::STATE_FINANCE, + 'remarks' => $remarks, + ]); + AfterSaleLog::create([ + 'after_sale_id' => $afterSale->id, + 'name' => '仓库审核', + 'desc' => $remarks, + ]); + } else { + throw new BizException('该售后订单状态异常'); + } + } + + /** + * 财务确认退款 + * + * @return void + */ + public function finance(AfterSale $afterSale, $remarks ='退款成功') + { + if ($this->isWaitFinance($afterSale)) { + + //todo-执行实际退款操作; + + $afterSale->update([ + 'state' => $afterSale::STATE_FINISH, + 'remarks' => $remarks, + ]); + AfterSaleLog::create([ + 'after_sale_id' => $afterSale->id, + 'name' => '财务审核', + 'desc' => $remarks, + ]); + AfterSaleLog::create([ + 'after_sale_id' => $afterSale->id, + 'name' => '售后完成', + 'desc' => '售后已结束', + ]); + } else { + throw new BizException('该售后订单状态异常'); + } + } +} diff --git a/database/migrations/2021_12_10_144920_create_after_sales_table.php b/database/migrations/2021_12_10_144920_create_after_sales_table.php new file mode 100644 index 00000000..7f379785 --- /dev/null +++ b/database/migrations/2021_12_10_144920_create_after_sales_table.php @@ -0,0 +1,43 @@ +id(); + $table->unsignedBigInteger('user_id')->comment('用户ID'); + $table->unsignedBigInteger('order_id')->comment('原订单ID'); + $table->string('sn')->comment('售后订单编号'); + $table->unsignedBigInteger('order_product_id')->comment('订单商品ID'); + $table->unsignedBigInteger('num')->comment('数量'); + $table->unsignedBigInteger('amount')->default(0)->comment('退款金额:分'); + $table->unsignedTinyInteger('type')->default(0)->comment('1.退款退货;2.退款不退货;3.换货'); + $table->unsignedTinyInteger('state')->default(0)->comment('1待补充资料,2待审核,3待客户确认,4待收货,5待打款,6完成,7已取消'); + $table->string('description')->comment('申请描述'); + $table->json('images')->comment('照片地址'); + $table->string('remarks')->nullable()->comment('备注'); + $table->string('tracking_number')->nullable()->comment('运单号'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('after_sales'); + } +} diff --git a/database/migrations/2021_12_10_144939_create_after_sale_logs_table.php b/database/migrations/2021_12_10_144939_create_after_sale_logs_table.php new file mode 100644 index 00000000..e9add273 --- /dev/null +++ b/database/migrations/2021_12_10_144939_create_after_sale_logs_table.php @@ -0,0 +1,35 @@ +id(); + $table->unsignedBigInteger('after_sale_id')->comment('售后ID'); + $table->string('name')->comment('进度名称'); + $table->string('desc')->nullable()->comment('描述'); + $table->json('images')->nullable()->comment('图片内容'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('after_sale_logs'); + } +} diff --git a/database/seeders/AdminPermissionSeeder.php b/database/seeders/AdminPermissionSeeder.php index be203869..66f49db3 100644 --- a/database/seeders/AdminPermissionSeeder.php +++ b/database/seeders/AdminPermissionSeeder.php @@ -111,6 +111,10 @@ class AdminPermissionSeeder extends Seeder 'batch_release_down'=>['name' =>'批量下架'], 'batch_release_cacel'=>['name' =>'批量取消申请'], 'batch_sku_sync_spu'=>['name' =>'批量同步主商品'], + 'release_up'=> ['name'=>'上架申请'], + 'release_down'=> ['name'=>'商品下架'], + 'release_cacel'=> ['name'=>'取消申请'], + 'sku_sync_spu'=>['name' =>'同步主商品'], 'sku_gift' =>['name' =>'赠品管理'], ], ], @@ -138,9 +142,7 @@ class AdminPermissionSeeder extends Seeder 'name' =>'优惠券管理', 'curd' => true, 'children'=>[ - 'range_list' =>[ - 'name' =>'使用范围', - ], + 'range_list' =>['name' =>'使用范围'], ], ], 'coupon_ranges'=>[ @@ -151,9 +153,7 @@ class AdminPermissionSeeder extends Seeder 'name' =>'运费模板管理', 'curd' => true, 'children'=>[ - 'rule_list' =>[ - 'name' =>'运费规则', - ], + 'rule_list' =>['name' =>'运费规则'], ], ], 'shipping_rules'=>[ @@ -171,6 +171,15 @@ class AdminPermissionSeeder extends Seeder 'name' =>'优惠券发放日志', 'curd' => ['index'], ], + 'after_sales'=>[ + 'name' =>'售后管理', + 'curd' => ['index', 'show'], + 'children' => [ + 'verify'=>['name' =>'审核'], + 'shipping'=>['name' =>'确认收货'], + 'finance'=>['name' =>'确认打款'], + ], + ], ]; try { DB::begintransaction(); diff --git a/dcat_admin_ide_helper.php b/dcat_admin_ide_helper.php index 46c8b1ca..b9614b22 100644 --- a/dcat_admin_ide_helper.php +++ b/dcat_admin_ide_helper.php @@ -50,6 +50,17 @@ namespace Dcat\Admin { * @property Grid\Column|Collection jump_link * @property Grid\Column|Collection jump_type * @property Grid\Column|Collection sort + * @property Grid\Column|Collection after_sale_id + * @property Grid\Column|Collection desc + * @property Grid\Column|Collection images + * @property Grid\Column|Collection amount + * @property Grid\Column|Collection num + * @property Grid\Column|Collection order_id + * @property Grid\Column|Collection order_product_id + * @property Grid\Column|Collection remarks + * @property Grid\Column|Collection sn + * @property Grid\Column|Collection state + * @property Grid\Column|Collection tracking_number * @property Grid\Column|Collection _lft * @property Grid\Column|Collection _rgt * @property Grid\Column|Collection is_recommend @@ -61,12 +72,11 @@ namespace Dcat\Admin { * @property Grid\Column|Collection coupon_id * @property Grid\Column|Collection ranges * @property Grid\Column|Collection status - * @property Grid\Column|Collection num - * @property Grid\Column|Collection task_id * @property Grid\Column|Collection administrator_id - * @property Grid\Column|Collection amount + * @property Grid\Column|Collection task_id * @property Grid\Column|Collection limit * @property Grid\Column|Collection sent + * @property Grid\Column|Collection stock * @property Grid\Column|Collection threshold * @property Grid\Column|Collection use_day * @property Grid\Column|Collection use_end_at @@ -80,7 +90,6 @@ namespace Dcat\Admin { * @property Grid\Column|Collection after_sale_deadline * @property Grid\Column|Collection discount_amount * @property Grid\Column|Collection is_comment - * @property Grid\Column|Collection order_id * @property Grid\Column|Collection quantity * @property Grid\Column|Collection reduced_amount * @property Grid\Column|Collection sell_price @@ -103,30 +112,27 @@ namespace Dcat\Admin { * @property Grid\Column|Collection products_total_amount * @property Grid\Column|Collection remark * @property Grid\Column|Collection shipping_fee - * @property Grid\Column|Collection sn * @property Grid\Column|Collection user_coupon_id * @property Grid\Column|Collection abilities * @property Grid\Column|Collection last_used_at * @property Grid\Column|Collection token * @property Grid\Column|Collection tokenable_id * @property Grid\Column|Collection tokenable_type - * @property Grid\Column|Collection remarks * @property Grid\Column|Collection gift_sku_id * @property Grid\Column|Collection attrs * @property Grid\Column|Collection part_id + * @property Grid\Column|Collection applicant_id + * @property Grid\Column|Collection reviewer_id * @property Grid\Column|Collection buynote_id * @property Grid\Column|Collection cost_price - * @property Grid\Column|Collection images * @property Grid\Column|Collection market_price * @property Grid\Column|Collection media * @property Grid\Column|Collection release_at * @property Grid\Column|Collection sales * @property Grid\Column|Collection shipping_template_id - * @property Grid\Column|Collection stock * @property Grid\Column|Collection verify_state * @property Grid\Column|Collection feature_id * @property Grid\Column|Collection items - * @property Grid\Column|Collection product_spu_id * @property Grid\Column|Collection view_date * @property Grid\Column|Collection rule_id * @property Grid\Column|Collection info @@ -135,10 +141,10 @@ namespace Dcat\Admin { * @property Grid\Column|Collection expires_at * @property Grid\Column|Collection is_use * @property Grid\Column|Collection phone + * @property Grid\Column|Collection coupon_amount * @property Grid\Column|Collection coupon_name * @property Grid\Column|Collection coupon_threshold * @property Grid\Column|Collection coupon_type - * @property Grid\Column|Collection coupon_value * @property Grid\Column|Collection birthday * @property Grid\Column|Collection gender * @property Grid\Column|Collection inviter_id @@ -192,6 +198,17 @@ namespace Dcat\Admin { * @method Grid\Column|Collection jump_link(string $label = null) * @method Grid\Column|Collection jump_type(string $label = null) * @method Grid\Column|Collection sort(string $label = null) + * @method Grid\Column|Collection after_sale_id(string $label = null) + * @method Grid\Column|Collection desc(string $label = null) + * @method Grid\Column|Collection images(string $label = null) + * @method Grid\Column|Collection amount(string $label = null) + * @method Grid\Column|Collection num(string $label = null) + * @method Grid\Column|Collection order_id(string $label = null) + * @method Grid\Column|Collection order_product_id(string $label = null) + * @method Grid\Column|Collection remarks(string $label = null) + * @method Grid\Column|Collection sn(string $label = null) + * @method Grid\Column|Collection state(string $label = null) + * @method Grid\Column|Collection tracking_number(string $label = null) * @method Grid\Column|Collection _lft(string $label = null) * @method Grid\Column|Collection _rgt(string $label = null) * @method Grid\Column|Collection is_recommend(string $label = null) @@ -203,12 +220,11 @@ namespace Dcat\Admin { * @method Grid\Column|Collection coupon_id(string $label = null) * @method Grid\Column|Collection ranges(string $label = null) * @method Grid\Column|Collection status(string $label = null) - * @method Grid\Column|Collection num(string $label = null) - * @method Grid\Column|Collection task_id(string $label = null) * @method Grid\Column|Collection administrator_id(string $label = null) - * @method Grid\Column|Collection amount(string $label = null) + * @method Grid\Column|Collection task_id(string $label = null) * @method Grid\Column|Collection limit(string $label = null) * @method Grid\Column|Collection sent(string $label = null) + * @method Grid\Column|Collection stock(string $label = null) * @method Grid\Column|Collection threshold(string $label = null) * @method Grid\Column|Collection use_day(string $label = null) * @method Grid\Column|Collection use_end_at(string $label = null) @@ -222,7 +238,6 @@ namespace Dcat\Admin { * @method Grid\Column|Collection after_sale_deadline(string $label = null) * @method Grid\Column|Collection discount_amount(string $label = null) * @method Grid\Column|Collection is_comment(string $label = null) - * @method Grid\Column|Collection order_id(string $label = null) * @method Grid\Column|Collection quantity(string $label = null) * @method Grid\Column|Collection reduced_amount(string $label = null) * @method Grid\Column|Collection sell_price(string $label = null) @@ -245,30 +260,27 @@ namespace Dcat\Admin { * @method Grid\Column|Collection products_total_amount(string $label = null) * @method Grid\Column|Collection remark(string $label = null) * @method Grid\Column|Collection shipping_fee(string $label = null) - * @method Grid\Column|Collection sn(string $label = null) * @method Grid\Column|Collection user_coupon_id(string $label = null) * @method Grid\Column|Collection abilities(string $label = null) * @method Grid\Column|Collection last_used_at(string $label = null) * @method Grid\Column|Collection token(string $label = null) * @method Grid\Column|Collection tokenable_id(string $label = null) * @method Grid\Column|Collection tokenable_type(string $label = null) - * @method Grid\Column|Collection remarks(string $label = null) * @method Grid\Column|Collection gift_sku_id(string $label = null) * @method Grid\Column|Collection attrs(string $label = null) * @method Grid\Column|Collection part_id(string $label = null) + * @method Grid\Column|Collection applicant_id(string $label = null) + * @method Grid\Column|Collection reviewer_id(string $label = null) * @method Grid\Column|Collection buynote_id(string $label = null) * @method Grid\Column|Collection cost_price(string $label = null) - * @method Grid\Column|Collection images(string $label = null) * @method Grid\Column|Collection market_price(string $label = null) * @method Grid\Column|Collection media(string $label = null) * @method Grid\Column|Collection release_at(string $label = null) * @method Grid\Column|Collection sales(string $label = null) * @method Grid\Column|Collection shipping_template_id(string $label = null) - * @method Grid\Column|Collection stock(string $label = null) * @method Grid\Column|Collection verify_state(string $label = null) * @method Grid\Column|Collection feature_id(string $label = null) * @method Grid\Column|Collection items(string $label = null) - * @method Grid\Column|Collection product_spu_id(string $label = null) * @method Grid\Column|Collection view_date(string $label = null) * @method Grid\Column|Collection rule_id(string $label = null) * @method Grid\Column|Collection info(string $label = null) @@ -277,10 +289,10 @@ namespace Dcat\Admin { * @method Grid\Column|Collection expires_at(string $label = null) * @method Grid\Column|Collection is_use(string $label = null) * @method Grid\Column|Collection phone(string $label = null) + * @method Grid\Column|Collection coupon_amount(string $label = null) * @method Grid\Column|Collection coupon_name(string $label = null) * @method Grid\Column|Collection coupon_threshold(string $label = null) * @method Grid\Column|Collection coupon_type(string $label = null) - * @method Grid\Column|Collection coupon_value(string $label = null) * @method Grid\Column|Collection birthday(string $label = null) * @method Grid\Column|Collection gender(string $label = null) * @method Grid\Column|Collection inviter_id(string $label = null) @@ -339,6 +351,17 @@ namespace Dcat\Admin { * @property Show\Field|Collection jump_link * @property Show\Field|Collection jump_type * @property Show\Field|Collection sort + * @property Show\Field|Collection after_sale_id + * @property Show\Field|Collection desc + * @property Show\Field|Collection images + * @property Show\Field|Collection amount + * @property Show\Field|Collection num + * @property Show\Field|Collection order_id + * @property Show\Field|Collection order_product_id + * @property Show\Field|Collection remarks + * @property Show\Field|Collection sn + * @property Show\Field|Collection state + * @property Show\Field|Collection tracking_number * @property Show\Field|Collection _lft * @property Show\Field|Collection _rgt * @property Show\Field|Collection is_recommend @@ -350,12 +373,11 @@ namespace Dcat\Admin { * @property Show\Field|Collection coupon_id * @property Show\Field|Collection ranges * @property Show\Field|Collection status - * @property Show\Field|Collection num - * @property Show\Field|Collection task_id * @property Show\Field|Collection administrator_id - * @property Show\Field|Collection amount + * @property Show\Field|Collection task_id * @property Show\Field|Collection limit * @property Show\Field|Collection sent + * @property Show\Field|Collection stock * @property Show\Field|Collection threshold * @property Show\Field|Collection use_day * @property Show\Field|Collection use_end_at @@ -369,7 +391,6 @@ namespace Dcat\Admin { * @property Show\Field|Collection after_sale_deadline * @property Show\Field|Collection discount_amount * @property Show\Field|Collection is_comment - * @property Show\Field|Collection order_id * @property Show\Field|Collection quantity * @property Show\Field|Collection reduced_amount * @property Show\Field|Collection sell_price @@ -392,30 +413,27 @@ namespace Dcat\Admin { * @property Show\Field|Collection products_total_amount * @property Show\Field|Collection remark * @property Show\Field|Collection shipping_fee - * @property Show\Field|Collection sn * @property Show\Field|Collection user_coupon_id * @property Show\Field|Collection abilities * @property Show\Field|Collection last_used_at * @property Show\Field|Collection token * @property Show\Field|Collection tokenable_id * @property Show\Field|Collection tokenable_type - * @property Show\Field|Collection remarks * @property Show\Field|Collection gift_sku_id * @property Show\Field|Collection attrs * @property Show\Field|Collection part_id + * @property Show\Field|Collection applicant_id + * @property Show\Field|Collection reviewer_id * @property Show\Field|Collection buynote_id * @property Show\Field|Collection cost_price - * @property Show\Field|Collection images * @property Show\Field|Collection market_price * @property Show\Field|Collection media * @property Show\Field|Collection release_at * @property Show\Field|Collection sales * @property Show\Field|Collection shipping_template_id - * @property Show\Field|Collection stock * @property Show\Field|Collection verify_state * @property Show\Field|Collection feature_id * @property Show\Field|Collection items - * @property Show\Field|Collection product_spu_id * @property Show\Field|Collection view_date * @property Show\Field|Collection rule_id * @property Show\Field|Collection info @@ -424,10 +442,10 @@ namespace Dcat\Admin { * @property Show\Field|Collection expires_at * @property Show\Field|Collection is_use * @property Show\Field|Collection phone + * @property Show\Field|Collection coupon_amount * @property Show\Field|Collection coupon_name * @property Show\Field|Collection coupon_threshold * @property Show\Field|Collection coupon_type - * @property Show\Field|Collection coupon_value * @property Show\Field|Collection birthday * @property Show\Field|Collection gender * @property Show\Field|Collection inviter_id @@ -481,6 +499,17 @@ namespace Dcat\Admin { * @method Show\Field|Collection jump_link(string $label = null) * @method Show\Field|Collection jump_type(string $label = null) * @method Show\Field|Collection sort(string $label = null) + * @method Show\Field|Collection after_sale_id(string $label = null) + * @method Show\Field|Collection desc(string $label = null) + * @method Show\Field|Collection images(string $label = null) + * @method Show\Field|Collection amount(string $label = null) + * @method Show\Field|Collection num(string $label = null) + * @method Show\Field|Collection order_id(string $label = null) + * @method Show\Field|Collection order_product_id(string $label = null) + * @method Show\Field|Collection remarks(string $label = null) + * @method Show\Field|Collection sn(string $label = null) + * @method Show\Field|Collection state(string $label = null) + * @method Show\Field|Collection tracking_number(string $label = null) * @method Show\Field|Collection _lft(string $label = null) * @method Show\Field|Collection _rgt(string $label = null) * @method Show\Field|Collection is_recommend(string $label = null) @@ -492,12 +521,11 @@ namespace Dcat\Admin { * @method Show\Field|Collection coupon_id(string $label = null) * @method Show\Field|Collection ranges(string $label = null) * @method Show\Field|Collection status(string $label = null) - * @method Show\Field|Collection num(string $label = null) - * @method Show\Field|Collection task_id(string $label = null) * @method Show\Field|Collection administrator_id(string $label = null) - * @method Show\Field|Collection amount(string $label = null) + * @method Show\Field|Collection task_id(string $label = null) * @method Show\Field|Collection limit(string $label = null) * @method Show\Field|Collection sent(string $label = null) + * @method Show\Field|Collection stock(string $label = null) * @method Show\Field|Collection threshold(string $label = null) * @method Show\Field|Collection use_day(string $label = null) * @method Show\Field|Collection use_end_at(string $label = null) @@ -511,7 +539,6 @@ namespace Dcat\Admin { * @method Show\Field|Collection after_sale_deadline(string $label = null) * @method Show\Field|Collection discount_amount(string $label = null) * @method Show\Field|Collection is_comment(string $label = null) - * @method Show\Field|Collection order_id(string $label = null) * @method Show\Field|Collection quantity(string $label = null) * @method Show\Field|Collection reduced_amount(string $label = null) * @method Show\Field|Collection sell_price(string $label = null) @@ -534,30 +561,27 @@ namespace Dcat\Admin { * @method Show\Field|Collection products_total_amount(string $label = null) * @method Show\Field|Collection remark(string $label = null) * @method Show\Field|Collection shipping_fee(string $label = null) - * @method Show\Field|Collection sn(string $label = null) * @method Show\Field|Collection user_coupon_id(string $label = null) * @method Show\Field|Collection abilities(string $label = null) * @method Show\Field|Collection last_used_at(string $label = null) * @method Show\Field|Collection token(string $label = null) * @method Show\Field|Collection tokenable_id(string $label = null) * @method Show\Field|Collection tokenable_type(string $label = null) - * @method Show\Field|Collection remarks(string $label = null) * @method Show\Field|Collection gift_sku_id(string $label = null) * @method Show\Field|Collection attrs(string $label = null) * @method Show\Field|Collection part_id(string $label = null) + * @method Show\Field|Collection applicant_id(string $label = null) + * @method Show\Field|Collection reviewer_id(string $label = null) * @method Show\Field|Collection buynote_id(string $label = null) * @method Show\Field|Collection cost_price(string $label = null) - * @method Show\Field|Collection images(string $label = null) * @method Show\Field|Collection market_price(string $label = null) * @method Show\Field|Collection media(string $label = null) * @method Show\Field|Collection release_at(string $label = null) * @method Show\Field|Collection sales(string $label = null) * @method Show\Field|Collection shipping_template_id(string $label = null) - * @method Show\Field|Collection stock(string $label = null) * @method Show\Field|Collection verify_state(string $label = null) * @method Show\Field|Collection feature_id(string $label = null) * @method Show\Field|Collection items(string $label = null) - * @method Show\Field|Collection product_spu_id(string $label = null) * @method Show\Field|Collection view_date(string $label = null) * @method Show\Field|Collection rule_id(string $label = null) * @method Show\Field|Collection info(string $label = null) @@ -566,10 +590,10 @@ namespace Dcat\Admin { * @method Show\Field|Collection expires_at(string $label = null) * @method Show\Field|Collection is_use(string $label = null) * @method Show\Field|Collection phone(string $label = null) + * @method Show\Field|Collection coupon_amount(string $label = null) * @method Show\Field|Collection coupon_name(string $label = null) * @method Show\Field|Collection coupon_threshold(string $label = null) * @method Show\Field|Collection coupon_type(string $label = null) - * @method Show\Field|Collection coupon_value(string $label = null) * @method Show\Field|Collection birthday(string $label = null) * @method Show\Field|Collection gender(string $label = null) * @method Show\Field|Collection inviter_id(string $label = null) diff --git a/resources/lang/zh_CN/after-sale.php b/resources/lang/zh_CN/after-sale.php new file mode 100644 index 00000000..def4104d --- /dev/null +++ b/resources/lang/zh_CN/after-sale.php @@ -0,0 +1,41 @@ + [ + 'AfterSale' => '售后申请', + 'after-sales' => '售后申请', + ], + 'fields' => [ + 'user_id' => '用户ID', + 'user'=>[ + 'phone' => '手机号', + ], + 'order_id' => '原订单ID', + 'order'=>[ + 'sn' => '订单编号', + ], + 'sn' => '售后编号', + 'order_product_id' => '订单商品', + 'orderProduct'=>[ + 'name' => '商品名称', + 'cover' => '商品图片', + ], + 'order_product'=>[ + 'name' => '商品名称', + 'cover' => '商品图片', + ], + 'num' => '数量', + 'amount' => '退款金额', + 'type' => '类别', + 'state' => '状态', + 'description' => '申请描述', + 'images' => '图片', + 'remarks' => '回复', + 'remarks1' => '备注', + 'remarks3' => '备注', + 'tracking_number' => '运单号', + 'created_at'=>'申请时间', + ], + 'options' => [ + ], +]; diff --git a/resources/views/admin/show/timeline.blade.php b/resources/views/admin/show/timeline.blade.php new file mode 100644 index 00000000..1e0a9dc3 --- /dev/null +++ b/resources/views/admin/show/timeline.blade.php @@ -0,0 +1,47 @@ +
+
+

{{$title}}

+
+
+
+
+ + @if($logs->count() > 0) +
+ @foreach($logs as $log) + +
+ {{$log->created_at}} +
+ + +
+ +
+ {{$log->created_at->diffForHumans()}} +

{{$log->name}}

+
{{$log->desc}}
+ @if(count($log->images) > 0) +
+ @foreach ($log->images as $image) + + + + @endforeach +
+ @endif +
+
+ + @endforeach +
+ +
+
+ @endif +
+ +
+
+
+