diff --git a/public/css/iconfont.css b/public/css/iconfont.css index 92de082a..2aa4e5fe 100644 --- a/public/css/iconfont.css +++ b/public/css/iconfont.css @@ -1,8 +1,8 @@ @font-face { font-family: "iconfont"; /* Project id 2340181 */ - src: url('iconfont.woff2?t=1651041108151') format('woff2'), - url('iconfont.woff?t=1651041108151') format('woff'), - url('iconfont.ttf?t=1651041108151') 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,62 @@ -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"; +} + +.icon-fuwuicon:before { + content: "\e929"; +} + .icon-personal-center:before { content: "\e927"; } diff --git a/public/css/iconfont.js b/public/css/iconfont.js index b910937d..81842232 100644 --- a/public/css/iconfont.js +++ b/public/css/iconfont.js @@ -1 +1 @@ -!function(a){var l,c,h,i,o,z='',t=(t=document.getElementsByTagName("script"))[t.length-1].getAttribute("data-injectcss"),p=function(a,l){l.parentNode.insertBefore(a,l)};if(t&&!a.__iconfont__svg__cssinject__){a.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(a){console&&console.log(a)}}function v(){o||(o=!0,h())}function m(){try{i.documentElement.doScroll("left")}catch(a){return void setTimeout(m,50)}v()}l=function(){var a,l=document.createElement("div");l.innerHTML=z,z=null,(l=l.getElementsByTagName("svg")[0])&&(l.setAttribute("aria-hidden","true"),l.style.position="absolute",l.style.width=0,l.style.height=0,l.style.overflow="hidden",l=l,(a=document.body).firstChild?p(l,a.firstChild):a.appendChild(l))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(l,0):(c=function(){document.removeEventListener("DOMContentLoaded",c,!1),l()},document.addEventListener("DOMContentLoaded",c,!1)):document.attachEvent&&(h=l,i=a.document,o=!1,m(),i.onreadystatechange=function(){"complete"==i.readyState&&(i.onreadystatechange=null,v())})}(window); \ No newline at end of file +!function(a){var l,c,h,i,o,z='',t=(t=document.getElementsByTagName("script"))[t.length-1].getAttribute("data-injectcss"),p=function(a,l){l.parentNode.insertBefore(a,l)};if(t&&!a.__iconfont__svg__cssinject__){a.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(a){console&&console.log(a)}}function v(){o||(o=!0,h())}function m(){try{i.documentElement.doScroll("left")}catch(a){return void setTimeout(m,50)}v()}l=function(){var a,l=document.createElement("div");l.innerHTML=z,z=null,(l=l.getElementsByTagName("svg")[0])&&(l.setAttribute("aria-hidden","true"),l.style.position="absolute",l.style.width=0,l.style.height=0,l.style.overflow="hidden",l=l,(a=document.body).firstChild?p(l,a.firstChild):a.appendChild(l))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(l,0):(c=function(){document.removeEventListener("DOMContentLoaded",c,!1),l()},document.addEventListener("DOMContentLoaded",c,!1)):document.attachEvent&&(h=l,i=a.document,o=!1,m(),i.onreadystatechange=function(){"complete"==i.readyState&&(i.onreadystatechange=null,v())})}(window); \ No newline at end of file diff --git a/public/css/iconfont.json b/public/css/iconfont.json index 3bf3eb57..8292425f 100644 --- a/public/css/iconfont.json +++ b/public/css/iconfont.json @@ -5,6 +5,104 @@ "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": "暂无数据", + "font_class": "zanwushuju", + "unicode": "e928", + "unicode_decimal": 59688 + }, + { + "icon_id": "29467272", + "name": "服务icon", + "font_class": "fuwuicon", + "unicode": "e929", + "unicode_decimal": 59689 + }, { "icon_id": "29206429", "name": "personal-center", diff --git a/public/css/iconfont.ttf b/public/css/iconfont.ttf index 76ccae2b..aaf41b74 100644 Binary files a/public/css/iconfont.ttf and b/public/css/iconfont.ttf differ diff --git a/public/css/iconfont.woff b/public/css/iconfont.woff index be0e660d..7ad90ffb 100644 Binary files a/public/css/iconfont.woff and b/public/css/iconfont.woff differ diff --git a/public/css/iconfont.woff2 b/public/css/iconfont.woff2 index 51640e89..f45e4e1d 100644 Binary files a/public/css/iconfont.woff2 and b/public/css/iconfont.woff2 differ diff --git a/public/index.html b/public/index.html index 9489fe42..bb947662 100755 --- a/public/index.html +++ b/public/index.html @@ -7,6 +7,7 @@ + diff --git a/src/App.js b/src/App.js index 3fdff34d..0cd7a9d4 100644 --- a/src/App.js +++ b/src/App.js @@ -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) { @@ -292,7 +292,7 @@ class App extends Component { this.Modifyloginvalue()}> - {pathName && pathName.indexOf("glcc") === -1 ? : } + {!pathName || (pathName && pathName.indexOf("glcc") === -1) ? : } {/* */} {/* wiki预览 */} diff --git a/src/forge/Component/NoticeModal/SystemNotice.jsx b/src/forge/Component/NoticeModal/SystemNotice.jsx index c95a8030..78619f18 100644 --- a/src/forge/Component/NoticeModal/SystemNotice.jsx +++ b/src/forge/Component/NoticeModal/SystemNotice.jsx @@ -11,7 +11,7 @@ function SystemNotice({showNotice,system_notification,history,login,hideSystemNo useEffect(()=>{ - if(system_notification && !system_notification.is_read && showNotice && login){ + if((system_notification && !system_notification.is_read) && showNotice && login){ setVisible(true); } },[system_notification,login]) @@ -22,11 +22,12 @@ function SystemNotice({showNotice,system_notification,history,login,hideSystemNo axios.post(url,{ system_notification_id:system_notification.id }).then(result=>{ - if(result){ - setVisible(false); - hideSystemNotice(); - } - }).catch(error=>{}) + setVisible(false); + hideSystemNotice(); + }).catch(error=>{ + setVisible(false); + hideSystemNotice(); + }) }else{ setVisible(false); hideSystemNotice(); diff --git a/src/forge/Main/CoderDepotReadme.jsx b/src/forge/Main/CoderDepotReadme.jsx index bb9bdd5b..586f57fb 100644 --- a/src/forge/Main/CoderDepotReadme.jsx +++ b/src/forge/Main/CoderDepotReadme.jsx @@ -11,8 +11,8 @@ function CoderDepotReadme({ operate , history , readme , ChangeFile }){ const [ content ,setContent ] = useState(undefined); useEffect(()=>{ - if(readme && readme.content){ - setContent(readme.content); + if(readme && readme.replace_content){ + setContent(readme.replace_content); }else{ setContent(undefined); } diff --git a/src/forge/Main/CoderRootFileDetail.js b/src/forge/Main/CoderRootFileDetail.js index b73a2168..6213f448 100644 --- a/src/forge/Main/CoderRootFileDetail.js +++ b/src/forge/Main/CoderRootFileDetail.js @@ -21,7 +21,7 @@ class CoderRootFileDetail extends Component { value: undefined, language: undefined, languages: undefined, - description: props.detail.content, + description: props.detail.replace_content, menuList:undefined }; } @@ -36,12 +36,12 @@ class CoderRootFileDetail extends Component { }; componentDidUpdate=(prevProps)=>{ - const { content } = this.props && this.props.detail; - const prevcontent = prevProps.detail && prevProps.detail.content; - if (content && prevcontent) { - if (prevcontent !== content){ + const { replace_content } = this.props && this.props.detail; + const prevcontent = prevProps.detail && prevProps.detail.replace_content; + if (replace_content && prevcontent) { + if (prevcontent !== replace_content){ this.setState({ - description: content + description: replace_content }); } } @@ -319,7 +319,7 @@ class CoderRootFileDetail extends Component { {...this.state} language={language ? language : "javascript"} filepath={`/${detail.path}`} - content={description} + content={detail.content} readOnly={readOnly} editorType="update" currentBranch={currentBranch} diff --git a/src/forge/Main/Detail.js b/src/forge/Main/Detail.js index ceebddc8..60b2fc3b 100644 --- a/src/forge/Main/Detail.js +++ b/src/forge/Main/Detail.js @@ -129,6 +129,10 @@ const Source = Loadable({ loader: () => import('../Source/Index'), loading: Loading, }) +const Server = Loadable({ + loader: () => import('../Server/Index'), + loading: Loading, +}) const DevIndex = Loadable({ loader: () => import('../DevOps/Index'), loading: Loading, @@ -168,6 +172,8 @@ function checkPathname(projectsId, owner, pathname) { name = "source" } else if (url.indexOf(`/wiki`) > -1) { name = "wiki" + } else if (url.indexOf(`/server`) > -1) { + name = "server" } } return name; @@ -651,6 +657,12 @@ class Detail extends Component { : + {/* 服务 */} + () + } + > {/* 资源 */} a{ position: relative; font-size: 14px; height: 36px; line-height: 24px; - display: block; + display: flex; color: #000!important; &> span.num{ line-height: 24px; diff --git a/src/forge/Main/sub/DetailBanner.jsx b/src/forge/Main/sub/DetailBanner.jsx index f03f14ba..8a0472ce 100644 --- a/src/forge/Main/sub/DetailBanner.jsx +++ b/src/forge/Main/sub/DetailBanner.jsx @@ -8,11 +8,13 @@ function DetailBanner({ history,list , owner , projectsId , isManager , url , pa useEffect(()=>{ if(list){ // 没有资源库banner但是通过连接进资源库页面时 - if(pathname && pathname==="source"){ - let a = list.filter(item=>item.menu_name === "resources"); - if(a && a.length === 0){ - history.push(`/${owner}/${projectsId}`); - } + let a = list.filter(item=>item.menu_name === "resources"); + if((pathname && pathname==="source") && (a && a.length === 0)){ + history.push(`/${owner}/${projectsId}`); + } + let b = list.filter(item=>item.menu_name === "server"); + if((pathname && pathname.indexOf("server") > 0) && (b && b.length === 0)){ + history.push(`/${owner}/${projectsId}`); } setMenuName(list); } @@ -106,6 +108,15 @@ function DetailBanner({ history,list , owner , projectsId , isManager , url , pa } + { + item.menu_name === "services" && +
  • + + + 服务 + +
  • + } { item.menu_name === "activity" &&
  • diff --git a/src/forge/Main/version/New.jsx b/src/forge/Main/version/New.jsx index 8cfd912d..248c010e 100644 --- a/src/forge/Main/version/New.jsx +++ b/src/forge/Main/version/New.jsx @@ -33,7 +33,7 @@ export default Form.create()( const [fileList, setFileList] = useState(undefined); const [attachment, setAttachment] = useState(undefined); const [options , setOptions] = useState(undefined); - const stable = history && history.location && history.location.state.stable; + const stable = history && history.location && history.location.state&&history.location.state.stable; const { projectsId, versionId , owner } = match.params; useEffect(()=>{ diff --git a/src/forge/Merge/Commits.jsx b/src/forge/Merge/Commits.jsx index 93e867ae..43e67181 100644 --- a/src/forge/Merge/Commits.jsx +++ b/src/forge/Merge/Commits.jsx @@ -4,8 +4,9 @@ import User from '../Component/User'; import { truncateCommitId } from '../common/util'; import { getImageUrl } from 'educoder'; import { Link } from 'react-router-dom'; +import { Pagination } from 'antd'; -function Commits({ commits , projectsId , owner }){ +function Commits({ commits , projectsId , owner , total ,limit , changeCommitFunc }){ return(
    { @@ -29,6 +30,12 @@ function Commits({ commits , projectsId , owner }){ ) }) } + { + total > limit && +
    + changeCommitFunc(page)}/> +
    + }
    ) } diff --git a/src/forge/Merge/CreateMerge.js b/src/forge/Merge/CreateMerge.js index ec8d14de..28ed7690 100644 --- a/src/forge/Merge/CreateMerge.js +++ b/src/forge/Merge/CreateMerge.js @@ -18,6 +18,8 @@ import './merge.css'; * 3、合并请求列表页(新建、无数据时的提示),仓库相同,源、目标都为默认分支,owner/projectId/compare * 4、新建页面,切换分支、切换目标仓库、刷新页面等,存在所有可能情况 */ + const limit = 15; + function getBranchParams(pathname) { const result = { // 目标仓库所有者 @@ -152,7 +154,7 @@ class CreateMerge extends Component { let getbranch =await this.getBranchList(mergeOwner,projectId,pullBranch,mergeBranch,"merge"); let checkpull =await this.getBranchList(pullOwner,projectId,pullBranch,mergeBranch,"pull"); if(getbranch && checkpull){ - this.compareProject(mergeOwner === pullOwner, branchParams); + this.compareProject(mergeOwner === pullOwner, branchParams,1); }else{ this.setState({ isSpin: false,isCompareSpin: false @@ -161,7 +163,7 @@ class CreateMerge extends Component { } // compare接口,获取分支对比信息 - compareProject = (sameProject, branchParams) => { + compareProject = (sameProject, branchParams ,page) => { const { pullOwner, pullBranch, mergeOwner, mergeBranch, projectId } = branchParams; let url = `/${mergeOwner}/${projectId}/compare`; if (sameProject) { @@ -170,7 +172,9 @@ class CreateMerge extends Component { url += `/${Base64.encode(returnbar(mergeBranch))}...${pullOwner}/${projectId}:${Base64.encode(returnbar(pullBranch))}.json`; } axios - .get(url) + .get(url,{ + params:{limit,page} + }) .then((result) => { if (result) { if (result.data.status === 0) { @@ -185,7 +189,7 @@ class CreateMerge extends Component { } this.setState({ comparesData: result.data, - isSpin: false,isCompareSpin: false + isSpin: false,isCompareSpin: false,isFirstLoading:false }); } }) @@ -354,6 +358,15 @@ class CreateMerge extends Component { }).catch(error=>{}) } + changeCommitFunc=(page)=>{ + this.setState({ + isSpin:true + }) + const branchParams = getBranchParams(this.props.location.pathname); + const { mergeOwner , pullOwner} = branchParams; + this.compareProject(mergeOwner === pullOwner, branchParams,page); + } + render() { const { data, @@ -465,6 +478,8 @@ class CreateMerge extends Component { {...this.props} merge={merge} pull={pull} + limit = {limit} + changeCommitFunc={this.changeCommitFunc} comparesData={comparesData} > )} diff --git a/src/forge/Merge/merge_footer.js b/src/forge/Merge/merge_footer.js index 868e736f..0ba3a143 100644 --- a/src/forge/Merge/merge_footer.js +++ b/src/forge/Merge/merge_footer.js @@ -22,9 +22,14 @@ class MergeFooter extends Component { }); }; + changeCommitFunc=(page)=>{ + const { changeCommitFunc } = this.props; + changeCommitFunc&& changeCommitFunc(page); + } + render() { const { projectsId, owner } = this.props.match.params; - const { comparesData = {} } = this.props; + const { comparesData = {} ,limit } = this.props; const { commits, diff, commits_count } = comparesData; const { activeKey } = this.state; @@ -53,6 +58,9 @@ class MergeFooter extends Component { diff --git a/src/forge/Server/Index.jsx b/src/forge/Server/Index.jsx new file mode 100644 index 00000000..cdcb8bbc --- /dev/null +++ b/src/forge/Server/Index.jsx @@ -0,0 +1,34 @@ +import React from 'react'; +import { Route, Switch } from 'react-router-dom'; +import "./index.scss"; +import Loadable from 'react-loadable'; +import Loading from '../../Loading'; + + +const List = Loadable({ + loader: () => import('./List'), + loading: Loading, +}) +const Data = Loadable({ + loader: () => import('./data'), + loading: Loading, +}) +function ServerIndex(props){ + return( +
    + + () + } + > + () + } + > + +
    + ) +} +export default ServerIndex; \ No newline at end of file diff --git a/src/forge/Server/List.jsx b/src/forge/Server/List.jsx new file mode 100644 index 00000000..3e49e815 --- /dev/null +++ b/src/forge/Server/List.jsx @@ -0,0 +1,48 @@ +import React,{useState , useEffect} from 'react'; +import AgreementModal from './agreementModal'; + +function Main(props){ + const [ visible , setVisible ] = useState(false); + const { owner , projectsId } = props.match.params; + const [ has_trace_user , setHas_trace_user ] = useState(false); + + const { current_user , resetUserInfo } = props; + + useEffect(()=>{ + if(current_user){ + setHas_trace_user(current_user.has_trace_user); + } + },[current_user]) + + function onOk(){ + setVisible(false); + resetUserInfo && resetUserInfo(); + props.history.push(`/${owner}/${projectsId}/server/1`); + } + + function openDetail(){ + if(!has_trace_user){ + setVisible(true); + }else{ + props.history.push(`/${owner}/${projectsId}/server/1`); + } + } + return( +
    + setVisible(false)} onOk={onOk}/> + +
    + ) +} +export default Main; \ No newline at end of file diff --git a/src/forge/Server/agreementModal.jsx b/src/forge/Server/agreementModal.jsx new file mode 100644 index 00000000..2e7a91b3 --- /dev/null +++ b/src/forge/Server/agreementModal.jsx @@ -0,0 +1,65 @@ +import React, { useState } from 'react'; +import { Modal , Checkbox } from 'antd'; +import axios from 'axios'; + + +function AgreementModal({ visible , onCancel , onOk}){ + const [ agree , setAgree ] = useState(false); + function changeAgree(e){ + setAgree(e.target.checked); + } + // 不同意 + function unAgree(){ + setAgree(false); + onCancel(); + } + // 同意协议 + function agreeFunc(){ + const url = `/traces/trace_users.json`; + axios.post(url).then(result=>{ + if(result){ + agree && onOk(); + setAgree(false); + } + }).catch(error=>{}) + } + return( + + 不同意 + 同意协议 + + } + > +
    +
    +

    在使用本系统前,请您务必仔细阅读下列条款: 本系统的资料、信息及其他内容均由国家超级计算无锡中心、中国科学院计算技术研究所、清华大学和北京大学提供,任何人进入本系统、阅读本系统所载任何内容、从本系统下载任何资料或使用本系统提供的任何资料,即表示同意遵守这些条款。如果您不同意遵守这些条款,请勿继续使用本系统。提供方有权对这些条款不时进行更新,前述更新之后的条款将在本系统进行公布,并自公布之日起生效。

    +

    版权声明

    +

    本系统所提供任何内容,包括但不限于数据、文字、图表或图象,其所有权、著作权及其他权利均由提供方享有。前述权利受中华人民共和国的法律、法规、规章、规范性法律文件及相关国际条约的保护;对前述权利的任何侵犯行为均有可能导致民事、行政或刑事责任,一切后果均由侵权行为人承担。未经提供方事先书面许可,您不得以任何方式复制、修改、传播、出版、转载或展示本系统的任何内容。

    +

    本系统采用但非本系统原创的所有内容,其版权归版权所有人所有;转载的部分内容源自其他系统,因无法和版权权利人联系,如果您是前述内容的版权权利人,请与我们联系并提供证明材料和详实说明,我们将及时加注版权信息;如果您提出异议,我们将立即撤除任何涉及版权问题的内容。对于独家授权本系统提供的任何内容,如您需要转载,应当事先得到本系统和版权所有人的同意。

    +

    引用本系统内容

    +

    1. 在遵守国家法律以及本协议的情况下,您可以出于非商业目的浏览、下载本系统的内容。如出于商业目的使用(如:拷贝、下载、存储、通过硬盘拷贝或电子抓取系统发送、转换、演示、传播、出版本系统的任何内容,或创造与前述内容有关的演绎作品或衍生产品),则必须事先经过提供方的书面许可,并在使用时注明来源和版权标记。

    +

    2. 如果您需要使用本系统包含的由任何其他主体提供的内容,请直接与版权权利人联系。

    +

    免责条款

    +

    对本系统的内容,我们已尽最大努力审核,但对于内容的正确性、完整性、及时性、有效性、稳定性、可用性、不侵犯他人权利等方面,不提供任何形式(无论明示或默示)的保证。我们不保证服务器的稳定性,任何由于黑客入侵或攻击、计算机病毒侵入或发作、因政府管制而造成的暂时性关闭等影响网络正常经营的不可抗力而造成的资料泄露、丢失、被盗用或被篡改等,本系统均得免责。我们不保证您在任何时候均可浏览、阅读、使用本系统;不保证本系统的内容不存在打印、复制及其他输入方面的错误。提供方有权随时更改本系统任何内容。 在任何情况下,对于无法进入本系统或无法使用本系统内容而导致的任何直接的、间接的、附带的、给第三人造成的损失(包括但不限于,利润损失、信息数据丢失、财产毁坏损失),提供方均不承担任何责任。 本系统提供的站外链接仅为用户提供方便,但链接的系统不属于本系统的控制范围或管理范畴,故提供方对链接系统所传送或登载的任何形式的内容不承担任何责任。 任何用户在本系统发表的商业信息、个人信息、留言以及其他信息,均不代表本系统以及提供方的立场,且与本系统与提供方无关,相关责任由作者完全承担;本系统有权对上述商业信息、个人信息、留言以及其他信息随时进行删除。

    +

    本系统支持用户在使用本系统系统过程中的合法经营行为,但因用户的作为或不作为所造成的后果概由用户自行承担。

    +

    隐私保护声明

    +

    本系统承诺按照相关法律的规定、本系统的隐私政策,保护本系统收集的用户个人信息。我们建议您认真阅读本隐私保护声明。

    +

    适用法律与争议解决

    +

    因本公告或使用本系统所发生的争议适用中华人民共和国法律。因本公告或使用本系统发生争议,应当协商解决,协商不成的,由本公司所在地人民法院受理解决。

    +

    终止协议或退出服务

    +

    如果您希望不再使用本系统提供的服务,或者您不同意上述条款及更新内容,您可以选择终止协议或者退出服务具体请联系客服人员。

    +
    + 我已阅读并同意《用户协议及声明条款》 +
    +
    + ) +} +export default AgreementModal; \ No newline at end of file diff --git a/src/forge/Server/data.jsx b/src/forge/Server/data.jsx new file mode 100644 index 00000000..5bf540cd --- /dev/null +++ b/src/forge/Server/data.jsx @@ -0,0 +1,184 @@ +import React, { useEffect, useState } from 'react'; +import DataEmpty from './dataEmpty'; +import DetectionModal from './detectionModal'; +import { Table , Spin, message } from 'antd'; +import axios from 'axios'; + + +function Data(props){ + const [ detectionVisible , setDetectionVisible ] = useState(false); + const [ dataSource , setDataSource ] = useState(undefined); + const [ page , setPage ] = useState(1); + const [ spining , setSpining ] = useState(true); + const [ relayCount , setRelayCount ] = useState(5); + const [ repeatId , setRepeatId ] = useState(undefined); + const [ repeatBranch , setRepeatBranch ] = useState(undefined); + + const { owner , projectsId } = props.match.params; + const { current_user , isManager } = props; + const limit = 15; + + + function onDetectionOk(){ + props.showNotification("扫描成功!"); + setDetectionVisible(false); + setSpining(true); + Init(); + } + + function Init(){ + const url = `/traces/${owner}/${projectsId}/task_results.json`; + axios.get(url,{ + params:{ + page,limit + } + }).then(result=>{ + if(result){ + setDataSource(result.data.data); + setRelayCount(result.data.left_tasks_count); + setSpining(false); + } + }).catch(error=>{}) + } + + useEffect(()=>{ + setSpining(true); + Init(); + },[]) + + + // 重新扫描 + function repeatCheck(project_id,branch){ + if(relayCount <= 0){ + message.error("无可用检测次数"); + return; + } + setRepeatId(project_id); + setRepeatBranch(branch); + setDetectionVisible(true); + } + + function createCheck(){ + if(relayCount <= 0){ + message.error("无可用检测次数"); + return; + } + setRepeatBranch(undefined); + setRepeatId(undefined); + setDetectionVisible(true); + } + + function handleDownExcel(task_id){ + setSpining(true); + const url = `/api/traces/${owner}/${projectsId}/task_pdf.json?task_id=${task_id}`; + // window.open(`/api/traces/${owner}/${projectsId}/task_pdf.json?task_id=${task_id}`); + const x = new XMLHttpRequest(); + x.open('GET', url, true) + x.responseType = 'blob'; + x.onload = (e) => { + // 会创建一个 DOMString,其中包含一个表示参数中给出的对象的URL。这个 URL 的生命周期和创建它的窗口中的 document 绑定。这个新的URL 对象表示指定的 File 对象或 Blob 对象。 + const url = window.URL.createObjectURL(x.response) + const a = document.createElement('a') + a.href = url; + a.download = "report.pdf"; + a.click(); + setSpining(false); + } + x.send(); + console.log("spining"); + } + + return( +
    + setDetectionVisible(false)} + onOk={onDetectionOk} + owner={owner} + projectsId={projectsId} + relayCount={relayCount} + repeatId={repeatId} + repeatBranch={repeatBranch} + /> +
    + 重晴鸟代码溯源系统 + { isManager && 新建分析 } +
    + +
    + { + dataSource && dataSource.length >0 && +
    +
      +
    • + 序号 + 分支名称 + 检测状态 + 检测时间 + { isManager && 操作 } +
    • + { + dataSource.map((e,key)=>{ + return( +
      +
    • + {key + 1 } + {e.branch_tag} + + { + e.detect_status === "fail" ? + 失败 + : e.detect_status==="detecting" ? +
      + + {e.detect_process}% +
      + : + 成功 + } +
      + {e.detect_startdate} + { + isManager && + +
      + { + e.detect_status ==="detecting" ? + 重新扫描 + : + repeatCheck(e.project_id,e.branch_tag)}>重新扫描 + } + {/* { + (e.detect_status ==="fail" || e.detect_status ==="detecting") ? + 查看 + : + 查看 + } */} + { + (e.detect_status ==="fail" || e.detect_status ==="detecting") ? + 下载报告 + : + handleDownExcel(e.task_id)}>下载报告 + } +
      +
      + } +
    • + {false && } +
      + ) + }) + } +
    +
    + } + { + (dataSource === null || (dataSource && dataSource.length === 0)) && + + } +
    +
    +
    + ) +} +export default Data; \ No newline at end of file diff --git a/src/forge/Server/dataEmpty.jsx b/src/forge/Server/dataEmpty.jsx new file mode 100644 index 00000000..b6ecf4f6 --- /dev/null +++ b/src/forge/Server/dataEmpty.jsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { Divider} from 'antd'; + + +function DataEmpty(props){ + return( +
    +
    + + 暂无数据 +

    重睛鸟代码溯源及安全审查系统是一款完全自主、面向主流语言的代码审查大数据平台。主要功能包含软件源代码的溯源分析、自主度评估、开源漏洞检测、开源许可证合规性分析,支持分析结果多层次可视化展示等,可用于提高软件代码的可控性与安全性。

    + +

    对每个仓库,可进行代码检测总次数仅为 5

    +
    +
    + ) +} +export default DataEmpty; \ No newline at end of file diff --git a/src/forge/Server/detectionModal.jsx b/src/forge/Server/detectionModal.jsx new file mode 100644 index 00000000..5e9acef2 --- /dev/null +++ b/src/forge/Server/detectionModal.jsx @@ -0,0 +1,162 @@ +import React, { useState , forwardRef, useEffect } from 'react'; +import { Modal , Form , Select } from 'antd'; +import axios from 'axios'; + +function DetectionModal({form , visible , onCancel , onOk , projectsId, owner , relayCount , repeatId , repeatBranch }){ + const { getFieldDecorator, validateFields , setFieldsValue } = form; + const [ check , setCheck ] = useState(false); + const [ branch , setBranch ] = useState(""); + const [ branchList , setBranchList ] = useState([]); + const source = axios.CancelToken.source(); + const layout = { + labelCol: { span: 5 }, + wrapperCol: { span: 18 }, + }; + + useEffect(()=>{ + if(visible && owner && projectsId){ + const url = `/${owner}/${projectsId}/branches.json`; + axios.get(url).then(result=>{ + if(result){ + setBranchList(result.data); + } + }).catch(error=>{}) + } + },[owner,projectsId,visible]) + + // 取消检测 + function onCancelFunc(){ + source.cancel(); + if(check) { + setCheck(false); + } else{ + onCancel(); + } + } + // 开始检测 + function onOkFunc(){ + validateFields((error,values)=>{ + if(!error){ + setCheck(true); + setBranch(values.branch); + if(repeatId){ + // 重新扫描 + const url = `/traces/${owner}/${projectsId}/reload_task.json`; + axios.get(url,{ + params:{ + project_id:repeatId, + branch_name:repeatBranch + } + },{ + CancelToken:source.token + }).then(result=>{ + if(result){ + onOk(); + } + setCheck(false); + }).catch(error=>{}) + }else{ + // 新建分析 + const url = `/traces/${owner}/${projectsId}/tasks.json`; + axios.post(url,{ + branch_name:values.branch + },{ + CancelToken:source.token + }).then(result=>{ + if(result){ + onOk(); + } + setCheck(false); + }).catch(error=>{}) + } + } + }) + } + return( + + 取消 + { !check && relayCount !== 0 && 开始检测 } + + } + > +
    +
    +
      +
    • +
    • +
    • +
    • +
    • +
    • +
    • +
    + { + check ? +

    正在开启检测,请等待...

    + : +

    剩余扫描次数{relayCount}

    + } +
    +
    +
    + { + !check && !repeatBranch && + + {getFieldDecorator("branch",{ + rules:[{required:true,message:"请选择要检测的分支"}] + })( + + )} + + } +
    + { + ((check && branch) || repeatBranch) && +
    + 检测分支 +

    {branch || repeatBranch}

    +
    + } +
    + 检测类型 +

    快速-组件级

    +
    +
    + 检测参数 +
    +

    解析层级:2

    +

    最小解析文件行数:10

    +

    许可证检测类型:开源软件

    + 文件相似阈值 +
      +
    • 行数:20
    • +
    • 相似比例:50%
    • +
    +
    +
    +
    +
    +
    +
    +
    + ) +} +export default Form.create()(forwardRef(DetectionModal)); \ No newline at end of file diff --git a/src/forge/Server/img/1.png b/src/forge/Server/img/1.png new file mode 100644 index 00000000..f68e8d95 Binary files /dev/null and b/src/forge/Server/img/1.png differ diff --git a/src/forge/Server/img/2.png b/src/forge/Server/img/2.png new file mode 100644 index 00000000..2643e352 Binary files /dev/null and b/src/forge/Server/img/2.png differ diff --git a/src/forge/Server/img/3.png b/src/forge/Server/img/3.png new file mode 100644 index 00000000..93987fcc Binary files /dev/null and b/src/forge/Server/img/3.png differ diff --git a/src/forge/Server/img/4.png b/src/forge/Server/img/4.png new file mode 100644 index 00000000..0374f991 Binary files /dev/null and b/src/forge/Server/img/4.png differ diff --git a/src/forge/Server/img/5.png b/src/forge/Server/img/5.png new file mode 100644 index 00000000..921b8c33 Binary files /dev/null and b/src/forge/Server/img/5.png differ diff --git a/src/forge/Server/img/6.png b/src/forge/Server/img/6.png new file mode 100644 index 00000000..31894e40 Binary files /dev/null and b/src/forge/Server/img/6.png differ diff --git a/src/forge/Server/img/7.png b/src/forge/Server/img/7.png new file mode 100644 index 00000000..2c2c3972 Binary files /dev/null and b/src/forge/Server/img/7.png differ diff --git a/src/forge/Server/img/bg.png b/src/forge/Server/img/bg.png new file mode 100644 index 00000000..ac89dfef Binary files /dev/null and b/src/forge/Server/img/bg.png differ diff --git a/src/forge/Server/img/detectionBG.png b/src/forge/Server/img/detectionBG.png new file mode 100644 index 00000000..d79ab961 Binary files /dev/null and b/src/forge/Server/img/detectionBG.png differ diff --git a/src/forge/Server/img/logo.png b/src/forge/Server/img/logo.png new file mode 100644 index 00000000..4bebd9fc Binary files /dev/null and b/src/forge/Server/img/logo.png differ diff --git a/src/forge/Server/img/modaltitle.png b/src/forge/Server/img/modaltitle.png new file mode 100644 index 00000000..81179304 Binary files /dev/null and b/src/forge/Server/img/modaltitle.png differ diff --git a/src/forge/Server/img/nullicon.png b/src/forge/Server/img/nullicon.png new file mode 100644 index 00000000..6801601d Binary files /dev/null and b/src/forge/Server/img/nullicon.png differ diff --git a/src/forge/Server/index.scss b/src/forge/Server/index.scss new file mode 100644 index 00000000..a0de01e4 --- /dev/null +++ b/src/forge/Server/index.scss @@ -0,0 +1,454 @@ +.panels{ + width: 1200px; + margin:20px auto; +} +.btnhover{ + background-color: #466aff; + color: #fff!important; + &:hover{ + background-color: rgba(26, 71, 255, 1)!important; + color: #fff!important; + } +} +.servertitle{ + display: flex; + align-items: center; + background-color:#fafcff; + border:1px solid rgba(42, 97, 255, 0.23); + border-radius:3px 3px 0px 0px; + justify-content: space-between; + padding:12px 16px; + .systitle{ + font-weight:500; + color:#333333; + font-size:16px; + } + a{ + width:88px; + height:36px; + line-height: 36px; + background-color:#466aff; + border-radius:5px; + text-align: center; + } +} +.dataEmpty{ + margin-top: 25px; + background-color:#fafcff; + border-radius:4px 4px 0px 0px; + min-height: 418px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + .dataemptyCon{ + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + max-width: 665px; + text-align: center; + .nullTitle{ + font-size: 22px; + height: 30px; + line-height: 30px; + margin:15px 0px 28px!important; + color: #333; + } + .nullDesc{ + color:#666666; + font-size:14px; + line-height:28px; + } + .ant-divider{ + min-width: 500px; + width: 500px; + border-top:1px solid rgba(90, 117, 193, 0.23); + margin:18px 0px!important; + height: 0px; + } + .nullSubDesc{ + color:#333333; + font-size:16px; + } + } +} +.agreementModal{ + .ant-modal-header{ + padding:0px ; + height: 56px; + background:url('./img/modaltitle.png') 100% 100% ; + color: #fff; + .ant-modal-title{ + color: #fff; + height: 56px; + line-height: 56px!important; + color: #fff; + } + } + .ant-modal-close{ + top:0px!important; + color: #fff; + } + .ant-modal-body{ + padding:0px; + } + .agreementCon{ + height: 400px; + overflow-y: auto; + padding:20px; + p{ + line-height: 26px; + font-size: 15px; + color: #333; + margin-bottom: 8px!important; + &.blod{ + font-weight:500; + color: #000; + } + } + } + .agreeBtn{ + display: flex; + align-items: center; + height: 67px; + justify-content: center; + a{ + display: block; + height:36px; + line-height: 34px; + margin:0px 20px; + background-color:#ffffff; + border:1px solid; + border-color:#d0d0d0; + border-radius:4px; + width: 120px; + text-align: center; + color:#666666; + font-size:15px; + &.notagree{ + background-color:rgba(177, 192, 255, 1); + border-color:rgba(177, 192, 255, 1); + color: #fff!important; + cursor: default; + } + &.agree{ + background-color:#466aff; + border-color:rgba(177, 192, 255, 1); + color: #fff!important; + } + } + } +} +.detectionAnimation{ + height: 240px; + width: 100%; + background-image: url('./img/detectionBG.png'); + background-size: 100%; + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + .animationUl{ + width: 166px; + height: 166px; + position: relative; + &.action li{ + -webkit-animation: App-logo-spin infinite 5s linear; + animation: App-logo-spin infinite 5s linear; + } + li{ + position: absolute; + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + &:last-child{ + align-items: flex-end; + height: 96px; + bottom: 36px; + } + } + } + @keyframes App-logo-spin { + from{ + transform:rotate(0deg); + } + to { + transform:rotate(360deg); + } + } + .lastTimes{ + color: #fff; + margin-top: 6px; + height: 30px; + line-height: 30px; + display: flex; + span{ + font-size: 20px; + margin-left: 8px; + } + } +} +.dataTable,.dataUl{ + .ant-table-thead > tr > th{ + background-color: #fff; + div{ + color: rgba(51, 51, 51, 1); + font-size: 16px; + } + } + .ant-table-tbody > tr:hover > td{ + background-color: rgba(248, 250, 255, 1)!important; + } + + .failure{ + display: block; + height:32px; + line-height:32px; + background-color:rgba(230, 0, 6, 0.1); + border:1px solid; + border-color:#fcb6c2; + border-radius:4px; + color: rgba(255, 12, 12, 1); + width:58px; + text-align: center; + } + .success{ + display: block; + height:32px; + line-height:32px; + background-color:rgba(83, 255, 163, 0.1); + border:1px solid; + border-color:rgba(0, 184, 67, 1); + border-radius:4px; + color: rgba(0, 156, 68, 1); + width:58px; + text-align: center; + } + .running{ + position: relative; + width: 137px; + height: 22px; + background-color: rgba(75, 75, 75, 0.1); + border-radius:26px; + span.percentline{ + position: absolute; + left: 0px; + top:0px; + height: 100%; + background-color: rgba(80, 156, 255, 1); + border-radius:26px; + text-align: center; + line-height: 24px; + color: rgba(51, 51, 51, 1); + } + } + .percentNum{ + position: absolute; + height: 24px; + line-height: 24px; + } + .operationBtns{ + display: flex; + align-items: center; + justify-content: center; + a,span{ + margin:0px 14px; + position: relative; + color: rgba(70, 106, 255, 1); + display: flex; + align-items: center; + height: 26px; + } + span{ + color: rgba(197, 204, 225, 1)!important; + cursor: default; + } + a > i,span>i{ + width: 13px; + } + a::before,span::before{ + position: absolute; + content: ""; + width: 1px; + height: 12px; + top:7px; + background-color: rgba(213, 213, 213, 1); + left: -14px; + } + a:first-child::before,span:first-child::before{ + display: none; + } + } +} +.dataUl{ + &>div{ + border-bottom: 1px solid #eee; + } + li{ + display: flex; + flex-wrap: wrap; + height: 66px; + align-items: center; + color:#333333; + &>span{ + padding:0px 10px; + text-align: left; + } + &>span:first-child{ + width: 7%; + text-align: center; + } + &>span:nth-child(2){ + width: 30%; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + &>span:nth-child(3){ + flex:1; + } + &>span:nth-child(4){ + width: 16%; + } + &>span:last-child{ + width: 30%; + text-align: center; + } + &.dataUlhead{ + font-size:16px; + } + &.dataUlbody{ + font-size: 14px; + &:hover{ + background-color:#f8faff + } + } + } +} +.formDiv{ + width: 430px; + margin:0px auto; + padding:20px 0px; + .has-error .ant-form-explain{ + position: absolute; + bottom: -15px; + } + .ant-form-item-label{ + width: 70px; + height: 32px; + line-height: 32px; + margin-top: 4px; + label{ + color:#20294a; + font-size:15px; + } + } + .ant-row.ant-form-item{ + margin-bottom: 12px!important; + } + .ant-form-item-required::before{ + display: none; + } + .checkInfos{ + &>div{ + display: flex; + &>span{ + display: block; + width: 70px; + line-height: 32px; + text-align: left; + color:#20294a; + font-size:15px; + } + ul{ + display: flex; + margin-top: 15px; + li:first-child{ + margin-right: 30px; + } + } + p,ul>li{ + height: 32px; + line-height: 32px; + padding:0px 12px; + background-color:#f5f7ff; + border-radius:4px; + color:#666666; + margin-bottom: 15px!important; + flex:1 + } + } + } +} +.serverlist{ + display: flex; + flex-wrap: wrap; + min-height: 500px; + align-content: flex-start; + li{ + width: 368px; + margin-right: 36px; + height: 198px; + background-image:url('./img/bg.png'); + background-repeat: no-repeat; + background-size: 100% 100%; + margin-bottom: 20px!important; + padding:30px 40px 0px 40px; + position: relative; + &:nth-child(3n+1){ + margin-left: -10px; + } + &:nth-child(3n){ + margin-right: -10px; + } + .servername{ + display: flex; + align-items: center; + margin-bottom: 12px; + img{ + margin-right: 8px; + width: 42px; + } + a{ + font-weight:500; + color:#466aff; + font-size:17px; + } + } + &:hover{ + .serverbtn{ + opacity: 1; + } + } + .serverdesc{ + -webkit-line-clamp: 3; + line-height: 25px; + color:#525662; + font-size:15px; + } + .serverbtn{ + position: absolute; + height: 56px; + background-color: transparent; + bottom: 10px; + left: 10px; + right: 10px; + display: flex; + justify-content: center; + padding: 10px; + opacity: 0; + transition: 0.3s; + a{ + display: block; + width: 224px; + height: 36px; + line-height: 36px; + text-align: center; + border-radius: 4px; + } + } + } +} \ No newline at end of file diff --git a/src/forge/Settings/Setting.js b/src/forge/Settings/Setting.js index 5e02796c..e44d9b49 100644 --- a/src/forge/Settings/Setting.js +++ b/src/forge/Settings/Setting.js @@ -18,6 +18,7 @@ const menu = [ // {name:"资源库",index:"resources"}, {name:"里程碑",index:"versions"}, {name:"维基 (Wiki)",index:"wiki"}, + // {name:"服务",index:"services"}, {name:"动态",index:"activity"}, ] class Setting extends Component { diff --git a/src/forge/Team/New.jsx b/src/forge/Team/New.jsx index 46e13c3e..7a0fe043 100644 --- a/src/forge/Team/New.jsx +++ b/src/forge/Team/New.jsx @@ -66,8 +66,8 @@ export default Form.create()( if(!value){ callback(); } - if(value && !value.match(/^[a-zA-Z][a-zA-Z0-9_-]{3,19}$/)){ - callback("只能使用以字母开头,包含字母、数字、下划线、横杠等,长度4到20个字符"); + if(value && !value.match(/^[a-zA-Z0-9][a-zA-Z0-9_-]{3,19}$/)){ + callback("只能使用以字母、数字开头,包含字母、数字、下划线、横杠等,长度4到20个字符"); } callback(); } diff --git a/src/forge/Team/Setting/TeamSettingCommon.jsx b/src/forge/Team/Setting/TeamSettingCommon.jsx index 3e0389e3..4c43d8ee 100644 --- a/src/forge/Team/Setting/TeamSettingCommon.jsx +++ b/src/forge/Team/Setting/TeamSettingCommon.jsx @@ -103,7 +103,7 @@ export default Form.create()( if(!value){ callback(); } - if(value && !value.match(/^[a-zA-Z][a-zA-Z0-9_-]{3,19}$/)){ + if(value && !value.match(/^[a-zA-Z0-9][a-zA-Z0-9_-]{3,19}$/)){ callback("只能使用以字母开头,包含字母、数字、下划线、横杠等,长度4到20个字符"); } callback(); diff --git a/src/forge/users/Infos.js b/src/forge/users/Infos.js index d5d54706..13d78239 100644 --- a/src/forge/users/Infos.js +++ b/src/forge/users/Infos.js @@ -102,7 +102,7 @@ class Infos extends Component { }else if(pathname === `/${username}/followers`){ this.setState({menuKey:undefined,route_type:"followers"}); }else{ - this.setState({menuKey:undefined,route_type:undefined}); + this.setState({menuKey:"6",route_type:undefined}); } } @@ -249,7 +249,6 @@ class Infos extends Component { const { current_user } = this.props; const { username } = this.props.match.params; const { user, isSpin, route_type , undo_events , menuKey , avatarVisible } = this.state; - return (
    { diff --git a/src/glcc/api.js b/src/glcc/api.js index f0f99d61..217d7870 100644 --- a/src/glcc/api.js +++ b/src/glcc/api.js @@ -1,6 +1,6 @@ import fetch from './fetch'; -// 获取当前用户报名信息 +// 获取当前用户项目报名信息 export function getUserApplyInfo(params) { return fetch({ url: `/api/applyInformation/getUserApplyInfo`, @@ -16,4 +16,76 @@ 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 + }); +} + +// 学生报名课题列表 +export function studentApplyList(params) { + return fetch({ + url: `/api/studentApply/list`, + method: 'get', + params + }); } \ No newline at end of file diff --git a/src/glcc/apply/index.jsx b/src/glcc/apply/index.jsx index bcc14677..74f23fd9 100644 --- a/src/glcc/apply/index.jsx +++ b/src/glcc/apply/index.jsx @@ -46,7 +46,6 @@ function Apply(props) { }else{ window.location.href="/login?go_page=/glcc/apply"; } - }, []) useEffect(()=>{ @@ -108,7 +107,6 @@ function Apply(props) { } return isLt100M && isType; } - function getBase64(img, callback) { const reader = new FileReader(); reader.addEventListener('load', () => callback(reader.result)); @@ -128,7 +126,7 @@ function Apply(props) { } return(
    - +
    开源夏令营 @@ -177,7 +175,7 @@ function Apply(props) { 'logo格式为png、jpg、jpeg,限制上传大小2m,建议上传尺寸为382*228', 'logo', [{ required: true, message: "请正确上传项目logo" }], - userApplyInfo && userApplyInfo.projectLogoId ?
    + userApplyInfo && userApplyInfo.projectLogoId ?
    :

    申请说明

    -
    1、项目报名时间为4月15日—5月8日,请在报名截止时间(北京时间2022年5月8日18点)前提交报名信息。
    +
    1、项目报名时间为4月15日—5月20日,请在报名截止时间(北京时间2022年5月20日24点)前提交报名信息。
    2、本次夏令营使用Gitlink为代码托管平台,学员基于Gitlink上项目数量完成课程任务。如果您的项目还未在Gitlink中,请现将项目迁移到Gitlink,迁移事项请查看迁移说明文档。如在迁移过程中遇到问题,请加qq群: 1071514693 联系qq群管理员。
    3、提交社区和项目信息后,欢迎与组委会联系沟通本次编程夏令营宣传推广和后续合作工作。联系人: _TigerWang(微信号,添加请备注Gitlink编程夏令营)
    diff --git a/src/glcc/home/award/index.jsx b/src/glcc/home/award/index.jsx index ffa1c758..70626de6 100644 --- a/src/glcc/home/award/index.jsx +++ b/src/glcc/home/award/index.jsx @@ -10,7 +10,7 @@ function Award() {
    丰厚现金奖励
    -
    根据项目难度设置高、中、低三个阶梯课题,对应奖金为12000 元、9000 元和 6000
    +
    根据课题开发耗时,对应奖金从6000元至12000元不等。可在课题详情中查看具体奖金标准
    @@ -28,7 +28,7 @@ function Award() {
    夏令营大礼包
    -
    夏令营纪念文化衫、帆布包、鼠标垫,开源系列图书,社区周边等。此外,还会评选出若干优秀社区、明星导师、最佳课题、开源之星等单项奖。
    +
    夏令营纪念文化衫、帆布包、鼠标垫,开源系列图书,社区周边等。此外,还会评选出若干优秀社区、明星导师、最佳课题、开源之星等单项奖
    diff --git a/src/glcc/home/index.jsx b/src/glcc/home/index.jsx index c446391b..c3085b39 100644 --- a/src/glcc/home/index.jsx +++ b/src/glcc/home/index.jsx @@ -8,26 +8,75 @@ 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; + 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 { + showNotification("不在报名时间,报名时间为4月15日~5月20日"); + window.location.href = "/glcc"; + } + } + + function goToStudent(){ + // 学生报名时间 + const studentApply = Date.parse(new Date()) > 1653494400000; + if(!studentApply){ + showNotification("不在报名时间,报名开始时间为5月26日"); + } + } return (
    {/* */} - + {/*
    */} - {!isGlccApplyDate && showNotification("不在报名时间,报名时间为4月15日~5月8日")}}> + {/* {!isGlccApplyDate && showNotification("不在报名时间,报名时间为4月15日~5月20日")}}> */} + {/*
    立即报名
    - - {/*
    */} -
    -
    活动简介
    -
    GitLink编程夏令营(GLCC),是在CCF中国计算机学会指导下,由CCF开源发展委员会(CCF ODC)举办的面向全国高校学生的暑期编程活动。活动将覆盖近千所高校,并联合各大开源基金会、开源企业、开源社区、开源专家,旨在鼓励青年学生通过参加真实的开源软件开发,提升自身技术能力,为开源社区输送优秀人才。为青年学生提供开放友好的交流平台,希望进一步推动国内开源社区的繁荣发展。
    +
    */} + {/* 报名入口 */} +
    + {/* 项目报名 */} +
    +
    + + 项目报名 > + 项目报名已截止 +
    +
    项目报名开启,导师席位虚位以待
    +
    + {/* 学生报名 */} +
    +
    + + 学生报名 > +
    +
    选择感兴趣的课题,开启您的开源之旅
    +
    - + {/*
    */} +
    +
    +
    活动简介
    +
    +
    GitLink编程夏令营(GLCC),是在CCF中国计算机学会指导下,由CCF开源发展委员会(CCF ODC)举办的面向全国高校学生的暑期编程活动。活动将覆盖近千所高校,并联合各大开源基金会、开源企业、开源社区、开源专家,旨在鼓励青年学生通过参加真实的开源软件开发,提升自身技术能力,为开源社区输送优秀人才。为青年学生提供开放友好的交流平台,希望进一步推动国内开源社区的繁荣发展。
    + +
    +
    +
    + diff --git a/src/glcc/home/index.scss b/src/glcc/home/index.scss index 6063018c..5805d848 100644 --- a/src/glcc/home/index.scss +++ b/src/glcc/home/index.scss @@ -17,22 +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; @@ -83,7 +130,7 @@ min-width: 62.5vw; max-width: 98vw; margin: 0 auto; - padding-top: 45px; + padding-top: 65px; } // 1行省略号 @@ -108,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; + } + } } diff --git a/src/glcc/home/lightspot/index.jsx b/src/glcc/home/lightspot/index.jsx index de56f190..b8ba6af0 100644 --- a/src/glcc/home/lightspot/index.jsx +++ b/src/glcc/home/lightspot/index.jsx @@ -14,6 +14,27 @@ import { Link } from 'react-router-dom'; function Lightspot(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/"; + } + }else{ + showNotification("不在报名时间,报名时间为4月15日~5月20日"); + window.location.href="/glcc"; + } + } + + function goToStudent(){ + // 学生报名时间 + const studentApply = Date.parse(new Date()) > 1653494400000; + if(!studentApply){ + showNotification("不在报名时间,报名开始时间为5月26日"); + } + } + return (
    @@ -23,32 +44,40 @@ function Lightspot(props) {

    有兴趣成为GLCC的导师吗?

    想要扩大项目知名度和影响力,为开源项目吸引新鲜血液,培养长期开发者。通过GitLink平台,与高校建立连接,指导开源新人传授他们的开源文化,享受开源的乐趣
    - {!isGlccApplyDate && showNotification("不在报名时间,报名时间为4月15日~5月8日")}}>立即报名 + {/* {!isGlccApplyDate && showNotification("不在报名时间,报名时间为4月15日~5月20日")}}>立即报名 */} + {/* onClick={goToApply} */} +
    项目报名项目报名已截止
    - +
    +

    你是开源新手,有兴趣参加GLCC吗?

    +
    想要参与一线开源项目开发,熟悉开源社区运作流程,接受资深开源软件专家指导,获得丰厚奖金和实习机会。参加GLCC,开启全新的开源之旅。
    + {/* {!isGlccApplyDate && showNotification("不在报名时间,报名时间为4月15日~5月20日")}}>立即报名 */} +
    学生报名
    +
    + {/* */}
    - +

    汇聚行业顶尖开源项目

    平台汇聚华为、xiuos、鲲鹏、开源基金会、飞腾、浪潮等行业尖端开源项目,把握开源生态发展脉搏
    - +

    覆盖全国千所高校、万名会员

    活动邀请10+全球顶尖开源基金会,100+顶级开源项目社区,致力营造专业、开放的开源社区
    - +

    结识开源伙伴和技术大咖

    每个项目配备一名导师,参与开源项目开发可接受一线资深开源项目专家专业指导,结识志同道合的开发伙伴
    - +

    丰厚奖励&实习绿色通道

    入选同学可获得丰厚奖金,并有机会进入优秀开源项目企业实习或工作,受邀参与开源大会等机会
    diff --git a/src/glcc/home/lightspot/index.scss b/src/glcc/home/lightspot/index.scss index 485a7a2b..7b708f88 100644 --- a/src/glcc/home/lightspot/index.scss +++ b/src/glcc/home/lightspot/index.scss @@ -10,6 +10,7 @@ .info-teacher { display: flex; justify-content: space-between; + margin-bottom: 50px; } .teacher-text { margin-right: 2.84%; @@ -25,6 +26,20 @@ &:hover{ 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; } } } diff --git a/src/glcc/home/partner/index.jsx b/src/glcc/home/partner/index.jsx index 97f13111..364ed825 100644 --- a/src/glcc/home/partner/index.jsx +++ b/src/glcc/home/partner/index.jsx @@ -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() {
    {window.open("https://www.ecnu.edu.cn/")}}>华东师范大学
    {window.open("http://www.csust.edu.cn/")}}>长沙理工大学
    {window.open("https://www.jnu.edu.cn/")}}>暨南大学
    +
    {window.open("https://www.shu.edu.cn/")}}>上海大学
    +
    {window.open("https://www.bnu.edu.cn/")}}>北京师范大学
    diff --git a/src/glcc/home/timerShaft/index.jsx b/src/glcc/home/timerShaft/index.jsx index 930ac780..aafad773 100644 --- a/src/glcc/home/timerShaft/index.jsx +++ b/src/glcc/home/timerShaft/index.jsx @@ -5,32 +5,32 @@ import './index.scss'; const stepArr = [{ title: "Step1", date: "4.15", - content: "GLCC发布" + content: "GLCC夏令营活动发布" }, { title: "Step2", - date: "4.15-5.8", - content: "社区启动报名" + date: "4.15-5.19", + content: "社区项目报名,提交课题" }, { title: "Step2", - date: "5.20", - content: "公示社区名单" + date: "5.20-5.25", + content: "公示社区项目名单" }, { title: "Step2", - date: "5.21-6.19", - content: "学生提交proposal" + date: "5.26-6.24", + content: "学生报名,提交Proposal" }, { title: "Step2", date: "7.1", - content: "公示项目申请审核结果", + content: "公示入选学生名单", noArrow: true, }, { title: "Step2", - date: "7.4-8.12", + date: "7.1-8.12", content: "项目开发第一阶段", }, { @@ -40,13 +40,13 @@ const stepArr = [{ }, { title: "Step2", - date: "10.1-10.14", - content: "结项审核", + date: "10.1-10.21", + content: "结项审核,并公示考核结果", }, { title: "Step2", - date: "11.11", - content: "公布优秀项目&学员", + date: "10.21-11.11", + content: "评选公布优秀项目和学员", noArrow: true, } ] diff --git a/src/glcc/img/apply1.png b/src/glcc/img/apply1.png new file mode 100644 index 00000000..1981aa58 Binary files /dev/null and b/src/glcc/img/apply1.png differ diff --git a/src/glcc/img/apply2.png b/src/glcc/img/apply2.png new file mode 100644 index 00000000..6d80273d Binary files /dev/null and b/src/glcc/img/apply2.png differ diff --git a/src/glcc/img/apply_bg1.png b/src/glcc/img/apply_bg1.png new file mode 100644 index 00000000..c2b4a222 Binary files /dev/null and b/src/glcc/img/apply_bg1.png differ diff --git a/src/glcc/img/apply_bg2.png b/src/glcc/img/apply_bg2.png new file mode 100644 index 00000000..850ce493 Binary files /dev/null and b/src/glcc/img/apply_bg2.png differ diff --git a/src/glcc/img/banner.png b/src/glcc/img/banner.png index 9fa40a46..3806f08b 100644 Binary files a/src/glcc/img/banner.png and b/src/glcc/img/banner.png differ diff --git a/src/glcc/img/introduce.png b/src/glcc/img/introduce.png new file mode 100644 index 00000000..43c007dd Binary files /dev/null and b/src/glcc/img/introduce.png differ diff --git a/src/glcc/img/logo1.png b/src/glcc/img/logo1.png new file mode 100644 index 00000000..590e9564 Binary files /dev/null and b/src/glcc/img/logo1.png differ diff --git a/src/glcc/img/logo2.png b/src/glcc/img/logo2.png new file mode 100644 index 00000000..e69c4f1e Binary files /dev/null and b/src/glcc/img/logo2.png differ diff --git a/src/glcc/img/projectBg.png b/src/glcc/img/projectBg.png new file mode 100644 index 00000000..7e469985 Binary files /dev/null and b/src/glcc/img/projectBg.png differ diff --git a/src/glcc/img/projectDetailTaskBg.png b/src/glcc/img/projectDetailTaskBg.png new file mode 100644 index 00000000..4caff1ae Binary files /dev/null and b/src/glcc/img/projectDetailTaskBg.png differ diff --git a/src/glcc/img/qqChat.png b/src/glcc/img/qqChat.png new file mode 100644 index 00000000..4e2d7d66 Binary files /dev/null and b/src/glcc/img/qqChat.png differ diff --git a/src/glcc/img/student.png b/src/glcc/img/student.png new file mode 100644 index 00000000..ede714ea Binary files /dev/null and b/src/glcc/img/student.png differ diff --git a/src/glcc/img/studentProject.png b/src/glcc/img/studentProject.png new file mode 100644 index 00000000..45539509 Binary files /dev/null and b/src/glcc/img/studentProject.png differ diff --git a/src/glcc/index.jsx b/src/glcc/index.jsx index 4598c494..1778b66d 100644 --- a/src/glcc/index.jsx +++ b/src/glcc/index.jsx @@ -11,6 +11,7 @@ import "./index.scss"; import Loadable from "react-loadable"; import Loading from "../Loading"; import { ImageLayerOfCommentHOC } from "../modules/page/layers/ImageLayerOfCommentHOC"; +import { useState } from "react"; // 任务管理审核 @@ -23,20 +24,37 @@ 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) => { - // 判断时间是否在开源夏令营报名时间内(4月15日~5月8日) - const isGlccApplyDate = Date.parse(new Date()) < 1652025600000; + // 判断时间是否在开源夏令营报名时间内(4月15日~5月20日) + const isGlccApplyDate = Date.parse(new Date()) < 1653062400000; return (
    + {/* 学生报名 */} + ( + + )} + > {/* 开源夏令营报名页面 */} { )} > + {/* 项目/课题列表 */} + ( + + )} + > {/* 首页 */} { + const [info, setInfo] = useState(detail); + + // 申请课题按钮点击函数 + 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(); + } + } + + useEffect(()=>{ + if(!detail && projectId){ + // 通过项目Id查询项目详情 + getProjectById(projectId).then(response=>{ + if(response && response.message === 'success'){ + setInfo(response.data) + } + }) + } + },[detail]) + + return ( + info ?
    +
    + {info.projectName} + {info.projectType && {info.projectType}} +

    GitLink项目地址:  {info.gitlinkUrl}

    +
    项目简介:  {info.projectIntro}
    +
    + {info.registrationTaskList && info.registrationTaskList.length > 0 ? info.registrationTaskList.map(item=>{ + return
    +
    +
    {item.taskName}
    +
    导师姓名:   {item.tutorName}
    +
    邮箱地址:   {item.tutorMail}
    +
    +
    +
          {item.taskDesc}
    +
    奖金:   {item.taskReward}
    + {item.taskUrl &&
    课题链接:   {item.taskUrl}
    } +
    {(isStudentApplyDate || studentApplyEnd) && (applyTaskId && item.id && Object.keys(applyTaskId).includes(item.id.toString()) ? : isStudentApplyDate && )}
    +
    +
    + }) : } +
    :
    + ) +} \ No newline at end of file diff --git a/src/glcc/project/index.jsx b/src/glcc/project/index.jsx new file mode 100644 index 00000000..652de14c --- /dev/null +++ b/src/glcc/project/index.jsx @@ -0,0 +1,84 @@ +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, showLoginDialog} = propsF; + const {pathname} = location; + const isStudentApplyDate = Date.parse(new Date()) > 1653494400000 && Date.parse(new Date()) < 1656086400000; + const studentApplyEnd = Date.parse(new Date()) > 1656086400000; + // const studentApplyEnd = false; + // const isStudentApplyDate = true; + + // 用户已报名课题id数组 + const [applyTaskId, setApplyTaskId] = useState({}); + // 刷新用户课题报名信息 + const [studentInfoReset, setStudentInfoReset] = useState(undefined); + + useEffect(()=>{ + // 获取用户课题报名信息current_user user_id + current_user && current_user.login && getStudentApplyInfo({userId: 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, current_user]) + return( +
    + +
    + 课题列表 + 项目列表 +
    +
    + 开源夏令营 / + 课题及项目列表 +
    + + + ( + + )} + > + ( + + )} + > + ( + + )} + > + + +
    + ) +} +export default Project; \ No newline at end of file diff --git a/src/glcc/project/index.scss b/src/glcc/project/index.scss new file mode 100644 index 00000000..77739a9c --- /dev/null +++ b/src/glcc/project/index.scss @@ -0,0 +1,200 @@ +.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; + &.task{ + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; + .ant-input-group-wrapper{width: 40%;} + } + } + .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; + line-height: 36px; + .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; + line-height: 26px; + } + .linkUrl{ + color: #466aff; + } + } + .taskItem { + display: flex; + justify-content: space-between; + border:1px solid #ffffff; + &:hover{ box-shadow: 0px 0px 12px rgba(71, 105, 198, 0.4);} + .oneLine{ + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + .left{ + width: 316px; + 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;} + .leftWidth{width: 270px;} + } + .center{ + // width: 650px; + text-align: left; + padding: 20px; + display: flex; + flex-direction: column; + justify-content: space-between; + .taskDesc{ + color:#6b6b6b; + } + .taskUrl{ + color:#465474; + font-size:16px; + line-height: 28px; + margin-bottom: 5px; + a{color:#466aff;} + } + .applyBut{ + background-color:#466aff; + border-color: #466aff; + &:hover{background-color:#5d7cff;} + &:focus{background-color:#1140ff;} + } + .taskReward{color:#ff8800;} + } + // .right{ + // min-width: 150px; + // font-weight:700; + // color:#ff8800; + // font-size:24px; + // padding: 30px 30px 0 0; + // } + } +} +.projectItemPopover{ + width: 1200px; + .ant-popover-content .ant-popover-arrow{ + border-width: 12px; + } +} +.projectItemPopover .ant-popover-inner{ + transform: translateY(8px); + 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; + } +} +.lookDetail{ + border-color: #466aff; + color: #466aff; + &:hover{ + border-color: #5d7cff; + color: #5d7cff; + } + &:focus{ + border-color: #1140ff; + color: #1140ff; + } +} \ No newline at end of file diff --git a/src/glcc/project/projectList/index.jsx b/src/glcc/project/projectList/index.jsx new file mode 100644 index 00000000..dda00dc0 --- /dev/null +++ b/src/glcc/project/projectList/index.jsx @@ -0,0 +1,53 @@ +import React , { useEffect , useState } from 'react'; +import { Input, Popover, Spin, 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, current_user, showLoginDialog, isStudentApplyDate, studentApplyEnd}) { + // 输入搜索框 + const [keyword, setKeyword] = useState(undefined); + const [data, setData] = useState([]); + const [loading, setLoading] = useState(false); + + useEffect(()=>{ + setLoading(true); + const params = { + curPage: 1, + keyword, + pageSize: 20 + } + projectList(params).then(response=>{ + if(response && response.message === "success"){ + setData(response.data.rows); + } + setLoading(false); + }) + },[keyword]) + + return( +
    +
    +
    {setKeyword(value)}}/>
    + +
    + {data && data.map((item, index)=>{ + return } trigger='click' overlayClassName='projectItemPopover' autoAdjustOverflow={false}> +
    +
    +
    +
    {item.projectName}
    +
    {item.projectIntro}
    +
    +
    + })} +
    +
    +
    +
    + ) +} +export default ProjectList; \ No newline at end of file diff --git a/src/glcc/project/projectList/index.scss b/src/glcc/project/projectList/index.scss new file mode 100644 index 00000000..581af5ff --- /dev/null +++ b/src/glcc/project/projectList/index.scss @@ -0,0 +1,68 @@ +.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—#FFFFFF(85%) + 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; + } + } +} \ No newline at end of file diff --git a/src/glcc/project/taskList/index.jsx b/src/glcc/project/taskList/index.jsx new file mode 100644 index 00000000..f6d58082 --- /dev/null +++ b/src/glcc/project/taskList/index.jsx @@ -0,0 +1,196 @@ +import React, { Fragment, useEffect, useState } from 'react'; +import { Checkbox, Input, message, Modal, Table, Tooltip } from 'antd'; +import './index.scss'; +import { cancelTaskApply, taskList, studentApplyList } from '../../api'; +import ProjectDetail from '../component/projectDetail'; +const { Search } = Input; + +// 课题列表 +function TaskList({applyTaskId, setStudentInfoReset, current_user, showLoginDialog, isStudentApplyDate, studentApplyEnd, studentInfoReset}) { + 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 [apply, setApply] = useState(false); + + const columns = [ + { title: '序号', dataIndex: 'index', align: 'center', className:"taskTableColumns", width: '6%', render: (text, item, index) => {(current-1)*pageSize+index + 1} }, + { title: '课题名称', dataIndex: 'taskName', className:"taskTableColumns taskName", width: '28%', ellipsis: true, render: (text, item) => {window.location.href=item.taskUrl}}>{text} }, + { title: '项目名称', dataIndex: 'projectName', className:"taskTableColumns", width: '28%', ellipsis: true, render: (text) => {text} }, + { title: '课题奖金', dataIndex: 'taskReward', className:"taskTableColumns", ellipsis: true, width: `${isStudentApplyDate || studentApplyEnd ? '15%' : ''}`, render: (text) => {text} }, + { + title: '操作', dataIndex: 'action', align: 'center', className:"actionColumns taskTableColumns", render: ((text, item, index) => { + return ( +
    + {(isStudentApplyDate || studentApplyEnd) && (applyTaskId && Object.keys(applyTaskId).includes(item.id.toString()) ? + {window.location.href=`/glcc/student/apply/${item.id}`}}>报名详情 + {setDeleteTaskId(item.id);setVisible(true)}}> + :isStudentApplyDate && + {applyTask(item.id)}}>申请课题)} +
    + ) + }) + }, + ] + + const customExpandIcon = (props) => { + if (props.expanded) { + return { + props.onExpand(props.record, e); + }}>项目详情 + } else { + return { + props.onExpand(props.record, e); + }}>项目详情 + } + } + + const expandRow = (record) => { + return + } + + // 展开收起行回调 + 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){ + setCurrent(1); + setPageSize(pageSize); + } + + // 切换页数 + function changePage(page, pageSize){ + setCurrent(page); + } + + // 数组元素置顶方法 + function toFirst(data, index){ + if(index != 0){ + data.unshift(data.splice(index,1)[0]); + } + } + + useEffect(() => { + setExpandedRowKeys([]); + setLoading(true); + const params = { + curPage: current, + keyword, + pageSize + } + taskList(params).then(response => { + if (response && response.message === "success") { + // 将已报名task任务置顶 + const ids = Object.keys(applyTaskId); + const data = response.data.rows; + data.map((item, index)=>{ + ids.includes(item.id.toString()) && toFirst(data, index); + }) + setData(data); + setTotal(response.data.total); + } + setLoading(false); + }) + }, [keyword, current, pageSize, applyTaskId]) + + useEffect(()=>{ + // if(apply){ + // // 判断用户是否已经登录 + // if(current_user && current_user.login){ + // apply && studentApplyList().then(response => { + // if (response && response.message === "success") { + // console.log(response); + // } + // }) + // }else{ + // showLoginDialog(); + // } + // } + },[apply]) + + return ( +
    +
    +
    + {setApply(e.target.checked)}}>已报名 + { setCurrent(1); setKeyword(value) }} /> +
    +
    + + + {setVisible(false)}} + onOk={cancelApply} + wrapClassName='cancelApplyTask' + > +
    !取消申请即删除本次报名记录,确定取消?
    +

    此操作将永久删除该报名记录,请进行确认以防数据的丢失

    +
    + + ) +} +export default TaskList; \ No newline at end of file diff --git a/src/glcc/project/taskList/index.scss b/src/glcc/project/taskList/index.scss new file mode 100644 index 00000000..76937b79 --- /dev/null +++ b/src/glcc/project/taskList/index.scss @@ -0,0 +1,110 @@ +.taskList{ + padding-bottom: 50px; + .ant-table{ + border: 1px solid white; + } + .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-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;} + } + } + } +} +.task.search{ + .ant-checkbox-wrapper:hover .ant-checkbox-inner, .ant-checkbox:hover .ant-checkbox-inner, .ant-checkbox-input:focus + .ant-checkbox-inner{border-color: #466aff;} + .ant-checkbox-checked{ + .ant-checkbox-inner { + background-color: #466aff; + } + } + .ant-checkbox::selection{border-color: #466aff;} + .ant-checkbox-input::after{border:1px solid #466aff;} + .ant-checkbox-checked::after{border:1px solid #466aff;} +} \ No newline at end of file diff --git a/src/glcc/siderBarHelp.js b/src/glcc/siderBarHelp.js index c59fbafc..7079133c 100644 --- a/src/glcc/siderBarHelp.js +++ b/src/glcc/siderBarHelp.js @@ -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 = ( +
    +
    +

    扫码进入QQ交流群

    +

    把握最新活动资讯

    +
    + ) + return ( // 开源夏令营定制帮助中心调整按钮 -
    window.open("/glcc/help")}> - - 帮助中心 +
    + +
    + + QQ交流 +
    +
    +
    window.open("/glcc/help")}> + + 帮助中心 +
    ) } diff --git a/src/glcc/student/index.jsx b/src/glcc/student/index.jsx new file mode 100644 index 00000000..05f4dbf4 --- /dev/null +++ b/src/glcc/student/index.jsx @@ -0,0 +1,514 @@ +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, match, setStudentInfoReset } = props; + const taskId = Number(match.params.taskId); + // 可用于开发时不同账号报名 + // current_user && (current_user.user_id = 6) + // current_user && (current_user.userName = "创新使者") + const isStudentApplyDate = new Date().getTime() > new Date('2022-05-26').getTime() && new Date().getTime() < new Date('2022-06-25').getTime(); + + 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(isStudentApplyDate); + const [files, setFiles] = useState([]); + const [files1, setFiles1] = useState([]); + const initTask = { + taskId, + memo: '', + memoAttachmentId: '' + }; + const [myTaskList, setMyTaskList] = useState([]); + const [allTaskList, setAllTaskList] = useState([]); + + // 学生报名时间范围内 + // 已过学生报名时间 + + useEffect(() => { + // 进入此页面到填写页面 + setTimeout(()=>{ + let clientWidth = document.body.clientWidth; + let scrollHeight = 500 * clientWidth / 1920; + window.scrollTo(0, scrollHeight); + }); + // window.scrollTo(0, 50); + + if (new Date().getTime() < new Date('2022-05-26').getTime()) { + // 不在开源夏令营报名时间之内 + window.location.href = "/glcc/student/2"; + } else if (current_user && current_user.login) { + + } else { + window.location.href = `/login?go_page=/glcc/student/apply/${taskId}`; + } + }, []) + + + 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) { + item.memoAttachment && setFiles([{ + name: item.memoAttachment && item.memoAttachment.fileName || '已上传文件', + id: item.memoAttachmentId, + uid: item.memoAttachmentId + }]); + } else { + item.memoAttachment && 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); + + // 如果只有一条报名数据,且课题id与当前id不一致,那么新增一条默认数据 + 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("修改信息成功"); + // setStudentInfoReset(Math.random()); + setReload(Math.random()); + setLoading(false); + } + }); + } else { + studentApply(params).then(response => { + if (response && response.message === "success") { + showNotification("报名成功"); + // setStudentInfoReset(Math.random()); + setReload(Math.random()); + setLoading(false); + } + }); + } + } + }); + }; + + const helper = useCallback( + (label, extra, name, rules, widget) => ( + + {getFieldDecorator(name, { rules, validateFirst: true })(widget)} + + ), + [] + ); + + + // 检查图片文件上传是否符合规定 + 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 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)); + 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') { + 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); + } + + const chooseArr = myTaskList.map(i => { return i.taskId }); + + return ( +
    + + +
    + + 开源夏令营 + 课题及项目列表 + 学生报名 + + +
    +

    申请说明:

    +
    1、学生报名时间为2022年5月26日-6月24日,请在报名截止时间(北京时间2022年6月24日24点)前提交报名信息。
    +
    2、本次GLCC夏令营基于GitLink代码托管平台完成编程任务,若您没有平台账户,请先注册后完成课题申请
    +
    3、每位学员最多可申请2个课题,至多有且仅有1个课题可以入选
    +
    4、建议在提交课题申请,与课题导师邮件沟通,详细了解课题描述、编码任务、技能要求&编程语言、预期产出结果等信息,以便您能够选择最适合的课题
    +
    5、提交申请后,请耐心等待,我们会在2022年7月1日公布入围结果。如有任何问题,请添加开源夏令营微信群进行咨询
    +
    +
    + 学生报名 +
    +
    +
    申请课题
    +
    +

    基本信息

    + {helper('学生姓名', + '', + 'studentName', + [{ required: true, message: "请正确输入学生姓名" }, + { max: 32, message: '超出限制长度32位字符,请重新编辑' }], + { verify("studentName") }} className={editable ? "" : "disabledInput"} disabled={editable ? false : true} /> + )} + {helper('所在高校', + '', + 'school', + [{ required: true, message: "请正确输入所在高校" }, + { max: 32, message: '超出限制长度32位字符,请重新编辑' }], + { verify("school") }} className={editable ? "" : "disabledInput"} disabled={editable ? false : true} /> + )} + {helper('所学专业', + '', + 'profession', + [{ max: 32, message: '超出限制长度32位字符,请重新编辑' }], + { verify("profession") }} className={editable ? "" : "disabledInput"} disabled={editable ? false : true} /> + )} + + {getFieldDecorator("location", { + rules: [] + })( + + )} + + {helper('所在年级', + '', + 'grade', + [], + + )} + {helper('联系电话', + '', + 'phone', + [{ required: true, message: "请正确输入联系电话" }, + { max: 14, message: '超出限制长度14位字符,请重新编辑' }, + { pattern: /(^(\d{3,4}-)?\d{7,8})$|([1][3,4,5,6,7,8,9][0-9]{9})/, message: '请正确输入联系电话' }], + { verify("phone") }} className={editable ? "" : "disabledInput"} disabled={editable ? false : true} /> + )} + {helper('邮箱地址', + '', + 'mail', + [ + { type: 'email', message: '请输入正确的邮箱地址', }, + { required: true, message: "请输入邮箱地址" }, + { max: 50, message: '超出限制长度50位字符,请重新编辑' }, + ], + { verify("mail") }} className={editable ? "" : "disabledInput"} disabled={editable ? false : true} /> + )} + +
    {helper('学生证明', + '请以图片的形式上传学生证明,大小不超过5M,格式为png、jpg、jpeg', + 'proveAttachmentId', + [{ required: true, message: "请正确上传学生证明" }], + + {imageUrl ? avatar : userApplyInfo && userApplyInfo.proveAttachmentId ? +
    :
    + +
    请上传学生证明
    +
    } +
    + )}
    + + { + myTaskList.map((item, i) => { + return ( + +

    课题信息({i + 1}/2) {myTaskList.length > 1 && { deleteTask(i) }}>删除}

    + {helper('课题名称', + '', + 'taskId' + i, + [{ required: true, message: "请选择课题名称" }], + + )} +
    {helper('自荐书', + , + 'memo' + i, + [{ required: true, message: "请正确输入自荐书" }, + { max: 500, message: '超出限制长度500位字符,请重新编辑' }], +