完善文件管理
This commit is contained in:
parent
9b9dcf9b56
commit
1444891d96
@ -111,7 +111,6 @@ func SetupRoutes() *echo.Echo {
|
|||||||
sessions.GET("/:id/download", SessionDownloadEndpoint)
|
sessions.GET("/:id/download", SessionDownloadEndpoint)
|
||||||
sessions.GET("/:id/ls", SessionLsEndpoint)
|
sessions.GET("/:id/ls", SessionLsEndpoint)
|
||||||
sessions.POST("/:id/mkdir", SessionMkDirEndpoint)
|
sessions.POST("/:id/mkdir", SessionMkDirEndpoint)
|
||||||
sessions.DELETE("/:id/rmdir", SessionRmDirEndpoint)
|
|
||||||
sessions.DELETE("/:id/rm", SessionRmEndpoint)
|
sessions.DELETE("/:id/rm", SessionRmEndpoint)
|
||||||
sessions.DELETE("/:id", SessionDeleteEndpoint)
|
sessions.DELETE("/:id", SessionDeleteEndpoint)
|
||||||
sessions.GET("/:id/recording", SessionRecordingEndpoint)
|
sessions.GET("/:id/recording", SessionRecordingEndpoint)
|
||||||
|
@ -476,63 +476,47 @@ func SessionMkDirEndpoint(c echo.Context) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func SessionRmDirEndpoint(c echo.Context) error {
|
|
||||||
sessionId := c.Param("id")
|
|
||||||
session, err := model.FindSessionById(sessionId)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
remoteDir := c.QueryParam("dir")
|
|
||||||
if "ssh" == session.Protocol {
|
|
||||||
tun, ok := global.Store.Get(sessionId)
|
|
||||||
if !ok {
|
|
||||||
return errors.New("获取sftp客户端失败")
|
|
||||||
}
|
|
||||||
fileInfos, err := tun.Subject.SftpClient.ReadDir(remoteDir)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := range fileInfos {
|
|
||||||
if err := tun.Subject.SftpClient.Remove(path.Join(remoteDir, fileInfos[i].Name())); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := tun.Subject.SftpClient.RemoveDirectory(remoteDir); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return Success(c, nil)
|
|
||||||
} else if "rdp" == session.Protocol {
|
|
||||||
drivePath, err := model.GetDrivePath()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := os.RemoveAll(path.Join(drivePath, remoteDir)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return Success(c, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func SessionRmEndpoint(c echo.Context) error {
|
func SessionRmEndpoint(c echo.Context) error {
|
||||||
sessionId := c.Param("id")
|
sessionId := c.Param("id")
|
||||||
session, err := model.FindSessionById(sessionId)
|
session, err := model.FindSessionById(sessionId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
remoteFile := c.QueryParam("file")
|
key := c.QueryParam("key")
|
||||||
if "ssh" == session.Protocol {
|
if "ssh" == session.Protocol {
|
||||||
tun, ok := global.Store.Get(sessionId)
|
tun, ok := global.Store.Get(sessionId)
|
||||||
if !ok {
|
if !ok {
|
||||||
return errors.New("获取sftp客户端失败")
|
return errors.New("获取sftp客户端失败")
|
||||||
}
|
}
|
||||||
if err := tun.Subject.SftpClient.Remove(remoteFile); err != nil {
|
|
||||||
|
sftpClient := tun.Subject.SftpClient
|
||||||
|
|
||||||
|
stat, err := sftpClient.Stat(key)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if stat.IsDir() {
|
||||||
|
fileInfos, err := tun.Subject.SftpClient.ReadDir(key)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range fileInfos {
|
||||||
|
if err := tun.Subject.SftpClient.Remove(path.Join(key, fileInfos[i].Name())); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := tun.Subject.SftpClient.RemoveDirectory(key); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := tun.Subject.SftpClient.Remove(key); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return Success(c, nil)
|
return Success(c, nil)
|
||||||
} else if "rdp" == session.Protocol {
|
} else if "rdp" == session.Protocol {
|
||||||
drivePath, err := model.GetDrivePath()
|
drivePath, err := model.GetDrivePath()
|
||||||
@ -540,11 +524,13 @@ func SessionRmEndpoint(c echo.Context) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := os.Remove(path.Join(drivePath, remoteFile)); err != nil {
|
if err := os.RemoveAll(path.Join(drivePath, key)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return Success(c, nil)
|
return Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,21 +1,15 @@
|
|||||||
import React, {Component} from 'react';
|
import React, {Component} from 'react';
|
||||||
import Guacamole from 'guacamole-common-js';
|
import Guacamole from 'guacamole-common-js';
|
||||||
import {Affix, Button, Col, Drawer, Dropdown, Form, Input, Menu, message, Modal, Row, Space, Tooltip} from 'antd'
|
import {Affix, Button, Col, Drawer, Dropdown, Form, Input, Menu, message, Modal, Row} from 'antd'
|
||||||
import qs from "qs";
|
import qs from "qs";
|
||||||
import request from "../../common/request";
|
import request from "../../common/request";
|
||||||
import {wsServer} from "../../common/constants";
|
import {wsServer} from "../../common/constants";
|
||||||
import {
|
import {
|
||||||
AppstoreTwoTone,
|
AppstoreTwoTone,
|
||||||
CloudDownloadOutlined,
|
|
||||||
CloudUploadOutlined,
|
|
||||||
CopyTwoTone,
|
CopyTwoTone,
|
||||||
DeleteOutlined,
|
|
||||||
DesktopOutlined,
|
DesktopOutlined,
|
||||||
ExclamationCircleOutlined,
|
ExclamationCircleOutlined,
|
||||||
ExpandOutlined,
|
ExpandOutlined
|
||||||
FolderAddOutlined,
|
|
||||||
LoadingOutlined,
|
|
||||||
ReloadOutlined
|
|
||||||
} from '@ant-design/icons';
|
} from '@ant-design/icons';
|
||||||
import {exitFull, getToken, isEmpty, requestFullScreen} from "../../utils/utils";
|
import {exitFull, getToken, isEmpty, requestFullScreen} from "../../utils/utils";
|
||||||
import './Access.css'
|
import './Access.css'
|
||||||
@ -48,9 +42,6 @@ class Access extends Component {
|
|||||||
uploadHeaders: {},
|
uploadHeaders: {},
|
||||||
keyboard: {},
|
keyboard: {},
|
||||||
protocol: '',
|
protocol: '',
|
||||||
treeData: [],
|
|
||||||
|
|
||||||
confirmVisible: false,
|
|
||||||
confirmLoading: false,
|
confirmLoading: false,
|
||||||
uploadVisible: false,
|
uploadVisible: false,
|
||||||
uploadLoading: false,
|
uploadLoading: false,
|
||||||
@ -315,7 +306,7 @@ class Access extends Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
onKeyDown = (keysym) => {
|
onKeyDown = (keysym) => {
|
||||||
if (true === this.state.clipboardVisible || true === this.state.confirmVisible) {
|
if (this.state.clipboardVisible || this.state.fileSystemVisible) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
this.state.client.sendKeyEvent(1, keysym);
|
this.state.client.sendKeyEvent(1, keysym);
|
||||||
@ -598,10 +589,10 @@ class Access extends Component {
|
|||||||
<Drawer
|
<Drawer
|
||||||
title={'会话详情'}
|
title={'会话详情'}
|
||||||
placement="right"
|
placement="right"
|
||||||
width={window.innerWidth * 0.5}
|
width={window.innerWidth * 0.8}
|
||||||
closable={true}
|
closable={true}
|
||||||
maskClosable={false}
|
// maskClosable={false}
|
||||||
onClose={()=>{
|
onClose={() => {
|
||||||
this.setState({
|
this.setState({
|
||||||
fileSystemVisible: false
|
fileSystemVisible: false
|
||||||
});
|
});
|
||||||
|
@ -5,14 +5,64 @@
|
|||||||
-ms-user-select: none;
|
-ms-user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.selectedRow {
|
@keyframes fadeIn {
|
||||||
background-color: #69c0ff;
|
0% {
|
||||||
|
transform: translateY(-25%);
|
||||||
|
}
|
||||||
|
50%{
|
||||||
|
transform: translateY(4%);
|
||||||
|
}
|
||||||
|
65%{
|
||||||
|
transform: translateY(-2%);
|
||||||
|
}
|
||||||
|
80%{
|
||||||
|
transform: translateY(2%);
|
||||||
|
}
|
||||||
|
95%{
|
||||||
|
transform: translateY(-1%);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translateY(0%);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.selectedRow > .ant-table-column-sort {
|
.popup {
|
||||||
background-color: #69c0ff;
|
animation-name: fadeIn;
|
||||||
|
animation-duration: 0.4s;
|
||||||
|
background-clip: padding-box;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.75);
|
||||||
|
left: 0;
|
||||||
|
list-style-type: none;
|
||||||
|
margin: 0;
|
||||||
|
outline: none;
|
||||||
|
padding: 0;
|
||||||
|
position: fixed;
|
||||||
|
text-align: left;
|
||||||
|
top: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
-webkit-box-shadow: 0 2px 8px rgba(0, 0, 0, 0.75);
|
||||||
}
|
}
|
||||||
|
|
||||||
.ant-table .ant-table-tbody > tr:hover:not(.ant-table-expanded-row .selectedRow) > td {
|
.popup li {
|
||||||
background: #bae7ff;
|
clear: both;
|
||||||
|
/*color: rgba(0, 0, 0, 0.65);*/
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: normal;
|
||||||
|
line-height: 22px;
|
||||||
|
margin: 0;
|
||||||
|
padding: 5px 12px;
|
||||||
|
transition: all .3s;
|
||||||
|
white-space: nowrap;
|
||||||
|
-webkit-transition: all .3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup li:hover {
|
||||||
|
background-color: #e6f7ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup li > i {
|
||||||
|
margin-right: 8px;
|
||||||
}
|
}
|
@ -1,21 +1,22 @@
|
|||||||
import React, {Component} from 'react';
|
import React, {Component} from 'react';
|
||||||
import {Button, Card, Form, Input, message, Modal, Row, Space, Table, Tooltip} from "antd";
|
import {Button, Card, Col, Form, Input, message, Modal, Row, Space, Table, Tooltip} from "antd";
|
||||||
import {
|
import {
|
||||||
CloudDownloadOutlined,
|
CloudDownloadOutlined,
|
||||||
CloudUploadOutlined,
|
CloudUploadOutlined,
|
||||||
DeleteOutlined,
|
DeleteOutlined,
|
||||||
FileExcelTwoTone,
|
ExclamationCircleOutlined,
|
||||||
FileImageTwoTone,
|
FileExcelOutlined,
|
||||||
FileMarkdownTwoTone,
|
FileImageOutlined,
|
||||||
FilePdfTwoTone,
|
FileMarkdownOutlined,
|
||||||
FileTextTwoTone,
|
FileOutlined,
|
||||||
FileTwoTone,
|
FilePdfOutlined,
|
||||||
FileWordTwoTone,
|
FileTextOutlined,
|
||||||
FileZipTwoTone,
|
FileWordOutlined,
|
||||||
|
FileZipOutlined,
|
||||||
FolderAddOutlined,
|
FolderAddOutlined,
|
||||||
FolderTwoTone,
|
FolderTwoTone,
|
||||||
LinkOutlined,
|
|
||||||
ReloadOutlined,
|
ReloadOutlined,
|
||||||
|
ThunderboltTwoTone,
|
||||||
UploadOutlined
|
UploadOutlined
|
||||||
} from "@ant-design/icons";
|
} from "@ant-design/icons";
|
||||||
import qs from "qs";
|
import qs from "qs";
|
||||||
@ -29,6 +30,7 @@ const formItemLayout = {
|
|||||||
labelCol: {span: 6},
|
labelCol: {span: 6},
|
||||||
wrapperCol: {span: 14},
|
wrapperCol: {span: 14},
|
||||||
};
|
};
|
||||||
|
const {confirm} = Modal;
|
||||||
|
|
||||||
class FileSystem extends Component {
|
class FileSystem extends Component {
|
||||||
|
|
||||||
@ -40,7 +42,10 @@ class FileSystem extends Component {
|
|||||||
files: [],
|
files: [],
|
||||||
loading: false,
|
loading: false,
|
||||||
selectedRowKeys: [],
|
selectedRowKeys: [],
|
||||||
selectedRow: {}
|
selectedRow: {},
|
||||||
|
dropdown: {
|
||||||
|
visible: false
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
@ -76,12 +81,6 @@ class FileSystem extends Component {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
mkdir = () => {
|
|
||||||
this.setState({
|
|
||||||
confirmVisible: true
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
upload = () => {
|
upload = () => {
|
||||||
this.setState({
|
this.setState({
|
||||||
uploadVisible: true
|
uploadVisible: true
|
||||||
@ -93,29 +92,40 @@ class FileSystem extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
rmdir = async () => {
|
rmdir = async () => {
|
||||||
if (!this.state.selectedRow.key) {
|
let selectedRowKeys = this.state.selectedRowKeys;
|
||||||
message.warning('请选择一个文件或目录');
|
if (selectedRowKeys === undefined || selectedRowKeys.length === 0) {
|
||||||
return;
|
message.warning('请至少选择一个文件或目录');
|
||||||
}
|
}
|
||||||
let result;
|
|
||||||
if (this.state.selectedRow.isLeaf) {
|
let title = '';
|
||||||
result = await request.delete(`/sessions/${this.state.sessionId}/rm?file=${this.state.selectedRow.key}`);
|
if (selectedRowKeys.length === 1) {
|
||||||
|
let file = selectedRowKeys[0].substring(selectedRowKeys[0].lastIndexOf('/') + 1, selectedRowKeys[0].length);
|
||||||
|
title = <p>您确认要删除"{file}"吗?</p>;
|
||||||
} else {
|
} else {
|
||||||
result = await request.delete(`/sessions/${this.state.sessionId}/rmdir?dir=${this.state.selectedRow.key}`);
|
title = `您确认要删除所选的${selectedRowKeys.length}项目吗?`;
|
||||||
}
|
}
|
||||||
if (result.code !== 1) {
|
confirm({
|
||||||
message.error(result.message);
|
title: title,
|
||||||
} else {
|
icon: <ExclamationCircleOutlined/>,
|
||||||
message.success('删除成功');
|
content: '所选项目将立即被删除。',
|
||||||
let path = this.state.selectedRow.key;
|
onOk: async () => {
|
||||||
let parentPath = path.substring(0, path.lastIndexOf('/'));
|
for (let i = 0; i < selectedRowKeys.length; i++) {
|
||||||
let items = await this.getTreeNodes(parentPath);
|
let rowKey = selectedRowKeys[i];
|
||||||
this.setState({
|
if (rowKey === '..') {
|
||||||
treeData: this.updateTreeData(this.state.treeData, parentPath, items),
|
continue;
|
||||||
selectedRow: {}
|
}
|
||||||
|
let result = await request.delete(`/sessions/${this.state.sessionId}/rm?key=${rowKey}`);
|
||||||
|
if (result['code'] !== 1) {
|
||||||
|
message.error(result['message']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await this.loadFiles(this.state.currentDirectory);
|
||||||
|
},
|
||||||
|
onCancel() {
|
||||||
|
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
refresh = async () => {
|
refresh = async () => {
|
||||||
this.loadFiles(this.state.currentDirectory);
|
this.loadFiles(this.state.currentDirectory);
|
||||||
@ -169,6 +179,34 @@ class FileSystem extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getNodeTreeRightClickMenu = () => {
|
||||||
|
const {pageX, pageY, visible} = {...this.state.dropdown};
|
||||||
|
if (visible) {
|
||||||
|
console.log(pageX, pageY)
|
||||||
|
const tmpStyle = {
|
||||||
|
left: `${pageX}px`,
|
||||||
|
top: `${pageY}px`,
|
||||||
|
};
|
||||||
|
|
||||||
|
let disableDownload = true;
|
||||||
|
if (this.state.selectedRowKeys.length === 1
|
||||||
|
&& !this.state.selectedRow['isDir']
|
||||||
|
&& !this.state.selectedRow['isLink']) {
|
||||||
|
disableDownload = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ul className="popup" style={tmpStyle}>
|
||||||
|
<li><Button type={'text'} size={'small'} icon={<CloudDownloadOutlined/>} onClick={this.download}
|
||||||
|
disabled={disableDownload}>下载</Button></li>
|
||||||
|
<li><Button type={'text'} size={'small'} icon={<DeleteOutlined/>} onClick={this.rmdir}>删除</Button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
@ -182,17 +220,17 @@ class FileSystem extends Component {
|
|||||||
icon = <FolderTwoTone/>;
|
icon = <FolderTwoTone/>;
|
||||||
} else {
|
} else {
|
||||||
if (item['isLink']) {
|
if (item['isLink']) {
|
||||||
icon = <LinkOutlined/>;
|
icon = <ThunderboltTwoTone/>;
|
||||||
} else {
|
} else {
|
||||||
const fileExtension = item['name'].split('.').pop().toLowerCase();
|
const fileExtension = item['name'].split('.').pop().toLowerCase();
|
||||||
switch (fileExtension) {
|
switch (fileExtension) {
|
||||||
case "doc":
|
case "doc":
|
||||||
case "docx":
|
case "docx":
|
||||||
icon = <FileWordTwoTone/>;
|
icon = <FileWordOutlined/>;
|
||||||
break;
|
break;
|
||||||
case "xls":
|
case "xls":
|
||||||
case "xlsx":
|
case "xlsx":
|
||||||
icon = <FileExcelTwoTone/>;
|
icon = <FileExcelOutlined/>;
|
||||||
break;
|
break;
|
||||||
case "bmp":
|
case "bmp":
|
||||||
case "jpg":
|
case "jpg":
|
||||||
@ -207,24 +245,25 @@ class FileSystem extends Component {
|
|||||||
case "psd":
|
case "psd":
|
||||||
case "ai":
|
case "ai":
|
||||||
case "webp":
|
case "webp":
|
||||||
icon = <FileImageTwoTone/>;
|
icon = <FileImageOutlined/>;
|
||||||
break;
|
break;
|
||||||
case "md":
|
case "md":
|
||||||
icon = <FileMarkdownTwoTone/>;
|
icon = <FileMarkdownOutlined/>;
|
||||||
break;
|
break;
|
||||||
case "pdf":
|
case "pdf":
|
||||||
icon = <FilePdfTwoTone/>;
|
icon = <FilePdfOutlined/>;
|
||||||
break;
|
break;
|
||||||
case "txt":
|
case "txt":
|
||||||
icon = <FileTextTwoTone/>;
|
icon = <FileTextOutlined/>;
|
||||||
break;
|
break;
|
||||||
case "zip":
|
case "zip":
|
||||||
case "gz":
|
case "gz":
|
||||||
case "tar":
|
case "tar":
|
||||||
icon = <FileZipTwoTone/>;
|
case "tgz":
|
||||||
|
icon = <FileZipOutlined/>;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
icon = <FileTwoTone/>;
|
icon = <FileOutlined/>;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -293,30 +332,28 @@ class FileSystem extends Component {
|
|||||||
];
|
];
|
||||||
|
|
||||||
const title = (
|
const title = (
|
||||||
<Row>
|
<Row justify="space-around" align="middle" gutter={24}>
|
||||||
|
<Col span={16} key={1}>
|
||||||
|
{this.state.currentDirectory}
|
||||||
|
</Col>
|
||||||
|
<Col span={8} key={2} style={{textAlign: 'right'}}>
|
||||||
<Space>
|
<Space>
|
||||||
远程文件管理
|
|
||||||
|
|
||||||
|
|
||||||
<Tooltip title="创建文件夹">
|
<Tooltip title="创建文件夹">
|
||||||
<Button type="primary" size="small" icon={<FolderAddOutlined/>}
|
<Button type="primary" size="small" icon={<FolderAddOutlined/>}
|
||||||
onClick={this.mkdir} ghost/>
|
onClick={() => {
|
||||||
|
this.setState({
|
||||||
|
mkdirVisible: true
|
||||||
|
})
|
||||||
|
}} ghost/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
||||||
<Tooltip title="上传">
|
<Tooltip title="上传">
|
||||||
<Button type="primary" size="small" icon={<CloudUploadOutlined/>}
|
<Button type="primary" size="small" icon={<CloudUploadOutlined/>}
|
||||||
onClick={this.upload} ghost/>
|
onClick={() => {
|
||||||
</Tooltip>
|
this.setState({
|
||||||
|
uploadVisible: true
|
||||||
<Tooltip title="下载">
|
})
|
||||||
<Button type="primary" size="small" icon={<CloudDownloadOutlined/>}
|
}} ghost/>
|
||||||
disabled={isEmpty(this.state.selectedRow['key']) || this.state.selectedRow['isDir'] || this.state.selectedRow['isLink']}
|
|
||||||
onClick={this.download} ghost/>
|
|
||||||
</Tooltip>
|
|
||||||
|
|
||||||
<Tooltip title="删除文件">
|
|
||||||
<Button type="dashed" size="small" icon={<DeleteOutlined/>} disabled={isEmpty(this.state.selectedRow['key'])} onClick={this.rmdir}
|
|
||||||
danger/>
|
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
||||||
<Tooltip title="刷新">
|
<Tooltip title="刷新">
|
||||||
@ -324,22 +361,41 @@ class FileSystem extends Component {
|
|||||||
ghost/>
|
ghost/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Space>
|
</Space>
|
||||||
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const {loading, selectedRowKeys} = this.state;
|
||||||
|
const rowSelection = {
|
||||||
|
selectedRowKeys,
|
||||||
|
onChange: (selectedRowKeys) => {
|
||||||
|
selectedRowKeys = selectedRowKeys.filter(rowKey => rowKey !== '..');
|
||||||
|
this.setState({selectedRowKeys});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const hasSelected = selectedRowKeys.length > 0;
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Card title={title} bordered={true} size="small">
|
<Card title={title} bordered={true} size="small">
|
||||||
|
|
||||||
<Table columns={columns}
|
<Table columns={columns}
|
||||||
|
rowSelection={rowSelection}
|
||||||
dataSource={this.state.files}
|
dataSource={this.state.files}
|
||||||
size={'small'}
|
size={'small'}
|
||||||
pagination={false}
|
pagination={false}
|
||||||
loading={this.state.loading}
|
loading={this.state.loading}
|
||||||
|
|
||||||
onRow={record => {
|
onRow={record => {
|
||||||
return {
|
return {
|
||||||
onClick: event => {
|
onClick: event => {
|
||||||
|
if (record['key'] === '..') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.setState({
|
this.setState({
|
||||||
selectedRow: record
|
selectedRow: record,
|
||||||
|
selectedRowKeys: [record['key']]
|
||||||
});
|
});
|
||||||
}, // 点击行
|
}, // 点击行
|
||||||
onDoubleClick: event => {
|
onDoubleClick: event => {
|
||||||
@ -358,12 +414,44 @@ class FileSystem extends Component {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
onContextMenu: event => {
|
onContextMenu: event => {
|
||||||
|
event.preventDefault();
|
||||||
|
if (record['key'] === '..') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let selectedRowKeys = this.state.selectedRowKeys;
|
||||||
|
if (selectedRowKeys.length === 0) {
|
||||||
|
selectedRowKeys = [record['key']]
|
||||||
|
}
|
||||||
|
this.setState({
|
||||||
|
selectedRow: record,
|
||||||
|
selectedRowKeys: selectedRowKeys,
|
||||||
|
dropdown: {
|
||||||
|
visible: true,
|
||||||
|
pageX: event.pageX,
|
||||||
|
pageY: event.pageY,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!this.state.dropdown.visible) {
|
||||||
|
const that = this;
|
||||||
|
document.addEventListener(`click`, function onClickOutside() {
|
||||||
|
that.setState({dropdown: {visible: false}});
|
||||||
|
document.removeEventListener(`click`, onClickOutside);
|
||||||
|
|
||||||
|
document.querySelector('.ant-drawer-body').style.height = 'unset';
|
||||||
|
document.querySelector('.ant-drawer-body').style['overflow-y'] = 'auto';
|
||||||
|
});
|
||||||
|
|
||||||
|
document.querySelector('.ant-drawer-body').style.height = '100vh';
|
||||||
|
document.querySelector('.ant-drawer-body').style['overflow-y'] = 'hidden';
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onMouseEnter: event => {
|
onMouseEnter: event => {
|
||||||
|
|
||||||
}, // 鼠标移入行
|
}, // 鼠标移入行
|
||||||
onMouseLeave: event => {
|
onMouseLeave: event => {
|
||||||
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}}
|
}}
|
||||||
@ -378,17 +466,19 @@ class FileSystem extends Component {
|
|||||||
title="上传文件"
|
title="上传文件"
|
||||||
visible={this.state.uploadVisible}
|
visible={this.state.uploadVisible}
|
||||||
onOk={() => {
|
onOk={() => {
|
||||||
|
this.setState({
|
||||||
|
uploadVisible: false
|
||||||
|
})
|
||||||
}}
|
}}
|
||||||
confirmLoading={this.state.uploadLoading}
|
confirmLoading={this.state.uploadLoading}
|
||||||
onCancel={()=>{
|
onCancel={() => {
|
||||||
this.setState({
|
this.setState({
|
||||||
uploadVisible: false
|
uploadVisible: false
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Upload
|
<Upload
|
||||||
action={server + '/sessions/' + this.state.sessionId + '/upload?X-Auth-Token=' + getToken() + '&dir=' + this.state.selectedRow.key}>
|
action={server + '/sessions/' + this.state.sessionId + '/upload?X-Auth-Token=' + getToken() + '&dir=' + this.state.currentDirectory}>
|
||||||
<Button icon={<UploadOutlined/>}>上传文件</Button>
|
<Button icon={<UploadOutlined/>}>上传文件</Button>
|
||||||
</Upload>
|
</Upload>
|
||||||
</Modal>
|
</Modal>
|
||||||
@ -396,12 +486,12 @@ class FileSystem extends Component {
|
|||||||
|
|
||||||
<Modal
|
<Modal
|
||||||
title="创建文件夹"
|
title="创建文件夹"
|
||||||
visible={this.state.confirmVisible}
|
visible={this.state.mkdirVisible}
|
||||||
onOk={() => {
|
onOk={() => {
|
||||||
this.formRef.current
|
this.mkdirFormRef.current
|
||||||
.validateFields()
|
.validateFields()
|
||||||
.then(values => {
|
.then(values => {
|
||||||
this.formRef.current.resetFields();
|
this.mkdirFormRef.current.resetFields();
|
||||||
this.handleOk(values);
|
this.handleOk(values);
|
||||||
})
|
})
|
||||||
.catch(info => {
|
.catch(info => {
|
||||||
@ -409,21 +499,21 @@ class FileSystem extends Component {
|
|||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
confirmLoading={this.state.confirmLoading}
|
confirmLoading={this.state.confirmLoading}
|
||||||
onCancel={()=>{
|
onCancel={() => {
|
||||||
this.setState({
|
this.setState({
|
||||||
confirmVisible: false
|
mkdirVisible: false
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Form ref={this.formRef} {...formItemLayout}>
|
<Form ref={this.mkdirFormRef}>
|
||||||
|
|
||||||
<Form.Item label="文件夹名称" name='dir' rules={[{required: true, message: '请输入文件夹名称'}]}>
|
<Form.Item name='dir' rules={[{required: true, message: '请输入文件夹名称'}]}>
|
||||||
<Input autoComplete="off" placeholder="请输入文件夹名称"/>
|
<Input autoComplete="off" placeholder="请输入文件夹名称"/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Form>
|
</Form>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
||||||
|
{this.getNodeTreeRightClickMenu()}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -437,14 +437,6 @@ class Asset extends Component {
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}, {
|
|
||||||
title: '网络',
|
|
||||||
dataIndex: 'ip',
|
|
||||||
key: 'ip',
|
|
||||||
render: (text, record) => {
|
|
||||||
|
|
||||||
return record['ip'] + ':' + record['port'];
|
|
||||||
}
|
|
||||||
}, {
|
}, {
|
||||||
title: '连接协议',
|
title: '连接协议',
|
||||||
dataIndex: 'protocol',
|
dataIndex: 'protocol',
|
||||||
|
@ -220,5 +220,5 @@ export function renderSize(value) {
|
|||||||
let index = Math.floor(Math.log(srcSize) / Math.log(1024));
|
let index = Math.floor(Math.log(srcSize) / Math.log(1024));
|
||||||
let size = srcSize / Math.pow(1024, index);
|
let size = srcSize / Math.pow(1024, index);
|
||||||
size = size.toFixed(2);
|
size = size.toFixed(2);
|
||||||
return size + unitArr[index];
|
return size + ' ' + unitArr[index];
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user