This commit is contained in:
谢思 2022-05-20 09:08:37 +08:00 committed by caishi
parent 9a32e37a0c
commit 5605d1638e
9 changed files with 197 additions and 150 deletions

View File

@ -10,7 +10,7 @@ function Award() {
<div className="glcc-content">
<div className="award-item">
<div className="award-tit">丰厚现金奖励</div>
<div className="award-content">根据课题开发耗时对应奖金从<span className="number">6000</span>元至<span className="number">12000</span>元不等详细可以课题详情中具体奖金标准</div>
<div className="award-content">根据课题开发耗时对应奖金从<span className="number">6000</span>元至<span className="number">12000</span>元不等可在课题详情中查看具体奖金标准</div>
<div className="award-line"></div>
</div>

View File

@ -46,7 +46,7 @@ const stepArr = [{
{
title: "Step2",
date: "10.21-11.11",
content: "评选公布优秀项目和学员&学员",
content: "评选公布优秀项目和学员",
noArrow: true,
}
]

View File

@ -56,8 +56,8 @@ export default ({ detail, projectId, applyTaskId, current_user, showLoginDialog,
<div className="projectDetailHead">
<span className='name'>{info.projectName}</span>
{info.projectType && <span className='type'>{info.projectType}</span>}
<p>GitLink项目地址: {info.gitlinkUrl}</p>
<div>项目简介: {info.projectIntro}</div>
<p>GitLink项目地址:&nbsp;&nbsp;<a href={info.gitlinkUrl} className='linkUrl'>{info.gitlinkUrl}</a></p>
<div>项目简介:&nbsp;&nbsp;{info.projectIntro}</div>
</div>
{info.registrationTaskList && info.registrationTaskList.length > 0 ? info.registrationTaskList.map(item=>{
return <div className='taskItem mt20'>
@ -68,7 +68,7 @@ export default ({ detail, projectId, applyTaskId, current_user, showLoginDialog,
</div>
<div className="center">
<div className="taskDesc">{item.taskDesc}</div>
<div className="taskUrl">课题链接: &nbsp;&nbsp;<span>{item.taskUrl}</span></div>
<div className="taskUrl">课题链接: &nbsp;&nbsp;<span><a href={info.gitlinkUrl}>{item.taskUrl}</a></span></div>
<div>{(isStudentApplyDate || studentApplyEnd) && (applyTaskId && item.id && Object.keys(applyTaskId).includes(item.id.toString()) ? <Button onClick={()=>{window.location.href=`/glcc/student/apply/${item.id}`}} className='lookDetail'>报名详情</Button> : isStudentApplyDate && <Button type='primary' className='applyBut' onClick={()=>{applyTask(item.id)}}>申请课题</Button>)}</div>
</div>
<div className="right oneLine"> {item.taskReward}</div>

View File

@ -49,8 +49,8 @@ function Project(propsF) {
<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>
<Link to="/glcc/student/2" className={(pathname.endsWith('/2') || pathname.endsWith('/student') ) ? 'active' : ''}>课题列表</Link>
<Link to="/glcc/student/1" className={pathname.endsWith('/1') ? 'active' : ''}>项目列表</Link>
</div>
<div className='gobackBox'>
<a href='/glcc'>开源夏令营 / </a>
@ -70,6 +70,12 @@ function Project(propsF) {
<TaskList applyTaskId={applyTaskId} setStudentInfoReset={setStudentInfoReset} current_user={current_user} showLoginDialog={showLoginDialog} isStudentApplyDate={isStudentApplyDate} studentApplyEnd={studentApplyEnd}/>
)}
></Route>
<Route
path="/glcc/student"
render={(props) => (
<TaskList applyTaskId={applyTaskId} setStudentInfoReset={setStudentInfoReset} current_user={current_user} showLoginDialog={showLoginDialog} isStudentApplyDate={isStudentApplyDate} studentApplyEnd={studentApplyEnd}/>
)}
></Route>
</Switch>
</Spin>
</div>

View File

@ -88,6 +88,7 @@
color:#465474;
padding-bottom: 12px;
border-bottom: 1px dashed #bec5d5;
line-height: 36px;
.name{
font-weight:700;
color:#3753c5;
@ -99,6 +100,10 @@
border-radius:4px;
margin-left: 12px;
padding: 4px 6px;
line-height: 26px;
}
.linkUrl{
color: #466aff;
}
}
.taskItem {
@ -137,7 +142,7 @@
.taskUrl{
color:#465474;
font-size:16px;
span{color:#466aff;}
a{color:#466aff;}
}
.applyBut{
background-color:#466aff;

View File

@ -35,7 +35,7 @@ function ProjectList({applyTaskId, current_user, showLoginDialog, isStudentApply
<Spin spinning={loading}>
<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} current_user={current_user} showLoginDialog={showLoginDialog}/>} trigger='click' overlayClassName='projectItemPopover' autoAdjustOverflow={false} isStudentApplyDate={isStudentApplyDate} studentApplyEnd={studentApplyEnd}>
return <Popover placement= {(index+1)%3 === 0 ? 'bottomRight' : (index+1)%3%2 === 0 ? 'bottom' : 'bottomLeft'} content={<ProjectDetail detail={item} applyTaskId={applyTaskId} current_user={current_user} showLoginDialog={showLoginDialog} isStudentApplyDate={isStudentApplyDate} studentApplyEnd={studentApplyEnd}/>} trigger='click' overlayClassName='projectItemPopover' autoAdjustOverflow={false}>
<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>

View File

@ -128,7 +128,7 @@ function TaskList({applyTaskId, setStudentInfoReset, current_user, showLoginDial
return (
<div className="taskList listBox">
<div className="list">
<div className='search'><Search placeholder='请输入课题名称进行搜索' allowClear enterButton onSearch={(value) => { setKeyword(value) }} /></div>
<div className='search'><Search placeholder='请输入课题名称进行搜索' allowClear enterButton onSearch={(value) => { setCurrent(1); setKeyword(value) }} /></div>
<Table
loading={loading}
columns={columns}

View File

@ -20,8 +20,9 @@
font-size: 15px;
color: #353f5e;
}
.taskTableColumns.taskName a{
.ant-table-tbody .taskTableColumns.taskName span{
color: #2545c9;
cursor: pointer;
}
.ant-table-thead > tr > .taskTableColumns, .ant-table-tbody > tr > .taskTableColumns{
background-color:#F1F6FF;

View File

@ -9,6 +9,7 @@ import banner from "../img/banner.png";
import studentSvg from "../img/student.png";
import './index.scss';
import { Link } from 'react-router-dom';
import { color } from 'echarts/lib/theme/light';
const Option = Select.Option;
const gradeList = [
@ -21,7 +22,7 @@ const gradeList = [
{ id: '研二', name: '研二' },
{ id: '研三', name: '研三' }];
function Apply(props) {
const { form, current_user, showNotification, isGlccApplyDate, match } = props;
const { form, current_user, showNotification, match } = props;
const taskId = Number(match.params.taskId);
//
// current_user && (current_user.user_id = 6)
@ -42,12 +43,21 @@ function Apply(props) {
const [myTaskList, setMyTaskList] = useState([]);
const [allTaskList, setAllTaskList] = useState([]);
//
const isStudentApplyDate = Date.parse(new Date()) > 1653494400000 && Date.parse(new Date()) < 1656086400000;
//
const studentApplyEnd = Date.parse(new Date()) > 1656086400000;
useEffect(() => {
//
window.scrollTo(0, 0);
if (!isGlccApplyDate) {
//
// setTimeout(()=>{
let clientWidth = document.body.clientWidth;
let scrollHeight = 500 * clientWidth / 1920;
window.scrollTo(0, scrollHeight);
if (!isStudentApplyDate) {
//
window.location.href = "/glcc";
window.location.href = "/glcc/student/2";
} else if (current_user && current_user.login) {
} else {
@ -55,6 +65,7 @@ function Apply(props) {
}
}, [])
useEffect(() => {
const params = {
curPage: 1,
@ -94,13 +105,13 @@ function Apply(props) {
applyInfo['memoAttachmentId' + i] = item.memoAttachmentId;
if (i == 0) {
setFiles([{
item.memoAttachment && setFiles([{
name: item.memoAttachment && item.memoAttachment.fileName || '已上传文件',
id: item.memoAttachmentId,
uid: item.memoAttachmentId
}]);
} else {
setFiles1([{
item.memoAttachment && setFiles1([{
name: item.memoAttachment && item.memoAttachment.fileName || '已上传文件',
id: item.memoAttachmentId,
uid: item.memoAttachmentId,
@ -205,15 +216,29 @@ function Apply(props) {
);
//
//
function beforeUpload(file) {
const isLittle = file.size / 1024 / 1024 < 5;
if (!isLittle) {
showNotification(`文件大小必须小于${5}MB!`);
}
const isType = file.type === "image/png" || file.type === "image/jpg" || file.type === "image/jpeg";
if (!isType) {
showNotification("只能上传png、jpg、jpeg格式文件");
}
return isType;
return isLittle && isType;
}
//
function beforeUpload2(file) {
const isLittle = file.size / 1024 / 1024 < 5;
if (!isLittle) {
showNotification(`文件大小必须小于${5}MB!`);
}
return isLittle;
}
function getBase64(img, callback) {
const reader = new FileReader();
reader.addEventListener('load', () => callback(reader.result));
@ -313,6 +338,8 @@ function Apply(props) {
setMyTaskList(taskListNew);
}
const chooseArr = myTaskList.map(i => { return i.taskId });
return (
<div className="glcc_student_apply">
<img className="glcc-banner" src={banner} alt=''></img>
@ -321,12 +348,12 @@ function Apply(props) {
<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.Item style={{ color: '#202D40' }}>学生报名</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">1学生报名时间为<span className="head_bold">2022年5月26日-6月24</span>请在报名截止时间北京时间<span className="head_bold">2022年6月24日24</span>前提交报名信息</div>
<div className="head_content">2本次GLCC夏令营基于GitLink代码托管平台完成编程任务若您没有平台账户请先注册后完成课题申请</div>
<div className="head_content">3每位学员最多可申请2个课题至多有且仅有1个课题可以入选</div>
<div className="head_content">4建议在提交课题申请与课题导师邮件沟通详细了解课题描述编码任务技能要求&编程语言预期产出结果等信息以便您能够选择最适合的课题</div>
@ -335,140 +362,148 @@ function Apply(props) {
<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} />
<div className="form-content">
<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 popupClassName="glcc_cascader" placeholder="请选择省份城市" options={locData} className={editable ? "" : "disabledInput"} disabled={editable ? false : true} />
)}
</Form.Item>
{helper('所在年级',
'',
'grade',
[],
<Select placeholder="请选择所在年级" disabled={editable ? false : true} className={editable ? "" : "disabledInput"} dropdownClassName="glcc_select">
{gradeList.map(item => { return <Option value={item.name} key={item.id}>{item.name}</Option> })}
</Select>
)}
{helper('联系电话',
'',
'phone',
[{ required: true, message: "请正确输入联系电话" },
{ max: 14, message: '超出限制长度14位字符请重新编辑' },
{ pattern: /[\d-]{4,14}$/, message: '请正确输入联系电话' }],
<Input placeholder="请输入联系电话" onBlur={() => { verify("phone") }} className={editable ? "" : "disabledInput"} disabled={editable ? false : true} />
)}
{helper('邮箱地址',
'',
'mail',
[
{ type: 'email', message: '请输入正确的邮箱地址', },
{ required: true, message: "请输入邮箱地址" },
{ max: 50, message: '超出限制长度50位字符请重新编辑' },
],
<Input placeholder="请输入邮箱地址" onBlur={() => { verify("mail") }} 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>
<div className='introArea update_item'>{helper('学生证明',
'请以图片的形式上传学生证明大小不超过5M格式为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>
{
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 && <span className="delete"><i className="iconfont icon-shanchu mr5" onClick={() => { deleteTask(i) }}></i>删除</span>}</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} disabled={chooseArr.includes(item.id)} key={item.id + ''}>{item.taskName}</Option> })}
</Select>
)}
<div className='introArea'>{helper('自荐书',
<div className="memoExtra">自荐书示例<span >https://forum.gitlink.org.cn/forums/7299/detail</span></div>,
'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 ? "memoText" : "memoText 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>
)
})
}
<div className='introArea'>{helper('附件',
'可以上传自荐书文件大小不超过5M',
'memoAttachmentId' + i,
[],
<Upload
// action={getUploadActionUrl()}
action={httpUrl + `/busiAttachments/upload`}
fileList={i ? files1 : files}
onChange={(info) => { bookChange(info, i) }}
onDownload={download}
beforeUpload={beforeUpload2}
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>
{
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>
</div>
</Spin>
</div>