From 7e752c4671f46b442d81602cbb9016e3e795ee2f Mon Sep 17 00:00:00 2001 From: chaos-zhu Date: Fri, 13 Mar 2026 20:04:49 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E7=BB=88=E7=AB=AF?= =?UTF-8?q?=E5=86=85=E5=8F=B3=E9=94=AE=E6=8C=82=E8=B5=B7&=E5=8D=95?= =?UTF-8?q?=E7=AA=97=E5=8F=A3=E6=A8=A1=E5=BC=8F=E5=A4=B4=E9=83=A8=E5=8F=B3?= =?UTF-8?q?=E9=94=AE=E8=8F=9C=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../composables/useTerminalTabContextMenu.js | 82 +++++++++++++++++ .../components/terminal-single-window.vue | 91 ++++++++++++++++++- .../terminal/components/terminal-wrapper.vue | 75 +++++++-------- .../views/terminal/components/terminal.vue | 12 ++- 4 files changed, 211 insertions(+), 49 deletions(-) create mode 100644 web/src/composables/useTerminalTabContextMenu.js diff --git a/web/src/composables/useTerminalTabContextMenu.js b/web/src/composables/useTerminalTabContextMenu.js new file mode 100644 index 0000000..6aff853 --- /dev/null +++ b/web/src/composables/useTerminalTabContextMenu.js @@ -0,0 +1,82 @@ +/** + * useTerminalTabContextMenu + * 抽离终端 Tab / 标题栏右键菜单的通用逻辑,供多窗口模式和单窗口模式复用。 + * + * @param {Object} options + * @param {import('vue').ComputedRef} options.terminalTabs - 当前所有终端 tab 列表 + * @param {Function} options.onSuspend - (item, index) => Promise 挂起单个终端 + * @param {Function} options.onSuspendAll - () => void 挂起所有 + * @param {Function} options.onCloseOther - (index) => void 关闭其他 + * @param {Function} options.onCloseAll - () => void 关闭所有 + * @param {import('@/composables/useContextMenu').showMenu} options.showMenu - 显示右键菜单的方法 + * @param {import('@/utils/enum').terminalStatus} options.terminalStatus - 终端状态枚举 + */ +export function useTerminalTabContextMenu({ + terminalTabs, + onSuspend, + onSuspendAll, + onCloseOther, + onCloseAll, + showMenu, + terminalStatus +}) { + /** + * 构建 Tab / 标题栏右键菜单项 + * @param {object} item - 当前 tab 对象 + * @param {number} index - 当前 tab 索引(单窗口模式中也传入相应索引) + */ + const buildTabMenuItems = (item, index) => { + const menuItems = [] + + // 挂起终端(仅在已连接状态显示) + if (item.status === terminalStatus.CONNECT_SUCCESS) { + menuItems.push({ + label: '挂起', + onClick: () => onSuspend(item, index) + }) + } + + // 挂起所有会话(存在已连接会话时显示) + const tabs = typeof terminalTabs === 'function' ? terminalTabs() : terminalTabs.value + if (tabs.some(tab => tab.status === terminalStatus.CONNECT_SUCCESS)) { + menuItems.push({ + label: '挂起所有', + onClick: () => onSuspendAll() + }) + } + + // 关闭其他终端 + if (tabs.length > 1) { + menuItems.push({ + label: '关闭其他', + onClick: () => onCloseOther(index, item) + }) + } + + // 关闭所有终端 + menuItems.push({ + label: '关闭所有', + onClick: () => onCloseAll() + }) + + return menuItems + } + + /** + * 处理 Tab / 标题栏右键事件 + * @param {MouseEvent} e + * @param {object} item + * @param {number} index + */ + const handleTabContextMenu = (e, item, index) => { + e.preventDefault() + e.stopPropagation() + const menuItems = buildTabMenuItems(item, index) + showMenu(e, menuItems) + } + + return { + buildTabMenuItems, + handleTabContextMenu + } +} diff --git a/web/src/views/terminal/components/terminal-single-window.vue b/web/src/views/terminal/components/terminal-single-window.vue index e32c05c..d9db66f 100644 --- a/web/src/views/terminal/components/terminal-single-window.vue +++ b/web/src/views/terminal/components/terminal-single-window.vue @@ -18,7 +18,10 @@ :style="panel.style" > -
+
{{ String(index + 1).padStart(2, '0') }}