/*
* @Author: code4eat awesomedema@gmail.com
* @Date: 2022-12-14 14:14:32
* @LastEditors: code4eat awesomedema@gmail.com
* @LastEditTime: 2023-03-29 16:03:35
* @FilePath: /BudgetManaSystem/src/app.ts
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
// 运行时配置
// 全局初始化数据配置,用于 Layout 用户信息和权限初始化
// 更多信息见文档:https://next.umijs.org/docs/api/runtime-config#getinitialstate
import { AxiosResponse } from '@umijs/max';
import { message, notification } from 'antd';
import type { RequestConfig } from 'umi';
import iconEnum from './menuIcons.js';
import DevicePixelRatio from './utils/devicePixelRatio.js';
import Icon, { createFromIconfontCN } from '@ant-design/icons';
const IconFont = createFromIconfontCN({
scriptUrl: '//at.alicdn.com/t/c/font_3878861_tw9yqguouab.js',
});
// 错误处理方案: 错误类型
enum ErrorShowType {
SILENT = 0,
WARN_MESSAGE = 1,
ERROR_MESSAGE = 2,
NOTIFICATION = 3,
REDIRECT = 9,
}
// 与后端约定的响应数据格式
interface ResponseStructure {
success?: boolean;
code?: string;
data: any;
errorCode?: number;
errorMessage?: string;
showType?: ErrorShowType;
}
export async function getInitialState(): Promise<{ name?: string, isCollapsed: boolean }> {
new DevicePixelRatio().init();
return { isCollapsed: false };
}
export const request: RequestConfig = {
// 统一的请求设定
timeout: 100000000,
headers: { 'X-Requested-With': 'XMLHttpRequest' },
// 错误处理: umi@3 的错误处理方案。
errorConfig: {
// 错误抛出
errorThrower: (res: ResponseStructure) => {
const { success, data, errorCode, errorMessage, showType } = res;
//console.log({success, data, errorCode, errorMessage, showType});
if (!success) {
const error: any = new Error(errorMessage);
error.name = 'BizError';
error.info = { errorCode, errorMessage, showType, data };
throw error; // 抛出自制的错误
}
},
// 错误接收及处理
errorHandler: (error: any, opts: any) => {
if (opts?.skipErrorHandler) throw error;
// 我们的 errorThrower 抛出的错误。
if (error.name === 'BizError') {
const errorInfo: ResponseStructure | undefined = error.info;
if (errorInfo) {
const { errorMessage, errorCode } = errorInfo;
switch (errorInfo.showType) {
case ErrorShowType.SILENT:
// do nothing
break;
case ErrorShowType.WARN_MESSAGE:
message.warning(errorMessage);
break;
case ErrorShowType.ERROR_MESSAGE:
message.error(errorMessage);
break;
case ErrorShowType.NOTIFICATION:
notification.open({
description: errorMessage,
message: errorCode,
});
break;
case ErrorShowType.REDIRECT:
// TODO: redirect
break;
default:
message.error(errorMessage);
}
}
} else if (error.response) {
// Axios 的错误
// 请求成功发出且服务器也响应了状态码,但状态代码超出了 2xx 的范围
message.error(`Response status:${error.response.status}`);
} else if (error.request) {
// 请求已经成功发起,但没有收到响应
// \`error.request\` 在浏览器中是 XMLHttpRequest 的实例,
// 而在node.js中是 http.ClientRequest 的实例
message.error('None response! Please retry.');
} else {
// 发送请求时出了点问题
message.error('Request error, please retry.');
}
},
},
// 请求拦截器
requestInterceptors: [
(config: RequestConfig) => {
// 拦截请求配置,进行个性化处理。
const userData = localStorage.getItem('userData');
const { token = '' } = JSON.parse(userData as any);
return { ...config, url: `/gateway${config.url}`, headers: { token } }
// return { ...config }
}
],
// 响应拦截器
responseInterceptors: [
(response: AxiosResponse) => {
// 拦截响应数据,进行个性化处理
const { status, data: { success, status: code, errorMessage, data: respData }, config: { method } } = response;
try {
if (status == 200) {
// 网络请求成功
if (method == 'post') {
if (code == 200) {
return response.data.data == null ? {
success: true,
data: true
} : response.data
} else {
notification.error({
message: '',
description: errorMessage,
placement: 'topRight',
icon: <>>
})
return false
}
} else {
if (status != 200) {
message.error('请求失败!');
return false
} else {
if (code == 200) {
return response.data
} else {
notification.error({
message: '',
description: errorMessage,
placement: 'topRight',
icon: <>>
})
return false;
}
}
}
} else {
return false
}
} catch (error) {
console.log({ error });
}
}
]
};
export type menuDataItemType = {
path: string,
name: string,
icon: any,
component?: string,
softUrl?: string, // 帆软url
children?: menuDataItemType[]
}
// 将服务端获取的菜单 icon 字符串映射为对应的 icon Dom
const mappingIcon = (menuData: menuDataItemType[]) => {
if (menuData.length == 0) {
return [
{
path: '',
name: '',
icon: '',
component: './404',
}
]
}
const mappingMenu: menuDataItemType[] = menuData.map(item => ({
...item,
icon: item.icon && iconEnum[item.icon],
children: item.children ? mappingIcon(item.children) : [],
}));
return mappingMenu;
};
const imgNode = (props: any) => {
return