Files
lotteryLaravel/app/Support/AgentNodePresenter.php
kang a44679665d feat: 增强代理和玩家管理功能
- 在多个控制器中更新权限检查逻辑,确保管理员能够更灵活地管理代理和玩家。
- 在 AdminPlayerStoreController 中引入对玩家创建能力的验证,确保只有具备相应权限的管理员能够创建玩家。
- 更新请求验证逻辑,新增 credit_limit、rebate_rate 和 extra_rebate_rate 字段,以支持更细粒度的玩家管理。
- 在 AgentNodeProfileController 中添加对父代理能力授予的验证,确保子代理的权限在父代理范围内。
- 引入 AgentProfileFieldRules 以简化代理资料更新请求的规则定义,提升代码复用性。
2026-06-04 18:00:50 +08:00

130 lines
4.2 KiB
PHP

<?php
namespace App\Support;
use App\Models\AdminSite;
use App\Models\AgentNode;
use App\Models\AgentProfile;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
final class AgentNodePresenter
{
/**
* @return array{
* id: int,
* admin_site_id: int,
* parent_id: ?int,
* path: string,
* depth: int,
* code: string,
* name: string,
* status: int,
* is_root: bool,
* username: ?string,
* email: ?string
* }
*/
/**
* @return array<string, mixed>
*/
public static function profileSummary(AgentProfile $profile): array
{
return [
'total_share_rate' => (float) $profile->total_share_rate,
'credit_limit' => (int) $profile->credit_limit,
'allocated_credit' => (int) $profile->allocated_credit,
'used_credit' => (int) $profile->used_credit,
'available_credit' => max(0, (int) $profile->credit_limit - (int) $profile->allocated_credit),
'rebate_limit' => (float) $profile->rebate_limit,
'default_player_rebate' => (float) $profile->default_player_rebate,
'settlement_cycle' => AgentSettlementCycle::normalize($profile->settlement_cycle),
];
}
public static function item(AgentNode $node, ?AgentProfile $profile = null): array
{
$account = DB::table('admin_user_agents as aua')
->join('admin_users as au', 'au.id', '=', 'aua.admin_user_id')
->where('aua.agent_node_id', $node->id)
->orderByDesc('aua.is_primary')
->orderBy('aua.admin_user_id')
->select('au.username', 'au.email')
->first();
$siteCode = AdminSite::query()->where('id', $node->admin_site_id)->value('code');
$payload = [
'id' => (int) $node->id,
'admin_site_id' => (int) $node->admin_site_id,
'site_code' => $siteCode !== null ? (string) $siteCode : null,
'parent_id' => $node->parent_id !== null ? (int) $node->parent_id : null,
'path' => (string) $node->path,
'depth' => (int) $node->depth,
'code' => (string) $node->code,
'name' => (string) $node->name,
'status' => (int) $node->status,
'is_root' => $node->isRoot(),
'is_line_root' => $node->isRoot(),
'username' => $account?->username !== null ? (string) $account->username : null,
'email' => $account?->email !== null ? (string) $account->email : null,
];
if ($profile !== null) {
$payload['profile_summary'] = self::profileSummary($profile);
}
return $payload;
}
/**
* @param iterable<AgentNode> $nodes
* @return list<array<string, mixed>>
*/
public static function tree(iterable $nodes): array
{
$nodeList = $nodes instanceof Collection ? $nodes : collect($nodes);
$profiles = AgentProfile::query()
->whereIn('agent_node_id', $nodeList->pluck('id'))
->get()
->keyBy('agent_node_id');
$items = [];
$byParent = [];
foreach ($nodeList as $node) {
$profile = $profiles->get($node->id);
$row = self::item($node, $profile instanceof AgentProfile ? $profile : null);
$row['children'] = [];
$items[(int) $node->id] = $row;
$parentKey = $node->parent_id !== null ? (int) $node->parent_id : 0;
$byParent[$parentKey][] = (int) $node->id;
}
$attach = static function (int $id) use (&$attach, &$items, $byParent): array {
$node = $items[$id];
foreach ($byParent[$id] ?? [] as $childId) {
$node['children'][] = $attach($childId);
}
return $node;
};
$ids = array_keys($items);
$rootIds = [];
foreach ($items as $id => $row) {
$parentId = $row['parent_id'];
if ($parentId === null || ! in_array((int) $parentId, $ids, true)) {
$rootIds[] = (int) $id;
}
}
$roots = [];
foreach ($rootIds as $rootId) {
$roots[] = $attach($rootId);
}
return $roots;
}
}