Authored by 陈轩

Merge branch 'feature/phone-login' into release/4.9.2

  1 +/* eslint no-unused-vars: ["error", { "args": "none" }] */
1 /** 2 /**
2 * 登录 3 * 登录
3 * @author: Bi Kai<kai.bi@yoho.cn> 4 * @author: Bi Kai<kai.bi@yoho.cn>
@@ -93,6 +94,7 @@ const local = { @@ -93,6 +94,7 @@ const local = {
93 backUrl: 'javascript:history.go(-1)', // eslint-disable-line 94 backUrl: 'javascript:history.go(-1)', // eslint-disable-line
94 showHeaderImg: true, // 控制显示头部图片 95 showHeaderImg: true, // 控制显示头部图片
95 isPassportPage: true, // 模板中模块标识 96 isPassportPage: true, // 模板中模块标识
  97 + smsLoginUrl: '/passport/sms_login',
96 registerUrl: '/passport/reg/index', // 注册的URL链接 98 registerUrl: '/passport/reg/index', // 注册的URL链接
97 aliLoginUrl: '/passport/login/alipay', // 支付宝快捷登录的URL链接 99 aliLoginUrl: '/passport/login/alipay', // 支付宝快捷登录的URL链接
98 weiboLoginUrl: '/passport/login/sina', // 微博登录的URL链接 100 weiboLoginUrl: '/passport/login/sina', // 微博登录的URL链接
  1 +/* eslint no-unused-vars: ["error", { "args": "none" }] */
  2 +'use strict';
  3 +const helpers = global.yoho.helpers;
  4 +const cookie = global.yoho.cookie;
  5 +const RegService = require('../models/reg-service');
  6 +const PhoneService = require('../models/phone-service');
  7 +const AuthHelper = require('../models/auth-helper');
  8 +
  9 +// constrant
  10 +const CODE_REQUIRED = '请输入校验码';
  11 +const PASSWORD_REQUIRED = '请输入密码';
  12 +const BAD_PASSWORD = '密码格式不正确';
  13 +const TOO_MANY = '请求太频繁';
  14 +const LOGIN_SUCCSS = '登录成功';
  15 +const VERIFY_ERROR = '校验失败';
  16 +
  17 +exports.beforeIn = (req, res, next) => {
  18 + if (!req.xhr && req.user.uid) {
  19 + return res.redirect(req.cookies.refer);
  20 + }
  21 +
  22 + next();
  23 +};
  24 +
  25 +// 短信登录 第一步: 展现页面
  26 +const _step1 = (req, res, next) => {
  27 + let template = 'sms/login';
  28 + let viewData = {
  29 + module: 'passport',
  30 + page: 'sms-login',
  31 + isPassportPage: true,
  32 + headerText: '手机号码快捷登录',
  33 + areaCode: '+86', // 默认的区号
  34 + countrys: RegService.getAreaData() // 地区信息列表
  35 + };
  36 +
  37 + res.render(template, viewData);
  38 +};
  39 +
  40 +// 短信登录 第二步: 输入 校验码
  41 +const _step2 = (req, res, next) => {
  42 + const mobile = req.session.smsLogin.mobile;
  43 + const area = req.session.smsLogin.area;
  44 + const interval = req.session.smsLogin.interval;
  45 +
  46 + const template = 'sms/check';
  47 + const viewData = {
  48 + module: 'passport',
  49 + page: 'sms-check',
  50 + backUrl: '/passport/sms_login?step=1',
  51 + isPassportPage: true,
  52 + headerText: '手机号码快捷登录',
  53 + canResend: interval < Date.now(),
  54 + mobile,
  55 + area
  56 + };
  57 +
  58 + res.render(template, viewData);
  59 +};
  60 +
  61 +// 短信登录 第三步: 设置密码 (针对 改手机未注册用户)
  62 +const _step3 = (req, res, next) => {
  63 + const template = 'sms/password';
  64 + const viewData = {
  65 + module: 'passport',
  66 + page: 'sms-password',
  67 + backUrl: '/passport/sms_login?step=2',
  68 + isPassportPage: true,
  69 + headerText: '设置密码'
  70 + };
  71 +
  72 + res.render(template, viewData);
  73 +};
  74 +
  75 +// 短信 登录
  76 +exports.loginPage = (req, res, next) => {
  77 + let step = Number(req.query.step) || 1;
  78 + let smsLoginStep = req.session.smsLoginStep || 1;
  79 +
  80 + if (step === 2 && smsLoginStep !== 2) {
  81 + return res.redirect(req.path);
  82 + }
  83 +
  84 + if (step === 3 && smsLoginStep !== 3) {
  85 + return res.redirect(req.path);
  86 + }
  87 +
  88 + switch (step) {
  89 + case 2:
  90 + _step2(req, res, next);
  91 + break;
  92 + case 3:
  93 + _step3(req, res, next);
  94 + break;
  95 + case 1:
  96 + default:
  97 + _step1(req, res, next);
  98 + }
  99 +};
  100 +
  101 +exports.tokenBefore = (req, res, next) => {
  102 + let area = req.query.area = (req.query.area || '').trim();
  103 + let mobile = req.query.mobile = (req.query.mobile || '').trim();
  104 +
  105 + if (!req.xhr) {
  106 + return next(404);
  107 + }
  108 +
  109 + if (req.session.smsLogin && req.session.smsLogin.interval > Date.now()) {
  110 + return res.json({
  111 + code: 429,
  112 + message: TOO_MANY
  113 + });
  114 + }
  115 +
  116 +
  117 + if ([area, mobile].some(val => val === '')) {
  118 + return res.json({
  119 + code: 401,
  120 + message: '请求参数,无法处理'
  121 + });
  122 + }
  123 +
  124 + next();
  125 +};
  126 +
  127 +// AJAX 获取验证码
  128 +exports.token = (req, res, next) => {
  129 + let mobile = req.query.area;
  130 + let area = req.query.mobile;
  131 +
  132 + PhoneService.sendSMS(mobile, area, 1).then(result => {
  133 + if (result.code === 200) {
  134 + req.session.smsLogin = {
  135 + interval: Date.now() + 60 * 1000, // 重发验证码 间隔: 60s
  136 + area,
  137 + mobile
  138 + };
  139 + req.session.smsLoginStep = 2; // 进入短信登录 step2
  140 +
  141 + result.redirect = '/passport/sms_login?step=2';
  142 + res.json(result);
  143 + return;
  144 + }
  145 +
  146 + res.json(result);
  147 + });
  148 +};
  149 +
  150 +exports.checkBefore = (req, res, next) => {
  151 + let code = req.query.code = (req.query.code || '').trim();
  152 +
  153 + if (!req.xhr && req.session.smsLoginStep !== 2) {
  154 + return next(404);
  155 + }
  156 +
  157 + if (!code) {
  158 + return res.json({
  159 + code: 404,
  160 + message: CODE_REQUIRED
  161 + });
  162 + }
  163 +
  164 + next();
  165 +};
  166 +
  167 +// AJAX 校验验证码 in step2
  168 +exports.check = (req, res, next) => {
  169 + const code = req.query.code;
  170 + const mobile = req.session.smsLogin.mobile;
  171 + const area = req.session.smsLogin.area;
  172 + const shopping_key = cookie.getShoppingKey(req); // eslint-disable-line
  173 +
  174 +
  175 + Promise.all([
  176 + PhoneService.checkUserPhoneExist(mobile, area),
  177 + PhoneService.verifySMS(mobile, area, code, 1)
  178 + ])
  179 + .then(result => {
  180 + let r1 = result[0] || {};
  181 + let r2 = result[1] || {};
  182 + let redirect;
  183 +
  184 + // 验证码 校验异常
  185 + if (r2.code !== 200) {
  186 + res.json(r2);
  187 + return;
  188 + }
  189 +
  190 + // 检测 手机号 是否注册 异常
  191 + if (r1.code !== 200) {
  192 + res.json(r1);
  193 + return;
  194 + }
  195 +
  196 + // 校验失败
  197 + if (r2.data.is_pass !== 'Y') {
  198 + res.json({
  199 + code: 401,
  200 + message: VERIFY_ERROR
  201 + });
  202 +
  203 + return;
  204 + }
  205 +
  206 + // 手机号码 没注册
  207 + if (r1.data.is_register !== 'Y') {
  208 + redirect = '/passport/sms_login?step=3';
  209 + req.session.smsLoginStep = 3;
  210 +
  211 + res.json({
  212 + code: 200,
  213 + redirect
  214 + });
  215 +
  216 + return;
  217 + }
  218 +
  219 + // 手机号码已注册 --> 直接登录
  220 + PhoneService.autoSignin({
  221 + profile: mobile,
  222 + code: r2.data.code,
  223 + area,
  224 + shopping_key
  225 + })
  226 + .then(info => {
  227 + if (info.code !== 200) {
  228 + return Promise.reject(info);
  229 + }
  230 +
  231 + return AuthHelper.syncUserSession(info.data.uid, req, res);
  232 + })
  233 + .then(() => {
  234 + res.json({
  235 + code: 200,
  236 + message: LOGIN_SUCCSS,
  237 + redirect: req.cookies.refer
  238 + });
  239 +
  240 + delete req.session.smsLogin;
  241 + delete req.session.smsLoginStep;
  242 + })
  243 + .catch(error => {
  244 + res.json(error);
  245 + });
  246 +
  247 + })
  248 + .catch(next);
  249 +};
  250 +
  251 +// AJAX 短信登录 设置密码 in step3
  252 +exports.password = (req, res, next) => {
  253 + if (req.session.smsLoginStep !== 3) {
  254 + return next();
  255 + }
  256 +
  257 +
  258 + let data = {
  259 + code: '400',
  260 + message: BAD_PASSWORD
  261 + };
  262 +
  263 + let smsLogin = req.session.smsLogin || {};
  264 + let mobile = smsLogin.mobile;
  265 + let area = smsLogin.area;
  266 + let password = (req.body.password || '').trim();
  267 +
  268 + if (!password) {
  269 + data.message = PASSWORD_REQUIRED;
  270 + return res.json(data);
  271 + }
  272 +
  273 + if (!helpers.verifyPassword(password)) {
  274 + return res.json(data);
  275 + }
  276 +
  277 + // 购物车key
  278 + let shoppingKey = cookie.getShoppingKey(req);
  279 +
  280 +
  281 + RegService.regMobileAes(area, mobile, password, shoppingKey).then(result => {
  282 + if (!result.code || result.code !== 200) {
  283 + return Promise.reject(result);
  284 + }
  285 + if (!result.data || !result.data.uid) {
  286 + return Promise.reject(result);
  287 + }
  288 +
  289 + return AuthHelper.syncUserSession(result.data.uid, req, res);
  290 + }).then(() => {
  291 + res.json({
  292 + code: 200,
  293 + message: LOGIN_SUCCSS,
  294 + redirect: req.cookies.refer
  295 + });
  296 + delete req.session.smsLogin;
  297 + delete req.session.smsLoginStep;
  298 + }).catch(next);
  299 +
  300 +
  301 +};
  1 +/* eslint no-unused-vars: ["error", { "args": "none" }] */
  2 +'use strict';
  3 +const API = global.yoho.API;
  4 +
  5 +class PhoneService {
  6 + // 校验 手机 是否 已注册
  7 + // http://git.yoho.cn/yoho-documents/api-interfaces/blob/master/个人中心/验证码登录/校验是否是注册用户.md
  8 + static checkUserPhoneExist(mobile, area) {
  9 + return API.get('', {
  10 + method: 'app.passport.checkUserExist',
  11 + mobile,
  12 + area
  13 + });
  14 + }
  15 +
  16 + // 手机号 自动登录
  17 + // http://git.yoho.cn/yoho-documents/api-interfaces/blob/master/个人中心/验证码登录/手机号自动登录.md
  18 + static autoSignin(param) {
  19 + return API.get('', {
  20 + method: 'app.passport.autoSignin',
  21 + profile: param.profile,
  22 + area: param.area,
  23 + code: param.code,
  24 + shopping_key: param.shopping_key
  25 + });
  26 + }
  27 +
  28 + // 发送 验证码
  29 + // http://git.yoho.cn/yoho-documents/api-interfaces/blob/master/个人中心/验证码登录/发送验证码.md
  30 + static sendSMS(mobile, area, type) {
  31 + if (process.env.NODE_ENV === 'development') {
  32 + return new Promise((resolve, reject) => {
  33 + return resolve({
  34 + alg: 'SALT_MD5',
  35 + code: 200,
  36 + data: {},
  37 + md5: '6d729d4b35f10fc73531210bd7ecff91',
  38 + message: '发送成功.'
  39 + });
  40 + });
  41 + }
  42 +
  43 + return API.get('', {
  44 + method: 'app.message.sendSms',
  45 + mobile,
  46 + area,
  47 + type
  48 + });
  49 + }
  50 +
  51 + // 校验 验证码
  52 + // http://git.yoho.cn/yoho-documents/api-interfaces/blob/master/个人中心/验证码登录/验证验证码.md
  53 + static verifySMS(mobile, area, code, type) {
  54 + if (process.env.NODE_ENV === 'development') {
  55 + return new Promise((resolve, reject) => {
  56 + return resolve({
  57 + alg: 'SALT_MD5',
  58 + code: 200,
  59 + data: {
  60 + is_pass: 'Y'
  61 + },
  62 + md5: '6d729d4b35f10fc73531210bd7ecff91',
  63 + message: '发送成功.'
  64 + });
  65 + });
  66 + }
  67 +
  68 + return API.get('', {
  69 + method: 'app.message.verifySmsCode',
  70 + mobile,
  71 + area,
  72 + code,
  73 + type
  74 + });
  75 + }
  76 +}
  77 +
  78 +module.exports = PhoneService;
@@ -12,6 +12,7 @@ const login = require(cRoot + '/login'); @@ -12,6 +12,7 @@ const login = require(cRoot + '/login');
12 const back = require(cRoot + '/back'); 12 const back = require(cRoot + '/back');
13 const bind = require(cRoot + '/bind'); 13 const bind = require(cRoot + '/bind');
14 const reg = require(cRoot + '/reg'); 14 const reg = require(cRoot + '/reg');
  15 +const smsLogin = require(cRoot + '/sms');
15 16
16 17
17 const router = express.Router(); // eslint-disable-line 18 const router = express.Router(); // eslint-disable-line
@@ -33,6 +34,17 @@ router.get('/passport/international', login.common.beforeLogin, login.local.inte @@ -33,6 +34,17 @@ router.get('/passport/international', login.common.beforeLogin, login.local.inte
33 // 本地登录 34 // 本地登录
34 router.post('/passport/login/auth', login.local.login); 35 router.post('/passport/login/auth', login.local.login);
35 36
  37 +// SMS 短信
  38 +router.use('/passport/sms_login', login.common.beforeLogin, smsLogin.beforeIn);
  39 +router.get('/passport/sms_login', smsLogin.loginPage);
  40 +router.get('/passport/sms_login/token.json',
  41 + smsLogin.tokenBefore,
  42 + smsLogin.token); // only ajax;
  43 +router.get('/passport/sms_login/check.json',
  44 + smsLogin.checkBefore,
  45 + smsLogin.check); // only ajax
  46 +router.post('/passport/sms_login/password.json', smsLogin.password);
  47 +
36 // 微信登录 48 // 微信登录
37 router.get('/passport/login/wechat', login.common.beforeLogin, login.wechat.login); 49 router.get('/passport/login/wechat', login.common.beforeLogin, login.wechat.login);
38 router.get('/passport/login/wechat/callback', login.wechat.callback); 50 router.get('/passport/login/wechat/callback', login.wechat.callback);
@@ -10,7 +10,7 @@ @@ -10,7 +10,7 @@
10 </div> 10 </div>
11 <span id="btn-login" class="btn btn-login disable">登录</span> 11 <span id="btn-login" class="btn btn-login disable">登录</span>
12 <p class="op-container"> 12 <p class="op-container">
13 - <a class="go-register" href={{registerUrl}}>免费注册</a> 13 + <a class="sms-login" href={{smsLoginUrl}}>手机号码快捷登录</a>
14 <span id="forget-pwd" class="forget-pwd">忘记密码</span> 14 <span id="forget-pwd" class="forget-pwd">忘记密码</span>
15 </p> 15 </p>
16 <div class="third-party-login"> 16 <div class="third-party-login">
@@ -22,6 +22,10 @@ @@ -22,6 +22,10 @@
22 </div> 22 </div>
23 </div> 23 </div>
24 <a class="international" href={{internationalUrl}}>International Customer</a> 24 <a class="international" href={{internationalUrl}}>International Customer</a>
  25 + <div class="go-register">
  26 + <i class="iconfont">&#xe610;</i>
  27 + <a href={{registerUrl}}>注册Yoho!Family</a>
  28 + </div>
25 <div class="login-tip"> 29 <div class="login-tip">
26 <div class="info-icon"></div> 30 <div class="info-icon"></div>
27 Yoho!Family账号可登录Yoho!Buy有货 31 Yoho!Family账号可登录Yoho!Buy有货
  1 +<div class="sms-login passport-page yoho-page">
  2 + {{> passport/header}}
  3 + <div class="content">
  4 + <p class="sms-login-msg">验证码已发至&nbsp;<span class="tel">+86 133601454888</span></p>
  5 + <div class="input-container input-group sms-input row">
  6 + <input id="sms-code" class="input" type="text" placeholder="验证码">
  7 + <span class="input-addon">
  8 + <button type="button" id="resend-sms">重发验证码</button>
  9 + </span>
  10 + </div>
  11 + <button id="btn-next" class="btn btn-next disable row" type="button">登录</button>
  12 + </div>
  13 + <input type="hidden" name="mobile" id="mobile" value="{{mobile}}">
  14 + <input type="hidden" name="area" id="area" value="{{area}}">
  15 +</div>
  16 +<script>
  17 + var canResend = {{canResend}};
  18 +</script>
  1 +<div class="sms-login-page passport-page yoho-page">
  2 + {{> passport/header}}
  3 + <div class="content">
  4 + {{> passport/country_list}}
  5 + <div class="input-container phone-container row has-clear">
  6 + <span id="area-code" class="area-code">{{areaCode}}</span>
  7 + <input id="phone-num" class="input phone-num" type="text" placeholder="手机号">
  8 + </div>
  9 + <span id="btn-next" class="btn btn-next disable row">获取短信验证码</span>
  10 + </div>
  11 +</div>
  1 +<div class="sms-login passport-page yoho-page">
  2 + {{> passport/header}}
  3 + <div class="content">
  4 + <p class="sms-login-msg small">你以后还可以使用手机号码 + 密码的形式登录有货哦!</p>
  5 + <div class="input-container row has-eye">
  6 + <input id="pwd" class="pwd input" type="password" placeholder="密码">
  7 + <div class="eye close" id="eye"></div>
  8 + </div>
  9 + <span id="btn-next" class="btn btn-next disable row">确定</span>
  10 + </div>
  11 +</div>
@@ -16,9 +16,16 @@ module.exports = { @@ -16,9 +16,16 @@ module.exports = {
16 domains: { 16 domains: {
17 // api: 'http://devapi.yoho.cn:58078/', 17 // api: 'http://devapi.yoho.cn:58078/',
18 // service: 'http://devservice.yoho.cn:58077/' 18 // service: 'http://devservice.yoho.cn:58077/'
19 - api: 'http://api-test3.yohops.com:9999/',  
20 - service: 'http://service-test3.yohops.com:9999/',  
21 - liveApi: 'http://testapi.live.yohops.com:9999/' 19 +
  20 + // api: 'http://api-test3.yohops.com:9999/',
  21 + // service: 'http://service-test3.yohops.com:9999/',
  22 + // liveApi: 'http://testapi.live.yohops.com:9999/'
  23 +
  24 + api: 'http://api.yoho.cn/',
  25 + service: 'http://service.yoho.cn/'
  26 +
  27 + // api: 'http://testapi.yoho.cn:28078/',
  28 + // service: 'http://testservice.yoho.cn:28077/'
22 }, 29 },
23 subDomains: { 30 subDomains: {
24 host: '.m.yohobuy.com', 31 host: '.m.yohobuy.com',
  1 +var tip = require('plugin/tip');
  2 +
  3 +var $resendBtn,
  4 + $nextBtn,
  5 + $smsCode,
  6 + mobile, area;
  7 +
  8 +var page = {
  9 + disableAjax: false,
  10 +
  11 + time: 60,
  12 + resendText: '重发验证码',
  13 + timerId: null,
  14 + init: function() {
  15 + this.domInit();
  16 + this.bindEvents();
  17 + if (!window.canResend) {
  18 + this.countDown();
  19 + }
  20 + },
  21 +
  22 +
  23 + domInit: function() {
  24 + $resendBtn = $('#resend-sms');
  25 + $nextBtn = $('#btn-next');
  26 + $smsCode = $('#sms-code');
  27 + mobile = $('#mobile').val();
  28 + area = $('#area').val();
  29 + },
  30 +
  31 +
  32 + bindEvents: function() {
  33 + var self = this;
  34 +
  35 + $resendBtn.on('click', function() {
  36 + self.resendSMS();
  37 + });
  38 +
  39 + $smsCode.on('input', function() {
  40 + var hasVal = Boolean($.trim(this.value));
  41 +
  42 + $nextBtn.toggleClass('disable', !hasVal);
  43 + });
  44 +
  45 + $nextBtn.on('click', function() {
  46 + !self.disableAjax && self.submit();
  47 + });
  48 + },
  49 +
  50 +
  51 + countDown: function() {
  52 + var self = this;
  53 + var second = this.time;
  54 +
  55 + if (this.timerId) {
  56 + return;
  57 + }
  58 +
  59 + $resendBtn.prop('disable', true);
  60 + this.timerId = setInterval(function() {
  61 + var txt = self.resendText;
  62 +
  63 + second = second - 1;
  64 +
  65 + if (second < 0) {
  66 + clearInterval(self.timerId);
  67 + self.timerId = null;
  68 + $resendBtn.prop('disable', false);
  69 + } else {
  70 + txt = second + 's';
  71 + }
  72 +
  73 + $resendBtn.text(txt);
  74 + }, 1000);
  75 +
  76 + },
  77 +
  78 +
  79 + resendSMS: function() {
  80 + var self = this;
  81 +
  82 + if ($resendBtn.prop('disable')) {
  83 + return;
  84 + }
  85 +
  86 + $.get('/passport/sms_login/token.json', {
  87 + area: area,
  88 + mobile: mobile,
  89 + })
  90 + .done(function(res) {
  91 + if (res.code === 200) {
  92 + self.countDown();
  93 + return;
  94 + }
  95 +
  96 + tip.show(res.message);
  97 + })
  98 + .fail(function() {
  99 + tip.show('出错啦~休息一下');
  100 + });
  101 + },
  102 +
  103 + submit: function() {
  104 + var self = this;
  105 + var code = $.trim($smsCode.val());
  106 +
  107 + this.disableAjax = true;
  108 + $.get('/passport/sms_login/check.json', {
  109 + code: code
  110 + })
  111 + .done(function(res) {
  112 + if (res.code === 200) {
  113 + location.href = res.redirect;
  114 + return;
  115 + }
  116 +
  117 + tip.show(res.message);
  118 + })
  119 + .fail(function() {
  120 + tip.show('出错了, 请重试');
  121 + })
  122 + .always(function() {
  123 + self.disableAjax = false;
  124 + });
  125 + }
  126 +};
  127 +
  128 +$(function() {
  129 + page.init();
  130 +});
  1 +'use strict';
  2 +
  3 +var tip = require('plugin/tip');
  4 +var api = require('./api');
  5 +
  6 +var $countrySelect,
  7 + $areaCode,
  8 + $nextBtn,
  9 + $phoneNum;
  10 +
  11 +var page = {
  12 + disableAjax: false,
  13 + init: function() {
  14 + this.domInit();
  15 + this.bindEvent();
  16 +
  17 + this.toggleNextBtn();
  18 + },
  19 + domInit: function() {
  20 + $countrySelect = $('#country-select');
  21 + $areaCode = $('#area-code');
  22 + $nextBtn = $('#btn-next');
  23 + $phoneNum = $('#phone-num');
  24 + },
  25 + bindEvent: function() {
  26 + var self = this;
  27 +
  28 + $countrySelect.on('change', function() {
  29 + $areaCode.text(this.value);
  30 + });
  31 + $phoneNum.on('input', function() {
  32 + self.toggleNextBtn();
  33 + });
  34 +
  35 + $nextBtn.on('click', function() {
  36 + !self.disableAjax && self.goNext();
  37 + });
  38 + },
  39 +
  40 + // 切换$nextBtn disable状态
  41 + toggleNextBtn: function() {
  42 + var bool = Boolean($.trim($phoneNum.val()));
  43 +
  44 + $nextBtn
  45 + .toggleClass('disable', !bool)
  46 + .prop('disable', !bool);
  47 + },
  48 +
  49 + // 提交按钮
  50 + goNext: function() {
  51 + var areaCode = $countrySelect.val();
  52 + var phone = $.trim($phoneNum.val());
  53 + var self = this;
  54 +
  55 + if ($nextBtn.hasClass('disable')) {
  56 + return;
  57 + }
  58 +
  59 + if (!api.phoneRegx[areaCode].test(phone)) {
  60 + tip.show('手机号码格式不正确, 请重新输入');
  61 + return;
  62 + }
  63 +
  64 + this.disableAjax = true;
  65 + $.get('/passport/sms_login/token.json', {
  66 + area: areaCode.replace('+', ''),
  67 + mobile: phone
  68 + })
  69 + .done(function(data) {
  70 + if (data.code === 200) {
  71 + location.href = data.redirect;
  72 + } else {
  73 + tip.show(data.message);
  74 + }
  75 + })
  76 + .fail(function() {
  77 + tip.show('出错了, 请重试');
  78 + })
  79 + .always(function() {
  80 + self.disableAjax = false;
  81 + });
  82 +
  83 +
  84 +
  85 + }
  86 +};
  87 +
  88 +$(function() {
  89 + page.init();
  90 +});
  1 +var tip = require('plugin/tip');
  2 +
  3 +var $eyeBtn,
  4 + $pwd,
  5 + $nextBtn;
  6 +
  7 +var page = {
  8 + disableAjax: false,
  9 +
  10 + init: function() {
  11 + this.domInit();
  12 + this.bindEvent();
  13 + },
  14 + domInit: function() {
  15 + $eyeBtn = $('#eye');
  16 + $pwd = $('#pwd');
  17 + $nextBtn = $('#btn-next');
  18 + },
  19 + bindEvent: function() {
  20 + var self = this;
  21 +
  22 + $eyeBtn.on('click', function() {
  23 + self.togglePassword();
  24 + });
  25 +
  26 + $nextBtn.on('click', function() {
  27 + !self.disableAjax && self.setPasswordAndLogin();
  28 + });
  29 +
  30 + $pwd.on('input', function() {
  31 + var bool = Boolean($.trim(this.value));
  32 +
  33 + $nextBtn
  34 + .toggleClass('disable', !bool)
  35 + .prop('disable', !bool);
  36 + });
  37 + },
  38 +
  39 + togglePassword: function() {
  40 + var bool = $eyeBtn.hasClass('close');
  41 +
  42 + $eyeBtn.toggleClass(function() {
  43 + $pwd.attr('type', !bool ? 'password' : 'text');
  44 + return 'close';
  45 + }, !bool);
  46 + },
  47 +
  48 + setPasswordAndLogin: function() {
  49 + var self = this;
  50 + var password = $.trim($pwd.val());
  51 +
  52 + this.disableAjax = true;
  53 + $.post('/passport/sms_login/password.json', {
  54 + password: password
  55 + })
  56 + .done(function(res) {
  57 + if (res.code === 200) {
  58 + location.href = res.redirect;
  59 + return;
  60 + }
  61 +
  62 + tip.show(res.message);
  63 + })
  64 + .fail(function() {
  65 + tip.show('出错了, 请重试');
  66 + })
  67 + .always(function() {
  68 + self.disableAjax = false;
  69 + });
  70 + }
  71 +};
  72 +
  73 +$(function() {
  74 + page.init();
  75 +});
1 @charset "utf-8"; 1 @charset "utf-8";
  2 +
2 @import "me/index"; 3 @import "me/index";
3 @import "layout/reset"; 4 @import "layout/reset";
4 @import "layout/common"; 5 @import "layout/common";
@@ -7,6 +8,7 @@ @@ -7,6 +8,7 @@
7 @import "layout/header"; 8 @import "layout/header";
8 @import "layout/footer"; 9 @import "layout/footer";
9 @import "layout/utils"; 10 @import "layout/utils";
  11 +@import "layout/form";
10 @import "common/index"; 12 @import "common/index";
11 @import "channel/index"; 13 @import "channel/index";
12 @import "product/index"; 14 @import "product/index";
  1 +.input-group {
  2 + display: table;
  3 +
  4 + .input {
  5 + width: 100%;
  6 + }
  7 +
  8 + .input,
  9 + .input-addon {
  10 + display: table-cell;
  11 + vertical-align: middle;
  12 + }
  13 +}
1 @import "common"; 1 @import "common";
2 @import "register"; 2 @import "register";
3 @import "login"; 3 @import "login";
  4 +@import "sms-login";
4 @import "back"; 5 @import "back";
5 @import "code"; 6 @import "code";
6 @import "bind"; 7 @import "bind";
@@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
3 position: absolute; 3 position: absolute;
4 height: 31PX; 4 height: 31PX;
5 width: 26PX; 5 width: 26PX;
6 - background: resolve('passport/yoho.png'); 6 + background: resolve("passport/yoho.png");
7 background-size: 100% 100%; 7 background-size: 100% 100%;
8 top: 10PX; 8 top: 10PX;
9 left: 15PX; 9 left: 15PX;
@@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
20 text-align: left; 20 text-align: left;
21 font-size: 16PX; 21 font-size: 16PX;
22 22
23 - .go-register { 23 + .sms-login {
24 text-decoration: underline; 24 text-decoration: underline;
25 color: #858585; 25 color: #858585;
26 } 26 }
@@ -57,20 +57,20 @@ @@ -57,20 +57,20 @@
57 } 57 }
58 58
59 .alipay { 59 .alipay {
60 - background-image: resolve('passport/alipay.png'); 60 + background-image: resolve("passport/alipay.png");
61 } 61 }
62 62
63 .weibo { 63 .weibo {
64 - background-image: resolve('passport/weibo.png'); 64 + background-image: resolve("passport/weibo.png");
65 } 65 }
66 66
67 .qq { 67 .qq {
68 - background-image: resolve('passport/qq.png'); 68 + background-image: resolve("passport/qq.png");
69 } 69 }
70 70
71 .wechat { 71 .wechat {
72 display: none; 72 display: none;
73 - background-image: resolve('passport/wechat.png'); 73 + background-image: resolve("passport/wechat.png");
74 } 74 }
75 } 75 }
76 } 76 }
@@ -82,11 +82,19 @@ @@ -82,11 +82,19 @@
82 background-color: #333; 82 background-color: #333;
83 border: none; 83 border: none;
84 border-radius: 20PX; 84 border-radius: 20PX;
85 - margin: 0 auto; 85 + margin: 0 auto 28px;
86 font-size: 16PX; 86 font-size: 16PX;
87 color: #d8d8d8; 87 color: #d8d8d8;
88 } 88 }
89 89
  90 + .go-register {
  91 + color: #858585;
  92 +
  93 + a {
  94 + color: inherit;
  95 + }
  96 + }
  97 +
90 .login-tip { 98 .login-tip {
91 font-size: 16PX; 99 font-size: 16PX;
92 position: relative; 100 position: relative;
@@ -97,7 +105,7 @@ @@ -97,7 +105,7 @@
97 display: inline-block; 105 display: inline-block;
98 height: 12PX; 106 height: 12PX;
99 width: 12PX; 107 width: 12PX;
100 - background-image: resolve('passport/info.png'); 108 + background-image: resolve("passport/info.png");
101 background-size: 100% 100%; 109 background-size: 100% 100%;
102 } 110 }
103 } 111 }
  1 +.sms-login {
  2 + .sms-input {
  3 + margin-top: 60px;
  4 + }
  5 +
  6 + #resend-sms {
  7 + display: block;
  8 + background-color: transparent;
  9 + width: 190px;
  10 + margin-right: 15px;
  11 + border: 1px solid #36a74c;
  12 + border-radius: 26px;
  13 + font-size: 20px;
  14 + line-height: 30px;
  15 + color: #36a74c;
  16 + }
  17 +
  18 + button {
  19 + border: none;
  20 + }
  21 +}
  22 +
  23 +.sms-login-msg {
  24 + font-size: 28px;
  25 + color: #fff;
  26 + margin-bottom: 20px;
  27 +
  28 + .tel {
  29 + color: #41cbe7;
  30 + }
  31 +
  32 + &.small {
  33 + font-size: 22px;
  34 + color: #858585;
  35 + }
  36 +}
@@ -42,7 +42,7 @@ module.exports = { @@ -42,7 +42,7 @@ module.exports = {
42 resolve: { 42 resolve: {
43 alias: { 43 alias: {
44 common: path.join(__dirname, 'js/common'), 44 common: path.join(__dirname, 'js/common'),
45 - plugin: path.join(__dirname, 'js/plugins') 45 + plugin: path.join(__dirname, 'js/plugin')
46 } 46 }
47 }, 47 },
48 plugins: [ 48 plugins: [