Merge pull request '登陆注册功能' (#250) from durian/forgeplus-react:featrue_login_and_register into featrue_login_and_register
27
src/App.js
|
@ -97,13 +97,17 @@ const ProjectIndex = Loadable({
|
|||
loading: Loading,
|
||||
});
|
||||
|
||||
const LoginRegisterPage = Loadable({
|
||||
loader: () => import("./modules/loginRegister/LoginRegisterPage"),
|
||||
loading: Loading,
|
||||
});
|
||||
// const CreateMerge = Loadable({
|
||||
// loader: () => import('./forge/Merge/NewMerge'),
|
||||
// loading: Loading,
|
||||
// })
|
||||
|
||||
// 此处仅维护前端可能的一级路由,不用进行项目或者组织判断的字段。
|
||||
const keyWord = ["explore", "settings", "setting", "mulan", "wiki", "issues", "setting", "trending", "code", "projects", "pulls", "mine", "login", "register", "email", "export", "nopage", "404", "403", "500", "501", "search", "organize"];
|
||||
const keyWord = ["explore", "settings", "setting", "mulan", "wiki", "issues", "setting", "trending", "code", "projects", "pulls", "mine", "login", "register", "email", "export", "nopage", "404", "403", "500", "501", "search", "organize","login","register","resetPassword"];
|
||||
|
||||
class App extends Component {
|
||||
constructor(props) {
|
||||
|
@ -303,14 +307,14 @@ class App extends Component {
|
|||
}>
|
||||
</Route>
|
||||
|
||||
<Route
|
||||
{/* <Route
|
||||
path="/register"
|
||||
render={
|
||||
(props) => {
|
||||
return (<EducoderLogin {...this.props} {...props} {...this.state} />)
|
||||
}
|
||||
}
|
||||
/>
|
||||
/> */}
|
||||
{/*403*/}
|
||||
<Route path="/403" component={Shixunauthority} />
|
||||
|
||||
|
@ -330,7 +334,24 @@ class App extends Component {
|
|||
}
|
||||
/>
|
||||
|
||||
{/* 登录 */}
|
||||
<Route
|
||||
path="/login"
|
||||
render={(props) =><LoginRegisterPage {...this.props} {...props}/>}
|
||||
></Route>
|
||||
|
||||
{/* 注册 */}
|
||||
<Route
|
||||
path="/register"
|
||||
render={(props) =><LoginRegisterPage {...this.props} {...props}/>}
|
||||
></Route>
|
||||
|
||||
{/* 忘记密码 */}
|
||||
<Route
|
||||
path="/resetPassword"
|
||||
render={(props) =><LoginRegisterPage {...this.props} {...props}/>}
|
||||
></Route>
|
||||
|
||||
{/* 组织 */}
|
||||
<Route path={"/organize"}
|
||||
render={
|
||||
|
|
|
@ -68,6 +68,8 @@ export function initAxiosInterceptors(props) {
|
|||
if (response.data.status === -1) {
|
||||
if (window.location.pathname.startsWith('/tasks/')) {
|
||||
props.showSnackbar(response.data.message || '服务器异常,请联系管理员。')
|
||||
} else if(window.location.pathname.startsWith('/login') || window.location.pathname.startsWith('/register') || window.location.pathname.startsWith('/resetPassword')) {
|
||||
return response;
|
||||
} else {
|
||||
notification.open({
|
||||
message: "提示",
|
||||
|
|
|
@ -2,6 +2,7 @@ import React, { Component } from 'react';
|
|||
import AccountProfile from "../../modules/user/AccountProfile";
|
||||
import { getImageUrl } from 'educoder'
|
||||
import axios from 'axios';
|
||||
import cookie from 'react-cookies';
|
||||
import { Input , notification , Dropdown ,Popover, Menu,Badge, Button } from 'antd';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
|
@ -98,11 +99,17 @@ class NewHeader extends Component {
|
|||
|
||||
educoderlogin = () => {
|
||||
//登录账号
|
||||
this.setState({
|
||||
isRender: true
|
||||
})
|
||||
if(window.location.pathname === "/"){
|
||||
window.location.href="/login";
|
||||
}else{
|
||||
this.setState({
|
||||
isRender: true
|
||||
})
|
||||
}
|
||||
}
|
||||
educoderloginysl = () => {
|
||||
//退出账号时清除登录页面的下次自动登录(用户再次打开登录页面时下次自动登录框不勾选)
|
||||
cookie.remove("autologin");
|
||||
//退出账号
|
||||
var url = `/accounts/logout.json`;
|
||||
axios.get((url)).then((result) => {
|
||||
|
@ -460,7 +467,7 @@ class NewHeader extends Component {
|
|||
<a onClick={() => this.educoderlogin()} className="mr5 color-grey-6">登录</a>
|
||||
{
|
||||
settings && settings.common && settings.common.register &&
|
||||
<span><em className="vertical-line"></em><a className="ml5 color-grey-6" href={`${settings.common.register}`} target="_blank">注册</a></span>
|
||||
<span><em className="vertical-line"></em><Link className="ml5 color-grey-6" to={`/register`}>注册</Link></span>
|
||||
}
|
||||
</span>
|
||||
:
|
||||
|
|
|
@ -376,7 +376,7 @@ class LoginDialog extends Component {
|
|||
const messge = (
|
||||
<div>
|
||||
<p>登录密码出错已达上限,账号已被锁定;</p>
|
||||
<p className="mt10">请10分钟后重新登录或<a href={'https://www.trustie.net/account/lost_password'} style={{textDecoration: "underline",color: "#4CACFF"}}>找回密码</a></p>
|
||||
<p className="mt10">请10分钟后重新登录或<a href="/resetPassword" style={{textDecoration: "underline",color: "#4CACFF"}}>找回密码</a></p>
|
||||
</div>
|
||||
)
|
||||
this.openNotifications(messge);
|
||||
|
@ -414,7 +414,6 @@ class LoginDialog extends Component {
|
|||
let { disabled } = this.state;
|
||||
if (disabled === false && e.keyCode === 13) {
|
||||
this.loginEDU()
|
||||
console.log(1)
|
||||
}
|
||||
};
|
||||
getloginurl = (url) => {
|
||||
|
@ -516,7 +515,7 @@ class LoginDialog extends Component {
|
|||
}
|
||||
value={this.state.loginValue}
|
||||
name="username"
|
||||
placeholder="请输入有效的手机号/邮箱号" ></input>
|
||||
placeholder="请输入邮箱地址/用户名" ></input>
|
||||
|
||||
<div style={{ height: '25px' }}><p className="color-orange edu-txt-left none" id="username_error_notice"
|
||||
style={{ display: Phonenumberisnotco === undefined ? 'none' : 'block' }}>{Phonenumberisnotco}</p></div>
|
||||
|
@ -533,7 +532,7 @@ class LoginDialog extends Component {
|
|||
this.loginEDU : () => {
|
||||
}
|
||||
}
|
||||
placeholder="密码"
|
||||
placeholder="请输入登录密码"
|
||||
/>
|
||||
<div style={{ height: '25px' }}>
|
||||
<p className="color-orange edu-txt-left none" id="password_error_notice">
|
||||
|
@ -560,9 +559,9 @@ class LoginDialog extends Component {
|
|||
<label htmlFor="p_autolog" style={{ top: '0px' }}>下次自动登录</label>
|
||||
</span>
|
||||
<span className="fr">
|
||||
<a onClick={(url) => this.getloginurl(`${settings && settings.common && settings.common.lost_password}`)} className="mr3 color-grey-9">找回密码</a>
|
||||
<a href="/resetPassword" className="mr3 color-grey-9">找回密码</a>
|
||||
<em className="vertical-line"></em>
|
||||
<a onClick={(url) => this.getloginurl(`${settings && settings.common && settings.common.register}`)} className="color-grey-9">注册</a>
|
||||
<a href="/register" className="color-grey-9">注册</a>
|
||||
</span>
|
||||
</p>
|
||||
{
|
||||
|
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 5.7 KiB |
|
@ -0,0 +1,131 @@
|
|||
import React, { useEffect, useState } from "react";
|
||||
import { Form, Input, Button, Checkbox } from "antd";
|
||||
import { Link } from "react-router-dom";
|
||||
import axios from 'axios';
|
||||
import educoderLogo from '../login/educoder.png';
|
||||
import cookie from 'react-cookies';
|
||||
import './LoginRegisterPage.scss';
|
||||
|
||||
function Login(props){
|
||||
const [message,setMessage] = useState();
|
||||
const [setting, setSetting] = useState(undefined);
|
||||
const {form} = props;
|
||||
const {getFieldDecorator } = form;
|
||||
|
||||
useEffect(()=>{
|
||||
//控制密码输入框在DOM不可见value
|
||||
clear;
|
||||
//请求settings.json接口获取第三方登录平台信息
|
||||
axios.get(`/setting.json`).then((response) => {
|
||||
if (response && response.data) {
|
||||
setSetting(response.data.setting);
|
||||
}
|
||||
})
|
||||
},[])
|
||||
|
||||
// 登录表单提交
|
||||
function handleSubmit(){
|
||||
form.validateFields((err, values) => {
|
||||
if (!err) {
|
||||
axios.post(`/accounts/login.json`, {
|
||||
login: values.username,
|
||||
password: values.password,
|
||||
autologin: values.remember?1:0,
|
||||
}).then((response) => {
|
||||
if (!response.data.login) {
|
||||
response.data.status === -2 ? setMessage(response.data.message) : setMessage("错误的账号或密码");
|
||||
} else {
|
||||
//判断用户是否选择【下次自动登录】
|
||||
cookie.save('autologin',values.remember);
|
||||
window.location.href = "/"+response.data.login;
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.log('error',error);
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//校验用户名
|
||||
function comfirmWrite(rule, value, callback, index){
|
||||
setMessage(undefined);
|
||||
value ? callback():index === 1? callback("请输入邮箱地址或用户名登录"):callback("请输入登录密码");
|
||||
}
|
||||
|
||||
//清除密码框的value属性->DOM看不见密码值
|
||||
function clear(){
|
||||
const password = document.getElementById("login_password");
|
||||
if(password && password.type==="password"){
|
||||
setTimeout(()=>{
|
||||
password.removeAttribute('value');
|
||||
},0)
|
||||
}
|
||||
}
|
||||
|
||||
return(
|
||||
<div>
|
||||
<div className="right_cont login_content">
|
||||
<div className="login_register_head">
|
||||
<span>欢迎登录 GitLink</span>
|
||||
<span className="link_span">没有账号?<Link to={`/register`}>去注册</Link></span>
|
||||
</div>
|
||||
<p className = {message?"message active":"message"}>{message}</p>
|
||||
<Form className="login-form">
|
||||
<Form.Item>
|
||||
{getFieldDecorator('username',{
|
||||
rules:[
|
||||
{
|
||||
validator: (rule, value, callback) => { comfirmWrite(rule, value, callback, 1) }
|
||||
}
|
||||
],
|
||||
validateTrigger:"onBlur",
|
||||
})(<Input className="account" placeholder="请输入邮箱地址/用户名"/>)}
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item>
|
||||
{getFieldDecorator('password', {
|
||||
rules: [
|
||||
{
|
||||
validator: (rule, value, callback) => { comfirmWrite(rule, value, callback, 2) }
|
||||
}
|
||||
],
|
||||
validateTrigger:"onBlur",
|
||||
})(
|
||||
<Input.Password className="psd" placeholder="请输入登录密码" onBlur={clear} onChange={clear}/>,
|
||||
)}
|
||||
</Form.Item>
|
||||
|
||||
<div className="login_register_head">
|
||||
<Form.Item>
|
||||
{getFieldDecorator('remember', {
|
||||
valuePropName: 'checked',
|
||||
initialValue: cookie.load('autologin'),
|
||||
})(<Checkbox>下次自动登录</Checkbox>)}
|
||||
</Form.Item>
|
||||
<Link to="/resetPassword" className="goResetPsdBut">忘记密码?</Link>
|
||||
</div>
|
||||
<Button type="primary" htmlType="submit" onClick={handleSubmit} className="login_register_cofBut">登录</Button>
|
||||
</Form>
|
||||
|
||||
{
|
||||
setting && setting.third_party && setting.third_party.length > 0 ?
|
||||
<p className="quick_logon">
|
||||
<p className="quick_logon_p"></p>
|
||||
<span className={"startlogin"}> 快速登录 </span>
|
||||
{setting.third_party.map((item,key)=>{
|
||||
return(
|
||||
<a href={`${item.url}`}>
|
||||
<img src={item.name === "educoder" ? educoderLogo : ""} width="46px" alt={`${item.name}登录`} />
|
||||
</a>
|
||||
)
|
||||
})
|
||||
}
|
||||
</p>
|
||||
:""
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
}
|
||||
export default Form.create({ name: 'login' })(Login);
|
|
@ -0,0 +1,28 @@
|
|||
import React from "react";
|
||||
import Login from "./Login";
|
||||
import Register from "./Register";
|
||||
import ResetPassword from "./ResetPassword";
|
||||
import logo from './img/logo.png';
|
||||
import banner from './img/banner.png';
|
||||
import ball from './img/ball.png';
|
||||
import img1 from './img/img1.png';
|
||||
import img2 from './img/img2.png';
|
||||
import '../loginRegister/LoginRegisterPage.scss';
|
||||
|
||||
function LoginRegisterPage(props){
|
||||
return(
|
||||
<div className="login_register">
|
||||
<div className="login_register_left">
|
||||
<img src={logo} className="logo"></img>
|
||||
<img src={ball} className="ball"></img>
|
||||
<img src={banner} className="banner"></img>
|
||||
</div>
|
||||
<div className="login_register_right">
|
||||
{props.location.pathname === "/login" ? <Login {...props}/> : props.location.pathname === "/register" ? <Register/> : <ResetPassword/>}
|
||||
<img src={img1} className="img1"></img>
|
||||
<img src={img2} className="img2"></img>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default LoginRegisterPage;
|
|
@ -0,0 +1,237 @@
|
|||
.login_register{
|
||||
height: 100%;
|
||||
}
|
||||
.login_register_left,.login_register_right,.right_cont{
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
}
|
||||
.login_register_left{
|
||||
display: flex;
|
||||
position: absolute;
|
||||
justify-content: center;
|
||||
width: 30%;
|
||||
height: 100%;
|
||||
background-image: url(./img/bg.png);
|
||||
.logo{
|
||||
height: 65px;
|
||||
margin-top: 160px;
|
||||
}
|
||||
.ball{
|
||||
height: 220px;
|
||||
z-index: 3;
|
||||
position: absolute;
|
||||
bottom: 270px;
|
||||
animation: moving2 10s linear infinite;
|
||||
}
|
||||
@keyframes moving2 {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
50% {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
.banner{
|
||||
height: 486px;
|
||||
position: absolute;
|
||||
bottom: -90px;
|
||||
left: 10px;
|
||||
}
|
||||
}
|
||||
.login_register_right{
|
||||
background-image: url(./img/rightBg.png);
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 30%;
|
||||
right: 0;
|
||||
height: 100%;
|
||||
.img1{
|
||||
position: relative;
|
||||
left: 130px;
|
||||
top: 50%;
|
||||
}
|
||||
.img2{
|
||||
position: relative;
|
||||
top: 65%;
|
||||
left: 550px;
|
||||
}
|
||||
.right_cont{
|
||||
width: 37.5rem;
|
||||
position: absolute;
|
||||
top: 15%;
|
||||
left: 16%;
|
||||
z-index: 3;
|
||||
border-radius: 7px;
|
||||
background-color: white;
|
||||
padding: 55px 90px;
|
||||
& .register_tips{
|
||||
margin-top: -15px;
|
||||
padding-bottom: 8px;
|
||||
color: #808080;
|
||||
font-size: 13px;
|
||||
}
|
||||
& .login_register_head{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
&>span:first-child{
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
color: #000000;
|
||||
line-height: 33px;
|
||||
}
|
||||
& .ant-input{
|
||||
width: 19rem;
|
||||
}
|
||||
}
|
||||
& .account{
|
||||
margin-top: 36px;
|
||||
}
|
||||
& .login_register_cofBut{
|
||||
width: 100%;
|
||||
height: 44px;
|
||||
background: #466AFF;
|
||||
border-color: #466AFF;
|
||||
border-radius: 7px;
|
||||
margin-top: 20px;
|
||||
font-size: 15px;
|
||||
&:hover{
|
||||
background: #3456E5;
|
||||
border-color: #3456E5;
|
||||
}
|
||||
}
|
||||
& a{
|
||||
color: #466AFF;
|
||||
&:hover{
|
||||
opacity:0.8;
|
||||
}
|
||||
}
|
||||
& .link_span{
|
||||
font-weight: 500;
|
||||
font-size: 15px;
|
||||
color: #808080;
|
||||
}
|
||||
& .ant-input{
|
||||
height: 44px;
|
||||
background-color: #F7F7F7 !important;
|
||||
font-size: 15px;
|
||||
color: #333333;
|
||||
&:hover{
|
||||
border-color:#466AFF;
|
||||
}
|
||||
}
|
||||
& .has-success .ant-input{
|
||||
background-color: #F7F7F7;
|
||||
}
|
||||
& .ant-form-explain{
|
||||
margin-top: 5px;
|
||||
}
|
||||
& .message, .ant-form-explain{
|
||||
color: #D40000;
|
||||
font-size: 13px;
|
||||
}
|
||||
& .message.active{
|
||||
margin-bottom: -30px !important;
|
||||
margin-top: 10px;
|
||||
}
|
||||
//取消antd表单默认样式
|
||||
.has-error .ant-input{
|
||||
background: #F7F7F7;
|
||||
border-color: #D40000;
|
||||
}
|
||||
//修改复选框默认antd样式
|
||||
.ant-checkbox-checked .ant-checkbox-inner {
|
||||
background-color: #466AFF;
|
||||
border: #466AFF;
|
||||
}
|
||||
|
||||
.ant-checkbox-checked::after{
|
||||
border: 1px solid #466AFF;
|
||||
}
|
||||
.ant-checkbox-wrapper:hover .ant-checkbox-inner, .ant-checkbox:hover .ant-checkbox-inner, .ant-checkbox-input:focus + .ant-checkbox-inner,.ant-radio-checked .ant-radio-inner,.ant-radio-wrapper:hover .ant-radio, .ant-radio:hover .ant-radio-inner, .ant-radio-input:focus + .ant-radio-inner {
|
||||
border-color: #466AFF;
|
||||
}
|
||||
}
|
||||
.login_content{
|
||||
background-image: url(./img/loginBg.png);
|
||||
height: 480px;
|
||||
& .login_register_cofBut{
|
||||
margin-top: 0;
|
||||
}
|
||||
& .login_register_head{
|
||||
& checkbox{
|
||||
font-size: 15px;
|
||||
color: #3C476E;
|
||||
line-height: 21px;
|
||||
}
|
||||
& .goResetPsdBut{
|
||||
margin-top: -25px;
|
||||
}
|
||||
}
|
||||
& .quick_logon{
|
||||
text-align: center;
|
||||
& .quick_logon_p{
|
||||
border-top: 1px solid #979797;
|
||||
margin-top: 24px;
|
||||
}
|
||||
& .startlogin{
|
||||
position: relative;
|
||||
background: #dfe0f7;
|
||||
display: block;
|
||||
width: 90px;
|
||||
top: -15px;
|
||||
left: 39%;
|
||||
font-size: 13px;
|
||||
color: #8D8D8D;
|
||||
}
|
||||
}
|
||||
}
|
||||
.Register_content{
|
||||
background-image: url(./img/registerBg.png);
|
||||
& .register_last_form .ant-form-item-control{
|
||||
line-height: 0.5;
|
||||
}
|
||||
}
|
||||
.ResetPassword_content{
|
||||
background-image: url(./img/resetPasswordBg.png);
|
||||
height: 550px;
|
||||
& .resetFailCaptcha{
|
||||
position: absolute;
|
||||
top: 25px;
|
||||
color: #D40000;
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
.codeBut{
|
||||
height: 45px;
|
||||
background: #F7F7F7;
|
||||
border-radius: 7px;
|
||||
border: 1px solid rgba(167, 177, 200, 0.33);
|
||||
margin-left: 14px;
|
||||
width: 102px;
|
||||
color: #466AFF;
|
||||
font-size: 15px;
|
||||
}
|
||||
.codeBut.disable{
|
||||
color: rgba(0, 0, 0, 0.25);
|
||||
background-color: #f5f5f5;
|
||||
border-color: #d9d9d9;
|
||||
}
|
||||
}
|
||||
.ant-message-notice-content{
|
||||
box-shadow: 0px 1px 8px 1px rgba(0, 0, 0, 0.11);
|
||||
border-radius: 10px;
|
||||
margin-top: 2rem;
|
||||
margin-left: 10%;
|
||||
font-size: 15px;
|
||||
& a{
|
||||
color: #466AFF;
|
||||
&:hover{
|
||||
opacity:0.8;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,312 @@
|
|||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { Form, Input, Button, Checkbox, message } from "antd";
|
||||
import { Link } from "react-router-dom";
|
||||
import axios from 'axios';
|
||||
import { setmiyah } from 'educoder';
|
||||
import './LoginRegisterPage.scss';
|
||||
|
||||
function Register(props){
|
||||
const {form} = props;
|
||||
const {getFieldDecorator } = form;
|
||||
const [emailStr, setEmailStr] = useState(undefined);
|
||||
const [secondsStr, setSecondsStr] = useState(60);
|
||||
const [countDown, setCountDown] = useState(false);
|
||||
const [getCaptchaBut, setGetCaptchaBut] = useState(false);
|
||||
const [mess, setMess] = useState(undefined);
|
||||
const [tipVisable, setTipVisable] = useState(false);
|
||||
//用于表单提交时会再次校验数据
|
||||
const [userNameGo, setUserNameGo] = useState(true);
|
||||
const [emailGo, setEmailGo] = useState(true);
|
||||
const seconds = useRef();
|
||||
let interval = undefined;
|
||||
//页面加载完自动聚焦到第一个输入框
|
||||
const inputEl = useRef(null);
|
||||
|
||||
//注册表单提交
|
||||
function handleSubmit(){
|
||||
form.validateFields((err, values) => {
|
||||
if (!err) {
|
||||
values.agreement && axios.post(`/accounts/register.json`, {
|
||||
login: values.email,
|
||||
namespace: values.register_username,
|
||||
password: values.register_psd,
|
||||
password_confirmation: values.psdComfirm,
|
||||
code: values.captcha
|
||||
}).then((response)=>{
|
||||
if(response.data && response.data.status === -6){
|
||||
//验证码不正确
|
||||
form.setFields({captcha: {value:values.captcha,errors:[new Error('验证码错误,请重新输入')]}})
|
||||
}else if(response.data && response.data.status === 0){
|
||||
//注册成功,页面跳转即可,注册后登录流程forge处理了
|
||||
window.location.href = "/"+values.register_username;
|
||||
}else{
|
||||
setMess(response.data.message);
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//判断用户名(username)是否注册
|
||||
function usernameConfirm(rule, value, callback){
|
||||
setUserNameGo(true);
|
||||
value && userNameGo ? axios.post(`/accounts/check.json`, {
|
||||
value: value,
|
||||
type: 1
|
||||
}).then(response => {
|
||||
if (response.data.status === -1) {
|
||||
callback('该名称已经被使用');
|
||||
} else {
|
||||
setUserNameGo(false);
|
||||
callback();
|
||||
}
|
||||
}):callback()
|
||||
}
|
||||
|
||||
//判断邮箱是否注册
|
||||
function emailConfirm(rule, value, callback) {
|
||||
setEmailGo(true);
|
||||
value && emailGo ? axios.post(`/accounts/check.json`, {
|
||||
value: value,
|
||||
type: 2
|
||||
}).then(response => {
|
||||
if (response.data.status === -1) {
|
||||
callback('该邮箱已被注册');
|
||||
} else {
|
||||
setEmailStr(value);
|
||||
setGetCaptchaBut(true);
|
||||
setEmailGo(false);
|
||||
callback();
|
||||
}
|
||||
}):callback();setEmailStr(undefined);
|
||||
}
|
||||
|
||||
//确认密码
|
||||
function comfirmPassWord(rule, value, callback, index) {
|
||||
if ((index === 2 && value && form.getFieldValue('register_psd') && value !== form.getFieldValue('register_psd')) || (index === 1 && value && form.getFieldValue('psdComfirm') && value !== form.getFieldValue('psdComfirm'))) {
|
||||
if(index===1){
|
||||
form.setFields({psdComfirm: {value:form.getFieldValue('psdComfirm'),errors:[new Error('密码不一致,请重新输入')]}});
|
||||
callback();
|
||||
}else{
|
||||
callback('密码不一致,请重新输入');
|
||||
}
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
//检查密码是否符合格式
|
||||
function checkPassWord(rule, value, callback){
|
||||
if(!value){
|
||||
setTipVisable(true);
|
||||
callback('请输入登录密码');
|
||||
}else if(/(?!.*\s)(?!^[\u4e00-\u9fa5]+$)^.{8,16}$/.test(value)){
|
||||
callback()
|
||||
}else{
|
||||
setTipVisable(true);
|
||||
if(value.length<8 || value.length>16){
|
||||
callback('密码长度为8-16个字符');
|
||||
}else{
|
||||
callback('密码不能使用空格');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//确认勾选服务
|
||||
function comfirmRead(rule, value, callback){
|
||||
if(value){
|
||||
callback();
|
||||
}else{
|
||||
callback("请阅读并接受我们的服务条款");
|
||||
}
|
||||
}
|
||||
|
||||
//获取验证码
|
||||
function getCaptcha() {
|
||||
setMess(undefined);
|
||||
if (emailStr) {
|
||||
// 倒计时开始
|
||||
setCountDown(true);
|
||||
setGetCaptchaBut(false);
|
||||
seconds.current = 60;
|
||||
!interval && clearInterval(interval);
|
||||
interval = setInterval(() => {
|
||||
if (seconds.current > 1) {
|
||||
let oldSeconds = seconds.current;
|
||||
seconds.current = oldSeconds - 1;
|
||||
setSecondsStr(oldSeconds - 1);
|
||||
} else {
|
||||
clearInterval(interval);
|
||||
//倒计时结束->可以获取验证码
|
||||
setGetCaptchaBut(true);
|
||||
setCountDown(false);
|
||||
}
|
||||
}, 1000)
|
||||
|
||||
//请求获取验证码接口
|
||||
axios.get(`/accounts/get_verification_code.json`, {
|
||||
params: {
|
||||
login: emailStr,
|
||||
type: 1,
|
||||
smscode: setmiyah(emailStr),
|
||||
}
|
||||
}).then(response => {
|
||||
if (response.data && response.data.status === 0) {
|
||||
//验证码发送成功
|
||||
let email = emailStr.substring(emailStr.indexOf("@")+1);
|
||||
message.success({content:<span>验证码已发送,请注意查收。<a href={`https://mail.${email}`} target="_blank">前往邮箱</a></span>});
|
||||
} else {
|
||||
//验证码发送失败,获取验证码按钮变灰并且文案变回【获取验证码】
|
||||
setGetCaptchaBut(false);
|
||||
setCountDown(false);
|
||||
clearInterval(interval);
|
||||
setMess(response.data.message);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
//清除密码框的value属性->DOM看不见密码值
|
||||
function clear(){
|
||||
const password = document.getElementById("register_register_psd");
|
||||
const passwordComfirm = document.getElementById("register_psdComfirm");
|
||||
if(password && password.type==="password"){
|
||||
setTimeout(()=>{
|
||||
password.removeAttribute('value');
|
||||
},0)
|
||||
}
|
||||
if(passwordComfirm && passwordComfirm.type==="password"){
|
||||
setTimeout(()=>{
|
||||
passwordComfirm.removeAttribute('value');
|
||||
},0)
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
inputEl.current.focus();
|
||||
clear;
|
||||
}, [])
|
||||
|
||||
return(
|
||||
<div>
|
||||
<div className="right_cont Register_content">
|
||||
<div className="login_register_head">
|
||||
<span>欢迎注册 GitLink</span>
|
||||
<span className="link_span">已有账号,<Link to={`/login`}>立即登录</Link></span>
|
||||
</div>
|
||||
<p className={mess ? "message active" : "message"}>{mess}</p>
|
||||
<Form className="login-form">
|
||||
<Form.Item>
|
||||
{getFieldDecorator('register_username',{
|
||||
rules:[
|
||||
{
|
||||
required:true,
|
||||
message:"请输入用户名"
|
||||
},
|
||||
{
|
||||
pattern: /^[a-zA-Z]/,
|
||||
message: "用户名必须以字母开头"
|
||||
},
|
||||
{
|
||||
pattern: /[a-zA-Z0-9]$/,
|
||||
message: "用户名只能使用英文字母和数字"
|
||||
},
|
||||
{
|
||||
min: 4,
|
||||
max: 15,
|
||||
message: "用户名长度为4到15个字符"
|
||||
},
|
||||
{
|
||||
validator: (rule, value, callback) => { usernameConfirm(rule, value, callback) }
|
||||
}
|
||||
],
|
||||
validateTrigger:"onBlur",
|
||||
validateFirst: true,
|
||||
})(<Input ref={inputEl} className="account" placeholder="请输入4-15位用户名,以字母开头,只能使用字母和数字" readOnly onFocus={()=>{document.getElementById("register_register_username").removeAttribute("readOnly")}}/>)}
|
||||
</Form.Item>
|
||||
<Form.Item>
|
||||
{getFieldDecorator('email',{
|
||||
rules:[
|
||||
{
|
||||
type: 'email',
|
||||
message: '请输入正确的邮箱格式',
|
||||
},
|
||||
{
|
||||
required:true,
|
||||
message:"请输入邮箱地址"
|
||||
},
|
||||
{
|
||||
validator: (rule, value, callback) => { emailConfirm(rule, value, callback) }
|
||||
}
|
||||
],
|
||||
validateTrigger:"onBlur",
|
||||
validateFirst: true,
|
||||
})(<Input className="email" placeholder="请输入邮箱地址" readOnly onFocus={()=>{document.getElementById("register_email").removeAttribute("readOnly")}} />)}
|
||||
</Form.Item>
|
||||
|
||||
<div className="login_register_head">
|
||||
<Form.Item>
|
||||
{getFieldDecorator('captcha', {
|
||||
rules: [{
|
||||
required: true,
|
||||
message: "请输入验证码"
|
||||
}],
|
||||
validateTrigger: "onBlur",
|
||||
})(
|
||||
<Input className="captcha" placeholder="请输入验证码" readOnly onFocus={()=>{document.getElementById("register_captcha").removeAttribute("readOnly")}} />
|
||||
)}
|
||||
<Button className={getCaptchaBut ? 'codeBut':'codeBut disable'} disabled={!getCaptchaBut} onClick={getCaptcha}>{getCaptchaBut || (!getCaptchaBut && !countDown)?"获取验证码":`重发(${secondsStr}s)`}</Button>
|
||||
</Form.Item>
|
||||
</div>
|
||||
|
||||
<Form.Item>
|
||||
{getFieldDecorator('register_psd',{
|
||||
rules:[
|
||||
{
|
||||
validator: (rule, value, callback) => { comfirmPassWord(rule, value, callback, 1) }
|
||||
},
|
||||
{
|
||||
validator: (rule, value, callback) => { checkPassWord(rule, value, callback) }
|
||||
}
|
||||
],
|
||||
validateTrigger:"onBlur",
|
||||
validateFirst: true,
|
||||
})(<Input.Password className="register_psd" placeholder="请输入登录密码" onBlur={clear} onChange={clear} readOnly onFocus={()=>{document.getElementById("register_register_psd").removeAttribute("readOnly")}}/>)}
|
||||
</Form.Item>
|
||||
<span className="register_tips" style={{display:tipVisable?"none":"block"}}>请输入8-16位密码,区分大小写、不能使用空格</span>
|
||||
|
||||
<Form.Item>
|
||||
{getFieldDecorator('psdComfirm', {
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: "请确认登录密码"
|
||||
},
|
||||
{
|
||||
validator: (rule, value, callback) => { comfirmPassWord(rule, value, callback, 2) }
|
||||
}
|
||||
],
|
||||
validateTrigger: "onBlur",
|
||||
validateFirst: true,
|
||||
})(<Input.Password className="psdComfirm" placeholder="请确认登录密码" onBlur={clear} onChange={clear} readOnly onFocus={()=>{document.getElementById("register_psdComfirm").removeAttribute("readOnly")}}/>)}
|
||||
</Form.Item>
|
||||
|
||||
|
||||
<Form.Item className="register_last_form">
|
||||
{getFieldDecorator('agreement', {
|
||||
valuePropName: 'checked',
|
||||
initialValue: false,
|
||||
rules: [
|
||||
{
|
||||
validator: (rule, value, callback) => { comfirmRead(rule, value, callback) }
|
||||
}
|
||||
],
|
||||
})(<Checkbox>我已阅读并接受<a className="login-form-forgot" href="https://forum.trustie.net/forums/5029/detail" target="_blank">《GitLink服务协议条款》</a></Checkbox>)}
|
||||
</Form.Item>
|
||||
<Button type="primary" htmlType="submit" className="login_register_cofBut" onClick={handleSubmit}>注册</Button>
|
||||
</Form>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default Form.create({ name: 'register' })(Register);
|
|
@ -0,0 +1,257 @@
|
|||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { Form, Input, Button, message } from "antd";
|
||||
import { Link } from "react-router-dom";
|
||||
import axios from 'axios';
|
||||
import { setmiyah } from 'educoder';
|
||||
import './LoginRegisterPage.scss';
|
||||
|
||||
function ResetPassword(props) {
|
||||
const {form } = props;
|
||||
const {getFieldDecorator } = form;
|
||||
const [emailStr, setEmailStr] = useState(undefined);
|
||||
const [secondsStr, setSecondsStr] = useState(60);
|
||||
const [countDown, setCountDown] = useState(false);
|
||||
const [getCaptchaBut, setGetCaptchaBut] = useState(false);
|
||||
const [mess, setMess] = useState(undefined);
|
||||
const [tipVisable, setTipVisable] = useState(false);
|
||||
//用于限制表单提交时会再次调用check.json接口校验数据
|
||||
const [emailGo, setEmailGo] = useState(true);
|
||||
const seconds = useRef();
|
||||
let interval = undefined;
|
||||
//页面加载完自动聚焦到第一个输入框
|
||||
const inputEl = useRef(null);
|
||||
|
||||
//重置密码表单提交
|
||||
function handleSubmit() {
|
||||
form.validateFieldsAndScroll((err, values) => {
|
||||
if (!err) {
|
||||
axios.post(`/accounts/reset_password.json`, {
|
||||
login: values.email,
|
||||
password: values.psd,
|
||||
password_confirmation: values.psdComfirm,
|
||||
code: values.captcha,
|
||||
}).then((response) => {
|
||||
if (response.data.status === 0) {
|
||||
//重置密码成功,调用登录接口
|
||||
axios.post(`/accounts/login.json`, {
|
||||
login: values.email,
|
||||
password: values.psd
|
||||
}).then((login_response) => {
|
||||
if (!login_response.data.login) {
|
||||
setMess(login_response.data.message);
|
||||
} else {
|
||||
window.location.href = "/" + login_response.data.login;
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.log('error',error);
|
||||
})
|
||||
} else {
|
||||
const message = response.data.message;
|
||||
message === "验证码不正确" ? form.setFields({captcha: {value:values.captcha,errors:[new Error('验证码错误,请重新输入')]}}) : setMess(message);
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//判断邮箱是否注册
|
||||
function emailConfirm(rule, value, callback) {
|
||||
setEmailGo(true);
|
||||
value && emailGo ? axios.post(`/accounts/check.json`, {
|
||||
value: value,
|
||||
type: 2
|
||||
}).then(response => {
|
||||
if (response.data && response.data.status === -1) {
|
||||
setEmailStr(value)
|
||||
setGetCaptchaBut(true);
|
||||
setEmailGo(false);
|
||||
callback();
|
||||
} else {
|
||||
callback('此邮箱未注册');
|
||||
}
|
||||
}):callback();setEmailStr(undefined);
|
||||
}
|
||||
|
||||
//确认密码
|
||||
function comfirmPassWord(rule, value, callback, index) {
|
||||
if ((index === 2 && value && form.getFieldValue('psd') && value !== form.getFieldValue('psd')) || (index === 1 && value && form.getFieldValue('psdComfirm') && value !== form.getFieldValue('psdComfirm'))) {
|
||||
if(index===1){
|
||||
form.setFields({psdComfirm: {value:form.getFieldValue('psdComfirm'),errors:[new Error('密码不一致,请重新输入')]}});
|
||||
callback();
|
||||
}else{
|
||||
callback('密码不一致,请重新输入');
|
||||
}
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
//检查密码是否符合格式
|
||||
function checkPassWord(rule, value, callback){
|
||||
if(!value){
|
||||
setTipVisable(true);
|
||||
callback('请输入新密码');
|
||||
}else if(/(?!.*\s)(?!^[\u4e00-\u9fa5]+$)^.{8,16}$/.test(value)){
|
||||
callback()
|
||||
}else{
|
||||
setTipVisable(true);
|
||||
if(value.length<8 || value.length>16){
|
||||
callback('密码长度为8-16个字符');
|
||||
}else{
|
||||
callback('密码不能使用空格');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//获取验证码
|
||||
function getCaptcha() {
|
||||
setMess(undefined);
|
||||
if (emailStr) {
|
||||
// 倒计时开始
|
||||
setCountDown(true);
|
||||
setGetCaptchaBut(false);
|
||||
seconds.current = 60;
|
||||
!interval && clearInterval(interval);
|
||||
interval = setInterval(() => {
|
||||
if (seconds.current > 1) {
|
||||
let oldSeconds = seconds.current;
|
||||
seconds.current = oldSeconds - 1;
|
||||
setSecondsStr(oldSeconds - 1);
|
||||
} else {
|
||||
//倒计时结束->可以获取验证码
|
||||
setGetCaptchaBut(true);
|
||||
setCountDown(false);
|
||||
clearInterval(interval);
|
||||
}
|
||||
}, 1000)
|
||||
|
||||
//请求获取验证码接口
|
||||
axios.get(`/accounts/get_verification_code.json`, {
|
||||
params: {
|
||||
login: emailStr,
|
||||
type: 2,
|
||||
smscode: setmiyah(emailStr),
|
||||
}
|
||||
}).then(response => {
|
||||
if (response.data && response.data.status === 0) {
|
||||
//验证码发送成功
|
||||
let email = emailStr.substring(emailStr.indexOf("@")+1);
|
||||
message.success({content:<span>验证码已发送,请注意查收。<a href={`https://mail.${email}`} target="_blank">前往邮箱</a></span>});
|
||||
} else {
|
||||
//验证码发送失败,获取验证码按钮变灰并且文案变回【获取验证码】
|
||||
setGetCaptchaBut(false);
|
||||
setCountDown(false);
|
||||
clearInterval(interval);
|
||||
setMess(response.data.message);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
//清除密码框的value属性->DOM看不见密码值
|
||||
function clear(){
|
||||
const password = document.getElementById("resetPassword_psd");
|
||||
const passwordComfirm = document.getElementById("resetPassword_psdComfirm");
|
||||
if(password && password.type==="password"){
|
||||
setTimeout(()=>{
|
||||
password.removeAttribute('value');
|
||||
},0)
|
||||
}
|
||||
if(passwordComfirm && passwordComfirm.type==="password"){
|
||||
setTimeout(()=>{
|
||||
passwordComfirm.removeAttribute('value');
|
||||
},0)
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
inputEl.current.focus();
|
||||
clear;
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="right_cont ResetPassword_content">
|
||||
<div className="login_register_head">
|
||||
<span>找回密码</span>
|
||||
<span className="link_span">已有账号,<Link to={`/login`}>立即登录</Link></span>
|
||||
</div>
|
||||
<p className={mess ? "message active" : "message"}>{mess}</p>
|
||||
<Form className="login-form">
|
||||
<Form.Item>
|
||||
{getFieldDecorator('email', {
|
||||
rules: [
|
||||
{
|
||||
type: 'email',
|
||||
message: '请输入正确的邮箱格式',
|
||||
},
|
||||
{
|
||||
required: true,
|
||||
message: "请输入已注册的邮箱"
|
||||
},
|
||||
{
|
||||
validator: (rule, value, callback) => { emailConfirm(rule, value, callback) }
|
||||
}
|
||||
],
|
||||
validateTrigger: "onBlur",
|
||||
validateFirst: true,
|
||||
})(<Input ref={inputEl} className="account" placeholder="请输入已注册的邮箱" readOnly onFocus={()=>{document.getElementById("resetPassword_email").removeAttribute("readOnly")}} />)}
|
||||
</Form.Item>
|
||||
|
||||
<div className="login_register_head">
|
||||
<Form.Item>
|
||||
{getFieldDecorator('captcha', {
|
||||
rules: [{
|
||||
required: true,
|
||||
message: "请输入验证码"
|
||||
}],
|
||||
validateTrigger: "onBlur",
|
||||
})(
|
||||
<Input className="captcha" placeholder="请输入验证码" readOnly onFocus={()=>{document.getElementById("resetPassword_captcha").removeAttribute("readOnly")}} />
|
||||
)}
|
||||
<Button className={getCaptchaBut ? 'codeBut':'codeBut disable'} disabled={!getCaptchaBut} onClick={getCaptcha}>{getCaptchaBut || (!getCaptchaBut && !countDown)?"获取验证码":`重发(${secondsStr}s)`}</Button>
|
||||
</Form.Item>
|
||||
</div>
|
||||
|
||||
<Form.Item>
|
||||
{getFieldDecorator('psd', {
|
||||
rules: [
|
||||
{
|
||||
validator: (rule, value, callback) => { comfirmPassWord(rule, value, callback,1) }
|
||||
},
|
||||
{
|
||||
validator: (rule, value, callback) => { checkPassWord(rule, value, callback) }
|
||||
}
|
||||
],
|
||||
validateTrigger: "onBlur",
|
||||
validateFirst: true,
|
||||
})(<Input.Password className="psd" placeholder="请输入新密码" onBlur={clear} onChange={clear} readOnly onFocus={()=>{document.getElementById("resetPassword_psd").removeAttribute("readOnly")}} />)}
|
||||
</Form.Item>
|
||||
<span className="register_tips" style={{display:tipVisable?"none":"block"}}>请输入8-16位密码,区分大小写、不能使用空格</span>
|
||||
|
||||
<Form.Item>
|
||||
{getFieldDecorator('psdComfirm', {
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: "请确认新密码"
|
||||
},
|
||||
{
|
||||
validator: (rule, value, callback) => { comfirmPassWord(rule, value, callback,2) }
|
||||
}
|
||||
],
|
||||
validateTrigger: "onBlur",
|
||||
validateFirst: true,
|
||||
})(<Input.Password className="psdComfirm" placeholder="请确认新密码" onBlur={clear} onChange={clear} readOnly onFocus={()=>{document.getElementById("resetPassword_psdComfirm").removeAttribute("readOnly")}} />)}
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item>
|
||||
<Button type="primary" htmlType="submit" className="login_register_cofBut" onClick={handleSubmit}>重置密码并登录</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
}
|
||||
export default Form.create({ name: 'resetPassword' })(ResetPassword);
|
After Width: | Height: | Size: 45 KiB |
After Width: | Height: | Size: 255 KiB |
After Width: | Height: | Size: 114 KiB |
After Width: | Height: | Size: 108 KiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 39 KiB |
After Width: | Height: | Size: 92 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 134 KiB |
After Width: | Height: | Size: 107 KiB |
After Width: | Height: | Size: 34 KiB |