From 862ee17c88b187812575ee73da727f2ce0d803bd Mon Sep 17 00:00:00 2001 From: h_mo <596417202@qq.com> Date: Mon, 17 Jun 2024 23:56:24 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=8C=E5=96=84=E9=83=A8=E5=88=86?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- eslint.config.js | 2 ++ src/App.vue | 3 ++ src/pages.json | 6 ++-- src/pages/about/index.vue | 34 ++++++++++++++++++- src/pages/demo/index.vue | 10 ++---- src/pages/index/index.vue | 25 ++++++-------- src/pages/log/index.vue | 8 +++-- src/router/guard.ts | 56 ++++++++++++++++--------------- src/services/api/auth.ts | 6 +++- src/stores/modules/auth.ts | 68 -------------------------------------- src/stores/modules/user.ts | 45 +++++++++++++++++++++---- src/utils/auth.ts | 26 +++++++++++++-- src/utils/character.ts | 13 ++++++++ src/utils/env.ts | 4 +-- src/utils/http/index.ts | 20 +++++++---- src/utils/platform.ts | 22 ++++++------ vite.config.ts | 3 ++ 17 files changed, 200 insertions(+), 151 deletions(-) delete mode 100644 src/stores/modules/auth.ts diff --git a/eslint.config.js b/eslint.config.js index 2fe17c7..530a235 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -29,6 +29,8 @@ export default antfu({ 'style/brace-style': ['error', '1tbs', { allowSingleLine: true }], 'vue/script-indent': ['error', 2, { baseIndent: 0 }], 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off', + 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', + 'no-useless-catch': 'off', }, env: { node: true, diff --git a/src/App.vue b/src/App.vue index 6fe725a..735c9d7 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,10 +1,13 @@ diff --git a/src/pages/index/index.vue b/src/pages/index/index.vue index 122890d..9d46c09 100644 --- a/src/pages/index/index.vue +++ b/src/pages/index/index.vue @@ -1,24 +1,19 @@ diff --git a/src/router/guard.ts b/src/router/guard.ts index dcc62f2..fc82141 100644 --- a/src/router/guard.ts +++ b/src/router/guard.ts @@ -1,4 +1,5 @@ import type { Router } from 'uni-mini-router/lib/interfaces'; +import { isLogin } from '@/utils/auth'; export function createRouterGuard(router: Router) { createBeforeEachGuard(router); @@ -6,37 +7,38 @@ export function createRouterGuard(router: Router) { } function createBeforeEachGuard(router: Router) { - router.beforeEach((_1, _2, next) => { - // const authStore = useAuthStore(); - // if (to && to?.meta?.ignoreAuth) { - // // 如果目标路由忽略验证直接跳转 - // next(); - // } else if (!authStore.isLogin && to && to.name !== 'Login') { - // // 如果没有登录且目标路由不是登录页面则跳转到登录页面 - // // 将目标路由和参数传入登录页面,登录成功后直接跳转到目标路由,优化体验 - // next({ name: 'Login', params: { redirect: to.name!, ...to.query }, navType: 'push' }); - // } else if (authStore.isLogin && to && to.name === 'Login') { - // // 如果已经登录且目标页面是登录页面则跳转至首页 - // next({ name: 'Home', navType: 'replaceAll' }); - // } else { - // next(); - // } + router.beforeEach((to, _, next) => { + console.log('beforeEach', to); + const _isLogin = isLogin(); + if (to && to?.meta?.ignoreAuth) { + // 如果目标路由忽略验证直接跳转 + next(); + } else if (!_isLogin && to && to.name !== 'Login') { + // 如果没有登录且目标路由不是登录页面则跳转到登录页面 + // 将目标路由和参数传入登录页面,登录成功后直接跳转到目标路由,优化体验 + next({ name: 'Login', params: { redirect: to.name!, ...to.query }, navType: 'push' }); + } else if (_isLogin && to && to.name === 'Login') { + // 如果已经登录且目标页面是登录页面则跳转至首页 + next({ name: 'Home', navType: 'replaceAll' }); + } else { + next(); + } next(); }); } function createAfterEachGuard(router: Router) { - router.afterEach((_) => { - // if (to && to?.meta?.ignoreAuth) - // return; - // const authStore = useAuthStore(); - // if (!authStore.isLogin && to && to.name !== 'Login') { - // // 如果没有登录且目标路由不是登录页面则跳转到登录页面 - // router.push({ name: 'Login', params: { ...to.query } }); - // } else if (authStore.isLogin && to && to.name === 'Login') { - // // 如果已经登录且目标页面是登录页面则跳转至首页 - // router.replaceAll({ name: 'Home' }); - // } - console.log('afterEach', _); + router.afterEach((to) => { + if (to && to?.meta?.ignoreAuth) + return; + const _isLogin = isLogin(); + if (!_isLogin && to && to.name !== 'Login') { + // 如果没有登录且目标路由不是登录页面则跳转到登录页面 + router.push({ name: 'Login', params: { ...to.query } }); + } else if (_isLogin && to && to.name === 'Login') { + // 如果已经登录且目标页面是登录页面则跳转至首页 + router.replaceAll({ name: 'Home' }); + } + console.log('afterEach', to); }); } diff --git a/src/services/api/auth.ts b/src/services/api/auth.ts index 3d2d7e6..3de0828 100644 --- a/src/services/api/auth.ts +++ b/src/services/api/auth.ts @@ -9,7 +9,11 @@ const REFRESH_TOKEN = '/refresh/token'; * @param params */ export function login(params: LoginParams) { - return request.Post(LOGIN, params); + return request.Post(LOGIN, params, { + meta: { + ignoreAuth: true, + }, + }); } /** diff --git a/src/stores/modules/auth.ts b/src/stores/modules/auth.ts deleted file mode 100644 index 904bc28..0000000 --- a/src/stores/modules/auth.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { defineStore } from 'pinia'; -import { useRequest } from 'alova'; -import { getCache, removeCache, setCache } from '@/utils/cache'; -import { TOKEN_KEY } from '@/enums/cacheEnum'; -import { login as loginApi, logout as logoutApi } from '@/services/api/auth'; - -const authenticationScheme = 'Bearer'; - -export const useAuthStore = defineStore('AuthStore', () => { - const token = ref(null); - - const initToken = () => { - token.value = getCache(TOKEN_KEY) || null; - }; - - function setToken(value: string | null) { - setCache(TOKEN_KEY, value); - token.value = value; - } - - const getAuthorization = computed(() => { - return token.value ? `${authenticationScheme} ${token.value}` : ''; - }); - - // 登录 - const { send: sendLogin } = useRequest(loginApi, { immediate: false }); - const login = async (params: LoginParams) => { - try { - const res = await sendLogin(params); - setToken(res.token); - } catch (error) { - console.log(error); - } - }; - - // 登出 - const { send: sendLogout } = useRequest(logoutApi, { immediate: false }); - async function logout() { - try { - await sendLogout(); - removeCache(TOKEN_KEY); - token.value = null; - } catch (err: any) { - console.error(err); - } - } - - // 刷新token - async function refreshToken() { - try { - // const res = await refreshToken(); - // setToken(res.data.access_token); - // return res.data; - } catch (err: any) { - console.error(err); - } - } - - return { - token, - initToken, - setToken, - getAuthorization, - login, - logout, - refreshToken, - }; -}); diff --git a/src/stores/modules/user.ts b/src/stores/modules/user.ts index 77ed453..cf78510 100644 --- a/src/stores/modules/user.ts +++ b/src/stores/modules/user.ts @@ -1,36 +1,69 @@ import { defineStore } from 'pinia'; import { useRequest } from 'alova'; -import { useAuthStore } from './auth'; import { getUserInfoApi } from '@/services/api/user'; import type { UserInfoModel } from '@/services/model/userModel'; +import { login as loginApi } from '@/services/api/auth'; +import { getToken, isLogin, setToken } from '@/utils/auth'; +import { removeCache } from '@/utils/cache'; +import { TOKEN_KEY } from '@/enums/cacheEnum'; export const useUserStore = defineStore('UserStore', () => { + const token = ref(null); const userInfo = ref(null); - const authStore = useAuthStore(); + // 初始化 + function initUserInfo() { + if (isLogin()) { + token.value = getToken(); + getUserInfo(); + } + } - const { send: _getUserInfo } = useRequest(getUserInfoApi, { initialData: null, immediate: false }); + // 是否登录 + const loggedIn = computed(() => !!token.value); + + // 登录 + const { send: sendLogin } = useRequest(loginApi, { immediate: false }); async function login(params: LoginParams) { try { - await authStore.login(params); + const res = await sendLogin(params); + token.value = res.token; + setToken(res.token); await getUserInfo(); } catch (error) { - console.log(error); + throw error; } } // 获取用户信息 + const { send: _getUserInfo } = useRequest(getUserInfoApi, { initialData: null, immediate: false }); async function getUserInfo() { try { userInfo.value = await _getUserInfo(); } catch (error) { - console.log(error); + throw error; + } + } + + // 登出 + // const { send: sendLogout } = useRequest(logoutApi, { immediate: false }); + async function logout() { + try { + // await sendLogout(); + removeCache(TOKEN_KEY); + userInfo.value = null; + token.value = null; + } catch (err: any) { + throw err; } } return { userInfo, + loggedIn, login, + logout, getUserInfo, + initUserInfo, }; }); diff --git a/src/utils/auth.ts b/src/utils/auth.ts index 2b5dbb3..552f2a0 100644 --- a/src/utils/auth.ts +++ b/src/utils/auth.ts @@ -1,4 +1,26 @@ -import { getCache } from '@/utils/cache'; +import { getCache, setCache } from '@/utils/cache'; import { TOKEN_KEY } from '@/enums/cacheEnum'; -export const TOKEN = () => getCache(TOKEN_KEY) || undefined; +const authenticationScheme = 'Bearer'; + +export function getToken() { + return getCache(TOKEN_KEY) || null; +} + +export function getAuthorization() { + const token = getToken(); + return token ? `${authenticationScheme} ${token}` : null; +} + +export function setToken(token: string) { + return setCache(TOKEN_KEY, token); +} + +export function removeToken() { + return setCache(TOKEN_KEY, null); +} + +// 是否登录 +export function isLogin() { + return !!getToken(); +} diff --git a/src/utils/character.ts b/src/utils/character.ts index d424a8a..70a4d82 100644 --- a/src/utils/character.ts +++ b/src/utils/character.ts @@ -1,3 +1,6 @@ +import { random } from 'lodash-es'; +import multiavatar from '@multiavatar/multiavatar'; + const CHS_RANGE_START = 0x4E00; // 简体中文编码范围开始 const CHS_RANGE_END = 0x9FA5; // 简体中文编码范围结束 @@ -19,3 +22,13 @@ export function getRandomChsString(length: number) { } return result; } + +/** + * 随机 svg 图标 + */ +export function getRandomIcon() { + const svgCode = multiavatar(getRandomChsString(random(16, 32))); + return `data:image/svg+xml;charset=utf-8,${encodeURIComponent( + svgCode, + )}`; +} diff --git a/src/utils/env.ts b/src/utils/env.ts index 40f84dd..792d798 100644 --- a/src/utils/env.ts +++ b/src/utils/env.ts @@ -70,7 +70,7 @@ export function isUseMock(): boolean { * @example: */ export function getBaseUrl(): string { - return (isH5 && isDevMode()) ? getEnvValue('VITE_PROXY_PREFIX') : getEnvValue('VITE_BASE_URL'); + return (isH5() && isDevMode()) ? getEnvValue('VITE_PROXY_PREFIX') : getEnvValue('VITE_BASE_URL'); } /** @@ -79,5 +79,5 @@ export function getBaseUrl(): string { * @example: */ export function getUploadUrl(): string { - return (isH5 && isDevMode()) ? getEnvValue('VITE_UPLOAD_PROXY_PREFIX') : getEnvValue('VITE_UPLOAD_URL'); + return (isH5() && isDevMode()) ? getEnvValue('VITE_UPLOAD_PROXY_PREFIX') : getEnvValue('VITE_UPLOAD_URL'); } diff --git a/src/utils/http/index.ts b/src/utils/http/index.ts index f802f34..5ec2d96 100644 --- a/src/utils/http/index.ts +++ b/src/utils/http/index.ts @@ -4,13 +4,13 @@ import { assign } from 'lodash-es'; import { checkStatus } from './checkStatus'; import { getBaseUrl, isUseMock } from '@/utils/env'; import { mockAdapter } from '@/mock'; -import { useAuthStore } from '@/stores/modules/auth'; import { ContentTypeEnum, ResultEnum } from '@/enums/httpEnum'; import type { API } from '@/services/model/baseModel'; +import { getAuthorization } from '@/utils/auth'; const BASE_URL = getBaseUrl(); -const HEADER = { +const ContentType = { 'Content-Type': ContentTypeEnum.JSON, 'Accept': 'application/json, text/plain, */*', }; @@ -29,8 +29,14 @@ const alovaInstance = createAlova({ }), timeout: 5000, beforeRequest: (method) => { - const authStore = useAuthStore(); - method.config.headers = assign(method.config.headers, HEADER, authStore.getAuthorization); + method.config.headers = assign(method.config.headers, ContentType); + const { config } = method; + const ignoreAuth = !config.meta?.ignoreAuth; + const authorization = ignoreAuth ? getAuthorization() : null; + if (ignoreAuth && !authorization) { + throw new Error('[请求错误]:未登录'); + } + method.config.headers.authorization = getAuthorization(); }, responded: { /** @@ -52,16 +58,16 @@ const alovaInstance = createAlova({ return data as any; } checkStatus(statusCode, message || ''); - throw new Error(`[请求错误]:${message}`); + throw new Error(`请求错误[${code}]:${message}`); } - throw new Error(`[请求错误]:${errMsg}`); + throw new Error(`请求错误[${statusCode}]:${errMsg}`); }, /** * 请求失败的拦截器,请求错误时将会进入该拦截器。 */ onError: (err) => { - throw new Error(`[请求错误]:${err}`); + throw new Error(`请求错误:${err}`); }, }, }); diff --git a/src/utils/platform.ts b/src/utils/platform.ts index 974ddd2..d29584e 100644 --- a/src/utils/platform.ts +++ b/src/utils/platform.ts @@ -2,14 +2,16 @@ * @description 获取当前平台 */ -const platform = PLATFORM; -const isH5 = platform === 'h5'; -const isApp = platform === 'app'; -const isMp = platform.startsWith('mp-'); +export const platform = PLATFORM; -export { - platform, - isH5, - isApp, - isMp, -}; +export function isH5() { + return platform === 'h5'; +} + +export function isApp() { + return platform === 'app'; +} + +export function isMp() { + return platform.startsWith('mp-'); +} diff --git a/vite.config.ts b/vite.config.ts index ce65922..9ca06fe 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -62,6 +62,9 @@ export default defineConfig(async ({ mode }) => { { 'uni-mini-router': ['useRouter', 'useRoute'], }, + { + alova: ['useRequest'], + }, ], dts: 'typings/auto-imports.d.ts', eslintrc: {