Files
2024-03-01 20:28:14 +08:00

445 lines
13 KiB
JavaScript

import React, { PureComponent as Component } from 'react';
import {
Table,
Card,
Badge,
Select,
Button,
Modal,
Row,
Col,
message,
Popconfirm,
Switch,
Tooltip
} from 'antd';
import PropTypes from 'prop-types';
import { fetchGroupMsg } from '../../../../reducer/modules/group';
import { connect } from 'react-redux';
import ErrMsg from '../../../../components/ErrMsg/ErrMsg.js';
import { fetchGroupMemberList } from '../../../../reducer/modules/group.js';
import {
fetchProjectList,
getProjectMemberList,
getProject,
addMember,
delMember,
changeMemberRole,
changeMemberEmailNotice
} from '../../../../reducer/modules/project.js';
import UsernameAutoComplete from '../../../../components/UsernameAutoComplete/UsernameAutoComplete.js';
import '../Setting.scss';
const Option = Select.Option;
const arrayAddKey = arr => {
return arr.map((item, index) => {
return {
...item,
key: index
};
});
};
@connect(
state => {
return {
projectMsg: state.project.currProject,
uid: state.user.uid,
projectList: state.project.projectList
};
},
{
fetchGroupMemberList,
getProjectMemberList,
addMember,
delMember,
fetchGroupMsg,
changeMemberRole,
getProject,
fetchProjectList,
changeMemberEmailNotice
}
)
class ProjectMember extends Component {
constructor(props) {
super(props);
this.state = {
groupMemberList: [],
projectMemberList: [],
groupName: '',
role: '',
visible: false,
dataSource: [],
inputUids: [],
inputRole: 'dev',
modalVisible: false,
selectProjectId: 0
};
}
static propTypes = {
match: PropTypes.object,
projectId: PropTypes.number,
projectMsg: PropTypes.object,
uid: PropTypes.number,
addMember: PropTypes.func,
delMember: PropTypes.func,
changeMemberRole: PropTypes.func,
getProject: PropTypes.func,
fetchGroupMemberList: PropTypes.func,
fetchGroupMsg: PropTypes.func,
getProjectMemberList: PropTypes.func,
fetchProjectList: PropTypes.func,
projectList: PropTypes.array,
changeMemberEmailNotice: PropTypes.func
};
showAddMemberModal = () => {
this.setState({
visible: true
});
};
showImportMemberModal = async () => {
await this.props.fetchProjectList(this.props.projectMsg.group_id);
this.setState({
modalVisible: true
});
};
// 重新获取列表
reFetchList = () => {
this.props.getProjectMemberList(this.props.match.params.id).then(res => {
this.setState({
projectMemberList: arrayAddKey(res.payload.data.data),
visible: false,
modalVisible: false
});
});
};
handleOk = () => {
this.addMembers(this.state.inputUids);
};
// 增 - 添加成员
addMembers = memberUids => {
this.props
.addMember({
id: this.props.match.params.id,
member_uids: memberUids,
role: this.state.inputRole
})
.then(res => {
if (!res.payload.data.errcode) {
const { add_members, exist_members } = res.payload.data.data;
const addLength = add_members.length;
const existLength = exist_members.length;
this.setState({
inputRole: 'dev',
inputUids: []
});
message.success(`添加成功! 已成功添加 ${addLength} 人,其中 ${existLength} 人已存在`);
this.reFetchList(); // 添加成功后重新获取分组成员列表
}
});
};
// 添加成员时 选择新增成员权限
changeNewMemberRole = value => {
this.setState({
inputRole: value
});
};
// 删 - 删除分组成员
deleteConfirm = member_uid => {
return () => {
const id = this.props.match.params.id;
this.props.delMember({ id, member_uid }).then(res => {
if (!res.payload.data.errcode) {
message.success(res.payload.data.errmsg);
this.reFetchList(); // 添加成功后重新获取分组成员列表
}
});
};
};
// 改 - 修改成员权限
changeUserRole = e => {
const id = this.props.match.params.id;
const role = e.split('-')[0];
const member_uid = e.split('-')[1];
this.props.changeMemberRole({ id, member_uid, role }).then(res => {
if (!res.payload.data.errcode) {
message.success(res.payload.data.errmsg);
this.reFetchList(); // 添加成功后重新获取分组成员列表
}
});
};
// 修改用户是否接收消息通知
changeEmailNotice = async (notice, member_uid) => {
const id = this.props.match.params.id;
await this.props.changeMemberEmailNotice({ id, member_uid, notice });
this.reFetchList(); // 添加成功后重新获取项目成员列表
};
// 关闭模态框
handleCancel = () => {
this.setState({
visible: false
});
};
// 关闭批量导入模态框
handleModalCancel = () => {
this.setState({
modalVisible: false
});
};
// 处理选择项目
handleChange = key => {
this.setState({
selectProjectId: key
});
};
// 确定批量导入模态框
handleModalOk = async () => {
// 获取项目中的成员列表
const menberList = await this.props.getProjectMemberList(this.state.selectProjectId);
const memberUidList = menberList.payload.data.data.map(item => {
return item.uid;
});
this.addMembers(memberUidList);
};
onUserSelect = uids => {
this.setState({
inputUids: uids
});
};
async UNSAFE_componentWillMount() {
const groupMemberList = await this.props.fetchGroupMemberList(this.props.projectMsg.group_id);
const groupMsg = await this.props.fetchGroupMsg(this.props.projectMsg.group_id);
const projectMemberList = await this.props.getProjectMemberList(this.props.match.params.id);
this.setState({
groupMemberList: groupMemberList.payload.data.data,
groupName: groupMsg.payload.data.data.group_name,
projectMemberList: arrayAddKey(projectMemberList.payload.data.data),
role: this.props.projectMsg.role
});
}
render() {
const isEmailChangeEable = this.state.role === 'owner' || this.state.role === 'admin';
const columns = [
{
title:
this.props.projectMsg.name + ' 项目成员 (' + this.state.projectMemberList.length + ') 人',
dataIndex: 'username',
key: 'username',
render: (text, record) => {
return (
<div className="m-user">
<img src={'/api/user/avatar?uid=' + record.uid} className="m-user-img" />
<p className="m-user-name">{text}</p>
<Tooltip placement="top" title="消息通知">
<span>
<Switch
size="small"
checkedChildren="开"
unCheckedChildren="关"
checked={record.email_notice}
disabled={!(isEmailChangeEable || record.uid === this.props.uid)}
onChange={e => this.changeEmailNotice(e, record.uid)}
/>
</span>
</Tooltip>
</div>
);
}
},
{
title:
this.state.role === 'owner' || this.state.role === 'admin' ? (
<div className="btn-container">
<Button className="btn" type="primary" icon="plus" onClick={this.showAddMemberModal}>
添加成员
</Button>
<Button className="btn" icon="plus" onClick={this.showImportMemberModal}>
批量导入成员
</Button>
</div>
) : (
''
),
key: 'action',
className: 'member-opration',
render: (text, record) => {
if (this.state.role === 'owner' || this.state.role === 'admin') {
return (
<div>
<Select
value={record.role + '-' + record.uid}
className="select"
onChange={this.changeUserRole}
>
<Option value={'owner-' + record.uid}>组长</Option>
<Option value={'dev-' + record.uid}>开发者</Option>
<Option value={'guest-' + record.uid}>访客</Option>
</Select>
<Popconfirm
placement="topRight"
title="你确定要删除吗? "
onConfirm={this.deleteConfirm(record.uid)}
okText="确定"
cancelText=""
>
<Button type="danger" icon="delete" className="btn-danger" />
</Popconfirm>
</div>
);
} else {
// 非管理员可以看到权限 但无法修改
if (record.role === 'owner') {
return '组长';
} else if (record.role === 'dev') {
return '开发者';
} else if (record.role === 'guest') {
return '访客';
} else {
return '';
}
}
}
}
];
// 获取当前分组下的所有项目名称
const children = this.props.projectList.map((item, index) => (
<Option key={index} value={'' + item._id}>
{item.name}
</Option>
));
return (
<div className="g-row">
<div className="m-panel">
{this.state.visible ? (
<Modal
title="添加成员"
visible={this.state.visible}
onOk={this.handleOk}
onCancel={this.handleCancel}
>
<Row gutter={6} className="modal-input">
<Col span="5">
<div className="label usernamelabel">用户名: </div>
</Col>
<Col span="15">
<UsernameAutoComplete callbackState={this.onUserSelect} />
</Col>
</Row>
<Row gutter={6} className="modal-input">
<Col span="5">
<div className="label usernamelabel">权限: </div>
</Col>
<Col span="15">
<Select defaultValue="dev" className="select" onChange={this.changeNewMemberRole}>
<Option value="owner">组长</Option>
<Option value="dev">开发者</Option>
<Option value="guest">访客</Option>
</Select>
</Col>
</Row>
</Modal>
) : (
''
)}
<Modal
title="批量导入成员"
visible={this.state.modalVisible}
onOk={this.handleModalOk}
onCancel={this.handleModalCancel}
>
<Row gutter={6} className="modal-input">
<Col span="5">
<div className="label usernamelabel">项目名: </div>
</Col>
<Col span="15">
<Select
showSearch
style={{ width: 200 }}
placeholder="请选择项目名称"
optionFilterProp="children"
onChange={this.handleChange}
>
{children}
</Select>
</Col>
</Row>
</Modal>
<Table
columns={columns}
dataSource={this.state.projectMemberList}
pagination={false}
locale={{ emptyText: <ErrMsg type="noMemberInProject" /> }}
className="setting-project-member"
/>
<Card
bordered={false}
title={
this.state.groupName + ' 分组成员 ' + '(' + this.state.groupMemberList.length + ') 人'
}
hoverable={true}
className="setting-group"
>
{this.state.groupMemberList.length ? (
this.state.groupMemberList.map((item, index) => {
return (
<div key={index} className="card-item">
<img
src={
location.protocol +
'//' +
location.host +
'/api/user/avatar?uid=' +
item.uid
}
className="item-img"
/>
<p className="item-name">
{item.username}
{item.uid === this.props.uid ? (
<Badge
count={'我'}
style={{
backgroundColor: '#689bd0',
fontSize: '13px',
marginLeft: '8px',
borderRadius: '4px'
}}
/>
) : null}
</p>
{item.role === 'owner' ? <p className="item-role">组长</p> : null}
{item.role === 'dev' ? <p className="item-role">开发者</p> : null}
{item.role === 'guest' ? <p className="item-role">访客</p> : null}
</div>
);
})
) : (
<ErrMsg type="noMemberInGroup" />
)}
</Card>
</div>
</div>
);
}
}
export default ProjectMember;