新增导师审核页面

This commit is contained in:
何童崇 2022-06-07 10:35:09 +08:00
parent bb1b8e6b36
commit 02e189741c
8 changed files with 755 additions and 49 deletions

View File

@ -96,4 +96,18 @@ export function getTaskById(id) {
url: `/api/applyInformation/task/${id}`,
method: 'get'
});
}
// 学生报名列表查询
export async function getStudentList(params) {
let res = await fetch({
url: '/api/studentApply/list',
method: 'get',
params,
});
if (res.message === 'success') {
return res.data;
} else {
showNotification(res.message || '请求错误');
}
}

401
src/glcc/check/index.jsx Normal file
View File

@ -0,0 +1,401 @@
import React, { Fragment, useEffect, useState } from 'react';
import { Checkbox, Input, message, Modal, Table, Tooltip, Breadcrumb, Tabs } from 'antd';
import { Link } from 'react-router-dom';
import moment from 'moment';
import checkTabs from '../img/check_tabs.png';
import './index.scss';
import { cancelTaskApply, getStudentList } from '../api';
// import ProjectDetail from '../component/projectDetail';
const { TabPane } = Tabs;
const defaultTask = [{
"id": 389,
"regId": 49,
"taskName": "日程表",
"taskDesc": "根据日程提示天气信息",
"taskDifficulty": 1,
"taskUrl": "https://testforgeplus.trustie.net/postman/calendar",
"taskReward": "9000",
"tutorName": "Floraachy",
"tutorMail": "1622042529@qq.com",
"tutorPhone": "13429151223",
"projectName": "天气助手-测试项目",
"projectType": "测试",
"createdOn": "2022-06-02 10:38:27",
"sortNo": 0
},
{
"id": 386,
"regId": 47,
"taskName": "添加新的神经形态数据集ES-UCF101、HARDVS与N-Car",
"taskDesc": "在SJ中存在大量神经元数据集用于原生支持SNN。神经形态数据集可以参考https://spikingjelly.readthedocs.io/zh_CN/latest/spikingjelly.datasets.htmlES-UCF101数据集可以参考以下论文https://arxiv.org/pdf/1212.0402.pdfHARDVS数据集可以参考如下repo与论文https://github.com/Computational-Imaging-Lab-IITM/HAR-DVShttps://arxiv.org/pdf/1803.04667.pdf技能要求Python预期完成效果在SpikingJelly中可正常调用这一模块",
"taskDifficulty": 1,
"taskUrl": "https://www.gitlink.org.cn/ridger/spikingjelly/issues/60663",
"taskReward": "6000",
"tutorName": "朱芮捷",
"tutorMail": "chenyh@csxjy.com.cn",
"tutorPhone": null,
"projectName": "SpikingJelly惊蛰脉冲神经网络框架",
"projectType": "人工智能",
"createdOn": "2022-05-27 09:23:59",
"sortNo": 0
},
{
"id": 379,
"regId": 46,
"taskName": "Verilog netlist网表解析和扫描链生成",
"taskDesc": "1、题目描述扫描设计是数字电路可测试性设计的基础和通用技术将逻辑电路中的触发器或锁存器转换为扫描单元Scan Cell并将所有扫描单元串接成若干移位寄存器称之为扫描链Scan Chain扫描链的输入端是扫描输入管脚其输出端是扫描输出管脚从而将同步时序电路转换成内部状态可控制和可观测的时序电路进行测试。该赛题要求在同步时序电路的网表上实现扫描链的自动插入。2、编码任务参考openDACS/ICTest开源的Fault Simulator的Verilog netlist网表解析器优化网表解析速度、识别触发器单元、完成扫描触发器的替换、根据扫描链的配置输入在网表中自动插入扫描链并生成扫描结构描述文件、以及可仿真扫描链功能的Testbench。3、技能要求和编程语言熟悉Verilog硬件描述语言具备数字电路课程基础C++编程能力强4、预期完成结果预期在出题方提供的不同规模的网表电路上完成扫描链的自动插入并自动生成扫描结构描述文件、插入扫描链后的网表电路、以及可仿真扫描链功能的Testbench使用openDACS/ICTest开源的Fault Simulator可正常完成扫描链功能的仿真。根据程序功能的完整性、文档和代码的规范性、程序的性能网表解析和扫描链插入的速度确定优胜者。",
"taskDifficulty": 1,
"taskUrl": "https://www.gitlink.org.cn/opendacs/ictest/issues/60879",
"taskReward": "6000",
"tutorName": "叶靖",
"tutorMail": "chenyh@csxjy.com.cn",
"tutorPhone": null,
"projectName": "openDACS开源电路与系统设计自动化",
"projectType": "开发工具",
"createdOn": "2022-05-27 09:23:58",
"sortNo": 0
}];
//
function Check({ applyTaskId, setStudentInfoReset, current_user, showLoginDialog, isStudentApplyDate, studentApplyEnd, cancelCount, showNotification }) {
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 [loading, setLoading] = useState(false);
const [expandedRowKeys, setExpandedRowKeys] = useState([]);
const [taskList, setTaskList] = useState(defaultTask);
const [taskId, setTaskId] = useState(defaultTask[0].id);
const columns = [
{
title: '学生姓名',
className: "taskTableColumns",
dataIndex: 'studentName',
key: 'studentName',
width: '9%',
ellipsis: true,
render: (text, record) => {
return (
<Tooltip title={text}>
<span>{text}</span>
</Tooltip>
);
},
},
{
title: '报名时间',
key: 'createdOn',
dataIndex: 'createdOn',
className: "taskTableColumns",
width: '10%',
render: (text, record) => {
return (
text && moment(text).format('YYYY-MM-DD')
);
},
},
{
title: '所在高校',
key: 'school',
dataIndex: 'school',
className: "taskTableColumns",
width: '14%',
ellipsis: true,
render: (text, record) => {
return (
<Tooltip title={text}>
<span>{text}</span>
</Tooltip>
);
},
},
{
title: '联系电话',
key: 'phone',
dataIndex: 'phone',
className: "taskTableColumns",
width: '12%',
ellipsis: true,
render: (text, record) => {
return (
<Tooltip title={text}>
<span>{text}</span>
</Tooltip>
);
},
},
{
title: '邮箱地址',
key: 'mail',
dataIndex: 'mail',
className: "taskTableColumns",
width: '15%',
ellipsis: true,
render: (text, record) => {
return (
<Tooltip title={text}>
<span>{text}</span>
</Tooltip>
);
},
},
{
title: '申请自荐书',
key: 'memo',
dataIndex: 'memo',
className: 'taskTableColumns',
ellipsis: true,
width: '20%',
render: (text, record) => {
return (
<Tooltip title={text}>
<span>{text}</span>
</Tooltip>
);
},
},
{
title: '操作',
dataIndex: 'action',
align: 'center',
width: '20%',
className: "actionColumns taskTableColumns",
render: ((text, item, index) => {
return (
<div className='actionBox'>
{(isStudentApplyDate || studentApplyEnd) && (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={() => { deleteItem(item.id) }}></i></Tooltip>
</Fragment> : isStudentApplyDate && <Fragment>
<span onClick={() => { applyTask(item.id) }}><i className='iconfont icon-shenqingketiicon applyTask mr5'></i><span className='applyTask'>申请课题</span></span></Fragment>)}
</div>
)
})
},
]
function deleteItem(id) {
if (cancelCount == 1) {
showNotification("您的取消报名次数已用光,请联系导师处理相关报名审核信息");
} else {
setDeleteTaskId(id);
setVisible(true);
}
}
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 <div className="student-expand">
<div className="info-line">
{(record.grade || record.profession) && <div className="info-item">
<span className="info-tit">所学专业</span>
<span className="info-content">{record.grade} | {record.profession}</span>
</div>}
{record.location && <div className="info-item">
<span className="info-tit">所在地区</span>
<span className="info-content">{record.location}</span>
</div>}
</div>
{record.memoAttachment && <div className="info-line">
<div className="info-item">
<span className="info-tit">自荐书附件</span>
<a
className="link"
onClick={() => {
window.open(
`${window.location.href.indexOf('localhost') > -1
? 'https://testglcc.trustie.net'
: ''
}/busiAttachments/download/${record.memoAttachment.id}`,
);
}}
>
{record.memoAttachment.fileName}
</a>
</div>
</div>}
{record.proveAttachmentId&&<div className="info-line">
<div className="info-item">
<span className="info-tit">学生证明</span>
<img
width="200"
src={`${window.location.href.indexOf('test') > -1 ||
window.location.href.indexOf('localhost') > -1
? 'https://testforgeplus.trustie.net'
: 'https://www.gitlink.org.cn'
}/api/attachments/${record.proveAttachmentId}`}
></img>
</div>
</div>}
</div>
}
//
function onExpand(expanded, record) {
const keys = new Set(expandedRowKeys);
if (expanded) {
keys.add(record.id);
} else {
keys.delete(record.id);
}
setExpandedRowKeys(Array.from(keys));
}
//
function applyTask(id) {
//
if (current_user && current_user.login) {
//
if (applyTaskId && Object.keys(applyTaskId).length >= 2) {
message.error('最多只能同时报名两个课题');
} else {
//
window.location.href = `/glcc/student/apply/${id}`;
}
} else {
showLoginDialog();
}
}
//
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) {
window.scrollTo(0, 0);
setCurrent(1);
setPageSize(pageSize);
}
//
function changePage(page, pageSize) {
window.scrollTo(0, 0);
setCurrent(page);
}
//
function toFirst(data, index) {
if (index != 0) {
data.unshift(data.splice(index, 1)[0]);
}
}
useEffect(() => {
setExpandedRowKeys([]);
setLoading(true);
const params = {
curPage: 1,
pageSize: 10,
keyword: '',
// taskId,
// userId: current_user.user_id
}
getStudentList(params).then(res => {
console.log(res.rows);
if (res && Array.isArray(res.rows)) {
setData(res.rows);
setTotal(res.total);
}
setLoading(false);
})
}, [])
return (
<div className="glcc-container glcc-check">
<div className="glcc-main">
<Breadcrumb className='glcc_breadcrumb font-16'>
<Breadcrumb.Item><Link to="/glcc">开源夏令营</Link></Breadcrumb.Item>
<Breadcrumb.Item><Link to="/glcc/subjects">课题及项目列表</Link></Breadcrumb.Item>
<Breadcrumb.Item style={{ color: '#202D40' }}>学生报名</Breadcrumb.Item>
</Breadcrumb>
<div className="head_introduce">
<h4 className="head_tit">申请说明</h4>
<div className="head_content">1欢迎进入导师审核页各位导师可查看到您发布课题的全部学生报名信息</div>
<div className="head_content">2您可根据学生报名信息与学生进行邮箱或电话沟通了解学生详细情况选择满意的学生</div>
<div className="head_content">3每个课题仅允许审核通过一个学生在审核过程中您可以随时调整各学生的审核状态</div>
<div className="head_content">4请各位导师在7.1日前完成课题申请的审核7.1日将根据各导师审核信息公布各课题学生入选名单</div>
</div>
<Tabs className="task-tabs" onChange={(e) => setTaskId(e)} activeKey={taskId + ''}>
{
taskList.map((item, i) => {
return <TabPane tab={`课题${i + 1}`} key={item.id} >
{item.taskName}
</TabPane>
})
}
</Tabs>
<div className="taskList listBox">
<div className='line'>
</div>
<Table
loading={loading}
columns={columns}
dataSource={data}
expandedRowRender={expandRow}
expandIconColumnIndex={6}
expandIconAsCell={false}
expandIcon={customExpandIcon}
rowKey={'id'}
expandedRowKeys={expandedRowKeys}
onExpand={onExpand}
pagination={{ current: current, pageSize: pageSize, total: total, showSizeChanger: true, onShowSizeChange: onShowSizeChange, showQuickJumper: true, onChange: changePage }}
/>
<Modal
okText="确认"
cancelText="再想想"
okType='default'
title="取消申请"
visible={visible}
onCancel={() => { setVisible(false) }}
onOk={cancelApply}
wrapClassName='cancelApplyTask'
>
<div className='tilTask mt20'><span className='carefulIcon'>!</span>确定取消申请此课题</div>
<p className='tipTask'>取消申请后将删除此条申请记录你仅有<span className="tipTaskTime"> {2 - cancelCount} </span>次取消申请的机会</p>
</Modal>
</div>
</div>
</div>
)
}
export default Check;

215
src/glcc/check/index.scss Normal file
View File

@ -0,0 +1,215 @@
.glcc-check {
.task-tabs {
border: 1px solid #fff;
border-bottom: 0;
margin-top: 30px;
.ant-tabs-nav-container {
background-color: #3758de;
}
}
.ant-tabs-nav .ant-tabs-tab {
padding: 14px 0px;
color: #fff;
margin-right: 64px;
}
.ant-tabs-nav-scroll {
margin-left: 64px;
}
.ant-tabs-nav .ant-tabs-tab-active {
color: #fff;
}
.ant-tabs-bar {
border: 0;
margin: 0;
}
.ant-tabs-ink-bar {
background: #fff;
}
.ant-tabs-tab-prev,
.ant-tabs-tab-next {
width: 163px;
background: url("../img/check_tabs.png") no-repeat;
background-size: 100% 100%;
opacity: 1;
& > span {
display: none;
}
}
.ant-tabs-tab-next {
transform: rotate(180deg);
right: 0;
}
.ant-tabs-tabpane {
padding:0 25px;
}
.ant-tabs-content {
padding:25px 0;
}
.taskList {
padding:0px 25px 50px 25px;
border-left: 1px solid white;
border-right: 1px solid white;
border-bottom: 1px solid white;
.line{
margin: 0 auto 25px;
height: 1px;
border-top: 1px dashed #bec5d5;
}
.ant-pagination-item-active,
.ant-pagination-item:hover,
.ant-pagination-next:not(.ant-pagination-disabled)
.ant-pagination-item-link:hover,
.ant-select-selection:hover,
.ant-pagination-options-quick-jumper:hover input {
border-color: #466aff;
a {
color: #466aff;
}
}
.ant-pagination-disabled .ant-pagination-item-link:hover .anticon {
color: rgba(0, 0, 0, 0.25);
}
}
.taskTableColumns span div span {
font-size: 16px;
font-weight: 700;
color: #273778;
}
.taskTableColumns span {
font-size: 15px;
color: #353f5e;
}
.ant-table-tbody .taskTableColumns.taskName span {
color: #2545c9;
cursor: pointer;
}
.ant-table-tbody > tr > .taskTableColumns {
background-color: #f1f6ff;
border-bottom: 1px dashed #bec5d5;
}
.ant-table-thead > tr > .taskTableColumns {
background: #e6ecff;
}
.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: 10px 0 30px 86px !important;
}
.tipTaskTime {
font-size: 36px;
color: #df0002;
}
.ant-modal-footer {
border-top: none;
text-align: center;
padding-bottom: 50px;
.ant-btn {
&.ant-btn-default {
color: #df0002;
}
&:hover {
border-color: #466aff;
color: #466aff;
&.ant-btn-default {
border-color: #df0002;
color: #df0002;
}
}
}
.ant-btn-default {
margin-left: 43px;
}
}
}
.ant-table-expanded-row td {
padding: 0;
}
.student-expand {
padding:23px;
opacity: 80%;
background-color: #e9efff;
border: 1px solid #ffffff;
.info-line{
line-height: 44px;
display: flex;
}
.info-tit{
display: inline-block;
width: 6em;
margin-right: 18px;
text-align: right;
}
}
}

View File

@ -37,6 +37,10 @@ export default (props) => {
}
}
function goToCheck(){
history.push("/glcc/check");
}
return (
<div className="glcc">
{/* <Banner /> */}
@ -66,6 +70,14 @@ export default (props) => {
</div>
<div className="pt6">选择感兴趣的课题开启您的开源之旅</div>
</div>
{/* 导师审核 */}
<div className="apply" onClick={goToCheck}>
<div>
<img src={apply2} alt="" className="applyIcon"/>
<span className="til">导师审核</span>
</div>
<div className="pt6">以赛代筛挖掘高潜力人才</div>
</div>
</div>
{/* </div> */}
<div className="introduce">

View File

@ -41,6 +41,10 @@
flex-direction: column;
justify-content: center;
width: 355px;
&:not(:first-child){
margin-left: 35px;
}
.til{
margin-left: 10px;
font-family:PingFang SC;
@ -71,9 +75,7 @@
}
}
}
.apply:last-child{
margin-left: 35px;
}
.applyIcon{
width: 30px;
}

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

View File

@ -31,11 +31,16 @@ const Help = Loadable({
loader: () => import("./help"),
loading: Loading,
});
//
//
const Student = Loadable({
loader: () => import("./student"),
loading: Loading,
});
//
const Check = Loadable({
loader: () => import("./check"),
loading: Loading,
});
//
const Project = Loadable({
@ -96,6 +101,13 @@ const Glcc = (propsF) => {
<Apply {...propsF} {...props} isGlccApplyDate={isGlccApplyDate}/>
)}
></Route>
{/* 教师审核 */}
<Route
path="/glcc/check"
render={(props) => (
<Check {...propsF} {...props} isGlccApplyDate={isGlccApplyDate}/>
)}
></Route>
{/* 帮助中心 */}
<Route
path="/glcc/help"

View File

@ -1,49 +1,99 @@
.-task-sidebar .glccHelp{
height: auto;
width: 48px;
padding: 6px 16px;
text-align: center;
background-color:#f6f9fe;
border:1px solid #ffffff;
border-radius:2px;
box-shadow:0px 0px 8px rgba(55, 148, 255, 0.16);
color:#1e1e1e;
.glcc-container {
background-image: linear-gradient(
180deg,
#ebf2ff 0%,
#ebf2ff 43.09%,
#f3f4f8 100%
);
padding-bottom: 120px;
.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: 35px;
word-break: break-word;
cursor: pointer;
.icon-bangzhuzhongxinicon, .icon-bangzhuzhongxinicon1{
color: #0654D6;
margin-left: -3px;}
&:hover{
color:#ffffff;
background-color:#466aff;
.icon-bangzhuzhongxinicon, .icon-bangzhuzhongxinicon1{color:#ffffff}
}
line-height: 38px;
}
.head_bold {
font-weight: 700;
color: #333;
}
}
.qqChatBox{
position: fixed;
.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;
.glcc-main {
width: 1200px;
margin: 0 auto;
}
.-task-sidebar .glccHelp {
height: auto;
width: 48px;
padding: 6px 16px;
text-align: center;
background-color: #f6f9fe;
border: 1px solid #ffffff;
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-bangzhuzhongxinicon1 {
color: #0654d6;
margin-left: -3px;
}
&:hover {
color: #ffffff;
background-color: #466aff;
.icon-bangzhuzhongxinicon,
.icon-bangzhuzhongxinicon1 {
color: #ffffff;
}
}
}
.qqChatBox {
position: fixed;
.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;
.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;}
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;
}
}
}
.qqTip {
color: #5769a5;
font-size: 14px;
line-height: 24px;
}
}