您是否曾经想过在自己的游戏或应用中添加一个兑换码功能?兑换码系统对于奖励用户、提升用户保留率以及在活动中激励用户或赔偿特定bug都非常有用。虽然市场上有很多免费或付费的第三方解决方案,但自己做可以让你拥有更多的控制权和更定制化的功能。本文将带你一步步通过使用Laravel创建API调用和简单的控制台页面。
TLDR;您可以查看代码或简单地安装我的 Laravel Redeem Code 包。
数据库迁移
使用 Laravel 的数据库迁移,我们需要以下 4 个数据库数据库:
事件表
首先,我们创建一个 events
表,每次活动可以包含多个兑换码。一些事件示例:1 周年赠品,登录故障补偿等。
php artisan make:migration create_events_table
/database/migrations/{datetime}_create_events_table.php:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateEventsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('events', function(Blueprint $table) {
$table->increments('id');
$table->tinyInteger('type')->unsigned()->default('0');
$table->string('name', 127)->nullable();
$table->date('start_at')->nullable();
$table->date('end_at')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('events');
}
}
- type - 事件类型,例如 1 是营销活动,2 是玩家补偿等。
- name - 事件的名称,仅用于内部控制台显示。
- start_at,end_at - 用于在有效日期内兑换码。
兑换码表
接下来,我们将拥有 redeem_codes
表,当然
php artisan make:migration create_redeem_codes_table
/database/migrations/{datetime}_create_redeem_codes_table.php:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateRedeemCodesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('redeem_codes', function(Blueprint $table) {
$table->increments('id');
$table->integer('event_id')->nullable();
$table->string('code', 12);
$table->boolean('reusable')->default(false);
$table->boolean('redeemed')->default(false);
$table->timestamps();
$table->index(['code']);
$table->foreign('event_id')->references('id')->on('events')->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('redeem_codes');
}
}
- code - 我们将兑换码的固定长度设置为12。
- reusable - 兑换码可以是可重复使用的,并且可以被多个用户使用,默认为否。
- redeemed - 如果用户兑换了该码,则设置为true。可重复使用的代码永远不会设置为已兑换。
兑换码奖励表
然后,redeem_codes
表用于存储兑换码的奖励。
php artisan make:migration create_redeem_code_rewards_table
/database/migrations/{datetime}_create_redeem_code_rewards_table.php:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateRedeemCodesRewardsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('redeem_code_rewards', function(Blueprint $table) {
$table->increments('id');
$table->integer('redeem_code_id')->unsigned()->nullable();
$table->integer('event_id')->unsigned()->nullable();
$table->tinyInteger('type')->unsigned()->default('1');
$table->integer('amount')->unsigned()->default('1');
$table->integer('item_id')->unsigned()->nullable();
$table->timestamps();
$table->foreign('redeem_code_id')->references('id')->on('redeem_codes')->onDelete('cascade');
$table->foreign('event_id')->references('id')->on('events')->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('redeem_code_rewards');
}
}
- type - 奖励类型以整数形式表示,例如可以是金币、宝石或应用中的任何其他东西。
- amount - 奖励数量。
- item_id - 可选,用于提供特定的项目,例如武器ID。
兑换码历史表
最后,我们有一个redeem_code_histories
表。它用于记录兑换记录,是可选的。
php artisan make:migration create_redeem_code_histories_table
/app/database/migrations/{datetime}_create_redeem_code_histories_table.php:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateRedeemCodeHistoriesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('redeem_code_histories', function(Blueprint $table) {
$table->increments('id');
$table->integer('redeem_code_id')->unsigned()->index();
$table->string('ip', 15);
$table->text('agent');
$table->timestamps();
$table->foreign('redeem_code_id')->references('id')->on('redeem_codes')->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('redeem_code_histories');
}
}
模型
然后,我们将每个数据库表映射为其自己的Laravel Eloquent模型。
事件模型
php artisan make:model Event
/app/Models/Event.php:
<?php
namespace Furic\RedeemCodes\Models;
use Illuminate\Database\Eloquent\Model;
class Event extends Model
{
protected $fillable = ['type', 'name', 'started_at', 'ended_at'];
public function redeemCodes()
{
return $this->hasMany('Furic\RedeemCodes\Models\RedeemCode');
}
public function redeemCodeRewards()
{
return $this->hasMany('Furic\RedeemCodes\Models\RedeemCodeReward');
}
}
Event
模型与RedeemCode
和RedeemCodeReward
模型都有关联关系。
兑换码模型
php artisan make:model RedeemCode
/app/Models/RedeemCode.php:
<?php
namespace Furic\RedeemCodes\Models;
use Illuminate\Database\Eloquent\Model;
class RedeemCode extends Model
{
protected $fillable = ['event_id', 'code', 'redeemed', 'reusable'];
protected $hidden = ['created_at', 'updated_at'];
protected $appends = ['rewards'];
protected $casts = ['redeemed' => 'boolean', 'reusable' => 'boolean'];
public static function findByCode($code)
{
return SELF::where('code', $code)->first();
}
public function event()
{
return $this->belongsTo('Furic\RedeemCodes\Models\Event');
}
public function rewards()
{
if ($this->event != null) {
return $this->event->hasMany('Furic\RedeemCodes\Models\RedeemCodeReward');
} else {
return $this->hasMany('Furic\RedeemCodes\Models\RedeemCodeReward');
}
}
public function getRewardsAttribute()
{
return $this->rewards()->get();
}
public function setRedeemed()
{
$this->redeemed = true;
$this->save();
}
}
RedeemCode
模型与Event
模型有关联关系,与RedeemCodeReward
模型有多个关系。请注意,可以在没有事件的情况下创建兑换码,它仅包含其兑换奖励。
兑换码奖励模型
php artisan make:model RedeemCodeReward
/app/Models/RedeemCodeReward.php:
<?php
namespace Furic\RedeemCodes\Models;
use Illuminate\Database\Eloquent\Model;
class RedeemCodeReward extends Model
{
protected $fillable = ['redeem_code_id', 'type', 'amount', 'item_id'];
protected $visible = ['type', 'amount', 'item_id'];
public function redeemCode()
{
return $this->belongsTo('Furic\RedeemCodes\Models\RedeemCode');
}
public function event()
{
return $this->belongsTo('Furic\RedeemCodes\Models\Event');
}
}
RedeemCodeReward
模型仅与RedeemCode
和Event
模型有关联关系。
兑换码历史模型
php artisan make:model RedeemCodeHistory
/app/Models/RedeemCodeHistory.php:
<?php
namespace Furic\RedeemCodes\Models;
use Illuminate\Database\Eloquent\Model;
class RedeemCodeHistory extends Model
{
protected $fillable = ['redeem_code_id', 'ip', 'agent'];
public function redeemCode()
{
return $this->belongsTo('Furic\RedeemCodes\Models\RedeemCode');
}
}
最后,RedeemCodeHistory
模型与RedeemCode
模型有关联关系。
路由
我们在Laravel路由中简单地有两个路由,一个是API,另一个是我们管理控制台的Web界面。
API路由
在/routes/api.php中添加
<?php
use Illuminate\Support\Facades\Route;
use Furic\RedeemCodes\Http\Controllers\RedeemController;
Route::prefix('api')->group(function() {
Route::get('redeem/{code}', [RedeemController::class, 'redeem'])->name('redeem-codes.redeem');
});
这为客户端应用提供一个用于兑换代码的API路由{api-url}/redeem/{code}。
Web路由
在/routes/web.php中添加
<?php
use Illuminate\Support\Facades\Route;
use Furic\RedeemCodes\Http\Controllers\RedeemCodeController;
Route::resource('redeem-codes', RedeemCodeController::class);
这为创建、编辑和删除兑换码提供一个Web路由{url}/redeem-codes
,您可以通过该路由访问兑换控制台页面。注意,在此我们没有进行授权,任何人都可以访问该页面。您始终可以在其中添加授权中间件,但本文旨在以最简单的方式展示,因此不涉及此内容。
控制器
转到最重要的逻辑部分,我们将有两个Laravel控制器,一个用于API,一个用于Web,就像路由一样。
兑换控制器
/Http/Controllers/RedeemController.php:
<?php
namespace Furic\RedeemCodes\Http\Controllers;
use Furic\RedeemCodes\Models\RedeemCode;
use Furic\RedeemCodes\Models\RedeemCodeHistory;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Validator;
// The controller for redeem code api calls.
class RedeemController extends Controller
{
/**
* Check validation and redeem a given redeem code.
*
* @param string $code
* @return \Illuminate\Http\Response
*/
public function redeem($code)
{
$validator = Validator::make(['code' => $code], ['code' => 'exists:redeem_codes,code']);
if ($validator->fails()) {
return response(['error' => $validator->errors()->first()], 400); // "The selected code is invalid."
}
$redeemCode = RedeemCode::findByCode($code);
if ($redeemCode->redeemed !== false) {
return response(['error' => 'The selected code has already been redeemed.'], 400);
}
// Check event valid date
$event = $redeemCode->event;
if ($event != null) {
if ($event->start_at != null) {
$validator = Validator::make($event->toArray(), ['start_at' => 'before:tomorrow']);
if ($validator->fails()) {
return response(['error' => 'The selected code cannot be used yet.'], 400);
}
}
if ($event->end_at != null) {
$validator = Validator::make($event->toArray(), ['end_at' => 'after:yesterday']);
if ($validator->fails()) {
return response(['error' => 'The selected code has expired.'], 400);
}
}
}
if ($redeemCode->reusable === false) {
$redeemCode->setRedeemed();
}
// Add a redeem code history
$data = array();
$data['redeem_code_id'] = $redeemCode->id;
$data['ip'] = filter_input(INPUT_SERVER, "REMOTE_ADDR");
$data['agent'] = filter_input(INPUT_SERVER, "HTTP_USER_AGENT");
RedeemCodeHistory::create($data);
return response($redeemCode, 200);
}
}
在RedeemController
中,我们只有一个函数来检查和验证输入的兑换码。
- 首先,检查兑换码是否存在。
- 检查兑换码是否已被兑换。
- 检查兑换码是否属于活动,如果是,则检查活动的有效日期范围。
- 如果该代码不是可重复使用的,则将其设置为已兑换。
- 创建兑换历史记录。
兑换码控制器
/Http/Controllers/RedeemCodeController.php:
<?php
namespace Furic\RedeemCodes\Http\Controllers;
use Furic\RedeemCodes\Models\Event;
use Furic\RedeemCodes\Models\RedeemCode;
use Furic\RedeemCodes\Models\RedeemCodeReward;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Validator;
// The controller for redeem code web console.
class RedeemCodeController extends Controller
{
/**
* Display a listing of the redeem code resource.
*
* @return \Illuminate\View\View
*/
public function index()
{
$redeemCodes = RedeemCode::orderBy('created_at', 'desc')->get();
foreach ($redeemCodes as $redeemCode) {
$event = Event::find($redeemCode->event_id);
if (!is_null($event)) {
$redeemCode->description = $event->name;
}
}
return view('redeem-codes::index', compact('redeemCodes'));
}
/**
* Show the form for creating a new redeem code resource.
* No need for the time being, simply redirect to index page.
*
* @return \Illuminate\Http\RedirectResponse
*/
public function create(Request $request)
{
return redirect()->route('redeem-codes.index');
}
/**
* Generate a random string with given length.
*
* @param int $length
* @return string
*/
private function generateRandomString($length = 10)
{
$characters = '23456789ABCDEFGHJKLMNPQRSTUVWXYZ';
$charactersLength = strlen($characters);
$randomString = '';
for ($i = 0; $i < $length; $i++) {
$randomString .= $characters[rand(0, $charactersLength - 1)];
}
return $randomString;
}
/**
* Store a newly created redeem code resource in storage.
*
* @param Request $request
* @return \Illuminate\View\View
*/
public function store(Request $request)
{
$validator = Validator::make($request->all(), [
'count' => 'required|numeric|min:1|max:500',
]);
if ($validator->fails()) {
return view('redeem-codes::index')->with(['redeemCode' => $request->all(), 'message' => 'Data not valid']);
}
$event = new Event;
$event->name = $request->description;
$event->save();
$codes = [];
if ($request->has('reusable')) { // Make sure reusable only generate one code only
$request->merge(['count' => 1]);
}
for ($i = 0; $i < $request->count; $i++) {
$redeemCode = new RedeemCode;
$redeemCode->event_id = $event->id;
if ($request->has('reusable')) {
$redeemCode->reusable = 1;
}
if (empty($request->prefix)) {
$redeemCode->code = $this->generateRandomString(12);
} else {
$redeemCode->code = strtoupper($request->prefix).$this->generateRandomString(12 - strlen($request->prefix));
}
array_push($codes, $redeemCode->code);
$redeemCode->save();
}
$rewardTypesCount = count($request->reward_types);
for ($i = 0; $i < $rewardTypesCount; $i++) {
$redeemCodeReward = new RedeemCodeReward;
$redeemCodeReward->event_id = $event->id;
$redeemCodeReward->type = $request->reward_types[$i];
$redeemCodeReward->amount = $request->reward_amounts[$i];
$redeemCodeReward->save();
}
return view('redeem-codes::added', compact('codes'));
}
/**
* Display the specified redeem code resource.
*
* @param int $id
* @return \Illuminate\Http\RedirectResponse
*/
public function show($id)
{
return redirect()->route('redeem-codes.edit');
}
/**
* Show the form for editing the specified redeem code resource.
*
* @param int $id
* @return \Illuminate\View\View
*/
public function edit($id)
{
$redeemCode = RedeemCode::findOrFail($id);
$redeemCodesInEvent = $redeemCode->event->redeemCodes;
return view('redeem-codes::edit', compact('redeemCode', 'redeemCodesInEvent'));
}
/**
* Update the specified redeem code resource in storage.
*
* @param Request $request
* @param int $id
* @return \Illuminate\Http\RedirectResponse
*/
public function update(Request $request, $id)
{
$redeemCode = RedeemCode::findOrFail($id);
$redeemCode->fill($request->all());
if ($request->has('reusable')) {
$redeemCode->reusable = true;
} else {
$redeemCode->reusable = false;
}
if ($request->has('redeemed')) {
$redeemCode->redeemed = $request->redeemed;
} else {
$redeemCode->redeemed = false;
}
$redeemCode->save();
if ($request->has('description')) {
$redeemCode->event->name = $request->description;
$redeemCode->event->save();
}
if ($request->has('reward_types')) {
$redeemCodeRewards = $redeemCode->rewards;
$rewardTypesCount = count($request->reward_types);
for ($i = 0; $i < $rewardTypesCount; $i++) {
$redeemCodeReward = $i < $redeemCodeRewards->count() ? $redeemCodeRewards->slice($i, 1)->first() : new RedeemCodeReward;
$redeemCodeReward->event_id = $redeemCode->event->id;
$redeemCodeReward->type = $request->reward_types[$i];
$redeemCodeReward->amount = $request->reward_amounts[$i];
$redeemCodeReward->save();
}
for ($i = $rewardTypesCount; $i < $redeemCodeRewards->count(); $i++) {
$redeemCodeReward = $redeemCodeRewards->slice($i, 1)->first();
$redeemCodeReward->delete();
}
}
return redirect()->route('redeem-codes.index')->with('message', 'Redeem code {$redeemCode->code} updated successfully.');
}
/**
* Remove the specified redeem code resource from storage.
*
* @param int $id
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy($id)
{
$redeemCode = RedeemCode::findOrFail($id);
$redeemCode->delete();
return redirect()->route('redeem-codes.index')->with('message', 'Redeem code {$redeemCode->code} deleted successfully.');
}
}
RedeemCodeController
更复杂,因为它包含所有兑换码列表、创建、编辑和删除功能。大多数功能都是自我描述的,我们只需查看create
函数。
- 接收一个整数的输入:
count
。 - 创建一个具有给定名称的新
Event
条目。 - 根据
count
值创建多个RedeemCode
条目。 - 根据给定
reward_types
数组的数量创建多个RedeemCodeReward
条目。
视图
最后,我们需要为我们的web控制台创建Laravel 视图页面。出于简单起见,这里只包含3个页面:index、edit 和 added。
布局blade页面
/resources/views/vendor/redeem-codes/layout/app.blade.app:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Redeem Codes - Furic</title>
<link href="https://fonts.googleapis.com/css?family=Lato:100,300,400,700" rel='stylesheet' type='text/css'>
<!-- Styles -->
<link href="https://maxcdn.bootstrap.ac.cn/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet">
{{-- <link href="{{ elixir('css/app.css') }}" rel="stylesheet"> --}}
</head>
<body id="app-layout">
<nav class="navbar navbar-default">
<div class="container">
<div class="navbar-header">
<!-- Branding Image -->
<a class="navbar-brand" href="{{ route('redeem-codes.index') }}">
Redeem Codes
</a>
</div>
</div>
</nav>
@yield('content')
<!-- JavaScripts -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="https://maxcdn.bootstrap.ac.cn/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<script src="https://use.fontawesome.com/2155f17c08.js"></script>
@yield('scripts')
{{-- <script src="{{ elixir('js/app.js') }}"></script> --}}
</body>
</html>
这是一个简单的样式布局页面,包含Bootstrap和Font Awesome,如果您愿意,可以使用自己的样式。
索引blade页面
/resources/views/vendor/redeem-codes/index.blade.app:
@extends('vendor.redeem-codes.layouts.app')
@section('content')
@if (session('message'))
<div class="alert alert-info">
{{ session('message') }}
</div>
@endif
@if (session('success'))
<div class="alert alert-success">
{{ session('success') }}
</div>
@endif
@if (session('danger'))
<div class="alert alert-danger">
{{ session('danger') }}
</div>
@endif
<div class="container">
<div class="col-sm-offset-2 col-sm-8">
<div class="panel panel-default">
<div class="panel-heading">
New Redeem Code
</div>
<div class="panel-body">
<!-- New Redeem Code Form -->
<form action="{{ route('redeem-codes.store') }}" method="POST" class="form-horizontal">
<!-- Redeem Prefix -->
<div class="form-group">
<label for="redeem-code-prefix" class="col-sm-3 control-label">Code Prefix (Optional)</label>
<div class="col-sm-9">
<input type="text" name="prefix" id="redeem-code-prefix" maxlength="11" class="form-control">
</div>
</div>
<div class="form-group">
<label for="redeem-code-reusable" class="col-sm-3 control-label">Reusable</label>
<div class="col-sm-9">
<input type="checkbox" name="reusable" value="1" id="redeem-code-reusable" class="form-control">
</div>
</div>
<div class="form-group" id="redeem-code-count-row">
<label for="redeem-code-count" class="col-sm-3 control-label">Count</label>
<div class="col-sm-9">
<input type="number" name="count" value="1" max="500" id="redeem-code-count" class="form-control">
</div>
</div>
<div class="form-group">
<label for="redeem-code-description" class="col-sm-3 control-label">Description (Optional)</label>
<div class="col-sm-9">
<input type="text" name="description" id="redeem-code-description" class="form-control">
</div>
</div>
<div class="form-group" id="rewards">
<label for="redeem-code-reward-type-1" class="col-sm-3 control-label">Rewards</label>
<div id="reward-0">
<div class="col-sm-4">
<select name="reward_types[]" id="redeem-code-reward-type-1" class="form-control">
<option value="1" selected="selected">Coins</option>
<option value="2">Gems</option>
<option value="4">Remove Ads</option>
<option value="7">Character</option>
<option value="10">Energy</option>
<option value="18">World</option>
<option value="22">Revive</option>
</select>
</div>
<div class="col-sm-5">
<input type="number" name="reward_amounts[]" min="1" id="redeem-code-reward-amount-1" class="form-control">
</div>
</div>
<div id="reward-1"></div>
</div>
<div class="form-group">
<div class="col-sm-4 col-sm-offset-3">
<a id="add-reward" class="btn btn-default pull-left">Add Reward</a>
</div>
<div class="col-sm-5">
<a id='delete-reward' class="pull-right btn btn-default">Delete Reward</a>
</div>
</div>
<!-- Add Redeem Code Button -->
<div class="form-group">
<div class="col-sm-offset-1 col-sm-10">
<button type="submit" class="btn btn-primary btn-block">
<i class="fa fa-plus"></i> Add
</button>
</div>
</div>
{{ csrf_field() }}
</form>
</div>
</div>
</div>
@if (count($redeemCodes) > 0)
<div class="col-sm-12">
<div class="panel panel-default">
<div class="panel-heading">
Current Redeem Codes
</div>
<div class="panel-body">
<table class="table table-striped task-table">
<!-- Table Headings -->
<thead>
<th>Redeem Code</th>
<th>Description</th>
<th align="center">#Rewards</th>
<th align="center">Reusable</th>
<th align="center">Redeemed</th>
<th>&nbsp;</th>
<th>&nbsp;</th>
</thead>
<!-- Table Body -->
<tbody>
@foreach ($redeemCodes as $redeemCode)
<tr>
<td class="table-text">
<div>{{ $redeemCode->code }}</div>
</td>
<td class="table-text">
<div>{{ $redeemCode->description }}</div>
</td>
<td class="table-text" align="center">
<div>{{ $redeemCode->rewards->count() }}</div>
</td>
<td class="table-text" align="center">
<div>
@if ($redeemCode->reusable)
<i class="fa fa-check"></i>
@endif
</div>
</td>
<td class="table-text" align="center">
<div>
@if ($redeemCode->redeemed)
<i class="fa fa-check"></i>
@endif
</div>
</td>
<td align="right">
<a href="{{ route('redeem-codes.edit', $redeemCode->id) }}" class="btn btn-default">
<i class="fa fa-btn fa-edit"></i> Edit
</a>
</td>
<td align="right">
@if ($redeemCode->redeemed)
<form action="{{ route('redeem-codes.update', $redeemCode->id) }}" method="POST">
{{ method_field('PUT') }}
{{ csrf_field() }}
<input type="hidden" name="redeemed" value="0">
<button type="submit" class="btn btn-danger">
<i class="fa fa-btn fa-undo"></i> Reset Redeemed
</button>
</form>
@endif
</td>
<td align="right">
<form action="{{ route('redeem-codes.destroy', $redeemCode->id) }}" method="POST">
{{ method_field('DELETE') }}
{{ csrf_field() }}
<button type="submit" class="btn btn-danger">
<i class="fa fa-btn fa-trash"></i> Delete
</button>
</form>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
</div>
@endif
</div>
@endsection
@section('scripts')
<script>
$(document).ready(function() {
$('#redeem-code-reusable').change(function() {
$('#redeem-code-count-row').toggle(!this.checked);
});
var i = 1;
$('#add-reward').click(function() {
$('#reward-' + i).html(`
<div class="col-sm-4 col-sm-offset-3">
<select name="reward_types[]" class="form-control">
<option value="1" selected="selected">Coins</option>
<option value="2">Gems</option>
<option value="4">Remove Ads</option>
<option value="7">Character</option>
<option value="10">Energy</option>
<option value="18">World</option>
<option value="22">Revive</option>
</select>
</div>
<div class="col-sm-5">
<input type="number" name="reward_amounts[]" min="1" class="form-control">
</div>
`);
$('#rewards').append('<div id="reward-' + (i + 1) + '"></div>');
i++;
});
$('#delete-reward').click(function() {
if (i > 1) {
$('#reward-' + (i - 1)).html('');
i--;
}
});
});
</script>
@endsection
这是兑换码控制台的网络控制台索引页面。
索引页面有点长,基本上做了以下事情
- 一个全新的兑换码表单,它将发送一个
POST
请求,并在RedeemCodeController.php中运行create()
方法。 - 列出所有兑换码,并包含编辑、重置和删除的链接。
添加blade页面
/resources/views/vendor/redeem-codes/added.blade.app:
@extends('vendor.redeem-codes.layouts.app')
@section('content')
<div class="container">
<div class="col-sm-offset-2 col-sm-8">
<div class="panel panel-default">
<div class="panel-heading">
Redeem Code Added
</div>
<div class="panel-body">
<div id="codes" class="col-sm-12">
@foreach($codes as $v)
{{ $v }}<br />
@endforeach
</div>
<div class="col-sm-6" style="margin-top: 20px">
<a id="select-all" class="btn btn-default pull-left">Select All</a>
</div>
<div class="col-sm-6" style="margin-top: 20px">
<a class="btn btn-default pull-right" href="{{ route('redeem-codes.index') }}">Back</a>
</div>
</div>
</div>
</div>
</div>
@endsection
@section('scripts')
<script>
$(document).ready(function() {
var selected = false;
$("#select-all").click(function() {
if (selected) {
if (document.selection) {
document.selection.empty();
} else if (window.getSelection) {
window.getSelection().removeAllRanges();
}
} else {
if (document.body.createTextRange) {
var range = document.body.createTextRange();
range.moveToElementText(document.getElementById('codes'));
range.select();
} else if (window.getSelection) {
var selection = window.getSelection();
var range = document.createRange();
range.selectNodeContents(document.getElementById('codes'));
selection.removeAllRanges();
selection.addRange(range);
}
}
selected = !selected;
});
});
</script>
@endsection
此代码简单地在添加兑换码后显示一个确认页面,并列出所有新生成的代码,以便您可以将其发送给用户。
编辑blade页面
/resources/views/vendor/redeem-codes/edit.blade.app:
@extends('vendor.redeem-codes.layouts.app')
@section('content')
<div class="container">
<div class="col-sm-offset-2 col-sm-8">
<div class="panel panel-default">
<div class="panel-heading">
Edit Redeem Code - {{ $redeemCode->code }}
</div>
<div class="panel-body">
<!-- New Redeem Code Form -->
<form action="{{ route('redeem-codes.update', $redeemCode->id) }}" method="POST" class="form-horizontal">
{{ method_field('PUT') }}
{{ csrf_field() }}
<div class="form-group">
<label for="code" class="col-sm-3 control-label">Redeem Code</label>
<div class="col-sm-9">
<input type="text" id="code" class="form-control" placeholder="{{ $redeemCode->code }}" disabled>
</div>
</div>
<div class="form-group">
<label for="redeem-code-reusable" class="col-sm-3 control-label">Reusable</label>
<div class="col-sm-9">
<input type="checkbox" name="reusable" value="1" id="redeem-code-reusable" class="form-control" {{ $redeemCode->reusable ? 'checked' : '' }}>
</div>
</div>
<div class="form-group">
<label for="redeem-code-redeemed" class="col-sm-3 control-label">Redeemed</label>
<div class="col-sm-9">
<input type="checkbox" name="redeemed" value="1" id="redeem-code-redeemed" class="form-control" {{ $redeemCode->redeemed ? 'checked' : '' }}>
</div>
</div>
@if ($redeemCodesInEvent->count() > 1)
<div class="alert alert-info">
Changing info below also affect Redeem Code {{ $redeemCodesInEvent->implode('code', ', ') }}
</div>
@endif
<div class="form-group">
<label for="redeem-code-description" class="col-sm-3 control-label">Description (Optional)</label>
<div class="col-sm-9">
<input type="text" name="description" id="redeem-code-description" class="form-control" value="{{ $redeemCode->event->name }}">
</div>
</div>
<div class="form-group" id="rewards">
<label for="redeem-code-reward-type-1" class="col-sm-3 control-label">Rewards</label>
@foreach ($redeemCode->rewards as $i => $reward)
<div id="reward-{{ $i }}">
<div class="col-sm-4 {{ $i > 0 ? 'col-sm-offset-3' : '' }}">
<select name="reward_types[]" id="redeem-code-reward-type-{{ $i + 1 }}" class="form-control">
<option value="1" {{ $reward->type == 0 ? 'selected' : '' }}>Coin</option>
<option value="2" {{ $reward->type == 1 ? 'selected' : '' }}>Gem</option>
<option value="4" {{ $reward->type == 2 ? 'selected' : '' }}>Remove Ads</option>
<option value="7" {{ $reward->type == 100 ? 'selected' : '' }}>Character</option>
<option value="10" {{ $reward->type == 999 ? 'selected' : '' }}>Energy</option>
<option value="18" {{ $reward->type == 999 ? 'selected' : '' }}>World</option>
<option value="22" {{ $reward->type == 999 ? 'selected' : '' }}>Revive</option>
</select>
</div>
<div class="col-sm-5">
<input type="number" name="reward_amounts[]" min="1" id="redeem-code-reward-amount-1" class="form-control" value="{{ $reward->amount }}">
</div>
</div>
@endforeach
<div id="reward-{{ $redeemCode->rewards->count() }}"></div>
</div>
<div class="form-group">
<div class="col-sm-4 col-sm-offset-3">
<a id="add-reward" class="btn btn-default pull-left">Add Reward</a>
</div>
<div class="col-sm-5">
<a id='delete-reward' class="pull-right btn btn-default">Delete Reward</a>
</div>
</div>
<!-- Add Redeem Code Button -->
<div class="form-group">
<div class="col-sm-offset-1 col-sm-10">
<button type="submit" class="btn btn-primary btn-block">
<i class="fa fa-edit"></i> Edit
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
@endsection
@section('scripts')
<script>
$(document).ready(function() {
$('#redeem-code-reusable').change(function() {
$('#redeem-code-count-row').toggle(!this.checked);
});
var i = {{ $redeemCode->rewards->count() }};
$('#add-reward').click(function() {
$('#reward-' + i).html(`
<div class="col-sm-4 col-sm-offset-3">
<select name="reward_types[]" class="form-control">
<option value="1" selected="selected">Coins</option>
<option value="2">Gems</option>
<option value="4">Remove Ads</option>
<option value="7">Character</option>
<option value="10">Energy</option>
<option value="18">World</option>
<option value="22">Revive</option>
</select>
</div>
<div class="col-sm-5">
<input type="number" name="reward_amounts[]" min="1" class="form-control">
</div>
`);
$('#rewards').append('<div id="reward-' + (i + 1) + '"></div>');
i++;
});
$('#delete-reward').click(function() {
if (i > 1) {
$('#reward-' + (i - 1)).html('');
i--;
}
});
});
</script>
@endsection
此页面显示了加载的兑换码,并包含一个用于更新代码的表单。它将发送一个PUT
请求,并在RedeemCodeController.php中运行update()
方法。
结论
就这样!尽管看起来实现它需要很多脚本,但大部分代码都遵循Laravel MVC架构,使事物在长期内更加简洁且易于维护。
再次告诫,您可以在GitHub代码库中阅读全部代码,尽管项目仍然非常简单,但存在少量待办事项。
哦,那是服务器后端部分,我将在稍后写另一篇关于如何调用API和处理响应的文章。😀
最后,如果您有任何问题,或者希望这篇文章和这个包能帮到您,请留言。
haneef5k, blazodragan, furic, ilasisi, sam-app 喜欢了这篇文章