/** * 树形表格 2.x * date:2019-11-08 License By http://easyweb.vip */ layui.define(['layer', 'laytpl', 'form'], function (exports) { var $ = layui.jquery; var layer = layui.layer; var laytpl = layui.laytpl; var form = layui.form; var device = layui.device(); var MOD_NAME = 'treeTable'; // 绑定事件的模块名 // 改为同步加载css,避免滚动条补丁首次进入无效 $.ajax({ url: layui.cache.base + 'treetable/treeTable.css', async: false, success: function (res) { $('head').append(''); } }); /** TreeTable类构造方法 */ var TreeTable = function (options) { // 表格默认参数 var defaultOption = { elem: undefined, // table容器 data: [], // 数据 cols: [], // 列配置 reqData: undefined, // 异步加载数据的方法 width: undefined, // 容器宽度 height: undefined, // 容器高度 cellMinWidth: 100, // 单元格最小宽度 skin: undefined, // 表格风格 size: undefined, // 表格尺寸 even: undefined, // 是否开启隔行变色 style: undefined, // 容器样式 getThead: function () { // 获取表头 return getThead(this); }, getAllChooseBox: function () { // 获取全选按钮 return getAllChooseBox(this); }, getColgroup: function () { // 获取colgroup return getColgroup(this); }, getTbWidth: function () { // 计算table的宽度 return getTbWidth(this); }, tree: {}, text: {} }; // 默认tree参数 var treeDefaultOption = { idName: 'id', // id的字段名 pidName: 'pid', // pid的字段名 childName: 'children', // children的字段名 haveChildName: 'haveChild', // 是否有children标识的字段名 openName: 'open', // 是否默认展开的字段名 isPidData: false, // 是否是pid形式的数据 iconIndex: 0, // 图标列的索引 arrowType: undefined, // 箭头类型 onlyIconControl: false, // 仅允许点击图标折叠 getIcon: function (d) { // 自定义图标 return getIcon(d, this); } }; // 默认提示文本 var textDefaultOption = { none: '
暂无数据
' // 空文本提示文字 }; this.options = $.extend(defaultOption, options); this.options.tree = $.extend(treeDefaultOption, options.tree); this.options.text = $.extend(textDefaultOption, options.text); for (var i = 0; i < options.cols.length; i++) { // 列默认参数 var colDefaultOption = { field: undefined, // 字段名 title: undefined, // 标题 align: undefined, // 对齐方式 templet: undefined, // 自定义模板 toolbar: undefined, // 工具列 width: undefined, // 宽度 minWidth: undefined, // 最小宽度 type: undefined, // 列类型 style: undefined, // 单元格样式 class: '', // 单元格class singleLine: true, // 一行显示 fixed: undefined, // 固定列 unresize: false // 关闭拖拽列宽 }; this.options.cols[i] = $.extend(colDefaultOption, options.cols[i]); } this.init(); // 初始化表格 this.bindEvents(); // 绑定事件 }; /** 初始化表格 */ TreeTable.prototype.init = function () { var options = this.options; var tbFilter = options.elem.substring(1); // 树表格的filter var $elem = $(options.elem); // 原始表格 // 生成树表格dom $elem.removeAttr('lay-filter'); $elem.next('.ew-tree-table').remove(); var viewHtml = '
'; viewHtml += '
'; viewHtml += '
'; viewHtml += '
'; viewHtml += '
'; viewHtml += '
'; viewHtml += '
'; viewHtml += '
'; viewHtml += '
'; viewHtml += ' '; viewHtml += '
'; viewHtml += '
'; viewHtml += '
'; viewHtml += '
'; viewHtml += '
'; $elem.after(viewHtml); // 获取各个组件 var components = this.getComponents(); var $view = components.$view; // 容器 $view.attr('lay-filter', tbFilter); var $group = components.$group; // 表格容器 var $tbBox = components.$tbBox; // 表格主体部分容器 var $table = components.$table; // 主体表格 var $headTb = components.$headTb; // 表头表格 var $tbEmpty = components.$tbEmpty; // 空视图 var $tbLoading = components.$tbLoading; // 空视图 // 基础参数设置 options.skin && $table.attr('lay-skin', options.skin); options.size && $table.attr('lay-size', options.size); options.even && $table.attr('lay-even', options.even); // 容器边框调整 if (device.ie) { $view.find('.ew-tree-table-border.bottom').css('height', '1px'); $view.find('.ew-tree-table-border.right').css('width', '1px'); } // 固定宽度 if (options.width) { $view.css('width', options.width); $headTb.parent().css('width', options.width); $tbBox.css('width', options.width); } // col最小宽度 var tbWidth = options.getTbWidth(); if (tbWidth.setWidth) { $table.css('width', tbWidth.minWidth); $headTb.css('width', tbWidth.minWidth); } else { $table.css('min-width', tbWidth.minWidth); $headTb.css('min-width', tbWidth.minWidth); } // 渲染表结构及表头 var colgroupHtmlStr = options.getColgroup(); var headHtmlStr = colgroupHtmlStr + '' + options.getThead() + ''; if (options.height) { // 固定表头 $table.html(colgroupHtmlStr + ''); $headTb.html(headHtmlStr); $table.css('margin-top', '-1px'); if (options.height.indexOf('full-') == 0) { // 差值高度 var h = parseFloat(options.height.substring(5)); var cssStr = ''; $tbBox.after(cssStr); $tbBox.attr('ew-tree-full', h); } else { // 固定高度 $tbBox.css('height', options.height); } } else { $table.html(headHtmlStr + ''); } form.render('checkbox', tbFilter); // 渲染表头的表单元素 // 渲染数据 if (options.reqData) { // 异步加载 this.renderBodyAsync(); } else { // 一次性渲染 if (options.data && options.data.length > 0) { // 处理数据 if (options.tree.isPidData) { // pid形式数据 options.data = treeTb.pidToChildren(options.data, options.tree.idName, options.tree.pidName, options.tree.childName); } else { // children形式数据 addPidField(options.data, options.tree); } $table.children('tbody').html(this.renderBody(options.data)); $tbLoading.hide(); this.renderNumberCol(); // 渲染序号列 form.render(null, tbFilter); // 渲染表单元素 this.checkChooseAllCB(); // 联动全选框 updateFixedTbHead($view); } else { $tbLoading.hide(); $tbEmpty.show(); } } }; /** 绑定各项事件 */ TreeTable.prototype.bindEvents = function () { var that = this; var options = this.options; var components = this.getComponents(); var $view = components.$view; var $table = components.$table; var $tbEmpty = components.$tbEmpty; var tbFilter = components.tbFilter; var checkboxFilter = components.checkboxFilter; var radioFilter = components.radioFilter; var cbAllFilter = components.cbAllFilter; var $tbody = $table.children('tbody'); /** 行事件公共返回对象 */ var commonMember = function (ext) { var $tr = $(this); if (!$tr.is('tr')) { var $td_tr = $tr.parent('tr[data-id]'); if ($td_tr.length > 0) { $tr = $td_tr; } else { $tr = $tr.parentsUntil('tr[data-id]').last().parent(); } } var id = $tr.data('id'); var data = getDataById(options.data, id, options.tree); var obj = { tr: $tr, // 当前行 data: data, //当前行数据 del: function () { // 删除行 var indent = parseInt(this.tr.data('indent')); this.tr.nextAll('tr').each(function () { if (parseInt($(this).data('indent')) <= indent) { return false; } $(this).remove(); }); var $parentTr = this.tr.prevAll('tr'); this.tr.remove(); delDataById(options.data, id, options.tree); if (!options.data || options.data.length <= 0) { $tbEmpty.show(); } that.renderNumberCol(); // 渲染序号列 // 联动父级 $parentTr.each(function () { var tInd = parseInt($(this).data('indent')); if (tInd < indent) { that.checkParentCB($(this)); indent = tInd; } }); that.checkChooseAllCB(); // 联动全选框 }, update: function (fields) { // 修改行 data = $.extend(data, fields); var indent = parseInt(this.tr.data('indent')); that.renderBodyTr(data, indent, undefined, this.tr); form.render(null, tbFilter); // 渲染表单元素 that.checkIndeterminateCB(); // 恢复半选框状态 that.checkChooseAllCB(); // 联动全选框 } }; return $.extend(obj, ext); }; // 绑定折叠展开事件 $tbody.off('click.fold').on('click.fold', '.ew-tree-pack', function (e) { layui.stope(e); var $tr = $(this).parentsUntil('tr').last().parent(); if ($tr.hasClass('ew-tree-table-loading')) { // 已是加载中 return; } var haveChild = $tr.data('have-child'); if (haveChild != true && haveChild != 'true') { // 子节点 return; } var id = $tr.data('id'); var isOpen = $tr.hasClass('ew-tree-table-open'); var data = getDataById(options.data, id, options.tree); if (!isOpen && (!data[options.tree.childName] || data[options.tree.childName].length <= 0)) { that.renderBodyAsync(data, $tr); } else { toggleRow($tr); } }); // 绑定lay-event事件 $tbody.off('click.tool').on('click.tool', '*[lay-event]', function (e) { layui.stope(e); var $this = $(this); layui.event.call(this, MOD_NAME, 'tool(' + tbFilter + ')', commonMember.call(this, { event: $this.attr('lay-event') })); }); // 绑定单选框事件 form.on('radio(' + radioFilter + ')', function (data) { var d = getDataById(options.data, data.value, options.tree); that.removeAllChecked(); d.LAY_CHECKED = true; // 同时更新数据 layui.event.call(this, MOD_NAME, 'checkbox(' + tbFilter + ')', {checked: true, data: d, type: 'one'}); }); // 绑定复选框事件 form.on('checkbox(' + checkboxFilter + ')', function (data) { var checked = data.elem.checked; var $cb = $(data.elem); var $layCb = $cb.next('.layui-form-checkbox'); // 如果是半选状态,点击全选 if (!checked && $layCb.hasClass('ew-form-indeterminate')) { checked = true; $cb.prop('checked', checked); $cb.data('indeterminate', 'false'); $layCb.addClass('layui-form-checked'); $layCb.removeClass('ew-form-indeterminate'); } var d = getDataById(options.data, data.value, options.tree); d.LAY_CHECKED = checked; // 同时更新数据 // 联动操作 var $tr = $cb.parentsUntil('tr').last().parent(); if (d[options.tree.childName] && d[options.tree.childName].length > 0) { that.checkSubCB($tr, checked); // 联动子级 } var indent = parseInt($tr.data('indent')); $tr.prevAll('tr').each(function () { var tInd = parseInt($(this).data('indent')); if (tInd < indent) { that.checkParentCB($(this)); // 联动父级 indent = tInd; } }); that.checkChooseAllCB(); // 联动全选框 // 回调事件 layui.event.call(this, MOD_NAME, 'checkbox(' + tbFilter + ')', { checked: checked, data: d, type: 'one' }); }); // 绑定全选复选框事件 form.on('checkbox(' + cbAllFilter + ')', function (data) { var checked = data.elem.checked; var $cb = $(data.elem); var $layCb = $cb.next('.layui-form-checkbox'); if (!options.data || options.data.length <= 0) { // 如果数据为空 $cb.prop('checked', false); $cb.data('indeterminate', 'false'); $layCb.removeClass('layui-form-checked ew-form-indeterminate'); return; } // 如果是半选状态,点击全选 if (!checked && $layCb.hasClass('ew-form-indeterminate')) { checked = true; $cb.prop('checked', checked); $cb.data('indeterminate', 'false'); $layCb.addClass('layui-form-checked'); $layCb.removeClass('ew-form-indeterminate'); } layui.event.call(this, MOD_NAME, 'checkbox(' + tbFilter + ')', { checked: checked, data: undefined, type: 'all' }); that.checkSubCB($table.children('tbody'), checked); // 联动操作 }); // 绑定行单击事件 $tbody.off('click.row').on('click.row', 'tr', function () { layui.event.call(this, MOD_NAME, 'row(' + tbFilter + ')', commonMember.call(this, {})); }); // 绑定行双击事件 $tbody.off('dblclick.rowDouble').on('dblclick.rowDouble', 'tr', function () { layui.event.call(this, MOD_NAME, 'rowDouble(' + tbFilter + ')', commonMember.call(this, {})); }); // 绑定单元格点击事件 $tbody.off('click.cell').on('click.cell', 'td', function (e) { var $td = $(this); var type = $td.data('type'); // 判断是否是复选框、单选框列 if (type == 'checkbox' || type == 'radio') { layui.stope(e); return; } var edit = $td.data('edit'); var field = $td.data('field'); if (edit) { // 开启了单元格编辑 layui.stope(e); if ($tbody.find('.ew-tree-table-edit').length > 0) { return; } var index = $td.data('index'); var indentSize = $td.children('.ew-tree-table-indent').length; var id = $td.parent().data('id'); var d = getDataById(options.data, id, options.tree); if ('text' == edit || 'number' == edit) { // 文本框 var $input = $(''); $input[0].value = d[field]; $td.append($input); $input.focus(); $input.blur(function () { var value = $(this).val(); if (value == d[field]) { $(this).remove(); return; } var rs = layui.event.call(this, MOD_NAME, 'edit(' + tbFilter + ')', commonMember.call(this, { value: value, field: field })); if (rs == false) { $(this).addClass('layui-form-danger'); $(this).focus(); } else { d[field] = value; // 同步更新数据 that.renderBodyTd(d, indentSize, index, $td); // 更新单元格 } }); } else { console.error('不支持的单元格编辑类型:' + edit); } } else { // 回调单元格点击事件 var rs = layui.event.call(this, MOD_NAME, 'cell(' + tbFilter + ')', commonMember.call(this, { td: $td, field: field })); if (rs == false) { layui.stope(e); } } }); // 绑定单元格双击事件 $tbody.off('dblclick.cellDouble').on('dblclick.cellDouble', 'td', function (e) { var $td = $(this); var type = $td.data('type'); // 判断是否是复选框、单选框列 if (type == 'checkbox' || type == 'radio') { layui.stope(e); return; } var edit = $td.data('edit'); var field = $td.data('field'); if (edit) { // 开启了单元格编辑 layui.stope(e); } else { // 回调单元格双击事件 var rs = layui.event.call(this, MOD_NAME, 'cellDouble(' + tbFilter + ')', commonMember.call(this, { td: $td, field: field })); if (rs == false) { layui.stope(e); } } }); // 同步滚动条 components.$tbBox.on('scroll', function () { var $this = $(this); var scrollLeft = $this.scrollLeft(); var scrollTop = $this.scrollTop(); components.$headTb.parent().scrollLeft(scrollLeft); // $headGroup.scrollTop(scrollTop); }); // 列宽拖拽调整 /*$view.off('mousedown.resize').on('mousedown.resize', '.ew-tb-resize', function (e) { layui.stope(e); var index = $(this).parent().data('index'); $(this).data('move', 'true'); $(this).data('x', e.clientX); var w = $(this).parent().parent().parent().parent().children('colgroup').children('col').eq(index).attr('width'); $(this).data('width', w); }); $view.off('mousemove.resize').on('mousemove.resize', '.ew-tb-resize', function (e) { layui.stope(e); var move = $(this).data('move'); if ('true' == move) { var x = $(this).data('x'); var w = $(this).data('width'); var index = $(this).parent().data('index'); var nw = parseFloat(w) + e.clientX - parseFloat(x); $(this).parent().parent().parent().parent().children('colgroup').children('col').eq(index).attr('width', nw); } }); $view.off('mouseup.resize').on('mouseup.resize', '.ew-tb-resize', function (e) { layui.stope(e); $(this).data('move', 'false'); }); $view.off('mouseleave.resize').on('mouseleave.resize', '.ew-tb-resize', function (e) { layui.stope(e); $(this).data('move', 'false'); });*/ }; /** 获取各个组件 */ TreeTable.prototype.getComponents = function () { var $view = $(this.options.elem).next(); // 容器 var $group = $view.children('.ew-tree-table-group'); // 表格容器 var $tbBox = $group.children('.ew-tree-table-box'); // 表格主体部分容器 var $table = $tbBox.children('.layui-table'); // 主体表格 var $headTb = $group.children('.ew-tree-table-head').children('.layui-table'); // 表头表格 var $tbEmpty = $tbBox.children('.ew-tree-table-empty'); // 空视图 var $tbLoading = $tbBox.children('.ew-tree-table-loading'); // 加载视图 var tbFilter = $view.attr('lay-filter'); // 容器filter var checkboxFilter = 'ew_tb_checkbox_' + tbFilter; // 复选框filter var radioFilter = 'ew_tb_radio_' + tbFilter; // 单选框filter var cbAllFilter = 'ew_tb_choose_all_' + tbFilter; // 全选按钮filter return { $view: $view, $group: $group, $tbBox: $tbBox, $table: $table, $headTb: $headTb, $tbEmpty: $tbEmpty, $tbLoading: $tbLoading, tbFilter: tbFilter, checkboxFilter: checkboxFilter, radioFilter: radioFilter, cbAllFilter: cbAllFilter }; }; /** * 递归渲染表格主体部分 * @param data 数据列表 * @param indentSize 缩进大小 * @param isHide 是否默认隐藏 * @returns {string} */ TreeTable.prototype.renderBody = function (data, indentSize, isHide) { var options = this.options; var treeOption = options.tree; indentSize || (indentSize = 0); var htmlStr = ''; for (var i = 0; i < data.length; i++) { var d = data[i]; htmlStr += this.renderBodyTr(d, indentSize, isHide); // 递归渲染子集 var children = d[treeOption.childName]; if (children && children.length > 0) { htmlStr += this.renderBody(children, indentSize + 1, !d[treeOption.openName]); } } return htmlStr; }; /** * 渲染一行数据 * @param d 行数据 * @param option 配置 * @param indentSize 缩进大小 * @param isHide 是否隐藏 * @param $tr * @returns {string} */ TreeTable.prototype.renderBodyTr = function (d, indentSize, isHide, $tr) { var options = this.options; var cols = options.cols; var treeOption = options.tree; indentSize || (indentSize = 0); var htmlStr = ''; var haveChild = getHaveChild(d, treeOption); if ($tr) { $tr.data('pid', d[treeOption.pidName] || ''); $tr.data('have-child', haveChild); $tr.data('indent', indentSize); $tr.removeClass('ew-tree-table-loading'); } else { var classNames = ''; if (haveChild && d[treeOption.openName]) { classNames += 'ew-tree-table-open'; } if (isHide) { classNames += 'ew-tree-tb-hide'; } htmlStr += ''; } for (var j = 0; j < cols.length; j++) { var $td; if ($tr) { $td = $tr.children('td').eq(j); } htmlStr += this.renderBodyTd(d, indentSize, j, $td); } htmlStr += ''; return htmlStr; }; /** * 渲染每一个单元格数据 * @param d 行数据 * @param indentSize 缩进大小 * @param index 第几列 * @param $td * @returns {string} */ TreeTable.prototype.renderBodyTd = function (d, indentSize, index, $td) { var options = this.options; var col = options.cols[index]; var treeOption = options.tree; var components = this.getComponents(); var checkboxFilter = components.checkboxFilter; var radioFilter = components.radioFilter; indentSize || (indentSize = 0); // 内容填充 var fieldStr = ''; if (col.type == 'numbers') { // 序号列 fieldStr += ''; col.singleLine = false; } else if (col.type == 'checkbox') { // 复选框列 var attrStr = 'name="' + checkboxFilter + '" lay-filter="' + checkboxFilter + '" value="' + d[treeOption.idName] + '"'; attrStr += d.LAY_CHECKED ? ' checked="checked"' : ''; fieldStr += ''; col.singleLine = false; } else if (col.type == 'radio') { // 单选框列 var attrStr = 'name="' + radioFilter + '" lay-filter="' + radioFilter + '" value="' + d[treeOption.idName] + '"'; attrStr += d.LAY_CHECKED ? ' checked="checked"' : ''; fieldStr += ''; col.singleLine = false; } else if (col.templet) { // 自定义模板 if (typeof col.templet == 'function') { fieldStr += col.templet(d); } else if (typeof col.templet == 'string') { laytpl($(col.templet).html()).render(d, function (html) { fieldStr += html; }); } } else if (col.toolbar) { // 工具列 laytpl($(col.toolbar).html()).render(d, function (html) { fieldStr += html; }); } else if (col.field && d[col.field] != undefined && d[col.field] != null) { // 普通字段 fieldStr += d[col.field]; } var tdStr = ''; // 图标列处理 if (index == treeOption.iconIndex) { // 缩进 for (var k = 0; k < indentSize; k++) { tdStr += ''; } tdStr += ''; // 加箭头 var haveChild = getHaveChild(d, treeOption); tdStr += (''); // 加图标 tdStr += treeOption.getIcon(d); if (options.tree.onlyIconControl) { tdStr += ''; tdStr += ('' + fieldStr + ''); } else { tdStr += ('' + fieldStr + ''); tdStr += ''; } } else { tdStr += fieldStr; } if ($td && col.type != 'numbers') { $td.html(tdStr); } var htmlStr = '
' + tdStr + '
'); } else { htmlStr += tdStr; } htmlStr += ''; return htmlStr; }; /** * 异步加载渲染 * @param data 父级数据 * @param $tr 父级dom */ TreeTable.prototype.renderBodyAsync = function (d, $tr) { var that = this; var options = this.options; var components = this.getComponents(); var $tbEmpty = components.$tbEmpty; var $tbLoading = components.$tbLoading; // 显示loading if ($tr) { $tr.addClass('ew-tree-table-loading'); $tr.children('td').find('.ew-tree-pack').children('.ew-tree-table-arrow').addClass('layui-anim layui-anim-rotate layui-anim-loop'); } else { if (options.data && options.data.length > 0) { $tbLoading.addClass('ew-loading-float'); } $tbLoading.show(); $tbEmpty.hide(); } // 请求数据 options.reqData(d, function (res) { if (options.tree.isPidData) { res = treeTb.pidToChildren(res, options.tree.idName, options.tree.pidName, options.tree.childName); } that.renderBodyData(res, d, $tr); // 渲染内容 // 移除loading if ($tr) { $tr.removeClass('ew-tree-table-loading'); $tr.children('td').find('.ew-tree-pack').children('.ew-tree-table-arrow').removeClass('layui-anim layui-anim-rotate layui-anim-loop'); } else { $tbLoading.hide(); $tbLoading.removeClass('ew-loading-float'); // 是否为空 if (!res || res.length == 0) { $tbEmpty.show(); } else { $tbEmpty.hide(); } } }); }; /** * 根据数据渲染body * @param data 数据集合 * @param option 配置项 * @param d 父级数据 * @param $tr 父级dom */ TreeTable.prototype.renderBodyData = function (data, d, $tr) { var that = this; var options = this.options; var components = this.getComponents(); var $view = components.$view; var $table = components.$table; var tbFilter = components.tbFilter; addPidField(data, options.tree, d); // 补充pid字段 // 更新到数据 if (d == undefined) { options.data = data; } else { d[options.tree.childName] = data; } var indent; if ($tr) { indent = parseInt($tr.data('indent')) + 1; } var htmlStr = this.renderBody(data, indent); if ($tr) { // 移除旧dom $tr.nextAll('tr').each(function () { if (parseInt($(this).data('indent')) <= (indent - 1)) { return false; } $(this).remove(); }); // 渲染新dom $tr.after(htmlStr); $tr.addClass('ew-tree-table-open'); } else { $table.children('tbody').html(htmlStr); } form.render(null, tbFilter); // 渲染表单元素 this.renderNumberCol(); // 渲染序号列 this.checkIndeterminateCB(); // 恢复复选框半选状态 if ($tr) { // 更新父级复选框状态 this.checkParentCB($tr); $tr.prevAll('tr').each(function () { var tInd = parseInt($(this).data('indent')); if (tInd < (indent - 1)) { that.checkParentCB($(this)); indent = tInd + 1; } }); } this.checkChooseAllCB(); // 联动全选框 updateFixedTbHead($view); }; /** * 联动子级复选框状态 * @param $tr 当前tr的dom * @param checked */ TreeTable.prototype.checkSubCB = function ($tr, checked) { var that = this; var components = this.getComponents(); var cbFilter = components.checkboxFilter; var indent = -1, $trList; if ($tr.is('tbody')) { $trList = $tr.children('tr'); } else { indent = parseInt($tr.data('indent')); $trList = $tr.nextAll('tr') } $trList.each(function () { if (parseInt($(this).data('indent')) <= indent) { return false; } var $cb = $(this).children('td').find('input[name="' + cbFilter + '"]'); $cb.prop('checked', checked); if (checked) { $cb.data('indeterminate', 'false'); $cb.next('.layui-form-checkbox').addClass('layui-form-checked'); $cb.next('.layui-form-checkbox').removeClass('ew-form-indeterminate'); } else { $cb.data('indeterminate', 'false'); $cb.next('.layui-form-checkbox').removeClass('layui-form-checked ew-form-indeterminate'); } that.update($(this).data('id'), {LAY_CHECKED: checked}); // 同步更新数据 }); }; /** * 联动父级复选框状态 * @param $tr 父级的dom */ TreeTable.prototype.checkParentCB = function ($tr) { var that = this; var components = this.getComponents(); var cbFilter = components.checkboxFilter; var indent = parseInt($tr.data('indent')); var ckNum = 0, unCkNum = 0; $tr.nextAll('tr').each(function () { if (parseInt($(this).data('indent')) <= indent) { return false; } var $cb = $(this).children('td').find('input[name="' + cbFilter + '"]'); if ($cb.prop('checked')) { ckNum++; } else { unCkNum++; } }); var $cb = $tr.children('td').find('input[name="' + cbFilter + '"]'); if (ckNum > 0 && unCkNum == 0) { // 全选 $cb.prop('checked', true); $cb.data('indeterminate', 'false'); $cb.next('.layui-form-checkbox').addClass('layui-form-checked'); $cb.next('.layui-form-checkbox').removeClass('ew-form-indeterminate'); that.update($tr.data('id'), {LAY_CHECKED: true}); // 同步更新数据 } else if (ckNum == 0 && unCkNum > 0) { // 全不选 $cb.prop('checked', false); $cb.data('indeterminate', 'false'); $cb.next('.layui-form-checkbox').removeClass('layui-form-checked ew-form-indeterminate'); that.update($tr.data('id'), {LAY_CHECKED: false}); // 同步更新数据 } else if (ckNum > 0 && unCkNum > 0) { // 半选 $cb.prop('checked', true); $cb.data('indeterminate', 'true'); $cb.next('.layui-form-checkbox').addClass('layui-form-checked ew-form-indeterminate'); that.update($tr.data('id'), {LAY_CHECKED: true}); // 同步更新数据 } }; /** 联动全选复选框 */ TreeTable.prototype.checkChooseAllCB = function () { var components = this.getComponents(); var cbAllFilter = components.cbAllFilter; var cbFilter = components.checkboxFilter; var $tbody = components.$table.children('tbody'); var ckNum = 0, unCkNum = 0; $tbody.children('tr').each(function () { var $cb = $(this).children('td').find('input[name="' + cbFilter + '"]'); if ($cb.prop('checked')) { ckNum++; } else { unCkNum++; } }); var $cb = $('input[lay-filter="' + cbAllFilter + '"]'); if (ckNum > 0 && unCkNum == 0) { // 全选 $cb.prop('checked', true); $cb.data('indeterminate', 'false'); $cb.next('.layui-form-checkbox').addClass('layui-form-checked'); $cb.next('.layui-form-checkbox').removeClass('ew-form-indeterminate'); } else if ((ckNum == 0 && unCkNum > 0) || (ckNum == 0 && unCkNum == 0)) { // 全不选 $cb.prop('checked', false); $cb.data('indeterminate', 'false'); $cb.next('.layui-form-checkbox').removeClass('layui-form-checked ew-form-indeterminate'); } else if (ckNum > 0 && unCkNum > 0) { // 半选 $cb.prop('checked', true); $cb.data('indeterminate', 'true'); $cb.next('.layui-form-checkbox').addClass('layui-form-checked ew-form-indeterminate'); } }; /** 填充序号列 */ TreeTable.prototype.renderNumberCol = function () { var components = this.getComponents(); var $tbody = components.$table.children('tbody'); $tbody.children('tr').each(function (index) { $(this).children('td').find('.ew-tree-table-numbers').text(index + 1); }); }; /* 解决form.render之后半选框被重置的问题 */ TreeTable.prototype.checkIndeterminateCB = function () { var components = this.getComponents(); var cbFilter = components.checkboxFilter; $('input[lay-filter="' + cbFilter + '"]').each(function () { var $cb = $(this); if ($cb.data('indeterminate') == 'true' && $cb.prop('checked')) { $cb.next('.layui-form-checkbox').addClass('ew-form-indeterminate'); } }); }; /** * 搜索数据 * @param ids 关键字或数据id集合 */ TreeTable.prototype.filterData = function (ids) { var components = this.getComponents(); var $trList = components.$table.children('tbody').children('tr'); if (typeof ids == 'string') { // 关键字 var keyword = ids; ids = []; $trList.each(function () { var id = $(this).data('id'); $(this).children('td').each(function () { if ($(this).text().indexOf(keyword) != -1) { ids.push(id); return false; } }); }); } $trList.addClass('ew-tree-table-filter-hide'); for (var i = 0; i < ids.length; i++) { var $tr = $trList.filter('[data-id="' + ids[i] + '"]'); $tr.removeClass('ew-tree-table-filter-hide'); // 联动父级 var indent = parseInt($tr.data('indent')); $tr.prevAll('tr').each(function () { var tInd = parseInt($(this).data('indent')); if (tInd < indent) { $(this).removeClass('ew-tree-table-filter-hide'); // 联动父级 if (!$(this).hasClass('ew-tree-table-open')) { toggleRow($(this)); } indent = tInd; } }); } }; /** 重置搜索 */ TreeTable.prototype.clearFilter = function () { var components = this.getComponents(); var $trList = components.$table.children('tbody').children('tr'); $trList.removeClass('ew-tree-table-filter-hide'); }; /** 展开指定行 */ TreeTable.prototype.expand = function (id, cascade) { var components = this.getComponents(); var $tr = components.$table.children('tbody').children('tr[data-id="' + id + '"]'); if (!$tr.hasClass('ew-tree-table-open')) { $tr.children('td').find('.ew-tree-pack').trigger('click'); } if (cascade == false) { return; } // 联动父级 var indent = parseInt($tr.data('indent')); $tr.prevAll('tr').each(function () { var tInd = parseInt($(this).data('indent')); if (tInd < indent) { if (!$(this).hasClass('ew-tree-table-open')) { $(this).children('td').find('.ew-tree-pack').trigger('click'); } indent = tInd; } }); }; /** 折叠指定行 */ TreeTable.prototype.fold = function (id, cascade) { var components = this.getComponents(); var $tr = components.$table.children('tbody').children('tr[data-id="' + id + '"]'); if ($tr.hasClass('ew-tree-table-open')) { $tr.children('td').find('.ew-tree-pack').trigger('click'); } if (cascade == false) { return; } // 联动父级 var indent = parseInt($tr.data('indent')); $tr.prevAll('tr').each(function () { var tInd = parseInt($(this).data('indent')); if (tInd < indent) { if ($(this).hasClass('ew-tree-table-open')) { $(this).children('td').find('.ew-tree-pack').trigger('click'); } indent = tInd; } }); }; /** 全部展开 */ TreeTable.prototype.expandAll = function () { var that = this; var components = this.getComponents(); var $trList = components.$table.children('tbody').children('tr'); $trList.each(function () { that.expand($(this).data('id'), false); }); }; /** 全部折叠 */ TreeTable.prototype.foldAll = function () { var that = this; var components = this.getComponents(); var $trList = components.$table.children('tbody').children('tr'); $trList.each(function () { that.fold($(this).data('id'), false); }); }; /** 获取当前数据 */ TreeTable.prototype.getData = function () { return this.options.data; }; /** 重载表格 */ TreeTable.prototype.reload = function (opt) { treeTb.render($.extend(this.options, opt)); }; /** 根据id更新数据 */ TreeTable.prototype.update = function (id, fields) { var data = getDataById(this.getData(), id, this.options.tree); $.extend(data, fields); }; /** 根据id删除数据 */ TreeTable.prototype.del = function (id) { delDataById(this.getData(), id, this.options.tree); }; /** 获取当前选中行 */ TreeTable.prototype.checkStatus = function (needIndeterminate) { (needIndeterminate == undefined) && (needIndeterminate = true); var that = this; var components = this.getComponents(); var $table = components.$table; var checkboxFilter = components.checkboxFilter; var radioFilter = components.radioFilter; var list = []; // 获取单选框选中数据 var $radio = $table.find('input[name="' + radioFilter + '"]'); if ($radio.length > 0) { var id = $radio.filter(':checked').val(); var d = getDataById(this.getData(), id, this.options.tree); if (d) { list.push(d); } } else { // 获取复选框数据 $table.find('input[name="' + checkboxFilter + '"]:checked').each(function () { var id = $(this).val(); var isIndeterminate = $(this).next('.layui-form-checkbox').hasClass('ew-form-indeterminate'); if (needIndeterminate || !isIndeterminate) { var d = getDataById(that.getData(), id, that.options.tree); if (d) { d.isIndeterminate = isIndeterminate; list.push(d); } } }); } return list; }; /** 设置复/单选框选中 */ TreeTable.prototype.setChecked = function (ids) { var components = this.getComponents(); var $table = components.$table; var checkboxFilter = components.checkboxFilter; var radioFilter = components.radioFilter; var $radio = $table.find('input[name="' + radioFilter + '"]'); if ($radio.length > 0) { // 开启了单选框 $radio.each(function () { if (ids[ids.length - 1] == $(this).val()) { $(this).next('.layui-form-radio').trigger('click'); return false; } }); } else { // 开启了复选框 $table.find('input[name="' + checkboxFilter + '"]').each(function () { var $cb = $(this); var value = $cb.val(); var $layCb = $cb.next('.layui-form-checkbox'); for (var i = 0; i < ids.length; i++) { if (value == ids[i]) { var checked = $cb.prop('checked'); var indeterminate = $layCb.hasClass('ew-form-indeterminate'); if (!checked || indeterminate) { $layCb.trigger('click'); } } } }); } }; /** 移除全部选中 */ TreeTable.prototype.removeAllChecked = function () { var components = this.getComponents(); var $table = components.$table; var checkboxFilter = components.checkboxFilter; this.checkSubCB($table.children('tbody'), false); }; /** * 刷新指定父级下的节点 * @param id 父级id,空则全部刷新 * @param data 非异步模式替换的数据 */ TreeTable.prototype.refresh = function (id, data) { if (isClass(id) == 'Array') { data = id; id = undefined; } var components = this.getComponents(); var $table = components.$table; var d, $tr; if (id != undefined) { d = getDataById(this.getData(), id, this.options.tree); $tr = $table.children('tbody').children('tr[data-id="' + id + '"]'); } if (data) { // 数据模式 components.$tbLoading.addClass('ew-loading-float'); components.$tbLoading.show(); this.renderBodyData(data, d, $tr); components.$tbLoading.hide(); components.$tbLoading.removeClass('ew-loading-float'); if (data && data.length > 0) { components.$tbEmpty.hide(); } else { components.$tbEmpty.show(); } } else { // 异步模式 this.renderBodyAsync(d, $tr); } }; /** 生成表头 */ function getThead(options) { var htmlStr = ''; for (var i = 0; i < options.cols.length; i++) { var col = options.cols[i]; htmlStr += ''; } /** 获取列图标 */ function getIcon(d, treeOption) { if (getHaveChild(d, treeOption)) { return ''; } else { return ''; } } /** 折叠/展开行 */ function toggleRow($tr) { var indent = parseInt($tr.data('indent')); var isOpen = $tr.hasClass('ew-tree-table-open'); if (isOpen) { // 折叠 $tr.removeClass('ew-tree-table-open'); $tr.nextAll('tr').each(function () { if (parseInt($(this).data('indent')) <= indent) { return false; } $(this).addClass('ew-tree-tb-hide'); }); } else { // 展开 $tr.addClass('ew-tree-table-open'); var hideInd; $tr.nextAll('tr').each(function () { var ind = parseInt($(this).data('indent')); if (ind <= indent) { return false; } if (hideInd != undefined && ind > hideInd) { return true; } $(this).removeClass('ew-tree-tb-hide'); if (!$(this).hasClass('ew-tree-table-open')) { hideInd = parseInt($(this).data('indent')); } else { hideInd = undefined; } }); } updateFixedTbHead($tr.parent().parent().parent().parent().parent()); } /** 固定表头滚动条补丁 */ function updateFixedTbHead($view) { var $group = $view.children('.ew-tree-table-group'); var $headBox = $group.children('.ew-tree-table-head'); var $tbBox = $group.children('.ew-tree-table-box'); var sWidth = $tbBox.width() - $tbBox.prop('clientWidth'); if (sWidth > 0) { $headBox.css('border-right', sWidth + 'px solid #f2f2f2'); } else { $headBox.css('border-right', 'none'); } } // 监听窗口大小改变 $(window).resize(function () { $('.ew-tree-table').each(function () { updateFixedTbHead($(this)); var $tbBox = $(this).children('.ew-tree-table-group').children('.ew-tree-table-box'); var full = $tbBox.attr('ew-tree-full'); if (full && device.ie && device.ie < 10) { $tbBox.css('height', getPageHeight() - full); } }); }); // 表格溢出点击展开功能 $(document).on('mouseenter', '.ew-tree-table td', function () { var $tdSingle = $(this).children('.ew-tree-table-td-single'); var $content = $tdSingle.children('.ew-tree-tips'); if ($tdSingle.length > 0 && $content.prop('scrollWidth') > $content.outerWidth()) { $(this).append('
'); } }).on('mouseleave', '.ew-tree-table td', function () { $(this).children('.layui-table-grid-down').remove(); }); // 点击箭头展开 $(document).on('click', '.ew-tree-table td>.layui-table-grid-down', function (e) { hideAllTdTips(); var $tdSingle = $(this).parent().children('.ew-tree-table-td-single'); $tdSingle.addClass('ew-tree-tips-open'); var $box = $tdSingle.parents().filter('.ew-tree-table-box'); if ($box.length <= 0) { $box = $tdSingle.parents().filter('.ew-tree-table-head'); } if (($tdSingle.outerWidth() + $tdSingle.parent().offset().left) > $box.offset().left + $box.outerWidth()) { $tdSingle.addClass('ew-show-left'); } if (($tdSingle.outerHeight() + $tdSingle.parent().offset().top) > $box.offset().top + $box.outerHeight()) { $tdSingle.addClass('ew-show-bottom'); } e.stopPropagation(); }); // 点击关闭按钮关闭 $(document).on('click', '.ew-tree-table .ew-tree-tips-c', function (e) { hideAllTdTips(); }); // 点击空白部分关闭 $(document).on('click', function () { hideAllTdTips(); }); $(document).on('click', '.ew-tree-table-td-single.ew-tree-tips-open', function (e) { e.stopPropagation(); }); /* 关闭所有单元格溢出提示框 */ function hideAllTdTips() { var $single = $('.ew-tree-table-td-single'); $single.removeClass('ew-tree-tips-open'); $single.removeClass('ew-show-left'); } /** 判断是否还有子节点 */ function getHaveChild(d, treeOption) { var haveChild = false; if (d[treeOption.haveChildName] != undefined) { haveChild = d[treeOption.haveChildName]; haveChild = haveChild == true || haveChild == 'true'; } else if (d[treeOption.childName]) { haveChild = d[treeOption.childName].length > 0; } return haveChild; } /** 补充pid字段 */ function addPidField(data, treeOption, parent) { for (var i = 0; i < data.length; i++) { if (parent) { data[i][treeOption.pidName] = parent[treeOption.idName]; } if (data[i][treeOption.childName] && data[i][treeOption.childName].length > 0) { addPidField(data[i][treeOption.childName], treeOption, data[i]); } } } /** 根据id获取数据 */ function getDataById(data, id, treeOption) { for (var i = 0; i < data.length; i++) { if (data[i][treeOption.idName] == id) { return data[i]; } if (data[i][treeOption.childName] && data[i][treeOption.childName].length > 0) { var d = getDataById(data[i][treeOption.childName], id, treeOption); if (d != undefined) { return d; } } } } /** 根据id删除数据 */ function delDataById(data, id, treeOption) { for (var i = 0; i < data.length; i++) { if (data[i][treeOption.idName] == id) { data.splice(i, 1); return true; } if (data[i][treeOption.childName] && data[i][treeOption.childName].length > 0) { var rs = delDataById(data[i][treeOption.childName], id, treeOption); if (rs) { return true; } } } } /** 获取顶级的pId */ function getPids(list, idName, pidName) { var pids = []; for (var i = 0; i < list.length; i++) { var hasPid = false; for (var j = 0; j < list.length; j++) { if (i != j && list[j][idName] == list[i][pidName]) { hasPid = true; } } if (!hasPid) { pids.push(list[i][pidName]); } } return pids; } /** 判断pId是否相等 */ function pidEquals(pId, pIds) { if (isClass(pIds) == 'Array') { for (var i = 0; i < pIds.length; i++) { if (pId == pIds[i]) { return true; } } } else { return pId == pIds; } return false; } /** 获取变量类型 */ function isClass(o) { if (o === null) return 'Null'; if (o === undefined) return 'Undefined'; return Object.prototype.toString.call(o).slice(8, -1); } /* 获取浏览器高度 */ function getPageHeight() { return document.documentElement.clientHeight || document.body.clientHeight; } /* 获取浏览器宽度 */ function getPageWidth() { return document.documentElement.clientWidth || document.body.clientWidth; } /** 对外提供的方法 */ var treeTb = { /* 渲染 */ render: function (options) { return new TreeTable(options); }, /* 事件监听 */ on: function (events, callback) { return layui.onevent.call(this, MOD_NAME, events, callback); }, /* pid转children形式 */ pidToChildren: function (data, idName, pidName, childName, pId) { childName || (childName = 'children'); var newList = []; for (var i = 0; i < data.length; i++) { (pId == undefined) && (pId = getPids(data, idName, pidName)); if (pidEquals(data[i][pidName], pId)) { var children = this.pidToChildren(data, idName, pidName, childName, data[i][idName]); (children.length > 0) && (data[i][childName] = children); newList.push(data[i]); } } return newList; } }; exports('treeTable', treeTb); });