Files
template-nuxt4/app/composables/useResourceAccess.ts
2026-04-29 01:33:33 +08:00

135 lines
4.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 资源中心协作权限 composable
*
* 权限级别:
* 0 - 无权限
* 1 - 基础查看:名称/IP/端口/状态(所有团队成员)
* 2 - 连接查看用户名、Host、连接方式技术负责人及以上
* 3 - 完全权限:密码、私钥、编辑/删除(仅资源 Owner
*/
import type { AppResource } from '@/api/app/appResource/model'
export type ResourceAccessLevel = 0 | 1 | 2 | 3
/**
* 判断当前用户是否是资源所有者
* 后端在返回时会带 ownerUserId 字段,前端基于 localStorage UserId 判断
*/
export function isResourceOwner(resource: AppResource): boolean {
if (!import.meta.client) return false
const currentUserId = localStorage.getItem('UserId')
if (!currentUserId) return false
return Number(currentUserId) === Number(resource.ownerUserId)
|| Number(currentUserId) === Number(resource.userId)
}
/**
* 获取当前用户对某资源的访问级别
* - 后端若已计算 accessLevel直接使用
* - 否则前端保底逻辑Owner=3其余=1
*/
export function getResourceAccessLevel(resource: AppResource): ResourceAccessLevel {
// 后端已计算的权限级别,优先使用
if (resource.accessLevel !== undefined) {
return resource.accessLevel
}
// 降级:判断是否是 owner
return isResourceOwner(resource) ? 3 : 1
}
/** 是否有基础查看权限(所有人) */
export function canViewBasic(resource: AppResource): boolean {
return getResourceAccessLevel(resource) >= 1
}
/** 是否有连接信息查看权限用户名、Host 等) */
export function canViewConnection(resource: AppResource): boolean {
return getResourceAccessLevel(resource) >= 2
}
/** 是否有完整权限(编辑、删除、查看密码/私钥) */
export function canViewSensitive(resource: AppResource): boolean {
return getResourceAccessLevel(resource) >= 3
}
/** 是否能编辑/删除该资源 */
export function canManageResource(resource: AppResource): boolean {
return getResourceAccessLevel(resource) >= 3
}
/** 脱敏占位符:判断某字段是否已被后端脱敏 */
export function isMaskedValue(value: string | null | undefined): boolean {
if (!value) return false
return value === '******' || value === '***' || /^\*{3,}$/.test(value)
}
/**
* 资源权限 composablereactive接受 computed/ref 的资源对象)
*/
export function useResourceAccess(resource: AppResource | (() => AppResource | null | undefined)) {
const getResource = (): AppResource | null | undefined =>
typeof resource === 'function' ? resource() : resource
const accessLevel = computed<ResourceAccessLevel>(() => {
const r = getResource()
if (!r) return 0
return getResourceAccessLevel(r)
})
const isOwner = computed(() => {
const r = getResource()
if (!r) return false
return isResourceOwner(r)
})
const canBasic = computed(() => accessLevel.value >= 1)
const canConnection = computed(() => accessLevel.value >= 2)
const canSensitive = computed(() => accessLevel.value >= 3)
const canManage = computed(() => accessLevel.value >= 3)
/** 权限级别对应的文字说明 */
const accessLevelText = computed(() => {
switch (accessLevel.value) {
case 3: return '完全权限'
case 2: return '连接权限'
case 1: return '查看权限'
default: return '无权限'
}
})
/** 权限不足时的提示文字 */
const noPermissionTip = computed(() =>
isOwner.value ? '' : '如需查看完整信息,请联系资源创建者',
)
return {
accessLevel,
isOwner,
canBasic,
canConnection,
canSensitive,
canManage,
accessLevelText,
noPermissionTip,
}
}
/**
* 批量处理资源列表,为每个资源附加 isOwner 字段
* 调用时机:后端未返回 accessLevel 时的前端降级处理
*/
export function enrichResourcesWithPermission<T extends AppResource>(resources: T[]): T[] {
if (!import.meta.client) return resources
const currentUserId = localStorage.getItem('UserId')
if (!currentUserId) return resources
return resources.map(r => ({
...r,
isOwner: Number(currentUserId) === Number(r.ownerUserId) || Number(currentUserId) === Number(r.userId),
accessLevel: r.accessLevel ?? (
(Number(currentUserId) === Number(r.ownerUserId) || Number(currentUserId) === Number(r.userId))
? 3
: 1
),
}))
}