512 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			512 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
import React, {Component} from 'react';
 | 
						||
 | 
						||
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;
 |