dataConnectConfig.jsx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. /**
  2. * 新增数据源-选择数据链接
  3. */
  4. import React from 'react'
  5. import { Layout, Form, Row, Col, Input, Icon, Menu, Dropdown, Divider, Upload, message, Card } from 'antd'
  6. import { connect } from 'dva'
  7. import DataConnectBox from './dataConnectBox'
  8. import EmptyContent from '../common/emptyContent/index'
  9. import './dataConnectConfig.less'
  10. const { Content } = Layout
  11. const CardGrid = Card.Grid
  12. const UploadDragger = Upload.Dragger
  13. const Search = Input.Search
  14. class DataConnectConfig extends React.Component {
  15. constructor(props) {
  16. super(props);
  17. this.state = {
  18. filterLabel: '',
  19. }
  20. }
  21. componentDidMount() {
  22. const { dispatch } = this.props;
  23. dispatch({ type: 'dataConnect/fetchList' });
  24. }
  25. generateCard() {
  26. const { dataConnect, dataSourceDetail, dispatch } = this.props;
  27. const { filterLabel: stateFilterLabel } = this.state;
  28. const reg = new RegExp('([+ \\- & | ! ( ) { } \\[ \\] ^ \" ~ * ? : ( ) \/])', 'g'); // 需要转义的字符
  29. let filterLabel = stateFilterLabel ? (stateFilterLabel + '').replace(new RegExp('(\\\\)', 'g'), '\\$1').replace(reg, '\\$1') : ''; // 添加转义符号
  30. let filterReg = new RegExp('(' + filterLabel + '){1}', 'ig');
  31. let cards = dataConnect.list.map(l => {
  32. let o = Object.assign({}, l);
  33. return o.code === dataSourceDetail.connectCode || ((o['name'] + '').search(filterReg) > -1) ? o : null
  34. }).filter(a => a!==null).map( (l, i) => (
  35. <CardGrid className='dataconnect-card' key={i}>
  36. <Card
  37. hoverable={true}
  38. title={
  39. <Row type='flex' justify='start'
  40. onClick={() => {
  41. // 选中项设置
  42. dispatch({ type: 'dataConnect/setSelected', selected: l });
  43. dispatch({ type: 'dataSourceDetail/setFields', fields: [
  44. { name: 'connectCode', value: l.code },
  45. { name: 'dbType', value: l.dbType },
  46. { name: 'address', value: l.address },
  47. { name: 'port', value: l.port },
  48. { name: 'dbName', value: l.dbName },
  49. { name: 'userName', value: l.userName },
  50. { name: 'password', value: l.password },
  51. { name: 'target', value: '' },
  52. { name: 'columns', value: [] },
  53. { name: 'notice', value: '' },
  54. ] });
  55. }}
  56. >
  57. <Col className='label' title={l.name}>
  58. { (filterLabel) ?
  59. ((l.name || '').split(new RegExp(`(${filterLabel})`, 'i')).map((fragment, i) => {
  60. return (
  61. fragment.toLowerCase().replace(new RegExp('(\\\\)', 'g'), '\\$1').replace(reg, '\\$1') === filterLabel.toLowerCase() ?
  62. <span key={i} style={{fontWeight: 'bold', color: 'red'}} className="highlight">{fragment}</span> :
  63. fragment
  64. )
  65. }
  66. )) : l.name
  67. }
  68. </Col>
  69. <div style={{ display: (dataConnect.selected && dataConnect.selected.code === l.code) ? 'block' : 'none' }} className='selected'></div>
  70. </Row>
  71. }
  72. actions={[
  73. <div>
  74. {l.dbType === 'file' ? <Icon type='file' /> : <div><Icon type='database' />{l.dbType[0].toUpperCase() + l.dbType.slice(1)}</div>}
  75. </div>,
  76. <Dropdown overlay={this.generateOperationMenu(l)} trigger={['click']}>
  77. <Icon style={{ fontSize: '24px' }} type="ellipsis" theme="outlined" />
  78. </Dropdown>
  79. ]}
  80. >
  81. <div className='content'
  82. onClick={() => {
  83. // 选中项设置
  84. dispatch({ type: 'dataConnect/setSelected', selected: l });
  85. dispatch({ type: 'dataSourceDetail/setFields', fields: [
  86. { name: 'connectCode', value: l.code },
  87. { name: 'connectName', value: l.name },
  88. { name: 'dbType', value: l.dbType },
  89. { name: 'address', value: l.address },
  90. { name: 'port', value: l.port },
  91. { name: 'dbName', value: l.dbName },
  92. { name: 'userName', value: l.userName },
  93. { name: 'password', value: l.password },
  94. { name: 'target', value: '' },
  95. { name: 'columns', value: [] },
  96. { name: 'notice', value: '' },
  97. ] });
  98. }}
  99. >
  100. { /** TODO 这里只考虑了数据库的展示情况,需要兼容展示文件类型的数据链接 */ }
  101. <Row className='address'>{l.address}</Row>
  102. <Row className='username'>{l.userName}</Row>
  103. </div>
  104. </Card>
  105. </CardGrid>
  106. ))
  107. if(cards.length === 0) {
  108. return <EmptyContent />
  109. }
  110. return cards;
  111. }
  112. generateOperationMenu = (item) => {
  113. const { dataConnect, dispatch } = this.props;
  114. return <Menu className='menu-operation'>
  115. <Menu.Item onClick={() => {
  116. dispatch({ type: 'dataConnect/setNewModel', model: item || dataConnect.selected });
  117. dispatch({ type: 'dataConnect/setNewModelFields', fields: [
  118. { name: 'visibleBox', value: true },
  119. { name: 'boxOperation', value: 'view' }
  120. ] });
  121. }}>
  122. <Icon type='edit'/>详情
  123. </Menu.Item>
  124. </Menu>
  125. }
  126. render() {
  127. const { dataSourceDetail, dispatch } = this.props;
  128. const { filterLabel } = this.state;
  129. return (
  130. <Form className='dataconnect-config' size='small'>
  131. {
  132. dataSourceDetail.type==='file'?(
  133. <div>
  134. <Divider orientation="left">选择文件</Divider>
  135. <UploadDragger
  136. className='upload'
  137. name='file' // 上传到后台的文件名
  138. fileList={dataSourceDetail.fileList}
  139. accept='application/vnd.ms-excel,.csv' // 只支持excel和csv格式文件
  140. action='//jsonplaceholder.typicode.com/posts/'
  141. headers={{authorization: 'authorization-text'}}
  142. beforeUpload={(file, fileList) => {
  143. const trueType = file.type === 'application/vnd.ms-excel';
  144. if (!trueType) {
  145. message.error('选择文件格式错误!');
  146. }
  147. const trueSize = file.size / 1024 / 1024 < 30;
  148. if (!trueSize) {
  149. message.error('选择文件过大!');
  150. }
  151. return trueType && trueSize;
  152. }}
  153. onChange={(info) => {
  154. const file = info.file;
  155. let fileList = info.fileList;
  156. fileList = fileList.slice(-1); // 只保留最后一个
  157. if (info.file.status !== 'uploading') {
  158. const trueType = file.type === 'application/vnd.ms-excel';
  159. const trueSize = file.size / 1024 / 1024 < 30;
  160. if(!trueType || !trueSize) {
  161. fileList = [];
  162. }
  163. }
  164. if (file.status === 'done') {
  165. message.success(`${file.name} 文件上传成功`);
  166. } else if (file.status === 'error') {
  167. fileList = [];
  168. message.error(`${file.name} 文件上传失败.`);
  169. }
  170. dispatch({ type: 'dataSourceDetail/setField', name: 'fileList', value: fileList })
  171. }}
  172. >
  173. <p className="ant-upload-drag-icon">
  174. <Icon type="inbox" />
  175. </p>
  176. <p className="ant-upload-text">点击选择或拖动文件到该区域</p>
  177. <p className="ant-upload-hint">仅支持上传单个30MB以内EXCEL/CSV格式文件</p>
  178. </UploadDragger>
  179. </div>
  180. ):(
  181. <Layout className='dataconnect'>
  182. <Content>
  183. <Card bordered={false} title={
  184. <Row type='flex' justify='end'>
  185. <Search
  186. style={{ width: '200px' }}
  187. value={filterLabel}
  188. placeholder="请输入关键字"
  189. onChange={e => {
  190. this.setState({
  191. filterLabel: e.target.value
  192. })
  193. // dispatch({ type: 'dataConnect/setFilterLabel', label: e.target.value });
  194. }}
  195. />
  196. </Row>
  197. }>
  198. <div className='dataconnect-list'>
  199. { this.generateCard() }
  200. </div>
  201. <DataConnectBox />
  202. </Card>
  203. </Content>
  204. </Layout>
  205. )
  206. }
  207. </Form>
  208. );
  209. }
  210. }
  211. export default connect(({ present: { dataSourceDetail, dataConnect } }) => ({ dataSourceDetail, dataConnect }))(DataConnectConfig);