2025-05-11 08:59:49 +08:00
|
|
|
|
import { ipcRenderer, WebviewTag } from "electron";
|
2025-04-30 00:05:32 +08:00
|
|
|
|
|
2025-04-30 18:42:39 +08:00
|
|
|
|
// 菜单项
|
2025-04-30 00:05:32 +08:00
|
|
|
|
interface MenuItem {
|
|
|
|
|
ShowName: string;
|
|
|
|
|
Url: string;
|
2025-04-30 18:42:39 +08:00
|
|
|
|
IconConfig: IconConfig;
|
2025-04-30 00:05:32 +08:00
|
|
|
|
Children: MenuItem[] | null;
|
|
|
|
|
}
|
2025-04-29 18:36:29 +08:00
|
|
|
|
|
2025-04-30 18:42:39 +08:00
|
|
|
|
// 图标配置
|
|
|
|
|
interface IconConfig {
|
|
|
|
|
_1x: {
|
|
|
|
|
Default: string;
|
|
|
|
|
Selected: string;
|
|
|
|
|
};
|
|
|
|
|
_2x: {
|
|
|
|
|
Default: string;
|
|
|
|
|
Selected: string;
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-30 00:05:32 +08:00
|
|
|
|
// API响应接口
|
|
|
|
|
interface ApiResponse<T> {
|
|
|
|
|
status: number;
|
|
|
|
|
code: number;
|
|
|
|
|
msg: string;
|
|
|
|
|
data: T;
|
|
|
|
|
}
|
2025-04-29 18:36:29 +08:00
|
|
|
|
|
2025-05-11 08:59:49 +08:00
|
|
|
|
// Tab management
|
|
|
|
|
interface Tab {
|
|
|
|
|
id: string;
|
|
|
|
|
title: string;
|
|
|
|
|
url: string;
|
|
|
|
|
webview: WebviewTag;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let tabs: Tab[] = [];
|
|
|
|
|
let activeTabId: string | null = null;
|
|
|
|
|
|
|
|
|
|
// Create a new tab
|
|
|
|
|
function createTab(title: string, url: string): Tab {
|
|
|
|
|
const id = `tab-${Date.now()}`;
|
|
|
|
|
const tabPane = document.createElement('div');
|
|
|
|
|
tabPane.className = 'tab-pane';
|
|
|
|
|
tabPane.id = `pane-${id}`;
|
|
|
|
|
|
|
|
|
|
const webview = document.createElement('webview');
|
|
|
|
|
webview.className = 'page-content';
|
|
|
|
|
webview.setAttribute('autosize', 'on');
|
|
|
|
|
webview.setAttribute('allowpopups', 'true');
|
|
|
|
|
webview.setAttribute('webpreferences', 'contextIsolation=yes, nodeIntegration=no');
|
|
|
|
|
webview.src = url;
|
|
|
|
|
|
|
|
|
|
tabPane.appendChild(webview);
|
|
|
|
|
document.getElementById('tabsContent')?.appendChild(tabPane);
|
|
|
|
|
|
|
|
|
|
const tab: Tab = {
|
|
|
|
|
id,
|
|
|
|
|
title,
|
|
|
|
|
url,
|
|
|
|
|
webview
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
tabs.push(tab);
|
|
|
|
|
return tab;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create tab header
|
|
|
|
|
function createTabHeader(tab: Tab): HTMLLIElement {
|
|
|
|
|
const li = document.createElement('li');
|
|
|
|
|
li.className = 'tab-item';
|
|
|
|
|
li.dataset.tabId = tab.id;
|
|
|
|
|
|
|
|
|
|
const titleSpan = document.createElement('span');
|
|
|
|
|
titleSpan.className = 'tab-title';
|
|
|
|
|
titleSpan.textContent = tab.title;
|
|
|
|
|
|
|
|
|
|
const closeButton = document.createElement('span');
|
|
|
|
|
closeButton.className = 'tab-close';
|
|
|
|
|
closeButton.textContent = '×';
|
|
|
|
|
closeButton.addEventListener('click', (e) => {
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
closeTab(tab.id);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
li.appendChild(titleSpan);
|
|
|
|
|
li.appendChild(closeButton);
|
|
|
|
|
|
|
|
|
|
li.addEventListener('click', () => {
|
|
|
|
|
activateTab(tab.id);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return li;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Activate a tab
|
|
|
|
|
function activateTab(tabId: string) {
|
|
|
|
|
const tab = tabs.find(t => t.id === tabId);
|
|
|
|
|
if (!tab) return;
|
|
|
|
|
|
|
|
|
|
// Update active states
|
|
|
|
|
document.querySelectorAll('.tab-item').forEach(item => {
|
|
|
|
|
item.classList.remove('active');
|
|
|
|
|
});
|
|
|
|
|
document.querySelectorAll('.tab-pane').forEach(pane => {
|
|
|
|
|
pane.classList.remove('active');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Activate the selected tab
|
|
|
|
|
const tabElement = document.querySelector(`.tab-item[data-tab-id="${tabId}"]`);
|
|
|
|
|
const paneElement = document.getElementById(`pane-${tabId}`);
|
|
|
|
|
if (tabElement && paneElement) {
|
|
|
|
|
tabElement.classList.add('active');
|
|
|
|
|
paneElement.classList.add('active');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
activeTabId = tabId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Close a tab
|
|
|
|
|
function closeTab(tabId: string) {
|
|
|
|
|
const tabIndex = tabs.findIndex(t => t.id === tabId);
|
|
|
|
|
if (tabIndex === -1) return;
|
|
|
|
|
|
|
|
|
|
const tab = tabs[tabIndex];
|
|
|
|
|
const tabElement = document.querySelector(`.tab-item[data-tab-id="${tabId}"]`);
|
|
|
|
|
const paneElement = document.getElementById(`pane-${tabId}`);
|
|
|
|
|
|
|
|
|
|
if (tabElement) tabElement.remove();
|
|
|
|
|
if (paneElement) paneElement.remove();
|
|
|
|
|
|
|
|
|
|
tabs.splice(tabIndex, 1);
|
|
|
|
|
|
|
|
|
|
// If we closed the active tab, activate another one
|
|
|
|
|
if (activeTabId === tabId) {
|
|
|
|
|
if (tabs.length > 0) {
|
|
|
|
|
activateTab(tabs[Math.min(tabIndex, tabs.length - 1)].id);
|
|
|
|
|
} else {
|
|
|
|
|
activeTabId = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-29 18:36:29 +08:00
|
|
|
|
// 检查登录状态
|
|
|
|
|
function checkLoginStatus() {
|
2025-04-30 23:09:05 +08:00
|
|
|
|
const cookie = window.electronAPI.getSessionStorage('cookie');
|
|
|
|
|
if (!cookie) {
|
2025-04-29 18:36:29 +08:00
|
|
|
|
window.location.href = 'login.html';
|
|
|
|
|
return;
|
|
|
|
|
}
|
2025-04-30 00:05:32 +08:00
|
|
|
|
|
2025-04-29 18:36:29 +08:00
|
|
|
|
// 显示用户信息
|
|
|
|
|
const userInfo = document.getElementById('userInfo');
|
|
|
|
|
if (userInfo) {
|
|
|
|
|
userInfo.textContent = '欢迎使用';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 处理退出登录
|
|
|
|
|
function handleLogout() {
|
2025-04-30 23:09:05 +08:00
|
|
|
|
window.electronAPI.removeSessionStorage('cookie');
|
2025-04-29 18:36:29 +08:00
|
|
|
|
window.location.href = 'login.html';
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-30 00:05:32 +08:00
|
|
|
|
// 获取菜单列表
|
|
|
|
|
async function getMenuList(): Promise<MenuItem[]> {
|
|
|
|
|
try {
|
|
|
|
|
const response = await fetch('http://1.12.73.211:8848/EIAC_Desktop_Api/api/Menu/GetMenu', {
|
2025-04-30 23:09:05 +08:00
|
|
|
|
method: 'POST',
|
|
|
|
|
headers: {
|
|
|
|
|
'Content-Type': 'application/json; charset=utf-8'
|
|
|
|
|
}
|
2025-04-29 18:36:29 +08:00
|
|
|
|
});
|
2025-04-30 00:05:32 +08:00
|
|
|
|
|
|
|
|
|
const result = await response.json() as ApiResponse<MenuItem[]>;
|
|
|
|
|
if (result.status === 0) {
|
|
|
|
|
return result.data;
|
|
|
|
|
} else {
|
|
|
|
|
throw new Error(result.msg || '获取菜单失败');
|
2025-04-29 18:36:29 +08:00
|
|
|
|
}
|
2025-04-30 00:05:32 +08:00
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('获取菜单失败:', error);
|
|
|
|
|
throw error;
|
2025-04-29 18:36:29 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-11 08:59:49 +08:00
|
|
|
|
// Modify the createMenuItem function to handle new tab creation
|
2025-04-30 18:42:39 +08:00
|
|
|
|
function createMenuItem(item: MenuItem, menuList: MenuItem[]): HTMLLIElement {
|
2025-04-30 00:05:32 +08:00
|
|
|
|
const li = document.createElement('li');
|
|
|
|
|
li.className = 'menu-item';
|
2025-04-29 18:36:29 +08:00
|
|
|
|
|
2025-04-30 00:05:32 +08:00
|
|
|
|
const icon = document.createElement('img');
|
2025-04-30 18:42:39 +08:00
|
|
|
|
icon.src = item.IconConfig._1x.Default;
|
2025-04-30 00:05:32 +08:00
|
|
|
|
icon.alt = item.ShowName;
|
|
|
|
|
icon.className = 'menu-icon';
|
|
|
|
|
|
|
|
|
|
const span = document.createElement('span');
|
|
|
|
|
span.textContent = item.ShowName;
|
|
|
|
|
|
|
|
|
|
li.appendChild(icon);
|
|
|
|
|
li.appendChild(span);
|
|
|
|
|
|
|
|
|
|
if (item.Url) {
|
2025-04-30 17:28:03 +08:00
|
|
|
|
li.addEventListener('click', async () => {
|
2025-05-11 08:59:49 +08:00
|
|
|
|
// Remove active state from other menu items
|
2025-04-30 18:42:39 +08:00
|
|
|
|
document.querySelectorAll('.menu-item').forEach(menuItem => {
|
|
|
|
|
menuItem.classList.remove('active');
|
|
|
|
|
const menuIcon = menuItem.querySelector('.menu-icon') as HTMLImageElement;
|
|
|
|
|
if (menuIcon) {
|
|
|
|
|
const menuItemData = menuList.find((m: MenuItem) => m.ShowName === menuItem.querySelector('span')?.textContent);
|
|
|
|
|
if (menuItemData) {
|
|
|
|
|
menuIcon.src = menuItemData.IconConfig._1x.Default;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
2025-04-30 23:09:05 +08:00
|
|
|
|
|
2025-05-11 08:59:49 +08:00
|
|
|
|
// Add active state to current menu item
|
2025-04-30 18:42:39 +08:00
|
|
|
|
li.classList.add('active');
|
|
|
|
|
icon.src = item.IconConfig._1x.Selected;
|
2025-04-30 17:28:03 +08:00
|
|
|
|
|
|
|
|
|
const url: string = item.Url.startsWith("http") ? item.Url : `http://${item.Url}`;
|
2025-04-30 23:09:05 +08:00
|
|
|
|
const result = await window.electronAPI.checkUrlAvailable(url);
|
2025-04-30 17:28:03 +08:00
|
|
|
|
if (result.ok && result.status >= 200 && result.status < 400) {
|
|
|
|
|
console.log('✅ URL 可访问:', result.status);
|
2025-04-30 23:31:36 +08:00
|
|
|
|
const cookies: string = window.electronAPI.getSessionStorage('cookie');
|
|
|
|
|
await window.electronAPI.setWebviewCookie(url, cookies);
|
2025-05-11 08:59:49 +08:00
|
|
|
|
|
|
|
|
|
// Create new tab
|
|
|
|
|
const tab = createTab(item.ShowName, url);
|
|
|
|
|
const tabHeader = createTabHeader(tab);
|
|
|
|
|
document.getElementById('tabsList')?.appendChild(tabHeader);
|
|
|
|
|
activateTab(tab.id);
|
2025-04-30 17:28:03 +08:00
|
|
|
|
} else {
|
|
|
|
|
console.warn('❌ URL 不可访问:', result.error ?? `status ${result.status}`);
|
2025-04-30 18:04:22 +08:00
|
|
|
|
showErrorModal(`无法访问 ${url}\r\n异常原因:${result.error ?? `status ${result.status}`}\r\n请联系10000技术支持。`);
|
2025-04-30 17:28:03 +08:00
|
|
|
|
}
|
2025-04-30 00:05:32 +08:00
|
|
|
|
});
|
2025-04-29 18:36:29 +08:00
|
|
|
|
}
|
2025-04-30 00:05:32 +08:00
|
|
|
|
|
|
|
|
|
return li;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 渲染菜单
|
|
|
|
|
function renderMenu(menuList: MenuItem[]) {
|
|
|
|
|
const menuContainer = document.getElementById('menuList');
|
|
|
|
|
if (!menuContainer) return;
|
|
|
|
|
|
|
|
|
|
menuList.forEach(item => {
|
2025-04-30 18:42:39 +08:00
|
|
|
|
const menuItem = createMenuItem(item, menuList);
|
2025-04-30 00:05:32 +08:00
|
|
|
|
menuContainer.appendChild(menuItem);
|
|
|
|
|
|
|
|
|
|
if (item.Children) {
|
|
|
|
|
const subMenu = document.createElement('ul');
|
|
|
|
|
subMenu.className = 'submenu';
|
|
|
|
|
item.Children.forEach(child => {
|
2025-04-30 18:42:39 +08:00
|
|
|
|
const childItem = createMenuItem(child, menuList);
|
2025-04-30 00:05:32 +08:00
|
|
|
|
subMenu.appendChild(childItem);
|
|
|
|
|
});
|
|
|
|
|
menuContainer.appendChild(subMenu);
|
|
|
|
|
}
|
|
|
|
|
});
|
2025-04-29 18:36:29 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-04-30 18:04:22 +08:00
|
|
|
|
// 显示故障窗口
|
|
|
|
|
function showErrorModal(message: string) {
|
|
|
|
|
const errorModal = document.getElementById('errorModal') as HTMLDivElement;
|
|
|
|
|
const errorMessage = document.getElementById('errorMessage') as HTMLParagraphElement;
|
|
|
|
|
errorMessage.textContent = message;
|
|
|
|
|
errorModal.style.display = 'block';
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-11 08:59:49 +08:00
|
|
|
|
// Modify the initialize function to create the first tab
|
2025-04-30 00:05:32 +08:00
|
|
|
|
async function initialize() {
|
2025-05-11 08:59:49 +08:00
|
|
|
|
// Check login status
|
2025-04-29 18:36:29 +08:00
|
|
|
|
checkLoginStatus();
|
2025-04-30 00:05:32 +08:00
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const menuList = await getMenuList();
|
|
|
|
|
renderMenu(menuList);
|
|
|
|
|
|
2025-05-11 08:59:49 +08:00
|
|
|
|
// Create initial tab
|
|
|
|
|
const initialTab = createTab('首页', 'about:blank');
|
|
|
|
|
const tabHeader = createTabHeader(initialTab);
|
|
|
|
|
document.getElementById('tabsList')?.appendChild(tabHeader);
|
|
|
|
|
activateTab(initialTab.id);
|
|
|
|
|
|
|
|
|
|
// Bind logout event
|
2025-04-30 00:05:32 +08:00
|
|
|
|
const logoutBtn = document.getElementById('btnLogout');
|
|
|
|
|
if (logoutBtn) {
|
|
|
|
|
logoutBtn.addEventListener('click', handleLogout);
|
|
|
|
|
}
|
2025-04-30 18:04:22 +08:00
|
|
|
|
|
|
|
|
|
const errorModal = document.getElementById('errorModal') as HTMLDivElement;
|
|
|
|
|
const closeErrorModal = document.getElementById('closeErrorModal') as HTMLButtonElement;
|
2025-05-11 08:59:49 +08:00
|
|
|
|
// Close button click event
|
2025-04-30 23:09:05 +08:00
|
|
|
|
closeErrorModal.addEventListener('click', (event) => {
|
2025-04-30 18:04:22 +08:00
|
|
|
|
errorModal.style.display = 'none';
|
|
|
|
|
});
|
|
|
|
|
|
2025-05-11 08:59:49 +08:00
|
|
|
|
// Click outside to close
|
2025-04-30 18:04:22 +08:00
|
|
|
|
window.addEventListener('click', (event) => {
|
|
|
|
|
if (event.target === errorModal) {
|
|
|
|
|
errorModal.style.display = 'none';
|
|
|
|
|
}
|
|
|
|
|
});
|
2025-04-30 00:05:32 +08:00
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('初始化失败:', error);
|
2025-04-29 18:36:29 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-30 00:05:32 +08:00
|
|
|
|
// 页面加载完成后初始化
|
2025-04-29 18:36:29 +08:00
|
|
|
|
document.addEventListener('DOMContentLoaded', initialize);
|