This commit is contained in:
vipg
2025-11-12 17:24:55 +08:00
parent 8159f03e8c
commit 6dd4a9a41a
16 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,31 @@
/* 顶部导航组件 */
import { systemConfig } from '../config/system.js';
import { Auth } from '../core/auth.js';
import { themeConfig } from '../config/theme.js';
export function renderHeader() {
const header = document.createElement('div');
header.className = 'header';
header.innerHTML = `
<div class="app-name">${systemConfig.appName}</div>
<div class="header-actions">
<button onclick="toggleTheme()">切换主题</button>
<button onclick="Auth.logout()">退出登录</button>
</div>
`;
return header;
}
// 主题切换函数
function toggleTheme() {
const body = document.body;
if (body.classList.contains(themeConfig.darkThemeClass)) {
body.classList.remove(themeConfig.darkThemeClass);
localStorage.setItem(themeConfig.themeStorageKey, 'light');
} else {
body.classList.add(themeConfig.darkThemeClass);
localStorage.setItem(themeConfig.themeStorageKey, 'dark');
}
}

View File

@@ -0,0 +1,94 @@
/**
* 全局加载动画组件
*/
window.Loading = {
/**
* 初始化加载容器
*/
init() {
let container = $('#loading-container');
if (!container.length) {
container = $('<div id="loading-container" class="loading-container"></div>');
const loadingHtml = `
<div class="loading-mask"></div>
<div class="loading-spinner">
<div class="spinner"></div>
<div class="loading-text">加载中...</div>
</div>
`;
container.html(loadingHtml);
$('body').append(container);
}
return container;
},
/**
* 显示加载动画
* @param {string} text - 加载提示文本
*/
show(text = '加载中...') {
const container = this.init();
container.find('.loading-text').text(text);
container.css('display', 'flex');
},
/**
* 隐藏加载动画
*/
hide() {
const container = $('#loading-container');
if (container.length) {
container.css('display', 'none');
}
}
};
// 添加加载动画样式
$('head').append(`
<style>
.loading-container {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: none;
justify-content: center;
align-items: center;
background-color: rgba(0, 0, 0, 0.5);
z-index: 99999;
}
.loading-mask {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
backdrop-filter: blur(2px);
}
.loading-spinner {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
z-index: 1;
}
.spinner {
width: 40px;
height: 40px;
border: 4px solid rgba(30, 136, 229, 0.3);
border-top: 4px solid var(--primary-color);
border-radius: 50%;
animation: spin 1s linear infinite;
margin-bottom: 12px;
}
.loading-text {
color: var(--text-primary);
font-size: 16px;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>
`);

View File

@@ -0,0 +1,177 @@
/**
* 侧边栏菜单组件
*/
window.Sidebar = {
/**
* 初始化侧边栏
* @param {jQuery} container - 容器元素
*/
init(container) {
this.container = container;
this.collapse = localStorage.getItem(SystemConfig.menuCollapseKey) === 'true';
this.renderMenu();
this.bindEvents();
this.updateCollapseState();
},
/**
* 渲染菜单
*/
renderMenu() {
const menuHtml = this.generateMenuHtml(MenuConfig);
this.container.html(menuHtml);
},
/**
* 生成菜单HTML递归处理多级菜单
* @param {array} menuList - 菜单列表
* @returns {string} - 菜单HTML
*/
generateMenuHtml(menuList) {
let html = '<ul class="sidebar-menu">';
menuList.forEach(menu => {
const hasChildren = menu.children && menu.children.length > 0;
const isActive = window.location.pathname.includes(menu.url);
html += `<li class="menu-item ${hasChildren ? 'has-children' : ''} ${isActive ? 'active' : ''}" data-id="${menu.id}">`;
// 菜单标题
html += `<div class="menu-title">`;
html += `<span class="menu-icon">${menu.icon}</span>`;
html += `<span class="menu-text">${menu.title}</span>`;
if (hasChildren) {
html += `<span class="menu-toggle ${this.collapse ? 'collapsed' : ''}">${this.collapse ? '+' : '-'}</span>`;
}
html += `</div>`;
// 子菜单
if (hasChildren) {
html += `<ul class="sub-menu ${this.collapse ? 'hidden' : ''}">`;
html += this.generateMenuHtml(menu.children);
html += `</ul>`;
} else if (menu.url) {
// 菜单项链接
html += `<a href="${menu.url}" class="menu-link"></a>`;
}
html += `</li>`;
});
html += '</ul>';
return html;
},
/**
* 绑定事件
*/
bindEvents() {
// 菜单折叠/展开
this.container.on('click', '.menu-toggle', (e) => {
const $toggle = $(e.currentTarget);
const $subMenu = $toggle.closest('.menu-item').find('.sub-menu');
this.collapse = !this.collapse;
localStorage.setItem(SystemConfig.menuCollapseKey, this.collapse);
$toggle.text(this.collapse ? '+' : '-');
$subMenu.toggleClass('hidden', this.collapse);
this.updateCollapseState();
});
// 菜单项点击(无链接时展开子菜单)
this.container.on('click', '.menu-title:not(.has-children)', (e) => {
const $title = $(e.currentTarget);
const $link = $title.siblings('.menu-link');
if ($link.length) {
$link[0].click();
}
});
},
/**
* 更新折叠状态样式
*/
updateCollapseState() {
$('.sidebar').toggleClass('collapsed', this.collapse);
$('.main-content').toggleClass('sidebar-collapsed', this.collapse);
}
};
// 添加侧边栏样式
$('head').append(`
<style>
.sidebar {
width: 240px;
height: 100%;
background-color: var(--bg-light-color);
border-right: 1px solid var(--border-color);
transition: width 0.3s ease;
overflow: hidden;
}
.sidebar.collapsed {
width: 60px;
}
.sidebar-menu {
list-style: none;
}
.menu-item {
margin-bottom: 2px;
}
.menu-title {
display: flex;
align-items: center;
padding: 12px 16px;
cursor: pointer;
transition: background-color 0.3s ease;
}
.menu-title:hover {
background-color: var(--hover-color);
}
.menu-item.active .menu-title {
background-color: var(--active-color);
}
.menu-icon {
margin-right: 12px;
font-size: 18px;
}
.menu-text {
flex: 1;
transition: opacity 0.3s ease;
}
.sidebar.collapsed .menu-text {
opacity: 0;
width: 0;
margin: 0;
}
.menu-toggle {
font-size: 14px;
cursor: pointer;
transition: transform 0.3s ease;
}
.sub-menu {
list-style: none;
background-color: var(--bg-color);
transition: all 0.3s ease;
}
.sub-menu.hidden {
display: none;
}
.menu-link {
display: block;
height: 100%;
width: 100%;
position: absolute;
top: 0;
left: 0;
}
.main-content {
flex: 1;
padding: 20px;
transition: margin-left 0.3s ease;
}
.main-content.sidebar-collapsed {
margin-left: -180px;
}
</style>
`);