new
This commit is contained in:
parent
26d2e0f541
commit
0c5dd61fdc
|
|
@ -0,0 +1,84 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { AutoComplete , Button , Icon } from 'antd';
|
||||
import axios from 'axios';
|
||||
|
||||
const { Option } = AutoComplete;
|
||||
function AddGroup({organizeId,getGroupID}){
|
||||
const [ id , setID ] = useState(undefined);
|
||||
const [ source , setSource ] = useState(undefined);
|
||||
const [ searchKey , setSearchKey ] = useState(undefined);
|
||||
|
||||
useEffect(()=>{
|
||||
getUserList();
|
||||
},[searchKey])
|
||||
|
||||
function getUserList(e){
|
||||
const url = `/organizations/${organizeId}/teams.json`;
|
||||
axios.get(url, {
|
||||
params: {
|
||||
search: searchKey,
|
||||
},
|
||||
}).then((result) => {
|
||||
if (result) {
|
||||
sourceOptions(result.data.teams);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
};
|
||||
|
||||
function sourceOptions(userDataSource){
|
||||
const s = userDataSource && userDataSource.map((item, key) => {
|
||||
return (
|
||||
<Option
|
||||
key={key}
|
||||
value={`${item.id}`}
|
||||
name={item.name}
|
||||
>
|
||||
{item.name}
|
||||
</Option>
|
||||
);
|
||||
});
|
||||
setSource(s);
|
||||
}
|
||||
|
||||
function changeInputUser(e){
|
||||
setSearchKey(e);
|
||||
};
|
||||
|
||||
// 选择用户
|
||||
function selectInputUser(e, option){
|
||||
setID(e);
|
||||
setSearchKey(option.props.name);
|
||||
};
|
||||
|
||||
function addCollaborator(){
|
||||
getGroupID && getGroupID(id);
|
||||
setSearchKey(undefined);
|
||||
}
|
||||
|
||||
return(
|
||||
<div className="addPanel">
|
||||
<AutoComplete
|
||||
dataSource={source}
|
||||
value={searchKey}
|
||||
style={{ width: 300 }}
|
||||
onChange={changeInputUser}
|
||||
onSelect={selectInputUser}
|
||||
placeholder="搜索需要添加的团队..."
|
||||
allowClear
|
||||
/>
|
||||
<Button
|
||||
type="primary"
|
||||
ghost
|
||||
onClick={addCollaborator}
|
||||
className="ml15"
|
||||
>
|
||||
<Icon type="plus" size="16"></Icon>
|
||||
添加团队
|
||||
</Button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default AddGroup;
|
||||
|
|
@ -4,7 +4,7 @@ import axios from 'axios';
|
|||
import { getImageUrl } from 'educoder';
|
||||
|
||||
const { Option } = AutoComplete;
|
||||
function AddMember({getID}){
|
||||
function AddMember({getID,login}){
|
||||
const [ id , setID ] = useState(undefined);
|
||||
const [ source , setSource ] = useState(undefined);
|
||||
const [ searchKey , setSearchKey ] = useState(undefined);
|
||||
|
|
@ -34,8 +34,9 @@ function AddMember({getID}){
|
|||
return (
|
||||
<Option
|
||||
key={key}
|
||||
value={`${item.login}`}
|
||||
searchValue={`${item.username}`}
|
||||
value={`${item.user_id}`}
|
||||
login={`${item.login}`}
|
||||
name={item.username}
|
||||
>
|
||||
<img
|
||||
className="user_img radius"
|
||||
|
|
@ -60,12 +61,13 @@ function AddMember({getID}){
|
|||
|
||||
// 选择用户
|
||||
function selectInputUser(e, option){
|
||||
setID(e);
|
||||
setSearchKey(option.props.searchValue);
|
||||
setID(login ? e : option.props.login);
|
||||
setSearchKey(option.props.name);
|
||||
};
|
||||
|
||||
function addCollaborator(){
|
||||
getID && getID(id);
|
||||
setSearchKey(undefined);
|
||||
}
|
||||
|
||||
return(
|
||||
|
|
@ -77,6 +79,7 @@ function AddMember({getID}){
|
|||
onChange={changeInputUser}
|
||||
onSelect={selectInputUser}
|
||||
placeholder="搜索需要添加的用户..."
|
||||
allowClear
|
||||
/>
|
||||
<Button
|
||||
type="primary"
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@ export default ({ getUser })=>{
|
|||
}
|
||||
|
||||
function selectInputUser(id, option){
|
||||
console.log(id,option);
|
||||
setSearchKey(option.props.value);
|
||||
getUserList(option.props.value);
|
||||
getUser && getUser(id);
|
||||
|
|
|
|||
|
|
@ -394,7 +394,7 @@ class Detail extends Component {
|
|||
<div className="f-wrap-between pb15" style={{ position: "relative" }}>
|
||||
<p className="font-22 df flex-1 lineH2 mt15" style={{ alignItems: "center" }}>
|
||||
{project && project.author &&
|
||||
<Link to={`/users/${project.author.login}`} className="show-user-link">
|
||||
<Link to={`${project.author.type ==="Organization" ? "/organize":'/users'}/${project.author.login}`} className="show-user-link">
|
||||
{project.author.name}
|
||||
</Link>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,522 +1,47 @@
|
|||
import React, { Component } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import {
|
||||
Input,
|
||||
AutoComplete,
|
||||
Dropdown,
|
||||
Menu,
|
||||
Icon,
|
||||
Spin,
|
||||
Pagination,
|
||||
Button,
|
||||
Table,
|
||||
Tooltip
|
||||
} from "antd";
|
||||
import NoneData from "../Nodata";
|
||||
import axios from "axios";
|
||||
import { getImageUrl } from "educoder";
|
||||
import React, { useState } from "react";
|
||||
import {WhiteBack} from '../Component/layout';
|
||||
import AddMember from '../Component/AddMember';
|
||||
import AddGroup from '../Component/AddGroup';
|
||||
import Member from './CollaboratorMember';
|
||||
import Group from './CollaboratorGroup';
|
||||
|
||||
const { Search } = Input;
|
||||
function Collaborator(props){
|
||||
const [ nav , setNav] = useState("1");
|
||||
const [ newId , setNewId] = useState(undefined);
|
||||
const [ newGroupId , setNewGroupId] = useState(undefined);
|
||||
const {projectsId ,owner} = props.match.params;
|
||||
|
||||
const { Option } = AutoComplete;
|
||||
const MENU_LIST = [
|
||||
{
|
||||
id: "Manager",
|
||||
name: "管理员",
|
||||
},
|
||||
{
|
||||
id: "Developer",
|
||||
name: "开发者",
|
||||
},
|
||||
{
|
||||
id: "Reporter",
|
||||
name: "报告者",
|
||||
},
|
||||
];
|
||||
const LIMIT = 15;
|
||||
class Collaborator extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
listData: undefined,
|
||||
user: undefined,
|
||||
user_id: undefined,
|
||||
userDataSource: undefined,
|
||||
page: 1,
|
||||
total_count: undefined,
|
||||
isSpin: true,
|
||||
searchKey: undefined,
|
||||
search: undefined,
|
||||
role: undefined,
|
||||
otherSpin: false,
|
||||
searchSpin: false,
|
||||
roleName: undefined,
|
||||
};
|
||||
function getID(id){
|
||||
setNewId(id);
|
||||
}
|
||||
componentDidUpdate=(prevPros)=>{
|
||||
if(prevPros && this.props && !this.props.checkIfLogin()){
|
||||
this.props.history.push("/403")
|
||||
return
|
||||
}
|
||||
function getGroupID(id){
|
||||
setNewGroupId(id);
|
||||
}
|
||||
componentDidMount = () => {
|
||||
// this.check_is_login()
|
||||
if (this.props.project_id) {
|
||||
this.getMember();
|
||||
}
|
||||
};
|
||||
|
||||
// check_is_login =() =>{
|
||||
// if(!this.props.checkIfLogin()){
|
||||
// this.props.history.push("/403")
|
||||
// return
|
||||
// }
|
||||
// };
|
||||
|
||||
componentDidUpdate = (prevState) => {
|
||||
if (
|
||||
this.props.project_id &&
|
||||
this.props.project_id !== prevState.project_id
|
||||
) {
|
||||
this.getMember();
|
||||
}
|
||||
};
|
||||
|
||||
// 获取项目协作者
|
||||
getMember = () => {
|
||||
const { page, search, role } = this.state;
|
||||
const {projectsId ,owner} = this.props.match.params;
|
||||
const url = `/${owner}/${projectsId}/collaborators.json`;
|
||||
axios
|
||||
.get(url, {
|
||||
params: {
|
||||
page,
|
||||
search: search,
|
||||
role: role,
|
||||
limit: LIMIT,
|
||||
},
|
||||
})
|
||||
.then((result) => {
|
||||
if (result) {
|
||||
this.setState({
|
||||
listData: result.data.members,
|
||||
isSpin: false,
|
||||
otherSpin: false,
|
||||
searchSpin: false,
|
||||
total_count: result.data.total_count,
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
this.setState({
|
||||
isSpin: false,
|
||||
otherSpin: false,
|
||||
searchSpin: false,
|
||||
});
|
||||
console.log(error);
|
||||
});
|
||||
};
|
||||
// 输入用户
|
||||
changeInputUser = (e) => {
|
||||
this.setState({
|
||||
searchKey: e,
|
||||
});
|
||||
this.getUserList(e);
|
||||
};
|
||||
searchMember = (e) => {
|
||||
this.state.search = e;
|
||||
this.setState({
|
||||
searchSpin: true,
|
||||
});
|
||||
this.getMember();
|
||||
};
|
||||
orderMember = (id, name) => {
|
||||
this.setState({
|
||||
isSpin: true
|
||||
})
|
||||
this.state.role = id;
|
||||
this.state.roleName = name;
|
||||
this.getMember();
|
||||
};
|
||||
// 选择用户
|
||||
selectInputUser = (e, option) => {
|
||||
this.setState({
|
||||
user_id: e,
|
||||
searchKey: option.props.searchValue,
|
||||
});
|
||||
this.getUserList(option.props.searchValue);
|
||||
};
|
||||
getUserList = (e) => {
|
||||
const url = `/users/list.json`;
|
||||
axios
|
||||
.get(url, {
|
||||
params: {
|
||||
search: e,
|
||||
},
|
||||
})
|
||||
.then((result) => {
|
||||
if (result) {
|
||||
this.setState({
|
||||
userDataSource: result.data.users,
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
};
|
||||
|
||||
// 增加协作者
|
||||
addCollaborator = () => {
|
||||
// const { project_id } = this.props;
|
||||
const { user_id } = this.state;
|
||||
if(user_id){
|
||||
this.setState({
|
||||
otherSpin: true,
|
||||
});
|
||||
const {projectsId ,owner} = this.props.match.params;
|
||||
const url = `/${owner}/${projectsId}/collaborators.json`;
|
||||
axios.post(url, {
|
||||
user_id,
|
||||
})
|
||||
.then((result) => {
|
||||
if (result) {
|
||||
this.setState({
|
||||
isSpin: true,
|
||||
otherSpin: false,
|
||||
});
|
||||
this.getMember();
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
this.setState({
|
||||
isSpin: false,
|
||||
otherSpin: false,
|
||||
});
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 修改权限
|
||||
changeOperaiton = (e, id) => {
|
||||
// const { project_id, page } = this.state;
|
||||
this.setState({
|
||||
isSpin: true,
|
||||
});
|
||||
const {projectsId ,owner} = this.props.match.params;
|
||||
|
||||
const url = `/${owner}/${projectsId}/collaborators/change_role.json`;
|
||||
axios
|
||||
.put(url, {
|
||||
user_id: id,
|
||||
role: e.key,
|
||||
})
|
||||
.then((result) => {
|
||||
if (result) {
|
||||
this.setState({
|
||||
isSpin: true,
|
||||
});
|
||||
this.props.showNotification("权限修改成功!");
|
||||
this.getMember();
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
this.setState({
|
||||
isSpin: false,
|
||||
});
|
||||
console.log(error);
|
||||
});
|
||||
};
|
||||
|
||||
// 删除协作者
|
||||
deleteUser = (id) => {
|
||||
const { page } = this.state;
|
||||
const {projectsId ,owner} = this.props.match.params;
|
||||
this.props.confirm({
|
||||
content: "确认将此成员从项目中移除?",
|
||||
onOk: () => {
|
||||
const { project_id } = this.props;
|
||||
const url = `/${owner}/${projectsId}/collaborators/remove.json`;
|
||||
axios
|
||||
.delete(url, {
|
||||
data: {
|
||||
user_id: id,
|
||||
},
|
||||
})
|
||||
.then((result) => {
|
||||
if (result) {
|
||||
this.setState({
|
||||
isSpin: true,
|
||||
});
|
||||
this.props.showNotification("成员删除成功!");
|
||||
this.getMember();
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
this.setState({
|
||||
isSpin: false,
|
||||
});
|
||||
console.log(error);
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
changePage = (page) => {
|
||||
this.state.page = page;
|
||||
this.setState({
|
||||
isSpin: true,
|
||||
});
|
||||
this.getMember();
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
userDataSource,
|
||||
listData,
|
||||
isSpin,
|
||||
page,
|
||||
total_count,
|
||||
searchKey,
|
||||
otherSpin,
|
||||
searchSpin,
|
||||
roleName,
|
||||
} = this.state;
|
||||
// 获取当前项目的拥有者
|
||||
const { author } = this.props;
|
||||
const get_color = (role) => {
|
||||
if (role === "Manager") {
|
||||
return "text-green";
|
||||
} else if (role === "Developer") {
|
||||
return "text-primary";
|
||||
} else {
|
||||
return "text-yellow";
|
||||
}
|
||||
};
|
||||
const member_roles = (item) => {
|
||||
const operation = MENU_LIST.filter((i) => i.id === item.role);
|
||||
return (
|
||||
|
||||
return (
|
||||
<WhiteBack>
|
||||
<div className="flex-a-center baseForm bbr">
|
||||
<span>
|
||||
{author && author.login === item.login ? (
|
||||
<label className={get_color(item.role)}>
|
||||
{operation && operation[0].name}
|
||||
</label>
|
||||
) : (
|
||||
<Dropdown overlay={setRoles(`${item.id}`)} placement={"bottomCenter"}>
|
||||
<span className={get_color(item.role)}>
|
||||
{operation && operation[0].name}
|
||||
<Icon type="caret-down" className="ml2" size="13" />
|
||||
</span>
|
||||
</Dropdown>
|
||||
)}
|
||||
<span style={{cursor:"pointer"}} className={nav === "1" ? "font-18 text-black color-blue":"font-18 text-black"} onClick={()=>setNav("1")}>协作者管理</span>
|
||||
<span style={{cursor:"pointer"}} className={nav === "2" ? "font-18 text-black ml30 color-blue":"font-18 text-black ml30"} onClick={()=>setNav("2")}>团队管理</span>
|
||||
</span>
|
||||
);
|
||||
};
|
||||
const roleTitle = (
|
||||
<div><span className="mr3">角色</span>
|
||||
<Tooltip placement='bottom' title={<div>
|
||||
<div className="mb3">管理员:拥有仓库设置功能、代码库读、写操作</div>
|
||||
<div className="mb3">开发人员:只拥有代码库读、写操作</div>
|
||||
<div className="mb3">报告者:只拥有代码库读操作</div>
|
||||
</div>
|
||||
}>
|
||||
<Icon type="question-circle"></Icon>
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
const columns = [
|
||||
{
|
||||
title: "头像",
|
||||
dataIndex: "image_url",
|
||||
render: (text, item) => (
|
||||
<span className="f-wrap-alignCenter">
|
||||
<Link
|
||||
to={`/users/${item.login}`}
|
||||
className="show-user-link"
|
||||
>
|
||||
<img
|
||||
src={getImageUrl(`images/${text}`)}
|
||||
alt=""
|
||||
width="32px"
|
||||
height="32px"
|
||||
className="mr3 radius"
|
||||
/>
|
||||
</Link>
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "用户名",
|
||||
dataIndex: "name",
|
||||
render: (text, item) => (
|
||||
<Link to={`/users/${item.login}`} className="show-user-link">
|
||||
{text}
|
||||
</Link>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "邮箱",
|
||||
dataIndex: "email",
|
||||
render: (text) => <span>{text}</span>,
|
||||
},
|
||||
{
|
||||
title: "Token值",
|
||||
dataIndex: "token",
|
||||
render: (text) => <span>{text}</span>,
|
||||
},
|
||||
{
|
||||
title: roleTitle,
|
||||
dataIndex: "role_name",
|
||||
render: (text, item) => member_roles(item),
|
||||
},
|
||||
{
|
||||
title: "操作",
|
||||
dataIndex: "action",
|
||||
render: (text, item) => (
|
||||
<span style={{ justifyContent: "center" }}>
|
||||
{author && author.login !== item.login && (
|
||||
<a
|
||||
className="text-delete"
|
||||
onClick={() => this.deleteUser(item.id)}
|
||||
>
|
||||
删除
|
||||
</a>
|
||||
)}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
];
|
||||
const roles = (id) => (
|
||||
<Menu>
|
||||
<Menu.Item
|
||||
key={0}
|
||||
value={undefined}
|
||||
onClick={(e) => this.orderMember(undefined, "角色筛选")}
|
||||
>
|
||||
全部
|
||||
</Menu.Item>
|
||||
{MENU_LIST.map((item, key) => {
|
||||
return (
|
||||
<Menu.Item
|
||||
key={item.id}
|
||||
value={item.id}
|
||||
onClick={(e) => this.orderMember(item.id, item.name)}
|
||||
>
|
||||
{item.name}
|
||||
</Menu.Item>
|
||||
);
|
||||
})}
|
||||
</Menu>
|
||||
);
|
||||
const setRoles = (id) => (
|
||||
<Menu>
|
||||
{MENU_LIST.map((item, key) => {
|
||||
return (
|
||||
<Menu.Item
|
||||
key={item.id}
|
||||
value={item.id}
|
||||
onClick={(e) => this.changeOperaiton(e,id)}
|
||||
>
|
||||
{item.name}
|
||||
</Menu.Item>
|
||||
);
|
||||
})}
|
||||
</Menu>
|
||||
);
|
||||
|
||||
const source =
|
||||
userDataSource &&
|
||||
userDataSource.map((item, key) => {
|
||||
return (
|
||||
<Option
|
||||
key={key}
|
||||
value={`${item.user_id}`}
|
||||
searchValue={`${item.username}`}
|
||||
>
|
||||
<img
|
||||
className="user_img radius"
|
||||
width="28"
|
||||
height="28"
|
||||
src={getImageUrl(`images/${item && item.image_url}`)}
|
||||
alt=""
|
||||
/>
|
||||
<span className="ml10" style={{ "vertical-align": "middle" }}>
|
||||
{item.username}
|
||||
<span className="color-grey ml10">({item.login})</span>
|
||||
</span>
|
||||
</Option>
|
||||
);
|
||||
});
|
||||
return (
|
||||
<WhiteBack>
|
||||
<div className="flex-a-center baseForm bbr">
|
||||
<span className="font-18 text-black">协作者管理</span>
|
||||
<div className="addPanel">
|
||||
<AutoComplete
|
||||
dataSource={source}
|
||||
value={searchKey}
|
||||
style={{ width: 300 }}
|
||||
onChange={this.changeInputUser}
|
||||
onSelect={this.selectInputUser}
|
||||
placeholder="搜索需要添加的用户..."
|
||||
/>
|
||||
<Button
|
||||
type="primary"
|
||||
ghost
|
||||
onClick={this.addCollaborator}
|
||||
className="ml15"
|
||||
loading={otherSpin}
|
||||
>
|
||||
<Icon type="plus" size="16"></Icon>
|
||||
添加成员
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid-item-left baseForm">
|
||||
<Search
|
||||
placeholder="搜索项目成员..."
|
||||
enterButton="搜索"
|
||||
loading={searchSpin}
|
||||
onSearch={(value) => this.searchMember(value)}
|
||||
/>
|
||||
<Dropdown overlay={roles} placement={"bottomCenter"}>
|
||||
<a className="ml180 text-primary">
|
||||
{roleName ? roleName : "角色筛选"}
|
||||
<Icon type="caret-down" size="16"></Icon>
|
||||
</a>
|
||||
</Dropdown>
|
||||
</div>
|
||||
|
||||
<Spin spinning={isSpin}>
|
||||
<div className="collaboratorList baseForm">
|
||||
{listData && listData.length>0 ? (
|
||||
<Table
|
||||
pagination={false}
|
||||
columns={columns}
|
||||
dataSource={listData}
|
||||
rowKey={(record) => record.id}
|
||||
></Table>
|
||||
) : (
|
||||
<NoneData _html="暂时还没有相关数据!" />
|
||||
)}
|
||||
</div>
|
||||
</Spin>
|
||||
{total_count && total_count > LIMIT ? (
|
||||
<div className="edu-txt-center mt20 mb20">
|
||||
<Pagination
|
||||
showQuickJumper
|
||||
pageSize={LIMIT}
|
||||
current={page}
|
||||
total={total_count}
|
||||
onChange={this.changePage}
|
||||
></Pagination>
|
||||
</div>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
</WhiteBack>
|
||||
);
|
||||
}
|
||||
{
|
||||
nav === "1" ?
|
||||
<AddMember getID={getID} login/>
|
||||
:
|
||||
<AddGroup getGroupID={getGroupID} organizeId={owner}/>
|
||||
}
|
||||
|
||||
</div>
|
||||
<div>
|
||||
{
|
||||
nav === "1" ?
|
||||
<Member newId={newId} projectsId={projectsId} owner={owner} project_id={props.project_id} author={props.author} showNotification={props.showNotification}/>
|
||||
:
|
||||
<Group {...props} newGroupId={newGroupId}/>
|
||||
}
|
||||
</div>
|
||||
</WhiteBack>
|
||||
);
|
||||
}
|
||||
export default Collaborator;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
|
||||
function CollaboratorGroup(props,{newGroupId}){
|
||||
|
||||
useEffect(()=>{
|
||||
if(newGroupId){
|
||||
addGroup(newGroupId);
|
||||
}
|
||||
},[newGroupId])
|
||||
function addGroup(id){
|
||||
|
||||
}
|
||||
return(
|
||||
<div>团队管理</div>
|
||||
)
|
||||
}
|
||||
export default CollaboratorGroup;
|
||||
|
|
@ -0,0 +1,278 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { Dropdown, Menu, Icon , Input , Spin , Table , Tooltip , Pagination , Popconfirm } from "antd";
|
||||
import axios from 'axios';
|
||||
import NoneData from "../Nodata";
|
||||
import { Link } from "react-router-dom";
|
||||
import { getImageUrl } from "educoder";
|
||||
|
||||
const { Search } = Input;
|
||||
const LIMIT = 15;
|
||||
const MENU_LIST = [
|
||||
{id: "Manager",name: "管理员"},
|
||||
{id: "Developer",name: "开发者"},
|
||||
{id: "Reporter",name: "报告者"}
|
||||
];
|
||||
function CollaboratorMember({projectsId,owner,project_id,author,showNotification,newId}){
|
||||
const [ roleName , setRoleName ] = useState(undefined);
|
||||
const [ search , setSearch ] = useState(undefined);
|
||||
const [ page , setPage ] = useState(undefined);
|
||||
const [ isSpin , setIsSpin ] = useState(false);
|
||||
const [ role , setRole ] = useState(undefined);
|
||||
const [ listData , setListData ] = useState(undefined);
|
||||
const [ total , setTotal ] = useState(0);
|
||||
|
||||
|
||||
useEffect(()=>{
|
||||
if(newId){
|
||||
addCollaborator(newId);
|
||||
}
|
||||
},[newId])
|
||||
// 增加协作者
|
||||
function addCollaborator(id){
|
||||
if(id){
|
||||
const url = `/${owner}/${projectsId}/collaborators.json`;
|
||||
axios.post(url, {
|
||||
user_id:id,
|
||||
})
|
||||
.then((result) => {
|
||||
if (result) {
|
||||
getMember();
|
||||
}
|
||||
})
|
||||
.catch((error) => {});
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(()=>{
|
||||
if(project_id && projectsId && owner) {
|
||||
getMember();
|
||||
}
|
||||
},[project_id,search,page,role])
|
||||
|
||||
// 获取项目协作者
|
||||
function getMember(){
|
||||
setIsSpin(true);
|
||||
const url = `/${owner}/${projectsId}/collaborators.json`;
|
||||
axios.get(url, {
|
||||
params: {
|
||||
page,search,role,limit: LIMIT,
|
||||
},
|
||||
})
|
||||
.then((result) => {
|
||||
if (result) {
|
||||
setListData(result.data.members);
|
||||
setTotal(result.data.total_count);
|
||||
setIsSpin(false);
|
||||
}
|
||||
})
|
||||
.catch((error) => {setIsSpin(false);});
|
||||
};
|
||||
|
||||
function orderMember(id, name){
|
||||
setRole(id);
|
||||
setRoleName(name);
|
||||
};
|
||||
const roles = (id) => (
|
||||
<Menu>
|
||||
<Menu.Item
|
||||
key={0}
|
||||
value={undefined}
|
||||
onClick={(e) => orderMember(undefined, "角色筛选")}
|
||||
>
|
||||
全部
|
||||
</Menu.Item>
|
||||
{MENU_LIST.map((item, key) => {
|
||||
return (
|
||||
<Menu.Item
|
||||
key={item.id}
|
||||
value={item.id}
|
||||
onClick={(e) => orderMember(item.id, item.name)}
|
||||
>
|
||||
{item.name}
|
||||
</Menu.Item>
|
||||
);
|
||||
})}
|
||||
</Menu>
|
||||
);
|
||||
|
||||
// 修改权限
|
||||
function changeOperaiton(e, id){
|
||||
const url = `/${owner}/${projectsId}/collaborators/change_role.json`;
|
||||
axios.put(url, {
|
||||
user_id: id,
|
||||
role: e.key,
|
||||
}).then((result) => {
|
||||
if (result) {
|
||||
showNotification("权限修改成功!");
|
||||
getMember();
|
||||
}
|
||||
})
|
||||
.catch((error) => {});
|
||||
};
|
||||
// 删除协作者
|
||||
function deleteUser(id){
|
||||
const url = `/${owner}/${projectsId}/collaborators/remove.json`;
|
||||
axios.delete(url, {
|
||||
data: {user_id: id,},
|
||||
})
|
||||
.then((result) => {
|
||||
if (result) {
|
||||
showNotification("成员删除成功!");
|
||||
getMember();
|
||||
}
|
||||
}).catch((error) => {});
|
||||
};
|
||||
const roleTitle = (
|
||||
<div><span className="mr3">角色</span>
|
||||
<Tooltip placement='bottom' title={<div>
|
||||
<div className="mb3">管理员:拥有仓库设置功能、代码库读、写操作</div>
|
||||
<div className="mb3">开发人员:只拥有代码库读、写操作</div>
|
||||
<div className="mb3">报告者:只拥有代码库读操作</div>
|
||||
</div>
|
||||
}>
|
||||
<Icon type="question-circle"></Icon>
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
const get_color = (role) => {
|
||||
if (role === "Manager") {
|
||||
return "text-green";
|
||||
} else if (role === "Developer") {
|
||||
return "text-primary";
|
||||
} else {
|
||||
return "text-yellow";
|
||||
}
|
||||
};
|
||||
const setRoles = (id) => (
|
||||
<Menu>
|
||||
{MENU_LIST.map((item, key) => {
|
||||
return (
|
||||
<Menu.Item
|
||||
key={item.id}
|
||||
value={item.id}
|
||||
onClick={(e) => changeOperaiton(e,id)}
|
||||
>
|
||||
{item.name}
|
||||
</Menu.Item>
|
||||
);
|
||||
})}
|
||||
</Menu>
|
||||
);
|
||||
const member_roles = (item) => {
|
||||
const operation = MENU_LIST.filter((i) => i.id === item.role);
|
||||
return (
|
||||
<span>
|
||||
{author && author.login === item.login ? (
|
||||
<label className={get_color(item.role)}>
|
||||
{operation && operation[0].name}
|
||||
</label>
|
||||
) : (
|
||||
<Dropdown overlay={setRoles(`${item.id}`)} placement={"bottomCenter"}>
|
||||
<span className={get_color(item.role)}>
|
||||
{operation && operation[0].name}
|
||||
<Icon type="caret-down" className="ml2" size="13" />
|
||||
</span>
|
||||
</Dropdown>
|
||||
)}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
const columns = [
|
||||
{
|
||||
title: "头像",
|
||||
dataIndex: "image_url",
|
||||
render: (text, item) => (
|
||||
<span className="f-wrap-alignCenter">
|
||||
<Link
|
||||
to={`/users/${item.login}`}
|
||||
className="show-user-link"
|
||||
>
|
||||
<img
|
||||
src={getImageUrl(`images/${text}`)}
|
||||
alt=""
|
||||
width="32px"
|
||||
height="32px"
|
||||
className="mr3 radius"
|
||||
/>
|
||||
</Link>
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "用户名",
|
||||
dataIndex: "name",
|
||||
render: (text, item) => (
|
||||
<Link to={`/users/${item.login}`} className="show-user-link">
|
||||
{text}
|
||||
</Link>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "邮箱",
|
||||
dataIndex: "email",
|
||||
render: (text) => <span>{text}</span>,
|
||||
},
|
||||
{
|
||||
title: roleTitle,
|
||||
dataIndex: "role_name",
|
||||
render: (text, item) => member_roles(item),
|
||||
},
|
||||
{
|
||||
title: "操作",
|
||||
dataIndex: "action",
|
||||
render: (text, item) => (
|
||||
<span style={{ justifyContent: "center" }}>
|
||||
{author && author.login !== item.login && (
|
||||
<Popconfirm title="确认将此成员从项目中移除?" okText="是" cancelText="否" onOk={() => deleteUser(item.id)}>
|
||||
<a className="text-delete">删除</a>
|
||||
</Popconfirm>
|
||||
)}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
];
|
||||
return(
|
||||
<React.Fragment>
|
||||
<div className="baseForm" style={{display:'flex',justifyContent:"space-between",alignItems:"center"}}>
|
||||
<Dropdown overlay={roles} placement={"bottomCenter"}>
|
||||
<a className="text-primary">
|
||||
{roleName ? roleName : "角色筛选"}
|
||||
<Icon type="caret-down" size="16"></Icon>
|
||||
</a>
|
||||
</Dropdown>
|
||||
<Search
|
||||
placeholder="搜索项目成员..."
|
||||
enterButton="搜索"
|
||||
onSearch={setSearch}
|
||||
style={{width:300}}
|
||||
/>
|
||||
</div>
|
||||
<Spin spinning={isSpin}>
|
||||
<div className="collaboratorList baseForm">
|
||||
{listData && listData.length>0 ? (
|
||||
<Table
|
||||
pagination={false}
|
||||
columns={columns}
|
||||
dataSource={listData}
|
||||
rowKey={(record) => record.id}
|
||||
></Table>
|
||||
) : (
|
||||
<NoneData _html="暂时还没有相关数据!" />
|
||||
)}
|
||||
</div>
|
||||
</Spin>
|
||||
{total > LIMIT ?
|
||||
<div className="edu-txt-center mt20 mb20">
|
||||
<Pagination
|
||||
showQuickJumper
|
||||
pageSize={LIMIT}
|
||||
current={page}
|
||||
total={total}
|
||||
onChange={()=>setPage(page)}
|
||||
></Pagination>
|
||||
</div>
|
||||
:""}
|
||||
</React.Fragment>
|
||||
)
|
||||
}
|
||||
export default CollaboratorMember;
|
||||
|
|
@ -112,8 +112,9 @@ function GroupProjectSetting(props) {
|
|||
let s = value || "";
|
||||
setSearch(s);
|
||||
}
|
||||
function selectInput(value,e){
|
||||
function selectInput(value){
|
||||
setRepoName(value);
|
||||
setSearch(value);
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import axios from 'axios';
|
|||
export default Form.create()(
|
||||
forwardRef(({ form , showNotification , history })=>{
|
||||
const [ image , setImage ] = useState(undefined);
|
||||
const [ imageFlag , setImageFlag] = useState(false);
|
||||
const { getFieldDecorator, validateFields } = form;
|
||||
|
||||
const radioStyle = {
|
||||
|
|
@ -29,12 +30,17 @@ export default Form.create()(
|
|||
// 获取上传的图片
|
||||
function getImage(image){
|
||||
setImage(image);
|
||||
setImageFlag(false);
|
||||
}
|
||||
|
||||
// 创建组织
|
||||
function createOrganize(){
|
||||
validateFields((error,values)=>{
|
||||
if(!error){
|
||||
if(!image){
|
||||
setImageFlag(true);
|
||||
return;
|
||||
}
|
||||
const url = `/organizations.json`;
|
||||
axios.post(url,{
|
||||
...values,image
|
||||
|
|
@ -74,7 +80,6 @@ export default Form.create()(
|
|||
'所在地区',
|
||||
"location",
|
||||
[],
|
||||
// <Cascader placeholder="请选择城市" options={locData}/>,false
|
||||
<Input placeholder="请输入地址"/>,false
|
||||
)}
|
||||
{helper(
|
||||
|
|
@ -87,9 +92,11 @@ export default Form.create()(
|
|||
<Radio style={radioStyle} value="privacy" key={3}>私有<span className="color-grey-8">(仅对组织成员可见)</span></Radio>
|
||||
</Radio.Group>
|
||||
)}
|
||||
<p className="font-16">选择头像</p>
|
||||
|
||||
<p className="font-16 lables must">选择头像</p>
|
||||
<UploadImage getImage={getImage}/>
|
||||
|
||||
{imageFlag && <p className="color-red" style={{marginTop:"-10px"}}>请上传头像</p> }
|
||||
|
||||
{helper(
|
||||
'权限',
|
||||
"repo_admin_change_team_access",
|
||||
|
|
|
|||
Loading…
Reference in New Issue