增加全局VNC与TELNET设置

This commit is contained in:
dushixiang 2021-02-10 21:56:05 +08:00 committed by dushixiang
parent 622fa65241
commit 25c3c6b929
11 changed files with 783 additions and 765 deletions

View File

@ -1,6 +1,7 @@
package api package api
import ( import (
"encoding/json"
"errors" "errors"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"next-terminal/pkg/model" "next-terminal/pkg/model"
@ -68,10 +69,17 @@ func AssetUpdateEndpoint(c echo.Context) error {
return err return err
} }
var item model.Asset m := echo.Map{}
if err := c.Bind(&item); err != nil { if err := c.Bind(&m); err != nil {
return err return err
} }
data, _ := json.Marshal(m)
var item model.Asset
if err := json.Unmarshal(data, &item); err != nil {
return err
}
switch item.AccountType { switch item.AccountType {
case "credential": case "credential":
item.Username = "-" item.Username = "-"
@ -102,6 +110,9 @@ func AssetUpdateEndpoint(c echo.Context) error {
} }
model.UpdateAssetById(&item, id) model.UpdateAssetById(&item, id)
if err := model.UpdateAssetAttributes(id, item.Protocol, m); err != nil {
return err
}
return Success(c, nil) return Success(c, nil)
} }
@ -151,8 +162,16 @@ func AssetGetEndpoint(c echo.Context) (err error) {
if item, err = model.FindAssetById(id); err != nil { if item, err = model.FindAssetById(id); err != nil {
return err return err
} }
attributeMap, err := model.FindAssetAttrMapByAssetId(id)
if err != nil {
return err
}
itemMap := utils.StructToMap(item)
for key := range attributeMap {
itemMap[key] = attributeMap[key]
}
return Success(c, item) return Success(c, itemMap)
} }
func AssetTcpingEndpoint(c echo.Context) (err error) { func AssetTcpingEndpoint(c echo.Context) (err error) {

View File

@ -1,8 +1,10 @@
package api package api
import ( import (
"errors"
"fmt" "fmt"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"gorm.io/gorm"
"next-terminal/pkg/model" "next-terminal/pkg/model"
) )
@ -19,11 +21,23 @@ func PropertyUpdateEndpoint(c echo.Context) error {
for key := range item { for key := range item {
value := fmt.Sprintf("%v", item[key]) value := fmt.Sprintf("%v", item[key])
if value == "" {
value = "-"
}
property := model.Property{ property := model.Property{
Name: key, Name: key,
Value: value, Value: value,
} }
model.UpdatePropertyByName(&property, key)
_, err := model.FindPropertyByName(key)
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
if err := model.CreateNewProperty(&property); err != nil {
return err
}
} else {
model.UpdatePropertyByName(&property, key)
}
} }
return Success(c, nil) return Success(c, nil)
} }

View File

@ -74,8 +74,6 @@ func SetupRoutes() *echo.Echo {
assets.GET("/paging", AssetPagingEndpoint) assets.GET("/paging", AssetPagingEndpoint)
assets.POST("/:id/tcping", AssetTcpingEndpoint) assets.POST("/:id/tcping", AssetTcpingEndpoint)
assets.PUT("/:id", AssetUpdateEndpoint) assets.PUT("/:id", AssetUpdateEndpoint)
assets.GET("/:id/attributes", AssetGetAttributeEndpoint)
assets.PUT("/:id/attributes", AssetUpdateAttributeEndpoint)
assets.DELETE("/:id", AssetDeleteEndpoint) assets.DELETE("/:id", AssetDeleteEndpoint)
assets.GET("/:id", AssetGetEndpoint) assets.GET("/:id", AssetGetEndpoint)
assets.POST("/:id/change-owner", Admin(AssetChangeOwnerEndpoint)) assets.POST("/:id/change-owner", Admin(AssetChangeOwnerEndpoint))

View File

@ -11,6 +11,7 @@ import (
"net" "net"
"os" "os"
"path/filepath" "path/filepath"
"reflect"
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
@ -157,3 +158,27 @@ func Contains(s []string, str string) bool {
} }
return false return false
} }
func StructToMap(obj interface{}) map[string]interface{} {
t := reflect.TypeOf(obj)
v := reflect.ValueOf(obj)
if t.Kind() == reflect.Ptr {
// 如果是指针,则获取其所指向的元素
t = t.Elem()
v = v.Elem()
}
var data = make(map[string]interface{})
if t.Kind() == reflect.Struct {
// 只有结构体可以获取其字段信息
for i := 0; i < t.NumField(); i++ {
jsonName := t.Field(i).Tag.Get("json")
if jsonName != "" {
data[jsonName] = v.Field(i).Interface()
} else {
data[t.Field(i).Name] = v.Field(i).Interface()
}
}
}
return data
}

View File

@ -40,10 +40,6 @@ import {
import {PROTOCOL_COLORS} from "../../common/constants"; import {PROTOCOL_COLORS} from "../../common/constants";
import Logout from "../user/Logout"; import Logout from "../user/Logout";
import {hasPermission, isAdmin} from "../../service/permission"; import {hasPermission, isAdmin} from "../../service/permission";
import AssetSSHAttributeModal from "./AssetSSHAttributeModal";
import AssetRDPAttributeModal from "./AssetRDPAttributeModal";
import AssetVNCAttributeModal from "./AssetVNCAttributeModal";
import AssetTelnetAttributeModal from "./AssetTelnetAttributeModal";
const confirm = Modal.confirm; const confirm = Modal.confirm;
const {Search} = Input; const {Search} = Input;
@ -89,8 +85,6 @@ class Asset extends Component {
users: [], users: [],
selected: {}, selected: {},
selectedSharers: [], selectedSharers: [],
attrVisible: false,
attributes: {}
}; };
async componentDidMount() { async componentDidMount() {
@ -230,34 +224,6 @@ class Asset extends Component {
await this.showModal('复制资产', result.data); await this.showModal('复制资产', result.data);
} }
async attr(record) {
let result = await request.get(`/assets/${record['id']}/attributes`);
if (result.code !== 1) {
message.error(result.message, 10);
return;
}
// eslint-disable-next-line no-extend-native
String.prototype.bool = function () {
return (/^true$/i).test(this);
};
let attributes = result['data'];
for (const key in attributes) {
if (!attributes.hasOwnProperty(key)) {
continue;
}
if (key === 'swap-red-blue') {
attributes[key] = attributes[key].bool();
}
}
this.setState({
selected: record,
attrVisible: true,
attributes: attributes
});
}
async showModal(title, asset = {}) { async showModal(title, asset = {}) {
// 并行请求 // 并行请求
let getCredentials = request.get('/credentials'); let getCredentials = request.get('/credentials');
@ -447,30 +413,6 @@ class Asset extends Component {
}) })
} }
handleUpdateAttr = async (formData) => {
// 弹窗 form 传来的数据
this.setState({
modalConfirmLoading: true
});
try {
let selected = this.state.selected;
let result = await request.put(`/assets/${selected['id']}/attributes?protocol=${selected['protocol']}`, formData);
if (result['code'] !== 1) {
message.error(result['message'], 10);
} else {
message.success('操作成功');
this.setState({
attrVisible: false
})
}
} finally {
this.setState({
modalConfirmLoading: false
});
}
}
handleCancelUpdateAttr = () => { handleCancelUpdateAttr = () => {
this.setState({ this.setState({
attrVisible: false, attrVisible: false,
@ -550,12 +492,6 @@ class Asset extends Component {
onClick={() => this.copy(record.id)}>复制</Button> onClick={() => this.copy(record.id)}>复制</Button>
</Menu.Item> </Menu.Item>
<Menu.Item key="3">
<Button type="text" size='small'
disabled={!hasPermission(record['owner'])}
onClick={() => this.attr(record)}>属性</Button>
</Menu.Item>
{isAdmin() ? {isAdmin() ?
<Menu.Item key="4"> <Menu.Item key="4">
<Button type="text" size='small' <Button type="text" size='small'
@ -893,50 +829,6 @@ class Asset extends Component {
/> />
</Modal> : undefined </Modal> : undefined
} }
{
this.state.attrVisible && this.state.selected['protocol'] === 'ssh' ?
<AssetSSHAttributeModal
handleOk={this.handleUpdateAttr}
handleCancel={this.handleCancelUpdateAttr}
confirmLoading={this.state.modalConfirmLoading}
attributes={this.state.attributes}
/>
: null
}
{
this.state.attrVisible && this.state.selected['protocol'] === 'rdp' ?
<AssetRDPAttributeModal
handleOk={this.handleUpdateAttr}
handleCancel={this.handleCancelUpdateAttr}
confirmLoading={this.state.modalConfirmLoading}
attributes={this.state.attributes}
/>
: null
}
{
this.state.attrVisible && this.state.selected['protocol'] === 'vnc' ?
<AssetVNCAttributeModal
handleOk={this.handleUpdateAttr}
handleCancel={this.handleCancelUpdateAttr}
confirmLoading={this.state.modalConfirmLoading}
attributes={this.state.attributes}
/>
: null
}
{
this.state.attrVisible && this.state.selected['protocol'] === 'telnet' ?
<AssetTelnetAttributeModal
handleOk={this.handleUpdateAttr}
handleCancel={this.handleCancelUpdateAttr}
confirmLoading={this.state.modalConfirmLoading}
attributes={this.state.attributes}
/>
: null
}
</Content> </Content>
</> </>
); );

View File

@ -1,8 +1,24 @@
import React, {useState} from 'react'; import React, {useState} from 'react';
import {Form, Input, InputNumber, Modal, Radio, Select, Tooltip} from "antd/lib/index"; import {
Col,
Collapse,
Form,
Input,
InputNumber,
Modal,
Radio,
Row,
Select,
Switch,
Tooltip,
Typography
} from "antd/lib/index";
import {ExclamationCircleOutlined} from "@ant-design/icons";
const {TextArea} = Input; const {TextArea} = Input;
const {Option} = Select; const {Option} = Select;
const {Text, Title} = Typography;
const {Panel} = Collapse;
// 子级页面 // 子级页面
// Ant form create 表单内置方法 // Ant form create 表单内置方法
@ -18,11 +34,29 @@ const protocolMapping = {
'telnet': [{text: '密码', value: 'custom'}, {text: '授权凭证', value: 'credential'}] 'telnet': [{text: '密码', value: 'custom'}, {text: '授权凭证', value: 'credential'}]
} }
const formLayout = {
labelCol: {span: 6},
wrapperCol: {span: 18},
};
const RDPFormItemLayout = {
labelCol: {span: 12},
wrapperCol: {span: 12},
};
const TELENETFormItemLayout = {
labelCol: {span: 8},
wrapperCol: {span: 16},
};
const AssetModal = function ({title, visible, handleOk, handleCancel, confirmLoading, credentials, tags, model}) { const AssetModal = function ({title, visible, handleOk, handleCancel, confirmLoading, credentials, tags, model}) {
const [form] = Form.useForm(); const [form] = Form.useForm();
if (model.accountType === undefined) {
model.accountType = 'rdp';
}
let [accountType, setAccountType] = useState(model.accountType); let [accountType, setAccountType] = useState(model.accountType);
let [protocol, setProtocol] = useState(model.protocol);
let initAccountTypes = [] let initAccountTypes = []
if (model.protocol) { if (model.protocol) {
@ -38,12 +72,8 @@ const AssetModal = function ({title, visible, handleOk, handleCancel, confirmLoa
} }
} }
const formItemLayout = {
labelCol: {span: 6},
wrapperCol: {span: 14},
};
const handleProtocolChange = e => { const handleProtocolChange = e => {
setProtocol(e.target.value)
let port; let port;
switch (e.target.value) { switch (e.target.value) {
case 'ssh': case 'ssh':
@ -109,109 +139,495 @@ const AssetModal = function ({title, visible, handleOk, handleCancel, confirmLoa
.catch(info => { .catch(info => {
}); });
}} }}
width={1040}
onCancel={handleCancel} onCancel={handleCancel}
confirmLoading={confirmLoading} confirmLoading={confirmLoading}
okText='确定' okText='确定'
cancelText='取消' cancelText='取消'
> >
<Form form={form} {...formItemLayout} initialValues={model}> <Form form={form} {...formLayout} initialValues={model}>
<Form.Item name='id' noStyle> <Row>
<Input hidden={true}/> <Col span={12}>
</Form.Item> <Form.Item name='id' noStyle>
<Input hidden={true}/>
</Form.Item>
<Form.Item label="资产名称" name='name' rules={[{required: true, message: "请输入资产名称"}]}> <Form.Item label="资产名称" name='name' rules={[{required: true, message: "请输入资产名称"}]}>
<Input placeholder="资产名称"/> <Input placeholder="资产名称"/>
</Form.Item> </Form.Item>
<Form.Item label="主机" name='ip' rules={[{required: true, message: '请输入资产的主机名称或者IP地址'}]}> <Form.Item label="主机" name='ip' rules={[{required: true, message: '请输入资产的主机名称或者IP地址'}]}>
<Input placeholder="资产的主机名称或者IP地址"/> <Input placeholder="资产的主机名称或者IP地址"/>
</Form.Item> </Form.Item>
<Form.Item label="接入协议" name='protocol' rules={[{required: true, message: '请选择接入协议'}]}> <Form.Item label="接入协议" name='protocol' rules={[{required: true, message: '请选择接入协议'}]}>
<Radio.Group onChange={handleProtocolChange}> <Radio.Group onChange={handleProtocolChange}>
<Radio value="rdp">rdp</Radio> <Radio value="rdp">rdp</Radio>
<Radio value="ssh">ssh</Radio> <Radio value="ssh">ssh</Radio>
<Radio value="vnc">vnc</Radio> <Radio value="vnc">vnc</Radio>
<Radio value="telnet">telnet</Radio> <Radio value="telnet">telnet</Radio>
</Radio.Group> </Radio.Group>
</Form.Item> </Form.Item>
<Form.Item label="端口号" name='port' rules={[{required: true, message: '请输入资产端口'}]}> <Form.Item label="端口号" name='port' rules={[{required: true, message: '请输入资产端口'}]}>
<InputNumber min={1} max={65535} placeholder='TCP端口'/> <InputNumber min={1} max={65535} placeholder='TCP端口'/>
</Form.Item> </Form.Item>
<Form.Item label="账户类型" name='accountType' rules={[{required: true, message: '请选择接账户类型'}]}> <Form.Item label="账户类型" name='accountType' rules={[{required: true, message: '请选择接账户类型'}]}>
<Select onChange={handleAccountTypeChange}> <Select onChange={handleAccountTypeChange}>
{accountTypes.map(item => { {accountTypes.map(item => {
return (<Option key={item.value} value={item.value}>{item.text}</Option>) return (<Option key={item.value} value={item.value}>{item.text}</Option>)
})}
</Select>
</Form.Item>
{
accountType === 'credential' ?
<Form.Item label="授权凭证" name='credentialId' rules={[{required: true, message: '请选择授权凭证'}]}>
<Select onChange={() => null}>
{credentials.map(item => {
return (
<Option key={item.id} value={item.id}>
<Tooltip placement="topLeft" title={item.name}>
{item.name}
</Tooltip>
</Option>
);
})} })}
</Select> </Select>
</Form.Item> </Form.Item>
: null
}
{ {
accountType === 'custom' ? accountType === 'credential' ?
<> <Form.Item label="授权凭证" name='credentialId'
<Form.Item label="授权账户" name='username' noStyle={!(accountType === 'custom')}> rules={[{required: true, message: '请选择授权凭证'}]}>
<Input placeholder="输入授权账户"/> <Select onChange={() => null}>
</Form.Item> {credentials.map(item => {
return (
<Option key={item.id} value={item.id}>
<Tooltip placement="topLeft" title={item.name}>
{item.name}
</Tooltip>
</Option>
);
})}
</Select>
</Form.Item>
: null
}
<Form.Item label="授权密码" name='password' noStyle={!(accountType === 'custom')}> {
<Input.Password placeholder="输入授权密码"/> accountType === 'custom' ?
</Form.Item> <>
</> <Form.Item label="授权账户" name='username' noStyle={!(accountType === 'custom')}>
: null <Input placeholder="输入授权账户"/>
} </Form.Item>
{ <Form.Item label="授权密码" name='password' noStyle={!(accountType === 'custom')}>
accountType === 'private-key' ? <Input.Password placeholder="输入授权密码"/>
<> </Form.Item>
<Form.Item label="授权账户" name='username'> </>
<Input placeholder="输入授权账户"/> : null
</Form.Item> }
<Form.Item label="私钥" name='privateKey' rules={[{required: true, message: '请输入私钥'}]}> {
<TextArea rows={4}/> accountType === 'private-key' ?
</Form.Item> <>
<Form.Item label="私钥密码" name='passphrase'> <Form.Item label="授权账户" name='username'>
<TextArea rows={1}/> <Input placeholder="输入授权账户"/>
</Form.Item> </Form.Item>
</>
: null
}
<Form.Item label="标签" name='tags'> <Form.Item label="私钥" name='privateKey'
<Select mode="tags" placeholder="标签可以更加方便的检索资产"> rules={[{required: true, message: '请输入私钥'}]}>
{tags.map(tag => { <TextArea rows={4}/>
if (tag === '-') { </Form.Item>
return undefined; <Form.Item label="私钥密码" name='passphrase'>
<TextArea rows={1}/>
</Form.Item>
</>
: null
}
<Form.Item label="标签" name='tags'>
<Select mode="tags" placeholder="标签可以更加方便的检索资产">
{tags.map(tag => {
if (tag === '-') {
return undefined;
}
return (<Option key={tag}>{tag}</Option>)
})}
</Select>
</Form.Item>
<Form.Item label="备注" name='description'>
<TextArea rows={4} placeholder='关于资产的一些信息您可以写在这里'/>
</Form.Item>
</Col>
<Col span={12}>
<Collapse defaultActiveKey={['remote-app', '认证', '显示设置', '控制终端行为', 'VNC中继']} ghost>
{
protocol === 'rdp' ?
<>
<Panel header={<Text strong>Remote App</Text>} key="remote-app">
<Form.Item
name="remote-app"
label={<Tooltip title="指定在远程桌面上启动的RemoteApp
如果您的远程桌面服务器支持该应用程序则该应用程序(且仅该应用程序)对用户可见
Windows需要对远程应用程序的名称使用特殊的符号
远程应用程序的名称必须以两个竖条作为前缀
例如如果您已经在您的服务器上为notepad.exe创建了一个远程应用程序并将其命名为notepad则您将该参数设置为:||notepad">
程序&nbsp;<ExclamationCircleOutlined/>
</Tooltip>}
>
<Input type='text' placeholder="remote app"/>
</Form.Item>
<Form.Item
name="remote-app-dir"
label={<Tooltip
title="remote app的工作目录如果未配置remote app此参数无效。">工作目录&nbsp;
<ExclamationCircleOutlined/></Tooltip>}
>
<Input type='text' placeholder="remote app的工作目录"/>
</Form.Item>
<Form.Item
name="remote-app-args"
label={<Tooltip title="remote app的命令行参数如果未配置remote app此参数无效。">参数&nbsp;
<ExclamationCircleOutlined/></Tooltip>}
>
<Input type='text' placeholder="remote app的命令行参数"/>
</Form.Item>
</Panel>
<Panel header={<Text strong>性能</Text>} key="">
<Form.Item
{...RDPFormItemLayout}
name="enable-wallpaper"
label="启用桌面墙纸"
valuePropName="checked"
rules={[
{
required: true,
},
]}
>
<Switch checkedChildren="开启" unCheckedChildren="关闭"/>
</Form.Item>
<Form.Item
{...RDPFormItemLayout}
name="enable-theming"
label="启用桌面主题"
valuePropName="checked"
rules={[
{
required: true,
},
]}
>
<Switch checkedChildren="开启" unCheckedChildren="关闭"/>
</Form.Item>
<Form.Item
{...RDPFormItemLayout}
name="enable-font-smoothing"
label="启用字体平滑ClearType"
valuePropName="checked"
rules={[
{
required: true,
},
]}
>
<Switch checkedChildren="开启" unCheckedChildren="关闭"/>
</Form.Item>
<Form.Item
{...RDPFormItemLayout}
name="enable-full-window-drag"
label="启用全窗口拖拽"
valuePropName="checked"
rules={[
{
required: true,
},
]}
>
<Switch checkedChildren="开启" unCheckedChildren="关闭"/>
</Form.Item>
<Form.Item
{...RDPFormItemLayout}
name="enable-desktop-composition"
label="启用桌面合成效果Aero"
valuePropName="checked"
rules={[
{
required: true,
},
]}
>
<Switch checkedChildren="开启" unCheckedChildren="关闭"/>
</Form.Item>
<Form.Item
{...RDPFormItemLayout}
name="enable-menu-animations"
label="启用菜单动画"
valuePropName="checked"
rules={[
{
required: true,
},
]}
>
<Switch checkedChildren="开启" unCheckedChildren="关闭"/>
</Form.Item>
<Form.Item
{...RDPFormItemLayout}
name="disable-bitmap-caching"
label="禁用位图缓存"
valuePropName="checked"
rules={[
{
required: true,
},
]}
>
<Switch checkedChildren="开启" unCheckedChildren="关闭"/>
</Form.Item>
<Form.Item
{...RDPFormItemLayout}
name="disable-offscreen-caching"
label="禁用离屏缓存"
valuePropName="checked"
rules={[
{
required: true,
},
]}
>
<Switch checkedChildren="开启" unCheckedChildren="关闭"/>
</Form.Item>
<Form.Item
{...RDPFormItemLayout}
name="disable-glyph-caching"
label="禁用字形缓存"
valuePropName="checked"
rules={[
{
required: true,
},
]}
>
<Switch checkedChildren="开启" unCheckedChildren="关闭"/>
</Form.Item>
</Panel>
</> : undefined
} }
return (<Option key={tag}>{tag}</Option>)
})}
</Select>
</Form.Item>
<Form.Item label="备注" name='description'> {
<TextArea rows={4} placeholder='关于资产的一些信息您可以写在这里'/> protocol === 'ssh' ?
</Form.Item> <>
<Panel header={<Text strong>显示设置</Text>} key="">
<Form.Item
name="color-scheme"
label="配色方案"
initialValue=""
>
<Select onChange={null}>
<Option value="">默认</Option>
<Option value="gray-black">黑底灰字</Option>
<Option value="green-black">黑底绿字</Option>
<Option value="white-black">黑底白字</Option>
<Option value="black-white">白底黑字</Option>
</Select>
</Form.Item>
<Form.Item
name="font-name"
label="字体名称"
>
<Input type='text' placeholder="为空时使用系统默认字体"/>
</Form.Item>
<Form.Item
name="font-size"
label="字体大小"
>
<Input type='number' placeholder="为空时使用系统默认字体大小" min={8} max={96}/>
</Form.Item>
</Panel>
<Panel header={<Text strong>控制终端行为</Text>} key="">
<Form.Item
name="backspace"
label="退格键映射"
initialValue=""
>
<Select onChange={null}>
<Option value="">默认</Option>
<Option value="127">删除键(Ctrl-?)</Option>
<Option value="8">退格键(Ctrl-H)</Option>
</Select>
</Form.Item>
<Form.Item
name="terminal-type"
label="终端类型"
initialValue=""
>
<Select onChange={null}>
<Option value="">默认</Option>
<Option value="ansi">ansi</Option>
<Option value="linux">linux</Option>
<Option value="vt100">vt100</Option>
<Option value="vt220">vt220</Option>
<Option value="xterm">xterm</Option>
<Option value="xterm-256color">xterm-256color</Option>
</Select>
</Form.Item>
</Panel>
</> : undefined
}
{
protocol === 'vnc' ?
<>
<Panel header={<Text strong>显示设置</Text>} key="">
<Form.Item
name="color-depth"
label="色彩深度"
initialValue=""
>
<Select onChange={null}>
<Option value="">默认</Option>
<Option value="16">低色16</Option>
<Option value="24">真彩24</Option>
<Option value="32">真彩32</Option>
<Option value="8">256</Option>
</Select>
</Form.Item>
<Form.Item
name="cursor"
label="光标"
initialValue=""
>
<Select onChange={null}>
<Option value="">默认</Option>
<Option value="local">本地</Option>
<Option value="remote">远程</Option>
</Select>
</Form.Item>
<Form.Item
name="swap-red-blue"
label="交换红蓝成分"
valuePropName="checked"
>
<Switch checkedChildren="开启" unCheckedChildren="关闭"/>
</Form.Item>
</Panel>
<Panel header={<Text strong>VNC中继</Text>} key="VNC">
<Form.Item label={<Tooltip
title="连接到VNC代理例如UltraVNC Repeater时要请求的目标主机。">目标主机&nbsp;
<ExclamationCircleOutlined/></Tooltip>}
name='dest-host'>
<Input placeholder="目标主机"/>
</Form.Item>
<Form.Item label={<Tooltip
title="连接到VNC代理例如UltraVNC Repeater时要请求的目标端口。">目标端口&nbsp;
<ExclamationCircleOutlined/></Tooltip>}
name='dest-port'>
<Input type='number' min={1} max={65535}
placeholder='目标端口'/>
</Form.Item>
</Panel>
</> : undefined
}
{
protocol === 'telnet' ?
<>
<Panel header={<Text strong>认证</Text>} key="">
<Form.Item
{...TELENETFormItemLayout}
name="username-regex"
label="用户名正则表达式"
>
<Input type='text' placeholder=""/>
</Form.Item>
<Form.Item
{...TELENETFormItemLayout}
name="password-regex"
label="密码正则表达式"
>
<Input type='text' placeholder=""/>
</Form.Item>
<Form.Item
{...TELENETFormItemLayout}
name="login-success-regex"
label="登录成功正则表达式"
>
<Input type='text' placeholder=""/>
</Form.Item>
<Form.Item
{...TELENETFormItemLayout}
name="login-failure-regex"
label="登录失败正则表达式"
>
<Input type='text' placeholder=""/>
</Form.Item>
</Panel>
<Panel header={<Text strong>显示设置</Text>} key="">
<Form.Item
name="color-scheme"
label="配色方案"
initialValue=""
>
<Select onChange={null}>
<Option value="">默认</Option>
<Option value="gray-black">黑底灰字</Option>
<Option value="green-black">黑底绿字</Option>
<Option value="white-black">黑底白字</Option>
<Option value="black-white">白底黑字</Option>
</Select>
</Form.Item>
<Form.Item
name="font-name"
label="字体名称"
>
<Input type='text' placeholder="为空时使用系统默认字体"/>
</Form.Item>
<Form.Item
name="font-size"
label="字体大小"
>
<Input type='number' placeholder="为空时使用系统默认字体大小" min={8} max={96}/>
</Form.Item>
</Panel>
<Panel header={<Text strong>控制终端行为</Text>} key="">
<Form.Item
name="backspace"
label="退格键映射"
initialValue=""
>
<Select onChange={null}>
<Option value="">默认</Option>
<Option value="127">删除键(Ctrl-?)</Option>
<Option value="8">退格键(Ctrl-H)</Option>
</Select>
</Form.Item>
<Form.Item
name="terminal-type"
label="终端类型"
initialValue=""
>
<Select onChange={null}>
<Option value="">默认</Option>
<Option value="ansi">ansi</Option>
<Option value="linux">linux</Option>
<Option value="vt100">vt100</Option>
<Option value="vt220">vt220</Option>
<Option value="xterm">xterm</Option>
<Option value="xterm-256color">xterm-256color</Option>
</Select>
</Form.Item>
</Panel>
</> : undefined
}
</Collapse>
</Col>
</Row>
</Form> </Form>
</Modal> </Modal>
) )

View File

@ -1,205 +0,0 @@
import React from 'react';
import {Collapse, Form, Input, Modal, Switch, Tooltip, Typography} from "antd/lib/index";
import {ExclamationCircleOutlined} from "@ant-design/icons";
const {Text} = Typography;
const {Panel} = Collapse;
const formLayout = {
labelCol: {span: 6},
wrapperCol: {span: 14},
};
const formItemLayout = {
labelCol: {span: 12},
wrapperCol: {span: 12},
};
const AssetRDPAttributeModal = function ({handleOk, handleCancel, confirmLoading, attributes}) {
const [form] = Form.useForm();
return (
<Modal
title={'属性'}
visible={true}
maskClosable={false}
centered={true}
onOk={() => {
form
.validateFields()
.then(values => {
form.resetFields();
handleOk(values);
})
.catch(info => {
});
}}
onCancel={handleCancel}
confirmLoading={confirmLoading}
okText='确定'
cancelText='取消'
>
<Form form={form} {...formLayout} initialValues={attributes}>
<Collapse defaultActiveKey={['remote-app']} ghost>
<Panel header={<Text strong>Remote App</Text>} key="remote-app">
<Form.Item
name="remote-app"
label={<Tooltip title="指定在远程桌面上启动的RemoteApp
如果您的远程桌面服务器支持该应用程序则该应用程序(且仅该应用程序)对用户可见
Windows需要对远程应用程序的名称使用特殊的符号
远程应用程序的名称必须以两个竖条作为前缀
例如如果您已经在您的服务器上为notepad.exe创建了一个远程应用程序并将其命名为notepad则您将该参数设置为:||notepad">
程序&nbsp;<ExclamationCircleOutlined/>
</Tooltip>}
>
<Input type='text' placeholder="remote app"/>
</Form.Item>
<Form.Item
name="remote-app-dir"
label={<Tooltip title="remote app的工作目录如果未配置remote app此参数无效。">工作目录&nbsp;
<ExclamationCircleOutlined/></Tooltip>}
>
<Input type='text' placeholder="remote app的工作目录"/>
</Form.Item>
<Form.Item
name="remote-app-args"
label={<Tooltip title="remote app的命令行参数如果未配置remote app此参数无效。">参数&nbsp;
<ExclamationCircleOutlined/></Tooltip>}
>
<Input type='text' placeholder="remote app的命令行参数"/>
</Form.Item>
</Panel>
<Panel header={<Text strong>性能</Text>} key="2">
<Form.Item
{...formItemLayout}
name="enable-wallpaper"
label="启用桌面墙纸"
valuePropName="checked"
rules={[
{
required: true,
},
]}
>
<Switch checkedChildren="开启" unCheckedChildren="关闭"/>
</Form.Item>
<Form.Item
{...formItemLayout}
name="enable-theming"
label="启用桌面主题"
valuePropName="checked"
rules={[
{
required: true,
},
]}
>
<Switch checkedChildren="开启" unCheckedChildren="关闭"/>
</Form.Item>
<Form.Item
{...formItemLayout}
name="enable-font-smoothing"
label="启用字体平滑ClearType"
valuePropName="checked"
rules={[
{
required: true,
},
]}
>
<Switch checkedChildren="开启" unCheckedChildren="关闭"/>
</Form.Item>
<Form.Item
{...formItemLayout}
name="enable-full-window-drag"
label="启用全窗口拖拽"
valuePropName="checked"
rules={[
{
required: true,
},
]}
>
<Switch checkedChildren="开启" unCheckedChildren="关闭"/>
</Form.Item>
<Form.Item
{...formItemLayout}
name="enable-desktop-composition"
label="启用桌面合成效果Aero"
valuePropName="checked"
rules={[
{
required: true,
},
]}
>
<Switch checkedChildren="开启" unCheckedChildren="关闭"/>
</Form.Item>
<Form.Item
{...formItemLayout}
name="enable-menu-animations"
label="启用菜单动画"
valuePropName="checked"
rules={[
{
required: true,
},
]}
>
<Switch checkedChildren="开启" unCheckedChildren="关闭"/>
</Form.Item>
<Form.Item
{...formItemLayout}
name="disable-bitmap-caching"
label="禁用位图缓存"
valuePropName="checked"
rules={[
{
required: true,
},
]}
>
<Switch checkedChildren="开启" unCheckedChildren="关闭"/>
</Form.Item>
<Form.Item
{...formItemLayout}
name="disable-offscreen-caching"
label="禁用离屏缓存"
valuePropName="checked"
rules={[
{
required: true,
},
]}
>
<Switch checkedChildren="开启" unCheckedChildren="关闭"/>
</Form.Item>
<Form.Item
{...formItemLayout}
name="disable-glyph-caching"
label="禁用字形缓存"
valuePropName="checked"
rules={[
{
required: true,
},
]}
>
<Switch checkedChildren="开启" unCheckedChildren="关闭"/>
</Form.Item>
</Panel>
</Collapse>
</Form>
</Modal>
)
}
export default AssetRDPAttributeModal;

View File

@ -1,107 +0,0 @@
import React from 'react';
import {Collapse, Form, Input, Modal, Select, Typography} from "antd/lib/index";
const {Option} = Select;
const {Panel} = Collapse;
const {Text} = Typography;
const AssetSSHAttributeModal = function ({handleOk, handleCancel, confirmLoading, attributes}) {
const [form] = Form.useForm();
const formItemLayout = {
labelCol: {span: 6},
wrapperCol: {span: 14},
};
return (
<Modal
title={'属性'}
visible={true}
maskClosable={false}
centered={true}
onOk={() => {
form
.validateFields()
.then(values => {
form.resetFields();
handleOk(values);
})
.catch(info => {
});
}}
onCancel={handleCancel}
confirmLoading={confirmLoading}
okText='确定'
cancelText='取消'
>
<Form form={form} {...formItemLayout} initialValues={attributes}>
<Collapse defaultActiveKey={['显示设置']} ghost>
<Panel header={<Text strong>显示设置</Text>} key="">
<Form.Item
name="color-scheme"
label="配色方案"
initialValue=""
>
<Select onChange={null}>
<Option value="">默认</Option>
<Option value="gray-black">黑底灰字</Option>
<Option value="green-black">黑底绿字</Option>
<Option value="white-black">黑底白字</Option>
<Option value="black-white">白底黑字</Option>
</Select>
</Form.Item>
<Form.Item
name="font-name"
label="字体名称"
>
<Input type='text' placeholder="为空时使用系统默认字体"/>
</Form.Item>
<Form.Item
name="font-size"
label="字体大小"
>
<Input type='number' placeholder="为空时使用系统默认字体大小" min={8} max={96}/>
</Form.Item>
</Panel>
<Panel header={<Text strong>控制终端行为</Text>} key="">
<Form.Item
name="backspace"
label="退格键映射"
initialValue=""
>
<Select onChange={null}>
<Option value="">默认</Option>
<Option value="string:127">删除键(Ctrl-?)</Option>
<Option value="string:8">退格键(Ctrl-H)</Option>
</Select>
</Form.Item>
<Form.Item
name="terminal-type"
label="终端类型"
initialValue=""
>
<Select onChange={null}>
<Option value="">默认</Option>
<Option value="ansi">ansi</Option>
<Option value="linux">linux</Option>
<Option value="vt100">vt100</Option>
<Option value="vt220">vt220</Option>
<Option value="xterm">xterm</Option>
<Option value="xterm-256color">xterm-256color</Option>
</Select>
</Form.Item>
</Panel>
</Collapse>
</Form>
</Modal>
)
}
export default AssetSSHAttributeModal;

View File

@ -1,133 +0,0 @@
import React from 'react';
import {Collapse, Form, Input, Modal, Select, Typography} from "antd/lib/index";
const {Option} = Select;
const {Panel} = Collapse;
const {Text} = Typography;
const AssetTelnetAttributeModal = function ({handleOk, handleCancel, confirmLoading, attributes}) {
const [form] = Form.useForm();
const formItemLayout = {
labelCol: {span: 8},
wrapperCol: {span: 14},
};
return (
<Modal
title={'属性'}
visible={true}
maskClosable={false}
centered={true}
onOk={() => {
form
.validateFields()
.then(values => {
form.resetFields();
handleOk(values);
})
.catch(info => {
});
}}
onCancel={handleCancel}
confirmLoading={confirmLoading}
okText='确定'
cancelText='取消'
>
<Form form={form} {...formItemLayout} initialValues={attributes}>
<Collapse defaultActiveKey={['认证']} ghost>
<Panel header={<Text strong>认证</Text>} key="">
<Form.Item
name="username-regex"
label="用户名正则表达式"
>
<Input type='text' placeholder=""/>
</Form.Item>
<Form.Item
name="password-regex"
label="密码正则表达式"
>
<Input type='text' placeholder=""/>
</Form.Item>
<Form.Item
name="login-success-regex"
label="登录成功正则表达式"
>
<Input type='text' placeholder=""/>
</Form.Item>
<Form.Item
name="login-failure-regex"
label="登录失败正则表达式"
>
<Input type='text' placeholder=""/>
</Form.Item>
</Panel>
<Panel header={<Text strong>显示设置</Text>} key="">
<Form.Item
name="color-scheme"
label="配色方案"
initialValue=""
>
<Select onChange={null}>
<Option value="">默认</Option>
<Option value="gray-black">黑底灰字</Option>
<Option value="green-black">黑底绿字</Option>
<Option value="white-black">黑底白字</Option>
<Option value="black-white">白底黑字</Option>
</Select>
</Form.Item>
<Form.Item
name="font-name"
label="字体名称"
>
<Input type='text' placeholder="为空时使用系统默认字体"/>
</Form.Item>
<Form.Item
name="font-size"
label="字体大小"
>
<Input type='number' placeholder="为空时使用系统默认字体大小" min={8} max={96}/>
</Form.Item>
</Panel>
<Panel header={<Text strong>控制终端行为</Text>} key="">
<Form.Item
name="backspace"
label="退格键映射"
initialValue=""
>
<Select onChange={null}>
<Option value="">默认</Option>
<Option value="string:127">删除键(Ctrl-?)</Option>
<Option value="string:8">退格键(Ctrl-H)</Option>
</Select>
</Form.Item>
<Form.Item
name="terminal-type"
label="终端类型"
initialValue=""
>
<Select onChange={null}>
<Option value="">默认</Option>
<Option value="ansi">ansi</Option>
<Option value="linux">linux</Option>
<Option value="vt100">vt100</Option>
<Option value="vt220">vt220</Option>
<Option value="xterm">xterm</Option>
<Option value="xterm-256color">xterm-256color</Option>
</Select>
</Form.Item>
</Panel>
</Collapse>
</Form>
</Modal>
)
}
export default AssetTelnetAttributeModal;

View File

@ -1,97 +0,0 @@
import React from 'react';
import {Collapse, Form, Input, Modal, Select, Switch, Tooltip, Typography} from "antd/lib/index";
import {ExclamationCircleOutlined} from "@ant-design/icons";
const {Text} = Typography;
const {Option} = Select;
const {Panel} = Collapse;
const formLayout = {
labelCol: {span: 6},
wrapperCol: {span: 14},
};
const AssetRDPAttributeModal = function ({handleOk, handleCancel, confirmLoading, attributes}) {
const [form] = Form.useForm();
return (
<Modal
title={'属性'}
visible={true}
maskClosable={false}
centered={true}
onOk={() => {
form
.validateFields()
.then(values => {
form.resetFields();
handleOk(values);
})
.catch(info => {
});
}}
onCancel={handleCancel}
confirmLoading={confirmLoading}
okText='确定'
cancelText='取消'
>
<Form form={form} {...formLayout} initialValues={attributes}>
<Collapse defaultActiveKey={['显示设置']} ghost>
<Panel header={<Text strong>显示设置</Text>} key="">
<Form.Item
name="color-depth"
label="色彩深度"
initialValue=""
>
<Select onChange={null}>
<Option value="">默认</Option>
<Option value="string:16">低色16</Option>
<Option value="string:24">真彩24</Option>
<Option value="string:32">真彩32</Option>
<Option value="string:8">256</Option>
</Select>
</Form.Item>
<Form.Item
name="cursor"
label="光标"
initialValue=""
>
<Select onChange={null}>
<Option value="">默认</Option>
<Option value="string:local">本地</Option>
<Option value="string:remote">远程</Option>
</Select>
</Form.Item>
<Form.Item
name="swap-red-blue"
label="交换红蓝成分"
>
<Switch checkedChildren="开启" unCheckedChildren="关闭"/>
</Form.Item>
</Panel>
<Panel header={<Text strong>VNC中继</Text>} key="2">
<Form.Item label={<Tooltip title="连接到VNC代理例如UltraVNC Repeater时要请求的目标主机。">目标主机&nbsp;
<ExclamationCircleOutlined/></Tooltip>}
name='dest-host'>
<Input placeholder="目标主机"/>
</Form.Item>
<Form.Item label={<Tooltip title="连接到VNC代理例如UltraVNC Repeater时要请求的目标端口。">目标端口&nbsp;
<ExclamationCircleOutlined/></Tooltip>}
name='dest-port'>
<Input type='number' min={1} max={65535}
placeholder='目标端口'/>
</Form.Item>
</Panel>
</Collapse>
</Form>
</Modal>
)
}
export default AssetRDPAttributeModal;

View File

@ -1,9 +1,10 @@
import React, {Component} from 'react'; import React, {Component} from 'react';
import {Button, Form, Input, Layout, PageHeader, Select, Switch, Tabs, Typography} from "antd"; import {Button, Form, Input, Layout, PageHeader, Select, Switch, Tabs, Tooltip, Typography} from "antd";
import {itemRender} from '../../utils/utils' import {itemRender} from '../../utils/utils'
import request from "../../common/request"; import request from "../../common/request";
import {message} from "antd/es"; import {message} from "antd/es";
import Logout from "../user/Logout"; import Logout from "../user/Logout";
import {ExclamationCircleOutlined} from "@ant-design/icons";
const {Content} = Layout; const {Content} = Layout;
const {Option} = Select; const {Option} = Select;
@ -37,9 +38,11 @@ class Setting extends Component {
properties: {} properties: {}
} }
settingFormRef1 = React.createRef(); rdpSettingFormRef = React.createRef();
settingFormRef2 = React.createRef(); sshSettingFormRef = React.createRef();
settingFormRef3 = React.createRef(); vncSettingFormRef = React.createRef();
telnetSettingFormRef = React.createRef();
otherSettingFormRef = React.createRef();
componentDidMount() { componentDidMount() {
this.getProperties(); this.getProperties();
@ -66,28 +69,36 @@ class Setting extends Component {
let properties = result['data']; let properties = result['data'];
for (let key in properties) { for (let key in properties) {
if(!properties.hasOwnProperty(key)){ if (!properties.hasOwnProperty(key)) {
continue; continue;
} }
if(key.startsWith('enable') || key.startsWith("disable")){ if (key.startsWith('enable') || key.startsWith("disable" || key === 'swap-red-blue')) {
properties[key] = properties[key].bool(); properties[key] = properties[key].bool();
} }
} }
console.log(properties)
this.setState({ this.setState({
properties: properties properties: properties
}) })
if (this.settingFormRef1.current) { if (this.rdpSettingFormRef.current) {
this.settingFormRef1.current.setFieldsValue(properties) this.rdpSettingFormRef.current.setFieldsValue(properties)
} }
if (this.settingFormRef2.current) { if (this.sshSettingFormRef.current) {
this.settingFormRef2.current.setFieldsValue(properties) this.sshSettingFormRef.current.setFieldsValue(properties)
} }
if (this.settingFormRef3.current) { if (this.vncSettingFormRef.current) {
this.settingFormRef3.current.setFieldsValue(properties) this.vncSettingFormRef.current.setFieldsValue(properties)
}
if (this.telnetSettingFormRef.current) {
this.telnetSettingFormRef.current.setFieldsValue(properties)
}
if (this.otherSettingFormRef.current) {
this.otherSettingFormRef.current.setFieldsValue(properties)
} }
} else { } else {
message.error(result['message']); message.error(result['message']);
@ -119,8 +130,8 @@ class Setting extends Component {
<Tabs tabPosition={'left'} onChange={this.handleOnTabChange} tabBarStyle={{width: 150}}> <Tabs tabPosition={'left'} onChange={this.handleOnTabChange} tabBarStyle={{width: 150}}>
<TabPane tab="RDP配置" key="1"> <TabPane tab="RDP配置" key="rdp">
<Form ref={this.settingFormRef1} name="password" onFinish={this.changeProperties} <Form ref={this.rdpSettingFormRef} name="rdp" onFinish={this.changeProperties}
layout="vertical"> layout="vertical">
<Title level={3}>RDP配置(远程桌面)</Title> <Title level={3}>RDP配置(远程桌面)</Title>
@ -306,8 +317,8 @@ class Setting extends Component {
</Form.Item> </Form.Item>
</Form> </Form>
</TabPane> </TabPane>
<TabPane tab="SSH配置" key="2"> <TabPane tab="SSH配置" key="ssh">
<Form ref={this.settingFormRef2} name="password" onFinish={this.changeProperties} <Form ref={this.sshSettingFormRef} name="ssh" onFinish={this.changeProperties}
layout="vertical"> layout="vertical">
<Title level={3}>SSH配置</Title> <Title level={3}>SSH配置</Title>
@ -360,6 +371,36 @@ class Setting extends Component {
<Input type='number' placeholder="请输入字体大小"/> <Input type='number' placeholder="请输入字体大小"/>
</Form.Item> </Form.Item>
<Form.Item
name="backspace"
label="退格键映射"
{...formItemLayout}
initialValue=""
>
<Select onChange={null}>
<Option value="">默认</Option>
<Option value="127">删除键(Ctrl-?)</Option>
<Option value="8">退格键(Ctrl-H)</Option>
</Select>
</Form.Item>
<Form.Item
name="terminal-type"
label="终端类型"
{...formItemLayout}
initialValue=""
>
<Select onChange={null}>
<Option value="">默认</Option>
<Option value="ansi">ansi</Option>
<Option value="linux">linux</Option>
<Option value="vt100">vt100</Option>
<Option value="vt220">vt220</Option>
<Option value="xterm">xterm</Option>
<Option value="xterm-256color">xterm-256color</Option>
</Select>
</Form.Item>
<Form.Item {...formTailLayout}> <Form.Item {...formTailLayout}>
<Button type="primary" htmlType="submit"> <Button type="primary" htmlType="submit">
更新 更新
@ -367,9 +408,166 @@ class Setting extends Component {
</Form.Item> </Form.Item>
</Form> </Form>
</TabPane> </TabPane>
<TabPane tab="其他配置" key="3"> <TabPane tab="VNC配置" key="vnc">
<Form ref={this.vncSettingFormRef} name="vnc" onFinish={this.changeProperties}
layout="vertical">
<Title level={3}>VNC配置</Title>
<Form.Item
{...formItemLayout}
name="color-depth"
label="色彩深度"
initialValue=""
>
<Select onChange={null}>
<Option value="">默认</Option>
<Option value="16">低色16</Option>
<Option value="24">真彩24</Option>
<Option value="32">真彩32</Option>
<Option value="8">256</Option>
</Select>
</Form.Item>
<Form.Item
{...formItemLayout}
name="cursor"
label="光标"
initialValue=""
>
<Select onChange={null}>
<Option value="">默认</Option>
<Option value="local">本地</Option>
<Option value="remote">远程</Option>
</Select>
</Form.Item>
<Form.Item
{...formItemLayout}
name="swap-red-blue"
label="交换红蓝成分"
valuePropName="checked"
>
<Switch checkedChildren="开启" unCheckedChildren="关闭"/>
</Form.Item>
<Form.Item label={<Tooltip
title="连接到VNC代理例如UltraVNC Repeater时要请求的目标主机。">目标主机&nbsp;
<ExclamationCircleOutlined/></Tooltip>}
{...formItemLayout}
name='dest-host'>
<Input placeholder="目标主机"/>
</Form.Item>
<Form.Item label={<Tooltip
title="连接到VNC代理例如UltraVNC Repeater时要请求的目标端口。">目标端口&nbsp;
<ExclamationCircleOutlined/></Tooltip>}
{...formItemLayout}
name='dest-port'>
<Input type='number' min={1} max={65535}
placeholder='目标端口'/>
</Form.Item>
<Form.Item {...formTailLayout}>
<Button type="primary" htmlType="submit">
更新
</Button>
</Form.Item>
</Form>
</TabPane>
<TabPane tab="TELNET配置" key="telnet">
<Form ref={this.telnetSettingFormRef} name="telnet" onFinish={this.changeProperties}
layout="vertical">
<Title level={3}>TELNET配置</Title>
<Form.Item
{...formItemLayout}
name="color-scheme"
label="配色方案"
rules={[
{
required: true,
message: '配色方案',
},
]}
initialValue="gray-black"
>
<Select style={{width: 120}} onChange={null}>
<Option value="gray-black">黑底灰字</Option>
<Option value="green-black">黑底绿字</Option>
<Option value="white-black">黑底白字</Option>
<Option value="black-white">白底黑字</Option>
</Select>
</Form.Item>
<Form.Item
{...formItemLayout}
name="font-name"
label="字体名称"
rules={[
{
required: true,
message: '字体名称',
},
]}
>
<Input type='text' placeholder="请输入字体名称"/>
</Form.Item>
<Form.Item
{...formItemLayout}
name="font-size"
label="字体大小"
rules={[
{
required: true,
message: '字体大小',
},
]}
>
<Input type='number' placeholder="请输入字体大小"/>
</Form.Item>
<Form.Item
name="backspace"
label="退格键映射"
{...formItemLayout}
initialValue=""
>
<Select onChange={null}>
<Option value="">默认</Option>
<Option value="127">删除键(Ctrl-?)</Option>
<Option value="8">退格键(Ctrl-H)</Option>
</Select>
</Form.Item>
<Form.Item
name="terminal-type"
label="终端类型"
{...formItemLayout}
initialValue=""
>
<Select onChange={null}>
<Option value="">默认</Option>
<Option value="ansi">ansi</Option>
<Option value="linux">linux</Option>
<Option value="vt100">vt100</Option>
<Option value="vt220">vt220</Option>
<Option value="xterm">xterm</Option>
<Option value="xterm-256color">xterm-256color</Option>
</Select>
</Form.Item>
<Form.Item {...formTailLayout}>
<Button type="primary" htmlType="submit">
更新
</Button>
</Form.Item>
</Form>
</TabPane>
<TabPane tab="其他配置" key="other">
<Title level={3}>Guacd 服务配置</Title> <Title level={3}>Guacd 服务配置</Title>
<Form ref={this.settingFormRef3} name="password" onFinish={this.changeProperties} <Form ref={this.otherSettingFormRef} name="password" onFinish={this.changeProperties}
layout="vertical"> layout="vertical">
<Form.Item <Form.Item
{...formItemLayout} {...formItemLayout}
@ -449,8 +647,6 @@ class Setting extends Component {
</Form> </Form>
</TabPane> </TabPane>
</Tabs> </Tabs>
</Content> </Content>
</> </>
); );