feat: 增强代理和玩家管理功能

- 在多个控制器中更新权限检查逻辑,确保管理员能够更灵活地管理代理和玩家。
- 在 AdminPlayerStoreController 中引入对玩家创建能力的验证,确保只有具备相应权限的管理员能够创建玩家。
- 更新请求验证逻辑,新增 credit_limit、rebate_rate 和 extra_rebate_rate 字段,以支持更细粒度的玩家管理。
- 在 AgentNodeProfileController 中添加对父代理能力授予的验证,确保子代理的权限在父代理范围内。
- 引入 AgentProfileFieldRules 以简化代理资料更新请求的规则定义,提升代码复用性。
This commit is contained in:
2026-06-04 18:00:50 +08:00
parent 96545f87f6
commit a44679665d
183 changed files with 10054 additions and 857 deletions

View File

@@ -0,0 +1,20 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
/** @deprecated 经营代理已改用平台角色 slug=agent */
final class AgentOwnerPermissionsResyncCommand extends Command
{
protected $signature = 'lottery:agent-owner-permissions-resync';
protected $description = '已废弃:请使用 lottery:agent-roles-sync并在「平台角色管理」编辑「代理」角色';
public function handle(): int
{
$this->warn('agent_owner_* 已不再用于经营主账号;正在转调 lottery:agent-roles-sync …');
return $this->call('lottery:agent-roles-sync');
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace App\Console\Commands;
use App\Models\AdminUser;
use App\Support\AgentDefaultRolePermissions;
use App\Support\AgentPlatformRole;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
final class AgentRolesSyncCommand extends Command
{
protected $signature = 'lottery:agent-roles-sync';
protected $description = '确保平台「代理」角色存在,并将所有经营代理主账号绑定到该角色(权限在平台角色管理维护)';
public function handle(): int
{
$platform = AgentDefaultRolePermissions::ensurePlatformAgentRole();
$this->info('平台角色 agent#'.$platform->id.')权限数: '.count($platform->legacyPermissionSlugs()));
$bindingCount = 0;
foreach (DB::table('admin_user_agents')->get(['admin_user_id', 'agent_node_id']) as $binding) {
$user = AdminUser::query()->find((int) $binding->admin_user_id);
if ($user === null) {
continue;
}
$user->syncPrimaryPlatformAgentRole((int) $binding->agent_node_id);
$bindingCount++;
}
$this->info("已绑定 {$bindingCount} 个经营代理主账号到平台「代理」角色。");
$this->line('调整权限请编辑:平台角色管理 → 代理');
return self::SUCCESS;
}
}

View File

@@ -0,0 +1,36 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
final class CreditLineDisableAllSitesCommand extends Command
{
protected $signature = 'lottery:credit-line-disable-all-sites';
protected $description = 'Disable credit_line_mode on all admin sites (rollback)';
public function handle(): int
{
$sites = DB::table('admin_sites')->get();
$count = 0;
foreach ($sites as $site) {
$extra = json_decode((string) ($site->extra_json ?? '{}'), true);
if (! is_array($extra)) {
$extra = [];
}
unset($extra['credit_line_mode']);
DB::table('admin_sites')->where('id', $site->id)->update([
'extra_json' => json_encode($extra),
'updated_at' => now(),
]);
$count++;
}
$this->info("Disabled credit_line_mode on {$count} site(s).");
return self::SUCCESS;
}
}

View File

@@ -0,0 +1,36 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
final class CreditLineEnableAllSitesCommand extends Command
{
protected $signature = 'lottery:credit-line-enable-all-sites';
protected $description = 'Enable credit_line_mode on all admin sites (big bang switch)';
public function handle(): int
{
$sites = DB::table('admin_sites')->get();
$count = 0;
foreach ($sites as $site) {
$extra = json_decode((string) ($site->extra_json ?? '{}'), true);
if (! is_array($extra)) {
$extra = [];
}
$extra['credit_line_mode'] = true;
DB::table('admin_sites')->where('id', $site->id)->update([
'extra_json' => json_encode($extra),
'updated_at' => now(),
]);
$count++;
}
$this->info("Enabled credit_line_mode on {$count} site(s).");
return self::SUCCESS;
}
}

View File

@@ -0,0 +1,32 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
final class SettlementMarkOverdueBillsCommand extends Command
{
protected $signature = 'settlement:mark-overdue-bills {--days=7}';
protected $description = 'Mark unpaid settlement bills as overdue past grace days';
public function handle(): int
{
$days = max(1, (int) $this->option('days'));
$cutoff = now()->subDays($days);
$updated = DB::table('settlement_bills')
->whereIn('status', ['confirmed', 'partial_paid'])
->where('unpaid_amount', '>', 0)
->where('updated_at', '<', $cutoff)
->update([
'status' => 'overdue',
'updated_at' => now(),
]);
$this->info("Marked {$updated} bill(s) overdue.");
return self::SUCCESS;
}
}

View File

@@ -9,6 +9,7 @@ use App\Support\AdminAgentLineSettlementPermissionMenuActionSync;
use App\Support\AdminAgentPermissionMenuActionSync;
use App\Support\AdminAuthorizationRegistry;
use App\Support\AdminDrawPermissionMenuActionSync;
use App\Support\PlatformSystemRoles;
final class SyncAdminAuthorizationCommand extends Command
{
@@ -92,6 +93,13 @@ final class SyncAdminAuthorizationCommand extends Command
count(AdminAuthorizationRegistry::resources()),
));
PlatformSystemRoles::ensureAll();
$super = PlatformSystemRoles::ensureSuperAdminRole();
$this->info(sprintf(
'Platform system roles synced (super_admin permissions: %d).',
count($super->legacyPermissionSlugs()),
));
if ((bool) $this->option('audit')) {
return $this->call('lottery:admin-auth-audit');
}

View File

@@ -0,0 +1,42 @@
<?php
namespace App\Console\Commands;
use App\Models\AgentNode;
use App\Models\AgentProfile;
use App\Services\Agent\AgentCreditAllocatedSyncService;
use Illuminate\Console\Command;
/** 按直属玩家/下级代理授信重算 allocated_credit修复历史增量漂移。 */
final class SyncAgentAllocatedCreditCommand extends Command
{
protected $signature = 'lottery:sync-agent-allocated-credit {--site= : 仅处理指定 admin_sites.code}';
protected $description = '重算代理已下发额度allocated_credit';
public function handle(AgentCreditAllocatedSyncService $sync): int
{
$siteCode = $this->option('site');
$query = AgentNode::query()->orderBy('id');
if (is_string($siteCode) && $siteCode !== '') {
$query->whereHas('adminSite', static fn ($q) => $q->where('code', $siteCode));
}
$nodes = $query->get();
$updated = 0;
foreach ($nodes as $node) {
$profile = AgentProfile::query()->where('agent_node_id', $node->id)->first();
$before = $profile !== null ? (int) $profile->allocated_credit : null;
$sync->syncForAgent($node);
$profile?->refresh();
$after = $profile !== null ? (int) $profile->allocated_credit : null;
if ($before !== $after) {
$updated++;
}
}
$this->info('已处理 '.count($nodes).' 个代理节点,其中 '.$updated.' 个 allocated_credit 有变更。');
return self::SUCCESS;
}
}