1 /**
  2  *
  3  * 验证手机公用组件(非业务流程)
  4  *
  5  * @fileOverView 验证手机公用组件
  6  * @author  <a href="mailto:zhang.gd@foxmail.com">Zhang Guangda</a>
  7  * @date    2012-10-25
  8  */
  9 define(["core", "component/form"], function() {
 10 
 11 	var _originalMsg = "点击发送",
 12 		_sendingCodeMsg = "发送中...",
 13 		_changedMsg = "重新获取验证码",
 14 		_label1 = '手机号码',
 15 		_label1_empty = '您的手机号',
 16 		_label2 = '免费获取验证码',
 17 		_label3 = '短信验证码',
 18 		_defaultCooldown = 60,
 19 		_changedBtnClass = "we_get_code_btn_gray",
 20 		_cookieName = "_we_comp_vm",
 21 		_keyCookie = "_we_vkey",
 22 		_codeType = "mixed",
 23 		_verifyName = "phone",
 24 		_transName = "phone",
 25 		_verifyReg = function() { return '^1(3|4|5|7|8)\\d{9}$' },
 26 		_getCodeUrl = $we.conf.ENV.__API + "/ajaxVcode/sendByMobile",
 27 		_verifyCodeUrl = $we.conf.ENV.__API + "/ajaxVcode/checkMobile",
 28 		_maxBindedIdPerPhone = 20,
 29 		_getPhoneBindedNumApi = $we.conf.ENV.__API + "/ajaxBindMobile/getSdidCountByMobile";
 30 
 31 	var _changeBtnStyle = function(start) {
 32 			$(this.btnInput).val(_changedMsg + "(" + start + "秒)");
 33 			$(this.btnInput).addClass(_changedBtnClass);
 34 			this.bCanGetCode = false;
 35 		};
 36 
 37 	var _recoverBtnStyle = function() {
 38 			$(this.btnInput).val(_originalMsg);
 39 			$(this.btnInput).removeClass(_changedBtnClass);
 40 			this.bCanGetCode = true;
 41 		};
 42 
 43 	var _countDown = function(start) {
 44 			start = start || this.params.cooldown + 1;
 45 			var btn = $(this.btnInput),
 46 				me = this;
 47 
 48 			_changeBtnStyle.call(this, start);
 49 
 50 			var __countDownFun = function() {
 51 					--start;
 52 					if(start < 0) {
 53 						_recoverBtnStyle.call(me);
 54 						return;
 55 					}
 56 
 57 					btn.val($we.string.addStrNum(btn.val(), -1));
 58 
 59 					setTimeout(__countDownFun, 1000);
 60 				}
 61 
 62 			__countDownFun();
 63 
 64 		};
 65 
 66 	var _setCookie = function() {
 67 			$.cookie(this.params.cookieName, +new Date);
 68 		};
 69 
 70 	var _setCodeRegExp = function(type) {
 71 		switch(type) {
 72 			case "digital":
 73 			return '^ *\\d{6} *$';
 74 			break;
 75 			case "mixed":
 76 			return '^ *[0-9a-zA-Z]{6} *$';
 77 			break;
 78 			case "alpha":
 79 			return '^ *[a-zA-Z]{6} *$';
 80 			break;
 81 		}
 82 	};
 83 
 84 	/**
 85 	 * 绑定手机组件
 86 	 * @lends  $we.widget.comp.verify_code
 87 	 */
 88 	$we.widget.reg("comp.verify_code", {
 89 		/**
 90 		 * @constructs
 91 		 */
 92 		init: function(el, params) {
 93 			if(typeof el == "string") this.verifyCodeRootEl = $("#" + el)[0];
 94 			else this.verifyCodeRootEl = el;
 95 			this.params = params || {};
 96 
 97 			// 获取code的url
 98 			this.params.getCodeUrl = $we.utils.setValue(this.params.getCodeUrl, _getCodeUrl);
 99 			// 验证code的url
100 			this.params.verifyUrl = $we.utils.setValue(this.params.verifyUrl, _verifyCodeUrl);
101 			// 验证码的类型,目前只有digital和alpha
102 			this.params.codeType = $we.utils.setValue(this.params.codeType, _codeType);
103 			// 需要验证的验证对象的名称(从process.data中可能设置该值)
104 			this.params.verifyName = $we.utils.setValue(this.params.verifyName, _verifyName);
105 			// 验证成功后,将该名称储存到process.data中,默认该值与verifyName相同
106 			this.params.saveVerifyName = $we.utils.setValue(this.params.saveVerifyName, this.params.verifyName);
107 			// 是否是jsonp请求,默认为true
108 			this.params.jsonp = $we.utils.setValue(this.params.jsonp, true);
109 			// 验证对象的值,deprecated
110 			this.params.verifier = $we.utils.setValue(this.params.verifier, false);
111 			// form表单之前的表单,array
112 			this.params.formBefore = $we.utils.setValue(this.params.formBefore, false);
113 			// form表单之后的表单,array
114 			this.params.formAfter = $we.utils.setValue(this.params.formAfter, false);
115 			// 表单中第一个label的文案,当该表单不需要输入,已经有值
116 			this.params.label1 = $we.utils.setValue(this.params.label1, _label1);
117 			// 表单中第一个label的文案,当该表单需要输入
118 			this.params.label1_empty = $we.utils.setValue(this.params.label1_empty, _label1_empty);
119 			// 表单中第二个label的文案
120 			this.params.label2 = $we.utils.setValue(this.params.label2, _label2);
121 			// 表单中第三个label的文案
122 			this.params.label3 = $we.utils.setValue(this.params.label3, _label3);
123 			// 冷却时间
124 			this.params.cooldown = $we.utils.setValue(this.params.cooldown, _defaultCooldown);
125 			// 冷却时间设置的cookie名称
126 			this.params.cookieName = $we.utils.setValue(this.params.cookieName, _cookieName);
127 			// 验证对象的正则, function或者直接注明正则名称
128 			this.params.verifyReg = $we.utils.setValue(this.params.verifyReg, _verifyReg);
129 			// 传递给后端接口时,验证对象的名称
130 			this.params.transName = $we.utils.setValue(this.params.transName, _transName);
131 			// verifyCode的时候额外的请求参数
132 			this.params.extraData = $we.utils.setValue(this.params.extraData, false);
133 			// 表单提交后的回调
134 			this.params.formCommit = $we.utils.setValue(this.params.formCommit, $we.emptyFunction);
135 		},
136 		/**
137 		 * interfaces
138 		 * @memberOf $we.widget.comp.verify_code
139 		 */
140 		interfaces: {
141 			render: function(params) {
142 				if (typeof params == "object") {
143 					// 如果设置了验证对象的名称,并且没有设置储存验证对象的名称,令储存验证对象的名称等于验证对象的名称
144 					if (params.verifyName && !params.saveVerifyName)
145 						params.saveVerifyName = params.verifyName;
146 
147 					for (var i in params) {
148 						this.params[i] = params[i];
149 					}
150 				}
151 
152 
153 				// 是否可以获取验证码
154 				this.bCanGetCode = true;
155 				// 是否需要将验证对象的名称传递给后端
156 				this.bTransVerifier = false;
157 				// 根据需要验证对象的名称获取验证对象的值,或者直接被赋值
158 				this.verifier = $we.process.getData(this.params.verifyName) || this.params.verifier;
159 				// 需要验证的对象可否被写入
160 				this.bVerifierWritable = false;
161 				// 如果验证对象的值存在,但是验证对象的名称与最终存储的名称不同,也就是当前验证对象的名称只是一个过渡名称
162 				// 那么,我们认为这个验证对象还是需要传递给后端
163 				if (this.verifier && (this.params.verifyName != this.params.saveVerifyName))
164 					this.bTransVerifier = true;
165 
166 				var me = this,
167 					codeRegExp = _setCodeRegExp(this.params.codeType),	// 验证码的正则
168 					verifierItem;	// 验证对象的表单item
169 
170 				if (this.verifier) {
171 					verifierItem = {
172 						label: this.params.label1,
173 						name: 'verifier',
174 						type: 'content',
175 						value: '<span class="we_yellow">'+$we.string.maskString(this.verifier)+'</span>'
176 					};
177 				} else {
178 					this.bTransVerifier = true;
179 					this.bVerifierWritable = true;
180 					verifierItem = {
181 						label: this.params.label1_empty,
182 						name: 'verifier',
183 						expression: me.params.verifyReg,
184 						events: "blur",
185 						require: "true"
186 					};
187 				}
188 
189 				var formConfigs = [
190 					verifierItem, {
191 						label: this.params.label2,
192 						name: 'send_code',
193 						type: 'button',
194 						value: "点击发送",
195 						click: function() {
196 							me.sendCode(this);
197 						}
198 					}, {
199 						label: this.params.label3,
200 						name: 'code',
201 						expression: function() { return codeRegExp; },
202 						events: "blur",
203 						require: "true"
204 					}];
205 
206 				if (this.params.formBefore) {
207 					if (!$.isArray(this.params.formBefore))
208 						this.params.formBefore = [this.params.formBefore];
209 					
210 					formConfigs = this.params.formBefore.concat(formConfigs);
211 				}
212 
213 				if (this.params.formAfter) {
214 					if (!$.isArray(this.params.formAfter))
215 						this.params.formAfter = [this.params.formAfter];
216 					
217 					formConfigs = formConfigs.concat(this.params.formAfter);
218 				}
219 					
220 				this.form = $we.widget.add("Form", this.verifyCodeRootEl, {
221                     form_elements: formConfigs,
222                     commit: this.params.formCommit
223 				});
224 
225 				this.btnInput = this.form.getElement("send_code");
226 
227 				// 如果当前是手机的验证码,并且需要填写手机
228 				if (this.bTransVerifier && this.params.verifyName == "phone" && this.form.getElement("verifier")[0] && this.form.getElement("verifier")[0].tagName.toLowerCase() == "input") {
229 					this.bInterrupt = true;
230 
231 					$(this.btnInput).addClass(_changedBtnClass);
232 					this.form.getElement("verifier").on("blur", function(e) {
233 						if (!me.form.valid("verifier")) return;
234 						me.form.showInfo("verifier", "验证中...");
235 						$we.utils.request(_getPhoneBindedNumApi, {
236 							phone: $(this).val()
237 						}, function(data) {
238 							if (parseInt(data.data) < _maxBindedIdPerPhone) {
239 								me.form.valid("verifier");
240 								if (me.bCanGetCode) $(me.btnInput).removeClass(_changedBtnClass);
241 								me.bInterrupt = false;
242 							} else {
243 								me.form.showError("verifier", "该手机绑定的账号超过20个,请换一个手机");
244 							}
245 						}, function(data) {
246 							me.form.showError("verifier", data.msg);
247 						}, "POST", me.params.jsonp);
248 					});
249 				}
250 
251 				var restCodeTime = parseInt((+new Date - parseInt($.cookie(this.params.cookieName))) / 1000);
252 				if(restCodeTime < this.params.cooldown && this.bCanGetCode) {
253 					_countDown.call(this, this.params.cooldown - restCodeTime);
254 				}
255 			},
256 			sendCode: function() {
257 				if (this.bSendingCode || !this.bCanGetCode || this.bInterrupt) return;
258 				if(!this.verifier && !this.form.valid("verifier")) return;
259 
260 				this.bSendingCode = true;
261 
262 				this.form.clearTip("send_code");
263 				this.form.clearTip("code");
264 				$(this.btnInput).val(_sendingCodeMsg);
265 				
266 				var me = this,
267 					data = {};
268 				if (this.bTransVerifier) {
269 					// 如果验证的号码可以被写入,重新读取它的值
270 					if (this.bVerifierWritable) this.verifier = this.form.getValue("verifier");
271 					data[this.params.transName] = this.verifier;
272 				}
273 
274 				if ($we.process.getData("auth_type")) {
275 					data.auth_type = $we.process.getData("auth_type");
276 				}
277 
278 				$we.utils.request(this.params.getCodeUrl, data, function(data) {
279 					me.vcodeKey = data.data;
280 					_setCookie.call(me);
281 					me.form.showSuccess("send_code", "验证码已经发送");
282 					_countDown.call(me);
283 					me.bSendingCode = false;
284 				}, function(data) {
285 					me.form.showError("send_code", data.msg);
286 					_recoverBtnStyle.call(me);
287 					me.bSendingCode = false;
288 				}, "GET", this.params.jsonp);
289 			},
290 			getData: function() {
291 				if (!this.form.valid()) return false;
292 
293 				return {
294 					verifier: this.verifier || this.form.getValue("verifier"),
295 					code: this.form.getValue("code")
296 				};
297 			},
298 			verifyCode: function(cb) {
299 				if (this.bVerifyingCode || this.bInterrupt || !this.form.valid()) return;
300 				if (!this.vcodeKey) {
301 					this.form.showError("code", "请先发送验证码再进行操作");
302 					return;
303 				}
304 				this.bVerifyingCode = true;
305 
306 				this.code = $.trim(this.form.getValue("code"));
307 
308 				var data = {
309 					key: this.vcodeKey,
310 					vcode: this.code
311 				};
312 
313 				if (this.bTransVerifier) {
314 					// 如果验证的号码可以被写入,重新读取它的值
315 					if (this.bVerifierWritable) this.verifier = this.form.getValue("verifier");
316 					data[this.params.transName] = this.verifier;
317 				}
318 
319 				if ($we.process.getData("auth_type")) {
320 					data.auth_type = $we.process.getData("auth_type");
321 				}
322 
323 				if (this.params.extraData && typeof this.params.extraData == "object") {
324 					for (var i in this.params.extraData) {
325 						data[i] = this.params.extraData[i];
326 					}
327 				}
328 
329 				var me = this;
330 				$we.utils.request(this.params.verifyUrl, data, function(data) {
331 					/**
332 					 * 设置 verifier
333 					 */
334 					$we.process.setData(me.params.saveVerifyName, me.verifier);
335 					// 清除cookie
336 					// $.removeCookie(me.params.cookieName);
337 					cb(data.data);
338 					me.bVerifyingCode = false;
339 				}, function(data) {
340 					if (data.errno == -2011) {
341 						me.form.clear("verifier");
342 						me.form.clear("code");
343 					}
344 					me.form.showError("code", data.msg);
345 					me.bVerifyingCode = false;
346 				}, "POST", this.params.jsonp);
347 			}
348 		}
349 	});
350 
351 	return $we.widget.amd("comp.verify_code");
352 
353 });