feat(api): 新增节点月流量限额强制下线

新增节点级月流量限额配置、重置调度和运行状态持久化
下发 traffic_limit 给 mi-node,并在超额后停止内核、到期后恢复
管理端支持编辑限额参数并展示额度进度、状态和下次重置
手动与定时重置会同步清理限额状态并通知节点刷新配置
This commit is contained in:
yinjianm
2026-04-29 00:46:12 +08:00
parent 52529d1f58
commit 922e86070d
26 changed files with 1127 additions and 11 deletions
@@ -0,0 +1,90 @@
<?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::table('v2_server', function (Blueprint $table) {
if (!Schema::hasColumn('v2_server', 'traffic_limit_enabled')) {
$table->boolean('traffic_limit_enabled')
->default(false)
->after('transfer_enable')
->comment('Enable node traffic limit enforcement');
}
if (!Schema::hasColumn('v2_server', 'traffic_limit_reset_day')) {
$table->unsignedTinyInteger('traffic_limit_reset_day')
->nullable()
->after('traffic_limit_enabled')
->comment('Monthly reset day, 1-31');
}
if (!Schema::hasColumn('v2_server', 'traffic_limit_reset_time')) {
$table->string('traffic_limit_reset_time', 5)
->nullable()
->after('traffic_limit_reset_day')
->comment('Monthly reset time in HH:mm');
}
if (!Schema::hasColumn('v2_server', 'traffic_limit_timezone')) {
$table->string('traffic_limit_timezone', 64)
->nullable()
->after('traffic_limit_reset_time')
->comment('Timezone used for node traffic reset');
}
if (!Schema::hasColumn('v2_server', 'traffic_limit_status')) {
$table->string('traffic_limit_status', 32)
->nullable()
->after('traffic_limit_timezone')
->comment('Runtime status reported by node traffic limiter');
}
if (!Schema::hasColumn('v2_server', 'traffic_limit_last_reset_at')) {
$table->unsignedBigInteger('traffic_limit_last_reset_at')
->nullable()
->after('traffic_limit_status')
->comment('Last node traffic reset timestamp');
}
if (!Schema::hasColumn('v2_server', 'traffic_limit_next_reset_at')) {
$table->unsignedBigInteger('traffic_limit_next_reset_at')
->nullable()
->after('traffic_limit_last_reset_at')
->comment('Next node traffic reset timestamp');
}
if (!Schema::hasColumn('v2_server', 'traffic_limit_suspended_at')) {
$table->unsignedBigInteger('traffic_limit_suspended_at')
->nullable()
->after('traffic_limit_next_reset_at')
->comment('Timestamp when node was suspended by traffic limit');
}
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('v2_server', function (Blueprint $table) {
$columns = [
'traffic_limit_enabled',
'traffic_limit_reset_day',
'traffic_limit_reset_time',
'traffic_limit_timezone',
'traffic_limit_status',
'traffic_limit_last_reset_at',
'traffic_limit_next_reset_at',
'traffic_limit_suspended_at',
];
foreach ($columns as $column) {
if (Schema::hasColumn('v2_server', $column)) {
$table->dropColumn($column);
}
}
});
}
};