diff --git a/index.html b/index.html
index 9a5d38e..4015727 100644
--- a/index.html
+++ b/index.html
@@ -28,7 +28,16 @@
diff --git a/src/index.css b/src/index.css
index 957ff21..f12c922 100644
--- a/src/index.css
+++ b/src/index.css
@@ -170,4 +170,89 @@ body {
.close-btn:hover {
background-color: #2980b9;
+}
+
+/* Tabs styles */
+.tabs-container {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ width: 100%;
+}
+
+.tabs-header {
+ background-color: #f5f5f5;
+ border-bottom: 1px solid #ddd;
+}
+
+.tabs-list {
+ display: flex;
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ height: 40px;
+}
+
+.tab-item {
+ display: flex;
+ align-items: center;
+ padding: 0 15px;
+ height: 100%;
+ border-right: 1px solid #ddd;
+ background-color: #fff;
+ cursor: pointer;
+ user-select: none;
+ position: relative;
+}
+
+.tab-item.active {
+ background-color: #fff;
+ border-bottom: 2px solid #1890ff;
+}
+
+.tab-item .tab-title {
+ margin-right: 8px;
+ max-width: 150px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.tab-item .tab-close {
+ width: 16px;
+ height: 16px;
+ line-height: 16px;
+ text-align: center;
+ border-radius: 50%;
+ color: #999;
+ font-size: 12px;
+}
+
+.tab-item .tab-close:hover {
+ background-color: #e6e6e6;
+ color: #666;
+}
+
+.tabs-content {
+ flex: 1;
+ position: relative;
+}
+
+.tab-pane {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ display: none;
+}
+
+.tab-pane.active {
+ display: block;
+}
+
+.tab-pane webview {
+ width: 100%;
+ height: 100%;
+ border: none;
}
\ No newline at end of file
diff --git a/src/index.ts b/src/index.ts
index ef06b29..b1ac258 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,4 +1,4 @@
-import { WebviewTag } from "electron";
+import { ipcRenderer, WebviewTag } from "electron";
// 菜单项
interface MenuItem {
@@ -28,6 +28,121 @@ interface ApiResponse {
data: T;
}
+// 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;
+ }
+ }
+}
+
// 检查登录状态
function checkLoginStatus() {
const cookie = window.electronAPI.getSessionStorage('cookie');
@@ -71,7 +186,7 @@ async function getMenuList(): Promise