import React, {Component} from 'react'; import { Alert, Badge, Button, Col, Divider, Dropdown, Form, Input, Layout, Menu, Modal, notification, Row, Select, Space, Table, Tag, Tooltip, Transfer, Typography } from "antd"; import qs from "qs"; import AssetModal from "./AssetModal"; import request from "../../common/request"; import {message} from "antd/es"; import {getHeaders, isEmpty} from "../../utils/utils"; import dayjs from 'dayjs'; import { DeleteOutlined, DownOutlined, ExclamationCircleOutlined, ImportOutlined, PlusOutlined, SyncOutlined, UndoOutlined, UploadOutlined } from '@ant-design/icons'; import {PROTOCOL_COLORS} from "../../common/constants"; import {hasPermission, isAdmin} from "../../service/permission"; import Upload from "antd/es/upload"; import axios from "axios"; import {server} from "../../common/env"; const confirm = Modal.confirm; const {Search} = Input; const {Content} = Layout; const {Title, Text} = Typography; class Asset extends Component { inputRefOfName = React.createRef(); inputRefOfIp = React.createRef(); changeOwnerFormRef = React.createRef(); state = { items: [], total: 0, queryParams: { pageIndex: 1, pageSize: 10, protocol: '', tags: '' }, loading: false, modalVisible: false, modalTitle: '', modalConfirmLoading: false, credentials: [], tags: [], selectedTags: [], model: {}, selectedRowKeys: [], delBtnLoading: false, changeOwnerModalVisible: false, changeSharerModalVisible: false, changeOwnerConfirmLoading: false, changeSharerConfirmLoading: false, users: [], selected: {}, selectedSharers: [], importModalVisible: false, fileList: [], uploading: false, }; async componentDidMount() { this.loadTableData(); let result = await request.get('/tags'); if (result['code'] === 1) { this.setState({ tags: result['data'] }) } } 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); }; handleSearchByIp = ip => { let query = { ...this.state.queryParams, 'pageIndex': 1, 'pageSize': this.state.queryParams.pageSize, 'ip': ip, } this.loadTableData(query); }; handleTagsChange = tags => { this.setState({ selectedTags: tags }) let query = { ...this.state.queryParams, 'pageIndex': 1, 'pageSize': this.state.queryParams.pageSize, 'tags': tags.join(','), } 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, asset = {}) { // 并行请求 let getCredentials = request.get('/credentials'); let getTags = request.get('/tags'); let credentials = []; let tags = []; let r1 = await getCredentials; let r2 = await getTags; if (r1['code'] === 1) { credentials = r1['data']; } if (r2['code'] === 1) { tags = r2['data']; } if (asset['tags'] && typeof (asset['tags']) === 'string') { if (asset['tags'] === '' || asset['tags'] === '-') { asset['tags'] = []; } else { asset['tags'] = asset['tags'].split(','); } } else { asset['tags'] = []; } asset['use-ssl'] = asset['use-ssl'] === 'true'; asset['ignore-cert'] = asset['ignore-cert'] === 'true'; console.log(asset) this.setState({ modalTitle: title, modalVisible: true, credentials: credentials, tags: tags, model: asset }); }; handleCancelModal = e => { this.setState({ modalTitle: '', modalVisible: false }); }; handleOk = async (formData) => { // 弹窗 form 传来的数据 this.setState({ modalConfirmLoading: true }); console.log(formData) if (formData['tags']) { formData.tags = formData['tags'].join(','); } 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 (record) => { const id = record['id']; const protocol = record['protocol']; const name = record['name']; const sshMode = record['sshMode']; 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}); if (protocol === 'ssh' && sshMode === 'naive') { window.open(`#/term?assetId=${id}&assetName=${name}`); } else { window.open(`#/access?assetId=${id}&assetName=${name}&protocol=${protocol}`); } } else { message.warn({content: '您访问的资产未在线,请确认网络状态。', key: id, duration: 10}); } } else { message.error({content: result.message, key: id, duration: 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 }) } } handleSearchByNickname = async nickname => { const result = await request.get(`/users/paging?pageIndex=1&pageSize=100&nickname=${nickname}`); if (result.code !== 1) { message.error(result.message, 10); return; } const items = result['data']['items'].map(item => { return {'key': item['id'], ...item} }) this.setState({ users: items }) } handleSharersChange = async targetKeys => { this.setState({ selectedSharers: targetKeys }) } handleShowSharer = async (record) => { let r1 = this.handleSearchByNickname(''); let r2 = request.get(`/resource-sharers/sharers?resourceId=${record['id']}`); await r1; let result = await r2; let selectedSharers = []; if (result['code'] !== 1) { message.error(result['message']); } else { selectedSharers = result['data']; } let users = this.state.users; users = users.map(item => { let disabled = false; if (record['owner'] === item['id']) { disabled = true; } return {...item, 'disabled': disabled} }); this.setState({ selectedSharers: selectedSharers, selected: record, changeSharerModalVisible: true, users: users }) } handleCancelUpdateAttr = () => { this.setState({ attrVisible: false, selected: {}, attributes: {} }); } handleTableChange = (pagination, filters, sorter) => { let query = { ...this.state.queryParams, 'order': sorter.order, 'field': sorter.field } this.loadTableData(query); } render() { const columns = [{ title: '序号', dataIndex: 'id', key: 'id', render: (id, record, index) => { return index + 1; } }, { title: '资产名称', dataIndex: 'name', key: 'name', render: (name, record) => { let short = name; if (short && short.length > 20) { short = short.substring(0, 20) + " ..."; } return ( {short} ); }, sorter: true, }, { title: '连接协议', dataIndex: 'protocol', key: 'protocol', render: (text, record) => { const title = `${record['ip'] + ':' + record['port']}` return ( {text} ) } }, { title: '标签', dataIndex: 'tags', key: 'tags', render: tags => { if (!isEmpty(tags)) { let tagDocuments = [] let tagArr = tags.split(','); for (let i = 0; i < tagArr.length; i++) { if (tags[i] === '-') { continue; } tagDocuments.push({tagArr[i]}) } return tagDocuments; } } }, { title: '状态', dataIndex: 'active', key: 'active', render: text => { if (text) { return ( ) } else { return ( ) } } }, { title: '所有者', dataIndex: 'ownerName', key: 'ownerName' }, { title: '创建日期', dataIndex: 'created', key: 'created', render: (text, record) => { return ( {dayjs(text).fromNow()} ) }, sorter: true, }, { title: '操作', key: 'action', render: (text, record) => { const menu = ( {isAdmin() ? : undefined } ); return (
) }, } ]; if (isAdmin()) { columns.splice(6, 0, { title: '授权人数', dataIndex: 'sharerCount', key: 'sharerCount', render: (text, record, index) => { return } }); } const selectedRowKeys = this.state.selectedRowKeys; const rowSelection = { selectedRowKeys: this.state.selectedRowKeys, onChange: (selectedRowKeys, selectedRows) => { this.setState({selectedRowKeys}); }, }; const hasSelected = selectedRowKeys.length > 0; return ( <>
资产列表 {isAdmin() ? : undefined }
`总计 ${total} 条` }} loading={this.state.loading} onChange={this.handleTableChange} /> { this.state.modalVisible ? : null } { this.state.importModalVisible ? { const formData = new FormData(); formData.append("file", this.state.fileList[0]); let headers = getHeaders(); headers['Content-Type'] = 'multipart/form-data'; axios .post(server + "/assets/import", formData, { headers: headers }) .then((resp) => { console.log("上传成功", resp); this.setState({ importModalVisible: false }) let result = resp.data; if (result['code'] === 1) { let data = result['data']; let successCount = data['successCount']; let errorCount = data['errorCount']; if (errorCount === 0) { notification['success']({ message: '导入资产成功', description: '共导入成功' + successCount + '条资产。', }); } else { notification['info']({ message: '导入资产完成', description: `共导入成功${successCount}条资产,失败${errorCount}条资产。`, }); } } else { notification['error']({ message: '导入资产失败', description: result['message'], }); } this.loadTableData(); }); }} onCancel={() => { this.setState({ importModalVisible: false }) }} okButtonProps={{ disabled: this.state.fileList.length === 0 }} > { this.setState(state => { const index = state.fileList.indexOf(file); const newFileList = state.fileList.slice(); newFileList.splice(index, 1); return { fileList: newFileList, }; }); }} beforeUpload={(file) => { this.setState(state => ({ fileList: [file], })); return false; }} fileList={this.state.fileList} > : undefined } 更换资源「{this.state.selected['name']}」的所有者 } visible={this.state.changeOwnerModalVisible} confirmLoading={this.state.changeOwnerConfirmLoading} onOk={() => { this.setState({ changeOwnerConfirmLoading: true }); let changeOwnerModalVisible = false; this.changeOwnerFormRef .current .validateFields() .then(async values => { let result = await request.post(`/assets/${this.state.selected['id']}/change-owner?owner=${values['owner']}`); if (result['code'] === 1) { message.success('操作成功'); this.loadTableData(); } else { message.error(result['message'], 10); changeOwnerModalVisible = true; } }) .catch(info => { }) .finally(() => { this.setState({ changeOwnerConfirmLoading: false, changeOwnerModalVisible: changeOwnerModalVisible }) }); }} onCancel={() => { this.setState({ changeOwnerModalVisible: false }) }} >
{ this.state.changeSharerModalVisible ? 更新资源「{this.state.selected['name']}」的授权人 } visible={this.state.changeSharerModalVisible} confirmLoading={this.state.changeSharerConfirmLoading} onOk={async () => { this.setState({ changeSharerConfirmLoading: true }); let changeSharerModalVisible = false; let result = await request.post(`/resource-sharers/overwrite-sharers`, { resourceId: this.state.selected['id'], resourceType: 'asset', userIds: this.state.selectedSharers }); if (result['code'] === 1) { message.success('操作成功'); this.loadTableData(); } else { message.error(result['message'], 10); changeSharerModalVisible = true; } this.setState({ changeSharerConfirmLoading: false, changeSharerModalVisible: changeSharerModalVisible }) }} onCancel={() => { this.setState({ changeSharerModalVisible: false }) }} okButtonProps={{disabled: !hasPermission(this.state.selected['owner'])}} > `${item.nickname}`} /> : undefined } ); } } export default Asset;