forked from Gitlink/forgeplus-react
组织-基本管理
This commit is contained in:
parent
6deb8db08f
commit
f68842beff
|
@ -236,7 +236,6 @@ class App extends Component {
|
|||
path="/register"
|
||||
render={
|
||||
(props) => {
|
||||
|
||||
return (<EducoderLogin {...this.props} {...props} {...this.state} />)
|
||||
}
|
||||
}
|
||||
|
@ -248,7 +247,7 @@ class App extends Component {
|
|||
<Route path={"/organize"}
|
||||
render={
|
||||
(props) => {
|
||||
return (<OrganizeIndex {...this.props} {...props} {...this.state} />)
|
||||
return (<OrganizeIndex {...props} {...this.props} {...this.state} />)
|
||||
}
|
||||
}>
|
||||
</Route>
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import React from 'react';
|
||||
import { getImageUrl } from 'educoder';
|
||||
import './Component.scss';
|
||||
|
||||
export default (({img , title, desc , rightBtn})=>{
|
||||
function Cards({img , title, desc , rightBtn}){
|
||||
return(
|
||||
<div className="cards">
|
||||
<div className="img"><img src={img} alt=""/></div>
|
||||
<div className="img"><img src={getImageUrl(`images/${img}`)} alt=""/></div>
|
||||
<div className="content">
|
||||
<p className="titles">
|
||||
<span>{title}</span>
|
||||
|
@ -16,4 +17,5 @@ export default (({img , title, desc , rightBtn})=>{
|
|||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
export default Cards;
|
|
@ -27,6 +27,7 @@ li.ant-menu-item{
|
|||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
img{
|
||||
max-width: 100%;
|
||||
}
|
||||
|
@ -39,6 +40,8 @@ li.ant-menu-item{
|
|||
justify-content: space-between;
|
||||
margin-bottom: 10px!important;
|
||||
align-items: center;
|
||||
height: 22px;
|
||||
line-height: 22px;;
|
||||
&>span{
|
||||
font-size:18px ;
|
||||
color: #333;
|
||||
|
@ -50,6 +53,7 @@ li.ant-menu-item{
|
|||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
line-height: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ const { Search } = Input;
|
|||
export default ({ placeholder , onSearch }) => {
|
||||
return (
|
||||
<Search
|
||||
allowClear
|
||||
placeholder={placeholder}
|
||||
enterButton={'搜索'}
|
||||
onSearch={onSearch}
|
||||
|
|
|
@ -31,14 +31,18 @@ const Infos = Loadable({
|
|||
loader: () => import("./users/Infos"),
|
||||
loading: Loading,
|
||||
});
|
||||
|
||||
class Index extends Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="newMain clearfix">
|
||||
<Handbook />
|
||||
<Switch {...this.props}>
|
||||
<Route
|
||||
path="/projects/:projectsType/new/:OIdentifier"
|
||||
render={(props) => (
|
||||
<ProjectNew {...this.props} {...props} />
|
||||
)}
|
||||
></Route>
|
||||
<Route
|
||||
path="/projects/:projectsType/new"
|
||||
render={(props) => (
|
||||
|
|
|
@ -153,7 +153,7 @@ class MergeFooter extends Component {
|
|||
}
|
||||
{
|
||||
filesData && filesData.files && filesData.files.length>0 &&
|
||||
<TabPane tab={
|
||||
<TabPane tab={
|
||||
<span><span className="font-16">文件</span>
|
||||
{filesCount > 0 && <span className="tabNum">{filesCount}</span>}
|
||||
</span>
|
||||
|
|
|
@ -23,18 +23,22 @@ class Index extends Component {
|
|||
LanguageList: undefined,
|
||||
GitignoreList: undefined,
|
||||
LicensesList: undefined,
|
||||
OwnerList: undefined,
|
||||
isSpin: false,
|
||||
|
||||
project_language_id: undefined,
|
||||
project_category_id: undefined,
|
||||
license_id: undefined,
|
||||
ignore_id: undefined,
|
||||
owners_id:undefined,
|
||||
|
||||
project_language_list: undefined,
|
||||
project_category_list: undefined,
|
||||
license_list: undefined,
|
||||
ignore_list: undefined,
|
||||
|
||||
owners_list:undefined,
|
||||
|
||||
project_language_name: undefined,
|
||||
project_category_name: undefined,
|
||||
license_name: undefined,
|
||||
|
@ -42,6 +46,8 @@ class Index extends Component {
|
|||
}
|
||||
}
|
||||
componentDidMount = () => {
|
||||
// 获取拥有者列表
|
||||
this.getOwner();
|
||||
// 获取项目类别
|
||||
this.getCategory();
|
||||
// 获取项目语言
|
||||
|
@ -50,7 +56,6 @@ class Index extends Component {
|
|||
this.getGitignore();
|
||||
// 获取开源许可证
|
||||
this.getLicenses();
|
||||
|
||||
}
|
||||
componentDidUpdate=(prevPros)=>{
|
||||
if(prevPros && this.props && !this.props.checkIfLogin()){
|
||||
|
@ -58,6 +63,30 @@ class Index extends Component {
|
|||
return
|
||||
}
|
||||
}
|
||||
|
||||
getOwner=()=>{
|
||||
const { OIdentifier } = this.props.match.params;
|
||||
const url = `/owners.json`;
|
||||
axios.get(url).then(result=>{
|
||||
if(result && result.data){
|
||||
let owner = result.data.owners;
|
||||
if(OIdentifier){
|
||||
owner = owner.filter(item=>item.name === OIdentifier);
|
||||
this.props.form.setFieldsValue({
|
||||
user_id:OIdentifier
|
||||
})
|
||||
this.setState({
|
||||
owners_id:owner && owner[0].id
|
||||
})
|
||||
}
|
||||
this.setOptionsList(owner, 'owners');
|
||||
this.setState({
|
||||
OwnerList: owner,
|
||||
})
|
||||
}
|
||||
}).catch(error=>{})
|
||||
}
|
||||
|
||||
getCategory = () => {
|
||||
const url = `/project_categories.json`
|
||||
axios.get(url).then((result) => {
|
||||
|
@ -131,8 +160,8 @@ class Index extends Component {
|
|||
isSpin: true
|
||||
})
|
||||
const { current_user } = this.props;
|
||||
const { projectsType } = this.props.match.params;
|
||||
const { project_language_id, project_category_id, license_id, ignore_id } = this.state;
|
||||
const { projectsType , OIdentifier } = this.props.match.params;
|
||||
const { project_language_id, project_category_id, license_id, ignore_id , owners_id } = this.state;
|
||||
const decoderPass = Base64.encode(values.password);
|
||||
const url = projectsType === "deposit" ? "/projects.json" : "/projects/migrate.json";
|
||||
axios.post(url, {
|
||||
|
@ -142,7 +171,7 @@ class Index extends Component {
|
|||
project_category_id,
|
||||
license_id,
|
||||
ignore_id,
|
||||
user_id: current_user.user_id
|
||||
user_id:owners_id
|
||||
}).then((result) => {
|
||||
if (result) {
|
||||
if (result.data.id) {
|
||||
|
@ -150,7 +179,7 @@ class Index extends Component {
|
|||
isSpin: false
|
||||
})
|
||||
this.props.showNotification(`${projectsType === "deposit" ? "托管" : "镜像"}项目创建成功!`);
|
||||
this.props.history.push(`/projects/${current_user && current_user.login}/${result.data.identifier}`);
|
||||
this.props.history.push(`/projects/${OIdentifier ? OIdentifier :(current_user && current_user.login)}/${result.data.identifier}`);
|
||||
}
|
||||
}
|
||||
}).catch((error) => {
|
||||
|
@ -230,20 +259,13 @@ class Index extends Component {
|
|||
const { projectsType } = this.props.match.params;
|
||||
|
||||
const {
|
||||
preType,
|
||||
languageValue,
|
||||
gitignoreType,
|
||||
LicensesType,
|
||||
|
||||
CategoryList,
|
||||
LanguageList,
|
||||
GitignoreList,
|
||||
LicensesList,
|
||||
isSpin,
|
||||
project_language_name,
|
||||
project_category_name,
|
||||
license_name,
|
||||
ignore_name,
|
||||
owners_list,
|
||||
OwnerList,
|
||||
|
||||
project_language_list,
|
||||
project_category_list,
|
||||
|
@ -259,6 +281,24 @@ class Index extends Component {
|
|||
<Spin spinning={isSpin}>
|
||||
<Form>
|
||||
<div className="newPanel_content">
|
||||
<Form.Item
|
||||
label="拥有者"
|
||||
>
|
||||
{getFieldDecorator('user_id', {
|
||||
rules: [{
|
||||
required: true, message: '请选择拥有者'
|
||||
}],
|
||||
})(
|
||||
<AutoComplete
|
||||
placeholder="请选择拥有者"
|
||||
onChange={(value, e) => this.ChangePlatform(value, e, 'owners', OwnerList)}
|
||||
className="plateAutoComplete"
|
||||
onBlur={(value) => this.blurCategory(value, OwnerList, "owners")}
|
||||
>
|
||||
{owners_list}
|
||||
</AutoComplete>
|
||||
)}
|
||||
</Form.Item>
|
||||
{
|
||||
projectsType !== "deposit" &&
|
||||
<React.Fragment>
|
||||
|
|
|
@ -4,7 +4,6 @@ import { getUploadActionUrl } from 'educoder';
|
|||
|
||||
function UploadImage({ getImage , url }){
|
||||
const [ imageUrl , setImageUrl ] = useState(undefined);
|
||||
|
||||
useEffect(()=>{
|
||||
if(url){
|
||||
setImageUrl(url);
|
||||
|
|
|
@ -11,25 +11,33 @@ const Common = Loadable({
|
|||
loader: () => import("./SettingCommon"),
|
||||
loading: Loading,
|
||||
});
|
||||
const Member = Loadable({
|
||||
loader: () => import("./Setting/GroupMemberSetting"),
|
||||
loading: Loading,
|
||||
});
|
||||
const Project = Loadable({
|
||||
loader: () => import("./Setting/GroupProjectSetting"),
|
||||
loading: Loading,
|
||||
});
|
||||
export default (props)=>{
|
||||
const pathname = props.location.pathname;
|
||||
const organizeId = props.match.params.organizeId;
|
||||
const memberId = props.match.params.memberId;
|
||||
const OIdentifier = props.match.params.OIdentifier;
|
||||
const groupId = props.match.params.groupId;
|
||||
|
||||
function returnActive (pathname){
|
||||
let a = 0;
|
||||
if(pathname === `/organize/${organizeId}/member/${memberId}/setting/member`){
|
||||
if(pathname === `/organize/${OIdentifier}/group/${groupId}/setting/member`){
|
||||
a = 1;
|
||||
}else if(pathname === `/organize/${organizeId}/member/${memberId}/setting/project`){
|
||||
}else if(pathname === `/organize/${OIdentifier}/group/${groupId}/setting/project`){
|
||||
a = 2;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
const active = returnActive(pathname);
|
||||
const array = {list:[
|
||||
{name:'基本设置',icon:"icon-base",href:`/organize/${organizeId}/member/${memberId}/setting`},
|
||||
{name:'团队成员管理',icon:"icon-zuzhichengyuan",href:`/organize/${organizeId}/member/${memberId}/setting/member`},
|
||||
{name:'团队项目管理',icon:"icon-zuzhixiangmu",href:`/organize/${organizeId}/member/${memberId}/setting/project`},
|
||||
{name:'基本设置',icon:"icon-base",href:`/organize/${OIdentifier}/group/${groupId}/setting`},
|
||||
{name:'团队成员管理',icon:"icon-zuzhichengyuan",href:`/organize/${OIdentifier}/group/${groupId}/setting/member`},
|
||||
{name:'团队项目管理',icon:"icon-zuzhixiangmu",href:`/organize/${OIdentifier}/group/${groupId}/setting/project`},
|
||||
],
|
||||
active
|
||||
}
|
||||
|
@ -43,7 +51,19 @@ export default (props)=>{
|
|||
<WhiteBack>
|
||||
<Switch>
|
||||
<Route
|
||||
path="/organize/:organizeId/member/:memberId/setting"
|
||||
path="/organize/:OIdentifier/group/:groupId/setting/project"
|
||||
render={() => (
|
||||
<Project {...props} />
|
||||
)}
|
||||
></Route>
|
||||
<Route
|
||||
path="/organize/:OIdentifier/group/:groupId/setting/member"
|
||||
render={() => (
|
||||
<Member {...props} />
|
||||
)}
|
||||
></Route>
|
||||
<Route
|
||||
path="/organize/:OIdentifier/group/:groupId/setting"
|
||||
render={() => (
|
||||
<Common {...props} />
|
||||
)}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
import React , { useState } from 'react';
|
||||
|
||||
|
||||
function GroupMemberSetting() {
|
||||
return(
|
||||
<div>团队成员管理</div>
|
||||
)
|
||||
}
|
||||
export default GroupMemberSetting;
|
|
@ -0,0 +1,9 @@
|
|||
import React , { useState } from 'react';
|
||||
|
||||
|
||||
function GroupProjectSetting() {
|
||||
return(
|
||||
<div>团队项目管理</div>
|
||||
)
|
||||
}
|
||||
export default GroupProjectSetting;
|
|
@ -3,7 +3,7 @@ import React from 'react';
|
|||
import { Route, Switch } from "react-router-dom";
|
||||
import Loadable from "react-loadable";
|
||||
import Loading from "../../Loading";
|
||||
|
||||
import { withRouter } from "react-router";
|
||||
import { SnackbarHOC } from "educoder";
|
||||
import { CNotificationHOC } from "../../modules/courses/common/CNotificationHOC";
|
||||
import { TPMIndexHOC } from "../../modules/tpm/TPMIndexHOC";
|
||||
|
@ -23,43 +23,41 @@ const SubDetail = Loadable({
|
|||
loader: () => import("./Sub/SubDetail"),
|
||||
loading: Loading,
|
||||
});
|
||||
export default CNotificationHOC()(SnackbarHOC()(TPMIndexHOC(
|
||||
export default withRouter(CNotificationHOC()(SnackbarHOC()(TPMIndexHOC(
|
||||
((props)=>{
|
||||
return (
|
||||
<div className="newMain">
|
||||
<Switch {...props}>
|
||||
<Switch>
|
||||
{/* 组织团队 */}
|
||||
<Route
|
||||
path="/organize/:organizeId/group"
|
||||
render={(props) => {
|
||||
return <SubDetail {...props} />
|
||||
path="/organize/:OIdentifier/group"
|
||||
render={(p) => {
|
||||
return <SubDetail {...props} {...p}/>
|
||||
}}
|
||||
></Route>
|
||||
{/* 组织成员 */}
|
||||
<Route
|
||||
path="/organize/:organizeId/member/:memberId/setting"
|
||||
render={(props) => {
|
||||
return <DetailIndex {...props} />
|
||||
}}
|
||||
></Route>
|
||||
<Route
|
||||
path="/organize/:organizeId/member"
|
||||
render={(props) => {
|
||||
return <SubDetail {...props} />
|
||||
path="/organize/:OIdentifier/member"
|
||||
render={(p) => {
|
||||
return <SubDetail {...props} {...p}/>
|
||||
}}
|
||||
></Route>
|
||||
{/* 新建组织 */}
|
||||
<Route
|
||||
path="/organize/new"
|
||||
render={(props) => {
|
||||
return <New {...props} />
|
||||
render={(p) => {
|
||||
return <New {...props} {...p}/>
|
||||
}}
|
||||
></Route>
|
||||
{/* 组织详情(包含组织设置) */}
|
||||
<Route
|
||||
path="/organize/:organizeId"
|
||||
render={(props) => {
|
||||
return <DetailIndex {...props} />
|
||||
}}
|
||||
path="/organize/:OIdentifier"
|
||||
render={(p) => (
|
||||
<DetailIndex {...props} {...p}/>
|
||||
)}
|
||||
></Route>
|
||||
</Switch>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
)))
|
||||
))))
|
|
@ -47,6 +47,7 @@
|
|||
background-color: #fff;
|
||||
max-width: 860px;
|
||||
width: 72%;
|
||||
margin-bottom: 30px;
|
||||
.head{
|
||||
padding:16px 32px;
|
||||
border-bottom: 1px solid #eee;
|
||||
|
@ -102,6 +103,7 @@
|
|||
max-width: 340px;
|
||||
padding-left: 20px;
|
||||
box-sizing: border-box;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.box{
|
||||
background:rgba(255,255,255,1);
|
||||
|
|
|
@ -1,124 +1,110 @@
|
|||
import React from 'react';
|
||||
import { Button } from 'antd';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import Search from '../Component/Search';
|
||||
import Sort from '../Component/Sort';
|
||||
import ListCount from '../Component/ListCount';
|
||||
import Box from './Box';
|
||||
import './Index.scss';
|
||||
import styled from 'styled-components';
|
||||
import Item from './ListItem';
|
||||
import Right from './RightBox';
|
||||
import NoData from '../Nodata';
|
||||
|
||||
import { Menu } from 'antd';
|
||||
import { Menu , Pagination , Dropdown , Spin } from 'antd';
|
||||
import axios from 'axios';
|
||||
|
||||
const Span = styled.span`{
|
||||
color:#888;
|
||||
font-size:12px;
|
||||
margin-right:10px;
|
||||
}`
|
||||
const Align = styled.div`{
|
||||
display:flex;
|
||||
aligin:center;
|
||||
}`
|
||||
const ListName = styled.div`{
|
||||
font-size:14px;
|
||||
color:#333;
|
||||
margin-bottom:8px;
|
||||
height:18px;
|
||||
line-height:18px;
|
||||
}`;
|
||||
const ColorListName = styled.div`{
|
||||
color:#5091FF;
|
||||
font-size:14px;
|
||||
margin-bottom:8px;
|
||||
height:18px;
|
||||
line-height:18px;
|
||||
}`
|
||||
const Img = styled.img`{
|
||||
border-radius:50%;
|
||||
width:45px;
|
||||
height:45px;
|
||||
margin-right:12px;
|
||||
}`
|
||||
export default (()=>{
|
||||
function onSearch(value){
|
||||
const limit = 15;
|
||||
function List(props){
|
||||
const [ list , setList ] = useState(undefined);
|
||||
const [ isSpin , setIsSpin ] = useState(false);
|
||||
const [ totalCount , setTotalCount ] = useState(undefined);
|
||||
const [ search , setSearch ] = useState(undefined);
|
||||
const [ page , setPage ] = useState(1);
|
||||
const [ sortBy , setSortBy ] = useState("updated_on");
|
||||
const [ sortDirection , setSortDirection ] = useState("asc");
|
||||
|
||||
const OIdentifier = props.match.params.OIdentifier;
|
||||
|
||||
useEffect(()=>{
|
||||
if(OIdentifier){
|
||||
setIsSpin(true);
|
||||
getProject();
|
||||
}
|
||||
},[OIdentifier,sortBy,page,search])
|
||||
|
||||
function getProject(){
|
||||
const url = `/organizations/${OIdentifier}/projects.json`;
|
||||
axios.get(url,{
|
||||
params:{
|
||||
search,page,limit,
|
||||
sort_by:sortBy,
|
||||
sort_direction:sortDirection
|
||||
}
|
||||
}).then(result=>{
|
||||
if(result && result.data){
|
||||
setList(result.data.projects);
|
||||
setTotalCount(result.data.total_count);
|
||||
}
|
||||
setIsSpin(false);
|
||||
}).catch(error=>{setIsSpin(false);})
|
||||
}
|
||||
|
||||
function onSearch(value){
|
||||
setSearch(value);
|
||||
}
|
||||
|
||||
const menu=(
|
||||
<Menu>
|
||||
<Menu onClick={(e)=>setSortBy(e.key)}>
|
||||
<Menu.Item key="updated_on">更新时间排序</Menu.Item>
|
||||
<Menu.Item key="created_on">项目数排序</Menu.Item>
|
||||
<Menu.Item key="created_on">创建时间排序</Menu.Item>
|
||||
<Menu.Item key="praises_count">点赞数排序</Menu.Item>
|
||||
<Menu.Item key="forked_count">fork数排序</Menu.Item>
|
||||
</Menu>
|
||||
)
|
||||
const menu_new=(
|
||||
<Menu>
|
||||
<Menu.Item key="updated_on">新建托管项目</Menu.Item>
|
||||
<Menu.Item key="created_on">新建镜像项目</Menu.Item>
|
||||
<Menu.Item key="updated_on"><Link to={`/projects/deposit/new/${OIdentifier}`}>新建托管项目</Link></Menu.Item>
|
||||
<Menu.Item key="created_on"><Link to={`/projects/mirror/new/${OIdentifier}`}>新建镜像项目</Link></Menu.Item>
|
||||
</Menu>
|
||||
)
|
||||
const leftList = (
|
||||
<div className="team_project">
|
||||
<p className="t_p_title">
|
||||
<span className="flex1">
|
||||
<span className="name">react项目react项目react项目react项目</span>
|
||||
<i className="iconfont icon-banbenku font-20 color-green" />
|
||||
<i className="iconfont icon-jingxiang font-18 color-green" />
|
||||
<i className="iconfont icon-fork font-18 color-orange" />
|
||||
</span>
|
||||
<ListCount fork={1} parise={0}/>
|
||||
</p>
|
||||
<div className="desc">
|
||||
用于构建用户界面的 JavaScript 库
|
||||
</div>
|
||||
<div className="infos">
|
||||
<span className="font-12 color-grey-8">更新于1天前</span>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
return(
|
||||
<div className="list">
|
||||
<div className="list-l">
|
||||
<div className="head">
|
||||
<div style={{width:"370px"}}>
|
||||
<Search placeholder="输入仓库名称进行搜索" onSearch={onSearch}/>
|
||||
</div>
|
||||
<p>
|
||||
<Sort menu={menu_new}>
|
||||
<a className="addBtn mr30">+ 新建项目</a>
|
||||
</Sort>
|
||||
<Sort menu={menu}>
|
||||
<a className="color-blue">排序<i className="iconfont icon-sanjiaoxing-down ml3 font-14"></i></a>
|
||||
</Sort>
|
||||
</p>
|
||||
</div>
|
||||
<div className="team">
|
||||
{leftList}
|
||||
</div>
|
||||
</div>
|
||||
<div className="list-r">
|
||||
<Box name="组织成员" count={8}>
|
||||
<div className="teammembers">
|
||||
<Img src="https://dss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=1990625098,3468619056&fm=111&gp=0.jpg" alt="" className="m-img"/>
|
||||
<div>
|
||||
<ListName>陈Professer</ListName>
|
||||
<Align><i className="iconfont icon-shijian color-green mr3 font-13"></i><Span>加入时间:2020-04-28</Span></Align>
|
||||
<div className="list-l">
|
||||
<div>
|
||||
<div className="head">
|
||||
<div style={{width:"370px"}}>
|
||||
<Search placeholder="输入仓库名称进行搜索" onSearch={onSearch}/>
|
||||
</div>
|
||||
<p>
|
||||
<Sort menu={menu_new}>
|
||||
<a className="addBtn mr30">+ 新建项目</a>
|
||||
</Sort>
|
||||
<Dropdown overlay={menu}>
|
||||
<a className="color-blue">排序<i className="iconfont icon-sanjiaoxing-down ml3 font-14"></i></a>
|
||||
</Dropdown>
|
||||
</p>
|
||||
</div>
|
||||
<Spin spinning={isSpin}>
|
||||
<div className="team">
|
||||
{
|
||||
list && list.length>0 ? list.map((item,key)=>{
|
||||
return(
|
||||
<Item item={item} keu={key} OIdentifier={OIdentifier}/>
|
||||
)
|
||||
})
|
||||
:
|
||||
<NoData _html="暂无数据"/>
|
||||
}
|
||||
</div>
|
||||
</Spin>
|
||||
</div>
|
||||
</Box>
|
||||
<Box
|
||||
name="组织团队"
|
||||
count={3}
|
||||
bottom={<Button type={'primary'} to={``}>新建团队</Button>}
|
||||
>
|
||||
<div className="teammembers">
|
||||
<div>
|
||||
<ColorListName>陈Professer</ColorListName>
|
||||
<Align>
|
||||
<Span>2名成员</Span>
|
||||
<Span>1个仓库</Span>
|
||||
</Align>
|
||||
{
|
||||
totalCount > limit &&
|
||||
<div className="mb20 mt20" style={{textAlign:"center"}}>
|
||||
<Pagination simple current={page} total={totalCount} onChange={(page)=>setPage(page)}/>
|
||||
</div>
|
||||
</div>
|
||||
</Box>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<Right OIdentifier={OIdentifier}/>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
export default List;
|
|
@ -0,0 +1,25 @@
|
|||
import React from 'react';
|
||||
import ListCount from '../Component/ListCount';
|
||||
import { Link } from 'react-router-dom';
|
||||
function ListItem({item,key,OIdentifier}) {
|
||||
return(
|
||||
<div className="team_project" key={key}>
|
||||
<p className="t_p_title">
|
||||
<span className="flex1">
|
||||
<Link to={`/projects/${OIdentifier}/${item.identifier}`} className="name">{item.identifier}</Link>
|
||||
<i className="iconfont icon-banbenku font-20 color-green ml8" />
|
||||
<i className="iconfont icon-jingxiang font-18 color-green ml8" />
|
||||
<i className="iconfont icon-fork font-18 color-orange ml8" />
|
||||
</span>
|
||||
<ListCount fork={item.forked_count} parise={item.praises_count}/>
|
||||
</p>
|
||||
<div className="desc">
|
||||
{item.description}
|
||||
</div>
|
||||
<div className="infos">
|
||||
<span className="font-12 color-grey-8">更新于{item.time_ago}</span>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default ListItem;
|
|
@ -1,14 +1,13 @@
|
|||
import React,{ forwardRef , useCallback, useEffect, useState } from 'react';
|
||||
import React,{ forwardRef , useCallback , useState } from 'react';
|
||||
import './Index.scss';
|
||||
import { Form , Input , Radio , Checkbox , Button, InputNumber } from "antd";
|
||||
import UploadImage from './Component/UploadImage';
|
||||
import axios from 'axios';
|
||||
|
||||
export default Form.create()(
|
||||
forwardRef(({form , showNotification ,history})=>{
|
||||
forwardRef(({ form , showNotification , history })=>{
|
||||
const [ image , setImage ] = useState(undefined);
|
||||
|
||||
const { getFieldDecorator, validateFields , setFieldsValue } = form;
|
||||
const { getFieldDecorator, validateFields } = form;
|
||||
|
||||
const radioStyle = {
|
||||
display: 'block',
|
||||
|
@ -42,6 +41,7 @@ export default Form.create()(
|
|||
}).then(result=>{
|
||||
if(result && result.data){
|
||||
showNotification("组织创建成功!");
|
||||
history.push(`/organize/${result.data.name}`);
|
||||
}
|
||||
}).catch(error=>{})
|
||||
}
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
import React , { useEffect , useState } from 'react';
|
||||
import { Button } from 'antd';
|
||||
import styled from 'styled-components';
|
||||
import Box from './Box';
|
||||
import axios from 'axios';
|
||||
import { getImageUrl } from 'educoder';
|
||||
|
||||
const Span = styled.span`{
|
||||
color:#888;
|
||||
font-size:12px;
|
||||
margin-right:10px;
|
||||
}`
|
||||
const Align = styled.div`{
|
||||
display:flex;
|
||||
aligin:center;
|
||||
}`
|
||||
const ListName = styled.div`{
|
||||
font-size:14px;
|
||||
color:#333;
|
||||
margin-bottom:8px;
|
||||
height:18px;
|
||||
line-height:18px;
|
||||
}`;
|
||||
const ColorListName = styled.div`{
|
||||
color:#5091FF;
|
||||
font-size:14px;
|
||||
margin-bottom:8px;
|
||||
height:18px;
|
||||
line-height:18px;
|
||||
}`
|
||||
const Img = styled.img`{
|
||||
border-radius:50%;
|
||||
width:45px;
|
||||
height:45px;
|
||||
margin-right:12px;
|
||||
}`
|
||||
function RightBox({ OIdentifier }) {
|
||||
const [ memberData, setMemberData ] = useState(undefined);
|
||||
const [ groupData, setGroupData ] = useState(undefined);
|
||||
|
||||
useEffect(()=>{
|
||||
if(OIdentifier){
|
||||
getMember(OIdentifier);
|
||||
getGroup(OIdentifier);
|
||||
}
|
||||
},[OIdentifier])
|
||||
|
||||
function getMember(iden){
|
||||
const url = `/organizations/${iden}/organization_users.json`;
|
||||
axios.get(url).then(result=>{
|
||||
if(result && result.data){
|
||||
setMemberData(result.data);
|
||||
}
|
||||
}).catch(error=>{})
|
||||
}
|
||||
function getGroup(iden){
|
||||
const url = `/organizations/${iden}/teams.json`;
|
||||
axios.get(url).then(result=>{
|
||||
if(result && result.data){
|
||||
setGroupData(result.data);
|
||||
}
|
||||
}).catch(error=>{})
|
||||
}
|
||||
return(
|
||||
<div className="list-r">
|
||||
{
|
||||
memberData && memberData.organization_users && memberData.organization_users.length>0 ?
|
||||
<Box name="组织成员" count={memberData && memberData.total_count}>
|
||||
{
|
||||
memberData.organization_users.map((item,key)=>{
|
||||
return(
|
||||
<div className="teammembers" key={key}>
|
||||
<Img src={getImageUrl(`images/${item.user && item.user.image_url}`)} alt="" className="m-img"/>
|
||||
<div>
|
||||
<ListName>{item.user && item.user.name}</ListName>
|
||||
<Align><i className="iconfont icon-shijian color-green mr3 font-13"></i><Span>加入时间:{item.created_at}</Span></Align>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
</Box>
|
||||
:""
|
||||
}
|
||||
{
|
||||
groupData && groupData.teams && groupData.teams.length>0?
|
||||
<Box
|
||||
name="组织团队"
|
||||
count={groupData && groupData.total_count}
|
||||
bottom={<Button type={'primary'} to={``}>新建团队</Button>}
|
||||
>
|
||||
{
|
||||
groupData.teams.map((item,key)=>{
|
||||
return(
|
||||
<div className="teammembers" key={key}>
|
||||
<div>
|
||||
<ColorListName>{item.name}</ColorListName>
|
||||
<Align>
|
||||
<Span>{item.num_users}名成员</Span>
|
||||
<Span>{item.num_projects}个仓库</Span>
|
||||
</Align>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
</Box>
|
||||
:""
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default RightBox;
|
|
@ -1,9 +1,11 @@
|
|||
import React, { forwardRef , useCallback } from 'react';
|
||||
import { Form , Input , Cascader , Radio ,Checkbox , Divider , Button } from 'antd';
|
||||
import React, { forwardRef , useCallback , useEffect, useState } from 'react';
|
||||
import { Form , Input , Radio ,Checkbox , Divider , Button } from 'antd';
|
||||
import { WhiteBack , FlexAJ } from '../../Component/layout';
|
||||
import Title from '../../Component/Title';
|
||||
import styled from 'styled-components';
|
||||
import { locData } from "../../Utils/locData";
|
||||
import UploadImage from '../Component/UploadImage';
|
||||
import axios from 'axios';
|
||||
import { getImageUrl } from 'educoder';
|
||||
const TextArea = Input.TextArea;
|
||||
|
||||
const Div = styled.div`{
|
||||
|
@ -15,19 +17,58 @@ const radioStyle = {
|
|||
lineHeight: '30px',
|
||||
};
|
||||
export default Form.create()(
|
||||
forwardRef(({ form })=>{
|
||||
const { getFieldDecorator } = form;
|
||||
forwardRef(({ form , organizeDetail , showNotification , history })=>{
|
||||
const [ image , setImage ] = useState(undefined);
|
||||
const [ imageFlag , setImageFlag ] = useState(false);
|
||||
const [ password , setPassword ] = useState(undefined);
|
||||
const { getFieldDecorator , validateFields, setFieldsValue} = form;
|
||||
|
||||
useEffect(()=>{
|
||||
if(organizeDetail){
|
||||
setFieldsValue({
|
||||
...organizeDetail
|
||||
})
|
||||
setImage(organizeDetail.avatar_url);
|
||||
}
|
||||
},[organizeDetail])
|
||||
|
||||
const helper = useCallback(
|
||||
(label, name, rules, widget , isRequired ) => (
|
||||
(label, name, rules, widget , isRequired , flag ) => (
|
||||
<div>
|
||||
<span className={isRequired?"required":""}>{label}</span>
|
||||
<Form.Item>
|
||||
{getFieldDecorator(name, { rules, validateFirst: true })(widget)}
|
||||
{getFieldDecorator(name, { rules, validateFirst: true , valuePropName:flag ? "checked":"value" })(widget)}
|
||||
</Form.Item>
|
||||
</div>
|
||||
),
|
||||
[]
|
||||
);
|
||||
|
||||
// 更新
|
||||
function updateDetail(){
|
||||
validateFields((error,values)=>{
|
||||
if(!error){
|
||||
const url = `/organizations/${organizeDetail.id}.json`;
|
||||
axios.patch(url,{
|
||||
...values,image:imageFlag ? image : undefined
|
||||
}).then(result=>{
|
||||
if(result && result.data){
|
||||
showNotification("组织信息更新成功!");
|
||||
history.push(`/organize/${values.name}/setting`);
|
||||
}
|
||||
}).catch(error=>{})
|
||||
}
|
||||
})
|
||||
}
|
||||
function getImage(image){
|
||||
setImageFlag(true);
|
||||
setImage(image);
|
||||
}
|
||||
|
||||
// 删除组织
|
||||
function deleteOrganize(){
|
||||
|
||||
}
|
||||
return(
|
||||
<div>
|
||||
<WhiteBack>
|
||||
|
@ -42,46 +83,48 @@ export default Form.create()(
|
|||
)}
|
||||
{helper(
|
||||
"组织描述:",
|
||||
"desc",
|
||||
"description",
|
||||
[],
|
||||
<TextArea placeholder="请输入组织名称" />
|
||||
)}
|
||||
{helper(
|
||||
"官方网站:",
|
||||
"web",
|
||||
"website",
|
||||
[],
|
||||
<Input placeholder="请输入官方网站" />
|
||||
)}
|
||||
{helper(
|
||||
'所在地区:',
|
||||
"area",
|
||||
"location",
|
||||
[],
|
||||
<Cascader placeholder="请选择城市" options={locData}/>
|
||||
<Input placeholder="请输入城市"/>
|
||||
)}
|
||||
{helper(
|
||||
'可见性:',
|
||||
"opacity",
|
||||
"visibility",
|
||||
[],
|
||||
<Radio.Group>
|
||||
<Radio value="0" style={radioStyle}>公开</Radio>
|
||||
<Radio value="0" style={radioStyle}>受限<span>(仅对登录用户可见)</span></Radio>
|
||||
<Radio value="0" style={radioStyle}>私有<span>(仅对组织成员可见)</span></Radio>
|
||||
<Radio value="common" style={radioStyle}>公开</Radio>
|
||||
<Radio value="limited" style={radioStyle}>受限<span>(仅对登录用户可见)</span></Radio>
|
||||
<Radio value="privacy" style={radioStyle}>公开<span>(仅对组织成员可见)</span></Radio>
|
||||
</Radio.Group>
|
||||
)}
|
||||
{helper(
|
||||
'权限:',
|
||||
"operation",
|
||||
"repo_admin_change_team_access",
|
||||
[],
|
||||
<Checkbox value="0" style={radioStyle}>仓库管理员可以添加或移除团队的访问权限</Checkbox>
|
||||
<Checkbox style={radioStyle}>仓库管理员可以添加或移除团队的访问权限</Checkbox>,false,true
|
||||
)}
|
||||
<Divider/>
|
||||
{helper(
|
||||
'最大仓库数:',
|
||||
"number",
|
||||
"max_repo_creation",
|
||||
[],
|
||||
<Input value="-1" style={{width:"350px"}}/>
|
||||
)}
|
||||
<Button type={"primary"}>更新仓库设置</Button>
|
||||
<p>选择头像:</p>
|
||||
<UploadImage url={getImageUrl(`images/${image}`)} getImage={getImage}/>
|
||||
<Button type={"primary"} onClick={updateDetail}>更新仓库设置</Button>
|
||||
</Form>
|
||||
</Div>
|
||||
</WhiteBack>
|
||||
|
@ -93,9 +136,9 @@ export default Form.create()(
|
|||
<FlexAJ>
|
||||
<div>
|
||||
<span className="required">密码:</span>
|
||||
<Input type="password" style={{width:"350px"}} />
|
||||
<Input type="password" style={{width:"350px"}} value={password} onChange={(e)=>setPassword(e.target.value)}/>
|
||||
</div>
|
||||
<a className="warningDelete">删除组织</a>
|
||||
<a className="warningDelete" onClick={deleteOrganize}>删除组织</a>
|
||||
</FlexAJ>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -26,25 +26,25 @@ const Hooks = Loadable({
|
|||
});
|
||||
export default (( props )=>{
|
||||
const pathname = props.location.pathname;
|
||||
const organizeId = props.match.params.organizeId;
|
||||
const OIdentifier = props.match.params.OIdentifier;
|
||||
|
||||
function returnActive (pathname){
|
||||
let a = 0;
|
||||
if(pathname === `/organize/${organizeId}/setting/member`){
|
||||
if(pathname === `/organize/${OIdentifier}/setting/member`){
|
||||
a = 1;
|
||||
}else if(pathname === `/organize/${organizeId}/setting/group`){
|
||||
}else if(pathname === `/organize/${OIdentifier}/setting/group`){
|
||||
a = 2;
|
||||
}else if(pathname === `/organize/${organizeId}/setting/hooks`){
|
||||
}else if(pathname === `/organize/${OIdentifier}/setting/hooks`){
|
||||
a = 3;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
const active = returnActive(pathname);
|
||||
const array = {list:[
|
||||
{name:'基本设置',icon:"icon-base",href:`/organize/${organizeId}/setting`},
|
||||
{name:'组织成员管理',icon:"icon-zuzhichengyuan",href:`/organize/${organizeId}/setting/member`},
|
||||
{name:'组织团队管理',icon:"icon-zuzhixiangmu",href:`/organize/${organizeId}/setting/group`},
|
||||
{name:'管理web钩子',icon:"icon-zhongqingdianxinicon10",href:`/organize/${organizeId}/setting/hooks`}
|
||||
{name:'基本设置',icon:"icon-base",href:`/organize/${OIdentifier}/setting`},
|
||||
{name:'组织成员管理',icon:"icon-zuzhichengyuan",href:`/organize/${OIdentifier}/setting/member`},
|
||||
{name:'组织团队管理',icon:"icon-zuzhixiangmu",href:`/organize/${OIdentifier}/setting/group`},
|
||||
{name:'管理web钩子',icon:"icon-zhongqingdianxinicon10",href:`/organize/${OIdentifier}/setting/hooks`}
|
||||
],
|
||||
active
|
||||
}
|
||||
|
@ -57,25 +57,25 @@ export default (( props )=>{
|
|||
<Gap>
|
||||
<Switch>
|
||||
<Route
|
||||
path="/organize/:organizeId/setting/hooks"
|
||||
path="/organize/:OIdentifier/setting/hooks"
|
||||
render={() => (
|
||||
<Hooks {...props} />
|
||||
)}
|
||||
></Route>
|
||||
<Route
|
||||
path="/organize/:organizeId/setting/group"
|
||||
path="/organize/:OIdentifier/setting/group"
|
||||
render={() => (
|
||||
<Group {...props} />
|
||||
)}
|
||||
></Route>
|
||||
<Route
|
||||
path="/organize/:organizeId/setting/member"
|
||||
path="/organize/:OIdentifier/setting/member"
|
||||
render={() => (
|
||||
<Member {...props} />
|
||||
)}
|
||||
></Route>
|
||||
<Route
|
||||
path="/organize/:organizeId/setting"
|
||||
path="/organize/:OIdentifier/setting"
|
||||
render={() => (
|
||||
<Common {...props} />
|
||||
)}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import React , { useEffect , useState } from 'react';
|
||||
import { Route, Switch } from "react-router-dom";
|
||||
import { Route, Switch , Link } from "react-router-dom";
|
||||
import Loadable from "react-loadable";
|
||||
import Loading from "../../../Loading";
|
||||
|
||||
import {AlignCenter} from '../../Component/layout';
|
||||
import Cards from '../../Component/Cards';
|
||||
|
||||
import axios from 'axios';
|
||||
import '../Index.scss';
|
||||
|
||||
const DetailIndex = Loadable({
|
||||
|
@ -15,39 +15,59 @@ const Setting = Loadable({
|
|||
loader: () => import("../Setting/TeamSettingIndex"),
|
||||
loading: Loading,
|
||||
});
|
||||
const GroupSetting = Loadable({
|
||||
loader: () => import("../Group/GroupDetailSetting"),
|
||||
loading: Loading,
|
||||
});
|
||||
export default ((props)=>{
|
||||
function Detail(props){
|
||||
const OIdentifier = props.match.params.OIdentifier;
|
||||
const pathname = props.location.pathname;
|
||||
|
||||
const [ detail , setDetail ] = useState(undefined);
|
||||
const [ flag , setFlag ] = useState(true);
|
||||
|
||||
// 设置页面:顶部不需要设置按钮了
|
||||
useEffect(()=>{
|
||||
if(pathname){
|
||||
if(pathname.indexOf("/setting") && pathname.indexOf("/organize")){
|
||||
setFlag(false);
|
||||
}
|
||||
}
|
||||
},[pathname])
|
||||
|
||||
useEffect(()=>{
|
||||
if(OIdentifier){
|
||||
getDetail(OIdentifier);
|
||||
}
|
||||
},[OIdentifier]);
|
||||
|
||||
function getDetail(id) {
|
||||
const url = `/organizations/${id}.json`;
|
||||
axios.get(url).then(result=>{
|
||||
if(result && result.data){
|
||||
setDetail(result.data);
|
||||
}
|
||||
}).catch(error=>{})
|
||||
}
|
||||
return(
|
||||
<div className="teamDetail">
|
||||
<Cards
|
||||
title="组织名称"
|
||||
desc="组织名称组织名称组织名称组织名称组织名称"
|
||||
rightBtn={<a className="color-blue">设置<i className="iconfont icon-shezhi2 ml3"></i></a>}
|
||||
img={`https://dss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=4193840146,2109186388&fm=26&gp=0.jpg`}
|
||||
title={detail && detail.name}
|
||||
desc={detail && detail.description}
|
||||
img={detail && 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>}
|
||||
/>
|
||||
<Switch {...props}>
|
||||
<Route
|
||||
path="/organize/:organizeId/member/:memberId/setting"
|
||||
render={() => {
|
||||
return <GroupSetting {...props} />
|
||||
path="/organize/:OIdentifier/setting"
|
||||
render={(p) => {
|
||||
return <Setting {...props} {...p} organizeDetail={detail} />
|
||||
}}
|
||||
></Route>
|
||||
<Route
|
||||
path="/organize/:organizeId/setting"
|
||||
render={() => {
|
||||
return <Setting {...props} />
|
||||
}}
|
||||
></Route>
|
||||
<Route
|
||||
path="/organize/:organizeId"
|
||||
render={() => {
|
||||
return <DetailIndex {...props} />
|
||||
path="/organize/:OIdentifier"
|
||||
render={(p) => {
|
||||
return <DetailIndex {...props} {...p}/>
|
||||
}}
|
||||
></Route>
|
||||
</Switch>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
export default Detail;
|
|
@ -22,6 +22,10 @@ const GroupDetails = Loadable({
|
|||
loader: () => import("../Group/GroupDetails"),
|
||||
loading: Loading,
|
||||
});
|
||||
const GroupSetting = Loadable({
|
||||
loader: () => import("../Group/GroupDetailSetting"),
|
||||
loading: Loading,
|
||||
});
|
||||
|
||||
export default ((props)=>{
|
||||
return(
|
||||
|
@ -37,26 +41,37 @@ export default ((props)=>{
|
|||
img={`https://dss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=4193840146,2109186388&fm=26&gp=0.jpg`}
|
||||
/>
|
||||
<Switch {...props}>
|
||||
{/* 组织团队-设置 */}
|
||||
<Route
|
||||
path="/organize/:organizeId/member/:memberId"
|
||||
path="/organize/:OIdentifier/group/:groupId/setting"
|
||||
render={(props) => {
|
||||
return <GroupSetting {...props} />
|
||||
}}
|
||||
></Route>
|
||||
{/* 组织团队-成员 */}
|
||||
<Route
|
||||
path="/organize/:OIdentifier/group/:groupId/member"
|
||||
render={(props) => {
|
||||
return <GroupDetails {...props} />
|
||||
}}
|
||||
></Route>
|
||||
{/* 组织成员 */}
|
||||
<Route
|
||||
path="/organize/:organizeId/member"
|
||||
path="/organize/:OIdentifier/member"
|
||||
render={(props) => {
|
||||
return <Member {...props} />
|
||||
}}
|
||||
></Route>
|
||||
{/* 组织-新建团队 */}
|
||||
<Route
|
||||
path="/organize/:organizeId/group/new"
|
||||
path="/organize/:OIdentifier/group/new"
|
||||
render={(props) => {
|
||||
return <GroupNew {...props} />
|
||||
}}
|
||||
></Route>
|
||||
{/* 组织团队 */}
|
||||
<Route
|
||||
path="/organize/:organizeId/group"
|
||||
path="/organize/:OIdentifier/group"
|
||||
render={(props) => {
|
||||
return <Group {...props} />
|
||||
}}
|
||||
|
|
Loading…
Reference in New Issue