Skip to content

Commit

Permalink
feat: 开发邮箱注册功能
Browse files Browse the repository at this point in the history
  • Loading branch information
JackySoft committed Aug 24, 2024
1 parent 6fff16e commit cdff0d7
Show file tree
Hide file tree
Showing 6 changed files with 138 additions and 61 deletions.
30 changes: 4 additions & 26 deletions packages/editor/src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,6 @@ import {
Menu,
Role,
} from './types';
// 用户登录
export const login = async <T>(params: T) => {
return request.post('/user/login', params, { showLoading: false });
};

// 获取用户信息
export const getUserInfo = async () => {
return request.get('/user/info', {}, { showLoading: false });
};

// 获取用户头像
export const getUserAvatar = () => {
// TODO 等后续接入微信扫码后生成用户头像
return Promise.resolve({
avatar: '',
});
};

// 获取页面列表
export const getPageList = (params: PageParams) => {
Expand Down Expand Up @@ -81,11 +64,6 @@ export const rollbackPage = (params: { page_id: number; env: string; last_publis
return request.post('/page/rollback', params);
};

// 搜索用户
export const searchUser = (keyword: string) => {
return request.post(`/user/search`, { keyword }, { showLoading: false });
};

// 获取项目列表
export const getProjectList = (params: ProjectListParams) => {
return request.get('/project/list', params, { showLoading: false });
Expand Down Expand Up @@ -136,22 +114,22 @@ export const copyMenu = (params: { id: number }) => {
return request.post('/menu/copy', params, { showLoading: false });
};

// 获取用户列表
// 获取项目配置的用户列表
export const getUserList = (params: UserListParams) => {
return request.get('/project/user/list', params, { showLoading: false });
};

// 新增用户
// 新增项目用户
export const addUser = (params: UserCreateParams) => {
return request.post('/project/user/create', params, { showLoading: false });
};

// 删除用户
// 删除项目用户
export const delUser = (params: { id: number }) => {
return request.post('/project/user/delete', params, { showLoading: false });
};

// 更新用户
// 更新项目用户
export const updateUser = (params: { id: number; system_role: number; role_id: number }) => {
return request.post('/project/user/update', params, { showLoading: false });
};
Expand Down
34 changes: 34 additions & 0 deletions packages/editor/src/api/user.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import request from '@/utils/request';

// 用户登录
export const login = async <T>(params: T) => {
return request.post('/user/login', params, { showLoading: false });
};

// 发送验证码
export const sendEmail = async (params: { email: string }) => {
return request.post('/user/sendEmail', params, { showLoading: false });
};

// 邮箱注册
export const regist = async (params: { userName: string; code?: number; userPwd: string }) => {
return request.post('/user/regist', params, { showLoading: false });
};

// 获取用户信息
export const getUserInfo = async () => {
return request.get('/user/info', {}, { showLoading: false });
};

// 获取用户头像
export const getUserAvatar = () => {
// TODO 等后续接入微信扫码后生成用户头像
return Promise.resolve({
avatar: '',
});
};

// 搜索用户
export const searchUser = (keyword: string) => {
return request.post(`/user/search`, { keyword }, { showLoading: false });
};
11 changes: 1 addition & 10 deletions packages/editor/src/layout/components/Header/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,14 @@ import { useLocation, useNavigate, useParams } from 'react-router-dom';
import { toBlob } from 'html-to-image';
import { usePageStore } from '@/stores/pageStore';
import { message } from '@/utils/AntdGlobal';
import { getUserAvatar, updatePageData, uploadImg } from '@/api';
import { updatePageData, uploadImg } from '@/api';
import Publish from './PublishPopover';
import styles from './index.module.less';

/**
* 编辑器顶部组件
*/
const Header = memo(() => {
const [avatar, setAvatar] = useState('');
const [isNav, setNav] = useState(false);
const [loading, setLoading] = useState(false);
const [navKey, setNavKey] = useState(['projects']);
Expand Down Expand Up @@ -60,12 +59,6 @@ const Header = memo(() => {
},
];

useEffect(() => {
getUserAvatar().then((res) => {
setAvatar(res.avatar);
});
}, []);

useEffect(() => {
if (['/projects', '/pages', '/libs'].includes(location.pathname)) {
setNav(true);
Expand Down Expand Up @@ -271,8 +264,6 @@ const Header = memo(() => {

{/* 用户头像 */}
<div className={styles.avatar}>
{avatar ? <img width={30} src={avatar} style={{ borderRadius: '50%' }} /> : null}

<Dropdown
menu={{
items: [
Expand Down
4 changes: 2 additions & 2 deletions packages/editor/src/pages/admin/user/CreateUser.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import { useDebounceFn } from 'ahooks';
import { message } from '@/utils/AntdGlobal';
import { IAction, IModalProp } from '@/pages/types';
import { UserItem } from '@/api/types';
import { searchUser, addUser, updateUser, getRoleListAll } from '@/api';

import { addUser, updateUser, getRoleListAll } from '@/api';
import { searchUser } from '@/api/user';
export default function CreateMenu(props: IModalProp<UserItem>) {
const [form] = Form.useForm();
const [action, setAction] = useState<IAction>('create');
Expand Down
118 changes: 96 additions & 22 deletions packages/editor/src/pages/login/Login.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,77 @@
import { useEffect, useState } from 'react';
import type { FormProps } from 'antd';
import { Button, Form, Input } from 'antd';
import { Button, Form, Input, InputNumber, Space } from 'antd';
import { useNavigate } from 'react-router-dom';
import { login } from '@/api';
import { login, sendEmail, regist } from '@/api/user';
import storage from '@/utils/storage';
import { usePageStore } from '@/stores/pageStore';
import { LockOutlined, UserOutlined } from '@ant-design/icons';
import { LockOutlined, SafetyOutlined, UserOutlined } from '@ant-design/icons';
import style from './index.module.less';
type FieldType = {
userName: string;
code?: number;
userPwd: string;
};
export default function Login() {
const [type, setType] = useState('login');
const [count, setCount] = useState(0);
const [loading1, setLoading1] = useState(false);
const [loading2, setLoading2] = useState(false);
const navigate = useNavigate();
const [form] = Form.useForm();
const saveUserInfo = usePageStore((state) => state.saveUserInfo);

// 类型切换
const onChange = () => {
setType(type == 'login' ? 'regist' : 'login');
};

// 生成验证码
const handleCreateCode = () => {
form.validateFields(['userName']).then(async ({ userName }) => {
setLoading1(true);
try {
await sendEmail({ email: userName });
setCount(60);
setLoading1(false);
} catch (error) {
setLoading1(false);
}
});
};

useEffect(() => {
const timer = setTimeout(() => {
if (count > 0) {
setCount(count - 1);
}
}, 1000);

// 清理函数
return () => clearTimeout(timer);
}, [count]);

// 登录或注册
const onFinish: FormProps<FieldType>['onFinish'] = async (values: FieldType) => {
const res = await login<FieldType>(values);
if (res.token) {
storage.set('token', res.token);
saveUserInfo(res);
if (location.search) {
const params = new URLSearchParams(location.search);
setTimeout(() => {
const url = new URL(params.get('callback') as string);
navigate(url.pathname || '/projects');
});
} else {
navigate('/projects');
setLoading2(true);
try {
const res = type === 'login' ? await login<FieldType>(values) : await regist(values);
setLoading2(false);
if (res.token) {
storage.set('token', res.token);
saveUserInfo(res);
if (location.search) {
const params = new URLSearchParams(location.search);
setTimeout(() => {
const url = new URL(params.get('callback') as string);
navigate(url.pathname || '/projects');
});
} else {
navigate('/projects');
}
}
} catch (error) {
setLoading2(false);
}
};
return (
Expand All @@ -36,10 +81,14 @@ export default function Login() {
<img src="/imgs/login-bg.png" />
</div>
<div className={style.form}>
<div className={style.title}>
<img src="/imgs/mars-logo.png" width={45} />
<span>Marsview</span>
</div>
{type === 'login' ? (
<div className={style.title}>
<img src="/imgs/mars-logo.png" width={45} />
<span>Marsview</span>
</div>
) : (
<div className={style.title}>账号注册</div>
)}
<Form
name="basic"
layout="vertical"
Expand All @@ -48,20 +97,45 @@ export default function Login() {
initialValues={{ userName: '[email protected]', userPwd: 'marsview' }}
autoComplete="off"
size="large"
form={form}
>
<Form.Item<FieldType> name="userName" rules={[{ required: true, message: '请输入邮箱' }]}>
<Input prefix={<UserOutlined />} />
<Form.Item<FieldType>
name="userName"
rules={[
{ required: true, message: '请输入邮箱' },
{ pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/, message: '请输入正确的邮箱' },
]}
>
<Input prefix={<UserOutlined />} placeholder="请输入个人邮箱" />
</Form.Item>

{type === 'regist' && (
<Form.Item>
<Space>
<Form.Item<FieldType> name="code" noStyle rules={[{ required: true, message: '请输入验证码' }]}>
<InputNumber prefix={<SafetyOutlined />} style={{ width: '100%' }} placeholder="验证码" />
</Form.Item>
<Button type="primary" onClick={handleCreateCode} disabled={count > 0} loading={loading1}>
{count > 0 ? count + 's' : '获取验证码'}
</Button>
</Space>
</Form.Item>
)}

<Form.Item<FieldType> style={{ marginTop: 32 }} name="userPwd" rules={[{ required: true, message: '请输入密码' }]}>
<Input.Password prefix={<LockOutlined />} />
</Form.Item>

<Form.Item style={{ marginTop: 40 }}>
<Button type="primary" block htmlType="submit">
<Button type="primary" block htmlType="submit" loading={loading2}>
登录
</Button>
</Form.Item>
<Form.Item style={{ marginTop: 40 }}>
<div style={{ textAlign: 'center' }}>
<a onClick={onChange}>{type === 'login' ? '没有账号?去注册' : '已有账号?去登录'}</a>
</div>
</Form.Item>
</Form>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion packages/editor/src/router/AuthLoader.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getUserInfo } from '@/api';
import { getUserInfo } from '@/api/user';
import storage from '@/utils/storage';
/**
* 加载用户信息,生成token
Expand Down

0 comments on commit cdff0d7

Please sign in to comment.