新增学生报名静态页面

This commit is contained in:
何童崇 2022-05-17 17:31:26 +08:00 committed by caishi
parent cdb7746e5e
commit b3398bf0d3
5 changed files with 661 additions and 1 deletions

View File

@ -16,4 +16,13 @@ export function applyGlcc(data) {
method: 'post',
data: data
});
}
}
// 获取当前学生用户报名信息
export function getStudentApplyInfo(params) {
return fetch({
url: `/api/studentApply/getUserApplyInfo`,
method: 'get',
params
});
}

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -28,6 +28,11 @@ const Help = Loadable({
loader: () => import("./help"),
loading: Loading,
});
//
const Student = Loadable({
loader: () => import("./student"),
loading: Loading,
});
const Glcc = (propsF) => {
@ -37,6 +42,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"

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

@ -0,0 +1,362 @@
import React, { useCallback, useEffect, useState, Fragment } from 'react';
import { Breadcrumb, Button, Form, Input, Select, Upload, Modal, Cascader, Tooltip } from 'antd';
import { getUploadActionUrl, appendFileSizeToUploadFileAll } from 'educoder';
import { locData } from '../../forge/Utils/locData';
import { getStudentApplyInfo, applyGlcc } from '../api';
import axios from 'axios';
import TextArea from 'antd/lib/input/TextArea';
import { main_site_url } from '../fetch';
import banner from "../img/banner.png";
import studentSvg from "../img/student.png";
import './index.scss';
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 } = match.params;
//
// 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 [userApplyInfo, setUserApplyInfo] = useState(undefined);
const [editable, setEditable] = useState(true);
const [files, setFiles] = useState([]);
const initTask = {
memo: '',
taskId,
taskName: '',
};
const [taskList, setTaskList] = 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(() => {
//
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) && data.registrationStudentTaskList.length) {
setTaskList(data.registrationStudentTaskList);
for (const [i, item] of data.registrationStudentTaskList.entries()) {
applyInfo['memo' + i] = item.memo;
applyInfo['taskId' + i] = item.taskId;
applyInfo['taskName' + i] = item.taskName;
applyInfo['memoAttachmentId'+i] =item.memoAttachmentId;
}
}
setFieldsValue(applyInfo);
setUserApplyInfo(response.data);
} else {
setTaskList([initTask]);
}
})
}, [current_user])
//
function verify(dataIndex) {
validateFields([dataIndex], (error, values) => {
if (error && error[dataIndex]) {
return;
}
})
}
//
function handleSubmit(e) {
e.preventDefault();
validateFieldsAndScroll((err, values) => {
if (!err) {
// Modal.confirm({
// title: "",
// content: "",
// onOk: () => {
const params = {
grade: values.grade,
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:data.profession,
studentName: values.studentName,
userId: current_user.user_id,
registrationStudentTaskList: taskList
}
// applyGlcc(params).then(response => {
// if (response && response.message === "success") {
// showNotification("");
// setReload(Math.random());
// }
// })
// }
// })
console.log(params);
}
});
};
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 isSmall = file.size / 1024 / 1024 < 2;
// if (!isSmall) {
// showNotification(`${2}MB!`);
// }
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) {
if (info.file.status === 'uploading' || info.file.status === "done" || info.file.status === 'removed') {
setLoading(true);
console.log(info.fileList);
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.id;
window.open(`${current_main_site_url}/api/attachments/${fileId}`);
}
function addTask() {
let taskListNew = [...taskList];
taskListNew.push(initTask);
setTaskList(taskListNew);
}
function deleteTask(i) {
let taskListNew = [...taskList];
taskListNew.splice(i, 1);
setTaskList(taskListNew);
}
function changeTaskItem(field, val, i) {
let taskListNew = [...taskList];
taskListNew[i][field] = val;
setTaskList(taskListNew);
}
return (
<div className="glcc_student_apply">
<img className="glcc-banner" src={banner} alt=''></img>
<div className='apply'>
<Breadcrumb className='glcc_breadcrumb font-16'>
<Breadcrumb.Item><a href="/glcc">开源夏令营</a></Breadcrumb.Item>
<Breadcrumb.Item><a href="/glcc">查看项目</a></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={`${main_site_url}/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>
{
taskList.map((item, i) => {
return (
<Fragment>
<h4 className="item-tit">课题信息{i + 1}/2) {taskList.length > 1 && <i className="iconfont icon-shanchu" onClick={() => { deleteTask(i) }}></i>}</h4>
{helper('课题名称',
'',
'taskName' + i,
[{ required: true, message: "请正确输入课题名称" }],
<Input placeholder="请输入课题名称" onBlur={(e) => { verify("taskName" + i); changeTaskItem("taskName", e.currentTarget.value, i) }} className={editable ? "" : "disabledInput"} disabled={editable ? false : true} />
)}
<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
accept=".zip,.rar"
action={getUploadActionUrl()}
fileList={files}
onChange={bookChange}
onDownload={download}
showUploadList={{
showDownloadIcon: true,
downloadIcon: <i className="iconfont icon-xiazai-icon"></i>,
showRemoveIcon: true
}}
>
<div className="glcc_btn">上传自荐书</div>
</Upload>
)}</div>
</Fragment>
)
})
}
{
taskList.length < 2 && <Button className="add_task" type="primary" onClick={addTask}>添加课题</Button>
}
{!userApplyInfo && <Form.Item className='subInfo introArea'>
<Button type="primary" htmlType="submit" className='sub' >提交</Button>
</Form.Item>}
</Form>
</div>
</div>
)
}
export default Form.create()(Apply);

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

@ -0,0 +1,277 @@
.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;
}
}
.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:75px;
}
.icon-shanchu{
float: right;
color: #466aff;
cursor: pointer;
:hover{
color: #1140ff;
}
}
}
.glcc-banner {
width: 100%;
}