mirror of
https://github.com/m-xlsea/ruoyi-plus-soybean.git
synced 2025-09-24 07:49:47 +08:00
feat(projects): 迁移登录完成
This commit is contained in:
@ -1,7 +1,11 @@
|
||||
import { ref, computed, reactive } from 'vue';
|
||||
import { ref, computed, reactive, unref } from 'vue';
|
||||
import type { Ref, ComputedRef } from 'vue';
|
||||
import { defineStore } from 'pinia';
|
||||
import { getUserInfo, getToken } from '@/utils';
|
||||
import { router as globalRouter } from '@/router';
|
||||
import { useRouterPush, useRouteQuery } from '@/composables';
|
||||
import { useLoading } from '@/hooks';
|
||||
import { fetchLogin, fetchUserInfo } from '@/service';
|
||||
import { getUserInfo, getToken, setUserInfo, setToken, setRefreshToken, clearAuthStorage } from '@/utils';
|
||||
|
||||
interface AuthStore {
|
||||
/** 用户信息 */
|
||||
@ -10,21 +14,94 @@ interface AuthStore {
|
||||
token: Ref<string>;
|
||||
/** 是否登录 */
|
||||
isLogin: ComputedRef<boolean>;
|
||||
/** 用户角色 */
|
||||
role: Ref<Auth.RoleType>;
|
||||
/**
|
||||
* 重置authStore
|
||||
* 是否需要跳转页面(例如当前页面是需要权限的,登出后需要跳转到登录页面)
|
||||
*/
|
||||
resetAuthStore(pushRoute: boolean): void;
|
||||
/** 登录的加载状态 */
|
||||
loginLoding: Ref<boolean>;
|
||||
/**
|
||||
* 登录
|
||||
* @param phone - 手机号
|
||||
* @param pwdOrCode - 密码或验证码
|
||||
* @param type - 登录方式: pwd - 密码登录; sms - 验证码登录
|
||||
*/
|
||||
login(phone: string, pwdOrCode: string, type: 'pwd' | 'sms'): void;
|
||||
}
|
||||
|
||||
export const useAuthStore = defineStore('auth-store', () => {
|
||||
const { toLogin, toLoginRedirect } = useRouterPush(false);
|
||||
const { loginRedirect } = useRouteQuery(false);
|
||||
const { loading: loginLoding, startLoading: startLoginLoading, endLoading: endLoginLoading } = useLoading();
|
||||
|
||||
const userInfo: Auth.UserInfo = reactive(getUserInfo());
|
||||
function handleSetUserInfo(data: Auth.UserInfo) {
|
||||
Object.assign(userInfo, data);
|
||||
}
|
||||
|
||||
const token = ref(getToken());
|
||||
function handleSetToken(data: string) {
|
||||
token.value = data;
|
||||
}
|
||||
|
||||
const isLogin = computed(() => Boolean(token.value));
|
||||
const role = ref<Auth.RoleType>('super');
|
||||
|
||||
function resetAuthStore(pushRoute: boolean = true) {
|
||||
const auth = useAuthStore();
|
||||
const route = unref(globalRouter.currentRoute);
|
||||
|
||||
clearAuthStorage();
|
||||
auth.$reset();
|
||||
|
||||
if (pushRoute && route.meta.requiresAuth) {
|
||||
toLogin();
|
||||
}
|
||||
}
|
||||
|
||||
async function login(phone: string, pwdOrCode: string, type: 'pwd' | 'sms') {
|
||||
startLoginLoading();
|
||||
const { data } = await fetchLogin(phone, pwdOrCode, type);
|
||||
if (data) {
|
||||
await loginByToken(data);
|
||||
}
|
||||
endLoginLoading();
|
||||
}
|
||||
|
||||
async function loginByToken(backendToken: ApiAuth.Token) {
|
||||
// 1.先把token存储到缓存中
|
||||
const { token, refreshToken } = backendToken;
|
||||
setToken(token);
|
||||
setRefreshToken(refreshToken);
|
||||
|
||||
// 2.获取用户信息
|
||||
const { data } = await fetchUserInfo();
|
||||
if (data) {
|
||||
// 成功后把用户信息存储到缓存中
|
||||
setUserInfo(data);
|
||||
handleSetToken(token);
|
||||
handleSetUserInfo(data);
|
||||
// 3. 跳转登录后的地址
|
||||
toLoginRedirect(loginRedirect.value);
|
||||
// 4.登录成功弹出欢迎提示
|
||||
window.$notification?.success({
|
||||
title: '登录成功!',
|
||||
content: `欢迎回来,${userInfo.userName}!`,
|
||||
duration: 3000
|
||||
});
|
||||
} else {
|
||||
// 不成功则重置状态
|
||||
resetAuthStore(false);
|
||||
}
|
||||
}
|
||||
|
||||
const authStore: AuthStore = {
|
||||
userInfo,
|
||||
token,
|
||||
isLogin,
|
||||
role
|
||||
resetAuthStore,
|
||||
loginLoding,
|
||||
login
|
||||
};
|
||||
|
||||
return authStore;
|
||||
|
@ -26,7 +26,7 @@ interface RouteStore {
|
||||
* 获取路由路径
|
||||
* @description getRouteName 和 getRoutePath 优先使用 getRouteName
|
||||
*/
|
||||
getRoutePath(key: AuthRoute.RouteKey): AuthRoute.RoutePath<''> | undefined;
|
||||
getRoutePath(key: AuthRoute.RouteKey): AuthRoute.RoutePath | undefined;
|
||||
/** 获取路由路径 */
|
||||
getRouteTitle(key: AuthRoute.RouteKey): string | undefined;
|
||||
}
|
||||
|
@ -37,3 +37,27 @@ export function getThemeColors(colors: [ColorType, string][]) {
|
||||
|
||||
return themeColor;
|
||||
}
|
||||
|
||||
/** windicss 暗黑模式 */
|
||||
export function handleWindicssDarkMode() {
|
||||
const DARK_CLASS = 'dark';
|
||||
function getHtmlElement() {
|
||||
return document.querySelector('html');
|
||||
}
|
||||
function addDarkClass() {
|
||||
const html = getHtmlElement();
|
||||
if (html) {
|
||||
html.classList.add(DARK_CLASS);
|
||||
}
|
||||
}
|
||||
function removeDarkClass() {
|
||||
const html = getHtmlElement();
|
||||
if (html) {
|
||||
html.classList.remove(DARK_CLASS);
|
||||
}
|
||||
}
|
||||
return {
|
||||
addDarkClass,
|
||||
removeDarkClass
|
||||
};
|
||||
}
|
||||
|
@ -1,11 +1,12 @@
|
||||
import { ref, computed } from 'vue';
|
||||
import { ref, computed, watch } from 'vue';
|
||||
import type { Ref, ComputedRef } from 'vue';
|
||||
import { defineStore } from 'pinia';
|
||||
import { useThemeVars } from 'naive-ui';
|
||||
import type { GlobalThemeOverrides } from 'naive-ui';
|
||||
import { useThemeVars, darkTheme, useOsTheme } from 'naive-ui';
|
||||
import type { GlobalThemeOverrides, GlobalTheme } from 'naive-ui';
|
||||
import { kebabCase } from 'lodash-es';
|
||||
import { useBoolean } from '@/hooks';
|
||||
import { getColorPalette } from '@/utils';
|
||||
import { getThemeColors } from './helpers';
|
||||
import { getThemeColors, handleWindicssDarkMode } from './helpers';
|
||||
|
||||
interface OtherColor {
|
||||
/** 信息 */
|
||||
@ -18,19 +19,31 @@ interface OtherColor {
|
||||
error: string;
|
||||
}
|
||||
|
||||
type BuiltInGlobalTheme = Omit<Required<GlobalTheme>, 'InternalSelectMenu' | 'InternalSelection'>;
|
||||
|
||||
interface ThemeStore {
|
||||
/** 暗黑模式 */
|
||||
darkMode: Ref<boolean>;
|
||||
/** 设置暗黑模式 */
|
||||
setDarkMode(dark: boolean): void;
|
||||
/** 切换/关闭 暗黑模式 */
|
||||
toggleDarkMode(dark: boolean): void;
|
||||
/** 主题颜色 */
|
||||
themeColor: Ref<string>;
|
||||
/** 其他颜色 */
|
||||
otherColor: ComputedRef<OtherColor>;
|
||||
/** naiveUI的主题配置 */
|
||||
naiveThemeOverrides: ComputedRef<GlobalThemeOverrides>;
|
||||
/** naive-ui暗黑主题 */
|
||||
naiveTheme: ComputedRef<BuiltInGlobalTheme | undefined>;
|
||||
}
|
||||
|
||||
type ThemeVarsKeys = keyof Exclude<GlobalThemeOverrides['common'], undefined>;
|
||||
|
||||
export const useThemeStore = defineStore('theme-store', () => {
|
||||
const themeVars = useThemeVars();
|
||||
const { bool: darkMode, setBool: setDarkMode, toggle: toggleDarkMode } = useBoolean();
|
||||
const { addDarkClass, removeDarkClass } = handleWindicssDarkMode();
|
||||
|
||||
const themeColor = ref('#1890ff');
|
||||
const otherColor = computed<OtherColor>(() => ({
|
||||
@ -62,6 +75,12 @@ export const useThemeStore = defineStore('theme-store', () => {
|
||||
};
|
||||
});
|
||||
|
||||
/** naive-ui暗黑主题 */
|
||||
const naiveTheme = computed(() => (darkMode.value ? darkTheme : undefined));
|
||||
|
||||
/** 操作系统暗黑主题 */
|
||||
const osTheme = useOsTheme();
|
||||
|
||||
/** 添加css vars至html */
|
||||
function addThemeCssVarsToHtml() {
|
||||
if (document.documentElement.style.cssText) return;
|
||||
@ -82,10 +101,40 @@ export const useThemeStore = defineStore('theme-store', () => {
|
||||
|
||||
init();
|
||||
|
||||
// 监听操作系统主题模式
|
||||
watch(
|
||||
osTheme,
|
||||
newValue => {
|
||||
const isDark = newValue === 'dark';
|
||||
if (isDark) {
|
||||
setDarkMode(true);
|
||||
} else {
|
||||
setDarkMode(false);
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
// 监听主题的暗黑模式
|
||||
watch(
|
||||
() => darkMode.value,
|
||||
newValue => {
|
||||
if (newValue) {
|
||||
addDarkClass();
|
||||
} else {
|
||||
removeDarkClass();
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
const themeStore: ThemeStore = {
|
||||
darkMode,
|
||||
setDarkMode,
|
||||
toggleDarkMode,
|
||||
themeColor,
|
||||
otherColor,
|
||||
naiveThemeOverrides
|
||||
naiveThemeOverrides,
|
||||
naiveTheme
|
||||
};
|
||||
|
||||
return themeStore;
|
||||
|
Reference in New Issue
Block a user