diff --git a/src/components/Designer/src/types/index.ts b/src/components/Designer/src/types/index.ts index 7316cb5..8347cd7 100644 --- a/src/components/Designer/src/types/index.ts +++ b/src/components/Designer/src/types/index.ts @@ -121,6 +121,9 @@ export const basicComponents = [ typeName: t('计数组件'), type: 'number', options: { + labelWidthMode: 'fix', + labelFixWidth: 120, + responsive: false, width: '100%', span: '', defaultValue: 0, @@ -1165,6 +1168,9 @@ export const infoComponents = [ typeName: t('人员选择'), type: 'user', options: { + labelWidthMode: 'fix', + labelFixWidth: 120, + responsive: false, span: '', width: '100%', defaultValue: '', diff --git a/src/components/MultiplePopup/src/MultiplePopup.vue b/src/components/MultiplePopup/src/MultiplePopup.vue index 9e0c695..02dd58d 100644 --- a/src/components/MultiplePopup/src/MultiplePopup.vue +++ b/src/components/MultiplePopup/src/MultiplePopup.vue @@ -1,206 +1,212 @@ diff --git a/src/utils/http/axios/Axios.ts b/src/utils/http/axios/Axios.ts index 7ad65f1..af23e83 100644 --- a/src/utils/http/axios/Axios.ts +++ b/src/utils/http/axios/Axios.ts @@ -310,11 +310,7 @@ export class VAxios { }) .catch((e: Error | AxiosError) => { if (e.message.includes('timeout') || e.message.includes('Network Error')) { - const userStore = useUserStore(); - userStore.setToken(undefined); - userStore.setSessionTimeout(false); - userStore.setUserInfo(null); - router.push(PageEnum.BASE_LOGIN); + // 太极端了,这里没必要给人踢回登录页面 } if (requestCatchHook && isFunction(requestCatchHook)) { reject(requestCatchHook(e, opt)); diff --git a/src/utils/http/axios/index.ts b/src/utils/http/axios/index.ts index 283aa98..62a7ad6 100644 --- a/src/utils/http/axios/index.ts +++ b/src/utils/http/axios/index.ts @@ -20,245 +20,255 @@ import { useUserStoreWithOut } from '/@/store/modules/user'; import { AxiosRetry } from '/@/utils/http/axios/axiosRetry'; import { useGo } from '/@/hooks/web/usePage'; import { validateScript } from '/@/utils/event/design'; +import { notification } from 'ant-design-vue'; +import { throttle } from 'lodash-es'; const globSetting = useGlobSetting(); const urlPrefix = globSetting.urlPrefix; const { createMessage, createErrorModal } = useMessage(); +const showNetworkError = function() { + notification.error({ + message: '网络超时,请检查本地网络是否正常,或者稍后再试', + placement: 'topRight', + duration: 3 + }); +}; + +const trNetworkError = throttle(showNetworkError, 5000, { trailing: false }); + /** * @description: 数据处理,方便区分多种处理方式 */ const transform: AxiosTransform = { - /** - * @description: 处理请求数据。如果数据不是预期格式,可直接抛出错误 - */ - transformRequestHook: (res: AxiosResponse, options: RequestOptions) => { - const { t } = useI18n(); - const { isTransformResponse, isReturnNativeResponse } = options; - // 是否返回原生响应头 比如:需要获取响应头时使用该属性 - if (isReturnNativeResponse) { - return res; - } - // 不进行任何处理,直接返回 - // 用于页面代码可能需要直接获取code,data,message这些信息时开启 - if (!isTransformResponse) { - return res.data; - } - // 错误的时候返回 - - const { data: result } = res; - if (!result) { - // return '[HTTP] Request has no return value'; - throw new Error(t('请求出错,请稍候重试')); - } - // 这里 code,result,message为 后台统一的字段,需要在 types.ts内修改为项目自己的接口返回格式 - const { code, data, msg } = result; - - // 这里逻辑可以根据项目进行修改 - const hasSuccess = code === ResultEnum.SUCCESS; - if (hasSuccess) { - return data; - } - - // 在此处根据自己项目的实际情况对不同的code执行不同的操作 - // 如果不希望中断当前请求,请return数据,否则直接抛出异常即可 - let timeoutMsg = ''; - switch (code) { - case ResultEnum.UNAUTHRAZATION: - timeoutMsg = t('登录超时,请重新登录!'); - const userStore = useUserStoreWithOut(); - userStore.setToken(undefined); - userStore.logout(true); - const go = useGo(); - go('/login'); - break; - default: - if (msg) { - timeoutMsg = msg; + /** + * @description: 处理请求数据。如果数据不是预期格式,可直接抛出错误 + */ + transformRequestHook: (res: AxiosResponse, options: RequestOptions) => { + const { t } = useI18n(); + const { isTransformResponse, isReturnNativeResponse } = options; + // 是否返回原生响应头 比如:需要获取响应头时使用该属性 + if (isReturnNativeResponse) { + return res; } - } - - // errorMessageMode=‘modal’的时候会显示modal错误弹窗,而不是消息提示,用于一些比较重要的错误 - // errorMessageMode='none' 一般是调用时明确表示不希望自动弹出错误提示 - if (options.errorMessageMode === 'modal') { - createErrorModal({ title: t('错误提示'), content: timeoutMsg }); - } else if (options.errorMessageMode === 'message') { - createMessage.error(timeoutMsg); - } - - throw new Error(timeoutMsg || t('请求出错,请稍候重试')); - }, - - // 请求之前处理config - beforeRequestHook: (config, options) => { - const { apiUrl, joinPrefix, joinParamsToUrl, formatDate, joinTime = true, urlPrefix } = options; - - if (joinPrefix) { - config.url = `${urlPrefix}${config.url}`; - } - - if (apiUrl && isString(apiUrl)) { - config.url = `${apiUrl}${config.url}`; - } - const params = config.params || {}; - const data = config.data || false; - formatDate && data && !isString(data) && formatRequestDate(data); - if (config.method?.toUpperCase() === RequestEnum.GET) { - if (!isString(params)) { - // 给 get 请求加上时间戳参数,避免从缓存中拿数据。 - config.params = Object.assign(params || {}, joinTimestamp(joinTime, false)); - } else { - validateScript(params); - // 兼容restful风格 - config.url = config.url + params + `${joinTimestamp(joinTime, true)}`; - config.params = undefined; - } - } else { - if (!isString(params)) { - formatDate && formatRequestDate(params); - if (Reflect.has(config, 'data') && config.data && Object.keys(config.data).length > 0) { - config.data = data; - config.params = params; - } else { - // 非GET请求如果没有提供data,则将params视为data - config.data = params; - config.params = undefined; + // 不进行任何处理,直接返回 + // 用于页面代码可能需要直接获取code,data,message这些信息时开启 + if (!isTransformResponse) { + return res.data; } - if (isBoolean(joinParamsToUrl) && joinParamsToUrl) { - config.url = setObjToUrlParams( - config.url as string, - Object.assign({}, config.params, config.data), - ); - } - } else { - // 兼容restful风格 - config.url = config.url + params; - config.params = undefined; - } - } - return config; - }, + // 错误的时候返回 + + const { data: result } = res; + if (!result) { + // return '[HTTP] Request has no return value'; + throw new Error(t('请求出错,请稍候重试')); + } + // 这里 code,result,message为 后台统一的字段,需要在 types.ts内修改为项目自己的接口返回格式 + const { code, data, msg } = result; + + // 这里逻辑可以根据项目进行修改 + const hasSuccess = code === ResultEnum.SUCCESS; + if (hasSuccess) { + return data; + } + + // 在此处根据自己项目的实际情况对不同的code执行不同的操作 + // 如果不希望中断当前请求,请return数据,否则直接抛出异常即可 + let timeoutMsg = ''; + switch (code) { + case ResultEnum.UNAUTHRAZATION: + timeoutMsg = t('登录超时,请重新登录!'); + const userStore = useUserStoreWithOut(); + userStore.setToken(undefined); + userStore.logout(true); + const go = useGo(); + go('/login'); + break; + default: + if (msg) { + timeoutMsg = msg; + } + } + + // errorMessageMode=‘modal’的时候会显示modal错误弹窗,而不是消息提示,用于一些比较重要的错误 + // errorMessageMode='none' 一般是调用时明确表示不希望自动弹出错误提示 + if (options.errorMessageMode === 'modal') { + createErrorModal({ title: t('错误提示'), content: timeoutMsg }); + } else if (options.errorMessageMode === 'message') { + createMessage.error(timeoutMsg); + } + + throw new Error(timeoutMsg || t('请求出错,请稍候重试')); + }, - /** - * @description: 请求拦截器处理 - */ - requestInterceptors: (config, options) => { // 请求之前处理config - const token = getToken(); - if (token && (config as Recordable)?.requestOptions?.withToken !== false) { - // jwt token - (config as Recordable).headers.Authorization = options.authenticationScheme - ? `${options.authenticationScheme} ${token}` - : token; - } - return config; - }, + beforeRequestHook: (config, options) => { + const { apiUrl, joinPrefix, joinParamsToUrl, formatDate, joinTime = true, urlPrefix } = options; - /** - * @description: 响应拦截器处理 - */ - responseInterceptors: (res: AxiosResponse) => { - return res; - }, - - /** - * @description: 响应错误处理 - */ - responseInterceptorsCatch: (axiosInstance: AxiosResponse, error: any) => { - const { t } = useI18n(); - const errorLogStore = useErrorLogStoreWithOut(); - errorLogStore.addAjaxErrorInfo(error); - const { response, code, message, config } = error || {}; - const errorMessageMode = config?.requestOptions?.errorMessageMode || 'none'; - const msg: string = response?.data?.error?.message ?? ''; - const err: string = error?.toString?.() ?? ''; - let errMessage = ''; - - try { - if (code === 'ECONNABORTED' && message.indexOf('timeout') !== -1) { - errMessage = t('接口请求超时,请刷新页面重试!'); - } - if (err?.includes('Network Error')) { - errMessage = t('网络异常,请检查您的网络连接是否正常!'); - } - - if (errMessage) { - if (errorMessageMode === 'modal') { - createErrorModal({ title: t('错误提示'), content: errMessage }); - } else if (errorMessageMode === 'message') { - createMessage.error(errMessage); + if (joinPrefix) { + config.url = `${urlPrefix}${config.url}`; } + + if (apiUrl && isString(apiUrl)) { + config.url = `${apiUrl}${config.url}`; + } + const params = config.params || {}; + const data = config.data || false; + formatDate && data && !isString(data) && formatRequestDate(data); + if (config.method?.toUpperCase() === RequestEnum.GET) { + if (!isString(params)) { + // 给 get 请求加上时间戳参数,避免从缓存中拿数据。 + config.params = Object.assign(params || {}, joinTimestamp(joinTime, false)); + } else { + validateScript(params); + // 兼容restful风格 + config.url = config.url + params + `${joinTimestamp(joinTime, true)}`; + config.params = undefined; + } + } else { + if (!isString(params)) { + formatDate && formatRequestDate(params); + if (Reflect.has(config, 'data') && config.data && Object.keys(config.data).length > 0) { + config.data = data; + config.params = params; + } else { + // 非GET请求如果没有提供data,则将params视为data + config.data = params; + config.params = undefined; + } + if (isBoolean(joinParamsToUrl) && joinParamsToUrl) { + config.url = setObjToUrlParams( + config.url as string, + Object.assign({}, config.params, config.data) + ); + } + } else { + // 兼容restful风格 + config.url = config.url + params; + config.params = undefined; + } + } + return config; + }, + + /** + * @description: 请求拦截器处理 + */ + requestInterceptors: (config, options) => { + // 请求之前处理config + const token = getToken(); + if (token && (config as Recordable)?.requestOptions?.withToken !== false) { + // jwt token + (config as Recordable).headers.Authorization = options.authenticationScheme + ? `${options.authenticationScheme} ${token}` + : token; + } + return config; + }, + + /** + * @description: 响应拦截器处理 + */ + responseInterceptors: (res: AxiosResponse) => { + return res; + }, + + /** + * @description: 响应错误处理 + */ + responseInterceptorsCatch: (axiosInstance: AxiosResponse, error: any) => { + const { t } = useI18n(); + const errorLogStore = useErrorLogStoreWithOut(); + errorLogStore.addAjaxErrorInfo(error); + const { response, code, message, config } = error || {}; + const errorMessageMode = config?.requestOptions?.errorMessageMode || 'none'; + const msg: string = response?.data?.error?.message ?? ''; + const err: string = error?.toString?.() ?? ''; + let errMessage = ''; + + try { + if (code === 'ECONNABORTED' && message.indexOf('timeout') !== -1) { + trNetworkError(); + } else if (err?.includes('Network Error')) { + trNetworkError(); + } else if (errMessage) { + if (errorMessageMode === 'modal') { + createErrorModal({ title: t('错误提示'), content: errMessage }); + } else if (errorMessageMode === 'message') { + createMessage.error(errMessage); + } + return Promise.reject(error); + } + } catch (error) { + throw new Error(error as unknown as string); + } + + checkStatus(error?.response?.status, msg, errorMessageMode); + + // 添加自动重试机制 保险起见 只针对GET请求 + const retryRequest = new AxiosRetry(); + const { isOpenRetry } = config.requestOptions?.retryRequest; + config.method?.toUpperCase() === RequestEnum.GET && + isOpenRetry && + // @ts-ignore + retryRequest.retry(axiosInstance, error); return Promise.reject(error); - } - } catch (error) { - throw new Error(error as unknown as string); } - - checkStatus(error?.response?.status, msg, errorMessageMode); - - // 添加自动重试机制 保险起见 只针对GET请求 - const retryRequest = new AxiosRetry(); - const { isOpenRetry } = config.requestOptions?.retryRequest; - config.method?.toUpperCase() === RequestEnum.GET && - isOpenRetry && - // @ts-ignore - retryRequest.retry(axiosInstance, error); - return Promise.reject(error); - }, }; function createAxios(opt?: Partial) { - return new VAxios( - deepMerge( - { - // See https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication#authentication_schemes - // authentication schemes,e.g: Bearer - // authenticationScheme: 'Bearer', - authenticationScheme: 'Bearer', - timeout: 10 * 1000, - // 基础接口地址 - // baseURL: globSetting.apiUrl, + return new VAxios( + deepMerge( + { + // See https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication#authentication_schemes + // authentication schemes,e.g: Bearer + // authenticationScheme: 'Bearer', + authenticationScheme: 'Bearer', + timeout: 10 * 1000, + // 基础接口地址 + // baseURL: globSetting.apiUrl, - headers: { 'Content-Type': ContentTypeEnum.JSON }, - // 如果是form-data格式 - // headers: { 'Content-Type': ContentTypeEnum.FORM_URLENCODED }, - // 数据处理方式 - transform: clone(transform), - // 配置项,下面的选项都可以在独立的接口请求中覆盖 - requestOptions: { - // 默认将prefix 添加到url - joinPrefix: true, - // 是否返回原生响应头 比如:需要获取响应头时使用该属性 - isReturnNativeResponse: false, - // 需要对返回数据进行处理 - isTransformResponse: true, - // post请求的时候添加参数到url - joinParamsToUrl: false, - // 格式化提交参数时间 - formatDate: true, - // 消息提示类型 - errorMessageMode: 'message', - // 接口地址 - apiUrl: globSetting.apiUrl, - // 接口拼接地址 - urlPrefix: urlPrefix, - // 是否加入时间戳 - joinTime: true, - // 忽略重复请求 - ignoreCancelToken: true, - // 是否携带token - withToken: true, - retryRequest: { - isOpenRetry: false, - count: 5, - waitTime: 100, - }, - }, - }, - opt || {}, - ), - ); + headers: { 'Content-Type': ContentTypeEnum.JSON }, + // 如果是form-data格式 + // headers: { 'Content-Type': ContentTypeEnum.FORM_URLENCODED }, + // 数据处理方式 + transform: clone(transform), + // 配置项,下面的选项都可以在独立的接口请求中覆盖 + requestOptions: { + // 默认将prefix 添加到url + joinPrefix: true, + // 是否返回原生响应头 比如:需要获取响应头时使用该属性 + isReturnNativeResponse: false, + // 需要对返回数据进行处理 + isTransformResponse: true, + // post请求的时候添加参数到url + joinParamsToUrl: false, + // 格式化提交参数时间 + formatDate: true, + // 消息提示类型 + errorMessageMode: 'message', + // 接口地址 + apiUrl: globSetting.apiUrl, + // 接口拼接地址 + urlPrefix: urlPrefix, + // 是否加入时间戳 + joinTime: true, + // 忽略重复请求 + ignoreCancelToken: true, + // 是否携带token + withToken: true, + retryRequest: { + isOpenRetry: false, + count: 5, + waitTime: 100 + } + } + }, + opt || {} + ) + ); } + export const defHttp = createAxios(); // other api url