list.jsx 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. import React from 'react'
  2. import { Layout, Button, Icon, Table, Menu, Dropdown, Card, Col, Row, Select, DatePicker } from 'antd'
  3. import { connect } from 'dva'
  4. import TransferBox from '../common/selectUserBox/selectUserBox';
  5. import AccessObjectBox from '../common/accessObjectBox/accessObjectBox'
  6. import { dateFormat } from '../../utils/baseUtils'
  7. import DeleteBox from '../common/deleteBox/deleteBox'
  8. import ShareBox from './shareBox'
  9. import CopyBox from './copyBox'
  10. import ListFilter from '../common/listFilter/index'
  11. import './list.less'
  12. const { Content } = Layout
  13. const { Option } = Select
  14. class DashboardList extends React.Component {
  15. constructor(props) {
  16. super(props);
  17. this.state = {
  18. selectedRecord: null,
  19. visibleChooseDataSourceBox: false,
  20. visibleDistributeBox: false,
  21. visibleShareBox: false,
  22. shareUrl: '',
  23. visibleTransferBox: false,
  24. visibleGroupMenu: false, // 显示分组菜单
  25. visibleDeleteBox: false,
  26. visibleCopyBox: false,
  27. defaultSelectedGroups: [],
  28. defaultSelectedUsers: [],
  29. }
  30. }
  31. // componentDidMount() {
  32. // const { dispatch } = this.props;
  33. // dispatch({ type: 'dashboard/remoteMenuDashboardList' });
  34. // }
  35. getShareList = () => {
  36. new Promise((resolve, reject) => {
  37. const { dispatch } = this.props;
  38. const { selectedRecord } = this.state;
  39. dispatch({ type: 'dashboard/shareList', code: selectedRecord.code })
  40. .then(
  41. (resolve) => {
  42. const resData = resolve.data.data;
  43. const { groupNames: defaultSelectedGroups, userNames: defaultSelectedUsers } = resData;
  44. this.setState({
  45. visibleDistributeBox: true,
  46. defaultSelectedGroups: defaultSelectedGroups.map(g => ({
  47. code: g.id + '',
  48. name: g.name
  49. })),
  50. defaultSelectedUsers: defaultSelectedUsers.map(u => ({
  51. code: u.id + '',
  52. name: u.name
  53. })),
  54. });
  55. }
  56. ).catch(reject => {
  57. console.log(reject);
  58. });
  59. });
  60. }
  61. handleVisibleChange = (flag) => {
  62. this.setState({ visibleGroupMenu: flag });
  63. }
  64. hideGroupMenu = () => {
  65. this.setState({
  66. visibleGrouMenu: false
  67. });
  68. }
  69. distribute = (group, geren) => {
  70. const { dispatch } = this.props;
  71. const { selectedRecord } = this.state;
  72. let targets = group.map(g => ({
  73. code: g.code,
  74. name: g.name,
  75. isGroup: true
  76. })).concat(geren.map(g => ({
  77. code: g.code,
  78. name: g.name,
  79. isGroup: false
  80. })))
  81. dispatch({ type: 'dashboard/share', code: selectedRecord.code, targets });
  82. }
  83. onSearch(list, dashboard) {
  84. const reg = new RegExp('([+ \\- & | ! ( ) { } \\[ \\] ^ \" ~ * ? : ( ) \/])', 'g'); // 需要转义的字符
  85. let filterLabel = dashboard.filterLabel ? (dashboard.filterLabel + '').replace(new RegExp('(\\\\)', 'g'), '\\$1').replace(reg, '\\$1') : ''; // 添加转义符号
  86. let filterItem = dashboard.filterItem;
  87. let filterReg = new RegExp('(' + filterLabel + '){1}', 'ig');
  88. return list.map(l => {
  89. let o = Object.assign({}, l);
  90. if(filterItem.type === 'date') {
  91. if(filterLabel===""){
  92. return o;
  93. }else if(filterLabel.indexOf('#')>-1){
  94. let start = filterLabel.split('#')[0]
  95. let end = filterLabel.split('#')[1]
  96. let nowTime = new Date(o[filterItem.name]).getTime();
  97. if(nowTime>=start && nowTime<=end){
  98. return o;
  99. }
  100. return null
  101. }else{
  102. return null
  103. }
  104. }else {
  105. return ((o[filterItem.name] + '').search(filterReg) > -1) ? o : null
  106. }
  107. }).filter(a => a!==null);
  108. }
  109. onSort(list) {
  110. return list.sort((a, b) => {
  111. return new Date(b.createTime) - new Date(a.createTime);
  112. });
  113. }
  114. generateFilterItems = () => {
  115. const { filterItems } = this.props.dashboard;
  116. return filterItems.map(t => <Option key={t.name} value={t.name}>{t.label}</Option>);
  117. }
  118. generateMenuItems = (menuTree) => {
  119. const { dispatch } = this.props;
  120. const { selectedRecord } = this.state;
  121. return menuTree.filter(t => t.type === 'menu').map(t => {
  122. if(t.children && t.children.length > 0) {
  123. return <Menu.SubMenu
  124. key={t.code}
  125. title={selectedRecord.menuCode === t.code ? <span style={{ color: '#1890ff', fontWeight: 'bold' }}>{t.name}</span> : t.name}
  126. onTitleClick={() => {
  127. dispatch({ type: 'dashboard/remoteSetMenu', dashboard: selectedRecord, menu: t });
  128. let obj = {selectedRecord: null};
  129. obj['visibleOperatingMenu' + selectedRecord.code] = false;
  130. this.setState(obj);
  131. }}
  132. >
  133. {this.generateMenuItems(t.children)}
  134. </Menu.SubMenu>
  135. }else {
  136. return <Menu.Item key={t.code} onClick={() => {
  137. dispatch({ type: 'dashboard/remoteSetMenu', dashboard: selectedRecord, menu: t });
  138. let obj = {selectedRecord: null};
  139. obj['visibleOperatingMenu' + selectedRecord.code] = false;
  140. this.setState(obj);
  141. }}>{selectedRecord.menuCode === t.code ? <span style={{ color: '#1890ff', fontWeight: 'bold' }}>{t.name}</span> : t.name}</Menu.Item>
  142. }
  143. })
  144. }
  145. render() {
  146. const { dispatch, dashboard, main } = this.props;
  147. const { visibleShareBox, shareUrl, visibleDistributeBox, visibleTransferBox, visibleDeleteBox,
  148. visibleCopyBox, selectedRecord, defaultSelectedGroups, defaultSelectedUsers } = this.state
  149. const { currentUser } = main;
  150. const { menuTree, menuSelectedKeys, filterItem } = dashboard;
  151. const reg = new RegExp('([+ \\- & | ! ( ) { } \\[ \\] ^ \" ~ * ? : ( ) \/])', 'g'); // 需要转义的字符
  152. let filterLabel = dashboard.filterLabel ? (dashboard.filterLabel + '').replace(new RegExp('(\\\\)', 'g'), '\\$1').replace(reg, '\\$1') : ''; // 添加转义符号
  153. const moreOperatingMenu = (
  154. <Menu className='menu-operation'>
  155. { selectedRecord && currentUser.code === selectedRecord.creatorCode && <Menu.Item onClick={() => {
  156. dispatch({ type: 'dashboard/getShareKey', record: selectedRecord, delay: 7 }).then((key) => {
  157. let obj = { visibleShareBox: true, shareUrl: window.location.origin + '/#/dashboard/share_key/' + key };
  158. obj['visibleOperatingMenu' + selectedRecord.code] = false;
  159. this.setState(obj);
  160. });
  161. }}>
  162. <Icon type='share-alt'/>分享
  163. </Menu.Item>}
  164. { selectedRecord && currentUser.code === selectedRecord.creatorCode && <Menu.Divider />}
  165. { selectedRecord && currentUser.code === selectedRecord.creatorCode && <Menu.Item onClick={this.getShareList}>
  166. <Icon type='share-alt'/>分发
  167. </Menu.Item>}
  168. { selectedRecord && currentUser.code === selectedRecord.creatorCode && <Menu.Item
  169. onClick={()=>{
  170. let obj = {visibleTransferBox: true};
  171. obj['visibleOperatingMenu' + selectedRecord.code] = false;
  172. this.setState(obj);
  173. }}
  174. >
  175. <Icon type="swap" />移交
  176. </Menu.Item>}
  177. { selectedRecord && currentUser.code === selectedRecord.creatorCode && <Menu.Divider />}
  178. { selectedRecord && currentUser.code === selectedRecord.creatorCode && <Menu.SubMenu className='setgroupmenu' title={<div><Icon style={{ marginRight: '6px' }} type='profile' />移动到</div>}>
  179. {this.generateMenuItems(menuTree)}
  180. </Menu.SubMenu>}
  181. { selectedRecord && (selectedRecord.dataConnects.length <= 1) && <Menu.Item
  182. onClick={()=>{
  183. let obj = {visibleCopyBox: true};
  184. obj['visibleOperatingMenu' + selectedRecord.code] = false;
  185. this.setState(obj);
  186. }}
  187. >
  188. <Icon type="copy" />复制
  189. </Menu.Item> }
  190. { selectedRecord && currentUser.code === selectedRecord.creatorCode && <Menu.Item
  191. onClick={(e) => {
  192. let obj = {visibleDeleteBox: true};
  193. obj['visibleOperatingMenu' + selectedRecord.code] = false;
  194. this.setState(obj);
  195. }}
  196. >
  197. <Icon type="delete" />删除
  198. </Menu.Item>}
  199. </Menu>
  200. )
  201. const dashboardColumns = [{
  202. title: '名称',
  203. dataIndex: 'name',
  204. key: 'name',
  205. width: 100,
  206. render: (text, record) => {
  207. return (
  208. <span style={{ color: '#1890ff', cursor: 'pointer' }} onClick={() => {
  209. dispatch({ type: 'dashboardDesigner/reset' });
  210. dispatch({ type: 'main/redirect', path: '/dashboard/' + record.code });
  211. dispatch({ type: 'recent/addRecentRecord', tarId: record.code, recordType: 1});
  212. }}>
  213. { filterLabel && filterItem.name === 'name' ?
  214. ((text || '').split(new RegExp(`(${filterLabel})`, 'i')).map((fragment, i) => {
  215. return (
  216. fragment.toLowerCase().replace(new RegExp('(\\\\)', 'g'), '\\$1').replace(reg, '\\$1') === filterLabel.toLowerCase() ?
  217. <span key={i} style={{fontWeight: 'bold', color: 'red'}} className="highlight">{fragment}</span> :
  218. fragment
  219. )
  220. }
  221. )) : text
  222. }
  223. </span>
  224. )
  225. }
  226. }, {
  227. title: '说明',
  228. dataIndex: 'description',
  229. key: 'description',
  230. width: 200,
  231. render: (text, record) => {
  232. return (
  233. <span>
  234. { filterLabel && filterItem.name === 'description' ?
  235. ((text || '').split(new RegExp(`(${filterLabel})`, 'i')).map((fragment, i) => {
  236. return (
  237. fragment.toLowerCase().replace(new RegExp('(\\\\)', 'g'), '\\$1').replace(reg, '\\$1') === filterLabel.toLowerCase() ?
  238. <span key={i} style={{fontWeight: 'bold', color: 'red'}} className="highlight">{fragment}</span> :
  239. fragment
  240. )
  241. }
  242. )) : text
  243. }
  244. </span>
  245. )
  246. }
  247. }, {
  248. title: '创建人',
  249. dataIndex: 'creatorName',
  250. key: 'creatorName',
  251. width: 100,
  252. render: (text, record) => {
  253. return (
  254. <span>
  255. { filterLabel && filterItem.name === 'creatorName' ?
  256. ((text || '').split(new RegExp(`(${filterLabel})`, 'i')).map((fragment, i) => {
  257. return (
  258. fragment.toLowerCase().replace(new RegExp('(\\\\)', 'g'), '\\$1').replace(reg, '\\$1') === filterLabel.toLowerCase() ?
  259. <span key={i} style={{fontWeight: 'bold', color: 'red'}} className="highlight">{fragment}</span> :
  260. fragment
  261. )
  262. }
  263. )) : text
  264. }
  265. </span>
  266. )
  267. }
  268. }, {
  269. title: '创建时间',
  270. dataIndex: 'createTime',
  271. key: 'createTime',
  272. render: (text, record) => dateFormat(text, 'yyyy-MM-dd hh:mm:ss'),
  273. width: 100
  274. }, {
  275. title: '操作',
  276. key: 'action',
  277. render: (text, record, index) => (
  278. <Dropdown key={record.code} code={record.code} overlay={moreOperatingMenu} trigger={['click']} visible={this.state['visibleOperatingMenu' + record.code]} onVisibleChange={visible => {
  279. let obj = {};
  280. obj['visibleOperatingMenu' + record.code] = visible;
  281. this.setState(obj)
  282. }}>
  283. <Icon type="setting" />
  284. </Dropdown>
  285. ),
  286. width: 50
  287. }];
  288. return (
  289. <Layout className='dashboard-view'>
  290. <Content>
  291. <Card className="dashboard-body" title={
  292. <Row className='dashboard-tools' type='flex' justify='space-between'>
  293. <Col style={{ display: 'flex' }}>
  294. </Col>
  295. <Col className='search'>
  296. <Col style={{ padding: '0 5px' }}>
  297. <ListFilter modelName='dashboard' model={dashboard}/>
  298. </Col>
  299. <Col >
  300. <Button style={{ marginRight: '8px' }} onClick={() => {
  301. dispatch({ type: 'dashboard/setFilterLabel', label: '' });
  302. if(!menuSelectedKeys || menuSelectedKeys.length === 0 || menuSelectedKeys[0] === '-1') {
  303. dispatch({ type: 'dashboard/fetchList', mandatory: true });
  304. }else {
  305. dispatch({ type: 'dashboard/remoteMenuDashboardList', menuCode: menuSelectedKeys[0] });
  306. }
  307. }}>
  308. <Icon type="sync" />
  309. </Button>
  310. <Button disabled={menuSelectedKeys.length !== 1 || menuSelectedKeys[0] === '-1'} onClick={() => {
  311. dispatch({ type: 'dashboardDesigner/reset' });
  312. dispatch({ type: 'dashboard/remoteQucikAdd', menuCode: menuSelectedKeys[0] });
  313. }}>
  314. <Icon type="layout" />创建报表
  315. </Button>
  316. </Col>
  317. </Col>
  318. </Row>
  319. }>
  320. {/* <div className='dashboard-body'>
  321. { this.generateCard() }
  322. </div> */}
  323. <Table
  324. className='dashboard-table'
  325. columns={dashboardColumns}
  326. dataSource={
  327. this.onSort(
  328. this.onSearch(dashboard.list, dashboard)
  329. )
  330. }
  331. size='small'
  332. scroll={{x: false, y: true}}
  333. pagination={false}
  334. onRow={(record) => {
  335. return {
  336. onClick: () => {
  337. this.setState({ selectedRecord: record})
  338. }
  339. }
  340. }}
  341. />
  342. </Card>
  343. </Content>
  344. {visibleDistributeBox && <AccessObjectBox
  345. visibleBox={visibleDistributeBox}
  346. hideBox={() => {
  347. this.setState({
  348. visibleDistributeBox: false
  349. })
  350. }}
  351. okHandler={this.distribute}
  352. defaultSelectedGroups={defaultSelectedGroups}
  353. defaultSelectedUsers={defaultSelectedUsers}
  354. />}
  355. {visibleTransferBox && <TransferBox
  356. visibleBox={visibleTransferBox}
  357. title='选择移交对象'
  358. okHandler={(user) => {
  359. dispatch({ type: 'dashboard/transfer', dashboardCode: this.state.selectedRecord.code, userCode: user.code });
  360. }}
  361. hideBox={() => {
  362. this.setState({
  363. visibleTransferBox: false
  364. })
  365. }}
  366. />}
  367. {visibleDeleteBox && <DeleteBox
  368. visibleBox={visibleDeleteBox}
  369. text={`确定要删除报表【${selectedRecord.name}】吗?`}
  370. hideBox={() => {
  371. this.setState({
  372. visibleDeleteBox: false
  373. })
  374. }}
  375. okHandler={() => {
  376. dispatch({ type: 'dashboard/remoteDelete', code: this.state.selectedRecord.code })
  377. }}
  378. />}
  379. {visibleShareBox && <ShareBox
  380. visibleBox={visibleShareBox}
  381. shareUrl={shareUrl}
  382. hideBox={() => {
  383. this.setState({
  384. visibleShareBox: false
  385. })
  386. }}
  387. onRefreshKey={(delay) => {
  388. return dispatch({ type: 'dashboard/getShareKey', record: this.state.selectedRecord, delay: delay })
  389. .then((key) => {
  390. this.setState({
  391. shareUrl: window.location.origin + '/#/dashboard/share_key/' + key
  392. })
  393. })
  394. }}
  395. />}
  396. {visibleCopyBox && <CopyBox
  397. visibleBox={visibleCopyBox}
  398. hideBox={()=>{this.setState({visibleCopyBox: false})}}
  399. currentDashboardCode={selectedRecord.code}
  400. currentDataConnect={selectedRecord.dataConnects[0]}
  401. />}
  402. </Layout>
  403. )
  404. }
  405. }
  406. export default connect(({ present: { main, dashboard } }) => ({ main, dashboard }))(DashboardList)