// 导入单独抽离的类型 import type { UserInfo, LoginForm, LoginResponse, ResetPasswordForm, ResetPasswordResponse, ChangePasswordForm, ChangePasswordResponse } from '@/type/user'; import { request } from '@/api/index' import { useLocalStorage, useSessionStorage } from '@/utils/storage' import router from '@/router'; /** * 用户状态管理 Store * 核心功能:登录、登出、状态持久化、初始化用户信息 */ export const useUserStore = defineStore('user', () => { // ========== 响应式状态 ========== /** 用户基本信息 */ const userInfo = ref({ id: '', username: '', nickname: '', roles: [], permissions: [] }); /** 用户登录令牌 */ const token = ref(''); /** 是否加载中(登录/登出请求时) */ const loading = ref(false); // ========== 方法 ========== /** * 用户登录 * @param form 登录表单数据 * @returns Promise */ const login = async (form: LoginForm): Promise => { try { loading.value = true; // 使用API服务进行登录请求 const response = await request.post('/login', form); // 从响应中获取数据 const res = response.data; ElNotification({ type: 'success', message: '登录成功', duration: 2000 }) // 更新响应式状态 userInfo.value = res.data.user; token.value = res.data.user.token ?? ''; // 持久化到本地存储(防止页面刷新丢失) useLocalStorage.set('user', res.data.user); useLocalStorage.set('token', res.data.user.token); } catch (error) { // 统一错误处理 const errMsg = error instanceof Error ? error.message : '登录异常'; ElNotification({ type: 'error', message: errMsg, duration: 2000 }) throw new Error(errMsg); // 抛出错误让组件层捕获 } finally { loading.value = false; } }; /** * 用户登出 */ const logout = async (): Promise => { try { loading.value = true; // 使用API服务进行登出请求 await request.post('/logout'); } catch (error) { // 统一错误处理 const errMsg = error instanceof Error ? error.message : '登出异常'; ElNotification({ type: 'error', message: errMsg, duration: 2000 }) throw new Error(errMsg); // 抛出错误让组件层捕获 } finally { loading.value = false; } // 清空响应式状态 userInfo.value = { id: '', username: '', nickname: '', roles: [], permissions: [] }; token.value = ''; // 清除本地存储 useLocalStorage.remove('user'); useLocalStorage.remove('token'); useSessionStorage.remove('backPath'); useLocalStorage.remove('menus'); // 可选:登出后跳转到登录页(如果需要) // 使用 Vue Router 进行跳转 // 显示登出成功通知 ElNotification({ type: 'success', message: '退出登录', duration: 2000 }); // 跳转到登录页 router.push('/login'); }; /** * 初始化用户信息(页面刷新后恢复) */ const initUser = (): void => { try { const savedUser = useLocalStorage.get('user'); const savedToken = useLocalStorage.get('token'); const savedMenus = useLocalStorage.get('menus'); if (savedUser.value && savedToken.value) { // 类型断言 + 验证,确保数据格式正确 const parsedUser = savedUser.value as UserInfo; // 基础校验(防止本地存储数据被篡改) if (parsedUser.id && parsedUser.username) { userInfo.value = parsedUser; token.value = savedToken.value; } } } catch (error) { console.error('初始化用户信息失败:', error); // 校验失败则清空本地存储 useLocalStorage.remove('user'); useLocalStorage.remove('token'); } }; /** * 检查用户是否拥有指定权限 * @param permission 权限标识 * @returns boolean */ const hasPermission = (permission: string): boolean => { return userInfo.value.permissions.includes(permission); }; /** * 检查用户是否拥有指定角色 * @param role 角色标识 * @returns boolean */ const hasRole = (role: string): boolean => { return userInfo.value.roles.includes(role); }; /** * 重置密码 * @param form 重置密码表单数据 * @returns Promise */ const resetPassword = async (form: ResetPasswordForm): Promise => { try { loading.value = true; // 使用API服务进行重置密码请求 const response = await request.post('user/reset-password', form); // 从响应中获取数据 const res = response.data; ElNotification({ type: 'success', message: '密码重置成功', duration: 2000 }); // 重置成功后跳转到登录页 router.push('/login'); } catch (error) { // 统一错误处理 const errMsg = error instanceof Error ? error.message : '密码重置失败'; ElNotification({ type: 'error', message: errMsg, duration: 2000 }); throw new Error(errMsg); // 抛出错误让组件层捕获 } finally { loading.value = false; } }; /** * 修改密码 * @param form 修改密码表单数据 * @returns Promise */ const changePassword = async (form: ChangePasswordForm): Promise => { try { loading.value = true; // 使用API服务进行修改密码请求 const response = await request.post('user/change-password', form); // 从响应中获取数据 const res = response.data; ElNotification({ type: 'success', message: '密码修改成功', duration: 2000 }); // 修改成功后跳转到登录页 useLocalStorage.remove('token'); router.push('/login'); } catch (error) { // 统一错误处理 const errMsg = error instanceof Error ? error.message : '密码修改失败'; ElNotification({ type: 'error', message: errMsg, duration: 2000 }); throw new Error(errMsg); // 抛出错误让组件层捕获 } finally { loading.value = false; } }; // ========== 暴露状态和方法 ========== return { // 状态和数据 userInfo, token, loading, // 方法 login, logout, initUser, hasPermission, hasRole, resetPassword, changePassword }; });