/** * 应用级权限管理 composable * * 管理当前用户在各应用中的角色权限,提供: * 1. 开发者中心访问检查 * 2. 可访问应用列表 + 角色映射 * 3. 按角色判断某应用的具体权限 */ import type { AppRole, AppPermissionInfo } from '@/api/app/appUser/model' // ============ 角色层级 ============ /** 角色层级:数字越大权限越高 */ export const ROLE_HIERARCHY: Record = { viewer: 1, developer: 2, admin: 3, owner: 4, } /** 角色中文名 */ export const ROLE_LABEL: Record = { owner: '所有者', admin: '管理员', developer: '开发者', viewer: '只读', } /** 角色颜色(用于 RoleTag) */ export const ROLE_COLOR: Record = { owner: 'gold', admin: 'blue', developer: 'green', viewer: 'default', } // ============ 权限定义 ============ export interface AppPermission { appId: number productName: string productCode?: string icon?: string role: AppRole isOwner: boolean canManageMembers: boolean // owner | admin canEditApp: boolean // owner | admin canDeleteApp: boolean // owner only canSubmitReview: boolean // owner | admin canEditResource: boolean // owner | admin | developer canViewSensitive: boolean // owner | admin | developer canCreateApiKey: boolean // owner | admin | developer canEditConfig: boolean // owner | admin canTriggerBuild: boolean // owner | admin | developer } /** 根据 role 计算权限字段 */ function buildPermission(info: AppPermissionInfo): AppPermission { const { role } = info const isOwner = role === 'owner' const isAtLeastAdmin = isOwner || role === 'admin' const isAtLeastDeveloper = isAtLeastAdmin || role === 'developer' return { appId: info.appId, productName: info.productName, productCode: info.productCode, icon: info.icon, role, isOwner, canManageMembers: isAtLeastAdmin, canEditApp: isAtLeastAdmin, canDeleteApp: isOwner, canSubmitReview: isAtLeastAdmin, canEditResource: isAtLeastDeveloper, canViewSensitive: isAtLeastDeveloper, canCreateApiKey: isAtLeastDeveloper, canEditConfig: isAtLeastAdmin, canTriggerBuild: isAtLeastDeveloper, } } // ============ 全局状态(模块级单例) ============ const appPermissionsMap = ref>(new Map()) const isPlatformDeveloper = ref(false) const hasCheckedAccess = ref(false) const loading = ref(false) // 用户信息(供其他组件复用,避免重复请求) const user = ref<{ userId?: number username?: string nickname?: string phone?: string mobile?: string type?: number } | null>(null) /** * 设置当前用户信息(布局中调用) */ function setCurrentUser(userInfo: typeof user.value) { user.value = userInfo } /** * 获取当前用户信息 */ function getCurrentUser() { return user.value } // ============ 核心方法 ============ /** * 检查用户是否有开发者中心访问权限 * 并自动加载可访问的应用列表 */ async function checkDeveloperAccess(): Promise<{ accessible: boolean isPlatformDeveloper: boolean hasJoinedApps: boolean }> { if (loading.value) return { accessible: false, isPlatformDeveloper: false, hasJoinedApps: false } loading.value = true try { // 尝试获取可访问应用列表(后端接口:GET /api/app/app-user/check-access) const { checkAppAccess } = await import('@/api/app/appUser') const res = await checkAppAccess() if (res?.accessible) { isPlatformDeveloper.value = res.isPlatformDeveloper ?? false hasCheckedAccess.value = true // 如果返回了可访问应用列表,直接缓存 if (res.apps?.length) { const newMap = new Map() for (const info of res.apps) { newMap.set(info.appId, buildPermission(info)) } appPermissionsMap.value = newMap } return { accessible: true, isPlatformDeveloper: res.isPlatformDeveloper ?? false, hasJoinedApps: (res.apps?.length ?? 0) > 0, } } return { accessible: false, isPlatformDeveloper: false, hasJoinedApps: false } } catch { // 接口失败时降级:如果 localStorage 有 UserId 且是 type=2,仍允许访问 if (import.meta.client) { const userType = localStorage.getItem('UserType') if (userType === '2') { isPlatformDeveloper.value = true hasCheckedAccess.value = true return { accessible: true, isPlatformDeveloper: true, hasJoinedApps: false } } } return { accessible: false, isPlatformDeveloper: false, hasJoinedApps: false } } finally { loading.value = false } } /** * 加载用户所有可访问应用的权限 * 后端接口:GET /api/app/product/accessible */ async function loadAppPermissions(): Promise> { try { const { getMyAccessibleApps } = await import('@/api/app/appProduct') const apps = await getMyAccessibleApps() const newMap = new Map() for (const app of apps) { const role = (app.myRole as AppRole) || 'viewer' newMap.set(app.productId!, { appId: app.productId!, productName: app.productName || '', productCode: app.productCode, icon: app.icon, role, ...(buildPermission({ appId: app.productId!, productName: app.productName || '', role } as AppPermissionInfo)), }) } appPermissionsMap.value = newMap return newMap } catch { console.warn('[useAppPermission] 加载应用权限失败') return appPermissionsMap.value } } /** * 设置单个应用的权限缓存 */ function setAppPermission(info: AppPermissionInfo) { const permission = buildPermission(info) appPermissionsMap.value.set(info.appId, permission) } /** * 获取指定应用的权限 */ function getAppPermission(appId: number | undefined | null): AppPermission | null { if (!appId) return null return appPermissionsMap.value.get(appId) ?? null } /** * 检查指定应用是否拥有某项权限 */ function hasPermission( appId: number | undefined | null, permission: keyof AppPermission, ): boolean { const perm = getAppPermission(appId) if (!perm) return false return !!perm[permission] } /** * 检查当前用户在指定应用中的角色是否 >= 某个级别 */ function hasRole(appId: number | undefined | null, minRole: AppRole): boolean { const perm = getAppPermission(appId) if (!perm) return false return ROLE_HIERARCHY[perm.role] >= ROLE_HIERARCHY[minRole] } /** * 清空权限缓存(登出时调用) */ function clearPermissions() { appPermissionsMap.value.clear() isPlatformDeveloper.value = false hasCheckedAccess.value = false } // ============ Computed ============ /** 可访问的应用 ID 列表 */ const accessibleAppIds = computed(() => [...appPermissionsMap.value.keys()]) /** 是否已检查过访问权限 */ const isChecked = computed(() => hasCheckedAccess.value) /** 是否正在加载 */ const isLoading = computed(() => loading.value) /** 权限不足时的提示文字 */ function getNoPermissionTip(role?: AppRole): string { const roleName = role ? ROLE_LABEL[role] : '当前角色' return `当前身份为「${roleName}」,无法执行此操作。如需更多权限,请联系应用管理员。` } // ============ 敏感信息遮罩 ============ /** * 遮罩敏感字段值 * @param value 原始值 * @param canView 是否有查看权限 * @param maskLength 遮罩长度,默认 6 个 * */ function maskSensitiveValue(value: string | null | undefined, canView: boolean, maskLength = 6): string { if (canView) return value || '' if (!value) return '' const mask = '*'.repeat(maskLength) // 对于较短的值直接全部遮罩,较长的值显示前几个字符 if (value.length <= maskLength) return mask return value.slice(0, 4) + mask } // ============ 组合式函数导出 ============ export function useAppPermission() { return { // 状态 user, appPermissions: appPermissionsMap, isPlatformDeveloper: readonly(isPlatformDeveloper), isChecked: readonly(isChecked), isLoading: readonly(isLoading), // 方法 setCurrentUser, getCurrentUser, checkDeveloperAccess, loadAppPermissions, setAppPermission, getAppPermission, hasPermission, hasRole, clearPermissions, getNoPermissionTip, // 工具 accessibleAppIds, maskSensitiveValue, } }