邀请用户链接页面

This commit is contained in:
何童崇 2022-06-17 11:08:33 +08:00
parent c30e229f73
commit cb241bece3
7 changed files with 169 additions and 42 deletions

View File

@ -80,7 +80,7 @@ function AddMember({getID,login,showNotification}){
<AutoComplete
dataSource={source}
value={searchKey}
style={{ width: 300 }}
style={{ width: 250 }}
onChange={changeInputUser}
onSelect={selectInputUser}
placeholder="搜索需要添加的用户..."

42
src/forge/Invite/Index.js Normal file
View File

@ -0,0 +1,42 @@
import React, { useState } from 'react';
import { Modal, Button } from 'antd';
import { Base64 } from 'js-base64';
import './index.scss';
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)
const [visible, setVisible] = useState(true);
function accept() {
}
return (
<div className="">
<Modal
visible={visible}
className="invite_development"
title="提示"
width="548px"
closable={true}
onCancel={() => setVisible(false)}
centered
okText={'接受'}
cancelText={'拒绝'}
onOk={accept}
>
<div className="">
{/* <Button type="primary" onClick={accept}>接受</Button> */}
</div>
</Modal>
</div>
)
}
export default Invite;

View File

@ -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;
}
}
}
}

View File

@ -145,6 +145,10 @@ const WikiEdit = Loadable({
loader: () => import('../Wiki/EditWiki'),
loading: Loading,
});
const Invite = Loadable({
loader: () => import('../Invite/Index'),
loading: Loading,
});
/**
* permissionManager:管理员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 {
<Link to={`/${owner}/${projectsId}`} className="projectN mt6">{projectDetail && projectDetail.name}</Link>
</div>
{projectDetail && projectDetail.private && <span className="privateTag mt6">私有</span>}
{ !platform && <span className="privateTag red mt6">只读</span> }
{!platform && <span className="privateTag red mt6">只读</span>}
</AlignTop>
<div className="mt8">
{
@ -718,7 +722,7 @@ class Detail extends Component {
(props) => (<Setting {...this.props} {...props} {...this.state} {...common} />)
}
></Route>
{/*修改里程碑*/}
<Route path="/:owner/:projectsId/milestones/:meilid/edit"
render={
@ -758,18 +762,18 @@ class Detail extends Component {
{/* 修改详情 edit*/}
<Route path="/:owner/:projectsId/issues/:orderId/edit"
render={
(props) => (<OrderupdateDetail {...this.props} {...props} {...this.state} {...common} form_type={"edit"}/>)
(props) => (<OrderupdateDetail {...this.props} {...props} {...this.state} {...common} form_type={"edit"} />)
}
></Route>
{/* 复制详情 copyetail*/}
<Route path="/:owner/:projectsId/issues/:orderId/copyetail"
render={
(props) => (<OrderupdateDetail {...this.props} {...props} {...this.state} {...common} form_type={"copy"}/>)
(props) => (<OrderupdateDetail {...this.props} {...props} {...this.state} {...common} form_type={"copy"} />)
}
></Route>
{/* 任务详情 */}
<Route path="/:owner/:projectsId/issues/:orderId"
{/* 任务详情 */}
<Route path="/:owner/:projectsId/issues/:orderId"
render={
(props) => (<OrderDetail {...this.props} {...this.state} {...props} {...common} />)
}
@ -861,6 +865,12 @@ class Detail extends Component {
(props) => (<CoderDepot {...this.props} {...props} {...this.state} {...common} />)
}
></Route>
{/* 邀请 */}
<Route path="/:owner/:projectsId/invite"
render={
(props) => (<Invite {...this.props} {...props} {...this.state} {...common} />)
}
></Route>
<Route path="/:owner/:projectsId/:subIndex"
render={
(props) => (<CoderRootIndex {...this.props} {...props} {...this.state} {...common} />)

View File

@ -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 (
<div className='addMemByLinkBox'>
<div className='font-16 mt20 mb5'>请选择邀请用户权限</div>
<Select className='selectBox' defaultValue="developer">
{optionList.map(item=>{
return <Select.Option value={item.value}>{item.name}</Select.Option>
<div className='font-16 mt20 mb10'>请选择邀请用户权限</div>
<Select className='selectBox' defaultValue="developer" onChange={(v) => { setRole(v) }}>
{optionList.map(item => {
return <Select.Option value={item.value} key={item.value}>{item.name}</Select.Option>
})}
</Select>
<Checkbox className='font-15 checkBox'>是否需要管理员审核</Checkbox>
<div className='font-16 mt10 mb5'>邀请链接</div>
<Input addonAfter={<Button type='primary'>复制链接</Button>} className='linkBox'/>
<div className='tipBox mt20'>
<Checkbox className='font-15 checkBox' onChange={e => { setIs_apply(e.target.checked) }}>是否需要管理员审核</Checkbox>
<div className='font-16 mt25 mb10'>邀请链接</div>
<Input
id="inviteUrl"
value={inviteUrl}
readOnly
addonAfter={<Button type='primary' onClick={ inviteClick}>{copy?'复制成功':'复制链接'}</Button>} className='linkBox'
/>
<div className='tipBox mt25'>
<div>: </div>
<div className='ml5'>
1管理员可通过分享邀请链接的方式邀请其他成员加入项目<br/>
2若已勾选管理员审核选项用户接收邀请后管理员可在个人主页中待办事项窗口审核成员审核信息若不需要管理员审核成员接收邀请后将直接加入项目
1管理员可通过分享邀请链接的方式邀请其他成员加入项目<br />
2若已勾选管理员审核选项用户接收邀请后管理员可在个人主页中待办事项窗口审核成员审核信息若不需要管理员审核成员接收邀请后将直接加入项目
</div>
</div>
</div>

View File

@ -249,7 +249,7 @@
.selectBox {
width: 55%;
display: block;
margin-bottom: 8px;
margin-bottom: 18px;
}
.checkBox{
color:#151d40;

View File

@ -242,6 +242,7 @@ form{
cursor: pointer;
padding-right: 20px;
margin:0px;
border-bottom: 1px solid #eee;
a{
width:100%;
color: #202d40;