foreign-admin-ui/src/stores/user.ts

237 lines
7.6 KiB
TypeScript

// 导入单独抽离的类型
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<UserInfo>({
id: '',
username: '',
nickname: '',
roles: [],
permissions: []
});
/** 用户登录令牌 */
const token = ref<string>('');
/** 是否加载中(登录/登出请求时) */
const loading = ref<boolean>(false);
// ========== 方法 ==========
/**
* 用户登录
* @param form 登录表单数据
* @returns Promise<void>
*/
const login = async (form: LoginForm): Promise<void> => {
try {
loading.value = true;
// 使用API服务进行登录请求
const response = await request.post<LoginResponse>('/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<void> => {
try {
loading.value = true;
// 使用API服务进行登出请求
await request.post<LoginResponse>('/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<void>
*/
const resetPassword = async (form: ResetPasswordForm): Promise<void> => {
try {
loading.value = true;
// 使用API服务进行重置密码请求
const response = await request.post<ResetPasswordResponse>('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<void>
*/
const changePassword = async (form: ChangePasswordForm): Promise<void> => {
try {
loading.value = true;
// 使用API服务进行修改密码请求
const response = await request.post<ChangePasswordResponse>('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
};
});