Authored by htoooth

add passport

Showing 43 changed files with 2275 additions and 902 deletions
... ... @@ -185,45 +185,33 @@ const validateCodeByEmailPage = (req, res, next) => {
.catch(next);
};
const resetPasswordPage = (req, res, next) => {
const resetPasswordPage = (req, res) => {
let code = req.query.code || '';
passportHelper.getLeftBannerAsync()
.then(result => {
res.render('back/reset-pwd', Object.assign({
module: 'passport',
page: 'back-reset-pwd',
title: '重置密码'
}, {
resetPwd: Object.assign({
coverHref: result.url,
coverImg: result.img,
code: code
}, req.mobileAuth)
}));
})
.catch(next);
res.render('back/reset-pwd', Object.assign({
module: 'passport',
page: 'back-reset-pwd',
title: '重置密码'
}, {
resetPwd: Object.assign({
code: code
}, req.mobileAuth)
}));
};
const verifyCodeByMobilePage = (req, res, next) => {
passportHelper.getLeftBannerAsync()
.then(result => {
res.render('back/verification', Object.assign({
module: 'passport',
page: 'back-verify-mobile-code',
title: '手机验证'
}, {
verification: {
coverHref: result.url,
coverImg: result.img,
mobile: req.body.mobile,
area: req.body.area,
verifyCode: req.body.verifyCode
}
}));
})
.catch(next);
const verifyCodeByMobilePage = (req, res) => {
res.render('back/verification', Object.assign({
module: 'passport',
page: 'back-verify-mobile-code',
title: '手机验证'
}, {
verification: {
mobile: req.body.mobile,
area: req.body.area,
verifyCode: req.body.verifyCode
}
}));
};
const validateSuccessStatusPage = (req, res, next) => {
... ...
... ... @@ -11,7 +11,6 @@ const helpers = global.yoho.helpers;
const PassportHelper = require('../models/passport-helper');
const BindService = require('../models/bind-service');
const AuthHelper = require('../models/auth-helper');
const UserService = require('../models/user-service');
const Sources = {
qq: 'QQ',
... ... @@ -27,84 +26,119 @@ const bind = {
let openId = req.query.openId;
let sourceType = req.query.sourceType;
res.render('bind', {
thirdLogin: true,
openId: openId,
sourceType: sourceType,
region: PassportHelper.getCountry(),
serviceUrl: helpers.urlFormat('/help', {
category_id: 9
}),
res.render('bind/index', Object.assign({
module: 'passport',
page: 'bind',
title: '联合登录补全信息'
});
}, {
openId: openId,
sourceType: sourceType,
region: PassportHelper.getCountry(),
local: '+86',
imgCaptcha: helpers.urlFormat('/passport/images', {t: Date.now()})
}));
},
noregist: (req, res) => {
bindSetPwdPage: (req, res) => {
let mobile = req.body.mobile;
let sourceType = req.body.sourceType;
let openId = req.body.openId;
let area = req.body.area;
res.render('bind/noregist', {
enablePerfectInformation: true,
res.render('bind/bind-set-pwd', Object.assign({
module: 'passport',
page: 'bind-set-pwd',
title: '登录绑定'
}, {
mobile: mobile,
sourceType: sourceType,
openId: openId,
area: area,
module: 'passport',
page: 'noregist',
title: '登录绑定'
});
area: area
}));
},
relate: (req, res, next) => {
let mobile = req.body.mobile;
let sourceType = req.body.sourceType;
let openId = req.body.openId;
let area = req.body.area;
bindConfirmPage: (req, res) => {
let thirdPart = req.body.thirdPart;
let user = req.body.user;
UserService.findByMobileAsync(area, mobile).then(user => {
if (user) {
return {
thumb: user.headImg,
userName: user.username,
loginHref: user.bindLogin
};
} else {
return {};
}
}).then(user => {
let data = _.assign(user, {
phoneNum: mobile,
areaCode: area,
openId: openId,
sourceType: sourceType,
changeHref: helpers.urlFormat('/passport/thirdlogin/index', {openId: openId, sourceType: sourceType}),
module: 'passport',
page: 'noregist',
title: '账号关联'
});
res.render('bind/relate', data);
}).catch(next);
const DEFAULT_URL = 'http://img10.static.yhbimg.com/headimg/2013/11/28/09/01cae078abe5fe320c88cdf4c220212688.gif?imageView/2/w/100/h/100';
let avatar = user.headImg || DEFAULT_URL;
res.render('bind/bind-confirm', Object.assign({
module: 'passport',
page: 'bind-confirm',
title: '绑定确认'
}, {
avatar: avatar,
name: user.username || '咸鸭蛋',
bindSuccess: helpers.urlFormat('/thirdlogin/bindSuccess', {
sourceType: thirdPart.sourceType
}),
bindUrl: helpers.urlFormat('/passport/thirdlogin/index', {
openId: thirdPart.openId,
sourceType: thirdPart.sourceType
}),
loginUrl: helpers.urlFormat('/passport/login'),
uid: user.uid,
mobile: thirdPart.mobile,
area: thirdPart.area,
code: thirdPart.code,
sourceType: thirdPart.sourceType
}));
},
bindSuccess: (req, res) => {
bindSuccessPage: (req, res) => {
let sourceType = _.trim(req.query.sourceType);
let sourceInfo = sourceType.split('_');
let sourceName = Sources[sourceInfo[0]];
let isRelate = (sourceInfo[1] === 'relate');
let data = {
thirdLogin: true,
goShopping: helpers.urlFormat('/'),
sourceName: sourceName,
relate: isRelate,
res.render('bind/bind-success', Object.assign({
module: 'passport',
page: 'bind-success',
title: '绑定手机号'
};
}, {
goShopping: helpers.urlFormat('/'),
sourceName: sourceName
}));
},
relateSuccessPage: (req, res) => {
let sourceType = _.trim(req.query.sourceType);
let sourceInfo = sourceType.split('_');
let sourceName = Sources[sourceInfo[0]];
res.render('bind/relate-success', Object.assign({
module: 'passport',
page: 'relate-success',
title: '关联手机号'
}, {
goShopping: helpers.urlFormat('/'),
sourceName: sourceName
}));
},
relateConfirmPage: (req, res) => {
let thirdPart = req.body.thirdPart;
let user = req.body.user;
const DEFAULT_URL = 'http://img10.static.yhbimg.com/headimg/2013/11/28/09/01cae078abe5fe320c88cdf4c220212688.gif?imageView/2/w/100/h/100';
let avatar = user.headImg || DEFAULT_URL;
res.render('bind/success', data);
res.render('bind/relate-confirm', Object.assign({
module: 'passport',
page: 'bind-confirm',
title: '关联确认'
}, {
avatar: avatar,
name: user.username || '咸鸭蛋',
relateUrl: helpers.urlFormat('/passport/thirdlogin/index', {
openId: thirdPart.openId,
sourceType: thirdPart.sourceType
}),
signinUrl: helpers.urlFprmat('/passport/login'),
mobile: thirdPart.mobile,
area: thirdPart.area,
sourceType: thirdPart.sourceType,
openId: thirdPart.openId
}));
},
bindCheck: (req, res, next) => {
let mobile = req.body.mobile;
... ... @@ -115,35 +149,35 @@ const bind = {
if (mobile && openId && area && sourceType) {
BindService.bindCheck(mobile, openId, sourceType, area).then(result => {
if (!result || !result.code) {
return { code: 400, message: '', data: '' };
return {code: 400, message: '', data: ''};
} else if (result.code === 200 && result.data.is_register === 0) {
let nextUrl = helpers.urlFormat('/passport/thirdlogin/noregist');
let nextUrl = helpers.urlFormat('/passport/thirdlogin/bindSetPwd');
// 绑定流程:code=200 未注册,可绑定
return { code: 200, message: result.message, data: { next: nextUrl } };
return {code: 200, message: result.message, data: {next: nextUrl}};
} else if (result.code === 200 && result.data.is_register === 1) {
return PassportHelper.getUserInfo(area, mobile).then(user => {
// 绑定流程:code=201 已注册 绑定过其他第三方
return {code: 201, message: result.message, data: { user: user } };
return {code: 201, message: result.message, data: {user: user}};
});
} else if (result.code === 200 && result.data.is_register === 3) {
let nextUrl = helpers.urlFormat('/passport/thirdlogin/relate');
// 关联流程
return { code: 203, message: result.message, data: { next: nextUrl } };
return {code: 203, message: result.message, data: {next: nextUrl}};
} else if (result.code === 506 || result.code === 505) {
return PassportHelper.getUserInfo(area, mobile).then(user => {
// 绑定流程:code=201 已注册 绑定过其他第三方
return { code: 205, message: result.message, data: { user: user } };
return {code: 205, message: result.message, data: {user: user}};
});
} else {
return { code: result.code, message: result.message, data: result.data ? result.data : '' };
return {code: result.code, message: result.message, data: result.data ? result.data : ''};
}
}).then(result => {
res.json(result);
}).catch(next);
} else {
res.json({ code: 400, message: '', data: '' });
res.json({code: 400, message: '', data: ''});
}
},
sendBindMsg: (req, res, next) => {
... ... @@ -154,7 +188,7 @@ const bind = {
if (result && result.code) {
res.json(result);
} else {
res.json({ code: 400, message: '', data: '' });
res.json({code: 400, message: '', data: ''});
}
}).catch(next);
},
... ... @@ -167,7 +201,7 @@ const bind = {
if (result && result.code) {
res.json(result);
} else {
res.json({ code: 400, message: '', data: '' });
res.json({code: 400, message: '', data: ''});
}
}).catch(next);
},
... ... @@ -176,16 +210,9 @@ const bind = {
let area = _.trim(req.body.area) || '86';
let openId = _.trim(req.body.openId);
let sourceType = _.trim(req.body.sourceType);
let code = _.trim(req.body.code);
let password = _.trim(req.body.password) || '';
BindService.checkBindCode(area, mobile, code).then(result => {
if (result && result.code !== 200) {
return { code: 402, message: '短信验证码不正确', data: '' };
} else {
return BindService.bindMobile(openId, sourceType, mobile, area, password);
}
}).then(result => {
BindService.bindMobile(openId, sourceType, mobile, area, password).then(result => {
if (result && result.code) {
if (result.code === 200 && result.data && result.data.uid) {
let refer = helpers.urlFormat('/passport/thirdlogin/bindsuccess', {
... ... @@ -193,10 +220,10 @@ const bind = {
});
return AuthHelper.syncUserSession(result.data.uid, req, res).then(() => {
return { code: 200, message: result.message, data: {refer: refer }};
return {code: 200, message: result.message, data: {refer: refer}};
});
} else {
return { code: result.code, message: result.message, data: { refer: ''} };
return {code: result.code, message: result.message, data: {refer: ''}};
}
} else {
return {code: 400, message: '', data: ''};
... ... @@ -210,37 +237,26 @@ const bind = {
let openId = req.body.openId;
let areaCode = req.body.areaCode || '86';
let sourceType = req.body.sourceType;
let code = req.body.code;
if (_.isNumber(parseInt(mobile, 0)) && openId && areaCode && sourceType && code) {
BindService.checkBindCode(areaCode, mobile, code).then(result => {
if (result && result.code && result.code === 200) {
return BindService.relateMobile(openId, sourceType, mobile, code);
} else {
return { code: 402, message: '短信验证码错误', data: '' };
}
}).then(result => {
if (result && result.code) {
if (result.code === 200 && result.data && result.data.uid) {
let refer = helpers.urlFormat('/passport/thirdlogin/bindsuccess', {
sourceType: sourceType + '_bind'
});
return AuthHelper.syncUserSession(result.data.uid, req, res).then(() => {
return { code: 200, message: result.message, data: {refer: refer }};
});
} else {
return { code: result.code, message: result.message, data: { refer: ''} };
}
return BindService.relateMobile(openId, sourceType, mobile, areaCode).then(result => {
if (result && result.code) {
if (result.code === 200 && result.data && result.data.uid) {
let refer = helpers.urlFormat('/passport/thirdlogin/relatesuccess', {
sourceType: sourceType + '_bind'
});
return AuthHelper.syncUserSession(result.data.uid, req, res).then(() => {
return {code: 200, message: result.message, data: {refer: refer}};
});
} else {
return {code: 400, message: '', data: ''};
return {code: result.code, message: result.message, data: {refer: ''}};
}
}).then(result => {
res.json(result);
}).catch(next);
} else {
res.json({ code: 400, message: '', data: '' });
}
} else {
return {code: 400, message: '', data: ''};
}
}).then(result => {
res.json(result);
}).catch(next);
}
};
... ...
... ... @@ -45,8 +45,25 @@ const generate = (req, res) => {
res.end(captcha.image);
};
const requiredPost = (req, res) => {
let captchaToken = req.body.verifyCode || '';
if (captchaToken === req.session.captcha) {
return res.json({
code: 200,
data: {}
});
} else {
return res.json({
code: 400,
message: '您输入的验证码不正确!'
});
}
};
module.exports = {
requiredAPI,
requiredPage,
generate
generate,
requiredPost
};
... ...
... ... @@ -33,22 +33,14 @@ function doPassportCallback(req, res, user) {
refer = config.siteUrl;
}
if (user.openId && user.nickname) {
let signinByOpenID;
if (user.sourceType === 'wechat') {
// PC 的微信登录之前使用了 open_id, 所以需要特别的接口处理
signinByOpenID = AuthHelper.signinByWechat(
user.nickname, user.openId, user.unionId, user.sourceType, shoppingKey);
} else {
signinByOpenID = AuthHelper.signinByOpenID(
user.nickname, user.openId, user.sourceType, shoppingKey);
}
let signinByOpenID = AuthHelper.signinByOpenID(
user.nickname, user.openId, user.sourceType, shoppingKey, user.unionId);
return signinByOpenID.then((result) => {
if (result.code !== 200) {
return Promise.reject(result);
}
if (result.data['is_bind'] && result.data['is_bind'] === 'N') { //eslint-disable-line
return helpers.urlFormat('/passport/thirdlogin/index', {
openId: user.unionId || user.openId,
... ...
... ... @@ -22,12 +22,12 @@ const Auth = {
return api.post('', param);
},
signinByOpenID(nickname, openId, sourceType, shoppingKey) {
signinByOtherOpenID(nickname, openId, sourceType, shoppingKey) {
let param = {
nickname: nickname,
openId: openId,
source_type: sourceType,
method: 'app.passport.signinByOpenID'
method: 'app.passport.signinByOtherOpenID'
};
if (shoppingKey) {
... ... @@ -36,7 +36,7 @@ const Auth = {
return api.get('', param);
},
signinByWechat(nickname, openId, unionId, sourceType, shoppingKey) {
signinByWechat(nickname, openId, sourceType, shoppingKey, unionId) {
let param = {
nickname: nickname,
openId: openId,
... ... @@ -51,6 +51,17 @@ const Auth = {
return api.get('', param);
},
signinByOpenID(nickname, openId, sourceType, shoppingKey, unionId) {
let signinFunc = {
other: this.signinByOtherOpenID,
wechat: this.signinByWechat
};
// PC 的微信登录之前使用了 open_id, 所以需要特别的接口处理
let type = sourceType !== 'wechat' ? 'other' : sourceType;
return signinFunc[type](nickname, openId, sourceType, shoppingKey, unionId);
},
profile(uid) {
let param = {
uid: uid,
... ...
... ... @@ -15,8 +15,6 @@ const userService = require('./user-service');
const passportHelper = require('./passport-helper');
const backHelper = require('./back-helper');
const BACK_LEFT_BANNER_CODE = '3bbaf502c447a2ddad60879042e286d8'; // 找回密码左边的banner
/**
* 验证手机和邮箱输入正确性
*/
... ... @@ -99,17 +97,13 @@ const sendCodeToMobileAsync = (areaCode, mobile) => {
*/
const indexPageDataAsync = () => {
return co(function *() {
let banner = yield passportHelper.getLeftBannerAsync(BACK_LEFT_BANNER_CODE);
let countryList = passportHelper.getCountry();
return {
back: {
coverHref: banner.url,
coverImg: banner.img,
countryCode: 86,
countryName: '中国',
captchaUrl: helpers.urlFormat('/passport/images', {t: moment().unix()}),
countryList: countryList
region: countryList,
captchaUrl: helpers.urlFormat('/passport/images'),
location: '+86'
}
};
})();
... ...
... ... @@ -23,7 +23,7 @@ const getLeftBannerAsync = (resourceCode) => {
url: ''
};
return co(function* () {
return co(function * () {
let resource = yield indexService.getResourceAsync(resourceCode);
if (_.isEmpty(resource)) {
... ... @@ -257,7 +257,7 @@ const getUserInfo = (area, mobile) => {
return {
username: profile,
headImg: user.head_ico ? helpers.image(user.head_ico, 100, 100, 2) : DEFAULT_HEAD_IMG_ICO,
bindLogin: helpers.urlFormat('/signin.html', { bindMobile: mobile, bindArea: area })
bindLogin: helpers.urlFormat('/signin', { bindMobile: mobile, bindArea: area })
};
});
};
... ...
... ... @@ -34,18 +34,16 @@ const findByEmailAsync = (email) => {
return api.get('', {
email: email,
method: 'app.passport.getProfileByEmail'
})
.then(result => {
if (!result.code || result.code !== 200 || !result.data || _.isEmpty(result.data)) {
return EMPTY;
}
}).then(result => {
if (!result.code || result.code !== 200 || !result.data || _.isEmpty(result.data)) {
return EMPTY;
}
return result.data;
return result.data;
})
.catch(() => {
return EMPTY;
});
}).catch(() => {
return EMPTY;
});
};
module.exports = {
... ...
... ... @@ -51,13 +51,22 @@ router.get('/login/account', login.common.needCaptcha);
// 第三方登录后绑定
router.get('/thirdlogin/index', bind.indexPage);
router.get('/thirdlogin/bindsuccess', bind.bindSuccess);
router.post('/thirdlogin/noregist', bind.noregist);
router.post('/thirdlogin/bindsetpwd', bind.bindSetPwdPage);
router.post('/thirdlogin/bindConfirm', bind.bindConfirmPage);
router.get('/thirdlogin/bindSuccess', bind.bindSuccessPage);
router.post('/autouserinfo/bindMobile', bind.bindMobile);
router.post('/autouserinfo/bindCheck', bind.bindCheck);
router.post('/autouserinfo/sendBindMsg', bind.sendBindMsg);
router.post('/autouserinfo/checkBindMsg', bind.checkBindMsg);
router.post('/autouserinfo/bindMobile', bind.bindMobile);
router.post('/autouserinfo/relatemobile', bind.relateMobile);
// 第三方登录后关联
router.post('/thirdlogin/relateConfirm', bind.relateConfirmPage);
router.get('/thirdlogin/relateSuccess', bind.relateSuccessPage);
/**
* 注册页面路由
... ... @@ -147,5 +156,6 @@ router.get('/back/resetSuccess',
back.resetPwdSuccessPage);
router.get('/images', captcha.generate);
router.post('/images/check', captcha.requiredPost);
module.exports = router;
... ...
<div class="back-page passport-page yoho-page clearfix">
{{> sign-header}}
<div class="back-page passport-page clearfix">
{{# back}}
{{> back/cover}}
<div class="content">
<div class="back-header clearfix">
<h2 class="title">找回密码</h2>
<span id="country-code" class="country-code">
<em>{{countryName}} +{{countryCode}}</em>
<i class="iconfont">&#xe61d;</i>
</span>
<ul id="country-code-list" class="country-code-list">
{{# countryList}}
<li data-cc="{{areaCode}}">{{name}} {{areaCode}}</li>
{{/ countryList}}
</ul>
<ul>
<li class="clearfix">
<div class="title">密码重置</div>
</li>
<div class="indicator">
<li class="clearfix small">
<div class="draw">
<div class="step first cur-step">
<div class="circle"></div>
</div>
<div class="step">
<div class="line"></div>
</div>
<div class="step second">
<div class="circle ring"></div>
</div>
<div class="step">
<div class="line"></div>
</div>
<div class="step third cur-step">
<div class="circle ring"></div>
</div>
</div>
</li>
<li class="clearfix small">
<div class="text">
<div class="step first cur-step">验证身份</div>
<div class="step second">重置密码</div>
<div class="step third">重置成功</div>
</div>
</li>
</div>
<li style="margin-bottom: 0">
</li>
<form id="back-form" class="back-form" action="/passport/back/email" method="post">
<input id="country-code-hide" type="hidden" name="area" value="+86">
<ul>
<li class="input-container-li clearfix">
<input id="phone-num" class="input va phone-num" type="text" name="phoneNum" placeholder="邮箱/手机号码" autocomplete="off">
<span id="account-err" class="err-tip hide">
<i></i>
<em>账户名不能为空</em>
</span>
</li>
<li class="input-container-li clearfix">
<input id="captcha" class="input va captcha" type="text" name="verifyCode" placeholder="验证码" autocomplete="off" maxlength="4">
<li class="clearfix">
<select id="area" class="country-list" name="region">
{{#each region}}
<option {{#if selected}}selected="selected"{{/if}} value="{{areaCode}}">{{name}}</option>
{{/each}}
</select>
<div id="phone" class="phone">
<span id="country-code" class="country-code">{{location}}</span>
<input value="" id="phoneNum" class="input va phone-num" type="text" name="phoneNum"
placeholder="Phone Number" autocomplete="off">
</div>
</li>
<li class="clearfix">
<input id="verifyCode" class="input va captcha" type="text" name="verifyCode" placeholder="图形验证码"
autocomplete="off" maxlength="4">
<div class="left captcha-component">
<img id="captcha-img" class="captcha-img" src="{{captchaUrl}}" alt="">
<a id="change-captcha" class="link change-captcha">换一张</a>
<a class="left link change-captcha"><span class="iconfont gray">&#xe613;</span></a>
</div>
<span id="captcha-err" class="err-tip captcha-err hide">
<i></i>
<em>验证码不能为空</em>
</span>
</li>
<li class="input-container-li clearfix">
<input name="refer" id="refer" type="hidden" value="http%3A%2F%2Fwww.yohobuy.com%2F">
<input id="find-btn" class="btn find-btn disable" type="submit" value="下一步" disabled="">
</li>
</ul>
</li>
<li class="clearfix">
<input name="refer" id="refer" type="hidden" value="http%3A%2F%2Fwww.yohoblk.com%2F">
<div class="center">
<input id="find-btn" class="find-btn disable" type="submit" value="下一步" disabled="">
</div>
</li>
</form>
</div>
</ul>
{{/ back}}
</div>
... ...
{{> sign-header}}
<div class="reset-pwd-page back-page passport-page yoho-page clearfix">
{{# resetPwd}}
{{> back/cover}}
<div class="content">
<h2 class="title2">重置密码</h2>
<ul>
<li class="clearfix">
<div class="title">密码重置</div>
</li>
<div class="indicator">
<li class="clearfix small">
<div class="draw">
<div class="step first cur-step">
<div class="circle"></div>
</div>
<div class="step">
<div class="line cur-step"></div>
</div>
<div class="step second">
<div class="circle"></div>
</div>
<div class="step">
<div class="line cur-step"></div>
</div>
<div class="step third cur-step">
<div class="circle ring"></div>
</div>
</div>
</li>
<li class="clearfix small">
<div class="text">
<div class="step first cur-step">验证身份</div>
<div class="step second cur-step">重置密码</div>
<div class="step third">重置成功</div>
</div>
</li>
</div>
<li style="margin-bottom: 0">
</li>
<form id="reset-pwd-form" class="reset-pwd-form" method="POST" action="/passport/back/update">
<ul>
<li class="input-container-li po-re">
<input id="pwd" class="input va pwd" type="password" name="pwd" placeholder="新密码"
maxlength="20">
<div class="pwd-intensity-container">
<span class="pwd-intensity low"></span>
<span class="pwd-intensity mid"></span>
<span class="pwd-intensity high"></span>
<li class="input-container-li po-re">
<input id="pwd" class="input va pwd" type="password" name="pwd" placeholder="新的登录密码"
maxlength="20">
<div id="pwd-tips" class="pwd-tips hide">
<div class="default" id="pwd-tip1">
<i></i>
密码只支持6-20位字符
</div>
<div id="pwd-tips" class="pwd-tips hide">
<div class="default" id="pwd-tip1">
<i></i>
密码只支持6-20位字符
</div>
<div class="default" id="pwd-tip2">
<i></i>
由字母、 数字组合,不能包含特殊符号
</div>
<div class="default" id="pwd-tip2">
<i></i>
由字母、 数字组合,不能包含特殊符号
</div>
</div>
<span id="pwd-err" class="err-tip hide">
<i></i>
<em>请输入密码</em>
</span>
</li>
<li class="input-container-li clearfix po-re">
<input id="re-input" class="input va re-input repwd" type="password" name="re-input"
placeholder="再次输入" maxlength="20">
</li>
<li class="clearfix">
<input id="re-input" class="input va re-input repwd" type="password" name="re-input"
placeholder="确认登录密码" maxlength="20">
<span id="repwd-err" class="err-tip hide">
<i></i>
<em>请输入密码确认</em>
</span>
</li>
<li class="input-container-li clearfix">
<input type="hidden" name="code" value="{{code}}">
<input type="hidden" name="mobile" value="{{mobile}}">
<input type="hidden" name="area" value="{{area}}">
<input type="hidden" name="token" value="{{token}}">
<input type="hidden" name="createdAt" value="{{createdAt}}">
<input id="reset-pwd-btn" class="btn reset-pwd-btn" type="submit" value="提交" disabled="">
</li>
</ul>
</li>
<li class="clearfix blank">
<input type="hidden" name="code" value="{{code}}">
<input type="hidden" name="mobile" value="{{mobile}}">
<input type="hidden" name="area" value="{{area}}">
<input type="hidden" name="token" value="{{token}}">
<input type="hidden" name="createdAt" value="{{createdAt}}">
</li>
<li>
<div>
<input id="reset-pwd-btn" class="reset-pwd-btn" type="submit" value="下一步" disabled="">
</div>
</li>
</form>
</div>
</ul>
{{/ resetPwd}}
</div>
... ...
{{> sign-header}}
<div class="reset-success-page back-page passport-page yoho-page clearfix">
{{# resetSuccess}}
{{> back/cover}}
<div class="content">
<ul>
<li class="clearfix">
<div class="title">密码重置</div>
</li>
<div class="indicator">
<li class="clearfix small">
<div class="draw">
<div class="step first cur-step">
<div class="circle"></div>
</div>
<div class="step">
<div class="line cur-step"></div>
</div>
<div class="step second">
<div class="circle"></div>
</div>
<div class="step">
<div class="line cur-step"></div>
</div>
<div class="step third cur-step">
<div class="circle"></div>
</div>
</div>
</li>
<li class="clearfix small">
<div class="text">
<div class="step first cur-step">验证身份</div>
<div class="step second cur-step">重置密码</div>
<div class="step third cur-step">重置成功</div>
</div>
</li>
</div>
<li style="margin-bottom: 0">
</li>
<div class="success-text">
<i class="iconfont">&#xe620;</i><span>恭喜!</span>密码修改成功,&nbsp;<span id="count-down">5</span>&nbsp;&nbsp;秒后将跳转至首页
<div class="title">恭喜您设置完成,请妥善保存您的密码!</div>
<div class="time">页面将在&nbsp;<span id="count-down" class="blue">5</span>&nbsp;秒后将跳转至首页</div>
</div>
<a class="success-btn" href="/">随便逛逛</a>
</div>
</ul>
{{/ resetSuccess}}
</div>
<script type="text/javascript">
(function() {
(function () {
var count = 5,
countDown = document.getElementById('count-down');
console.log(countDown);
var timer = setInterval(function(){
var timer = setInterval(function () {
if (count > 1) {
count--;
countDown.innerHTML = count;
... ...
<div class="send-email-page passport-page yoho-page clearfix">
{{# sendEmail}}
{{> back/cover}}
<div class="content">
<div class="send-tips"><i class="iconfont">&#xe61e;</i>我们已经把验证邮件发送至您的邮箱,请在24小时内通过邮件内的<br>链接继续设置新的密码。</div>
<div class="no-find">没有收到?到您邮箱的垃圾邮件里找找。</div>
... ...
<div class="verification-page back-page passport-page yoho-page clearfix">
{{> sign-header}}
<div class="verification-page back-page passport-page clearfix">
{{# verification}}
{{> back/cover}}
<div class="content">
<ul>
<li class="clearfix">
<div class="title">密码重置</div>
</li>
<div class="indicator">
<li class="clearfix small">
<div class="draw">
<div class="step first cur-step">
<div class="circle"></div>
</div>
<div class="step">
<div class="line cur-step"></div>
</div>
<div class="step second">
<div class="circle ring"></div>
</div>
<div class="step">
<div class="line"></div>
</div>
<div class="step third cur-step">
<div class="circle ring"></div>
</div>
</div>
</li>
<li class="clearfix small">
<div class="text">
<div class="step first cur-step">验证身份</div>
<div class="step second cur-step">重置密码</div>
<div class="step third">重置成功</div>
</div>
</li>
</div>
<li style="margin-bottom: 0">
</li>
<li class="clearfix">
<div class="desc">
<span>手机验证码已经发送至{{mobile}}</span><br>
<span>请在有效时间内输入验证码点击下一步来重置密码</span>
</div>
</li>
<form id="verification-form" class="verification-form" method="POST" action="/passport/back/backmobile">
<ul>
<li class="head-title">验证身份</li>
<li class="po-re">
<label class="pn-label">手机号码</label>
<span class="country-code">+{{area}}</span>
<span class="phone-num">{{mobile}}</span>
</li>
<li class="po-re">
<input id="captcha" class="input va captcha" type="text" name="code" maxlength="4">
<input id="send-captcha" class="btn send-captcha" type="button" value="发送验证码" disabled="">
<div id="captcha-tip" class="captcha-tips"><i class="iconfont">&#xe61f;</i>验证码已发送至您的手机,请查收</div>
<li>
<input id="captcha" class="input va captcha" type="text" name="code" maxlength="4"
placeholder="请输入短信验证码">
<input id="send-captcha" class="input send-captcha" type="button" value="获取短信验证码" disabled="">
<span id="err-tip" class="err-tip hide">
<i></i>
<em>请输入验证码</em>
</span>
</li>
<li>
<input name="area" id="area" type="hidden" value="{{area}}">
<input name="mobile" id="mobile" type="hidden" value="{{mobile}}">
<input name="verifyCode" id="captchaPic" type="hidden" value="{{verifyCode}}">
<input name="refer" id="refer" type="hidden" value="">
<a id="next-step" class="btn next-step disable" href="javascript:;">下一步</a>
<!-- <input id="next-step" class="btn next-step disable" type="submit" value="下一步" disabled=""> -->
</li>
</ul>
</li>
<li class="blank">
<input name="area" id="area" type="hidden" value="{{area}}">
<input name="mobile" id="mobile" type="hidden" value="{{mobile}}">
<input name="verifyCode" id="captchaPic" type="hidden" value="{{verifyCode}}">
<input name="refer" id="refer" type="hidden" value="">
</li>
<li>
<a id="next-step" class="next-step disable" href="javascript:;">下一步</a>
</li>
</form>
</div>
</ul>
{{/ verification}}
</div>
... ...
{{> sign-header}}
<div class="bind-wrapper">
<div id="bindConfirmPage" class="bindConfirmPage">
<ul>
<li class="clearfix big-width">
<div class="center">
{{#if avatar}}
<img id="avatar" class="avatar" src="{{avatar}}">
{{^}}
<img id="avatar" class="avatar"
src="http://img10.static.yhbimg.com/headimg/2013/11/28/09/01cae078abe5fe320c88cdf4c220212688.gif?imageView/2/w/100/h/100">
{{/if}}
</div>
</li>
<li>
<div id="name" class="title center small">
{{#if name}}
<span>{{name}}</span>
{{^}}
<span>咸鸭蛋</span>
{{/if}}
</div>
</li>
<li class="clearfix">
<div id="confirmInfo">
<div class="desc center">手机号{{mobile}}已经被以上用户注册,请确认是否归您本人所有</div>
<div class="desc center"></div>
<div class="desc center">您可以绑定该手机号或者更换一个新的手机号绑定该帐号,也可以使用该手机直接登录</div>
</div>
</li>
<li style="margin: -10px 0">
</li>
<li>
<div>
<a id="next" class="btn btn-fixed-height" href="{{bindSuccess}}">是朕的,绑定该手机号</a>
</div>
</li>
<li>
<div class="quick-link">
<a class="blue left" href="{{bindUrl}}">绑定其他手机号</a>
<a class="blue right" href="{{loginUrl}}">使用手机号登录</a>
</div>
</li>
</ul>
</div>
<input type="hidden" value="{{uid}}">
<input type="hidden" value="{{mobile}}">
<input type="hidden" value="{{area}}">
<input type="hidden" value="{{code}}">
<input type="hidden" value="{{sourceType}}">
</div>
... ...
{{> sign-header}}
<div class="bind-wrapper">
<div id="pwdPage" class="pwdPage">
<ul>
<li class="clearfix">
<div class="title center">欢迎加入 YOHO!BLK</div>
</li>
<li class="clearfix small">
<div class="prompt desc center">为了您的购物安全,请完善账户信息哦!</div>
</li>
<li>
<div>
<input id="pwd" class="input" type="password" placeholder="新的登录密码">
</div>
</li>
<li>
<div>
<input id="repwd" class="input" type="password" placeholder="确认登录密码">
</div>
</li>
<li>
<div>
<a id="next" class="btn btn-fixed-height disable" href="">确认</a>
</div>
</li>
</ul>
</div>
<input type="hidden" id="sourceType" value="{{sourceType}}">
<input type="hidden" id="openId" value="{{openId}}">
<input type="hidden" id="mobile" value="{{mobile}}">
<input type="hidden" id="area" value="{{area}}">
</div>
\ No newline at end of file
... ...
{{> sign-header}}
<div class="bind-wrapper">
<div id="bindSuccessPage" class="bindSuccessPage">
<ul>
<li>
<div class="title center">
恭喜您,手机绑定成功啦!
</div>
</li>
<li>
<div class="desc center">
尊敬的会员,今后您可以选择{{sourceName}}或者手机号+密码的方式登录YOHO!BLK!即刻您可以开启时尚购物之旅!
</div>
</li>
<li>
<div>
<a class="btn btn-fixed-height" href="{{goShopping}}">开始购物</a>
</div>
</li>
</ul>
</div>
</div>
\ No newline at end of file
... ...
<div class="bindwrapper">
<h3 class="welcomeword">
欢迎加入
<span class="yoho">YOHO!FAMILY</span>
</h3>
{{> sign-header}}
<div class="bind-wrapper">
<p class="safeword">为了您的账户安全,请您完善账户信息,以便为您提供更优质的服务</p>
<form action="" id="bindmobileform" method="post">
<input type="hidden" value="{{openId}}" id="openId" name="openId"/>
<input type="hidden" value="{{sourceType}}" id="sourceType" name="sourceType"/>
<input type="hidden" value="86" id="areacode" name="area"/>
<div class="yohobindrow">
<div class="name areatag">地区</div>
<div class="content">
<div class="yohoselectarea">
<div class="optionshow">
<span class="areaname" id="areaname">中国</span>
<span class="righttag"></span>
</div>
<div class="optionslist hide">
<div id="authPage" class="authPage">
<ul>
<li class="clearfix">
<div class="title center">欢迎加入 YOHO!BLK</div>
</li>
<li class="clearfix small">
<div class="prompt desc center">为了您的购物安全,请完善账户信息哦!</div>
</li>
<li class="clearfix">
<div id="mobile-input-component" class="mobile-input-component">
<select id="region" name="select" class="region left">
{{#each region}}
<div class="optionitem" areanum="{{areaCode}}">{{name}}</div>
<option {{#if selected}}selected="selected"{{/if}}
value="{{areaCode}}">{{name}}</option>
{{/each}}
</select>
<div id="mobile" class="ctrl left">
<div id="region-code" class="code left">
{{local}}
</div>
<div id="phone-num">
<input id="phoneNum" class="phone-num" type="text" placeholder="Phone Number">
</div>
</div>
</div>
</div>
</div>
<div class="yohobindrow">
<div class="name phonetag">手机号码</div>
<div class="content">
<div class="yohophonewrapper">
<div class="areanum" >
+
<span id="areanum">86</span>
</li>
<li class="clearfix">
<div id="img-captcha-component" class="img-captcha-component">
<input id="verifyCode" class="input left" name="code" type="text" placeholder="图形验证码">
<div class="refresh left">
<img class="left img-captcha" src="{{imgCaptcha}}">
<span class="img-captcha-refresh iconfont left ctrl">&#xe613;</span>
</div>
<input type="text" class="phonenum" name="mobile" id="mobile"/>
<span class="err-tip phone-err-tip hide">
<i></i>
<em></em>
</span>
</div>
</div>
</div>
</form>
</li>
<div class="protoctolwrapper">
<div class="choosewrapper">
<input type="checkbox" class="choosetag" checked='checked'></div>
<span>
我已阅读并同意遵守
<a target="_blank" href="{{serviceUrl}}" class="protoctol">YOHO!BUY 有货服务条款</a>
</span>
</div>
<div class="btnwrapper">
<a href="javascript:void(0)" class="yohobindbtn" id="bindfirststep">下一步</a>
</div>
</div>
<li class="clearfix">
<div id="sms-captcha-component" class="sms-captcha-component">
<input id="sms-captcha-input" class="input left sms-captcha-input" type="text" placeholder="短信验证码">
<div id="bindconfirm" style="display:none">
<div class="mask">
<div class="bindconfrimwrapper">
<div class="topwrapper">
<img src="" alt="" class="userphoto" id="userphoto1">
<span class="username">
用户名: <i id="username1"></span>
</div>
<h2 class="usertaginfo">
手机号
<span id="registphonetwo"></span>
已经被以上账户注册,请确认是否归您本人所有
</h2>
<h1 class="usertagremind">您可以使用该手机号码直接登录或更换一个新的手机号码绑定该账号</h1>
<a href="javascript:;" class="yohobindbtn otherphone" id="yohobindbtn">绑定其他手机号</a>
<a href="" class="logindirectly" id="logindirectly">使用手机号直接登录</a>
</div>
</div>
</div>
<div class="backdrop" style="display:none"></div>
</div>
<div id="alreayregist" style="display:none">
<div class="mask">
<div class="bindconfrimwrapper">
<div class="topwrapper">
<img src="" alt="" class="userphoto" id="userphoto">
<span class="username">
用户名: <i id="username"></i>
</span>
</div>
<h2 class="usertaginfo">
手机号
<span id="registphone"></span>
已经被以上账户注册,请确认是否归您本人所有
</h2>
<h1 class="usertagremind">您可以绑定该手机号码或更换一个新的手机号码绑定该账号,也可以使用该手机号码直接登录</h1>
<form id="gobindform" action="/passport/autouserinfo/bindMobile" method="post">
<div class="gobindwrapper">
<div class="validaterow">
<div class="content">
<input type="text" class="validatacode" placeholder="验证码" maxlength="4" id="validatenum"/>
</div>
<div class="validatewrapper">
<a href="javascript:void(0)" class="yohobindbtn" id="sendmessage">免费获取短信验证码</a>
</div>
<div class="hide" id="nopermissionmessage">
<span class="second">60</span>
秒后可重新操作
</div>
<div class="left">
<a class="btn send disable sms-captcha-send">获取短信验证码</a>
</div>
<input type="hidden" name="area" value="" id="inarea"/>
<input type="hidden" name="mobile" value="" id="inmobile"/>
<input type="hidden" name="openId" value="{{openId}}"/>
<input type="hidden" name="sourceType" value="{{sourceType}}"/>
<a href="javascript:;" class="yohobindbtn myphone" id="gotobindphone">是的我绑定该手机号</a>
</div>
<div class="gobindbottomwrapper">
<a href="javascript:;" class="logindirectly" id="yohobindbtn2">绑定其他手机号</a>
<a href="javascript:;" class="logindirectly" id="logindirectly2">使用手机号直接登录</a>
</li>
<li class="clearfix">
<div>
<a id="validate-phone-next" class="btn btn-fixed-height disable">下一步</a>
</div>
</form>
</div>
</li>
</ul>
</div>
<div class="backdrop" style="display:none"></div>
<div>
<input id="openId" type="hidden" value="{{openId}}">
<input id="sourceType" type="hidden" value="{{sourceType}}">
<input id="refer" type="hidden" value="{{refer}}">
</div>
</div>
\ No newline at end of file
... ...
{{> sign-header}}
<div class="bind-wrapper">
<div id="relateConfirmPage" class="relateConfirmPage">
<ul>
<li class="clearfix big-width">
<div id="avatar" class="center">
<img class="avatar"
src="http://img10.static.yhbimg.com/headimg/2013/11/28/09/01cae078abe5fe320c88cdf4c220212688.gif?imageView/2/w/100/h/100">
</div>
</li>
<li>
<div id="name" class="title center">
<span>咸鸭蛋</span>
</div>
</li>
<li class="clearfix">
<div id="confirmInfo" class="confirmInfo">
<div class="desc center">手机号{{mobile}}已经被以上用户注册,点击<a class="blue underline" href="{{signinUrl}}">登录该帐号</a>
</div>
<div class="desc"></div>
<div class="desc center">您可以使用此号码进行帐户关联或者更换一个新的手机号码</div>
</div>
</li>
<li style="margin: -10px 0">
</li>
<li>
<div class="quick-btn">
<a id="relate-btn" class="btn btn-fixed-height left" href="">关联此手机号</a>
<a class="btn btn-fixed-height right" href="">更换新手机号</a>
</div>
</li>
<li>
<div class="desc center">
注:关联的手机号码不能用来登录此帐号
</div>
</li>
</ul>
</div>
<input id="mobile" type="hidden" value="{{mobile}}">
<input id="area" type="hidden" value="{{area}}">
<input id="sourceType" type="hidden" value="{{sourceType}}">
<input id="openId" type="hidden" value="{{openId}}">
</div>
\ No newline at end of file
... ...
{{> sign-header}}
<div class="bind-wrapper">
<div id="relateSuccessPage" class="relateSuccessPage">
<ul>
<li>
<div class="title center">
恭喜您,手机关联成功啦!
</div>
</li>
<li>
<div class="desc center">
该手机号不能用来登录帐号,您可以选择继续使用{{sourceName}}登录
</div>
</li>
<li>
<div>
<a class="btn btn-fixed-height" href="{{goShopping}}">开始购物</a>
</div>
</li>
</ul>
</div>
</div>
\ No newline at end of file
... ...
... ... @@ -12,33 +12,20 @@
{{/each}}
</select>
<div id="phone" class="left phone">
<span id="country-code" class="country-code">{{countryCode}}</span>
<input id="account" class="account input phone-num va" name="account" value="{{bindMobile}}"
type="text"
placeholder="Phone Number" autocomplete="off">
</div>
<span class="err-tip hide">
<span class="iconfont">&#xe60c;</span>
<em></em>
</span>
</li>
<li class="clearfix">
<input id="password" class="input password va" name="password" type="password" placeholder="Password"
autocomplete="off" maxlength="20">
<span id="caps-lock" class="caps-lock hide">大写状态开启</span>
<span class="err-tip hide">
<span class="iconfont">&#xe60c;</span>
<em>请输入密码</em>
</span>
</li>
<li class="clearfix captcha-wrap hide">
<input id="captcha" class="input va captcha" type="text" name="captcha" placeholder="图形验证码"
... ... @@ -48,21 +35,10 @@
<img id="captcha-img" class="left captcha-img" alt="">
<a class="left link change-captcha"><span class="iconfont gray">&#xe613;</span></a>
</div>
<span class="err-tip hide">
<span class="iconfont">&#xe60c;</span>
<em></em>
</span>
</li>
<li class="clearfix relative">
<span class="left login-fail-tip hide">
<span class="iconfont">&#xe608;</span>
<em></em>
</span>
<span id="login-btn" class="btn login-btn">登录</span>
<li class="clearfix">
<a id="login-btn" class="btn login-btn">登录</a>
</li>
<li class="clearfix">
... ...
... ... @@ -9,7 +9,7 @@
<div>
尊敬的{{mobile}},恭喜您已经成为YOHO!BLK会员!即刻您可以开启时尚购物之旅!
</div>
<a class="success-btn" href="{{goShoppong}}" data-url="{{goUrl}}">开始购物</a>
<a class="btn btn-fixed-height success-btn" href="{{goShoppong}}" data-url="{{goUrl}}">开始购物</a>
</div>
{{/ passport}}
</div>
... ...
... ... @@ -67,7 +67,7 @@
<li class="clearfix">
<input name="refer" id="refer" type="hidden" value="{{referUrl}}">
<div style="width: 100%;text-align: center">
<input id="register-btn" class="btn register-btn disable" type="submit" value="{{regBtnText}}"
<input id="register-btn" class="btn btn-fixed-height disable" type="submit" value="{{regBtnText}}"
disabled="">
</div>
</li>
... ...

7.68 KB | W: | H:

6.52 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
... ... @@ -9,10 +9,10 @@ var $ = require('yoho-jquery'),
var emailAc = require('../common/ac-email'); // 邮箱自动完成
var $cr = $('#country-code-hide'),
$phoneNum = $('#phone-num'),
$ca = $('#captcha'),
$ccList = $('#country-code-list'),
var $cr = $('#country-code'),
$phoneNum = $('.phone-num'),
$ca = $('#verifyCode'),
$ccList = $('#area'),
$cc = $('#country-code'),
$btn = $('#find-btn'),
$accErr = $('#account-err'),
... ... @@ -34,6 +34,11 @@ function imgcode() {
$('#captcha-img').attr('src', captchaImgSrc + '?t=' + time.getTime());
}
$ccList.change(function() {
'use strict';
$cc.text($ccList.val());
});
function enableBtn() {
if (hasPh && hasCa) {
$btn.removeClass('disable').prop('disabled', false);
... ... @@ -54,7 +59,7 @@ function authcode() {
data: {
verifyCode: $.trim($ca.val()),
phoneNum: $phoneNum.val(),
area: $cr.val()
area: $cr.text()
}
}).then(function(data) {
... ... @@ -80,7 +85,7 @@ function vaPn(v) {
v = $.trim(v);
if (v !== '') {
if (/^[0-9]+$/.test(v)) {
if (phoneRegx[$cr.val()].test(v)) {
if (phoneRegx[$cr.text()].test(v)) {
pass = true;
} else {
errTxt = '手机号码格式不正确, 请重新输入';
... ... @@ -107,6 +112,8 @@ function vaPn(v) {
};
}
function vaCa() {
var v = $.trim($ca.val());
... ... @@ -139,48 +146,10 @@ $ca.attr('maxlength', caCount);
// IE8 placeholder
$('input').placeholder();
$('#change-captcha, #captcha-img').on('click', function() {
$('.change-captcha, #captcha-img').on('click', function() {
imgcode();
});
$cc.on('click', function(e) {
e.stopPropagation();
if ($ccList.css('style') === 'block') {
$ccList.slideUp('fast');
} else {
$ccList.slideDown('fast');
}
});
$ccList.delegate('li', 'click', function(e) {
var $cur = $(this),
code = $cur.data('cc'),
pnVa;
e.stopPropagation();
$cr.val(code);
$cc.find('em').html($cur.text());
// 切换后验证手机号码
if ($.trim($phoneNum.val()) !== '') {
pnVa = vaPn($phoneNum.val());
enableBtn();
if (hasPh) {
$accErr.addClass('hide');
$phoneNum.removeClass('error');
} else {
$accErr.removeClass('hide').text(pnVa.errTxt);
$phoneNum.addClass('error');
}
}
$ccList.slideUp('fast');
});
$(document).click(function() {
if ($ccList.css('display') === 'block') {
$ccList.slideUp();
}
});
$phoneNum.keyup(function() {
vaPn($.trim($(this).val()));
... ... @@ -221,7 +190,7 @@ $ca.blur(function() {
$('#find-btn').click(function(e) {
if (/^[0-9]+$/.test($.trim($phoneNum.val()))) {
$('#find-form').attr('action', '/passport/back/mobile');
$('#back-form').attr('action', '/passport/back/mobile');
}
if ($(this).hasClass('disable')) {
return;
... ...
... ... @@ -30,15 +30,15 @@ $sc.click(function() {
$sc.addClass('disable').attr('disabled', true);
$msgTip.removeClass('hide');
$sc.val(seconds-- + '后可重新操作');
$sc.val(seconds-- + 's后可重新操作');
itime = setInterval(function() {
if (seconds === 0) {
clearInterval(itime);
// $sc.val('发送验证码').removeClass('disable').prop('disabled', false);
$sc.val('发送验证码').removeClass('disable').removeAttr('disabled');
$sc.val('获取短信验证码').removeClass('disable').removeAttr('disabled');
} else {
$sc.val(seconds-- + '后可重新操作');
$sc.val(seconds-- + 's后可重新操作');
}
}, 1000);
... ... @@ -55,15 +55,15 @@ seconds = 60;
$sc.addClass('disable').attr('disabled', true);
$msgTip.removeClass('hide');
$sc.val(seconds-- + '后可重新操作');
$sc.val(seconds-- + 's后可重新操作');
itime = setInterval(function() {
if (seconds === 0) {
clearInterval(itime);
// $sc.val('发送验证码').removeClass('disable').prop('disabled', false);
$sc.val('发送验证码').removeClass('disable').removeAttr('disabled');
$sc.val('获取短信验证码').removeClass('disable').removeAttr('disabled');
} else {
$sc.val(seconds-- + '后可重新操作');
$sc.val(seconds-- + 's后可重新操作');
}
}, 1000);
... ... @@ -85,9 +85,6 @@ $('#captcha').keyup(function() {
},
success: function(res) {
if (res.code === 200) {
console.log(res.data);
// 添加验证码正确验证
$next.removeClass('disable').attr('href', res.data);
$errTip.addClass('hide');
... ...
/**
* 第三方绑定确认
* @author: TaoHuang
* @date: 2016/7/12
*/
var $ = require('yoho-jquery');
var $mobile = $('#mobile');
var $area = $('#area');
var $sourceType = $('#sourceType');
var $openId = $('#openId');
var $next = $('#relate-btn');
$next.on('click', function() {
return $.ajax({
type: 'POST',
url: '/passport/autouserinfo/bindMobile',
data: {
mobile: $mobile.val(),
area: $area.val(),
sourceType: $sourceType.val(),
openId: $openId.val()
}
}).then(function(result) {
if (result.code === 200) {
location.href = result.data.refer;
}
});
});
... ...
require('./bind/third-pwd');
... ...
/**
* Created by TaoHuang on 2016/7/12.
*/
... ...
require('./bind/third-login');
... ...
/**
* 第三方登录首页
* @author: TaoHuang
* @date: 2016/7/12
*/
var $ = require('yoho-jquery');
var phoneRegx = require('../common/mail-phone-regx').phoneRegx;
var EventProxy = require('../common/eventproxy');
var $areaCodeText = $('#region-code');
var $phoneNumInput = $('#phoneNum');
var $imgCaptchaInput = $('#verifyCode');
var $imgCaptchaCtrl = $('.img-captcha-refresh');
var $smsCaptchaInput = $('#sms-captcha-input');
var $smsCaptchaCtrl = $('.sms-captcha-send');
var $next = $('#validate-phone-next');
var $openId = $('#openId');
var $sourceType = $('#sourceType');
var $refer = $('#refer');
var second = 60;
var ep = new EventProxy();
function errTip(el, msg) {
console.log(el, msg);
}
function updateSMSBtn() {
second -= 1;
if (second < 0) {
second = 60;
$smsCaptchaCtrl.text('获取短信验证码');
} else {
$smsCaptchaCtrl.text(second + '秒后可重新操作');
window.setTimeout(updateSMSBtn, 1000);
}
}
function sendSMSCaptcha() {
return $.ajax({
type: 'POST',
url: '/passport/autouserinfo/sendBindMsg',
data: {
mobile: $phoneNumInput.val(),
area: $areaCodeText.text()
}
});
}
function refreshImgCaptcha() {
var time = new Date(),
$captchaImg = $('.img-captcha'),
captchaImgSrc = $captchaImg.attr('src').split('?')[0];
$captchaImg.attr('src', captchaImgSrc + '?t=' + time.getTime());
}
function validateImgCaptcha() {
return $.ajax({
type: 'POST',
url: '/passport/images/check',
data: {
verifyCode: $imgCaptchaInput.val()
}
});
}
function validateSMSCaptcha() {
return $.ajax({
type: 'POST',
url: '/passport/autouserinfo/checkBindMsg',
data: {
code: $smsCaptchaInput.val(),
mobile: $smsCaptchaInput.val(),
area: $areaCodeText.text()
}
});
}
ep.tail('phoneNum', 'img-captcha', 'sms-captcha', function(phoneAuth, imgAuth, smsAuth) {
if (phoneAuth && imgAuth && smsAuth) {
$next.removeClass('disable');
} else {
$next.addClass('disable');
}
});
$('#region').change(function() {
var $this = $(this);
$areaCodeText.text($this.val());
});
ep.on('phoneNum', function(isCheck) {
if (isCheck) {
$smsCaptchaCtrl.removeClass('disable');
} else {
$smsCaptchaCtrl.addClass('disable');
}
});
$phoneNumInput.on('blur', function() {
var length = $phoneNumInput.val().length;
if (length === 0) {
errTip($phoneNumInput, '请输入手机号码');
ep.emit('phoneNum', false);
return;
}
if (length !== 11) {
errTip($phoneNumInput, '手机号码格式不正确');
ep.emit('phoneNum', false);
return;
}
if (!phoneRegx[$areaCodeText.text()].test($phoneNumInput.val())) {
errTip($phoneNumInput, '手机号码格式不正确');
ep.emit('phoneNum', false);
return;
}
ep.emit('phoneNum', true);
});
$imgCaptchaInput.on('blur', function() {
var length = $imgCaptchaInput.val().length;
switch (length) {
case 4 :
break;
case 0:
errTip($imgCaptchaInput, '请输入验证码');
refreshImgCaptcha();
ep.emit('img-captcha', false);
break;
default:
errTip($imgCaptchaInput, '验证码不正确');
refreshImgCaptcha();
ep.emit('img-captcha', false);
break;
}
validateImgCaptcha().then(function(result) {
if (result.code === 200) {
ep.emit('img-captcha', true);
} else {
ep.emit('img-captcha', false);
refreshImgCaptcha();
}
});
});
$imgCaptchaCtrl.on('click', function() {
refreshImgCaptcha();
});
$smsCaptchaInput.on('blur', function() {
var length = $smsCaptchaInput.val().length;
switch (length) {
case 4:
break;
case 0:
errTip($smsCaptchaCtrl, '请输入短信验证码');
ep.emit('sms-captcha', false);
break;
default:
errTip($smsCaptchaInput, '验证码不正确');
ep.emit('sms-captcha', false);
break;
}
validateSMSCaptcha().then(function(result) {
if (result.code === 200) {
ep.emit('sms-captcha', true);
} else {
ep.emit('sms-captcha', false);
errTip($smsCaptchaCtrl, '验证码不正确');
}
});
});
$smsCaptchaCtrl.on('click', function() {
if ($smsCaptchaCtrl.hasClass('disable')) {
return;
}
$smsCaptchaCtrl.addClass('disable');
sendSMSCaptcha();
updateSMSBtn();
});
function setPwdPage(thirdPart) {
return $.ajax({
type: 'POST',
url: '/passport/thirdlogin/bindsetpwd',
data: thirdPart
});
}
function bindConfirmPage(thirdPart, user) {
return $.ajax({
type: 'POST',
url: '/passport/thirdlogin/bindConfirm',
data: {
thirdPart: thirdPart,
user: user
}
});
}
function relateConfirmPage(thirdPart, user) {
return $.ajax({
type: 'POST',
url: '/passport/thirdlogin/relateConfirm',
data: {
thirdPart: thirdPart,
user: user
}
});
}
function nextPage() {
var thirdPart = {
mobile: $phoneNumInput.val(),
area: $areaCodeText.text(),
openId: $openId.val(),
sourceType: $sourceType.val(),
verifyCode: $imgCaptchaInput.val(),
code: $smsCaptchaInput.val(),
refer: $refer.val()
};
return $.ajax({
type: 'post',
url: '/passport/autouserinfo/bindCheck',
data: {
mobile: thirdPart.mobile,
area: thirdPart.area,
openId: thirdPart.openId,
sourceType: thirdPart.sourceType
}
}).then(function(result) {
switch (result.code) {
case 200:
// 未注册,可绑定,设定密码页面;
setPwdPage(thirdPart);
break;
case 201:
case 205:
// 已注册绑定过其他的第三方,绑定确定页面
bindConfirmPage(thirdPart, result.data);
break;
case 203:
// 关联帐号,关联页面
relateConfirmPage(thirdPart, result.data);
break;
default:
// 出错
errTip($next, '输入错误,请重新输入!');
break;
}
});
}
$next.on('click', function() {
if ($next.hasClass('disable')) {
return;
}
nextPage();
});
... ...
/**
* 第三方绑定重设密码
* @author: TaoHuang
* @date: 2016/7/12
*/
var $ = require('yoho-jquery');
var pwdRegx = require('../common/mail-phone-regx').pwdValidateRegx;
var $pwd = $('#pwd');
var $repwd = $('#repwd');
var $sourceType = $('#sourceType');
var $openId = $('#openId');
var $mobile = $('#mobile');
var $area = $('#area');
var $next = $('#next');
var EventProxy = require('../common/eventproxy');
var ep = new EventProxy();
require('yoho-jquery-placeholder');
function errTip($dom, info) {
console.log($dom, info);
}
ep.tail('pwd', 'repwd', function(pwd, repwd) {
if (pwd && repwd) {
$next.removeClass('disable');
} else {
$next.addClass('disable');
}
});
$pwd.on('keyup blur', function() {
var length = $pwd.val().length;
if (length === 0) {
errTip($pwd, '请输入密码');
ep.emit('pwd', false);
return;
}
if (length < 6 || length > 20) {
errTip($pwd, '密码只支持 6-20 位字符,建议字母+数字的组合');
ep.emit('pwd', false);
return;
}
if (!pwdRegx.test($pwd.val())) {
errTip($pwd, '密码只支持 6-20 位字符,建议字母+数字的组合');
ep.emit('pwd', false);
return;
}
ep.emit('pwd', true);
});
$repwd.on('keyup blur', function() {
var length = $repwd.val().length;
if (length === 0) {
errTip($repwd, '请再次输入密码');
ep.emit('repwd', false);
return;
}
if ($pwd.val() !== $repwd.val()) {
errTip($repwd, '两次输入的密码不一致,请重新输入');
ep.emit('repwd', false);
return;
}
ep.emit('repwd', true);
});
function nextPage() {
$.ajax({
type: 'POST',
url: '/passport/thirdlogin/bindMobile',
data: {
openId: $openId.val(),
sourceType: $sourceType.val(),
mobile: $mobile.val(),
area: $area.val(),
password: $pwd.val()
}
}).then(function(result) {
if (result.code === 200) {
window.local = result.data.refer;
} else {
errTip($next, result.message);
}
});
}
$('[placeholder]').placeholder();
$next.on('click', function() {
if ($next.hasClass('disable')) {
return;
}
if ($pwd.val() !== $repwd.val()) {
errTip($repwd, '两次输入的密码不一致,请重新输入');
return;
}
nextPage();
});
... ...
/**
* Created by TaoHuang on 2016/7/12.
*/
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this,
args = arguments;
var later = function() {
timeout = null;
if (!immediate) {
func.apply(context, args);
}
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) {
func.apply(context, args);
}
};
}
module.exports = debounce;
... ...
/* eslint-disable */
/*global define*/
!(function (name, definition) {
// Check define
var hasDefine = typeof define === 'function',
// Check exports
hasExports = typeof module !== 'undefined' && module.exports;
if (hasDefine) {
// AMD Module or CMD Module
define('eventproxy_debug', function () {return function () {};});
define(['eventproxy_debug'], definition);
} else if (hasExports) {
// Node.js Module
module.exports = definition(require('debug')('eventproxy'));
} else {
// Assign to common namespaces or simply the global object (window)
this[name] = definition();
}
})('EventProxy', function (debug) {
debug = debug || function () {};
/*!
* refs
*/
var SLICE = Array.prototype.slice;
var CONCAT = Array.prototype.concat;
var ALL_EVENT = '__all__';
/**
* EventProxy. An implementation of task/event based asynchronous pattern.
* A module that can be mixed in to *any object* in order to provide it with custom events.
* You may `bind` or `unbind` a callback function to an event;
* `trigger`-ing an event fires all callbacks in succession.
* Examples:
* ```js
* var render = function (template, resources) {};
* var proxy = new EventProxy();
* proxy.assign("template", "l10n", render);
* proxy.trigger("template", template);
* proxy.trigger("l10n", resources);
* ```
*/
var EventProxy = function () {
if (!(this instanceof EventProxy)) {
return new EventProxy();
}
this._callbacks = {};
this._fired = {};
};
/**
* Bind an event, specified by a string name, `ev`, to a `callback` function.
* Passing __ALL_EVENT__ will bind the callback to all events fired.
* Examples:
* ```js
* var proxy = new EventProxy();
* proxy.addListener("template", function (event) {
* // TODO
* });
* ```
* @param {String} eventname Event name.
* @param {Function} callback Callback.
*/
EventProxy.prototype.addListener = function (ev, callback) {
debug('Add listener for %s', ev);
this._callbacks[ev] = this._callbacks[ev] || [];
this._callbacks[ev].push(callback);
return this;
};
/**
* `addListener` alias, `bind`
*/
EventProxy.prototype.bind = EventProxy.prototype.addListener;
/**
* `addListener` alias, `on`
*/
EventProxy.prototype.on = EventProxy.prototype.addListener;
/**
* `addListener` alias, `subscribe`
*/
EventProxy.prototype.subscribe = EventProxy.prototype.addListener;
/**
* Bind an event, but put the callback into head of all callbacks.
* @param {String} eventname Event name.
* @param {Function} callback Callback.
*/
EventProxy.prototype.headbind = function (ev, callback) {
debug('Add listener for %s', ev);
this._callbacks[ev] = this._callbacks[ev] || [];
this._callbacks[ev].unshift(callback);
return this;
};
/**
* Remove one or many callbacks.
*
* - If `callback` is null, removes all callbacks for the event.
* - If `eventname` is null, removes all bound callbacks for all events.
* @param {String} eventname Event name.
* @param {Function} callback Callback.
*/
EventProxy.prototype.removeListener = function (eventname, callback) {
var calls = this._callbacks;
if (!eventname) {
debug('Remove all listeners');
this._callbacks = {};
} else {
if (!callback) {
debug('Remove all listeners of %s', eventname);
calls[eventname] = [];
} else {
var list = calls[eventname];
if (list) {
var l = list.length;
for (var i = 0; i < l; i++) {
if (callback === list[i]) {
debug('Remove a listener of %s', eventname);
list[i] = null;
}
}
}
}
}
return this;
};
/**
* `removeListener` alias, unbind
*/
EventProxy.prototype.unbind = EventProxy.prototype.removeListener;
/**
* Remove all listeners. It equals unbind()
* Just add this API for as same as Event.Emitter.
* @param {String} event Event name.
*/
EventProxy.prototype.removeAllListeners = function (event) {
return this.unbind(event);
};
/**
* Bind the ALL_EVENT event
*/
EventProxy.prototype.bindForAll = function (callback) {
this.bind(ALL_EVENT, callback);
};
/**
* Unbind the ALL_EVENT event
*/
EventProxy.prototype.unbindForAll = function (callback) {
this.unbind(ALL_EVENT, callback);
};
/**
* Trigger an event, firing all bound callbacks. Callbacks are passed the
* same arguments as `trigger` is, apart from the event name.
* Listening for `"all"` passes the true event name as the first argument.
* @param {String} eventname Event name
* @param {Mix} data Pass in data
*/
EventProxy.prototype.trigger = function (eventname, data) {
var list, ev, callback, i, l;
var both = 2;
var calls = this._callbacks;
debug('Emit event %s with data %j', eventname, data);
while (both--) {
ev = both ? eventname : ALL_EVENT;
list = calls[ev];
if (list) {
for (i = 0, l = list.length; i < l; i++) {
if (!(callback = list[i])) {
list.splice(i, 1);
i--;
l--;
} else {
var args = [];
var start = both ? 1 : 0;
for (var j = start; j < arguments.length; j++) {
args.push(arguments[j]);
}
callback.apply(this, args);
}
}
}
}
return this;
};
/**
* `trigger` alias
*/
EventProxy.prototype.emit = EventProxy.prototype.trigger;
/**
* `trigger` alias
*/
EventProxy.prototype.fire = EventProxy.prototype.trigger;
/**
* Bind an event like the bind method, but will remove the listener after it was fired.
* @param {String} ev Event name
* @param {Function} callback Callback
*/
EventProxy.prototype.once = function (ev, callback) {
var self = this;
var wrapper = function () {
callback.apply(self, arguments);
self.unbind(ev, wrapper);
};
this.bind(ev, wrapper);
return this;
};
var later = (typeof setImmediate !== 'undefined' && setImmediate) ||
(typeof process !== 'undefined' && process.nextTick) || function (fn) {
setTimeout(fn, 0);
};
/**
* emitLater
* make emit async
*/
EventProxy.prototype.emitLater = function () {
var self = this;
var args = arguments;
later(function () {
self.trigger.apply(self, args);
});
};
/**
* Bind an event, and trigger it immediately.
* @param {String} ev Event name.
* @param {Function} callback Callback.
* @param {Mix} data The data that will be passed to calback as arguments.
*/
EventProxy.prototype.immediate = function (ev, callback, data) {
this.bind(ev, callback);
this.trigger(ev, data);
return this;
};
/**
* `immediate` alias
*/
EventProxy.prototype.asap = EventProxy.prototype.immediate;
var _assign = function (eventname1, eventname2, cb, once) {
var proxy = this;
var argsLength = arguments.length;
var times = 0;
var flag = {};
// Check the arguments length.
if (argsLength < 3) {
return this;
}
var events = SLICE.call(arguments, 0, -2);
var callback = arguments[argsLength - 2];
var isOnce = arguments[argsLength - 1];
// Check the callback type.
if (typeof callback !== "function") {
return this;
}
debug('Assign listener for events %j, once is %s', events, !!isOnce);
var bind = function (key) {
var method = isOnce ? "once" : "bind";
proxy[method](key, function (data) {
proxy._fired[key] = proxy._fired[key] || {};
proxy._fired[key].data = data;
if (!flag[key]) {
flag[key] = true;
times++;
}
});
};
var length = events.length;
for (var index = 0; index < length; index++) {
bind(events[index]);
}
var _all = function (event) {
if (times < length) {
return;
}
if (!flag[event]) {
return;
}
var data = [];
for (var index = 0; index < length; index++) {
data.push(proxy._fired[events[index]].data);
}
if (isOnce) {
proxy.unbindForAll(_all);
}
debug('Events %j all emited with data %j', events, data);
callback.apply(null, data);
};
proxy.bindForAll(_all);
};
/**
* Assign some events, after all events were fired, the callback will be executed once.
*
* Examples:
* ```js
* proxy.all(ev1, ev2, callback);
* proxy.all([ev1, ev2], callback);
* proxy.all(ev1, [ev2, ev3], callback);
* ```
* @param {String} eventname1 First event name.
* @param {String} eventname2 Second event name.
* @param {Function} callback Callback, that will be called after predefined events were fired.
*/
EventProxy.prototype.all = function (eventname1, eventname2, callback) {
var args = CONCAT.apply([], arguments);
args.push(true);
_assign.apply(this, args);
return this;
};
/**
* `all` alias
*/
EventProxy.prototype.assign = EventProxy.prototype.all;
/**
* Assign the only one 'error' event handler.
* @param {Function(err)} callback
*/
EventProxy.prototype.fail = function (callback) {
var that = this;
that.once('error', function () {
that.unbind();
// put all arguments to the error handler
// fail(function(err, args1, args2, ...){})
callback.apply(null, arguments);
});
return this;
};
/**
* A shortcut of ep#emit('error', err)
*/
EventProxy.prototype.throw = function () {
var that = this;
that.emit.apply(that, ['error'].concat(SLICE.call(arguments)));
};
/**
* Assign some events, after all events were fired, the callback will be executed first time.
* Then any event that predefined be fired again, the callback will executed with the newest data.
* Examples:
* ```js
* proxy.tail(ev1, ev2, callback);
* proxy.tail([ev1, ev2], callback);
* proxy.tail(ev1, [ev2, ev3], callback);
* ```
* @param {String} eventname1 First event name.
* @param {String} eventname2 Second event name.
* @param {Function} callback Callback, that will be called after predefined events were fired.
*/
EventProxy.prototype.tail = function () {
var args = CONCAT.apply([], arguments);
args.push(false);
_assign.apply(this, args);
return this;
};
/**
* `tail` alias, assignAll
*/
EventProxy.prototype.assignAll = EventProxy.prototype.tail;
/**
* `tail` alias, assignAlways
*/
EventProxy.prototype.assignAlways = EventProxy.prototype.tail;
/**
* The callback will be executed after the event be fired N times.
* @param {String} eventname Event name.
* @param {Number} times N times.
* @param {Function} callback Callback, that will be called after event was fired N times.
*/
EventProxy.prototype.after = function (eventname, times, callback) {
if (times === 0) {
callback.call(null, []);
return this;
}
var proxy = this,
firedData = [];
this._after = this._after || {};
var group = eventname + '_group';
this._after[group] = {
index: 0,
results: []
};
debug('After emit %s times, event %s\'s listenner will execute', times, eventname);
var all = function (name, data) {
if (name === eventname) {
times--;
firedData.push(data);
if (times < 1) {
debug('Event %s was emit %s, and execute the listenner', eventname, times);
proxy.unbindForAll(all);
callback.apply(null, [firedData]);
}
}
if (name === group) {
times--;
proxy._after[group].results[data.index] = data.result;
if (times < 1) {
debug('Event %s was emit %s, and execute the listenner', eventname, times);
proxy.unbindForAll(all);
callback.call(null, proxy._after[group].results);
}
}
};
proxy.bindForAll(all);
return this;
};
/**
* The `after` method's helper. Use it will return ordered results.
* If you need manipulate result, you need callback
* Examples:
* ```js
* var ep = new EventProxy();
* ep.after('file', files.length, function (list) {
* // Ordered results
* });
* for (var i = 0; i < files.length; i++) {
* fs.readFile(files[i], 'utf-8', ep.group('file'));
* }
* ```
* @param {String} eventname Event name, shoule keep consistent with `after`.
* @param {Function} callback Callback function, should return the final result.
*/
EventProxy.prototype.group = function (eventname, callback) {
var that = this;
var group = eventname + '_group';
var index = that._after[group].index;
that._after[group].index++;
return function (err, data) {
if (err) {
// put all arguments to the error handler
return that.emit.apply(that, ['error'].concat(SLICE.call(arguments)));
}
that.emit(group, {
index: index,
// callback(err, args1, args2, ...)
result: callback ? callback.apply(null, SLICE.call(arguments, 1)) : data
});
};
};
/**
* The callback will be executed after any registered event was fired. It only executed once.
* @param {String} eventname1 Event name.
* @param {String} eventname2 Event name.
* @param {Function} callback The callback will get a map that has data and eventname attributes.
*/
EventProxy.prototype.any = function () {
var proxy = this,
callback = arguments[arguments.length - 1],
events = SLICE.call(arguments, 0, -1),
_eventname = events.join("_");
debug('Add listenner for Any of events %j emit', events);
proxy.once(_eventname, callback);
var _bind = function (key) {
proxy.bind(key, function (data) {
debug('One of events %j emited, execute the listenner');
proxy.trigger(_eventname, {"data": data, eventName: key});
});
};
for (var index = 0; index < events.length; index++) {
_bind(events[index]);
}
};
/**
* The callback will be executed when the event name not equals with assigned event.
* @param {String} eventname Event name.
* @param {Function} callback Callback.
*/
EventProxy.prototype.not = function (eventname, callback) {
var proxy = this;
debug('Add listenner for not event %s', eventname);
proxy.bindForAll(function (name, data) {
if (name !== eventname) {
debug('listenner execute of event %s emit, but not event %s.', name, eventname);
callback(data);
}
});
};
/**
* Success callback wrapper, will handler err for you.
*
* ```js
* fs.readFile('foo.txt', ep.done('content'));
*
* // equal to =>
*
* fs.readFile('foo.txt', function (err, content) {
* if (err) {
* return ep.emit('error', err);
* }
* ep.emit('content', content);
* });
* ```
*
* ```js
* fs.readFile('foo.txt', ep.done('content', function (content) {
* return content.trim();
* }));
*
* // equal to =>
*
* fs.readFile('foo.txt', function (err, content) {
* if (err) {
* return ep.emit('error', err);
* }
* ep.emit('content', content.trim());
* });
* ```
* @param {Function|String} handler, success callback or event name will be emit after callback.
* @return {Function}
*/
EventProxy.prototype.done = function (handler, callback) {
var that = this;
return function (err, data) {
if (err) {
// put all arguments to the error handler
return that.emit.apply(that, ['error'].concat(SLICE.call(arguments)));
}
// callback(err, args1, args2, ...)
var args = SLICE.call(arguments, 1);
if (typeof handler === 'string') {
// getAsync(query, ep.done('query'));
// or
// getAsync(query, ep.done('query', function (data) {
// return data.trim();
// }));
if (callback) {
// only replace the args when it really return a result
return that.emit(handler, callback.apply(null, args));
} else {
// put all arguments to the done handler
//ep.done('some');
//ep.on('some', function(args1, args2, ...){});
return that.emit.apply(that, [handler].concat(args));
}
}
// speed improve for mostly case: `callback(err, data)`
if (arguments.length <= 2) {
return handler(data);
}
// callback(err, args1, args2, ...)
handler.apply(null, args);
};
};
/**
* make done async
* @return {Function} delay done
*/
EventProxy.prototype.doneLater = function (handler, callback) {
var _doneHandler = this.done(handler, callback);
return function (err, data) {
var args = arguments;
later(function () {
_doneHandler.apply(null, args);
});
};
};
/**
* Create a new EventProxy
* Examples:
* ```js
* var ep = EventProxy.create();
* ep.assign('user', 'articles', function(user, articles) {
* // do something...
* });
* // or one line ways: Create EventProxy and Assign
* var ep = EventProxy.create('user', 'articles', function(user, articles) {
* // do something...
* });
* ```
* @return {EventProxy} EventProxy instance
*/
EventProxy.create = function () {
var ep = new EventProxy();
var args = CONCAT.apply([], arguments);
if (args.length) {
var errorHandler = args[args.length - 1];
var callback = args[args.length - 2];
if (typeof errorHandler === 'function' && typeof callback === 'function') {
args.pop();
ep.fail(errorHandler);
}
ep.assign.apply(ep, args);
}
return ep;
};
// Backwards compatibility
EventProxy.EventProxy = EventProxy;
return EventProxy;
});
// eslint-
\ No newline at end of file
... ...
... ... @@ -257,7 +257,6 @@ mailAc($account, function() {
if (validateAccount()) {
tryUser().then(function() {
'use strict';
return $.ajax({
url: '/passport/login/account',
... ... @@ -283,34 +282,13 @@ $account.on('keyup', function() {
disableTips();
}
}).on('focus', function() {
'use strict';
$phone.addClass('focus-gain');
$phone.addClass('focus');
}).on('blur', function() {
'use strict';
$phone.removeClass('focus-gain');
$phone.removeClass('focus');
});
$('[placeholder]').placeholder();
// 展开地区列表
// $('#country-code').on('click', function() {
// if ($countryList.css('display') === 'none') {
// $countryList.slideDown();
// }
// });
// 选中地区列表项
// $countryList.on('click', 'li', function() {
// var $this = $(this),
// cc = $this.data('cc');
//
// $countryCodeEm.html($this.html());
//
// $countryCodeHide.val(cc);
//
// //$countryList.slideUp();
// });
$countryList.change(function() {
'use strict';
var $this = $(this);
... ... @@ -319,20 +297,9 @@ $countryList.change(function() {
});
// 点击其他区域,收起区域列表
// $(document).on('click', function(e) {
// if ($(e.target).closest('#country-code').length > 0) {
// return;
// }
// if ($countryList.css('display') === 'block') {
// $countryList.slideUp();
// }
// });
// 密码
$password.on('blur', function() {
$password.removeClass('focus-gain');
$password.removeClass('focus');
validatePassword();
if ($capsLock.hasClass('hide')) {
... ... @@ -350,26 +317,21 @@ $password.on('blur', function() {
}
$capsLock.addClass('hide');
}).on('focus', function() {
'use strict';
$password.addClass('focus-gain');
$password.addClass('focus');
});
// 验证码
$captcha.on('blur', function() {
$captcha.removeClass('focus-gain');
$captcha.removeClass('focus');
validateCaptcha();
}).on('focus', function() {
'use strict';
$captcha.addClass('focus-gain');
$captcha.addClass('focus');
});
// 邮箱自动完成列表项点击
$emailAutoComplete.on('click', 'li', function() {
clearTimeout(emailAcTime); // 清空默认关闭
$account.val($(this).text()).focus();
$emailAutoComplete.addClass('hide');
});
... ... @@ -413,3 +375,4 @@ if (($account.val() !== '' || $account.val() === $account.attr('placeholder')) &
$password.val() === '') {
$password.focus();
}
... ...
/**
* Created by TaoHuang on 2016/7/12.
*/
var $ = require('yoho-jquery');
var $mobile = $('#mobile');
var $area = $('#area');
var $sourceType = $('#sourceType');
var $openId = $('#openId');
var $next = $('#next');
$next.on('click', function() {
return $.ajax({
type: 'POST',
url: '/passport/autouserinfo/relateMobile',
data: {
mobile: $mobile.val(),
area: $area.val(),
sourceType: $sourceType.val(),
openId: $openId.val()
}
}).then(function(result) {
if (result.code === 200) {
location.href = result.data.refer;
}
});
});
... ...
/**
* Created by TaoHuang on 2016/7/12.
*/
... ...
@import "config";
.back-page {
font-size: 14px;
@mixin passport-page;
.content {
margin: 175px 0 0 !important;
li {
@mixin li-setting;
&.small {
height: calc($item-height / 3);
margin-bottom: 5px;
}
}
.back-header {
position: relative;
width: 268px;
line-height: 40px;
margin-bottom: 5px;
.country-code {
@mixin country-code ;
}
.country-code {
float: right;
cursor: pointer;
color: #b9b9b9;
.country-list {
@mixin region ;
}
.iconfont {
font-size: 14px;
vertical-align: middle;
}
.phone {
@mixin phone ;
&.focus-gain {
border: 2px solid #000;
}
}
.title {
float: left;
margin: 0;
font-size: 22px;
line-height: 40px;
color: #000;
font-weight: normal;
}
.title2 {
margin: 0 0 5px;
font-size: 22px;
line-height: 40px;
color: #000;
font-weight: normal;
}
.err-tip.captcha-err {
top: 10px;
left: 326px;
}
.country-code-list {
display: none;
position: absolute;
padding: 0 10px;
color: #000;
background-color: #fff;
border: 1px solid #000;
margin-top: 5px;
cursor: pointer;
z-index: 100;
top: 30px;
right: 0;
border-radius: 5px;
li {
height: 20px;
line-height: 20px;
&.focus-lost {
border: 1px solid #dbdbdb;
}
}
.input-container-li {
position: relative;
margin-bottom: 22px;
.input {
@mixin input;
.btn {
width: 270px;
height: 45px;
line-height: 45px;
cursor: pointer;
font-size: 20px;
border: none;
letter-spacing: 0;
&.phone-num {
width: 150px;
display: block;
float: left;
border: none !important;
}
.captcha {
width: 160px;
}
&.captcha {
width: $captcha;
float: left;
.captcha-img {
height: 37px;
width: 90px;
border: 0;
margin-left: 10px;
vertical-align: middle;
outline: none;
cursor: pointer;
&.focus-gain {
border: 2px solid #000;
}
&.focus-lost {
border: 1px solid #dbdbdb;
}
}
.change-captcha {
color: #ff1901;
font-size: 12px;
text-decoration: underline;
margin-left: 10px;
cursor: pointer;
}
.captcha-component {
margin-left: $margin-left;
background-color: $captcha-img-bg-color;
width: 130px;
}
.gray {
color: $captcha-fresh;
}
/* 验证码 */
.captcha-img {
height: 37px;
width: 90px;
border: 0;
outline: none;
margin-left: 10px;
margin-top: 4px;
float: left;
}
.change-captcha {
cursor: pointer;
height: 43px;
font-size: 14px;
line-height: @height;
}
.find-btn {
border: 0;
width: 180px;
height: $item-height;
background-color: $theme-color;
color: white;
margin-top: 40px;
&.disable {
background-color: $inactive-color;
}
}
.center {
text-align: center;
}
}
.send-email-page {
... ... @@ -143,100 +144,167 @@
}
}
.verification-page .content {
li {
position: relative;
margin-bottom: 43px;
}
.btn {
display: inline-block;
border: none;
}
.verification-page {
@mixin passport-page;
.head-title {
font-size: 24px;
color: #000;
}
.pn-label {
color: #828282;
font-size: 16px;
}
.country-code {
margin: 0 10px;
li {
@mixin li-setting;
}
.country-code,
.phone-num {
color: #000;
font-size: 16px;
.desc {
text-align: center;
line-height: 20px;
margin-top: -10px;
}
.captcha {
width: 160px !important;
width: 200px;
}
.send-captcha {
width: 133px;
width: $input-button;
font-size: 12px;
position: relative;
top: -1px;
letter-spacing: 0;
background: $theme-color;
margin-left: 20px;
color: white;
&.disable {
background-color: $inactive-color;
}
}
.err-tip {
left: 310px;
}
.captcha-tips {
position: absolute;
top: 50px;
color: #a5a4a4;
.next-step {
display: inline-block;
width: 180px;
height: $item-height;
line-height: @height;
font-size: 15px;
background-color: $theme-color;
text-align: center;
color: white;
margin: 0 calc(($item-width - @width) / 2);
.iconfont {
color: #0f9acd;
font-size: 14px;
margin: 0 8px 0 0;
vertical-align: 12%;
&.disable {
background-color: $inactive-color;
}
}
.blank {
height: 20px;
}
}
.reset-success-page {
.content {
margin: 255px 0 0 !important;
.reset-pwd-page {
.blank {
height: 20px;
}
.reset-pwd-btn {
display: inline-block;
width: 180px;
height: $item-height;
line-height: @height;
font-size: 15px;
background-color: $theme-color;
text-align: center;
color: white;
margin: 0 calc(($item-width - @width) / 2);
border: none;
&.disable {
background-color: $inactive-color;
}
}
}
.reset-success-page {
.success-text {
line-height: 35px;
text-align: center;
.iconfont {
font-size: 30px;
color: #ee3f14;
.title {
font-size: 18px;
}
span {
font-size: 24px;
margin: 0 18px;
.time {
font-size: 14px;
color: $inactive-color;
}
}
}
$step-height: calc($item-height / 2);
$step-circle: 12px;
$step-line: calc(($item-width - 3 * $step-circle) / 2);
.indicator {
.draw {
width: $item-width;
.step {
color: $captcha-fresh;
font-weight: bold;
height: $step-height;
float: left;
#count-down {
color: #ee3f14;
.line {
width: $step-line;
border: 1px solid $captcha-fresh;
&.cur-step {
border-color: $theme-color;
}
margin-top: calc(($step-height - 2px) / 2);
}
.circle {
width: $step-circle;
height: @width;
background: $theme-color;
border-radius: calc(@width / 2);
&.ring {
border: 2px solid $theme-color;
background-color: white;
}
margin-top: calc(($step-height - @height) / 2);
}
}
}
.success-btn {
display: block;
margin: 43px auto 0;
width: 269px;
line-height: 269px;
height: 45px;
line-height: 45px;
font-size: 14px;
color: #fff;
text-align: center;
background-color: #ff1901;
.text {
width: $item-width;
height: $item-height;
clear: left;
.step {
color: $captcha-fresh;
width: calc($item-width / 3);
float: left;
&.first {
text-align: left;
}
&.second {
text-align: center;
}
&.third {
text-align: right;
}
&.cur-step {
color: $theme-color;
}
}
}
}
... ...
$theme-color: #1d1d1d;
$input-button: 125px;
$item-height: 43px;
$item-height: 40px;
$item-width: 340px;
$bord-color: #dbdbdb;
$margin-left: 15px;
... ... @@ -59,9 +59,9 @@ $option-color:#f8f8f8;
@define-mixin input {
height: $item-height;
width: 100%;
line-height: 43px;
font-size: 16px;
width: 100%;
border: 1px solid $bord-color;
text-indent: 10px;
color: #9a9a9a;
... ...
@import "config";
.passport-page {
width: 1150px;
width: 100%;
margin-left: auto;
margin-right: auto;
.content {
float: left;
margin-top: 107px;
padding-left: 85px;
}
.input {
height: 43px;
height: $item-height;
font-size: 16px;
line-height: 1.2;
line-height: 43px;
line-height: @height;
width: 268px;
border: 1px solid #dbdbdb;
text-indent: 10px;
... ... @@ -24,33 +18,12 @@
}
.title {
font-size: 30px;
font-size: 20px;
text-align: center;
width: $item-width;
color: $theme-color;
}
.error {
border-color: #f00 !important;
}
.btn {
display: block;
height: 46px;
line-height: 46px;
width: 100%;
text-align: center;
color: #fff;
background-color: $theme-color;
letter-spacing: 10px;
font-size: 20px;
cursor: pointer;
&.disable {
background-color: #555;
cursor: default;
}
}
.pwd-intensity-container {
width: 270px;
text-align: right;
... ... @@ -99,50 +72,6 @@
}
}
.pwd-tips {
position: absolute;
top: -10px;
left: 360px;
width: 160px;
height: 78px;
padding-top: 7px;
font-size: 12px;
background: url(/passport/tip/block.png) no-repeat;
z-index: 3;
> div {
position: relative;
height: 22px;
line-height: 22px;
margin-left: 15px;
padding-left: 15px;
font-size: 12px;
color: #b9b9b9;
i {
position: absolute;
width: 14px;
height: 14px;
left: -2px;
top: 50%;
margin: -7px 0 0;
background: url(/passport/tip/info.png) no-repeat;
}
&.no {
color: red;
i {
background: url(/passport/tip/error.png) no-repeat;
}
}
&.yes i {
background: url(/passport/tip/success.png) no-repeat;
}
}
}
.email-autocomplete {
position: absolute;
width: 225px;
... ... @@ -164,58 +93,9 @@
}
}
.err-tip {
position: absolute;
font-size: 14px;
white-space: nowrap;
top: 8px;
left: $err-tips-width;
padding: 6px 0;
color: $blue;
span {
font-size: 1em;
}
a {
text-decoration: underline;
color: $blue;
}
}
/* 完善信息提示框 */
.page-tip {
display: block;
width: 100%;
height: 30px;
line-height: 30px;
text-align: center;
font-size: 20px;
font-weight: bold;
color: #ccc;
clear: both;
margin-bottom: 15px;
}
}
.passport-cover {
float: left;
margin: 107px 0;
width: 575px;
.cover-content {
width: 100%;
height: 318px;
padding: 50px 0;
border-right: 1px solid #dfdfdf;
}
.cover-img {
display: block;
width: 252px;
height: 190px;
margin: 0 auto;
margin-top: 50px;
.focus {
border: 2px solid #000 !important;
}
}
... ... @@ -224,3 +104,4 @@
@import "back";
@import "welcome";
@import "relate";
@import "third";
... ...
@import "config";
.login-page {
@mixin passport-page ;
@mixin passport-page
;
li {
@mixin li-setting ;
}
.relative {
position: relative;
}
.right {
float: right;
@mixin li-setting
;
}
.login-fail-tip {
... ... @@ -37,19 +31,13 @@
}
.phone {
@mixin phone ;
&.focus-gain {
border: 2px solid #000;
}
&.focus-lost {
border: 1px solid #dbdbdb;
}
@mixin phone
;
}
.input {
@mixin input;
@mixin input
;
&.phone-num {
width: 150px;
... ... @@ -62,28 +50,14 @@
width: $captcha;
float: left;
&.focus-gain {
border: 2px solid #000;
}
&.focus-lost {
border: 1px solid #dbdbdb;
}
}
&.password {
&.focus-gain {
border: 2px solid #000;
}
&.focus-lost {
border: 1px solid #dbdbdb;
}
}
}
.login-btn {
margin-top: 40px;
margin-top: 35px;
height: $item-height;
width: $item-width;
line-height: @height;
}
.captcha-component {
... ... @@ -119,7 +93,8 @@
cursor: pointer;
.small {
@mixin small;
@mixin small
;
}
}
... ... @@ -128,14 +103,6 @@
color: #b9b9b9;
font-size: 14px;
text-align: center;
.iconfont {
font-size: 14px;
}
.fast-reg {
color: #ff1901;
}
}
.third-party-login {
... ... @@ -178,58 +145,4 @@
background: url(/passport/third/renren.png) no-repeat;
}
}
.caps-lock {
position: absolute;
color: #666;
border: #ffe57d;
background: #fff6d2;
white-space: nowrap;
top: 8px;
left: 278px;
padding: 0 20px;
height: 27px;
line-height: 30px;
}
/* 选择国家 */
.select {
.header {
float: left;
.name {
display: inline-block;
}
.icon {
color: red;
}
}
}
.options {
position: absolute;
background-color: #f8f8f8;
top: $item-height;
left: 0;
z-index: 100;
font-size: 1.2em;
.option {
width: $item-width;
.selected {
display: inline-block;
width: 50px;
color: red;
text-align: center;
}
.name {
display: inline-block;
}
&.touch {
background-color: #666;
}
}
}
}
... ...
... ... @@ -25,7 +25,11 @@
border: none !important;
}
&.captcha,
&.captcha {
width: $captcha;
float: left;
}
&.msg-captcha {
width: $captcha;
float: left;
... ... @@ -56,8 +60,8 @@
}
.btn {
height: 45px;
line-height: 45px;
height: $item-height;
line-height: @height;
color: #fff;
border: none;
padding: 0;
... ... @@ -237,15 +241,6 @@
}
.success-btn {
display: block;
margin: 46px auto 0;
width: 180px;
height: 45px;
line-height: 45px;
background: $theme-color;
text-align: center;
color: #fff;
letter-spacing: 2px;
text-align: center;
}
}
... ...
@import "config";
$big-font: 20px;
$small-font: 13px;
$btn-height: 50px;
$btn-width: 180px;
.bind-wrapper {
.authPage,
.pwdPage,
.relateSuccessPage {
@mixin passport-page;
}
.bindConfirmPage {
@mixin passport-page;
width: 530px !important;
.quick-link {
margin: 0 150px;
}
}
.relateConfirmPage {
@mixin passport-page;
width: 530px !important;
.quick-btn {
margin: 0 70px;
}
}
.bindSuccessPage {
@mixin passport-page;
width: 650px !important;
}
.relateSuccessPage {
@mixin passport-page;
}
li {
@mixin li-setting;
&.small {
height: calc($item-height / 3);
}
&.big-width {
height: 110px;
margin: -10px 0;
}
}
.title {
font-size: $big-font;
color: $theme-color;
font-weight: bold;
height: $item-height;
line-height: @height;
}
.desc {
font-size: $small-font;
height: @font-size;
}
.center {
text-align: center;
}
.underline {
text-decoration: underline;
}
.input {
@mixin input;
}
.bindConfirmPage {
li {
width: 530px !important;
height: $item-height;
}
}
}
.btn-fixed-height {
height: $btn-height;
line-height: @height;
width: $btn-width;
margin: 0 auto;
}
.bottom {
position: absolute;
bottom: 0;
}
$captcha-input: 195px;
$captcha-margin: 20px;
$captcha-ctrl: calc($item-width - $captcha-input - $captcha-margin);
$captcha-img-width: 90px;
$captcha-btn-width: calc($captcha-ctrl - $captcha-img-width);
.img-captcha-component {
.input {
@mixin input;
width: $captcha-input;
}
.refresh {
background-color: $captcha-img-bg-color;
margin-left: $captcha-margin;
width: $captcha-ctrl;
height: $item-height;
.img-captcha {
width: 90px;
height: $item-height;
}
.ctrl {
height: $item-height;
width: $captcha-btn-width;
line-height: @height;
text-align: center;
color: $captcha-fresh;
cursor: pointer;
}
}
}
.sms-captcha-component {
.input {
@mixin input;
width: $captcha-input;
}
.send {
margin-left: $captcha-margin;
width: $captcha-ctrl;
height: $item-height;
line-height: @height;
}
}
$mobile-margin: 20px;
$mobile-region: 100px;
$mobile-code: 50px;
$mobile-mobile: calc($item-width - $mobile-margin - $mobile-region);
$mobile-phone: calc($item-width - $mobile-margin - $mobile-region - $mobile-code - 2px);
.mobile-input-component {
.region {
@mixin region;
}
.ctrl {
border: 1px solid $bord-color;
width: $mobile-mobile;
margin-left: $mobile-margin;
height: $item-height;
.code {
@mixin country-code;
}
.phone-num {
width: $mobile-phone;
height: calc($item-height - 2px);
border: none !important;
}
}
}
... ...