Bläddra i källkod

fix(server): 登录注册

Go 4 år sedan
förälder
incheckning
28ef5feaed

+ 29 - 7
front/project/h5/routes/page/bind/page.js

@@ -16,7 +16,8 @@ export default class extends Page {
   }
 
   init() {
-    this.validNumber = 0;
+    this.validMobileNumber = 0;
+    this.validEmailNumber = 0;
   }
 
   changeData(field, value) {
@@ -30,14 +31,14 @@ export default class extends Page {
     const { data } = this.state;
     const { area, mobile } = data;
     if (!area || !mobile) return;
-    this.validNumber += 1;
-    const number = this.validNumber;
+    this.validMobileNumber += 1;
+    const number = this.validMobileNumber;
     User.validWechat(area, mobile)
       .then(result => {
         if (result) {
           this.setState({ mobileError: '' });
           return User.validMobile(area, mobile).then(r => {
-            if (number !== this.validNumber) return;
+            if (number !== this.validMobileNumber) return;
             this.setState({ needEmail: r });
           });
         }
@@ -49,6 +50,26 @@ export default class extends Page {
       });
   }
 
+  validEmail() {
+    const { data } = this.state;
+    const { email } = data;
+    if (!email) return;
+    this.validEmailNumber += 1;
+    const number = this.validEmailNumber;
+    User.validEmail(email)
+      .then(result => {
+        if (number !== this.validEmailNumber) return Promise.resolve();
+        if (result) {
+          this.setState({ emailError: '' });
+          return Promise.resolve();
+        }
+        return Promise.reject(new Error('该邮箱已绑定其他账号,请更换邮箱地址'));
+      })
+      .catch(err => {
+        this.setState({ emailError: err.message });
+      });
+  }
+
   sendValid() {
     const { data, mobileError } = this.state;
     const { area, mobile } = data;
@@ -69,9 +90,9 @@ export default class extends Page {
   }
 
   submit() {
-    const { data, needEmail, mobileError, validError } = this.state;
+    const { data, needEmail, mobileError, emailError, validError } = this.state;
     const { area, mobile, mobileVerifyCode, email } = data;
-    if (mobileError || validError) return;
+    if (mobileError || emailError || validError) return;
     if (!area || !mobile || !mobileVerifyCode) return;
     if (needEmail && !email) return;
     User.bind(area, mobile, mobileVerifyCode, email)
@@ -84,9 +105,10 @@ export default class extends Page {
         }
       })
       .catch(err => {
-        console.log(err.message);
         if (err.message.indexOf('验证码') >= 0) {
           this.setState({ validError: err.message });
+        } else if (err.message.indexOf('邮箱') >= 0) {
+          this.setState({ emailError: err.message });
         } else {
           this.setState({ mobileError: err.message });
         }

+ 7 - 0
front/project/h5/stores/user.js

@@ -125,6 +125,13 @@ export default class UserStore extends BaseStore {
   }
 
   /**
+   * 查询邮箱对应账号
+   */
+  validEmail(email) {
+    return this.apiGet('/auth/valid/email', { email });
+  }
+
+  /**
    * 查询手机是否绑定微信
    */
   validWechat(area, mobile) {

+ 1 - 1
front/project/www/components/Header/index.js

@@ -90,7 +90,7 @@ function Header(props) {
             >
               <Link to="/my/main" className="info">
                 <Assets src={user.info.avatar} />
-                <span className="t-2 f-s-12">{user.info.nickname}</span>
+                <span className="t-2 f-s-12">{user.info.nickname || `qx${user.info.mobile}`}</span>
               </Link>
             </Dropdown>
           ) : (<Button onClick={() => {

+ 51 - 15
front/project/www/components/Login/index.js

@@ -20,7 +20,8 @@ const BIND_WX_ERROR = 'BIND_WX_ERROR';
 export default class Login extends Component {
   constructor(props) {
     super(props);
-    this.validNumber = 0;
+    this.validMobileNumber = 0;
+    this.validEmailNumber = 0;
     this.state = { type: LOGIN_WX, data: { area: MobileArea[0].value } };
     window.addEventListener(
       'message',
@@ -57,9 +58,9 @@ export default class Login extends Component {
   }
 
   login() {
-    const { data, needEmail, mobileError, validError } = this.state;
+    const { data, needEmail, mobileError, emailError, validError } = this.state;
     const { area, mobile, mobileVerifyCode, email } = data;
-    if (mobileError || validError) return;
+    if (mobileError || emailError || validError) return;
     if (!area || !mobile || !mobileVerifyCode) return;
     if (needEmail && !email) return;
     User.login(area, mobile, mobileVerifyCode, email, null, false)
@@ -73,6 +74,8 @@ export default class Login extends Component {
       .catch(err => {
         if (err.message.indexOf('验证码') >= 0) {
           this.setState({ validError: err.message });
+        } else if (err.message.indexOf('邮箱') >= 0) {
+          this.setState({ emailError: err.message });
         } else {
           this.setState({ mobileError: err.message });
         }
@@ -80,9 +83,9 @@ export default class Login extends Component {
   }
 
   bind() {
-    const { data, needEmail, mobileError, validError } = this.state;
+    const { data, needEmail, mobileError, emailError, validError } = this.state;
     const { area, mobile, mobileVerifyCode, email } = data;
-    if (mobileError || validError) return;
+    if (mobileError || emailError || validError) return;
     if (!area || !mobile || !mobileVerifyCode) return;
     if (needEmail && !email) return;
     User.bind(area, mobile, mobileVerifyCode, email)
@@ -92,6 +95,8 @@ export default class Login extends Component {
       .catch(err => {
         if (err.message.indexOf('验证码') >= 0) {
           this.setState({ validError: err.message });
+        } else if (err.message.indexOf('邮箱') >= 0) {
+          this.setState({ emailError: err.message });
         } else {
           this.setState({ mobileError: err.message });
         }
@@ -132,14 +137,14 @@ export default class Login extends Component {
     const { data } = this.state;
     const { area, mobile } = data;
     if (!area || !mobile) return;
-    this.validNumber += 1;
-    const number = this.validNumber;
+    this.validMobileNumber += 1;
+    const number = this.validMobileNumber;
     User.validWechat(area, mobile)
       .then(result => {
         if (result) {
           this.setState({ mobileError: '' });
           return User.validMobile(area, mobile).then(r => {
-            if (number !== this.validNumber) return;
+            if (number !== this.validMobileNumber) return;
             this.setState({ needEmail: r });
           });
         }
@@ -151,6 +156,26 @@ export default class Login extends Component {
       });
   }
 
+  validEmail() {
+    const { data } = this.state;
+    const { email } = data;
+    if (!email) return;
+    this.validEmailNumber += 1;
+    const number = this.validEmailNumber;
+    User.validEmail(email)
+      .then(result => {
+        if (number !== this.validEmailNumber) return Promise.resolve();
+        if (result) {
+          this.setState({ emailError: '' });
+          return Promise.resolve();
+        }
+        return Promise.reject(new Error('该邮箱已绑定其他账号,请更换邮箱地址'));
+      })
+      .catch(err => {
+        this.setState({ emailError: err.message });
+      });
+  }
+
   sendValid() {
     const { data, mobileError } = this.state;
     const { area, mobile } = data;
@@ -188,7 +213,12 @@ export default class Login extends Component {
         <GIcon
           name="close"
           onClick={() => {
-            User.closeLogin(new Error('no login'));
+            if (type === BIND_WX_ERROR) {
+              // 绑定微信错误,返回重新绑定微信
+              this.setState({ type: BIND_WX });
+            } else {
+              User.closeLogin(new Error('no login'));
+            }
           }}
         />
       </Modal>
@@ -250,14 +280,16 @@ export default class Login extends Component {
           <Input
             placeholder="请输入邮箱"
             value={this.state.data.email}
+            error={this.state.emailError}
             onChange={e => {
               this.changeData('email', e.target.value);
+              this.validEmail();
             }}
           />
         )}
         {needEmail && (<div>
           <RadioItem checked theme="white" className="m-r-5" />
-          我已经阅读并同意 <a href={`/contract/${registerContract.key}`} target="_blank">{registerContract.title}</a>  <a href={`/contract/${privacyContract.key}`} target="_blank">{privacyContract.title}</a>.
+          我已同意 <a href={`/contract/${registerContract.key}`} target="_blank">{registerContract.title}</a>  <a href={`/contract/${privacyContract.key}`} target="_blank">{privacyContract.title}</a>
         </div>)}
         <Button
           type="primary"
@@ -311,7 +343,7 @@ export default class Login extends Component {
   }
 
   renderBindPhone() {
-    const { needEmail, contract = {} } = this.state;
+    const { needEmail, registerContract = {}, privacyContract } = this.state;
     return (
       <div className="body">
         <div className="title">绑定手机号</div>
@@ -349,15 +381,19 @@ export default class Login extends Component {
           <Input
             placeholder="请输入邮箱"
             value={this.state.data.email}
+            error={this.state.emailError}
             onChange={e => {
               this.changeData('email', e.target.value);
+              this.validEmail();
             }}
           />
         )}
         {needEmail && (<div>
           <RadioItem checked theme="white" className="m-r-5" />
-          我已经阅读并同意 <a href={`/contract/${contract.key}`} target="_blank">{contract.title}</a> 与 <a href={`/contract/${contract.key}`} target="_blank">隐私政策</a>.
+          我已同意 <a href={`/contract/${registerContract.key}`} target="_blank">《{registerContract.title}》</a> <a href={`/contract/${privacyContract.key}`} target="_blank">《{privacyContract.title}》</a>
+          <a className="f-r" onClick={() => this.setState({ type: LOGIN_PHONE })}>使用手机号码登录</a>
         </div>)}
+        {!needEmail && <div><a className="f-r" onClick={() => this.setState({ type: LOGIN_PHONE })}>使用手机号码登录</a></div>}
         <Button
           type="primary"
           size="large"
@@ -406,15 +442,15 @@ export default class Login extends Component {
     return (
       <div className="body">
         <div className="title">绑定失败</div>
-        <div className="text">该微信账户已绑定其他手机号,您可直接使用微信登入。</div>
+        <div className="text">该微信账户已绑定其他手机号码,您可直接扫码登入。</div>
         <div className="btn">
           <GButton
             radius
             onClick={() => {
-              this.close();
+              this.setState({ type: LOGIN_WX });
             }}
           >
-            Ok
+            扫码登入
           </GButton>
         </div>
       </div>

+ 44 - 13
front/project/www/components/OtherModal/index.js

@@ -22,6 +22,7 @@ const TextbookFeedbackTargetMap = getMap(TextbookFeedbackTarget, 'value', 'tip')
 export class BindPhone extends Component {
   constructor(props) {
     super(props);
+    this.validNumber = 0;
     this.props.data = this.props.data || {};
     this.state = Object.assign({ step: 0, data: {} }, this.initState(this.props));
     this.stepProp = {
@@ -59,7 +60,7 @@ export class BindPhone extends Component {
     let { data } = this.state;
     data = data || {};
     data[field] = value;
-    this.setState({ data, error: null });
+    this.setState({ data, mobileError: null });
   }
 
   validMobile() {
@@ -71,7 +72,11 @@ export class BindPhone extends Component {
     User.validMobile(area, mobile)
       .then(result => {
         if (number !== this.validNumber) return Promise.resolve();
-        return result ? Promise.resolve() : Promise.reject(new Error('该手机已绑定其他账号,请更换手机号码'));
+        if (result) {
+          this.setState({ mobileError: '' });
+          return Promise.resolve();
+        }
+        return Promise.reject(new Error('该手机已绑定其他账号,请更换手机号码'));
       })
       .catch(err => {
         this.setState({ mobileError: err.message });
@@ -79,37 +84,41 @@ export class BindPhone extends Component {
   }
 
   sendValid() {
-    const { data, error } = this.state;
+    const { data, mobileError } = this.state;
     const { area, mobile } = data;
-    if (!area || !mobile || error) return Promise.reject();
+    if (!area || !mobile || mobileError) return Promise.reject();
     return Common.sendSms(area, mobile)
       .then(result => {
         if (result) {
           asyncSMessage('发送成功');
-          this.setState({ error: '', validError: '' });
+          this.setState({ mobileError: '', validError: '' });
         } else {
           throw new Error('发送失败');
         }
       })
       .catch(err => {
-        this.setState({ error: err.message });
+        this.setState({ mobileError: err.message });
         throw err;
       });
   }
 
   submit() {
-    const { data, error } = this.state;
-    if (!data.mobile || !data.area || error) return;
+    const { data, validError, mobileError } = this.state;
+    if (!data.mobile || !data.area || validError || mobileError) return;
     const { area, mobile } = data;
     My.bindMobile(area, mobile)
       .then(() => {
         asyncSMessage('操作成功');
-        this.setState({ step: 0 });
+        this.setState({ step: 0, validError: '', mobileError: '' });
         User.infoHandle(Object.assign(this.props.data, { area, mobile }));
         this.props.onConfirm();
       })
-      .catch(e => {
-        this.setState({ error: e.message });
+      .catch(err => {
+        if (err.message.indexOf('验证码') >= 0) {
+          this.setState({ validError: err.message });
+        } else {
+          this.setState({ mobileError: err.message });
+        }
       });
   }
 
@@ -143,7 +152,7 @@ export class BindPhone extends Component {
             selectValue={this.state.data.area}
             select={MobileArea}
             value={this.state.data.mobile}
-            error={this.state.error}
+            error={this.state.mobileError}
             onSelect={value => {
               this.changeData('area', value);
               this.validMobile();
@@ -173,6 +182,7 @@ export class BindPhone extends Component {
 export class BindEmail extends Component {
   constructor(props) {
     super(props);
+    this.validNumber = 0;
     this.props.data = this.props.data || {};
     this.state = Object.assign({ step: 0, data: {} }, this.initState(this.props));
     this.stepProp = {
@@ -211,6 +221,26 @@ export class BindEmail extends Component {
     this.setState({ data, error: null });
   }
 
+  validEmail() {
+    const { data } = this.state;
+    const { email } = data;
+    if (!email) return;
+    this.validNumber += 1;
+    const number = this.validNumber;
+    User.validEmail(email)
+      .then(result => {
+        if (number !== this.validNumber) return Promise.resolve();
+        if (result) {
+          this.setState({ error: '' });
+          return Promise.resolve();
+        }
+        return Promise.reject(new Error('该邮箱已绑定其他账号,请更换邮箱地址'));
+      })
+      .catch(err => {
+        this.setState({ error: err.message });
+      });
+  }
+
   submit() {
     const { data, error } = this.state;
     if (!data.email || error) return;
@@ -218,7 +248,7 @@ export class BindEmail extends Component {
     My.bindEmail(email)
       .then(() => {
         asyncSMessage('操作成功');
-        this.setState({ step: 0 });
+        this.setState({ step: 0, error: '' });
         User.infoHandle(Object.assign(this.props.data, { email }));
         this.props.onConfirm();
       })
@@ -258,6 +288,7 @@ export class BindEmail extends Component {
             error={this.state.error}
             onChange={e => {
               this.changeData('email', e.target.value);
+              this.validEmail();
             }}
           />
         </div>

+ 8 - 0
front/project/www/stores/user.js

@@ -239,6 +239,7 @@ export default class UserStore extends BaseStore {
         return true;
       })
       .then(() => {
+        this.setToken('');
         this.setState({ login: false, info: {}, username: '' });
       })
       .then(() => {
@@ -280,6 +281,13 @@ export default class UserStore extends BaseStore {
   }
 
   /**
+   * 查询邮箱对应账号
+   */
+  validEmail(email) {
+    return this.apiGet('/auth/valid/email', { email });
+  }
+
+  /**
    * 查询手机是否绑定微信
    */
   validWechat(area, mobile) {

+ 28 - 0
server/data/src/main/resources/db/migration/V2__update_message.sql

@@ -0,0 +1,28 @@
+UPDATE message_template SET content = '<p>同学您好,<br  />\r\n您的账号于{time}发生异常登入,异常登入可能会影响您账号的正常使用,望知悉。</p>\r\n<p></p>\r\n<p>Best<br />\r\n千行团队</p>' WHERE id = 10;
+UPDATE message_template SET content = '<p>同学您好,<br  />\r\n最新换库时间是{date},上次换库时间是{prevDate},间隔{period}天,库长{days}天。<br />\r\n查看本年度换库情况: {linkSecondHtml}\r\n获取机经:{linkHtml}</p>\r\n<p></p>\r\n<p>Best<br />\r\n千行团队</p>' WHERE id = 11;
+UPDATE message_template SET content = '<p>同学您好,<br  />\r\n欢迎加入“千行GMAT”,您的账号已绑定该邮箱地址。\r\n愿您Waste Less, Learn More.</p>\r\n<p></p>\r\n<p>Best<br />\r\n千行团队</p>' WHERE id = 12;
+UPDATE message_template SET content = '<p>同学您好,<br  />\r\n您有{number}份“{title}”作业待完成,去做作业:{linkHtml}</p>\r\n<p></p>\r\n<p>Best<br />\r\n千行团队</p>' WHERE id = 13;
+UPDATE message_template SET content = '<p>同学您好,<br  />\r\n您已成功购买“{title}”服务,祝您在 千行 学习愉快~</p>\r\n<p></p>\r\n<p>Best<br />\r\n千行团队</p>' WHERE id = 14;
+UPDATE message_template SET content = '<p>您的好友{nickname}邀请您加入“千行GMAT”,{linkHtml}<br />\r\n<br />\r\n{content}</p>\r\n<p></p>\r\n<p>Best<br />\r\n千行团队</p>' WHERE id = 15;
+UPDATE message_template SET content = '<p>同学您好,<br  />\r\n您的“千行GMAT”账号更换绑定邮箱成功。</p>\r\n<p></p>\r\n<p>Best<br />\r\n千行团队</p>' WHERE id = 16;
+UPDATE message_template SET content = '<p>同学您好,<br  />\r\n您订阅的“{title}”已更新至版本{version},<br />\r\n更新日志:{description}<br />\r\n您也可以:{linkHtml}</p>\r\n<p></p>\r\n<p>Best<br />\r\n千行团队</p>' WHERE id = 17;
+UPDATE message_template SET content = '<p>同学您好,<br  />\r\n您的“千行GMAT”账号不再绑定本邮箱,您更换的新邮箱地址为:{email}</p>\r\n<p></p>\r\n<p>Best<br />\r\n千行团队</p>' WHERE id = 20;
+UPDATE message_template SET content = '<p>同学您好,<br  />\r\n您已完成实名认证,{useExpireDays}天VIP权限已赠送至您的账户,VIP有效期至{expireTime}.<br />\r\n我们将重视和保护您的隐私,祝您在 千行 学习愉快~</p>\r\n<p></p>\r\n<p>Best<br />\r\n千行团队</p>' WHERE id = 21;
+UPDATE message_template SET content = '<p>同学您好,<br  />\r\n您已成功购买“{titleJoin}”共{number}个商品,祝您在 千行 学习愉快~</p>\r\n<p></p>\r\n<p>Best<br />\r\n千行团队</p>' WHERE id = 22;
+UPDATE message_template SET content = '<p>同学您好,<br  />\r\n请于{expireDate}前开通“{title}”,过期后将无法正常开通使用。{linkHtml}</p>\r\n<p></p>\r\n<p>Best<br />\r\n千行团队</p>' WHERE id = 23;
+UPDATE message_template SET content = '<p>同学您好,<br  />\r\n请于{expireDate}前开通“{title}”,过期后将无法正常开通使用。{linkHtml}</p>\r\n<p></p>\r\n<p>Best<br />\r\n千行团队</p>' WHERE id = 24;
+UPDATE message_template SET content = '<p>同学您好,<br  />\r\n请于{expireDate}前开通“{title}”,过期后将无法正常开通使用。{linkHtml}</p>\r\n<p></p>\r\n<p>Best<br />\r\n千行团队</p>' WHERE id = 25;
+UPDATE message_template SET content = '<p>同学您好,<br  />\r\n您的“{title}”将于{days}天后过期,{linkHtml}</p>\r\n<p></p>\r\n<p>Best<br />\r\n千行团队</p>' WHERE id = 26;
+UPDATE message_template SET content = '<p>同学您好,<br  />\r\n您的“{title}”将于{days}天后过期,{linkHtml}</p>\r\n<p></p>\r\n<p>Best<br />\r\n千行团队</p>' WHERE id = 27;
+UPDATE message_template SET content = '<p>同学您好,<br  />\r\n您的“{title}”将于{days}天后过期,{linkHtml}</p>\r\n<p></p>\r\n<p>Best<br />\r\n千行团队</p>' WHERE id = 28;
+UPDATE message_template SET content = '<p>同学您好,<br  />\r\n数学机经{quantDescription},更新至版本{quantVersion};<br />\r\n逻辑机经{irDescription},更新至版本{irVersion};<br />\r\n阅读机经{rcDescription},更新至版本{rcVersion};<br />\r\n您可以:{linkHtml}</p>\r\n<p></p>\r\n<p>Best<br />\r\n千行团队</p>' WHERE id = 29;
+UPDATE message_template SET content = '<p>同学您好,<br  />\r\n您订阅的“{title}”已更新至版本{version},<br />\r\n更新日志:{description}<br />\r\n附件为最新版资料,您也可以:{linkHtml}</p>\r\n<p></p>\r\n<p>Best<br />\r\n千行团队</p>' WHERE id = 30;
+UPDATE message_template SET content = '<p>同学您好,<br  />\r\n您订阅的“{title}”已更新至版本{version},<br />\r\n更新日志:{description}<br />\r\n您也可以:{linkHtml}</p>\r\n<p></p>\r\n<p>Best<br />\r\n千行团队</p>' WHERE id = 31;
+UPDATE message_template SET content = '<p>同学您好,<br  />\r\n您已成功购买“{title}”服务,祝您在 千行 学习愉快~</p>\r\n<p></p>\r\n<p>Best<br />\r\n千行团队</p>' WHERE id = 37;
+UPDATE message_template SET content = '<p>同学您好,<br  />\r\n您已成功购买“{title}”服务,祝您在 千行 学习愉快~</p>\r\n<p></p>\r\n<p>Best<br />\r\n千行团队</p>' WHERE id = 38;
+UPDATE message_template SET content = '<p>同学您好,<br  />\r\n您已成功购买“{title}”服务,祝您在 千行 学习愉快~</p>\r\n<p></p>\r\n<p>Best<br />\r\n千行团队</p>' WHERE id = 39;
+UPDATE message_template SET content = '<p>同学您好,<br  />\r\n您已成功购买“{title}”服务,祝您在 千行 学习愉快~</p>\r\n<p></p>\r\n<p>Best<br />\r\n千行团队</p>' WHERE id = 51;
+UPDATE message_template SET content = '<p>同学您好,<br  />\r\n您已成功购买“{titleJoin}”共{number}个商品,祝您在 千行 学习愉快~</p>\r\n<p></p>\r\n<p>Best<br />\r\n千行团队</p>' WHERE id = 52;
+UPDATE message_template SET content = '<p>同学您好,<br  />\r\n您已成功购买“{titleJoin}”共{number}个商品,祝您在 千行 学习愉快~</p>\r\n<p></p>\r\n<p>Best<br />\r\n千行团队</p>' WHERE id = 53;
+UPDATE message_template SET content = '<p>同学您好,<br  />\r\n数学机经{quantDescription},更新至版本{quantVersion};<br />\r\n逻辑机经{irDescription},更新至版本{irVersion};<br />\r\n阅读机经{rcDescription},更新至版本{rcVersion};<br />\r\n附件为最新版机经,您也可以:{linkHtml}</p>\r\n<p></p>\r\n<p>Best<br />\r\n千行团队</p>' WHERE id = 67;
+UPDATE message_template SET content = '<p>同学您好,<br  />\r\n您的“{title}”将于{days}天后过期,{linkHtml}</p>\r\n<p></p>\r\n<p>Best<br />\r\n千行团队</p>' WHERE id = 69;

+ 34 - 1
server/gateway-api/src/main/java/com/qxgmat/controller/api/AuthController.java

@@ -116,6 +116,12 @@ public class AuthController {
         if (!smsHelp.verifyCode(userLoginDto.getArea(), userLoginDto.getMobile(), userLoginDto.getMobileVerifyCode(), session)) {
             throw new ParameterException("手机验证码错误!");
         }
+        if (userLoginDto.getEmail() != null){
+            User emailUser = usersService.getByEmail(userLoginDto.getEmail());
+            if (emailUser != null){
+                throw new ParameterException("该邮箱已绑定其他账号,请更换邮箱地址");
+            }
+        }
         try {
             String ip = Tools.getClientIp(request);
             usersService.register(userLoginDto.getArea(), userLoginDto.getMobile(), userLoginDto.getInviteCode(), userLoginDto.getEmail(), null, ip, aiHelp.parseIp(ip));
@@ -136,8 +142,15 @@ public class AuthController {
     public Response<MyDto> directWechatPc(
             @RequestParam(required = false, defaultValue = "") String code,
             HttpSession session, HttpServletRequest request) {
+        User user = (User) shiroHelp.getLoginUser();
         try{
-            shiroHelp.getSession().login(shiroHelp.oauth(code, "wechat_pc", true));
+            if (user == null){
+                // 直接二维码登录
+                shiroHelp.getSession().login(shiroHelp.oauth(code, "wechat_pc", true));
+            }else{
+                // 登录成功绑定二维码
+                usersService.Oauth(user, code, "wechat_pc", true);
+            }
         }catch (Exception e){
             throw new ParameterException("登录失败");
         }
@@ -159,6 +172,8 @@ public class AuthController {
             @RequestParam(required = false, defaultValue = "") boolean userInfo,
             HttpSession session, HttpServletRequest request) {
         try{
+            // userInfo:false,尝试登录
+            // userInfo:true,第一次登录,尝试授权,等待绑定手机号
             shiroHelp.getSession().login(shiroHelp.oauth(code, "wechat_native", userInfo));
         }catch (Exception e){
             throw new ParameterException("登录失败");
@@ -190,6 +205,12 @@ public class AuthController {
         if(openUser.getMobile() != null && openUser.getMobile().length() > 0)
             throw new SystemException("手机号已绑定");
 
+        if (userValidMobileDto.getEmail() != null){
+            User emailUser = usersService.getByEmail(userValidMobileDto.getEmail());
+            if (emailUser != null){
+                throw new ParameterException("该邮箱已绑定其他账号,请更换邮箱地址");
+            }
+        }
         try{
             // 创建新的账号,设定手机号,绑定第三方登录
             String ip = Tools.getClientIp(request);
@@ -231,6 +252,18 @@ public class AuthController {
         return ResponseHelp.success(true);
     }
 
+    @RequestMapping(value = "/valid/email", method = RequestMethod.GET)
+    @ApiOperation(value = "验证手机号", notes="查询手机对应账号", httpMethod = "GET")
+    public Response<Boolean> validEmail(
+            @RequestParam(required = true) String email
+    ){
+        User user = usersService.getByEmail(email);
+        if(user != null){
+            return ResponseHelp.success(false);
+        }
+        return ResponseHelp.success(true);
+    }
+
     @RequestMapping(value = "/valid/wechat", method = RequestMethod.GET)
     @ApiOperation(value = "验证手机号是否绑定微信", notes="查询手机对应账号", httpMethod = "GET")
     public Response<Boolean> validWechat(

+ 7 - 0
server/gateway-api/src/main/java/com/qxgmat/controller/api/MyController.java

@@ -236,6 +236,13 @@ public class MyController {
     public Response<Boolean> email(@RequestBody @Validated UserEmailDto dto, HttpSession session, HttpServletRequest request) {
         User user = (User) shiroHelp.getLoginUser();
         User in = usersService.get(user.getId());
+        if (in.getEmail().equals(dto.getEmail())) {
+            return ResponseHelp.success(true);
+        }
+        User other = usersService.getByEmail(dto.getEmail());
+        if (other != null){
+            throw new ParameterException("该邮箱已绑定其他账号,请更换邮箱地址。");
+        }
         usersService.edit(User.builder()
                 .id(user.getId())
                 .email(dto.getEmail())

+ 6 - 0
server/gateway-api/src/main/java/com/qxgmat/service/UsersService.java

@@ -271,6 +271,12 @@ public class UsersService extends AbstractService {
         return one(userMapper, user);
     }
 
+    // 通过邮箱获取用户
+    public User getByEmail(String email){
+        User user = User.builder().email(email).build();
+        return one(userMapper, user);
+    }
+
     // 通过身份证获取用户
     public User getByIdentity(String identity){
         User user = User.builder().realIdentity(identity).build();