优化 后台等级设置

This commit is contained in:
2026-04-26 20:37:23 +08:00
parent e69bceeb77
commit b07f4e971a
13 changed files with 753 additions and 14 deletions
@@ -61,6 +61,8 @@ class AdminDashboardControllerTest extends TestCase
$response->assertOk();
$response->assertSee('当前在线人数');
$response->assertSee('2');
$response->assertDontSee('队列监控面板');
$response->assertDontSee('打开 Horizon 控制台');
}
/**
@@ -0,0 +1,167 @@
<?php
/**
* 文件功能:后台等级经验阈值配置页测试
*
* 覆盖独立菜单页的展示、保存与非法阈值拦截,
* 确保 levelexp 已从通用系统参数页中拆分出来单独维护。
*/
namespace Tests\Feature\Feature;
use App\Models\Sysparam;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
/**
* 类功能:验证后台等级经验阈值独立配置页的核心行为。
*/
class AdminLevelExpConfigControllerTest extends TestCase
{
use RefreshDatabase;
/**
* 方法功能:验证独立配置页会按列表模式展示每一级阈值。
*/
public function test_level_exp_index_displays_threshold_rows(): void
{
$this->seedLevelExpParam();
$admin = $this->createSuperAdmin();
$response = $this->actingAs($admin)->get(route('admin.level-exp-configs.index'));
$response->assertOk();
$response->assertSee('等级经验阈值管理');
$response->assertSee('第 1 级');
$response->assertSee('第 3 级');
$response->assertSee('10');
$response->assertSee('150');
$response->assertSee('最高可配置到 99 级');
}
/**
* 方法功能:验证独立配置页可保存新的等级经验阈值。
*/
public function test_level_exp_update_persists_thresholds(): void
{
$this->seedLevelExpParam();
$admin = $this->createSuperAdmin();
$response = $this->actingAs($admin)->put(route('admin.level-exp-configs.update'), [
'thresholds' => ['20', '80', '180', '360'],
]);
$response->assertRedirect(route('admin.level-exp-configs.index'));
$response->assertSessionHas('success');
$this->assertDatabaseHas('sysparam', [
'alias' => 'levelexp',
'body' => '20,80,180,360',
]);
$this->assertDatabaseHas('sysparam', [
'alias' => 'maxlevel',
'body' => '99',
]);
$this->assertDatabaseHas('sysparam', [
'alias' => 'superlevel',
'body' => '100',
]);
}
/**
* 方法功能:验证阈值必须严格递增,防止错误配置写入。
*/
public function test_level_exp_update_requires_strictly_increasing_thresholds(): void
{
$this->seedLevelExpParam();
$admin = $this->createSuperAdmin();
$response = $this->from(route('admin.level-exp-configs.index'))
->actingAs($admin)
->put(route('admin.level-exp-configs.update'), [
'thresholds' => ['20', '18', '100'],
]);
$response->assertRedirect(route('admin.level-exp-configs.index'));
$response->assertSessionHasErrors('thresholds');
$this->assertDatabaseHas('sysparam', [
'alias' => 'levelexp',
'body' => '10,50,150',
]);
}
/**
* 方法功能:验证等级数量不能超过用户最高可达等级。
*/
public function test_level_exp_update_requires_threshold_count_not_exceed_maxlevel(): void
{
$this->seedLevelExpParam();
Sysparam::updateOrCreate(
['alias' => 'maxlevel'],
['body' => '2', 'guidetxt' => '用户最高可达等级']
);
$admin = $this->createSuperAdmin();
$response = $this->from(route('admin.level-exp-configs.index'))
->actingAs($admin)
->put(route('admin.level-exp-configs.update'), [
'thresholds' => ['20', '80', '180'],
]);
$response->assertRedirect(route('admin.level-exp-configs.index'));
$response->assertSessionHasErrors('thresholds');
$this->assertDatabaseHas('sysparam', [
'alias' => 'levelexp',
'body' => '10,50,150',
]);
$this->assertDatabaseHas('sysparam', [
'alias' => 'maxlevel',
'body' => '2',
]);
$this->assertDatabaseHas('sysparam', [
'alias' => 'superlevel',
'body' => '100',
]);
}
/**
* 方法功能:创建可访问后台页面的超级管理员。
*/
private function createSuperAdmin(): User
{
return User::factory()->create([
'user_level' => 100,
]);
}
/**
* 方法功能:初始化等级经验阈值参数。
*/
private function seedLevelExpParam(): void
{
$rows = [
'levelexp' => [
'body' => '10,50,150',
'guidetxt' => '按列表逐级维护升级所需的累计经验阈值',
],
'maxlevel' => [
'body' => '99',
'guidetxt' => '用户最高可达等级',
],
'superlevel' => [
'body' => '100',
'guidetxt' => '管理员级别(= 最高等级 + 1,拥有最高权限的等级阈值)',
],
];
foreach ($rows as $alias => $payload) {
Sysparam::updateOrCreate(
['alias' => $alias],
$payload
);
}
}
}
@@ -0,0 +1,45 @@
<?php
/**
* 文件功能:运维工具页面展示测试
*
* 覆盖运维工具页中 Horizon 控制台入口的展示,
* 并验证该入口已从后台仪表盘迁移到运维工具页面。
*
* @author ChatRoom Laravel
*
* @version 1.0.0
*/
namespace Tests\Feature\Feature;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
/**
* 类功能:验证运维工具页面的核心展示内容。
*/
class AdminOpsControllerTest extends TestCase
{
use RefreshDatabase;
/**
* 方法功能:验证运维工具页会展示 Horizon 控制台入口。
*/
public function test_ops_page_displays_horizon_console_entry(): void
{
$siteOwner = User::factory()->create([
'id' => 1,
'username' => 'site-owner',
'user_level' => 100,
]);
$response = $this->actingAs($siteOwner)->get(route('admin.ops.index'));
$response->assertOk();
$response->assertSee('队列监控面板');
$response->assertSee('打开 Horizon 控制台');
$response->assertSee('/horizon');
}
}
@@ -38,6 +38,9 @@ class AdminSystemControllerTest extends TestCase
$response->assertDontSee('vip_payment_app_secret');
$response->assertDontSee('wechat_bot_config');
$response->assertDontSee('chatbot_max_gold');
$response->assertDontSee('levelexp');
$response->assertSee('maxlevel');
$response->assertSee('superlevel');
}
/**
@@ -51,6 +54,9 @@ class AdminSystemControllerTest extends TestCase
$response = $this->actingAs($admin)->put(route('admin.system.update'), [
'sys_name' => '新版聊天室',
'sys_notice' => '新的公共公告',
'levelexp' => '20,80,180',
'maxlevel' => '88',
'superlevel' => '666',
'smtp_host' => 'attacker.smtp.example',
'vip_payment_app_secret' => 'tampered-secret',
'wechat_bot_config' => '{"api":{"bot_key":"stolen"}}',
@@ -69,6 +75,18 @@ class AdminSystemControllerTest extends TestCase
'alias' => 'sys_notice',
'body' => '新的公共公告',
]);
$this->assertDatabaseHas('sysparam', [
'alias' => 'levelexp',
'body' => '10,50,150',
]);
$this->assertDatabaseHas('sysparam', [
'alias' => 'maxlevel',
'body' => '88',
]);
$this->assertDatabaseHas('sysparam', [
'alias' => 'superlevel',
'body' => '89',
]);
// 敏感配置必须保持原值,不能被通用系统页伪造请求覆盖。
$this->assertDatabaseHas('sysparam', [
@@ -128,6 +146,9 @@ class AdminSystemControllerTest extends TestCase
return [
'sys_name' => '原始聊天室',
'sys_notice' => '原始公告',
'levelexp' => '10,50,150',
'maxlevel' => '99',
'superlevel' => '100',
'smtp_host' => 'owner.smtp.example',
'vip_payment_app_secret' => 'owner-secret',
'wechat_bot_config' => '{"api":{"bot_key":"owner-only"}}',