pull 何 代码-glcc

This commit is contained in:
caishi 2022-05-19 10:40:10 +08:00
commit 24bb69cc22
38 changed files with 1841 additions and 60 deletions

View File

@ -1,8 +1,8 @@
@font-face {
font-family: "iconfont"; /* Project id 2340181 */
src: url('iconfont.woff2?t=1652151013948') format('woff2'),
url('iconfont.woff?t=1652151013948') format('woff'),
url('iconfont.ttf?t=1652151013948') format('truetype');
src: url('iconfont.woff2?t=1652927945088') format('woff2'),
url('iconfont.woff?t=1652927945088') format('woff'),
url('iconfont.ttf?t=1652927945088') format('truetype');
}
.iconfont {
@ -13,6 +13,54 @@
-moz-osx-font-smoothing: grayscale;
}
.icon-bangzhuzhongxinicon1:before {
content: "\e935";
}
.icon-ketixiangqingicon:before {
content: "\e92b";
}
.icon-bianjiicon:before {
content: "\e92c";
}
.icon-baomingxiangqingicon:before {
content: "\e92d";
}
.icon-sousuo4:before {
content: "\e92e";
}
.icon-quxiaoshenqingicon:before {
content: "\e92f";
}
.icon-xiala3:before {
content: "\e930";
}
.icon-tianjia_tianchong:before {
content: "\e931";
}
.icon-a-shanchu2:before {
content: "\e932";
}
.icon-shanchuicon3:before {
content: "\e933";
}
.icon-shenqingketiicon:before {
content: "\e934";
}
.icon-weixin:before {
content: "\e92a";
}
.icon-zanwushuju:before {
content: "\e928";
}

File diff suppressed because one or more lines are too long

View File

@ -5,6 +5,90 @@
"css_prefix_text": "icon-",
"description": "",
"glyphs": [
{
"icon_id": "29811507",
"name": "帮助中心icon",
"font_class": "bangzhuzhongxinicon1",
"unicode": "e935",
"unicode_decimal": 59701
},
{
"icon_id": "29701613",
"name": "课题详情icon",
"font_class": "ketixiangqingicon",
"unicode": "e92b",
"unicode_decimal": 59691
},
{
"icon_id": "29701614",
"name": "编辑icon",
"font_class": "bianjiicon",
"unicode": "e92c",
"unicode_decimal": 59692
},
{
"icon_id": "29701615",
"name": "报名详情icon",
"font_class": "baomingxiangqingicon",
"unicode": "e92d",
"unicode_decimal": 59693
},
{
"icon_id": "29701616",
"name": "搜索",
"font_class": "sousuo4",
"unicode": "e92e",
"unicode_decimal": 59694
},
{
"icon_id": "29701617",
"name": "取消申请icon",
"font_class": "quxiaoshenqingicon",
"unicode": "e92f",
"unicode_decimal": 59695
},
{
"icon_id": "29701618",
"name": "下拉",
"font_class": "xiala3",
"unicode": "e930",
"unicode_decimal": 59696
},
{
"icon_id": "29701619",
"name": "添加_填充",
"font_class": "tianjia_tianchong",
"unicode": "e931",
"unicode_decimal": 59697
},
{
"icon_id": "29701620",
"name": "删除 (2)",
"font_class": "a-shanchu2",
"unicode": "e932",
"unicode_decimal": 59698
},
{
"icon_id": "29701621",
"name": "删除icon",
"font_class": "shanchuicon3",
"unicode": "e933",
"unicode_decimal": 59699
},
{
"icon_id": "29701622",
"name": "申请课题icon",
"font_class": "shenqingketiicon",
"unicode": "e934",
"unicode_decimal": 59700
},
{
"icon_id": "29665762",
"name": "微信",
"font_class": "weixin",
"unicode": "e92a",
"unicode_decimal": 59690
},
{
"icon_id": "29467269",
"name": "暂无数据",

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -125,7 +125,7 @@ const Glcc = Loadable({
// })
// 此处仅维护前端可能的一级路由,不用进行项目或者组织判断的字段。
const keyWord = ["explore", "settings", "setting", "mulan", "wiki", "issues", "setting", "trending", "code", "projects", "pulls", "mine", "login", "register", "email", "export", "nopage", "404", "403", "500", "501", "search", "organize", "login", "register", "resetPassword", "aboutus","educoder"];
const keyWord = ["explore", "settings", "setting", "mulan", "wiki", "issues", "setting", "trending", "code", "projects", "pulls", "mine", "login", "register", "email", "export", "nopage", "404", "403", "500", "501", "search", "organize", "login", "register", "resetPassword", "aboutus","educoder", "glcc"];
class App extends Component {
constructor(props) {

View File

@ -1,6 +1,6 @@
import fetch from './fetch';
// 获取当前用户报名信息
// 获取当前用户项目报名信息
export function getUserApplyInfo(params) {
return fetch({
url: `/api/applyInformation/getUserApplyInfo`,
@ -16,4 +16,67 @@ export function applyGlcc(data) {
method: 'post',
data: data
});
}
}
//提交报名信息(学生)
export function studentApply(data) {
return fetch({
url: '/api/studentApply/create',
method: 'post',
data: data
});
}
//修改报名信息(学生)
export function studentApplyEdit(data) {
return fetch({
url: '/api/studentApply/update',
method: 'post',
data: data
});
}
// 获取当前学生用户报名信息
// 课题列表
export function projectList(params) {
return fetch({
url: `/api/applyInformation/list`,
method: 'get',
params
});
}
// 课题列表
export function taskList(params) {
return fetch({
url: `/api/applyInformation/taskList`,
method: 'get',
params
});
}
// 项目id查询项目详情
export function getProjectById(id) {
return fetch({
url: `/api/applyInformation/${id}`,
method: 'get'
});
}
// 获取用户(学生)课题报名信息
export function getStudentApplyInfo(params) {
return fetch({
url: `/api/studentApply/getUserApplyInfo`,
method: 'get',
params
});
}
// 用户取消课题报名
export function cancelTaskApply(data) {
return fetch({
url: '/api/studentApply/delete',
method: 'post',
data: data
});
}

View File

@ -8,20 +8,23 @@ import News from './news';
import Partner from "./partner";
import Contact from "./contact";
import banner from "../img/banner.png";
import introduce from "../img/introduce.png";
import apply1 from "../img/apply1.png";
import apply2 from "../img/apply2.png";
import './index.scss';
export default (props) => {
const {current_user, isGlccApplyDate, showNotification} = 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/";
const { current_user, isGlccApplyDate, showNotification } = 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{
} else {
showNotification("不在报名时间报名时间为4月15日~5月20日");
window.location.href="/glcc";
window.location.href = "/glcc";
}
}
@ -30,18 +33,42 @@ export default (props) => {
{/* <Banner /> */}
<img className="glcc-banner" src={banner} alt=""></img>
{/* <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}>
{/* <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">
{/* 项目报名 */}
<div 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>
</div>
{/* 学生报名 */}
<div className="apply" onClick={()=>{window.location.href="/glcc/student/2"}}>
<div>
<img src={apply2} alt="" className="applyIcon"/>
<span className="til">学生报名</span> >
</div>
<div className="pt6">选择感兴趣的课题开启您的开源之旅</div>
</div>
{/* </Link> */}
{/* </div> */}
<div className="introduce glcc-content">
<div className="glcc-tit">活动简介</div>
<div className="introduce-content">GitLink编程夏令营GLCC是在CCF中国计算机学会指导下由CCF开源发展委员会CCF ODC举办的面向全国高校学生的暑期编程活动活动将覆盖近千所高校并联合各大开源基金会开源企业开源社区开源专家旨在鼓励青年学生通过参加真实的开源软件开发提升自身技术能力为开源社区输送优秀人才为青年学生提供开放友好的交流平台希望进一步推动国内开源社区的繁荣发展</div>
</div>
<Lightspot isGlccApplyDate={isGlccApplyDate} current_user={current_user} showNotification={showNotification}/>
{/* </div> */}
<div className="introduce">
<div className="glcc-content">
<div className="glcc-tit">活动简介</div>
<div className="introduceBox">
<div className="introduce-content">GitLink编程夏令营GLCC是在CCF中国计算机学会指导下由CCF开源发展委员会CCF ODC举办的面向全国高校学生的暑期编程活动活动将覆盖近千所高校并联合各大开源基金会开源企业开源社区开源专家旨在鼓励青年学生通过参加真实的开源软件开发提升自身技术能力为开源社区输送优秀人才为青年学生提供开放友好的交流平台希望进一步推动国内开源社区的繁荣发展</div>
<img src={introduce} alt="" className="introduceImg" />
</div>
</div>
</div>
<Lightspot isGlccApplyDate={isGlccApplyDate} current_user={current_user} showNotification={showNotification} />
<TimerShaft />
<Award />
<News />

View File

@ -17,23 +17,69 @@
.ant-btn-primary{
background-color: #466aff;
border-color: #466aff;
&:hover{
opacity: .8;
}
}
.apply-btn {
.applyBox {
position: absolute;
top: 15vw;
left: 18.8vw;
width: 152px;
height: 40px;
background-color: #2e5bfe;
border: 1px solid #466aff;
color: #fff;
top: 21vw;
left: 17.5vw;
padding-left: 18px;
cursor: pointer;
display: flex;
.apply{
color:#666666;
font-size:15px;
padding: 20px 0 20px 30px;
background-image:linear-gradient(45deg,#C6D3F0 0%,#C9D8FF 50.63%,#E7ECFE 100%);
border:1px solid #ffffff;
border-radius:4px;
box-shadow:0px 0px 6px rgba(255, 255, 255, 0.73);
display: flex;
flex-direction: column;
justify-content: center;
width: 355px;
.til{
margin-left: 10px;
font-family:PingFang SC;
font-weight:700;
color:#333333;
font-size:18px;
margin-bottom: 10px;
}
&:hover, &:hover .til{
color:#466aff;
}
.hover-show{
display: none;
}
&:hover .hover-none, &:hover .pt6{
display: none;
}
&:hover.project{
background-image:linear-gradient(45deg,#EBEFFF 0%, #E0E4F9 50.63%,#F1F1F1 100%);
box-shadow:0px 0px 6px #466aff;
cursor: default;
.hover-show{
display: inline-block;
margin-left: 10px;
font-weight:700;
color: #999999;
font-size:18px;
}
}
}
.apply:last-child{
margin-left: 35px;
}
.applyIcon{
width: 30px;
}
.pt6{
padding-top: 10px;
}
}
.apply-text {
font-family: Alibaba PuHuiTi;
@ -84,7 +130,7 @@
min-width: 62.5vw;
max-width: 98vw;
margin: 0 auto;
padding-top: 45px;
padding-top: 65px;
}
// 1行省略号
@ -109,25 +155,34 @@
}
.introduce {
z-index: 1;
position: relative;
top: -45px;
background-image: linear-gradient(
163.51deg,
#e5ecff 0%,
#e0e9ff 32.91%,
#fbfcff 100%
);
background: url("../img/introduce-bg.png");
box-shadow: 0 0 12px rgba(161, 186, 255, 0.6);
background-size: 100% 100%;
padding: 48px;
// z-index: 1;
// position: relative;
// top: -45px;
// background-image: linear-gradient(
// 163.51deg,
// #e5ecff 0%,
// #e0e9ff 32.91%,
// #fbfcff 100%
// );
// background: url("../img/introduce-bg.png");
// box-shadow: 0 0 12px rgba(161, 186, 255, 0.6);
// background-size: 100% 100%;
// padding: 48px;
min-height: 500px;
background-image:linear-gradient(132.67deg,#e5ecff 0%,#e0e9ff 53.13%,#fbfcff 100%);
.glcc-tit {
margin-bottom: 30px !important;
margin-bottom: 60px !important;
}
.introduce-content {
color: #202d40;
font-size: 15px;
line-height: 30px;
}
.introduceBox{
display: flex;
.introduceImg{
width: 32vw;
margin-left: 3vw;
}
}
}

View File

@ -37,9 +37,16 @@ function Lightspot(props) {
<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> */}
<div className='applyBut' onClick={goToApply}>立即报名</div>
{/* onClick={goToApply} */}
<div className='applyBut project'><span className='hover-none'>项目报名</span><span className='hover-show'>项目报名已截止</span></div>
</div>
<img className="teacher-img" src={teacherImg} alt=''></img>
<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={()=>{window.location.href="/glcc/student/2"}}>学生报名</div>
</div>
{/* <img className="teacher-img" src={teacherImg} alt=''></img> */}
</div>
<div className="info-student">
@ -50,19 +57,19 @@ function Lightspot(props) {
</div>
<div className="info-item">
<img className="info-item-img" src={lightspot2}></img>
<img className="info-item-img" src={lightspot2} alt=''></img>
<h3 className="info-item-tit">覆盖全国千所高校万名会员</h3>
<div className="info-item-content">活动邀请10+全球顶尖开源基金会100+顶级开源项目社区致力营造专业开放的开源社区</div>
</div>
<div className="info-item">
<img className="info-item-img" src={lightspot3}></img>
<img className="info-item-img" src={lightspot3} alt=''></img>
<h3 className="info-item-tit">结识开源伙伴和技术大咖</h3>
<div className="info-item-content">每个项目配备一名导师参与开源项目开发可接受一线资深开源项目专家专业指导结识志同道合的开发伙伴</div>
</div>
<div className="info-item">
<img className="info-item-img" src={lightspot4}></img>
<img className="info-item-img" src={lightspot4} alt=''></img>
<h3 className="info-item-tit">丰厚奖励&实习绿色通道</h3>
<div className="info-item-content">入选同学可获得丰厚奖金并有机会进入优秀开源项目企业实习或工作受邀参与开源大会等机会</div>
</div>

View File

@ -10,6 +10,7 @@
.info-teacher {
display: flex;
justify-content: space-between;
margin-bottom: 50px;
}
.teacher-text {
margin-right: 2.84%;
@ -26,6 +27,19 @@
opacity: .8;
color: white !important;
cursor: pointer;
.hover-show{
display: inline-block;
}
.hover-none{
display: none;
}
}
&:hover.project{
background-color:#abafbe;
cursor: default;
}
.hover-show{
display: none;
}
}
}

View File

@ -25,6 +25,8 @@ import log65 from '../../img/65@2x.png';
import log67 from '../../img/67@2x.png';
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() {
return (
@ -149,6 +151,8 @@ function Partner() {
<div onClick={()=>{window.open("https://www.ecnu.edu.cn/")}}><img src={log65} className='gitlink' alt='华东师范大学'/></div>
<div onClick={()=>{window.open("http://www.csust.edu.cn/")}}><img src={log67} className='gitlink' alt='长沙理工大学'/></div>
<div onClick={()=>{window.open("https://www.jnu.edu.cn/")}}><img src={log50} className='gitlink' alt='暨南大学'/></div>
<div onClick={()=>{window.open("https://www.shu.edu.cn/")}}><img src={logo2} className='gitlink' alt='上海大学'/></div>
<div onClick={()=>{window.open("https://www.bnu.edu.cn/")}}><img src={logo1} className='gitlink' alt='北京师范大学'/></div>
</div>
</div>
</div>

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 479 KiB

After

Width:  |  Height:  |  Size: 4.0 MiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 384 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 410 KiB

View File

@ -23,12 +23,22 @@ const Apply = Loadable({
loader: () => import("./apply"),
loading: Loading,
});
//
//
const Help = Loadable({
loader: () => import("./help"),
loading: Loading,
});
//
const Student = Loadable({
loader: () => import("./student"),
loading: Loading,
});
//
const Project = Loadable({
loader: () => import("./project"),
loading: Loading,
});
const Glcc = (propsF) => {
// 415~520
@ -37,6 +47,13 @@ const Glcc = (propsF) => {
return (
<div className="newMain clearfix">
<Switch {...propsF}>
{/* 学生报名 */}
<Route
path="/glcc/student/apply/:taskId"
render={(props) => (
<Student {...propsF} {...props} isGlccApplyDate={isGlccApplyDate}/>
)}
></Route>
{/* 开源夏令营报名页面 */}
<Route
path="/glcc/apply"
@ -51,6 +68,13 @@ const Glcc = (propsF) => {
<Help {...propsF} {...props} />
)}
></Route>
{/* 项目/课题列表 */}
<Route
path="/glcc/student"
render={(props) => (
<Project {...propsF} {...props} />
)}
></Route>
{/* 首页 */}
<Route
path="/glcc"

View File

@ -1,4 +1,5 @@
.glccHelp{
.-task-sidebar .glccHelp{
height: auto;
width: 48px;
padding: 6px 16px;
text-align: center;
@ -7,13 +8,39 @@
border-radius:2px;
box-shadow:0px 0px 8px rgba(55, 148, 255, 0.16);
color:#1e1e1e;
font-size: 14px;
line-height: 35px;
word-break: break-word;
cursor: pointer;
.icon-bangzhuzhongxinicon{
.icon-bangzhuzhongxinicon, .icon-bangzhuzhongxinicon1{
color: #0654D6;
margin-left: -3px;}
&:hover{
color:#ffffff;
background-color:#466aff;
.icon-bangzhuzhongxinicon{color:#ffffff}
.icon-bangzhuzhongxinicon, .icon-bangzhuzhongxinicon1{color:#ffffff}
}
}
.qqChatBox .ant-popover-arrow{display: none;}
.qqChat{
margin: -12px -16px;
background-image:linear-gradient(180deg,#f8faff 0%,#dee7ff 100%);
border:1px solid #ffffff;
border-radius:4px;
box-shadow:0px 0px 6px rgba(121, 154, 245, 0.27);
padding: 25px 40px;
text-align: center;
.qqMa{
padding: 8px;
margin-bottom: 15px;
text-align: center;
background-image:radial-gradient(ellipse 50% 50% at 50% 50% ,rgba(255, 255, 255, 0) 0%,rgba(239, 243, 251, 0) 100%);
box-shadow:0px 0px 6px #aecaff inset;
img{width: 120px;}
}
.qqTip{
color:#5769a5;
font-size:14px;
line-height:24px;
}
}

View File

@ -0,0 +1,63 @@
import React, { useState } from 'react';
import { Button } from 'antd';
import Nodata from '../../../forge/Nodata';
import { useEffect } from 'react';
import { getProjectById } from '../../api';
export default ({ detail, projectId, applyTaskId }) => {
const [info, setInfo] = useState(detail);
useEffect(()=>{
if(!detail && projectId){
// Id
getProjectById(projectId).then(response=>{
if(response && response.message === 'success'){
setInfo(response.data)
}
})
}
},[detail])
// detail && (detail.registrationTaskList = [{
// id: 1,
// taskName: 'aaaa',
// tutorName: 'daoshi',
// tutorMail: 'email',
// taskDesc: 'sfdjhdf,hsldf',
// taskUrl: 'url',
// taskReward: '9000'
// },{
// id: 2,
// taskName: 'aaaa',
// tutorName: 'daoshi',
// tutorMail: 'email',
// taskDesc: 'sfdjhdf,hsldfaaaaaaaaaaaaaaaa',
// taskUrl: 'url',
// taskReward: '9000'
// }])
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>{info.gitlinkUrl}</p>
<div>{info.officialWebsiteUrl}</div>
</div>
{info.registrationTaskList && info.registrationTaskList.length > 0 ? info.registrationTaskList.map(item=>{
return <div className='taskItem mt20'>
<div className="left">
<div className="taskTitle">{item.taskName}</div>
<div className='mt20'>导师姓名: &nbsp;&nbsp;{item.tutorName}</div>
<div className='mb20 email'>邮箱地址: &nbsp;&nbsp;<span>{item.tutorMail}</span></div>
</div>
<div className="center">
<div className="taskDesc">{item.taskDesc}</div>
<div className="taskUrl">课题链接: &nbsp;&nbsp;<span>{item.taskUrl}</span></div>
<div>{applyTaskId && item.id && Object.keys(applyTaskId).includes(item.id.toString()) ? <Button onClick={()=>{window.location.href=`/glcc/student/apply/${item.id}`}}>报名详情</Button> : <Button type='primary' className='applyBut' onClick={()=>{window.location.href=`/glcc/student/apply/${item.id}`}}>申请课题</Button>}</div>
</div>
<div className="right"> {item.taskReward}</div>
</div>
}) : <Nodata _html="课题暂无数据" small={true}/>}
</div>: <div className="projectDetailBox nodata"><Nodata _html="暂无数据" small={true}/></div>
)
}

View File

@ -0,0 +1,74 @@
import React , { useEffect , useState } from 'react';
import { Spin } from 'antd';
import { Route, Switch } from "react-router-dom";
import banner from "../img/studentProject.png";
import './index.scss';
import Loadable from "react-loadable";
import Loading from "../../Loading";
import { Link } from 'react-router-dom';
import { getStudentApplyInfo } from '../api';
//
const ProjectList = Loadable({
loader: () => import("./projectList"),
loading: Loading,
});
//
const TaskList = Loadable({
loader: () => import("./taskList"),
loading: Loading,
});
function Project(propsF) {
const {location, current_user} = propsF;
const {pathname} = location;
// id
const [applyTaskId, setApplyTaskId] = useState({});
//
const [studentInfoReset, setStudentInfoReset] = useState(undefined);
useEffect(()=>{
// current_user user_id
getStudentApplyInfo({userId: current_user && current_user.user_id}).then(response=>{
if(response && response.message === "success"){
// setData(response.data.rows);
const data = {};
response.data && response.data.registrationStudentTaskList.map(item=>{
data[item.taskId] = item.id;
})
setApplyTaskId(data);
}
})
},[studentInfoReset])
return(
<div className="glcc_project">
<img className="glcc-banner" src={banner} alt=''></img>
<div className='head'>
<Link to="/glcc/student/2" className={pathname.lastIndexOf('/2') !== -1 ? 'active' : ''}>课题列表</Link>
<Link to="/glcc/student/1" className={pathname.lastIndexOf('/1') !== -1 ? 'active' : ''}>项目列表</Link>
</div>
<div className='gobackBox'>
<a href='/glcc'>开源夏令营 / </a>
课题及项目列表
</div>
<Spin spinning={false}>
<Switch {...propsF}>
<Route
path="/glcc/student/1"
render={(props) => (
<ProjectList applyTaskId={applyTaskId}/>
)}
></Route>
<Route
path="/glcc/student/2"
render={(props) => (
<TaskList applyTaskId={applyTaskId} setStudentInfoReset={setStudentInfoReset}/>
)}
></Route>
</Switch>
</Spin>
</div>
)
}
export default Project;

160
src/glcc/project/index.scss Normal file
View File

@ -0,0 +1,160 @@
.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%);
.list{
width: 1200px;
margin: 0 auto;
.search{
width: 40%;
margin: 0 auto;
padding: 25px 0 40px;
}
.search .ant-btn, .search .ant-input{
height: 48px;
}
.search .ant-btn{font-size: 30px;}
.search .ant-input{
font-size: 16px;
border-color: #ebf2ff;
&:hover{
border-color: #466aff;
}
}
}
.search{
.ant-btn-primary{
background-color:#466aff;
border-color: #466aff;
}
// .ant-input:hover{
// border-color: #466aff;
// }
}
}
}
.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: 60%;
}
.right{padding-right: 10px;}
}
}
&.nodata{width: 200px;}
font-size:15px;
line-height:30px;
.projectDetailHead{
color:#465474;
padding-bottom: 12px;
border-bottom: 1px dashed #bec5d5;
.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;
}
}
.taskItem {
display: flex;
justify-content: space-between;
background-color: #ffffff;
box-shadow: 0px 0px 12px rgba(71, 105, 198, 0.4);
.left{
width: 250px;
background-image: url('../img/projectDetailTaskBg.png');
background-size: 100% 100%;
padding: 22px 20px;
color:#25304a;
.taskTitle{
color:#1834a7;
font-size:18px;
}
.email span{color:#466aff;}
}
.center{
width: 66%;
text-align: left;
padding: 20px;
display: flex;
flex-direction: column;
justify-content: space-between;
.taskDesc{
color:#6b6b6b;
}
.taskUrl{
color:#465474;
font-size:16px;
span{color:#466aff;}
}
.applyBut{
background-color:#466aff;
border-color: #466aff;
&:hover{background-color:#5d7cff;}
&:focus{background-color:#1140ff;}
}
}
.right{
font-weight:700;
color:#ff8800;
font-size:24px;
padding: 30px 30px 0 0;
}
}
}
.projectItemPopover{width: 1200px;}
.projectItemPopover .ant-popover-inner{
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;
}
}

View File

@ -0,0 +1,48 @@
import React , { useEffect , useState } from 'react';
import { Input, Popover, Table, Tooltip } from 'antd';
import { main_site_url } from '../../fetch';
import './index.scss';
import { projectList } from '../../api';
import ProjectDetail from '../component/projectDetail';
const {Search} = Input;
//
function ProjectList({applyTaskId}) {
//
const [keyword, setKeyword] = useState(undefined);
const [data, setData] = useState([]);
useEffect(()=>{
const params = {
curPage: 1,
keyword,
pageSize: 20
}
projectList(params).then(response=>{
if(response && response.message === "success"){
setData(response.data.rows);
}
})
},[keyword])
return(
<div className="taskList listBox">
<div className="list">
<div className='search'><Search placeholder='请输入项目名称进行搜索' allowClear enterButton onSearch={(value)=>{setKeyword(value)}}/></div>
<div className='projectListBox'>
{data && data.map((item, index)=>{
return <Popover placement= {(index+1)%3 === 0 ? 'bottomRight' : (index+1)%3%2 === 0 ? 'bottom' : 'bottomLeft'} content={<ProjectDetail detail={item} applyTaskId={applyTaskId}/>} trigger='click' overlayClassName='projectItemPopover'>
<div className={`projectItem ${(index+1)%3 === 0 || (index+1)%3%2 === 0 ? '' : 'firstBox'}`}>
<div className="border"></div>
<div className="projectLogo"><img src={`${main_site_url}/api/attachments/${item.projectLogoId}`} alt=''/></div>
<div className="title">{item.projectName}</div>
<div className="intro">{item.projectIntro}</div>
</div>
</Popover>
})}
</div>
</div>
</div>
)
}
export default ProjectList;

View File

@ -0,0 +1,80 @@
.actionBox{
display: flex;
align-items: center;
color: #466aff;
cursor: pointer;
.iconfont{
margin: 0 10px 0 14px;
}
.applyTask{
color:#eb9350;
}
}
.projectListBox{
display: flex;
flex-wrap: wrap;
// justify-content: space-between;
.projectItem{
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#FFFFFF85%
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;
}
.projectLogo{
width: 100px;
height: 100px;
border: 1px solid #fff;
border-radius: 50%;
text-align: center;
overflow: hidden;
margin: 25px auto 10px;
img{
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;
}
}
}

View File

@ -0,0 +1,136 @@
import React, { Fragment, useEffect, useState } from 'react';
import { Input, message, Modal, Table, Tooltip } from 'antd';
import './index.scss';
import { cancelTaskApply, taskList } from '../../api';
import ProjectDetail from '../component/projectDetail';
const { Search } = Input;
//
function TaskList({applyTaskId, setStudentInfoReset}) {
const [visible, setVisible] = useState(false);
const [deleteTaskId, setDeleteTaskId] = useState(undefined);
//
const [keyword, setKeyword] = useState(undefined);
const [data, setData] = useState([]);
// table
const [current, setCurrent] = useState(1);
const [total, setTotal] = useState(0);
const [pageSize, setPageSize] = useState(20);
const columns = [
{ title: '序号', dataIndex: 'index', align: 'center', className:"taskTableColumns", render: (text, item, index) => index + 1 },
{ title: '课题名称', dataIndex: 'taskName', className:"taskTableColumns taskName", width: '28%', render: (text, item) => <Tooltip title={text}><a onClick={()=>{window.location.href=item.taskUrl}}>{text}</a></Tooltip> },
{ title: '项目名称', dataIndex: 'tutorName', className:"taskTableColumns", width: '28%', render: (text) => <Tooltip title={text}>{text}</Tooltip> },
{ title: '课题奖金', dataIndex: 'taskReward', className:"taskTableColumns", render: (text) => <span> {text}</span> },
{
title: '操作', dataIndex: 'action', align: 'center', className:"actionColumns taskTableColumns", render: ((text, item, index) => {
return (
<div className='actionBox'>
{applyTaskId && Object.keys(applyTaskId).includes(item.id.toString()) ? <Fragment>
<span onClick={()=>{window.location.href=`/glcc/student/apply/${item.id}`}}><i className='iconfont icon-baomingxiangqingicon mr5'></i>报名详情</span>
<Tooltip title={"取消申请"}><i className='iconfont icon-shanchuicon3 ml20 cancelApply' onClick={()=>{setDeleteTaskId(item.id);setVisible(true)}}></i></Tooltip>
</Fragment>:<Fragment>
<span onClick={()=>{window.location.href=`/glcc/student/apply/${item.id}`}}><i className='iconfont icon-shenqingketiicon applyTask mr5'></i><span className='applyTask' onClick={()=>{applyTask(item.id)}}>申请课题</span></span></Fragment>}
</div>
)
})
},
]
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} applyTaskId={applyTaskId}/>
}
//
function applyTask(id){
//
if(applyTaskId.length >= 2){
message.error('最多只能同时报名两个课题');
}else{
//
window.location.href=`/glcc/student/apply/${id}`;
}
}
//
function cancelApply(){
const id = [];
id.push(applyTaskId[deleteTaskId]);
const params = {
ids: id
}
cancelTaskApply(params).then(response=>{
if(response && response.message === "success"){
setVisible(false);
setStudentInfoReset(Math.random());
message.success('取消成功');
}
})
}
// pagesize
function onShowSizeChange(current, pageSize){
setPageSize(pageSize);
}
//
function changePage(page, pageSize){
setCurrent(page);
}
useEffect(() => {
const params = {
curPage: current,
keyword,
pageSize
}
taskList(params).then(response => {
if (response && response.message === "success") {
setData(response.data.rows);
setTotal(response.data.total)
}
})
}, [keyword, current, pageSize])
return (
<div className="taskList listBox">
<div className="list">
<div className='search'><Search placeholder='请输入课题名称进行搜索' allowClear enterButton onSearch={(value) => { setKeyword(value) }} /></div>
<Table
columns={columns}
dataSource={data}
expandedRowRender={expandRow}
expandIconColumnIndex={4}
expandIconAsCell={false}
expandIcon={customExpandIcon}
pagination={{pageSize: pageSize, total: total, showSizeChanger: true, onShowSizeChange:onShowSizeChange, showQuickJumper: true, onChange: changePage}}
/>
</div>
<Modal
okText="确认删除"
okType='default'
title="删除"
visible={visible}
onCancel={()=>{setVisible(false)}}
onOk={cancelApply}
wrapClassName='cancelApplyTask'
>
<div className='tilTask mt20'><span className='carefulIcon'>!</span>取消申请即删除本次报名记录确定取消</div>
<p className='tipTask'>此操作将永久删除该报名记录请进行确认以防数据的丢失</p>
</Modal>
</div>
)
}
export default TaskList;

View File

@ -0,0 +1,91 @@
.taskList{
padding-bottom: 50px;
.ant-table{
border: 1px solid white;
}
}
.taskTableColumns span div span{
font-size: 16px;
font-weight:700;
color:#273778;
}
.taskTableColumns span{
font-size: 15px;
color: #353f5e;
}
.taskTableColumns.taskName a{
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;}
}
.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: 30px 0 30px 86px !important;
}
.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;}
}
}
}
}

View File

@ -1,12 +1,30 @@
import React from 'react';
import { Popover } from 'antd';
import qqChat from "./img/qqChat.png";
import './index.scss';
function SiderBar() {
const content = (
<div className='qqChat'>
<div className='qqMa'><img src={qqChat} alt=''/></div>
<p className='qqTip'>扫码进入QQ交流群</p>
<p className='qqTip'>把握最新活动资讯</p>
</div>
)
return (
// 开源夏令营定制帮助中心调整按钮
<div className={"glccHelp -task-sidebar"} onClick={()=>window.open("/glcc/help")}>
<i className='iconfont icon-bangzhuzhongxinicon font-20'></i>
帮助中心
<div className={"-task-sidebar"}>
<Popover placement='leftBottom' content={content} title={null} forceRender={true} overlayClassName='qqChatBox'>
<div className={"glccHelp"}>
<i className='iconfont icon-bangzhuzhongxinicon1 font-20'></i>
QQ交流
</div>
</Popover>
<div className={"glccHelp"} onClick={()=>window.open("/glcc/help")}>
<i className='iconfont icon-bangzhuzhongxinicon font-20'></i>
帮助中心
</div>
</div>
)
}

477
src/glcc/student/index.jsx Normal file
View File

@ -0,0 +1,477 @@
import React, { useCallback, useEffect, useState, Fragment } from 'react';
import { Breadcrumb, Button, Form, Input, Select, Upload, Cascader, Spin } from 'antd';
import { getUploadActionUrl, getUrl, appendFileSizeToUploadFileAll } from 'educoder';
import { locData } from '../../forge/Utils/locData';
import { getStudentApplyInfo, taskList, studentApply, studentApplyEdit } from '../api';
import TextArea from 'antd/lib/input/TextArea';
import { httpUrl } from '../fetch';
import banner from "../img/banner.png";
import studentSvg from "../img/student.png";
import './index.scss';
import { Link } from 'react-router-dom';
const Option = Select.Option;
const gradeList = [
{ id: '大一', name: '大一' },
{ id: '大二', name: '大二' },
{ id: '大三', name: '大三' },
{ id: '大四', name: '大四' },
{ id: '大五', name: '大五' },
{ id: '研一', name: '研一' },
{ id: '研二', name: '研二' },
{ id: '研三', name: '研三' }];
function Apply(props) {
const { form, current_user, showNotification, isGlccApplyDate, match } = props;
const taskId = Number(match.params.taskId);
//
// current_user && (current_user.user_id = 6)
// current_user && (current_user.userName = "使")
const { getFieldDecorator, validateFields, setFieldsValue, validateFieldsAndScroll } = form;
const [imageUrl, setImageUrl] = useState(undefined);
const [loading, setLoading] = useState(false);
const [reload, setReload] = useState();
const [userApplyInfo, setUserApplyInfo] = useState(undefined);
const [editable, setEditable] = useState(true);
const [files, setFiles] = useState([]);
const [files1, setFiles1] = useState([]);
const initTask = {
taskId,
memo: '',
memoAttachmentId: ''
};
const [myTaskList, setMyTaskList] = useState([]);
const [allTaskList, setAllTaskList] = useState([]);
useEffect(() => {
//
window.scrollTo(0, 0);
if (!isGlccApplyDate) {
//
window.location.href = "/glcc";
} else if (current_user && current_user.login) {
} else {
window.location.href = "/login?go_page=/glcc";
}
}, [])
useEffect(() => {
const params = {
curPage: 1,
pageSize: 10000
}
taskList(params).then(response => {
if (response && response.message === "success") {
setAllTaskList(response.data.rows);
}
})
}, [])
useEffect(() => {
//
current_user && getStudentApplyInfo({ userId: current_user.user_id }).then(response => {
if (response && response.message === "success" && response.data) {
let data = response.data;
let applyInfo = {
grade: data.grade,
location: data.location && data.location.split(','),
mail: data.mail,
phone: data.phone,
proveAttachmentId: data.proveAttachmentId,
school: data.school,
studentName: data.studentName,
userId: current_user.user_id,
profession: data.profession,
};
if (Array.isArray(data.registrationStudentTaskList)) {
if (data.registrationStudentTaskList.length) {
let initTaskList = [];
for (const [i, item] of data.registrationStudentTaskList.entries()) {
applyInfo['memo' + i] = item.memo;
applyInfo['taskId' + i] = item.taskId;
applyInfo['memoAttachmentId' + i] = item.memoAttachmentId;
if (i == 0) {
setFiles([{
name: item.memoAttachment && item.memoAttachment.fileName || '已上传文件',
id: item.memoAttachmentId,
uid: item.memoAttachmentId
}]);
} else {
setFiles1([{
name: item.memoAttachment && item.memoAttachment.fileName || '已上传文件',
id: item.memoAttachmentId,
uid: item.memoAttachmentId,
}]);
}
initTaskList.push({
id: item.id,
memo: item.memo,
memoAttachmentId: item.memoAttachmentId,
taskId: item.taskId,
});
}
setMyTaskList(initTaskList);
// idid
if (data.registrationStudentTaskList.length === 1 && data.registrationStudentTaskList[0].taskId != taskId) {
addTask(data.registrationStudentTaskList);
}
} else {
//
new Promise((resove) => {
setMyTaskList(() => {
resove();
return [initTask]
});
}).then(res => setFieldsValue({ 'taskId0': taskId }))
}
}
setFieldsValue(applyInfo);
setUserApplyInfo(response.data);
} else {
//
new Promise((resove) => {
setMyTaskList(() => {
resove();
return [initTask]
});
}).then(res => setFieldsValue({ 'taskId0': taskId }))
}
})
}, [current_user, reload])
//
function verify(dataIndex) {
validateFields([dataIndex], (error, values) => {
if (error && error[dataIndex]) {
return;
}
})
}
//
function handleSubmit(e) {
e.preventDefault();
validateFieldsAndScroll((err, values) => {
if (!err) {
setLoading(true);
const params = {
grade: values.grade,
location: Array.isArray(values.location) && values.location.join(),
mail: values.mail,
phone: values.phone,
proveAttachmentId: values.proveAttachmentId.file ? values.proveAttachmentId.file.response.id : userApplyInfo.proveAttachmentId,
school: values.school,
profession: values.profession,
studentName: values.studentName,
userId: current_user.user_id,
registrationStudentTaskList: myTaskList
}
if (userApplyInfo) {
params.id = userApplyInfo.id;
studentApplyEdit(params).then(response => {
if (response && response.message === "success") {
showNotification("修改信息成功");
setReload(Math.random());
setLoading(false);
}
});
} else {
studentApply(params).then(response => {
if (response && response.message === "success") {
showNotification("报名成功");
setReload(Math.random());
setLoading(false);
}
});
}
}
});
};
const helper = useCallback(
(label, extra, name, rules, widget) => (
<Form.Item label={label} extra={extra}>
{getFieldDecorator(name, { rules, validateFirst: true })(widget)}
</Form.Item>
),
[]
);
//
function beforeUpload(file) {
const isType = file.type === "image/png" || file.type === "image/jpg" || file.type === "image/jpeg";
if (!isType) {
showNotification("只能上传png、jpg、jpeg格式文件");
}
return 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 bookChange(info, i) {
if (info.file.status === 'uploading' || info.file.status === "done" || info.file.status === 'removed') {
setLoading(true);
if (info.file.status === "done") {
changeTaskItem('memoAttachmentId', info.fileList[0].response && info.fileList[0].response.data.id, i)
}
if (info.file.status === 'removed') {
console.log(1111)
changeTaskItem('memoAttachmentId', '', i);
}
console.log(info.fileList);
if (i) {
setFiles1(appendFileSizeToUploadFileAll(info.fileList).slice(-1));
} else {
setFiles(appendFileSizeToUploadFileAll(info.fileList).slice(-1));
}
}
if (info.file.status === "done" || info.file.status === 'removed') {
setLoading(false);
}
}
//
function download(file) {
const fileId = file.id || file.response.data.id;
window.open(`${httpUrl}/busiAttachments/download/${fileId}`);
}
function addTask(List) {
let taskListNew = List ? [...List] : [...myTaskList];
if (taskId != taskListNew[0].taskId) {
taskListNew.push(initTask);
//
new Promise((resove) => {
setMyTaskList(() => {
resove();
return taskListNew
});
}).then(res => setFieldsValue({ 'taskId1': taskId }))
} else {
taskListNew.push({ ...initTask, taskId: '' });
setMyTaskList(taskListNew);
}
}
function deleteTask(i) {
let taskListNew = myTaskList.slice();
let reWriteInfo;
if (i) {
reWriteInfo = {
taskId1: '',
memo1: '',
memoAttachmentId1: ''
}
setFiles1([]);
} else {
reWriteInfo = {
taskId0: taskListNew[1].taskId,
memo0: taskListNew[1].memo,
memoAttachmentId0: taskListNew[1].memoAttachmentId,
taskId1: '',
memo1: '',
memoAttachmentId1: ''
}
setFiles(files1);
setFiles1([]);
}
taskListNew.splice(i, 1);
setMyTaskList(taskListNew);
setFieldsValue(reWriteInfo);
}
function changeTaskItem(field, val, i) {
let taskListNew = [...myTaskList];
taskListNew[i][field] = val;
setMyTaskList(taskListNew);
}
return (
<div className="glcc_student_apply">
<img className="glcc-banner" src={banner} alt=''></img>
<Spin spinning={loading}>
<div className='apply'>
<Breadcrumb className='glcc_breadcrumb font-16'>
<Breadcrumb.Item><Link to="/glcc">开源夏令营</Link></Breadcrumb.Item>
<Breadcrumb.Item><Link to="/glcc/student/2">查看项目</Link></Breadcrumb.Item>
<Breadcrumb.Item>学生报名</Breadcrumb.Item>
</Breadcrumb>
<div className="head_introduce">
<h4 className="head_tit">申请说明</h4>
<div className="head_content">1学生报名时间为<span className="head_bold">2022年5月21日-6月19日</span>请在报名截止时间北京时间<span className="head_bold">2022年6月19日18点</span>前提交报名信息</div>
<div className="head_content">2本次GLCC夏令营基于GitLink代码托管平台完成编程任务若您没有平台账户请先注册后完成课题申请</div>
<div className="head_content">3每位学员最多可申请2个课题至多有且仅有1个课题可以入选</div>
<div className="head_content">4建议在提交课题申请与课题导师邮件沟通详细了解课题描述编码任务技能要求&编程语言预期产出结果等信息以便您能够选择最适合的课题</div>
<div className="head_content">5提交申请后请耐心等待我们会在2022年7月1日公布入围结果如有任何问题请添加开源夏令营微信群进行咨询</div>
</div>
<div className="main-tit">
<img src={studentSvg} /><span className="tit-text">学生报名</span>
</div>
<div className="form-tit">申请课题</div>
<Form className="glcc_info_form" onSubmit={handleSubmit}>
<h4 className="item-tit">基本信息</h4>
{helper('学生姓名',
'',
'studentName',
[{ required: true, message: "请正确输入学生姓名" },
{ max: 32, message: '超出限制长度32位字符请重新编辑' }],
<Input placeholder="请输入学生姓名" onBlur={() => { verify("studentName") }} className={editable ? "" : "disabledInput"} disabled={editable ? false : true} />
)}
{helper('所在高校',
'',
'school',
[{ required: true, message: "请正确输入所在高校" },
{ max: 32, message: '超出限制长度32位字符请重新编辑' }],
<Input placeholder="请输入所在高校" onBlur={() => { verify("school") }} className={editable ? "" : "disabledInput"} disabled={editable ? false : true} />
)}
{helper('所学专业',
'',
'profession',
[{ max: 32, message: '超出限制长度32位字符请重新编辑' }],
<Input placeholder="请输入所学专业" onBlur={() => { verify("profession") }} className={editable ? "" : "disabledInput"} disabled={editable ? false : true} />
)}
<Form.Item label="地区">
{getFieldDecorator("location", {
rules: []
})(
<Cascader placeholder="请选择省份城市" options={locData} className={editable ? "" : "disabledInput"} disabled={editable ? false : true} />
)}
</Form.Item>
{helper('所在年级',
'',
'grade',
[],
<Select placeholder="请选择所在年级" disabled={editable ? false : true} className={editable ? "" : "disabledInput"}>
{gradeList.map(item => { return <Option value={item.name} key={item.id}>{item.name}</Option> })}
</Select>
)}
{helper('联系电话',
'',
'phone',
[{ required: true, message: "请正确输入联系电话" }],
<Input placeholder="请输入联系电话" onBlur={() => { verify("phone") }} className={editable ? "" : "disabledInput"} disabled={editable ? false : true} />
)}
{helper('邮箱地址',
'',
'mail',
[{ required: true, message: "请正确输入邮箱地址" }],
<Input placeholder="请输入邮箱地址" onBlur={() => { verify("mail") }} className={editable ? "" : "disabledInput"} disabled={editable ? false : true} />
)}
<div className='introArea update_item'>{helper('学生证明',
'请以图片的形式上传学生证明格式为png、jpg、jpeg',
'proveAttachmentId',
[{ required: true, message: "请正确上传学生证明" }],
userApplyInfo && userApplyInfo.proveAttachmentId ? <div className='projectLogo'><img src={`${getUrl()}/api/attachments/${userApplyInfo.proveAttachmentId}`} 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">请上传学生证明</div>
</div>}
</Upload>
)}</div>
{
myTaskList.map((item, i) => {
return (
<Fragment key={item.taskId + '' + i}>
<h4 className="item-tit">课题信息<span className="item-tit-num">{i + 1}</span>/2) {myTaskList.length > 1 && <i className="iconfont icon-shanchu" onClick={() => { deleteTask(i) }}></i>}</h4>
{helper('课题名称',
'',
'taskId' + i,
[{ required: true, message: "请选择课题名称" }],
<Select
placeholder="请选择课题名称"
showSearch
disabled={editable ? false : true}
className={editable ? "" : "disabledInput"}
filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) > -1}
onBlur={() => { verify("taskId" + i) }}
onChange={(val) => { changeTaskItem("taskId", val, i) }}
>
{allTaskList.map(item => { return <Option value={item.id} key={item.id + ''}>{item.taskName}</Option> })}
</Select>
)}
<div className='introArea'>{helper('自荐书',
'',
'memo' + i,
[{ required: true, message: "请正确输入自荐书" },
{ max: 500, message: '超出限制长度500位字符请重新编辑' }],
<TextArea placeholder="请填写你的优势和能力不超过500字" onBlur={(e) => { verify("memo" + i); changeTaskItem("memo", e.currentTarget.value, i) }} rows={4} className={editable ? "" : "disabledInput"} />
)}</div>
<div className='introArea'>{helper('附件',
'',
'memoAttachmentId' + i,
[],
<Upload
// action={getUploadActionUrl()}
action={httpUrl + `/busiAttachments/upload`}
fileList={i ? files1 : files}
onChange={(info) => { bookChange(info, i) }}
onDownload={download}
showUploadList={{
showDownloadIcon: true,
downloadIcon: <i className="iconfont icon-xiazai-icon"></i>,
showRemoveIcon: true
}}
>
<div className="glcc_btn">上传自荐书</div>
</Upload>
)}</div>
</Fragment>
)
})
}
{
myTaskList.length < 2 && <Button className="add_task" type="primary" onClick={() => { addTask() }}>添加课题</Button>
}
<Form.Item className='subInfo introArea'>
<Button type="primary" htmlType="submit" className='sub' disabled={!editable}>提交</Button>
</Form.Item>
</Form>
</div>
</Spin>
</div>
)
}
export default Form.create()(Apply);

281
src/glcc/student/index.scss Normal file
View File

@ -0,0 +1,281 @@
.glcc_student_apply {
font-family: PingFang SC;
background-image: linear-gradient(
180deg,
#ebf2ff 0%,
#ebf2ff 43.09%,
#f3f4f8 100%
);
padding-bottom: 120px;
.has-error .ant-form-explain,
.has-error .ant-form-split {
position: absolute;
}
.ant-btn-primary{
background-color: #466aff;
border-color: #466aff;
&:hover {
background-color: #5d7cff;
border-color: #5d7cff;
}
&:active {
background-color: #1140ff;
border-color: #1140ff;
}
}
.apply {
width: 1200px;
margin: 0 auto;
}
.glcc_breadcrumb {
padding: 18px 0;
border-bottom: 1px dashed #bec5d5;
margin-bottom: 30px;
}
.head_introduce {
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;
}
.main-tit {
margin: 25px 0;
img {
width: 25px;
margin-right: 10px;
}
.tit-text {
color: #333333;
font-size: 18px;
line-height: 30px;
}
}
.form-tit {
background-color: #e1e8ff;
color: #333333;
font-size: 18px;
line-height: 56px;
font-weight: 500;
text-align: center;
}
.item-tit {
width: 100%;
line-height: 66px;
color: #333333;
font-size: 16px;
border-bottom: 1px dashed #bec5d5;
margin-bottom: 20px !important;
&::before {
position: relative;
top: 2px;
content: "";
display: inline-block;
width: 5px;
height: 14px;
margin-right: 10px;
background-color: #466aff;
}
.item-tit-num{
color:#466aff;
}
}
.glcc_info_form {
padding: 0 15px;
}
.glcc_info_form {
display: flex;
flex-wrap: wrap;
.ant-row.ant-form-item {
margin-bottom: 20px;
display: flex;
width: 50%;
justify-content: flex-end;
}
.ant-form-item:nth-child(2n) {
.ant-form-item-control-wrapper {
padding-right: 3%;
}
}
.ant-col.ant-form-item-control-wrapper {
width: 85%;
}
.ant-form-item-label {
margin-right: 15px;
& > label::after {
content: none;
}
}
.ant-upload.ant-upload-select-picture-card {
margin-bottom: 0;
width: 118px;
height: 118px;
border: 1px solid;
}
.icon-tianjiadaohang:before {
color: #b3c3db;
}
.ant-upload-text {
color: #a4aabb;
}
.ant-input,
.ant-select-selection,
.ant-upload.ant-upload-select-picture-card {
background: none !important;
border-color: #b3c3db;
&:hover {
border-color: #466aff;
}
}
.has-error .ant-input:not([disabled]) {
border-color: #ef0000;
}
.disabledInput,
.disabledInput .ant-select-selection {
background-color: #e5ebf9 !important;
border: none;
color: #202d40;
}
.projectLogo {
width: 120px;
height: 120px;
border: 1px dashed #b3c3db;
border-radius: 4px;
line-height: 120px;
text-align: center;
img {
max-width: 100px;
max-height: 100px;
}
}
}
.ant-cascader-picker{
background: none;
&:hover{
.ant-cascader-input{
border:1px solid #466aff;
}
}
&:focus .ant-cascader-input {
box-shadow: none;
}
}
.introArea {
width: 100%;
.ant-row.ant-form-item {
width: auto;
justify-content: flex-start;
}
.ant-col.ant-form-item-control-wrapper {
width: 90%;
}
.ant-form-item-label {
width: 74px;
}
&.tips {
margin-left: 40px;
color: #e90000;
}
}
.update_item{
.ant-form-explain{
bottom: 17px;
}
}
.glcc_info_form .introArea.subInfo {
width: 100%;
text-align: center;
margin: 40px 0 70px -60px;
.sub {
width: 200px;
height: 36px;
background-color: #466aff;
border-color: #466aff;
&:hover {
background-color: #5d7cff;
border-color: #5d7cff;
}
&:active {
background-color: #1140ff;
border-color: #1140ff;
}
}
}
.explain {
background-color: #f6f9fe;
border: 2px solid;
border-color: #ffffff;
color: #6c7283;
padding: 20px 30px 30px 20px;
.c000 {
color: #000000;
}
div > .c000 {
font-weight: bold;
}
> div {
margin: 10px 0;
}
.link {
color: rgba(70, 106, 255, 1);
&:hover {
opacity: 0.8;
}
}
}
.applySuccess {
height: 45px;
border: 1px solid;
border-color: #466aff;
line-height: 45px;
padding-left: 20px;
color: #466aff;
}
.glcc_btn {
width: 90px;
height: 32px;
border: 1px solid;
border-color: #b3c3db;
border-radius: 4px;
color: #466aff;
font-size: 14px;
line-height: 30px;
text-align: center;
cursor: pointer;
&:hover{
opacity: .8;
}
}
.add_task{
margin-left:90px;
}
.icon-shanchu{
float: right;
color: #466aff;
cursor: pointer;
:hover{
color: #1140ff;
}
}
}
.glcc-banner {
width: 100%;
}