mirror of
https://github.com/ProxyPanel/ProxyPanel.git
synced 2026-04-11 15:10:54 +00:00
Major update: 强化卡券玩法 & 相关代码优化
详情 https://proxypanel.gitbook.io/wiki/coupon
This commit is contained in:
@@ -5,6 +5,8 @@ namespace App\Http\Controllers\Admin;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Admin\CouponRequest;
|
||||
use App\Models\Coupon;
|
||||
use App\Models\Level;
|
||||
use App\Models\UserGroup;
|
||||
use Exception;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
@@ -35,6 +37,16 @@ class CouponController extends Controller
|
||||
return view('admin.coupon.index', ['couponList' => $query->latest()->paginate(15)->appends($request->except('page'))]);
|
||||
}
|
||||
|
||||
// 优惠券列表
|
||||
public function show(Coupon $coupon)
|
||||
{
|
||||
return view('admin.coupon.show', [
|
||||
'coupon' => $coupon,
|
||||
'userGroups' => UserGroup::all()->pluck('name', 'id')->toArray(),
|
||||
'levels' => Level::all()->pluck('name', 'level')->toArray(),
|
||||
]);
|
||||
}
|
||||
|
||||
// 添加优惠券
|
||||
public function store(CouponRequest $request)
|
||||
{
|
||||
@@ -49,7 +61,28 @@ class CouponController extends Controller
|
||||
$logo = 'upload/'.$fileName;
|
||||
}
|
||||
$num = (int) $request->input('num');
|
||||
$data = $request->only(['name', 'type', 'usable_times', 'value', 'rule', 'start_time', 'end_time']);
|
||||
$data = $request->only(['name', 'type', 'priority', 'usable_times', 'value', 'start_time', 'end_time']);
|
||||
$data['limit'] = [
|
||||
'minimum' => $request->input('minimum'),
|
||||
'used' => $request->input('used'),
|
||||
'users' => [
|
||||
'white' => $request->has('users_whitelist') ? array_map('intval', explode(', ', $request->input('users_whitelist'))) : null,
|
||||
'black' => $request->has('users_blacklist') ? array_map('intval', explode(', ', $request->input('users_blacklist'))) : null,
|
||||
'newbie' => [
|
||||
'coupon' => $request->input('coupon'),
|
||||
'order' => $request->input('order'),
|
||||
'days' => $request->has('days') ? (int) $request->input(['days']) : null,
|
||||
],
|
||||
'levels' => $request->has('levels') ? array_map('intval', $request->input('levels')) : null,
|
||||
'groups' => $request->has('groups') ? array_map('intval', $request->input('groups')) : null,
|
||||
],
|
||||
'services' => [
|
||||
'white' => $request->has('services_whitelist') ? array_map('intval', explode(', ', $request->input('services_whitelist'))) : null,
|
||||
'black' => $request->has('services_blacklist') ? array_map('intval', explode(', ', $request->input('services_blacklist'))) : null,
|
||||
],
|
||||
];
|
||||
array_clean($data['limit']);
|
||||
|
||||
$data['logo'] = $logo;
|
||||
$data['status'] = 0;
|
||||
try {
|
||||
@@ -69,7 +102,10 @@ class CouponController extends Controller
|
||||
// 添加优惠券页面
|
||||
public function create()
|
||||
{
|
||||
return view('admin.coupon.create');
|
||||
return view('admin.coupon.create', [
|
||||
'userGroups' => UserGroup::all()->pluck('name', 'id')->toArray(),
|
||||
'levels' => Level::all()->pluck('name', 'level')->toArray(),
|
||||
]);
|
||||
}
|
||||
|
||||
// 删除优惠券
|
||||
@@ -108,10 +144,10 @@ class CouponController extends Controller
|
||||
$spreadsheet->setActiveSheetIndex(0);
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
$sheet->setTitle('抵用券');
|
||||
$sheet->fromArray(['名称', '使用次数', '有效期', '券码', '金额(元)', '使用限制(元)']);
|
||||
$sheet->fromArray(['名称', '使用次数', '有效期', '券码', '金额(元)', '权重', '使用限制']);
|
||||
foreach ($voucherList as $k => $vo) {
|
||||
$dateRange = $vo->start_time.' ~ '.$vo->end_time;
|
||||
$sheet->fromArray([$vo->name, $vo->usable_times ?? '无限制', $dateRange, $vo->sn, $vo->value, $vo->rule], null, 'A'.($k + 2));
|
||||
$sheet->fromArray([$vo->name, $vo->usable_times ?? '无限制', $dateRange, $vo->sn, $vo->value, $vo->priority, json_encode($vo->limit)], null, 'A'.($k + 2));
|
||||
}
|
||||
|
||||
// 折扣券
|
||||
@@ -119,10 +155,10 @@ class CouponController extends Controller
|
||||
$spreadsheet->setActiveSheetIndex(1);
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
$sheet->setTitle('折扣券');
|
||||
$sheet->fromArray(['名称', '使用次数', '有效期', '券码', '折扣(折)', '使用限制(元)']);
|
||||
$sheet->fromArray(['名称', '使用次数', '有效期', '券码', '折扣(折)', '权重', '使用限制']);
|
||||
foreach ($discountCouponList as $k => $vo) {
|
||||
$dateRange = $vo->start_time.' ~ '.$vo->end_time;
|
||||
$sheet->fromArray([$vo->name, $vo->usable_times ?? '无限制', $dateRange, $vo->sn, $vo->value, $vo->rule], null, 'A'.($k + 2));
|
||||
$sheet->fromArray([$vo->name, $vo->usable_times ?? '无限制', $dateRange, $vo->sn, $vo->value, $vo->priority, json_encode($vo->limit)], null, 'A'.($k + 2));
|
||||
}
|
||||
|
||||
// 充值券
|
||||
|
||||
@@ -18,6 +18,7 @@ use App\Models\Coupon;
|
||||
use App\Models\Goods;
|
||||
use App\Models\Order;
|
||||
use App\Models\Payment;
|
||||
use App\Services\CouponService;
|
||||
use Auth;
|
||||
use Exception;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
@@ -127,13 +128,12 @@ class PaymentController extends Controller
|
||||
|
||||
// 使用优惠券
|
||||
if ($coupon_sn) {
|
||||
$ret = $this->couponCheck($coupon_sn, $goods->price);
|
||||
$ret = (new CouponService($coupon_sn))->search($goods); // 检查券合规性
|
||||
|
||||
if ($ret !== true) {
|
||||
if (! $ret instanceof Coupon) {
|
||||
return $ret;
|
||||
}
|
||||
|
||||
$coupon = Coupon::whereStatus(0)->whereIn('type', [1, 2])->whereSn($coupon_sn)->firstOrFail();
|
||||
$coupon = $ret;
|
||||
|
||||
// 计算实际应支付总价
|
||||
$amount = $coupon->type === 2 ? $goods->price * $coupon->value / 100 : $goods->price - $coupon->value;
|
||||
@@ -198,50 +198,6 @@ class PaymentController extends Controller
|
||||
return Response::json(['status' => 'fail', 'message' => '订单创建失败']);
|
||||
}
|
||||
|
||||
public function couponCheck($coupon_sn, $price) // 检查券合规性
|
||||
{
|
||||
if (empty($coupon_sn)) {
|
||||
return Response::json([
|
||||
'status' => 'fail', 'title' => trans('common.failed'), 'message' => trans('validation.required', ['attribute' => trans('user.coupon.attribute')]),
|
||||
]);
|
||||
}
|
||||
|
||||
$coupon = Coupon::whereSn($coupon_sn)->whereIn('type', [1, 2])->first();
|
||||
if (! $coupon) {
|
||||
return Response::json(['status' => 'fail', 'title' => trans('common.failed'), 'message' => trans('user.coupon.error.unknown')]);
|
||||
}
|
||||
|
||||
if ($coupon->status === 1) {
|
||||
return Response::json(['status' => 'fail', 'title' => trans('common.sorry'), 'message' => trans('user.coupon.error.used')]);
|
||||
}
|
||||
if ($coupon->getRawOriginal('end_time') < time()) {
|
||||
$coupon->status = 2;
|
||||
$coupon->save();
|
||||
|
||||
return Response::json(['status' => 'fail', 'title' => trans('common.sorry'), 'message' => trans('user.coupon.error.expired')]);
|
||||
}
|
||||
|
||||
if ($coupon->status === 2) {
|
||||
if ($coupon->usable_times === 0) {
|
||||
return Response::json(['status' => 'fail', 'title' => trans('common.sorry'), 'message' => trans('user.coupon.error.run_out')]);
|
||||
}
|
||||
|
||||
return Response::json(['status' => 'fail', 'title' => trans('common.sorry'), 'message' => trans('user.coupon.error.expired')]);
|
||||
}
|
||||
|
||||
if ($coupon->start_time > date('Y-m-d H:i:s')) {
|
||||
return Response::json(['status' => 'fail', 'title' => trans('user.coupon.error.inactive'),
|
||||
'message' => trans('user.coupon.error.wait', ['time' => $coupon->start_time]),
|
||||
]);
|
||||
}
|
||||
|
||||
if ($price < $coupon->rule) {
|
||||
return Response::json(['status' => 'fail', 'title' => trans('user.coupon.error.limit'), 'message' => trans('user.coupon.error.higher', ['amount' => $coupon->rule])]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function close(Order $order): JsonResponse
|
||||
{
|
||||
if (! $order->close()) {
|
||||
|
||||
@@ -14,6 +14,7 @@ use App\Models\Ticket;
|
||||
use App\Models\User;
|
||||
use App\Notifications\TicketCreated;
|
||||
use App\Notifications\TicketReplied;
|
||||
use App\Services\CouponService;
|
||||
use Cache;
|
||||
use DB;
|
||||
use Exception;
|
||||
@@ -205,14 +206,11 @@ class UserController extends Controller
|
||||
|
||||
if ($user && $nodes = $user->userGroup) {
|
||||
$nodes = $nodes->nodes();
|
||||
foreach ($goodsList as $goods) {
|
||||
$goods->node_count = $nodes->where('level', '<=', $goods->level)->count();
|
||||
}
|
||||
} else {
|
||||
$nodes = Node::all();
|
||||
foreach ($goodsList as $goods) {
|
||||
$goods->node_count = $nodes->where('level', '<=', $goods->level)->count();
|
||||
}
|
||||
}
|
||||
foreach ($goodsList as $goods) {
|
||||
$goods->node_count = $nodes->where('level', '<=', $goods->level)->count();
|
||||
}
|
||||
|
||||
return view('user.services', [
|
||||
@@ -385,14 +383,12 @@ class UserController extends Controller
|
||||
if ($user->invite_num <= 0) {
|
||||
return Response::json(['status' => 'fail', 'message' => trans('user.invite.generate_failed')]);
|
||||
}
|
||||
|
||||
$obj = new Invite();
|
||||
$obj->inviter_id = $user->id;
|
||||
$obj->code = strtoupper(mb_substr(md5(microtime().Str::random()), 8, 12));
|
||||
$obj->dateline = date('Y-m-d H:i:s', strtotime(sysConfig('user_invite_days').' days'));
|
||||
$obj->save();
|
||||
if ($obj) {
|
||||
$user->update(['invite_num' => $user->invite_num - 1]);
|
||||
$invite = $user->invites()->create([
|
||||
'code' => strtoupper(mb_substr(md5(microtime().Str::random()), 8, 12)),
|
||||
'dateline' => date('Y-m-d H:i:s', strtotime(sysConfig('user_invite_days').' days')),
|
||||
]);
|
||||
if ($invite) {
|
||||
$user->decrement('invite_num');
|
||||
|
||||
return Response::json(['status' => 'success', 'message' => trans('common.generate_item', ['attribute' => trans('common.success')])]);
|
||||
}
|
||||
@@ -401,21 +397,24 @@ class UserController extends Controller
|
||||
}
|
||||
|
||||
// 使用优惠券
|
||||
public function redeemCoupon(Request $request): JsonResponse
|
||||
public function redeemCoupon(Request $request, Goods $good): JsonResponse
|
||||
{
|
||||
$coupon_sn = $request->input('coupon_sn');
|
||||
|
||||
$ret = (new PaymentController())->couponCheck($coupon_sn, $request->input('price'));
|
||||
if (empty($coupon_sn)) {
|
||||
return Response::json(['status' => 'fail', 'title' => trans('common.failed'), 'message' => trans('user.coupon.error.unknown')]);
|
||||
}
|
||||
|
||||
if ($ret !== true) {
|
||||
$ret = (new CouponService($coupon_sn))->search($good); // 检查券合规性
|
||||
|
||||
if (! $ret instanceof Coupon) {
|
||||
return $ret;
|
||||
}
|
||||
$coupon = Coupon::whereSn($coupon_sn)->whereIn('type', [1, 2])->firstOrFail();
|
||||
|
||||
$data = [
|
||||
'name' => $coupon->name,
|
||||
'type' => $coupon->type,
|
||||
'value' => $coupon->value,
|
||||
'name' => $ret->name,
|
||||
'type' => $ret->type,
|
||||
'value' => $ret->value,
|
||||
];
|
||||
|
||||
return Response::json(['status' => 'success', 'data' => $data, 'message' => trans('common.applied', ['attribute' => trans('user.coupon.attribute')])]);
|
||||
@@ -534,32 +533,10 @@ class UserController extends Controller
|
||||
return Response::json(['status' => 'fail', 'message' => $validator->errors()->all()]);
|
||||
}
|
||||
|
||||
$coupon = Coupon::whereSn($request->input('coupon_sn'))->firstOrFail();
|
||||
|
||||
try {
|
||||
DB::beginTransaction();
|
||||
// 写入日志
|
||||
$user = auth()->user();
|
||||
Helpers::addUserCreditLog($user->id, null, $user->credit, $user->credit + $coupon->value, $coupon->value,
|
||||
trans('user.recharge').' - ['.trans('user.coupon.recharge').':'.$request->input('coupon_sn').']');
|
||||
|
||||
// 余额充值
|
||||
$user->updateCredit($coupon->value);
|
||||
|
||||
// 更改卡券状态
|
||||
$coupon->update(['status' => 1]);
|
||||
|
||||
// 写入卡券日志
|
||||
Helpers::addCouponLog(trans('user.recharge_credit'), $coupon->id);
|
||||
|
||||
DB::commit();
|
||||
|
||||
if ((new CouponService($request->input('coupon_sn')))->charge()) {
|
||||
return Response::json(['status' => 'success', 'message' => trans('user.recharge').trans('common.success')]);
|
||||
} catch (Exception $e) {
|
||||
Log::error(trans('user.recharge').trans('common.failed').$e->getMessage());
|
||||
DB::rollBack();
|
||||
|
||||
return Response::json(['status' => 'fail', 'message' => trans('user.recharge').trans('common.failed')]);
|
||||
}
|
||||
|
||||
return Response::json(['status' => 'fail', 'message' => trans('user.recharge').trans('common.failed')]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,12 +10,23 @@ class CouponRequest extends FormRequest
|
||||
{
|
||||
return [
|
||||
'name' => 'required|string',
|
||||
'sn' => 'unique:coupon',
|
||||
'sn' => 'exclude_unless:type,3|unique:coupon',
|
||||
'logo' => 'nullable|image',
|
||||
'type' => 'required|numeric|between:1,3',
|
||||
'usable_times' => 'nullable|numeric',
|
||||
'priority' => 'nullable|numeric|min:0|max:255',
|
||||
'usable_times' => 'nullable|numeric|min:1',
|
||||
'value' => 'required|numeric|min:0',
|
||||
'rule' => 'nullable|numeric',
|
||||
'minimum' => 'nullable|numeric',
|
||||
'used' => 'nullable|numeric',
|
||||
'levels' => 'nullable|array',
|
||||
'groups' => 'nullable|array',
|
||||
'users_whitelist' => 'nullable|string',
|
||||
'users_blacklist' => 'nullable|string',
|
||||
'services_blacklist' => 'nullable|string',
|
||||
'services_whitelist' => 'nullable|string',
|
||||
'coupon' => 'nullable',
|
||||
'order' => 'nullable',
|
||||
'days' => 'nullable|numeric',
|
||||
'num' => 'required|numeric|min:1',
|
||||
'start_time' => 'required|date|before_or_equal:end_time',
|
||||
'end_time' => 'required|date|after_or_equal:start_time',
|
||||
|
||||
@@ -13,7 +13,7 @@ class Coupon extends Model
|
||||
use SoftDeletes;
|
||||
|
||||
protected $table = 'coupon';
|
||||
protected $casts = ['start_time' => 'date:Y-m-d', 'end_time' => 'date:Y-m-d'];
|
||||
protected $casts = ['limit' => 'array', 'start_time' => 'date:Y-m-d', 'end_time' => 'date:Y-m-d'];
|
||||
protected $dates = ['deleted_at'];
|
||||
protected $guarded = [];
|
||||
|
||||
@@ -32,4 +32,18 @@ class Coupon extends Model
|
||||
{
|
||||
return $this->attributes['end_time'] = strtotime($value);
|
||||
}
|
||||
|
||||
public function used()
|
||||
{
|
||||
$this->attributes['status'] = 1;
|
||||
|
||||
return $this->save();
|
||||
}
|
||||
|
||||
public function expired()
|
||||
{
|
||||
$this->attributes['status'] = 2;
|
||||
|
||||
return $this->save();
|
||||
}
|
||||
}
|
||||
|
||||
142
app/Services/CouponService.php
Normal file
142
app/Services/CouponService.php
Normal file
@@ -0,0 +1,142 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Components\Helpers;
|
||||
use App\Models\Coupon;
|
||||
use App\Models\Goods;
|
||||
use Auth;
|
||||
use Exception;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Response;
|
||||
|
||||
class CouponService
|
||||
{
|
||||
public $code;
|
||||
public $user;
|
||||
|
||||
public function __construct(string $code)
|
||||
{
|
||||
$this->code = $code;
|
||||
$this->user = Auth::getUser();
|
||||
}
|
||||
|
||||
public function search(Goods $goods) // 寻找合适的券
|
||||
{
|
||||
$coupons = Coupon::whereSn($this->code)->whereIn('type', [1, 2])->orderByDesc('priority')->get();
|
||||
if ($coupons->isNotEmpty()) {
|
||||
foreach ($coupons as $coupon) {
|
||||
$ret = $this->check($goods, $coupon);
|
||||
if ($ret === true) { // passed
|
||||
return $coupon;
|
||||
}
|
||||
}
|
||||
|
||||
return $ret ?? $this->failedReturn(trans('common.failed'), trans('user.coupon.error.unknown'));
|
||||
}
|
||||
|
||||
return $this->failedReturn(trans('common.failed'), trans('user.coupon.error.unknown'));
|
||||
}
|
||||
|
||||
private function check(Goods $goods, Coupon $coupon) // 检查券合规性
|
||||
{
|
||||
if ($coupon->status === 1) {
|
||||
return $this->failedReturn(trans('common.sorry'), trans('user.coupon.error.used'));
|
||||
}
|
||||
|
||||
if (time() > $coupon->getRawOriginal('end_time')) {
|
||||
$coupon->expired();
|
||||
|
||||
return $this->failedReturn(trans('common.sorry'), trans('user.coupon.error.expired'));
|
||||
}
|
||||
|
||||
if ($coupon->usable_times === 0) {
|
||||
return $this->failedReturn(trans('common.sorry'), trans('user.coupon.error.run_out'));
|
||||
}
|
||||
|
||||
if ($coupon->status === 2) {
|
||||
return $this->failedReturn(trans('common.sorry'), trans('user.coupon.error.expired'));
|
||||
}
|
||||
|
||||
if (time() < $coupon->getRawOriginal('start_time')) {
|
||||
return $this->failedReturn(trans('user.coupon.error.inactive'), trans('user.coupon.error.wait', ['time' => $coupon->start_time]));
|
||||
}
|
||||
|
||||
if (isset($coupon->limit['minimum']) && $goods->price < $coupon->limit['minimum']) {
|
||||
return $this->failedReturn(trans('user.coupon.error.unmet'), trans('user.coupon.error.minimum', ['amount' => $coupon->limit['minimum']]));
|
||||
}
|
||||
|
||||
if (isset($coupon->limit['users']['black']) && in_array($this->user->id, $coupon->limit['users']['black'], true)) {
|
||||
return $this->failedReturn(trans('user.coupon.error.unmet'), trans('user.coupon.error.users'));
|
||||
}
|
||||
|
||||
if (isset($coupon->limit['services']['black']) && in_array($goods->id, $coupon->limit['services']['black'], true)) {
|
||||
return $this->failedReturn(trans('user.coupon.error.unmet'), trans('user.coupon.error.services'));
|
||||
}
|
||||
|
||||
if (isset($coupon->limit['users']['white']) && ! in_array($this->user->id, $coupon->limit['users']['white'], true)) {
|
||||
return $this->failedReturn(trans('user.coupon.error.unmet'), trans('user.coupon.error.users'));
|
||||
}
|
||||
|
||||
if (isset($coupon->limit['services']['white']) && ! in_array($goods->id, $coupon->limit['services']['white'], true)) {
|
||||
return $this->failedReturn(trans('user.coupon.error.unmet'), trans('user.coupon.error.services'));
|
||||
}
|
||||
|
||||
if (isset($coupon->limit['users']['levels']) && ! in_array($this->user->level, $coupon->limit['users']['levels'], true)) {
|
||||
return $this->failedReturn(trans('user.coupon.error.unmet'), trans('user.coupon.error.users'));
|
||||
}
|
||||
|
||||
if (isset($coupon->limit['users']['groups']) && ! in_array($this->user->user_group_id, $coupon->limit['users']['groups'], true)) {
|
||||
return $this->failedReturn(trans('user.coupon.error.unmet'), trans('user.coupon.error.users'));
|
||||
}
|
||||
|
||||
if (isset($coupon->limit['users']['newbie'])) { // 新用户可用
|
||||
if (isset($coupon->limit['users']['newbie']['coupon']) && $this->user->orders()->whereNotNull('coupon_id')->exists()) { // 第一次使用优惠券
|
||||
return $this->failedReturn(trans('user.coupon.error.unmet'), trans('user.coupon.error.users'));
|
||||
}
|
||||
|
||||
if (isset($coupon->limit['users']['newbie']['order']) && $this->user->orders()->exists()) { // 第一个套餐订单
|
||||
|
||||
return $this->failedReturn(trans('user.coupon.error.unmet'), trans('user.coupon.error.users'));
|
||||
}
|
||||
|
||||
if (isset($coupon->limit['users']['newbie']['days']) && (time() > strtotime($this->user->created_at.' +'.$coupon->limit['users']['newbie']['days'].' days') ||
|
||||
$this->user->orders()->whereCouponId($coupon->id)->exists())) { // 创号N天内, 且第一次用优惠券
|
||||
|
||||
return $this->failedReturn(trans('user.coupon.error.unmet'), trans('user.coupon.error.users'));
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($coupon->limit['used']) && $this->user->orders()->whereCouponId($coupon->id)->count() >= $coupon->limit['used']) {
|
||||
return $this->failedReturn(trans('user.coupon.error.unmet'),
|
||||
trans_choice('user.coupon.error.overused', $coupon->limit['used'], ['times' => $coupon->limit['used']]));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function failedReturn(string $title, string $message)
|
||||
{
|
||||
return Response::json(['status' => 'fail', 'title' => $title, 'message' => $message]);
|
||||
}
|
||||
|
||||
public function charge(): bool
|
||||
{
|
||||
$coupon = Coupon::whereSn($this->code)->whereType(3)->first();
|
||||
if ($coupon && $coupon->status === 0) {
|
||||
try {
|
||||
Helpers::addUserCreditLog($this->user->id, null, $this->user->credit, $this->user->credit + $coupon->value, $coupon->value,
|
||||
trans('user.recharge').' - ['.trans('user.coupon.recharge').':'.$coupon->sn.']'); // 写入用户余额变动日志
|
||||
$this->user->updateCredit($coupon->value); // 余额充值
|
||||
$coupon->used(); // 更改卡券状态
|
||||
Helpers::addCouponLog(trans('user.recharge_credit'), $coupon->id); // 写入卡券使用日志
|
||||
|
||||
return true;
|
||||
} catch (Exception $exception) {
|
||||
Log::emergency('[重置券处理出现错误] '.$exception->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -109,3 +109,20 @@ if (! function_exists('string_decrypt')) {
|
||||
return openssl_decrypt(base64url_decode($data), 'aes-128-ctr', hash('sha256', config('app.key')), OPENSSL_RAW_DATA, substr(sha1(config('app.key')), 0, 16));
|
||||
}
|
||||
}
|
||||
|
||||
// Array values and indexes clean
|
||||
if (! function_exists('array_clean')) {
|
||||
function array_clean(array &$array): array
|
||||
{
|
||||
foreach ($array as $key => &$value) {
|
||||
if (is_array($value)) {
|
||||
$value = array_clean($value);
|
||||
}
|
||||
if (empty($value)) {
|
||||
unset($array[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
}
|
||||
|
||||
59
database/migrations/2022_08_25_204229_improve_coupon.php
Normal file
59
database/migrations/2022_08_25_204229_improve_coupon.php
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
use App\Components\MigrationToolBox;
|
||||
use App\Models\Coupon;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class ImproveCoupon extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('coupon', function (Blueprint $table) {
|
||||
if ((new MigrationToolBox())->versionCheck()) {
|
||||
$table->json('limit')->nullable()->comment('使用限制')->after('rule');
|
||||
} else {
|
||||
$table->text('limit')->nullable()->comment('使用限制')->after('rule');
|
||||
}
|
||||
$table->unsignedTinyInteger('priority')->default(0)->comment('使用权重, 高者优先')->after('limit');
|
||||
$table->dropUnique(['sn']);
|
||||
});
|
||||
|
||||
foreach (Coupon::whereNotNull('rule')->get() as $coupon) {
|
||||
$coupon->update(['limit' => ['minimum' => $coupon->rule]]);
|
||||
}
|
||||
|
||||
Schema::table('coupon', function (Blueprint $table) {
|
||||
$table->dropColumn('rule');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('coupon', function (Blueprint $table) {
|
||||
$table->unsignedInteger('rule')->nullable()->comment('使用限制(元)')->after('limit');
|
||||
});
|
||||
|
||||
foreach (Coupon::whereNotNull('limit')->get() as $coupon) {
|
||||
if (isset($coupon->limit['minimum'])) {
|
||||
$coupon->update(['rule' => $coupon->limit['minimum']]);
|
||||
}
|
||||
}
|
||||
|
||||
Schema::table('coupon', function (Blueprint $table) {
|
||||
$table->dropColumn('limit', 'priority');
|
||||
$table->unique('sn');
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -96,8 +96,11 @@ return [
|
||||
'run_out' => 'Run Out of Usage',
|
||||
'inactive' => 'Coupon Inactive yet',
|
||||
'wait' => 'The Event will begin until :time, Please wait',
|
||||
'limit' => 'Order\'s price is reach the minimum requirement of this coupon',
|
||||
'higher' => 'The minimum requirement of this coupon is ¥:amount',
|
||||
'unmet' => 'Conditions of use are not met',
|
||||
'minimum' => 'The minimum requirement of this coupon is ¥:amount',
|
||||
'overused' => 'You can only use this coupon once|You can only use this coupon :times times',
|
||||
'users' => 'This account is not eligible for promotions',
|
||||
'services' => 'This item is not qualify for this discount, please check the promotion terms',
|
||||
],
|
||||
],
|
||||
'error_response' => 'Something went wrong, please try again later.',
|
||||
|
||||
@@ -96,8 +96,11 @@ return [
|
||||
'run_out' => '优惠券耗尽',
|
||||
'inactive' => '优惠券尚未生效',
|
||||
'wait' => '活动将于:time生效,请耐心等待!',
|
||||
'limit' => '使用条件未满足',
|
||||
'higher' => '本券最低使用金额为 ¥:amount',
|
||||
'unmet' => '使用条件未满足',
|
||||
'minimum' => '本券最低使用金额为 ¥:amount',
|
||||
'overused' => '本券只能使用 :times 次',
|
||||
'users' => '帐户不符合促销条件',
|
||||
'services' => '商品不符合折扣条件,请查看促销条款',
|
||||
],
|
||||
],
|
||||
'error_response' => '出现了错误,请稍后再试。',
|
||||
@@ -119,7 +122,7 @@ return [
|
||||
],
|
||||
'referral' => [
|
||||
'link' => '推广链接',
|
||||
'total' => '合计返利 :amount 元( :total 次),满 :money 元可以申请提现。',
|
||||
'total' => '合计返利 ¥ :amount( :total 次),满 ¥ :money 可以申请提现。',
|
||||
'amount' => '消费金额',
|
||||
'commission' => '返利金额',
|
||||
'logs' => '佣金记录',
|
||||
@@ -128,7 +131,7 @@ return [
|
||||
'msg' => [
|
||||
'account' => '账号已过期,请先购买服务吧',
|
||||
'applied' => '已存在申请,请等待之前的申请处理完',
|
||||
'unfulfilled' => '满:amount元才可以提现,继续努力吧',
|
||||
'unfulfilled' => '满¥ :amount才可以提现,继续努力吧',
|
||||
'wait' => '请等待管理员审核',
|
||||
'error' => '返利单建立失败,请稍后尝试或通知管理员',
|
||||
],
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
@extends('admin.layouts')
|
||||
@section('css')
|
||||
<link href="/assets/global/vendor/dropify/dropify.min.css" rel="stylesheet">
|
||||
<link href="/assets/global/vendor/bootstrap-select/bootstrap-select.min.css" rel="stylesheet">
|
||||
<link href="/assets/global/vendor/bootstrap-datepicker/bootstrap-datepicker.min.css" rel="stylesheet">
|
||||
<link href="/assets/global/vendor/bootstrap-tokenfield/bootstrap-tokenfield.min.css" rel="stylesheet">
|
||||
@endsection
|
||||
@section('content')
|
||||
<div class="page-content container">
|
||||
@@ -58,33 +60,143 @@
|
||||
<span class="text-help"> 抵用:抵扣商品金额,折扣:商品百分比打折,充值:充值用户账号余额 </span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row usage">
|
||||
<label class="col-md-2 col-form-label" for="usable_times">使用次数</label>
|
||||
<div class="col-md-4 input-group">
|
||||
<input type="number" class="form-control" name="usable_times" id="usable_times" value="{{old('usable_times')}}"/>
|
||||
<span class="input-group-text">次</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-md-2 col-form-label" for="value">优惠额度</label>
|
||||
<div class="col-md-10">
|
||||
<div class="input-group">
|
||||
<input type="number" class="form-control col-md-3" name="value" id="value" value="{{old('value')}}" required/>
|
||||
<input type="number" class="form-control col-md-3" min="1" max="99" name="value" id="value" value="{{old('value')}}" required/>
|
||||
<span class="input-group-text" id="amount">元</span>
|
||||
<span class="input-group-text discount" style="display: none;">%</span>
|
||||
</div>
|
||||
<span class="text-help discount" style="display: none;"> 范围为 1~99折,即 1% ~ 99% </span>
|
||||
<span class="text-help discount" style="display: none;"> 范围为 1% ~ 99% </span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row usage">
|
||||
<label class="col-md-2 col-form-label" for="rule">满减条件</label>
|
||||
<div class="col-md-10">
|
||||
<div class="input-group">
|
||||
<input type="number" class="form-control col-md-3" name="rule" id="rule" value="{{old('rule')}}" step="0.01" />
|
||||
<span class="input-group-text">元</span>
|
||||
<div class="usage">
|
||||
<div class="form-group row">
|
||||
<label class="col-md-2 col-form-label" for="priority"> 权 重 </label>
|
||||
<div class="col-md-10">
|
||||
<div class="input-group">
|
||||
<input type="number" class="form-control col-md-2" min="0" max="255" name="priority" id="priority" value="{{old('priority')}}"/>
|
||||
</div>
|
||||
<span class="text-help"> 同【使用券码】下,符合条件的高权重码将会被优先使用。最高为 255 </span>
|
||||
</div>
|
||||
<span class="text-help"> 当支付金额超过N值时,才能使用本优惠劵;不设置/0,即为无限制 </span>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-md-2 col-form-label" for="usable_times">使用次数</label>
|
||||
<div class="col-md-4 input-group">
|
||||
<input type="number" class="form-control" min="1" name="usable_times" id="usable_times" value="{{old('usable_times', 1)}}"/>
|
||||
<span class="input-group-text">次</span>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="form-group row">
|
||||
<label class="col-md-2 col-form-label" for="minimum">满减条件</label>
|
||||
<div class="col-md-10">
|
||||
<div class="input-group">
|
||||
<input type="number" class="form-control col-md-3" name="minimum" id="minimum" value="{{old('minimum')}}" step="0.01"/>
|
||||
<span class="input-group-text">元</span>
|
||||
</div>
|
||||
<span class="text-help"> 当支付金额超过N值时,才能使用本优惠劵;不设置/0,即为无限制 </span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-md-2 col-form-label" for="used">个人限用</label>
|
||||
<div class="col-md-10">
|
||||
<div class="input-group">
|
||||
<input type="number" class="form-control col-md-3" name="used" id="used" value="{{old('used')}}" step="1"/>
|
||||
<span class="input-group-text">次</span>
|
||||
</div>
|
||||
<span class="text-help"> 符合条件的用户可以使用本券N次;不设置/0,即为无限制 </span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="levels" class="col-md-2 col-form-label">等级限定</label>
|
||||
<div class="col-md-10">
|
||||
<select data-plugin="selectpicker" data-style="btn-outline btn-primary" class="col-md-5 form-control show-tick" id="levels" name="levels[]"
|
||||
multiple>
|
||||
@foreach($levels as $key => $level)
|
||||
<option value="{{$key}}">{{$level}}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
<span class="text-help"> 用户等级在选定等级内,方可使用本券</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="groups" class="col-md-2 col-form-label">分组限定</label>
|
||||
<div class="col-md-10">
|
||||
<select data-plugin="selectpicker" data-style="btn-outline btn-primary" class="col-md-5 form-control show-tick" id="groups" name="groups[]"
|
||||
multiple>
|
||||
@foreach($userGroups as $key => $group)
|
||||
<option value="{{$key}}">{{$group}}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
<span class="text-help"> 选定的用户分组,方可使用本券</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-md-2 col-form-label" for="users_whitelist">专属用户</label>
|
||||
<div class="col-md-10">
|
||||
<input type="text" class="form-control col-md-6" data-plugin="tokenfield" id="users_whitelist" name="users_whitelist"
|
||||
value="{{old('users_whitelist')}}" placeholder="输入用户ID, 再回车"/>
|
||||
<span class="text-help"> 涉及用户均可使用本券,留空为不使用此条件</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-md-2 col-form-label" for="users_blacklist">禁用用户</label>
|
||||
<div class="col-md-10">
|
||||
<input type="text" class="form-control col-md-6" data-plugin="tokenfield" id="users_blacklist" name="users_blacklist"
|
||||
value="{{old('users_blacklist')}}" placeholder="输入用户ID, 再回车"/>
|
||||
<span class="text-help"> 涉及用户均不可使用本券,空为不使用此条件</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-md-2 col-form-label" for="services_whitelist">许可商品</label>
|
||||
<div class="col-md-10">
|
||||
<input type="text" class="form-control col-md-4" data-plugin="tokenfield" id="services_whitelist" name="services_whitelist"
|
||||
value="{{old('services_whitelist')}}" placeholder="输入商品ID, 再回车"/>
|
||||
<span class="text-help"> 涉及商品方可使用本券,留空为不使用此条件</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-md-2 col-form-label" for="services_blacklist">禁用商品</label>
|
||||
<div class="col-md-10">
|
||||
<input type="text" class="form-control col-md-4" data-plugin="tokenfield" id="services_blacklist" name="services_blacklist"
|
||||
value="{{old('services_blacklist')}}" placeholder="输入商品ID, 再回车"/>
|
||||
<span class="text-help"> 涉及商品不可使用本券,留空为不使用此条件</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="newbie" class="col-md-2 col-form-label">新人专属</label>
|
||||
<div class="col-md-10">
|
||||
<ul class="list-unstyled">
|
||||
<li class="list-group-item p-0">
|
||||
<div class="checkbox-custom checkbox-primary">
|
||||
<input type="checkbox" id="coupon" name="coupon" {{ old('coupon') ? 'checked' : '' }}/>
|
||||
<label for="coupon">首次用任意券</label>
|
||||
</div>
|
||||
</li>
|
||||
<li class="list-group-item p-0">
|
||||
<div class="checkbox-custom checkbox-primary">
|
||||
<input type="checkbox" id="order" name="order" {{ old('order') ? 'checked' : '' }}/>
|
||||
<label for="order">首单</label>
|
||||
</div>
|
||||
</li>
|
||||
<li class="list-group-item pb-0 pl-0">
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<label class="input-group-text" for="days">创号</label>
|
||||
</div>
|
||||
<input type="number" class="form-control col-md-3" name="days" id="days" value="{{old('days')}}"/>
|
||||
<div class="input-group-append">
|
||||
<span class="input-group-text">天</span>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<span class="text-help"> 本项各条件为 <strong>并且</strong> 关系,请自行搭配使用 </span>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-md-2 col-form-label" for="num">数量</label>
|
||||
@@ -119,38 +231,41 @@
|
||||
</div>
|
||||
@endsection
|
||||
@section('javascript')
|
||||
<script src="/assets/global/vendor/bootstrap-datepicker/bootstrap-datepicker.min.js"></script>
|
||||
<script src="/assets/global/vendor/dropify/dropify.min.js"></script>
|
||||
<script src="/assets/global/js/Plugin/bootstrap-datepicker.js"></script>
|
||||
<script src="/assets/global/vendor/bootstrap-select/bootstrap-select.min.js"></script>
|
||||
<script src="/assets/global/vendor/bootstrap-datepicker/bootstrap-datepicker.min.js"></script>
|
||||
<script src="/assets/global/vendor/bootstrap-tokenfield/bootstrap-tokenfield.min.js"></script>
|
||||
<script src="/assets/global/js/Plugin/dropify.js"></script>
|
||||
<script src="/assets/global/js/Plugin/bootstrap-select.js"></script>
|
||||
<script src="/assets/global/js/Plugin/bootstrap-datepicker.js"></script>
|
||||
<script src="/assets/global/js/Plugin/bootstrap-tokenfield.js"></script>
|
||||
<script>
|
||||
@if(old('type'))
|
||||
@if(old())
|
||||
$(document).ready(function() {
|
||||
$("input[name='type'][value='{{old('type')}}']").click();
|
||||
$("input[name='type'][value='{{old('type')}}']").click();
|
||||
$('#levels').selectpicker('val', @json(old('levels')));
|
||||
$('#groups').selectpicker('val', @json(old('groups')));
|
||||
});
|
||||
@endif
|
||||
|
||||
$('.input-daterange>input').datepicker({
|
||||
format: 'yyyy-mm-dd',
|
||||
format: 'yyyy-mm-dd',
|
||||
});
|
||||
|
||||
$('input[name=\'type\']').change(function() {
|
||||
if ($(this).val() === '2') {
|
||||
$('#rule').attr('required', true);
|
||||
$('.discount').show();
|
||||
$('.usage').show();
|
||||
$('.amount').hide();
|
||||
} else if ($(this).val() === '3') {
|
||||
$('#rule').attr('required', false);
|
||||
$('.discount').hide();
|
||||
$('.usage').hide();
|
||||
$('.amount').show();
|
||||
} else {
|
||||
$('#rule').attr('required', true);
|
||||
$('.discount').hide();
|
||||
$('.usage').show();
|
||||
$('.amount').show();
|
||||
}
|
||||
if ($(this).val() === '2') {
|
||||
$('.discount').show();
|
||||
$('.usage').show();
|
||||
$('#amount').hide();
|
||||
} else if ($(this).val() === '3') {
|
||||
$('.discount').hide();
|
||||
$('.usage').hide();
|
||||
$('#amount').show();
|
||||
} else {
|
||||
$('.discount').hide();
|
||||
$('.usage').show();
|
||||
$('#amount').show();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@endsection
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
<th> 券码</th>
|
||||
<th> 图片</th>
|
||||
<th> 类型</th>
|
||||
<th> 权重</th>
|
||||
<th> 使用次数</th>
|
||||
<th> 优惠</th>
|
||||
<th> 有效期</th>
|
||||
@@ -67,36 +68,32 @@
|
||||
<td> {{$coupon->sn}} </td>
|
||||
<td> @if($coupon->logo) <img src="{{asset($coupon->logo)}}" class="h-50" alt="优惠码logo"/> @endif </td>
|
||||
<td>
|
||||
@if($coupon->type === 1)
|
||||
抵用券
|
||||
@elseif($coupon->type === 2)
|
||||
折扣券
|
||||
@else
|
||||
充值券
|
||||
@endif
|
||||
{{ ['未知卡券','抵用券','折扣券','充值券'][$coupon->type] }}
|
||||
</td>
|
||||
<td> {{$coupon->priority}} </td>
|
||||
<td> {{$coupon->type === 3 ? '一次性' : ($coupon->usable_times ?? '无限制')}} </td>
|
||||
<td>
|
||||
{{$coupon->value}}@if($coupon->type === 2)%@else元@endif
|
||||
{{($coupon->type === 2 ?'减 ':'抵 ').$coupon->value.($coupon->type === 2 ?' %':' 元')}}
|
||||
</td>
|
||||
<td> {{$coupon->start_time}} ~ {{$coupon->end_time}} </td>
|
||||
<td>
|
||||
@if($coupon->status === 1)
|
||||
<span class="badge badge-lg badge-default"> 已使用 </span>
|
||||
@elseif ($coupon->status === 2)
|
||||
<span class="badge badge-lg badge-default"> 已失效 </span>
|
||||
@else
|
||||
<span class="badge badge-lg badge-success"> 生效中 </span>
|
||||
@endif
|
||||
<span class="badge badge-lg @if($coupon->status) badge-default @else badge-success @endif"> {{['生效中','已使用','已失效'][$coupon->status]}} </span>
|
||||
</td>
|
||||
<td>
|
||||
@if($coupon->status !== 1)
|
||||
@can('admin.coupon.destroy')
|
||||
<button class="btn btn-danger" onclick="delCoupon('{{$coupon->id}}','{{$coupon->name}}')">
|
||||
<i class="icon wb-close"></i>
|
||||
</button>
|
||||
<div class="btn-group">
|
||||
@can('admin.coupon.show')
|
||||
<a class="btn btn-info" href="{{route('admin.coupon.show', $coupon)}}" target="_blank">
|
||||
<i class="icon wb-eye"></i>
|
||||
</a>
|
||||
@endcan
|
||||
@endif
|
||||
@if($coupon->status !== 1)
|
||||
@can('admin.coupon.destroy')
|
||||
<button class="btn btn-danger" onclick="delCoupon('{{$coupon->id}}','{{$coupon->name}}')">
|
||||
<i class="icon wb-close"></i>
|
||||
</button>
|
||||
@endcan
|
||||
@endif
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
@@ -122,59 +119,59 @@
|
||||
<script src="/assets/global/vendor/bootstrap-table/bootstrap-table.min.js"></script>
|
||||
<script src="/assets/global/vendor/bootstrap-table/extensions/mobile/bootstrap-table-mobile.min.js"></script>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$('#type').val({{Request::query('type')}});
|
||||
$('#status').val({{Request::query('status')}});
|
||||
$(document).ready(function() {
|
||||
$('#type').val({{Request::query('type')}});
|
||||
$('#status').val({{Request::query('status')}});
|
||||
|
||||
$('select').on('change', function() { this.form.submit(); });
|
||||
$('select').on('change', function() { this.form.submit(); });
|
||||
});
|
||||
|
||||
@can('admin.coupon.export')
|
||||
// 批量导出卡券
|
||||
function exportCoupon() {
|
||||
swal.fire({
|
||||
title: '卡券导出',
|
||||
text: '确定导出所有卡券吗?',
|
||||
icon: 'question',
|
||||
showCancelButton: true,
|
||||
cancelButtonText: '{{trans('common.close')}}',
|
||||
confirmButtonText: '{{trans('common.confirm')}}',
|
||||
}).then((result) => {
|
||||
if (result.value) {
|
||||
window.location.href = '{{route('admin.coupon.export')}}';
|
||||
}
|
||||
});
|
||||
}
|
||||
@endcan
|
||||
|
||||
@can('admin.coupon.export')
|
||||
// 批量导出卡券
|
||||
function exportCoupon() {
|
||||
swal.fire({
|
||||
title: '卡券导出',
|
||||
text: '确定导出所有卡券吗?',
|
||||
icon: 'question',
|
||||
showCancelButton: true,
|
||||
cancelButtonText: '{{trans('common.close')}}',
|
||||
confirmButtonText: '{{trans('common.confirm')}}',
|
||||
}).then((result) => {
|
||||
if (result.value) {
|
||||
window.location.href = '{{route('admin.coupon.export')}}';
|
||||
@can('admin.coupon.destroy')
|
||||
// 删除卡券
|
||||
function delCoupon(id, name) {
|
||||
swal.fire({
|
||||
title: '确定删除卡券 【' + name + '】 吗?',
|
||||
icon: 'question',
|
||||
allowEnterKey: false,
|
||||
showCancelButton: true,
|
||||
cancelButtonText: '{{trans('common.close')}}',
|
||||
confirmButtonText: '{{trans('common.confirm')}}',
|
||||
}).then((result) => {
|
||||
if (result.value) {
|
||||
$.ajax({
|
||||
method: 'DELETE',
|
||||
url: '{{route('admin.coupon.destroy', '')}}/' + id,
|
||||
data: {_token: '{{csrf_token()}}'},
|
||||
dataType: 'json',
|
||||
success: function(ret) {
|
||||
if (ret.status === 'success') {
|
||||
swal.fire({title: ret.message, icon: 'success', timer: 1000, showConfirmButton: false}).then(() => window.location.reload());
|
||||
} else {
|
||||
swal.fire({title: ret.message, icon: 'error'}).then(() => window.location.reload());
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
@endcan
|
||||
|
||||
@can('admin.coupon.destroy')
|
||||
// 删除卡券
|
||||
function delCoupon(id, name) {
|
||||
swal.fire({
|
||||
title: '确定删除卡券 【' + name + '】 吗?',
|
||||
icon: 'question',
|
||||
allowEnterKey: false,
|
||||
showCancelButton: true,
|
||||
cancelButtonText: '{{trans('common.close')}}',
|
||||
confirmButtonText: '{{trans('common.confirm')}}',
|
||||
}).then((result) => {
|
||||
if (result.value) {
|
||||
$.ajax({
|
||||
method: 'DELETE',
|
||||
url: '{{route('admin.coupon.destroy', '')}}/' + id,
|
||||
data: {_token: '{{csrf_token()}}'},
|
||||
dataType: 'json',
|
||||
success: function(ret) {
|
||||
if (ret.status === 'success') {
|
||||
swal.fire({title: ret.message, icon: 'success', timer: 1000, showConfirmButton: false}).then(() => window.location.reload());
|
||||
} else {
|
||||
swal.fire({title: ret.message, icon: 'error'}).then(() => window.location.reload());
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@endcan
|
||||
</script>
|
||||
@endsection
|
||||
|
||||
234
resources/views/admin/coupon/show.blade.php
Normal file
234
resources/views/admin/coupon/show.blade.php
Normal file
@@ -0,0 +1,234 @@
|
||||
@extends('admin.layouts')
|
||||
@section('css')
|
||||
<link href="/assets/global/vendor/bootstrap-select/bootstrap-select.min.css" rel="stylesheet">
|
||||
<link href="/assets/global/vendor/bootstrap-tokenfield/bootstrap-tokenfield.min.css" rel="stylesheet">
|
||||
<style>
|
||||
.text-fit {
|
||||
width: fit-content;
|
||||
width: -moz-fit-content;
|
||||
}
|
||||
</style>
|
||||
@endsection
|
||||
@section('content')
|
||||
<div class="page-content container">
|
||||
<div class="panel">
|
||||
<div class="panel-heading">
|
||||
<h1 class="panel-title">卡券信息</h1>
|
||||
<div class="panel-actions">
|
||||
<a href="{{route('admin.coupon.index')}}" class="btn btn-danger">返 回</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="form-group row">
|
||||
<label class="col-md-2 col-form-label" for="name">卡券名称</label>
|
||||
<div class="col-md-10">
|
||||
<input class="form-control text-fit" id="name" value="{{$coupon->name}}" disabled/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-md-2 col-form-label" for="sn">使用券码</label>
|
||||
<div class="col-md-10">
|
||||
<input type="text" class="form-control text-fit" id="sn" value="{{$coupon->sn}}" disabled/>
|
||||
</div>
|
||||
</div>
|
||||
@if($coupon->logo)
|
||||
<div class="form-group row">
|
||||
<span class="col-md-2 col-form-label">卡券图片</span>
|
||||
<div class="col-md-10">
|
||||
<img src="{{asset($coupon->logo)}}" class="h-100" alt="优惠码logo"/>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
<div class="form-group row">
|
||||
<span class="col-md-2 col-form-label">类型</span>
|
||||
<div class="col-md-10 align-items-center">
|
||||
<div class="radio-custom radio-primary radio-inline">
|
||||
<input type="radio" id="voucher" checked/>
|
||||
<label for="voucher">
|
||||
{{ ['未知卡券','抵用券','折扣券','充值券'][$coupon->type] }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-md-2 col-form-label" for="value">优惠额度</label>
|
||||
<div class="col-md-10">
|
||||
<p class="form-control text-fit">
|
||||
@switch ($coupon->type)
|
||||
@case(1)
|
||||
抵用 <code>{{$coupon->value}}</code> 元
|
||||
@break
|
||||
@case(2)
|
||||
减 <code>{{$coupon->value}}</code> %
|
||||
@break
|
||||
@case(3)
|
||||
充值 <code>{{$coupon->value}}</code> 元
|
||||
@break
|
||||
@default
|
||||
未知卡券
|
||||
@endswitch
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@isset($coupon->priority)
|
||||
<div class="form-group row">
|
||||
<span class="col-md-2 col-form-label"> 权 重 </span>
|
||||
<div class="col-md-10">
|
||||
<span class="form-control text-fit"> {{$coupon->priority}} </span>
|
||||
</div>
|
||||
</div>
|
||||
@endisset
|
||||
@isset($coupon->usable_times)
|
||||
<div class="form-group row">
|
||||
<span class="col-md-2 col-form-label">剩余使用次数</span>
|
||||
<div class="col-md-10">
|
||||
<span class="form-control text-fit"><code>{{$coupon->usable_times}}</code> 次</span>
|
||||
</div>
|
||||
</div>
|
||||
@endisset
|
||||
@if(!empty($coupon->limit))
|
||||
<hr>
|
||||
@isset($coupon->limit['minimum'])
|
||||
<div class="form-group row">
|
||||
<label class="col-md-2 col-form-label" for="minimum">满减条件</label>
|
||||
<div class="col-md-10">
|
||||
<p class="form-control text-fit">当支付金额超过<strong> {{$coupon->limit['minimum']}}元</strong> 时,才能使用本优惠劵</p>
|
||||
</div>
|
||||
</div>
|
||||
@endisset
|
||||
@isset($coupon->limit['used'])
|
||||
<div class="form-group row">
|
||||
<span class="col-md-2 col-form-label">个人限用</span>
|
||||
<div class="col-md-10">
|
||||
<p class="form-control text-fit">符合条件的用户可以使用本券 <strong>{{$coupon->limit['used']}}次</strong></p>
|
||||
</div>
|
||||
</div>
|
||||
@endisset
|
||||
@isset($coupon->limit['users']['levels'])
|
||||
<div class="form-group row">
|
||||
<label class="col-md-2 col-form-label" for="levels">等级限定</label>
|
||||
<div class="col-md-10">
|
||||
<select data-plugin="selectpicker" data-style="btn-outline btn-primary" class="col-md-5 form-control show-tick" id="levels" multiple disabled>
|
||||
@foreach($levels as $key => $level)
|
||||
<option value="{{$key}}">{{$level}}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
<span class="text-help"> 以上用户等级,方可使用本券</span>
|
||||
</div>
|
||||
</div>
|
||||
@endisset
|
||||
@isset($coupon->limit['users']['groups'])
|
||||
<div class="form-group row">
|
||||
<label class="col-md-2 col-form-label" for="groups">分组限定</label>
|
||||
<div class="col-md-10">
|
||||
<select data-plugin="selectpicker" data-style="btn-outline btn-primary" class="col-md-5 form-control show-tick" id="groups" multiple disabled>
|
||||
@foreach($userGroups as $key => $group)
|
||||
<option value="{{$key}}">{{$group}}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
<span class="text-help"> 以上用户分组,方可使用本券</span>
|
||||
</div>
|
||||
</div>
|
||||
@endisset
|
||||
@isset($coupon->limit['users']['white'])
|
||||
<div class="form-group row">
|
||||
<label class="col-md-2 col-form-label" for="users_whitelist">专属用户</label>
|
||||
<div class="col-md-6">
|
||||
<input class="form-control" data-plugin="tokenfield" id="users_whitelist" value="{{ implode(',', $coupon->limit['users']['white']) }}"
|
||||
disabled/>
|
||||
<span class="text-help"> 以上用户均可使用本券</span>
|
||||
</div>
|
||||
</div>
|
||||
@endisset
|
||||
@isset($coupon->limit['users']['black'])
|
||||
<div class="form-group row">
|
||||
<label class="col-md-2 col-form-label" for="users_blacklist">禁用用户</label>
|
||||
<div class="col-md-6">
|
||||
<input class="form-control" data-plugin="tokenfield" id="users_blacklist" value="{{ implode(',', $coupon->limit['users']['black']) }}"
|
||||
disabled/>
|
||||
<span class="text-help"> 以上用户均不可使用本券</span>
|
||||
</div>
|
||||
</div>
|
||||
@endisset
|
||||
@isset($coupon->limit['services']['white'])
|
||||
<div class="form-group row">
|
||||
<label class="col-md-2 col-form-label" for="services_whitelist">许可商品</label>
|
||||
<div class="col-md-6">
|
||||
<input class="form-control" data-plugin="tokenfield" id="services_whitelist" value="{{ implode(',', $coupon->limit['services']['white']) }}"
|
||||
disabled/>
|
||||
<span class="text-help"> 以上商品方可使用本券</span>
|
||||
</div>
|
||||
</div>
|
||||
@endisset
|
||||
@isset($coupon->limit['services']['black'])
|
||||
<div class="form-group row">
|
||||
<label class="col-md-2 col-form-label" for="services_blacklist">禁用商品</label>
|
||||
<div class="col-md-6">
|
||||
<input class="form-control" data-plugin="tokenfield" id="services_blacklist" value="{{ implode(',', $coupon->limit['services']['black']) }}"
|
||||
disabled/>
|
||||
<span class="text-help"> 以上商品不可使用本券</span>
|
||||
</div>
|
||||
</div>
|
||||
@endisset
|
||||
@isset($coupon->limit['users']['newbie'])
|
||||
<div class="form-group row">
|
||||
<label for="newbie" class="col-md-2 col-form-label">新人专属</label>
|
||||
<div class="col-md-10">
|
||||
<ul class="list-unstyled">
|
||||
<li class="list-group-item p-0">
|
||||
<div class="checkbox-custom checkbox-primary">
|
||||
<input type="checkbox" id="coupon" {{ isset($coupon->limit['users']['newbie']['coupon']) ? 'checked' : '' }} disabled/>
|
||||
<label for="coupon">首次用任意券</label>
|
||||
</div>
|
||||
</li>
|
||||
<li class="list-group-item p-0">
|
||||
<div class="checkbox-custom checkbox-primary">
|
||||
<input type="checkbox" id="order" {{ isset($coupon->limit['users']['newbie']['order']) ? 'checked' : '' }} disabled/>
|
||||
<label for="order">首单</label>
|
||||
</div>
|
||||
</li>
|
||||
@isset($coupon->limit['users']['newbie']['days'])
|
||||
<li class="list-group-item p-0">
|
||||
<span class="form-control text-fit">且 创号 <code>{{$coupon->limit['users']['newbie']['days']}}</code> 天</span>
|
||||
</li>
|
||||
@endisset
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@endisset
|
||||
<hr>
|
||||
@endif
|
||||
<div class="form-group row">
|
||||
<label class="col-md-2 col-form-label">有效期</label>
|
||||
<div class="col-md-6 input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="icon wb-calendar" aria-hidden="true"></i></span>
|
||||
</div>
|
||||
<span class="form-control"> {{$coupon->start_time}} </span>
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">至</span>
|
||||
</div>
|
||||
<span class="form-control"> {{$coupon->end_time}} </span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@section('javascript')
|
||||
<script src="/assets/global/vendor/bootstrap-select/bootstrap-select.min.js"></script>
|
||||
<script src="/assets/global/vendor/bootstrap-tokenfield/bootstrap-tokenfield.min.js"></script>
|
||||
<script src="/assets/global/js/Plugin/bootstrap-select.js"></script>
|
||||
<script src="/assets/global/js/Plugin/bootstrap-tokenfield.js"></script>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
@isset($coupon->limit['users']['levels'])
|
||||
$('#levels').selectpicker('val', @json($coupon->limit['users']['levels']));
|
||||
@endisset
|
||||
|
||||
@isset($coupon->limit['users']['groups'])
|
||||
$('#groups').selectpicker('val', @json($coupon->limit['users']['groups']));
|
||||
@endisset
|
||||
});
|
||||
</script>
|
||||
@endsection
|
||||
@@ -77,9 +77,9 @@
|
||||
const goods_price = '{{$goods->price}}';
|
||||
$.ajax({
|
||||
method: 'POST',
|
||||
url: '{{route('redeemCoupon')}}',
|
||||
url: '{{route('redeemCoupon', $goods)}}',
|
||||
dataType: 'json',
|
||||
data: {_token: '{{csrf_token()}}', coupon_sn: coupon_sn, price: '{{$goods->price}}'},
|
||||
data: {_token: '{{csrf_token()}}', coupon_sn: coupon_sn},
|
||||
success: function(ret) {
|
||||
$('.input-group-prepend').remove();
|
||||
if (ret.status === 'success') {
|
||||
|
||||
@@ -59,7 +59,7 @@ Route::prefix('admin')->name('admin.')->group(function () {
|
||||
});
|
||||
|
||||
Route::resource('goods', 'ShopController')->except('show'); // 商品管理
|
||||
Route::resource('coupon', 'CouponController')->except('show', 'edit', 'update'); // 优惠券
|
||||
Route::resource('coupon', 'CouponController')->except('edit', 'update'); // 优惠券
|
||||
Route::get('coupon/export', 'CouponController@exportCoupon')->name('coupon.export'); // 导出优惠券
|
||||
|
||||
Route::prefix('aff')->name('aff.')->group(function () {
|
||||
|
||||
@@ -14,8 +14,8 @@ Route::get('invoices', 'UserController@invoices')->name('invoice'); // 订单列
|
||||
Route::post('closePlan', 'UserController@closePlan')->name('cancelPlan'); // 激活预支付套餐
|
||||
Route::get('invoice/{sn}', 'UserController@invoiceDetail')->name('invoiceInfo'); // 订单明细
|
||||
Route::post('resetUserTraffic', 'UserController@resetUserTraffic')->name('resetTraffic'); // 重置用户流量
|
||||
Route::post('buy/{good}/redeem', 'UserController@redeemCoupon')->name('redeemCoupon'); // 使用优惠券
|
||||
Route::get('buy/{good}', 'UserController@buy')->name('buy'); // 购买商品
|
||||
Route::post('redeemCoupon', 'UserController@redeemCoupon')->name('redeemCoupon'); // 使用优惠券
|
||||
Route::get('invite', 'UserController@invite')->name('invite'); // 邀请码
|
||||
Route::post('makeInvite', 'UserController@makeInvite')->name('createInvite'); // 生成邀请码
|
||||
Route::match(['get', 'post'], 'profile', 'UserController@profile')->name('profile'); // 修改个人信息
|
||||
|
||||
Reference in New Issue
Block a user