mock平台

ProjectMember.js 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. import React, { PureComponent as Component } from 'react';
  2. import {
  3. Table,
  4. Card,
  5. Badge,
  6. Select,
  7. Button,
  8. Modal,
  9. Row,
  10. Col,
  11. message,
  12. Popconfirm,
  13. Switch,
  14. Tooltip
  15. } from 'antd';
  16. import PropTypes from 'prop-types';
  17. import { fetchGroupMsg } from '../../../../reducer/modules/group';
  18. import { connect } from 'react-redux';
  19. import ErrMsg from '../../../../components/ErrMsg/ErrMsg.js';
  20. import { fetchGroupMemberList } from '../../../../reducer/modules/group.js';
  21. import {
  22. fetchProjectList,
  23. getProjectMemberList,
  24. getProject,
  25. addMember,
  26. delMember,
  27. changeMemberRole,
  28. changeMemberEmailNotice
  29. } from '../../../../reducer/modules/project.js';
  30. import UsernameAutoComplete from '../../../../components/UsernameAutoComplete/UsernameAutoComplete.js';
  31. import '../Setting.scss';
  32. const Option = Select.Option;
  33. const arrayAddKey = arr => {
  34. return arr.map((item, index) => {
  35. return {
  36. ...item,
  37. key: index
  38. };
  39. });
  40. };
  41. @connect(
  42. state => {
  43. return {
  44. projectMsg: state.project.currProject,
  45. uid: state.user.uid,
  46. projectList: state.project.projectList
  47. };
  48. },
  49. {
  50. fetchGroupMemberList,
  51. getProjectMemberList,
  52. addMember,
  53. delMember,
  54. fetchGroupMsg,
  55. changeMemberRole,
  56. getProject,
  57. fetchProjectList,
  58. changeMemberEmailNotice
  59. }
  60. )
  61. class ProjectMember extends Component {
  62. constructor(props) {
  63. super(props);
  64. this.state = {
  65. groupMemberList: [],
  66. projectMemberList: [],
  67. groupName: '',
  68. role: '',
  69. visible: false,
  70. dataSource: [],
  71. inputUids: [],
  72. inputRole: 'dev',
  73. modalVisible: false,
  74. selectProjectId: 0
  75. };
  76. }
  77. static propTypes = {
  78. match: PropTypes.object,
  79. projectId: PropTypes.number,
  80. projectMsg: PropTypes.object,
  81. uid: PropTypes.number,
  82. addMember: PropTypes.func,
  83. delMember: PropTypes.func,
  84. changeMemberRole: PropTypes.func,
  85. getProject: PropTypes.func,
  86. fetchGroupMemberList: PropTypes.func,
  87. fetchGroupMsg: PropTypes.func,
  88. getProjectMemberList: PropTypes.func,
  89. fetchProjectList: PropTypes.func,
  90. projectList: PropTypes.array,
  91. changeMemberEmailNotice: PropTypes.func
  92. };
  93. showAddMemberModal = () => {
  94. this.setState({
  95. visible: true
  96. });
  97. };
  98. showImportMemberModal = async () => {
  99. await this.props.fetchProjectList(this.props.projectMsg.group_id);
  100. this.setState({
  101. modalVisible: true
  102. });
  103. };
  104. // 重新获取列表
  105. reFetchList = () => {
  106. this.props.getProjectMemberList(this.props.match.params.id).then(res => {
  107. this.setState({
  108. projectMemberList: arrayAddKey(res.payload.data.data),
  109. visible: false,
  110. modalVisible: false
  111. });
  112. });
  113. };
  114. handleOk = () => {
  115. this.addMembers(this.state.inputUids);
  116. };
  117. // 增 - 添加成员
  118. addMembers = memberUids => {
  119. this.props
  120. .addMember({
  121. id: this.props.match.params.id,
  122. member_uids: memberUids,
  123. role: this.state.inputRole
  124. })
  125. .then(res => {
  126. if (!res.payload.data.errcode) {
  127. const { add_members, exist_members } = res.payload.data.data;
  128. const addLength = add_members.length;
  129. const existLength = exist_members.length;
  130. this.setState({
  131. inputRole: 'dev',
  132. inputUids: []
  133. });
  134. message.success(`添加成功! 已成功添加 ${addLength} 人,其中 ${existLength} 人已存在`);
  135. this.reFetchList(); // 添加成功后重新获取分组成员列表
  136. }
  137. });
  138. };
  139. // 添加成员时 选择新增成员权限
  140. changeNewMemberRole = value => {
  141. this.setState({
  142. inputRole: value
  143. });
  144. };
  145. // 删 - 删除分组成员
  146. deleteConfirm = member_uid => {
  147. return () => {
  148. const id = this.props.match.params.id;
  149. this.props.delMember({ id, member_uid }).then(res => {
  150. if (!res.payload.data.errcode) {
  151. message.success(res.payload.data.errmsg);
  152. this.reFetchList(); // 添加成功后重新获取分组成员列表
  153. }
  154. });
  155. };
  156. };
  157. // 改 - 修改成员权限
  158. changeUserRole = e => {
  159. const id = this.props.match.params.id;
  160. const role = e.split('-')[0];
  161. const member_uid = e.split('-')[1];
  162. this.props.changeMemberRole({ id, member_uid, role }).then(res => {
  163. if (!res.payload.data.errcode) {
  164. message.success(res.payload.data.errmsg);
  165. this.reFetchList(); // 添加成功后重新获取分组成员列表
  166. }
  167. });
  168. };
  169. // 修改用户是否接收消息通知
  170. changeEmailNotice = async (notice, member_uid) => {
  171. const id = this.props.match.params.id;
  172. await this.props.changeMemberEmailNotice({ id, member_uid, notice });
  173. this.reFetchList(); // 添加成功后重新获取项目成员列表
  174. };
  175. // 关闭模态框
  176. handleCancel = () => {
  177. this.setState({
  178. visible: false
  179. });
  180. };
  181. // 关闭批量导入模态框
  182. handleModalCancel = () => {
  183. this.setState({
  184. modalVisible: false
  185. });
  186. };
  187. // 处理选择项目
  188. handleChange = key => {
  189. this.setState({
  190. selectProjectId: key
  191. });
  192. };
  193. // 确定批量导入模态框
  194. handleModalOk = async () => {
  195. // 获取项目中的成员列表
  196. const menberList = await this.props.getProjectMemberList(this.state.selectProjectId);
  197. const memberUidList = menberList.payload.data.data.map(item => {
  198. return item.uid;
  199. });
  200. this.addMembers(memberUidList);
  201. };
  202. onUserSelect = uids => {
  203. this.setState({
  204. inputUids: uids
  205. });
  206. };
  207. async componentWillMount() {
  208. const groupMemberList = await this.props.fetchGroupMemberList(this.props.projectMsg.group_id);
  209. const groupMsg = await this.props.fetchGroupMsg(this.props.projectMsg.group_id);
  210. const projectMemberList = await this.props.getProjectMemberList(this.props.match.params.id);
  211. this.setState({
  212. groupMemberList: groupMemberList.payload.data.data,
  213. groupName: groupMsg.payload.data.data.group_name,
  214. projectMemberList: arrayAddKey(projectMemberList.payload.data.data),
  215. role: this.props.projectMsg.role
  216. });
  217. }
  218. render() {
  219. const isEmailChangeEable = this.state.role === 'owner' || this.state.role === 'admin';
  220. const columns = [
  221. {
  222. title:
  223. this.props.projectMsg.name + ' 项目成员 (' + this.state.projectMemberList.length + ') 人',
  224. dataIndex: 'username',
  225. key: 'username',
  226. render: (text, record) => {
  227. return (
  228. <div className="m-user">
  229. <img src={'/api/user/avatar?uid=' + record.uid} className="m-user-img" />
  230. <p className="m-user-name">{text}</p>
  231. <Tooltip placement="top" title="消息通知">
  232. <span>
  233. <Switch
  234. size="small"
  235. checkedChildren="开"
  236. unCheckedChildren="关"
  237. checked={record.email_notice}
  238. disabled={!(isEmailChangeEable || record.uid === this.props.uid)}
  239. onChange={e => this.changeEmailNotice(e, record.uid)}
  240. />
  241. </span>
  242. </Tooltip>
  243. </div>
  244. );
  245. }
  246. },
  247. {
  248. title:
  249. this.state.role === 'owner' || this.state.role === 'admin' ? (
  250. <div className="btn-container">
  251. <Button className="btn" type="primary" icon="plus" onClick={this.showAddMemberModal}>
  252. 添加成员
  253. </Button>
  254. <Button className="btn" icon="plus" onClick={this.showImportMemberModal}>
  255. 批量导入成员
  256. </Button>
  257. </div>
  258. ) : (
  259. ''
  260. ),
  261. key: 'action',
  262. className: 'member-opration',
  263. render: (text, record) => {
  264. if (this.state.role === 'owner' || this.state.role === 'admin') {
  265. return (
  266. <div>
  267. <Select
  268. value={record.role + '-' + record.uid}
  269. className="select"
  270. onChange={this.changeUserRole}
  271. >
  272. <Option value={'owner-' + record.uid}>组长</Option>
  273. <Option value={'dev-' + record.uid}>开发者</Option>
  274. <Option value={'guest-' + record.uid}>访客</Option>
  275. </Select>
  276. <Popconfirm
  277. placement="topRight"
  278. title="你确定要删除吗? "
  279. onConfirm={this.deleteConfirm(record.uid)}
  280. okText="确定"
  281. cancelText=""
  282. >
  283. <Button type="danger" icon="delete" className="btn-danger" />
  284. </Popconfirm>
  285. </div>
  286. );
  287. } else {
  288. // 非管理员可以看到权限 但无法修改
  289. if (record.role === 'owner') {
  290. return '组长';
  291. } else if (record.role === 'dev') {
  292. return '开发者';
  293. } else if (record.role === 'guest') {
  294. return '访客';
  295. } else {
  296. return '';
  297. }
  298. }
  299. }
  300. }
  301. ];
  302. // 获取当前分组下的所有项目名称
  303. const children = this.props.projectList.map((item, index) => (
  304. <Option key={index} value={'' + item._id}>
  305. {item.name}
  306. </Option>
  307. ));
  308. return (
  309. <div className="g-row">
  310. <div className="m-panel">
  311. {this.state.visible ? (
  312. <Modal
  313. title="添加成员"
  314. visible={this.state.visible}
  315. onOk={this.handleOk}
  316. onCancel={this.handleCancel}
  317. >
  318. <Row gutter={6} className="modal-input">
  319. <Col span="5">
  320. <div className="label usernamelabel">用户名: </div>
  321. </Col>
  322. <Col span="15">
  323. <UsernameAutoComplete callbackState={this.onUserSelect} />
  324. </Col>
  325. </Row>
  326. <Row gutter={6} className="modal-input">
  327. <Col span="5">
  328. <div className="label usernamelabel">权限: </div>
  329. </Col>
  330. <Col span="15">
  331. <Select defaultValue="dev" className="select" onChange={this.changeNewMemberRole}>
  332. <Option value="owner">组长</Option>
  333. <Option value="dev">开发者</Option>
  334. <Option value="guest">访客</Option>
  335. </Select>
  336. </Col>
  337. </Row>
  338. </Modal>
  339. ) : (
  340. ''
  341. )}
  342. <Modal
  343. title="批量导入成员"
  344. visible={this.state.modalVisible}
  345. onOk={this.handleModalOk}
  346. onCancel={this.handleModalCancel}
  347. >
  348. <Row gutter={6} className="modal-input">
  349. <Col span="5">
  350. <div className="label usernamelabel">项目名: </div>
  351. </Col>
  352. <Col span="15">
  353. <Select
  354. showSearch
  355. style={{ width: 200 }}
  356. placeholder="请选择项目名称"
  357. optionFilterProp="children"
  358. onChange={this.handleChange}
  359. >
  360. {children}
  361. </Select>
  362. </Col>
  363. </Row>
  364. </Modal>
  365. <Table
  366. columns={columns}
  367. dataSource={this.state.projectMemberList}
  368. pagination={false}
  369. locale={{ emptyText: <ErrMsg type="noMemberInProject" /> }}
  370. className="setting-project-member"
  371. />
  372. <Card
  373. bordered={false}
  374. title={
  375. this.state.groupName + ' 分组成员 ' + '(' + this.state.groupMemberList.length + ') 人'
  376. }
  377. hoverable={true}
  378. className="setting-group"
  379. >
  380. {this.state.groupMemberList.length ? (
  381. this.state.groupMemberList.map((item, index) => {
  382. return (
  383. <div key={index} className="card-item">
  384. <img
  385. src={
  386. location.protocol +
  387. '//' +
  388. location.host +
  389. '/api/user/avatar?uid=' +
  390. item.uid
  391. }
  392. className="item-img"
  393. />
  394. <p className="item-name">
  395. {item.username}
  396. {item.uid === this.props.uid ? (
  397. <Badge
  398. count={'我'}
  399. style={{
  400. backgroundColor: '#689bd0',
  401. fontSize: '13px',
  402. marginLeft: '8px',
  403. borderRadius: '4px'
  404. }}
  405. />
  406. ) : null}
  407. </p>
  408. {item.role === 'owner' ? <p className="item-role">组长</p> : null}
  409. {item.role === 'dev' ? <p className="item-role">开发者</p> : null}
  410. {item.role === 'guest' ? <p className="item-role">访客</p> : null}
  411. </div>
  412. );
  413. })
  414. ) : (
  415. <ErrMsg type="noMemberInGroup" />
  416. )}
  417. </Card>
  418. </div>
  419. </div>
  420. );
  421. }
  422. }
  423. export default ProjectMember;