Files
cn-rdms-web/src/store/modules/auth/index.ts
2026-05-18 13:19:45 +08:00

224 lines
5.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { computed, reactive, ref } from 'vue';
import { useRoute } from 'vue-router';
import { defineStore } from 'pinia';
import { useLoading } from '@sa/hooks';
import { clearAuthApiCache, fetchGetUserInfo, fetchLogin } from '@/service/api';
import { resetSessionExpiredFlag } from '@/service/request/shared';
import { useRouterPush } from '@/hooks/common/router';
import { localStg } from '@/utils/storage';
import { SetupStoreId } from '@/enum';
import { $t } from '@/locales';
import { useDictStore } from '../dict';
import { useRouteStore } from '../route';
import { useTabStore } from '../tab';
import { useObjectContextStore } from '../object-context';
import { clearAuthStorage, getToken } from './shared';
export const useAuthStore = defineStore(SetupStoreId.Auth, () => {
const route = useRoute();
const authStore = useAuthStore();
const routeStore = useRouteStore();
const tabStore = useTabStore();
const dictStore = useDictStore();
const objectContextStore = useObjectContextStore();
const { toLogin, redirectFromLogin } = useRouterPush(false);
const { loading: loginLoading, startLoading, endLoading } = useLoading();
const token = ref(getToken());
const userInfo: Api.Auth.UserInfo = reactive({
userId: '',
userName: '',
nickname: '',
roles: [],
buttons: []
});
/** is super role in static route */
const isStaticSuper = computed(() => {
const { VITE_AUTH_ROUTE_MODE, VITE_STATIC_SUPER_ROLE } = import.meta.env;
return VITE_AUTH_ROUTE_MODE === 'static' && userInfo.roles.includes(VITE_STATIC_SUPER_ROLE);
});
/** Is login */
const isLogin = computed(() => Boolean(token.value));
/** Reset auth store */
async function resetStore() {
recordUserId();
clearAuthApiCache();
clearAuthStorage();
// setup store 没有内置 $reset需要显式重置内部状态避免 token / userInfo 残留导致 isLogin 误判。
token.value = '';
Object.assign(userInfo, {
userId: '',
userName: '',
nickname: '',
roles: [],
buttons: []
});
dictStore.resetDictCache();
objectContextStore.clearContext();
// 用路由名判断当前是否已在登录页,避免依赖 route.meta.constant ——
// workbench 等首页也是常量路由,原写法会让常量路由上的登出请求不跳转。
if (route.name !== 'login') {
await toLogin();
}
tabStore.cacheTabs();
await routeStore.resetStore();
}
/** Record the user ID of the previous login session Used to compare with the current user ID on next login */
function recordUserId() {
if (!userInfo.userId) {
return;
}
// Store current user ID locally for next login comparison
localStg.set('lastLoginUserId', userInfo.userId);
}
/**
* Check if current login user is different from previous login user If different, clear all tabs
*
* @returns {boolean} Whether to clear all tabs
*/
function checkTabClear(): boolean {
if (!userInfo.userId) {
return false;
}
const lastLoginUserId = localStg.get('lastLoginUserId');
// Clear all tabs if current user is different from previous user
if (lastLoginUserId !== userInfo.userId) {
localStg.remove('globalTabs');
tabStore.clearTabs();
return true;
}
return false;
}
/**
* Login
*
* @param userName User name
* @param password Password
* @param [redirect=true] Whether to redirect after login. Default is `true`
*/
async function login(userName: string, password: string, redirect = true) {
startLoading();
const { data: loginToken, error } = await fetchLogin(userName, password);
if (!error) {
const pass = await loginByToken(loginToken);
if (pass) {
// Check if the tab needs to be cleared
const isClear = checkTabClear();
let needRedirect = redirect;
if (isClear) {
// If the tab needs to be cleared,it means we don't need to redirect.
needRedirect = false;
}
await redirectFromLogin(needRedirect);
window.$notification?.success({
title: $t('page.login.common.loginSuccess'),
message: $t('page.login.common.welcomeBack', { userName: userInfo.userName }),
duration: 4500
});
}
} else {
resetStore();
}
endLoading();
}
async function loginByToken(loginToken: Api.Auth.LoginToken) {
clearAuthApiCache();
// 1. stored in the localStorage, the later requests need it in headers
localStg.set('token', loginToken.token);
localStg.set('refreshToken', loginToken.refreshToken);
// 2. get user info
const pass = await getUserInfo();
if (pass) {
await dictStore.initDictCache(true);
token.value = loginToken.token;
// 复位会话失效一次性锁,让下一次会话失效仍能正常提示
resetSessionExpiredFlag();
return true;
}
return false;
}
async function getUserInfo() {
const { data: info, error } = await fetchGetUserInfo();
if (!error) {
// update store
Object.assign(userInfo, info);
return true;
}
return false;
}
async function refreshUserInfo() {
const { data: info, error } = await fetchGetUserInfo(true);
if (!error) {
Object.assign(userInfo, info);
return true;
}
return false;
}
async function initUserInfo() {
const hasToken = getToken();
if (!hasToken || userInfo.userId) {
return;
}
const pass = await getUserInfo();
if (!pass) {
resetStore();
}
}
return {
token,
userInfo,
isStaticSuper,
isLogin,
loginLoading,
resetStore,
login,
initUserInfo,
refreshUserInfo
};
});