diff --git a/backend/views/roles.py b/backend/views/roles.py index 9c7392d..a6b0da4 100644 --- a/backend/views/roles.py +++ b/backend/views/roles.py @@ -144,8 +144,8 @@ class GetRolePermissionView(APIView): if kefu is None: return permissions # 直接返回错误响应 - # 2. 检查是否有 000001 权限 - if '000001' not in permissions: + from jituan.services.admin_context import can_access_admin_user_management + if not can_access_admin_user_management(request.user, permissions): return Response({'code': 403, 'msg': '您无权访问此页面'}) # 3. 获取所有权限 @@ -410,7 +410,8 @@ class GetAdminUserListView(APIView): kefu, permissions = verify_kefu_permission(request, username) if kefu is None: return permissions - if '000001' not in permissions: + from jituan.services.admin_context import can_access_admin_user_management + if not can_access_admin_user_management(request.user, permissions): return Response({'code': 403, 'msg': '您无权访问此页面'}) phone = request.data.get('phone', '').strip() @@ -541,7 +542,8 @@ class GetAdminRolesView(APIView): kefu, permissions = verify_kefu_permission(request, username) if kefu is None: return permissions - if '000001' not in permissions: + from jituan.services.admin_context import can_access_admin_user_management + if not can_access_admin_user_management(request.user, permissions): return Response({'code': 403, 'msg': '您无权访问此页面'}) from jituan.services.admin_context import can_manage_admin_assignments, get_manageable_club_ids @@ -588,7 +590,8 @@ class GetAdminRolesView(APIView): kefu, permissions = verify_kefu_permission(request, username) if kefu is None: return permissions - if '000001' not in permissions: + from jituan.services.admin_context import can_access_admin_user_management + if not can_access_admin_user_management(request.user, permissions): return Response({'code': 403, 'msg': '您无权访问此页面'}) # 筛选条件 @@ -659,7 +662,11 @@ class ModifyAdminUserView(APIView): if kefu is None: return permissions - from jituan.services.admin_context import can_manage_admin_assignments, can_manage_roles_for_club + from jituan.services.admin_context import ( + can_manage_admin_assignments, + can_manage_roles_for_club, + can_access_admin_user_management, + ) club_assign_actions = {'add_club_assignment', 'remove_club_assignment'} role_manage_actions = {'add_user_roles', 'remove_user_role'} @@ -667,8 +674,9 @@ class ModifyAdminUserView(APIView): if not can_manage_admin_assignments(request.user, permissions): return Response({'code': 403, 'msg': '无权分配俱乐部任职'}) elif action in role_manage_actions: - pass - elif '000001' not in permissions: + if not can_access_admin_user_management(request.user, permissions): + return Response({'code': 403, 'msg': '您无权管理角色分配'}) + elif not can_manage_admin_assignments(request.user, permissions) and '000001' not in permissions: return Response({'code': 403, 'msg': '您无权进行此操作'}) target_yonghuid = request.data.get('yonghuid', '').strip() @@ -726,6 +734,10 @@ class ModifyAdminUserView(APIView): if not role: missing.append(rc) continue + role_club = (getattr(role, 'ClubID', None) or '').strip() + if role_club and role_club != bind_club_id: + missing.append(rc) + continue _, created = UserRole.objects.get_or_create( UserUUID=target_user.UserUUID, RoleUUID=role.RoleUUID, @@ -822,8 +834,19 @@ class AddAdminUserView(APIView): kefu, permissions = verify_kefu_permission(request, username) if kefu is None: return permissions - if '000001' not in permissions: - return Response({'code': 403, 'msg': '您无权进行此操作'}) + + from jituan.services.admin_context import ( + can_manage_admin_assignments, + can_manage_roles_for_club, + ) + from jituan.services.club_context import resolve_club_id_from_request + + target_club_id = resolve_club_id_from_request(request) + if not ( + can_manage_admin_assignments(request.user, permissions) + or can_manage_roles_for_club(request.user, permissions, target_club_id) + ): + return Response({'code': 403, 'msg': '您无权在该俱乐部添加用户'}) phone = request.data.get('phone', '').strip() password = request.data.get('password', '').strip() @@ -836,11 +859,8 @@ class AddAdminUserView(APIView): if len(password) < 6 or len(erjimima) < 6: return Response({'code': 400, 'msg': '密码和二级密码至少6位'}) - from jituan.services.club_context import resolve_club_id_from_request from jituan.services.club_rbac import resolve_roles_for_binding - target_club_id = resolve_club_id_from_request(request) - # 校验手机号是否已被后台客服占用(同俱乐部优先) existing_kefu = User.query.filter( Phone=phone, KefuProfile__isnull=False diff --git a/jituan/services/admin_context.py b/jituan/services/admin_context.py index 181a72e..ae6188f 100644 --- a/jituan/services/admin_context.py +++ b/jituan/services/admin_context.py @@ -213,6 +213,20 @@ def get_manageable_club_ids(user, permissions=None): } +def can_access_admin_user_management(user, permissions=None): + """ + 是否可访问「后台用户」页(列表、按俱乐部分配功能角色)。 + 系统超管 / 000001 / 集团高管 / 任一俱乐部超管均可。 + """ + if is_system_super_admin(user): + return True + if permissions and '000001' in permissions: + return True + if can_manage_admin_assignments(user, permissions): + return True + return bool(get_manageable_club_ids(user, permissions)) + + def _pack(scope, club_id, is_group_admin, assignments, clubs, can_switch_club, role_code, role_name): allowed_club_ids = sorted({ diff --git a/jituan/services/club_rbac.py b/jituan/services/club_rbac.py index c5260c1..e901939 100644 --- a/jituan/services/club_rbac.py +++ b/jituan/services/club_rbac.py @@ -94,10 +94,8 @@ def resolve_role_by_name(role_name, club_id=None): qs = Role.objects.filter(RoleName=name, RoleStatus=1) cid = (club_id or '').strip() if cid: - hit = qs.filter(ClubID=cid).first() - if hit: - return hit - return qs.filter(ClubID='').first() or qs.first() + return qs.filter(ClubID=cid).first() + return qs.filter(ClubID='').first() def role_uuid_bytes(role_uuid): @@ -192,10 +190,23 @@ def resolve_permission_codes_for_club(user, club_id, allowed_club_ids=None, scop def resolve_effective_permission_codes(user, club_id, scope, allowed_club_ids=None): - """菜单与各业务接口统一权限码:仅当前俱乐部 gvsdsdk 角色,不串其他俱乐部。""" - return resolve_permission_codes_for_club( + """ + 菜单与各业务接口统一权限码:当前俱乐部 gvsdsdk 角色。 + 单俱乐部任职且 gvsdsdk 为空时,兜底合并旧 user_role 表(兼容未迁移账号)。 + """ + from backend.utils import _legacy_backend_role_permissions + + codes = resolve_permission_codes_for_club( user, club_id, allowed_club_ids, scope=scope, ) + if codes: + return codes + allowed = {c for c in (allowed_club_ids or []) if c} + if len(allowed) <= 1: + legacy_codes, _ = _legacy_backend_role_permissions(getattr(user, 'Phone', '')) + if legacy_codes: + return list(legacy_codes) + return [] def user_bound_role_names(user, club_id=None, scope=None, allowed_club_ids=None): diff --git a/jituan/services/kefu_menu.py b/jituan/services/kefu_menu.py index ed69e10..65dabe8 100644 --- a/jituan/services/kefu_menu.py +++ b/jituan/services/kefu_menu.py @@ -6,6 +6,7 @@ from backend.utils import _AllPermissions, verify_kefu_permission from jituan.models import KefuMenuPage from jituan.services.admin_context import ( build_admin_club_context, + can_access_admin_user_management, can_manage_admin_assignments, get_allowed_club_ids, is_system_super_admin, @@ -32,6 +33,9 @@ def _page_visible(page, permissions, user): if page.require_group_manage: return can_manage_admin_assignments(user) + if getattr(page, 'require_admin_user_manage', False): + return can_access_admin_user_management(user, permissions) + if page.require_super: return _has_super_perm(permissions) or is_system_super_admin(user) @@ -46,8 +50,8 @@ def _page_visible(page, permissions, user): def _permission_codes_list(permissions): - if _is_super_permissions(permissions): - return ['000001'] + if isinstance(permissions, _AllPermissions): + return list(dict.fromkeys(permissions)) if len(permissions) else ['000001'] return list(permissions) if permissions else [] @@ -64,6 +68,7 @@ def _builtin_menu_pages(): perm_codes=row.get('perm_codes', []), require_super=row.get('require_super', False), require_group_manage=row.get('require_group_manage', False), + require_admin_user_manage=row.get('require_admin_user_manage', False), )) return pages @@ -145,6 +150,7 @@ def build_menu_access_payload(request, username=None): 'yonghuid': getattr(request.user, 'UserUID', '') or '', 'club_id': club_id, 'club_scope': scope, + 'effective_club_id': club_id, 'can_switch_club': bool(club_ctx.get('can_switch_club')), 'is_group_admin': bool(club_ctx.get('is_group_admin')), 'menu_ready': True, diff --git a/jituan/services/kefu_menu_definitions.py b/jituan/services/kefu_menu_definitions.py index 2858772..7448af6 100644 --- a/jituan/services/kefu_menu_definitions.py +++ b/jituan/services/kefu_menu_definitions.py @@ -55,7 +55,7 @@ KEFU_MENU_ROW_DEFS = [ {'page_id': 'admin.club-config', 'name': '俱乐部密钥配置', 'path': '/admin/club-config', 'parent_id': 'admin', 'sort_order': 73, 'require_group_manage': True}, {'page_id': 'admin.user', 'name': '后台用户', 'path': '/admin/user', 'parent_id': 'admin', 'sort_order': 74, - 'require_super': True}, + 'require_admin_user_manage': True}, {'page_id': 'admin.operation-log', 'name': '操作日志', 'path': '/admin/operation-log', 'parent_id': 'admin', 'sort_order': 75, 'perm_codes': ['czrz666']}, {'page_id': 'punishment', 'name': '处罚管理', 'path': '/punishment', 'parent_id': '', 'sort_order': 80, diff --git a/users/views/kefu_orders.py b/users/views/kefu_orders.py index 533bd83..42fa2fa 100644 --- a/users/views/kefu_orders.py +++ b/users/views/kefu_orders.py @@ -131,11 +131,10 @@ class KefuGetOrderListView(APIView): return Response({'code': 400, 'msg': '缺少username'}) # 2. 公共权限校验 - kefu, permissions = verify_kefu_permission(request, username) + kefu, permissions = verify_kefu_permission(request, None) if kefu is None: return permissions - # 3. 检查平台订单管理权限(002ab) if not has_perm_code(permissions, '002ab'): return Response({'code': 403, 'msg': '您无权查看平台订单列表'}) @@ -299,10 +298,8 @@ class KefuGetShangjiaOrderListView(APIView): if not username: return Response({'code': 400, 'msg': '缺少username'}) - # 2. 权限校验(与 menu-access 完全一致:须 002ac) - kefu, permissions = verify_kefu_permission( - request, getattr(request.user, 'Phone', '') or None, - ) + # 2. 权限校验(与 menu-access 同一算法、同一用户) + kefu, permissions = verify_kefu_permission(request, None) if kefu is None: return permissions