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