Files
lotteryLaravel/app/Support/AdminSiteScope.php
kang 0841fbed32 feat: 增强管理员功能与数据处理
- 在多个控制器中引入 agent_node_id,以支持基于代理节点的权限和数据过滤。
- 更新 AdminRole 和 AdminUser 模型,新增角色范围和代理节点相关功能,提升角色管理的灵活性。
- 在请求验证中添加 agent_node_id 字段,确保 API 接口支持代理节点的相关操作。
- 优化 LotterySettings 服务,支持批量写入设置,提升配置管理的效率。
- 更新仪表板和报告服务,增强数据统计功能,确保管理员能够获取更全面的统计信息。
2026-06-02 14:36:58 +08:00

175 lines
5.1 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace App\Support;
use App\Models\AdminSite;
use App\Models\AdminUser;
use App\Models\Player;
use App\Lottery\ErrorCode;
use App\Support\ApiMessage;
use App\Support\ApiResponse;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\JsonResponse;
/**
* 后台站点数据范围:非超管仅可访问 {@see AdminUser::accessibleAdminSiteIds()} 绑定站点。
*
* 对应产品「site_only / site_all_data」运行时以 admin_user_site_roles 为准(非已废弃的 admin_data_scopes 表)。
*/
final class AdminSiteScope
{
/**
* @return list<string>|null `null` 表示不限制(超管)
*/
public static function accessibleSiteCodes(AdminUser $admin): ?array
{
$siteIds = $admin->accessibleAdminSiteIds();
if ($siteIds === null) {
return null;
}
if ($siteIds === []) {
return [];
}
return AdminSite::query()
->whereIn('id', $siteIds)
->orderBy('code')
->pluck('code')
->map(static fn ($code): string => (string) $code)
->values()
->all();
}
public static function siteCodeAllowed(AdminUser $admin, string $siteCode): bool
{
$allowed = self::accessibleSiteCodes($admin);
if ($allowed === null) {
return true;
}
return in_array($siteCode, $allowed, true);
}
public static function playerAccessible(AdminUser $admin, Player $player): bool
{
if (! self::siteCodeAllowed($admin, (string) $player->site_code)) {
return false;
}
return AdminAgentScope::playerAccessible($admin, $player);
}
/**
* @param Builder<Player> $query
*/
public static function applyToPlayerQuery(Builder $query, AdminUser $admin): void
{
$codes = self::accessibleSiteCodes($admin);
if ($codes === null) {
AdminAgentScope::applyToPlayerQuery($query, $admin);
return;
}
if ($codes === []) {
$query->whereRaw('0 = 1');
return;
}
$query->whereIn('site_code', $codes);
AdminAgentScope::applyToPlayerQuery($query, $admin);
}
/**
* 在站点范围基础上,可选按请求的 site_code 再收窄。
*
* @param Builder<Player> $query
*/
public static function applyPlayerFilters(
Builder $query,
AdminUser $admin,
?string $requestedSiteCode,
?int $requestedAgentNodeId = null,
): void {
self::applyToPlayerQuery($query, $admin);
$siteCode = is_string($requestedSiteCode) ? trim($requestedSiteCode) : '';
if ($siteCode !== '') {
if (! self::siteCodeAllowed($admin, $siteCode)) {
$query->whereRaw('0 = 1');
return;
}
$query->where('site_code', $siteCode);
}
if ($requestedAgentNodeId !== null && $requestedAgentNodeId > 0) {
AdminAgentScope::applyRequestedAgentNodeFilter($query, $admin, $requestedAgentNodeId);
}
}
/**
* @param Builder<mixed> $query
*/
public static function applyViaPlayerRelation(Builder $query, AdminUser $admin, string $relation = 'player'): void
{
if ($admin->isSuperAdmin()) {
return;
}
$query->whereHas($relation, static function (Builder $playerQuery) use ($admin): void {
self::applyToPlayerQuery($playerQuery, $admin);
});
}
/**
* @param Builder<mixed> $query
*/
public static function applyViaPlayerRelationWithSiteCode(
Builder $query,
AdminUser $admin,
?string $requestedSiteCode,
string $relation = 'player',
?int $requestedAgentNodeId = null,
): void {
if ($admin->isSuperAdmin()) {
$siteCode = is_string($requestedSiteCode) ? trim($requestedSiteCode) : '';
$agentNodeId = $requestedAgentNodeId !== null && $requestedAgentNodeId > 0
? $requestedAgentNodeId
: null;
if ($siteCode === '' && $agentNodeId === null) {
return;
}
$query->whereHas($relation, static function (Builder $playerQuery) use ($admin, $siteCode, $agentNodeId): void {
self::applyPlayerFilters($playerQuery, $admin, $siteCode !== '' ? $siteCode : null, $agentNodeId);
});
return;
}
$query->whereHas($relation, static function (Builder $playerQuery) use ($admin, $requestedSiteCode, $requestedAgentNodeId): void {
self::applyPlayerFilters($playerQuery, $admin, $requestedSiteCode, $requestedAgentNodeId);
});
}
public static function denyUnlessPlayerAccessible(AdminUser $admin, Player $player): ?JsonResponse
{
if (! self::playerAccessible($admin, $player)) {
return ApiMessage::errorResponse(
request(),
'admin.site_player_access_denied',
ErrorCode::AdminForbidden->value,
null,
403,
);
}
return null;
}
}