diff --git a/app/common/service/AdminChannelScopeService.php b/app/common/service/AdminChannelScopeService.php index 740150d..fd572dc 100644 --- a/app/common/service/AdminChannelScopeService.php +++ b/app/common/service/AdminChannelScopeService.php @@ -8,12 +8,14 @@ use app\admin\library\Auth; use support\think\Db; /** - * 后台管理员渠道数据范围:角色组 channel_id 未绑定时可读全平台;否则按绑定渠道过滤。 + * 后台管理员渠道数据范围: + * - 账号 channel_id 或角色组 channel_id 任一绑定 → 仅可读对应渠道(优先于「查看所有渠道」) + * - 均未绑定且拥有 viewAllChannels → 全平台只读 */ class AdminChannelScopeService { /** - * 是否具备全平台只读范围(超管 / 角色组均未绑定渠道 / 拥有查看所有渠道权限) + * 是否具备全平台只读范围(超管 / 未绑定任何渠道且拥有查看所有渠道) */ public static function hasGlobalReadScope(Auth $auth): bool { @@ -23,8 +25,8 @@ class AdminChannelScopeService if ($auth->isSuperAdmin()) { return true; } - if (self::resolveBoundGroupChannelIds($auth) === []) { - return true; + if (self::resolveEffectiveChannelIds($auth) !== []) { + return false; } return self::hasViewAllChannelsPermission($auth); @@ -40,23 +42,58 @@ class AdminChannelScopeService if (!$auth->isLogin()) { return [0]; } - if (self::hasGlobalReadScope($auth)) { + if ($auth->isSuperAdmin()) { return null; } - $ids = self::resolveBoundGroupChannelIds($auth); + $ids = self::resolveEffectiveChannelIds($auth); if ($ids !== []) { return $ids; } - $selfChannelId = (int) Db::name('admin')->where('id', (int) $auth->id)->value('channel_id'); - if ($selfChannelId > 0) { - return [$selfChannelId]; + if (self::hasViewAllChannelsPermission($auth)) { + return null; } return [0]; } + /** + * 管理员实际绑定的渠道(角色组 channel_id + 账号 admin.channel_id,去重) + * + * @return array + */ + 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(去重) * diff --git a/docs/en/channel-admin-guide.md b/docs/en/channel-admin-guide.md index f4db931..d110530 100644 --- a/docs/en/channel-admin-guide.md +++ b/docs/en/channel-admin-guide.md @@ -24,13 +24,9 @@ List filters: **All / With balance / No balance / Enabled only / Disabled only** `AdminChannelScopeService` applies to list and stats: -**Global read** (all channels) if any of: +**Bound channel wins** (only those channels) if `admin.channel_id` > 0 and/or any role group has `channel_id` — even with `viewAllChannels`. -- Super admin (`*`) -- No `admin_group.channel_id` bound for the user’s groups -- Button permission `channel/viewAllChannels` - -Otherwise: bound group channel IDs, or `admin.channel_id`, or empty. +**Global read** only when: super admin, **or** no channel binding on account and all groups **and** `viewAllChannels`. **Write** (add/edit/delete/manual settle DB) stays on **writable** channels only; `viewAllChannels` does not expand write scope. diff --git a/docs/分红说明文档.md b/docs/分红说明文档.md index 425ec7f..09a4f53 100644 --- a/docs/分红说明文档.md +++ b/docs/分红说明文档.md @@ -50,7 +50,7 @@ | 渠道分红参数 | `/admin/channel` | `agent_mode`、返水/联营比例、结算周期等;详见 [渠道管理后台说明.md](./渠道管理后台说明.md) | | 代理树与分红比例 | `/admin/auth/admin` | 树形列表;配置上级代理、分红比例、渠道归属 | | 渠道筛选 | 管理员列表公共搜索 | 超管可按渠道筛选 | -| 渠道列表可见范围 | `/admin/channel` | 超管 / 角色组未绑渠道 / `viewAllChannels` → 全平台只读;否则仅绑定渠道 | +| 渠道列表可见范围 | `/admin/channel` | 账号或角色组绑定渠道 → 仅该渠道;均未绑定且 `viewAllChannels` → 全平台;超管不限 | | 数据可见范围 | 管理员列表 | 非超管仅见 **本人 + 全部下级**,不见其他代理线 | | 结算执行 | `/admin/channel` 手动结算 / 定时任务 | **超管**或 `channel/manualSettle`(渠道可读);批量结算仍仅超管;结算即发放至 `admin_wallet` | diff --git a/docs/渠道管理后台说明.md b/docs/渠道管理后台说明.md index ad9e146..5a255ba 100644 --- a/docs/渠道管理后台说明.md +++ b/docs/渠道管理后台说明.md @@ -26,17 +26,22 @@ 由 `app/common/service/AdminChannelScopeService.php` 统一判定,列表与统计均遵守: -| 条件(满足任一即**全平台渠道可读**) | 说明 | -|--------------------------------------|------| +**优先规则:只要绑定了渠道,就只能看绑定渠道**(即使勾选了「查看所有渠道」): + +- 本人 `admin.channel_id` > 0,或 +- 任一所属角色组 `admin_group.channel_id` > 0 + +上述情况合并去重后作为可读渠道 ID 列表。 + +**全平台只读**(仅当同时满足): + +| 条件 | 说明 | +|------|------| | 超管 | 权限含 `*` | -| 角色组均未绑定 `channel_id` | 该管理员所属角色组 `admin_group.channel_id` 均为空 | -| 拥有「查看所有渠道」 | 按钮权限 `channel/viewAllChannels` | +| 未绑定任何渠道 | 账号 `channel_id` 为空且所有角色组 `channel_id` 为空 | +| 且拥有「查看所有渠道」 | 按钮权限 `channel/viewAllChannels` | -否则仅可读: - -- 角色组绑定的 `channel_id` 集合,或 -- 本人 `admin.channel_id`(若 > 0),或 -- 无绑定且无账号渠道时返回空列表。 +未绑定渠道且无 `viewAllChannels` 时,渠道列表为空。 **写操作**(新增/编辑/删除渠道、手动结算写库)仍限制在**可写渠道**:角色组绑定渠道 + 账号 `channel_id`,**不**因「查看所有渠道」而扩大写范围。 @@ -156,3 +161,4 @@ |------|------| | 2026-05-30 | 新增:查看所有渠道、下注/分红查看按钮;下注记录弹窗列与筛选;移动端弹窗适配 | | 2026-05-30 | 手动结算:拥有 `channel/manualSettle` 且渠道可读即可操作(不再仅限超管展示按钮) | +| 2026-05-30 | 修复:账号已设 `channel_id` 时不再因角色组未绑渠道而误判为全平台可见 |