From 5b8dda60bd74d2347e81e83c5ead4bb9fa58aa98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A5=94=E8=B7=91=E7=9A=84=E9=9D=A2=E6=9D=A1?= <1262327911@qq.com> Date: Sat, 21 May 2022 17:31:01 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9A=20=E6=96=B0=E5=A2=9E=E9=80=80?= =?UTF-8?q?=E5=87=BA=E7=99=BB=E5=BD=95=E6=8E=A5=E5=8F=A3=EF=BC=8C=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E5=85=A8=E5=B1=80=E6=8E=A5=E5=8F=A3=E5=B0=81=E8=A3=85?= =?UTF-8?q?=EF=BC=8C=E4=BF=AE=E6=94=B9=E7=99=BB=E5=BD=95=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/axios.config.ts | 9 ++++ src/api/axios.ts | 38 +++++++++++++--- src/api/http.ts | 9 ++-- src/api/path/photo.ts | 3 ++ .../api/index.ts => api/path/project.ts} | 8 ++-- src/api/path/system.api.ts | 23 ++++++++++ src/enums/httpEnum.ts | 7 +++ src/i18n/en/index.ts | 1 + .../modules/systemStore/systemStore.d.ts | 2 + src/store/modules/systemStore/systemStore.ts | 3 +- src/utils/router.ts | 14 ++++-- src/utils/storage.ts | 44 +++++++++++++++++-- src/views/login/index.vue | 13 ++++-- .../ProjectItemsList/hooks/useData.hook.ts | 2 +- .../components/CreateModal/index.vue | 20 +++++---- 15 files changed, 161 insertions(+), 35 deletions(-) create mode 100644 src/api/axios.config.ts create mode 100644 src/api/path/photo.ts rename src/{views/login/api/index.ts => api/path/project.ts} (68%) create mode 100644 src/api/path/system.api.ts diff --git a/src/api/axios.config.ts b/src/api/axios.config.ts new file mode 100644 index 00000000..9a6f2ee2 --- /dev/null +++ b/src/api/axios.config.ts @@ -0,0 +1,9 @@ +import { ModuleTypeEnum } from '@/enums/httpEnum' + +// 接口白名单(免登录) +export const fetchAllowList = [ + `${ModuleTypeEnum.SYSTEM}/login` +] + +// 接口黑名单 +export const fetchBlockList = [] \ No newline at end of file diff --git a/src/api/axios.ts b/src/api/axios.ts index 0cdd9386..ef102ed0 100644 --- a/src/api/axios.ts +++ b/src/api/axios.ts @@ -1,8 +1,12 @@ import axios, { AxiosResponse, AxiosRequestConfig } from 'axios' -import { ResultEnum } from "@/enums/httpEnum" -import { ErrorPageNameMap } from "@/enums/pageEnum" -import { redirectErrorPage } from '@/utils' +import { ResultEnum, RequestHttpHeaderEnum } from "@/enums/httpEnum" +import { PageEnum, ErrorPageNameMap } from "@/enums/pageEnum" +import { StorageEnum } from '@/enums/storageEnum' import { axiosPre } from '@/settings/httpSetting' +import { SystemStoreEnum, SystemStoreUserInfoEnum } from '@/store/modules/systemStore/systemStore.d' +import { redirectErrorPage, getLocalStorage, routerTurnByName } from '@/utils' +import { fetchAllowList } from './axios.config' +import includes from 'lodash/includes' interface MyResponseType { code: number; @@ -17,7 +21,15 @@ const axiosInstance = axios.create({ axiosInstance.interceptors.request.use( (config: AxiosRequestConfig) => { - config.headers = {} + // 白名单校验 + if (includes(fetchAllowList, config.url)) return config + // 获取 token + const info = getLocalStorage(StorageEnum.GO_SYSTEM_STORE) + // 重新登录 + if (!info) return routerTurnByName(PageEnum.BASE_LOGIN_NAME) + config.headers = { + [RequestHttpHeaderEnum.TOKEN]: info[SystemStoreEnum.USER_INFO][SystemStoreUserInfoEnum.USER_TOKEN] || '' + } return config }, (error: AxiosRequestConfig) => { @@ -29,9 +41,23 @@ axiosInstance.interceptors.request.use( axiosInstance.interceptors.response.use( (res: AxiosResponse) => { const { code } = res.data as { code: number } - if (code === ResultEnum.DATA_SUCCESS) return Promise.resolve(res.data) + + // 成功 + if (code === ResultEnum.DATA_SUCCESS) { + return Promise.resolve(res.data) + } + + // 登录过期 + if (code === ResultEnum.SERVER_FORBIDDEN) { + routerTurnByName(PageEnum.BASE_LOGIN_NAME) + return Promise.reject(res.data) + } + // 重定向 - if (ErrorPageNameMap.get(code)) redirectErrorPage(code) + if (ErrorPageNameMap.get(code)) { + redirectErrorPage(code) + } + return Promise.resolve(res.data) }, (err: AxiosResponse) => { diff --git a/src/api/http.ts b/src/api/http.ts index 13d69659..1542ff3e 100644 --- a/src/api/http.ts +++ b/src/api/http.ts @@ -1,25 +1,26 @@ import axiosInstance from './axios' import { RequestHttpEnum, ContentTypeEnum } from '@/enums/httpEnum' -export const get = (url: string) => { +export const get = (url: string, params?: object) => { return axiosInstance({ url: url, method: RequestHttpEnum.GET, + params: params, }) } -export const post = (url: string, params: object, headersType?: string) => { +export const post = (url: string, data?: object, headersType?: string) => { return axiosInstance({ url: url, method: RequestHttpEnum.POST, - data: params, + data: data, headers: { 'Content-Type': headersType || ContentTypeEnum.JSON } }) } -export const del = (url: string, params: object) => { +export const del = (url: string, params?: object) => { return axiosInstance({ url: url, method: RequestHttpEnum.DELETE, diff --git a/src/api/path/photo.ts b/src/api/path/photo.ts new file mode 100644 index 00000000..986fec7f --- /dev/null +++ b/src/api/path/photo.ts @@ -0,0 +1,3 @@ +import { http } from '@/api/http' +import { httpErrorHandle } from '@/utils' +import { RequestHttpEnum, ModuleTypeEnum } from '@/enums/httpEnum' diff --git a/src/views/login/api/index.ts b/src/api/path/project.ts similarity index 68% rename from src/views/login/api/index.ts rename to src/api/path/project.ts index c4634ac6..40f90649 100644 --- a/src/views/login/api/index.ts +++ b/src/api/path/project.ts @@ -2,10 +2,10 @@ import { http } from '@/api/http' import { httpErrorHandle } from '@/utils' import { RequestHttpEnum, ModuleTypeEnum } from '@/enums/httpEnum' -// 登录 -export const loginRequest = async (data: object) => { - try { - const res = await http(RequestHttpEnum.POST)(`${ModuleTypeEnum.SYSTEM}/login`, data); +// * 新增项目 +export const createProjectApi = async (data: object) => { + try { + const res = await http(RequestHttpEnum.POST)(`${ModuleTypeEnum.SYSTEM}/project/create`, data); return res; } catch { httpErrorHandle(); diff --git a/src/api/path/system.api.ts b/src/api/path/system.api.ts new file mode 100644 index 00000000..1197fd39 --- /dev/null +++ b/src/api/path/system.api.ts @@ -0,0 +1,23 @@ +import { http } from '@/api/http' +import { httpErrorHandle } from '@/utils' +import { RequestHttpEnum, ModuleTypeEnum } from '@/enums/httpEnum' + +// * 登录 +export const loginApi = async (data: object) => { + try { + const res = await http(RequestHttpEnum.POST)(`${ModuleTypeEnum.SYSTEM}/login`, data); + return res; + } catch { + httpErrorHandle(); + } +} + +// * 登出 +export const logoutApi = async () => { + try { + const res = await http(RequestHttpEnum.GET)(`${ModuleTypeEnum.SYSTEM}/logout`); + return res; + } catch(err) { + httpErrorHandle(); + } +} \ No newline at end of file diff --git a/src/enums/httpEnum.ts b/src/enums/httpEnum.ts index 3c6ffa0c..8bb72a91 100644 --- a/src/enums/httpEnum.ts +++ b/src/enums/httpEnum.ts @@ -11,6 +11,7 @@ export enum ResultEnum { SERVER_ERROR = 500, SERVER_FORBIDDEN = 403, NOT_FOUND = 404, + TOKEN_OVERDUE = 886, TIMEOUT = 10042, } @@ -22,6 +23,12 @@ export enum RequestDataTypeEnum { AJAX = 1, } +// 头部 +export enum RequestHttpHeaderEnum { + TOKEN = 'Token', + COOKIE = 'Cookie' +} + // 请求方法 export enum RequestHttpEnum { GET = 'get', diff --git a/src/i18n/en/index.ts b/src/i18n/en/index.ts index 140a3add..f398a737 100644 --- a/src/i18n/en/index.ts +++ b/src/i18n/en/index.ts @@ -11,6 +11,7 @@ const global = { help: 'Help', contact: 'Contact Us', logout: 'Logout', + logout_success: 'Logout success', // system setting sys_set: 'System Setting', lang_set: 'Language Setting', diff --git a/src/store/modules/systemStore/systemStore.d.ts b/src/store/modules/systemStore/systemStore.d.ts index 9bfec8ed..acdc8120 100644 --- a/src/store/modules/systemStore/systemStore.d.ts +++ b/src/store/modules/systemStore/systemStore.d.ts @@ -2,12 +2,14 @@ export enum SystemStoreUserInfoEnum { USER_TOKEN = 'userToken', USER_ID = 'userId', USER_NAME = 'userName', + NICK_NAME = 'nickName', } export interface UserInfoType { [SystemStoreUserInfoEnum.USER_TOKEN]?: string, [SystemStoreUserInfoEnum.USER_ID]?: string, [SystemStoreUserInfoEnum.USER_NAME]?: string, + [SystemStoreUserInfoEnum.NICK_NAME]?: string, } export enum SystemStoreEnum { diff --git a/src/store/modules/systemStore/systemStore.ts b/src/store/modules/systemStore/systemStore.ts index 08e10a23..a1e11b15 100644 --- a/src/store/modules/systemStore/systemStore.ts +++ b/src/store/modules/systemStore/systemStore.ts @@ -14,7 +14,8 @@ export const useSystemStore = defineStore({ userInfo: { userId: undefined, userName: undefined, - userToken: undefined + userToken: undefined, + nickName: undefined } }, getters: {}, diff --git a/src/utils/router.ts b/src/utils/router.ts index 6f38959c..3f1d95b0 100644 --- a/src/utils/router.ts +++ b/src/utils/router.ts @@ -1,11 +1,12 @@ import { useRoute } from 'vue-router' -import { ResultEnum } from '@/enums/httpEnum' +import { ResultEnum, RequestHttpHeaderEnum } from '@/enums/httpEnum' import { ErrorPageNameMap, PageEnum } from '@/enums/pageEnum' import { docPath, giteeSourceCodePath } from '@/settings/pathConst' import { SystemStoreEnum, SystemStoreUserInfoEnum } from '@/store/modules/systemStore/systemStore.d' import { StorageEnum } from '@/enums/storageEnum' -import { clearLocalStorage, getLocalStorage } from './storage' +import { clearLocalStorage, getLocalStorage, clearCookie } from './storage' import router from '@/router' +import { logoutApi } from '@/api/path/system.api' /** * * 根据名字跳转路由 @@ -101,9 +102,14 @@ export const reloadRoutePage = () => { } /** - * * 退出 + * * 退出登录 */ -export const logout = () => { +export const logout = async () => { + const res:any = await logoutApi() + if(res.code === ResultEnum.SUCCESS) { + window['$message'].success((`${window.$t('global.logout_success')}!`)) + } + clearCookie(RequestHttpHeaderEnum.COOKIE) clearLocalStorage(StorageEnum.GO_SYSTEM_STORE) routerTurnByName(PageEnum.BASE_LOGIN_NAME) } diff --git a/src/utils/storage.ts b/src/utils/storage.ts index 60e7c7e8..be46d576 100644 --- a/src/utils/storage.ts +++ b/src/utils/storage.ts @@ -5,7 +5,7 @@ * @param v 键值(无需stringiiy) * @returns RemovableRef */ - export const setLocalStorage = (k: string, v: T) => { +export const setLocalStorage = (k: string, v: T) => { try { window.localStorage.setItem(k, JSON.stringify(v)) } catch (error) { @@ -18,7 +18,7 @@ * @param k 键名 * @returns any */ - export const getLocalStorage = (k: string) => { +export const getLocalStorage = (k: string) => { const item = window.localStorage.getItem(k) try { return item ? JSON.parse(item) : item @@ -31,7 +31,7 @@ * * 清除本地会话数据 * @param name */ - export const clearLocalStorage = (name: string) => { +export const clearLocalStorage = (name: string) => { window.localStorage.removeItem(name) } @@ -68,4 +68,42 @@ export const getSessionStorage: (k: string) => any = (k: string) => { */ export const clearSessioStorage = (name: string) => { window.sessionStorage.removeItem(name) +} + +/** + * * 设置 cookie + * @param name 键名 + * @param cvalue 键值 + * @param exdays 过期时间 + */ +export const setCookie = (name: string, cvalue: string, exdays: number) => { + const d = new Date(); + d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000)); + const expires = "expires=" + d.toUTCString(); + document.cookie = name + "=" + cvalue + "; " + expires; +} + +/** + * * 获取 cookie + * @param cname 键名 + * @returns string + */ +export const getCookie = (cname: string) => { + const name = cname + "="; + const ca = document.cookie.split(';'); + for (let i = 0; i < ca.length; i++) { + let c = ca[i]; + while (c.charAt(0) == ' ') c = c.substring(1); + if (c.indexOf(name) != -1) return c.substring(name.length, c.length); + } + return ""; +} + +/** + * * 清除 cookie + * @param name 键名 + * @returns string + */ +export const clearCookie = (name: string) => { + setCookie(name, "", -1); } \ No newline at end of file diff --git a/src/views/login/index.vue b/src/views/login/index.vue index 057a9857..cf1422e1 100644 --- a/src/views/login/index.vue +++ b/src/views/login/index.vue @@ -128,7 +128,7 @@ import { PageEnum } from '@/enums/pageEnum' import { icon } from '@/plugins' import { StorageEnum } from '@/enums/storageEnum' import { routerTurnByName } from '@/utils' -import { loginRequest } from './api/index' +import { loginApi } from '@/api/path/system.api' interface FormState { username: string @@ -213,17 +213,22 @@ const handleSubmit = async (e: Event) => { const { username, password } = formInline loading.value = true // 提交请求 - const res:any = await loginRequest({ + const res:any = await loginApi({ username, password }) if(res.data) { - const { tokenValue, loginId } = res.data + const { tokenValue } = res.data.token + const { nickname, username, id } = res.data.userinfo + + // 存储到 pinia systemStore.setItem(SystemStoreEnum.USER_INFO, { userToken: tokenValue, - userId: loginId, + userId: id, userName: username, + nickName: nickname, }) + window['$message'].success(`${t('login.login_success')}!`) routerTurnByName(PageEnum.BASE_HOME_NAME, true) } diff --git a/src/views/project/items/components/ProjectItemsList/hooks/useData.hook.ts b/src/views/project/items/components/ProjectItemsList/hooks/useData.hook.ts index 1c38b116..aa3b91d9 100644 --- a/src/views/project/items/components/ProjectItemsList/hooks/useData.hook.ts +++ b/src/views/project/items/components/ProjectItemsList/hooks/useData.hook.ts @@ -45,7 +45,7 @@ export const useDataListInit = () => { onPositiveCallback: () => new Promise(res => setTimeout(() => res(1), 1000)), promiseResCallback: (e: any) => { - window.$message.success('删除成功') + window['$message'].success('删除成功') list.value.splice(index, 1) } }) diff --git a/src/views/project/layout/components/ProjectLayoutCreate/components/CreateModal/index.vue b/src/views/project/layout/components/ProjectLayoutCreate/components/CreateModal/index.vue index 2cbae29e..d8cae3ff 100644 --- a/src/views/project/layout/components/ProjectLayoutCreate/components/CreateModal/index.vue +++ b/src/views/project/layout/components/ProjectLayoutCreate/components/CreateModal/index.vue @@ -18,7 +18,7 @@ :disabled="item.disabled" v-for="item in typeList" :key="item.key" - @click="btnHandle" + @click="btnHandle(item.key)" >