You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

301 lines
13 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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 += '&nbsp;&nbsp;';
// 根据是否是目录设置类型为'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);
});