DataPortalList.tsx 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. import React from 'react'
  2. import classnames from 'classnames'
  3. import { createStructuredSelector } from 'reselect'
  4. import { compose } from 'redux'
  5. import { connect } from 'react-redux'
  6. import { Icon, Col, Button, Tooltip, Popconfirm, Modal, Row } from 'antd'
  7. import { IconProps } from 'antd/lib/icon'
  8. import AntdFormType from 'antd/lib/form/Form'
  9. const styles = require('../Viz.less')
  10. import PortalForm from './PortalForm'
  11. import ModulePermission from 'containers/Account/components/checkModulePermission'
  12. import { IProject } from 'containers/Projects/types'
  13. import { IPortal } from 'containers/Viz/types'
  14. import { makeSelectProjectRoles } from 'containers/Projects/selectors'
  15. import {IProjectRoles} from 'containers/Organizations/component/ProjectRole'
  16. interface IPortalListProps {
  17. projectId: number
  18. portals: IPortal[]
  19. projectRoles: IProjectRoles[]
  20. currentProject: IProject
  21. onPortalClick: (portalId: number) => () => void
  22. onAdd: (portal, resolve) => void
  23. onEdit: (portal, resolve) => void
  24. onDelete: (portalId: number) => void
  25. onExcludeRoles: (type: string, id: number, resolve?: any) => any
  26. onCheckUniqueName: (pathname: string, data: any, resolve: () => any, reject: (error: string) => any) => any
  27. }
  28. export interface IExludeRoles extends IProjectRoles {
  29. permission?: boolean
  30. }
  31. interface IPortalListStates {
  32. modalLoading: boolean
  33. formType: 'edit' | 'add'
  34. formVisible: boolean
  35. exludeRoles: IExludeRoles[]
  36. }
  37. export class PortalList extends React.Component<IPortalListProps, IPortalListStates> {
  38. private portalForm: AntdFormType
  39. private refHandlers = {
  40. portalForm: (ref) => this.portalForm = ref
  41. }
  42. constructor (props: IPortalListProps) {
  43. super(props)
  44. this.state = {
  45. modalLoading: false,
  46. formType: 'add',
  47. formVisible: false,
  48. exludeRoles: []
  49. }
  50. }
  51. private stopPPG = (e) => {
  52. e.stopPropagation()
  53. }
  54. private delegate = (func: (...args) => void, ...args) => (e: React.MouseEvent) => {
  55. func.apply(this, args)
  56. e.stopPropagation()
  57. }
  58. public componentWillReceiveProps (nextProps) {
  59. if (nextProps && nextProps.projectRoles) {
  60. this.setState({
  61. exludeRoles: nextProps.projectRoles.map((role) => {
  62. return {
  63. ...role,
  64. permission: false
  65. }
  66. })
  67. })
  68. }
  69. }
  70. private hidePortalForm = () => {
  71. this.setState({
  72. formVisible: false,
  73. modalLoading: false
  74. }, () => {
  75. this.portalForm.props.form.resetFields()
  76. })
  77. }
  78. private onModalOk = () => {
  79. this.portalForm.props.form.validateFieldsAndScroll((err, values) => {
  80. if (!err) {
  81. const { projectId, onAdd, onEdit } = this.props
  82. const { formType } = this.state
  83. const { id, name, description, publish, avatar } = values
  84. const val = {
  85. description,
  86. name,
  87. publish,
  88. roleIds: this.state.exludeRoles.filter((role) => !role.permission).map((p) => p.id),
  89. avatar: formType === 'add' ? `${Math.ceil(Math.random() * 19)}` : avatar
  90. }
  91. if (formType === 'add') {
  92. onAdd({
  93. ...val,
  94. projectId: Number(projectId)
  95. }, () => {
  96. this.hidePortalForm()
  97. })
  98. } else {
  99. onEdit({
  100. ...val,
  101. id
  102. }, () => {
  103. this.hidePortalForm()
  104. })
  105. }
  106. }
  107. })
  108. }
  109. private showPortalForm = (formType: 'edit' | 'add', portal?: any) => (e: React.MouseEvent<HTMLDivElement>) => {
  110. e.stopPropagation()
  111. this.setState({
  112. formType,
  113. formVisible: true
  114. }, () => {
  115. setTimeout(() => {
  116. if (portal) {
  117. this.portalForm.props.form.setFieldsValue(portal)
  118. }
  119. }, 0)
  120. const { onExcludeRoles, projectRoles } = this.props
  121. if (onExcludeRoles && portal) {
  122. onExcludeRoles('portal', portal.id, (result: number[]) => {
  123. this.setState({
  124. exludeRoles: projectRoles.map((role) => {
  125. return result.some((re) => re === role.id) ? role : {...role, permission: true}
  126. })
  127. })
  128. })
  129. } else {
  130. this.setState({
  131. exludeRoles: this.state.exludeRoles.map((role) => {
  132. return {
  133. ...role,
  134. permission: true
  135. }
  136. })
  137. })
  138. }
  139. })
  140. }
  141. private changePermission = (scope: IExludeRoles, event) => {
  142. scope.permission = event.target.checked
  143. this.setState({
  144. exludeRoles: this.state.exludeRoles.map((role) => role && role.id === scope.id ? scope : role)
  145. })
  146. }
  147. private renderCreate () {
  148. return (
  149. <Col
  150. key="createPortal"
  151. xxl={4}
  152. xl={6}
  153. lg={8}
  154. md={12}
  155. sm={24}
  156. >
  157. <div className={styles.unit} onClick={this.showPortalForm('add')}>
  158. <div className={styles.central}>
  159. <div className={`${styles.item} ${styles.add}`}><Icon type="plus-circle-o" /></div>
  160. <div className={`${styles.item} ${styles.text}`}>创建新 仪表板</div>
  161. </div>
  162. </div>
  163. </Col>
  164. )
  165. }
  166. private renderPortal = (portal: any) => {
  167. const { onPortalClick, onDelete, currentProject } = this.props
  168. const editHint = !portal.publish && '(编辑中…)'
  169. const itemClass = classnames({
  170. [styles.unit]: true,
  171. [styles.editing]: !portal.publish
  172. })
  173. const EditIcon = ModulePermission<IconProps>(currentProject, 'viz', false)(Icon)
  174. const AdminIcon = ModulePermission<IconProps>(currentProject, 'viz', true)(Icon)
  175. return (
  176. <Col
  177. key={portal.id}
  178. xxl={4}
  179. xl={6}
  180. lg={8}
  181. md={12}
  182. sm={24}
  183. onClick={onPortalClick(portal.id)}
  184. >
  185. <div
  186. className={itemClass}
  187. style={{ backgroundImage: `url(${require(`assets/images/bg${portal.avatar}.png`)}` }}
  188. >
  189. <header>
  190. <h3 className={styles.title}>
  191. {portal.name} {editHint}
  192. </h3>
  193. <p className={styles.content}>
  194. {portal.description}
  195. </p>
  196. </header>
  197. <div className={styles.portalActions}>
  198. <Tooltip title="编辑">
  199. <EditIcon className={styles.edit} type="setting" onClick={this.showPortalForm('edit', portal)} />
  200. </Tooltip>
  201. <Popconfirm
  202. title="确定删除?"
  203. placement="bottom"
  204. onConfirm={this.delegate(onDelete, portal.id)}
  205. >
  206. <Tooltip title="删除">
  207. <AdminIcon className={styles.delete} type="delete" onClick={this.stopPPG} />
  208. </Tooltip>
  209. </Popconfirm>
  210. </div>
  211. </div>
  212. </Col>
  213. )
  214. }
  215. public render () {
  216. const {
  217. projectId,
  218. portals,
  219. currentProject,
  220. onCheckUniqueName
  221. } = this.props
  222. if (!Array.isArray(portals)) { return null }
  223. const {
  224. formType,
  225. formVisible,
  226. modalLoading
  227. } = this.state
  228. const modalButtons = [(
  229. <Button
  230. key="back"
  231. size="large"
  232. onClick={this.hidePortalForm}
  233. >
  234. 取 消
  235. </Button>
  236. ), (
  237. <Button
  238. key="submit"
  239. size="large"
  240. type="primary"
  241. loading={modalLoading}
  242. disabled={modalLoading}
  243. onClick={this.onModalOk}
  244. >
  245. 保 存
  246. </Button>
  247. )]
  248. let addAction
  249. if (currentProject && currentProject.permission) {
  250. const vizPermission = currentProject.permission.vizPermission
  251. addAction = vizPermission === 3
  252. ? [this.renderCreate(), ...portals.map((p) => this.renderPortal(p))]
  253. : [...portals.map((p) => this.renderPortal(p))]
  254. }
  255. return (
  256. <div>
  257. <Row
  258. gutter={20}
  259. >
  260. {addAction}
  261. </Row>
  262. <Modal
  263. title={`${formType === 'add' ? '新增' : '修改'} 入口`}
  264. wrapClassName="ant-modal-small"
  265. visible={formVisible}
  266. footer={modalButtons}
  267. onCancel={this.hidePortalForm}
  268. >
  269. <PortalForm
  270. type={formType}
  271. onCheckUniqueName={onCheckUniqueName}
  272. projectId={projectId}
  273. exludeRoles={this.state.exludeRoles}
  274. onChangePermission={this.changePermission}
  275. wrappedComponentRef={this.refHandlers.portalForm}
  276. />
  277. </Modal>
  278. </div>
  279. )
  280. }
  281. }
  282. const mapStateToProps = createStructuredSelector({
  283. projectRoles: makeSelectProjectRoles()
  284. })
  285. const withConnect = connect(mapStateToProps, null)
  286. export default compose(
  287. withConnect
  288. )(PortalList)