2025-11-23 14:50:18 +08:00
|
|
|
|
import './utils/amap_system';
|
2025-03-28 15:30:35 +08:00
|
|
|
|
import { AvatarDropdown, AvatarName, Footer, SelectLang } from '@/components';
|
2024-11-18 16:38:38 +08:00
|
|
|
|
import type { Settings as LayoutSettings } from '@ant-design/pro-components';
|
|
|
|
|
|
import { SettingDrawer } from '@ant-design/pro-components';
|
|
|
|
|
|
import type { RunTimeLayoutConfig } from '@umijs/max';
|
2025-03-28 15:30:35 +08:00
|
|
|
|
import { history } from '@umijs/max';
|
2024-11-18 16:38:38 +08:00
|
|
|
|
import defaultSettings from '../config/defaultSettings';
|
|
|
|
|
|
import { errorConfig } from './requestErrorConfig';
|
|
|
|
|
|
import { clearSessionToken, getAccessToken, getRefreshToken, getTokenExpireTime } from './access';
|
2025-03-28 15:30:35 +08:00
|
|
|
|
import {
|
|
|
|
|
|
getRemoteMenu,
|
|
|
|
|
|
getRoutersInfo,
|
|
|
|
|
|
getUserInfo,
|
|
|
|
|
|
patchRouteWithRemoteMenus,
|
|
|
|
|
|
setRemoteMenu,
|
|
|
|
|
|
} from './services/session';
|
2024-11-18 16:38:38 +08:00
|
|
|
|
import { PageEnum } from './enums/pagesEnums';
|
2024-11-19 16:16:30 +08:00
|
|
|
|
import { stringify } from 'querystring';
|
2025-03-28 15:30:35 +08:00
|
|
|
|
import { message } from 'antd';
|
2025-11-28 16:28:54 +08:00
|
|
|
|
import { encrypt, decrypt, needEncrypt } from '@/utils/encrypt';
|
2024-11-18 16:38:38 +08:00
|
|
|
|
|
|
|
|
|
|
const isDev = process.env.NODE_ENV === 'development';
|
2024-11-19 16:16:30 +08:00
|
|
|
|
const loginOut = async () => {
|
|
|
|
|
|
clearSessionToken();
|
|
|
|
|
|
setRemoteMenu(null);
|
|
|
|
|
|
const { search, pathname } = window.location;
|
|
|
|
|
|
const urlParams = new URL(window.location.href).searchParams;
|
|
|
|
|
|
/** 此方法会跳转到 redirect 参数所在的位置 */
|
|
|
|
|
|
const redirect = urlParams.get('redirect');
|
|
|
|
|
|
// Note: There may be security issues, please note
|
2025-03-28 15:30:35 +08:00
|
|
|
|
console.log('redirect', window.location.pathname, redirect);
|
2025-01-20 17:42:05 +08:00
|
|
|
|
if (window.location.pathname !== '/qingdao/user/login' && !redirect) {
|
2024-11-19 16:16:30 +08:00
|
|
|
|
history.replace({
|
|
|
|
|
|
pathname: '/user/login',
|
|
|
|
|
|
search: stringify({
|
2025-01-20 17:42:05 +08:00
|
|
|
|
redirect: pathname.replace('/qingdao', '') + search,
|
2024-11-19 16:16:30 +08:00
|
|
|
|
}),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
2024-11-18 16:38:38 +08:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @see https://umijs.org/zh-CN/plugins/plugin-initial-state
|
|
|
|
|
|
* */
|
|
|
|
|
|
export async function getInitialState(): Promise<{
|
|
|
|
|
|
settings?: Partial<LayoutSettings>;
|
|
|
|
|
|
currentUser?: API.CurrentUser;
|
|
|
|
|
|
loading?: boolean;
|
|
|
|
|
|
fetchUserInfo?: () => Promise<API.CurrentUser | undefined>;
|
|
|
|
|
|
}> {
|
|
|
|
|
|
const fetchUserInfo = async () => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const response = await getUserInfo({
|
|
|
|
|
|
skipErrorHandler: true,
|
|
|
|
|
|
});
|
|
|
|
|
|
if (response.user.avatar === '') {
|
|
|
|
|
|
response.user.avatar =
|
|
|
|
|
|
'https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png';
|
|
|
|
|
|
}
|
|
|
|
|
|
return {
|
|
|
|
|
|
...response.user,
|
|
|
|
|
|
permissions: response.permissions,
|
|
|
|
|
|
roles: response.roles,
|
|
|
|
|
|
} as API.CurrentUser;
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.log(error);
|
|
|
|
|
|
history.push(PageEnum.LOGIN);
|
|
|
|
|
|
}
|
|
|
|
|
|
return undefined;
|
|
|
|
|
|
};
|
|
|
|
|
|
// 如果不是登录页面,执行
|
|
|
|
|
|
const { location } = history;
|
|
|
|
|
|
if (location.pathname !== PageEnum.LOGIN) {
|
|
|
|
|
|
const currentUser = await fetchUserInfo();
|
|
|
|
|
|
return {
|
|
|
|
|
|
fetchUserInfo,
|
|
|
|
|
|
currentUser,
|
|
|
|
|
|
settings: defaultSettings as Partial<LayoutSettings>,
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
return {
|
|
|
|
|
|
fetchUserInfo,
|
|
|
|
|
|
settings: defaultSettings as Partial<LayoutSettings>,
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
2025-03-28 15:30:35 +08:00
|
|
|
|
|
2024-11-18 16:38:38 +08:00
|
|
|
|
// ProLayout 支持的api https://procomponents.ant.design/components/layout
|
|
|
|
|
|
export const layout: RunTimeLayoutConfig = ({ initialState, setInitialState }) => {
|
|
|
|
|
|
return {
|
2024-11-19 16:16:30 +08:00
|
|
|
|
// actionsRender: () => [<Question key="doc" />, <SelectLang key="SelectLang" />],
|
2025-03-28 15:30:35 +08:00
|
|
|
|
actionsRender: () => [<SelectLang key="SelectLang" />],
|
2024-11-18 16:38:38 +08:00
|
|
|
|
avatarProps: {
|
|
|
|
|
|
src: initialState?.currentUser?.avatar,
|
|
|
|
|
|
title: <AvatarName />,
|
|
|
|
|
|
render: (_, avatarChildren) => {
|
|
|
|
|
|
return <AvatarDropdown menu="True">{avatarChildren}</AvatarDropdown>;
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
waterMarkProps: {
|
|
|
|
|
|
// content: initialState?.currentUser?.nickName,
|
|
|
|
|
|
},
|
2025-01-20 17:42:05 +08:00
|
|
|
|
// actionRef: layoutActionRef,
|
2024-11-18 16:38:38 +08:00
|
|
|
|
menu: {
|
|
|
|
|
|
locale: false,
|
2025-01-20 17:42:05 +08:00
|
|
|
|
// // 每当 initialState?.currentUser?.userid 发生修改时重新执行 request
|
2024-11-18 16:38:38 +08:00
|
|
|
|
params: {
|
|
|
|
|
|
userId: initialState?.currentUser?.userId,
|
|
|
|
|
|
},
|
|
|
|
|
|
request: async () => {
|
|
|
|
|
|
if (!initialState?.currentUser?.userId) {
|
|
|
|
|
|
return [];
|
|
|
|
|
|
}
|
2025-03-28 15:30:35 +08:00
|
|
|
|
return getRemoteMenu();
|
2024-11-18 16:38:38 +08:00
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
footerRender: () => <Footer />,
|
|
|
|
|
|
onPageChange: () => {
|
|
|
|
|
|
const { location } = history;
|
|
|
|
|
|
// 如果没有登录,重定向到 login
|
|
|
|
|
|
if (!initialState?.currentUser && location.pathname !== PageEnum.LOGIN) {
|
|
|
|
|
|
history.push(PageEnum.LOGIN);
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
layoutBgImgList: [
|
|
|
|
|
|
{
|
|
|
|
|
|
src: 'https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/D2LWSqNny4sAAAAAAAAAAAAAFl94AQBr',
|
|
|
|
|
|
left: 85,
|
|
|
|
|
|
bottom: 100,
|
|
|
|
|
|
height: '303px',
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
src: 'https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/C2TWRpJpiC0AAAAAAAAAAAAAFl94AQBr',
|
|
|
|
|
|
bottom: -68,
|
|
|
|
|
|
right: -45,
|
|
|
|
|
|
height: '303px',
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
src: 'https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/F6vSTbj8KpYAAAAAAAAAAAAAFl94AQBr',
|
|
|
|
|
|
bottom: 0,
|
|
|
|
|
|
left: 0,
|
|
|
|
|
|
width: '331px',
|
|
|
|
|
|
},
|
|
|
|
|
|
],
|
2025-03-28 15:30:35 +08:00
|
|
|
|
pure: false,
|
2024-11-19 16:16:30 +08:00
|
|
|
|
// links: isDev
|
|
|
|
|
|
// ? [
|
|
|
|
|
|
// <Link key="openapi" to="/umi/plugin/openapi" target="_blank">
|
|
|
|
|
|
// <LinkOutlined />
|
|
|
|
|
|
// <span>OpenAPI 文档</span>
|
|
|
|
|
|
// </Link>,
|
|
|
|
|
|
// ]
|
|
|
|
|
|
// : [],
|
2024-11-18 16:38:38 +08:00
|
|
|
|
menuHeaderRender: undefined,
|
|
|
|
|
|
// 自定义 403 页面
|
|
|
|
|
|
// unAccessible: <div>unAccessible</div>,
|
|
|
|
|
|
// 增加一个 loading 的状态
|
|
|
|
|
|
childrenRender: (children) => {
|
|
|
|
|
|
// if (initialState?.loading) return <PageLoading />;
|
|
|
|
|
|
return (
|
|
|
|
|
|
<>
|
|
|
|
|
|
{children}
|
|
|
|
|
|
<SettingDrawer
|
|
|
|
|
|
disableUrlParams
|
|
|
|
|
|
enableDarkTheme
|
|
|
|
|
|
settings={initialState?.settings}
|
|
|
|
|
|
onSettingChange={(settings) => {
|
|
|
|
|
|
setInitialState((preInitialState) => ({
|
|
|
|
|
|
...preInitialState,
|
|
|
|
|
|
settings,
|
|
|
|
|
|
}));
|
|
|
|
|
|
}}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</>
|
|
|
|
|
|
);
|
|
|
|
|
|
},
|
|
|
|
|
|
...initialState?.settings,
|
|
|
|
|
|
};
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
export async function onRouteChange({ clientRoutes, location }) {
|
|
|
|
|
|
const menus = getRemoteMenu();
|
2025-03-28 15:30:35 +08:00
|
|
|
|
// console.log('onRouteChange', clientRoutes, location, menus);
|
|
|
|
|
|
if (menus === null && location.pathname !== PageEnum.LOGIN) {
|
|
|
|
|
|
console.log('refresh');
|
2025-01-20 17:42:05 +08:00
|
|
|
|
// history.go(0);
|
2024-11-18 16:38:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// export function patchRoutes({ routes, routeComponents }) {
|
|
|
|
|
|
// console.log('patchRoutes', routes, routeComponents);
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
export async function patchClientRoutes({ routes }) {
|
|
|
|
|
|
// console.log('patchClientRoutes', routes);
|
|
|
|
|
|
patchRouteWithRemoteMenus(routes);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-11-19 16:16:30 +08:00
|
|
|
|
export async function render(oldRender: () => void) {
|
2025-03-28 15:30:35 +08:00
|
|
|
|
console.log('render get routers', oldRender);
|
2024-11-18 16:38:38 +08:00
|
|
|
|
const token = getAccessToken();
|
2025-03-28 15:30:35 +08:00
|
|
|
|
if (!token || token?.length === 0) {
|
2024-11-18 16:38:38 +08:00
|
|
|
|
oldRender();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-03-28 15:30:35 +08:00
|
|
|
|
await getRoutersInfo().then((res) => {
|
|
|
|
|
|
console.log('render get routers', 123);
|
2025-01-20 17:42:05 +08:00
|
|
|
|
|
2024-11-18 16:38:38 +08:00
|
|
|
|
setRemoteMenu(res);
|
2025-03-28 15:30:35 +08:00
|
|
|
|
oldRender();
|
2024-11-18 16:38:38 +08:00
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @name request 配置,可以配置错误处理
|
|
|
|
|
|
* 它基于 axios 和 ahooks 的 useRequest 提供了一套统一的网络请求和错误处理方案。
|
|
|
|
|
|
* @doc https://umijs.org/docs/max/request#配置
|
|
|
|
|
|
*/
|
|
|
|
|
|
const checkRegion = 5 * 60 * 1000;
|
|
|
|
|
|
export const request = {
|
|
|
|
|
|
...errorConfig,
|
2025-12-09 14:44:09 +08:00
|
|
|
|
baseURL: process.env.NODE_ENV === 'development' ? '' : 'https://qd.zhaopinzao8dian.com/api',
|
2025-01-20 17:42:05 +08:00
|
|
|
|
// baseURL: 'http://39.98.44.136:8080',
|
2025-12-09 14:44:09 +08:00
|
|
|
|
// baseURL:
|
|
|
|
|
|
// process.env.NODE_ENV === 'development'
|
|
|
|
|
|
// ? 'http://10.213.6.207:19010'
|
|
|
|
|
|
// : 'http://10.213.6.207:19010/api',
|
2024-11-18 16:38:38 +08:00
|
|
|
|
requestInterceptors: [
|
2025-11-28 16:28:54 +08:00
|
|
|
|
(url: any, options: { headers: any; data?: any; params?: any; method?: string }) => {
|
|
|
|
|
|
const headers = options.headers ? options.headers : {};
|
2024-11-18 16:38:38 +08:00
|
|
|
|
console.log('request ====>:', url);
|
|
|
|
|
|
const authHeader = headers['Authorization'];
|
|
|
|
|
|
const isToken = headers['isToken'];
|
2025-11-28 16:28:54 +08:00
|
|
|
|
|
2025-11-28 19:14:42 +08:00
|
|
|
|
// 处理开发环境API路径
|
|
|
|
|
|
if (process.env.NODE_ENV !== 'development') {
|
|
|
|
|
|
if (url.startsWith('/api')) {
|
|
|
|
|
|
url = url.replace(/^\/api/, '');
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-28 16:28:54 +08:00
|
|
|
|
// 处理认证token
|
2024-11-18 16:38:38 +08:00
|
|
|
|
if (!authHeader && isToken !== false) {
|
|
|
|
|
|
const expireTime = getTokenExpireTime();
|
|
|
|
|
|
if (expireTime) {
|
|
|
|
|
|
const left = Number(expireTime) - new Date().getTime();
|
|
|
|
|
|
const refreshToken = getRefreshToken();
|
|
|
|
|
|
if (left < checkRegion && refreshToken) {
|
|
|
|
|
|
if (left < 0) {
|
|
|
|
|
|
clearSessionToken();
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
const accessToken = getAccessToken();
|
|
|
|
|
|
if (accessToken) {
|
|
|
|
|
|
headers['Authorization'] = `Bearer ${accessToken}`;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
clearSessionToken();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-11-28 16:28:54 +08:00
|
|
|
|
|
|
|
|
|
|
// 处理SM4加密 - 根据config的isEncrypt来判断
|
|
|
|
|
|
if (needEncrypt(options)) {
|
|
|
|
|
|
console.log('进行SM4加密处理');
|
|
|
|
|
|
|
|
|
|
|
|
let requestData = options.data;
|
|
|
|
|
|
let requestParams = options.params;
|
|
|
|
|
|
|
|
|
|
|
|
// 加密请求数据
|
|
|
|
|
|
if (requestData && Object.keys(requestData).length > 0) {
|
|
|
|
|
|
const jsonData = JSON.stringify(requestData);
|
|
|
|
|
|
const encryptedBody = encrypt(jsonData);
|
|
|
|
|
|
requestData = {
|
|
|
|
|
|
encrypted: true,
|
|
|
|
|
|
encryptedData: encryptedBody,
|
|
|
|
|
|
timestamp: Date.now(),
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 加密查询参数
|
|
|
|
|
|
if (requestParams && Object.keys(requestParams).length > 0) {
|
|
|
|
|
|
const jsonParams = JSON.stringify(requestParams);
|
|
|
|
|
|
const encryptedParams = encrypt(jsonParams);
|
|
|
|
|
|
requestParams = {
|
|
|
|
|
|
encrypted: true,
|
|
|
|
|
|
encryptedData: encryptedParams,
|
|
|
|
|
|
timestamp: Date.now(),
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 添加加密标识头
|
|
|
|
|
|
headers['X-Encrypted'] = 'true';
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
url,
|
|
|
|
|
|
options: {
|
|
|
|
|
|
...options,
|
|
|
|
|
|
headers,
|
|
|
|
|
|
data: requestData,
|
|
|
|
|
|
params: requestParams,
|
|
|
|
|
|
},
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return { url, options: { ...options, headers } };
|
2024-11-18 16:38:38 +08:00
|
|
|
|
},
|
|
|
|
|
|
],
|
|
|
|
|
|
responseInterceptors: [
|
2024-11-19 16:16:30 +08:00
|
|
|
|
(response) => {
|
|
|
|
|
|
// 不再需要异步处理读取返回体内容,可直接在data中读出,部分字段可在 config 中找到
|
|
|
|
|
|
const { data = {} as any, config } = response;
|
2025-11-28 16:28:54 +08:00
|
|
|
|
|
|
|
|
|
|
// 检查是否需要解密
|
|
|
|
|
|
const isEncrypted = data.encrypted;
|
|
|
|
|
|
|
|
|
|
|
|
if (isEncrypted && data.encryptedData) {
|
|
|
|
|
|
console.log('进行SM4解密处理');
|
|
|
|
|
|
try {
|
|
|
|
|
|
// 解密响应数据
|
|
|
|
|
|
const decryptedData = decrypt(data.encryptedData);
|
2025-12-02 14:58:19 +08:00
|
|
|
|
// console.log(decryptedData)
|
2025-11-28 16:28:54 +08:00
|
|
|
|
response.data =
|
|
|
|
|
|
typeof decryptedData === 'string' ? JSON.parse(decryptedData) : decryptedData;
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('响应解密失败:', error);
|
|
|
|
|
|
// 如果解密失败,保持原始数据
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 处理业务状态码
|
2024-11-19 16:16:30 +08:00
|
|
|
|
switch (data.code) {
|
|
|
|
|
|
case 401:
|
2025-03-28 15:30:35 +08:00
|
|
|
|
loginOut();
|
|
|
|
|
|
break;
|
2024-11-19 16:16:30 +08:00
|
|
|
|
}
|
2025-03-28 15:30:35 +08:00
|
|
|
|
if (data.code !== 200 && data.msg) {
|
|
|
|
|
|
message.info(data.msg);
|
2024-12-05 16:32:02 +08:00
|
|
|
|
}
|
2025-11-28 16:28:54 +08:00
|
|
|
|
|
2025-03-28 15:30:35 +08:00
|
|
|
|
return response;
|
2024-11-19 16:16:30 +08:00
|
|
|
|
},
|
2024-11-18 16:38:38 +08:00
|
|
|
|
],
|
|
|
|
|
|
};
|