mirror of https://github.com/openspug/spug
A 新增web终端独立文件管理器模式
parent
efc6bf5f2b
commit
c42b795f33
|
@ -29,7 +29,8 @@ export default observer(function () {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AuthDiv auth="host.host.view">
|
<AuthDiv auth="host.host.view">
|
||||||
<Breadcrumb extra={<AuthButton auth="host.console.view" type="primary" icon={<CodeOutlined/>} onClick={openTerminal}>Web 终端</AuthButton>}>
|
<Breadcrumb extra={<AuthButton auth="host.console.view|host.console.list" type="primary" icon={<CodeOutlined/>}
|
||||||
|
onClick={openTerminal}>Web 终端</AuthButton>}>
|
||||||
<Breadcrumb.Item>首页</Breadcrumb.Item>
|
<Breadcrumb.Item>首页</Breadcrumb.Item>
|
||||||
<Breadcrumb.Item>主机管理</Breadcrumb.Item>
|
<Breadcrumb.Item>主机管理</Breadcrumb.Item>
|
||||||
</Breadcrumb>
|
</Breadcrumb>
|
||||||
|
@ -49,7 +50,7 @@ export default observer(function () {
|
||||||
{store.cloudImport && <CloudImport/>}
|
{store.cloudImport && <CloudImport/>}
|
||||||
{store.syncVisible && <BatchSync/>}
|
{store.syncVisible && <BatchSync/>}
|
||||||
{store.selectorVisible &&
|
{store.selectorVisible &&
|
||||||
<Selector oneGroup={!store.addByCopy} onCancel={() => store.selectorVisible = false} onOk={store.updateGroup}/>}
|
<Selector oneGroup={!store.addByCopy} onCancel={() => store.selectorVisible = false} onOk={store.updateGroup}/>}
|
||||||
</AuthDiv>
|
</AuthDiv>
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* Released under the AGPL-3.0 License.
|
* Released under the AGPL-3.0 License.
|
||||||
*/
|
*/
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Drawer, Breadcrumb, Table, Switch, Progress, Modal, message } from 'antd';
|
import { Breadcrumb, Table, Switch, Progress, Modal, message } from 'antd';
|
||||||
import {
|
import {
|
||||||
DeleteOutlined,
|
DeleteOutlined,
|
||||||
DownloadOutlined,
|
DownloadOutlined,
|
||||||
|
@ -34,6 +34,10 @@ class FileManager extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.fetchFiles()
|
||||||
|
}
|
||||||
|
|
||||||
columns = [{
|
columns = [{
|
||||||
title: '名称',
|
title: '名称',
|
||||||
key: 'name',
|
key: 'name',
|
||||||
|
@ -78,12 +82,6 @@ class FileManager extends React.Component {
|
||||||
) : null
|
) : null
|
||||||
}];
|
}];
|
||||||
|
|
||||||
onShow = (visible) => {
|
|
||||||
if (visible) {
|
|
||||||
this.fetchFiles()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
_kindSort = (item) => {
|
_kindSort = (item) => {
|
||||||
return item.kind === 'd'
|
return item.kind === 'd'
|
||||||
};
|
};
|
||||||
|
@ -131,7 +129,7 @@ class FileManager extends React.Component {
|
||||||
this.setState({uploadStatus: 'success'});
|
this.setState({uploadStatus: 'success'});
|
||||||
this.fetchFiles()
|
this.fetchFiles()
|
||||||
}, () => this.setState({uploadStatus: 'exception'}))
|
}, () => this.setState({uploadStatus: 'exception'}))
|
||||||
.finally(() => setTimeout(() => this.setState({uploading: false}), 2000))
|
.finally(() => setTimeout(() => this.setState({uploading: false}), 2000))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -188,15 +186,9 @@ class FileManager extends React.Component {
|
||||||
if (!this.state.showDot) {
|
if (!this.state.showDot) {
|
||||||
objects = objects.filter(x => !x.name.startsWith('.'))
|
objects = objects.filter(x => !x.name.startsWith('.'))
|
||||||
}
|
}
|
||||||
const scrollY = document.body.clientHeight - 182;
|
const scrollY = document.body.clientHeight - 168;
|
||||||
return (
|
return (
|
||||||
<Drawer
|
<React.Fragment>
|
||||||
title="文件管理器"
|
|
||||||
placement="right"
|
|
||||||
width={900}
|
|
||||||
afterVisibleChange={this.onShow}
|
|
||||||
visible={this.props.visible}
|
|
||||||
onClose={this.props.onClose}>
|
|
||||||
<input style={{display: 'none'}} type="file" ref={ref => this.input = ref}/>
|
<input style={{display: 'none'}} type="file" ref={ref => this.input = ref}/>
|
||||||
<div className={styles.drawerHeader}>
|
<div className={styles.drawerHeader}>
|
||||||
<Breadcrumb>
|
<Breadcrumb>
|
||||||
|
@ -239,7 +231,7 @@ class FileManager extends React.Component {
|
||||||
scroll={{y: scrollY}}
|
scroll={{y: scrollY}}
|
||||||
style={{fontFamily: 'Source Code Pro, Courier New, Courier, Monaco, monospace, PingFang SC, Microsoft YaHei'}}
|
style={{fontFamily: 'Source Code Pro, Courier New, Courier, Monaco, monospace, PingFang SC, Microsoft YaHei'}}
|
||||||
dataSource={objects}/>
|
dataSource={objects}/>
|
||||||
</Drawer>
|
</React.Fragment>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
*/
|
*/
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { observer } from 'mobx-react';
|
import { observer } from 'mobx-react';
|
||||||
import { Tabs, Tree, Input, Spin, Dropdown, Menu, Button } from 'antd';
|
import { Tabs, Tree, Input, Spin, Dropdown, Menu, Button, Drawer } from 'antd';
|
||||||
import {
|
import {
|
||||||
FolderOutlined,
|
FolderOutlined,
|
||||||
FolderOpenOutlined,
|
FolderOpenOutlined,
|
||||||
|
@ -40,6 +40,7 @@ function WebSSH(props) {
|
||||||
const [activeId, setActiveId] = useState();
|
const [activeId, setActiveId] = useState();
|
||||||
const [hostId, setHostId] = useState();
|
const [hostId, setHostId] = useState();
|
||||||
const [width, setWidth] = useState(280);
|
const [width, setWidth] = useState(280);
|
||||||
|
const [sshMode] = useState(hasPermission('host.console.view'))
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
window.document.title = 'Spug web terminal'
|
window.document.title = 'Spug web terminal'
|
||||||
|
@ -212,7 +213,8 @@ function WebSSH(props) {
|
||||||
'/____// .___/ \\__,_/ \\__, / |__/|__/ \\___//_.___/ \\__/ \\___//_/ /_/ /_/ /_//_//_/ /_/ \\__,_//_/ \n' +
|
'/____// .___/ \\__,_/ \\__, / |__/|__/ \\___//_.___/ \\__/ \\___//_/ /_/ /_/ /_//_//_/ /_/ \\__,_//_/ \n' +
|
||||||
' /_/ /____/ \n'
|
' /_/ /____/ \n'
|
||||||
|
|
||||||
return hasPermission('host.console.view') ? (
|
console.log(sshMode)
|
||||||
|
return hasPermission('host.console.view|host.console.list') ? (
|
||||||
<div className={styles.container} onMouseUp={() => posX = 0} onMouseMove={handleMouseMove}>
|
<div className={styles.container} onMouseUp={() => posX = 0} onMouseMove={handleMouseMove}>
|
||||||
<div className={styles.sider} style={{width}}>
|
<div className={styles.sider} style={{width}}>
|
||||||
<div className={styles.logo}>
|
<div className={styles.logo}>
|
||||||
|
@ -245,7 +247,7 @@ function WebSSH(props) {
|
||||||
style={{background: '#fff', width: `calc(100vw - ${width}px)`}}
|
style={{background: '#fff', width: `calc(100vw - ${width}px)`}}
|
||||||
tabBarExtraContent={hosts.length === 0 ? (
|
tabBarExtraContent={hosts.length === 0 ? (
|
||||||
<div className={styles.tips}>小提示:双击标签快速复制窗口,右击标签展开更多操作。</div>
|
<div className={styles.tips}>小提示:双击标签快速复制窗口,右击标签展开更多操作。</div>
|
||||||
) : (
|
) : sshMode ? (
|
||||||
<AuthButton
|
<AuthButton
|
||||||
auth="host.console.list"
|
auth="host.console.list"
|
||||||
type="link"
|
type="link"
|
||||||
|
@ -253,18 +255,32 @@ function WebSSH(props) {
|
||||||
style={{marginRight: 5}}
|
style={{marginRight: 5}}
|
||||||
onClick={handleOpenFileManager}
|
onClick={handleOpenFileManager}
|
||||||
icon={<LeftOutlined/>}>文件管理器</AuthButton>
|
icon={<LeftOutlined/>}>文件管理器</AuthButton>
|
||||||
)}>
|
) : null}>
|
||||||
{hosts.map(item => (
|
{hosts.map(item => (
|
||||||
<Tabs.TabPane key={item.vId} tab={<TabRender host={item}/>}>
|
<Tabs.TabPane key={item.vId} tab={<TabRender host={item}/>}>
|
||||||
<Terminal id={item.id} vId={item.vId} activeId={activeId}/>
|
{sshMode ? (
|
||||||
|
<Terminal id={item.id} vId={item.vId} activeId={activeId}/>
|
||||||
|
) : (
|
||||||
|
<div className={styles.fileManger}>
|
||||||
|
<FileManager id={item.id}/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</Tabs.TabPane>
|
</Tabs.TabPane>
|
||||||
))}
|
))}
|
||||||
</Tabs>
|
</Tabs>
|
||||||
{hosts.length === 0 && (
|
{hosts.length === 0 && (
|
||||||
<pre className={styles.fig}>{spug_web_terminal}</pre>
|
<pre className={sshMode ? styles.fig : styles.fig2}>{spug_web_terminal}</pre>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<FileManager id={hostId} visible={visible} onClose={() => setVisible(false)}/>
|
<Drawer
|
||||||
|
title="文件管理器"
|
||||||
|
placement="right"
|
||||||
|
width={900}
|
||||||
|
className={styles.drawerContainer}
|
||||||
|
visible={visible}
|
||||||
|
onClose={() => setVisible(false)}>
|
||||||
|
<FileManager id={hostId}/>
|
||||||
|
</Drawer>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div style={{height: '100vh'}}>
|
<div style={{height: '100vh'}}>
|
||||||
|
|
|
@ -75,6 +75,16 @@
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fig2 {
|
||||||
|
flex: 1;
|
||||||
|
background-color: #fff;
|
||||||
|
color: #2b2b2b;
|
||||||
|
margin: 12px;
|
||||||
|
padding-top: 200px;
|
||||||
|
text-align: center;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
.tabRender {
|
.tabRender {
|
||||||
user-select: none;
|
user-select: none;
|
||||||
padding: 8px 8px 8px 16px;
|
padding: 8px 8px 8px 16px;
|
||||||
|
@ -82,6 +92,14 @@
|
||||||
color: #2563fc;
|
color: #2563fc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fileManger {
|
||||||
|
margin: 12px;
|
||||||
|
padding: 12px;
|
||||||
|
border-radius: 6px;
|
||||||
|
background: #fff;
|
||||||
|
height: calc(100vh - 66px);
|
||||||
|
}
|
||||||
|
|
||||||
:global(.ant-tabs-nav) {
|
:global(.ant-tabs-nav) {
|
||||||
height: 42px;
|
height: 42px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
@ -124,6 +142,12 @@
|
||||||
padding-right: 24px !important;
|
padding-right: 24px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.drawerContainer {
|
||||||
|
:global(.ant-drawer-body) {
|
||||||
|
padding: 10px 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.drawerHeader {
|
.drawerHeader {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|
|
@ -29,8 +29,8 @@ export default [{
|
||||||
key: 'console',
|
key: 'console',
|
||||||
label: 'Web终端',
|
label: 'Web终端',
|
||||||
perms: [
|
perms: [
|
||||||
{key: 'view', label: '使用Web终端'},
|
{key: 'view', label: 'Web终端'},
|
||||||
{key: 'list', label: '查看文件'},
|
{key: 'list', label: '文件管理'},
|
||||||
{key: 'upload', label: '上传文件'},
|
{key: 'upload', label: '上传文件'},
|
||||||
{key: 'del', label: '删除文件'},
|
{key: 'del', label: '删除文件'},
|
||||||
]
|
]
|
||||||
|
|
Loading…
Reference in New Issue