list.jsx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. import React from 'react'
  2. import { Layout, Button, Icon, Input, Menu, Dropdown, Card, Col, Row } from 'antd'
  3. import { connect } from 'dva'
  4. import { dateFormat } from '../../utils/baseUtils'
  5. import Ellipsis from 'ant-design-pro/lib/Ellipsis'
  6. import DistributeBox from './distributeBox'
  7. import TransferBox from '../common/selectUserBox';
  8. import 'ant-design-pro/dist/ant-design-pro.css'
  9. import Thumbnail from './thumbnail'
  10. import './list.less'
  11. import DeleteBox from '../common/deleteBox'
  12. const { Content } = Layout
  13. const { Search } = Input
  14. const CardGrid = Card.Grid
  15. class DashboardList extends React.Component {
  16. constructor(props) {
  17. super(props);
  18. this.state = {
  19. selectedRecord: null,
  20. visibleChooseDataSourceBox: false,
  21. visibleDistributeBox: false,
  22. visibleTransferBox: false,
  23. visibleGroupMenu: false, // 显示分组菜单
  24. visibleDeleteBox: false
  25. }
  26. }
  27. componentDidMount() {
  28. const { dispatch } = this.props;
  29. this.setBodyWidth();
  30. dispatch({ type: 'dashboard/fetchList' });
  31. }
  32. /**
  33. * 设置卡片容器宽度 = 每行最大卡片数量 * 卡片宽度
  34. */
  35. setBodyWidth() {
  36. const chartBody = document.getElementsByClassName('dashboard-body')[0]; // 卡片容器
  37. const parent = chartBody.parentNode; // 父级容器
  38. const pWidth = parent.offsetWidth; // 父级容器宽度
  39. const pPadding = 10 + 10; // 父级容器左右padding
  40. const cWidth = 512; // 每个卡片宽度
  41. const cMargin = 5 + 5; // 每个卡片左右margin
  42. const pTrueWidth = pWidth - pPadding; // 父容器实际可用宽度
  43. const cTrueWidth = cWidth + cMargin; // 卡片实际占用宽度
  44. const count = Math.floor(pTrueWidth/cTrueWidth); // 每行最大卡片数量
  45. chartBody.style.width = count * cTrueWidth + 'px';
  46. }
  47. generateCard() {
  48. const { dashboard, dispatch } = this.props;
  49. const list = dashboard.list;
  50. const reg = new RegExp('([+ \\- & | ! ( ) { } \\[ \\] ^ \" ~ * ? : ( ) \/])', 'g'); // 需要转义的字符
  51. let filterLabel = dashboard.filterLabel.replace(new RegExp('(\\\\)', 'g'), '\\$1').replace(reg, '\\$1'); // 添加转义符号
  52. const operationMenu = (
  53. <Menu className='menu-operation'>
  54. <Menu.Item onClick={() => {
  55. this.setState({visibleDistributeBox: true})
  56. }}>
  57. <Icon type='share-alt'/>分发
  58. </Menu.Item>
  59. <Menu.Divider />
  60. <Menu.Item
  61. onClick={()=>{
  62. this.setState({ visibleTransferBox: true})
  63. }}
  64. >
  65. <Icon type="swap" />移交
  66. </Menu.Item>
  67. <Menu.Item
  68. onClick={(e) => {
  69. this.setState({ visibleDeleteBox: true})
  70. }}
  71. >
  72. <Icon type="delete" />删除
  73. </Menu.Item>
  74. </Menu>
  75. )
  76. let cards = list.filter(l => {
  77. let reg = new RegExp('(' + filterLabel + '){1}', 'ig');
  78. return (l.name || '').search(reg) !== -1 || (l.description || '').search(reg) !== -1;
  79. }).sort((a, b) => {
  80. return new Date(b.createTime) - new Date(a.createTime)
  81. }).map( (l, i) => (
  82. <CardGrid className='dashboard-card' key={i} onClick={() => {
  83. this.setState({ selectedRecord: l })
  84. }}>
  85. <Card
  86. title={
  87. <Row type='flex' justify='space-between'>
  88. <Col span={21} style={{ overflow: 'hidden', textOverflow: 'ellipsis' }} >
  89. { filterLabel ?
  90. ((l.name || '').split(new RegExp(`(${filterLabel})`, 'i')).map((fragment, i) => {
  91. return (
  92. fragment.toLowerCase().replace(new RegExp('(\\\\)', 'g'), '\\$1').replace(reg, '\\$1') === filterLabel.toLowerCase() ?
  93. <span key={i} style={{fontWeight: 'bold', color: 'red'}} className="highlight">{fragment}</span> :
  94. fragment
  95. )
  96. }
  97. )) : l.name
  98. }
  99. </Col>
  100. <Col style={{ textAlign: 'right' }} span={3} >
  101. <Icon type='star-o'/>
  102. </Col>
  103. </Row>
  104. }
  105. cover={
  106. <Col className='cover-body'>
  107. <Row className='thumb' onClick={() => {
  108. dispatch({ type: 'dashboardDesigner/reset' });
  109. dispatch({ type: 'main/redirect', path: '/dashboard/' + l.code });
  110. }}>
  111. <Thumbnail type={l.type} code={l.code} option={l.chartOption} thumbnail={l.thumbnail}/>
  112. </Row>
  113. <Row className='desc'>
  114. <Ellipsis tooltip={l.description.length > 16} lines={2}>{
  115. <span>
  116. { filterLabel ?
  117. ((l.description || '').split(new RegExp(`(${filterLabel})`, 'i')).map((fragment, i) => {
  118. return (
  119. fragment.toLowerCase().replace(new RegExp('(\\\\)', 'g'), '\\$1').replace(reg, '\\$1') === filterLabel.toLowerCase() ?
  120. <span key={i} style={{fontWeight: 'bold', color: 'red'}} className="highlight">{fragment}</span> :
  121. fragment
  122. )
  123. }
  124. )) : l.description
  125. }
  126. </span>
  127. }</Ellipsis>
  128. </Row>
  129. <Row className='footer' type='flex' justify='end' align='bottom'>
  130. <Col style={{ textAlign: 'left' }} span={22}>
  131. <Row>{l.creator} {dateFormat(l.createTime, 'yyyy-MM-dd')}</Row>
  132. </Col>
  133. <Col span={2} style={{ textAlign: 'right' }}>
  134. <Dropdown overlay={operationMenu} trigger={['click']}>
  135. <Icon type="ellipsis" />
  136. </Dropdown>
  137. </Col>
  138. </Row>
  139. </Col>
  140. }
  141. >
  142. </Card>
  143. </CardGrid>
  144. ));
  145. if(cards.length === 0) {
  146. cards = <div style={{ padding: '7px', textAlign: 'center', fontSize: '14px', color: 'rgba(0, 0, 0, 0.45)' }}>暂无数据</div>
  147. }
  148. return cards;
  149. }
  150. handleVisibleChange = (flag) => {
  151. this.setState({ visibleGroupMenu: flag });
  152. }
  153. hideGroupMenu = () => {
  154. this.setState({
  155. visibleGrouMenu: false
  156. });
  157. }
  158. render() {
  159. const { dispatch, dashboard } = this.props;
  160. const { visibleDistributeBox, visibleTransferBox, visibleDeleteBox, selectedRecord } = this.state
  161. return (
  162. <Layout className='dashboard-list'>
  163. <Content>
  164. <Card title={
  165. <Row className='tools' type='flex' justify='space-between'>
  166. <Col style={{ display: 'flex' }}>
  167. </Col>
  168. <Col className='search'>
  169. <Col style={{ padding: '0 5px' }}>
  170. <Search
  171. placeholder="请输入关键字"
  172. value={dashboard.filterLabel}
  173. onChange={e => {
  174. dispatch({ type: 'dashboard/setFilterLabel', label: e.target.value });
  175. }}
  176. />
  177. </Col>
  178. <Col >
  179. <Button onClick={() => {
  180. dispatch({ type: 'dashboard/remoteQucikAdd' });
  181. }}>
  182. <Icon type="layout" />创建看板
  183. </Button>
  184. </Col>
  185. </Col>
  186. </Row>
  187. }>
  188. <div className='dashboard-body'>
  189. { this.generateCard() }
  190. </div>
  191. </Card>
  192. </Content>
  193. <DistributeBox
  194. visibleDistributeBox={visibleDistributeBox}
  195. selectedRecord={this.state.selectedRecord}
  196. hideBox={() => {
  197. this.setState({
  198. visibleDistributeBox: false
  199. });
  200. }} />
  201. <TransferBox
  202. visibleBox={visibleTransferBox}
  203. title='选择移交对象'
  204. onOk={(user) => {
  205. dispatch({ type: 'dashboard/transfer', dashboardCode: this.state.selectedRecord.code, userCode: user.code });
  206. }}
  207. hideBox={() => {
  208. this.setState({
  209. visibleTransferBox: false
  210. })
  211. }}
  212. />
  213. <DeleteBox
  214. visibleDeleteBox={visibleDeleteBox}
  215. type='dashboard'
  216. hideBox={() => {
  217. this.setState({
  218. visibleDeleteBox: false
  219. })
  220. }}
  221. selectedRecord={selectedRecord}
  222. onOk={() => {
  223. dispatch({ type: 'dashboard/remoteDelete', code: this.state.selectedRecord.code })
  224. }} />
  225. </Layout>
  226. )
  227. }
  228. }
  229. function mapStateToProps({ present: { dashboard } }) {
  230. return { dashboard }
  231. }
  232. export default connect(mapStateToProps)(DashboardList)