layui.define(['layer', 'table'], function (exports) { // 引入jQuery库 var $ = layui.jquery; // 引入layer模块 var layer = layui.layer; // 引入table模块 var table = layui.table; var treetable = { render: function (param) { // 检查参数是否合法 if (!treetable.checkParam(param)) { // 如果参数不合法,直接返回 return; } // 获取数据 if (param.data) { // 如果参数中包含数据,则直接初始化树表 treetable.init(param, param.data); } else { // 如果参数中不包含数据,则通过AJAX请求获取数据并初始化树表 $.getJSON(param.url, param.where, function (res) { treetable.init(param, res.data); }); } }, }; }); // 渲染表格 init: function (param, data) { // 存储处理后的数据 var mData = []; // 保存回调函数 var doneCallback = param.done; // 获取传入的节点数据 var tNodes = data; // 补上id和pid字段 for (var i = 0; i < tNodes.length; i++) { var tt = tNodes[i]; // 检查tt对象是否有id属性,如果没有则进行以下操作 if (!tt.id) { // 如果param对象中没有treeIdName属性,提示错误信息并返回 if (!param.treeIdName) { layer.msg('参数treeIdName不能为空', {icon: 5}); return; } // 将tt对象的id属性设置为tt对象中对应treeIdName属性的值 tt.id = tt[param.treeIdName]; } // 检查tt对象是否有pid属性,如果没有则进行以下操作 if (!tt.pid) { // 如果param对象中没有treePidName属性,提示错误信息并返回 if (!param.treePidName) { layer.msg('参数treePidName不能为空', {icon: 5}); return; } // 将tt对象的pid属性设置为tt对象中对应treePidName属性的值 tt.pid = tt[param.treePidName]; } var sort = function (s_pid, data) { // 遍历数据数组中的每一个元素 for (var i = 0; i < data.length; i++) { // 如果当前元素的父节点ID等于传入的父节点ID if (data[i].pid == s_pid) { // 获取mData数组的长度 var len = mData.length; // 如果mData数组不为空且最后一个元素的ID等于传入的父节点ID if (len > 0 && mData[len - 1].id == s_pid) { // 将最后一个元素的isParent属性设置为true mData[len - 1].isParent = true; } // 将当前元素添加到mData数组中 mData.push(data[i]); // 递归调用sort函数,处理当前元素的子节点 sort(data[i].id, data); } } }; sort(param.treeSpid, tNodes); // 对树形节点进行排序 param.url = undefined; // 将参数中的URL设置为undefined param.data = mData; // 将处理后的数据赋值给参数的data属性 param.page = { count: param.data.length, limit: param.data.length }; // 设置分页信息,count和limit都为数据的长度 param.cols[0][param.treeColIndex].templet = function (d) { // 定义树表列的模板函数 var mId = d.id; // 获取当前节点的ID var mPid = d.pid; // 获取当前节点的父节点ID var isDir = d.isParent; // 判断当前节点是否为目录(是否有子节点) var emptyNum = treetable.getEmptyNum(mPid, mData); // 计算当前节点前面的空位数量 var iconHtml = ''; // 初始化图标HTML字符串 for (var i = 0; i < emptyNum; i++) { iconHtml += ''; // 根据空位数量生成相应数量的空位图标 } if (isDir) { // 如果是目录,添加两个图标:一个三角形和一个图层图标 iconHtml += ' '; } else { // 如果是文件,添加一个文件图标 iconHtml += ''; } // 添加两个空格作为间隔 iconHtml += '  '; // 根据是否是目录设置类型为'dir'或'file' var ttype = isDir ? 'dir' : 'file'; // 创建包含图标和名称的HTML字符串 var vg = ''; // 返回完整的HTML字符串 return vg + iconHtml + d[param.cols[0][param.treeColIndex].field] + '' param.done = function (res, curr, count) { // 在目标元素后插入一个带有'class'为'treeTable'的元素 $(param.elem).next().addClass('treeTable'); // 隐藏'treeTable'中的分页控件 $('.treeTable .layui-table-page').css('display', 'none'); // 设置'treeTable'元素的'treeLinkage'属性 $(param.elem).next().attr('treeLinkage', param.treeLinkage); // 如果设置了默认关闭树形结构,则折叠所有节点 if (param.treeDefaultClose) { treetable.foldAll(param.elem); } // 如果存在回调函数,则执行回调函数 if (doneCallback) { doneCallback(res, curr, count); } }; // 渲染表格 table.render(param); }, // 计算缩进的数量 getEmptyNum: function (pid, data) { // 初始化缩进数量为0 var num = 0; // 如果pid不存在,直接返回缩进数量0 if (!pid) { return num; } // 临时变量tPid用于存储当前节点的父节点ID var tPid; // 遍历数据数组 for (var i = 0; i < data.length; i++) { if (pid == data[i].id) { // 如果当前节点的父ID与目标ID匹配,则计数器加1 num += 1; // 更新tPid为当前节点的父ID tPid = data[i].pid; // 跳出循环 break; } return num + treetable.getEmptyNum(tPid, data); // 返回当前节点及其子节点的数量总和 }, // 展开/折叠行 toggleRows: function ($dom, linkage) { // 获取当前行的lay-ttype属性值 var type = $dom.attr('lay-ttype'); // 如果类型是'file',直接返回 if ('file' == type) { return; } // 获取当前行的lay-tid属性值 var mId = $dom.attr('lay-tid'); // 判断当前行是否处于打开状态 var isOpen = $dom.hasClass('open'); if (isOpen) { // 如果当前状态是打开的,移除 'open' 类 $dom.removeClass('open'); } else { // 如果当前状态是关闭的,添加 'open' 类 $dom.addClass('open'); } // 遍历当前元素最近的父级 中的所有 元素 $dom.closest('tbody').find('tr').each(function () { // 获取当前行中的树表图标元素 var $ti = $(this).find('.treeTable-icon'); // 获取图标元素的父节点 ID var pid = $ti.attr('lay-tpid'); // 获取图标元素的类型(目录或文件) var ttype = $ti.attr('lay-ttype'); // 判断图标元素是否处于打开状态 var tOpen = $ti.hasClass('open'); // 如果当前行的父节点 ID 与目标 ID 相同 if (mId == pid) { if (isOpen) { // 如果当前状态是打开的,隐藏当前行 $(this).hide(); // 如果当前行的类型是目录且其打开状态与当前状态一致,触发点击事件 if ('dir' == ttype && tOpen == isOpen) { $ti.trigger('click'); } } else { // 如果当前状态是关闭的,显示当前行 $(this).show(); // 如果需要联动且当前行的类型是目录且其打开状态与当前状态一致,触发点击事件 if (linkage && 'dir' == ttype && tOpen == isOpen) { $ti.trigger('click'); } } } }); // 检查参数 checkParam: function (param) { if (!param.treeSpid && param.treeSpid != 0) { // 如果参数treeSpid为空且不等于0,则弹出提示信息并返回false layer.msg('参数treeSpid不能为空', {icon: 5}); return false; } if (!param.treeColIndex && param.treeColIndex != 0) { // 如果参数treeColIndex为空且不等于0,则弹出提示信息并返回false layer.msg('参数treeColIndex不能为空', {icon: 5}); return false; } // 参数验证通过,返回true return true; }, // 展开所有 expandAll: function (dom) { // 查找指定DOM元素的下一个兄弟元素中的树表,遍历其每一行 $(dom).next('.treeTable').find('.layui-table-body tbody tr').each(function () { // 获取当前行的树图标元素 var $ti = $(this).find('.treeTable-icon'); // 获取树图标的类型属性 var ttype = $ti.attr('lay-ttype'); // 判断树图标是否处于打开状态 var tOpen = $ti.hasClass('open'); // 如果类型是目录且未打开,则触发点击事件以展开目录 if ('dir' == ttype && !tOpen) { $ti.trigger('click'); } }); }, // 折叠所有树节点 foldAll: function (dom) { // 遍历指定DOM元素下的所有树表行 $(dom).next('.treeTable').find('.layui-table-body tbody tr').each(function () { // 获取当前行的图标元素 var $ti = $(this).find('.treeTable-icon'); // 获取图标元素的类型属性 var ttype = $ti.attr('lay-ttype'); // 判断图标是否处于打开状态 var tOpen = $ti.hasClass('open'); // 如果图标类型为目录且处于打开状态,则触发点击事件以折叠该节点 if ('dir' == ttype && tOpen) { $ti.trigger('click'); } }); } }; // 加载树表样式文件 layui.link(layui.cache.base + 'treetable-lay/treetable.css'); // 给图标列绑定点击事件 $('body').on('click', '.treeTable .treeTable-icon', function () { // 获取当前树表的联动属性值 var treeLinkage = $(this).parents('.treeTable').attr('treeLinkage'); // 根据联动属性值决定是否联动展开或折叠行 if ('true' == treeLinkage) { treetable.toggleRows($(this), true); } else { treetable.toggleRows($(this), false); } }); // 导出 treetable 模块,使其可以在其他文件中被引用和使用 exports('treetable', treetable); });