Files

258 lines
10 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Layui Admin Index Module - Theme v2.7.1
* 功能:处理后台管理系统的标签页(Tabs)逻辑,包括打开新标签、切换标签、URL路由监听等。
*/
layui.define(["ywxapp", "http"], function (exports) {
// 获取 Layui 核心模块引用
var $ = layui.$;
var element = layui.element;
var ywxapp = layui.ywxapp;
var http = layui.http;
var setter = layui.setter;
var view = layui.view;
var util = layui.util;
// 状态与配置常量
var tabsPageState = ywxapp.tabsPage; // 当前标签页状态
var TABS_CONTAINER_ID = "layadmin-layout-tabs"; // 标签容器ID
/**
* 核心函数:打开或切换标签页
* @param {Object} options - 配置对象
* @param {String} options.url - 页面URL
* @param {String} options.title - 页面标题
* @param {Boolean} options.escape - 是否转义标题(默认true)
* @param {String} options.highlight - 标题高亮样式
*/
function openOrSwitchTab(options) {
// 合并默认配置
options = $.extend({
url: "",
escape: true
}, options);
var isTabExists = false;
var tabHeaders = $("#LAY_app_tabsheader > li");
// 提取用于匹配的唯一标识(去除协议头和查询参数)
var matchKey = options.url.replace(/(^http(s*):)|(\?[\s\S]*$)/g, "");
// 1. 检查标签是否已存在
tabHeaders.each(function (index) {
if ($(this).attr("lay-id") === options.url) {
isTabExists = true;
tabsPageState.index = index; // 更新当前激活标签索引
}
});
// 设置默认标题
if (!options.title) {
options.title = (tabsPageState.index === 0) ? "" : "\u65b0\u6807\u7b7e\u9875"; // "新标签页"
}
/**
* 执行标签切换动作
*/
function performTabChange() {
element.tabChange(TABS_CONTAINER_ID, options.url);
ywxapp.tabsBodyChange(tabsPageState.index, {
url: options.url,
title: options.title
});
}
// 2. 根据配置决定是新增标签还是刷新现有iframe
if (setter.pageTabs) {
// 如果开启了多标签模式
if (!isTabExists) {
// 延迟添加DOM,确保渲染顺序
setTimeout(function () {
var iframeHtml = [
'<div class="layadmin-tabsbody-item layui-show">',
'<iframe src="' + options.url + '" frameborder="0" class="layadmin-iframe"></iframe>',
"</div>"
].join("");
$("#LAY_app_body").append(iframeHtml);
performTabChange();
}, 10);
// 添加标签头
var displayTitle = options.title;
if (options.escape) {
displayTitle = util.escape(displayTitle);
}
// 处理标题高亮
var titleHtml = displayTitle;
if (options.highlight) {
titleHtml = '<span style="' + options.highlight + '">' + displayTitle + "</span>";
}
element.tabAdd(TABS_CONTAINER_ID, {
title: "<span>" + titleHtml + "</span>",
id: options.url,
attr: matchKey
});
// 更新索引为新添加的标签
tabsPageState.index = tabHeaders.length;
} else {
// 标签已存在,直接切换
performTabChange();
}
} else {
// 如果未开启多标签模式,直接在当前iframe中跳转
var currentIframe = ywxapp.tabsBody(ywxapp.tabsPage.index).find(".layadmin-iframe")[0];
if (currentIframe && currentIframe.contentWindow) {
currentIframe.contentWindow.location.href = options.url;
}
// 即使不新增标签,也可能需要更新内部状态
performTabChange();
}
}
/**
* 递归构建侧边菜单的HTML结构(无限极)
* 约定:有 child 且非空 => 父节点(可展开);否则 => 叶子节点(可点击跳转 lay-href)
* @param {Array} data 当前层级菜单数组
* @param {Number} depth 递归深度(0 为顶级 <li>>=1 为 <dd> 子项)
* @returns {String}
*/
function buildSideMenu(data, depth) {
depth = depth || 0;
var html = '';
$.each(data, function (i, item) {
var hasChild = item.child && item.child.length > 0;
var iconHtml = item.icon
? '<i class="layui-icon ' + item.icon + '"></i>'
: '';
var titleHtml = '<cite>' + item.title + '</cite>';
if (depth === 0) {
// 顶级:<li>
if (hasChild) {
html += '<li data-name="' + item.name + '" class="layui-nav-item' + (item.spread ? ' layui-nav-itemed' : '') + '">';
html += ' <a href="javascript:;" lay-tips="' + item.title + '" lay-direction="2">';
html += ' ' + iconHtml + titleHtml;
html += ' </a>';
html += ' <dl class="layui-nav-child">';
html += buildSideMenu(item.child, depth + 1);
html += ' </dl>';
html += '</li>';
} else {
html += '<li data-name="' + item.name + '" class="layui-nav-item">';
html += ' <a lay-href="' + item.route + '" lay-tips="' + item.title + '" lay-direction="2">';
html += ' ' + iconHtml + titleHtml;
html += ' </a>';
html += '</li>';
}
} else {
// 子级:<dd>
if (hasChild) {
html += '<dd data-name="' + item.name + '">';
html += ' <a href="javascript:;">' + iconHtml + item.title + '</a>';
html += ' <dl class="layui-nav-child">';
html += buildSideMenu(item.child, depth + 1);
html += ' </dl>';
html += '</dd>';
} else {
html += '<dd data-name="' + item.name + '">';
html += ' <a lay-href="' + item.route + '">' + iconHtml + item.title + '</a>';
html += '</dd>';
}
}
});
return html;
}
// 加载侧边菜单(与后端菜单保持一致:使用绝对路径命中会员菜单接口,并始终拉取最新数据)
var _appShown = false;
function showApp() {
if (_appShown) return;
_appShown = true;
$('#' + setter.container).css('visibility', 'visible');
}
function renderMenu(data) {
var html = buildSideMenu(data || []);
$('#LAY-system-side-menu').html(html);
element.init(); // 重新渲染导航
showApp(); // 菜单就绪后立即显示主体,消除白屏等待
}
// 菜单接口不可用时的兜底静态菜单(仅保证框架可点击,避免侧栏留白)
var FALLBACK_MENU = [
{ name: 'console', title: '控制台', icon: 'layui-icon-console', route: '/static/member/views/console/index.html' },
{ name: 'profile', title: '账户中心', icon: 'layui-icon-user', child: [
{ name: 'info', title: '个人资料', route: '/user/profile/index' },
{ name: 'avatar', title: '头像设置', route: '/user/profile/avatar' },
{ name: 'password', title: '密码修改', route: '/user/profile/password' },
{ name: 'settings', title: '账户设置', route: '/user/settings/index' }
]},
{ name: 'payment', title: '充值中心', icon: 'layui-icon-rmb', route: '/user/payment/index' }
];
http.get('/user/index/menu').then(function (res) {
if (res.code === 0 && res.data && res.data.length > 0) {
renderMenu(res.data);
} else {
if (res.code !== 0) {
layer.msg('菜单加载失败,已使用默认菜单: ' + (res.msg || ''), { icon: 2 });
}
renderMenu(FALLBACK_MENU);
}
}).catch(function (error) {
layer.msg('菜单加载失败,已使用默认菜单: ' + error, { icon: 2 });
renderMenu(FALLBACK_MENU);
});
/**
* 初始化路由监听与自动渲染
*/
(function initRouter() {
// 自动渲染视图
view().autoRender();
// 监听 Hash 变化
var hashObj = layui.url().hash;
var recordConfig = setter.record || {};
var path = hashObj.href.replace(/^\//, ""); // 去除开头的斜杠
// 尝试从本地存储获取标题
var storedData = layui.data(setter.tableName).record || {};
var savedTitle = storedData[path] || "";
// 如果配置了记录功能且路径有效
if (recordConfig.url && path) {
var cleanPath = $.trim(path);
// 安全检查:如果是外部链接且不属于当前域名,则通过 openOrSwitchTab 处理
// 注意:原代码逻辑中,正则测试失败(即不是外部链接)或者属于当前域名时,可能不走这个分支,
// 但原代码结构是:如果满足条件则调用 n (即 openOrSwitchTab)。
// 原逻辑:/^(\w*:)*\/\/.+/.test(i) && -1 === i.indexOf(location.hostname)
// 意思是:如果是绝对路径且域名不同,则作为新标签打开。
if (/^(\w*:)*\/\/.+/.test(cleanPath) && cleanPath.indexOf(location.hostname) === -1) {
openOrSwitchTab({
url: cleanPath,
title: savedTitle
});
}
}
// 保护超时:即便菜单接口异常,最多等待 1.2s 也显示主体(正常情况由 renderMenu 提前显示)
setTimeout(showApp, 1200);
})();
// 导出模块接口
var exportsData = {
openTabsPage: openOrSwitchTab
};
// 扩展 ywxapp 模块的功能
$.extend(ywxapp, exportsData);
// 完成模块定义
exports("index",{});
});