dataConnectConfig.jsx 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  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 Ellipsis from 'ant-design-pro/lib/Ellipsis'
  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. componentDidMount() {
  12. const { dispatch } = this.props;
  13. dispatch({ type: 'dataConnect/fetchList' });
  14. }
  15. render() {
  16. const { dataSourceDetail, dataConnect, dispatch } = this.props;
  17. const reg = new RegExp('([+ \\- & | ! ( ) { } \\[ \\] ^ \" ~ * ? : ( ) \/])', 'g'); // 需要转义的字符
  18. let filterLabel = dataConnect.filterLabel.replace(new RegExp('(\\\\)', 'g'), '\\$1').replace(reg, '\\$1'); // 添加转义符号
  19. const generateCard = () => {
  20. const operationMenu = (
  21. <Menu className='menu-operation'>
  22. <Menu.Item onClick={() => {
  23. dispatch({ type: 'dataConnect/setNewModel', model: dataConnect.selected });
  24. dispatch({ type: 'dataConnect/setNewModelFields', fields: [
  25. { name: 'visibleBox', value: true },
  26. { name: 'boxOperation', value: 'modify' }
  27. ] });
  28. }}>
  29. <Icon type='edit'/>编辑
  30. </Menu.Item>
  31. <Menu.Item onClick={(e) => {
  32. dispatch({ type: 'dataConnect/remoteDelete', code: dataConnect.selected.code });
  33. }}>
  34. <Icon type='delete'/>删除
  35. </Menu.Item>
  36. </Menu>
  37. )
  38. let cards = dataConnect.list.filter(l => {
  39. return ((l.name || '').search(new RegExp('(' + filterLabel + '){1}', 'ig')) !== -1) ||
  40. ((l.description || '').search(new RegExp('(' + filterLabel + '){1}', 'ig')) !== -1);
  41. }).map( (l, i) => (
  42. <CardGrid className='dataconnect-card' key={i}>
  43. <Card
  44. title={
  45. <Row type='flex' justify='start'>
  46. <Col className='label'>{l.name}</Col>
  47. <div style={{ display: (dataConnect.selected && dataConnect.selected.code === l.code) ? 'block' : 'none' }} className='selected'></div>
  48. </Row>
  49. }
  50. onClick={() => {
  51. // 选中项设置
  52. dispatch({ type: 'dataConnect/setSelected', selected: l });
  53. dispatch({ type: 'dataSourceDetail/setFields', fields: [
  54. { name: 'connectCode', value: l.code },
  55. { name: 'dbType', value: l.dbType },
  56. { name: 'address', value: l.address },
  57. { name: 'port', value: l.port },
  58. { name: 'dbName', value: l.dbName },
  59. { name: 'userName', value: l.userName },
  60. { name: 'password', value: l.password },
  61. { name: 'target', value: '' },
  62. { name: 'columns', value: [] },
  63. { name: 'notice', value: '' },
  64. ] });
  65. }}
  66. >
  67. <div style={{ display: 'flex', flexDirection: 'column', justifyContent: 'space-between', height: '100%' }}>
  68. <Row>
  69. <Ellipsis lines={3}>
  70. {l.description}
  71. </Ellipsis>
  72. </Row>
  73. <Row type='flex' justify='space-between'>
  74. <Col>{l.dbType}</Col>
  75. <Col>
  76. <Dropdown overlay={operationMenu} trigger={['click']}>
  77. <Icon type="ellipsis" />
  78. </Dropdown>
  79. </Col>
  80. </Row>
  81. </div>
  82. </Card>
  83. </CardGrid>
  84. ))
  85. cards.unshift(
  86. <CardGrid className='dataconnect-card dataconnect-card-create' key='create' onClick={() => {
  87. dispatch({ type: 'dataConnect/setNewModel', model: {} });
  88. dispatch({ type: 'dataConnect/setNewModelFields', fields: [
  89. { name: 'visibleBox', value: true },
  90. { name: 'boxOperation', value: 'create' }
  91. ] });
  92. }}>
  93. <Card>
  94. <Icon type="plus-circle-o" />
  95. </Card>
  96. </CardGrid>
  97. );
  98. return cards;
  99. }
  100. return (
  101. <Form className='form-base' size='small'>
  102. {
  103. dataSourceDetail.type==='file'?(
  104. <div>
  105. <Divider orientation="left">选择文件</Divider>
  106. <UploadDragger
  107. className='upload'
  108. name='file' // 上传到后台的文件名
  109. fileList={dataSourceDetail.fileList}
  110. accept='application/vnd.ms-excel,.csv' // 只支持excel和csv格式文件
  111. action='//jsonplaceholder.typicode.com/posts/'
  112. headers={{authorization: 'authorization-text'}}
  113. beforeUpload={(file, fileList) => {
  114. const trueType = file.type === 'application/vnd.ms-excel';
  115. if (!trueType) {
  116. message.error('选择文件格式错误!');
  117. }
  118. const trueSize = file.size / 1024 / 1024 < 30;
  119. if (!trueSize) {
  120. message.error('选择文件过大!');
  121. }
  122. return trueType && trueSize;
  123. }}
  124. onChange={(info) => {
  125. const file = info.file;
  126. let fileList = info.fileList;
  127. fileList = fileList.slice(-1); // 只保留最后一个
  128. if (info.file.status !== 'uploading') {
  129. console.log(file, info.fileList);
  130. const trueType = file.type === 'application/vnd.ms-excel';
  131. const trueSize = file.size / 1024 / 1024 < 30;
  132. if(!trueType || !trueSize) {
  133. fileList = [];
  134. }
  135. }
  136. if (file.status === 'done') {
  137. message.success(`${file.name} 文件上传成功`);
  138. } else if (file.status === 'error') {
  139. fileList = [];
  140. message.error(`${file.name} 文件上传失败.`);
  141. }
  142. dispatch({ type: 'dataSourceDetail/setField', name: 'fileList', value: fileList })
  143. }}
  144. >
  145. <p className="ant-upload-drag-icon">
  146. <Icon type="inbox" />
  147. </p>
  148. <p className="ant-upload-text">点击选择或拖动文件到该区域</p>
  149. <p className="ant-upload-hint">仅支持上传单个30MB以内EXCEL/CSV格式文件</p>
  150. </UploadDragger>
  151. </div>
  152. ):(
  153. <Layout className='dataconnect'>
  154. <Content>
  155. <Card title={
  156. <Row type='flex' justify='end'>
  157. <Search
  158. style={{ width: '200px' }}
  159. value={dataConnect.filterLabel}
  160. placeholder="请输入关键字"
  161. onChange={e => {
  162. dispatch({ type: 'dataConnect/setFilterLabel', label: e.target.value });
  163. }}
  164. />
  165. </Row>
  166. }>
  167. <div className='dataconnect-list'>
  168. { generateCard() }
  169. </div>
  170. <DataConnectBox />
  171. </Card>
  172. </Content>
  173. </Layout>
  174. )
  175. }
  176. </Form>
  177. );
  178. }
  179. }
  180. export default connect(({ present: { dataSourceDetail, dataConnect } }) => ({ dataSourceDetail, dataConnect }))(DataConnectConfig);