Authored by zhangxiaoru

merge

... ... @@ -5,11 +5,10 @@
* @date: 2016/05/09
*/
'use strict';
const _ = require('lodash');
const passport = require('passport');
// const md5 = require('md5');
const _ = require('lodash');
const uuid = require('uuid');
const cookie = global.yoho.cookie;
const helpers = global.yoho.helpers;
... ... @@ -99,9 +98,9 @@ const local = {
});
res.render('login', {
slideUnlock: _.get(req.session, 'login.errorCount') <= 0,
width750: true,
loginIndex: true, // 模板中使用JS的标识
captchaShow: _.get(req.session, 'login.errorCount') <= 0,
// 返回的URL链接
backUrl: 'javascript:history.go(-1)', // eslint-disable-line
... ... @@ -139,11 +138,11 @@ const local = {
});
res.render('international', {
slideUnlock: _.get(req.session, 'login.errorCount') <= 0,
width750: true,
// 返回的URL链接
backUrl: 'javascript:history.go(-1)', // eslint-disable-line
loginInternational: true, // 模板中使用JS的标识
captchaShow: _.get(req.session, 'login.errorCount') <= 0,
isPassportPage: true, // 模板中模块标识
headerText: '登录',
areaCode: '+86', // 默认区号
... ... @@ -156,11 +155,28 @@ const local = {
login: (req, res, next) => {
let count = _.get(req.session, 'login.errorCount');
if (count == null) { //eslint-disable-line
if (count == null) { // eslint-disable-line
_.set(req.session, 'login.errorCount', 3);
} else if (count <= 0) {
let captchaInput = req.body.captcha;
let captchaCode = _.get(req.session, 'captcha');
delete req.session.captcha; // 用过就丢弃
if (!captchaInput || !captchaCode || captchaInput !== captchaCode) {
res.json({
code: 400,
message: '请将图片旋转到正确方向',
captchaShow: true
});
return;
}
}
passport.authenticate('local', (err, user) => {
let loginSession = req.session.login;
if (err) {
let obj = {
code: 400,
... ... @@ -168,10 +184,10 @@ const local = {
data: ''
};
--req.session.login.errorCount;
--loginSession.errorCount;
if (req.session.login.errorCount <= 0) {
obj.slideUnlock = true;
if (loginSession.errorCount <= 0) {
obj.captchaShow = true;
}
res.json(obj);
... ...
... ... @@ -9,7 +9,7 @@
<div class="input-container row has-eye">
<input id="pwd" class="pwd input" type="password" placeholder="密码">
</div>
<div id="js-slideunlock" data-init="{{slideUnlock}}"></div>
<div id="js-img-check" {{#captchaShow }}data-init{{/captchaShow}}></div>
<span id="btn-login" class="btn btn-login disble row">登录</span>
</div>
... ...
... ... @@ -8,7 +8,7 @@
<div class="input-container row has-eye">
<input id="pwd" class="pwd input" type="password" placeholder="密码">
</div>
<div id="js-slideunlock" data-init="{{slideUnlock}}"></div>
<div id="js-img-check" {{#captchaShow }}data-init{{/captchaShow}}></div>
<span id="btn-login" class="btn btn-login disable">登录</span>
<p class="op-container">
<a class="sms-login" href={{smsLoginUrl}}>手机号码快捷登录</a>
... ... @@ -44,4 +44,4 @@
</li>
</ul>
</div>
</div>
\ No newline at end of file
</div>
... ...
... ... @@ -11,7 +11,7 @@ const isTest = process.env.NODE_ENV === 'test';
module.exports = {
app: 'h5',
appVersion: '5.1.0', // 调用api的版本
appVersion: '5.3.0', // 调用api的版本
port: 6001,
siteUrl: '//m.yohobuy.com',
assetUrl: '//127.0.0.1:5001',
... ...
... ... @@ -4,7 +4,7 @@
* @date: 2015/10/8
*/
var $ = require('yoho-jquery');
var SlideUnlock = require('plugin/slideunlock');
var ImgCheck = require('plugin/img-check');
var $phoneNum = $('#phone-num'),
$countrySelect = $('#country-select'),
... ... @@ -12,7 +12,7 @@ var $phoneNum = $('#phone-num'),
$pwd = $('#pwd'),
$loginBtn = $('#btn-login'),
slideUnlock,
$captcha = $('#js-img-check'),
pnPass = false,
pwdPass = false;
... ... @@ -23,11 +23,21 @@ var tip = require('../../plugin/tip');
var trim = $.trim;
var showErrTip = tip.show;
var imgCheck = new ImgCheck($captcha, {
useREM: {
rootFontSize: 40,
picWidth: 150
}
});
if ($captcha.data('init') != null) { //eslint-disable-line
imgCheck.init();
}
// 登录按钮状态切换
function switchLoginBtnStatus() {
var bool = slideUnlock ?
!(slideUnlock.isOk && pnPass && pwdPass) :
!(pnPass && pwdPass);
var bool = !(pnPass && pwdPass);
$loginBtn.toggleClass('disable', bool);
}
... ... @@ -75,23 +85,39 @@ $countrySelect.change(function() {
$loginBtn.on('touchstart', function() {
var pn = trim($phoneNum.val()),
areaCode = $countrySelect.val(),
pwd = trim($pwd.val());
pwd = trim($pwd.val()),
captcha = null;
if ($loginBtn.hasClass('disable')) {
return;
}
if (imgCheck.atWorking) {
captcha = imgCheck.getResults();
if (captcha === '0000') {
return tip.show(' 请将图片旋转到正确方向');
}
}
$loginBtn.text('正在登录...').addClass('disable');
if (api.phoneRegx[areaCode].test(pn) && api.pwdValidate(pwd)) {
let data = {
areaCode: areaCode.replace('+', ''),
account: pn,
password: pwd
};
if (imgCheck.atWorking) {
$.extend(data, {captcha});
}
$.ajax({
type: 'POST',
url: '/passport/login/auth',
data: {
areaCode: areaCode.replace('+', ''),
account: pn,
password: pwd
},
data,
success: function(data) {
var res,
time;
... ... @@ -121,22 +147,19 @@ $loginBtn.on('touchstart', function() {
$loginBtn.text('登录成功').off();
showErrTip('登录成功');
} else {
if (!slideUnlock && data.slideUnlock) {
slideUnlock = new SlideUnlock('#js-slideunlock', {}, switchLoginBtnStatus);
slideUnlock.init();
} else {
slideUnlock && slideUnlock.reset();
if (data.captchaShow) {
imgCheck.atWorking ? imgCheck.refresh() : imgCheck.init();
}
showErrTip(data.message);
resetForm();
}
},
error: function() {
showErrTip('网络断开连接啦~');
slideUnlock && slideUnlock.reset();
$loginBtn.text('登录');
imgCheck.atWorking && imgCheck.refresh();
}
});
} else {
... ... @@ -145,11 +168,6 @@ $loginBtn.on('touchstart', function() {
}
});
if ($('#js-slideunlock').data('init') === true) {
slideUnlock = new SlideUnlock('#js-slideunlock', {}, switchLoginBtnStatus);
slideUnlock.init();
}
// 对初始有默认值的情况去初始化登录按钮状态
$phoneNum.trigger('input');
$pwd.trigger('input');
... ...
... ... @@ -4,7 +4,7 @@
* @date: 2015/9/30
*/
var $ = require('yoho-jquery');
var SlideUnlock = require('plugin/slideunlock');
var ImgCheck = require('plugin/img-check');
var $account = $('#account'),
$pwd = $('#pwd'),
... ... @@ -13,7 +13,7 @@ var $account = $('#account'),
$mask = $('#retrive-pwd-mask'),
$ways = $('#retrive-pwd-ways'),
slideUnlock,
$captcha = $('#js-img-check'),
accPass = false,
pwdPass = false;
... ... @@ -24,13 +24,23 @@ var tip = require('../../plugin/tip');
var trim = $.trim;
var showErrTip = tip.show;
var imgCheck = new ImgCheck($captcha, {
useREM: {
rootFontSize: 40,
picWidth: 150
}
});
if ($captcha.data('init') != null) { //eslint-disable-line
imgCheck.init();
}
// 登录按钮状态切换
function switchLoginBtnStatus() {
var bool = true;
bool = slideUnlock ?
!(slideUnlock.isOk && accPass && pwdPass) :
!(accPass && pwdPass);
bool = !(accPass && pwdPass);
$loginBtn.toggleClass('disable', bool);
}
... ... @@ -80,23 +90,38 @@ $pwd.bind('input', function() {
// Login
$loginBtn.on('touchstart', function() {
var acc = trim($account.val()),
pwd = trim($pwd.val());
pwd = trim($pwd.val()),
captcha = null;
if ($loginBtn.hasClass('disable')) {
return;
}
if (imgCheck.atWorking) {
captcha = imgCheck.getResults();
if (captcha === '0000') {
return tip.show(' 请将图片旋转到正确方向');
}
}
$loginBtn.text('正在登录...').addClass('disable');
// 验证账号(数字或者邮箱)和密码合理性
if ((/^[0-9]+$/.test(acc) || api.emailRegx.test(acc)) && api.pwdValidate(pwd)) {
let data = {
account: acc,
password: pwd
};
if (imgCheck.atWorking) {
$.extend(data, {captcha});
}
$.ajax({
type: 'POST',
url: '/passport/login/auth',
data: {
account: acc,
password: pwd
},
data,
success: function(data) {
var res;
... ... @@ -107,21 +132,23 @@ $loginBtn.on('touchstart', function() {
location.href = res.href;
$loginBtn.text('登录成功').off();
} else {
if (!slideUnlock && data.slideUnlock) {
slideUnlock = new SlideUnlock('#js-slideunlock', {}, switchLoginBtnStatus);
slideUnlock.init();
} else {
slideUnlock && slideUnlock.reset();
if (data.captchaShow) {
imgCheck.atWorking ? imgCheck.refresh() : imgCheck.init();
}
showErrTip(data.message);
resetForm();
}
return data;
},
error: function() {
showErrTip('网络断开连接啦~');
slideUnlock && slideUnlock.reset();
$loginBtn.text('登录');
imgCheck.atWorking && imgCheck.refresh();
},
complete: function() {
$loginBtn.text('登录').removeClass('disable');
}
});
} else {
... ... @@ -144,11 +171,6 @@ $('#cancel-retrive').on('touchstart', function(e) {
hideRetrivePanel();
});
if ($('#js-slideunlock').data('init') === true) {
slideUnlock = new SlideUnlock('#js-slideunlock', {}, switchLoginBtnStatus);
slideUnlock.init();
}
// 对初始有默认值的情况去初始化登录按钮状态
$account.trigger('input');
$pwd.trigger('input');
... ...
... ... @@ -67,11 +67,17 @@ const ImgCheck = function(container, options) {
this.$imgPics = null;
this.picWidth = null;
this.atWorking = false;
return this;
};
ImgCheck.prototype = {
init: function() {
if (this.atWorking) {
return;
}
var self = this;
if (this.useREM) {
... ... @@ -81,6 +87,8 @@ ImgCheck.prototype = {
this.refresh().done(function() {
self.bindEvents();
});
this.atWorking = true;
},
/**
... ...
/**
* jquery plugin -- jquery.slideunlock.js
* Description: a slideunlock plugin based on jQuery
* Version: 1.1
* Author: Dong Yuhao
* www.sucaijiayuan.com
* created: March 27, 2016
*/
function SliderUnlock(elm, options, success) {
var me = this;
var html = require('common/slide-unlock.hbs')();
var $c = me.checkElm(elm) ? $(elm) : $;
success = me.checkFn(success) ? success : function() {};
me.elm = $(html).replaceAll($c);
me.$progress = me.elm.find('.progress');
me.$labelTip = me.elm.find('.label-tip');
var opts = {
successLabelTip: '验证成功',
duration: 200,
swipestart: false,
min: 0,
max: me.elm.width(),
index: 0,
isOk: false,
lableIndex: 0
};
opts = $.extend(opts, options || {});
$(opts.html).appendTo($c);
// $elm
// opts
me.opts = opts;
// 是否开始滑动
me.swipestart = opts.swipestart;
// 最小值
me.min = opts.min;
// 最大值
me.max = opts.max;
// 当前滑动条所处的位置
me.index = opts.index;
// 是否滑动成功
me.isOk = opts.isOk;
// 滑块宽度
me.labelWidth = me.elm.find('.label').width();
// 滑块背景
me.sliderBg = me.elm.find('#slider_bg');
// 鼠标在滑动按钮的位置
me.lableIndex = opts.lableIndex;
// success
me.success = success;
return this;
}
SliderUnlock.prototype.init = function() {
var me = this;
me.updateView();
me.elm.find('.label').on('mousedown', function(event) {
if (me.isOk) {
return;
}
var e = event || window.event;
me.lableIndex = e.clientX - this.offsetLeft;
me.handerIn();
}).on('mousemove', function(event) {
if (me.isOk) {
return;
}
me.handerMove(event);
}).on('mouseup', function(event) {
if (me.isOk) {
return;
}
me.handerOut();
}).on('mouseout', function(event) {
if (me.isOk) {
return;
}
me.handerOut();
}).on('touchstart', function(event) {
if (me.isOk) {
return;
}
var e = event || window.event;
me.lableIndex = e.originalEvent.touches[0].pageX - this.offsetLeft;
me.handerIn();
}).on('touchmove', function(event) {
if (me.isOk) {
return;
}
me.handerMove(event, 'mobile');
}).on('touchend', function(event) {
if (me.isOk) {
return;
}
me.handerOut();
});
};
/**
* 鼠标/手指接触滑动按钮
*/
SliderUnlock.prototype.handerIn = function() {
var me = this;
me.swipestart = true;
me.min = 0;
me.max = me.elm.width();
};
/**
* 鼠标/手指移出
*/
SliderUnlock.prototype.handerOut = function() {
var me = this;
// 停止
me.swipestart = false;
// me.move();
if (me.index < me.max) {
me.reset();
}
};
/**
* 鼠标/手指移动
* @param event
* @param type
*/
SliderUnlock.prototype.handerMove = function(event, type) {
var me = this;
if (me.swipestart) {
event.preventDefault();
event = event || window.event;
if (type === 'mobile') {
me.index = event.originalEvent.touches[0].pageX - me.lableIndex;
} else {
me.index = event.clientX - me.lableIndex;
}
me.move();
}
};
/**
* 鼠标/手指移动过程
*/
SliderUnlock.prototype.move = function() {
var me = this;
if ((me.index + me.labelWidth) >= me.max) {
me.index = me.max - me.labelWidth - 2;
// 停止
me.swipestart = false;
// 解锁
me.isOk = true;
}
if (me.index < 0) {
me.index = me.min;
// 未解锁
me.isOk = false;
}
if (me.index + me.labelWidth + 2 === me.max && me.max > 0 && me.isOk) {
// 解锁默认操作
$('.label').next('.label-tip').
text(me.opts.successLabelTip).css({
color: '#fff'
});
me.success();
}
me.updateView();
};
/**
* 更新视图
*/
SliderUnlock.prototype.updateView = function() {
var me = this;
me.sliderBg.css('width', me.index);
me.elm.find('.label').css('left', me.index + 'px');
me.$progress.css('width', me.index + 'px');
me.elm.toggleClass('slide-unlock-ok', me.isOk);
};
/**
* 重置slide的起点
*/
SliderUnlock.prototype.reset = function() {
var me = this;
me.index = 0;
me.isOk = false;
me.sliderBg.animate({
width: 0
}, me.opts.duration);
me.elm.find('.label').animate({
left: me.index
}, me.opts.duration);
me.$labelTip
.text('向右滑动验证')
.animate({
opacity: 1
}, me.opts.duration);
me.updateView();
};
/**
* 检测元素是否存在
* @param elm
* @returns {boolean}
*/
SliderUnlock.prototype.checkElm = function(elm) {
if ($(elm).length > 0) {
return true;
} else {
throw 'this element does not exist.';
}
};
/**
* 检测传入参数是否是function
* @param fn
* @returns {boolean}
*/
SliderUnlock.prototype.checkFn = function(fn) {
if (typeof fn === 'function') {
return true;
} else {
throw 'the param is not a function.';
}
};
module.exports = SliderUnlock;
... ... @@ -11,7 +11,6 @@
/* component */
@import "layout/modal";
@import "layout/slide-unlock";
@import "layout/img-check";
/* module */
... ...
.slide-unlock {
margin: 10PX auto 15PX;
height: 80px;
position: relative;
border-radius: 2px;
background-color: #b3b3b3;
border-radius: 5PX;
overflow: hidden;
text-align: center;
user-select: none;
-moz-user-select: none;
-webkit-user-select: none;
.bg {
position: absolute;
left: 0;
top: 0;
height: 100%;
background-color: #7ac23c;
z-index: 1;
}
.label {
width: 80px;
position: absolute;
left: 0;
top: 0;
height: 80px;
line-height: 80px;
outline: 1px solid #ccc;
border-radius: 4PX;
background: #e7e7e7;
z-index: 3;
cursor: move;
color: #ff9e77;
font-size: 16px;
font-weight: 900;
&:after {
display: block;
font-family: "iconfont";
content: "\e901";
color: #757575;
font-size: 25px;
}
}
.label-tip {
position: absolute;
left: 0;
width: 100%;
height: 100%;
font-size: 28px;
color: #787878;
line-height: 80px;
text-align: center;
z-index: 2;
}
.progress {
float: left;
height: 80px;
background-color: #36a74c;
}
}
.slide-unlock-ok .label:after {
content: "\e900" !important;
}