feat: refactor super admin to use is_super_admin flag and enhance site deletion logic

- Changed super admin detection from role-based to `is_super_admin` flag in AdminUser model
- Added `requireDefaultAdminSiteId()` method to throw validation error when no integration site exists
- Enhanced site deletion to migrate platform role bindings to fallback site and auto-delete site-specific admin accounts
- Made agent line code optional with auto-generation fallback using `{site_code}-agent-{counter}` format
This commit is contained in:
2026-06-12 20:47:40 +08:00
parent 980f3c9593
commit 395e1c7400
36 changed files with 1193 additions and 153 deletions

View File

@@ -0,0 +1,67 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('admin_users', function (Blueprint $table): void {
$table->boolean('is_super_admin')->default(false)->after('status');
});
$superRoleId = DB::table('admin_roles')->where('slug', 'super_admin')->value('id');
if ($superRoleId !== null) {
$superUserIds = DB::table('admin_user_site_roles')
->where('role_id', $superRoleId)
->distinct()
->pluck('admin_user_id');
foreach ($superUserIds as $userId) {
DB::table('admin_users')
->where('id', $userId)
->update(['is_super_admin' => true]);
}
DB::table('admin_user_site_roles')
->where('role_id', $superRoleId)
->delete();
}
// 仅允许一名超管:若历史数据误绑多名,保留最小 id。
$superAdminIds = DB::table('admin_users')
->where('is_super_admin', true)
->orderBy('id')
->pluck('id');
if ($superAdminIds->count() > 1) {
$keepId = (int) $superAdminIds->first();
DB::table('admin_users')
->where('is_super_admin', true)
->where('id', '!=', $keepId)
->update(['is_super_admin' => false]);
}
$driver = Schema::getConnection()->getDriverName();
if ($driver === 'pgsql') {
DB::statement('CREATE UNIQUE INDEX admin_users_single_super_admin ON admin_users (is_super_admin) WHERE is_super_admin = true');
} elseif ($driver === 'sqlite') {
DB::statement('CREATE UNIQUE INDEX admin_users_single_super_admin ON admin_users (is_super_admin) WHERE is_super_admin = 1');
}
}
public function down(): void
{
$driver = Schema::getConnection()->getDriverName();
if (in_array($driver, ['pgsql', 'sqlite'], true)) {
DB::statement('DROP INDEX IF EXISTS admin_users_single_super_admin');
}
Schema::table('admin_users', function (Blueprint $table): void {
$table->dropColumn('is_super_admin');
});
}
};

View File

@@ -0,0 +1,47 @@
<?php
use App\Models\AdminRole;
use App\Support\SiteAdminDefaultRolePermissions;
use App\Support\SitePlatformRole;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
return new class extends Migration
{
public function up(): void
{
SiteAdminDefaultRolePermissions::ensurePlatformSiteAdminRole();
$platformRoleId = SitePlatformRole::id();
$legacyRoles = AdminRole::query()
->where('scope_type', AdminRole::SCOPE_SYSTEM)
->where('slug', 'like', 'site_admin_%')
->where('slug', '<>', SitePlatformRole::SLUG)
->get(['id', 'slug']);
foreach ($legacyRoles as $legacy) {
$bindings = DB::table('admin_user_site_roles')
->where('role_id', $legacy->id)
->get(['admin_user_id', 'site_id', 'granted_at']);
foreach ($bindings as $binding) {
DB::table('admin_user_site_roles')->updateOrInsert(
[
'admin_user_id' => (int) $binding->admin_user_id,
'site_id' => (int) $binding->site_id,
'role_id' => $platformRoleId,
],
['granted_at' => $binding->granted_at ?? now()],
);
}
DB::table('admin_user_site_roles')->where('role_id', $legacy->id)->delete();
AdminRole::query()->where('id', $legacy->id)->delete();
}
}
public function down(): void
{
// 不回滚 per-site 角色拆分;仅保留平台 site_admin 角色。
}
};

View File

@@ -7,6 +7,7 @@ use Illuminate\Database\Seeder;
use App\Support\AdminAgentPermissionMenuActionSync;
use App\Support\AdminDrawPermissionMenuActionSync;
use App\Support\PlatformSystemRoles;
use App\Support\SuperAdminAccount;
/**
* 后台 RBAC平台固定角色 super_admin / agent。
@@ -22,8 +23,6 @@ final class AdminRbacAndUserSeeder extends Seeder
PlatformSystemRoles::ensureAll();
$super = PlatformSystemRoles::ensureSuperAdminRole();
$username = 'admin';
AdminUser::query()->updateOrCreate(
['username' => $username],
@@ -37,13 +36,6 @@ final class AdminRbacAndUserSeeder extends Seeder
/** @var AdminUser $admin */
$admin = AdminUser::query()->where('username', $username)->firstOrFail();
$siteId = AdminUser::defaultAdminSiteId();
$superId = (int) $super->getKey();
$admin->roles()->sync([
$superId => [
'site_id' => $siteId,
'granted_at' => now(),
],
]);
SuperAdminAccount::assign($admin);
}
}