MemberList.tsx 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  1. /*
  2. * <<
  3. * Davinci
  4. * ==
  5. * Copyright (C) 2016 - 2017 EDP
  6. * ==
  7. * Licensed under the Apache License, Version 2.0 (the "License");
  8. * you may not use this file except in compliance with the License.
  9. * You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS,
  15. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. * See the License for the specific language governing permissions and
  17. * limitations under the License.
  18. * >>
  19. */
  20. import React from 'react'
  21. import FormType, { WrappedFormUtils } from 'antd/lib/form/Form'
  22. import {
  23. Row,
  24. Col,
  25. Tooltip,
  26. Button,
  27. Input,
  28. Popconfirm,
  29. Modal,
  30. Table,
  31. Tag,
  32. Popover,
  33. Icon
  34. } from 'antd'
  35. const styles = require('../Organization.less')
  36. const utilStyles = require('assets/less/util.less')
  37. import MemberForm from './AddForm'
  38. import Avatar from 'components/Avatar'
  39. import ChangeRoleForm from './ChangeRoleForm'
  40. import ComponentPermission from 'containers/Account/components/checkMemberPermission'
  41. import {
  42. IOrganizationMember,
  43. IMembersState,
  44. IMembersProps,
  45. IMembers,
  46. ISetRange
  47. } from '../types'
  48. import NotUsersList from './NotUsersList'
  49. export class MemberList extends React.PureComponent<
  50. IMembersProps,
  51. IMembersState
  52. > {
  53. constructor(props) {
  54. super(props)
  55. this.state = {
  56. formKey: 0,
  57. category: '',
  58. changeRoleFormCategory: '',
  59. currentMember: null,
  60. formVisible: false,
  61. modalLoading: false,
  62. notUsersModalVisible: false,
  63. notUsers: [],
  64. changeRoleFormVisible: false,
  65. changeRoleModalLoading: false,
  66. organizationMembers: [],
  67. currentMemberId: 0,
  68. keywords: ''
  69. }
  70. }
  71. private MemberForm: WrappedFormUtils
  72. private ChangeRoleForm: FormType
  73. private refHandles = {
  74. MemberForm: (ref) => (this.MemberForm = ref),
  75. ChangeRoleForm: (ref) => (this.ChangeRoleForm = ref)
  76. }
  77. private showMemberForm = (type: string) => (e) => {
  78. e.stopPropagation()
  79. this.setState({
  80. category: type,
  81. formVisible: true
  82. })
  83. }
  84. private showChangeRoleForm = (type: string, member: IOrganizationMember) => (
  85. e
  86. ) => {
  87. e.stopPropagation()
  88. this.setState(
  89. {
  90. currentMember: member,
  91. changeRoleFormVisible: true,
  92. changeRoleFormCategory: type
  93. },
  94. () => {
  95. setTimeout(() => {
  96. const {
  97. user: { role },
  98. id
  99. } = member
  100. this.ChangeRoleForm.props.form.setFieldsValue({ id, role })
  101. }, 0)
  102. }
  103. )
  104. }
  105. private hideMemberForm = () => {
  106. this.setState({
  107. formKey: this.state.formKey + 10,
  108. formVisible: false,
  109. modalLoading: false
  110. })
  111. }
  112. private afterMemberFormClose = () => {
  113. this.MemberForm.resetFields()
  114. }
  115. private removeMemberForm = (text, obj) => () => {
  116. this.props.deleteOrganizationMember(obj.id, () => {
  117. const { organizationId } = this.props
  118. if (this.props.loadOrganizationsMembers) {
  119. this.props.loadOrganizationsMembers(Number(organizationId))
  120. }
  121. })
  122. }
  123. private changRole = () => {
  124. this.ChangeRoleForm.props.form.validateFieldsAndScroll((err, values) => {
  125. if (!err) {
  126. const { id, role } = values
  127. this.props.changeOrganizationMemberRole(id, role, () => {
  128. const { organizationId } = this.props
  129. if (this.props.loadOrganizationsMembers) {
  130. this.props.loadOrganizationsMembers(Number(organizationId))
  131. }
  132. this.hideChangeRoleForm()
  133. })
  134. }
  135. })
  136. }
  137. private add = () => {
  138. const { currentOrganization } = this.props
  139. this.MemberForm.validateFieldsAndScroll((err, values) => {
  140. if (!err) {
  141. const { members, needEmail } = values
  142. const orgId = currentOrganization.id
  143. this.props.onInviteMember(orgId, members, needEmail, (result) => {
  144. if (result && result.notUsers.length) {
  145. this.setState({
  146. notUsersModalVisible: true,
  147. notUsers: result.notUsers
  148. })
  149. }
  150. this.props.loadOrganizationsMembers(Number(orgId))
  151. })
  152. this.hideMemberForm()
  153. }
  154. })
  155. }
  156. private search = (event) => {
  157. const value = event.target.value
  158. const { organizationMembers } = this.props
  159. const result = this.getOrgMembersBysearch(organizationMembers, value)
  160. this.updateOrganizationMembers(
  161. value && value.length ? result : this.props.organizationMembers
  162. )
  163. this.setState({ keywords: value })
  164. }
  165. private getOrgMembersBysearch(
  166. orgMembers: IOrganizationMember[],
  167. keywords: string
  168. ) {
  169. return orgMembers.filter((member) => {
  170. return member?.user?.username?.indexOf(keywords.trim()) > -1
  171. })
  172. }
  173. public updateOrganizationMembers = (orgMembers) => {
  174. this.setState({ organizationMembers: orgMembers })
  175. }
  176. public componentDidMount() {
  177. const { organizationMembers } = this.props
  178. if (organizationMembers) {
  179. this.updateOrganizationMembers(organizationMembers)
  180. }
  181. }
  182. public componentWillReceiveProps(nextProps) {
  183. const { keywords } = this.state
  184. const { organizationMembers } = this.props
  185. const nextOrgMembers = nextProps.organizationMembers
  186. if (nextOrgMembers && nextOrgMembers !== organizationMembers) {
  187. keywords && keywords.length
  188. ? this.updateOrganizationMembers(
  189. this.getOrgMembersBysearch(nextOrgMembers, keywords)
  190. )
  191. : this.updateOrganizationMembers(nextOrgMembers)
  192. }
  193. }
  194. private hideNotUsersModal = () => {
  195. this.setState({
  196. notUsersModalVisible: false
  197. })
  198. }
  199. private searchMember = (searchValue: string) => {
  200. if (searchValue && searchValue.length) {
  201. this.props.handleSearchMember(searchValue)
  202. }
  203. }
  204. private hideChangeRoleForm = () => {
  205. this.setState({
  206. changeRoleFormVisible: false,
  207. changeRoleModalLoading: false
  208. })
  209. }
  210. private afterChangeRoleFormClose = () => {
  211. this.ChangeRoleForm.props.form.resetFields()
  212. }
  213. private getContent(record: IMembers) {
  214. const { id } = record
  215. const { currentMemberId, organizationMembers } = this.state
  216. const content = <Icon type="loading" />
  217. if (currentMemberId !== id) {
  218. return content
  219. } else {
  220. const member = organizationMembers.find(
  221. (member) => member.id === currentMemberId
  222. )
  223. const { roles } = member
  224. return Array.isArray(roles) && roles.length
  225. ? this.getRoleTags(roles)
  226. : '暂无角色'
  227. }
  228. }
  229. private getRoleTags(text) {
  230. return text.map((t) => <Tag key={`ind${t.name}ex`}>{t.name}</Tag>)
  231. }
  232. private getRoleList = (record: IMembers) => () => {
  233. const { onGetRoleListByMemberId, organizationId } = this.props
  234. const { user, id } = record
  235. onGetRoleListByMemberId(organizationId, user.id, () => {
  236. this.setState({
  237. currentMemberId: id
  238. })
  239. })
  240. }
  241. private getPagination() {
  242. const { organizationMembers } = this.props
  243. return {
  244. defaultCurrent: 1,
  245. defaultPageSize: 10,
  246. showSizeChanger: true,
  247. pageSizeOptions: ['10', '20', '50', '100'],
  248. total: organizationMembers.length,
  249. showTotal: (total) => `共 ${total} 条`
  250. }
  251. }
  252. public render() {
  253. const {
  254. formVisible,
  255. category,
  256. currentMember,
  257. modalLoading,
  258. changeRoleFormVisible,
  259. changeRoleModalLoading,
  260. changeRoleFormCategory,
  261. organizationMembers,
  262. notUsersModalVisible,
  263. notUsers
  264. } = this.state
  265. const { inviteMemberList, currentOrganization, loginUser } = this.props
  266. let CreateButton = void 0
  267. if (currentOrganization) {
  268. CreateButton = ComponentPermission(currentOrganization, '')(Button)
  269. }
  270. const addButton = (
  271. <Tooltip placement="bottom" title="邀请">
  272. <CreateButton
  273. type="primary"
  274. icon="plus"
  275. onClick={this.showMemberForm('member')}
  276. />
  277. </Tooltip>
  278. )
  279. const columns = [
  280. {
  281. title: '姓名',
  282. dataIndex: 'user',
  283. key: 'user',
  284. render: (text) => (
  285. <div className={styles.avatarWrapper}>
  286. <Avatar path={text.avatar} size="small" border enlarge={true} />
  287. <span
  288. className={styles.avatarName}
  289. >
  290. {text.username}
  291. </span>
  292. </div>
  293. )
  294. },
  295. {
  296. title: '成员类型',
  297. dataIndex: 'user',
  298. key: 'userKey',
  299. render: (text) => <span>{text.role === 1 ? '拥有者' : '成员'}</span>
  300. },
  301. {
  302. title: '设置',
  303. dataIndex: 'user',
  304. key: 'settings',
  305. width: 300,
  306. render: (text, record) => {
  307. return (
  308. <span>
  309. <Popover title="角色列表" content={this.getContent(record)}>
  310. <a href="javascript:;" onMouseEnter={this.getRoleList(record)}>
  311. 获取角色列表
  312. </a>
  313. </Popover>
  314. {record?.user?.id !== loginUser.id ? (
  315. currentOrganization?.role === 1 ? (
  316. <>
  317. <span className="ant-divider" />
  318. <a
  319. href="javascript:;"
  320. onClick={this.showChangeRoleForm('orgMember', record)}
  321. >
  322. 更改成员类型
  323. </a>
  324. <span className="ant-divider" />
  325. <Popconfirm
  326. title="确定删除?"
  327. placement="bottom"
  328. onConfirm={this.removeMemberForm(text, record)}
  329. >
  330. <a href="javascript:;">移除成员</a>
  331. </Popconfirm>
  332. </>
  333. ) : (
  334. ''
  335. )
  336. ) : (
  337. ''
  338. )}
  339. </span>
  340. )
  341. }
  342. }
  343. ]
  344. const pagination = this.getPagination()
  345. return (
  346. <div className={styles.listWrapper}>
  347. <Row>
  348. <Col span={16}>
  349. <Input.Search placeholder="搜索成员" onChange={this.search} />
  350. </Col>
  351. <Col span={1} offset={7}>
  352. {addButton}
  353. </Col>
  354. </Row>
  355. <Row>
  356. <div className={styles.tableWrap}>
  357. <Table
  358. bordered
  359. rowKey="id"
  360. columns={columns}
  361. dataSource={organizationMembers}
  362. pagination={pagination}
  363. />
  364. </div>
  365. </Row>
  366. <Modal
  367. key={this.state.formKey}
  368. title={null}
  369. visible={formVisible}
  370. footer={null}
  371. onCancel={this.hideMemberForm}
  372. afterClose={this.afterMemberFormClose}
  373. >
  374. <MemberForm
  375. category={category}
  376. addHandler={this.add}
  377. inviteMemberList={inviteMemberList}
  378. handleSearchMember={this.searchMember}
  379. wrappedComponentRef={this.refHandles.MemberForm}
  380. organizationDetail={this.props.currentOrganization}
  381. />
  382. </Modal>
  383. <Modal
  384. title={null}
  385. visible={changeRoleFormVisible}
  386. footer={null}
  387. onCancel={this.hideChangeRoleForm}
  388. afterClose={this.afterChangeRoleFormClose}
  389. >
  390. <ChangeRoleForm
  391. member={currentMember}
  392. category={changeRoleFormCategory}
  393. organizationOrTeam={this.props.currentOrganization}
  394. submitLoading={changeRoleModalLoading}
  395. wrappedComponentRef={this.refHandles.ChangeRoleForm}
  396. changeHandler={this.changRole}
  397. />
  398. </Modal>
  399. <Modal
  400. title={null}
  401. visible={notUsersModalVisible}
  402. footer={null}
  403. onCancel={this.hideNotUsersModal}
  404. >
  405. <NotUsersList
  406. category={category}
  407. notUsers={notUsers}
  408. hideHandler={this.hideNotUsersModal}
  409. />
  410. </Modal>
  411. </div>
  412. )
  413. }
  414. }
  415. export default MemberList