dataConnectConfig.jsx 11 KB

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