This commit is contained in:
caishi 2021-02-02 18:26:55 +08:00
parent 34ba476011
commit 9380c0172c
14 changed files with 281 additions and 210 deletions

View File

@ -4,9 +4,9 @@ import nodata from './Images/nodata.png';
class Nodata extends Component{
render(){
const { _html } = this.props;
const { _html , small } = this.props;
return(
<div className="none_panels">
<div className={small ? "none_panels small":"none_panels"}>
<div>
<img src={nodata} alt="" />
<div className="none_p_title">{_html}</div>

View File

@ -1,69 +1,25 @@
import React, { useState, useEffect } from 'react';
import React from 'react';
import Cards from '../../Component/MemberCards';
import { getImageUrl } from 'educoder';
import axios from 'axios';
import { Spin, Empty,Pagination } from 'antd';
export default ((props) => {
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 { OIdentifier, groupId } = props.match.params;
const { current_user } = props;
useEffect(() => {
if(groupId && OIdentifier){
getMember();
}
}, [OIdentifier,groupId,page])
function getMember() {
setIsSpin(true)
const url = `/organizations/${OIdentifier}/teams/${groupId}/team_users.json`;
axios.get(url, {
params: {
page,
limit
},
})
.then((result) => {
if (result && result.data) {
setMembers(result.data.team_users)
setTotal(result.data.total_count)
}
}).catch((error) => { });
setIsSpin(false)
};
import Nodata from '../../Nodata';
export default (({ data , current_user }) => {
return (
<Spin spinning={isSpin}>
{ data && data.length > 0 ?
<div className="MemberBoxThree">
{
data.map((item, key) => {
return (
<Cards
img={item.user.image_url}
name={item.user.name}
time={item.created_at}
focusStatus={item.user.watched}
is_current_user={current_user && item.user.login === current_user.login}
login={item.user.login}
/>
)
})
}
</div>:""
}
data && data.length > 0 ?
<div className="MemberBoxThree">
{
total > limit ?
<div className="edu-txt-center mt30 mb20">
<Pagination simple defaultCurrent={page} total={total} pageSize={limit} onChange={ChangePage}></Pagination>
</div>
: ""
data.map((item, key) => {
return (
<Cards
img={item.user.image_url}
name={item.user.name}
time={item.created_at}
focusStatus={item.user.watched}
is_current_user={current_user && item.user.login === current_user.login}
login={item.user.login}
/>
)
})
}
</Spin>
</div>:<Nodata _html="暂无团队成员"/>
)
})

View File

@ -1,11 +1,12 @@
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import { Spin, Empty, Pagination } from 'antd';
import React from 'react';
import styled from 'styled-components';
import { Link } from 'react-router-dom';
import { getImageUrl } from 'educoder';
import Nodata from '../../Nodata';
const Box = styled.div`{
padding:0px 38px;
min-height:400px;
}`
const Div = styled.div`{
display:flex;
@ -22,51 +23,20 @@ const Imgs = styled.img`{
margin-right:12px;
border-radius:50%;
}`
const limit = 15;
export default ((props) => {
const [isSpin, setIsSpin] = useState(false);
const [projects, setProjects] = useState(undefined);
const [page, setPage] = useState(1);
const [total, setTotal] = useState(0);
const { OIdentifier, groupId } = props.match.params;
useEffect(() => {
get_project()
}, [page])
function get_project() {
setIsSpin(true)
const url = `/organizations/${OIdentifier}/teams/${groupId}/team_projects.json`;
axios.get(url, {
params: {
page,
limit
},
}).then((result) => {
if (result && result.data && result.data.team_projects.length > 0) {
setProjects(result.data.team_projects)
setTotal(result.data.total_count)
}
}).catch((error) => { });
setIsSpin(false)
}
export default (({projects}) => {
return (
projects && projects.length > 0 ?
<Box>
<Spin spinning={isSpin}>
{
projects && projects.length > 0 ? projects.map((item, key) => {
return (
<Div>
<Imgs src={item.project && getImageUrl(`images/${item.project.owner_image_url}`)}/>
<Link to={`/projects/${item.project.owner_name}/${item.project.name}`}>{item.project.name}</Link>
</Div>
)
}):<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
}
</Spin>
</Box>
{
projects.map((item, key) => {
return (
<Div>
<Imgs src={item.project && getImageUrl(`images/${item.project.owner_image_url}`)}/>
<Link to={`/projects/${item.project.owner_name}/${item.project.name}`}>{item.project.name}</Link>
</Div>
)
})
}
</Box>:<Nodata _html="暂无团队项目"/>
)
})

View File

@ -1,5 +1,5 @@
import React, { useState, useEffect } from 'react';
import { Button, Spin, Popconfirm, Empty } from 'antd';
import { Button , Popconfirm, Empty , Pagination } from 'antd';
import styled from 'styled-components';
import { Box, Short, Long, Gap, WhiteBack, AlignCenterBetween } from '../../Component/layout';
import Tabs from '../../Component/Tabs';
@ -15,11 +15,72 @@ const Leave = styled.a`{
padding:0px 14px;
height:30px;
line-height:30px;
}`
}`;
const limit = 15;
export default ((props) => {
const [nav, setNav] = useState('0');
const [ page , setPage ] = useState(1);
const [ total , setTotal ] = useState(0);
const [ projects , setProjects ] = useState(undefined);
const [ members , setMembers ] = useState(undefined);
const [ group , setGroup ] = useState(undefined);
const { OIdentifier, groupId } = props.match.params;
const { current_user , group } = props;
const { current_user } = props;
useEffect(()=>{
if(groupId){
getInit();
}
},[groupId]);
function getInit(){
const url = `/organizations/${OIdentifier}/teams/${groupId}.json`;
axios.get(url).then(result=>{
if(result && result.data){
setGroup(result.data);
}
}).catch(error=>{})
}
useEffect(()=>{
if(nav === "0"){
getMember(OIdentifier, groupId,page);
}else{
get_project(OIdentifier, groupId,page);
}
},[nav,page])
//
function getMember( OIdentifier, groupId, page ) {
const url = `/organizations/${OIdentifier}/teams/${groupId}/team_users.json`;
axios.get(url, {
params: {
page,
limit
},
})
.then((result) => {
if (result && result.data) {
setMembers(result.data.team_users);
setTotal(result.data.total_count);
}
}).catch((error) => { });
};
//
function get_project(OIdentifier,groupId,page) {
const url = `/organizations/${OIdentifier}/teams/${groupId}/team_projects.json`;
axios.get(url, {
params: {
page,limit
},
}).then((result) => {
if (result && result.data && result.data.team_projects.length > 0) {
setProjects(result.data.team_projects);
setTotal(result.data.total_count);
}
}).catch((error) => { });
}
//
function removeUser(username) {
@ -41,7 +102,7 @@ export default ((props) => {
<div>
<AlignCenterBetween>
<span className="color-grey-3">{group.name}</span>
{group.is_member ?
{group.is_member && !group.is_admin ?
<Popconfirm
title="确认离开团队吗?"
onConfirm={() => removeUser(current_user.login)}
@ -69,9 +130,15 @@ export default ((props) => {
<WhiteBack>
<Tabs nav={['团队成员', '团队项目']} index={nav} onChange={setNav}>
{
nav === "0" ? <Memberlist {...props} /> : <Grouplist {...props}/>
nav === "0" ? <Memberlist data={members} current_user={props.current_user}/> : <Grouplist projects={projects}/>
}
</Tabs>
{
total > limit &&
<div className="mt20 pb20 edu-txt-center">
<Pagination simple current={page} total={total} pageSize={limit} onChange={(page)=>setPage(page)}/>
</div>
}
</WhiteBack>
</Gap>
</Long>

View File

@ -18,7 +18,7 @@ const addStyle = {
}
export default Form.create()(
forwardRef(({ form,props, match, showNotification, history, GroupDetail }) => {
forwardRef(({ form , match, showNotification, history, GroupDetail }) => {
const [isSpin, setIsSpin] = useState(false);
const [check_box, setGroupDetail] = useState(false);
@ -72,7 +72,7 @@ export default Form.create()(
}).then(result => {
if (result && result.data) {
showNotification("基本设置更新成功!");
history.push(`/organizations/${OIdentifier}/teams/${groupId}`);
history.push(`/organize/${OIdentifier}/group/${groupId}`);
}
}).catch(error => { })
} else {
@ -82,7 +82,7 @@ export default Form.create()(
}).then(result => {
if (result && result.data) {
showNotification("团队创建成功!");
history.push(`/organizations/${OIdentifier}/teams/${result.data.id}`);
history.push(`/organize/${OIdentifier}/group/${result.data.id}`);
}
}).catch(error => { })
}
@ -130,9 +130,9 @@ export default Form.create()(
function cancelEdit(){
if(groupId){
history.push(`/organizations/${OIdentifier}/teams/${groupId}`);
history.push(`/organize/${OIdentifier}/group/${groupId}`);
}else{
history.push(`/organizations/${OIdentifier}/teams`);
history.push(`/organize/${OIdentifier}`);
}
}
return (

View File

@ -3,7 +3,9 @@ import GroupFrom from './GroupForm'
function GropNew(props){
return(
<GroupFrom {...props}></GroupFrom>
<div className="teamDetail">
<GroupFrom {...props}></GroupFrom>
</div>
)
}
export default GropNew;

View File

@ -7,11 +7,13 @@ import { withRouter } from "react-router";
import { SnackbarHOC } from "educoder";
import { CNotificationHOC } from "../../modules/courses/common/CNotificationHOC";
import { TPMIndexHOC } from "../../modules/tpm/TPMIndexHOC";
import '../css/index.scss';
import Detail from './Sub/Detail';
import './Index.scss';
const GroupNew = Loadable({
loader: () => import("./Group/GroupNew"),
loading: Loading,
});
const New = Loadable({
loader: () => import("./New"),
loading: Loading,
@ -20,7 +22,7 @@ const DetailIndex = Loadable({
loader: () => import("./Sub/Detail"),
loading: Loading,
});
const SubDetail = Loadable({
const SubDetailIndex = Loadable({
loader: () => import("./Sub/SubDetail"),
loading: Loading,
});
@ -29,11 +31,18 @@ export default withRouter(CNotificationHOC()(SnackbarHOC()(TPMIndexHOC(
return (
<div className="newMain">
<Switch>
{/* 组织团队-子级(不包含组织团队列表) */}
{/* 组织团队-设置 */}
<Route
path="/organize/:OIdentifier/group/:groupId"
path="/organize/:OIdentifier/group/:groupId/setting"
render={(p) => {
return <SubDetail {...props} {...p}/>
return <SubDetailIndex {...props} {...p}/>
}}
></Route>
{/* 组织团队-新建 */}
<Route
path="/organize/:OIdentifier/group/new"
render={(p) => {
return <GroupNew {...props} {...p}/>
}}
></Route>
{/* 组织团队-子级(包含组织团队列表) */}

View File

@ -66,6 +66,7 @@
}
.team{
padding:0px 32px;
min-height: 450px;
.team_project{
padding:22px 0px;
border-bottom: 1px solid #eee;
@ -202,6 +203,7 @@
}
.g-body{
padding:15px 25px;
min-height: 84px;
}
}
&>div:nth-child(2n){

View File

@ -5,6 +5,7 @@ import Box from './Box';
import axios from 'axios';
import { getImageUrl } from 'educoder';
import { Link } from 'react-router-dom';
import Nodata from '../Nodata';
const Span = styled.span`{
color:#888;
@ -83,32 +84,31 @@ function RightBox({ OIdentifier , history }) {
</Box>
:""
}
{
groupData && groupData.teams && groupData.teams.length>0?
<Box
name="组织团队"
count={groupData && groupData.total_count}
bottom={<Button type={'primary'} onClick={()=>history.push(`/organize/${OIdentifier}/group/new`)}>新建团队</Button>}
url={`/organize/${OIdentifier}/group`}
>
{
groupData.teams.map((item,key)=>{
return(
<div className="teammembers" key={key}>
<div>
<Link to={`/organize/${OIdentifier}/group/${item.id}`}><ColorListName>{item.name}</ColorListName></Link>
<Align>
<Span>{item.num_users}名成员</Span>
<Span>{item.num_projects}个仓库</Span>
</Align>
</div>
<Box
name="组织团队"
count={groupData && groupData.total_count}
bottom={<Button type={'primary'} onClick={()=>history.push(`/organize/${OIdentifier}/group/new`)}>新建团队</Button>}
url={`/organize/${OIdentifier}/group`}
>
{
groupData && groupData.teams && groupData.teams.length>0?
<React.Fragment>
{groupData.teams.map((item,key)=>{
return(
<div className="teammembers" key={key}>
<div>
<Link to={`/organize/${OIdentifier}/group/${item.id}`}><ColorListName>{item.name}</ColorListName></Link>
<Align>
<Span>{item.num_users}名成员</Span>
<Span>{item.num_projects}个仓库</Span>
</Align>
</div>
)
})
}
</Box>
:""
}
</div>
)
})}
</React.Fragment>:<Nodata _html="暂无团队" small/>
}
</Box>
</div>
)
}

View File

@ -83,7 +83,7 @@ function TeamSettingGroup({organizeDetail,history}){
<p className="g-head">
<SpanName>{item.name}</SpanName>
<span className="df">
{ item.is_member && !item.is_admin &&
{ item.is_member &&
<Popconfirm title="确定离开团队?" okText="是" cancelText="否" onConfirm={()=>removeMember(item.id)}><ALink>离开团队</ALink></Popconfirm>
}
{ item.is_admin && <Blueline className="ml15" onClick={()=>toGroupSetting(item.id)}>团队设置</Blueline> }

View File

@ -7,6 +7,10 @@ import Cards from '../../Component/Cards';
import axios from 'axios';
import '../Index.scss';
const GroupDetails = Loadable({
loader: () => import("../Group/GroupDetails"),
loading: Loading,
});
const Group = Loadable({
loader: () => import("../TeamGroup"),
loading: Loading,
@ -29,15 +33,21 @@ function Detail(props){
const [ detail , setDetail ] = useState(undefined);
const [ flag , setFlag ] = useState(true);
const [ buttonflag , setButtonflagFlag ] = useState(false);
//
useEffect(()=>{
if(pathname){
if(pathname.indexOf("/setting")>-1 && pathname.indexOf("/organize")>-1){
if(pathname.indexOf(`/organize/${OIdentifier}/setting`)>-1){
setFlag(false);
}else{
setFlag(true);
}
if(pathname.indexOf(`/organize/${OIdentifier}/group`)>-1 || pathname.indexOf(`/organize/${OIdentifier}/member`)>-1){
setButtonflagFlag(true);
}else{
setButtonflagFlag(false);
}
}
},[pathname])
@ -71,11 +81,31 @@ function Detail(props){
title={detail.name}
desc={detail.description}
img={detail.avatar_url}
rightBtn={flag && <AlignCenter className="color-blue"><Link to={`/organize/${OIdentifier}/setting`} className="color-blue">设置</Link><i className="iconfont icon-shezhi2 ml3"></i></AlignCenter>}
rightBtn={
<React.Fragment>
{flag && !buttonflag && <AlignCenter className="color-blue">
<Link to={`/organize/${OIdentifier}/setting`} className="color-blue">设置</Link>
<i className="iconfont icon-shezhi2 ml3"></i>
</AlignCenter>}
{buttonflag &&
<span className="subNavs">
<Link to={`/organize/${OIdentifier}/member`} className={pathname ===`/organize/${OIdentifier}/member` ? "active":""}><span>组织成员</span>{detail.num_users && <lable>{detail.num_users}</lable>}</Link>
<Link to={`/organize/${OIdentifier}/group`} className={pathname ===`/organize/${OIdentifier}/group` ? "active":""}><span>组织团队</span>{detail.num_teams &&<lable>{detail.num_teams}</lable>}</Link>
</span>
}
</React.Fragment>
}
/>
}
<Switch {...props}>
{/* 组织团队-详情 */}
<Route
path="/organize/:OIdentifier/group/:groupId"
render={(p) => {
return <GroupDetails {...props} {...p} group={detail}/>
}}
></Route>
{/* 组织成员 */}
<Route
path="/organize/:OIdentifier/member"
@ -87,7 +117,7 @@ function Detail(props){
<Route
path="/organize/:OIdentifier/group"
render={(p) => {
return <Group {...props} {...p}/>
return <Group {...props} {...p} organizeDetail={detail}/>
}}
></Route>
<Route

View File

@ -7,14 +7,6 @@ import axios from 'axios';
import Cards from '../../Component/Cards';
const GroupNew = Loadable({
loader: () => import("../Group/GroupNew"),
loading: Loading,
});
const GroupDetails = Loadable({
loader: () => import("../Group/GroupDetails"),
loading: Loading,
});
const GroupSetting = Loadable({
loader: () => import("../Group/GroupDetailSetting"),
loading: Loading,
@ -24,11 +16,9 @@ export default ((props)=>{
const OIdentifier = props.match.params.OIdentifier;
const groupId = props.match.params.groupId;
const pathname = props.location.pathname;
const [ detail , setDetail ] = useState(undefined);
const [ flag , setFlag ] = useState(false);
//
useEffect(()=>{
if(pathname){
@ -59,8 +49,8 @@ export default ((props)=>{
<div>
<i className="iconfont icon-zuobiao mr5"></i>
<Link to={`/organize/${OIdentifier}`}>{OIdentifier}</Link>
<i className="iconfont icon-youjiantou ml3 mr3 font-12"></i>
<span>{detail && detail.name}</span>
<i className="iconfont icon-youjiantou ml3 mr3 font-12 color-grey-9"></i>
<span className="color-grey-9">{detail ? detail.name : "新建团队"}</span>
</div>
{
detail &&
@ -84,20 +74,6 @@ export default ((props)=>{
return <GroupSetting {...props} {...p}/>
}}
></Route>
{/* 组织团队-新建 */}
<Route
path="/organize/:OIdentifier/group/new"
render={(p) => {
return <GroupNew {...props} {...p}/>
}}
></Route>
{/* 组织团队-详情 */}
<Route
path="/organize/:OIdentifier/group/:groupId"
render={(p) => {
return <GroupDetails {...props} {...p} group={detail}/>
}}
></Route>
</Switch>
</div>
)

View File

@ -1,11 +1,12 @@
import React from 'react';
import React , { useEffect , useState } from 'react';
import { Banner } from '../Component/layout';
import styled from 'styled-components';
import axios from 'axios';
import { getImageUrl } from 'educoder';
import Nodata from '../Nodata';
import { Pagination } from 'antd';
import { Link } from 'react-router-dom';
const SpanName = styled.span`{
font-size:16px;
color:#333;
}`
const SpanFoot = styled.span`{
margin-right:5px;
color:#333
@ -24,26 +25,78 @@ const ImgContent = styled.img`{
border-radius:50%;
margin:5px 20px 5px 0px;
}`
export default (()=>{
const limit = 14;
function TeamGroup({organizeDetail,current_user}){
const [ page , setPage ] = useState(1);
const [ total , setTotal ] = useState(0);
const [ list , setList ] = useState(undefined);
useEffect(()=>{
if(organizeDetail){
getData();
}
},[organizeDetail]);
function getData(){
const url = `/organizations/${organizeDetail.id}/teams.json`;
axios.get(url,{
params:{ page ,limit}
}).then(result=>{
if(result && result.data){
setList(result.data.teams);
setTotal(result.data.total_count);
}
})
}
//
function outTeam(id){
const url = `/organizations/${organizeDetail.id}/teams/${id}/team_users/quit.json`;
axios.delete(url).then(result =>{
if(result && result.data){
getData();
}
}).catch(error=>{})
}
return(
<div>
<div style={{background:"#fff",marginBottom:"30px"}}>
<Banner>组织团队</Banner>
<div className="groupBox">
<div>
<p className="g-head">
<SpanName>oweners</SpanName>
<ALink>离开团队</ALink>
</p>
<div className="g-body">
<ImgContent src="https://dss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=3331079987,1190181307&fm=111&gp=0.jpg"/>
<ImgContent src="https://dss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=3331079987,1190181307&fm=111&gp=0.jpg"/>
</div>
<p className="g-foot">
<SpanFoot>2&nbsp;名成员</SpanFoot>
<SpanFoot>1&nbsp;个项目</SpanFoot>
</p>
{
list && list.length > 0 ?
<div className="groupBox">
{
list.map((item,key)=>{
return(
<div>
<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>}
</p>
<div className="g-body">
{
item.users && item.users.map((i,k)=>{
return(
<ImgContent src={getImageUrl(`images/${i.image_url}`)}/>
)
})
}
</div>
<p className="g-foot">
<SpanFoot>{item.num_users}&nbsp;名成员</SpanFoot>
<SpanFoot>{item.num_projects}&nbsp;个项目</SpanFoot>
</p>
</div>
)
})
}
</div>:<Nodata _html="暂无数据"/>
}
{
total > limit &&
<div className="mt20 pb20 edu-txt-center">
<Pagination simple current={page} total={total} pageSize={limit} onChange={(page)=>setPage(page)}/>
</div>
</div>
}
</div>
)
})
}
export default TeamGroup;

View File

@ -89,9 +89,15 @@ ul,ol,dl{
display: flex;
justify-content: center;
align-items: center;
}
.none_panels img{
margin-bottom: 15px;
&.small{
height: 120px;
img{
width:50px;
}
}
img{
margin-bottom: 15px;
}
}
.none_p_title{
font-size: 16px;