datasource.jsx 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. import React from 'react'
  2. import { routerRedux } from 'dva/router'
  3. import { Tabs, Input, Button, Table, Icon, Tag, Menu, Dropdown, Divider } from 'antd'
  4. const { TabPane } = Tabs
  5. const { Search } = Input
  6. import { connect } from 'dva'
  7. import { Link } from 'react-router-dom'
  8. import DataConnectBox from './dataConnectBox'
  9. import dataSource from '../../models/dataSource'
  10. import dataConnect from '../../models/dataConnect'
  11. import './dataSource.less'
  12. class DataSource extends React.Component {
  13. constructor(props) {
  14. super(props);
  15. this.state = {
  16. loading: false,
  17. activeTab: 'dataSource',
  18. operation: 'create', // 打开数据编辑界面的类型
  19. visibleCreateBox: false,
  20. visibleBox: false, // 数据编辑界面显示标识
  21. selectedDataSourceCode: -1, // 当前选中的dataSource的code
  22. selectedDataConnectCode: -1, // 当前选中的dataConnect的code
  23. filterDropdownVisible: false,
  24. search: {} // 搜索条件
  25. }
  26. };
  27. componentDidMount() {
  28. this.setScrollTableHeight();
  29. }
  30. /**
  31. * 根据视图设置表格高度以呈现滚动条
  32. */
  33. setScrollTableHeight() {
  34. const mainContent = document.getElementsByClassName('main-content')[0];
  35. const tabBar = mainContent.getElementsByClassName('ant-tabs-bar')[0];
  36. const tableHeader = mainContent.getElementsByClassName('ant-table-header')[0];
  37. const tableBody = mainContent.getElementsByClassName('ant-table-body')[0];
  38. tableBody.style.maxHeight=`${mainContent.offsetHeight - tabBar.offsetHeight - tableHeader.offsetHeight - 38}px`;
  39. }
  40. showCreateBox = () => {
  41. this.setState({
  42. visibleCreateBox: true
  43. });
  44. }
  45. showDataConnectBox = (o) => {
  46. this.setState({
  47. operation: o,
  48. visibleBox: true
  49. });
  50. }
  51. hideDataConnectBox = () => {
  52. this.setState({
  53. visibleBox: false
  54. });
  55. }
  56. onInputChange = (name, value) => {
  57. const { search } = this.state;
  58. let newSearch = Object.assign({}, search );
  59. newSearch[name] = value;
  60. this.setState({ search: newSearch });
  61. }
  62. onSearch = () => {
  63. const { search } = this.state;
  64. const reg = new RegExp(search.name, 'gi');
  65. this.setState({
  66. filterDropdownVisible: false
  67. });
  68. }
  69. render() {
  70. const { dataSource, dataConnect, dispatch } = this.props;
  71. const { loading, activeTab, search, visibleBox, operation, selectedDataSourceCode, selectedDataConnectCode } = this.state;
  72. const moreOperatingMenu = (
  73. <Menu className='operationmenu'>
  74. <Menu.Item
  75. onClick={(e) => {
  76. let selectedModel = dataSource.list.find((i) => { return i.code == selectedDataSourceCode })
  77. dispatch({type: 'main/redirect', path: {pathname: '/datasource/'+ selectedModel.type +'/' + selectedModel.code + '/base'}});
  78. }}>
  79. <Icon type="info-circle-o" />属性设置
  80. </Menu.Item>
  81. <Menu.Item onClick={() => {
  82. let selectedModel = dataSource.list.find((i) => { return i.code == selectedDataSourceCode })
  83. dispatch({type: 'main/redirect', path: {pathname: '/datasource/'+ selectedModel.type +'/' + selectedModel.code + '/column'}});
  84. }}>
  85. <Icon type="table" />数据列设置
  86. </Menu.Item>
  87. <Menu.Item><Icon type="search" />预览数据</Menu.Item>
  88. <Menu.Item onClick={() => {
  89. let selectedModel = dataSource.list.find((i) => { return i.code == selectedDataSourceCode })
  90. dispatch({type: 'main/redirect', path: {pathname: '/datasource/'+ selectedModel.type +'/' + selectedModel.code + '/access'}});
  91. }}><Icon type="lock" />权限设置</Menu.Item>
  92. <Menu.Divider />
  93. <Menu.Item
  94. onClick={(e) => {
  95. dispatch({ type: 'dataSource/remoteDelete', code: selectedDataSourceCode });
  96. }}
  97. ><Icon type="delete" />删除</Menu.Item>
  98. </Menu>
  99. );
  100. const dataSourceColumns = [{
  101. title: '名称',
  102. dataIndex: 'name',
  103. key: 'name',
  104. width: 100,
  105. sorter: (a, b) => a.name.localeCompare(b.name, 'zh-Hans-CN', {sensitivity: 'accent'}),
  106. filterDropdown: (
  107. <div className="custom-filter-dropdown">
  108. <Input
  109. ref={ele => this.searchInput = ele}
  110. placeholder="Search name"
  111. value={this.state.search.name}
  112. onChange={(e) => { this.onInputChange('name', e.target.value) }}
  113. onPressEnter={this.onSearch}
  114. />
  115. <Button type="primary" onClick={this.onSearch}>Search</Button>
  116. </div>
  117. ),
  118. className: `column-${this.state.search.name?'filtered':'nofiltered'}`,
  119. filterIcon: <Icon type="smile-o"/>,
  120. filterDropdownVisible: this.state.filterDropdownVisible,
  121. onFilterDropdownVisibleChange: (visible) => {
  122. this.setState({
  123. filterDropdownVisible: visible,
  124. }, () => this.searchInput && this.searchInput.focus());
  125. },
  126. render: (text, record) => {
  127. return <div className='datasource-name'>
  128. <div className={`datasource-type type-${record.type.key}`}></div>
  129. <div>{text}</div>
  130. </div>
  131. }
  132. }, {
  133. title: '标签',
  134. dataIndex: 'tags',
  135. key: 'tag',
  136. width: 150,
  137. render: (text, record) => {
  138. text=text.join(',');
  139. let tags = text ? text.split(',').map((t, i) => {
  140. return <Tag className='datasource-tag' key={i}>{t}</Tag>
  141. }) : '';
  142. return (<div>
  143. {tags}
  144. </div>)
  145. }
  146. }, {
  147. title: '说明',
  148. dataIndex: 'description',
  149. key: 'description',
  150. width: 200
  151. }, {
  152. title: '创建人',
  153. dataIndex: 'creator',
  154. key: 'creator',
  155. width: 100
  156. }, {
  157. title: '创建时间',
  158. dataIndex: 'createTime',
  159. key: 'createTime',
  160. render: (text, record) => text.format('yyyy-MM-dd hh:mm:ss'),
  161. width: 100
  162. }, {
  163. title: '图表',
  164. dataIndex: 'chartSum',
  165. key: 'chartSum',
  166. width: 80
  167. }, {
  168. title: '操作',
  169. key: 'action',
  170. render: (text, record, index) => (
  171. <Dropdown code={record.code} overlay={moreOperatingMenu} trigger={['click']} >
  172. <Icon type="setting" />
  173. </Dropdown>
  174. ),
  175. width: 80
  176. }];
  177. const dataConnectColumns = [{
  178. title: '名称',
  179. dataIndex: 'name',
  180. key: 'name',
  181. width: 100,
  182. render: (text, record) => {
  183. return <div className='datasource-name'>
  184. <div className={`datasource-type type-${record.type}`}></div>
  185. <div>{text}</div>
  186. </div>
  187. }
  188. }, {
  189. title: '说明',
  190. dataIndex: 'description',
  191. key: 'description',
  192. width: 100
  193. }, {
  194. title: '操作',
  195. key: 'action',
  196. width: 300,
  197. render: (text, record) => (
  198. <div className='action-col'>
  199. <div className='operation' onClick={() => {
  200. let selectedModel = dataConnect.list.find((i) => { return i.code == record.code });
  201. dispatch({ type: 'dataConnect/setNewModel', model: selectedModel });
  202. this.showDataConnectBox('modify')
  203. }}><Icon type="info-circle-o"/>属性</div>
  204. <div className='operation'><Divider type="vertical" /></div>
  205. <div className='operation' onClick={() => {
  206. dispatch({ type: 'dataSource/resetNewModel' });
  207. dispatch({ type: 'dataSource/setNewModelField', fields: [
  208. { name: 'dbType', value: record.dbType },
  209. { name: 'address', value: record.address },
  210. { name: 'port', value: record.port },
  211. { name: 'dbName', value: record.dbName },
  212. { name: 'userName', value: record.userName },
  213. { name: 'password', value: record.password }
  214. ] });
  215. dispatch({type: 'main/redirect', path: {pathname: '/datasource/database/create'}});
  216. }}><Icon type="plus"/>创建数据源</div>
  217. <div className='operation'><Divider type="vertical" /></div>
  218. <div className='operation' onClick={() => {
  219. dispatch({ type: 'dataConnect/remoteDelete', code: record.code });
  220. }}><Icon type="delete"/>删除</div>
  221. </div>
  222. ),
  223. width: 80
  224. }];
  225. return (
  226. <Tabs
  227. className='datasource-tabs'
  228. type="card"
  229. defaultActiveKey="1"
  230. tabBarExtraContent={
  231. <div className='datasource-tabs-tools'>
  232. <Search
  233. placeholder="请输入关键字"
  234. onSearch={value => console.log(value)}
  235. />
  236. <Dropdown overlay={(
  237. <Menu onClick={(item, key, keyPath) => {
  238. const type = item.key;
  239. dispatch({ type: 'dataSource/resetNewModel' });
  240. dispatch({ type: 'dataSource/setNewModelField', name: 'type', value: type });
  241. dispatch({type: 'main/redirect', path: {pathname: '/datasource/'+ type +'/create'}});
  242. }}>
  243. <Menu.Item key='database'>数据库</Menu.Item>
  244. <Menu.Item key='file'>文件</Menu.Item>
  245. </Menu>
  246. )} trigger={['click']}>
  247. <Button style={{ display: activeTab=='dataConnect'?'none':'inline-block' }}>
  248. <Icon type="plus" />添加数据源
  249. </Button>
  250. </Dropdown>
  251. <Button style={{ display: activeTab=='dataConnect'?'inline-block':'none' }} onClick={(e) => {
  252. dispatch({ type: 'dataConnect/resetNewModel' });
  253. this.showDataConnectBox('create')
  254. }}>
  255. <Icon type="plus" />添加数据连接
  256. </Button>
  257. <DataConnectBox operation={operation} visibleBox={visibleBox} hideBox={this.hideDataConnectBox} />
  258. </div>
  259. }
  260. onChange={(key) => {
  261. this.setState({
  262. activeTab: key == '1' ? 'dataSource' : 'dataConnect'
  263. });
  264. }}
  265. >
  266. <TabPane className='datasource-tab' tab="数据源" key="1" >
  267. <Table
  268. className='datasource-table datasource-table'
  269. columns={dataSourceColumns}
  270. dataSource={dataSource.list}
  271. loading={loading}
  272. size='small'
  273. scroll={{x: false, y: 471}}
  274. pagination={false}
  275. onRow={(record) => {
  276. return {
  277. onClick: () => {this.setState({ selectedDataSourceCode: record.code})}
  278. }
  279. }}
  280. />
  281. </TabPane>
  282. <TabPane className='dataconnect-tab dataconnect' tab="数据库连接" key="2" >
  283. <Table
  284. className='dataconnect-table dataconnect-table'
  285. columns={dataConnectColumns}
  286. dataSource={dataConnect.list}
  287. loading={loading}
  288. size='small'
  289. scroll={{x: false, y: 471}}
  290. pagination={false}
  291. />
  292. </TabPane>
  293. </Tabs>
  294. )
  295. }
  296. }
  297. function mapStateToProps({present: {dataSource, dataConnect}}) {
  298. return { dataSource, dataConnect }
  299. }
  300. export default connect(mapStateToProps)(DataSource)