/** * 表格扩展模块 * date:2019-07-12 License By http://easyweb.vip */ layui.define(['layer', 'table', 'laytpl', 'form', 'util', 'contextMenu'], function (exports) { var $ = layui.jquery; var layer = layui.layer; var table = layui.table; var laytpl = layui.laytpl; var form = layui.form; var util = layui.util; var contextMenu = layui.contextMenu; var device = layui.device; var tbSearchAttr = 'tb-search'; // 前端搜索属性 var tbRefreshAttr = 'tb-refresh'; // 刷新按钮属性 var tbExportAttr = 'tb-export'; // 导出按钮属性 var txFieldPre = 'txField_'; // templte列filed前缀 var tableX = { // 合并相同单元格 merges: function (tableId, indexs, fields, sort) { // 检查参数是否为空 if (!tableId) { console.error('table filter not be null'); return; } if (!indexs) { console.warn('merge indexs not be null'); return; } if (typeof fields === 'boolean') { sort = fields; fields = undefined; } var $tb = $('[lay-filter="' + tableId + '"]+.layui-table-view>.layui-table-box>.layui-table-body>table'); var $trs = $tb.find('>tbody>tr'); $tb.addClass('layui-table-x'); // 合并一列 function merge(tableId, index, field) { var data = table.cache[tableId]; if (data.length > 0) { var lastValue, spanNum = 1; if (field) { lastValue = data[0][field]; } else { lastValue = $trs.eq(0).find('td').eq(index).find('.layui-table-cell').html(); } for (var i = 1; i < data.length; i++) { var currentValue; if (field) { currentValue = data[i][field]; } else { currentValue = $trs.eq(i).find('td').eq(index).find('.layui-table-cell').html(); } if (currentValue == lastValue) { spanNum++; if (i == data.length - 1) { $trs.eq(i - spanNum + 1).find('td').eq(index).attr('rowspan', spanNum); for (var j = 1; j < spanNum; j++) { $trs.eq(i - j + 1).find('td').eq(index).attr('del', 'true'); } } } else { $trs.eq(i - spanNum).find('td').eq(index).attr('rowspan', spanNum); for (var j = 1; j < spanNum; j++) { $trs.eq(i - j).find('td').eq(index).attr('del', 'true'); } spanNum = 1; lastValue = currentValue; } } } } // 循环合并每一列 for (var i = 0; i < indexs.length; i++) { if (!fields) { merge(tableId, indexs[i], undefined); } else { merge(tableId, indexs[i], fields[i]); } } $trs.find('[del="true"]').remove(); // 移除多余的单元格 // 监听排序事件 (sort == undefined) && (sort = true); if (sort) { table.on('sort(' + tableId + ')', function (obj) { tableX.merges(tableId, indexs, fields); }); } }, // 导出表格数据 exportData: function (param) { var cols = param.cols; // 表头 var dataList = param.data; // 数据 var fileName = param.fileName; // 文件名 var fileType = param.expType; // 类型,xls、csv var option = param.option; // url方式加载的配置 if (device.ie) return layer.msg('不支持ie导出'); // data为url先请求数据 if (dataList && typeof dataList === 'string') { var loadIndex = layer.msg('加载中..', {icon: 16, shade: 0.01, time: 0}); option.url = dataList; tableX.loadUrl(option, function (res) { layer.close(loadIndex); param.data = res; tableX.exportData(param); }); } // 列参数补全 for (var i = 0; i < cols.length; i++) { for (var j = 0; j < cols[i].length; j++) { if (cols[i][j].type == undefined) { cols[i][j].type = 'normal'; } if (cols[i][j].hide == undefined) { cols[i][j].hide = false; } } } var titles = [], fields = [], expData = []; // 获取表头和表头字段名 table.eachCols(undefined, function (i, item) { if (item.type == 'normal' && !item.hide) { titles.push(item.title ? item.title : ''); fields.push(item.field ? item.field : (txFieldPre + i)); } }, cols); // 格式化数据 var allList = tableX.parseTbData(cols, tableX.deepClone(dataList), true); for (var i = 0; i < allList.length; i++) { var rowItem = []; for (var j = 0; j < fields.length; j++) { var itemVal = allList[i][fields[j]]; if (typeof itemVal == 'string') { itemVal = itemVal.replace(/,/g, ','); } rowItem.push(itemVal); } expData.push(rowItem); } // 创建下载文件的a标签 var textType = ({csv: 'text/csv', xls: 'application/vnd.ms-excel'})[fileType]; var alink = document.createElement("a"); var getDataStr = function () { var dataTitle = [], dataMain = []; layui.each(expData, function (i1, item1) { var vals = []; layui.each(titles, function (i, item) { i1 == 0 && dataTitle.push(item || ''); }); layui.each(table.clearCacheKey(item1), function (i2, item2) { vals.push(item2); }); dataMain.push(vals.join(',')) }); return titles.join(',') + '\r\n' + expData.join('\r\n'); }; alink.href = 'data:' + textType + ';charset=utf-8,\ufeff' + encodeURIComponent(getDataStr()); alink.download = (fileName || 'table') + '.' + (fileType ? fileType : 'xls'); document.body.appendChild(alink); alink.click(); document.body.removeChild(alink); }, // 渲染表格,后端排序 render: function (param) { var tableId = $(param.elem).attr('lay-filter'); param.autoSort = false; // 关闭默认排序 var insTb = table.render(param); // 渲染表格 // 排序监听 table.on('sort(' + tableId + ')', function (obj) { var sortField = obj.field, sortType = obj.type; // 排序字段、类型 var sortWhere = $.extend(param.where, {sort: sortField, order: sortType}); insTb.reload({where: sortWhere, page: {curr: 1}}); }); return insTb; }, // 渲染表格,前端分页 renderFront: function (param) { var insTb, tableId = $(param.elem).attr('lay-filter'); param.autoSort = false; // 关闭默认排序 // 没有field的templet列补上,因为排序必须有filed字段,否则点击排序会报错 for (var i = 0; i < param.cols.length; i++) { for (var j = 0; j < param.cols[i].length; j++) { if (param.cols[i][j].templet && !param.cols[i][j].field) { param.cols[i][j].field = txFieldPre + i + '_' + j; } } } if (param.url) { // url方式 var xParam = tableX.deepClone(param); xParam.data = [], xParam.url = ''; insTb = table.render(xParam); // 先渲染表格结构 // 提供刷新方法 insTb.reloadUrl = function (p) { var reParam = tableX.deepClone(param); p && (reParam = $.extend(reParam, p)); var loadIndex = layer.msg('加载中..', {icon: 16, shade: 0.01, time: 0}); tableX.loadUrl(reParam, function (data) { // 获取url数据 layer.close(loadIndex); tableX.parseTbData(reParam.cols, data); // 解析temple列 tableX.putTbData(tableId, data); // 缓存数据 $('input[' + tbSearchAttr + '="' + tableId + '"]').val(''); // 清空搜索输入框 window.tbX.cacheSearch[tableId] = undefined; // 重置搜索结果 insTb.reload({url: '', data: data, page: {curr: 1}}); }); }; // 请求数据 var loadIndex = layer.msg('加载中..', {icon: 16, shade: 0.01, time: 0}); tableX.loadUrl(param, function (data) { // 获取url数据 layer.close(loadIndex); tableX.parseTbData(param.cols, data); // 解析temple列 tableX.putTbData(tableId, data); // 缓存数据 insTb.reload({url: '', data: data, page: {curr: 1}}); }); tableX.renderAllTool(insTb); // 渲染工具组件 } else { tableX.parseTbData(param.cols, param.data); // 解析temple列 tableX.putTbData(tableId, param.data); // 缓存数据 insTb = table.render(param); // 渲染表格 tableX.renderAllTool(insTb); // 渲染工具组件 // 提供刷新的方法 insTb.reloadData = function (p) { insTb.reload(p); tableX.parseTbData(param.cols, p.data); // 解析temple列 tableX.putTbData(tableId, p.data); $('input[' + tbSearchAttr + '="' + tableId + '"]').val(''); // 清空搜索输入框 window.tbX.cacheSearch[tableId] = undefined; // 重置搜索结果 }; } return insTb; }, // 渲染所有组件 renderAllTool: function (insTb) { renderRefresh(insTb); // 刷新 renderFrontSort(insTb); // 排序 renderFrontSearch(insTb); // 搜索 renderExport(insTb); // 导出 }, // 加载表格数据 loadUrl: function (options, callback) { // 响应数据的自定义格式 options.response = $.extend({ statusName: 'code', statusCode: 0, msgName: 'msg', dataName: 'data', countName: 'count' }, options.response); var request = options.request, response = options.response, params = {}; var data = $.extend(params, options.where); // 参数 if (options.contentType && options.contentType.indexOf("application/json") == 0) { data = JSON.stringify(data); // 提交 json 格式 } $.ajax({ type: options.method || 'get', url: options.url, contentType: options.contentType, data: data, dataType: 'json', headers: options.headers || {}, success: function (res) { // 如果有数据解析的回调,则获得其返回的数据 if (typeof options.parseData === 'function') { res = options.parseData(res) || res; } // 检查数据格式是否符合规范 if (res[response.statusName] != response.statusCode) { var msgText = res[response.msgName] || ('返回的数据不符合规范,正确的成功状态码 (' + response.statusName + ') 应为:' + response.statusCode); layer.msg(msgText, {icon: 2}); } else { callback(res[response.dataName]); } }, error: function (e, m) { layer.msg('数据接口请求异常:' + m, {icon: 2}); } }); }, // 解析数据表格templet列 parseTbData: function (cols, dataList, overwrite) { var templets = []; // 需要解析的列 table.eachCols(undefined, function (i, item) { if (item.templet) { var one = {field: ((item.field && (overwrite || item.field.indexOf(txFieldPre) == 0)) ? item.field : ('txField_' + i))}; if (typeof item.templet === 'string') { one.templet = function (d) { // templet列使用laytpl渲染 var rsStr = undefined; laytpl($(item.templet).html()).render(d, function (html) { rsStr = html; }); return rsStr; } } else { one.templet = item.templet; } templets.push(one); } }, cols); for (var i = 0; i < dataList.length; i++) { var current = dataList[i]; for (var j = 0; j < templets.length; j++) { var htmlStr = '
' + templets[j].templet(current) + '
'; current[templets[j].field] = $(htmlStr).not('.export-hide').text().replace(/(^\s*)|(\s*$)/g, ''); // 去除前后空格 } } return dataList; }, // 获取表格缓存的数据 getTbData: function (tableId) { var dataList = window.tbX.cache[tableId]; if (dataList == undefined) { dataList = table.cache[tableId]; } return tableX.deepClone(dataList); }, // 缓存表格的数据 putTbData: function (tableId, dataList) { window.tbX.cache[tableId] = dataList; return dataList; }, // 行绑定鼠标右键 bindCtxMenu: function (tableId, items) { var dataList = table.cache[tableId]; var elem = '#' + tableId + '+.layui-table-view .layui-table-body tr'; $(elem).bind('contextmenu', function (e) { var $tr = $(this); var trIndex = $(this).attr('data-index'); var tempItems = []; for (var i = 0; i < items.length; i++) { var item = items[i]; tempItems.push({ icon: item.icon, name: item.name, click: function () { var layId = $(this).attr('lay-id'); items[parseInt(layId.substring(8))].click(dataList[trIndex]); $tr.removeClass('layui-table-click'); } }); } $(elem).removeClass('layui-table-click'); $tr.addClass('layui-table-click'); contextMenu.show(tempItems, e.clientX, e.clientY); return false; }); }, // 搜索数据 filterData: function (dataList, searchName, searchValue) { var newList = [], sfs; for (var i = 0; i < dataList.length; i++) { var obj = dataList[i]; if (!sfs) { // 搜索的字段 if (!searchName) { sfs = []; for (var f in obj) { sfs.push(f); } } else { sfs = searchName.split(','); } } for (var j = 0; j < sfs.length; j++) { if (tableX.isContains(obj[sfs[j]], searchValue)) { newList.push(obj); break; } } } return newList; }, // 字符串是否包含 isContains: function (str1, str2) { str1 || (str1 = ''); str2 || (str2 = ''); str1 = str1.toString().toLowerCase(); str2 = str2.toString().toLowerCase(); if (str1 == str2 || str1.indexOf(str2) != -1) { return true; } return false; }, // 深度克隆对象 deepClone: function (obj) { var result; var oClass = tableX.isClass(obj); if (oClass === "Object") { result = {}; } else if (oClass === "Array") { result = []; } else { return obj; } for (var key in obj) { var copy = obj[key]; if (tableX.isClass(copy) == "Object") { result[key] = arguments.callee(copy);//递归调用 } else if (tableX.isClass(copy) == "Array") { result[key] = arguments.callee(copy); } else { result[key] = obj[key]; } } return result; }, // 获取变量类型 isClass: function (o) { if (o === null) return "Null"; if (o === undefined) return "Undefined"; return Object.prototype.toString.call(o).slice(8, -1); } }; // 创建数据缓存对象 window.tbX || (window.tbX = new Object()); window.tbX.cache || (window.tbX.cache = new Object()); window.tbX.cacheSearch || (window.tbX.cacheSearch = new Object()); // 前端搜索 var renderFrontSearch = function (insTb) { var tableId = insTb.config.id, $input = $('input[' + tbSearchAttr + '="' + tableId + '"]'); if (!($input && $input.length > 0)) { return; } if (!$input.attr('placeholder')) { $input.attr('placeholder', '输入关键字按回车键搜索'); } $input.off('keydown').on('keydown', function (event) { if (event.keyCode != 13) { return; } var searchName = $input.attr('name'); // 搜索的字段名,用逗号分隔 var searchValue = $input.val().replace(/(^\s*)|(\s*$)/g, ''); // 搜索关键字 var loadIndex = layer.msg('搜索中..', {icon: 16, shade: 0.01, time: 0}); var dataList = tableX.getTbData(tableId); var newDataList = tableX.filterData(dataList, searchName, searchValue); window.tbX.cacheSearch[tableId] = newDataList; // 缓存搜索后的数据用于排序 insTb.reload({url: '', data: newDataList, page: {curr: 1}}); layer.close(loadIndex); }); }; // 前端排序 var renderFrontSort = function (insTb) { var tableId = insTb.config.id; table.on('sort(' + tableId + ')', function (obj) { var sortField = obj.field, sortType = obj.type; // 排序字段、类型 var loadIndex = layer.msg('加载中..', {icon: 16, shade: 0.01, time: 0}); var dataList = window.tbX.cacheSearch[tableId]; // 表格搜索后的数据 dataList || (dataList = tableX.getTbData(tableId)); if (sortType) { dataList = dataList.sort(function (o1, o2) { var o1Str = o1[sortField], o2Str = o2[sortField]; if (sortType == 'asc') { // 升序 return (o1Str == o2Str) ? 0 : ((o1Str < o2Str) ? -1 : 1); } else { // 降序 return (o1Str == o2Str) ? 0 : ((o1Str < o2Str) ? 1 : -1); } }); } insTb.reload({initSort: obj, url: '', data: dataList, page: {curr: 1}}); layer.close(loadIndex); }); }; // 表格刷新按鈕 var renderRefresh = function (insTb) { $('[' + tbRefreshAttr + '="' + insTb.config.id + '"]').off('click').on('click', function () { if (insTb.reloadUrl) { insTb.reloadUrl(); } else { insTb.reload({page: {curr: 1}}); } }); }; // 渲染导出按钮 var renderExport = function (insTb) { var tableId = insTb.config.id; $('[' + tbExportAttr + '="' + tableId + '"]').off('click').on('click', function (event) { if ($(this).find('.tbx-dropdown-menu').length > 0) { return; } if (event !== void 0) { event.preventDefault(); event.stopPropagation(); } var htmlStr = '
'; htmlStr += '
导出选中数据
'; htmlStr += '
导出当前页数据
'; htmlStr += '
导出全部数据
'; htmlStr += '
'; $(this).append(htmlStr); $(this).addClass('tbx-dropdown-btn'); $(this).parent().css('position', 'relative'); $(this).parent().css('z-index', '9998'); $('.tbx-dropdown-menu').off('click').on('click', '.tbx-dropdown-menu-item', function (event) { var type = $(this).data('type'); if (type == 'check') { var checkRows = table.checkStatus(tableId); if (checkRows.data.length == 0) { layer.msg('请选择要导出的数据', {icon: 2}); } else { $('.tbx-dropdown-menu').remove(); tableX.exportData({ fileName: insTb.config.title, cols: insTb.config.cols, data: checkRows.data }); } } else if (type == 'current') { tableX.exportData({ fileName: insTb.config.title, cols: insTb.config.cols, data: table.cache[tableId] }); } else if (type == 'all') { tableX.exportData({ fileName: insTb.config.title, cols: insTb.config.cols, data: tableX.getTbData(tableId) }); } if (event !== void 0) { event.preventDefault(); event.stopPropagation(); } }); }); $(document).off('click.tbxDropHide').on('click.tbxDropHide', function () { $('.tbx-dropdown-menu').remove(); }); }; // css样式 var getCommonCss = function () { // 下拉菜单样式 var cssStr = '.tbx-dropdown-btn {'; cssStr += ' position: relative;'; cssStr += ' }'; cssStr += ' .tbx-dropdown-btn:hover {'; cssStr += ' opacity: 1'; cssStr += ' }'; cssStr += ' .tbx-dropdown-menu {'; cssStr += ' position: absolute;'; cssStr += ' top: 100%;'; cssStr += ' right: 0;'; cssStr += ' padding: 5px 0;'; cssStr += ' margin: 5px 0 0 0;'; cssStr += ' overflow: visible;'; cssStr += ' min-width: 110px;'; cssStr += ' background: #fff;'; cssStr += ' border-radius: 2px;'; cssStr += ' box-shadow: 0 2px 4px rgba(0, 0, 0, .12);'; cssStr += ' border: 1px solid #d2d2d2;'; cssStr += ' z-index: 9998;'; cssStr += ' cursor: default;'; cssStr += ' }'; cssStr += ' .tbx-dropdown-menu .tbx-dropdown-menu-item {'; cssStr += ' display: block;'; cssStr += ' color: #555;'; cssStr += ' font-size: 14px;'; cssStr += ' padding: 10px 15px;'; cssStr += ' text-decoration: none;'; cssStr += ' white-space: nowrap;'; cssStr += ' cursor: pointer;'; cssStr += ' user-select: none;'; cssStr += ' line-height: normal;'; cssStr += ' }'; cssStr += ' .tbx-dropdown-menu .tbx-dropdown-menu-item:hover {'; cssStr += ' background-color: #eeeeee;'; cssStr += ' }'; cssStr += ' .export-show {'; cssStr += ' display: none;'; cssStr += ' }'; return cssStr; }; $('head').append(''); exports("tableX", tableX); });