|
@@ -2,12 +2,15 @@ import React, { Component } from 'react';
|
|
|
import './index.less';
|
|
|
import { Modal, Icon, Button, Tooltip } from 'antd';
|
|
|
import Assets from '@src/components/Assets';
|
|
|
+import { asyncSMessage } from '@src/services/AsyncTools';
|
|
|
import { Icon as GIcon } from '../Icon';
|
|
|
import { Button as GButton } from '../Button';
|
|
|
import { User } from '../../stores/user';
|
|
|
+import { My } from '../../stores/my';
|
|
|
+import { Common } from '../../stores/common';
|
|
|
+import { MobileArea } from '../../../Constant';
|
|
|
|
|
|
const LOGIN_PHONE = 'LOGIN_PHONE';
|
|
|
-const REGISTER_PHONE = 'REGISTER_PHONE';
|
|
|
const LOGIN_WX = 'LOGIN_WX';
|
|
|
const BIND_PHONE = 'BIND_PHONE';
|
|
|
const BIND_WX = 'BIND_WX';
|
|
@@ -23,23 +26,142 @@ export default class Login extends Component {
|
|
|
User.closeLogin();
|
|
|
}
|
|
|
|
|
|
+ login() {
|
|
|
+ const { data, needEmail, mobileError, validError } = this.state;
|
|
|
+ const { area, mobile, mobileVerifyCode, email } = data;
|
|
|
+ if (mobileError !== '' || validError !== '') return;
|
|
|
+ if (area === '' || mobile === '' || mobileVerifyCode === '') return;
|
|
|
+ if (needEmail && email === '') return;
|
|
|
+ User.login(area, mobile, mobileVerifyCode).then(() => {
|
|
|
+ let handler = null;
|
|
|
+ if (needEmail) {
|
|
|
+ handler = My.bindEmail(email);
|
|
|
+ } else {
|
|
|
+ handler = Promise.resolve();
|
|
|
+ }
|
|
|
+ handler.then((result) => {
|
|
|
+ if (result.bindWechat) {
|
|
|
+ this.close();
|
|
|
+ } else {
|
|
|
+ this.setState({ type: BIND_WX });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ })
|
|
|
+ .catch(err => {
|
|
|
+ if (err.message.indexOf('验证码') >= 0) {
|
|
|
+ this.setState({ validError: err.message });
|
|
|
+ } else {
|
|
|
+ this.setState({ mobileError: err.message });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ bind() {
|
|
|
+ const { data, needEmail, mobileError, validError } = this.state;
|
|
|
+ const { area, mobile, mobileVerifyCode, email } = data;
|
|
|
+ if (mobileError !== '' || validError !== '') return;
|
|
|
+ if (area === '' || mobile === '' || mobileVerifyCode === '') return;
|
|
|
+ if (needEmail && email === '') return;
|
|
|
+ User.bind(area, mobile, mobileVerifyCode).then(() => {
|
|
|
+ let handler = null;
|
|
|
+ if (needEmail) {
|
|
|
+ handler = My.bindEmail(email);
|
|
|
+ } else {
|
|
|
+ handler = Promise.resolve();
|
|
|
+ }
|
|
|
+ handler.then(() => {
|
|
|
+ this.close();
|
|
|
+ });
|
|
|
+ })
|
|
|
+ .catch(err => {
|
|
|
+ if (err.message.indexOf('验证码') >= 0) {
|
|
|
+ this.setState({ validError: err.message });
|
|
|
+ } else {
|
|
|
+ this.setState({ mobileError: err.message });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ scanLogin() {
|
|
|
+ User.loginWechat('').then((result) => {
|
|
|
+ if (result.id) {
|
|
|
+ this.close();
|
|
|
+ } else {
|
|
|
+ this.setState({ type: BIND_PHONE });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ scanBind() {
|
|
|
+ User.loginWechat('').then(() => {
|
|
|
+ this.close();
|
|
|
+ }).catch(err => {
|
|
|
+ this.setState({ type: BIND_WX_ERROR, wechatError: err.message });
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ changeData(field, value) {
|
|
|
+ let { data } = this.state;
|
|
|
+ data = data || {};
|
|
|
+ data[field] = value;
|
|
|
+ this.setState({ data });
|
|
|
+ }
|
|
|
+
|
|
|
+ validMobile() {
|
|
|
+ const { data } = this.state;
|
|
|
+ const { area, mobile } = data;
|
|
|
+ if (area === '' || mobile === '') return;
|
|
|
+ User.validWechat(area, mobile)
|
|
|
+ .then(result => {
|
|
|
+ if (result) {
|
|
|
+ this.setState({ mobileError: '' });
|
|
|
+ return User.validMobile(area, mobile)
|
|
|
+ .then(r => {
|
|
|
+ this.setState({ needEmail: r });
|
|
|
+ });
|
|
|
+ }
|
|
|
+ this.setState({ needEmail: false });
|
|
|
+ return Promise.reject(new Error('该手机已绑定其他账号,请更换手机号码'));
|
|
|
+ })
|
|
|
+ .catch(err => {
|
|
|
+ this.setState({ mobileError: err.message });
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ sendValid() {
|
|
|
+ const { data, mobileError } = this.state;
|
|
|
+ const { area, mobile } = data;
|
|
|
+ if (area === '' || mobile === '' || mobileError !== '') return Promise.reject();
|
|
|
+ return Common.sendSms(area, mobile)
|
|
|
+ .then((result) => {
|
|
|
+ if (result) {
|
|
|
+ asyncSMessage('发送成功');
|
|
|
+ this.setState({ mobileError: '', validError: '' });
|
|
|
+ } else {
|
|
|
+ throw new Error('发送失败');
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .catch(err => {
|
|
|
+ this.setState({ mobileError: err.message });
|
|
|
+ throw err;
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
render() {
|
|
|
const { type } = this.state;
|
|
|
const { user } = this.props;
|
|
|
return (
|
|
|
<Modal wrapClassName={`login-modal ${type}`} visible={user.needLogin} footer={null} closable={false} width={470}>
|
|
|
{this.renderBody(type)}
|
|
|
- <GIcon name="close" onClick={() => this.close()} />
|
|
|
+ <GIcon name="close" onClick={() => {
|
|
|
+ this.close();
|
|
|
+ }} />
|
|
|
</Modal>
|
|
|
);
|
|
|
}
|
|
|
|
|
|
renderBody(type) {
|
|
|
switch (type) {
|
|
|
- case LOGIN_PHONE:
|
|
|
- return this.renderLoginPhone();
|
|
|
- case REGISTER_PHONE:
|
|
|
- return this.renderRegisterPhone();
|
|
|
case LOGIN_WX:
|
|
|
return this.renderLoginWx();
|
|
|
case BIND_PHONE:
|
|
@@ -48,45 +170,42 @@ export default class Login extends Component {
|
|
|
return this.renderBindWx();
|
|
|
case BIND_WX_ERROR:
|
|
|
return this.renderBindWxError();
|
|
|
+ case LOGIN_PHONE:
|
|
|
default:
|
|
|
- return this.LOGIN_PHONE();
|
|
|
+ return this.renderLoginPhone();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
renderLoginPhone() {
|
|
|
+ const { needEmail } = this.state;
|
|
|
return (
|
|
|
<div className="body">
|
|
|
<div className="title">手机号登录</div>
|
|
|
- <SelectInput placeholder="请输入手机号" />
|
|
|
- <VerificationInput placeholder="请输入验证码" />
|
|
|
- <Button type="primary" size="large" block>
|
|
|
- 登录
|
|
|
- </Button>
|
|
|
- <Tooltip overlayClassName="gray" placement="left" title="微信扫码登录">
|
|
|
- <a className="other">
|
|
|
- <Assets name="code" />
|
|
|
- </a>
|
|
|
- </Tooltip>
|
|
|
- </div>
|
|
|
- );
|
|
|
- }
|
|
|
-
|
|
|
- renderRegisterPhone() {
|
|
|
- return (
|
|
|
- <div className="body">
|
|
|
- <div className="title">手机号登录</div>
|
|
|
- <div className="tip">
|
|
|
+ <div className="tip" hidden={!needEmail}>
|
|
|
<Assets name="notice" />
|
|
|
该手机号尚未注册,将自动为您注册账户
|
|
|
</div>
|
|
|
- <SelectInput placeholder="请输入手机号" />
|
|
|
- <VerificationInput placeholder="请输入验证码" />
|
|
|
- <Input placeholder="请输入邮箱" />
|
|
|
- <Button type="primary" size="large" block>
|
|
|
+ <SelectInput placeholder="请输入手机号" selectValue={this.state.data.area} select={MobileArea} value={this.state.data.mobile} error={this.state.mobileError} onSelect={(value) => {
|
|
|
+ this.changeData('area', value);
|
|
|
+ }} onChange={(e) => {
|
|
|
+ this.changeData('mobile', e.target.value);
|
|
|
+ this.validMobile(e.target.value);
|
|
|
+ }} />
|
|
|
+ <VerificationInput placeholder="请输入验证码" value={this.state.data.mobileVerifyCode} error={this.state.validError} onSend={() => {
|
|
|
+ return this.sendValid();
|
|
|
+ }} />
|
|
|
+ {needEmail && <Input placeholder="请输入邮箱" value={this.state.data.email} onChange={(e) => {
|
|
|
+ this.changeData('email', e.target.value);
|
|
|
+ }} />}
|
|
|
+ <Button type="primary" size="large" block onClick={() => {
|
|
|
+ this.login();
|
|
|
+ }}>
|
|
|
登录
|
|
|
</Button>
|
|
|
<Tooltip overlayClassName="gray" placement="left" title="微信扫码登录">
|
|
|
- <a className="other">
|
|
|
+ <a className="other" onClick={() => {
|
|
|
+ this.setState({ type: LOGIN_WX });
|
|
|
+ }}>
|
|
|
<Assets name="code" />
|
|
|
</a>
|
|
|
</Tooltip>
|
|
@@ -103,7 +222,9 @@ export default class Login extends Component {
|
|
|
<div className="text">请使用微信扫描二维码登录</div>
|
|
|
</div>
|
|
|
<Tooltip overlayClassName="gray" placement="left" title="手机号登录">
|
|
|
- <a className="other">
|
|
|
+ <a className="other" onClick={() => {
|
|
|
+ this.setState({ type: LOGIN_PHONE });
|
|
|
+ }}>
|
|
|
<Assets name="phone" />
|
|
|
</a>
|
|
|
</Tooltip>
|
|
@@ -112,6 +233,7 @@ export default class Login extends Component {
|
|
|
}
|
|
|
|
|
|
renderBindPhone() {
|
|
|
+ const { needEmail } = this.state;
|
|
|
return (
|
|
|
<div className="body">
|
|
|
<div className="title">绑定手机号</div>
|
|
@@ -119,10 +241,21 @@ export default class Login extends Component {
|
|
|
<Assets name="notice" />
|
|
|
微信登录成功!为更好的使用服务,请您绑定手机号和邮箱。
|
|
|
</div>
|
|
|
- <SelectInput placeholder="请输入手机号" />
|
|
|
- <VerificationInput placeholder="请输入验证码" />
|
|
|
- <Input placeholder="请输入邮箱" />
|
|
|
- <Button type="primary" size="large" block>
|
|
|
+ <SelectInput placeholder="请输入手机号" selectValue={this.state.data.area} select={MobileArea} value={this.state.data.mobile} error={this.state.mobileError} onSelect={(value) => {
|
|
|
+ this.changeData('area', value);
|
|
|
+ }} onChange={(e) => {
|
|
|
+ this.changeData('mobile', e.target.value);
|
|
|
+ this.validMobile(e.target.value);
|
|
|
+ }} />
|
|
|
+ <VerificationInput placeholder="请输入验证码" value={this.state.data.mobileVerifyCode} error={this.state.validError} onSend={() => {
|
|
|
+ return this.sendValid();
|
|
|
+ }} />
|
|
|
+ {needEmail && <Input placeholder="请输入邮箱" value={this.state.data.email} onChange={(e) => {
|
|
|
+ this.changeData('email', e.target.value);
|
|
|
+ }} />}
|
|
|
+ <Button type="primary" size="large" block onClick={() => {
|
|
|
+ this.bind();
|
|
|
+ }}>
|
|
|
绑定
|
|
|
</Button>
|
|
|
</div>
|
|
@@ -140,7 +273,9 @@ export default class Login extends Component {
|
|
|
<div className="qr-code">
|
|
|
<Assets name="qrcode" />
|
|
|
<div className="text">请使用微信扫描二维码登录</div>
|
|
|
- <div className="jump">跳过</div>
|
|
|
+ <div className="jump" onClick={() => {
|
|
|
+ this.close();
|
|
|
+ }}>跳过</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
);
|
|
@@ -152,7 +287,9 @@ export default class Login extends Component {
|
|
|
<div className="title">绑定失败</div>
|
|
|
<div className="text">该微信账户已绑定其他手机号,您可直接使用微信登入。</div>
|
|
|
<div className="btn">
|
|
|
- <GButton radius>Ok</GButton>
|
|
|
+ <GButton radius onClick={() => {
|
|
|
+ this.close();
|
|
|
+ }}>Ok</GButton>
|
|
|
</div>
|
|
|
</div>
|
|
|
);
|
|
@@ -161,12 +298,12 @@ export default class Login extends Component {
|
|
|
|
|
|
class Input extends Component {
|
|
|
render() {
|
|
|
- const { className = '', onChange, placeholder, error, left, right } = this.props;
|
|
|
+ const { className = '', onChange, placeholder, value, error, left, right } = this.props;
|
|
|
return (
|
|
|
<div className={`g-input-container ${className}`}>
|
|
|
<div className={`g-input-wrapper ${error ? 'error' : ''}`}>
|
|
|
{left && <div className="g-input-left">{left}</div>}
|
|
|
- <input className="g-input" placeholder={placeholder} onChange={data => onChange && onChange(data)} />
|
|
|
+ <input className="g-input" placeholder={placeholder} value={value} onChange={data => onChange && onChange(data)} />
|
|
|
{right && <div className="g-input-right">{right}</div>}
|
|
|
</div>
|
|
|
<div hidden={!error} className="g-input-error">
|
|
@@ -178,26 +315,39 @@ class Input extends Component {
|
|
|
}
|
|
|
|
|
|
class SelectInput extends Component {
|
|
|
+ constructor(props) {
|
|
|
+ super(props);
|
|
|
+ this.state = { showSelect: false };
|
|
|
+ }
|
|
|
+
|
|
|
render() {
|
|
|
- const { className = '', onChange, placeholder, value, selectValue, onSelect } = this.props;
|
|
|
+ const { showSelect } = this.state;
|
|
|
+ const { className = '', onChange, placeholder, value, error, selectValue, select, onSelect } = this.props;
|
|
|
return (
|
|
|
<Input
|
|
|
className={className}
|
|
|
left={
|
|
|
- <span className="g-input-left-select" onClick={() => onSelect && onSelect()}>
|
|
|
+ <span className="g-input-left-select" onClick={() => this.setState({ showSelect: !showSelect })}>
|
|
|
{selectValue}
|
|
|
- <Icon type="down" />
|
|
|
+ <Icon type={showSelect ? 'up' : 'down'} />
|
|
|
+ {showSelect && <ul className="select-list">{select.map((row) => {
|
|
|
+ return <li onClick={() => {
|
|
|
+ this.setState({ showSelect: false });
|
|
|
+ if (onSelect) onSelect(row.value);
|
|
|
+ }}>{row.label}</li>;
|
|
|
+ })}</ul>}
|
|
|
</span>
|
|
|
}
|
|
|
value={value}
|
|
|
placeholder={placeholder}
|
|
|
onChange={data => onChange && onChange(data)}
|
|
|
+ error={error}
|
|
|
/>
|
|
|
);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-class VerificationInput extends Component {
|
|
|
+export class VerificationInput extends Component {
|
|
|
constructor(props) {
|
|
|
super(props);
|
|
|
this.timeKey = null;
|
|
@@ -211,9 +361,11 @@ class VerificationInput extends Component {
|
|
|
onSend() {
|
|
|
const { onSend, time = 60 } = this.props;
|
|
|
if (onSend) {
|
|
|
- onSend();
|
|
|
+ onSend()
|
|
|
+ .then(() => {
|
|
|
+ this.setTime(time);
|
|
|
+ });
|
|
|
}
|
|
|
- this.setTime(time);
|
|
|
}
|
|
|
|
|
|
setTime(time) {
|