198 lines
5.0 KiB
PHP
198 lines
5.0 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
namespace app\common\service;
|
||
|
||
use app\admin\library\Auth;
|
||
use support\think\Db;
|
||
|
||
/**
|
||
* 后台管理员渠道数据范围:
|
||
* - 账号或角色组绑定 channel_id → 仅该批渠道(读+写)
|
||
* - 均未绑定且拥有渠道模块基础权限(channel/index、edit 等)→ 全部渠道(读+写)
|
||
* - 均未绑定且无渠道模块权限 → 不可见
|
||
*/
|
||
class AdminChannelScopeService
|
||
{
|
||
/**
|
||
* 是否具备全平台只读范围(其它菜单按 admin 收窄时跳过):超管 / 未绑定渠道且拥有渠道模块权限
|
||
*/
|
||
public static function hasGlobalReadScope(Auth $auth): bool
|
||
{
|
||
if (!$auth->isLogin()) {
|
||
return false;
|
||
}
|
||
if ($auth->isSuperAdmin()) {
|
||
return true;
|
||
}
|
||
if (self::resolveEffectiveChannelIds($auth) !== []) {
|
||
return false;
|
||
}
|
||
|
||
return self::hasAnyChannelMenuPermission($auth);
|
||
}
|
||
|
||
/**
|
||
* 可读渠道 ID 列表;null 表示不限制(全部渠道)
|
||
*
|
||
* @return array<int, int>|null
|
||
*/
|
||
public static function readableChannelIds(Auth $auth): ?array
|
||
{
|
||
return self::resolveScopedChannelIds($auth);
|
||
}
|
||
|
||
/**
|
||
* 可写渠道 ID 列表;null 表示不限制(全部渠道)
|
||
*
|
||
* @return array<int, int>|null
|
||
*/
|
||
public static function writableChannelIds(Auth $auth): ?array
|
||
{
|
||
return self::resolveScopedChannelIds($auth);
|
||
}
|
||
|
||
/**
|
||
* @return array<int, int>|null
|
||
*/
|
||
private static function resolveScopedChannelIds(Auth $auth): ?array
|
||
{
|
||
if (!$auth->isLogin()) {
|
||
return [0];
|
||
}
|
||
if ($auth->isSuperAdmin()) {
|
||
return null;
|
||
}
|
||
|
||
$ids = self::resolveEffectiveChannelIds($auth);
|
||
if ($ids !== []) {
|
||
return $ids;
|
||
}
|
||
|
||
if (self::hasAnyChannelMenuPermission($auth)) {
|
||
return null;
|
||
}
|
||
|
||
return [0];
|
||
}
|
||
|
||
/**
|
||
* 是否拥有渠道管理模块相关权限(菜单或任一 channel/* 按钮)
|
||
*/
|
||
public static function hasAnyChannelMenuPermission(Auth $auth): bool
|
||
{
|
||
if (!$auth->isLogin()) {
|
||
return false;
|
||
}
|
||
if ($auth->isSuperAdmin()) {
|
||
return true;
|
||
}
|
||
|
||
$checkNodes = [
|
||
'channel',
|
||
'channel/index',
|
||
'channel/add',
|
||
'channel/edit',
|
||
'channel/del',
|
||
'channel/manualSettle',
|
||
'channel/batchSettlePending',
|
||
'channel/settleStats',
|
||
];
|
||
foreach ($checkNodes as $node) {
|
||
if ($auth->check($node)) {
|
||
return true;
|
||
}
|
||
}
|
||
|
||
$ruleList = $auth->getRuleList();
|
||
foreach ($ruleList as $name) {
|
||
if (!is_string($name) || $name === '') {
|
||
continue;
|
||
}
|
||
$lower = strtolower($name);
|
||
if ($lower === 'channel' || str_starts_with($lower, 'channel/')) {
|
||
return true;
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* 管理员实际绑定的渠道(角色组 channel_id + 账号 admin.channel_id,去重)
|
||
*
|
||
* @return array<int, int>
|
||
*/
|
||
public static function resolveEffectiveChannelIds(Auth $auth): array
|
||
{
|
||
$ids = self::resolveBoundGroupChannelIds($auth);
|
||
$selfChannelId = self::resolveAdminAccountChannelId($auth);
|
||
if ($selfChannelId > 0) {
|
||
$ids[] = $selfChannelId;
|
||
}
|
||
|
||
return array_values(array_unique($ids));
|
||
}
|
||
|
||
/**
|
||
* 当前管理员账号上的 channel_id
|
||
*/
|
||
public static function resolveAdminAccountChannelId(Auth $auth): int
|
||
{
|
||
if (!$auth->isLogin()) {
|
||
return 0;
|
||
}
|
||
$uid = (int) $auth->id;
|
||
if ($uid <= 0) {
|
||
return 0;
|
||
}
|
||
$value = Db::name('admin')->where('id', $uid)->value('channel_id');
|
||
if ($value === null || $value === '') {
|
||
return 0;
|
||
}
|
||
|
||
return (int) $value;
|
||
}
|
||
|
||
/**
|
||
* 当前管理员所属角色组上绑定的渠道 ID(去重)
|
||
*
|
||
* @return array<int, int>
|
||
*/
|
||
public static function resolveBoundGroupChannelIds(Auth $auth): array
|
||
{
|
||
$uid = (int) $auth->id;
|
||
if ($uid <= 0) {
|
||
return [];
|
||
}
|
||
$groupIds = Db::name('admin_group_access')->where('uid', $uid)->column('group_id');
|
||
if ($groupIds === []) {
|
||
return [];
|
||
}
|
||
|
||
$rows = Db::name('admin_group')
|
||
->where('id', 'in', $groupIds)
|
||
->whereNotNull('channel_id')
|
||
->where('channel_id', '>', 0)
|
||
->column('channel_id');
|
||
|
||
$ids = [];
|
||
foreach ($rows as $cid) {
|
||
$ids[] = (int) $cid;
|
||
}
|
||
|
||
return array_values(array_unique($ids));
|
||
}
|
||
|
||
/**
|
||
* 列表按 channel_id 过滤时使用的 ID;null=不过滤
|
||
*
|
||
* @return array<int, int>|null
|
||
*/
|
||
public static function channelIdFilterForQuery(Auth $auth): ?array
|
||
{
|
||
return self::readableChannelIds($auth);
|
||
}
|
||
}
|