Merge branch 'dev_item_bank' of http://bdgit.educoder.net/Hjqreturn/educoder into dev_item_bank

dev_jupyter
cxt 5 years ago
commit 1fbf0960e7

@ -12,6 +12,7 @@ class ApplicationController < ActionController::Base
protect_from_forgery prepend: true, unless: -> { request.format.json? }
before_action :check_sign
before_action :user_setup
#before_action :check_account
@ -20,6 +21,21 @@ class ApplicationController < ActionController::Base
helper_method :current_user
# 所有请求必须合法签名
def check_sign
Rails.logger.info("66666 #{params}")
if params[:client_key].present?
Rails.logger.info("111111 #{params[:client_key]}")
Rails.logger.info("00000 #{params[:timestamp]}")
timestamp = params[:timestamp]
sign = Digest::MD5.hexdigest("#{OPENKEY}#{timestamp}")
Rails.logger.info("2222 #{sign}")
tip_exception(501, "请求不合理") if sign != params[:client_key]
else
tip_exception(501, "请求不合理")
end
end
# 全局配置参数
# 返回name对应的value
def edu_setting(name)
@ -259,6 +275,7 @@ class ApplicationController < ActionController::Base
# reacct静态资源加载不需要走这一步
return if params[:controller] == "main"
# Find the current user
Rails.logger.info("current_laboratory is #{current_laboratory} domain is #{request.subdomain}")
User.current = find_current_user
uid_logger("user_setup: " + (User.current.logged? ? "#{User.current.try(:login)} (id=#{User.current.try(:id)})" : "anonymous"))
@ -603,7 +620,7 @@ class ApplicationController < ActionController::Base
end
def paginate(relation)
limit = params[:limit].to_i.zero? ? 20 : params[:limit].to_i
limit = (params[:limit].to_i.zero? || params[:limit].to_i > 20) ? 20 : params[:limit].to_i
page = params[:page].to_i.zero? ? 1 : params[:page].to_i
offset = (page - 1) * limit
@ -678,4 +695,5 @@ class ApplicationController < ActionController::Base
HotSearchKeyword.add(keyword)
end
end

@ -16,7 +16,7 @@ class Cooperative::BaseController < ApplicationController
private
def current_laboratory
@_current_laboratory ||= Laboratory.find_by_subdomain(request.subdomain)
@_current_laboratory ||= (Laboratory.find_by_subdomain(request.subdomain) || Laboratory.first)
# @_current_laboratory ||= Laboratory.find 1
end

@ -5,6 +5,7 @@ class HackUserLastestCodesController < ApplicationController
before_action :update_user_hack_status, only: [:code_debug, :code_submit]
before_action :require_auth_identity, only: [:add_notes]
before_action :require_manager_identity, only: [:show, :update_code, :restore_initial_code, :sync_code]
skip_before_action :check_sign, only: [:listen_result]
def show
@my_hack.update_attribute(:submit_status, 0) if @my_hack.submit_status == 1
@ -85,7 +86,7 @@ class HackUserLastestCodesController < ApplicationController
testCase = ojEvaResult['testCase']
# 只有编译出错时,才正则匹配错误行数
error_line=
if params[:status] == "-4"
if ojEvaResult['status'] == "4" || ojEvaResult['status'] == "5"
regular_match_error_line ojEvaResult['outPut'], @my_hack.hack.language
end
# debug 与submit 公用的参数
@ -148,11 +149,12 @@ class HackUserLastestCodesController < ApplicationController
# 正则错误行数
def regular_match_error_line content, language
content = Base64.decode64(content).force_encoding("utf-8")
logger.info("######content: #{content}")
case language
when 'Java'
content.scan(/.java.\d+/).map{|s| s.match(/\d+/)[0].to_i}.min
when 'C', 'C++'
content.scan(/\d:\d+: error/).map{|s| s.match(/\d+/)[0]}.min
content.scan(/\d:\d+:/).map{|s| s.match(/\d+/)[0].to_i}.min
when 'Python'
content.scan(/line \d+/).map{|s| s.match(/\d+/)[0].to_i}.min
end

@ -1046,7 +1046,7 @@ class HomeworkCommonsController < ApplicationController
course_module_id: course_module.id, position: course_module.course_second_categories.count + 1)
# 去掉不对当前用户的单位公开的实训,已发布的实训
stage.shixuns.where.not(shixuns: {id: none_shixun_ids}).unhidden.each do |shixun|
stage.shixuns.no_jupyter.where.not(shixuns: {id: none_shixun_ids}).unhidden.each do |shixun|
homework = HomeworksService.new.create_homework shixun, @course, category, current_user
@homework_ids << homework.id
CreateStudentWorkJob.perform_later(homework.id)

@ -1,4 +1,6 @@
class MainController < ApplicationController
skip_before_action :check_sign
def index
render file: 'public/react/build/index.html', :layout => false
end

@ -3,6 +3,7 @@ class MyshixunsController < ApplicationController
before_action :find_myshixun, :except => [:training_task_status, :code_runinng_message]
before_action :find_repo_name, :except => [:training_task_status, :code_runinng_message]
skip_before_action :verify_authenticity_token, :only => [:html_content]
skip_before_action :check_sign, only: [:training_task_status, :code_runinng_message]
## TPI关卡列表
def challenges

@ -772,7 +772,7 @@ class ShixunsController < ApplicationController
# jupyter开启挑战
def jupyter_exec
begin
if is_shixun_opening?
tip_show_exception(-3, "#{@shixun.opening_time.strftime('%Y-%m-%d %H:%M:%S')}")
end
@ -786,22 +786,23 @@ class ShixunsController < ApplicationController
commit_id = commit["id"]
cloud_bridge = edu_setting('cloud_bridge')
myshixun_identifier = generate_identifier Myshixun, 10
ActiveRecord::Base.transaction do
@myshixun = @shixun.myshixuns.create!(user_id: current_user.id, identifier: myshixun_identifier,
modify_time: @shixun.modify_time, reset_time: @shixun.reset_time,
onclick_time: Time.now, commit_id: commit_id)
# fork仓库
project_fork(@myshixun, @repo_path, current_user.login)
rep_url = Base64.urlsafe_encode64(repo_ip_url @repo_path)
uri = "#{cloud_bridge}/bridge/game/openGameInstance"
params = {tpiID: "#{@myshixun.id}", tpmGitURL: rep_url, tpiRepoName: @myshixun.repo_name.split("/").last}
interface_post uri, params, 83, "服务器出现问题,请重置环境"
begin
ActiveRecord::Base.transaction do
@myshixun = @shixun.myshixuns.create!(user_id: current_user.id, identifier: myshixun_identifier,
modify_time: @shixun.modify_time, reset_time: @shixun.reset_time,
onclick_time: Time.now, commit_id: commit_id)
# fork仓库
project_fork(@myshixun, @repo_path, current_user.login)
rep_url = Base64.urlsafe_encode64(repo_ip_url @repo_path)
uri = "#{cloud_bridge}/bridge/game/openGameInstance"
params = {tpiID: "#{@myshixun.id}", tpmGitURL: rep_url, tpiRepoName: @myshixun.repo_name.split("/").last}
interface_post uri, params, 83, "服务器出现问题,请重置环境"
end
rescue => e
uid_logger_error(e.message)
tip_exception("服务器出现问题,请重置环境")
end
end
rescue => e
uid_logger_error(e.message)
tip_exception(e.message)
end
end
def publish

@ -255,7 +255,7 @@ class SubjectsController < ApplicationController
CourseSecondCategory.create!(name: stage.name, course_id: @course.id, category_type: "shixun_homework",
course_module_id: course_module.id, position: course_module.course_second_categories.count + 1)
stage.shixuns.where(id: params[:shixun_ids], status: 2).each do |shixun|
stage.shixuns.no_jupyter.where(id: params[:shixun_ids], status: 2).each do |shixun|
homework = HomeworksService.new.create_homework shixun, @course, category, current_user
homework_ids << homework.id
end

@ -226,7 +226,8 @@ module TidingDecorator
end
def discuss_content
I18n.t(locale_format(parent_container_type, container.parent_id.present?)) % message_content_helper(container.content)
I18n.t(locale_format(parent_container_type, container.parent_id.present?)) %
(parent_container_type == 'Hack' ? container.content : message_content_helper(container.content))
end
def grade_content

@ -83,6 +83,7 @@ class Shixun < ApplicationRecord
scope :publiced, lambda{ where(public: 2) }
scope :field_for_recommend, lambda{ select([:id, :name, :identifier, :myshixuns_count]) }
scope :find_by_ids,lambda{|k| where(id:k)}
scope :no_jupyter, -> { where(is_jupyter: false) }
after_create :send_tiding
#同步到trustie

@ -1,7 +1,8 @@
json.hack do
json.(@hack, :id, :name, :difficult, :time_limit, :description, :score, :identifier, :status, :praises_count)
json.language @hack.language
json.username @hack.user.real_name
json.username @hack.user&.real_name
json.user_path "/users/#{@hack.user&.login}"
json.code @my_hack.code
json.pass_count @hack.pass_num
json.submit_count @hack.submit_num
@ -19,5 +20,4 @@ json.user do
json.partial! 'users/user', user: current_user
json.hack_manager @hack.manager?(current_user)
json.admin current_user.admin_or_business?
end

@ -1,111 +0,0 @@
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
# Code is not reloaded between requests.
config.cache_classes = true
# Eager load code on boot. This eager loads most of Rails and
# your application in memory, allowing both threaded web servers
# and those relying on copy on write to perform better.
# Rake tasks automatically ignore this option for performance.
config.eager_load = true
# Full error reports are disabled and caching is turned on.
config.consider_all_requests_local = false
config.action_controller.perform_caching = true
# Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"]
# or in config/master.key. This key is used to decrypt credentials (and other encrypted files).
# config.require_master_key = true
# Disable serving static files from the `/public` folder by default since
# Apache or NGINX already handles this.
## config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
config.public_file_server.enabled = true
# Compress JavaScripts and CSS.
config.assets.js_compressor = :uglifier
# config.assets.css_compressor = :sass
# Do not fallback to assets pipeline if a precompiled asset is missed.
config.assets.compile = false
# `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb
# Enable serving of images, stylesheets, and JavaScripts from an asset server.
# config.action_controller.asset_host = 'http://assets.example.com'
# Specifies the header that your server uses for sending files.
# config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
# Store uploaded files on the local file system (see config/storage.yml for options)
config.active_storage.service = :local
# Mount Action Cable outside main process or domain
# config.action_cable.mount_path = nil
# config.action_cable.url = 'wss://example.com/cable'
# config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ]
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
# config.force_ssl = true
# Use the lowest log level to ensure availability of diagnostic information
# when problems arise.
config.log_level = :info
# Prepend all log lines with the following tags.
config.log_tags = [ :request_id ]
# Use a different cache store in production.
# config.cache_store = :mem_cache_store
# Use a real queuing backend for Active Job (and separate queues per environment)
# config.active_job.queue_adapter = :resque
# config.active_job.queue_name_prefix = "educoderplus_#{Rails.env}"
config.action_mailer.perform_caching = false
# Ignore bad email addresses and do not raise email delivery errors.
# Set this to true and configure the email server for immediate delivery to raise delivery errors.
# config.action_mailer.raise_delivery_errors = false
# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
# the I18n.default_locale when a translation cannot be found).
config.i18n.fallbacks = true
# Send deprecation notices to registered listeners.
config.active_support.deprecation = :notify
# Use default logging formatter so that PID and timestamp are not suppressed.
config.log_formatter = ::Logger::Formatter.new
# Use a different logger for distributed setups.
# require 'syslog/logger'
# config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name')
if ENV["RAILS_LOG_TO_STDOUT"].present?
logger = ActiveSupport::Logger.new(STDOUT)
logger.formatter = config.log_formatter
config.logger = ActiveSupport::TaggedLogging.new(logger)
end
# Do not dump schema after migrations.
config.active_record.dump_schema_after_migration = false
config.active_record.belongs_to_required_by_default = false
# config.cache_store = :file_store, "#{Rails.root }/files/cache_store/"
#config.cache_store = :redis_store, 'redis://r-bp122bd1b710f274.redis.rds.aliyuncs.com:6379/0/cache', { expires_in: 90.minutes }
config.cache_store = :redis_store, 'redis://10.9.72.102:6379/0/cache', { expires_in: 90.minutes }
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
address: 'smtp.exmail.qq.com',
port: 25,
domain: 'smtp.qq.com',
user_name: 'educoder@trustie.org',
password: 'mAZc9EWbe2Kawaqo2',
authentication: 'login',
enable_starttls_auto: true }
end

@ -49,6 +49,7 @@
"lodash": "^4.17.5",
"loglevel": "^1.6.1",
"material-ui": "^1.0.0-beta.40",
"md5": "^2.2.1",
"moment": "^2.23.0",
"monaco-editor": "^0.15.6",
"monaco-editor-webpack-plugin": "^1.7.0",

@ -3484,3 +3484,16 @@ a.singlepublishtwo{
text-align: justify;
word-break: break-all;
}
.RightPaneDrawer .ant-drawer-content{
background: #070f1a;
overflow: hidden !important;
}
.deletebuttom{
border: transparent;
}
.RightPaneDrawer .jupyter_data_list{
max-height: 340px;
}

@ -301,19 +301,28 @@ const Developer = Loadable({
loader: () => import('./modules/developer'),
loading: Loading
})
// 题库
// 题库
const Headplugselection = Loadable({
loader: () => import('./modules/question/Question'),
loading: Loading
})
//题库新建 //题库编辑
//题库新建 //题库编辑
const Questionitem_banks = Loadable({
loader: () => import('./modules/question/Questionitem_banks'),
loading: Loading
})
//试卷库
const Testpaperlibrary= Loadable({
loader: () => import('./modules/testpaper/Testpaperlibrary'),
loading: Loading
})
//人工组卷
const Paperreview= Loadable({
loader: () => import('./modules/question/Paperreview'),
loading: Loading
})
@ -476,6 +485,9 @@ class App extends Component {
this.setState({
mygetHelmetapi:response.data.setting
});
//存储配置到游览器
localStorage.setItem('chromesetting',JSON.stringify(response.data.setting));
localStorage.setItem('chromesettingresponse',JSON.stringify(response));
try {
if (response.data.setting.tab_logo_url) {
this.gettablogourldata(response);
@ -756,7 +768,7 @@ class App extends Component {
render={
(props) => (<Headplugselection {...this.props} {...props} {...this.state} />)
} />
<Route path="/myproblems/:id"
<Route path="/myproblems/:id/:tab?"
render={
(props) => (<StudentStudy {...this.props} {...props} {...this.state} />)
} />
@ -765,6 +777,15 @@ class App extends Component {
render={
(props) => (<Developer {...this.props} {...props} {...this.state} />)
}/>
<Route path="/paperreview"
render={
(props) => (<Paperreview {...this.props} {...props} {...this.state} />)
}/>
<Route path="/paperlibrary"
render={
(props) => (<Testpaperlibrary {...this.props} {...props} {...this.state} />)
}/>
<Route path="/question"
render={
(props) => (<Headplugselection {...this.props} {...props} {...this.state} />)

@ -1,10 +1,14 @@
import React from "react";
import axios from 'axios';
import md5 from 'md5';
import { requestProxy } from "./indexEduplus2RequestProxy";
import { broadcastChannelOnmessage ,SetAppModel, isDev, queryString } from 'educoder';
import { notification } from 'antd';
import './index.css'
import './index.css';
const opens ="79e33abd4b6588941ab7622aed1e67e8";
let timestamp = Date.parse(new Date());
const newopens=md5(opens+timestamp)
broadcastChannelOnmessage('refreshPage', () => {
window.location.reload()
})
@ -91,20 +95,20 @@ export function initAxiosInterceptors(props) {
}
if(`${config[0]}`!=`true`){
if (window.location.port === "3007") {
// if (url.indexOf('.json') == -1) {
//
// alert('开发提示:请给接口加.json:' + url)
//
// }
config.url = `${proxy}${url}`;
if (config.url.indexOf('?') == -1) {
config.url = `${config.url}?debug=${debugType}`;
config.url = `${config.url}?debug=${debugType}&timestamp=${timestamp}&client_key=${newopens}`;
} else {
config.url = `${config.url}&debug=${debugType}`;
config.url = `${config.url}&debug=${debugType}&timestamp=${timestamp}&client_key=${newopens}`;
}
} else {
// 加api前缀
config.url = url;
config.url = url;
if (config.url.indexOf('?') == -1) {
config.url = `${config.url}?&timestamp=${timestamp}&client_key=${newopens}`;
} else {
config.url = `${config.url}&timestamp=${timestamp}&client_key=${newopens}`;
}
}
}
//
@ -191,6 +195,11 @@ export function initAxiosInterceptors(props) {
locationurl('/500');
}
if (response.data.status === 501) {
notification.warning({
description:response.data.message || '访问异常,请求不合理',
})
}
// if (response.data.status === 402) {

@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-12-17 17:32:55
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-26 18:43:21
* @LastEditTime : 2019-12-27 16:50:43
*/
import './index.scss';
import React, { useState } from 'react';
@ -25,6 +25,7 @@ function CommentForm (props) {
const { getFieldDecorator } = form;
const [ctx, setCtx] = useState('');
const [focus, setFocus] = useState(false);
const options = [
['bold', 'italic', 'underline'],
@ -38,6 +39,7 @@ function CommentForm (props) {
// 点击输入框
const handleInputClick = (type) => {
setShowQuill(true);
setFocus(true);
}
// 取消
const handleCancle = () => {
@ -116,6 +118,7 @@ function CommentForm (props) {
overflow: showQuill ? 'none' : 'hidden',
transition: 'all 0.3s'
}}
autoFocus={focus}
style={{ height: '150px' }}
placeholder="说点儿什么~"
options={options}

@ -41,12 +41,14 @@ $ml: 20px;
}
.item-desc{
flex: 1;
margin-left: $ml;
// margin-left: $ml;
margin-left: 5px;
}
.item-header{
font-size: $fz14;
line-height: $lh14;
color: #333;
margin-left: 15px;
.item-time{
font-size: $fz12;
line-height: $lh14;

@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-12-18 08:49:30
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-27 10:36:11
* @LastEditTime : 2019-12-27 16:49:25
*/
import './index.scss';
import 'quill/dist/quill.core.css'; // 核心样式
@ -26,6 +26,7 @@ Quill.register(ImageBlot);
function QuillForEditor ({
placeholder,
readOnly,
autoFocus,
options,
value,
imgAttrs = {}, // 指定图片的宽高
@ -172,6 +173,12 @@ function QuillForEditor ({
}
}, [quill, handleOnChange]);
useEffect(() => {
if (autoFocus) {
quill.focus();
}
}, [quill, autoFocus]);
// 返回结果
return (
<div className='quill_editor_for_react_area' style={wrapStyle}>

@ -721,14 +721,28 @@ class CoursesBanner extends Component {
.ant-breadcrumb-separator{
color: rgba(255,255,255,0.3) !important;
}
.pointer .ant-tooltip-inner{
background:rgba(204,204,204,0.2) !important;
}
.pointer .ant-tooltip-arrow::before{
background:rgba(204,204,204,0.2) !important;
}
.pointer .antsoancss{
color: #fff;
}
`}
</style>
<Breadcrumb separator="|" className={"mt5"}>
<Breadcrumb.Item className={"pointer"}>
<Tooltip visible={coursedata.teacher_applies_count===undefined?false:coursedata.teacher_applies_count>0?true:false}
placement="topLeft"
title={<pre>{coursedata.teacher_applies_count===undefined?"":coursedata.teacher_applies_count>0?<span>您有{coursedata.teacher_applies_count}条新的加入申请<a className={"daishenp"} onClick={()=>this.setHistoryFun("/courses/"+this.props.match.params.coursesId+"/teachers?tab=2")}>
<Tooltip getPopupContainer={trigger => trigger.parentNode} visible={coursedata.teacher_applies_count===undefined?false:coursedata.teacher_applies_count>0?true:false}
placement="topLeft"
title={<pre className="antsoancss">
{coursedata.teacher_applies_count===undefined?"":coursedata.teacher_applies_count>0?
<span >您有{coursedata.teacher_applies_count}条新的加入申请
<a className={"daishenp"} onClick={()=>this.setHistoryFun("/courses/"+this.props.match.params.coursesId+"/teachers?tab=2")}>
<span style={{
color:"#FFA804"
}}>

@ -2,14 +2,14 @@ i.iconfont {
cursor: pointer;
}
.overflowHidden1 {
overflow: hidden;
text-overflow: ellipsis;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: inline-block;
}
.overflowHidden2 {
overflow: hidden;
text-overflow: ellipsis;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
@ -637,7 +637,7 @@ a.white-btn.use_scope-btn:hover{
/* 公用的文字按钮:蓝、白、灰 */
.btn.colorblue {
color:#4CACFF !important;
}
}
.btn.colorblue:hover{
color:#459BE5 !important;
}
@ -685,7 +685,7 @@ a.white-btn.use_scope-btn:hover{
background-color: #fff;
color: #4CACFF!important;
border: 1px solid #4CACFF;
}
}
.greyBack{
/* 不要固定宽度 */
/* width: 64px; */
@ -1217,7 +1217,7 @@ samp {
top: 4px;
color: #FE4F4C;
}
/* 毕设任务 */
.graduationTaskMenu>a{
display: block;
@ -1240,7 +1240,7 @@ samp {
.graduationTaskMenu>a.active{
color: #4CACFF!important;
}
/* end */
/* form表单包含多个item时 */
.createPage{
@ -1268,7 +1268,7 @@ samp {
.createPage .ant-form-explain{
padding-left: 0px;
}
.has-error .ant-input-group-addon{
border-color:#f5222d!important;
}
@ -1282,7 +1282,7 @@ samp {
top: 32px;
color: #FE4F4C;
}
.searchView{
width: 248px;
height: 40px;
@ -1544,7 +1544,7 @@ samp {
/* 单选下拉列表(超出十条数据带搜索、且有添加按钮) */
.drop_down_menu li{
overflow:hidden;
white-space: nowrap;
white-space: nowrap;
text-overflow:ellipsis;
padding:0px 20px;
height: 34px;
@ -1571,7 +1571,7 @@ samp {
line-height: 48px;
color: #666666;
}
/* 下拉 ---------------- END */
/* List列表页的公共样式---------------------------------------------- END */
@ -1749,4 +1749,8 @@ input.ant-input-number-input:focus {
.daishenp{
color: #F79946 !important;
text-decoration: underline !important;
}
}
.pointertooltip{
background: #DDDDDD;
}

@ -120,7 +120,6 @@ const testMaps = {
2: '数据结构与算法'
}
}
class DeveloperHome extends React.PureComponent {
/**
* 表格列

@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-11-27 16:02:36
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-27 09:32:34
* @LastEditTime : 2019-12-27 18:05:50
*/
import './index.scss';
import React, { useState, useRef, useEffect } from 'react';
@ -19,6 +19,7 @@ const ControlSetting = (props) => {
const {
hack,
userCode,
inputValue,
loading,
submitLoading,
@ -58,7 +59,7 @@ const ControlSetting = (props) => {
// 调试代码
const handleTestCode = (e) => {
if (!hack.code) {
if (!userCode) {
notification.warning({
message: '提示',
description: '代码块内容不能为空'
@ -77,6 +78,13 @@ const ControlSetting = (props) => {
// 提交
const handleSubmit = (e) => {
e.preventDefault();
if (!userCode) {
notification.warning({
message: '提示',
description: '代码块内容不能为空'
});
return;
}
changeSubmitLoadingStatus(true);
onSubmitForm && onSubmitForm();
}
@ -145,9 +153,10 @@ const ControlSetting = (props) => {
const mapStateToProps = (state) => {
const {commonReducer, ojForUserReducer} = state;
const {loading, excuteState, submitLoading, showOrHideControl } = commonReducer;
const { commitTestRecordDetail, hack } = ojForUserReducer;
const { commitTestRecordDetail, hack, userCode } = ojForUserReducer;
return {
hack,
userCode,
loading,
submitLoading,
excuteState,

@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-12-03 15:20:55
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-25 11:41:42
* @LastEditTime : 2019-12-27 22:35:14
*/
import './index.scss';
import React from 'react';

@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-11-27 15:02:52
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-27 10:32:25
* @LastEditTime : 2019-12-27 20:49:46
*/
import './index.scss';
import React, { useState, useRef, useEffect } from 'react';
@ -23,7 +23,7 @@ const maps = {
'c': 'main.c',
'c++': 'main.cc',
'java': 'main.java',
'pythone': 'main.py'
'python': 'main.py'
};
function MyMonacoEditor (props, ref) {
@ -86,6 +86,7 @@ function MyMonacoEditor (props, ref) {
// TODO 需要优化 节流
const val = editorRef.current.getValue();
// setEditCode(val);
// console.log('编辑器代码====>>>>', val);
onCodeChange(val);
// 值一变化保存当前代码值
// saveUserInputCode(val);

@ -0,0 +1,48 @@
/*
* @Description:
* @Author: tangjiang
* @Github:
* @Date: 2019-12-27 19:18:09
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-27 19:19:23
*/
import React, { useState } from 'react';
import Editor from "@monaco-editor/react";
function App() {
const [theme, setTheme] = useState("light");
const [language, setLanguage] = useState("javascript");
const [isEditorReady, setIsEditorReady] = useState(false);
function handleEditorDidMount() {
setIsEditorReady(true);
}
function toggleTheme() {
setTheme(theme === "light" ? "dark" : "light");
}
function toggleLanguage() {
setLanguage(language === "javascript" ? "python" : "javascript");
}
return (
<React.Fragment>
<LinkToRepo />
<button onClick={toggleTheme} disabled={!isEditorReady}>
Toggle theme
</button>
<button onClick={toggleLanguage} disabled={!isEditorReady}>
Toggle language
</button>
<Editor
height="calc(100% - 19px)" // By default, it fully fits with its parent
theme={theme}
language={language}
value={'c'}
editorDidMount={handleEditorDidMount}
/>
</React.Fragment>
);
}

@ -4,10 +4,10 @@
* @Github:
* @Date: 2019-12-01 10:18:35
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-27 10:17:07
* @LastEditTime : 2019-12-27 19:33:50
*/
import './index.scss';
import React from 'react';
import React, { useState, useEffect } from 'react';
import { connect } from 'react-redux';
import MyMonacoEditor from '../../components/myMonacoEditor';
// import ControlSetting from '../../components/controlSetting';
@ -18,6 +18,7 @@ function RightPane (props, ref) {
const {
// identifier,
code,
showCode,
language,
// onSubmitForm,
saveOjFormCode
@ -46,7 +47,7 @@ function RightPane (props, ref) {
<div className={'right_pane_code_wrap'}>
<MyMonacoEditor
language={language}
code={code}
code={showCode}
onCodeChange={handleCodeChange}/>
{/* <ControlSetting
@ -60,9 +61,10 @@ function RightPane (props, ref) {
}
const mapStateToProps = (state) => {
const { ojForm, testCases, code, identifier } = state.ojFormReducer;
const { ojForm, testCases, code, identifier, showCode } = state.ojFormReducer;
return {
code,
showCode,
identifier,
language: ojForm.language,
input: (testCases[0] && testCases[0].input) || '',

@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-12-04 08:36:21
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-27 14:51:42
* @LastEditTime : 2019-12-27 21:18:39
*/
import './index.scss';
import React, { useState, useEffect } from 'react';
@ -60,6 +60,14 @@ function RecordDetail (props) {
props.history.push(`/myproblems/${identifier}`);
}
}
const handleEditorCode = (identifier, code) => {
if (identifier) {
console.log(code);
saveEditorCodeForDetail(code);
props.history.push(`/myproblems/${identifier}`);
}
}
return (
<div className="record_detail_area">
<div className="record_detail_header">
@ -114,9 +122,10 @@ function RecordDetail (props) {
style={{ visibility: identifier ? 'visible' : 'hidden'}}
className={'header_btn'}
type="primary"
onClick={() => handleEditorCode(identifier, detail.code)}
>
{/* 编辑代码 */}
<Link to={`/myproblems/${identifier}`}>编辑代码</Link>
编辑代码
{/* <Link to={`/myproblems/${identifier}`}>编辑代码</Link> */}
</Button>
</div>
<div className="result_code_area">

@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-11-23 10:53:19
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-27 10:25:14
* @LastEditTime : 2019-12-27 16:22:47
*/
import './index.scss';
import React, { useEffect, useState } from 'react';
@ -30,6 +30,7 @@ function StudentStudy (props) {
// hack_identifier,
// user_program_identifier,
restoreInitialCode,
changeUserCodeTab,
changeShowOrHideControl
} = props;
@ -39,13 +40,17 @@ function StudentStudy (props) {
saveUserProgramIdentifier
} = props;
let { id } = params;
let { id, tab } = params;
useEffect(() => {
// 保存当前的id
saveUserProgramIdentifier(id);
// startProgramQuestion(id);
getUserProgramDetail(id);
if (tab) {
changeUserCodeTab(tab);
}
}, []);
useEffect(() => {
@ -176,7 +181,8 @@ const mapDispatchToProps = (dispatch) => ({
// 恢复初始代码
restoreInitialCode: (identifier, msg) => dispatch(actions.restoreInitialCode(identifier, msg)),
changeShowOrHideControl: (flag) => dispatch(actions.changeShowOrHideControl(flag)),
clearOjForUserReducer: () => dispatch(actions.clearOjForUserReducer())
clearOjForUserReducer: () => dispatch(actions.clearOjForUserReducer()),
changeUserCodeTab: (tab) => dispatch(actions.changeUserCodeTab(tab))
});
export default withRouter(connect(

@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-11-27 09:49:33
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-27 10:39:00
* @LastEditTime : 2019-12-27 22:40:32
*/
import './index.scss';
import React, { useState, useEffect } from 'react';
@ -96,7 +96,7 @@ const CommitRecord = (props) => {
const {
id,
// error_line,
// error_msg,
error_msg,
// execute_memory,
// execute_time,
// input,
@ -116,13 +116,14 @@ const CommitRecord = (props) => {
执行结果: <span className={classes}>{reviewResult[status]}</span>
</p>
<p
id="copyError"
onClick={clickCopyErrInfo}
className={showErrorCopy} data-clipboard-target="#errcode">
<span>
复制错误信息 <Icon type="copy" className={'icon_style'}/>
</span>
</p>
<p className={'show_detail'}>
<p className={'show_detail'} style={{ visibility: id ? 'visible' : 'hidden' }}>
<Link to={`/myproblems/record_detail/${id}`}>
显示详情 <Icon type="right" className={'icon_style'}/>
</Link>
@ -158,7 +159,7 @@ const CommitRecord = (props) => {
// 复制功能
let count = 0;
useEffect(() => {
clipboard = new ClipboardJS('.copy_error');
clipboard = new ClipboardJS('#copyError');
clipboard && clipboard.on('success', (e) => {
e.clearSelection();
if (count > 0) return;
@ -166,8 +167,12 @@ const CommitRecord = (props) => {
message.success('复制成功');
setTimeout(() => {
message.destroy();
}, 300);
}, 3000);
});
return () => {
clipboard = null;
}
}, []);
const clickCopyErrInfo = () => {

@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-11-23 11:33:41
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-25 17:10:30
* @LastEditTime : 2019-12-27 16:03:04
// */
import './index.scss';
import React, { useState, useEffect, useMemo } from 'react';
@ -28,7 +28,7 @@ const LeftPane = (props) => {
comments_count, /* 评论数*/
user_praise // 用户是否点赞
} = hack;
const [defaultActiveKey, setDefaultActiveKey] = useState('comment');
const [defaultActiveKey, setDefaultActiveKey] = useState('task');
const navItem = [
{
@ -51,6 +51,8 @@ const LeftPane = (props) => {
comment: (<Comment />)
};
console.log('======>>>>>>>', props);
useEffect(() => {
setDefaultActiveKey(userCodeTab);
}, [userCodeTab])

@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-11-27 09:49:30
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-25 14:50:37
* @LastEditTime : 2019-12-27 20:22:55
*/
import '../index.scss';
import React from 'react';
@ -18,7 +18,7 @@ const {tagBackground, diffText} = CONST;
const TaskDescription = (props) => {
const { hack = {} } = props;
const { hack = {}, userInfo = {} } = props;
const {language, difficult, time_limit, username, description} = hack;
return (
<div className={'task_description_area'}>
@ -37,7 +37,7 @@ const TaskDescription = (props) => {
</p>
<p className={'header_flex'}>
<span className={'flex_label'}>出题者:</span>
<Link to="/users/innov/courses" target="_blank" style={{ color: '#5091FF'}}>{username}</Link>
<Link to={hack.user_path || '/'} target="_blank" style={{ color: '#5091FF'}}>{username}</Link>
</p>
</div>
<div className="task_desc_area">
@ -52,8 +52,10 @@ const TaskDescription = (props) => {
const mapStateToProps = (state) => {
const { hack } = state.ojForUserReducer;
const { userInfo } = state.userReducer;
return {
hack
hack,
userInfo
}
}

@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-11-27 14:59:51
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-27 10:28:41
* @LastEditTime : 2019-12-27 19:23:46
*/
import React, { useState, useEffect } from 'react';
import {connect} from 'react-redux';
@ -45,13 +45,14 @@ const RightPane = (props) => {
// const [code, setCode] = useState(editor_code || hack.code);
// let initFlag = true;
useEffect(() => {
if (editor_code) {
setEditorCode(editor_code);
} else {
setEditorCode(hack.code);
}
}, [hack, editor_code]);
// useEffect(() => {
// if (editor_code) {
// setEditorCode(editor_code);
// } else {
// setEditorCode(hack.code);
// }
// }, [hack, editor_code]);
const handleSubmitForm = () => {
// 提交时, 先调用提交接口,提交成功后,循环调用测评接口
@ -119,7 +120,7 @@ const RightPane = (props) => {
notice={notice}
identifier={identifier}
language={hack.language}
code={editorCode}
code={editor_code || hack.code}
hadCodeUpdate={hadCodeUpdate}
onCodeChange={handleCodeChange}
onUpdateNotice={handleUpdateNotice}

@ -475,7 +475,11 @@ class MessagSub extends Component {
// }
}
case "Discuss":
return window.open(`/shixuns/${item.identifier}/shixun_discuss`);
if (item.parent_container_type === 'Hack' && item.extra) {
return window.open(`/myproblems/${item.extra}/comment`);
} else {
return window.open(`/shixuns/${item.identifier}/shixun_discuss`);
}
case "Video":
if (item.tiding_type === "Apply") {
return window.open(`/admins/video_applies`);
@ -506,6 +510,10 @@ class MessagSub extends Component {
//分组作业
return window.open(`/courses/${item.belong_container_id}/group_homeworks/${item.parent_container_id}`);
}
case 'Hack':
if (item.extra && item.parent_container_type !== 'HackDelete') {
return window.open(`/problems/${item.extra}/edit`);
}
default :
return
}

@ -0,0 +1,159 @@
import React, {Component} from "react";
import {Link, NavLink} from 'react-router-dom';
import {WordsBtn, ActionBtn, SnackbarHOC, getImageUrl} from 'educoder';
import axios from 'axios';
import {
notification,
Spin,
Table,
Pagination,
Drawer,
Input,
Button,
Breadcrumb
} from "antd";
import {TPMIndexHOC} from "../tpm/TPMIndexHOC";
import Itembankstop from "./component/Itembankstop";
import NoneData from './component/NoneData';
import './questioncss/questioncom.css';
import '../tpm/newshixuns/css/Newshixuns.css';
import Choicequestion from './component/Choicequestion';
import SingleEditor from "./component/SingleEditor";
import ChoquesEditor from "./component/ChoquesEditor"
import JudquestionEditor from "./component/JudquestionEditor";
import Paperreview_item from "./Paperreview_item"
import Bottomsubmit from "../../modules/modals/Bottomsubmit";
class Paperreview extends Component {
constructor(props) {
super(props);
this.contentMdRef = React.createRef();
this.answerMdRef = React.createRef();
this.Choques = React.createRef();
this.Judquestio = React.createRef();
this.state = {
item_type: null,
item_banksedit: [],
myquestion_choicesco: [],
disciplinesdata: [],
knowledgepoints: [],
disciplmy:[]
}
}
//初始化
componentDidMount() {
}
getdata = (data) => {
}
getcontentMdRef = (Ref) => {
this.contentMdRef = Ref;
}
getanswerMdRef = (Ref) => {
this.answerMdRef = Ref;
}
getJudquestio = (Ref) => {
this.Judquestio = Ref;
}
getChoquesEditor = (Ref) => {
this.Choques = Ref;
}
//跳转道描点的地方
scrollToAnchor = (anchorName) => {
try {
if (anchorName) {
// 找到锚点
let anchorElement = document.getElementById(anchorName);
// 如果对应id的锚点存在就跳转到锚点
if (anchorElement) {
anchorElement.scrollIntoView();
}
}
} catch (e) {
}
}
preservation = () => {
//保存试卷
}
setitem_type = (item_type) => {
}
render() {
let {page, limit, count, Headertop, visible, placement, modalsType, item_type} = this.state;
const params = this.props && this.props.match && this.props.match.params;
// //console.log(params);
return (
<div>
<div id={"Itembankstopid"} className="newMain clearfix intermediatecenter "
>
<style>
{
`
.newFooter{
display: none;
}
`
}
</style>
<div className="w1200mss">
<div className="w100s mt30">
<Breadcrumb separator=">">
<Breadcrumb.Item href="/question">试题库</Breadcrumb.Item>
<Breadcrumb.Item className={"xiaoshou"} >人工组卷</Breadcrumb.Item>
<Breadcrumb.Item className={"xiaoshout"}>试卷预览</Breadcrumb.Item>
</Breadcrumb>
</div>
<Paperreview_item>
</Paperreview_item>
</div>
</div>
{
item_type === null ?
""
:
<Bottomsubmit {...this.props} {...this.state} bottomvalue={"保存组卷"}
onSubmits={() => this.preservation()} url={'/question'}></Bottomsubmit>
}
</div>
)
}
}
export default SnackbarHOC()(TPMIndexHOC(Paperreview));

@ -0,0 +1,85 @@
import React, {Component} from "react";
import {Link, NavLink} from 'react-router-dom';
import {WordsBtn, ActionBtn, getImageUrl} from 'educoder';
import axios from 'axios';
import {
notification,
Spin,
Table,
Pagination,
Drawer,
Input,
Button,
Breadcrumb
} from "antd";
import Itembankstop from "./component/Itembankstop";
import NoneData from './component/NoneData';
import './questioncss/questioncom.css';
import '../tpm/newshixuns/css/Newshixuns.css';
import Choicequestion from './component/Choicequestion';
import SingleEditor from "./component/SingleEditor";
import ChoquesEditor from "./component/ChoquesEditor"
import JudquestionEditor from "./component/JudquestionEditor";
import Bottomsubmit from "../../modules/modals/Bottomsubmit";
class Paperreview_item extends Component {
constructor(props) {
super(props);
this.state = {
questions:0,
totalscore:0,
}
}
//初始化
componentDidMount() {
}
getdata = (data) => {
}
preservation = () => {
}
setitem_type = (item_type) => {
}
render() {
let {questions,totalscore} = this.state;
// //console.log(params);
return (
<div className=" clearfix educontent Contentquestionbankstyle w100s w1200fpx mt19">
<div className="w100s mt20 mb20">
<div className="w100s sortinxdirection">
<p className="questionstishu">题数{questions}</p>
<p className="ml58 questionstotal">总分{totalscore}</p>
</div>
</div>
</div>
)
}
}
export default Paperreview_item

@ -612,7 +612,12 @@ class Question extends Component {
}
//跳转
gotopaperreview=()=>{
this.props.history.replace("/paperreview");
}
render() {
let {
@ -739,7 +744,6 @@ class Question extends Component {
{Datacount && Datacount > 0 ?
<div>
<div className="mt25 mb26">
<Input placeholder="未命名试卷"/>
</div>
{
single_questions_count === 0 ?
@ -819,7 +823,8 @@ class Question extends Component {
}
<div className="intermediatecenter verticallayout mt42">
<div className="drawerbutton">
<div className="drawerbutton" onClick={()=>this.gotopaperreview()}>
试卷预览
</div>
</div>

@ -486,7 +486,6 @@ class Questionitem_banks extends Component {
return (
<div>
<div id={"Itembankstopid"} className="newMain clearfix intermediatecenter "
style={{}}
>
<style>

@ -357,7 +357,10 @@
color: #4CACFF;
}
.xiaoshou{
cursor:pointer
cursor:pointer;
}
.xiaoshout{
cursor:default;
}
.mt40{
margin-top: 40px;
@ -609,3 +612,19 @@
.minheight{
min-height: 500px !important;
}
.pd20{
padding: 20px;
}
.ml58{
margin-left: 58px;
}
.questionstishu{
color: #888888;
font-size: 14px;
}
.questionstotal{
color: #333333;
font-size: 14px;
}

@ -0,0 +1,239 @@
import React, {Component} from "react";
import {Link, NavLink} from 'react-router-dom';
import {WordsBtn, ActionBtn, SnackbarHOC, getImageUrl} from 'educoder';
import axios from 'axios';
import {
notification,
Spin,
Table,
Pagination,
Drawer,
Input
} from "antd";
import {TPMIndexHOC} from "../tpm/TPMIndexHOC";
import NoneData from './component/NoneData';
import './testioncss/testioncss.css';
import Contentpart from "./component/Contentpart";
import SiderBar from "../tpm/SiderBar";
import Headplugselection from "../question/component/Headplugselection";
class Testpaperlibrary extends Component {
constructor(props) {
super(props);
this.state = {
Headertop: "",
disciplinesdata:null,
discipline_id:null,
sub_discipline_id:null,
tag_discipline_id:null,
public:null,
difficulty:null,
item_type:null,
keywords:null,
page:1,
per_page:10,
booljupyterurls:false,
Contentdata:[],
items_count:0,
}
}
getContainer = () => {
return this.container;
};
saveContainer = container => {
this.container = container;
};
//初始化
componentDidMount() {
let url = `/users/get_navigation_info.json`;
axios.get(url, {}).then((response) => {
// ////console.log("开始请求/get_navigation_info.json");
// ////console.log(response);
if (response != undefined) {
if (response.status === 200) {
this.setState({
Headertop: response.data.top,
Footerdown: response.data.down
})
}
}
});
//获取题库筛选资料
let urls = `/disciplines.json`;
axios.get(urls, {params: {
source:"question"
}}).then((response) => {
if (response) {
this.setState({
disciplinesdata: response.data.disciplines,
})
}
});
}
paginationonChange=()=>{
var data={
}
this.getdata(data);
}
// 选择难度
setdifficulty=()=>{
}
callback=()=>{
}
//搜索框的内容
setdatafunsval=()=>{
}
//搜索按钮
setdatafuns=()=>{
}
//获取数据
getdata=(data)=>{
const url = `/item_banks.json`;
this.setState({
booljupyterurls:true,
})
axios.get((url), {params: data}).then((response) => {
setTimeout(()=>{
this.setState({
booljupyterurls:false,
})
},1000);
if (response === null || response === undefined) {
return
}
if (response.data.status === 403 || response.data.status === 401 || response.data.status === 500) {
} else {
}
////console.log("item_banks");
////console.log(response);
this.setState({
Contentdata: response.data,
items_count: response.data.items_count,
})
}).catch((error) => {
////console.log(error)
this.setState({
booljupyterurls:false,
})
});
}
setdiscipline_id=(discipline_id)=>{
this.setState({
discipline_id:discipline_id,
sub_discipline_id:null,
tag_discipline_id:null
})
var data = {
discipline_id:discipline_id,
sub_discipline_id:null,
tag_discipline_id:null,
public: this.state.defaultActiveKey,
difficulty: this.state.difficulty,
item_type: this.state.item_type,
keywords: this.state.keywords,
page: this.state.page,
per_page:10,
};
this.getdata(data);
}
setsub_discipline_id=(sub_discipline_id)=>{
this.setState({
sub_discipline_id:sub_discipline_id,
tag_discipline_id:null
})
var data = {
discipline_id:this.state.discipline_id,
sub_discipline_id:sub_discipline_id,
tag_discipline_id:null,
public: this.state.defaultActiveKey,
difficulty: this.state.difficulty,
item_type: this.state.item_type,
keywords: this.state.keywords,
page: this.state.page,
per_page:10,
};
this.getdata(data);
}
settag_discipline_id=(tag_discipline_id)=>{
this.setState({
tag_discipline_id:tag_discipline_id
})
var data = {
discipline_id:this.state.discipline_id,
sub_discipline_id:this.state.sub_discipline_id,
tag_discipline_id:tag_discipline_id,
public: this.state.defaultActiveKey,
difficulty: this.state.difficulty,
item_type: this.state.item_type,
keywords: this.state.keywords,
page: this.state.page,
per_page:10,
};
this.getdata(data);
}
render() {
let{Headertop,items_count,page,per_page}=this.state;
return (
<div className="newMain clearfix" ref={this.saveContainer}>
{/*试卷库*/}
<SiderBar
{...this.props}
{...this.state}
showDrawer={() => this.showDrawer()}
Headertop={Headertop}/>
{/*顶部*/}
<Headplugselection {...this.props} {...this.state}
setdiscipline_id={(e)=>this.setdiscipline_id(e)}
setsub_discipline_id={(e)=>this.setsub_discipline_id(e)}
settag_discipline_id={(e)=>this.settag_discipline_id(e)}
></Headplugselection>
{/*头部*/}
<Contentpart>
</Contentpart>
{
items_count&&items_count>10?
<div className="mb30 clearfix educontent mt40 intermediatecenter">
<Pagination showQuickJumper current={page} onChange={this.paginationonChange}
pageSize={per_page}
total={items_count}></Pagination>
</div>
:
<div className="h30 clearfix educontent mt40 intermediatecenter">
</div>
}
</div>
)
}
}
export default SnackbarHOC()(TPMIndexHOC(Testpaperlibrary));

@ -0,0 +1,175 @@
import React, {Component} from "react";
import {Link, NavLink} from 'react-router-dom';
import {WordsBtn, ActionBtn,SnackbarHOC,getImageUrl} from 'educoder';
import axios from 'axios';
import {
notification,
Spin,
Table,
Pagination,
Tabs,
Input,
Popover
} from "antd";
import './../testioncss/testioncss.css';
import NoneDatas from '../component/NoneDatas';
import LoadingSpin from '../../../common/LoadingSpin';
import Contentquestionbank from "./Contentquestionbank";
const { TabPane } = Tabs;
const Search = Input.Search;
class Contentpart extends Component {
constructor(props) {
super(props);
this.state = {
page:1,
}
}
//初始化
componentDidMount(){
}
render() {
let {page}=this.state;
let {defaultActiveKey}=this.props;
const content = (
<div className="questiontypes" style={{
width:'93px',
height:'161px',
}}>
<p className="questiontype " onClick={()=>this.props.setitem_types("SINGLE")}>单选题</p>
<p className="questiontypeheng" ></p>
<p className="questiontype " onClick={()=>this.props.setitem_types("MULTIPLE")}>多选题</p>
<p className="questiontypeheng"></p>
<p className="questiontype " onClick={()=>this.props.setitem_types("JUDGMENT")}>判断题</p>
<p className="questiontypeheng"></p>
<p className="questiontype " onClick={()=>this.props.setitem_types("PROGRAM")}>编程题</p>
<p className="questiontypeheng"></p>
</div>
);
const contents = (
<div className="questiontypes" style={{
width:'93px',
height:'120px',
}}>
<p className="questiontype " onClick={()=>this.props.setdifficulty(1)}>简单</p>
<p className="questiontypeheng"></p>
<p className="questiontype " onClick={()=>this.props.setdifficulty(2)}>适中</p>
<p className="questiontypeheng"></p>
<p className="questiontype " onClick={()=>this.props.setdifficulty(3)}>困难</p>
<p className="questiontypeheng"></p>
</div>
);
return (
<div className=" clearfix mt40">
<div className="educontent mt10 pb20 w1200s">
<div className="w1200ms contentparttit" style={{
position: "relative",
}}>
<style>
{
`
.contentparttit .ant-tabs-nav .ant-tabs-tab{
margin: 10px 10px 10px 0 !important;
}
.contentparttit .ant-tabs-nav .ant-tabs-ink-bar{
width: 31px !important;
left: 14px;
}
`
}
</style>
<Tabs defaultActiveKey={defaultActiveKey} onChange={(e)=>this.props.callback(e)}>
<TabPane tab="公共" key="1">
</TabPane>
<TabPane tab="我的" key="0">
</TabPane>
</Tabs>
<div className=" mt19" style={{
position:"absolute",
top: "0px",
right:" 0px",
paddingRight: "20px",
}}>
<style>
{
`
.xaxisreverseorder .ant-input-group-addon{
width: 60px !important;
}
.xaxisreverseorder .ant-input-lg {
height: 41px;}
.xaxisreverseorder .ant-popover{
top: 348px !important;
}
.ant-popover-inner-content {
padding:0px !important;
}
`
}
</style>
<div className="xaxisreverseorder">
{
defaultActiveKey===0||defaultActiveKey==="0"?
<a href={'/question/newitem'}>
<div className="newbutoon">
<p className="newbutoontes" >新增</p>
</div>
</a>
:""
}
<Popover placement="bottom" content={contents} trigger="click" visible={this.props.visiblemys} onVisibleChange={()=>this.props.handleVisibleChange(true)}>
<div className=" sortinxdirection mr10">
<div className="subjecttit">
难度
</div>
<i className="iconfont icon-sanjiaoxing-down font-12 lg ml7 icondowncolor"></i>
</div>
</Popover>
<Popover placement="bottom" content={content} trigger="click" visible={this.props.visiblemyss} onVisibleChange={()=>this.props.handleVisibleChanges(true)}>
<div className="sortinxdirection mr40">
<div className="subjecttit">
题型
</div>
<i className="iconfont icon-sanjiaoxing-down font-12 lg ml7 icondowncolor"></i>
</div>
</Popover>
<Search
style={{ width: "347px",marginRight:"60px",}}
placeholder="请输入题目名称、内容"
enterButton
size="large"
onInput={(e)=>this.props.setdatafunsval(e)}
onSearch={ (value)=>this.props.setdatafuns(value)} />
</div>
</div>
</div>
</div>
</div>
)
}
}
export default Contentpart

@ -0,0 +1,68 @@
import React, {Component} from "react";
import {Link, NavLink} from 'react-router-dom';
import {WordsBtn, ActionBtn,SnackbarHOC,getImageUrl} from 'educoder';
import axios from 'axios';
import {
notification,
Spin,
Table,
Pagination,
Radio,
Checkbox
} from "antd";
import './../testioncss/testioncss.css';
class Contentquestionbank extends Component {
constructor(props) {
super(props);
this.state = {
page:1,
}
}
//初始化
componentDidMount(){
////console.log("componentDidMount");
////console.log(this.state);
////console.log(this.props);
// let homeworkid = this.props.match.params.homeworkid;
// let url = "/homework_commons/" + homeworkid + "/end_groups.json";
// axios.get(url).then((response) => {
// if (response.status === 200) {
// this.setState({})
// }
// }).catch((error) => {
// ////console.log(error)
// });
}
onChange=(e)=> {
////console.log(`checked = ${e.target.checked}`);
}
render() {
return (
<div className=" clearfix mt5 Contentquestionbankstyle">
<div className="educontent mt10 w100s">
<div className="sortinxdirection w100s" >
<div className="sortinxdirection w50s">
</div>
<div className="xaxisreverseorder testpaper w50s">
{this.props.items_count?this.props.items_count:0}个试题
</div>
</div>
</div>
</div>
)
}
}
export default Contentquestionbank ;

@ -0,0 +1,37 @@
import React, { Component } from 'react';
import { getImageUrl , getUrl } from 'educoder';
class NoneData extends Component{
constructor(props) {
super(props)
}
render(){
const { style } = this.props;
return(
<div className="edu-tab-con-box clearfix edu-txt-center intermediatecenter" style={ style || { width:"100%",height:"100%"}}>
<style>
{`
.edu-tab-con-box{
padding:100px 0px;
}
.ant-modal-body .edu-tab-con-box{
padding:0px!important;
}
img.edu-nodata-img{
margin: 40px auto 20px;
}
.zenwuxgsj{
font-size:17px;
font-family:MicrosoftYaHei;
color:rgba(136,136,136,1);
}
`}
</style>
<img className="edu-nodata-img mb20" src={getUrl("/images/educoder/nodata.png")}/>
<p className="edu-nodata-p mb10 zenwuxgsj">暂无相关数据</p>
<p className="edu-nodata-p mb20 mt4 zenwuxgsj">请选择试题进行组卷</p>
</div>
)
}
}
export default NoneData;

@ -0,0 +1,36 @@
import React, { Component } from 'react';
import { getImageUrl , getUrl } from 'educoder';
class NoneDatas extends Component{
constructor(props) {
super(props)
}
render(){
const { style } = this.props;
return(
<div className="edu-tab-con-box clearfix edu-txt-center intermediatecenter" style={ style || { width:"100%",height:"100%"}}>
<style>
{`
.edu-tab-con-box{
padding:100px 0px;
}
.ant-modal-body .edu-tab-con-box{
padding:0px!important;
}
img.edu-nodata-img{
margin: 40px auto 20px;
}
.zenwuxgsj{
font-size:17px;
font-family:MicrosoftYaHei;
color:rgba(136,136,136,1);
}
`}
</style>
<img className="edu-nodata-img mb20" src={getUrl("/images/educoder/nodata.png")}/>
<p className="edu-nodata-p mb10 zenwuxgsj">暂无相关数据</p>
</div>
)
}
}
export default NoneDatas;

@ -716,6 +716,28 @@ submittojoinclass=(value)=>{
getAppdata=()=>{
try {
var chromesettingArray = JSON.parse(localStorage.getItem('chromesetting'));
var chromesettingresponseArray = JSON.parse(localStorage.getItem('chromesettingresponse'));
// console.log("NewHeaderNewHeaderNewHeader");
// console.log(chromesettingArray);
// console.log(chromesettingresponseArray);
this.setState({
mygetHelmetapi2:chromesettingArray
});
if (chromesettingArray.tab_logo_url) {
this.gettablogourldata(chromesettingresponseArray);
} else {
this.gettablogourlnull();
}
}catch (e) {
console.log("head获取游览器配置失败 重新请求开始读取配置");
this.geturlsdata();
}
};
geturlsdata=()=>{
let url = "/setting.json";
axios.get(url).then((response) => {
// console.log("app.js开始请求/setting.json");
@ -725,6 +747,8 @@ submittojoinclass=(value)=>{
this.setState({
mygetHelmetapi2:response.data.setting
});
localStorage.setItem('chromesetting',JSON.stringify(response.data.setting));
localStorage.setItem('chromesettingresponse',JSON.stringify(response));
try {
if (response.data.setting.tab_logo_url) {
this.gettablogourldata(response);
@ -751,7 +775,7 @@ submittojoinclass=(value)=>{
this.gettablogourlnull();
});
};
}
matchpaths=(url)=>{
@ -891,7 +915,7 @@ submittojoinclass=(value)=>{
}}>
<a href={'/question'} ><p className="questiontype">试题库</p></a>
<p className="questiontypeheng"></p>
<a href={'/question'} ><p className="questiontype">试卷库</p></a>
<a href={'/paperlibrary'} ><p className="questiontype">试卷库</p></a>
<p className="questiontypeheng"></p>
</div>
);
@ -968,35 +992,32 @@ submittojoinclass=(value)=>{
)
})
}
{/*<style>*/}
{/* {*/}
{/* `*/}
{/* .queyppors {*/}
{/* top: 63px !important;*/}
{/* }*/}
{/* .ant-popover-inner-content {*/}
{/* padding:0px !important;*/}
{/* }*/}
{/* `*/}
{/* }*/}
{/*</style>*/}
{/*<li className={`pr `}>*/}
{/* <Popover placement="bottom" content={contents} trigger="click" >*/}
{/* <div className=" sortinxdirection mr10">*/}
{/* <div style={{*/}
{/* color:"#fff"*/}
{/* }}>*/}
{/* 题库*/}
{/* </div>*/}
{/* </div>*/}
{/* </Popover>*/}
{/*</li>*/}
<style>
{
`
.queyppors {
top: 63px !important;
}
.ant-popover-inner-content {
padding:0px !important;
}
`
}
</style>
<li className={`pr `}>
<Popover placement="bottom" content={contents} trigger="click" >
<div className=" sortinxdirection mr10">
<div style={{
color:"#fff"
}}>
题库
</div>
</div>
</Popover>
</li>
<li className={`pr `}>
<Link to={'/question'}>题库</Link>
</li>

@ -388,6 +388,7 @@ class TPMIndex extends Component {
let url = window.location.href;
let flag = url.indexOf("add_file")>-1;
return (
<div className="newMain clearfix">
{/*头部*/}

@ -315,6 +315,27 @@ export function TPMIndexHOC(WrappedComponent) {
}
//获取当前定制信息
getAppdata = () => {
try {
var chromesettingArray = JSON.parse(localStorage.getItem('chromesetting'));
var chromesettingresponseArray = JSON.parse(localStorage.getItem('chromesettingresponse'));
// console.log("TPMLNdexHOC");
// console.log(chromesettingArray);
// console.log(chromesettingresponseArray);
this.setState({
mygetHelmetapi:chromesettingArray
});
if (chromesettingArray.tab_logo_url) {
this.gettablogourldata(chromesettingresponseArray);
} else {
this.gettablogourlnull();
}
}catch (e) {
console.log("hoc获取游览器配置失败 重新请求开始读取配置");
this.getAppdatausr();
}
};
getAppdatausr=()=>{
let url = "/setting.json";
axios.get(url).then((response) => {
// console.log("app.js开始请求/setting.json");
@ -324,6 +345,8 @@ export function TPMIndexHOC(WrappedComponent) {
this.setState({
mygetHelmetapi: response.data.setting
});
localStorage.setItem('chromesetting',JSON.stringify(response.data.setting));
localStorage.setItem('chromesettingresponse',JSON.stringify(response));
try {
if (response.data.setting.tab_logo_url) {
this.gettablogourldata(response);
@ -350,7 +373,8 @@ export function TPMIndexHOC(WrappedComponent) {
this.gettablogourlnull();
});
};
}
/**
课堂权限相关方法暂时写这里了 ----------------------------------------END
*/

@ -164,7 +164,7 @@ export default class Shixuninformation extends Component {
axios.post(url,
{
scope_partment: list,
scope_partment:use_scope===0?undefined:list,
shixun: {
can_copy: can_copy,
use_scope: use_scope,
@ -213,7 +213,6 @@ export default class Shixuninformation extends Component {
if(scope_partment.length>0){
scope_partment.map((item, key) => {
if (item === e) {
debugger
scopetype = true
}
})
@ -222,7 +221,6 @@ export default class Shixuninformation extends Component {
if(oldscope_partment.length>0){
oldscope_partment.map((item, key) => {
if (item === e) {
debugger
scopetype = true
}
})

@ -18,6 +18,13 @@ const Option = Select.Option;
const RadioGroup = Radio.Group;
function isNulltpm( str ){
if ( str == "" ) return true;
var regu = "^[ ]+$";
var re = new RegExp(regu);
return re.test(str);
}
export default class TPMchallengesnew extends Component {
constructor(props) {
super(props)
@ -195,7 +202,7 @@ export default class TPMchallengesnew extends Component {
}
CreatePracticesend = () => {
const exercise_editormdvalue = this.exercisememoMDRef.current.getValue().trim();
this.setState({
CreatePracticesendtype:true
@ -237,6 +244,25 @@ export default class TPMchallengesnew extends Component {
}
if (exercise_editormdvalue === undefined||exercise_editormdvalue==""||exercise_editormdvalue===null) {
this.setState({
tpmcourseMessageMDType:true,
CreatePracticesendtype:false
})
this.props.scrollToAnchor("tpmcourseMessageMD");
return
}
if(isNulltpm(exercise_editormdvalue)){
this.setState({
tpmcourseMessageMDType:true,
CreatePracticesendtype:false
})
this.props.scrollToAnchor("tpmcourseMessageMD");
return
}
if(shixunCreatePracticeGroup===undefined){
this.setState({
shixunCreatePracticeGrouptype:true,
@ -284,7 +310,8 @@ export default class TPMchallengesnew extends Component {
// return
// }
const exercise_editormdvalue = this.exercisememoMDRef.current.getValue().trim();
let id = this.props.match.params.shixunId;
let url = "/shixuns/" + id + "/challenges.json";
// exec_time:exec_time
@ -369,19 +396,13 @@ export default class TPMchallengesnew extends Component {
}
editPracticesend=()=>{
this.setState({
editPracticesendtype:true
})
let {shixunCreatePractice, shixunCreatePracticeGroup, onshixunsmarkvalue, shixunsskillvaluelist,checkpointId,exec_time} = this.state;
const exercise_editormdvalue = this.exercisememoMDRef.current.getValue().trim();
let id = this.props.match.params.shixunId;
let url = "/shixuns/"+id+"/challenges/"+checkpointId+".json";
const exercise_editormdvalue = this.exercisememoMDRef.current.getValue().trim();
if (shixunCreatePractice === undefined||shixunCreatePractice=="") {
this.setState({
@ -408,6 +429,25 @@ export default class TPMchallengesnew extends Component {
return
}
if (exercise_editormdvalue === undefined||exercise_editormdvalue==""||exercise_editormdvalue===null) {
this.setState({
tpmcourseMessageMDType:true,
editPracticesendtype:false
})
this.props.scrollToAnchor("tpmcourseMessageMD");
return
}
if(isNulltpm(exercise_editormdvalue)){
this.setState({
tpmcourseMessageMDType:true,
editPracticesendtype:false
})
this.props.scrollToAnchor("tpmcourseMessageMD");
this.props.showNotification("过关任务,请勿输入空格");
return
}
if(shixunCreatePracticeGroup===undefined){
this.setState({
shixunCreatePracticeGrouptype:true,
@ -591,7 +631,7 @@ export default class TPMchallengesnew extends Component {
<div className="edu-back-white newpadding02020">
<p className="color-grey-6 font-16 mb10"><span className="mr5 color-red">*</span></p>
<p className="color-grey-6 font-16 mb10" id={"tpmcourseMessageMD"}><span className="mr5 color-red">*</span></p>
<style>
{
`
@ -607,10 +647,13 @@ export default class TPMchallengesnew extends Component {
}
</style>
<TPMMDEditor ref={this.exercisememoMDRef} placeholder="请输入选择题的题干内容" mdID={'exercisememoMD'} refreshTimeout={1500}
watch={true} className="courseMessageMD" initValue={this.state.exercisememoMDRefval} height={800}></TPMMDEditor>
<p id="e_tip_Memochallengesnew" className="edu-txt-right color-grey-cd font-12"></p>
<p id="e_tips_Memochallengesnew" className="edu-txt-right color-grey-cd font-12"></p>
{this.state.tpmcourseMessageMDType===true?<div className="color-red mt7 ml5 font-14" >必填项不能为空</div>:""}
</div>

@ -153,7 +153,7 @@ export default class TPMevaluation extends Component {
addevaluationon=()=>{
let {evaluationlist,markvalue}=this.state;
let newevaluationlist=evaluationlist;
newevaluationlist.push({hidden:0,input:"",output:"",score:0});
newevaluationlist.push({hidden:0,input:"",output:"",score:0,match_rule:"full"});
newevaluationlist=this.oneditevaluationlist(newevaluationlist,markvalue);
this.setevaluationlist(newevaluationlist);
}

@ -168,8 +168,7 @@ function JupyterTPI (props) {
title: '更新通知',
content: (<div className="update_notice">
{stopposttpip(1)}
<p className="update_txt">该实训已更新您选择更新后之前编写的实训代码将会丢失</p>
<p className="update_txt">如有需要请先使用jupyter中-文件-下载保存代码再进行更新</p>
<p className="update_txt">该实训已更新您选择更新后之前编写的实训代码将会丢失如有需要请先使用jupyter中-文件-下载保存代码再进行更新</p>
{/*<p className="update_txt">还未完成评测的任务代码,请自行保存</p>*/}
</div>),
okText: '立即更新',
@ -188,6 +187,7 @@ function JupyterTPI (props) {
// 重置实训
const handleClickResetTpi = () => {
stopposttpip(1)
updataspinning(true)
Modal.confirm({
title: '重置实训',
content: (
@ -206,6 +206,7 @@ function JupyterTPI (props) {
},
onCancel() {
stopposttpip(2)
updataspinning(false)
},
})
}
@ -219,7 +220,6 @@ function JupyterTPI (props) {
title: '重置环境',
content: (
<p style={{ lineHeight: '24px' }}>
你在本文件中修改的内容将丢失,<br />
是否确定重置环境
</p>
),
@ -277,16 +277,22 @@ function JupyterTPI (props) {
const firstDrawerWidth = ()=>{
return 260
};
let newPage=false
// 分页处理
const handleChangePage = (page) => {
handlePageChange(page);
const handleChangePage = (e,page) => {
//滑动到底判断
let newscrollTop=parseInt(e.currentTarget.scrollTop);
let allclientHeight=e.currentTarget.clientHeight+newscrollTop;
if(dataSets.length<total){
if(e.currentTarget.scrollHeight-allclientHeight===0||e.currentTarget.scrollHeight-allclientHeight===1||e.currentTarget.scrollHeight-allclientHeight===-1){
handlePageChange(page+1);
}
}
}
// const listCtx = ;
useEffect(() => {
if (dataSets.length > 0) {
console.log('数据集的个数: ', dataSets.length);
// console.log('数据集的个数: ', dataSets.length);
const oList = dataSets.map((item, i) => {
return (
<li className="jupyter_item" key={`key_${i}`}>
@ -310,7 +316,7 @@ function JupyterTPI (props) {
});
const oUl = (
<ul className="jupyter_data_list" >
<ul className="jupyter_data_list" onScroll={(event)=>handleChangePage(event,pagination.page)} >
{ oList }
</ul>
);
@ -324,13 +330,14 @@ function JupyterTPI (props) {
title: '倒计时截止',
content: (
<p style={{ lineHeight: '24px' }}>
Jupyter将中断服务是否需要延长使用时间
服务已中断是否确认重置实验环境
</p>
),
okText: '确定',
cancelText: '取消',
onOk () {
active_with_tpi(myIdentifier, '重置成功');
reset_with_tpi(myIdentifier, '重置成功');
// active_with_tpi(myIdentifier, '重置成功');
}
})
}
@ -409,29 +416,29 @@ function JupyterTPI (props) {
<i className={"iconfont icon-base"}></i>
{/* <span className="iconfont icon-java jupyter_data_icon"></span>数据集 */}
</h2>
<h2 className="borbottom17212F jupyterfilepaths">
{dataSets&&dataSets.length===0?"":<h2 className="borbottom17212F jupyterfilepaths bortop17212F pt5">
<span className={"ml50"}>文件路径</span>
<div className="sortinxdirection">
<a className="jupyter_name ml50 maxnamewidth186JUPYTER lineheighttaj colorlineheighttaj">{jupyter_folder_name}</a>
<a className={"fr color-blue lineheighttaj font-14"}
<a className="jupyter_name ml50 maxnamewidth186JUPYTER colorlineheightta height45lineheight45">{jupyter_folder_name}</a>
<a className={"fr color-blue font-14 height45lineheight45"}
onClick={() => {
jsCopy("jupyter_folder_name")
}}>复制地址</a>
</div>
<input id="jupyter_folder_name" className={"file_path_input"} value={jupyter_folder_name}/>
</h2>
{ renderCtx }
<div className='jupyter_pagination'>
{total<20?"":<Pagination
simple
current={pagination.page}
pageSize={pagination.limit}
total={total}
onChange={handleChangePage}
/>}
</div>
</h2>}
{ renderCtx }
{/*<div className='jupyter_pagination'>*/}
{/* {total<20?"":<Pagination*/}
{/* simple*/}
{/* current={pagination.page}*/}
{/* pageSize={pagination.limit}*/}
{/* total={total}*/}
{/* onChange={handleChangePage}*/}
{/* />}*/}
{/*</div>*/}
</div>
</Drawer>
</div>
</div>

@ -124,11 +124,17 @@
padding: 0px;
}
.ant-drawer-wrapper-body{
overflow: hidden !important;
padding-top: 60px;
background: #070F1A;
padding-bottom: 40px;
}
.jupyter_data_list{
height:500px;
overflow-y: auto;
}
.ant-pagination{
color:#fff !important;
}
@ -231,4 +237,9 @@ line-height: 50px !important;
white-space: nowrap;
cursor: default;
width: 181px;
}
.height45lineheight45{
height: 45px;
line-height: 45px !important;
}

@ -26,7 +26,7 @@ function RightPane (props) {
const loadInit = (
<div className="jupyter_loading_init">
<Spin tip="加载中..."></Spin>
{/*<Spin tip="加载中..."></Spin>*/}
</div>
);

@ -1,13 +1,14 @@
import React, { Component } from 'react';
import { Link } from "react-router-dom";
import { markdownToHTML, configShareForCustom,getImageUrl,getUploadActionUrlthree,appendFileSizeToUploadFileAll} from 'educoder'
import { Divider, Tooltip,Upload,Modal,Spin} from 'antd';
import { Divider, Tooltip,Upload,Modal,Statistic} from 'antd';
import LoadingSpin from '../../../../common/LoadingSpin';
import 'antd/lib/pagination/style/index.css';
import '../shixunchildCss/Challenges.css';
import axios from 'axios';
import {addjypertime} from "../../../../redux/actions/jupyter";
const $ = window.$;
const { Countdown } = Statistic;
class Challengesjupyter extends Component {
constructor(props) {
super(props)
@ -28,7 +29,8 @@ class Challengesjupyter extends Component {
enlarge:false,
fileList:[],
shuaxin:false,
showtime:false
showtime:false,
jupytertime:Date.now() +3600 * 1000
}
}
@ -103,14 +105,46 @@ class Challengesjupyter extends Component {
}
}
gettimeinfo_with_tpm=(datas)=>{
let timeinfo_with_tpm=`/jupyters/timeinfo_with_tpm.json`
axios.get(timeinfo_with_tpm, {params: datas}).then((response) => {
if (response.data.status === 403||response.data.status === 401||response.data.status === 500) {
}else{
if(response.data.status===0){
if(response.data.useSeconds===null){
this.handleClickResetTpi()
}else{
let useSeconds=response.data.useSeconds;
let summain=3600 * 1000;
let sums= useSeconds * 1000;
let sum=summain-sums;
setTimeout(()=>{
this.setState({
jupytertime:Date.now() +sum
})
},500);
}
}else{
}
}
}).catch((error) => {
});
}
componentDidMount() {
var that=this;
let that=this;
setTimeout(this.ChallengesList(), 1000);
let id = this.props.match.params.shixunId;
let ChallengesURL = `/jupyters/get_info_with_tpm.json`;
let datas={
identifier:id,
}
let ChallengesURL = `/jupyters/get_info_with_tpm.json`;
axios.get(ChallengesURL, {params: datas}).then((response) => {
if (response.data.status === 403||response.data.status === 401||response.data.status === 500) {
setTimeout(() => {
@ -120,6 +154,7 @@ class Challengesjupyter extends Component {
}, 600)
}else{
if(response.data.status===0){
this.gettimeinfo_with_tpm(datas)
setTimeout(() => {
this.setState({
jupyter_url:response.data.url,
@ -344,14 +379,20 @@ class Challengesjupyter extends Component {
identifier:id
}}).then((response) => {
if(response.data.status===0){
setTimeout(()=>{
this.setState({
jupyter_url :response.data.url,
booljupyterurls:true,
})
},500);
this.props.showNotification('重置环境成功!');
setTimeout(()=>{
this.setState({
booljupyterurls:true,
})
},1000);
this.props.showNotification('重置实训成功!');
}
});
}
@ -363,7 +404,6 @@ class Challengesjupyter extends Component {
title: '重置环境',
content: (
<p style={{ lineHeight: '24px' }}>
你在本文件中修改的内容将丢失,<br />
是否确定重置环境
</p>
),
@ -377,6 +417,23 @@ class Challengesjupyter extends Component {
},
})
}
onFinish=()=>{
let id=this.props.match.params.shixunId;
Modal.confirm({
title: '倒计时截止',
content: (
<p style={{ lineHeight: '24px' }}>
服务已中断是否确认重置实验环境
</p>
),
okText: '确定',
cancelText: '取消',
onOk () {
this.handleClickResetTpisync_code(id)
}
})
}
render() {
let{ChallengesDataList,booljupyterurls,enlarge,fileList}=this.state;
let id = this.props.match.params.shixunId;
@ -427,7 +484,7 @@ class Challengesjupyter extends Component {
<div >
<style>
{
`
`
.ant-notification{
position: fixed !important;
@ -437,10 +494,21 @@ class Challengesjupyter extends Component {
position: fixed !important;
z-index: 3000 !important;
margin-top: 100px !important;
}
.Countdowntypes{
width:1px;
height:1px;
overflow: hidden;
display: block;
}
`
}
</style>
<span className={"Countdowntypes"}>
{/*this.state.jupytertime*/}
<Countdown value={this.state.jupytertime} format="HH:mm:ss" onFinish={this.onFinish}/>
</span>
<p className="clearfix mb20 edu-back-white">
<div className={"shixunjianjie"}>
<span className="font-16 fl">简介</span>
@ -504,20 +572,7 @@ class Challengesjupyter extends Component {
}
</p>}
</p>
{
booljupyterurls===true?
(
this.state.jupyter_url === null?
<div className="mt50 intermediatecenter juplbool">
<span className="icon iconfontysl icon-jiazaishibai1"></span>
<p className="intermediatecenter sortinxdirection mt5 juplboolp"><p className="colorbluetest">加载实训失败</p><p className="colorbluetwo" onClick={()=>this.updatamakedowns()}></p></p>
</div>
:""
)
:""
}
</div>
{this.state.isopentitletype==="Less"?"":this.state.opentitletype===true?<Divider dashed={true} onClick={()=>this.opentitle()} className={"pointer Breadcrumbfont color-grey-9 "}>
@ -557,7 +612,49 @@ class Challengesjupyter extends Component {
</style>
{
this.state.jupyter_url === null || this.state.jupyter_url === undefined ?
""
enlarge===true?
<div style={{
height: '63px',
}} className={enlarge?"shixunjianjiecballenges edu-back-white intermediatecenter fangdaone":"shixunjianjiecballenges edu-back-white mt20"}>
<div className={enlarge?"sortinxdirection jupyterswidth":"sortinxdirection"} >
<div className="renwuxiangssi sortinxdirection">
<div><p className="renwuxiangqdiv">任务详情</p></div>
<div><p className="renwuxiangqdivtest ml1 shixunbingbaocun">请将实训题目写在下方并保存</p></div>
</div>
<div className="renwuxiangssit xaxisreverseorder">
{
enlarge===true?
<i className="iconfont icon-suoxiao2 font-18 ml2 ysliconfont" style={{
marginLeft: '30px',
}} onClick={()=>this.onclki(false)}></i>
:
<i className="iconfont icon-fangda font-18 ml2 ysliconfont" style={{
marginLeft: '30px',
}} onClick={()=>this.onclki(true)}></i>
}
<style>
{
`
.ant-upload-list{
display:none
}
`
}
</style>
<Upload {...uploadProps}>
<div className="challenbaocun" type="upload">
<p className="challenbaocuntest" type="upload" >导入</p>
</div>
</Upload>
<button type="button" className="ant-btn deletebuttom chongzhistyles" onClick={this.handleClickResetTpi}><span>重置环境</span></button>
</div>
</div>
</div>
:""
:
(
admin===true||business===true||mysidentity===true?
@ -640,15 +737,26 @@ class Challengesjupyter extends Component {
this.state.jupyter_url===null || this.state.jupyter_url===undefined?
(
booljupyterurls===false?
<LoadingSpin></LoadingSpin>
:""
<div className={enlarge?"fangdatwo edu-back-white fangdatwoswidth":""}>
<LoadingSpin ></LoadingSpin>
</div>
:
<div className={enlarge?"fangdatwo edu-back-white fangdatwoswidth":""}>
<div className="mt50 intermediatecenter juplbool">
<span className="icon iconfontysl icon-jiazaishibai1"></span>
<p className="intermediatecenter sortinxdirection mt5 juplboolp"><p className="colorbluetest">加载实训失败</p><p className="colorbluetwo" onClick={()=>this.updatamakedowns()}></p></p>
</div>
</div>
)
:
<div className={enlarge?"fangdatwo edu-back-white":""}>
<iframe src={this.state.jupyter_url} className={enlarge?"fangdatwo":""}
scrolling="no" id="frame"
name="framename" width="100%" height="700" frameBorder="0"
></iframe>
scrolling="no" id="frame"
name="framename" width="100%" height="700" frameBorder="0"
></iframe>
</div>
}
</div>
</div>
@ -664,3 +772,17 @@ class Challengesjupyter extends Component {
}
export default Challengesjupyter;
{/*{*/}
{/* booljupyterurls===true?*/}
{/* (*/}
{/* this.state.jupyter_url === null?*/}
{/* <div className="mt50 intermediatecenter juplbool">*/}
{/* <span className="icon iconfontysl icon-jiazaishibai1"></span>*/}
{/* <p className="intermediatecenter sortinxdirection mt5 juplboolp"><p className="colorbluetest">加载实训失败,</p><p className="colorbluetwo" onClick={()=>this.updatamakedowns()}>重新加载</p></p>*/}
{/* </div>*/}
{/* :""*/}
{/* )*/}
{/* :""*/}
{/*}*/}

@ -214,6 +214,10 @@
right: 0px;
}
.fangdatwoswidth{
border-top: 1px solid #eeee;
}
.jupyterswidth{
width: 1140px;
}

@ -248,10 +248,16 @@ export const timeinfo_with_tpi = (identifier, dispatch) => {
if (res.status === 200) {
if(res.data.status===0){
if(res.data.useSeconds===null){
Modal.warning({
title: '提示',
content: '因为这个实训pod不在了无法获取倒计时请联系系统管理人员',
});
Modal.confirm({
title: '重置环境',
content:" 是否确定重置环境?" ,
okText: '确定',
cancelText: '取消',
onOk () {
reset_with_tpi(identifier, '重置成功');
},
onCancel() {}
})
}else{
let useSeconds=res.data.useSeconds;
let summain=3600 * 1000;

@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-11-20 16:35:46
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-27 14:18:02
* @LastEditTime : 2019-12-27 22:19:15
*/
import types from './actionTypes';
import CONST from '../../constants';
@ -286,17 +286,28 @@ export const validateOjForm = (props, type, cb) => {
} else if (type === 'challenge') {
cb && cb();
} else {
const {identifier} = res.data;
// message.success(paramsObj['submitType'] === 'update' ? '更新成功' : '保存成功');
notification.success({
message: '提示',
description: paramsObj['submitType'] === 'update' ? '更新成功' : '保存成功'
});
const {identifier} = res.data;
// 保存成功后的identifier
identifier && dispatch({
type: types.SAVE_OJ_FORM_ID,
payload: identifier
});
console.log(identifier , props.identifier);
if (identifier || props.identifier) {
dispatch(getOJFormById(identifier || props.identifier));
}
// 保存成功后,调用编辑接口并改变路
if (paramsObj['submitType'] === 'add' && identifier) {
props.history.push(`/problems/${identifier}/edit`);
};
}
// 保存或更新后调用start接口
// linkToDev(dispatch, props);
@ -499,7 +510,7 @@ export const deleteTestCase = (obj) => {
export const getOJFormById = (id) => {
return (dispatch) => {
fetchGetOjById(id).then(res => {
console.log('获取OJ表单信息成功: ', res);
// console.log('获取OJ表单信息成功: ', res);
dispatch({
type: types.SAVE_EDIT_OJ_FORM_AND_TEST_CASE,
payload: res.data

@ -26,9 +26,13 @@ const JupyterReducer = (state = initState, action) => {
switch (action.type) {
case types.GET_JUPYTER_DATA_SETS:
const { data_sets, data_sets_count,folder_name} = action.payload;
let newjupyter_data_set=state.jupyter_data_set;
data_sets.map((item,key)=>{
newjupyter_data_set.push(item)
})
return {
...state,
jupyter_data_set: data_sets,
jupyter_data_set: newjupyter_data_set,
jupyter_data_set_count: data_sets_count,
jupyter_folder_name:folder_name,
}

@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-11-27 13:41:48
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-27 09:18:02
* @LastEditTime : 2019-12-27 21:28:28
*/
import types from "../actions/actionTypes";
import { Base64 } from 'js-base64';
@ -58,7 +58,8 @@ const ojForUserReducer = (state = initialState, action) => {
...state,
hack: Object.assign({}, hack),
test_case: Object.assign({}, test_case),
comment_identifier: hack.identifier
comment_identifier: hack.identifier,
userCode: tempCode
}
case types.COMMIT_RECORD_DETAIL:
let result = action.payload.data;
@ -138,7 +139,8 @@ const ojForUserReducer = (state = initialState, action) => {
console.log(curHack);
return {
...state,
hack: Object.assign({}, state.hack, curHack)
hack: Object.assign({}, state.hack, curHack),
editor_code: curHack['code']
}
case types.SAVE_HACK_IDENTIFIER:
return {
@ -179,7 +181,7 @@ const ojForUserReducer = (state = initialState, action) => {
commitTestRecordDetail: {}, // 调试代码执行结果
commitRecordDetail: {}, // 提交成功后记录提交的详情
commitRecord: [], // 提交记录
userCode: '', // 保存当前用户输入的代码
// userCode: '', // 保存当前用户输入的代码
isUpdateCode: false, // 是否更新了代码内容
userCodeTab: 'task', // 学员测评tab位置: task | record | comment
userTestInput: '', // 用户自定义输入值

@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-11-20 16:40:32
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-27 10:35:06
* @LastEditTime : 2019-12-27 20:00:26
*/
import { Base64 } from 'js-base64';
import types from '../actions/actionTypes';
@ -61,6 +61,7 @@ const init = {
position: 1, // TODO 每次加载信息时同步指定positio值
score: 200, // 分值: 选择难易度后自动计算分值 200 | 500 | 1000
code: '', // 提交的代码
showCode: '', // 编辑器显示的代码
identifier: '', // OJ表单id
loading: false, // 僵尸loading标志
testCodeStatus: 'default', // 调试代码状态 default(默认值) | loading(加载中) | loaded(加载完成) | userCase(用户自定义测试用例) | finish(测试完成)
@ -216,7 +217,8 @@ const ojFormReducer = (state = initialState, action) => {
testCases: curTestCases,
testCasesValidate: curTcValidates,
testCodeStatus: hack_sets.length > 0 ? 'userCase' : 'default',
isPublish: status
isPublish: status,
showCode: cbcode
}
case types.CHANGE_PUBLISH_VALUE:
return {

@ -137,8 +137,10 @@ class SearchPage extends Component{
margin-right: 4px;
font-size: 16px !important;
}
.shixundetailtopcss{
}
`}</style>
<div className="shixunDetail_top " >
<div className="shixunDetail_top shixundetailtopcss" >
{/*<div style={{height:"53px"}}></div>*/}
<div className="intermediatecenter" style={{ width: "100%"}}>
<Search

@ -178,9 +178,10 @@
.ml9{
margin-left: 9px;
}
.shixunDetail_top{width: 100%;background-image: url("/images/educoder/searchforbackres.jpg"); height: 240px;
.shixunDetail_top{width: 100%;background-image: url("/images/educoder/searchforbackres.jpg"); height: 160px;
justify-content: center;align-items: center;display: -webkit-flex;
background-size: cover;
background-position: center;
background-repeat: no-repeat;
padding-top: 0px !important;
}

@ -3804,3 +3804,16 @@ a.singlepublishtwo{
text-align: justify;
word-break: break-all;
}
.RightPaneDrawer .ant-drawer-content{
background: #070f1a;
overflow: hidden !important;
}
.deletebuttom{
border: transparent;
}
.RightPaneDrawer .jupyter_data_list{
max-height: 340px;
}

@ -824,4 +824,17 @@ html>body #ajax-indicator { position: fixed; }
.markdown-body {
text-align: justify;
word-break: break-all;
}
.RightPaneDrawer .ant-drawer-content{
background: #070f1a;
overflow: hidden !important;
}
.deletebuttom{
border: transparent;
}
.RightPaneDrawer .jupyter_data_list{
max-height: 340px;
}
Loading…
Cancel
Save