feat: 重构管理员权限管理,移除 AdminPermission 模型,整合权限与角色管理逻辑,优化 API 接口以支持角色与权限的同步,增强数据库填充器以对齐权限配置

This commit is contained in:
2026-05-13 10:40:07 +08:00
parent 3c92bef774
commit edd863764b
18 changed files with 1486 additions and 224 deletions

View File

@@ -0,0 +1,742 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
$this->createTables();
$this->seedInitialData();
$this->migrateLegacyAssignments();
$this->dropLegacyTables();
}
public function down(): void
{
$this->recreateLegacyTables();
$this->migrateBackToLegacyTables();
Schema::dropIfExists('admin_user_site_roles');
Schema::dropIfExists('admin_user_menu_actions');
Schema::dropIfExists('admin_user_data_scopes');
Schema::dropIfExists('admin_role_menu_actions');
Schema::dropIfExists('admin_role_api_resources');
Schema::dropIfExists('admin_role_menus');
Schema::dropIfExists('admin_role_data_scopes');
Schema::dropIfExists('admin_api_resource_bindings');
Schema::dropIfExists('admin_api_resources');
Schema::dropIfExists('admin_menu_actions');
Schema::dropIfExists('admin_action_catalog');
Schema::dropIfExists('admin_menus');
Schema::dropIfExists('admin_data_scopes');
Schema::dropIfExists('admin_sites');
}
private function createTables(): void
{
Schema::create('admin_sites', function (Blueprint $table): void {
$table->id();
$table->string('code', 64)->unique();
$table->string('name', 128);
$table->string('currency_code', 16)->default('NPR');
$table->unsignedTinyInteger('status')->default(1)->comment('1=enabled,0=disabled');
$table->boolean('is_default')->default(false);
$table->json('extra_json')->nullable();
$table->timestamps();
});
Schema::table('admin_roles', function (Blueprint $table): void {
$table->string('code', 64)->nullable()->after('id');
$table->text('description')->nullable()->after('name');
$table->unsignedTinyInteger('status')->default(1)->comment('1=enabled,0=disabled')->after('description');
$table->boolean('is_system')->default(false)->after('status');
$table->unsignedInteger('sort_order')->default(0)->after('is_system');
});
DB::table('admin_roles')->update([
'code' => DB::raw('slug'),
'status' => 1,
'is_system' => true,
'sort_order' => 0,
]);
Schema::table('admin_roles', function (Blueprint $table): void {
$table->string('code', 64)->nullable(false)->change();
$table->unique('code');
});
Schema::create('admin_menus', function (Blueprint $table): void {
$table->id();
$table->foreignId('parent_id')->nullable()->constrained('admin_menus')->nullOnDelete();
$table->string('menu_type', 24)->comment('directory|menu|page');
$table->string('code', 128)->unique();
$table->string('name', 128);
$table->string('path', 255)->nullable();
$table->string('route_name', 255)->nullable();
$table->string('component', 255)->nullable();
$table->string('icon', 128)->nullable();
$table->string('active_menu_code', 128)->nullable();
$table->unsignedInteger('sort_order')->default(0);
$table->boolean('is_visible')->default(true);
$table->boolean('is_cache')->default(false);
$table->boolean('is_external')->default(false);
$table->unsignedTinyInteger('status')->default(1)->comment('1=enabled,0=disabled');
$table->json('meta_json')->nullable();
$table->timestamps();
$table->index(['parent_id', 'sort_order'], 'idx_admin_menus_parent_sort');
});
Schema::create('admin_action_catalog', function (Blueprint $table): void {
$table->id();
$table->string('code', 64)->unique();
$table->string('name', 64);
$table->unsignedInteger('sort_order')->default(0);
$table->unsignedTinyInteger('status')->default(1)->comment('1=enabled,0=disabled');
$table->timestamps();
});
Schema::create('admin_menu_actions', function (Blueprint $table): void {
$table->id();
$table->foreignId('menu_id')->constrained('admin_menus')->cascadeOnDelete();
$table->foreignId('action_id')->constrained('admin_action_catalog')->cascadeOnDelete();
$table->string('permission_code', 128)->unique();
$table->string('name', 128);
$table->unsignedTinyInteger('status')->default(1)->comment('1=enabled,0=disabled');
$table->timestamps();
$table->unique(['menu_id', 'action_id'], 'uk_admin_menu_actions_menu_action');
$table->index(['menu_id', 'status'], 'idx_admin_menu_actions_menu_status');
});
Schema::create('admin_api_resources', function (Blueprint $table): void {
$table->id();
$table->string('code', 128)->unique();
$table->string('module_code', 64);
$table->string('name', 128);
$table->string('http_method', 16);
$table->string('uri_pattern', 255);
$table->string('route_name', 255)->nullable();
$table->string('auth_mode', 24)->default('permission_required')->comment('login_only|permission_required|internal_only');
$table->boolean('is_audit_required')->default(false);
$table->unsignedTinyInteger('status')->default(1)->comment('1=enabled,0=disabled');
$table->json('meta_json')->nullable();
$table->timestamps();
$table->index(['module_code', 'status'], 'idx_admin_api_resources_module_status');
});
Schema::create('admin_api_resource_bindings', function (Blueprint $table): void {
$table->id();
$table->foreignId('api_resource_id')->constrained('admin_api_resources')->cascadeOnDelete();
$table->foreignId('menu_action_id')->constrained('admin_menu_actions')->cascadeOnDelete();
$table->timestamps();
$table->unique(['api_resource_id', 'menu_action_id'], 'uk_admin_api_bindings_api_action');
});
Schema::create('admin_data_scopes', function (Blueprint $table): void {
$table->id();
$table->string('code', 64)->unique();
$table->string('name', 128);
$table->string('scope_type', 32)->comment('all_sites|site_only|site_all_data|site_single_player|self_only');
$table->string('module_code', 64)->nullable();
$table->text('description')->nullable();
$table->unsignedTinyInteger('status')->default(1)->comment('1=enabled,0=disabled');
$table->timestamps();
});
Schema::create('admin_role_menus', function (Blueprint $table): void {
$table->foreignId('role_id')->constrained('admin_roles')->cascadeOnDelete();
$table->foreignId('menu_id')->constrained('admin_menus')->cascadeOnDelete();
$table->primary(['role_id', 'menu_id']);
});
Schema::create('admin_role_menu_actions', function (Blueprint $table): void {
$table->foreignId('role_id')->constrained('admin_roles')->cascadeOnDelete();
$table->foreignId('menu_action_id')->constrained('admin_menu_actions')->cascadeOnDelete();
$table->primary(['role_id', 'menu_action_id']);
});
Schema::create('admin_role_api_resources', function (Blueprint $table): void {
$table->foreignId('role_id')->constrained('admin_roles')->cascadeOnDelete();
$table->foreignId('api_resource_id')->constrained('admin_api_resources')->cascadeOnDelete();
$table->primary(['role_id', 'api_resource_id']);
});
Schema::create('admin_role_data_scopes', function (Blueprint $table): void {
$table->id();
$table->foreignId('role_id')->constrained('admin_roles')->cascadeOnDelete();
$table->foreignId('site_id')->nullable()->constrained('admin_sites')->nullOnDelete();
$table->foreignId('data_scope_id')->constrained('admin_data_scopes')->cascadeOnDelete();
$table->string('module_code', 64)->nullable();
$table->json('constraint_json')->nullable();
$table->timestamps();
$table->unique(['role_id', 'site_id', 'data_scope_id', 'module_code'], 'uk_admin_role_data_scopes');
});
Schema::create('admin_user_site_roles', function (Blueprint $table): void {
$table->foreignId('admin_user_id')->constrained('admin_users')->cascadeOnDelete();
$table->foreignId('site_id')->constrained('admin_sites')->cascadeOnDelete();
$table->foreignId('role_id')->constrained('admin_roles')->cascadeOnDelete();
$table->timestamp('granted_at')->nullable();
$table->primary(['admin_user_id', 'site_id', 'role_id'], 'pk_admin_user_site_roles');
});
Schema::create('admin_user_menu_actions', function (Blueprint $table): void {
$table->foreignId('admin_user_id')->constrained('admin_users')->cascadeOnDelete();
$table->foreignId('site_id')->nullable()->constrained('admin_sites')->nullOnDelete();
$table->foreignId('menu_action_id')->constrained('admin_menu_actions')->cascadeOnDelete();
$table->timestamp('granted_at')->nullable();
$table->primary(['admin_user_id', 'site_id', 'menu_action_id'], 'pk_admin_user_menu_actions');
});
Schema::create('admin_user_data_scopes', function (Blueprint $table): void {
$table->id();
$table->foreignId('admin_user_id')->constrained('admin_users')->cascadeOnDelete();
$table->foreignId('site_id')->nullable()->constrained('admin_sites')->nullOnDelete();
$table->foreignId('data_scope_id')->constrained('admin_data_scopes')->cascadeOnDelete();
$table->string('module_code', 64)->nullable();
$table->json('constraint_json')->nullable();
$table->timestamps();
$table->unique(['admin_user_id', 'site_id', 'data_scope_id', 'module_code'], 'uk_admin_user_data_scopes');
});
}
private function seedInitialData(): void
{
$now = Carbon::now();
DB::table('admin_sites')->insert([
'code' => 'default_site',
'name' => '默认站点',
'currency_code' => 'NPR',
'status' => 1,
'is_default' => true,
'extra_json' => json_encode(['source' => 'migration'], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
'created_at' => $now,
'updated_at' => $now,
]);
DB::table('admin_action_catalog')->insert([
['code' => 'view', 'name' => '查看', 'sort_order' => 10, 'status' => 1, 'created_at' => $now, 'updated_at' => $now],
['code' => 'create', 'name' => '新增', 'sort_order' => 20, 'status' => 1, 'created_at' => $now, 'updated_at' => $now],
['code' => 'update', 'name' => '编辑', 'sort_order' => 30, 'status' => 1, 'created_at' => $now, 'updated_at' => $now],
['code' => 'delete', 'name' => '删除', 'sort_order' => 40, 'status' => 1, 'created_at' => $now, 'updated_at' => $now],
['code' => 'review', 'name' => '审核', 'sort_order' => 50, 'status' => 1, 'created_at' => $now, 'updated_at' => $now],
['code' => 'publish', 'name' => '发布', 'sort_order' => 60, 'status' => 1, 'created_at' => $now, 'updated_at' => $now],
['code' => 'export', 'name' => '导出', 'sort_order' => 70, 'status' => 1, 'created_at' => $now, 'updated_at' => $now],
['code' => 'manage', 'name' => '管理', 'sort_order' => 80, 'status' => 1, 'created_at' => $now, 'updated_at' => $now],
]);
DB::table('admin_data_scopes')->insert([
['code' => 'all_sites', 'name' => '全站点', 'scope_type' => 'all_sites', 'module_code' => null, 'description' => '可访问所有站点数据', 'status' => 1, 'created_at' => $now, 'updated_at' => $now],
['code' => 'site_only', 'name' => '指定站点', 'scope_type' => 'site_only', 'module_code' => null, 'description' => '仅限授权站点登录和访问', 'status' => 1, 'created_at' => $now, 'updated_at' => $now],
['code' => 'site_all_data', 'name' => '站点内全部数据', 'scope_type' => 'site_all_data', 'module_code' => null, 'description' => '可访问站点内全部业务数据', 'status' => 1, 'created_at' => $now, 'updated_at' => $now],
['code' => 'site_single_player', 'name' => '站点内单玩家', 'scope_type' => 'site_single_player', 'module_code' => 'player_service', 'description' => '仅限按指定玩家处理客诉与查单', 'status' => 1, 'created_at' => $now, 'updated_at' => $now],
['code' => 'self_only', 'name' => '仅本人相关', 'scope_type' => 'self_only', 'module_code' => 'audit', 'description' => '仅可查看与自身相关的数据', 'status' => 1, 'created_at' => $now, 'updated_at' => $now],
]);
$this->seedMenuTree($now);
$this->seedApiResources($now);
}
private function seedMenuTree(Carbon $now): void
{
$menus = [
['parent_code' => null, 'menu_type' => 'menu', 'code' => 'dashboard', 'name' => '仪表盘', 'path' => '/admin', 'route_name' => 'admin.dashboard', 'component' => 'dashboard/index', 'icon' => 'layout-dashboard', 'sort_order' => 10],
['parent_code' => null, 'menu_type' => 'directory', 'code' => 'draw', 'name' => '开奖管理', 'path' => '/admin/draws', 'route_name' => null, 'component' => null, 'icon' => 'dice-5', 'sort_order' => 20],
['parent_code' => 'draw', 'menu_type' => 'page', 'code' => 'draw.results', 'name' => '开奖结果', 'path' => '/admin/draws', 'route_name' => 'admin.draws.index', 'component' => 'draw/results', 'icon' => null, 'sort_order' => 10],
['parent_code' => 'draw', 'menu_type' => 'page', 'code' => 'draw.review', 'name' => '开奖审核', 'path' => '/admin/draws/review', 'route_name' => 'admin.draws.review', 'component' => 'draw/review', 'icon' => null, 'sort_order' => 20],
['parent_code' => null, 'menu_type' => 'directory', 'code' => 'config', 'name' => '运营配置', 'path' => '/admin/config', 'route_name' => null, 'component' => null, 'icon' => 'sliders-horizontal', 'sort_order' => 30],
['parent_code' => 'config', 'menu_type' => 'page', 'code' => 'config.play', 'name' => '玩法开关', 'path' => '/admin/config/play-switches', 'route_name' => 'admin.config.play', 'component' => 'config/play', 'icon' => null, 'sort_order' => 10],
['parent_code' => 'config', 'menu_type' => 'page', 'code' => 'config.odds', 'name' => '赔率配置', 'path' => '/admin/config/odds', 'route_name' => 'admin.config.odds', 'component' => 'config/odds', 'icon' => null, 'sort_order' => 20],
['parent_code' => 'config', 'menu_type' => 'page', 'code' => 'config.risk_cap', 'name' => '封顶配置', 'path' => '/admin/config/play-limits', 'route_name' => 'admin.config.risk_cap', 'component' => 'config/risk-cap', 'icon' => null, 'sort_order' => 30],
['parent_code' => 'config', 'menu_type' => 'page', 'code' => 'config.jackpot', 'name' => 'Jackpot 配置', 'path' => '/admin/jackpot/pools', 'route_name' => 'admin.jackpot.pools', 'component' => 'config/jackpot', 'icon' => null, 'sort_order' => 40],
['parent_code' => null, 'menu_type' => 'page', 'code' => 'risk.monitor', 'name' => '风控监控', 'path' => '/admin/risk', 'route_name' => 'admin.risk.monitor', 'component' => 'risk/monitor', 'icon' => 'shield-alert', 'sort_order' => 40],
['parent_code' => null, 'menu_type' => 'page', 'code' => 'settlement.batch', 'name' => '结算批次', 'path' => '/admin/settlement-batches', 'route_name' => 'admin.settlement.batches', 'component' => 'settlement/batches', 'icon' => 'receipt-text', 'sort_order' => 50],
['parent_code' => null, 'menu_type' => 'directory', 'code' => 'service', 'name' => '客服财务', 'path' => '/admin/service-desk', 'route_name' => null, 'component' => null, 'icon' => 'hand-helping', 'sort_order' => 60],
['parent_code' => 'service', 'menu_type' => 'page', 'code' => 'service.players', 'name' => '玩家查询', 'path' => '/admin/players', 'route_name' => 'admin.players.index', 'component' => 'service/players', 'icon' => null, 'sort_order' => 10],
['parent_code' => 'service', 'menu_type' => 'page', 'code' => 'service.tickets', 'name' => '玩家注单', 'path' => '/admin/tickets', 'route_name' => 'admin.tickets.index', 'component' => 'service/tickets', 'icon' => null, 'sort_order' => 20],
['parent_code' => 'service', 'menu_type' => 'page', 'code' => 'service.wallet', 'name' => '钱包流水', 'path' => '/admin/wallet/transactions', 'route_name' => 'admin.wallet.transactions', 'component' => 'service/wallet', 'icon' => null, 'sort_order' => 30],
['parent_code' => 'service', 'menu_type' => 'page', 'code' => 'service.reconcile', 'name' => '对账管理', 'path' => '/admin/reconcile', 'route_name' => 'admin.reconcile.index', 'component' => 'service/reconcile', 'icon' => null, 'sort_order' => 40],
['parent_code' => 'service', 'menu_type' => 'page', 'code' => 'service.reports', 'name' => '报表导出', 'path' => '/admin/reports', 'route_name' => 'admin.reports.index', 'component' => 'service/reports', 'icon' => null, 'sort_order' => 50],
['parent_code' => 'service', 'menu_type' => 'page', 'code' => 'service.audit', 'name' => '审计日志', 'path' => '/admin/audit-logs', 'route_name' => 'admin.audit.index', 'component' => 'service/audit', 'icon' => null, 'sort_order' => 60],
['parent_code' => null, 'menu_type' => 'page', 'code' => 'system.admin_user', 'name' => '管理员权限', 'path' => '/admin/admin-users', 'route_name' => 'admin.system.admin-users', 'component' => 'system/admin-users', 'icon' => 'users-round', 'sort_order' => 70],
];
$menuIds = [];
foreach ($menus as $menu) {
$menuIds[$menu['code']] = DB::table('admin_menus')->insertGetId([
'parent_id' => $menu['parent_code'] === null ? null : $menuIds[$menu['parent_code']],
'menu_type' => $menu['menu_type'],
'code' => $menu['code'],
'name' => $menu['name'],
'path' => $menu['path'],
'route_name' => $menu['route_name'],
'component' => $menu['component'],
'icon' => $menu['icon'],
'active_menu_code' => null,
'sort_order' => $menu['sort_order'],
'is_visible' => true,
'is_cache' => false,
'is_external' => false,
'status' => 1,
'meta_json' => null,
'created_at' => $now,
'updated_at' => $now,
]);
}
$actionIds = DB::table('admin_action_catalog')->pluck('id', 'code');
$menuActions = [
['menu_code' => 'dashboard', 'action_code' => 'view', 'permission_code' => 'dashboard.view', 'name' => '仪表盘查看'],
['menu_code' => 'draw.results', 'action_code' => 'view', 'permission_code' => 'draw.results.view', 'name' => '开奖结果查看'],
['menu_code' => 'draw.review', 'action_code' => 'review', 'permission_code' => 'draw.review.review', 'name' => '开奖审核'],
['menu_code' => 'draw.review', 'action_code' => 'publish', 'permission_code' => 'draw.review.publish', 'name' => '开奖发布'],
['menu_code' => 'config.play', 'action_code' => 'manage', 'permission_code' => 'config.play.manage', 'name' => '玩法开关管理'],
['menu_code' => 'config.odds', 'action_code' => 'manage', 'permission_code' => 'config.odds.manage', 'name' => '赔率配置管理'],
['menu_code' => 'config.risk_cap', 'action_code' => 'view', 'permission_code' => 'config.risk_cap.view', 'name' => '封顶配置查看'],
['menu_code' => 'config.risk_cap', 'action_code' => 'manage', 'permission_code' => 'config.risk_cap.manage', 'name' => '封顶配置管理'],
['menu_code' => 'config.jackpot', 'action_code' => 'view', 'permission_code' => 'config.jackpot.view', 'name' => 'Jackpot 查看'],
['menu_code' => 'config.jackpot', 'action_code' => 'manage', 'permission_code' => 'config.jackpot.manage', 'name' => 'Jackpot 管理'],
['menu_code' => 'risk.monitor', 'action_code' => 'view', 'permission_code' => 'risk.monitor.view', 'name' => '风控监控查看'],
['menu_code' => 'settlement.batch', 'action_code' => 'view', 'permission_code' => 'settlement.batch.view', 'name' => '结算查看'],
['menu_code' => 'settlement.batch', 'action_code' => 'review', 'permission_code' => 'settlement.batch.review', 'name' => '结算审核'],
['menu_code' => 'settlement.batch', 'action_code' => 'manage', 'permission_code' => 'settlement.batch.manage', 'name' => '结算执行'],
['menu_code' => 'service.players', 'action_code' => 'view', 'permission_code' => 'service.players.view', 'name' => '玩家查询查看'],
['menu_code' => 'service.players', 'action_code' => 'manage', 'permission_code' => 'service.players.manage', 'name' => '玩家查询管理'],
['menu_code' => 'service.tickets', 'action_code' => 'view', 'permission_code' => 'service.tickets.view', 'name' => '玩家注单查看'],
['menu_code' => 'service.wallet', 'action_code' => 'view', 'permission_code' => 'service.wallet.view', 'name' => '钱包流水查看'],
['menu_code' => 'service.wallet', 'action_code' => 'manage', 'permission_code' => 'service.wallet.manage', 'name' => '钱包流水管理'],
['menu_code' => 'service.reconcile', 'action_code' => 'view', 'permission_code' => 'service.reconcile.view', 'name' => '对账查看'],
['menu_code' => 'service.reconcile', 'action_code' => 'manage', 'permission_code' => 'service.reconcile.manage', 'name' => '对账管理'],
['menu_code' => 'service.reports', 'action_code' => 'view', 'permission_code' => 'service.reports.view', 'name' => '报表查看'],
['menu_code' => 'service.reports', 'action_code' => 'export', 'permission_code' => 'service.reports.export', 'name' => '报表导出'],
['menu_code' => 'service.audit', 'action_code' => 'view', 'permission_code' => 'service.audit.view', 'name' => '审计查看'],
['menu_code' => 'system.admin_user', 'action_code' => 'manage', 'permission_code' => 'system.admin_user.manage', 'name' => '管理员权限管理'],
];
foreach ($menuActions as $row) {
DB::table('admin_menu_actions')->insert([
'menu_id' => $menuIds[$row['menu_code']],
'action_id' => $actionIds[$row['action_code']],
'permission_code' => $row['permission_code'],
'name' => $row['name'],
'status' => 1,
'created_at' => $now,
'updated_at' => $now,
]);
}
}
private function seedApiResources(Carbon $now): void
{
$resources = [
['code' => 'admin.dashboard', 'module_code' => 'dashboard', 'name' => '后台仪表盘', 'http_method' => 'GET', 'uri_pattern' => '/api/v1/admin/dashboard', 'route_name' => 'api.v1.admin.dashboard', 'auth_mode' => 'login_only', 'is_audit_required' => false, 'permission_codes' => ['dashboard.view']],
['code' => 'admin.draws.index', 'module_code' => 'draw', 'name' => '期开奖列表', 'http_method' => 'GET', 'uri_pattern' => '/api/v1/admin/draws', 'route_name' => 'api.v1.admin.draws.index', 'auth_mode' => 'permission_required', 'is_audit_required' => false, 'permission_codes' => ['draw.results.view']],
['code' => 'admin.draws.show', 'module_code' => 'draw', 'name' => '期开奖详情', 'http_method' => 'GET', 'uri_pattern' => '/api/v1/admin/draws/{draw}', 'route_name' => 'api.v1.admin.draws.show', 'auth_mode' => 'permission_required', 'is_audit_required' => false, 'permission_codes' => ['draw.results.view']],
['code' => 'admin.draws.publish', 'module_code' => 'draw', 'name' => '开奖发布', 'http_method' => 'POST', 'uri_pattern' => '/api/v1/admin/draws/{draw}/result-batches/{batch}/publish', 'route_name' => 'api.v1.admin.draws.result-batches.publish', 'auth_mode' => 'permission_required', 'is_audit_required' => true, 'permission_codes' => ['draw.review.publish']],
['code' => 'admin.draws.settlement.run', 'module_code' => 'settlement', 'name' => '执行结算', 'http_method' => 'POST', 'uri_pattern' => '/api/v1/admin/draws/{draw}/settlement/run', 'route_name' => 'api.v1.admin.draws.settlement.run', 'auth_mode' => 'permission_required', 'is_audit_required' => true, 'permission_codes' => ['settlement.batch.manage', 'settlement.batch.review']],
['code' => 'admin.wallet.transactions', 'module_code' => 'wallet', 'name' => '钱包流水查询', 'http_method' => 'GET', 'uri_pattern' => '/api/v1/admin/wallet/transactions', 'route_name' => 'api.v1.admin.wallet.transactions', 'auth_mode' => 'permission_required', 'is_audit_required' => false, 'permission_codes' => ['service.wallet.view', 'service.wallet.manage']],
['code' => 'admin.wallet.transfer-orders', 'module_code' => 'wallet', 'name' => '转账单查询', 'http_method' => 'GET', 'uri_pattern' => '/api/v1/admin/wallet/transfer-orders', 'route_name' => 'api.v1.admin.wallet.transfer-orders', 'auth_mode' => 'permission_required', 'is_audit_required' => false, 'permission_codes' => ['service.wallet.view', 'service.wallet.manage']],
['code' => 'admin.players.wallets', 'module_code' => 'player_service', 'name' => '玩家钱包查看', 'http_method' => 'GET', 'uri_pattern' => '/api/v1/admin/players/{player}/wallets', 'route_name' => 'api.v1.admin.players.wallets', 'auth_mode' => 'permission_required', 'is_audit_required' => false, 'permission_codes' => ['service.players.view', 'service.players.manage']],
['code' => 'admin.players.ticket-items', 'module_code' => 'player_service', 'name' => '玩家注单查看', 'http_method' => 'GET', 'uri_pattern' => '/api/v1/admin/players/{player}/ticket-items', 'route_name' => 'api.v1.admin.players.ticket-items.index', 'auth_mode' => 'permission_required', 'is_audit_required' => false, 'permission_codes' => ['service.tickets.view']],
['code' => 'admin.reports.index', 'module_code' => 'report', 'name' => '报表任务列表', 'http_method' => 'GET', 'uri_pattern' => '/api/v1/admin/report-jobs', 'route_name' => 'api.v1.admin.report-jobs.index', 'auth_mode' => 'permission_required', 'is_audit_required' => false, 'permission_codes' => ['service.reports.view', 'service.reports.export']],
['code' => 'admin.reports.store', 'module_code' => 'report', 'name' => '创建报表任务', 'http_method' => 'POST', 'uri_pattern' => '/api/v1/admin/report-jobs', 'route_name' => 'api.v1.admin.report-jobs.store', 'auth_mode' => 'permission_required', 'is_audit_required' => true, 'permission_codes' => ['service.reports.export']],
['code' => 'admin.reconcile.index', 'module_code' => 'reconcile', 'name' => '对账任务列表', 'http_method' => 'GET', 'uri_pattern' => '/api/v1/admin/reconcile-jobs', 'route_name' => 'api.v1.admin.reconcile-jobs.index', 'auth_mode' => 'permission_required', 'is_audit_required' => false, 'permission_codes' => ['service.reconcile.view', 'service.reconcile.manage']],
['code' => 'admin.reconcile.store', 'module_code' => 'reconcile', 'name' => '创建对账任务', 'http_method' => 'POST', 'uri_pattern' => '/api/v1/admin/reconcile-jobs', 'route_name' => 'api.v1.admin.reconcile-jobs.store', 'auth_mode' => 'permission_required', 'is_audit_required' => true, 'permission_codes' => ['service.reconcile.manage']],
['code' => 'admin.audit.index', 'module_code' => 'audit', 'name' => '审计日志查询', 'http_method' => 'GET', 'uri_pattern' => '/api/v1/admin/audit-logs', 'route_name' => 'api.v1.admin.audit-logs.index', 'auth_mode' => 'permission_required', 'is_audit_required' => false, 'permission_codes' => ['service.audit.view']],
['code' => 'admin.admin-users.index', 'module_code' => 'system', 'name' => '管理员列表', 'http_method' => 'GET', 'uri_pattern' => '/api/v1/admin/admin-users', 'route_name' => 'api.v1.admin.admin-users.index', 'auth_mode' => 'permission_required', 'is_audit_required' => false, 'permission_codes' => ['system.admin_user.manage']],
['code' => 'admin.admin-users.permission-catalog', 'module_code' => 'system', 'name' => '管理员权限目录', 'http_method' => 'GET', 'uri_pattern' => '/api/v1/admin/admin-user-permission-catalog', 'route_name' => 'api.v1.admin.admin-users.permission-catalog', 'auth_mode' => 'permission_required', 'is_audit_required' => false, 'permission_codes' => ['system.admin_user.manage']],
['code' => 'admin.admin-users.permissions.sync', 'module_code' => 'system', 'name' => '管理员权限同步', 'http_method' => 'PUT', 'uri_pattern' => '/api/v1/admin/admin-users/{admin_user}/permissions', 'route_name' => 'api.v1.admin.admin-users.permissions.sync', 'auth_mode' => 'permission_required', 'is_audit_required' => true, 'permission_codes' => ['system.admin_user.manage']],
];
$menuActionIds = DB::table('admin_menu_actions')->pluck('id', 'permission_code');
foreach ($resources as $resource) {
$resourceId = DB::table('admin_api_resources')->insertGetId([
'code' => $resource['code'],
'module_code' => $resource['module_code'],
'name' => $resource['name'],
'http_method' => $resource['http_method'],
'uri_pattern' => $resource['uri_pattern'],
'route_name' => $resource['route_name'],
'auth_mode' => $resource['auth_mode'],
'is_audit_required' => $resource['is_audit_required'],
'status' => 1,
'meta_json' => null,
'created_at' => $now,
'updated_at' => $now,
]);
foreach ($resource['permission_codes'] as $permissionCode) {
if (! isset($menuActionIds[$permissionCode])) {
continue;
}
DB::table('admin_api_resource_bindings')->insert([
'api_resource_id' => $resourceId,
'menu_action_id' => $menuActionIds[$permissionCode],
'created_at' => $now,
'updated_at' => $now,
]);
}
}
}
private function migrateLegacyAssignments(): void
{
$now = Carbon::now();
$defaultSiteId = (int) DB::table('admin_sites')->where('is_default', true)->value('id');
$legacyRoles = DB::table('admin_roles')
->select('id', 'code', 'slug', 'name')
->get();
$legacyRoleAssignments = DB::table('admin_user_roles')->get();
foreach ($legacyRoleAssignments as $row) {
$legacyRoleId = (int) $row->role_id;
DB::table('admin_user_site_roles')->insert([
'admin_user_id' => (int) $row->admin_user_id,
'site_id' => $defaultSiteId,
'role_id' => $legacyRoleId,
'granted_at' => $now,
]);
}
$legacyPermissionById = DB::table('admin_permissions')->pluck('slug', 'id');
$legacyRolePermissions = DB::table('admin_role_permissions')->get()->groupBy('role_id');
$legacyUserPermissions = DB::table('admin_user_permissions')->get()->groupBy('admin_user_id');
$menuActionIds = DB::table('admin_menu_actions')->pluck('id', 'permission_code');
$apiResourceIdsByPermission = DB::table('admin_api_resource_bindings')
->join('admin_menu_actions', 'admin_menu_actions.id', '=', 'admin_api_resource_bindings.menu_action_id')
->select('admin_menu_actions.permission_code', 'admin_api_resource_bindings.api_resource_id')
->get()
->groupBy('permission_code')
->map(static fn ($rows) => $rows->pluck('api_resource_id')->all());
$menuIdsByPermission = DB::table('admin_menu_actions')
->join('admin_menus', 'admin_menus.id', '=', 'admin_menu_actions.menu_id')
->pluck('admin_menus.id', 'admin_menu_actions.permission_code');
$legacyToNewPermissionMap = [
'prd.users.manage' => ['service.players.manage'],
'prd.users.view_finance' => ['service.players.view', 'service.wallet.view'],
'prd.users.view_cs' => ['service.players.view', 'service.tickets.view', 'service.wallet.view'],
'prd.play_switch.manage' => ['config.play.manage'],
'prd.odds.manage' => ['config.odds.manage'],
'prd.risk_cap.manage' => ['config.risk_cap.manage'],
'prd.risk_cap.view' => ['config.risk_cap.view'],
'prd.rebate.manage' => ['config.odds.manage'],
'prd.rebate.view' => ['config.odds.manage'],
'prd.jackpot.manage' => ['config.jackpot.manage'],
'prd.jackpot.view' => ['config.jackpot.view'],
'prd.draw_result.manage' => ['draw.results.view', 'draw.review.review', 'draw.review.publish', 'risk.monitor.view'],
'prd.draw_result.view' => ['draw.results.view', 'risk.monitor.view'],
'prd.payout.manage' => ['settlement.batch.manage', 'settlement.batch.view'],
'prd.payout.review' => ['settlement.batch.review', 'settlement.batch.view'],
'prd.payout.view' => ['settlement.batch.view'],
'prd.wallet_reconcile.manage' => ['service.wallet.manage', 'service.reconcile.manage'],
'prd.wallet_reconcile.view' => ['service.wallet.view', 'service.reconcile.view'],
'prd.wallet_reconcile.view_cs' => ['service.wallet.view', 'service.reconcile.view'],
'prd.report.all' => ['service.reports.view', 'service.reports.export'],
'prd.report.risk' => ['service.reports.view'],
'prd.report.finance' => ['service.reports.view', 'service.reports.export'],
'prd.report.player' => ['service.reports.view'],
'prd.audit.all' => ['service.audit.view'],
'prd.audit.self' => ['service.audit.view'],
'prd.audit.finance' => ['service.audit.view'],
'prd.admin_user.manage' => ['system.admin_user.manage'],
'prd.player_freeze.manage' => ['service.players.manage'],
'prd.wallet_adjust.manage' => ['service.wallet.manage'],
'prd.draw_reopen.manage' => ['draw.review.publish'],
];
foreach ($legacyRoles as $role) {
$roleId = (int) $role->id;
$grantedPermissions = ['dashboard.view' => true];
foreach ($legacyRolePermissions->get((int) $role->id, collect()) as $pivot) {
$permissionId = (int) $pivot->permission_id;
$legacySlug = $legacyPermissionById[$permissionId] ?? null;
if (! is_string($legacySlug)) {
continue;
}
foreach ($legacyToNewPermissionMap[$legacySlug] ?? [] as $permissionCode) {
$grantedPermissions[$permissionCode] = true;
}
}
foreach (array_keys($grantedPermissions) as $permissionCode) {
if (isset($menuIdsByPermission[$permissionCode])) {
$this->grantMenuWithAncestors($roleId, (int) $menuIdsByPermission[$permissionCode]);
}
if (isset($menuActionIds[$permissionCode])) {
DB::table('admin_role_menu_actions')->updateOrInsert([
'role_id' => $roleId,
'menu_action_id' => (int) $menuActionIds[$permissionCode],
]);
}
foreach ($apiResourceIdsByPermission[$permissionCode] ?? [] as $apiResourceId) {
DB::table('admin_role_api_resources')->updateOrInsert([
'role_id' => $roleId,
'api_resource_id' => (int) $apiResourceId,
]);
}
}
$roleCode = (string) ($role->code ?: $role->slug);
$this->assignRoleDataScopes($roleId, $roleCode, $defaultSiteId, $now);
}
foreach ($legacyUserPermissions as $adminUserId => $pivots) {
$grantedPermissions = [];
foreach ($pivots as $pivot) {
$permissionId = (int) $pivot->permission_id;
$legacySlug = $legacyPermissionById[$permissionId] ?? null;
if (! is_string($legacySlug)) {
continue;
}
foreach ($legacyToNewPermissionMap[$legacySlug] ?? [] as $permissionCode) {
$grantedPermissions[$permissionCode] = true;
}
}
foreach (array_keys($grantedPermissions) as $permissionCode) {
if (! isset($menuActionIds[$permissionCode])) {
continue;
}
DB::table('admin_user_menu_actions')->updateOrInsert([
'admin_user_id' => (int) $adminUserId,
'site_id' => $defaultSiteId,
'menu_action_id' => (int) $menuActionIds[$permissionCode],
], [
'granted_at' => $now,
]);
}
}
}
private function assignRoleDataScopes(int $roleId, string $roleCode, int $siteId, Carbon $now): void
{
$dataScopeIds = DB::table('admin_data_scopes')->pluck('id', 'code');
$rows = match ($roleCode) {
'super_admin' => [
['scope_code' => 'all_sites', 'module_code' => null],
['scope_code' => 'site_all_data', 'module_code' => null],
],
'risk_operator' => [
['scope_code' => 'site_only', 'module_code' => null],
['scope_code' => 'site_all_data', 'module_code' => 'risk'],
['scope_code' => 'self_only', 'module_code' => 'audit'],
],
'finance' => [
['scope_code' => 'site_only', 'module_code' => null],
['scope_code' => 'site_all_data', 'module_code' => 'wallet'],
['scope_code' => 'site_all_data', 'module_code' => 'settlement'],
['scope_code' => 'site_all_data', 'module_code' => 'report'],
['scope_code' => 'site_all_data', 'module_code' => 'reconcile'],
],
'customer_service' => [
['scope_code' => 'site_only', 'module_code' => null],
['scope_code' => 'site_single_player', 'module_code' => 'player_service'],
],
default => [
['scope_code' => 'site_only', 'module_code' => null],
],
};
foreach ($rows as $row) {
$scopeId = $dataScopeIds[$row['scope_code']] ?? null;
if ($scopeId === null) {
continue;
}
DB::table('admin_role_data_scopes')->insert([
'role_id' => $roleId,
'site_id' => $row['scope_code'] === 'all_sites' ? null : $siteId,
'data_scope_id' => (int) $scopeId,
'module_code' => $row['module_code'],
'constraint_json' => null,
'created_at' => $now,
'updated_at' => $now,
]);
}
}
private function grantMenuWithAncestors(int $roleId, int $menuId): void
{
$currentMenuId = $menuId;
while ($currentMenuId > 0) {
DB::table('admin_role_menus')->updateOrInsert([
'role_id' => $roleId,
'menu_id' => $currentMenuId,
]);
$parentId = DB::table('admin_menus')->where('id', $currentMenuId)->value('parent_id');
$currentMenuId = $parentId === null ? 0 : (int) $parentId;
}
}
private function dropLegacyTables(): void
{
Schema::dropIfExists('admin_user_permissions');
Schema::dropIfExists('admin_user_roles');
Schema::dropIfExists('admin_role_permissions');
Schema::dropIfExists('admin_permissions');
}
private function recreateLegacyTables(): void
{
Schema::table('admin_roles', function (Blueprint $table): void {
$table->dropUnique(['code']);
$table->dropColumn(['code', 'description', 'status', 'is_system', 'sort_order']);
});
Schema::create('admin_permissions', function (Blueprint $table): void {
$table->id();
$table->string('slug', 128)->unique();
$table->string('name', 128);
$table->timestamps();
});
Schema::create('admin_role_permissions', function (Blueprint $table): void {
$table->foreignId('role_id')->constrained('admin_roles')->cascadeOnDelete();
$table->foreignId('permission_id')->constrained('admin_permissions')->cascadeOnDelete();
$table->primary(['role_id', 'permission_id']);
});
Schema::create('admin_user_roles', function (Blueprint $table): void {
$table->foreignId('admin_user_id')->constrained('admin_users')->cascadeOnDelete();
$table->foreignId('role_id')->constrained('admin_roles')->cascadeOnDelete();
$table->primary(['admin_user_id', 'role_id']);
});
Schema::create('admin_user_permissions', function (Blueprint $table): void {
$table->foreignId('admin_user_id')->constrained('admin_users')->cascadeOnDelete();
$table->foreignId('permission_id')->constrained('admin_permissions')->cascadeOnDelete();
$table->primary(['admin_user_id', 'permission_id']);
});
}
private function migrateBackToLegacyTables(): void
{
$now = Carbon::now();
$legacyPermissions = [
['slug' => 'prd.users.manage', 'name' => '用户管理·可管理'],
['slug' => 'prd.users.view_finance', 'name' => '用户管理·财务查看'],
['slug' => 'prd.users.view_cs', 'name' => '用户管理·客服单用户'],
['slug' => 'prd.play_switch.manage', 'name' => '玩法开关·可管理'],
['slug' => 'prd.odds.manage', 'name' => '赔率配置·可管理'],
['slug' => 'prd.risk_cap.manage', 'name' => '封顶配置·可管理'],
['slug' => 'prd.risk_cap.view', 'name' => '封顶配置·查看'],
['slug' => 'prd.rebate.manage', 'name' => '佣金/回水·可管理'],
['slug' => 'prd.rebate.view', 'name' => '佣金/回水·查看'],
['slug' => 'prd.jackpot.manage', 'name' => 'Jackpot 配置·可管理'],
['slug' => 'prd.jackpot.view', 'name' => 'Jackpot 配置·查看'],
['slug' => 'prd.draw_result.manage', 'name' => '开奖结果录入·可管理'],
['slug' => 'prd.draw_result.view', 'name' => '开奖结果·查看'],
['slug' => 'prd.draw_reopen.manage', 'name' => '开奖结果重开·可管理'],
['slug' => 'prd.payout.manage', 'name' => '派彩确认·可管理'],
['slug' => 'prd.payout.review', 'name' => '派彩确认·可审核'],
['slug' => 'prd.payout.view', 'name' => '派彩确认·查看'],
['slug' => 'prd.wallet_reconcile.manage', 'name' => '钱包对账·可管理'],
['slug' => 'prd.wallet_reconcile.view', 'name' => '钱包对账·查看'],
['slug' => 'prd.wallet_reconcile.view_cs', 'name' => '钱包对账·客服单用户'],
['slug' => 'prd.wallet_adjust.manage', 'name' => '补单/冲正·可管理'],
['slug' => 'prd.report.all', 'name' => '报表·全部'],
['slug' => 'prd.report.risk', 'name' => '报表·风控'],
['slug' => 'prd.report.finance', 'name' => '报表·财务'],
['slug' => 'prd.report.player', 'name' => '报表·单用户'],
['slug' => 'prd.audit.all', 'name' => '审计日志·全部'],
['slug' => 'prd.audit.self', 'name' => '审计日志·自身相关'],
['slug' => 'prd.audit.finance', 'name' => '审计日志·资金相关'],
['slug' => 'prd.player_freeze.manage', 'name' => '冻结/解冻玩家·可管理'],
['slug' => 'prd.admin_user.manage', 'name' => '后台用户权限管理·可管理'],
];
foreach ($legacyPermissions as $permission) {
DB::table('admin_permissions')->insert([
'slug' => $permission['slug'],
'name' => $permission['name'],
'created_at' => $now,
'updated_at' => $now,
]);
}
$permissionIds = DB::table('admin_permissions')->pluck('id', 'slug');
$roleCodeMap = DB::table('admin_roles')->pluck('id', 'slug');
$rolePermissionMap = [
'super_admin' => array_keys($permissionIds->all()),
'risk_operator' => [
'prd.play_switch.manage',
'prd.odds.manage',
'prd.risk_cap.manage',
'prd.rebate.manage',
'prd.jackpot.manage',
'prd.draw_result.manage',
'prd.payout.review',
'prd.wallet_reconcile.view',
'prd.report.risk',
'prd.audit.self',
'prd.player_freeze.manage',
],
'finance' => [
'prd.users.view_finance',
'prd.risk_cap.view',
'prd.rebate.view',
'prd.jackpot.view',
'prd.draw_result.view',
'prd.payout.view',
'prd.wallet_reconcile.manage',
'prd.wallet_adjust.manage',
'prd.report.finance',
'prd.audit.finance',
],
'customer_service' => [
'prd.users.view_cs',
'prd.draw_result.view',
'prd.wallet_reconcile.view_cs',
'prd.report.player',
],
];
foreach ($rolePermissionMap as $roleCode => $permissionSlugs) {
$roleId = $roleCodeMap[$roleCode] ?? null;
if ($roleId === null) {
continue;
}
foreach ($permissionSlugs as $slug) {
$permissionId = $permissionIds[$slug] ?? null;
if ($permissionId === null) {
continue;
}
DB::table('admin_role_permissions')->insert([
'role_id' => (int) $roleId,
'permission_id' => (int) $permissionId,
]);
}
}
$userRoles = DB::table('admin_user_site_roles')
->select('admin_user_id', 'role_id')
->distinct()
->get();
foreach ($userRoles as $row) {
DB::table('admin_user_roles')->insert([
'admin_user_id' => (int) $row->admin_user_id,
'role_id' => (int) $row->role_id,
]);
}
}
};

View File

@@ -2,102 +2,62 @@
namespace Database\Seeders;
use App\Models\AdminPermission;
use App\Models\AdminRole;
use App\Models\AdminUser;
use App\Support\AdminPermissionBridge;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
/**
* 后台 RBAC {@see AdminUser::ROLE_SUPER_ADMIN} PRD 对齐。
*
* - 角色 slug`01-产品文档.md` §3 + `04-领域字典与编码规范.md` §11
* - 权限点 slug`01-产品文档.md` §8「功能」行 `prd.{功能键}.{动作}`,路由中间件引用同表
* 后台 RBAC {@see AdminUser::ROLE_SUPER_ADMIN} `config/admin_permissions.php` 对齐。
*
* 演示账号 **admin** / **123456**(仅限非 production
*/
class AdminRbacAndUserSeeder extends Seeder
{
/** @return list<array{slug: string, name: string}> */
private function permissionDefinitions(): array
/** @param list<string> $legacySlugs */
private function syncRoleMenuActions(AdminRole $role, array $legacySlugs): void
{
return [
['slug' => 'prd.users.manage', 'name' => '用户管理·可管理'],
['slug' => 'prd.users.view_finance', 'name' => '用户管理·财务查看'],
['slug' => 'prd.users.view_cs', 'name' => '用户管理·客服单用户'],
$codes = [];
foreach ($legacySlugs as $slug) {
$codes = array_merge($codes, AdminPermissionBridge::menuActionCodesForLegacy($slug));
}
$codes = array_values(array_unique($codes));
['slug' => 'prd.play_switch.manage', 'name' => '玩法开关·可管理'],
['slug' => 'prd.odds.manage', 'name' => '赔率配置·可管理'],
['slug' => 'prd.risk_cap.manage', 'name' => '封顶配置·可管理'],
['slug' => 'prd.risk_cap.view', 'name' => '封顶配置·查看'],
['slug' => 'prd.rebate.manage', 'name' => '佣金/回水·可管理'],
['slug' => 'prd.rebate.view', 'name' => '佣金/回水·查看'],
['slug' => 'prd.jackpot.manage', 'name' => 'Jackpot 配置·可管理'],
['slug' => 'prd.jackpot.view', 'name' => 'Jackpot 配置·查看'],
$ids = DB::table('admin_menu_actions')
->whereIn('permission_code', $codes)
->where('status', 1)
->pluck('id')
->all();
['slug' => 'prd.draw_result.manage', 'name' => '开奖结果录入·可管理'],
['slug' => 'prd.draw_result.view', 'name' => '开奖结果·查看'],
['slug' => 'prd.draw_reopen.manage', 'name' => '开奖结果重开·可管理'],
['slug' => 'prd.payout.manage', 'name' => '派彩确认·可管理'],
['slug' => 'prd.payout.review', 'name' => '派彩确认·可审核'],
['slug' => 'prd.payout.view', 'name' => '派彩确认·查看'],
['slug' => 'prd.wallet_reconcile.manage', 'name' => '钱包对账·可管理'],
['slug' => 'prd.wallet_reconcile.view', 'name' => '钱包对账·查看'],
['slug' => 'prd.wallet_reconcile.view_cs', 'name' => '钱包对账·客服单用户'],
['slug' => 'prd.wallet_adjust.manage', 'name' => '补单/冲正·可管理'],
['slug' => 'prd.report.all', 'name' => '报表·全部'],
['slug' => 'prd.report.risk', 'name' => '报表·风控'],
['slug' => 'prd.report.finance', 'name' => '报表·财务'],
['slug' => 'prd.report.player', 'name' => '报表·单用户'],
['slug' => 'prd.audit.all', 'name' => '审计日志·全部'],
['slug' => 'prd.audit.self', 'name' => '审计日志·自身相关'],
['slug' => 'prd.audit.finance', 'name' => '审计日志·资金相关'],
['slug' => 'prd.player_freeze.manage', 'name' => '冻结/解冻玩家·可管理'],
['slug' => 'prd.admin_user.manage', 'name' => '后台用户权限管理·可管理'],
];
DB::table('admin_role_menu_actions')->where('role_id', $role->id)->delete();
foreach ($ids as $mid) {
DB::table('admin_role_menu_actions')->insert([
'role_id' => $role->id,
'menu_action_id' => (int) $mid,
]);
}
}
/** @param list<string> $slugs */
private function syncRolePermissions(AdminRole $role, array $slugs): void
/** @return list<string> */
private function allCatalogSlugs(): array
{
$ids = AdminPermission::query()->whereIn('slug', $slugs)->pluck('id')->all();
$role->permissions()->sync($ids);
return AdminPermissionBridge::allLegacySlugs();
}
public function run(): void
{
foreach ($this->permissionDefinitions() as $row) {
AdminPermission::query()->updateOrCreate(
['slug' => $row['slug']],
['name' => $row['name']],
);
}
$legacySlugs = [
'admin.dashboard', 'admin.players.read', 'admin.wallet.read', 'admin.draws.read',
'admin.draws.publish', 'admin.settlement.run', 'admin.settlement.read', 'admin.jackpot.read',
'admin.jackpot.write', 'admin.config.read', 'admin.config.write', 'admin.audit.read',
'admin.reports.manage', 'admin.reconcile.manage',
];
AdminPermission::query()->whereIn('slug', $legacySlugs)->delete();
$super = AdminRole::query()->updateOrCreate(
['slug' => AdminUser::ROLE_SUPER_ADMIN],
['name' => '超级管理员'],
);
$this->syncRolePermissions($super, array_column($this->permissionDefinitions(), 'slug'));
$this->syncRoleMenuActions($super, $this->allCatalogSlugs());
$risk = AdminRole::query()->updateOrCreate(
['slug' => 'risk_operator'],
['name' => '风控运营员'],
);
$this->syncRolePermissions($risk, [
$this->syncRoleMenuActions($risk, [
'prd.play_switch.manage',
'prd.odds.manage',
'prd.risk_cap.manage',
@@ -115,7 +75,7 @@ class AdminRbacAndUserSeeder extends Seeder
['slug' => 'finance'],
['name' => '财务/对账员'],
);
$this->syncRolePermissions($finance, [
$this->syncRoleMenuActions($finance, [
'prd.users.view_finance',
'prd.risk_cap.view',
'prd.rebate.view',
@@ -132,7 +92,7 @@ class AdminRbacAndUserSeeder extends Seeder
['slug' => 'customer_service'],
['name' => '客服人员'],
);
$this->syncRolePermissions($cs, [
$this->syncRoleMenuActions($cs, [
'prd.users.view_cs',
'prd.draw_result.view',
'prd.wallet_reconcile.view_cs',
@@ -152,10 +112,13 @@ class AdminRbacAndUserSeeder extends Seeder
/** @var AdminUser $admin */
$admin = AdminUser::query()->where('username', $username)->firstOrFail();
$admin->roles()->sync([(int) $super->getKey()]);
DB::table('admin_user_roles')->where('admin_user_id', $admin->id)
->whereNotIn('role_id', [(int) $super->getKey()])
->delete();
$siteId = AdminUser::defaultAdminSiteId();
$superId = (int) $super->getKey();
$admin->roles()->sync([
$superId => [
'site_id' => $siteId,
'granted_at' => now(),
],
]);
}
}