完善部分文件操作功能

This commit is contained in:
dushixiang 2021-02-03 00:50:44 +08:00 committed by dushixiang
parent 32b31eba1a
commit 9b9dcf9b56
4 changed files with 139 additions and 164 deletions

View File

@ -1,19 +1,19 @@
// prod // prod
let wsPrefix; // let wsPrefix;
if (window.location.protocol === 'https:') { // if (window.location.protocol === 'https:') {
wsPrefix = 'wss:' // wsPrefix = 'wss:'
} else { // } else {
wsPrefix = 'ws:' // wsPrefix = 'ws:'
} // }
//
export const server = ''; // export const server = '';
export const wsServer = wsPrefix + window.location.host; // export const wsServer = wsPrefix + window.location.host;
export const prefix = window.location.protocol + '//' + window.location.host; // export const prefix = window.location.protocol + '//' + window.location.host;
// dev // dev
// export const server = '//127.0.0.1:8088'; export const server = '//127.0.0.1:8088';
// export const wsServer = 'ws://127.0.0.1:8088'; export const wsServer = 'ws://127.0.0.1:8088';
// export const prefix = ''; export const prefix = '';
export const PROTOCOL_COLORS = { export const PROTOCOL_COLORS = {
'rdp': 'red', 'rdp': 'red',

View File

@ -33,7 +33,6 @@ const STATE_DISCONNECTED = 5;
class Access extends Component { class Access extends Component {
formRef = React.createRef();
clipboardFormRef = React.createRef(); clipboardFormRef = React.createRef();
state = { state = {

View File

@ -0,0 +1,18 @@
.dode {
-webkit-user-select: none;
-moz-user-select: none;
-o-user-select: none;
-ms-user-select: none;
}
.selectedRow {
background-color: #69c0ff;
}
.selectedRow > .ant-table-column-sort {
background-color: #69c0ff;
}
.ant-table .ant-table-tbody > tr:hover:not(.ant-table-expanded-row .selectedRow) > td {
background: #bae7ff;
}

View File

@ -1,5 +1,5 @@
import React, {Component} from 'react'; import React, {Component} from 'react';
import {Button, Card, Form, Input, message, Modal, Row, Space, Table, Tooltip, Tree} from "antd"; import {Button, Card, Form, Input, message, Modal, Row, Space, Table, Tooltip} from "antd";
import { import {
CloudDownloadOutlined, CloudDownloadOutlined,
CloudUploadOutlined, CloudUploadOutlined,
@ -15,7 +15,6 @@ import {
FolderAddOutlined, FolderAddOutlined,
FolderTwoTone, FolderTwoTone,
LinkOutlined, LinkOutlined,
LoadingOutlined,
ReloadOutlined, ReloadOutlined,
UploadOutlined UploadOutlined
} from "@ant-design/icons"; } from "@ant-design/icons";
@ -23,26 +22,25 @@ import qs from "qs";
import request from "../../common/request"; import request from "../../common/request";
import {server} from "../../common/constants"; import {server} from "../../common/constants";
import Upload from "antd/es/upload"; import Upload from "antd/es/upload";
import {download, getToken, renderSize} from "../../utils/utils"; import {download, getToken, isEmpty, renderSize} from "../../utils/utils";
import './FileSystem.css'
const antIcon = <LoadingOutlined/>;
const formItemLayout = { const formItemLayout = {
labelCol: {span: 6}, labelCol: {span: 6},
wrapperCol: {span: 14}, wrapperCol: {span: 14},
}; };
const {DirectoryTree} = Tree;
class FileSystem extends Component { class FileSystem extends Component {
mkdirFormRef = React.createRef();
state = { state = {
sessionId: undefined, sessionId: undefined,
currentDirectory: '/', currentDirectory: '/',
files: [], files: [],
loading: false, loading: false,
selectNode: {}, selectedRowKeys: [],
selectedRowKeys: [] selectedRow: {}
} }
componentDidMount() { componentDidMount() {
@ -50,22 +48,14 @@ class FileSystem extends Component {
this.setState({ this.setState({
sessionId: sessionId sessionId: sessionId
}, () => { }, () => {
this.loadFiles('/'); this.loadFiles(this.state.currentDirectory);
}); });
} }
onSelect = (keys, event) => {
this.setState({
selectNode: {
key: keys[0],
isLeaf: event.node.isLeaf
}
})
};
handleOk = async (values) => { handleOk = async (values) => {
let params = { let params = {
'dir': this.state.selectNode.key + '/' + values['dir'] 'dir': this.state.selectedRow.key + '/' + values['dir']
} }
let paramStr = qs.stringify(params); let paramStr = qs.stringify(params);
@ -75,12 +65,7 @@ class FileSystem extends Component {
let result = await request.post(`/sessions/${this.state.sessionId}/mkdir?${paramStr}`); let result = await request.post(`/sessions/${this.state.sessionId}/mkdir?${paramStr}`);
if (result.code === 1) { if (result.code === 1) {
message.success('创建成功'); message.success('创建成功');
let parentPath = this.state.selectNode.key; this.loadFiles(this.state.currentDirectory);
let items = await this.getTreeNodes(parentPath);
this.setState({
treeData: this.updateTreeData(this.state.treeData, parentPath, items),
selectNode: {}
});
} else { } else {
message.error(result.message); message.error(result.message);
} }
@ -91,82 +76,49 @@ class FileSystem extends Component {
}) })
} }
handleConfirmCancel = () => {
this.setState({
confirmVisible: false
})
}
handleUploadCancel = () => {
this.setState({
uploadVisible: false
})
}
mkdir = () => { mkdir = () => {
if (!this.state.selectNode.key || this.state.selectNode.isLeaf) {
message.warning('请选择一个目录');
return;
}
this.setState({ this.setState({
confirmVisible: true confirmVisible: true
}) })
} }
upload = () => { upload = () => {
if (!this.state.selectNode.key || this.state.selectNode.isLeaf) {
message.warning('请选择一个目录进行上传');
return;
}
this.setState({ this.setState({
uploadVisible: true uploadVisible: true
}) })
} }
download = () => { download = () => {
if (!this.state.selectNode.key || !this.state.selectNode.isLeaf) { download(`${server}/sessions/${this.state.sessionId}/download?file=${this.state.selectedRow.key}`);
message.warning('当前只支持下载文件');
return;
}
download(`${server}/sessions/${this.state.sessionId}/download?file=${this.state.selectNode.key}`);
} }
rmdir = async () => { rmdir = async () => {
if (!this.state.selectNode.key) { if (!this.state.selectedRow.key) {
message.warning('请选择一个文件或目录'); message.warning('请选择一个文件或目录');
return; return;
} }
let result; let result;
if (this.state.selectNode.isLeaf) { if (this.state.selectedRow.isLeaf) {
result = await request.delete(`/sessions/${this.state.sessionId}/rm?file=${this.state.selectNode.key}`); result = await request.delete(`/sessions/${this.state.sessionId}/rm?file=${this.state.selectedRow.key}`);
} else { } else {
result = await request.delete(`/sessions/${this.state.sessionId}/rmdir?dir=${this.state.selectNode.key}`); result = await request.delete(`/sessions/${this.state.sessionId}/rmdir?dir=${this.state.selectedRow.key}`);
} }
if (result.code !== 1) { if (result.code !== 1) {
message.error(result.message); message.error(result.message);
} else { } else {
message.success('删除成功'); message.success('删除成功');
let path = this.state.selectNode.key; let path = this.state.selectedRow.key;
let parentPath = path.substring(0, path.lastIndexOf('/')); let parentPath = path.substring(0, path.lastIndexOf('/'));
let items = await this.getTreeNodes(parentPath); let items = await this.getTreeNodes(parentPath);
this.setState({ this.setState({
treeData: this.updateTreeData(this.state.treeData, parentPath, items), treeData: this.updateTreeData(this.state.treeData, parentPath, items),
selectNode: {} selectedRow: {}
}); });
} }
} }
refresh = async () => { refresh = async () => {
if (!this.state.selectNode.key || this.state.selectNode.isLeaf) { this.loadFiles(this.state.currentDirectory);
await this.loadDirData('/');
} else {
let key = this.state.selectNode.key;
let items = await this.getTreeNodes(key);
this.setState({
treeData: this.updateTreeData(this.state.treeData, key, items),
});
}
message.success('刷新目录成功');
} }
loadFiles = async (key) => { loadFiles = async (key) => {
@ -174,6 +126,9 @@ class FileSystem extends Component {
loading: true loading: true
}) })
try { try {
if (isEmpty(key)) {
key = '/';
}
let result = await request.get(`${server}/sessions/${this.state.sessionId}/ls?dir=${key}`); let result = await request.get(`${server}/sessions/${this.state.sessionId}/ls?dir=${key}`);
if (result['code'] !== 1) { if (result['code'] !== 1) {
message.error(result['message']); message.error(result['message']);
@ -184,10 +139,16 @@ class FileSystem extends Component {
const items = data.map(item => { const items = data.map(item => {
return {'key': item['path'], ...item} return {'key': item['path'], ...item}
}) });
if (key !== '/') {
items.splice(0, 0, {key: '..', name: '..', path: '..', isDir: true})
}
this.setState({ this.setState({
files: items files: items,
currentDirectory: key,
selectedRow: {}
}) })
} finally { } finally {
this.setState({ this.setState({
@ -197,64 +158,6 @@ class FileSystem extends Component {
} }
loadDirData = async (key) => {
let items = await this.getTreeNodes(key);
this.setState({
treeData: items,
});
}
getTreeNodes = async (key) => {
const url = server + '/sessions/' + this.state.sessionId + '/ls?dir=' + key;
let result = await request.get(url);
if (result.code !== 1) {
message.error(result['message']);
return [];
}
let data = result.data;
return data.map(item => {
return {
title: item['name'],
key: item['path'],
isLeaf: !item['isDir'] && !item['isLink'],
}
});
}
onLoadData = ({key, children}) => {
return new Promise(async (resolve) => {
if (children) {
resolve();
return;
}
let items = await this.getTreeNodes(key);
this.setState({
treeData: this.updateTreeData(this.state.treeData, key, items),
});
resolve();
});
}
updateTreeData = (list, key, children) => {
return list.map((node) => {
if (node.key === key) {
return {...node, children};
} else if (node.children) {
return {...node, children: this.updateTreeData(node.children, key, children)};
}
return node;
});
}
uploadChange = (info) => { uploadChange = (info) => {
if (info.file.status !== 'uploading') { if (info.file.status !== 'uploading') {
@ -327,9 +230,18 @@ class FileSystem extends Component {
} }
} }
return <>{icon}&nbsp;&nbsp;{item['name']}</>; return <span className={'dode'}>{icon}&nbsp;&nbsp;{item['name']}</span>;
},
sorter: (a, b) => {
if (a['key'] === '..') {
return 0;
}
if (b['key'] === '..') {
return 0;
}
return a.name.localeCompare(b.name);
}, },
sorter: (a, b) => a.name - b.name,
sortDirections: ['descend', 'ascend'], sortDirections: ['descend', 'ascend'],
}, },
{ {
@ -338,30 +250,48 @@ class FileSystem extends Component {
key: 'size', key: 'size',
render: (value, item) => { render: (value, item) => {
if (!item['isDir'] && !item['isLink']) { if (!item['isDir'] && !item['isLink']) {
return renderSize(value) return <span className={'dode'}>{renderSize(value)}</span>;
} }
return '-'; return <span className={'dode'}/>;
}, },
sorter: (a, b) => a.size - b.size, sorter: (a, b) => {
}, if (a['key'] === '..') {
{ return 0;
}
if (b['key'] === '..') {
return 0;
}
return a.size - b.size;
},
}, {
title: '修改日期', title: '修改日期',
dataIndex: 'modTime', dataIndex: 'modTime',
key: 'modTime', key: 'modTime',
sorter: (a, b) => a.modTime - b.modTime, sorter: (a, b) => {
if (a['key'] === '..') {
return 0;
}
if (b['key'] === '..') {
return 0;
}
return a.modTime.localeCompare(b.modTime);
},
sortDirections: ['descend', 'ascend'], sortDirections: ['descend', 'ascend'],
render: (value, item) => {
return <span className={'dode'}>{value}</span>;
},
}, {
title: '属性',
dataIndex: 'mode',
key: 'mode',
render: (value, item) => {
return <span className={'dode'}>{value}</span>;
},
} }
]; ];
const {loading, selectedRowKeys} = this.state;
const rowSelection = {
selectedRowKeys,
onChange: () => {
},
};
const hasSelected = selectedRowKeys.length > 0;
const title = ( const title = (
<Row> <Row>
<Space> <Space>
@ -380,11 +310,12 @@ class FileSystem extends Component {
<Tooltip title="下载"> <Tooltip title="下载">
<Button type="primary" size="small" icon={<CloudDownloadOutlined/>} <Button type="primary" size="small" icon={<CloudDownloadOutlined/>}
disabled={isEmpty(this.state.selectedRow['key']) || this.state.selectedRow['isDir'] || this.state.selectedRow['isLink']}
onClick={this.download} ghost/> onClick={this.download} ghost/>
</Tooltip> </Tooltip>
<Tooltip title="删除文件"> <Tooltip title="删除文件">
<Button type="dashed" size="small" icon={<DeleteOutlined/>} onClick={this.rmdir} <Button type="dashed" size="small" icon={<DeleteOutlined/>} disabled={isEmpty(this.state.selectedRow['key'])} onClick={this.rmdir}
danger/> danger/>
</Tooltip> </Tooltip>
@ -400,7 +331,6 @@ class FileSystem extends Component {
<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}
@ -408,19 +338,39 @@ class FileSystem extends Component {
onRow={record => { onRow={record => {
return { return {
onClick: event => { onClick: event => {
this.setState({
selectedRow: record
});
}, // 点击行 }, // 点击行
onDoubleClick: event => { onDoubleClick: event => {
this.loadFiles(record['path']); if (record['isDir'] || record['isLink']) {
if (record['path'] === '..') {
// 获取当前目录的上级目录
let currentDirectory = this.state.currentDirectory;
console.log(currentDirectory)
let parentDirectory = currentDirectory.substring(0, currentDirectory.lastIndexOf('/'));
this.loadFiles(parentDirectory);
} else {
this.loadFiles(record['path']);
}
} else {
}
}, },
onContextMenu: event => { onContextMenu: event => {
}, },
onMouseEnter: event => { onMouseEnter: event => {
}, // 鼠标移入行 }, // 鼠标移入行
onMouseLeave: event => { onMouseLeave: event => {
}, },
}; };
}} }}
rowClassName={(record) => {
return record['key'] === this.state.selectedRow['key'] ? 'selectedRow' : '';
}}
/> />
</Card> </Card>
@ -431,10 +381,14 @@ class FileSystem extends Component {
}} }}
confirmLoading={this.state.uploadLoading} confirmLoading={this.state.uploadLoading}
onCancel={this.handleUploadCancel} onCancel={()=>{
this.setState({
uploadVisible: false
})
}}
> >
<Upload <Upload
action={server + '/sessions/' + this.state.sessionId + '/upload?X-Auth-Token=' + getToken() + '&dir=' + this.state.selectNode.key}> action={server + '/sessions/' + this.state.sessionId + '/upload?X-Auth-Token=' + getToken() + '&dir=' + this.state.selectedRow.key}>
<Button icon={<UploadOutlined/>}>上传文件</Button> <Button icon={<UploadOutlined/>}>上传文件</Button>
</Upload> </Upload>
</Modal> </Modal>
@ -455,7 +409,11 @@ class FileSystem extends Component {
}); });
}} }}
confirmLoading={this.state.confirmLoading} confirmLoading={this.state.confirmLoading}
onCancel={this.handleConfirmCancel} onCancel={()=>{
this.setState({
confirmVisible: false
})
}}
> >
<Form ref={this.formRef} {...formItemLayout}> <Form ref={this.formRef} {...formItemLayout}>