A 新增web终端独立文件管理器模式

pull/480/head
vapao 2022-04-15 23:57:25 +08:00
parent efc6bf5f2b
commit c42b795f33
5 changed files with 61 additions and 28 deletions

View File

@ -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>
); );
}) })

View File

@ -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>
) )
} }
} }

View File

@ -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'}}>

View File

@ -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;

View File

@ -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: '删除文件'},
] ]