treeGrid.js 52 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390
  1. layui.define(['laytpl', 'laypage', 'layer', 'form'], function(exports){
  2. "use strict";
  3. var $ = layui.$
  4. ,laytpl = layui.laytpl
  5. ,laypage = layui.laypage
  6. ,layer = layui.layer
  7. ,form = layui.form
  8. ,hint = layui.hint()
  9. ,device = layui.device()
  10. //外部接口
  11. ,table = {
  12. config: {
  13. checkName: 'LAY_CHECKED' //是否选中状态的字段名
  14. ,indexName: 'LAY_TABLE_INDEX' //下标索引名
  15. } //全局配置项
  16. ,cache: {} //数据缓存
  17. ,index: layui.table ? (layui.table.index + 10000) : 0
  18. //设置全局项
  19. ,set: function(options){
  20. var that = this;
  21. that.config = $.extend({}, that.config, options);
  22. return that;
  23. }
  24. //事件监听
  25. ,on: function(events, callback){
  26. return layui.onevent.call(this, MOD_NAME, events, callback);
  27. }
  28. }
  29. //操作当前实例
  30. ,thisTable = function(){
  31. var that = this
  32. ,options = that.config
  33. ,id = options.id;
  34. id && (thisTable.config[id] = options);
  35. return {
  36. reload: function(options){
  37. that.reload.call(that, options);
  38. }
  39. ,config: options
  40. }
  41. }
  42. //字符常量
  43. ,MOD_NAME = 'treeGrid', ELEM = '.layui-table', THIS = 'layui-this', SHOW = 'layui-show', HIDE = 'layui-hide', DISABLED = 'layui-disabled', NONE = 'layui-none'
  44. ,ELEM_VIEW = 'layui-table-view', ELEM_HEADER = '.layui-table-header', ELEM_BODY = '.layui-table-body', ELEM_MAIN = '.layui-table-main', ELEM_FIXED = '.layui-table-fixed', ELEM_FIXL = '.layui-table-fixed-l', ELEM_FIXR = '.layui-table-fixed-r', ELEM_TOOL = '.layui-table-tool', ELEM_PAGE = '.layui-table-page', ELEM_SORT = '.layui-table-sort', ELEM_EDIT = 'layui-table-edit', ELEM_HOVER = 'layui-table-hover'
  45. //thead区域模板
  46. ,TPL_HEADER = function(options){
  47. var rowCols = '{{#if(item2.colspan){}} colspan="{{item2.colspan}}"{{#} if(item2.rowspan){}} rowspan="{{item2.rowspan}}"{{#}}}';
  48. options = options || {};
  49. return ['<table cellspacing="0" cellpadding="0" border="0" class="layui-table" '
  50. ,'{{# if(d.data.skin){ }}lay-skin="{{d.data.skin}}"{{# } }} {{# if(d.data.size){ }}lay-size="{{d.data.size}}"{{# } }} {{# if(d.data.even){ }}lay-even{{# } }}>'
  51. ,'<thead>'
  52. ,'{{# layui.each(d.data.cols, function(i1, item1){ }}'
  53. ,'<tr>'
  54. ,'{{# layui.each(item1, function(i2, item2){ }}'
  55. ,'{{# if(item2.fixed && item2.fixed !== "right"){ left = true; } }}'
  56. ,'{{# if(item2.fixed === "right"){ right = true; } }}'
  57. ,function(){
  58. if(options.fixed && options.fixed !== 'right'){
  59. return '{{# if(item2.fixed && item2.fixed !== "right"){ }}';
  60. }
  61. if(options.fixed === 'right'){
  62. return '{{# if(item2.fixed === "right"){ }}';
  63. }
  64. return '';
  65. }()
  66. ,'<th data-field="{{ item2.field||i2 }}" {{# if(item2.minWidth){ }}data-minwidth="{{item2.minWidth}}"{{# } }} '+ rowCols +' {{# if(item2.unresize){ }}data-unresize="true"{{# } }}>'
  67. ,'<div class="layui-table-cell laytable-cell-'
  68. ,'{{# if(item2.colspan > 1){ }}'
  69. ,'group'
  70. ,'{{# } else { }}'
  71. ,'{{d.index}}-{{item2.field || i2}}'
  72. ,'{{# if(item2.type !== "normal"){ }}'
  73. ,' laytable-cell-{{ item2.type }}'
  74. ,'{{# } }}'
  75. ,'{{# } }}'
  76. ,'" {{#if(item2.align){}}align="{{item2.align}}"{{#}}}>'
  77. ,'{{# if(item2.type === "checkbox"){ }}' //复选框
  78. ,'<input type="checkbox" name="layTableCheckbox" lay-skin="primary" lay-filter="layTableAllChoose" {{# if(item2[d.data.checkName]){ }}checked{{# }; }}>'
  79. ,'{{# } else { }}'
  80. ,'<span>{{item2.title||""}}</span>'
  81. ,'{{# if(!(item2.colspan > 1) && item2.sort){ }}'
  82. ,'<span class="layui-table-sort layui-inline"><i class="layui-edge layui-table-sort-asc"></i><i class="layui-edge layui-table-sort-desc"></i></span>'
  83. ,'{{# } }}'
  84. ,'{{# } }}'
  85. ,'</div>'
  86. ,'</th>'
  87. ,(options.fixed ? '{{# }; }}' : '')
  88. ,'{{# }); }}'
  89. ,'</tr>'
  90. ,'{{# }); }}'
  91. ,'</thead>'
  92. ,'</table>'].join('');
  93. }
  94. //tbody区域模板
  95. ,TPL_BODY = ['<table cellspacing="0" cellpadding="0" border="0" class="layui-table" '
  96. ,'{{# if(d.data.skin){ }}lay-skin="{{d.data.skin}}"{{# } }} {{# if(d.data.size){ }}lay-size="{{d.data.size}}"{{# } }} {{# if(d.data.even){ }}lay-even{{# } }}>'
  97. ,'<tbody></tbody>'
  98. ,'</table>'].join('')
  99. //主模板
  100. ,TPL_MAIN = ['<div class="layui-form layui-border-box {{d.VIEW_CLASS}}" lay-filter="LAY-table-{{d.index}}" style="{{# if(d.data.width){ }}width:{{d.data.width}}px;{{# } }} {{# if(d.data.height){ }}height:{{d.data.height}}px;{{# } }}">'
  101. ,'{{# if(d.data.toolbar){ }}'
  102. ,'<div class="layui-table-tool"></div>'
  103. ,'{{# } }}'
  104. ,'<div class="layui-table-box">'
  105. ,'{{# var left, right; }}'
  106. ,'<div class="layui-table-header">'
  107. ,TPL_HEADER()
  108. ,'</div>'
  109. ,'<div class="layui-table-body layui-table-main">'
  110. ,TPL_BODY
  111. ,'</div>'
  112. ,'{{# if(left){ }}'
  113. ,'<div class="layui-table-fixed layui-table-fixed-l">'
  114. ,'<div class="layui-table-header">'
  115. ,TPL_HEADER({fixed: true})
  116. ,'</div>'
  117. ,'<div class="layui-table-body">'
  118. ,TPL_BODY
  119. ,'</div>'
  120. ,'</div>'
  121. ,'{{# }; }}'
  122. ,'{{# if(right){ }}'
  123. ,'<div class="layui-table-fixed layui-table-fixed-r">'
  124. ,'<div class="layui-table-header">'
  125. ,TPL_HEADER({fixed: 'right'})
  126. ,'<div class="layui-table-mend"></div>'
  127. ,'</div>'
  128. ,'<div class="layui-table-body">'
  129. ,TPL_BODY
  130. ,'</div>'
  131. ,'</div>'
  132. ,'{{# }; }}'
  133. ,'</div>'
  134. ,'{{# if(d.data.page){ }}'
  135. ,'<div class="layui-table-page">'
  136. ,'<div id="layui-table-page{{d.index}}"></div>'
  137. ,'</div>'
  138. ,'{{# } }}'
  139. ,'<style>'
  140. ,'{{# layui.each(d.data.cols, function(i1, item1){'
  141. ,'layui.each(item1, function(i2, item2){ }}'
  142. ,'.laytable-cell-{{d.index}}-{{item2.field||i2}}{ '
  143. ,'{{# if(item2.width){ }}'
  144. ,'width: {{item2.width}}px;'
  145. ,'{{# } }}'
  146. ,' }'
  147. ,'{{# });'
  148. ,'}); }}'
  149. ,'</style>'
  150. ,'</div>'].join('')
  151. ,_WIN = $(window)
  152. ,_DOC = $(document)
  153. //构造器
  154. ,Class = function(options){
  155. var that = this;
  156. that.index = ++table.index;
  157. that.config = $.extend({}, that.config, table.config, options);
  158. that.render();
  159. };
  160. //默认配置
  161. Class.prototype.config = {
  162. limit: 10 //每页显示的数量
  163. ,loading: true //请求数据时,是否显示loading
  164. ,cellMinWidth: 60 //所有单元格默认最小宽度
  165. ,text: {
  166. none: '无数据'
  167. }
  168. };
  169. //表格渲染
  170. Class.prototype.render = function(){
  171. var that = this
  172. ,options = that.config;
  173. options.elem = $(options.elem);
  174. options.where = options.where || {};
  175. options.id = options.id || options.elem.attr('id');
  176. //请求参数的自定义格式
  177. options.request = $.extend({
  178. pageName: 'page'
  179. ,limitName: 'limit'
  180. }, options.request)
  181. //响应数据的自定义格式
  182. options.response = $.extend({
  183. statusName: 'code'
  184. ,statusCode: 0
  185. ,msgName: 'msg'
  186. ,dataName: 'data'
  187. ,countName: 'count'
  188. }, options.response);
  189. //如果 page 传入 laypage 对象
  190. if(typeof options.page === 'object'){
  191. options.limit = options.page.limit || options.limit;
  192. options.limits = options.page.limits || options.limits;
  193. that.page = options.page.curr = options.page.curr || 1;
  194. delete options.page.elem;
  195. delete options.page.jump;
  196. }
  197. if(!options.elem[0]) return that;
  198. that.setArea(); //动态分配列宽高
  199. //开始插入替代元素
  200. var othis = options.elem
  201. ,hasRender = othis.next('.' + ELEM_VIEW)
  202. //主容器
  203. ,reElem = that.elem = $(laytpl(TPL_MAIN).render({
  204. VIEW_CLASS: ELEM_VIEW
  205. ,data: options
  206. ,index: that.index //索引
  207. }));
  208. options.index = that.index;
  209. //生成替代元素
  210. hasRender[0] && hasRender.remove(); //如果已经渲染,则Rerender
  211. othis.after(reElem);
  212. //各级容器
  213. that.layHeader = reElem.find(ELEM_HEADER);
  214. that.layMain = reElem.find(ELEM_MAIN);
  215. that.layBody = reElem.find(ELEM_BODY);
  216. that.layFixed = reElem.find(ELEM_FIXED);
  217. that.layFixLeft = reElem.find(ELEM_FIXL);
  218. that.layFixRight = reElem.find(ELEM_FIXR);
  219. that.layTool = reElem.find(ELEM_TOOL);
  220. that.layPage = reElem.find(ELEM_PAGE);
  221. that.layTool.html(
  222. laytpl($(options.toolbar).html()||'').render(options)
  223. );
  224. if(options.height) that.fullSize(); //设置body区域高度
  225. //如果多级表头,则填补表头高度
  226. if(options.cols.length > 1){
  227. var th = that.layFixed.find(ELEM_HEADER).find('th');
  228. th.height(that.layHeader.height() - 1 - parseFloat(th.css('padding-top')) - parseFloat(th.css('padding-bottom')));
  229. }
  230. //请求数据
  231. that.pullData(that.page);
  232. that.events();
  233. };
  234. //根据列类型,定制化参数
  235. Class.prototype.initOpts = function(item){
  236. var that = this,
  237. options = that.config
  238. ,initWidth = {
  239. checkbox: 48
  240. ,space: 15
  241. ,numbers: 40
  242. };
  243. //让 type 参数兼容旧版本
  244. if(item.checkbox) item.type = "checkbox";
  245. if(item.space) item.type = "space";
  246. if(!item.type) item.type = "normal";
  247. if(item.type !== "normal"){
  248. item.unresize = true;
  249. item.width = item.width || initWidth[item.type];
  250. }
  251. };
  252. //动态分配列宽高
  253. Class.prototype.setArea = function(){
  254. var that = this,
  255. options = that.config
  256. ,colNums = 0 //列个数
  257. ,autoColNums = 0 //自动列宽的列个数
  258. ,autoWidth = 0 //自动列分配的宽度
  259. ,countWidth = 0 //所有列总宽度和
  260. ,cntrWidth = options.width || function(){ //获取容器宽度
  261. //如果父元素宽度为0(一般为隐藏元素),则继续查找上层元素,直到找到真实宽度为止
  262. var getWidth = function(parent){
  263. var width, isNone;
  264. parent = parent || options.elem.parent()
  265. width = parent.width();
  266. try {
  267. isNone = parent.css('display') === 'none';
  268. } catch(e){}
  269. if(parent[0] && (!width || isNone)) return getWidth(parent.parent());
  270. return width;
  271. };
  272. return getWidth();
  273. }();
  274. //统计列个数
  275. that.eachCols(function(){
  276. colNums++;
  277. });
  278. //减去边框差
  279. cntrWidth = cntrWidth - function(){
  280. return (options.skin === 'line' || options.skin === 'nob') ? 2 : colNums + 1;
  281. }();
  282. //遍历所有列
  283. layui.each(options.cols, function(i1, item1){
  284. layui.each(item1, function(i2, item2){
  285. var width;
  286. if(!item2){
  287. item1.splice(i2, 1);
  288. return;
  289. }
  290. that.initOpts(item2);
  291. width = item2.width || 0;
  292. if(item2.colspan > 1) return;
  293. if(/\d+%$/.test(width)){
  294. item2.width = width = Math.floor((parseFloat(width) / 100) * cntrWidth);
  295. } else if(!width){ //列宽未填写
  296. item2.width = width = 0;
  297. autoColNums++;
  298. }
  299. countWidth = countWidth + width;
  300. });
  301. });
  302. that.autoColNums = autoColNums; //记录自动列数
  303. //如果未填充满,则将剩余宽度平分。否则,给未设定宽度的列赋值一个默认宽
  304. (cntrWidth > countWidth && autoColNums) && (
  305. autoWidth = (cntrWidth - countWidth) / autoColNums
  306. );
  307. layui.each(options.cols, function(i1, item1){
  308. layui.each(item1, function(i2, item2){
  309. var minWidth = item2.minWidth || options.cellMinWidth;
  310. if(item2.colspan > 1) return;
  311. if(item2.width === 0){
  312. item2.width = Math.floor(autoWidth >= minWidth ? autoWidth : minWidth); //不能低于设定的最小宽度
  313. }
  314. });
  315. });
  316. //高度铺满:full-差距值
  317. if(options.height && /^full-\d+$/.test(options.height)){
  318. that.fullHeightGap = options.height.split('-')[1];
  319. options.height = _WIN.height() - that.fullHeightGap;
  320. }
  321. };
  322. //表格重载
  323. Class.prototype.reload = function(options){
  324. var that = this;
  325. if(that.config.data && that.config.data.constructor === Array) delete that.config.data;
  326. that.config = $.extend({}, that.config, options);
  327. that.render();
  328. };
  329. //页码
  330. Class.prototype.page = 1;
  331. //获得数据
  332. Class.prototype.pullData = function(curr, loadIndex){
  333. var that = this
  334. ,options = that.config
  335. ,request = options.request
  336. ,response = options.response
  337. ,sort = function(){
  338. if(typeof options.initSort === 'object'){
  339. that.sort(options.initSort.field, options.initSort.type);
  340. }
  341. };
  342. that.startTime = new Date().getTime(); //渲染开始时间
  343. if(options.url){ //Ajax请求
  344. var params = {};
  345. params[request.pageName] = curr;
  346. params[request.limitName] = options.limit;
  347. $.ajax({
  348. type: options.method || 'get'
  349. ,url: options.url
  350. ,data: $.extend(params, options.where)
  351. ,dataType: 'json'
  352. ,success: function(res){
  353. var data = that.filterArray(res.data,options.treeId,options.treeUpId);
  354. res.data=data[0];
  355. if(res[response.statusName] != response.statusCode){
  356. that.renderForm();
  357. that.layMain.html('<div class="'+ NONE +'">'+ (res[response.msgName] || '返回的数据状态异常') +'</div>');
  358. } else {
  359. that.renderData(res, curr, res[response.countName]), sort();
  360. options.time = (new Date().getTime() - that.startTime) + ' ms'; //耗时(接口请求+视图渲染)
  361. }
  362. loadIndex && layer.close(loadIndex);
  363. typeof options.done === 'function' && options.done(res, curr, res[response.countName]);
  364. }
  365. ,error: function(e, m){
  366. that.layMain.html('<div class="'+ NONE +'">数据接口请求异常</div>');
  367. that.renderForm();
  368. loadIndex && layer.close(loadIndex);
  369. }
  370. });
  371. } else if(options.data && options.data.constructor === Array){ //已知数据
  372. var res = {}
  373. ,startLimit = curr*options.limit - options.limit
  374. console.log(options.data,options.treeId,options.treeUpId);
  375. var data = that.filterArray(options.data,options.treeId,options.treeUpId);
  376. res.data=data[0];
  377. res[response.dataName] = res.data;//.concat().splice(startLimit, options.limit);
  378. res[response.countName] = res.data.length;
  379. console.log(res.data);
  380. that.renderData(res, curr, options.data.length), sort();
  381. typeof options.done === 'function' && options.done(res, curr, res[response.countName]);
  382. }
  383. };
  384. //遍历表头
  385. Class.prototype.eachCols = function(callback){
  386. var cols = $.extend(true, [], this.config.cols)
  387. ,arrs = [], index = 0;
  388. //重新整理表头结构
  389. layui.each(cols, function(i1, item1){
  390. layui.each(item1, function(i2, item2){
  391. //如果是组合列,则捕获对应的子列
  392. if(item2.colspan > 1){
  393. var childIndex = 0;
  394. index++
  395. item2.CHILD_COLS = [];
  396. layui.each(cols[i1 + 1], function(i22, item22){
  397. if(item22.PARENT_COL || childIndex == item2.colspan) return;
  398. item22.PARENT_COL = index;
  399. item2.CHILD_COLS.push(item22);
  400. childIndex = childIndex + (item22.colspan > 1 ? item22.colspan : 1);
  401. });
  402. }
  403. if(item2.PARENT_COL) return; //如果是子列,则不进行追加,因为已经存储在父列中
  404. arrs.push(item2)
  405. });
  406. });
  407. //重新遍历列,如果有子列,则进入递归
  408. var eachArrs = function(obj){
  409. layui.each(obj || arrs, function(i, item){
  410. if(item.CHILD_COLS) return eachArrs(item.CHILD_COLS);
  411. callback(i, item);
  412. });
  413. };
  414. eachArrs();
  415. };
  416. /**
  417. * 将列表数据转成树形结构和符合table展示的列表
  418. * @param data 列表数据
  419. * @param field_Id 树形结构主键字段
  420. * @param field_upId 树形结构上级字段
  421. * @returns {Array} [0]表格列表 [1]树形结构
  422. */
  423. Class.prototype.filterArray=function(data,field_Id,field_upId) {
  424. var list=[];
  425. var treeList=[];
  426. var tableList=[];
  427. console.log(data,field_Id,field_upId);
  428. //设置默认参数
  429. for (var i = 0; i < data.length; i++) {
  430. var n = data[i];
  431. n.isOpen=true;
  432. }
  433. //处理树结构
  434. var fa = function(upId) {
  435. var _array = [];
  436. for (var i = 0; i < data.length; i++) {
  437. var n = data[i];
  438. if (n[field_upId] === upId) {
  439. n.children = fa(n[field_Id]);
  440. _array.push(n);
  441. }
  442. }
  443. return _array;
  444. }
  445. treeList=fa(data[0][field_upId],"");//递归
  446. //处理表格结构
  447. var fa2=function (l,level,upids) {
  448. for (var i = 0; i < l.length; i++) {
  449. var n = l[i];
  450. n.level=level;//设置当前层级
  451. n.upIds=upids;
  452. tableList.push(n);
  453. if (n.children&&n.children.length>0) {
  454. fa2(n.children,1+level,upids+"_"+n[field_Id]+"_");
  455. }
  456. }
  457. return;
  458. }
  459. fa2(treeList,1,"");
  460. list.push(tableList);//table结构
  461. list.push(treeList)//tree树结构
  462. return list;
  463. }
  464. //数据渲染
  465. Class.prototype.renderData = function(res, curr, count, sort){
  466. var that = this
  467. ,options = that.config
  468. ,data = res[options.response.dataName] || []
  469. ,trs = []
  470. ,trs_fixed = []
  471. ,trs_fixed_r = []
  472. //渲染视图
  473. ,render = function(){ //后续性能提升的重点
  474. if(!sort && that.sortKey){
  475. return that.sort(that.sortKey.field, that.sortKey.sort, true);
  476. }
  477. layui.each(data, function(i1, item1){
  478. var tds = [], tds_fixed = [], tds_fixed_r = []
  479. ,numbers = i1 + options.limit*(curr - 1) + 1; //序号
  480. if(item1.length === 0) return;
  481. if(!sort){
  482. item1[table.config.indexName] = i1;
  483. }
  484. that.eachCols(function(i3, item3){
  485. var field = item3.field || i3, content = item1[field]
  486. ,cell = that.getColElem(that.layHeader, field);
  487. if(content === undefined || content === null) content = '';
  488. if(item3.colspan > 1) return;
  489. var o=data[i1];
  490. var treeImgHtml='';//树形图标
  491. var treeShowName=options.treeShowName;//显示值
  492. if(treeShowName==item3.field){//当前是否用于显示的值
  493. treeImgHtml+='<div style="float: left;height: 28px;line-height: 28px;padding-left: 5px;">';
  494. var temTreeHtml='<i class="layui-icon layui-tree-head">&#xe625;</i> ';
  495. var nbspHtml="<i>"//一次位移
  496. for(var i=1;i<o.level;i++) {
  497. nbspHtml = nbspHtml + "&nbsp;&nbsp;&nbsp;&nbsp;";
  498. }
  499. nbspHtml=nbspHtml+"</i>";
  500. if(o.children&&o.children.length>0){//非叶子节点
  501. treeImgHtml+=nbspHtml+temTreeHtml;
  502. }else{
  503. treeImgHtml+=nbspHtml+'<i class="layui-icon layui-tree-head">&nbsp;&nbsp;</i> ';
  504. }
  505. treeImgHtml+="</div>";
  506. }
  507. //td内容
  508. var td = ['<td data-field="'+ field +'" '+ function(){
  509. var attr = [];
  510. if(item3.edit) attr.push('data-edit="'+ item3.edit +'"'); //是否允许单元格编辑
  511. if(item3.align) attr.push('align="'+ item3.align +'"'); //对齐方式
  512. if(item3.templet) attr.push('data-content="'+ content +'"'); //自定义模板
  513. if(item3.toolbar) attr.push('data-off="true"'); //自定义模板
  514. if(item3.event) attr.push('lay-event="'+ item3.event +'"'); //自定义事件
  515. if(item3.style) attr.push('style="'+ item3.style +'"'); //自定义样式
  516. if(item3.minWidth) attr.push('data-minwidth="'+ item3.minWidth +'"'); //单元格最小宽度
  517. return attr.join(' ');
  518. }() +'>'
  519. ,'<div class="layui-table-cell laytable-cell-'+ function(){ //返回对应的CSS类标识
  520. var str = (options.index + '-' + field);
  521. return item3.type === 'normal' ? str
  522. : (str + ' laytable-cell-' + item3.type);
  523. }() +'">'+treeImgHtml+'<p style="width: auto;height: 100%;">'+function(){
  524. var tplData = $.extend(true, {
  525. LAY_INDEX: numbers
  526. }, item1);
  527. //渲染复选框列视图
  528. if(item3.type === 'checkbox'){
  529. return '<input type="checkbox" name="layTableCheckbox" lay-skin="primary" '+ function(){
  530. var checkName = table.config.checkName;
  531. //如果是全选
  532. if(item3[checkName]){
  533. item1[checkName] = item3[checkName];
  534. return item3[checkName] ? 'checked' : '';
  535. }
  536. return tplData[checkName] ? 'checked' : '';
  537. }() +'>';
  538. } else if(item3.type === 'numbers'){ //渲染序号
  539. return numbers;
  540. }
  541. //解析工具列模板
  542. if(item3.toolbar){
  543. return laytpl($(item3.toolbar).html()||'').render(tplData);
  544. }
  545. return item3.templet ? function(){
  546. return typeof item3.templet === 'function'
  547. ? item3.templet(tplData)
  548. : laytpl($(item3.templet).html() || String(content)).render(tplData)
  549. }() : content;
  550. }()
  551. ,' </p></div></td>'].join('');
  552. tds.push(td);
  553. if(item3.fixed && item3.fixed !== 'right') tds_fixed.push(td);
  554. if(item3.fixed === 'right') tds_fixed_r.push(td);
  555. });
  556. trs.push('<tr data-index="'+ i1 +'" upids="'+item1["upIds"]+'">'+ tds.join('') + '</tr>');
  557. trs_fixed.push('<tr data-index="'+ i1 +'">'+ tds_fixed.join('') + '</tr>');
  558. trs_fixed_r.push('<tr data-index="'+ i1 +'">'+ tds_fixed_r.join('') + '</tr>');
  559. });
  560. //if(data.length === 0) return;
  561. that.layBody.scrollTop(0);
  562. that.layMain.find('.'+ NONE).remove();
  563. that.layMain.find('tbody').html(trs.join(''));
  564. that.layFixLeft.find('tbody').html(trs_fixed.join(''));
  565. that.layFixRight.find('tbody').html(trs_fixed_r.join(''));
  566. that.renderForm();
  567. that.syncCheckAll();
  568. that.haveInit ? that.scrollPatch() : setTimeout(function(){
  569. that.scrollPatch();
  570. }, 50);
  571. that.haveInit = true;
  572. layer.close(that.tipsIndex);
  573. };
  574. that.key = options.id || options.index;
  575. table.cache[that.key] = data; //记录数据
  576. //显示隐藏分页栏
  577. that.layPage[data.length === 0 && curr == 1 ? 'addClass' : 'removeClass'](HIDE);
  578. //排序
  579. if(sort){
  580. return render();
  581. }
  582. if(data.length === 0){
  583. that.renderForm();
  584. that.layFixed.remove();
  585. that.layMain.find('tbody').html('');
  586. that.layMain.find('.'+ NONE).remove();
  587. return that.layMain.append('<div class="'+ NONE +'">'+ options.text.none +'</div>');
  588. }
  589. render();
  590. //同步分页状态
  591. if(options.page){
  592. options.page = $.extend({
  593. elem: 'layui-table-page' + options.index
  594. ,count: count
  595. ,limit: options.limit
  596. ,limits: options.limits || [10,20,30,40,50,60,70,80,90]
  597. ,groups: 3
  598. ,layout: ['prev', 'page', 'next', 'skip', 'count', 'limit']
  599. ,prev: '<i class="layui-icon">&#xe603;</i>'
  600. ,next: '<i class="layui-icon">&#xe602;</i>'
  601. ,jump: function(obj, first){
  602. if(!first){
  603. //分页本身并非需要做以下更新,下面参数的同步,主要是因为其它处理统一用到了它们
  604. //而并非用的是 options.page 中的参数(以确保分页未开启的情况仍能正常使用)
  605. that.page = obj.curr; //更新页码
  606. options.limit = obj.limit; //更新每页条数
  607. that.pullData(obj.curr, that.loading());
  608. }
  609. }
  610. }, options.page);
  611. options.page.count = count; //更新总条数
  612. laypage.render(options.page);
  613. }
  614. };
  615. //找到对应的列元素
  616. Class.prototype.getColElem = function(parent, field){
  617. var that = this
  618. ,options = that.config;
  619. return parent.eq(0).find('.laytable-cell-'+ (options.index + '-' + field) + ':eq(0)');
  620. };
  621. //渲染表单
  622. Class.prototype.renderForm = function(type){
  623. form.render(type, 'LAY-table-'+ this.index);
  624. }
  625. //数据排序
  626. Class.prototype.sort = function(th, type, pull, formEvent){
  627. var that = this
  628. ,field
  629. ,res = {}
  630. ,options = that.config
  631. ,filter = options.elem.attr('lay-filter')
  632. ,data = table.cache[that.key], thisData;
  633. //字段匹配
  634. if(typeof th === 'string'){
  635. that.layHeader.find('th').each(function(i, item){
  636. var othis = $(this)
  637. ,_field = othis.data('field');
  638. if(_field === th){
  639. th = othis;
  640. field = _field;
  641. return false;
  642. }
  643. });
  644. }
  645. try {
  646. var field = field || th.data('field');
  647. //如果欲执行的排序已在状态中,则不执行渲染
  648. if(that.sortKey && !pull){
  649. if(field === that.sortKey.field && type === that.sortKey.sort){
  650. return;
  651. }
  652. }
  653. var elemSort = that.layHeader.find('th .laytable-cell-'+ options.index +'-'+ field).find(ELEM_SORT);
  654. that.layHeader.find('th').find(ELEM_SORT).removeAttr('lay-sort'); //清除其它标题排序状态
  655. elemSort.attr('lay-sort', type || null);
  656. that.layFixed.find('th')
  657. } catch(e){
  658. return hint.error('Table modules: Did not match to field');
  659. }
  660. //记录排序索引和类型
  661. that.sortKey = {
  662. field: field
  663. ,sort: type
  664. };
  665. if(type === 'asc'){ //升序
  666. thisData = layui.sort(data, field);
  667. } else if(type === 'desc'){ //降序
  668. thisData = layui.sort(data, field, true);
  669. } else { //清除排序
  670. thisData = layui.sort(data, table.config.indexName);
  671. delete that.sortKey;
  672. }
  673. res[options.response.dataName] = thisData;
  674. that.renderData(res, that.page, that.count, true);
  675. if(formEvent){
  676. layui.event.call(th, MOD_NAME, 'sort('+ filter +')', {
  677. field: field
  678. ,type: type
  679. });
  680. }
  681. };
  682. //请求loading
  683. Class.prototype.loading = function(){
  684. var that = this
  685. ,options = that.config;
  686. if(options.loading && options.url){
  687. return layer.msg('数据请求中', {
  688. icon: 16
  689. ,offset: [
  690. that.elem.offset().top + that.elem.height()/2 - 35 - _WIN.scrollTop() + 'px'
  691. ,that.elem.offset().left + that.elem.width()/2 - 90 - _WIN.scrollLeft() + 'px'
  692. ]
  693. ,time: -1
  694. ,anim: -1
  695. ,fixed: false
  696. });
  697. }
  698. };
  699. //同步选中值状态
  700. Class.prototype.setCheckData = function(index, checked){
  701. var that = this
  702. ,options = that.config
  703. ,thisData = table.cache[that.key];
  704. if(!thisData[index]) return;
  705. if(thisData[index].constructor === Array) return;
  706. thisData[index][options.checkName] = checked;
  707. };
  708. //同步全选按钮状态
  709. Class.prototype.syncCheckAll = function(){
  710. var that = this
  711. ,options = that.config
  712. ,checkAllElem = that.layHeader.find('input[name="layTableCheckbox"]')
  713. ,syncColsCheck = function(checked){
  714. that.eachCols(function(i, item){
  715. if(item.type === 'checkbox'){
  716. item[options.checkName] = checked;
  717. }
  718. });
  719. return checked;
  720. };
  721. if(!checkAllElem[0]) return;
  722. if(table.checkStatus(that.key).isAll){
  723. if(!checkAllElem[0].checked){
  724. checkAllElem.prop('checked', true);
  725. that.renderForm('checkbox');
  726. }
  727. syncColsCheck(true);
  728. } else {
  729. if(checkAllElem[0].checked){
  730. checkAllElem.prop('checked', false);
  731. that.renderForm('checkbox');
  732. }
  733. syncColsCheck(false);
  734. }
  735. };
  736. //获取cssRule
  737. Class.prototype.getCssRule = function(field, callback){
  738. var that = this
  739. ,style = that.elem.find('style')[0]
  740. ,sheet = style.sheet || style.styleSheet || {}
  741. ,rules = sheet.cssRules || sheet.rules;
  742. layui.each(rules, function(i, item){
  743. if(item.selectorText === ('.laytable-cell-'+ that.index +'-'+ field)){
  744. return callback(item), true;
  745. }
  746. });
  747. };
  748. //铺满表格主体高度
  749. Class.prototype.fullSize = function(){
  750. var that = this
  751. ,options = that.config
  752. ,height = options.height, bodyHeight;
  753. if(that.fullHeightGap){
  754. height = _WIN.height() - that.fullHeightGap;
  755. if(height < 135) height = 135;
  756. that.elem.css('height', height);
  757. }
  758. //tbody区域高度
  759. bodyHeight = parseFloat(height) - parseFloat(that.layHeader.height()) - 1;
  760. if(options.toolbar){
  761. bodyHeight = bodyHeight - that.layTool.outerHeight();
  762. }
  763. if(options.page){
  764. bodyHeight = bodyHeight - that.layPage.outerHeight() - 1;
  765. }
  766. that.layMain.css('height', bodyHeight);
  767. };
  768. //获取滚动条宽度
  769. Class.prototype.getScrollWidth = function(elem){
  770. var width = 0;
  771. if(elem){
  772. width = elem.offsetWidth - elem.clientWidth;
  773. } else {
  774. elem = document.createElement('div');
  775. elem.style.width = '100px';
  776. elem.style.height = '100px';
  777. elem.style.overflowY = 'scroll';
  778. document.body.appendChild(elem);
  779. width = elem.offsetWidth - elem.clientWidth;
  780. document.body.removeChild(elem);
  781. }
  782. return width;
  783. };
  784. //滚动条补丁
  785. Class.prototype.scrollPatch = function(){
  786. var that = this
  787. ,layMainTable = that.layMain.children('table')
  788. ,scollWidth = that.layMain.width() - that.layMain.prop('clientWidth') //纵向滚动条宽度
  789. ,scollHeight = that.layMain.height() - that.layMain.prop('clientHeight') //横向滚动条高度
  790. ,getScrollWidth = that.getScrollWidth(that.layMain[0]) //获取主容器滚动条宽度,如果有的话
  791. ,outWidth = layMainTable.outerWidth() - that.layMain.width(); //表格内容器的超出宽度
  792. //如果存在自动列宽,则要保证绝对填充满,并且不能出现横向滚动条
  793. if(that.autoColNums && outWidth < 5 && !that.scrollPatchWStatus){
  794. var th = that.layHeader.eq(0).find('thead th:last-child')
  795. ,field = th.data('field');
  796. that.getCssRule(field, function(item){
  797. var width = item.style.width || th.outerWidth();
  798. item.style.width = (parseFloat(width) - getScrollWidth - outWidth) + 'px';
  799. //二次校验,如果仍然出现横向滚动条
  800. if(that.layMain.height() - that.layMain.prop('clientHeight') > 0){
  801. item.style.width = parseFloat(item.style.width) - 1 + 'px';
  802. }
  803. that.scrollPatchWStatus = true;
  804. });
  805. }
  806. if(scollWidth && scollHeight){
  807. if(!that.elem.find('.layui-table-patch')[0]){
  808. var patchElem = $('<th class="layui-table-patch"><div class="layui-table-cell"></div></th>'); //补丁元素
  809. patchElem.find('div').css({
  810. width: scollWidth
  811. });
  812. that.layHeader.eq(0).find('thead tr').append(patchElem)
  813. }
  814. } else {
  815. that.layHeader.eq(0).find('.layui-table-patch').remove();
  816. }
  817. //固定列区域高度
  818. var mainHeight = that.layMain.height()
  819. ,fixHeight = mainHeight - scollHeight;
  820. that.layFixed.find(ELEM_BODY).css('height', layMainTable.height() > fixHeight ? fixHeight : 'auto');
  821. //表格宽度小于容器宽度时,隐藏固定列
  822. that.layFixRight[outWidth > 0 ? 'removeClass' : 'addClass'](HIDE);
  823. //操作栏
  824. that.layFixRight.css('right', scollWidth - 1);
  825. };
  826. //事件处理
  827. Class.prototype.events = function(){
  828. var that = this
  829. ,options = that.config
  830. ,_BODY = $('body')
  831. ,dict = {}
  832. ,th = that.layHeader.find('th')
  833. ,resizing
  834. ,ELEM_CELL = '.layui-table-cell p'
  835. ,filter = options.elem.attr('lay-filter');
  836. //拖拽调整宽度
  837. th.on('mousemove', function(e){
  838. var othis = $(this)
  839. ,oLeft = othis.offset().left
  840. ,pLeft = e.clientX - oLeft;
  841. if(othis.attr('colspan') > 1 || othis.data('unresize') || dict.resizeStart){
  842. return;
  843. }
  844. dict.allowResize = othis.width() - pLeft <= 10; //是否处于拖拽允许区域
  845. _BODY.css('cursor', (dict.allowResize ? 'col-resize' : ''));
  846. }).on('mouseleave', function(){
  847. var othis = $(this);
  848. if(dict.resizeStart) return;
  849. _BODY.css('cursor', '');
  850. }).on('mousedown', function(e){
  851. var othis = $(this);
  852. if(dict.allowResize){
  853. var field = othis.data('field');
  854. e.preventDefault();
  855. dict.resizeStart = true; //开始拖拽
  856. dict.offset = [e.clientX, e.clientY]; //记录初始坐标
  857. that.getCssRule(field, function(item){
  858. var width = item.style.width || othis.outerWidth();
  859. dict.rule = item;
  860. dict.ruleWidth = parseFloat(width);
  861. dict.minWidth = othis.data('minwidth') || options.cellMinWidth;
  862. });
  863. }
  864. });
  865. //拖拽中
  866. _DOC.on('mousemove', function(e){
  867. if(dict.resizeStart){
  868. e.preventDefault();
  869. if(dict.rule){
  870. var setWidth = dict.ruleWidth + e.clientX - dict.offset[0];
  871. if(setWidth < dict.minWidth) setWidth = dict.minWidth;
  872. dict.rule.style.width = setWidth + 'px';
  873. layer.close(that.tipsIndex);
  874. }
  875. resizing = 1
  876. }
  877. }).on('mouseup', function(e){
  878. if(dict.resizeStart){
  879. dict = {};
  880. _BODY.css('cursor', '');
  881. that.scrollPatch();
  882. }
  883. if(resizing === 2){
  884. resizing = null;
  885. }
  886. });
  887. //排序
  888. th.on('click', function(){
  889. var othis = $(this)
  890. ,elemSort = othis.find(ELEM_SORT)
  891. ,nowType = elemSort.attr('lay-sort')
  892. ,type;
  893. if(!elemSort[0] || resizing === 1) return resizing = 2;
  894. if(nowType === 'asc'){
  895. type = 'desc';
  896. } else if(nowType === 'desc'){
  897. type = null;
  898. } else {
  899. type = 'asc';
  900. }
  901. that.sort(othis, type, null, true);
  902. }).find(ELEM_SORT+' .layui-edge ').on('click', function(e){
  903. var othis = $(this)
  904. ,index = othis.index()
  905. ,field = othis.parents('th').eq(0).data('field')
  906. layui.stope(e);
  907. if(index === 0){
  908. that.sort(field, 'asc', null, true);
  909. } else {
  910. that.sort(field, 'desc', null, true);
  911. }
  912. });
  913. /**
  914. * 树形节点点击事件(隐藏展开下级节点)
  915. */
  916. that.elem.on('click', 'i.layui-tree-head', function(){
  917. var othis = $(this)
  918. ,index = othis.parents('tr').eq(0).data('index')
  919. ,tr = that.layBody.find('tr[data-index="'+ index +'"]')
  920. ,datas=table.cache[that.key];//数据
  921. var o=datas[index];
  922. var stime=new Date();
  923. var sonO=$("[upids*=_"+o[options.treeId]+"_]");
  924. if(o.isOpen){//打开状态的,关闭
  925. sonO.hide();
  926. }else{
  927. sonO.show();
  928. }
  929. var etime=new Date();
  930. console.log((etime-stime)/1000+"秒");
  931. o.isOpen=!o.isOpen;//设置打开状态
  932. //处理图标
  933. var dbClickI=tr.find('.layui-tree-head');
  934. if(o.isOpen){//打开状态
  935. dbClickI.html('&#xe625;');
  936. }else{
  937. dbClickI.html('&#xe623;');
  938. }
  939. });
  940. //复选框选择
  941. that.elem.on('click', 'input[name="layTableCheckbox"]+', function(){
  942. var checkbox = $(this).prev()
  943. ,childs = that.layBody.find('input[name="layTableCheckbox"]')
  944. ,index = checkbox.parents('tr').eq(0).data('index')
  945. ,checked = checkbox[0].checked
  946. ,isAll = checkbox.attr('lay-filter') === 'layTableAllChoose';
  947. //全选
  948. if(isAll){
  949. childs.each(function(i, item){
  950. item.checked = checked;
  951. that.setCheckData(i, checked);
  952. });
  953. that.syncCheckAll();
  954. that.renderForm('checkbox');
  955. } else {
  956. that.setCheckData(index, checked);
  957. that.syncCheckAll();
  958. }
  959. layui.event.call(this, MOD_NAME, 'checkbox('+ filter +')', {
  960. checked: checked
  961. ,data: table.cache[that.key] ? (table.cache[that.key][index] || {}) : {}
  962. ,type: isAll ? 'all' : 'one'
  963. });
  964. });
  965. //行事件
  966. that.layBody.on('mouseenter', 'tr', function(){
  967. var othis = $(this)
  968. ,index = othis.index();
  969. that.layBody.find('tr:eq('+ index +')').addClass(ELEM_HOVER)
  970. }).on('mouseleave', 'tr', function(){
  971. var othis = $(this)
  972. ,index = othis.index();
  973. that.layBody.find('tr:eq('+ index +')').removeClass(ELEM_HOVER)
  974. });
  975. //单元格编辑
  976. that.layBody.on('change', '.'+ELEM_EDIT, function(){
  977. var othis = $(this)
  978. ,value = this.value
  979. ,field = othis.parent().data('field')
  980. ,index = othis.parents('tr').eq(0).data('index')
  981. ,data = table.cache[that.key][index];
  982. data[field] = value; //更新缓存中的值
  983. layui.event.call(this, MOD_NAME, 'edit('+ filter +')', {
  984. value: value
  985. ,data: data
  986. ,field: field
  987. });
  988. }).on('blur', '.'+ELEM_EDIT, function(){
  989. var templet
  990. ,othis = $(this)
  991. ,field = othis.parent().data('field')
  992. ,index = othis.parents('tr').eq(0).data('index')
  993. ,data = table.cache[that.key][index];
  994. that.eachCols(function(i, item){
  995. if(item.field == field && item.templet){
  996. templet = item.templet;
  997. }
  998. });
  999. othis.parent().find(ELEM_CELL).html(
  1000. templet ? laytpl($(templet).html() || this.value).render(data) : this.value
  1001. );
  1002. othis.parent().data('content', this.value);
  1003. othis.remove();
  1004. });
  1005. //单元格事件[td改成单元格内容点击事件]
  1006. that.layBody.on('click', 'td div.layui-table-cell p', function(){
  1007. var othis = $(this).parent().parent()
  1008. ,field = othis.data('field')
  1009. ,editType = othis.data('edit')
  1010. ,elemCell = othis.children(ELEM_CELL);
  1011. layer.close(that.tipsIndex);
  1012. if(othis.data('off')) return;
  1013. //显示编辑表单
  1014. if(editType){
  1015. if(editType === 'select') {
  1016. } else { //输入框
  1017. var input = $('<input class="layui-input '+ ELEM_EDIT +'">');
  1018. input[0].value = $(this).text();
  1019. othis.find('.'+ELEM_EDIT)[0] || othis.append(input);
  1020. input.focus();
  1021. }
  1022. return;
  1023. }
  1024. if(elemCell.find('.layui-form-switch,.layui-form-checkbox')[0]) return; //限制不出现更多(暂时)
  1025. if(Math.round(elemCell.prop('scrollWidth')) > Math.round(elemCell.outerWidth())){
  1026. that.tipsIndex = layer.tips([
  1027. '<div class="layui-table-tips-main" style="margin-top: -'+ (elemCell.height() + 16) +'px;'+ function(){
  1028. if(options.size === 'sm'){
  1029. return 'padding: 4px 15px; font-size: 12px;';
  1030. }
  1031. if(options.size === 'lg'){
  1032. return 'padding: 14px 15px;';
  1033. }
  1034. return '';
  1035. }() +'">'
  1036. ,elemCell.html()
  1037. ,'</div>'
  1038. ,'<i class="layui-icon layui-table-tips-c">&#x1006;</i>'
  1039. ].join(''), elemCell[0], {
  1040. tips: [3, '']
  1041. ,time: -1
  1042. ,anim: -1
  1043. ,maxWidth: (device.ios || device.android) ? 300 : 600
  1044. ,isOutAnim: false
  1045. ,skin: 'layui-table-tips'
  1046. ,success: function(layero, index){
  1047. layero.find('.layui-table-tips-c').on('click', function(){
  1048. layer.close(index);
  1049. });
  1050. }
  1051. });
  1052. }
  1053. });
  1054. //工具条操作事件
  1055. that.layBody.on('click', '*[lay-event]', function(){
  1056. var othis = $(this)
  1057. ,index = othis.parents('tr').eq(0).data('index')
  1058. ,tr = that.layBody.find('tr[data-index="'+ index +'"]')
  1059. ,ELEM_CLICK = 'layui-table-click'
  1060. ,data = table.cache[that.key][index];
  1061. layui.event.call(this, MOD_NAME, 'tool('+ filter +')', {
  1062. data: table.clearCacheKey(data)
  1063. ,event: othis.attr('lay-event')
  1064. ,tr: tr
  1065. ,del: function(){
  1066. table.cache[that.key][index] = [];
  1067. tr.remove();
  1068. that.scrollPatch();
  1069. }
  1070. ,update: function(fields){
  1071. fields = fields || {};
  1072. layui.each(fields, function(key, value){
  1073. if(key in data){
  1074. var templet, td = tr.children('td[data-field="'+ key +'"]');
  1075. data[key] = value;
  1076. that.eachCols(function(i, item2){
  1077. if(item2.field == key && item2.templet){
  1078. templet = item2.templet;
  1079. }
  1080. });
  1081. td.children(ELEM_CELL).html(
  1082. templet ? laytpl($(templet).html() || value).render(data) : value
  1083. );
  1084. td.data('content', value);
  1085. }
  1086. });
  1087. }
  1088. });
  1089. tr.addClass(ELEM_CLICK).siblings('tr').removeClass(ELEM_CLICK);
  1090. });
  1091. //同步滚动条
  1092. that.layMain.on('scroll', function(){
  1093. var othis = $(this)
  1094. ,scrollLeft = othis.scrollLeft()
  1095. ,scrollTop = othis.scrollTop();
  1096. that.layHeader.scrollLeft(scrollLeft);
  1097. that.layFixed.find(ELEM_BODY).scrollTop(scrollTop);
  1098. layer.close(that.tipsIndex);
  1099. });
  1100. _WIN.on('resize', function(){ //自适应
  1101. that.fullSize();
  1102. that.scrollPatch();
  1103. });
  1104. };
  1105. //初始化
  1106. table.init = function(filter, settings){
  1107. settings = settings || {};
  1108. var that = this
  1109. ,elemTable = filter ? $('table[lay-filter="'+ filter +'"]') : $(ELEM + '[lay-data]')
  1110. ,errorTips = 'Table element property lay-data configuration item has a syntax error: ';
  1111. //遍历数据表格
  1112. elemTable.each(function(){
  1113. var othis = $(this), tableData = othis.attr('lay-data');
  1114. try{
  1115. tableData = new Function('return '+ tableData)();
  1116. } catch(e){
  1117. hint.error(errorTips + tableData)
  1118. }
  1119. var cols = [], options = $.extend({
  1120. elem: this
  1121. ,cols: []
  1122. ,data: []
  1123. ,skin: othis.attr('lay-skin') //风格
  1124. ,size: othis.attr('lay-size') //尺寸
  1125. ,even: typeof othis.attr('lay-even') === 'string' //偶数行背景
  1126. }, table.config, settings, tableData);
  1127. filter && othis.hide();
  1128. //获取表头数据
  1129. othis.find('thead>tr').each(function(i){
  1130. options.cols[i] = [];
  1131. $(this).children().each(function(ii){
  1132. var th = $(this), itemData = th.attr('lay-data');
  1133. try{
  1134. itemData = new Function('return '+ itemData)();
  1135. } catch(e){
  1136. return hint.error(errorTips + itemData)
  1137. }
  1138. var row = $.extend({
  1139. title: th.text()
  1140. ,colspan: th.attr('colspan') || 0 //列单元格
  1141. ,rowspan: th.attr('rowspan') || 0 //行单元格
  1142. }, itemData);
  1143. if(row.colspan < 2) cols.push(row);
  1144. options.cols[i].push(row);
  1145. });
  1146. });
  1147. //获取表体数据
  1148. othis.find('tbody>tr').each(function(i1){
  1149. var tr = $(this), row = {};
  1150. //如果定义了字段名
  1151. tr.children('td').each(function(i2, item2){
  1152. var td = $(this)
  1153. ,field = td.data('field');
  1154. if(field){
  1155. return row[field] = td.html();
  1156. }
  1157. });
  1158. //如果未定义字段名
  1159. layui.each(cols, function(i3, item3){
  1160. var td = tr.children('td').eq(i3);
  1161. row[item3.field] = td.html();
  1162. });
  1163. options.data[i1] = row;
  1164. });
  1165. table.render(options);
  1166. });
  1167. return that;
  1168. };
  1169. //表格选中状态
  1170. table.checkStatus = function(id){
  1171. var nums = 0
  1172. ,invalidNum = 0
  1173. ,arr = []
  1174. ,data = table.cache[id] || [];
  1175. //计算全选个数
  1176. layui.each(data, function(i, item){
  1177. if(item.constructor === Array){
  1178. invalidNum++; //无效数据,或已删除的
  1179. return;
  1180. }
  1181. if(item[table.config.checkName]){
  1182. nums++;
  1183. arr.push(table.clearCacheKey(item));
  1184. }
  1185. });
  1186. return {
  1187. data: arr //选中的数据
  1188. ,isAll: data.length ? (nums === (data.length - invalidNum)) : false //是否全选
  1189. };
  1190. };
  1191. //表格重载
  1192. thisTable.config = {};
  1193. table.reload = function(id, options){
  1194. var config = thisTable.config[id];
  1195. options = options || {};
  1196. if(!config) return hint.error('The ID option was not found in the table instance');
  1197. if(options.data && options.data.constructor === Array) delete config.data;
  1198. return table.render($.extend(true, {}, config, options));
  1199. };
  1200. //核心入口
  1201. table.render = function(options){
  1202. var inst = new Class(options);
  1203. return thisTable.call(inst);
  1204. };
  1205. //清除临时Key
  1206. table.clearCacheKey = function(data){
  1207. data = $.extend({}, data);
  1208. delete data[table.config.checkName];
  1209. delete data[table.config.indexName];
  1210. return data;
  1211. };
  1212. //自动完成渲染
  1213. table.init();
  1214. exports(MOD_NAME, table);
  1215. });