first commit
This commit is contained in:
13
src/stores/index.ts
Normal file
13
src/stores/index.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { createPinia } from 'pinia'
|
||||
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
|
||||
|
||||
export * from './modules/app'
|
||||
export * from './modules/route'
|
||||
export * from './modules/tabs'
|
||||
export * from './modules/dict'
|
||||
export * from './modules/user'
|
||||
|
||||
const pinia = createPinia()
|
||||
pinia.use(piniaPluginPersistedstate)
|
||||
|
||||
export default pinia
|
||||
144
src/stores/modules/app.ts
Normal file
144
src/stores/modules/app.ts
Normal file
@@ -0,0 +1,144 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { computed, reactive, toRefs } from 'vue'
|
||||
import { generate, getRgbStr } from '@arco-design/color'
|
||||
import { type BasicConfig, listSiteOptionDict } from '@/apis'
|
||||
import { getSettings } from '@/config/setting'
|
||||
|
||||
const storeSetup = () => {
|
||||
// App配置
|
||||
const settingConfig = reactive({ ...getSettings() }) as App.AppSettings
|
||||
// 页面切换动画类名
|
||||
const transitionName = computed(() => (settingConfig.animate ? settingConfig.animateMode : ''))
|
||||
|
||||
// 深色菜单主题色变量
|
||||
const themeCSSVar = computed<Record<string, string>>(() => {
|
||||
const obj: Record<string, string> = {}
|
||||
const list = generate(settingConfig.themeColor, { list: true, dark: true }) as string[]
|
||||
list.forEach((color, index) => {
|
||||
obj[`--primary-${index + 1}`] = getRgbStr(color)
|
||||
})
|
||||
return obj
|
||||
})
|
||||
|
||||
// 设置主题色
|
||||
const setThemeColor = (color: string) => {
|
||||
if (!color) return
|
||||
settingConfig.themeColor = color
|
||||
const list = generate(settingConfig.themeColor, { list: true, dark: settingConfig.theme === 'dark' }) as string[]
|
||||
list.forEach((color, index) => {
|
||||
const rgbStr = getRgbStr(color)
|
||||
document.body.style.setProperty(`--primary-${index + 1}`, rgbStr)
|
||||
})
|
||||
}
|
||||
|
||||
// 切换主题 暗黑模式|简白模式
|
||||
const toggleTheme = (dark: boolean) => {
|
||||
if (dark) {
|
||||
settingConfig.theme = 'dark'
|
||||
document.body.setAttribute('arco-theme', 'dark')
|
||||
} else {
|
||||
settingConfig.theme = 'light'
|
||||
document.body.removeAttribute('arco-theme')
|
||||
}
|
||||
setThemeColor(settingConfig.themeColor)
|
||||
}
|
||||
|
||||
// 初始化主题
|
||||
const initTheme = () => {
|
||||
if (!settingConfig.themeColor) return
|
||||
setThemeColor(settingConfig.themeColor)
|
||||
}
|
||||
|
||||
// 设置左侧菜单折叠状态
|
||||
const setMenuCollapse = (collapsed: boolean) => {
|
||||
settingConfig.menuCollapse = collapsed
|
||||
}
|
||||
|
||||
// 系统配置配置
|
||||
const siteConfig = reactive({}) as BasicConfig
|
||||
// 初始化系统配置
|
||||
const initSiteConfig = () => {
|
||||
listSiteOptionDict().then((res) => {
|
||||
const resMap = new Map()
|
||||
res.data.forEach((item) => {
|
||||
resMap.set(item.label, item.value)
|
||||
})
|
||||
siteConfig.SITE_FAVICON = resMap.get('SITE_FAVICON')
|
||||
siteConfig.SITE_LOGO = resMap.get('SITE_LOGO')
|
||||
siteConfig.SITE_TITLE = resMap.get('SITE_TITLE')
|
||||
siteConfig.SITE_COPYRIGHT = resMap.get('SITE_COPYRIGHT')
|
||||
siteConfig.SITE_BEIAN = resMap.get('SITE_BEIAN')
|
||||
document.title = resMap.get('SITE_TITLE')
|
||||
document
|
||||
.querySelector('link[rel="shortcut icon"]')
|
||||
?.setAttribute('href', resMap.get('SITE_FAVICON') || '/favicon.ico')
|
||||
})
|
||||
}
|
||||
|
||||
// 设置系统配置
|
||||
const setSiteConfig = (config: BasicConfig) => {
|
||||
Object.assign(siteConfig, config)
|
||||
document.title = config.SITE_TITLE || ''
|
||||
document.querySelector('link[rel="shortcut icon"]')?.setAttribute('href', config.SITE_FAVICON || '/favicon.ico')
|
||||
}
|
||||
// 监听 色弱模式 和 哀悼模式
|
||||
watch([
|
||||
() => settingConfig.enableMourningMode,
|
||||
() => settingConfig.enableColorWeaknessMode,
|
||||
], ([mourningMode, colorWeaknessMode]) => {
|
||||
const filters = [] as string[]
|
||||
if (mourningMode) {
|
||||
filters.push('grayscale(100%)')
|
||||
}
|
||||
if (colorWeaknessMode) {
|
||||
filters.push('invert(80%)')
|
||||
}
|
||||
// 如果没有任何滤镜条件,移除 `filter` 样式
|
||||
if (filters.length === 0) {
|
||||
document.documentElement.style.removeProperty('filter')
|
||||
} else {
|
||||
document.documentElement.style.setProperty('filter', filters.join(' '))
|
||||
}
|
||||
}, {
|
||||
immediate: true,
|
||||
})
|
||||
|
||||
const getFavicon = () => {
|
||||
return siteConfig.SITE_FAVICON
|
||||
}
|
||||
|
||||
const getLogo = () => {
|
||||
return siteConfig.SITE_LOGO
|
||||
}
|
||||
|
||||
const getTitle = () => {
|
||||
return siteConfig.SITE_TITLE
|
||||
}
|
||||
|
||||
const getCopyright = () => {
|
||||
return siteConfig.SITE_COPYRIGHT
|
||||
}
|
||||
|
||||
const getForRecord = () => {
|
||||
return siteConfig.SITE_BEIAN
|
||||
}
|
||||
return {
|
||||
...toRefs(settingConfig),
|
||||
...toRefs(siteConfig),
|
||||
transitionName,
|
||||
themeCSSVar,
|
||||
toggleTheme,
|
||||
setThemeColor,
|
||||
initTheme,
|
||||
setMenuCollapse,
|
||||
initSiteConfig,
|
||||
setSiteConfig,
|
||||
getFavicon,
|
||||
getLogo,
|
||||
getTitle,
|
||||
getCopyright,
|
||||
getForRecord,
|
||||
}
|
||||
}
|
||||
|
||||
export const useAppStore = defineStore('app', storeSetup, { persist: true })
|
||||
44
src/stores/modules/dict.ts
Normal file
44
src/stores/modules/dict.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
const storeSetup = () => {
|
||||
const dictData = ref<Record<string, App.DictItem[]>>({})
|
||||
|
||||
// 设置字典
|
||||
const setDict = (code: string, items: App.DictItem[]) => {
|
||||
if (code) {
|
||||
dictData.value[code] = items
|
||||
}
|
||||
}
|
||||
|
||||
// 获取字典
|
||||
const getDict = (code: string) => {
|
||||
if (!code) {
|
||||
return null
|
||||
}
|
||||
return dictData.value[code] || null
|
||||
}
|
||||
|
||||
// 删除字典
|
||||
const deleteDict = (code: string) => {
|
||||
if (!code || !(code in dictData.value)) {
|
||||
return false
|
||||
}
|
||||
delete dictData.value[code]
|
||||
return true
|
||||
}
|
||||
|
||||
// 清空字典
|
||||
const cleanDict = () => {
|
||||
dictData.value = {}
|
||||
}
|
||||
|
||||
return {
|
||||
dictData,
|
||||
setDict,
|
||||
getDict,
|
||||
deleteDict,
|
||||
cleanDict,
|
||||
}
|
||||
}
|
||||
|
||||
export const useDictStore = defineStore('dict', storeSetup)
|
||||
109
src/stores/modules/route.ts
Normal file
109
src/stores/modules/route.ts
Normal file
@@ -0,0 +1,109 @@
|
||||
import { ref } from 'vue'
|
||||
import { defineStore } from 'pinia'
|
||||
import type { RouteRecordRaw } from 'vue-router'
|
||||
import { mapTree, toTreeArray } from 'xe-utils'
|
||||
import { cloneDeep, omit } from 'lodash-es'
|
||||
import { constantRoutes, systemRoutes } from '@/router/route'
|
||||
import { type RouteItem, getUserRoute } from '@/apis'
|
||||
import { transformPathToName } from '@/utils'
|
||||
import { asyncRouteModules } from '@/router/asyncModules'
|
||||
|
||||
const layoutComponentMap = {
|
||||
Layout: () => import('@/layout/index.vue'),
|
||||
ParentView: () => import('@/components/ParentView/index.vue'),
|
||||
}
|
||||
|
||||
/** 将component由字符串转成真正的模块 */
|
||||
const transformComponentView = (component: string) => {
|
||||
return layoutComponentMap[component as keyof typeof layoutComponentMap] || asyncRouteModules[component]
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 前端来做排序、格式化
|
||||
* @params {menus} 后端返回的路由数据,已经根据当前用户角色过滤掉了没权限的路由
|
||||
* 1. 对后端返回的路由数据进行排序,格式化
|
||||
* 2. 同时将component由字符串转成真正的模块
|
||||
*/
|
||||
const formatAsyncRoutes = (menus: RouteItem[]) => {
|
||||
if (!menus.length) return []
|
||||
|
||||
const pathMap = new Map()
|
||||
return mapTree(menus, (item) => {
|
||||
pathMap.set(item.id, item.path)
|
||||
|
||||
if (item.children?.length) {
|
||||
item.children.sort((a, b) => (a?.sort ?? 0) - (b?.sort ?? 0))
|
||||
}
|
||||
|
||||
// 部分子菜单,例如:通知公告新增、查看详情,需要选中其父菜单
|
||||
if (item.parentId && item.type === 2 && item.permission) {
|
||||
item.activeMenu = pathMap.get(item.parentId)
|
||||
}
|
||||
|
||||
return {
|
||||
path: item.path,
|
||||
name: item.name ?? transformPathToName(item.path),
|
||||
component: transformComponentView(item.component),
|
||||
redirect: item.redirect,
|
||||
meta: {
|
||||
title: item.title,
|
||||
hidden: item.isHidden,
|
||||
keepAlive: item.isCache,
|
||||
icon: item.icon,
|
||||
showInTabs: item.showInTabs,
|
||||
activeMenu: item.activeMenu,
|
||||
// 在meta配置中添加affix属性处理
|
||||
affix: item.path === '/dashboard/analysis',
|
||||
},
|
||||
}
|
||||
}) as unknown as RouteRecordRaw[]
|
||||
}
|
||||
|
||||
/** 判断路由层级是否大于 2 */
|
||||
export const isMultipleRoute = (route: RouteRecordRaw) => {
|
||||
return route.children?.some((child) => child.children?.length) ?? false
|
||||
}
|
||||
|
||||
/** 路由降级(把三级及其以上的路由转化为二级路由) */
|
||||
export const flatMultiLevelRoutes = (routes: RouteRecordRaw[]) => {
|
||||
return cloneDeep(routes).map((route) => {
|
||||
if (!isMultipleRoute(route)) return route
|
||||
|
||||
return {
|
||||
...route,
|
||||
children: toTreeArray(route.children).map((item) => omit(item, 'children')) as RouteRecordRaw[],
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const storeSetup = () => {
|
||||
// 所有路由(常驻路由 + 动态路由)
|
||||
const routes = ref<RouteRecordRaw[]>([])
|
||||
// 动态路由(异步路由)
|
||||
const asyncRoutes = ref<RouteRecordRaw[]>([])
|
||||
|
||||
// 合并路由
|
||||
const setRoutes = (data: RouteRecordRaw[]) => {
|
||||
// 合并路由并排序
|
||||
routes.value = [...constantRoutes, ...systemRoutes].concat(data)
|
||||
.sort((a, b) => (a.meta?.sort ?? 0) - (b.meta?.sort ?? 0))
|
||||
asyncRoutes.value = data
|
||||
}
|
||||
|
||||
// 生成路由
|
||||
const generateRoutes = async (): Promise<RouteRecordRaw[]> => {
|
||||
const { data } = await getUserRoute()
|
||||
const asyncRoutes = formatAsyncRoutes(data)
|
||||
const flatRoutes = flatMultiLevelRoutes(cloneDeep(asyncRoutes))
|
||||
setRoutes(asyncRoutes)
|
||||
return flatRoutes
|
||||
}
|
||||
|
||||
return {
|
||||
routes,
|
||||
asyncRoutes,
|
||||
generateRoutes,
|
||||
}
|
||||
}
|
||||
|
||||
export const useRouteStore = defineStore('route', storeSetup, { persist: true })
|
||||
172
src/stores/modules/tabs.ts
Normal file
172
src/stores/modules/tabs.ts
Normal file
@@ -0,0 +1,172 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
import { type RouteLocationNormalized, type RouteRecordName, useRouter } from 'vue-router'
|
||||
import _XEUtils_ from 'xe-utils'
|
||||
import { useRouteStore } from '@/stores'
|
||||
|
||||
const storeSetup = () => {
|
||||
const router = useRouter()
|
||||
const tabList = ref<RouteLocationNormalized[]>([]) // 保存页签tab的数组
|
||||
const cacheList = ref<RouteRecordName[]>([]) // keep-alive缓存的数组,元素是组件名
|
||||
|
||||
// 添加一个页签,如果当前路由已经打开,则不再重复添加
|
||||
const addTabItem = (item: RouteLocationNormalized) => {
|
||||
const index = tabList.value.findIndex((i) => i.path === item.path)
|
||||
if (index >= 0) {
|
||||
tabList.value[index].fullPath !== item.fullPath && (tabList.value[index] = item)
|
||||
} else {
|
||||
if (item.meta?.showInTabs ?? true) {
|
||||
tabList.value.push(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 删除一个页签
|
||||
const deleteTabItem = (path: string) => {
|
||||
const index = tabList.value.findIndex((item) => item.path === path && !item.meta?.affix)
|
||||
if (index < 0) return
|
||||
const isActive = router.currentRoute.value.path === tabList.value[index].path
|
||||
tabList.value.splice(index, 1)
|
||||
if (isActive) {
|
||||
const lastObj = tabList.value[tabList.value.length - 1]
|
||||
router.push(lastObj.fullPath || lastObj.path)
|
||||
}
|
||||
}
|
||||
|
||||
// 清空页签
|
||||
const clearTabList = () => {
|
||||
const routeStore = useRouteStore()
|
||||
const arr: RouteLocationNormalized[] = []
|
||||
_XEUtils_.eachTree(routeStore.routes, (item) => {
|
||||
if (item.meta?.affix ?? false) {
|
||||
arr.push(item as unknown as RouteLocationNormalized)
|
||||
}
|
||||
})
|
||||
tabList.value = arr
|
||||
}
|
||||
|
||||
// 设置当前tab页签名称
|
||||
const setTabTitle = (title: string) => {
|
||||
if (!title) return false
|
||||
const route = router.currentRoute.value
|
||||
const path = route?.fullPath || route.path
|
||||
const index = tabList.value.findIndex((i) => i.fullPath === path)
|
||||
if (index >= 0) {
|
||||
tabList.value[index].meta.title = title
|
||||
}
|
||||
}
|
||||
|
||||
// 添加缓存页
|
||||
const addCacheItem = (item: RouteLocationNormalized) => {
|
||||
if (!item.name) return
|
||||
if (cacheList.value.includes(item.name)) return
|
||||
if (item.meta?.keepAlive) {
|
||||
cacheList.value.push(item.name)
|
||||
}
|
||||
}
|
||||
|
||||
// 删除一个缓存页
|
||||
const deleteCacheItem = (name: RouteRecordName) => {
|
||||
const index = cacheList.value.findIndex((i) => i === name)
|
||||
if (index >= 0) {
|
||||
cacheList.value.splice(index, 1)
|
||||
}
|
||||
}
|
||||
|
||||
// 清空缓存页
|
||||
const clearCacheList = () => {
|
||||
cacheList.value = []
|
||||
}
|
||||
|
||||
// 关闭当前
|
||||
const closeCurrent = (path: string) => {
|
||||
const item = tabList.value.find((i) => i.path === path)
|
||||
item?.name && deleteCacheItem(item.name)
|
||||
deleteTabItem(path)
|
||||
}
|
||||
|
||||
// 关闭其他
|
||||
const closeOther = (path: string) => {
|
||||
const arr = tabList.value.filter((i) => i.path !== path)
|
||||
arr.forEach((item) => {
|
||||
deleteTabItem(item.path)
|
||||
item?.name && deleteCacheItem(item.name)
|
||||
})
|
||||
}
|
||||
|
||||
// 关闭左侧
|
||||
const closeLeft = (path: string) => {
|
||||
const index = tabList.value.findIndex((i) => i.path === path)
|
||||
if (index < 0) return
|
||||
const arr = tabList.value.filter((i, n) => n < index)
|
||||
arr.forEach((item) => {
|
||||
deleteTabItem(item.path)
|
||||
item?.name && deleteCacheItem(item.name)
|
||||
})
|
||||
}
|
||||
|
||||
// 关闭右侧
|
||||
const closeRight = (path: string) => {
|
||||
const index = tabList.value.findIndex((i) => i.path === path)
|
||||
if (index < 0) return
|
||||
const arr = tabList.value.filter((i, n) => n > index)
|
||||
arr.forEach((item) => {
|
||||
deleteTabItem(item.path)
|
||||
item?.name && deleteCacheItem(item.name)
|
||||
})
|
||||
}
|
||||
|
||||
// 关闭全部
|
||||
const closeAll = () => {
|
||||
clearTabList()
|
||||
clearCacheList()
|
||||
router.push({ path: '/' })
|
||||
}
|
||||
|
||||
// 重置
|
||||
const reset = () => {
|
||||
clearTabList()
|
||||
clearCacheList()
|
||||
}
|
||||
|
||||
// 初始化
|
||||
const init = () => {
|
||||
if (tabList.value.some((i) => !i?.meta.affix)) return
|
||||
reset()
|
||||
}
|
||||
|
||||
// Tabs页签右侧刷新按钮-页面重新加载
|
||||
const reloadFlag = ref(true)
|
||||
const reloadPage = () => {
|
||||
const route = router.currentRoute.value
|
||||
deleteCacheItem(route.name as string) // 修复点击刷新图标,无法重新触发生命周期钩子函数问题
|
||||
reloadFlag.value = false
|
||||
nextTick(() => {
|
||||
reloadFlag.value = true
|
||||
addCacheItem(route)
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
tabList,
|
||||
cacheList,
|
||||
addTabItem,
|
||||
deleteTabItem,
|
||||
clearTabList,
|
||||
setTabTitle,
|
||||
addCacheItem,
|
||||
deleteCacheItem,
|
||||
clearCacheList,
|
||||
closeCurrent,
|
||||
closeOther,
|
||||
closeLeft,
|
||||
closeRight,
|
||||
closeAll,
|
||||
reset,
|
||||
init,
|
||||
reloadFlag,
|
||||
reloadPage,
|
||||
}
|
||||
}
|
||||
|
||||
export const useTabsStore = defineStore('tabs', storeSetup, { persist: { storage: sessionStorage } })
|
||||
133
src/stores/modules/user.ts
Normal file
133
src/stores/modules/user.ts
Normal file
@@ -0,0 +1,133 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { computed, reactive, ref } from 'vue'
|
||||
import { resetRouter } from '@/router'
|
||||
import {
|
||||
type AccountLoginReq,
|
||||
AuthTypeConstants,
|
||||
type EmailLoginReq,
|
||||
type PhoneLoginReq,
|
||||
type UserInfo,
|
||||
accountLogin as accountLoginApi,
|
||||
emailLogin as emailLoginApi,
|
||||
getUserInfo as getUserInfoApi,
|
||||
logout as logoutApi,
|
||||
phoneLogin as phoneLoginApi,
|
||||
socialLogin as socialLoginApi,
|
||||
} from '@/apis'
|
||||
import { clearToken, getToken, setToken } from '@/utils/auth'
|
||||
import { resetHasRouteFlag } from '@/router/guard'
|
||||
|
||||
const storeSetup = () => {
|
||||
const userInfo = reactive<UserInfo>({
|
||||
id: '',
|
||||
username: '',
|
||||
nickname: '',
|
||||
gender: 0,
|
||||
email: '',
|
||||
phone: '',
|
||||
avatar: '',
|
||||
pwdResetTime: '',
|
||||
pwdExpired: false,
|
||||
registrationDate: '',
|
||||
deptName: '',
|
||||
roles: [],
|
||||
permissions: [],
|
||||
})
|
||||
const nickname = computed(() => userInfo.nickname)
|
||||
const username = computed(() => userInfo.username)
|
||||
const avatar = computed(() => userInfo.avatar)
|
||||
|
||||
const token = ref(getToken() || '')
|
||||
const pwdExpiredShow = ref<boolean>(true)
|
||||
const roles = ref<string[]>([]) // 当前用户角色
|
||||
const permissions = ref<string[]>([]) // 当前角色权限标识集合
|
||||
|
||||
// 重置token
|
||||
const resetToken = () => {
|
||||
token.value = ''
|
||||
clearToken()
|
||||
resetHasRouteFlag()
|
||||
}
|
||||
|
||||
// 登录
|
||||
const accountLogin = async (req: AccountLoginReq) => {
|
||||
const res = await accountLoginApi({ ...req, clientId: import.meta.env.VITE_CLIENT_ID, authType: AuthTypeConstants.ACCOUNT })
|
||||
setToken(res.data.token)
|
||||
token.value = res.data.token
|
||||
}
|
||||
|
||||
// 邮箱登录
|
||||
const emailLogin = async (req: EmailLoginReq) => {
|
||||
const res = await emailLoginApi({ ...req, clientId: import.meta.env.VITE_CLIENT_ID, authType: AuthTypeConstants.EMAIL })
|
||||
setToken(res.data.token)
|
||||
token.value = res.data.token
|
||||
}
|
||||
|
||||
// 手机号登录
|
||||
const phoneLogin = async (req: PhoneLoginReq) => {
|
||||
const res = await phoneLoginApi({ ...req, clientId: import.meta.env.VITE_CLIENT_ID, authType: AuthTypeConstants.PHONE })
|
||||
setToken(res.data.token)
|
||||
token.value = res.data.token
|
||||
}
|
||||
|
||||
// 三方账号登录
|
||||
const socialLogin = async (source: string, req: any) => {
|
||||
const res = await socialLoginApi({ ...req, source, clientId: import.meta.env.VITE_CLIENT_ID, authType: AuthTypeConstants.SOCIAL })
|
||||
setToken(res.data.token)
|
||||
token.value = res.data.token
|
||||
}
|
||||
|
||||
// 退出登录回调
|
||||
const logoutCallBack = async () => {
|
||||
roles.value = []
|
||||
permissions.value = []
|
||||
pwdExpiredShow.value = true
|
||||
resetToken()
|
||||
resetRouter()
|
||||
}
|
||||
|
||||
// 退出登录
|
||||
const logout = async () => {
|
||||
try {
|
||||
await logoutApi()
|
||||
await logoutCallBack()
|
||||
return true
|
||||
} catch (error) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// 获取用户信息
|
||||
const getInfo = async () => {
|
||||
const res = await getUserInfoApi()
|
||||
Object.assign(userInfo, res.data)
|
||||
userInfo.avatar = res.data.avatar
|
||||
if (res.data.roles && res.data.roles.length) {
|
||||
roles.value = res.data.roles
|
||||
permissions.value = res.data.permissions
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
userInfo,
|
||||
nickname,
|
||||
username,
|
||||
avatar,
|
||||
token,
|
||||
roles,
|
||||
permissions,
|
||||
pwdExpiredShow,
|
||||
accountLogin,
|
||||
emailLogin,
|
||||
phoneLogin,
|
||||
socialLogin,
|
||||
logout,
|
||||
logoutCallBack,
|
||||
getInfo,
|
||||
resetToken,
|
||||
}
|
||||
}
|
||||
|
||||
export const useUserStore = defineStore('user', storeSetup, {
|
||||
persist: { paths: ['token', 'roles', 'permissions', 'pwdExpiredShow'], storage: localStorage },
|
||||
})
|
||||
Reference in New Issue
Block a user