Browse Source

feat: 重构登录 & 整理图片

pull/105/head
cp3hnu 1 year ago
parent
commit
3c70e8576a
45 changed files with 349 additions and 490 deletions
  1. +0
    -1
      react-ui/config/config.ts
  2. +1
    -1
      react-ui/config/defaultSettings.ts
  3. BIN
      react-ui/public/assets/images/delete-icon.png
  4. +0
    -0
      react-ui/public/assets/images/experiment-status/fail-icon.png
  5. +0
    -0
      react-ui/public/assets/images/experiment-status/omitted-icon.png
  6. +0
    -0
      react-ui/public/assets/images/experiment-status/pending-icon.png
  7. +0
    -0
      react-ui/public/assets/images/experiment-status/running-icon.png
  8. +0
    -0
      react-ui/public/assets/images/experiment-status/success-icon.png
  9. BIN
      react-ui/public/assets/images/left-top-logo-1.png
  10. BIN
      react-ui/public/assets/images/pipeline-back.png
  11. BIN
      react-ui/public/assets/images/upload-icon.png
  12. BIN
      react-ui/public/favicon.ico
  13. +1
    -0
      react-ui/src/app.tsx
  14. +0
    -0
      react-ui/src/assets/img/dataset-intro-top.png
  15. BIN
      react-ui/src/assets/img/delete-icon.png
  16. +0
    -0
      react-ui/src/assets/img/duty-message.png
  17. +0
    -0
      react-ui/src/assets/img/login-ai-logo.png
  18. BIN
      react-ui/src/assets/img/login-captcha.png
  19. +0
    -0
      react-ui/src/assets/img/login-left-image.png
  20. BIN
      react-ui/src/assets/img/login-password.png
  21. BIN
      react-ui/src/assets/img/login-user.png
  22. +0
    -0
      react-ui/src/assets/img/logo.png
  23. +0
    -0
      react-ui/src/assets/img/modal-back.png
  24. +0
    -0
      react-ui/src/assets/img/pipeline-canvas-bg.png
  25. +0
    -0
      react-ui/src/assets/img/static-message.png
  26. +1
    -1
      react-ui/src/components/KFModal/index.less
  27. +4
    -0
      react-ui/src/global.less
  28. +1
    -1
      react-ui/src/overrides.less
  29. +1
    -1
      react-ui/src/pages/Dataset/components/ResourceIntro/index.less
  30. +2
    -1
      react-ui/src/pages/DevelopmentEnvironment/Create/index.tsx
  31. +2
    -2
      react-ui/src/pages/DevelopmentEnvironment/List/index.tsx
  32. +1
    -1
      react-ui/src/pages/Experiment/Info/index.less
  33. +16
    -4
      react-ui/src/pages/Experiment/components/ExperimentParameter/index.tsx
  34. +1
    -1
      react-ui/src/pages/Experiment/index.less
  35. +8
    -8
      react-ui/src/pages/Experiment/status.ts
  36. +1
    -0
      react-ui/src/pages/Mirror/Create/index.tsx
  37. +1
    -1
      react-ui/src/pages/Model/components/ModelEvolution/index.less
  38. +1
    -0
      react-ui/src/pages/ModelDeployment/Create/index.tsx
  39. +1
    -1
      react-ui/src/pages/Pipeline/editPipeline/index.less
  40. +16
    -4
      react-ui/src/pages/Pipeline/editPipeline/props.tsx
  41. +1
    -1
      react-ui/src/pages/Pipeline/index.less
  42. +128
    -435
      react-ui/src/pages/User/Login/index.tsx
  43. +154
    -25
      react-ui/src/pages/User/Login/login.less
  44. +6
    -0
      react-ui/src/utils/localStorage.ts
  45. +1
    -1
      react-ui/src/utils/ui.tsx

+ 0
- 1
react-ui/config/config.ts View File

@@ -78,7 +78,6 @@ export default defineConfig({
*/
title: '智能材料科研平台',
layout: {
locale: false,
...defaultSettings,
},
// keepalive: [/./],


+ 1
- 1
react-ui/config/defaultSettings.ts View File

@@ -7,6 +7,7 @@ const Settings: ProLayoutProps & {
pwa?: boolean;
logo?: string;
} = {
locale: 'zh-CN',
navTheme: 'light',
// 拂晓蓝
colorPrimary: '#1664ff',
@@ -18,7 +19,6 @@ const Settings: ProLayoutProps & {
colorWeak: false,
title: '智能材料科研平台',
pwa: true,
logo: '/assets/images/left-top-logo.png',
token: {
// 参见ts声明,demo 见文档,通过token 修改样式
//https://procomponents.ant.design/components/layout#%E9%80%9A%E8%BF%87-token-%E4%BF%AE%E6%94%B9%E6%A0%B7%E5%BC%8F


BIN
react-ui/public/assets/images/delete-icon.png View File

Before After
Width: 313  |  Height: 184  |  Size: 14 kB

react-ui/public/assets/images/fail-icon.png → react-ui/public/assets/images/experiment-status/fail-icon.png View File


react-ui/public/assets/images/omitted-icon.png → react-ui/public/assets/images/experiment-status/omitted-icon.png View File


react-ui/public/assets/images/pending-icon.png → react-ui/public/assets/images/experiment-status/pending-icon.png View File


react-ui/public/assets/images/running-icon.png → react-ui/public/assets/images/experiment-status/running-icon.png View File


react-ui/public/assets/images/success-icon.png → react-ui/public/assets/images/experiment-status/success-icon.png View File


BIN
react-ui/public/assets/images/left-top-logo-1.png View File

Before After
Width: 79  |  Height: 86  |  Size: 4.8 kB

BIN
react-ui/public/assets/images/pipeline-back.png View File

Before After
Width: 3360  |  Height: 98  |  Size: 151 kB

BIN
react-ui/public/assets/images/upload-icon.png View File

Before After
Width: 35  |  Height: 28  |  Size: 939 B

BIN
react-ui/public/favicon.ico View File

Before After

+ 1
- 0
react-ui/src/app.tsx View File

@@ -146,6 +146,7 @@ export const layout: RuntimeConfig['layout'] = ({ initialState }) => {
},
},
...initialState?.settings,
logo: require('@/assets/img/logo.png'),
token: {
sider: {
colorTextMenu: themes['textColor'],


react-ui/public/assets/images/dataset-back.png → react-ui/src/assets/img/dataset-intro-top.png View File


BIN
react-ui/src/assets/img/delete-icon.png View File

Before After
Width: 200  |  Height: 200  |  Size: 3.3 kB Width: 313  |  Height: 184  |  Size: 14 kB

react-ui/public/assets/images/duty-message.png → react-ui/src/assets/img/duty-message.png View File


react-ui/public/assets/images/ai-logo.png → react-ui/src/assets/img/login-ai-logo.png View File


BIN
react-ui/src/assets/img/login-captcha.png View File

Before After
Width: 46  |  Height: 53  |  Size: 1.3 kB

react-ui/public/assets/images/left-back-logo.png → react-ui/src/assets/img/login-left-image.png View File


BIN
react-ui/src/assets/img/login-password.png View File

Before After
Width: 45  |  Height: 53  |  Size: 1.1 kB

BIN
react-ui/src/assets/img/login-user.png View File

Before After
Width: 47  |  Height: 51  |  Size: 1.3 kB

react-ui/public/assets/images/left-top-logo.png → react-ui/src/assets/img/logo.png View File


react-ui/public/assets/images/modal-back.png → react-ui/src/assets/img/modal-back.png View File


react-ui/public/assets/images/pipeline-canvas-back.png → react-ui/src/assets/img/pipeline-canvas-bg.png View File


react-ui/public/assets/images/static-message.png → react-ui/src/assets/img/static-message.png View File


+ 1
- 1
react-ui/src/components/KFModal/index.less View File

@@ -1,7 +1,7 @@
.kf-modal {
.ant-modal-content {
padding: 40px 67px;
background-image: url(/assets/images/modal-back.png);
background-image: url(@/assets/img/modal-back.png);
background-repeat: no-repeat;
background-position: top center;
background-size: 100%;


+ 4
- 0
react-ui/src/global.less View File

@@ -148,3 +148,7 @@ ol {
left: 0;
z-index: 999;
}

input:-webkit-autofill {
transition: background-color 5000s ease-in-out 0s;
}

+ 1
- 1
react-ui/src/overrides.less View File

@@ -126,7 +126,7 @@
.ant-modal-confirm {
.ant-modal-content {
padding: 40px 67px;
background-image: url(/assets/images/modal-back.png);
background-image: url(@/assets/img/modal-back.png);
background-repeat: no-repeat;
background-position: top center;
background-size: 100%;


+ 1
- 1
react-ui/src/pages/Dataset/components/ResourceIntro/index.less View File

@@ -6,7 +6,7 @@
height: 110px;
margin-bottom: 10px;
padding: 20px 30px 0;
background-image: url(/assets/images/dataset-back.png);
background-image: url(@/assets/img/dataset-intro-top.png);
background-repeat: no-repeat;
background-position: top center;
background-size: 100% 100%;


+ 2
- 1
react-ui/src/pages/DevelopmentEnvironment/Create/index.tsx View File

@@ -84,7 +84,7 @@ function EditorCreate() {

return (
<div className={styles['editor-create']}>
<PageTitle title="创建编辑器"></PageTitle>
<PageTitle title="创建开发环境"></PageTitle>
<div className={styles['editor-create__content']}>
<div>
<Form
@@ -96,6 +96,7 @@ function EditorCreate() {
initialValues={{ computing_resource: ComputingResourceType.GPU }}
onFinish={handleSubmit}
size="large"
autoComplete="off"
>
<SubAreaTitle
title="基本信息"


+ 2
- 2
react-ui/src/pages/DevelopmentEnvironment/List/index.tsx View File

@@ -213,7 +213,7 @@ function EditorList() {
icon={<KFIcon type="icon-tiaoshi" />}
onClick={() => startEditor(record.id)}
>
再次调试
启动
</Button>
)}
<ConfigProvider
@@ -247,7 +247,7 @@ function EditorList() {
onClick={createEditor}
icon={<KFIcon type="icon-xinjian2" />}
>
创建编辑器
创建开发环境
</Button>
<Button
style={{ marginLeft: '20px' }}


+ 1
- 1
react-ui/src/pages/Experiment/Info/index.less View File

@@ -27,7 +27,7 @@
width: 100%;
height: calc(100% - 56px);
background-color: @background-color;
background-image: url(/assets/images/pipeline-canvas-back.png);
background-image: url(@/assets/img/pipeline-canvas-bg.png);
background-size: 100% 100%;
}



+ 16
- 4
react-ui/src/pages/Experiment/components/ExperimentParameter/index.tsx View File

@@ -49,7 +49,10 @@ function ExperimentParameter({ nodeData }: ExperimentParameterProps) {
className={styles['experiment-parameter']}
>
<div className={styles['experiment-parameter__title']}>
<SubAreaTitle image="/assets/images/static-message.png" title="基本信息"></SubAreaTitle>
<SubAreaTitle
image={require('@/assets/img/static-message.png')}
title="基本信息"
></SubAreaTitle>
</div>
<Form.Item
label="任务名称"
@@ -76,7 +79,10 @@ function ExperimentParameter({ nodeData }: ExperimentParameterProps) {
<Input disabled />
</Form.Item>
<div className={styles['experiment-parameter__title']}>
<SubAreaTitle image="/assets/images/duty-message.png" title="任务信息"></SubAreaTitle>
<SubAreaTitle
image={require('@/assets/img/duty-message.png')}
title="任务信息"
></SubAreaTitle>
</div>
<Form.Item
label="镜像"
@@ -128,7 +134,10 @@ function ExperimentParameter({ nodeData }: ExperimentParameterProps) {
</Form.Item>
))}
<div className={styles['experiment-parameter__title']}>
<SubAreaTitle image="/assets/images/duty-message.png" title="输入参数"></SubAreaTitle>
<SubAreaTitle
image={require('@/assets/img/duty-message.png')}
title="输入参数"
></SubAreaTitle>
</div>
{inParametersList.map((item) => (
<Form.Item
@@ -145,7 +154,10 @@ function ExperimentParameter({ nodeData }: ExperimentParameterProps) {
</Form.Item>
))}
<div className={styles['experiment-parameter__title']}>
<SubAreaTitle image="/assets/images/duty-message.png" title="输出参数"></SubAreaTitle>
<SubAreaTitle
image={require('@/assets/img/duty-message.png')}
title="输出参数"
></SubAreaTitle>
</div>
{outParametersList.map((item) => (
<Form.Item


+ 1
- 1
react-ui/src/pages/Experiment/index.less View File

@@ -8,7 +8,7 @@
height: 49px;
margin-bottom: 10px;
padding-right: 30px;
background-image: url(/assets/images/pipeline-back.png);
background-image: url(@/assets/img/page-title-bg.png);
background-repeat: no-repeat;
background-position: top center;
background-size: 100% 100%;


+ 8
- 8
react-ui/src/pages/Experiment/status.ts View File

@@ -11,41 +11,41 @@ export const experimentStatusInfo: Record<ExperimentStatus, ExperimentStatusInfo
Running: {
label: '运行中',
color: themes.primaryColor,
icon: '/assets/images/running-icon.png',
icon: '/assets/images/experiment-status/running-icon.png',
},
Succeeded: {
label: '成功',
color: themes.successColor,
icon: '/assets/images/success-icon.png',
icon: '/assets/images/experiment-status/success-icon.png',
},
Pending: {
label: '等待中',
color: themes.pendingColor,
icon: '/assets/images/pending-icon.png',
icon: '/assets/images/experiment-status/pending-icon.png',
},
Failed: {
label: '失败',
color: themes.errorColor,
icon: '/assets/images/fail-icon.png',
icon: '/assets/images/experiment-status/fail-icon.png',
},
Error: {
label: '错误',
color: themes.errorColor,
icon: '/assets/images/fail-icon.png',
icon: '/assets/images/experiment-status/fail-icon.png',
},
Terminated: {
label: '终止',
color: themes.abortColor,
icon: '/assets/images/omitted-icon.png',
icon: '/assets/images/experiment-status/omitted-icon.png',
},
Skipped: {
label: '未执行',
color: themes.abortColor,
icon: '/assets/images/omitted-icon.png',
icon: '/assets/images/experiment-status/omitted-icon.png',
},
Omitted: {
label: '未执行',
color: themes.abortColor,
icon: '/assets/images/omitted-icon.png',
icon: '/assets/images/experiment-status/omitted-icon.png',
},
};

+ 1
- 0
react-ui/src/pages/Mirror/Create/index.tsx View File

@@ -136,6 +136,7 @@ function MirrorCreate() {
initialValues={{ upload_type: CommonTabKeys.Public }}
onFinish={handleSubmit}
size="large"
autoComplete="off"
>
<SubAreaTitle
title="基本信息"


+ 1
- 1
react-ui/src/pages/Model/components/ModelEvolution/index.less View File

@@ -12,7 +12,7 @@
&__graph {
height: calc(100% - 92px);
background-color: @background-color;
background-image: url(/assets/images/pipeline-canvas-back.png);
background-image: url(@/assets/img/pipeline-canvas-bg.png);
background-size: 100% 100%;
}
}

+ 1
- 0
react-ui/src/pages/ModelDeployment/Create/index.tsx View File

@@ -141,6 +141,7 @@ function ModelDeploymentCreate() {
initialValues={{ upload_type: CommonTabKeys.Public }}
onFinish={handleSubmit}
size="large"
autoComplete="off"
>
<SubAreaTitle
title="基本信息"


+ 1
- 1
react-ui/src/pages/Pipeline/editPipeline/index.less View File

@@ -23,7 +23,7 @@
width: 100%;
height: calc(100% - 52px);
background-color: @background-color;
background-image: url(/assets/images/pipeline-canvas-back.png);
background-image: url(@/assets/img/pipeline-canvas-bg.png);
background-size: 100% 100%;
}
}


+ 16
- 4
react-ui/src/pages/Pipeline/editPipeline/props.tsx View File

@@ -299,7 +299,10 @@ const PipelineNodeParameter = forwardRef(({ onFormChange }: PipelineNodeParamete
scrollToFirstError
>
<div className={styles['pipeline-drawer__title']}>
<SubAreaTitle image="/assets/images/static-message.png" title="基本信息"></SubAreaTitle>
<SubAreaTitle
image={require('@/assets/img/static-message.png')}
title="基本信息"
></SubAreaTitle>
</div>
<Form.Item
label="任务名称"
@@ -326,7 +329,10 @@ const PipelineNodeParameter = forwardRef(({ onFormChange }: PipelineNodeParamete
<Input disabled />
</Form.Item>
<div className={styles['pipeline-drawer__title']}>
<SubAreaTitle image="/assets/images/duty-message.png" title="任务信息"></SubAreaTitle>
<SubAreaTitle
image={require('@/assets/img/duty-message.png')}
title="任务信息"
></SubAreaTitle>
</div>
<Form.Item label="镜像" required>
<div className={styles['pipeline-drawer__ref-row']}>
@@ -436,7 +442,10 @@ const PipelineNodeParameter = forwardRef(({ onFormChange }: PipelineNodeParamete
</Form.Item>
))}
<div className={styles['pipeline-drawer__title']}>
<SubAreaTitle image="/assets/images/duty-message.png" title="输入参数"></SubAreaTitle>
<SubAreaTitle
image={require('@/assets/img/duty-message.png')}
title="输入参数"
></SubAreaTitle>
</div>
{inParametersList.map((item) => (
<Form.Item
@@ -469,7 +478,10 @@ const PipelineNodeParameter = forwardRef(({ onFormChange }: PipelineNodeParamete
</Form.Item>
))}
<div className={styles['pipeline-drawer__title']}>
<SubAreaTitle image="/assets/images/duty-message.png" title="输出参数"></SubAreaTitle>
<SubAreaTitle
image={require('@/assets/img/duty-message.png')}
title="输出参数"
></SubAreaTitle>
</div>
{outParametersList.map((item) => (
<Form.Item


+ 1
- 1
react-ui/src/pages/Pipeline/index.less View File

@@ -6,7 +6,7 @@
height: 49px;
margin-bottom: 10px;
padding-right: 30px;
background-image: url(/assets/images/pipeline-back.png);
background-image: url(@/assets/img/page-title-bg.png);
background-repeat: no-repeat;
background-position: top left;
background-size: 100% 100%;


+ 128
- 435
react-ui/src/pages/User/Login/index.tsx View File

@@ -1,187 +1,48 @@
import { clearSessionToken, setSessionToken } from '@/access';
import { getFakeCaptcha } from '@/services/ant-design-pro/login';
import { getCaptchaImg, login } from '@/services/system/auth';
import {
AlipayCircleOutlined,
LockOutlined,
MobileOutlined,
TaobaoCircleOutlined,
UserOutlined,
WeiboCircleOutlined,
} from '@ant-design/icons';
import {
LoginForm,
ProFormCaptcha,
ProFormCheckbox,
ProFormText,
} from '@ant-design/pro-components';
import { useEmotionCss } from '@ant-design/use-emotion-css';
import { FormattedMessage, SelectLang, history, useIntl, useModel } from '@umijs/max';
import { Alert, Col, Image, Row, message } from 'antd';
import { loginPasswordKey, loginUserKey, rememberPasswordKey } from '@/utils/localStorage';
import { to } from '@/utils/promise';
import { history, useModel } from '@umijs/max';
import { Button, Checkbox, Flex, Form, Image, Input, message } from 'antd';
import React, { useEffect, useState } from 'react';
import { flushSync } from 'react-dom';
import styles from './login.less';

const ActionIcons = () => {
const langClassName = useEmotionCss(({ token }) => {
return {
marginLeft: '8px',
color: 'rgba(0, 0, 0, 0.2)',
fontSize: '24px',
verticalAlign: 'middle',
cursor: 'pointer',
transition: 'color 0.3s',
'&:hover': {
color: token.colorPrimaryActive,
},
};
});

return (
<>
<AlipayCircleOutlined key="AlipayCircleOutlined" className={langClassName} />
<TaobaoCircleOutlined key="TaobaoCircleOutlined" className={langClassName} />
<WeiboCircleOutlined key="WeiboCircleOutlined" className={langClassName} />
</>
);
};

const Lang = () => {
const langClassName = useEmotionCss(({ token }) => {
return {
width: 42,
height: 42,
lineHeight: '42px',
position: 'fixed',
right: 16,
borderRadius: token.borderRadius,
':hover': {
backgroundColor: token.colorBgTextHover,
},
};
});

const LoginInputPrefix = ({ icon }: { icon: string }) => {
return (
<div className={langClassName} data-lang>
{SelectLang && <SelectLang />}
<div className={styles['login-input-prefix']}>
<img className={styles['login-input-prefix__icon']} src={icon} alt="" />
<div className={styles['login-input-prefix__line']}></div>
</div>
);
};

const LoginMessage: React.FC<{
content: string;
}> = ({ content }) => {
return (
<Alert
style={{
marginBottom: 24,
}}
message={content}
type="error"
showIcon
/>
);
};

const Login: React.FC = () => {
const [userLoginState, setUserLoginState] = useState<API.LoginResult>({ code: 200 });
const [type, setType] = useState<string>('account');
const { initialState, setInitialState } = useModel('@@initialState');
const [captchaCode, setCaptchaCode] = useState<string>('');
const [uuid, setUuid] = useState<string>('');
const [form] = Form.useForm();
const [usernameReadOnly, setUsernameReadOnly] = useState<boolean>(true);

const containerClassName = useEmotionCss(() => {
return {
display: 'flex',
height: '100vh',
backgroundColor: '#fff',
backgroundSize: '100% 100%',
};
});
const containerLeftBox = useEmotionCss(() => {
return {
background: 'linear-gradient(180deg,#e2ecff 0%,#f6fafe 100%)',
width: '43%',
height: '100%',
position: 'relative',
};
});
const leftTopBoX = useEmotionCss(() => {
return {
display: 'flex',
position: 'absolute',
top: '55px',
left: '60px',
fontWeight: '500',
color: '#1d1d20',
fontSize: '36px',
fontFamily: 'Alibaba',
};
});
const centerTitleBoX = useEmotionCss(() => {
return {
display: 'flex',
position: 'absolute',
top: '163px',
left: '50%',
transform: 'translateX(-50%)',
fontWeight: '500',
color: '#111111',
fontSize: '45px',
fontFamily: 'Alibaba',
};
});
const centerMessage = useEmotionCss(() => {
return {
display: 'flex',
position: 'absolute',
top: '242px',
left: '50%',
transform: 'translateX(-50%)',
fontWeight: '500',
color: '#606b7a',
fontSize: '26px',
fontFamily: 'Alibaba',
letterSpacing: '8px',
};
});
const containerRightBox = useEmotionCss(() => {
return {
background: '#fff',
width: '57%',
height: '100%',
position: 'relative',
};
});
const rightTopTitle = useEmotionCss(() => {
return {
display: 'flex',
position: 'absolute',
alignItems: 'center',
top: '147px',
left: '230px',
fontFamily: 'Alibaba',
};
});
const containerLoginForm = useEmotionCss(() => {
return {
width: '640px',
position: 'absolute',
background: '#ffffff',
borderRadius: '10px',
boxShadow: '0px 3px 20px rgba(153, 153, 153, 0.16)',
padding: '62px 36px 45px 36px',
left: '230px',
top: '220px',
};
});
const intl = useIntl();
useEffect(() => {
getCaptchaCode();
const autoLogin = localStorage.getItem(rememberPasswordKey) ?? 'false';
if (autoLogin === 'true') {
const username = localStorage.getItem(loginUserKey);
const password = localStorage.getItem(loginPasswordKey);
form.setFieldsValue({ username: username, password: password, autoLogin: true });
} else {
form.setFieldsValue({ username: '', password: '', autoLogin: false });
}
}, []);

const getCaptchaCode = async () => {
const response = await getCaptchaImg();
const imgdata = `data:image/png;base64,${response.img}`;
setCaptchaCode(imgdata);
setUuid(response.uuid);
const [res] = await to(getCaptchaImg());
if (res) {
const imgdata = `data:image/png;base64,${res.img}`;
setCaptchaCode(imgdata);
setUuid(res.uuid);
}
};

const fetchUserInfo = async () => {
@@ -196,302 +57,134 @@ const Login: React.FC = () => {
}
};

// 登录
const handleSubmit = async (values: API.LoginParams) => {
try {
// 登录
const response = await login({ ...values, uuid });
if (response.code === 200) {
const defaultLoginSuccessMessage = intl.formatMessage({
id: 'pages.login.success',
defaultMessage: '登录成功!',
});
const current = new Date();
const expireTime = current.setTime(current.getTime() + 1000 * 12 * 60 * 60);
setSessionToken(response.data?.access_token, response.data?.access_token, expireTime);
message.success(defaultLoginSuccessMessage);
await fetchUserInfo();
const urlParams = new URL(window.location.href).searchParams;
history.push(urlParams.get('redirect') || '/');
return;
const [response] = await to(login({ ...values, uuid }));
if (response && response.data) {
const current = new Date();
const expireTime = current.setTime(current.getTime() + 1000 * 12 * 60 * 60);
const { access_token } = response.data;
setSessionToken(access_token, access_token, expireTime);
message.success('登录成功!');

localStorage.setItem(rememberPasswordKey, values.autoLogin ? 'true' : 'false');
if (values.autoLogin) {
localStorage.setItem(loginUserKey, values.username ?? '');
localStorage.setItem(loginPasswordKey, values.password ?? '');
} else {
clearSessionToken();
// 如果失败去设置用户错误信息
setUserLoginState({ ...response, type });
getCaptchaCode();
localStorage.removeItem(loginUserKey);
localStorage.removeItem(loginPasswordKey);
}
} catch (error) {

await fetchUserInfo();
const urlParams = new URL(window.location.href).searchParams;
history.push(urlParams.get('redirect') || '/');
} else {
clearSessionToken();
getCaptchaCode();
}
};
const { code } = userLoginState;
const loginType = type;

useEffect(() => {
getCaptchaCode();
}, []);

return (
<div className={containerClassName}>
<div className={containerLeftBox}>
<div className={leftTopBoX}>
<div className={styles['user-login']}>
<div className={styles['user-login__left']}>
<div className={styles['user-login__left__top']}>
<img
src="/assets/images/left-top-logo.png"
style={{ height: '42px', marginRight: '10px' }}
src={require('@/assets/img/logo.png')}
style={{ width: '32px', marginRight: '12px' }}
alt=""
/>
智能材料科研平台
</div>
<div className={centerTitleBoX}>
<span style={{ whiteSpace: 'nowrap' }}>智能材料科研平台</span>

<div className={styles['user-login__left__title']}>
<span>智能材料科研平台</span>
<img
src="/assets/images/ai-logo.png"
style={{ height: '47px', marginTop: '-10px' }}
src={require('@/assets/img/login-ai-logo.png')}
className={styles['user-login__left__title__img']}
alt=""
/>
</div>
<div className={centerMessage}>
<span style={{ whiteSpace: 'nowrap' }}>大语言模型运维 统一管理平台</span>
<div className={styles['user-login__left__message']}>
<span>大语言模型运维 统一管理平台</span>
</div>
<img
src="/assets/images/left-back-logo.png"
style={{
width: '90%',
position: 'absolute',
top: '326px',
left: '50%',
transform: 'translateX(-50%)',
}}
className={styles['user-login__left__bottom-img']}
src={require('@/assets/img/login-left-image.png')}
alt=""
/>
</div>
<div className={containerRightBox}>
<div className={rightTopTitle}>
<span style={{ color: '#111111', fontSize: '36px' }}>hello~</span>
<span style={{ color: '#606b7a', fontSize: '32px', marginLeft: '10px' }}>欢迎登陆</span>
<span style={{ color: '#1664ff', fontSize: '32px' }}>智能材料科研平台</span>
</div>
<div className={containerLoginForm}>
<div
style={{
color: '#1d1d20',
fontSize: '22px',
marginLeft: '30px',
fontFamily: 'Alibaba',
}}
>
账号登录
<div className={styles['user-login__right']}>
<div>
<div className={styles['user-login__right__title']}>
<span style={{ color: '#111111' }}>欢迎登录</span>
<span>智能材料科研平台</span>
</div>
<div className={styles.loginForm}>
<LoginForm
title=""
initialValues={{
autoLogin: true,
}}
// actions={[
// <FormattedMessage
// key="loginWith"
// id="pages.login.loginWith"
// defaultMessage="其他登录方式"
// />,
// <ActionIcons key="icons" />,
// ]}
onFinish={async (values) => {
await handleSubmit(values as API.LoginParams);
}}
>
{code !== 200 && loginType === 'account' && (
<LoginMessage
content={intl.formatMessage({
id: 'pages.login.accountLogin.errorMessage',
defaultMessage: '账户或密码错误(admin/admin123)',
})}
/>
)}
{type === 'account' && (
<>
<ProFormText
name="username"
initialValue="admin"
fieldProps={{
size: 'large',
prefix: <UserOutlined />,
}}
placeholder={intl.formatMessage({
id: 'pages.login.username.placeholder',
defaultMessage: '用户名: admin',
})}
rules={[
{
required: true,
message: (
<FormattedMessage
id="pages.login.username.required"
defaultMessage="请输入用户名!"
/>
),
},
]}
/>
<ProFormText.Password
name="password"
initialValue="admin123"
fieldProps={{
size: 'large',
prefix: <LockOutlined />,
}}
placeholder={intl.formatMessage({
id: 'pages.login.password.placeholder',
defaultMessage: '请输入密码',
})}
rules={[
{
required: true,
message: (
<FormattedMessage
id="pages.login.password.required"
defaultMessage="请输入密码!"
/>
),
},
]}
<div className={styles['user-login__right__content']}>
<div className={styles['user-login__right__content__title']}>账号登录</div>
<div className={styles['user-login__right__content__form']}>
<Form
labelCol={{ span: 0 }}
wrapperCol={{ span: 24 }}
initialValues={{ autoLogin: true }}
onFinish={handleSubmit}
autoComplete="off"
form={form}
>
<Form.Item name="username" rules={[{ required: true, message: '请输入用户名' }]}>
<Input
placeholder="请输入用户名"
prefix={<LoginInputPrefix icon={require('@/assets/img/login-user.png')} />}
allowClear
readOnly={usernameReadOnly}
onFocus={() => setUsernameReadOnly(false)}
/>
<Row>
<Col flex={4}>
<ProFormText
style={{
float: 'right',
}}
name="code"
placeholder={intl.formatMessage({
id: 'pages.login.captcha.placeholder',
defaultMessage: '请输入验证',
})}
rules={[
{
required: true,
message: (
<FormattedMessage
id="pages.login.captcha.placeholder"
defaultMessage="请输入验证啊"
/>
),
},
]}
/>
</Col>
<Col>
<Image
src={captchaCode}
alt="验证码"
style={{
display: 'inline-block',
verticalAlign: 'top',
cursor: 'pointer',
paddingLeft: '22px',
width: '170px',
height: '66px',
}}
preview={false}
onClick={() => getCaptchaCode()}
/>
</Col>
</Row>
</>
)}
</Form.Item>

{code !== 200 && loginType === 'mobile' && <LoginMessage content="验证码错误" />}
{type === 'mobile' && (
<>
<ProFormText
fieldProps={{
size: 'large',
prefix: <MobileOutlined />,
}}
name="mobile"
placeholder={intl.formatMessage({
id: 'pages.login.phoneNumber.placeholder',
defaultMessage: '手机号',
})}
rules={[
{
required: true,
message: (
<FormattedMessage
id="pages.login.phoneNumber.required"
defaultMessage="请输入手机号!"
/>
),
},
{
pattern: /^1\d{10}$/,
message: (
<FormattedMessage
id="pages.login.phoneNumber.invalid"
defaultMessage="手机号格式错误!"
/>
),
},
]}
<Form.Item name="password" rules={[{ required: true, message: '请输入密码' }]}>
<Input.Password
placeholder="请输入密码"
prefix={<LoginInputPrefix icon={require('@/assets/img/login-password.png')} />}
allowClear
/>
<ProFormCaptcha
fieldProps={{
size: 'large',
prefix: <LockOutlined />,
}}
captchaProps={{
size: 'large',
}}
placeholder={intl.formatMessage({
id: 'pages.login.captcha.placeholder',
defaultMessage: '请输入验证码',
})}
captchaTextRender={(timing, count) => {
if (timing) {
return `${count} ${intl.formatMessage({
id: 'pages.getCaptchaSecondText',
defaultMessage: '获取验证码',
})}`;
}
return intl.formatMessage({
id: 'pages.login.phoneLogin.getVerificationCode',
defaultMessage: '获取验证码',
});
}}
name="captcha"
rules={[
{
required: true,
message: (
<FormattedMessage
id="pages.login.captcha.required"
defaultMessage="请输入验证码!"
/>
),
},
]}
onGetCaptcha={async (phone) => {
const result = await getFakeCaptcha({
phone,
});
if (!result) {
return;
}
message.success('获取验证码成功!验证码为:1234');
}}
</Form.Item>

<Flex align="start" style={{ height: '98px' }}>
<div style={{ flex: 1 }}>
<Form.Item name="code" rules={[{ required: true, message: '请输入验证码' }]}>
<Input
placeholder="请输入验证码"
prefix={
<LoginInputPrefix icon={require('@/assets/img/login-captcha.png')} />
}
allowClear
/>
</Form.Item>
</div>
<Image
className={styles['user-login__right__content__form__captcha']}
src={captchaCode}
alt="验证码"
preview={false}
onClick={() => getCaptchaCode()}
/>
</>
)}
<div
style={{
marginBottom: 24,
}}
>
<ProFormCheckbox noStyle name="autoLogin">
<FormattedMessage id="pages.login.rememberMe" defaultMessage="记住密码" />
</ProFormCheckbox>
</div>
</LoginForm>
</Flex>

<Form.Item
name="autoLogin"
valuePropName="checked"
labelCol={{ span: 0 }}
wrapperCol={{ span: 16 }}
>
<Checkbox>记住密码</Checkbox>
</Form.Item>

<Form.Item labelCol={{ span: 0 }} wrapperCol={{ span: 24 }}>
<Button type="primary" htmlType="submit">
登录
</Button>
</Form.Item>
</Form>
</div>
</div>
</div>
</div>


+ 154
- 25
react-ui/src/pages/User/Login/login.less View File

@@ -1,31 +1,160 @@
.loginForm {
:global {
.ant-pro-form-login-main {
width: auto !important;
max-width: auto !important;
margin: unset;
.user-login {
display: flex;
height: 100vh;
background-color: #fff;

&__left {
position: relative;
width: 43%;
height: 100%;
padding-top: 56px;
background: linear-gradient(180deg, #e2ecff 0%, #f6fafe 100%);

&__top {
display: flex;
align-items: center;
margin-left: 50px;
color: @text-color;
font-size: 30px;
font-family: Alibaba;
}
.ant-input-affix-wrapper-lg {
padding: 19px 11px;
color: rgba(29, 29, 32, 0.6);
font-size: 18px;
font-family: 'Alibaba';
border-radius: 13px;

&__title {
position: relative;
display: flex;
justify-content: center;
margin-top: 70px;
margin-left: 85px;
color: #111111;
font-weight: 500;
font-size: 45px;
font-family: Alibaba;

&__img {
position: relative;
top: -10px;
width: 85px;
height: 47px;
}
}
.ant-input-affix-wrapper {
padding: 19px 11px;
color: rgba(29, 29, 32, 0.6);
font-size: 18px;
font-family: 'Alibaba';
border-radius: 13px;

&__message {
display: flex;
justify-content: center;
margin-top: 18px;
color: #606b7a;
font-size: 26px;
font-family: Alibaba;
}
.ant-btn.ant-btn-lg {
height: 76px;
color: #ffffff;
font-size: 20px;
font-family: 'Alibaba';
background: @primary-color;
border-radius: 41px;

&__bottom-img {
width: 100%;
margin-top: 50px;
}
}

&__right {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 57%;
height: 100%;
background: #fff;

&__title {
margin-bottom: 24px;
color: @primary-color;
font-size: 36px;
font-family: Alibaba;
}

&__content {
width: 640px;
padding: 60px 60px 45px;
background-color: white;
border-radius: 10px;
box-shadow: 0px 3px 20px rgba(153, 153, 153, 0.16);

&__title {
margin-bottom: 40px;
color: @text-color;
font-size: 22px;
font-family: Alibaba;
}

&__form {
&__captcha {
width: 170px;
height: 66px;
padding-left: 22px;
cursor: pointer;
}
:global {
.ant-form-item {
margin-bottom: 32px;

&:last-child {
margin-bottom: 0;
}
}
.ant-input-affix-wrapper {
padding: 10px 11px;
color: @text-color;
font-size: 18px !important;
background-color: white;
border: 1px solid #caced8;
border-radius: 13px;

.ant-input {
height: 44px;
font-size: 18px !important;
}
}

.ant-btn {
width: 100%;
height: 76px;
font-size: 20px;
border-radius: 38px;
}
}
}
}
}

input {
font-size: 18px !important;
}

input:-webkit-autofill {
font-size: 18px !important;
transition: background-color 5000s ease-in-out 0s;
-webkit-text-fill-color: @text-color !important;
}

input:-webkit-autofill::first-line {
font-size: 18px !important;
}
}

.login-input-prefix {
display: flex;
align-items: center;
height: 44px;
margin-right: 15px;

&__icon {
width: 24px;
height: 26px;
margin-right: 18px;
margin-left: 14px;
}

&__line {
width: 1px;
height: 30px;
background-color: #caced8;
}
}

+ 6
- 0
react-ui/src/utils/localStorage.ts View File

@@ -0,0 +1,6 @@
// 登录的用户名
export const loginUserKey = 'login-user';
// 登录的密码
export const loginPasswordKey = 'login-password';
// 记住密码
export const rememberPasswordKey = 'login-remember-password';

+ 1
- 1
react-ui/src/utils/ui.tsx View File

@@ -19,7 +19,7 @@ export function modalConfirm({ title, content, onOk, ...rest }: ModalFuncProps)
title: (
<div>
<img
src="/assets/images/delete-icon.png"
src={require('@/assets/img/delete-icon.png')}
style={{ width: '120px', marginBottom: '24px' }}
alt=""
/>


Loading…
Cancel
Save