mirror of
https://github.com/1Panel-dev/MaxKB.git
synced 2025-12-26 01:33:05 +00:00
feat: ui hasPermission (#3267)
This commit is contained in:
parent
8e93e1ea2e
commit
baf1c2cdc2
|
|
@ -1,6 +1,5 @@
|
|||
import type { App } from 'vue'
|
||||
import { hasPermission } from '@/utils/permission'
|
||||
|
||||
const display = async (el: any, binding: any) => {
|
||||
const has = hasPermission(
|
||||
binding.value?.permission || binding.value,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
import { ComplexPermission } from '@/utils/permission/type'
|
||||
import { PermissionConst, RoleConst } from '@/utils/permission/data'
|
||||
|
||||
const ApplicationDetailRouter = {
|
||||
path: '/application/:id/:type',
|
||||
name: 'ApplicationDetail',
|
||||
|
|
@ -15,6 +18,10 @@ const ApplicationDetailRouter = {
|
|||
active: 'overview',
|
||||
parentPath: '/application/:id/:type',
|
||||
parentName: 'ApplicationDetail',
|
||||
permission: [
|
||||
PermissionConst.APPLICATION_OVERVIEW_READ.getWorkspacePermission,
|
||||
RoleConst.WORKSPACE_MANAGE.getWorkspaceRole,
|
||||
],
|
||||
},
|
||||
component: () => import('@/views/application-overview/index.vue'),
|
||||
},
|
||||
|
|
@ -66,10 +73,10 @@ const ApplicationDetailRouter = {
|
|||
title: 'views.chatLog.title',
|
||||
active: 'chat-log',
|
||||
parentPath: '/application/:id/:type',
|
||||
parentName: 'ApplicationDetail'
|
||||
parentName: 'ApplicationDetail',
|
||||
},
|
||||
component: () => import('@/views/chat-log/index.vue')
|
||||
}
|
||||
component: () => import('@/views/chat-log/index.vue'),
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,40 +0,0 @@
|
|||
import { defineStore } from 'pinia'
|
||||
import { cloneDeep } from 'lodash'
|
||||
import { useElementPlusTheme } from 'use-element-plus-theme'
|
||||
import ThemeApi from '@/api/system-settings/theme'
|
||||
import type {Ref} from "vue";
|
||||
export interface themeStateTypes {
|
||||
themeInfo: any
|
||||
}
|
||||
const defalueColor = '#3370FF'
|
||||
|
||||
const useThemeStore = defineStore('them', {
|
||||
state: (): themeStateTypes => ({
|
||||
themeInfo: null,
|
||||
}),
|
||||
actions: {
|
||||
isDefaultTheme() {
|
||||
return !this.themeInfo?.theme || this.themeInfo?.theme === defalueColor
|
||||
},
|
||||
|
||||
setTheme(data?: any) {
|
||||
const { changeTheme } = useElementPlusTheme(this.themeInfo?.theme || defalueColor)
|
||||
changeTheme(defalueColor)
|
||||
changeTheme(data?.['theme'])
|
||||
this.themeInfo = cloneDeep(data)
|
||||
},
|
||||
|
||||
// async theme(loading?: Ref<boolean>) {
|
||||
// return await ThemeApi.getThemeInfo(loading).then((ok) => {
|
||||
// this.setTheme(ok.data)
|
||||
// // window.document.title = this.themeInfo['title'] || 'MaxKB'
|
||||
// // const link = document.querySelector('link[rel="icon"]') as any
|
||||
// // if (link) {
|
||||
// // link['href'] = this.themeInfo['icon'] || '/favicon.ico'
|
||||
// // }
|
||||
// })
|
||||
// },
|
||||
},
|
||||
})
|
||||
|
||||
export default useThemeStore
|
||||
|
|
@ -1,191 +0,0 @@
|
|||
import {defineStore} from 'pinia'
|
||||
import {type Ref} from 'vue'
|
||||
import type {User} from '@/api/type/user'
|
||||
import UserApi from '@/api/user/user'
|
||||
import LoginApi from '@/api/user/login'
|
||||
import {cloneDeep} from 'lodash'
|
||||
import ThemeApi from '@/api/system-settings/theme'
|
||||
// import { defaultPlatformSetting } from '@/utils/theme'
|
||||
import {useLocalStorage} from '@vueuse/core'
|
||||
import {localeConfigKey, getBrowserLang} from '@/locales/index'
|
||||
import useThemeStore from './theme'
|
||||
import {useElementPlusTheme} from "use-element-plus-theme";
|
||||
import {defaultPlatformSetting} from "@/utils/theme";
|
||||
|
||||
export interface userStateTypes {
|
||||
userType: number // 1 系统操作者 2 对话用户
|
||||
userInfo: User | null
|
||||
version?: string
|
||||
XPACK_LICENSE_IS_VALID: true
|
||||
isXPack: true
|
||||
themeInfo: any
|
||||
token: any
|
||||
}
|
||||
|
||||
const useLoginStore = defineStore('use', {
|
||||
state: (): userStateTypes => ({
|
||||
userType: 1, // 1 系统操作者 2 对话用户
|
||||
userInfo: null,
|
||||
version: '',
|
||||
XPACK_LICENSE_IS_VALID: false,
|
||||
isXPack: false,
|
||||
themeInfo: null,
|
||||
token: ''
|
||||
}),
|
||||
actions: {
|
||||
getLanguage() {
|
||||
return this.userType === 1
|
||||
? localStorage.getItem('MaxKB-locale') || getBrowserLang()
|
||||
: sessionStorage.getItem('language') || getBrowserLang()
|
||||
},
|
||||
isDefaultTheme() {
|
||||
return !this.themeInfo?.theme || this.themeInfo?.theme === '#3370FF'
|
||||
},
|
||||
setTheme(data: any) {
|
||||
const {changeTheme} = useElementPlusTheme(this.themeInfo?.theme)
|
||||
changeTheme(data?.['theme'])
|
||||
this.themeInfo = cloneDeep(data)
|
||||
},
|
||||
async profile(loading?: Ref<boolean>) {
|
||||
return UserApi.getUserProfile(loading).then((ok) => {
|
||||
this.userInfo = ok.data
|
||||
useLocalStorage<string>(localeConfigKey, 'en-US').value =
|
||||
ok?.data?.language || this.getLanguage()
|
||||
const theme = useThemeStore()
|
||||
theme.setTheme()
|
||||
return this.asyncGetProfile()
|
||||
})
|
||||
},
|
||||
async asyncGetProfile() {
|
||||
return new Promise((resolve, reject) => {
|
||||
UserApi.getProfile()
|
||||
.then(async (ok) => {
|
||||
// this.version = ok.data?.version || '-'
|
||||
this.isXPack = true
|
||||
this.XPACK_LICENSE_IS_VALID = true
|
||||
|
||||
if (this.isEnterprise()) {
|
||||
// await this.theme()
|
||||
} else {
|
||||
this.themeInfo = {
|
||||
...defaultPlatformSetting
|
||||
}
|
||||
}
|
||||
resolve(ok)
|
||||
})
|
||||
.catch((error) => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
getPermissions() {
|
||||
if (this.userInfo) {
|
||||
return this.isXPack && this.XPACK_LICENSE_IS_VALID
|
||||
? [...this.userInfo?.permissions, 'x-pack']
|
||||
: this.userInfo?.permissions
|
||||
} else {
|
||||
return this.userInfo?.permissions
|
||||
}
|
||||
},
|
||||
getRole() {
|
||||
if (this.userInfo) {
|
||||
return this.userInfo?.role
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
},
|
||||
async theme(loading?: Ref<boolean>) {
|
||||
return await ThemeApi.getThemeInfo(loading).then((ok) => {
|
||||
this.setTheme(ok.data)
|
||||
// window.document.title = this.themeInfo['title'] || 'MaxKB'
|
||||
// const link = document.querySelector('link[rel="icon"]') as any
|
||||
// if (link) {
|
||||
// link['href'] = this.themeInfo['icon'] || '/favicon.ico'
|
||||
// }
|
||||
})
|
||||
},
|
||||
showXpack() {
|
||||
return this.isXPack
|
||||
},
|
||||
|
||||
isExpire() {
|
||||
return this.isXPack && !this.XPACK_LICENSE_IS_VALID
|
||||
},
|
||||
isEnterprise() {
|
||||
return this.isXPack && this.XPACK_LICENSE_IS_VALID
|
||||
},
|
||||
|
||||
// changeUserType(num: number, token?: string) {
|
||||
// this.userType = num
|
||||
// this.userAccessToken = token
|
||||
// },
|
||||
|
||||
|
||||
async dingCallback(code: string) {
|
||||
return LoginApi.getDingCallback(code).then((ok) => {
|
||||
this.token = ok.data
|
||||
localStorage.setItem('token', ok.data)
|
||||
return this.profile()
|
||||
})
|
||||
},
|
||||
async dingOauth2Callback(code: string) {
|
||||
return LoginApi.getDingOauth2Callback(code).then((ok) => {
|
||||
this.token = ok.data
|
||||
localStorage.setItem('token', ok.data)
|
||||
return this.profile()
|
||||
})
|
||||
},
|
||||
async wecomCallback(code: string) {
|
||||
return LoginApi.getWecomCallback(code).then((ok) => {
|
||||
this.token = ok.data
|
||||
localStorage.setItem('token', ok.data)
|
||||
return this.profile()
|
||||
})
|
||||
},
|
||||
async larkCallback(code: string) {
|
||||
return LoginApi.getLarkCallback(code).then((ok) => {
|
||||
this.token = ok.data
|
||||
localStorage.setItem('token', ok.data)
|
||||
return this.profile()
|
||||
})
|
||||
},
|
||||
|
||||
async logout() {
|
||||
return LoginApi.logout().then(() => {
|
||||
localStorage.removeItem('token')
|
||||
return true
|
||||
})
|
||||
},
|
||||
async getAuthType() {
|
||||
return LoginApi.getAuthType().then((ok) => {
|
||||
return ok.data
|
||||
})
|
||||
},
|
||||
async getQrType() {
|
||||
return LoginApi.getQrType().then((ok) => {
|
||||
return ok.data
|
||||
})
|
||||
},
|
||||
async getQrSource() {
|
||||
return LoginApi.getQrSource().then((ok) => {
|
||||
return ok.data
|
||||
})
|
||||
},
|
||||
async postUserLanguage(lang: string, loading?: Ref<boolean>) {
|
||||
return new Promise((resolve, reject) => {
|
||||
LoginApi.postLanguage({ language: lang }, loading)
|
||||
.then(async (ok) => {
|
||||
useLocalStorage(localeConfigKey, 'en-US').value = lang
|
||||
window.location.reload()
|
||||
resolve(ok)
|
||||
})
|
||||
.catch((error) => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
export default useLoginStore
|
||||
|
|
@ -73,7 +73,6 @@ const useUserStore = defineStore('user', {
|
|||
UserApi.getProfile()
|
||||
.then(async (ok) => {
|
||||
// this.version = ok.data?.version || '-'
|
||||
console.log(ok)
|
||||
this.license_is_valid = ok.data.license_is_valid
|
||||
this.edition = ok.data.edition
|
||||
|
||||
|
|
@ -91,21 +90,23 @@ const useUserStore = defineStore('user', {
|
|||
})
|
||||
})
|
||||
},
|
||||
|
||||
getPermissions() {
|
||||
if (this.userInfo) {
|
||||
return this.isXPack && this.XPACK_LICENSE_IS_VALID
|
||||
? [...this.userInfo?.permissions, 'x-pack']
|
||||
: this.userInfo?.permissions
|
||||
} else {
|
||||
if (this.isEE()) {
|
||||
return [...this.userInfo?.permissions, 'x-pack-ee']
|
||||
} else if (this.isPE()) {
|
||||
return [...this.userInfo?.permissions, 'x-pack-pe']
|
||||
}
|
||||
return this.userInfo?.permissions
|
||||
} else {
|
||||
return []
|
||||
}
|
||||
},
|
||||
getRole() {
|
||||
if (this.userInfo) {
|
||||
return this.userInfo?.role
|
||||
} else {
|
||||
return ''
|
||||
return []
|
||||
}
|
||||
},
|
||||
async theme(loading?: Ref<boolean>) {
|
||||
|
|
|
|||
|
|
@ -66,3 +66,7 @@ export const defaultIcon = '/ui/favicon.ico'
|
|||
export function isAppIcon(url: string | undefined) {
|
||||
return url === defaultIcon ? '' : url
|
||||
}
|
||||
|
||||
export function isFunction(fn: any) {
|
||||
return typeof fn === 'function'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,13 @@
|
|||
import { Permission } from '@/utils/permission/type'
|
||||
import { Permission, Role } from '@/utils/permission/type'
|
||||
const PermissionConst = {
|
||||
USER_READ: new Permission('USER:READ'),
|
||||
USER_CREATE: new Permission('USER:CREATE'),
|
||||
KNOWLEDGE_READ: new Permission('KNOWLEDGE:READ'),
|
||||
APPLICATION_OVERVIEW_READ: new Permission('APPLICATION_OVERVIEW_READ'),
|
||||
}
|
||||
export default PermissionConst
|
||||
const RoleConst = {
|
||||
ADMIN: new Role('ADMIN'),
|
||||
WORKSPACE_MANAGE: new Role('WORKSPACE_MANAGE'),
|
||||
USER: new Role('USER'),
|
||||
}
|
||||
export { PermissionConst, RoleConst }
|
||||
|
|
|
|||
|
|
@ -1,26 +1,33 @@
|
|||
import useStore from '@/stores'
|
||||
import { Role, Permission, ComplexPermission } from '@/utils/permission/type'
|
||||
import { isFunction } from '@/utils/common'
|
||||
|
||||
type PF = () => Role | string | Permission | ComplexPermission
|
||||
/**
|
||||
* 是否包含当前权限
|
||||
* @param permission 当前权限
|
||||
* @returns True 包含 false 不包含
|
||||
*/
|
||||
const hasPermissionChild = (permission: Role | string | Permission | ComplexPermission) => {
|
||||
const hasPermissionChild = (permission: Role | string | Permission | ComplexPermission | PF) => {
|
||||
const { user } = useStore()
|
||||
const permissions = user.getPermissions()
|
||||
const role = user.getRole()
|
||||
const role: Array<string> = user.getRole()
|
||||
if (!permission) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (isFunction(permission)) {
|
||||
permission = (permission as PF)()
|
||||
}
|
||||
if (permission instanceof Role) {
|
||||
return role === permission.role
|
||||
return role.includes(permission.role)
|
||||
}
|
||||
if (permission instanceof Permission) {
|
||||
return permissions.includes(permission.permission)
|
||||
}
|
||||
if (permission instanceof ComplexPermission) {
|
||||
const permissionOk = permission.permissionList.some((p) => permissions.includes(p))
|
||||
const roleOk = permission.roleList.includes(role)
|
||||
const roleOk = role.some((r) => permission.roleList.includes(r))
|
||||
return permission.compare === 'AND' ? permissionOk && roleOk : permissionOk || roleOk
|
||||
}
|
||||
if (typeof permission === 'string') {
|
||||
|
|
@ -38,11 +45,12 @@ const hasPermissionChild = (permission: Role | string | Permission | ComplexPerm
|
|||
*/
|
||||
export const hasPermission = (
|
||||
permission:
|
||||
| Array<Role | string | Permission | ComplexPermission>
|
||||
| Array<Role | string | Permission | ComplexPermission | PF>
|
||||
| Role
|
||||
| string
|
||||
| Permission
|
||||
| ComplexPermission,
|
||||
| ComplexPermission
|
||||
| PF,
|
||||
compare: 'OR' | 'AND',
|
||||
): boolean => {
|
||||
if (permission instanceof Array) {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import useStore from '@/stores'
|
||||
/**
|
||||
* 角色对象
|
||||
*/
|
||||
|
|
@ -7,6 +8,11 @@ export class Role {
|
|||
constructor(role: string) {
|
||||
this.role = role
|
||||
}
|
||||
|
||||
getWorkspaceRole = () => {
|
||||
const { user } = useStore()
|
||||
return new Role(`${this.role}:/WORKSPACE/${user.getWorkspaceId()}`)
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 权限对象
|
||||
|
|
@ -22,8 +28,9 @@ export class Permission {
|
|||
* @param workspace_id 工作空间id
|
||||
* @returns 工作空间权限
|
||||
*/
|
||||
getWorkspacePermission(workspace_id: string) {
|
||||
return `${this.permission}:/WORKSPACE/${workspace_id}`
|
||||
getWorkspacePermission = () => {
|
||||
const { user } = useStore()
|
||||
return `${this.permission}:/WORKSPACE/${user.getWorkspaceId()}`
|
||||
}
|
||||
/**
|
||||
* 工作空间资源权限
|
||||
|
|
@ -32,8 +39,9 @@ export class Permission {
|
|||
* @param resource_id 资源id
|
||||
* @returns 工作空间资源权限
|
||||
*/
|
||||
getWorkspaceResourcePermission(workspace_id: string, resource: string, resource_id: string) {
|
||||
return `${this.permission}:/WORKSPACE/${workspace_id}/${resource}/${resource_id}`
|
||||
getWorkspaceResourcePermission = (resource: string, resource_id: string) => {
|
||||
const { user } = useStore()
|
||||
return `${this.permission}:/WORKSPACE/${user.getWorkspaceId()}/${resource}/${resource_id}`
|
||||
}
|
||||
}
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in New Issue