diff --git a/react-ui/src/pages/User/Login/login.tsx b/react-ui/src/pages/User/Login/login.tsx
new file mode 100644
index 00000000..9ef18148
--- /dev/null
+++ b/react-ui/src/pages/User/Login/login.tsx
@@ -0,0 +1,221 @@
+import { clearSessionToken, setSessionToken } from '@/access';
+import { getCaptchaImg, login } from '@/services/system/auth';
+import { parseJsonText } from '@/utils';
+import { safeInvoke } from '@/utils/functional';
+import LocalStorage from '@/utils/localStorage';
+import { to } from '@/utils/promise';
+import { history, useModel } from '@umijs/max';
+import { Button, Checkbox, Flex, Form, Image, Input, message, type InputRef } from 'antd';
+import CryptoJS from 'crypto-js';
+import { useEffect, useRef, useState } from 'react';
+import { flushSync } from 'react-dom';
+import styles from './login.less';
+
+const VERSION = 1;
+const AESKEY = 'OPENSOURCETECHNOLOGYCENTER';
+
+const LoginInputPrefix = ({ icon }: { icon: string }) => {
+ return (
+
+

+
+
+ );
+};
+
+const Login = () => {
+ const { initialState, setInitialState } = useModel('@@initialState');
+ const [captchaCode, setCaptchaCode] = useState('');
+ const [uuid, setUuid] = useState('');
+ const [form] = Form.useForm();
+ const captchaInputRef = useRef(null);
+
+ useEffect(() => {
+ getCaptchaCode();
+ const autoLogin = LocalStorage.getItem(LocalStorage.rememberPasswordKey) ?? 'false';
+ if (autoLogin === 'true') {
+ const userStorage = LocalStorage.getItem(LocalStorage.loginUserKey);
+ const userJson = safeInvoke((text: string) =>
+ CryptoJS.AES.decrypt(text, AESKEY).toString(CryptoJS.enc.Utf8),
+ )(userStorage);
+ const user = safeInvoke(parseJsonText)(userJson);
+ if (user && typeof user === 'object' && user.version === VERSION) {
+ const { username, password } = user;
+ form.setFieldsValue({ username: username, password: password, autoLogin: true });
+ } else {
+ form.setFieldsValue({ username: '', password: '', autoLogin: true });
+ LocalStorage.removeItem(LocalStorage.loginUserKey);
+ }
+ } else {
+ form.setFieldsValue({ username: '', password: '', autoLogin: false });
+ }
+ }, []);
+ const getCaptchaCode = async () => {
+ const [res] = await to(getCaptchaImg());
+ if (res) {
+ const imgdata = `data:image/png;base64,${res.img}`;
+ setCaptchaCode(imgdata);
+ setUuid(res.uuid);
+ }
+ };
+
+ const fetchUserInfo = async () => {
+ const userInfo = await initialState?.fetchUserInfo?.();
+ if (userInfo) {
+ flushSync(() => {
+ setInitialState((s) => ({
+ ...s,
+ currentUser: userInfo,
+ }));
+ });
+ }
+ };
+
+ // 登录
+ const handleSubmit = async (values: API.LoginParams) => {
+ const [res, error] = await to(login({ ...values, uuid }));
+ if (res && res.data) {
+ const current = new Date();
+ const expireTime = current.setTime(current.getTime() + 1000 * 12 * 60 * 60);
+ const { access_token } = res.data;
+ setSessionToken(access_token, access_token, expireTime);
+ message.success('登录成功!');
+
+ LocalStorage.setItem(LocalStorage.rememberPasswordKey, values.autoLogin ? 'true' : 'false');
+ if (values.autoLogin) {
+ const user = {
+ username: values.username,
+ password: values.password,
+ version: VERSION,
+ };
+ const encrypted = CryptoJS.AES.encrypt(JSON.stringify(user), AESKEY).toString();
+ LocalStorage.setItem(LocalStorage.loginUserKey, encrypted);
+ } else {
+ LocalStorage.removeItem(LocalStorage.loginUserKey);
+ }
+
+ await fetchUserInfo();
+ const urlParams = new URL(window.location.href).searchParams;
+ history.push(urlParams.get('redirect') || '/');
+ } else {
+ if (error?.data?.code === 500 && error?.data?.msg === '验证码错误') {
+ captchaInputRef.current?.focus({
+ cursor: 'all',
+ });
+ }
+
+ clearSessionToken();
+ getCaptchaCode();
+ }
+ };
+
+ return (
+
+
+
+
})
+ 智能材料科研平台
+
+
+
智能材料科研平台
+
})
+
+
+ 大语言模型运维 统一管理平台
+
+
})
+
+
+
+
+ 欢迎登录
+ 智能材料科研平台
+
+
+
账号登录
+
+
+ }
+ allowClear
+ />
+
+
+
+ }
+ allowClear
+ />
+
+
+
+
+
+
+ }
+ ref={captchaInputRef}
+ allowClear
+ />
+
+
+ getCaptchaCode()}
+ />
+
+
+
+ 记住密码
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default Login;