// 运行时配置 // 全局初始化数据配置,用于 Layout 用户信息和权限初始化 // 更多信息见文档:https://umijs.org/docs/api/runtime-config#getinitialstate import { VersionChecker } from '@/components'; import Avatar from '@/layout/guide/Avatar'; import { auth } from '@/services'; import { Navigate } from '@@/exports'; import { RunTimeLayoutConfig } from '@@/plugin-layout/types'; import { RequestConfig } from '@@/plugin-request/request'; import { InfoCircleFilled } from '@ant-design/icons'; import { LeftMenu } from '@chageable/components'; import '@nutui/nutui-react/dist/style.scss'; import { history } from '@umijs/max'; import { Alert, Button, message, notification, Spin } from 'antd'; import React from 'react'; import './global.less'; interface InitialStateProps { currentUser?: AuthAPI.UserVO; currentAdmin?: AuthAPI.AdminVO; platformId: string; channel?: AuthAPI.ChannelVO; tip: any; } // 动态导入组件 function dynamicImport(componentPath: string) { const Component = React.lazy(() => { // 处理不同的组件路径格式 const path = componentPath.startsWith('@/') ? componentPath.replace('@/', '') : componentPath; return new Promise((resolve) => { import(`@/pages/${path}`) .then((module) => resolve(module)) .catch((reason) => { console.log('组件加载异常', reason); resolve(import(`@/pages/404` as string)); }); // 处理查找兜底,需要对应路径下有404兜底组件 }); }); return ( }> ); } // 路由转换函数 function transformTreeRoutes(serverRoutes: any[], parentId = ''): any[] { return serverRoutes.map((route) => { const umiRoute: any = { id: route.menuId, path: route.path, parentId, name: route.name, icon: route.icon, access: route.access, hideInMenu: route.hideInMenu, }; // 处理组件 if (route.component) { try { umiRoute.element = dynamicImport(route.component); } catch (e) { console.log('组件加载异常', e); umiRoute.element = dynamicImport('@page/404'); } } // 处理子路由 if (route.routes?.length) { umiRoute.children = transformTreeRoutes( route.routes, route.menuId, ).filter((r) => !(r?.path === ' ') && r.hideInMenu === false); if (umiRoute.children[0]?.path) { umiRoute.children.unshift({ path: route.path, element: , }); } } return umiRoute; }); } // 动态路由缓存(改为函数内部变量) let cachedRoutes: any[] = []; let cachedMenus: any[] = []; export async function patchClientRoutes({ routes }: { routes: any[] }) { try { // 转换路由结构 const root = routes.find((r) => r.path === '/'); root.children.push(...cachedRoutes); root.children.unshift({ path: '/', element: , }); } catch (error) { console.error('Failed to load dynamic routes:', error); history.push('/404'); } } // 拦截路由渲染,比如做一些权限校验 export const render = async (oldRender: () => void) => { // 如果已有缓存,直接使用 if (cachedRoutes.length > 0) { oldRender(); return; } const { data: employeeVO } = await auth.user.userEmployee({ employeeShowQry: {}, }); let platformId = '1769220738064285698'; let roleIdList: string[] = []; if (employeeVO) { window.localStorage.setItem('employee', JSON.stringify(employeeVO)); const userRoleVOList = employeeVO.userRoleList?.filter( (item) => item.platformId === platformId, ); if (!userRoleVOList?.length) { message.error('请先绑定角色'); window.localStorage.removeItem('employee'); window.localStorage.removeItem('admin'); window.localStorage.removeItem('roleSlug'); // 未登录,跳转到登录页面 window.location.href = process.env.UMI_APP_SSO_LOGIN_URL + encodeURIComponent(process.env.UMI_APP_OPERATION_URL || ''); return; } window.localStorage.setItem( 'userRoleVOList', JSON.stringify(userRoleVOList), ); // 根据 localStorage 判断有没有选择角色,如果没有选择则默认选择第一个 if (!window.localStorage.getItem('roleSlug')) { window.localStorage.setItem('roleSlug', userRoleVOList?.[0]?.slug); roleIdList = [userRoleVOList?.[0]?.roleId]; } else { const roleSlug = window.localStorage.getItem('roleSlug'); const role = userRoleVOList?.find((item) => item.slug === roleSlug); if (!role) { message.error('请先绑定角色'); window.localStorage.removeItem('employee'); window.localStorage.removeItem('admin'); window.localStorage.removeItem('roleSlug'); // 未登录,跳转到登录页面 window.location.href = process.env.UMI_APP_SSO_LOGIN_URL + encodeURIComponent(process.env.UMI_APP_OPERATION_URL || ''); return; } roleIdList = [role?.roleId]; } } else { const { data: adminVO } = await auth.user.userAdmin({ adminShowQry: {}, }); window.localStorage.setItem('admin', JSON.stringify(adminVO)); window.localStorage.setItem( 'userRoleVOList', JSON.stringify([]), ); window.localStorage.setItem('roleSlug', 'operation'); } // 获取服务端路由配置 await auth.user .userMenu({ roleMenuTreeQry: { platformId: platformId, roleId: roleIdList, }, }) .then(({ data: serverRoutes }) => { cachedMenus = serverRoutes as any[]; cachedRoutes = transformTreeRoutes( serverRoutes || [], 'ant-design-pro-layout', ); oldRender(); }); }; export async function getInitialState(): Promise { let current: any; const { data: channel } = await auth.channel.selectChannelByDomain({ domain: 'operation.erp.qilincloud168.com', }); // 根据 localStorage 获取当前用户信息 admin 和 employee const adminVO = JSON.parse(window.localStorage.getItem('admin') || '{}'); const employeeVO = JSON.parse( window.localStorage.getItem('employee') || '{}', ); current = { channel, platformId: '1769220738064285698', currentUser: { ...employeeVO, ...adminVO, }, }; return current; } export const layout: RunTimeLayoutConfig = ({ initialState }) => { const link = document.querySelector("link[rel*='icon']") || document.createElement('link'); //@ts-ignore link.type = 'image/x-icon'; //@ts-ignore link.rel = 'shortcut icon'; //@ts-ignore link.href = initialState?.channel?.logo; document.getElementsByTagName('head')[0].appendChild(link); return { title: initialState?.channel?.title, subTitle: initialState?.channel?.subTitle, logo: initialState?.channel?.logo, menuRender: (props, defaultDom) => { if (props.isMobile) { return defaultDom; } const menuData = props.menuData; if (!menuData) { return defaultDom; } return ( { history.push(item.key as string); }} /> ); }, menu: { type: 'group', locale: false, request: async () => cachedMenus, }, fixedHeader: true, // links: false, layout: 'mix', navTheme: 'light', // splitMenus: true, contentWidth: 'Fluid', siderWidth: 134, // siderMenuType: 'inline', hasPageContainer: 1, token: { header: { heightLayoutHeader: initialState?.tip?.show ? 108 : 56, }, }, avatarProps: { src: initialState?.currentUser?.avatar, size: 'small', title: initialState?.currentUser?.name, render: (props, dom) => { return {dom}; }, }, onPageChange: () => { // if (!initialState?.currentUser) { // // 未登录,跳转到登录页面 // window.location.href = // process.env.UMI_APP_SSO_LOGIN_URL + // encodeURIComponent(process.env.UMI_APP_OPERATION_URL || ''); // } }, // actionsRender: (props) => { // if (props.isMobile) return []; // if (typeof window === 'undefined') return []; // return [ // props.layout !== 'side' && document.body.clientWidth > 1400 ? ( // // ) : undefined, // , // , // , // ]; // }, headerRender: (props, defaultDom) => { return ( <> {initialState?.tip?.show && ( 本网站提供的部分服务在你当前浏览器中无法使用,建议你更换为 Chrome 浏览器查看本网站。 } icon={ } banner style={{ backgroundColor: 'black', }} action={ } /> )} {React.cloneElement(defaultDom as any, { style: { height: '56px', lineHeight: '56px', }, })} ); }, footerRender: () => { return <>; }, // menuExtraRender: (props) => { // if (props.isMobile) { // return ; // } // }, menuFooterRender: (props) => { if (props?.collapsed) return undefined; return (

{initialState?.channel?.title} 提供技术支持

); }, }; }; // 错误处理方案: 错误类型 enum ErrorShowType { SILENT = 0, WARN_MESSAGE = 1, ERROR_MESSAGE = 2, NOTIFICATION = 3, REDIRECT = 9, } // 与后端约定的响应数据格式 interface ResponseStructure { success: boolean; data: any; errCode?: string; errMessage?: string; showType?: ErrorShowType; } // 运行时配置 export const request: RequestConfig = { // 统一的请求设定 timeout: 60000, headers: { 'X-Requested-With': 'XMLHttpRequest', 'Xh-Platform-Id': '1769220738064285698', }, // 错误处理: umi@3 的错误处理方案。 errorConfig: { // 错误抛出 errorThrower: (res: ResponseStructure) => { const { success, data, errCode, errMessage, showType } = res; if (!success) { if (errCode === '401' || errCode === '403') { window.localStorage.removeItem('employee'); window.localStorage.removeItem('admin'); window.localStorage.removeItem('roleSlug'); // 未登录,跳转到登录页面 window.location.href = process.env.UMI_APP_SSO_LOGIN_URL + encodeURIComponent(process.env.UMI_APP_OPERATION_URL || ''); return; } if (errCode === '400') { message.error(errMessage); return; } if (errCode === 'UNKNOWN_ERROR') { message.error('未知的错误'); return; } const error: any = new Error(errMessage || errCode); error.name = 'BizError'; error.info = { errCode, errMessage, 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 { errMessage, errCode } = errorInfo; switch (errorInfo.showType) { case ErrorShowType.SILENT: // do nothing break; case ErrorShowType.WARN_MESSAGE: message.warning(errMessage); break; case ErrorShowType.ERROR_MESSAGE: message.error(errMessage); break; case ErrorShowType.NOTIFICATION: notification.open({ description: errMessage, message: errCode, }); break; case ErrorShowType.REDIRECT: // TODO: redirect break; default: message.error(errMessage); } } } 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.1'); } else { // 发送请求时出了点问题 message.error('Request error, please retry.2'); } }, }, // 请求拦截器 requestInterceptors: [ ( url: any, options: { headers: any; }, ) => { const roleSlug = window.localStorage.getItem('roleSlug'); if (roleSlug) { options.headers = { ...options.headers, 'Xh-Role-Slug': roleSlug, }; } console.debug('请求拦截器', url, options); const apiUrl = '/api' + url; return { url: apiUrl, options, }; }, ], // 响应拦截器 responseInterceptors: [ (response: ResponseStructure) => { // 拦截响应数据,进行个性化处理 return response; }, ], } as any;