123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586 |
- /**
- * 表格扩展模块
- * 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 = '<div>' + templets[j].templet(current) + '</div>';
- 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 = '<div class="tbx-dropdown-menu">';
- htmlStr += ' <div class="tbx-dropdown-menu-item" data-type="check">导出选中数据</div>';
- htmlStr += ' <div class="tbx-dropdown-menu-item" data-type="current">导出当前页数据</div>';
- htmlStr += ' <div class="tbx-dropdown-menu-item" data-type="all">导出全部数据</div>';
- htmlStr += ' </div>';
- $(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('<style>' + getCommonCss() + '</style>');
- exports("tableX", tableX);
- });
|