feat: 支持应用内多 SSH 终端标签页
- 新增 terminalTabs store 管理标签页状态 - 新增 TerminalWorkspaceView 终端工作区视图 - 修改 ConnectionsView 终端按钮改用标签页模式 - 修改 TerminalView 作为兼容入口自动跳转到工作区 - 同一连接默认只保留一个标签页 - 切换标签时保持各自 SSH 会话不断开
This commit is contained in:
74
frontend/src/stores/terminalTabs.ts
Normal file
74
frontend/src/stores/terminalTabs.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref, computed } from 'vue'
|
||||
import type { Connection } from '../api/connections'
|
||||
|
||||
export interface TerminalTab {
|
||||
id: string
|
||||
connectionId: number
|
||||
title: string
|
||||
active: boolean
|
||||
}
|
||||
|
||||
export const useTerminalTabsStore = defineStore('terminalTabs', () => {
|
||||
const tabs = ref<TerminalTab[]>([])
|
||||
const activeTabId = ref<string | null>(null)
|
||||
|
||||
const activeTab = computed(() => tabs.value.find(t => t.id === activeTabId.value) || null)
|
||||
|
||||
function generateTabId() {
|
||||
return `tab-${Date.now()}-${Math.random().toString(16).slice(2)}`
|
||||
}
|
||||
|
||||
function openOrFocus(connection: Connection) {
|
||||
// 检查是否已存在该连接的标签页
|
||||
const existing = tabs.value.find(t => t.connectionId === connection.id)
|
||||
if (existing) {
|
||||
activate(existing.id)
|
||||
return existing.id
|
||||
}
|
||||
|
||||
// 创建新标签页
|
||||
const newTab: TerminalTab = {
|
||||
id: generateTabId(),
|
||||
connectionId: connection.id,
|
||||
title: connection.name,
|
||||
active: true,
|
||||
}
|
||||
|
||||
tabs.value.push(newTab)
|
||||
activate(newTab.id)
|
||||
return newTab.id
|
||||
}
|
||||
|
||||
function activate(tabId: string) {
|
||||
tabs.value.forEach(t => {
|
||||
t.active = t.id === tabId
|
||||
})
|
||||
activeTabId.value = tabId
|
||||
}
|
||||
|
||||
function close(tabId: string) {
|
||||
const index = tabs.value.findIndex(t => t.id === tabId)
|
||||
if (index === -1) return
|
||||
|
||||
const wasActive = tabs.value[index]!.active
|
||||
tabs.value.splice(index, 1)
|
||||
|
||||
// 如果关闭的是活动标签,激活相邻标签
|
||||
if (wasActive && tabs.value.length > 0) {
|
||||
const newIndex = Math.min(index, tabs.value.length - 1)
|
||||
activate(tabs.value[newIndex]!.id)
|
||||
} else if (tabs.value.length === 0) {
|
||||
activeTabId.value = null
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
tabs,
|
||||
activeTabId,
|
||||
activeTab,
|
||||
openOrFocus,
|
||||
activate,
|
||||
close,
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user