Merge pull request 'glcc启动2023届' (#529) from durian/forgeplus-react:feature_glcc into gitlink_server

This commit is contained in:
caishi 2023-04-27 17:24:09 +08:00
commit 0ca189ebe2
29 changed files with 986 additions and 256 deletions

View File

@ -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=1682485448664') format('woff2'),
url('iconfont.woff?t=1682485448664') format('woff'),
url('iconfont.ttf?t=1682485448664') format('truetype');
}
.iconfont {
@ -13,6 +13,42 @@
-moz-osx-font-smoothing: grayscale;
}
.icon-zanting:before {
content: "\e96a";
}
.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";
}

File diff suppressed because one or more lines are too long

View File

@ -5,6 +5,69 @@
"css_prefix_text": "icon-",
"description": "",
"glyphs": [
{
"icon_id": "887857",
"name": "暂停",
"font_class": "zanting",
"unicode": "e96a",
"unicode_decimal": 59754
},
{
"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",

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

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

View File

@ -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({
@ -194,4 +203,13 @@ export function getMediumTermExamineInfoList(params) {
method: 'get',
params,
});
}
// 查看GLCC配置信息列表
export function getGlccSettings(params) {
return fetch({
url: `/api/glccSettings/settingList`,
method: 'get',
params,
});
}

View File

@ -1,24 +1,29 @@
import React , { useCallback, useEffect , useState } from 'react';
import { Breadcrumb, Button, Form, Input, Select, Upload, Modal } from 'antd';
import { Breadcrumb, Button, Form, Input, Select, Upload, Modal, message } from 'antd';
import {getUploadActionUrl} from 'educoder';
import {getUserApplyInfo, applyGlcc} from '../api';
import {getUserApplyInfo, applyGlcc, updateApplyGlcc} from '../api';
import axios from 'axios';
import TextArea from 'antd/lib/input/TextArea';
import { main_site_url } from '../fetch';
import TaskApply from './taskApply';
import banner from "../img/banner.png";
import apply1 from "../img/apply1.png";
import './index.scss';
import { FlexAJ } from '../../forge/Component/layout';
const Option = Select.Option;
function Apply(props) {
const {form, current_user, showNotification, isGlccApplyDate} = props;
//
// current_user && (current_user.user_id = 6)
// current_user && (current_user.userName = "使")
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 {form, current_user, showNotification, round} = props;
const {getFieldDecorator, validateFields, setFieldsValue, validateFieldsAndScroll } = form;
const [reload, setReload] = useState(undefined);
const [imageUrl, setImageUrl] = useState(undefined);
// loading
const [loading, setLoading] = useState(false);
const [cateList, setCateList] = useState([]);
const [userApplyInfo, setUserApplyInfo] = useState(undefined);
//
const [taskCount, setTaskCount] = useState([1]);
const helper = useCallback(
(label, extra, name, rules, widget) => (
@ -32,10 +37,7 @@ function Apply(props) {
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,15 +52,36 @@ 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);
if(!response.data){
return
}
const {projectName, projectType, gitlinkUrl, contactName, contactPhone, projectIntro, registrationTaskList, projectLogoId, contactMail} = response.data;
const taskInfo = {};
const taskCountArr = []
registrationTaskList.map((item, index)=>{
taskCountArr.push(index+1);
const{taskName, taskUrl, taskDifficulty, taskReward, tutorName, tutorMail, taskDesc, tutorPhone} = 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;
})
setTaskCount(taskCountArr);
setFieldsValue({
projectName, projectType, gitlinkUrl, contactName, contactPhone, projectIntro, contactMail,
...taskInfo,
logo: {file:{response:{id: projectLogoId}}}
})
}
})
}, [reload])
}, [])
//
function verify(dataIndex){
@ -74,32 +97,58 @@ function Apply(props) {
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
const registrationTaskList = []
taskCount && taskCount.map(item=>{
registrationTaskList.push({
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(userApplyInfo){
//
params[`id`] = userApplyInfo.id;
updateApplyGlcc(params).then(response=>{
if(response && response.message === "success"){
message.success("修改成功");
setReload(Math.random());
}
applyGlcc(params).then(response=>{
if(response && response.message === "success"){
showNotification("报名成功");
setReload(Math.random());
}
})
setLoading(false);
window.scrollTo(0,0);
})
return
}
applyGlcc(params).then(response=>{
if(response && response.message === "success"){
message.success("报名成功");
setReload(Math.random());
}
})}
setLoading(false);
window.scrollTo(0,0);
})
}
});
};
//
function beforeUpload(file){
const isLt100M = file.size / 1024 / 1024 < 2;
const isLt100M = file.size / 1024 / 1024 < 20;
if (!isLt100M) {
showNotification(`文件大小必须小于${2}MB!`);
showNotification(`文件大小必须小于${20}M!`);
}
const isType = file.type === "image/png" || file.type === "image/jpg" || file.type === "image/jpeg";
if (!isType) {
@ -124,83 +173,123 @@ function Apply(props) {
);
}
}
//
function addTaskApplyForm(){
setTaskCount(taskCount.concat([taskCount.length+1]));
}
//
function deleteTaskApply(index){
const arr = [...taskCount];
arr.splice(index-1, 1)
setTaskCount(arr);
}
return(
<div className="glcc_apply">
<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 && <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'>2022年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>
<div className='pt20 font-18'><img src={apply1} alt="" width="25px" className="mr10"/>项目报名</div>
<div className='applyInfoBox mt20'>
<div className='titleG font-18 mb10'>项目信息</div>
<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 || userApplyInfo) ? <img src={imageUrl || `${main_site_url}/api/attachments/${userApplyInfo.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}/>
</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'>
<Button type="primary" htmlType="submit" className='sub' loading={loading}>提交</Button>
</Form.Item>
</Form>
</div>
</div>
</div>

View File

@ -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;
@ -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,68 @@
}
.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;
}
}

View File

@ -0,0 +1,85 @@
import React , { useCallback, useEffect , useState } from 'react';
import { Breadcrumb, Button, Form, Input, Select, Upload, Modal, InputNumber } from 'antd';
import TextArea from 'antd/lib/input/TextArea';
const Option = Select.Option;
function TaskApply(props) {
const {helper, disabled, taskKey, phonereg, emailreg} = props;
//
const difficultyList = [
{id: 1, name: "低"},
{id: 2, name: "中"},
{id: 3, name: "高"}
]
return(
<div className="taskApplyForm">
<div className="pt20 glcc_info_form">
{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元");
}
}}],
<Input placeholder="请输入课题奖金" disabled = {disabled} className={disabled? "disabledInput":""}/>
)}
{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);

View File

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

View File

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

View File

@ -18,20 +18,22 @@ import logo from "../img/openmmlab/logo1.png";
import { hasAuditRole } from '../api';
import './index.scss';
// round20221 20232
// period: 0
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("415~520");
// window.location.href = "/glcc";
// }
// }
const { current_user, isGlccApplyDate, showNotification, studentApplyStart, history, secondStudentApplyDate, isStudentApplyDate, checkedTaskId, checkTime1, checkTime2, checkTime3, round, match:{params:{id}}, period, showLoginDialog} = 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();
@ -67,6 +69,15 @@ export default (props) => {
history.push("/glcc/result");
}
//
function gotoCheckLogin(url){
if(current_user && current_user.login){
history.push(url);
return
}
showLoginDialog();
}
return (
<div className="glcc">
{/* <Banner /> */}
@ -74,54 +85,79 @@ 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 === 0 && <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>}
{/* 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>
<img src={img1} alt="" className="applyIcon" />
<span className="til">考核结果</span>
</div>
<div className="pt6">结项课题考核结果公示</div>
</Link>} */}
{/* 项目报名 */}
{/* <Link to="/glcc/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> */}
{/* 学生报名6.24结束第一次报名6.29 1:00 - 6.30 24:00第二次报名 */}
{/* <div className="apply" onClick={goToStudent}>
<div>
@ -139,7 +175,7 @@ export default (props) => {
</div>
<div className="pt6">以赛代筛挖掘高潜力人才</div>
</div>} */}
</div>
</div>}
{/* </div> */}
<div className="introduce">
<div className="glcc-content">
@ -149,7 +185,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>
@ -158,14 +194,14 @@ export default (props) => {
</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>}
</div>
</div>
<Lightspot isGlccApplyDate={isGlccApplyDate} current_user={current_user} showNotification={showNotification} goToStudent={goToStudent}/>
<TimerShaft />
<Lightspot period={period} history={history} current_user={current_user} round={round} showLoginDialog={showLoginDialog}/>
<TimerShaft round={round}/>
<Award />
<News />
<Partner />
<Partner round={round}/>
<Contact />
</div>
)

View File

@ -1,30 +1,20 @@
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} = 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";
if(current_user && !current_user.login){
showLoginDialog();
return;
}
history.push(period === 0 ? `/glcc/apply` : `/glcc/subjects`);
}
return (
@ -36,17 +26,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 === 0 && round === 2 ? <div className='applyBut' onClick={goToApply}>立即报名</div> : <div className='applyBut project'><span className='hover-none'>项目报名</span><span className='hover-show'>{period === -1 ? "敬请期待" : "已结束"}</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 === 2 && round === 2 ? <div className='applyBut' onClick={goToApply}>学生报名</div> : <div className='applyBut project'><span className='hover-none'>学生报名</span><span className='hover-show'>{period<2 && round === 2 ? "敬请期待" : "已结束"}</span></div>}
</div>
{/* <img className="teacher-img" src={teacherImg} alt=''></img> */}
</div>
<div className="info-student">

View File

@ -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'>

View File

@ -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,72 @@ 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.30-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}) {
const step = round === 2 ? stepArr : stepArr2022
return (
<div className="timerShaft">
@ -59,7 +113,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}/>
})
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 540 B

BIN
src/glcc/img/sponsor42.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
src/glcc/img/sponsor43.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -11,7 +11,7 @@ import "./index.scss";
import Loadable from "react-loadable";
import Loading from "../Loading";
import { ImageLayerOfCommentHOC } from "../modules/page/layers/ImageLayerOfCommentHOC";
import { getStudentApplyInfo } from "./api";
import { getGlccSettings, getStudentApplyInfo } from "./api";
import { message } from "antd";
@ -77,7 +77,32 @@ const MiddleResult = Loadable({
loading: Loading,
});
const Glcc = (propsF) => {
const {current_user, showLoginDialog} = propsF;
const {current_user, showLoginDialog, match:{params:{id}}} = propsF;
// round20221 20232
const [round, setRound] = useState(2);
const [period, setPeriod] = useState(undefined);
useEffect(()=>{
if(id && id === "2022"){
setRound(1);
}
}, [id])
useEffect(()=>{
// glcc
getGlccSettings({round: 2}).then(res=>{
if(res && res.message === "success"){
const nowTime = new Date().getTime();
setPeriod(res.data.findIndex(item=>judge(nowTime, item.value)));
}
})
}, [])
//
function judge(nowTime, timeRnge){
const timeArr = timeRnge.split(",").map(item=>{return new Date(item).getTime()});
return nowTime > timeArr[0] && nowTime < timeArr[1]
}
// 415~520
const isGlccApplyDate = Date.parse(new Date()) < 1653062400000;
@ -108,8 +133,8 @@ const Glcc = (propsF) => {
}, [])
useEffect(()=>{
//
current_user && current_user.login && getStudentApplyInfo({userId: current_user.user_id}).then(response=>{
// (todo)
false && current_user && current_user.login && getStudentApplyInfo({userId: current_user.user_id}).then(response=>{
if(response && response.message === "success"){
// setData(response.data.rows);
const data = {};
@ -155,12 +180,12 @@ const Glcc = (propsF) => {
)}
></Route>
{/* 开源夏令营报名页面 */}
<Route
{period === 0 && <Route
path="/glcc/apply"
render={(props) => (
<Apply {...propsF} {...props} isGlccApplyDate={isGlccApplyDate}/>
<Apply round={round} {...propsF} {...props}/>
)}
></Route>
></Route>}
{/* 教师审核 */}
<Route
path="/glcc/mentoradmin"
@ -176,22 +201,22 @@ const Glcc = (propsF) => {
)}
></Route>
<Route
path="/glcc/subjects/detail/:taskId"
path="/glcc/:id/subjects/detail/:taskId"
render={(props) => (
<TaskDetail {...propsF} {...props} isStudentApplyDate={isStudentApplyDate} secondStudentApplyDate={secondStudentApplyDate} applyTaskId={applyTaskId} applyTask={applyTask} />
)}
></Route>
{/* 项目/课题列表 */}
<Route
path="/glcc/projects"
path="/glcc/:id/projects"
render={(props) => (
<Project {...propsF} {...props} isStudentApplyDate={isStudentApplyDate} secondStudentApplyDate={secondStudentApplyDate} applyTaskId={applyTaskId} setStudentInfoReset={setStudentInfoReset} applyTask={applyTask}/>
<Project round={round} {...propsF} {...props} isStudentApplyDate={isStudentApplyDate} secondStudentApplyDate={secondStudentApplyDate} applyTaskId={applyTaskId} setStudentInfoReset={setStudentInfoReset} applyTask={applyTask}/>
)}
></Route>
{/* 课题列表 */}
<Route
path="/glcc/subjects"
path="/glcc/:id/subjects"
render={(props) => (
<Project {...propsF} {...props} isStudentApplyDate={isStudentApplyDate} secondStudentApplyDate={secondStudentApplyDate} applyTaskId={applyTaskId} setStudentInfoReset={setStudentInfoReset} cancelCount={cancelCount} applyTask={applyTask}/>
)}
@ -215,9 +240,9 @@ const Glcc = (propsF) => {
{/* 中期审核-结果公示 */}
<Route
path="/glcc/final/result"
path="/glcc/:id/final/result"
render={(props) => (
<MiddleResult current_user={current_user} history={props.history} checkTime3={checkTime3}/>
<MiddleResult id={id} round={round} current_user={current_user} history={props.history} checkTime3={checkTime3}/>
)}
></Route>
@ -237,11 +262,19 @@ const Glcc = (propsF) => {
)}
></Route>
{/* 首页 */}
<Route
path="/glcc/:id"
render={(props) => (
<Home period={period} round={round} {...propsF} {...props} studentApplyStart={studentApplyStart} isStudentApplyDate={isStudentApplyDate} secondStudentApplyDate={secondStudentApplyDate} checkedTaskId={checkedTaskId} checkTime1={checkTime1} checkTime2={checkTime2} checkTime3={checkTime3}/>
)}
></Route>
{/* 首页 */}
<Route
path="/glcc"
render={(props) => (
<Home {...propsF} {...props} studentApplyStart={studentApplyStart} isStudentApplyDate={isStudentApplyDate} secondStudentApplyDate={secondStudentApplyDate} checkedTaskId={checkedTaskId} checkTime1={checkTime1} checkTime2={checkTime2} checkTime3={checkTime3}/>
<Home period={period} round={round} {...propsF} {...props} studentApplyStart={studentApplyStart} isStudentApplyDate={isStudentApplyDate} secondStudentApplyDate={secondStudentApplyDate} checkedTaskId={checkedTaskId} checkTime1={checkTime1} checkTime2={checkTime2} checkTime3={checkTime3}/>
)}
></Route>

View File

@ -37,8 +37,8 @@
}
.-task-sidebar .glccHelp {
height: auto;
width: 48px;
padding: 6px 16px;
width: 38px;
padding: 6px 10px;
text-align: center;
background-color: #f6f9fe;
border: 1px solid #ffffff;
@ -46,22 +46,31 @@
box-shadow: 0px 0px 8px rgba(55, 148, 255, 0.16);
color: #1e1e1e;
font-size: 14px;
line-height: 35px;
line-height: 20px;
word-break: break-word;
cursor: pointer;
.icon-bangzhuzhongxinicon,
.icon-bangzhuzhongxinicon1 {
.icon-bangzhuzhongxinicon1{
color: #0654d6;
margin-left: -3px;
}
.icon-zanting {
color: #0654d6;
}
&:hover {
color: #ffffff;
background-color: #466aff;
.icon-bangzhuzhongxinicon,
.icon-bangzhuzhongxinicon1 {
.icon-bangzhuzhongxinicon1,
.icon-zanting {
color: #ffffff;
}
}
.glccList{
width: 21px;
position: relative;
left: -2px;
}
}
.qqChatBox {
position: fixed;

View File

@ -11,7 +11,7 @@ import '../project/index.scss';
const { Search } = Input;
//
function CheckResult({current_user, history, checkTime3}) {
function CheckResult({current_user, history, checkTime3, round, id}) {
//
const [keyword, setKeyword] = useState(undefined);
const [data, setData] = useState([]);
@ -36,7 +36,8 @@ function CheckResult({current_user, history, checkTime3}) {
curPage: current,
keyword,
pageSize,
term: 2
term: 2,
round
}
getMediumTermExamineInfoList(params).then(response => {
if (response && response.message === "success") {
@ -54,7 +55,7 @@ function CheckResult({current_user, history, checkTime3}) {
{ 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: '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/${id}/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: 'introduce', className:"columnsResult", width: '13%', ellipsis: true},
{ title: '答辩视频', dataIndex: 'defenceVideoUrl', className:"columnsResult", width: '15%', ellipsis: true, render: (text, item) => <Tooltip title={text} placement="topLeft"><span className='toolTipSpan link' onClick={()=>{window.open(text)}}>{text}</span></Tooltip>},
@ -106,7 +107,7 @@ function CheckResult({current_user, history, checkTime3}) {
<img className="bannerInterim" src={resultBanner} alt=""></img>
<div className='bgBox'>
<div className="resultList">
<div className='goBackBox'><a href='/glcc'>开源夏令营 / </a>结项课题考核结果公示</div>
<div className='goBackBox'><a href={`/glcc/${id}`}>开源夏令营 / </a>结项课题考核结果公示</div>
<div className='searchBox'>
<Search className='search' placeholder='请输入学生姓名或课题名称进行搜索' allowClear enterButton onSearch={(value) => { setCurrent(1); setKeyword(value) }} />
<div style={{width: 100}}></div>

View File

@ -4,7 +4,7 @@ import Nodata from '../../../forge/Nodata';
import { useEffect } from 'react';
import { getProjectById } from '../../api';
export default ({ detail, projectId, applyTaskId, isStudentApplyDate, secondStudentApplyDate, showTask=true, applyTask }) => {
export default ({ detail, projectId, applyTaskId, isStudentApplyDate, secondStudentApplyDate, showTask=true, applyTask, id }) => {
const [info, setInfo] = useState(detail);
useEffect(()=>{
@ -30,7 +30,7 @@ export default ({ detail, projectId, applyTaskId, isStudentApplyDate, secondStud
{showTask && (info.registrationTaskList && info.registrationTaskList.length > 0 ? info.registrationTaskList.map((item, index)=>{
return <div className='taskItem mt20' key={index}>
<div className="left">
<div className="taskTitle" onClick={()=>{window.location.href=`/glcc/subjects/detail/${item.id}`}}><Tooltip title={item.taskName}>{item.taskName}</Tooltip></div>
<div className="taskTitle" onClick={()=>{window.location.href=`/glcc/${id}/subjects/detail/${item.id}`}}><Tooltip title={item.taskName}>{item.taskName}</Tooltip></div>
<div className='mt20 oneLine leftWidth'>导师姓名: &nbsp;&nbsp;{item.tutorName}</div>
{item.tutorMail && <div className='mb20 email oneLine leftWidth'>邮箱地址: &nbsp;&nbsp;<span><Tooltip title={item.tutorMail}>{item.tutorMail}</Tooltip></span></div>}
</div>
@ -48,7 +48,7 @@ export default ({ detail, projectId, applyTaskId, isStudentApplyDate, secondStud
{secondStudentApplyDate && !(applyTaskId && Object.keys(applyTaskId).includes(item.id.toString())) && (item.locked ? <Tooltip title={"该课题已有学生入选"}><Button type='primary' className='mr10' disabled>申请课题</Button></Tooltip> : <Button type='primary' className='applyBut mr10' onClick={()=>{applyTask(item.id)}}>申请课题</Button>)}
{/* 查看课题详情按钮 */}
<Button onClick={()=>{window.open(`/glcc/subjects/detail/${item.id}`)}} className='lookDetail'>课题详情</Button>
<Button onClick={()=>{window.open(`/glcc/${id}/subjects/detail/${item.id}`)}} className='lookDetail'>课题详情</Button>
</div>
</div>
<div className="right oneLine taskUrl"><span className='taskReward'>{item.taskReward}</span></div>

View File

@ -20,7 +20,7 @@ const TaskList = Loadable({
});
function Project(propsF) {
const {location} = propsF;
const {location, match:{params:{id}}} = propsF;
const {pathname} = location;
useEffect(()=>{
window.scrollTo(0, 0);
@ -30,35 +30,35 @@ function Project(propsF) {
<div className="glcc_project">
<img className="glcc-banner" src={banner} alt=''></img>
<div className='head'>
<Link to="/glcc/subjects" className={!pathname.endsWith('projects') ? 'active' : ''}>课题列表</Link>
<Link to="/glcc/projects" className={pathname.endsWith('projects') ? 'active' : ''}>项目列表</Link>
<Link to={`/glcc/${id}/subjects`} className={!pathname.endsWith('projects') ? 'active' : ''}>课题列表</Link>
<Link to={`/glcc/${id}/projects`} className={pathname.endsWith('projects') ? 'active' : ''}>项目列表</Link>
</div>
<div className='gobackBox'>
<a href='/glcc'>开源夏令营 / </a>
<a href={`/glcc/${id}`}>开源夏令营 / </a>
课题及项目列表
</div>
<Spin spinning={false}>
<Switch {...propsF}>
<Route
path="/glcc/projects/:gitlinkLastUrl"
path="/glcc/:id/projects/:gitlinkLastUrl"
render={(props) => (
<ProjectList {...propsF} {...props}/>
)}
></Route>
<Route
path="/glcc/projects"
path="/glcc/:id/projects"
render={(props) => (
<ProjectList {...propsF} {...props}/>
)}
></Route>
<Route
path="/glcc/subjects"
path="/glcc/:id/subjects"
render={(props) => (
<TaskList {...propsF} {...props}/>
)}
></Route>
<Route
path="/glcc/student"
path="/glcc/:id/student"
render={(props) => (
<TaskList {...propsF} {...props}/>
)}

View File

@ -10,7 +10,7 @@ import star from "../../img/star.png";
const { Search } = Input;
//
function ProjectList({ applyTaskId, isStudentApplyDate, location, match, secondStudentApplyDate, applyTask }) {
function ProjectList({ applyTaskId, isStudentApplyDate, location, match, secondStudentApplyDate, applyTask, round, match:{params:{id}}}) {
let gitlinkLastUrl = match.params.gitlinkLastUrl && match.params.gitlinkLastUrl.replace(/\./g, '');
let openmmlab = location.search && location.search.split('=')[1];
//
@ -23,7 +23,8 @@ function ProjectList({ applyTaskId, isStudentApplyDate, location, match, secondS
const params = {
curPage: 1,
keyword,
pageSize: 10000
pageSize: 10000,
round
}
projectList(params).then(response => {
if (response && response.message === "success") {
@ -83,7 +84,7 @@ function ProjectList({ applyTaskId, isStudentApplyDate, location, match, secondS
onVisibleChange={(visible) => { changeVisible(visible, item) }}
key={index}
placement={(index + 1) % 3 === 0 ? 'bottomRight' : (index + 1) % 3 % 2 === 0 ? 'bottom' : 'bottomLeft'}
content={<ProjectDetail detail={item} applyTaskId={applyTaskId} isStudentApplyDate={isStudentApplyDate} secondStudentApplyDate={secondStudentApplyDate} applyTask={applyTask}/>}
content={<ProjectDetail id={id} detail={item} applyTaskId={applyTaskId} isStudentApplyDate={isStudentApplyDate} secondStudentApplyDate={secondStudentApplyDate} applyTask={applyTask}/>}
trigger='click'
overlayClassName='projectItemPopover'
autoAdjustOverflow={false}

View File

@ -7,7 +7,7 @@ import './index.scss';
//
function TaskDetail(props) {
const {match, location, isStudentApplyDate, secondStudentApplyDate, applyTaskId, applyTask} = props
const {match, location, isStudentApplyDate, secondStudentApplyDate, applyTaskId, applyTask, match:{params:{id}}} = props
const taskId = Number(match.params.taskId);
const [detail, setDetail] = useState(undefined);
@ -26,8 +26,8 @@ function TaskDetail(props) {
{detail && <div className="bgBox">
<div className="detailBox">
<div className='goBackBox'>
<a href='/glcc'>开源夏令营 / </a>
<a href='/glcc/subjects'>课题及项目列表 / </a>
<a href={`/glcc/${id}`}>开源夏令营 / </a>
<a href={`/glcc/${id}/subjects`}>课题及项目列表 / </a>
课题详情
</div>
</div>

View File

@ -7,7 +7,7 @@ import bgPng from "../../img/bgPng.png";
const { Search } = Input;
//
function TaskList({applyTaskId, setStudentInfoReset, current_user, showLoginDialog, isStudentApplyDate, secondStudentApplyDate,cancelCount,showNotification, applyTask}) {
function TaskList({applyTaskId, setStudentInfoReset, current_user, showLoginDialog, isStudentApplyDate, secondStudentApplyDate,cancelCount,showNotification, applyTask, round, match:{params:{id}}}) {
const [visible, setVisible] = useState(false);
const [deleteTaskId, setDeleteTaskId] = useState(undefined);
//
@ -24,7 +24,7 @@ function TaskList({applyTaskId, setStudentInfoReset, current_user, showLoginDial
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: '24%', ellipsis: true, render: (text, item) => <Tooltip title={text} placement="topLeft"><span onClick={()=>{window.open(`/glcc/subjects/detail/${item.id}`)}}>{text}</span></Tooltip> },
{ title: '课题名称', dataIndex: 'taskName', className:"taskTableColumns taskName", width: '24%', ellipsis: true, render: (text, item) => <Tooltip title={text} placement="topLeft"><span onClick={()=>{window.open(`/glcc/${id}/subjects/detail/${item.id}`)}}>{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> },
@ -71,7 +71,7 @@ function TaskList({applyTaskId, setStudentInfoReset, current_user, showLoginDial
}
const expandRow = (record) => {
return <ProjectDetail detail={null} projectId={record.regId} applyTaskId={applyTaskId} current_user={current_user} showLoginDialog={showLoginDialog} isStudentApplyDate={isStudentApplyDate} showNotification={showNotification} secondStudentApplyDate={secondStudentApplyDate} applyTask={applyTask}/>
return <ProjectDetail id={id} detail={null} projectId={record.regId} applyTaskId={applyTaskId} current_user={current_user} showLoginDialog={showLoginDialog} isStudentApplyDate={isStudentApplyDate} showNotification={showNotification} secondStudentApplyDate={secondStudentApplyDate} applyTask={applyTask}/>
}
//
@ -128,7 +128,8 @@ function TaskList({applyTaskId, setStudentInfoReset, current_user, showLoginDial
curPage: current,
keyword,
pageSize,
userId: apply ? current_user.user_id : ''
userId: apply ? current_user.user_id : '',
round
}
taskList(params).then(response => {
if (response && response.message === "success") {
@ -149,7 +150,7 @@ function TaskList({applyTaskId, setStudentInfoReset, current_user, showLoginDial
<div className="taskList listBox">
<div className="list">
<div className='search task'>
{current_user && current_user.login ? <Checkbox onChange={(e)=>{setCurrent(1);setApply(e.target.checked)}}>已报名</Checkbox> : <div></div>}
{round === 2 && current_user && current_user.login ? <Checkbox onChange={(e)=>{setCurrent(1);setApply(e.target.checked)}}>已报名</Checkbox> : <div></div>}
<Search className='taskSearch' placeholder='请输入课题/项目名称进行搜索' allowClear enterButton onSearch={(value) => { setCurrent(1); setKeyword(value) }} />
<div></div>
</div>

View File

@ -25,6 +25,10 @@ function SiderBar() {
<i className='iconfont icon-bangzhuzhongxinicon font-20'></i>
帮助中心
</div>
<div className={"glccHelp"} onClick={()=>window.open("/glcc/2022")}>
<i className='iconfont icon-zanting font-17'></i>
往期回顾
</div>
</div>
)
}