Merge branch 'jupyter' of https://bdgit.educoder.net/Hjqreturn/educoder into dev_jupyter

chromesetting
杨树林 5 years ago
commit 4bf67843a8

@ -1,114 +1,114 @@
'use strict';
// Do this as the first thing so that any code reading it knows the right env.
process.env.BABEL_ENV = 'development';
process.env.NODE_ENV = 'development';
// Makes the script crash on unhandled rejections instead of silently
// ignoring them. In the future, promise rejections that are not handled will
// terminate the Node.js process with a non-zero exit code.
process.on('unhandledRejection', err => {
throw err;
});
// Ensure environment variables are read.
require('../config/env');
const fs = require('fs');
const chalk = require('chalk');
const webpack = require('webpack');
const WebpackDevServer = require('webpack-dev-server');
const clearConsole = require('react-dev-utils/clearConsole');
const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
const {
choosePort,
createCompiler,
prepareProxy,
prepareUrls,
} = require('react-dev-utils/WebpackDevServerUtils');
const openBrowser = require('react-dev-utils/openBrowser');
const paths = require('../config/paths');
const config = require('../config/webpack.config.dev');
const createDevServerConfig = require('../config/webpackDevServer.config');
const useYarn = fs.existsSync(paths.yarnLockFile);
const isInteractive = process.stdout.isTTY;
const portSetting = require(paths.appPackageJson).port
if ( portSetting ) {
process.env.port = portSetting
}
// Warn and crash if required files are missing
if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
process.exit(1);
}
// Tools like Cloud9 rely on this.
const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3007;
const HOST = process.env.HOST || '0.0.0.0';
if (process.env.HOST) {
console.log(
chalk.cyan(
`Attempting to bind to HOST environment variable: ${chalk.yellow(
chalk.bold(process.env.HOST)
)}`
)
);
console.log(
`If this was unintentional, check that you haven't mistakenly set it in your shell.`
);
console.log(`Learn more here: ${chalk.yellow('http://bit.ly/2mwWSwH')}`);
console.log();
}
// We attempt to use the default port but if it is busy, we offer the user to
// run on a different port. `choosePort()` Promise resolves to the next free port.
choosePort(HOST, DEFAULT_PORT)
.then(port => {
if (port == null) {
// We have not found a port.
return;
}
const protocol = process.env.HTTPS === 'true' ? 'https' : 'http';
const appName = require(paths.appPackageJson).name;
const urls = prepareUrls(protocol, HOST, port);
// Create a webpack compiler that is configured with custom messages.
const compiler = createCompiler(webpack, config, appName, urls, useYarn);
// Load proxy config
const proxySetting = require(paths.appPackageJson).proxy;
console.log('-------------------------proxySetting:', proxySetting)
const proxyConfig = prepareProxy(proxySetting, paths.appPublic);
// Serve webpack assets generated by the compiler over a web sever.
const serverConfig = createDevServerConfig(
proxyConfig,
urls.lanUrlForConfig
);
const devServer = new WebpackDevServer(compiler, serverConfig);
// Launch WebpackDevServer.
devServer.listen(port, HOST, err => {
if (err) {
return console.log(err);
}
if (isInteractive) {
clearConsole();
}
console.log(chalk.cyan('Starting the development server...\n'));
openBrowser(urls.localUrlForBrowser);
});
['SIGINT', 'SIGTERM'].forEach(function(sig) {
process.on(sig, function() {
devServer.close();
process.exit();
});
});
})
.catch(err => {
if (err && err.message) {
console.log(err.message);
}
process.exit(1);
});
'use strict';
// Do this as the first thing so that any code reading it knows the right env.
process.env.BABEL_ENV = 'development';
process.env.NODE_ENV = 'development';
// Makes the script crash on unhandled rejections instead of silently
// ignoring them. In the future, promise rejections that are not handled will
// terminate the Node.js process with a non-zero exit code.
process.on('unhandledRejection', err => {
throw err;
});
// Ensure environment variables are read.
require('../config/env');
const fs = require('fs');
const chalk = require('chalk');
const webpack = require('webpack');
const WebpackDevServer = require('webpack-dev-server');
const clearConsole = require('react-dev-utils/clearConsole');
const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
const {
choosePort,
createCompiler,
prepareProxy,
prepareUrls,
} = require('react-dev-utils/WebpackDevServerUtils');
const openBrowser = require('react-dev-utils/openBrowser');
const paths = require('../config/paths');
const config = require('../config/webpack.config.dev');
const createDevServerConfig = require('../config/webpackDevServer.config');
const useYarn = fs.existsSync(paths.yarnLockFile);
const isInteractive = process.stdout.isTTY;
const portSetting = require(paths.appPackageJson).port
if ( portSetting ) {
process.env.port = portSetting
}
// Warn and crash if required files are missing
if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
process.exit(1);
}
// Tools like Cloud9 rely on this.
const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3007;
const HOST = process.env.HOST || '0.0.0.0';
if (process.env.HOST) {
console.log(
chalk.cyan(
`Attempting to bind to HOST environment variable: ${chalk.yellow(
chalk.bold(process.env.HOST)
)}`
)
);
console.log(
`If this was unintentional, check that you haven't mistakenly set it in your shell.`
);
console.log(`Learn more here: ${chalk.yellow('http://bit.ly/2mwWSwH')}`);
console.log();
}
// We attempt to use the default port but if it is busy, we offer the user to
// run on a different port. `choosePort()` Promise resolves to the next free port.
choosePort(HOST, DEFAULT_PORT)
.then(port => {
if (port == null) {
// We have not found a port.
return;
}
const protocol = process.env.HTTPS === 'true' ? 'https' : 'http';
const appName = require(paths.appPackageJson).name;
const urls = prepareUrls(protocol, HOST, port);
// Create a webpack compiler that is configured with custom messages.
const compiler = createCompiler(webpack, config, appName, urls, useYarn);
// Load proxy config
const proxySetting = require(paths.appPackageJson).proxy;
console.log('-------------------------proxySetting:', proxySetting)
const proxyConfig = prepareProxy(proxySetting, paths.appPublic);
// Serve webpack assets generated by the compiler over a web sever.
const serverConfig = createDevServerConfig(
proxyConfig,
urls.lanUrlForConfig
);
const devServer = new WebpackDevServer(compiler, serverConfig);
// Launch WebpackDevServer.
devServer.listen(port, HOST, err => {
if (err) {
return console.log(err);
}
if (isInteractive) {
clearConsole();
}
console.log(chalk.cyan('Starting the development server...\n'));
openBrowser(urls.localUrlForBrowser);
});
['SIGINT', 'SIGTERM'].forEach(function(sig) {
process.on(sig, function() {
devServer.close();
process.exit();
});
});
})
.catch(err => {
if (err && err.message) {
console.log(err.message);
}
process.exit(1);
});

@ -316,6 +316,11 @@ const RecordDetail = Loadable({
loader: () => import('./modules/developer/recordDetail'),
loading: Loading
});
// jupyter tpi
const JupyterTPI = Loadable({
loader: () => import('./modules/tpm/jupyter'),
loading: Loading
});
// //个人竞赛报名
// const PersonalCompetit = Loadable({
// loader: () => import('./modules/competition/personal/PersonalCompetit.js'),
@ -358,7 +363,7 @@ class App extends Component {
mydisplay:true,
})
};
disableVideoContextMenu = () => {
window.$( "body" ).on( "mousedown", "video", function(event) {
if(event.which === 3) {
@ -577,14 +582,14 @@ class App extends Component {
<Route path="/users/:username"
render={
(props) => {
return (<InfosIndex {...this.props} {...props} {...this.state} />)
}
}></Route>
<Route path="/banks"
render={
(props) => {
(props) => {
return (<BanksIndex {...this.props} {...props} {...this.state} />)
}
}></Route>
@ -615,7 +620,7 @@ class App extends Component {
<Route path="/shixuns/:shixunId" component={TPMIndexComponent}>
</Route>
{/*列表页*/}
{/*列表页 实训项目列表*/}
<Route path="/shixuns" component={TPMShixunsIndexComponent}/>
@ -637,8 +642,8 @@ class App extends Component {
<Route path="/moop_cases"render={
(props) => (<MoopCases {...this.props} {...props} {...this.state} />)
}/>
<Route path="/forums"
<Route path="/forums"
render={
(props)=>(<ForumsIndexComponent {...this.props} {...props} {...this.state}></ForumsIndexComponent>)
}
@ -671,7 +676,7 @@ class App extends Component {
(props)=>(<Ecs {...this.props} {...props} {...this.state}></Ecs>)
}/>
<Route path="/problems/new/:id?"
<Route path="/problems/new/:id?"
render={
(props) => {
return (<NewOrEditTask {...this.props} {...props} {...this.state} />)
@ -679,11 +684,11 @@ class App extends Component {
}
/>
<Route
path="/problems/:id/edit"
path="/problems/:id/edit"
render={
(props) => (<NewOrEditTask {...this.props} {...props} {...this.state} />)
} />
<Route path="/myproblems/record_detail/:id"
<Route path="/myproblems/record_detail/:id"
render={
(props) => (<RecordDetail {...this.props} {...props} {...this.state} />)
}
@ -697,13 +702,17 @@ class App extends Component {
(props) => (<Developer {...this.props} {...props} {...this.state} />)
}/>
<Route path="/jupytertpi"
component={JupyterTPI}
/>
<Route exact path="/"
// component={ShixunsHome}
render={
(props)=>(<ShixunsHome {...this.props} {...props} {...this.state}></ShixunsHome>)
}
/>
<Route component={Shixunnopage}/>
<Route component={Shixunnopage}/>
</Switch>
</Router>
@ -825,4 +834,4 @@ moment.defineLocale('zh-cn', {
doy: 4 // The week that contains Jan 4th is the first week of the year.
}
});
export default SnackbarHOC()(App) ;
export default SnackbarHOC()(App) ;

@ -13,10 +13,10 @@ function locationurl(list){
if (window.location.port === "3007") {
} else {
window.location.replace(list)
window.location.href(list)
}
}
let hashTimeout
let hashTimeout
// TODO 开发期多个身份切换
let debugType =""
@ -224,7 +224,7 @@ export function initAxiosInterceptors(props) {
return Promise.reject(error);
});
// -----------------------------------------------------------------------------------
}

@ -1,8 +1,8 @@
export function isDev() {
return window.location.port === "3007";
}
// const isMobile
export const isMobile = (/android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(navigator.userAgent.toLowerCase()));
// const isWeiXin = (/MicroMessenger/i.test(navigator.userAgent.toLowerCase()));
export function isDev() {
return window.location.port === "3007";
}
// const isMobile
export const isMobile = (/android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(navigator.userAgent.toLowerCase()));
// const isWeiXin = (/MicroMessenger/i.test(navigator.userAgent.toLowerCase()));

@ -85,4 +85,4 @@ export function htmlEncode(str) {
s = s.replace(/\'/g, "&#39;");//IE下不支持实体名称
s = s.replace(/\"/g, "&quot;");
return s;
}
}

@ -0,0 +1,15 @@
/*
* @Description: 引入阿里图标库
* @Author: tangjiang
* @Github:
* @Date: 2019-12-10 09:03:48
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-10 09:05:41
*/
import { Icon } from 'antd';
const MyIcon = Icon.createFromIconfontCN({
scriptUrl: '//at.alicdn.com/t/font_1535266_ss6796i6f6j.js'
});
export default MyIcon;

@ -41,17 +41,17 @@ const styles = MUIDialogStyleUtil.getTwoButtonStyle()
// 主题自定义
const theme = createMuiTheme({
palette: {
primary: {
primary: {
main: '#4CACFF',
contrastText: 'rgba(255, 255, 255, 0.87)'
},
},
secondary: { main: '#4CACFF' }, // This is just green.A700 as hex.
},
});
const testSetsExpandedArrayInitVal = [false, false, false, false, false,
false, false, false, false, false,
false, false, false, false, false,
const testSetsExpandedArrayInitVal = [false, false, false, false, false,
false, false, false, false, false,
false, false, false, false, false,
false, false, false, false, false]
window.__fetchAllFlag = false; // 是否调用过fetchAll TODO 如何多次使用provider
@ -70,7 +70,7 @@ class TPIContextProvider extends Component {
this.readGameAnswer = this.readGameAnswer.bind(this)
this.praisePlus = this.praisePlus.bind(this)
this.onGamePassed = this.onGamePassed.bind(this)
this.onPathChange = this.onPathChange.bind(this)
@ -80,7 +80,7 @@ class TPIContextProvider extends Component {
this.onShowUpdateDialog = this.onShowUpdateDialog.bind(this)
this.updateDialogClose = this.updateDialogClose.bind(this)
// this.showEffectDisplay();
this.state = {
@ -142,7 +142,7 @@ class TPIContextProvider extends Component {
// request
// var shixunId = this.props.match.params.shixunId;
var stageId = this.props.match.params.stageId;
window.__fetchAllFlag = false;
this.fetchAll(stageId);
this.costTimeInterval = window.setInterval(()=> {
@ -192,7 +192,7 @@ class TPIContextProvider extends Component {
onGamePassed(passed) {
const { game } = this.state
// 随便给个分以免重新评测时又出现评星组件注意目前game.star没有显示在界面上如果有则不能这么做
// game.star = 6;
// game.star = 6;
this.setState({
game: update(game, {star: { $set: 6 }}),
currentGamePassed: !!passed
@ -253,14 +253,14 @@ pop_box_new(htmlvalue, 480, 182);
const { praise_count, praise } = response.data;
// challenge.praise_count = praise_tread_count;
// challenge.user_praise = praise;
this.setState({ challenge: update(challenge,
this.setState({ challenge: update(challenge,
{
praise_count: { $set: praise_count },
user_praise: { $set: praise },
})
})
}
})
.catch(function (error) {
console.log(error);
@ -286,11 +286,11 @@ pop_box_new(htmlvalue, 480, 182);
}
const { myshixun } = this.state;
// myshixun.system_tip = false;
challenge.path = path;
const newChallenge = this.handleChallengePath(challenge);
this.setState({ challenge: newChallenge,
this.setState({ challenge: newChallenge,
myshixun: update(myshixun, {system_tip: { $set: false }}),
})
}
@ -313,7 +313,7 @@ pop_box_new(htmlvalue, 480, 182);
newResData2OldResData(newResData) {
newResData.latest_output = newResData.last_compile_output
// newResData.power
// newResData.power
newResData.record = newResData.record_onsume_time
// 老版用的hide_code
@ -329,7 +329,7 @@ pop_box_new(htmlvalue, 480, 182);
newResData.output_sets.test_sets = newResData.test_sets // JSON.stringify()
newResData.output_sets.test_sets_count = newResData.test_sets_count
// newResData.output_sets.had_passed_testsests_error_count = newResData.sets_error_count
newResData.output_sets.had_passed_testsests_error_count = newResData.test_sets_count
newResData.output_sets.had_passed_testsests_error_count = newResData.test_sets_count
- newResData.sets_error_count
// allowed_hidden_testset
// sets_error_count
@ -354,8 +354,8 @@ pop_box_new(htmlvalue, 480, 182);
let output_sets = resData.output_sets;
if (resData.st === 0) { // 代码题
challenge = this.handleChallengePath(challenge)
const mirror_name = (resData.mirror_name && resData.mirror_name.join)
const mirror_name = (resData.mirror_name && resData.mirror_name.join)
? resData.mirror_name.join(';') : (resData.mirror_name || '');
if (mirror_name.indexOf('Html') !== -1) {
challenge.isHtml = true;
@ -364,7 +364,7 @@ pop_box_new(htmlvalue, 480, 182);
challenge.isWeb = true;
} else if (mirror_name.indexOf('Android') !== -1) {
challenge.isAndroid = true;
}
}
if (output_sets && output_sets.test_sets && typeof output_sets.test_sets == 'string') {
const test_sets_array = JSON.parse("[" + output_sets.test_sets + "]");
@ -378,7 +378,7 @@ pop_box_new(htmlvalue, 480, 182);
const $ = window.$
window.setTimeout(()=>{
var lens = $("#choiceRepositoryView textarea").length;
for(var i = 1; i <= lens; i++){
window.editormd.markdownToHTML("choose_subject_" + i, {
htmlDecode: "style,script,iframe", // you can filter tags decode
@ -404,14 +404,14 @@ pop_box_new(htmlvalue, 480, 182);
game.isPassThrough = true
}
resData.game = game;
const { tpm_cases_modified, tpm_modified, tpm_script_modified, myshixun } = resData;
if (myshixun.system_tip) {
// system_tip为true的时候 不弹框提示用户更新
resData.showUpdateDialog = false
} else {
let needUpdateScript = (tpm_modified || tpm_script_modified) && challenge.st === 0;
resData.showUpdateDialog = needUpdateScript || tpm_cases_modified
resData.showUpdateDialog = needUpdateScript || tpm_cases_modified
}
/**
@ -458,7 +458,7 @@ pop_box_new(htmlvalue, 480, 182);
// const EDU_NORMAL = 7 // 普通用户
/**
/**
EDU_ADMIN = 1 # 超级管理员
EDU_BUSINESS = 2 # 运营人员
EDU_SHIXUN_MANAGER = 3 # 实训管理员
@ -467,7 +467,7 @@ pop_box_new(htmlvalue, 480, 182);
EDU_GAME_MANAGER = 6 # TPI的创建者
EDU_TEACHER = 7 # 平台老师,但是未认证
EDU_NORMAL = 8 # 普通用户
*/
*/
// myshixun_manager power is_teacher
resData.power = 0
@ -495,8 +495,8 @@ pop_box_new(htmlvalue, 480, 182);
} else if (resData.user.identity === EDU_TEACHER) {
// resData.is_teacher = true
} else if (resData.user.identity === EDU_NORMAL) {
}
}
return resData
}
@ -524,7 +524,7 @@ pop_box_new(htmlvalue, 480, 182);
loading: true,
currentGamePassed: false, // 切换game时重置passed字段
})
// test
// var data = {"st":0,"discusses_count":0,"game_count":3,"record_onsume_time":0.36,"prev_game":null,"next_game":"7p9xwo2hklqv","praise_count":0,"user_praise":false,"time_limit":20,"tomcat_url":"http://47.96.157.89","is_teacher":false,"myshixun_manager":true,"game":{"id":2192828,"myshixun_id":580911,"user_id":57844,"created_at":"2019-09-03T15:50:49.000+08:00","updated_at":"2019-09-03T15:51:05.000+08:00","status":2,"final_score":0,"challenge_id":10010,"open_time":"2019-09-03T15:50:49.000+08:00","identifier":"hknvz4oaw825","answer_open":0,"end_time":"2019-09-03T15:51:04.000+08:00","retry_status":0,"resubmit_identifier":null,"test_sets_view":false,"picture_path":null,"accuracy":1.0,"modify_time":"2019-09-03T15:23:33.000+08:00","star":0,"cost_time":14,"evaluate_count":1,"answer_deduction":0},"challenge":{"id":10010,"shixun_id":3516,"subject":"1.1 列表操作","position":1,"task_pass":"[TOC]\n\n---\n\n####任务描述\n\n\n数据集a包含1-10共10个整数请以a为输入数据编写python程序实现如下功能\n①\t用2种方法输出a中所有奇数\n②\t输出大于3小于7的偶数\n③\t用2种方法输出[1,2,3,…10,11,…20]\n④\t输出a的最大值、最小值。\n⑤\t用2种方法输出[10,9,…2,1]\n⑥\t输出[1,2,3,1,2,3,1,2,3,1,2,3]\n\n\n####相关知识\n\n\n请自行学习相关知识\n\n\n---\n开始你的任务吧祝你成功","score":100,"path":"1-1-stu.py","st":0,"web_route":null,"modify_time":"2019-09-03T15:23:33.000+08:00","exec_time":20,"praises_count":0},"shixun":{"id":3516,"name":"作业1——Python程序设计","user_id":77620,"gpid":null,"visits":23,"created_at":"2019-09-03T14:18:17.000+08:00","updated_at":"2019-09-03T15:58:16.000+08:00","status":0,"language":null,"authentication":false,"identifier":"6lzjig58","trainee":1,"major_id":null,"webssh":2,"homepage_show":false,"hidden":false,"fork_from":null,"can_copy":true,"modify_time":"2019-09-03T14:18:17.000+08:00","reset_time":"2019-09-03T14:18:17.000+08:00","publish_time":null,"closer_id":null,"end_time":null,"git_url":null,"vnc":null,"myshixuns_count":3,"challenges_count":3,"use_scope":0,"mirror_script_id":20,"image_text":null,"code_hidden":false,"task_pass":true,"exec_time":20,"test_set_permission":true,"sigle_training":false,"hide_code":false,"multi_webssh":false,"excute_time":null,"repo_name":"p09218567/6lzjig58","averge_star":5.0,"opening_time":null,"users_count":1,"forbid_copy":false,"pod_life":0},"myshixun":{"id":580911,"shixun_id":3516,"is_public":true,"user_id":57844,"gpid":null,"created_at":"2019-09-03T15:50:49.000+08:00","updated_at":"2019-09-03T15:59:04.000+08:00","status":0,"identifier":"k36hm4rwav","commit_id":"f25e1713882156480fc45ce0af57eff395a5037f","modify_time":"2019-09-03T14:18:17.000+08:00","reset_time":"2019-09-03T14:18:17.000+08:00","system_tip":false,"git_url":null,"onclick_time":"2019-09-03T15:50:49.000+08:00","repo_name":"p53276410/k36hm4rwav20190903155049"},"user":{"user_id":57844,"login":"p53276410","name":"文振乾","grade":24624,"identity":1,"image_url":"avatars/User/57844","school":"EduCoder团队"},"tpm_modified":true,"tpm_cases_modified":false,"mirror_name":["Python3.6"],"has_answer":false,"test_sets":[{"is_public":true,"result":true,"input":"","output":"result of a:\n[1, 3, 5, 7, 9]\n[1, 3, 5, 7, 9]\nresult of b:\n[2, 4, 6, 8, 10]\nresult of c:\n[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]\n[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]\nresult of d:\nThe minimum is:1\nThe maxium is:10\nresult of e:\n[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]\n[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\nresult of f:\n[10, 9, 8, 10, 9, 8, 10, 9, 8, 10, 9, 8]\n","actual_output":"result of a:\r\n[1, 3, 5, 7, 9]\r\n[1, 3, 5, 7, 9]\r\nresult of b:\r\n[2, 4, 6, 8, 10]\r\nresult of c:\r\n[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]\r\n[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]\r\nresult of d:\r\nThe minimum is:1\r\nThe maxium is:10\r\nresult of e:\r\n[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]\r\n[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\r\nresult of f:\r\n[10, 9, 8, 10, 9, 8, 10, 9, 8, 10, 9, 8]\r\n","compile_success":1,"ts_time":0.05,"ts_mem":8.77}],"allowed_unlock":true,"last_compile_output":"compile successfully","test_sets_count":1,"sets_error_count":0}
// data.test_sets[0].actual_output = data.test_sets[0].actual_output.replace(/\r\n/g, '\n')
@ -534,7 +534,7 @@ pop_box_new(htmlvalue, 480, 182);
// data.vnc_url= "http://47.96.157.89:41158/vnc_lite.html?password=headless"
// this._handleResponseData(data)
// return
// return
axios.get(url, {
// https://stackoverflow.com/questions/48861290/the-value-of-the-access-control-allow-origin-header-in-the-response-must-not-b
@ -550,7 +550,7 @@ pop_box_new(htmlvalue, 480, 182);
return;
}
if (response.data.status == 404) {
// 如果第一次发生404则隔1s后再调用一次本接口因为ucloud主从同步可能有延迟
// 如果第一次发生404则隔1s后再调用一次本接口因为ucloud主从同步可能有延迟
if (!noTimeout) {
setTimeout(() => {
this.fetchAll(stageId, true)
@ -562,12 +562,12 @@ pop_box_new(htmlvalue, 480, 182);
}
this._handleResponseData(response.data)
})
.catch(function (error) {
console.log(error);
});
}
readGameAnswer(resData) {
@ -583,7 +583,7 @@ pop_box_new(htmlvalue, 480, 182);
grade: resData.grade
})
}
}
closeTaskResultLayer() {
this.setState({
@ -605,7 +605,7 @@ pop_box_new(htmlvalue, 480, 182);
currentGamePassed = true;
this._updateCostTime(true, true);
}
this.setState({
@ -618,14 +618,14 @@ pop_box_new(htmlvalue, 480, 182);
currentPassedGameGainGold: gold,
currentPassedGameGainExperience: experience,
})
}
}
initDisplayInterval = () => {
const challenge = this.state.challenge
if (this.showWebDisplayButtonTimeout) {
window.clearTimeout(this.showWebDisplayButtonTimeout)
}
this.showWebDisplayButtonTimeout = window.setTimeout(() => {
this.setState({ challenge: update(challenge,
this.setState({ challenge: update(challenge,
{
showWebDisplayButton: { $set: false },
})
@ -650,7 +650,7 @@ pop_box_new(htmlvalue, 480, 182);
this.displayInterval = null
return;
}
remain -= 1;
}, 1000)
}
@ -716,7 +716,7 @@ pop_box_new(htmlvalue, 480, 182);
const currentGamePassed = this.props.game !== 2 && status === 2
// 评测通过了立即同步costTime
currentGamePassed && this._updateCostTime(true, true);
@ -738,7 +738,7 @@ pop_box_new(htmlvalue, 480, 182);
// const test_sets_array = JSON.parse("[" + output_sets.test_sets + "]");
// output_sets.test_sets_array = test_sets_array;
// }
// 检查是否编译通过
let compileSuccess = false;
if (test_sets && test_sets.length) {
@ -754,7 +754,7 @@ pop_box_new(htmlvalue, 480, 182);
if (currentGamePassed) {
game.status = 2;
// game.isPassThrough = true
game.next_game = next_game;
game.next_game = next_game;
} else {
this.showDialog({
contentText: <div>
@ -764,7 +764,7 @@ pop_box_new(htmlvalue, 480, 182);
isSingleButton: true
})
}
this.setState({
testSetsExpandedArray: testSetsExpandedArrayInitVal.slice(0), // 重置测试集展开状态
@ -775,12 +775,12 @@ pop_box_new(htmlvalue, 480, 182);
output_sets,
game,
next_game,
latest_output: last_compile_output,
record: record_consume_time,
grade,
had_done,
})
}
resetTestSetsExpandedArray = () => {
@ -809,15 +809,15 @@ pop_box_new(htmlvalue, 480, 182);
output_sets = Object.assign({}, output_sets);
// const test_sets_array = JSON.parse("[" + response.data.test_sets + "]");
output_sets.test_sets_array = response.data.test_sets;
this.setState({
this.setState({
output_sets: output_sets,
grade: this.state.grade + deltaScore,
game : update(game, {test_sets_view: { $set: true }}),
testSetsExpandedArray: testSetsExpandedArrayInitVal.slice(0)
game : update(game, {test_sets_view: { $set: true }}),
testSetsExpandedArray: testSetsExpandedArrayInitVal.slice(0)
})
this.handleGdialogClose();
}
})
.catch(function (error) {
console.log(error);
@ -841,10 +841,10 @@ pop_box_new(htmlvalue, 480, 182);
})
}
/*
/*
TODO 写成HOC组件更好复用
全局的Dialog this.props.showDialog调用即可
@param contentText dialog显示的提示文本
@param contentText dialog显示的提示文本
@param callback 确定按钮回调方法
@param moreButtonsRender 除了确定取消按钮外的其他按钮
@param okButtonText 确定按钮显示文本 继续查看
@ -908,13 +908,13 @@ pop_box_new(htmlvalue, 480, 182);
match: this.props.match
}}
>
>
<Dialog
id="tpi-dialog"
open={this.state.gDialogOpen}
disableEscapeKeyDown={true}
onClose={() => this.handleGdialogClose()}
>
>
<DialogTitle id="alert-dialog-title">{"提示"}</DialogTitle>
<DialogContent id="dialog-content">
<DialogContentText id="alert-dialog-description" style={{textAlign: 'center'}}>
@ -930,7 +930,7 @@ pop_box_new(htmlvalue, 480, 182);
>知道啦</a>
</div> :
<React.Fragment>
<Button onClick={() => this.handleGdialogClose()} color="primary"
<Button onClick={() => this.handleGdialogClose()} color="primary"
className={`${classes.button} ${classes.buttonGray} ${classes.borderRadiusNone}`}>
关闭
</Button>
@ -938,7 +938,7 @@ pop_box_new(htmlvalue, 480, 182);
onClick={() => this.onGdialogOkBtnClick() } color="primary" autoFocus>
{ this.okButtonText ? this.okButtonText : '确定' }
</Button>
</React.Fragment> }
</React.Fragment> }
{this.moreButtonsRender && this.moreButtonsRender()}
</DialogActions>
</Dialog>

@ -756,7 +756,7 @@ class Fileslists extends Component{
Savesname={this.state.Savesname}
Cancel={this.state.Cancel}
Saves={this.state.Saves}
course_groups={this.state.course_groups}
// course_groups={this.state.course_groups}
/>:""}
{/*发送*/}

@ -428,6 +428,9 @@ class NewShixunModel extends Component{
.ant-drawer-body {
padding:15px 24px 24px 0px;
}
.ant-dropdown {
z-index:11000
}
`
}
</style>
@ -536,6 +539,21 @@ class NewShixunModel extends Component{
className="fl task-hide edu-txt-left mt3"
name="shixun_homework[]"
></Checkbox>
{
this.props.type==='shixuns'?
(
item.is_jupyter===true?
<div className="myysljupyter fl ml15 mt3 intermediatecenter">
<p className="myysljupytertest">
Jupyter
</p>
</div>
:""
)
:""
}
<a target="_blank" href={this.props.type==='shixuns'?`/shixuns/${item.identifier}/challenges`:`/paths/${item.id}`} className="ml15 fl font-16 color-dark maxwidth1100"
dangerouslySetInnerHTML={{__html: item.title}}
>
@ -681,4 +699,4 @@ export default NewShixunModel;
// <span dangerouslySetInnerHTML={{__html: item}}>{}</span>
// )
// })}
// </div>}
// </div>}

@ -384,4 +384,23 @@
.newshixunmodels{
margin: 0 auto;
}
}
.myysljupyter{
width:48px;
height:22px;
background:#FF6802;
border-radius:2px 10px 10px 2px;
}
.myysljupytertest{
width:39px;
height:16px;
font-size:12px;
color:#FFFFFF;
line-height:16px;
}
.intermediatecenter{
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}

@ -492,13 +492,13 @@ class YslDetailCards extends Component{
:<i className="iconfont icon-bofang progressRing-part font-18 mt10"></i>
}
</span>
<span className={this.props.current_user&&this.props.current_user.admin===false&&line.shixun_status==="暂未公开"?"paragraph_name color204":"paragraph_name color-grey3"}>
<span className={this.props.current_user&&this.props.current_user.admin===false&&this.props.current_user&&this.props.current_user.business===false&&line.shixun_status==="暂未公开"?"paragraph_name color204":"paragraph_name color-grey3"}>
<span className="subject_stage_shixun_index">{key+1}</span>-{index+1}&nbsp;&nbsp;{line.shixun_name}
</span>
</li>
{
this.props.current_user&&this.props.current_user.admin===false&&line.shixun_status==="暂未公开"?
this.props.current_user&&this.props.current_user.admin===false&&this.props.current_user&&this.props.current_user.business===false&&line.shixun_status==="暂未公开"?
<li className="fr status_li"><span className="fr color204">暂未公开</span></li>
:
<li className={showparagraph===false?"none":"fr status_li"}>
@ -512,7 +512,7 @@ class YslDetailCards extends Component{
</li>
}
{this.props.current_user&&this.props.current_user.admin===false&&line.shixun_status==="暂未公开"?"": <li className={showparagraph===false?"fr status_li":"fr status_li"}>
{this.props.current_user&&this.props.current_user.admin===false&&this.props.current_user&&this.props.current_user.business===false&&line.shixun_status==="暂未公开"?"": <li className={showparagraph===false?"fr status_li":"fr status_li"}>
{
showparagraphkey === key && showparagraphindex === index ? "" :
<span className="fr color204">实验任务 <span

@ -9,13 +9,15 @@
import './index.scss';
import React from 'react';
import { Table, Button, Dropdown, Icon, Menu, Card, Input, Select, Tag } from 'antd';
import { Table, Button, Dropdown, Icon, Menu, Card, Input, Select, Tag, Modal } from 'antd';
import { connect } from 'react-redux';
import actions from '../../redux/actions';
import MultipTags from './components/multiptags';
import { Link } from 'react-router-dom';
// import { Link } from 'react-router-dom';
import CONST from '../../constants';
import { withRouter } from 'react-router';
import { toStore } from 'educoder';
// import MyIcon from '../../common/components/MyIcon';
const {tagBackground, diffText} = CONST;
const { Search } = Input;
@ -104,14 +106,30 @@ class DeveloperHome extends React.PureComponent {
options = {
title: '操作',
key: 'action',
fixed: 'right',
// fixed: 'right',
width: 100,
render: (text, record) => (
<span>
<Button type="primary" onClick={() => this.handleClickEditor(record.identifier)}>编辑
<React.Fragment>
<Button
shape="circle"
type="primary"
icon="edit"
size="small"
onClick={() => this.handleClickEditor(record.identifier)}
>
{/* <Link to={`/problems/${record.identifier}/edit`}></Link> */}
</Button>
</span>
<Button
shape="circle"
type="danger"
icon="close"
size="small"
style={{ marginLeft: '10px' }}
onClick={() => this.handleClickDelete(record)}
>
{/* <Link to={`/problems/${record.identifier}/edit`}></Link> */}
</Button>
</React.Fragment>
),
}
@ -222,6 +240,22 @@ class DeveloperHome extends React.PureComponent {
this.props.history.push(`/problems/${identifier}/edit`)
}
}
// 删除
handleClickDelete = (record) => {
const { deleteItem } = this.props;
Modal.confirm({
title: '删除',
content: `确定要删除${record.name}吗?`,
okText: '确定',
cancelText: '取消',
onOk () {
// 调用删除接口
console.log(record.identifier);
deleteItem(record.identifier);
}
});
}
// table条件变化时
handleTableChange = (pagination, filters, sorter) => {
const {field, order} = sorter;
@ -374,7 +408,7 @@ class DeveloperHome extends React.PureComponent {
// console.log('name has click', record);
// 先调用start接口获取返回的 identifier, 再跳转到开启编辑
if (this.isLogin()) {
// console.log(record);
toStore('hack_identifier', record.identifier); // 保存当前编辑的id号
this.props.startProgramQuestion(record.identifier, this.props);
}
}
@ -499,7 +533,8 @@ const mapDispatchToProps = (dispatch) => ({
handleClick: () => dispatch(actions.toggleTodo()),
fetchOJList: (params) => dispatch(actions.getOJList(params)),
changePaginationInfo: (obj) => dispatch(actions.changePaginationInfo(obj)),
startProgramQuestion: (id, props) => dispatch(actions.startProgramQuestion(id, props))
startProgramQuestion: (id, props) => dispatch(actions.startProgramQuestion(id, props)),
deleteItem: (identifier) => dispatch(actions.deleteItem(identifier))
});
export default withRouter(connect(

@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-11-27 16:02:36
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-03 09:19:54
* @LastEditTime: 2019-12-10 09:30:27
*/
import './index.scss';
import React, { useState, useRef } from 'react';

@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-11-28 08:44:54
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-03 12:38:27
* @LastEditTime: 2019-12-10 09:24:02
*/
import './index.scss';
import React, { useState, useEffect } from 'react';
@ -19,7 +19,7 @@ function ExecResult (props) {
// 指定渲染初始, 加载中, 加载完成页面内容
const renderInit = () => (
<div className={'excute_result_area excute_flex_center'}>
<span className={'init_ctx'}>先点击调试代码运行您的代码</span>
<span className={'init_ctx'}>填写测试用例的输入值点击调试代码</span>
</div>
);
const renderLoading = () => (

@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-11-27 19:46:14
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-03 09:14:59
* @LastEditTime: 2019-12-10 09:31:00
*/
import './index.scss';
import React, { useState, useEffect, useRef, useImperativeHandle, forwardRef } from 'react';
@ -42,7 +42,6 @@ function InitTabCtx (props, ref) {
<Form className={'user_case_form'}>
<FormItem
className={'input_area flex_l'}
label='输入'
>
{
getFieldDecorator('input', {
@ -50,7 +49,10 @@ function InitTabCtx (props, ref) {
{ required: true, message: '输入值不能为空'}
],
initialValue: inputValue
})(<TextArea rows={5} />)
})(<TextArea
rows={8}
placeholder="请填写测试用例的输入值,点击“调试代码”"
/>)
}
</FormItem>
</Form>

@ -27,7 +27,7 @@ export default class MultipTags extends PureComponent {
<span className={`tag-txt ${type}`}>
{ text }
</span>
<span className={'tag-numb'}>
<span className={`tag-numb ${type}`}>
{ result }
</span>
</div>

@ -5,38 +5,75 @@
.tag-txt, .tag-numb{
display: inline-block;
vertical-align: middle;
padding: 0 10px;
// line-height: 20px;
// height: 20px;
box-sizing: border-box;
font-size: 12px;
text-align: center;
height: 24px;
padding: 0 10px;
}
.tag-txt{
border: 1px solid transparent;
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
color: #fff;
.tag-txt,
.tag-numb{
border: 1px solid transparent;
&.primary{
background: #1890ff;
// background: #28BD8B;
border-color: #28BD8B;
color: #28BD8B;
}
&.warning{
background: #faad14;
// background: #FF9802;
border-color: #FF9802;
color: #FF9802;
}
&.success{
background: #52c41a;
// background: #52c41a;
border-color: #28BD8B;
color: #28BD8B;
}
&.error{
background: #f5222d;
// background: #FF5555;
border-color: #FF5555;
color: #FF5555;
}
}
.tag-txt{
position: relative;
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
// color: #fff;
border-right: none;
&::before {
position: absolute;
content: '';
right: 0;
top: 5px;
bottom:5px;
border-right: 1px solid transparent;
}
&.primary::before{
border-right-color: #28BD8B;
}
&.warning::before{
border-right-color: #FF9802;
}
&.success::before{
border-right-color: #28BD8B;
}
&.error::before{
border-right-color: #FF5555;
}
}
.tag-numb{
border: 1px solid rgba(238, 238, 238, 1);
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
border-left-color: transparent;
margin-left: -1px;
min-width: 40px;
border-left: none;
}
}

@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-11-27 15:02:52
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-06 16:50:54
* @LastEditTime: 2019-12-10 09:20:42
*/
import './index.scss';
import React, { useState, useRef, useEffect } from 'react';
@ -14,6 +14,8 @@ import { connect } from 'react-redux';
import MonacoEditor from '@monaco-editor/react';
import SettingDrawer from '../../components/monacoSetting';
import CONST from '../../../../constants';
import MyIcon from '../../../../common/components/MyIcon';
// import actions from '../../../../redux/actions';
const { fontSetting, opacitySetting } = CONST;
@ -38,7 +40,7 @@ function MyMonacoEditor (props, ref) {
const [theme, setTheme] = useState(() => { // 主题 theme
return fromStore('oj_theme') || 'dark';
});
const [ height, setHeight ] = useState('calc(100% - 112px)');
const [ height, setHeight ] = useState('calc(100% - 56px)');
const editorRef = useRef(null);
useEffect(() => {
@ -48,7 +50,7 @@ function MyMonacoEditor (props, ref) {
}, [props]);
useEffect(() => {
setHeight(showOrHideControl ? 'calc(100% - 382px)' : 'calc(100% - 112px)');
setHeight(showOrHideControl ? 'calc(100% - 382px)' : 'calc(100% - 56px)');
}, [showOrHideControl]);
// 控制侧边栏设置的显示
@ -101,13 +103,19 @@ function MyMonacoEditor (props, ref) {
})
}
const renderRestore = identifier ? (
<MyIcon type="iconzaicizairu" />
) : '';
return (
<React.Fragment>
<div className={"monaco_editor_area"}>
<div className="code_title">
{/* 未保存时 ? '学员初始代码文件' : main.x */}
<span className='flex_strict' style={{ color: '#fff'}}>{identifier ? '' : '学员初始代码文件'}</span>
<span className='flex_strict'>{identifier ? '已保存' : ''}</span>
<span onClick={handleRestoreCode} className="flex_normal">{identifier ? '恢复初始代码' : ''}</span>
<Icon className={'code-icon'} type="setting" onClick={handleShowDrawer}/>
<span onClick={handleRestoreCode} className="flex_normal">{renderRestore}</span>
{/* <Icon className={'code-icon'} type="setting" onClick={handleShowDrawer}/> */}
<MyIcon className='code-icon' type="iconshezhi" onClick={handleShowDrawer}/>
</div>
<MonacoEditor
height={height}

@ -4,7 +4,8 @@
display: flex;
align-items: center;
// justify-content: space-between;
background: #000;
// background: #000;
background: #333333;
color: #fff;
height: 56px;
padding: 0 30px;
@ -19,5 +20,39 @@
.code-icon{
cursor: pointer;
}
.flex_strict,
.flex_normal,
.code-icon{
color: #888;
}
}
}
.setting_drawer{
// .ant-drawer-body{
// // height: calc(100vh - 120px);
// // overflow-y: auto;
// }
.ant-drawer-content{
top: 120px;
bottom: 56px;
height: calc(100vh - 176px);
background: #333333;
color: #fff;
.setting_h2{
color: #fff;
}
select{
color: #fff;
background: #222222;
height: 24px;
// line-height: 24px;
margin-top: 4px;
}
select option{
background: gold;
color: #fff;
}
}
}

@ -0,0 +1,28 @@
/*
* @Description: 用户头像及昵称
* @Author: tangjiang
* @Github:
* @Date: 2019-12-09 17:11:28
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-09 17:36:55
*/
import './index.scss';
import React from 'react';
import { getImageUrl } from 'educoder'
function UserInfo (props) {
const {image_url, name} = props.userInfo;
return (
<div className={'avator_nicker'}>
<img alt="用户头像" className={'student_img'} src={getImageUrl(`images/${image_url}` || 'images/educoder/headNavLogo.png?1526520218')} />
<span className={'student_nicker'}>
{name || ''}
</span>
</div>
);
}
export default UserInfo
export {
UserInfo
};

@ -0,0 +1,25 @@
.avator_nicker{
position: absolute;
color: #fff;
line-height: 65px;
// height: 65px;
.student_img,
.student_nicker{
display: inline-block;
vertical-align: top;
}
.student_nicker{
margin-left: 10px;
}
.student_img{
width: 30px;
height: 30px;
border-radius: 50%;
margin-top: 15px;
}
}

@ -9,10 +9,12 @@ import './index.scss';
import React, { useEffect } from 'react';
import { connect } from 'react-redux';
import SplitPane from 'react-split-pane';// import { Form } from 'antd';
import { Button, Icon } from 'antd';
import { Link } from 'react-router-dom';
import { Button } from 'antd';
import LeftPane from './leftpane';
import RightPane from './rightpane';
import { withRouter } from 'react-router';
import { toStore } from 'educoder';
import UserInfo from '../components/userInfo';
// import RightPane from './rightpane/index';
import actions from '../../../redux/actions';
@ -22,10 +24,15 @@ const NewOrEditTask = (props) => {
handlePublish,
// testCases = [],
// ojTestCaseValidate = [],
// changeSubmitLoadingStatus,
identifier,
isPublish,
userInfo,
submitLoading,
changeSubmitLoadingStatus,
changePublishLoadingStatus,
startProgramQuestion,
getUserInfoForNew,
// updateTestAndValidate,
identifier,
} = props;
// 表单提交
@ -34,12 +41,15 @@ const NewOrEditTask = (props) => {
if (props.identifier) {
props.handleUpdateOjForm(props);
} else {
// 改变loading状态
changeSubmitLoadingStatus(true);
props.handleFormSubmit(props); // 提交表单
}
};
useEffect(() => {
// 获取用户信息
getUserInfoForNew();
// console.log('获取路由参数: ====', props.match.params);
const id = props.match.params.id;
// 保存OJForm的id号指明是编辑还是新增
@ -55,25 +65,101 @@ const NewOrEditTask = (props) => {
return () => {}
}, []);
// 模拟挑战
const startChallenge = () => {
// 调用 start 接口, 成功后跳转到模拟页面
startProgramQuestion(identifier, props);
}
// 取消
const handleClickCancel = () => {
// 清空当前输入值并跳转至列表页
props.clearOJFormStore();
// 清空描述信息
toStore('oj_description', '');
setInterval(function () {
props.history.push('/problems');
}, 500);
}
// 发布
const handleClickPublish = () => {
// console.log('public has click');
changePublishLoadingStatus(true);
handlePublish(props, 'publish');
}
// 取消保存/取消按钮
const renderSaveOrCancel = () => {
return (
<React.Fragment>
<Button
onClick={handleClickCancel}
style={{ background: '#666666', color: '#fff', border: 'none' }}
>取消</Button>
<Button
type="primary"
loading={submitLoading}
onClick={handleSubmitForm}
>保存</Button>
</React.Fragment>
);
}
// 发布/模拟挑战
const renderPubOrFight = () => {
const pubButton = isPublish ? '' : (<Button
type="primary"
loading={publishLoading}
onClick={handleClickPublish}
>立即发布</Button>);
return (
<React.Fragment>
<Button
type="primary"
loading={submitLoading}
onClick={handleSubmitForm}
>更新</Button>
{pubButton}
<Button type="primary" onClick={startChallenge}>模拟挑战</Button>
</React.Fragment>
)
}
// 渲染退出
const renderQuit = () => {
return identifier ? (
<Button type="link"
style={{
position: 'absolute',
right: '10px',
top: '15px',
color: '#5091FF'
}}
onClick={handleClickCancel}
>退出</Button>
) : ''
}
return (
<div className={'new_add_task_wrap'}>
<div className={'task_header'}>
<Link to="/problems" className={'header_btn'} >
{/* <Link to="/problems" className={'header_btn'} >
<Icon type="left" style={{ marginRight: '5px'}}/>后退
</Link>
</Link> */}
<UserInfo userInfo={userInfo}/>
<p className={'header_title'}>{props.name || ''}</p>
<Button
{ renderQuit() }
{/* <Link style={{
position: 'absolute',
right: '30px',
top: 0,
color: '#5091FF'
}} to="/problems">退出</Link> */}
{/* <Button
style={{ display: identifier ? 'none' : 'block'}}
loading={publishLoading}
className={`header_btn`}
type="primary"
onClick={handleClickPublish}>立即发布</Button>
onClick={handleClickPublish}>立即发布</Button> */}
</div>
<div className="split-pane-area">
<SplitPane split="vertical" minSize={350} maxSize={-350} defaultSize="40%">
@ -86,18 +172,30 @@ const NewOrEditTask = (props) => {
</SplitPane>
</SplitPane>
</div>
{/* 控制台 */}
<div className='new_add_task_ctl'>
{
/* 录入时: 取消 保存 */
/* 保存未发布: 立即发布 模拟挑战 */
}
{ !identifier ? renderSaveOrCancel() : renderPubOrFight() }
</div>
</div>
)
}
const mapStateToProps = (state) => {
const { ojForm, identifier, testCases } = state.ojFormReducer;
const { publishLoading } = state.commonReducer;
const { ojForm, identifier, testCases, isPublish } = state.ojFormReducer;
const { publishLoading, submitLoading } = state.commonReducer;
const { userInfo } = state.userReducer;
return {
name: ojForm.name,
identifier,
testCases,
publishLoading
isPublish, // 是否已发布
publishLoading,
submitLoading,
userInfo
}
};
@ -122,9 +220,13 @@ const mapDispatchToProps = (dispatch) => ({
changePublishLoadingStatus: (flag) => dispatch(actions.changePublishLoadingStatus(flag)),
// 测试用例及验证
updateTestAndValidate: (obj) => dispatch(actions.updateTestAndValidate(obj)),
// 开启模拟挑战
startProgramQuestion: (id, props) => dispatch(actions.startProgramQuestion(id, props)),
// 新建时获取信息
getUserInfoForNew: () => dispatch(actions.getUserInfoForNew())
});
export default connect(
export default withRouter(connect(
mapStateToProps,
mapDispatchToProps
)(NewOrEditTask);
)(NewOrEditTask));

@ -1,2 +1,18 @@
@import '../split_pane_resizer.scss';
.new_add_task_wrap {
.split-pane-area{
height: calc(100vh - 121px);
}
}
.new_add_task_ctl{
display: flex;
align-items: center;
justify-content: center;
height: 56px;
background: #333333;
> button{
margin-right: 20px;
}
}

@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-11-21 09:19:38
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-04 15:44:12
* @LastEditTime: 2019-12-10 19:37:35
*/
import './index.scss';
import React, { useState } from 'react';
@ -16,7 +16,7 @@ const { TextArea } = Input;
const FormItem = Form.Item;
const AddTestDemo = (props) => {
const {
key,
// key,
onSubmitTest,
onDeleteTest,
testCase,
@ -158,7 +158,8 @@ const AddTestDemo = (props) => {
help={testCaseValidate.output.errMsg}
colon={ false }
>
<Input
<TextArea
rows={5}
value={testCase.output}
onChange={handleOutputChange}
disabled={isDisabled(testCase)}/>

@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-11-20 10:35:40
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-06 20:20:27
* @LastEditTime: 2019-12-09 10:22:03
*/
import 'quill/dist/quill.core.css';
import 'quill/dist/quill.bubble.css';
@ -236,22 +236,41 @@ class EditTab extends React.Component {
<div className={'editor_area'} id="textCase">
<Form className={'editor_form'}>
<FormItem
className={`input_area flex_60`}
label={<span>{myLabel(jcLabel['name'])}</span>}
validateStatus={ojFormValidate.name.validateStatus}
help={ojFormValidate.name.errMsg}
className={`input_area flex_50 flex_50_left`}
label={<span>{myLabel(jcLabel['difficult'])}</span>}
validateStatus={ojFormValidate.difficult.validateStatus}
help={ojFormValidate.difficult.errMsg}
colon={ false }
>
<Input
maxLength={60}
placeholder="请输入任务名称"
value={ojForm.name}
suffix={<span style={{ fontSize: '12px', color: 'rgba(0, 0, 0, 0.45)' }}>{60 - ojForm.name.length}</span>}
onChange={this.handleNameChange}
/>
<Select onChange={this.handleChangeDifficult} value={`${ojForm.difficult}`}>
{getOptions('difficult')}
</Select>
</FormItem>
<FormItem
className={`input_area flex_40`}
className={`input_area flex_50 flex_50_right`}
label={<span>{myLabel(jcLabel['category'], '合理的分类有利于快速检索')}</span>}
validateStatus={ojFormValidate.category.validateStatus}
help={ojFormValidate.category.errMsg}
colon={ false }
>
<Select onChange={this.handleChangeCategory} value={`${ojForm.category}`}>
{getOptions('category')}
</Select>
</FormItem>
<FormItem
className={`input_area flex_50 flex_50_left`}
label={<span>{myLabel(jcLabel['timeLimit'], '程序允许时间限制时长,单位:秒')}</span>}
validateStatus={ojFormValidate.timeLimit.validateStatus}
help={ojFormValidate.timeLimit.errMsg}
colon={ false }
>
<InputNumber value={ojForm.timeLimit} min={0} style={{ width: '100%' }} onChange={this.handleTimeLimitChange}/>
</FormItem>
<FormItem
className={`input_area flex_50 flex_50_right`}
label={<span>{myLabel(jcLabel['language'])}</span>}
validateStatus={ojFormValidate.language.validateStatus}
help={ojFormValidate.language.errMsg}
@ -261,6 +280,23 @@ class EditTab extends React.Component {
{getOptions('language')}
</Select>
</FormItem>
<FormItem
className={`input_area flex_100`}
label={<span>{myLabel(jcLabel['name'])}</span>}
validateStatus={ojFormValidate.name.validateStatus}
help={ojFormValidate.name.errMsg}
colon={ false }
>
<Input
maxLength={60}
placeholder="请输入任务名称"
value={ojForm.name}
suffix={<span style={{ fontSize: '12px', color: 'rgba(0, 0, 0, 0.45)' }}>{60 - ojForm.name.length}</span>}
onChange={this.handleNameChange}
/>
</FormItem>
<FormItem
className={`input_area flex_100`}
label={<span>{myLabel(jcLabel['description'])}</span>}
@ -276,38 +312,8 @@ class EditTab extends React.Component {
options={quillConfig}
/>
</FormItem>
<FormItem
className={`input_area flex_50 flex_50_left`}
label={<span>{myLabel(jcLabel['difficult'], '任务的难易程度')}</span>}
validateStatus={ojFormValidate.difficult.validateStatus}
help={ojFormValidate.difficult.errMsg}
colon={ false }
>
<Select onChange={this.handleChangeDifficult} value={`${ojForm.difficult}`}>
{getOptions('difficult')}
</Select>
</FormItem>
<FormItem
className={`input_area flex_50 flex_50_right`}
label={<span>{myLabel(jcLabel['timeLimit'], '程序允许时间限制时长,单位:秒')}</span>}
validateStatus={ojFormValidate.timeLimit.validateStatus}
help={ojFormValidate.timeLimit.errMsg}
colon={ false }
>
<InputNumber value={ojForm.timeLimit} min={0} style={{ width: '100%' }} onChange={this.handleTimeLimitChange}/>
</FormItem>
<FormItem
className={`input_area flex_50 flex_50_left`}
label={<span>{myLabel(jcLabel['category'], '任务所属分类')}</span>}
validateStatus={ojFormValidate.category.validateStatus}
help={ojFormValidate.category.errMsg}
colon={ false }
>
<Select onChange={this.handleChangeCategory} value={`${ojForm.category}`}>
{getOptions('category')}
</Select>
</FormItem>
<FormItem
{/* <FormItem
className={`input_area flex_50 flex_50_right`}
label={<span>{myLabel(jcLabel['openOrNot'], '社区:您的任务将向整个社会公开')}</span>}
validateStatus={ojFormValidate.openOrNot.validateStatus}
@ -317,13 +323,13 @@ class EditTab extends React.Component {
<Select onChange={this.handleChangeOpenOrNot} value={`${ojForm.openOrNot}`}>
{getOptions('openOrNot')}
</Select>
</FormItem>
</FormItem> */}
</Form>
{/* 添加测试用例 */}
<div className={'test_demo_title'} ref={this.headerRef}>
<h2>测试用例</h2>
<Button type="primary" onClick={handleAddTest}>添加测试用例</Button>
<Button type="primary" ghost onClick={handleAddTest}>添加测试用例</Button>
</div>
<div className="test_demo_ctx">
{ renderTestCase() }

@ -7,44 +7,84 @@
*/
import './index.scss';
import React, { useState } from 'react';
import { Tabs } from 'antd';
import React, { useState, useMemo } from 'react';
// import { Tabs } from 'antd';
import EditorTab from './editorTab';
import PrevTab from './prevTab';
import CommitTab from './commitTab';
const { TabPane } = Tabs;
// const { TabPane } = Tabs;
function LeftPane (props) {
const navItem = [
{
title: '编辑',
key: 'editor'
}, {
title: '预览',
key: 'prev'
}
];
const Comp = {
editor: (<EditorTab />),
prev: (<PrevTab />)
};
const [defaultActiveKey, setDefaultActiveKey] = useState('editor');
const tabArrs = [
{ title: '编辑', key: 'editor', content: (<EditorTab />) },
{ title: '预览', key: 'prev', content: (<PrevTab />) },
// { title: '提交记录', key: 'commit', content: (<CommitTab />) },
];
// const tabArrs = [
// { title: '编辑', key: 'editor', content: (<EditorTab />) },
// { title: '预览', key: 'prev', content: (<PrevTab />) },
// // { title: '提交记录', key: 'commit', content: (<CommitTab />) },
// ];
const tabs = tabArrs.map((tab) => {
const Comp = tab.content;
return (
<TabPane tab={tab.title} key={tab.key}>
{ Comp }
</TabPane>
)
});
// const tabs = tabArrs.map((tab) => {
// const Comp = tab.content;
// return (
// <TabPane tab={tab.title} key={tab.key}>
// { Comp }
// </TabPane>
// )
// });
// tab切换时
const handleTabChange = (key) => {
setDefaultActiveKey(key);
}
// const handleTabChange = (key) => {
// setDefaultActiveKey(key);
// }
// 执行表单提交函数
const renderComp = useMemo(() => {
return Comp[defaultActiveKey];
}, [defaultActiveKey]);
const renderNavItem = navItem.map((item) => {
const _classes = item.key === defaultActiveKey ? 'add_editor_item active' : 'add_editor_item';
return (
<li
key={item.key}
className={_classes}
onClick={() => setDefaultActiveKey(item.key)}
>
<span className={'item-span'}>{item.title}</span>
</li>
)
});
return (
<Tabs activeKey={defaultActiveKey} onChange={handleTabChange}>
{ tabs }
</Tabs>
// <Tabs activeKey={defaultActiveKey} onChange={handleTabChange}>
// { tabs }
// </Tabs>
<React.Fragment>
<ul className={'add_editor_list_area'}>
{ renderNavItem }
</ul>
<div className="comp_ctx">
{ renderComp }
</div>
</React.Fragment>
)
};

@ -4,21 +4,21 @@
* @Github:
* @Date: 2019-12-01 10:18:35
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-06 17:50:58
* @LastEditTime: 2019-12-09 11:38:15
*/
import './index.scss';
import React from 'react';
import { connect } from 'react-redux';
import MyMonacoEditor from '../../components/myMonacoEditor';
import ControlSetting from '../../components/controlSetting';
// import ControlSetting from '../../components/controlSetting';
import actions from '../../../../redux/actions';
function RightPane (props, ref) {
const {
// identifier,
code,
onSubmitForm,
// code,
// onSubmitForm,
saveOjFormCode
} = props;
@ -48,12 +48,12 @@ function RightPane (props, ref) {
code={props.code}
onCodeChange={handleCodeChange}/>
<ControlSetting
{/* <ControlSetting
// identifier={identifier}
inputValue={props.input}
onSubmitForm={onSubmitForm}
// onDebuggerCode={handleDebuggerCode}
/>
/> */}
</div>
)
}

@ -3,7 +3,7 @@
// justify-content: center;
background-color: #222;
height: 100%;
// justify-content: ;
// height: calc(100vh - 178px);
.code-title,
.controller-pane,
.pane_control_opts{

@ -1,215 +0,0 @@
/*
* @Description: 右侧代码块
* @Author: tangjiang
* @Date: 2019-11-18 08:42:04
* @Last Modified by: tangjiang
* @Last Modified time: 2019-11-20 00:00:34
*/
import './index.scss';
import React, { Fragment, useState, useRef, useEffect } from 'react';
import { Icon, Drawer, Tabs, Button, notification } from 'antd';
import _ from 'lodash';
import MonacoEditor from '@monaco-editor/react';
import { connect } from 'react-redux';
import InitTabCtx from './initTabCtx';
import SettingDrawer from '../../components/monacoSetting';
import CONST from '../../../../constants';
import actions from '../../../../redux/actions';
const { fontSetting, opacitySetting } = CONST;
const { TabPane } = Tabs;
const RightPaneCode = (props) => {
const [showDrawer, setShowDrawer] = useState(false); // 控制配置滑框
const [defaultActiveKey, setDefaultActiveKey] = useState('1'); // 当前选中的tab
const [showTextResult, setShowTextResult] = useState(false); // 是否点击控制台按钮
const [editCode, setEditCode] = useState(()=> {
return '#include <stdio.h>';
}); // monaco编辑器内容
const [language, setLanguage] = useState('C')
const [fontSize,setFontSize] = useState(12);
const editorRef = useRef(null); // 编辑器ref
useEffect(() => {
if (props.language) {
// console.log('当前输入的代码:', editCode);
// console.log('当前输入的语言:', props.language);
setLanguage(props.language)
}
}, [props.language]);
useEffect(() => {
}, [props.testCases]);
useEffect(() => {
}, [editCode]);
// 监听store中编辑器内容变化
useEffect(() => {
setEditCode(props.code);
}, [props.code]);
// 打开设置
const handleShowDrawer = (e) => {
e.preventDefault();
setShowDrawer(true);
}
// 关闭设置
const handleDrawerClose = (e) => {
e.preventDefault();
setShowDrawer(false);
}
// 切换tab
const handleTabChange = (key) => {
setDefaultActiveKey(key);
}
// 显示/隐藏tab
const handleShowControl = () => {
setShowTextResult(!showTextResult);
}
// 侧边栏改变字体大小
const handleFontSizeChange = (value) => {
setFontSize(value);
}
// 文本框内容变化时,记录文本框内容
const handleEditorChange = (origin, monaco) => {
editorRef.current = monaco; // 获取当前monaco实例
setEditCode(origin); // 保存编辑器初始值
editorRef.current.onDidChangeModelContent(e => { // 监听编辑器内容的变化
// TODO 需要优化 节流
const val = editorRef.current.getValue();
setEditCode(val);
// 保存当前代码
props.saveOjFormCode(val);
});
}
// 提交按钮点击
const handleSubmit = (e) => {
e.preventDefault();
if (!editCode) {
notification['error']({
message: '必填',
description: '代码块内容必须输入!'
});
editorRef.current.focus();
return;
}
props.changePublishLoadingStatus(true);
const { onSubmitForm } = props;
onSubmitForm(editCode);
}
// 调试测试代码
// const handleTestCode = () => {
// // 打开控制台信息
// setShowTextResult(true);
// this.formRef.handleTestCodeFormSubmit(() => {
// // 当验证通过后 切换tab 到代码执行结果
// setDefaultActiveKey('2');
// });
// }
// 控制台点击时 添加active属性
const classNames = `control_tab ${showTextResult ? 'move_up move_up_final' : 'move_down_final'}`;
// 配置编辑器属性
const editorOptions = {
selectOnLineNumbers: true,
automaticLayout: true,
fontSize: `${fontSize}px`
}
// 返回渲染值
return (
<Fragment>
<div className={'right_pane_code_wrap'}>
<div className={'code-title'}>
<span></span>
<Icon className={'code-icon'} type="setting" onClick={handleShowDrawer}/>
</div>
{/** 代码编辑器 */}
<MonacoEditor
height={showTextResult ? 'calc(100% - 382px)' : 'calc(100% - 112px)'}
width="100%"
language={language.toLowerCase()}
value={editCode}
options={editorOptions}
theme="dark"
editorDidMount={handleEditorChange}
/>
{/* 控制台信息 */}
<div className="pane_control_area">
<Tabs
className={classNames}
activeKey={defaultActiveKey}
tabBarStyle={{ backgroundColor: '#000', color: '#fff' }}
onChange={handleTabChange}
>
<TabPane tab={'自定义测试用例'} key={'1'} style={{ height: '280px', overflowY: 'auto' }}>
<InitTabCtx wrappedComponentRef={(form) => this.formRef = form }/>
</TabPane>
<TabPane tab={'代码执行结果'} key={'2'} style={{ height: '280px', overflowY: 'auto' }}>
<h2>代码执行结果</h2>
</TabPane>
</Tabs>
<div className="pane_control_opts">
<Button type="link" style={{ color: '#fff' }} onClick={handleShowControl}>控制台 <Icon type={ showTextResult ? "down" : "up" } /></Button>
<p>
{/* <Button ghost
style={{ marginRight: '10px', color: '#28BD8B', borderColor: '#28BD8B' }}
onClick={handleTestCode}
disabled={!props.identifier || props.testCases.length === 0}
>调试代码</Button> */}
<Button
loading={props.submitLoading}
type="primary"
onClick={handleSubmit}
>{props.identifier ? '更新' : '提交'}</Button>
</p>
</div>
</div>
</div>
<Drawer
className={'setting_drawer'}
placement="right"
closable={false}
onClose={handleDrawerClose}
visible={showDrawer}
>
<SettingDrawer {...fontSetting} onChangeFontSize={handleFontSizeChange}/>
<SettingDrawer {...opacitySetting}/>
</Drawer>
</Fragment>
);
}
const mapStateToProps = (state) => {
const { ojForm, testCases, identifier, code } = state.ojFormReducer;
const { submitLoading } = state.commonReducer;
return {
language: ojForm.language,
testCases,
identifier,
code,
submitLoading
}
};
const mapDispatchToProps = (dispatch) => ({
saveOjFormCode: (code) => dispatch(actions.saveOjFormCode(code)),
changePublishLoadingStatus: (flag) => dispatch(actions.changeSubmitLoadingStatus(flag))
});
//
export default connect(
mapStateToProps,
mapDispatchToProps
)(RightPaneCode);

@ -4,13 +4,14 @@
* @Github:
* @Date: 2019-11-25 09:46:03
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-04 23:09:38
* @LastEditTime: 2019-12-10 16:10:23
*/
// import 'quill/dist/quill.core.css';
// import 'quill/dist/quill.bubble.css';
// import 'quill/dist/quill.snow.css';
// import 'katex/dist/katex.css';
import './index.scss';
import 'katex/dist/katex.min.css';
import React from 'react';
import katex from 'katex';
const Quill = require('quill');
@ -120,15 +121,12 @@ class QuillEditor extends React.Component {
render () {
const styles = this.props.style || {}
return (
<div>
<div
id="quill_editor"
style={styles}
className={'quill_editor_area'}
ref={this.editorRef}>
</div>
</div>
<div
id="quill_editor"
style={styles}
className={'quill_editor_area'}
ref={this.editorRef}>
</div>
);
}
}

@ -1,4 +0,0 @@
.quill_editor_area{
height: 300px;
overflow-y: auto;
}

@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-12-04 08:36:21
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-05 13:52:04
* @LastEditTime: 2019-12-10 18:55:02
*/
import './index.scss';
import React, { useState, useEffect } from 'react';
@ -14,23 +14,26 @@ import ErrorResult from '../components/errorResult';
import { Link } from 'react-router-dom';
import MonacoEditor from '@monaco-editor/react';
import { connect } from 'react-redux';
import { getImageUrl } from 'educoder';
// import { getImageUrl } from 'educoder';
import actions from '../../../redux/actions';
import CONST from '../../../constants';
import UserInfo from '../components/userInfo';
const {reviewResult} = CONST;
function RecordDetail (props) {
const {
match: { params },
mygetHelmetapi = {},
recordDetail,
identifier,
getUserCommitRecordDetail
// identifier,
getUserCommitRecordDetail,
saveEditorCodeForDetail
} = props;
const id = params.id;
const [detail, setDetail] = useState({});
const [user, setUser] = useState({});
const [identifier, setIdentifier] = useState('');
useEffect(() => {
// 根据id获取记录详情
@ -40,17 +43,27 @@ function RecordDetail (props) {
useEffect(() => {
setDetail(recordDetail);
console.log('详情: ', recordDetail);
if (recordDetail) {
const { user, myproblem_identifier, code } = recordDetail;
setUser(user);
setIdentifier(myproblem_identifier);
if (code) {
saveEditorCodeForDetail(code);
}
}
}, [recordDetail]);
return (
<div className="record_detail_area">
<div className="record_detail_header">
<div className="avator_nicker">
<img alt="用户头像" className={'student_img'} src={getImageUrl((mygetHelmetapi && mygetHelmetapi.nav_logo_url) || 'images/educoder/headNavLogo.png?1526520218')} />
{/* <div className="avator_nicker">
<img alt="用户头像" className={'student_img'} src={getImageUrl( (user && `images/${user.image_url}`)|| 'images/educoder/headNavLogo.png?1526520218')} />
<span className={'student_nicker'}>
{(mygetHelmetapi &&mygetHelmetapi.name) || ''}
{(user && user.name) || ''}
</span>
</div>
</div> */}
<UserInfo userInfo={user || {}}/>
<div className={'study_name'}>
<span>{detail.name || 'test'}</span>
</div>
@ -82,7 +95,13 @@ function RecordDetail (props) {
</div>
<div className="detail_ctx_header">
<h2 className="header_h2">提交内容</h2>
<Button className={'header_btn'} type="primary">编辑代码</Button>
<Button
className={'header_btn'}
type="primary"
>
{/* 编辑代码 */}
<Link to={`/myproblems/${identifier}`}>编辑代码</Link>
</Button>
</div>
<div className="result_code_area">
<MonacoEditor
@ -100,15 +119,16 @@ function RecordDetail (props) {
}
const mapStateToProps = (state) => {
const {recordDetail, user_program_identifier} = state.ojForUserReducer;
const {recordDetail} = state.ojForUserReducer;
return {
identifier: user_program_identifier,
// identifier: user_program_identifier,
recordDetail
}
}
const mapDispatchToProps = (dispatch) => ({
// 根据id号获取记录详情
getUserCommitRecordDetail: (id, type) => dispatch(actions.getUserCommitRecordDetail(id, type))
getUserCommitRecordDetail: (id, type) => dispatch(actions.getUserCommitRecordDetail(id, type)),
saveEditorCodeForDetail: (code) => dispatch(actions.saveEditorCodeForDetail(code))
});
export default connect(

@ -7,7 +7,8 @@
.student_study_header,
.record_detail_header{
height: 65px;
background:rgba(34,34,34,1);
// background:rgba(34,34,34,1);
background: #1E1E1E;
padding:0 30px;
}
@ -45,11 +46,6 @@
.pane_right_area
{
position: relative;
height: calc(100% - 65px);
.left_pane,
.right_pane{
height: 100%;
}
}
.student_study_header,
@ -89,6 +85,41 @@
}
}
.add_editor_list_area{
background: #fff;
padding: 0 30px;
margin: 0;
.add_editor_item{
display: inline-block;
height: 56px;
line-height: 56px;
box-sizing: border-box;
margin-right: 30px;
border-bottom: 2px solid transparent;
transition: all .3s;
cursor: pointer;
.item-span{
color: #666;
font-size: 16px;
}
// > span{
// cursor: pointer;
// }
&.active{
border-bottom-color: #5091FF;
.item-span{
color: #5091FF;
}
}
}
}
.comp_ctx{
height: calc(100vh - 178px);
overflow-y: hidden;
}
.split-pane-area,
.split-pane-left{
.ant-tabs-nav-wrap{
@ -109,9 +140,8 @@
.editor_area,
.prev_area{
height: calc(100vh - 110px);
height: 100%;
overflow-y: auto;
// padding: 20px 0;
}
}

@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-11-23 10:53:19
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-06 18:59:22
* @LastEditTime: 2019-12-10 19:16:18
*/
import './index.scss';
import React, { useEffect } from 'react';
@ -12,22 +12,26 @@ import { connect } from 'react-redux';
import SplitPane from 'react-split-pane';
import LeftPane from './leftpane';
import RightPane from './rightpane';
import { Link } from 'react-router-dom';
import { getImageUrl } from 'educoder'
// import { Link } from 'react-router-dom';
// import { getImageUrl } from 'educoder'
// import RightPane from '../newOrEditTask/rightpane';
import { Button } from 'antd';
import { Icon } from 'antd';
import UserInfo from '../components/userInfo';
import actions from '../../../redux/actions';
import { fromStore} from 'educoder';
import { withRouter } from 'react-router';
const StudentStudy = (props) => {
const {
mygetHelmetapi = {}
userInfo,
hack_identifier
} = props;
useEffect(() => {
const {
match: { params },
getUserProgramDetail,
saveUserProgramIdentifier,
saveUserProgramIdentifier
} = props;
let { id } = params;
@ -37,22 +41,48 @@ const StudentStudy = (props) => {
// startProgramQuestion(id);
getUserProgramDetail(id);
}, []);
const _hack_id = hack_identifier || fromStore('hack_identifier');
// 处理编辑
const handleClickEditor = () => {
props.saveEditorCodeForDetail();
props.history.push(`/problems/${_hack_id}/edit`);
}
// 处理退出
const handleClickQuit = () => {
props.saveEditorCodeForDetail();
props.history.push('/problems');
}
return (
<div className={'student_study_warp'}>
<div className={'student_study_header'}>
<div className={'avator_nicker'}>
{/* <div className={'avator_nicker'}>
<img alt="用户头像" className={'student_img'} src={getImageUrl((mygetHelmetapi && mygetHelmetapi.nav_logo_url) || 'images/educoder/headNavLogo.png?1526520218')} />
<span className={'student_nicker'}>
{(mygetHelmetapi &&mygetHelmetapi.name) || ''}
</span>
</div>
</div> */}
<UserInfo userInfo={userInfo}/>
<div className={'study_name'}>
<span>乘积最大序列</span>
</div>
<div className={'study_quit'}>
<Button>
<Link to="/problems">退出</Link>
{/* to={`/problems/${_hack_id}/edit`} */}
<span onClick={handleClickEditor} className="quit-btn">
<Icon type="form" className="quit-icon"/> 编辑
</span>
{/* to="/problems" */}
<span onClick={handleClickQuit} className="quit-btn">
<Icon type="poweroff" className="quit-icon"/> 退出
</span>
{/* <Button type="link" icon="form" className='quit-btn'>
<Link to="/problems">编辑</Link>
</Button>
<Button type="link" icon="poweroff" className='quit-btn'>
<Link to="/problems">退出</Link>
</Button> */}
</div>
</div>
<div className="split-pane-area">
@ -70,19 +100,27 @@ const StudentStudy = (props) => {
)
}
const mapStateToProps = (state) => ({});
const mapStateToProps = (state) => {
const { userInfo } = state.userReducer;
const { hack_identifier } = state.ojForUserReducer;
return {
userInfo,
hack_identifier
};
};
const mapDispatchToProps = (dispatch) => ({
// 调用开启编辑
// startProgramQuestion: (id) => dispatch(actions.startProgramQuestion(id))
// 调用编程题详情
getUserProgramDetail: (id) => dispatch(actions.getUserProgramDetail(id)),
saveUserProgramIdentifier: (id) => dispatch(actions.saveUserProgramIdentifier(id))
saveUserProgramIdentifier: (id) => dispatch(actions.saveUserProgramIdentifier(id)),
saveEditorCodeForDetail: (code) => dispatch(actions.saveEditorCodeForDetail(code))
});
export default connect(
export default withRouter(connect(
mapStateToProps,
mapDispatchToProps
)(StudentStudy);
)(StudentStudy));

@ -1,4 +1,7 @@
@import '../split_pane_resizer.scss';
.split-pane-area{
height: calc(100vh - 65px);
}
.right_pane_code_wrap{
position: relative;

@ -1,5 +1,6 @@
.commit_record_area{
padding: 20px 30px;
// padding: 20px 30px;
padding: 0 30px;
.record_header{
display: flex;
// justify-content: space-between;

@ -4,10 +4,10 @@
* @Github:
* @Date: 2019-11-23 11:33:41
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-03 14:13:19
* @LastEditTime: 2019-12-09 19:57:21
// */
import './index.scss';
import React, { useState, useEffect } from 'react';
import React, { useState, useEffect, useMemo } from 'react';
import { Tabs, Divider } from 'antd';
import { connect } from 'react-redux';
import Comment from './comment';
@ -15,13 +15,14 @@ import CommitRecord from './commitRecord';
import TaskDescription from './taskDescription';
import TextNumber from './../../components/textNumber';
import actions from '../../../../redux/actions';
const { TabPane } = Tabs;
// const { TabPane } = Tabs;
const LeftPane = (props) => {
const { hack, userCodeTab, changeUserCodeTab } = props;
const { pass_count, submit_count } = hack;
const [defaultActiveKey, setDefaultActiveKey] = useState('task');
console.log(pass_count, submit_count);
const tabArrs = [
{ title: '任务描述', key: 'task', content: (<TaskDescription />) },
@ -29,25 +30,58 @@ const LeftPane = (props) => {
// { title: '评论', key: 'comment', content: (<Comment />) },
];
const navItem = [
{
title: '任务描述',
key: 'task'
},
{
title: '提交记录',
key: 'record'
}
];
const Comp = {
task: (<TaskDescription />),
record: (<CommitRecord />)
};
useEffect(() => {
setDefaultActiveKey(userCodeTab);
}, [userCodeTab])
const tabs = tabArrs.map((tab) => {
const Comp = tab.content;
// const tabs = tabArrs.map((tab) => {
// const Comp = tab.content;
// return (
// <TabPane tab={tab.title} key={tab.key}>
// { Comp }
// </TabPane>
// )
// });
// // tab切换时
// const handleTabChange = (key) => {
// // setDefaultActiveKey(key);
// changeUserCodeTab(key);
// }
const renderComp = useMemo(() => {
return Comp[defaultActiveKey];
}, [defaultActiveKey]);
const renderNavItem = navItem.map((item) => {
const _classes = item.key === defaultActiveKey ? 'add_editor_item active' : 'add_editor_item';
return (
<TabPane tab={tab.title} key={tab.key}>
{ Comp }
</TabPane>
<li
key={item.key}
className={_classes}
onClick={() => setDefaultActiveKey(item.key)}
>
<span className={'item-span'}>{item.title}</span>
</li>
)
});
// tab切换时
const handleTabChange = (key) => {
// setDefaultActiveKey(key);
changeUserCodeTab(key);
}
// 点击消息
const handleClickMessage = () => {
console.log('点击的消息图标---------');
@ -65,9 +99,27 @@ const LeftPane = (props) => {
return (
<React.Fragment>
<Tabs className={'user_code_tab_area'} activeKey={defaultActiveKey} onChange={handleTabChange}>
{/* <Tabs className={'user_code_tab_area'} activeKey={defaultActiveKey} onChange={handleTabChange}>
{ tabs }
</Tabs>
<div className={'number_area'}>
<div className="number_flex flex_count">
<TextNumber text="通过次数" number={pass_count} position="vertical"/>
<Divider type="vertical" style={{ height: '20px', margin: '10px 20px' }}/>
<TextNumber text="提交次数" number={submit_count} position="vertical"/>
</div>
<div className="number_flex flex_info">
<TextNumber text="message" number={4235} type="icon" onIconClick={handleClickMessage}/>
<TextNumber text="like" number={4235} type="icon" onIconClick={handleClickLike}/>
<TextNumber text="dislike" type="icon" onIconClick={handleClickDisLike}/>
</div>
</div> */}
<ul className={'add_editor_list_area'}>
{ renderNavItem }
</ul>
<div className="comp_ctx">
{ renderComp }
</div>
<div className={'number_area'}>
<div className="number_flex flex_count">
<TextNumber text="通过次数" number={pass_count} position="vertical"/>

@ -15,7 +15,8 @@
width: 100%;
// background: pink;
padding: 0 30px;
background-color: rgba(250,250,250,1);
// background-color: rgba(250,250,250,1);
background: #fff;
.flex_count,
.flex_info{
@ -28,18 +29,23 @@
}
}
.task_description_area,
.commit_record_area{
padding: 0 30px;
height: calc(100vh - 166px);
overflow-y: auto;
// height: calc(100vh - 178px);
// overflow-y: auto;
}
.task_description_area{
.task_desc_area{
height: calc(100vh - 242px);
padding: 0 0 0 15px;
}
.desc_area_header{
display: flex;
justify-content: space-between;
align-items: center;
height: 64px;
padding: 0 30px;
.header_flex{
font-size: 14px;
.flex_label{
@ -51,4 +57,26 @@
}
}
}
}
.student_study_header{
.study_quit{
position: absolute;
right: 30px;
}
.quit-btn{
cursor: pointer;
margin-left: 30px;
color: #888888;
transition: all .3s;
&:hover{
color: #5091FF;
}
// &:last-child{
// color: #888888;
// }
.quit-icon{
margin-right: 5px;
}
}
}

@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-11-27 09:49:30
* @LastEditors: tangjiang
* @LastEditTime: 2019-11-29 13:46:11
* @LastEditTime: 2019-12-09 19:21:55
*/
import '../index.scss';
import React from 'react';
@ -39,12 +39,18 @@ const TaskDescription = (props) => {
<Link to="/" style={{ color: '#5091FF'}}>{username}</Link>
</p>
</div>
<QuillEditor
<div className="task_desc_area">
<QuillEditor
htmlCtx={description}
readOnly={true}
/>
</div>
{/* <QuillEditor
htmlCtx={description}
readOnly={true}
options={[]}
style={{ height: "calc(100% - 109px)" }}
/>
style={{ backgroundColor: 'gold' }}
/> */}
{/* <div dangerouslySetInnerHTML={{__html: description}}></div> */}
</div>
)

@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-11-27 14:59:51
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-06 18:48:52
* @LastEditTime: 2019-12-10 19:00:30
*/
import React, { useState, useEffect } from 'react';
import {connect} from 'react-redux';
@ -21,6 +21,7 @@ const RightPane = (props) => {
input,
hack,
updateCode,
editor_code,
saveUserInputCode,
restoreInitialCode,
saveUserCodeForInterval
@ -29,9 +30,12 @@ const RightPane = (props) => {
const [editorCode, setEditorCode] = useState('');
useEffect(() => {
console.log('1111111');
setEditorCode(hack.code);
}, [hack]);
if (editor_code) {
setEditorCode(editor_code);
} else {
setEditorCode(hack.code);
}
}, [hack, editor_code]);
const handleSubmitForm = () => {
// 提交时, 先调用提交接口,提交成功后,循环调用测评接口
@ -49,7 +53,7 @@ const RightPane = (props) => {
timer = setInterval(() => {
clearInterval(timer);
timer = null;
saveUserCodeForInterval(identifier, code);
saveUserCodeForInterval && saveUserCodeForInterval(identifier, code);
}, 3000);
}
// 保存用户代码块
@ -85,10 +89,11 @@ const RightPane = (props) => {
const mapStateToProps = (state) => {
const {user_program_identifier, hack, userTestInput} = state.ojForUserReducer;
const {user_program_identifier, hack, userTestInput, editor_code} = state.ojForUserReducer;
// const { language, code } = hack;
return {
hack,
editor_code,
input: userTestInput,
submitInput: hack.input,
identifier: user_program_identifier

@ -159,7 +159,7 @@ class ShixunsHome extends Component {
}
</style>
<div className="clearfix edu-back-white pb40 pt30 mb20 banners" id="index-top" onMouseMove={this.bannaronmousemove} onMouseOut={this.bannaronmouseout}>
<div className="educontent pr educontentSlider">
<div className="educontent pr educontentSlider" style={{"width":'1200px'}}>
{homedatalist===undefined?"":
<Slider
nextArrow={<CustomNextArrow />}
@ -240,7 +240,7 @@ class ShixunsHome extends Component {
<p className="color-dark edu-txt-center font-24" style={{lineHeight: '30px'}}>实践课程</p>
<p className="color-grey-cd font-12">TRAINING COURSE</p>
</div>
<Link to={"/paths"} className="moreitem">更多<i className="fa fa-angle-right ml5"></i></Link>
<Link to={"/paths"} className="moreitem mr18">更多<i className="fa fa-angle-right ml5"></i></Link>
<div className="square-list clearfix" style={{'width':'100%','padding-left':'25px'}}>
@ -319,7 +319,7 @@ class ShixunsHome extends Component {
<p className="color-dark edu-txt-center font-24" style={{lineHeight: '30px'}}>实训项目</p>
<p className="color-grey-cd font-12">DEVELOPMENT COMMUNITY</p>
</div>
<Link to={"/shixuns"} className="moreitem">更多<i className="fa fa-angle-right ml5"></i></Link>
<Link to={"/shixuns"} className="moreitem mr18">更多<i className="fa fa-angle-right ml5"></i></Link>
<div className="square-list clearfix" style={{'width':'100%','padding-left':'25px'}}>
<style>

@ -0,0 +1,50 @@
import React, {Component} from 'react';
class Bottomsubmit extends Component {
constructor(props) {
super(props)
this.state = {
}
}
cannelfun=()=>{
window.location.href=this.props.url
}
render() {
return (
<div>
<style>
{
`
.newFooter{
display:none;
}
`
}
</style>
<div className="clearfix bor-bottom-greyE edu-back-white orderingbox newshixunbottombtn">
<div className=" edu-txt-center padding13-30">
<button type="button" className="ant-btn mr20 newshixunmode backgroundFFF" onClick={()=>this.cannelfun()}><span> </span></button>
<button type="button" className="ant-btn newshixunmode mr40 ant-btn-primary" type="primary" htmlType="submit" onClick={()=>this.props.onSubmits()}><span> </span></button>
</div>
</div>
</div>
);
}
}
export default Bottomsubmit;

@ -23,7 +23,7 @@ import { isThisSecond } from 'date-fns';
monaco.editor.defineTheme('myCoolTheme', {
base: 'vs', // vs、vs-dark、hc-black
inherit: true,
rules: [
rules: [
{ token: 'green', background: 'FF0000', foreground: '00FF00', fontStyle: 'italic'},
{ token: 'red', foreground: 'FF0000' , fontStyle: 'bold underline'},
{ background: '#121c23' },
@ -37,7 +37,7 @@ monaco.editor.defineTheme('myCoolTheme', {
// 'editor.selectionHighlightBorder': '#ffffff',
// 'input.border': '#ffffff',
'editor.lineHighlightBorder': '#222c34', // .current-line
// 'editor.selectionBackground': '#FFFF0030',
// 'editor.selectionHighlightBackground' :'#0000FFFF',
}
@ -60,7 +60,7 @@ function loadMonacoResouce(callback) {
// https://github.com/Microsoft/monaco-editor/issues/82
// window.require = { paths: { 'vs': '../node_modules/monaco-editor/min/vs' } };
// window.require = { paths: { 'vs': `${_url_origin}${prefix}/js/monaco/vs` } };
// $('head').append($('<link rel="stylesheet" type="text/css" />')
// .attr('href', `${_url_origin}${prefix}/js/monaco/vs/editor/editor.main.css`));
@ -68,7 +68,7 @@ function loadMonacoResouce(callback) {
// cache: true
// });
// $.when(
// // $.getScript( `${_url_origin}${prefix}/js/monaco/vs/language/typescript/tsMode.js` ),
// // $.getScript( `${_url_origin}${prefix}/js/monaco/vs/basic-languages/javascript/javascript.js` ),
// $.getScript( `${_url_origin}${prefix}/js/monaco/vs/basic-languages/python/python.js` ),
@ -79,7 +79,7 @@ function loadMonacoResouce(callback) {
// $.getScript( `${_url_origin}${prefix}/js/monaco/vs/editor/editor.main.js` ),
// $.Deferred(function( deferred ){
// console.log('Deferred')
// // TODO 暂时放这里
// $( deferred.resolve );
// checkIfLoaded(callback);
@ -126,7 +126,7 @@ function checkIfLoaded (callback) {
}
/*
language
language
javascript css less scss html typescript
java ruby vb r python php perl go cpp csharp
sql pgsql mysql
@ -155,7 +155,7 @@ function checkIfLoaded (callback) {
version: 3,
singleLineStringErrors: false
},
*/
*/
const mirror2LanguageMap = {
'JFinal': 'java',
'Java': 'java',
@ -194,10 +194,10 @@ function getLanguageByMirrorName(mirror_name) {
let notCallCodeMirrorOnChangeFlag = false;
/**
props :
/**
props :
mirror_name 决定语言
isEditablePath
isEditablePath
repositoryCode
codemirrorDidMount
@ -218,7 +218,7 @@ class TPIMonaco extends Component {
autoCompleteSwitch: fromStore('autoCompleteSwitch', true),
}
}
componentDidUpdate(prevProps, prevState, snapshot) {
const { mirror_name } = this.props
const editor_monaco = this.editor_monaco;
@ -234,20 +234,20 @@ class TPIMonaco extends Component {
} else {
editor_monaco.updateOptions({readOnly: true})
}
} else if (editor_monaco && prevProps.codeLoading === true && this.props.codeLoading === false
} else if (editor_monaco && prevProps.codeLoading === true && this.props.codeLoading === false
) {
if (this.props.repositoryCode != editor_monaco.getValue()) {
// newProps.repositoryCode !== this.props.repositoryCode &&
// newProps.repositoryCode !== this.props.repositoryCode &&
notCallCodeMirrorOnChangeFlag = true;
// 重要setState(因获取代码、重置代码等接口引起的调用)调用引起的变化才需要setValue
editor_monaco.setValue(this.props.repositoryCode)
}
// 代码没变也需要layout可能从命令行自动切回了代码tab
editor_monaco.layout();
// Clears the editor's undo history.
// TODO
// extend_editor.clearHistory()
@ -258,7 +258,7 @@ class TPIMonaco extends Component {
// 注意销毁不然会出现不能编辑的bug
this.editor_monaco && this.editor_monaco.dispose()
}
componentDidMount() {
checkIfLoaded(() => {
let value = [
@ -290,7 +290,7 @@ class TPIMonaco extends Component {
// http://testeduplus2.educoder.net/react/build/static/node_modules/_monaco-editor@0.15.6@monaco-editor/esm/vs/editor/common/config/commonEditorConfig.js
// https://github.com/Microsoft/monaco-editor/issues/29
scrollBeyondLastLine: false,
language: lang,
// language: 'css',
@ -304,7 +304,7 @@ class TPIMonaco extends Component {
window.editor_monaco = editor;
this.editor_monaco = editor
// editor.setPosition({ lineNumber: 2, column: 30 });
// editor.model.onDidChangeContent((event) => {
@ -323,27 +323,27 @@ class TPIMonaco extends Component {
this.props.onRepositoryCodeUpdate && this.props.onRepositoryCodeUpdate(editor.getValue())
})
this.props.codemirrorDidMount && this.props.codemirrorDidMount()
if(this.props.shixun && this.props.shixun.forbid_copy == true) {
// 禁用粘贴
// https://github.com/Microsoft/monaco-editor/issues/100
window.editor_monaco.onDidPaste( (a, b, c) => { window.__pastePosition = a })
window.addEventListener('paste', (a, b, c) => {
const selection = window.editor_monaco.getSelection();
const range = new monaco.Range(
window.__pastePosition.startLineNumber || selection.endLineNumber,
window.__pastePosition.startColumn || selection.endColumn,
window.__pastePosition.endLineNumber || selection.endLineNumber,
window.__pastePosition.endColumn || selection.endColumn,);
window.addEventListener('paste', (a, b, c) => {
const selection = window.editor_monaco.getSelection();
const range = new monaco.Range(
window.__pastePosition.startLineNumber || selection.endLineNumber,
window.__pastePosition.startColumn || selection.endColumn,
window.__pastePosition.endLineNumber || selection.endLineNumber,
window.__pastePosition.endColumn || selection.endColumn,);
window.editor_monaco.executeEdits('', [{range, text: ''}] )
})
})
// 禁用复制
window.editor_monaco.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KEY_C, () => null);
window.editor_monaco.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KEY_V, () => null);
}
setTimeout(() => {
editor.layout();
@ -352,23 +352,23 @@ class TPIMonaco extends Component {
window.editor_monaco.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KEY_S, () => {
this.props.doFileUpdateRequestOnCodeMirrorBlur();
return false;
return false;
});
window.editor_monaco.onDidBlurEditorWidget(() => {
window.editor_monaco.onDidBlurEditorWidget(() => {
this.props.onEditBlur && this.props.onEditBlur();
})
})
})
// window.document.onkeydown = (e) => {
// window.document.onkeydown = (e) => {
// e = window.event || e;
// if(e.keyCode== 83 && e.ctrlKey){
// if(e.keyCode== 83 && e.ctrlKey){
// /*延迟兼容FF浏览器 */
// // setTimeout(function(){
// // alert('ctrl+s');
// // },1);
// // alert('ctrl+s');
// // },1);
// this.props.doFileUpdateRequestOnCodeMirrorBlur();
// return false;
// }
// return false;
// }
// };
}
onFontSizeChange = (value) => {
@ -390,7 +390,7 @@ class TPIMonaco extends Component {
render() {
const { repositoryCode, showSettingDrawer, settingDrawerOpen } = this.props;
const { cmFontSize } = this.state;
return (
<React.Fragment>
<Drawer
@ -400,10 +400,10 @@ class TPIMonaco extends Component {
width={260}
open={settingDrawerOpen}
onClose={() => showSettingDrawer( false )}
>
<TPICodeSetting {...this.props} {...this.state}
<TPICodeSetting {...this.props} {...this.state}
onFontSizeChange={this.onFontSizeChange}
onCodeModeChange={this.onCodeModeChange}
onAutoCompleteSwitchChange={this.onAutoCompleteSwitchChange}
@ -436,7 +436,7 @@ export var EDITOR_DEFAULTS = {
wordWrap: 'off',
wordWrapColumn: 80,
wordWrapMinified: true,
wrappingIndent: 1
wrappingIndent: 1
wordWrapBreakBeforeCharacters: '([{‘“〈《「『【〔([{「£¥$£¥+',
wordWrapBreakAfterCharacters: ' \t})]?|&,;¢°′″‰℃、。。、¢,.:;?!%・・ゝゞヽヾーァィゥェォッャュョヮヵヶぁぃぅぇぉっゃゅょゎゕゖㇰㇱㇲㇳㇴㇵㇶㇷㇸㇹㇺㇻㇼㇽㇾㇿ々〻ァィゥェォャュョッー”〉》」』】〕)]}」',
wordWrapBreakObtrusiveCharacters: '.',
@ -555,4 +555,4 @@ export var EDITOR_DEFAULTS = {
};
*/
*/

@ -1,12 +1,13 @@
import React, { Component } from 'react';
import {getImageUrl} from 'educoder';
import {Modal,Input} from 'antd';
import {Modal,Input,Form,Radio} from 'antd';
class Addshixuns extends Component {
constructor(props) {
super(props);
this.state = {
shixunname:undefined,
shixunzero:false
shixunzero:false,
is_jupyter:"1"
}
}
@ -52,12 +53,22 @@ class Addshixuns extends Component {
})
return
}
this.props.Setaddshixuns(shixunname);
let is_jupyter=this.state.is_jupyter==="1"?false:true
this.props.Setaddshixuns(shixunname,is_jupyter);
this.props.modalCancel();
}
GrouponChange = e => {
this.setState({
is_jupyter: e.target.value,
});
};
render() {
const formItemLayout = {
labelCol: { span: 4 },
wrapperCol: { span: 14 },
};
return(
<Modal
className={this.props.className}
@ -81,6 +92,14 @@ class Addshixuns extends Component {
</style>:""}
<div className="task-popup-content">
<Form {...formItemLayout}>
<Form.Item label="实训类型">
<Radio.Group value={this.state.is_jupyter} onChange={this.GrouponChange}>
<Radio value="1">普通实训</Radio>
<Radio value="2">jupyter实训</Radio>
</Radio.Group>
</Form.Item>
</Form>
<p className="task-popup-text-center font-16">
<span style={{ "line-height":"30px"}}>实训名称</span>
<span><Input style={{ width:"80%"}} className="yslzxueshisy " placeholder="请输入60字以内的实训名称" onChange={this.handleChange} addonAfter={String(this.state.shixunname===undefined?0:this.state.shixunname.length)+"/60"} maxLength={60} />

@ -320,7 +320,7 @@ class DetailCardsEditAndAdd extends Component{
})
}
Getaddshixuns=(value)=>{
Getaddshixuns=(value,is_jupyter)=>{
let {
shixuns_listeditlist,
shixuns_listedit,
@ -329,7 +329,8 @@ class DetailCardsEditAndAdd extends Component{
let list=shixuns_listeditlist
let url='/paths/add_shixun_to_stage.json';
axios.post(url,{
name:value
name:value,
is_jupyter:is_jupyter
}).then((response) => {
if(response){
if(response.data){
@ -383,7 +384,7 @@ class DetailCardsEditAndAdd extends Component{
{this.state.Addshixunstype===true?<Addshixuns
modalCancel={this.cardsModalcancel}
Setaddshixuns={(value)=>this.Getaddshixuns(value)}
Setaddshixuns={(value,is_jupyter)=>this.Getaddshixuns(value,is_jupyter)}
{...this.props}
{...this.state}
/>:""}

@ -320,7 +320,7 @@ class DetailCardsEditAndEdit extends Component{
notification.open(data);
}
Getaddshixuns=(value)=>{
Getaddshixuns=(value,is_jupyter)=>{
let {
shixuns_listeditlist,
shixuns_listedit,
@ -329,7 +329,8 @@ class DetailCardsEditAndEdit extends Component{
let list=shixuns_listeditlist
let url='/paths/add_shixun_to_stage.json';
axios.post(url,{
name:value
name:value,
is_jupyter:is_jupyter
}).then((response) => {
if(response){
if(response.data){
@ -383,7 +384,7 @@ class DetailCardsEditAndEdit extends Component{
</Modals>
{this.state.Addshixunstype===true?<Addshixuns
modalCancel={this.cardsModalcancel}
Setaddshixuns={(value)=>this.Getaddshixuns(value)}
Setaddshixuns={(value,is_jupyter)=>this.Getaddshixuns(value,is_jupyter)}
{...this.props}
{...this.state}
/>:""}

@ -55,8 +55,9 @@ class TPMBanner extends Component {
isIE:false,
Forkvisibletype: false,
isSpin:false,
Senttothevcaluetype:false
}
Senttothevcaluetype:false,
jupyterbool:false,
}
}
// star_info:[0, 0, 0, 0, 0, 0],
@ -656,7 +657,7 @@ class TPMBanner extends Component {
{/*<span className="mt10">{shixunsDetails.experience}</span>*/}
{/*</li>*/}
<li>
<span>难度系数</span>
<span>难度级别</span>
<span className="shixunsdiffcult mt10">{shixunsDetails.diffcult}</span>
</li>

@ -1,54 +1,61 @@
import React, { Component } from 'react';
import { Redirect } from 'react-router';
import PropTypes from 'prop-types';
import { CircularProgress } from 'material-ui/Progress';
import './TPMShixunDiscuss.css'
import Challenges from './shixunchild/Challenges/Challenges'
import TPMRightSection from './component/TPMRightSection'
import TPMNav from './component/TPMNav'
class TPMChallenge extends Component {
constructor(props) {
super(props)
}
render() {
const { loadingContent, shixun, user, match
} = this.props;
return (
<React.Fragment>
<div className="educontent clearfix mt30 mb80">
<div className="with65 fl edu-back-white" >
<TPMNav
match={match}
user={user}
shixun={shixun}
{...this.props}
></TPMNav>
<Challenges
{...this.props}
/>
</div>
<div className="with35 fr pl20">
<TPMRightSection
{...this.props}
/>
</div>
</div>
</React.Fragment>
);
}
}
export default TPMChallenge;
import React, { Component } from 'react';
import { Redirect } from 'react-router';
import PropTypes from 'prop-types';
import { CircularProgress } from 'material-ui/Progress';
import './TPMShixunDiscuss.css'
import Challenges from './shixunchild/Challenges/Challenges'
import Challengesjupyter from './shixunchild/Challenges/Challengesjupyter'
import TPMRightSection from './component/TPMRightSection'
import TPMNav from './component/TPMNav'
class TPMChallenge extends Component {
constructor(props) {
super(props)
}
render() {
const { loadingContent, shixun, user, match,jupyterbool
} = this.props;
return (
<React.Fragment>
<div className="educontent clearfix mt30 mb80">
<div className="with65 fl edu-back-white" >
<TPMNav
match={match}
user={user}
shixun={shixun}
{...this.props}
></TPMNav>
{
jupyterbool===true?
<Challengesjupyter
{...this.props}
/>
: <Challenges
{...this.props}
/>
}
</div>
<div className="with35 fr pl20">
<TPMRightSection
{...this.props}
/>
</div>
</div>
</React.Fragment>
);
}
}
export default TPMChallenge;

@ -0,0 +1,531 @@
import React, {Component} from 'react';
import {Redirect} from 'react-router';
import {List, Typography, Tag, Modal, Radio, Checkbox, Table, Pagination,Upload,notification} from 'antd';
import { NoneData } from 'educoder'
import TPMRightSection from './component/TPMRightSection';
import TPMNav from './component/TPMNav';
import axios from 'axios';
import './tpmmodel/tpmmodel.css'
import {getUploadActionUrl} from 'educoder';
import moment from 'moment';
const confirm = Modal.confirm;
class TPMDataset extends Component {
constructor(props) {
super(props)
this.state = {
datas: [0, 1, 2, 3, 4, 5],
value: undefined,
columns: [
{
title: '文件',
dataIndex: 'number',
key: 'number',
align: 'left',
className: " font-14 wenjiantit",
width: '200px',
render: (text, record) => (
<div>
{record.title}
</div>
)
},
{
title: '最后修改时间',
dataIndex: 'number',
key: 'number',
align: 'center',
className: "edu-txt-center font-14 zuihoushijian",
width: '150px',
render: (text, record) => (
<div>
{record.timedata}
</div>
)
},
{
title: '最后修改人',
dataIndex: 'number',
key: 'number',
align: 'center',
className: "edu-txt-center font-14 ",
render: (text, record) => (
<div>
{record.author}
</div>
)
},
{
title: '文件大小',
dataIndex: 'number',
key: 'number',
align: 'center',
className: "edu-txt-center font-14 ",
render: (text, record) => (
<div>
{record.filesize}
</div>
)
},
],
page: 1,
limit: 10,
selectedRowKeys: [],
mylistansum:30,
collaboratorList:[],
fileList:[],
file:null,
datalist:[],
data_sets_count:0,
selectedRowKeysdata:[],
}
}
componentDidMount() {
this.getdatas()
}
mysonChange = (e) => {
console.log(`全选checked = ${e.target.checked}`);
if (e.target.checked === true) {
let mydata=[];
let datas=[];
for(let i=0;i<this.state.collaboratorList.data_sets.length;i++){
mydata.push(this.state.collaboratorList.data_sets[i].id);
datas.push(i);
}
this.setState({
selectedRowKeysdata:mydata,
selectedRowKeys: datas,
})
console.log(mydata);
console.log(datas);
} else {
this.setState({
selectedRowKeys: [],
})
}
}
getdatas = () => {
let id=this.props.match.params.shixunId;
let collaborators=`/shixuns/${id}/jupyter_data_sets.json`;
axios.get(collaborators,{params:{
page:1,
limit:10,
}}).then((response)=> {
if(response.status===200){
if (response.data.status === 403||response.data.status === 401||response.data.status === 500) {
}else{
let datalists=[];
for(let i=0;i<response.data.data_sets.length;i++){
const datas=response.data.data_sets;
var timedata = moment(datas[i].created_on).format('YYYY-MM-DD HH:mm');
datalists.push({
timedata:timedata,
author:datas[i].author,
filesize:datas[i].filesize,
id:datas[i].id,
title:datas[i].title,
})
}
this.setState({
collaboratorList: response.data,
data_sets_count:response.data.data_sets_count,
datalist:datalists,
});
}
}
}).catch((error)=>{
console.log(error)
});
}
getdatastwo = (page,limit) => {
let id=this.props.match.params.shixunId;
let collaborators=`/shixuns/${id}/jupyter_data_sets.json`;
axios.get(collaborators,{params:{
page:page,
limit:limit,
}}).then((response)=> {
if(response.status===200){
if (response.data.status === 403||response.data.status === 401||response.data.status === 500) {
}else{
let datalists=[];
for(let i=0;i<response.data.data_sets.length;i++){
const datas=response.data.data_sets;
var timedata = moment(datas[i].created_on).format('YYYY-MM-DD HH:mm');
datalists.push({
timedata:timedata,
author:datas[i].author,
filesize:datas[i].filesize,
id:datas[i].id,
title:datas[i].title,
})
}
this.setState({
collaboratorList: response.data,
data_sets_count:response.data.data_sets_count,
datalist:datalists,
});
}
}
}).catch((error)=>{
console.log(error)
});
}
showModal = (id, status) => {
};
handleOk = (id, editid) => {
};
handleCancel = (e) => {
};
paginationonChanges = (pageNumber) => {
// //console.log('Page: ');
this.setState({
page: pageNumber,
})
this.getdatastwo(pageNumber,10);
}
onSelectChange = (selectedRowKeys, selectedRows) => {
console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
this.setState(
{
selectedRowKeys
}
);
let mydata=[];
for(let i=0;i<selectedRows.length;i++){
mydata.push(selectedRows[i].id);
}
this.setState({
selectedRowKeysdata:mydata,
})
console.log(mydata);
}
rowClassName = (record, index) => {
let className = 'light-row';
if (index % 2 === 1) className = 'dark-row';
return className;
}
// 附件相关 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
});
this.getdatas();
// }
}
}
}
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;
}
}
deleteRemovedata(){
debugger
console.log("删除");
console.log(this.state.selectedRowKeysdata);
const url = `/attachments/destroy_files.json`;
axios.delete(url, {
id:this.state.selectedRowKeysdata,
})
.then((response) => {
if (response.data) {
const { status } = response.data;
if (status == 0) {
this.props.showNotification(`删除成功`);
this.getdatas()
}
}
})
.catch(function (error) {
console.log(error);
});
}
deleteAttachment = (file) => {
console.log(file);
let id=file.response ==undefined ? file.id : file.response.id
const url = `/attachements/destroy_files.json`
axios.delete(url, {
id:[id],
})
.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);
});
}
render() {
const {tpmLoading, shixun, user, match} = this.props;
const {columns, datas, page, limit, selectedRowKeys,mylistansum,fileList,datalist,data_sets_count} = this.state;
const rowSelection = {
selectedRowKeys,
onChange: this.onSelectChange,
};
// getCheckboxProps: record => ({
// disabled: record.name === 'Disabled User', // Column configuration not to be checked
// name: record.name,
// }),
let id=this.props.match.params.shixunId;
const uploadProps = {
width: 600,
fileList,
data:{
attachtype: 2,
container_id:this.props.match.params.shixunId,
container_type: "Shixun",
},
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;
},
}
return (
<React.Fragment>
<div className="tpmComment educontent clearfix mt30 mb80">
<div className="with65 fl edu-back-white commentsDelegateParent">
<TPMNav
match={match}
user={user}
shixun={shixun}
{...this.props}
></TPMNav>
<div className="padding20 edu-back-white mt20 " style={{minHeight: '463px'}}>
<div className="sortinxdirection">
<div className="tpmwidth">
{ data_sets_count>0?
<Checkbox onChange={this.mysonChange}>全选</Checkbox>:""}
</div>
<div className="tpmwidth xaxisreverseorder">
<style>
{
`
.ant-upload-list{
display:none
}
`
}
</style>
<div className="deletebuttom intermediatecenter "> <Upload {...uploadProps}><p className="deletebuttomtest">
上传文件</p> </Upload></div>
{
data_sets_count>0?
<div
className={selectedRowKeys.length > 0 ? "deletebutomtextcode intermediatecenter mr21" : "deletebutom intermediatecenter mr21"} onClick={()=>this.deleteRemovedata()}>
<p className="deletebutomtext" >删除</p></div>
:""
}
</div>
</div>
<div className="mt24">
<style>{`
.ant-spin-nested-loading > div > .ant-spin .ant-spin-dot {
top: 72%;}
}
.edu-table .ant-table-tbody > tr > td {
height: 42px;
}
.edu-table .ant-table-thead > tr > th{
height: 42px;
}
.ysltableowss .ant-table-thead > tr > th{
height: 42px;
}
.ysltableowss .ant-table-tbody > tr > td{
height: 42px;
}
.ysltableowss .ant-table-thead > tr > th, .ant-table-tbody > tr > td {
padding: 9px;
}
.mysjysltable4 .ant-table-thead > tr > th, .ant-table-tbody > tr > td {
padding: 0px;
}
.ant-table-thead .ant-table-selection-column span{
visibility:hidden;
}
.ant-table-thead > tr > th {
background:#FFFFFF !important;
}
.ant-table table {
width: 100%;
text-align: left;
border-radius: 4px 4px 0 0;
border-collapse: separate;
border-spacing: 0;
border-left: 1px solid #eeeeee;
border-top: 1px solid #eeeeee;
border-right: 1px solid #eeeeee;
}
`}</style>
{data_sets_count===0?
<style>
{
`
.ant-table-tbody{
display:none;
}
.ant-table table {
border-bottom: 1px solid #eeeeee !important;
}
`
}
</style>
:
<div className="edu-table edu-back-white ysltableowss">
<Table
dataSource={datalist}
columns={columns}
pagination={false}
className="mysjysltable4"
rowSelection={rowSelection}
rowClassName={this.rowClassName}
/>
</div>
}
{
data_sets_count>=11?
<div className="edu-txt-center mt40 mb20">
<Pagination showQuickJumper current={page}
onChange={this.paginationonChanges} pageSize={limit}
total={data_sets_count}
></Pagination>
</div>
:""
}
{ data_sets_count===0?
<NoneData style={{width: '100%'}}></NoneData>:""
}
</div>
</div>
</div>
<div className="with35 fr pl20">
<TPMRightSection
{...this.props}
/>
</div>
</div>
</React.Fragment>
);
}
}
export default TPMDataset;

@ -114,7 +114,7 @@ body>.-task-title {
/*-------------------个人主页:右侧提示区域--------------------------*/
.-task-sidebar{position:fixed;width:40px;height:180px;right:0;bottom:30px;z-index: 10;}
.-task-sidebar{position:fixed;width:40px;height:180px;right:0;bottom:80px !important;z-index: 10;}
.-task-sidebar>div{height: 40px;line-height: 40px;box-sizing: border-box;width:40px;background:#4CACFF;color:#fff;font-size:20px;text-align:center;margin-bottom:5px;border-radius: 4px;}
.-task-sidebar>div i{ color:#fff;}
.-task-sidebar>div i:hover{color: #fff!important;}

@ -27,7 +27,7 @@ import TPMPropaedeuticsComponent from './TPMPropaedeuticsComponent';
import TPMRanking_listComponent from './TPMRanking_listContainer';
import TPMCollaboratorsComponent from './TPMCollaboratorsContainer';
import Audit_situationComponent from './Audit_situationComponent';
import TPMDataset from './TPMDataset';
import '../page/tpiPage.css'
const $ = window.$
@ -142,6 +142,7 @@ class TPMIndex extends Component {
identity:undefined,
TPMRightSectionData:undefined,
PropaedeuticsList: undefined,
tpmindexjupyterbool:false,
}
}
@ -192,7 +193,7 @@ class TPMIndex extends Component {
propaedeutics:response.data.propaedeutics,
status: response.data.shixun_status,
secret_repository: response.data.secret_repository,
});
}
}).catch((error) => {
@ -259,8 +260,8 @@ class TPMIndex extends Component {
axios.interceptors.request.eject(this.tpmContentResponseInterceptor);
this.tpmContentResponseInterceptor = null;
}
setLoadingContent = (isLoadingContent) => {
this.setState({ loadingContent: isLoadingContent })
}
@ -270,20 +271,29 @@ class TPMIndex extends Component {
// }
render() {
let url = window.location.href;
let flag = url.indexOf("add_file")>-1;
return (
<div className="newMain clearfix">
{/*头部*/}
{
!flag &&
!flag &&
<TPMBanner
{...this.props}
{...this.state}
></TPMBanner>
}
{/*筛选*/}
{/*{*/}
{/* tpmindexjupyterbool===false?*/}
{/* :""*/}
{/*}*/}
{/* */}
<Switch {...this.props}>
<Route path="/shixuns/:shixunId/repository/:repoId/commits" render={
(props) => (<TPMRepositoryCommits {...this.props} {...this.state} {...props}
/>)
@ -294,7 +304,7 @@ class TPMIndex extends Component {
}></Route>
<Route exact path="/shixuns/:shixunId/challenges" render={
(props) => (<TPMChallengeComponent {...this.props} {...this.state} {...props}
(props) => (<TPMChallengeComponent {...this.props} jupyterbool={true} {...this.state} {...props}
/>)
}></Route>
@ -311,7 +321,7 @@ class TPMIndex extends Component {
(props) => (<TPMRepositoryComponent {...this.props} {...this.state} {...props} secret_repository_tab={true}
/>)
}></Route>
{/* <Route exact path="/shixuns/:shixunId/propaedeutics" component={TPMPropaedeuticsComponent}></Route> */}
<Route exact path="/shixuns/:shixunId/propaedeutics" render={
@ -325,7 +335,7 @@ class TPMIndex extends Component {
/>)
}></Route>
{/* <Route exact path="/shixuns/:shixunId/repository/:shixunId/" component={TPMRepositoryComponent}></Route> */}
@ -342,12 +352,17 @@ class TPMIndex extends Component {
(props) => (<TPMsettings {...this.props} {...this.state} {...props} />)
}></Route>
{/*实训项目条目塞选*/}
<Route exact path="/shixuns/:shixunId/ranking_list" render={
(props) => (<TPMRanking_listComponent {...this.props} {...this.state} {...props}
/>)
}></Route>
<Route exact path="/shixuns/:shixunId/dataset" render={
(props) => (<TPMDataset {...this.props} {...this.state} {...props}
/>)
}></Route>
<Route exact path="/shixuns/:shixunId/audit_situation" render={
(props) => (<Audit_situationComponent {...this.props} {...this.state} {...props}
/>)

@ -23,7 +23,7 @@ const versionNum = '0001';
// let _url_origin = getUrl()
let _url_origin='';
if(window.location.port === "3007"){
_url_origin="http://pre-newweb.educoder.net";
_url_origin="https://test-newweb.educoder.net";
}
// let _url_origin=`https://www.educoder.net`;
@ -31,7 +31,7 @@ if(window.location.port === "3007"){
if (!window['indexHOCLoaded']) {
window.indexHOCLoaded = true;
//解决首屏加载问题
// $('head').append($('<link rel="stylesheet" type="text/css" />')
// .attr('href', `${_url_origin}/stylesheets/educoder/antd.min.css?1525440977`));
$('head').append($('<link rel="stylesheet" type="text/css" />')
@ -51,7 +51,7 @@ if (!window['indexHOCLoaded']) {
// setTimeout(() => {
// $('head').append( $('<link rel="stylesheet" type="text/css" />')
// .attr('href', `${_url_origin}/stylesheets/css/edu-common.css?1525440977`) );
// $('head').append( $('<link rel="stylesheet" type="text/css" />')
// .attr('href', `${_url_origin}/stylesheets/educoder/edu-all.css?1525440977`) );
// $('head').append( $('<link rel="stylesheet" type="text/css" />')
@ -60,7 +60,7 @@ if (!window['indexHOCLoaded']) {
$("script").append('<script></script>')
.attr('src', `${_url_origin}/javascripts/jquery-1.8.3-ui-1.9.2-ujs-2.0.3.js?_t=${versionNum}`);
}
// `${_url_origin}/javascripts/jquery-1.8.3-ui-1.9.2-ujs-2.0.3.js?_t=${versionNum}`
// TODO css加载完成后再打开页面行为和tpm其他页面一致
@ -146,7 +146,7 @@ export function TPMIndexHOC(WrappedComponent) {
componentWillUnmount() {
window.removeEventListener('keyup', this.keyupListener)
}
componentDidMount() {
// console.log("TPMIndexHOC========");
// console.log(this.props);
@ -216,7 +216,7 @@ export function TPMIndexHOC(WrappedComponent) {
this.getAppdata();
}
/**
课堂权限相关方法暂时写这里了 ----------------------------------------START
课堂权限相关方法暂时写这里了 ----------------------------------------START
ADMIN = 0 # 超级管理员
CREATOR = 1 # 课程创建者
PROFESSOR = 2 # 课程老师
@ -560,7 +560,7 @@ export function TPMIndexHOC(WrappedComponent) {
checkIfProfessionalCertification = () => {
return this.state.current_user && this.state.current_user.professional_certification
}
ShowOnlinePdf = (url) => {
return axios({
@ -642,14 +642,14 @@ export function TPMIndexHOC(WrappedComponent) {
isAdminOrCreator:this.isAdminOrCreator,
isClassManagement:this.isClassManagement,
isCourseAdmin:this.isCourseAdmin,
isAdmin: this.isAdmin,
isAdminOrTeacher: this.isAdminOrTeacher,
isStudent: this.isStudent,
isAdminOrStudent: this.isAdminOrStudent,
isNotMember: this.isNotMember,
isCourseEnd: this.isCourseEnd,
isUserid:this.state.coursedata&&this.state.coursedata.userid,
fetchUser: this.fetchUser,
@ -660,7 +660,7 @@ export function TPMIndexHOC(WrappedComponent) {
checkIfProfileCompleted: this.checkIfProfileCompleted,
checkIfProfessionalCertification: this.checkIfProfessionalCertification,
showProfessionalCertificationDialog: this.showProfessionalCertificationDialog,
ShowOnlinePdf:(url)=>this.ShowOnlinePdf(url),
DownloadFileA:(title,url)=>this.DownloadFileA(title,url),
DownloadOpenPdf:(type,url)=>this.DownloadOpenPdf(type,url),
@ -671,7 +671,7 @@ export function TPMIndexHOC(WrappedComponent) {
yslslowCheckresults:this.yslslowCheckresults,
yslslowCheckresultsNo:this.yslslowCheckresultsNo,
MdifHasAnchorJustScorll:this.MdifHasAnchorJustScorll
};
// console.log("this.props.mygetHelmetapi");
// console.log(this.props.mygetHelmetapi);
@ -742,7 +742,7 @@ export function TPMIndexHOC(WrappedComponent) {
}
`
}</style>
<NewHeader {...this.state} {...this.props}></NewHeader>
<Spin spinning={this.state.globalLoading} delay={0} className="globalSpin"
@ -765,9 +765,9 @@ export function TPMIndexHOC(WrappedComponent) {
{...this.state} {...this.props}
Footerdown={Footerdown}
/>
</div>
);
}
}
}
}

@ -0,0 +1,131 @@
import React, { Component } from 'react';
import MonacoEditor from 'react-monaco-editor';
//MonacoDiffEditor 对比模式
import {Input, Select, Radio, Checkbox, Popconfirm, message, Modal,Icon,DatePicker,Breadcrumb,Upload,Button,notification, Tooltip} from 'antd';
// import "antd/dist/antd.css";
import locale from 'antd/lib/date-picker/locale/zh_CN';
import moment from 'moment';
import axios from 'axios';
import './css/TPMsettings.css';
import { getImageUrl, toPath, getUrl ,appendFileSizeToUploadFileAll, getUploadActionUrl} 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 confirm = Modal.confirm;
export default class Shixuninformation extends Component {
constructor(props) {
super(props)
this.state = {
}
}
render() {
let {can_copy}=this.state;
let options;
if (this.props.departmentslist != undefined) {
options = this.props.departmentslist.map((d, k) => {
return (
<Option key={d} id={k}>{d}</Option>
)
})
}
return (
<div>
<div className="clearfix ml30">
<span className="color-grey-6 mt5 fl" style={{minWidth: '95px'}}>复制:</span>
<span className="fl mt5">
<Checkbox checked={this.props.data&&this.props.data.shixun.can_copy === undefined ? false : this.props.data&&this.props.data.shixun.can_copy} onChange={this.props.data&&this.props.data.shixun.can_copy}></Checkbox>
<label style={{top:'6px'}} className="color-grey-9 ml10">(勾选则允许已认证的教师复制该实训)</label>
</span>
</div>
<div className="edu-back-white mb10 padding40-20" style={{display:this.props.identity===1?"block":this.props.data&&this.props.data.shixun.status===2&&this.props.data&&this.props.data.shixun.use_scope===0||this.props.data&&this.props.data.shixun.status===1&&this.props.data&&this.props.data.shixun.use_scope===0?"none":"block"}}>
<p className="color-grey-6 font-16 mb30">公开程度</p>
<RadioGroup onChange={this.SelectOpenpublic} value={this.props.data&&this.props.data.use_scope}>
<Radio className="radioStyle" value={0}><span>对所有公开</span> <span className="color-grey-9">()</span></Radio>
<Radio className="radioStyle" value={1}><span>对指定单位公开</span> <span className="color-grey-9">()</span></Radio>
</RadioGroup>
<div className="clearfix none" id="unit-all" style={{display: this.props.scopetype === false ? 'none' : 'block'}}>
<div className="fl ml25">
<div className="fl" id="unit-input-part" style={{width:'100%'}}>
<div id="person-unit" className="fl pr mr10">
<div className="shixunScopeInput fl" >
<Select
style={{width:'200px'}}
placeholder="请输入并选择单位名称"
onChange={(value)=>this.shixunScopeInput(value)}
onSearch={this.shixunHandleSearch}
showSearch
defaultActiveFirstOption={false}
showArrow={false}
filterOption={false}
notFoundContent={null}
className={this.props.scope_partmenttype===true?"bor-red":""}
>
{options}
</Select>
</div>
<span className="color-grey-9">(搜索并选中添加单位名称)</span>
</div>
</div>
<div style={{width:'100%'}}>
<div className="mt20 clearfix" id="task_tag_content">
{
this.props.scope_partment===undefined?"":this.props.scope_partment.map((item,key)=>{
return(
<li className="task_tag_span" key={key}><span>{item}</span>
<a style={{ color: 'rgba(0,0,0,.25)' }}
onClick={(key)=>this.deleteScopeInput(key)}
>
{this.props.identity===1?"x":this.state.status===2&&this.props.scope_partment===this.props.scope_partments||this.state.status===1&&this.props.scope_partment===this.props.scope_partments?"":"×"}
</a>
</li>
)
})
}
</div>
</div>
<span className={this.props.scope_partmenttype===true?"color-orange ml20 fl":"color-orange ml20 fl none"} id="public_unit_notice">
<i className="fa fa-exclamation-circle mr3"></i>
请选择需要公开的单位
</span>
</div>
</div>
</div>
</div>
);
}
}

@ -0,0 +1,33 @@
import React, { Component } from 'react';
import {Input, Select, Radio, Checkbox, Popconfirm, message, Modal,Icon,DatePicker,Breadcrumb,Upload,Button,notification, Tooltip,Tabs} from 'antd';
import axios from 'axios';
import './css/TPMsettings.css';
import { getImageUrl, toPath, getUrl ,appendFileSizeToUploadFileAll, getUploadActionUrl} from 'educoder';
export default class Shixuninformation extends Component {
constructor(props) {
super(props)
this.state = {
}
}
render() {
return (
<div>
1111
</div>
);
}
}

@ -0,0 +1,484 @@
import React, {Component} from 'react';
import MonacoEditor from 'react-monaco-editor';
import {
Input,
Select,
Radio,
Checkbox,
Popconfirm,
message,
Modal,
Icon,
DatePicker,
Breadcrumb,
Upload,
Button,
notification,
Tooltip,
Tabs,
Form
} from 'antd';
import axios from 'axios';
import TPMMDEditor from "../challengesnew/TPMMDEditor";
import {getImageUrl, toPath, getUrl, appendFileSizeToUploadFileAll, getUploadActionUrl} from 'educoder';
import {TPMIndexHOC} from "../TPMIndexHOC";
import './css/TPMsettings.css';
import '../newshixuns/css/Newshixuns.css';
class Shixuninformation extends Component {
constructor(props) {
super(props)
this.contentMdRef = React.createRef();
this.state = {
NAME_COUNT: 60,
shixunmemoMDvalue: "",
language: "java",
}
}
getshixunmemoMDvalue = (value, e) => {
this.setState({
shixunmemoMDvalue: value
})
}
render() {
console.log(this.props.data)
const {getFieldDecorator} = this.props.form;
const {newshixunlist, languagewrite, systemenvironment, testcoderunmode, fileList, postapplytitle, postapplyvisible, shixunmemoMDvalue} = this.state;
const {shixun_service_configs}=this.props;
let operateauthority = this.props.identity === 1 ? true : this.props.identity < 5 && this.state.status == 0 ? true : false;
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;
},
}
return (
<div>
<Form>
<Form.Item
label="名称"
style={{"borderBottom": 'none'}}
className="mt15"
>
{getFieldDecorator('name', {
rules: [{
required: true, message: '请输入选题名称',
}, {
max: 60, message: '请输入名称最大限制60个字符',
}, {
whitespace: true, message: '请勿输入空格'
}],
})(
<Input placeholder="请输入名称最大限制60个字符"
className={"input-100-45 greyInput"}
onInput={this.shixunNameInput} autoComplete="off"
addonAfter={`${String(!this.state.shixunName ? 0 : this.state.shixunName.length)}/${this.state.NAME_COUNT}`}
className="newViewAfter"/>
)}
</Form.Item>
<Form.Item
label="简介"
style={{"borderBottom": 'none', 'marginBottom': '0px'}}
className="chooseDes pr"
>
<TPMMDEditor ref={this.contentMdRef} placeholder="请输入简介" mdID={'courseContentMD'}
refreshTimeout={1500}
className="courseMessageMD"
// initValue={this.state.description === null ? "" : this.state.description}
></TPMMDEditor>
</Form.Item>
<Form.Item
label={"难易度"}
style={{"borderBottom": 'none'}}
className="chooseDes pr"
>
{getFieldDecorator('select', {
rules: [{required: true, message: '请选择难易度'}],
})(
<div className="with15 fl pr">
<Select placeholder="请选择难易度"
style={{width: 180}}
onChange={this.Selectthestudent}
>
<Option value={1}>初级</Option>
<Option value={2}>中级</Option>
<Option value={3}>中高级</Option>
<Option value={4}>高级</Option>
</Select>
</div>
)}
<span className="fl ml20 color-grey">实训的难易程度</span>
</Form.Item>
<Form.Item
label={"实验环境"}
style={{"borderBottom": 'none', 'width': '18%', 'float': 'left'}}
className="chooseDes pr"
>
<div>
{getFieldDecorator('selectleft', {
rules: [{required: true, message: '请选择主类别'}],
})(
<div className="width100 fl mr20">
<Select placeholder="请选择主类别"
style={{width: 180}}
onChange={this.selectleft}
defaultOpen={false}
>
{
newshixunlist === undefined ? "" : newshixunlist.main_type.map((item, key) => {
return (
<Option value={item.id} key={key}>
<Tooltip placement="right"
title={item.description === "" ? "无描述" : item.description}>
{item.type_name}
</Tooltip>
</Option>
)
})
}
</Select>
</div>
)}
</div>
</Form.Item>
<Form.Item
style={{"borderBottom": 'none', 'width': '61%', 'float': 'left', 'marginTop': '40px'}}
className="chooseDes pr"
>
<div className=" fl pr mr20">
{getFieldDecorator('selectright', {
rules: [{required: true, message: '请选择小类别'}],
})(
<div className=" fl pr mr20">
<Select placeholder="请选择小类别"
style={{width: 180}}
onChange={this.selectright}
defaultOpen={false}
>
{
newshixunlist === undefined ? "" : newshixunlist.small_type.map((item, key) => {
return (
<Option value={item.id} key={key}>
<Tooltip placement="right"
title={item.description === "" ? "无描述" : item.description}>
{item.type_name}
</Tooltip>
</Option>
)
})
}
</Select>
</div>
)}
<span className="fl ml20 color-grey lineh-20">
<div>
<div className={"font-12"}>
已安装软件hadoop3.1.0jdk1.8
</div>
<div className={"font-12"}>
说明添加了hadoop3.1.0jdk1.8的源码包添加了hadoop3.1.0jdk1.8的源码包
</div>
</div>
</span>
</div>
</Form.Item>
<div className={"both"}></div>
<div className=" color-grey lineh-20 mb20">
没有实验环境
<a className="color-blue" onClick={this.post_apply}> 申请新建</a>
</div>
<Form.Item
label={"评测脚本"}
style={{"borderBottom": 'none'}}
className="chooseDes pr"
>
{getFieldDecorator('select', {
rules: [{required: true, message: '请选择评测脚本'}],
})(
<div className="with15 fl pr">
<Select placeholder="请选择评测脚本"
style={{width: 180}}
onChange={this.Selectthestudent}
>
<Option value={1}>初级</Option>
<Option value={2}>中级</Option>
<Option value={3}>中高级</Option>
<Option value={4}>高级</Option>
</Select>
</div>
)}
<span className="fl ml20 color-blue">
使用自定义脚本
<span className={"color-grey ml10"}>
<Icon type="exclamation-circle"/>
</span>
</span>
</Form.Item>
<div className="mt30 clearfix df">
<div
className={operateauthority === false ? 'nonemodel' : ""}
></div>
<div className="flex1">
<div className="fl" style={{border: '1px solid #ccc'}}>
<MonacoEditor
height="450"
width="1100"
language={this.state.language}
value={shixunmemoMDvalue}
options={{
selectOnLineNumbers: true
}}
onChange={this.getshixunmemoMDvalue}
// onChange={this.getshixunmemoMDvalue}
/>
</div>
</div>
</div>
</Form>
<span className="ant-form-text mt20" >私密版本库
<Checkbox>若需要对学员隐藏部分版本库内容时请选中选中即启用私密版本库请将需要对学员隐藏的文件存储在私密版本库</Checkbox>
</span>
{this.props.identity<3?<div className="edu-back-white padding40-20 mb20">
<p className="color-grey-6 font-16 mb30">服务配置</p>
{ shixun_service_configs&&shixun_service_configs.map((item,key)=>{
return(
<div key={key}>
<div id="5">
<div className="color-grey-6 font-16 mt30 mb20" id="shixun_scenario_type_name">
<span className={"fl"}>{item.name}</span>
{/*<span className={"fr mr40"} onClick={()=>this.Deselectlittle(item.mirror_repository_id)}><i className="fa fa-times-circle color-grey-c font-16 fl"></i></span>*/}
</div>
<div className="clearfix mb5">
<label className="panel-form-label fl">CPU()</label>
<div className="pr fl with80 status_con">
<input type="text" value={item.cpu_limit} onInput={(e)=>this.setConfigsInputs(e,key,1)}
className="panel-box-sizing task-form-100 task-height-40" placeholder="请输入类别名称" />
</div>
<div className="cl"></div>
</div>
<div className="clearfix mb5">
<label className="panel-form-label fl">最低CPU()</label>
<div className="pr fl with80 status_con">
<input type="text" value={item.lower_cpu_limit} onInput={(e)=>this.setConfigsInputs(e,key,2)}
className="panel-box-sizing task-form-100 task-height-40" placeholder="请输入类别名称" />
</div>
<div className="cl"></div>
</div>
<div className="clearfix mb5">
<label className="panel-form-label fl">内存限制(M)</label>
<div className="pr fl with80 status_con">
<input type="text" value={item.memory_limit} onInput={(e)=>this.setConfigsInputs(e,key,3)}
className="panel-box-sizing task-form-100 task-height-40" placeholder="请输入类别名称" />
</div>
<div className="cl"></div>
</div>
<div className="clearfix mb5">
<label className="panel-form-label fl">内存要求(M)</label>
<div className="pr fl with20 status_con">
<input type="text" value={item.request_limit} onInput={(e)=>this.setConfigsInputs(e,key,4)}
className="panel-box-sizing task-form-100 task-height-40" placeholder="请输入类别名称" />
</div>
<label className="panel-form-label fl" style={{width: '48%'}}>温馨提示纯编程类型实训建议使用默认值对于大数据等建议使用最大内存的30%</label>
<div className="cl"></div>
</div>
</div>
</div>
)
})}
</div> :""}
{postapplyvisible === true ? <style>
{
`
body{
overflow: hidden !important;
}
`
}
</style> : ""}
<Modal
keyboard={false}
title="申请新建"
visible={postapplyvisible}
closable={false}
footer={null}
width={850}
heigth={720}
>
<div>
<li className="clearfix ml82">
<label className="fl mt10 "><span
className="color-red fl mt3">*</span>&nbsp;&nbsp;</label>
<textarea
className={this.state.languagewritetype === true ? "fl task-form-80 task-height-150 bor-reds" : "fl task-form-80 task-height-150"}
style={{width: '89%', height: '100px'}}
onInput={this.setlanguagewrite}
value={languagewrite}
placeholder="请填写该镜像是基于什么语言示例Python"
id="demand_info"></textarea>
</li>
<div className={"color-red shixunspanred"}>{this.state.languagewritetype === true ? "请填写该镜像语言" : ""}</div>
<li className="clearfix ml1">
<label className="panel-form-label fl ml50"><span
className="color-red fl mt3">*</span>&nbsp;&nbsp;</label>
<textarea
className={this.state.systemenvironmenttype === true ? "fl task-form-80 task-height-150 bor-reds" : "fl task-form-80 task-height-150"}
onInput={this.setsystemenvironment}
style={{height: '100px'}}
value={systemenvironment}
placeholder="请填写该镜像是基于什么linux系统环境,代码运行环境"
id="demand_info"></textarea>
</li>
<div
className={"color-red shixunspanred"}>{this.state.systemenvironmenttype === true ? "请填写该镜像语言系统环境" : ""}</div>
<li className="clearfix">
<label className="fl mt10"><span
className="color-red fl mt3">*</span>&nbsp;&nbsp;</label>
<textarea
className={this.state.testcoderunmodetype === true ? "fl task-form-80 task-height-150 bor-reds" : "fl task-form-80 task-height-150"}
onInput={this.settestcoderunmode}
value={testcoderunmode}
style={{height: '100px'}}
placeholder="请填写该镜像中测试代码运行方式"
id="demand_info"></textarea>
</li>
<div
className={"color-red shixunspanred"}>{this.state.testcoderunmodetype === true ? "请填写该镜像测试代码运行方式" : ""}</div>
<li className="clearfix ml50">
<label className="panel-form-label fl mt-5"><span
className="color-red fl">*</span>&nbsp;&nbsp;</label>
<div className="mt10" style={{
display: "inline-block"
}}>
<Upload {...uploadProps}>
<Icon type="upload" className="fl mt3"> </Icon>
<span className="color-blue fl cdefault">上传附件</span>
<span className="color-grey-c fl ml10 ">(单个文件50M以内)</span>
</Upload>
</div>
</li>
<div className={"color-red shixunspanred"}>
{this.state.attachmentidstype === true ? "请上传附件" : ""}
</div>
<li className="edu-txt-center clearfix ">
<a className="pop_close task-btn mr30"
onClick={() => this.sendhideModaly()}
>取消</a>
<Button type="primary" onClick={() => this.sendsure_apply()}
className="task-btn task-btn-orange">确定</Button>
</li>
<div className="cl"></div>
</div>
{/*</Form>*/}
</Modal>
<Modal
keyboard={false}
title="提示"
visible={postapplytitle}
closable={false}
footer={null}
>
<div>
<div className="task-popup-content"><p
className="task-popup-text-center font-16"><span
className="font-17 mt10">新建申请已提交请等待管理员的审核</span></p>
<li className="font-14 mt15 color-grey-6 edu-txt-center">我们将在1-2个工作日内与您联系
</li>
</div>
<div className="task-popup-OK clearfix">
<a className="task-btn task-btn-orange"
onClick={this.yeshidemodel}>知道啦</a>
</div>
</div>
</Modal>
</div>
);
}
}
const TopShixuninformation = Form.create({name: 'newshixun'})(Shixuninformation);
export default TopShixuninformation;

File diff suppressed because it is too large Load Diff

@ -111,3 +111,18 @@ a.newuse_scope-btn {
.ml82{
margin-left:82px;
}
.Permanentban{
color:#5091FF !important;
border-color: #5091FF !important;
}
/*tab*/
.ant-tabs-nav{
padding-bottom:18px;
padding-top: 18px;
}
.ant-tabs-extra-content{
margin-top: 18px;
}

File diff suppressed because it is too large Load Diff

@ -344,7 +344,7 @@ export default class TPMMDEditor extends Component {
</div>
</div>
<div className={"fr rememberTip"}>
{noStorage == true ? ' ' : <p id={`e_tips_mdEditor_${mdID}`} className="edu-txt-right color-grey-cd font-12"> </p>}
{noStorage == true ? ' ' : <div id={`e_tips_mdEditor_${mdID}`} className="edu-txt-right color-grey-cd font-12"> </div>}
{/* {noStorage == true ? ' ' : <p id={`e_tips_mdEditor_${mdID}`} className="edu-txt-right color-grey-cd font-12"> </p>} */}
</div>
</React.Fragment>

@ -36,6 +36,10 @@ class TPMNav extends Component {
<Link to={`/shixuns/${shixunId}/collaborators`}
className={`${match.url.indexOf('collaborators') != -1 ? 'active' : ''} fl mr40`}>合作者</Link>
{/*jupyter*/}
<Link to={`/shixuns/${shixunId}/dataset`}
className={`${match.url.indexOf('dataset') != -1 ? 'active' : ''} fl mr40`}>数据集</Link>
<Link to={`/shixuns/${shixunId}/shixun_discuss`}
className={`${match.url.indexOf('shixun_discuss') != -1 ? 'active' : ''} fl mr40`}>评论</Link>
@ -45,10 +49,8 @@ class TPMNav extends Component {
{this.props.identity >2||this.props.identity===undefined?"":<Link to={`/shixuns/${shixunId}/audit_situation`}
className={`${match.url.indexOf('audit_situation') != -1 ? 'active' : ''} fl`}>审核情况</Link>}
<a
href={`/shixuns/${shixunId}/settings`} className="edu-default-btn edu-blueline-btn ml20 fr"
style={{display: this.props.identity >4||this.props.identity===undefined ? "none" : 'block'}}
>配置</a>
{this.props.identity >4||this.props.identity===undefined ? "":<Link to={`/shixuns/${shixunId}/settings`} className="edu-default-btn edu-blueline-btn ml20 fr"
>配置</Link>}
</div>
);
}

@ -0,0 +1,47 @@
/*
* @Description: jupyter tpi
* @Author: tangjiang
* @Github:
* @Date: 2019-12-11 08:35:23
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-11 09:13:09
*/
import './index.scss';
import React from 'react';
import SplitPane from 'react-split-pane';
import { Button } from 'antd';
import UserInfo from '../../developer/components/userInfo';
function JupyterTPI (props) {
return (
<div className="jupyter_area">
<div className="jupyter_header">
<UserInfo userInfo={{}} />
<p className="jupyter_title">
<span className="title_desc">MySQL数据库编程开发实训(基础篇)</span>
<span className="title_time">时间</span>
</p>
<p className="jupyter_btn">
{/* sync | poweroff */}
<Button className="btn_common" type="link" icon="sync">重置实训</Button>
<Button className="btn_common" type="link" icon="poweroff">退出实训</Button>
</p>
</div>
<div className="jupyter_ctx">
<SplitPane split="vertical" minSize={350} maxSize={-350} defaultSize="30%">
<div className={'split-pane-left'}>
左侧内容
</div>
<SplitPane split="vertical" defaultSize="100%" allowResize={false}>
<div>右侧内容</div>
<div />
</SplitPane>
</SplitPane>
</div>
</div>
);
}
export default JupyterTPI;

@ -0,0 +1,93 @@
.Resizer {
background: #000;
opacity: 0.2;
z-index: 1;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
-moz-background-clip: padding;
-webkit-background-clip: padding;
background-clip: padding-box;
}
.Resizer:hover {
-webkit-transition: all 2s ease;
transition: all 2s ease;
}
.Resizer.horizontal {
height: 11px;
margin: -5px 0;
border-top: 5px solid rgba(255, 255, 255, 0);
border-bottom: 5px solid rgba(255, 255, 255, 0);
cursor: row-resize;
width: 100%;
}
.Resizer.horizontal:hover {
border-top: 5px solid rgba(0, 0, 0, 0.5);
border-bottom: 5px solid rgba(0, 0, 0, 0.5);
}
.Resizer.vertical {
width: 11px;
margin: 0 -5px;
border-left: 5px solid rgba(255, 255, 255, 0);
border-right: 5px solid rgba(255, 255, 255, 0);
cursor: col-resize;
}
.Resizer.vertical:hover {
border-left: 5px solid rgba(0, 0, 0, 0.5);
border-right: 5px solid rgba(0, 0, 0, 0.5);
}
.Resizer.disabled {
cursor: not-allowed;
}
.Resizer.disabled:hover {
border-color: transparent;
}
.jupyter_area{
.jupyter_header{
position: relative;
height: 60px;
line-height: 60px;
background-color: #070F1A;
.jupyter_title{
display: flex;
flex-direction: column;
// justify-content: space-around;
align-items: center;
height: 100%;
color: #fff;
.title_desc{
margin-top: 12px;
font-size: 16px;
}
.title_time{
font-size: 12px;
}
// text-align: center;
}
.jupyter_btn{
position: absolute;
right: 10px;
top: 14px;
.btn_common:hover{
// background-color: #29BD8B;
color: #29BD8B;
}
}
}
.jupyter_ctx{
position: relative;
height: calc(100vh - 60px);
}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,111 @@
import React, { Component } from 'react';
import {Button,Form,Input} from 'antd';
import axios from 'axios';
import TPMMDEditor from '../../tpm/challengesnew/TPMMDEditor';
class Osshackathonmd extends Component{
constructor(props) {
super(props)
this.contentMdRef = React.createRef();
this.state={
title_num: 0,
title_value: undefined
}
}
componentDidUpdate =(prevState)=>{
// if(prevState!=this.props){
// let url=`/osshackathon/edit_hackathon.json`;
// axios.get(url).then((result)=>{
// if(result.status==200){
// this.setState({
// title_value:result.data.name
// })
// this.contentMdRef.current.setValue(result.data.description);
// }
// })
// }
}
componentDidMount(){
let url=`/osshackathon/edit_hackathon.json`;
axios.get(url).then((result)=>{
if(result.status==200){
this.setState({
title_value:result.data.name
})
this.contentMdRef.current.setValue(result.data.description === null ? "" : result.data.description);
}
})
}
// 输入title
changeTitle = (e) => {
// title_num: 60 - parseInt(e.target.value.length),
this.setState({
title_num: e.target.value.length,
title_value: e.target.value
})
}
handleSubmit = () => {
let {title_value}=this.state;
const mdContnet = this.contentMdRef.current.getValue().trim();
// if(mdContnet.length>10000){
// this.props.showNotification("内容超过10000个字");
// return
// }
let url=`/osshackathon/update_hackathon.json`;
axios.post(url,{
name:title_value,
description:mdContnet,
}
).then((response) => {
if(response.data.status===0){
this.props.getosshackathon()
this.props.hidehackathonedit()
this.props.showNotification(`提交成功`);
}
}).catch((error) => {
console.log(error)
})
}
render() {
// console.log(this.props.tabkey)
// console.log(chart_rules)
return (
<div className={"mt20"}>
<Form>
<Form.Item label="标题">
<Input placeholder="请输入标题"
value={this.state.title_value}
onInput={this.changeTitle}
className="searchView searchViewAfter h45input" style={{"width": "100%"}} maxLength="60"
addonAfter={String(this.state.title_value === undefined || this.state.title_value === null ? 0 : this.state.title_value.length) + "/60"}
/>
</Form.Item>
<Form.Item label="描述">
<TPMMDEditor ref={this.contentMdRef} placeholder="请输入描述" mdID={'courseContentMD'} refreshTimeout={1500}
className="courseMessageMD"
initValue={this.state.description === null ? "" : this.state.description}></TPMMDEditor>
</Form.Item>
</Form>
<div className="clearfix mt30 mb30">
<div className={"fr"}>
<Button type="primary" onClick={this.handleSubmit} className="defalutSubmitbtn fl mr20">提交</Button>
<a className="defalutCancelbtn fl" onClick={() => this.props.hidehackathonedit()}>取消</ a>
</div>
</div>
</div>
)
}
}
export default Osshackathonmd;

@ -394,4 +394,440 @@ a.white-btn.use_scope-btn:hover{
.ant-btn:hover, .ant-btn:focus, .ant-btn:active, .ant-btn.active{
background-color: #4CACFF;
}
.newViewAfter .ant-input{
line-height: 40px !important;
height: 40px !important;
box-shadow: none!important;
}
.width30{
width: 30%;
}
.newshixunheadersear{
display: -ms-flexbox;
display: flex;
-ms-flex-pack: center;
justify-content: center;
margin: 0 auto;
}
.packinput .ant-input{
height: 55px;
width:663px !important;
font-size: 14px;
/*color: #681616 !important;*/
border-color: #E1EDF8 !important;
padding-left: 20px;
}
.packinput .ant-input-group-addon .ant-btn{
width:137px !important;
font-size: 18px;
height: 53px;
background:rgba(76,172,255,1);
}
.tabtitle{
height: 62px !important;
-webkit-box-shadow: 3px 10px 21px 0px rgba(76, 76, 76, 0.15);
box-shadow: 3px 10px 21px 0px rgba(76, 76, 76, 0.15);
border-radius: 6px;
background: #fff;
display: -ms-flexbox;
display: flex;
-ms-flex-pack: center;
justify-content: center;
}
.tabtitles2{
background: #fff;
height: 62px !important;
width: 1200px;
}
.tabtitless{
height: 62px !important;
line-height: 62px !important;
}
.tabtitle1{
}
.tabtitle2{
margin-left: 30px !important;
}
.counttit{
display: -ms-flexbox;
display: flex;
-ms-flex-pack: center;
justify-content: center;
}
.counttittext{
text-align: left;
width: 1200px;
height: 18px;
color: #888888;
font-size: 13px;
margin-top: 24px;
}
.counttittexts{
color: #4CACFF !important;
font-size: 13px;
}
.mainx{
display: -ms-flexbox;
display: flex;
-ms-flex-pack: center;
justify-content: center;
margin-top: 17px;
}
.project-packages-list{
}
.project-package-item{
display: -ms-flexbox;
display: flex;
-ms-flex-direction:column;
flex-direction:column;
margin-bottom: 20px;
padding: 20px;
background: white;
/* box-shadow: 1px 3px 3px 1px rgba(156,156,156,0.16); */
}
.xuxianpro{
height: 20px;
border-bottom: 1px dashed;
border-color: #EAEAEA;
margin-bottom: 18px;
}
.magr11{
margin-top: 11px;
}
.highlight{
color: #4CACFF;
}
.fonttext{
font-size: 20px;
font-weight:bold;
}
.fontextcolor{
color: #777777;
}
.tzbq{
margin-left: 68px;
}
.tzbqx{
/* margin-left: 24px; */
}
.bjyss{
background: #F8F8F8;
}
.zj{
overflow:hidden;
-o-text-overflow:ellipsis;
text-overflow:ellipsis;
white-space:nowrap
}
.ziticor{
color: #777777;
font-size: 13px;
}
.foohter{
margin-top: 20px;
display: -ms-flexbox;
display: flex;
-ms-flex-direction:row;
flex-direction:row;
}
.maxwidth1100{
max-width: 1100px;
overflow:hidden;
-o-text-overflow:ellipsis;
text-overflow:ellipsis;
white-space:nowrap;
font-size: 18px !important;
font-weight: 500;
color: rgba(51,51,51,1) !important;
}
.newshixunmodelmidfont{
font-size: 14px;
font-weight: 400;
color: #999999;
margin-top: 15px;
margin-left: 30px;
max-width: 1100px;
overflow: hidden;
-o-text-overflow: ellipsis;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
}
.newshixunmodelbotfont{
font-size:12px;
font-weight:400;
color:rgba(102,102,102,1);
margin-top: 15px;
margin-left: 30px;
}
.newshixunlist{
max-height:227px;
width: 1200px;
}
.xuxianpro {
height: 20px;
border-bottom: 1px dashed;
border-color: #eaeaea;
margin-bottom: 18px;
}
.newshixunpd030{
padding: 0px 30px;
}
.pd303010{
padding: 30px 30px 10px;
}
.newshixunfont12{
font-size: 12px;
color: rgba(76,172,255,1);
line-height: 21px;
}
.newshixunmode{
width: 100px;
height: 38px;
border-radius: 3px;
/*border: 1px solid rgba(191,191,191,1);*/
}
.ntopsj {
position: absolute;
top: -4px;
}
.nyslbottomsj {
position: absolute;
bottom: -6px;
}
.inherits .ant-dropdown-menu-item{
cursor: inherit !important;
}
.menus{
width: 91px;
text-align: center;
}
.newshixunmodelbotfont span{
display: inline-block;
margin-right: 34px;
}
.minhegiht300{
min-height: 300px;
}
.newshixunlist:hover{
-webkit-box-shadow: 1px 6px 16px rgba(156,156,156,0.16);
box-shadow: 1px 6px 16px rgba(156,156,156,0.16);
opacity: 1;
border-radius: 2px;
}
.newshixun500{
max-width: 500px;
overflow: hidden;
-o-text-overflow: ellipsis;
text-overflow: ellipsis;
white-space: nowrap;
}
.mt3 {
margin-top: 3px !important;
}
.highlight{
color: #4CACFF;
}
.newshixunbottombtn{
position: fixed;
z-index: 1000;
bottom: 0px;
width: 100%;
height: 63px;
background: rgba(255,255,255,1);
-webkit-box-shadow: 0px -4px 4px 0px rgba(0,0,0,0.05);
box-shadow: 0px -4px 4px 0px rgba(0,0,0,0.05);
}
.mb60shixun{
margin-bottom: 60px !important;
}
.padding13-30 {
padding: 13px 30px;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
.displaymodulat {
display: -ms-flexbox;
display: flex;
display: -webkit-flex;
-ms-flex-direction: column;
flex-direction: column;
-ms-flex-align: center;
align-items: center;
}
.WordNumberTextarea {
outline: none; /* 去掉输入字符时的默认样式 */
appearance: none;
-webkit-appearance: none;
-moz-appearance: none;
background-color: white;
text-shadow: none;
-webkit-writing-mode: horizontal-tb !important;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
resize: none; /*禁止拉伸*/
border: none; /*去掉默认边框*/
width: 100%;
height: 130px;
border: none;
display: block;
}
.WordNumbernote {
padding: 0;
margin: 0;
list-style: none;
text-decoration: none;
-webkit-box-sizing: border-box;
box-sizing: border-box;
overflow: hidden;
height: auto;
border: 1px solid rgba(234, 234, 234, 1);
border-radius: 0.125rem;
margin: 10px 10px 0px 10px;
padding: 10px 10px 5px 10px;
backgroud: rgba(234, 234, 234, 1);
width: 530px;
margin-left: 10px;
margin-top: 25px;
height: 214px !important;
}
.WordNumbernote .WordNumberTextarea {
outline: none;
appearance: none;
-webkit-appearance: none;
-moz-appearance: none;
background-color: white;
text-shadow: none;
-webkit-writing-mode: horizontal-tb !important;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
resize: none;
border: none;
width: 100%;
height: 169px !important;
border: none;
display: block;
}
.WordNumberTextarea-count {
display: inline-block;
float: right;
font-size: 16px;
color: #adadad;
padding-right: 0.25rem;
}
.borerinput {
border: 1px solid #DD1717 !important;
}
.borerinputs {
border: 1px solid #eee !important;
}
.mexertwo {
display: -ms-flexbox;
display: flex;
-ms-flex-direction: initial;
flex-direction: initial;
}
.mexeheigth {
line-height: 40px;
}
.mexeheigth2 {
line-height: 40px;
width: 74px;
}
.minbuttionte {
/* display: flex; */
margin-top: 20px;
width: 100%;
/* align-items: center; */
margin-bottom: 17px;
display: -ms-flexbox;
display: flex;
-ms-flex-direction: column;
flex-direction: column;
-ms-flex-align: center;
align-items: center;
-ms-flex-pack: center;
justify-content: center;
-ms-flex-direction: initial;
flex-direction: initial;
}
.initialflex{
display: -ms-flexbox;
display: flex;
-ms-flex-direction:initial;
flex-direction:initial;
}
.newshixunheadersear{
margin: 0 auto;
}
.newshixunmodels{
margin: 0 auto;
}
.backgroundFFF{
background: #FFF !important;
}
.relative{
position: relative;
}
.pd40px{
padding-bottom: 40px;
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,281 @@
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 ReactDOM from 'react-dom';
import axios from 'axios';
import AccountProfile from"../../../user/AccountProfile";
const $ = window.$;
class Challengesjupyter extends Component {
constructor(props) {
super(props)
this.state = {
ChallengesDataList: undefined,
operate: true,
startbtns: false,
iFrameHeight: '0px',
jupyter_port:0,
jupyter_url:null,
}
}
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);
console.log("componentDidMount");
console.log("Challengesjupyter");
console.log(this.props);
}
updatamakedown = (id) => {
}
// 关卡的上移下移操作
operations = (sumid, type) => {
}
delOperations = (sumid) => {
}
clonedelOperationss = () => {
}
delOperationss = () => {
}
startgameid=(id)=>{
}
hidestartshixunsreplace=(url)=>{
}
//编辑实训题目选择题
EditTraining=(type, ids, path)=>{
}
//开始实战按钮
startshixunCombat = (type, ids, id) => {
}
hidestartshixunCombattype=()=>{
}
hideAccountProfile=()=>{
};
modifyjupyter=(propsysl)=>{
console.log("propsysl");
console.log(propsysl);
let id=this.props.match.params.shixunId;
const url=`/shixuns/${id}/update_jupyter.json`;
const data={
identifier:id,
jupyter_port:propsysl.shixunsDetails.jupyter_port
}
axios.post(url, data)
.then((result) => {
if (result.data.status == 0) {
this.props.showNotification(`应用成功`);
}
}).catch((error) => {
})
}
sendToken=()=>{
// console.log("sendToken");
// const iframe = document.getElementById('iframe');
// console.log("modifyjupyter");
// const frameWindow = iframe.contentWindow;
// console.log("frameWindow");
// console.log(frameWindow);
}
render() {
let{ChallengesDataList}=this.state;
let id = this.props.match.params.shixunId;
// var deptObjs=document.getElementById("IFRAMEID").contentWindow.document.getElementById("TAGID");
// //判断此元素是否存在
// if(deptObjs!=null){
// //设置该元素的样式或其他属性
// deptObjs.setAttribute('style',' height: 20px !important;'); //!important用来提升指定样式条目的应用优先权
// }
// var submitObj = document.getElementById('submit');
// if(submitObj){
// submitObj.style.color = 'green';
// }
// const dom = document.getElementById('shutdown');
// ReactDOM.unmountComponentAtNode(dom)
// // window.$('#picture_display').hide();
// window.$('.data-tip-right').hide()
// window.onload=()=>{
// debugger
// var _iframe = document.getElementById('header');
// console.log(_iframe);
// // .contentWindow.document.getElementById('shutdown_widget') //get iframe下的id
// // _iframe.style.display= "none"; //修改样式
// }
return (
<React.Fragment>
<div className="mt30 pl20 pr20" >
<p className="clearfix mb20">
<span className="font-16 fl">简介</span>
<Tooltip placement="bottom" title={"编辑"}>
<a style={{ display: this.props.identity < 5 && ChallengesDataList&&ChallengesDataList.shixun_status < 3 ? "block" : 'none' }}
href={"/shixuns/" + id + "/settings?edit=1"} className="ring-green fr">
<img src={getImageUrl("images/educoder/icon/edit.svg")} className="fl mt3 ml2" />
</a>
</Tooltip>
</p>
<div className="justify break_full_word new_li "
id="challenge_editorMd_description">
<p id="ReactMarkdown" style={{overflow:'hidden'}}>
{ChallengesDataList === undefined ? "" :ChallengesDataList&&ChallengesDataList.description===null?"":
<div className={"markdown-body"} dangerouslySetInnerHTML={{__html: markdownToHTML(ChallengesDataList.description).replace(/▁/g,"▁▁▁")}}></div>
}
</p>
<style>
{
`
.intermediatecenter{
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.sortinxdirection{
display: flex;
flex-direction:row;
}
.xaxisreverseorder{
display: flex;
flex-direction:row-reverse;
}
`
}
</style>
<div className="sortinxdirection mt60">
<div className="renwuxiangssi sortinxdirection">
<div><p className="renwuxiangqdiv">任务详情</p></div> <div><p className="renwuxiangqdivtest ml24"></p></div>
</div>
<div className="renwuxiangssit xaxisreverseorder"><div className="challenbaocun" onClick={()=>this.modifyjupyter(this.props)}><p className="challenbaocuntest">应用到实训</p></div></div>
</div>
<style>
{
`
iframe {
border-width: 0px;
border-style: inset;
border-color: initial;
border-image: initial;
}
iframe {
border-left: 1px solid #eeeeee;
border-top: 1px solid #eeeeee;
border-right: 1px solid #eeeeee;
border-bottom: 1px solid #eeeeee;
}
#header{
visibility:hidden;
}
`
}
</style>
<div className="mt35">
{/*https://48888.jupyter.educoder.net/tree?*/}
<div className="pb47">
{
this.props.shixunsDetails===null || this.props.shixunsDetails===undefined||JSON.stringify(this.props.shixunsDetails)==="{}"?
""
:
(
this.props&&this.props.shixunsDetails&&this.props.shixunsDetails.jupyter_url?
<iframe src={this.props.shixunsDetails.jupyter_url}
sandbox="allow-same-origin allow-scripts allow-top-navigation " scrolling="no" id="frame"
name="framename" width="100%" height="700" frameBorder="0"
></iframe>
:""
)
}
</div>
</div>
</div>
</div>
</React.Fragment>
)
}
}
export default Challengesjupyter;

@ -6,4 +6,126 @@
.line27{
line-height: 27px;
vertical-align: 1px;
}
}
/* 中间居中 */
.intermediatecenter{
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
/* 简单居中 */
.intermediatecenterysls{
display: flex;
align-items: center;
}
.spacearound{
display: flex;
justify-content: space-around;
}
.spacebetween{
display: flex;
justify-content: space-between;
}
/* 头顶部居中 */
.topcenter{
display: -webkit-flex;
flex-direction: column;
align-items: center;
}
/* x轴正方向排序 */
/* 一 二 三 四 五 六 七 八 */
.sortinxdirection{
display: flex;
flex-direction:row;
}
/* x轴反方向排序 */
/* 八 七 六 五 四 三 二 一 */
.xaxisreverseorder{
display: flex;
flex-direction:row-reverse;
}
/* 垂直布局 正方向*/
/*
*/
.verticallayout{
display: flex;
flex-direction:column;
}
/* 垂直布局 反方向*/
.reversedirection{
display: flex;
flex-direction:column-reverse;
}
.yslwushiwidth{
width: 50%;
}
.yslwushiwidth90{
width: 90%;
}
.yslwushiwidth10{
width: 10%;
}
.yslwushiwidthbuton{
width: 110px;
}
.yslwushiwidthcolortest{
color: #A8A8A8;
font-size:16px;
}
.yslusername{
color: #000000;
font-size: 18px;
}
.yslusercjz{
width:60px;
height:28px;
border-radius:3px;
border:1px solid #F38B03;
}
.yslusercjztest{
width:60px;
height:28px;
font-size:16px;
color:#F38B03;
line-height:28px;
text-align: center;
}
.w18{
width: 18px;
}
.maxnamewidth150{
width: 150px;
max-width: 150px;
overflow:hidden;
text-overflow:ellipsis;
white-space:nowrap;
cursor: default;
}
.fabushixunwidth{
color: #000000;
font-size: 16px;
}
.fabushixunwidthcolor{
color: #4CACFF;
font-size: 16px;
}
.divfontexdivs{
border-left: 1px solid #eeeeee;
border-top: 1px solid #eeeeee;
border-right: 1px solid #eeeeee;
border-bottom: 1px solid #eeeeee;
}

@ -2,7 +2,7 @@ import React, { Component } from 'react';
import { Redirect } from 'react-router';
import {Modal, Button, Radio, Input, Checkbox,message,Spin, Icon} from 'antd';
import {Modal, Button, Radio, Input, Checkbox,message,Spin, Icon,Pagination} from 'antd';
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
@ -48,7 +48,9 @@ class Collaborators extends Component {
user_name:undefined,
school_name:undefined,
spinnings:false,
useristrue:false
useristrue:false,
mylistansum:6,
limit:20,
}
}
componentDidMount() {
@ -434,7 +436,10 @@ class Collaborators extends Component {
collaboratorListsumtype,
user_name,
school_name,
useristrue
useristrue,
mylistansum,
page,
limit
} = this.state;
let {loadingContent} = this.props;
const radioStyle = {
@ -448,18 +453,26 @@ class Collaborators extends Component {
console.log(Searchadmin)
return (
<React.Fragment>
<p className="clearfix mt30"
style={{display:this.props.identity<5?"block":"none"}}
<p className=" mt30 sortinxdirection"
style={{display:this.props.identity<5?"flex":"none"}}
>
<a onClick={() => this.showCollaboratorsvisible("cooperation")}
className="edu-default-btn edu-greenback-btn fr mr20 height40"
data-remote="true">
<span className={"line27"}>+ </span>
</a>
<a onClick={() => this.showCollaboratorsvisible("admin")}
style={{display:this.props.identity===1?"block":"none"}}
data-remote="true"
className="edu-default-btn edu-greenback-btn fr mr20 height40">更换管理员</a>
<div className="yslwushiwidth">
<p className="edu-default-btn edu-greenback-btn ml20 height40 yslwushiwidthcolortest">共12人</p>
</div>
<div className="yslwushiwidth xaxisreverseorder">
<a onClick={() => this.showCollaboratorsvisible("cooperation")}
className="edu-default-btn edu-greenback-btn mr20 height40 yslwushiwidthbuton"
data-remote="true">
<span className={"line27"}>+ </span>
</a>
<a onClick={() => this.showCollaboratorsvisible("admin")}
style={{display:this.props.identity===1?"flex":"none"}}
data-remote="true"
className="edu-default-btn edu-greenback-btn mr20 height40 yslwushiwidthbuton">更换管理员</a>
</div>
</p>
<Modal
@ -537,6 +550,8 @@ class Collaborators extends Component {
<span className="fl edu-txt-w100 task-hide font-bd">职业</span>
<span className="fl edu-txt-w180 task-hide font-bd ml80">单位</span>
</p>
<div className="mt5" style={{background: '#f7f9fd'}}>
<Spin indicator={antIcon} spinning={this.state.spinnings}>
<div className="clearfix">
@ -584,39 +599,58 @@ class Collaborators extends Component {
onClick={() => this.submit_add_collaborators_form()}>确定</a>
</div>
</Modal>:""}
<style>
{
`
.collaborators-item-middles{width: 100% !important; margin-left: 20px;}
.ysltithead{
padding-bottom: 20px;
}
`
}
</style>
<div className="pl20" id="collaborators_list_info">
{
collaboratorList===undefined?"":collaboratorList.map((item,key)=>{
if(key<collaboratorListsum){
return(
<div className="collaborators-item clearfix" key={key}>
<a href={item.user.user_url} target="_blank" className="mr20 fl">
<img alt="用户头像" className="radius" height="80" src={getImageUrl("images/"+item.user.image_url)} width="80"/></a>
<div className="fl collaborators-item-middle">
<p className="mb10">
<a href={item.user.user_url} target="_blank">{item.user.name}</a>
<span className="ml20" style={{display:this.props.power===false?"none":"inline-block"}}>{item.user.shixun_manager === true ? "(管理员)" : ""}</span>
</p>
<div className="collaborators-item clearfix sortinxdirection ysltithead" key={key}>
<a href={item.user.user_url} target="_blank" className="mr20 fl">
<img alt="用户头像" className="radius" height="80" src={getImageUrl("images/"+item.user.image_url)} width="80"/></a>
<p className="color-grey-B2 font-12 mb10"><span className="mr20">{item.user.identity}</span><span>{item.user.school_name}</span></p>
<p className="mb10">
<span className="mr20">发布&nbsp;&nbsp;{item.user.user_shixuns_count}</span>
{/*<span>粉丝&nbsp;&nbsp;*/}
{/*<span id="user_h_fan_count">{item.user.fans_count}</span>*/}
{/*</span>*/}
</p>
<div className="fl collaborators-item-middles">
<p className="mb10 ">
<a href={item.user.user_url} target="_blank" className="yslusername">{item.user.name}</a>
{/* <p className="color-grey-B2 task-hide">{item.user.brief_introduction}</p> */}
<span className={item&&item.user&&item.user.shixun_manager === true?"ml20 yslusercjz ":"ml20"} style={{display:this.props.power===false?"none":"inline-block"}}><p className="yslusercjztest">{item.user.shixun_manager === true ? "创建者" : ""}</p></span>
</p>
<p className="color-grey-B2 font-12 mb10 sortinxdirection mt14">
<p className="yslwushiwidth90 sortinxdirection">
<p className="mr20 font-16 w70">{item.user.identity}</p>
<p className={item.user.school_name===null||item.user.school_name===""?"":"mr40 font-16 maxnamewidth150"}>{item.user.school_name}</p>
<p className="fabushixunwidth">发布实训项目&nbsp;&nbsp;<span className="fabushixunwidthcolor ml2">{item.user.user_shixuns_count}</span></p>
</p>
<div className="xaxisreverseorder yslwushiwidth10">
{item.user.shixun_manager === true ? "" :
<i className="iconfont icon-shanchu newbianji1 color-grey-c font-16 w40"
style={{display: this.props.power === false ? "none" : "block"}}
onClick={() => this.collaborators_delete(item.user.user_id)}>
</i>
}
</div>
</p>
{/*<p className="mb10">*/}
{/* */}
{/* /!*<span>粉丝&nbsp;&nbsp;*!/*/}
{/* /!*<span id="user_h_fan_count">{item.user.fans_count}</span>*!/*/}
{/* /!*</span>*!/*/}
{/*</p>*/}
{/* <p className="color-grey-B2 task-hide">{item.user.brief_introduction}</p> */}
</div>
{item.user.shixun_manager === true ? "" : <a className="fr color-grey-c mr40 mt35 font-16"
style={{display: this.props.power === false ? "none" : "block"}}
onClick={() => this.collaborators_delete(item.user.user_id)}>删除</a>}
{/*<a href="/watchers/unwatch?object_id=3039&amp;object_type=user&amp;shixun_id=61&amp;target_id=3039" className="fr user_default_btn user_private_btn mt30 font-16 mr20" data-method="post" data-remote="true" rel="nofollow">取消关注</a>*/}
</div>
@ -647,7 +681,18 @@ class Collaborators extends Component {
className={collaboratorList.length>10&&collaboratorListsumtype===true?"":"none"}
style={{textAlign:'center',borderTop:'1px solid #eee'}}>
<a className="loadMore" onClick={this.loadMore}>加载更多</a>
</div>
{/*{*/}
{/* mylistansum>5?*/}
{/* <div className="edu-txt-center mt40 mb40">*/}
{/* <Pagination showQuickJumper current={page}*/}
{/* onChange={this.paginationonChanges} pageSize={limit}*/}
{/* total={mylistansum}*/}
{/* ></Pagination>*/}
{/* </div>*/}
{/* :""*/}
{/*}*/}
</div>
</React.Fragment>

@ -25,4 +25,44 @@
.addshixuns{
height: 27px;
line-height: 25px;
}
}
.challenbaocun{
width:103px;
height:30px;
background:#29BD8B;
border-radius:3px;
}
.challenbaocuntest{
width:103px;
height:30px;
font-size:16px;
color:#FFFFFF;
text-align: center;
line-height:30px;
}
.renwuxiangqdiv{
width:72px;
height:30px;
font-size:18px;
color:#000000;
line-height:30px;
}
.renwuxiangqdivtest{
width:32px;
height:30px;
font-size:16px;
font-family:MicrosoftYaHei;
color:#4CACFF;
line-height:30px;
}
.renwuxiangssi{
width: 30%;
}
.renwuxiangssit{
width: 70%;
}
.pb47{
padding-bottom: 47px;
}

@ -95,6 +95,33 @@ class ShixunCard extends Component {
left: 10px;
bottom: 125px;
}
.tag-org{
position: absolute;
left: 0px;
top: 20px;
}
.tag-org-name{
width:66px;
height:28px;
background:#FF6802;
width:66px;
height:28px;
border-radius:0px 20px 20px 0px;
}
.tag-org-name-test{
width:45px;
height:23px;
font-size:14px;
color:#FFFFFF;
line-height:19px;
margin-right: 6px;
}
.intermediatecenter{
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
`
}
</style>
@ -105,6 +132,14 @@ class ShixunCard extends Component {
{/*<img style={{display:'block',height: '28px'}} src={require(`./shixunCss/tag2.png`)}/>*/}
</div>
}
{
item.is_jupyter===true?
<div className="tag-org">
<p className="tag-org-name intermediatecenter"> <span className="tag-org-name-test">Jupyter</span></p>
{/*<img style={{display:'block',height: '28px'}} src={require(`./shixunCss/tag2.png`)}/>*/}
</div>
:""}
<div className={item.power === false ? "closeSquare" : "none"}>
<img src={getImageUrl("images/educoder/icon/lockclose.svg")}
className="mt80 mb25"/>

@ -404,7 +404,7 @@ class ShixunsIndex extends Component {
{...this.state}
OnSearchInput={this.OnSearchInput.bind(this)}
/>
{/*下方图片*/}
<ShixunCard
typepvisible={typepvisible}
middleshixundata={middleshixundata.shixuns}

@ -0,0 +1,121 @@
.tpmborder{
border: 1px solid;
}
/* 中间居中 */
.intermediatecenter{
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
/* 简单居中 */
.intermediatecenterysls{
display: flex;
align-items: center;
}
.spacearound{
display: flex;
justify-content: space-around;
}
.spacebetween{
display: flex;
justify-content: space-between;
}
/* 头顶部居中 */
.topcenter{
display: -webkit-flex;
flex-direction: column;
align-items: center;
}
/* x轴正方向排序 */
/* 一 二 三 四 五 六 七 八 */
.sortinxdirection{
display: flex;
flex-direction:row;
}
/* x轴反方向排序 */
/* 八 七 六 五 四 三 二 一 */
.xaxisreverseorder{
display: flex;
flex-direction:row-reverse;
}
/* 垂直布局 正方向*/
/*
*/
.verticallayout{
display: flex;
flex-direction:column;
}
/* 垂直布局 反方向*/
.reversedirection{
display: flex;
flex-direction:column-reverse;
}
.deletebutom{
width:85px;
height:30px;
background:#C4C4C4;
border-radius:3px;
}
.deletebutomtext{
width:28px;
height:19px;
font-size:14px;
color:#FFFFFF;
line-height:19px;
}
.deletebuttom{
width:85px;
height:30px;
background:#29BD8B;
border-radius:3px;
}
.deletebuttomtest{
width:56px;
height:19px;
font-size:14px;
color:#FFFFFF;
line-height:19px;
}
.tpmwidth{
width: 50%;
}
.mr21{
margin-right: 21px;
}
.wenjiantit{
width: 300px;
}
.zuihoushijian{
width: 125px;
}
.zuihouxiugairen{
width: 70px;
}
.wenjiandaxiao{
width: 56px;
}
.deletebutomtextcode{
width:85px;
height:30px;
background:#FF5555;
border-radius:3px;
}
.light-row{
background: #F7F7F8;
}
.dark-row{
background: #FFFFFF;
}

@ -48,6 +48,8 @@ const types = {
GET_COMMIT_RECORD_DETAIL_BY_ID: 'GET_COMMIT_RECORD_DETAIL_BY_ID', // 根据id号获取提交记录详情
RESTORE_INITIAL_CODE: 'RESTORE_INITIAL_CODE', // 恢复初始代码
SAVE_USER_INFO: 'SAVE_USER_INFO', // 只在用户信息
SAVE_HACK_IDENTIFIER: 'SAVE_HACK_IDENTIFIER', // 用户界面跑到编辑界面需要用的id值
SAVE_EDITOR_CODE: 'SAVE_EDITOR_CODE', // 保存详情页面中编辑时的代码
}
export default types;

@ -7,7 +7,11 @@
*/
import toggleTodo from './testAction.js';
import {getOJList, changePaginationInfo} from './ojList';
import {
getOJList,
changePaginationInfo,
deleteItem
} from './ojList';
import {
validateOjForm,
saveOjFormCode,
@ -41,6 +45,8 @@ import {
getUserProgramDetail,
saveUserProgramIdentifier,
restoreInitialCode,
saveUserCodeForInterval,
saveEditorCodeForDetail,
// isUpdateCodeCtx
} from './ojForUser';
@ -52,9 +58,14 @@ import {
isMyPublish,
} from './common';
import {
getUserInfoForNew
} from './user';
export default {
toggleTodo,
getOJList,
deleteItem,
changePaginationInfo,
getOJFormById,
saveOJFormId,
@ -90,5 +101,8 @@ export default {
updateOpenTestCaseIndex,
saveUserProgramIdentifier,
restoreInitialCode,
getUserInfoForNew,
saveUserCodeForInterval,
saveEditorCodeForDetail
// isUpdateCodeCtx
}

@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-11-27 13:42:11
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-06 17:56:02
* @LastEditTime: 2019-12-10 19:05:36
*/
import types from "./actionTypes";
import { Base64 } from 'js-base64';
@ -31,6 +31,11 @@ export const startProgramQuestion = (id, props) => {
type: types.SAVE_USER_PROGRAM_ID,
payload: identifier
});
// 保存id值
dispatch({
type: types.SAVE_HACK_IDENTIFIER,
payload: id
});
// 跳转至开启编程
if (identifier) {
// let data = Object.assign({}, props);
@ -74,8 +79,13 @@ export const getUserProgramDetail = (identifier, type) => {
dispatch({
type: types.GET_COMMIT_RECORD_DETAIL_BY_ID,
payload: data
})
});
}
// 保存用户登录信息
dispatch({
type: types.SAVE_USER_INFO,
payload: data.user
});
}
});
}
@ -277,10 +287,12 @@ export const getUserCommitRecordDetail = (identifier) => {
return (dispatch) => {
fetchUserCommitRecordDetail(identifier).then(res => {
console.log('提交记录详情======》》》》', res);
const { data } = res;
if (data.status === 401) return;
dispatch({
type: types.GET_COMMIT_RECORD_DETAIL_BY_ID,
payload: res.data
})
payload: data
});
});
}
}
@ -327,6 +339,11 @@ export const submitUserCode = (identifier, inputValue, type) => {
});
return;
};
// 将编辑代码清空
dispatch({
type: types.SAVE_EDITOR_CODE,
payload: ''
});
dispatch(debuggerCode(identifier, inputValue, type || 'submit'));
}
}).catch(() => {
@ -383,3 +400,10 @@ export const restoreInitialCode = (identifier) => {
}
}
// 保存详情页面中的编辑代码
export const saveEditorCodeForDetail = (code) => {
return {
type: types.SAVE_EDITOR_CODE,
payload: code
}
}

@ -4,13 +4,13 @@
* @Github:
* @Date: 2019-11-20 16:35:46
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-06 20:24:11
* @LastEditTime: 2019-12-10 19:54:56
*/
import types from './actionTypes';
import CONST from '../../constants';
import { fetchPostOjForm, fetchGetOjById, publishTask } from '../../services/ojService';
import { Base64 } from 'js-base64';
import { message, notification } from 'antd';
import { message, notification, Modal } from 'antd';
import { toStore } from 'educoder';
const { jcLabel } = CONST;
// 表单字段映射
@ -85,6 +85,7 @@ export const validateOjForm = (props, type) => {
return (dispatch, getState) => {
const {ojForm, testCases, identifier, code } = getState().ojFormReducer;
// console.log('code', code);
/** 表单验证开始 */
let keys = Object.keys(ojForm);
// 循环判断每个字段是否为空
let hasSuccess = true;
@ -104,14 +105,35 @@ export const validateOjForm = (props, type) => {
});
// 验证测试用例中的数组是否都有对应的值
const tcValidResult = [];
testCases.forEach(obj => {
// 验证测试用例: 1.必须要有输出值 2. 输入值与输出值必须唯一
testCases.forEach((obj, i) => {
let tempObj = {};
['input', 'output'].forEach(key => {
const value = obj[key];
const validateResult = emptyValidate(key, value);
// 非空校验
let validateResult = emptyValidate(key, value);
const errMsg = validateResult[key].errMsg;
if (errMsg) {
hasSuccess = false;
} else {
// 唯一性校验
const bool = testCases.some((item, j) => {
if (i !== j) {
return (item[key] === value);
} else {
return false;
}
});
if (bool) {
hasSuccess = false;
validateResult = {
[key]: {
validateStatus: 'error',
errMsg: key === 'input' ? '输入值必须是唯一的' : '输出值必须是唯一的'
}
};
}
}
Object.assign(tempObj, validateResult);
});
@ -151,6 +173,8 @@ export const validateOjForm = (props, type) => {
payload: false
});
}
/** 表单验证结束 */
/** 表单验证通过后,调用保存 or 更新 or 发布 */
if (hasSuccess) {
// console.log('表单保存的数据为: ', getState());
const {ojFormReducer} = getState();
@ -205,6 +229,7 @@ export const validateOjForm = (props, type) => {
paramsObj['identifier'] = identifier;
}
// 接口调用成功后,跳转至列表页
function linkToDev () {
toStore('oj_description', '');
dispatch({
@ -216,51 +241,61 @@ export const validateOjForm = (props, type) => {
}, 1000);
}
fetchPostOjForm(paramsObj).then(res => {
// TODO
if (res.status === 200) { // 保存成功后,重新跳转至列表页
const {identifier} = res.data
if (type === 'publish') { // 存在发布时,直接调用发布接口
if (identifier) {
publishTask(identifier).then(res => {
if (res.data.status === 0) {
message.success('发布成功!');
linkToDev();
}
dispatch({
type: types.PUBLISH_LOADING_STATUS,
payload: false
});
}).catch(() => {
dispatch({
type: types.PUBLISH_LOADING_STATUS,
payload: false
});
// 调用保存或更新
if (type === 'publish') {
// 提示发布信息
Modal.confirm({
title: '提示',
content: `
发布后即可应用到自己管理的课堂,
是否确定发布?`,
okText: '确定',
cancelText: '取消',
onOk () {
publishTask(identifier).then(res => {
if (res.data.status === 0) {
message.success('发布成功!');
linkToDev();
}
dispatch({
type: types.PUBLISH_LOADING_STATUS,
payload: false
});
} else {
}).catch(() => {
dispatch({
type: types.PUBLISH_LOADING_STATUS,
payload: false
});
}
} else {
});
},
onCancel () {
dispatch({
type: types.PUBLISH_LOADING_STATUS,
payload: false
});
}
});
} else {
// 调用更新
fetchPostOjForm(paramsObj).then(res => {
if (res.status === 200) { // 保存成功后,重新跳转至列表页
if (res.data.identifier) {
message.success('保存成功!');
linkToDev();
}
dispatch({
type: types.SUBMIT_LOADING_STATUS,
payload: false
});
}
}).catch(err => {
dispatch({
type: types.SUBMIT_LOADING_STATUS,
payload: false
});
}
}
}).catch(err => {
dispatch({
type: types.SUBMIT_LOADING_STATUS,
payload: false
});
});
);
}
}
}
};
@ -361,6 +396,11 @@ export const getOJFormById = (id) => {
type: types.SAVE_EDIT_OJ_FORM_AND_TEST_CASE,
payload: res.data
});
// 保存用户信息
dispatch({
type: types.SAVE_USER_INFO,
payload: res.data.user
});
});
}
}
@ -371,7 +411,7 @@ export const saveOJFormId = (id) => {
payload: id
}
}
// 清空测试用例集合
// 清空
export const clearOJFormStore = () => {
return {
type: types.CLEAR_JSFORM_STORE
@ -380,27 +420,76 @@ export const clearOJFormStore = () => {
// 测试用例输入值改变时
export const testCaseInputChange = (value, index) => {
const validate = emptyValidate('input', value)['input'];
return {
type: types.TEST_CASE_INPUT_CHANGE,
payload: {
input: validate,
value,
index
return (dispatch, getState) => {
// 非空校验
let validate = emptyValidate('input', value)['input'];
if (!validate.errMsg) {
// 唯一性校验
const {testCases} = getState().ojFormReducer;
const bool = testCases.some((item, i) => {
if (i !== index) {
return item['input'] === value;
} else {
return false;
}
});
if (bool) {
validate = {
validateStatus: 'error',
errMsg: '输入值必须唯一'
};
}
}
dispatch({
type: types.TEST_CASE_INPUT_CHANGE,
payload: {
input: validate,
value,
index
}
});
}
}
// 测试用例输出值改变时
export const testCaseOutputChange = (value, index) => {
const validate = emptyValidate('output', value)['output'];
return {
type: types.TEST_CASE_OUTPUT_CHANGE,
payload: {
output: validate,
value,
index
// const validate = emptyValidate('output', value)['output'];
// return {
// type: types.TEST_CASE_OUTPUT_CHANGE,
// payload: {
// output: validate,
// value,
// index
// }
// }
return (dispatch, getState) => {
// 非空校验
let validate = emptyValidate('output', value)['output'];
if (!validate.errMsg) {
// 唯一性校验
const {testCases} = getState().ojFormReducer;
const bool = testCases.some((item, i) => {
if (i !== index) {
return item['output'] === value;
} else {
return false;
}
});
if (bool) {
validate = {
validateStatus: 'error',
errMsg: '输入值必须唯一'
};
}
}
dispatch({
type: types.TEST_CASE_OUTPUT_CHANGE,
payload: {
output: validate,
value,
index
}
});
}
}

@ -4,10 +4,10 @@
* @Github:
* @Date: 2019-11-20 10:48:24
* @LastEditors: tangjiang
* @LastEditTime: 2019-11-29 11:09:54
* @LastEditTime: 2019-12-10 20:40:55
*/
import types from './actionTypes';
import { fetchOJList } from '../../services/ojService';
import { fetchOJList, fetchDeleteOJItem } from '../../services/ojService';
export const getOJList = (params) => {
return (dispatch) => {
@ -35,3 +35,15 @@ export const changePaginationInfo = (obj) => {
payload: obj
}
}
// 删除
export const deleteItem = (identifier) => {
return (dispatch, getState) => {
const {pagination} = getState().ojListReducer;
fetchDeleteOJItem(identifier).then(res => {
if (res.status === 200) {
dispatch(getOJList(pagination));
}
});
}
}

@ -4,13 +4,24 @@
* @Github:
* @Date: 2019-12-06 15:09:22
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-06 15:15:00
* @LastEditTime: 2019-12-09 20:34:50
*/
import types from './actionTypes';
import { fetchUserInfoForNew } from '../../services/ojService';
// 获取用户信息
export default function getUserInfo () {
export const getUserInfoForNew = () => {
return (dispatch) => {
// 调用获取用户信息, 如果没有登录直接调用登录,成功后保存当前用户信息
fetchUserInfoForNew().then(res => {
// console.log('获取用户信息成功: ', res);
const { data } = res;
if (data.status === 401) return;
dispatch({
type: types.SAVE_USER_INFO,
payload: data.user
});
})
}
}

@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-11-27 13:41:48
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-05 13:37:17
* @LastEditTime: 2019-12-10 10:09:59
*/
import types from "../actions/actionTypes";
import { Base64 } from 'js-base64';
@ -20,6 +20,8 @@ const initialState = {
userCodeTab: 'task', // 学员测评tab位置: task | record | comment
userTestInput: '', // 用户自定义输入值
recordDetail: {}, // 根据id号获取的记录详情
hack_identifier: '', // 用户界面编辑时
editor_code: '' // 保存编辑代码
};
const ojForUserReducer = (state = initialState, action) => {
@ -109,6 +111,16 @@ const ojForUserReducer = (state = initialState, action) => {
...state,
hack: Object.assign({}, curHack)
}
case types.SAVE_HACK_IDENTIFIER:
return {
...state,
hack_identifier: action.payload
}
case types.SAVE_EDITOR_CODE:
return {
...state,
editor_code: action.payload
}
default:
return state;
}

@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-11-20 16:40:32
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-05 09:35:29
* @LastEditTime: 2019-12-09 16:30:46
*/
import { Base64 } from 'js-base64';
import types from '../actions/actionTypes';
@ -16,8 +16,8 @@ const init = {
description: '',
difficult: 1,
category: 1,
openOrNot: 1,
timeLimit: ''
// openOrNot: 1,
timeLimit: 3
},
ojFormValidate: {
name: {
@ -40,10 +40,10 @@ const init = {
validateStatus: '',
errMsg: ''
},
openOrNot: {
validateStatus: '',
errMsg: ''
},
// openOrNot: {
// validateStatus: '',
// errMsg: ''
// },
timeLimit: {
validateStatus: '',
errMsg: ''
@ -64,7 +64,8 @@ const init = {
identifier: '', // OJ表单id
loading: false, // 僵尸loading标志
testCodeStatus: 'default', // 调试代码状态 default(默认值) | loading(加载中) | loaded(加载完成) | userCase(用户自定义测试用例) | finish(测试完成)
openTestCodeIndex: [0] // 展开的测试用例: 数组, 当出错时,展开所有出错的测试用例, 默认展开第一个
openTestCodeIndex: [0], // 展开的测试用例: 数组, 当出错时,展开所有出错的测试用例, 默认展开第一个
isPublish: 0, // 是否是发布状态: 0 未发布 1 已发布
}
const tcValidateObj = {
@ -167,7 +168,7 @@ const ojFormReducer = (state = initialState, action) => {
* 6. 更改测试用例状态
* 7. 添加测试用例验证
*/
const { code = '', description, language, name, hack_sets = [], time_limit, difficult, category } = action.payload;
const { code = '', description, language, name, hack_sets = [], time_limit, difficult, category, status } = action.payload;
const currentOjForm = {
name, // 任务名称
language,
@ -203,7 +204,8 @@ const ojFormReducer = (state = initialState, action) => {
code: cbcode,
testCases: curTestCases,
testCasesValidate: curTcValidates,
testCodeStatus: hack_sets.length > 0 ? 'userCase' : 'default'
testCodeStatus: hack_sets.length > 0 ? 'userCase' : 'default',
isPublish: status
}
case types.CLEAR_JSFORM_STORE:
state = Object.assign({}, init);

@ -20,12 +20,13 @@ class SearchPage extends Component{
page:1,
perpages:20,
data:[],
jupyterbool:false,
}
}
//切换tab
changeTab=(e)=>{
// course 课堂, shixun 开发社区 subject 实践课程 memo 交流问答
// course 2 课堂, shixun 0 实训项目 subject 1 实践课程 memo 3交流问答
let types ="";
if(parseInt(e.key)===0){
@ -106,7 +107,7 @@ class SearchPage extends Component{
}
}).then((response) => {
this.setState({ loading: false })
if(response === undefined){
return
@ -178,7 +179,19 @@ class SearchPage extends Component{
<div className="mainx">
<style>
{
`
.maxnamewidth92{
max-width: 92%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
cursor: default;
}
`
}
</style>
<div className="educontent project-packages-list mb30">
{data === undefined ? "" : data.map((item, key) => {
return (
@ -193,10 +206,28 @@ class SearchPage extends Component{
<div className={"font-16 color-dark fl "} style={{width:"100%"}} >
{/*标题*/}
<span className={"markdown-body fonttext"}
dangerouslySetInnerHTML={{__html:item.title}}/>
<div className="sortinxdirection jupytertextheig" style={{width:"100%"}}>
<span className={"markdown-body fonttext maxnamewidth92"}
dangerouslySetInnerHTML={{__html:item.title}}/>
{
type==="shixun"?
(
item.is_jupyter===true?
<div className="jupytertext intermediatecenter ml15"><p className="jupytertextp">Jupyter</p></div>
:""
)
:""
}
</div>
{/*描述*/}
<div>
{item.content.content === undefined || item.content.content===0?"": item.content.content.map((item4, key4) => {
return (
<span className={"markdown-body magr11 fontextcolor"}
@ -221,8 +252,8 @@ class SearchPage extends Component{
<div>
{/*挑战名字*/}
{item.content.challenge_names === undefined || item.content.challenge_names===0?"": item.content.challenge_names.map((item5, key5) => {
return (
<div className={"df"}>
@ -269,13 +300,13 @@ class SearchPage extends Component{
{/* <span className="ziticor">
<i className="fa fa-user ziticor"></i><span className="ml10">{item.author_name}</span>
</span>
<span className="ml10 ziticor "><span>{item.author_school_name}</span></span>
<span className="ml10 ziticor "><span>{item.author_school_name}</span></span>
<span className="ml20 ziticor">
<i className="iconfont icon-shixunguanqia ziticor"></i>
<span>任务:
<span className="ml10 ziticor">{item.challenges_count===undefined?0:item.challenges_count}</span>
</span>
</span>
</span>
<span className="ml20 ziticor">
<i className="iconfont icon-chengyuan ziticor"></i>
<span>学习人数:
@ -287,7 +318,7 @@ class SearchPage extends Component{
{/* <i className="fa fa-user ziticor"></i> */}
<span className="">{item.author_name}</span></span>
<span className="ml10 ziticor "><span>{item.author_school_name}</span>
</span>
</span>
{!!item.challenges_count && <span className="ml20 ziticor">
{/* <i className="iconfont icon-shixunguanqia ziticor"></i> */}
<span>任务:
@ -325,7 +356,7 @@ class SearchPage extends Component{
{/* <i className="iconfont icon-huifu1 ziticor"></i> */}
<span>回复数:<span className="ml10 ziticor">{item.all_replies_count}</span></span>
</span> }
{/* <span className="ml20 ziticor">
<i className="iconfont icon-chengyuan ziticor"></i>
<span>
@ -354,7 +385,7 @@ class SearchPage extends Component{
{
count && count && count> perpages ?
<div className="edu-txt-center" style={{paddingBottom:"30px"}}>
<div className="edu-txt-center" style={{marginBottom:"30px",paddingBottom:"30px"}}>
<Pagination showQuickJumper current={page}
onChange={this.paginationonChanges} pageSize={perpages}
total={count}></Pagination>
@ -368,4 +399,4 @@ class SearchPage extends Component{
}
}
export default SnackbarHOC() (TPMIndexHOC ( SearchPage ));
export default SnackbarHOC() (TPMIndexHOC ( SearchPage ));

@ -131,4 +131,45 @@
margin-top: 20px;
display: flex;
flex-direction:row;
}
}
.jupytertext{
width:54px;
height:24px;
background:#FF6802;
border-radius:2px 10px 10px 2px;
margin-top: 2px;
text-align: center;
}
.jupytertextp{
width:39px;
height:16px;
font-size:12px;
color:#FFFFFF;
line-height:16px;
}
/* x轴正方向排序 */
/* 一 二 三 四 五 六 七 八 */
.sortinxdirection{
display: flex;
flex-direction:row;
}
/* x轴反方向排序 */
/* 八 七 六 五 四 三 二 一 */
.xaxisreverseorder{
display: flex;
flex-direction:row-reverse;
}
.intermediatecenter{
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.jupytertextheig{
height: 32px;
line-height: 32px;
}
.ml9{
margin-left: 9px;
}

@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-11-20 10:55:38
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-04 18:05:10
* @LastEditTime: 2019-12-10 20:46:16
*/
import axios from 'axios';
@ -20,6 +20,12 @@ export async function fetchOJList (params) {
return axios.get('/problems.json', { params: obj });
}
// 删除OJ列表
export async function fetchDeleteOJItem (identifier) {
const url = `/problems/${identifier}.json`;
return axios.delete(url);
}
// 提交
export async function fetchPostOjForm (paramsObj) {
const { params, submitType, identifier } = paramsObj;
@ -106,3 +112,9 @@ export async function fetchRestoreInitialCode (identifier) {
const url = `/myproblems/${identifier}/restore_initial_code.json`;
return axios.post(url);
}
// 新建时调用获取用户信息接口
export async function fetchUserInfoForNew () {
const url = `/problems/new.json`;
return axios.get(url);
}

@ -674,7 +674,7 @@ input.radio-width90{ width: 90px; }
.ringauto{width: 20px;height: 20px;line-height: 20px;text-align: center;border-radius: 50%;background-color: #F4FAFF;margin-right:5px;}
/*-------------------个人主页:右侧提示区域--------------------------*/
.-task-sidebar{position:fixed;width:40px;height:180px;right:0;bottom:30px;z-index: 10;}
.-task-sidebar{position:fixed;width:40px;height:180px;right:0;bottom:80px;z-index: 10;}
.-task-sidebar div{height: 40px;line-height: 40px;box-sizing: border-box;width:40px;background:#4CACFF;color:#fff;font-size:20px;text-align:center;margin-bottom:5px;border-radius: 4px;}
.-task-sidebar div i{ color:#fff;}
.-task-sidebar div i:hover{color: #fff!important;}

Loading…
Cancel
Save