|
|
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 += '<span class="treeTable-empty"></span>';
|
|
|
// 根据空位数量生成相应数量的空位图标
|
|
|
}
|
|
|
if (isDir) {
|
|
|
// 如果是目录,添加两个图标:一个三角形和一个图层图标
|
|
|
iconHtml += '<i class="layui-icon layui-icon-triangle-d"></i> <i class="layui-icon layui-icon-layer"></i>';
|
|
|
} else {
|
|
|
// 如果是文件,添加一个文件图标
|
|
|
iconHtml += '<i class="layui-icon layui-icon-file"></i>';
|
|
|
}
|
|
|
// 添加两个空格作为间隔
|
|
|
iconHtml += ' ';
|
|
|
// 根据是否是目录设置类型为'dir'或'file'
|
|
|
var ttype = isDir ? 'dir' : 'file';
|
|
|
// 创建包含图标和名称的HTML字符串
|
|
|
var vg = '<span class="treeTable-icon open" lay-tid="' + mId + '" lay-tpid="' + mPid + '" lay-ttype="' + ttype + '">';
|
|
|
// 返回完整的HTML字符串
|
|
|
return vg + iconHtml + d[param.cols[0][param.treeColIndex].field] + '</span>'
|
|
|
|
|
|
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');
|
|
|
}
|
|
|
|
|
|
// 遍历当前元素最近的父级 <tbody> 中的所有 <tr> 元素
|
|
|
$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);
|
|
|
}); |