user.ts 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. import { useStorage } from '@vueuse/core'
  2. import { acceptHMRUpdate, defineStore } from 'pinia'
  3. import { ref } from 'vue'
  4. import router from '@/router'
  5. import { resolveMenu, resolveRoute } from '@/router/helper'
  6. import { routeRecordRaw } from '@/router/record'
  7. import type { MergeMenuMixedOptions } from '@/router/helper'
  8. import type { MenuProps } from 'naive-ui'
  9. import type { RouteRecordRaw } from 'vue-router'
  10. import { parseJwtToken, type JwtPayload } from '@/utils/casdoor/token'
  11. interface User {
  12. avatar?: string
  13. id?: string
  14. name?: string
  15. role?: 'admin' | 'user'
  16. permissions: UserPermissions
  17. }
  18. interface UserPermissions {
  19. isAdmin: boolean
  20. items: UserPermissionsItems
  21. }
  22. interface UserPermissionsItems {
  23. xlog?: boolean // xlog操作权限
  24. autoUpdate?: boolean // 自动升级配置页面操作权限
  25. faultRecord?: boolean // 故障录波操作权限
  26. }
  27. const DEFAULT_USER: User = {
  28. avatar: '',
  29. id: '2000',
  30. name: 'FWH User',
  31. role: 'user',
  32. permissions: {
  33. isAdmin: false,
  34. items: {},
  35. },
  36. }
  37. // 特权菜单定义
  38. const adminMenuNames: string[] = [
  39. 'backgroundTask', // 后台任务管理
  40. ] as const
  41. const xlogMenuNames: string[] = [
  42. 'xlogManage', // XLOG管理
  43. 'xlogTerminal', // XLOG终端
  44. ] as const
  45. const autoUpdateMenuNames: string[] = [
  46. 'autoUpdate', // 自动升级
  47. 'autoUpdatePackage', // 升级包管理
  48. 'autoUpdateAPowerVersion', // aPower版本管理
  49. 'autoUpdateConfig', // 自动升级配置
  50. 'autoUpdateConfigFile', // 配置文件管理
  51. ] as const
  52. const faultRecordMenuNames: string[] = [
  53. 'faultRecord', // 故障录波主菜单
  54. 'faultRecordRead', // 故障录波参数读界面
  55. 'faultRecordWrite', // 故障录波参数写界面
  56. ] as const
  57. const parsePermissions = (payload: JwtPayload): User => {
  58. return {
  59. avatar: '',
  60. id: payload.id,
  61. name: payload.name,
  62. role: payload.isAdmin ? 'admin' : 'user',
  63. permissions: {
  64. isAdmin: payload.isAdmin,
  65. items: payload.permissions.reduce<UserPermissionsItems>((acc, cur) => {
  66. switch (cur.name) {
  67. case 'xlog':
  68. acc.xlog = true
  69. break
  70. case 'autoUpdate':
  71. acc.autoUpdate = true
  72. break
  73. case 'faultRecord':
  74. acc.faultRecord = true
  75. break
  76. }
  77. return acc
  78. }, {}),
  79. },
  80. }
  81. }
  82. export const useUserStore = defineStore('userStore', () => {
  83. const user = useStorage<User>('user', DEFAULT_USER)
  84. const token = useStorage<string | undefined>('token', undefined)
  85. const tokenPayload = useStorage<JwtPayload | undefined>('tokenPayload', undefined, undefined, {
  86. serializer: {
  87. read: (v: string) => (v ? (v !== '' ? JSON.parse(v) : undefined) : undefined),
  88. write: (v: JwtPayload | undefined) => (v ? JSON.stringify(v) : ''),
  89. },
  90. })
  91. const menuList = ref<MenuProps['options']>([])
  92. const routeList = ref<RouteRecordRaw[]>([])
  93. const getUserInfo = (): User => {
  94. return user.value
  95. }
  96. const setToken = (value: string | undefined) => {
  97. token.value = value
  98. if (value !== undefined) {
  99. const jwtData = parseJwtToken(value)
  100. console.log({ jwtData, jwtDataStr: JSON.stringify(jwtData) })
  101. tokenPayload.value = jwtData
  102. user.value = parsePermissions(jwtData)
  103. } else {
  104. tokenPayload.value = undefined
  105. user.value = DEFAULT_USER
  106. }
  107. }
  108. async function resolveMenuList() {
  109. const res = await new Promise<MergeMenuMixedOptions[]>((resolve) => {
  110. if (tokenPayload.value !== undefined) {
  111. if (user.value.permissions.isAdmin) {
  112. resolve(routeRecordRaw)
  113. } else {
  114. // const allowedRoutes = tokenPayload.value.roles.map((role) => role.domains).flat()
  115. // const filterRoutes = (routeRecord: MergeMenuMixedOptions[]) => {
  116. // return routeRecord
  117. // .map((route): MergeMenuMixedOptions | undefined => {
  118. // const selfAllowed =
  119. // !route.type && route.name && allowedRoutes.includes(route.name as string)
  120. // if (selfAllowed) return route
  121. // // 先递归处理 children
  122. // if (!('children' in route) || route.children === undefined) {
  123. // return undefined
  124. // }
  125. // const result = { ...route }
  126. // result.children = filterRoutes(route.children)
  127. // return result
  128. // })
  129. // .filter((item): item is MergeMenuMixedOptions => Boolean(item))
  130. // }
  131. // resolve(filterRoutes(routeRecordRaw))
  132. const permissionsItems = user.value.permissions.items
  133. resolve(
  134. routeRecordRaw.filter((route) => {
  135. if (route.type === undefined && typeof route.name === 'string') {
  136. // 清除admin权限页面
  137. if (adminMenuNames.includes(route.name)) {
  138. return false
  139. }
  140. // xlog界面控制
  141. if (permissionsItems.xlog !== true) {
  142. if (xlogMenuNames.includes(route.name)) {
  143. return false
  144. }
  145. }
  146. // autoUpdate界面控制
  147. if (permissionsItems.autoUpdate !== true) {
  148. if (autoUpdateMenuNames.includes(route.name)) {
  149. return false
  150. }
  151. }
  152. // faultRecord界面控制
  153. if (permissionsItems.faultRecord !== true) {
  154. if (faultRecordMenuNames.includes(route.name)) {
  155. return false
  156. }
  157. }
  158. }
  159. return true
  160. }),
  161. )
  162. }
  163. } else {
  164. cleanup()
  165. resolve([])
  166. }
  167. // if (token.value?.includes('admin')) {
  168. // resolve(routeRecordRaw)
  169. // } else {
  170. // const allowedRoutes = ['dashboard', 'dataShow', 'notfoundPage', 'about']
  171. // const filteredRoutes = routeRecordRaw.filter((route) => {
  172. // return !route.type && route.name && allowedRoutes.includes(route.name as string)
  173. // })
  174. // resolve(filteredRoutes)
  175. // }
  176. // 暂时没有管理员权限
  177. // resolve(routeRecordRaw)
  178. })
  179. menuList.value = resolveMenu(res) || []
  180. routeList.value = resolveRoute(res) || []
  181. }
  182. function cleanup(redirectPath?: string) {
  183. router.replace({
  184. name: 'signin',
  185. ...(redirectPath ? { query: { r: redirectPath } } : {}),
  186. })
  187. token.value = undefined
  188. if (router.hasRoute('layout')) {
  189. router.removeRoute('layout')
  190. }
  191. menuList.value = []
  192. routeList.value = []
  193. }
  194. return {
  195. user,
  196. token,
  197. tokenPayload,
  198. menuList,
  199. routeList,
  200. resolveMenuList,
  201. getUserInfo,
  202. setToken,
  203. cleanup,
  204. }
  205. })
  206. if (import.meta.hot) {
  207. import.meta.hot.accept(acceptHMRUpdate(useUserStore, import.meta.hot))
  208. }