Browse Source

数据连接 界面设计/数据源详情界面调整

zhuth 6 years ago
parent
commit
2ba72df38c

+ 3 - 0
src/components/common/navigator.jsx

@@ -56,6 +56,9 @@ class Navigator extends React.Component {
                     <Menu.Item className='nav-page' key="home">
                         <Link to='/home'><Icon type="home" />我的</Link>
                     </Menu.Item>
+                    <Menu.Item className='nav-page' key="dataconnect">
+                        <Link to='/dataconnect'><Icon type="link" />数据连接</Link>
+                    </Menu.Item>
                     <Menu.Item className='nav-page' key="datasource">
                         <Link to='/datasource'><Icon type="database" />数据源</Link>
                     </Menu.Item>

+ 245 - 0
src/components/dataConnect/list.jsx

@@ -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)

+ 174 - 0
src/components/dataConnect/list.less

@@ -0,0 +1,174 @@
+.dataconnect-view {
+    .dataconnect-body {
+        padding: 0;
+        .ant-card-head {
+            padding: 0 10px;
+            .dataconnect-tools {
+                flex: 1;
+                .anticon-bars {
+                    cursor: pointer;
+                    line-height: 1.6;
+                    font-size: 20px;
+                    margin-right: 6px;
+                    &> svg {
+                        height: 100%;
+                    }
+                }
+                .group {
+                    line-height: 2.1;
+                    .ant-breadcrumb-link {
+                        .ant-tag {
+                            margin: 0;
+                        }
+                    }
+                }
+                .search {
+                    display: flex;
+                    > div:first-child {
+                        margin-right: 5px;
+                    }
+                }
+            }
+        }
+    }
+    .ant-card-body {
+        padding: 0;
+        .dataconnect-table{
+            .ant-table {
+                .ant-table-scroll {
+                    .ant-table-header {
+                        overflow: hidden;
+                        table {
+                            thead {
+                                th {
+                                    .ant-table-column-sorter, .ant-table-filter-icon {
+                                        opacity: 0;
+                                    }
+                                    :hover {
+                                        .ant-table-column-sorter, .ant-table-filter-icon {
+                                            opacity: 1;
+                                        }
+                                    }
+                                }
+                                .column-filtered {
+                                    .ant-table-filter-icon {
+                                        opacity: 1;
+                                        color: red;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                    .ant-table-body {
+                        margin-top: 17px;
+                        overflow-y: auto !important;
+                        table {
+                            padding: 0;
+                            .ant-table-row {
+                                td {
+                                    padding: 8px;
+                                    .dataconnect-name {
+                                        display: flex;
+                                        .dataconnect-type {
+                                            margin-right: 5px;
+                                        }
+                                    }
+                                    .dataconnect-tag {
+                                        margin: 2px;
+                                        cursor: default;
+                                    }
+                                    .ant-dropdown-trigger {
+                                        font-size: 18px;
+                                        cursor: pointer;
+                                    }
+                                }
+                                .action-col {
+                                    display: flex;
+                                    .operation {
+                                        cursor: pointer;
+                                    }
+                                    .operation:hover {
+                                        color: #40a9ff;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+.popover-group {
+    width: 300px;
+    .grouptree-title {
+        .create-group {
+            cursor: pointer;
+            color: #40a9ff;
+        }
+    }
+    .ant-popover-inner-content {
+        cursor: default;
+        max-height: 60vh;
+        overflow: auto;
+    }
+    .tree-group {
+        li.drag-over {
+            input {
+                background-color: #40a9ff;
+            }
+        }
+        li {
+            .ant-tree-node-content-wrapper {
+                width: 90%;
+                height: 28px;
+                margin: 0 !important;
+                padding: 0;
+                background-color: transparent;
+
+                :hover {
+                    background-color: transparent !important;
+                }
+                .ant-tree-node-selected {
+                    background-color: transparent !important;
+                }
+                input {
+                    max-width: 180px;
+                    border: none;
+                }
+                .anticon-plus-circle-o {
+                    margin-left: 5px;
+                }
+                .anticon-minus-circle {
+                    margin-left: 5px;
+                }
+            }
+            .drag-over {
+                span[draggable] {
+                    opacity: .7;
+                }
+            }
+        }
+    }
+}
+.tree-group li.drag-over > span[draggable] {
+    opacity: .5;
+}
+
+.operationmenu {
+    padding: 0;
+    width: 120px;
+    .ant-dropdown-menu-item {
+        .anticon {
+            margin-right: 6px;
+        }
+    }
+    .ant-dropdown-menu-item-divider {
+        margin: 0;
+    }
+    .setgroupmenu {
+        .ant-dropdown-menu-submenu-title {
+            display: flex;
+        }
+    }
+}

+ 2 - 2
src/components/dataSource/list.jsx

@@ -437,8 +437,8 @@ class DataSource extends React.Component {
                                             dispatch({ type: 'dataSource/setNewModelField', name: 'type', value: type });
                                             dispatch({type: 'main/redirect', path: {pathname: '/datasource/'+ type +'/create/base'}});
                                         }}>
-                                            { currentUser.role === 'admin' && <Menu.Item key='database'>数据库</Menu.Item>}
-                                            <Menu.Item disabled key='file'>文件</Menu.Item>
+                                            { currentUser.role === 'admin' && <Menu.Item key='database'>来自数据库</Menu.Item>}
+                                            <Menu.Item disabled key='file'>来自文件</Menu.Item>
                                         </Menu>
                                     )} trigger={['click']}>
                                         <Button>

+ 1 - 1
src/components/dataSourceDetail/columnConfig.jsx

@@ -290,7 +290,7 @@ class DataSourceColumnConfig extends React.Component {
                                 <FormItem className='textarea-target'>
                                     <Input.TextArea
                                         disabled={!dataSourceDetail.address}
-                                        placeholder={dataSourceDetail.address ? '输入表名或查询SQL,注意不能以分号结尾' : '请返回上一步选择数据库连接'}
+                                        placeholder={dataSourceDetail.address ? '输入表名或查询SQL,注意不能以分号结尾' : '请点击底部“上一步”按钮返回上一步选择数据库连接'}
                                         autosize={{ minRows: 3 }}
                                         value={dataSourceDetail.target}
                                         onChange={(e) => {

+ 8 - 3
src/components/dataSourceDetail/content.less

@@ -86,9 +86,13 @@
                                     display: flex;
                                     flex-direction: column;
                                     .ant-card-head {
+                                        min-height: 32px;
                                         background: #F5F5F5;
+                                        padding: 0;
                                         .ant-card-head-wrapper {
+                                            height: 100%;
                                             .ant-card-head-title {
+                                                padding: 0 16px;
                                                 .ant-row-flex {
                                                     .label {
                                                         overflow: hidden;
@@ -98,9 +102,10 @@
                                             }
                                         }
                                         .selected {
-                                            width: 60px;
-                                            height: 60px;
-                                            background-size: cover;
+                                            width: 32px;
+                                            height: 32px;
+                                            background-repeat: no-repeat;
+                                            background-size: 32px;
                                             background-image: url(/images/selected.png);
                                             position: absolute;
                                             right: 0px;

+ 29 - 15
src/components/dataSourceDetail/dataConnectBox.jsx

@@ -24,6 +24,8 @@ class DataConnectBox extends React.Component {
 
     render() {
         const { dispatch, dataConnect } = this.props;
+        const operation = dataConnect.newOne.boxOperation;
+        const disabled = operation === 'view';
 
         const formItemLayout = {
             labelCol: { span: 4 },
@@ -33,29 +35,33 @@ class DataConnectBox extends React.Component {
         return (
             <Modal
                 className='dataconnect-box'
-                title={<Row type='flex' justify='space-between'><Col>{`${dataConnect.newOne.boxOperation === 'create'?'新建':'修改'}数据库连接`}</Col><Col style={{ marginRight: '35px', fontSize: '14px', cursor: 'pointer', color: 'red' }} onClick={() => {
+                title={<Row type='flex' justify='space-between'><Col>{`${operation === 'create'?'新建':(operation === 'modify' ? '修改' : '查看')}数据库连接`}</Col><Col style={{ marginRight: '35px', fontSize: '14px', cursor: 'pointer', color: 'red' }} onClick={() => {
                     // 密码input特殊处理
                     document.getElementsByClassName('password')[0].value = '';
                     dispatch({ type:'dataConnect/resetNewModel'})
-                }}><Icon type='delete' />清空</Col></Row>}
+                }}>
+                    {/* <Icon type='delete' />清空 */}
+                </Col></Row>}
                 visible={dataConnect.newOne.visibleBox}
                 onCancel={() => { this.hideBox() }}
                 maskClosable={false}
                 destroyOnClose={true}
                 footer={
-                    <Row>
-                        <Col className='validatemessage' span={12}>
-                            {dataConnect.newOne.invalid !== undefined ? (dataConnect.newOne.invalid ? <span style={{ color: '#F5222D' }}>数据连接配置有误</span> : <span style={{ color: '#52C41A' }}>测试通过</span>) : ''}
-                        </Col>
-                        <Col span={12}>
-                            <Button disabled={dataConnect.newOne.validating} onClick={() => dispatch({ type:'dataConnect/remoteValidate'})}>测试</Button>
-                            {/* <Button onClick={() => dispatch({ type:'dataConnect/resetNewModel'})}>清空</Button> */}
-                            <Button onClick={() => {this.hideBox()}}>取 消</Button>
-                            <Button className={dataConnect.newOne.validating ? 'ant-btn-loading' : ''} type="primary" onClick={() => {this.okHandler()}}>
-                                {dataConnect.newOne.validating ? (<Icon type='loading' />) : ''}{dataConnect.newOne.validating ? '校验中' : '保存'}
-                            </Button>
-                        </Col>
-                    </Row>
+                    operation === 'view' ? null : (
+                        <Row>
+                            <Col className='validatemessage' span={12}>
+                                {dataConnect.newOne.invalid !== undefined ? (dataConnect.newOne.invalid ? <span style={{ color: '#F5222D' }}>数据连接配置有误</span> : <span style={{ color: '#52C41A' }}>测试通过</span>) : ''}
+                            </Col>
+                            <Col span={12}>
+                                <Button disabled={dataConnect.newOne.validating} onClick={() => dispatch({ type:'dataConnect/remoteValidate'})}>
+                                {dataConnect.newOne.validating ? (<Icon type='loading' />) : ''}{dataConnect.newOne.validating ? '测试中' : '测试'}
+                                </Button>
+                                <Button onClick={() => dispatch({ type:'dataConnect/resetNewModel'})}>清空</Button>
+                                {/* <Button onClick={() => {this.hideBox()}}>取 消</Button> */}
+                                <Button className={dataConnect.newOne.validating ? 'ant-btn-loading' : ''} type="primary" disabled={dataConnect.newOne.validating} onClick={() => {this.okHandler()}}>保存</Button>
+                            </Col>
+                        </Row>
+                    )
                 }
             >
                 <Form size='small'>
@@ -66,6 +72,7 @@ class DataConnectBox extends React.Component {
                         help={dataConnect.validInfo.name ? dataConnect.validInfo.name.help : ''}
                     >
                         <Input
+                            disabled={disabled}
                             placeholder="输入数据库连接名称"
                             value={dataConnect.newOne.name}
                             onChange={(e) => { dispatch({ type: 'dataConnect/setNewModelField', name: 'name', value: e.target.value }) }}
@@ -74,6 +81,7 @@ class DataConnectBox extends React.Component {
                     </FormItem>
                     <FormItem label='数据库类型' {...formItemLayout}>
                         <Select
+                            disabled={disabled}
                             placeholder="选择数据库类型"
                             value={dataConnect.newOne.dbType}
                             onChange={(value) => {
@@ -101,6 +109,7 @@ class DataConnectBox extends React.Component {
                                 wrapperCol: { span: 19 }
                             }}>
                                 <Input
+                                    disabled={disabled}
                                     placeholder="格式:192.168.1.1"
                                     value={dataConnect.newOne.address}
                                     onChange={(e) => {
@@ -115,6 +124,7 @@ class DataConnectBox extends React.Component {
                                 wrapperCol: { span: 12 }
                             }}>
                                 <InputNumber
+                                    disabled={disabled}
                                     value={dataConnect.newOne.port}
                                     onChange={(value) => {
                                         dispatch({ type: 'dataConnect/setNewModelField', name: 'port', value: value });
@@ -125,6 +135,7 @@ class DataConnectBox extends React.Component {
                     </Row>
                     <FormItem label='数据库名(SID)' {...formItemLayout}>
                         <Input
+                            disabled={disabled}
                             value={dataConnect.newOne.dbName}
                             onChange={(e) => {
                                 dispatch({ type: 'dataConnect/setNewModelField', name: 'dbName', value: e.target.value });
@@ -138,6 +149,7 @@ class DataConnectBox extends React.Component {
                                 wrapperCol: { span: 16 }
                             }}>
                                 <Input
+                                    disabled={disabled}
                                     value={dataConnect.newOne.userName}
                                     onChange={(e) => {
                                         dispatch({ type: 'dataConnect/setNewModelField', name: 'userName', value: e.target.value });
@@ -151,6 +163,7 @@ class DataConnectBox extends React.Component {
                                 wrapperCol: { span: 16 }
                             }}>
                                 <Input
+                                    disabled={disabled}
                                     className='password'
                                     type='password'
                                     // value={dataConnect.newOne.password}
@@ -163,6 +176,7 @@ class DataConnectBox extends React.Component {
                     </Row>
                     <FormItem className='textarea-desc' label='说明' {...formItemLayout}>
                         <Input.TextArea
+                            disabled={disabled}
                             autosize={{ minRows: 2 }}
                             value={dataConnect.newOne.description}
                             onChange={(e) => {

+ 31 - 21
src/components/dataSourceDetail/dataConnectConfig.jsx

@@ -27,15 +27,10 @@ class DataConnectConfig extends React.Component {
                         dispatch({ type: 'dataConnect/setNewModel', model: dataConnect.selected });
                         dispatch({ type: 'dataConnect/setNewModelFields', fields: [
                             { name: 'visibleBox', value: true },
-                            { name: 'boxOperation', value: 'modify' }
+                            { name: 'boxOperation', value: 'view' }
                         ] });
                     }}>
-                        <Icon type='edit'/>编辑
-                    </Menu.Item>
-                    <Menu.Item onClick={(e) => {
-                        dispatch({ type: 'dataConnect/remoteDelete', code: dataConnect.selected.code });
-                    }}>
-                        <Icon type='delete'/>删除
+                        <Icon type='edit'/>详情
                     </Menu.Item>
                 </Menu>
             )
@@ -48,7 +43,18 @@ class DataConnectConfig extends React.Component {
                     <Card
                         title={
                             <Row type='flex' justify='start'>
-                                <Col className='label'>{l.name}</Col>
+                                <Col className='label'>
+                                    { filterLabel ?
+                                        ((l.name || '').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
+                                            )
+                                        }
+                                        )) : l.name
+                                    }
+                                </Col>
                                 <div style={{ display: (dataConnect.selected && dataConnect.selected.code === l.code) ? 'block' : 'none' }} className='selected'></div>
                             </Row>
                         }
@@ -88,19 +94,23 @@ class DataConnectConfig extends React.Component {
                 </CardGrid>
             ))
 
-            cards.unshift(
-                <CardGrid className='dataconnect-card dataconnect-card-create' key='create' onClick={() => {
-                    dispatch({ type: 'dataConnect/setNewModel', model: {} });
-                    dispatch({ type: 'dataConnect/setNewModelFields', fields: [
-                        { name: 'visibleBox', value: true },
-                        { name: 'boxOperation', value: 'create' }
-                    ] });
-                }}>
-                    <Card>
-                        <Icon type="plus-circle-o" />
-                    </Card>
-                </CardGrid>
-            );
+            // cards.unshift(
+            //     <CardGrid className='dataconnect-card dataconnect-card-create' key='create' onClick={() => {
+            //         dispatch({ type: 'dataConnect/setNewModel', model: { dbType: 'oracle' } });
+            //         dispatch({ type: 'dataConnect/setNewModelFields', fields: [
+            //             { name: 'visibleBox', value: true },
+            //             { name: 'boxOperation', value: 'create' }
+            //         ] });
+            //     }}>
+            //         <Card>
+            //             <Icon type="plus-circle-o" />
+            //         </Card>
+            //     </CardGrid>
+            // );
+
+            if(cards.length === 0) {
+                return (<div class="ant-empty ant-empty-normal"><div class="ant-empty-image"><img alt="暂无数据" src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNjQiIGhlaWdodD0iNDEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAxKSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj4KICAgIDxlbGxpcHNlIGZpbGw9IiNGNUY1RjUiIGN4PSIzMiIgY3k9IjMzIiByeD0iMzIiIHJ5PSI3Ii8+CiAgICA8ZyBmaWxsLXJ1bGU9Im5vbnplcm8iIHN0cm9rZT0iI0Q5RDlEOSI+CiAgICAgIDxwYXRoIGQ9Ik01NSAxMi43Nkw0NC44NTQgMS4yNThDNDQuMzY3LjQ3NCA0My42NTYgMCA0Mi45MDcgMEgyMS4wOTNjLS43NDkgMC0xLjQ2LjQ3NC0xLjk0NyAxLjI1N0w5IDEyLjc2MVYyMmg0NnYtOS4yNHoiLz4KICAgICAgPHBhdGggZD0iTTQxLjYxMyAxNS45MzFjMC0xLjYwNS45OTQtMi45MyAyLjIyNy0yLjkzMUg1NXYxOC4xMzdDNTUgMzMuMjYgNTMuNjggMzUgNTIuMDUgMzVoLTQwLjFDMTAuMzIgMzUgOSAzMy4yNTkgOSAzMS4xMzdWMTNoMTEuMTZjMS4yMzMgMCAyLjIyNyAxLjMyMyAyLjIyNyAyLjkyOHYuMDIyYzAgMS42MDUgMS4wMDUgMi45MDEgMi4yMzcgMi45MDFoMTQuNzUyYzEuMjMyIDAgMi4yMzctMS4zMDggMi4yMzctMi45MTN2LS4wMDd6IiBmaWxsPSIjRkFGQUZBIi8+CiAgICA8L2c+CiAgPC9nPgo8L3N2Zz4K"/></div><p class="ant-empty-description">暂无数据</p></div>)
+            }
             
             return cards;
         }

+ 4 - 0
src/custom.less

@@ -15,3 +15,7 @@
 .ant-dropdown-menu {
     padding: 0;
 }
+
+.ant-input[disabled],.ant-select-disabled,.ant-input-number-disabled {
+    color: rgba(0, 0, 0, 0.5);
+}

+ 2 - 0
src/routes/mainLayout.jsx

@@ -4,6 +4,7 @@ import { Route, Switch } from 'dva/router'
 import Navigator from '../components/common/navigator'
 import HomePage from '../components/homePage/homePage'
 import Loading from '../components/common/loading/loading'
+import DataConnect from '../components/dataConnect/list'
 import DataSource from '../components/dataSource/list'
 import Dashboard from '../components/dashboard/list'
 import Chart from '../components/chart/list'
@@ -24,6 +25,7 @@ const MainLayout = ({ isAuthenticated }) => {
                 <Switch>
                     <Route sensitive path='/demo' component={Demo}/>
                     <Route sensitive path='/home' component={HomePage}/>
+                    <Route sensitive path='/dataconnect' component={DataConnect}/>
                     <Route sensitive path='/datasource' component={DataSource}/>
                     <Route sensitive path='/dashboard' component={Dashboard} />
                     <Route sensitive path='/chart' component={Chart} />