194 lines
5.6 KiB
TypeScript
194 lines
5.6 KiB
TypeScript
import type { AuthPermissionInfo, Recordable, UserInfo } from '@vben/types';
|
||
|
||
import type { AuthApi } from '#/api';
|
||
|
||
import { ref } from 'vue';
|
||
import { useRouter } from 'vue-router';
|
||
|
||
import { LOGIN_PATH } from '@vben/constants';
|
||
import { preferences } from '@vben/preferences';
|
||
import { resetAllStores, useAccessStore, useUserStore } from '@vben/stores';
|
||
|
||
import { notification } from 'ant-design-vue';
|
||
import { defineStore } from 'pinia';
|
||
|
||
import {
|
||
getAuthPermissionInfoApi,
|
||
loginApi,
|
||
logoutApi,
|
||
register,
|
||
smsLogin,
|
||
socialLogin,
|
||
} from '#/api';
|
||
import { $t } from '#/locales';
|
||
|
||
export const useAuthStore = defineStore('auth', () => {
|
||
const accessStore = useAccessStore();
|
||
const userStore = useUserStore();
|
||
const router = useRouter();
|
||
|
||
const loginLoading = ref(false);
|
||
|
||
/**
|
||
* 异步处理登录操作
|
||
* Asynchronously handle the login process
|
||
* @param type 登录类型
|
||
* @param params 登录表单数据
|
||
* @param onSuccess 登录成功后的回调函数
|
||
*/
|
||
async function authLogin(
|
||
type: 'mobile' | 'register' | 'social' | 'username',
|
||
params: Recordable<any>,
|
||
onSuccess?: () => Promise<void> | void,
|
||
) {
|
||
// 异步处理用户登录操作并获取 accessToken
|
||
let userInfo: null | UserInfo = null;
|
||
try {
|
||
let loginResult: AuthApi.LoginResult;
|
||
loginLoading.value = true;
|
||
switch (type) {
|
||
case 'mobile': {
|
||
loginResult = await smsLogin(params as AuthApi.SmsLoginParams);
|
||
break;
|
||
}
|
||
case 'register': {
|
||
loginResult = await register(params as AuthApi.RegisterParams);
|
||
break;
|
||
}
|
||
case 'social': {
|
||
loginResult = await socialLogin(params as AuthApi.SocialLoginParams);
|
||
break;
|
||
}
|
||
default: {
|
||
loginResult = await loginApi(params);
|
||
}
|
||
}
|
||
const { accessToken, refreshToken } = loginResult;
|
||
|
||
// 如果成功获取到 accessToken
|
||
if (accessToken) {
|
||
accessStore.setAccessToken(accessToken);
|
||
accessStore.setRefreshToken(refreshToken);
|
||
|
||
// 获取用户信息并存储到 userStore、accessStore 中
|
||
// TODO @芋艿:清理掉 accessCodes 相关的逻辑
|
||
// const [fetchUserInfoResult, accessCodes] = await Promise.all([
|
||
// fetchUserInfo(),
|
||
// // getAccessCodesApi(),
|
||
// ]);
|
||
const fetchUserInfoResult = await fetchUserInfo();
|
||
|
||
userInfo = fetchUserInfoResult.user;
|
||
|
||
if (accessStore.loginExpired) {
|
||
accessStore.setLoginExpired(false);
|
||
} else {
|
||
onSuccess
|
||
? await onSuccess?.()
|
||
: await router.push(
|
||
userInfo.homePath || preferences.app.defaultHomePath,
|
||
);
|
||
}
|
||
|
||
if (userInfo?.nickname) {
|
||
notification.success({
|
||
description: `${$t('authentication.loginSuccessDesc')}:${userInfo?.nickname}`,
|
||
duration: 3,
|
||
message: $t('authentication.loginSuccess'),
|
||
});
|
||
}
|
||
}
|
||
} finally {
|
||
loginLoading.value = false;
|
||
}
|
||
|
||
return {
|
||
userInfo,
|
||
};
|
||
}
|
||
|
||
async function logout(redirect: boolean = true) {
|
||
try {
|
||
const accessToken = accessStore.accessToken as string;
|
||
if (accessToken) {
|
||
await logoutApi(accessToken);
|
||
}
|
||
} catch {
|
||
// 不做任何处理
|
||
}
|
||
resetAllStores();
|
||
accessStore.setLoginExpired(false);
|
||
|
||
// 回登录页带上当前路由地址
|
||
await router.replace({
|
||
path: LOGIN_PATH,
|
||
query: redirect
|
||
? {
|
||
redirect: encodeURIComponent(router.currentRoute.value.fullPath),
|
||
}
|
||
: {},
|
||
});
|
||
}
|
||
|
||
async function fetchUserInfo() {
|
||
// 加载
|
||
let authPermissionInfo: AuthPermissionInfo | null = null;
|
||
authPermissionInfo = await getAuthPermissionInfoApi();
|
||
// userStore
|
||
userStore.setUserInfo(authPermissionInfo.user);
|
||
userStore.setUserRoles(authPermissionInfo.roles);
|
||
// accessStore - 隐藏不需要的菜单项 + 重命名菜单
|
||
const processedMenus = renameMenuItems(hideMenuItems(authPermissionInfo.menus));
|
||
accessStore.setAccessMenus(processedMenus);
|
||
accessStore.setAccessCodes(authPermissionInfo.permissions);
|
||
return authPermissionInfo;
|
||
}
|
||
|
||
/** 递归标记菜单为隐藏(visible=false),保留路由可直接访问 */
|
||
function hideMenuItems(menus: any[]): any[] {
|
||
// 需要从侧边栏隐藏的菜单路径(ROI 区域配置已整合到摄像头管理中)
|
||
const hiddenPaths = new Set(['roi']);
|
||
const hiddenNameKeywords = ['ROI', 'roi'];
|
||
return menus.map((menu) => {
|
||
const shouldHide =
|
||
hiddenPaths.has(menu.path) ||
|
||
(menu.name &&
|
||
hiddenNameKeywords.some((kw: string) => menu.name.includes(kw)));
|
||
return {
|
||
...menu,
|
||
visible: shouldHide ? false : menu.visible,
|
||
children: menu.children ? hideMenuItems(menu.children) : menu.children,
|
||
};
|
||
});
|
||
}
|
||
|
||
/** 递归重命名菜单项 */
|
||
function renameMenuItems(menus: any[]): any[] {
|
||
const renameMap: Record<string, string> = {
|
||
'摄像头告警汇总': '告警看板',
|
||
'告警汇总': '告警看板',
|
||
};
|
||
return menus.map((menu) => {
|
||
const newName = menu.name && renameMap[menu.name];
|
||
return {
|
||
...menu,
|
||
name: newName || menu.name,
|
||
meta: newName && menu.meta ? { ...menu.meta, title: newName } : menu.meta,
|
||
children: menu.children ? renameMenuItems(menu.children) : menu.children,
|
||
};
|
||
});
|
||
}
|
||
|
||
function $reset() {
|
||
loginLoading.value = false;
|
||
}
|
||
|
||
return {
|
||
$reset,
|
||
authLogin,
|
||
fetchUserInfo,
|
||
loginLoading,
|
||
logout,
|
||
};
|
||
});
|