Authored by 王水玲

Merge branch 'feature/login-msg' into release/2.0

... ... @@ -14,18 +14,17 @@ if (config.useOneapm) {
const express = require('express');
const path = require('path');
const uuid = require('uuid');
const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser');
const favicon = require('serve-favicon');
const session = require('express-session');
const memcached = require('connect-memcached');
const session = require('client-sessions');
const hbs = require('express-handlebars');
const multer = require('connect-multiparty');
const pkg = require('./package.json');
const yohoLib = require('yoho-node-lib');
const app = express();
const MemcachedStore = memcached(session);
// 全局注册library
yohoLib.global(config);
... ... @@ -55,26 +54,21 @@ app.use(cookieParser());
app.use(multer());
app.use(session({
proxy: true,
resave: false,
saveUninitialized: true,
unset: 'destroy',
requestKey: 'session',
cookieName: 'yohoblk-session',
secret: '82dd7e724f2c6870472c89dfa43cf48d',
name: 'yohoblk-session',
cookie: {
domain: config.cookieDomain,
httpOnly: true
},
store: new MemcachedStore({
hosts: config.memcache.session,
prefix: 'yohoblk_session:'
})
domain: config.cookieDomain
}));
app.use((req, res, next) => {
req.user = {}; // 全局的用户数据
req.yoho = {}; // req和res绑定yoho对象,用于传递全局数据, 如req.yoho.channel等
if (!req.session || !req.session.uuid) {
req.session = {
uuid: uuid.v4()
};
}
next();
});
... ...
... ... @@ -10,6 +10,7 @@ const passport = require('passport');
const uuid = require('uuid');
const md5 = require('md5');
const Promise = require('bluebird');
const qs = require('querystring');
const co = Promise.coroutine;
const cookie = global.yoho.cookie;
... ... @@ -17,6 +18,7 @@ const helpers = global.yoho.helpers;
const log = global.yoho.logger;
const config = global.yoho.config;
const cache = global.yoho.cache;
const crypto = global.yoho.crypto;
const LoginService = require('../models/login-service');
const PassportHelper = require('../models/passport-helper');
const safeRedirect = require('../../../doraemon/middleware/safe-redirect').safeRedirect;
... ... @@ -126,6 +128,11 @@ const local = {
let loginCountryCode = '+' + _.trim(req.query.bindArea || '86');
let countries = PassportHelper.getCountry();
let defaultCountryName = '';
let account = req.cookies.account || '';
if (account) {
account = crypto.decrypt('yoho9646yoho9646', account);
}
if (loginCountryCode) {
let area = countries.find((a) => {
... ... @@ -152,7 +159,7 @@ const local = {
qqLogin: helpers.urlFormat('/passport/autosign/qq'),
weiboLogin: helpers.urlFormat('/passport/autosign/sina'),
alipayLogin: helpers.urlFormat('/passport/autosign/alipay'),
bindMobile: loginMobile
bindMobile: loginMobile || account
},
module: 'passport',
page: 'login',
... ... @@ -181,9 +188,18 @@ const local = {
account: req.body.account,
password: req.body.password
}, req, res);
res.cookie('account', crypto.encryption('yoho9646yoho9646', req.body.account), {
domain: config.cookieDomain,
httpOnly: true
});
} else {
res.clearCookie('account', {
domain: config.cookieDomain
});
}
refer = !BlockRedirectFilter.test(decodeURI(refer)) ? decodeURI(refer) : config.siteUrl;
refer = !BlockRedirectFilter.test(decodeURI(refer)) && refer ? decodeURI(refer) : config.siteUrl;
yield LoginService.syncUserSession(user.uid, req, res).then(() => {
res.json({
... ... @@ -198,9 +214,13 @@ const local = {
})(req, res, next);
},
logout: (req, res) => {
req.session.destroy();
req.session.reset();
const clearAll = (v, k) => {
if (k === 'account') {
return;
}
res.clearCookie(k, {
domain: config.cookieDomain
});
... ... @@ -209,6 +229,85 @@ const local = {
_.forOwn(req.cookies, clearAll);
res.redirect(config.siteUrl);
},
sms: {
send: (req, res, next) => {
let area = req.body.area || '86';
let mobile = req.body.mobile || '';
if (!mobile) {
return res.json({
code: 400,
message: '格式错误'
});
}
LoginService.sendPasswordBySMS(area, mobile).then((result) => {
return res.json(result);
}).catch(next);
},
auth: (req, res, next) => {
let area = req.body.area || '86';
let mobile = req.body.mobile || '';
let code = req.body.code || '';
if (!area || !mobile || !code) {
return res.json({
code: 400,
message: '格式错误'
});
}
LoginService.verifyPasswordBySMS(area, mobile, code).then((result) => {
if (_.get(result, 'code', 200) !== 200) {
return res.json(result);
}
let pass = _.get(result, 'data.is_pass', 'N');
if (pass === 'Y') {
return res.json({
token: _.get(result, 'data.code', ''),
code: 200
});
} else {
return res.json({
code: 400
});
}
}).catch(next);
},
checkUser: (req, res, next) => {
let area = req.body.area || '86';
let mobile = req.body.phoneNum || '';
if (!area || !mobile) {
return res.json({
code: 400,
message: '格式错误'
});
}
LoginService.checkUserExitBySMS(area, mobile).then((result) => {
if (_.get(result, 'code') !== 200) {
return Promise.reject('check user by sms error');
}
if (_.get(result, 'data.is_register', 'N') === 'Y') {
return res.json({
code: 200,
message: '用户已注册'
});
} else {
return res.json({
code: 402,
message: '手机号尚未注册,请核对后重新输入或<a href="' + helpers.urlFormat('/passport/reg') + '?' +
qs.stringify({mobile: mobile, area: (area ? '+' + area : '+86') || '+86'}) +
'" >注册</a>'
});
}
}).catch(next);
}
}
};
... ...
... ... @@ -54,6 +54,8 @@ let index = (req, res) => {
req.session._REG_EXPIRE = Date.now() + 1800000;
let refer = req.query.refer;
let mobile = req.query.mobile;
let area = req.query.area;
refer && res.cookie('refer', encodeURI(refer), {
domain: config.cookieDomain,
... ... @@ -67,7 +69,8 @@ let index = (req, res) => {
country: {
list: passportHelper.getCountry()
},
location: '+86',
location: area || '+86',
defaultMobile: mobile || '',
countryName: {
text: '中国'
},
... ...
... ... @@ -25,6 +25,29 @@ const signinAsync = (area, profile, password, shoppingKey) => {
};
/**
* 手机短信登录
* @param area
* @param mobile
* @param token
* @param shoppingKey
* @returns {*|Promise}
*/
const signinBySMS = (area, mobile, token, shoppingKey) => {
let param = {
method: 'app.passport.autoSignin',
area: area,
profile: mobile,
code: token
};
if (shoppingKey) {
param.shopping_key = shoppingKey;
}
return api.post('', param);
};
/**
* 除微信第三方登录
*/
const signinByOtherOpenIDAsync = (nickname, openId, sourceType, shoppingKey) => {
... ... @@ -61,8 +84,41 @@ const signinByWechatAsync = (nickname, openId, sourceType, shoppingKey, unionId)
return api.get('', param);
};
const sendPasswordBySMS = (area, mobile) => {
let param = {
method: 'app.message.sendSms',
area: area,
mobile: mobile,
type: 1 // 手机快捷登录短信验证码
};
return api.get('', param);
};
const verifyPasswordBySMS = (area, mobile, code) => {
return api.get('', {
method: 'app.message.verifySmsCode',
area: area,
mobile: mobile,
code: code,
type: 1 // 手机快捷登录短信验证码
});
};
const checkUserExitBySMS = (area, mobile) => {
return api.get('', {
method: 'app.passport.checkUserExist',
area: area,
mobile: mobile
});
};
module.exports = {
signinAsync,
signinBySMS,
signinByOtherOpenIDAsync,
signinByWechatAsync
signinByWechatAsync,
sendPasswordBySMS,
verifyPasswordBySMS,
checkUserExitBySMS
};
... ...
... ... @@ -27,13 +27,13 @@ let siteUrl = config.siteUrl.indexOf('//') === 0 ? 'http:' + config.siteUrl : co
// 本地登录
passport.use(new LocalStrategy({
passport.use('local', new LocalStrategy({
usernameField: 'account',
passwordField: 'password',
passReqToCallback: true
}, (req, username, password, done) => {
let area = req.body.areaCode || '86';
let type = req.body.loginType;
if (isNaN(_.parseInt(area)) || _.isEmpty(username) || _.isEmpty(password)) {
logger.info(`【Passport Loginbad params, area:${area} account:${username} password:${password}`);
... ... @@ -76,7 +76,7 @@ passport.use(new LocalStrategy({
if (accountTimes >= 10) {
done({message: '您的账号已被暂时锁定,请30分钟后再试'}, null);
} else {
return LoginService.signinAsync(area, username, password, shoppingKey).then((result) => {
return LoginService.signin(type, area, username, password, shoppingKey).then((result) => {
if (result.code && result.code === 200 && result.data.uid) {
cache.del(errorLoginKey);
... ...
... ... @@ -14,6 +14,15 @@ const crypto = global.yoho.crypto;
const api = require('./login-api');
const UserService = require('./user-service');
const signin = (type, area, profile, password, shoppingKey) => {
let loginBy = {
PasswordLogin: api.signinAsync,
SMSLogin: api.signinBySMS
};
return loginBy[type](area, profile, password, shoppingKey);
};
/**
* 登录,包括微信和其它第三方
*/
... ... @@ -89,8 +98,11 @@ const rememberAccountAsync = (accountInfo, req, res) => {
};
module.exports = {
signinAsync: api.signinAsync,
signin,
signinByOpenIDAsync,
syncUserSession,
rememberAccountAsync
rememberAccountAsync,
sendPasswordBySMS: api.sendPasswordBySMS,
verifyPasswordBySMS: api.verifyPasswordBySMS,
checkUserExitBySMS: api.checkUserExitBySMS
};
... ...
... ... @@ -23,6 +23,11 @@ router.post('/login/auth', login.local.login);
router.post('/login/user', back.validateInputAPI, back.getUserInfoAPI);
router.get('/logout', login.local.logout);
// 手机短信验证码
router.post('/login/sms/send', login.local.sms.send); // 发短信验证码
router.post('/login/sms/auth', login.local.sms.auth); // 验证短信验证码
router.post('/login/sms/checkuser', login.local.sms.checkUser); // 短信检查用户是否注册
// 微信登录
router.get('/autosign/wechat', login.common.beforeLogin, login.wechat.login);
router.get('/login/wechat/callback', login.wechat.callback);
... ...
... ... @@ -7,6 +7,12 @@
<div class="title">登录 SIGN IN</div>
</li>
<li class="clearfix">
<div class="switch">
<div class="left selected" data-type="PasswordLogin">普通登录</div>
<div class="right" data-type="SMSLogin">手机验证码登录</div>
</div>
</li>
<li class="clearfix">
{{> select-header}}
{{> select-list}}
... ... @@ -22,7 +28,7 @@
</div>
</li>
<li class="clearfix">
<li class="clearfix pwd-wrap">
<div class="pwd-wrapper">
<input id="password" class="input password va needTip" name="password" type="password"
placeholder="Password"
... ... @@ -47,6 +53,19 @@
</div>
</li>
<li class="clearfix sms-code-wrap hide">
<div class="sms-captcha-wrapper">
<input id="captcha-sms" class="input va captcha needTip" type="text" name="smsCode" placeholder="短信验证码"
autocomplete="off" maxlength="4">
{{> err-tip}}
</div>
<div class="left sms-btn-wrap">
<input type="button" id="sms-btn" class="btn sms-btn" value='获取短信验证码'/>
</div>
</li>
<li class="clearfix">
<span class="left login-fail-tip hide">
<span class="iconfont">&#xe61d;</span>
... ... @@ -93,6 +112,7 @@
</li>
</ul>
<input id="country-code-hide" name="countryCode" type="hidden" value="{{countryCode}}">
<input id="captcha-sms-token-hide" name="token" type="hidden">
</form>
{{/ passport}}
</div>
... ...
... ... @@ -11,7 +11,7 @@
{{>select-list}}
<div id="phone" class="left phone relative">
<span id="country-code" class="country-code">{{location}}</span>
<input value="" id="phone-num" class="input phone-num" type="text" name="phoneNum"
<input value="{{defaultMobile}}" id="phone-num" class="input phone-num" type="text" name="phoneNum"
placeholder="Phone Number" autocomplete="off">
{{> err-tip}}
... ...
... ... @@ -34,7 +34,7 @@
"bluebird": "^3.4.0",
"body-parser": "^1.15.0",
"captchapng": "0.0.1",
"connect-memcached": "^0.2.0",
"client-sessions": "^0.7.0",
"connect-multiparty": "^2.0.0",
"cookie-parser": "^1.4.3",
"csurf": "^1.9.0",
... ... @@ -44,7 +44,6 @@
"influxdb-winston": "^1.0.1",
"lodash": "^4.13.1",
"md5": "^2.1.0",
"memcached": "^2.2.2",
"moment": "^2.13.0",
"morgan": "^1.7.0",
"oneapm": "^1.2.20",
... ...

374 Bytes | W: | H:

1.38 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
... ... @@ -10,25 +10,27 @@ var EventProxy = require('yoho-eventproxy');
var $phoneNumInput = $('#account'),
$passwordInput = $('#password'),
$imgCaptchaInput = $('#captcha'),
$smsCaptchaInput = $('#captcha-sms'),
$smsCodeWrap = $('.sms-code-wrap'),
$pwdWrap = $('.pwd-wrap'),
$captchaSmsTokenHideInput = $('#captcha-sms-token-hide'),
$loginBtn = $('#login-btn'),
$phone = $('#phone');
$phone = $('#phone'),
$smsBtn = $('#sms-btn'),
$regionCodeText = $('#country-code'),
$regionSelectList = $('#country-select-list'),
$regionSelectHeader = $('#country-select-header'),
$emailAutoComplete = $('#email-autocomplete');
var $loginTip = $loginBtn.siblings('.login-fail-tip'),
ep = new EventProxy();
var $regionCodeText = $('#country-code'),
$regionSelectList = $('#country-select-list'),
$regionSelectHeader = $('#country-select-header');
var $emailAutoComplete = $('#email-autocomplete');
var mailPhoneRegx = require('../common/mail-phone-regx');
var mailAc = require('../common/ac-email'); // 邮箱自动完成
var $remember = $('.remember-me');
var captchaUrl = '/passport/images?t='; // /passport/images?t=1454464125
var showCaptcha = false;
var $captchaWrap = $('.captcha-wrap'),
$captchaImg = $captchaWrap.find('#captcha-img');
... ... @@ -45,13 +47,26 @@ var upDown = {
var selectedIcon = '&#xe60b;';
// 短信验证码的计数器,60s
var secondCount = 60;
// 短信验证码只能验证一次
var isSmsCheckedSuccessFlag = false;
var currLoginType = 'PasswordLogin';
require('yoho-jquery-placeholder');
function refreshCaptcha() {
$captchaImg.attr('src', captchaUrl + $.now());
$imgCaptchaInput.val('');
}
function errTip(ele, msg) {
var $errTip = ele.next('.tips');
var $errMsg = $errTip.find('.content');
$errMsg.text(msg);
$errMsg.html(msg);
return $errTip.removeClass('hide');
}
... ... @@ -59,9 +74,19 @@ function hideTip(ele) {
return ele.next('.tips').addClass('hide');
}
// 获取区域号
function getArea() {
return $regionCodeText.text().replace('+', '');
}
// 获取用户输入的手机号
function getMoblie() {
return $.trim($phoneNumInput.val());
}
// 验证账户名
function validateAccountLocal() {
var phoneNum = $.trim($phoneNumInput.val()),
var phoneNum = getMoblie(),
regionCode = $regionCodeText.text();
if (phoneNum !== '') {
... ... @@ -96,19 +121,19 @@ function validateAccountLocal() {
}
// 异步验证帐号是否存在
function validateAccountAsync() {
function validateAccountAsync(url) {
return $.ajax({
type: 'POST',
url: '/passport/login/user',
url: url,
data: {
phoneNum: $phoneNumInput.val(),
area: $regionCodeText.text().replace('+', '')
phoneNum: getMoblie(),
area: getArea()
}
}).then(function(data) {
if (data.code && data.code === 200) {
return true;
} else {
errTip($phoneNumInput, '账号不存在');
errTip($phoneNumInput, data.message);
return false;
}
});
... ... @@ -118,9 +143,14 @@ function validateAccountAsync() {
function validateAccount() {
return (function() {
var defer = $.Deferred(); // eslint-disable-line
var url = '/passport/login/user';
if (currLoginType === 'SMSLogin') {
url = '/passport/login/sms/checkuser';
}
if (validateAccountLocal()) {
validateAccountAsync().then(function(result) {
validateAccountAsync(url).then(function(result) {
if (result) {
defer.resolve(result);
} else {
... ... @@ -161,16 +191,11 @@ function validatePasswordLocal() {
}
}
// 验证验证码
// 图形验证验证码
function validateCaptchaLocal() {
var captcha = $.trim($imgCaptchaInput.val());
var length = captcha.length;
if ($captchaWrap.hasClass('hide')) {
ep.emit('captcha', true);
return true;
}
switch (length) {
case 0:
errTip($imgCaptchaInput, '请输入验证码');
... ... @@ -186,56 +211,70 @@ function validateCaptchaLocal() {
}
}
// 密码错误次数,超过三次显示验证码
function showAccountErrTimes() {
$captchaWrap.removeClass('hide');
$captchaImg.attr('src', captchaUrl + $.now());
$imgCaptchaInput.val('');
}
// 登录
function login() {
// 异步验证图片验证码
function validateCaptchaImgAsync() {
return $.ajax({
url: '/passport/login/auth',
url: '/passport/images/check',
type: 'POST',
data: {
areaCode: $regionCodeText.text().replace('+', ''),
account: $.trim($phoneNumInput.val()),
password: $.trim($passwordInput.val()),
captcha: $.trim($imgCaptchaInput.val()),
isRemember: $remember.hasClass('checked') ? true : false
},
success: function(res) {
if (res.code === 200) {
if (res.data) {
verifyCode: $.trim($imgCaptchaInput.val())
}
}).then(function(result) {
if (result.code === 200) {
return true;
} else {
errTip($imgCaptchaInput, '验证码不正确');
return false;
}
});
}
// 防止data.data为undefined时下行语句执行出错而导致脚本不能走到complete去处理authing
location.href = res.data.refer;
}
} else {
if (res.data.errorType === 'captcha') {
$imgCaptchaInput.val('');
} else {
$loginTip.removeClass('hide').children('em').html(res.message);
$passwordInput.val('');
}
// 整合本地和异步验证信息
function validateCaptchaImg() {
if ($captchaWrap.hasClass('hide')) {
return true;
}
// 验证错误次数
if (res.data && res.data.needCaptcha) {
showAccountErrTimes();
return (function() {
var defer = $.Deferred(); // eslint-disable-line
if (validateCaptchaLocal()) {
validateCaptchaImgAsync().then(function(result) {
if (result) {
defer.resolve(result);
} else {
defer.reject(result);
}
}
});
} else {
defer.reject(false);
}
return defer.promise();
}()).then(function() {
hideTip($imgCaptchaInput);
ep.emit('captcha', true);
}).fail(function() {
ep.emit('captcha', false);
refreshCaptcha();
});
}
// 密码错误次数,超过三次显示验证码
function showAccountErrTimes() {
$captchaWrap.removeClass('hide');
showCaptcha = true;
$captchaImg.attr('src', captchaUrl + $.now());
$imgCaptchaInput.val('');
}
// 登录次数限制接口
function throttle() {
return $.ajax({
url: '/passport/login/account',
type: 'GET',
data: {
account: $.trim($phoneNumInput.val())
account: getMoblie()
}
});
}
... ... @@ -266,23 +305,6 @@ function validate() {
});
}
// 全部的本地验证
function loginAsync() {
return validateAccount().then(function() {
var defer = $.Deferred(); // eslint-disable-line
if (validateCaptchaLocal() && validatePasswordLocal()) {
defer.resolve(true);
} else {
defer.reject(false);
}
return defer.promise();
}).then(function() {
return login();
});
}
// 邮箱自动补全
mailAc($phoneNumInput, function() {
});
... ... @@ -332,22 +354,22 @@ $regionSelectHeader.on('click', function() {
changeHeader();
});
// 密码
// 密码失去焦点后校验
$passwordInput.on('blur', function() {
$passwordInput.removeClass('focus');
validatePasswordLocal();
}).on('focus', function() {
$passwordInput.addClass('focus');
hideTip($passwordInput);
});
// 验证码
// 图形验证码失去焦点|获取焦点的校验
$imgCaptchaInput.on('blur', function() {
$imgCaptchaInput.removeClass('focus');
validateCaptchaLocal();
validateCaptchaImg();
}).on('focus', function() {
$imgCaptchaInput.addClass('focus');
hideTip($imgCaptchaInput);
});
// 邮箱自动完成列表项点击
... ... @@ -380,7 +402,7 @@ if (($phoneNumInput.val() !== '' || $phoneNumInput.val() === $phoneNumInput.attr
$passwordInput.focus();
}
// 同时监听三个事件
// 同时监听三个事件-- 密码登录
ep.tail('phone', 'password', 'captcha', function(phoneAuth, passwordAuth, captchaAuth) {
if (phoneAuth && passwordAuth && captchaAuth) {
$loginBtn.removeClass('auth_ok');
... ... @@ -389,6 +411,22 @@ ep.tail('phone', 'password', 'captcha', function(phoneAuth, passwordAuth, captch
}
});
// 同时监听三个事件-- 短信验证码登录
ep.tail('phone', 'captcha', 'smsCode', function(phoneAuth, captchaAuth, smsCodeAuth) {
if (phoneAuth && captchaAuth && smsCodeAuth) {
$loginBtn.removeClass('auth_ok');
} else {
$loginBtn.addClass('auth_ok');
}
});
// 如果密码登录的图形验证码隐藏状态就直接通过校验
if (currLoginType === 'PasswordLogin') {
if ($captchaWrap.hasClass('hide')) {
ep.emit('captcha', true);
}
}
ep.on('phone', function(auth) {
if (auth) {
hideTip($phoneNumInput);
... ... @@ -407,21 +445,267 @@ ep.on('captcha', function(auth) {
}
});
ep.on('smsCode', function(auth) {
if (auth && !$smsCodeWrap.hasClass('hide')) {
hideTip($smsCaptchaInput);
}
});
/** ***********************************************手机验证码登录*********************************************/
// 倒计时 60秒
function disable60sSendSmsBtn() {
secondCount -= 1;
if (secondCount < 0) {
secondCount = 60;
$smsBtn.val('获取短信验证码')
.removeClass('second-progress')
.removeClass('disable');
} else {
$smsBtn.addClass('disable')
.addClass('second-progress')
.val(secondCount + '秒后可重新操作');
window.setTimeout(disable60sSendSmsBtn, 1000);
}
}
// 发送短信验证码
function sendCaptchaSmsAsync() {
return $.ajax({
type: 'POST',
url: '/passport/login/sms/send',
data: {
area: getArea(),
mobile: getMoblie()
}
});
}
// 验证码输入本地校验
function validateCaptchaSmsLocal() {
var smsCaptcha = $.trim($smsCaptchaInput.val());
var length = smsCaptcha.length;
switch (length) {
case 0:
errTip($smsCaptchaInput, '请输入短信验证码');
return false;
case 4:
return true;
default:
errTip($smsCaptchaInput, '请输入长度为4字符的验证码');
return false;
}
}
// 异步校验短信验证码是否存在 Note: 这里的验证码只能成功验证一次,十分钟内有效
function validateCaptchaSmsAsync() {
var smsToken = $.trim($captchaSmsTokenHideInput.val());
if (isSmsCheckedSuccessFlag && smsToken !== '') {
return $.Deferred().resolve(true).promise(); // eslint-disable-line
}
return $.ajax({
url: '/passport/login/sms/auth',
type: 'POST',
data: {
area: getArea(),
mobile: getMoblie(),
code: $.trim($smsCaptchaInput.val())
}
}).then(function(data) {
if (data.code && data.code === 200) {
$captchaSmsTokenHideInput.val(data.token);
isSmsCheckedSuccessFlag = true;
return true;
} else if (data.code && data.code === 501) {
errTip($smsCaptchaInput, data.message);
$captchaSmsTokenHideInput.val('');
return false;
} else {
errTip($smsCaptchaInput, '验证码不正确');
$captchaSmsTokenHideInput.val('');
return false;
}
});
}
// 整合本地和异步验证信息--短信验证
function validateCaptchaSms() {
return (function() {
var defer = $.Deferred(); // eslint-disable-line
if (validateCaptchaSmsLocal()) {
validateCaptchaSmsAsync().then(function(result) {
if (result) {
defer.resolve(result);
} else {
defer.reject(result);
}
});
} else {
defer.reject(false);
}
return defer.promise();
}()).then(function() {
hideTip($smsCaptchaInput);
ep.emit('smsCode', true);
}).fail(function() {
ep.emit('smsCode', false);
});
}
// 切换登录方式
function changeLoginType() {
var type = $(this).data('type');
if ($(this).hasClass('selected')) {
return false;
}
currLoginType = type;
if (type === 'PasswordLogin') {
$pwdWrap.removeClass('hide');
$smsCodeWrap.addClass('hide');
if (!showCaptcha) {
$captchaWrap.addClass('hide');
ep.emit('captcha', true);
} else {
refreshCaptcha();
}
hideTip($smsCaptchaInput);
} else if (type === 'SMSLogin') {
$pwdWrap.addClass('hide');
$smsCodeWrap.removeClass('hide');
$captchaWrap.removeClass('hide');
ep.emit('captcha', false);
$smsCaptchaInput.val('');
hideTip($passwordInput);
refreshCaptcha();
}
hideTip($phoneNumInput);
hideTip($imgCaptchaInput);
$(this).siblings().removeClass('selected');
$(this).addClass('selected');
}
$('.login-page .switch > div').off().on('click', changeLoginType);
// 短信验证码发送按钮
$smsBtn.on('click', function() {
// 已在发送短信时间范围内
if ($smsBtn.hasClass('second-progress')) {
return;
}
validateAccount()
.then(validateCaptchaImg)
.then(function() {
disable60sSendSmsBtn();
return sendCaptchaSmsAsync();
});
});
// 短信验证码
$smsCaptchaInput.on('blur', function() {
$smsCaptchaInput.removeClass('focus');
validateCaptchaSms();
}).on('focus', function() {
$smsCaptchaInput.addClass('focus');
hideTip($smsCaptchaInput);
});
/** **************************************************登录事件********************************************/
// 登录
function login() {
return $.ajax({
url: '/passport/login/auth',
type: 'POST',
data: {
areaCode: getArea(),
account: getMoblie(),
password: currLoginType === 'PasswordLogin' ? $.trim($passwordInput.val()) : $captchaSmsTokenHideInput.val(), // eslint-disable-line
captcha: $.trim($imgCaptchaInput.val()),
isRemember: $remember.hasClass('checked') ? true : false,
loginType: currLoginType
},
success: function(res) {
if (res.code === 200) {
if (res.data) {
// 防止data.data为undefined时下行语句执行出错而导致脚本不能走到complete去处理authing
location.href = res.data.refer;
}
} else {
if (res.data.errorType === 'captcha') {
$imgCaptchaInput.val('');
} else {
$loginTip.removeClass('hide').children('em').html(res.message);
$passwordInput.val('');
}
// 验证错误次数
if (res.data && res.data.needCaptcha) {
showAccountErrTimes();
}
}
}
});
}
// 全部的本地验证-- 密码登录
function loginAsync() {
return validateAccount()
.then(validateCaptchaImg)
.then(function() {
var defer = $.Deferred(); // eslint-disable-line
if (validatePasswordLocal()) {
defer.resolve(true);
} else {
defer.reject(false);
}
return defer.promise();
}).then(function() {
return login();
});
}
// 全部的本地验证-- 短信验证登录
function smsLoginAsync() {
return validateAccount()
.then(validateCaptchaImg)
.then(validateCaptchaSms)
.then(function() {
return login();
});
}
// 登录
$loginBtn.on('click', function() {
if ($loginBtn.hasClass('auth_ok')) {
return;
}
loginAsync();
if (currLoginType === 'PasswordLogin') {
loginAsync();
} else {
smsLoginAsync();
}
});
// Enter登录
$('input.va').on('keypress', function(e) {
if (e.which === 13) {
loginAsync();
if (currLoginType === 'PasswordLogin') {
loginAsync();
} else {
smsLoginAsync();
}
}
});
// 首次触发
$imgCaptchaInput.triggerHandler('blur');
... ...
... ... @@ -58,7 +58,6 @@ function hideTip(ele) {
}
setTimeout(function() {
$phoneNumInput.val('');
$smsCaptchaInput.val('');
$passwordInput.val('');
$imgCaptchaInput.val('');
... ...
... ... @@ -27,7 +27,8 @@ $option-color: #f8f8f8;
@define-mixin passport-page {
font-size: 14px;
width: $item-width;
margin: $margin-top auto;
margin: $margin-top auto 0 auto;
height: 597px;
}
@define-mixin region {
... ... @@ -37,7 +38,7 @@ $option-color: #f8f8f8;
border-color: #c1c1c1;
color: #9a9a9a;
font-size: 16px;
font-family: '黑体' Regular;
font-family: "黑体" Regular;
float: left;
text-indent: 10px;
}
... ...
... ... @@ -29,6 +29,17 @@
.phone {
@mixin phone;
.rectangle {
width: auto;
min-width: 100%;
white-space: nowrap;
padding-right: 15px;
a {
padding-left: 5px;
}
}
}
.input {
... ... @@ -117,4 +128,66 @@
.img-captcha-wrapper {
width: $captcha;
}
.sms-captcha-wrapper {
width: $captcha;
.rectangle {
width: auto;
min-width: 100%;
white-space: nowrap;
}
}
$switchbg: #ccc;
.switch {
width: 100%;
height: 26px;
background: url(/passport/login-mode-bg.png) no-repeat;
font-size: 14px;
.left {
width: 170px;
height: 26px;
text-align: center;
line-height: @height;
position: absolute;
left: 0;
cursor: pointer;
&.selected {
background: url(/passport/login-mode-select.png) no-repeat;
color: white;
}
}
.right {
width: 170px;
height: 26px;
text-align: center;
line-height: @height;
position: absolute;
right: 0;
cursor: pointer;
&.selected {
background: url(/passport/login-mode-select.png) no-repeat;
color: white;
}
}
}
.sms-btn-wrap {
margin-left: 15px;
width: 130px;
height: 44px;
.sms-btn {
width: 100%;
height: 44px;
line-height: 44px;
border: none;
}
}
}
... ...