权限系统开发
This commit is contained in:
parent
05124c2f6e
commit
51604aae64
|
|
@ -15,8 +15,9 @@
|
||||||
v-for="item in items"
|
v-for="item in items"
|
||||||
:key="item.key"
|
:key="item.key"
|
||||||
@click="handleClick(item)"
|
@click="handleClick(item)"
|
||||||
|
v-permission="item.permission"
|
||||||
>
|
>
|
||||||
<view class="icon-wrapper">
|
<view class="icon-wrapper">
|
||||||
<image class="icon-image" :src="item.icon" mode="aspectFit" />
|
<image class="icon-image" :src="item.icon" mode="aspectFit" />
|
||||||
</view>
|
</view>
|
||||||
<text class="item-text">{{ item.text }}</text>
|
<text class="item-text">{{ item.text }}</text>
|
||||||
|
|
@ -34,7 +35,7 @@ import { ref } from 'vue';
|
||||||
import FabPlus from '@/components/FabPlus.vue';
|
import FabPlus from '@/components/FabPlus.vue';
|
||||||
|
|
||||||
const items = ref([
|
const items = ref([
|
||||||
{ key: 'verify', text: '审批管理', icon: '/static/workbench/verify.png' },
|
{ key: 'verify', text: '审批管理', icon: '/static/workbench/verify.png', permission: ['bst:verify:list'] },
|
||||||
// { key: 'customer', text: '客户管理', icon: '/static/workbench/customer.png' },
|
// { key: 'customer', text: '客户管理', icon: '/static/workbench/customer.png' },
|
||||||
{ key: 'project', text: '项目管理', icon: '/static/workbench/project.png' },
|
{ key: 'project', text: '项目管理', icon: '/static/workbench/project.png' },
|
||||||
{ key: 'task', text: '任务管理', icon: '/static/workbench/task.png' },
|
{ key: 'task', text: '任务管理', icon: '/static/workbench/task.png' },
|
||||||
|
|
|
||||||
114
directives/permission.js
Normal file
114
directives/permission.js
Normal file
|
|
@ -0,0 +1,114 @@
|
||||||
|
import { useUserStore } from '@/store/user'
|
||||||
|
|
||||||
|
const ADMIN_ROLES = ['admin', 'sys_admin']
|
||||||
|
|
||||||
|
const normalizePermissionList = (permissions) => {
|
||||||
|
if (!permissions) return []
|
||||||
|
if (Array.isArray(permissions)) return permissions.filter(Boolean)
|
||||||
|
if (typeof permissions === 'object') {
|
||||||
|
return Object.keys(permissions).filter(key => !!permissions[key])
|
||||||
|
}
|
||||||
|
if (typeof permissions === 'string') {
|
||||||
|
return permissions
|
||||||
|
.split(',')
|
||||||
|
.map((perm) => perm.trim())
|
||||||
|
.filter(Boolean)
|
||||||
|
}
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
const resolveRequiredPermissions = (value) => {
|
||||||
|
if (!value) return []
|
||||||
|
if (Array.isArray(value)) return value.filter(Boolean)
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
return value
|
||||||
|
.split(',')
|
||||||
|
.map((item) => item.trim())
|
||||||
|
.filter(Boolean)
|
||||||
|
}
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
const evaluatePermission = (userStore, requiredPermissions, modifiers = {}) => {
|
||||||
|
if (!userStore) return false
|
||||||
|
const { requireAll = modifiers.all } = modifiers
|
||||||
|
const permissionsToCheck = resolveRequiredPermissions(requiredPermissions)
|
||||||
|
if (permissionsToCheck.length === 0) return false
|
||||||
|
|
||||||
|
const userInfo = userStore.userInfo
|
||||||
|
const userRoles = userInfo?.roles || []
|
||||||
|
const isAdmin = Array.isArray(userRoles) && userRoles.some((role) => ADMIN_ROLES.includes(role))
|
||||||
|
if (isAdmin) return true
|
||||||
|
|
||||||
|
const userPermissions = normalizePermissionList(userInfo?.permissions)
|
||||||
|
if (userPermissions.length === 0) return false
|
||||||
|
|
||||||
|
if (requireAll) {
|
||||||
|
return permissionsToCheck.every((permission) => userPermissions.includes(permission))
|
||||||
|
}
|
||||||
|
|
||||||
|
return permissionsToCheck.some((permission) => userPermissions.includes(permission))
|
||||||
|
}
|
||||||
|
|
||||||
|
const getUserStore = (binding, vnode) => {
|
||||||
|
const piniaInstance =
|
||||||
|
binding?.instance?.proxy?.$pinia ||
|
||||||
|
binding?.instance?.appContext?.app?.$pinia ||
|
||||||
|
vnode?.context?.$pinia ||
|
||||||
|
binding?.instance?.appContext?.appContext?.provides?.pinia
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (piniaInstance) {
|
||||||
|
return useUserStore(piniaInstance)
|
||||||
|
}
|
||||||
|
return useUserStore()
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('[v-permission] failed to access pinia instance:', error)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const toggleElementVisibility = (el, shouldShow) => {
|
||||||
|
if (shouldShow) {
|
||||||
|
el.style.display = el.__vOriginalDisplay || ''
|
||||||
|
} else {
|
||||||
|
if (el.style.display !== 'none') {
|
||||||
|
el.__vOriginalDisplay = el.style.display
|
||||||
|
}
|
||||||
|
el.style.display = 'none'
|
||||||
|
}
|
||||||
|
el.__vPermissionVisible = shouldShow
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDirective = (el, binding, vnode) => {
|
||||||
|
const userStore = getUserStore(binding, vnode)
|
||||||
|
const shouldShow = evaluatePermission(userStore, binding.value, binding.modifiers)
|
||||||
|
toggleElementVisibility(el, shouldShow)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const registerPermissionDirective = (appOrVue) => {
|
||||||
|
if (!appOrVue) return
|
||||||
|
|
||||||
|
const directiveConfig = {
|
||||||
|
mounted: handleDirective,
|
||||||
|
updated: handleDirective,
|
||||||
|
beforeMount: handleDirective,
|
||||||
|
beforeUpdate: handleDirective
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof appOrVue.directive === 'function') {
|
||||||
|
// Vue3
|
||||||
|
appOrVue.directive('permission', directiveConfig)
|
||||||
|
} else if (typeof appOrVue.prototype?.directive === 'function' || typeof appOrVue.directive === 'function') {
|
||||||
|
// Vue2 global Vue constructor
|
||||||
|
const VueCtor = appOrVue.prototype?.constructor || appOrVue
|
||||||
|
VueCtor.directive('permission', {
|
||||||
|
inserted: handleDirective,
|
||||||
|
update: handleDirective,
|
||||||
|
componentUpdated: handleDirective
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default registerPermissionDirective
|
||||||
|
|
||||||
4
main.js
4
main.js
|
|
@ -1,6 +1,7 @@
|
||||||
import App from './App'
|
import App from './App'
|
||||||
import uvUI from '@climblee/uv-ui'
|
import uvUI from '@climblee/uv-ui'
|
||||||
import { Request } from '@/utils/request/index'
|
import { Request } from '@/utils/request/index'
|
||||||
|
import { registerPermissionDirective } from '@/directives/permission'
|
||||||
|
|
||||||
// #ifndef VUE3
|
// #ifndef VUE3
|
||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
|
|
@ -9,6 +10,8 @@ import './uni.promisify.adaptor'
|
||||||
|
|
||||||
Vue.config.productionTip = false
|
Vue.config.productionTip = false
|
||||||
App.mpType = 'app'
|
App.mpType = 'app'
|
||||||
|
registerPermissionDirective(Vue)
|
||||||
|
|
||||||
const app = new Vue({
|
const app = new Vue({
|
||||||
...App
|
...App
|
||||||
})
|
})
|
||||||
|
|
@ -27,6 +30,7 @@ export function createApp() {
|
||||||
app.use(pinia)
|
app.use(pinia)
|
||||||
app.use(uvUI);
|
app.use(uvUI);
|
||||||
Request(app)
|
Request(app)
|
||||||
|
registerPermissionDirective(app)
|
||||||
|
|
||||||
// 调用setConfig方法,方法内部会进行对象属性深度合并,可以放心嵌套配置
|
// 调用setConfig方法,方法内部会进行对象属性深度合并,可以放心嵌套配置
|
||||||
// 需要在Vue.use(uvUI)之后执行
|
// 需要在Vue.use(uvUI)之后执行
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
"name" : "OfficeSystem",
|
"name" : "OfficeSystem",
|
||||||
"appid" : "__UNI__53A0BE0",
|
"appid" : "__UNI__53A0BE0",
|
||||||
"description" : "",
|
"description" : "",
|
||||||
"versionName" : "1.0.7",
|
"versionName" : "1.0.8",
|
||||||
"versionCode" : "100",
|
"versionCode" : "100",
|
||||||
"transformPx" : false,
|
"transformPx" : false,
|
||||||
/* 5+App特有相关 */
|
/* 5+App特有相关 */
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,22 @@
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
|
|
||||||
|
const ADMIN_ROLES = ['admin', 'sys_admin']
|
||||||
|
|
||||||
|
const normalizePermissions = (permissions) => {
|
||||||
|
if (!permissions) return []
|
||||||
|
if (Array.isArray(permissions)) return permissions.filter(Boolean)
|
||||||
|
if (typeof permissions === 'object') {
|
||||||
|
return Object.keys(permissions).filter(key => !!permissions[key])
|
||||||
|
}
|
||||||
|
if (typeof permissions === 'string') {
|
||||||
|
return permissions
|
||||||
|
.split(',')
|
||||||
|
.map((perm) => perm.trim())
|
||||||
|
.filter(Boolean)
|
||||||
|
}
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用户信息 Store
|
* 用户信息 Store
|
||||||
* 用于管理用户登录状态、token等信息
|
* 用于管理用户登录状态、token等信息
|
||||||
|
|
@ -56,6 +73,63 @@ export const useUserStore = defineStore('user', {
|
||||||
return state.privateView
|
return state.privateView
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户角色列表
|
||||||
|
*/
|
||||||
|
getRoles: (state) => {
|
||||||
|
return Array.isArray(state.userInfo?.roles) ? state.userInfo.roles : []
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否拥有管理员角色
|
||||||
|
*/
|
||||||
|
isAdmin: (state) => {
|
||||||
|
const roles = Array.isArray(state.userInfo?.roles) ? state.userInfo.roles : []
|
||||||
|
return roles.some((role) => ADMIN_ROLES.includes(role))
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取权限列表
|
||||||
|
*/
|
||||||
|
getPermissions: (state) => {
|
||||||
|
return normalizePermissions(state.userInfo?.permissions)
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否拥有指定权限
|
||||||
|
* 支持字符串、数组或以逗号分隔的字符串
|
||||||
|
* @param {string|string[]} requiredPermissions
|
||||||
|
* @param {object} options - { requireAll?: boolean }
|
||||||
|
*/
|
||||||
|
hasPermission: (state) => (requiredPermissions, options = {}) => {
|
||||||
|
const permissionsToCheck = (() => {
|
||||||
|
if (!requiredPermissions) return []
|
||||||
|
if (Array.isArray(requiredPermissions)) {
|
||||||
|
return requiredPermissions.filter(Boolean)
|
||||||
|
}
|
||||||
|
if (typeof requiredPermissions === 'string') {
|
||||||
|
return requiredPermissions
|
||||||
|
.split(',')
|
||||||
|
.map((perm) => perm.trim())
|
||||||
|
.filter(Boolean)
|
||||||
|
}
|
||||||
|
return []
|
||||||
|
})()
|
||||||
|
|
||||||
|
if (permissionsToCheck.length === 0) return false
|
||||||
|
if (Array.isArray(state.userInfo?.roles) && state.userInfo.roles.some((role) => ADMIN_ROLES.includes(role))) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
const userPermissions = normalizePermissions(state.userInfo?.permissions)
|
||||||
|
if (userPermissions.length === 0) return false
|
||||||
|
|
||||||
|
const requireAll = options.requireAll || options.all
|
||||||
|
return requireAll
|
||||||
|
? permissionsToCheck.every((permission) => userPermissions.includes(permission))
|
||||||
|
: permissionsToCheck.some((permission) => userPermissions.includes(permission))
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 判断 token 是否过期(如果设置了过期时间)
|
* 判断 token 是否过期(如果设置了过期时间)
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user