react-app-shell
Version:
react打包脚本和example, 这里的版本请忽略
442 lines (410 loc) • 15.4 kB
JavaScript
import React from 'react';
import propTypes from 'prop-types';
import classNames from 'classnames';
import {message, myToast, monitor, localStore} from '../../utils';
import {authService} from '../../service';
import {REISTER_RESULT_CODE} from '../../constants/user';
import styles from './auth.less';
import image_close from '../../public/images/group/close.png';
import image_login_logo from '../../public/images/group/login-logo.png';
import image_phone from '../../public/images/group/phone.png';
import image_pwd from '../../public/images/group/pwd.png';
import image_code from '../../public/images/group/auth-code.png';
import image_p_code from '../../public/images/group/code.png';
import {appConfig} from '../../config';
const noop = () => {
};
const phoneReg = /^1\d{10}$/;
const passwordReg = /^[a-zA-Z0-9]{6,18}$/;
/**
* @author pssgo
* @description 登录组件
*/
export default class Auth extends React.Component {
static propTypes = {
visible: propTypes.bool,
registerCallback: propTypes.func, // 注册成功的callback
loginCallback: propTypes.func, // 登录成功的callback
onClose: propTypes.func, // 点击关闭按钮触发的事件
initialMode: propTypes.oneOf(['login', 'register']), // 初始化的组件状态只触发一次 默认为登录组件
grf: propTypes.oneOfType([propTypes.string, propTypes.number]), // 团长的id 如果没有传给我空字符串或者-1
rf: propTypes.oneOfType([propTypes.string, propTypes.number]), // rf码 如果没有传给我空字符串或者 -1
};
static defaultProps = {
visible: false,
registerCallback: noop,
loginCallback: noop,
onClose: noop,
initialMode: 'register',
grf: -1,
rf: -1,
};
constructor(props) {
super(...props);
this.timer = null;
this.allow = true;
this.state = {
mode: 'login',
login: {
phone: '',
password: '',
},
register: {
needCaptcha: false,
countdown: false,
icode: '',
code: '',
endTime: 0,
phone: '',
password: '',
}
};
}
componentDidMount() {
if (this.props.initialMode) {
this.setState({
mode: this.props.initialMode,
});
}
}
/**
* @description 切换 模式
*/
switchMode = () => {
this.allow = true;
this.timer = null;
this.setState(state => ({
mode: state.mode === 'login' ? 'register' : 'login'
}));
};
/**
* @description 设置登录的state
*/
transferSetLoginState = field => event => {
const value = event.target.value;
this.setState(state => ({
login: {
...state.login,
[field]: value,
}
}));
};
/**
* @description 设置注册的state
*/
transferSetRegisterState = field => event => {
const value = event.target.value;
this.setState(state => ({
register: {
...state.register,
[field]: value
}
}));
};
// 刷新验证码
handleChangeImageCode = () => {
if (this.refs.captchaImg) {
this.refs.captchaImg.src = '/captcha/get?t=' + Math.random();
}
};
// 注册组件
renderRegisterComponent = () => {
const {register: {countdown, endTime, phone, needCaptcha, icode, password, code}} = this.state;
return (
<div className={styles.p_register}>
<div className={styles.p_input_wrapper}>
<div className={styles.icon}>
<img src={image_phone} alt=""/>
</div>
<div className={styles.p_input}>
<input
placeholder={'手机账号'}
value={phone}
maxLength={11}
onChange={this.transferSetRegisterState('phone')}
/>
</div>
</div>
{
needCaptcha &&
<div className={classNames(styles.p_input_wrapper, styles.image_code_wrapper)}>
{/* 图形验证码 */}
<div className={styles.icon}>
<img src={image_p_code} alt=""/>
</div>
<div className={styles.p_input}>
<input
type={'text'}
maxLength={18}
onChange={this.transferSetRegisterState('icode')}
value={icode}
placeholder={'请输入图片验证码'}
/>
</div>
<div className={styles.image_code} onClick={this.handleChangeImageCode}>
<img src={''} ref={'captchaImg'} alt={''}/>
</div>
</div>
}
<div className={classNames(styles.p_input_wrapper, styles.code)}>
<div className={styles.icon}>
<img src={image_code} alt=""/>
</div>
<div className={styles.p_input}>
<input
placeholder={'请输入验证码'}
maxLength={6}
onChange={this.transferSetRegisterState('code')}
value={code}
/>
</div>
<div
className={classNames(styles.code_btn, {
[styles.disable]: countdown
})}
onClick={this.handleSendCode}
>{countdown ? `${endTime}秒后重新获取` : '获取验证码'}</div>
</div>
<div className={styles.p_input_wrapper}>
<div className={styles.icon}>
<img src={image_pwd} alt=""/>
</div>
<div className={styles.p_input}>
<input
type={'password'}
maxLength={18} value={password}
onChange={this.transferSetRegisterState('password')}
placeholder={'6-18位数字或字母'}
/>
</div>
</div>
<div className={styles.padding_top_20}>
<button className={styles.login_btn} onClick={this.handleRegister}>免费注册</button>
</div>
<button className={styles.register_btn} onClick={this.switchMode}>已有账号? 直接登录</button>
<div className={styles.desc}>
<a href={appConfig.resources.protocolUrl} target={'_blank'}>注册即视为同意《魔力耳朵用户注册协议》</a>
</div>
</div>
);
};
// 登录组件
renderLoginComponent = () => {
const {login: {phone, password}} = this.state;
return (
<div className={styles.p_login}>
<div className={styles.p_input_wrapper}>
<div className={styles.icon}>
<img src={image_phone} alt=""/>
</div>
<div className={styles.p_input}>
<input placeholder={'手机账号'} value={phone} maxLength={11}
onChange={this.transferSetLoginState('phone')}
/>
</div>
</div>
<div className={styles.p_input_wrapper}>
<div className={styles.icon}>
<img src={image_pwd} alt=""/>
</div>
<div className={styles.p_input}>
<input type={'password'} maxLength={18} value={password}
onChange={this.transferSetLoginState('password')} placeholder={'6-18位数字或字母'}
/>
</div>
</div>
<div className={styles.padding_top_20}>
<button className={styles.login_btn} onClick={this.handleLogin}>登录</button>
</div>
<button className={styles.register_btn} onClick={this.switchMode}>免费注册</button>
</div>
);
};
/**
* @description 校验
* @return {boolean}
*/
verifyLogin = () => {
const {login: {phone, password}} = this.state;
if (!phone) {
message.info('请输入手机号码');
return false;
}
if (!phoneReg.test(phone)) {
message.info('手机号格式错误');
return false;
}
if (!password) {
message.info('请输入密码');
return false;
}
if (password.length < 6) {
message.info('请输入正确的登录密码');
return false;
}
return true;
};
/**
* @description 校验注册
* @return {boolean}
*/
verifyRegister = () => {
const {register: {phone, password, code}} = this.state;
if (!phone) {
message.info('手机号不能为空');
return false;
}
if (!phoneReg.test(phone)) {
message.info('请输入正确的手机号');
return false;
}
if (!code) {
message.info('验证码不能为空');
return false;
}
if (!password) {
message.info('密码不能为空');
return false;
}
if (!passwordReg.test(password)) {
message.info('请输入6-18位数字或字母');
return false;
}
return true;
};
/**
* @description 注册
*/
handleRegister = () => {
if (!this.verifyRegister()) return;
this.allow = false;
const {register: {phone, password, code}} = this.state;
let grf = this.props.grf || -1;
let rf = this.props.rf || -1;
authService.register(phone, password, code, grf, rf).then(({data}) => {
this.allow = true;
localStore.setToken(data.userId, data.passToken);
monitor.login();
this.props.registerCallback();
}).catch(e => {
this.allow = true;
message.error(e.msg || '注册失败');
});
};
handleSendCode = () => {
if (!this.allow) return false;
const {register: {phone, icode, needCaptcha}} = this.state;
if (!phoneReg.test(phone)) {
return message.info('请输入手机号码');
}
if (needCaptcha && icode.length !== 4) {
return message.info('请输入图片验证码');
}
monitor.log(phone, '获取短信验证码');
this.allow = false;
authService.sendCode(phone, icode).then(() => {
this.allow = true;
myToast.success('发送成功', 1500);
this.setState(state => ({
register: {
...state.register,
countdown: true,
endTime: 30,
}
}));
this.timer = setInterval(() => {
this.setState(state => {
if (state.register.endTime - 1 < 0) {
clearInterval(this.timer);
return {
register: {
...state.register,
countdown: false,
}
};
} else {
return {
register: {
...state.register,
endTime: state.register.endTime - 1,
}
};
}
});
}, 1000);
}).catch(e => {
this.allow = true;
switch (e.code) {
case REISTER_RESULT_CODE.EXCEED_MAX_COUNT: {
monitor.log(phone, '超过获取手机验证码最大次数');
message.error('超过获取手机验证码最大次数');
break;
}
case REISTER_RESULT_CODE.PHONE_ALEARDY_REGISTED: {
monitor.log(phone, '该手机号已注册');
message.error('该手机号已注册');
break;
}
case REISTER_RESULT_CODE.INVALID_CODE: {
monitor.log(phone, '弹出图形验证码');
this.setState(state => ({
register: {
...state.register,
needCaptcha: true,
}
}), this.handleChangeImageCode);
message.error('请输入图片验证码');
break;
}
default: {
// empty
}
}
console.log('e', e);
});
};
/**
* @description 登录
*/
handleLogin = () => {
if (!this.allow) {
return false;
}
if (!this.verifyLogin()) {
return false;
}
const {login: {phone, password}} = this.state;
this.allow = false;
authService.login(phone, password).then(({userId, passToken}) => {
localStore.setToken(userId, passToken);
monitor.login();
console.log('登录成功');
this.props.loginCallback();
}).catch(e => {
message.error(e.msg || '登录失败');
this.allow = true;
});
};
render() {
const {mode} = this.state;
const {onClose} = this.props;
return (
<div className={styles.p_auth}>
<div className={classNames(styles.modal, {
[styles.super_height]: mode !== 'login'
})}>
<div className={styles.header}>
<img src={image_login_logo} alt={''}/>
</div>
<p className={styles.title}>{mode === 'login' ? '登录' : '注册'}魔力耳朵账号</p>
<div className={styles.content}>
{mode === 'login' ? this.renderLoginComponent() : this.renderRegisterComponent()}
</div>
<div className={styles.close} onClick={onClose}>
<img src={image_close} alt={''}/>
</div>
</div>
</div>
);
}
}