diff --git a/spug_api/consumer/consumers.py b/spug_api/consumer/consumers.py index 913982e..6e20b77 100644 --- a/spug_api/consumer/consumers.py +++ b/spug_api/consumer/consumers.py @@ -107,9 +107,10 @@ class SSHConsumer(WebsocketConsumer): self.chan.send(data['data']) def disconnect(self, code): - self.chan.close() - self.ssh.close() - # print('Connection close') + if self.chan: + self.chan.close() + if self.ssh: + self.ssh.close() def connect(self): if has_host_perm(self.user, self.id): diff --git a/spug_web/src/pages/ssh/index.js b/spug_web/src/pages/ssh/index.js index 57731e5..6bde02a 100644 --- a/spug_web/src/pages/ssh/index.js +++ b/spug_web/src/pages/ssh/index.js @@ -5,13 +5,18 @@ */ import React, { useEffect, useState } from 'react'; import { observer } from 'mobx-react'; -import { Tabs, Tree, Input, Spin, Button } from 'antd'; +import { Tabs, Tree, Input, Spin, Dropdown, Menu, Button } from 'antd'; import { FolderOutlined, FolderOpenOutlined, CloudServerOutlined, SearchOutlined, - SyncOutlined + SyncOutlined, + CopyOutlined, + ReloadOutlined, + VerticalAlignBottomOutlined, + VerticalAlignMiddleOutlined, + CloseOutlined } from '@ant-design/icons'; import { NotFound, AuthButton } from 'components'; import Terminal from './Terminal'; @@ -85,11 +90,17 @@ function WebSSH(props) { .finally(() => setFetching(false)) } - function _openNode(node) { - node.vId = String(new Date().getTime()) - hosts.push(node); + function _openNode(node, replace) { + const newNode = {...node} + newNode.vId = String(new Date().getTime()) + if (replace) { + const index = lds.findIndex(hosts, {vId: node.vId}) + if (index >= 0) hosts[index] = newNode + } else { + hosts.push(newNode); + } setHosts(lds.cloneDeep(hosts)) - setActiveId(node.vId) + setActiveId(newNode.vId) } function handleSelect(e) { @@ -98,12 +109,13 @@ function WebSSH(props) { } } - function handleRemove(key, action) { - if (action === 'remove') { - const index = lds.findIndex(hosts, x => x.vId === key); - if (index !== -1) { - hosts.splice(index, 1); - setHosts(lds.cloneDeep(hosts)); + function handleRemove(key, target) { + const index = lds.findIndex(hosts, x => x.vId === key); + if (index === -1) return; + switch (target) { + case 'self': + hosts.splice(index, 1) + setHosts([...hosts]) if (hosts.length > index) { setActiveId(hosts[index].vId) } else if (hosts.length) { @@ -111,7 +123,22 @@ function WebSSH(props) { } else { setActiveId(undefined) } - } + break + case 'right': + hosts.splice(index + 1, hosts.length) + setHosts([...hosts]) + setActiveId(key) + break + case 'other': + setHosts([hosts[index]]) + setActiveId(key) + break + case 'all': + setHosts([]) + setActiveId(undefined) + break + default: + break } } @@ -139,6 +166,43 @@ function WebSSH(props) { } } + function handeTabAction(action, host, e) { + if (e) e.stopPropagation() + switch (action) { + case 'copy': + return _openNode(host) + case 'reconnect': + return _openNode(host, true) + case 'rClose': + return handleRemove(host.vId, 'right') + case 'oClose': + return handleRemove(host.vId, 'other') + case 'aClose': + return handleRemove(host.vId, 'all') + default: + break + } + } + + function TabRender(props) { + const host = props.host; + return ( + handeTabAction(key, host, domEvent)}> + }>复制窗口 + }>重新连接 + }>关闭右侧 + }>关闭其他 + }>关闭所有 + + )}> +
handeTabAction('copy', host)}>{host.title}
+
+ ) + } + const spug_web_terminal = ' __ __ _ __\n' + ' _____ ____ __ __ ____ _ _ __ ___ / /_ / /_ ___ _____ ____ ___ (_)____ ____ _ / /\n' + @@ -158,12 +222,14 @@ function WebSSH(props) { } placeholder="输入检索" onChange={e => setSearchValue(e.target.value)}/>