XNSim/XNSimHtml/main.html

730 lines
28 KiB
HTML
Raw 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.

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>XNSim - 主页面</title>
<link rel="icon" type="image/png" href="assets/icons/XNSim.png">
<link rel="shortcut icon" type="image/png" href="assets/icons/XNSim.png">
<script src="chart.min.js"></script>
<script src="components/auth-component.js"></script>
<script src="components/main-toolbar.js"></script>
<script src="components/sub-toolbar.js"></script>
<script src="components/user-info.js"></script>
<script src="components/tabs-container.js"></script>
<script src="components/content-area.js"></script>
<script src="components/overview-page.js"></script>
<script src="components/update-history.js"></script>
<script src="components/run-log.js"></script>
<script src="components/system-info.js"></script>
<script src="components/help-component.js"></script>
<script src="components/system-log.js"></script>
<script src="components/configuration-config.js"></script>
<script src="components/interface-config.js" type="module"></script>
<script src="components/run-sim.js"></script>
<script src="components/simulation-monitor.js"></script>
<script src="components/model-monitor.js"></script>
<script src="components/data-monitor.js"></script>
<script src="components/data-collection.js"></script>
<script src="components/network-monitor.js"></script>
<script src="components/qtg-monitor.js"></script>
<script src="components/profile-center.js"></script>
<script src="components/user-management.js"></script>
<script src="components/model-development.js"></script>
<script src="components/service-development.js"></script>
<script src="components/header-tools.js"></script>
<script src="components/qa-component.js"></script>
<script src="components/todo-component.js" type="module"></script>
<style>
.icon {
width: 24px;
height: 24px;
display: inline-block;
vertical-align: middle;
margin-bottom: 5px;
}
.icon-small {
width: 16px;
height: 16px;
}
/* 用户等级图标样式 */
.user-level-icon {
width: 20px;
height: 20px;
margin-right: 8px;
vertical-align: middle;
}
/* 主要内容区域样式 */
.main-content {
flex: 1;
display: flex;
flex-direction: column;
background-color: #fff;
height: 100vh;
padding: 0;
margin: 0;
overflow: hidden;
}
/* 内容包装器样式 */
.content-wrapper {
display: flex;
height: 100vh;
background: #fff;
}
/* 主工具栏样式 */
.main-toolbar {
width: 80px;
background: linear-gradient(180deg, #667eea 0%, #764ba2 100%);
display: flex;
flex-direction: column;
transition: width 0.3s ease;
box-shadow: 2px 0 5px rgba(0, 0, 0, 0.1);
}
/* 子工具栏样式 */
.sub-toolbar {
width: 200px;
background: linear-gradient(180deg, #7986E7 0%, #8B6DB3 100%);
position: relative;
transition: width 0.3s ease;
box-shadow: 2px 0 5px rgba(0, 0, 0, 0.1);
}
.sub-toolbar.collapsed {
width: 0;
}
.sub-toolbar-content {
width: 200px;
height: 100%;
overflow-y: auto;
overflow-x: hidden;
padding: 10px 0;
}
.sub-toolbar.collapsed .sub-toolbar-content {
display: none;
}
/* 主容器样式 */
.main-container {
display: none;
width: 100%;
height: 100vh;
overflow: hidden;
opacity: 0;
transition: opacity 0.3s ease;
}
.main-container.visible {
display: block !important;
opacity: 1;
}
/* 认证容器样式 */
#authContainer {
display: none;
opacity: 0;
transition: opacity 0.3s ease;
}
#authContainer.visible {
display: block !important;
opacity: 1;
}
/* 内容头部样式 */
.content-header {
display: flex;
justify-content: space-between;
align-items: center;
height: 54px;
background: white;
border-bottom: 1px solid #e0e0e0;
padding: 0 16px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
flex-shrink: 0;
}
.breadcrumb {
display: flex;
align-items: center;
color: #000000;
font-size: 20px;
font-weight: 1000;
height: 100%;
gap: 8px;
}
.breadcrumb .icon-small {
margin-right: 0;
margin-left: 0;
width: 20px;
height: 20px;
}
/* 添加新的样式 */
.header-right {
display: flex;
align-items: center;
gap: 16px;
}
/* 重置body样式 */
body {
margin: 0;
padding: 0;
overflow: hidden;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
font-size: 15px;
}
/* 确保内容区域完全填充 */
.main-content > * {
width: 100%;
}
/* 内容区域容器 */
.content-area-container {
display: flex;
flex-direction: column;
flex: 1;
overflow: hidden;
}
tabs-container {
flex-shrink: 0;
}
content-area {
flex: 1;
overflow: hidden;
}
/* Toast 提示样式 */
.toast {
position: fixed;
top: 20px;
right: 20px;
background: rgba(0, 0, 0, 0.8);
color: white;
padding: 12px 24px;
border-radius: 8px;
font-size: 14px;
z-index: 10000;
opacity: 0;
transition: opacity 0.3s ease;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.toast.show {
opacity: 1;
}
</style>
</head>
<body>
<div id="authContainer">
<auth-component></auth-component>
</div>
<div id="mainContainer" class="main-container">
<div class="content-wrapper">
<main-toolbar></main-toolbar>
<sub-toolbar></sub-toolbar>
<main class="main-content">
<div class="content-header">
<div class="breadcrumb">
<img src="assets/icons/png/con_b.png" alt="主页 / 概览" class="icon-small">
<span id="currentPath">主页 / 概览</span>
</div>
<div class="header-right">
<header-tools></header-tools>
<user-info></user-info>
</div>
</div>
<div class="content-area-container">
<tabs-container></tabs-container>
<content-area></content-area>
</div>
</main>
</div>
</div>
<script>
// Toast 提示函数
function showToast(message) {
const toast = document.createElement('div');
toast.className = 'toast';
toast.textContent = message;
document.body.appendChild(toast);
setTimeout(() => toast.classList.add('show'), 10);
setTimeout(() => {
toast.classList.remove('show');
setTimeout(() => toast.remove(), 300);
}, 2000);
}
document.addEventListener('DOMContentLoaded', () => {
const authComponent = document.querySelector('auth-component');
const authContainer = document.getElementById('authContainer');
const mainContainer = document.getElementById('mainContainer');
const tabsContainer = document.querySelector('tabs-container');
const contentArea = document.querySelector('content-area');
// 检查是否已登录
const checkAuth = async () => {
try {
const response = await fetch('/api/check-auth', {
credentials: 'include'
});
const result = await response.json();
if (result.success) {
// 只存储非敏感的用户信息
localStorage.setItem('userInfo', JSON.stringify({
username: result.user.username,
role: result.user.role,
// 其他非敏感信息...
}));
// 先初始化主页面
initializeMainPage();
authContainer.classList.remove('visible');
mainContainer.classList.add('visible');
// 触发一个自定义事件,通知其他组件登录成功
const loginSuccessEvent = new CustomEvent('login-success', {
detail: { user: result.user }
});
document.dispatchEvent(loginSuccessEvent);
} else {
authContainer.classList.add('visible');
mainContainer.classList.remove('visible');
}
} catch (error) {
console.error('认证检查错误:', error);
authContainer.classList.add('visible');
mainContainer.classList.remove('visible');
}
};
// 初始化主页面
async function initializeMainPage() {
// 清除所有现有的标签页,但保留概览标签页
const tabsContainer = document.querySelector('tabs-container');
if (tabsContainer) {
// 获取所有非概览标签页
const nonOverviewTabs = Array.from(tabsContainer.shadowRoot.querySelectorAll('.tab'))
.filter(tab => tab.getAttribute('data-tab') !== 'overview');
// 关闭所有非概览标签页
nonOverviewTabs.forEach(tab => {
tabsContainer.closeTab(tab.getAttribute('data-tab'));
});
}
// 确保所有组件都已经加载
const components = [
'main-toolbar',
'sub-toolbar',
'tabs-container',
'content-area'
];
// 等待所有组件加载完成
await Promise.all(components.map(component => {
return new Promise(resolve => {
if (customElements.get(component)) {
resolve();
} else {
customElements.whenDefined(component).then(resolve);
}
});
}));
// 初始化时创建概览标签页并加载概览内容
const contentArea = document.querySelector('content-area');
tabsContainer.createTab('overview', '概览', 'dashboard', '主页', 'home');
contentArea.loadContent('overview');
// 监听主工具栏选择事件
document.querySelector('main-toolbar').addEventListener('tool-selected', function(e) {
const { tool, text } = e.detail;
document.querySelector('sub-toolbar').setAttribute('current-tool', tool);
// 当选择主页时,显示概览
if (tool === 'home') {
tabsContainer.createTab('overview', '概览', 'dashboard', '主页', 'home');
}
});
// 监听子工具栏选择事件
document.querySelector('sub-toolbar').addEventListener('sub-item-selected', function(e) {
const { parent, text, icon } = e.detail;
const parentText = document.querySelector(`main-toolbar`).shadowRoot.querySelector(`[data-tool="${parent}"] span`).textContent;
updateBreadcrumb(parentText, text);
updateContent(text, icon, parentText, parent);
});
// 监听用户菜单动作
document.querySelector('user-info').addEventListener('menu-action', function(e) {
const { action } = e.detail;
handleMenuAction(action);
});
// 监听标签页激活事件
tabsContainer.addEventListener('tab-activated', function(e) {
const { id, parentText, title, parentTool, isTabSwitch } = e.detail;
// 更新面包屑导航
updateBreadcrumb(parentText, title);
// 只有在真正的标签切换时才加载内容
if (isTabSwitch) {
contentArea.loadContent(id);
}
// 同步更新面包屑导航
const breadcrumbIcon = document.querySelector('.breadcrumb .icon-small');
if (breadcrumbIcon) {
const iconName = getIconNameForTitle(title, parentTool);
breadcrumbIcon.src = `assets/icons/png/${iconName}_b.png`;
breadcrumbIcon.alt = `${parentText} / ${title}`;
}
});
// 监听标签页关闭事件
tabsContainer.addEventListener('tab-closed', function(e) {
const { id } = e.detail;
// 清除关闭标签页的内容缓存
contentArea.clearCache(id);
});
}
function handleMenuAction(action) {
const contentArea = document.querySelector('content-area');
const tabsContainer = document.querySelector('tabs-container');
switch(action) {
case 'profile':
tabsContainer.createTab('profile', '个人中心', 'user', '系统', 'system');
contentArea.loadContent('profile');
break;
case 'users':
tabsContainer.createTab('users', '用户管理', 'users', '系统', 'system');
contentArea.loadContent('users');
break;
case 'logout':
// 调用登出接口
fetch('/api/logout', {
method: 'POST',
credentials: 'include'
}).then(() => {
// 清除本地存储的用户信息
localStorage.removeItem('userInfo');
// 清除所有标签页
tabsContainer.clearAllTabs();
// 显示退出成功提示
showToast('已安全退出登录');
// 隐藏主容器
mainContainer.classList.remove('visible');
setTimeout(() => {
mainContainer.style.display = 'none';
authContainer.style.display = 'block';
requestAnimationFrame(() => {
authContainer.classList.add('visible');
const authComponent = document.querySelector('auth-component');
if (authComponent) {
authComponent.reset();
}
});
}, 300);
}).catch(error => {
console.error('登出错误:', error);
showToast('登出过程中发生错误');
});
break;
}
}
function updateBreadcrumb(mainMenu, subMenu) {
const currentPath = document.getElementById('currentPath');
currentPath.textContent = subMenu ? `${mainMenu} / ${subMenu}` : mainMenu;
}
function updateContent(title, icon, parentText, parentTool) {
const tabsContainer = document.querySelector('tabs-container');
const contentArea = document.querySelector('content-area');
if (title === '概览') {
// 直接激活第一个标签页(概览标签页)
const firstTab = tabsContainer.shadowRoot.querySelector('.tab');
if (firstTab) {
tabsContainer.activateTab(firstTab.getAttribute('data-tab'));
}
return;
}
// 特殊处理更新记录标签页
if (title === '更新记录') {
const id = 'update-history';
tabsContainer.createTab(id, title, icon, parentText, parentTool);
return;
}
// 处理运行日志标签页
if (title === '运行日志') {
const id = 'run-log';
tabsContainer.createTab(id, title, icon, parentText, parentTool);
return;
}
// 处理资源监控标签页
if (title === '资源监控') {
const id = 'system-info';
tabsContainer.createTab(id, title, icon, parentText, parentTool);
contentArea.loadContent(id);
return;
}
// 处理系统日志标签页
if (title === '系统日志') {
const id = 'system-log';
tabsContainer.createTab(id, title, icon, parentText, parentTool);
contentArea.loadContent(id);
return;
}
// 处理待办事项标签页
if (title === '待办事项') {
const id = 'todo';
tabsContainer.createTab(id, title, icon, parentText, parentTool);
contentArea.loadContent(id);
return;
}
// 处理帮助标签页
if (title === '帮助') {
const id = 'help';
tabsContainer.createTab(id, title, icon, parentText, parentTool);
contentArea.loadContent(id);
return;
}
// 处理Q&A标签页
if (title === 'Q&A') {
const id = 'qa';
tabsContainer.createTab(id, title, icon, parentText, parentTool);
contentArea.loadContent(id);
return;
}
// 处理构型配置标签页
if (title === '构型配置') {
const id = 'configuration-config';
tabsContainer.createTab(id, title, icon, parentText, parentTool);
contentArea.loadContent(id);
return;
}
// 处理接口配置标签页
if (title === '接口配置') {
const id = 'interface-config';
tabsContainer.createTab(id, title, icon, parentText, parentTool);
return;
}
// 处理模型开发标签页
if (title === '模型开发') {
const id = 'model-development';
tabsContainer.createTab(id, title, icon, parentText, parentTool);
return;
}
// 处理服务开发标签页
if (title === '服务开发') {
const id = 'service-development';
tabsContainer.createTab(id, title, icon, parentText, parentTool);
return;
}
// 处理运行测试标签页
if (title === '运行仿真') {
const id = 'run-sim';
tabsContainer.createTab(id, title, icon, parentText, parentTool);
return;
}
// 处理仿真监控标签页
if (title === '仿真监控') {
const id = 'simulation-monitor';
tabsContainer.createTab(id, title, icon, parentText, parentTool);
return;
}
// 处理模型监控标签页
if (title === '模型监控') {
const id = 'model-monitor';
tabsContainer.createTab(id, title, icon, parentText, parentTool);
return;
}
// 处理数据监控标签页
if (title === '数据监控') {
const id = 'data-monitor';
tabsContainer.createTab(id, title, icon, parentText, parentTool);
return;
}
// 处理数据采集标签页
if (title === '数据采集') {
const id = 'data-collection';
tabsContainer.createTab(id, title, icon, parentText, parentTool);
return;
}
// 处理个人中心标签页
if (title === '个人中心') {
const id = 'profile';
tabsContainer.createTab(id, title, icon, parentText, parentTool);
return;
}
// 处理用户管理标签页
if (title === '用户管理') {
const id = 'users';
tabsContainer.createTab(id, title, icon, parentText, parentTool);
return;
}
// 默认情况下使用标题转换为ID
const id = title.toLowerCase().replace(/\s+/g, '-');
tabsContainer.createTab(id, title, icon, parentText, parentTool);
}
// 根据标题和父工具获取图标名称的辅助函数
function getIconNameForTitle(title, parentTool) {
const iconMap = {
'概览': 'dashboard',
'更新记录': 'clock',
'运行日志': 'file',
'资源监控': 'server',
'帮助': 'help',
'Q&A': 'question',
'构型配置': 'chip',
'接口配置': 'plug',
'运行仿真': 'rocket',
'仿真监控': 'desktop',
'模型监控': 'cubes',
'数据监控': 'chart-bar',
'数据采集': 'database',
'个人中心': 'user',
'用户管理': 'users',
'模型开发': 'cube',
'服务开发': 'settings',
'系统日志': 'file-text'
};
return iconMap[title] || parentTool || 'con';
}
// 监听登录事件
authComponent.addEventListener('login', async (e) => {
const data = e.detail;
try {
const response = await fetch('/api/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data),
credentials: 'include' // 允许跨域请求携带cookie
});
const result = await response.json();
if (result.success) {
showToast(`欢迎回来,${result.user.username}`);
// 先显示主容器
mainContainer.style.display = 'block';
// 等待一帧以确保display:block生效
await new Promise(resolve => requestAnimationFrame(resolve));
// 添加visible类触发过渡效果
mainContainer.classList.add('visible');
// 等待过渡效果完成
await new Promise(resolve => setTimeout(resolve, 300));
// 隐藏认证容器
authContainer.classList.remove('visible');
// 等待过渡效果完成
await new Promise(resolve => setTimeout(resolve, 300));
authContainer.style.display = 'none';
// 初始化主页面
await initializeMainPage();
// 更新用户信息组件
const userInfo = document.querySelector('user-info');
if (userInfo) {
userInfo.updateUserInfo(result.user);
}
// 触发登录成功事件
const loginSuccessEvent = new CustomEvent('login-success', {
detail: { user: result.user }
});
document.dispatchEvent(loginSuccessEvent);
// 重新初始化todo-component
const todoComponent = document.querySelector('todo-component');
if (todoComponent) {
todoComponent.initialize();
}
} else {
showToast(result.message || '登录失败,请检查用户名和密码');
}
} catch (error) {
console.error('登录错误:', error);
showToast('登录过程中发生错误');
}
});
// 监听注册事件
authComponent.addEventListener('register', async (e) => {
const data = e.detail;
try {
const response = await fetch('/api/register', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
const result = await response.json();
if (result.success) {
showToast('注册成功!请登录');
// 切换到登录表单
const loginToggle = authComponent.shadowRoot.getElementById('loginToggle');
loginToggle.click();
} else {
showToast(result.message || '注册失败,请稍后重试');
}
} catch (error) {
console.error('注册错误:', error);
showToast('注册过程中发生错误');
}
});
// 初始检查认证状态
checkAuth();
});
</script>
</body>
</html>