完善支持多行指令

This commit is contained in:
dushixiang 2021-01-26 23:19:16 +08:00
parent 807d24ccd8
commit 4bacdf3dbe
9 changed files with 84 additions and 58 deletions

View File

@ -104,8 +104,8 @@ func SetupRoutes() *echo.Echo {
{ {
sessions.POST("", SessionCreateEndpoint) sessions.POST("", SessionCreateEndpoint)
sessions.GET("/paging", SessionPagingEndpoint) sessions.GET("/paging", SessionPagingEndpoint)
sessions.POST("/:id/content", SessionContentEndpoint) sessions.POST("/:id/connect", SessionConnectEndpoint)
sessions.POST("/:id/discontent", Admin(SessionDiscontentEndpoint)) sessions.POST("/:id/disconnect", Admin(SessionDisconnectEndpoint))
sessions.POST("/:id/resize", SessionResizeEndpoint) sessions.POST("/:id/resize", SessionResizeEndpoint)
sessions.POST("/:id/upload", SessionUploadEndpoint) sessions.POST("/:id/upload", SessionUploadEndpoint)
sessions.GET("/:id/download", SessionDownloadEndpoint) sessions.GET("/:id/download", SessionDownloadEndpoint)

View File

@ -75,7 +75,7 @@ func SessionDeleteEndpoint(c echo.Context) error {
return Success(c, nil) return Success(c, nil)
} }
func SessionContentEndpoint(c echo.Context) error { func SessionConnectEndpoint(c echo.Context) error {
sessionId := c.Param("id") sessionId := c.Param("id")
session := model.Session{} session := model.Session{}
@ -89,7 +89,7 @@ func SessionContentEndpoint(c echo.Context) error {
return Success(c, nil) return Success(c, nil)
} }
func SessionDiscontentEndpoint(c echo.Context) error { func SessionDisconnectEndpoint(c echo.Context) error {
sessionIds := c.Param("id") sessionIds := c.Param("id")
split := strings.Split(sessionIds, ",") split := strings.Split(sessionIds, ",")

View File

@ -167,7 +167,7 @@ class Access extends Component {
}; };
updateSessionStatus = async (sessionId) => { updateSessionStatus = async (sessionId) => {
let result = await request.post(`/sessions/${sessionId}/content`); let result = await request.post(`/sessions/${sessionId}/connect`);
if (result.code !== 1) { if (result.code !== 1) {
message.error(result.message); message.error(result.message);
} }

View File

@ -101,7 +101,10 @@ class Console extends Component {
if (command !== '') { if (command !== '') {
let webSocket = this.state.webSocket; let webSocket = this.state.webSocket;
if (webSocket !== undefined && webSocket.readyState === WebSocket.OPEN) { if (webSocket !== undefined && webSocket.readyState === WebSocket.OPEN) {
webSocket.send(JSON.stringify({type: 'data', content: command + String.fromCharCode(13)})); webSocket.send(JSON.stringify({
type: 'data',
content: command + String.fromCharCode(13)
}));
} }
} }
executedCommand = true; executedCommand = true;
@ -142,7 +145,7 @@ class Console extends Component {
} }
term.focus(); term.focus();
if(webSocket.readyState === WebSocket.OPEN){ if (webSocket.readyState === WebSocket.OPEN) {
webSocket.send(JSON.stringify({type: 'resize', content: JSON.stringify({height, width})})); webSocket.send(JSON.stringify({type: 'resize', content: JSON.stringify({height, width})}));
} }
} }

View File

@ -1,9 +1,11 @@
import React, {Component} from 'react'; import React, {Component} from 'react';
import {Card, Input, List, PageHeader} from "antd"; import {Card, Input, List, PageHeader, Spin} from "antd";
import Console from "../access/Console"; import Console from "../access/Console";
import {itemRender} from "../../utils/utils"; import {itemRender} from "../../utils/utils";
import Logout from "../user/Logout"; import Logout from "../user/Logout";
import './Command.css' import './Command.css'
import request from "../../common/request";
import {message} from "antd/es";
const {Search} = Input; const {Search} = Input;
const routes = [ const routes = [
@ -29,13 +31,31 @@ class BatchCommand extends Component {
webSockets: [], webSockets: [],
assets: [], assets: [],
active: undefined, active: undefined,
loading: true
} }
componentDidMount() { componentDidMount() {
let params = new URLSearchParams(this.props.location.search); let params = new URLSearchParams(this.props.location.search);
let command = params.get('command');
let assets = JSON.parse(params.get('assets')); let assets = JSON.parse(params.get('assets'));
let commandId = params.get('commandId');
this.init(commandId, assets)
}
init = async (commandId, assets) => {
let result = await request.get(`/commands/${commandId}`);
if (result['code'] !== 1) {
message.error(result['message'], 10);
this.setState({
loading: false
})
return;
}
let command = result['data']['content'];
this.setState({ this.setState({
loading: false,
command: command, command: command,
assets: assets assets: assets
}) })
@ -66,50 +86,53 @@ class BatchCommand extends Component {
> >
</PageHeader> </PageHeader>
<div className="page-search"> <Spin spinning={this.state.loading} tip='正在获取指令内容...'>
<Search ref={this.commandRef} placeholder="请输入指令" onSearch={value => { <div className="page-search">
for (let i = 0; i < this.state.webSockets.length; i++) { <Search ref={this.commandRef} placeholder="请输入指令" onSearch={value => {
let ws = this.state.webSockets[i]['ws']; for (let i = 0; i < this.state.webSockets.length; i++) {
if (ws.readyState === WebSocket.OPEN) { let ws = this.state.webSockets[i]['ws'];
ws.send(JSON.stringify({ if (ws.readyState === WebSocket.OPEN) {
type: 'data', ws.send(JSON.stringify({
content: value + String.fromCharCode(13) type: 'data',
})); content: value + String.fromCharCode(13)
}));
}
} }
} this.commandRef.current.setValue('');
this.commandRef.current.setValue(''); }} enterButton='执行'/>
}} enterButton='执行'/> </div>
</div>
<div className="page-card">
<List
grid={{gutter: 16, column: 2}}
dataSource={this.state.assets}
renderItem={item => (
<List.Item>
<Card title={item.name}
className={this.state.active === item['id'] ? 'command-active' : ''}
onClick={() => {
if (this.state.active === item['id']) {
this.setState({
active: undefined
})
} else {
this.setState({
active: item['id']
})
}
}}
>
<Console assetId={item.id} command={this.state.command}
width={(window.innerWidth - 350) / 2}
height={420}
appendWebsocket={this.appendWebsocket}/>
</Card>
</List.Item>
)}
/>
</div>
</Spin>
<div className="page-card">
<List
grid={{gutter: 16, column: 2}}
dataSource={this.state.assets}
renderItem={item => (
<List.Item>
<Card title={item.name}
className={this.state.active === item['id'] ? 'command-active' : ''}
onClick={() => {
if (this.state.active === item['id']) {
this.setState({
active: undefined
})
} else {
this.setState({
active: item['id']
})
}
}}
>
<Console assetId={item.id} command={this.state.command}
width={(window.innerWidth - 350) / 2}
height={420}
appendWebsocket={this.appendWebsocket}/>
</Card>
</List.Item>
)}
/>
</div>
</> </>
); );
} }

View File

@ -1,4 +1,4 @@
.command-active { .command-active {
box-shadow: 0 0 0 2px #1890FF; box-shadow: 0 0 0 2px red;
outline: 2px solid #1890FF; outline: 2px solid red;
} }

View File

@ -73,7 +73,7 @@ class DynamicCommand extends Component {
assetsVisible: false, assetsVisible: false,
assets: [], assets: [],
checkedAssets: [], checkedAssets: [],
command: '', commandId: '',
model: null, model: null,
selectedRowKeys: [], selectedRowKeys: [],
delBtnLoading: false, delBtnLoading: false,
@ -223,7 +223,7 @@ class DynamicCommand extends Component {
} }
}); });
window.location.href = '#/batch-command?command=' + this.state.command + '&assets=' + JSON.stringify(cAssets); window.location.href = '#/batch-command?commandId=' + this.state.commandId + '&assets=' + JSON.stringify(cAssets);
}; };
handleOk = async (formData) => { handleOk = async (formData) => {
@ -463,7 +463,7 @@ class DynamicCommand extends Component {
this.setState({ this.setState({
assetsVisible: true, assetsVisible: true,
command: record.content commandId: record['id']
}); });
let result = await request.get('/assets?protocol=ssh'); let result = await request.get('/assets?protocol=ssh');

View File

@ -48,7 +48,7 @@ const DynamicCommandModal = ({title, visible, handleOk, handleCancel, confirmLoa
</Form.Item> </Form.Item>
<Form.Item label="指令内容" name='content' rules={[{required: true, message: '请输入指令内容'}]}> <Form.Item label="指令内容" name='content' rules={[{required: true, message: '请输入指令内容'}]}>
<TextArea autoSize={{minRows: 5, maxRows: 10}} placeholder="多行指令也会当做一行执行,请使用 && 或 其他方式进行连接"/> <TextArea autoSize={{minRows: 5, maxRows: 10}} placeholder="一行一个指令"/>
</Form.Item> </Form.Item>
</Form> </Form>

View File

@ -297,7 +297,7 @@ class OnlineSession extends Component {
}); });
const dis = async (id) => { const dis = async (id) => {
const result = await request.post(`/sessions/${id}/discontent`); const result = await request.post(`/sessions/${id}/disconnect`);
if (result.code === 1) { if (result.code === 1) {
notification['success']({ notification['success']({
message: '提示', message: '提示',