加入了登录注册页面(ptstation-register文件夹),需启动react前端和创建虚拟环境并安装requirements.txt并运行run_server.py
Change-Id: I6abba3854c517286245d118a591e00761ac98685
diff --git a/react-ui/src/locales/zh-CN/pages.ts b/react-ui/src/locales/zh-CN/pages.ts
index fc7abfb..5d13109 100644
--- a/react-ui/src/locales/zh-CN/pages.ts
+++ b/react-ui/src/locales/zh-CN/pages.ts
@@ -1,7 +1,7 @@
export default {
- 'pages.layouts.userLayout.title': 'Ant Design 是西湖区最具影响力的 Web 设计规范',
+ 'pages.layouts.userLayout.title': 'Welcome!',
'pages.login.accountLogin.tab': '账户密码登录',
- 'pages.login.accountLogin.errorMessage': '错误的用户名和密码(admin/admin123)',
+ 'pages.login.accountLogin.errorMessage': '错误的用户名和密码',
'pages.login.failure': '登录失败,请重试!',
'pages.login.success': '登录成功!',
'pages.login.username.placeholder': '用户名: admin',
diff --git a/react-ui/src/pages/User/Login/index.tsx b/react-ui/src/pages/User/Login/index.tsx
index a18f785..87759c3 100644
--- a/react-ui/src/pages/User/Login/index.tsx
+++ b/react-ui/src/pages/User/Login/index.tsx
@@ -1,6 +1,8 @@
import Footer from '@/components/Footer';
import { getCaptchaImg, login } from '@/services/system/auth';
import { getFakeCaptcha } from '@/services/ant-design-pro/login';
+import { Modal, Form, Input, Button } from 'antd';
+
import {
AlipayCircleOutlined,
LockOutlined,
@@ -90,6 +92,8 @@
const { initialState, setInitialState } = useModel('@@initialState');
const [captchaCode, setCaptchaCode] = useState<string>('');
const [uuid, setUuid] = useState<string>('');
+const [forgotModalVisible, setForgotModalVisible] = useState(false);
+const [form] = Form.useForm();
const containerClassName = useEmotionCss(() => {
return {
@@ -190,50 +194,37 @@
maxWidth: '75vw',
}}
logo={<img alt="logo" src="/logo.svg" />}
- title="Ant Design"
+ title="PT Station"
subTitle={intl.formatMessage({ id: 'pages.layouts.userLayout.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);
}}
- >
- <Tabs
- activeKey={type}
- onChange={setType}
- centered
- items={[
- {
- key: 'account',
- label: intl.formatMessage({
- id: 'pages.login.accountLogin.tab',
- defaultMessage: '账户密码登录',
- }),
- },
- {
- key: 'mobile',
- label: intl.formatMessage({
- id: 'pages.login.phoneLogin.tab',
- defaultMessage: '手机号登录',
- }),
- },
- ]}
- />
+ ><Tabs
+ activeKey={type}
+ onChange={setType}
+ centered
+ items={[
+ {
+ key: 'account',
+ label: intl.formatMessage({
+ id: 'pages.login.accountLogin.tab',
+ defaultMessage: '账户密码登录',
+ }),
+ },
+ ]}
+/>
{code !== 200 && loginType === 'account' && (
<LoginMessage
content={intl.formatMessage({
id: 'pages.login.accountLogin.errorMessage',
- defaultMessage: '账户或密码错误(admin/admin123)',
+ defaultMessage: '账户或密码错误',
})}
/>
)}
@@ -302,7 +293,7 @@
message: (
<FormattedMessage
id="pages.searchTable.updateForm.ruleName.nameRules"
- defaultMessage="请输入验证啊"
+ defaultMessage="请输入验证"
/>
),
},
@@ -418,18 +409,134 @@
<ProFormCheckbox noStyle name="autoLogin">
<FormattedMessage id="pages.login.rememberMe" defaultMessage="自动登录" />
</ProFormCheckbox>
- <a
- style={{
- float: 'right',
- }}
- >
- <FormattedMessage id="pages.login.forgotPassword" defaultMessage="忘记密码" />
- </a>
+ <a
+ style={{ float: 'right' }}
+ onClick={() => setForgotModalVisible(true)}
+ >
+ <FormattedMessage id="pages.login.forgotPassword" defaultMessage="忘记密码?" />
+ </a>
+
</div>
</LoginForm>
+<div style={{ textAlign: 'center', marginTop: 16 }}>
+ <span style={{ marginRight: 8 }}>
+ <FormattedMessage id="pages.login.noAccount" defaultMessage="没有账号?" />
+ </span>
+ <a href="http://localhost:5173/" target="_self">
+ <FormattedMessage id="pages.login.registerNow" defaultMessage="立即注册" />
+ </a>
+</div>
+
+
</div>
+
+
+ <Modal
+ title="重置密码"
+ open={forgotModalVisible}
+ onCancel={() => setForgotModalVisible(false)}
+ footer={null}
+>
+<Form
+ form={form}
+ onFinish={async (values) => {
+ const { email, code, newPassword, confirmPassword } = values;
+
+ if (newPassword !== confirmPassword) {
+ message.error('两次密码输入不一致');
+ return;
+ }
+
+ const res = await fetch('http://127.0.0.1:6001/reset-password', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+
+ body: JSON.stringify({ email, code, newPassword }),
+ });
+ const data = await res.json();
+
+ if (data.success) {
+ message.success('密码重置成功');
+ setForgotModalVisible(false);
+ form.resetFields();
+ } else {
+ message.error(data.message || '重置失败');
+ }
+ }}
+>
+ <Form.Item name="email" rules={[{ required: true, message: '请输入邮箱' }, { type: 'email' }]}>
+ <Input placeholder="邮箱" />
+ </Form.Item>
+
+ <Form.Item name="code" rules={[{ required: true, message: '请输入验证码' }]}>
+ <Input
+ placeholder="验证码"
+ addonAfter={
+ <a
+ onClick={async () => {
+ const email = form.getFieldValue('email');
+ if (!email) return message.warning('请先输入邮箱');
+ const res = await fetch('http://127.0.0.1:6001/send-code', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ email }),
+ });
+ const result = await res.json();
+ if (result.success) {
+ message.success('验证码发送成功');
+ } else {
+ message.error(result.message || '验证码发送失败');
+ }
+ }}
+ >
+ 获取验证码
+ </a>
+ }
+ />
+ </Form.Item>
+
+ <Form.Item
+ name="newPassword"
+ rules={[{ required: true, message: '请输入新密码' }]}
+ hasFeedback
+ >
+ <Input.Password placeholder="新密码" />
+ </Form.Item>
+
+ <Form.Item
+ name="confirmPassword"
+ dependencies={['newPassword']}
+ hasFeedback
+ rules={[
+ { required: true, message: '请确认新密码' },
+ ({ getFieldValue }) => ({
+ validator(_, value) {
+ if (!value || getFieldValue('newPassword') === value) {
+ return Promise.resolve();
+ }
+ return Promise.reject(new Error('两次密码输入不一致'));
+ },
+ }),
+ ]}
+ >
+ <Input.Password placeholder="确认密码" />
+ </Form.Item>
+
+ <Form.Item>
+ <Button type="primary" htmlType="submit" block>
+ 重置密码
+ </Button>
+ </Form.Item>
+</Form>
+
+</Modal>
+
<Footer />
</div>
+
+
+
+
);
};