335 lines
10 KiB
JavaScript
335 lines
10 KiB
JavaScript
import { defineStore } from 'pinia'
|
||
import {adminApi,requestUtils} from '@deotaland/utils'
|
||
import {permissionRoutes} from '../router/index.js';
|
||
import { nextTick } from 'vue';
|
||
// 管理员认证状态管理store
|
||
export const useAuthStore = defineStore('auth', {
|
||
state: () => ({
|
||
token: localStorage.getItem('token') || '',
|
||
user: JSON.parse(localStorage.getItem('user') || 'null'),
|
||
permissionRouter: JSON.parse(localStorage.getItem('permissionRouter') || '[]'),
|
||
permissionButton: JSON.parse(localStorage.getItem('permissionButton') || '[]'),
|
||
router: null,
|
||
routesUpdated: 0,//路由更新次数
|
||
routerList: window.location.hostname.indexOf('local') === -1 ? [] : permissionRoutes,//侧边栏路由
|
||
}),
|
||
|
||
getters: {
|
||
// 判断是否已登录
|
||
isAuthenticated: (state) => !!state.token && !!state.user,
|
||
// 获取用户名
|
||
username: (state) => state.user?.username || '',
|
||
// 获取用户角色
|
||
userRole: (state) => state.user?.role || '',
|
||
// 判断是否有按钮权限
|
||
hasButtonPermission: (state) => (buttonName) => state.permissionButton.includes(buttonName),
|
||
},
|
||
|
||
actions: {
|
||
// 登录
|
||
login(loginData,callback) {
|
||
const { accessToken} = loginData
|
||
this.token = accessToken
|
||
this.user = loginData
|
||
// 持久化存储
|
||
localStorage.setItem('token', accessToken)
|
||
localStorage.setItem('user', JSON.stringify(this.user))
|
||
this.getPermissionCodesByUserId(callback);
|
||
},
|
||
|
||
// 登出
|
||
logout() {
|
||
this.token = ''
|
||
this.user = null
|
||
// 清除持久化存储
|
||
localStorage.removeItem('token')
|
||
localStorage.removeItem('user')
|
||
localStorage.removeItem('admin-remember-me')
|
||
},
|
||
//获取用户权限
|
||
async getPermissionCodesByUserId(callback){
|
||
let requestUrl = {
|
||
method: adminApi.default.getPermissionCodesByUserId.method,
|
||
url: adminApi.default.getPermissionCodesByUserId.url.replace('{userId}', this.user.userId),
|
||
}
|
||
const res = await requestUtils.common(requestUrl);
|
||
if(res.code === 0){
|
||
const data = res.data;
|
||
this.permissionRouter = data.filter(item => item.indexOf('router') !== -1);
|
||
this.permissionButton = data.filter(item => item.indexOf('admin') !== -1);
|
||
//本地存储权限列表
|
||
localStorage.setItem('permissionRouter', JSON.stringify(this.permissionRouter))
|
||
localStorage.setItem('permissionButton', JSON.stringify(this.permissionButton))
|
||
this.addPermissionRoutes(callback);
|
||
}
|
||
},
|
||
// 动态添加权限路由
|
||
addPermissionRoutes(callback) {
|
||
if (!this.router) {
|
||
console.error('Router 未初始化');
|
||
callback && callback();
|
||
return;
|
||
}
|
||
// const accessibleRoutes = permissionRoutes.filter(route => {
|
||
// const hasPermission = this.permissionRouter.includes('router:'+route.name);
|
||
// return hasPermission;
|
||
// });
|
||
let accessibleRoutes = [];
|
||
|
||
const findRouteInTree = (tree, name) => {
|
||
for (const route of tree) {
|
||
if (route.name === name) {
|
||
return route;
|
||
}
|
||
if (route.children) {
|
||
const found = findRouteInTree(route.children, name);
|
||
if (found) return found;
|
||
}
|
||
}
|
||
return null;
|
||
};
|
||
|
||
const findRouteInPermissionRoutes = (name) => {
|
||
return findRouteInTree(permissionRoutes, name);
|
||
};
|
||
|
||
const deepCopyRoute = (route, includeChildren = false) => {
|
||
const copy = { ...route };
|
||
delete copy.children;
|
||
if (includeChildren && route.children) {
|
||
copy.children = route.children.map(child => deepCopyRoute(child, includeChildren));
|
||
}
|
||
return copy;
|
||
};
|
||
|
||
const builderRouterTree = (routes) => {
|
||
if (!routes || routes.length === 0) return;
|
||
|
||
for (let i = 0; i < routes.length; i++) {
|
||
const currentName = routes[i];
|
||
|
||
const targetRoute = findRouteInPermissionRoutes(currentName);
|
||
|
||
if (!targetRoute) {
|
||
console.warn(`未找到路由: ${currentName}`);
|
||
return;
|
||
}
|
||
|
||
if (i === 0) {
|
||
const existingRoute = accessibleRoutes.find(r => r.name === currentName);
|
||
|
||
if (!existingRoute) {
|
||
const newRoute = deepCopyRoute(targetRoute, false);
|
||
accessibleRoutes.push(newRoute);
|
||
}
|
||
} else {
|
||
const parentName = routes[i - 1];
|
||
const parentRoute = findRouteInTree(accessibleRoutes, parentName);
|
||
|
||
if (!parentRoute) {
|
||
console.warn(`父路由不存在: ${parentName}, 当前路由: ${currentName}, accessibleRoutes:`, accessibleRoutes);
|
||
return;
|
||
}
|
||
|
||
if (!parentRoute.children) {
|
||
parentRoute.children = [];
|
||
}
|
||
|
||
const existingChild = parentRoute.children.find(child => child.name === currentName);
|
||
|
||
if (!existingChild) {
|
||
const newChildRoute = deepCopyRoute(targetRoute, false);
|
||
parentRoute.children.push(newChildRoute);
|
||
}
|
||
}
|
||
}
|
||
};
|
||
// 将权限字符串转成二维数组:去掉前缀后按“:”拆成层级数组
|
||
const permissionRouterTree = this.permissionRouter.map(code => {
|
||
// 去掉 router: 前缀
|
||
const remain = code.replace(/^router:/, '');
|
||
// 按冒号拆成层级
|
||
return remain.split(':');
|
||
});
|
||
console.log('permissionRouterTree:', permissionRouterTree);
|
||
permissionRouterTree.forEach(item => {
|
||
builderRouterTree(item);
|
||
});
|
||
if (accessibleRoutes.length === 0) {
|
||
console.warn('没有可访问的路由,请检查权限列表');
|
||
callback && callback();
|
||
return;
|
||
}
|
||
this.routerList = [];
|
||
accessibleRoutes.forEach(route => {
|
||
this.router.addRoute('Admin', route);
|
||
this.routerList.push(route);
|
||
});
|
||
this.routesUpdated++;
|
||
callback && callback();
|
||
},
|
||
// 检查认证状态
|
||
checkAuth() {
|
||
const storedToken = localStorage.getItem('token')
|
||
const storedUser = localStorage.getItem('user')
|
||
if (storedToken && storedUser) {
|
||
this.token = storedToken
|
||
this.user = JSON.parse(storedUser)
|
||
return true
|
||
}
|
||
return false
|
||
},
|
||
}
|
||
})
|
||
|
||
// 全局状态管理store
|
||
export const useAppStore = defineStore('app', {
|
||
state: () => ({
|
||
// 应用主题设置
|
||
theme: 'light',
|
||
// 国际化语言设置
|
||
locale: 'zh-CN',
|
||
// 加载状态
|
||
isLoading: false,
|
||
// 侧边栏展开状态(响应式适配用)
|
||
sidebarCollapsed: false,
|
||
// 移动端菜单显示状态
|
||
mobileMenuVisible: false
|
||
}),
|
||
|
||
getters: {
|
||
// 获取当前主题
|
||
currentTheme: (state) => state.theme,
|
||
// 获取当前语言
|
||
currentLocale: (state) => state.locale,
|
||
// 判断是否是深色主题
|
||
isDarkTheme: (state) => state.theme === 'dark',
|
||
// 判断是否是浅色主题
|
||
isLightTheme: (state) => state.theme === 'light',
|
||
// 获取加载状态(兼容性)
|
||
loading: (state) => state.isLoading
|
||
},
|
||
|
||
actions: {
|
||
// 切换主题
|
||
toggleTheme() {
|
||
this.theme = this.theme === 'light' ? 'dark' : 'light'
|
||
// 保存到localStorage
|
||
localStorage.setItem('theme', this.theme)
|
||
// 应用到document
|
||
document.documentElement.setAttribute('data-theme', this.theme)
|
||
},
|
||
|
||
// 设置主题
|
||
setTheme(theme) {
|
||
this.theme = theme
|
||
localStorage.setItem('theme', theme)
|
||
document.documentElement.setAttribute('data-theme', theme)
|
||
},
|
||
|
||
// 切换语言
|
||
toggleLocale() {
|
||
this.locale = this.locale === 'zh-CN' ? 'en-US' : 'zh-CN'
|
||
localStorage.setItem('locale', this.locale)
|
||
// 不再触发事件,由Vue的响应式系统自动通知
|
||
},
|
||
|
||
// 设置语言
|
||
setLocale(locale) {
|
||
this.locale = locale
|
||
localStorage.setItem('locale', locale)
|
||
// 不再触发事件,由Vue的响应式系统自动通知
|
||
},
|
||
|
||
// 设置加载状态
|
||
setLoading(loading) {
|
||
this.isLoading = loading
|
||
},
|
||
|
||
// 切换侧边栏状态
|
||
toggleSidebar() {
|
||
this.sidebarCollapsed = !this.sidebarCollapsed
|
||
},
|
||
|
||
// 设置侧边栏状态
|
||
setSidebarCollapsed(collapsed) {
|
||
this.sidebarCollapsed = collapsed
|
||
},
|
||
|
||
// 切换移动端菜单显示状态
|
||
toggleMobileMenu() {
|
||
this.mobileMenuVisible = !this.mobileMenuVisible
|
||
},
|
||
|
||
// 设置移动端菜单显示状态
|
||
setMobileMenuVisible(visible) {
|
||
this.mobileMenuVisible = visible
|
||
},
|
||
|
||
// 初始化应用状态
|
||
initApp() {
|
||
// 从localStorage读取保存的主题和语言设置
|
||
const savedTheme = localStorage.getItem('theme') || 'light'
|
||
const savedLocale = localStorage.getItem('locale') || 'zh-CN'
|
||
|
||
this.setTheme(savedTheme)
|
||
this.setLocale(savedLocale)
|
||
|
||
// 初始化移动端状态
|
||
const isMobile = window.innerWidth < 768
|
||
this.sidebarCollapsed = isMobile
|
||
this.mobileMenuVisible = false
|
||
}
|
||
}
|
||
})
|
||
|
||
// 用户状态管理store(可根据需要扩展)
|
||
export const useUserStore = defineStore('user', {
|
||
state: () => ({
|
||
userInfo: null,
|
||
isLoggedIn: false,
|
||
token: null
|
||
}),
|
||
|
||
getters: {
|
||
// 获取用户信息
|
||
user: (state) => state.userInfo,
|
||
// 判断是否已登录
|
||
loggedIn: (state) => state.isLoggedIn
|
||
},
|
||
|
||
actions: {
|
||
// 设置用户信息
|
||
setUser(userInfo) {
|
||
this.userInfo = userInfo
|
||
this.isLoggedIn = true
|
||
},
|
||
|
||
// 清除用户信息
|
||
clearUser() {
|
||
this.userInfo = null
|
||
this.isLoggedIn = false
|
||
this.token = null
|
||
localStorage.removeItem('token')
|
||
},
|
||
|
||
// 设置token
|
||
setToken(token) {
|
||
this.token = token
|
||
localStorage.setItem('token', token)
|
||
},
|
||
|
||
// 从localStorage初始化用户状态
|
||
initUser() {
|
||
const token = localStorage.getItem('token')
|
||
if (token) {
|
||
this.token = token
|
||
// 这里可以添加token验证逻辑
|
||
this.isLoggedIn = true
|
||
}
|
||
}
|
||
}
|
||
})
|
||
|
||
// 默认导出,用于兼容 useStore() 调用
|
||
export default useAppStore |