| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299 |
- import React from 'react'
- import { Layout, Row, Col, Button, Icon, Card, Select, Menu, Dropdown } from 'antd'
- import { connect } from 'dva'
- import DeleteBox from '../common/deleteBox/deleteBox'
- import EmptyContent from '../common/emptyContent/index'
- import DataConnectBox from '../dataSourceDetail/dataConnectBox'
- import ListFilter from '../common/listFilter/index'
- import CusIcon from '../common/cusIcon/index'
- import './list.less'
- const CardGrid = Card.Grid
- const { Content } = Layout
- const { Option } = Select
- class DataConnect extends React.Component {
- constructor(props) {
- super(props);
- this.state = {
- visibleDeleteBox: false,
- }
- this.bodyRef = React.createRef();
- };
- componentDidMount() {
- const { dispatch } = this.props;
- this.setBodyWidth();
- dispatch({ type: 'dataConnect/fetchList' });
- window.addEventListener('resize', this.setBodyWidth);
- }
- componentWillUnmount() {
- window.removeEventListener('resize', this.setBodyWidth)
- }
- /**
- * 设置卡片容器宽度 = 每行最大卡片数量 * 卡片宽度
- */
- setBodyWidth = () => {
- const cardBody = this.bodyRef.current; // 卡片容器
- const parent = cardBody.parentNode; // 父级容器
- const pWidth = parent.offsetWidth; // 父级容器宽度
- const pPadding = 10 + 10; // 父级容器左右padding
- const cWidth = 160; // 每个卡片宽度
- const cMargin = 8 + 8; // 每个卡片左右margin
- const pTrueWidth = pWidth - pPadding; // 父容器实际可用宽度
- const cTrueWidth = cWidth + cMargin; // 卡片实际占用宽度
- const count = Math.floor(pTrueWidth/cTrueWidth); // 每行最大卡片数量
- const cardBodyWidth = (count - 1) * cTrueWidth; // 可能有滚动条,减少一个
- cardBodyWidth > 0 ? cardBody.style.width = cardBodyWidth + 'px' : void(0);
- }
- 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 });
- }
- generateOperationMenu = (l) => {
- const { dispatch } = this.props;
- return (
- <Menu className='menu-operation'>
- <Menu.Item onClick={()=>{
- dispatch({ type: 'dataConnect/setSelected', selected: l });
- dispatch({ type: 'dataConnect/setNewModel', model: l });
- dispatch({ type: 'dataConnect/setNewModelFields', fields: [
- { name: 'visibleBox', value: true },
- { name: 'boxOperation', value: 'modify' }
- ] });
- }}>
- <Icon type="info-circle-o" />属性设置
- </Menu.Item>
- <Menu.Item onClick={(e) => {
- dispatch({ type: 'dataConnect/setSelected', selected: l });
- dispatch({ type: 'dataConnect/setNewModel', model: { ...l, code: null } });
- dispatch({ type: 'dataConnect/setNewModelFields', fields: [
- { name: 'visibleBox', value: true },
- { name: 'boxOperation', value: 'create' }
- ] });
- }}>
- <Icon type="copy" />复制新增
-
- </Menu.Item>
- <Menu.Item onClick={(e) => {
- dispatch({ type: 'dataConnect/setSelected', selected: l });
- this.setState({ visibleDeleteBox: true})
- }}>
- <Icon type="delete" />删除
-
- </Menu.Item>
- </Menu>
- )
- }
- generateCard() {
- const { dataConnect, dispatch } = this.props;
- const reg = new RegExp('([+ \\- & | ! ( ) { } \\[ \\] ^ \" ~ * ? : ( ) \/])', 'g'); // 需要转义的字符
- let filterLabel = dataConnect.filterLabel ? (dataConnect.filterLabel + '').replace(new RegExp('(\\\\)', 'g'), '\\$1').replace(reg, '\\$1') : ''; // 添加转义符号
- let filterItem = dataConnect.filterItem
- let filterReg = new RegExp('(' + filterLabel + '){1}', 'ig');
- let cards = dataConnect.list.map(l => {
- let o = Object.assign({}, l);
- if(filterItem.type === 'date') {
- if(filterLabel===""){
- return o;
- }else if(filterLabel.indexOf('#')>-1){
- let start = filterLabel.split('#')[0]
- let end = filterLabel.split('#')[1]
- let nowTime = o[filterItem.name].getTime();
- if(nowTime>=start && nowTime<=end){
- return o;
- }
- return null
- }else{
- return null
- }
- }else {
- return ((o[filterItem.name] + '').search(filterReg) > -1) ? o : null
- }
- }).filter(a => a!==null).map( (l, i) => (
- <CardGrid className='dataconnect-card' key={i}>
- <Card
- bordered={false}
- hoverable={true}
- title={
- <Row type='flex' justify='start'
- onClick={() => {
- // 选中项设置
- dispatch({ type: 'dataConnect/setSelected', selected: l });
- dispatch({ type: 'dataConnect/setNewModel', model: l });
- dispatch({ type: 'dataConnect/setNewModelFields', fields: [
- { name: 'visibleBox', value: true },
- { name: 'boxOperation', value: 'modify' }
- ] });
- }}
- >
- <Col className='label' title={l.name}>
- { (filterItem.name === 'name' && 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>
- </Row>
- }
- actions={[
- <div>
- {l.dbType === 'file' ? <Icon type='file' /> : <div><Icon type='database' />{l.dbType[0].toUpperCase() + l.dbType.slice(1)}</div>}
- </div>,
- <Dropdown overlay={this.generateOperationMenu(l)} trigger={['click']}>
- <Icon style={{ fontSize: '24px' }} type="ellipsis" theme="outlined" />
- </Dropdown>
- ]}
- >
- <div className='content'
- onClick={() => {
- // 选中项设置
- dispatch({ type: 'dataConnect/setSelected', selected: l });
- dispatch({ type: 'dataConnect/setNewModel', model: l });
- dispatch({ type: 'dataConnect/setNewModelFields', fields: [
- { name: 'visibleBox', value: true },
- { name: 'boxOperation', value: 'modify' }
- ] });
- }}
- >
- { /** TODO 这里只考虑了数据库的展示情况,需要兼容展示文件类型的数据链接 */ }
- <Row className='address'>
- { filterLabel && filterItem.name === 'address' ?
- ((l.address || '').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.address
- }
- </Row>
- <Row className='username'>
- { filterLabel && filterItem.name === 'userName' ?
- ((l.userName || '').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.userName
- }
- </Row>
- </div>
- </Card>
- </CardGrid>
- ))
- if(cards.length === 0) {
- return <EmptyContent />
- }
-
- return cards;
- }
- generateFilterItems = () => {
- const { filterItems } = this.props.dataConnect;
- return filterItems.map(t => <Option key={t.name} value={t.name}>{t.label}</Option>);
- }
- render() {
- const { dataConnect, dispatch } = this.props;
- const { selected } = dataConnect;
- const { visibleDeleteBox } = this.state;
- return (
- <Layout className='layout-dataconnect'>
- <Content>
- <Card title={
- <Row className='tools' type='flex' justify='space-between'>
- <Col style={{ display: 'flex' }}>
- </Col>
- <Col className='search'>
- <Col>
- <Button className='btn-refresh' onClick={() => {
- dispatch({ type: 'dataConnect/setFilterLabel', label: '' });
- dispatch({ type: 'dataConnect/fetchList', mandatory: true });
- }}>
- <CusIcon type='bi-refresh'/>
- </Button>
- </Col>
- <Col>
- <ListFilter modelName='dataConnect' model={dataConnect} />
- </Col>
- <Col>
- <Button className='btn-add' onClick={() => {
- // 设置新增默认值
- dispatch({ type: 'dataConnect/setNewModel', model: { dbType: 'oracle', dbName: 'orcl' } });
- dispatch({ type: 'dataConnect/setNewModelFields', fields: [
- { name: 'visibleBox', value: true },
- { name: 'boxOperation', value: 'create' }
- ] });
- }}>
- 添加数据链接
- </Button>
- </Col>
- </Col>
- </Row>
- }>
- <div ref={this.bodyRef} className='body'>
- { this.generateCard() }
- </div>
- </Card>
- </Content>
- {visibleDeleteBox && <DeleteBox
- visibleBox={visibleDeleteBox}
- text={<div><span>确定要删除数据链接【{selected.name}】吗?</span></div>}
- hideBox={() => {
- this.setState({
- visibleDeleteBox: false
- })
- }}
- okHandler={() =>{
- dispatch({ type: 'dataConnect/remoteDelete', code: selected.code })
- }}
- />}
- {dataConnect.newOne.visibleBox && <DataConnectBox />}
- </Layout>
- )
- }
- }
- function mapStateToProps({present: {dataConnect}}) {
- return { dataConnect }
- }
- export default connect(mapStateToProps)(DataConnect)
|