diff --git a/public/react/config/webpack.config.dev.js b/public/react/config/webpack.config.dev.js index 4acbb35a7..86938e51d 100644 --- a/public/react/config/webpack.config.dev.js +++ b/public/react/config/webpack.config.dev.js @@ -267,7 +267,7 @@ module.exports = { // https://github.com/jmblog/how-to-optimize-momentjs-with-webpack // You can remove this if you don't use Moment.js: new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/), - new MonacoWebpackPlugin(), + new MonacoWebpackPlugin(), ], // Some libraries import Node modules but don't use them in the browser. // Tell Webpack to provide empty mocks for them so importing them works. diff --git a/public/react/config/webpack.config.prod.js b/public/react/config/webpack.config.prod.js index 1cc105517..f312da3e6 100644 --- a/public/react/config/webpack.config.prod.js +++ b/public/react/config/webpack.config.prod.js @@ -11,6 +11,7 @@ const SWPrecacheWebpackPlugin = require('sw-precache-webpack-plugin'); const eslintFormatter = require('react-dev-utils/eslintFormatter'); const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin'); const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin'); +const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin'); const paths = require('./paths'); const getClientEnvironment = require('./env'); @@ -371,6 +372,7 @@ module.exports = { // https://github.com/jmblog/how-to-optimize-momentjs-with-webpack // You can remove this if you don't use Moment.js: new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/), + new MonacoWebpackPlugin(), ], // Some libraries import Node modules but don't use them in the browser. // Tell Webpack to provide empty mocks for them so importing them works. diff --git a/public/react/index.js b/public/react/index.js new file mode 100644 index 000000000..cb8cb4f94 --- /dev/null +++ b/public/react/index.js @@ -0,0 +1,46 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; + +import './index.css'; +import './indexPlus.css'; +import App from './App'; + +// 加之前main.js 18.1MB +// import { message } from 'antd'; +import message from 'antd/lib/message'; +import 'antd/lib/message/style/css'; + +import { AppContainer } from 'react-hot-loader'; + +import registerServiceWorker from './registerServiceWorker'; + +import { configureUrlQuery } from 'react-url-query'; + +import history from './history'; + +// link the history used in our app to url-query so it can update the URL with it. +configureUrlQuery({ history }); +// ----------------------------------------------------------------------------------- 请求配置 + +window.__useKindEditor = false; + + +const render = (Component) => { + ReactDOM.render( + + + , + document.getElementById('root') + ); +} + + +// ReactDOM.render( +// , +// document.getElementById('root')); +// registerServiceWorker(); + +render(App); +if (module.hot) { + module.hot.accept('./App', () => { render(App) }); +} diff --git a/public/react/package-lock.json b/public/react/package-lock.json index 631da270e..d66fbf62a 100644 --- a/public/react/package-lock.json +++ b/public/react/package-lock.json @@ -84,7 +84,6 @@ "@icedesign/base": { "version": "0.2.8", "resolved": "https://registry.npm.taobao.org/@icedesign/base/download/@icedesign/base-0.2.8.tgz", - "integrity": "sha1-hmlSY+17gnKJB3sbgoy446sqzAk=", "requires": { "async-validator": "^1.6.7", "classnames": "^2.2.3", @@ -138,8 +137,7 @@ }, "@types/tapable": { "version": "1.0.4", - "resolved": "https://registry.npm.taobao.org/@types/tapable/download/@types/tapable-1.0.4.tgz", - "integrity": "sha1-tP/H3Je0mMlps2CkHu4kf4JhY3A=" + "resolved": "https://registry.npm.taobao.org/@types/tapable/download/@types/tapable-1.0.4.tgz" }, "@types/uglify-js": { "version": "3.0.4", @@ -2779,8 +2777,7 @@ }, "cropperjs": { "version": "0.7.2", - "resolved": "https://registry.npm.taobao.org/cropperjs/download/cropperjs-0.7.2.tgz", - "integrity": "sha1-atinHbAGKbqULZzt5lKyeXXp50o=" + "resolved": "https://registry.npm.taobao.org/cropperjs/download/cropperjs-0.7.2.tgz" }, "cross-spawn": { "version": "5.1.0", @@ -10456,6 +10453,11 @@ "resolved": "http://registry.npm.taobao.org/requires-port/download/requires-port-1.0.0.tgz", "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" }, + "reqwest": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/reqwest/-/reqwest-2.0.5.tgz", + "integrity": "sha1-APsVrEkYxBnKgrQ/JMeIguZgOaE=" + }, "resize-observer-polyfill": { "version": "1.5.1", "resolved": "http://registry.npm.taobao.org/resize-observer-polyfill/download/resize-observer-polyfill-1.5.1.tgz", @@ -10834,86 +10836,6 @@ "resolved": "http://registry.npm.taobao.org/shellwords/download/shellwords-0.1.1.tgz", "integrity": "sha1-1rkYHBpI05cyTISHHvvPxz/AZUs=" }, - "showdown": { - "version": "1.9.0", - "resolved": "http://registry.npm.taobao.org/showdown/download/showdown-1.9.0.tgz", - "integrity": "sha1-1J0qC22yG3wulu+FX3s7KijvRvQ=", - "requires": { - "yargs": "^10.0.3" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "http://registry.npm.taobao.org/ansi-regex/download/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" - }, - "camelcase": { - "version": "4.1.0", - "resolved": "http://registry.npm.taobao.org/camelcase/download/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=" - }, - "cliui": { - "version": "4.1.0", - "resolved": "http://registry.npm.taobao.org/cliui/download/cliui-4.1.0.tgz", - "integrity": "sha1-NIQi2+gtgAswIu709qwQvy5NG0k=", - "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" - } - }, - "os-locale": { - "version": "2.1.0", - "resolved": "http://registry.npm.taobao.org/os-locale/download/os-locale-2.1.0.tgz", - "integrity": "sha1-QrwpAKa1uL0XN2yOiCtlr8zyS/I=", - "requires": { - "execa": "^0.7.0", - "lcid": "^1.0.0", - "mem": "^1.1.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "http://registry.npm.taobao.org/strip-ansi/download/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "requires": { - "ansi-regex": "^3.0.0" - } - }, - "which-module": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/which-module/download/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" - }, - "yargs": { - "version": "10.1.2", - "resolved": "http://registry.npm.taobao.org/yargs/download/yargs-10.1.2.tgz", - "integrity": "sha1-RU0HTCsWpRpD4vt4B+T53mnMtcU=", - "requires": { - "cliui": "^4.0.0", - "decamelize": "^1.1.1", - "find-up": "^2.1.0", - "get-caller-file": "^1.0.1", - "os-locale": "^2.0.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1", - "yargs-parser": "^8.1.0" - } - }, - "yargs-parser": { - "version": "8.1.0", - "resolved": "http://registry.npm.taobao.org/yargs-parser/download/yargs-parser-8.1.0.tgz", - "integrity": "sha1-8TdqM7Ziml0GN4KUTacyYx6WaVA=", - "requires": { - "camelcase": "^4.1.0" - } - } - } - }, "signal-exit": { "version": "3.0.2", "resolved": "http://registry.npm.taobao.org/signal-exit/download/signal-exit-3.0.2.tgz", diff --git a/public/react/package.json b/public/react/package.json index e43132877..b06c70e5f 100644 --- a/public/react/package.json +++ b/public/react/package.json @@ -4,6 +4,7 @@ "private": true, "dependencies": { "@icedesign/base": "^0.2.5", + "@monaco-editor/react": "^2.3.0", "@novnc/novnc": "^1.1.0", "antd": "^3.23.2", "array-flatten": "^2.1.2", @@ -28,6 +29,7 @@ "dotenv": "4.0.0", "dotenv-expand": "4.2.0", "echarts": "^4.2.0-rc.2", + "editor.md": "^1.5.0", "eslint": "4.10.0", "eslint-config-react-app": "^2.1.0", "eslint-loader": "1.9.0", @@ -42,6 +44,8 @@ "immutability-helper": "^2.6.6", "install": "^0.12.2", "jest": "20.0.4", + "js-base64": "^2.5.1", + "katex": "^0.11.1", "lodash": "^4.17.5", "loglevel": "^1.6.1", "material-ui": "^1.0.0-beta.40", @@ -49,12 +53,14 @@ "monaco-editor": "^0.15.6", "monaco-editor-webpack-plugin": "^1.7.0", "npm": "^6.10.1", + "numeral": "^2.0.6", "object-assign": "4.1.1", "postcss-flexbugs-fixes": "3.2.0", "postcss-loader": "2.0.8", "promise": "8.0.1", "prop-types": "^15.6.1", "qs": "^6.6.0", + "quill": "^1.3.7", "raf": "3.4.0", "rc-form": "^2.1.7", "rc-pagination": "^1.16.2", @@ -77,11 +83,12 @@ "react-redux": "5.0.7", "react-router": "^4.2.0", "react-router-dom": "^4.2.2", - "react-split-pane": "^0.1.87", + "react-split-pane": "^0.1.89", "react-url-query": "^1.4.0", "redux": "^4.0.0", "redux-thunk": "2.3.0", "rsuite": "^4.0.1", + "sass-loader": "7.3.1", "store": "^2.0.12", "style-loader": "0.19.0", "styled-components": "^4.1.3", @@ -167,7 +174,7 @@ "concat": "^1.0.3", "happypack": "^5.0.1", "node-sass": "^4.12.0", - "sass-loader": "^7.3.1", + "reqwest": "^2.0.5", "webpack-bundle-analyzer": "^3.0.3", "webpack-parallel-uglify-plugin": "^1.1.0" } diff --git a/public/react/public/index.html b/public/react/public/index.html index c79d4d148..aac86e776 100755 --- a/public/react/public/index.html +++ b/public/react/public/index.html @@ -13,6 +13,7 @@ + + diff --git a/public/react/src/App.js b/public/react/src/App.js index 75eb03aad..217848308 100644 --- a/public/react/src/App.js +++ b/public/react/src/App.js @@ -40,11 +40,11 @@ import history from './history'; import {SnackbarHOC} from 'educoder' import {initAxiosInterceptors} from './AppConfig' - - +import { Provider } from 'react-redux'; +import configureStore from './redux/stores/configureStore'; // !!!tpi需要这个来加载css import {TPMIndexHOC} from './modules/tpm/TPMIndexHOC'; - +const store = configureStore(); const theme = createMuiTheme({ palette: { @@ -295,7 +295,22 @@ const Ecs = Loadable({ loading: Loading, }) +// 添加开发者社区 +const Developer = Loadable({ + loader: () => import('./modules/developer'), + loading: Loading +}) +// 开发者编辑模块 +const NewOrEditTask = Loadable({ + loader: () => import('./modules/developer/newOrEditTask'), + loading: Loading +}); +// 学员学习 +const StudentStudy = Loadable({ + loader: () => import('./modules/developer/studentStudy'), + loading: Loading +}); // //个人竞赛报名 // const PersonalCompetit = Loadable({ // loader: () => import('./modules/competition/personal/PersonalCompetit.js'), @@ -462,211 +477,213 @@ class App extends Component { // console.log("appappapp"); // console.log(mygetHelmetapi); return ( - - - - - - - - this.Modifyloginvalue()}> - - - - this.HideAddcoursestypess(i)}/> - - - - - - {/*题库*/} - { - - return () - } - }> - {/*题库*/} - { - - return () - } - }> - {/*/!*众包创新*!/*/} - {/**/} - {/*竞赛*/} - { - - return () - } - }> - - {/*黑客松定制竞赛*/} - { - return( - - ) + + + + + this.Modifyloginvalue()}> + + + + this.HideAddcoursestypess(i)}/> + + + + + + {/*题库*/} + { + + return () + } + }> + {/*题库*/} + { + + return () + } + }> + {/*/!*众包创新*!/*/} + {/**/} + {/*竞赛*/} + { + + return () + } + }> + + {/*黑客松定制竞赛*/} + { + return( + + ) + } } - } - /> + /> - {/*认证*/} - + {/*认证*/} + - {/*403*/} - + {/*403*/} + - + - {/*404*/} - + {/*404*/} + - - { + + { - return () + return () + } } - } - /> - { - - return () + /> + { + + return () + } } - } - /> - - - - { - - return () + /> + + + + { + + return () + } + }> + + { + return () + } + }> + {/* ()*/} + {/*}*/} + {/*/>*/} + { + + return () + } } - }> + /> + { - return () - } - }> - {/* ()*/} - {/*}*/} - {/*/>*/} - { - - return () + /> + + + + + + + + + {/*列表页*/} + + + + {/*实训课程(原实训路径)*/} + + + () + } + > + + {/*课堂*/} + + + {/* + */} + {/* 教学案例 */} + () + }/> + + () } - } - /> - - - - - - - - - - {/*列表页*/} - - - - {/*实训课程(原实训路径)*/} - - - () - } - > - - {/*课堂*/} - - - {/* - */} - {/* 教学案例 */} - () - }/> - - () - } - > - - - {/**/} - {/**/} - {/**/} - {/**/} - {/**/} - {/* ()*/} - {/*}*/} - {/*/>*/} - - () - } - > - () - }/> - () - }/> - - () - } - /> - - - - - - - + > + + + {/**/} + {/**/} + {/**/} + {/**/} + {/**/} + {/* ()*/} + {/*}*/} + {/*/>*/} + + () + } + > + () + }/> + () + }/> + + + + + + + () + } + /> + + + + + + + ); } } diff --git a/public/react/src/constants/index.js b/public/react/src/constants/index.js new file mode 100644 index 000000000..abae13db0 --- /dev/null +++ b/public/react/src/constants/index.js @@ -0,0 +1,117 @@ +/* + * @Description: + * @Author: tangjiang + * @Github: + * @Date: 2019-11-20 23:10:48 + * @LastEditors: tangjiang + * @LastEditTime: 2019-11-28 14:41:42 + */ +const CONST = { + jcLabel: { + name: '任务名称', + language: '编程语言', + description: '描述', + difficult: '难易度', + category: '分类', + openOrNot: '公开程序', + timeLimit: '时间限制' + }, + fontSetting: { + title: '代码格式', + type: 'select', + content: [ + { + text: '字体大小', + value: [ + { + key: 1, + text: '12px', + value: 12 + }, + { + key: 1, + text: '14px', + value: 14 + }, + { + key: 1, + text: '16px', + value: 16 + }, + { + key: 1, + text: '18px', + value: 18 + }, + { + key: 1, + text: '24px', + value: 24 + }, + { + key: 1, + text: '30px', + value: 30 + } + ] + } + ] + }, + opacitySetting: { + title: '代码格式', + type: 'label', + content: [ + { + text: '字体大小', + value: 'CTRL + S' + }, + { + text: '唤出快捷键列表', + value: 'F1/ALT + F1' + }, + { + text: '向左缩进', + value: 'CTRL + [' + }, + { + text: '向右缩进', + value: 'CTRL + ]' + }, + { + text: '跳到匹配的括号', + value: 'CTRL + SHIFT + \\' + }, + { + text: '转到行首', + value: 'HOME' + }, + { + text: '转到行尾', + value: 'END' + } + ] + }, + tagBackground: { + 1: '#52c41a', + 2: '#faad14', + 3: '#f5222d' + }, + diffText: { + 1: '简单', + 2: '中等', + 3: '困难' + }, + reviewResult: { + '-1': '测试用例结果不匹配', + '0': '评测通过', + '1': '', + '2': '评测超时', + '3': '评测pod失败', + '4': '编译失败', + '5': '执行失败' + } +} + + +export default CONST; + diff --git a/public/react/src/modules/courses/competitions/Competitimain/CompetitionsIndex.js b/public/react/src/modules/courses/competitions/Competitimain/CompetitionsIndex.js new file mode 100644 index 000000000..5a341726d --- /dev/null +++ b/public/react/src/modules/courses/competitions/Competitimain/CompetitionsIndex.js @@ -0,0 +1,225 @@ +import React, { Component } from 'react'; +import { Link } from 'react-router-dom'; +import { Menu, Icon, List, Avatar,Row, Col,Tag,Pagination,Alert} from 'antd'; +import {getImageUrl} from 'educoder'; +import axios from 'axios'; +import './Competitionsindex.css'; +import NoneData from "../../courses/coursesPublic/NoneData"; +import LoadingSpin from '../../../common/LoadingSpin'; + +class CompetitionsIndex extends Component{ + constructor(props) { + super(props) + this.state={ + current: 'all', + datas:undefined, + page:1, + category:undefined + + } + } + + componentDidMount(){ + window.document.title = '竞赛'; + let{category,page}=this.state; + this.getdata(category,page) + } + + getdata=(category,page)=>{ + const Url =`/competitions.json`; + axios.get(Url,{params:{ + category:category, + page:page, + per_page:15, + } + }).then((response) => { + if(response.status===200){ + this.setState({ + datas:response.data.competitions, + count:response.data.count, + }) + } + }) + .catch(function (error) { + console.log(error); + }); + } + + + handleClick = e => { + this.setState({ + current: e.key, + datas:undefined + }); + let{category,page}=this.state; + this.getdata(e.key,page) + }; + + PaginationCourse=(pageNumber)=>{ + let {category}=this.state; + this.setState({ + page: pageNumber, + }) + this.getdata(category,pageNumber); + } + + render() { + let {datas,page,count}=this.state; + + + return ( +
+
+
+
+ +
+
+
+
+
+ +
+
+ + + 全部 + + + 即将发布 + + + 进行中 + + + 往期比赛 + + +
+
+ +
+ + {datas===undefined?"":datas.length===0?"": ( + + +
+ {item.competition_status==="nearly_published"? + item.permission.editable==true?"":
即将发布 敬请期待
:""} + {/*
即将发布 敬请期待
*/} + {/*{item.description===null||item.description===undefined||item.description===""?:""}*/} + + 竞赛时间: {item.start_time}~{item.end_time}, + 报名截止时间:{item.enroll_end_time}, + ]} + extra={ +
+ + + +
奖金
+ + +
浏览数
+ + +
报名数
+ +
+ + + +
¥{item.bonus}
+ + +
{item.competition_status==="nearly_published"?"--":item.visits_count}
+ + +
{item.competition_status==="nearly_published"?"--":item.member_count}
+ +
+
+ } + > + +
{item.name}{item.sub_title===null?"":`——${item.sub_title}`} + {/*{item.sub_title===null?"":*/} + {/*{item.sub_title}}*/} + {/**/} + } + /> + {item.description} + +
+ + + ) + + } + />} + + {datas===undefined?"":count===undefined?"":count >15 ?
+ + + +
:""} + + { + datas===undefined?:datas && datas.length===0? :"" + } +
+ +
+ +
+
+
+ ) + } +} +export default CompetitionsIndex; diff --git a/public/react/src/modules/courses/competitions/Competitimain/Competitionsindex.css b/public/react/src/modules/courses/competitions/Competitimain/Competitionsindex.css new file mode 100644 index 000000000..cddb1492b --- /dev/null +++ b/public/react/src/modules/courses/competitions/Competitimain/Competitionsindex.css @@ -0,0 +1,163 @@ +.teamsLayout{background: transparent !important;} + +.competitionstitle{ + height:50px !important; + border-radius: 6px; + background: #fff; + display: flex; + justify-content: center; +} + +.competitionstitle2{ + height:50px !important; + margin-left: 30px !important; + background: #fff; + width: 1200px; +} +.CompetitionsList{ + position: relative; + /*max-height: 210px;*/ +} +.competitonimg{ + position: absolute; + right: -5px; + width: 80px; + top: 20px; +} + +.ant-menu-horizontal { + border-bottom:none !important; +} + + +.competitionsvalue{ + font-size: 16px; + font-family: PingFangSC-Medium,PingFangSC; + font-weight: 500; +} + +.competitionmr50 { + margin-right: 50px !important; +} + +.CompetitionsIndex .ant-list-item{ + background: #fff !important; + margin-top: 20px; + border: none !important; +} + +.CompetitionsIndex .ant-list-item{ + padding:25px; +} + +.CompetitionsIndex .ant-list-item-meta-title{ + height:28px; + font-size:28px; + font-family:PingFangSC-Regular,PingFangSC; + font-weight:400; + color:rgba(5,16,26,1); + line-height:28px; +} + +.CompetitionsIndex .ant-list-vertical .ant-list-item-meta{ + margin-bottom: 20px !important; +} + +.CompetitionsIndex .ant-list-vertical .ant-list-item-action { + margin-top: 20px; + margin-left: auto; +} + +.CompetitionsIndex .ant-list-item-action-split{ + display: none !important; +} + +.CompetitionsIndexdadels{ + font-family: PingFangSC-Regular,PingFangSC; + font-weight: 400; + color: #777777; + margin-bottom: 14px; + text-align: center; +} + +.CompetitionsIndexbottomvalue{ + font-size: 24px; + font-family: ArialMT; + color: rgba(5,16,26,1); + text-align: center; +} + +.CompetitionsIndex .gutter-row{ + /*margin-right:20px;*/ + width: 33%; +} + +.pt50{ + padding-top: 50px; +} + +.competitionstitles{ + max-width: 789px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + display: inline-block; + margin-right: 15px; + color:#000 !important; +} + +.competitionsrelative{ + position: absolute; + top: 28px; +} + +.CompetitionsList:hover{ + /*box-shadow: 0 2px 6px rgba(51,51,51,.09);*/ + box-shadow:3px 4px 10px 2px rgba(229,229,229,0.5); + opacity: 1; + border-radius: 2px; +} +.endedfont{ + color:#000 !important; +} +.CompetitionsListzhezhao{ + position: absolute; + top: 0px; + left: 0px; + width: 1206px; + height: 100%; + z-index: 10000; + display: none; + background: rgba(0,0,0,0.33); + text-align: center; + color: #fff; + font-size: 22px; + + align-items: center; + justify-content: space-around; + flex-direction: column; +} +.CompetitionsList:hover .CompetitionsListzhezhao{ + display: block; + display: flex; +} +.competitionstitlesshou:hover a{ + cursor: pointer; + color: #1c91e8 !important; +} + +.competitionstitlesshou{ + cursor: pointer; +} + + +.Competitionshead{ + background-color: #2d28ba !important; + background-position: center !important; + background-position: 50% !important; + background-repeat: no-repeat !important; +} + +.span666{ + color:#666666 !important; +} \ No newline at end of file diff --git a/public/react/src/modules/courses/competitions/Competition_teams/Competitionteams.css b/public/react/src/modules/courses/competitions/Competition_teams/Competitionteams.css new file mode 100644 index 000000000..af1f40aba --- /dev/null +++ b/public/react/src/modules/courses/competitions/Competition_teams/Competitionteams.css @@ -0,0 +1,53 @@ +.teamsLayout{background: transparent !important;} +.teamsLayout .teamsLayoutitle{ + font-size:18px; + font-family:PingFangSC-Semibold,PingFang SC; + font-weight:600; + color:rgba(5,16,26,1); + line-height:25px; + margin-top: 10px; + margin-bottom: 10px; +} +.teamsLayoutTable .ant-table-bordered .ant-table-thead > tr > th, .ant-table-bordered .ant-table-tbody > tr > td { + border-right: 1px solid transparent !important; +} + +.teamsLayoutTable .ant-table-body .ant-table-thead > tr> th:nth-last-child(1){ + border-right: 1px solid #e8e8e8 !important; +} + +.teamsLayoutTable .ant-table-body .ant-table-tbody > tr> td:nth-last-child(1){ + border-right: 1px solid #e8e8e8 !important; +} + +.teamsLayoutTable .ant-table-bordered .ant-table-thead > tr > th{ + background:#EEEEEE; + font-size: 14px; + font-family: PingFangSC-Regular,PingFang SC; + font-weight: 400; + color: rgba(102,102,102,1); + line-height: 20px; +} + +.teamsLayoutTable .ant-table-bordered .ant-table-tbody > tr > th{ + background:#EEEEEE; + font-size:14px; + font-family:PingFangSC-Regular,PingFang SC; + font-weight:400; + color:rgba(5,16,26,1); + line-height:20px; +} + +.teamsLayout .mt40{ + margin-top: 40px !important; +} + +.teamsLayoutheji{ + color: #878787; + font-size: 16px; +} + +.teamsLayoucolor-orange { + color: #ff6800!important; + font-size: 16px; +} \ No newline at end of file diff --git a/public/react/src/modules/courses/competitions/Competition_teams/Competitionteams.js b/public/react/src/modules/courses/competitions/Competition_teams/Competitionteams.js new file mode 100644 index 000000000..be6c2e68d --- /dev/null +++ b/public/react/src/modules/courses/competitions/Competition_teams/Competitionteams.js @@ -0,0 +1,267 @@ +import React, { Component } from 'react'; +import { Breadcrumb,Layout,Table, Divider, Tag,Badge,Tooltip} from 'antd'; +import { Link } from 'react-router-dom'; +import axios from 'axios'; + + +import './Competitionteams.css'; +const { Content } = Layout; + +class Competitionteams extends Component{ + constructor(props) { + super(props) + this.state={ + shixundata: undefined, + coursedata:undefined, + } + } + + componentDidMount(){ + window.document.title = '竞赛'; + if(this.props.match.params.identifier!=null){ + let url=`/competitions/${this.props.match.params.identifier}/common_header.json`; + axios.get(url).then((response) => { + if(response.status===200){ + this.setState({ + data:response.data, + }) + } + }).catch((error) => { + console.log(error) + }) + } + + this.getshixundata(); + this.getcoursedata(); + } + + getshixundata=()=>{ + + const Url =`/competitions/${this.props.match.params.identifier}/competition_teams/${this.props.match.params.competition_team_id}/shixun_detail.json`; + axios.get(Url).then((response) => { + if(response.status===200){ + // let data={ + // shixuns: [ + // { + // creator: "黄井泉", // 创建者 + // shixun_name: "单链表的学习与应用(I)", // 实训名称 + // shixun_identifier: "mnf6b7z3", + // forked: false, // false:原创 + // myshixuns_count: 179, // 学习人数 + // forked_myshixun_count: 0, // 被fork发布的学习人数 + // valid_count: 82, // 有效作品数 + // score: 1320 // 应用值 + // } + // ], + // shixun_count: 1, // 实训总计 + // total_myshixun_count: 179, // 学习人数总计 + // total_forked_myshixun_count: 0, // 被fork发布的学习人数总计 + // total_valid_count: 82, // 有效作品数总计 + // total_shixun_score: 1320 // 应用值总计 + // } + let data=response.data; + + let newarr=data.shixuns; + + let newobj={ + creator:"合计:", + shixun_name:data.shixun_count, + myshixuns_count:data.total_myshixun_count, + forked_myshixun_count:data.total_forked_myshixun_count, + valid_count:data.total_valid_count, + score:data.total_shixun_score + } + newarr.push(newobj) + + this.setState({ + shixundata:newarr + }) + + + } + }) + .catch(function (error) { + console.log(error); + }); + + + + + } + + getcoursedata=()=>{ + const Url =`/competitions/${this.props.match.params.identifier}/competition_teams/${this.props.match.params.competition_team_id}/course_detail.json`; + + axios.get(Url).then((response) => { + if(response.status===200){ + // let data={ + // courses: [ + // { + // creator: "周海芳", // 创建者 + // creator_login: "Nancy", // login + // course_name: "大学计算机基础2018年秋季", + // course_id: 1502, + // students_count: 122, // 学生数量 + // shixun_homework_count: 8, // 发布的实训作业数量 + // valid_count: 977, // 有效作品数 + // score: 29810 // 应用值 + // } + // ], + // total_course_count: 1, // 课堂总计 + // total_students_count: 122, // 学生数总计 + // total_shixun_homework_count: 8, // 实训作业数总计 + // total_valid_count: 977, // 有效作品数总计 + // total_course_score: 29810 // 应用值总计 + // } + + let data=response.data; + + let newarr=data.courses; + + let newobj={ + creator:"合计:", + course_name:data.total_course_count, + students_count:data.total_students_count, + shixun_homework_count:data.total_shixun_homework_count, + valid_count:data.total_valid_count, + score:data.total_course_score + } + newarr.push(newobj) + + this.setState({ + coursedata:newarr + }) + + } + }) + .catch(function (error) { + console.log(error); + }); + + + } + + render() { + let {data}=this.state; + const shixuncolumns = [ + { + title: '创建者', + dataIndex: 'creator', + key: 'creator', + render: (text, record) =>
{text}
, + }, + { + title: '名称', + dataIndex: 'shixun_name', + key: 'shixun_name', + render: (text, record) => +
{text}{record.forked===true?:""}
, + }, + { + title: '学习人数', + dataIndex: 'myshixuns_count', + key: 'myshixuns_count', + render: (text, record) =>
{text}
, + }, + { + title: '被fork发布的学习人数', + dataIndex: 'forked_myshixun_count', + key: 'forked_myshixun_count', + render: (text, record) => + +
{text}
+
, + }, + { + title: '有效作品数', + dataIndex: 'valid_count', + key: 'valid_count', + render: (text, record) => + +
{text}
+
, + }, + { + title: '应用值', + dataIndex: 'score', + key: 'score', + render: (text, record) =>
{text}
, + }, + ]; + + const coursecolumns = [ + { + title: '创建者', + dataIndex: 'creator', + key: 'creator', + render: (text, record) =>
{text}
, + }, + { + title: '名称', + dataIndex: 'course_name', + key: 'course_name', + render: (text, record) =>
{text}
, + }, + { + title: '学生数量', + dataIndex: 'students_count', + key: 'students_count', + render: (text, record) =>
{text}
, + }, + { + title: '发布的实训作业数量', + dataIndex: 'shixun_homework_count', + key: 'shixun_homework_count', + render: (text, record) => +
{text}
+ , + }, + { + title: '有效作品数', + dataIndex: 'valid_count', + key: 'valid_count', + render: (text, record) => + +
{text}
+
, + }, + { + title: '应用值', + dataIndex: 'score', + key: 'score', + render: (text, record) =>
{text}
, + }, + ]; + + + // console.log(this.state.shixundata) + return ( + +
+ + {data&&data.name} + 报名 + 战队详情 + + + + + 实训项目 + + + + 翻转课堂 + +
+ + + + + + + + + ) + } +} +export default Competitionteams; diff --git a/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommon.css b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommon.css new file mode 100644 index 000000000..984498203 --- /dev/null +++ b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommon.css @@ -0,0 +1,438 @@ +.teamsLayout{background: transparent !important;} + +.teamsLayout .ant-layout-sider{ + background: transparent !important; + flex: 0 0 180px !important; + max-width: 180px !important; + min-width: 180px !important; + width: 180px !important; +} +.teamsLayout .teamsLayoutitle{ + font-size:18px; + font-family:PingFangSC-Semibold,PingFang SC; + font-weight:600; + color:rgba(5,16,26,1); + line-height:25px; + margin-top: 10px; + margin-bottom: 10px; +} +.teamsLayoutTable .ant-table-bordered .ant-table-thead > tr > th, .ant-table-bordered .ant-table-tbody > tr > td { + border-right: 1px solid transparent !important; +} + +.teamsLayoutTable .ant-table-body .ant-table-thead > tr> th:nth-last-child(1){ + border-right: 1px solid #e8e8e8 !important; +} + +.teamsLayoutTable .ant-table-body .ant-table-tbody > tr> td:nth-last-child(1){ + border-right: 1px solid #e8e8e8 !important; +} + +.teamsLayoutTable .ant-table-bordered .ant-table-thead > tr > th{ + background:#EEEEEE; + font-size: 14px; + font-family: PingFangSC-Regular,PingFang SC; + font-weight: 400; + color: rgba(102,102,102,1); + line-height: 20px; +} + +.teamsLayoutTable .ant-table-bordered .ant-table-tbody > tr > th{ + background:#EEEEEE; + font-size:14px; + font-family:PingFangSC-Regular,PingFang SC; + font-weight:400; + color:rgba(5,16,26,1); + line-height:20px; +} + +.teamsLayout .mt40{ + margin-top: 40px !important; +} + +.teamsLayoutheji{ + color: #878787; + font-size: 16px; +} + +.teamsLayoucolor-orange { + color: #ff6800 !important; + font-size: 16px; +} + +.CompetitionCommonbanner{ + padding: 20px; + background:rgba(255,255,255,1); + box-shadow:3px 2px 12px 2px rgba(0,0,0,0.05); + position: relative; +} + +.CompetitionCommonbannerfont{ + height:100%; + width: 365px !important; + line-height: 34px; +} + +.CompetitionCommonbannerfont .competitionbannerdiv:nth-child(1){ + max-height:100px; + font-size:25px; + font-weight:400; + color:rgba(5,16,26,1); + line-height: 30px; +} + +.CompetitionCommonbannerfont .competitionbannerdiv:nth-child(2){ + max-height: 70px; + font-size:16px; + font-weight:400; + /*color:rgba(155,155,155,1);*/ + color:#05101A; +} + +.CompetitionCommonbannerfont .competitionbannerdiv:nth-child(3){ + max-height: 70px; + font-size: 16px; + font-weight: 400; + /*color: rgba(155,155,155,1);*/ + color:#05101A; +} + + + +.Competitioncolor9b{ + color: #9B9B9B; +} + +.Competitioncolor77{ + color: #777777; + font-size: 14px; +} + +.Competitioncolor516{ + font-size:24px; + color:rgba(5,16,26,1); +} + +.Competitionfontsize22{ + font-size:22px; + font-weight:500; + color:rgba(255,255,255,1); +} + +.Competitionfontsize16{ + font-size: 16px; + font-weight: 400; + color: rgba(102,102,102,1); +} + +.ant-layout-sider { + position: relative; + min-width: 0; + background: #001529; + -webkit-transition: all 0.2s; + -o-transition: all 0.2s; + transition: all 0.2s; +} + +.CompetitionMenu .ant-menu-item::after { + left: 0px !important; + right: auto; + border-right: 5px solid #4CACFF; +} + +.CompetitionMenu .ant-menu-item{ + height: 30px; + line-height: 30px; + background:none; + color:#666; +} + +.ant-menu:not(.ant-menu-horizontal) .ant-menu-item-selected { + background-color: transparent; +} + +.CompetitionMenu .ant-menu-item:not(:last-child){ + margin-bottom: 40px; + background: transparent; + color:#666; +} + +.CompetitionMenu .ant-menu-item{ + font-size: 18px; +} + +.CompetitionMenu .ant-menu-item-selected { + color: rgba(76,172,255,1) !important; +} + +.CompetitionMenu{ + width: 145px; + background: #fff; + border: 1px solid rgba(239,239,239,1); + padding-top: 20px; + padding-bottom: 40px !important; +} + +.teamsLayoutleft{ + background: transparent !important; +} + +.Competitioncharts{ + font-size: 24px; + color: rgba(5,16,26,1); +} +.Competitionfirst{ + width:233px; + height:298px; + background:rgba(250,250,250,1); + box-shadow:0px 2px 8px 2px rgba(255,134,34,0.5); + border-radius:5px; +} +.Competitionsecondary{ + width:234px; + height:298px; + background:rgba(250,250,250,1); + box-shadow:0px 3px 5px 0px rgba(254,190,154,1); + border-radius:5px; +} + +.Competitionthird{ + width: 234px; + height: 298px; + background: rgba(250,250,250,1); + box-shadow: 0px 4px 5px 0px rgba(200,200,202,1); + border-radius: 5px; +} + +.Competition399{ + height:399px; +} + +.Competitiontransparent table{ + background: transparent; +} + +.Commonimg{ + position: absolute; + right: -5px; + width:93px; + top: 10px; +} + +.Competitionthirdbox{ + width:234px; + height:167px; + background:rgba(223,223,225,1); + position: relative; +} + +.Competitionfirstbox{ + width:233px; + height:167px; + background:rgba(255,231,160,1); + position: relative; +} + +.Competitionsecondarybox{ + width:234px; + height:167px; + background:rgba(253,230,217,1); + position: relative; +} + +.rankingimg{ + width: 60px; + height: 60px; + border-radius: 50% !important; + box-shadow: 0px 0px 12px rgba(0,0,0,0.2); + border: 2px solid #459BE5; +} + +.Competitioncenter{ + text-align: center; + padding-top: 20px; +} + + +.jinshaifont{ + font-size: 16px; + color: rgba(5,16,26,1); + margin-top: 13px !important; +} + +.Competitionthird .ant-card-body { + padding: 12px; + zoom: 1; +} + +/*.Competitionthird .ant-card-meta-title{*/ + /*margin-bottom: 0px !important;*/ +/*}*/ + +.Competitionfirst .ant-card-body { + padding: 12px; + zoom: 1; +} + +.Competitionsecondary .ant-card-body { + padding: 12px; + zoom: 1; +} + +.center{ + text-align: center; +} + +.rankfonttop{ + font-size:14px; + color:rgba(102,102,102,1); +} + +.rankfontmid{ + font-size:18px; + color:rgba(102,102,102,1); +} + +.rankfontbottom{ + font-size:26px; + color:rgba(165,91,41,1); + text-align: center; +} + +.rankfontbottoms{ + font-size:28px; + color:rgba(165,91,41,1); + text-align: center; +} + +.Competitionuserimg{ + width: 64px; + height: 63px; + border-radius: 50%; + border: 2px solid #459BE5; +} + +.CompetitionsListzhezhao{ + position: absolute; + top: 0px; + left: 0px; + width: 1206px; + height: 100%; + z-index: 10000; + display: none; + background: rgba(0,0,0,0.33); + text-align: center; + color: #fff; + font-size: 22px; + +} + +.relative{position: relative;} + +.relative:hover .CompetitionsListzhezhao{ + display: block; + display: flex; + align-items: center; + justify-content: space-around; + flex-direction: column; +} + +.image_urlbox{ + width: 790px; + height: 340px; +} + +.CompetitionContents{ + background: #fff !important; + padding: 40px; + box-shadow: 3px 2px 12px 2px rgba(0,0,0,0.05); + border: 1px solid rgba(239,239,239,1); +} + +.rankbeicenter{ + text-align: center; +} +.rankbei{ + font-size: 16px; + color: rgba(119,119,119,1); + +} + +.youranklist{ + background: rgba(226,241,255,1); + line-height: 50px; + text-align: center; + padding-left: 20px; +} + +.ranknames{ + font-size: 16px; + color: rgba(62,62,62,1); +} + +.ranknameslast{ + font-size:16px; + color:rgba(12,158,254,1); +} + +.textleft{ + text-align: left; +} + +.textright{ + text-align: right; +} + +.userranksclass{ + text-align: left; + width: 18%; + padding-left: 12px; + margin-right: 28px; +} + +.Commonimgbox{ + width: 800px !important; +} + +.CompetitionCommonbannerfont{ + width: 350px !important; + margin-left:10px; +} + +.color000{ + color: #000; +} + +.cursorpointer{ + cursor: pointer; +} + +.rankfonttop{ + overflow:hidden; + text-overflow:ellipsis; + white-space:nowrap +} + +.usernamebox{ + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + cursor: default; + max-width: 100px; + display: inherit; +} + +.competimgabsolute{ + position: absolute; + left: 72px; + bottom: -10px; +} +.competimgabsolute .ant-badge-count{ + box-shadow: none !important; +} + +.competimgabsoluteijmg{ + position: absolute; + left: -11px; + bottom: 0px; +} \ No newline at end of file diff --git a/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommon.js b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommon.js new file mode 100755 index 000000000..b2ac34fe1 --- /dev/null +++ b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommon.js @@ -0,0 +1,548 @@ +import React, { Component } from 'react'; +import { Breadcrumb,Layout,Table, Divider, Tag,Badge,Row, Col,Button, Menu, Icon} from 'antd'; +import { Link } from 'react-router-dom'; +import axios from 'axios'; +import {markdownToHTML,getImageUrl} from 'educoder'; +import CompetitionContents from './CompetitionCommonChild/CompetitionContents'; +import CompetitionContentsChart from './CompetitionCommonChild/CompetitionContentsChart'; +import CompetitionContentsMd from './CompetitionCommonChild/CompetitionContentsMd'; +import CompetitionContentspdf from './CompetitionCommonChild/CompetitionContentspdf'; + +import './CompetitionCommon.css'; + +const {Sider } = Layout; + +class CompetitionCommon extends Component{ + constructor(props) { + super(props) + this.state={ + data: undefined, + bannerdata: undefined, + module_type: undefined, + mdContentdata: undefined, + chart_rules: undefined, + Competitionedittype: false, + chartdata: undefined, + has_url: false, + signupdata: undefined + } + } + + componentDidMount(){ + window.document.title = '竞赛'; + if(this.props.match.params.identifier!=null){ + this.getbannerdata(); + // this.setState({ + // thiskeys:this.props.location.search.replace('?menu=', '') + // }) + // let url=`/competitions/${this.props.match.params.identifier}.json`; + // axios.get(url).then((response) => { + // if(response.status===200){ + // this.setState({ + // bannerdata:response.data + // }) + // } + // }).catch((error) => { + // //console.log(error) + // }) + } + } + + componentDidUpdate = (prevProps) => { + if (prevProps.user != this.props.user) { + + //console.log("componentDidUpdatess"); + //console.log(this.props.user); + if (this.props.user && this.props.user.login != "") { + const zul = `/competitions/${this.props.match.params.identifier}/competition_staff.json`; + axios.get((zul)).then((result) => { + if (result) { + if (result.data) { + this.setState({ + signupdata: result.data + }) + } + } + }).catch((error) => { + ////console.log(error); + }) + } + } + + } + //获取头部信息 + getbannerdata=()=>{ + // let menuid=this.props.location.search.replace('?menu=', ''); + let query=this.props.location&&this.props.location.search; + const types = query.split('&') + const menuid = types[0].split('?menu=') + let url=`/competitions/${this.props.match.params.identifier}/common_header.json`; + axios.get(url).then((response) => { + if(response.status===200){ + this.setState({ + data: response.data, + thiskeys: menuid[1] === undefined || menuid[1] === "" ? response.data.competition_modules[0].id : menuid[1], + mode: response.data.mode + }) + if(menuid[1]===undefined||menuid[1]===""){ + this.getrightdata( + response.data.competition_modules[0].id, + response.data.competition_modules[0].module_type, + response.data.competition_modules[0].module_url, + response.data.competition_modules[0].has_url + ) + }else{ + let newlist=response.data.competition_modules; + newlist.map((item,key)=>{ + if(`${item.id}`===`${menuid[1]}`){ + this.getrightdata( + item.id, + item.module_type, + item.module_url, + item.has_url + ) + } + }) + } + } + }).catch((error) => { + //console.log(error) + }) + + //this.props.user 有可能为空 + + if (this.props.user && this.props.user.login != "") { + const zul = `/competitions/${this.props.match.params.identifier}/competition_staff.json`; + axios.get((zul)).then((result) => { + if (result) { + if (result.data) { + this.setState({ + signupdata: result.data + }) + } + } + }).catch((error) => { + ////console.log(error); + }) + } + + } + + getrightdatas=(e)=>{ + let keys = parseInt(e.key); + this.getlistdata(keys) + this.props.history.replace(`?menu=${keys}`); + } + + getlistdata=(keys,listkey)=>{ + + let{data}=this.state; + this.setState({ + thiskeys:keys + }) + data&&data.competition_modules.map((item,key)=>{ + if(item.module_type!="enroll") { + if (keys === item.id) { + this.getrightdata(item.id, item.module_type, item.module_url, item.has_url, listkey) + return + } + } + }) + } + + getnewchartdata=(typeid,tabkey)=>{ + if(typeid==="chart"){ + let url=`/competitions/${this.props.match.params.identifier}/chart_rules.json`; + axios.get(url) + .then((response) => { + if(response.status===200){ + this.setState({ + chart_rules:response.data, + tabkey: tabkey === undefined ? response.data.stages[0].id === null ? "0" : `${response.data.stages[0].id}` : tabkey + }) + + + } + }).catch((error) => { + //console.log(error) + }) + } + } + + getrightdata=(id,typeid,module_url,has_url,listkey)=>{ + + // if(typeid==="enroll"){ + // this.props.history.replace(`/competitions/${this.props.match.params.identifier}/enroll`); + // return + // } + + this.getnewchartdata(typeid, listkey) + + if(has_url===false){ + let url=`${module_url}`; + axios.get(url).then((response) => { + if(response.status===200){ + + if(typeid==="chart"){ + this.setState({ + chartdata:response.data + }) + }else{ + this.setState({ + mdContentdata:response.data + }) + } + + } + }).catch((error) => { + //console.log(error) + }) + }else{ + if (module_url.substring(0, 7) == 'http://' || module_url.substring(0, 8) == 'https://') { + // window.location.href= module_url + window.open(module_url) + }else{ + window.open(`https://${module_url}`) + // window.location.href=; + } + return + } + + this.setState({ + module_id:id, + module_type:typeid, + has_url:has_url + }) + + } + + Competitionedit=()=>{ + this.setState({ + Competitionedittype: true + }) + } + + hideCompetitionedit=()=>{ + this.setState({ + Competitionedittype:false + }) + + } + newgotocourse=(url)=>{ + if(this.props.checkIfLogin()===false){ + this.props.showLoginDialog() + return + } + if(this.props.checkIfProfileCompleted()===false){ + this.props.showProfileCompleteDialog() + return + } + window.open(url); + + } + + gotocourse=(url)=>{ + if(this.props.checkIfLogin()===false){ + this.props.showLoginDialog() + return + } + if(this.props.checkIfProfileCompleted()===false){ + this.props.showProfileCompleteDialog() + return + } + + if(url===undefined){ + let {data,signupdata}=this.state; + // if(signupdata.enrolled===true){ + // this.props.history.replace(`/courses/${data.course_id}`); + // }else{ } + + if (data.member_of_course === true) { + // this.props.history.replace(`/courses/${data.course_id}`); + window.open(`/courses/${data.course_id}`) + } else { + // 以学生身份调用加入课堂 进入课堂首页 + let url = "/courses/apply_to_join_course.json" + axios.post(url, { + invite_code: data.invite_code, + student: 1 + } + ).then((response) => { + if (response.data.status === 0) { + // this.props.history.replace(); + this.getbannerdata() + window.open(`/courses/${data.course_id}`); + + } + }) + + } + + }else{ + + if (url === "personal") { + let urls = `/competitions/${this.props.match.params.identifier}/enroll`; + this.Personalregistration(urls) + } else { + window.open(url); + } + + } + } + + + Personalregistration = (urls) => { + + let {signupdata} = this.state; + + if (signupdata.enroll_ended === true) { + //已截止 + this.props.showNotification(`报名已截止`); + return; + } + if (signupdata.enrolled === true) { + this.props.showNotification(`你已经报名,不能重复报名!`); + return; + } + const url = `/competitions/${this.props.match.params.identifier}/competition_teams.json`; + axios.post(url).then((response) => { + if (response) { + if (response.data) { + this.props.showNotification(`报名成功,预祝您夺得桂冠!`); + // this.props.history.replace(urls); + this.getbannerdata() + window.open(urls) + } + } + }).catch((error) => { + + }); + } + + + Competitioncallback=(key)=>{ + this.setState({ + tabkey:key + }) + let url=`/competitions/${this.props.match.params.identifier}/charts.json`; + axios.get(url,{params:{ + stage_id:key===0||key===null?undefined:key + }}).then((response) => { + if(response.status===200){ + this.setState({ + chartdata:response.data + }) + } + }).catch((error) => { + //console.log(error) + }) + + } + + + render() { + let {data, module_type, Competitionedittype, signupdata} = this.state; + + return ( + data===undefined?"":
+ + + 在线竞赛 + {data && data.name} + + +
+ + + {data.competition_status === "nearly_published" ? + data && data.permission.editable === true ? "" : +
即将发布 敬请期待
: ""} + +
+ + + + + 15 ? "competitionbannerdiv mt30" : "competitionbannerdiv mt30"}>{data && data.name} + + + 竞赛时间:{data && data.start_time}~{data && data.end_time} + {/**/} + + + + + +
奖金
+ + +
浏览数
+ + +
报名数
+ + + + + +
¥{data && data.bonus}
+ + +
{data.competition_status === "nearly_published" ? "--" : data && data.visits_count}
+ + + + {data.competition_status === "ended" ? +
this.gotocourse(`/competitions/${this.props.match.params.identifier}/enroll`)} + onClick={ data.mode === 2 ?data.member_of_course==true?() => this.newgotocourse(`/courses/${data.course_id}`):"":() => this.newgotocourse(`/competitions/${this.props.match.params.identifier}/enroll`)} + >{data && data.member_count}
+ :data.competition_status === "nearly_published" ? +
this.gotocourse(`/competitions/${this.props.match.params.identifier}/enroll`)} + >{"--"}
: + data.competition_status === "progressing" ? + data.mode === 2 ? +
this.gotocourse()}>{data && data.member_count}
: signupdata && signupdata.personal === true ? +
this.gotocourse("personal")}>{data && data.member_count}
:
this.gotocourse(`/competitions/${this.props.match.params.identifier}/enroll`)}>{data && data.member_count}
+ :""} + + + + + + {data.competition_status === "ended" ? : } + + {data.competition_status === "ended" ? + : data.enroll_end === true ? + : + data.competition_status === "progressing" ? + :""} + + {data && data.enroll_end_time === null ? "" : `报名截止时间:${data && data.enroll_end_time}`} + + + + + + + this.getrightdatas(e)}> + {data && data.competition_modules.map((item, key) => { + if (item.module_type != "enroll") { + return ( + + {/*{item.has_url===false?this.getrightdata(item.id,item.module_type,item.module_url,item.has_url)}*/} + {/*>{item.name}:this.getrightdata(item.id,item.module_type)}*/} + {/*>{item.name}}*/} + {item.name} + + ) + } + })} + + + {/*this.isdownloadpdf(e)}>*/} + {/**/} + {/*证书下载*/} + {/**/} + {/**/} + + + {module_type === "certificate" ? "" : + {this.state.module_type === "chart" ? Competitionedittype === false ? this.Competitionedit()} + Competitioncallback={(e) => this.Competitioncallback(e)} + /> : "" : Competitionedittype === false ? this.Competitionedit()} + {...this.props} + {...this.state} + /> : ""} + {/**/} + {Competitionedittype === true ? this.hideCompetitionedit()} + getlistdata={(keys, listkey) => this.getlistdata(keys, listkey)} + Competitioncallback={(e) => this.Competitioncallback(e)} + {...this.props} + {...this.state} + /> : ""} + } + + {module_type === "certificate" ? + + : ""} + + + + + ) + } +} +export default CompetitionCommon; diff --git a/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContents.js b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContents.js new file mode 100644 index 000000000..62c7140cd --- /dev/null +++ b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContents.js @@ -0,0 +1,45 @@ +import React, { Component } from 'react'; +import {Button,Layout} from 'antd'; +import axios from 'axios'; +import {markdownToHTML,getImageUrl,AttachmentList} from 'educoder'; + + +const { Header, Footer, Sider, Content } = Layout; +class CompetitionContents extends Component{ + constructor(props) { + super(props) + this.state={ + hash:undefined + } + } + + componentDidMount(){ + window.document.title = '竞赛'; + this.props.MdifHasAnchorJustScorll(); + } + + render() { + let {mdContentdata, data} = this.props; + //mdhash滚动 + this.props.MdifHasAnchorJustScorll(); + return ( + +
+ {data && data.permission.editable === true ? this.props.Competitionedittype === false ? this.props.has_url === false ? + :"":"":""} +
+ + + +
+ +
+
+
+ + ) + } +} +export default CompetitionContents; diff --git a/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentsChart.js b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentsChart.js new file mode 100644 index 000000000..420f83ff1 --- /dev/null +++ b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentsChart.js @@ -0,0 +1,423 @@ +import React, { Component } from 'react'; +import {Button,Layout,Tabs,Icon, Card, Avatar, Row, Col ,Table,Badge} from 'antd'; +import {markdownToHTML,getImageUrl} from 'educoder'; +import axios from 'axios'; + +const { Content } = Layout; +const { TabPane } = Tabs; +const { Meta } = Card; + +class CompetitionContents extends Component{ + constructor(props) { + super(props) + this.state={ + personal:undefined + } + } + + componentDidMount(){ + window.document.title = '竞赛'; + let url=`/competitions/${this.props.match.params.identifier}/competition_staff.json`; + axios.get(url) + .then((response) => { + if(response.status===200){ + console.log(response) + this.setState({ + personal:response.data.personal + }) + } + }).catch((error) => { + console.log(error) + }) + this.props.MdifHasAnchorJustScorll(); + } + + derivefun=(url)=>{ + axios.get(url).then((response)=>{ + if(response === undefined){ + return + } + if(response.data.status&&response.data.status===-1){ + this.props.showNotification(response.data.message); + }else if(response.data.status&&response.data.status===-2){ + // if(response.data.message === "100"){ + // // 已超出文件导出的上限数量(100 ),建议: + // + // this.setState({ + // DownloadType:true, + // DownloadMessageval:100 + // }) + // }else { + // //因附件资料超过500M + // this.setState({ + // DownloadType:true, + // DownloadMessageval:500 + // }) + // } + this.props.showNotification(response.data.message); + }else { + // this.props.showNotification(`正在下载中`); + // window.open("/api"+url, '_blank'); + this.props.slowDownload(url); + } + }).catch((error) => { + console.log(error) + }); + } + render() { + this.props.MdifHasAnchorJustScorll(); + const operations =
+ + +
+ const columns = [ + { + title: 'usersum', + dataIndex: 'usersum', + key: 'name', + render: text => {text}, + }, + { + title: 'userimg', + dataIndex: 'userimg', + key: 'userimg', + render: (text, record) =>( + +
+ +
+
+
), + }, + { + title: 'username', + dataIndex: 'username', + key: 'username', + render: text => {text}, + }, + { + title: 'school', + dataIndex: 'school', + key: 'school', + render: text => {text}, + }, + { + title: 'spendtime', + dataIndex: 'spendtime', + key: 'spendtime', + render: text => {text}, + }, + { + title: 'score', + dataIndex: 'score', + key: 'score', + render: text => {text}, + }, + ]; + + const datas = []; + let {chart_rules, chartdata, data} = this.props; + let {personal}=this.state; + + if(this.props&&this.props.mode!=1){ + + columns.some((item,key)=> { + if (item.title === "spendtime") { + columns.splice(key, 1) + return true + } + } + ) + + } + + {chartdata===undefined?"":chartdata.teams.length===0?"":chartdata.teams.map((item,key)=>{ + let list={ + usersum:key+1, + userimg:item.user_image, + username:personal===undefined||personal===null?item.record_user_name:personal===true?item.record_user_name:item.team_name, + school:item.school_name, + spendtime:item.spend_time, + score:item.score<50?"< 50 分":item.score, + user_login:item.user_login, + competition_prize:item.competition_prize + } + datas.push(list) + })} + + // console.log(this.props&&this.props.mode) + // console.log(columns) + + return ( +
+ + {chart_rules === undefined ? "" : + this.props.Competitioncallback(e)} activeKey={this.props.tabkey} + tabBarExtraContent={data && data.permission.editable === true ? this.props.Competitionedittype === false ? this.props.has_url === false ? operations : "" : "" : ""}> + {chart_rules.stages.map((item,key)=>{ + return( + + {chart_rules.rule_contents.map((items,keys)=>{ + if(item.id===items.competition_stage_id){ + return( + + ) + }else if(item.id===null&&items.competition_stage_id===0){ + return( + + ) + } + })} + + ) + })} + } + + +
总排名 + {chartdata===undefined?"":chartdata.teams.length===0?+ +
要抓住一切机会,向所有人证明你自己,证明你能够迎接荣耀
+ :""} + + {chartdata===undefined?"":chartdata.teams.length===0?"":chartdata.teams.map((item,key)=>{ + + + if(key===1){ + return( + + +
  • + + +
  • + + } + > + +
    {item.school_name}
    + {this.props&&this.props.mode===1?
    {item.spend_time}
    :""} + } + description={ +
    {item.score<50?"< 50 分":item.score}分
    + } + /> +
    + + + ) + } + + })} + {chartdata===undefined?"":chartdata.teams.length===0?"":chartdata.teams.map((item,key)=>{ + if(key===0){ + return( + + +
  • + + +
  • + + } + > + +
    {item.school_name}
    + {this.props&&this.props.mode===1?
    {item.spend_time}
    :""} + } + description={ +
    {item.score<50?"< 50 分":item.score}分
    + } + + /> +
    + + + ) + } + })} + {chartdata===undefined?"":chartdata.teams.length===0?"":chartdata.teams.map((item,key)=>{ + if(key===2){ + return( + + +
  • + + +
  • + + } + > + +
    {item.school_name}
    + {this.props&&this.props.mode===1?
    {item.spend_time}
    :""} + } + description={ +
    {item.score<50?"< 50 分":item.score}分
    + } + + /> +
    + + ) + } + + + + })} + + + {chartdata===undefined?"":chartdata.user_ranks.length===0?"":
    + + {chartdata.user_ranks.map((item,key)=>{ + + return( + +
    + 您当前排名:{item.rank} + + + {personal===undefined||personal===null?item.record_user_name:personal===true?item.user_name:item.team_name} + + + {/*{item.team_name}*/} + + {item.cost_time=== "--"?+ {this.props&&this.props.mode===1?item.cost_time:""} + :+ {this.props&&this.props.mode===1?item.cost_time:""} + } + {item.cost_time=== "--"?+ {item.score<50?"< 50 分":item.score} + :+ {item.score<50?"< 50 分":item.score} + } + + ) + })} + } + + + {chartdata === undefined ? "" : chartdata.teams.length === 0 ? "" : +
    } + + + + + + ) + } +} +export default CompetitionContents; diff --git a/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentsMd.js b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentsMd.js new file mode 100644 index 000000000..049f2bab1 --- /dev/null +++ b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentsMd.js @@ -0,0 +1,232 @@ +import React, { Component } from 'react'; +import {Button, Card, Row, Col ,Upload,Icon,message,Tabs} from 'antd'; +import axios from 'axios'; +import {getImageUrl,getUrl,appendFileSizeToUploadFileAll,appendFileSizeToUploadFile} from 'educoder'; +import TPMMDEditor from '../../../tpm/challengesnew/TPMMDEditor'; +const { TabPane } = Tabs; +class CompetitionContentsMd extends Component{ + constructor(props) { + super(props) + this.contentMdRef = React.createRef(); + this.state={ + contentFileList:[], + chartmodule_id:undefined + } + } + componentDidUpdate =(prevState)=>{ + if(prevState!=this.props){ + this.getchartdata(); + } + } + componentDidMount(){ + window.document.title = '竞赛'; + + this.getchartdata() + } + + getchartdata=()=>{ + let {mdContentdata,chart_rules}=this.props; + + // is_pdf: false + if(this.props.module_type==="chart"){ + let type=true; + if(chart_rules===undefined){ + + }else{ + chart_rules.rule_contents.map((items,keys)=>{ + debugger + if(parseInt(this.props.tabkey)===items.competition_stage_id){ + console.log(items) + this.contentMdRef.current.setValue(items.content); + this.setState({ + contentFileList:undefined, + chartmodule_id:items.id + }) + type=false; + } + }) + + if(type===true){ + this.contentMdRef.current.setValue(""); + this.setState({ + contentFileList:undefined, + chartmodule_id:undefined + }) + + } + } + + + }else{ + let contentFileList = mdContentdata===undefined?[]:mdContentdata.attachments===undefined?[]:mdContentdata.attachments.map((item) => { + return { + id: item.id, + uid: item.id, + name: appendFileSizeToUploadFile(item), + url: item.url, + filesize: item.filesize, + status: 'done', + response:{id: item.id} + } + }) + this.setState({ + contentFileList:contentFileList + }) + this.contentMdRef.current.setValue(mdContentdata===undefined?"":mdContentdata.md_content===undefined?"":mdContentdata.md_content || '') + + } + } + + handleContentUploadChange = (info) => { + if (info.file.status === 'uploading' || info.file.status === 'done' || info.file.status === 'removed') { + let contentFileList = info.fileList; + this.setState({ contentFileList: appendFileSizeToUploadFileAll(contentFileList) }); + } + + } + + onAttachmentRemove = (file, stateName) => { + if(file.response!=undefined){ + this.props.confirm({ + content: '是否确认删除?', + + onOk: () => { + this.deleteAttachment(file, stateName) + }, + onCancel() { + console.log('Cancel'); + }, + }); + return false; + } + + } + deleteAttachment = (file, stateName) => { + // 初次上传不能直接取uid + const url = `/attachments/${file.response ? file.response.id : file.uid}.json` + axios.delete(url, { + }) + .then((response) => { + if (response.data) { + const { status } = response.data; + if (status == 0) { + console.log('--- success') + this.props.showNotification(response.data.message); + this.setState((state) => { + const index = state[stateName].indexOf(file); + const newFileList = state[stateName].slice(); + newFileList.splice(index, 1); + return { + [stateName]: newFileList, + }; + }); + } + } + }) + .catch(function (error) { + console.log(error); + }); + } + handleSubmit = () => { + let {contentFileList}=this.state; + const mdContnet = this.contentMdRef.current.getValue().trim(); + // if(mdContnet.length>10000){ + // this.props.showNotification("内容超过10000个字"); + // return + // } + let attachment_ids=undefined + if(contentFileList!=undefined){ + attachment_ids= contentFileList.map(item => { + return item.response ? item.response.id : item.id + }) + } + + let newstage_id=parseInt(this.props.tabkey)===0||null?undefined:parseInt(this.props.tabkey) + let data={} + if(this.props.module_type==="chart"){ + data={ + md_content_id:this.state.chartmodule_id, + competition_module_id:this.props.module_id, + stage_id:newstage_id, + content:mdContnet, + } + }else{ + data={ + md_content_id:this.props.mdContentdata.md_id, + competition_module_id:this.props.mdContentdata.id, + content:mdContnet, + attachment_ids:attachment_ids + } + } + + let url=`/competitions/${this.props.match.params.identifier}/update_md_content.json`; + axios.post(url,data + ).then((response) => { + if(response.data.status===0){ + this.props.showNotification(response.data.message); + this.props.getlistdata(this.props.thiskeys,this.props.tabkey); + this.props.hideCompetitionedit(); + }else{ + this.props.showNotification(response.data.message); + } + }).catch((error) => { + console.log(error) + }) + + } + render() { + let {contentFileList}=this.state; + let {chart_rules}=this.props; + const uploadProps = { + width: 600, + fileList: contentFileList, + multiple: true, + // https://github.com/ant-design/ant-design/issues/15505 + // showUploadList={false},然后外部拿到 fileList 数组自行渲染列表。 + // showUploadList: false, + action: `${getUrl()}/api/attachments.json`, + onChange: this.handleContentUploadChange, + onRemove: (file) => this.onAttachmentRemove(file, 'contentFileList'), + beforeUpload: (file) => { + console.log('beforeUpload', file.name); + const isLt150M = file.size / 1024 / 1024 < 150; + if (!isLt150M) { + this.props.showNotification("文件大小必须小于150MB"); + } + return isLt150M; + }, + }; + // console.log(this.props.tabkey) + // console.log(chart_rules) + console.log(this.props.mdContentdata) + return ( +
    + {chart_rules===undefined?"":this.props.module_type==="chart"?this.props.Competitioncallback(e)}> + + {chart_rules.stages.map((item,key)=>{ + return( + + ) + })} + + :""} + + {this.props.module_type==="chart"?"": + + (单个文件150M以内) + } + +
    + {/* htmlType="submit" */} + + this.props.hideCompetitionedit()}>取消 +
    +
    + + ) + } +} +export default CompetitionContentsMd; \ No newline at end of file diff --git a/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdf.js b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdf.js new file mode 100644 index 000000000..218e8497f --- /dev/null +++ b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdf.js @@ -0,0 +1,64 @@ +import React, { Component } from 'react'; +import {Tabs} from 'antd'; +import axios from 'axios'; +import {markdownToHTML,getImageUrl,AttachmentList} from 'educoder'; +import CompetitionContentspdfdownload from './CompetitionContentspdfChild/CompetitionContentspdfdownload'; +import CompetitionContentspdfpeopledata from './CompetitionContentspdfChild/CompetitionContentspdfpeopledata'; +// import NoneData from "../../../courses/shixunHomework/shixunHomework"; + +const { TabPane } = Tabs; +class CompetitionContentspdf extends Component{ + constructor(props) { + super(props) + this.state={ + Tabskey:"1" + } + } + + componentDidMount(){ + window.document.title = '竞赛'; + let query=this.props.location&&this.props.location.search; + const types = query.split('user_id=') + if(types[1]===undefined){ + }else{ + this.setState({ + Tabskey:"2" + }) + } + } + + Competitioncallback=(key)=>{ + this.setState({ + Tabskey:key + }) + } + + render() { + + + return ( + +
    +
    + this.Competitioncallback(e)} activeKey={this.state.Tabskey}> + + {this.state.Tabskey==="1"?this.Competitioncallback(e)} + />:""} + + + {this.state.Tabskey==="2"?:""} + + +
    +
    + + ) + } +} +export default CompetitionContentspdf; diff --git a/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/Bankcardnumberverification.js b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/Bankcardnumberverification.js new file mode 100644 index 000000000..d48ea8fe2 --- /dev/null +++ b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/Bankcardnumberverification.js @@ -0,0 +1,292 @@ +import React, {Component} from 'react'; +import {Button, Layout, Input, Form} from 'antd'; +import axios from 'axios'; +import {getImageUrl} from 'educoder'; +import mycompetotionchild from './mycompetotionchild.css'; +import {getHiddenName} from "../../../../user/account/AccountBasicEdit"; +import '../../../../courses/css/Courses.css' + +export const identityMap = {"teacher": "教师", "student": "学生", "professional": "专业人士"} + +class Bankcardnumberverification extends Component { + constructor(props) { + super(props) + this.state = { + basicInfo: {}, + updating: '', + secondsFlag: false, + seconds: 60, + phonebool: false, + emailbool: false, + formationdata: [], + bank_account_editable: false, + leader: false, + bank_account: undefined, + certification: 1 + } + } + + componentDidMount() { + window.document.title = '竞赛'; + // console.log("3获取用户信息"); + // console.log(this.props) + try { + this.props.triggerRef(this); + }catch (e) { + + } + console.log(this.props.bank_account); + + //初始化值 + if (this.props.bank_account) { + this.props.form.setFieldsValue({ + openingbank: this.props.bank_account.bank, + subbranch: this.props.bank_account.second_bank, + subbranchs: this.props.bank_account.card_no, + }) + this.setState({ + openingbank: this.props.bank_account.bank, + subbranch: this.props.bank_account.second_bank, + subbranchs: this.props.bank_account.card_no, + }) + } + + } + + setdata(bank,second_bank,card_no){ + this.props.form.setFieldsValue({ + openingbank: bank, + subbranch: second_bank, + subbranchs:card_no, + }) + } + componentDidUpdate = (prevProps) => { + if (prevProps.bank_account != this.props.bank_account) { + console.log("componentDidUpdate"); + console.log(this.props);//是新数据 + console.log(prevProps);//是老数据 + ////console.log("Registration"); + ////console.log("componentDidUpdate"); + ////console.log(this.props.user.admin); + try { + if(this.props.bank_account){ + this.props.form.setFieldsValue({ + openingbank: this.props.bank_account.bank, + subbranch: this.props.bank_account.second_bank, + subbranchs: this.props.bank_account.card_no, + }) + } + this.setState({ + openingbank: this.props.bank_account.bank, + subbranch: this.props.bank_account.second_bank, + subbranchs: this.props.bank_account.card_no, + }) + }catch (e) { + + } + } + + } + yhBankstrue = () => { + this.props.form.validateFieldsAndScroll((err, values) => { + if (!err) { + let url = `/competitions/${this.props.match.params.identifier}/prize_leader_account.json`; + axios.patch(url, { + user_id:this.props.userdata.id, + bank: values.openingbank, + second_bank: values.subbranch , + card_no: values.subbranchs + }) + .then((result) => { + try { + if (result.data.status === 0) { + try { + // console.log(values.openingbank); + // console.log(values.subbranch); + // console.log(values.subbranchs); + this.props.form.setFieldsValue({ + openingbank: values.openingbank, + subbranch: values.subbranch, + subbranchs: values.subbranchs, + }); + this.setState({ + openingbank: values.openingbank, + subbranch: values.subbranch, + subbranchs: values.subbranchs, + }) + }catch (e) { + + } + + try { + this.props.showNotification(`提交成功,等待审核!`); + + }catch (e) { + + } + try { + this.props.getdata(this.props.userdata.id); + }catch (e) { + + } + try { + this.props.GetawardinformationAPI(); + }catch (e) { + + } + } + } catch (e) { + + } + + }).catch((error) => { + console.log(error); + }) + } + }) + + } + + render() { + const {getFieldDecorator} = this.props.form; + const {updating, seconds, secondsFlag, basicInfo, phonebool, emailbool, certification, formationdata, bank_account_editable, leader, bank_account} = this.state + return ( +
    +
    +

    签/领/开户行及银行卡号

    +

    为保障奖金的及时发放,请队长如实填写你名下的银行卡信息

    +
    +
    + +
    + +
    + + {getFieldDecorator('openingbank', { + rules: [{ + initialValue:this.state.openingbank, + required: true, + message: '请输入开户行', + }], + })( + + )} + + + + {getFieldDecorator('subbranch', { + rules: [{ + initialValue: this.state.subbranch, + required: true, + message: '请输入支行', + }], + })( + + )} + + + + {getFieldDecorator('subbranchs', { + rules: [{ + initialValue: this.state.subbranchs, + required: true, + message: '请输入账号', + }], + })( + + )} + + +
    +

    +
    + {/*
    this.yhBanksfalse()}>

    取消

    */} + +
    +
    + + +
    +
    + +
    +
    + ) + } +} + +const Bankcardnumberverifications = Form.create({name: 'Bankcardnumberverification'})(Bankcardnumberverification); + +export default Bankcardnumberverifications; + diff --git a/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/CompetitionContentspdfdownload.css b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/CompetitionContentspdfdownload.css new file mode 100644 index 000000000..726a02277 --- /dev/null +++ b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/CompetitionContentspdfdownload.css @@ -0,0 +1,24 @@ +.pdfdownload { + max-width: 791px; + height: 40px; + background: rgba(249, 249, 249, 1); + line-height: 40px; + padding-left: 15px; +} + +.pdfpicture { + font-size: 16px; + color: rgba(0, 0, 0, 1); +} + +.pdfdownloadfont4CACFF { + color: #4CACFF !important; +} + +.pdfdownloadfont00CC5F { + color: #00CC5F; +} + +.pdfdownloadfontFF6602 { + color: #FF6602; +} diff --git a/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/CompetitionContentspdfdownload.js b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/CompetitionContentspdfdownload.js new file mode 100644 index 000000000..eb304e007 --- /dev/null +++ b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/CompetitionContentspdfdownload.js @@ -0,0 +1,215 @@ +import React, { Component } from 'react'; +import {Button,Layout,Row, Col,Divider,Table} from 'antd'; +import axios from 'axios'; +import {getImageUrl} from 'educoder'; +import './CompetitionContentspdfdownload.css'; +// import NoneData from "../../../courses/shixunHomework/shixunHomework"; + + +class CompetitionContentspdfdownload extends Component{ + constructor(props) { + super(props) + this.state={ + data:undefined, + teams:undefined + } + } + + componentDidMount(){ + window.document.title = '竞赛'; + let url=`/competitions/${this.props.match.params.identifier}/prize.json`; + let query=this.props.location&&this.props.location.search; + const types = query.split('user_id=') + let userid; + if(types[1]===undefined){ + userid=this.props.user&&this.props.user.user_id; + }else{ + userid=types[1]; + } + axios.get(url,{params:{ + user_id:userid, + } + }).then((response) => { + if(response.status===200){ + + let datas=response.data.teams; + if(datas.length>0){ + datas.map((item,key)=>{ + let lista=item.team_members; + if(lista.length>0){ + console.log(lista) + lista.map((i,k)=>{ + i["bank_account"]=item.bank_account; + }) + } + }) + } + this.setState({ + data:response.data, + teams:datas, + }) + } + }).catch((error) => { + console.log(error) + }) + } + + render() { + + + + let {data,teams}=this.state; + + const columns = [ + { + title: '角色', + dataIndex: 'type', + key: 'type', + render: (text, record) => ( + + {record.role} + + ), + }, + { + title: '姓名', + dataIndex: 'name', + key: 'name', + render: (text, record) => ( + + {record.name} + + ), + }, + { + title: '实名认证', + dataIndex: 'namecertify', + key: 'namecertify', + render: (text, record) => ( + + {record.real_name_auth==="authed"?已认证:record.real_name_auth==="authing"?待审核:record.real_name_auth==="not_authed"?未认证:""} + + ), + }, + { + title: '职业认证', + key: 'certify', + dataIndex: 'certify', + render: (text, record) => ( + + {record.professional_auth==="authed"?已认证:record.professional_auth==="authing"?待审核:record.professional_auth==="not_authed"?未认证:""} + + ), + }, + { + title: '手机绑定', + key: 'mobile', + dataIndex: 'mobile', + render: (text, record) => ( + + {record.phone_binded===true?已绑定:未绑定} + + ), + }, + { + title: '邮箱绑定', + key: 'mail', + dataIndex: 'mail', + render: (text, record) => ( + + {record.email_binded===true?已绑定:未绑定} + + ), + }, + { + title: '开户行及银行卡号信息(队长填写)', + key: 'idcard', + dataIndex: 'idcard', + render: (value, record, index) => { + if (index === 0&&record.bank_account!=null) { + return { + children: {record.bank_account.bank + record.bank_account.second_bank + record.bank_account.card_no}, + }; + } + + }, + }, + ]; + + + let people=[ { url: '/api/competitions/xxxxx/certificates/1/personal' }, + { url: '/api/competitions/xxxxx/certificates/2/personal' },] + return ( + + +
    温馨提示:填写的个人信息经审批后,将提供个人获奖证书下载;团队队员信息全部审批后,将提供团队获奖证书下载。 + + + + 证书情况 + + + + 个人证书:{data&&data.personal_certifications.length===0&&data&&data.all_certified===false? + 暂未生成 原因:还未认证个人信息,this.props.Competitioncallback("2")}>立即认证: + data&&data.personal_certifications.length===0&&data&&data.all_certified===true? + 暂未生成 原因:组委会未完成证书审批,请稍后: + data&&data.personal_certifications.map((item,key)=>{ + return( + + + 立即下载 + + ) + })} + + + + 团队证书: + {data&&data.team_certifications.length===0?暂未生成 + :data&&data.team_certifications.map((item,key)=>{ + return( + + + 立即下载 + + ) + })} + + + + + {teams&&teams.map((item,key)=>{ + return( + + {item.name}战队信息填报概况 + +
    + + ) + }) + } + + + + ) + } +} +export default CompetitionContentspdfdownload; \ No newline at end of file diff --git a/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/CompetitionContentspdfpeopledata.js b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/CompetitionContentspdfpeopledata.js new file mode 100644 index 000000000..1afbf16a7 --- /dev/null +++ b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/CompetitionContentspdfpeopledata.js @@ -0,0 +1,596 @@ +import React, {Component} from 'react'; +import {Button, Layout, Input, Form} from 'antd'; +import axios from 'axios'; +import {getImageUrl} from 'educoder'; +import mycompetotionchild from './mycompetotionchild.css'; +import {getHiddenName} from "../../../../user/account/AccountBasicEdit"; +import '../../../../courses/css/Courses.css' +import RealNameCertificationModal from "../../../../user/modal/RealNameCertificationModal"; +import Phonenumberverifications from './Phonenumberverification'; +import Mailboxvalidations from './Mailboxvalidation' +import Bankcardnumberverifications from './Bankcardnumberverification' +export const identityMap = {"teacher": "教师", "student": "学生", "professional": "专业人士"} + +class CompetitionContentspdfpeopledata extends Component { + constructor(props) { + super(props) + this.state = { + basicInfo: {}, + updating: '', + secondsFlag: false, + seconds: 60, + phonebool: false, + emailbool: false, + formationdata: [], + bank_account_editable: false, + leader: false, + bank_account: undefined, + certification: 1, + userdata:undefined + } + } + + componentDidMount() { + window.document.title = '竞赛'; + console.log("获取用户信息"); + console.log(this.props); + + this.GetawardinformationAPI(); + let query=this.props.location&&this.props.location.search; + const types = query.split('user_id=') + let userid; + if(types[1]===undefined){ + userid=this.props.user&&this.props.user.user_id; + }else{ + userid=types[1]; + } + this.getdata(userid); + this.GetuseridApi(userid); + + } + + GetuseridApi=(id)=>{ + //个人信息API 获取个人信息 + let url = `/users/accounts/${id}.json`; + axios.get(url).then((result) => { + if (result.data) { + console.log("GetuseridApi"); + console.log(result.data); + this.setState({ + userdata:result.data + }) + } + }).catch((error) => { + console.log(error); + }) + + } + + GetawardinformationAPI = () => { + let url = `/competitions/${this.props.match.params.identifier}/prize.json`; + let query=this.props.location&&this.props.location.search; + const types = query.split('user_id=') + let userid; + if(types[1]===undefined){ + userid=this.props.user&&this.props.user.user_id; + }else{ + userid=types[1]; + } + axios.get(url,{params:{ + user_id:userid, + } + }).then((result) => { + if (result.data) { + this.setState({ + formationdata: result.data.formationdata, + bank_account_editable: result.data.bank_account_editable, //队长是否可以编辑 + leader: result.data.leader, //是否是队长 + bank_account: result.data.bank_account, //队长银行卡号信息 + }) + } + }).catch((error) => { + console.log(error); + }) + } + + + getdata = (id) => { + this.setState({ + certification: 3 + }) + this.GetuseridApi(id); + }; + // 绑定手机 + onPhoneSubmit = () => { + this.props.form.validateFieldsAndScroll((err, values) => { + if (!err) { + let {id} =this.state.userdata; + let reg = /^1\d{10}$/; + if (reg.test(values.phone)) { + let url = `/users/accounts/${id}/phone_bind.json` + axios.post((url), { + phone: values.phone, + code: values.phoneValidateCode + }).then((result) => { + if (result) { + this.props.showNotification("手机号码绑定成功!"); + this.setState({ + phonebool: false + }) + this.getdata(this.state.userdata.id); + } + }).catch((error) => { + console.log(error); + }) + } else { + this.props.showNotification("请输入有效的11位手机号码"); + } + } + }) + } + // 绑定邮箱 + onEmailSubmit = () => { + this.props.form.validateFieldsAndScroll((err, values) => { + if (!err) { + let {id} =this.state.userdata; + let reg = /^[a-zA-Z0-9]+([.\-_\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/; + if (reg.test(values.email)) { + let url = `/users/accounts/${id}/email_bind.json` + axios.post((url), { + email: values.email, + code: values.emailValidateCode + }).then((result) => { + if (result) { + this.props.showNotification("邮箱地址绑定成功!"); + this.setState({ + emailbool: false + }) + this.getdata(this.state.userdata.id); + } + }).catch((error) => { + console.log(error); + }) + } else { + this.props.showNotification("请输入正确的邮箱地址"); + } + } + }) + } + //取消编辑 + hideUpdating = (i) => { + if (i === 1) { + this.setState({ + phonebool: false + }) + } else if (i === 2) { + this.setState({ + emailbool: false + }) + + } else if (i === 3) { + + } + + } + + // 获取验证码 + getCode = (index) => { + let url = `/accounts/get_verification_code.json` + let login = ''; + let values = this.props.form.getFieldsValue(); + if (index == 3) { + //绑定手机号码 + login = values.phone; + let reg = /^1\d{10}$/; + if (reg.test(login) == false) { + this.props.showNotification(`请先输入正确的手机号码`); + return; + } + } else if (index == 4) { + // 绑定邮箱 + login = values.email; + let reg = /^[a-zA-Z0-9]+([.\-_\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/; + if (reg.test(login) == false) { + this.props.showNotification(`请先输入正确的邮箱地址`); + return; + } + } + let type = index; + if (!login) { + this.props.showNotification(`请先输入${index == 3 ? "手机号码" : "邮箱地址"}`); + return; + } + axios.get((url), { + params: { + login, type + } + }).then((result) => { + if (result) { + // 倒计时 + this.setState({ + secondsFlag: true + }) + this.remainTime(); + } + }).catch((error) => { + console.log(error); + }) + } + + // 获取验证码倒计时 + remainTime = () => { + this.setState({ + seconds: 60 + }) + this.timer = setInterval(() => { + let {seconds} = this.state; + let s = parseInt(seconds) - 1; + if (s > -1) { + this.setState({ + seconds: s + }) + } else { + this.setState({ + secondsFlag: false + }) + clearInterval(this.timer); + } + }, 1000) + } + + phonebools = () => { + this.setState({ + phonebool: true + }) + } + + emailbools = () => { + console.log("点击了邮箱"); + this.setState({ + emailbool: true + }) + } + + //立即认证 + checkBasicInfo = (index) => { + if (this.state.userdata.base_info_completed == true) { + this.showRealNameCertificationModal(index) + } else { + try { + this.props.confirm({ + okText: `立即完善`, + content: `请先完善基本信息`, + onOk: () => { + this.props.history.push('/account/profile/edit') + } + }) + } catch (e) { + this.props.history.push(`/account/profile/edit`); + + } + } + + } + showRealNameCertificationModal = (index) => { + this.setState({ + certification: index, + }, () => { + if (index == 1) { + this.realNameCertificationModal1.setVisible(true) + } else if (index == 2) { + this.realNameCertificationModal2.setVisible(true) + } + }) + } + //绑定银行确认 + yhBankstrue = () => { + this.props.form.validateFieldsAndScroll((err, values) => { + if (!err) { + let url = `/competitions/${this.props.match.params.identifier}/prize_leader_account.json`; + axios.patch(url, { + user_id:this.state.userdata.id, + bank: values.openingbank, + second_bank: values.subbranchs, + card_no: values.subbranch + }) + .then((result) => { + try { + if (result.data.status == 0) { + // console.log(JSON.stringify(result)); + this.props.showNotification(`提交成功`); + this.getdata(this.state.userdata.id); + this.GetawardinformationAPI(); + } + } catch (e) { + + } + + }).catch((error) => { + console.log(error); + }) + } + }) + + } + + //取消认证弹框 + onCancel = () => { + this.getdata(this.state.userdata.id); + + } + + bindRef = ref => { this.child = ref } + //撤销认证 + Cancellationofapplication = (index) => { + let userid; + let query=this.props.location&&this.props.location.search; + const types = query.split('user_id=') + if(types[1]===undefined){ + userid=this.props.user&&this.props.user.user_id; + }else{ + userid=types[1]; + } + let url = "" + if (index === 1) { + url = `/users/accounts/${userid}/authentication_apply.json`; + } else if (index === 2) { + url = `/users/accounts/${userid}/professional_auth_apply.json`; + } + axios.delete(url) + .then((response) => { + try { + if (response.data.status == 0) { + if (index === 1) { + this.props.showNotification('撤销实名认证成功') + } else if (index === 2) { + this.props.showNotification('撤销职业认证成功') + } + try { + this.getdata(this.state.userdata.id); + }catch (e) { + + } + + } + } catch (e) { + + } + + }) + .catch(function (error) { + console.log(error); + }); + + } + + + render() { + const admins=this.props.user.admin; + if(admins===undefined||admins===null) { + admins === false; + } + const {updating, seconds, secondsFlag,userdata, basicInfo, phonebool, emailbool, certification, formationdata, bank_account_editable, leader, bank_account} = this.state + return ( +
    + {this.state.certification === 1 &&userdata? + + this.realNameCertificationModal1 = form} + certification={certification} + Getdata={(id) => this.getdata(id)} + onCancel={() => this.onCancel()} + > + + + : ""} + + {this.state.certification === 2 &&userdata ? + this.realNameCertificationModal2 = form} + certification={certification} + Getdata={(id) => this.getdata(id)} + onCancel={() => this.onCancel()} + + > : ""} +
    +

    *实名信息 +

    + {userdata && userdata.authentication == "uncertified" ? +

    通过实名认证后才能获得证书

    : "" + } + {userdata && userdata.authentication == "uncertified" ? +

    this.checkBasicInfo(1)}>立即认证

    : "" + } + +
    +
    +

    姓名:

    +

    {userdata && userdata.name} + + { + userdata && userdata.authentication == "uncertified" ? "" : + userdata && userdata.authentication == "applying" ? +

    待审核!

    this.Cancellationofapplication(1)}>撤销认证

    + : +

    +

    已认证

    +

    + } +

    +
    + +
    +

    性别:

    +

    {userdata && userdata.gender == 0 ? "男" : "女"}

    +
    + +
    +

    *职业信息 +

    + { + userdata && userdata.professional_certification == "uncertified" ? +

    通过职业认证后才能获得证书

    + + : ""} + { + userdata && userdata.professional_certification == "uncertified" ? +

    this.checkBasicInfo(2)}>立即认证

    + + : ""} +
    + +
    +

    职业:

    +

    {userdata && userdata.identity && identityMap[userdata.identity]} + { + userdata && userdata.professional_certification == "uncertified" ? + "" : + userdata && userdata.professional_certification == "applying" ? +

    +

    待审核!

    this.Cancellationofapplication(2)}>撤销认证

    +

    + : +

    +

    已认证

    +

    this.checkBasicInfo(2)}>重新认证

    + +

    + } +

    +
    +
    +

    {userdata && userdata.technical_title ? "职称:" : ""}{userdata && userdata.student_id ? "学号:" : ""}

    +

    {userdata && (userdata.technical_title || userdata.student_id)}

    +
    +
    +

    学校:

    +

    {userdata && userdata.school_name}

    +
    +
    +

    院系:

    +

    {userdata && userdata.department_name}

    +
    +
    +

    *联系方式 +

    +
    +
    +

    手机号:

    + { + userdata && userdata.phone ? +

    {userdata && userdata.phone}

    + : +

    未绑定

    + } +

    this.phonebools()}>{userdata && userdata.phone ? (phonebool === false ? "更换" : "") : (phonebool === false ? "立即绑定" : "")}

    +
    + {/*手机号绑定*/} + { + phonebool === true &&userdata ? + this.hideUpdating(i)} + getdata={(id) => this.getdata(id)}> + : "" + } + + +
    +

    Email:

    +

    {userdata && userdata.mail}

    +

    this.emailbools()}>{userdata && userdata.mail ? (emailbool === false ? "更换" : "") : (emailbool === false ? "立即绑定" : "")}

    +
    + { + emailbool === false ? "" : + ( + userdata? + this.hideUpdating(i)} + getdata={(id) => this.getdata(id)}> + :"" + ) + } + { + leader === true ? +
    + { + bank_account_editable === true ? + this.hideUpdating(i)} + getdata={(id) => this.getdata(id)} + GetawardinformationAPI={() => this.GetawardinformationAPI()} + bank_account={this.state.bank_account} + > + : + admins===true? + this.hideUpdating(i)} + getdata={(id) => this.getdata(id)} + GetawardinformationAPI={() => this.GetawardinformationAPI()} + bank_account={this.state.bank_account} + > + : +
    +
    +

    签/领/开户行及银行卡号

    +

    为保障奖金的及时发放,请队长如实填写你名下的银行卡信息

    +
    + { + bank_account && bank_account ? +
    +
    +

    开户行:

    +

    {bank_account && bank_account.bank}

    +
    +
    +

    支行:

    +

    {bank_account && bank_account.second_bank}

    +
    +
    +

    账号:

    +

    {bank_account && bank_account.card_no}

    +
    +
    + : + "" + } + +
    + } +
    + : +
    + { + admins===true? + this.hideUpdating(i)} + getdata={(id) => this.getdata(id)} + GetawardinformationAPI={() => this.GetawardinformationAPI()} + bank_account={this.state.bank_account} + > + :"" + } +
    + } + + +
    + ) + } +} + +export default CompetitionContentspdfpeopledata; + diff --git a/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/Mailboxvalidation.js b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/Mailboxvalidation.js new file mode 100644 index 000000000..934369aac --- /dev/null +++ b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/Mailboxvalidation.js @@ -0,0 +1,270 @@ +import React, {Component} from 'react'; +import {Button, Layout, Input, Form} from 'antd'; +import axios from 'axios'; +import {getImageUrl} from 'educoder'; +import mycompetotionchild from './mycompetotionchild.css'; +import {getHiddenName} from "../../../../user/account/AccountBasicEdit"; +import '../../../../courses/css/Courses.css' + +export const identityMap = {"teacher": "教师", "student": "学生", "professional": "专业人士"} + +class Mailboxvalidation extends Component { + constructor(props) { + super(props) + this.state = { + basicInfo: {}, + updating: '', + secondsFlag: false, + seconds: 60, + phonebool: false, + emailbool: false, + formationdata: [], + bank_account_editable: false, + leader: false, + bank_account: undefined, + certification: 1 + } + } + + componentDidMount() { + window.document.title = '竞赛'; + // console.log("3获取用户信息"); + // console.log(this.props); + } + + + // 绑定邮箱 + onEmailSubmit = () => { + this.props.form.validateFieldsAndScroll((err, values) => { + if (!err) { + let {id} = this.props.userdata; + let reg = /^[a-zA-Z0-9]+([.\-_\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/; + if (reg.test(values.email)) { + let url = `/users/accounts/${id}/email_bind.json` + axios.post((url), { + email: values.email, + code: values.emailValidateCode + }).then((result) => { + if (result) { + this.props.showNotification("邮箱地址绑定成功!"); + this.hideUpdating(2); + this.props.getdata(id); + } + }).catch((error) => { + console.log(error); + }) + } else { + this.props.showNotification("请输入正确的邮箱地址"); + } + } + }) + } + //取消编辑 + hideUpdating = (i) => { + if (i === 1) { + this.props.hideUpdating(1); + } else if (i === 2) { + this.props.hideUpdating(2); + + + } else if (i === 3) { + + } + + } + + // 获取验证码 + getCode = (index) => { + let url = `/accounts/get_verification_code.json` + let login = ''; + let values = this.props.form.getFieldsValue(); + if (index == 3) { + //绑定手机号码 + login = values.phone; + let reg = /^1\d{10}$/; + if (reg.test(login) == false) { + this.props.showNotification(`请先输入正确的手机号码`); + return; + } + } else if (index == 4) { + // 绑定邮箱 + login = values.email; + let reg = /^[a-zA-Z0-9]+([.\-_\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/; + if (reg.test(login) == false) { + this.props.showNotification(`请先输入正确的邮箱地址`); + return; + } + } + let type = index; + if (!login) { + this.props.showNotification(`请先输入${index == 3 ? "手机号码" : "邮箱地址"}`); + return; + } + axios.get((url), { + params: { + login, type + } + }).then((result) => { + if (result) { + // 倒计时 + this.setState({ + secondsFlag: true + }) + this.remainTime(); + } + }).catch((error) => { + console.log(error); + }) + } + + // 获取验证码倒计时 + remainTime = () => { + this.setState({ + seconds: 60 + }) + this.timer = setInterval(() => { + let {seconds} = this.state; + let s = parseInt(seconds) - 1; + if (s > -1) { + this.setState({ + seconds: s + }) + } else { + this.setState({ + secondsFlag: false + }) + clearInterval(this.timer); + } + }, 1000) + } + + phonebools = () => { + this.setState({ + phonebool: true + }) + } + + emailbools = () => { + console.log("点击了邮箱"); + this.setState({ + emailbool: true + }) + } + + + render() { + const {getFieldDecorator} = this.props.form; + const {updating, seconds, secondsFlag, basicInfo, phonebool, emailbool, certification, formationdata, bank_account_editable, leader, bank_account} = this.state + console.log(emailbool); + return ( +
    + +
    + +
    + + {getFieldDecorator('email', { + rules: [{ + // initialValue: this.state.cityDefaultValue, + required: true, + message: basicInfo && basicInfo.mail ? '请输入要更换的新邮箱地址' : '请输入邮箱地址', + }], + })( + + )} + + + + {getFieldDecorator('emailValidateCode', { + rules: [{ + // initialValue: this.state.cityDefaultValue, + required: true, + message: '请输入邮箱收到的验证码', + }], + })( + + )} + + + +
    + + +
    + +
    +
    +
    + ) + } +} + +const Mailboxvalidations = Form.create({name: 'Mailboxvalidation'})(Mailboxvalidation); + +export default Mailboxvalidations; + diff --git a/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/Phonenumberverification.js b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/Phonenumberverification.js new file mode 100644 index 000000000..fa0b20b7a --- /dev/null +++ b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/Phonenumberverification.js @@ -0,0 +1,262 @@ +import React, {Component} from 'react'; +import {Button, Layout, Input, Form} from 'antd'; +import axios from 'axios'; +import {getImageUrl} from 'educoder'; +import mycompetotionchild from './mycompetotionchild.css'; +import {getHiddenName} from "../../../../user/account/AccountBasicEdit"; +import '../../../../courses/css/Courses.css' +import RealNameCertificationModal from "../../../../user/modal/RealNameCertificationModal"; + +export const identityMap = {"teacher": "教师", "student": "学生", "professional": "专业人士"} + +class Phonenumberverification extends Component { + constructor(props) { + super(props) + this.state = { + updating: '', + secondsFlag: false, + seconds: 60, + phonebool: false, + emailbool: false, + formationdata: [], + bank_account_editable: false, + leader: false, + bank_account: undefined, + certification: 1 + } + } + + componentDidMount() { + window.document.title = '竞赛'; + // console.log("获取用户信息"); + // console.log(this.props); + } + + + // 绑定手机 + onPhoneSubmit = () => { + this.props.form.validateFieldsAndScroll((err, values) => { + if (!err) { + let {id} = this.props.userdata; + let reg = /^1\d{10}$/; + if (reg.test(values.phone)) { + let url = `/users/accounts/${id}/phone_bind.json` + axios.post((url), { + phone: values.phone, + code: values.phoneValidateCode + }).then((result) => { + if (result) { + this.props.showNotification("手机号码绑定成功!"); + this.props.hideUpdating(1) + this.props.getdata(id); + } + }).catch((error) => { + console.log(error); + }) + } else { + this.props.showNotification("请输入有效的11位手机号码"); + } + } + }) + } + //取消编辑 + hideUpdating = (i) => { + if (i === 1) { + this.props.hideUpdating(1); + } else if (i === 2) { + this.props.hideUpdating(2); + + } else if (i === 3) { + + } + + } + + // 获取验证码 + getCode = (index) => { + let url = `/accounts/get_verification_code.json` + let login = ''; + let values = this.props.form.getFieldsValue(); + if (index == 3) { + //绑定手机号码 + login = values.phone; + let reg = /^1\d{10}$/; + if (reg.test(login) == false) { + this.props.showNotification(`请先输入正确的手机号码`); + return; + } + } else if (index == 4) { + // 绑定邮箱 + login = values.email; + let reg = /^[a-zA-Z0-9]+([.\-_\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/; + if (reg.test(login) == false) { + this.props.showNotification(`请先输入正确的邮箱地址`); + return; + } + } + let type = index; + if (!login) { + this.props.showNotification(`请先输入${index == 3 ? "手机号码" : "邮箱地址"}`); + return; + } + axios.get((url), { + params: { + login, type + } + }).then((result) => { + if (result) { + // 倒计时 + this.setState({ + secondsFlag: true + }) + this.remainTime(); + } + }).catch((error) => { + console.log(error); + }) + } + + // 获取验证码倒计时 + remainTime = () => { + this.setState({ + seconds: 60 + }) + this.timer = setInterval(() => { + let {seconds} = this.state; + let s = parseInt(seconds) - 1; + if (s > -1) { + this.setState({ + seconds: s + }) + } else { + this.setState({ + secondsFlag: false + }) + clearInterval(this.timer); + } + }, 1000) + } + + phonebools = () => { + this.setState({ + phonebool: true + }) + } + + + render() { + const {getFieldDecorator} = this.props.form; + const {updating, seconds, secondsFlag, phonebool, emailbool, certification, formationdata, bank_account_editable, leader, bank_account} = this.state + const {basicInfo} = this.props + console.log(emailbool); + return ( +
    + +
    + +
    + + {getFieldDecorator('phone', { + rules: [{ + // initialValue: this.state.cityDefaultValue, + required: true, + message: `请输入要${basicInfo.phone ? '更换' : '绑定'}的手机号码`, + }], + })( + + )} + + + + {getFieldDecorator('phoneValidateCode', { + rules: [{ + // initialValue: this.state.cityDefaultValue, + required: true, + message: '请输入手机获取的验证码', + }], + })( + + )} + + + +
    + + +
    + +
    +
    +
    + ) + } +} + +const Phonenumberverifications = Form.create({name: 'Phonenumberverification'})(Phonenumberverification); + +export default Phonenumberverifications; + diff --git a/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/mycompetotionchild.css b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/mycompetotionchild.css new file mode 100644 index 000000000..fd85606e0 --- /dev/null +++ b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/mycompetotionchild.css @@ -0,0 +1,314 @@ +/*垂直布局 + + 一 + 二 + 三 +*/ +.flexdirectionjust { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} + + +.directstwebkitflex { + display: flex; + display: -webkit-flex; + flex-direction: column; + align-items: center; +} + +.diredisplayitflex { + display: flex; + display: -webkit-flex; + align-items: center; +} + +/*垂直布局*/ +/*靠左侧 +一 二 三 四 五 六 七 八 +*/ +.flexdirection { + display: flex; + flex-direction: row; +} + +.flexdirections { + display: flex; + flex-direction: initial; +} + +/*靠左侧 +*/ + + +/*靠右侧八 七 六 五 四 三 二 一*/ +.flexdirectionss { + display: flex; + flex-direction: row-reverse; +} + + +/*垂直布局 +一 +二 +三 +四 +*/ +.flexdidirectionss { + display: flex; + flex-direction: column; +} + +/*垂直布局 +四 +三 +二 +一 +*/ +.flexdidireverses { + display: flex; + flex-direction: column-reverse; +} + +.fontcolorsysl { + color: #FF0000 +} + +.fontcolorsyslhei { + color: #000000 +} + +.fontcolorsyslhui { + color: #888888 +} + +.fontcolorsyslhui1 { + color: #666666; +} + +.fontcolorsysllan { + color: #4CACFF +} + +.fontcolorsysljin { + color: #DD7600 +} + +.w200 { + width: 200px; +} + +.w64 { + width: 64px; +} + +.w60 { + width: 60px; +} + +.w98 { + width: 98px; +} + +.myysllineheight { + line-height: 40px; +} + +.myyslminwidth { + min-width: 60px; +} + +.myyslminwidth276 { + width: 276px; +} + +.buttongo { + background: #E7E7E7; + border: 1px solid #E7E7E7; + width: 60px; + height: 30px; + border-radius: 4px; + color: #999999; + font-size: 16px; +} + +.buttongo2 { + background: #4CACFF; + border: 1px solid #4CACFF; + width: 64px; + height: 32px; + border-radius: 4px; + color: #FFFFFF; + font-size: 16px; +} + +.fontwenzi { + text-align: center; + line-height: 30px; +} + +.mt17 { + margin-top: 17px; +} + +.mt36 { + margin-top: 36px; +} + +.mt23 { + margin-top: 23px; +} + +.mt19 { + margin-top: 19px; +} + +.mt23 { + margin-top: 23px; +} + +.mt34 { + margin-top: 34px; +} + +.ml11 { + margin-left: 11px; +} + +.ml38 { + margin-left: 38px; +} + +.ml7 { + margin-left: 7px; +} + +.colorgreenlight { + color: #6EC76E +} + +.colorgreenorg { + color: #FF7300; +} + +.borcolors { + border: 1px solid #4CACFF; + + text-align: center; +} + +.mycompitcursor { + cursor: pointer; +} + +.basicForm { + background: #fff; + padding: 30px; + margin-bottom: 10px; + box-sizing: border-box; + width: 100%; + min-height: 390px; +} + +.basicForm .title { + font-size: 16px; + padding-left: 30px; + margin-bottom: 10px; +} + +.flexTable { + display: flex; + flex-direction: column; +} + +.flexRow { + display: flex; +} + +.mb15 { + margin-bottom: 15px !important; +} + +/* BUTTOn */ +.ant-btn { + border-radius: 2px; +} + +button.ant-btn.ant-btn-primary.grayBtn { + background: #CBCBCB; + border-color: #CBCBCB; +} + +.borderBottom { + border-bottom: 1px solid #4CACFF; +} + +/* form ---------------- START */ +.formItemInline { + display: flex; +} + +.formItemInline .ant-form-item-control-wrapper { + display: inline-block; +} + +.hideRequireTag .ant-form-item-required:before { + display: none; +} + + +/* .basicForm .ant-form-item-label { + width: 100px; + padding-right: 10px; +} + .basicForm .ant-form-item-label label { + color: #979797 + } */ + + +.courseNormalForm .ant-select-show-search { + height: 40px; +} + +.courseNormalForm .ant-select-auto-complete.ant-select .ant-input { + height: 40px; +} + +.courseNormalForm .ant-select-search__field__mirror { + height: 40px; +} + +.courseNormalForm .ant-input-lg { + height: 40px; +} + +.courseNormalForm .ant-select-selection--single { + height: 40px; +} + +.courseNormalForm .ant-select-auto-complete.ant-select .ant-select-selection--single { + height: 40px +} + +.courseNormalForm .ant-input-affix-wrapper { + height: 40px; +} + +/* 职业 */ +.courseNormalForm .ant-select-selection-selected-value { + line-height: 38px +} + +.courseNormalForm input { + height: 40px; +} + +.w300 { + width: 300px; +} + +.w56 { + width: 56px; +} diff --git a/public/react/src/modules/courses/competitions/Competitions.js b/public/react/src/modules/courses/competitions/Competitions.js new file mode 100644 index 000000000..704b85ef9 --- /dev/null +++ b/public/react/src/modules/courses/competitions/Competitions.js @@ -0,0 +1,92 @@ +import React, { Component } from 'react'; + +import { Redirect } from 'react-router'; + +import { Route, Link, Switch } from "react-router-dom"; + +import Loading from '../../Loading'; + +import Loadable from 'react-loadable'; +import { TPMIndexHOC } from '../tpm/TPMIndexHOC'; +import { CNotificationHOC } from '../courses/common/CNotificationHOC'; + +//新版竞赛首页 +const CompetitionsIndex = Loadable({ + loader: () => import('./Competitimain/CompetitionsIndex'), + loading: Loading, +}) + +//竞赛详情页 +const CompetitionCommon=Loadable({ + loader: () => import('./Competitioncommon/CompetitionCommon'), + loading: Loading, +}) + + +//战队详情 +const CompetitionTeams = Loadable({ + loader: () => import('./Competition_teams/Competitionteams'), + loading: Loading, +}) + +//团队竞赛报名 +const Registration = Loadable({ + loader: () => import('../competition/Registration'), + loading: Loading, +}); + +class Competitions extends Component { + constructor(props) { + super(props) + } + + componentDidMount(){ + + window.document.title = '竞赛'; + } + + render() { + + return ( +
    + + + + {/*新版竞赛战队详情*/} + () + } + > + + + {/*新版竞赛报名*/} + () + } + /> + + {/*新版竞赛详情页面*/} + () + } + > + + {/*新版竞赛首页*/} + () + } + > + + + +
    + ); + } +} + +export default CNotificationHOC() (TPMIndexHOC (Competitions)) ; \ No newline at end of file diff --git a/public/react/src/modules/developer/DeveloperHome.js b/public/react/src/modules/developer/DeveloperHome.js new file mode 100644 index 000000000..9746fe4cc --- /dev/null +++ b/public/react/src/modules/developer/DeveloperHome.js @@ -0,0 +1,462 @@ +/* + * @Description: undefined + * @Author: tangjiang + * @Date: 2019-11-15 11:02:49 + * @Last Modified by: tangjiang + * @Last Modified time: 2019-11-18 16:52:38 + */ + +import './index.scss'; + +import React from 'react'; +import { Table, Button, Dropdown, Icon, Menu, Card, Input, Select, Tag } from 'antd'; +import { connect } from 'react-redux'; +import actions from '../../redux/actions'; +import MultipTags from './components/multiptags'; +import { Link } from 'react-router-dom'; +import CONST from '../../constants'; + +const {tagBackground, diffText} = CONST; +const { Search } = Input; +const { Option } = Select; +// import reqwest from 'reqwest'; +/** + * 下拉菜单 + */ +const maps = { + 'categoryMenu': [ + { + 'key': '0', + 'name': '全部', + 'value': '0' + }, + { + 'key': '1', + 'name': '程序设计基础', + 'value': '1' + }, + { + 'key': '2', + 'name': '数据结构与计算', + 'value': '2' + } + ], + 'difficultMenu': [ + { + 'key': '1', + 'name': '简单', + 'value': '1' + }, + { + 'key': '2', + 'name': '中等', + 'value': '2' + }, + { + 'key': '3', + 'name': '困难', + 'value': '3' + } + ], + 'statusMenu': [ + { + 'key': '-1', + 'name': '未做', + 'value': '-1' + }, + { + 'key': '0', + 'name': '未通过', + 'value': '0' + }, + { + 'key': '1', + 'name': '已通过', + 'value': '1' + } + ], + 'come_fromMenu': [ + { + 'key': 'all', + 'name': '全部', + 'value': 'all' + }, + { + 'key': 'mine', + 'name': '我创建的', + 'value': 'mine' + } + ] +}; + +const testMaps = { + category: { + 1: '程序设计基础', + 2: '数据结构与算法' + } +} + +/** + * 表格列 + */ +const options = { + title: '操作', + key: 'action', + fixed: 'right', + width: 100, + render: (text, record) => ( + + + + ), +} +const columns = [ + { + title: '标题', + dataIndex: 'name', + render: (name, record) => {name} + }, + { + title: '分类', + dataIndex: 'category', + width: '20%', + align: 'center', + render: (category) => {category ? testMaps['category'][+category] : '-'} + }, + { + title: '难度', + dataIndex: 'difficult', + align: 'center', + width: '15%', + render: (difficult) => { + if (difficult) { + return {diffText[+difficult]} + } else { + return '-'; + } + } + }, + { + title: '热度', + dataIndex: 'hack_user_lastest_codes_count', + sorter: true, + align: 'center', + width: '10%' + }, + { + title: '通过率', + dataIndex: 'passed_rate', + sorter: true, + align:'right', + width: '10%', + render: val => {`${val}%`} + }, +]; + +class DeveloperHome extends React.PureComponent { + state = { + data: [], + loading: false, + searchParams: { + search: '', // 查询关键字 + 'come_from': '', // 来源 + difficult: '', // 难易度 + status: '', // 未做 + category: '', // 分类 + 'sort_by': '', // 排序 + 'sort_direction': '', // 排序方向 + page: 1, // 当前页数 + limit: 10 // 每页显示条件 + }, + columns: columns, + searchInfo: [] + }; + + componentDidMount() { + // 是否是我的,如果是我的 显示编辑按钮 + const { isMySource } = this.props; + if (isMySource) { + this.handleFilterSearch({come_from: 'mine'}); + let _columns = columns.concat([options]); + this.setState({ + columns: _columns + }); + } else { + this.fetchData(); + } + + const {hacks_count} = this.props.ojListReducer; + this.setState({ + pagination: { + total: hacks_count + } + }); + } + + handleTableChange = (pagination, filters, sorter) => { + const {field, order} = sorter; + const {current, pageSize} = pagination; + this.handleFilterSearch({ + sort_by: field, + sort_direction: order === 'descend' ? 'desc' : 'asc', + page: current, + limit: pageSize + }); + this.props.changePaginationInfo(pagination); + }; + + fetchData = () => { + this.props.fetchOJList(this.state.searchParams); + }; + + /** + * 根据类型获取下拉菜单 + * @param type 类型 + * @param handleClick 处理函数 + */ + getMenuItems = (type, handleClick) => { + return ( + + { + maps[type].map((item) => { + return ( + + {item.name} + + ) + }) + } + + ) + }; + + getOptionsItem = (type) => { + return maps[type].map(item => { + return + }); + } + // 点击条件时加载数据 + handleFilterSearch = (obj) => { + const searchParams = Object.assign({}, this.state.searchParams, obj); + this.setState({ + searchParams: searchParams + }, () => { + this.fetchData(); + }); + } + + // 添加显示搜索条件 + addShowFilterCtx = (obj) => { + const {searchInfo} = this.state + const index = searchInfo.findIndex(item => item.type === obj.type); + let tempArr = [...searchInfo]; + if (index > -1) { + tempArr[index] = obj; + } else { + tempArr.push(obj); + } + this.setState({ + searchInfo: tempArr + }); + } + /** + * 搜索输入框 + * @param value 输入框值 + */ + handleInputSearch = (value) => { + value = value.trim(); + // if (value.length === 0) return; + this.handleFilterSearch({search: value}); + } + // handleSearchChange = (e) => { + // console.log(e.target.value); + // const value = e.target.value.trim(); + // } + // 下拉类别菜单 + handleCategoryMenuClick = (item) => { + this.addShowFilterCtx({ + type: 'category', + key: item.key + }); + this.handleFilterSearch({category: +item.key === 0 ? '' : +item.key}); + } + // 难度下拉 + handleHardMenuClick = (item) => { + this.addShowFilterCtx({ + type: 'difficult', + key: item.key + }); + this.handleFilterSearch({difficult: +item.key}); + } + // 状态下拉 + handleSatusMenuClick = (item) => { + this.addShowFilterCtx({ + type: 'status', + key: item.key + }); + this.handleFilterSearch({status: +item.key}); + } + // 来源下拉 + handleOriginMenuClick = (item) => { + + this.addShowFilterCtx({ + type: 'come_from', + key: item.key + }); + + this.handleFilterSearch({come_from: item.key === 'all' ? '' : item.key}); + + if (item.key !== 'all') { + let _columns = columns.concat([options]); + this.setState({ + columns: _columns + }); + } else { + this.setState({ + columns: columns + }) + } + } + + handleTagClose = (info) => { + + this.handleFilterSearch({[info.type]: ''}); + // 移除 searcInfo 中的数据 + const { type } = info; + let tempArr = [...this.state.searchInfo]; + const index = tempArr.findIndex(item => item.type === type); + if (index > -1) tempArr.splice(index, 1); + this.setState({ + searchInfo: tempArr + }); + if (info.type === 'come_from' && info.key === 'mine') { + this.setState({ + columns: columns + }); + } + } + render () { + // const { testReducer, handleClick } = this.props; + const { + ojListReducer: {hacks_list, top_data, hacks_count}, + pagination + } = this.props; + const {passed_count = 0, simple_count = 0, medium_count = 0, diff_count = 0} = top_data; + const { columns } = this.state; + + // 渲染条件内容 + const renderSearch = () => { + return this.state.searchInfo.map(info => { + let ctx = ''; + const arrs = maps[`${info.type}Menu`]; + arrs.forEach(item => { + if (item.key === info.key) ctx = item.name; + }); + return ( + this.handleTagClose(info)} + >{ctx} + )}); + }; + + return ( +
    +
    +
    +
    +
    +
    +

    已解决 {passed_count} / {hacks_count} 题

    +
    + + + +
    + +
    +
    +
    +
    +
    + + 分类 + + + 难度 + + + 状态 + + + 来源 + +
    + +
    + {renderSearch()} +
    + this.handleInputSearch(value)} + style={{ width: 320, float: 'right' }} + /> +
    + + +
    Math.random()} + dataSource={hacks_list} + pagination={pagination} + onChange={this.handleTableChange} + /> + + + + + + ); + } +} + +/** + * @param {*} state store + * @param {*} ownProps DeveloperHome 中的 props + */ +const mapStateToProps = (state, ownProps) => { + const { + testReducer, + ojListReducer, + commonReducer + } = state; + + const { pagination } = ojListReducer; + + return { + testReducer, + ojListReducer, + isMySource: commonReducer.isMySource, + pagination + } +}; + + +const mapDispatchToProps = (dispatch) => ({ + handleClick: () => dispatch(actions.toggleTodo()), + fetchOJList: (params) => dispatch(actions.getOJList(params)), + changePaginationInfo: (obj) => dispatch(actions.changePaginationInfo(obj)), +}); + +export default connect( + mapStateToProps, + mapDispatchToProps +)(DeveloperHome); +// export default DeveloperHome; diff --git a/public/react/src/modules/developer/components/controlSetting/index.js b/public/react/src/modules/developer/components/controlSetting/index.js new file mode 100644 index 000000000..ba43b5733 --- /dev/null +++ b/public/react/src/modules/developer/components/controlSetting/index.js @@ -0,0 +1,154 @@ +/* + * @Description: 右侧代码块控制台 + * @Author: tangjiang + * @Github: + * @Date: 2019-11-27 16:02:36 + * @LastEditors: tangjiang + * @LastEditTime: 2019-11-28 16:48:50 + */ +import './index.scss'; +import React, { useState, useRef } from 'react'; +import { Tabs, Button, Icon } from 'antd'; +import { connect } from 'react-redux'; +import InitTabCtx from '../initTabCtx'; +import ExecResult from '../execResult'; +import actions from '../../../../redux/actions'; + +const { TabPane } = Tabs; +const ControlSetting = (props) => { + + const { + inputValue, + loading, + submitLoading, + identifier, + excuteState, + commitRecordDetail, + changeLoadingState, + changeSubmitLoadingStatus, + showOrHideControl, + // debuggerCode + updateCode, + onSubmitForm + } = props; + const [defaultActiveKey, setDefaultActiveKey] = useState('1'); // 当前选中的tab + const [showTextResult, setShowTextResult] = useState(false); // 是否点击控制台按钮 + const formRef = useRef(null); + + const classNames = `control_tab ${showTextResult ? 'move_up move_up_final' : 'move_down_final'}`; + + // 切换tab + const handleTabChange = (key) => { + setDefaultActiveKey(key); + } + + // 显示/隐藏tab + const handleShowControl = () => { + setShowTextResult(!showTextResult); + showOrHideControl(!showTextResult); + } + + // 调试代码 + const handleTestCode = (e) => { + // console.log(formRef.current.handleTestCodeFormSubmit); + // 调出控制台界面 + setShowTextResult(true); + showOrHideControl(true); + formRef.current.handleTestCodeFormSubmit(() => { + setDefaultActiveKey('2'); + }); + } + + // 提交 + const handleSubmit = (e) => { + e.preventDefault(); + changeSubmitLoadingStatus(true) + onSubmitForm && onSubmitForm(); + } + + // 处理调度代码 + const handleDebuggerCode = (values) => { + // 改变状态值 + changeLoadingState(true); + // 调用代码保存接口, 成功后再调用调试接口 + updateCode(identifier, values, 'debug'); + // 调用调试接口 + // debuggerCode(identifier, values); + } + + return ( +
    + + + formRef.current = form} + onDebuggerCode={handleDebuggerCode} + /> + + + + + +
    + +

    + + +

    +
    +
    + ); +} + +const mapStateToProps = (state) => { + const {commonReducer, ojForUserReducer} = state; + const { loading, excuteState, submitLoading } = commonReducer; + const { user_program_identifier, commitRecordDetail } = ojForUserReducer; + return { + loading, + submitLoading, + excuteState, + identifier: user_program_identifier, + commitRecordDetail // 提交详情 + }; +}; +// changeSubmitLoadingStatus +const mapDispatchToProps = (dispatch) => ({ + showOrHideControl: (flag) => dispatch(actions.showOrHideControl(flag)), + changeLoadingState: (flag) => dispatch(actions.changeLoadingState(flag)), + changeSubmitLoadingStatus: (flag) => dispatch(actions.changeSubmitLoadingStatus(flag)), + debuggerCode: (identifier, values) => dispatch(actions.debuggerCode(identifier, values)), + // inputValue 输入值 + updateCode: (identifier, inputValue, type) => dispatch(actions.updateCode(identifier, inputValue, type)) +}); + +export default connect( + mapStateToProps, + mapDispatchToProps +)(ControlSetting); diff --git a/public/react/src/modules/developer/components/controlSetting/index.scss b/public/react/src/modules/developer/components/controlSetting/index.scss new file mode 100644 index 000000000..0c7f726f5 --- /dev/null +++ b/public/react/src/modules/developer/components/controlSetting/index.scss @@ -0,0 +1,103 @@ +.pane_control_area{ + position: absolute; + bottom: 0; + width: 100%; + // height: 56px; + .control_tab{ + position: absolute; + bottom: -325px; + width: 100%; + // transition: all .2s; + opacity: 0; + // animation: .3s ease-in-out move_up; + // &.active{ + // bottom: 0; + // opacity: 1; + // } + &.move_up{ + animation: move_up .3s ease-in; + } + &.move_up_final { + bottom: 0; + opacity: 1; + } + &.move_down{ + animation: move_down .3s ease-in-out; + } + &.move_down_final{ + bottom: -325px; + opacity: 0; + } + } +} + + +.ant-tabs-bar{ + padding: 0 10px; + margin: 0px; + border-bottom: transparent; +} +.ant-tabs-ink-bar{ + bottom: 1px; +} +// .tab_ctx_area.pos_center{ +// background: #222; +// } +.pane_control_opts{ + display: flex; + justify-content: space-between; + align-items: center; + z-index: 20; + height: 56px; + padding-right: 30px; + padding-left: 10px; + background: #000; +} + +.setting_drawer{ + .setting_h2{ + line-height: 50px; + } + .setting_desc{ + display: flex; + justify-content: space-between; + margin-bottom: 10px; + .flex_item{ + line-height: 32px; + font-size: 12px; + } + } +} + + +@keyframes move_up { + 0%{ + opacity: 0; + // bottom: -325px; + } + 90%{ + opacity: 0.5; + // bottom: 0px; + } + 100%{ + opacity: 1; + bottom: 0; + } +} + +@keyframes move_down{ + 0%{ + opacity: 1; + bottom: 0 + } + 10%{ + opacity: .2; + } + 20%{ + opacity: 0; + } + 100%{ + opacity: 0; + bottom: -325px; + } +} \ No newline at end of file diff --git a/public/react/src/modules/developer/components/execResult/index.js b/public/react/src/modules/developer/components/execResult/index.js new file mode 100644 index 000000000..c659021ed --- /dev/null +++ b/public/react/src/modules/developer/components/execResult/index.js @@ -0,0 +1,134 @@ +/* + * @Description: 执行结果 + * @Author: tangjiang + * @Github: + * @Date: 2019-11-28 08:44:54 + * @LastEditors: tangjiang + * @LastEditTime: 2019-11-28 15:14:42 + */ +import './index.scss'; +import React, { useState, useEffect } from 'react'; +import { Icon } from 'antd'; +import CONST from '../../../../constants'; + +const {reviewResult} = CONST; +function ExecResult (props) { + + const { excuteState, excuteDetail } = props; + // 指定渲染初始, 加载中, 加载完成页面内容 + const renderInit = () => ( +
    + 请先点击“调试代码”运行您的代码 +
    + ); + const renderLoading = () => ( +
    + + + 加载中... + +
    + ); + const readerLoaded = () => ( +
    + + + 加载完成 + +
    + ); + const renderFinish = () => { + const { + error_line, + error_msg, + execute_memory, + execute_time, + input, + output, + status, + expected_output + } = codeResult; + + const excuteHeader = (state) => { + const review_class = state === 0 ? `excute_suc` : `excute_err`; + return ( +

    + 执行结果: + {reviewResult[`${state}`]} +

    + ) + } + + const excuteCtx = (state) => { + if (state === 0) { + return ( + +

    输入: {input}

    +

    输出: {output}

    +
    + ); + } else if (state === 4){ + return ( +

    + {error_msg} +

    + ) + } else if (state === -1) { + return ( + +

    输入: {input}

    +

    输出: {output}

    +

    预期输出: {expected_output}

    +
    + ) + } else if (state === 5) { + return ( + +

    执行出错信息: {error_msg}

    +

    最后执行的输入: {input}

    +
    + ) + } + } + return ( +
    + {excuteHeader(status)} + {excuteCtx(status)} +
    + ); + }; + + // 渲染状态 + const [renderCtx, setRenderCtx] = useState(() => { + return function () { + return renderInit(); + } + }); + // 提交记录详情 + const [codeResult, setCodeResult] = useState({}) + + // 渲染状态变化时渲染相应的内容 + useEffect(() => { + if ('loading' === excuteState) { + setRenderCtx(() => (renderLoading)); + } else if ('loaded' === excuteState) { + setRenderCtx(() => (readerLoaded)); + } else if ('finish' === excuteState) { + setRenderCtx(() => (renderFinish)); + } + }, [excuteState]); + + // 提交详情变化时 + useEffect(() => { + console.log('提交记录详情=====>>>>>', excuteDetail); + setCodeResult(excuteDetail); + }, [excuteDetail]); + + return ( + + {renderCtx()} + + ) +} + +export default ExecResult; diff --git a/public/react/src/modules/developer/components/execResult/index.scss b/public/react/src/modules/developer/components/execResult/index.scss new file mode 100644 index 000000000..1a0c2d9f2 --- /dev/null +++ b/public/react/src/modules/developer/components/execResult/index.scss @@ -0,0 +1,47 @@ +.excute_result_area{ + display: flex; + height: 224px; + width: 100%; + + &.excute_flex_center{ + align-items: center; + justify-content: center; + } + + .init_ctx{ + color: #666666; + } + .loading_ctx, + .loaded_ctx{ + display: flex; + flex-direction: column; + color: #1890ff; + .ctx_icon{ + font-size: 40px; + margin-bottom: 10px; + } + } +} + +.excute_result_info{ + padding: 20px 30px; + color: #fff; + height: 220px; + /* overflow-y: auto; */ + overflow-y: auto; + + .result_info_style{ + word-wrap: break-word; + color: #ccc; + } + + .excute_head_area{ + line-height: 30px; + .excute_suc{ + color: #28BD8B; + } + .excute_err{ + color: #E51C24; + } + } +} \ No newline at end of file diff --git a/public/react/src/modules/developer/components/initTabCtx/index.js b/public/react/src/modules/developer/components/initTabCtx/index.js new file mode 100644 index 000000000..c4b989354 --- /dev/null +++ b/public/react/src/modules/developer/components/initTabCtx/index.js @@ -0,0 +1,92 @@ +/* + * @Description: 自定义测试化用例 + * @Author: tangjiang + * @Github: + * @Date: 2019-11-27 19:46:14 + * @LastEditors: tangjiang + * @LastEditTime: 2019-11-27 23:49:21 + */ +import './index.scss'; +import React, { useState, useEffect, useRef, useImperativeHandle, forwardRef } from 'react'; +import { Form, Input} from 'antd'; +const FormItem = Form.Item; +const { TextArea } = Input; + +/** + * @description 初始化测试用例: 当有inputValue值时, 显示表单输入框,否则显示文本提示信息 + * @param {*} props + * props: { + * inputValue: '' // 初始值 + * onDebuggerCode: func // 点击调试代码执行函数 + * } + */ +function InitTabCtx (props, ref) { + // useImperativeHandle // 让子组件只暴露一定的api给父组件 + const tabRef = useRef(null); + + const { inputValue, onDebuggerCode } = props; + + useImperativeHandle(ref, () => ({ + handleTestCodeFormSubmit: (cb) => { + console.log('父组件调用我啦~~~~~~~~~'); + _handleTestCodeFormSubmit(cb); + } + })); + + // 渲染文本提示信息 + const renderText = () => (请在这里添加测试用例,点击“调试代码”时将从这里读取输入来测试你的代码...); + // 渲染表单信息 + const renderForm = () => { + const {form: { getFieldDecorator } } = props; + return ( + + + { + getFieldDecorator('input', { + rules: [ + { required: true, message: '输入值不能为空'} + ], + initialValue: inputValue + })( +
    +
    + +

    +

    + + +
    +
    +

    技术平台

    + + +
    + * +
    + +

    + 列表中没有? + 申请新建 +

    + + +
    +
  • + + +
  • +
    {this.state.languagewritetype===true?"请填写该镜像语言":""}
    +
  • + + +
  • +
    {this.state.systemenvironmenttype===true?"请填写该镜像语言系统环境":""}
    +
  • + + + +
  • +
    {this.state.testcoderunmodetype===true?"请填写该镜像测试代码运行方式":""}
    +
  • + +
    + + + 上传附件 + (单个文件50M以内) + +
    +
  • +
    + {this.state.attachmentidstype===true?"请上传附件":""} +
    +
  • + this.sendhideModaly()} + >取消 + +
  • +
    +
    + +
    + + + + + +
    +

    新建申请已提交,请等待管理员的审核

    +
  • 我们将在1-2个工作日内与您联系 +
  • +
    +
    + 知道啦 +
    +
    +
    +
    + +
    + +
    +
    + 必填项 +
    + {/*

    请在配置页面完成后续的评测脚本设置操作

    */} + +
    +
    + {/*
    */} + {/*
    */} +
    +

    评测脚本

    +
    + + +
    +

    原有脚本将被新的脚本覆盖,无法撤销

    +

    是否确认执行覆盖操作

    +
    + + +
    + + +

    评测脚本生成成功!

    + +
    + + { + this.props.identity<5||this.props.power==true? + 使用自定义脚本 : "" + } +
    + this.testscripttip(0)}> +
    + +
    +

    + 使用自定义模板,平台无法自动更新脚本,
    + 请在关卡创建完后手动更新脚本中的必填参
    + 数和以下2个数组元素:
    + challengeProgramNames
    + sourceClassNames

    + 示例:有2个关卡的实训

    + 各关卡的待编译文件为:
    + src/step1/HelloWorld.java
    + src/step2/Other.java

    + 各关卡的编译后生成的执行文件为:
    + step1.HelloWorld
    + step2.Other

    + 则数组元素更新如下:
    + challengeProgramNames=("src/step1/
    + HelloWorld.java" "src/step2/Other.java")
    + sourceClassNames=("step1.HelloWorld
    + " "step2.Other")

    + 其它参数可按实际需求定制 +

    +
    +

    + this.testscripttip(1)}>知道了 +

    +
    +
    + + +
    +
  • + + +

    执行命令不能为空

    +
  • + +
  • + + +
  • +
    +
    +
    +
    + +
    +
    + * +
    + + +
    + {/**/} + +
    + + + {/*
    */} + {/*{evaluate_script===undefined?"":evaluate_script}*/} + + {/*
    */} + + + +
    + +
    +
    +
    + + 必填项 +
    +

    +

    +
    +
    + + {/*
    */} + {/***/} + + {/*

    程序最大执行时间

    */} + + {/* 秒*/} + + {/*
    */} + {/*必填项*/} + {/*
    */} + {/*
    */} + + {/*
    + * + +

    Pod存活时间

    + + + +
    + 必填项 +
    +
    */} + + +
    +

    命令行

    + + 无命令行窗口 (选中则不给学员的实践任务提供命令窗口) + 命令行练习窗口 (选中则给学员提供用于练习操作的命令行窗口) + 命令行评测窗口 (选中则给学员提供用于关卡评测的命令行窗口) + + 多个命令行窗口(选中则允许学员同时开启多个命令行窗口) + + +
    + +
    +

    公开程度

    + + 对所有公开 (选中则所有已被试用授权的用户可以学习) + 对指定单位公开 (选中则下方指定单位的已被试用授权的用户可以学习) + + +
    +
    +
    +
    +
    + +
    + (搜索并选中添加单位名称) +
    + {/*+*/} + {/*添加*/} +
    + +
    + + {/*{*/} + {/*scope_partment===undefined?"":scope_partment.map((item,key)=>{*/} + {/*return(*/} + {/*
    */} + {/*this.deleteScopeInput(key)} style={{ color: 'rgba(0,0,0,.25)' }} />}*/} + {/*value={item}*/} + {/*/>*/} + {/*
    */} + + {/*)*/} + {/*})*/} + {/*}*/} +
    + + + 请选择需要公开的单位 + +
    +
    +
    + +
    +

    发布信息

    + +
    + * + 面向学员: + +
    + +
    + 实训难易度定位,不限定用户群体 +
    + 必填项 +
    + +
    +
    + 复制: + + + + +
    + +
    + 跳关: + + + + +
    +
    + 测试集解锁: + + + + +
    + + {!code_hidden && !hide_code &&
    + 代码开放修改: + + + + +
    } + +
    + 隐藏代码窗口: + + + + +
    + +
    + 代码目录隐藏: + + + + +
    + + { (vnc || webssh == 2) &&
    + 私密版本库: + + + + +
    } + +
    + 禁用复制粘贴: + + + + +
    + +
    + 开启时间: + + + + +
    + + {this.props.identity<3?
    + VNC图形化: + + + + +
    :""} + {this.props.identity<3 && vnc ?
    + VNC图形化评测: + + + + +
    :""} + + + +
    + + {this.props.identity<3?
    +

    服务配置

    + { shixun_service_configs&&shixun_service_configs.map((item,key)=>{ + + return( +
    +
    +
    + {item.name} + {/*this.Deselectlittle(item.mirror_repository_id)}>*/} +
    +
    + +
    + this.setConfigsInputs(e,key,1)} + className="panel-box-sizing task-form-100 task-height-40" placeholder="请输入类别名称" /> +
    +
    +
    +
    + +
    + this.setConfigsInputs(e,key,2)} + className="panel-box-sizing task-form-100 task-height-40" placeholder="请输入类别名称" /> +
    +
    +
    +
    + +
    + this.setConfigsInputs(e,key,3)} + className="panel-box-sizing task-form-100 task-height-40" placeholder="请输入类别名称" /> +
    +
    +
    +
    + +
    + this.setConfigsInputs(e,key,4)} + className="panel-box-sizing task-form-100 task-height-40" placeholder="请输入类别名称" /> +
    + +
    +
    +
    +
    + ) + + })} +
    :""} + +

    + { + // this.props.identity<4&&this.props.status==0? + this.props.identity<5? +

    + 保存 + 取消 +
    :"" + } + +

    + + + ); + } +} + + diff --git a/public/react/src/tpm/TPMsettings/css/TPMsettings.css b/public/react/src/tpm/TPMsettings/css/TPMsettings.css new file mode 100644 index 000000000..8047bbde8 --- /dev/null +++ b/public/react/src/tpm/TPMsettings/css/TPMsettings.css @@ -0,0 +1,113 @@ +.radioStyle{ + display: block; + height: 30px; + } +#settingsMarkdown{ + background:transparent; +} +#challenge_begin{ + height: 30px; + line-height: 30px; +} +#shixundescription .CodeMirror{ + margin-top: 31px !important; + height: 364px !important; +} +#shixundescription .editormd-preview{ + width:578px !important; + top: 40px !important; + height: 364px !important; +} + +#shixunmemoMD .CodeMirror{ + margin-top: 31px !important; + height: 578px !important; +} + +#shixunmemoMD .editormd-preview{ + width: 578px !important; + top: 40px !important; + height: 578px !important; +} + +.radioStyle { + display: block; + height: 30px; +} + +a.white-btn.use_scope-btn:hover { + color: #FFF !important; +} + +.shixunScopeInput { + width: 218px; + height: 33px; + display: block; + margin-bottom: 15px; +} + +.ant-modal-title { + text-align: center; +} + +a.newuse_scope-btn:hover { + border: 1px solid #F06200; + color: #fff !important; + background: #FF7500; +} + +a.newuse_scope-btn { + border: 1px solid #FF7500; + color: #FF7500 !important; +} + +.tpmprompt { + padding-left: 20px; + margin-top: -4px; +} +.ml36{ + margin-left: 26px; +} + +#shixunmemoMD{ + width:98% !important; + height: 620px !important; +} +#shixunmemoMDs{ + width: 98% !important; + height: 420px !important; +} +#shixunmemoMDs .CodeMirror { + /* width: 548px !important; */ + margin-top: 31px !important; + height: 402px !important; +} +.pdr20{ + padding-right:20px; +} + +.nonemodel{ + width: 59%; + height: 468px; + /*background: rgba(0, 0, 0, 0.65);*/ + background: #f5f5f5; + position: absolute; + z-index: 100; + opacity: 0.5; + left: 21.5%; +} + +.shixunmemoMDdiv{ + width: 99%; + height: 615px; +} + +.shixunspanred{ + margin-left: 142px; + margin-top: 5px; + margin-bottom: 5px; +} + +.ml82{ + margin-left:82px; +} diff --git a/public/react/src/tpm/beian.png b/public/react/src/tpm/beian.png new file mode 100755 index 000000000..9f763946d Binary files /dev/null and b/public/react/src/tpm/beian.png differ diff --git a/public/react/src/tpm/challengesnew/TPMMDEditor.js b/public/react/src/tpm/challengesnew/TPMMDEditor.js new file mode 100644 index 000000000..11b88a037 --- /dev/null +++ b/public/react/src/tpm/challengesnew/TPMMDEditor.js @@ -0,0 +1,355 @@ +import React, {Component} from 'react'; + +import {Input, Select, Radio, Checkbox, Popconfirm, message, Modal} from 'antd'; + +import {BrowserRouter as Router, Route, Link, Switch} from "react-router-dom"; + +// import "antd/dist/antd.css"; + +import { getImageUrl, toPath, getUrl } from 'educoder'; +import '../../courses/css/Courses.css' + +import axios from 'axios'; + +import './css/TPMchallengesnew.css'; +require('codemirror/lib/codemirror.css'); + +let origin = getUrl(); + +let path = '/editormd/lib/' + path = getUrl("/editormd/lib/") +const $ = window.$; + +let timeout; + +let currentValue; + +const Option = Select.Option; + +const RadioGroup = Radio.Group; + + + +// 保存数据 +function md_add_data(k,mdu,d){ + window.sessionStorage.setItem(k+mdu,d); +} + +// 清空保存的数据 +function md_clear_data(k,mdu,id){ + window.sessionStorage.removeItem(k+mdu); + var id1 = "#e_tip_"+id; + var id2 = "#e_tips_"+id; + if(k == 'content'){ + $(id2).html(" "); + }else{ + $(id1).html(" "); + } +} +window.md_clear_data = md_clear_data +// editor 存在了jquery对象上,应用不需要自己写md_rec_data方法了 +function md_rec_data(k, mdu, id) { + if (window.sessionStorage.getItem(k + mdu) !== null) { + var editor = $("#e_tips_" + id).data('editor'); + editor.setValue(window.sessionStorage.getItem(k + mdu)); + // debugger; + // /shixuns/b5hjq9zm/challenges/3977/tab=3 setValue可能导致editor样式问题 + md_clear_data(k, mdu, id); + } +} +window.md_rec_data = md_rec_data; + +function md_elocalStorage(editor,mdu,id){ + if (window.sessionStorage){ + var oc = window.sessionStorage.getItem('content'+mdu); + if(oc !== null && oc != editor.getValue()){ + console.log("#e_tips_"+id) + $("#e_tips_"+id).data('editor', editor); + var h = '您上次有已保存的数据,是否恢复 ? / 不恢复'; + $("#e_tips_"+id).html(h); + } + setInterval(function() { + var d = new Date(); + var h = d.getHours(); + var m = d.getMinutes(); + var s = d.getSeconds(); + h = h < 10 ? '0' + h : h; + m = m < 10 ? '0' + m : m; + s = s < 10 ? '0' + s : s; + if(editor.getValue().trim() != ""){ + md_add_data("content",mdu,editor.getValue()); + var id1 = "#e_tip_"+id; + var id2 = "#e_tips_"+id; + + var textStart = " 数据已于 " + var text = textStart + h + ':' + m + ':' + s +" 保存 "; + // 占位符 + var oldHtml = $(id2).html(); + if (oldHtml && oldHtml != ' ' && oldHtml.startsWith(textStart) == false) { + $(id2).html( oldHtml.split(' (')[0] + ` (${text})`); + } else { + $(id2).html(text); + } + // $(id2).html(""); + } + },10000); + + }else{ + $("#e_tip_"+id).after('您的浏览器不支持localStorage.无法开启自动保存草稿服务,请升级浏览器!'); + } +} + + +function create_editorMD(id, width, high, placeholder, imageUrl, callback, initValue, + onchange, watch, { noStorage, showNullButton, emoji }, that) { + // 还是出现了setting只有一份,被共用的问题 + + var editorName = window.editormd(id, { + width: width, + height: high===undefined?400:high, + path: path, // "/editormd/lib/" + markdown : initValue, + + dialogLockScreen: false, + watch:watch===undefined?true:watch, + syncScrolling: "single", + tex: true, + tocm: true, + emoji: !!emoji , + taskList: true, + codeFold: true, + searchReplace: true, + htmlDecode: "style,script,iframe", + sequenceDiagram: true, + autoFocus: false, + + // mine + + toolbarIcons: function (mdEditor) { + let react_id = `react_${mdEditor.id}`; + const __that = window[react_id] + + // Or return editormd.toolbarModes[name]; // full, simple, mini + // Using "||" set icons align right. + const icons = ["bold", "italic", "|", "list-ul", "list-ol", "|", "code", "code-block", "link", "|", "testIcon", "testIcon1", '|', "image", "table", '|', "watch", "clear"]; + // 试卷处用到的填空题新增按钮 + if (__that.props.showNullButton) { + icons.push('nullBtton') + } + return icons + }, + toolbarCustomIcons: { + testIcon: "
    ", + testIcon1: "
    ", + nullBtton: "
    点击插入填空项
    ", + }, + //这个配置在simple.html中并没有,但是为了能够提交表单,使用这个配置可以让构造出来的HTML代码直接在第二个隐藏的textarea域中,方便post提交表单。 + saveHTMLToTextarea: true, + // 用于增加自定义工具栏的功能,可以直接插入HTML标签,不使用默认的元素创建图标 + dialogMaskOpacity: 0.6, + placeholder: placeholder, + imageUpload: true, + imageFormats: ["jpg", "jpeg", "gif", "png", "bmp", "webp", "JPG", "JPEG", "GIF", "PNG", "BMP", "WEBP"], + imageUploadURL: imageUrl,//url + onchange: onchange, + onload: function() { + let _id = this.id // 如果要使用this,这里不能使用箭头函数 + let _editorName = this; + let react_id = `react_${_editorName.id}`; + const __that = window[react_id] + + // this.previewing(); + // let _id = id; + $("#" + _id + " [type=\"latex\"]").bind("click", function () { + _editorName.cm.replaceSelection("```latex"); + _editorName.cm.replaceSelection("\n"); + _editorName.cm.replaceSelection("\n"); + _editorName.cm.replaceSelection("```"); + var __Cursor = _editorName.cm.getDoc().getCursor(); + _editorName.cm.setCursor(__Cursor.line - 1, 0); + }); + + $("#" + _id + " [type=\"inline\"]").bind("click", function () { + _editorName.cm.replaceSelection("`$$$$`"); + var __Cursor = _editorName.cm.getDoc().getCursor(); + _editorName.cm.setCursor(__Cursor.line, __Cursor.ch - 3); + _editorName.cm.focus(); + }); + $("[type=\"inline\"]").attr("title", "行内公式"); + $("[type=\"latex\"]").attr("title", "多行公式"); + + if (__that.props.showNullButton) { + const NULL_CH = '▁' + // const NULL_CH = '〇' + // const NULL_CH = '🈳' + + $("#" + _id + " [type=\"nullBtton\"]").bind("click", function () { + _editorName.cm.replaceSelection(NULL_CH); + // var __Cursor = _editorName.cm.getDoc().getCursor(); + // _editorName.cm.setCursor(__Cursor.line - 1, 0); + }); + } + + if (noStorage == true) { + + } else { + md_elocalStorage(_editorName, `MDEditor__${_id}`, _id); + } + + callback && callback(_editorName) + } + }); + return editorName; +} + + +export default class TPMMDEditor extends Component { + constructor(props) { + super(props) + this.state = { + initValue: '' + } + } + componentDidUpdate(prevProps, prevState) { + // 不能加,影响了试卷填空题 + // if (this.props.initValue != prevProps.initValue) { + // this.answers_editormd.setValue(this.props.initValue) + // } + } + + // react_mdEditor_ + componentDidMount = () => { + const { mdID, initValue, placeholder, showNullButton} = this.props; + + let _id = `mdEditor_${mdID}` + this.contentChanged = false; + const _placeholder = placeholder || ""; + // amp; + // 编辑时要传memoId + const imageUrl = `/api/attachments.json`; + // 创建editorMd + let react_id = `react_${_id}`; + // 将实例存到了window + window[react_id] = this + const answers_editormd = create_editorMD(_id, '100%', this.props.height, _placeholder, imageUrl, (_editorName) => { + const __editorName = _editorName; + react_id = `react_${__editorName.id}`; + const that = window[react_id] + + // 一个延迟的recreate或resize,不加这段代码,md初始化可能会出现样式问题 + setTimeout(() => { + if (that.props.needRecreate == true) { + __editorName.recreate() // 注意 必须在setValue之前触发,不然会清空 + } else { + __editorName.resize() + } + console.log('timeout', __editorName.id) + __editorName.cm && __editorName.cm.refresh() + }, that.props.refreshTimeout || 500) + if (this.props.noSetValueOnInit) { + that.onEditorChange() + } else { + if (that.props.initValue != undefined && that.props.initValue != '') { + __editorName.setValue(that.props.initValue) + } + if (that.state.initValue) { + __editorName.setValue(that.state.initValue) + } + } + + __editorName.cm.on("change", (_cm, changeObj) => { + that.contentChanged = true; + if (that.state.showError) { + that.setState({showError: false}) + } + that.onEditorChange() + }) + that.props.onCMBlur && __editorName.cm.on('blur', () => { + that.props.onCMBlur() + }) + that.props.onCMBeforeChange && __editorName.cm.on('beforeChange', (cm,change) => { + that.props.onCMBeforeChange(cm,change) + }) + that.answers_editormd = __editorName; + // 这里应该可以去掉了,方便调试加的 + window[__editorName.id+'_'] = __editorName; + }, initValue, this.onEditorChange,this.props.watch, { + noStorage: this.props.noStorage, + showNullButton: this.props.showNullButton, + emoji: this.props.emoji + }, this); + + } + // 用在form里时,validate失败时出现一个红色边框 + showError = () => { + this.setState({showError: true}) + } + onEditorChange = () => { + if (!this.answers_editormd) return; + const val = this.answers_editormd.getValue(); + //console.log('onEditorChange', this.props.id, val) + try { + this.props.onChange && this.props.onChange(val) + } catch(e) { + // http://localhost:3007/courses/1309/common_homeworks/6566/setting + // 从这个页面,跳转到编辑页面,再在编辑页面点击返回的时候,这里会报错 + console.error('出错') + console.error(e) + } + } + resize = () => { + if (!this.answers_editormd) { // 还未初始化 + return; + } + this.answers_editormd.resize() + this.answers_editormd.cm && this.answers_editormd.cm.refresh() + this.answers_editormd.cm.focus() + } + + getValue = () => { + try { + return this.answers_editormd.getValue() + } catch (e) { + return '' + } + } + setValue = (val) => { + try { + this.answers_editormd.setValue(val) + } catch (e) { + // TODO 这里多实例的时候,前一个实例的state会被后面这个覆盖 参考NewWork.js http://localhost:3007/courses/1309/homework/9300/edit/1 + // 未初始化 + this.setState({ initValue: val }) + } + } + + render() { + + let { + showError + } = this.state; + let { mdID, className, noStorage, imageExpand } = this.props; + let _style = {} + if (showError) { + _style.border = '1px solid red' + } + return ( + +
    + {/* padding10-20 */} +
    + +
    +
    +
    +
    +
    + {noStorage == true ? ' ' :

     

    } + {/* {noStorage == true ? ' ' :

     

    } */} +
    +
    + ) + } +} + + diff --git a/public/react/src/tpm/challengesnew/TPManswer.js b/public/react/src/tpm/challengesnew/TPManswer.js new file mode 100644 index 000000000..bc9523422 --- /dev/null +++ b/public/react/src/tpm/challengesnew/TPManswer.js @@ -0,0 +1,366 @@ +import React, {Component} from 'react'; + +import {Input, Select, Radio, Checkbox, Popconfirm, message, Modal} from 'antd'; + +import {BrowserRouter as Router, Route, Link, Switch} from "react-router-dom"; + +// import "antd/dist/antd.css"; + +import { getImageUrl, toPath, getUrl } from 'educoder'; + +import axios from 'axios'; + +import './css/TPMchallengesnew.css'; + +let origin = getUrl(); + +let path = getUrl("/editormd/lib/") + +const $ = window.$; + +let timeout; + +let currentValue; + +const Option = Select.Option; + +const RadioGroup = Radio.Group; + + +// 恢复数据 +function md_rec_data(k,mdu,id, editor){ + if(window.sessionStorage.getItem(k+mdu) !== null){ + editor.setValue(window.sessionStorage.getItem(k+mdu)); + md_clear_data(k,mdu,id); + } +} + +// 保存数据 +function md_add_data(k,mdu,d){ + window.sessionStorage.setItem(k+mdu,d); +} + +// 清空保存的数据 +function md_clear_data(k,mdu,id){ + window.sessionStorage.removeItem(k+mdu); + var id1 = "#e_tip_"+id; + var id2 = "#e_tips_"+id; + if(k == 'content'){ + $(id2).html(""); + }else{ + $(id1).html(""); + } +} + +function md_elocalStorage(editor,mdu,id){ + if (window.sessionStorage){ + var oc = window.sessionStorage.getItem('content'+mdu); + if(oc !== null ){ + console.log("#e_tips_"+id) + $("#e_tips_"+id).data('editor', editor); + var h = '您上次有已保存的数据,是否恢复 ? / 不恢复'; + $("#e_tips_"+id).html(h); + } + setInterval(function() { + var d = new Date(); + var h = d.getHours(); + var m = d.getMinutes(); + var s = d.getSeconds(); + h = h < 10 ? '0' + h : h; + m = m < 10 ? '0' + m : m; + s = s < 10 ? '0' + s : s; + if(editor.getValue().trim() != ""){ + md_add_data("content",mdu,editor.getValue()); + var id1 = "#e_tip_"+id; + var id2 = "#e_tips_"+id; + + $(id1).html(" 数据已于 " + h + ':' + m + ':' + s +" 保存 "); + $(id2).html(""); + } + },10000); + + }else{ + $("#e_tip_"+id).after('您的浏览器不支持localStorage.无法开启自动保存草稿服务,请升级浏览器!'); + } +} + + +function create_editorMD(id, width, high, placeholder, imageUrl, callback) { + var editorName = window.editormd(id, { + width: width, + height: high, + path: path, // "/editormd/lib/" + + syncScrolling: "single", + tex: true, + tocm: true, + emoji: true, + taskList: true, + codeFold: true, + searchReplace: true, + htmlDecode: "style,script,iframe", + sequenceDiagram: true, + autoFocus: false, + toolbarIcons: function () { + // Or return editormd.toolbarModes[name]; // full, simple, mini + // Using "||" set icons align right. + return ["bold", "italic", "|", "list-ul", "list-ol", "|", "code", "code-block", "|", "testIcon", "testIcon1", '|', "image", "table", '|', "watch", "clear"] + }, + toolbarCustomIcons: { + testIcon: "
    ", + testIcon1: "
    " + }, + //这个配置在simple.html中并没有,但是为了能够提交表单,使用这个配置可以让构造出来的HTML代码直接在第二个隐藏的textarea域中,方便post提交表单。 + saveHTMLToTextarea: true, + // 用于增加自定义工具栏的功能,可以直接插入HTML标签,不使用默认的元素创建图标 + dialogMaskOpacity: 0.6, + placeholder: placeholder, + imageUpload: true, + imageFormats: ["jpg", "jpeg", "gif", "png", "bmp", "webp", "JPG", "JPEG", "GIF", "PNG", "BMP", "WEBP"], + imageUploadURL: imageUrl,//url + onload: function () { + // this.previewing(); + $("#" + id + " [type=\"latex\"]").bind("click", function () { + editorName.cm.replaceSelection("```latex"); + editorName.cm.replaceSelection("\n"); + editorName.cm.replaceSelection("\n"); + editorName.cm.replaceSelection("```"); + var __Cursor = editorName.cm.getDoc().getCursor(); + editorName.cm.setCursor(__Cursor.line - 1, 0); + }); + + $("#" + id + " [type=\"inline\"]").bind("click", function () { + editorName.cm.replaceSelection("`$$$$`"); + var __Cursor = editorName.cm.getDoc().getCursor(); + editorName.cm.setCursor(__Cursor.line, __Cursor.ch - 3); + editorName.cm.focus(); + }); + $("[type=\"inline\"]").attr("title", "行内公式"); + $("[type=\"latex\"]").attr("title", "多行公式"); + + md_elocalStorage(editorName, `answers__${id}`, "Memoanswers"); + + callback && callback() + } + }); + return editorName; +} + + +export default class TPManswer extends Component { + constructor(props) { + super(props) + this.state = { + choice_url: undefined, + practice_url: undefined, + go_back_url: undefined, + value: 1, + answer:"", + id:undefined, + checkpointId:undefined, + power: false, + prev_challenge: undefined, + next_challenge: undefined, + } + } + + answerMD(initValue, id) { + + this.contentChanged = false; + const placeholder = ""; + // amp; + // 编辑时要传memoId + const imageUrl = `/api/attachments.json`; + // 创建editorMd + + const answers_editormd = create_editorMD(id, '100%', 400, placeholder, imageUrl, () => { + setTimeout(() => { + answers_editormd.resize() + answers_editormd.cm && answers_editormd.cm.refresh() + }, 500) + + if (initValue != undefined) { + answers_editormd.setValue(initValue) + } + answers_editormd.cm.on("change", (_cm, changeObj) => { + console.log('....contentChanged') + this.contentChanged = true; + }) + }); + this.answers_editormd = answers_editormd; + window.answers_editormd = answers_editormd; + + } + + componentDidMount() { + let id = this.props.match.params.shixunId; + let checkpointId=this.props.match.params.checkpointId; + + let newchoice_url= "/shixuns/"+id+"/challenges/newquestion"; + let newpractice_url= "/shixuns/"+id+"/challenges/new"; + let newgo_back_url="/shixuns/"+id+"/challenges"; + this.setState({ + shixunId:id, + checkpointId:checkpointId + }) + + + let url = "/shixuns/" + id + "/challenges/" + checkpointId + "/edit.json?tab=2"; + axios.get(url).then((response) => { + let newprev_challenge = response.data.prev_challenge; + let next_challenge = response.data.next_challenge; + if (newprev_challenge != undefined) { + if(newprev_challenge.st===0){ + newprev_challenge = "/shixuns/" + id + "/challenges/" + newprev_challenge.id + "/editcheckpoint"; + }else{ + newprev_challenge = "/shixuns/" + id + "/challenges/" + newprev_challenge.id + "/editquestion"; + } + } + if (next_challenge != undefined) { + + if(next_challenge.st===0){ + next_challenge = "/shixuns/" + id + "/challenges/" + next_challenge.id+ "/editcheckpoint"; + }else{ + next_challenge = "/shixuns/" + id + "/challenges/" + next_challenge.id+ "/editquestion"; + } + } + this.setState({ + answer:response.data.answer, + power: response.data.power, + choice_url: newchoice_url, // 导航中的新建选择题url + practice_url: newpractice_url, //string 导航中新建实践题url + go_back_url: newgo_back_url, //string 导航中的返回url + position: response.data.position, //int 关卡位置,导航栏中的第几关 + prev_challenge: newprev_challenge, + next_challenge: next_challenge, + }) + + if(response.data.power===false){ + this.props.showSnackbar("没有权限修改"); + } + if(response.data.answer===undefined||response.data.answer===null){ + this.answerMD("", "answerMD"); + }else{ + this.answerMD(response.data.answer, "answerMD"); + } + + }).catch((error) => { + console.log(error) + }); + } + + challenge_answer_submit=()=> { + let id = this.props.match.params.shixunId; + let{checkpointId}=this.state; + let url = "/shixuns/"+id+"/challenges/"+checkpointId+".json"; + const answer_editormdvalue = this.answers_editormd.getValue(); + + axios.put(url,{ + tab:2, + identifier:id, + id:checkpointId, + challenge:{ + answer:answer_editormdvalue + } + } + ).then((response) => { + this.props.showSnackbar(response.data.messages); + + }).catch((error) => { + console.log(error) + }); + } + + render() { + + let { + choice_url, + practice_url, + go_back_url, + position, + task_pass_default, + submit_url, + shixunId, + checkpointId, + power, + prev_challenge, + next_challenge, + } = this.state; + let tab1url="/shixuns/" + shixunId + "/challenges/"+checkpointId+"/editcheckpoint"; + let tab2url="/shixuns/" + shixunId + "/challenges/"+checkpointId+"/tab=2"; + let tab3url="/shixuns/" + shixunId + "/challenges/"+checkpointId+"/tab=3"; + // console.log(this.props) + return ( + +
    +
    + + + + 第{position}关 + 返回 + + {prev_challenge === undefined ? "" : + 上一关 + } + + {next_challenge === undefined ? "" : + 下一关 + } + + + 实践类型 + + 选择题类型 + +
    + +
    + +
  • + 本关任务 +
  • + +
  • + 评测设置 +
  • + +
  • + 参考答案 +
  • +
    + +
    + +
    +

    参考答案

    +
    +
    + +
    +
    +
    +
    +

    +

    +
    + +
    + +
    4||this.props.identity===undefined||power===false?"none":"block"}}> + 提交 + 取消 +
    +
    +
    + ) + } +} + + diff --git a/public/react/src/tpm/challengesnew/TPManswer2.js b/public/react/src/tpm/challengesnew/TPManswer2.js new file mode 100644 index 000000000..6cbfcd081 --- /dev/null +++ b/public/react/src/tpm/challengesnew/TPManswer2.js @@ -0,0 +1,368 @@ +import React, {Component} from 'react'; + +import {Input, InputNumber, Select, Radio, Checkbox, Popconfirm, message, Modal, Tooltip} from 'antd'; + +import {BrowserRouter as Router, Route, Link, Switch} from "react-router-dom"; + +// import "antd/dist/antd.css"; + +import { getImageUrl, toPath, getUrl } from 'educoder'; + +import axios from 'axios'; + +import './css/TPMchallengesnew.css'; + +import TPMMDEditor from './TPMMDEditor'; + + +let origin = getUrl(); + +let path = getUrl("/editormd/lib/") + +const $ = window.$; + +let timeout; + +let currentValue; + +const Option = Select.Option; + +const RadioGroup = Radio.Group; + +// const testAnswers = [{ +// "id": 4337, +// "name": "解题思路1", +// "contents": "答案的解题思路1", +// "level": 1, +// "score": 25 +// }, +// { +// "id": 4338, +// "name": "解题思路2", +// "contents": "答案的解题思路2", +// "level": 2, +// "score": 25 +// }] +export default class TPManswer extends Component { + constructor(props) { + super(props) + this.state = { + choice_url: undefined, + practice_url: undefined, + go_back_url: undefined, + value: 1, + answer:"", + id:undefined, + checkpointId:undefined, + power: false, + prev_challenge: undefined, + next_challenge: undefined, + answers: [] //testAnswers + } + } + + componentDidMount() { + let id = this.props.match.params.shixunId; + let checkpointId=this.props.match.params.checkpointId; + + let newchoice_url= "/shixuns/"+id+"/challenges/newquestion"; + let newpractice_url= "/shixuns/"+id+"/challenges/new"; + let newgo_back_url="/shixuns/"+id+"/challenges"; + this.setState({ + shixunId:id, + checkpointId:checkpointId + }) + + + let url = "/shixuns/" + id + "/challenges/" + checkpointId + "/edit.json?tab=2"; + axios.get(url).then((response) => { + let newprev_challenge = response.data.prev_challenge; + let next_challenge = response.data.next_challenge; + if (newprev_challenge != undefined) { + if(newprev_challenge.st===0){ + newprev_challenge = "/shixuns/" + id + "/challenges/" + newprev_challenge.id + "/editcheckpoint"; + }else{ + newprev_challenge = "/shixuns/" + id + "/challenges/" + newprev_challenge.id + "/editquestion"; + } + } + if (next_challenge != undefined) { + + if(next_challenge.st===0){ + next_challenge = "/shixuns/" + id + "/challenges/" + next_challenge.id+ "/editcheckpoint"; + }else{ + next_challenge = "/shixuns/" + id + "/challenges/" + next_challenge.id+ "/editquestion"; + } + } + this.setState({ + answer:response.data.answer, + power: response.data.power, + choice_url: newchoice_url, // 导航中的新建选择题url + practice_url: newpractice_url, //string 导航中新建实践题url + go_back_url: newgo_back_url, //string 导航中的返回url + position: response.data.position, //int 关卡位置,导航栏中的第几关 + prev_challenge: newprev_challenge, + next_challenge: next_challenge, + }) + + if(response.data.power===false){ + this.props.showSnackbar("没有权限修改"); + } + // if(response.data.answer===undefined||response.data.answer===null){ + // this.answerMD("", "answerMD"); + // }else{ + // this.answerMD(response.data.answer, "answerMD"); + // } + + }).catch((error) => { + console.log(error) + }); + + + let urlAnswer = `/shixuns/${id}/challenges/${checkpointId}/answer.json`; + axios.get(urlAnswer).then((response) => { + if (response.data.status === 401) { + + } else if (response.data) { + this.setState({ answers: response.data }) + } + }) + } + + challenge_answer_submit=()=> { + // `levelSection${index}` + // this.refs.md0 + const { answers } = this.state; + const answersParams = answers.slice(0) + console.log(answersParams) + let isValidate = true; + let totalScore = 0; + answersParams.forEach( (item, index) => { + if (!isValidate) { + return; + } + const sectionId = `#levelSection${index}`; + const mdContnet = this.refs[`md${index}`].getValue().trim();; + item.contents = mdContnet; + item.name = item.name.trim() + totalScore += item.score; + delete item.id; + if (!item.name) { + this.props.showSnackbar("请先填写参考答案名称"); + isValidate = false; + } else if (!mdContnet) { + this.props.showSnackbar("请先填写参考答案内容"); + isValidate = false; + } + if (!isValidate) { + $("html, body").animate({ scrollTop: $(`${sectionId}`).offset().top - 100}) + } + }) + if (!isValidate) { + return; + } + if (answersParams.length != 0 && totalScore != 100) { + this.props.showSnackbar("请先保证占比和为100%"); + return; + } + let id = this.props.match.params.shixunId; + let {checkpointId} = this.state; + let url = `/shixuns/${id}/challenges/${checkpointId}/crud_answer.json`; + + axios.post(url,{ + challenge_answer: answersParams + } + ).then((response) => { + if (response.data) { + if (response.data.message) { + this.props.showSnackbar(response.data.message); + } + if (response.data.status == 1) { + $("html").animate({ scrollTop: 0 }) + } + } + + }).catch((error) => { + console.log(error) + }); + } + onNameChange = (e, index) => { + const newAnswer = Object.assign({}, this.state.answers[index]) + newAnswer.name = e.target.value + const newAnswers = this.state.answers.slice(0) + newAnswers[index] = newAnswer + this.setState({ answers: newAnswers}) + } + onScoreChange = (val, index) => { + const newAnswer = Object.assign({}, this.state.answers[index]) + newAnswer.score = val + const newAnswers = this.state.answers.slice(0) + newAnswers[index] = newAnswer + this.setState({ answers: newAnswers}) + } + answerOnChange = (val, index) => { + if (!this.state.answers[index]) { + // 1、2、3删除2会走到这里 + return; + } + const newAnswer = Object.assign({}, this.state.answers[index]) + newAnswer.contents = val + const newAnswers = this.state.answers.slice(0) + newAnswers[index] = newAnswer + this.setState({ answers: newAnswers}) + } + addAnswer = () => { + const newAnswers = this.state.answers.slice(0) + newAnswers.push({ + "name": `解题思路${newAnswers.length + 1}`, + "contents": "", + "score": 10 + }) + this.setState({ answers: newAnswers }) + } + + delanswers=(index)=>{ + let {answers}=this.state; + let newanswers=answers; + newanswers.splice(index,1) + this.setState({ + answers:newanswers + }, () => { + for(let i = index; i < newanswers.length; i ++) { + this.refs[`md${i}`].setValue(newanswers[i].contents) + } + }) + } + render() { + + let { + choice_url, + practice_url, + go_back_url, + position, + task_pass_default, + submit_url, + shixunId, + checkpointId, + power, + prev_challenge, + next_challenge, + answers, + } = this.state; + let tab1url="/shixuns/" + shixunId + "/challenges/"+checkpointId+"/editcheckpoint"; + let tab2url="/shixuns/" + shixunId + "/challenges/"+checkpointId+"/tab=2"; + let tab3url="/shixuns/" + shixunId + "/challenges/"+checkpointId+"/tab=3"; + // console.log(this.props) + return ( + +
    +
    + + + + 第{position}关 + 返回 + + {prev_challenge === undefined ? "" : + 上一关 + } + + {next_challenge === undefined ? "" : + 下一关 + } + + + 实践类型 + + 选择题类型 + +
    + +
    + +
  • + 本关任务 +
  • + +
  • + 评测设置 +
  • + +
  • + 参考答案 +
  • +
    + +
    + +
    +

    + 可以将参考答案分级设置,让学员自行选择级别,每级查看后按照比例扣分值(学员已完成任务再查看,则不影响原因已获得的成绩) +

    +

    + 示例:级别1,扣减分值占比25%;级别2,扣减分值占比35%;级别3,扣减分值占比40%;则学员选择查看级别1的答案,将被扣减25%的分值; + 选择查看级别2的答案,将被扣减60%的分值;选择查看级别3的答案,将被扣减100%的分值。 +

    + + + + { + answers.map((answer, index) => { + return
    + * +

    级别{index + 1}

    + + this.delanswers(index)}> + + + +
    +
    + 名称: + this.onNameChange(e, index)}> + + 扣减分值占比: + this.onScoreChange(e, index)} >% +
    +
    + 参考答案: + this.answerOnChange(val, index)}> +
    +
    +
    + }) + } + +
    4||this.props.identity===undefined||power===false?"none":"block"}}> + 新增 +
    +
    + + +
    + +
    4||this.props.identity===undefined||power===false?"none":"block"}}> + 提交 + 取消 +
    +
    +
    + ) + } +} + + diff --git a/public/react/src/tpm/challengesnew/TPMchallengesnew.js b/public/react/src/tpm/challengesnew/TPMchallengesnew.js new file mode 100644 index 000000000..9da0b79f5 --- /dev/null +++ b/public/react/src/tpm/challengesnew/TPMchallengesnew.js @@ -0,0 +1,615 @@ +import React, {Component} from 'react'; + +import {Input, Select, Radio, Checkbox, Popconfirm, message, Modal} from 'antd'; + +import {BrowserRouter as Router, Route, Link, Switch} from "react-router-dom"; + +// import "antd/dist/antd.css"; + +import TPMMDEditor from '../../tpm/challengesnew/TPMMDEditor'; + +import axios from 'axios'; + +import './css/TPMchallengesnew.css'; + +import { getImageUrl, toPath } from 'educoder'; + +import {getUrl} from 'educoder'; + +let origin = getUrl(); + +let path = getUrl("/editormd/lib/") + +const $ = window.$; + +let timeout; + +let currentValue; + +const Option = Select.Option; + +const RadioGroup = Radio.Group; + +export default class TPMchallengesnew extends Component { + constructor(props) { + super(props) + this.exercisememoMDRef=React.createRef(); + this.state = { + choice_url: undefined, + practice_url: undefined, + go_back_url: undefined, + task_pass_default: undefined, + submit_url: undefined, + shixunCreatePracticeGroup: 1, + optionsums:[100,200], + activetype:0, + setopen: false, + shixunCreatePractice: undefined, + onshixunsmarkvalue: 100, + shixunsskillvalue: undefined, + shixunsskillvaluelist: [], + tab2url: "", + tab3url: "", + prev_challenge:undefined, + next_challenge:undefined, + power: false, + shixunCreatePracticetype: false, + shixunsskillvaluelisttype: false, + marktype:false, + editPracticesendtype:false, + CreatePracticesendtype:false, + exec_time:20, + shixunExec_timeType:false + } + } + + + componentDidMount() { + let id = this.props.match.params.shixunId; + let checkpointId=this.props.match.params.checkpointId; + + let newchoice_url= "/shixuns/"+id+"/challenges/newquestion"; + let newpractice_url= "/shixuns/"+id+"/challenges/new"; + let newgo_back_url="/shixuns/"+id+"/challenges" + if(checkpointId===undefined){ + //新建模式 + let url = "/shixuns/" + id + "/challenges/new.json" + axios.get(url).then((response) => { + this.setState({ + choice_url: newchoice_url, + practice_url: newpractice_url, + go_back_url: newgo_back_url, + position: response.data.position, + task_pass_default: response.data.task_pass_default, + submit_url: response.data.submit_url, + checkpointId:checkpointId, + exercisememoMDRefval:response.data.task_pass_default + }) + + this.exercisememoMDRef.current.setValue(response.data.task_pass_default||'') + }).catch((error) => { + console.log(error) + }); + }else{ + //编辑模式 + let url="/shixuns/"+id+"/challenges/"+checkpointId+".json?tab=0"; + axios.get(url).then((response) => { + + let optionsum; + if(response.data.difficulty===1){ + optionsum=[100,200]; + }else if(response.data.difficulty===2){ + optionsum=[300,400,500,600]; + }else if(response.data.difficulty===3){ + optionsum=[700,800,900,1000] + } + let newprev_challenge=response.data.prev_challenge; + let next_challenge=response.data.next_challenge; + if (newprev_challenge != undefined) { + if(newprev_challenge.st===0){ + newprev_challenge = "/shixuns/" + id + "/challenges/" + newprev_challenge.id + "/editcheckpoint"; + }else{ + newprev_challenge = "/shixuns/" + id + "/challenges/" + newprev_challenge.id + "/editquestion"; + } + } + if (next_challenge != undefined) { + if(next_challenge.st===0){ + next_challenge = "/shixuns/" + id + "/challenges/" + next_challenge.id+ "/editcheckpoint"; + }else{ + next_challenge = "/shixuns/" + id + "/challenges/" + next_challenge.id+ "/editquestion"; + } + } + this.setState({ + power: response.data.power, + prev_challenge:newprev_challenge, + next_challenge:next_challenge, + choice_url: newchoice_url, + practice_url: newpractice_url, + go_back_url: newgo_back_url, + shixunCreatePractice:response.data.subject, + position:response.data.position, + shixunCreatePracticeGroup:response.data.difficulty, + optionsums:optionsum, + onshixunsmarkvalue:response.data.score, + shixunsskillvaluelist:response.data.tags, + checkpointId:checkpointId, + exec_time:response.data.exec_time, + tab2url: "/shixuns/" + id + "/challenges/"+checkpointId+"/tab=2", + tab3url: "/shixuns/" + id + "/challenges/"+checkpointId+"/tab=3", + exercisememoMDRefval:response.data.task_pass + }) + if(response.data.power===false){ + this.props.showSnackbar("你没有权限修改"); + } + + this.exercisememoMDRef.current.setValue(response.data.task_pass||'') + }).catch((error) => { + console.log(error) + }); + + } + + } + + onshixunCreatePracticeChange = (e) => { + let optionsum; + let onshixunsmark; + if(e.target.value===1){ + optionsum=[100,200]; + onshixunsmark=100; + }else if(e.target.value===2){ + optionsum=[300,400,500,600]; + onshixunsmark=300; + }else if(e.target.value===3){ + optionsum=[700,800,900,1000] + onshixunsmark=700; + } + this.setState({ + shixunCreatePracticeGroup: e.target.value, + optionsums:optionsum, + onshixunsmarkvalue:onshixunsmark + }) + } + + shixunCreatePractice = (e) => { + this.setState({ + shixunCreatePractice: e.target.value + }) + } + + CreatePracticesend = () => { + + + this.setState({ + CreatePracticesendtype:true + }) + + if(this.props.status===2){ + this.props.showSnackbar("该实训已经发布不能新建") + this.setState({ + CreatePracticesendtype:false + }) + return + } + let {shixunCreatePractice, shixunCreatePracticeGroup, onshixunsmarkvalue, shixunsskillvaluelist,exec_time} = this.state; + if (shixunCreatePractice === undefined||shixunCreatePractice=="") { + this.setState({ + shixunCreatePracticetype: true + }) + this.props.showSnackbar("任务名称为空") + $('html').animate({ + scrollTop: 10 + }, 1000); + + this.setState({ + CreatePracticesendtype:false + }) + return + } + + if (shixunsskillvaluelist.length === 0) { + this.setState({ + shixunsskillvaluelisttype: true, + CreatePracticesendtype:false + }) + this.props.showSnackbar("技能标签为空") + return + } + if(exec_time===null||exec_time===undefined||exec_time===""){ + + this.setState({ + shixunExec_timeType:false + }) + return + } + + const exercise_editormdvalue = this.exercisememoMDRef.current.getValue().trim(); + let id = this.props.match.params.shixunId; + + let url = "/shixuns/" + id + "/challenges.json"; + + axios.post(url, { + identifier:id, + subject: shixunCreatePractice, + task_pass: exercise_editormdvalue, + difficulty: shixunCreatePracticeGroup, + score: onshixunsmarkvalue, + challenge_tag: shixunsskillvaluelist, + st: 0, + exec_time:exec_time + }).then((response) => { + if (response.data.status === 1) { + // $("html").animate({ scrollTop: 0 }) + + window.location.href=`/shixuns/${id}/challenges/${response.data.challenge_id}/editcheckpoint`; + // this.setState({ + // setopen: true, + // CreatePracticesendtype:false, + // tab2url: "/shixuns/" + id + "/challenges/"+response.data.challenge_id+"/tab=2", + // tab3url: "/shixuns/" + id + "/challenges/"+response.data.challenge_id+"/tab=3", + // }) + + } + // this.props.showSnackbar(response.data.messages); + }).catch((error) => { + console.log(error) + }); + + + + } + + onshixunsmark = (value) => { + this.setState({ + onshixunsmarkvalue: value + }) + } + + shixunsskill = (e) => { + this.setState({ + shixunsskillvalue: e.target.value + }) + } + + clickshixunsskill = () => { + + let {shixunsskillvalue, shixunsskillvaluelist} = this.state; + if (shixunsskillvalue === "") { + return + } else if (shixunsskillvalue === undefined) { + return + } + + if(shixunsskillvalue == "" || shixunsskillvalue == undefined || shixunsskillvalue == null || (shixunsskillvalue.length>0 && shixunsskillvalue.trim().length == 0)){ + message.error("输入为空,不能保存!"); + return + } + + let list = shixunsskillvaluelist; + list.push(shixunsskillvalue); + this.setState({ + shixunsskillvaluelist: list, + shixunsskillvalue: "" + }) + } + + delshixunsskilllist = (key) => { + let {shixunsskillvaluelist} = this.state; + let newshixunsskillvaluelist = shixunsskillvaluelist; + newshixunsskillvaluelist.splice(key, 1); + this.setState({ + shixunsskillvaluelist: newshixunsskillvaluelist + }) + } + + editPracticesend=()=>{ + + this.setState({ + editPracticesendtype:true + }) + + let {shixunCreatePractice, shixunCreatePracticeGroup, onshixunsmarkvalue, shixunsskillvaluelist,checkpointId,exec_time} = this.state; + + const exercise_editormdvalue = this.exercisememoMDRef.current.getValue().trim(); + + let id = this.props.match.params.shixunId; + + let url = "/shixuns/"+id+"/challenges/"+checkpointId+".json"; + + if (shixunCreatePractice === undefined||shixunCreatePractice=="") { + // this.setState({ + // shixunCreatePracticetype: true + // }) + this.props.showSnackbar("任务名称为空") + $('html').animate({ + scrollTop: 10 + }, 1000); + this.setState({ + editPracticesendtype:false + }) + return + } + + if (shixunsskillvaluelist.length === 0) { + // this.setState({ + // shixunsskillvaluelisttype: true + // }) + this.props.showSnackbar("技能标签为空") + this.setState({ + editPracticesendtype:false + }) + return + } + + if(exec_time===null||exec_time===undefined||exec_time===""){ + + this.setState({ + shixunExec_timeType:false + }) + return + } + axios.put(url, { + tab:0, + identifier:id, + id:checkpointId, + challenge:{ + subject: shixunCreatePractice, + task_pass: exercise_editormdvalue, + difficulty: shixunCreatePracticeGroup, + score: onshixunsmarkvalue, + exec_time:exec_time + }, + challenge_tag:shixunsskillvaluelist + }).then((response) => { + this.props.showSnackbar(response.data.messages); + if (response.data.status === 1) { + this.setState({ + setopen: true, + editPracticesendtype:false, + tab2url: "/shixuns/" + id + "/challenges/"+checkpointId+"/tab=2", + tab3url: "/shixuns/" + id + "/challenges/"+checkpointId+"/tab=3", + }) + // window.location.href = "/shixuns/" + id + "/challenges/"+response.data.challenge_id+"/tab=2" + } + }).catch((error) => { + console.log(error) + }); + + + } + + onshixunsmarks=()=> { + this.setState({ + marktype:true + }) + } + + onshixunsmarkss=()=> { + this.setState({ + marktype:false + }) + } + + setexec_time=(e)=>{ + this.setState({ + exec_time:e.target.value + }) + } + render() { + + let shixuntype = this.props.match.params.type; + + + let {marktype, + shixunCreatePracticetype, shixunsskillvaluelisttype, + choice_url, practice_url, go_back_url, position, task_pass_default, submit_url, setopen,checkpointId,prev_challenge,next_challenge,power, + shixunCreatePractice, shixunCreatePracticeGroup, onshixunsmarkvalue, shixunsskillvalue, shixunsskillvaluelist, tab2url, tab3url,optionsums, + CreatePracticesendtype,editPracticesendtype + } = this.state; + + let options; + if(optionsums!=undefined){ + options = optionsums.map((d, k) => { + return ( + + ) + }) + } + + return ( + +
    + + +
    + +
  • + 本关任务 +
  • + +
  • + {tab2url === "" ? 评测设置 : 评测设置} +
  • + +
  • + {tab3url === "" ? 参考答案 : 参考答案} + +
  • +
    + +
    +
    +

    任务名称

    +
    + * +
    + +
    +
    + 必填项 +
    +
    +
    +
    + + +
    + +

    过关任务

    + + + +

    +

    +
    + + +
    +

    难度系数

    +
    + + + 简单 + 中等 + 困难 + + +
    +

    奖励经验值

    +
    + * + + + +

    + 如果学员答题错误,则不能得到相应的经验值
    + 如果学员成功得到经验值,那么将同时获得等值的金币奖励,如:+10经验值、+10金币 +

    + + 必填项 +
    +
    + + +
    +

    技能标签

    +
    + * +
    + + {/*+ 添加*/} +
    学员答题正确将获得技能,否则不能获得技能
    +
    + + { + shixunsskillvaluelist===undefined?"":shixunsskillvaluelist.length === 0 ? "" : shixunsskillvaluelist.map((itme, key) => { + return ( +
  • {itme} + this.delshixunsskilllist(key)}>× +
  • + ) + }) + } + + +
    +
    + + 必填项 +
    +
    + +
    +

    服务配置

    +
    + * + +
    + +
    + 必填项 +
    +
    +
    + +
    4||this.props.identity===undefined?"none":'block'}} + > + {checkpointId===undefined?提交: + 提交} + 取消 +
    +
    +
    + ) + } +} + + diff --git a/public/react/src/tpm/challengesnew/TPMevaluation.js b/public/react/src/tpm/challengesnew/TPMevaluation.js new file mode 100644 index 000000000..f29e9311e --- /dev/null +++ b/public/react/src/tpm/challengesnew/TPMevaluation.js @@ -0,0 +1,1213 @@ +import React, {Component} from 'react'; + +import {Input, Select, Radio, Checkbox, Popconfirm, message, Modal,Button,Icon,Tooltip} from 'antd'; + +import {BrowserRouter as Router, Route, Link, Switch} from "react-router-dom"; + +// import "antd/dist/antd.css"; + +import axios from 'axios'; + +import { getImageUrl, toPath } from 'educoder'; + +import './css/TPMchallengesnew.css'; + +import {getUrl} from 'educoder'; + +let origin = getUrl(); + +let path = getUrl("/editormd/lib/") + +const $ = window.$; + +let timeout; + +let currentValue; + +const Option = Select.Option; + +const RadioGroup = Radio.Group; + +const { TextArea } = Input; + +function create_editorMD(id, width, high, placeholder, imageUrl, callback) { + var editorName = window.editormd(id, { + width: width, + height: high, + path: path, // "/editormd/lib/" + + syncScrolling: "single", + tex: true, + tocm: true, + emoji: true, + taskList: true, + codeFold: true, + searchReplace: true, + htmlDecode: "style,script,iframe", + sequenceDiagram: true, + autoFocus: false, + toolbarIcons: function () { + // Or return editormd.toolbarModes[name]; // full, simple, mini + // Using "||" set icons align right. + return ["bold", "italic", "|", "list-ul", "list-ol", "|", "code", "code-block", "|", "testIcon", "testIcon1", '|', "image", "table", '|', "watch", "clear"] + }, + toolbarCustomIcons: { + testIcon: "
    ", + testIcon1: "
    " + }, + //这个配置在simple.html中并没有,但是为了能够提交表单,使用这个配置可以让构造出来的HTML代码直接在第二个隐藏的textarea域中,方便post提交表单。 + saveHTMLToTextarea: true, + // 用于增加自定义工具栏的功能,可以直接插入HTML标签,不使用默认的元素创建图标 + dialogMaskOpacity: 0.6, + placeholder: placeholder, + imageUpload: true, + imageFormats: ["jpg", "jpeg", "gif", "png", "bmp", "webp", "JPG", "JPEG", "GIF", "PNG", "BMP", "WEBP"], + imageUploadURL: imageUrl,//url + onload: function () { + // this.previewing(); + $("#" + id + " [type=\"latex\"]").bind("click", function () { + editorName.cm.replaceSelection("```latex"); + editorName.cm.replaceSelection("\n"); + editorName.cm.replaceSelection("\n"); + editorName.cm.replaceSelection("```"); + var __Cursor = editorName.cm.getDoc().getCursor(); + editorName.cm.setCursor(__Cursor.line - 1, 0); + }); + + $("#" + id + " [type=\"inline\"]").bind("click", function () { + editorName.cm.replaceSelection("`$$$$`"); + var __Cursor = editorName.cm.getDoc().getCursor(); + editorName.cm.setCursor(__Cursor.line, __Cursor.ch - 3); + editorName.cm.focus(); + }); + $("[type=\"inline\"]").attr("title", "行内公式"); + $("[type=\"latex\"]").attr("title", "多行公式"); + + window.md_elocalStorage(editorName, `exercise__${id}`, "Memochallengesnew"); + + callback && callback() + } + }); + return editorName; +} + + +export default class TPMevaluation extends Component { + constructor(props) { + super(props) + this.state = { + choice_url: undefined, + practice_url: undefined, + go_back_url: undefined, + task_pass_default: undefined, + submit_url: undefined, + value: 1, + evaluationlist:[], + shixunId:undefined, + power:false, + shixunfilepath:undefined, + evaluationvisible:false, + trees:undefined, + path:"", + main:[], + saveshixunfilepath:undefined, + selectpath:undefined, + shixunfilepathplay:undefined, + shixunfileexpectpicturepath:undefined, + shixunfilestandardpicturepath:undefined, + shixunfilepicturepath:undefined, + pathoptionvalue:-1, + showrepositoryurltiptype: false, + prev_challenge: undefined, + next_challenge: undefined, + StudentTaskPapers:false, + StudentTaskDocs:false, + selectpatharr:[], + handpathopt:false, + scorevalue:false, + markvalue:true, + scoretype:undefined, + web_route:null + } + } + + + exerciseMD(initValue, id) { + + this.contentChanged = false; + const placeholder = ""; +// amp; +// 编辑时要传memoId + const imageUrl = `/api/attachments.json`; +// 创建editorMd + + const exercise_editormd = create_editorMD(id, '100%', 400, placeholder, imageUrl, () => { + setTimeout(() => { + exercise_editormd.resize() + exercise_editormd.cm && exercise_editormd.cm.refresh() + }, 500) + + if (initValue != undefined) { + exercise_editormd.setValue(initValue) + } + exercise_editormd.cm.on("change", (_cm, changeObj) => { + console.log('....contentChanged') + this.contentChanged = true; + }) + }); + this.exercise_editormd = exercise_editormd; + window.exercise_editormd = exercise_editormd; + + } + + componentDidMount() { + let id = this.props.match.params.shixunId; + let checkpointId=this.props.match.params.checkpointId; + this.setState({ + shixunId:id, + checkpointId:checkpointId + }) + let newchoice_url= "/shixuns/"+id+"/challenges/newquestion"; + let newpractice_url= "/shixuns/"+id+"/challenges/new"; + let newgo_back_url="/shixuns/"+id+"/challenges"; + + let url = "/shixuns/" + id + "/challenges/" + checkpointId + "/edit.json?tab=1"; + axios.get(url).then((response) => { + let newprev_challenge = response.data.prev_challenge; + let next_challenge = response.data.next_challenge; + if (newprev_challenge != undefined) { + if(newprev_challenge.st===0){ + newprev_challenge = "/shixuns/" + id + "/challenges/" + newprev_challenge.id + "/editcheckpoint"; + }else{ + newprev_challenge = "/shixuns/" + id + "/challenges/" + newprev_challenge.id + "/editquestion"; + } + } + if (next_challenge != undefined) { + + if(next_challenge.st===0){ + next_challenge = "/shixuns/" + id + "/challenges/" + next_challenge.id+ "/editcheckpoint"; + }else{ + next_challenge = "/shixuns/" + id + "/challenges/" + next_challenge.id+ "/editquestion"; + } + } + let newevaluationlist=[] + if(response.data.test_sets.length===0){ + let newlist=[ + {hidden:0,input:"",output:"",score:50}, + {hidden:0,input:"",output:"",score:50} + ] + newevaluationlist=newlist + }else{ + newevaluationlist=response.data.test_sets + } + + this.setState({ + power: response.data.power, + evaluationlist:newevaluationlist, + shixunfilepath:response.data.path, + shixunfilepathplay:response.data.exec_path, + pathoptionvalue:response.data.show_type, + shixunfileexpectpicturepath:response.data.original_picture_path, + shixunfilestandardpicturepath:response.data.expect_picture_path, + shixunfilepicturepath:response.data.picture_path, + prev_challenge: newprev_challenge, + next_challenge: next_challenge, + choice_url: newchoice_url, // 导航中的新建选择题url + practice_url: newpractice_url, //string 导航中新建实践题url + go_back_url: newgo_back_url, //string 导航中的返回url + position: response.data.position, //int 关卡位置,导航栏中的第几关 + scorevalue:response.data.test_set_score, + markvalue:response.data.test_set_average, + web_route:response.data.web_route, + has_web_route:response.data.has_web_route + }) + this.evaluationoninputvalueonload(); + if(response.data.power===false){ + this.props.showSnackbar("你没有权限修改"); + } + if(response.data.answer===undefined){ + this.answerMD("", "answerMD"); + }else{ + this.answerMD(response.data.answer, "answerMD"); + } + + }).catch((error) => { + console.log(error) + }); + + } + + + setevaluationlist=(newevaluationlist)=>{ + this.setState({ + evaluationlist:newevaluationlist + }) + console.log(newevaluationlist) + } + + + addevaluationon=()=>{ + let {evaluationlist,markvalue}=this.state; + let newevaluationlist=evaluationlist; + newevaluationlist.push({hidden:0,input:"",output:"",score:0}); + newevaluationlist=this.oneditevaluationlist(newevaluationlist,markvalue); + this.setevaluationlist(newevaluationlist); + } + + del_test_array=(key)=>{ + let {evaluationlist,markvalue}=this.state; + let newevaluationlist=evaluationlist; + newevaluationlist.splice(key,1); + newevaluationlist=this.oneditevaluationlist(newevaluationlist,markvalue); + this.setevaluationlist(newevaluationlist); + } + + getfilepath=(e,shixunfilepath,type)=>{ + this.setState({ + evaluationvisible: true, + selectpath:e.target.value, + selectpatharr:[], + pathtype:type + }); + let id = this.props.match.params.shixunId; + let url ="/shixuns/"+id+"/repository.json"; + axios.post(url,{ + path: "" + }).then((response) => { + if (response.data.status === 403||response.data.status === 401||response.data.status === 500) { + + }else{ + this.setState({ + trees:response.data.trees, + saveshixunfilepath:shixunfilepath, + path:"", + main:[], + }) + } + + }).catch((error) => { + console.log(error) + }); + } + + sendgetfilepath=(newpath,type,newpathtype)=>{ + let id = this.props.match.params.shixunId; + let{path,main,pathtype}=this.state; + let ary=main; + let paths=path; + + this.setState({ + selectpatharr:[], + }) + if(paths===""&&type==="tree"){ + newpath=newpath+"/"; + paths=""; + if(main.length===0){ + ary.push({val:"根目录/",path:""},{val:newpath,path:paths+newpath}) + }else{ + ary.push({val:newpath,path:paths+newpath}) + } + + }else if(paths!=""&&type==="tree"){ + newpath=newpath+"/"; + ary.push({val:newpath,path:paths+newpath}) + } + + + let url ="/shixuns/"+id+"/repository.json"; + if(type==="tree"){ + + axios.post(url,{ + path: paths+newpath + }).then((response) => { + if (response.data.status === 403||response.data.status === 401||response.data.status === 500) { + + }else{ + this.setState({ + trees:response.data.trees, + path:paths+newpath, + main:ary, + // selectpath:"" + }) + } + + }).catch((error) => { + console.log(error) + }); + } + + if(pathtype===2){ + this.setState({ + selectpath: newpathtype, + }) + } + } + + goblakepath=(path,key)=>{ + let {main,selectpath,pathtype} =this.state; + let newmain=[] + for(var i=0;i<=key;i++){ + newmain.push(main[i]) + } + let id = this.props.match.params.shixunId; + let url ="/shixuns/"+id+"/repository.json"; + axios.post(url,{ + path: path + }).then((response) => { + if (response.data.status === 403||response.data.status === 401||response.data.status === 500) { + + }else { + this.setState({ + trees: response.data.trees, + path: path, + main: newmain, + // selectpath:selectpath + }) + } + }).catch((error) => { + console.log(error) + }); + + if(pathtype===2){ + let paths = path.substring(0,path.length-1); + console.log(paths) + this.setState({ + selectpath: paths, + }) + } + + + } + + + + + + // delesavegetfilepath=(value)=>{ + // let {selectpatharr} = this.state + // let newarr =selectpatharr; + // let newselectpath=""; + // for(var i=0; i{ + let {selectpath,saveshixunfilepath,pathtype} = this.state + + if(pathtype===1){ + let newselectpath; + + if(saveshixunfilepath==="shixunfilepathplay"){ + newselectpath=value + }else{ + const type = selectpath.split(';'); + let types=false; + for(var i=0; i1&&arrtype===false){ + // for(var i=0; i{ + let {saveshixunfilepath,selectpath}=this.state; + this.setState({ + evaluationvisible: false, + [saveshixunfilepath]:selectpath + }); + } + evaluationhideModal=()=>{ + this.setState({ + evaluationvisible: false, + }); + } + handpathoptionvalue=(value)=>{ + this.setState({ + pathoptionvalue:value, + shixunfileexpectpicturepath:undefined, + shixunfilestandardpicturepath:undefined, + shixunfilepicturepath:undefined + }) + } + showrepositoryurltip=(type)=>{ + if(type===1){ + this.setState({ + showrepositoryurltiptype:true + }) + }else{ + this.setState({ + showrepositoryurltiptype:false + }) + } + } + + evaluationonChange=(e,key)=>{ + let {evaluationlist}=this.state; + let newevaluationlist=evaluationlist; + let newtype; + if(e===1){ + newtype=0; + }else{ + newtype=1; + } + // newevaluationlist[key].is_public=newtype; + // for(var i=0; i{ + let {evaluationlist,scoretype}=this.state; + + if(scoretype===key){ + this.setState({ + scoretype:undefined + }) + } + let newevaluationlist=evaluationlist; + let sum =parseInt(e.target.value); + if(isNaN(sum)){ + sum=0 + } + newevaluationlist[key].score=sum; + + this.setState({ + evaluationlist:newevaluationlist, + markvalue:false + }) + this.setevaluationlist(newevaluationlist); + } + + // 修改测试集的匹配规则 + changeEvaluationRule=(e,key)=>{ + let {evaluationlist}=this.state; + let newevaluationlist=evaluationlist; + newevaluationlist[key].match_rule=e.target.value + this.setevaluationlist(newevaluationlist); + } + + evaluationoninputvalue=(e,key,type)=>{ + $.fn.autoHeight = function(){ + function autoHeight(elem){ + elem.style.height = 'auto'; + elem.style.maxHeight = '140px'; + elem.scrollTop = 0; //防抖动 + elem.style.height = elem.scrollHeight + 'px'; + } + this.each(function(){ + autoHeight(this); + $(this).on('keyup', function(){ + autoHeight(this); + }); + }); + } + $('textarea[autoHeight]').autoHeight(); + + let {evaluationlist}=this.state; + let newevaluationlist=evaluationlist; + if(type==="sr"){ + newevaluationlist[key].input=e.target.value + }else if(type==="yq"){ + // 统一转成\r\n + newevaluationlist[key].output= e.target.value ? e.target.value.replace(/\r?\n/g, "\r\n") : e.target.value + } + this.setevaluationlist(newevaluationlist); + } + + + evaluationoninputvalueonload=()=>{ + $.fn.autoHeight = function(){ + function autoHeight(elem){ + elem.style.height = 'auto'; + elem.style.maxHeight = '140px'; + elem.scrollTop = 0; //防抖动 + elem.style.height = elem.scrollHeight + 'px'; + } + this.each(function(){ + autoHeight(this); + $(this).on('keyup', function(){ + autoHeight(this); + }); + }); + } + $('textarea[autoHeight]').autoHeight(); + } + submitarbitrationevaluation=()=>{ + let{evaluationlist,shixunfilepath,shixunfilepathplay,shixunfileexpectpicturepath,shixunfilestandardpicturepath,shixunfilepicturepath,pathoptionvalue,scorevalue,markvalue,web_route}=this.state; + + + let newscorevalue; + if(scorevalue===false){ + newscorevalue=false + }else{ + //判断占比 + newscorevalue=true + + let sum=0; + for(var i=0; i100){ + this.props.showSnackbar("测试集的评分占比不能大于100"); + this.setState({ + scoretype:i + }) + return + } + sum=sum+evaluationlist[i].score + } + + if(sum>100||sum<100){ + this.props.showSnackbar("测试集的评分占比之和必须等于100"); + return + } + + + } + if(shixunfilepath===undefined||shixunfilepath===""||shixunfilepath===null){ + this.props.showSnackbar("学员任务文件路径为空"); + this.setState({ + StudentTaskPapers:true + }) + $('html').animate({ + scrollTop: 120 + }, 1000); + return + } + + if(shixunfilepathplay===undefined||shixunfilepathplay===""||shixunfilepathplay===null){ + this.props.showSnackbar("评测执行文件路径为空"); + this.setState({ + StudentTaskDocs:true + }) + $('html').animate({ + scrollTop: 130 + }, 1000); + return + } + + if(evaluationlist.length===0){ + this.props.showSnackbar("测试集不能为空"); + return + } + let id = this.props.match.params.shixunId; + let{checkpointId}=this.state; + let url = "/shixuns/"+id+"/challenges/"+checkpointId+".json"; + let newchallenge={ + path:shixunfilepath, + exec_path:shixunfilepathplay, + show_type:pathoptionvalue, + original_picture_path:pathoptionvalue===-1?undefined:shixunfileexpectpicturepath===undefined?null:shixunfileexpectpicturepath, + expect_picture_path:pathoptionvalue===-1?undefined:shixunfilestandardpicturepath===undefined?null:shixunfilestandardpicturepath, + picture_path:pathoptionvalue===-1?undefined:shixunfilepicturepath===undefined?null:shixunfilepicturepath, + test_set_score:newscorevalue, + test_set_average:markvalue, + web_route:web_route===null?undefined:web_route + } + axios.put(url,{ + tab:1, + challenge:newchallenge, + test_set:evaluationlist + } + ).then((response) => { + this.props.showSnackbar(response.data.messages); + // if(response.data.status===1){ + // window.location.href = "/shixuns/" + id + "/challenges/"+response.data.challenge_id+"/tab=3" + // } + }).catch((error) => { + console.log(error) + }); + } + handpathoptionvalues=()=>{ + this.setState({ + handpathopt:true + }) + } + handpathoptionvaluess=()=>{ + this.setState({ + handpathopt:false + }) + } + saveselectpath=(e)=>{ + + this.setState({ + selectpath:e.target.value + }) + + } + updatepath=(e,name,type)=>{ + this.setState({ + [name]:e.target.value, + pathtype:type + }) + } + + + oneditevaluationlist=(newevaluationlist,markvalue)=>{ + + if(markvalue===true){ + if(100%newevaluationlist.length===0){ + let sum=100/newevaluationlist.length; + for(var i=0; i{ + + let {markvalue,evaluationlist}=this.state; + let newevaluationlist=evaluationlist; + + if(e.target.value===true){ + newevaluationlist=this.oneditevaluationlist(newevaluationlist,markvalue) + } + + this.setState({ + scorevalue: e.target.value, + evaluationlist:newevaluationlist + }); + + this.setevaluationlist(newevaluationlist); + } + + //均匀比例 + onChangemarkvalue=(e)=>{ + let {evaluationlist}=this.state; + + if(e.target.value===true){ + let newevaluationlist=evaluationlist; + newevaluationlist=this.oneditevaluationlist(newevaluationlist,e.target.value); + this.setevaluationlist(newevaluationlist); + } + + this.setState({ + markvalue: e.target.value, + }); + + } + + updatewebroute=(e)=>{ + this.setState({ + web_route:e.target.value + }) + } + render() { + + let { + choice_url, + practice_url, + go_back_url, + position, + evaluationlist, + shixunId, + checkpointId, + power, + shixunfileexpectpicturepath, + shixunfilestandardpicturepath, + shixunfilepicturepath, + shixunfilepath, + evaluationvisible, + trees, + path, + main, + selectpath, + shixunfilepathplay, + pathoptionvalue, + showrepositoryurltiptype, + prev_challenge, + next_challenge, + StudentTaskPapers, + StudentTaskDocs, + web_route, + scorevalue, + markvalue, + scoretype, + has_web_route + } = this.state; + + let tab1url="/shixuns/" + shixunId + "/challenges/"+checkpointId+"/editcheckpoint"; + let tab2url="/shixuns/" + shixunId + "/challenges/"+checkpointId+"/tab=2"; + let tab3url="/shixuns/" + shixunId + "/challenges/"+checkpointId+"/tab=3"; + // console.log(this.props) + const radioStyle = { + display: 'block', + height: '30px', + lineHeight: '30px', + marginLeft: '20px', + }; + return ( + +
    +
    + + + + 第{position}关 + 返回 + + {prev_challenge === undefined ? "" : + 上一关 + } + + {next_challenge === undefined ? "" : + 下一关 + } + + 4||this.props.identity===undefined||this.props.status===2||this.props.status===1? "none":'block'}} + data-tip-down="新增代码编辑类型的任务">+ 实践类型 + 4||this.props.identity===undefined||this.props.status===2||this.props.status===1?"none":'block'}} + data-tip-down="新增选择题类型的任务">+ 选择题类型 + +
    + +
    + +
  • + 本关任务 +
  • + +
  • + 评测设置 +
  • + +
  • + 参考答案 +
  • +
    + +

    + 请先上传本关任务的所有代码文件、标准图片等所有必要的文件到 + 版本库 +

    + + +
    +
    +

    学员任务文件

    +
    + * +
    + this.updatepath(e,"shixunfilepath",1)} + onClick={(e)=>this.getfilepath(e,"shixunfilepath",1)} + /> +

    该文件将直接显示给学生,需要学生在其中填写代码

    +
    +
    + 必填项 +
    +
    +
    +
    + +
    +
    + +
    + + this.saveselectpath(e)} + value={selectpath}/> +
    + + this.evaluationenter()}>确定 + this.evaluationhideModal()}>取消 +
    +
    +
    + +
    +
    +

    评测执行文件

    +
    + * +
    + this.updatepath(e,"shixunfilepathplay",1)} + onClick={(e)=>this.getfilepath(e,"shixunfilepathplay",1)} + /> +

    该文件由平台执行,用来测试平台学员代码是否正确

    +
    +
    + 必填项 +
    +
    +
    +
    + + +
    +
    +

    效果展现方式

    +
    + + this.showrepositoryurltip(1)}> +
    + +
    +

    + 图片:处理或输出图片类型的任务,请选填此项
    + 可以通过设置图片路径和学员答案文件路径,展示代码对应的图片效果

    + apk/exe:写可执行文件的任务,请选填此项
    + 可以通过设置学员答案文件路径,展示二维码以供扫码下载

    + txt:输出txt文档类型的任务,请选填此项
    + 可以通过学员答案文件路径设置,展示txt文件内容

    + html:web类型的任务,请选填此项
    + 可以通过Web路由设置,展示html效果预览页 +

    +

    this.showrepositoryurltip(2)} + >知道了 +

    +
    +
    +

    该选项用来配置学员评测本关任务时,查看效果页上需要展现的文件类型

    +
    +
    + + {pathoptionvalue===4&&web_route!=null||pathoptionvalue===4&&has_web_route===true?
    +
    +

    Web路由

    +
    +
    + this.updatewebroute(e)} + placeholder="网站类型实训,请填写Web路由地址。例:java/mypage"/> +
    +
    +
    +
    :""} + + {pathoptionvalue===1||pathoptionvalue===5||pathoptionvalue===6?
    +
    +

    待处理文件路径

    +
    +
    + this.updatepath(e,"shixunfileexpectpicturepath",2)} + onClick={(e)=>this.getfilepath(e,"shixunfileexpectpicturepath",2)} + /> +

    + 该路径下的文件将在学员评测本关任务时,作为原始文件显示在查看效果页,供学员参考;任务为文件处理时请指定该路径,并注意与程序文件所在文件夹分开。 +

    +
    +
    +
    +
    +
    :""} + + + {pathoptionvalue===1||pathoptionvalue===5||pathoptionvalue===6?
    +
    +

    标准答案文件路径

    +
    +
    + this.updatepath(e,"shixunfilestandardpicturepath",2)} + onClick={(e)=>this.getfilepath(e,"shixunfilestandardpicturepath",2)} + /> +

    + 该路径下的文件将在学员评测本关任务时,作为参考答案显示在查看效果页,供学员参考;任务输出结果为文件时请指定该路径,并注意与程序文件所在文件夹分开。 +

    +
    +
    +
    +
    +
    :""} + + + {pathoptionvalue===-1?"":
    +
    +

    学员答案文件路径

    +
    +
    + this.updatepath(e,"shixunfilepicturepath",2)} + onClick={(e)=>this.getfilepath(e,"shixunfilepicturepath",2)} + placeholder="请在版本库中指定用来保存学员代码实际输出结果的路径。例:src/step1/outputfiles"/> +

    + 学员评测本关任务时生成的文件将保存在该路径下,并作为实际输出显示在查看效果页,供学员确认;任务输出结果为文件时请指定该路径,并注意与程序文件所在文件夹分开。 +

    +
    +
    +
    +
    +
    } + + +
    +
    + {/*

    测试集

    */} +

    测试集和系统评分规则

    +

    + 得分规范: + + + 通过全部测试集 + (学员评测,仅当所有测试集都正确时,才获得一次性奖励) + + + 通过部分测试集 + (学员评测,当至少有一组测试集正确时,即可获得其对应比例的奖励) + +

    + +

    + + 系统评分占比: + + 均分比例 + 自定义比例 + + + +

    + +
    +
    + +
    + + {evaluationlist===undefined?"":evaluationlist.length===0?"":evaluationlist.map((item,key)=>{ + return( +
    +

    + * + 组{key+1} + + {/*checked={item.is_public===1?false:true}*/} + + this.editpercentage(e,key)} + value={item.score} /> + % + + + this.evaluationonChange(item.hidden,key)} checked={item.hidden===1?true:false}>隐藏 + + + + this.del_test_array(key)}> + + + +

    + + +
    + 匹配规则: + this.changeEvaluationRule(e,key)}> + 完全匹配 + 末尾匹配 + +
    +
    + ) + })} + +
    +
    + +

    + + 新增测试集 + +

    +

    温馨提示:建议公开测试集和隐藏测试集结合使用,降低作弊的几率;隐藏测试集,在“提交评测”时也将被自动检测

    +
    +
    +
    + + +
    4||this.props.identity===undefined||power===false?"none":"block"}}> + 提交 + 取消 +
    + + +
    +
    + ) + } +} + + diff --git a/public/react/src/tpm/challengesnew/TPMquestion.js b/public/react/src/tpm/challengesnew/TPMquestion.js new file mode 100644 index 000000000..b76e17b17 --- /dev/null +++ b/public/react/src/tpm/challengesnew/TPMquestion.js @@ -0,0 +1,1052 @@ +import React, {Component} from 'react'; + +import {Input, Select, Radio, Checkbox, Popconfirm, message, Modal,Tooltip,notification} from 'antd'; + +import {BrowserRouter as Router, Route, Link, Switch} from "react-router-dom"; + +// import "antd/dist/antd.css"; + +import axios from 'axios'; + +import { getImageUrl, toPath } from 'educoder'; + +import './css/TPMchallengesnew.css'; + +import {getUrl} from 'educoder'; + +import TpmQuestionMain from './TpmQuestionMain'; + +import TpmQuestionNew from './TpmQuestionNew'; + +import TpmQuestionEdit from './TpmQuestionEdit'; + +let origin = getUrl(); + +let path = getUrl("/editormd/lib/") + +const $ = window.$; + +const Option = Select.Option; + +const RadioGroup = Radio.Group; + +var letterArr = []; +for (var i = 65, j = 0; i < 91; i++, j++) { + letterArr[j] = String.fromCharCode(i); +} + + +export default class TPMquestion extends Component { + constructor(props) { + super(props) + this.contentMdRef = React.createRef(); + this.newquestioMDMdRef = React.createRef(); + this.newquestioMDMdCont=React.createRef(); + this.neweditanswerRef=React.createRef(); + this.editanswersRef=React.createRef(); + this.state = { + choice_url: undefined, + practice_url: undefined, + go_back_url: undefined, + position: undefined, + task_pass_default: undefined, + submit_url: undefined, + questionsInputvalue:undefined, + questionaddsum:0, + questionaddarray:[], + questionaddtype:true, + activetype:"", + questionlists:[{str:"A",val:"",type:false},{str:"B",val:"",type:false},{str:"C",val:"",type:false},{str:"D",val:"",type:false}], + answeshixunsGroup: 1, + answeoptions:[10,20], + answeonshixunsmark:10, + shixunssanswerkillvalue:"", + shixunsskillanswerlist:[], + challenge_id:"", + challenge_choose_id:undefined, + questionlistss:[], + newcnttype:false, + newquestioMDvaluetype:false, + challenge_tagtype:false, + editquestionaddtype:false, + mancheckpointId:undefined, + power:false, + questionInputvaluetype:false, + questioMD:"", + standard_answer:"", + subject:"", + newquestioMDvaluetypes:false, + questionInputvaluetypes:false, + prev_challenge:undefined, + next_challenge:undefined, + newcnttypesum:1, + marktype:false, + answer:"", + sumittype:false + } + } + + + questionInputvalue=(e)=>{ + this.setState({ + questionsInputvalue: e.target.value + }) + } + + componentDidMount() { + if(this.props.status===2){ + + } + let id = this.props.match.params.shixunId; + let checkpointId=this.props.match.params.checkpointId; + + this.setState({ + mancheckpointId:id, + }) + + let newchoice_url= "/shixuns/"+id+"/challenges/newquestion"; + let newpractice_url= "/shixuns/"+id+"/challenges/new"; + let newgo_back_url="/shixuns/"+id+"/challenges"; + + if(this.props.match.params.choose_id===undefined){ + if(checkpointId===undefined){ + //新建模式 + let nurl = "/shixuns/" + id + "/challenges/new.json" + axios.get(nurl).then((response) => { + + if (response.data.status === 403||response.data.status === 401||response.data.status === 500) { + + }else { + this.setState({ + choice_url: newchoice_url, + practice_url: newpractice_url, + go_back_url: newgo_back_url, + position: response.data.position, + task_pass_default: response.data.task_pass_default, + submit_url: response.data.submit_url, + power:true, + activetype:"first", + + }) + if (response.data.status === 403||response.data.status === 401||response.data.status === 500) { + this.setState({ + contentMdRefval:"" + }) + } else { + + this.setState({ + contentMdRefval:response.data.task_pass_default + }) + this.contentMdRef.current.setValue(response.data.task_pass_default || '') + } + this.shixunsautoHeight() + } + + }).catch((error) => { + console.log(error) + }); + + }else{ + //编辑模式 + let url = "/shixuns/"+ id +"/challenges/"+checkpointId+"/edit.json?st=1" + axios.get(url).then((response) => { + if (response.data.status === 403||response.data.status === 401||response.data.status === 500) { + + }else { + let newprev_challenge=response.data.prev_challenge; + let next_challenge=response.data.next_challenge; + if (newprev_challenge != undefined) { + if(newprev_challenge.st===0){ + newprev_challenge = "/shixuns/" + id + "/challenges/" + newprev_challenge.id + "/editcheckpoint"; + }else{ + newprev_challenge = "/shixuns/" + id + "/challenges/" + newprev_challenge.id + "/editquestion"; + } + } + if (next_challenge != undefined) { + if(next_challenge.st===0){ + next_challenge = "/shixuns/" + id + "/challenges/" + next_challenge.id+ "/editcheckpoint"; + }else{ + next_challenge = "/shixuns/" + id + "/challenges/" + next_challenge.id+ "/editquestion"; + } + } + this.setState({ + questionaddtype:false, + newquestionaddtype:false, + activetype:"first", + prev_challenge:newprev_challenge, + next_challenge:next_challenge, + questionsInputvalue:response.data.subject, + questionaddarray:response.data.chooses, + challenge_id:response.data.id, + mancheckpointId:checkpointId, + position: response.data.position, + choice_url: newchoice_url, + practice_url: newpractice_url, + go_back_url: newgo_back_url, + power:response.data.power, + // questioMD:response.data.task_pass, + answer:response.data.answer + + }) + + this.setState({ + contentMdRefval:response.data.task_pass + }) + // this.contentMdRef.current.setValue(response.data.task_pass || '') + if(response.data.chooses.length===0){ + // 新建选择题时,没法切回 ‘本关任务’ tab + // this.questionadd() + } + + this.shixunsautoHeight() + } + + }).catch((error) => { + console.log(error) + }); + } + + }else{ + $('html').animate({ + scrollTop:10 + }, 500); + + let{challenge_id} =this.state; + + let id = this.props.match.params.shixunId; + let url = "/shixuns/"+ id +"/challenges/"+checkpointId+"/edit.json?st=1" + axios.get(url).then((response) => { + if (response.data.status === 403||response.data.status === 401||response.data.status === 500) { + + }else { + let newprev_challenge=response.data.prev_challenge; + let next_challenge=response.data.next_challenge; + if (newprev_challenge != undefined) { + if(newprev_challenge.st===0){ + newprev_challenge = "/shixuns/" + id + "/challenges/" + newprev_challenge.id + "/editcheckpoint"; + }else{ + newprev_challenge = "/shixuns/" + id + "/challenges/" + newprev_challenge.id + "/editquestion"; + } + } + if (next_challenge != undefined) { + if(next_challenge.st===0){ + next_challenge = "/shixuns/" + id + "/challenges/" + next_challenge.id+ "/editcheckpoint"; + }else{ + next_challenge = "/shixuns/" + id + "/challenges/" + next_challenge.id+ "/editquestion"; + } + } + this.setState({ + questionaddtype:false, + newquestionaddtype:false, + prev_challenge:newprev_challenge, + next_challenge:next_challenge, + questionsInputvalue:response.data.subject, + questionaddarray:response.data.chooses, + challenge_id:response.data.id, + mancheckpointId:checkpointId, + position: response.data.position, + choice_url: newchoice_url, + practice_url: newpractice_url, + go_back_url: newgo_back_url, + power:response.data.power, + // questioMD:response.data.task_pass, + + }) + + this.setState({ + contentMdRefval:response.data.task_pass + }) + // this.contentMdRef.current.setValue(response.data.task_pass || '') + if(response.data.chooses.length===0){ + this.questionadd() + } + this.shixunsautoHeight() + } + + }).catch((error) => { + console.log(error) + }); + + let zrl ='/shixuns/'+this.props.match.params.shixunId+'/challenges/'+this.props.match.params.checkpointId+'/edit_choose_question.json?choose_id='+this.props.match.params.choose_id; + axios.get(zrl).then((response) => { + if(response.status===200){ + let choose_contents=response.data.choose_contents; + let newchoose_contentslist=[] + for(var i=0; i { + }); + + } + } + + clickquestionsumit=()=>{ + this.setState({ + sumittype:true + }) + let checkpointId=this.props.match.params.checkpointId; + if(this.props.status===2&&checkpointId===undefined){ + this.props.showSnackbar("该实训已经发布不能新建") + this.setState({ + sumittype:false + }) + return + } + let {questionsInputvalue} =this.state; + // const exercise_editormdvalue = this.questio_editormd.getValue(); + const exercise_editormdvalue = this.contentMdRef.current.getValue().trim(); + let id = this.props.match.params.shixunId; + + if(questionsInputvalue===undefined||questionsInputvalue===null||questionsInputvalue===""){ + this.setState({ + questionInputvaluetype:true + }) + $('html').animate({ + scrollTop: 10 + }, 1000); + this.setState({ + sumittype:false + }) + return + } + + + if(exercise_editormdvalue===null ||exercise_editormdvalue===""){ + this.setState({ + questionInputvaluetypes:true + }) + $('html').animate({ + scrollTop: 500 + }, 1000); + this.setState({ + sumittype:false + }) + return + } + if(checkpointId===undefined){ + + let url = "/shixuns/" + id + "/challenges.json"; + + axios.post(url, { + identifier:id, + subject: questionsInputvalue, + task_pass: exercise_editormdvalue, + st: 1 + }).then((response) => { + this.props.showSnackbar(response.data.messages); + // if(response.data.status===1){ + // + // this.setState({ + // questionaddtype:false, + // challenge_id:response.data.challenge_id + // }) + // + // this.questionadd() + // } + window.location.href = '/shixuns/'+id+'/challenges/'+response.data.challenge_id+'/editquestion'; + + }).catch((error) => { + console.log(error) + }); + }else{ + let url ="/shixuns/"+id+"/challenges/"+checkpointId+".json"; + axios.put(url, { + tab:0, + subject: questionsInputvalue, + task_pass: exercise_editormdvalue, + }).then((response) => { + if(response.data.status===1){ + this.setState({ + questionaddtype:false, + challenge_id:response.data.challenge_id + }) + } + $('html').animate({ + scrollTop: 10 + }, 200); + this.props.showSnackbar(response.data.messages); + window.location.href = '/shixuns/'+id+'/challenges/'+response.data.challenge_id+'/editquestion'; + }).catch((error) => { + console.log(error) + }); + } + + } + + questionall=()=>{ + // this.setState({ + // activetype:"first", + // newquestionaddtype:false, + // editquestionaddtype:false, + // questionaddtype:false + // }) + + window.location.href = '/shixuns/'+this.props.match.params.shixunId+'/challenges/'+this.props.match.params.checkpointId+'/editquestion'; + } + questionadd=()=>{ + + let{questionaddarray}=this.state; + + let questionaddsums=questionaddarray.length; + + if(questionaddsums-1>9){ + this.props.showSnackbar("选择题目最大支持设置9道题") + return + } + + let questionaddarrays=questionaddarray; + + questionaddarrays.map((item,key)=>{ + if(item.choose_id===0){ + questionaddarrays.splice(key,1) + } + }) + + questionaddarrays.push({type:0,choose_id:0}); + this.setState({ + activetype:0, + questionaddarray:questionaddarrays, + questionaddtype:true, + editquestionaddtype:false, + newquestionaddtype:true, + questionlists:[{str:"A",val:"",type:false},{str:"B",val:"",type:false},{str:"C",val:"",type:false},{str:"D",val:"",type:false}], + answeshixunsGroup: 1, + answeoptions:[10,20], + answeonshixunsmark:10, + shixunssanswerkillvalue:"", + shixunsskillanswerlist:[], + contentMdRefval:"", + newquestioMDMdContval:"", + }) + + + setTimeout(() => { + this.newquestioMDMdRef.current.setValue('') + }, 1000) + setTimeout(() => { + this.newquestioMDMdCont.current.setValue('') + }, 1500) + // this.shixunsautoHeight() + } + + editquestionlists=(newquestionlists)=>{ + let newlist=newquestionlists; + let list=[] + for(var i=0; i{ + let{questionlists} = this.state; + let newquestionlists=questionlists; + let newli={str:letterArr[questionlists.length],val:"",type:false}; + newquestionlists.push(newli); + this.editquestionlists(newquestionlists); + } + + + delquestionlists=(key)=>{ + let{questionlists} = this.state; + let newquestionlists=questionlists; + newquestionlists.splice(key,1); + for(var i=0; i{ + let{questionlists} = this.state; + let newquestionlists=questionlists; + if(newquestionlists[key].type===true){ + newquestionlists[key].type=false; + }else if(newquestionlists[key].type===false){ + newquestionlists[key].type=true; + } + + this.editquestionlists(newquestionlists); + } + + onshixunGroupanswe=(e)=> { + let optionsum; + let onshixunsmark; + if(e.target.value===1){ + optionsum=[10,20]; + onshixunsmark=10; + }else if(e.target.value===2){ + optionsum=[30,40,50,60]; + onshixunsmark=30; + }else if(e.target.value===3){ + optionsum=[70,80,90,100] + onshixunsmark=70; + } + this.setState({ + answeshixunsGroup: e.target.value, + answeoptions:optionsum, + answeonshixunsmark:onshixunsmark + }) + } + shixunssanswerkill = (e) => { + this.setState({ + shixunssanswerkillvalue: e.target.value + }) + + } + clickshixunsanswerskill = () => { + + let {shixunssanswerkillvalue, shixunsskillanswerlist} = this.state; + if (shixunssanswerkillvalue === "") { + return + } else if (shixunssanswerkillvalue === undefined) { + return + } + + if(shixunssanswerkillvalue == "" || shixunssanswerkillvalue == undefined || shixunssanswerkillvalue == null || (shixunssanswerkillvalue.length>0 && shixunssanswerkillvalue.trim().length == 0)){ + message.error("输入为空,不能保存!"); + return + } + + let list = shixunsskillanswerlist; + list.push(shixunssanswerkillvalue); + this.setState({ + shixunsskillanswerlist: list, + shixunssanswerkillvalue: "" + }) + } + delshixunssnswerllist=(key)=>{ + let {shixunsskillanswerlist} = this.state; + let newshixunsskillanswerlist = shixunsskillanswerlist; + newshixunsskillanswerlist.splice(key, 1); + this.setState({ + shixunsskillanswerlist: newshixunsskillanswerlist + }) + } + onInputoquestionption=(e,key)=>{ + + $.fn.autoHeight = function(){ + function autoHeight(elem){ + elem.style.height = 'auto'; + elem.style.maxHeight = '140px'; + elem.scrollTop = 0; //防抖动 + elem.style.height = elem.scrollHeight + 'px'; + } + this.each(function(){ + autoHeight(this); + $(this).on('keyup', function(){ + autoHeight(this); + }); + }); + } + $("#"+e.target.id).autoHeight(); + + let {questionlists}=this.state; + let newquestionlists=questionlists; + newquestionlists[key].val=e.target.value; + this.editquestionlists(newquestionlists); + } + + onshixunsansweSelect=(value)=>{ + this.setState({ + answeonshixunsmark: value + }) + } + + answer_subit=(sumtype,challenge_choose_id)=>{ + $('html').animate({ + scrollTop:10 + }, 500); + + let {challenge_id,questionlists,shixunsskillanswerlist,answeonshixunsmark,answeshixunsGroup,questionaddarray} =this.state; + if(challenge_id===undefined){ + message.error("关卡id为空"); + return + } + let newquestionlists=questionlists; + let newlist=""; + let newtype=[]; + let newcnt=[]; + let list=0; + for(var i=0; i { + console.log(error) + }); + }else{ + + let newquestioMDvalue = this.newquestioMDMdRef.current.getValue().trim(); + if(newquestioMDvalue===""||newquestioMDvalue==="请输入选择题的题干内容"){ + this.setState({ + newquestioMDvaluetype:true, + }) + $('html').animate({ + scrollTop:100 + }, 200); + message.error("题干为空"); + return + } + let newnewanswerMDvalue = this.newquestioMDMdCont.current.getValue().trim(); + + if(newnewanswerMDvalue===""||newnewanswerMDvalue===" "){ + newnewanswerMDvalue=undefined + } + url="/shixuns/" + id + "/challenges/" + challenge_id + "/create_choose_question.json"; + axios.post(url, { + challenge_choose: {subject: newquestioMDvalue, answer: newnewanswerMDvalue, standard_answer:newlist , score: answeonshixunsmark, difficult: answeshixunsGroup}, + challenge_tag: shixunsskillanswerlist, + question: {cnt: newcnt}, + choice: {answer: newtype} + }).then((response) => { + + let questionaddsums=questionaddarray.length; + let questionaddarrays=questionaddarray; + questionaddarrays[questionaddsums-1].choose_id=response.data.challenge_choose_id; + if(newlist.length===1){ + questionaddarrays[questionaddsums-1].type=1; + }else if(newlist.length>1){ + questionaddarrays[questionaddsums-1].type=2; + } + this.setState({ + challenge_choose_id:response.data.challenge_choose_id, + questionaddtype:false, + editquestionaddtype:false, + newquestioMDvaluetype:false, + newquestioMDvaluetypes:false, + questionaddarray:questionaddarrays + }) + $('html').animate({ + scrollTop: 10 + }, 200); + + notification.open({ + message: '提示', + description: + '新建成功,请点击右侧加号继续添加', + }); + window.location.href=`/shixuns/${id}/challenges/${checkpointId}/editquestion/${response.data.challenge_choose_id}`; + + // this.getanswer_subitlist() + // this.gochooseid("/shixuns/"+this.props.match.params.shixunId+"/challenges/"+this.props.match.params.checkpointId+"/editquestion"+"/"+response.data.challenge_choose_id) + }).catch((error) => { + console.log(error) + }); + } + + + } + + questionlist=(key,challenge_choose_id,type)=>{ + $('html').animate({ + scrollTop:10 + }, 500); + + let{challenge_id} =this.state; + + if(challenge_choose_id===""||type===0){ + + + // this.neweditanswerRef.current.setValue('') + // this.editanswersRef.current.setValue('') + this.setState({ + activetype:challenge_choose_id, + editquestionaddtype:true, + questionaddtype:true, + newquestionaddtype:false, + questionlists:[{str:"A",val:"",type:false},{str:"B",val:"",type:false},{str:"C",val:"",type:false},{str:"D",val:"",type:false}], + answeshixunsGroup: 1, + answeoptions:[10,20], + answeonshixunsmark:10, + shixunssanswerkillvalue:"", + shixunsskillanswerlist:[], + neweditanswerRefval:'', + editanswersRefval:'' + }) + this.newquestioMDMdRef.current.setValue('') + this.newquestioMDMdCont.current.setValue('') + }else{ + let id = this.props.match.params.shixunId; + let url ='/shixuns/'+id+'/challenges/'+challenge_id+'/edit_choose_question.json?choose_id='+challenge_choose_id; + axios.get(url).then((response) => { + if(response.status===200){ + let choose_contents=response.data.choose_contents; + let newchoose_contentslist=[] + for(var i=0; i { + }); + + } + + } + + shixunsautoHeight=()=>{ + $.fn.autoHeight = function(){ + function autoHeight(elem){ + elem.style.height = 'auto'; + elem.style.maxHeight = '140px'; + elem.scrollTop = 0; //防抖动 + if(elem.scrollHeight===0){ + elem.style.height = 62 + 'px'; + }else{ + + elem.style.height = elem.scrollHeight + 'px'; + } + + } + this.each(function(){ + autoHeight(this); + $(this).on('keyup', function(){ + autoHeight(this); + }); + }); + } + $('textarea[autoHeight]').autoHeight(); + } + + gochooseid=(url)=>{ + window.location.href =url + // window.location.Reload(url) + // this.props.history.replace( url ); + // this.props.history.push( url ); + // 返回 + // this.props.history.goBack(); + } + + render() { + + let {choice_url, + practice_url, + go_back_url, + position, + answeoptions, + questionaddarray, + questionaddtype, + activetype, + newquestionaddtype, + editquestionaddtype, + challenge_choose_id, + prev_challenge, + next_challenge, + answer, + + } = this.state; + + let options; + + + options = answeoptions.map((d, k) => { + return ( + + ) + }) + + return ( + +
    + + +
    + + +
  • + 本关任务 +
  • +
    + + { + questionaddarray.length===0?"":questionaddarray.map((item,key)=>{ + return( +
  • this.questionlist(key,item.choose_id,item.type):""} + > + + { + item.choose_id!=0? + this.gochooseid("/shixuns/"+this.props.match.params.shixunId+"/challenges/"+this.props.match.params.checkpointId+"/editquestion"+"/"+item.choose_id)}> + {key+1}.{item.type===2?"多选题":item.type===1?"单选题":'选择题'} + :activetype==="first"?"":{key+1}.{item.type===2?"多选题":item.type===1?"单选题":'选择题'} + } + +
  • + ) + }) + } + + +
  • + + + + +
  • + +
    + + {/*x选择题首页*/} + {activetype==="first"?this.questionInputvalue(e)} + clickquestionsumit={(e)=>this.clickquestionsumit(e)} + + />:""} + + {/*新建*/} + + {newquestionaddtype===true? + this.selquestionlists(key)} + onInputoquestionption={(e,key)=>this.onInputoquestionption(e,key)} + delquestionlists={(key)=>this.delquestionlists(key)} + addquestionlists={(e)=>this.addquestionlists(e)} + onshixunGroupanswe={(e)=>this.onshixunGroupanswe(e)} + onshixunsansweSelect={(e)=>this.onshixunsansweSelect(e)} + shixunssanswerkill={(e)=>this.shixunssanswerkill(e)} + clickshixunsanswerskill={(e)=>this.clickshixunsanswerskill(e)} + delshixunssnswerllist={(key)=>this.delshixunssnswerllist(key)} + answer_subit={()=>this.answer_subit()} + />:""} + + + {/*修改*/} + {editquestionaddtype===true? + this.selquestionlists(key)} + onInputoquestionption={(e,key)=>this.onInputoquestionption(e,key)} + delquestionlists={(key)=>this.delquestionlists(key)} + addquestionlists={(e)=>this.addquestionlists(e)} + onshixunGroupanswe={(e)=>this.onshixunGroupanswe(e)} + onshixunsansweSelect={(e)=>this.onshixunsansweSelect(e)} + shixunssanswerkill={(e)=>this.shixunssanswerkill(e)} + clickshixunsanswerskill={(e)=>this.clickshixunsanswerskill(e)} + delshixunssnswerllist={(key)=>this.delshixunssnswerllist(key)} + answer_subit={()=>this.answer_subit("edit",challenge_choose_id)} + /> + :""} + +
    +
    + ) + } +} + diff --git a/public/react/src/tpm/challengesnew/TpmQuestionEdit.js b/public/react/src/tpm/challengesnew/TpmQuestionEdit.js new file mode 100644 index 000000000..d0e6f98bd --- /dev/null +++ b/public/react/src/tpm/challengesnew/TpmQuestionEdit.js @@ -0,0 +1,229 @@ +import React, {Component} from 'react'; + +import {Input, Select, Radio, Checkbox, Popconfirm, message, Modal,Tooltip} from 'antd'; + +import {BrowserRouter as Router, Route, Link, Switch} from "react-router-dom"; + +import axios from 'axios'; + +import TPMMDEditor from '../../tpm/challengesnew/TPMMDEditor'; + +const Option = Select.Option; + +const RadioGroup = Radio.Group; + +export default class TpmQuestionEdit extends Component { + constructor(props) { + super(props) + this.state = { + + } + } + + componentDidMount() { + + } + delecbtns=()=>{ + let url=`/shixuns/${this.props.match.params.shixunId}/challenges/${this.props.match.params.checkpointId}/destroy_challenge_choose.json`; + axios.delete((url), { data: { + choose_id:this.props.match.params.choose_id + }}) + .then((result)=>{ + if(result.data.status===1){ + window.location.href=`/shixuns/${this.props.match.params.shixunId}/challenges/${this.props.match.params.checkpointId}/editquestion`; + } + }) + } + + render() { + + return ( +
    + +
    +
    +

    题干

    +
    + * +
    + +
    + + +
    + 必填项 +
    + +
    +

    +

    +
    + { + this.props.questionlists===undefined||this.props.questionlists.length===0?"":this.props.questionlists.map((item,key)=>{ + return( +
  • + + + this.props.delquestionlists(key)}> + + +
  • + ) + }) + } +

    + this.props.addquestionlists()} + className="fl edu-default-btn edu-greyline-btn mb20 option_icon_add">新增选项 + + + {this.props.newcnttypesum===0?"请选择答案":"选项内容不能为空"} + +

    +
  • + + +
  • +
    +
    +
    + + +
    +
    +

    参考答案

    +
    +
    + +
    +
    + 必填项 +
    +
    +

    +

    +
    +
    + +
    +

    难度系数

    +
    + + this.props.onshixunGroupanswe(e)}> + 简单 + 中等 + 困难 + + +
    +

    奖励经验值

    +
    + * + + +

    + 如果学员答题错误,则不能得到相应的经验值
    + 如果学员成功得到经验值,那么将同时获得等值的金币奖励,如:+10经验值、+10金币 +

    + + 必填项 +
    +
    + +
    +

    技能标签

    +
    + * +
    + this.props.shixunssanswerkill(e)} + value={this.props.shixunssanswerkillvalue} + onPressEnter={(e)=>this.props.clickshixunsanswerskill(e)} + onBlur={(e)=>this.props.clickshixunsanswerskill(e)} + /> + {/*+ 添加*/} +
    学员答题正确将获得技能,否则不能获得技能 + + 必填项 + +
    +
    + + { + this.props.shixunsskillanswerlist.length === 0 ? "" : this.props.shixunsskillanswerlist.map((itme, key) => { + return ( +
  • {itme} + this.props.delshixunssnswerllist(key)}>× +
  • + ) + }) + } + + +
    + +
    + +
    +
    + + +
    4||this.props.identity===undefined||this.props.power===false?"none":"block"}}> + this.props.answer_subit()}>提交 + 取消 + + this.delecbtns()} + className="delectshixuncdbtn fr">删除 +
    + +
    + + ) + } +} + + + diff --git a/public/react/src/tpm/challengesnew/TpmQuestionMain.js b/public/react/src/tpm/challengesnew/TpmQuestionMain.js new file mode 100644 index 000000000..614842ab8 --- /dev/null +++ b/public/react/src/tpm/challengesnew/TpmQuestionMain.js @@ -0,0 +1,84 @@ +import React, {Component} from 'react'; + +import {BrowserRouter as Router, Route, Link, Switch} from "react-router-dom"; +import TPMMDEditor from '../../tpm/challengesnew/TPMMDEditor'; + + +export default class TpmQuestionMain extends Component { + constructor(props) { + super(props) + this.state = { + + } + } + + componentDidMount() { + + } + + + render() { + return ( +
    +
    +
    +

    任务名称

    +
    + * +
    + +
    +
    + 必填项 +
    +
    +
    +
    + + +
    +

    过关任务

    +
    + * +
    + +
    +
    + 必填项 +
    +
    +

    +

    +
    + + +
    4 || this.props.identity === undefined || this.props.power === false ? "none" : "block"}}> + 提交 + 取消 + +
    + +
    + + ) + } + } + + + diff --git a/public/react/src/tpm/challengesnew/TpmQuestionNew.js b/public/react/src/tpm/challengesnew/TpmQuestionNew.js new file mode 100644 index 000000000..861c4f879 --- /dev/null +++ b/public/react/src/tpm/challengesnew/TpmQuestionNew.js @@ -0,0 +1,219 @@ +import React, {Component} from 'react'; + +import {Input, Select, Radio, Checkbox, Popconfirm, message, Modal,Tooltip} from 'antd'; + +import {BrowserRouter as Router, Route, Link, Switch} from "react-router-dom"; + +import TPMMDEditor from '../../tpm/challengesnew/TPMMDEditor'; + +const Option = Select.Option; + +const RadioGroup = Radio.Group; + +export default class TpmQuestionNew extends Component { + constructor(props) { + super(props) + this.state = { + + } + } + + componentDidMount() { + + } + + + render() { + // console.log( this.props.questionlists) + return ( +
    + +
    +
    +

    题干

    +
    + * +
    + +
    + + +
    + 必填项 +
    + +
    +

    +

    + + +
    + { + this.props.questionlists===undefined||this.props.questionlists.length===0?"":this.props.questionlists.map((item,key)=>{ + return( +
  • + + + this.props.delquestionlists(key)}> + + + + + +
  • + ) + }) + } +

    + this.props.addquestionlists()} + className="fl edu-default-btn edu-greyline-btn mb20 option_icon_add">新增选项 + + + {this.props.newcnttypesum===0?"请选择答案":"选项内容不能为空"} + +

    +
  • + + +
  • +
    +
    +
    + + +
    +
    +

    参考答案

    +
    +
    + +
    +
    + 必填项 +
    +
    +

    +

    + +
    +
    + +
    +

    难度系数

    +
    + + this.props.onshixunGroupanswe(e)} + > + 简单 + 中等 + 困难 + + +
    +

    奖励经验值

    +
    + * + + + +

    + 如果学员答题错误,则不能得到相应的经验值
    + 如果学员成功得到经验值,那么将同时获得等值的金币奖励,如:+10经验值、+10金币 +

    + + 必填项 +
    +
    + +
    +

    技能标签

    +
    + * +
    + this.props.shixunssanswerkill(e)} + value={this.props.shixunssanswerkillvalue} + onPressEnter={(e)=>this.props.clickshixunsanswerskill(e)} + onBlur={(e)=>this.props.clickshixunsanswerskill(e)} + /> + {/*+ 添加*/} +
    学员答题正确将获得技能,否则不能获得技能 + + 必填项 + +
    +
    + + { + this.props.shixunsskillanswerlist.length === 0 ? "" : this.props.shixunsskillanswerlist.map((itme, key) => { + return ( +
  • {itme} + this.props.delshixunssnswerllist(key)}>× +
  • + ) + }) + } + + +
    + +
    + +
    +
    + + +
    4||this.props.identity===undefined||this.props.power===false?"none":"block"}}> + 提交 + 取消 +
    + +
    + + ) + } +} + + + diff --git a/public/react/src/tpm/challengesnew/css/TPMchallengesnew.css b/public/react/src/tpm/challengesnew/css/TPMchallengesnew.css new file mode 100644 index 000000000..37a65ef97 --- /dev/null +++ b/public/react/src/tpm/challengesnew/css/TPMchallengesnew.css @@ -0,0 +1,269 @@ +.CodeMirror-scroll { + overflow: auto !important; + margin-bottom: -30px; + margin-right: -30px; + padding-bottom: 30px; + height: 100%; + outline: none; + position: relative; +} +a.white-btn.orange-btn:hover { + border: 1px solid #F06200; + color: #FFF !important; +} +.flex1 a.white-btn.orange-btn:hover { + border: 1px solid #F06200; + color: #FFF !important; +} + +/*.challenge_nav li a{*/ + /*color:#000 !important;*/ +/*}*/ + +.questionli{ + width: 95%; + margin-left: 37px; +} +#directory_file{ + height:200px; + overflow-y:auto; + background:#f5f5f5; + padding:10px; +} +.directory_filepath{ + width:120px; + text-align:left; +} + +a{ + text-decoration: none; + color: #05101a; +} +.repository_url_tippostion{ + position: absolute; + left: 22%; + width: 500px; + top: 100%; +} + +.top-black-trangleft { + display: block; + border-width: 8px; + position: absolute; + top: -16px; + /* right: 4px; */ + border-style: dashed solid dashed dashed; + border-color: transparent transparent rgba(5,16,26,0.6) transparent; + font-size: 0; + line-height: 0; +} + +#exercisememoMD .CodeMirror { + margin-top: 31px !important; + height: 370px !important; + /*width: 579px !important;*/ +} + +#exercisememoMD .editormd-preview { + top: 40px !important; + height: 370px !important; + width: 578px !important; +} +#exercisememoMD{ + /*height: 700px !important;*/ +} +#questioMD{ + /*width: 95% !important;*/ + height: 417px !important; + margin-left: 0% !important; +} + + +#questioMD .CodeMirror { + /*width: 550.5px !important;*/ + margin-top: 31px !important; + height: 374px !important; +} + +#questioMD .editormd-preview { + top: 40px !important; + height: 375px !important; + width: 550px !important; +} + +#newquestioMD .CodeMirror { + /*width: 549px !important;*/ + margin-top: 31px !important; + height: 364px !important; +} + +#newquestioMD .editormd-preview { + top: 40px !important; + height: 364px !important; + width: 578px !important; +} + +#challenge_choose_answer .CodeMirror { + margin-top: 31px !important; + height: 364px !important; + /*width: 578px !important;*/ +} + + +#challenge_choose_answer .editormd-preview { + top: 40px !important; + height: 364px !important; + width: 578px !important; +} + +#neweditanswer .CodeMirror { + margin-top: 31px !important; + height: 364px !important; + /*width: 549.5px !important;*/ +} + +#neweditanswer .editormd-preview { + top: 40px !important; + height: 364px !important; + width: 551px !important; +} + +#repository_url_tip { + top: 30px !important; + left: 249px !important; + width: 292px !important; +} + +#editanswers .CodeMirror{ + /*width: 548px !important;*/ + height: 358px !important; + margin-top: 30px !important; +} +#editanswers .editormd-preview{ + width: 578px !important; + height: 358px !important; + +} +#newquestioMDs .CodeMirror{ + /*width: 510px !important;*/ + height: 358px !important; + margin-top: 30px !important; +} + +#newquestioMDs .editormd-preview{ + width: 578px !important; + height: 358px !important; +} + +.choose_names{ + width: 80px; + margin-left: 20px; +} + +#answerMD .CodeMirror{ + /*width: 569px !important;*/ + height: 600px !important; + margin-top: 30px !important; +} + +#answerMD .editormd-preview{ + width: 578px !important; + height: 600px !important; +} + +#answerMD { + height: 600px !important; +} + +.textareavalue{ + width: 100%; + padding: 5px; + + box-sizing: border-box; +} +.greyInput{ + width: 107%; +} +.greyInpus{ + width: 100%; +} + +.pdr20{ + padding-right:20px; +} + +.winput-240-40s { + background-color: #F5F5F5; +} + + +.winput-240-40s:focus{ + background-color: #fff; +} +.input-100-45{ + background-color: #F5F5F5; +} +.input-100-45:focus{ + background-color: #fff; + } + +.wind100{ + width:100% !important; +} + +.color-bule-tip { + color: #5485f7 !important; +} +.martopf4{ + margin-top:-4px; +} + +.headdfgf{ + display: block; + width: 100px; + height: 30px; + line-height: 30px; + float: left; +} + +.color979797{ + color: #979797 !important; +} + +.border-left{ + width: 0; + height: 0; + border-bottom: 6px solid transparent; + border-right: 6px solid #cccbcb; + border-top: 6px solid transparent; + position: absolute; + left: 30px; + top: 12px; +} +.border-left span{ + display: block; + width: 0; + height: 0; + border-bottom: 6px solid transparent; + border-right: 6px solid #fff; + border-top: 6px solid transparent; + position: absolute; + left: 1px; + top: -6px; + z-index: 10; +} +.fillTip{ + position: absolute; + left: 36px; + top: 2px; + width: 125px; + font-size: 12px; + display: block; + padding: 5px; + border: 1px solid #eaeaea; + border-radius: 5px; + box-sizing: border-box; + height: 32px; + line-height: 20px; + font-family: "微软雅黑","宋体"; +} \ No newline at end of file diff --git a/public/react/src/tpm/challengesnew/editorMD.js b/public/react/src/tpm/challengesnew/editorMD.js new file mode 100644 index 000000000..50f15b601 --- /dev/null +++ b/public/react/src/tpm/challengesnew/editorMD.js @@ -0,0 +1,122 @@ +import React, {Component} from 'react'; + +import {getUrl} from 'educoder'; + +let path = getUrl("/editormd/lib/"); + +const $ = window.$; + +function create_editorMD(id, width, high, placeholder, imageUrl, callback) { + var editorName = window.editormd(id, { + width: width, + height: high, + path: path, // "/editormd/lib/" + + syncScrolling: "single", + tex: true, + tocm: true, + emoji: true, + taskList: true, + codeFold: true, + searchReplace: true, + htmlDecode: "style,script,iframe", + sequenceDiagram: true, + autoFocus: false, + toolbarIcons: function () { + // Or return editormd.toolbarModes[name]; // full, simple, mini + // Using "||" set icons align right. + return ["bold", "italic", "|", "list-ul", "list-ol", "|", "code", "code-block", "|", "testIcon", "testIcon1", '|', "image", "table", '|', "watch", "clear"] + }, + toolbarCustomIcons: { + testIcon: "
    ", + testIcon1: "
    " + }, + //这个配置在simple.html中并没有,但是为了能够提交表单,使用这个配置可以让构造出来的HTML代码直接在第二个隐藏的textarea域中,方便post提交表单。 + saveHTMLToTextarea: true, + // 用于增加自定义工具栏的功能,可以直接插入HTML标签,不使用默认的元素创建图标 + dialogMaskOpacity: 0.6, + placeholder: placeholder, + imageUpload: true, + imageFormats: ["jpg", "jpeg", "gif", "png", "bmp", "webp", "JPG", "JPEG", "GIF", "PNG", "BMP", "WEBP"], + imageUploadURL: imageUrl,//url + onload: function () { + // this.previewing(); + $("#" + id + " [type=\"latex\"]").bind("click", function () { + editorName.cm.replaceSelection("```latex"); + editorName.cm.replaceSelection("\n"); + editorName.cm.replaceSelection("\n"); + editorName.cm.replaceSelection("```"); + var __Cursor = editorName.cm.getDoc().getCursor(); + editorName.cm.setCursor(__Cursor.line - 1, 0); + }); + + $("#" + id + " [type=\"inline\"]").bind("click", function () { + editorName.cm.replaceSelection("`$$$$`"); + var __Cursor = editorName.cm.getDoc().getCursor(); + editorName.cm.setCursor(__Cursor.line, __Cursor.ch - 3); + editorName.cm.focus(); + }); + $("[type=\"inline\"]").attr("title", "行内公式"); + $("[type=\"latex\"]").attr("title", "多行公式"); + + window.md_elocalStorage(editorName, `MemoQuestion_${id}`, `${id}Question`); + + callback && callback() + } + }); + return editorName; +} + + +export default class TPMeditorMD extends Component { + constructor(props) { + super(props) + + } + componentDidMount() { + + + } + + questioMD=(initValue, id)=> { + + this.contentChanged = false; + const placeholder = ""; +// amp; +// 编辑时要传memoId + // const imageUrl = `/upload_with_markdown?container_id=&container_type=Memo`; + const imageUrl = `/api/attachments.json`; +// 创建editorMd + + let questio_editormd = create_editorMD(id, '100%', 400, placeholder, imageUrl, () => { + setTimeout(() => { + questio_editormd.resize() + questio_editormd.cm && questio_editormd.cm.refresh() + }, 500) + + if (initValue != undefined) { + questio_editormd.setValue(initValue) + } + questio_editormd.cm.on("change", (_cm, changeObj) => { + console.log('....contentChanged') + this.contentChanged = true; + }) + }); + this.questio_editormd = questio_editormd; + window.questio_editormd = questio_editormd; + + } + + componentWillReceiveProps(newProps) { + this.questioMD(newProps.value,newProps.id) + } + render() { + return ( +
    + +
    +
    +
    + ) + } +} diff --git a/public/react/src/tpm/component/TPMNav.js b/public/react/src/tpm/component/TPMNav.js new file mode 100644 index 000000000..ff8f57aa5 --- /dev/null +++ b/public/react/src/tpm/component/TPMNav.js @@ -0,0 +1,57 @@ +import React, { Component } from 'react'; + +import { BrowserRouter as Router, Route, Link } from "react-router-dom"; + +class TPMNav extends Component { + + render() { + const { user, match, shixun, secret_repository } = this.props; + let isAdminOrCreator = false; + if (user) { + isAdminOrCreator = user.admin || user.manager + } + const shixunId = match.params.shixunId; + // const challengesPath = `/shixuns/${shixunId}/challenges`; + // console.log(this.props.propaedeutics) + const challengesPath = `/shixuns/${shixunId}/challenges`; + // console.log(match.path) + return ( +
    + 任务 + + { + this.props.propaedeutics===undefined?"":this.props.propaedeutics===false?"":背景知识 + } + + { this.props.identity >4||this.props.identity===undefined ?"":版本库} + {this.props.identity >4||this.props.identity===undefined ?"": secret_repository && 私密版本库} + + 合作者 + + 评论 + + 排行榜 + + {this.props.identity >2||this.props.identity===undefined?"":审核情况} + + 4||this.props.identity===undefined ? "none" : 'block'}} + >配置 +
    + ); + } +} + +export default TPMNav; diff --git a/public/react/src/tpm/component/TPMRightSection.js b/public/react/src/tpm/component/TPMRightSection.js new file mode 100644 index 000000000..4306fc6e3 --- /dev/null +++ b/public/react/src/tpm/component/TPMRightSection.js @@ -0,0 +1,205 @@ +import React, { Component } from 'react'; + +import { BrowserRouter as Router, Route, Link } from "react-router-dom"; + +import axios from 'axios'; + +import { getImageUrl,} from "educoder"; + +import './TPMright.css'; + +import {Icon,Tooltip} from 'antd'; + +// import "antd/dist/antd.css"; + +class TPMRightSection extends Component { + constructor(props) { + super(props) + this.state = { + + TPMRightSection:false, + clickNewsubscripttype:false + } + } + + // componentDidMount() { + // let id=this.props.match.params.shixunId; + // + // let shixunsDetailsURL=`/shixuns/`+id+`/show_right.json`; + // + // axios.get(shixunsDetailsURL).then((response)=> { + // if(response.status===200){ + // this.setState({ + // TPMRightSectionData: response.data + // }); + // } + // }).catch((error)=>{ + // console.log(error) + // }); + // } + + // shouldComponentUpdate(nextProps, nextState) { + // return nextProps.TPMRightSectionData !== this.state.TPMRightSectionData + // } + clickNewsubscript=(val)=>{ + if(val===0){ + this.setState({ + TPMRightSection:true, + clickNewsubscripttype:true + }) + }else{ + this.setState({ + TPMRightSection:false, + clickNewsubscripttype:false + }) + } + + } + render() { + let {TPMRightSection,clickNewsubscripttype}=this.state; + let {TPMRightSectionData}=this.props + + return ( +
    + { + TPMRightSectionData===undefined?"": +
    +
    +

    创建者

    +
    + + 头像 + +
    + +

    {TPMRightSectionData===undefined?"":TPMRightSectionData.creator===undefined?"":TPMRightSectionData.creator.name}

    +
    + 发布 {TPMRightSectionData.user_shixuns_count} + {/*粉丝 {TPMRightSectionData.fans_count}*/} + {/* 取消关注 */} +
    + +
    +
    +
    + { + TPMRightSectionData === undefined ? "" :TPMRightSectionData.tags===undefined?"": TPMRightSectionData.tags.length === 0 ? "" : +
    +

    技能标签 {TPMRightSectionData.tags.length}

    +
    +
    + { TPMRightSectionData.tags.map((item,key)=>{ + return( + {item.tag_name} + )}) + } +
    +
    + + +
    15&&clickNewsubscripttype===false?"newsubscript mb9 color-grey-9":"newsubscript mb9 color-grey-9 none"} + + data-tip-down="显示全部" + onClick={()=>this.clickNewsubscript(0)}>... +
    + + +
    this.clickNewsubscript(1)}> +
    + +
    + + + } + + +
    +

    所属课程

    +
    + { + TPMRightSectionData===undefined?"":TPMRightSectionData.paths===undefined?"":TPMRightSectionData.paths.map((i,k)=>{ + + return( + +
    + + + 实训 + + +
    + {i.name} +

    + + + {i.stages_count} + + + {/**/} + {/*{i.score_count}*/} + {/**/} + + + {i.members_count} + + +

    +
    + +
    + + ) + }) + } +
    +
    + + {TPMRightSectionData === undefined?"":TPMRightSectionData.paths===undefined?"":TPMRightSectionData.paths.length === 0 ? "" : + this.props.user&&this.props.user.main_site===true?
    +

    推荐实训

    +
    + { + TPMRightSectionData===undefined?"":TPMRightSectionData.recommands===undefined?"":TPMRightSectionData.recommands.map((item,key)=>{ + return( +
    + + 69?1526971094 + +
    + + {item.name} + +

    + {item.stu_num} 人学习 +

    +

    {item.level}

    +
    +
    + ) + }) + } +
    +
    :"" + } +
    + } +
    + ) + + + } +} + +export default TPMRightSection; diff --git a/public/react/src/tpm/component/TPMright.css b/public/react/src/tpm/component/TPMright.css new file mode 100644 index 000000000..c664d75c4 --- /dev/null +++ b/public/react/src/tpm/component/TPMright.css @@ -0,0 +1,79 @@ +/*b新标签*/ +.newedu-filter-btn{ + display: block; + float: left; + padding: 0 9px; + /*height: 28px;*/ + line-height: 28px; + border-radius: 14px; + background-color: #F5F5F5; + color: #666; + margin-right: 10px; + margin-bottom: 9px; +} +.newedbox{ + /*flex-wrap: wrap;*/ + /*display: -webkit-flex; !* Safari *!*/ + /*display: flex;*/ + width: 360px; + position:relative; + overflow: hidden; +} +.newsubscript{ + position: absolute; + right: 23px; + bottom: 16px; + cursor: pointer; +} +.newsubscript:hover{ + color:deepskyblue; +} +.edu-filter-btn29BD8B{ + display: block; + float: left; + padding: 0 9px; + height: 28px; + line-height: 28px; + border-radius: 14px; + background-color: #29BD8B; + color: #FFF; + margin-right: 10px; + margin-bottom: 9px; +} +.relative{ + position:relative; +} +.newedboxheight{ + max-height: 177px; + overflow-y: hidden; +} +.newminheight{ + /*max-height: 670px;*/ + max-height: 300px; + overflow-y: auto; +} + +.delSubentry{ + font-size:7px; + font-family:MicrosoftYaHei; + font-weight:400; + color:rgba(76,172,255,1); + line-height:9px; + cursor: pointer; +} +.operationalter .delSubentry{ + font-size:15px !important; + line-height: 25px; +} +/*临时的tpi关闭按钮样式*/ +.headerRight a { + color: #1a3f5f; +} +/*实训做成弹窗a标签样式调整*/ +.-task-list-title a:link, .-task-list-title a:visited {color: #bcc6cd;} +.-task-list-title a:hover{ + color: #459be5; +} +.headerLeft .-header-right{ + height: 32px; +} \ No newline at end of file diff --git a/public/react/src/tpm/component/modal/RepositoryChooseModal.js b/public/react/src/tpm/component/modal/RepositoryChooseModal.js new file mode 100644 index 000000000..4b72ae2bd --- /dev/null +++ b/public/react/src/tpm/component/modal/RepositoryChooseModal.js @@ -0,0 +1,153 @@ +// import React, { useState, useEffect, memo } from 'react'; +// import axios from 'axios' +// import { Modal, Input } from 'antd'; + +// function RepositoryChooseModal(props) { +// const [trees, setTrees] = useState([]) +// const [path, setPath] = useState('') +// const [pathArray, setPathArray] = useState([{val: "根目录/", path: ""}]) +// const [modalVisible, setModalVisible] = useState(true) + +// useEffect(() => { +// repository('') +// }, []) +// function onOk() { + +// } +// function onCancel() { + +// } +// /** +// 点nav 会传入key +// 点item 会传入 newPath + +// item => name, type type tree/leaf +// */ +// const repository=(item, key, newPath)=>{ +// let newPathArray = [] // +// // +// if (key) { +// for(var i=0; i<=key; i++){ +// newPathArray.push(pathArray[i]) +// } +// } else if (item) { +// newPathArray = pathArray.slice(0) +// newPathArray.push({val: item.name, path: pathArray[pathArray.length - 1] + "/" + item.name}) +// } + +// const path = item || key ? newPathArray[newPathArray.length - 1] : '' + +// let id = props.match.params.shixunId; +// let url ="/shixuns/"+id+"/repository.json"; +// axios.post(url,{ +// path: path +// }).then((response) => { +// if (response.data.status === 403||response.data.status === 401||response.data.status === 500) { + +// }else{ +// setTrees(response.data.trees) +// setPath(path) +// pathArray(newPathArray) +// } + +// }).catch((error) => { +// console.log(error) +// }); +// } +// const savegetfilepath=(value)=>{ +// const state = {} +// let {selectpath,saveshixunfilepath,pathtype} = state + +// if(pathtype===1){ +// let newselectpath; + +// if(saveshixunfilepath==="shixunfilepathplay"){ +// newselectpath=value +// }else{ +// const type = selectpath.split(';'); +// let types=false; +// for(var i=0; i{ + +// } +// function sendgetfilepath() { + +// } +// return ( +// +//
    +//
    +// +//
    +// +// saveselectpath(e)} +// value={path}/> +//
    + +// onOk()}>确定 +// onCancel()}>取消 +//
    +//
    +//
    +// ) + +// } + +// export default RepositoryChooseModal \ No newline at end of file diff --git a/public/react/src/tpm/newshixuns/Newshixuns.js b/public/react/src/tpm/newshixuns/Newshixuns.js new file mode 100644 index 000000000..1eaee9ad6 --- /dev/null +++ b/public/react/src/tpm/newshixuns/Newshixuns.js @@ -0,0 +1,1356 @@ +import React, {Component} from 'react'; + +import {TPMIndexHOC} from '../TPMIndexHOC'; + +import {SnackbarHOC,appendFileSizeToUploadFileAll, getUploadActionUrl} from 'educoder'; + +import {Input, Select, Radio, Checkbox, Modal, Icon, DatePicker,Upload,Button,message,Form,notification,Tooltip} from 'antd'; + +// import "antd/dist/antd.css"; + +import locale from 'antd/lib/date-picker/locale/zh_CN'; + +import axios from 'axios'; + +import './css/Newshixuns.css'; + +import {getUrl} from 'educoder' + +import moment from 'moment'; + +let path = getUrl("/editormd/lib/") + +const $ = window.$; + +let timeout; + +let currentValue; + +const Option = Select.Option; + +const RadioGroup = Radio.Group; +const confirm = Modal.confirm; + + +// 处理整点 半点 +// 取传入时间往后的第一个半点 +export function handleDateStrings(dateString) { + if (!dateString) return dateString; + const ar = dateString.split(':') + if (ar[1] == '00' || ar[1] == '30') { + return dateString + } + const miniute = parseInt(ar[1]); + if (miniute < 30 || miniute == 60) { + return [ar[0], '30'].join(':') + } + if (miniute < 60) { + // 加一个小时 + const tempStr = [ar[0], '00'].join(':'); + const format = "YYYY-MM-DD HH:mm"; + const _moment = moment(tempStr, format) + _moment.add(1, 'hours') + return _moment.format(format) + } + + return dateString +} + + + +// 恢复数据 +function md_rec_data(k, mdu, id, editor) { + if (window.sessionStorage.getItem(k + mdu) !== null) { + editor.setValue(window.sessionStorage.getItem(k + mdu)); + md_clear_data(k, mdu, id); + } +} + +// 保存数据 +function md_add_data(k, mdu, d) { + window.sessionStorage.setItem(k + mdu, d); +} + +// 清空保存的数据 +function md_clear_data(k, mdu, id) { + window.sessionStorage.removeItem(k + mdu); + var id1 = "#e_tip_" + id; + var id2 = "#e_tips_" + id; + if (k == 'content') { + $(id2).html(""); + } else { + $(id1).html(""); + } +} + +function md_elocalStorage(editor, mdu, id) { + if (window.sessionStorage) { + var oc = window.sessionStorage.getItem('content' + mdu); + if (oc !== null) { + $("#e_tips_" + id).data('editor', editor); + var h = '您上次有已保存的数据,是否恢复 ? / 不恢复'; + $("#e_tips_" + id).html(h); + } + setInterval(function () { + var d = new Date(); + var h = d.getHours(); + var m = d.getMinutes(); + var s = d.getSeconds(); + h = h < 10 ? '0' + h : h; + m = m < 10 ? '0' + m : m; + s = s < 10 ? '0' + s : s; + if (editor.getValue().trim() != "") { + md_add_data("content", mdu, editor.getValue()); + var id1 = "#e_tip_" + id; + var id2 = "#e_tips_" + id; + + $(id1).html(" 数据已于 " + h + ':' + m + ':' + s + " 保存 "); + $(id2).html(""); + } + }, 10000); + + } else { + $("#e_tip_" + id).after('您的浏览器不支持localStorage.无法开启自动保存草稿服务,请升级浏览器!'); + } +} + + +function create_editorMD(id, width, high, placeholder, imageUrl, callback) { + var editorName = window.editormd(id, { + width: width, + height: high, + path: path, // "/editormd/lib/" + + syncScrolling: "single", + tex: true, + tocm: true, + emoji: true, + taskList: true, + codeFold: true, + searchReplace: true, + htmlDecode: "style,script,iframe", + sequenceDiagram: true, + autoFocus: false, + toolbarIcons: function () { + // Or return editormd.toolbarModes[name]; // full, simple, mini + // Using "||" set icons align right. + return ["bold", "italic", "|", "list-ul", "list-ol", "|", "code", "code-block", "|", "testIcon", "testIcon1", '|', "image", "table", '|', "watch", "clear"] + }, + toolbarCustomIcons: { + testIcon: "
    ", + testIcon1: "
    " + }, + //这个配置在simple.html中并没有,但是为了能够提交表单,使用这个配置可以让构造出来的HTML代码直接在第二个隐藏的textarea域中,方便post提交表单。 + saveHTMLToTextarea: true, + // 用于增加自定义工具栏的功能,可以直接插入HTML标签,不使用默认的元素创建图标 + dialogMaskOpacity: 0.6, + placeholder: placeholder, + imageUpload: true, + imageFormats: ["jpg", "jpeg", "gif", "png", "bmp", "webp", "JPG", "JPEG", "GIF", "PNG", "BMP", "WEBP"], + imageUploadURL: imageUrl,//url + onload: function () { + // this.previewing(); + $("#" + id + " [type=\"latex\"]").bind("click", function () { + editorName.cm.replaceSelection("```latex"); + editorName.cm.replaceSelection("\n"); + editorName.cm.replaceSelection("\n"); + editorName.cm.replaceSelection("```"); + var __Cursor = editorName.cm.getDoc().getCursor(); + editorName.cm.setCursor(__Cursor.line - 1, 0); + }); + + $("#" + id + " [type=\"inline\"]").bind("click", function () { + editorName.cm.replaceSelection("`$$$$`"); + var __Cursor = editorName.cm.getDoc().getCursor(); + editorName.cm.setCursor(__Cursor.line, __Cursor.ch - 3); + editorName.cm.focus(); + }); + $("[type=\"inline\"]").attr("title", "行内公式"); + $("[type=\"latex\"]").attr("title", "多行公式"); + + md_elocalStorage(editorName, `memoNew_${id}`, "memoNew"); + + callback && callback() + } + }); + return editorName; +} + +function range(start, end) { + const result = []; + for (let i = start; i < end; i++) { + result.push(i); + } + return result; +} +function disabledDateTime() { + return { + // disabledHours: () => range(0, 24).splice(4, 20), + disabledMinutes: () => range(1, 30).concat(range(31, 60)), + // disabledSeconds: () => [0, 60], + }; +} + +function disabledDate(current) { + return current && current < moment().endOf('day').subtract(1, 'days'); +} +class Newshixuns extends Component { + constructor(props) { + super(props) + this.state = { + fileList: [], + newshixunlist: undefined, + departmentslist: undefined, + name: "", + main_type: "", + small_type: "", + trainee: "", + webssh: 0, + use_scope: 0, + can_copy: "", + scope_partment: undefined, + vnc: "", + scopetype: false, + postapplyvisible: false, + sendsure_applyvalue: undefined, + postapplytitle: false, + shixun_nametype: false, + main_types: false, + trainee_types: false, + SelectTheCommandtype: false, + opers: false, + operss: false, + TimePickervalue: "", + opensmail: false, + onSearchvalue: "", + scope_partmenttype: false, + languagewrite: undefined, + systemenvironment:undefined, + testcoderunmode:undefined, + file:undefined, + deleteisnot:true, + languagewritetype:false, + systemenvironmenttype:false, + testcoderunmodetype:false, + attachmentidstype:false, + datalisttype:false, + bottonloading:false + } + } + + initMD(initValue) { + this.contentChanged = false; + const placeholder = ""; + // amp; + // 编辑时要传memoId + const imageUrl = `/api/attachments.json`; + // 创建editorMd + + const taskpass_editormd = create_editorMD("memoMD", '100%', 400, placeholder, imageUrl, () => { + setTimeout(() => { + taskpass_editormd.resize() + taskpass_editormd.cm && taskpass_editormd.cm.refresh() + }, 500) + + if (initValue) { + taskpass_editormd.setValue(initValue) + } + taskpass_editormd.cm.on("change", (_cm, changeObj) => { + // console.log('....contentChanged') + this.contentChanged = true; + }) + }); + this.taskpass_editormd = taskpass_editormd; + window.taskpass_editormd = taskpass_editormd; + + } + + componentDidMount() { + let newshixunUrl = `/shixuns/new.json`; + axios.get(newshixunUrl).then((response) => { + if (response.status === 200) { + if (response.data.message===undefined) { + this.setState({ + newshixunlist: response.data + }); + this.initMD(response.data.sample[0][1]); + } + + } + }).catch((error) => { + console.log(error) + }); + + let departmentsUrl = `/shixuns/departments.json`; + axios.get(departmentsUrl).then((response) => { + if (response.status === 200) { + if (response.data.message===undefined) { + this.setState({ + departmentslist: response.data.shools_name + }); + } + } + }).catch((error) => { + console.log(error) + }); + } + + setlanguagewrite = (e)=>{ + this.setState({ + languagewrite: e.target.value + }) + } + + setsystemenvironment = (e) => { + this.setState({ + systemenvironment: e.target.value + }) + } + settestcoderunmode = (e) => { + this.setState({ + testcoderunmode: e.target.value + }) + + } + shixunname = (e) => { + this.setState({ + name: e.target.value, + shixun_nametype: false + }); + } + + bigClass = (value) => { + this.setState({ + main_type: value + }) + } + + littleClass = (value) => { + this.setState({ + small_type: value + }) + } + + Selectthestudent = (value) => { + this.setState({ + trainee: value + }) + } + + SelectTheCommand = (e) => { + this.setState({ + webssh: e.target.value, + }); + + if (e.target.value === 2) { + this.setState({ + SelectTheCommandtype: true, + multi_webssh: false + }); + } else { + this.setState({ + SelectTheCommandtype: false, + multi_webssh: false + }); + } + } + + Selectpublic = (e) => { + this.setState({ + scopetype: false, + use_scope: e.target.value, + }); + if (e.target.value === 1) { + this.setState({ + scopetype: true + }); + } + + } + + Teacherscopy = (e) => { + let sum = "" + if (e.target.checked === false) { + sum = 0 + } else if (e.target.checked === true) { + sum = 1 + } + this.setState({ + can_copy: sum, + }); + } + + TeachersUbuntu = (e) => { + let sum = "" + if (e.target.checked === false) { + sum = 0 + } else if (e.target.checked === true) { + sum = 1 + } + this.setState({ + vnc: sum, + }); + } + + adduse_scopeinput = () => { + let {scope_partment} = this.state; + let array = scope_partment; + let newarray = "" + array.push(newarray) + this.setState({ + scope_partment: array, + }); + } + + shixunScopeInput = (e, id) => { + let types=false + let {scope_partment} = this.state; + let datalist = scope_partment; + if (datalist === undefined) { + datalist = [] + } + + datalist.map((item,key)=>{ + if(e===item){ + types=true + this.setState({ + datalisttype:true + }) + return + } + }) + + if(types===false){ + datalist.push(e) + this.setState({ + scope_partment: datalist, + onSearchvalue: "" + }); + } + + + } + + deleteScopeInput = (key) => { + let {scope_partment} = this.state; + let datalist = scope_partment; + datalist.splice(key, 1); + this.setState({ + scope_partment: datalist + }); + } + + //提交数据 + submit_new_shixun = () => { + const mdVal = this.taskpass_editormd.getValue(); + let {can_copy, main_type, name, scope_partment, small_type, trainee, use_scope, vnc, webssh, multi_webssh, TimePickervalue} = this.state; + let Url = `/shixuns.json` + if (name === "") { + this.setState({ + shixun_nametype: true + }) + this.props.showSnackbar("实训名称为空"); + $('html').animate({ + scrollTop: 10 + }, 1000); + return + } + if (main_type === "") { + this.setState({ + main_types: true + }) + $('html').animate({ + scrollTop: 700 + }, 1000); + this.props.showSnackbar("请选择技术平台大类别"); + + return + } + + if (use_scope === 1) { + if (scope_partment === undefined || scope_partment.length === 0) { + this.setState({ + scope_partmenttype: true + }) + $('html').animate({ + scrollTop: 900 + }, 1000); + this.props.showSnackbar("公开程度,指定单位为空"); + return + } + } + if (trainee === "") { + this.setState({ + trainee_types: true + }) + // $('html').animate({ + // scrollTop: 700 + // }, 1000); + this.props.showSnackbar("请选择发布信息"); + return + } + let newmulti_webssh = multi_webssh; + if (newmulti_webssh === true) { + newmulti_webssh = 1 + } else { + newmulti_webssh = "" + } + this.setState({ + bottonloading:true + }) + axios.post(Url, { + name: name, + can_copy: can_copy, + description: mdVal, + main_type: main_type, + scope_partment: scope_partment, + small_type: small_type, + trainee: trainee, + use_scope: use_scope, + vnc: vnc, + webssh: webssh, + multi_webssh: newmulti_webssh, + task_pass: 1, + opening_time: TimePickervalue + } + ).then((response) => { + if (response.status === 200) { + window.location.href = "/shixuns/" + response.data.shixun_identifier + "/challenges"; + // window.open("/shixuns/"+response.data.shixun_identifier+"/challenges"); + }else{ + this.setState({ + bottonloading:false + }) + } + }).catch((error) => { + console.log(error) + this.setState({ + bottonloading:false + }) + }) + } + + + shixunsfetch = (value, callback) => { + if (timeout) { + clearTimeout(timeout); + timeout = null; + } + currentValue = value; + + function fake() { + let departmentsUrl = `/shixuns/departments.json?q=` + currentValue; + axios.get(departmentsUrl).then((response) => { + if (response.data.message===undefined) { + callback(response.data.shools_name); + } + }).catch((error) => { + console.log(error) + }); + } + + timeout = setTimeout(fake, 300); + } + + shixunHandleSearch = (value) => { + + this.shixunsfetch(value, departmentslist => this.setState({departmentslist})); + + this.setState({ + onSearchvalue: "" + }) + } + + post_apply = () => { + this.setState({ + postapplyvisible: true + }) + } + sendsure_apply = () => { + let {languagewrite,systemenvironment,testcoderunmode} = this.state; + // console.log("点击确定") + // console.log("languagewrite"+languagewrite); + // console.log("systemenvironment"+systemenvironment); + // console.log("testcoderunmode"+testcoderunmode); + + // let attachment_ids = undefined + // if (this.state.fileList) { + // attachment_ids = this.state.fileList.map(item => { + // return item.response ? item.response.id : item.id + // }) + // } + if(languagewrite === undefined || languagewrite === "" ){ + // this.props.showNotification(`请填写该镜像是基于什么语言`); + this.setState({ + languagewritetype:true + }) + return + } + if(systemenvironment === undefined || systemenvironment === ""){ + // this.props.showNotification(`请填写该镜像是基于什么语言系统环境`); + this.setState({ + systemenvironmenttype:true + }) + return; + + } + if(testcoderunmode === undefined || testcoderunmode === "") { + // this.props.showNotification(`请填写该镜像中测试代码运行方式`); + this.setState({ + testcoderunmodetype:true + }) + return; + } + var attachment_ids=undefined; + if (this.state.fileList) { + attachment_ids = this.state.fileList.map(item => { + return item.response ? item.response.id : item.id + }) + } + + if( attachment_ids === undefined || attachment_ids.length===0){ + + // notification.open( + // { + // message: '提示', + // description: + // '请上传附件!', + // + // } + // ) + this.setState({ + attachmentidstype:true + }) + return; + } + // console.log("attachment_ids"+attachment_ids); + + // alert(languagewrite +" "+systemenvironment +" "+testcoderunmode + " "+attachment_ids); + + var data={ + language:languagewrite, + runtime:systemenvironment, + run_method:testcoderunmode, + attachment_id:attachment_ids[0], + } + var url =`/shixuns/apply_shixun_mirror.json`; + axios.post(url,data + ).then((response) => { + + try { + if (response.data) { + // const { id } = response.data; + // if (id) { + if(this.state.file !== undefined){ + console.log("549"); + // this.deleteAttachment(this.state.file); + this.setState({ + file:undefined, + deleteisnot:true, + languagewrite:"", + systemenvironment:"", + testcoderunmode:"", + fileList:[] + }) + }else { + this.setState({ + file:undefined, + deleteisnot:true, + languagewrite:"", + systemenvironment:"", + testcoderunmode:"", + fileList:[] + }) + } + // this.props.showNotification('提交成功!'); + notification.open( + { + message: '提示', + description: + '提交成功!', + + } + ) + this.sendhideModaly() + // this.props.history.push(`/courses/${cid}/graduation_topics`); + // } + } + }catch (e) { + + } + + }) + + } + sendhideModaly = () => { + this.setState({ + postapplyvisible: false, + }) + if(this.state.file !== undefined){ + console.log("580"); + // this.deleteAttachment(this.state.file); + this.setState({ + file:undefined, + deleteisnot:true, + languagewrite:"", + systemenvironment:"", + testcoderunmode:"", + fileList:[] + }) + }else { + this.setState({ + file:undefined, + deleteisnot:true, + languagewrite:"", + systemenvironment:"", + testcoderunmode:"", + fileList:[] + }) + } + } + sendsure_applyvalues = (e) => { + this.setState({ + sendsure_applyvalue: e.target.value + }) + } + yeshidemodel = () => { + this.setState({ + postapplytitle: false + }) + } + + SelectTheCommandonChange = (e) => { + this.setState({ + multi_webssh: e.target.checked + }) + } + + + bigopen = (e) => { + this.setState({ + opers: true + }) + + } + + bigopens = (e) => { + this.setState({ + opers: false, + operss: false, + opensmail: false + }) + + } + + bigopensmal = (e) => { + this.setState({ + opensmail: true + }) + + } + + sbigopen = (e) => { + this.setState({ + operss: true + }) + + } + + // sbigopens=()=>{ + // this.setState({ + // operss:false + // }) + // } + + onChangeTimePicker = (value, dateString) => { + this.setState({ + TimePickervalue: dateString=== ""?"":moment(handleDateStrings(dateString)) + }) + } + + // 附件相关 START + handleChange = (info) => { + if(info.file.status === 'uploading' || info.file.status === 'done' || info.file.status === 'removed') { + let {fileList} = this.state; + + if (info.file.status === 'uploading' || info.file.status === 'done' || info.file.status === 'removed') { + console.log("handleChange1"); + // if(fileList.length===0){ + let fileLists = info.fileList; + this.setState({ + // fileList:appendFileSizeToUploadFileAll(fileList), + fileList: fileLists, + deleteisnot: false + }); + // } + } + } + } + onAttachmentRemove = (file) => { + if(!file.percent || file.percent == 100){ + confirm({ + title: '确定要删除这个附件吗?', + okText: '确定', + cancelText: '取消', + // content: 'Some descriptions', + onOk: () => { + console.log("665") + this.deleteAttachment(file) + }, + onCancel() { + console.log('Cancel'); + }, + }); + return false; + } + + } + deleteAttachment = (file) => { + console.log(file); + let id=file.response ==undefined ? file.id : file.response.id + const url = `/attachments/${id}.json` + axios.delete(url, { + }) + .then((response) => { + if (response.data) { + const { status } = response.data; + if (status == 0) { + // console.log('--- success') + + this.setState((state) => { + + const index = state.fileList.indexOf(file); + const newFileList = state.fileList.slice(); + newFileList.splice(index, 1); + return { + fileList: newFileList, + deleteisnot:true + }; + }); + } + } + }) + .catch(function (error) { + console.log(error); + }); + } + + + handleSubmit=()=>{ + // console.log(this.state.languagewrite) + // console.log(this.state.systemenvironment) + // console.log(this.state.testcoderunmode) + var attachment_ids; + if (this.state.fileList) { + attachment_ids = this.state.fileList.map(item => { + return item.response ? item.response.id : item.id + }) + } + // console.log(attachment_ids); + // var data={ + // language:"", + // runtime:"", + // run_method:"", + // attachment_id:"", + // } + // axios.post(url,data + // ).then((response) => { + // if (response.data) { + // // const { id } = response.data; + // // if (id) { + // this.props.showNotification('提交成功!'); + // // this.props.history.push(`/courses/${cid}/graduation_topics`); + // // } + // } + // }) + + + + } + render() { + const { getFieldDecorator } = this.props.form; + let {testcoderunmode ,systemenvironment,languagewrite,deleteisnot, fileList,TimePickervalue, scope_partmenttype, opensmail, newshixunlist, name, scope_partment, departmentslist, postapplyvisible, sendsure_applyvalue, postapplytitle, shixun_nametype, main_types, trainee_types, SelectTheCommandtype, opers, datalisttype, onSearchvalue} = this.state; + let options + if (departmentslist != undefined) { + options = this.state.departmentslist.map((d, k) => { + return ( + + ) + }) + } + const uploadProps = { + width: 600, + fileList, + multiple: true, + // https://github.com/ant-design/ant-design/issues/15505 + // showUploadList={false},然后外部拿到 fileList 数组自行渲染列表。 + // showUploadList: false, + action: `${getUploadActionUrl()}`, + onChange: this.handleChange, + onRemove: this.onAttachmentRemove, + beforeUpload: (file, fileList) => { + + if (this.state.fileList.length >= 1) { + return false + } + // console.log('beforeUpload', file.name); + const isLt150M = file.size / 1024 / 1024 < 50; + if (!isLt150M) { + // this.props.showNotification(`文件大小必须小于50MB`); + notification.open( + { + message: '提示', + description: + '文件大小必须小于50MB', + + } + ) + } + if(this.state.file !== undefined){ + console.log("763") + this.setState({ + file:file + }) + }else { + this.setState({ + file:file + }) + } + + console.log("handleChange2"); + return isLt150M; + }, + } + // const uploadProps = { + // width: 600, + // fileList, + // multiple: true, + // // https://github.com/ant-design/ant-design/issues/15505 + // // showUploadList={false},然后外部拿到 fileList 数组自行渲染列表。 + // // showUploadList: false, + // action: `${getUrl()}/api/attachments.json`, + // onChange: this.handleChange, + // onRemove: this.onAttachmentRemove, + // beforeUpload: (file) => { + // // console.log('beforeUpload', file.name); + // const isLt50M = file.size / 1024 / 1024 < 50; + // if (!isLt50M) { + // this.props.showNotification('文件大小必须小于150MB!'); + // } + // return isLt50M; + // }, + // }; + + return ( + +
    +
    +
    + +
    +

    + 创建实训 + {this.props.user&&this.props.user.main_site===true?实训制作指南:""} +

    + +
    +

    实训名称

    +
    + * +
    + + + 必填项 + +
    + +
    +
    + +
    + + +
    + +

    简介

    + +
    +
    + +
    +
    +

    +

    +
    + +
    +

    技术平台

    +
    + * +
    + +

    + 列表中没有? + 申请新建 +

    + + + {/**/} +
    +
  • + + +
  • +
    {this.state.languagewritetype===true?"请填写该镜像语言":""}
    +
  • + + +
  • +
    {this.state.systemenvironmenttype===true?"请填写该镜像语言系统环境":""}
    +
  • + + + +
  • +
    {this.state.testcoderunmodetype===true?"请填写该镜像测试代码运行方式":""}
    +
  • + +
    + + + 上传附件 + (单个文件50M以内) + + +
    + +
  • +
    + {this.state.attachmentidstype===true?"请上传附件":""} +
    +
  • + this.sendhideModaly()} + >取消 + +
  • +
    +
    + {/**/} +
    + + + + +
    +

    新建申请已提交,请等待管理员的审核

    +
  • 我们将在1-2个工作日内与您联系 +
  • +
    +
    + 知道啦 +
    +
    +
    +
    +
    + +
    +

    请在配置页面完成后续的评测脚本设置操作

    +
    + 必填项 +
    +
    +
    + + +
    +

    命令行

    +
    + + 无命令行窗口 (选中则不给学员的实践任务提供命令窗口) + 命令行练习窗口 (选中则给学员提供用于练习操作的命令行窗口) + 命令行评测窗口 (选中则给学员提供用于关卡评测的命令行窗口) + + 多个命令行窗口(选中则允许学员同时开启多个命令行窗口) + + +
    +
    + + +
    +

    公开程度

    +
    + + 对所有公开 (选中则所有已被试用授权的用户可以学习) + 对指定单位公开 (选中则下方指定单位的已被试用授权的用户可以学习) + + +
    +
    +
    +
    +
    + +
    + (搜索选中添加单位名称) + {this.state.datalisttype===true?请勿选择重复单位:""} + {/*+ 添加*/} +
    +
    + +
    +
    + { + scope_partment === undefined ? "" : scope_partment.map((item, key) => { + return ( +
  • {item} + this.deleteScopeInput(key)}>× +
  • + ) + }) + } +
    + {/*{*/} + {/*scope_partment===undefined?"":scope_partment.map((item,key)=>{*/} + {/*return(*/} + {/*
    */} + {/*this.deleteScopeInput(key)} style={{ color: 'rgba(0,0,0,.25)' }} />}*/} + {/*value={item}*/} + {/*/>*/} + {/*
    */} + + {/*)*/} + {/*})*/} + {/*}*/} +
    + + + + 请选择需要公开的单位 + +
    +
    +
    +
    + + +
    +

    发布信息

    +
    +
    + *面向学员: +
    + +
    + 实训难易度定位,不限定用户群体 +
    + 必填项 +
    +
    +
    +
  • + 复制: + + +
  • +
    + 开启时间: +
  • + + +
  • +
    +
    + {/*
    */} + {/*

    VNC图形化

    */} + {/*
  • */} + {/**/} + {/**/} + {/*
  • */} + {/*
    */} + + +
    + + 取消 +
    + + +
    +
    +
    + + ); + } +} +const NewshixunsNew = Form.create({ name: 'newshixunsnew' })(Newshixuns); +export default SnackbarHOC()(TPMIndexHOC(NewshixunsNew)); + + + + + + diff --git a/public/react/src/tpm/newshixuns/TPMNewshixuns/TPMNewshixuns.js b/public/react/src/tpm/newshixuns/TPMNewshixuns/TPMNewshixuns.js new file mode 100644 index 000000000..8b102651f --- /dev/null +++ b/public/react/src/tpm/newshixuns/TPMNewshixuns/TPMNewshixuns.js @@ -0,0 +1,19 @@ +import React, { Component } from 'react'; + +import axios from 'axios'; + +export default class TPMNewshixuns extends Component { + constructor(props) { + super(props) + this.state = { + + } + } + render() { + return ( + + ); + } +} + + diff --git a/public/react/src/tpm/newshixuns/css/Newshixuns.css b/public/react/src/tpm/newshixuns/css/Newshixuns.css new file mode 100644 index 000000000..e241dcf0d --- /dev/null +++ b/public/react/src/tpm/newshixuns/css/Newshixuns.css @@ -0,0 +1,397 @@ +/* BASICS */ + +.CodeMirror { + /* Set height, width, borders, and global font properties here */ + font-family: monospace; + height: 300px; + color: black; + direction: ltr; +} + +/* PADDING */ + +.CodeMirror-lines { + padding: 4px 0; /* Vertical padding around content */ +} +.CodeMirror pre { + padding: 0 4px; /* Horizontal padding of content */ +} + +.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { + background-color: white; /* The little square between H and V scrollbars */ +} + +/* GUTTER */ + +.CodeMirror-gutters { + border-right: 1px solid #ddd; + background-color: #f7f7f7; + white-space: nowrap; +} +.CodeMirror-linenumbers {} +.CodeMirror-linenumber { + padding: 0 3px 0 5px; + min-width: 20px; + text-align: right; + color: #999; + white-space: nowrap; +} + +.CodeMirror-guttermarker { color: black; } +.CodeMirror-guttermarker-subtle { color: #999; } + +/* CURSOR */ + +.CodeMirror-cursor { + border-left: 1px solid black; + border-right: none; + width: 0; +} +/* Shown when moving in bi-directional text */ +.CodeMirror div.CodeMirror-secondarycursor { + border-left: 1px solid silver; +} +.cm-fat-cursor .CodeMirror-cursor { + width: auto; + border: 0 !important; + background: #7e7; +} +.cm-fat-cursor div.CodeMirror-cursors { + z-index: 1; +} +.cm-fat-cursor-mark { + background-color: rgba(20, 255, 20, 0.5); + -webkit-animation: blink 1.06s steps(1) infinite; + animation: blink 1.06s steps(1) infinite; +} +.cm-animate-fat-cursor { + width: auto; + border: 0; + -webkit-animation: blink 1.06s steps(1) infinite; + animation: blink 1.06s steps(1) infinite; + background-color: #7e7; +} +@-webkit-keyframes blink { + 0% {} + 50% { background-color: transparent; } + 100% {} +} +@keyframes blink { + 0% {} + 50% { background-color: transparent; } + 100% {} +} + +/* Can style cursor different in overwrite (non-insert) mode */ +.CodeMirror-overwrite .CodeMirror-cursor {} + +.cm-tab { display: inline-block; text-decoration: inherit; } + +.CodeMirror-rulers { + position: absolute; + left: 0; right: 0; top: -50px; bottom: -20px; + overflow: hidden; +} +.CodeMirror-ruler { + border-left: 1px solid #ccc; + top: 0; bottom: 0; + position: absolute; +} + +/* DEFAULT THEME */ + +.cm-s-default .cm-header {color: blue;} +.cm-s-default .cm-quote {color: #090;} +.cm-negative {color: #d44;} +.cm-positive {color: #292;} +.cm-header, .cm-strong {font-weight: bold;} +.cm-em {font-style: italic;} +.cm-link {text-decoration: underline;} +.cm-strikethrough {text-decoration: line-through;} + +.cm-s-default .cm-keyword {color: #708;} +.cm-s-default .cm-atom {color: #219;} +.cm-s-default .cm-number {color: #164;} +.cm-s-default .cm-def {color: #00f;} +.cm-s-default .cm-variable, +.cm-s-default .cm-punctuation, +.cm-s-default .cm-property, +.cm-s-default .cm-operator {} +.cm-s-default .cm-variable-2 {color: #05a;} +.cm-s-default .cm-variable-3, .cm-s-default .cm-type {color: #085;} +.cm-s-default .cm-comment {color: #a50;} +.cm-s-default .cm-string {color: #a11;} +.cm-s-default .cm-string-2 {color: #f50;} +.cm-s-default .cm-meta {color: #555;} +.cm-s-default .cm-qualifier {color: #555;} +.cm-s-default .cm-builtin {color: #30a;} +.cm-s-default .cm-bracket {color: #997;} +.cm-s-default .cm-tag {color: #170;} +.cm-s-default .cm-attribute {color: #00c;} +.cm-s-default .cm-hr {color: #999;} +.cm-s-default .cm-link {color: #00c;} + +.cm-s-default .cm-error {color: #f00;} +.cm-invalidchar {color: #f00;} + +.CodeMirror-composing { border-bottom: 2px solid; } + +/* Default styles for common addons */ + +div.CodeMirror span.CodeMirror-matchingbracket {color: #0b0;} +div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;} +.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); } +.CodeMirror-activeline-background {background: #e8f2ff;} + +/* STOP */ + +/* The rest of this file contains styles related to the mechanics of + the editor. You probably shouldn't touch them. */ + +.CodeMirror { + position: relative; + overflow: hidden; + background: white; +} + +.CodeMirror-scroll { + overflow: scroll !important; /* Things will break if this is overridden */ + /* 30px is the magic margin used to hide the element's real scrollbars */ + /* See overflow: hidden in .CodeMirror */ + margin-bottom: -30px; margin-right: -30px; + padding-bottom: 30px; + height: 100%; + outline: none; /* Prevent dragging from highlighting the element */ + position: relative; +} +.CodeMirror-sizer { + position: relative; + border-right: 30px solid transparent; +} + +/* The fake, visible scrollbars. Used to force redraw during scrolling + before actual scrolling happens, thus preventing shaking and + flickering artifacts. */ +.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { + position: absolute; + z-index: 6; + display: none; +} +.CodeMirror-vscrollbar { + right: 0; top: 0; + overflow-x: hidden; + overflow-y: scroll; +} +.CodeMirror-hscrollbar { + bottom: 0; left: 0; + overflow-y: hidden; + overflow-x: scroll; +} +.CodeMirror-scrollbar-filler { + right: 0; bottom: 0; +} +.CodeMirror-gutter-filler { + left: 0; bottom: 0; +} + +.CodeMirror-gutters { + position: absolute; left: 0; top: 0; + min-height: 100%; + z-index: 3; +} +.CodeMirror-gutter { + white-space: normal; + height: 100%; + display: inline-block; + vertical-align: top; + margin-bottom: -30px; +} +.CodeMirror-gutter-wrapper { + position: absolute; + z-index: 4; + background: none !important; + border: none !important; +} +.CodeMirror-gutter-background { + position: absolute; + top: 0; bottom: 0; + z-index: 4; +} +.CodeMirror-gutter-elt { + position: absolute; + cursor: default; + z-index: 4; +} +.CodeMirror-gutter-wrapper ::-moz-selection { background-color: transparent } +.CodeMirror-gutter-wrapper ::selection { background-color: transparent } +.CodeMirror-gutter-wrapper ::-moz-selection { background-color: transparent } + +.CodeMirror-lines { + cursor: text; + min-height: 1px; /* prevents collapsing before first draw */ +} +.CodeMirror pre { + /* Reset some styles that the rest of the page might have set */ border-radius: 0; + border-width: 0; + background: transparent; + font-family: inherit; + font-size: inherit; + margin: 0; + white-space: pre; + word-wrap: normal; + line-height: inherit; + color: inherit; + z-index: 2; + position: relative; + overflow: visible; + -webkit-tap-highlight-color: transparent; + -webkit-font-variant-ligatures: contextual; + font-variant-ligatures: contextual; +} +.CodeMirror-wrap pre { + word-wrap: break-word; + white-space: pre-wrap; + word-break: normal; +} + +.CodeMirror-linebackground { + position: absolute; + left: 0; right: 0; top: 0; bottom: 0; + z-index: 0; +} + +.CodeMirror-linewidget { + position: relative; + z-index: 2; + padding: 0.1px; /* Force widget margins to stay inside of the container */ +} + +.CodeMirror-widget {} + +.CodeMirror-rtl pre { direction: rtl; } + +.CodeMirror-code { + outline: none; +} + +/* Force content-box sizing for the elements where we expect it */ +.CodeMirror-scroll, +.CodeMirror-sizer, +.CodeMirror-gutter, +.CodeMirror-gutters, +.CodeMirror-linenumber { + -webkit-box-sizing: content-box; + box-sizing: content-box; +} + +.CodeMirror-measure { + position: absolute; + width: 100%; + height: 0; + overflow: hidden; + visibility: hidden; +} + +.CodeMirror-cursor { + position: absolute; + pointer-events: none; +} +.CodeMirror-measure pre { position: static; } + +div.CodeMirror-cursors { + visibility: hidden; + position: relative; + z-index: 3; +} +div.CodeMirror-dragcursors { + visibility: visible; +} + +.CodeMirror-focused div.CodeMirror-cursors { + visibility: visible; +} + +.CodeMirror-selected { background: #d9d9d9; } +.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; } +.CodeMirror-crosshair { cursor: crosshair; } +.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; } +.CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; } +.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; } + +.cm-searching { + background-color: #ffa; + background-color: rgba(255, 255, 0, .4); +} + +/* Used to force a border model for a node */ +.cm-force-border { padding-right: .1px; } + +@media print { + /* Hide the cursor when printing */ + .CodeMirror div.CodeMirror-cursors { + visibility: hidden; + } +} + +/* See issue #2901 */ +.cm-tab-wrap-hack:after { content: ''; } + +/* Help users use markselection to safely style text background */ +span.CodeMirror-selectedtext { background: none; } + + + + +.radioStyle{ + display: block; + height: 30px; + } +a.white-btn.use_scope-btn:hover{ + +} +.shixunScopeInput{ + width:218px; + height:33px; + display:block; + margin-bottom:15px; +} + +#memoMD .CodeMirror { + /*width: 576px !important;*/ + margin-top: 31px !important; + height: 364px !important; +} + +#memoMD .editormd-preview { + width: 578px !important; + top: 40px !important; + height: 364px !important; +} + +.ml36{ + margin-left: 26px; +} +#person-unit a.white-btn.use_scope-btn:hover { + border: 1px solid #F06200; + color:#FFF !important; +} + +.shixunspanred{ + margin-left: 142px; + margin-top: 5px; + margin-bottom: 5px; +} + +.ml82{ + margin-left: 82px; +} + +.ant-btn-primary.active, .ant-btn-primary:active { + color: #fff; + background-color: #096dd9; + border-color: #096dd9; +} + +.ant-btn:hover, .ant-btn:focus, .ant-btn:active, .ant-btn.active{ + background-color: #4CACFF; +} \ No newline at end of file diff --git a/public/react/src/tpm/roundedRectangle.png b/public/react/src/tpm/roundedRectangle.png new file mode 100755 index 000000000..0d2d0b0dc Binary files /dev/null and b/public/react/src/tpm/roundedRectangle.png differ diff --git a/public/react/src/tpm/shixunchild/Challenges/Challenges.js b/public/react/src/tpm/shixunchild/Challenges/Challenges.js new file mode 100644 index 000000000..1470d45db --- /dev/null +++ b/public/react/src/tpm/shixunchild/Challenges/Challenges.js @@ -0,0 +1,676 @@ +import React, { Component } from 'react'; + +import { Redirect } from 'react-router'; + +import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom"; + +import PropTypes from 'prop-types'; + +import classNames from 'classnames'; + +import { getImageUrl ,markdownToHTML, configShareForCustom} from 'educoder' + +import { CircularProgress } from 'material-ui/Progress'; + +import { Modal, Spin, Tooltip ,message,Icon} from 'antd'; + +import 'antd/lib/pagination/style/index.css'; + +import '../shixunchildCss/Challenges.css' + +import axios from 'axios'; + +import AccountProfile from"../../../user/AccountProfile"; + +const $ = window.$; + +class Challenges extends Component { + constructor(props) { + super(props) + this.state = { + ChallengesDataList: undefined, + operate: true, + startbtns: false, + sumid: "", + sumidtype: false, + startshixunCombattype:false, + shixunsreplace:false, + shixunsmessage:"", + hidestartshixunsreplacevalue:"", + operationstrue:false, + isSpin:false, + } + } + + ChallengesList = () => { + let id = this.props.match.params.shixunId; + let ChallengesURL = `/shixuns/` + id + `/challenges.json`; + + axios.get(ChallengesURL).then((response) => { + if (response.status === 200) { + if (response.data.status === 403||response.data.status === 401||response.data.status === 500) { + + }else{ + configShareForCustom(this.props.shixunsDetails.name, response.data.description) + this.setState({ + ChallengesDataList: response.data, + sumidtype: false, + }); + } + } + }).catch((error) => { + console.log(error) + }); + } + + componentDidMount() { + setTimeout(this.ChallengesList(), 1000); + } + + updatamakedown = (id) => { + setTimeout(() => { + var shixunDescr = window.editormd.markdownToHTML(id, { + htmlDecode: "style,script,iframe", + taskList: true, + tex: true, + flowChart: true, + sequenceDiagram: true + }); + $("#" + id + " p:first").addClass("ReactMarkdown"); + }, 200) + } + + // 关卡的上移下移操作 + operations = (sumid, type) => { + this.setState({ + operationstrue:true + }) + let { ChallengesDataList } = this.state; + let operationUrl; + if (type === "up") { + operationUrl = "/shixuns/" + ChallengesDataList.shixun_identifier + "/challenges/" + sumid + "/index_up.json"; + } else if (type === "down") { + operationUrl = "/shixuns/" + ChallengesDataList.shixun_identifier + "/challenges/" + sumid + "/index_down.json"; + } + if (this.state.operate) { + + this.setState({ + operate: false + }); + axios.get(operationUrl).then((response) => { + if (response.status === 200) { + this.setState({ + operate: true, + operationstrue:false + }); + this.ChallengesList(); + + } + }).catch((error) => { + console.log(error); + this.setState({ + operate: true, + operationstrue:false + }); + this.ChallengesList() + }) + } + } + delOperations = (sumid) => { + this.setState({ + sumid: sumid, + sumidtype: true + }) + } + + clonedelOperationss = () => { + this.setState({ + sumidtype: false + }) + } + delOperationss = () => { + let { ChallengesDataList, sumid } = this.state; + let operationUrl = "/shixuns/" + ChallengesDataList.shixun_identifier + "/challenges/" + sumid+".json" + + if (this.state.operate) { + this.setState({ + operate: false, + sumidtype: false + }) + axios.delete(operationUrl, { + withCredentials: true + }).then((response) => { + if (response.status === 200) { + this.setState({ + operate: true, + sumidtype: false + }); + this.ChallengesList(); + } + this.ChallengesList() + }).catch((error) => { + console.log(error); + this.setState({ + operate: true, + sumidtype: false + }); + this.ChallengesList() + }) + } + } + + startgameid=(id)=>{ + + let url = "/shixuns/" + id + "/shixun_exec.json"; + axios.get(url).then((response) => { + + if (response.data.status === -2) { + this.setState({ + shixunsreplace:true, + hidestartshixunsreplacevalue:response.data.message+".json" + }) + } else if (response.data.status === -1) { + console.log(response) + }else if(response.data.status===-3){ + this.setState({ + shixunsmessage:response.data.message, + startshixunCombattype:true, + }) + } else { + window.location.href = "/tasks/" + response.data.game_identifier; + // window.location.href = path + // let path="/tasks/"+response.data.game_identifier; + // this.props.history.push(path); + } + }).catch((error) => { + + }); + + + } + + hidestartshixunsreplace=(url)=>{ + this.setState({ + isSpin:true, + }) + axios.get(url).then((response) => { + if(response.status===200){ + // let path="/shixuns/"+response.data.shixun_identifier+"/challenges"; + // this.props.history.push(path); + message.success('重置成功,正在进入实训!'); + this.startgameid(response.data.shixun_identifier); + this.setState({ + shixunsreplace:false, + isSpin:false, + }) + + // message.success('重置成功,正在进入实训!'); + // this.startshixunCombat(); + }} + ).catch((error) => { + + }); + + } + + //编辑实训题目选择题 + EditTraining=(type, ids, path)=>{ + let { ChallengesDataList } = this.state; + window.location.href = "/shixuns/" + ChallengesDataList.shixun_identifier + "/challenges/" + ids + path; + } + + //开始实战按钮 + startshixunCombat = (type, ids, id) => { + + if(this.props.checkIfLogin()===false){ + this.props.showLoginDialog() + return + } + + if(this.props.checkIfProfileCompleted()===false){ + this.setState({ + AccountProfiletype:true + }) + return + } + + // if(this.props.checkIfProfessionalCertification()===false){ + // this.setState({ + // AccountProfiletype:true + // }) + // return + // } + + + let { ChallengesDataList } = this.state; + // let id = this.props.match.params.shixunId; + this.setState({ + startbtns: true + }) + let url = "/shixuns/" + ChallengesDataList.shixun_identifier + "/shixun_exec.json?challenge_id="+id; + axios.get(url).then((response) => { + + if (response.data.status === -2) { + this.setState({ + startbtns:false, + shixunsreplace:true, + hidestartshixunsreplacevalue:response.data.message+".json" + }) + } else if (response.data.status === -1) { + this.setState({ + startbtns: false + }) + console.log(response) + }else if(response.data.status===-3){ + this.setState({ + shixunsmessage:response.data.message, + startshixunCombattype:true, + startbtns:false + }) + } else { + window.location.href = "/tasks/" + response.data.game_identifier; + // window.location.href = path + // let path="/tasks/"+response.data.game_identifier; + // this.props.history.push(path); + } + }).catch((error) => { + + }); + + + // if(path===null){ + // }else{ + // if (type > 4 || type === false) { + // window.location.href = path; + // } else { + // + // } + // } + + + } + hidestartshixunCombattype=()=>{ + this.setState({ + startshixunCombattype:false + }) + } + + hideAccountProfile=()=>{ + this.setState({ + AccountProfiletype:false + }) + } + + render() { + let { ChallengesDataList, startbtns, sumidtype ,startshixunCombattype,shixunsreplace,shixunsmessage,hidestartshixunsreplacevalue,operationstrue,AccountProfiletype} = this.state; + let { loadingContent } = this.props; + if (ChallengesDataList != undefined) { + this.updatamakedown("ReactMarkdown") + } + let id = this.props.match.params.shixunId; + const antIcon = ; + return ( + + {AccountProfiletype===true?this.hideAccountProfile()} + {...this.props} + {...this.state} + />:""} + + {loadingContent ? + : + +
    +

    + {this.props.identity < 5 && ChallengesDataList&&ChallengesDataList.shixun_status=== 0 ? + + + + 实践任务 + + + : "" + } + {this.props.identity < 5 && ChallengesDataList&&ChallengesDataList.shixun_status=== 0 ? + + + + 选择题任务 + + : "" + } +

    +

    + 简介 + + + + + + +

    + +
    +

    + {ChallengesDataList === undefined ? "" :ChallengesDataList&&ChallengesDataList.description===null?"": +

    + } +

    + + {/* + + */} +
    + +

    + 全部任务 + {this.props.identity < 5 && ChallengesDataList&&ChallengesDataList.shixun_status=== 0 ? + + + + 实践任务 + + + : "" + } + {this.props.identity < 5 && ChallengesDataList&&ChallengesDataList.shixun_status=== 0 ? + + + + 选择题任务 + + : "" + } +

    + +
    + {ChallengesDataList === undefined ?
    +
    + +

    暂时还没有相关数据哦!

    +
    +
    : ChallengesDataList.challenge_list === undefined ? +
    +
    + +

    暂时还没有相关数据哦!

    +
    +
    + : ChallengesDataList.challenge_list.length === 0 ? +
    +
    + +

    暂时还没有相关数据哦!

    +
    +
    + : ChallengesDataList.challenge_list.map((item, key) => { + + let newstatus = 2; + if(ChallengesDataList.challenge_list[key - 1]!=undefined){ + newstatus=ChallengesDataList.challenge_list[key - 1].status; + } + return ( +
    + +
    + + {item.st === 0 ? + + + + : + + + + } + + 第{key+1}关 + + {this.props.identity<5? + item.st === 1 ? + this.EditTraining(this.props.identity, item.challenge_id, "/editquestion")} + className="font-16 color05101a">{item.name} + : + this.EditTraining(this.props.identity, item.challenge_id, "/editcheckpoint")} + className="font-16 color05101a">{item.name}: this.startshixunCombat(this.props.identity, item.challenge_id, "/editcheckpoint")} + className="font-16 color05101a">{item.name} + } + + + + + + + + {item.delete_url != undefined && + + this.delOperations(item.challenge_id)} + style={{ display:this.props.user.admin===true?"block":this.props.identity < 5 && ChallengesDataList.shixun_status === 0 ? "block" : 'none' }} + className="fl ring-op-green mr25"> + + + + } + + + {item.up_url != undefined && + + this.operations(item.challenge_id, "up")} + style={{ display:this.props.user.admin===true?"block":this.props.identity < 5 && ChallengesDataList.shixun_status === 0 ? "block" : 'none' }} + className="fl ring-op-green mr25"> + + + + } + {item.down_url != undefined && + + this.operations(item.challenge_id, "down")} + style={{ display: this.props.user.admin===true?"block":this.props.identity < 5 && ChallengesDataList.shixun_status=== 0 ? "block" : 'none' }} + className="fl ring-op-green mr25"> + + + + + } + + { + item.st === 1 ? + + + + + + : + + + + + + + } + + +
    +
    + {item.passed_count} 人完成挑战 + {item.playing_count} 人正在挑战 + 完成挑战可获得经验值 {item.score} + + + {/*判断比较复杂 有排第一不能是灰色按钮*/} + {item.status === 2 ? + this.startshixunCombat(false,undefined, item.challenge_id)} + // onClick={() => this.startshixunCombat(false)} + title={"查看挑战关卡"} + >已完成 : "" + } + + { + ChallengesDataList.allow_skip === true && item.status === 1? + this.startshixunCombat(false,undefined, item.challenge_id)} + // onClick={() => this.startshixunCombat(false)} + >直接挑战 : "" + } + + + { + ChallengesDataList.allow_skip === false ? item.status === 1? + + this.startshixunCombat(false,undefined, item.challenge_id)} + style={{marginTop: '-2px'}}>直接挑战 + :"":"" + + } + + + + { + item.status === 0 ? + + this.startshixunCombat(false,undefined, item.challenge_id):""} + style={{marginTop: '-2px'}}>直接挑战 + :"" + } + + + +
    +
    + ) + })} +
    + + + + + + +
    +

    目前该实训项目尚在内测中,将于{shixunsmessage}之后开放,谢谢!

    +
    +
    + {/*取消*/} + 知道了啦 +
    + {/*

    */} + {/*知道了*/} + {/*

    */} +
    + + + +
    +

    实训已经更新了,正在为您重置!

    +
    + +
    +
    +
    + } +
    + + ) + } +} + +export default Challenges; + // { + // ChallengesDataList.allow_skip === false ? item.status === 1 && newstatus === 2 ? + // + // this.startshixunCombat(false,undefined, item.challenge_id)} + // style={{marginTop: '-2px'}}>直接挑战 + // + // + // : item.status === 1 && newstatus === 1 ? + // + // this.startshixunCombat(false,undefined, item.challenge_id)} + // style={{marginTop: '-2px'}}>直接挑战 + // : "" : "" + // + // } \ No newline at end of file diff --git a/public/react/src/tpm/shixunchild/Collaborators/Collaborators.css b/public/react/src/tpm/shixunchild/Collaborators/Collaborators.css new file mode 100644 index 000000000..31917086f --- /dev/null +++ b/public/react/src/tpm/shixunchild/Collaborators/Collaborators.css @@ -0,0 +1,9 @@ +.height40 { + height: 30px; + line-height: 30px; +} + +.line27{ + line-height: 27px; + vertical-align: 1px; +} \ No newline at end of file diff --git a/public/react/src/tpm/shixunchild/Collaborators/Collaborators.js b/public/react/src/tpm/shixunchild/Collaborators/Collaborators.js new file mode 100644 index 000000000..d67599bf1 --- /dev/null +++ b/public/react/src/tpm/shixunchild/Collaborators/Collaborators.js @@ -0,0 +1,658 @@ +import React, { Component } from 'react'; + +import { Redirect } from 'react-router'; + +import {Modal, Button, Radio, Input, Checkbox,message,Spin, Icon} from 'antd'; + +import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom"; + +import PropTypes from 'prop-types'; + +import classNames from 'classnames'; + +import { CircularProgress } from 'material-ui/Progress'; + +import { getImageUrl, toPath } from 'educoder' + +import axios from 'axios'; + +import NoneData from "../../../courses/coursesPublic/NoneData"; + +import './Collaborators.css'; + + +const $ = window.$; + +const RadioGroup = Radio.Group; + +const Search = Input.Search; + +class Collaborators extends Component { + constructor(props) { + super(props) + this.state = { + collaboratorList: [], + Collaboratorsvisible: false, + Collaboratorsvisibleadmin: false, + value: 1, + page: 1, + Searchadmin: undefined, + allChangechecked: false, + Collaboratorslist: [], + Collaboratorslisttype: false, + collaborators_deletetype: false, + collaborators_deletevalue: null, + onSearchcalue:"", + collaboratorListsum:10, + collaboratorListsumtype:true, + user_name:undefined, + school_name:undefined, + spinnings:false, + useristrue:false + } + } + componentDidMount() { + let id=this.props.match.params.shixunId; + + let collaborators=`/shixuns/`+id+`/collaborators.json`; + axios.get(collaborators).then((response)=> { + if(response.status===200){ + if (response.data.status === 403||response.data.status === 401||response.data.status === 500) { + + }else{ + this.setState({ + collaboratorList: response.data + }); + } + + } + }).catch((error)=>{ + console.log(error) + }); + } + + updatacomponentDiddata = () => { + let id = this.props.match.params.shixunId; + + let collaborators = `/shixuns/` + id + `/collaborators.json`; + axios.get(collaborators).then((response) => { + if (response.status === 200) { + if (response.data.status === 403||response.data.status === 401||response.data.status === 500) { + + }else{ + this.setState({ + collaboratorList: response.data + }); + } + } + }).catch((error) => { + console.log(error) + }); + } + CollaboratorsshowModal = (type) => { + + if (type === "cooperation") { + this.setState({ + Collaboratorsvisibleadmin: false, + Collaboratorslist:[], + Searchadmin:[] + }); + } else if (type === "admin") { + this.setState({ + Collaboratorsvisible: false, + Collaboratorslist:[], + Searchadmin:[] + }); + } else if (type === "collaborators_deletetype") { + this.setState({ + collaborators_deletetype: false, + }); + } + } + + showCollaboratorsvisible = (type) => { + + this.setState({ + Collaboratorslist: [], + Searchadmin:undefined, + onSearchcalue:"" + }) + let admintype = this.props.identity; + if (admintype>4) { + this.props.showSnackbar("您没有权限"); + return + } + if (type === "cooperation") { + this.setState({ + Collaboratorsvisibleadmin: true, + }); + } else if ("admin") { + let id = this.props.match.params.shixunId; + let url = "/shixuns/" + id + "/change_manager.json"; + axios.get(url).then((response) => { + if (response.status === 200) { + // this.setState({ + // Collaboratorsvisible: true + // }) + if (response.data.status === 403||response.data.status === 401||response.data.status === 500) { + + }else{ + this.setState({ + Collaboratorsvisible: true, + Collaboratorslist: response.data + }) + } + } + }).catch((error) => { + console.log(error) + }); + + } + } + + onChange = (e) => { + this.setState({ + value: e.target.value, + }); + } + onSearchadmins=(e)=>{ + this.setState({ + onSearchcalue:e.target.value + }) + } + onSearchadmin = (value) => { + + let {collaboratorList,user_name,school_name} = this.state; + this.setState({ + // Searchadmin: undefined, + spinnings:true, + }) + // if (value === "") { + // this.setState({ + // Searchadmin: [], + // collaboratorList: collaboratorList + // }) + // } else { + // + // } + let id = this.props.match.params.shixunId; + let url = "/shixuns/" + id + "/add_collaborators.json"; + axios.get(url,{params:{ + user_name:user_name , + school_name:school_name, + }}).then((response) => { + if (response.data.status === 403||response.data.status === 401||response.data.status === 500) { + this.setState({ + spinnings:false + }) + }else{ + let newlist = response.data.users; + for (var i = 0; i < newlist.length; i++) { + newlist[i].checked = false + } + this.setState({ + Searchadmin: newlist, + collaboratorList: collaboratorList, + spinnings:false + }) + } + + }).catch((error) => { + console.log(error) + }); + } + + selectChangenickname = (e, key) => { + + let {Searchadmin} = this.state; + let newlist = Searchadmin; + for (var i = 0; i < newlist.length; i++) { + newlist[key].checked = e.target.checked + } + + let arrlist = []; + let alltype = false; + for (var z = 0; z < newlist.length; z++) { + if (newlist[z].checked === true) { + arrlist.push(newlist[z]) + } + } + + if (Searchadmin.length === arrlist.length) { + alltype = true + } else { + alltype = false + } + + if(newlist.length===0){ + this.setState({ + Searchadmin: newlist, + allChangechecked: alltype, + }) + }else{ + this.setState({ + Searchadmin: newlist, + allChangechecked: alltype, + useristrue:false + }) + } + + + } + allChange = (e) => { + + let {Searchadmin} = this.state; + let newlist = Searchadmin; + for (var i = 0; i < newlist.length; i++) { + newlist[i].checked = e.target.checked + } + this.setState({ + Searchadmin: newlist, + allChangechecked: e.target.checked + }) + } + submit_add_collaborators_form = () => { + + let id = this.props.match.params.shixunId; + let {Searchadmin,collaboratorList} = this.state; + let newlist = Searchadmin; + let user_ids = [] + if (newlist.length === 0) { + this.setState({ + Collaboratorslisttype: true + }) + return + } + for (var i = 0; i < newlist.length; i++) { + if (newlist[i].checked === true) { + user_ids.push(newlist[i].user_id) + } + } + + for(var i=0; i { + this.updatacomponentDiddata(); + this.props.showSnackbar(response.data.message); + this.setState({ + Collaboratorsvisibleadmin: false, + Collaboratorslist:[], + Searchadmin:[] + }) + }).catch((error) => { + console.log(error) + }); + } + addadminredio = (e) => { + this.setState({ + addadminrediovalue: e + }) + + } + submit_addadminredio = () => { + + let {addadminrediovalue} = this.state; + + let id = this.props.match.params.shixunId; + + let url = "/shixuns/" + id + "/change_manager.json"; + if(addadminrediovalue===undefined){ + this.setState({ + Collaboratorsvisible: false, + Collaboratorslist:[], + Searchadmin:[] + }); + this.props.showSnackbar("所选人员为空,没有更换成功"); + this.CollaboratorsshowModal("admin") + return + } + + + axios.post(url, { + user_id: addadminrediovalue + }).then((response) => { + this.setState({ + Collaboratorsvisible: false, + Collaboratorslist:[], + Searchadmin:[] + }); + this.updatacomponentDiddata(); + this.props.showSnackbar(response.data.message); + }).catch((error) => { + console.log(error) + }); + } + + collaborators_delete = (value) => { + this.setState({ + collaborators_deletetype: true, + collaborators_deletevalue: value + }) + + } + collaborators_deletes = () => { + let {collaborators_deletevalue} = this.state; + if (collaborators_deletevalue === null) { + return + } + let id = this.props.match.params.shixunId; + let url = "/shixuns/" + id + "/collaborators_delete.json?user_id=" + collaborators_deletevalue; + axios.delete(url).then((response) => { + if (this.props.current_user.user_id == collaborators_deletevalue) { + this.props.history.push('/shixuns') + return; + } + this.props.showSnackbar(response.data.message); + this.updatacomponentDiddata(); + this.setState({ + collaborators_deletetype: false + }) + }).catch((error) => { + console.log(error) + }); + } + + loadMore=()=>{ + let {collaboratorList}=this.state; + this.setState({ + collaboratorListsum:collaboratorList.length, + collaboratorListsumtype:false + }) + } + + + contentViewScrolledit=(e)=>{ + + //滑动到底判断 + let newscrollTop=parseInt(e.currentTarget.scrollTop); + let allclientHeight=e.currentTarget.clientHeight+newscrollTop; + + if(e.currentTarget.scrollHeight-allclientHeight===0||e.currentTarget.scrollHeight-allclientHeight===1||e.currentTarget.scrollHeight-allclientHeight===-1){ + let {page,collaboratorList,user_name,school_name,Searchadmin} = this.state; + let newpage=page+1; + let newSearchadmin=Searchadmin + let id = this.props.match.params.shixunId; + let url = "/shixuns/" + id + "/add_collaborators.json"; + axios.get(url,{params:{ + user_name:user_name , + school_name:school_name, + page:newpage + }}).then((response) => { + if (response.data.status === 403||response.data.status === 401||response.data.status === 500) { + + }else{ + let newlist = response.data.users; + for (var i = 0; i < newlist.length; i++) { + newlist[i].checked = false + newSearchadmin.push(newlist[i]) + } + + this.setState({ + Searchadmin: newSearchadmin, + collaboratorList: collaboratorList, + page:newpage + }) + } + + }).catch((error) => { + console.log(error) + }); + + } + + } + + render() { + let { + collaboratorList, + Collaboratorsvisible, + Collaboratorsvisibleadmin, + Searchadmin, + allChangechecked, + Collaboratorslist, + Collaboratorslisttype, + collaborators_deletetype, + onSearchcalue, + collaboratorListsum, + collaboratorListsumtype, + user_name, + school_name, + useristrue + } = this.state; + let {loadingContent} = this.props; + const radioStyle = { + display: 'block', + height: '30px', + lineHeight: '30px', + }; + + const antIcon = ; + + console.log(Searchadmin) + return ( + +

    + this.showCollaboratorsvisible("cooperation")} + className="edu-default-btn edu-greenback-btn fr mr20 height40" + data-remote="true"> + + 添加合作者 + + this.showCollaboratorsvisible("admin")} + style={{display:this.props.identity===1?"block":"none"}} + data-remote="true" + className="edu-default-btn edu-greenback-btn fr mr20 height40">更换管理员 +

    + + + +
    + 选择的成员将会成为新的管理员
    您将不再拥有管理员的权限,但您仍是合作团队的一员 +
    + + +
    +
      +
    • + + + { + Collaboratorslist.length === 0 ? "" : Collaboratorslist.map((item, key) => { + return ( + this.addadminredio(item.user_id)}>{item.name} + ) + }) + } + + +
    • +
    +
    + + + +
    + + {Collaboratorsvisibleadmin===true? + {/* this.onSearchadmin(value)}*/} + {/*onInput={this.onSearchadmins}*/} + {/*style={{width: '100%'}}*/} + {/*/>*/} + 姓名或手机号: + + {this.setState({user_name: e.target.value})}} + style={{ width: '215px'}} + > + 单位: + {this.setState({school_name: e.target.value})}} + style={{ width: '215px'}} + > + + + this.onSearchadmin()} + style={{ height: '30px', lineHeight: '30px', width: '70px'}} + >搜索 +

    + 姓名 + 职业 + 单位 +

    +
    + +
    +
      + {Searchadmin === undefined ?
    • + 请试试搜索一下 +
    • :Searchadmin.length === 0 ?: Searchadmin.map((item, key) => { + return ( +
    • + this.selectChangenickname(e, key)} + id={item.user_id}> + {item.nickname} + {item.identify} + {item.school_name} +
    • + ) + }) + + } +
    +
    +
    +
    +
    + + + 全选 +
    + 请至少选择一个用户 +
    +
    + + +
    + {useristrue===true?请先选择用户:""} + +
    :""} + +
    + { + collaboratorList===undefined?"":collaboratorList.map((item,key)=>{ + if(key + + 用户头像 +
    +

    + {item.user.name} + + {item.user.shixun_manager === true ? "(管理员)" : ""} +

    + +

    {item.user.identity}{item.user.school_name}

    + +

    + 发布  {item.user.user_shixuns_count} + {/*粉丝  */} + {/*{item.user.fans_count}*/} + {/**/} +

    + + {/*

    {item.user.brief_introduction}

    */} + + +
    + + {item.user.shixun_manager === true ? "" : this.collaborators_delete(item.user.user_id)}>删除} + {/*取消关注*/} +
    + + ) + } + }) + } + +
    +
    确定要删除吗?
    +
    + + +
    + + +
    10&&collaboratorListsumtype===true?"":"none"} + style={{textAlign:'center',borderTop:'1px solid #eee'}}> + 加载更多 +
    + +
    + + ); + } +} + +export default Collaborators; diff --git a/public/react/src/tpm/shixunchild/Propaedeutics/Propaedeu_tics.js b/public/react/src/tpm/shixunchild/Propaedeutics/Propaedeu_tics.js new file mode 100644 index 000000000..f40e9fa63 --- /dev/null +++ b/public/react/src/tpm/shixunchild/Propaedeutics/Propaedeu_tics.js @@ -0,0 +1,114 @@ +import React, { Component } from 'react'; + +import { Redirect } from 'react-router'; + +import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom"; + +import PropTypes from 'prop-types'; + +import classNames from 'classnames'; + +import { getImageUrl, toPath } from 'educoder'; + +import { Tooltip } from 'antd'; + +import axios from 'axios'; + +import { CircularProgress } from 'material-ui/Progress'; + +const $ = window.$; + +class Propaedeutics extends Component { + constructor(props) { + super(props) + this.state={ + PropaedeuticsListcontent:undefined, + shixunId:undefined + } + } + + componentDidMount() { + let id = this.props.match.params.shixunId; + this.setState({ + shixunId:id + }) + let url="/shixuns/"+id+"/propaedeutics.json"; + axios.get(url).then((response) => { + + if (response.data.status === 403||response.data.status === 401||response.data.status === 500) { + + }else{ + if(response.data.content!=null){ + this.setState({ + PropaedeuticsListcontent:response.data.content + }) + }else{ + this.setState({ + PropaedeuticsListcontent:"" + }) + } + } + }).catch((error) => { + console.log(error) + }); + + } + + updatamakedown=(id)=>{ + setTimeout(()=>{ + var shixunDescr = window.editormd.markdownToHTML(id, { + htmlDecode: "style,script,iframe", + taskList: true, + tex: true, + flowChart: true, + sequenceDiagram: true + }); + $("#"+id+" p:first").addClass("ReactMarkdown"); + $('#collaborators_list_info').show() + }, 200) + } + render() { + let {loadingContent} = this.props; + let {PropaedeuticsListcontent,shixunId}=this.state + + if(PropaedeuticsListcontent!=undefined){ + this.updatamakedown("ReactMarkdown") + } + + return ( + +

    + + + + +

    + { + loadingContent ? + : +
    + {PropaedeuticsListcontent===undefined?"": +

    + + {PropaedeuticsListcontent === undefined ||PropaedeuticsListcontent === ""? +

    +
    +
    + +

    暂时还没有相关数据哦!

    +
    +
    +
    + :} + +

    + } +
    + } +
    + ); + } +} + +export default Propaedeutics; diff --git a/public/react/src/tpm/shixunchild/Ranking_list/Ranking_list.js b/public/react/src/tpm/shixunchild/Ranking_list/Ranking_list.js new file mode 100644 index 000000000..0e5d0498b --- /dev/null +++ b/public/react/src/tpm/shixunchild/Ranking_list/Ranking_list.js @@ -0,0 +1,145 @@ +import React, { Component } from 'react'; + +import { Redirect } from 'react-router'; + +import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom"; + +import PropTypes from 'prop-types'; + +import classNames from 'classnames'; + +import { getImageUrl, toPath } from 'educoder'; + +import { CircularProgress } from 'material-ui/Progress'; + +import axios from 'axios'; + +const $ = window.$; + +class Ranking_list extends Component { + constructor(props) { + super(props) + this.state = { + Ranking_listData:[] + } + } + + Ranking_listList = (id) => { + let Ranking_listURL = `/shixuns/` + id + `/ranking_list.json`; + axios.get(Ranking_listURL).then((response) => { + if (response.status === 200) { + if (response.data.status === 403||response.data.status === 401||response.data.status === 500) { + + }else{ + this.setState({ + Ranking_listData: response.data + }); + } + } + + }).catch((error) => { + console.log(error) + }); + } + + componentDidMount() { + let id = this.props.match.params.shixunId; + setTimeout(this.Ranking_listList(id), 1000); + } + checkAddZone=(num)=>{ + return num<10 ? '0' + num.toString() : num + } + dateTimeFormatter=(t)=> { + if (!t) return '' + t = new Date(t).getTime() + t = new Date(t) + var year = t.getFullYear() + var month = (t.getMonth() + 1) + month = this.checkAddZone(month) + + var date = t.getDate() + date = this.checkAddZone(date) + + var hour = t.getHours() + hour = this.checkAddZone(hour) + + var min = t.getMinutes() + min = this.checkAddZone(min) + + return year + '-' + month + '-' + date + ' ' + hour + ':' + min + } + + formatSeconds=(value)=> { + var theTime = parseInt(value);// 秒 + var theTime1 = 0;// 分 + var theTime2 = 0;// 小时 + if(theTime > 60) { + theTime1 = parseInt(theTime/60); + theTime = parseInt(theTime%60); + if(theTime1 > 60) { + theTime2 = parseInt(theTime1/60); + theTime1 = parseInt(theTime1%60); + } + } + var result = ""+parseInt(theTime)+"秒"; + if(theTime1 > 0) { + result = ""+parseInt(theTime1)+"分"+result; + } + if(theTime2 > 0) { + result = ""+parseInt(theTime2)+"小时"+result; + } + return result; + } + + render() { + let { Ranking_listData } = this.state; + let { loadingContent } = this.props; + + // console.log(Ranking_listData) + return ( + + { loadingContent ? + : + +
    + {Ranking_listData===undefined||Ranking_listData.length===0? +
    + +

    我们在等你,不轻言放弃

    +
    + :Ranking_listData.map((item,key)=>{ + var keys=key+1 + return( +
    +
  • + + 2?"block":"none"}} + >{key+1} + + 头像 + + + {item.users.name} +
  • + +
  • {this.dateTimeFormatter(item.time)}通关
  • + {/*
  • */} + {/*/!*{item.accuracy} %准确率*!/*/} + {/*
  • */} +
  • {this.formatSeconds(item.use_time)}
  • +
  • +{item.gold}金币
  • +
    + ) + })} +
    + } +
    + + ); + } +} + +export default Ranking_list; diff --git a/public/react/src/tpm/shixunchild/Repository/Repository.js b/public/react/src/tpm/shixunchild/Repository/Repository.js new file mode 100644 index 000000000..c477422e8 --- /dev/null +++ b/public/react/src/tpm/shixunchild/Repository/Repository.js @@ -0,0 +1,266 @@ +import React, { Component } from 'react'; + +import { Redirect } from 'react-router'; + +import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom"; + +import PropTypes from 'prop-types'; + +import classNames from 'classnames'; + +import axios from 'axios'; + +import { trace, trace_collapse ,getImageUrl, toPath} from "educoder"; + +import RepositoryDirectories from './RepositoryDirectories' + +import { ActionBtn , NoneData } from 'educoder' +import RepositoryCombinePath from './RepositoryCombinePath' +const $ = window.$; + +// 点击按钮复制功能 +function jsCopy(){ + var e = document.getElementById("copy_rep_content"); + e.select(); + document.execCommand("Copy"); +} +/** + 提交记录 + 使用指南 + */ +class Repository extends Component { + constructor(props) { + super(props); + this.state={ + + } + } + componentDidMount() { + } + onRepoFileClick = (item) => { + + this.props.fetchRepo(item) + + } + render() { + let { match, author, git_url, lastest_commit,repositoryLoading, commits,trees,pathArray , TPMRightSectionData } = this.props; + + if (!author) { + author = {} + } + let userauthority=false; + if(this.props.author!=undefined){ + userauthority=this.props.author.login===""||this.props.author.user_id===""||this.props.author.login===null||this.props.author.user_id===null; + } + return ( + + {/* jfinalshop/WebRoot */} + {/*
    + + + 分支 1 + + Git使用指南 +
    */} + + { repositoryLoading ?
    : + +
    +
    +
    +
    +
    + {/*
    + +
    + +
    + + + + */} + + Git使用指南 + { + this.props.current_user && (this.props.current_user.admin ==true || (TPMRightSectionData && TPMRightSectionData.creator && TPMRightSectionData.creator.login == this.props.current_user.login)) ? + !this.props.secret_repository_tab && + +添加文件 + :"" + } + + + +
    + + + { + jsCopy() + }} data-tip-down="点击复制版本库地址" + className="fl ml5"> + + + + + {/* Git使用指南 */} + + + { $('#repository_url_tip').css('display') === 'none' + ? $('#repository_url_tip').show() + : $('#repository_url_tip').hide() }} + className="fl ml6 mt1"> + + + + +
    +
    + + {this.props.secret_repository_tab && + + } + +
    +
    + + + {/* 用户、最近提交时间 */} + { + trees === undefined || trees === null ||trees.length===0? : +
    + {commits===undefined?"":commits===null||commits.length===0?"":
    + {author.name} + {commits[0].author.name} + 提交于 + + {commits===undefined?"":commits[0].time} + :{commits===undefined?"":commits[0].title} + + + + 提交记录 + +
    } + +
    +
    + {/* 当前目录位置 */} + + +
    + { trees === undefined ?"": trees === null || trees.length===0?"":trees.map((item, index) => { + return ( +
  • + + + this.onRepoFileClick(item)}> +  {item.name} + + +
  • + ) + })} +
    +
    +
    +
    + } + + {/* 当前分支的文件 */} + +
    +
    + } +
    + + ); + } +} +/* + 提交记录 +
    + { RepositoryList===undefined?"":RepositoryList.commits.map((item,key)=>{ + // {"email":"李暾","title":"2\n","id":"80cb6fc55a14bdd64a9c99913f416966238ed3de","time":"49年前"} + return( +
    +
    {item.email}
    +
    {item.title}
    +
    {item.id}
    +
    {item.time}
    +
    + ) + }) } +
    + + + +
  • + + + 1-1.py + +
  • + + + +*/ + +export default Repository; diff --git a/public/react/src/tpm/shixunchild/Repository/RepositoryAddFile.js b/public/react/src/tpm/shixunchild/Repository/RepositoryAddFile.js new file mode 100644 index 000000000..9ca535bb4 --- /dev/null +++ b/public/react/src/tpm/shixunchild/Repository/RepositoryAddFile.js @@ -0,0 +1,198 @@ +import React, { Component } from 'react'; +import { ActionBtn } from 'educoder' + +import { Form , Modal , Input , Breadcrumb , Button } from 'antd' + +import { Link } from 'react-router-dom' + +import axios from 'axios' + +/** + ---------------------------- START + */ +function getModeByMirrorName(mirror_name) { + let mode = 'javascript' + if (mirror_name && mirror_name.length) { + for (let i = 0; i < mirror_name.length; i++) { + let modeVal = mirrorNameModeMap[mirror_name[i]]; + if (modeVal) { + mode = modeVal; + break; + } + } + } + return mode; +} +const _extraKeys = {"Alt-/": "autocomplete"}; +function createCMOptions(mirror_name) { + let mode = getModeByMirrorName(mirror_name) + + let cmOptions = { + lineNumbers: true, + mode: mode, + theme: "railscasts", + indentUnit:4, + matchBrackets: true, + autoRefresh: true, + smartIndent: true,//智能换行 + extraKeys: _extraKeys, + autofocus: true, + styleActiveLine: true, + lint: true, + gutters: ["CodeMirror-linenumbers", "breakpoints", "CodeMirror-lint-markers"] + }; + return cmOptions; +} + +const mirrorNameModeMap = { + 'JFinal': 'text/x-java', + 'Java': 'text/x-java', + 'Kotlin': 'text/x-kotlin', + 'C/C++' : 'text/x-c++src', + 'MachineLearning': { + name: "python", + version: 3, + singleLineStringErrors: false + }, + 'Python2.7': { + name: "python", + version: 3, + singleLineStringErrors: false + }, + 'Python3.6': { + name: "python", + version: 3, + singleLineStringErrors: false + }, +} +/** + ---------------------------- END +*/ + +class RepositoryAddFile extends Component { + constructor(props) { + super(props); + } + + componentDidMount(){ + let cmOptions = createCMOptions(this.props.mirror_name) + const extend_editor = window.CodeMirror.fromTextArea(window.$('#codemirror-file-edit')[0] + , cmOptions); + + // tpi没setValue也可以 + extend_editor.setValue('') + extend_editor.refresh(); + + // 拖拽也需要用 : window.editor_CodeMirror.refresh() + window.editor_tempCodeMirror = extend_editor; + this.extend_editor = extend_editor; + } + + checkPath= (rule, value, callback) =>{ + if(!value){ + callback('文件名不能为空'); + }else if (value == "/" || value.indexOf('.') == -1 ) { + callback('请输入正确的文件路径,如:src/HelloWorld.java'); + }else{ + callback(); + } + } + + handleSubmit = () =>{ + this.props.form.validateFieldsAndScroll((err, values) => { + if(!err){ + let shixunId = this.props.match.params.shixunId; + let url = `/shixuns/${shixunId}/add_file.json` + axios.post(url,{ + path:values.path, + message:values.message, + content:this.extend_editor.getValue() + }).then((result)=>{ + if(result){ + this.props.history.push(`${result.data.url}`) + } + }).catch((error)=>{ + console.log(error); + }) + } + }) + } + render(){ + const {getFieldDecorator} = this.props.form; + let { shixunId } = this.props.match.params; + return( +
    + +

    + + 实训项目 + 版本库 + 添加新文件 + +

    +
    +
    + + {getFieldDecorator('path', { + rules: [ + { + validator:this.checkPath + }] + })( + + )} + +
    +
    +

    + +

    + +
    + +
    + + + {getFieldDecorator('message', { + rules: [{required: true, message: "请输入提交信息"}], + })( + + )} + +
    +
    + + 取消 +
    + + +
    + ) + } +} +const WrappedRepositoryAddFile = Form.create({name: 'taskRepositoryAddFile'})(RepositoryAddFile); +// RouteHOC() +export default (WrappedRepositoryAddFile); \ No newline at end of file diff --git a/public/react/src/tpm/shixunchild/Repository/RepositoryCodeEditor.js b/public/react/src/tpm/shixunchild/Repository/RepositoryCodeEditor.js new file mode 100644 index 000000000..51f6e35f2 --- /dev/null +++ b/public/react/src/tpm/shixunchild/Repository/RepositoryCodeEditor.js @@ -0,0 +1,185 @@ +import React, { Component } from 'react'; + +import { Redirect } from 'react-router'; + +import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom"; + +import PropTypes from 'prop-types'; + +import classNames from 'classnames'; + +import axios from 'axios'; + +import RepositoryDirectories from './RepositoryDirectories' + +import { trace_collapse } from 'educoder' + +import Popconfirm from 'antd/lib/popconfirm'; +import 'antd/lib/popconfirm/style/css'; + +import { message } from 'antd'; + +require('codemirror/lib/codemirror.css'); + +const $ = window.$; + + +/** + ---------------------------- START + */ +function getModeByMirrorName(mirror_name) { + let mode = 'javascript' + if (mirror_name && mirror_name.length) { + for (let i = 0; i < mirror_name.length; i++) { + let modeVal = mirrorNameModeMap[mirror_name[i]]; + if (modeVal) { + mode = modeVal; + break; + } + } + } + return mode; +} +const _extraKeys = {"Alt-/": "autocomplete"}; +function createCMOptions(mirror_name) { + let mode = getModeByMirrorName(mirror_name) + + let cmOptions = { + lineNumbers: true, + mode: mode, + theme: "railscasts", + indentUnit:4, + matchBrackets: true, + autoRefresh: true, + smartIndent: true,//智能换行 + extraKeys: _extraKeys, + autofocus: true, + styleActiveLine: true, + lint: true, + gutters: ["CodeMirror-linenumbers", "breakpoints", "CodeMirror-lint-markers"] + }; + return cmOptions; +} + +const mirrorNameModeMap = { + 'JFinal': 'text/x-java', + 'Java': 'text/x-java', + 'Kotlin': 'text/x-kotlin', + 'C/C++' : 'text/x-c++src', + 'MachineLearning': { + name: "python", + version: 3, + singleLineStringErrors: false + }, + 'Python2.7': { + name: "python", + version: 3, + singleLineStringErrors: false + }, + 'Python3.6': { + name: "python", + version: 3, + singleLineStringErrors: false + }, +} +/** + ---------------------------- END + */ + +class RepositoryCodeEditor extends Component { + constructor(props) { + super(props) + this.state = { + codeSaving: false + } + } + componentDidUpdate = (prevProps, prevState) => { + + if (this.props.fileContent && this.props.fileContent != prevProps.fileContent) { + // window.setTimeout(() => { + this.extend_editor.setValue(this.props.fileContent) + // }, 2000) + } + } + componentDidMount(){ + let cmOptions = createCMOptions(this.props.mirror_name) + const extend_editor = window.CodeMirror.fromTextArea(window.$('#codemirror-file-edit')[0] + , cmOptions); + + // tpi没setValue也可以 + extend_editor.setValue('') + extend_editor.refresh(); + + // 拖拽也需要用 : window.editor_CodeMirror.refresh() + window.editor_tempCodeMirror = extend_editor; + this.extend_editor = extend_editor; + } + + saveCode = () => { + const { shixunId, pathArray } = this.props; + const url = `/shixuns/${shixunId}/update_file.json` + const path = pathArray.join('/') + this.setState({ codeSaving: true }) + axios.post(url, { + secret_repository: this.props.secret_repository_tab, + content: this.extend_editor.getValue(), + // type: forTest === true ? 1 : 0, + path: path + } + ).then((response) => { + if (response.data.content) { + message.success('保存成功'); + this.setState({ codeSaving: false }) + } + }) + } + render() { + const { fileContent, match, saveCode } = this.props; + const { codeSaving } = this.state; + return ( + + +
    + + +
    +
    +
    +
    + { codeSaving ? + 保存中... + : this.saveCode(this.extend_editor.getValue())} + okText="确定" cancelText="取消"> + {/* onClick={this.saveCode} + onClick={() => saveCode(this.extend_editor.getValue())} + */} + 保存 + } +
    +
    +
    + + +
    + +
    +
    + +
    + + ); + } +} +export default RepositoryCodeEditor; diff --git a/public/react/src/tpm/shixunchild/Repository/RepositoryCombinePath.js b/public/react/src/tpm/shixunchild/Repository/RepositoryCombinePath.js new file mode 100644 index 000000000..aba008e20 --- /dev/null +++ b/public/react/src/tpm/shixunchild/Repository/RepositoryCombinePath.js @@ -0,0 +1,82 @@ +import React, { Component } from 'react'; + +import { Redirect } from 'react-router'; + +import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom"; + +import PropTypes from 'prop-types'; + +import classNames from 'classnames'; + +import axios from 'axios'; + +import { trace_collapse, WordsBtn } from 'educoder' + +import { message, Input } from 'antd'; + + +const $ = window.$; + + +class RepositoryCombinePath extends Component { + constructor(props) { + super(props) + this.state = { + value: this.props.secret_dir_path || '', + isEdit: false, + } + } + + onSave = () => { + const { shixunId, pathArray } = this.props; + const url = `/shixuns/${shixunId}/set_secret_dir.json` + + this.setState({ codeSaving: true }) + axios.post(url, { + secret_dir_path: this.state.value + } + ).then((response) => { + if (response.data) { + message.success('保存成功'); + this.setState({isEdit: false}) + } + }) + } + onChange = (e) => { + const { value } = e.target; + this.setState({ value }) + } + onEdit = () => { + this.setState({isEdit: true}, () => { + window.$('.combinePathEditRow input')[0].focus() + }); + } + render() { + const { fileContent, match, saveCode } = this.props; + const { isEdit, value } = this.state; + return ( + +
    + + 第一版本库合并路径: + + {!isEdit && 修改} + {isEdit && 保存} +
    + + + ); + } +} +export default RepositoryCombinePath; diff --git a/public/react/src/tpm/shixunchild/Repository/RepositoryDirectories.js b/public/react/src/tpm/shixunchild/Repository/RepositoryDirectories.js new file mode 100644 index 000000000..7c6eca37a --- /dev/null +++ b/public/react/src/tpm/shixunchild/Repository/RepositoryDirectories.js @@ -0,0 +1,66 @@ +import React, { Component } from 'react'; + +import { Redirect } from 'react-router'; + +import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom"; + +import PropTypes from 'prop-types'; + +import classNames from 'classnames'; + +import axios from 'axios'; + +import { trace_collapse } from 'educoder' +const $ = window.$; + + +class RepositoryDirectories extends Component { + constructor(props) { + super(props) + this.state = { + + } + } + componentDidMount() { + } + render() { + const { match, pathArray, fetchRepo + } = this.props; + let { RepositoryList } = this.state; + return ( + + + { pathArray.length !== 0 && +
    + fetchRepo(0)} + > + {match.params.shixunId} + + / + { pathArray.map((item, index) => { + // /shixuns/3ozvy5f8/repository/3ozvy5f8/master/shixun_show/src + return ( + + { this.props.nameTypeMap[item] === 'tree' || item.indexOf('.') === -1 + ? fetchRepo(index + 1)} + className="color-blue"> + {item} + : + + {item} + } + {index !== pathArray.length - 1 && /} + + ) + }) + } +
    } + +
    + + ); + } +} +export default RepositoryDirectories; diff --git a/public/react/src/tpm/shixunchild/Repository/TPMRepositoryCommits.js b/public/react/src/tpm/shixunchild/Repository/TPMRepositoryCommits.js new file mode 100644 index 000000000..663c5fcf3 --- /dev/null +++ b/public/react/src/tpm/shixunchild/Repository/TPMRepositoryCommits.js @@ -0,0 +1,145 @@ +import React, { Component } from 'react'; + +import { Redirect } from 'react-router'; + +import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom"; + +import PropTypes from 'prop-types'; + +import classNames from 'classnames'; + +import axios from 'axios'; + +import TPMNav from '../../component/TPMNav' +import TPMRightSection from '../../component/TPMRightSection' +import { CircularProgress } from 'material-ui/Progress'; + +import { trace_collapse } from 'educoder' +const $ = window.$; + +// 点击按钮复制功能 +function jsCopy(){ + var e = document.getElementById("copy_rep_content"); + e.select(); + document.execCommand("Copy"); +} +class TPMRepositoryCommits extends Component { + constructor(props) { + super(props) + this.state = { + RepositoryList: undefined, + } + } + componentDidMount() { + let id = this.props.match.params.shixunId; + + let collaborators=`/shixuns/`+id+`/commits.json`; + axios.post(collaborators, { + secret_repository: this.props.secret_repository_tab + }).then((response)=> { + + if(response.status===200){ + this.setState({ + RepositoryList: response.data + }); + } + trace_collapse('repo commits res', response.data) + + }).catch((error)=>{ + console.log(error) + }); + + } + render() { + const { loadingContent, creator, shixun, myshixun, recommend_shixuns, current_user, watched, + aboutFocus, user, match + } = this.props; + let { RepositoryList } = this.state; + return ( + + +
    + {/* 可能会影响到其他页面的样式,需要测试、协商 */} +
    + + { loadingContent ? + + : + +
    +
    + + 提交记录 + + {/*  35 */} + + 返回 + +
    + + +
    +
      + { RepositoryList === undefined ? "" : RepositoryList.commits.map( (item, key)=>{ + return ( +
    • + {item.email} +

      + {item.title} +

      + {item.time} + +
      +
    • ) + }) + } +
    +
    +
    + } +
    + +
    + +
    +
    + + +
    + + ); + } +} + +/** + { RepositoryList === undefined ? "" : RepositoryList.commits.map( (item, key)=>{ + // {"email":"李暾","title":"2\n","id":"80cb6fc55a14bdd64a9c99913f416966238ed3de","time":"49年前"} + return ( +
    +
    {item.email}
    +
    {item.title}
    +
    {item.id}
    +
    {item.time}
    +
    + ) + }) + */ +export default TPMRepositoryCommits; diff --git a/public/react/src/tpm/shixunchild/ShixunDiscuss/ShixunDiscuss.js b/public/react/src/tpm/shixunchild/ShixunDiscuss/ShixunDiscuss.js new file mode 100644 index 000000000..4e9470f89 --- /dev/null +++ b/public/react/src/tpm/shixunchild/ShixunDiscuss/ShixunDiscuss.js @@ -0,0 +1,170 @@ +import React, { Component } from 'react'; + +import { Redirect } from 'react-router'; + +import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom"; + +import PropTypes from 'prop-types'; + +import classNames from 'classnames'; + +import { getImageUrl, toPath } from 'educoder' + +import axios from 'axios'; + +const $ = window.$; + +class ShixunDiscuss extends Component { + constructor(props) { + super(props) + this.state = { + TPMRightSectionData: undefined + } + } + getshixunsDetailsList = (id) => { + let shixunsDetailsURL = `/shixuns/` + id + `/discusses.json`; + axios.get(shixunsDetailsURL).then((response) => { + if (response.status === 200) { + this.setState({ + TPMRightSectionData: response.data + }); + } + }).catch((error) => { + console.log(error) + }); + } + + componentDidMount() { + let id = this.props.match.params.shixunId; + setTimeout(this.getshixunsDetailsList(id), 1000); + } + render() { + let { TPMRightSectionData } = this.state; + + return ( +
    +
    +
    + + + { + TPMRightSectionData===undefined?"":TPMRightSectionData.map((item,key)=>{ + return( +
    +
    + + 用户头像 + +
    + +
    +
    +
    + +
    +
    + {item.user.name} + {item.time} + [第{item.round}关] +
    +
    + +
    +
    +

    {item.content}

    +
    +
    +
    +
    + + { + item.replies.map((i,k)=>{ + return( +
    +
    +
    +
    +
    + {i.user.name} + {i.time} +
    +

    + + + + + + + +

    +
    +
    +
    +
    +

    {i.content}

    +
    +
    +
    +
    +
    +
    + + ) + }) + } + + +

    + + + + + + + + + + + + + + + + + 3 + + +

    + + +
    +
    + + 0?1442652658 + +
    + +
    +
    + +
    +
    调整高度
    + 发送 +
    +
    +
    +
    +
    +
    + ) + }) + } + +
    +
    +
    + ) + } + } + + export default ShixunDiscuss; diff --git a/public/react/src/tpm/shixunchild/Shixunfork_list.js b/public/react/src/tpm/shixunchild/Shixunfork_list.js new file mode 100644 index 000000000..f813441f1 --- /dev/null +++ b/public/react/src/tpm/shixunchild/Shixunfork_list.js @@ -0,0 +1,69 @@ +import React, { Component } from 'react'; +import { Redirect } from 'react-router'; + +import { BrowserRouter as Router, Route, Link} from "react-router-dom"; + +import { Switch } from 'antd'; + +import PropTypes from 'prop-types'; + +import classNames from 'classnames' + +import { TPMIndexHOC } from '../TPMIndexHOC' + +import { SnackbarHOC } from 'educoder' + +import ShixunCard from '.././shixuns/ShixunCard'; + +import { Pagination,Row,Col,Rate } from 'antd'; + + import './shixunchildCss/Shixunfork_list.css'; + +import 'antd/lib/rate/style/index.css'; + +const $ = window.$; + +class Shixunforklist extends Component { + constructor(props) { + super(props) + this.state = { + + } + } + + handleChange = (value) => { + console.log('Page: ', value); + // this.setState({ value }); + } + //JSX + render() { + const { match, history } = this.props + + return ( +
    + +
    +
    + Fork实训列表 + 返回 +
    + + + + + + +
    +
    +
      + +
    +
    +
    +
    +
    +
    + ); + } +} +export default SnackbarHOC() (TPMIndexHOC ( Shixunforklist )); diff --git a/public/react/src/tpm/shixunchild/shixunchildCss/Challenges.css b/public/react/src/tpm/shixunchild/shixunchildCss/Challenges.css new file mode 100644 index 000000000..493a95301 --- /dev/null +++ b/public/react/src/tpm/shixunchild/shixunchildCss/Challenges.css @@ -0,0 +1,28 @@ +.editormd-html-preview, .editormd-preview-container { + width: 95% !important; +} +.Finish_button{ + height: 30px; + line-height: 30px; + margin-top: -8px; +} +.startbtnModal .ant-modal-content{ + background: transparent; + box-shadow: 0 4px 12px transparent; +} + +.startbtnModal .ant-modal-content .ant-modal-body .ant-spin-spinning{ + margin-left: 45%; +} + +.color05101a{ + color:#05101a; +} + +.mtf3{ + margin-top: -3px; +} +.addshixuns{ + height: 27px; + line-height: 25px; +} \ No newline at end of file diff --git a/public/react/src/tpm/shixunchild/shixunchildCss/Shixunfork_list.css b/public/react/src/tpm/shixunchild/shixunchildCss/Shixunfork_list.css new file mode 100644 index 000000000..d6ef5ebfe --- /dev/null +++ b/public/react/src/tpm/shixunchild/shixunchildCss/Shixunfork_list.css @@ -0,0 +1,6 @@ +.ant-rate{ + color: #FFAA05 !important; +} +.ant-pagination-options-quick-jumper input{ + height: 22 !important; +} \ No newline at end of file diff --git a/public/react/src/tpm/shixuns/ShixunCard.js b/public/react/src/tpm/shixuns/ShixunCard.js new file mode 100644 index 000000000..9f62ed6b7 --- /dev/null +++ b/public/react/src/tpm/shixuns/ShixunCard.js @@ -0,0 +1,200 @@ +import React, { Component } from 'react'; +import { Redirect } from 'react-router'; + +import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom"; + +import PropTypes from 'prop-types'; + +import classNames from 'classnames'; + +import { Rating ,Pagination} from "@icedesign/base"; + +import {getImageUrl,setImagesUrl, toPath,getUrl} from 'educoder'; + +import { Spin,Icon,Tooltip ,Rate} from 'antd'; +import LoadingSpin from '../../../common/LoadingSpin'; +import './shixunCss/shixunCard.css'; + +// 引入业务组件样式 + +import axios from 'axios'; + +const $ = window.$; + +class ShixunCard extends Component { + constructor(props) { + super(props) + + this.state = { + startValue:[], + order_by:"", + page:1, + limit:16, + keyword:"", + status:0, + diff:0, + hideme:false, + tag_level:3, + tag_id:'' + } + + } + + PaginationonChange=(pageNumber)=> { + this.props.shixunsPage(pageNumber); + } + + render() { + let {middleshixundata, pagination, typepvisible, pages, totalcount} = this.props; + const MyRate = ({ defaultValue, ...rest }) => { + let myValue = defaultValue; + // console.log(myValue-Math.floor(myValue)) + // if (myValue < Math.ceil(myValue)) { + // myValue = Math.floor(myValue) + 0.5; + // } + + return ; + }; + return ( +
    + + + + { middleshixundata === undefined?"":middleshixundata.length === 0 ?
    + + +

    暂时还没有相关数据哦!

    +
    :""} + + +
    +
    +
    + {middleshixundata === undefined || middleshixundata.length === 0?" ":middleshixundata.map((item,key)=>{ + return( +
    + + { + item.tag_name === null ? "": +
    + {item.tag_name} + {/**/} +
    + } +
    + +

    非试用内容,需要授权

    +
    + + + {/**/} + + + {/*target="_blank"*/} + +
    +

    + + {item.name} + +

    + + {/*target="_blank"*/} + {/**/} +

    + + {/**/} + + + {item.score_info===null?"5分":item.score_info+"分"} +

    + +

    + + + {item.challenges_count} + + + + {/**/} + {/**/} + {/*{item.exp}*/} + {/**/} + {/**/} + + + + {item.stu_num} + + + + {item.level} +

    + +
    +
    + ) + }) + } + +
    + +
    + {/*totalcount*/} +
    + {/**/} + {/* 不加参数请求的时候,没返回总数了。加了个比较大的数字,让他可以翻页 */} + +
    + +
    + +
    +
    +
    + ) + } +} + +export default ShixunCard; diff --git a/public/react/src/tpm/shixuns/ShixunCardList.js b/public/react/src/tpm/shixuns/ShixunCardList.js new file mode 100644 index 000000000..d95ef75fe --- /dev/null +++ b/public/react/src/tpm/shixuns/ShixunCardList.js @@ -0,0 +1,253 @@ +import React, { Component } from 'react'; +import { Redirect } from 'react-router'; + +import { BrowserRouter as Router, Route} from "react-router-dom"; + +import { Switch ,Input,Tooltip,Icon} from 'antd'; + +import PropTypes from 'prop-types'; + +import classNames from 'classnames' + +import 'antd/lib/switch/style/index.css' + +import './shixunCss/ShixunCardList.css'; + +import { on, off } from 'educoder' + +const $ = window.$; + +const Search = Input.Search; + +class ShixunCardList extends Component { + + constructor(props) { + super(props); + this.state={ + allevent:"desc", + mine:0, + InputValue: props.keyword || "", + typemy:0, + hots:0, + news:0, + shixunid:"", + upcircle:false, + typekeyid:undefined, + } + } + + componentDidUpdate = (prevProps, prevState) => { + if (this.props.keyword != prevProps.keyword) { + this.setState({ + InputValue: this.props.keyword + }) + } + } + componentDidMount = () => { + on('searchKeywordChange', (event, data) => { + // console.log(data) + this.Input_search(data) + }) + } + componentWillUnmount = () => { + off('searchKeywordChange') + } + + + latestHot=(e,key)=>{ + + let{upcircle,typekeyid}=this.state; + + let id = e.target.id; + $("#"+id).siblings().removeClass("active"); + $("#"+id).addClass("active"); + + let type; + + // if(id==="all"){ + // type="publish_time"; + // } + if(id==="hot"){ + type="hot"; + }else if(id==="new"){ + type="new"; + + } + if(typekeyid===key){ + if(upcircle===true){ + this.setState({ + upcircle:false, + }) + this.props.Shixunsupcircles("desc") + }else if(upcircle===false){ + this.setState({ + upcircle:true, + }) + this.props.Shixunsupcircles("asc") + } + }else{ + this.setState({ + typekeyid:key + }) + } + + //allevent + this.props.ShixunsState(false,type); + } + + + onSwitchChange=(e,key)=>{ + let id=e.target.id + $("#"+id).siblings().removeClass("active"); + $("#"+id).addClass("active"); + let {typemy,upcircle,typekeyid}=this.state; + + if(typekeyid===key){ + if(upcircle===true){ + this.setState({ + upcircle:false, + }) + this.props.Shixunsupcircles("desc") + }else if(upcircle===false){ + this.setState({ + upcircle:true + }) + this.props.Shixunsupcircles("asc") + } + }else{ + this.setState({ + typekeyid:key + }) + } + + + if(typemy===0){ + this.setState({ + typemy:1 + }) + }else{ + this.setState({ + typemy:0 + }) + } + // allevent + this.props.ShixunsSwitch(); + } + //输入框搜索 + Input_search = (value) => { + this.setState({ + InputValue: value + }) + this.props.OnSearchInput(value,true); + } + + Input_searchs = (e) => { + this.setState({ + InputValue: e.target.value + }) + this.props.OnSearchInput(e.target.value,false); + } + upcircles=(val)=>{ + if(val==="asc"){ + this.setState({ + upcircle:false, + }) + this.props.Shixunsupcircles("desc") + }else if(val==="desc"){ + this.setState({ + upcircle:true + }) + this.props.Shixunsupcircles("asc") + } + } + render(){ + let {mine,InputValue,upcircle}=this.state; + return ( +
    +
    + + {/*
    this.latestHot(e,1)}>全部*/} + {/*
    */} + {/*
    this.onSwitchChange(e,2)}>我的*/} + {/*
    */} + +
    this.latestHot(e,4)}>最新 +
    + +
    this.latestHot(e,3)}>最热 +
    + + + {/*
    this.upcircles("asc")}*/} + {/*>*/} + {/**/} + {/**/} + {/*/!**!/*/} + {/**/} + {/*
    */} + {/*
    this.upcircles("desc")}*/} + {/*style={{display:upcircle===true?"none":"block"}}*/} + {/*>*/} + {/**/} + {/**/} + {/*/!**!/*/} + {/**/} + {/*
    */} + + {/*
    */} + {/* this.Input_search(value)}*/} + {/*enterButton*/} + {/*/>*/} + + {/* this.Input_search(value)} + autoComplete="off" + > */} + {/*
    */} + {/*
    */} + {/*{*/} + {/*this.props.search_tags === null ? "" : this.props.search_tags*/} + {/*}*/} + {/*
    */} + {/*/!*
    */} + {/* *!/*/} + {/**/} + {/*
    */} + {/*隐藏我的*/} + + {/*
    */} + {/**/} +
    +
    + ); + } +} + +export default ShixunCardList; diff --git a/public/react/src/tpm/shixuns/ShixunSearchBar.js b/public/react/src/tpm/shixuns/ShixunSearchBar.js new file mode 100644 index 000000000..f9c4a7936 --- /dev/null +++ b/public/react/src/tpm/shixuns/ShixunSearchBar.js @@ -0,0 +1,292 @@ +import React, { Component } from 'react'; + +import { Select, Input,Menu, Dropdown } from 'antd'; + +import 'antd/lib/style/index.css'; + +import 'antd/lib/select/style/index.css'; + +import 'antd/lib/input/style/index.css'; + +import './shixunCss/ShixunSearchBar.css'; + +import axios from 'axios'; + +const $ = window.$; + +const Option = Select.Option; + +const Search = Input.Search; + + +class ShixunSearchBar extends Component { + + constructor(props) { + super(props) + this.state = { + status: undefined, + diff: 0, + InputValue: undefined, + shixunhoverData: [], + shixunchildValues:'', + shixunsearchAllvalue:"a", + openStatus:false, + openLevel:false + } +} + + //状态筛选 + status_search = (value) => { + let newvalue = value; + if (newvalue === "0") { + newvalue = " " + } else if (newvalue === "1") { + newvalue = 2 + } else if (newvalue === "2") { + newvalue = 1 + } else if (newvalue === "3") { + newvalue = 3 + } + + this.setState({ + status: newvalue, + openStatus:false + }) + let list = [{'type': 1}, {'value': newvalue}]; + this.props.StatusEnquiry(list); +} + + //难度筛选 +diff_search = (value) => { + this.setState({ + diff: value, + openLevel:false + }) + let list=[{'type':2},{'value':value}]; + this.props.StatusEnquiry(list); +} + + //输入框搜索 +Input_search = (value) => { + this.setState({ + InputValue: value + }) + this.props.OnSearchInput(value); +} + //查询 +shixunsearchAll = (e) => { + let{shixunsearchAllvalue}=this.state; + let id = e.target.value; + + if(shixunsearchAllvalue===id){ + return + } + if(id===0){ + id=" " + this.setState({ + InputValue: " " + }) + this.props.OnSearchInput(""); + } + let list=[{'tag_level':1},{'tag_id':id}]; + if(id!=undefined){ + this.setState({ + shixunsearchAllvalue:id, + shixunchildValues:"" + }) + this.props.Updatasearchlist(list); + } + +} + + shixunsearchall=(e)=>{ + let{shixunsearchAllvalue}=this.state; + let id = "a"; + + if(shixunsearchAllvalue===id){ + return + } + this.setState({ + shixunsearchAllvalue:"a", + shixunchildValues:"" + }) + this.props.allUpdatashixunlist(); + } + + //选择Tab页详情 + getshixunchildValue = (e) => { + + debugger + let id = e.target.name; + let newid=e.target.id; + let list=[{'tag_level':2},{'tag_id':id}]; + if(id!=undefined||newid!=undefined){ + this.setState({ + shixunsearchAllvalue:newid + }) + this.props.Updatasearchlist(list); + } + } + +getshixunchildValues = (e) => { + let id = e.target.id; + let newid=e.target.name; + let list=[{'tag_level':3},{'tag_id':id}]; + if(id!=undefined||newid!=undefined){ + this.setState({ + shixunchildValues:id, + shixunsearchAllvalue:newid + }) + this.props.Updatasearchlist(list); + } + +} + +componentDidMount() { + let hoverUrlArr = []; + let hoverUrl = `/shixuns/menus.json`; + axios.get(hoverUrl + ).then((response) => { + hoverUrlArr = response.data; + // hoverUrlArr.reverse(); + this.setState({ + shixunhoverData: hoverUrlArr + }) + }).catch((error) => { + console.log(error) + }) +} + +render() { + let {shixunhoverData, shixunchildValues, shixunsearchAllvalue, InputValue,openStatus,openLevel} = this.state; + let {typepvisible} = this.props; + // //实训首页筛选的移入和点击事件 + // $(".shaiItem").hover(function(){ + // var hei=parseInt($(".shaiAllItem").height())-2; + // $(this).find(".subshaicontent").css("top", '34px'); + // $(this).find(".subshaicontent").show(); + // },function(){ + // $(this).find(".subshaicontent").hide(); + // }); + // + // $(".shaiItem").live("click",function(){ + // $(".shaiItem").removeClass("active"); + // $(this).addClass("active"); + // $(".subshaicontent").hide(); + // }); + // + // $(".subshaicontent").live("click", function(event){ + // $(".subshaicontent").hide(); + // event.stopPropagation(); + // }); + + let overlaymenu=(item,id)=>( + + { + item.map((list,k)=>{ + return( + +
    + {list.name} +
    + { + list.tags.map((tag,e)=>{ + return( + {tag.name} + ) + }) + } +
    +
    +
    + ) + }) + } +
    + ) + + return ( +
    +
    +
    +
    + 方向: +
    +
  • 全部
  • + + { + shixunhoverData.map((item,key)=>{ + return( + +
  • + {item.name} +
  • +
    + ) + }) + } + + +
    +
    +
    + 筛选: + { + + } +
    +
  • this.diff_search(0)}>全部难度
  • +
  • this.diff_search(1)}>初级学员
  • +
  • this.diff_search(2)}>中级学员
  • +
  • this.diff_search(3)}>高级学员
  • +
  • this.diff_search(4)}>顶级学员
  • +
    + +
    +
    +
    +
    + ); +} +} + +export default ShixunSearchBar; diff --git a/public/react/src/tpm/shixuns/ShixunsIndex.js b/public/react/src/tpm/shixuns/ShixunsIndex.js new file mode 100644 index 000000000..15579610d --- /dev/null +++ b/public/react/src/tpm/shixuns/ShixunsIndex.js @@ -0,0 +1,422 @@ +import React, { Component } from 'react'; + +import { Redirect } from 'react-router'; + +import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom"; + +import axios from 'axios'; + +import { Spin } from 'antd'; + +import { TPMIndexHOC } from '../TPMIndexHOC'; + +import { SnackbarHOC } from 'educoder'; + +import ShixunCardList from './ShixunCardList'; + +import ShixunSearchBar from './ShixunSearchBar'; + +import ShixunCard from './ShixunCard'; + +import UpgradeModals from '../../modals/UpgradeModals'; + +const queryString = require('query-string'); + +const $ = window.$; + +class ShixunsIndex extends Component { + constructor(props) { + super(props) + this.state={ + order_by: "new", + page:1, + limit:16, + keyword:"", + status:0, + diff:0, + tag_level: 1, + tag_id:'', + middleshixundata:[], + typepvisible:true, + pages:1, + search_tags:null, + parsedid:undefined, + newtag_level:undefined, + newpalce:undefined, + sort:"desc" + } + } + componentDidMount(){ + + const upsystem=`/users/system_update.json`; + axios.get(upsystem).then((response)=>{ + let updata=response.data; + this.setState({ + updata:updata + }) + }).catch((error)=>{ + console.log(error); + }) + + + + let _keyword; + if (window.__headSearchKeyword) { + this.setState({ keyword: window.__headSearchKeyword }) + _keyword = window.__headSearchKeyword + delete window.__headSearchKeyword + } + const parsed = queryString.parse(this.props.location.search); + if(parsed.id===undefined&&parsed.type===undefined){ + let {order_by, tag_level, tag_id, page, limit, keyword, status, diff} = this.state; + let params={ + order_by:order_by, + tag_level:tag_level, + tag_id:tag_id, + page:page, + limit:limit, + keyword: _keyword || keyword , + status:status, + diff:diff, + sort: "desc" + } + this.shixunresultend(params); + }else{ + let {order_by,page, limit, keyword, status, diff} = this.state; + let nawparsed=parsed.type; + let newpalce=parsed.palce; + if(nawparsed==="rep"){ + nawparsed=1 + } + else if(nawparsed==="sub"){ + nawparsed=2 + }else if(nawparsed==="tag"){ + nawparsed=3 + } + let params={ + order_by:order_by, + tag_level:nawparsed, + tag_id:parsed.id, + page:page, + limit:limit, + keyword: _keyword || keyword, + status:status, + diff:diff, + sort: "desc" + } + this.setState({ + parsedid:parsed.id, + newtag_level:nawparsed, + newpalce:newpalce + }) + this.shixunresultend(params); + } + + } + + allUpdatashixunlist=()=>{ + let{sort,order_by}=this.state; + + this.setState({ + tag_level: 1, + tag_id:'', + page: 1, + limit: 16, + keyword:'', + status: 0, + diff: 0, + }) + + let params={ + order_by:order_by, + tag_level: 1, + tag_id:'', + page: 1, + limit: 16, + keyword:'', + status: 0, + diff: 0, + sort:sort + } + this.shixunresultend(params) + } + Updatasearchlist=(value)=>{ + if (value[1].tag_id === " ") { + this.setState({ + keyword: "" + }) + } + this.setState({ + tag_level:value[0].tag_level, + tag_id:value[1].tag_id, + typepvisible:true + }) + + let {order_by, sort, limit, keyword, status, diff} = this.state; + + let params={ + order_by:order_by, + tag_level:value[0].tag_level, + tag_id:value[1].tag_id, + page:1, + limit:limit, + keyword:keyword, + status:status, + diff:diff, + sort:sort + } + + this.shixunresultend(params) + } + + StatusEnquiry=(key)=>{ + + let Vrl=`/shixuns.json`; + let newstatus; + let newdiff; + if(key[0].type===1){ + this.setState({ + status: key[1].value, + typepvisible:true + }) + newstatus=key[1].value; + newdiff=this.state.diff; + }else if(key[0].type===2){ + this.setState({ + diff: key[1].value, + typepvisible:true + }) + newdiff=key[1].value; + newstatus=this.state.status; + } + let params= { + order_by:this.state.order_by, + tag_level:this.state.tag_level, + tag_id:this.state.tag_id, + page:1, + limit:this.state.limit, + keyword:this.state.keyword, + status:newstatus, + diff:newdiff, + } + this.shixunresultend(params) + + } + + OnSearchInput=(value,type)=>{ + if(type===true){ + this.setState({ + keyword:value, + typepvisible:true, + pages:1 + }) + let {order_by, tag_level, tag_id, sort, limit, status, diff} = this.state; + let params= { + order_by:order_by, + tag_level:tag_level, + tag_id:tag_id, + page:1, + limit:limit, + keyword:value, + status:status, + diff:diff, + sort:sort + } + this.shixunresultend(params) + }else{ + this.setState({ + keyword:value, + pages:1 + }) + } + + + } + + ShixunsSwitch=()=>{ + //types + this.setState({ + order_by:"mine", + typepvisible:true, + pages:1, + }) + let{tag_level,tag_id,page,limit,keyword,status,diff,sort}=this.state; + let newsort=sort; + if(newsort===undefined){ + newsort="desc" + } + let params= { + order_by:"mine", + tag_level:tag_level, + tag_id:tag_id, + page:1, + limit:limit, + keyword:keyword, + status:status, + diff:diff, + sort:newsort + } + this.shixunresultend(params) + } + + + shixunsPage=(value)=>{ + this.setState({ + page:value, + typepvisible:true, + pages:value + }) + let {order_by, tag_level, tag_id, limit, keyword, status, diff,sort} = this.state; + let params= { + order_by:order_by, + tag_level:tag_level, + tag_id:tag_id, + page:value, + limit:limit, + keyword:keyword, + status:status, + diff:diff, + sort:sort + } + + let Url=`/shixuns.json`; + axios.get(Url,{ + params + }).then((response)=> { + if(response.status===200){ + this.setState({ + middleshixundata: response.data, + typepvisible:false, + }); + } + }).catch((error)=>{ + console.log(error) + }); + } + ShixunsState=(val,type)=>{ + // sort, + let {tag_level, tag_id, page, limit, keyword, status, diff,sort} = this.state; + let newsort=sort; + this.setState({ + order_by:type, + typepvisible:true, + pages:1, + // sort:sort + }) + + let params + // let vals=false + if(newsort===undefined){ + newsort="desc" + } + params= { + order_by:type, + tag_level:tag_level, + tag_id:tag_id, + page:1, + limit:limit, + keyword:keyword, + status:status, + diff:diff, + sort:newsort + } + this.shixunresultend(params) + } + + Shixunsupcircles=(sort)=>{ + console.log(sort) + this.setState({ + sort:sort + }) + let { + order_by, + tag_level, + tag_id, + limit, + keyword, + status, + diff, + } = this.state; + + + + let params= { + order_by:order_by, + tag_level:tag_level, + tag_id:tag_id, + page:1, + limit:limit, + keyword:keyword, + status:status, + diff:diff, + sort:sort + } + this.shixunresultend(params) + } + + + + + shixunresultend=(params)=>{ + let Url=`/shixuns.json`; + axios.get(Url,{ + params + }).then((response)=> { + // TODO 有keyword返回值时 显示一共有多少条记录 + if(response.status===200){ + this.setState({ + search_tags:response.data.search_tags, + middleshixundata: response.data, + typepvisible:false, + pages:1 + }); + } + }).catch((error)=>{ + console.log(error) + }); + } + render() { + let {middleshixundata, typepvisible, pages, search_tags, keyword,parsedid,newtag_level,newpalce} = this.state; + + // console.log(this.state.updata) + return ( +
    + {this.state.updata===undefined?"":} + {/**/} + + + + + + {/**/} +
    + ); + } +} + +export default SnackbarHOC() (TPMIndexHOC ( ShixunsIndex )); diff --git a/public/react/src/tpm/shixuns/css/TPMBanner.css b/public/react/src/tpm/shixuns/css/TPMBanner.css new file mode 100644 index 000000000..fe059fccd --- /dev/null +++ b/public/react/src/tpm/shixuns/css/TPMBanner.css @@ -0,0 +1,114 @@ +.shixunsdiffcult{ + width: 40px; + height: 21px; + overflow: hidden; + margin-left: 8px; + } + + .rateYo{ + text-align: center; + cursor: default; + width: 111px; + } + + a:link, a:visited { + color: #05101a; +} + +a:link{text-decoration:none;} + +a:visited{text-decoration:none;} + +a:hover{text-decoration:none;} + +a:active{text-decoration:none;} + + +.next-rating-overlay .next-icon{ + color: #FFA800!important; +} + +.displayblock{ + display:block; + text-align: center; + margin-bottom: 20px; +} + +.totalScore{ + justify-content: center; + align-items: center; + display: -webkit-flex; + height: 100%; +} + +.next-progress-line{ + width: 210px !important; + margin-left: 10px; + margin-top: 4px; +} + +.next-progress-line-overlay-normal{ + background-color: #FFA800 !important; +} +.next-rating-base-disabled{ + cursor: default!important; +} +/*#challenge_begin {*/ +/*!*height: 40px !important;*!*/ +/*line-height: 30px;*/ +/*}*/ +.ant-modal-title{ + font-size: 16px; + font-weight: bold !important; + color: #333; +} + +.ml60{ + margin-left:20px; +} + +.marginauto{ + margin:0 auto; +} +.margin152{ + margin-left: 152px; +} + +.margin-tp26{ + margin-top: -26px; +} +.edu-h315{ + height:315px; +} + +.height39 { + height: 39px !important; +} + +#commentsStar{ + margin-top: -7px; + width: 90px; + height: 80px; +} + +.startbtnModal .ant-modal-content{ + background: transparent; + box-shadow: 0 4px 12px transparent; +} + +.startbtnModal .ant-modal-content .ant-modal-body .ant-spin-spinning{ + margin-left: 45%; +} + +.mr51{ + margin-right:51px; +} + +.flexbannerright{ + display: flex; + justify-content: flex-end; +} + +.width360{ + width:360px; +} \ No newline at end of file diff --git a/public/react/src/tpm/shixuns/shixunCss/ShixunCardList.css b/public/react/src/tpm/shixuns/shixunCss/ShixunCardList.css new file mode 100644 index 000000000..c806434f5 --- /dev/null +++ b/public/react/src/tpm/shixuns/shixunCss/ShixunCardList.css @@ -0,0 +1,13 @@ +#myshixuns_count{ + text-decoration:none !important; +} +#created_at{ + text-decoration:none !important; +} +.shixun_repertoire{ + cursor: pointer ; +} +.next-btn-medium:hover{ + color: #4CACFF; + border:1px solid #4CACFF; +} \ No newline at end of file diff --git a/public/react/src/tpm/shixuns/shixunCss/ShixunSearchBar.css b/public/react/src/tpm/shixuns/shixunCss/ShixunSearchBar.css new file mode 100644 index 000000000..9fba271ce --- /dev/null +++ b/public/react/src/tpm/shixuns/shixunCss/ShixunSearchBar.css @@ -0,0 +1,20 @@ +.iconfontShixunSearchBar{ + z-index: 1000; + position: absolute; + right: 3px; + top: 0px; +} + +.diffSelect{ + margin-left:20px !important; + } + .ant-input-search-button{ + /*margin-right: 10px;*/ + border: 1px solid transparent; + } +.Mousebox{ + width: 800px !important; +} +.subshaicontent a{ + height:30px; +} \ No newline at end of file diff --git a/public/react/src/tpm/shixuns/shixunCss/shixunCard.css b/public/react/src/tpm/shixuns/shixunCss/shixunCard.css new file mode 100644 index 000000000..1ec00a26e --- /dev/null +++ b/public/react/src/tpm/shixuns/shixunCss/shixunCard.css @@ -0,0 +1,42 @@ +.ml350 { + margin-left: 40%; +} + +.ml32 { + margin-left: 32%; +} + +.square-img{ + min-height: 210px; +} +.task-hide{ + margin-bottom: 0em; +} +.backFAFAFA{ + background:#FAFAFA; +} + +.demo { + width: 500px; + background-color: #0dcecb; + text-align: center; + padding:50px; +} +.next-loading { + margin-bottom: 5px; + width:100%; +} + +.next-rating-overlay .next-icon{ + color: #FFA800!important; +} + +.custom-pagination { + display: inline-block; + margin-left: 10px; +} + +.ml425{ + margin-left:42.5%; + margin-top:20px; +} \ No newline at end of file diff --git a/public/react/src/tpm/shixuns/shixunCss/tag2.png b/public/react/src/tpm/shixuns/shixunCss/tag2.png new file mode 100644 index 000000000..423d2f7e3 Binary files /dev/null and b/public/react/src/tpm/shixuns/shixunCss/tag2.png differ diff --git a/public/react/src/tpm/shixuns/shixusFunction/ShixunSearchBar.js b/public/react/src/tpm/shixuns/shixusFunction/ShixunSearchBar.js new file mode 100644 index 000000000..4211e3196 --- /dev/null +++ b/public/react/src/tpm/shixuns/shixusFunction/ShixunSearchBar.js @@ -0,0 +1,142 @@ +const $ = window.$; + + +$(function(){ + //实训首页筛选的移入和点击事件 + $(".shaiItem").hover(function(){ + var hei=parseInt($(".shaiAllItem").height())-2; + $(this).find(".subshaicontent").css("top",hei); + $(this).find(".subshaicontent").show(); + },function(){ + $(this).find(".subshaicontent").hide(); + }); + + $(".shaiItem").live("click",function(){ + $(".shaiItem").removeClass("active"); + $(this).addClass("active"); + $(".subshaicontent").hide(); + }); + + $(".subshaicontent").live("click", function(event){ + $(".subshaicontent").hide(); + event.stopPropagation(); + }); + + //最新、最热 + $(".bestChoose").click(function(){ + $(".bestChoose").removeClass("active"); + $(this).addClass("active"); + }) + + //实训路径选择导航条 + $(".path-nav li a").live("click",function(){ + $(".path-nav li").removeClass("active"); + $(this).parent().addClass("active"); + }) +}); + +//隐藏我的学习 + function clickControl(item, type){ + var wid=$(item).width(); + var wid1=$(".controlring").width(); + var hidden_course = 1; + if($(".controlring").css("left")=="1px"){ + $(".controlring").animate({left:parseInt(wid-wid1-1)+"px"}); + $(".controlblue").animate({width:wid+"px"}); + $("input[name='hidden_learn']").val('1'); + }else{ + $(".controlring").animate({left:"1px"}); + $(".controlblue").animate({width:"0px"}); + $("input[name='hidden_learn']").val(''); + hidden_course = 0; + } + if(type == "l_shixun"){ + $("#shixun_search_condition").submit(); + } else{ + $.get("/courses?select="+$("#select_type").val()+"&order="+$("#select_order").val()+"&hidden="+hidden_course); + } +} + +// 清空条件 + function clear_style(){ + $("#shixun_search_condition").find('input[type=hidden]').each(function() { + $(this).val(''); + }); +} + +// 精选实训的搜索 #type参数( status:实训状态; diff:实训难度; search:实训搜索; order:最新最热排序) +function filter_search(values, type){ + switch(type){ + case "status": + $("input[name='status']").val(values); + break; + case "diff": + $("input[name='diff']").val(values); + break; + case "search": + $("input[name='search']").val(values); + break; + } + $("#shixun_search_condition").submit(); +} + +// 点击实训体系名称 # type参数(rep:体系大类别; sub:体系子类别; tags 实训标签; order: 排序) +// # name参数: 列表显示使用 +// # values参数: 赋值给表单的值 +$(".shixun_repertoire").live("click", function(event){ + var type = $(this).attr("data-type"); + var name = $(this).attr("data-name"); + var values = $(this).attr("data-values"); + if(type != 'order'){ + $(".subshaicontent a").removeClass("active"); + $(".shaiItem").removeClass("active"); + $("input[name='repertoire'], input[name='sub_repertoire'], input[name='tag_repertoire']").val(''); + } + $(this).closest(".shaiItem").addClass("active"); + $(".subshaicontent").hide(); + $("#search_name").html(name); + + switch(type){ + case "rep": + $("input[name='repertoire']").val(values); + $("#shixun_search_input").val(""); + $("input[name='search']").val(""); + break; + case "sub": + $("input[name='sub_repertoire']").val(values); + break; + case "tag": + $("input[name='tag_repertoire']").val(values); + break; + case "order": + var $sort = $("input[name='sort']"); + var oldValue = $("input[name='order']").val(); + $("input[name='order']").val(values); + var newValue = $("input[name='order']").val(); + if(oldValue != newValue){ + $("input[name='sort']").val("desc"); + }else { + if($sort.val() == "desc"){ + $sort.val("asc"); + }else{ + $sort.val("desc"); + } + } + break; + } + $(this).addClass("active"); // 因为order需要判断样式因此写在switch之后 + $("#shixun_search_condition").submit(); + event.stopPropagation(); +}); + + +// 实训首页回车搜索 +$("#shixun_search_input").live("keyup", function(e){ + // 兼容FF和IE和Opera + var theEvent = e || window.event; + var code = theEvent.keyCode || theEvent.which || theEvent.charCode; + if (code == 13) { + //回车执行查询 + filter_search($(this).val(), "search"); + } +}); \ No newline at end of file