mirror of
https://github.com/dqzboy/Docker-Proxy.git
synced 2026-01-12 16:25:42 +08:00
fix: fix the nav menu
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
"username": "root",
|
||||
"password": "$2b$10$lh1kqJtq3shL2BhMD1LbVOThGeAlPXsDgME/he4ZyDMRupVtj0Hl.",
|
||||
"loginCount": 1,
|
||||
"lastLogin": "2025-04-01T22:16:21.808Z"
|
||||
"lastLogin": "2025-04-01T22:45:10.184Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -7,6 +7,7 @@
|
||||
<link rel="icon" href="https://cdn.jsdelivr.net/gh/dqzboy/Blog-Image/BlogCourse/docker-proxy.png" type="image/png">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<script src="js/nav-menu.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<header class="header">
|
||||
@@ -168,12 +169,6 @@
|
||||
// 设置当前年份
|
||||
document.getElementById('currentYear').textContent = new Date().getFullYear();
|
||||
document.addEventListener('DOMContentLoaded', (event) => {
|
||||
const menuToggle = document.getElementById('menuToggle');
|
||||
const navMenu = document.getElementById('navMenu');
|
||||
menuToggle.addEventListener('click', () => {
|
||||
navMenu.classList.toggle('active');
|
||||
});
|
||||
|
||||
// 版权保护
|
||||
protectCopyright();
|
||||
});
|
||||
@@ -343,6 +338,29 @@
|
||||
let currentTagPage = 1;
|
||||
let currentImageData = null;
|
||||
|
||||
// 初始化时加载代理域名配置
|
||||
async function initProxyDomain() {
|
||||
try {
|
||||
const response = await fetch('/api/config');
|
||||
if (response.ok) {
|
||||
const config = await response.json();
|
||||
if (config.proxyDomain) {
|
||||
proxyDomain = config.proxyDomain;
|
||||
console.log('成功加载代理域名:', proxyDomain);
|
||||
} else {
|
||||
console.warn('配置中没有proxyDomain字段');
|
||||
proxyDomain = 'registry-1.docker.io'; // 使用默认值
|
||||
}
|
||||
} else {
|
||||
console.error('加载配置失败:', response.status, response.statusText);
|
||||
proxyDomain = 'registry-1.docker.io'; // 使用默认值
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('初始化代理域名失败:', error);
|
||||
proxyDomain = 'registry-1.docker.io'; // 使用默认值
|
||||
}
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// === 新增:全局提示函数 ===
|
||||
// ========================================
|
||||
@@ -1648,6 +1666,9 @@
|
||||
|
||||
// DOMContentLoaded 事件监听器
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// 初始化代理域名
|
||||
initProxyDomain();
|
||||
|
||||
// 确保元素存在再添加事件监听器
|
||||
const searchInput = document.getElementById('searchInput');
|
||||
if (searchInput) {
|
||||
|
||||
154
hubcmdui/web/js/nav-menu.js
Normal file
154
hubcmdui/web/js/nav-menu.js
Normal file
@@ -0,0 +1,154 @@
|
||||
/**
|
||||
* 导航菜单加载模块
|
||||
* 负责从config加载并渲染前端导航菜单
|
||||
*/
|
||||
|
||||
// 用于跟踪菜单是否已加载
|
||||
let menuLoaded = false;
|
||||
|
||||
// 立即执行初始化函数
|
||||
(function() {
|
||||
console.log('[菜单模块] 初始化开始');
|
||||
try {
|
||||
// 页面加载完成后执行,但不在这里调用加载函数
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
console.log('[菜单模块] DOM内容加载完成,等待loadMenu或loadNavMenu调用');
|
||||
// 不在这里调用,避免重复加载
|
||||
});
|
||||
console.log('[菜单模块] 初始化完成,等待调用');
|
||||
} catch (error) {
|
||||
console.error('[菜单模块] 初始化失败:', error);
|
||||
}
|
||||
})();
|
||||
|
||||
// 加载导航菜单
|
||||
async function loadNavMenu() {
|
||||
if (menuLoaded) {
|
||||
console.log('[菜单模块] 菜单已加载,跳过');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('[菜单模块] loadNavMenu() 函数被调用');
|
||||
const navMenu = document.getElementById('navMenu');
|
||||
if (!navMenu) {
|
||||
console.error('[菜单模块] 无法找到id为navMenu的元素,菜单加载失败');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
console.log('[菜单模块] 正在从/api/config获取菜单配置...');
|
||||
|
||||
// 从API获取配置
|
||||
const response = await fetch('/api/config');
|
||||
console.log('[菜单模块] API响应状态:', response.status, response.statusText);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`获取配置失败: ${response.status} ${response.statusText}`);
|
||||
}
|
||||
|
||||
const config = await response.json();
|
||||
console.log('[菜单模块] 成功获取配置:', config);
|
||||
|
||||
// 确保menuItems存在且是数组
|
||||
if (!config.menuItems || !Array.isArray(config.menuItems) || config.menuItems.length === 0) {
|
||||
console.warn('[菜单模块] 配置中没有菜单项或格式不正确', config);
|
||||
navMenu.innerHTML = '<span class="no-menu" style="color: #ff6b6b; font-size: 14px;">未设置菜单</span>';
|
||||
menuLoaded = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// 渲染菜单
|
||||
renderNavMenu(navMenu, config.menuItems);
|
||||
menuLoaded = true;
|
||||
|
||||
} catch (error) {
|
||||
console.error('[菜单模块] 加载导航菜单失败:', error);
|
||||
navMenu.innerHTML = `<span class="menu-error" style="color: #ff6b6b; font-size: 14px;">菜单加载失败: ${error.message}</span>`;
|
||||
}
|
||||
}
|
||||
|
||||
// 渲染导航菜单
|
||||
function renderNavMenu(navMenuElement, menuItems) {
|
||||
try {
|
||||
console.log('[菜单模块] 开始渲染导航菜单,菜单项数量:', menuItems.length);
|
||||
|
||||
// 清空现有内容
|
||||
navMenuElement.innerHTML = '';
|
||||
|
||||
// 移动设备菜单切换按钮
|
||||
const menuToggle = document.createElement('div');
|
||||
menuToggle.id = 'menuToggle';
|
||||
menuToggle.className = 'menu-toggle';
|
||||
menuToggle.innerHTML = '<i class="fas fa-bars"></i>';
|
||||
menuToggle.style.color = '#333'; // 设置为深色
|
||||
menuToggle.style.fontSize = '28px'; // 增大菜单图标
|
||||
navMenuElement.appendChild(menuToggle);
|
||||
|
||||
// 菜单项容器
|
||||
const menuList = document.createElement('ul');
|
||||
menuList.className = 'nav-list';
|
||||
menuList.style.display = 'flex';
|
||||
menuList.style.listStyle = 'none';
|
||||
menuList.style.margin = '0';
|
||||
menuList.style.padding = '0';
|
||||
|
||||
// 添加菜单项
|
||||
menuItems.forEach((item, index) => {
|
||||
console.log(`[菜单模块] 渲染菜单项 #${index+1}:`, item);
|
||||
const menuItem = document.createElement('li');
|
||||
menuItem.style.marginLeft = '25px'; // 增加间距
|
||||
|
||||
const link = document.createElement('a');
|
||||
link.href = item.link || '#';
|
||||
link.textContent = item.text || '未命名菜单';
|
||||
|
||||
// 使用内联样式确保文字颜色可见,并增大字体
|
||||
link.style.color = '#333'; // 黑色文字
|
||||
link.style.textDecoration = 'none';
|
||||
link.style.fontSize = '16px'; // 从14px增大到16px
|
||||
link.style.fontWeight = 'bold';
|
||||
link.style.padding = '8px 15px'; // 增大内边距
|
||||
link.style.borderRadius = '4px';
|
||||
link.style.transition = 'background-color 0.3s, color 0.3s';
|
||||
|
||||
// 添加鼠标悬停效果
|
||||
link.addEventListener('mouseover', function() {
|
||||
this.style.backgroundColor = '#3d7cf4'; // 蓝色背景
|
||||
this.style.color = '#fff'; // 白色文字
|
||||
});
|
||||
|
||||
// 鼠标移出时恢复原样
|
||||
link.addEventListener('mouseout', function() {
|
||||
this.style.backgroundColor = 'transparent';
|
||||
this.style.color = '#333';
|
||||
});
|
||||
|
||||
if (item.newTab) {
|
||||
link.target = '_blank';
|
||||
link.rel = 'noopener noreferrer';
|
||||
}
|
||||
|
||||
menuItem.appendChild(link);
|
||||
menuList.appendChild(menuItem);
|
||||
});
|
||||
|
||||
navMenuElement.appendChild(menuList);
|
||||
|
||||
// 绑定移动端菜单切换事件
|
||||
menuToggle.addEventListener('click', () => {
|
||||
console.log('[菜单模块] 菜单切换按钮被点击');
|
||||
navMenuElement.classList.toggle('active');
|
||||
});
|
||||
|
||||
console.log(`[菜单模块] 成功渲染了 ${menuItems.length} 个导航菜单项`);
|
||||
} catch (error) {
|
||||
console.error('[菜单模块] 渲染导航菜单失败:', error);
|
||||
navMenuElement.innerHTML = `<span class="menu-error" style="color: #ff6b6b; font-size: 14px;">菜单渲染失败: ${error.message}</span>`;
|
||||
}
|
||||
}
|
||||
|
||||
// 添加loadMenu函数,作为loadNavMenu的别名,确保与index.html中的调用匹配
|
||||
function loadMenu() {
|
||||
console.log('[菜单模块] 调用loadMenu() - 转发到loadNavMenu()');
|
||||
loadNavMenu();
|
||||
}
|
||||
@@ -65,55 +65,90 @@
|
||||
|
||||
/* 头部导航 */
|
||||
.header {
|
||||
background-color: var(--container-bg);
|
||||
box-shadow: var(--shadow-md);
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 1000;
|
||||
padding: 0;
|
||||
transition: all var(--transition-normal);
|
||||
background-color: #ffffff; /* 白色背景 */
|
||||
padding: 20px 0; /* 增加上下padding */
|
||||
position: relative;
|
||||
border-bottom: 1px solid #e0e0e0; /* 添加边框分隔 */
|
||||
}
|
||||
|
||||
.header-content {
|
||||
max-width: 1320px;
|
||||
margin: 0 auto;
|
||||
padding: 0.75rem 1.5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 0 30px; /* 增加左右padding */
|
||||
}
|
||||
|
||||
.logo {
|
||||
height: 42px;
|
||||
height: 60px; /* 将原来的40px增大到60px */
|
||||
width: auto;
|
||||
transition: transform var(--transition-fast);
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.logo:hover {
|
||||
transform: scale(1.05);
|
||||
transform: scale(1.05); /* 添加悬停效果 */
|
||||
}
|
||||
|
||||
/* 导航菜单修复 */
|
||||
.nav-menu {
|
||||
display: flex;
|
||||
gap: 1.2rem;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.nav-menu a {
|
||||
color: var(--text-secondary);
|
||||
text-decoration: none;
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: var(--radius-md);
|
||||
transition: all var(--transition-fast);
|
||||
font-weight: 500;
|
||||
font-size: 0.95rem;
|
||||
letter-spacing: 0.2px;
|
||||
.menu-toggle {
|
||||
display: none;
|
||||
font-size: 24px;
|
||||
color: #333333; /* 深色图标 */
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.nav-menu a:hover {
|
||||
background-color: var(--primary-light);
|
||||
color: white;
|
||||
transform: translateY(-2px);
|
||||
.nav-list {
|
||||
display: flex;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.nav-list li {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
/* 注意:菜单项的具体样式由JS中的内联样式控制 */
|
||||
|
||||
/* 移动设备适配 */
|
||||
@media (max-width: 768px) {
|
||||
.menu-toggle {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.nav-list {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
right: 20px;
|
||||
background-color: #ffffff; /* 白色背景 */
|
||||
border-radius: 5px;
|
||||
padding: 20px;
|
||||
flex-direction: column;
|
||||
display: none;
|
||||
z-index: 100;
|
||||
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
|
||||
border: 1px solid #e0e0e0;
|
||||
}
|
||||
|
||||
.nav-menu.active .nav-list {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.nav-list li {
|
||||
margin: 10px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.no-menu, .menu-error {
|
||||
color: #ff6b6b;
|
||||
font-size: 14px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
/* 主容器 */
|
||||
@@ -2581,11 +2616,11 @@
|
||||
/* 为 名称 列设置最大宽度和文本溢出处理 */
|
||||
#dockerStatusTable th:nth-child(2),
|
||||
#dockerStatusTable td:nth-child(2) {
|
||||
max-width: 200px; /* 根据需要调整 */
|
||||
width: 25%; /* 尝试百分比宽度 */
|
||||
width: 25%; /* 将宽度从原来的过大值减小到25% */
|
||||
max-width: 250px; /* 限制最大宽度 */
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* 为 镜像 列设置最大宽度和文本溢出处理 */
|
||||
@@ -2694,9 +2729,9 @@
|
||||
|
||||
/* --- 新增:详情弹窗表格样式 --- */
|
||||
.details-swal-popup .details-table-container {
|
||||
max-height: 60vh; /* 限制最大高度,出现滚动条 */
|
||||
max-height: 70vh;
|
||||
overflow-y: auto;
|
||||
margin-top: 1rem;
|
||||
text-align: left; /* 确保内容左对齐 */
|
||||
}
|
||||
|
||||
.details-swal-popup .details-table {
|
||||
@@ -2718,11 +2753,13 @@
|
||||
}
|
||||
|
||||
.details-swal-popup .details-table tbody td {
|
||||
padding: 0.8rem 1rem;
|
||||
border-bottom: 1px solid var(--border-light, #e5e7eb);
|
||||
vertical-align: middle;
|
||||
color: var(--text-primary);
|
||||
text-align: left; /* 确保单元格左对齐 */
|
||||
padding: 8px 12px;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
|
||||
word-break: break-word;
|
||||
font-family: monospace;
|
||||
white-space: pre-wrap;
|
||||
text-align: left; /* 确保文本左对齐 */
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.details-swal-popup .details-table tbody tr:last-child td {
|
||||
@@ -2774,4 +2811,175 @@
|
||||
}
|
||||
/* --- 结束:资源详情类 Excel 表格样式 --- */
|
||||
|
||||
/* ... 其他样式 ... */
|
||||
/* ... 其他样式 ... */
|
||||
|
||||
/* 导航菜单样式 */
|
||||
.nav-menu {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.nav-menu .nav-list {
|
||||
display: flex;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.nav-menu .nav-list li {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.nav-menu .nav-list li a {
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
font-size: 14px;
|
||||
transition: color 0.3s;
|
||||
}
|
||||
|
||||
.nav-menu .nav-list li a:hover {
|
||||
color: #3d7cf4;
|
||||
}
|
||||
|
||||
.menu-toggle {
|
||||
display: none;
|
||||
cursor: pointer;
|
||||
font-size: 1.5rem;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* 移动设备适配 */
|
||||
@media (max-width: 768px) {
|
||||
.nav-menu {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.menu-toggle {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.nav-menu .nav-list {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
right: 0;
|
||||
flex-direction: column;
|
||||
background-color: #111;
|
||||
padding: 20px;
|
||||
border-radius: 5px;
|
||||
display: none;
|
||||
box-shadow: 0 5px 15px rgba(0,0,0,0.5);
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.nav-menu.active .nav-list {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.nav-menu .nav-list li {
|
||||
margin: 10px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.no-menu, .menu-error {
|
||||
color: #ff6b6b;
|
||||
font-size: 14px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
/* 操作按钮布局优化 */
|
||||
.action-cell {
|
||||
white-space: nowrap;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 5px; /* 使用gap来控制按钮间隔 */
|
||||
}
|
||||
|
||||
.action-cell button,
|
||||
.action-cell .btn {
|
||||
margin: 0;
|
||||
padding: 5px 8px;
|
||||
font-size: 13px;
|
||||
display: inline-block;
|
||||
min-width: auto; /* 防止按钮过宽 */
|
||||
flex-shrink: 0; /* 防止按钮被压缩 */
|
||||
}
|
||||
|
||||
/* 确保操作按钮保持在一行 */
|
||||
#dockerStatusTable th:last-child,
|
||||
#dockerStatusTable td:last-child {
|
||||
width: auto;
|
||||
min-width: 180px; /* 确保有足够的空间放置按钮 */
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* 日志弹窗内容优化 */
|
||||
.log-content {
|
||||
text-align: left;
|
||||
font-family: 'Courier New', monospace;
|
||||
white-space: pre-wrap;
|
||||
overflow-x: auto;
|
||||
background-color: #f5f5f5;
|
||||
padding: 15px;
|
||||
border-radius: 5px;
|
||||
max-height: 60vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
/* 确保SweetAlert2弹窗内容左对齐 */
|
||||
.swal2-html-container {
|
||||
text-align: left !important;
|
||||
}
|
||||
|
||||
/* 确保弹窗样式优先级最高 */
|
||||
.swal2-popup .swal2-html-container,
|
||||
.swal2-popup .swal2-content {
|
||||
text-align: left !important;
|
||||
}
|
||||
|
||||
.swal2-popup pre,
|
||||
.swal2-popup code,
|
||||
.swal2-popup .log-content {
|
||||
text-align: left !important;
|
||||
direction: ltr !important;
|
||||
font-family: 'Courier New', monospace !important;
|
||||
font-size: 14px !important;
|
||||
line-height: 1.5 !important;
|
||||
}
|
||||
|
||||
/* 调整容器表格布局 */
|
||||
#dockerStatusTable {
|
||||
table-layout: fixed;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* 容器ID/名称列宽度 */
|
||||
#dockerStatusTable th:nth-child(1),
|
||||
#dockerStatusTable td:nth-child(1) {
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
/* 镜像名称列宽度 */
|
||||
#dockerStatusTable th:nth-child(2),
|
||||
#dockerStatusTable td:nth-child(2) {
|
||||
width: 25%;
|
||||
max-width: 250px;
|
||||
}
|
||||
|
||||
/* 容器状态列宽度 */
|
||||
#dockerStatusTable th:nth-child(3),
|
||||
#dockerStatusTable td:nth-child(3) {
|
||||
width: 15%;
|
||||
}
|
||||
|
||||
/* 创建时间列宽度 */
|
||||
#dockerStatusTable th:nth-child(4),
|
||||
#dockerStatusTable td:nth-child(4) {
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
/* 操作列宽度 */
|
||||
#dockerStatusTable th:nth-child(5),
|
||||
#dockerStatusTable td:nth-child(5) {
|
||||
width: 20%;
|
||||
}
|
||||
Reference in New Issue
Block a user