Initial commit
This commit is contained in:
512
web/src/components/asset/Asset.js
Normal file
512
web/src/components/asset/Asset.js
Normal file
@ -0,0 +1,512 @@
|
||||
import React, {Component} from 'react';
|
||||
import "video-react/dist/video-react.css";
|
||||
|
||||
import {
|
||||
Badge,
|
||||
Button,
|
||||
Col,
|
||||
Divider,
|
||||
Input,
|
||||
Layout,
|
||||
Modal,
|
||||
PageHeader,
|
||||
Row,
|
||||
Select,
|
||||
Space,
|
||||
Table,
|
||||
Tag,
|
||||
Tooltip,
|
||||
Typography
|
||||
} from "antd";
|
||||
import qs from "qs";
|
||||
import AssetModal from "./AssetModal";
|
||||
import request from "../../common/request";
|
||||
import {message} from "antd/es";
|
||||
|
||||
|
||||
import {
|
||||
CodeTwoTone,
|
||||
CopyTwoTone,
|
||||
DeleteOutlined,
|
||||
DeleteTwoTone,
|
||||
EditTwoTone,
|
||||
ExclamationCircleOutlined,
|
||||
PlusOutlined,
|
||||
SyncOutlined,
|
||||
UndoOutlined
|
||||
} from '@ant-design/icons';
|
||||
import {itemRender} from "../../utils/utils";
|
||||
import {PROTOCOL_COLORS} from "../../common/constants";
|
||||
|
||||
const confirm = Modal.confirm;
|
||||
const {Search} = Input;
|
||||
const {Content} = Layout;
|
||||
const {Title, Text} = Typography;
|
||||
const routes = [
|
||||
{
|
||||
path: '',
|
||||
breadcrumbName: '首页',
|
||||
},
|
||||
{
|
||||
path: 'assets',
|
||||
breadcrumbName: '资产管理',
|
||||
}
|
||||
];
|
||||
|
||||
class Asset extends Component {
|
||||
|
||||
inputRefOfName = React.createRef();
|
||||
|
||||
state = {
|
||||
items: [],
|
||||
total: 0,
|
||||
queryParams: {
|
||||
pageIndex: 1,
|
||||
pageSize: 10,
|
||||
protocol: ''
|
||||
},
|
||||
loading: false,
|
||||
modalVisible: false,
|
||||
modalTitle: '',
|
||||
modalConfirmLoading: false,
|
||||
credentials: [],
|
||||
model: {},
|
||||
selectedRowKeys: [],
|
||||
delBtnLoading: false,
|
||||
};
|
||||
|
||||
async componentDidMount() {
|
||||
await this.loadTableData();
|
||||
}
|
||||
|
||||
async delete(id) {
|
||||
const result = await request.delete('/assets/' + id);
|
||||
if (result['code'] === 1) {
|
||||
message.success('删除成功');
|
||||
await this.loadTableData(this.state.queryParams);
|
||||
} else {
|
||||
message.error('删除失败 :( ' + result.message, 10);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async loadTableData(queryParams) {
|
||||
this.setState({
|
||||
loading: true
|
||||
});
|
||||
|
||||
queryParams = queryParams || this.state.queryParams;
|
||||
|
||||
// queryParams
|
||||
let paramsStr = qs.stringify(queryParams);
|
||||
|
||||
let data = {
|
||||
items: [],
|
||||
total: 0
|
||||
};
|
||||
|
||||
try {
|
||||
let result = await request.get('/assets/paging?' + paramsStr);
|
||||
if (result['code'] === 1) {
|
||||
data = result['data'];
|
||||
} else {
|
||||
message.error(result['message']);
|
||||
}
|
||||
} catch (e) {
|
||||
|
||||
} finally {
|
||||
const items = data.items.map(item => {
|
||||
return {'key': item['id'], ...item}
|
||||
})
|
||||
this.setState({
|
||||
items: items,
|
||||
total: data.total,
|
||||
queryParams: queryParams,
|
||||
loading: false
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
handleChangPage = async (pageIndex, pageSize) => {
|
||||
let queryParams = this.state.queryParams;
|
||||
queryParams.pageIndex = pageIndex;
|
||||
queryParams.pageSize = pageSize;
|
||||
|
||||
this.setState({
|
||||
queryParams: queryParams
|
||||
});
|
||||
|
||||
await this.loadTableData(queryParams)
|
||||
};
|
||||
|
||||
handleSearchByName = name => {
|
||||
let query = {
|
||||
...this.state.queryParams,
|
||||
'pageIndex': 1,
|
||||
'pageSize': this.state.queryParams.pageSize,
|
||||
'name': name,
|
||||
}
|
||||
|
||||
this.loadTableData(query);
|
||||
};
|
||||
|
||||
handleSearchByProtocol = protocol => {
|
||||
let query = {
|
||||
...this.state.queryParams,
|
||||
'pageIndex': 1,
|
||||
'pageSize': this.state.queryParams.pageSize,
|
||||
'protocol': protocol,
|
||||
}
|
||||
this.loadTableData(query);
|
||||
}
|
||||
|
||||
showDeleteConfirm(id, content) {
|
||||
let self = this;
|
||||
confirm({
|
||||
title: '您确定要删除此资产吗?',
|
||||
content: content,
|
||||
okText: '确定',
|
||||
okType: 'danger',
|
||||
cancelText: '取消',
|
||||
onOk() {
|
||||
self.delete(id);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
async update(id) {
|
||||
let result = await request.get(`/assets/${id}`);
|
||||
if (result.code !== 1) {
|
||||
message.error(result.message, 10);
|
||||
return;
|
||||
}
|
||||
await this.showModal('更新资产', result.data);
|
||||
}
|
||||
|
||||
async copy(id) {
|
||||
let result = await request.get(`/assets/${id}`);
|
||||
if (result.code !== 1) {
|
||||
message.error(result.message, 10);
|
||||
return;
|
||||
}
|
||||
result.data['id'] = undefined;
|
||||
await this.showModal('复制资产', result.data);
|
||||
}
|
||||
|
||||
async showModal(title, assets = {}) {
|
||||
let result = await request.get('/credentials');
|
||||
let credentials = [];
|
||||
if (result.code === 1) {
|
||||
credentials = result.data;
|
||||
}
|
||||
this.setState({
|
||||
modalTitle: title,
|
||||
modalVisible: true,
|
||||
credentials: credentials,
|
||||
model: assets
|
||||
});
|
||||
};
|
||||
|
||||
handleCancelModal = e => {
|
||||
this.setState({
|
||||
modalTitle: '',
|
||||
modalVisible: false
|
||||
});
|
||||
};
|
||||
|
||||
handleOk = async (formData) => {
|
||||
// 弹窗 form 传来的数据
|
||||
this.setState({
|
||||
modalConfirmLoading: true
|
||||
});
|
||||
|
||||
if (formData.id) {
|
||||
// 向后台提交数据
|
||||
const result = await request.put('/assets/' + formData.id, formData);
|
||||
if (result.code === 1) {
|
||||
message.success('操作成功', 3);
|
||||
|
||||
this.setState({
|
||||
modalVisible: false
|
||||
});
|
||||
await this.loadTableData(this.state.queryParams);
|
||||
} else {
|
||||
message.error('操作失败 :( ' + result.message, 10);
|
||||
}
|
||||
} else {
|
||||
// 向后台提交数据
|
||||
const result = await request.post('/assets', formData);
|
||||
if (result.code === 1) {
|
||||
message.success('操作成功', 3);
|
||||
|
||||
this.setState({
|
||||
modalVisible: false
|
||||
});
|
||||
await this.loadTableData(this.state.queryParams);
|
||||
} else {
|
||||
message.error('操作失败 :( ' + result.message, 10);
|
||||
}
|
||||
}
|
||||
|
||||
this.setState({
|
||||
modalConfirmLoading: false
|
||||
});
|
||||
};
|
||||
|
||||
access = async (id, protocol) => {
|
||||
message.loading({content: '正在检测资产是否在线...', key: id});
|
||||
let result = await request.post(`/assets/${id}/tcping`);
|
||||
if (result.code === 1) {
|
||||
if (result.data === true) {
|
||||
message.success({content: '检测完成,您访问的资产在线,即将打开窗口进行访问。', key: id, duration: 3});
|
||||
window.open(`#/access?assetsId=${id}&protocol=${protocol}`);
|
||||
} else {
|
||||
message.warn('您访问的资产未在线,请确认网络状态。', 10);
|
||||
}
|
||||
} else {
|
||||
message.error('操作失败 :( ' + result.message, 10);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
batchDelete = async () => {
|
||||
this.setState({
|
||||
delBtnLoading: true
|
||||
})
|
||||
try {
|
||||
let result = await request.delete('/assets/' + this.state.selectedRowKeys.join(','));
|
||||
if (result.code === 1) {
|
||||
message.success('操作成功', 3);
|
||||
this.setState({
|
||||
selectedRowKeys: []
|
||||
})
|
||||
await this.loadTableData(this.state.queryParams);
|
||||
} else {
|
||||
message.error('删除失败 :( ' + result.message, 10);
|
||||
}
|
||||
} finally {
|
||||
this.setState({
|
||||
delBtnLoading: false
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
const columns = [{
|
||||
title: '序号',
|
||||
dataIndex: 'id',
|
||||
key: 'id',
|
||||
render: (id, record, index) => {
|
||||
return index + 1;
|
||||
}
|
||||
}, {
|
||||
title: '资产名称',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
render: (name, record) => {
|
||||
if (name && name.length > 20) {
|
||||
name = name.substring(0, 20) + "...";
|
||||
}
|
||||
|
||||
return (
|
||||
<Tooltip placement="topLeft" title={name}>
|
||||
{name}
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
}, {
|
||||
title: 'IP',
|
||||
dataIndex: 'ip',
|
||||
key: 'ip',
|
||||
}, {
|
||||
title: '端口',
|
||||
dataIndex: 'port',
|
||||
key: 'port',
|
||||
}, {
|
||||
title: '连接协议',
|
||||
dataIndex: 'protocol',
|
||||
key: 'protocol',
|
||||
render: (text, record) => {
|
||||
|
||||
return (<Tag color={PROTOCOL_COLORS[text]}>{text}</Tag>);
|
||||
}
|
||||
}, {
|
||||
title: '状态',
|
||||
dataIndex: 'active',
|
||||
key: 'active',
|
||||
render: text => {
|
||||
if (text) {
|
||||
return (<Badge status="processing" text="运行中"/>);
|
||||
} else {
|
||||
return (<Badge status="error" text="不可用"/>);
|
||||
}
|
||||
}
|
||||
}, {
|
||||
title: '创建日期',
|
||||
dataIndex: 'created',
|
||||
key: 'created'
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
render: (text, record) => {
|
||||
return (
|
||||
<div>
|
||||
<Button type="link" size='small' icon={<CodeTwoTone/>}
|
||||
onClick={() => this.access(record.id, record.protocol)}>接入</Button>
|
||||
<Button type="link" size='small' icon={<EditTwoTone/>}
|
||||
onClick={() => this.update(record.id)}>编辑</Button>
|
||||
<Button type="link" size='small' icon={<CopyTwoTone/>}
|
||||
onClick={() => this.copy(record.id)}>复制</Button>
|
||||
<Button type="link" size='small' icon={<DeleteTwoTone/>}
|
||||
onClick={() => this.showDeleteConfirm(record.id, record.name)}>删除</Button>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
}
|
||||
];
|
||||
|
||||
const selectedRowKeys = this.state.selectedRowKeys;
|
||||
const rowSelection = {
|
||||
selectedRowKeys: this.state.selectedRowKeys,
|
||||
onChange: (selectedRowKeys, selectedRows) => {
|
||||
this.setState({selectedRowKeys});
|
||||
},
|
||||
};
|
||||
const hasSelected = selectedRowKeys.length > 0;
|
||||
|
||||
return (
|
||||
<>
|
||||
<PageHeader
|
||||
className="site-page-header-ghost-wrapper page-herder"
|
||||
title="资产管理"
|
||||
breadcrumb={{
|
||||
routes: routes,
|
||||
itemRender: itemRender
|
||||
}}
|
||||
subTitle="资产"
|
||||
>
|
||||
</PageHeader>
|
||||
|
||||
<Content key='page-content' className="site-layout-background page-content">
|
||||
<div style={{marginBottom: 20}}>
|
||||
<Row justify="space-around" align="middle" gutter={24}>
|
||||
<Col span={12} key={1}>
|
||||
<Title level={3}>资产列表</Title>
|
||||
</Col>
|
||||
<Col span={12} key={2} style={{textAlign: 'right'}}>
|
||||
<Space>
|
||||
|
||||
<Search
|
||||
ref={this.inputRefOfName}
|
||||
placeholder="资产名称"
|
||||
allowClear
|
||||
onSearch={this.handleSearchByName}
|
||||
/>
|
||||
|
||||
<Select onChange={this.handleSearchByProtocol}
|
||||
value={this.state.queryParams.protocol ? this.state.queryParams.protocol : ''}
|
||||
style={{width: 100}}>
|
||||
<Select.Option value="">全部协议</Select.Option>
|
||||
<Select.Option value="rdp">rdp</Select.Option>
|
||||
<Select.Option value="ssh">ssh</Select.Option>
|
||||
<Select.Option value="vnc">vnc</Select.Option>
|
||||
<Select.Option value="telnet">telnet</Select.Option>
|
||||
</Select>
|
||||
|
||||
<Tooltip title='重置查询'>
|
||||
|
||||
<Button icon={<UndoOutlined/>} onClick={() => {
|
||||
this.inputRefOfName.current.setValue('');
|
||||
this.loadTableData({pageIndex: 1, pageSize: 10, protocol: ''})
|
||||
}}>
|
||||
|
||||
</Button>
|
||||
</Tooltip>
|
||||
|
||||
<Divider type="vertical"/>
|
||||
|
||||
<Tooltip title="新增">
|
||||
<Button type="dashed" icon={<PlusOutlined/>}
|
||||
onClick={() => this.showModal('新增资产', {})}>
|
||||
|
||||
</Button>
|
||||
</Tooltip>
|
||||
|
||||
|
||||
<Tooltip title="刷新列表">
|
||||
<Button icon={<SyncOutlined/>} onClick={() => {
|
||||
this.loadTableData(this.state.queryParams)
|
||||
}}>
|
||||
|
||||
</Button>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip title="批量删除">
|
||||
<Button type="primary" danger disabled={!hasSelected} icon={<DeleteOutlined/>}
|
||||
loading={this.state.delBtnLoading}
|
||||
onClick={() => {
|
||||
const content = <div>
|
||||
您确定要删除选中的<Text style={{color: '#1890FF'}}
|
||||
strong>{this.state.selectedRowKeys.length}</Text>条记录吗?
|
||||
</div>;
|
||||
confirm({
|
||||
icon: <ExclamationCircleOutlined/>,
|
||||
content: content,
|
||||
onOk: () => {
|
||||
this.batchDelete()
|
||||
},
|
||||
onCancel() {
|
||||
|
||||
},
|
||||
});
|
||||
}}>
|
||||
|
||||
</Button>
|
||||
</Tooltip>
|
||||
|
||||
</Space>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
|
||||
<Table key='assets-table'
|
||||
rowSelection={rowSelection}
|
||||
dataSource={this.state.items}
|
||||
columns={columns}
|
||||
position={'both'}
|
||||
pagination={{
|
||||
showSizeChanger: true,
|
||||
current: this.state.queryParams.pageIndex,
|
||||
pageSize: this.state.queryParams.pageSize,
|
||||
onChange: this.handleChangPage,
|
||||
onShowSizeChange: this.handleChangPage,
|
||||
total: this.state.total,
|
||||
showTotal: total => `总计 ${total} 条`
|
||||
}}
|
||||
loading={this.state.loading}
|
||||
/>
|
||||
|
||||
{
|
||||
this.state.modalVisible ?
|
||||
<AssetModal
|
||||
modalFormRef={this.modalFormRef}
|
||||
visible={this.state.modalVisible}
|
||||
title={this.state.modalTitle}
|
||||
handleOk={this.handleOk}
|
||||
handleCancel={this.handleCancelModal}
|
||||
confirmLoading={this.state.modalConfirmLoading}
|
||||
credentials={this.state.credentials}
|
||||
model={this.state.model}
|
||||
/>
|
||||
: null
|
||||
}
|
||||
|
||||
</Content>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Asset;
|
Reference in New Issue
Block a user