Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 | 2x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 1x 9x 9x 9x 9x 10x 13x 13x 13x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 12x 12x 9x 9x 9x 9x 9x 8x 9x 9x 9x 3x 9x 9x 9x 3x 9x 9x 9x 8x 8x 9x 9x 1x 1x 1x 1x 1x 4x 4x 4x 1x 1x 1x 4x 4x 4x 4x 4x 9x 11x 9x | import { computed, ref, watch } from 'vue'
import { defineStore } from 'pinia'
import { loadDataApi } from '@/services/api'
import { useAuthStore } from './auth'
/**
* 权限 store:负责拉取模块 / 用户授权数据并暴露访问与功能点判断。
* 逻辑与 fms-vue-old2 完全一致:
* - 管理员账号(g3soft)提权,直接可见全部启用模块
* - 普通用户按 b_user_module / b_user_power 授权
* - 同一主体(orgId:userId)加载结果去重,并发请求复用
*/
export const usePermissionStore = defineStore('permissions', () => {
const authStore = useAuthStore()
const loadedPrincipalKey = ref('')
const modules = ref([])
const grantedPageIds = ref([])
const moduleCodes = ref([])
const powerCodes = ref([])
let loadingPromise = null
let loadingPrincipalKey = ''
let loadVersion = 0
const moduleByCode = computed(
() => new Map(modules.value.map((m) => [String(m.b_code || ''), m])),
)
const moduleById = computed(() => new Map(modules.value.map((m) => [String(m.b_id || ''), m])))
const grantedPageSet = computed(() => new Set(grantedPageIds.value))
const powerSet = computed(() => new Set(powerCodes.value))
const isG3soft = computed(() => {
return (
String(authStore.loginInfo.user?.account || '')
.trim()
.toLowerCase() === 'g3soft'
)
})
/**
* 加载权限数据;重复调用对同一主体去重,并发调用共享同一请求。
*/
async function load() {
const userId = String(authStore.loginInfo.user?.id || '')
const principalKey = `${String(authStore.userInfo.orgId || '')}:${userId}`
// 管理员提权:直接加载全部启用模块,不查授权表
if (isG3soft.value) {
const elevatedKey = `g3soft:${principalKey}`
Iif (loadedPrincipalKey.value === elevatedKey) return
loadingPromise = null
loadingPrincipalKey = ''
const requestVersion = ++loadVersion
const request = loadDataApi('s_module', 'b_canuse = 1', 'b_id ASC')
.then((res) => {
Iif (requestVersion !== loadVersion) return
modules.value = res.data || []
grantedPageIds.value = []
moduleCodes.value = []
powerCodes.value = []
loadedPrincipalKey.value = elevatedKey
})
.finally(() => {
Iif (requestVersion !== loadVersion) return
loadingPromise = null
loadingPrincipalKey = ''
})
loadingPromise = request
return request
}
Iif (!/^\d+$/.test(userId)) throw new Error('登录用户 ID 无效,请重新登录')
if (loadedPrincipalKey.value === principalKey) return
Iif (loadingPromise && loadingPrincipalKey === principalKey) return loadingPromise
const requestVersion = ++loadVersion
loadingPrincipalKey = principalKey
const request = Promise.all([
loadDataApi('s_module', 'b_canuse = 1', 'b_id ASC'),
loadDataApi('b_user_module', `b_user_id = ${userId}`, 'b_id ASC'),
loadDataApi('b_user_power', `b_user_id = ${userId}`, 'b_id ASC'),
loadDataApi('s_module_power', 'b_canuse = 1', 'b_id ASC'),
])
.then(([moduleResponse, userModules, userPowers, powers]) => {
if (requestVersion !== loadVersion) return
const activeModules = moduleResponse.data || []
const mById = new Map(activeModules.map((m) => [String(m.b_id), m]))
const pById = new Map(powers.data.map((p) => [String(p.b_id), p]))
const pageIds = userModules.data
.map((item) => String(item.b_module_id || ''))
.filter(Boolean)
modules.value = activeModules
grantedPageIds.value = pageIds
moduleCodes.value = userModules.data
.map((item) => mById.get(String(item.b_module_id))?.b_code)
.filter(Boolean)
powerCodes.value = userPowers.data
.map((item) => pById.get(String(item.b_power_id)))
.filter((p) => Boolean(p))
.map((power) => `${String(power.b_module_id)}.${power.b_code}`)
loadedPrincipalKey.value = principalKey
})
.finally(() => {
if (requestVersion !== loadVersion) return
loadingPromise = null
loadingPrincipalKey = ''
})
loadingPromise = request
return request
}
/**
* 由模块编码向上查找其所属 page 类型模块的 ID。
*/
function resolvePageId(code) {
let module = moduleByCode.value.get(String(code || ''))
const visited = new Set()
while (module) {
const moduleId = String(module.b_id || '')
if (!moduleId || visited.has(moduleId)) return ''
visited.add(moduleId)
if (module.b_module_type === 'page') return moduleId
const parentId = String(module.b_parent_id || '')
module = parentId ? moduleById.value.get(parentId) : undefined
}
return ''
}
/**
* 判断当前用户是否有某模块的访问权限(管理员恒为 true)。
*/
function canAccess(moduleCode) {
Iif (isG3soft.value || !moduleCode) return true
const module = moduleByCode.value.get(String(moduleCode))
Eif (!module) return false
const moduleId = String(module.b_id || '')
const pageId = resolvePageId(moduleCode)
return grantedPageSet.value.has(moduleId) || (!!pageId && grantedPageSet.value.has(pageId))
}
/**
* 判断当前用户是否有某模块的功能点权限。
*/
function canPower(scopeCode, powerCode) {
if (isG3soft.value) return true
const module = moduleByCode.value.get(String(scopeCode || ''))
if (!module || !canAccess(scopeCode)) return false
const moduleId = String(module.b_id || '')
const pageId = resolvePageId(scopeCode || '')
return (
powerSet.value.has(`${moduleId}.${powerCode}`) ||
(!!pageId && powerSet.value.has(`${pageId}.${powerCode}`))
)
}
function clear() {
// 仅当“正在进行中的请求属于别的主体”时才作废它(如切换账号),
// 否则保留进行中请求、只清空已加载数据,交由后续 load 结果填充。
// 这避免登录(setSession 后守卫立即 load)被自身的 watch(clear) 误作废,导致菜单空白。
const userId = String(authStore.loginInfo.user?.id || '')
const principalKey = `${String(authStore.userInfo.orgId || '')}:${userId}`
if (loadingPrincipalKey && loadingPrincipalKey !== principalKey) {
loadVersion++
loadingPromise = null
loadingPrincipalKey = ''
}
loadedPrincipalKey.value = ''
modules.value = []
grantedPageIds.value = []
moduleCodes.value = []
powerCodes.value = []
}
// 登录主体变化(退出/切换账号)时清空权限缓存
watch(
() => [
authStore.userInfo.orgId,
authStore.loginInfo.user?.id,
authStore.loginInfo.user?.account,
authStore.loginInfo.token,
],
clear,
)
return {
load,
canAccess,
canPower,
clear,
modules,
grantedPageIds,
moduleCodes,
powerCodes,
isG3soft,
}
})
|