继续完善文件管理
This commit is contained in:
parent
1444891d96
commit
248815538d
@ -107,14 +107,14 @@ func SetupRoutes() *echo.Echo {
|
||||
sessions.POST("/:id/connect", SessionConnectEndpoint)
|
||||
sessions.POST("/:id/disconnect", Admin(SessionDisconnectEndpoint))
|
||||
sessions.POST("/:id/resize", SessionResizeEndpoint)
|
||||
sessions.POST("/:id/upload", SessionUploadEndpoint)
|
||||
sessions.GET("/:id/download", SessionDownloadEndpoint)
|
||||
sessions.GET("/:id/ls", SessionLsEndpoint)
|
||||
sessions.GET("/:id/download", SessionDownloadEndpoint)
|
||||
sessions.POST("/:id/upload", SessionUploadEndpoint)
|
||||
sessions.POST("/:id/mkdir", SessionMkDirEndpoint)
|
||||
sessions.DELETE("/:id/rm", SessionRmEndpoint)
|
||||
sessions.POST("/:id/rm", SessionRmEndpoint)
|
||||
sessions.POST("/:id/rename", SessionRenameEndpoint)
|
||||
sessions.DELETE("/:id", SessionDeleteEndpoint)
|
||||
sessions.GET("/:id/recording", SessionRecordingEndpoint)
|
||||
sessions.GET("/:id/status", SessionGetStatusEndpoint)
|
||||
}
|
||||
|
||||
resourceSharers := e.Group("/resource-sharers")
|
||||
|
@ -442,7 +442,7 @@ func SessionLsEndpoint(c echo.Context) error {
|
||||
return Success(c, files)
|
||||
}
|
||||
|
||||
return err
|
||||
return errors.New("当前协议不支持此操作")
|
||||
}
|
||||
|
||||
func SessionMkDirEndpoint(c echo.Context) error {
|
||||
@ -473,7 +473,7 @@ func SessionMkDirEndpoint(c echo.Context) error {
|
||||
return Success(c, nil)
|
||||
}
|
||||
|
||||
return nil
|
||||
return errors.New("当前协议不支持此操作")
|
||||
}
|
||||
|
||||
func SessionRmEndpoint(c echo.Context) error {
|
||||
@ -497,22 +497,22 @@ func SessionRmEndpoint(c echo.Context) error {
|
||||
}
|
||||
|
||||
if stat.IsDir() {
|
||||
fileInfos, err := tun.Subject.SftpClient.ReadDir(key)
|
||||
fileInfos, err := 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 {
|
||||
if err := sftpClient.Remove(path.Join(key, fileInfos[i].Name())); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := tun.Subject.SftpClient.RemoveDirectory(key); err != nil {
|
||||
if err := sftpClient.RemoveDirectory(key); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := tun.Subject.SftpClient.Remove(key); err != nil {
|
||||
if err := sftpClient.Remove(key); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -531,7 +531,43 @@ func SessionRmEndpoint(c echo.Context) error {
|
||||
return Success(c, nil)
|
||||
}
|
||||
|
||||
return nil
|
||||
return errors.New("当前协议不支持此操作")
|
||||
}
|
||||
|
||||
func SessionRenameEndpoint(c echo.Context) error {
|
||||
sessionId := c.Param("id")
|
||||
session, err := model.FindSessionById(sessionId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
oldName := c.QueryParam("oldName")
|
||||
newName := c.QueryParam("newName")
|
||||
if "ssh" == session.Protocol {
|
||||
tun, ok := global.Store.Get(sessionId)
|
||||
if !ok {
|
||||
return errors.New("获取sftp客户端失败")
|
||||
}
|
||||
|
||||
sftpClient := tun.Subject.SftpClient
|
||||
|
||||
if err := sftpClient.Rename(oldName, newName); 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.Rename(path.Join(drivePath, oldName), path.Join(drivePath, newName)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return Success(c, nil)
|
||||
}
|
||||
return errors.New("当前协议不支持此操作")
|
||||
}
|
||||
|
||||
func SessionRecordingEndpoint(c echo.Context) error {
|
||||
@ -551,14 +587,3 @@ func SessionRecordingEndpoint(c echo.Context) error {
|
||||
logrus.Debugf("读取录屏文件:%v,是否存在: %v, 是否为文件: %v", recording, utils.FileExists(recording), utils.IsFile(recording))
|
||||
return c.File(recording)
|
||||
}
|
||||
|
||||
func SessionGetStatusEndpoint(c echo.Context) error {
|
||||
sessionId := c.Param("id")
|
||||
session, err := model.FindSessionById(sessionId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return Success(c, H{
|
||||
"status": session.Status,
|
||||
})
|
||||
}
|
||||
|
@ -106,11 +106,11 @@ class Access extends Component {
|
||||
})
|
||||
if (this.state.protocol === 'ssh') {
|
||||
if (data.data && data.data.length > 0) {
|
||||
message.info('您输入的内容已复制到远程服务器上,使用右键将自动粘贴。');
|
||||
// message.info('您输入的内容已复制到远程服务器上,使用右键将自动粘贴。');
|
||||
}
|
||||
} else {
|
||||
if (data.data && data.data.length > 0) {
|
||||
message.info('您输入的内容已复制到远程服务器上');
|
||||
// message.info('您输入的内容已复制到远程服务器上');
|
||||
}
|
||||
}
|
||||
|
||||
@ -282,9 +282,13 @@ class Access extends Component {
|
||||
// Set clipboard contents once stream is finished
|
||||
reader.onend = async () => {
|
||||
|
||||
message.info('您选择的内容已复制到您的粘贴板中,在右侧的输入框中可同时查看到。');
|
||||
// message.info('您选择的内容已复制到您的粘贴板中,在右侧的输入框中可同时查看到。');
|
||||
this.setState({
|
||||
clipboardText: data
|
||||
}, () => {
|
||||
// 选中粘贴板文本框中的内容
|
||||
|
||||
// 调用API粘贴进
|
||||
});
|
||||
|
||||
if (navigator.clipboard) {
|
||||
@ -306,9 +310,9 @@ class Access extends Component {
|
||||
};
|
||||
|
||||
onKeyDown = (keysym) => {
|
||||
if (this.state.clipboardVisible || this.state.fileSystemVisible) {
|
||||
return true;
|
||||
}
|
||||
// if (this.state.clipboardVisible || this.state.fileSystemVisible) {
|
||||
// return true;
|
||||
// }
|
||||
this.state.client.sendKeyEvent(1, keysym);
|
||||
if (keysym === 65288) {
|
||||
return false;
|
||||
@ -416,8 +420,11 @@ class Access extends Component {
|
||||
}
|
||||
};
|
||||
|
||||
const sink = new Guacamole.InputSink();
|
||||
display.appendChild(sink.getElement());
|
||||
|
||||
// Keyboard
|
||||
const keyboard = new Guacamole.Keyboard(document);
|
||||
const keyboard = new Guacamole.Keyboard(sink.getElement());
|
||||
|
||||
keyboard.onkeydown = this.onKeyDown;
|
||||
keyboard.onkeyup = this.onKeyUp;
|
||||
|
@ -5,28 +5,28 @@
|
||||
-ms-user-select: none;
|
||||
}
|
||||
|
||||
@-webkit-keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
0% {
|
||||
transform: translateY(-25%);
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
50%{
|
||||
transform: translateY(4%);
|
||||
}
|
||||
65%{
|
||||
transform: translateY(-2%);
|
||||
}
|
||||
80%{
|
||||
transform: translateY(2%);
|
||||
}
|
||||
95%{
|
||||
transform: translateY(-1%);
|
||||
}
|
||||
100% {
|
||||
transform: translateY(0%);
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.popup {
|
||||
-webkit-animation-name: fadeIn;
|
||||
animation-name: fadeIn;
|
||||
animation-duration: 0.4s;
|
||||
background-clip: padding-box;
|
||||
|
@ -4,6 +4,7 @@ import {
|
||||
CloudDownloadOutlined,
|
||||
CloudUploadOutlined,
|
||||
DeleteOutlined,
|
||||
EditOutlined,
|
||||
ExclamationCircleOutlined,
|
||||
FileExcelOutlined,
|
||||
FileImageOutlined,
|
||||
@ -23,18 +24,15 @@ import qs from "qs";
|
||||
import request from "../../common/request";
|
||||
import {server} from "../../common/constants";
|
||||
import Upload from "antd/es/upload";
|
||||
import {download, getToken, isEmpty, renderSize} from "../../utils/utils";
|
||||
import {download, getFileName, getToken, isEmpty, renderSize} from "../../utils/utils";
|
||||
import './FileSystem.css'
|
||||
|
||||
const formItemLayout = {
|
||||
labelCol: {span: 6},
|
||||
wrapperCol: {span: 14},
|
||||
};
|
||||
const {confirm} = Modal;
|
||||
|
||||
class FileSystem extends Component {
|
||||
|
||||
mkdirFormRef = React.createRef();
|
||||
renameFormRef = React.createRef();
|
||||
|
||||
state = {
|
||||
sessionId: undefined,
|
||||
@ -57,36 +55,6 @@ class FileSystem extends Component {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
handleOk = async (values) => {
|
||||
let params = {
|
||||
'dir': this.state.selectedRow.key + '/' + values['dir']
|
||||
}
|
||||
let paramStr = qs.stringify(params);
|
||||
|
||||
this.setState({
|
||||
confirmLoading: true
|
||||
})
|
||||
let result = await request.post(`/sessions/${this.state.sessionId}/mkdir?${paramStr}`);
|
||||
if (result.code === 1) {
|
||||
message.success('创建成功');
|
||||
this.loadFiles(this.state.currentDirectory);
|
||||
} else {
|
||||
message.error(result.message);
|
||||
}
|
||||
|
||||
this.setState({
|
||||
confirmLoading: false,
|
||||
confirmVisible: false
|
||||
})
|
||||
}
|
||||
|
||||
upload = () => {
|
||||
this.setState({
|
||||
uploadVisible: true
|
||||
})
|
||||
}
|
||||
|
||||
download = () => {
|
||||
download(`${server}/sessions/${this.state.sessionId}/download?file=${this.state.selectedRow.key}`);
|
||||
}
|
||||
@ -97,9 +65,9 @@ class FileSystem extends Component {
|
||||
message.warning('请至少选择一个文件或目录');
|
||||
}
|
||||
|
||||
let title = '';
|
||||
let title;
|
||||
if (selectedRowKeys.length === 1) {
|
||||
let file = selectedRowKeys[0].substring(selectedRowKeys[0].lastIndexOf('/') + 1, selectedRowKeys[0].length);
|
||||
let file = getFileName(selectedRowKeys[0]);
|
||||
title = <p>您确认要删除"{file}"吗?</p>;
|
||||
} else {
|
||||
title = `您确认要删除所选的${selectedRowKeys.length}项目吗?`;
|
||||
@ -114,7 +82,7 @@ class FileSystem extends Component {
|
||||
if (rowKey === '..') {
|
||||
continue;
|
||||
}
|
||||
let result = await request.delete(`/sessions/${this.state.sessionId}/rm?key=${rowKey}`);
|
||||
let result = await request.post(`/sessions/${this.state.sessionId}/rm?key=${rowKey}`);
|
||||
if (result['code'] !== 1) {
|
||||
message.error(result['message']);
|
||||
}
|
||||
@ -158,7 +126,8 @@ class FileSystem extends Component {
|
||||
this.setState({
|
||||
files: items,
|
||||
currentDirectory: key,
|
||||
selectedRow: {}
|
||||
selectedRow: {},
|
||||
selectedRowKeys: []
|
||||
})
|
||||
} finally {
|
||||
this.setState({
|
||||
@ -182,7 +151,6 @@ 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`,
|
||||
@ -195,10 +163,24 @@ class FileSystem extends Component {
|
||||
disableDownload = false;
|
||||
}
|
||||
|
||||
let disableRename = true;
|
||||
if (this.state.selectedRowKeys.length === 1) {
|
||||
disableRename = 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={<EditOutlined/>} disabled={disableRename}
|
||||
onClick={() => {
|
||||
this.setState({
|
||||
renameVisible: true
|
||||
})
|
||||
}}
|
||||
>重命名</Button></li>
|
||||
|
||||
<li><Button type={'text'} size={'small'} icon={<DeleteOutlined/>} onClick={this.rmdir}>删除</Button>
|
||||
</li>
|
||||
</ul>
|
||||
@ -365,7 +347,7 @@ class FileSystem extends Component {
|
||||
</Row>
|
||||
);
|
||||
|
||||
const {loading, selectedRowKeys} = this.state;
|
||||
const {selectedRowKeys} = this.state;
|
||||
const rowSelection = {
|
||||
selectedRowKeys,
|
||||
onChange: (selectedRowKeys) => {
|
||||
@ -465,10 +447,12 @@ class FileSystem extends Component {
|
||||
<Modal
|
||||
title="上传文件"
|
||||
visible={this.state.uploadVisible}
|
||||
centered={true}
|
||||
onOk={() => {
|
||||
this.setState({
|
||||
uploadVisible: false
|
||||
})
|
||||
this.loadFiles(this.state.currentDirectory);
|
||||
}}
|
||||
confirmLoading={this.state.uploadLoading}
|
||||
onCancel={() => {
|
||||
@ -484,34 +468,135 @@ class FileSystem extends Component {
|
||||
</Modal>
|
||||
|
||||
|
||||
<Modal
|
||||
title="创建文件夹"
|
||||
visible={this.state.mkdirVisible}
|
||||
onOk={() => {
|
||||
this.mkdirFormRef.current
|
||||
.validateFields()
|
||||
.then(values => {
|
||||
this.mkdirFormRef.current.resetFields();
|
||||
this.handleOk(values);
|
||||
})
|
||||
.catch(info => {
|
||||
{
|
||||
this.state.mkdirVisible ?
|
||||
<Modal
|
||||
title="创建文件夹"
|
||||
visible={this.state.mkdirVisible}
|
||||
centered={true}
|
||||
onOk={() => {
|
||||
this.mkdirFormRef.current
|
||||
.validateFields()
|
||||
.then(async values => {
|
||||
this.mkdirFormRef.current.resetFields();
|
||||
let params = {
|
||||
'dir': this.state.currentDirectory + '/' + values['dir']
|
||||
}
|
||||
let paramStr = qs.stringify(params);
|
||||
|
||||
});
|
||||
}}
|
||||
confirmLoading={this.state.confirmLoading}
|
||||
onCancel={() => {
|
||||
this.setState({
|
||||
mkdirVisible: false
|
||||
})
|
||||
}}
|
||||
>
|
||||
<Form ref={this.mkdirFormRef}>
|
||||
this.setState({
|
||||
confirmLoading: true
|
||||
})
|
||||
let result = await request.post(`/sessions/${this.state.sessionId}/mkdir?${paramStr}`);
|
||||
if (result.code === 1) {
|
||||
message.success('创建成功');
|
||||
this.loadFiles(this.state.currentDirectory);
|
||||
} else {
|
||||
message.error(result.message);
|
||||
}
|
||||
|
||||
this.setState({
|
||||
confirmLoading: false,
|
||||
mkdirVisible: false
|
||||
})
|
||||
})
|
||||
.catch(info => {
|
||||
|
||||
});
|
||||
}}
|
||||
confirmLoading={this.state.confirmLoading}
|
||||
onCancel={() => {
|
||||
this.setState({
|
||||
mkdirVisible: false
|
||||
})
|
||||
}}
|
||||
>
|
||||
<Form ref={this.mkdirFormRef}>
|
||||
|
||||
<Form.Item name='dir' rules={[{required: true, message: '请输入文件夹名称'}]}>
|
||||
<Input autoComplete="off" placeholder="请输入文件夹名称"/>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal> : undefined
|
||||
}
|
||||
|
||||
{
|
||||
this.state.renameVisible ?
|
||||
<Modal
|
||||
title="重命名"
|
||||
visible={this.state.renameVisible}
|
||||
centered={true}
|
||||
onOk={() => {
|
||||
this.renameFormRef.current
|
||||
.validateFields()
|
||||
.then(async values => {
|
||||
this.renameFormRef.current.resetFields();
|
||||
|
||||
try {
|
||||
let currentDirectory = this.state.currentDirectory;
|
||||
if (!currentDirectory.endsWith("/")) {
|
||||
currentDirectory += '/';
|
||||
}
|
||||
let params = {
|
||||
'oldName': this.state.selectedRowKeys[0],
|
||||
'newName': currentDirectory + values['newName'],
|
||||
}
|
||||
|
||||
if (params['oldName'] === params['newName']) {
|
||||
message.success('重命名成功');
|
||||
return;
|
||||
}
|
||||
|
||||
let paramStr = qs.stringify(params);
|
||||
|
||||
this.setState({
|
||||
confirmLoading: true
|
||||
})
|
||||
let result = await request.post(`/sessions/${this.state.sessionId}/rename?${paramStr}`);
|
||||
if (result['code'] === 1) {
|
||||
message.success('重命名成功');
|
||||
let files = this.state.files;
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
if (files['key'] === params['oldName']) {
|
||||
files[i].path = params['newName'];
|
||||
files[i].key = params['newName'];
|
||||
files[i].name = getFileName(params['newName']);
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.setState({
|
||||
files: files
|
||||
})
|
||||
} else {
|
||||
message.error(result.message);
|
||||
}
|
||||
} finally {
|
||||
this.setState({
|
||||
confirmLoading: false,
|
||||
renameVisible: false
|
||||
})
|
||||
}
|
||||
})
|
||||
.catch(info => {
|
||||
|
||||
});
|
||||
}}
|
||||
confirmLoading={this.state.confirmLoading}
|
||||
onCancel={() => {
|
||||
this.setState({
|
||||
renameVisible: false
|
||||
})
|
||||
}}
|
||||
>
|
||||
<Form ref={this.renameFormRef}
|
||||
initialValues={{newName: getFileName(this.state.selectedRowKeys[0])}}>
|
||||
<Form.Item name='newName' rules={[{required: true, message: '请输入新的名称'}]}>
|
||||
<Input autoComplete="off" placeholder="新的名称"/>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal> : undefined
|
||||
}
|
||||
|
||||
<Form.Item name='dir' rules={[{required: true, message: '请输入文件夹名称'}]}>
|
||||
<Input autoComplete="off" placeholder="请输入文件夹名称"/>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
|
||||
{this.getNodeTreeRightClickMenu()}
|
||||
</div>
|
||||
|
@ -221,4 +221,8 @@ export function renderSize(value) {
|
||||
let size = srcSize / Math.pow(1024, index);
|
||||
size = size.toFixed(2);
|
||||
return size + ' ' + unitArr[index];
|
||||
}
|
||||
|
||||
export function getFileName(fullFileName){
|
||||
return fullFileName.substring(fullFileName.lastIndexOf('/') + 1, fullFileName.length);
|
||||
}
|
Loading…
Reference in New Issue
Block a user