首页 > 代码库 > 如何用easyui+JAVA 实现动态拼凑datagrid表格(续)
如何用easyui+JAVA 实现动态拼凑datagrid表格(续)
前面一段时间写了一篇文章:
如何用easyui+JAVA 实现动态拼凑datagrid表格
这篇文章的话,效果是可以实现,但是经过我反复试验,还是存在一些问题的。
今天这篇文章就是向大家介绍下如何避免和解决这些问题。
问题如下:
这个TEMP值其实就是上面文章提到的z1,z2,z3,z4的值,也就是说,每次进行each循环,都会查出不同的值,并返回,但是事实并不是这样的
这个TEMP返回的是EACH循环以后的最后一次的值。
记住,EACH循环本身就是一个封闭的,不会循环一次返回一个值,而是让前面的值被后面的值覆盖掉了!,所以查出来的结果都一样了,怎么样避免这种情况的发生呢?
我先放出整个代码块,然后我们再一步一步分析并解决问题。
1 using("sable.easyui"); 2 3 var gv=$("#dg"); 4 var today=new Date(); 5 6 //动态生成列 7 var dynamicCols=[]; 8 var dynamicItems=[]; 9 var dynamicItemsAfter=[]; 10 var dynamicItemsEnd=[]; 11 12 //设置时间 13 function GetDateStr(AddDayCount) { 14 var dd = new Date(); 15 dd.setDate(dd.getDate()+AddDayCount);//获取AddDayCount天后的日期 16 var y = dd.getFullYear(); 17 var m = dd.getMonth()+1;//获取当前月份的日期 18 var d = dd.getDate(); 19 return y+"-"+m+"-"+d; 20 } 21 22 //以开始时间为基准设置时间 23 24 function GetDateStrA(AddDayCount) { 25 26 //得到开始时间 27 28 var dd = new Date($("#StartTime").datebox(‘getValue‘)); 29 dd.setDate(dd.getDate()+AddDayCount);//获取AddDayCount天后的日期 30 var y = dd.getFullYear(); 31 var m = dd.getMonth()+1;//获取当前月份的日期 32 var d = dd.getDate(); 33 return y+"-"+m+"-"+d; 34 } 35 36 $(function(){ 37 $("#StartTime").datebox(‘setValue‘,GetDateStr(-1)); 38 $("#EndTime").datebox(‘setValue‘,GetDateStr(0)); 39 40 //绑定空数据 41 gv.datagrid( "dataBind" , 42 { 43 autoHeight : 46 , 44 datas : [], 45 striped:true, 46 pagination : true, 47 autoRowHeight:false 48 49 }); 50 //绑定空列 51 gv.datagrid({ 52 columns:[[ 53 {title:‘时间‘,width:150,sortable:true}, 54 {title:‘站点1‘,width:150,sortable:true}, 55 {title:‘站点2‘,width:150,sortable:true}, 56 {title:‘站点3‘,width:500,sortable:true}, 57 ]] 58 59 }); 60 61 }); 62 63 //列元素(动态) 64 //序号 65 var stcd={ 66 field: ‘Stcd‘, 67 title: ‘序号‘, 68 // width: 150, 69 rowspan:3, 70 sortable:true 71 } 72 73 //站名 74 var stnm={ 75 field: ‘Stnm‘, 76 title: ‘站名‘, 77 // width: 150, 78 rowspan:3, 79 sortable:true 80 } 81 82 83 84 85 86 //平均值 87 var avg={ 88 title:‘平均值‘, 89 //width:500, 90 colspan:2 91 } 92 93 //库水位 94 var rz={ 95 title:‘库水位‘, 96 //width:150 /*PS:动态列中不适宜固定宽度,其他同样的*/ 97 } 98 99 //库容100 var rv={101 title:‘库容‘,102 width:150103 }104 105 106 //查询按钮107 $("#btnSearch").click(function(){108 109 110 //得到开始日期和结束日期之间的天数之差111 var ipt1=$("#StartTime").datebox(‘getValue‘);112 var ipt2=$("#EndTime").datebox(‘getValue‘);113 114 var arr1 = ipt1.split("-"); 115 var arr2 = ipt2.split("-"); 116 117 var dt1 = new Date(); 118 dt1.setFullYear(arr1[0]); 119 dt1.setMonth(arr1[1] - 1); 120 dt1.setDate(arr1[2]); 121 var dt2 = new Date(); 122 dt2.setFullYear(arr2[0]); 123 dt2.setMonth(arr2[1] - 1); 124 dt2.setDate(arr2[2]); 125 var dif = dt2.getTime() - dt1.getTime(); 126 var days = dif / (24 * 60 * 60 * 1000); 127 128 129 130 //再次初始化,避免数组的堆积131 dynamicCols=[];132 dynamicItems=[];133 dynamicItemsAfter=[];134 dynamicItemsEnd=[];135 136 137 //前部138 dynamicItems.push(stcd);139 dynamicItems.push(stnm);140 141 //查询条件数据142 var datas={143 "Stcd":$("#stnmCombo").combobox(‘getValue‘),144 "StartTime":$("#StartTime").datebox(‘getValue‘),145 "EndTime":$("#EndTime").datebox(‘getValue‘) 146 }147 //查询具体的数据148 formLoader.load("querydata",datas,function(s){149 150 //空白SPAN151 var blank={152 title:‘ ‘,153 colspan:days*2+4 //动态得到COLSPAN的跨度,根据天数154 155 }156 dynamicItems.push(blank);157 158 //动态载入库水位数据159 160 161 162 163 164 //创建一个新的存储MAP中的键的东西(表头Field) -水位165 var index=[];166 $.each(s[0].DynamicList, function(i,option){167 index.push(i);168 169 });170 171 //创建一个新的存储MAP中的键的东西(表头Field) -流量172 var indexQ=[];173 $.each(s[0].DynamicListQ, function(i,option){174 indexQ.push(i);175 176 });177 178 179 180 181 //拼凑表头182 $.each(s[0].DynamicList, function(i,option){183 184 185 //详细数据186 var k=0; //设定一个值,匹配Z0,Z1,Z2。。。。。187 188 var d = new Date($("#StartTime").datebox(‘getValue‘));189 do{190 //alert(i.substring(1));191 d.setDate(d.getDate()+(parseInt(i.substring(1)))/2); //转换成INT类型的192 193 var RealDate=d.getFullYear()+"-"+(d.getMonth()+1)+"-"+d.getDate(); //动态得到日期值194 195 var details2={196 title:RealDate,197 // width:150,198 colspan:2199 200 }201 202 dynamicItemsAfter.push(details2);203 k+=2;204 break; //这里因为会执行i此结果 ,所以 BREAK掉205 }while(days>k)206 207 });208 209 //把水位和流量合并成一个对象210 var extend=function(o,n,override){211 for(var p in n)212 {213 //alert(n[p]);214 215 if(n.hasOwnProperty(p) && (!o.hasOwnProperty(p) || override))216 {217 218 o[p]=n[p]; 219 }220 221 }222 223 };224 extend(s[0].DynamicList,s[0].DynamicListQ);225 226 //表头排序227 /*表头排序的作用是将2个不相干的MAP组合到一起,然后按照第二个数字的大小进行冒泡排序*/228 var aa=Object.keys(s[0].DynamicList);229 var bb=[];230 231 // for(var j=0;j<aa.length;j++)232 // {233 // var temp;234 //235 // if(j+1==aa.length)236 // {237 // break;238 // }239 // 240 //// alert(aa[j]);241 //// alert(aa[j+1]);242 // 243 // if(Number(aa[j].substring(1))>Number(aa[j+1].substring(1)))244 // {245 //246 // temp=aa[j];247 // aa[j]=aa[j+1];248 // aa[j+1]=temp;249 // }250 // 251 //252 // }253 254 //进行排序,因为是从第二个字母开始比较大小的,所以截取字符串长度255 aa.sort(function(a,b){return Number(a.substring(1))>Number(b.substring(1))?1:-1});256 //alert(aa);257 //alert(aa);258 //alert(aa.sortable());259 //再次PUSH表头列260 var indexAll=[];261 $.each(s[0].DynamicList, function(i,option){262 indexAll.push(i);263 });264 265 266 //alert(aa);267 //alert(Object.Keys());268 var z=Object.keys(s[0].DynamicList);269 var q=Object.keys(s[0].DynamicListQ);270 271 //这里的s指的是下标0,1,2,3,m指的是对应的z0,q1,z2,q3等等272 $(aa).each(function(s,m){273 274 for(var j=0;j<index.length;j++)275 {276 // if(j<z.length)277 // {278 if(m==index[j])279 {280 //alert(index[j]);281 var mk=index[j]; 282 283 //库水位284 rz={285 title:‘水位‘,286 field:"DynamicList"+mk, //切记,这里的field不能相同,每次循环都需要创建一个新的FIELD287 formatter:function(value,row,index){288 //alert(row);289 //return value.z1; //因为这是一个对象DynamicList,所以返回对象的值290 //alert(value);291 292 293 var temp=[];294 295 var count=0;296 var final;297 $.each(row.DynamicList,function(i,option){298 299 temp[i]=bibao(option);300 301 302 });303 304 //alert(temp["z0"]());305 return temp[mk]();306 //return temp;307 } 308 }309 dynamicItemsEnd.push(rz);310 }311 if(m==indexQ[j])312 {313 314 315 var mk2=indexQ[j];316 317 //流量(动态值)318 rv={319 title:‘流量‘,320 field:"DynamicListQ"+mk2,321 formatter:function(value,row,index)322 {323 var temp2=[];324 $.each(row.DynamicListQ,function(i,option){325 //alert(option);326 327 temp2[i]=bibao(option); //闭包法则328 329 });330 //alert(temp2[mk2]());331 return temp2[mk2]();332 } 333 }334 dynamicItemsEnd.push(rv);335 }336 337 338 339 340 }341 342 });343 344 345 346 //库水位(平均)347 var rzAvg={348 title:‘水位‘,349 field:"AvgRz"}350 351 //流量(平均)352 var rvAvg={353 title:‘流量‘,354 field:"AvgQ",355 //width:500356 formatter:function(value,row,index)357 {358 if(valuehttp://www.mamicode.com/=="NaN")359 {360 return "-";361 }362 else363 {364 return value;365 }366 }367 }368 369 dynamicItemsAfter.push(avg);370 dynamicItemsEnd.push(rzAvg);371 dynamicItemsEnd.push(rvAvg);372 373 dynamicCols.push(dynamicItems);374 dynamicCols.push(dynamicItemsAfter);375 dynamicCols.push(dynamicItemsEnd);376 377 //绑定动态列378 gv.datagrid({379 columns:dynamicCols,380 381 }); 382 383 //获取动态表头384 var opts = $(‘#dg‘).datagrid(‘getColumnFields‘);385 colName_=[]; //全局变量386 387 var count=0.5; 388 var r = /^[-+]?\d*$/; //判断是否为整数389 390 for(i=0;i<opts.length;i++)391 {392 393 394 var col = $(‘#dg‘).datagrid( "getColumnOption" , opts[i] );395 396 var title=col.title;397 398 if(i>=2)399 {400 //奇数列必须和偶数列的值相同,也就是说水位和库容值相同。比如1月水位,1月库容,2月水位,2月库容。401 //如果i的值为奇数的话,那么比如使奇数列的值和上一个偶数列的值相同,也就是减一。402 //每次增量改为0.5,也就是2分之一,可以有效避免数字退后。403 //因为是从0开始计算的,所以下面的并不是i-3和i-4而是i-2,i-3404 405 406 //偶数列407 if(r.test(count)==true)408 {409 if((i-2)%2==0)410 { 411 412 title=col.title+"("+GetDateStrA(i-1-count)+")";413 414 }415 else if((i-2)%2!=0)416 {417 title=col.title+"("+GetDateStrA(i-2-count)+")";418 419 }420 }421 //奇数列422 else423 {424 if((i-2)%2==0)425 { 426 427 title=col.title+"("+GetDateStrA(i-1-count-0.5)+")";428 429 }430 else if((i-2)%2!=0)431 {432 title=col.title+"("+GetDateStrA(i-2-count-0.5)+")";433 434 } 435 436 }437 438 count+=0.5;439 //最后一列算作平均值,不参与计算440 if(i==opts.length-2||i==opts.length-1)441 {442 title=col.title+"(平均值)";443 }444 445 }446 447 colName_.push(title);448 }449 450 gv.datagrid( "dataBind" ,451 {452 datas : s,453 striped:true,454 pagination : true,455 pageSize:15456 457 });458 459 460 461 });462 463 //重置大小,动态重置464 if(days>11)465 {466 var realwidth=1700+125*(days-11)467 gv.datagrid("resize",{width:realwidth});468 }469 else470 {471 gv.datagrid("resize",{width:1360});472 }473 474 475 });476 477 //导出excel478 $("#export").click(function(){479 480 var url= colName_;481 location.href = http://www.mamicode.com/context.RootPath + context.ControllerPath +"/exportexcel?StartTime="+$("#StartTime").datebox(‘getValue‘)+"&EndTime="+$("#EndTime").datebox(‘getValue‘)+"&Stcd="+$("#stnmCombo").combobox(‘getValue‘)+"&ColName="+encodeURI(encodeURI(url));482 483 });484 485 486 //得到测站编码487 var dataCount=0;488 formLoader.load("getstnm","",function(data){489 490 data.unshift({Stnm : "全部" , Stcd : "" });491 $("#stnmCombo").combobox({492 data:data,493 valueField:"Stcd",494 textField:"Stnm",495 editable:false,496 //panelHeight:"auto",497 498 onl oadSuccess:function()499 {500 //alert(‘1‘);501 //alert(data[0].Stcd);502 $("#stnmCombo").combobox(‘setValue‘,data[0].Stcd);503 dataCount=data.length;504 505 },506 onShowPanel:function()507 {508 if(dataCount.length>10)509 {510 $(this).combobox(‘panel‘).height(251);511 512 } 513 514 }515 });516 });517 518 //闭包效应519 function bibao(a){520 return function (){521 return a;522 }523 }
上面的是整个JS代码块,大家看得可能有点头晕,我们下面就来一步一步分析。
先放张效果图吧。
上面的是正确的结果,每一天的值都是不同的。
我们在解决这个值的显示问题的时候还要明白一个隐含的问题:每一天不止有水位,还有库容。
水位和库容在Json对象里面都是按照z0,z1,z2...q0,q1,q2这样的键值对的形式存在的,其中z开头的为水位,q开头的为库容。
我这里拿的是另一个JS跟你们讲解的,其实都一样啦,大家明白原理就行了。
//创建一个新的存储MAP中的键的东西(表头Field) -水位 var index=[]; $.each(s[0].DynamicList, function(i,option){ index.push(i); }); //创建一个新的存储MAP中的键的东西(表头Field) -流量 var indexQ=[]; $.each(s[0].DynamicListQ, function(i,option){ indexQ.push(i); });
上面的代码其实是得到水位或者流量的index,即键值对中的键,然后把这些键存到2个数组里面去。
下面的代码是单独进行表头的拼接,唯一需要注意的是,一个日期跨度为2列,包括了水位和库容。
//拼凑表头 $.each(s[0].DynamicList, function(i,option){ //详细数据 var k=0; //设定一个值,匹配Z0,Z1,Z2。。。。。 var d = new Date($("#StartTime").datebox(‘getValue‘)); do{ //alert(i.substring(1)); d.setDate(d.getDate()+(parseInt(i.substring(1)))/2); //转换成INT类型的 var RealDate=d.getFullYear()+"-"+(d.getMonth()+1)+"-"+d.getDate(); //动态得到日期值 var details2={ title:RealDate, // width:150, colspan:2 } dynamicItemsAfter.push(details2); k+=2; break; //这里因为会执行i此结果 ,所以 BREAK掉 }while(days>k) });
因为后面要循环PUSH,把水位或者流量给PUSH到数组里面去,然后显示动态列,所以,这里我们合并一下2个动态列
//把水位和流量合并成一个对象 var extend=function(o,n,override){ for(var p in n) { //alert(n[p]); if(n.hasOwnProperty(p) && (!o.hasOwnProperty(p) || override)) { o[p]=n[p]; } } }; extend(s[0].DynamicList,s[0].DynamicListQ);
这里用到了原生态的EXTEND方法去合并。
现在就变成了z0~zn,q0~qn
这显然不是我们想要的结果,因为正确的顺序其实是z0,q0,z1,q1,那么这里我们就需要进行排序
aa.sort(function(a,b){return Number(a.substring(1))>Number(b.substring(1))?1:-1});
排序完了,一半的工作就进行完了。
这里还用到了闭包,就是在EACH外面访问EACH里面的返回值。
具体代码如下:
//闭包效应function bibao(a){ return function (){ return a; }}
既然排序已经完成了,我们就可以一路下来放心的EACH了。
下面的代码用到了另一种EACH,其中参数m为z0,q0,z1,q1这些键。
唯一需要注意的是,每次的FIELD都是不同的,因为FIELD有唯一性。
在每次formatter里面的值是从row.对象 里面取出来的哦,这点要注意。
//这里的s指的是下标0,1,2,3,m指的是对应的z0,q1,z2,q3等等 $(aa).each(function(s,m){ for(var j=0;j<index.length;j++) {// if(j<z.length)// { if(m==index[j]) { //alert(index[j]); var mk=index[j]; //库水位 rz={ title:‘水位‘, field:"DynamicList"+mk, //切记,这里的field不能相同,每次循环都需要创建一个新的FIELD formatter:function(value,row,index){ //alert(row); //return value.z1; //因为这是一个对象DynamicList,所以返回对象的值 //alert(value); var temp=[]; var count=0; var final; $.each(row.DynamicList,function(i,option){ temp[i]=bibao(option); }); //alert(temp["z0"]()); return temp[mk](); //return temp; } } dynamicItemsEnd.push(rz); } if(m==indexQ[j]) { var mk2=indexQ[j]; //流量(动态值) rv={ title:‘流量‘, field:"DynamicListQ"+mk2, formatter:function(value,row,index) { var temp2=[]; $.each(row.DynamicListQ,function(i,option){ //alert(option); temp2[i]=bibao(option); //闭包法则 }); //alert(temp2[mk2]()); return temp2[mk2](); } } dynamicItemsEnd.push(rv); } } });
下面再个大家放一个小小的福利,就是如何做多级菜单,我这里只做到了3级,这个多级菜单的话,其实大家并不陌生,关键是我这个多级菜单是专门为公司做的,
也就是说有些方法在网上很难找到答案。
废话不多,开搞。
1 $.each(model.NavigateData,function(index,value) 2 { 3 if( $.trim(value.Text) =="浏阳山洪灾害预警系统") 4 { 5 mainid = value.Value; 6 $(‘.main_head_left‘).css(‘background-image‘,‘url( ../interface/view/default/core/public/skin/default/images/core_index_main/logo.jpg)‘); 7 $(‘.logo2‘).css(‘left‘,‘660px‘); 8 menulist.push(mainid); 9 } 10 }); 11 //一级菜单 12 $.each(model.NavigateData,function(index,value) 13 { 14 if( $.trim(value.ParentValue) == mainid) 15 { 16 var vl = value.Value; 17 //mainmenu = mainmenu + "<td><a href=http://www.mamicode.com/‘#‘ class=‘mymenu‘ id=‘menu"+k+"‘ name=‘"+value.Value+"‘>"+value.Text+"</a> </td>"; 18 mainmenu = mainmenu + "<li><a href=http://www.mamicode.com/‘#‘ id=‘menu"+k+"‘ name=‘"+value.Value+"‘>"+value.Text+"</a></li>"; 19 concatDiv(vl,k); 20 k++; 21 menulist.push(vl); 22 } 23 }); 24 //添加主菜单 25 $(‘#tbmenu‘).append(mainmenu); 26 //二级菜单 27 function concatDiv(vl,k) 28 { 29 var count=0; 30 var divStr = "<div id=‘mm"+k+"‘ style=‘width:140px;‘>"; 31 $.each(model.NavigateData,function(index,value) 32 { 33 var vl2=value.Value; 34 if(value.ParentValue =http://www.mamicode.com/= vl) 35 { 36 //alert(vl); 37 //menulist.push(value.Value); 38 var link = value.Link; 39 divStr = divStr + "<div id=‘"+link+"‘ name=‘"+value.Value+"‘ onclick=‘setUrl(this);‘>"+"<span>"+value.Text+"</span>"; 40 41 42 43 //添加三级菜单,原理就是先找出对应的二级菜单,然后再进行遍历 44 //divStr+="<div>"; 45 //tempMenu(value.Value,k); 46 //把子菜单PUSH到数组里去 47 //SAME数组用来存放有三级菜单父级ID的数组。 48 var s=[]; 49 var same=[]; 50 $.each(model.NavigateData,function(index,value){ 51 var vl=value.Value; 52 var vlparent=value.ParentValue; 53 var link =value.Link; 54 55 if(vlparent==vl2) 56 { 57 //alert("parent:"+vlparent+",vl2:"+vl2); 58 59 //alert(value.Value); 60 61 var div=$("div[name=‘"+vlparent+"‘] .menu-text"); 62 var divSub=$("div[name=‘"+vl+"‘]"); 63 //divStr = divStr + "<div id=‘"+link+"‘ name=‘"+value.Value+"‘ onclick=‘setUrl(this);‘>"+"<span>"+value.Text+"</div>"; 64 s.push("<div id=‘"+link+"‘ name=‘"+value.Value+"‘ onclick=‘setUrl(this);‘>"+"<span>"+value.Text+"</div>"); 65 same.push(vlparent); 66 //divStr+="<div><div>1</div><div>2</div></div>"; 67 //divStr+=divStrSub; 68 69 } 70 71 72 }); 73 74 //去除相同的元素 75 76 function unique(array) { 77 var ret = [], record = {},it,tmp,obj = "__object__", bak = [],i,len; 78 var type ={ 79 "number": function(n) { return "__number__" + n; }, 80 "string": function(n) { return "__string__" + n; }, 81 "boolean": function(n) { return "__boolean__" + n; }, 82 "undefined": function(n) { return "__undefined__"; }, 83 "object": function(n) { 84 return n === null ? "__null__" : obj in n ? n[obj] : ( n[obj] = obj + bak.push(n) ); 85 } 86 }; 87 for (i = 0, len = array.length; i < len; i++) { 88 it = array[i]; tmp = type[typeof it](it); 89 if (!(tmp in record)) { ret.push(it); record[tmp] = true; } 90 } 91 for (i = 0, len = bak.length; i < len; delete bak[i++][obj]) { } 92 return ret; 93 }; 94 var uniq=unique(same); 95 96 //判断是否为3级菜单的元素 97 $.each(model.NavigateData,function(index,value){ 98 var vl=value.Value; 99 var vlparent=value.ParentValue;100 var link =value.Link;101 102 if(vlparent==uniq)103 {104 divStr+="<div>";105 divStr+=s.join(‘‘); //把数组里的数据全部加进来106 divStr+="</div>";107 108 }109 110 111 });112 113 114 //alert(s);115 //divStr+="</div>";116 117 118 119 // 120 // if(value.Valuehttp://www.mamicode.com/=="b15fa5ba-5a73-4792-a65a-5bcf2e8a20ec")121 // {122 // divStr+="<div><div>1</div><div>2</div></div>";123 // }124 125 divStr+="</div>";126 127 //tempMenu(value.Value);128 }129 130 131 132 });133 divStr = divStr+"</div>";134 $(‘#main‘).append(divStr);135 }136 137 //添加菜单项138 for(var i=0;i<k;i++)139 {140 $(‘#menu‘+i).menubutton({menu:‘#mm‘+i});141 142 }
大家又头晕了吧?容我慢慢道来,
这种多级菜单并不是通过ul li来实现的,而是通过div来实现的。
easyui有一个方法叫做menubutton,可以添加二级菜单
//添加菜单项 for(var i=0;i<k;i++) { $(‘#menu‘+i).menubutton({menu:‘#mm‘+i}); }
其中的model.NavigateData里面存储的是如下JSON
大家看到了吧?就是所有的菜单项的数据,我们需要的工作是提取有效的东西从里面。
具体怎么实现3级菜单上面都写了,就是在下图箭头所指的地方字符串拼接DIV
但是这里有一个难点,就是每次拼接出来的都是一个一个的整体,而我每个三级菜单其实是包含在一个大的DIV下面的。如下图
大家看到了吧,测试菜单2,3,4其实是在一个大的DIV里面的,而这个大的DIV只循环了一次,小的内容迭代了3次,这个如何实现的呢?
上面代码写了注释,我简单的说一下,其实很简单,就是把里面的三项的DIV都迭代出来放到数组里面去,然后再把他们的父亲节点的ID放入数组,由于迭代次数有多次,所以数组里有多个一样的东西,所以我们需要去掉相同的,然后再迭代判断父亲ID是否等于数组里面的ID,如果相等的话,把里面的数据拼接字符串,是不是很简单呢?
就说到这里了,最后:
祝大家中秋节快乐!!!
如何用easyui+JAVA 实现动态拼凑datagrid表格(续)