1 if(typeof(Sucang)=='undefined') window.Sucang={};
  2 if(typeof(Sucang.page)=='undefined') Sucang.page={};
  3 if(typeof(Sucang.util)=='undefined') Sucang.util={};
  4 Ext.BLANK_IMAGE_URL='/ext/resources/images/default/s.gif';
  5 (function(){
  6 	var s=navigator.userAgent;
  7 	Sucang.isIE = s.indexOf('Trident/')>0 || s.indexOf('MSIE ')>0;
  8 	Ext.isIE9=(s.indexOf('Trident/5.0')>0);
  9 	Ext.isIE10=(s.indexOf('Trident/6.0')>0);
 10 	Ext.isIE11=(s.indexOf('Trident/7.0')>0);
 11 	Ext.isIE6=(s.indexOf('MSIE 6.0;')>0);
 12 	if(typeof(Ext.isWebkit)=='undefined')
 13 		Ext.isWebkit=(s.indexOf('AppleWebKit')>0);
 14 	if(Ext.isIE11 && !Ext.isIE) Ext.isIE = true;
 15 }());
 16 
 17 Sucang.isParent=function(p){
 18 	var ret = true;
 19 	try{
 20 		//用于检测试是否对当前窗口有权限,如果无则表示跨域执行了
 21 		var puri=p.location.protocol+'//'+p.location.host;
 22 		ret = puri==location.protocol+'//'+location.host;
 23 		
 24 	}catch(e){/*console.log('Sucang.getTopParent Error:'+e.message);*/ ret=false;}
 25 	return ret;
 26 }
 27 
 28 if(typeof(String.format)!='function'){
 29 	String.format = function(){
 30 		if(arguments.length == 0) return '';
 31 		var format = arguments[0];
 32 		var args = Array.prototype.slice.call(arguments, 1);
 33 		return format.replace(/\{(\d+)\}/g, function(m, i){
 34 			return args[i];
 35 		});
 36 	}
 37 }
 38 var __top=function(){
 39 	var w=window;
 40 	if(Sucang.page.isFrame || window.frameElement){
 41 		if(Sucang.isParent(top)) w=top;//表示顶部窗口有权限
 42 		else{//表示top非当前域,需要循环获取  //console.log('循环获取正确的top对象。。。');
 43 			var p = w;
 44 			while(Sucang.isParent(p)){w=p;p=p.parent;}//先记住p,再取p的父级对象
 45 		}
 46 	}
 47 	return w;
 48 }
 49 var __frameElement=function(win){
 50 	var fr = null;
 51 	if(!win) return fr;
 52 	try{
 53 		if(Sucang.isParent(win.parent)) fr = win.frameElement;
 54 	}catch(e){console.log('__frameElement.error:'+e.message);}
 55 	return fr;
 56 }
 57 
 58 /** 字段符两头去空格String.trim() */
 59 String.prototype.trim=function(){
 60 	return this.replace(/^\s+|\s+$/g,"");
 61 }
 62 Sucang.trim=function(s){
 63 	if(Sucang.isEmpty(s)) return '';
 64 	return s.replace(/^\s+|\s+$/g,"");
 65 }
 66 Sucang.isEmptyObject=function(d){
 67 	return $.isEmptyObject(d);
 68 }
 69 Sucang.isEmpty=function(d){
 70 	return Ext.isEmpty(d);
 71 }
 72 Sucang.apply=function(a, b){
 73 	return $.extend({}, a, b);
 74 }
 75 Sucang.value=function(val,def){
 76 	return Sucang.isEmpty(val) ? def : val;
 77 }
 78 Sucang.stripTags = function(v) {
 79 	return !v ? v : String(v).replace(/<\/?[^>]+>/gi, "");
 80 }
 81 
 82 Sucang.isChinese = function(temp){
 83     var re=/[^\u4e00-\u9fa5]/gi;
 84     if (re.test(temp)) return false ;
 85     return true ;
 86 }
 87 
 88 Sucang.stripSpecial = function(str){// 去掉转义字符
 89 	if(!str) return '';
 90 	var s = str.replace(/[\'\"\\\/\b\f\n\r\t]/g, '');// 去掉特殊字符
 91 	s = s.replace(/[\(\)\|\@\#\$\%\^\&\*\{\}\:\"\L\<\>\?]/g,'');
 92 	return s;
 93 }
 94 
 95 Sucang.ellipsis =function (value,len,suffix){
 96 	if(!value) return value;
 97 	if( typeof suffix == 'undefined') suffix = '...';
 98 	if(typeof(len) != 'number' || len<=3) return value;
 99 	var s = value.toString().trim();
100 	var buf = '';
101 	for(var i = 0,j = 0; i < s.length; i++){
102 		j += Sucang.isChinese(s.charAt(i)) ? 2 : 1;
103 		if(j > len){
104 			if(i != s.length -1) buf += suffix;
105 			return buf;
106 		}else{
107 			buf += s.charAt(i);
108 		}
109 	}
110 	//if(value && value.length>len){return value.substr(0,len-3) + "...";}
111 	return buf;
112 }
113 /** 
114  * @description 判断字符串是否以suffix为后缀
115  * @param {suffix} String
116  * @return {bl} boolean
117  */
118 String.prototype.endsWith=function(suffix){
119 	return (suffix && suffix.length<=this.length)?
120 		this.substring(this.length-suffix.length).toLowerCase()==suffix.toLowerCase():
121 		false;
122 }
123 function endsWith(s,suffix){
124 	return (s && suffix && suffix.length<=s.length)?
125 		s.substring(s.length-suffix.length).toLowerCase()==suffix.toLowerCase():
126 		false;
127 }
128 /** 
129  * @description 判断字符串是否以prefix为前缀
130  * @param {prefix} String
131  * @return {bl} boolean
132  */
133 String.prototype.startsWith=function(prefix){
134 	return (prefix && prefix.length<=this.length)?
135 		this.substr(0,prefix.length).toLowerCase()==prefix.toLowerCase():
136 		false;
137 }
138 function startsWith(s,prefix){
139 	return (s && prefix && prefix.length<=s.length)?
140 		s.substr(0,prefix.length).toLowerCase()==prefix.toLowerCase():
141 		false;
142 }
143 /** 
144  * @description 判断字符串是否是数字,
145  * @see Sucang.isNumeric(str);
146  * @return {bl} boolean
147  */
148 String.prototype.isNumeric=function(){
149 	return !/[\D]+/i.test(this.trim());
150 }
151 /** 
152  * @description 判断str字符串是否为整数
153  * @param {str} String
154  * @return {bl} boolean
155  */
156 Sucang.isNumeric=function(str){
157 	if(str==null || typeof(str)=='undefined') return false;
158 	return !/[\D]+/i.test(str.toString().trim());
159 }
160 /** @ignore */
161 var isNumeric=Sucang.isNumeric;
162 
163 /**
164  * @description 调整图片显示的大小<br>
165  * 调用方式如<img src="photo.jpg" onload="imgAdjust(this,250,250);">
166  * @param {obj} HTMLImgElement
167  * @param {width} Number 默认250
168  * @param {height} Number 默认250
169  * @param {flag} Number 如果为1表示保持比例的同时,宽度和高度总大于等于指定值
170  */
171 Sucang.imgAdjust=function(obj,w,h,n){
172 		if(obj==null || obj.width==0) return;
173         if(typeof(h)!="number")h=250;
174         if(typeof(w)!="number")w=250;
175 		var _w=0;
176 		var _h=0;
177 		if(n==1){
178         	var rate = obj.width/obj.height;
179       		if(rate<=1){//高度比宽度大
180 				_w=w;
181       			_h=Math.floor(_w/rate);
182       			if(_h<=h){
183       				_h=h;
184       				_w=Math.floor(_h*rate);
185       			}
186       		}else{
187 				_h=h;
188 				_w=Math.floor(_h*rate);
189 				if(_w<=w){
190 					_w=w;
191 					_h=Math.floor(_w/rate);
192 				}
193       		}
194       		var p=obj.parentNode;
195       		if(p){
196       			p.style.width=w+'px';
197       			p.style.height=h+'px';
198       		}
199         }else{
200         	_h=obj.height>h?h:obj.height;
201         	_w=obj.width>w?w:obj.width;
202         	var rate = obj.width/obj.height;
203         	if(w==0){
204         		_w=Math.floor(_h*rate);
205         	}else if(h==0){
206         		_h=Math.floor(_w/rate);
207         	}
208         }
209 		obj.height=_h;
210 		obj.width=_w;
211 }
212 
213 /**
214  * 判断id是否为32位的唯一标识符
215  * @param {id} String 
216  * @return boolean
217  */
218 Sucang.isGUID=function(id){
219 	if(typeof(id)=='undefined' || id==null) return false;
220 	return (id.toString().trim().length==32);
221 }
222 /** @ignore */
223 var isGUID=Sucang.isGUID;
224 
225 /**
226  * @description 将参数转换为JSON对象,如果非正确的JSON格式,则返回null
227  * @param {str} String
228  * @return Object | Array
229  */
230 Sucang.parseJSON=function(s){
231 	if(typeof(s)!='string' || s.trim().length==0) return null;
232 	var data=null;
233 	try{
234 		data = Ext.decode(s.trim());
235 	}catch(e){console.log('Sucang.parseJSON:Exception:'+e.message);if(location.href.indexOf('localhost')>0) throw e;}
236 	return data;
237 }
238 
239 /**
240  * @description 获取指定id或name的Ext对象,自动识别布局中表单字段的name前缀,为方便使用
241  * @param {name} String 自动识别布局中表单字段的name前缀,如F11name和name是相同的
242  * @return Ext.Element
243  */
244 Sucang.get=function(name){
245 	return Ext.get(Sucang.getDom(name));
246 }
247 /**
248  * @description 获取float型数值,如果无默认值为0.0
249  * @param {name} String
250  * @param {val} Number //可省略,默认为0.0
251  * @return {int}
252  */
253 Sucang.getFloat=function(d,val){
254 	if(Ext.isEmpty(val)) val=0.0;
255 	if(typeof(d)=='number') return Number(d);
256 	var n=Sucang.getValue(d);
257 	if(Ext.isEmpty(n)) n=val;
258 	else{n=parseFloat(n);if(isNaN(n)) n=val;}
259 	return Number(n);
260 }
261 /**
262  * @description 获取int型数值,如果无默认值为0
263  * @param {name} String
264  * @param {val} Number //可省略,默认为0
265  * @return {int}
266  */
267 Sucang.getInt=function(d,val){
268 	if(Ext.isEmpty(val)) val=0;
269 	if(typeof(d)=='number') return Number(d);
270 	var n=Sucang.getValue(d);
271 	if(Ext.isEmpty(n)) n=val;
272 	else{n=parseInt(n);if(isNaN(n)) n=val;}
273 	return Number(n);
274 }
275 /**
276  * @description 获取指定id或name的HTMLElementDom对象,自动识别布局中表单字段的name前缀,为方便使用
277  * @param {name} String 自动识别布局中表单字段的name前缀,如F11name和name是相同的
278  * @return HTMLElement
279  */
280 Sucang.getDom=function(name){
281 	if(Ext.isEmpty(name)) return null;
282 	if(typeof(name)=='object') return name;
283 	var d=Ext.getDom(name);
284 	if(d);
285 	else if(!Ext.isEmpty(YrwUtils.formPrefix)){d=Ext.getDom(YrwUtils.formPrefix+name);}
286 	return d;
287 }
288 /**
289  * @description 获取指定id或name的值,自动识别布局中表单字段的name前缀,为方便使用
290  * @param {name} String 自动识别布局中表单字段的name前缀,如F11name和name是相同的
291  * @return {val} String //不存在为null
292  */
293 Sucang.getValue=function(name){
294 	var d=Sucang.getDom(name);
295 	var v=null;
296 	if(d) v=d.value;
297 	else if(!Ext.isEmpty(name)){
298 		var ar=document.getElementsByName(name);
299 		for(var i=0;i<ar.length;i++){
300 			if(ar[i].type=='radio'){
301 				if(ar[i].checked){v=ar[i].value;break;}
302 			}else if(ar[i].type=='checkbox'){
303 				if(!ar[i].checked) continue;
304 				if(v==null) v=''; else v+=',';
305 				v += ar[i].value;
306 			}else if(typeof(ar[i].value)=='string'){
307 				if(v==null) v=''; else v+=',';
308 				v += ar[i].value;
309 			}
310 		}
311 	}
312 	return v;
313 }
314 /**
315  * @description 设置字段的数值到指定名称的控件中去,如果是下拉框请用Sucang.util.Selected(id,val,text) 弹出对话框用Sucang.browser.setValue(btn,[$value,$text]);
316  * @param {name} String
317  * @param {value} String
318  * @return {val} true|null 表示对象赋值成功或者对象不存在
319  */
320 Sucang.setValue=function(name,value){
321 	var d=Sucang.getDom(name);
322 	var ret=null;
323 	if(d){
324 		//var MO = window.WebKitMutationObserver || window.MutationObserver;
325 		if(d.tagName=='INPUT' || d.tagName=='TEXTAREA'){
326 			var txt=value;
327 			if(d.type=='hidden' && d.className.indexOf('scOptions')>=0){//表示只读下拉框
328 				txt = value[1];
329 				value=value[0];
330 			}
331 			d.value=value;// && Ext.isEmpty(MO)
332 			if(!Ext.isIE) d.setAttribute('value',value);//表示用于兼容低版本的FF/chrome浏览器的公式计算,使用setAttribute实现的
333 			var dSpan=Sucang.getDom(d.id+'span');
334 			if(dSpan){
335 				var _f = d.getAttribute('data-format');
336 				if(_f=='MONEY') txt = Sucang.util.money(txt);
337 				else if(_f=='RMB') txt = Sucang.formular.Rmb(txt);
338 				dSpan.innerHTML=txt;
339 			}
340 		}else if(d.tagName=='SELECT'){
341 			d.value=value;
342 			if(!Ext.isIE) d.setAttribute('value',value);
343 			if(Sucang.isMobile || Sucang.isApp) $(d).selectmenu("refresh");
344 		}else d.innerHTML=value;
345 		ret=true;
346 	}
347 	return ret;
348 }
349 
350 Sucang.gotoPage=function(oInput,url,event){
351 	if(event!=null && event.keyCode!=13) return;
352 	var val=(typeof(oInput)=='object')?oInput.value:Sucang.getValue(oInput);
353 	if(Sucang.isEmpty(val) || !isNumeric(val)){
354 		alert('输入页码不能为空或者非数字!');
355 		if(typeof(oInput)=='string') Sucang.get(oInput).focus();
356 		return;
357 	}
358 	//var objs=Ext.query("div[class=pageNav]");//这里还可以加强,变为数字增减的控件
359 	//if(objs==null || objs.length<=0 || Sucang.isEmpty(objs[0].getAttribute('info'))) return;
360 	//var pageInfo=Ext.decode(objs[0].getAttribute('info'));
361 	location.href=url+val.trim();
362 };
363 
364 	/** JS动态的加载模板数据 */
365 	/**
366 	* _callback(opt,succ,resp)
367 	*/
368 Sucang.loadView=function(tid,_paramObject,targetDiv,_callback){
369 		if(Ext.isEmpty(_paramObject))_paramObject={};
370 		if(Ext.isEmpty(tid)){alert('Layout.loadView的模板ID或者链接不能为空!');return;}
371 		if(typeof(_paramObject)!='object'){alert('Layout.loadView的参数必须为JS对象类型!');return;}
372 		var _url='/webpage.do?id='+tid;
373 		if(tid.startsWith('/')) _url=tid;
374 		var _cfg={
375 	        url: _url,
376 	        scripts: true,
377 	        text: "加载中,请稍候..."
378 		};
379 		if(!Ext.isEmpty(_paramObject)) _cfg.params=_paramObject;
380 		if(targetDiv!=null){
381 			if(typeof(_callback)=='function') _cfg.callback=_callback;//(el,isSuccess,resp,options);
382 			Ext.get(targetDiv).load(_cfg);
383 		}else{
384 			if(typeof(_callback)=='function'){
385 				_cfg.callback=_callback;
386 				Ext.Ajax.request(_cfg);
387 			}else{//如果没有回调函数,则同步请求
388 				return Sucang.util.Ajax(_cfg.url,_cfg.params,null,true);
389 			}
390 		}
391 	}; //end fun.
392 
393 /*
394  * 用于提交数据至隐藏域iframe时,网络断开或者服务器关闭时的检测提示信息
395  * @namespace
396  * @private
397  */
398 Sucang.connect={
399 objFrame:null,
400 _callback:null,
401 /* 用于监听指定$frameid的IFrame标签的连接状态 */
402 Init:function(frameid,callback){
403 	if(typeof(callback)!='function') 
404 		this._callback=function(){
405 			if(typeof(RestoreBtn)=='function') RestoreBtn();
406 			alert('网络未连接或者服务器正重启,以防提交数据丢失请不要关闭窗口或刷新页面,请联系管理员稍候再试...');
407 		};
408 	else this._callback=callback;
409 	if(Ext.isEmpty(frameid)) frameid='submitFrame';
410 	this.objFrame=Ext.getDom(frameid);
411 	if(!this.objFrame){/*alert('iframe.id='+frameid+' is null!');*/return;}
412 	//this.objFrame.src='about:blank';
413 	//console.log('Sucang.connect.inited complete.');
414 	if(Ext.isIE) Ext.get(frameid).on('readystatechange',this.FnStateChange,this);
415 },
416 FnStateChange:function(){
417 	var of=Sucang.connect.objFrame;
418 	//console.log('FnStateChange::objFrame:'+Sucang.connect.objFrame);
419 	if(Ext.isIE && of.readyState!='complete') return;
420 	//IE:Access is denied.
421 	//FF:Permission denied 
422 	var doc=null;
423 	try{
424 		doc=of.contentWindow.document;
425 	}catch(e){
426 		//console.log('FnStateChange.error:'+e.message);
427 		Sucang.connect._callback();
428 		return;
429 	}
430 	of.loopIndex+=1;
431 	if(of.loopIndex<5 && !Ext.isIE) 
432 		window.setTimeout(Sucang.connect.FnStateChange,2000);
433 },
434 /* 用于非IE浏览器的form.onsubmit提交前执行检测的初始化 */
435 submitBefore:function(){
436 	if(Ext.isIE) return;
437 	this.objFrame.loopIndex=0;
438 	this.objFrame.src='about:blank';
439 	window.setTimeout(this.FnStateChange,500);
440 }
441 };
442 
443 Sucang.util.dwrError = function(errorString, exception){
444 	if(errorString && errorString.toString().indexOf('dwr.engine._debug')>=0) return;
445 	alert(errorString+'\t远程服务器执行异常,请联系系统管理员!');
446 };
447 Sucang.util.loadError = function(){
448 	console.error('加载异常');
449 };
450 /**
451  * @description 自定义按钮的服务器端运行函数
452  * @param {id} String //自定义按钮的id
453  * @param {args} Object //参数值
454  * @param {callback} Function //如果有该参数表示异步回调,否则直接返回结果
455  **/
456 Sucang.util.executeButton = function(id,args,callback){
457 	var _ret=null;
458 	if(Ext.isEmpty(args)) args={};
459 	else if(typeof(args)=='string' || Ext.isArray(args)) args={'value':args};
460 	args=Ext.encode(args);
461 	var async = typeof(callback)=='function';
462 	if(!async) callback=function(data){_ret=data;};
463 	if(!async) dwr.engine.setAsync(false);//默认总是同步
464 	FormQueryService.runButton(id, args, callback);
465 	if(!async) dwr.engine.setAsync(true);
466 	return _ret;
467 };
468 
469 /**
470  * @description 为了模块化,使ajax也可使用,不然DWR加载不存在的模块类服务器时会异常
471  * @param {url} String //也可以为ControllName.MethodName将映射到/ControllName.do?action=json&__method=$MethodName
472  * @param {params} Object //如果为空则使用Get方式,如果有值则使用POST
473  * @param {callback} Function //调用成功后的回调函数,如果失败则直接alert错误信息.function callback(txt){ ... }
474  * @param {isSync} boolean //是否同步,如果为true则以同步方式调用,可省略
475  **/
476 Sucang.util.Ajax = function(url,params,callback,isSync){
477 	if(Ext.isEmpty(url)) return;
478 	if(url.charAt(0)!='/'){
479 		var tmps=url.split('.');
480 		url='/'+tmps[0].toLowerCase()+'.do?action=json&__method='+tmps[1];
481 	}
482 	var Ft=Ext.util.Format;
483 	if(isSync){//同步方式调用
484 		var opt={'async':false, 'url':url, 'method':'GET','cache':false,'dataTpye':'text'};
485 		opt.error=function(req,status,error) {
486 			//console.log('req.readyState :'+req.readyState +',req.status:'+req.status+',Status:'+status+",error:"+error);
487 			if(status=='error' && req.readyState==0) alert('网络未连接或者服务器正重启,请不要关闭窗口,稍会操作或联系管理员.');
488 			else if(status=='parsererror'){
489 				var txt=Ft.trim(req.responseText);
490 				if(txt.length>0) console.log('Sucang.util.Ajax::data parsererror:'+ Ft.stripTags(txt));
491 			}else if(status=='timeout') alert('连接服务器超时,请检查网络连接或联系管理员。');
492 		};
493 		if(!Ext.isEmpty(params)){
494 			opt.method = 'POST';
495 			opt.data=params;
496 		}
497 		var txt = jQuery.ajax(opt).responseText;
498 		txt=Ft.trim(txt);
499 		if(!Sucang.isMobile && txt.startsWith('<scr'+'ipt')){
500 			Sucang.util.evalScripts(txt);
501 		}else{
502 			if(typeof(callback)=='function') callback(txt);
503 		}
504 		//console.log("ajax:txt:"+txt);
505 		return txt;
506 	}else{
507 		Ext.Ajax.request({
508 		   'url':url,
509 		   'cache':false,
510 		   'success': function(resp){
511 		   	var txt = Ft.trim(resp.responseText);
512 		   	if(!Sucang.isMobile && txt.startsWith('<scr'+'ipt')){ Sucang.util.evalScripts(txt);}
513 		   	else if(typeof(callback)=='function') callback(txt);
514 		   },
515 		   'failure': function(resp){alert('Sucang.util.Ajax::Error:'+Ft.stripTags(resp.responseText));},
516 		   'params':(params==null || typeof(params)!='object')?{}:params
517 		});
518 	}
519 };
520 /**
521  * @description 用于在布局中Ajax同步方式请求获取服务器端数据
522  * @param {sqlid} String //sqlid标识符
523  * @param {params} String|Object 指定参数对象,如果只传一个参数,则Sql页面用value变量表示
524  * @param {options} Object|function(txt)回调函数,如果为空则同步执行。String类型为layoutid,Function类型为回调函数且同步调用,Object可设置参数{dsname:'数据源名称',layoutid:'布局id',callback:异步回调函数}
525  * @return {val} String 如果服务器端执行失败则返回null,如果是单行单列的则直接返回字符串,否则为JSON字符串需转译
526  */
527 Sucang.util.sql = function(id,params,options,isArray){
528 	if(Ext.isEmpty(id)) return null;
529 	var uri='/datainterfacelist.do?action=json&_type=validateajax&_n='+id;
530 	if(typeof(isArray)=='boolean' && isArray) uri += '&_result=array';
531 	var getRefid = function(){
532 		var dom = Sucang.getDom('layoutid');
533 		return dom ? dom.value : '';
534 	};
535 	var callback = null;
536 	var _refid = getRefid();
537 	if(Ext.isEmpty(options)){
538 		//如果参数为空则默认为同步且获取当前布局id
539 	}else if(typeof(options)=='string'){
540 		_refid = options;
541 		
542 	}else if(typeof(options)=='object'){//覆盖用户指定的布局id,否则为默认获取布局中的参数layoutid
543 		if(options.layoutid) _refid = options.layoutid;
544 		if(options.dsname) uri += '&_dsname='+options.dsname;
545 		if(typeof(options.callback)=='function') callback = options.callback;
546 		
547 	}else if(typeof(options)=='function'){
548 		callback = options;
549 	}
550 	if(typeof(_refid)=='string' && _refid!='none'){
551 		uri+='&_refid='+_refid;
552 	}
553 	if(callback!=null && typeof(callback)!='function'){
554 		console.log('Warn:sql(...)的options参数callback必须为function类型,已自动重置为同步执行');
555 		callback = null;
556 	}
557 	return Sucang.util.Ajax(uri,params,callback,callback==null);//callback==null为true表示同步执行,否则为异步通过callback返回内容
558 };
559 /**
560  * @description 参数同Sucang.page.sql函数,只是返回结果是数组或者为空
561  * @param {sqlid} String
562  * @param {params} String|Object 指定参数对象,如果只传一个参数,则Sql页面用value变量表示
563  * @param {callback} function(txt)回调函数,如果为空则同步执行,否则为异步调用并返回结果。
564  * @return {result} 返回的是空或数组字面量,如:[{fieldname: value}] 
565  */
566 Sucang.util.sql2 = function(sqlid,params,options){
567 	return Sucang.util.sql(sqlid, params, options,true);
568 };
569 
570 /**
571  * @description 缩放图片到指定大小并居中
572  * @param {img} HTMLImgElement 
573  * @param {width} Number 最大允许宽度
574  * @param {height} Number 最大允许高度
575  * @param {i} Number 表示是否居中显示,默认自动调整,如果为0则不调整,1只调整宽度居中,2只调整高度居中
576  */
577 Sucang.util.justCenterImage=function(ImgD,iwidth,iheight,i){
578 	//参数(图片,允许的宽度,允许的高度)
579 	//var iwidth=ImgD.width;
580 	//var iheight=ImgD.height;
581 	if(Ext.isEmpty(i)) i=3;
582 	else if(typeof(i)!='number') i=0;
583 	var image=new Image();
584 	image.src=ImgD.src;
585 	var justCenter=function(i){
586 		if((i==1 || i==3) && ImgD.width<iwidth) ImgD.hspace=Math.ceil((iwidth-ImgD.width)/2);
587 		if((i==2 || i==3) && ImgD.height<iheight) ImgD.vspace=Math.ceil((iheight-ImgD.height)/2);
588 	};
589 	if(image.width<=iwidth && image.height<=iheight){
590 		justCenter(i);
591 		return;
592 	}
593 	var rw=iwidth/image.width;
594 	var rh=iheight/image.height;
595 	if(rw<rh && image.width>iwidth){//宽度大,270*129[---205*53]
596 		ImgD.width=iwidth;
597 		ImgD.height=(image.height>iheight)?Math.ceil(rw*image.height):image.height;
598 	}else{//高度大
599 		ImgD.height=iheight;
600 		ImgD.iwidth=(image.width>iwidth)?Math.ceil(rh*image.width):image.width;
601 	}
602 	justCenter(i);
603 };
604 
605 /**
606  * 对input[type=text][event=oninput],datefield[callback],select[event=onchange],textarea[event=input]事件的监听,如果非这几种类型则无效
607  * @param {dom} HTMLElement | String
608  * @param {handler} Function //回调函数,格式为function(date,oriValue,newValue){ ... }
609  * @param {interval} int [可选] //文字输入间隔多少毫秒才触发一次
610  * @param {scope} int [可选] 
611  * @param {return} boolean 返回true表示监听成功,否则失败dom不符合类型
612  **/
613 Sucang.util.inputChange = function(dom, handler, nmm, scope){
614 	if(typeof(dom)=='string') dom = Sucang.getDom(dom);
615 	if(!dom) {console.log('argument dom is null'); return false;}
616 	if(typeof(handler)!='function'){console.log('argument handler is not function'); return false;}
617 	
618 	var names={'INPUT':'input','SELECT':'change', 'TEXTAREA':'input'};
619 	var eventName = names[dom.tagName];
620 	if(Ext.isEmpty(eventName) || dom.tagName=='INPUT' && dom.type!='text') return false;
621 	var _timer = null,_lastMill = null;
622 	var fun = function(e){
623 		var target = e.getTarget();
624 		/*
625 		if(Ext.isIE8){//IE8的特殊处理
626 			var oriE = e.browserEvent.originalEvent;
627 			console.log("orie:"+oriE+",ev---"+ oriE.propertyName +",vlaue:"+target.value+',fromJs:'+Sucang.util['__fromJs_' + target.id]);
628 			if(oriE.propertyName == 'value'){
629 				if(Sucang.util['__fromJs_' + target.id]){
630 					Sucang.util['__fromJs_' + target.id] = false;
631 					return;
632 				}
633 			}else return;
634 		}*/
635 		var curMill = new Date().getTime();
636 		var funHandler = function(){
637 			_timer = null;
638 			//var obj=Sucang.util._obsAttr[target.id];
639 			//if(obj) obj.fun(target, null, target.value);
640 			handler.call(scope||window, target, null, target.value);
641 		};
642 		var mm = Ext.value(nmm, 600);//表示文字输入间隔,这毫秒数内的事件不触发
643 		if(nmm<50 || target.tagName=='SELECT'){
644 			funHandler();
645 			return;
646 		}
647 		//console.log('last sub:::'+(curMill-target._lastMill));
648 		if(!Ext.isEmpty(_lastMill) && (curMill - _lastMill)<mm){
649 			//表示现在的时间 减去 上一次触发的时间 小于 $mm 则不需要触发
650 			if(_timer) clearTimeout(_timer);//
651 		}
652 		_lastMill = curMill;
653 		_timer = setTimeout(funHandler, mm + 10);//表示迟延触发
654 		
655 	};
656 	if(Ext.isIE8 && eventName=='input'){
657 		/*Object.defineProperty(dom, "value",{
658 			set:function(val){
659 				Sucang.util['__fromJs_' + dom.id] = true;
660 				this.setAttribute('value', val);
661 			},
662 			get:function(){
663 				var v = this.getAttribute('value');
664 				return v==null ? '' : v;
665 			}
666 		});*/
667 		eventName = 'keydown';
668 	}
669 	Ext.EventManager.on(dom, eventName, fun);
670 	
671 	return true;
672 };
673 Sucang.util._setBBoxWithValue = function(strVal){//设置单选或多选浏览框带回来的值
674 	var parse1 = function(str){
675 		if(!str) return null;
676 		var s=str.replace(new RegExp('"\\[\'(.*?)\'\\]"', 'gi'), '[\'$1\']');//*?表示最小匹配,默认为贪婪模式,只处理['xxxxx']这种模式
677 		return Sucang.parseJSON(s);
678 	}
679 	var _jsonObj={},dataObj;
680 	if(Ext.isArray(strVal)){//多选浏览框带回来的值
681 		for(var n =0;n<strVal.length;n++){
682 			dataObj = parse1(strVal[n]);
683 			if(dataObj==null) continue;
684 			for(var i in dataObj){
685 				var obj = dataObj[i];
686 				if(typeof(_jsonObj[i])=='undefined') _jsonObj[i] = obj;
687 				else if(Ext.isArray(_jsonObj[i])){
688 					var ar0 = _jsonObj[i][0],ar1 = _jsonObj[i][1];
689 					if(typeof(ar0)=='string') ar0=[ar0];
690 					if(typeof(ar1)=='string') ar1=[ar1];
691 					if(ar0.indexOf(obj[0])<0) ar0.push(obj[0]);
692 					if(ar1.indexOf(obj[1])<0) ar1.push(obj[1]);
693 					_jsonObj[i][0] = ar0;
694 					_jsonObj[i][1] = ar1;
695 				}else{
696 					if(!Ext.isEmpty(obj)) _jsonObj[i]+=","+obj;
697 				}
698 			} //end.for(dataObj)
699 		} //end.for(strVal)
700 	}else{
701 		_jsonObj = parse1(strVal);
702 	}
703 	if(Sucang.isEmptyObject(_jsonObj)) return;
704 	for(var _n in _jsonObj){
705 		var _dom=Sucang.getDom(_n);
706 		if(Ext.isEmpty(_dom))continue;
707 		if(_dom.className.indexOf('browserValue')>=0){
708 			Sucang.browser.setValue(_n, _jsonObj[_n], true);//Browser框赋值
709 		}else Sucang.setValue(_n,_jsonObj[_n]);
710 	} //for(_jsonobj)
711 };
712 Sucang.util.addRule = function(tid, rules){
713 	if(Ext.isIE8){
714 		Ext.util.CSS.createStyleSheet(rules, tid); 
715 		return;
716 	}
717 	var styleId = '#vue-styles';
718 	var el = $(styleId);
719 	if(el.length==0){
720 		var styleEl = document.createElement('style');
721         styleEl.type = 'text/css';
722         $('head')[0].appendChild(styleEl);
723         el = $(styleEl);
724         el.attr('id', styleId.substring(1));
725         //console.log('new <style>'+styleId);
726 	}
727 	var ruleid = '/*' + tid + '-rule-find*/';
728 	var findid = ruleid;
729 	var cssText = el.html();
730 	if(Ext.isIE){
731 		findid = tid + '-rule-find {';
732 		ruleid = findid + '}';
733 		cssText = el[0].sheet.cssText;
734 	}
735 	if(cssText.indexOf(findid)>=0){
736 		//console.log('css规则已经存在了');
737 		return false;
738 	}
739 	rules += ruleid;
740 	if(Ext.isIE){   //判断IE浏览器
741 		el[0].sheet.cssText += rules;
742 	}else {
743 		var frag = document.createDocumentFragment();
744 		frag.appendChild(document.createTextNode(rules));
745         el[0].appendChild(frag);
746 	}
747 	return true;
748 }
749 
750 /**
751  * @description 根据父下拉框的值从服务器获取下级下拉框列表,并赋值至subName的下拉列表中
752  * @param {obj} HTMLSelectElement 父下拉框对象
753  * @param {subName} String 子下拉框的id,如果是子列表有_allowempty="true"属性则添加空行
754  */
755 Sucang.util.getSubOption = function(obj,subName,cb){
756 	var val=null;
757 	if(typeof(obj)=='object'){
758 		var opts=obj.options,opt=null;
759 		val=obj.options[obj.selectedIndex].value;
760 	}else val=obj.toString();
761 	if(!Sucang.isGUID(val) && Sucang.isGUID(obj.getAttribute("data-fieldid"))){
762 		val = obj.getAttribute("data-fieldid")+'_'+val;
763 	}
764 	var subOpt=Sucang.getDom(subName);
765 	var mainPrefix = Sucang.getValue('_formPrefix');
766 	if(!Ext.isEmpty(mainPrefix) && !subName.startsWith(mainPrefix)){
767 		var names=Sucang.detail.getName(obj.name);
768 		if(names.rowindex >= 0){//要判断非空,否则当扩展表有下拉框时会出现异常
769 			subOpt = Sucang.getDom(names.prefix+'_'+names.rowindex+'_'+subName.substring(names.prefix.length));
770 		}
771 	}
772 	var allowEmpty=(subOpt.getAttribute('_allowempty')=='true');
773 	var subOptionId = subOpt.getAttribute('data-sub');
774 
775 	if(Ext.isEmpty(val) || val=='0'){//如果传递的父级参数值是空的,则当前也要设置为空
776 		DWRUtil.removeAllOptions(subOpt.id);
777 		if(allowEmpty) Ext.getDom(subOpt.id).appendChild(new Option(' ',''));
778 		if(subOptionId!=null) Sucang.util.getSubOption(subOpt, subOptionId, cb);
779 		return;
780 	}
781 	
782 	var valueField=subOpt.getAttribute('data-valuefield');
783 	
784 	ItemService.getItemList(val,function(list1){
785 		DWRUtil.removeAllOptions(subOpt.id);
786 		if(allowEmpty) Ext.getDom(subOpt.id).appendChild(new Option(' ',''));
787 		//Ext.DomHelper.append(subOpt.id,{tag:'option', value:'',html:' '});//IE不支持该模式 
788 		if(Ext.isEmpty(list1) || !Ext.isArray(list1) || list1.length<=0)return;
789 		var keyId=valueField;
790 		if(Ext.isEmpty(keyId)) keyId=Ext.isEmpty(list1[0].value)?'id':'value';
791 		DWRUtil.addOptions(subOpt.id,list1,keyId,'name');
792 		if(Sucang.isMobile) $(subOpt).selectmenu( "refresh", true);//如果是移动端则需要强制刷新UI
793 		if(subOptionId!=null){//如果还有动态级联,则再次触发
794 			Sucang.util.getSubOption(subOpt, subOptionId, cb);
795 		}
796 		if($.isFunction(cb)) cb(obj);
797 	});
798 };
799 
800 Sucang.util.str2mins = function(str){
801 	if(Ext.isEmpty(str) || typeof(str)!='string') return '';
802 	else str = str.trim();
803 	var lpos = str.length - 1;
804 	if(str.length>1 && str.charAt(lpos).match('[a-zA-Z]')){
805 		var flag = str.charAt(lpos);
806 		str = str.substring(0, lpos)+'*';
807 		if(flag=='y') str += '60*24*365';//年
808 		else if(flag=="M")//月为单位30天
809 			str += "60*24*30";
810 		else if(flag=="w")//周为单位7天
811 			str += "60*24*7";
812 		else if(flag=="d")//天为单位
813 			str += "60*24";
814 		else if(flag=="h")//小时为单位
815 			str += "60";
816 		else str += "1";//其他的默认为分钟
817 	}
818 	//console.log('str:----'+str);
819 	var fun = new Function("return " + str);
820 	return fun();
821 };
822 
823 Sucang.switchUser=function(userName){
824 	var _errMsg = ['','Licence非法或过期请联系管理员!','帐号不存在或被冻结注销!','密码错误(或大写锁定,区分大小写)!','','验证码错误!'];
825 	if(!confirm('是否确定切换帐号(Y/N)?'))return;
826 	__top().onbeforeunload=null;//清除main.do的退出提示
827 	$.ajax({
828 	   url: '/login.do?action=login&isAjax=true&allowSwitchUser=true',
829 	   success: function(result,status,xhr){
830 		  var obj=Sucang.parseJSON(result);
831 		  if(obj==null){
832 		  	console.log('Response error:'+result);
833 		  	return;
834 		  }
835 		  if(obj.errNum>=0){
836 		  	__top().location.href = Sucang.isMobile ? '/index/' : '/main.do';
837 		  }else alert(_errMsg[Math.abs(obj.errNum)]);
838 	   },
839 	   method:'POST',
840 	   error: function(xhr,status,error){
841 	   		alert('Login Error:' + error);
842 	   },
843 	   data: {'username':userName}
844 	});
845 }
846 
847 
848 /** 编号相关的初始化和操作 */
849 Sucang.number={
850 _numbers:{},
851 /**
852  * @description 自动生成唯一编号
853  * @param {fieldName} String 指向保存编号的Input.name属性,在布局中不能包含字段前缀。如:num1,而不能F45num1
854  * @param {eType} Number
855  * @param {callback} Function 生成完成后回调,function callback(num){...}
856  */
857 generateNumber:function(name,eType,_callback){
858 	if(typeof(eType)=='undefined') eType=0;
859 	if(eType>1)return;//如果非创建时不生成编号,这里会多次调用为防止并发时生成重复的编号
860 	var nid=Sucang.number._numbers[name].id;
861 	var fields=Sucang.number._numbers[name].args;
862 	var data={};
863 	if(!Ext.isEmpty(fields)){
864 		var ar0=fields.split(',');
865 		for(var i=0;i<ar0.length;i++) data[ar0[i]] = Sucang.getValue(ar0[i]);
866 	}
867 	var num='';
868 	dwr.engine.setAsync(false);//改成同步执行
869 	NumberRuleService.generateNumber2(nid,Ext.encode(data),function(val){
870 		var obj=Ext.decode(val);
871 		if(!Ext.isEmpty(obj.msg)) alert(obj.msg);
872 		num=obj.value;
873 	});
874 
875 	dwr.engine.setAsync(true);//改回异步执行
876 	var target = Ext.getDom(name);
877 	Sucang.setValue(target, num);
878 	if(Ext.isEmpty(_callback)){
879 		var fun = target.getAttribute('data-calback');
880 		if(!Ext.isEmpty(fun)) _callback = new Function("val", "return "+fun+"(val);");
881 	}
882 	if(typeof(_callback)=='function') _callback(num, target);
883 },
884 /**
885  * @description //检查编号的唯一性
886  * @return {ret} boolean
887  */
888 checkNumberUnique:function(){
889 	var ret=true;
890 	var $this = Sucang.number;
891 	for(var name in $this._numbers){
892 		var val=Sucang.getValue(name);
893 		var nid=$this._numbers[name].id;
894 		dwr.engine.setAsync(false);//改成同步执行
895 		NumberRuleService.checkNumberUnique(nid,val,function(d){
896 			if(d<0){alert('编号数据不完整!');ret=false;}
897 			if(d>0){
898 				if(confirm('编号'+val+'已存在是否重新获取(Y/N)?'))
899 				$this.generateNumber(name,1);else ret=false;
900 			}
901 		});
902 		dwr.engine.setAsync(true);//改回异步执行
903 		if(!ret)break;
904 	}
905 	return ret;
906 },
907 /**
908  *  初始化格式为:Sucang.number._numbers['F98num0'] = {id:'4028818a3ea2d695013ea332bf470007',args:'sel0,box0'};
909  *  
910  **/
911 initNumbers:function(eType,id){//eType=0,表示之前的,1表示创建时即将保存时的校验,2表示更新时即将保存时的校验
912 	$this = Sucang.number;
913 	if(typeof(id)!='undefined'){
914 		$this.generateNumber(''+id,eType);
915 		return;
916 	}
917 
918 	for(var name in $this._numbers){
919 		var dom1=Ext.getDom(name);
920 		if(dom1==null || (eType==0 && !Ext.isEmpty(dom1.value))) continue;//如果是初始化且已经有编号数据了表示更新数据时不生成编号
921 		$this.generateNumber(name,eType);
922 		var strArg=$this._numbers[name].args;
923 		if(typeof(strArg)=='string' && !Ext.isEmpty(strArg)){
924 			var ar=strArg.split(',');
925 			var fun=function(e,odate){
926 				var o = typeof(e.browserEvent)=='object'?e.getTarget():e;
927 				if(typeof(o)=='string' && odate && odate.className.indexOf('datefield')>=0) o = odate;//为了兼容日期回调函数的参数兼容
928 				$this.generateNumber(o.getAttribute('data-number-target'));
929 			};
930 			for(var i = 0;i < ar.length; i++){
931 				var dom = Sucang.getDom(ar[i]);
932 				if(dom==null){console.log('编号所需要的字段:'+ar[i]+'在字段中不存在.');continue;}
933 				dom.setAttribute('data-number-target', name);
934 				if(dom.tagName == 'SELECT'){
935 					Ext.EventManager.on(dom, 'change', fun);
936 				}else if(dom.tagName == 'INPUT'){
937 					var _type = dom.type.toLowerCase();
938 					if(_type == 'hidden' || _type == 'text' && dom.className.indexOf('datefield')>=0) Sucang.util.watch(dom,'value',fun);
939 				}
940 			} //end.for(ar)
941 		} //end.if(strArg)
942 	} //end.for($this._numbers)
943 }, //end.function::initNumbers
944 _init: function(){
945 	var d=Ext.getDom('__isEdit');
946 	if(d && d.value=='true'){//初始化编号数据
947 		var ar=Ext.query('input[class*=numberfield]');
948 		var nid=null;
949 		for(var i=0;i<ar.length;i++){
950 			nid=ar[i].getAttribute('data-numberid');
951 			if(Ext.isEmpty(nid)) continue;
952 			Sucang.number._numbers[ar[i].id]={'id':nid,'args':ar[i].getAttribute('data-number-args')};
953 		}
954 		if(ar.length>0) Sucang.number.initNumbers(0);//初始化编号
955 	}
956 
957 }
958 };
959 
960 (function(){
961     /*
962      * 判断obj是否为一个整数
963      */
964     function isInteger(obj) {
965         return Math.floor(obj) === obj
966     }
967     
968     /*
969      * 将一个浮点数转成整数,返回整数和倍数。如 3.14 >> 314,倍数是 100
970      * @param floatNum {number} 小数
971      * @return {object}
972      *   {times:100, num: 314}
973      */
974     function toInteger(floatNum) {
975         var ret = {times: 1, num: 0}
976         if (isInteger(floatNum)) {
977             ret.num = floatNum
978             return ret
979         }
980         var strfi  = floatNum + ''
981         var dotPos = strfi.indexOf('.')
982         var len    = strfi.substr(dotPos+1).length
983         var times  = Math.pow(10, len)
984         var intNum = parseInt(floatNum * times + 0.5, 10)
985         ret.times  = times
986         ret.num    = intNum
987         return ret
988     }
989     
990     /*
991      * 核心方法,实现加减乘除运算,确保不丢失精度
992      * 思路:把小数放大为整数(乘),进行算术运算,再缩小为小数(除)
993      *
994      * @param a {number} 运算数1
995      * @param b {number} 运算数2
996      * @param digits {number} 精度,保留的小数点数,比如 2, 即保留为两位小数
997      * @param op {string} 运算类型,有加减乘除(add/subtract/multiply/divide)
998      *
999      */
1000     function operation(a, b, digits, op) {
1001         var o1 = toInteger(a)
1002         var o2 = toInteger(b)
1003         var n1 = o1.num
1004         var n2 = o2.num
1005         var t1 = o1.times
1006         var t2 = o2.times
1007         var max = t1 > t2 ? t1 : t2;
1008         var result = null
1009         switch (op) {
1010             case 'add':
1011                 if (t1 === t2) { // 两个小数位数相同
1012                     result = n1 + n2
1013                 } else if (t1 > t2) { // o1 小数位 大于 o2
1014                     result = n1 + n2 * (t1 / t2)
1015                 } else { // o1 小数位 小于 o2
1016                     result = n1 * (t2 / t1) + n2
1017                 }
1018                 result = result / max;
1019             break;
1020             case 'subtract':
1021                 if (t1 === t2) {
1022                     result = n1 - n2
1023                 } else if (t1 > t2) {
1024                     result = n1 - n2 * (t1 / t2)
1025                 } else {
1026                     result = n1 * (t2 / t1) - n2
1027                 }
1028                 result = result / max;
1029             break;
1030             case 'multiply':
1031                 result = (n1 * n2) / (t1 * t2);
1032             break;
1033             case 'divide':
1034                 result = (n1 / n2) * (t2 / t1);
1035             break;
1036             	console.log('Number.operation 非法操作'+op);
1037                 
1038         }
1039         if(isNaN(result)){
1040         	result = 0;
1041         	console.log("Number.operation: result is NaN." + a + ' '+ op + ' ' + b + ' = NaN');
1042     	}
1043         return Number(result)
1044     }
1045     function getPrecision(d){
1046     	var digits = 2;//默认精度
1047     	if(typeof(d)=='number' && d>0) digits = d;
1048     	return digits;
1049     }
1050     // 加减乘除的四个接口
1051     Number.prototype.add = function(b,digits){
1052 		return operation(this, b, getPrecision(digits), 'add');
1053     }
1054     Number.prototype.sub = function(b, digits) {
1055         return operation(this, b, getPrecision(digits), 'subtract');
1056     }
1057     Number.prototype.mul = function(b, digits) {
1058     	return operation(this, b, getPrecision(digits), 'multiply');
1059     }
1060     Number.prototype.div = function(b, digits) {
1061         return operation(this, b, digits, 'divide');
1062     }
1063     
1064 
1065 }());
1066 
1067 Sucang._genTodoIcon = function(v, m, r, ts, nodeTOpt){//生成待办事项前的图标显示HTML
1068 	ts = parseInt(ts); //"{s:sysValue('RequestTodoIconStatus')}  1-back, 2-timeout, 3-back&&timeout
1069 	if(isNaN(ts)) ts = 0;
1070 	if(ts<=0 || ts>3) return '';
1071 	var style = '';
1072 	var title = '';
1073 	if((ts==1 || ts==3) && r.get('backStep')){
1074 		var ar = nodeTOpt.back.split('|');
1075 		style = ' border:3px solid ' + Ext.value(ar[1], '#368DD9') + ';';
1076 		title = '退回';
1077 	}
1078 	if(ts==2 || ts==3){
1079 		var mins = r.get('elapsedTime');
1080 		var keys = [];
1081 		for(var i in nodeTOpt){
1082 			if(i.trim().length==0 || i=='back') continue;
1083 			keys = [i].concat(keys);
1084 		}
1085 		for(var i = 0;i < keys.length; i++){
1086 			var t1 = Sucang.util.str2mins(keys[i]);
1087 			//console.log(t1,mins);
1088 			if(mins > t1){
1089 				var ar = nodeTOpt[keys[i]].split('|');
1090 				if(title.length > 0) title += '且';
1091 				title += ar[0];
1092 				style += ' background-color: ' + Ext.value(ar[1], 'red') + ';';
1093 				break;
1094 			}
1095 		}
1096 	}
1097 	return '<span class="dotstyle" title="' + title + '的流程" style="' + style + '"></span>';
1098 }