Authored by wangtao

fix: table分页全局样式

@@ -275,7 +275,7 @@ layui.define(['laytpl', 'laypage', 'layer', 'form', 'util', 'sessions', 'common' @@ -275,7 +275,7 @@ layui.define(['laytpl', 'laypage', 'layer', 'form', 'util', 'sessions', 'common'
275 } 275 }
276 }); 276 });
277 return Object.assign({ 277 return Object.assign({
278 - limit: 10 //每页显示的数量 278 + limit: 20 //每页显示的数量
279 , loading: true //请求数据时,是否显示loading 279 , loading: true //请求数据时,是否显示loading
280 , cellMinWidth: 60 //所有单元格默认最小宽度 280 , cellMinWidth: 60 //所有单元格默认最小宽度
281 , defaultToolbar: ['filter', 'exports', 'print'] //工具栏右侧图标 281 , defaultToolbar: ['filter', 'exports', 'print'] //工具栏右侧图标
@@ -959,7 +959,7 @@ layui.define(['laytpl', 'laypage', 'layer', 'form', 'util', 'sessions', 'common' @@ -959,7 +959,7 @@ layui.define(['laytpl', 'laypage', 'layer', 'form', 'util', 'sessions', 'common'
959 elem: 'layui-table-page' + options.index 959 elem: 'layui-table-page' + options.index
960 , count: count 960 , count: count
961 , limit: options.limit 961 , limit: options.limit
962 - , limits: options.limits || [10, 20, 30, 40, 50, 60, 70, 80, 90] 962 + , limits: [10, 20, 30, 40, 50, 100,200]
963 , groups: 3 963 , groups: 3
964 , layout: ['prev', 'page', 'next', 'skip', 'count', 'limit'] 964 , layout: ['prev', 'page', 'next', 'skip', 'count', 'limit']
965 , prev: '<i class="layui-icon">&#xe603;</i>' 965 , prev: '<i class="layui-icon">&#xe603;</i>'
  1 +/**
  2 +
  3 + @Name:layui.table 表格操作
  4 + @Author:贤心
  5 + @License:MIT
  6 + @version:2.5.6
  7 +
  8 + */
  9 +
  10 +layui.define(['laytpl', 'laypage', 'layer', 'form', 'util', 'sessions', 'common'], function (exports) {
  11 + "use strict";
  12 + var $ = layui.$
  13 + , laytpl = layui.laytpl
  14 + , laypage = layui.laypage
  15 + , layer = layui.layer
  16 + , form = layui.form
  17 + , util = layui.util
  18 + , hint = layui.hint()
  19 + , device = layui.device()
  20 + , common = layui.common
  21 + , sessions = layui.sessions
  22 + , admin = layui.admin
  23 + , accessToken = sessions.getToken()['access_token']
  24 +
  25 + //外部接口
  26 + , table = {
  27 + config: {
  28 + checkName: 'LAY_CHECKED' //是否选中状态的字段名
  29 + , indexName: 'LAY_TABLE_INDEX' //下标索引名
  30 + } //全局配置项
  31 + , cache: {} //数据缓存
  32 + , index: layui.table ? (layui.table.index + 10000) : 0
  33 +
  34 + //设置全局项
  35 + , set: function (options) {
  36 + var that = this;
  37 + that.config = $.extend({}, that.config, options);
  38 + return that;
  39 + }
  40 +
  41 + //事件监听
  42 + , on: function (events, callback) {
  43 + return layui.onevent.call(this, MOD_NAME, events, callback);
  44 + }
  45 + }
  46 +
  47 + //操作当前实例
  48 + , thisTable = function () {
  49 + var that = this
  50 + , options = that.config
  51 + , id = options.id || options.index;
  52 +
  53 + if (id) {
  54 + thisTable.that[id] = that; //记录当前实例对象
  55 + thisTable.config[id] = options; //记录当前实例配置项
  56 + }
  57 +
  58 + return {
  59 + config: options
  60 + , reload: function (options) {
  61 + that.reload.call(that, options);
  62 + }
  63 + , setColsWidth: function () {
  64 + that.setColsWidth.call(that);
  65 + }
  66 + , resize: function () { //重置表格尺寸/结构
  67 + that.resize.call(that);
  68 + }
  69 + }
  70 + }
  71 +
  72 + //获取当前实例配置项
  73 + , getThisTableConfig = function (id) {
  74 + var config = thisTable.config[id];
  75 + if (!config) hint.error('The ID option was not found in the table instance');
  76 + return config || null;
  77 + }
  78 +
  79 + //解析自定义模板数据
  80 + , parseTempData = function (item3, content, tplData, text) { //表头数据、原始内容、表体数据、是否只返回文本
  81 + var str = item3.templet ? function () {
  82 + return typeof item3.templet === 'function'
  83 + ? item3.templet(tplData)
  84 + : laytpl($(item3.templet).html() || String(content)).render(tplData)
  85 + }() : content;
  86 + return text ? $('<div>' + str + '</div>').text() : str;
  87 + }
  88 + , loadConfig = (function () {
  89 + // let c = {};
  90 + // layui.$.ajax({
  91 + // url: '/config/getConfig',
  92 + // data: {
  93 + // configName: 'config.layer.load'
  94 + // },
  95 + // async: false,
  96 + // success(res) {
  97 + // c = res;
  98 + // },
  99 + // error() {
  100 + // console.error('获取配置失败, 请检查配置文件.');
  101 + // }
  102 + // });
  103 + return layer.loadConfig('config.layer.load');
  104 + })()
  105 +
  106 + //字符常量
  107 + , MOD_NAME = 'table', ELEM = '.layui-table', THIS = 'layui-this', SHOW = 'layui-show', HIDE = 'layui-hide',
  108 + DISABLED = 'layui-disabled', NONE = 'layui-none'
  109 +
  110 + , ELEM_VIEW = 'layui-table-view', ELEM_TOOL = '.layui-table-tool', ELEM_BOX = '.layui-table-box',
  111 + ELEM_INIT = '.layui-table-init', ELEM_HEADER = '.layui-table-header', ELEM_BODY = '.layui-table-body',
  112 + ELEM_MAIN = '.layui-table-main', ELEM_FIXED = '.layui-table-fixed', ELEM_FIXL = '.layui-table-fixed-l',
  113 + ELEM_FIXR = '.layui-table-fixed-r', ELEM_TOTAL = '.layui-table-total', ELEM_PAGE = '.layui-table-page',
  114 + ELEM_SORT = '.layui-table-sort', ELEM_EDIT = 'layui-table-edit', ELEM_HOVER = 'layui-table-hover'
  115 +
  116 + //thead区域模板
  117 + , TPL_HEADER = function (options) {
  118 + var rowCols = '{{#if(item2.colspan){}} colspan="{{item2.colspan}}"{{#} if(item2.rowspan){}} rowspan="{{item2.rowspan}}"{{#}}}';
  119 +
  120 + options = options || {};
  121 + return ['<table cellspacing="0" cellpadding="0" border="0" class="layui-table" '
  122 + , '{{# if(d.data.skin){ }}lay-skin="{{d.data.skin}}"{{# } }} {{# if(d.data.size){ }}lay-size="{{d.data.size}}"{{# } }} {{# if(d.data.even){ }}lay-even{{# } }}>'
  123 + , '<thead>'
  124 + , '{{# layui.each(d.data.cols, function(i1, item1){ }}'
  125 + , '<tr>'
  126 + , '{{# layui.each(item1, function(i2, item2){ }}'
  127 + , '{{# if(item2.fixed && item2.fixed !== "right"){ left = true; } }}'
  128 + , '{{# if(item2.fixed === "right"){ right = true; } }}'
  129 + , function () {
  130 + if (options.fixed && options.fixed !== 'right') {
  131 + return '{{# if(item2.fixed && item2.fixed !== "right"){ }}';
  132 + }
  133 + if (options.fixed === 'right') {
  134 + return '{{# if(item2.fixed === "right"){ }}';
  135 + }
  136 + return '';
  137 + }()
  138 + , '{{# var isSort = !(item2.colGroup) && item2.sort; }}'
  139 + , '<th data-field="{{ item2.field||i2 }}" data-key="{{d.index}}-{{i1}}-{{i2}}" {{# if( item2.parentKey){ }}data-parentkey="{{ item2.parentKey }}"{{# } }} {{# if(item2.minWidth){ }}data-minwidth="{{item2.minWidth}}"{{# } }} ' + rowCols + ' {{# if(item2.unresize || item2.colGroup){ }}data-unresize="true"{{# } }} class="{{# if(item2.hide){ }}layui-hide{{# } }}{{# if(isSort){ }} layui-unselect{{# } }}{{# if(!item2.field){ }} layui-table-col-special{{# } }}">'
  140 + , '<div class="layui-table-cell laytable-cell-'
  141 + , '{{# if(item2.colGroup){ }}'
  142 + , 'group'
  143 + , '{{# } else { }}'
  144 + , '{{d.index}}-{{i1}}-{{i2}}'
  145 + , '{{# if(item2.type !== "normal"){ }}'
  146 + , ' laytable-cell-{{ item2.type }}'
  147 + , '{{# } }}'
  148 + , '{{# } }}'
  149 + , '" {{#if(item2.align){}}align="{{item2.align}}"{{#}}}>'
  150 + , '{{# if(item2.type === "checkbox"){ }}' //复选框
  151 + , '<input type="checkbox" name="layTableCheckbox" lay-skin="primary" lay-filter="layTableAllChoose" {{# if(item2[d.data.checkName]){ }}checked{{# }; }}>'
  152 + , '{{# } else { }}'
  153 + , '<span>{{item2.title||""}}</span>'
  154 + , '{{# if(isSort){ }}'
  155 + , '<span class="layui-table-sort layui-inline"><i class="layui-edge layui-table-sort-asc" title="升序"></i><i class="layui-edge layui-table-sort-desc" title="降序"></i></span>'
  156 + , '{{# } }}'
  157 + , '{{# } }}'
  158 + , '</div>'
  159 + , '</th>'
  160 + , (options.fixed ? '{{# }; }}' : '')
  161 + , '{{# }); }}'
  162 + , '</tr>'
  163 + , '{{# }); }}'
  164 + , '</thead>'
  165 + , '</table>'].join('');
  166 + }
  167 +
  168 + //tbody区域模板
  169 + , TPL_BODY = ['<table cellspacing="0" cellpadding="0" border="0" class="layui-table" '
  170 + , '{{# if(d.data.skin){ }}lay-skin="{{d.data.skin}}"{{# } }} {{# if(d.data.size){ }}lay-size="{{d.data.size}}"{{# } }} {{# if(d.data.even){ }}lay-even{{# } }}>'
  171 + , '<tbody></tbody>'
  172 + , '</table>'].join('')
  173 +
  174 + //主模板
  175 + ,
  176 + TPL_MAIN = ['<div class="layui-form layui-border-box {{d.VIEW_CLASS}}" lay-filter="LAY-table-{{d.index}}" lay-id="{{ d.data.id }}" style="{{# if(d.data.width){ }}width:{{d.data.width}}px;{{# } }} {{# if(d.data.height){ }}height:{{d.data.height}}px;{{# } }}">'
  177 +
  178 + , '{{# if(d.data.toolbar){ }}'
  179 + , '<div class="layui-table-tool">'
  180 + , '<div class="layui-table-tool-temp"></div>'
  181 + , '<div class="layui-table-tool-self"></div>'
  182 + , '</div>'
  183 + , '{{# } }}'
  184 +
  185 + , '<div class="layui-table-box">'
  186 + , '{{# if(d.data.loading){ }}'
  187 + , '<div class="layui-table-init" style="background-color: #fff;">'
  188 + , '<div class="layui-icon loading-' + loadConfig.icon + ' layui-anim layui-anim-rotate layui-anim-loop"></div>'
  189 + , '</div>'
  190 + , '{{# } }}'
  191 +
  192 + , '{{# var left, right; }}'
  193 + , '<div class="layui-table-header">'
  194 + , TPL_HEADER()
  195 + , '</div>'
  196 + , '<div class="layui-table-body layui-table-main">'
  197 + , TPL_BODY
  198 + , '</div>'
  199 +
  200 + , '{{# if(left){ }}'
  201 + , '<div class="layui-table-fixed layui-table-fixed-l">'
  202 + , '<div class="layui-table-header">'
  203 + , TPL_HEADER({fixed: true})
  204 + , '</div>'
  205 + , '<div class="layui-table-body">'
  206 + , TPL_BODY
  207 + , '</div>'
  208 + , '</div>'
  209 + , '{{# }; }}'
  210 +
  211 + , '{{# if(right){ }}'
  212 + , '<div class="layui-table-fixed layui-table-fixed-r">'
  213 + , '<div class="layui-table-header">'
  214 + , TPL_HEADER({fixed: 'right'})
  215 + , '<div class="layui-table-mend"></div>'
  216 + , '</div>'
  217 + , '<div class="layui-table-body">'
  218 + , TPL_BODY
  219 + , '</div>'
  220 + , '</div>'
  221 + , '{{# }; }}'
  222 + , '</div>'
  223 +
  224 + , '{{# if(d.data.totalRow){ }}'
  225 + , '<div class="layui-table-total">'
  226 + , '<table cellspacing="0" cellpadding="0" border="0" class="layui-table" '
  227 + , '{{# if(d.data.skin){ }}lay-skin="{{d.data.skin}}"{{# } }} {{# if(d.data.size){ }}lay-size="{{d.data.size}}"{{# } }} {{# if(d.data.even){ }}lay-even{{# } }}>'
  228 + , '<tbody><tr><td><div class="layui-table-cell" style="visibility: hidden;">Total</div></td></tr></tbody>'
  229 + , '</table>'
  230 + , '</div>'
  231 + , '{{# } }}'
  232 +
  233 + , '{{# if(d.data.page){ }}'
  234 + , '<div class="layui-table-page">'
  235 + , '<div id="layui-table-page{{d.index}}"></div>'
  236 + , '</div>'
  237 + , '{{# } }}'
  238 +
  239 + , '<style>'
  240 + , '{{# layui.each(d.data.cols, function(i1, item1){'
  241 + , 'layui.each(item1, function(i2, item2){ }}'
  242 + , '.laytable-cell-{{d.index}}-{{i1}}-{{i2}}{ '
  243 + , '{{# if(item2.width){ }}'
  244 + , 'width: {{item2.width}}px;'
  245 + , '{{# } }}'
  246 + , ' }'
  247 + , '{{# });'
  248 + , '}); }}'
  249 + , '</style>'
  250 + , '</div>'].join('')
  251 +
  252 + , _WIN = $(window)
  253 + , _DOC = $(document)
  254 +
  255 + //构造器
  256 + , Class = function (options) {
  257 + var that = this;
  258 + that.index = ++table.index;
  259 + that.config = $.extend({}, that.config, table.config, options);
  260 + that.render();
  261 + };
  262 +
  263 + //默认配置
  264 + Class.prototype.config = (function () {
  265 + var remoteConfig = {};
  266 + admin.req({
  267 + url: common.domainName + '/api-web/home/getConfig',
  268 + async: false,
  269 + data: {
  270 + access_token: accessToken,
  271 + configName: 'layui.table'
  272 + },
  273 + success: function (response) {
  274 + remoteConfig = response;
  275 + }
  276 + });
  277 + return Object.assign({
  278 + limit: 10 //每页显示的数量
  279 + , loading: true //请求数据时,是否显示loading
  280 + , cellMinWidth: 60 //所有单元格默认最小宽度
  281 + , defaultToolbar: ['filter', 'exports', 'print'] //工具栏右侧图标
  282 + , autoSort: true //是否前端自动排序。如果否,则需自主排序(通常为服务端处理好排序)
  283 + , text: {
  284 + none: '无数据'
  285 + }
  286 + }, remoteConfig);
  287 + })();
  288 +
  289 + //表格渲染
  290 + Class.prototype.render = function () {
  291 + var that = this
  292 + , options = that.config;
  293 + var request = layui.setter.request
  294 +
  295 + options.elem = $(options.elem);
  296 + options.where = options.where || {};
  297 + options.id = options.id || options.elem.attr('id') || that.index;
  298 +
  299 + if (request.tokenName) {
  300 + let tokenVal = options.where[request.tokenName];
  301 + if(!tokenVal || tokenVal == ''){
  302 + options.where[request.tokenName] = localStorage.getItem(request.tokenName);
  303 + }
  304 + }
  305 +
  306 + //请求参数的自定义格式
  307 + options.request = $.extend({
  308 + pageName: 'page'
  309 + , limitName: 'limit'
  310 + }, options.request)
  311 +
  312 + //响应数据的自定义格式
  313 + options.response = $.extend({
  314 + statusName: 'code' //规定数据状态的字段名称
  315 + , statusCode: 0 //规定成功的状态码
  316 + , msgName: 'msg' //规定状态信息的字段名称
  317 + , dataName: 'data' //规定数据总数的字段名称
  318 + , totalRowName: 'totalRow' //规定数据统计的字段名称
  319 + , countName: 'count'
  320 + }, options.response);
  321 +
  322 + //如果 page 传入 laypage 对象
  323 + if (typeof options.page === 'object') {
  324 + options.limit = options.page.limit || options.limit;
  325 + options.limits = options.page.limits || options.limits;
  326 + that.page = options.page.curr = options.page.curr || 1;
  327 + delete options.page.elem;
  328 + delete options.page.jump;
  329 + }
  330 +
  331 + if (!options.elem[0]) return that;
  332 +
  333 + //高度铺满:full-差距值
  334 + if (options.height && /^full-\d+$/.test(options.height)) {
  335 + that.fullHeightGap = options.height.split('-')[1];
  336 + options.height = _WIN.height() - that.fullHeightGap;
  337 + }
  338 +
  339 + //初始化一些参数
  340 + that.setInit();
  341 +
  342 + //开始插入替代元素
  343 + var othis = options.elem
  344 + , hasRender = othis.next('.' + ELEM_VIEW)
  345 +
  346 + //主容器
  347 + , reElem = that.elem = $(laytpl(TPL_MAIN).render({
  348 + VIEW_CLASS: ELEM_VIEW
  349 + , data: options
  350 + , index: that.index //索引
  351 + }));
  352 +
  353 + options.index = that.index;
  354 + that.key = options.id || options.index;
  355 +
  356 + //生成替代元素
  357 + hasRender[0] && hasRender.remove(); //如果已经渲染,则Rerender
  358 + othis.after(reElem);
  359 +
  360 + //各级容器
  361 + that.layTool = reElem.find(ELEM_TOOL);
  362 + that.layBox = reElem.find(ELEM_BOX);
  363 + that.layHeader = reElem.find(ELEM_HEADER);
  364 + that.layMain = reElem.find(ELEM_MAIN);
  365 + that.layBody = reElem.find(ELEM_BODY);
  366 + that.layFixed = reElem.find(ELEM_FIXED);
  367 + that.layFixLeft = reElem.find(ELEM_FIXL);
  368 + that.layFixRight = reElem.find(ELEM_FIXR);
  369 + that.layTotal = reElem.find(ELEM_TOTAL);
  370 + that.layPage = reElem.find(ELEM_PAGE);
  371 +
  372 + //初始化工具栏
  373 + that.renderToolbar();
  374 +
  375 + //让表格平铺
  376 + that.fullSize();
  377 +
  378 + //如果多级表头,则填补表头高度
  379 + if (options.cols.length > 1) {
  380 + //补全高度
  381 + var th = that.layFixed.find(ELEM_HEADER).find('th');
  382 + th.height(that.layHeader.height() - 1 - parseFloat(th.css('padding-top')) - parseFloat(th.css('padding-bottom')));
  383 + }
  384 +
  385 + that.pullData(that.page); //请求数据
  386 + that.events(); //事件
  387 + };
  388 +
  389 + //根据列类型,定制化参数
  390 + Class.prototype.initOpts = function (item) {
  391 + var that = this
  392 + , options = that.config
  393 + , initWidth = {
  394 + checkbox: 48
  395 + , radio: 48
  396 + , space: 15
  397 + , numbers: 40
  398 + };
  399 +
  400 + //让 type 参数兼容旧版本
  401 + if (item.checkbox) item.type = "checkbox";
  402 + if (item.space) item.type = "space";
  403 + if (!item.type) item.type = "normal";
  404 +
  405 + if (item.type !== "normal") {
  406 + item.unresize = true;
  407 + item.width = item.width || initWidth[item.type];
  408 + }
  409 + };
  410 +
  411 + //初始化一些参数
  412 + Class.prototype.setInit = function (type) {
  413 + var that = this
  414 + , options = that.config;
  415 +
  416 + options.clientWidth = options.width || function () { //获取容器宽度
  417 + //如果父元素宽度为0(一般为隐藏元素),则继续查找上层元素,直到找到真实宽度为止
  418 + var getWidth = function (parent) {
  419 + var width, isNone;
  420 + parent = parent || options.elem.parent()
  421 + width = parent.width();
  422 + try {
  423 + isNone = parent.css('display') === 'none';
  424 + } catch (e) {
  425 + }
  426 + if (parent[0] && (!width || isNone)) return getWidth(parent.parent());
  427 + return width;
  428 + };
  429 + return getWidth();
  430 + }();
  431 +
  432 + if (type === 'width') return options.clientWidth;
  433 +
  434 + //初始化列参数
  435 + layui.each(options.cols, function (i1, item1) {
  436 + layui.each(item1, function (i2, item2) {
  437 +
  438 + //如果列参数为空,则移除
  439 + if (!item2) {
  440 + item1.splice(i2, 1);
  441 + return;
  442 + }
  443 +
  444 + item2.key = i1 + '-' + i2;
  445 + item2.hide = item2.hide || false;
  446 +
  447 + //设置列的父列索引
  448 + //如果是组合列,则捕获对应的子列
  449 + if (item2.colGroup || item2.colspan > 1) {
  450 + var childIndex = 0;
  451 + layui.each(options.cols[i1 + 1], function (i22, item22) {
  452 + //如果子列已经被标注为{HAS_PARENT},或者子列累计 colspan 数等于父列定义的 colspan,则跳出当前子列循环
  453 + if (item22.HAS_PARENT || (childIndex > 1 && childIndex == item2.colspan)) return;
  454 +
  455 + item22.HAS_PARENT = true;
  456 + item22.parentKey = i1 + '-' + i2;
  457 +
  458 + childIndex = childIndex + parseInt(item22.colspan > 1 ? item22.colspan : 1);
  459 + });
  460 + item2.colGroup = true; //标注是组合列
  461 + }
  462 +
  463 + //根据列类型,定制化参数
  464 + that.initOpts(item2);
  465 + });
  466 + });
  467 +
  468 + };
  469 +
  470 + //初始工具栏
  471 + Class.prototype.renderToolbar = function () {
  472 + var that = this
  473 + , options = that.config
  474 +
  475 + //添加工具栏左侧模板
  476 + var leftDefaultTemp = [
  477 + '<div class="layui-inline" lay-event="add"><i class="layui-icon layui-icon-add-1"></i></div>'
  478 + , '<div class="layui-inline" lay-event="update"><i class="layui-icon layui-icon-edit"></i></div>'
  479 + , '<div class="layui-inline" lay-event="delete"><i class="layui-icon layui-icon-delete"></i></div>'
  480 + ].join('')
  481 + , elemToolTemp = that.layTool.find('.layui-table-tool-temp');
  482 +
  483 + if (options.toolbar === 'default') {
  484 + elemToolTemp.html(leftDefaultTemp);
  485 + } else if (typeof options.toolbar === 'string') {
  486 + var toolbarHtml = $(options.toolbar).html() || '';
  487 + toolbarHtml && elemToolTemp.html(
  488 + laytpl(toolbarHtml).render(options)
  489 + );
  490 + }
  491 +
  492 + //添加工具栏右侧面板
  493 + var layout = {
  494 + filter: {
  495 + title: '筛选列'
  496 + , layEvent: 'LAYTABLE_COLS'
  497 + , icon: 'layui-icon-cols'
  498 + }
  499 + , exports: {
  500 + title: '导出'
  501 + , layEvent: 'LAYTABLE_EXPORT'
  502 + , icon: 'layui-icon-export'
  503 + }
  504 + , print: {
  505 + title: '打印'
  506 + , layEvent: 'LAYTABLE_PRINT'
  507 + , icon: 'layui-icon-print'
  508 + }
  509 + }, iconElem = [];
  510 +
  511 + if (typeof options.defaultToolbar === 'object') {
  512 + layui.each(options.defaultToolbar, function (i, item) {
  513 + var thisItem = typeof item === 'string' ? layout[item] : item;
  514 + if (thisItem) {
  515 + iconElem.push('<div class="layui-inline" title="' + thisItem.title + '" lay-event="' + thisItem.layEvent + '">'
  516 + + '<i class="layui-icon ' + thisItem.icon + '"></i>'
  517 + + '</div>');
  518 + }
  519 + });
  520 + }
  521 + that.layTool.find('.layui-table-tool-self').html(iconElem.join(''));
  522 + }
  523 +
  524 + //同步表头父列的相关值
  525 + Class.prototype.setParentCol = function (hide, parentKey) {
  526 + var that = this
  527 + , options = that.config
  528 +
  529 + , parentTh = that.layHeader.find('th[data-key="' + options.index + '-' + parentKey + '"]') //获取父列元素
  530 + , parentColspan = parseInt(parentTh.attr('colspan')) || 0;
  531 +
  532 + if (parentTh[0]) {
  533 + var arrParentKey = parentKey.split('-')
  534 + , getThisCol = options.cols[arrParentKey[0]][arrParentKey[1]];
  535 +
  536 + hide ? parentColspan-- : parentColspan++;
  537 +
  538 + parentTh.attr('colspan', parentColspan);
  539 + parentTh[parentColspan < 1 ? 'addClass' : 'removeClass'](HIDE);
  540 +
  541 + getThisCol.colspan = parentColspan; //同步 colspan 参数
  542 + getThisCol.hide = parentColspan < 1; //同步 hide 参数
  543 +
  544 + //递归,继续往上查询是否有父列
  545 + var nextParentKey = parentTh.data('parentkey');
  546 + nextParentKey && that.setParentCol(hide, nextParentKey);
  547 + }
  548 + };
  549 +
  550 + //多级表头补丁
  551 + Class.prototype.setColsPatch = function () {
  552 + var that = this
  553 + , options = that.config
  554 +
  555 + //同步表头父列的相关值
  556 + layui.each(options.cols, function (i1, item1) {
  557 + layui.each(item1, function (i2, item2) {
  558 + if (item2.hide) {
  559 + that.setParentCol(item2.hide, item2.parentKey);
  560 + }
  561 + });
  562 + });
  563 + };
  564 +
  565 + //动态分配列宽
  566 + Class.prototype.setColsWidth = function () {
  567 + var that = this
  568 + , options = that.config
  569 + , colNums = 0 //列个数
  570 + , autoColNums = 0 //自动列宽的列个数
  571 + , autoWidth = 0 //自动列分配的宽度
  572 + , countWidth = 0 //所有列总宽度和
  573 + , cntrWidth = that.setInit('width');
  574 +
  575 + //统计列个数
  576 + that.eachCols(function (i, item) {
  577 + item.hide || colNums++;
  578 + });
  579 +
  580 + //减去边框差和滚动条宽
  581 + cntrWidth = cntrWidth - function () {
  582 + return (options.skin === 'line' || options.skin === 'nob') ? 2 : colNums + 1;
  583 + }() - that.getScrollWidth(that.layMain[0]) - 1;
  584 +
  585 + //计算自动分配的宽度
  586 + var getAutoWidth = function (back) {
  587 + //遍历所有列
  588 + layui.each(options.cols, function (i1, item1) {
  589 + layui.each(item1, function (i2, item2) {
  590 + var width = 0
  591 + , minWidth = item2.minWidth || options.cellMinWidth; //最小宽度
  592 +
  593 + if (!item2) {
  594 + item1.splice(i2, 1);
  595 + return;
  596 + }
  597 +
  598 + if (item2.colGroup || item2.hide) return;
  599 +
  600 + if (!back) {
  601 + width = item2.width || 0;
  602 + if (/\d+%$/.test(width)) { //列宽为百分比
  603 + width = Math.floor((parseFloat(width) / 100) * cntrWidth);
  604 + width < minWidth && (width = minWidth);
  605 + } else if (!width) { //列宽未填写
  606 + item2.width = width = 0;
  607 + autoColNums++;
  608 + }
  609 + } else if (autoWidth && autoWidth < minWidth) {
  610 + autoColNums--;
  611 + width = minWidth;
  612 + }
  613 +
  614 + if (item2.hide) width = 0;
  615 + countWidth = countWidth + width;
  616 + });
  617 + });
  618 +
  619 + //如果未填充满,则将剩余宽度平分
  620 + (cntrWidth > countWidth && autoColNums) && (
  621 + autoWidth = (cntrWidth - countWidth) / autoColNums
  622 + );
  623 + }
  624 +
  625 + getAutoWidth();
  626 + getAutoWidth(true); //重新检测分配的宽度是否低于最小列宽
  627 +
  628 + //记录自动列数
  629 + that.autoColNums = autoColNums;
  630 +
  631 + //设置列宽
  632 + that.eachCols(function (i3, item3) {
  633 + var minWidth = item3.minWidth || options.cellMinWidth;
  634 + if (item3.colGroup || item3.hide) return;
  635 +
  636 + //给位分配宽的列平均分配宽
  637 + if (item3.width === 0) {
  638 + that.getCssRule(options.index + '-' + item3.key, function (item) {
  639 + item.style.width = Math.floor(autoWidth >= minWidth ? autoWidth : minWidth) + 'px';
  640 + });
  641 + }
  642 +
  643 + //给设定百分比的列分配列宽
  644 + else if (/\d+%$/.test(item3.width)) {
  645 + that.getCssRule(options.index + '-' + item3.key, function (item) {
  646 + item.style.width = Math.floor((parseFloat(item3.width) / 100) * cntrWidth) + 'px';
  647 + });
  648 + }
  649 + });
  650 +
  651 + //填补 Math.floor 造成的数差
  652 + var patchNums = that.layMain.width() - that.getScrollWidth(that.layMain[0])
  653 + - that.layMain.children('table').outerWidth();
  654 +
  655 + if (that.autoColNums && patchNums >= -colNums && patchNums <= colNums) {
  656 + var getEndTh = function (th) {
  657 + var field;
  658 + th = th || that.layHeader.eq(0).find('thead th:last-child')
  659 + field = th.data('field');
  660 + if (!field && th.prev()[0]) {
  661 + return getEndTh(th.prev())
  662 + }
  663 + return th
  664 + }
  665 + , th = getEndTh()
  666 + , key = th.data('key');
  667 +
  668 + that.getCssRule(key, function (item) {
  669 + var width = item.style.width || th.outerWidth();
  670 + item.style.width = (parseFloat(width) + patchNums) + 'px';
  671 +
  672 + //二次校验,如果仍然出现横向滚动条(通常是 1px 的误差导致)
  673 + if (that.layMain.height() - that.layMain.prop('clientHeight') > 0) {
  674 + item.style.width = (parseFloat(item.style.width) - 1) + 'px';
  675 + }
  676 + });
  677 + }
  678 +
  679 + that.loading(!0);
  680 + };
  681 +
  682 + //重置表格尺寸/结构
  683 + Class.prototype.resize = function () {
  684 + var that = this;
  685 + that.fullSize(); //让表格铺满
  686 + that.setColsWidth(); //自适应列宽
  687 + that.scrollPatch(); //滚动条补丁
  688 + };
  689 +
  690 + //表格重载
  691 + Class.prototype.reload = function (options) {
  692 + var that = this;
  693 +
  694 + options = options || {};
  695 + delete that.haveInit;
  696 +
  697 + if (options.data && options.data.constructor === Array) delete that.config.data;
  698 + that.config = $.extend(true, {}, that.config, options);
  699 +
  700 + that.render();
  701 + };
  702 +
  703 + //异常提示
  704 + Class.prototype.errorView = function (html) {
  705 + var that = this
  706 + , elemNone = that.layMain.find('.' + NONE)
  707 + , layNone = $('<div class="' + NONE + '">' + (html || 'Error') + '</div>');
  708 +
  709 + if (elemNone[0]) {
  710 + that.layNone.remove();
  711 + elemNone.remove();
  712 + }
  713 +
  714 + that.layFixed.addClass(HIDE);
  715 + that.layMain.find('tbody').html('');
  716 +
  717 + that.layMain.append(that.layNone = layNone);
  718 +
  719 + table.cache[that.key] = []; //格式化缓存数据
  720 + };
  721 +
  722 + //页码
  723 + Class.prototype.page = 1;
  724 +
  725 + //获得数据
  726 + Class.prototype.pullData = function (curr) {
  727 + var that = this
  728 + , options = that.config
  729 + , request = options.request
  730 + , response = options.response
  731 + , sort = function () {
  732 + if (typeof options.initSort === 'object') {
  733 + that.sort(options.initSort.field, options.initSort.type);
  734 + }
  735 + };
  736 +
  737 + that.startTime = new Date().getTime(); //渲染开始时间
  738 +
  739 + if (options.url) { //Ajax请求
  740 + var params = {};
  741 + params[request.pageName] = curr;
  742 + params[request.limitName] = options.limit;
  743 +
  744 + //参数
  745 + var data = $.extend(params, options.where);
  746 + if (options.contentType && options.contentType.indexOf("application/json") == 0) { //提交 json 格式
  747 + data = JSON.stringify(data);
  748 + }
  749 +
  750 + that.loading();
  751 +
  752 + admin.req({
  753 + type: options.method || 'get'
  754 + , url: options.url
  755 + , contentType: options.contentType
  756 + , data: data
  757 + , dataType: 'json'
  758 + , headers: options.headers || {}
  759 + , success: function (res) {
  760 + //如果有数据解析的回调,则获得其返回的数据
  761 + if (typeof options.parseData === 'function') {
  762 + res = options.parseData(res) || res;
  763 + }
  764 + //检查数据格式是否符合规范
  765 + if (res[response.statusName] != response.statusCode) {
  766 + that.renderForm();
  767 + that.errorView(
  768 + res[response.msgName] ||
  769 + ('返回的数据不符合规范,正确的成功状态码应为:"' + response.statusName + '": ' + response.statusCode)
  770 + );
  771 + } else {
  772 + that.renderData(res, curr, res[response.countName]), sort();
  773 + options.time = (new Date().getTime() - that.startTime) + ' ms'; //耗时(接口请求+视图渲染)
  774 + }
  775 + that.setColsWidth();
  776 + typeof options.done === 'function' && options.done(res, curr, res[response.countName]);
  777 + }
  778 + , error: function (e, m) {
  779 + that.errorView('数据接口请求异常:' + m);
  780 +
  781 + that.renderForm();
  782 + that.setColsWidth();
  783 + }
  784 + });
  785 + } else if (options.data && options.data.constructor === Array) { //已知数据
  786 + var res = {}
  787 + , startLimit = curr * options.limit - options.limit
  788 +
  789 + res[response.dataName] = options.data.concat().splice(startLimit, options.limit);
  790 + res[response.countName] = options.data.length;
  791 +
  792 + //记录合计行数据
  793 + if (typeof options.totalRow === 'object') {
  794 + res[response.totalRowName] = $.extend({}, options.totalRow);
  795 + }
  796 +
  797 + that.renderData(res, curr, res[response.countName]), sort();
  798 + that.setColsWidth();
  799 + typeof options.done === 'function' && options.done(res, curr, res[response.countName]);
  800 + }
  801 + };
  802 +
  803 + //遍历表头
  804 + Class.prototype.eachCols = function (callback) {
  805 + var that = this;
  806 + table.eachCols(null, callback, that.config.cols);
  807 + return that;
  808 + };
  809 +
  810 + //数据渲染
  811 + Class.prototype.renderData = function (res, curr, count, sort) {
  812 + var that = this
  813 + , options = that.config
  814 + , data = res[options.response.dataName] || [] //列表数据
  815 + , totalRowData = res[options.response.totalRowName] //合计行数据
  816 + , trs = []
  817 + , trs_fixed = []
  818 + , trs_fixed_r = []
  819 +
  820 + //渲染视图
  821 + , render = function () { //后续性能提升的重点
  822 + var thisCheckedRowIndex;
  823 + if (!sort && that.sortKey) {
  824 + return that.sort(that.sortKey.field, that.sortKey.sort, true);
  825 + }
  826 + layui.each(data, function (i1, item1) {
  827 + var tds = [], tds_fixed = [], tds_fixed_r = []
  828 + , numbers = i1 + options.limit * (curr - 1) + 1; //序号
  829 +
  830 + if (item1.length === 0) return;
  831 +
  832 + if (!sort || !options.autoSort) {
  833 + item1[table.config.indexName] = i1;
  834 + }
  835 +
  836 + that.eachCols(function (i3, item3) {
  837 + var field = item3.field || i3
  838 + , key = options.index + '-' + item3.key
  839 + , content = item1[field];
  840 +
  841 + if (content === undefined || content === null) content = '';
  842 + if (item3.colGroup) return;
  843 +
  844 + //td内容
  845 + var td = ['<td data-field="' + field + '" data-key="' + key + '" ' + function () { //追加各种属性
  846 + var attr = [];
  847 + if (item3.edit) attr.push('data-edit="' + item3.edit + '"'); //是否允许单元格编辑
  848 + if (item3.align) attr.push('align="' + item3.align + '"'); //对齐方式
  849 + if (item3.templet) attr.push('data-content="' + content + '"'); //自定义模板
  850 + if (item3.toolbar) attr.push('data-off="true"'); //行工具列关闭单元格事件
  851 + if (item3.event) attr.push('lay-event="' + item3.event + '"'); //自定义事件
  852 + if (item3.style) attr.push('style="' + item3.style + '"'); //自定义样式
  853 + if (item3.minWidth) attr.push('data-minwidth="' + item3.minWidth + '"'); //单元格最小宽度
  854 + return attr.join(' ');
  855 + }() + ' class="' + function () { //追加样式
  856 + var classNames = [];
  857 + if (item3.hide) classNames.push(HIDE); //插入隐藏列样式
  858 + if (!item3.field) classNames.push('layui-table-col-special'); //插入特殊列样式
  859 + return classNames.join(' ');
  860 + }() + '">'
  861 + , '<div class="layui-table-cell laytable-cell-' + function () { //返回对应的CSS类标识
  862 + return item3.type === 'normal' ? key
  863 + : (key + ' laytable-cell-' + item3.type);
  864 + }() + '">' + function () {
  865 + var tplData = $.extend(true, {
  866 + LAY_INDEX: numbers
  867 + }, item1)
  868 + , checkName = table.config.checkName;
  869 +
  870 + //渲染不同风格的列
  871 + switch (item3.type) {
  872 + case 'checkbox':
  873 + return '<input type="checkbox" name="layTableCheckbox" lay-skin="primary" ' + function () {
  874 + //如果是全选
  875 + if (item3[checkName]) {
  876 + item1[checkName] = item3[checkName];
  877 + return item3[checkName] ? 'checked' : '';
  878 + }
  879 + return tplData[checkName] ? 'checked' : '';
  880 + }() + '>';
  881 + break;
  882 + case 'radio':
  883 + if (tplData[checkName]) {
  884 + thisCheckedRowIndex = i1;
  885 + }
  886 + return '<input type="radio" name="layTableRadio_' + options.index + '" '
  887 + + (tplData[checkName] ? 'checked' : '') + ' lay-type="layTableRadio">';
  888 + break;
  889 + case 'numbers':
  890 + return numbers;
  891 + break;
  892 + }
  893 + ;
  894 +
  895 + //解析工具列模板
  896 + if (item3.toolbar) {
  897 + return laytpl($(item3.toolbar).html() || '').render(tplData);
  898 + }
  899 + return parseTempData(item3, content, tplData);
  900 + }()
  901 + , '</div></td>'].join('');
  902 +
  903 + tds.push(td);
  904 + if (item3.fixed && item3.fixed !== 'right') tds_fixed.push(td);
  905 + if (item3.fixed === 'right') tds_fixed_r.push(td);
  906 + });
  907 +
  908 + trs.push('<tr data-index="' + i1 + '">' + tds.join('') + '</tr>');
  909 + trs_fixed.push('<tr data-index="' + i1 + '">' + tds_fixed.join('') + '</tr>');
  910 + trs_fixed_r.push('<tr data-index="' + i1 + '">' + tds_fixed_r.join('') + '</tr>');
  911 + });
  912 +
  913 + that.layBody.scrollTop(0);
  914 + that.layMain.find('.' + NONE).remove();
  915 + that.layMain.find('tbody').html(trs.join(''));
  916 + that.layFixLeft.find('tbody').html(trs_fixed.join(''));
  917 + that.layFixRight.find('tbody').html(trs_fixed_r.join(''));
  918 +
  919 + that.renderForm();
  920 + typeof thisCheckedRowIndex === 'number' && that.setThisRowChecked(thisCheckedRowIndex);
  921 + that.syncCheckAll();
  922 +
  923 + //滚动条补丁
  924 + that.haveInit ? that.scrollPatch() : setTimeout(function () {
  925 + that.scrollPatch();
  926 + }, 50);
  927 + that.haveInit = true;
  928 +
  929 + layer.close(that.tipsIndex);
  930 +
  931 + //同步表头父列的相关值
  932 + options.HAS_SET_COLS_PATCH || that.setColsPatch();
  933 + options.HAS_SET_COLS_PATCH = true;
  934 + };
  935 +
  936 + table.cache[that.key] = data; //记录数据
  937 +
  938 + //显示隐藏分页栏
  939 + that.layPage[(count == 0 || (data.length === 0 && curr == 1)) ? 'addClass' : 'removeClass'](HIDE);
  940 +
  941 + //排序
  942 + if (sort) {
  943 + return render();
  944 + }
  945 +
  946 + if (data.length === 0) {
  947 + that.renderForm();
  948 + return that.errorView(options.text.none);
  949 + } else {
  950 + that.layFixed.removeClass(HIDE);
  951 + }
  952 +
  953 + render(); //渲染数据
  954 + that.renderTotal(data, totalRowData); //数据合计
  955 +
  956 + //同步分页状态
  957 + if (options.page) {
  958 + options.page = $.extend({
  959 + elem: 'layui-table-page' + options.index
  960 + , count: count
  961 + , limit: options.limit
  962 + , limits: options.limits || [10, 20, 30, 40, 50, 60, 70, 80, 90]
  963 + , groups: 3
  964 + , layout: ['prev', 'page', 'next', 'skip', 'count', 'limit']
  965 + , prev: '<i class="layui-icon">&#xe603;</i>'
  966 + , next: '<i class="layui-icon">&#xe602;</i>'
  967 + , jump: function (obj, first) {
  968 + if (!first) {
  969 + //分页本身并非需要做以下更新,下面参数的同步,主要是因为其它处理统一用到了它们
  970 + //而并非用的是 options.page 中的参数(以确保分页未开启的情况仍能正常使用)
  971 + that.page = obj.curr; //更新页码
  972 + options.limit = obj.limit; //更新每页条数
  973 +
  974 + that.pullData(obj.curr);
  975 + }
  976 + }
  977 + }, options.page);
  978 + options.page.count = count; //更新总条数
  979 + // 分页组件展示顺序
  980 + options.page.layout = ['count','limit', 'prev', 'page', 'next', 'skip']
  981 + laypage.render(options.page);
  982 + }
  983 + };
  984 +
  985 + //数据合计行
  986 + Class.prototype.renderTotal = function (data, totalRowData) {
  987 + var that = this
  988 + , options = that.config
  989 + , totalNums = {};
  990 +
  991 + if (!options.totalRow) return;
  992 +
  993 + layui.each(data, function (i1, item1) {
  994 + if (item1.length === 0) return;
  995 +
  996 + that.eachCols(function (i3, item3) {
  997 + var field = item3.field || i3
  998 + , content = item1[field];
  999 +
  1000 + if (item3.totalRow) {
  1001 + totalNums[field] = (totalNums[field] || 0) + (parseFloat(content) || 0);
  1002 + }
  1003 + });
  1004 + });
  1005 +
  1006 + that.dataTotal = {};
  1007 +
  1008 + var tds = [];
  1009 + that.eachCols(function (i3, item3) {
  1010 + var field = item3.field || i3;
  1011 +
  1012 + //td内容
  1013 + var content = function () {
  1014 + var text = item3.totalRowText || ''
  1015 + , thisTotalNum = parseFloat(totalNums[field]).toFixed(2)
  1016 + , tplData = {};
  1017 +
  1018 + tplData[field] = thisTotalNum;
  1019 + thisTotalNum = parseTempData(item3, thisTotalNum, tplData);
  1020 +
  1021 + //如果直接传入了合计行数据,则不输出自动计算的结果
  1022 + if (totalRowData) {
  1023 + return totalRowData[item3.field] || text;
  1024 + } else {
  1025 + return item3.totalRow ? (thisTotalNum || text) : text;
  1026 + }
  1027 + }()
  1028 + ,
  1029 + td = ['<td data-field="' + field + '" data-key="' + options.index + '-' + item3.key + '" ' + function () {
  1030 + var attr = [];
  1031 + if (item3.align) attr.push('align="' + item3.align + '"'); //对齐方式
  1032 + if (item3.style) attr.push('style="' + item3.style + '"'); //自定义样式
  1033 + if (item3.minWidth) attr.push('data-minwidth="' + item3.minWidth + '"'); //单元格最小宽度
  1034 + return attr.join(' ');
  1035 + }() + ' class="' + function () { //追加样式
  1036 + var classNames = [];
  1037 + if (item3.hide) classNames.push(HIDE); //插入隐藏列样式
  1038 + if (!item3.field) classNames.push('layui-table-col-special'); //插入特殊列样式
  1039 + return classNames.join(' ');
  1040 + }() + '">'
  1041 + , '<div class="layui-table-cell laytable-cell-' + function () { //返回对应的CSS类标识
  1042 + var str = (options.index + '-' + item3.key);
  1043 + return item3.type === 'normal' ? str
  1044 + : (str + ' laytable-cell-' + item3.type);
  1045 + }() + '">' + content
  1046 + , '</div></td>'].join('');
  1047 +
  1048 + item3.field && (that.dataTotal[field] = content);
  1049 + tds.push(td);
  1050 + });
  1051 +
  1052 + that.layTotal.find('tbody').html('<tr>' + tds.join('') + '</tr>');
  1053 + };
  1054 +
  1055 + //找到对应的列元素
  1056 + Class.prototype.getColElem = function (parent, key) {
  1057 + var that = this
  1058 + , options = that.config;
  1059 + return parent.eq(0).find('.laytable-cell-' + (options.index + '-' + key) + ':eq(0)');
  1060 + };
  1061 +
  1062 + //渲染表单
  1063 + Class.prototype.renderForm = function (type) {
  1064 + form.render(type, 'LAY-table-' + this.index);
  1065 + };
  1066 +
  1067 + //标记当前行选中状态
  1068 + Class.prototype.setThisRowChecked = function (index) {
  1069 + var that = this
  1070 + , options = that.config
  1071 + , ELEM_CLICK = 'layui-table-click'
  1072 + , tr = that.layBody.find('tr[data-index="' + index + '"]');
  1073 +
  1074 + tr.addClass(ELEM_CLICK).siblings('tr').removeClass(ELEM_CLICK);
  1075 + };
  1076 +
  1077 + //数据排序
  1078 + Class.prototype.sort = function (th, type, pull, formEvent) {
  1079 + var that = this
  1080 + , field
  1081 + , res = {}
  1082 + , options = that.config
  1083 + , filter = options.elem.attr('lay-filter')
  1084 + , data = table.cache[that.key], thisData;
  1085 +
  1086 + //字段匹配
  1087 + if (typeof th === 'string') {
  1088 + that.layHeader.find('th').each(function (i, item) {
  1089 + var othis = $(this)
  1090 + , _field = othis.data('field');
  1091 + if (_field === th) {
  1092 + th = othis;
  1093 + field = _field;
  1094 + return false;
  1095 + }
  1096 + });
  1097 + }
  1098 +
  1099 + try {
  1100 + var field = field || th.data('field')
  1101 + , key = th.data('key');
  1102 +
  1103 + //如果欲执行的排序已在状态中,则不执行渲染
  1104 + if (that.sortKey && !pull) {
  1105 + if (field === that.sortKey.field && type === that.sortKey.sort) {
  1106 + return;
  1107 + }
  1108 + }
  1109 +
  1110 + var elemSort = that.layHeader.find('th .laytable-cell-' + key).find(ELEM_SORT);
  1111 + that.layHeader.find('th').find(ELEM_SORT).removeAttr('lay-sort'); //清除其它标题排序状态
  1112 + elemSort.attr('lay-sort', type || null);
  1113 + that.layFixed.find('th')
  1114 + } catch (e) {
  1115 + return hint.error('Table modules: Did not match to field');
  1116 + }
  1117 +
  1118 + //记录排序索引和类型
  1119 + that.sortKey = {
  1120 + field: field
  1121 + , sort: type
  1122 + };
  1123 +
  1124 + //默认为前端自动排序。如果否,则需自主排序(通常为服务端处理好排序)
  1125 + if (options.autoSort) {
  1126 + if (type === 'asc') { //升序
  1127 + thisData = layui.sort(data, field);
  1128 + } else if (type === 'desc') { //降序
  1129 + thisData = layui.sort(data, field, true);
  1130 + } else { //清除排序
  1131 + thisData = layui.sort(data, table.config.indexName);
  1132 + delete that.sortKey;
  1133 + }
  1134 + }
  1135 +
  1136 + res[options.response.dataName] = thisData || data;
  1137 + that.renderData(res, that.page, that.count, true);
  1138 +
  1139 + if (formEvent) {
  1140 + layui.event.call(th, MOD_NAME, 'sort(' + filter + ')', {
  1141 + field: field
  1142 + , type: type
  1143 + });
  1144 + }
  1145 + };
  1146 +
  1147 + //请求loading
  1148 + Class.prototype.loading = function (hide) {
  1149 + var that = this
  1150 + , options = that.config;
  1151 + if (options.loading) {
  1152 + if (hide) {
  1153 + that.layInit && that.layInit.remove();
  1154 + delete that.layInit;
  1155 + that.layBox.find(ELEM_INIT).remove();
  1156 + } else {
  1157 + that.layInit = $(['<div class="layui-table-init">'
  1158 + , '<i class="layui-icon loading-' + loadConfig.icon + ' layui-anim layui-anim-rotate layui-anim-loop"></i>'
  1159 + , '</div>'].join(''));
  1160 + that.layBox.append(that.layInit);
  1161 + }
  1162 + }
  1163 + };
  1164 +
  1165 + //同步选中值状态
  1166 + Class.prototype.setCheckData = function (index, checked) {
  1167 + var that = this
  1168 + , options = that.config
  1169 + , thisData = table.cache[that.key];
  1170 + if (!thisData[index]) return;
  1171 + if (thisData[index].constructor === Array) return;
  1172 + thisData[index][options.checkName] = checked;
  1173 + };
  1174 +
  1175 + //同步全选按钮状态
  1176 + Class.prototype.syncCheckAll = function () {
  1177 + var that = this
  1178 + , options = that.config
  1179 + , checkAllElem = that.layHeader.find('input[name="layTableCheckbox"]')
  1180 + , syncColsCheck = function (checked) {
  1181 + that.eachCols(function (i, item) {
  1182 + if (item.type === 'checkbox') {
  1183 + item[options.checkName] = checked;
  1184 + }
  1185 + });
  1186 + return checked;
  1187 + };
  1188 +
  1189 + if (!checkAllElem[0]) return;
  1190 +
  1191 + if (table.checkStatus(that.key).isAll) {
  1192 + if (!checkAllElem[0].checked) {
  1193 + checkAllElem.prop('checked', true);
  1194 + that.renderForm('checkbox');
  1195 + }
  1196 + syncColsCheck(true);
  1197 + } else {
  1198 + if (checkAllElem[0].checked) {
  1199 + checkAllElem.prop('checked', false);
  1200 + that.renderForm('checkbox');
  1201 + }
  1202 + syncColsCheck(false);
  1203 + }
  1204 + };
  1205 +
  1206 + //获取cssRule
  1207 + Class.prototype.getCssRule = function (key, callback) {
  1208 + var that = this
  1209 + , style = that.elem.find('style')[0]
  1210 + , sheet = style.sheet || style.styleSheet || {}
  1211 + , rules = sheet.cssRules || sheet.rules;
  1212 + layui.each(rules, function (i, item) {
  1213 + if (item.selectorText === ('.laytable-cell-' + key)) {
  1214 + return callback(item), true;
  1215 + }
  1216 + });
  1217 + };
  1218 +
  1219 + //让表格铺满
  1220 + Class.prototype.fullSize = function () {
  1221 + var that = this
  1222 + , options = that.config
  1223 + , height = options.height, bodyHeight;
  1224 +
  1225 + if (that.fullHeightGap) {
  1226 + height = _WIN.height() - that.fullHeightGap;
  1227 + if (height < 135) height = 135;
  1228 + that.elem.css('height', height);
  1229 + }
  1230 +
  1231 + if (!height) return;
  1232 +
  1233 + //减去列头区域的高度
  1234 + bodyHeight = parseFloat(height) - (that.layHeader.outerHeight() || 38); //此处的数字常量是为了防止容器处在隐藏区域无法获得高度的问题,暂时只对默认尺寸的表格做支持。
  1235 +
  1236 + //减去工具栏的高度
  1237 + if (options.toolbar) {
  1238 + bodyHeight = bodyHeight - (that.layTool.outerHeight() || 50);
  1239 + }
  1240 +
  1241 + //减去统计朗的高度
  1242 + if (options.totalRow) {
  1243 + bodyHeight = bodyHeight - (that.layTotal.outerHeight() || 40);
  1244 + }
  1245 +
  1246 + //减去分页栏的高度
  1247 + if (options.page) {
  1248 + bodyHeight = bodyHeight - (that.layPage.outerHeight() || 41);
  1249 + }
  1250 +
  1251 + that.layMain.css('height', bodyHeight - 2);
  1252 + };
  1253 +
  1254 + //获取滚动条宽度
  1255 + Class.prototype.getScrollWidth = function (elem) {
  1256 + var width = 0;
  1257 + if (elem) {
  1258 + width = elem.offsetWidth - elem.clientWidth;
  1259 + } else {
  1260 + elem = document.createElement('div');
  1261 + elem.style.width = '100px';
  1262 + elem.style.height = '100px';
  1263 + elem.style.overflowY = 'scroll';
  1264 +
  1265 + document.body.appendChild(elem);
  1266 + width = elem.offsetWidth - elem.clientWidth;
  1267 + document.body.removeChild(elem);
  1268 + }
  1269 + return width;
  1270 + };
  1271 +
  1272 + //滚动条补丁
  1273 + Class.prototype.scrollPatch = function () {
  1274 + var that = this
  1275 + , layMainTable = that.layMain.children('table')
  1276 + , scollWidth = that.layMain.width() - that.layMain.prop('clientWidth') //纵向滚动条宽度
  1277 + , scollHeight = that.layMain.height() - that.layMain.prop('clientHeight') //横向滚动条高度
  1278 + , getScrollWidth = that.getScrollWidth(that.layMain[0]) //获取主容器滚动条宽度,如果有的话
  1279 + , outWidth = layMainTable.outerWidth() - that.layMain.width() //表格内容器的超出宽度
  1280 +
  1281 + //添加补丁
  1282 + , addPatch = function (elem) {
  1283 + if (scollWidth && scollHeight) {
  1284 + elem = elem.eq(0);
  1285 + if (!elem.find('.layui-table-patch')[0]) {
  1286 + var patchElem = $('<th class="layui-table-patch"><div class="layui-table-cell"></div></th>'); //补丁元素
  1287 + patchElem.find('div').css({
  1288 + width: scollWidth
  1289 + });
  1290 + elem.find('tr').append(patchElem);
  1291 + }
  1292 + } else {
  1293 + elem.find('.layui-table-patch').remove();
  1294 + }
  1295 + }
  1296 +
  1297 + addPatch(that.layHeader);
  1298 + addPatch(that.layTotal);
  1299 +
  1300 + //固定列区域高度
  1301 + var mainHeight = that.layMain.height()
  1302 + , fixHeight = mainHeight - scollHeight;
  1303 + that.layFixed.find(ELEM_BODY).css('height', layMainTable.height() >= fixHeight ? fixHeight : 'auto');
  1304 +
  1305 + //表格宽度小于容器宽度时,隐藏固定列
  1306 + that.layFixRight[outWidth > 0 ? 'removeClass' : 'addClass'](HIDE);
  1307 +
  1308 + //操作栏
  1309 + that.layFixRight.css('right', scollWidth - 1);
  1310 + };
  1311 +
  1312 + //事件处理
  1313 + Class.prototype.events = function () {
  1314 + var that = this
  1315 + , options = that.config
  1316 + , _BODY = $('body')
  1317 + , dict = {}
  1318 + , th = that.layHeader.find('th')
  1319 + , resizing
  1320 + , ELEM_CELL = '.layui-table-cell'
  1321 + , filter = options.elem.attr('lay-filter');
  1322 +
  1323 + //工具栏操作事件
  1324 + that.layTool.on('click', '*[lay-event]', function (e) {
  1325 + var othis = $(this)
  1326 + , events = othis.attr('lay-event')
  1327 + , openPanel = function (sets) {
  1328 + var list = $(sets.list)
  1329 + , panel = $('<ul class="layui-table-tool-panel"></ul>');
  1330 +
  1331 + panel.html(list);
  1332 +
  1333 + //限制最大高度
  1334 + if (options.height) {
  1335 + panel.css('max-height', options.height - (that.layTool.outerHeight() || 50));
  1336 + }
  1337 +
  1338 + //插入元素
  1339 + othis.find('.layui-table-tool-panel')[0] || othis.append(panel);
  1340 + that.renderForm();
  1341 +
  1342 + panel.on('click', function (e) {
  1343 + layui.stope(e);
  1344 + });
  1345 +
  1346 + sets.done && sets.done(panel, list)
  1347 + };
  1348 +
  1349 + layui.stope(e);
  1350 + _DOC.trigger('table.tool.panel.remove');
  1351 + layer.close(that.tipsIndex);
  1352 +
  1353 + switch (events) {
  1354 + case 'LAYTABLE_COLS': //筛选列
  1355 + openPanel({
  1356 + list: function () {
  1357 + var lis = [];
  1358 + that.eachCols(function (i, item) {
  1359 + if (item.field && item.type == 'normal') {
  1360 + lis.push('<li><input type="checkbox" name="' + item.field + '" data-key="' + item.key + '" data-parentkey="' + (item.parentKey || '') + '" lay-skin="primary" ' + (item.hide ? '' : 'checked') + ' title="' + (item.title || item.field) + '" lay-filter="LAY_TABLE_TOOL_COLS"></li>');
  1361 + }
  1362 + });
  1363 + return lis.join('');
  1364 + }()
  1365 + , done: function () {
  1366 + form.on('checkbox(LAY_TABLE_TOOL_COLS)', function (obj) {
  1367 + var othis = $(obj.elem)
  1368 + , checked = this.checked
  1369 + , key = othis.data('key')
  1370 + , parentKey = othis.data('parentkey');
  1371 +
  1372 + layui.each(options.cols, function (i1, item1) {
  1373 + layui.each(item1, function (i2, item2) {
  1374 + if (i1 + '-' + i2 === key) {
  1375 + var hide = item2.hide;
  1376 +
  1377 + //同步勾选列的 hide 值和隐藏样式
  1378 + item2.hide = !checked;
  1379 + that.elem.find('*[data-key="' + options.index + '-' + key + '"]')
  1380 + [checked ? 'removeClass' : 'addClass'](HIDE);
  1381 +
  1382 + //根据列的显示隐藏,同步多级表头的父级相关属性值
  1383 + if (hide != item2.hide) {
  1384 + that.setParentCol(!checked, parentKey);
  1385 + }
  1386 +
  1387 + //重新适配尺寸
  1388 + that.resize();
  1389 + }
  1390 + });
  1391 + });
  1392 + });
  1393 + }
  1394 + });
  1395 + break;
  1396 + case 'LAYTABLE_EXPORT': //导出
  1397 + if (device.ie) {
  1398 + layer.tips('导出功能不支持 IE,请用 Chrome 等高级浏览器导出', this, {
  1399 + tips: 3
  1400 + })
  1401 + } else {
  1402 + openPanel({
  1403 + list: function () {
  1404 + return [
  1405 + '<li data-type="csv">导出到 Csv 文件</li>'
  1406 + , '<li data-type="xls">导出到 Excel 文件</li>'
  1407 + ].join('')
  1408 + }()
  1409 + , done: function (panel, list) {
  1410 + list.on('click', function () {
  1411 + var type = $(this).data('type')
  1412 + table.exportFile.call(that, options.id, null, type);
  1413 + });
  1414 + }
  1415 + });
  1416 + }
  1417 + break;
  1418 + case 'LAYTABLE_PRINT': //打印
  1419 + var printWin = window.open('打印窗口', '_blank')
  1420 + , style = ['<style>'
  1421 + , 'body{font-size: 12px; color: #666;}'
  1422 + , 'table{width: 100%; border-collapse: collapse; border-spacing: 0;}'
  1423 + , 'th,td{line-height: 20px; padding: 9px 15px; border: 1px solid #ccc; text-align: left; font-size: 12px; color: #666;}'
  1424 + , 'a{color: #666; text-decoration:none;}'
  1425 + , '*.layui-hide{display: none}'
  1426 + , '</style>'].join('')
  1427 + , html = $(that.layHeader.html()); //输出表头
  1428 +
  1429 + html.append(that.layMain.find('table').html()); //输出表体
  1430 + html.append(that.layTotal.find('table').html()) //输出合计行
  1431 +
  1432 + html.find('th.layui-table-patch').remove(); //移除补丁
  1433 + html.find('.layui-table-col-special').remove(); //移除特殊列
  1434 +
  1435 + printWin.document.write(style + html.prop('outerHTML'));
  1436 + printWin.document.close();
  1437 + printWin.print();
  1438 + printWin.close();
  1439 + break;
  1440 + }
  1441 +
  1442 + layui.event.call(this, MOD_NAME, 'toolbar(' + filter + ')', $.extend({
  1443 + event: events
  1444 + , config: options
  1445 + }, {}));
  1446 + });
  1447 +
  1448 + //拖拽调整宽度
  1449 + th.on('mousemove', function (e) {
  1450 + var othis = $(this)
  1451 + , oLeft = othis.offset().left
  1452 + , pLeft = e.clientX - oLeft;
  1453 + if (othis.data('unresize') || dict.resizeStart) {
  1454 + return;
  1455 + }
  1456 + dict.allowResize = othis.width() - pLeft <= 10; //是否处于拖拽允许区域
  1457 + _BODY.css('cursor', (dict.allowResize ? 'col-resize' : ''));
  1458 + }).on('mouseleave', function () {
  1459 + var othis = $(this);
  1460 + if (dict.resizeStart) return;
  1461 + _BODY.css('cursor', '');
  1462 + }).on('mousedown', function (e) {
  1463 + var othis = $(this);
  1464 + if (dict.allowResize) {
  1465 + var key = othis.data('key');
  1466 + e.preventDefault();
  1467 + dict.resizeStart = true; //开始拖拽
  1468 + dict.offset = [e.clientX, e.clientY]; //记录初始坐标
  1469 +
  1470 + that.getCssRule(key, function (item) {
  1471 + var width = item.style.width || othis.outerWidth();
  1472 + dict.rule = item;
  1473 + dict.ruleWidth = parseFloat(width);
  1474 + dict.minWidth = othis.data('minwidth') || options.cellMinWidth;
  1475 + });
  1476 + }
  1477 + });
  1478 +
  1479 + //拖拽中
  1480 + _DOC.on('mousemove', function (e) {
  1481 + if (dict.resizeStart) {
  1482 + e.preventDefault();
  1483 + if (dict.rule) {
  1484 + var setWidth = dict.ruleWidth + e.clientX - dict.offset[0];
  1485 + if (setWidth < dict.minWidth) setWidth = dict.minWidth;
  1486 + dict.rule.style.width = setWidth + 'px';
  1487 + layer.close(that.tipsIndex);
  1488 + }
  1489 + resizing = 1
  1490 + }
  1491 + }).on('mouseup', function (e) {
  1492 + if (dict.resizeStart) {
  1493 + dict = {};
  1494 + _BODY.css('cursor', '');
  1495 + that.scrollPatch();
  1496 + }
  1497 + if (resizing === 2) {
  1498 + resizing = null;
  1499 + }
  1500 + });
  1501 +
  1502 + //排序
  1503 + th.on('click', function (e) {
  1504 + var othis = $(this)
  1505 + , elemSort = othis.find(ELEM_SORT)
  1506 + , nowType = elemSort.attr('lay-sort')
  1507 + , type;
  1508 +
  1509 + if (!elemSort[0] || resizing === 1) return resizing = 2;
  1510 +
  1511 + if (nowType === 'asc') {
  1512 + type = 'desc';
  1513 + } else if (nowType === 'desc') {
  1514 + type = null;
  1515 + } else {
  1516 + type = 'asc';
  1517 + }
  1518 + that.sort(othis, type, null, true);
  1519 + }).find(ELEM_SORT + ' .layui-edge ').on('click', function (e) {
  1520 + var othis = $(this)
  1521 + , index = othis.index()
  1522 + , field = othis.parents('th').eq(0).data('field')
  1523 + layui.stope(e);
  1524 + if (index === 0) {
  1525 + that.sort(field, 'asc', null, true);
  1526 + } else {
  1527 + that.sort(field, 'desc', null, true);
  1528 + }
  1529 + });
  1530 +
  1531 + //数据行中的事件监听返回的公共对象成员
  1532 + var commonMember = function (sets) {
  1533 + var othis = $(this)
  1534 + , index = othis.parents('tr').eq(0).data('index')
  1535 + , tr = that.layBody.find('tr[data-index="' + index + '"]')
  1536 + , data = table.cache[that.key] || [];
  1537 +
  1538 +
  1539 + data = data[index] || {};
  1540 +
  1541 + return $.extend({
  1542 + tr: tr //行元素
  1543 + , data: table.clearCacheKey(data) //当前行数据
  1544 + , del: function () { //删除行数据
  1545 + table.cache[that.key][index] = [];
  1546 + tr.remove();
  1547 + that.scrollPatch();
  1548 + }
  1549 + , update: function (fields) { //修改行数据
  1550 + fields = fields || {};
  1551 + layui.each(fields, function (key, value) {
  1552 + if (key in data) {
  1553 + var templet, td = tr.children('td[data-field="' + key + '"]');
  1554 + data[key] = value;
  1555 + that.eachCols(function (i, item2) {
  1556 + if (item2.field == key && item2.templet) {
  1557 + templet = item2.templet;
  1558 + }
  1559 + });
  1560 + td.children(ELEM_CELL).html(parseTempData({
  1561 + templet: templet
  1562 + }, value, data));
  1563 + td.data('content', value);
  1564 + }
  1565 + });
  1566 + }
  1567 + }, sets);
  1568 + };
  1569 +
  1570 + //复选框选择
  1571 + that.elem.on('click', 'input[name="layTableCheckbox"]+', function () { //替代元素的 click 事件
  1572 + var checkbox = $(this).prev()
  1573 + , childs = that.layBody.find('input[name="layTableCheckbox"]')
  1574 + , index = checkbox.parents('tr').eq(0).data('index')
  1575 + , checked = checkbox[0].checked
  1576 + , isAll = checkbox.attr('lay-filter') === 'layTableAllChoose';
  1577 +
  1578 + //全选
  1579 + if (isAll) {
  1580 + childs.each(function (i, item) {
  1581 + item.checked = checked;
  1582 + that.setCheckData(i, checked);
  1583 + });
  1584 + that.syncCheckAll();
  1585 + that.renderForm('checkbox');
  1586 + } else {
  1587 + that.setCheckData(index, checked);
  1588 + that.syncCheckAll();
  1589 + }
  1590 +
  1591 + layui.event.call(checkbox[0], MOD_NAME, 'checkbox(' + filter + ')', commonMember.call(checkbox[0], {
  1592 + checked: checked
  1593 + , type: isAll ? 'all' : 'one'
  1594 + }));
  1595 + });
  1596 +
  1597 + //单选框选择
  1598 + that.elem.on('click', 'input[lay-type="layTableRadio"]+', function () {
  1599 + var radio = $(this).prev()
  1600 + , checked = radio[0].checked
  1601 + , thisData = table.cache[that.key]
  1602 + , index = radio.parents('tr').eq(0).data('index');
  1603 +
  1604 + //重置数据单选属性
  1605 + layui.each(thisData, function (i, item) {
  1606 + if (index === i) {
  1607 + item.LAY_CHECKED = true;
  1608 + } else {
  1609 + delete item.LAY_CHECKED;
  1610 + }
  1611 + });
  1612 + that.setThisRowChecked(index);
  1613 +
  1614 + layui.event.call(this, MOD_NAME, 'radio(' + filter + ')', commonMember.call(this, {
  1615 + checked: checked
  1616 + }));
  1617 + });
  1618 +
  1619 + //行事件
  1620 + that.layBody.on('mouseenter', 'tr', function () { //鼠标移入行
  1621 + var othis = $(this)
  1622 + , index = othis.index();
  1623 + if (othis.data('off')) return; //不触发事件
  1624 + that.layBody.find('tr:eq(' + index + ')').addClass(ELEM_HOVER)
  1625 + }).on('mouseleave', 'tr', function () { //鼠标移出行
  1626 + var othis = $(this)
  1627 + , index = othis.index();
  1628 + if (othis.data('off')) return; //不触发事件
  1629 + that.layBody.find('tr:eq(' + index + ')').removeClass(ELEM_HOVER)
  1630 + }).on('click', 'tr', function () { //单击行
  1631 + setRowEvent.call(this, 'row');
  1632 + }).on('dblclick', 'tr', function () { //双击行
  1633 + setRowEvent.call(this, 'rowDouble');
  1634 + });
  1635 +
  1636 + //创建行单击、双击事件监听
  1637 + var setRowEvent = function (eventType) {
  1638 + var othis = $(this);
  1639 + if (othis.data('off')) return; //不触发事件
  1640 + layui.event.call(this,
  1641 + MOD_NAME, eventType + '(' + filter + ')'
  1642 + , commonMember.call(othis.children('td')[0])
  1643 + );
  1644 + };
  1645 +
  1646 + //单元格编辑
  1647 + that.layBody.on('change', '.' + ELEM_EDIT, function () {
  1648 + var othis = $(this)
  1649 + , value = this.value
  1650 + , field = othis.parent().data('field')
  1651 + , index = othis.parents('tr').eq(0).data('index')
  1652 + , data = table.cache[that.key][index];
  1653 +
  1654 + data[field] = value; //更新缓存中的值
  1655 +
  1656 + layui.event.call(this, MOD_NAME, 'edit(' + filter + ')', commonMember.call(this, {
  1657 + value: value
  1658 + , field: field
  1659 + }));
  1660 + }).on('blur', '.' + ELEM_EDIT, function () {
  1661 + var templet
  1662 + , othis = $(this)
  1663 + , thisElem = this
  1664 + , field = othis.parent().data('field')
  1665 + , index = othis.parents('tr').eq(0).data('index')
  1666 + , data = table.cache[that.key][index];
  1667 + that.eachCols(function (i, item) {
  1668 + if (item.field == field && item.templet) {
  1669 + templet = item.templet;
  1670 + }
  1671 + });
  1672 + othis.siblings(ELEM_CELL).html(function (value) {
  1673 + return parseTempData({
  1674 + templet: templet
  1675 + }, value, data);
  1676 + }(thisElem.value));
  1677 + othis.parent().data('content', thisElem.value);
  1678 + othis.remove();
  1679 + });
  1680 +
  1681 + /*列表上链接点击后颜色高亮凸显*/
  1682 + that.layBody.on('click', '.layui-table-link', function (e) {
  1683 + let othat = $(this);
  1684 +
  1685 + othat.parents('table').find('tr').removeClass('tbody-tr-background-color');
  1686 + othat.parents('table').find('tr').css('background-color', '');
  1687 + othat.parents('tr').css('background-color', '#d0ddec');
  1688 + })
  1689 + /*列表上链接点击后颜色高亮凸显*/
  1690 +
  1691 + //单元格单击事件
  1692 + that.layBody.on('click', 'td', function (e) {
  1693 + var othis = $(this)
  1694 + , field = othis.data('field')
  1695 + , editType = othis.data('edit')
  1696 + , elemCell = othis.children(ELEM_CELL);
  1697 +
  1698 + if (othis.data('off')) return; //不触发事件
  1699 +
  1700 + //显示编辑表单
  1701 + if (editType) {
  1702 + var input = $('<input class="layui-input ' + ELEM_EDIT + '">');
  1703 + input[0].value = othis.data('content') || elemCell.text();
  1704 + othis.find('.' + ELEM_EDIT)[0] || othis.append(input);
  1705 + input.focus();
  1706 + layui.stope(e);
  1707 + return;
  1708 + }
  1709 + }).on('mouseenter', 'td', function () {
  1710 + gridExpand.call(this)
  1711 + }).on('mouseleave', 'td', function () {
  1712 + gridExpand.call(this, 'hide');
  1713 + });
  1714 +
  1715 + //单元格展开图标
  1716 + var ELEM_GRID = 'layui-table-grid', ELEM_GRID_DOWN = 'layui-table-grid-down',
  1717 + ELEM_GRID_PANEL = 'layui-table-grid-panel'
  1718 + , gridExpand = function (hide) {
  1719 + var othis = $(this)
  1720 + , elemCell = othis.children(ELEM_CELL);
  1721 +
  1722 + if (othis.data('off')) return; //不触发事件
  1723 +
  1724 + if (hide) {
  1725 + othis.find('.layui-table-grid-down').remove();
  1726 + } else if (elemCell.prop('scrollWidth') > elemCell.outerWidth()) {
  1727 + if (elemCell.find('.' + ELEM_GRID_DOWN)[0]) return;
  1728 + othis.append('<div class="' + ELEM_GRID_DOWN + '"><i class="layui-icon layui-icon-down"></i></div>');
  1729 + }
  1730 + };
  1731 +
  1732 + //单元格展开事件
  1733 + that.layBody.on('click', '.' + ELEM_GRID_DOWN, function (e) {
  1734 + var othis = $(this)
  1735 + , td = othis.parent()
  1736 + , elemCell = td.children(ELEM_CELL);
  1737 +
  1738 + that.tipsIndex = layer.tips([
  1739 + '<div class="layui-table-tips-main" style="margin-top: -' + (elemCell.height() + 16) + 'px;' + function () {
  1740 + if (options.size === 'sm') {
  1741 + return 'padding: 4px 15px; font-size: 12px;';
  1742 + }
  1743 + if (options.size === 'lg') {
  1744 + return 'padding: 14px 15px;';
  1745 + }
  1746 + return '';
  1747 + }() + '">'
  1748 + , elemCell.html()
  1749 + , '</div>'
  1750 + , '<i class="layui-icon layui-table-tips-c layui-icon-close"></i>'
  1751 + ].join(''), elemCell[0], {
  1752 + tips: [3, '']
  1753 + , time: -1
  1754 + , anim: -1
  1755 + , maxWidth: (device.ios || device.android) ? 300 : that.elem.width() / 2
  1756 + , isOutAnim: false
  1757 + , skin: 'layui-table-tips'
  1758 + , success: function (layero, index) {
  1759 + layero.find('.layui-table-tips-c').on('click', function () {
  1760 + layer.close(index);
  1761 + });
  1762 + }
  1763 + });
  1764 +
  1765 + layui.stope(e);
  1766 + });
  1767 +
  1768 + //行工具条操作事件
  1769 + that.layBody.on('click', '*[lay-event]', function () {
  1770 + var othis = $(this)
  1771 + , index = othis.parents('tr').eq(0).data('index');
  1772 + layui.event.call(this, MOD_NAME, 'tool(' + filter + ')', commonMember.call(this, {
  1773 + event: othis.attr('lay-event')
  1774 + }));
  1775 + that.setThisRowChecked(index);
  1776 + });
  1777 +
  1778 + //同步滚动条
  1779 + that.layMain.on('scroll', function () {
  1780 + var othis = $(this)
  1781 + , scrollLeft = othis.scrollLeft()
  1782 + , scrollTop = othis.scrollTop();
  1783 +
  1784 + that.layHeader.scrollLeft(scrollLeft);
  1785 + that.layTotal.scrollLeft(scrollLeft);
  1786 + that.layFixed.find(ELEM_BODY).scrollTop(scrollTop);
  1787 +
  1788 + layer.close(that.tipsIndex);
  1789 + });
  1790 +
  1791 + //自适应
  1792 + _WIN.on('resize', function () {
  1793 + that.resize();
  1794 + });
  1795 + };
  1796 +
  1797 + //一次性事件
  1798 + ;(function () {
  1799 + //全局点击
  1800 + _DOC.on('click', function () {
  1801 + _DOC.trigger('table.remove.tool.panel');
  1802 + });
  1803 +
  1804 + //工具面板移除事件
  1805 + _DOC.on('table.remove.tool.panel', function () {
  1806 + $('.layui-table-tool-panel').remove();
  1807 + });
  1808 + })();
  1809 +
  1810 + //初始化
  1811 + table.init = function (filter, settings) {
  1812 + settings = settings || {};
  1813 + var that = this
  1814 + , elemTable = filter ? $('table[lay-filter="' + filter + '"]') : $(ELEM + '[lay-data]')
  1815 + , errorTips = 'Table element property lay-data configuration item has a syntax error: ';
  1816 +
  1817 + //遍历数据表格
  1818 + elemTable.each(function () {
  1819 + var othis = $(this), tableData = othis.attr('lay-data');
  1820 +
  1821 + try {
  1822 + tableData = new Function('return ' + tableData)();
  1823 + } catch (e) {
  1824 + hint.error(errorTips + tableData)
  1825 + }
  1826 +
  1827 + var cols = [], options = $.extend({
  1828 + elem: this
  1829 + , cols: []
  1830 + , data: []
  1831 + , skin: othis.attr('lay-skin') //风格
  1832 + , size: othis.attr('lay-size') //尺寸
  1833 + , even: typeof othis.attr('lay-even') === 'string' //偶数行背景
  1834 + }, table.config, settings, tableData);
  1835 +
  1836 + filter && othis.hide();
  1837 +
  1838 + //获取表头数据
  1839 + othis.find('thead>tr').each(function (i) {
  1840 + options.cols[i] = [];
  1841 + $(this).children().each(function (ii) {
  1842 + var th = $(this), itemData = th.attr('lay-data');
  1843 +
  1844 + try {
  1845 + itemData = new Function('return ' + itemData)();
  1846 + } catch (e) {
  1847 + return hint.error(errorTips + itemData)
  1848 + }
  1849 +
  1850 + var row = $.extend({
  1851 + title: th.text()
  1852 + , colspan: th.attr('colspan') || 0 //列单元格
  1853 + , rowspan: th.attr('rowspan') || 0 //行单元格
  1854 + }, itemData);
  1855 +
  1856 + if (row.colspan < 2) cols.push(row);
  1857 + options.cols[i].push(row);
  1858 + });
  1859 + });
  1860 +
  1861 + //获取表体数据
  1862 + othis.find('tbody>tr').each(function (i1) {
  1863 + var tr = $(this), row = {};
  1864 + //如果定义了字段名
  1865 + tr.children('td').each(function (i2, item2) {
  1866 + var td = $(this)
  1867 + , field = td.data('field');
  1868 + if (field) {
  1869 + return row[field] = td.html();
  1870 + }
  1871 + });
  1872 + //如果未定义字段名
  1873 + layui.each(cols, function (i3, item3) {
  1874 + var td = tr.children('td').eq(i3);
  1875 + row[item3.field] = td.html();
  1876 + });
  1877 + options.data[i1] = row;
  1878 + });
  1879 + table.render(options);
  1880 + });
  1881 +
  1882 + return that;
  1883 + };
  1884 +
  1885 + //记录所有实例
  1886 + thisTable.that = {}; //记录所有实例对象
  1887 + thisTable.config = {}; //记录所有实例配置项
  1888 +
  1889 + //遍历表头
  1890 + table.eachCols = function (id, callback, cols) {
  1891 + var config = thisTable.config[id] || {}
  1892 + , arrs = [], index = 0;
  1893 +
  1894 + cols = $.extend(true, [], cols || config.cols);
  1895 +
  1896 + //重新整理表头结构
  1897 + layui.each(cols, function (i1, item1) {
  1898 + layui.each(item1, function (i2, item2) {
  1899 +
  1900 + //如果是组合列,则捕获对应的子列
  1901 + if (item2.colGroup) {
  1902 + var childIndex = 0;
  1903 + index++
  1904 + item2.CHILD_COLS = [];
  1905 +
  1906 + layui.each(cols[i1 + 1], function (i22, item22) {
  1907 + //如果子列已经被标注为{PARENT_COL_INDEX},或者子列累计 colspan 数等于父列定义的 colspan,则跳出当前子列循环
  1908 + if (item22.PARENT_COL_INDEX || (childIndex > 1 && childIndex == item2.colspan)) return;
  1909 +
  1910 + item22.PARENT_COL_INDEX = index;
  1911 +
  1912 + item2.CHILD_COLS.push(item22);
  1913 + childIndex = childIndex + parseInt(item22.colspan > 1 ? item22.colspan : 1);
  1914 + });
  1915 + }
  1916 +
  1917 + if (item2.PARENT_COL_INDEX) return; //如果是子列,则不进行追加,因为已经存储在父列中
  1918 + arrs.push(item2)
  1919 + });
  1920 + });
  1921 +
  1922 + //重新遍历列,如果有子列,则进入递归
  1923 + var eachArrs = function (obj) {
  1924 + layui.each(obj || arrs, function (i, item) {
  1925 + if (item.CHILD_COLS) return eachArrs(item.CHILD_COLS);
  1926 + typeof callback === 'function' && callback(i, item);
  1927 + });
  1928 + };
  1929 +
  1930 + eachArrs();
  1931 + };
  1932 +
  1933 + //表格选中状态
  1934 + table.checkStatus = function (id) {
  1935 + var nums = 0
  1936 + , invalidNum = 0
  1937 + , arr = []
  1938 + , data = table.cache[id] || [];
  1939 + //计算全选个数
  1940 + layui.each(data, function (i, item) {
  1941 + if (item.constructor === Array) {
  1942 + invalidNum++; //无效数据,或已删除的
  1943 + return;
  1944 + }
  1945 + if (item[table.config.checkName]) {
  1946 + nums++;
  1947 + arr.push(table.clearCacheKey(item));
  1948 + }
  1949 + });
  1950 + return {
  1951 + data: arr //选中的数据
  1952 + , isAll: data.length ? (nums === (data.length - invalidNum)) : false //是否全选
  1953 + };
  1954 + };
  1955 +
  1956 + //表格导出
  1957 + table.exportFile = function (id, data, type) {
  1958 + var that = this;
  1959 +
  1960 + data = data || table.clearCacheKey(table.cache[id]);
  1961 + type = type || 'csv';
  1962 +
  1963 + var config = thisTable.config[id] || {}
  1964 + , textType = ({
  1965 + csv: 'text/csv'
  1966 + , xls: 'application/vnd.ms-excel'
  1967 + })[type]
  1968 + , alink = document.createElement("a");
  1969 +
  1970 + if (device.ie) return hint.error('IE_NOT_SUPPORT_EXPORTS');
  1971 +
  1972 + alink.href = 'data:' + textType + ';charset=utf-8,\ufeff' + encodeURIComponent(function () {
  1973 + var dataTitle = [], dataMain = [], dataTotal = [];
  1974 +
  1975 + //表头和表体
  1976 + layui.each(data, function (i1, item1) {
  1977 + var vals = [];
  1978 + if (typeof id === 'object') { //如果 id 参数直接为表头数据
  1979 + layui.each(id, function (i, item) {
  1980 + i1 == 0 && dataTitle.push(item || '');
  1981 + });
  1982 + layui.each(table.clearCacheKey(item1), function (i2, item2) {
  1983 + vals.push('"' + (item2 || '') + '"');
  1984 + });
  1985 + } else {
  1986 + table.eachCols(id, function (i3, item3) {
  1987 + if (item3.field && item3.type == 'normal' && !item3.hide) {
  1988 + var content = item1[item3.field];
  1989 + if (content === undefined || content === null) content = '';
  1990 +
  1991 + i1 == 0 && dataTitle.push(item3.title || '');
  1992 + vals.push('"' + parseTempData(item3, content, item1, 'text') + '"');
  1993 + }
  1994 + });
  1995 + }
  1996 + dataMain.push(vals.join(','));
  1997 + });
  1998 +
  1999 + //表合计
  2000 + layui.each(that.dataTotal, function (key, value) {
  2001 + dataTotal.push(value);
  2002 + });
  2003 +
  2004 + return dataTitle.join(',') + '\r\n' + dataMain.join('\r\n') + '\r\n' + dataTotal.join(',');
  2005 + }());
  2006 +
  2007 + alink.download = (config.title || 'table_' + (config.index || '')) + '.' + type;
  2008 + document.body.appendChild(alink);
  2009 + alink.click();
  2010 + document.body.removeChild(alink);
  2011 + };
  2012 +
  2013 + //重置表格尺寸结构
  2014 + table.resize = function (id) {
  2015 + //如果指定表格唯一 id,则只执行该 id 对应的表格实例
  2016 + if (id) {
  2017 + var config = getThisTableConfig(id); //获取当前实例配置项
  2018 + if (!config) return;
  2019 +
  2020 + thisTable.that[id].resize();
  2021 +
  2022 + } else { //否则重置所有表格实例尺寸
  2023 + layui.each(thisTable.that, function () {
  2024 + this.resize();
  2025 + });
  2026 + }
  2027 + };
  2028 +
  2029 + //表格重载
  2030 + table.reload = function (id, options) {
  2031 + var config = getThisTableConfig(id); //获取当前实例配置项
  2032 + if (!config) return;
  2033 +
  2034 + var that = thisTable.that[id];
  2035 + that.reload(options);
  2036 +
  2037 + return thisTable.call(that);
  2038 + };
  2039 +
  2040 + //核心入口
  2041 + table.render = function (options) {
  2042 + var inst = new Class(options);
  2043 + return thisTable.call(inst);
  2044 + };
  2045 +
  2046 + //清除临时Key
  2047 + table.clearCacheKey = function (data) {
  2048 + data = $.extend({}, data);
  2049 + delete data[table.config.checkName];
  2050 + delete data[table.config.indexName];
  2051 + return data;
  2052 + };
  2053 +
  2054 + //自动完成渲染
  2055 + table.init();
  2056 +
  2057 + exports(MOD_NAME, table);
  2058 +});