- 修复操作磁盘空间失败的问题
- 移除不可用的菜单 - 修复接入页面粘贴板等按钮不可点击的问题 - 修复接入RDP协议时无法自适应窗口大小的问题
This commit is contained in:
parent
8f51644cae
commit
a52ad2e356
@ -3,14 +3,14 @@ package api
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"next-terminal/server/common"
|
|
||||||
"next-terminal/server/common/maps"
|
|
||||||
"next-terminal/server/common/nt"
|
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"next-terminal/server/common"
|
||||||
|
"next-terminal/server/common/maps"
|
||||||
|
"next-terminal/server/common/nt"
|
||||||
"next-terminal/server/model"
|
"next-terminal/server/model"
|
||||||
"next-terminal/server/repository"
|
"next-terminal/server/repository"
|
||||||
"next-terminal/server/service"
|
"next-terminal/server/service"
|
||||||
|
@ -216,6 +216,9 @@ var DefaultMenu = []*model.Menu{
|
|||||||
model.NewMenu("job-log", "日志", "job",
|
model.NewMenu("job-log", "日志", "job",
|
||||||
model.NewPermission("GET", "/jobs/:id/logs/paging"),
|
model.NewPermission("GET", "/jobs/:id/logs/paging"),
|
||||||
),
|
),
|
||||||
|
model.NewMenu("job-log-clear", "日志清空", "job",
|
||||||
|
model.NewPermission("DELETE", "/jobs/:id/logs"),
|
||||||
|
),
|
||||||
|
|
||||||
model.NewMenu("storage", "磁盘空间", "ops",
|
model.NewMenu("storage", "磁盘空间", "ops",
|
||||||
model.NewPermission("GET", "/storages/paging"),
|
model.NewPermission("GET", "/storages/paging"),
|
||||||
|
@ -30,8 +30,6 @@ const STATE_CONNECTED = 3;
|
|||||||
const STATE_DISCONNECTING = 4;
|
const STATE_DISCONNECTING = 4;
|
||||||
const STATE_DISCONNECTED = 5;
|
const STATE_DISCONNECTED = 5;
|
||||||
|
|
||||||
let clientState = STATE_IDLE;
|
|
||||||
|
|
||||||
const Guacd = () => {
|
const Guacd = () => {
|
||||||
|
|
||||||
let [searchParams] = useSearchParams();
|
let [searchParams] = useSearchParams();
|
||||||
@ -48,6 +46,7 @@ const Guacd = () => {
|
|||||||
height = window.innerHeight;
|
height = window.innerHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let [box, setBox] = useState({width, height});
|
||||||
let [guacd, setGuacd] = useState({});
|
let [guacd, setGuacd] = useState({});
|
||||||
let [session, setSession] = useState({});
|
let [session, setSession] = useState({});
|
||||||
let [clipboardText, setClipboardText] = useState('');
|
let [clipboardText, setClipboardText] = useState('');
|
||||||
@ -57,6 +56,17 @@ const Guacd = () => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.title = assetName;
|
document.title = assetName;
|
||||||
|
createSession();
|
||||||
|
}, [assetId, assetName]);
|
||||||
|
|
||||||
|
const createSession = async () => {
|
||||||
|
let session = await sessionApi.create(assetId, 'guacd');
|
||||||
|
if (!strings.hasText(session['id'])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setSession(session);
|
||||||
|
renderDisplay(session['id'], protocol, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
const renderDisplay = (sessionId, protocol, width, height) => {
|
const renderDisplay = (sessionId, protocol, width, height) => {
|
||||||
let tunnel = new Guacamole.WebSocketTunnel(`${wsServer}/sessions/${sessionId}/tunnel`);
|
let tunnel = new Guacamole.WebSocketTunnel(`${wsServer}/sessions/${sessionId}/tunnel`);
|
||||||
@ -146,17 +156,6 @@ const Guacd = () => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const x = async () => {
|
|
||||||
let session = await sessionApi.create(assetId, 'guacd');
|
|
||||||
if (!strings.hasText(session['id'])) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setSession(session);
|
|
||||||
renderDisplay(session['id'], protocol, width, height);
|
|
||||||
}
|
|
||||||
x();
|
|
||||||
}, [assetId, assetName]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let resize = debounce(() => {
|
let resize = debounce(() => {
|
||||||
onWindowResize();
|
onWindowResize();
|
||||||
@ -175,10 +174,15 @@ const Guacd = () => {
|
|||||||
const onWindowResize = () => {
|
const onWindowResize = () => {
|
||||||
if (guacd.client && !fixedSize) {
|
if (guacd.client && !fixedSize) {
|
||||||
const display = guacd.client.getDisplay();
|
const display = guacd.client.getDisplay();
|
||||||
display.scale(Math.min(
|
let width = window.innerWidth;
|
||||||
window.innerHeight / display.getHeight(),
|
let height = window.innerHeight;
|
||||||
window.innerWidth / display.getHeight()
|
setBox({width, height});
|
||||||
));
|
let scale = Math.min(
|
||||||
|
height / display.getHeight(),
|
||||||
|
width / display.getHeight()
|
||||||
|
);
|
||||||
|
display.scale(scale);
|
||||||
|
guacd.client.sendSize(width, height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,7 +230,7 @@ const Guacd = () => {
|
|||||||
if (navigator.clipboard) {
|
if (navigator.clipboard) {
|
||||||
await navigator.clipboard.writeText(data);
|
await navigator.clipboard.writeText(data);
|
||||||
}
|
}
|
||||||
message.info('您选择的内容已复制到您的粘贴板中,在右侧的输入框中可同时查看到。');
|
message.success('您选择的内容已复制到您的粘贴板中,在右侧的输入框中可同时查看到。');
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
let reader = new Guacamole.BlobReader(stream, mimetype);
|
let reader = new Guacamole.BlobReader(stream, mimetype);
|
||||||
@ -237,9 +241,6 @@ const Guacd = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const sendClipboard = (data) => {
|
const sendClipboard = (data) => {
|
||||||
if (clientState !== STATE_CONNECTED) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!guacd.client) {
|
if (!guacd.client) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -266,7 +267,6 @@ const Guacd = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const onClientStateChange = (state, sessionId) => {
|
const onClientStateChange = (state, sessionId) => {
|
||||||
clientState = state;
|
|
||||||
const key = 'message';
|
const key = 'message';
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case STATE_IDLE:
|
case STATE_IDLE:
|
||||||
@ -309,6 +309,7 @@ const Guacd = () => {
|
|||||||
for (let j = 0; j < keys.length; j++) {
|
for (let j = 0; j < keys.length; j++) {
|
||||||
guacd.client.sendKeyEvent(0, keys[j]);
|
guacd.client.sendKeyEvent(0, keys[j]);
|
||||||
}
|
}
|
||||||
|
message.success('发送组合键成功');
|
||||||
}
|
}
|
||||||
|
|
||||||
const showMessage = (msg) => {
|
const showMessage = (msg) => {
|
||||||
@ -441,17 +442,17 @@ const Guacd = () => {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="container" style={{
|
<div className="container" style={{
|
||||||
width: width,
|
width: box.width,
|
||||||
height: height,
|
height: box.height,
|
||||||
margin: '0 auto'
|
margin: '0 auto',
|
||||||
|
backgroundColor: '#1b1b1b'
|
||||||
}}>
|
}}>
|
||||||
<div id="display"/>
|
<div id="display"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Draggable>
|
<Draggable>
|
||||||
<Affix style={{position: 'absolute', top: 50, right: 50}}>
|
<Affix style={{position: 'absolute', top: 50, right: 50}}>
|
||||||
<Button icon={<ExpandOutlined/>} disabled={clientState !== STATE_CONNECTED}
|
<Button icon={<ExpandOutlined/>} onClick={() => {
|
||||||
onClick={() => {
|
|
||||||
fullScreen();
|
fullScreen();
|
||||||
}}/>
|
}}/>
|
||||||
</Affix>
|
</Affix>
|
||||||
@ -461,7 +462,7 @@ const Guacd = () => {
|
|||||||
session['copy'] === '1' || session['paste'] === '1' ?
|
session['copy'] === '1' || session['paste'] === '1' ?
|
||||||
<Draggable>
|
<Draggable>
|
||||||
<Affix style={{position: 'absolute', top: 50, right: 100}}>
|
<Affix style={{position: 'absolute', top: 50, right: 100}}>
|
||||||
<Button icon={<CopyOutlined/>} disabled={clientState !== STATE_CONNECTED}
|
<Button icon={<CopyOutlined/>}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setClipboardVisible(true);
|
setClipboardVisible(true);
|
||||||
}}/>
|
}}/>
|
||||||
@ -475,8 +476,7 @@ const Guacd = () => {
|
|||||||
<Draggable>
|
<Draggable>
|
||||||
<Affix style={{position: 'absolute', top: 100, right: 100}}>
|
<Affix style={{position: 'absolute', top: 100, right: 100}}>
|
||||||
<Dropdown overlay={hotKeyMenu} trigger={['click']} placement="bottomLeft">
|
<Dropdown overlay={hotKeyMenu} trigger={['click']} placement="bottomLeft">
|
||||||
<Button icon={<WindowsOutlined/>}
|
<Button icon={<WindowsOutlined/>}/>
|
||||||
disabled={clientState !== STATE_CONNECTED}/>
|
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
</Affix>
|
</Affix>
|
||||||
</Draggable>
|
</Draggable>
|
||||||
@ -486,8 +486,7 @@ const Guacd = () => {
|
|||||||
(protocol === 'rdp' && session['fileSystem'] === '1') &&
|
(protocol === 'rdp' && session['fileSystem'] === '1') &&
|
||||||
<Draggable>
|
<Draggable>
|
||||||
<Affix style={{position: 'absolute', top: 100, right: 50}}>
|
<Affix style={{position: 'absolute', top: 100, right: 50}}>
|
||||||
<Button icon={<FolderOutlined/>}
|
<Button icon={<FolderOutlined/>} onClick={() => {
|
||||||
disabled={clientState !== STATE_CONNECTED} onClick={() => {
|
|
||||||
setFileSystemVisible(true);
|
setFileSystemVisible(true);
|
||||||
}}/>
|
}}/>
|
||||||
</Affix>
|
</Affix>
|
||||||
@ -499,8 +498,7 @@ const Guacd = () => {
|
|||||||
<Draggable>
|
<Draggable>
|
||||||
<Affix style={{position: 'absolute', top: 100, right: 100}}>
|
<Affix style={{position: 'absolute', top: 100, right: 100}}>
|
||||||
<Dropdown overlay={hotKeyMenu} trigger={['click']} placement="bottomLeft">
|
<Dropdown overlay={hotKeyMenu} trigger={['click']} placement="bottomLeft">
|
||||||
<Button icon={<WindowsOutlined/>}
|
<Button icon={<WindowsOutlined/>}/>
|
||||||
disabled={clientState !== STATE_CONNECTED}/>
|
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
</Affix>
|
</Affix>
|
||||||
</Draggable>
|
</Draggable>
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
import React, {useEffect} from 'react';
|
import React, {useState} from 'react';
|
||||||
import {Form, Input, Modal, Switch} from "antd";
|
import {Form, Input, InputNumber, Modal, Select, Switch} from "antd";
|
||||||
import storageApi from "../../api/storage";
|
import storageApi from "../../api/storage";
|
||||||
|
import {renderSize} from "../../utils/utils";
|
||||||
|
import {useQuery} from "react-query";
|
||||||
|
import strings from "../../utils/strings";
|
||||||
|
|
||||||
const formItemLayout = {
|
const formItemLayout = {
|
||||||
labelCol: {span: 6},
|
labelCol: {span: 6},
|
||||||
@ -17,23 +20,38 @@ const StorageModal = ({
|
|||||||
|
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
|
|
||||||
|
useQuery('getStorageById', () => storageApi.getById(id), {
|
||||||
useEffect(() => {
|
enabled: visible && strings.hasText(id),
|
||||||
|
onSuccess: data => {
|
||||||
const getItem = async () => {
|
if (data['limitSize'] > 0) {
|
||||||
let data = await storageApi.getById(id);
|
let limitSize = renderSize(data['limitSize']);
|
||||||
if (data) {
|
let ss = limitSize.split(' ');
|
||||||
form.setFieldsValue(data);
|
data['limitSize'] = parseInt(ss[0]);
|
||||||
}
|
setUnit(ss[1]);
|
||||||
}
|
|
||||||
if (visible && id) {
|
|
||||||
getItem();
|
|
||||||
} else {
|
} else {
|
||||||
form.setFieldsValue({
|
data['limitSize'] = -1;
|
||||||
isShare: false,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}, [visible])
|
form.setFieldsValue(data);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
let [unit, setUnit] = useState('MB');
|
||||||
|
|
||||||
|
const selectAfter = (
|
||||||
|
<Select value={unit} style={{width: 65}} onChange={(value) => {
|
||||||
|
setUnit(value);
|
||||||
|
}}>
|
||||||
|
<Select.Option value="B">B</Select.Option>
|
||||||
|
<Select.Option value="KB">KB</Select.Option>
|
||||||
|
<Select.Option value="MB">MB</Select.Option>
|
||||||
|
<Select.Option value="GB">GB</Select.Option>
|
||||||
|
<Select.Option value="TB">TB</Select.Option>
|
||||||
|
<Select.Option value="PB">PB</Select.Option>
|
||||||
|
<Select.Option value="EB">EB</Select.Option>
|
||||||
|
<Select.Option value="ZB">ZB</Select.Option>
|
||||||
|
<Select.Option value="YB">YB</Select.Option>
|
||||||
|
</Select>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
@ -45,6 +63,35 @@ const StorageModal = ({
|
|||||||
form
|
form
|
||||||
.validateFields()
|
.validateFields()
|
||||||
.then(async values => {
|
.then(async values => {
|
||||||
|
let limitSize = values['limitSize'];
|
||||||
|
switch (unit) {
|
||||||
|
case 'B':
|
||||||
|
break;
|
||||||
|
case 'KB':
|
||||||
|
limitSize = limitSize * 1024;
|
||||||
|
break;
|
||||||
|
case 'MB':
|
||||||
|
limitSize = limitSize * 1024 * 1024;
|
||||||
|
break;
|
||||||
|
case 'GB':
|
||||||
|
limitSize = limitSize * 1024 * 1024 * 1024;
|
||||||
|
break;
|
||||||
|
case 'TB':
|
||||||
|
limitSize = limitSize * 1024 * 1024 * 1024 * 1024 * 1024;
|
||||||
|
break;
|
||||||
|
case 'EB':
|
||||||
|
limitSize = limitSize * 1024 * 1024 * 1024 * 1024 * 1024 * 1024;
|
||||||
|
break;
|
||||||
|
case 'ZB':
|
||||||
|
limitSize = limitSize * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024;
|
||||||
|
break;
|
||||||
|
case 'YB':
|
||||||
|
limitSize = limitSize * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
values['limitSize'] = limitSize;
|
||||||
let ok = await handleOk(values);
|
let ok = await handleOk(values);
|
||||||
if (ok) {
|
if (ok) {
|
||||||
form.resetFields();
|
form.resetFields();
|
||||||
@ -53,6 +100,7 @@ const StorageModal = ({
|
|||||||
}}
|
}}
|
||||||
onCancel={() => {
|
onCancel={() => {
|
||||||
form.resetFields();
|
form.resetFields();
|
||||||
|
setUnit('MB');
|
||||||
handleCancel();
|
handleCancel();
|
||||||
}}
|
}}
|
||||||
confirmLoading={confirmLoading}
|
confirmLoading={confirmLoading}
|
||||||
@ -76,7 +124,7 @@ const StorageModal = ({
|
|||||||
|
|
||||||
<Form.Item label="大小限制" name='limitSize' rules={[{required: true, message: '请输入大小限制'}]}
|
<Form.Item label="大小限制" name='limitSize' rules={[{required: true, message: '请输入大小限制'}]}
|
||||||
tooltip='无限制请填写-1'>
|
tooltip='无限制请填写-1'>
|
||||||
<Input type={'number'} min={-1} suffix="MB"/>
|
<InputNumber min={-1} addonAfter={selectAfter} style={{width: 275}}/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
</Form>
|
</Form>
|
||||||
|
@ -369,7 +369,7 @@ class Setting extends Component {
|
|||||||
<Form ref={this.sshSettingFormRef} name="ssh" onFinish={this.changeProperties}
|
<Form ref={this.sshSettingFormRef} name="ssh" onFinish={this.changeProperties}
|
||||||
layout="vertical">
|
layout="vertical">
|
||||||
|
|
||||||
<Title level={4}>SSH/TELNET配置</Title>
|
<Title level={4}>TELNET配置</Title>
|
||||||
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
{...formItemLayout}
|
{...formItemLayout}
|
||||||
|
@ -83,11 +83,6 @@ export const routers = [
|
|||||||
label: '登录日志',
|
label: '登录日志',
|
||||||
icon: <LoginOutlined/>,
|
icon: <LoginOutlined/>,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
key: 'storage-log',
|
|
||||||
label: '文件日志',
|
|
||||||
icon: <LoginOutlined/>,
|
|
||||||
},
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -95,11 +90,6 @@ export const routers = [
|
|||||||
label: '系统运维',
|
label: '系统运维',
|
||||||
icon: <ControlOutlined/>,
|
icon: <ControlOutlined/>,
|
||||||
children: [
|
children: [
|
||||||
// {
|
|
||||||
// key: 'batch-command',
|
|
||||||
// label: '批量命令',
|
|
||||||
// icon: <BlockOutlined/>,
|
|
||||||
// },
|
|
||||||
{
|
{
|
||||||
key: 'job',
|
key: 'job',
|
||||||
label: '计划任务',
|
label: '计划任务',
|
||||||
|
@ -217,7 +217,7 @@ export function exitFull() {
|
|||||||
|
|
||||||
export function renderSize(value) {
|
export function renderSize(value) {
|
||||||
if (null == value || value === '' || value === 0) {
|
if (null == value || value === '' || value === 0) {
|
||||||
return "0 Bytes";
|
return "0 B";
|
||||||
}
|
}
|
||||||
const unitArr = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
|
const unitArr = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
|
||||||
let srcSize = parseFloat(value);
|
let srcSize = parseFloat(value);
|
||||||
|
Loading…
Reference in New Issue
Block a user