- 修复操作磁盘空间失败的问题
- 移除不可用的菜单 - 修复接入页面粘贴板等按钮不可点击的问题 - 修复接入RDP协议时无法自适应窗口大小的问题
This commit is contained in:
		| @ -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); | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user