6
0
Fork 0

解决冲突

release
vine_liutk 2021-12-11 18:52:28 +08:00
parent 03d0c1d0d3
commit df17196b3f
30 changed files with 1527 additions and 47 deletions

View File

@ -0,0 +1,82 @@
<?php
namespace App\Admin\Actions\Show;
use App\Models\AfterSale;
use App\Services\AfterSaleService;
use Dcat\Admin\Show\AbstractTool;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Throwable;
class AfterSaleFinance extends AbstractTool
{
/**
* @return string
*/
protected $title = '<i class="fa fa-exclamation-triangle icon-shuffle"></i>&nbsp;打款';
/**
* 按钮样式定义,默认 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().'&nbsp;&nbsp;';
}
/**
* 确认弹窗信息,如不需要可以删除此方法
*
* @return string|array|void
*/
public function confirm()
{
return ['是否确认打款?', '该操作不可逆,打款后退款金额将原路退还。'];
}
}

View File

@ -0,0 +1,82 @@
<?php
namespace App\Admin\Actions\Show;
use App\Models\AfterSale;
use App\Services\AfterSaleService;
use Dcat\Admin\Show\AbstractTool;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Throwable;
class AfterSaleShipping extends AbstractTool
{
/**
* @return string
*/
protected $title = '<i class="fa fa-exclamation-triangle icon-shuffle"></i>&nbsp;确认收货';
/**
* 按钮样式定义,默认 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().'&nbsp;&nbsp;';
}
/**
* 确认弹窗信息,如不需要可以删除此方法
*
* @return string|array|void
*/
public function confirm()
{
return ['是否确认收货?', '该操作不可逆,确认后将进入打款流程。'];
}
}

View File

@ -0,0 +1,32 @@
<?php
namespace App\Admin\Actions\Show;
use App\Admin\Forms\AfterSaleVerify as AfterSaleVerifyForm;
use Dcat\Admin\Show\AbstractTool;
use Dcat\Admin\Widgets\Modal;
class AfterSaleVerify extends AbstractTool
{
/**
* @return string
*/
protected $title = '<i class="feather icon-shuffle"></i>&nbsp;审核';
/**
* 按钮样式定义,默认 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("<a href=\"javascript:void(0)\" class=\"btn btn-sm {$this->style}\">{$this->title}</a>&nbsp;&nbsp;");
}
}

View File

@ -0,0 +1,178 @@
<?php
namespace App\Admin\Controllers;
use App\Admin\Actions\Show\AfterSaleFinance;
use App\Admin\Actions\Show\AfterSaleShipping;
use App\Admin\Actions\Show\AfterSaleVerify;
use App\Admin\Repositories\AfterSale;
use App\Models\AfterSale as AfterSaleModel;
use App\Models\AfterSaleLog;
use Dcat\Admin\Form;
use Dcat\Admin\Grid;
use Dcat\Admin\Http\Controllers\AdminController;
use Dcat\Admin\Layout\Row;
use Dcat\Admin\Show;
class AfterSaleController extends AdminController
{
/**
* Make a grid builder.
*
* @return Grid
*/
protected function grid()
{
$builder = AfterSale::with(['user', 'order', 'orderProduct']);
return Grid::make($builder, function (Grid $grid) {
$grid->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');
});
}
}

View File

@ -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.
*

View File

@ -0,0 +1,92 @@
<?php
namespace App\Admin\Forms;
use App\Models\AfterSale;
use App\Services\AfterSaleService;
use Dcat\Admin\Contracts\LazyRenderable;
use Dcat\Admin\Traits\LazyWidget;
use Dcat\Admin\Widgets\Form;
use Illuminate\Support\Facades\DB;
use Throwable;
class AfterSaleVerify extends Form implements LazyRenderable
{
use LazyWidget;
/**
* 权限判断,如不需要可以删除此方法
*
* @param Model|Authenticatable|HasPermissions|null $user
*
* @return bool
*/
protected function authorize($user): bool
{
return $user->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);
}
}

View File

@ -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) {

View File

@ -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.
*

View File

@ -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.
*

View File

@ -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.
*

View File

@ -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.
*

View File

@ -0,0 +1,16 @@
<?php
namespace App\Admin\Repositories;
use App\Models\AfterSale as Model;
use Dcat\Admin\Repositories\EloquentRepository;
class AfterSale extends EloquentRepository
{
/**
* Model.
*
* @var string
*/
protected $eloquentClass = Model::class;
}

View File

@ -80,6 +80,9 @@ Route::group([
'index',
])->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');

View File

@ -0,0 +1,164 @@
<?php
namespace App\Endpoint\Api\Http\Controllers;
use App\Endpoint\Api\Http\Resources\AfterSaleResource;
use App\Endpoint\Api\Http\Resources\AfterSaleSimpleResource;
use App\Exceptions\BizException;
use App\Helpers\Paginator as PaginatorHelper;
use App\Models\AfterSale;
use App\Models\OrderProduct;
use App\Services\AfterSaleService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Throwable;
class AfterSaleController extends Controller
{
/**
* 售后订单列表
*
* @param Request $request
* @return void
*/
public function index(Request $request)
{
$query = AfterSale::query()->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);
}
}

View File

@ -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'))) {

View File

@ -0,0 +1,24 @@
<?php
namespace App\Endpoint\Api\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class AfterSaleLogResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
public function toArray($request)
{
return [
'id' => $this->id,
'name' =>$this->name,
'desc' => $this->desc,
'created_at' => $this->created_at->toDateTimeString(),
];
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace App\Endpoint\Api\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class AfterSaleResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
public function toArray($request)
{
return [
'id' => $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')),
];
}
}

View File

@ -0,0 +1,25 @@
<?php
namespace App\Endpoint\Api\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class AfterSaleSimpleResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
public function toArray($request)
{
return [
'id' => $this->id,
'order_sn' => $this->whenLoaded('order')?->sn,
'order_product'=>'',
'state' => $this->state,
'remarks' => $this->remarks,
];
}
}

View File

@ -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']);
});
});

View File

@ -0,0 +1,139 @@
<?php
namespace App\Models;
use App\Casts\JsonArray;
use App\Casts\Price;
use Dcat\Admin\Traits\HasDateTimeFormatter;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
class AfterSale extends Model
{
use HasFactory;
use HasDateTimeFormatter;
public const STATE_APPLY = 1; // 待补充资料
public const STATE_VERIFY = 2; // 待审核
public const STATE_AGREE = 3; // 待同意
public const STATE_SHIPPING = 4; // 待收货
public const STATE_FINANCE = 5; // 待打款
public const STATE_FINISH = 6; // 完成
public const STATE_CANCEL = 7; // 取消
public const TYPE_REFUND_AND_RETURN = 1; // 退款退货
public const TYPE_REFUND = 2; // 退款不退货
public const TYPE_CHANGE = 3; // 换货
public const TYPE_FILL = 4; // 漏发
protected $casts = [
'images' => 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));
}
}

View File

@ -0,0 +1,25 @@
<?php
namespace App\Models;
use App\Casts\JsonArray;
use Dcat\Admin\Traits\HasDateTimeFormatter;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class AfterSaleLog extends Model
{
use HasFactory;
use HasDateTimeFormatter;
protected $casts = [
'images' => JsonArray::class,
];
protected $fillable = [
'name',
'desc',
'after_sale_id',
'images',
];
}

View File

@ -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
*/

View File

@ -120,6 +120,14 @@ class User extends Model implements AuthorizableContract, AuthenticatableContrac
return false;
}
/**
* 属于此用户的售后订单
*/
public function afterSales()
{
return $this->hasMany(AfterSale::class);
}
/**
* 禁用用户
*

View File

@ -0,0 +1,307 @@
<?php
namespace App\Services;
use App\Exceptions\BizException;
use App\Models\AfterSale;
use App\Models\AfterSaleLog;
use App\Models\OrderProduct;
use App\Models\User;
class AfterSaleService
{
/**
* 创建售后单
*
* @param User $user
* @param OrderProduct $orderProduct
* @param integer $type
* @param integer $num
* @param array $params
* @return AfterSale
*/
public function create(User $user, OrderProduct $orderProduct, int $type, int $num, array $params): AfterSale
{
// todo 校验这个订单商品是否还能发起售后-待完成
// if (1) {
// throw new BizException('该订单商品已过售后时间');
// }
//校验该订单商品不能有已完成、处理中的售后记录
if (AfterSale::where('order_product_id', $orderProduct->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('该售后订单状态异常');
}
}
}

View File

@ -0,0 +1,43 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateAfterSalesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('after_sales', function (Blueprint $table) {
$table->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');
}
}

View File

@ -0,0 +1,35 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateAfterSaleLogsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('after_sale_logs', function (Blueprint $table) {
$table->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');
}
}

View File

@ -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();

View File

@ -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)

View File

@ -0,0 +1,41 @@
<?php
return [
'labels' => [
'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' => [
],
];

View File

@ -0,0 +1,47 @@
<div class="card">
<div class="box-header with-border" style="height:50px;">
<h3 class="box-title" style="line-height:20px;">{{$title}}</h3>
</div>
<div class="card-body">
<div class="col-md-12" style="position: relative; overflow: auto; width: auto; height: 75vh;">
<div style="overflow: auto; width: auto; height: 100%;">
<!-- The time line -->
@if($logs->count() > 0)
<div class="timeline">
@foreach($logs as $log)
<!-- timeline time label -->
<div class="time-label">
<span class="bg-green">{{$log->created_at}}</span>
</div>
<!-- /.timeline-label -->
<!-- timeline item -->
<div>
<i class="fa fa-envelope bg-blue"></i>
<div class="timeline-item">
<span class="time"><i class="fas fa-clock"></i> {{$log->created_at->diffForHumans()}}</span>
<h3 class="timeline-header">{{$log->name}}</h3>
<div class="timeline-body">{{$log->desc}}</div>
@if(count($log->images) > 0)
<div class="timeline-body">
@foreach ($log->images as $image)
<a href="{{$image}}" target="_blank" style="display:inline-block; margin:10px;">
<img src="{{$image}}" style="max-height: 100px;max-width: 100px;vertical-align: middle;">
</a>
@endforeach
</div>
@endif
</div>
</div>
<!-- ./ timeline item -->
@endforeach
<div>
<i class="fas fa-clock bg-gray"></i>
</div>
</div>
@endif
</div>
</div>
</div>
</div>