Merge pull request '分支维护' (#560) from gitlink_server into pre_gitlink_server
|
|
@ -100,6 +100,7 @@
|
|||
"styled-components": "^4.4.1",
|
||||
"whatwg-fetch": "2.0.3",
|
||||
"wrap-md-editor": "^0.2.20",
|
||||
"xss": "^1.0.14",
|
||||
"xterm": "4.8.1",
|
||||
"xterm-addon-fit": "0.4.0"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -3268,6 +3268,7 @@ a.user_greybg_btn {
|
|||
.markdown-body ul>li {
|
||||
list-style-type: disc !important;
|
||||
margin-bottom: 0 !important;
|
||||
|
||||
}
|
||||
|
||||
.new_li .markdown-body ol>li,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
@font-face {
|
||||
font-family: "iconfont"; /* Project id 2340181 */
|
||||
src: url('iconfont.woff2?t=1680498859493') format('woff2'),
|
||||
url('iconfont.woff?t=1680498859493') format('woff'),
|
||||
url('iconfont.ttf?t=1680498859493') format('truetype');
|
||||
src: url('iconfont.woff2?t=1682403222759') format('woff2'),
|
||||
url('iconfont.woff?t=1682403222759') format('woff'),
|
||||
url('iconfont.ttf?t=1682403222759') format('truetype');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
|
|
@ -13,6 +13,38 @@
|
|||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.icon-cangkuyuyanicon:before {
|
||||
content: "\e962";
|
||||
}
|
||||
|
||||
.icon-dongtaiicon1:before {
|
||||
content: "\e963";
|
||||
}
|
||||
|
||||
.icon-jingxuanxiangmu:before {
|
||||
content: "\e964";
|
||||
}
|
||||
|
||||
.icon-zuzhichengyuan1:before {
|
||||
content: "\e965";
|
||||
}
|
||||
|
||||
.icon-zuzhijieshao:before {
|
||||
content: "\e966";
|
||||
}
|
||||
|
||||
.icon-zuzhituandui:before {
|
||||
content: "\e967";
|
||||
}
|
||||
|
||||
.icon-shezhi6:before {
|
||||
content: "\e968";
|
||||
}
|
||||
|
||||
.icon-zidingyi:before {
|
||||
content: "\e969";
|
||||
}
|
||||
|
||||
.icon-a-zu37:before {
|
||||
content: "\e961";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,62 @@
|
|||
"css_prefix_text": "icon-",
|
||||
"description": "",
|
||||
"glyphs": [
|
||||
{
|
||||
"icon_id": "34965902",
|
||||
"name": "仓库语言icon",
|
||||
"font_class": "cangkuyuyanicon",
|
||||
"unicode": "e962",
|
||||
"unicode_decimal": 59746
|
||||
},
|
||||
{
|
||||
"icon_id": "34965903",
|
||||
"name": "动态icon",
|
||||
"font_class": "dongtaiicon1",
|
||||
"unicode": "e963",
|
||||
"unicode_decimal": 59747
|
||||
},
|
||||
{
|
||||
"icon_id": "34965904",
|
||||
"name": "精选项目",
|
||||
"font_class": "jingxuanxiangmu",
|
||||
"unicode": "e964",
|
||||
"unicode_decimal": 59748
|
||||
},
|
||||
{
|
||||
"icon_id": "34965905",
|
||||
"name": "组织成员",
|
||||
"font_class": "zuzhichengyuan1",
|
||||
"unicode": "e965",
|
||||
"unicode_decimal": 59749
|
||||
},
|
||||
{
|
||||
"icon_id": "34965906",
|
||||
"name": "组织介绍",
|
||||
"font_class": "zuzhijieshao",
|
||||
"unicode": "e966",
|
||||
"unicode_decimal": 59750
|
||||
},
|
||||
{
|
||||
"icon_id": "34965907",
|
||||
"name": "组织团队",
|
||||
"font_class": "zuzhituandui",
|
||||
"unicode": "e967",
|
||||
"unicode_decimal": 59751
|
||||
},
|
||||
{
|
||||
"icon_id": "34965908",
|
||||
"name": "设置",
|
||||
"font_class": "shezhi6",
|
||||
"unicode": "e968",
|
||||
"unicode_decimal": 59752
|
||||
},
|
||||
{
|
||||
"icon_id": "34965909",
|
||||
"name": "自定义",
|
||||
"font_class": "zidingyi",
|
||||
"unicode": "e969",
|
||||
"unicode_decimal": 59753
|
||||
},
|
||||
{
|
||||
"icon_id": "34875122",
|
||||
"name": "组 37",
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
<link rel="canonical" href="https://gitlink.org.cn" data-turbo-transient="">
|
||||
<link rel="fluid-icon" href="https://www.gitlink.org.cn/images/logo.png" title="GitLink">
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
|
||||
<link href="https://gw.alipayobjects.com/os/lib/alipay/alex/2.0.19/bundle/alex.all.global.min.css" rel="stylesheet"/>
|
||||
<link rel="stylesheet" type="text/css" href="%PUBLIC_URL%css/alex/alex.all.global.min.css">
|
||||
<link rel="stylesheet" type="text/css" href="%PUBLIC_URL%css/iconfont.css">
|
||||
<!-- <link rel="stylesheet" type="text/css" href="%PUBLIC_URL%css/edu-purge.css"> -->
|
||||
<link rel="stylesheet" type="text/css" href="%PUBLIC_URL%css/editormd.min.css">
|
||||
|
|
@ -53,7 +53,7 @@
|
|||
<script src="%PUBLIC_URL%js/codemirror/codemirror.js"></script>
|
||||
<script src="%PUBLIC_URL%js/editormd/editormd.min.js"></script>
|
||||
<script src="%PUBLIC_URL%js/codemirror/merge/merge.js"></script>
|
||||
<script src="https://gw.alipayobjects.com/os/lib/moment/2.29.4/moment.js"></script>
|
||||
<script src="%PUBLIC_URL%js/alex/moment.js"></script>
|
||||
<script src="https://gw.alipayobjects.com/os/lib/alipay/alex/2.0.19/bundle/alex.all.global.min.js"></script>
|
||||
<%= htmlWebpackPlugin.tags.bodyTags %>
|
||||
<script>
|
||||
|
|
|
|||
|
|
@ -329,7 +329,7 @@ class App extends Component {
|
|||
<MuiThemeProvider theme={theme}>
|
||||
<LoginDialog {...this.props} {...this.state} Modifyloginvalue={() => this.Modifyloginvalue()}></LoginDialog>
|
||||
{/* <GlccModal /> */}
|
||||
{!pathName || (pathName && pathName.indexOf("glcc") === -1) ? <SiderBar {...this.props}/> : <SiderBarHelp/>}
|
||||
{!pathName || (pathName && pathName.toLowerCase().indexOf("glcc") === -1) ? <SiderBar {...this.props}/> : <SiderBarHelp/>}
|
||||
{/* <Router> */}
|
||||
<Switch>
|
||||
{/* wiki预览 */}
|
||||
|
|
@ -449,6 +449,10 @@ class App extends Component {
|
|||
></Route>
|
||||
|
||||
{/*glcc */}
|
||||
<Route
|
||||
path="/glcc/:id"
|
||||
render={(props) => <Glcc {...this.props} {...props} />}
|
||||
></Route>
|
||||
<Route
|
||||
path="/glcc"
|
||||
render={(props) => <Glcc {...this.props} {...props} />}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { Spin } from 'antd';
|
|||
class Loading extends Component {
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
if (!prevProps.error && this.props.error) {
|
||||
console.log(this.props.error)
|
||||
// console.log(this.props.error)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,16 @@
|
|||
import React, { useEffect, useRef, useMemo } from 'react'
|
||||
import 'katex/dist/katex.min.css'
|
||||
import React, { useEffect, useRef, useMemo , useState } from 'react'
|
||||
import 'katex/dist/katex.min.css';
|
||||
import marked, { getTocContent, cleanToc, getMathExpressions, resetMathExpressions } from '../common/marked';
|
||||
import 'code-prettify';
|
||||
import dompurify from 'dompurify';
|
||||
import { getEmoji } from '../forge/Main/emoji';
|
||||
import axios from 'axios';
|
||||
|
||||
import { renderToString } from 'katex'
|
||||
|
||||
const preRegex = /<pre[^>]*>/g;
|
||||
const strRegexSub = /:([a-zA-Z_]+):/g;
|
||||
const quoteRegex = /\[[#][0-9]{0,}\]\(\/[A-Za-z0-9]{0,}\/[A-Za-z0-9]{0,}\/issues\/[0-9]{0,}\)/g;
|
||||
function _unescape(str) {
|
||||
let div = document.createElement('div')
|
||||
div.innerHTML = str
|
||||
|
|
@ -21,8 +23,36 @@ export default ({
|
|||
value = '',
|
||||
className,
|
||||
style = {},
|
||||
url
|
||||
url,
|
||||
owner=undefined,
|
||||
projectsId=undefined
|
||||
}) => {
|
||||
const [ issues , setIssues ] = useState([]);
|
||||
|
||||
useEffect(()=>{
|
||||
if(owner&&projectsId){
|
||||
getIssueList();
|
||||
}
|
||||
},[owner,projectsId])
|
||||
|
||||
function getIssueList(){
|
||||
let matchQuote = str.match(quoteRegex);
|
||||
let array = [];
|
||||
if(matchQuote && matchQuote.length>0){
|
||||
for(var x=0;x<matchQuote.length;x++){
|
||||
let getIndex = matchQuote[x].match(/#(\S*)\]/)[1];
|
||||
getIndex && array.push(getIndex);
|
||||
}
|
||||
axios.get(`/${owner}/${projectsId}/issues/index_to_name`,{params:{
|
||||
index:array
|
||||
}}).then(result=>{
|
||||
if(result){
|
||||
setIssues(result.data);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
let str = String(value);
|
||||
const html = useMemo(() => {
|
||||
let rs = marked(str);
|
||||
|
|
@ -38,6 +68,13 @@ export default ({
|
|||
rs = rs.replace(matchStr[i],getEmoji(matchStr[i]));
|
||||
}
|
||||
}
|
||||
if(owner && projectsId && issues && issues.length>0){
|
||||
for(var x=0;x<issues.length;x++){
|
||||
let item = issues[x];
|
||||
let content = item.id ? `<a href="`+`/${owner}/${projectsId}/issues/${item.project_issues_index}`+`">#${item.project_issues_index}:${item.subject}</a>` : `<span>#${item.project_issues_index}(已删除)</span>`;
|
||||
rs = rs.replaceAll(`<a href="`+`/${owner}/${projectsId}/issues/${item.project_issues_index}`+`">#${item.project_issues_index}</a>`,content);
|
||||
}
|
||||
}
|
||||
|
||||
rs = rs.replace(/(__special_katext_id_\d+__)/g, (_match, capture) => {
|
||||
const { type, expression } = math_expressions[capture];
|
||||
|
|
@ -46,7 +83,7 @@ export default ({
|
|||
rs = rs.replace(/▁/g, "▁▁▁")
|
||||
resetMathExpressions()
|
||||
return dompurify.sanitize(rs)
|
||||
}, [str]);
|
||||
}, [str,issues]);
|
||||
|
||||
// 锚点跳转,链接地址里含#对应的id
|
||||
useEffect(()=>{
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import React , { useEffect , useState } from 'react';
|
||||
import { TPMIndexHOC} from '../../modules/tpm/TPMIndexHOC';
|
||||
import { Timeline, Carousel } from 'antd';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { getImageUrl } from 'educoder';
|
||||
import CountUp from 'react-countup';
|
||||
import axios from 'axios';
|
||||
|
|
@ -17,6 +18,14 @@ import fun2 from './image/fun2.png';
|
|||
import fun3 from './image/fun3.png';
|
||||
import fun4 from './image/fun4.png';
|
||||
import fun5 from './image/fun5.png';
|
||||
import huawei from '../Main/img/index/unit/huawei.png';
|
||||
import langchao from '../Main/img/index/unit/langchao.png';
|
||||
import jijinhui from '../Main/img/index/unit/jijinhui.png';
|
||||
import mulan from '../Main/img/index/unit/mulan.png';
|
||||
import xigongye from '../Main/img/index/unit/xigongye.png';
|
||||
import feiteng from '../Main/img/index/unit/feiteng.png';
|
||||
import xiuos from '../Main/img/index/unit/xiuos.png';
|
||||
import huake from '../Main/img/index/unit/huake.png';
|
||||
|
||||
function AboutUs(){
|
||||
const countUpProps = {
|
||||
|
|
@ -53,6 +62,19 @@ function AboutUs(){
|
|||
}
|
||||
}
|
||||
|
||||
const teamlist =
|
||||
[
|
||||
{url:"/Huawei_Technology",avatar_url:huawei,name:"华为技术有限公司"},
|
||||
{url:"/openatom_foundation",avatar_url:jijinhui,name:"开放原子开源基金会"},
|
||||
{url:"/Inspur",avatar_url:langchao,name:"浪潮信息"},
|
||||
{url:"/mulan-community",avatar_url:mulan,name:"木兰开源社区"},
|
||||
{url:"/CrowdOS_WeSense",avatar_url:xigongye,name:"西北工业大学"},
|
||||
{url:"/pkecosystem",avatar_url:feiteng,name:"PK开源生态项目组"},
|
||||
{url:"/xuos",avatar_url:xiuos,name:"泛在操作系统实验室"},
|
||||
{url:"/hustos",avatar_url:huake,name:"华中科技大学操作系统团队"},
|
||||
]
|
||||
|
||||
|
||||
return(
|
||||
<div className="aboutUs_body">
|
||||
<div className="aboutUs_head df">
|
||||
|
|
@ -63,6 +85,7 @@ function AboutUs(){
|
|||
<a className={selectTitle === 1 ? "active" : ""} href="#value1" onClick={() => setSelectTitle(1)}>关于我们</a>
|
||||
<a className={selectTitle === 2 ? "active" : ""} href="#value2" onClick={() => setSelectTitle(2)}>平台统计</a>
|
||||
<a className={selectTitle === 3 ? "active" : ""} href="#value3" onClick={() => setSelectTitle(3)}>加入我们</a>
|
||||
<a className={selectTitle === 5 ? "active" : ""} href="#value5" onClick={() => setSelectTitle(5)}>精选组织</a>
|
||||
<a className={selectTitle === 4 ? "active" : ""} href="#value4" onClick={() => setSelectTitle(4)}>合作单位</a>
|
||||
</div>
|
||||
<div className="aboutUs">
|
||||
|
|
@ -255,6 +278,24 @@ function AboutUs(){
|
|||
<p className="delivery">简历投递邮箱:zengyt#csxjy.com.cn 曾先生 (用@符号替换#)</p>
|
||||
</div>
|
||||
</div>
|
||||
{/* 精选组织 */}
|
||||
|
||||
<div className="about_team">
|
||||
<a id="value5" className="mao"></a>
|
||||
<div className="au_title">精选组织</div>
|
||||
{
|
||||
teamlist && teamlist.length > 0 &&
|
||||
<ul className="about_team_lists">
|
||||
{
|
||||
teamlist.map((i,k)=>{
|
||||
return(
|
||||
<li><Link to={i.url}><img src={i.avatar_url} title={i.name} alt={i.name} style={{maxWidth:"240px",marginLeft:k===3?"-45px":"0px"}}/></Link></li>
|
||||
)
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
}
|
||||
</div>
|
||||
|
||||
{/* 合作单位 */}
|
||||
<div className="unit">
|
||||
|
|
|
|||
|
|
@ -21,6 +21,41 @@
|
|||
top: -70px;
|
||||
}
|
||||
}
|
||||
.about_team{
|
||||
min-height: 495px;
|
||||
background-image: url('./image/teambanner.png');
|
||||
background-size: 100% 100%;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
.about_team_lists{
|
||||
width: 1200px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
margin-top: 20px;
|
||||
li{
|
||||
height: 120px;
|
||||
width: 266px;
|
||||
margin-right: 40px;
|
||||
margin-bottom: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
&:hover{
|
||||
background-color:#ffffff;
|
||||
border:2px solid #ffffff;
|
||||
border-color:#ffffff;
|
||||
border-radius:6px;
|
||||
box-shadow:0px 1px 8px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
&:nth-child(4n){
|
||||
margin-right: 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.aboutUs_head.df{
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
|
|
|
|||
|
After Width: | Height: | Size: 659 KiB |
|
|
@ -263,15 +263,15 @@ class Activity extends Component{
|
|||
<div class="normalBox-title">项目演化分析</div>
|
||||
<div className="echartBox">
|
||||
|
||||
<span className="echartTitle" style={{marginTop:0}}>开源项目社群激发熵</span>
|
||||
<span className="echartTitle" style={{marginTop:0}}>开源项目社群激发演化拓扑熵</span>
|
||||
<BranchLine url={ai_shang_v1_url}/>
|
||||
<p>基于信息熵围绕疑修任务的社群群智激发演化度量</p>
|
||||
|
||||
<span className="echartTitle">开源项目代码变更熵</span>
|
||||
<span className="echartTitle">开源项目代码变更演化拓扑熵</span>
|
||||
<IssueLine url={ai_shang_v3_url}/>
|
||||
<p>基于信息熵围绕代码提交的软件代码变更演化度量</p>
|
||||
|
||||
<span className="echartTitle">开源项目社区演化熵</span>
|
||||
<span className="echartTitle">开源项目社区演化拓扑熵</span>
|
||||
<SmoothLineTwo url={ai_shang_v4_url}/>
|
||||
<p>基于信息熵围绕项目社群的社区分裂、缩减、合并和扩大演化行为度量</p>
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ function Line({url}) {
|
|||
yAxis: {
|
||||
type: 'value',
|
||||
scale: true,
|
||||
name: '社\n群\n激\n发\n熵',
|
||||
name: '社\n群\n激\n发\n演\n化\n拓\n扑\n熵',
|
||||
min:0,
|
||||
splitLine : {
|
||||
show : true,
|
||||
|
|
@ -49,7 +49,7 @@ function Line({url}) {
|
|||
nameLocation:'end',
|
||||
nameTextStyle:{
|
||||
fontSize:14,
|
||||
padding:[0,70,-80,0]
|
||||
padding:[0,70,-120,0]
|
||||
}
|
||||
},
|
||||
dataZoom: [
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ function Line({url}) {
|
|||
yAxis: {
|
||||
type: 'value',
|
||||
scale: true,
|
||||
name: '代\n码\n变\n更\n熵',
|
||||
name: '代\n码\n变\n更\n演\n化\n拓\n扑\n熵',
|
||||
min:0,
|
||||
splitLine : {
|
||||
show : true,
|
||||
|
|
@ -51,7 +51,7 @@ function Line({url}) {
|
|||
nameLocation:'end',
|
||||
nameTextStyle:{
|
||||
fontSize:14,
|
||||
padding:[0,70,-80,0]
|
||||
padding:[0,70,-120,0]
|
||||
}
|
||||
},
|
||||
dataZoom: [
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ function SmoothLineTwo({url}) {
|
|||
yAxis: {
|
||||
type: 'value',
|
||||
scale: true,
|
||||
name: '社\n区\n演\n化\n熵',
|
||||
name: '社\n区\n演\n化\n拓\n扑\n熵',
|
||||
min:0,
|
||||
splitLine : {
|
||||
show : true,
|
||||
|
|
@ -61,7 +61,7 @@ function SmoothLineTwo({url}) {
|
|||
nameLocation:'end',
|
||||
nameTextStyle:{
|
||||
fontSize:14,
|
||||
padding:[0,70,-80,0]
|
||||
padding:[0,70,-120,0]
|
||||
}
|
||||
},
|
||||
dataZoom: [
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ onChangeFile,addonBefore , name , empty , onEmpty
|
|||
}
|
||||
},[name])
|
||||
|
||||
|
||||
useEffect(()=>{
|
||||
if(addonBefore){
|
||||
setDefaultUrl(addonBefore.split('/'));
|
||||
|
|
@ -50,7 +51,6 @@ onChangeFile,addonBefore , name , empty , onEmpty
|
|||
|
||||
function changeValue(e){
|
||||
const value = e.target.value;
|
||||
console.log(value);
|
||||
if(value){
|
||||
if(value === "/"){
|
||||
setValue(undefined);
|
||||
|
|
|
|||
|
|
@ -75,6 +75,9 @@ class NewHeader extends Component {
|
|||
this.setState({
|
||||
user: newProps.user
|
||||
})
|
||||
// if(!newProps.user ||(newProps.user && !newProps.user.login)){
|
||||
// cookie.remove("login");
|
||||
// }
|
||||
}
|
||||
|
||||
educoderlogin = () => {
|
||||
|
|
@ -311,22 +314,7 @@ class NewHeader extends Component {
|
|||
{
|
||||
settings.navbar && settings.navbar.map((item, key) => {
|
||||
var new_link = item.link;
|
||||
// var user_login = current_user && current_user.login;
|
||||
var is_hidden = item.hidden;
|
||||
// if (new_link && (new_link.indexOf("courses") > -1 || new_link.indexOf("contests") > -1)) {
|
||||
// if (user_login) {
|
||||
// if (new_link.indexOf("courses") > -1) {
|
||||
// new_link = new_link.replace(/courses/g, user_login + "/courses")
|
||||
// } else if (new_link.indexOf("contests") > -1) {
|
||||
// new_link = new_link.replace(/contests/g, user_login + "/contests")
|
||||
// }
|
||||
// } else {
|
||||
// is_hidden = true
|
||||
// }
|
||||
// }
|
||||
// if (user_login && (new_link && new_link.indexOf("homes") > -1)) {
|
||||
// new_link = new_link.replace(/homes/g, user_login + "/user_activities")
|
||||
// }
|
||||
var waiLian = (new_link && str.filter(item=>new_link.indexOf(item)>-1) );
|
||||
var wl = waiLian && waiLian.length>0;
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -115,6 +115,7 @@ function EditComment(props){
|
|||
initValue={content}
|
||||
onChange={(value)=>{setQuillFlag(false);setContent(value);}}
|
||||
isCanAtme = {true}
|
||||
isQuoteIssue={true}
|
||||
changeAtWhoLoginList = {(loginList)=>{setAtWhoLoginList(loginList); setAttachmentClean(true)}}
|
||||
owner = {owner}
|
||||
projectsId = {projectsId}
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ function IssueCommentList(props){
|
|||
}, [reload, category, page])
|
||||
|
||||
function commentCtx(v){
|
||||
return <RenderHtml className="break_word_comments imageLayerParent commentRenderHtml" value={v} url={location}/>;
|
||||
return <RenderHtml owner={owner} projectsId={projectsId} className="break_word_comments imageLayerParent commentRenderHtml" value={v} url={location}/>;
|
||||
};
|
||||
|
||||
// 删除评论内容
|
||||
|
|
|
|||
|
|
@ -106,6 +106,7 @@
|
|||
}
|
||||
.commentContentBox{
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
}
|
||||
.commentContentRight{
|
||||
flex: 1;
|
||||
|
|
|
|||
|
|
@ -17,6 +17,12 @@ function Date({name , today , setDate , editFlag},ref){
|
|||
const refFa = useRef(null);
|
||||
const refBox = useRef(null);
|
||||
|
||||
useEffect(()=>{
|
||||
if(!visible && !editFlag && (time && time !== today)){
|
||||
setDate(time);
|
||||
}
|
||||
},[visible,editFlag,time])
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
document.addEventListener('click', clickMe , false);
|
||||
|
|
@ -29,7 +35,8 @@ function Date({name , today , setDate , editFlag},ref){
|
|||
if (faComponent && boxComponent) {
|
||||
const isChild = faComponent.contains(target);
|
||||
const isBox = boxComponent.contains(target);
|
||||
if(!isChild && !isBox){
|
||||
let role = target.getAttribute("role");
|
||||
if(!isChild && !isBox && !(role && role === "option")){
|
||||
setVisible(false);
|
||||
}
|
||||
}
|
||||
|
|
@ -78,7 +85,7 @@ function Date({name , today , setDate , editFlag},ref){
|
|||
|
||||
<Row type="flex" justify="space-between">
|
||||
<Col>
|
||||
<Group size="small" onChange={e => onTypeChange(e.target.value)} value={type}>
|
||||
<Group size="small" onChange={e => {console.log("typyCHange:",e);onTypeChange(e.target.value)}} value={type}>
|
||||
<Button value="month">日期</Button>
|
||||
<Button value="year">月份</Button>
|
||||
</Group>
|
||||
|
|
@ -91,6 +98,7 @@ function Date({name , today , setDate , editFlag},ref){
|
|||
style={{ width: 80 }}
|
||||
onChange={newYear => {
|
||||
const now = value.clone().year(newYear);
|
||||
setTime(moment(now).format('YYYY-MM-DD'));
|
||||
onChange(now);
|
||||
}}
|
||||
value={String(year)}
|
||||
|
|
@ -106,6 +114,7 @@ function Date({name , today , setDate , editFlag},ref){
|
|||
onChange={selectedMonth => {
|
||||
const newValue = value.clone();
|
||||
newValue.month(parseInt(selectedMonth, 10));
|
||||
setTime(moment(newValue).format('YYYY-MM-DD'));
|
||||
onChange(newValue);
|
||||
}}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import Attachments from "../../Upload/attachment";
|
|||
import UploadImg from '../Img/UploadImg.png';
|
||||
|
||||
function NewPanel(props,ref){
|
||||
const [ description , setDescription ] = useState("");
|
||||
const [ description , setDescription ] = useState(undefined);
|
||||
const [ fileList , setFileList] = useState(undefined);
|
||||
const [ attachments , setAttachments ] = useState([]);
|
||||
const [ save , setSave ] = useState([]);
|
||||
|
|
@ -15,12 +15,11 @@ function NewPanel(props,ref){
|
|||
const { createFunc , title , desc , files , onCancel , owner , projectsId } = props;
|
||||
|
||||
const { form: { getFieldDecorator, validateFields , setFieldsValue } } = props;
|
||||
|
||||
useState(()=>{
|
||||
title && setTimeout(()=>{
|
||||
setFieldsValue({subject:title});
|
||||
desc && onContentChange(desc);
|
||||
},100)
|
||||
desc && setDescription(desc);
|
||||
files && setAttachments(files);
|
||||
files && setSave(files);
|
||||
},[title , desc , files])
|
||||
|
|
@ -84,11 +83,12 @@ function NewPanel(props,ref){
|
|||
<MDEditor
|
||||
placeholder={"请输入描述信息"}
|
||||
height={392}
|
||||
mdID={"order-new-description"}
|
||||
mdID={"issue-edit-description"}
|
||||
initValue={description}
|
||||
onChange={onContentChange}
|
||||
className="mt20"
|
||||
isCanAtme = {true}
|
||||
isQuoteIssue={true}
|
||||
owner = {owner}
|
||||
projectsId = {projectsId}
|
||||
changeAtWhoLoginList = {changeAtWhoLoginList}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ function Details(props){
|
|||
const [ tag , setTag ] = useState(undefined);
|
||||
const [ branchList , setBranchList ] = useState(undefined);
|
||||
const [ branch , setBranch ] = useState(undefined);
|
||||
const [ desc , setDesc ] = useState(undefined);
|
||||
|
||||
const [ orderId , setOrderId ] = useState(undefined);
|
||||
|
||||
|
|
@ -91,6 +92,8 @@ function Details(props){
|
|||
let per = data && !data.user_permission;
|
||||
setEditFlag(per);
|
||||
|
||||
setDesc(data && data.description);
|
||||
|
||||
const aut = current_user && data.author && (data.author.login === current_user.login);
|
||||
const con = data.pull_fixed === false && aut;
|
||||
setAmountEditFlag(con);
|
||||
|
|
@ -277,10 +280,10 @@ function Details(props){
|
|||
if(result){
|
||||
window.scrollTo(0,0);
|
||||
props.showNotification("疑修更新成功!");
|
||||
// 刷新操作记录
|
||||
setCommentReload(Math.random());
|
||||
Init();
|
||||
setEdit(false);
|
||||
// 刷新操作记录
|
||||
setCommentReload(Math.random());
|
||||
}
|
||||
}).catch(error=>{})
|
||||
}else{
|
||||
|
|
@ -318,6 +321,7 @@ function Details(props){
|
|||
props.history.push(`/${owner}/${projectsId}/issues/${index}`);
|
||||
}else{
|
||||
setEdit(false);
|
||||
window.scrollTo(0,0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -367,7 +371,7 @@ function Details(props){
|
|||
{...props}
|
||||
onCancel={onCancel}
|
||||
title={details.subject}
|
||||
desc={details.description}
|
||||
desc={edit ? desc : undefined}
|
||||
files={copy ? undefined : details.attachments}
|
||||
createFunc={createFunc}
|
||||
owner = {owner} projectsId = {projectsId}
|
||||
|
|
@ -405,8 +409,8 @@ function Details(props){
|
|||
}
|
||||
</div>
|
||||
<div class="descPanel">
|
||||
{details.description ?
|
||||
<RenderHtml className="break_word_comments imageLayerParent" value={details.description} url={props.history.location} />
|
||||
{desc ?
|
||||
<RenderHtml owner={owner} projectsId={projectsId} className="break_word_comments imageLayerParent" value={desc} url={props.history.location} />
|
||||
:
|
||||
<span className="color-grey-9 ml3 mr3">暂无描述</span>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -223,6 +223,10 @@ function CoderDepot(props){
|
|||
type
|
||||
}
|
||||
}).then((result) => {
|
||||
if(result.data.status === -2){
|
||||
props.showNotification(result.data.message);
|
||||
props.history.push(`/${owner}/${projectsId}/tree/${turnbar(ref || branchName)}`)
|
||||
}
|
||||
if (result) {
|
||||
let en = result.data.entries;
|
||||
if(en.type){
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ import Meditor from "../Newfile/m_editor";
|
|||
import RenderHtml from "../../components/render-html";
|
||||
import ReadmeCatelogue from "./sub/ReadmeCatelogue";
|
||||
import { Base64 } from "js-base64";
|
||||
import ReplaceModal from "./Modal/ReplaceModal";
|
||||
import {returnbar , turnbar} from 'educoder';
|
||||
|
||||
const $ = window.$;
|
||||
function bytesToSize(bytes) {
|
||||
|
|
@ -23,7 +25,9 @@ class CoderRootFileDetail extends Component {
|
|||
language: undefined,
|
||||
languages: undefined,
|
||||
description: props.detail.replace_content,
|
||||
menuList:undefined
|
||||
menuList:undefined,
|
||||
replaceVisible:false,
|
||||
loading:false
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -212,6 +216,49 @@ class CoderRootFileDetail extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
//------------- 替换原始文件相关
|
||||
showReplaceBox=()=>{
|
||||
this.setState({
|
||||
replaceVisible:true
|
||||
})
|
||||
}
|
||||
|
||||
replaceSure=(e)=>{
|
||||
this.setState({
|
||||
loading:true
|
||||
})
|
||||
const { projectsId, owner , branchName } = this.props.match.params;
|
||||
const { detail } = this.props;
|
||||
const url = `/${owner}/${projectsId}/replace_file.json`;
|
||||
const path = `/${detail.path && detail.path.replace(detail.name,"")}${e.fileName}`;
|
||||
const msg = detail.commit && detail.commit.message;
|
||||
const params={
|
||||
filepath: returnbar(path.substr(1)),
|
||||
base64_filepath:Base64.encode(returnbar(path.substr(1))),
|
||||
branch: returnbar(branchName),
|
||||
content:Base64.encode(e.fileContent),
|
||||
message: msg,
|
||||
delete_file:{
|
||||
filepath: detail.path,
|
||||
base64_filepath:Base64.encode(detail.path),
|
||||
branch:branchName,
|
||||
sha: detail.sha,
|
||||
}
|
||||
};
|
||||
axios.post(url, {
|
||||
...params
|
||||
}).then(result=>{
|
||||
if(result && result.status === 200){
|
||||
this.setState({
|
||||
replaceVisible:false,
|
||||
loading:false
|
||||
})
|
||||
this.props.history.push(`/${owner}/${projectsId}/tree/${turnbar(branchName)}/${turnbar(path.substr(1))}`);
|
||||
}
|
||||
}).catch(error=>{})
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
const {
|
||||
detail,
|
||||
|
|
@ -221,15 +268,22 @@ class CoderRootFileDetail extends Component {
|
|||
currentBranch,
|
||||
platform,
|
||||
md,
|
||||
type
|
||||
type,
|
||||
} = this.props;
|
||||
// 文件只读状态
|
||||
const readOnly = this.props.history.location.search.indexOf('edit') === -1
|
||||
const { language, languages, description } = this.state;
|
||||
const { language, languages, description , replaceVisible , loading } = this.state;
|
||||
let flag = current_user && current_user.login && (isManager || isDeveloper);
|
||||
const Option = Select.Option;
|
||||
return (
|
||||
<React.Fragment>
|
||||
<ReplaceModal
|
||||
visible={replaceVisible}
|
||||
onCancel={()=>{this.setState({replaceVisible:false})}}
|
||||
onOk={this.replaceSure}
|
||||
showNotification={this.props.showNotification}
|
||||
loading={loading}
|
||||
/>
|
||||
<Anchor className="griditemAnchor" offsetTop={58}>
|
||||
<div className="griditemCate">
|
||||
{
|
||||
|
|
@ -318,10 +372,15 @@ class CoderRootFileDetail extends Component {
|
|||
<img alt="" src={detail.download_url} style={{ maxWidth: "80%" }} />
|
||||
</div>
|
||||
) : detail.direct_download ? (
|
||||
<div className="mt20 text-center">
|
||||
<div className="pt10 text-center pb10">
|
||||
<a onClick={() => this.DownLoadFile(detail.download_url)} className="color-blue font-15">
|
||||
下载原始文件
|
||||
</a>
|
||||
{
|
||||
flag ?
|
||||
<a onClick={this.showReplaceBox} className="color-blue font-15" style={{marginLeft:"120px"}}>替换原始文件</a>
|
||||
:""
|
||||
}
|
||||
</div>
|
||||
) : (
|
||||
md && readOnly ?
|
||||
|
|
|
|||
|
|
@ -519,7 +519,6 @@ class Detail extends Component {
|
|||
}
|
||||
|
||||
textFunc = (forked_from_project_id, fork_info) => {
|
||||
let type = fork_info && fork_info.fork_project_user_type;
|
||||
return forked_from_project_id && fork_info ?
|
||||
<div className="color-grey-9 df">
|
||||
<span>复刻自</span>
|
||||
|
|
|
|||
|
|
@ -547,4 +547,8 @@
|
|||
line-height: 24px;
|
||||
color: $primary-color;
|
||||
}
|
||||
}
|
||||
|
||||
.replaceStyle{
|
||||
height: 140px!important;
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
import React , { useState , useRef } from 'react';
|
||||
import { Button, message, Modal } from 'antd';
|
||||
import Upload from "../../Upload/read";
|
||||
import UploadImg from "../../Images/upload.png";
|
||||
import '../Index.scss';
|
||||
|
||||
function ReplaceModal(props){
|
||||
const { visible , onCancel , onOk , showNotification , loading } = props;
|
||||
const [ content , setContent ] = useState(undefined);
|
||||
const [ uploadTip , setUploadTip ] = useState(false);
|
||||
const DelRef = useRef(null);
|
||||
|
||||
function onClose(){
|
||||
setContent(undefined);
|
||||
onCancel();
|
||||
}
|
||||
|
||||
|
||||
function UploadFunc(e){
|
||||
setContent(e);
|
||||
if(e){
|
||||
setUploadTip(false);
|
||||
}else{
|
||||
setUploadTip(true);
|
||||
}
|
||||
}
|
||||
function onSure() {
|
||||
if(!uploadTip && content){
|
||||
onOk && onOk(content);
|
||||
}else{
|
||||
setUploadTip(true);
|
||||
}
|
||||
}
|
||||
return(
|
||||
<Modal
|
||||
title={"替换文件"}
|
||||
width="500px"
|
||||
visible={visible}
|
||||
onCancel={onCancel}
|
||||
footer={
|
||||
<div>
|
||||
<Button onClick={onClose}>取消</Button>
|
||||
<Button onClick={onSure} type={"primary"} className="ml20" loading={loading}>确定</Button>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<Upload
|
||||
className="replaceStyle"
|
||||
load={UploadFunc}
|
||||
ref={DelRef}
|
||||
icon={
|
||||
<img
|
||||
src={UploadImg}
|
||||
width="58"
|
||||
alt=""
|
||||
style={{ marginBottom: 15 }}
|
||||
/>
|
||||
}
|
||||
size={5}
|
||||
showNotification={showNotification}
|
||||
/>
|
||||
<p className="color-red">{uploadTip ? "请上传文件!":""}</p>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
export default ReplaceModal;
|
||||
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 82 KiB |
|
|
@ -65,7 +65,7 @@ function Index() {
|
|||
return(
|
||||
<div>
|
||||
<SubBanner />
|
||||
<SubUnitBanner />
|
||||
{/* <SubUnitBanner /> */}
|
||||
<div className="dataPanel">
|
||||
<div className="left">
|
||||
<ul className="leftTypes">
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
.banners{
|
||||
background: url('../img/index/banner.png') no-repeat top;
|
||||
min-height: 516px;
|
||||
min-height: 360px;
|
||||
background-size: cover;
|
||||
background-color: #0C2A5B;
|
||||
.bannersCenter{
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
max-width: 1200px;
|
||||
margin: 0px auto;
|
||||
position: relative;
|
||||
height: 516px;
|
||||
height: 360px;
|
||||
}
|
||||
.bTitle{
|
||||
height: 30px;
|
||||
|
|
@ -35,8 +35,8 @@
|
|||
.bannerBox{
|
||||
background: url('../img/index/box.png') no-repeat;
|
||||
background-size: 100% 100%;
|
||||
height: 240px;
|
||||
width: 380px;
|
||||
height: 195px;
|
||||
width: 330px;
|
||||
margin:0px auto;
|
||||
padding:25px 30px 34px;
|
||||
.bannersProject{
|
||||
|
|
@ -48,12 +48,12 @@
|
|||
.slick-track{
|
||||
display: flex;
|
||||
li{
|
||||
padding:15px 20px;
|
||||
padding:3px 10px;
|
||||
.projectinfos{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
margin-bottom: 13px;
|
||||
margin-bottom: 8px;
|
||||
img{
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
|
|
@ -63,7 +63,7 @@
|
|||
.name{
|
||||
height: 28px;
|
||||
line-height: 28px;
|
||||
font-size: 20px;
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
|
|
@ -104,7 +104,7 @@
|
|||
}
|
||||
.infoData{
|
||||
display: flex;
|
||||
margin-top: 16px;
|
||||
margin-top: 7px;
|
||||
justify-content: space-around;
|
||||
&>span{
|
||||
display: flex;
|
||||
|
|
@ -127,7 +127,7 @@
|
|||
.airBubble{
|
||||
&>div{
|
||||
position: absolute;
|
||||
height: 410px;
|
||||
height: 100%;
|
||||
width: 415px;
|
||||
bottom: 0px;
|
||||
&.right{
|
||||
|
|
|
|||
|
|
@ -66,6 +66,10 @@ function Files({ data,history,owner,projectsId , parentsSha }){
|
|||
</div>
|
||||
)
|
||||
|
||||
function subStrContent(content){
|
||||
return content ? content.slice(1) :"";
|
||||
}
|
||||
|
||||
return(
|
||||
<div onClick={(e)=>{e.nativeEvent.stopImmediatePropagation()}}>
|
||||
<AlignCenter className="color-grey-9" style={{position:'relative'}}>
|
||||
|
|
@ -127,7 +131,10 @@ function Files({ data,history,owner,projectsId , parentsSha }){
|
|||
<span>{item.leftIdx && item.leftIdx !=="0" ? item.leftIdx :"" }</span>
|
||||
<span>{item.rightIdx && item.rightIdx !=="0" ? item.rightIdx :"" }</span>
|
||||
</span>
|
||||
<p>{item.content}</p>
|
||||
<p style={{display:"flex"}}>
|
||||
<span className="linetype">{item.type===2 ? "+" : item.type===3 ? "-" :""}</span>
|
||||
{ (item.type===3 || item.type===2) ? subStrContent(item.content) : item.content}
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -112,4 +112,9 @@
|
|||
.mergeBox{
|
||||
margin:0px auto;
|
||||
width: 1200px;
|
||||
}
|
||||
.linetype{
|
||||
width:30px;
|
||||
text-align: center;
|
||||
display: inline-block;
|
||||
}
|
||||
|
|
@ -41,10 +41,19 @@ class MergeItem extends Component {
|
|||
}
|
||||
};
|
||||
|
||||
toDetailFunc=(url)=>{
|
||||
const { disable_pr_vew } = this.props;
|
||||
if(disable_pr_vew && disable_pr_vew === true){
|
||||
this.props.showNotification("暂无权限访问合并请求,请联系项目管理员开启访问权限!");
|
||||
}else{
|
||||
this.props.history.push(url);
|
||||
window.scrollTo(0,0);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { issues, project_name, project_author_name , user_admin_or_developer , open_blockchain} = this.props;
|
||||
const { issues , project_author_name , user_admin_or_developer , open_blockchain } = this.props;
|
||||
const { projectsId , owner } = this.props.match.params;
|
||||
const { current_user } = this.props;
|
||||
const renderList = () => {
|
||||
if (issues && issues.length > 0) {
|
||||
return issues.map((item, key) => {
|
||||
|
|
@ -54,14 +63,13 @@ class MergeItem extends Component {
|
|||
<div className="flex-1">
|
||||
<p className="mb15 df" style={{ alignItems: "center" }}>
|
||||
<i className={`iconfont icon-hebingqingqiu1 font-14 mr3 i_${status}`}></i>
|
||||
<Link
|
||||
to={`/${owner}/${projectsId}/pulls/${item.pull_request_number || item.pull_request_id}`}
|
||||
onClick={()=>{window.scrollTo(0,0)}}
|
||||
<a
|
||||
onClick={()=>this.toDetailFunc(`/${owner}/${projectsId}/pulls/${item.pull_request_number || item.pull_request_id}`)}
|
||||
className="hide-1 font-15 color-grey-3 fwb lineh-30 mr10"
|
||||
style={{ maxWidth: "600px" }}
|
||||
>
|
||||
{item.name}
|
||||
</Link>
|
||||
</a>
|
||||
<Tag className={`pr_tags_${status}`}>
|
||||
{status === "merged"
|
||||
? "已合并"
|
||||
|
|
|
|||
|
|
@ -382,7 +382,7 @@ class MessageCount extends Component {
|
|||
<div className="ver-middle">
|
||||
<span className="mr10 ver-middle">
|
||||
<span className="font-18 fwb" style={{wordBreak:"break-all"}}>
|
||||
{data.issue.subject}
|
||||
{data.issue && data.issue.subject}
|
||||
</span>
|
||||
</span>
|
||||
|
||||
|
|
|
|||
|
|
@ -193,7 +193,6 @@ form .ant-cascader-picker, form .ant-select {
|
|||
width: 100px;
|
||||
padding: 0px 8px;
|
||||
box-sizing: border-box;
|
||||
margin-right: 8px;
|
||||
}
|
||||
.linesContent .lines > span:first-child{
|
||||
margin-right: 0px;
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ class merge extends Component {
|
|||
page: 1,
|
||||
limit: 15,
|
||||
},
|
||||
disable_pr_vew:false //访问pr的权限
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -114,7 +115,8 @@ class merge extends Component {
|
|||
issues: result.data.issues,
|
||||
search_count: result.data.search_count,
|
||||
isSpin: false,
|
||||
has_created_pull_requests:result.data.has_created_pull_requests
|
||||
has_created_pull_requests:result.data.has_created_pull_requests,
|
||||
disable_pr_vew:result.data.disable_pr_vew
|
||||
});
|
||||
}
|
||||
})
|
||||
|
|
@ -249,7 +251,7 @@ class merge extends Component {
|
|||
data,
|
||||
isSpin,
|
||||
status_type,
|
||||
select_params,has_created_pull_requests
|
||||
select_params,has_created_pull_requests,disable_pr_vew
|
||||
} = this.state;
|
||||
const menu = (
|
||||
<Menu onClick={(e) => this.getMenu(e)}>
|
||||
|
|
@ -420,6 +422,7 @@ class merge extends Component {
|
|||
{...this.state}
|
||||
user_admin_or_developer={data && data.user_admin_or_developer}
|
||||
open_blockchain={open_blockchain}
|
||||
disable_pr_vew={disable_pr_vew}
|
||||
></MergeItem>
|
||||
</div>
|
||||
):""}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,8 @@ class MergeForm extends Component {
|
|||
issue_priories: undefined,
|
||||
atWhoLoginList:undefined,
|
||||
issue_lists:undefined,
|
||||
issue_id:undefined
|
||||
issue_id:undefined,
|
||||
disable_pr_vew:false//是否有权限访问pr
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -79,6 +80,7 @@ class MergeForm extends Component {
|
|||
issue_tags: result.data.issue_tags,
|
||||
issue_versions: result.data.issue_versions,
|
||||
issue_priories: result.data.issue_priories,
|
||||
disable_pr_vew:result.data.disable_pr_vew
|
||||
});
|
||||
}
|
||||
this.setState({ isSpin: false });
|
||||
|
|
@ -91,7 +93,6 @@ class MergeForm extends Component {
|
|||
set_defatul = () => {
|
||||
const { data, merge_type } = this.props;
|
||||
if (data && merge_type === "edit") {
|
||||
console.log("dddddddd",data);
|
||||
this.setState({
|
||||
desc: data.body,
|
||||
issue_tag_ids: data.issue_tag_ids ? data.issue_tag_ids[0] : undefined,
|
||||
|
|
@ -168,7 +169,7 @@ class MergeForm extends Component {
|
|||
} else {
|
||||
values.issue_tag_ids = [];
|
||||
}
|
||||
const { desc , atWhoLoginList } = this.state;
|
||||
const { desc , atWhoLoginList , disable_pr_vew } = this.state;
|
||||
if (merge_type === "new") {
|
||||
let url = `/${owner}/${projectsId}/pulls.json`;
|
||||
axios.post(url, {
|
||||
|
|
@ -190,7 +191,7 @@ class MergeForm extends Component {
|
|||
isSpin: false,
|
||||
});
|
||||
const { pull_request_number } = result.data;
|
||||
this.props.history.push({pathname: `/${owner}/${projectsId}/pulls/${pull_request_number}`, query:{showNps: true}});
|
||||
this.props.history.push({pathname: disable_pr_vew ? `/${owner}/${projectsId}/pulls`:`/${owner}/${projectsId}/pulls/${pull_request_number}`, query:{showNps: true}});
|
||||
const { getDetail } = this.props;
|
||||
getDetail && getDetail();
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -398,7 +398,7 @@ class Index extends Component {
|
|||
<Input placeholder="请输入需要导入到本项目的仓库地址" onBlur={this.ChangeAddr} />
|
||||
)}
|
||||
</Form.Item>
|
||||
<p className="formTip color-orange">示例:https://github.com/facebook/reack.git</p>
|
||||
<p className="formTip color-orange">示例:https://github.com/Stability-AI/StableStudio.git</p>
|
||||
</React.Fragment>
|
||||
}
|
||||
{
|
||||
|
|
|
|||
|
|
@ -37,6 +37,11 @@ function Index(props){
|
|||
|
||||
function onChangeFile(value){
|
||||
setFileName(value);
|
||||
if(value){
|
||||
setEmpty(false);
|
||||
}else{
|
||||
setEmpty(true);
|
||||
}
|
||||
}
|
||||
|
||||
return(
|
||||
|
|
|
|||
|
|
@ -88,8 +88,8 @@ class UserSubmitComponent extends Component {
|
|||
if (!err && !checkName) {
|
||||
const url = `/${owner}/${projectsId}/create_file.json`;
|
||||
axios.post(url, {
|
||||
filepath: path.substr(1),
|
||||
base64_filepath:Base64.encode(path.substr(1)),
|
||||
filepath: returnbar(path.substr(1)),
|
||||
base64_filepath:Base64.encode(returnbar(path.substr(1))),
|
||||
branch: returnbar(branch),
|
||||
new_branch: submitType === "1" ? values.branchname : undefined,
|
||||
content:content ? (editor_type === "upload" ? content : Base64.encode(content)):"",
|
||||
|
|
@ -130,8 +130,8 @@ class UserSubmitComponent extends Component {
|
|||
if (!err && !checkName) {
|
||||
axios
|
||||
.put(url, {
|
||||
filepath: detail.path,
|
||||
base64_filepath:Base64.encode(detail.path),
|
||||
filepath: returnbar(detail.path),
|
||||
base64_filepath:Base64.encode(returnbar(detail.path)),
|
||||
branch: submitType === "1" ? undefined : returnbar(b),
|
||||
new_branch: submitType === "1" ? values.branchname : undefined,
|
||||
content: content,
|
||||
|
|
@ -143,7 +143,7 @@ class UserSubmitComponent extends Component {
|
|||
if (result.data && result.data.status === 1) {
|
||||
let b = currentBranch || branch;
|
||||
window.scrollTo(0,0);
|
||||
let url = `/${owner}/${projectsId}${(values.branchname ? `/tree/${turnbar(values.branchname)}` : (b ? `/tree/${turnbar(b)}`:""))}`;
|
||||
let url = `/${owner}/${projectsId}${(values.branchname ? `/tree/${turnbar(values.branchname)}` : (b ? `/tree/${turnbar(b)}`:""))}${detail.path ? `/${returnbar(detail.path)}` : ""}`;
|
||||
this.props.history.push(url);
|
||||
this.props.showNotification("文件修改成功!");
|
||||
}
|
||||
|
|
@ -185,7 +185,8 @@ class UserSubmitComponent extends Component {
|
|||
onChangeFile=(value)=>{
|
||||
const { changeName } = this.props;
|
||||
this.setState({
|
||||
filename:value
|
||||
filename:value,
|
||||
empty:value?false:true
|
||||
})
|
||||
changeName && changeName(value);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import IDEPlugin, { ExtensionCommand } from './plugins/idePlugin';
|
|||
import { repoService } from './codeReview/mock/repo.service';
|
||||
|
||||
|
||||
function CloudIDE({ download_url, params: { owner, projectsId, branchName }, filepath }) {
|
||||
function CloudIDE({ download_url, params: { owner, projectsId, branchName }, filepath , value }) {
|
||||
function FileContentStore() {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [showIde, setShowIde] = useState(false);
|
||||
|
|
@ -35,8 +35,7 @@ function CloudIDE({ download_url, params: { owner, projectsId, branchName }, fil
|
|||
};
|
||||
}
|
||||
|
||||
const { fileSize, fileName } =
|
||||
FileContentStore();
|
||||
const { fileSize, fileName } = FileContentStore();
|
||||
const fileCache = new Map();
|
||||
|
||||
const copyFile = () => {
|
||||
|
|
@ -92,12 +91,11 @@ function CloudIDE({ download_url, params: { owner, projectsId, branchName }, fil
|
|||
// blame
|
||||
const onBlame = async (e) => {
|
||||
setBlameChecked(e.target.checked);
|
||||
console.log('onBlame:', e.target.checked);
|
||||
if (!e.target.checked) {
|
||||
plugin.current.commands.executeCommand(ExtensionCommand.toggleBlame);
|
||||
if (!e.target.checked ) {
|
||||
plugin.current.commands && plugin.current.commands.executeCommand(ExtensionCommand.toggleBlame);
|
||||
} else {
|
||||
const res = await repoService.getCodeBlame(projectsId, owner, { sha:decodeURIComponent(branchName), filepath })
|
||||
plugin.current.commands.executeCommand(ExtensionCommand.toggleBlame, res);
|
||||
plugin.current.commands && plugin.current.commands.executeCommand(ExtensionCommand.toggleBlame, res);
|
||||
}
|
||||
};
|
||||
const [wordWrap, setWordWrap] = useState(false);
|
||||
|
|
@ -194,89 +192,92 @@ function CloudIDE({ download_url, params: { owner, projectsId, branchName }, fil
|
|||
wordWrap={wordWrap}
|
||||
setWordWrap={onWordWrapChange}
|
||||
/> */}
|
||||
|
||||
|
||||
<EditorRenderer
|
||||
appConfig={{
|
||||
// 工作空间目录
|
||||
plugins: [changeThemePlugin, plugin.current],
|
||||
workspaceDir: `${owner}/${projectsId}`,
|
||||
defaultPreferences: {
|
||||
// 默认主题,如果暗色为 opensumi-dark
|
||||
// 'general.theme': 'opensumi-light',
|
||||
'general.theme': 'opensumi-light',
|
||||
// 编辑器只读
|
||||
'editor.forceReadOnly': true,
|
||||
// 最后一行禁止继续滚动
|
||||
'editor.scrollBeyondLastLine': false,
|
||||
},
|
||||
extensionMetadata: [
|
||||
html,
|
||||
css,
|
||||
json,
|
||||
typescript,
|
||||
markdown,
|
||||
ideTheme,
|
||||
CodeBlame],
|
||||
}}
|
||||
runtimeConfig={{
|
||||
// 业务标识
|
||||
biz: 'gitlink',
|
||||
// 在 editor 下推荐传 null,此时不会持久化缓存工作空间数据
|
||||
scenario: null,
|
||||
// 启动时显示的编辑器,editor 下传 none 即可
|
||||
startupEditor: 'none',
|
||||
// 隐藏 editor tab
|
||||
hideEditorTab: true,
|
||||
}}
|
||||
editorConfig={{
|
||||
stretchHeight: true,
|
||||
disableEditorSearch: true,
|
||||
}}
|
||||
// 文档模型,以下数据变更时会更新打开的编辑器
|
||||
documentModel={{
|
||||
// 类型,code 下为 code,保持不变
|
||||
type: 'code',
|
||||
// 分支或 tag
|
||||
ref: branchName,
|
||||
// 仓库群组和用户
|
||||
owner: owner,
|
||||
// 仓库名
|
||||
name: projectsId,
|
||||
// 仓库文件路径
|
||||
filepath: filepath,
|
||||
// 读取文件接口
|
||||
readFile: async (filepath) => {
|
||||
if (!filepath) {
|
||||
return;
|
||||
}
|
||||
// 请求接口
|
||||
// const res = await fetch('https://gist.githubusercontent.com/gaearon/0b180827c190fe4fd98b4c7f570ea4a8/raw/b9157ce933c79a4559d2aa9ff3372668cce48de7/LikeButton.js');
|
||||
const res = await fetch(`${getUrl()}/attachments/entries/get_file?download_url=${download_url}`);
|
||||
setTimeout(()=>{
|
||||
onWordWrapChange(localStorage.getItem('code.file.viewer.worlWrap') === 'on');
|
||||
},5000)
|
||||
return res.arrayBuffer();
|
||||
},
|
||||
// 文件编码,和标准工作空间支持编码类型一致,简单场景只传 utf8 或 gbk 即可
|
||||
// encoding: 'utf8',
|
||||
encoding,
|
||||
onFilepathChange: (changedFilepath) => {
|
||||
if (changedFilepath) {
|
||||
console.log(`路由跳转到 ${changedFilepath}`)
|
||||
}
|
||||
},
|
||||
// 指定当前选中多少行
|
||||
// lineNumber: [0, 1],
|
||||
onLineNumberChange: line => {
|
||||
if (typeof line === 'number') {
|
||||
console.log(`#L${line}`)
|
||||
} else {
|
||||
console.log(`#L${line[0]}-${line[1]}`)
|
||||
}
|
||||
},
|
||||
}}
|
||||
/>
|
||||
{
|
||||
value ?
|
||||
<EditorRenderer
|
||||
appConfig={{
|
||||
// 工作空间目录
|
||||
plugins: [changeThemePlugin, plugin.current],
|
||||
workspaceDir: `${owner}/${projectsId}`,
|
||||
defaultPreferences: {
|
||||
// 默认主题,如果暗色为 opensumi-dark
|
||||
// 'general.theme': 'opensumi-light',
|
||||
'general.theme': 'opensumi-light',
|
||||
// 编辑器只读
|
||||
'editor.forceReadOnly': true,
|
||||
// 最后一行禁止继续滚动
|
||||
'editor.scrollBeyondLastLine': false,
|
||||
},
|
||||
extensionMetadata: [
|
||||
html,
|
||||
css,
|
||||
json,
|
||||
typescript,
|
||||
markdown,
|
||||
ideTheme,
|
||||
CodeBlame],
|
||||
}}
|
||||
runtimeConfig={{
|
||||
// 业务标识
|
||||
biz: 'gitlink',
|
||||
// 在 editor 下推荐传 null,此时不会持久化缓存工作空间数据
|
||||
scenario: null,
|
||||
// 启动时显示的编辑器,editor 下传 none 即可
|
||||
startupEditor: 'none',
|
||||
// 隐藏 editor tab
|
||||
hideEditorTab: true,
|
||||
}}
|
||||
editorConfig={{
|
||||
stretchHeight: true,
|
||||
disableEditorSearch: true,
|
||||
}}
|
||||
// 文档模型,以下数据变更时会更新打开的编辑器
|
||||
documentModel={{
|
||||
// 类型,code 下为 code,保持不变
|
||||
type: 'code',
|
||||
// 分支或 tag
|
||||
ref: branchName,
|
||||
// 仓库群组和用户
|
||||
owner: owner,
|
||||
// 仓库名
|
||||
name: projectsId,
|
||||
// 仓库文件路径
|
||||
filepath: filepath,
|
||||
// 读取文件接口
|
||||
readFile: async (filepath) => {
|
||||
if (!filepath) {
|
||||
return;
|
||||
}
|
||||
// 请求接口
|
||||
// const res = await fetch('https://gist.githubusercontent.com/gaearon/0b180827c190fe4fd98b4c7f570ea4a8/raw/b9157ce933c79a4559d2aa9ff3372668cce48de7/LikeButton.js');
|
||||
const res = await fetch(`${getUrl()}/attachments/entries/get_file?download_url=${download_url}`);
|
||||
setTimeout(()=>{
|
||||
onWordWrapChange(localStorage.getItem('code.file.viewer.worlWrap') === 'on');
|
||||
},5000)
|
||||
return res.arrayBuffer();
|
||||
},
|
||||
// 文件编码,和标准工作空间支持编码类型一致,简单场景只传 utf8 或 gbk 即可
|
||||
// encoding: 'utf8',
|
||||
encoding,
|
||||
onFilepathChange: (changedFilepath) => {
|
||||
if (changedFilepath) {
|
||||
console.log(`路由跳转到 ${changedFilepath}`)
|
||||
}
|
||||
},
|
||||
// 指定当前选中多少行
|
||||
// lineNumber: [0, 1],
|
||||
onLineNumberChange: line => {
|
||||
if (typeof line === 'number') {
|
||||
console.log(`#L${line}`)
|
||||
} else {
|
||||
console.log(`#L${line[0]}-${line[1]}`)
|
||||
}
|
||||
},
|
||||
}}
|
||||
/>:
|
||||
<div className="pl20">空文件</div>
|
||||
}
|
||||
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ class m_editor extends Component {
|
|||
|
||||
render() {
|
||||
const { editorValue, changeValue } = this.state;
|
||||
console.log("editorValue:",editorValue)
|
||||
const { readOnly, editorType,onEmpty,filename,empty, currentBranch, descName, checkName, detail, match: { params },filepath,ideTheme } = this.props;
|
||||
const editor_options = {
|
||||
lineNumbers: "on",
|
||||
|
|
@ -68,7 +69,7 @@ class m_editor extends Component {
|
|||
options={editor_options}
|
||||
onChange={this.changeEditor}
|
||||
/> :
|
||||
<CloudIDE download_url={download_url} params={params} filepath={filepath&&filepath.startsWith('/')?filepath.slice(1):filepath}/>
|
||||
<CloudIDE download_url={download_url} value={editorValue} params={params} filepath={filepath&&filepath.startsWith('/')?filepath.slice(1):filepath}/>
|
||||
}
|
||||
</div>
|
||||
{!readOnly && (
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ class Setting extends Component {
|
|||
CategoryList: undefined,
|
||||
LanguageList: undefined,
|
||||
private_check: undefined,
|
||||
prview_check:undefined,
|
||||
loading:true,
|
||||
project_units:['home',"activity","code"],
|
||||
divertVisible:false,
|
||||
|
|
@ -93,6 +94,7 @@ class Setting extends Component {
|
|||
this.setState({
|
||||
projectName:result.data.project_name,
|
||||
private_check: result.data.private,
|
||||
prview_check:result.data.pr_view_admin,
|
||||
loading:false,
|
||||
project_units:units,
|
||||
transfer:result.data.transfer,
|
||||
|
|
@ -224,6 +226,11 @@ class Setting extends Component {
|
|||
});
|
||||
};
|
||||
|
||||
changePrview=(e) => {
|
||||
this.setState({
|
||||
prview_check: e.target.checked,
|
||||
});
|
||||
};
|
||||
// 转移仓库
|
||||
DivertProject=()=>{
|
||||
this.setState({
|
||||
|
|
@ -266,7 +273,7 @@ class Setting extends Component {
|
|||
const { projectsId , owner } = this.props.match.params;
|
||||
const { projectDetail } = this.props;
|
||||
|
||||
const { CategoryList, LanguageList, private_check ,loading , divertVisible , is_transfering, transfer } = this.state;
|
||||
const { CategoryList, LanguageList, private_check , prview_check ,loading , divertVisible , is_transfering, transfer } = this.state;
|
||||
let mirror = projectDetail && projectDetail.mirror;
|
||||
let type = projectDetail && projectDetail.type;
|
||||
const forked_from_project_id = this.props && this.props.projectDetail && this.props.projectDetail.forked_from_project_id;
|
||||
|
|
@ -361,6 +368,26 @@ class Setting extends Component {
|
|||
</Select>
|
||||
)}
|
||||
</Form.Item>
|
||||
<span className="mb15">访问权限:</span>
|
||||
<div className="df" style={{ alignItems: "center" }}>
|
||||
<span className="mr20 mb15 font-16">合并请求(PR)</span>
|
||||
<Form.Item label="">
|
||||
{getFieldDecorator("pr_view_admin", {
|
||||
rules: [],
|
||||
})(
|
||||
<Checkbox
|
||||
checked={prview_check}
|
||||
onChange={this.changePrview}
|
||||
disabled={forked_from_project_id}
|
||||
>
|
||||
<span className="color-grey-3">仅管理员可见</span>
|
||||
{/* <span className="color-grey-6">
|
||||
(合并请求(PR))
|
||||
</span> */}
|
||||
</Checkbox>
|
||||
)}
|
||||
</Form.Item>
|
||||
</div>
|
||||
<Form.Item label="项目导航">
|
||||
{getFieldDecorator("project_units", {
|
||||
rules: [],
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { Button, Collapse , Tooltip , Spin } from 'antd';
|
||||
import { Button, Collapse , Tooltip , Spin , Pagination } from 'antd';
|
||||
import axios from 'axios';
|
||||
import Content from './historyContent';
|
||||
import Fault from '../images/fault.png';
|
||||
|
|
@ -8,21 +8,30 @@ const { Panel } = Collapse;
|
|||
function PushHistory({id,owner,projectsId,showNotification}) {
|
||||
const [ list , setList ] = useState(undefined);
|
||||
const [ isSpin , setIsSpin ] = useState(false);
|
||||
const [ page , setPage ] = useState(1);
|
||||
const [ total , setTotal ] = useState(0);
|
||||
const pageSize = 10;
|
||||
|
||||
useEffect(()=>{
|
||||
if(id && owner && projectsId){
|
||||
Init();
|
||||
Init(1);
|
||||
}
|
||||
},[id,owner,projectsId])
|
||||
|
||||
function Init() {
|
||||
useEffect(()=>{
|
||||
setList(undefined)
|
||||
Init(page);
|
||||
},[page])
|
||||
|
||||
function Init(page) {
|
||||
const url = `/${owner}/${projectsId}/webhooks/${id}/tasks.json`;
|
||||
axios.get(url,{
|
||||
params:{page:1,limit:10}
|
||||
params:{page:page,limit:pageSize}
|
||||
}).then(result=>{
|
||||
if(result && result.data){
|
||||
setList(result.data.tasks);
|
||||
setIsSpin(false);
|
||||
setTotal(result.data.total_count);
|
||||
}
|
||||
}).catch(error=>{})
|
||||
}
|
||||
|
|
@ -49,7 +58,7 @@ function PushHistory({id,owner,projectsId,showNotification}) {
|
|||
</span>
|
||||
</div>
|
||||
{
|
||||
list && list.length>0 &&
|
||||
list && list.length>0 ?
|
||||
<Collapse accordion bordered={false} className="historyColl">
|
||||
{
|
||||
list.map((i,k)=>{
|
||||
|
|
@ -75,6 +84,15 @@ function PushHistory({id,owner,projectsId,showNotification}) {
|
|||
})
|
||||
}
|
||||
</Collapse>
|
||||
:
|
||||
<div style={{height:"470px",display:"flex",alignItems:"center",justifyContent:"center"}}>
|
||||
<Spin />
|
||||
</div>
|
||||
}
|
||||
{
|
||||
total > pageSize ?
|
||||
<div style={{padding:"15px 0px",textAlign:"right"}}><Pagination size="small" showQuickJumper pageSize={pageSize} current={page} total={total} onChange={(p)=>setPage(p)}/></div>
|
||||
:""
|
||||
}
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
export default (({ name , count , bottom , children , url })=>{
|
||||
export default (({ name , icon , count , bottom , children , url })=>{
|
||||
return(
|
||||
<div className="box">
|
||||
<div className="head">
|
||||
<span className="font-16">{name}</span>
|
||||
<Link to={url}>{count}<i className="iconfont icon-youjiantou font-12 ml3"></i></Link>
|
||||
<span className="font-17">{icon}{name}{count && `(${count})`}</span>
|
||||
{ url && <Link to={url} style={{color:"rgba(31, 35, 41, 1)"}}>更多<i className="iconfont icon-youjiantou font-12 ml3"></i></Link>}
|
||||
</div>
|
||||
<div className="content">
|
||||
{children}
|
||||
|
|
|
|||
|
|
@ -5,9 +5,7 @@ import { getUploadActionUrl } from 'educoder';
|
|||
function UploadImage({ getImage , url, getImageId }){
|
||||
const [ imageUrl , setImageUrl ] = useState(undefined);
|
||||
useEffect(()=>{
|
||||
if(url){
|
||||
setImageUrl(url);
|
||||
}
|
||||
setImageUrl(url);
|
||||
},[url])
|
||||
|
||||
function getBase64(img, callback) {
|
||||
|
|
@ -33,7 +31,6 @@ function UploadImage({ getImage , url, getImageId }){
|
|||
// 上传完成后
|
||||
function handleChange(info){
|
||||
if(info && info.file && info.file.status === "done"){
|
||||
console.log('info', info);
|
||||
getImageId && getImageId(info.file.response.id);
|
||||
getBase64(info.file.originFileObj, imageUrl =>
|
||||
setImageUrl(imageUrl)
|
||||
|
|
@ -49,6 +46,7 @@ function UploadImage({ getImage , url, getImageId }){
|
|||
action={getUploadActionUrl()}
|
||||
beforeUpload={beforeUpload}
|
||||
onChange={handleChange}
|
||||
accept="image/*"
|
||||
>
|
||||
{
|
||||
imageUrl ?
|
||||
|
|
|
|||
|
|
@ -19,6 +19,10 @@ const New = Loadable({
|
|||
loading: Loading,
|
||||
});
|
||||
const DetailIndex = Loadable({
|
||||
loader: () => import("./List"),
|
||||
loading: Loading,
|
||||
});
|
||||
const TeamDetailIndex = Loadable({
|
||||
loader: () => import("./Sub/Detail"),
|
||||
loading: Loading,
|
||||
});
|
||||
|
|
@ -61,14 +65,14 @@ export default withRouter(CNotificationHOC()(SnackbarHOC()(TPMIndexHOC(
|
|||
<Route
|
||||
path="/:OIdentifier/teams"
|
||||
render={(p) => {
|
||||
return <DetailIndex {...props} {...p}/>
|
||||
return <TeamDetailIndex {...props} {...p}/>
|
||||
}}
|
||||
></Route>
|
||||
{/* 组织成员 */}
|
||||
<Route
|
||||
path="/:OIdentifier/members"
|
||||
render={(p) => {
|
||||
return <DetailIndex {...props} {...p}/>
|
||||
return <TeamDetailIndex {...props} {...p}/>
|
||||
}}
|
||||
></Route>
|
||||
|
||||
|
|
@ -77,17 +81,17 @@ export default withRouter(CNotificationHOC()(SnackbarHOC()(TPMIndexHOC(
|
|||
<Route
|
||||
path="/:OIdentifier/setting"
|
||||
render={(p) => (
|
||||
<DetailIndex {...props} {...p}/>
|
||||
<TeamDetailIndex {...props} {...p}/>
|
||||
)}
|
||||
></Route>
|
||||
|
||||
{/* 组织下的项目详情 */}
|
||||
<Route
|
||||
path="/:owner/:projectsId"
|
||||
render={(p) => (
|
||||
<ProjectDetail {...props} {...p} />
|
||||
)}
|
||||
></Route>
|
||||
path="/:owner/:projectsId"
|
||||
render={(p) => (
|
||||
<ProjectDetail {...props} {...p} />
|
||||
)}
|
||||
></Route>
|
||||
|
||||
{/* 组织详情(包含组织设置) */}
|
||||
<Route
|
||||
|
|
|
|||
|
|
@ -1,3 +1,47 @@
|
|||
.top-orz{
|
||||
background-color:#f9fbfe;
|
||||
box-shadow:0px 8px 20px rgba(17, 35, 146, 0.06);
|
||||
.box{
|
||||
width: 1200px;
|
||||
display: flex;
|
||||
margin:0px auto;
|
||||
align-items: center;
|
||||
padding:25px 0px 35px;
|
||||
&>img{
|
||||
margin-right: 27px;
|
||||
// max-width: 140px;
|
||||
height: 112px;
|
||||
border-radius:4px;
|
||||
}
|
||||
.df{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.info-orz{
|
||||
flex: 1;
|
||||
.orz-main{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
margin-bottom: 14px!important;
|
||||
height:30px;
|
||||
}
|
||||
.orz-name{
|
||||
font-weight:700;
|
||||
color:#333333;
|
||||
font-size:22px;
|
||||
}
|
||||
.orz-desc{
|
||||
color:#4c5b76;
|
||||
font-size:15px;
|
||||
line-height:26px;
|
||||
height: 52px;
|
||||
word-break: break-all;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.teamBox{
|
||||
margin:10px 0px;
|
||||
border:1px solid #eee;
|
||||
|
|
@ -40,17 +84,79 @@
|
|||
margin:0px auto;
|
||||
padding-top:18px;
|
||||
}
|
||||
.list{
|
||||
.content-orz{
|
||||
background-color:#f3f5f8;
|
||||
}
|
||||
.content-orz .list{
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
width: 1200px;
|
||||
margin:0px auto;
|
||||
padding-top: 40px;
|
||||
.list-l{
|
||||
background-color: #fff;
|
||||
// background-image: url('./images/left-bc.png');
|
||||
background-size: 100%;
|
||||
max-width: 860px;
|
||||
width: 72%;
|
||||
margin-bottom: 30px;
|
||||
border:1px solid #eee;
|
||||
padding:30px;
|
||||
.teamnewstatus{
|
||||
padding-bottom: 20px;
|
||||
border-bottom: 1px dashed rgba(170, 175, 190, 1);
|
||||
.teamdesc{
|
||||
color:#4c5876;
|
||||
font-size:14px;
|
||||
line-height:26px;
|
||||
}
|
||||
.teamtitle{
|
||||
height:22px;
|
||||
line-height:22px;
|
||||
color:#1f2329;
|
||||
font-size:16px;
|
||||
margin:20px auto 14px!important;
|
||||
}
|
||||
.teamname{
|
||||
height:24px;
|
||||
span{
|
||||
font-weight:700;
|
||||
color:#1f2329;
|
||||
font-size:17px;
|
||||
}
|
||||
i{
|
||||
margin-right: 4px;
|
||||
color:rgba(31, 35, 41, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
.sepment{
|
||||
margin:30px auto 20px;
|
||||
.ant-radio-group{
|
||||
.ant-radio-button-wrapper{
|
||||
height: 44px;
|
||||
line-height: 42px;
|
||||
border:none;
|
||||
border:1px solid #cccfd2;
|
||||
text-align: center;
|
||||
&:first-child{
|
||||
border-right: none;
|
||||
}
|
||||
&:last-child{
|
||||
border-left: none;
|
||||
}
|
||||
span{
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
.ant-radio-button-wrapper-checked{
|
||||
background-color:#466aff;
|
||||
border-color:#466aff;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
.head{
|
||||
padding:16px 32px;
|
||||
padding:16px 0px;
|
||||
border-bottom: 1px solid #eee;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
|
@ -70,7 +176,6 @@
|
|||
}
|
||||
}
|
||||
.team{
|
||||
padding:0px 32px;
|
||||
min-height: 450px;
|
||||
.team_project{
|
||||
padding:22px 0px;
|
||||
|
|
@ -97,6 +202,8 @@
|
|||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
word-break: break-all;
|
||||
line-height: 22px;
|
||||
}
|
||||
&:last-child{
|
||||
border-bottom: none;;
|
||||
|
|
@ -106,31 +213,53 @@
|
|||
}
|
||||
.list-r{
|
||||
width: 28%;
|
||||
max-width: 340px;
|
||||
padding-left: 20px;
|
||||
max-width: 338px;
|
||||
padding-left:30px;
|
||||
padding-bottom: 30px;
|
||||
box-sizing: border-box;
|
||||
margin-bottom: 30px;
|
||||
& > div{
|
||||
border:1px solid #eee;
|
||||
}
|
||||
}
|
||||
.box{
|
||||
background:rgba(255,255,255,1);
|
||||
border-radius:5px;
|
||||
margin-bottom: 20px;
|
||||
.head{
|
||||
padding:25px 20px;
|
||||
padding:25px 0px 15px;
|
||||
display: flex;
|
||||
border-bottom: 1px solid #eee;
|
||||
border-bottom: 1px dashed rgba(170, 175, 190, 1);
|
||||
justify-content: space-between;
|
||||
color: #333;
|
||||
align-items: center;
|
||||
margin:0px 20px;
|
||||
a:hover{
|
||||
color: #466aff!important;
|
||||
}
|
||||
}
|
||||
.content{
|
||||
padding:13px 0px;
|
||||
padding:5px 0px;
|
||||
.progress{
|
||||
display: flex;
|
||||
padding:10px 35px 10px 20px;
|
||||
align-items: center;
|
||||
&:hover{
|
||||
background-color: rgba(175, 183, 194, 0.13);
|
||||
}
|
||||
}
|
||||
.teammembers{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding:13px 20px;
|
||||
align-items: flex-start;
|
||||
padding:10px 20px 7px 20px;
|
||||
&:hover{
|
||||
background-color: rgba(175, 183, 194, 0.13);
|
||||
}
|
||||
.memberIndex{
|
||||
display: block;
|
||||
width:22px;
|
||||
height:22px;
|
||||
line-height:22px;
|
||||
background-color:#466aff;
|
||||
border-radius:2px;
|
||||
margin-right: 10px;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
}
|
||||
.m-img{
|
||||
border-radius: 50%;
|
||||
width:45px;
|
||||
|
|
@ -141,7 +270,14 @@
|
|||
}
|
||||
.foot{
|
||||
padding:15px 20px;
|
||||
border-top: 1px solid #eee;
|
||||
text-align: center;
|
||||
.newBtn{
|
||||
border-color:#466aff;
|
||||
border-radius:8px;
|
||||
color: #466aff;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -413,4 +549,16 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.overviewcontent{
|
||||
.concentrateUl li{
|
||||
border-color:#cddbeb!important;
|
||||
border-radius:4px;
|
||||
}
|
||||
.ConcentrateTipImg{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
|
@ -7,7 +7,11 @@ import Item from './ListItem';
|
|||
import Right from './RightBox';
|
||||
import NoData from '../Nodata';
|
||||
import CheckProfile from '../Component/ProfileModal/Profile';
|
||||
import { Menu , Pagination , Dropdown , Spin } from 'antd';
|
||||
import { Menu , Pagination , Dropdown , Spin , Tabs , Radio } from 'antd';
|
||||
import ConcentrateProject from '../users/GeneralView/ConcentrateProject';
|
||||
import { getImageUrl } from 'educoder';
|
||||
import RenderHtml from "../../components/render-html";
|
||||
import EmptyImg from '../Images/nodata.png';
|
||||
import axios from 'axios';
|
||||
|
||||
const limit = 15;
|
||||
|
|
@ -18,9 +22,27 @@ function List(props){
|
|||
const [ search , setSearch ] = useState(undefined);
|
||||
const [ page , setPage ] = useState(1);
|
||||
const [ sortBy , setSortBy ] = useState("updated_on");
|
||||
const [ organizeDetail , setOrganizeDetail ] = useState(undefined);
|
||||
const [ mode , setMode ] = useState("overview");
|
||||
|
||||
const OIdentifier = props.match.params.OIdentifier;
|
||||
const organizeDetail = props.organizeDetail;
|
||||
const { current_user } = props;
|
||||
console.log(props);
|
||||
|
||||
useEffect(()=>{
|
||||
if(OIdentifier){
|
||||
getDetail(OIdentifier);
|
||||
}
|
||||
},[OIdentifier]);
|
||||
|
||||
function getDetail(id) {
|
||||
const url = `/organizations/${id}.json`;
|
||||
axios.get(url).then(result=>{
|
||||
if(result && result.data){
|
||||
setOrganizeDetail(result.data);
|
||||
}
|
||||
}).catch(error=>{})
|
||||
}
|
||||
|
||||
useEffect(()=>{
|
||||
if(organizeDetail){
|
||||
|
|
@ -31,11 +53,11 @@ function List(props){
|
|||
},[organizeDetail])
|
||||
|
||||
useEffect(()=>{
|
||||
if(OIdentifier){
|
||||
if(OIdentifier && mode==="subject"){
|
||||
setIsSpin(true);
|
||||
getProject();
|
||||
}
|
||||
},[OIdentifier,sortBy,page,search])
|
||||
},[OIdentifier,sortBy,page,search,mode])
|
||||
|
||||
function getProject(){
|
||||
const url = `/organizations/${OIdentifier}/projects.json`;
|
||||
|
|
@ -76,55 +98,136 @@ function List(props){
|
|||
</li>
|
||||
</ul>
|
||||
)
|
||||
|
||||
function changeRadio(e){
|
||||
setMode(e.target.value);
|
||||
}
|
||||
|
||||
|
||||
return(
|
||||
<div className="list">
|
||||
<div className="list-l">
|
||||
<div>
|
||||
<div className="head">
|
||||
<div style={{width:"370px"}}>
|
||||
<Search placeholder="输入仓库名称进行搜索" onSearch={onSearch}/>
|
||||
</div>
|
||||
<p>
|
||||
{ organizeDetail && organizeDetail.can_create_project ?
|
||||
<Sort menu={menu_new} overlayClassName={"newPopUl"}>
|
||||
<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>
|
||||
organizeDetail ?
|
||||
<div className="content-orz">
|
||||
<div className="top-orz">
|
||||
<div className="box">
|
||||
<img src={getImageUrl(organizeDetail && organizeDetail.avatar_url)} alt=""/>
|
||||
<div className="info-orz">
|
||||
<p className="orz-main">
|
||||
<span className="orz-name">{organizeDetail && organizeDetail.nickname}</span>
|
||||
{organizeDetail && organizeDetail.is_admin ?
|
||||
<Link to={`/${OIdentifier}/setting`} className="color-blue ml10 font-14 df"><i className="iconfont icon-shezhi2"></i>设置</Link>
|
||||
:""}
|
||||
</p>
|
||||
<div className="orz-desc task-hide-2">{organizeDetail && organizeDetail.description}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="list">
|
||||
<div className="list-l">
|
||||
{
|
||||
totalCount > limit &&
|
||||
<div className="mb20 mt20" style={{textAlign:"center"}}>
|
||||
<Pagination simple current={page} total={totalCount} pageSize={limit} onChange={(page)=>setPage(page)}/>
|
||||
organizeDetail.news_title &&
|
||||
<div className="teamnewstatus">
|
||||
<p className="teamname"><i className="iconfont icon-dongtaiicon1" /><span>新闻动态</span></p>
|
||||
<p className="teamtitle">
|
||||
{organizeDetail.news_title}
|
||||
</p>
|
||||
<div className="teamdesc">
|
||||
{organizeDetail.news_content}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div className="sepment" onChange={changeRadio} >
|
||||
<Radio.Group size="large" value={mode}>
|
||||
<Radio.Button value="overview" style={{width:"130px"}}>概览</Radio.Button>
|
||||
<Radio.Button value="subject" style={{width:"130px"}}>仓库</Radio.Button>
|
||||
</Radio.Group>
|
||||
</div>
|
||||
{
|
||||
mode === "overview" &&
|
||||
<div className="overviewcontent">
|
||||
<ConcentrateProject
|
||||
{...props}
|
||||
title={
|
||||
<p className="names">
|
||||
<i className="iconfont icon-jingxuanxiangmu font-17 mr8"></i>
|
||||
<span className="font-17">精选项目</span>
|
||||
</p>
|
||||
}
|
||||
btn={
|
||||
<span><i className="iconfont icon-zidingyi font-14 mr5"></i>自定义</span>
|
||||
}
|
||||
emptyContent={
|
||||
<img src={EmptyImg} width="325px" alt=""/>
|
||||
}
|
||||
typeFlag={true}
|
||||
userLogin={OIdentifier}
|
||||
type="organizations"
|
||||
current={organizeDetail.is_admin}
|
||||
/>
|
||||
{
|
||||
organizeDetail.memo &&
|
||||
<div>
|
||||
<p className="mt30 mb10">
|
||||
<i className="iconfont icon-zuzhijieshao mr4"></i>
|
||||
<span className="font-17">组织介绍</span>
|
||||
</p>
|
||||
<RenderHtml className="break_word_comments imageLayerParent" value={organizeDetail.memo} url={props.history.location}/>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
{
|
||||
mode === "subject" &&
|
||||
<div>
|
||||
<div>
|
||||
<div className="head">
|
||||
<div style={{width:"370px"}}>
|
||||
<Search placeholder="输入仓库名称进行搜索" onSearch={onSearch}/>
|
||||
</div>
|
||||
<p>
|
||||
{ organizeDetail && organizeDetail.can_create_project ?
|
||||
<Sort menu={menu_new} overlayClassName={"newPopUl"}>
|
||||
<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>
|
||||
{
|
||||
totalCount > limit &&
|
||||
<div className="mb20 mt20" style={{textAlign:"center"}}>
|
||||
<Pagination simple current={page} total={totalCount} pageSize={limit} onChange={(page)=>setPage(page)}/>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
</div>
|
||||
<Right
|
||||
admin={organizeDetail && organizeDetail.is_admin}
|
||||
OIdentifier={OIdentifier}
|
||||
showCompeleteDialog={props.showCompeleteDialog}
|
||||
completeProfile={props.completeProfile}
|
||||
history={props.history}
|
||||
/>
|
||||
<Right
|
||||
admin={organizeDetail && organizeDetail.is_admin}
|
||||
OIdentifier={OIdentifier}
|
||||
showCompeleteDialog={props.showCompeleteDialog}
|
||||
completeProfile={props.completeProfile}
|
||||
history={props.history}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
:""
|
||||
)
|
||||
}
|
||||
export default List;
|
||||
|
|
@ -5,28 +5,32 @@ import axios from 'axios';
|
|||
import { getImageUrl } from 'educoder';
|
||||
import { Link } from 'react-router-dom';
|
||||
import Nodata from '../Nodata';
|
||||
import { Progress } from 'antd';
|
||||
import Right from './images/right.png';
|
||||
|
||||
import CheckProfile from '../Component/ProfileModal/Profile';
|
||||
|
||||
const Span = styled.span`{
|
||||
color:#888;
|
||||
font-size:12px;
|
||||
font-size:14px;
|
||||
margin-right:10px;
|
||||
height:20px;
|
||||
line-height:20px;
|
||||
}`
|
||||
const Align = styled.div`{
|
||||
display:flex;
|
||||
aligin:center;
|
||||
}`
|
||||
const ListName = styled.div`{
|
||||
font-size:14px;
|
||||
font-size:15px;
|
||||
color:#333;
|
||||
margin-bottom:8px;
|
||||
height:18px;
|
||||
line-height:18px;
|
||||
}`;
|
||||
const ColorListName = styled.div`{
|
||||
color:#5091FF;
|
||||
font-size:14px;
|
||||
color:rgba(31, 35, 41, 1);
|
||||
font-size:15px;
|
||||
margin-bottom:8px;
|
||||
height:18px;
|
||||
line-height:18px;
|
||||
|
|
@ -38,6 +42,7 @@ const Img = styled.img`{
|
|||
margin-right:12px;
|
||||
}`
|
||||
function RightBox({ OIdentifier , history , admin , showCompeleteDialog ,completeProfile }) {
|
||||
const [ languageData, setLanguageData ] = useState(undefined);
|
||||
const [ memberData, setMemberData ] = useState(undefined);
|
||||
const [ groupData, setGroupData ] = useState(undefined);
|
||||
|
||||
|
|
@ -45,8 +50,32 @@ function RightBox({ OIdentifier , history , admin , showCompeleteDialog ,complet
|
|||
if(OIdentifier){
|
||||
getMember(OIdentifier);
|
||||
getGroup(OIdentifier);
|
||||
getLanguage(OIdentifier);
|
||||
}
|
||||
},[OIdentifier])
|
||||
function getLanguage(iden){
|
||||
const url = `/organizations/${iden}/languages.json`;
|
||||
axios.get(url,{params:{limit:10}}).then(result=>{
|
||||
if(result && result.data){
|
||||
let languages = result.data;
|
||||
let arr = [];
|
||||
Object.keys(languages).map((item,key)=>{
|
||||
arr.push({name:item,percent:languages[item].replace("%",""),color:getColor()});
|
||||
})
|
||||
setLanguageData(arr);
|
||||
console.log(arr);
|
||||
}
|
||||
}).catch(error=>{})
|
||||
}
|
||||
function getColor(){
|
||||
let str = "#";
|
||||
let arr = ["1","2","3","4","4","5","6","7","8","9","a","b","c","d","e","f"];
|
||||
for(var i=0;i<6;i++){
|
||||
let num = parseInt(Math.random() * 16);
|
||||
str+=arr[num];
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
function getMember(iden){
|
||||
const url = `/organizations/${iden}/organization_users.json`;
|
||||
|
|
@ -66,17 +95,43 @@ function RightBox({ OIdentifier , history , admin , showCompeleteDialog ,complet
|
|||
}
|
||||
return(
|
||||
<div className="list-r">
|
||||
{
|
||||
languageData && languageData.length>0 ?
|
||||
<Box
|
||||
name="仓库语言"
|
||||
// count={languageData && languageData.length}
|
||||
icon={<i className="iconfont icon-cangkuyuyanicon font-17 mr8"></i>}
|
||||
// url={`/${OIdentifier}/members`}
|
||||
>
|
||||
{
|
||||
languageData.map((item,key)=>{
|
||||
return(
|
||||
<div className="progress">
|
||||
<span className="mr10">{item.name}</span>
|
||||
<Progress percent={item.percent} strokeColor={item.color}/>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
</Box>
|
||||
:""
|
||||
}
|
||||
{
|
||||
memberData && memberData.organization_users && memberData.organization_users.length>0 ?
|
||||
<Box name="组织成员" count={memberData && memberData.total_count} url={`/${OIdentifier}/members`}>
|
||||
<Box
|
||||
name="组织成员"
|
||||
count={memberData && memberData.total_count}
|
||||
icon={<i className="iconfont icon-zuzhichengyuan1 font-16 mr8"></i>}
|
||||
url={`/${OIdentifier}/members`}>
|
||||
{
|
||||
memberData.organization_users.map((item,key)=>{
|
||||
return(
|
||||
<div className="teammembers" key={key}>
|
||||
key<5 && <div className="teammembers" key={key}>
|
||||
<Link to={`/${item.user && item.user.login}`}><Img src={getImageUrl(`/${item.user && item.user.image_url}`)} alt="" className="m-img"/></Link>
|
||||
<div>
|
||||
<Link to={`/${item.user && item.user.login}`}><ListName>{item.user && item.user.name}</ListName></Link>
|
||||
<Align><i className="iconfont icon-shijian color-green mr3 font-13"></i><Span>加入时间:{item.created_at}</Span></Align>
|
||||
<Align><Span>加入时间:{item.created_at}</Span></Align>
|
||||
{/* <i className="iconfont icon-shijian color-green mr3 font-13"></i> */}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
|
@ -88,14 +143,15 @@ function RightBox({ OIdentifier , history , admin , showCompeleteDialog ,complet
|
|||
<Box
|
||||
name="组织团队"
|
||||
count={groupData && groupData.total_count}
|
||||
icon={<i className="iconfont icon-zuzhituandui font-17 mr8"></i>}
|
||||
bottom={
|
||||
admin &&
|
||||
<CheckProfile
|
||||
showCompeleteDialog={showCompeleteDialog}
|
||||
completeProfile={completeProfile}
|
||||
sureFunc={()=>history.push(`/${OIdentifier}/teams/new`)}
|
||||
className={"ant-btn ant-btn-primary"}
|
||||
>新建团队</CheckProfile>
|
||||
className={"ant-btn newBtn"}
|
||||
>新建团队<img src={Right} alt="" width="9" className="ml5" /></CheckProfile>
|
||||
}
|
||||
url={`/${OIdentifier}/teams`}
|
||||
>
|
||||
|
|
@ -104,7 +160,8 @@ function RightBox({ OIdentifier , history , admin , showCompeleteDialog ,complet
|
|||
<React.Fragment>
|
||||
{groupData.teams.map((item,key)=>{
|
||||
return(
|
||||
<div className="teammembers" key={key}>
|
||||
key < 5 &&<div className="teammembers" key={key}>
|
||||
<span className="memberIndex">{key+1}</span>
|
||||
<div>
|
||||
{
|
||||
(item.is_admin || item.is_member) ?
|
||||
|
|
@ -113,8 +170,8 @@ function RightBox({ OIdentifier , history , admin , showCompeleteDialog ,complet
|
|||
<ColorListName>{item.name}</ColorListName>
|
||||
}
|
||||
<Align>
|
||||
<Span>{item.num_users}名成员</Span>
|
||||
<Span>{item.num_projects}个仓库</Span>
|
||||
<Span><span style={{color:"rgba(31, 35, 41, 1)"}}>{item.num_users}</span>名成员</Span>
|
||||
<Span><span style={{color:"rgba(31, 35, 41, 1)"}}>{item.num_projects}</span>个仓库</Span>
|
||||
</Align>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -16,6 +16,10 @@ const Member = Loadable({
|
|||
loader: () => import("./TeamSettingMember"),
|
||||
loading: Loading,
|
||||
});
|
||||
const Index = Loadable({
|
||||
loader: () => import("./TeamSettingPage"),
|
||||
loading: Loading,
|
||||
});
|
||||
const Common = Loadable({
|
||||
loader: () => import("./TeamSettingCommon"),
|
||||
loading: Loading,
|
||||
|
|
@ -39,17 +43,20 @@ export default (( props )=>{
|
|||
function returnActive (pathname){
|
||||
let a = 0;
|
||||
if(pathname === `/${OIdentifier}/setting/member`){
|
||||
a = 2;
|
||||
}else if(pathname === `/${OIdentifier}/setting/index`){
|
||||
a = 1;
|
||||
}else if(pathname === `/${OIdentifier}/setting/group`){
|
||||
a = 2;
|
||||
}else if(pathname === `/${OIdentifier}/setting/hooks`){
|
||||
a = 3;
|
||||
}else if(pathname === `/${OIdentifier}/setting/hooks`){
|
||||
a = 4;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
const active = returnActive(pathname);
|
||||
const array = {list:[
|
||||
{name:'基本设置',icon:"icon-base",href:`/${OIdentifier}/setting`},
|
||||
{name:'组织首页管理',icon:"icon-huabanfuben",href:`/${OIdentifier}/setting/index`},
|
||||
{name:'组织成员管理',icon:"icon-zuzhichengyuan",href:`/${OIdentifier}/setting/member`},
|
||||
{name:'组织团队管理',icon:"icon-zuzhixiangmu",href:`/${OIdentifier}/setting/group`},
|
||||
// {name:'管理web钩子',icon:"icon-zhongqingdianxinicon10",href:`/${OIdentifier}/setting/hooks`}
|
||||
|
|
@ -71,6 +78,12 @@ export default (( props )=>{
|
|||
<Hooks {...props} />
|
||||
)}
|
||||
></Route>
|
||||
<Route
|
||||
path="/:OIdentifier/setting/index"
|
||||
render={() => (
|
||||
<Index {...props} />
|
||||
)}
|
||||
></Route>
|
||||
<Route
|
||||
path="/:OIdentifier/setting/group"
|
||||
render={() => (
|
||||
|
|
|
|||
|
|
@ -0,0 +1,97 @@
|
|||
import React, { useEffect, useState , forwardRef } from 'react';
|
||||
import { Button, Form , Input } from 'antd';
|
||||
import Title from '../../Component/Title';
|
||||
import MDEditor from "../../../modules/tpm/challengesnew/tpm-md-editor";
|
||||
import UploadImage from '../Component/UploadImage';
|
||||
import {getImageUrl } from 'educoder';
|
||||
import axios from 'axios';
|
||||
|
||||
export default Form.create()(forwardRef((props)=>{
|
||||
const { form , organizeDetail } = props;
|
||||
const OIdentifier = props.match.params.OIdentifier;
|
||||
const { getFieldDecorator , validateFields , setFieldsValue , getFieldsValue} = form;
|
||||
const [ content , setContent ] = useState("");
|
||||
const [ imageUrl , setImageUrl ] = useState("");
|
||||
const [ imageId , setImageId ] = useState(undefined);
|
||||
|
||||
// useEffect(()=>{
|
||||
// let url = imageId ? getImageUrl(`/api/attachments/${imageId}`) :"";
|
||||
// setImageUrl(url);
|
||||
// },[imageId])
|
||||
|
||||
useEffect(()=>{
|
||||
if(organizeDetail){
|
||||
setContent(organizeDetail.memo);
|
||||
setFieldsValue({
|
||||
...organizeDetail
|
||||
})
|
||||
setImageId(organizeDetail.news_banner_id);
|
||||
}
|
||||
},[organizeDetail])
|
||||
|
||||
|
||||
function onChangeDesc(v){
|
||||
setContent(v);
|
||||
}
|
||||
|
||||
function save(){
|
||||
validateFields((error,values)=>{
|
||||
if(!error){
|
||||
const url = `/organizations/${OIdentifier}/update_other.json`;
|
||||
axios.post(url,{
|
||||
...values,
|
||||
memo:content,
|
||||
// news_banner_id:imageId
|
||||
}).then(result=>{
|
||||
if(result){
|
||||
props.showNotification("组织首页更新成功!");
|
||||
}
|
||||
}).catch(error=>{})
|
||||
}
|
||||
})
|
||||
}
|
||||
return(
|
||||
<div>
|
||||
<Title>
|
||||
<span>组织首页管理</span>
|
||||
</Title>
|
||||
|
||||
<Form style={{padding:"20px 30px 30px 30px"}}>
|
||||
{/* <p>新闻动态图片</p>
|
||||
<UploadImage url={imageUrl} getImageId={(id)=>{setImageId(id);}}/>
|
||||
<p><a className="color-blue" onClick={()=>setImageId("")}>删除</a></p> */}
|
||||
<Form.Item label="新闻动态原文链接">
|
||||
{getFieldDecorator("news_url",{
|
||||
rules:[]
|
||||
})(
|
||||
<Input placeholder="请输入新闻动态原文链接" maxLength={50}/>
|
||||
)}
|
||||
</Form.Item>
|
||||
<Form.Item label="新闻动态标题">
|
||||
{getFieldDecorator("news_title",{
|
||||
rules:[]
|
||||
})(
|
||||
<Input placeholder="请输入新闻动态标题" maxLength={45}/>
|
||||
)}
|
||||
</Form.Item>
|
||||
<Form.Item label="新闻动态内容">
|
||||
{getFieldDecorator("news_content",{
|
||||
rules:[]
|
||||
})(
|
||||
<Input placeholder="请输入新闻动态内容" maxLength={200}/>
|
||||
)}
|
||||
</Form.Item>
|
||||
<p class="mt30">组织介绍</p>
|
||||
<MDEditor
|
||||
placeholder={"请输入组织介绍"}
|
||||
height={300}
|
||||
mdID={"teamdescription"}
|
||||
initValue={content}
|
||||
onChange={onChangeDesc}
|
||||
></MDEditor>
|
||||
<Button type="primary" onClick={save}>确定</Button>
|
||||
</Form>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
)
|
||||
|
After Width: | Height: | Size: 125 KiB |
|
After Width: | Height: | Size: 736 B |
|
|
@ -89,6 +89,8 @@ class Index extends Component {
|
|||
return item.response && item.status==="done" && array.push((item.response.id || (item.response.data && item.response.data.id)));
|
||||
})
|
||||
array && array.length>0 && this.props.load(array);
|
||||
}else{
|
||||
this.props.load([]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ class Read extends Component {
|
|||
fileContent: undefined,
|
||||
fileName: undefined,
|
||||
});
|
||||
const { load } = this.props;
|
||||
load && load();
|
||||
};
|
||||
|
||||
beforeUpload = (file) => {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import CheckProfile from '../../Component/ProfileModal/Profile';
|
|||
|
||||
const { Search } = Input;
|
||||
const limit = 20;
|
||||
function ConcentrateBox({ visible , onCancel , onSure , username , choosed , history , showCompeleteDialog , completeProfile }) {
|
||||
function ConcentrateBox({ visible , onCancel , onSure , type , username , choosed , history , showCompeleteDialog , completeProfile }) {
|
||||
const [ page , setPage ]= useState(1);
|
||||
const [ total , setTotal ]= useState(0);
|
||||
const [ pageSize , setPageSize ] = useState(false);
|
||||
|
|
@ -54,7 +54,7 @@ function ConcentrateBox({ visible , onCancel , onSure , username , choosed , his
|
|||
},[value])
|
||||
|
||||
function getProjectList(p,s) {
|
||||
const url = `/users/${username}/projects.json`;
|
||||
const url = `/${type || `users`}/${username}/projects.json`;
|
||||
Axios.get(url,{
|
||||
params:{
|
||||
page:p,limit,is_public: "public",search:s,choosed
|
||||
|
|
@ -147,12 +147,12 @@ function ConcentrateBox({ visible , onCancel , onSure , username , choosed , his
|
|||
onChange={(e)=>setSearch(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="listbox">
|
||||
<Checkbox.Group value={value} onChange={chooseProject} style={{width:"100%"}}>
|
||||
<div className="conbox">
|
||||
<Checkbox.Group value={value} onChange={chooseProject}>
|
||||
{
|
||||
copyList && copyList.length >0 && copyList.map((i,k)=>{
|
||||
return(
|
||||
<Checkbox value={i.id} disabled={disable && (value.filter(j=>j === i.id).length===0)}>{i.author && i.author.name}/{i.name}</Checkbox>
|
||||
<Checkbox value={i.id} disabled={disable && (value.filter(j=>j === i.id).length===0)}>{i.author && `${i.author.name}/`}{i.name}</Checkbox>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
|
@ -160,7 +160,7 @@ function ConcentrateBox({ visible , onCancel , onSure , username , choosed , his
|
|||
list && list.length > 0 && list.map((i,k)=>{
|
||||
let c = copyList && copyList.length >0 && copyList.filter(j=>j.id === i.id).length !== 0;
|
||||
return(
|
||||
!c && <Checkbox value={i.id} disabled={disable && (value.filter(j=>j === i.id).length===0)}>{i.author && i.author.name}/{i.name}</Checkbox>
|
||||
!c && <Checkbox value={i.id} disabled={disable && (value.filter(j=>j === i.id).length===0)}>{i.author && `${i.author.name}/`}{i.name}</Checkbox>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
|
@ -173,7 +173,7 @@ function ConcentrateBox({ visible , onCancel , onSure , username , choosed , his
|
|||
<CheckProfile
|
||||
showCompeleteDialog={showCompeleteDialog}
|
||||
completeProfile={completeProfile}
|
||||
sureFunc={()=>{history.push(`/projects/deposit/new`)}}
|
||||
sureFunc={()=>{history.push(`/projects/deposit/new${type ? `/${username}`:""}`)}}
|
||||
className="color-blue">新建项目</CheckProfile>
|
||||
</div>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,20 @@ import { FlexAJ , AlignCenter } from '../../Component/layout';
|
|||
import { Link } from 'react-router-dom';
|
||||
import axios from 'axios';
|
||||
import Box from './ConcentrateBox';
|
||||
import './Index.scss';
|
||||
|
||||
function ConcentrateProject({userLogin,current,showCompeleteDialog,completeProfile,history}) {
|
||||
function ConcentrateProject({
|
||||
userLogin,
|
||||
current,
|
||||
showCompeleteDialog,
|
||||
completeProfile,
|
||||
history,
|
||||
type,
|
||||
title,
|
||||
typeFlag,
|
||||
btn,
|
||||
emptyContent
|
||||
}) {
|
||||
const [ list , setList ] = useState(undefined);
|
||||
const [ visible , setVisible ] = useState(false);
|
||||
const [ value , setValue ] = useState([]);
|
||||
|
|
@ -14,7 +26,7 @@ function ConcentrateProject({userLogin,current,showCompeleteDialog,completeProfi
|
|||
},[])
|
||||
|
||||
function getList() {
|
||||
const url = `/users/${userLogin}/is_pinned_projects.json`;
|
||||
const url = `/${type || `users`}/${userLogin}/is_pinned_projects.json`;
|
||||
axios.get(url).then(result=>{
|
||||
if(result && result.data){
|
||||
let p = result.data.projects;
|
||||
|
|
@ -33,7 +45,7 @@ function ConcentrateProject({userLogin,current,showCompeleteDialog,completeProfi
|
|||
if(is_pinned_project_ids && is_pinned_project_ids.length===0){
|
||||
setValue([]);
|
||||
}
|
||||
const url = `/users/${userLogin}/is_pinned_projects/pin.json`;
|
||||
const url = `/${type || `users`}/${userLogin}/is_pinned_projects/pin.json`;
|
||||
axios.post(url,{
|
||||
is_pinned_project_ids
|
||||
}).then(result=>{
|
||||
|
|
@ -54,29 +66,36 @@ function ConcentrateProject({userLogin,current,showCompeleteDialog,completeProfi
|
|||
completeProfile={completeProfile}
|
||||
showCompeleteDialog={showCompeleteDialog}
|
||||
history={history}
|
||||
type={type}
|
||||
/>
|
||||
{
|
||||
list && list.length>0 &&
|
||||
<div className="concentrate">
|
||||
<FlexAJ>
|
||||
<span className="font-18">精选项目</span>
|
||||
{ current && <a className="color-blue" onClick={()=>setVisible(true)}>自定义精选项目</a> }
|
||||
{
|
||||
title || <span className="font-18">精选项目</span>
|
||||
}
|
||||
{ (current && ((btn && list && list.length > 0) || !btn)) &&
|
||||
<a className="color-blue" onClick={()=>setVisible(true)}>
|
||||
{btn || "自定义精选项目"}
|
||||
</a>
|
||||
}
|
||||
</FlexAJ>
|
||||
{
|
||||
list && list.length>0 &&
|
||||
<div>
|
||||
<ul className="concentrateUl">
|
||||
{
|
||||
list.map((i,k)=>{
|
||||
return(
|
||||
<li key={i.id}>
|
||||
<Link to={`/${i.author && i.author.login}/${i.identifier}`} className="name">{i.name}</Link>
|
||||
<Link to={`/${i.author && i.author.login}/${i.identifier}`} className="name task-hide">{i.name}</Link>
|
||||
<p className="task-hide desc">{i.description}</p>
|
||||
{/* 项目标签 */}
|
||||
{i.topics && <div className='viewProListTopics'>
|
||||
{i.topics && <div className='viewProListTopics mt10'>
|
||||
{i.topics.map(item=><Link to={`/explore/topic/${item.id}/${encodeURIComponent(item.name)}`} className='viewProListTopic mr15 font-13 task-hide'>{item.name}</Link>)}
|
||||
</div>}
|
||||
<AlignCenter>
|
||||
{ i.category && <span className="tagName">{i.category.name}</span> }
|
||||
<span className="pariseCount"><i className="iconfont icon-xingzhuang"></i>{i.watchers_count}</span>
|
||||
{ i.category && !typeFlag && <span className="tagName">{i.category.name}</span> }
|
||||
<span className="pariseCount ml2"><i className="iconfont icon-xingzhuang"></i>{i.watchers_count}</span>
|
||||
<span className="forkCount"><i className="iconfont icon-morenfuke_icon1"></i>{i.forked_count}</span>
|
||||
</AlignCenter>
|
||||
</li>
|
||||
|
|
@ -85,10 +104,22 @@ function ConcentrateProject({userLogin,current,showCompeleteDialog,completeProfi
|
|||
}
|
||||
</ul>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
{
|
||||
(!emptyContent && list && list.length === 0 && current) &&
|
||||
<div className="ConcentrateTip">
|
||||
<i className="iconfont icon-tishi2"></i>
|
||||
你还没有设置精选项目,<a onClick={()=>setVisible(true)}>点击设置</a>
|
||||
</div>
|
||||
}
|
||||
{
|
||||
list && list.length === 0 && current && <div className="ConcentrateTip"><i className="iconfont icon-tishi2"></i>你还没有设置精选项目,<a onClick={()=>setVisible(true)}>点击设置</a></div>
|
||||
emptyContent && list && list.length === 0 ?
|
||||
<div className="ConcentrateTipImg">
|
||||
{emptyContent}
|
||||
<span className="font-15">暂无数据{current && <span>,<a className="color-blue" onClick={()=>setVisible(true)}>点击设置</a></span>}</span>
|
||||
</div>
|
||||
:""
|
||||
}
|
||||
</React.Fragment>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -18,14 +18,16 @@
|
|||
}
|
||||
.name{
|
||||
font-size: 16px;
|
||||
// color: #4CACFF;
|
||||
color: $primary-color;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
&:hover{
|
||||
color: $primary-color-hover;
|
||||
}
|
||||
}
|
||||
.desc{
|
||||
color: #999;
|
||||
line-height: 21px;
|
||||
}
|
||||
.tagName{
|
||||
display: block;
|
||||
|
|
@ -36,6 +38,7 @@
|
|||
height: 22px;
|
||||
line-height: 22px;
|
||||
font-size: 13px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
.pariseCount,.forkCount{
|
||||
i{
|
||||
|
|
@ -43,7 +46,7 @@
|
|||
margin-right: 4px;
|
||||
}
|
||||
color: #999;
|
||||
margin-left: 20px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -71,10 +74,27 @@
|
|||
padding:0px;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
.listbox{
|
||||
.conbox{
|
||||
max-height: 210px;
|
||||
overflow-y: auto;
|
||||
padding-left: 30px;
|
||||
.ant-checkbox-group{
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
width: 100%;
|
||||
.ant-checkbox-wrapper{
|
||||
width: 48%;
|
||||
margin-left: 0px!important;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
span:last-child{
|
||||
flex:1;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.operateDiv{
|
||||
padding:20px 30px
|
||||
|
|
@ -84,24 +104,6 @@
|
|||
padding-top:15px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.ant-checkbox-group{
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
.ant-checkbox-wrapper{
|
||||
width: 50%;
|
||||
margin-left: 0px!important;
|
||||
display: flex;
|
||||
.ant-checkbox{
|
||||
padding-top: 3px;
|
||||
}
|
||||
span:last-child{
|
||||
flex:1;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.recentStatic{
|
||||
padding: 30px 0px;
|
||||
|
|
@ -152,13 +154,13 @@
|
|||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
.viewProListTopic{
|
||||
background-color:#f3f8ff;
|
||||
background-color:rgba(70, 106, 255, 0.12);
|
||||
border-radius: 4px;
|
||||
max-width: 158px;
|
||||
padding: 0 10px;
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
color: #4c5b76;
|
||||
color:#466aff;
|
||||
margin-bottom: 5px !important;
|
||||
}
|
||||
}
|
||||
|
|
@ -34,7 +34,7 @@ $primary-color:#466aff;
|
|||
text-align: center;
|
||||
}
|
||||
}
|
||||
.contentBox{
|
||||
.contentForm{
|
||||
padding:20px 20px 0px 20px;
|
||||
& > div{
|
||||
margin-bottom: 20px;
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ export default Form.create()(
|
|||
</Form.Item>
|
||||
<Form.Item label="昵称">
|
||||
{getFieldDecorator("nickname",{
|
||||
rules:[{required:true,message:"请输入昵称"}]
|
||||
rules:[]
|
||||
})(
|
||||
<Input placeholder="请输入您的昵称" maxLength={20} style={{width:"400px"}}/>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ function Team(props){
|
|||
</div>
|
||||
{
|
||||
list && list.length > 0 ?
|
||||
<div className="contentBox">
|
||||
<div className="contentForm">
|
||||
{
|
||||
list.map((item,key)=>{
|
||||
return(
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import fetch from './fetch';
|
||||
|
||||
// 获取当前用户项目报名信息
|
||||
// 获取当前用户项目报名信息(项目、课题)
|
||||
export function getUserApplyInfo(params) {
|
||||
return fetch({
|
||||
url: `/api/applyInformation/getUserApplyInfo`,
|
||||
|
|
@ -9,7 +9,7 @@ export function getUserApplyInfo(params) {
|
|||
});
|
||||
}
|
||||
|
||||
//报名夏令营
|
||||
//报名夏令营(项目、课题报名)
|
||||
export function applyGlcc(data) {
|
||||
return fetch({
|
||||
url: '/api/applyInformation/create',
|
||||
|
|
@ -18,6 +18,15 @@ export function applyGlcc(data) {
|
|||
});
|
||||
}
|
||||
|
||||
// 修改报名信息
|
||||
export function updateApplyGlcc(data) {
|
||||
return fetch({
|
||||
url: '/api/applyInformation/update',
|
||||
method: 'post',
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
//提交报名信息(学生)
|
||||
export function studentApply(data) {
|
||||
return fetch({
|
||||
|
|
@ -36,8 +45,7 @@ export function studentApplyEdit(data) {
|
|||
});
|
||||
}
|
||||
|
||||
// 获取当前学生用户报名信息
|
||||
// 课题列表
|
||||
// 项目列表
|
||||
export function projectList(params) {
|
||||
return fetch({
|
||||
url: `/api/applyInformation/list`,
|
||||
|
|
@ -46,6 +54,15 @@ export function projectList(params) {
|
|||
});
|
||||
}
|
||||
|
||||
// 0元项目列表
|
||||
export function freeProjectList(params) {
|
||||
return fetch({
|
||||
url: `/api/applyInformation/projectListFor0`,
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
}
|
||||
|
||||
// 课题列表
|
||||
export function taskList(params) {
|
||||
return fetch({
|
||||
|
|
@ -55,11 +72,21 @@ export function taskList(params) {
|
|||
});
|
||||
}
|
||||
|
||||
// 0元课题列表
|
||||
export function freeTaskList(params) {
|
||||
return fetch({
|
||||
url: `/api/applyInformation/taskListFor0`,
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
}
|
||||
|
||||
// 项目id查询项目详情
|
||||
export function getProjectById(id) {
|
||||
export function getProjectById(id, params) {
|
||||
return fetch({
|
||||
url: `/api/applyInformation/${id}`,
|
||||
method: 'get'
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -194,4 +221,31 @@ export function getMediumTermExamineInfoList(params) {
|
|||
method: 'get',
|
||||
params,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 查看GLCC配置信息列表
|
||||
export function getGlccSettings(params) {
|
||||
return fetch({
|
||||
url: `/api/glccSettings/settingList`,
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
// 删除项目报名信息
|
||||
export function deleteApplyInfo(data) {
|
||||
return fetch({
|
||||
url: `/api/applyInformation/delete`,
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
// 判断课题是否有学生报名
|
||||
export async function findStudentTaskByTaskId(params) {
|
||||
return await fetch({
|
||||
url: '/api/applyInformation/findStudentTaskByTaskId',
|
||||
method: 'get',
|
||||
params: params,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,298 @@
|
|||
import React , { useCallback, useEffect , useState } from 'react';
|
||||
import { Button, Form, Input, Select, Upload, message, Popconfirm } from 'antd';
|
||||
import {getUploadActionUrl} from 'educoder';
|
||||
import {applyGlcc, findStudentTaskByTaskId, updateApplyGlcc} from '../api';
|
||||
import TextArea from 'antd/lib/input/TextArea';
|
||||
import { main_site_url } from '../fetch';
|
||||
import TaskApply from './taskApply';
|
||||
import './index.scss';
|
||||
import { FlexAJ } from '../../forge/Component/layout';
|
||||
const Option = Select.Option;
|
||||
// 编辑项目、课题报名信息
|
||||
function EditRepoApplyInfo(props) {
|
||||
const {form, applyInfo, current_user, round, cateList, setReload, isAddRepo, setIsAddRepo, setIsEdit, setEditRepoCount} = props;
|
||||
const phonereg = /(^|\s*\+?0?0?86|\D)(1\d{2})[-\s]{0,3}(\d{4})[-\s]{0,3}(\d{4})(?=\D|$)/
|
||||
const emailreg = /^[a-zA-Z0-9]+([.\-_\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/
|
||||
const {getFieldDecorator, validateFields, setFieldsValue, validateFieldsAndScroll, getFieldValue } = form;
|
||||
const [imageUrl, setImageUrl] = useState(undefined);
|
||||
// 提交按钮loading效果
|
||||
const [loading, setLoading] = useState(false);
|
||||
// 课题报名个数
|
||||
const [taskCount, setTaskCount] = useState(undefined);
|
||||
|
||||
useEffect(()=>{
|
||||
if(applyInfo){
|
||||
const {projectName, projectType, gitlinkUrl, contactName, contactPhone, projectIntro, registrationTaskList, projectLogoId, contactMail} = applyInfo;
|
||||
const taskInfo = {};
|
||||
const taskCountArr = []
|
||||
registrationTaskList.map((item, index)=>{
|
||||
taskCountArr.push(index+1);
|
||||
const{taskName, taskUrl, taskDifficulty, taskReward, tutorName, tutorMail, taskDesc, tutorPhone, id} = item;
|
||||
taskInfo[`taskName${index+1}`] = taskName;
|
||||
taskInfo[`taskUrl${index+1}`] = taskUrl;
|
||||
taskInfo[`taskDifficulty${index+1}`] = taskDifficulty;
|
||||
taskInfo[`taskReward${index+1}`] = taskReward;
|
||||
taskInfo[`tutorName${index+1}`] = tutorName;
|
||||
taskInfo[`tutorMail${index+1}`] = tutorMail;
|
||||
taskInfo[`taskDesc${index+1}`] = taskDesc;
|
||||
taskInfo[`tutorPhone${index+1}`] = tutorPhone;
|
||||
taskInfo[`taskId${index+1}`] = id;
|
||||
})
|
||||
setTaskCount(taskCountArr);
|
||||
setTimeout(() => {
|
||||
setFieldsValue({
|
||||
projectName, projectType, gitlinkUrl, contactName, contactPhone, projectIntro, contactMail,
|
||||
...taskInfo,
|
||||
logo: {file:{response:{id: projectLogoId}}}
|
||||
})
|
||||
}, 100);
|
||||
}else{
|
||||
setTaskCount([1])
|
||||
}
|
||||
}, [])
|
||||
|
||||
const helper = useCallback(
|
||||
(label, extra, name, rules, widget) => (
|
||||
<Form.Item label={label} extra={extra}>
|
||||
{getFieldDecorator(name, { rules, validateFirst: true })(widget)}
|
||||
</Form.Item>
|
||||
),
|
||||
[]
|
||||
);
|
||||
|
||||
// 当用户输入结束时 检验用户输入是否符合规范
|
||||
function verify(dataIndex){
|
||||
validateFields([dataIndex],(error, values)=>{
|
||||
if(error && error[dataIndex]){
|
||||
return;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 报名夏令营
|
||||
function handleSubmit(e){
|
||||
e.preventDefault();
|
||||
validateFieldsAndScroll((err, values) => {
|
||||
if (!err) {
|
||||
const registrationTaskList = []
|
||||
taskCount && taskCount.map(item=>{
|
||||
registrationTaskList.push({
|
||||
id: values[`taskId${item}`],
|
||||
taskName: values[`taskName${item}`],
|
||||
taskUrl: values[`taskUrl${item}`],
|
||||
taskDifficulty: values[`taskDifficulty${item}`],
|
||||
taskReward: values[`taskReward${item}`],
|
||||
tutorName: values[`tutorName${item}`],
|
||||
tutorMail: values[`tutorMail${item}`],
|
||||
taskDesc: values[`taskDesc${item}`],
|
||||
tutorPhone: values[`tutorPhone${item}`],
|
||||
round
|
||||
})
|
||||
})
|
||||
const {projectName, projectType, gitlinkUrl, contactName, contactPhone, projectIntro, contactMail} = values;
|
||||
const params ={
|
||||
projectName, projectType, gitlinkUrl, contactName, contactPhone, projectIntro, registrationTaskList, round, contactMail,
|
||||
projectLogoId: values.logo.file.response.id+"",
|
||||
userId: current_user.user_id,
|
||||
userName: current_user.username
|
||||
}
|
||||
setLoading(true);
|
||||
if(applyInfo){
|
||||
// 用户已经报名项目
|
||||
params[`id`] = applyInfo.id;
|
||||
updateApplyGlcc(params).then(response=>{
|
||||
if(response && response.message === "success"){
|
||||
message.success("修改成功");
|
||||
setReload();
|
||||
}
|
||||
setLoading(false);
|
||||
setIsEdit(false);
|
||||
setEditRepoCount(0);
|
||||
setTimeout(() => {
|
||||
scrollToRepoInfo()
|
||||
}, 100);
|
||||
})
|
||||
return
|
||||
}
|
||||
applyGlcc(params).then(response=>{
|
||||
if(response && response.message === "success"){
|
||||
message.success("报名成功");
|
||||
isAddRepo && setIsAddRepo(false);
|
||||
setReload();
|
||||
}
|
||||
setLoading(false);
|
||||
window.scrollTo(0,950);
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 检查文件上传是否符合规定
|
||||
function beforeUpload(file){
|
||||
const isLt100M = file.size / 1024 / 1024 < 20;
|
||||
if (!isLt100M) {
|
||||
message.error(`文件大小必须小于${20}M!`);
|
||||
}
|
||||
const isType = file.type === "image/png" || file.type === "image/jpg" || file.type === "image/jpeg";
|
||||
if (!isType) {
|
||||
message.error("只能上传png、jpg、jpeg格式文件");
|
||||
}
|
||||
return isLt100M && isType;
|
||||
}
|
||||
function getBase64(img, callback) {
|
||||
const reader = new FileReader();
|
||||
reader.addEventListener('load', () => callback(reader.result));
|
||||
reader.readAsDataURL(img);
|
||||
reader.onload = function(e) {
|
||||
setImageUrl(e.target.result); // 上传的图片的编码
|
||||
}
|
||||
}
|
||||
|
||||
// 上传完成后
|
||||
function handleChange(info){
|
||||
if(info && info.file && info.file.status === "done"){
|
||||
getBase64(info.file.originFileObj, imageUrl =>
|
||||
setImageUrl(imageUrl)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 添加课题输入框
|
||||
function addTaskApplyForm(){
|
||||
setTaskCount(taskCount.concat([taskCount[taskCount.length-1]+1]));
|
||||
}
|
||||
|
||||
// 删除课题报名
|
||||
async function deleteTaskApply(index){
|
||||
const delTaskId = getFieldValue(`taskId${index}`);
|
||||
const res = delTaskId ? await findStudentTaskByTaskId({ taskId: delTaskId }) : "newTask";
|
||||
if((res && res.data && res.data.length)){
|
||||
message.error("已有学生报名,不允许删除");
|
||||
}else{
|
||||
const arr = taskCount.filter(item=>item!== index);
|
||||
setTaskCount(arr);
|
||||
}
|
||||
}
|
||||
|
||||
// 取消编辑点击函数
|
||||
function cancelEdit(){
|
||||
if(isAddRepo){
|
||||
// 新增项目信息
|
||||
setIsAddRepo(false);
|
||||
return
|
||||
}
|
||||
// 编辑项目信息
|
||||
setIsEdit(false);
|
||||
setEditRepoCount(0);
|
||||
setTimeout(() => {
|
||||
scrollToRepoInfo()
|
||||
}, 100);
|
||||
}
|
||||
|
||||
// 屏幕滚动到当前项目区域
|
||||
function scrollToRepoInfo(){
|
||||
const element = document.getElementById(`repoShowId${applyInfo.id}`);
|
||||
window.scrollTo(0, element.offsetTop-100);
|
||||
}
|
||||
|
||||
return(
|
||||
<div className='applyInfoBox'>
|
||||
<div className='titleG font-18 mb10' id="editRepoInfoId">项目信息</div>
|
||||
{taskCount && <Form className="pt20 glcc_info_form" onSubmit={handleSubmit}>
|
||||
{helper('项目名称',
|
||||
'',
|
||||
'projectName',
|
||||
[{ required: true, message: "请输入项目名称,长度限制32个字符" },
|
||||
{ max: 32, message: '超出限制长度32位字符,请重新编辑' }],
|
||||
<Input placeholder="请输入项目名称,长度限制32个字符" onBlur={()=>{verify("name")}}/>
|
||||
)}
|
||||
{helper('项目分类',
|
||||
'',
|
||||
'projectType',
|
||||
[{ required: true, message: "请选择项目分类" }],
|
||||
<Select placeholder="请选择项目分类">
|
||||
{cateList && cateList.map(item=> {return <Option value={item.name} key={item.id}>{item.name}</Option>})}
|
||||
</Select>
|
||||
)}
|
||||
{helper('GitLink地址',
|
||||
'',
|
||||
'gitlinkUrl',
|
||||
[{ required: true, message: "请输入GitLink项目地址" },
|
||||
{ max: 252, message: '超出限制长度252位字符,请重新编辑' }],
|
||||
<Input placeholder="请输入GitLink项目地址" onBlur={()=>{verify("gitlink")}}/>
|
||||
)}
|
||||
{helper('联系人姓名',
|
||||
'',
|
||||
'contactName',
|
||||
[{ required: true, message: "请输入项目联系人姓名" },
|
||||
{ max: 32, message: '超出限制长度32位字符,请重新编辑' }],
|
||||
<Input placeholder="请输入项目联系人姓名" onBlur={()=>{verify("name")}}/>
|
||||
)}
|
||||
{helper('联系人电话',
|
||||
'',
|
||||
'contactPhone',
|
||||
[{ required: true, message: "输入项目联系人手机号码" },
|
||||
{ pattern: phonereg, message: "请输入正确的手机号码"},],
|
||||
<Input placeholder="输入项目联系人手机号码" onBlur={()=>{verify("name")}}/>
|
||||
)}
|
||||
{helper('联系人邮箱',
|
||||
'',
|
||||
'contactMail',
|
||||
[{ required: true, message: "输入项目联系人邮箱" },
|
||||
{ pattern: emailreg, message: "请输入正确的邮箱地址"},],
|
||||
<Input placeholder="输入项目联系人邮箱" onBlur={()=>{verify("name")}}/>
|
||||
)}
|
||||
<div className='introArea'>{helper('社区简介',
|
||||
'',
|
||||
'projectIntro',
|
||||
[{ required: true, message: "请输入社区简介" },
|
||||
{ max: 200, message: '超出限制长度200位字符,请重新编辑' }],
|
||||
<TextArea placeholder="请输入社区简介" onBlur={()=>{verify("intro")}} rows={4}/>
|
||||
)}</div>
|
||||
<div className='introArea'>{helper('项目logo',
|
||||
'限制上传格式为:png、jpg、jpeg,限制20M。建议上传大小为382*228',
|
||||
'logo',
|
||||
[{ required: true, message: "请正确上传项目logo" }],
|
||||
<Upload
|
||||
listType="picture-card"
|
||||
className="avatar-uploader"
|
||||
showUploadList={false}
|
||||
action={getUploadActionUrl()}
|
||||
accept=".png,.jpg,.jpeg"
|
||||
beforeUpload={beforeUpload}
|
||||
onChange={handleChange}
|
||||
>
|
||||
{(imageUrl || applyInfo) ? <img src={imageUrl || `${main_site_url}/api/attachments/${applyInfo && applyInfo.projectLogoId}`} alt="avatar" style={{ maxWidth: '100px', maxHeight: '100px' }} /> : <div>
|
||||
<i className='iconfont icon-tianjiadaohang font-30'></i>
|
||||
<div className="ant-upload-text font-13">请上传logo图片</div>
|
||||
</div>}
|
||||
</Upload>
|
||||
)}</div>
|
||||
{taskCount.map((item, index)=>{
|
||||
return <div className='taskApplyBox' key={item}>
|
||||
<FlexAJ className='taskApplyTitleBox'>
|
||||
<div className='taskApplyTitle font-16'>课题信息(<span>{index+1}</span>/5)</div>
|
||||
{index>0 && <Button type="link" onClick={()=>{deleteTaskApply(item)}}><i className='iconfont icon-shanchuicon3 mr5 font-15'></i>删除</Button>}
|
||||
</FlexAJ>
|
||||
<TaskApply helper={helper} taskKey={item} phonereg={phonereg} emailreg={emailreg} getFieldDecorator={getFieldDecorator}/>
|
||||
</div>
|
||||
})}
|
||||
{taskCount && taskCount.length<5 && <div>
|
||||
<Button type="primary" className='taskApplyBox' style={{width: "100px", height: "36px"}} onClick={addTaskApplyForm}>添加课题</Button>
|
||||
</div>}
|
||||
<Form.Item className='subInfo introArea'>
|
||||
{(isAddRepo || applyInfo) && <Popconfirm
|
||||
title={<span>取消编辑将清除已填写的所有项目信息,请谨慎操作</span>}
|
||||
onConfirm={cancelEdit}
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
>
|
||||
<Button className='mr20' style={{height: '36px', width: '110px'}}>取消</Button>
|
||||
</Popconfirm>}
|
||||
<Button type="primary" htmlType="submit" className='sub' loading={loading}>提交</Button>
|
||||
</Form.Item>
|
||||
</Form>}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default Form.create()(EditRepoApplyInfo);
|
||||
|
|
@ -1,41 +1,28 @@
|
|||
import React , { useCallback, useEffect , useState } from 'react';
|
||||
import { Breadcrumb, Button, Form, Input, Select, Upload, Modal } from 'antd';
|
||||
import {getUploadActionUrl} from 'educoder';
|
||||
import {getUserApplyInfo, applyGlcc} from '../api';
|
||||
import React , { useEffect , useState } from 'react';
|
||||
import { Breadcrumb, message } from 'antd';
|
||||
import {getUserApplyInfo} from '../api';
|
||||
import axios from 'axios';
|
||||
import TextArea from 'antd/lib/input/TextArea';
|
||||
import { main_site_url } from '../fetch';
|
||||
import RepoInfo from './repoInfo';
|
||||
import EditInfo from './editInfo';
|
||||
import banner from "../img/banner.png";
|
||||
import apply1 from "../img/apply1.png";
|
||||
import './index.scss';
|
||||
const Option = Select.Option;
|
||||
import { FlexAJ } from '../../forge/Component/layout';
|
||||
// 项目、课题报名
|
||||
function Apply(props) {
|
||||
const {form, current_user, showNotification, isGlccApplyDate} = props;
|
||||
// 可用于开发时不同账号报名
|
||||
// current_user && (current_user.user_id = 6)
|
||||
// current_user && (current_user.userName = "创新使者")
|
||||
const {getFieldDecorator, validateFields, setFieldsValue, validateFieldsAndScroll } = form;
|
||||
const {current_user, round} = props;
|
||||
const [reload, setReload] = useState(undefined);
|
||||
const [imageUrl, setImageUrl] = useState(undefined);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [cateList, setCateList] = useState([]);
|
||||
const [userApplyInfo, setUserApplyInfo] = useState(undefined);
|
||||
|
||||
const helper = useCallback(
|
||||
(label, extra, name, rules, widget) => (
|
||||
<Form.Item label={label} extra={extra}>
|
||||
{getFieldDecorator(name, { rules, validateFirst: true })(widget)}
|
||||
</Form.Item>
|
||||
),
|
||||
[]
|
||||
);
|
||||
const [userApplyInfo, setUserApplyInfo] = useState([]);
|
||||
// 添加一个项目
|
||||
const [isAddRepo, setIsAddRepo] = useState(false);
|
||||
// 编辑项目个数
|
||||
const [editRepoCount, setEditRepoCount] = useState(0);
|
||||
|
||||
useEffect(()=>{
|
||||
// 进入此页面置顶
|
||||
window.scrollTo(0,0);
|
||||
if(!isGlccApplyDate){
|
||||
// 不在开源夏令营报名时间之内
|
||||
window.location.href="/glcc";
|
||||
}else if(current_user && current_user.login){
|
||||
if(current_user && current_user.login){
|
||||
// 获取项目分类参数
|
||||
const url = `/project_categories/pinned_index.json`;
|
||||
axios.get(url).then(result=>{
|
||||
|
|
@ -50,160 +37,59 @@ function Apply(props) {
|
|||
|
||||
useEffect(()=>{
|
||||
// 获取当前用户报名信息
|
||||
current_user && getUserApplyInfo({userId: current_user.user_id}).then(response=>{
|
||||
current_user && round && getUserApplyInfo({userId: current_user.user_id, round}).then(response=>{
|
||||
if(response && response.message === "success"){
|
||||
response.data && setFieldsValue({
|
||||
...response.data
|
||||
})
|
||||
setUserApplyInfo(response.data);
|
||||
}
|
||||
})
|
||||
}, [reload])
|
||||
|
||||
// 当用户输入结束时 检验用户输入是否符合规范
|
||||
function verify(dataIndex){
|
||||
validateFields([dataIndex],(error, values)=>{
|
||||
if(error && error[dataIndex]){
|
||||
return;
|
||||
}
|
||||
})
|
||||
// 添加项目点击函数
|
||||
function addRepoBut(){
|
||||
if(isAddRepo || editRepoCount){
|
||||
scrollToEdit();
|
||||
message.error("请先提交当前项目信息");
|
||||
return;
|
||||
}
|
||||
setIsAddRepo(true);
|
||||
setTimeout(() => {
|
||||
scrollToEdit()
|
||||
}, 100);
|
||||
}
|
||||
|
||||
// 报名夏令营
|
||||
function handleSubmit(e){
|
||||
e.preventDefault();
|
||||
validateFieldsAndScroll((err, values) => {
|
||||
if (!err) {
|
||||
Modal.confirm({
|
||||
title: "报名",
|
||||
content: "确定提交报名信息,提交后报名信息将无法修改",
|
||||
onOk: ()=>{
|
||||
const params ={
|
||||
...values,
|
||||
projectLogoId: values.logo.file.response.id,
|
||||
userId: current_user.user_id,
|
||||
userName: current_user.username
|
||||
}
|
||||
applyGlcc(params).then(response=>{
|
||||
if(response && response.message === "success"){
|
||||
showNotification("报名成功");
|
||||
setReload(Math.random());
|
||||
}
|
||||
})
|
||||
}
|
||||
})}
|
||||
});
|
||||
};
|
||||
|
||||
// 检查文件上传是否符合规定
|
||||
function beforeUpload(file){
|
||||
const isLt100M = file.size / 1024 / 1024 < 2;
|
||||
if (!isLt100M) {
|
||||
showNotification(`文件大小必须小于${2}MB!`);
|
||||
}
|
||||
const isType = file.type === "image/png" || file.type === "image/jpg" || file.type === "image/jpeg";
|
||||
if (!isType) {
|
||||
showNotification("只能上传png、jpg、jpeg格式文件");
|
||||
}
|
||||
return isLt100M && isType;
|
||||
}
|
||||
function getBase64(img, callback) {
|
||||
const reader = new FileReader();
|
||||
reader.addEventListener('load', () => callback(reader.result));
|
||||
reader.readAsDataURL(img);
|
||||
reader.onload = function(e) {
|
||||
setImageUrl(e.target.result); // 上传的图片的编码
|
||||
}
|
||||
// 屏幕滚动到编辑区域
|
||||
function scrollToEdit(){
|
||||
const element = document.getElementById("editRepoInfoId");
|
||||
window.scrollTo(0, element.offsetTop-80);
|
||||
}
|
||||
|
||||
// 上传完成后
|
||||
function handleChange(info){
|
||||
if(info && info.file && info.file.status === "done"){
|
||||
getBase64(info.file.originFileObj, imageUrl =>
|
||||
setImageUrl(imageUrl)
|
||||
);
|
||||
}
|
||||
}
|
||||
return(
|
||||
<div className="glcc_apply">
|
||||
<img className="glcc-banner" src={banner} alt=''></img>
|
||||
{/* <img className="glcc-banner" src={banner} alt=''></img> */}
|
||||
<div className='apply'>
|
||||
<Breadcrumb className='pt20 font-16'>
|
||||
<Breadcrumb className='pt20 font-16 breadcrumbGlcc'>
|
||||
<Breadcrumb.Item><a href="/glcc">开源夏令营</a></Breadcrumb.Item>
|
||||
<Breadcrumb.Item>项目报名</Breadcrumb.Item>
|
||||
</Breadcrumb>
|
||||
{userApplyInfo && <div className='applySuccess mt20 font-15'>
|
||||
<i className='iconfont icon-wancheng mr5'></i>您已报名成功,请关注活动后续新闻公告!
|
||||
</div>}
|
||||
<Form className="pt20 glcc_info_form" onSubmit={handleSubmit}>
|
||||
{helper('项目名称',
|
||||
'',
|
||||
'projectName',
|
||||
[{ required: true, message: "请正确输入项目名称" },
|
||||
{ max: 32, message: '超出限制长度32位字符,请重新编辑' }],
|
||||
<Input placeholder="请输入项目名称" onBlur={()=>{verify("name")}} disabled = {userApplyInfo ? true : false} className={userApplyInfo? "disabledInput":""}/>
|
||||
)}
|
||||
{helper('项目分类',
|
||||
'',
|
||||
'projectType',
|
||||
[],
|
||||
<Select placeholder="请选择项目分类" disabled = {userApplyInfo ? true : false} className={userApplyInfo? "disabledInput":""}>
|
||||
{cateList && cateList.map(item=> {return <Option value={item.name} key={item.id}>{item.name}</Option>})}
|
||||
</Select>
|
||||
)}
|
||||
{helper('GitLink项目地址',
|
||||
'',
|
||||
'gitlinkUrl',
|
||||
[{ required: true, message: "请正确输入预申报项目在GitLink平台的地址" },
|
||||
{ max: 252, message: '超出限制长度252位字符,请重新编辑' }],
|
||||
<Input placeholder="请输入预申报项目在GitLink平台的地址" onBlur={()=>{verify("gitlink")}} disabled = {userApplyInfo ? true : false} className={userApplyInfo? "disabledInput":""}/>
|
||||
)}
|
||||
{helper('官网地址',
|
||||
'',
|
||||
'officialWebsiteUrl',
|
||||
[{ max: 252, message: '超出限制长度252位字符,请重新编辑' }],
|
||||
<Input placeholder="请输入官网地址" disabled = {userApplyInfo ? true : false} className={userApplyInfo? "disabledInput":""}/>
|
||||
)}
|
||||
<div className='introArea'>{helper('项目简介',
|
||||
'',
|
||||
'projectIntro',
|
||||
[{ required: true, message: "请正确输入项目简介" },
|
||||
{ max: 200, message: '超出限制长度200位字符,请重新编辑' }],
|
||||
<TextArea placeholder="请输入项目简介,长度不超过200字符" onBlur={()=>{verify("intro")}} rows={4} disabled = {userApplyInfo ? true : false} className={userApplyInfo? "disabledInput":""}/>
|
||||
)}</div>
|
||||
<div className='introArea'>{helper('项目logo',
|
||||
'logo格式为png、jpg、jpeg,限制上传大小2m,建议上传尺寸为382*228',
|
||||
'logo',
|
||||
[{ required: true, message: "请正确上传项目logo" }],
|
||||
userApplyInfo && userApplyInfo.projectLogoId ? <div className='projectLogo'><img src={`${main_site_url}/api/attachments/${userApplyInfo.projectLogoId}`} alt=''/></div>
|
||||
:<Upload
|
||||
listType="picture-card"
|
||||
className="avatar-uploader"
|
||||
showUploadList={false}
|
||||
action={getUploadActionUrl()}
|
||||
accept=".png,.jpg,.jpeg"
|
||||
beforeUpload={beforeUpload}
|
||||
onChange={handleChange}
|
||||
>
|
||||
{imageUrl ? <img src={imageUrl} alt="avatar" style={{ maxWidth: '100px', maxHeight: '100px' }} /> : <div>
|
||||
<i className='iconfont icon-tianjiadaohang font-30'></i>
|
||||
<div className="ant-upload-text font-13">请上传logo图片</div>
|
||||
</div>}
|
||||
</Upload>
|
||||
)}</div>
|
||||
<p className='introArea tips'>注: 课题及导师信息请在GitLink项目中以issue的形式编辑</p>
|
||||
{!userApplyInfo && <Form.Item className='subInfo introArea'>
|
||||
<Button type="primary" htmlType="submit" className='sub'>提交</Button>
|
||||
</Form.Item>}
|
||||
</Form>
|
||||
<div className={`explain ${userApplyInfo ? "mt70" : ""}`}>
|
||||
{userApplyInfo.length > 0 && <div className='applySuccess mt20 font-15'>您已报名成功,可实时修改您的报名信息再次提交。请关注夏令营首页新闻公告获得更多活动资讯!</div>}
|
||||
<div className={`explain`}>
|
||||
<p className='font-15 c000'>申请说明</p>
|
||||
<div>1、项目报名时间为<span className='c000'>4月15日—5月20日</span>,请在报名截止时间(北京时间<span className='c000'>2022年5月20日24点</span>)前提交报名信息。</div>
|
||||
<div>2、本次夏令营使用Gitlink为代码托管平台,学员基于Gitlink上项目数量完成课程任务。如果您的项目还未在Gitlink中,请现将项目迁移到Gitlink,迁移事项请查看<a href='https://forum.gitlink.org.cn/forums/7296/detail' target="_blank" className='link'>迁移说明文档</a>。如在迁移过程中遇到问题,请加qq群: 1071514693 联系qq群管理员。</div>
|
||||
<div>3、提交社区和项目信息后,欢迎与组委会联系沟通本次编程夏令营宣传推广和后续合作工作。联系人: _TigerWang(微信号,添加请备注Gitlink编程夏令营)</div>
|
||||
<div>1、项目报名时间为<span className='c000'>4月29日—5月30日</span>,请在报名截止时间(北京时间<span className='c000'>2023年5月30日24点</span>)前提交报名信息。</div>
|
||||
<div>2、本次GLCC夏令营建议使用GitLink为代码托管平台,学生基于GitLink上项目完成编程任务。同时也欢迎使用其他代码托管平台的项目参与活动。目前GLCC只对夏令营期间使用GitLink托管的项目提供部分奖金支持。</div>
|
||||
<div>3、如果您的项目还未迁移到GitLink上,迁移事项请查看<a href='https://forum.gitlink.org.cn/forums/7296/detail' target="_blank" className='link'>迁移说明文档</a>。如在迁移过程中遇到问题,请加qq群: 1071514693 联系qq群管理员。</div>
|
||||
<div>4、提交社区和题目信息后,欢迎与组委会联系沟通宣传推广和后续合作工作。联系人微信: _TigerWang(备注GitLink编程夏令营)</div>
|
||||
<div><span className='c000'>5、奖金默认由项目方支持,请根据课题难度设定金额。若您可能无法支撑本课题奖金,GLCC组委会将进行资助评审,择优资助。如未获得资助,将下线该课题</span></div>
|
||||
</div>
|
||||
<FlexAJ className='pt20 font-18 pb20'>
|
||||
<span><img src={apply1} alt="" width="25px" className="mr10"/>项目报名</span>
|
||||
{userApplyInfo.length > 0 && <a className='font-16 addRepoBut' onClick={addRepoBut}><i className='iconfont icon-tianjia_tianchong mr5 font-22'></i>添加项目</a>}
|
||||
</FlexAJ>
|
||||
{userApplyInfo.length > 0 && <div className='repoListBox'>
|
||||
{userApplyInfo.map((item, index)=><div className='repoList mb20' key={index}><RepoInfo cateList={cateList} applyInfo={item} current_user={current_user} round={round} setReload={()=>{setReload(Math.random())}} isAddRepo={isAddRepo} editRepoCount={editRepoCount} setEditRepoCount={setEditRepoCount} repoCount={userApplyInfo.length} scrollToEdit={scrollToEdit}/></div>)}
|
||||
</div>}
|
||||
{(!userApplyInfo.length || isAddRepo) && <EditInfo isAddRepo={isAddRepo} setIsAddRepo={setIsAddRepo} round={round} cateList={cateList} current_user={current_user} setReload={()=>{setReload(Math.random())}}/>}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default Form.create()(Apply);
|
||||
export default Apply;
|
||||
|
|
@ -8,6 +8,7 @@
|
|||
.glcc_info_form{
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
padding: 10px 25px 10px 0;
|
||||
.ant-row.ant-form-item{
|
||||
margin-bottom: 20px;
|
||||
display: flex;
|
||||
|
|
@ -15,7 +16,7 @@
|
|||
justify-content: flex-end;
|
||||
}
|
||||
.ant-col.ant-form-item-control-wrapper {
|
||||
width: 78%;
|
||||
width: 77%;
|
||||
}
|
||||
.ant-form-item-label{
|
||||
margin-right: 15px;
|
||||
|
|
@ -75,7 +76,7 @@
|
|||
text-align: center;
|
||||
margin: 40px 0 70px -60px;
|
||||
.sub{
|
||||
width: 200px;
|
||||
width: 110px;
|
||||
height: 36px;
|
||||
background-color: #466aff;
|
||||
border-color: #466aff;
|
||||
|
|
@ -90,11 +91,10 @@
|
|||
}
|
||||
}
|
||||
.explain{
|
||||
background-color:#f6f9fe;
|
||||
border:2px solid;
|
||||
border-color:#ffffff;
|
||||
margin-top: 35px;
|
||||
background-color:#e4edff;
|
||||
color:#6c7283;
|
||||
padding: 20px 30px 30px 20px;
|
||||
padding: 10px 30px 2px 20px;
|
||||
.c000{color: #000000;}
|
||||
div>.c000{font-weight: bold;}
|
||||
>div{margin: 10px 0;}
|
||||
|
|
@ -105,13 +105,162 @@
|
|||
}
|
||||
.applySuccess{
|
||||
height: 45px;
|
||||
border: 1px solid;
|
||||
border-color: #466aff;
|
||||
line-height: 45px;
|
||||
padding-left: 20px;
|
||||
color:#466aff;
|
||||
color:#2dab4d;
|
||||
border: 1px solid rgba(36, 167, 67, 0.61);
|
||||
background-color:rgba(82, 206, 152, 0.11);
|
||||
}
|
||||
.applyInfoBox{
|
||||
background-color:rgba(255, 255, 255, 0.27);
|
||||
border:1px solid #ffffff;
|
||||
.titleG{
|
||||
background-color:#e1e8ff;
|
||||
padding: 10px 0;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
.glcc-banner {
|
||||
width: 100%;
|
||||
}
|
||||
.breadcrumbGlcc{
|
||||
padding-bottom: 15px;
|
||||
border-bottom: 1px dashed #bec5d5;
|
||||
}
|
||||
.taskApplyBox{
|
||||
width: 100%;
|
||||
margin-left: 50px;
|
||||
.taskApplyTitleBox{
|
||||
padding-bottom: 15px;
|
||||
border-bottom: 1px dashed #bec5d5;
|
||||
}
|
||||
.taskApplyTitle{
|
||||
color:#333333;
|
||||
padding-left: 15px;
|
||||
position: relative;
|
||||
&::before{
|
||||
content: "";
|
||||
width:5px;
|
||||
height:14px;
|
||||
background-color:$primary-color;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 6px;
|
||||
}
|
||||
&>span{
|
||||
color: $primary-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
.taskApplyForm{
|
||||
.glcc_info_form{
|
||||
position: relative;
|
||||
left: -20px;
|
||||
.ant-row.ant-form-item{
|
||||
justify-content: space-between;
|
||||
}
|
||||
.ant-form-item-label{
|
||||
margin-right: 0px;
|
||||
}
|
||||
}
|
||||
.introArea .ant-form-item-label{
|
||||
width: 100px;
|
||||
position: relative;
|
||||
left: -17px;
|
||||
}
|
||||
}
|
||||
.repoListBox{
|
||||
background-color:rgba(255, 255, 255, 0.27);
|
||||
border:1px solid #ffffff;
|
||||
padding: 15px 15px 0;
|
||||
}
|
||||
.repoList{
|
||||
border-bottom: 1px dashed #bec5d5;
|
||||
&:hover{
|
||||
background-color:#ffffff;
|
||||
border-radius:4px;
|
||||
box-shadow:0px 0px 10px rgba(84, 124, 255, 0.28);
|
||||
.taskApplyInfo{
|
||||
background-color:rgba(236, 242, 255, 0.83);
|
||||
}
|
||||
}
|
||||
}
|
||||
.flexStartBox{
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: flex-start;
|
||||
.repoName{
|
||||
font-weight:700;
|
||||
color:#333333;
|
||||
}
|
||||
}
|
||||
.repoInfo{
|
||||
padding: 20px 10px 30px 10px;
|
||||
.repoLogo{
|
||||
width:36px;
|
||||
height:36px;
|
||||
border-radius: 50%;
|
||||
object-fit: cover;
|
||||
}
|
||||
.repoType{
|
||||
display: inline-block;
|
||||
padding: 5px 10px;
|
||||
line-height: normal;
|
||||
color:#465474;
|
||||
border:1px solid #6680bb;
|
||||
border-radius:4px;
|
||||
}
|
||||
.repoOthersInfo{
|
||||
color:#465474;
|
||||
word-break: break-all;
|
||||
}
|
||||
.labelInfoBox{
|
||||
width: 75px;
|
||||
display: inline-block;
|
||||
&.gitlinkUrl{
|
||||
width: 95px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.taskApplyInfo{
|
||||
background-color:rgba(251, 252, 255, 0.8);
|
||||
border:1px solid #ffffff;
|
||||
padding: 20px;
|
||||
.taskDifficulty{
|
||||
display: inline-block;
|
||||
width:27px;
|
||||
height:24px;
|
||||
border:1px solid #0ba840;
|
||||
border-radius:6px;
|
||||
color:#0ba840;
|
||||
line-height: 24px;
|
||||
text-align: center;
|
||||
&.diff2{
|
||||
color:#ffb300;
|
||||
border-color:#ffb300;
|
||||
}
|
||||
&.diff3{
|
||||
color:#ff0000;
|
||||
border-color:#ff1d1d;
|
||||
}
|
||||
}
|
||||
.taskRewardBox{
|
||||
color: $primary-color;
|
||||
}
|
||||
}
|
||||
.addRepoBut{
|
||||
color: $primary-color;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
.openTaskBox{
|
||||
text-align: center;
|
||||
margin-top: 20px;
|
||||
.openTask{
|
||||
color: $primary-color;
|
||||
border:1px solid $primary-color;
|
||||
border-radius:6px;
|
||||
padding: 10px 20px;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
import { Button, Row, Col, Popconfirm, message } from "antd";
|
||||
import React, { useState } from "react";
|
||||
import EditInfo from "./editInfo";
|
||||
import { FlexAJ } from "../../forge/Component/layout";
|
||||
import { main_site_url } from "../fetch";
|
||||
import './index.scss';
|
||||
import { deleteApplyInfo } from "../api";
|
||||
// 项目、课题信息展示
|
||||
function RepoInfo(props) {
|
||||
const {applyInfo:{id, projectLogoId, projectName, projectType, contactName, contactPhone, contactMail, gitlinkUrl, projectIntro, registrationTaskList}, setReload, editRepoCount, setEditRepoCount, repoCount, isAddRepo, scrollToEdit} = props;
|
||||
// 课题难度:低、中、高
|
||||
const difficultyList = ['', '低', '中', '高'];
|
||||
const [isEdit, setIsEdit] = useState(false);
|
||||
const [showAllTask, setShowAllTask] = useState(false);
|
||||
|
||||
// 编辑项目信息
|
||||
function editRepoBut(){
|
||||
if(editRepoCount || isAddRepo){
|
||||
scrollToEdit();
|
||||
message.error("请先提交当前项目信息");
|
||||
return;
|
||||
}
|
||||
setEditRepoCount(editRepoCount+1);
|
||||
setIsEdit(true);
|
||||
}
|
||||
|
||||
// 删除项目
|
||||
function deleteBut(){
|
||||
deleteApplyInfo({ids: [id], round: 2}).then(res=>{
|
||||
message.success("删除成功");
|
||||
setReload();
|
||||
})
|
||||
}
|
||||
|
||||
// 课题信息展示
|
||||
const showTask = (task) => {
|
||||
const {id, taskDifficulty, taskName, taskReward, tutorName, tutorPhone, tutorMail, taskDesc, taskUrl} = task;
|
||||
return <div className="taskApplyInfo mt20" key={id}>
|
||||
<FlexAJ>
|
||||
<div>
|
||||
<div className={`taskDifficulty diff${taskDifficulty} font-14 mr10`}>{difficultyList[taskDifficulty]}</div>
|
||||
<span className="repoName font-16">{taskName}</span>
|
||||
</div>
|
||||
<span className="font-20 taskRewardBox">¥ {taskReward}</span>
|
||||
</FlexAJ>
|
||||
<div style={{flex: 1}} className="font-15 ml35 mt10">
|
||||
<Row gutter={16}>
|
||||
<Col span={12}><div className="repoOthersInfo"><span className="labelInfoBox">导师信息:</span>{tutorName}({tutorPhone} | {tutorMail})</div></Col>
|
||||
<Col span={12}><div className="repoOthersInfo"><span className="labelInfoBox">课题链接:</span>{taskUrl}</div></Col>
|
||||
</Row>
|
||||
<div className="repoOthersInfo mt10"><span className="labelInfoBox">课题简介:</span>{taskDesc}</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
return (
|
||||
isEdit ? <EditInfo {...props} setIsEdit={setIsEdit}/> : <div className="flexStartBox repoInfo">
|
||||
<img className="repoLogo mr10" src={`${main_site_url}/api/attachments/${projectLogoId}`} alt= { `${projectName}-glcc`} />
|
||||
<div style={{flex: 1, width: 0}} className="font-15" id={`repoShowId${id}`}>
|
||||
{/* 项目信息 */}
|
||||
<FlexAJ>
|
||||
<div>
|
||||
<span className="repoName font-16">{projectName}</span>
|
||||
<span className="repoType ml20">{projectType}</span>
|
||||
</div>
|
||||
<div>
|
||||
<Button type="link" onClick={editRepoBut}><i className='iconfont icon-a-bianji12 mr5 font-12'></i>编辑</Button>
|
||||
{repoCount > 1 && <Popconfirm
|
||||
title={<span>删除项目将清除项目信息及所有课题信息,<br/>请谨慎操作。</span>}
|
||||
onConfirm={deleteBut}
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
>
|
||||
<Button type="link"><i className='iconfont icon-shanchuicon3 mr5 font-15'></i>删除</Button>
|
||||
</Popconfirm>}
|
||||
</div>
|
||||
</FlexAJ>
|
||||
{/* <Rows label={["官网地址", "GitLink地址"]} content={[]}/> */}
|
||||
<Row gutter={16}>
|
||||
<Col span={12}><div className="repoOthersInfo mt15"><span className="labelInfoBox">导师信息:</span>{contactName}({contactPhone} | {contactMail})</div></Col>
|
||||
<Col span={12}><div className="repoOthersInfo mt15"><span className="labelInfoBox gitlinkUrl">GitLink地址:</span>{gitlinkUrl}</div></Col>
|
||||
</Row>
|
||||
<div className="repoOthersInfo mt10"><span className="labelInfoBox">社区简介:</span>{projectIntro}</div>
|
||||
|
||||
{/* 课题信息list */}
|
||||
{/* 多个课题(仅展示一个课题) 单个课题 */}
|
||||
{registrationTaskList && registrationTaskList.length > 1 && !showAllTask && <div>
|
||||
{showTask(registrationTaskList[0])}
|
||||
<div className="openTaskBox"><a onClick={()=>{setShowAllTask(!showAllTask)}} className="openTask">展开课题<i className="iconfont icon-xiala1 ml10 font-14"></i></a></div>
|
||||
</div>}
|
||||
{/* 多个课题同时展示 */}
|
||||
{registrationTaskList && (registrationTaskList.length === 1 || showAllTask) && <React.Fragment>
|
||||
{registrationTaskList.map(item=>showTask(item))}
|
||||
{showAllTask && <div className="openTaskBox"><a onClick={()=>{setShowAllTask(!showAllTask)}} className="openTask">收起课题<i className="iconfont icon-xiala2 ml10 font-14"></i></a></div>}
|
||||
</React.Fragment>}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default RepoInfo;
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
import React from 'react';
|
||||
import {Form, Input, Select } from 'antd';
|
||||
import TextArea from 'antd/lib/input/TextArea';
|
||||
const Option = Select.Option;
|
||||
// 课题信息编辑
|
||||
function TaskApply(props) {
|
||||
const {helper, disabled, taskKey, phonereg, emailreg, getFieldDecorator} = props;
|
||||
// 低、中、高
|
||||
const difficultyList = [
|
||||
{id: 1, name: "低"},
|
||||
{id: 2, name: "中"},
|
||||
{id: 3, name: "高"}
|
||||
]
|
||||
// 奖金
|
||||
const rewardList = [
|
||||
{id: 12000},
|
||||
{id: 11000},
|
||||
{id: 10000},
|
||||
{id: 9000},
|
||||
{id: 8000},
|
||||
{id: 7000},
|
||||
{id: 6000},
|
||||
{id: 0},
|
||||
]
|
||||
|
||||
return(
|
||||
<div className="taskApplyForm">
|
||||
<div className="pt20 glcc_info_form">
|
||||
<Form.Item label="课题id" hidden>
|
||||
{getFieldDecorator(`taskId${taskKey}`, {})(<Input/>)}
|
||||
</Form.Item>
|
||||
{helper('课题名称',
|
||||
'',
|
||||
`taskName${taskKey}`,
|
||||
[{ required: true, message: "请输入课题名称,长度限制32个字符" },
|
||||
{ max: 32, message: '超出限制长度32位字符,请重新编辑' }],
|
||||
<Input placeholder="请输入课题名称" disabled = {disabled} className={disabled? "disabledInput":""}/>
|
||||
)}
|
||||
{helper('课题链接',
|
||||
'',
|
||||
`taskUrl${taskKey}`,
|
||||
[{ required: true, message: "请输入课题链接" },
|
||||
{ max: 252, message: '超出限制长度252位字符,请重新编辑' }],
|
||||
<Input placeholder="请输入课题链接" disabled = {disabled} className={disabled? "disabledInput":""}/>
|
||||
)}
|
||||
{helper('课题难度',
|
||||
'',
|
||||
`taskDifficulty${taskKey}`,
|
||||
[{ required: true, message: "请选择课题难度" }],
|
||||
<Select placeholder="请选择课题难度" disabled = {disabled} className={disabled? "disabledInput":""}>
|
||||
{difficultyList && difficultyList.map(item=> {return <Option value={item.id} key={item.id}>{item.name}</Option>})}
|
||||
</Select>
|
||||
)}
|
||||
{helper('课题奖金',
|
||||
'',
|
||||
`taskReward${taskKey}`,
|
||||
[{ required: true, message: "请选择课题奖金" },
|
||||
// {pattern: /^[1-9]+[0-9]*]*$/, message: "请输入正整数" },
|
||||
// { validator: (rule,val,callback) =>{
|
||||
// if(val>=6000 && val<=12000){
|
||||
// callback();
|
||||
// }else{
|
||||
// callback("区间为6000-12000元");
|
||||
// }
|
||||
// }}
|
||||
],
|
||||
<Select placeholder="请根据课题难度选择奖金" disabled = {disabled} className={disabled? "disabledInput":""}>
|
||||
{rewardList && rewardList.map(item=> {return <Option value={item.id} key={item.id}>{item.id}</Option>})}
|
||||
</Select>
|
||||
)}
|
||||
{helper('导师姓名',
|
||||
'',
|
||||
`tutorName${taskKey}`,
|
||||
[{ required: true, message: "请输入导师姓名" },
|
||||
{ max: 32, message: '超出限制长度32位字符,请重新编辑' }],
|
||||
<Input placeholder="请输入导师姓名" disabled = {disabled} className={disabled? "disabledInput":""}/>
|
||||
)}
|
||||
{helper('导师手机号',
|
||||
'',
|
||||
`tutorPhone${taskKey}`,
|
||||
[{ required: true, message: "请输入导师手机号" },
|
||||
{ pattern: phonereg, message: "请输入正确的电话号码"},],
|
||||
<Input placeholder="请输入导师手机号" disabled = {disabled} className={disabled? "disabledInput":""}/>
|
||||
)}
|
||||
{helper('导师邮箱',
|
||||
'',
|
||||
`tutorMail${taskKey}`,
|
||||
[{ required: true, message: "请输入导师邮箱地址" },
|
||||
{ pattern: emailreg, message: "请输入正确的邮箱地址"},],
|
||||
<Input placeholder="请输入导师邮箱地址" disabled = {disabled} className={disabled? "disabledInput":""}/>
|
||||
)}
|
||||
<div className='introArea'>{helper('课题简介',
|
||||
'',
|
||||
`taskDesc${taskKey}`,
|
||||
[{ required: true, message: "请输入课题简介" },
|
||||
{ max: 200, message: '超出限制长度200位字符,请重新编辑' }],
|
||||
<TextArea placeholder="请输入课题简介" rows={4} disabled = {disabled} className={disabled? "disabledInput":""}/>
|
||||
)}</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default Form.create()(TaskApply);
|
||||
|
|
@ -3,13 +3,13 @@ import { Modal, Table, Tooltip, Breadcrumb, Tabs, Button } from 'antd';
|
|||
import { Link } from 'react-router-dom';
|
||||
import moment from 'moment';
|
||||
import './index.scss';
|
||||
import { auditPassTask, getStudentList, getAuditList, hasAuditRole } from '../api';
|
||||
import { auditPassTask, getStudentList, getAuditList } from '../api';
|
||||
import {httpUrl} from '../fetch';
|
||||
const { TabPane } = Tabs;
|
||||
|
||||
|
||||
|
||||
function Check({ current_user, showNotification, history }) {
|
||||
function Check({ current_user, showNotification, currentRound }) {
|
||||
|
||||
// 输入搜索框
|
||||
const [data, setData] = useState([]);
|
||||
|
|
@ -23,8 +23,6 @@ function Check({ current_user, showNotification, history }) {
|
|||
const [taskId, setTaskId] = useState();
|
||||
const [havePass, setHavePass] = useState(false);
|
||||
|
||||
const disabledCheck = new Date().getTime() > new Date('2022/07/01 00:00:00').getTime();
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: '学生姓名',
|
||||
|
|
@ -133,33 +131,19 @@ function Check({ current_user, showNotification, history }) {
|
|||
{record.locked && !record.used && <Tooltip title="恭喜,该学生已成功入选您的课题!"><Button disabled type="primary" className='greenColBor'>已入选</Button></Tooltip>}
|
||||
{/* 学生已经被其他导师锁定 */}
|
||||
{record.locked && record.used && <Tooltip title="此学生已入选其他课题"><Button disabled type="primary" className='redColBor'>已被选</Button></Tooltip>}
|
||||
{/* 学生未被锁定 */}
|
||||
{!record.locked && !record.used && (text ? <Button disabled={disabledCheck} type="default" onClick={() => { checkStudent(record.id, 0) }}>撤销</Button> :
|
||||
<Button disabled={disabledCheck || havePass} type="primary" onClick={() => { checkStudent(record.id, 1) }}>通过</Button>)}
|
||||
{/* 导师邮箱与系统绑定邮箱进行判断 + 学生未被锁定 */}
|
||||
{record.tutorMail === current_user.email && (!record.locked && !record.used && (text ? <Button type="default" onClick={() => { checkStudent(record.id, 0) }}>撤销</Button> :
|
||||
<Button disabled={havePass} type="primary" onClick={() => { checkStudent(record.id, 1) }}>通过</Button>))}
|
||||
</div>
|
||||
)
|
||||
})
|
||||
},
|
||||
];
|
||||
|
||||
useEffect(() => {
|
||||
if(new Date().getTime() > new Date('2022/07/01 0:0').getTime()){
|
||||
history.push('/403');
|
||||
}
|
||||
if (!current_user.user_id) {
|
||||
history.push('/403');
|
||||
}
|
||||
hasAuditRole({ userId: current_user.user_id }).then(res => {
|
||||
if (!(res && res.message == 'success' && res.data.hasRole)) {
|
||||
history.push('/403');
|
||||
}
|
||||
})
|
||||
}, [])
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
getAuditList({ userId: current_user.user_id }).then(res => {
|
||||
if (res.message == 'success') {
|
||||
getAuditList({ userId: current_user.user_id, round: currentRound }).then(res => {
|
||||
if (res.message === 'success') {
|
||||
setTaskList(res.data.rows);
|
||||
res.data.rows.length && setTaskId(res.data.rows[0].id);
|
||||
} else {
|
||||
|
|
@ -172,6 +156,7 @@ function Check({ current_user, showNotification, history }) {
|
|||
auditPassTask({
|
||||
id,
|
||||
status,
|
||||
round: currentRound
|
||||
}).then(res => {
|
||||
if (res && res.message === 'success') {
|
||||
showNotification(status ? '已通过该学生课题申请' : '撤销成功')
|
||||
|
|
@ -264,9 +249,10 @@ function Check({ current_user, showNotification, history }) {
|
|||
setLoading(true);
|
||||
const params = {
|
||||
curPage: 1,
|
||||
pageSize: 10000,
|
||||
pageSize: 999,
|
||||
keyword: '',
|
||||
taskId,
|
||||
round: currentRound
|
||||
}
|
||||
taskId && getStudentList(params).then(res => {
|
||||
if (res.data && Array.isArray(res.data.rows)) {
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@ import React, { useEffect, useState } from 'react';
|
|||
import { Input, Table, Tooltip } from 'antd';
|
||||
import { getPassList, hasAuditRole } from '../api';
|
||||
import ProjectDetail from '../project/component/projectDetail';
|
||||
// 预公示banner
|
||||
import resultBanner from "../img/resultBanner.png";
|
||||
// 公示banner
|
||||
import resultBanner2 from "../img/resultBanner2.png";
|
||||
import bgPng from "../img/bgPng.png";
|
||||
|
|
@ -12,7 +10,7 @@ import '../project/index.scss';
|
|||
const { Search } = Input;
|
||||
|
||||
// 课题列表
|
||||
function CheckResult({current_user, history}) {
|
||||
function CheckResult({current_user, history, round}) {
|
||||
// 输入搜索框
|
||||
const [keyword, setKeyword] = useState(undefined);
|
||||
const [data, setData] = useState([]);
|
||||
|
|
@ -22,7 +20,6 @@ function CheckResult({current_user, history}) {
|
|||
const [pageSize, setPageSize] = useState(20);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [expandedRowKeys, setExpandedRowKeys] = useState([]);
|
||||
const time = new Date().getTime() > new Date('2022/06/28 1:0').getTime() && new Date().getTime() < new Date('2022/07/01 0:0').getTime();
|
||||
|
||||
useEffect(()=>{
|
||||
// 未到时间
|
||||
|
|
@ -44,6 +41,7 @@ function CheckResult({current_user, history}) {
|
|||
curPage: current,
|
||||
keyword,
|
||||
pageSize,
|
||||
round
|
||||
}
|
||||
getPassList(params).then(response => {
|
||||
if (response && response.message === "success") {
|
||||
|
|
@ -58,9 +56,9 @@ function CheckResult({current_user, history}) {
|
|||
{ title: '序号', dataIndex: 'index', align: 'center', className:"columnsResult", width: '6%', render: (text, item, index) => <span>{(current-1)*pageSize+index + 1}</span> },
|
||||
{ title: '入选学生', dataIndex: 'studentName', className:"columnsResult taskName", width: '10%', ellipsis: true},
|
||||
{ title: '学生院校', dataIndex: 'school', className:"columnsResult taskName", width: '12%', ellipsis: true,render: (text) => <Tooltip title={text} placement="topLeft"><span className='toolTipSpan'>{text}</span></Tooltip>},
|
||||
{ title: '学生专业', dataIndex: 'profession', className:"columnsResult taskName", width: '12%', ellipsis: true, render: (text) => <Tooltip title={text} placement="topLeft"><span className='toolTipSpan'>{text}</span></Tooltip>},
|
||||
{ title: '学生专业', dataIndex: 'profession', className:"columnsResult taskName", width: '12%', ellipsis: true, render: (text) => <Tooltip title={text} placement="topLeft"><span className='toolTipSpan'>{text || '-'}</span></Tooltip>},
|
||||
{ title: '课题导师', dataIndex: 'tutorName', className:"columnsResult", width: '10%', ellipsis: true},
|
||||
{ title: '课题名称', dataIndex: 'taskName', className:"columnsResult", width: '20%', ellipsis: true, render: (text, item) => <Tooltip title={text} placement="topLeft"><span className='toolTipSpan link' onClick={()=>{window.open(`/glcc/subjects/detail/${item.taskId}`)}}>{text}</span></Tooltip> },
|
||||
{ title: '课题名称', dataIndex: 'taskName', className:"columnsResult", width: '20%', ellipsis: true, render: (text, item) => <Tooltip title={text} placement="topLeft"><span className='toolTipSpan link' onClick={()=>{window.open(`/glcc/2023/subjects/detail/${item.taskId}`)}}>{text}</span></Tooltip> },
|
||||
{ title: '项目名称', dataIndex: 'projectName', className:"columnsResult", ellipsis: true, width: '14%', render: (text) => <Tooltip title={text} placement="topLeft"><span className='toolTipSpan'>{text}</span></Tooltip> },
|
||||
{ title: '操作', dataIndex: 'action', align: 'center', className:"columnsResult actionBox"},
|
||||
]
|
||||
|
|
@ -107,11 +105,10 @@ function CheckResult({current_user, history}) {
|
|||
|
||||
return (
|
||||
<div className="resultListBox">
|
||||
{time && <img className="resultBanner" src={resultBanner} alt=""></img>}
|
||||
{new Date().getTime() > new Date('2022/07/01 12:0').getTime() && <img className="resultBanner" src={resultBanner2} alt=""></img>}
|
||||
<img className="resultBanner" src={resultBanner2} alt=""></img>
|
||||
<div className='bgBox'>
|
||||
<div className="resultList">
|
||||
<div className='goBackBox'><a href='/glcc'>开源夏令营 / </a>入选学生名单{time && '预'}公示</div>
|
||||
<div className='goBackBox'><a href='/glcc'>开源夏令营 / </a>入选学生名单公示</div>
|
||||
<Search className='search' placeholder='请输入学生姓名或课题名称进行搜索' allowClear enterButton onSearch={(value) => { setCurrent(1); setKeyword(value) }} />
|
||||
<Table
|
||||
loading={loading}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,206 @@
|
|||
import React from "react";
|
||||
import { Table, Input, Button, Popconfirm, Form } from 'antd';
|
||||
import { Base64 } from 'js-base64';
|
||||
|
||||
import './index.scss';
|
||||
import apply_delete from "../../img/apply_delete.png";
|
||||
|
||||
const EditableContext = React.createContext();
|
||||
|
||||
const EditableRow = ({ form, index, ...props }) => (
|
||||
<EditableContext.Provider value={form}>
|
||||
<tr {...props} />
|
||||
</EditableContext.Provider>
|
||||
);
|
||||
|
||||
const EditableFormRow = Form.create()(EditableRow);
|
||||
|
||||
class EditableCell extends React.Component {
|
||||
|
||||
save = (dataIndex, e) => {
|
||||
const { record, handleSave } = this.props;
|
||||
this.form.validateFields([dataIndex],(error, values) => {
|
||||
handleSave({ ...record, ...values });
|
||||
if (error && error[e.currentTarget.id]) {
|
||||
return;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
renderCell = form => {
|
||||
this.form = form;
|
||||
const {record, dataIndex, title } = this.props;
|
||||
return <Form.Item >
|
||||
{form.getFieldDecorator(dataIndex, {
|
||||
rules: [
|
||||
{required: true,message: `${title}不能为空.`,},
|
||||
{max: 32, message: '超出限制长度32位字符,请重新编辑' }
|
||||
],
|
||||
validateFirst: true,
|
||||
initialValue: record[dataIndex],
|
||||
})(<Input onPressEnter={(e)=>{this.save(dataIndex,e)}} onBlur={(e)=>{this.save(dataIndex,e)}} placeholder="请输入"/>)}
|
||||
</Form.Item>
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
editable,
|
||||
dataIndex,
|
||||
title,
|
||||
record,
|
||||
index,
|
||||
handleSave,
|
||||
children,
|
||||
...restProps
|
||||
} = this.props;
|
||||
return (
|
||||
<td {...restProps}>
|
||||
{editable ? (
|
||||
<EditableContext.Consumer>{this.renderCell}</EditableContext.Consumer>
|
||||
) : (
|
||||
children
|
||||
)}
|
||||
</td>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class EditableTable extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.columns = [
|
||||
{
|
||||
title: '姓名',
|
||||
dataIndex: 'real_name',
|
||||
editable: true,
|
||||
width: "40%"
|
||||
},
|
||||
{
|
||||
title: '单位',
|
||||
dataIndex: 'org_name',
|
||||
editable: true,
|
||||
width: '50%',
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'operation',
|
||||
width: '10%',
|
||||
render: (text, record) =>
|
||||
this.state.dataSource.length >= 1 ? (
|
||||
<Popconfirm title="确定删除此成员?" onConfirm={() => this.handleDelete(record.key)}>
|
||||
<img src={apply_delete} className="apply_delete" alt=""/>
|
||||
</Popconfirm>
|
||||
) : null,
|
||||
},
|
||||
];
|
||||
if(props.isLocal){
|
||||
this.columns = [{
|
||||
title: '姓名',
|
||||
dataIndex: 'real_name',
|
||||
editable: true,
|
||||
},
|
||||
{
|
||||
title: '单位',
|
||||
dataIndex: 'org_name',
|
||||
editable: true,
|
||||
width: '30%',
|
||||
},{
|
||||
title: '职务',
|
||||
dataIndex: 'org_job',
|
||||
editable: true,
|
||||
},
|
||||
{
|
||||
title: Base64.decode('5Yab6KGU'),
|
||||
dataIndex: 'org_rank',
|
||||
editable: true,
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'operation',
|
||||
width: '10%',
|
||||
render: (text, record) =>
|
||||
this.state.dataSource.length >= 1 ? (
|
||||
<Popconfirm title="确定删除此成员?" onConfirm={() => this.handleDelete(record.key)}>
|
||||
<img src={apply_delete} className="apply_delete" alt=""/>
|
||||
</Popconfirm>
|
||||
) : null,
|
||||
},];
|
||||
}
|
||||
this.state = {
|
||||
dataSource: this.props.members,
|
||||
count: this.props.members.length,
|
||||
};
|
||||
}
|
||||
|
||||
handleDelete = key => {
|
||||
const dataSource = [...this.state.dataSource];
|
||||
const newData = dataSource.filter(item => item.key !== key);
|
||||
this.setState({ dataSource: newData });
|
||||
this.props.setMembers(newData);
|
||||
};
|
||||
|
||||
handleAdd = () => {
|
||||
const { count, dataSource } = this.state;
|
||||
const newData = {
|
||||
key: count,
|
||||
};
|
||||
this.setState({
|
||||
dataSource: [...dataSource, newData],
|
||||
count: count + 1,
|
||||
});
|
||||
};
|
||||
|
||||
handleSave = row => {
|
||||
const newData = [...this.state.dataSource];
|
||||
const index = newData.findIndex(item => row.key === item.key);
|
||||
const item = newData[index];
|
||||
newData.splice(index, 1, {
|
||||
...item,
|
||||
...row,
|
||||
});
|
||||
this.setState({ dataSource: newData });
|
||||
this.props.setMembers(newData);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { dataSource } = this.state;
|
||||
const components = {
|
||||
body: {
|
||||
row: EditableFormRow,
|
||||
cell: EditableCell,
|
||||
},
|
||||
};
|
||||
const columns = this.columns.map(col => {
|
||||
if (!col.editable) {
|
||||
return col;
|
||||
}
|
||||
return {
|
||||
...col,
|
||||
onCell: record => ({
|
||||
record,
|
||||
editable: col.editable,
|
||||
dataIndex: col.dataIndex,
|
||||
title: col.title,
|
||||
handleSave: this.handleSave,
|
||||
}),
|
||||
};
|
||||
});
|
||||
return (
|
||||
<div className="apply_team">
|
||||
<Button onClick={this.handleAdd} type="primary" className="add_member">
|
||||
添加成员
|
||||
</Button>
|
||||
<div className="member_info">
|
||||
<Table
|
||||
components={components}
|
||||
rowClassName={() => 'editable-row'}
|
||||
dataSource={dataSource}
|
||||
columns={columns}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default EditableTable;
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
.editable-cell {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.editable-cell-value-wrap {
|
||||
padding: 5px 12px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.editable-row .editable-cell-value-wrap {
|
||||
height: 30px;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 4px;
|
||||
padding: 4px 11px;
|
||||
}
|
||||
|
||||
.member_info table{
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.member_info table tr:last-child td{
|
||||
border-bottom: none;
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
import React, { useState } from 'react';
|
||||
import { Button, Tooltip } from 'antd';
|
||||
import Nodata from '../../../forge/Nodata';
|
||||
import { useEffect } from 'react';
|
||||
import { getProjectById } from '../../api';
|
||||
|
||||
export default ({ detail, projectId }) => {
|
||||
const [info, setInfo] = useState(detail);
|
||||
|
||||
useEffect(()=>{
|
||||
if(!detail && projectId){
|
||||
// 通过项目Id查询项目详情
|
||||
getProjectById(projectId, {round: 2, isFree: true}).then(response=>{
|
||||
if(response && response.message === 'success'){
|
||||
setInfo(response.data)
|
||||
}
|
||||
})
|
||||
}
|
||||
},[detail])
|
||||
|
||||
return (
|
||||
info ? <div className={`projectDetailBox ${detail ? '':'byTask'}`}>
|
||||
<div className={`projectDetailHead`}>
|
||||
<span className='name'>{info.projectName}</span>
|
||||
{info.projectType && <span className='type'>{info.projectType}</span>}
|
||||
<p>GitLink项目地址: <a href={info.gitlinkUrl} className='linkUrl' target={"_blank"}>{info.gitlinkUrl}</a></p>
|
||||
<div>项目简介: {info.projectIntro}</div>
|
||||
</div>
|
||||
{/* 课题列表 */}
|
||||
{info.registrationTaskList && info.registrationTaskList.length ? info.registrationTaskList.map((item, index)=>{
|
||||
return <div className='taskItem mt20' key={index}>
|
||||
<div className="left">
|
||||
<div className="taskTitle"><Tooltip title={item.taskName}>{item.taskName}</Tooltip></div>
|
||||
<div className='mt20 oneLine leftWidth'>导师姓名: {item.tutorName}</div>
|
||||
{item.tutorMail && <div className='mb20 email oneLine leftWidth'>邮箱地址: <span><Tooltip title={item.tutorMail}>{item.tutorMail}</Tooltip></span></div>}
|
||||
</div>
|
||||
<div className="center">
|
||||
<div className="taskDesc"><Tooltip title={item.taskDesc}>{item.taskDesc}</Tooltip></div>
|
||||
{item.taskUrl && <div className="taskUrl oneLine">课题链接: <a href={item.taskUrl} target={"_blank"}>{item.taskUrl}</a></div>}
|
||||
<div></div>
|
||||
</div>
|
||||
<div className="right oneLine taskUrl"><span className='taskReward'>¥{item.taskReward}</span></div>
|
||||
</div>
|
||||
}) : <Nodata _html="课题暂无数据" small={true}/>}
|
||||
</div>: <div className="projectDetailBox nodata"><Nodata _html="暂无数据" small={true}/></div>
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
import React from 'react';
|
||||
import { Spin } from 'antd';
|
||||
import { Route, Switch } from "react-router-dom";
|
||||
import banner from "../img/studentProject2.png";
|
||||
import './index.scss';
|
||||
import Loadable from "react-loadable";
|
||||
import Loading from "../../Loading";
|
||||
import { Link } from 'react-router-dom';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
// 项目列表页面
|
||||
const ProjectList = Loadable({
|
||||
loader: () => import("./projectList"),
|
||||
loading: Loading,
|
||||
});
|
||||
// 课题列表页面
|
||||
const TaskList = Loadable({
|
||||
loader: () => import("./taskList"),
|
||||
loading: Loading,
|
||||
});
|
||||
|
||||
function FreeProject(propsF) {
|
||||
const {location: {pathname}} = propsF;
|
||||
useEffect(()=>{
|
||||
window.scrollTo(0, 0);
|
||||
},[])
|
||||
console.log('FreeProject');
|
||||
return(
|
||||
<div className="glcc_project">
|
||||
<div className='projectBannerBox'>
|
||||
<img className="glcc-banner" src={banner} alt=''></img>
|
||||
</div>
|
||||
<div className='head'>
|
||||
<Link to={`/glcc/freesubject`} className={!pathname.endsWith('freeproject') ? 'active' : ''}>课题列表</Link>
|
||||
<Link to={`/glcc/freeproject`} className={pathname.endsWith('freeproject') ? 'active' : ''}>项目列表</Link>
|
||||
</div>
|
||||
<div className='gobackBox'>
|
||||
<a href={`/glcc`}>开源夏令营 / </a>
|
||||
无奖金课题及项目列表
|
||||
</div>
|
||||
<div className="head_introduce mt30 mb30">
|
||||
<h4 className="head_tit">申请说明:</h4>
|
||||
<div className="head_content">1、参与GitLink编程夏令营无奖金项目的同学,<span className='head_bold'>请通过邮件或电话与课题导师直接沟通并根据导师课题要求完成课题,无需在GLCC平台报名课题</span>。</div>
|
||||
<div className="head_content">2、参与GitLink编程夏令营无奖金项目的同学,如完成课题并经导师评定通过,将会在GLCC官网进行公示(无奖金奖励)。</div>
|
||||
<div className="head_content">3、活动最终解释权归GLCC所有。</div>
|
||||
</div>
|
||||
<Spin spinning={false}>
|
||||
<Switch {...propsF}>
|
||||
<Route
|
||||
path="/glcc/freeproject"
|
||||
render={(props) => (
|
||||
<ProjectList {...propsF} {...props}/>
|
||||
)}
|
||||
></Route>
|
||||
<Route
|
||||
path="/glcc/freesubject"
|
||||
render={(props) => (
|
||||
<TaskList {...propsF} {...props}/>
|
||||
)}
|
||||
></Route>
|
||||
</Switch>
|
||||
</Spin>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default FreeProject;
|
||||
|
|
@ -0,0 +1,229 @@
|
|||
.glcc_project{
|
||||
background-color: #ebf2ff;
|
||||
.head{
|
||||
background-color:rgba(188, 208, 255, 0.27);
|
||||
border:1px solid #ffffff;
|
||||
text-align: center;
|
||||
a{
|
||||
padding: 18px 20px 20px;
|
||||
display: inline-block;
|
||||
color: #273778;
|
||||
font-size: 18px;
|
||||
font-weight:700;
|
||||
line-height: 30px;
|
||||
&.active{
|
||||
border-bottom: 1px solid #5474df;;
|
||||
}
|
||||
&:last-child{
|
||||
margin-left: 40px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.gobackBox{
|
||||
width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 25px 0 12px;
|
||||
color: #202d40;
|
||||
font-size: 16px;
|
||||
border-bottom: 1px dashed #bec5d5;
|
||||
a{
|
||||
color:#a4aabb;
|
||||
}
|
||||
}
|
||||
.listBox{
|
||||
background-image:linear-gradient(180deg,#ebf2ff 0%,#ebf2ff 43.09%,#f3f4f8 100%);
|
||||
position: relative;
|
||||
.bgPng3, .bgPng4{
|
||||
width: 146px;
|
||||
position: absolute;
|
||||
z-index: 0;
|
||||
top: 162px;
|
||||
left: 100px;
|
||||
}
|
||||
.bgPng4{
|
||||
top: 450px;
|
||||
left: auto;
|
||||
right: 310px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.glcc-banner {
|
||||
width: 100%;
|
||||
}
|
||||
// 项目详情框
|
||||
.projectDetailBox{
|
||||
&.byTask{
|
||||
background-image:linear-gradient(180deg,#f1f5ff 0%,#ffffff 100%);
|
||||
border:1px solid #ffffff;
|
||||
border-radius:4px;
|
||||
box-shadow:0px 0px 10px rgba(100, 141, 255, 0.2);
|
||||
padding: 30px 30px 50px;
|
||||
.taskItem{
|
||||
.center{
|
||||
width: 640px;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.nodata{width: 200px;}
|
||||
font-size:15px;
|
||||
line-height:30px;
|
||||
.projectDetailHead{
|
||||
color:#465474;
|
||||
padding-bottom: 12px;
|
||||
border-bottom: 1px dashed #bec5d5;
|
||||
line-height: 36px;
|
||||
&.byResult{
|
||||
margin: -15px -10px -40px;
|
||||
border-bottom: none;
|
||||
}
|
||||
.name{
|
||||
font-weight:700;
|
||||
color:#3753c5;
|
||||
font-size:20px;
|
||||
}
|
||||
.type{
|
||||
display: inline-block;
|
||||
border:1px solid #6680bb;
|
||||
border-radius:4px;
|
||||
margin-left: 12px;
|
||||
padding: 4px 6px;
|
||||
line-height: 26px;
|
||||
}
|
||||
.linkUrl{
|
||||
color: #466aff;
|
||||
}
|
||||
}
|
||||
.taskItem {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
border:1px solid #ffffff;
|
||||
&:hover{ box-shadow: 0px 0px 12px rgba(71, 105, 198, 0.4);}
|
||||
.oneLine{
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.left{
|
||||
width: 316px;
|
||||
background-image: url('../img/projectDetailTaskBg.png');
|
||||
background-size: 100% 100%;
|
||||
padding: 22px 20px;
|
||||
color:#25304a;
|
||||
.taskTitle{
|
||||
color:#1834a7;
|
||||
font-size:18px;
|
||||
display: -webkit-box;
|
||||
overflow: hidden;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.email span{color:#466aff;}
|
||||
.leftWidth{width: 270px;}
|
||||
}
|
||||
.center{
|
||||
width: 665px;
|
||||
text-align: left;
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
.taskDesc{
|
||||
color:#6b6b6b;
|
||||
display: -webkit-box;
|
||||
overflow: hidden;
|
||||
-webkit-line-clamp: 3;
|
||||
-webkit-box-orient: vertical;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.taskUrl{
|
||||
color:#465474;
|
||||
font-size:16px;
|
||||
line-height: 28px;
|
||||
margin-bottom: 5px;
|
||||
a{color:#466aff;}
|
||||
}
|
||||
.applyBut{
|
||||
background-color:#466aff;
|
||||
border-color: #466aff;
|
||||
&:hover{background-color:#5d7cff;}
|
||||
&:focus{background-color:#1140ff;}
|
||||
}
|
||||
.taskReward{color:#ff8800;}
|
||||
}
|
||||
.right{
|
||||
margin-top: 35px;
|
||||
padding-right: 10px;
|
||||
width: 120px;
|
||||
font-weight:700;
|
||||
color:#ff8800;
|
||||
font-size:24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.ant-popover.projectItemPopover{
|
||||
width: 1200px;
|
||||
z-index: 1000;
|
||||
.ant-popover-content .ant-popover-arrow{
|
||||
border-width: 12px;
|
||||
}
|
||||
}
|
||||
.projectItemPopover .ant-popover-inner{
|
||||
transform: translateY(8px);
|
||||
background-image:linear-gradient(180deg,#f1f5ff 0%,#ffffff 100%);
|
||||
border:1px solid #ffffff;
|
||||
border-radius:4px;
|
||||
box-shadow:0px 0px 10px rgba(100, 141, 255, 0.2);
|
||||
.ant-popover-inner-content{
|
||||
padding: 30px 30px 50px;
|
||||
}
|
||||
}
|
||||
.lookDetail{
|
||||
border-color: #466aff;
|
||||
color: #466aff;
|
||||
&:hover{
|
||||
border-color: #5d7cff;
|
||||
color: #5d7cff;
|
||||
}
|
||||
&:focus{
|
||||
border-color: #1140ff;
|
||||
color: #1140ff;
|
||||
}
|
||||
}
|
||||
.projectBannerBox{
|
||||
position: relative;
|
||||
.stuApplytimeBox{
|
||||
background-image: url('../img/studentProject1.png');
|
||||
position: absolute;
|
||||
color: #FFDC95;
|
||||
font-size: 20px;
|
||||
bottom: 28%;
|
||||
left: 50%;
|
||||
margin-left: -250px;
|
||||
width: 500px;
|
||||
height: 60px;
|
||||
line-height: 60px;
|
||||
text-align: center;
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
}
|
||||
.head_introduce {
|
||||
width: 1200px;
|
||||
margin: 0 auto;
|
||||
background: #e4edff;
|
||||
padding: 20px;
|
||||
}
|
||||
.head_tit {
|
||||
color: #000000;
|
||||
font-size: 15px;
|
||||
line-height: 2;
|
||||
}
|
||||
.head_content {
|
||||
color: #6c7283;
|
||||
font-size: 14px;
|
||||
line-height: 38px;
|
||||
}
|
||||
.head_bold {
|
||||
font-weight: 700;
|
||||
color: #333;
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { Input, Popover, Spin } from 'antd';
|
||||
import { main_site_url } from '../../fetch';
|
||||
import './index.scss';
|
||||
import { freeProjectList, projectList } from '../../api';
|
||||
import ProjectDetail from '../component/projectDetail';
|
||||
import bgPng from "../../img/bgPng.png";
|
||||
import logo from "../../img/logo.png";
|
||||
import star from "../../img/star.png";
|
||||
import Nodata from '../../../forge/Nodata';
|
||||
const { Search } = Input;
|
||||
|
||||
// 项目列表
|
||||
function ProjectList() {
|
||||
const [data, setData] = useState([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setLoading(true);
|
||||
const params = {
|
||||
curPage: 1,
|
||||
pageSize: 10000,
|
||||
round: 2
|
||||
}
|
||||
freeProjectList(params).then(response => {
|
||||
if (response && response.message === "success") {
|
||||
setData(response.data.rows);
|
||||
}
|
||||
setLoading(false);
|
||||
})
|
||||
}, [])
|
||||
|
||||
// 修改taskList盒子的高度,防止弹框过高影响整体页面
|
||||
function changeVisible(visible, item) {
|
||||
if (visible) {
|
||||
let height = document.documentElement.clientWidth / 1920 * 500 + 70 + document.querySelector(`.${item.gitlinkLastUrl}`).offsetTop + item.registrationTaskList.length * 320;
|
||||
document.querySelector('#taskList').style.height = height + 'px';
|
||||
} else {
|
||||
document.querySelector('#taskList').style.height = 'auto';
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div id="taskList" className="taskList listBox">
|
||||
<Spin spinning={loading}>
|
||||
<div className='projectListBox'>
|
||||
{data && data.map((item, index) => {
|
||||
return <Popover
|
||||
onVisibleChange={(visible) => { changeVisible(visible, item) }}
|
||||
key={index}
|
||||
placement={(index + 1) % 3 === 0 ? 'bottomRight' : (index + 1) % 3 % 2 === 0 ? 'bottom' : 'bottomLeft'}
|
||||
content={<ProjectDetail detail={item}/>}
|
||||
trigger='click'
|
||||
overlayClassName='projectItemPopover'
|
||||
autoAdjustOverflow={false}
|
||||
>
|
||||
<div className={`projectItem ${(index + 1) % 3 === 0 || (index + 1) % 3 % 2 === 0 ? '' : 'firstBox'} ${item.projectName.replace(/ /g, '')} ${item.gitlinkLastUrl}`}>
|
||||
<div className="border"></div>
|
||||
<div className="projectLogo">
|
||||
<img className="projectLogoImg" src={item.projectLogoId ? `${main_site_url}/api/attachments/${item.projectLogoId}` : logo} alt='' />
|
||||
</div>
|
||||
<div className="title">{item.projectName}</div>
|
||||
<div className="intro">{item.projectIntro}</div>
|
||||
</div>
|
||||
</Popover>
|
||||
})}
|
||||
</div>
|
||||
{data && !data.length && <div style={{paddingBottom: '50px'}}><Nodata _html="暂无数据"/></div>}
|
||||
</Spin>
|
||||
<img src={bgPng} alt='' className='bgPng3' />
|
||||
<img src={bgPng} alt='' className='bgPng4' />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default ProjectList;
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
.projectListBox{
|
||||
width: 1200px;
|
||||
margin: 0 auto;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
// justify-content: space-between;
|
||||
.projectItem{
|
||||
position: relative;
|
||||
width: 30%;
|
||||
background-image: linear-gradient(180deg,rgba(232, 237, 255, 0.85) 0%,rgba(255, 255, 255, 0.85) 100%);
|
||||
border: 1px solid;
|
||||
border-color: #ffffff;
|
||||
border-radius: 4px;
|
||||
box-shadow:0px 0px 8px rgba(93, 131, 255, 0.26);
|
||||
text-align: center;
|
||||
margin-bottom: 50px;
|
||||
background-image: url('../../img/projectBg.png');
|
||||
background-size: 100% 100%;
|
||||
margin-left: 5%;
|
||||
&.firstBox{
|
||||
margin-left: 0;
|
||||
}
|
||||
&:hover{
|
||||
cursor: pointer;
|
||||
background-image: none;
|
||||
// #E8EDFF—#FFFFFF(85%)
|
||||
background-image: linear-gradient(180deg,rgba(232, 237, 255, 0.85) 0%,rgba(255, 255, 255, 0.85) 100%);
|
||||
}
|
||||
.border{
|
||||
height: 5px;
|
||||
background-color:#657edf;
|
||||
border-radius:2px 2px 0px 0px;
|
||||
}
|
||||
.projectLogoStar{
|
||||
position: absolute;
|
||||
top:30px;
|
||||
right: 130px;
|
||||
width: 28px;
|
||||
z-index: 10;
|
||||
transform: rotate(46deg);
|
||||
}
|
||||
.projectLogo{
|
||||
position: relative;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
border: 1px solid #fff;
|
||||
background-color: #fff;
|
||||
border-radius: 50%;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
margin: 25px auto 10px;
|
||||
line-height: 95px;
|
||||
.projectLogoImg{
|
||||
width: 100%;
|
||||
// height: 100%;
|
||||
// display: block;
|
||||
}
|
||||
|
||||
}
|
||||
.title{
|
||||
color:#2a51bf;
|
||||
font-size:17px;
|
||||
line-height:30px;
|
||||
margin-bottom: 15px;
|
||||
padding: 0 50px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.intro{
|
||||
color:#4f5d84;
|
||||
font-size:15px;
|
||||
margin-bottom: 15px;
|
||||
display: -webkit-box;
|
||||
overflow: hidden;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
text-overflow: ellipsis;
|
||||
text-align: left;
|
||||
padding: 0 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { Table, Tooltip } from 'antd';
|
||||
import './index.scss';
|
||||
import { freeTaskList, taskList } from '../../api';
|
||||
import ProjectDetail from '../component/projectDetail';
|
||||
import bgPng from "../../img/bgPng.png";
|
||||
|
||||
// 课题列表
|
||||
function TaskList() {
|
||||
const [data, setData] = useState([]);
|
||||
// table
|
||||
const [current, setCurrent] = useState(1);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [pageSize, setPageSize] = useState(20);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [expandedRowKeys, setExpandedRowKeys] = useState([]);
|
||||
|
||||
const columns = [
|
||||
{ title: '序号', dataIndex: 'index', align: 'center', className:"taskTableColumns", width: '6%', render: (text, item, index) => <span>{(current-1)*pageSize+index + 1}</span> },
|
||||
{ title: '课题名称', dataIndex: 'taskName', className:"taskTableColumns taskName", width: '28%', ellipsis: true, render: (text, item) => <Tooltip title={text} placement="topLeft"><span>{text}</span></Tooltip> },
|
||||
{ title: '课题类型', dataIndex: 'projectType', className:"taskTableColumns", width: '12%', ellipsis: true, },
|
||||
{ title: '项目名称', dataIndex: 'projectName', className:"taskTableColumns", width: '24%', ellipsis: true, render: (text) => <Tooltip title={text} placement="topLeft">{text}</Tooltip> },
|
||||
{ title: '课题奖金', dataIndex: 'taskReward', className:"taskTableColumns", ellipsis: true, width: '10%', render: (text) => <Tooltip title={text} placement="topLeft"><span>{text}</span></Tooltip> },
|
||||
{ title: '操作', dataIndex: 'action', align: 'center', className:"actionColumns taskTableColumns"},
|
||||
]
|
||||
|
||||
const customExpandIcon = (props) => {
|
||||
if (props.expanded) {
|
||||
return <a className='actionBox' style={{marginRight: 8 }} onClick={e => {
|
||||
props.onExpand(props.record, e);
|
||||
}}><i className='iconfont icon-ketixiangqingicon mr5'></i>项目详情<i className="iconfont icon-changyongtubiao-xianxingdaochu-zhuanqu- font-12 ml5 down mr10"></i></a>
|
||||
} else {
|
||||
return <a className='actionBox' style={{marginRight: 8 }} onClick={e => {
|
||||
props.onExpand(props.record, e);
|
||||
}}><i className='iconfont icon-ketixiangqingicon mr5'></i>项目详情<i className="iconfont icon-jiantou9 font-12 ml5 down mr10"></i></a>
|
||||
}
|
||||
}
|
||||
|
||||
const expandRow = (record) => {
|
||||
return <ProjectDetail detail={null} projectId={record.regId}/>
|
||||
}
|
||||
|
||||
// 展开收起行回调
|
||||
function onExpand(expanded, record){
|
||||
const keys = new Set(expandedRowKeys);
|
||||
if(expanded){
|
||||
keys.add(record.id);
|
||||
}else{
|
||||
keys.delete(record.id);
|
||||
}
|
||||
setExpandedRowKeys(Array.from(keys));
|
||||
}
|
||||
|
||||
// 改变pagesize
|
||||
function onShowSizeChange(current, pageSize){
|
||||
window.scrollTo(0, 0);
|
||||
setCurrent(1);
|
||||
setPageSize(pageSize);
|
||||
}
|
||||
|
||||
// 切换页数
|
||||
function changePage(page, pageSize){
|
||||
window.scrollTo(0, 0);
|
||||
setCurrent(page);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
setExpandedRowKeys([]);
|
||||
setLoading(true);
|
||||
const params = {
|
||||
curPage: current,
|
||||
pageSize,
|
||||
round: 2
|
||||
}
|
||||
freeTaskList(params).then(response => {
|
||||
if (response && response.message === "success") {
|
||||
setData(response.data.rows);
|
||||
setTotal(response.data.total);
|
||||
}
|
||||
setLoading(false);
|
||||
})
|
||||
}, [current, pageSize])
|
||||
|
||||
return (
|
||||
<div className="taskList listBox">
|
||||
<div className="listTable">
|
||||
<Table
|
||||
loading={loading}
|
||||
columns={columns}
|
||||
dataSource={data}
|
||||
expandedRowRender={expandRow}
|
||||
expandIconColumnIndex={5}
|
||||
expandIconAsCell={false}
|
||||
expandIcon={customExpandIcon}
|
||||
rowKey={'id'}
|
||||
expandedRowKeys={expandedRowKeys}
|
||||
onExpand={onExpand}
|
||||
pagination={{current: current, pageSize: pageSize, total: total, showSizeChanger: true, onShowSizeChange:onShowSizeChange, showQuickJumper: true, onChange: changePage}}
|
||||
/>
|
||||
</div>
|
||||
<img src={bgPng} alt='' className='bgPng3'/>
|
||||
<img src={bgPng} alt='' className='bgPng4'/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default TaskList;
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
.taskList{
|
||||
padding-bottom: 50px;
|
||||
.ant-table{
|
||||
border: 1px solid white;
|
||||
}
|
||||
.ant-pagination-item-active, .ant-pagination-item:hover, .ant-pagination-next:not(.ant-pagination-disabled) .ant-pagination-item-link:hover, .ant-select-selection:hover, .ant-pagination-options-quick-jumper:hover input{
|
||||
border-color: #466aff;
|
||||
a{color: #466aff;}
|
||||
}
|
||||
.ant-pagination-disabled .ant-pagination-item-link:hover .anticon{
|
||||
color: rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
.listTable{
|
||||
width: 1200px;
|
||||
margin: 0 auto;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
.taskTableColumns span div span{
|
||||
font-size: 16px;
|
||||
font-weight:700;
|
||||
color:#273778;
|
||||
}
|
||||
.taskTableColumns span{
|
||||
font-size: 15px;
|
||||
color: #353f5e;
|
||||
}
|
||||
.ant-table-tbody .taskTableColumns.taskName span{
|
||||
color: #2545c9;
|
||||
}
|
||||
.ant-table-thead > tr > .taskTableColumns, .ant-table-tbody > tr > .taskTableColumns{
|
||||
background-color:#F1F6FF;
|
||||
border-bottom: 1px dashed #bec5d5;
|
||||
}
|
||||
.ant-table-tbody > tr:hover:not(.ant-table-expanded-row):not(.ant-table-row-selected) > .taskTableColumns{
|
||||
background-color:#fbfbfc;
|
||||
}
|
||||
.actionColumns{
|
||||
display: flex;
|
||||
.actionBox, .actionBox span{
|
||||
cursor: pointer;
|
||||
color: #466aff;
|
||||
&:hover{color:#5d7cff !important;}
|
||||
&:active{color:#1140ff !important;}
|
||||
&.disabled .disabled{
|
||||
&:hover, &:active{color:#a4aabb !important;}
|
||||
color:#a4aabb;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
.applyTask, span.applyTask{
|
||||
color:#eb9350;
|
||||
&:hover{color: #FFB074 !important;}
|
||||
&:active{color:#D66A17 !important;}
|
||||
}
|
||||
.cancelApply{visibility: hidden;}
|
||||
}
|
||||
tr:hover .actionColumns .cancelApply{
|
||||
visibility: visible;
|
||||
color: #E31E1E;
|
||||
}
|
||||
.cancelApplyTask{
|
||||
.ant-modal-close{top: 0px !important;}
|
||||
.ant-modal-header{
|
||||
padding: 8px 20px;
|
||||
background-color: #e9edff;
|
||||
.ant-modal-title{text-align: left;}
|
||||
}
|
||||
.carefulIcon{
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
background: #ca0002;
|
||||
display: inline-block;
|
||||
border-radius: 50%;
|
||||
text-align: center;
|
||||
line-height: 36px;
|
||||
font-size: 18px;
|
||||
color: white;
|
||||
margin-right: 15px;
|
||||
}
|
||||
.tilTask{
|
||||
color:#333333;
|
||||
font-size:16px;
|
||||
margin-left: 35px;
|
||||
}
|
||||
.tipTask{
|
||||
color:#666666;
|
||||
font-size:14px;
|
||||
margin: 10px 0 10px 37px!important;
|
||||
}
|
||||
.tipTaskTime{
|
||||
font-size: 36px;
|
||||
color: #df0002;
|
||||
}
|
||||
.ant-modal-footer{
|
||||
border-top: none;
|
||||
text-align: center;
|
||||
padding-bottom: 50px;
|
||||
.ant-btn{
|
||||
&.ant-btn-default{
|
||||
color: #df0002;
|
||||
}
|
||||
&:hover{
|
||||
border-color: #466aff;
|
||||
color: #466aff;
|
||||
&.ant-btn-default{
|
||||
border-color: #df0002;
|
||||
color: #df0002;}
|
||||
}
|
||||
}
|
||||
.ant-btn-default{
|
||||
margin-left:43px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -21,7 +21,7 @@ function Help(props) {
|
|||
projectId: locationStatus ? '1403908' : '546103'
|
||||
}).then(res => {
|
||||
if (res && res.message === "200" && Array.isArray(res.data)) {
|
||||
setFileArrInit(res.data);
|
||||
setFileArrInit(res.data.filter(item=>item.name !== "_Sidebar"));
|
||||
if (res.data.length) {
|
||||
setCheckItem(res.data[0]);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
border:1px solid;
|
||||
border-color:#ffffff;
|
||||
margin-right: 40px;
|
||||
min-height: 450px;
|
||||
}
|
||||
.wiki_title{
|
||||
cursor: pointer;
|
||||
|
|
|
|||
|
|
@ -18,53 +18,25 @@ import logo from "../img/openmmlab/logo1.png";
|
|||
import { hasAuditRole } from '../api';
|
||||
import './index.scss';
|
||||
|
||||
// round:2022届(1) 2023届(2)
|
||||
// period: 项目报名阶段("repoApply")
|
||||
// match:{params:{id=2023}} 注意默认值记得每届修改
|
||||
export default (props) => {
|
||||
const { current_user, isGlccApplyDate, showNotification, studentApplyStart, history, secondStudentApplyDate, isStudentApplyDate, checkedTaskId, checkTime1, checkTime2, checkTime3 } = props;
|
||||
// function goToApply() {
|
||||
// if (isGlccApplyDate) {
|
||||
// if (current_user && current_user.login) {
|
||||
// window.location.href = "https://wj.qq.com/s2/10175205/e8df/";
|
||||
// } else {
|
||||
// window.location.href = "/login?go_page=https://wj.qq.com/s2/10175205/e8df/";
|
||||
// }
|
||||
// } else {
|
||||
// showNotification("不在报名时间,报名时间为4月15日~5月20日");
|
||||
// window.location.href = "/glcc";
|
||||
// }
|
||||
// }
|
||||
|
||||
const [hasRole, setHasRole] = useState(false);
|
||||
const resultTime1 = new Date().getTime() > new Date('2022/06/28 1:0').getTime() && new Date().getTime() < new Date('2022/07/01 0:0').getTime();
|
||||
const resultTime2 = new Date().getTime() > new Date('2022/07/01 12:0').getTime() && new Date().getTime() < new Date('2022/08/12 0:0').getTime();
|
||||
const { current_user, history, round, match:{params:{id=2023}}, period, showLoginDialog, glccSettings, repoPublic, showMatchingBut, isResultPublic} = props;
|
||||
|
||||
useEffect(() => {
|
||||
if (!current_user.user_id) {
|
||||
history.push('/403');
|
||||
}
|
||||
hasAuditRole({ userId: current_user.user_id }).then(res => {
|
||||
if (res && res.message == 'success' && res.data.hasRole) {
|
||||
setHasRole(true);
|
||||
}
|
||||
})
|
||||
}, [])
|
||||
|
||||
function goToStudent() {
|
||||
// 学生报名时间
|
||||
if (!studentApplyStart) {
|
||||
showNotification("不在报名时间,报名开始时间为5月26日");
|
||||
} else if(!isStudentApplyDate && !secondStudentApplyDate) {
|
||||
showNotification("课题申请时间已截止");
|
||||
} else{
|
||||
history.push("/glcc/subjects");
|
||||
// 页面跳转,判断是否登录
|
||||
function gotoCheckLogin(url){
|
||||
if(current_user && current_user.login){
|
||||
history.push(url);
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
function goToCheck() {
|
||||
history.push("/glcc/mentoradmin");
|
||||
}
|
||||
|
||||
function goToCheckResult(){
|
||||
history.push("/glcc/result");
|
||||
showLoginDialog(url);
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
@ -74,72 +46,108 @@ export default (props) => {
|
|||
{/* <div > */}
|
||||
{/* <Link className="apply-btn" to={isGlccApplyDate ? current_user && current_user.login ? 'https://wj.qq.com/s2/10175205/e8df/' : '/login?go_page=/glcc/apply' : '/glcc'} onClick={()=>{!isGlccApplyDate && showNotification("不在报名时间,报名时间为4月15日~5月20日")}}> */}
|
||||
{/* <div className="apply-btn" onClick={goToApply}>
|
||||
<div className="apply-text">立即报名</div>
|
||||
<div className="apply-icon"><i className="font-14 iconfont icon-xiangyoujiantou "></i></div>
|
||||
</div> */}
|
||||
{/* 报名入口 */}
|
||||
<div className="applyBox">
|
||||
{/* 6.28.-7.1 审核结果仅对导师可见,7.1之后对所有用户可见*/}
|
||||
{resultTime2 && <div className="apply" onClick={goToCheckResult}>
|
||||
<div>
|
||||
<img src={apply2} alt="" className="applyIcon" />
|
||||
<span className="til">名单{resultTime1 ? '预' : ''}公示</span>
|
||||
</div>
|
||||
<div className="pt6">查看各课题入选学生名单</div>
|
||||
</div>}
|
||||
|
||||
{/* 学生结项考核 */}
|
||||
{!hasRole && checkTime1 && checkedTaskId && <Link className="apply" to={`/glcc/submission`}>
|
||||
<div>
|
||||
<img src={img1} alt="" className="applyIcon" />
|
||||
<span className="til">结项考核</span>
|
||||
</div>
|
||||
<div className="pt6">学生提交考核材料</div>
|
||||
</Link>}
|
||||
{/* 导师结项考核 */}
|
||||
{hasRole && new Date().getTime() > new Date('2022/10/01 8:0').getTime() && <Link className="apply" to={`/glcc/final/examination`}>
|
||||
<div>
|
||||
<img src={img1} alt="" className="applyIcon" />
|
||||
<span className="til">结项考核</span>
|
||||
</div>
|
||||
<div className="pt6">导师拟定结项考核结果</div>
|
||||
</Link>}
|
||||
{/* 结项考核结果公示页 */}
|
||||
{checkTime3 && <Link className="apply" to={`/glcc/final/result`}>
|
||||
<div className="apply-text">立即报名</div>
|
||||
<div className="apply-icon"><i className="font-14 iconfont icon-xiangyoujiantou "></i></div>
|
||||
</div> */}
|
||||
{/* 往期回顾 */}
|
||||
{round !== 2 && <div className="applyBox">
|
||||
<Link className="apply" to={`/glcc/${id}/final/result`}>
|
||||
<div>
|
||||
<img src={img1} alt="" className="applyIcon" />
|
||||
<span className="til">考核结果</span>
|
||||
</div>
|
||||
<div className="pt6">结项课题考核结果公示</div>
|
||||
</Link>}
|
||||
|
||||
{/* 项目报名 */}
|
||||
<Link to="/glcc/projects" className="apply project" >
|
||||
</Link>
|
||||
<Link to={`/glcc/${id}/projects`} className="apply project" >
|
||||
<div>
|
||||
<img src={apply1} alt="" className="applyIcon" />
|
||||
<span className="hover-none"><span className="til">查看项目</span> </span>
|
||||
{/* <span className="hover-show">项目报名已截止</span> */}
|
||||
</div>
|
||||
<div className="pt6">掌握项目课题详细信息</div>
|
||||
</Link>
|
||||
</div>}
|
||||
{/* 当前glcc */}
|
||||
{round === 2 && <div className="applyBox">
|
||||
{/* 项目报名入口 */}
|
||||
{period === "repoApply" && <a onClick={()=>{gotoCheckLogin(`/glcc/apply`)}} className="apply project" >
|
||||
<div>
|
||||
<img src={apply1} alt="" className="applyIcon" />
|
||||
<span className="hover-none"><span className="til">项目报名</span> </span>
|
||||
{/* <span className="hover-show">项目报名已截止</span> */}
|
||||
</div>
|
||||
<div className="pt6">项目报名开启,导师席位虚位以待</div>
|
||||
</a>}
|
||||
|
||||
{/* 查看项目、课题 */}
|
||||
{repoPublic && <Link to={`/glcc/${id}/projects`} className="apply project" >
|
||||
<div>
|
||||
<img src={apply1} alt="" className="applyIcon" />
|
||||
<span className="hover-none"><span className="til">有奖金项目</span> </span>
|
||||
</div>
|
||||
<div className="pt6">掌握项目课题详细信息</div>
|
||||
</Link>}
|
||||
|
||||
{/* 0元项目 */}
|
||||
<Link to={`/glcc/freeproject`} className="apply project" >
|
||||
<div>
|
||||
<img src={apply1} alt="" className="applyIcon" />
|
||||
<span className="hover-none"><span className="til">无奖金项目</span> </span>
|
||||
</div>
|
||||
<div className="pt6">欢迎广大学生踊跃参与</div>
|
||||
</Link>
|
||||
|
||||
{/* 学生报名6.24结束第一次报名,6.29 1:00 - 6.30 24:00第二次报名 */}
|
||||
{/* <div className="apply" onClick={goToStudent}>
|
||||
{(period === "stuApply" || period === "stuApply1") && <div className="apply" onClick={()=>{gotoCheckLogin(`/glcc/${id}/subjects`)}}>
|
||||
<div>
|
||||
<img src={apply2} alt="" className="applyIcon" />
|
||||
<span className="til">学生报名</span>
|
||||
</div>
|
||||
<div className="pt6">选择课题,开启您的开源之旅</div>
|
||||
</div> */}
|
||||
</div>}
|
||||
|
||||
{/* 导师审核 */}
|
||||
{/* {hasRole && new Date().getTime() < new Date('2022/07/01 0:0').getTime() && <div className="apply" onClick={goToCheck}>
|
||||
{showMatchingBut && <div className="apply" onClick={()=>{history.push("/glcc/mentoradmin");}}>
|
||||
<div>
|
||||
<img src={teacher} alt="" className="applyIcon" />
|
||||
<span className="til">导师审核</span>
|
||||
</div>
|
||||
<div className="pt6">以赛代筛,挖掘高潜力人才</div>
|
||||
</div>} */}
|
||||
</div>
|
||||
</div>}
|
||||
|
||||
{/* 学生-课题匹配结果公示 */}
|
||||
{isResultPublic && <div className="apply" onClick={()=>{history.push("/glcc/result");}}>
|
||||
<div>
|
||||
<img src={apply2} alt="" className="applyIcon" />
|
||||
<span className="til">名单公示</span>
|
||||
</div>
|
||||
<div className="pt6">查看各课题入选学生名单</div>
|
||||
</div>}
|
||||
|
||||
{/* 学生结项考核 */}
|
||||
{/* {!hasRole && checkedTaskId && <Link className="apply" to={`/glcc/submission`}>
|
||||
<div>
|
||||
<img src={img1} alt="" className="applyIcon" />
|
||||
<span className="til">结项考核</span>
|
||||
</div>
|
||||
<div className="pt6">学生提交考核材料</div>
|
||||
</Link>} */}
|
||||
{/* 导师结项考核 */}
|
||||
{/* {hasRole && new Date().getTime() > new Date('2022/10/01 8:0').getTime() && <Link className="apply" to={`/glcc/final/examination`}>
|
||||
<div>
|
||||
<img src={img1} alt="" className="applyIcon" />
|
||||
<span className="til">结项考核</span>
|
||||
</div>
|
||||
<div className="pt6">导师拟定结项考核结果</div>
|
||||
</Link>} */}
|
||||
{/* 结项考核结果公示页 */}
|
||||
{/* {<Link className="apply" to={`/glcc/final/result`}>
|
||||
<div>
|
||||
<img src={img1} alt="" className="applyIcon" />
|
||||
<span className="til">考核结果</span>
|
||||
</div>
|
||||
<div className="pt6">结项课题考核结果公示</div>
|
||||
</Link>} */}
|
||||
</div>}
|
||||
{/* </div> */}
|
||||
<div className="introduce">
|
||||
<div className="glcc-content">
|
||||
|
|
@ -149,7 +157,7 @@ export default (props) => {
|
|||
<img src={introduce} alt="" className="introduceImg" />
|
||||
</div>
|
||||
{/* 活动特邀合作单位 */}
|
||||
<div className="openMMlabBox">
|
||||
{round === 1 && <div className="openMMlabBox">
|
||||
<div className="logoTitle">
|
||||
<img src={logo} alt="" className="logo"/>
|
||||
<span className="title">活动特邀合作单位 OpenMMLab</span>
|
||||
|
|
@ -157,15 +165,15 @@ export default (props) => {
|
|||
<div></div>
|
||||
</div>
|
||||
<div className="intro">OpenMMLab是深度学习时代最完整的计算机视觉开源算法体系。自开源以来,累计发布了超过20个算法库,有超过300个算法2300多个预训练模型。所有算法均具备风格统一、模型丰富、质量高、易复现等特点。在社区生态上,OpenMMLab一直秉持开放、认真、持续成长的原则,积极推动社区建设发展</div>
|
||||
<div className="goToButBox"><button className="goToBut" onClick={()=>{window.location.href='/glcc/openmmlab'}}>查看详情</button></div>
|
||||
</div>
|
||||
<div className="goToButBox"><button className="goToBut" onClick={()=>{window.location.href='/glcc/openmmlab/2022'}}>查看详情</button></div>
|
||||
</div>}
|
||||
</div>
|
||||
</div>
|
||||
<Lightspot isGlccApplyDate={isGlccApplyDate} current_user={current_user} showNotification={showNotification} goToStudent={goToStudent}/>
|
||||
<TimerShaft />
|
||||
<Lightspot id={id} period={period} history={history} current_user={current_user} round={round} showLoginDialog={showLoginDialog}/>
|
||||
<TimerShaft round={round} glccSettings={glccSettings}/>
|
||||
<Award />
|
||||
<News />
|
||||
<Partner />
|
||||
<Partner round={round}/>
|
||||
<Contact />
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -185,6 +185,7 @@
|
|||
}
|
||||
.introduceBox{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.introduceImg{
|
||||
width: 32vw;
|
||||
margin-left: 3vw;
|
||||
|
|
|
|||
|
|
@ -1,30 +1,21 @@
|
|||
import { Button } from 'antd';
|
||||
import React from 'react';
|
||||
import teacherImg from '../../img/teacher-img.png';
|
||||
import lightspot1 from '../../img/lightspot1.png';
|
||||
import lightspot2 from '../../img/lightspot2.png';
|
||||
import lightspot3 from '../../img/lightspot3.png';
|
||||
import lightspot4 from '../../img/lightspot4.png';
|
||||
|
||||
|
||||
import './index.scss';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
|
||||
function Lightspot(props) {
|
||||
const {current_user, isGlccApplyDate, showNotification, goToStudent} = props;
|
||||
const {current_user, period, history, round, showLoginDialog, id} = props;
|
||||
|
||||
function goToApply(){
|
||||
if(isGlccApplyDate){
|
||||
if(current_user && current_user.login){
|
||||
window.location.href="https://wj.qq.com/s2/10175205/e8df/";
|
||||
}else{
|
||||
window.location.href="/login?go_page=https://wj.qq.com/s2/10175205/e8df/";
|
||||
}
|
||||
}else{
|
||||
showNotification("不在报名时间,报名时间为4月15日~5月20日");
|
||||
window.location.href="/glcc";
|
||||
const url = period === "repoApply" ? `/glcc/apply` : `/glcc/${id}/subjects`;
|
||||
if(current_user && !current_user.login){
|
||||
showLoginDialog(url);
|
||||
return;
|
||||
}
|
||||
history.push(url);
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
@ -36,17 +27,13 @@ function Lightspot(props) {
|
|||
<div className="teacher-text">
|
||||
<h3 className="teacher-invite">有兴趣成为GLCC的导师吗?</h3>
|
||||
<div className="teacher-content">想要扩大项目知名度和影响力,为开源项目吸引新鲜血液,培养长期开发者。通过GitLink平台,与高校建立连接,指导开源新人传授他们的开源文化,享受开源的乐趣</div>
|
||||
{/* <Link className='applyBut' to={isGlccApplyDate ? current_user && current_user.login ? 'https://wj.qq.com/s2/10175205/e8df/' : '/login?go_page=/glcc/apply' : '/glcc'} onClick={()=>{!isGlccApplyDate && showNotification("不在报名时间,报名时间为4月15日~5月20日")}}>立即报名</Link> */}
|
||||
{/* onClick={goToApply} */}
|
||||
<div className='applyBut project'><span className='hover-none'>项目报名</span><span className='hover-show'>项目报名已截止</span></div>
|
||||
{period === "repoApply" && round === 2 ? <div className='applyBut' onClick={goToApply}>立即报名</div> : <div className='applyBut project'><span className='hover-none'>项目报名</span><span className='hover-show'>已结束</span></div>}
|
||||
</div>
|
||||
<div className="teacher-text">
|
||||
<h3 className="teacher-invite">你是开源新手,有兴趣参加GLCC吗?</h3>
|
||||
<div className="teacher-content">想要参与一线开源项目开发,熟悉开源社区运作流程,接受资深开源软件专家指导,获得丰厚奖金和实习机会。参加GLCC,开启全新的开源之旅。</div>
|
||||
{/* <Link className='applyBut' to={isGlccApplyDate ? current_user && current_user.login ? 'https://wj.qq.com/s2/10175205/e8df/' : '/login?go_page=/glcc/apply' : '/glcc'} onClick={()=>{!isGlccApplyDate && showNotification("不在报名时间,报名时间为4月15日~5月20日")}}>立即报名</Link> */}
|
||||
<div className='applyBut' onClick={goToStudent}>学生报名</div>
|
||||
{(period === "stuApply" || period === "stuApply1") && round === 2 ? <div className='applyBut' onClick={goToApply}>学生报名</div> : <div className='applyBut project'><span className='hover-none'>学生报名</span><span className='hover-show'>{period === "repoApply" && round === 2 ? "敬请期待" : "已结束"}</span></div>}
|
||||
</div>
|
||||
{/* <img className="teacher-img" src={teacherImg} alt=''></img> */}
|
||||
</div>
|
||||
|
||||
<div className="info-student">
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ import sponsor31 from '../../img/sponsor31.png';
|
|||
import sponsor32 from '../../img/sponsor32.png';
|
||||
import sponsor33 from '../../img/sponsor33.png';
|
||||
import sponsor41 from '../../img/sponsor41.png';
|
||||
|
||||
|
||||
import sponsor42 from '../../img/sponsor42.png';
|
||||
import sponsor43 from '../../img/sponsor43.png';
|
||||
import log34 from '../../img/34@2x.png';
|
||||
import log35 from '../../img/35@2x.png';
|
||||
import log36 from '../../img/36@2x.png';
|
||||
|
|
@ -38,13 +38,38 @@ import log69 from '../../img/69@2x.png';
|
|||
import log70 from '../../img/浙江大学.png';
|
||||
import logo1 from '../../img/logo1.png';
|
||||
import logo2 from '../../img/logo2.png';
|
||||
function Partner() {
|
||||
function Partner({round}) {
|
||||
|
||||
return (
|
||||
<div className="partner">
|
||||
<div className="glcc-content">
|
||||
<h3 className="glcc-tit">组织方及合作伙伴</h3>
|
||||
<div className='cont1 cont mb10'>
|
||||
{round === 2 && <div className='cont1 cont mb10'>
|
||||
<div>
|
||||
主办方
|
||||
<div onClick={() => { window.open("https://www.ccf.org.cn/") }} className='div8b9'><img src={ccf1} /></div>
|
||||
</div>
|
||||
<div>
|
||||
承办方
|
||||
<div onClick={() => { window.open("https://www.zhejianglab.com/home") }} className='div8b9'><img src={sponsor42} alt='之江实验室' className='gitlink'/></div>
|
||||
</div>
|
||||
<div>
|
||||
协办方
|
||||
<div className='flex_div'>
|
||||
<div onClick={() => { window.open("https://www.gitlink.org.cn/") }} className='div8b9 mr35'><img src={gitlink} className='gitlink' /></div>
|
||||
<div onClick={() => { window.open("http://111.8.36.180:81/#/about") }} className='div8b9'><img src={xjy} className='xjy' /></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>}
|
||||
|
||||
{/* {round === 2 && <div className='cont cont3 mt15'>
|
||||
钻石赞助商
|
||||
<div className='pt10'>
|
||||
<div className="sponsor" onClick={() => { window.open("https://www.bytedance.com/") }}><img src={sponsor43} className='gitlink' alt='字节跳动' /></div>
|
||||
</div>
|
||||
</div>} */}
|
||||
|
||||
{round === 1 && <div className='cont1 cont mb10'>
|
||||
<div>
|
||||
主办方
|
||||
<div onClick={() => { window.open("https://www.ccf.org.cn/") }} className='div8b9'><img src={ccf1} /></div>
|
||||
|
|
@ -60,39 +85,39 @@ function Partner() {
|
|||
<div onClick={() => { window.open("http://111.8.36.180:81/#/about") }} className='div8b9'><img src={xjy} className='xjy' /></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>}
|
||||
|
||||
<div className='cont cont3 mt15'>
|
||||
{round === 1 && <div className='cont cont3 mt15'>
|
||||
特邀合作单位
|
||||
<div className='pt10'>
|
||||
<div className="sponsor" onClick={() => { window.open("https://github.com/open-mmlab") }}><img src={sponsor11} className='gitlink' alt='OpenMMLab' /></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>}
|
||||
|
||||
<div className='cont cont3 mt15'>
|
||||
{round === 1 && <div className='cont cont3 mt15'>
|
||||
白金赞助商
|
||||
<div className='pt10'>
|
||||
<div className="sponsor" onClick={() => { window.open("http://www.baidu.com/") }}><img src={sponsor21} className='gitlink' alt='百度' /></div>
|
||||
<div className="sponsor" onClick={() => { window.open("https://www.antgroup.com/") }}><img src={sponsor22} className='gitlink' alt='蚂蚁集团' /></div>
|
||||
<div className="sponsor" onClick={() => { window.open("https://www.alibaba.com/") }}><img src={sponsor23} className='gitlink' alt='阿里巴巴' /></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>}
|
||||
|
||||
<div className='cont cont3 mt15'>
|
||||
{round === 1 && <div className='cont cont3 mt15'>
|
||||
黄金赞助商
|
||||
<div className='pt10'>
|
||||
<div className="sponsor" onClick={() => { window.open("https://aws.amazon.com/cn/") }}><img src={sponsor31} className='gitlink' alt='亚马逊云科技' /></div>
|
||||
<div className="sponsor" onClick={() => { window.open("https://www.didiglobal.com/") }}><img src={sponsor32} className='gitlink' alt='滴滴出行' /></div>
|
||||
<div className="sponsor" onClick={() => { window.open("https://www.99cloud.net/") }}><img src={sponsor33} className='gitlink' alt='九州云' /></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>}
|
||||
|
||||
<div className='cont cont3 mt15'>
|
||||
{round === 1 && <div className='cont cont3 mt15'>
|
||||
白银赞助商
|
||||
<div className='pt10'>
|
||||
<div className="sponsor" onClick={() => { window.open(" https://www.cloudwego.io/") }}><img src={sponsor41} className='gitlink' alt='cloudwego' /></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>}
|
||||
|
||||
|
||||
<div className='cont cont3 mt15'>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
|||
import Step from './step';
|
||||
import './index.scss';
|
||||
|
||||
const stepArr = [{
|
||||
const stepArr2022 = [{
|
||||
title: "Step1",
|
||||
date: "4.15",
|
||||
content: "GLCC夏令营活动发布"
|
||||
|
|
@ -40,18 +40,93 @@ const stepArr = [{
|
|||
},
|
||||
{
|
||||
title: "Step2",
|
||||
date: "10.1-10.24",
|
||||
date: "10.1-10.21",
|
||||
content: "结项审核,并公示考核结果",
|
||||
},
|
||||
{
|
||||
title: "Step2",
|
||||
date: "10.24-11.11",
|
||||
date: "10.21-11.11",
|
||||
content: "评选公布优秀项目和学员",
|
||||
noArrow: true,
|
||||
}
|
||||
]
|
||||
const stepArr = [{
|
||||
title: "Step1",
|
||||
date: "4.29",
|
||||
content: "GLCC夏令营活动发布"
|
||||
},
|
||||
{
|
||||
title: "Step2",
|
||||
date: "4.29-5.30",
|
||||
content: "社区项目报名,提交课题"
|
||||
},
|
||||
{
|
||||
title: "Step2",
|
||||
date: "5.31-6.3",
|
||||
content: "课题审核及公布"
|
||||
},
|
||||
{
|
||||
title: "Step2",
|
||||
date: "6.4-6.21",
|
||||
content: "学生报名,提交Proposal"
|
||||
},
|
||||
{
|
||||
title: "Step2",
|
||||
date: "7.1",
|
||||
content: "公示入选学生名单",
|
||||
noArrow: true,
|
||||
},
|
||||
{
|
||||
title: "Step2",
|
||||
date: "7.1-8.11",
|
||||
content: "项目开发第一阶段",
|
||||
},
|
||||
{
|
||||
title: "Step2",
|
||||
date: "8.20",
|
||||
content: "中期考核,公示考核结果",
|
||||
},
|
||||
{
|
||||
title: "Step2",
|
||||
date: "8.21-9.28",
|
||||
content: "项目开发第二阶段",
|
||||
},
|
||||
{
|
||||
title: "Step2",
|
||||
date: "10.11",
|
||||
content: "结项考核,公示考核结果",
|
||||
},
|
||||
{
|
||||
title: "Step2",
|
||||
date: "10.22",
|
||||
content: "优秀项目/学生公布及颁奖",
|
||||
noArrow: true,
|
||||
}
|
||||
]
|
||||
|
||||
function TimerShaft() {
|
||||
function TimerShaft({round, glccSettings}) {
|
||||
// if(glccSettings && glccSettings.length > 12){
|
||||
// stepArr[1].date = getRangeTime(glccSettings[0].value);
|
||||
// stepArr[2].date = getRangeTime(glccSettings[1].value);
|
||||
// stepArr[3].date = getRangeTime(glccSettings[2].value);
|
||||
// stepArr[4].date = getTime(glccSettings[3].value);
|
||||
// stepArr[5].date = getRangeTime(glccSettings[11].value);
|
||||
// stepArr[6].date = getTime(glccSettings[7].value);
|
||||
// stepArr[7].date = getRangeTime(glccSettings[12].value);
|
||||
// stepArr[8].date = getTime(glccSettings[9].value);
|
||||
// stepArr[9].date = getTime(glccSettings[4].value);
|
||||
// }
|
||||
const step = round === 2 ? stepArr : stepArr2022
|
||||
|
||||
// 截取月份/日期
|
||||
function getRangeTime(value){
|
||||
return value.split(",").map(item=>`${new Date(item).getMonth()+1}.${new Date(item).getDate()}`).join("-");
|
||||
}
|
||||
|
||||
function getTime(value){
|
||||
const time = new Date(value.split(",")[0]);
|
||||
return `${new Date(time).getMonth()+1}.${new Date(time).getDate()}`;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="timerShaft">
|
||||
|
|
@ -59,7 +134,7 @@ function TimerShaft() {
|
|||
<h3 className="glcc-tit">时间规划</h3>
|
||||
<div className="time-content">
|
||||
{
|
||||
stepArr.map((item, i) => {
|
||||
step.map((item, i) => {
|
||||
return <Step {...item} title={`Step${i + 1}`} key={i}/>
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
After Width: | Height: | Size: 540 B |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 406 KiB After Width: | Height: | Size: 1.9 MiB |
|
After Width: | Height: | Size: 150 KiB |
|
After Width: | Height: | Size: 279 KiB |