修复 Bug, 增加流量激活码

This commit is contained in:
cyq 2023-10-02 23:30:58 +08:00
parent 6919487fe8
commit fa8732e548
16 changed files with 294 additions and 10 deletions

1
.gitignore vendored
View File

@ -17,3 +17,4 @@ yarn-error.log
/.idea
/.vscode
.DS_Store
/project

View File

@ -0,0 +1,71 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Models\TrafficActivateCode;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Illuminate\View\View;
class TrafficActivateCodeController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index()
{
$codes = TrafficActivateCode::all();
$count = $codes->count();
return view('admin.codes.index', ['codes' => $codes, 'count' => $count]);
}
/**
* Show the form for creating a new resource.
*/
public function create(): View
{
return view('admin.codes.create');
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
$amount = $request->input('amount');
$traffic = $request->input('traffic');
$codes = $this->generate_key($amount);
foreach ($codes as $code) {
TrafficActivateCode::create([
'code' => $code,
'traffic' => $traffic,
]);
}
return view('admin.codes.show', compact('codes'));
}
private function generate_key($count): array
{
$codes = [];
for ($i = 0; $i < $count; $i++) {
$code = Str::random(25);
$code = strtoupper($code);
$formattedCode = preg_replace('/(\w{5})(\w{5})(\w{5})(\w{5})(\w{5})/', '$1-$2-$3-$4-$5', $code);
$codes[] = $formattedCode;
}
return $codes;
}
/**
* Remove the specified resource from storage.
*/
public function destroy(TrafficActivateCode $code)
{
$code->delete();
return back()->with('success', '删除成功');
}
}

View File

@ -18,7 +18,6 @@ class UserController extends Controller
public function index(Request $request)
{
$users = new User();
$count = User::count();
foreach ($request->except(['page']) as $key => $value) {
if (empty($value)) {

View File

@ -0,0 +1,33 @@
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\TrafficActivateCode;
use App\Models\User;
use Illuminate\Http\Request;
class TrafficActivateCodeController extends Controller
{
public function useActivateCode(Request $request)
{
$request->validate([
'code' => 'required|string'
]);
$code = $request->post('code');
$trafficActivateCode = TrafficActivateCode::where('code', $code)->first();
if ($trafficActivateCode == null) {
return $this->error('激活码错误');
}
if ($trafficActivateCode->used_at != null) {
return $this->error('激活码已被使用');
}
$trafficActivateCode->user_id = $request->user()->id;
$trafficActivateCode->used_at = now();
$trafficActivateCode->update();
$user = User::find($request->user()->id);
$user->traffic += $trafficActivateCode->traffic;
$user->update();
return $this->success('激活成功');
}
}

View File

@ -0,0 +1,28 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class TrafficActivateCode extends Model
{
use HasFactory;
protected $fillable = [
'code',
'traffic',
'user_id',
];
protected $casts = [
'used_at' => 'datetime',
];
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
}

View File

@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('traffic_activate_codes', function (Blueprint $table) {
$table->id();
$table->string('code')->index()->unique();
$table->bigInteger('traffic')->index();
$table->dateTime('used_at')->nullable();
$table->unsignedBigInteger('user_id')->nullable()->index();
$table->foreign('user_id')->references('id')->on('users')->nullOnDelete();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('traffic_activate_codes');
}
};

View File

@ -45,7 +45,7 @@ const items = ref([
route: "tunnels.create",
},
{
name: "签到",
name: "流量补给",
route: "sign",
},
{

View File

@ -17,27 +17,36 @@
</div>
</div>
<div class="mt-4">
<h3>兑换流量激活码</h3>
<div class="input-group mt-3">
<input v-model="activate_code" class="form-control" type="text">
<button class="btn btn-primary" @click="exchange">兑换</button>
</div>
</div>
<button
type="button"
class="btn btn-primary"
style="display: none"
id="signinButton"
class="btn btn-primary"
data-bs-target="#signinModal"
data-bs-toggle="modal"
data-bs-target="#signinModal">
style="display: none"
type="button">
</button>
<div class="modal fade" id="signinModal" tabindex="-1" aria-labelledby="signinModalLabel" aria-hidden="true">
<div id="signinModal" aria-hidden="true" aria-labelledby="signinModalLabel" class="modal fade" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="signinModalLabel">签到</h1>
<h1 id="signinModalLabel" class="modal-title fs-5">签到</h1>
</div>
<div class="modal-body">
签到成功{{ content }}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-bs-dismiss="modal">确定</button>
<button class="btn btn-primary" data-bs-dismiss="modal" type="button">确定</button>
</div>
</div>
</div>
@ -61,6 +70,7 @@ const traffic = ref({
});
const theme = ref("")
const activate_code = ref("")
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
theme.value = "dark"
@ -101,6 +111,21 @@ function sign(captcha_token) {
});
}
function exchange() {
http.post('/codes/use', {
'code': activate_code.value
}).then(res => {
alert(res.data.message)
}).catch(res => {
alert(res.data.message)
}).finally(() => {
http.get("user")
.then((res) => {
traffic.value.traffic = res.data.traffic;
})
})
}
// function refreshSign() {
// const date = new Date(traffic.value.last_sign_at)
//

View File

@ -0,0 +1,13 @@
<x-app-layout>
<h3 class="mb-3">创建流量激活码</h3>
<form action="{{ route('admin.codes.store') }}" method="post">
@csrf
<label for="name" class="form-label">数量</label>
<input type="number" name="amount" id="amount" placeholder="数量" class="form-control mb-3" required>
<label for="name" class="form-label">流量</label>
<input type="number" name="traffic" id="traffic" placeholder="流量 (GB)" class="form-control mb-3" required>
<button class="btn btn-primary" type="submit">创建</button>
</form>
</x-app-layout>

View File

@ -0,0 +1,20 @@
<x-app-layout>
<h3 class="mb-3">编辑客户端</h3>
<form action="{{ route('admin.clients.update', $client->id) }}" method="post">
@csrf
@method('PUT')
<label for="name" class="form-label">名称</label>
<input type="text" name="name" id="name" placeholder="名称" class="form-control mb-3" required
value="{{ $client->name }}">
<label for="name" class="form-label">架构</label>
<input type="text" name="arch" id="arch" placeholder="架构" class="form-control mb-3" required
value="{{ $client->arch }}">
<label for="name" class="form-label">下载链接</label>
<input type="text" name="url" id="url" placeholder="下载链接" class="form-control mb-3" required
value="{{ $client->url }}">
<button class="btn btn-primary" type="submit">保存更改</button>
</form>
</x-app-layout>

View File

@ -0,0 +1,45 @@
<x-app-layout>
<h3>流量激活码</h3>
<a href="{{ route('admin.codes.create') }}">新建激活码</a>
<div class="alert alert-primary mt-3" role="alert">
总计: {{ $count }}
</div>
<table class="mt-3 table table-hover text-center table-bordered" style="vertical-align: middle">
<thead>
<tr>
<th>ID</th>
<th>激活码</th>
<th>流量</th>
<th>使用用户</th>
<th>操作</th>
</tr>
</thead>
<tbody>
@foreach ($codes as $code)
<tr>
<td>{{ $code->id }}</td>
<td>{{ $code->code }}</td>
<td>{{ $code->traffic }}</td>
<td>
@isset($code->user_id)
{{ $code->user->name }} # {{ $code->user_id }}
@endisset
</td>
<td>
<form action="{{ route('admin.codes.destroy', ['code' => $code]) }}" method="POST"
onsubmit="return confirm('真的要删除吗?')">
@csrf
@method('DELETE')
<button type="submit" class="btn btn-sm btn-danger">删除</button>
</form>
</td>
</tr>
@endforeach
</tbody>
</table>
</x-app-layout>

View File

@ -0,0 +1,8 @@
<x-app-layout>
<h3 class="mb-3">流量激活码生成详情</h3>
<textarea class="form-control" id="code" rows="10" readonly>
@foreach($codes as $code)
{{ $code }}
@endforeach
</textarea>
</x-app-layout>

View File

@ -86,7 +86,7 @@
<td>{{ $host->created_at }}</td>
<td>{{ $host->updated_at }}</td>
<td>
<a href="{{ route('admin.tunnels.show', ['tunnel' => $host]) }}"
<a href="{{ route('admin.tunnels.show', ['host' => $host]) }}"
class="btn btn-sm btn-primary">编辑</a>
&nbsp;
<form action="{{ route('admin.tunnels.destroy', ['tunnel' => $host]) }}" method="POST"

View File

@ -42,6 +42,9 @@
<li class="nav-item">
<a class="nav-link" href="{{ route('admin.clients.index') }}">客户端</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ route('admin.codes.index') }}">流量激活码</a>
</li>
</ul>
<ul class="navbar-nav ml-auto mb-2 mb-lg-0">
<li class="nav-item">

View File

@ -5,6 +5,7 @@
use App\Http\Controllers\Admin\ServerController;
use App\Http\Controllers\Admin\UserController;
use App\Http\Controllers\Admin\ClientController;
use App\Http\Controllers\Admin\TrafficActivateCodeController;
use Illuminate\Support\Facades\Route;
Route::withoutMiddleware('auth:admin')->group(function() {
@ -20,6 +21,9 @@
Route::resource('servers', ServerController::class);
Route::resource('tunnels', TunnelController::class);
Route::resource('clients', ClientController::class);
Route::resource('codes', TrafficActivateCodeController::class)->except([
'show', 'edit', 'update'
]);
Route::get('/logout', [IndexController::class, 'logout'])->name('logout');

View File

@ -10,6 +10,7 @@
use App\Http\Controllers\Application\UserController as ApplicationUserController;
use App\Http\Controllers\Api\ClientController;
use App\Http\Controllers\Review\ReviewController;
use App\Http\Controllers\Api\TrafficActivateCodeController;
Route::prefix('tunnel')->name('api.tunnel.')->group(function () {
Route::post('/handler/{key}', [PortManagerController::class, 'handler'])->name('handler');
@ -29,6 +30,7 @@
Route::apiResource('servers', ServerController::class);
Route::apiResource('clients', ClientController::class);
Route::post('codes/use', [TrafficActivateCodeController::class, 'useActivateCode'])->name('codes.useActivateCode');
Route::get('traffic', [TrafficController::class, 'free']);
Route::post('traffic', [TrafficController::class, 'sign']);