Authored by 毕凯

Merge branch 'feature/newBindMobile' into 'release/6.5'

强绑定手机号



See merge request !1234
@@ -89,6 +89,8 @@ passport.use(new LocalStrategy({ @@ -89,6 +89,8 @@ passport.use(new LocalStrategy({
89 done({code: 4189}, null); 89 done({code: 4189}, null);
90 } else if (result.code && result.code === 510) { 90 } else if (result.code && result.code === 510) {
91 done(null, Object.assign(result.data, {weakPassword: true})); 91 done(null, Object.assign(result.data, {weakPassword: true}));
  92 + } else if (result.code && result.code === 50004) {
  93 + done(result, null);
92 } else if (result.code) { 94 } else if (result.code) {
93 done(result.message, null); 95 done(result.message, null);
94 } else { 96 } else {
@@ -13,6 +13,7 @@ const RegServiceModel = require('../models/reg-service'); @@ -13,6 +13,7 @@ const RegServiceModel = require('../models/reg-service');
13 const BindServiceModel = require('../models/bind-service'); 13 const BindServiceModel = require('../models/bind-service');
14 const AuthHelperModel = require('../models/auth-helper'); 14 const AuthHelperModel = require('../models/auth-helper');
15 const _ = require('lodash'); 15 const _ = require('lodash');
  16 +const headerModel = require('../../../doraemon/models/header'); // 头部model
16 17
17 const Sources = { 18 const Sources = {
18 qq: 'QQ', 19 qq: 'QQ',
@@ -275,9 +276,8 @@ const bind = { @@ -275,9 +276,8 @@ const bind = {
275 276
276 successPage: (req, res) => { 277 successPage: (req, res) => {
277 let refer = req.cookies.refer; 278 let refer = req.cookies.refer;
278 - let type = req.query.type;  
279 279
280 - if (!refer || /signin|login/.test(refer)) { 280 + if (!refer || /signin|login|\/bind\//.test(refer)) {
281 refer = helpers.urlFormat('/?go=1'); 281 refer = helpers.urlFormat('/?go=1');
282 } 282 }
283 283
@@ -286,7 +286,7 @@ const bind = { @@ -286,7 +286,7 @@ const bind = {
286 286
287 res.render('bind/success', { 287 res.render('bind/success', {
288 isPassportPage: true, 288 isPassportPage: true,
289 - successTip: type === 'bind' ? '恭喜您,第三方账号绑定手机号码成功!' : '恭喜您,第三方账号关联手机号码成功!', 289 + successTip: '恭喜您,绑定手机号码成功!',
290 goUrl: refer, 290 goUrl: refer,
291 module: 'passport', 291 module: 'passport',
292 page: 'bind-success', 292 page: 'bind-success',
@@ -320,6 +320,138 @@ const bind = { @@ -320,6 +320,138 @@ const bind = {
320 } else { 320 } else {
321 res.json({ code: 400, message: '', data: '' }); 321 res.json({ code: 400, message: '', data: '' });
322 } 322 }
  323 + },
  324 +
  325 + // 第三方绑定手机号页面
  326 + thirdBindMobilePage: (req, res) => {
  327 + let headerData = headerModel.setNav({
  328 + navTitle: '绑定手机号', // 标题
  329 + navBack: true, // 是否显示返回按钮
  330 + backUrl: helpers.urlFormat('/signin.html'), // 返回按钮对应的url
  331 + navBtn: false // 顶部下拉菜单选项
  332 + });
  333 +
  334 + res.render('bind/bind-mobile', {
  335 + captchaShow: req.yoho.captchaShow,
  336 + width750: true,
  337 + pageHeader: headerData,
  338 + localCss: true,
  339 + module: 'passport',
  340 + page: 'third-bind-mobile',
  341 + btnName: '绑定手机号',
  342 + areaCode: '+86', // 默认区号
  343 + countrys: req.ctx(RegServiceModel).getAreaData(), // 国别码
  344 + });
  345 + },
  346 +
  347 + // 第三方绑定手机号发送短信
  348 + thirdSendMsgApi: (req, res, next) => {
  349 + req.ctx(BindServiceModel).sendThirdBindMobileCodeOnly(req.body).then(result => {
  350 + if (_.get(result, 'code', 400) === 200) {
  351 + return next();
  352 + }
  353 + return res.json(result);
  354 + }).catch(next);
  355 + },
  356 +
  357 + // 第三方调用绑定接口
  358 + thirdBindMobileApi: (req, res, next) => {
  359 + if (_.isEmpty(req.body.open_id) || _.isEmpty(req.body.source_type)) {
  360 + return res.json({code: 401, data: {}, message: '请重新登录授权'});
  361 + }
  362 +
  363 + req.ctx(BindServiceModel).thirdBindMobile(req.body).then(result => {
  364 + if (_.get(result, 'code', 400) !== 200) {
  365 + return res.json(result);
  366 + }
  367 +
  368 + return req.ctx(AuthHelperModel).syncUserSession(
  369 + result.data.uid,
  370 + req,
  371 + res,
  372 + result.data.session_key
  373 + ).then(() => {
  374 + return res.json({code: 200, data: {}, message: 'success'});
  375 + });
  376 + }).catch(next);
  377 + },
  378 +
  379 + // 通过邮箱绑定手机号发送短信
  380 + sendMsgApi: (req, res, next) => {
  381 + req.ctx(BindServiceModel).sendChangeBindMobileCodeOnly(req.body).then(result => {
  382 + if (_.get(result, 'code', 400) === 200) {
  383 + return next();
  384 + }
  385 + return res.json(result);
  386 + }).catch(next);
  387 + },
  388 +
  389 + // 检查手机是否绑定
  390 + changeMobileCheckApi: (req, res, next) => {
  391 + req.ctx(BindServiceModel).changeMobileCheck(req.body).then(result => {
  392 + if (_.get(result, 'data.isBind', '') === 'N' &&
  393 + _.get(result, 'data.isRegister', '') === 'N') {
  394 + return next();
  395 + }
  396 + return res.json(result);
  397 + }).catch(next);
  398 + },
  399 +
  400 + // 通过邮箱强制绑定手机号页面
  401 + forceBindMobilePage: (req, res) => {
  402 + let headerData = headerModel.setNav({
  403 + navTitle: '绑定手机号', // 标题
  404 + navBack: true, // 是否显示返回按钮
  405 + backUrl: helpers.urlFormat('/signin.html'), // 返回按钮对应的url
  406 + navBtn: false // 顶部下拉菜单选项
  407 + });
  408 +
  409 + res.render('bind/bind-mobile', {
  410 + captchaShow: req.yoho.captchaShow,
  411 + width750: true,
  412 + pageHeader: headerData,
  413 + localCss: true,
  414 + module: 'passport',
  415 + page: 'bind-email-mobile',
  416 + btnName: '绑定手机号',
  417 + areaCode: '+86', // 默认区号
  418 + countrys: req.ctx(RegServiceModel).getAreaData(), // 国别码
  419 + });
  420 + },
  421 +
  422 + forceSendMsg: (req, res) => {
  423 + return res.json({code: 200, data: {}, message: 'success'});
  424 + },
  425 +
  426 + isCheckEmailPassword: (req, res, next) => {
  427 + if (!req.session.bindEmail || !req.session.bindPassword) {
  428 + return res.json({code: 401, data: {}, message: '请重新登录授权'});
  429 + }
  430 +
  431 + return next();
  432 + },
  433 +
  434 + // 调用绑定接口
  435 + forceBindMobileApi: (req, res, next) => {
  436 + req.ctx(BindServiceModel).bindEmailLoginMobile(Object.assign(req.body, {
  437 + email: req.session.bindEmail,
  438 + password: req.session.bindPassword,
  439 + })).then(result => {
  440 + if (_.get(result, 'code', 400) !== 200) {
  441 + return res.json(result);
  442 + }
  443 +
  444 + return req.ctx(AuthHelperModel).syncUserSession(
  445 + result.data.uid,
  446 + req,
  447 + res,
  448 + result.data.session_key
  449 + ).then(() => {
  450 + delete req.session.bindEmail;
  451 + delete req.session.bindPassword;
  452 + return res.json({code: 200, data: {}, message: 'success'});
  453 + });
  454 + }).catch(next);
323 } 455 }
324 }; 456 };
325 457
@@ -283,6 +283,13 @@ const local = { @@ -283,6 +283,13 @@ const local = {
283 }; 283 };
284 284
285 return res.json(obj); 285 return res.json(obj);
  286 + } else if (_.get(err, 'code', 400) === 50004) {
  287 + // 强制绑定手机号需要邮箱和密码
  288 + req.session.bindEmail = req.body.account;
  289 + req.session.bindPassword = req.body.password;
  290 + return res.json(Object.assign(err, {
  291 + url: '//m.yohobuy.com/passport/bind/forceBindMobile'
  292 + }));
286 } else { 293 } else {
287 let obj = { 294 let obj = {
288 code: 400, 295 code: 400,
@@ -9,6 +9,7 @@ @@ -9,6 +9,7 @@
9 9
10 const FROM = require('../../../config/from'); 10 const FROM = require('../../../config/from');
11 const PAGE = 'H5'; 11 const PAGE = 'H5';
  12 +const aes = require('./aes-pwd');
12 13
13 class BindServiceModel extends global.yoho.BaseModel { 14 class BindServiceModel extends global.yoho.BaseModel {
14 constructor(ctx) { 15 constructor(ctx) {
@@ -99,6 +100,63 @@ class BindServiceModel extends global.yoho.BaseModel { @@ -99,6 +100,63 @@ class BindServiceModel extends global.yoho.BaseModel {
99 area: area 100 area: area
100 }}); 101 }});
101 } 102 }
  103 +
  104 + // 强制绑定手机↓↓↓↓ -> 邮件登录绑定手机号发送短信
  105 + sendChangeBindMobileCodeOnly(params) {
  106 + return this.get({data: {
  107 + method: 'app.bind.sendChangeBindMobileCodeOnly',
  108 + business_line: 'yohobuy',
  109 + mobile: params.mobile || '',
  110 + area: params.area || '86'
  111 + }});
  112 + }
  113 +
  114 + // 校验手机号,判断这个手机号是否已经注册,是否下面有第三方
  115 + changeMobileCheck(params) {
  116 + return this.get({data: {
  117 + method: 'app.bind.changeMobileCheck',
  118 + business_line: 'yohobuy',
  119 + mobile: params.mobile || '',
  120 + area: params.area || '86',
  121 + code: params.code || ''
  122 + }});
  123 + }
  124 +
  125 + // 邮箱强制绑定手机号(邮箱强制绑定手机号场景使用)
  126 + bindEmailLoginMobile(params) {
  127 + return this.get({data: {
  128 + method: 'app.bind.bindEmailLoginMobile',
  129 + business_line: 'yohobuy',
  130 + mobile: params.mobile || '',
  131 + area: params.area || '86',
  132 + code: params.code,
  133 + email: params.email,
  134 + password: aes.aesPwd(params.password || '')
  135 + }});
  136 + }
  137 +
  138 + // 第三方绑定手机号发送短信
  139 + sendThirdBindMobileCodeOnly(params) {
  140 + return this.get({data: {
  141 + method: 'app.bind.sendThirdBindMobileCodeOnly',
  142 + business_line: 'yohobuy',
  143 + mobile: params.mobile || '',
  144 + area: params.area || '86'
  145 + }});
  146 + }
  147 +
  148 + // 第三方绑定手机号
  149 + thirdBindMobile(params) {
  150 + return this.get({data: {
  151 + method: 'app.bind.bindMobile',
  152 + business_line: 'yohobuy',
  153 + mobile: params.mobile || '',
  154 + area: params.area || '86',
  155 + code: params.code,
  156 + open_id: params.open_id,
  157 + source_type: params.source_type
  158 + }});
  159 + }
102 } 160 }
103 161
104 module.exports = BindServiceModel; 162 module.exports = BindServiceModel;
@@ -62,7 +62,7 @@ router.get('/passport/login/alipay', login.common.beforeLogin, login.alipay.logi @@ -62,7 +62,7 @@ router.get('/passport/login/alipay', login.common.beforeLogin, login.alipay.logi
62 router.get('/passport/login/alipay/callback', login.alipay.callback); 62 router.get('/passport/login/alipay/callback', login.alipay.callback);
63 63
64 // 登录绑定 64 // 登录绑定
65 -router.get('/passport/bind/index', validateCode.load, bind.indexPage); 65 +// router.get('/passport/bind/index', validateCode.load, bind.indexPage);
66 router.post('/passport/bind/bindCheck', bind.bindCheck); 66 router.post('/passport/bind/bindCheck', bind.bindCheck);
67 router.get('/passport/bind/code', validateCode.load, bind.codePage); 67 router.get('/passport/bind/code', validateCode.load, bind.codePage);
68 router.post('/passport/bind/sendBindMsg', 68 router.post('/passport/bind/sendBindMsg',
@@ -81,6 +81,30 @@ router.get('/passport/password/resetpage', reset.passwordResetPage); // 重置 @@ -81,6 +81,30 @@ router.get('/passport/password/resetpage', reset.passwordResetPage); // 重置
81 router.post('/passport/password/reset', reset.passwordReset); // 重置密码 81 router.post('/passport/password/reset', reset.passwordReset); // 重置密码
82 router.get('/passport/password/resetsuccess', reset.passwordResetOkPage); // 重置成功 82 router.get('/passport/password/resetsuccess', reset.passwordResetOkPage); // 重置成功
83 83
  84 +// 通过邮箱登录绑定手机号
  85 +router.get('/passport/bind/forceBindMobile', validateCode.load, bind.forceBindMobilePage);
  86 +router.post('/passport/bind/forceSendMsg',
  87 + validateCode.check,
  88 + bind.isCheckEmailPassword,
  89 + bind.sendMsgApi,
  90 + bind.forceSendMsg
  91 +);
  92 +router.post('/passport/bind/forceMobileCheck',
  93 + bind.isCheckEmailPassword,
  94 + bind.changeMobileCheckApi,
  95 + bind.forceBindMobileApi
  96 +);
  97 +router.post('/passport/bind/continueMobile', bind.isCheckEmailPassword, bind.forceBindMobileApi);
  98 +
  99 +// 第三方绑定手机号
  100 +router.get('/passport/bind/index', validateCode.load, bind.thirdBindMobilePage);
  101 +router.post('/passport/bind/thirdSendMsg', validateCode.check, bind.thirdSendMsgApi, bind.forceSendMsg);
  102 +router.post('/passport/bind/thirdMobileCheck',
  103 + bind.changeMobileCheckApi,
  104 + bind.thirdBindMobileApi
  105 +);
  106 +router.post('/passport/bind/thirdContinueMobile', bind.thirdBindMobileApi);
  107 +
84 /** 108 /**
85 * 密码找回 109 * 密码找回
86 */ 110 */
  1 +<div class="passport-bind-page">
  2 + <div class="safety-tip">
  3 + <i for="verifyCode" class="iconfont">&#xe71c;</i>
  4 + 您的账户存在安全风险,建议您绑定手机号码提升安全级别
  5 + </div>
  6 +
  7 + {{> passport/mobile-form-login}}
  8 +</div>
  1 +<div class="mobile-form-login">
  2 + <div class="form-group mobile">
  3 + <label for="mobile" class="iconfont">&#xe727;</label>
  4 + <select name="" id="countryCodeSelector" class="country-select">
  5 + {{# countrys}}
  6 + <option value={{areaCode}} {{#if selected}}selected{{/if}}>{{name}}</option>
  7 + {{/ countrys}}
  8 + </select>
  9 + <i class="iconfont arrow-icon">&#xe72f;</i>
  10 + <i class="line">|</i>
  11 + <input type="tel" name="mobile" placeholder="请输入手机号" class="mobile-input">
  12 + <i id="clearMobile" class="iconfont clear hide">&#xe72a;</i>
  13 + </div>
  14 + <div class="form-group verify-code">
  15 + <label for="verifyCode" class="iconfont">&#xe71c;</label>
  16 + <input type="text" name="verifyCode" placeholder="请输入验证码" class="verify-code-input">
  17 + <button id="getVerifyCodeBtn" class="get-verify-code">获取验证码</button>
  18 + </div>
  19 +
  20 + {{> use-geetest}}
  21 +
  22 + <button id="smsLoginBtn" class="sms-login-btn">
  23 + {{#if btnName}}
  24 + {{btnName}}
  25 + {{^}}
  26 + 登录
  27 + {{/if}}
  28 + </button>
  29 +</div>
@@ -12,10 +12,10 @@ const isTest = process.env.NODE_ENV === 'test'; @@ -12,10 +12,10 @@ const isTest = process.env.NODE_ENV === 'test';
12 12
13 const domains = { 13 const domains = {
14 14
15 - api: 'http://api.yoho.cn/',  
16 - service: 'http://service.yoho.cn/',  
17 - liveApi: 'http://testapi.live.yohops.com:9999/',  
18 - singleApi: 'http://api-test3.yohops.com:9999/', 15 + // api: 'http://api.yoho.cn/',
  16 + // service: 'http://service.yoho.cn/',
  17 + // liveApi: 'http://testapi.live.yohops.com:9999/',
  18 + // singleApi: 'http://api-test3.yohops.com:9999/',
19 19
20 // gray 20 // gray
21 // singleApi: 'http://single.gray.yohops.com/', 21 // singleApi: 'http://single.gray.yohops.com/',
@@ -24,10 +24,10 @@ const domains = { @@ -24,10 +24,10 @@ const domains = {
24 // platformApi: 'http://172.16.6.210:8088/', 24 // platformApi: 'http://172.16.6.210:8088/',
25 25
26 26
27 - // api: 'http://api-test3.yohops.com:9999/',  
28 - // service: 'http://service-test3.yohops.com:9999/',  
29 - // liveApi: 'http://testapi.live.yohops.com:9999/',  
30 - // singleApi: 'http://api-test3.yohops.com:9999/', 27 + api: 'http://api-test3.yohops.com:9999/',
  28 + service: 'http://service-test3.yohops.com:9999/',
  29 + liveApi: 'http://testapi.live.yohops.com:9999/',
  30 + singleApi: 'http://api-test3.yohops.com:9999/',
31 31
32 imSocket: 'ws://socket.yohobuy.com:10240', 32 imSocket: 'ws://socket.yohobuy.com:10240',
33 imCs: 'http://im.yohobuy.com/api', 33 imCs: 'http://im.yohobuy.com/api',
  1 +<div data-userverify="{{captchaShow}}" data-geetest="{{useGeetest}}" id="js-img-check" {{#unless useGeetest}} class="full-img-verify" {{/unless}}></div>
  1 +{{#if isBind}}
  2 +<div class="bind-title">
  3 +该手机已绑定Yoho!Family其他账号,
  4 +点击“继续”将解绑并绑定当前账号,
  5 +是否继续?
  6 +</div>
  7 +<div class="bind-subtitle">
  8 +解绑后原账号将不可使用该手机号登录!
  9 +</div>
  10 +{{else if isRegister}}
  11 +<div class="bind-title">
  12 +该账号已被注册,是否选择绑定?
  13 +点击“继续”原注册账号将被停用!
  14 +</div>
  15 +{{/if}}
  1 +require('passport/bind-mobile.page.css');
  2 +
  3 +const $ = require('yoho-jquery');
  4 +const BindEmailMobile = require('./bind/_email-bind-mobile.js');
  5 +
  6 +$(() => {
  7 + new BindEmailMobile();
  8 +});
  1 +import $ from 'yoho-jquery';
  2 +import tip from 'plugin/tip';
  3 +import Page from 'yoho-page';
  4 +import api from '../api';
  5 +import Validate from 'plugin/validata';
  6 +import dialog from 'plugin/dialog';
  7 +import bindDialogHbs from 'passport/bind-dialog-tip.hbs';
  8 +
  9 +const $captcha = $('#js-img-check');
  10 +const validate = new Validate($captcha, {
  11 + useREM: {
  12 + rootFontSize: 40,
  13 + picWidth: 150
  14 + }
  15 +});
  16 +const showErrTip = tip.show;
  17 +
  18 +class EmailBindMobile extends Page {
  19 + constructor() {
  20 + super();
  21 +
  22 + this.selector = {
  23 + itime: 0,
  24 + countrySelect: $('.mobile-form-login select.country-select'),
  25 + mobileInput: $('.mobile-form-login input.mobile-input'),
  26 + clearMobile: $('.mobile-form-login .clear'),
  27 + verifyCodeInput: $('.mobile-form-login input.verify-code-input'),
  28 + verifyCodeBtn: $('.mobile-form-login .get-verify-code'),
  29 + loginBtn: $('.mobile-form-login .sms-login-btn'),
  30 + };
  31 +
  32 + this.init();
  33 + }
  34 +
  35 + init() {
  36 + if ($captcha.data('userverify')) {
  37 + validate.init();
  38 + }
  39 +
  40 + this.bindEvents();
  41 + }
  42 +
  43 + bindEvents() {
  44 + this.selector.countrySelect.on('change', this.changeBtnStatus.bind(this));
  45 + this.selector.mobileInput.on('input', this.changeBtnStatus.bind(this));
  46 + this.selector.clearMobile.on('click', this.clearMobile.bind(this));
  47 + this.selector.verifyCodeInput.on('input', this.changeBtnStatus.bind(this, true));
  48 + this.selector.verifyCodeBtn.on('click', this.getVerifyCode.bind(this));
  49 + this.selector.loginBtn.on('click', this.login.bind(this));
  50 + }
  51 +
  52 + /**
  53 + * 清除输入的手机号
  54 + */
  55 + clearMobile() {
  56 + this.selector.mobileInput.val('');
  57 + this.selector.verifyCodeInput.val('');
  58 + this.selector.clearMobile.addClass('hide');
  59 + this.selector.countrySelect.trigger('change');
  60 + }
  61 +
  62 + /**
  63 + * 输入监听,改变按钮状态
  64 + */
  65 + changeBtnStatus(isVerifycode) {
  66 + let areaCode = $.trim(this.selector.countrySelect.val());
  67 + let phoneNum = $.trim(this.selector.mobileInput.val());
  68 + let verifyCode = $.trim(this.selector.verifyCodeInput.val());
  69 +
  70 + if (!api.phoneRegx[areaCode]) {
  71 + return showErrTip('出错了,请重新刷新页面');
  72 + }
  73 +
  74 + if (phoneNum) {
  75 + this.selector.clearMobile.removeClass('hide');
  76 + }
  77 +
  78 + // 验证码输入框单独处理
  79 + if (isVerifycode === true) {
  80 + // 提交表单按钮激活
  81 + if (verifyCode && api.phoneRegx[areaCode].test(phoneNum)) {
  82 + this.selector.loginBtn.addClass('active');
  83 + } else {
  84 + this.selector.loginBtn.removeClass('active');
  85 + }
  86 +
  87 + return;
  88 + }
  89 +
  90 + clearInterval(this.selector.itime);
  91 + this.selector.verifyCodeBtn.text('获取验证码');
  92 +
  93 + if (api.phoneRegx[areaCode].test(phoneNum)) {
  94 + this.selector.verifyCodeBtn.addClass('active');
  95 + if (verifyCode) {
  96 + this.selector.loginBtn.addClass('active');
  97 + }
  98 + } else {
  99 + this.selector.verifyCodeBtn.removeClass('active');
  100 + this.selector.loginBtn.removeClass('active');
  101 + }
  102 + }
  103 +
  104 + /**
  105 + * 获取验证码倒计时
  106 + */
  107 + countDown(during) {
  108 + let count = parseInt(during, 10) || 59;
  109 +
  110 + if (!this.selector.verifyCodeBtn.hasClass('active')) {
  111 + return;
  112 + }
  113 +
  114 + this.selector.verifyCodeBtn.removeClass('active');
  115 +
  116 + this.selector.itime = setInterval(() => {
  117 + window.setCookie('intTimer', count, {path: '/' });
  118 +
  119 + if (count <= 0) {
  120 + this.selector.verifyCodeBtn.text('重新获取').addClass('active');
  121 + clearInterval(this.selector.itime);
  122 + } else {
  123 + this.selector.verifyCodeBtn.text('重新获取 (' + count-- + '秒)');
  124 + }
  125 +
  126 + }, 1000);
  127 + }
  128 +
  129 +
  130 + /**
  131 + * 获取验证码
  132 + */
  133 + getVerifyCode() {
  134 + let pn = $.trim(this.selector.mobileInput.val());
  135 + let area = $.trim(this.selector.countrySelect.val());
  136 +
  137 + if (!this.selector.verifyCodeBtn.hasClass('active') ||
  138 + this.selector.verifyCodeBtn.data('oneClick')) {
  139 + return;
  140 + }
  141 +
  142 + if (!api.phoneRegx[area]) {
  143 + return showErrTip('出错了,请重新刷新页面');
  144 + } else if (!api.phoneRegx[area].test(pn)) {
  145 + return showErrTip('手机号格式不正确,请重新输入');
  146 + }
  147 +
  148 + this.selector.verifyCodeBtn.data('oneClick', true);
  149 +
  150 + validate.getResults().then(result => {
  151 + let params = {
  152 + area: area.replace('+', ''),
  153 + mobile: pn
  154 + };
  155 +
  156 + $.extend(params, result);
  157 +
  158 + this.ajax({
  159 + url: '/passport/bind/forceSendMsg',
  160 + type: 'POST',
  161 + data: params
  162 + }).then(codeResult => {
  163 + this.selector.verifyCodeBtn.data('oneClick', false);
  164 + validate.type === 2 && validate.refresh();
  165 + if (codeResult.code === 200) {
  166 + this.countDown();
  167 + return;
  168 + } else {
  169 + showErrTip(codeResult.message);
  170 + }
  171 +
  172 + (codeResult.changeCaptcha && validate.type !== 2) && validate.refresh();
  173 + }).catch(() => {
  174 + this.selector.verifyCodeBtn.data('oneClick', false);
  175 + showErrTip('出错了,请重试');
  176 + validate.refresh();
  177 + });
  178 + });
  179 + }
  180 +
  181 + login() {
  182 + let pn = $.trim(this.selector.mobileInput.val());
  183 + let area = $.trim(this.selector.countrySelect.val());
  184 + let verifyCode = $.trim(this.selector.verifyCodeInput.val());
  185 +
  186 + if (!this.selector.loginBtn.hasClass('active')) {
  187 + return;
  188 + }
  189 +
  190 + if (!api.phoneRegx[area]) {
  191 + return showErrTip('出错了,请重新刷新页面');
  192 + } else if (!api.phoneRegx[area].test(pn)) {
  193 + return showErrTip('手机号格式不正确,请重新输入');
  194 + }
  195 +
  196 + this.selector.loginBtn.data('oneClick', true);
  197 +
  198 + let params = {
  199 + area: area.replace('+', ''),
  200 + mobile: pn,
  201 + code: verifyCode,
  202 + };
  203 +
  204 + this.ajax({
  205 + url: '/passport/bind/forceMobileCheck',
  206 + type: 'POST',
  207 + data: params
  208 + }).then(codeResult => {
  209 + this.selector.loginBtn.data('oneClick', false);
  210 +
  211 + if (codeResult.code === 200) {
  212 + this.continueBind(
  213 + $.extend({isBind: 'N', isRegister: 'N'}, codeResult.data),
  214 + params
  215 + );
  216 + } else {
  217 + showErrTip(codeResult.message);
  218 + }
  219 + }).catch(() => {
  220 + this.selector.loginBtn.data('oneClick', false);
  221 + showErrTip('出错了,请重试');
  222 + });
  223 + }
  224 +
  225 + continueBind(codeResult, params) {
  226 + let that = this;
  227 + let goUrl = '/passport/bind/success';
  228 + let bindParams = {
  229 + isBind: codeResult.isBind === 'Y',
  230 + isRegister: codeResult.isRegister === 'Y'
  231 + };
  232 +
  233 + // 如果没有绑定没有注册,直接注册
  234 + if (!(bindParams.isBind || bindParams.isRegister)) {
  235 + document.location.href = goUrl;
  236 + return;
  237 + }
  238 +
  239 + dialog.showDialog({
  240 + dialogText: bindDialogHbs(bindParams),
  241 + fast: true,
  242 + hasFooter: {
  243 + leftBtnText: '去登录',
  244 + rightBtnText: '继续'
  245 + }
  246 + }, function() {
  247 + return that.ajax({
  248 + url: '/passport/bind/continueMobile',
  249 + type: 'POST',
  250 + data: params
  251 + }).then(cresult => {
  252 + if (cresult.code === 200) {
  253 + document.location.href = goUrl;
  254 + return;
  255 + } else {
  256 + showErrTip(cresult.message);
  257 + }
  258 + }).catch(() => {
  259 + showErrTip('出错了,请重试');
  260 + });
  261 + }, function() {
  262 + document.location.href = '//m.yohobuy.com/signin.html';
  263 + });
  264 +
  265 + $('.dialog-wrapper').addClass('s-dialog-bind');
  266 + }
  267 +}
  268 +
  269 +module.exports = EmailBindMobile;
  1 +import $ from 'yoho-jquery';
  2 +import tip from 'plugin/tip';
  3 +import Page from 'yoho-page';
  4 +import api from '../api';
  5 +import Validate from 'plugin/validata';
  6 +import dialog from 'plugin/dialog';
  7 +import bindDialogHbs from 'passport/bind-dialog-tip.hbs';
  8 +
  9 +const $captcha = $('#js-img-check');
  10 +const validate = new Validate($captcha, {
  11 + useREM: {
  12 + rootFontSize: 40,
  13 + picWidth: 150
  14 + }
  15 +});
  16 +const showErrTip = tip.show;
  17 +
  18 +class ThirdBindMobile extends Page {
  19 + constructor() {
  20 + super();
  21 +
  22 + this.selector = {
  23 + itime: 0,
  24 + openId: $.trim($.queryString().openId),
  25 + sourceType: $.trim($.queryString().sourceType),
  26 + countrySelect: $('.mobile-form-login select.country-select'),
  27 + mobileInput: $('.mobile-form-login input.mobile-input'),
  28 + clearMobile: $('.mobile-form-login .clear'),
  29 + verifyCodeInput: $('.mobile-form-login input.verify-code-input'),
  30 + verifyCodeBtn: $('.mobile-form-login .get-verify-code'),
  31 + loginBtn: $('.mobile-form-login .sms-login-btn'),
  32 + };
  33 +
  34 + this.init();
  35 + }
  36 +
  37 + init() {
  38 + if ($captcha.data('userverify')) {
  39 + validate.init();
  40 + }
  41 +
  42 + this.bindEvents();
  43 + }
  44 +
  45 + bindEvents() {
  46 + this.selector.countrySelect.on('change', this.changeBtnStatus.bind(this));
  47 + this.selector.mobileInput.on('input', this.changeBtnStatus.bind(this));
  48 + this.selector.clearMobile.on('click', this.clearMobile.bind(this));
  49 + this.selector.verifyCodeInput.on('input', this.changeBtnStatus.bind(this, true));
  50 + this.selector.verifyCodeBtn.on('click', this.getVerifyCode.bind(this));
  51 + this.selector.loginBtn.on('click', this.login.bind(this));
  52 + }
  53 +
  54 + /**
  55 + * 清除输入的手机号
  56 + */
  57 + clearMobile() {
  58 + this.selector.mobileInput.val('');
  59 + this.selector.verifyCodeInput.val('');
  60 + this.selector.clearMobile.addClass('hide');
  61 + this.selector.countrySelect.trigger('change');
  62 + }
  63 +
  64 + /**
  65 + * 输入监听,改变按钮状态
  66 + */
  67 + changeBtnStatus(isVerifycode) {
  68 + let areaCode = $.trim(this.selector.countrySelect.val());
  69 + let phoneNum = $.trim(this.selector.mobileInput.val());
  70 + let verifyCode = $.trim(this.selector.verifyCodeInput.val());
  71 +
  72 + if (!api.phoneRegx[areaCode]) {
  73 + return showErrTip('出错了,请重新刷新页面');
  74 + }
  75 +
  76 + if (phoneNum) {
  77 + this.selector.clearMobile.removeClass('hide');
  78 + }
  79 +
  80 + // 验证码输入框单独处理
  81 + if (isVerifycode === true) {
  82 + // 提交表单按钮激活
  83 + if (verifyCode && api.phoneRegx[areaCode].test(phoneNum)) {
  84 + this.selector.loginBtn.addClass('active');
  85 + } else {
  86 + this.selector.loginBtn.removeClass('active');
  87 + }
  88 +
  89 + return;
  90 + }
  91 +
  92 + clearInterval(this.selector.itime);
  93 + this.selector.verifyCodeBtn.text('获取验证码');
  94 +
  95 + if (api.phoneRegx[areaCode].test(phoneNum)) {
  96 + this.selector.verifyCodeBtn.addClass('active');
  97 + if (verifyCode) {
  98 + this.selector.loginBtn.addClass('active');
  99 + }
  100 + } else {
  101 + this.selector.verifyCodeBtn.removeClass('active');
  102 + this.selector.loginBtn.removeClass('active');
  103 + }
  104 + }
  105 +
  106 + /**
  107 + * 获取验证码倒计时
  108 + */
  109 + countDown(during) {
  110 + let count = parseInt(during, 10) || 59;
  111 +
  112 + if (!this.selector.verifyCodeBtn.hasClass('active')) {
  113 + return;
  114 + }
  115 +
  116 + this.selector.verifyCodeBtn.removeClass('active');
  117 +
  118 + this.selector.itime = setInterval(() => {
  119 + window.setCookie('intTimer', count, {path: '/' });
  120 +
  121 + if (count <= 0) {
  122 + this.selector.verifyCodeBtn.text('重新获取').addClass('active');
  123 + clearInterval(this.selector.itime);
  124 + } else {
  125 + this.selector.verifyCodeBtn.text('重新获取 (' + count-- + '秒)');
  126 + }
  127 +
  128 + }, 1000);
  129 + }
  130 +
  131 +
  132 + /**
  133 + * 获取验证码
  134 + */
  135 + getVerifyCode() {
  136 + let pn = $.trim(this.selector.mobileInput.val());
  137 + let area = $.trim(this.selector.countrySelect.val());
  138 +
  139 + if (!this.selector.verifyCodeBtn.hasClass('active') ||
  140 + this.selector.verifyCodeBtn.data('oneClick')) {
  141 + return;
  142 + }
  143 +
  144 + if (!api.phoneRegx[area]) {
  145 + return showErrTip('出错了,请重新刷新页面');
  146 + } else if (!api.phoneRegx[area].test(pn)) {
  147 + return showErrTip('手机号格式不正确,请重新输入');
  148 + }
  149 +
  150 + this.selector.verifyCodeBtn.data('oneClick', true);
  151 +
  152 + validate.getResults().then(result => {
  153 + let params = {
  154 + area: area.replace('+', ''),
  155 + mobile: pn
  156 + };
  157 +
  158 + $.extend(params, result);
  159 +
  160 + this.ajax({
  161 + url: '/passport/bind/thirdSendMsg',
  162 + type: 'POST',
  163 + data: params
  164 + }).then(codeResult => {
  165 + this.selector.verifyCodeBtn.data('oneClick', false);
  166 + validate.type === 2 && validate.refresh();
  167 + if (codeResult.code === 200) {
  168 + this.countDown();
  169 + return;
  170 + } else {
  171 + showErrTip(codeResult.message);
  172 + }
  173 +
  174 + (codeResult.changeCaptcha && validate.type !== 2) && validate.refresh();
  175 + }).catch(() => {
  176 + this.selector.verifyCodeBtn.data('oneClick', false);
  177 + showErrTip('出错了,请重试');
  178 + validate.refresh();
  179 + });
  180 + });
  181 + }
  182 +
  183 + login() {
  184 + let pn = $.trim(this.selector.mobileInput.val());
  185 + let area = $.trim(this.selector.countrySelect.val());
  186 + let verifyCode = $.trim(this.selector.verifyCodeInput.val());
  187 +
  188 + if (!this.selector.loginBtn.hasClass('active')) {
  189 + return;
  190 + }
  191 +
  192 + if (!api.phoneRegx[area]) {
  193 + return showErrTip('出错了,请重新刷新页面');
  194 + } else if (!api.phoneRegx[area].test(pn)) {
  195 + return showErrTip('手机号格式不正确,请重新输入');
  196 + }
  197 +
  198 + this.selector.loginBtn.data('oneClick', true);
  199 +
  200 + let params = {
  201 + area: area.replace('+', ''),
  202 + mobile: pn,
  203 + code: verifyCode,
  204 + open_id: this.selector.openId,
  205 + source_type: this.selector.sourceType,
  206 + };
  207 +
  208 + this.ajax({
  209 + url: '/passport/bind/thirdMobileCheck',
  210 + type: 'POST',
  211 + data: params
  212 + }).then(codeResult => {
  213 + this.selector.loginBtn.data('oneClick', false);
  214 +
  215 + if (codeResult.code === 200) {
  216 + this.continueBind(
  217 + $.extend({isBind: 'N', isRegister: 'N'}, codeResult.data),
  218 + params
  219 + );
  220 + } else {
  221 + showErrTip(codeResult.message);
  222 + }
  223 + }).catch(() => {
  224 + this.selector.loginBtn.data('oneClick', false);
  225 + showErrTip('出错了,请重试');
  226 + });
  227 + }
  228 +
  229 + continueBind(codeResult, params) {
  230 + let that = this;
  231 + let goUrl = '/passport/bind/success';
  232 + let bindParams = {
  233 + isBind: codeResult.isBind === 'Y',
  234 + isRegister: codeResult.isRegister === 'Y'
  235 + };
  236 +
  237 + // 如果没有绑定没有注册,直接注册
  238 + if (!(bindParams.isBind || bindParams.isRegister)) {
  239 + document.location.href = goUrl;
  240 + return;
  241 + }
  242 +
  243 + dialog.showDialog({
  244 + dialogText: bindDialogHbs(bindParams),
  245 + fast: true,
  246 + hasFooter: {
  247 + leftBtnText: '去登录',
  248 + rightBtnText: '继续'
  249 + }
  250 + }, function() {
  251 + return that.ajax({
  252 + url: '/passport/bind/thirdContinueMobile',
  253 + type: 'POST',
  254 + data: params
  255 + }).then(cresult => {
  256 + if (cresult.code === 200) {
  257 + document.location.href = goUrl;
  258 + return;
  259 + } else {
  260 + showErrTip(cresult.message);
  261 + }
  262 + }).catch(() => {
  263 + showErrTip('出错了,请重试');
  264 + });
  265 + }, function() {
  266 + document.location.href = '//m.yohobuy.com/signin.html';
  267 + });
  268 +
  269 + $('.dialog-wrapper').addClass('s-dialog-bind');
  270 + }
  271 +}
  272 +
  273 +module.exports = ThirdBindMobile;
@@ -139,7 +139,7 @@ class Login { @@ -139,7 +139,7 @@ class Login {
139 localStorage.loginJumpUrl = $('#account').val(); 139 localStorage.loginJumpUrl = $('#account').val();
140 localStorage.loginJump = 'true'; 140 localStorage.loginJump = 'true';
141 location.href = data.url; 141 location.href = data.url;
142 - } else if (data.code === 510) { 142 + } else if (data.code === 510 || data.code === 50004) {
143 location.href = data.url; 143 location.href = data.url;
144 } else { 144 } else {
145 $captcha.data('userverify', data.captchaShow); 145 $captcha.data('userverify', data.captchaShow);
@@ -100,7 +100,7 @@ function loginAuth(params, acc) { @@ -100,7 +100,7 @@ function loginAuth(params, acc) {
100 localStorage.loginJumpUrl = $('#account').val(); 100 localStorage.loginJumpUrl = $('#account').val();
101 localStorage.loginJump = 'true'; 101 localStorage.loginJump = 'true';
102 location.href = data.url; 102 location.href = data.url;
103 - } else if (data.code === 510) { 103 + } else if (data.code === 510 || data.code === 50004) {
104 location.href = data.url; 104 location.href = data.url;
105 } else { 105 } else {
106 $captcha.data('userverify', data.captchaShow); 106 $captcha.data('userverify', data.captchaShow);
  1 +require('passport/bind-mobile.page.css');
  2 +
  3 +const $ = require('yoho-jquery');
  4 +const ThirdEmailMobile = require('./bind/_third-bind-mobile.js');
  5 +
  6 +$(() => {
  7 + new ThirdEmailMobile();
  8 +});
@@ -836,7 +836,6 @@ @@ -836,7 +836,6 @@
836 } 836 }
837 837
838 > .dialog-content { 838 > .dialog-content {
839 -  
840 .safe-check-tip { 839 .safe-check-tip {
841 font-size: 22px; 840 font-size: 22px;
842 color: #b0b0b0; 841 color: #b0b0b0;
  1 +@import "layout/img-check";
  2 +
  3 +$disable-gray: #b0b0b0;
  4 +
  5 +.mobile-form-login {
  6 + padding: 100px 45px 45px;
  7 +
  8 + .active {
  9 + background-color: #444 !important;
  10 + }
  11 +
  12 + > .form-group {
  13 + border-bottom: 1px solid #e0e0e0;
  14 + height: 50px;
  15 +
  16 + > label {
  17 + font-size: 26px;
  18 + margin-right: 36px;
  19 + }
  20 +
  21 + > input {
  22 + width: 400px;
  23 + border: none;
  24 +
  25 + &.mobile-input {
  26 + width: 350px;
  27 + }
  28 +
  29 + &.verify-code-input {
  30 + width: 350px;
  31 + }
  32 + }
  33 +
  34 + > i {
  35 + float: right;
  36 +
  37 + &.line {
  38 + float: none;
  39 + margin-right: 20px;
  40 + }
  41 + }
  42 +
  43 + &.mobile {
  44 + margin-bottom: 62px;
  45 +
  46 + > label {
  47 + margin-right: 30px;
  48 + }
  49 +
  50 + > .country-select {
  51 + width: 140px;
  52 + appearance: none;
  53 + border: none;
  54 + background-color: transparent;
  55 + }
  56 +
  57 + > .arrow-icon {
  58 + color: #444;
  59 + float: none;
  60 + font-size: 12px;
  61 + }
  62 +
  63 + > .clear {
  64 + color: #e0e0e0;
  65 + margin-right: 4px;
  66 + margin-top: 10px;
  67 + }
  68 + }
  69 +
  70 + .country-code {
  71 + width: 98px;
  72 + height: 22px;
  73 + font-size: 28px;
  74 + line-height: 1.14;
  75 + color: #444;
  76 + background-color: transparent;
  77 + margin-right: 20px;
  78 + }
  79 +
  80 + > .get-verify-code {
  81 + padding: 0 16px;
  82 + height: 50px;
  83 + line-height: 50px;
  84 + border-radius: 25px;
  85 + background-color: $disable-gray;
  86 + color: #fff;
  87 + font-size: 22px;
  88 + float: right;
  89 + margin-top: -8px;
  90 + min-width: 187px;
  91 + }
  92 + }
  93 +
  94 + > .verify-code {
  95 + margin-bottom: 0;
  96 + }
  97 +
  98 + .sms-login-btn {
  99 + width: 100%;
  100 + height: 70px;
  101 + border-radius: 4px;
  102 + background-color: $disable-gray;
  103 + margin-top: 40px;
  104 + font-size: 32px;
  105 + color: #fff;
  106 + }
  107 +}
  1 +@import "mobile-form-login";
  2 +
  3 +.passport-bind-page {
  4 + background-color: #fff;
  5 +
  6 + .safety-tip {
  7 + line-height: 70px;
  8 + height: 70px;
  9 + padding: 0 30px;
  10 + font-size: 24px;
  11 + background-color: #ff575c;
  12 + color: #fff;
  13 + opacity: 0.8;
  14 + }
  15 +}
  16 +
  17 +.s-dialog-bind {
  18 + .bind-title {
  19 + font-size: 28px;
  20 + text-align: center;
  21 + color: #444;
  22 + }
  23 +
  24 + .bind-subtitle {
  25 + font-size: 24px;
  26 + text-align: left;
  27 + color: #b0b0b0;
  28 + margin-top: 25px;
  29 + }
  30 +
  31 + .dialog-box {
  32 + background-color: #fff;
  33 + }
  34 +}