From 8e80683427955d52c53f7628f587e37e39e73f91 Mon Sep 17 00:00:00 2001 From: juetan Date: Fri, 3 Nov 2023 22:37:52 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BC=98=E5=8C=96=E8=A1=A8=E6=A0=BCemp?= =?UTF-8?q?ty=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/instance/axios.d.ts | 10 ++- src/api/interceptors/exception.ts | 60 ++++++++++++++--- src/components/empty/index.vue | 106 ++++++++++++++++++++++++++++++ src/components/table/table.tsx | 9 ++- src/components/toast/toast.ts | 2 +- src/components/toast/toast.vue | 2 +- src/types/auto-component.d.ts | 1 + src/utils/index.ts | 6 ++ 8 files changed, 183 insertions(+), 13 deletions(-) create mode 100644 src/components/empty/index.vue diff --git a/src/api/instance/axios.d.ts b/src/api/instance/axios.d.ts index 2c76af7..ced771e 100644 --- a/src/api/instance/axios.d.ts +++ b/src/api/instance/axios.d.ts @@ -1,5 +1,5 @@ -import "axios"; import { IToastOptions } from "@/components"; +import "axios"; declare module "axios" { interface AxiosRequestConfig { @@ -13,5 +13,13 @@ declare module "axios" { * @private */ closeToast?: () => void; + /** + * 响应异常提示 + */ + resErrorTip?: boolean | string; + /** + * 请求异常提示 + */ + reqErrorTip?: boolean | string; } } diff --git a/src/api/interceptors/exception.ts b/src/api/interceptors/exception.ts index edd597a..7d36207 100644 --- a/src/api/interceptors/exception.ts +++ b/src/api/interceptors/exception.ts @@ -1,15 +1,28 @@ import { Notification } from "@arco-design/web-vue"; import { AxiosInstance } from "axios"; +import { has, isString } from "lodash-es"; const successCodes = [2000]; const expiredCodes = [4050, 4051]; -let tipShowing = false; +const resMessageTip = `响应异常,请检查参数或稍后重试!`; +const reqMessageTip = `请求失败,请检查网络或稍后重试!`; + +let logoutTipShowing = false; /** * 异常拦截器 * @param axios Axios实例 */ export function addExceptionInterceptor(axios: AxiosInstance, exipreHandler?: (...args: any[]) => any) { + axios.interceptors.request.use(null, (error) => { + const msg = error.response?.data?.message; + Notification.error({ + title: "请求提示", + content: msg ?? `发送请求失败,请检查参数或稍后重试!`, + }); + return Promise.reject(error); + }); + axios.interceptors.response.use( (res) => { const code = res.data?.code; @@ -23,23 +36,52 @@ export function addExceptionInterceptor(axios: AxiosInstance, exipreHandler?: (. if (error.response) { const code = error.response.data?.code; if (expiredCodes.includes(code)) { - Notification.warning({ - title: "登陆提示", - content: "当前登陆已过期,请重新登陆!", + if (!logoutTipShowing) { + logoutTipShowing = true; + Notification.warning({ + title: "登陆提示", + content: "当前登陆已过期,请重新登陆!", + onClose: () => (logoutTipShowing = false), + }); + exipreHandler?.(error); + } + return Promise.reject(error); + } + const resMsg = error.response?.data?.message; + let message: string | null = resMsg ?? resMessageTip; + if (has(error.config, "resErrorTip")) { + const tip = error.config.resErrorTip; + if (tip) { + message = isString(tip) ? tip : message; + } else { + message = null; + } + } + if (message) { + Notification.error({ + title: "请求提示", + content: message, }); - exipreHandler?.(error); } return Promise.reject(error); } // 客户端请求错误 if (error.request) { - if (!tipShowing) { - tipShowing = true; + const resMsg = error.response?.message; + let message: string | null = resMsg ?? reqMessageTip; + if (has(error.config, "reqErrorTip")) { + const tip = error.config.reqErrorTip; + if (tip) { + message = isString(tip) ? tip : message; + } else { + message = null; + } + } + if (message) { Notification.error({ title: "请求提示", - content: `请求服务器失败,请检查网络或稍后重试!`, - onClose: () => (tipShowing = false), + content: message, }); } return Promise.reject(error); diff --git a/src/components/empty/index.vue b/src/components/empty/index.vue new file mode 100644 index 0000000..41f59c8 --- /dev/null +++ b/src/components/empty/index.vue @@ -0,0 +1,106 @@ + + + diff --git a/src/components/table/table.tsx b/src/components/table/table.tsx index 8a60657..89d8221 100644 --- a/src/components/table/table.tsx +++ b/src/components/table/table.tsx @@ -1,6 +1,7 @@ import { TableColumnData as BaseColumn, TableData as BaseData, Table as BaseTable } from "@arco-design/web-vue"; import { merge } from "lodash-es"; import { PropType, computed, defineComponent, reactive, ref } from "vue"; +import AniEmpty from "../empty/index.vue"; import { Form, FormInstance, FormModal, FormModalInstance, FormModalProps, FormProps } from "../form"; import { config } from "./table.config"; @@ -110,6 +111,8 @@ export const Table = defineComponent({ renderData.value = data; props.pagination.total = total; props.pagination.current = paging.page; + } catch (e) { + // todo } finally { loading.value = false; } @@ -188,7 +191,11 @@ export const Table = defineComponent({ data={this.renderData} columns={this.columns} onPageChange={(current: number) => this.loadData({ current })} - > + > + {{ + empty: () => , + }} + ); }, diff --git a/src/components/toast/toast.ts b/src/components/toast/toast.ts index d144dbd..5791fe5 100644 --- a/src/components/toast/toast.ts +++ b/src/components/toast/toast.ts @@ -19,7 +19,7 @@ export interface IToastOptions { mask?: boolean; /** * 是否覆盖窗口(即不允许其他操作) - * @default false + * @default true */ cover?: boolean; } diff --git a/src/components/toast/toast.vue b/src/components/toast/toast.vue index e134c13..31afe07 100644 --- a/src/components/toast/toast.vue +++ b/src/components/toast/toast.vue @@ -27,7 +27,7 @@ const props = defineProps({ }, mask: { type: Boolean, - default: false, + default: true, }, cover: { type: Boolean, diff --git a/src/types/auto-component.d.ts b/src/types/auto-component.d.ts index 95a4bed..9d5a922 100644 --- a/src/types/auto-component.d.ts +++ b/src/types/auto-component.d.ts @@ -67,6 +67,7 @@ declare module '@vue/runtime-core' { ColorPicker: typeof import('./../components/editor/components/ColorPicker.vue')['default'] DragResizer: typeof import('./../components/editor/components/DragResizer.vue')['default'] Editor: typeof import('./../components/editor/index.vue')['default'] + Empty: typeof import('./../components/empty/index.vue')['default'] Header: typeof import('./../components/editor/panel-main/components/header.vue')['default'] ImagePicker: typeof import('./../components/editor/components/ImagePicker.vue')['default'] InputColor: typeof import('./../components/editor/components/InputColor.vue')['default'] diff --git a/src/utils/index.ts b/src/utils/index.ts index af256b9..c07c186 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,2 +1,8 @@ export * from "./delConfirm"; +/** + * 暂停一段时间 + * @param ms 时长(毫秒) + * @returns + */ +export const sleep = (ms: number) => new Promise(res => setTimeout(res, ms)) \ No newline at end of file