diff --git a/app/api/dependencies.py b/app/api/dependencies.py index e7959ab..10b5707 100644 --- a/app/api/dependencies.py +++ b/app/api/dependencies.py @@ -27,25 +27,10 @@ def get_db(request: Request) -> Database: return request.app.state.db -async def _resolve_identity(user: dict, identity_id: str | None, db: Database) -> dict: - """按令牌携带的 identity_id 装配当前身份;缺失则回退到 users.role 单角色。 - - 身份即权限来源:从 user_identities 取 role/sub_role/org/region, - 并据此计算 permissions 与数据范围(全异步,角色变更即时生效)。 - """ - if identity_id: - ident = await db.identities.get_for_user(identity_id, user["id"]) - if ident and ident.get("status") == "active": - user["identity_id"] = ident["id"] - user["port"] = ident["port"] - user["role"] = ident["role"] - user["sub_role"] = ident.get("sub_role") - user["org_id"] = ident.get("org_id") - user["region_id"] = ident.get("region_id") - user["identity_name"] = ident.get("name", "") - +async def _resolve_identity(user: dict, db: Database) -> dict: + """单账号角色(多身份已收敛):role 由 users.role 提供,仅计算权限与数据范围。""" user["permissions"] = await db.roles.permissions_for( - user.get("role", "opc_member"), user.get("sub_role"), + user.get("role", "opc_member"), None, ) user["scope_region_ids"] = await db.regions.visible_region_ids(user.get("region_id")) user["scope_level"] = await db.regions.level(user.get("region_id")) @@ -77,7 +62,7 @@ async def get_current_user( if user is None or user.get("status") != "active": raise HTTPException(status_code=401, detail="Invalid or expired token") - return await _resolve_identity(user, payload.get("identity_id"), db) + return await _resolve_identity(user, db) async def optional_current_user( diff --git a/app/api/routers/auth.py b/app/api/routers/auth.py index a5a789c..59e6495 100644 --- a/app/api/routers/auth.py +++ b/app/api/routers/auth.py @@ -219,19 +219,19 @@ async def login(req: LoginRequest, db: Database = Depends(get_db)): if user.get("status") != "active": raise HTTPException(status_code=403, detail="Account is disabled") - identities = await db.identities.list_for_user(user["id"], active_only=True) - identity = identities[0] if len(identities) == 1 else None - token_record = await _issue_token(db, user, req.expires_in, identity=identity) - profile = await _profile_for(user, identity, db) + # 账号单一角色(去多身份):不再按 user_identities 选身份,按 users.role 解析账号类型。 + identity = None + token_record = await _issue_token(db, user, req.expires_in, identity=None) + profile = await _profile_for(user, None, db) await db.audit.add( action="login", resource="auth", resource_id=user["id"], - detail=f"login {user['username']} ({len(identities)} identities)", + detail=f"login {user['username']} (account_type={profile.get('account_type', '')})", user_id=user["id"], ) return LoginResponse( token=token_record["token"], - identities=_identity_summaries(identities), + identities=[], **profile, ) @@ -242,17 +242,12 @@ async def select_identity( user: dict = Depends(get_current_user), db: Database = Depends(get_db), ): - """把当前令牌切换到指定端口身份(该身份须属于当前账号且为启用状态)。""" - ident = await db.identities.get_for_user(req.identity_id, user["id"]) - if ident is None or ident.get("status") != "active": - raise HTTPException(status_code=404, detail="Identity not found or disabled") - - token_record = await _issue_token(db, user, None, identity=ident) - profile = await _profile_for(user, ident, db) - identities = await db.identities.list_for_user(user["id"], active_only=True) + """切换身份(多身份已收敛)——恒按账号单一角色(users.role)签发,忽略 identity_id。""" + token_record = await _issue_token(db, user, None, identity=None) + profile = await _profile_for(user, None, db) return LoginResponse( token=token_record["token"], - identities=_identity_summaries(identities), + identities=[], **profile, ) diff --git a/app/domain/account_types.py b/app/domain/account_types.py index 1eb78bd..cd5b152 100644 --- a/app/domain/account_types.py +++ b/app/domain/account_types.py @@ -20,7 +20,7 @@ ACCOUNT_TYPES = ("operator", "carrier", "opc_member", "service") def account_type(role: str | None) -> str: """把任意(端口)角色归一为四种账号类型之一。非运营/非OPC → service。""" r = (role or "").strip().lower() - if r in ("operator", "operator_internal", "op_admin", "admin"): + if r in ("operator", "operator_internal", "op_admin", "op_super_admin", "superadmin", "admin"): return "operator" if r in ("carrier", "park", "park_staff", "carrier_staff"): return "carrier" diff --git a/app/infrastructure/repositories.py b/app/infrastructure/repositories.py index a80606e..d7b7026 100644 --- a/app/infrastructure/repositories.py +++ b/app/infrastructure/repositories.py @@ -588,9 +588,9 @@ class UserRepository: profile["topics"] = _parse_topics(user.get("topics", "")) profile["role"] = user.get("role", "opc_member") profile["sub_role"] = None # 子角色已停用 - atype = user.get("account_type") or _acct_type(user.get("role")) + atype = _acct_type(user.get("role")) profile["account_type"] = atype - profile["account_type_label"] = user.get("account_type_label") or _acct_label(atype) + profile["account_type_label"] = _acct_label(atype) profile["org_id"] = user.get("org_id") profile["region_id"] = user.get("region_id") profile["permissions"] = user.get("permissions", []) diff --git a/app/infrastructure/seed.py b/app/infrastructure/seed.py index af15254..d41abde 100644 --- a/app/infrastructure/seed.py +++ b/app/infrastructure/seed.py @@ -128,12 +128,45 @@ PERMISSIONS = [ ("action:content.manage", "内容管理(建发)", "action", "operator"), ("action:config.manage", "系统配置(修改)", "action", "operator"), ("action:settlement.manage", "结算管理", "action", "operator"), + # 平台运营(operator)功能页 + ("menu:admin_courses", "课程管理", "menu", "admin"), + ("menu:admin_activities", "活动管理", "menu", "admin"), + ("menu:admin_bookings", "报名管理", "menu", "admin"), + ("menu:admin_tests", "测评管理", "menu", "admin"), + ("menu:admin_surveys", "调研结果", "menu", "admin"), + ("menu:admin_policies", "政策结果", "menu", "admin"), + ("menu:admin_plans", "流程启动", "menu", "admin"), + ("menu:admin_compute", "算力管理", "menu", "admin"), + ("menu:admin_content", "资讯管理", "menu", "admin"), + ("menu:admin_tasks", "任务管理", "menu", "admin"), + ("menu:admin_providers", "服务商管理", "menu", "admin"), + ("menu:admin_config", "系统配置", "menu", "admin"), + ("menu:admin_park", "平台园区", "menu", "admin"), + ("menu:admin_park_screens", "屏幕绑定", "menu", "admin"), + ("menu:opc_cert", "OPC认证", "menu", "admin"), + ("menu:admission", "入驻审核", "menu", "admin"), + ("menu:park_transfer", "转园审核", "menu", "admin"), + # 园区(carrier)工作台 + ("menu:park_screens", "屏幕管理", "menu", "carrier"), + ("menu:park_screen", "大屏控制台", "menu", "carrier"), + ("menu:park_companies", "入驻企业", "menu", "carrier"), + ("menu:park_kb", "园区知识库", "menu", "carrier"), + ("menu:park_agent", "园区智能体", "menu", "carrier"), + ("menu:park_data", "大屏数据", "menu", "carrier"), + ("menu:park_vision", "视频识别", "menu", "carrier"), + ("menu:park_admissions", "入园申请", "menu", "carrier"), + ("menu:park_transfers", "转园申请", "menu", "carrier"), ] # role_id -> [permission_id] ROLE_PERMISSIONS: dict[str, list[str]] = { "opc_member": ["menu:opc_dashboard"], - "carrier": ["menu:carrier_dashboard", "action:org.manage"], + "carrier": [ + "menu:carrier_dashboard", "action:org.manage", + "menu:park_screens", "menu:park_screen", "menu:park_companies", "menu:park_kb", + "menu:park_agent", "menu:park_data", "menu:park_vision", + "menu:park_admissions", "menu:park_transfers", + ], "enterprise": ["menu:enterprise_dashboard", "action:org.manage"], "provider": [ "menu:provider_dashboard", "action:org.manage", "action:data.export", @@ -144,7 +177,18 @@ ROLE_PERMISSIONS: dict[str, list[str]] = { "government|gov_district": ["action:data.export"], "government|gov_org_admin": ["action:org.manage"], "government|gov_op_account": ["action:data.export"], - "operator": ["menu:operator_dashboard"], + "operator": [ + "menu:operator_dashboard", + "menu:admin_user_mgmt", "menu:admin_role_mgmt", "menu:audit", "menu:settlements", + "menu:admin_courses", "menu:admin_activities", "menu:admin_bookings", "menu:admin_tests", + "menu:admin_surveys", "menu:admin_policies", "menu:admin_plans", "menu:admin_compute", + "menu:admin_content", "menu:admin_tasks", "menu:admin_providers", "menu:admin_config", + "menu:admin_park", "menu:admin_park_screens", "menu:opc_cert", "menu:admission", "menu:park_transfer", + "action:user.assign_role", "action:user.disable", "action:role.grant_perm", + "action:org.manage", "action:data.export", "action:audit.view", + "action:task.manage", "action:provider.manage", "action:content.manage", + "action:config.manage", "action:settlement.manage", + ], "operator|op_super_admin": [ "menu:admin_user_mgmt", "menu:admin_role_mgmt", "menu:audit", "menu:settlements", "action:user.assign_role", "action:user.disable", "action:role.grant_perm",