|
|
@@ -0,0 +1,245 @@
|
|
|
+import React from 'react'
|
|
|
+import { Layout, Row, Col, Input, Button, Table, Icon, Menu, Dropdown, Card } from 'antd'
|
|
|
+import { connect } from 'dva'
|
|
|
+import DeleteBox from '../common/deleteBox/deleteBox'
|
|
|
+import DataConnectBox from '../dataSourceDetail/dataConnectBox'
|
|
|
+import './list.less'
|
|
|
+const { Content } = Layout
|
|
|
+const { Search } = Input
|
|
|
+
|
|
|
+class DataConnect extends React.Component {
|
|
|
+ constructor(props) {
|
|
|
+ super(props);
|
|
|
+ this.state = {
|
|
|
+ selectedRecord: null, // 当前选中的dataSource
|
|
|
+ visibleDeleteBox: false,
|
|
|
+ }
|
|
|
+ };
|
|
|
+ componentDidMount() {
|
|
|
+ const { dispatch } = this.props;
|
|
|
+ this.setScrollTableHeight();
|
|
|
+ dispatch({ type: 'dataConnect/fetchList' });
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据视图设置表格高度以呈现滚动条
|
|
|
+ */
|
|
|
+ setScrollTableHeight() {
|
|
|
+ const mainContent = document.getElementsByClassName('main-content')[0];
|
|
|
+ const toolbar = mainContent.getElementsByClassName('dataconnect-tools')[0];
|
|
|
+ const tableHeader = mainContent.getElementsByClassName('ant-table-header')[0];
|
|
|
+ const tableBody = mainContent.getElementsByClassName('ant-table-body')[0];
|
|
|
+ tableBody.style.maxHeight=`${mainContent.offsetHeight - toolbar.offsetHeight - tableHeader.offsetHeight - 58}px`;
|
|
|
+ }
|
|
|
+
|
|
|
+ onSearch(list, text) {
|
|
|
+ const reg = new RegExp('([+ \\- & | ! ( ) { } \\[ \\] ^ \" ~ * ? : ( ) \/])', 'g'); // 需要转义的字符
|
|
|
+ let filterLabel = (text || '').replace(new RegExp('(\\\\)', 'g'), '\\$1').replace(reg, '\\$1'); // 添加转义符号
|
|
|
+ return list.map(l => {
|
|
|
+ let o = Object.assign({}, l);
|
|
|
+ let reg = new RegExp('('+ filterLabel +'){1}', 'ig');
|
|
|
+ if(o.name && o.name.search(reg) !== -1) {
|
|
|
+ return o;
|
|
|
+ }else if(o.description && o.description.search(reg) !== -1) {
|
|
|
+ return o;
|
|
|
+ }else {
|
|
|
+ return null
|
|
|
+ }
|
|
|
+ }).filter(a => a!==null);
|
|
|
+ }
|
|
|
+
|
|
|
+ onSort(list) {
|
|
|
+ return list.sort((a, b) => {
|
|
|
+ return new Date(b.createDate) - new Date(a.createDate);
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ handleVisibleChange = (flag) => {
|
|
|
+ this.setState({ visibleGroupMenu: flag });
|
|
|
+ }
|
|
|
+
|
|
|
+ render() {
|
|
|
+
|
|
|
+ const { dataConnect, dispatch } = this.props;
|
|
|
+ const { selectedRecord, visibleDeleteBox } = this.state;
|
|
|
+
|
|
|
+ const reg = new RegExp('([+ \\- & | ! ( ) { } \\[ \\] ^ \" ~ * ? : ( ) \/])', 'g'); // 需要转义的字符
|
|
|
+ let filterLabel = dataConnect.filterLabel.replace(new RegExp('(\\\\)', 'g'), '\\$1').replace(reg, '\\$1'); // 添加转义符号
|
|
|
+
|
|
|
+ const moreOperatingMenu = (
|
|
|
+ <Menu className='operationmenu' visible={true}>
|
|
|
+ {selectedRecord && <Menu.Item onClick={(e) => {
|
|
|
+ dispatch({ type: 'dataConnect/setNewModel', model: selectedRecord });
|
|
|
+ dispatch({ type: 'dataConnect/setNewModelFields', fields: [
|
|
|
+ { name: 'visibleBox', value: true },
|
|
|
+ { name: 'boxOperation', value: 'modify' }
|
|
|
+ ] });
|
|
|
+ }}>
|
|
|
+ <Icon type="info-circle-o" />属性设置
|
|
|
+ </Menu.Item>}
|
|
|
+ <Menu.Divider />
|
|
|
+ { selectedRecord && <Menu.Item
|
|
|
+ onClick={(e) => {
|
|
|
+ this.setState({ visibleDeleteBox: true})
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <Icon type="delete" />删除
|
|
|
+ </Menu.Item>}
|
|
|
+ </Menu>
|
|
|
+ );
|
|
|
+ const dataConnectColumns = [{
|
|
|
+ title: '连接名',
|
|
|
+ dataIndex: 'name',
|
|
|
+ key: 'name',
|
|
|
+ width: 200,
|
|
|
+ render: (text, record) => {
|
|
|
+ return <div className='dataconnect-name'>
|
|
|
+ <div>
|
|
|
+ <span>
|
|
|
+ { filterLabel ?
|
|
|
+ ((text || '').split(new RegExp(`(${filterLabel})`, 'i')).map((fragment, i) => {
|
|
|
+ return (
|
|
|
+ fragment.toLowerCase().replace(new RegExp('(\\\\)', 'g'), '\\$1').replace(reg, '\\$1') === filterLabel.toLowerCase() ?
|
|
|
+ <span key={i} style={{fontWeight: 'bold', color: 'red'}} className="highlight">{fragment}</span> :
|
|
|
+ fragment
|
|
|
+ )
|
|
|
+ }
|
|
|
+ )) : text
|
|
|
+ }
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ }
|
|
|
+ }, {
|
|
|
+ title: '数据库类型',
|
|
|
+ dataIndex: 'dbType',
|
|
|
+ key: 'dbType',
|
|
|
+ width: 120
|
|
|
+ }, {
|
|
|
+ title: '数据库地址',
|
|
|
+ dataIndex: 'address',
|
|
|
+ key: 'address',
|
|
|
+ width: 120
|
|
|
+ }, {
|
|
|
+ title: '端口',
|
|
|
+ dataIndex: 'port',
|
|
|
+ key: 'port',
|
|
|
+ width: 100
|
|
|
+ }, {
|
|
|
+ title: '数据库名',
|
|
|
+ dataIndex: 'dbName',
|
|
|
+ key: 'dbName',
|
|
|
+ width: 100
|
|
|
+ }, {
|
|
|
+ title: '用户名',
|
|
|
+ dataIndex: 'userName',
|
|
|
+ key: 'userName',
|
|
|
+ width: 150
|
|
|
+ }, {
|
|
|
+ title: '说明',
|
|
|
+ dataIndex: 'description',
|
|
|
+ key: 'description',
|
|
|
+ render: (text, record) => {
|
|
|
+ return <div className='dataconnect-name'>
|
|
|
+ <div>
|
|
|
+ <span>
|
|
|
+ { filterLabel ?
|
|
|
+ ((text || '').split(new RegExp(`(${filterLabel})`, 'i')).map((fragment, i) => {
|
|
|
+ return (
|
|
|
+ fragment.toLowerCase().replace(new RegExp('(\\\\)', 'g'), '\\$1').replace(reg, '\\$1') === filterLabel.toLowerCase() ?
|
|
|
+ <span key={i} style={{fontWeight: 'bold', color: 'red'}} className="highlight">{fragment}</span> :
|
|
|
+ fragment
|
|
|
+ )
|
|
|
+ }
|
|
|
+ )) : text
|
|
|
+ }
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ }
|
|
|
+ }, {
|
|
|
+ title: '操作',
|
|
|
+ key: 'action',
|
|
|
+ render: (text, record, index) => (
|
|
|
+ <Dropdown code={record.code} overlay={moreOperatingMenu} trigger={['click']} >
|
|
|
+ <Icon type="setting" />
|
|
|
+ </Dropdown>
|
|
|
+ ),
|
|
|
+ width: 50
|
|
|
+ }];
|
|
|
+
|
|
|
+ return (
|
|
|
+ <Layout className='dataconnect-view'>
|
|
|
+ <Content>
|
|
|
+ <Card className='dataconnect-body' title={
|
|
|
+ <Row className='dataconnect-tools' type='flex' justify='space-between'>
|
|
|
+ <Col style={{ display: 'flex' }}>
|
|
|
+ </Col>
|
|
|
+ <Col className='search'>
|
|
|
+ <Col>
|
|
|
+ <Search
|
|
|
+ value={dataConnect.filterLabel}
|
|
|
+ placeholder="请输入关键字"
|
|
|
+ onChange={e => {
|
|
|
+ dispatch({ type: 'dataConnect/setFilterLabel', label: e.target.value });
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ </Col>
|
|
|
+ <Col>
|
|
|
+ <Button onClick={() => {
|
|
|
+ dispatch({ type: 'dataConnect/setNewModel', model: { dbType: 'oracle' } });
|
|
|
+ dispatch({ type: 'dataConnect/setNewModelFields', fields: [
|
|
|
+ { name: 'visibleBox', value: true },
|
|
|
+ { name: 'boxOperation', value: 'create' }
|
|
|
+ ] });
|
|
|
+ }}>
|
|
|
+ <Icon type="plus" />添加数据连接
|
|
|
+ </Button>
|
|
|
+ </Col>
|
|
|
+ </Col>
|
|
|
+ </Row>
|
|
|
+ }>
|
|
|
+ <Table
|
|
|
+ className='dataconnect-table'
|
|
|
+ columns={dataConnectColumns}
|
|
|
+ dataSource={
|
|
|
+ this.onSort(
|
|
|
+ this.onSearch(dataConnect.list, dataConnect.filterLabel)
|
|
|
+ )
|
|
|
+ }
|
|
|
+ size='small'
|
|
|
+ scroll={{x: false, y: true}}
|
|
|
+ pagination={false}
|
|
|
+ onRow={(record) => {
|
|
|
+ return {
|
|
|
+ onClick: () => {this.setState({ selectedRecord: record})}
|
|
|
+ }
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ {visibleDeleteBox && <DeleteBox
|
|
|
+ visibleBox={visibleDeleteBox}
|
|
|
+ text={<div><span>确定要删除数据连接【{selectedRecord.name}】吗?</span></div>}
|
|
|
+ hideBox={() => {
|
|
|
+ this.setState({
|
|
|
+ visibleDeleteBox: false
|
|
|
+ })
|
|
|
+ }}
|
|
|
+ okHandler={() =>{
|
|
|
+ dispatch({ type: 'dataConnect/remoteDelete', code: selectedRecord.code })
|
|
|
+ }}
|
|
|
+ />}
|
|
|
+ <DataConnectBox />
|
|
|
+ </Card>
|
|
|
+ </Content>
|
|
|
+ </Layout>
|
|
|
+ )
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function mapStateToProps({present: {dataConnect}}) {
|
|
|
+ return { dataConnect }
|
|
|
+}
|
|
|
+
|
|
|
+export default connect(mapStateToProps)(DataConnect)
|