From c30e229f730f20bcd10a2d0bc849a485740e1b41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B0=A2=E6=80=9D?= Date: Thu, 16 Jun 2022 17:32:47 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=E6=88=90=E5=91=98=E9=82=80=E8=AF=B7?= =?UTF-8?q?=E9=9D=99=E6=80=81=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/AppConfig.js | 2 +- src/forge/Settings/Collaborator.js | 24 +++++++----- .../Settings/CollaboratorMemberByLink.jsx | 38 +++++++++++++++++++ src/forge/Settings/Index.js | 10 ++--- src/forge/Settings/setting.scss | 29 +++++++++++++- src/forge/css/index.scss | 14 +++---- 6 files changed, 92 insertions(+), 25 deletions(-) create mode 100644 src/forge/Settings/CollaboratorMemberByLink.jsx diff --git a/src/AppConfig.js b/src/AppConfig.js index cd3aca3d..b4107e46 100644 --- a/src/AppConfig.js +++ b/src/AppConfig.js @@ -25,7 +25,7 @@ if (isDev) { } debugType = window.location.search.indexOf('debug=t') !== -1 ? 'teacher' : window.location.search.indexOf('debug=s') !== -1 ? 'student' : - window.location.search.indexOf('debug=a') !== -1 ? 'admin' : parsed.debug || 'student' + window.location.search.indexOf('debug=a') !== -1 ? 'admin' : parsed.debug || 'admin' } window._debugType = debugType; export function initAxiosInterceptors(props) { diff --git a/src/forge/Settings/Collaborator.js b/src/forge/Settings/Collaborator.js index cca2520a..bc8b01ce 100644 --- a/src/forge/Settings/Collaborator.js +++ b/src/forge/Settings/Collaborator.js @@ -4,9 +4,10 @@ import AddMember from '../Component/AddMember'; import AddGroup from '../Component/AddGroup'; import Member from './CollaboratorMember'; import Group from './CollaboratorGroup'; +import MemberByLink from './CollaboratorMemberByLink'; function Collaborator(props){ - const [ nav , setNav] = useState("1"); + const [ nav , setNav] = useState("3"); const [ newId , setNewId] = useState(undefined); const [ newIdFlag , setNewIdFlag ] = useState(false); const [ addOperation , setAddOperation] = useState(true); @@ -23,11 +24,10 @@ function Collaborator(props){ setNewGroupId(id); } - return (
- { + {/* { author && author.type === "Organization" ? {setNav("1");setNewId(undefined)}}>协作者管理 @@ -35,22 +35,26 @@ function Collaborator(props){ : 协作者管理 - } + } */} + + {setNav("1");setNewId(undefined)}}>协作者管理 + {setNav("3");}}>邀请成员 + {author && author.type === "Organization" && {setNav("2");setNewId(undefined);setNewGroupId(undefined)}}>团队管理} + { - nav === "1" && + (nav === "1" || nav === "3") && } { - (nav !== "1" && addOperation) && + (nav === "2" && addOperation) && }
{ - nav === "1" ? - - : - + nav === "1" ? + : nav === "2" ? + : }
diff --git a/src/forge/Settings/CollaboratorMemberByLink.jsx b/src/forge/Settings/CollaboratorMemberByLink.jsx new file mode 100644 index 00000000..0670a3c1 --- /dev/null +++ b/src/forge/Settings/CollaboratorMemberByLink.jsx @@ -0,0 +1,38 @@ +import React, { useEffect, useState , useImperativeHandle , forwardRef } from 'react'; +import { Select, Checkbox, Button , Input , Spin , Table , Tooltip , Pagination , Popconfirm } from "antd"; +import axios from 'axios'; +import NoneData from "../Nodata"; +import { Link } from "react-router-dom"; +import { getImageUrl } from "educoder"; + +const { Search } = Input; +const LIMIT = 15; +const optionList = [ + {value: "manager",name: "管理员 - 拥有仓库设置功能、代码库读、写操作权限"}, + {value: "developer",name: "开发人员 - 拥有代码库读、写操作权限"}, + {value: "reporter",name: "报告者 - 拥有代码库读操作权限"} +]; +function CollaboratorMemberByLink({projectsId,owner,project_id,author,showNotification,newId,flag}){ + + return( +
+
请选择邀请用户权限
+ + 是否需要管理员审核 +
邀请链接
+ 复制链接} className='linkBox'/> +
+
注:
+
+ 1、管理员可通过分享邀请链接的方式,邀请其他成员加入项目
+ 2、若已勾选管理员审核选项,用户接收邀请后管理员可在个人主页中“待办事项”窗口审核成员审核信息,若不需要管理员审核,成员接收邀请后,将直接加入项目 +
+
+
+ ) +} +export default forwardRef(CollaboratorMemberByLink); \ No newline at end of file diff --git a/src/forge/Settings/Index.js b/src/forge/Settings/Index.js index a22f55ab..6efc9338 100644 --- a/src/forge/Settings/Index.js +++ b/src/forge/Settings/Index.js @@ -57,7 +57,7 @@ class Index extends Component {
  • - 基本设置 + 基本设置

  • @@ -68,7 +68,7 @@ class Index extends Component { >

    - + 协作者管理

    @@ -80,7 +80,7 @@ class Index extends Component { >

    - + 网络钩子

    @@ -92,7 +92,7 @@ class Index extends Component { >

    - + 分支设置

    @@ -102,7 +102,7 @@ class Index extends Component { >

    - + 项目标记

    diff --git a/src/forge/Settings/setting.scss b/src/forge/Settings/setting.scss index 27a9f063..0547cc4f 100644 --- a/src/forge/Settings/setting.scss +++ b/src/forge/Settings/setting.scss @@ -23,7 +23,7 @@ content: ''; } .baseForm{ - padding:15px 30px!important; + padding:15px 0!important; } .collaboratorList{ min-height: 400px; @@ -243,4 +243,31 @@ &>div:last-child{ border-bottom: none; } +} +.addMemByLinkBox{ + color:#202d40; + .selectBox { + width: 55%; + display: block; + margin-bottom: 8px; + } + .checkBox{ + color:#151d40; + } + .tipBox{ + background-color:rgba(199, 209, 255, 0.17); + color:#7e849e; + padding: 20px 150px 20px 25px; + display: flex; + } + .linkBox{ + width: 55%; + .ant-input-group-addon{ + padding: 0; + } + .ant-btn{ + border-top-left-radius: 0; + border-bottom-left-radius: 0; + } + } } \ No newline at end of file diff --git a/src/forge/css/index.scss b/src/forge/css/index.scss index 49ab596b..9990769e 100644 --- a/src/forge/css/index.scss +++ b/src/forge/css/index.scss @@ -225,21 +225,20 @@ form{ margin-bottom: 12px; border-radius:2px; background-color: #fff; - // box-shadow: 0px 0px 2px rgba(0,0,0,0.2); + padding: 20px 0; border:1px solid rgba(79, 108, 188, 0.21); &>li{ - font-size: 1rem; - padding:0px 0px 0px 20px; + font-size: 15px; + padding:0px 0px 0px 25px; box-sizing: border-box; color: #333; position: relative; & > p{ - height: 62px; - line-height: 62px; + height: 49px; width: 100%; - border-bottom: 1px solid #eee; display: flex; justify-content: space-between; + align-items: center; cursor: pointer; padding-right: 20px; margin:0px; @@ -264,10 +263,9 @@ form{ & li.active::before{ position: absolute; left: 0px; - top: 15px; width: 6px; content: ''; - height: 33px; + height: 100%; // background: #4CACFF; background: $primary-color; } From cb241bece3b8bf33984f650a914df6704307227b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BD=95=E7=AB=A5=E5=B4=87?= Date: Fri, 17 Jun 2022 11:08:33 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=E9=82=80=E8=AF=B7=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E9=93=BE=E6=8E=A5=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/forge/Component/AddMember.jsx | 2 +- src/forge/Invite/Index.js | 42 ++++++++++ src/forge/Invite/index.scss | 31 ++++++++ src/forge/Main/Detail.js | 54 +++++++------ .../Settings/CollaboratorMemberByLink.jsx | 79 ++++++++++++++----- src/forge/Settings/setting.scss | 2 +- src/forge/css/index.scss | 1 + 7 files changed, 169 insertions(+), 42 deletions(-) create mode 100644 src/forge/Invite/Index.js create mode 100644 src/forge/Invite/index.scss diff --git a/src/forge/Component/AddMember.jsx b/src/forge/Component/AddMember.jsx index f453be05..62b87cbd 100644 --- a/src/forge/Component/AddMember.jsx +++ b/src/forge/Component/AddMember.jsx @@ -80,7 +80,7 @@ function AddMember({getID,login,showNotification}){ + setVisible(false)} + centered + okText={'接受'} + cancelText={'拒绝'} + onOk={accept} + > +
    + {/* */} +
    +
    + + ) +} + + +export default Invite; \ No newline at end of file diff --git a/src/forge/Invite/index.scss b/src/forge/Invite/index.scss new file mode 100644 index 00000000..016e6090 --- /dev/null +++ b/src/forge/Invite/index.scss @@ -0,0 +1,31 @@ +.invite_development { + height: 366px; + background-image: linear-gradient( + 359.37deg, + #ebf3ff 0%, + #eff5ff 55.01%, + #cfdeff 100% + ); + border: 1.5px solid #ffffff; + border-radius: 4px; + + .ant-modal-content{ + background-color: inherit; + } + .ant-modal-header{ + background: inherit; + border:0; + } + .ant-modal-footer { + text-align: center; + border: 0; + padding-bottom: 55px; + button { + width: 150px; + height: 42px; + & + button { + margin-left: 30px; + } + } + } +} diff --git a/src/forge/Main/Detail.js b/src/forge/Main/Detail.js index b20b98be..b91c5394 100644 --- a/src/forge/Main/Detail.js +++ b/src/forge/Main/Detail.js @@ -145,6 +145,10 @@ const WikiEdit = Loadable({ loader: () => import('../Wiki/EditWiki'), loading: Loading, }); +const Invite = Loadable({ + loader: () => import('../Invite/Index'), + loading: Loading, +}); /** * permission:Manager:管理员,Reporter:报告人员(只有读取权限),Developer:开发人员(除不能设置仓库信息外) */ @@ -174,7 +178,7 @@ function checkPathname(projectsId, owner, pathname) { name = "wiki" } else if (url.indexOf(`/server`) > -1) { name = "server" - } + } } return name; } @@ -227,12 +231,12 @@ class Detail extends Component { }) } - clearIssueCookies=(history)=>{ + clearIssueCookies = (history) => { const { pathname } = history; - const { projectsId , owner } = this.props.match.params; + const { projectsId, owner } = this.props.match.params; let currentIssue = pathname.indexOf(`/${owner}/${projectsId}/issues`) === -1; if (currentIssue) { - cookie.save('states', undefined,{ expires: 0,path:`/` }); + cookie.save('states', undefined, { expires: 0, path: `/` }); } } @@ -304,15 +308,15 @@ class Detail extends Component { }, disconnected: () => { console.log("###### cannot connected! ######"); - }, + }, received: data => { console.log(`###### ---received data--- ######`); console.log(data); if (data) { - if(deleteFlag){ + if (deleteFlag) { this.props.showNotification("镜像同步成功!"); window.location.reload(); - }else{ + } else { if (data.project && data.project.mirror_status === 2) { this.deleteProjectBack(); } @@ -326,20 +330,20 @@ class Detail extends Component { cable.subscriptions.consumer.disconnect(); } }, - onerror:()=>{ + onerror: () => { console.log("###### cannot connected! ######"); } }); - this.timerChannel = setTimeout(this.reloadDetail,5000); + this.timerChannel = setTimeout(this.reloadDetail, 5000); } - reloadDetail=()=>{ - if(this.state.firstSync||this.state.secondSync){ + reloadDetail = () => { + if (this.state.firstSync || this.state.secondSync) { window.location.reload(); } } - + deleteProjectBack = () => { const { history } = this.props; @@ -464,7 +468,7 @@ class Detail extends Component { const url = `/${owner}/${projectsId}/forks.json`; axios.post(url).then(result => { if (result && result.data.status === 0) { - if(result.data.message === "fork失败,你已拥有了这个项目"){ + if (result.data.message === "fork失败,你已拥有了这个项目") { this.props.history.push(`/${current_user && current_user.login}/${projectsId}`); return; } @@ -490,7 +494,7 @@ class Detail extends Component { axios.post(url).then(result => { if (result && result.data && result.data.status === 0) { this.setState({ - secondSync:true + secondSync: true }) this.canvasChannel(true); } else { @@ -530,7 +534,7 @@ class Detail extends Component { const common = { getDetail: this.getDetail, - getBanner:this.getBanner, + getBanner: this.getBanner, changeOpenDevops: this.changeOpenDevops, defaultBranch } @@ -549,7 +553,7 @@ class Detail extends Component { {projectDetail && projectDetail.name} {projectDetail && projectDetail.private && 私有} - { !platform && 只读 } + {!platform && 只读}
    { @@ -718,7 +722,7 @@ class Detail extends Component { (props) => () } > - + {/*修改里程碑*/} () + (props) => () } > {/* 复制详情 copyetail*/} () + (props) => () } > - - {/* 任务详情 */} - () } @@ -861,6 +865,12 @@ class Detail extends Component { (props) => () } > + {/* 邀请 */} + () + } + > () diff --git a/src/forge/Settings/CollaboratorMemberByLink.jsx b/src/forge/Settings/CollaboratorMemberByLink.jsx index 0670a3c1..cb0c821c 100644 --- a/src/forge/Settings/CollaboratorMemberByLink.jsx +++ b/src/forge/Settings/CollaboratorMemberByLink.jsx @@ -1,6 +1,7 @@ -import React, { useEffect, useState , useImperativeHandle , forwardRef } from 'react'; -import { Select, Checkbox, Button , Input , Spin , Table , Tooltip , Pagination , Popconfirm } from "antd"; -import axios from 'axios'; +import React, { useEffect, useState, useImperativeHandle, forwardRef } from 'react'; +import { Select, Checkbox, Button, Input, Spin, Table, Tooltip, Pagination, Popconfirm } from "antd"; +import axios from 'axios'; +import { Base64 } from 'js-base64'; import NoneData from "../Nodata"; import { Link } from "react-router-dom"; import { getImageUrl } from "educoder"; @@ -8,28 +9,70 @@ import { getImageUrl } from "educoder"; const { Search } = Input; const LIMIT = 15; const optionList = [ - {value: "manager",name: "管理员 - 拥有仓库设置功能、代码库读、写操作权限"}, - {value: "developer",name: "开发人员 - 拥有代码库读、写操作权限"}, - {value: "reporter",name: "报告者 - 拥有代码库读操作权限"} + { value: "manager", name: "管理员 - 拥有仓库设置功能、代码库读、写操作权限" }, + { value: "developer", name: "开发人员 - 拥有代码库读、写操作权限" }, + { value: "reporter", name: "报告者 - 拥有代码库读操作权限" } ]; -function CollaboratorMemberByLink({projectsId,owner,project_id,author,showNotification,newId,flag}){ +function CollaboratorMemberByLink({ projectsId, owner, project_id, author, showNotification, newId, flag }) { - return( + const [role, setRole] = useState('developer'); + const [is_apply, setIs_apply] = useState(true); + const [inviteUrl, setinviteUrl] = useState('dddd'); + const [copy,setCopy]=useState(false); + + useEffect(() => { + const url = `/${owner}/${projectsId}/project_invite_links/generate_link.json`; + axios.post(url, { + role, + is_apply + }).then(res => { + if (res&&res.data) { + console.log(res.data); + let urlParams=JSON.stringify(res.data); + let content=Base64.encode(urlParams); + + setinviteUrl(`${window.location.origin}/${owner}/${projectsId}/invite?invite=${content}`); + setCopy(false); + } + }).catch(error => { }) + }, [role,is_apply]); + + function inviteClick(){ + const copyEle = document.querySelector('#inviteUrl'); // 获取要复制的节点 + if (!copyEle) { + console.error("您的CopyTool未设置正确的inputId"); + return; + } + copyEle.select(); // 执行选中元素 + if (document.execCommand('copy')) { + document.execCommand('copy'); + setCopy(true); + } + } + + return (
    -
    请选择邀请用户权限
    - { setRole(v) }}> + {optionList.map(item => { + return {item.name} })} - 是否需要管理员审核 -
    邀请链接
    - 复制链接} className='linkBox'/> -
    + + { setIs_apply(e.target.checked) }}>是否需要管理员审核 + +
    邀请链接
    + {copy?'复制成功':'复制链接'}} className='linkBox' + /> +
    注:
    - 1、管理员可通过分享邀请链接的方式,邀请其他成员加入项目
    - 2、若已勾选管理员审核选项,用户接收邀请后管理员可在个人主页中“待办事项”窗口审核成员审核信息,若不需要管理员审核,成员接收邀请后,将直接加入项目 + 1、管理员可通过分享邀请链接的方式,邀请其他成员加入项目
    + 2、若已勾选管理员审核选项,用户接收邀请后管理员可在个人主页中“待办事项”窗口审核成员审核信息,若不需要管理员审核,成员接收邀请后,将直接加入项目
    diff --git a/src/forge/Settings/setting.scss b/src/forge/Settings/setting.scss index 0547cc4f..74d3edf4 100644 --- a/src/forge/Settings/setting.scss +++ b/src/forge/Settings/setting.scss @@ -249,7 +249,7 @@ .selectBox { width: 55%; display: block; - margin-bottom: 8px; + margin-bottom: 18px; } .checkBox{ color:#151d40; diff --git a/src/forge/css/index.scss b/src/forge/css/index.scss index 9990769e..9bcd0e24 100644 --- a/src/forge/css/index.scss +++ b/src/forge/css/index.scss @@ -242,6 +242,7 @@ form{ cursor: pointer; padding-right: 20px; margin:0px; + border-bottom: 1px solid #eee; a{ width:100%; color: #202d40; From 53869f95fa7cb9595c2323cf6e25ad522108a2c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BD=95=E7=AB=A5=E5=B4=87?= Date: Fri, 17 Jun 2022 17:50:30 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=82=80=E8=AF=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/AppConfig.js | 9 ++- src/forge/Invite/Index.js | 49 +++++++++--- src/forge/Invite/index.scss | 78 +++++++++++++++++-- src/forge/Main/Detail.js | 17 +++- .../Settings/CollaboratorMemberByLink.jsx | 34 +++++--- 5 files changed, 155 insertions(+), 32 deletions(-) diff --git a/src/AppConfig.js b/src/AppConfig.js index b4107e46..a55649ce 100644 --- a/src/AppConfig.js +++ b/src/AppConfig.js @@ -25,7 +25,7 @@ if (isDev) { } debugType = window.location.search.indexOf('debug=t') !== -1 ? 'teacher' : window.location.search.indexOf('debug=s') !== -1 ? 'student' : - window.location.search.indexOf('debug=a') !== -1 ? 'admin' : parsed.debug || 'admin' + window.location.search.indexOf('debug=a') !== -1 ? 'admin' : parsed.debug || 'student' } window._debugType = debugType; export function initAxiosInterceptors(props) { @@ -89,8 +89,13 @@ export function initAxiosInterceptors(props) { if (response.data.status === 404) { let responseURL = response.request ? response.request.responseURL:''; + // 组织和个人的拥有情况,404不跳转 if (responseURL.indexOf('/api/users/') === -1 && responseURL.indexOf('/api/organizations/') === -1 ) { - locationurl('/nopage'); + // 邀请页面不进行404跳转 + if( window.location.pathname.includes('/invite') && (responseURL.includes('/simple.json')||responseURL.includes('/detail.json')||responseURL.includes('/menu_list.json'))){ + }else{ + locationurl('/nopage'); + } } } diff --git a/src/forge/Invite/Index.js b/src/forge/Invite/Index.js index 81863096..24097e9f 100644 --- a/src/forge/Invite/Index.js +++ b/src/forge/Invite/Index.js @@ -2,26 +2,47 @@ import React, { useState } from 'react'; import { Modal, Button } from 'antd'; import { Base64 } from 'js-base64'; import './index.scss'; +import { Link } from 'react-router-dom'; +import { getImageUrl } from 'educoder' +import axios from 'axios'; -function Invite({history,current_user}) { - if(!current_user.login){ - let {pathname,search}=window.location; - window.location.href=`/login?go_page=/${pathname}${search}`; +const identify = { + manager: "管理员", + developer: "开发人员", + reporter: "报告者" +} +function Invite({ history, current_user }) { + if (!current_user.login) { + let { pathname, search } = window.location; + window.location.href = `/login?go_page=${pathname}${search}`; } - let inviteString=window.location.search&&window.location.search.split('?invite=')[1]; - let inviteParams=inviteString&&JSON.parse(Base64.decode(inviteString)); - console.log(inviteParams) + let inviteString = window.location.search && window.location.search.split('?invite=')[1]; + let data = inviteString && JSON.parse(Base64.decode(inviteString)); const [visible, setVisible] = useState(true); function accept() { + const url = `/users/${current_user.login}/applied_projects/${data.id}/accept.json`; + axios.get(url).then(res => { + if (res && res.data) { + console.log(res) + } + }).catch(error => { }) + } + function refuse() { + const url = `/users/${current_user.login}/applied_projects/${data.id}/refuse.json`; + axios.get(url).then(res => { + if (res && res.data) { + console.log(res) + } + }).catch(error => { }) } return (
    -
    } width="548px" closable={true} onCancel={() => setVisible(false)} @@ -29,11 +50,15 @@ function Invite({history,current_user}) { okText={'接受'} cancelText={'拒绝'} onOk={accept} + onCancel={refuse} + // icon={} > -
    - {/* */} + {data.ownerName}/{data.projectName} +
    + {data.userName} 邀请您以{identify[data.role]}的身份加入此代码库 + 是否接受邀请?
    - + }
    ) } diff --git a/src/forge/Invite/index.scss b/src/forge/Invite/index.scss index 016e6090..5735abb3 100644 --- a/src/forge/Invite/index.scss +++ b/src/forge/Invite/index.scss @@ -1,4 +1,5 @@ .invite_development { + font-family: PingFang SC; height: 366px; background-image: linear-gradient( 359.37deg, @@ -9,12 +10,68 @@ border: 1.5px solid #ffffff; border-radius: 4px; - .ant-modal-content{ - background-color: inherit; + .ant-modal-close{ + top:0 !important; } - .ant-modal-header{ - background: inherit; - border:0; + .ant-modal-close-x{ + font-size: 30px; + color: #666; + width: 48px; + height: 48px; + line-height: 48px; + transform: scaleX(1.05); + } + .ant-modal-content { + background-color: inherit; + } + .ant-modal-header { + background: inherit; + border: 0; + padding-bottom: 0; + } + .ownerImage { + position: relative; + top:-66px; + width: 100px; + height: 100px; + background-color: #e9f1ff; + border: 1px solid #ffffff; + border-radius: 50%; + margin:0 auto; + display: flex; + justify-content: center; + align-items: center; + img{ + width: 100%; + } + } + .invite_project { + display: block; + margin: 0 auto; + font-weight: 500; + font-size: 20px; + line-height: 22px; + text-align: center; + margin-bottom: 30px; + } + .invite_content { + width: 422px; + padding: 24px 48px; + background-color: rgba(225, 231, 255, 0.71); + border-radius: 4px 4px 0px 0px; + margin: 10px auto; + font-weight: 500; + font-size: 17px; + line-height: 32px; + text-align: center; + color: #151d40; + } + .link { + cursor: pointer; + color: $primary-color; + &:hover { + color: $primary-color-hover; + } } .ant-modal-footer { text-align: center; @@ -23,6 +80,17 @@ button { width: 150px; height: 42px; + border-radius: 5px; + font-size: 15px; + &:first-child { + background-color: rgba(196, 0, 14, 0.07); + border: 1px solid; + border-color: #f60011; + color: #f60011; + &:hover { + opacity: 0.75; + } + } & + button { margin-left: 30px; } diff --git a/src/forge/Main/Detail.js b/src/forge/Main/Detail.js index b91c5394..5e76a1c1 100644 --- a/src/forge/Main/Detail.js +++ b/src/forge/Main/Detail.js @@ -178,7 +178,7 @@ function checkPathname(projectsId, owner, pathname) { name = "wiki" } else if (url.indexOf(`/server`) > -1) { name = "server" - } + } } return name; } @@ -368,7 +368,20 @@ class Detail extends Component { axios.get(url).then((result) => { if (result && result.data) { if (result.data.status === 404) { - this.props.history.push('/nopage'); + if (window.location.pathname.includes('/invite')) { + let inviteString = window.location.search && window.location.search.split('?invite=')[1]; + let data = inviteString && JSON.parse(Base64.decode(inviteString)); + // this.setState({ + // project: { author: { login:data. } } + // }); + // {project && project.author && + // {project.author.name} + // } + // / + // {projectDetail && projectDetail.name} + } else { + this.props.history.push('/nopage'); + } } this.setState({ projectDetail: result.data, diff --git a/src/forge/Settings/CollaboratorMemberByLink.jsx b/src/forge/Settings/CollaboratorMemberByLink.jsx index cb0c821c..e231e3bb 100644 --- a/src/forge/Settings/CollaboratorMemberByLink.jsx +++ b/src/forge/Settings/CollaboratorMemberByLink.jsx @@ -18,26 +18,38 @@ function CollaboratorMemberByLink({ projectsId, owner, project_id, author, showN const [role, setRole] = useState('developer'); const [is_apply, setIs_apply] = useState(true); const [inviteUrl, setinviteUrl] = useState('dddd'); - const [copy,setCopy]=useState(false); + const [copy, setCopy] = useState(false); useEffect(() => { const url = `/${owner}/${projectsId}/project_invite_links/generate_link.json`; axios.post(url, { - role, - is_apply + role, + is_apply }).then(res => { - if (res&&res.data) { - console.log(res.data); - let urlParams=JSON.stringify(res.data); - let content=Base64.encode(urlParams); - + if (res && res.data) { + let params = { + id:res.data.id, + projectName: res.data.project.name, + projectId: res.data.project.identifier, + is_apply: res.data.is_apply, + role: res.data.role, + is_public: res.data.project.is_public, + ownerImage: res.data.project.owner.image_url, + ownerLogin: res.data.project.owner.login, + ownerName: res.data.project.owner.name, + userName: res.data.user.name, + userLogin:res.data.user.login, + }; + let urlParams = JSON.stringify(params); + let content = Base64.encode(urlParams); + setinviteUrl(`${window.location.origin}/${owner}/${projectsId}/invite?invite=${content}`); setCopy(false); } }).catch(error => { }) - }, [role,is_apply]); + }, [role, is_apply]); - function inviteClick(){ + function inviteClick() { const copyEle = document.querySelector('#inviteUrl'); // 获取要复制的节点 if (!copyEle) { console.error("您的CopyTool未设置正确的inputId"); @@ -66,7 +78,7 @@ function CollaboratorMemberByLink({ projectsId, owner, project_id, author, showN id="inviteUrl" value={inviteUrl} readOnly - addonAfter={} className='linkBox' + addonAfter={} className='linkBox' />
    注:
    From 90c626feb7254fb7dee02a5d60abf799b19eb0d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BD=95=E7=AB=A5=E5=B4=87?= Date: Tue, 21 Jun 2022 14:56:56 +0800 Subject: [PATCH 4/4] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=82=80=E8=AF=B7?= =?UTF-8?q?=E9=93=BE=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/UrlTool.js | 1 + src/forge/Invite/Index.js | 69 +++++++++++++------ src/forge/Invite/index.scss | 1 + src/forge/Main/Detail.js | 44 ++++++------ src/forge/Settings/Collaborator.js | 4 +- .../Settings/CollaboratorMemberByLink.jsx | 25 ++++--- src/forge/users/InfosUser.js | 2 +- 7 files changed, 85 insertions(+), 61 deletions(-) diff --git a/src/common/UrlTool.js b/src/common/UrlTool.js index 53540e38..24512d67 100644 --- a/src/common/UrlTool.js +++ b/src/common/UrlTool.js @@ -11,6 +11,7 @@ export function getImageUrl(path) { // https://www.educoder.net // https://testbdweb.trustie.net // const local = 'http://localhost:3000' + path && !path.startsWith('/') && !path.startsWith('http') && (path = '/'.concat(path)); const local = 'https://testforgeplus.trustie.net'; if (isDev) { return `${local}/${path}` diff --git a/src/forge/Invite/Index.js b/src/forge/Invite/Index.js index 24097e9f..71272b27 100644 --- a/src/forge/Invite/Index.js +++ b/src/forge/Invite/Index.js @@ -1,5 +1,5 @@ -import React, { useState } from 'react'; -import { Modal, Button } from 'antd'; +import React, { useState, useEffect } from 'react'; +import { Modal, Button, } from 'antd'; import { Base64 } from 'js-base64'; import './index.scss'; import { Link } from 'react-router-dom'; @@ -8,54 +8,79 @@ import axios from 'axios'; const identify = { manager: "管理员", - developer: "开发人员", - reporter: "报告者" + developer: "开发者", + reporter: "报告者", + owner: "所有者", } -function Invite({ history, current_user }) { +function Invite({ history, current_user, match, projectDetail, showNotification }) { + if (!current_user.login) { let { pathname, search } = window.location; window.location.href = `/login?go_page=${pathname}${search}`; } + let permission = projectDetail && projectDetail.permission; + const { projectsId, owner } = match.params; let inviteString = window.location.search && window.location.search.split('?invite=')[1]; let data = inviteString && JSON.parse(Base64.decode(inviteString)); + const [detail, setDetail] = useState({}); const [visible, setVisible] = useState(true); - function accept() { - const url = `/users/${current_user.login}/applied_projects/${data.id}/accept.json`; + useEffect(() => { + if (permission && detail.role && detail.role == permission.toLocaleLowerCase() || permission == 'Owner') { + showNotification(`您已经是${identify[detail.role]}了`) + setTimeout(() => { + history.push(`/${owner}/${projectsId}`); + }, 2000) + } else { + setVisible(true) + } + }, [permission, detail.role]); + + useEffect(() => { + const url = `/${owner}/${projectsId}/project_invite_links/show_link.json?invite_sign=${data.sign}`; axios.get(url).then(res => { if (res && res.data) { - console.log(res) + setDetail(res.data); + } else { + showNotification('查询邀请链接失败'); + } + }) + }, []) + + function accept() { + const url = `/${owner}/${projectsId}/project_invite_links/redirect_link.json?invite_sign=${data.sign}`; + axios.post(url).then(res => { + if (res && res.data.message == 'success') { + if (detail.is_apply) { + setVisible(false); + Modal.success({ content: '提交申请成功,请等待该仓库管理员审核' }); + } else { + history.push(`/${owner}/${projectsId}`); + } } }).catch(error => { }) + } - function refuse() { - const url = `/users/${current_user.login}/applied_projects/${data.id}/refuse.json`; - axios.get(url).then(res => { - if (res && res.data) { - console.log(res) - } - }).catch(error => { }) - } + return (
    {data &&
    } + title={
    } width="548px" closable={true} - onCancel={() => setVisible(false)} + onCancel={() => { setVisible(false); history.push(`/${current_user.login}`) }} centered okText={'接受'} cancelText={'拒绝'} onOk={accept} - onCancel={refuse} - // icon={} + maskClosable={false} > - {data.ownerName}/{data.projectName} + {detail.project && detail.project.owner.name}/{detail.project && detail.project.name}
    - {data.userName} 邀请您以{identify[data.role]}的身份加入此代码库 + {detail.user && detail.user.name} 邀请您以{identify[detail.role]}的身份加入此代码库 是否接受邀请?
    } diff --git a/src/forge/Invite/index.scss b/src/forge/Invite/index.scss index 5735abb3..87912b65 100644 --- a/src/forge/Invite/index.scss +++ b/src/forge/Invite/index.scss @@ -41,6 +41,7 @@ display: flex; justify-content: center; align-items: center; + overflow: hidden; img{ width: 100%; } diff --git a/src/forge/Main/Detail.js b/src/forge/Main/Detail.js index 5e76a1c1..b6b90b9b 100644 --- a/src/forge/Main/Detail.js +++ b/src/forge/Main/Detail.js @@ -4,6 +4,7 @@ import { Link, Route, Switch } from 'react-router-dom'; import { Content, AlignTop } from '../Component/layout'; import DetailBanner from './sub/DetailBanner'; import cookie from 'react-cookies'; +import { Base64 } from 'js-base64'; import '../css/index.scss' import './list.scss'; @@ -371,32 +372,30 @@ class Detail extends Component { if (window.location.pathname.includes('/invite')) { let inviteString = window.location.search && window.location.search.split('?invite=')[1]; let data = inviteString && JSON.parse(Base64.decode(inviteString)); - // this.setState({ - // project: { author: { login:data. } } - // }); - // {project && project.author && - // {project.author.name} - // } - // / - // {projectDetail && projectDetail.name} + const { project = {}, projectDetail = {} } = this.state + this.setState({ + project: Object.assign(project, { author: { name: data.ownerName } }), + projectDetail: Object.assign(projectDetail, { name: data.projectName }) + }); } else { this.props.history.push('/nopage'); } + } else { + this.setState({ + projectDetail: result.data, + project_id: result.data.project_id, + isManager: result.data.permission && (result.data.permission === "Manager" || result.data.permission === "Admin" || result.data.permission === "Owner"), + isReporter: result.data.permission && result.data.permission === "Reporter", + isDeveloper: result.data.permission && result.data.permission === "Developer", + http_url: result.data.clone_url, + praised: result.data.praised, + watched: result.data.watched, + watchers_count: result.data.watchers_count, + praises_count: result.data.praises_count, + forked_count: result.data.forked_count, + defaultBranch: result.data.default_branch + }) } - this.setState({ - projectDetail: result.data, - project_id: result.data.project_id, - isManager: result.data.permission && (result.data.permission === "Manager" || result.data.permission === "Admin" || result.data.permission === "Owner"), - isReporter: result.data.permission && result.data.permission === "Reporter", - isDeveloper: result.data.permission && result.data.permission === "Developer", - http_url: result.data.clone_url, - praised: result.data.praised, - watched: result.data.watched, - watchers_count: result.data.watchers_count, - praises_count: result.data.praises_count, - forked_count: result.data.forked_count, - defaultBranch: result.data.default_branch - }) } }).catch((error) => { }) } @@ -544,7 +543,6 @@ class Detail extends Component { let pathname = checkPathname(projectsId, owner, url); const { state } = this.props.history.location; - const common = { getDetail: this.getDetail, getBanner: this.getBanner, diff --git a/src/forge/Settings/Collaborator.js b/src/forge/Settings/Collaborator.js index bc8b01ce..d22862aa 100644 --- a/src/forge/Settings/Collaborator.js +++ b/src/forge/Settings/Collaborator.js @@ -7,7 +7,7 @@ import Group from './CollaboratorGroup'; import MemberByLink from './CollaboratorMemberByLink'; function Collaborator(props){ - const [ nav , setNav] = useState("3"); + const [ nav , setNav] = useState("1"); const [ newId , setNewId] = useState(undefined); const [ newIdFlag , setNewIdFlag ] = useState(false); const [ addOperation , setAddOperation] = useState(true); @@ -42,7 +42,7 @@ function Collaborator(props){ {author && author.type === "Organization" && {setNav("2");setNewId(undefined);setNewGroupId(undefined)}}>团队管理} { - (nav === "1" || nav === "3") && + nav === "1" && } { diff --git a/src/forge/Settings/CollaboratorMemberByLink.jsx b/src/forge/Settings/CollaboratorMemberByLink.jsx index e231e3bb..ea34ec8f 100644 --- a/src/forge/Settings/CollaboratorMemberByLink.jsx +++ b/src/forge/Settings/CollaboratorMemberByLink.jsx @@ -17,28 +17,27 @@ function CollaboratorMemberByLink({ projectsId, owner, project_id, author, showN const [role, setRole] = useState('developer'); const [is_apply, setIs_apply] = useState(true); - const [inviteUrl, setinviteUrl] = useState('dddd'); + const [inviteUrl, setinviteUrl] = useState(''); const [copy, setCopy] = useState(false); useEffect(() => { - const url = `/${owner}/${projectsId}/project_invite_links/generate_link.json`; - axios.post(url, { - role, - is_apply + const url = `/${owner}/${projectsId}/project_invite_links/current_link.json`; + axios.get(url, { + params: { + role, + is_apply + } }).then(res => { if (res && res.data) { let params = { - id:res.data.id, projectName: res.data.project.name, projectId: res.data.project.identifier, - is_apply: res.data.is_apply, - role: res.data.role, - is_public: res.data.project.is_public, - ownerImage: res.data.project.owner.image_url, + // role: res.data.role, ownerLogin: res.data.project.owner.login, ownerName: res.data.project.owner.name, - userName: res.data.user.name, - userLogin:res.data.user.login, + // userName: res.data.user.name, + // userLogin: res.data.user.login, + sign:res.data.sign, }; let urlParams = JSON.stringify(params); let content = Base64.encode(urlParams); @@ -71,7 +70,7 @@ function CollaboratorMemberByLink({ projectsId, owner, project_id, author, showN })} - { setIs_apply(e.target.checked) }}>是否需要管理员审核 + { setIs_apply(e.target.checked) }}>需要管理员审核
    邀请链接
    {this.get_projects()}} className="list-r-Search" value={search} onChange={this.changeSearchValue}