diff --git a/mock/api/auth.ts b/mock/api/auth.ts index ce769db2..c2481c9c 100644 --- a/mock/api/auth.ts +++ b/mock/api/auth.ts @@ -10,7 +10,7 @@ const apis: MockMethod[] = [ { url: '/mock/getSmsCode', method: 'post', - response: (): Service.BackendServiceResult => { + response: (): Service.MockServiceResult => { return { code: 200, message: 'ok', @@ -22,7 +22,7 @@ const apis: MockMethod[] = [ { url: '/mock/loginByPwd', method: 'post', - response: (): Service.BackendServiceResult => { + response: (): Service.MockServiceResult => { return { code: 200, message: 'ok', @@ -34,7 +34,7 @@ const apis: MockMethod[] = [ { url: '/mock/loginByCode', method: 'post', - response: (): Service.BackendServiceResult => { + response: (): Service.MockServiceResult => { return { code: 200, message: 'ok', @@ -46,7 +46,7 @@ const apis: MockMethod[] = [ { url: '/mock/getUserInfo', method: 'get', - response: (): Service.BackendServiceResult => { + response: (): Service.MockServiceResult => { return { code: 200, message: 'ok', @@ -62,7 +62,7 @@ const apis: MockMethod[] = [ { url: '/mock/testToken', method: 'post', - response: (option: any): Service.BackendServiceResult => { + response: (option: any): Service.MockServiceResult => { if (option.headers?.authorization !== token.token) { return { code: 66666, @@ -80,7 +80,7 @@ const apis: MockMethod[] = [ { url: '/mock/updateToken', method: 'post', - response: (): Service.BackendServiceResult => { + response: (): Service.MockServiceResult => { return { code: 200, message: 'ok', diff --git a/mock/api/route.ts b/mock/api/route.ts index 925653f6..febeac8f 100644 --- a/mock/api/route.ts +++ b/mock/api/route.ts @@ -210,7 +210,7 @@ const apis: MockMethod[] = [ { url: '/mock/getUserRoutes', method: 'post', - response: (): Service.BackendServiceResult => { + response: (): Service.MockServiceResult => { return { code: 200, message: 'ok', diff --git a/src/composables/events/index.ts b/src/composables/events/index.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/src/composables/events/index.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/config/business/index.ts b/src/config/business/index.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/src/config/business/index.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/directives/index.ts b/src/directives/index.ts new file mode 100644 index 00000000..37e897fe --- /dev/null +++ b/src/directives/index.ts @@ -0,0 +1,8 @@ +import type { App } from 'vue'; +import setupNetworkDirective from './network'; +import setupLoginDirective from './login'; + +export function setupDirectives(app: App) { + setupNetworkDirective(app); + setupLoginDirective(app); +} diff --git a/src/directives/login.ts b/src/directives/login.ts new file mode 100644 index 00000000..450d78f9 --- /dev/null +++ b/src/directives/login.ts @@ -0,0 +1,27 @@ +import type { App, Directive } from 'vue'; +import { useAuthStore } from '@/store'; +import { useRouterPush } from '@/composables'; + +export default function setupLoginDirective(app: App) { + const auth = useAuthStore(); + const { toLogin } = useRouterPush(false); + function listenerHandler(event: MouseEvent) { + if (!auth.isLogin) { + event.stopPropagation(); + toLogin(); + } + } + + const loginDirective: Directive = { + mounted(el: HTMLElement, binding) { + if (binding.value === false) return; + el.addEventListener('click', listenerHandler, { capture: true }); + }, + unmounted(el: HTMLElement, binding) { + if (binding.value === false) return; + el.removeEventListener('click', listenerHandler); + } + }; + + app.directive('login', loginDirective); +} diff --git a/src/directives/network.ts b/src/directives/network.ts new file mode 100644 index 00000000..229b092f --- /dev/null +++ b/src/directives/network.ts @@ -0,0 +1,25 @@ +import type { App, Directive } from 'vue'; +import { NETWORK_ERROR_MSG } from '@/config'; + +export default function setupNetworkDirective(app: App) { + function listenerHandler(event: MouseEvent) { + const hasNetwork = window.navigator.onLine; + if (!hasNetwork) { + window.$message?.error(NETWORK_ERROR_MSG); + event.stopPropagation(); + } + } + + const networkDirective: Directive = { + mounted(el: HTMLElement, binding) { + if (binding.value === false) return; + el.addEventListener('click', listenerHandler, { capture: true }); + }, + unmounted(el: HTMLElement, binding) { + if (binding.value === false) return; + el.removeEventListener('click', listenerHandler); + } + }; + + app.directive('network', networkDirective); +} diff --git a/src/enum/business/index.ts b/src/enum/business/index.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/src/enum/business/index.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/main.ts b/src/main.ts index bc02edf1..70c5a672 100644 --- a/src/main.ts +++ b/src/main.ts @@ -2,6 +2,7 @@ import { createApp } from 'vue'; import { setupAssets } from '@/plugins'; import { setupRouter } from '@/router'; import { setupStore } from '@/store'; +import { setupDirectives } from '@/directives'; import App from './App.vue'; async function setupApp() { @@ -13,6 +14,9 @@ async function setupApp() { // 挂载pinia状态 setupStore(app); + // 挂载自定义vue指令 + setupDirectives(app); + // 挂载路由 await setupRouter(app); diff --git a/src/plugins/index.ts b/src/plugins/index.ts index fddc1b12..4de580b2 100644 --- a/src/plugins/index.ts +++ b/src/plugins/index.ts @@ -1,4 +1,3 @@ import setupAssets from './assets'; -import setupInitSvgLogo from './logo'; -export { setupAssets, setupInitSvgLogo }; +export { setupAssets }; diff --git a/src/plugins/logo.ts b/src/plugins/logo.ts deleted file mode 100644 index 6d982d66..00000000 --- a/src/plugins/logo.ts +++ /dev/null @@ -1,28 +0,0 @@ -/** 初始化加载效果的svg格式logo */ -export default function setupInitSvgLogo(id: string) { - const svgStr = ` - - - - - - -`; - const appEl = document.querySelector(id); - const div = document.createElement('div'); - div.innerHTML = svgStr; - appEl?.appendChild(div); -} diff --git a/src/service/request/instance.ts b/src/service/request/instance.ts index f41b14fb..6afed14c 100644 --- a/src/service/request/instance.ts +++ b/src/service/request/instance.ts @@ -1,5 +1,5 @@ import axios from 'axios'; -import type { AxiosRequestConfig, AxiosInstance, AxiosError, CancelTokenStatic } from 'axios'; +import type { AxiosRequestConfig, AxiosInstance, AxiosError } from 'axios'; import { REQUEST_TIMEOUT, REFRESH_TOKEN_CODE } from '@/config'; import { getToken, @@ -18,17 +18,28 @@ import { refreshToken } from './helpers'; export default class CustomAxiosInstance { instance: AxiosInstance; - private backendSuccessCode = 200; + backendConfig: Service.BackendResultConfig; - cancelToken: CancelTokenStatic; - - constructor(axiosConfig: AxiosRequestConfig) { + /** + * + * @param axiosConfig - axios配置 + * @param backendSuccessCode - 后端业务上定义的成功请求的状态码 + */ + constructor( + axiosConfig: AxiosRequestConfig, + backendConfig: Service.BackendResultConfig = { + codeKey: 'code', + dataKey: 'data', + msgKey: 'message', + successCode: 200 + } + ) { + this.backendConfig = backendConfig; const defaultConfig: AxiosRequestConfig = { timeout: REQUEST_TIMEOUT }; Object.assign(defaultConfig, axiosConfig); this.instance = axios.create(defaultConfig); - this.cancelToken = axios.CancelToken; this.setInterceptor(); } @@ -55,21 +66,22 @@ export default class CustomAxiosInstance { async response => { const { status } = response; if (status === 200 || status < 300 || status === 304) { - const backend = response.data as Service.BackendServiceResult; + const backend = response.data; + const { codeKey, dataKey, successCode } = this.backendConfig; // 请求成功 - if (backend.code === this.backendSuccessCode) { - return handleServiceResult(null, backend.data); + if (backend[codeKey] === successCode) { + return handleServiceResult(null, backend[dataKey]); } // token失效, 刷新token - if (REFRESH_TOKEN_CODE.includes(backend.code)) { + if (REFRESH_TOKEN_CODE.includes(backend[codeKey])) { const config = await refreshToken(response.config); if (config) { return this.instance.request(config); } } - const error = handleBackendError(backend); + const error = handleBackendError(backend, this.backendConfig); return handleServiceResult(error, null); } const error = handleResponseError(response); diff --git a/src/service/request/request.ts b/src/service/request/request.ts index 9c9eb391..aa66dd6c 100644 --- a/src/service/request/request.ts +++ b/src/service/request/request.ts @@ -16,9 +16,10 @@ interface RequestParam { /** * 创建请求 * @param axiosConfig - axios配置 + * @param backendConfig - 后端接口字段配置 */ -export function createRequest(axiosConfig: AxiosRequestConfig) { - const customInstance = new CustomAxiosInstance(axiosConfig); +export function createRequest(axiosConfig: AxiosRequestConfig, backendConfig?: Service.BackendResultConfig) { + const customInstance = new CustomAxiosInstance(axiosConfig, backendConfig); /** * 异步promise请求 @@ -98,9 +99,10 @@ type RequestResultHook = { /** * 创建hooks请求 * @param axiosConfig - axios配置 + * @param backendConfig - 后端接口字段配置 */ -export function createHookRequest(axiosConfig: AxiosRequestConfig) { - const customInstance = new CustomAxiosInstance(axiosConfig); +export function createHookRequest(axiosConfig: AxiosRequestConfig, backendConfig?: Service.BackendResultConfig) { + const customInstance = new CustomAxiosInstance(axiosConfig, backendConfig); /** * hooks请求 diff --git a/src/typings/common/service.d.ts b/src/typings/common/service.d.ts index 1844558e..71415650 100644 --- a/src/typings/common/service.d.ts +++ b/src/typings/common/service.d.ts @@ -23,14 +23,16 @@ declare namespace Service { msg: string; } - /** 后端接口返回的数据的类型 */ - interface BackendServiceResult { - /** 状态码 */ - code: string | number; - /** 接口数据 */ - data: T; - /** 接口消息 */ - message: string; + /** 后端接口返回的数据结构配置 */ + interface BackendResultConfig { + /** 表示后端请求状态码的属性字段 */ + codeKey: string; + /** 表示后端请求数据的属性字段 */ + dataKey: string; + /** 表示后端消息的属性字段 */ + msgKey: string; + /** 后端业务上定义的成功请求的状态 */ + successCode: number | string; } /** 自定义的请求成功结果 */ @@ -51,4 +53,14 @@ declare namespace Service { /** 自定义的请求结果 */ type RequestResult = SuccessResult | FailedResult; + + /** mock示例接口类型:后端接口返回的数据的类型 */ + interface MockServiceResult { + /** 状态码 */ + code: string | number; + /** 接口数据 */ + data: T; + /** 接口消息 */ + message: string; + } } diff --git a/src/utils/service/error.ts b/src/utils/service/error.ts index edf3a4ac..3f1e3c2a 100644 --- a/src/utils/service/error.ts +++ b/src/utils/service/error.ts @@ -87,11 +87,12 @@ export function handleResponseError(response: AxiosResponse) { * 处理后端返回的错误(业务错误) * @param backendResult - 后端接口的响应数据 */ -export function handleBackendError(backendResult: Service.BackendServiceResult) { +export function handleBackendError(backendResult: Record, config: Service.BackendResultConfig) { + const { codeKey, msgKey } = config; const error: Service.RequestError = { type: 'backend', - code: backendResult.code, - msg: backendResult.message + code: backendResult[codeKey], + msg: backendResult[msgKey] }; showErrorMsg(error);