Showing
14 changed files
with
382 additions
and
71 deletions
apps/api/controllers/captcha.js
0 → 100644
@@ -15,10 +15,13 @@ var multipartMiddleware = multipart(); | @@ -15,10 +15,13 @@ var multipartMiddleware = multipart(); | ||
15 | const uploadApi = require(cRoot + '/upload.js'); | 15 | const uploadApi = require(cRoot + '/upload.js'); |
16 | 16 | ||
17 | const hotfix = require(`${cRoot}/hotfix`); | 17 | const hotfix = require(`${cRoot}/hotfix`); |
18 | +const captcha = require(`${cRoot}/captcha`); | ||
18 | 19 | ||
19 | // routers | 20 | // routers |
20 | 21 | ||
21 | router.post('/api/upload/image', multipartMiddleware, uploadApi.uploadImg); | 22 | router.post('/api/upload/image', multipartMiddleware, uploadApi.uploadImg); |
22 | router.post('/hf/v1', hotfix.v1); | 23 | router.post('/hf/v1', hotfix.v1); |
23 | 24 | ||
25 | +router.get('/api/captcha/get', captcha.get); | ||
26 | + | ||
24 | module.exports = router; | 27 | module.exports = router; |
@@ -3,11 +3,12 @@ | @@ -3,11 +3,12 @@ | ||
3 | const _ = require('lodash'); | 3 | const _ = require('lodash'); |
4 | const helpers = global.yoho.helpers; | 4 | const helpers = global.yoho.helpers; |
5 | const cookie = global.yoho.cookie; | 5 | const cookie = global.yoho.cookie; |
6 | +const EventEmitter = require('events'); | ||
6 | const utils = require(global.utils); | 7 | const utils = require(global.utils); |
7 | const RegService = require('../models/reg-service'); | 8 | const RegService = require('../models/reg-service'); |
8 | const PhoneService = require('../models/phone-service'); | 9 | const PhoneService = require('../models/phone-service'); |
9 | const AuthHelper = require('../models/auth-helper'); | 10 | const AuthHelper = require('../models/auth-helper'); |
10 | -const captchaService = require('../models/captcha-service'); | 11 | +const imgcheckAPI = require('../../serverAPI/imgcheck'); |
11 | 12 | ||
12 | // constrant | 13 | // constrant |
13 | const CODE_REQUIRED = '请输入校验码'; | 14 | const CODE_REQUIRED = '请输入校验码'; |
@@ -42,19 +43,28 @@ const _step1 = (req, res, next) => { | @@ -42,19 +43,28 @@ const _step1 = (req, res, next) => { | ||
42 | req.session.smsLogin.count = 5; | 43 | req.session.smsLogin.count = 5; |
43 | } | 44 | } |
44 | 45 | ||
45 | - let template = 'sms/login'; | ||
46 | - let viewData = { | ||
47 | - module: 'passport', | ||
48 | - page: 'sms-login', | ||
49 | - title: '手机短信登录', | ||
50 | - isPassportPage: true, | ||
51 | - headerText: '手机号码快捷登录', | ||
52 | - captchaUrl: helpers.urlFormat('/passport/sms_login/captcha.png', {t: Date.now()}), | ||
53 | - areaCode: '+86', // 默认的区号 | ||
54 | - countrys: RegService.getAreaData() // 地区信息列表 | ||
55 | - }; | 46 | + imgcheckAPI.gen() |
47 | + .then(captcha => { | ||
48 | + _.set(req.session, 'captcha.code', captcha.data.code); | ||
49 | + | ||
50 | + let template = 'sms/login'; | ||
51 | + let viewData = { | ||
52 | + width750: true, | ||
53 | + module: 'passport', | ||
54 | + page: 'sms-login', | ||
55 | + title: '手机短信登录', | ||
56 | + isPassportPage: true, | ||
57 | + headerText: '手机号码快捷登录', | ||
58 | + captchaUrl: helpers.urlFormat('/passport/sms_login/captcha.png', {t: Date.now()}), | ||
59 | + areaCode: '+86', // 默认的区号 | ||
60 | + countrys: RegService.getAreaData(), // 地区信息列表 | ||
61 | + captsrc: captcha.data.src | ||
62 | + }; | ||
63 | + | ||
64 | + res.render(template, viewData); | ||
65 | + }) | ||
66 | + .catch(next); | ||
56 | 67 | ||
57 | - res.render(template, viewData); | ||
58 | }; | 68 | }; |
59 | 69 | ||
60 | // 短信登录 第二步: 输入 校验码 | 70 | // 短信登录 第二步: 输入 校验码 |
@@ -118,44 +128,59 @@ exports.loginPage = (req, res, next) => { | @@ -118,44 +128,59 @@ exports.loginPage = (req, res, next) => { | ||
118 | } | 128 | } |
119 | }; | 129 | }; |
120 | 130 | ||
121 | -exports.tokenBefore = (req, res, next) => { | 131 | + |
132 | +/** | ||
133 | + * step1 的表单提交验证 | ||
134 | + */ | ||
135 | +exports.indexCheck = (req, res, next) => { | ||
136 | + _.set(req.session, 'smsLogin.step', 1); | ||
137 | + | ||
122 | let area = req.query.area = (req.query.area || '').trim(); | 138 | let area = req.query.area = (req.query.area || '').trim(); |
123 | let mobile = req.query.mobile = (req.query.mobile || '').trim(); | 139 | let mobile = req.query.mobile = (req.query.mobile || '').trim(); |
124 | - let step = _.get(req.session, 'smsLogin.step'); | ||
125 | - let count = _.get(req.session, 'smsLogin.count'); | ||
126 | - let interval = _.get(req.session, 'smsLogin.interval'); | ||
127 | - let captcha1 = _.get(req.session, 'smsLogin.captcha'); | ||
128 | - let captcha2 = (req.query.captcha || '').trim(); | 140 | + let captcode = (req.body.captcode || '').trim(); |
141 | + let captcodeValid = _.get(req.session, 'captcha.code'); | ||
129 | 142 | ||
143 | + let em = new EventEmitter(); | ||
130 | 144 | ||
131 | - if (!req.xhr) { | ||
132 | - return next(404); | ||
133 | - } | 145 | + // 校验 成功 |
146 | + em.on('resolve', () => { | ||
147 | + // 1. 将信息放入 session | ||
148 | + _.set(req.session, 'smsLogin.area', area); | ||
149 | + _.set(req.session, 'smsLogin.mobile', mobile); | ||
150 | + _.set(req.session, 'smsLogin.step', 2); | ||
134 | 151 | ||
135 | - if ([area, mobile].some(val => val === '')) { | ||
136 | - return res.json({ | ||
137 | - code: 401, | ||
138 | - message: '手机号 必填' | 152 | + res.json({ |
153 | + redirect: '/passport/sms_login?step=2' | ||
139 | }); | 154 | }); |
155 | + }); | ||
156 | + | ||
157 | + // 校验 失败 | ||
158 | + em.on('reject', error => { | ||
159 | + _.set(req.session, 'smsLogin.step', 1); | ||
160 | + | ||
161 | + res.status(400).json(error); | ||
162 | + }); | ||
163 | + | ||
164 | + // 验证 | ||
165 | + if ([area, mobile].some(val => val === '')) { | ||
166 | + em.emit('reject', {message: '请填写手机号'}); | ||
167 | + } else if (captcode !== captcodeValid) { | ||
168 | + em.emit('reject', {message: '请将图片旋转到正确位置'}); | ||
140 | } | 169 | } |
141 | 170 | ||
142 | - delete req.session.smsLogin.captcha; // 图形验证码 一次性 | 171 | + // congratulation~~ |
172 | + em.emit('resolve'); | ||
173 | +}; | ||
143 | 174 | ||
144 | - // step1 要 校验图形验证码 | ||
145 | - if (step === 1) { | ||
146 | - if (!captcha2) { | ||
147 | - return res.json({ | ||
148 | - code: 400, | ||
149 | - message: '请填写验证码' | ||
150 | - }); | ||
151 | - } | 175 | +exports.tokenBefore = (req, res, next) => { |
152 | 176 | ||
153 | - if (captcha1 !== captcha2) { | ||
154 | - return res.json({ | ||
155 | - code: 400, | ||
156 | - message: VERIFY_ERROR | ||
157 | - }); | ||
158 | - } | 177 | + let step = _.get(req.session, 'smsLogin.step'); |
178 | + let count = _.get(req.session, 'smsLogin.count'); | ||
179 | + let interval = _.get(req.session, 'smsLogin.interval'); | ||
180 | + | ||
181 | + | ||
182 | + if (!req.xhr || step !== 2) { | ||
183 | + return next(404); | ||
159 | } | 184 | } |
160 | 185 | ||
161 | let now = Date.now(); | 186 | let now = Date.now(); |
@@ -186,8 +211,8 @@ exports.tokenBefore = (req, res, next) => { | @@ -186,8 +211,8 @@ exports.tokenBefore = (req, res, next) => { | ||
186 | 211 | ||
187 | // AJAX 获取验证码 | 212 | // AJAX 获取验证码 |
188 | exports.token = (req, res, next) => { | 213 | exports.token = (req, res, next) => { |
189 | - let area = req.query.area; | ||
190 | - let mobile = req.query.mobile; | 214 | + let area = _.get(req.session, 'smsLogin.area'); |
215 | + let mobile = _.get(req.session, 'smsLogin.mobile'); | ||
191 | 216 | ||
192 | PhoneService.sendSMS(mobile, area, 1).then(result => { | 217 | PhoneService.sendSMS(mobile, area, 1).then(result => { |
193 | if (result.code === 200) { | 218 | if (result.code === 200) { |
@@ -376,6 +401,7 @@ exports.password = (req, res, next) => { | @@ -376,6 +401,7 @@ exports.password = (req, res, next) => { | ||
376 | /** | 401 | /** |
377 | * 生成 校验码 | 402 | * 生成 校验码 |
378 | */ | 403 | */ |
404 | +/* | ||
379 | exports.genCaptcha = (req, res) => { | 405 | exports.genCaptcha = (req, res) => { |
380 | let captcha = captchaService.generateCaptcha(90, 52, 4); | 406 | let captcha = captchaService.generateCaptcha(90, 52, 4); |
381 | 407 | ||
@@ -386,3 +412,4 @@ exports.genCaptcha = (req, res) => { | @@ -386,3 +412,4 @@ exports.genCaptcha = (req, res) => { | ||
386 | .status(200) | 412 | .status(200) |
387 | .send(captcha.image); | 413 | .send(captcha.image); |
388 | }; | 414 | }; |
415 | +*/ |
apps/passport/img-check.js
0 → 100644
@@ -41,6 +41,7 @@ router.post('/passport/login/auth', login.local.login); | @@ -41,6 +41,7 @@ router.post('/passport/login/auth', login.local.login); | ||
41 | // SMS 短信 | 41 | // SMS 短信 |
42 | router.use('/passport/sms_login', login.common.beforeLogin, smsLogin.beforeIn); | 42 | router.use('/passport/sms_login', login.common.beforeLogin, smsLogin.beforeIn); |
43 | router.get('/passport/sms_login', smsLogin.loginPage); | 43 | router.get('/passport/sms_login', smsLogin.loginPage); |
44 | +router.post('/passport/sms_login/step1_check', smsLogin.indexCheck); | ||
44 | router.get('/passport/sms_login/token.json', | 45 | router.get('/passport/sms_login/token.json', |
45 | smsLogin.tokenBefore, | 46 | smsLogin.tokenBefore, |
46 | smsLogin.token); // only ajax; | 47 | smsLogin.token); // only ajax; |
@@ -48,7 +49,6 @@ router.get('/passport/sms_login/check.json', | @@ -48,7 +49,6 @@ router.get('/passport/sms_login/check.json', | ||
48 | smsLogin.checkBefore, | 49 | smsLogin.checkBefore, |
49 | smsLogin.check); // only ajax | 50 | smsLogin.check); // only ajax |
50 | router.post('/passport/sms_login/password.json', smsLogin.password); | 51 | router.post('/passport/sms_login/password.json', smsLogin.password); |
51 | -router.get('/passport/sms_login/captcha.png', smsLogin.genCaptcha); | ||
52 | 52 | ||
53 | // 微信登录 | 53 | // 微信登录 |
54 | router.get('/passport/login/wechat', login.common.beforeLogin, login.wechat.login); | 54 | router.get('/passport/login/wechat', login.common.beforeLogin, login.wechat.login); |
@@ -7,12 +7,11 @@ | @@ -7,12 +7,11 @@ | ||
7 | <input id="phone-num" class="input phone-num" type="text" placeholder="手机号"> | 7 | <input id="phone-num" class="input phone-num" type="text" placeholder="手机号"> |
8 | <button class="clear-input" type="button"></button> | 8 | <button class="clear-input" type="button"></button> |
9 | </div> | 9 | </div> |
10 | - <div class="passport-captcha row"> | ||
11 | - <div class="passport-captcha-img"><img src="{{captchaUrl}}" alt=""></div> | ||
12 | - <div class="passport-captcha-input"> | ||
13 | - <input id="js-captcha" type="text" placeholder="验证码"> | ||
14 | - </div> | 10 | + {{!--图片验证 start--}} |
11 | + <div id="js-img-check"> | ||
12 | + <input type="hidden" name="captsrc" value="{{captsrc}}"> | ||
15 | </div> | 13 | </div> |
14 | + {{!--图片验证 end--}} | ||
16 | <button id="btn-next" class="btn btn-next disable row" disabled>获取短信验证码</button> | 15 | <button id="btn-next" class="btn btn-next disable row" disabled>获取短信验证码</button> |
17 | </div> | 16 | </div> |
18 | </div> | 17 | </div> |
apps/serverAPI/imgcheck.js
0 → 100644
public/hbs/common/img-check.hbs
0 → 100644
1 | + {{!--图片验证--}} | ||
2 | +<div class="img-check"> | ||
3 | + <div class="img-check-header"> | ||
4 | + <span>请将下列图片点击翻转至正确方向</span> | ||
5 | + <a class="img-check-refresh">换一批</a> | ||
6 | + </div> | ||
7 | + <div class="img-check-main"> | ||
8 | + <ul class="img-check-pics"> | ||
9 | + <li class="img-check-pic" data-val="0" style="background-image:url('{{imgSrc}}');"></li> | ||
10 | + <li class="img-check-pic" data-val="0" style="background-image:url('{{imgSrc}}');"></li> | ||
11 | + <li class="img-check-pic" data-val="0" style="background-image:url('{{imgSrc}}');"></li> | ||
12 | + <li class="img-check-pic" data-val="0" style="background-image:url('{{imgSrc}}');"></li> | ||
13 | + </ul> | ||
14 | + </div> | ||
15 | +</div> |
@@ -17,6 +17,23 @@ tip = require('plugin/tip'); | @@ -17,6 +17,23 @@ tip = require('plugin/tip'); | ||
17 | api = require('./api'); | 17 | api = require('./api'); |
18 | checkPoint = require('./smslogin/check-point'); | 18 | checkPoint = require('./smslogin/check-point'); |
19 | 19 | ||
20 | + | ||
21 | +// 图片验证码 | ||
22 | +let ImgCheck = require('plugin/img-check'); | ||
23 | + | ||
24 | +let imgCheck = new ImgCheck('#js-img-check', { | ||
25 | + useREM: { | ||
26 | + rootFontSize: 40, | ||
27 | + picWidth: 150 | ||
28 | + } | ||
29 | +}); | ||
30 | + | ||
31 | +imgCheck.init({ | ||
32 | + imgSrc: $('#js-img-check').find('input').val() | ||
33 | +}); | ||
34 | + | ||
35 | + | ||
36 | + | ||
20 | page = { | 37 | page = { |
21 | init: function() { | 38 | init: function() { |
22 | this.domInit(); | 39 | this.domInit(); |
@@ -28,8 +45,6 @@ page = { | @@ -28,8 +45,6 @@ page = { | ||
28 | $nextBtn = $('#btn-next'); | 45 | $nextBtn = $('#btn-next'); |
29 | $phoneNum = $('#phone-num'); | 46 | $phoneNum = $('#phone-num'); |
30 | $resetBtn = $('.clear-input'); | 47 | $resetBtn = $('.clear-input'); |
31 | - $captcha = $('.passport-captcha input'); | ||
32 | - $captchaPNG = $('.passport-captcha-img img'); | ||
33 | }, | 48 | }, |
34 | bindEvent: function() { | 49 | bindEvent: function() { |
35 | var self = this; | 50 | var self = this; |
@@ -41,12 +56,6 @@ page = { | @@ -41,12 +56,6 @@ page = { | ||
41 | self.toggleNextBtn(); | 56 | self.toggleNextBtn(); |
42 | }); | 57 | }); |
43 | 58 | ||
44 | - $captcha.on('input', function() { | ||
45 | - self.toggleNextBtn(); | ||
46 | - }); | ||
47 | - | ||
48 | - $captchaPNG.on('click', $.proxy(this.refreshCapatch, this)); | ||
49 | - | ||
50 | $nextBtn.on('click', function() { | 59 | $nextBtn.on('click', function() { |
51 | self.goNext(); | 60 | self.goNext(); |
52 | }); | 61 | }); |
@@ -62,7 +71,7 @@ page = { | @@ -62,7 +71,7 @@ page = { | ||
62 | 71 | ||
63 | // 切换$nextBtn disable状态 | 72 | // 切换$nextBtn disable状态 |
64 | toggleNextBtn: function() { | 73 | toggleNextBtn: function() { |
65 | - var bool = Boolean($.trim($phoneNum.val())) && Boolean($.trim($captcha.val())); | 74 | + var bool = Boolean($.trim($phoneNum.val())); |
66 | 75 | ||
67 | $nextBtn | 76 | $nextBtn |
68 | .toggleClass('disable', !bool) | 77 | .toggleClass('disable', !bool) |
@@ -71,17 +80,11 @@ page = { | @@ -71,17 +80,11 @@ page = { | ||
71 | $resetBtn.toggle(bool); | 80 | $resetBtn.toggle(bool); |
72 | }, | 81 | }, |
73 | 82 | ||
74 | - refreshCapatch: function() { | ||
75 | - $captchaPNG.attr('src', '/passport/sms_login/captcha.png?t=' + Date.now()); | ||
76 | - $captcha.val(''); | ||
77 | - }, | ||
78 | - | ||
79 | // 提交按钮 | 83 | // 提交按钮 |
80 | goNext: function() { | 84 | goNext: function() { |
81 | - var self = this; | ||
82 | var areaCode = $countrySelect.val(); | 85 | var areaCode = $countrySelect.val(); |
83 | var phone = $.trim($phoneNum.val()); | 86 | var phone = $.trim($phoneNum.val()); |
84 | - var captcha = $.trim($captcha.val()); | 87 | + var captcha = $.trim(imgCheck.getResults()); |
85 | 88 | ||
86 | if ($nextBtn.prop('disabled')) { | 89 | if ($nextBtn.prop('disabled')) { |
87 | return; | 90 | return; |
@@ -92,11 +95,16 @@ page = { | @@ -92,11 +95,16 @@ page = { | ||
92 | return; | 95 | return; |
93 | } | 96 | } |
94 | 97 | ||
98 | + if (captcha === '0000') { | ||
99 | + tip.show('请将图片旋转到正确位置'); | ||
100 | + return; | ||
101 | + } | ||
102 | + | ||
95 | $nextBtn.prop('disabled', true); | 103 | $nextBtn.prop('disabled', true); |
96 | - $.get('/passport/sms_login/token.json', { | 104 | + $.post('/passport/sms_login/step1_check', { |
97 | area: areaCode.replace('+', ''), | 105 | area: areaCode.replace('+', ''), |
98 | mobile: phone, | 106 | mobile: phone, |
99 | - captcha: captcha | 107 | + captcode: captcha |
100 | }) | 108 | }) |
101 | .done(function(data) { | 109 | .done(function(data) { |
102 | if (data.code === 200) { | 110 | if (data.code === 200) { |
@@ -104,12 +112,14 @@ page = { | @@ -104,12 +112,14 @@ page = { | ||
104 | $nextBtn.off(); | 112 | $nextBtn.off(); |
105 | location.href = data.redirect; | 113 | location.href = data.redirect; |
106 | } else { | 114 | } else { |
107 | - self.refreshCapatch(); | 115 | + imgCheck.refresh(); |
108 | tip.show(data.message); | 116 | tip.show(data.message); |
109 | } | 117 | } |
110 | }) | 118 | }) |
111 | - .fail(function() { | ||
112 | - tip.show('出错了, 请重试'); | 119 | + .fail(function(error) { |
120 | + var message = error && error.message || ''; | ||
121 | + | ||
122 | + tip.show(message || '出错了, 请重试'); | ||
113 | }) | 123 | }) |
114 | .always(function() { | 124 | .always(function() { |
115 | $nextBtn.prop('disabled', false); | 125 | $nextBtn.prop('disabled', false); |
public/js/plugin/img-check.js
0 → 100644
1 | +/** | ||
2 | + * Plugin: 图片旋转验证; | ||
3 | + * @example | ||
4 | + * pc: | ||
5 | + * var ImgCheck = require('path/to/img-check') | ||
6 | + * var imgCheck = new ImgCheck('#js-img-check', { | ||
7 | + * template: require('path/to/hbs') | ||
8 | + * }, { | ||
9 | + * imgSrc | ||
10 | + * }) | ||
11 | + * | ||
12 | + * imgCheck.init({imgSrc}) | ||
13 | + * | ||
14 | + * imgCheck.getResult() // '1230' | ||
15 | + *- ---------------------------------------- | ||
16 | + * @example | ||
17 | + * wap: | ||
18 | + * var imgCheck = new ImgCheck('#js-img-check', { | ||
19 | + * useREM: { | ||
20 | + * rootFontSize: 40, | ||
21 | + * picWidth: 150 | ||
22 | + * } | ||
23 | + * }) | ||
24 | + * imgCheck.init({ | ||
25 | + * imgSrc | ||
26 | + * }) | ||
27 | + * | ||
28 | + * imgCheck.getResult() // '1112' | ||
29 | + */ | ||
30 | + | ||
31 | + | ||
32 | + | ||
33 | +/** | ||
34 | + * @param selector|jQuery|Element container | ||
35 | + * @param object options 配置选项 | ||
36 | + * pc: | ||
37 | + * { | ||
38 | + * template, | ||
39 | + * refreshURI | ||
40 | + * } | ||
41 | + * | ||
42 | + * wap: | ||
43 | + * { | ||
44 | + * useREM: { | ||
45 | + * rootFontSize, // 设计稿基准字体大小 | ||
46 | + * picWidth // 设计稿的验证图片宽度 | ||
47 | + * }, | ||
48 | + * template, | ||
49 | + * refreshURI | ||
50 | + * } | ||
51 | + * | ||
52 | + * @param object data 初始值 | ||
53 | + * { | ||
54 | + * imgSrc: '图片src' | ||
55 | + * } | ||
56 | + * | ||
57 | + */ | ||
58 | +const ImgCheck = function(container, options) { | ||
59 | + let optionDefault = { | ||
60 | + useREM: null, | ||
61 | + template: require('common/img-check.hbs'), | ||
62 | + refreshURI: '/api/captcha/get' | ||
63 | + }; | ||
64 | + | ||
65 | + $.extend(this, optionDefault, options); | ||
66 | + | ||
67 | + this.$container = $(container); | ||
68 | + this.$imgCheck = null; | ||
69 | + this.$imgPics = null; | ||
70 | + this.picWidth = null; | ||
71 | + | ||
72 | + return this; | ||
73 | +}; | ||
74 | + | ||
75 | +ImgCheck.prototype = { | ||
76 | + /** | ||
77 | + * method:初始化 | ||
78 | + * @param object data | ||
79 | + * { | ||
80 | + * imgSrc | ||
81 | + * } | ||
82 | + */ | ||
83 | + init: function(data) { | ||
84 | + if (this.useREM) { | ||
85 | + this.picWidth = this.useREM.picWidth / this.useREM.rootFontSize; | ||
86 | + } | ||
87 | + | ||
88 | + | ||
89 | + this.render(data); | ||
90 | + this.bindEvents(); | ||
91 | + }, | ||
92 | + | ||
93 | + /** | ||
94 | + * method: 绑定事件 | ||
95 | + */ | ||
96 | + bindEvents: function() { | ||
97 | + this.$container | ||
98 | + .on('click.refresh', '.img-check-refresh', $.proxy(this.refresh, this)) | ||
99 | + .on('click.rotate', '.img-check-pic', $.proxy(this.rotateImg, this)); | ||
100 | + }, | ||
101 | + | ||
102 | + /** | ||
103 | + * method: 渲染 dom | ||
104 | + * @param obj data 渲染数据 | ||
105 | + * { | ||
106 | + * imgSrc: 'src' //图片src | ||
107 | + * } | ||
108 | + */ | ||
109 | + render: function(data) { | ||
110 | + var self = this; | ||
111 | + | ||
112 | + this.$container.html(this.template(data)); | ||
113 | + this.$imgPics = this.$container.find('.img-check-pic'); | ||
114 | + | ||
115 | + if (!this.useREM && !this.picWidth) { | ||
116 | + this.picWidth = this.$imgPics.width(); | ||
117 | + } | ||
118 | + | ||
119 | + this.$imgPics.each(function(index, elem) { | ||
120 | + var $elem = $(elem); | ||
121 | + var position = self.calcPosition($elem); | ||
122 | + | ||
123 | + $elem.css('backgroundPosition', position); | ||
124 | + }); | ||
125 | + }, | ||
126 | + | ||
127 | + /** | ||
128 | + * method: 计算 background-position | ||
129 | + * @param num index img-check-pic 的index | ||
130 | + * @param num count img-check-pic | ||
131 | + */ | ||
132 | + calcPosition: function($elem) { | ||
133 | + var positionX, positionY; | ||
134 | + var index = $elem.index(); | ||
135 | + var count = parseInt($elem.attr('data-val'), 10); | ||
136 | + var unit = this.useREM ? 'rem' : 'px'; | ||
137 | + | ||
138 | + count = count % 4; | ||
139 | + | ||
140 | + positionX = -index * this.picWidth + unit; | ||
141 | + positionY = -count * this.picWidth + unit; | ||
142 | + | ||
143 | + | ||
144 | + return [positionX, positionY].join(' '); | ||
145 | + }, | ||
146 | + | ||
147 | + /** | ||
148 | + * Handler method: 刷新验证码 | ||
149 | + */ | ||
150 | + refresh: function() { | ||
151 | + this.render({ | ||
152 | + imgSrc: 'http://portal.mogujie.com/api/validate/captcha/pc/zie3qc7b1tia?' + Date.now() | ||
153 | + }); | ||
154 | + }, | ||
155 | + | ||
156 | + | ||
157 | + /** | ||
158 | + * Handler method: 旋转图片 | ||
159 | + */ | ||
160 | + rotateImg: function(event) { | ||
161 | + var $pic = $(event.target); | ||
162 | + var prevRotateCount = parseInt($pic.attr('data-val'), 10); | ||
163 | + | ||
164 | + $pic.attr('data-val', prevRotateCount + 1); | ||
165 | + | ||
166 | + $pic.css({ | ||
167 | + backgroundPosition: this.calcPosition($pic) | ||
168 | + }); | ||
169 | + }, | ||
170 | + | ||
171 | + /** | ||
172 | + * method: 获取结果 | ||
173 | + * @return string '0123' | ||
174 | + */ | ||
175 | + getResults: function() { | ||
176 | + var result = []; | ||
177 | + | ||
178 | + this.$container.find('.img-check-pic') | ||
179 | + .each(function() { | ||
180 | + var $elem = $(this); | ||
181 | + | ||
182 | + result.push($elem.attr('data-val')); | ||
183 | + }); | ||
184 | + | ||
185 | + return result.join(''); | ||
186 | + } | ||
187 | +}; | ||
188 | + | ||
189 | +ImgCheck.prototype.construct = ImgCheck; | ||
190 | + | ||
191 | + | ||
192 | +module.exports = ImgCheck; |
public/scss/layout/_img-check.css
0 → 100644
1 | +/* ======================= *\ | ||
2 | + Module: 图片旋转验证 | ||
3 | +\* ======================= */ | ||
4 | +.img-check { | ||
5 | + margin-top: 45px; | ||
6 | + margin-bottom: 30px; | ||
7 | +} | ||
8 | + | ||
9 | +.img-check-header { | ||
10 | + font-size: 28px; | ||
11 | + line-height: 35px; | ||
12 | + text-align: left; | ||
13 | + margin-bottom: 30px; | ||
14 | + color: #B0B0B0; | ||
15 | +} | ||
16 | + | ||
17 | +.img-check-refresh { | ||
18 | + float: right; | ||
19 | + font-size: 22px; | ||
20 | + color: #36A74C; | ||
21 | +} | ||
22 | + | ||
23 | +.img-check-pics { | ||
24 | + display: flex; | ||
25 | + justify-content: space-between; | ||
26 | + list-style: none; | ||
27 | + padding: 0; | ||
28 | + margin: 0; | ||
29 | + | ||
30 | + li { | ||
31 | + background-size: 600px 600px; | ||
32 | + background-repeat: no-repeat; | ||
33 | + background-color: #575757; | ||
34 | + width: 150px; | ||
35 | + height: 150px; | ||
36 | + } | ||
37 | +} |
-
Please register or login to post a comment