| @@ -163,4 +163,5 @@ export default defineConfig({ | |||
| }, | |||
| javascriptEnabled: true, | |||
| }, | |||
| // plugins: ['umi-plugin-keep-alive'], | |||
| }); | |||
| @@ -133,22 +133,7 @@ export const layout: RunTimeLayoutConfig = ({ initialState }) => { | |||
| // 增加一个 loading 的状态 | |||
| childrenRender: (children) => { | |||
| // if (initialState?.loading) return <PageLoading />; | |||
| return ( | |||
| <> | |||
| {children} | |||
| {/* <SettingDrawer | |||
| disableUrlParams | |||
| enableDarkTheme | |||
| settings={initialState?.settings} | |||
| onSettingChange={(settings) => { | |||
| setInitialState((preInitialState) => ({ | |||
| ...preInitialState, | |||
| settings, | |||
| })); | |||
| }} | |||
| /> */} | |||
| </> | |||
| ); | |||
| return <>{children}</>; | |||
| }, | |||
| ...initialState?.settings, | |||
| }; | |||
| @@ -17,13 +17,8 @@ const HeaderDropdown: React.FC<HeaderDropdownProps> = ({ overlayClassName: cls, | |||
| }, | |||
| }; | |||
| }); | |||
| return ( | |||
| <Dropdown | |||
| overlayClassName={classNames(className, cls)} | |||
| getPopupContainer={(target) => target.parentElement || document.body} | |||
| {...restProps} | |||
| /> | |||
| ); | |||
| return <Dropdown overlayClassName={classNames(className, cls)} {...restProps} />; | |||
| }; | |||
| export default HeaderDropdown; | |||
| @@ -1,13 +1,12 @@ | |||
| import { clearSessionToken } from '@/access'; | |||
| import { PageEnum } from '@/enums/pagesEnums'; | |||
| import { setRemoteMenu } from '@/services/session'; | |||
| import { logout } from '@/services/system/auth'; | |||
| import { gotoLoginPage } from '@/utils/ui'; | |||
| import { LogoutOutlined, SettingOutlined, UserOutlined } from '@ant-design/icons'; | |||
| import { setAlpha } from '@ant-design/pro-components'; | |||
| import { useEmotionCss } from '@ant-design/use-emotion-css'; | |||
| import { history, useModel } from '@umijs/max'; | |||
| import { Avatar, Spin } from 'antd'; | |||
| import { stringify } from 'querystring'; | |||
| import type { MenuInfo } from 'rc-menu/lib/interface'; | |||
| import React, { useCallback } from 'react'; | |||
| import { flushSync } from 'react-dom'; | |||
| @@ -23,7 +22,7 @@ const Name = () => { | |||
| const nameClassName = useEmotionCss(({ token }) => { | |||
| return { | |||
| width: '70px', | |||
| // width: '70px', | |||
| height: '48px', | |||
| overflow: 'hidden', | |||
| lineHeight: '48px', | |||
| @@ -64,19 +63,7 @@ const AvatarDropdown: React.FC<GlobalHeaderRightProps> = ({ menu }) => { | |||
| await logout(); | |||
| 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 | |||
| if (window.location.pathname !== PageEnum.LOGIN && !redirect) { | |||
| history.replace({ | |||
| pathname: PageEnum.LOGIN, | |||
| search: stringify({ | |||
| redirect: pathname + search, | |||
| }), | |||
| }); | |||
| } | |||
| gotoLoginPage(); | |||
| }; | |||
| const actionClassName = useEmotionCss(({ token }) => { | |||
| return { | |||
| @@ -1,6 +1,5 @@ | |||
| import { QuestionCircleOutlined } from '@ant-design/icons'; | |||
| import { useEmotionCss } from '@ant-design/use-emotion-css'; | |||
| import { SelectLang, useModel } from '@umijs/max'; | |||
| import { useModel } from '@umijs/max'; | |||
| import React from 'react'; | |||
| import Avatar from './AvatarDropdown'; | |||
| @@ -17,21 +16,21 @@ const GlobalHeaderRight: React.FC = () => { | |||
| }; | |||
| }); | |||
| const actionClassName = useEmotionCss(({ token }) => { | |||
| return { | |||
| display: 'flex', | |||
| float: 'right', | |||
| height: '48px', | |||
| marginLeft: 'auto', | |||
| overflow: 'hidden', | |||
| cursor: 'pointer', | |||
| padding: '0 12px', | |||
| borderRadius: token.borderRadius, | |||
| '&:hover': { | |||
| backgroundColor: token.colorBgTextHover, | |||
| }, | |||
| }; | |||
| }); | |||
| // const actionClassName = useEmotionCss(({ token }) => { | |||
| // return { | |||
| // display: 'flex', | |||
| // float: 'right', | |||
| // height: '48px', | |||
| // marginLeft: 'auto', | |||
| // overflow: 'hidden', | |||
| // cursor: 'pointer', | |||
| // padding: '0 12px', | |||
| // borderRadius: token.borderRadius, | |||
| // '&:hover': { | |||
| // backgroundColor: token.colorBgTextHover, | |||
| // }, | |||
| // }; | |||
| // }); | |||
| const { initialState } = useModel('@@initialState'); | |||
| @@ -41,15 +40,15 @@ const GlobalHeaderRight: React.FC = () => { | |||
| return ( | |||
| <div className={className}> | |||
| <span | |||
| {/* <span | |||
| className={actionClassName} | |||
| onClick={() => { | |||
| window.open('https://pro.ant.design/docs/getting-started'); | |||
| }} | |||
| > | |||
| <QuestionCircleOutlined /> | |||
| </span> | |||
| <Avatar menu={true} /> | |||
| </span> */} | |||
| <Avatar menu={false} /> | |||
| {/* <SelectLang className={actionClassName} /> */} | |||
| </div> | |||
| ); | |||
| @@ -145,7 +145,13 @@ function AddExperimentModal({ | |||
| name="description" | |||
| rules={[{ required: true, message: '请输入实验描述' }]} | |||
| > | |||
| <Input placeholder="请输入实验描述" maxLength={128} showCount allowClear /> | |||
| <Input.TextArea | |||
| placeholder="请输入实验描述" | |||
| maxLength={128} | |||
| autoSize={{ minRows: 2, maxRows: 5 }} | |||
| showCount | |||
| allowClear | |||
| /> | |||
| </Form.Item> | |||
| <Form.Item | |||
| label="选择流水线" | |||
| @@ -6,8 +6,8 @@ | |||
| import type { RequestConfig } from '@umijs/max'; | |||
| import { message } from 'antd'; | |||
| import { clearSessionToken, getAccessToken, getRefreshToken, getTokenExpireTime } from './access'; | |||
| const checkRegion = 5 * 60 * 1000; | |||
| import { setRemoteMenu } from './services/session'; | |||
| import { gotoLoginPage } from './utils/ui'; | |||
| /** | |||
| * Umi Max 网络请求配置 | |||
| @@ -25,10 +25,8 @@ export const requestConfig: RequestConfig = { | |||
| if (expireTime) { | |||
| const left = Number(expireTime) - new Date().getTime(); | |||
| const refreshToken = getRefreshToken(); | |||
| if (left < checkRegion && refreshToken) { | |||
| if (left < 0) { | |||
| clearSessionToken(); | |||
| } | |||
| if (left < 0 && refreshToken) { | |||
| clearSessionToken(); | |||
| } else { | |||
| const accessToken = getAccessToken(); | |||
| if (accessToken) { | |||
| @@ -45,15 +43,19 @@ export const requestConfig: RequestConfig = { | |||
| responseInterceptors: [ | |||
| (response: any) => { | |||
| const { status, data } = response; | |||
| // console.log('response', response); | |||
| if (status >= 200 && status < 300 && data && (data instanceof Blob || data.code === 200)) { | |||
| return response; | |||
| } else { | |||
| if (data && data.msg) { | |||
| message.error(data.msg); | |||
| if (status >= 200 && status < 300) { | |||
| if (data && (data instanceof Blob || data.code === 200)) { | |||
| return response; | |||
| } else if (data && data.code === 401) { | |||
| clearSessionToken(); | |||
| setRemoteMenu(null); | |||
| gotoLoginPage(false); | |||
| } else { | |||
| message.error('请求失败'); | |||
| message.error(data?.msg ?? '请求失败'); | |||
| return Promise.reject(response); | |||
| } | |||
| } else { | |||
| message.error('请求失败'); | |||
| return Promise.reject(response); | |||
| } | |||
| }, | |||
| @@ -1,8 +1,7 @@ | |||
| import { createIcon } from '@/utils/IconUtil'; | |||
| import { MenuDataItem } from '@ant-design/pro-components'; | |||
| import { request } from '@umijs/max'; | |||
| import React, { lazy } from 'react'; | |||
| import { createFromIconfontCN } from '@ant-design/icons'; | |||
| let remoteMenu: any = null; | |||
| export function getRemoteMenu() { | |||
| @@ -101,7 +100,7 @@ export function convertCompatRouters(childrens: API.RoutersMenuItem[]): any[] { | |||
| return { | |||
| path: item.path, | |||
| // icon:'icon-a-057_fenlei', | |||
| icon: 'icon-'+item.meta.icon, | |||
| icon: 'icon-' + item.meta.icon, | |||
| // icon: item.meta.icon, | |||
| name: item.meta.title, | |||
| routes: item.children ? convertCompatRouters(item.children) : undefined, | |||
| @@ -28,8 +28,8 @@ export async function login(body: API.LoginParams, options?: Record<string, any> | |||
| /** 退出登录接口 POST /api/login/outLogin */ | |||
| export async function logout() { | |||
| return request<Record<string, any>>('/api/logout', { | |||
| method: 'delete', | |||
| return request<Record<string, any>>('/api/auth/logout', { | |||
| method: 'DELETE', | |||
| }); | |||
| } | |||
| @@ -3,7 +3,9 @@ | |||
| * @Date: 2024-04-19 14:42:51 | |||
| * @Description: UI 公共方法 | |||
| */ | |||
| import { PageEnum } from '@/enums/pagesEnums'; | |||
| import themes from '@/styles/theme.less'; | |||
| import { history } from '@umijs/max'; | |||
| import { Modal, type ModalFuncProps, type UploadFile } from 'antd'; | |||
| // 自定义 Confirm 弹框 | |||
| @@ -43,3 +45,17 @@ export const getFileListFromEvent = (e: any) => { | |||
| return item; | |||
| }); | |||
| }; | |||
| // 去登录页面 | |||
| export const gotoLoginPage = (toHome: boolean = true) => { | |||
| const { search, pathname } = window.location; | |||
| const urlParams = new URLSearchParams(); | |||
| urlParams.append('redirect', pathname + search); | |||
| const newSearch = toHome ? '' : urlParams.toString(); | |||
| if (window.location.pathname !== PageEnum.LOGIN) { | |||
| history.replace({ | |||
| pathname: PageEnum.LOGIN, | |||
| search: newSearch, | |||
| }); | |||
| } | |||
| }; | |||