forked from Gitlink/forgeplus-react
组织 all over
This commit is contained in:
parent
9380c0172c
commit
3b208ba751
|
@ -0,0 +1,93 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { AutoComplete , Button , Icon } from 'antd';
|
||||
import axios from 'axios';
|
||||
import { getImageUrl } from 'educoder';
|
||||
|
||||
const { Option } = AutoComplete;
|
||||
function AddMember({getID}){
|
||||
const [ id , setID ] = useState(undefined);
|
||||
const [ source , setSource ] = useState(undefined);
|
||||
const [ searchKey , setSearchKey ] = useState(undefined);
|
||||
|
||||
useEffect(()=>{
|
||||
getUserList();
|
||||
},[searchKey])
|
||||
|
||||
function getUserList(e){
|
||||
const url = `/users/list.json`;
|
||||
axios.get(url, {
|
||||
params: {
|
||||
search: searchKey,
|
||||
},
|
||||
}).then((result) => {
|
||||
if (result) {
|
||||
sourceOptions(result.data.users);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
};
|
||||
|
||||
function sourceOptions(userDataSource){
|
||||
const s = userDataSource && userDataSource.map((item, key) => {
|
||||
return (
|
||||
<Option
|
||||
key={key}
|
||||
value={`${item.login}`}
|
||||
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>
|
||||
);
|
||||
});
|
||||
setSource(s);
|
||||
}
|
||||
|
||||
function changeInputUser(e){
|
||||
setSearchKey(e);
|
||||
};
|
||||
|
||||
// 选择用户
|
||||
function selectInputUser(e, option){
|
||||
setID(e);
|
||||
setSearchKey(option.props.searchValue);
|
||||
};
|
||||
|
||||
function addCollaborator(){
|
||||
getID && getID(id);
|
||||
}
|
||||
|
||||
return(
|
||||
<div className="addPanel">
|
||||
<AutoComplete
|
||||
dataSource={source}
|
||||
value={searchKey}
|
||||
style={{ width: 300 }}
|
||||
onChange={changeInputUser}
|
||||
onSelect={selectInputUser}
|
||||
placeholder="搜索需要添加的用户..."
|
||||
/>
|
||||
<Button
|
||||
type="primary"
|
||||
ghost
|
||||
onClick={addCollaborator}
|
||||
className="ml15"
|
||||
>
|
||||
<Icon type="plus" size="16"></Icon>
|
||||
添加成员
|
||||
</Button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default AddMember;
|
|
@ -32,26 +32,6 @@ const I = styled.i`{
|
|||
color:#60B25E;
|
||||
margin-right:2px;
|
||||
}`
|
||||
const FocusBtn = styled.a`{
|
||||
display:inline-block;
|
||||
height:30px;
|
||||
line-height:26px;
|
||||
padding:0px 12px;
|
||||
background-color:#fafafa;
|
||||
border:1px solid #eee;
|
||||
border-radius:2px;
|
||||
color:#888!important;
|
||||
}`
|
||||
const Ifocused = styled.i`{
|
||||
font-size:16px!important;
|
||||
color:#FFA802;
|
||||
margin-right:4px;
|
||||
}`
|
||||
const Ifocus = styled.i`{
|
||||
font-size:16px!important;
|
||||
color:#BBBBBB;
|
||||
margin-right:4px;
|
||||
}`
|
||||
const Div = styled.div`{
|
||||
margin-bottom: 18px;
|
||||
padding:20px 16px;
|
||||
|
@ -59,7 +39,7 @@ const Div = styled.div`{
|
|||
align-items: center;
|
||||
border:1px solid #eee;
|
||||
}`
|
||||
export default (({ img, name, time, focusStatus, is_current_user, login }) => {
|
||||
export default (({ img, name, time, focusStatus, is_current_user, login , successFunc }) => {
|
||||
return (
|
||||
<Div>
|
||||
<Img src={getImageUrl(`images/${img}`)} />
|
||||
|
@ -70,7 +50,7 @@ export default (({ img, name, time, focusStatus, is_current_user, login }) => {
|
|||
is_current_user ?
|
||||
<Button type="default">当前用户</Button>
|
||||
:
|
||||
<FocusButton is_watch={focusStatus} id={login} />
|
||||
<FocusButton is_watch={focusStatus} id={login} successFunc={successFunc}/>
|
||||
}
|
||||
</div>
|
||||
</Div>
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
import React, { useState } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import Modals from './Modals';
|
||||
|
||||
|
||||
const ALink = styled.a`{
|
||||
border:1px solid #F73030;
|
||||
color:#F73030!important;
|
||||
height:30px;
|
||||
line-height:30px;
|
||||
padding:0px 15px;
|
||||
border-radius:5px;
|
||||
}`
|
||||
function LeaveTeam({teamID , onOk }){
|
||||
const [ visible , setVisible ] = useState(false);
|
||||
|
||||
return(
|
||||
<React.Fragment>
|
||||
<ALink onClick={()=>setVisible(true)}>离开团队</ALink>
|
||||
<Modals visible={visible} okText={"确定"} cancelText={"取消"} onCancel={()=>setVisible(false)} onOk={()=>onOk(teamID)}>
|
||||
<p className="font-16 edu-txt-center">确定要离开当前团队吗?</p>
|
||||
</Modals>
|
||||
</React.Fragment>
|
||||
)
|
||||
}
|
||||
export default LeaveTeam;
|
|
@ -0,0 +1,21 @@
|
|||
import React from 'react';
|
||||
import { Modal } from 'antd';
|
||||
|
||||
function Modals({visible , okText , cancelText , onOk , onCancel , children}){
|
||||
|
||||
return(
|
||||
<Modal
|
||||
visible={visible}
|
||||
okText={okText}
|
||||
onCancel={onCancel}
|
||||
onOk={onOk}
|
||||
cancelText={cancelText}
|
||||
title={"提示"}
|
||||
closable={false}
|
||||
centered
|
||||
>
|
||||
{children}
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
export default Modals;
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
|||
import Cards from '../../Component/MemberCards';
|
||||
import Nodata from '../../Nodata';
|
||||
|
||||
export default (({ data , current_user }) => {
|
||||
export default (({ data , current_user , successFunc }) => {
|
||||
return (
|
||||
data && data.length > 0 ?
|
||||
<div className="MemberBoxThree">
|
||||
|
@ -16,6 +16,7 @@ export default (({ data , current_user }) => {
|
|||
focusStatus={item.user.watched}
|
||||
is_current_user={current_user && item.user.login === current_user.login}
|
||||
login={item.user.login}
|
||||
successFunc={successFunc}
|
||||
/>
|
||||
)
|
||||
})
|
||||
|
|
|
@ -18,8 +18,7 @@ const Div = styled.div`{
|
|||
}
|
||||
}`
|
||||
const Imgs = styled.img`{
|
||||
width:30px;
|
||||
height:30px;
|
||||
width:60px;
|
||||
margin-right:12px;
|
||||
border-radius:50%;
|
||||
}`
|
||||
|
|
|
@ -130,7 +130,7 @@ export default ((props) => {
|
|||
<WhiteBack>
|
||||
<Tabs nav={['团队成员', '团队项目']} index={nav} onChange={setNav}>
|
||||
{
|
||||
nav === "0" ? <Memberlist data={members} current_user={props.current_user}/> : <Grouplist projects={projects}/>
|
||||
nav === "0" ? <Memberlist data={members} current_user={props.current_user} successFunc={()=>getMember( OIdentifier, groupId, page )}/> : <Grouplist projects={projects}/>
|
||||
}
|
||||
</Tabs>
|
||||
{
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import { WhiteBack, Blueline, AlignCenter, FlexAJ } from '../../../Component/layout';
|
||||
import { WhiteBack , FlexAJ } from '../../../Component/layout';
|
||||
import { Menu, Table, Pagination, Icon, Tooltip, Popconfirm, Dropdown, Spin } from 'antd';
|
||||
import Sort from '../../../Component/Sort';
|
||||
import Title from '../../../Component/Title';
|
||||
import Search from '../../../Component/Search';
|
||||
import SearchUser from '../../../Component/SearchUser';
|
||||
import AddMember from '../../../Component/AddMember';
|
||||
|
||||
import styled from 'styled-components';
|
||||
import { getImageUrl } from 'educoder';
|
||||
import axios from 'axios';
|
||||
|
@ -14,18 +15,15 @@ const Img = styled.img`{
|
|||
height:30px;
|
||||
border-radius:50%;
|
||||
}`
|
||||
|
||||
const limit = 15
|
||||
export default ((props) => {
|
||||
const [login, setAddUserLogin] = useState(undefined);
|
||||
const [page, setPage] = useState(1);
|
||||
const [limit, setLimit] = useState(15);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [data, setMembers] = useState(undefined);
|
||||
const [isSpin, setIsSpin] = useState(false);
|
||||
const [identify, setIdentify] = useState(undefined);
|
||||
const [search, setQuery] = useState(undefined);
|
||||
const { OIdentifier, groupId } = props.match.params;
|
||||
const { current_user } = props;
|
||||
|
||||
useEffect(() => {
|
||||
getMember()
|
||||
|
@ -34,8 +32,7 @@ export default ((props) => {
|
|||
function getMember() {
|
||||
setIsSpin(true)
|
||||
const url = `/organizations/${OIdentifier}/teams/${groupId}/team_users.json`;
|
||||
axios
|
||||
.get(url, {
|
||||
axios.get(url, {
|
||||
params: {
|
||||
page,
|
||||
search,
|
||||
|
@ -52,51 +49,9 @@ export default ((props) => {
|
|||
setIsSpin(false)
|
||||
};
|
||||
|
||||
// 获取搜索用户框里面选择的用户Login字段,接口是这样定义的
|
||||
function getUser(login) {
|
||||
setAddUserLogin(login)
|
||||
}
|
||||
|
||||
function addUser() {
|
||||
setIsSpin(true)
|
||||
const url = `/organizations/${OIdentifier}/teams/${groupId}/team_users.json`;
|
||||
if (login) {
|
||||
axios.post(url, {
|
||||
username: login
|
||||
})
|
||||
.then((result) => {
|
||||
if (result && result.data) {
|
||||
setPage(1)
|
||||
setQuery(undefined)
|
||||
setIdentify(undefined)
|
||||
this.getMember();
|
||||
}
|
||||
})
|
||||
.catch((error) => { });
|
||||
}
|
||||
setIsSpin(false)
|
||||
}
|
||||
// 搜索
|
||||
function onSearch(value) {
|
||||
setQuery(value)
|
||||
}
|
||||
|
||||
// 角色筛选
|
||||
function onSelectMenu(e) {
|
||||
let select_role = e.key
|
||||
setPage(1)
|
||||
setQuery(undefined)
|
||||
setIdentify(select_role === "all" ? undefined : select_role)
|
||||
}
|
||||
|
||||
// 切换分页
|
||||
function ChangePage(page) {
|
||||
setPage(page);
|
||||
}
|
||||
|
||||
// 移除成员
|
||||
function removeUser(username) {
|
||||
setIsSpin(true)
|
||||
setIsSpin(true);
|
||||
const url = `/organizations/${OIdentifier}/teams/${groupId}/team_users/${username}.json`;
|
||||
if (username) {
|
||||
axios.delete(url)
|
||||
|
@ -105,7 +60,7 @@ export default ((props) => {
|
|||
setPage(1)
|
||||
setQuery(undefined)
|
||||
setIdentify(undefined)
|
||||
this.getMember();
|
||||
getMember();
|
||||
}
|
||||
})
|
||||
.catch((error) => { });
|
||||
|
@ -113,112 +68,6 @@ export default ((props) => {
|
|||
setIsSpin(false)
|
||||
}
|
||||
|
||||
const MENU_LIST = [
|
||||
{
|
||||
id: "Manager",
|
||||
name: "管理员",
|
||||
desc: "拥有仓库设置功能、代码库读、写操作"
|
||||
},
|
||||
{
|
||||
id: "Developer",
|
||||
name: "开发者",
|
||||
desc: "只拥有代码库读、写操作"
|
||||
},
|
||||
{
|
||||
id: "Reporter",
|
||||
name: "报告者",
|
||||
desc: "只拥有代码库读操作"
|
||||
},
|
||||
];
|
||||
|
||||
const menu = (
|
||||
<Menu onSelect={onSelectMenu}>
|
||||
<Menu.Item key="all">全部</Menu.Item>
|
||||
{MENU_LIST.map((item, key) => {
|
||||
return (
|
||||
<Menu.Item
|
||||
key={item.id}
|
||||
value={item.id}
|
||||
>
|
||||
{item.name}
|
||||
</Menu.Item>
|
||||
);
|
||||
})}
|
||||
</Menu>
|
||||
)
|
||||
const roleTitle = (
|
||||
<div><span className="mr3">角色</span>
|
||||
<Tooltip placement='bottom' title=
|
||||
{
|
||||
<div>
|
||||
{MENU_LIST.map((item, key) => {
|
||||
return (
|
||||
<div className="mb3">{item.name}:{item.desc}</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<Icon type="question-circle"></Icon>
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
function 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) => this.changeOperaiton(e, id)}
|
||||
>
|
||||
{item.name}
|
||||
</Menu.Item>
|
||||
);
|
||||
})}
|
||||
</Menu>
|
||||
);
|
||||
|
||||
// 修改权限
|
||||
function changeOperaiton(e, id) {
|
||||
console.log(e)
|
||||
};
|
||||
|
||||
const member_roles = (item) => {
|
||||
const operation = MENU_LIST.filter((i) => i.id === item.identify);
|
||||
return (
|
||||
<span>
|
||||
{operation && operation[0] ?
|
||||
<span>
|
||||
{current_user && current_user.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>
|
||||
: ""
|
||||
}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: '头像',
|
||||
|
@ -251,12 +100,6 @@ export default ((props) => {
|
|||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: roleTitle,
|
||||
dataIndex: 'role',
|
||||
width: "20%",
|
||||
render: (value, item) => member_roles(item.user),
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'operation',
|
||||
|
@ -268,29 +111,46 @@ export default ((props) => {
|
|||
okText="确认"
|
||||
cancelText="取消"
|
||||
>
|
||||
<a className="color-grey-8" href="#">移除成员</a>
|
||||
<a className="color-grey-8">移除成员</a>
|
||||
</Popconfirm>
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
function getID(id){
|
||||
addUser(id);
|
||||
}
|
||||
|
||||
function addUser(l) {
|
||||
setIsSpin(true);
|
||||
const url = `/organizations/${OIdentifier}/teams/${groupId}/team_users.json`;
|
||||
if (l) {
|
||||
axios.post(url, {
|
||||
username: l
|
||||
}).then((result) => {
|
||||
if (result && result.data) {
|
||||
setPage(1)
|
||||
setQuery(undefined)
|
||||
setIdentify(undefined)
|
||||
getMember();
|
||||
}
|
||||
})
|
||||
.catch((error) => { });
|
||||
}
|
||||
setIsSpin(false)
|
||||
}
|
||||
|
||||
return (
|
||||
<Spin spinning={isSpin}>
|
||||
<WhiteBack style={{minHeight:"400px"}}>
|
||||
<Title>
|
||||
<span>团队成员管理</span>
|
||||
<AlignCenter>
|
||||
<SearchUser getUser={getUser} />
|
||||
<Blueline className="ml30" onClick={addUser}>+ 添加用户</Blueline>
|
||||
</AlignCenter>
|
||||
<AddMember getID={getID}/>
|
||||
</Title>
|
||||
<FlexAJ className="padding20-30">
|
||||
<div style={{ width: "580px" }}>
|
||||
<Search placeholder="输入用户名或邮箱、团队名搜索" value={search} onSearch={onSearch} />
|
||||
<Search placeholder="输入用户名或邮箱、团队名搜索" value={search} onSearch={(value)=>setQuery(value)} />
|
||||
</div>
|
||||
<Sort menu={menu}>
|
||||
<a className="color-blue">角色筛选<i className="iconfont icon-sanjiaoxing-down ml3 font-14"></i></a>
|
||||
</Sort>
|
||||
</FlexAJ>
|
||||
<div className="pl30 pr30 pb30">
|
||||
<Table
|
||||
|
@ -303,7 +163,7 @@ export default ((props) => {
|
|||
{
|
||||
total > limit ?
|
||||
<div className="edu-txt-center mt30 mb20">
|
||||
<Pagination simple defaultCurrent={page} total={total} pageSize={limit} onChange={ChangePage}></Pagination>
|
||||
<Pagination simple defaultCurrent={page} total={total} pageSize={limit} onChange={(page)=>setPage(page)}></Pagination>
|
||||
</div>
|
||||
: ""
|
||||
}
|
||||
|
|
|
@ -3,56 +3,35 @@ import axios from 'axios';
|
|||
import { AutoComplete, Pagination, List, Popconfirm, Dropdown, Spin } from 'antd';
|
||||
import { WhiteBack, Blueline, FlexAJ, GroupProjectBackgroup, Greenline, Redline } from '../../../Component/layout';
|
||||
import Title from '../../../Component/Title';
|
||||
const faker_projects = [
|
||||
{
|
||||
id: 2,
|
||||
project: {
|
||||
owner_name: "ceshi_org_1",
|
||||
name: "jajaj0",
|
||||
identifier: "ssjsksjsk"
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
project: {
|
||||
owner_name: "sylor_test",
|
||||
name: "sylor_test",
|
||||
identifier: "sylor_test"
|
||||
}
|
||||
}
|
||||
]
|
||||
const { Option } = AutoComplete;
|
||||
const limit = 15;
|
||||
// 使用了faker数据,后续需要修改
|
||||
function GroupProjectSetting(props) {
|
||||
const [isSpin, setIsSpin] = useState(false);
|
||||
const [projects, setProjects] = useState(undefined);
|
||||
const [page, setPage] = useState(1);
|
||||
const [limit, setLimit] = useState(15);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [search, setQuery] = useState(undefined);
|
||||
const [repo_name, setRepoName] = useState(undefined);
|
||||
|
||||
const [ search , setSearch ] = useState("");
|
||||
const [ optionsSource , setOptionsSource ] = useState(undefined);
|
||||
|
||||
const { OIdentifier, groupId } = props.match.params;
|
||||
|
||||
useEffect(() => {
|
||||
get_project()
|
||||
}, [page, search])
|
||||
}, [page])
|
||||
|
||||
function get_project() {
|
||||
setIsSpin(true)
|
||||
setIsSpin(true);
|
||||
const url = `/organizations/${OIdentifier}/teams/${groupId}/team_projects.json`;
|
||||
axios
|
||||
.get(url, {
|
||||
params: {
|
||||
page,
|
||||
search,
|
||||
limit
|
||||
},
|
||||
axios.get(url, {
|
||||
params: {page,limit},
|
||||
})
|
||||
.then((result) => {
|
||||
if (result && result.data && result.data.team_projects.length > 0) {
|
||||
if (result && result.data) {
|
||||
setProjects(result.data.team_projects)
|
||||
setTotal(result.data.total_count)
|
||||
} else {
|
||||
setProjects(faker_projects)
|
||||
}
|
||||
}).catch((error) => { });
|
||||
setIsSpin(false)
|
||||
|
@ -70,7 +49,6 @@ function GroupProjectSetting(props) {
|
|||
.then((result) => {
|
||||
if (result && result.data.status > -1) {
|
||||
setPage(1)
|
||||
setQuery(undefined)
|
||||
get_project()
|
||||
}
|
||||
}).catch((error) => { });
|
||||
|
@ -87,35 +65,80 @@ function GroupProjectSetting(props) {
|
|||
|
||||
// 添加单个项目
|
||||
function addSingleProject(){
|
||||
setIsSpin(true)
|
||||
if(repo_name){
|
||||
setIsSpin(true);
|
||||
const url = `/organizations/${OIdentifier}/teams/${groupId}/team_projects.json`;
|
||||
axios.post(url, {repo_name: repo_name})
|
||||
axios.post(url, {repo_name})
|
||||
.then((result) => {
|
||||
if (result && result.data.id) {
|
||||
setPage(1)
|
||||
setQuery(undefined)
|
||||
get_project()
|
||||
}
|
||||
}).catch((error) => { });
|
||||
setIsSpin(false)
|
||||
}).catch((error) => {setIsSpin(false)});
|
||||
}else{
|
||||
props.showNotification("请选择要添加的项目!");
|
||||
}
|
||||
}
|
||||
|
||||
// 搜索项目有关
|
||||
useEffect(()=>{
|
||||
const url = `/organizations/${OIdentifier}/projects/search.json`;
|
||||
axios.get(url,{
|
||||
params:{
|
||||
search
|
||||
}
|
||||
}).then(result=>{
|
||||
if(result && result.data){
|
||||
setOptions(result.data.projects);
|
||||
}
|
||||
}).catch(error=>{})
|
||||
},[search])
|
||||
function setOptions(data){
|
||||
const s = data && data.map((item, key) => {
|
||||
return (
|
||||
<Option
|
||||
key={key}
|
||||
value={`${item.id}`}
|
||||
searchValue={`${item.name}`}
|
||||
>
|
||||
{item.name}
|
||||
</Option>
|
||||
);
|
||||
});
|
||||
setOptionsSource(s);
|
||||
}
|
||||
function changeInput(value){
|
||||
let s = value || "";
|
||||
setSearch(s);
|
||||
}
|
||||
function selectInput(value,e){
|
||||
setRepoName(value);
|
||||
}
|
||||
|
||||
return (
|
||||
<Spin spinning={isSpin}>
|
||||
<WhiteBack className="mb30">
|
||||
<Title>
|
||||
<FlexAJ style={{width:"100%"}}>
|
||||
<span>团队项目管理</span>
|
||||
</Title>
|
||||
<FlexAJ className="padding20-30">
|
||||
<GroupProjectBackgroup>
|
||||
<FlexAJ>
|
||||
<div>
|
||||
<AutoComplete
|
||||
style={{ width: 300 }}
|
||||
placeholder="搜索项目..."
|
||||
/>
|
||||
onChange={changeInput}
|
||||
onSelect={selectInput}
|
||||
allowClear
|
||||
>
|
||||
{optionsSource}
|
||||
</AutoComplete>
|
||||
<Blueline className="ml30" onClick={()=>addSingleProject()}>+ 添加项目</Blueline>
|
||||
</div>
|
||||
</FlexAJ>
|
||||
</Title>
|
||||
{/* <FlexAJ className="padding20-30">
|
||||
<GroupProjectBackgroup>
|
||||
<FlexAJ>
|
||||
<div>
|
||||
<Popconfirm
|
||||
title="确认添加所有成员的项目吗?"
|
||||
|
@ -137,8 +160,8 @@ function GroupProjectSetting(props) {
|
|||
</div>
|
||||
</FlexAJ>
|
||||
</GroupProjectBackgroup>
|
||||
</FlexAJ>
|
||||
<div className="padding20-30"style={{paddingTop:"0px"}}>
|
||||
</FlexAJ>*/}
|
||||
<div className="padding20-30"style={{paddingTop:"0px",minHeight:"400px"}}>
|
||||
<List
|
||||
itemLayout="horizontal"
|
||||
dataSource={projects}
|
||||
|
@ -151,7 +174,7 @@ function GroupProjectSetting(props) {
|
|||
okText="确认"
|
||||
cancelText="取消"
|
||||
>
|
||||
<a className="color-red" href="#">移除</a>
|
||||
<a className="color-red">移除</a>
|
||||
</Popconfirm>
|
||||
}
|
||||
>
|
||||
|
@ -162,7 +185,6 @@ function GroupProjectSetting(props) {
|
|||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{
|
||||
total > limit ?
|
||||
<div className="edu-txt-center mt30 mb20">
|
||||
|
|
|
@ -49,7 +49,7 @@ function RightBox({ OIdentifier , history }) {
|
|||
|
||||
function getMember(iden){
|
||||
const url = `/organizations/${iden}/organization_users.json`;
|
||||
axios.get(url).then(result=>{
|
||||
axios.get(url,{params:{limit:5}}).then(result=>{
|
||||
if(result && result.data){
|
||||
setMemberData(result.data);
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ function RightBox({ OIdentifier , history }) {
|
|||
}
|
||||
function getGroup(iden){
|
||||
const url = `/organizations/${iden}/teams.json`;
|
||||
axios.get(url).then(result=>{
|
||||
axios.get(url,{params:{limit:5}}).then(result=>{
|
||||
if(result && result.data){
|
||||
setGroupData(result.data);
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@ import Title from '../../Component/Title';
|
|||
import styled from 'styled-components';
|
||||
import UploadImage from '../Component/UploadImage';
|
||||
import axios from 'axios';
|
||||
import Modals from '../Component/Modals';
|
||||
|
||||
import { getImageUrl } from 'educoder';
|
||||
const TextArea = Input.TextArea;
|
||||
|
||||
|
@ -22,6 +24,7 @@ export default Form.create()(
|
|||
const [ imageFlag , setImageFlag ] = useState(false);
|
||||
const [ password , setPassword ] = useState(undefined);
|
||||
const [ passwordFlag , setPasswordFlag ] = useState(false);
|
||||
const [ visible , setVisible ] = useState(false);
|
||||
const { getFieldDecorator , validateFields , setFieldsValue } = form;
|
||||
|
||||
useEffect(()=>{
|
||||
|
@ -74,9 +77,13 @@ export default Form.create()(
|
|||
function deleteOrganize(){
|
||||
if(!password){
|
||||
setPasswordFlag(true);
|
||||
return
|
||||
}else{
|
||||
setPasswordFlag(false);
|
||||
setVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
function onOk(password){
|
||||
const url = `/organizations/${organizeDetail.id}.json`;
|
||||
axios.delete(url,{
|
||||
params:{ password }
|
||||
|
@ -86,7 +93,7 @@ export default Form.create()(
|
|||
history.push(`/users/${current_user && current_user.login}/organizes`);
|
||||
}
|
||||
})
|
||||
}
|
||||
setVisible(false);
|
||||
}
|
||||
return(
|
||||
<div>
|
||||
|
@ -159,6 +166,9 @@ export default Form.create()(
|
|||
{ passwordFlag && <span className="color-red ml10">请输入密码</span>}
|
||||
</div>
|
||||
<a className="warningDelete" onClick={deleteOrganize}>删除组织</a>
|
||||
<Modals visible={visible} okText={"确定"} cancelText={"取消"} onCancel={()=>setVisible(false)} onOk={()=>onOk(password)}>
|
||||
<p className="font-16 edu-txt-center">确定要删除当前组织吗?</p>
|
||||
</Modals>
|
||||
</FlexAJ>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import React , { useEffect , useState } from 'react';
|
||||
import { WhiteBack , Banner , Blueline } from '../../Component/layout';
|
||||
import styled from 'styled-components';
|
||||
import Axios from 'axios';
|
||||
import { Pagination , Popconfirm } from 'antd';
|
||||
import axios from 'axios';
|
||||
import { Pagination } from 'antd';
|
||||
import { getImageUrl } from 'educoder';
|
||||
import LeaveTeam from '../Component/LeaveTeam';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
const SpanName = styled.span`{
|
||||
font-size:16px;
|
||||
|
@ -13,15 +15,6 @@ const SpanFoot = styled.span`{
|
|||
margin-right:5px;
|
||||
color:#333
|
||||
}`
|
||||
const ALink = styled.a`{
|
||||
border:1px solid #F73030;
|
||||
color:#F73030!important;
|
||||
height:32px;
|
||||
line-height:30px;
|
||||
display:block;
|
||||
padding:0px 15px;
|
||||
border-radius:2px;
|
||||
}`
|
||||
const ImgContent = styled.img`{
|
||||
height:44px;
|
||||
width:44px;
|
||||
|
@ -33,19 +26,18 @@ function TeamSettingGroup({organizeDetail,history}){
|
|||
const [ list ,setList ] = useState(undefined);
|
||||
const [ page ,setPage ] = useState(1);
|
||||
const [ total ,setTotal ] = useState(0);
|
||||
const [ search ,setSearch ] = useState(undefined);
|
||||
|
||||
useEffect(()=>{
|
||||
if(organizeDetail){
|
||||
getData();
|
||||
}
|
||||
},[organizeDetail,page,search]);
|
||||
},[organizeDetail,page]);
|
||||
|
||||
function getData(){
|
||||
const url = `/organizations/${organizeDetail.id}/teams.json`;
|
||||
Axios.get(url,{
|
||||
axios.get(url,{
|
||||
params:{
|
||||
page,limit,search
|
||||
page,limit
|
||||
}
|
||||
}).then(result=>{
|
||||
if(result && result.data){
|
||||
|
@ -58,7 +50,7 @@ function TeamSettingGroup({organizeDetail,history}){
|
|||
// 当前用户离开团队
|
||||
function removeMember(teamid){
|
||||
const url = `/organizations/${organizeDetail.id}/teams/${teamid}/team_users/quit.json`;
|
||||
Axios.delete(url).then(result=>{
|
||||
axios.delete(url).then(result=>{
|
||||
if(result && result.data){
|
||||
getData();
|
||||
}
|
||||
|
@ -81,10 +73,10 @@ function TeamSettingGroup({organizeDetail,history}){
|
|||
return(
|
||||
<div>
|
||||
<p className="g-head">
|
||||
<SpanName>{item.name}</SpanName>
|
||||
<Link to={`/organize/${organizeDetail && organizeDetail.name}/group/${item.id}`}><SpanName>{item.name}</SpanName></Link>
|
||||
<span className="df">
|
||||
{ item.is_member &&
|
||||
<Popconfirm title="确定离开团队?" okText="是" cancelText="否" onConfirm={()=>removeMember(item.id)}><ALink>离开团队</ALink></Popconfirm>
|
||||
<LeaveTeam teamID={item.id} onOk={removeMember}/>
|
||||
}
|
||||
{ item.is_admin && <Blueline className="ml15" onClick={()=>toGroupSetting(item.id)}>团队设置</Blueline> }
|
||||
</span>
|
||||
|
|
|
@ -51,95 +51,60 @@ export default (({organizeDetail})=>{
|
|||
}).catch(error=>{})
|
||||
}
|
||||
|
||||
// 获取搜索用户框里面选择的用户ID,方便添加组织成员
|
||||
function getUser(login){
|
||||
serChoiceId(login);
|
||||
}
|
||||
// 切换分页
|
||||
function ChangePage(page){
|
||||
setPage(page);
|
||||
}
|
||||
|
||||
const menu=(
|
||||
<Menu>
|
||||
<Menu.Item key="all">全部</Menu.Item>
|
||||
<Menu.Item key="Manager">管理员</Menu.Item>
|
||||
<Menu.Item key="Developer">开发者</Menu.Item>
|
||||
<Menu.Item key="Reporter">报告者</Menu.Item>
|
||||
</Menu>
|
||||
)
|
||||
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',
|
||||
dataIndex: 'user',
|
||||
width:"5%",
|
||||
render:(value,item)=>{
|
||||
render:(value)=>{
|
||||
return(
|
||||
item.user && <Img src={getImageUrl('images/'+item.user.image_url)}></Img>
|
||||
value && <Img src={getImageUrl('images/'+value.image_url)}></Img>
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '用户名',
|
||||
dataIndex: 'name',
|
||||
dataIndex: 'user',
|
||||
width:"15%",
|
||||
render:(value,item)=>{
|
||||
return(
|
||||
item.user && item.user.name
|
||||
)
|
||||
return value && value.name
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '邮箱',
|
||||
dataIndex: 'mail',
|
||||
dataIndex: 'user',
|
||||
width:"25%",
|
||||
align:"left",
|
||||
render:(value,item)=>{
|
||||
return(
|
||||
item.user && item.user.mail
|
||||
)
|
||||
render:(value)=>{
|
||||
return value && value.mail
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '所属团队',
|
||||
dataIndex: 'team',
|
||||
dataIndex: 'team_names',
|
||||
width:"20%",
|
||||
render:(value,item)=>{
|
||||
return item.team_names && item.team_names.length > 0 && item.team_names[0]
|
||||
render:(value)=>{
|
||||
let array = value && value.length > 0 && value.map((i,k)=>{
|
||||
return (i+",")
|
||||
})
|
||||
console.log(array && array[0]);
|
||||
return array && array[0].substring(0,array[0].length-1);
|
||||
}
|
||||
},
|
||||
// {
|
||||
// title: roleTitle,
|
||||
// dataIndex: 'role',
|
||||
// width:"20%",
|
||||
// render:(value,item)=>{
|
||||
// return(
|
||||
// item.role
|
||||
// )
|
||||
// }
|
||||
// },
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'operation',
|
||||
width:"15%",
|
||||
render:(value,item)=>{
|
||||
return (organizeDetail && organizeDetail.is_admin ? "" :
|
||||
<Popconfirm title="是否将此成员移出组织?" okText={"是"} cancelText={"否"} onConfirm={()=>deleteMember(item.login)}><a className="color-grey-8">移除成员</a></Popconfirm>
|
||||
let c_isAdmin = organizeDetail && organizeDetail.is_admin;
|
||||
let last = (data && data.length === 1) && (item.team_names && item.team_names.length === 1 && item.team_names[0]==="Owners");
|
||||
return (
|
||||
c_isAdmin && !last && <Popconfirm title="是否将此成员移出组织?" okText={"是"} cancelText={"否"} onConfirm={()=>deleteMember(item.user && item.user.login)}><a className="color-grey-8">移除成员</a></Popconfirm>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -149,7 +114,7 @@ export default (({organizeDetail})=>{
|
|||
const url = `/organizations/${organizeDetail && organizeDetail.id}/organization_users/${login}.json`;
|
||||
axios.delete(url).then(result=>{
|
||||
if(result && result.data){
|
||||
|
||||
getData();
|
||||
}
|
||||
}).catch(error=>{})
|
||||
}
|
||||
|
|
|
@ -79,7 +79,7 @@ function Detail(props){
|
|||
<Cards
|
||||
src={`/organize/${detail.name}`}
|
||||
title={detail.name}
|
||||
desc={detail.description}
|
||||
desc={!buttonflag && detail.description}
|
||||
img={detail.avatar_url}
|
||||
rightBtn={
|
||||
<React.Fragment>
|
||||
|
|
|
@ -6,6 +6,7 @@ import { getImageUrl } from 'educoder';
|
|||
import Nodata from '../Nodata';
|
||||
import { Pagination } from 'antd';
|
||||
import { Link } from 'react-router-dom';
|
||||
import LeaveTeam from './Component/LeaveTeam';
|
||||
|
||||
const SpanFoot = styled.span`{
|
||||
margin-right:5px;
|
||||
|
@ -66,10 +67,10 @@ function TeamGroup({organizeDetail,current_user}){
|
|||
{
|
||||
list.map((item,key)=>{
|
||||
return(
|
||||
<div>
|
||||
<div key={key}>
|
||||
<p className="g-head">
|
||||
<Link to={`/organize/${organizeDetail.name}/group/${item.id}`} className="color-grey-3 font-16">{item.name}</Link>
|
||||
{item.is_member && <ALink onClick={()=>outTeam(item.id)}>离开团队</ALink>}
|
||||
{item.is_member && <LeaveTeam teamID={item.id} onOk={outTeam}/>}
|
||||
</p>
|
||||
<div className="g-body">
|
||||
{
|
||||
|
|
|
@ -1,23 +1,27 @@
|
|||
import React ,{ useEffect , useState } from 'react';
|
||||
import { Banner } from '../Component/layout';
|
||||
import { Banner , WhiteBack } from '../Component/layout';
|
||||
import Cards from '../Component/MemberCards';
|
||||
import axios from 'axios';
|
||||
import Nodata from '../Nodata';
|
||||
import { Pagination } from 'antd';
|
||||
|
||||
const limit = 15;
|
||||
function TeamMember({organizeDetail,current_user}){
|
||||
const [ page , setPage ] = useState(1);
|
||||
const [ total , setTotal ] = useState(0);
|
||||
const [ list , setList ] = useState(undefined);
|
||||
|
||||
useEffect(()=>{
|
||||
if(organizeDetail){
|
||||
getData();
|
||||
}
|
||||
},[organizeDetail]);
|
||||
},[organizeDetail,page]);
|
||||
|
||||
function getData(){
|
||||
const url = `/organizations/${organizeDetail.id}/organization_users.json`;
|
||||
axios.get(url).then(result=>{
|
||||
axios.get(url,{
|
||||
page,limit
|
||||
}).then(result=>{
|
||||
if(result && result.data){
|
||||
setList(result.data.organization_users);
|
||||
setTotal(result.data.total_count);
|
||||
|
@ -26,14 +30,13 @@ function TeamMember({organizeDetail,current_user}){
|
|||
}
|
||||
|
||||
return(
|
||||
<div>
|
||||
<WhiteBack style={{marginBottom:"30px"}}>
|
||||
<Banner>组织成员</Banner>
|
||||
{
|
||||
list && list.length > 0 ?
|
||||
<div className="memberBox">
|
||||
{
|
||||
list.map((item,key)=>{
|
||||
console.log(current_user);
|
||||
return(
|
||||
item.user && <Cards
|
||||
img={item.user.image_url}
|
||||
|
@ -41,6 +44,8 @@ function TeamMember({organizeDetail,current_user}){
|
|||
time={item.created_at}
|
||||
focusStatus={item.user.watched}
|
||||
is_current_user={current_user && current_user.login === item.user.login}
|
||||
login={item.user && item.user.login}
|
||||
successFunc={getData}
|
||||
/>
|
||||
)
|
||||
})
|
||||
|
@ -48,6 +53,12 @@ function TeamMember({organizeDetail,current_user}){
|
|||
</div>
|
||||
:<Nodata _html="暂无数据"/>
|
||||
}
|
||||
{
|
||||
total >limit &&
|
||||
<div className="mt20 pb20 edu-txt-center">
|
||||
<Pagination simple current={page} pageSize={limit} total={total} onChange={(page)=>setPage(page)}/>
|
||||
</div>
|
||||
}
|
||||
</WhiteBack>
|
||||
)
|
||||
}export default TeamMember
|
||||
}export default TeamMember;
|
|
@ -1,80 +1,44 @@
|
|||
import React, { Component } from "react";
|
||||
import React , {useState} from "react";
|
||||
import axios from "axios";
|
||||
import { Button } from "antd";
|
||||
import "./list.css";
|
||||
|
||||
class FocusButton extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
is_watch: false,
|
||||
id: "",
|
||||
isSpin: false,
|
||||
fontClass: "font-12",
|
||||
starText: "关注",
|
||||
is_block: false
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount = () => {
|
||||
this.set_watch();
|
||||
};
|
||||
|
||||
set_watch = () => {
|
||||
this.setState({
|
||||
is_watch: this.props.is_watch,
|
||||
id: this.props.id,
|
||||
isSpin: false,
|
||||
fontClass: this.props.fontClass ? this.props.fontClass : "font-12",
|
||||
starText: this.props.starText ? this.props.starText : "关注",
|
||||
is_block: this.props.is_block === undefined ? false : this.props.is_block
|
||||
});
|
||||
};
|
||||
|
||||
function FocusButton({is_watch , fontClass, starText, is_block , id , successFunc}){
|
||||
const [ isSpin , setIsSpin ] = useState(false);
|
||||
// 关注和取消关注
|
||||
focusFunc = (flag) => {
|
||||
const { id } = this.state;
|
||||
this.setState({ isSpin: true });
|
||||
function focusFunc(flag){
|
||||
setIsSpin(true);
|
||||
axios({
|
||||
method: flag ? "delete" : "post",
|
||||
url: `/watchers/${flag ? "unfollow" : "follow"}.json`,
|
||||
params: {
|
||||
target_type: "user",
|
||||
id: id,
|
||||
id,
|
||||
},
|
||||
})
|
||||
.then((result) => {
|
||||
}).then((result) => {
|
||||
if (result && result.data.status === 0) {
|
||||
this.setState({
|
||||
is_watch: result.data.watched,
|
||||
isSpin: false,
|
||||
});
|
||||
successFunc && successFunc();
|
||||
}
|
||||
setIsSpin(false);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.setState({ isSpin: false })
|
||||
});
|
||||
.catch((error) => {setIsSpin(false);});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { is_watch, isSpin, fontClass, starText, is_block } = this.state;
|
||||
|
||||
return (
|
||||
<Button type={is_watch ? "default" : "primary"} ghost={!is_watch} block={is_block} loading={isSpin} onClick={() => this.focusFunc(is_watch)}>
|
||||
<Button type={is_watch ? "default" : "primary"} ghost={!is_watch} block={is_block} loading={isSpin} onClick={() => focusFunc(is_watch)}>
|
||||
{is_watch ? (
|
||||
<span className="">
|
||||
<i className="iconfont icon-shixing font-15 text-yellow mr-4"></i>
|
||||
<span className={fontClass}>已关注</span>
|
||||
<span className={fontClass || "font-12"}>已关注</span>
|
||||
</span>
|
||||
) : (
|
||||
<span className="">
|
||||
<i className="iconfont icon-kongxing font-15"></i>
|
||||
<span className={fontClass}>{starText}</span>
|
||||
<span className={fontClass}>{starText || "关注"}</span>
|
||||
</span>
|
||||
)}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default FocusButton;
|
||||
|
|
Loading…
Reference in New Issue