diff --git a/src/AppConfig.js b/src/AppConfig.js index f897831f..2c34caa6 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) { diff --git a/src/forge/Head/AddProjectModal.jsx b/src/forge/Head/AddProjectModal.jsx new file mode 100644 index 00000000..8e3073e3 --- /dev/null +++ b/src/forge/Head/AddProjectModal.jsx @@ -0,0 +1,84 @@ +import React, { useState , forwardRef, useEffect } from 'react'; +import { Form , Modal , Input , Radio } from 'antd'; +import Axios from 'axios'; + +export default Form.create()( + forwardRef((props)=>{ + const { getFieldDecorator, validateFields , setFieldsValue } = props && props.form; + const [ visible , setVisible ] = useState(false); + + useEffect(()=>{ + if(!visible){ + setFieldsValue({ + code:undefined, + role:"developer" + }) + } + },[visible]) + + function onOk() { + validateFields((error,values)=>{ + if(!error){ + const url = `/applied_projects.json`; + Axios.post(url,{ + applied_project:{ + ...values + } + }).then(result=>{ + if(result && result.data){ + setVisible(false); + props.showNotification("申请加入项目成功,等待审核!"); + } + }).catch(error=>{}) + } + }) + } + function checkValue(rule, value, callback){ + if(!value){ + callback(); + } + if(value.length < 6 || value.length > 6){ + callback("请输入6位数的邀请码"); + } + callback(); + } + + return( + + setVisible(false)} + > +
+ + {getFieldDecorator("code",{ + rules:[ + {required:true,message:"请输入6位项目邀请码"}, + {validator:checkValue} + ] + })( + + )} + + + {getFieldDecorator("role",{ + rules:[{required:true,message:"请选择角色"}] + })( + + 管理员 + 开发者 + 报告者 + + )} + +
+
+ setVisible(true)}>加入项目 +
+ ) + }) +) \ No newline at end of file diff --git a/src/forge/Head/Header.js b/src/forge/Head/Header.js index b2387cb6..f9071162 100644 --- a/src/forge/Head/Header.js +++ b/src/forge/Head/Header.js @@ -5,8 +5,7 @@ import axios from 'axios'; import { Input , notification , Dropdown , Menu } from 'antd'; import LoginDialog from '../../modules/login/LoginDialog'; -import GotoQQgroup from '../../modal/GotoQQgroup' - +import AddProjectModal from './AddProjectModal'; import '../../modules/tpm/TPMIndex.css'; import './header.scss'; @@ -268,11 +267,11 @@ class NewHeader extends Component { ) }) } + ) } - renderMenu=(personal)=>{ const { current_user } = this.props; return( diff --git a/src/forge/Head/header.scss b/src/forge/Head/header.scss index 507262e3..a2c11b7a 100644 --- a/src/forge/Head/header.scss +++ b/src/forge/Head/header.scss @@ -1,7 +1,6 @@ .dropdownFlex{ display:flex; - padding:5px; background:#fff; border-radius: 3px; .ant-menu-vertical > .ant-menu-item{ @@ -9,6 +8,13 @@ height: 35px; line-height: 35px; margin:0px; + &.ant-menu-item-selected{ + background-color: #fff; + a{color: rgba(0, 0, 0, 0.65)!important;} + } + &.ant-menu-item-active{ + a{color: #4cacff!important;} + } } .ant-menu-vertical{ border:none; @@ -104,4 +110,13 @@ } } } +} +.inviteForm{ + .ant-form-item{ + margin-right: 0px; + } + .ant-form-item-label{ + width: 110px; + text-align: right; + } } \ No newline at end of file diff --git a/src/forge/Notice/Apply.jsx b/src/forge/Notice/Apply.jsx new file mode 100644 index 00000000..3c77edfa --- /dev/null +++ b/src/forge/Notice/Apply.jsx @@ -0,0 +1,114 @@ +import React, { useEffect , useState } from 'react'; +import Axios from 'axios'; +import { Pagination , Spin , Popconfirm }from 'antd'; +import { Link } from 'react-router-dom'; +import { getImageUrl } from 'educoder'; +import Nodata from '../Nodata'; +import { FlexAJ } from '../Component/layout'; + +const limit = 15; +function Apply(props) { + const username = props.match.params.username; + const [ list , setList ] = useState(undefined); + const [ page , setPage ] = useState(1); + const [ total , setTotal ] = useState(0); + const [ isSpin , setIsSpin ] = useState(true); + + useEffect(()=>{ + if(username){ + setIsSpin(true); + getList(); + } + },[username]) + + function getList() { + const url = `/users/${username}/applied_projects.json`; + Axios.get(url).then(result=>{ + if(result){ + setList(result.data.applied_projects); + setTotal(result.data.total_count); + setIsSpin(false); + } + }).catch(error=>{}) + } + + // 接受 + function acceptDivert(id){ + const url = `/users/${username}/applied_projects/${id}/accept.json`; + Axios.post(url).then(result=>{ + if(result && result.data){ + getList(); + props && props.deleteEvent("apply",1); + } + }).catch(error=>{}) + } + + // 拒绝 + function revertDivert(id){ + const url = `/users/${username}/applied_projects/${id}/refuse.json`; + Axios.post(url).then(result=>{ + if(result && result.data){ + getList(); + props && props.deleteEvent("apply",1); + } + }).catch(error=>{}) + } + return( +
+ +
+ { + list && list.length > 0 ? +
    + { + list.map((i,k)=>{ + return( +
  • + +
    +

    + {i.user && i.user.name} + {i.time_ago} +

    + +

    申请以【{i.role === "developer" ?"开发者":i.role === "manager" ? "管理者":"报告者"}】身份加入【{i.project && i.project.name}】项目。是否同意?

    + { + i.status === "common" && + + acceptDivert(i.id)}> + 同意 + + revertDivert(i.id)}> + 拒绝 + + + } + { + i.status === "accepted" && 已接受 + } + { + i.status === "refused" && 已拒绝 + } +
    +
    +
  • + ) + }) + } +
+ : + "" + } + {list && list.length === 0 && } + { + total > limit && +
+ {setPage(p)}}/> +
+ } +
+
+
+ ) +} +export default Apply; \ No newline at end of file diff --git a/src/forge/Notice/Index.jsx b/src/forge/Notice/Index.jsx new file mode 100644 index 00000000..94c63804 --- /dev/null +++ b/src/forge/Notice/Index.jsx @@ -0,0 +1,128 @@ +import React, { useEffect, useState } from "react"; +import { Link } from 'react-router-dom'; +import './Index.scss'; + +import Loadable from "react-loadable"; +import Loading from "../../Loading"; +import { Route, Switch } from "react-router-dom"; + +const Apply = Loadable({ + loader: () => import("./Apply"), + loading: Loading, +}); +const Notify = Loadable({ + loader: () => import("./Notify"), + loading: Loading, +}); +const UndoEvent = Loadable({ + loader: () => import("./UndoEvent"), + loading: Loading, +}); +function Index(props){ + const username = props.match.params.username; + const pathname = props.history.location.pathname; + const user = props.user; + + const [ menu , setMenu ] = useState("notify"); + const [ messagesCount , setMessagesCount ] = useState(0); + const [ transferCount , setTransferCount ] = useState(0); + const [ applyCount , setApplyCount ] = useState(0); + + const [ flag , setFlag ] = useState(true); + const { current_user } = props; + + useEffect(()=>{ + if((username && current_user && (current_user.login !== username))){ + props.history.push(`/users/${username}`); + } + },[current_user,username]) + + useEffect(()=>{ + if(user){ + setTransferCount(user.undo_transfer_projects); + setApplyCount(user.undo_join_projects); + setMessagesCount(user.undo_messages); + } + },[user]) + + useEffect(()=>{ + if(pathname && username){ + if(pathname === `/users/${username}/notice`){ + setMenu("notify"); + changeNum(user.undo_messages); + } + if(pathname === `/users/${username}/notice/undo`){ + setMenu("undo"); + } + if(pathname === `/users/${username}/notice/apply`){ + setMenu("apply"); + } + } + },[pathname,user]) + + function changeNum(){ + if(flag){ + messagesCount && props.deleteUndoEvent(messagesCount); + setFlag(false); + } + } + + function deleteEvent(type,count) { + let c = count; + if(type==="apply"){ + setApplyCount(applyCount-count); + }else if(type==="undo"){ + setTransferCount(applyCount-count); + }else{ + setMessagesCount(0); + c = messagesCount; + } + (c || c===0) && props.deleteUndoEvent(c); + } + + return ( +
+ + + { + return ; + }} + > + { + return ; + }} + > + { + return ; + }} + > + +
+ ); +} +export default Index; diff --git a/src/forge/Notice/Index.scss b/src/forge/Notice/Index.scss index a50c3413..b00e18a5 100644 --- a/src/forge/Notice/Index.scss +++ b/src/forge/Notice/Index.scss @@ -26,7 +26,7 @@ min-width: 23px; text-align: center; background-color: #ffe4b3; - margin-top: 19px; + margin-top: 27px; margin-left: 10px; display: block; } diff --git a/src/forge/Notice/Notify.jsx b/src/forge/Notice/Notify.jsx index 3aad55ae..761366d3 100644 --- a/src/forge/Notice/Notify.jsx +++ b/src/forge/Notice/Notify.jsx @@ -13,6 +13,10 @@ function Notify(props){ const [ total , setTotal ] = useState(0); const [ isSpin , setIsSpin ] = useState(true); + useEffect(()=>{ + props && props.deleteEvent("notify",0); + },[]) + useEffect(()=>{ if(username){ setIsSpin(true); @@ -43,7 +47,7 @@ function Notify(props){ return

取消转移【{project && project.name}】仓库

case 'common': return

正在将【{project && project.name}】仓库转移给【{owner && owner.name}】

- case 'successed': + case 'successed': return

{project && project.name}】仓库成功转移给【{owner && owner.name}】

default: return

拒绝转移【{project && project.name}】仓库

@@ -53,6 +57,20 @@ function Notify(props){ } } + function renderApplyStatus(status,applied) { + let { project } = applied; + if(status){ + switch(status){ + case 'successed': + return

已通过你加入【{project && project.name}】项目的申请

+ default: + return

已拒绝你加入【{project && project.name}】项目的申请

+ } + }else{ + return "" + } + } + return(
@@ -70,7 +88,7 @@ function Notify(props){ {i.applied_user && i.applied_user.name} {i.time_ago}

- {renderStatus(i.status,i.applied)} + { i.applied_type === "AppliedProject" ? renderApplyStatus(i.status,i.applied):renderStatus(i.status,i.applied)}
) diff --git a/src/forge/Notice/UndoEvent.jsx b/src/forge/Notice/UndoEvent.jsx index 68557a9e..c8c579dc 100644 --- a/src/forge/Notice/UndoEvent.jsx +++ b/src/forge/Notice/UndoEvent.jsx @@ -42,7 +42,7 @@ function UndoEvent(props){ Axios.post(url).then(result=>{ if(result && result.data){ getList(); - props && props.fetchUser(); + props && props.deleteEvent("undo",1); } }).catch(error=>{}) } @@ -53,7 +53,7 @@ function UndoEvent(props){ Axios.post(url).then(result=>{ if(result && result.data){ getList(); - props && props.fetchUser(); + props && props.deleteEvent("undo",1); } }).catch(error=>{}) } diff --git a/src/forge/users/Infos.js b/src/forge/users/Infos.js index c19bce07..9b292d2e 100644 --- a/src/forge/users/Infos.js +++ b/src/forge/users/Infos.js @@ -66,7 +66,6 @@ class Infos extends Component { project_type: undefined, route_type: undefined, undo_events:0, - undo_messages:0, menuKey:"0" }; } @@ -124,20 +123,14 @@ class Infos extends Component { }); const { current_user } = this.props; const { username } = this.props.match.params; - const { pathname } = this.props.location; - const { notice } = this.state; let url = `/users/${username || (current_user && current_user.login)}.json`; axios.get(url).then((result) => { let e = result.data && result.data.undo_events; - let p = result.data && result.data.undo_messages; - let n = notice || pathname === `/users/${username}/notice` ; this.setState({ user: result.data, isSpin: false, - undo_events:n ? (e-p) : e, - undo_messages:0, - notice:n + undo_events:e }); }) .catch((error) => { @@ -161,7 +154,6 @@ class Infos extends Component { this.setState({ route_type: undefined, project_type:"notice", - notice:true },()=>{ this.props.history.push(`/users/${user && user.login}/notice`); this.fetchUser(); @@ -190,6 +182,15 @@ class Infos extends Component { resetUserInfo && resetUserInfo(); } + // 修改待办事项右侧的数量 + deleteUndoEvent=(count)=>{ + let { undo_events } = this.state; + let undo = undo_events - count; + this.setState({ + undo_events:undo + }) + } + render() { const { current_user } = this.props; const { username } = this.props.match.params; @@ -306,7 +307,7 @@ class Infos extends Component { { - return ; + return ; }} >