dev_cxt
jingquan huang 5 years ago
commit 0ebf2a6918

@ -259,6 +259,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"))
@ -400,7 +401,7 @@ class ApplicationController < ActionController::Base
end
rescue Exception => e
uid_logger("--uri_exec: exception #{e.message}")
raise Educoder::TipException.new("实训平台繁忙繁忙等级84")
raise Educoder::TipException.new(message)
end
end
@ -603,7 +604,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 +679,5 @@ class ApplicationController < ActionController::Base
HotSearchKeyword.add(keyword)
end
end

@ -70,6 +70,9 @@ class HackUserLastestCodesController < ApplicationController
# 提交记录详情
def record_detail
@hack_user = HackUserCode.find params[:id]
set = HackSet.find_by(id: @hack_user.error_test_set_id)
@pass_set_count = set ? set.position - 1 : 0
@set_count = @hack_user.hack.hack_sets.count
@my_hack = @hack_user.hack_user_lastest_code
end
@ -82,7 +85,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 公用的参数
@ -96,7 +99,8 @@ class HackUserLastestCodesController < ApplicationController
if ojEvaResult['execMode'] == "debug"
save_debug_data ds_params
elsif ojEvaResult['execMode'] == "submit"
save_submit_data ds_params.merge(expected_output: testCase['expectedOutput'])
save_submit_data ds_params.merge(expected_output: testCase['expectedOutput'],
error_test_set_id: ojEvaResult['failCaseNum'])
end
# 评测完成后,还原评测中的状态
@my_hack.update_attribute(:submit_status, 0)
@ -144,11 +148,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]}.min
when 'Python'
content.scan(/line \d+/).map{|s| s.match(/\d+/)[0].to_i}.min
end
@ -172,7 +177,7 @@ class HackUserLastestCodesController < ApplicationController
# 编程题已经发布,且之前未通关奖励积分
@hack.increment!(:pass_num)
if @hack.status == 1 && !@my_hack.passed?
reward_attrs = { container_id: game.id, container_type: 'Hack', score: @hack.score }
reward_attrs = { container_id: @hack.id, container_type: 'Hack', score: @hack.score }
RewardGradeService.call(@my_hack.user, reward_attrs)
RewardExperienceService.call(@my_hack.user, reward_attrs)
# 评测完成更新通过数

@ -100,7 +100,7 @@ class HacksController < ApplicationController
@hack.update_attribute(:status, 1)
base_attrs = {
trigger_user_id: current_user.id, viewed: 0, tiding_type: 'System', user_id: @hack.user_id,
parent_container_type: "HackPublish"
parent_container_type: "HackPublish", extra: @hack.identifier
}
@hack.tidings.create!(base_attrs)
render_ok
@ -111,7 +111,7 @@ class HacksController < ApplicationController
@hack.update_attribute(:status, 0)
base_attrs = {
trigger_user_id: current_user.id, viewed: 0, tiding_type: 'System', user_id: @hack.user_id,
parent_container_type: "HackUnPublish"
parent_container_type: "HackUnPublish", extra: @hack.identifier
}
@hack.tidings.create!(base_attrs)
render_ok
@ -232,6 +232,11 @@ class HacksController < ApplicationController
hacks = hacks.where(category: params[:category])
end
# 语言
if params[:language]
hacks = hacks.joins(:hack_codes).where(hack_codes: {language: params[:language]})
end
# 排序
sort_by = params[:sort_by] || "hack_user_lastest_codes_count"
sort_direction = params[:sort_direction] || "desc"

@ -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)

@ -88,7 +88,7 @@ class JupytersController < ApplicationController
def timeinfo_with_tpi
myshixun = Myshixun.find_by(identifier: params[:identifier])
info = jupyter_timeinfo_tpi(shixun)
info = jupyter_timeinfo_tpi(myshixun)
render json: {status: 0}.merge(info)
end

@ -4,7 +4,8 @@ class ShixunListsController < ApplicationController
end
private
def search_params
params.permit(:keyword, :type, :page, :limit, :order, :status, :diff, :sort)
params.permit(:keyword, :type, :page, :limit, :order, :status, :diff, :sort, :no_jupyter)
end
end

@ -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, "实训云平台繁忙繁忙等级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("服务器出现问题,请重置环境")
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

@ -53,18 +53,20 @@ class Discuss < ApplicationRecord
def send_tiding
if dis_type == 'Shixun'
user_id = has_parent? ? parent.user_id : Challenge.find(challenge_id).user_id
send_user_id = has_parent? ? parent.user_id : Challenge.find(challenge_id).user_id
parent_container_type = 'Challenge'
challenge_id = challenge_id
extra = ''
elsif dis_type == 'Hack'
user_id = has_parent? ? parent.user_id : Hack.find(dis_id).user_id
send_user_id = has_parent? ? parent.user_id : Hack.find(dis_id).user_id
parent_container_type = 'Hack'
challenge_id = dis_id
extra = HackUserLastestCode.where(user_id: user_id, hack_id: dis_id).first&.identifier
end
base_attrs = {
trigger_user_id: user_id, parent_container_id: challenge_id, parent_container_type: parent_container_type,
belong_container_id: dis_id, belong_container_type: dis_type, viewed: 0, tiding_type: 'Comment'
belong_container_id: dis_id, belong_container_type: dis_type, viewed: 0, tiding_type: 'Comment', extra: extra
}
tidings.create!(base_attrs.merge(user_id: user_id))
tidings.create!(base_attrs.merge(user_id: send_user_id))
end
end

@ -1,4 +1,5 @@
class HackUserCode < ApplicationRecord
# error_test_set_id: 错误的测试集id
# 用户编程题的信息
belongs_to :hack
belongs_to :hack_user_lastest_code

@ -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

@ -9,7 +9,7 @@ module ElasticsearchAble
highlight: highlight_options,
body_options: body_options,
page: page,
per_page: per_page
per_page: 20
}
end
@ -37,7 +37,7 @@ module ElasticsearchAble
def per_page
per_page = params[:per_page].to_s.strip.presence || params[:limit].to_s.strip.presence
per_page.to_i <= 0 ? 20 : per_page.to_i
per_page.to_i <= 0 || per_page.to_i > 20 ? 20 : per_page.to_i
end
def page

@ -6,6 +6,9 @@ json.data do
json.language @hack_user.hack.language
json.name @hack_user.hack.name
json.myproblem_identifier @my_hack.identifier
json.pass_sets_count @pass_set_count
json.set_count @set_count
json.user do
json.partial! 'users/user', user: current_user
end

@ -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,5 +1,5 @@
json.extract! tiding, :id, :status, :viewed, :user_id, :tiding_type, :container_id, :container_type,
:parent_container_id, :parent_container_type, :belong_container_id, :belong_container_type
:parent_container_id, :parent_container_type, :belong_container_id, :belong_container_type, :extra
json.content tiding.content
json.identifier tiding.identifier

@ -0,0 +1,5 @@
class AddErrorTestSetIdForHackUserLastest < ActiveRecord::Migration[5.2]
def change
add_column :hack_user_codes, :error_test_set_id, :integer
end
end

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

@ -30,7 +30,7 @@ const env = getClientEnvironment(publicUrl);
module.exports = {
// You may want 'eval' instead if you prefer to see the compiled output in DevTools.
// See the discussion in https://github.com/facebookincubator/create-react-app/issues/343.s
devtool: "cheap-module-eval-source-map",
//devtool: "cheap-module-eval-source-map",
// 开启调试
//devtool: "source-map", // 开启调试
// These are the "entry points" to our application.

@ -1242,6 +1242,12 @@
<div class="code-name">&amp;#xe6c8;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe70f;</span>
<div class="name">减号</div>
<div class="code-name">&amp;#xe70f;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe60f;</span>
<div class="name">工程</div>
@ -1758,6 +1764,54 @@
<div class="code-name">&amp;#xe6d9;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe701;</span>
<div class="name">缩小</div>
<div class="code-name">&amp;#xe701;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe707;</span>
<div class="name">放大</div>
<div class="code-name">&amp;#xe707;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe709;</span>
<div class="name">编辑</div>
<div class="code-name">&amp;#xe709;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe70b;</span>
<div class="name">公开</div>
<div class="code-name">&amp;#xe70b;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe70c;</span>
<div class="name">解析</div>
<div class="code-name">&amp;#xe70c;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe70d;</span>
<div class="name">删除</div>
<div class="code-name">&amp;#xe70d;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe70e;</span>
<div class="name">试题栏</div>
<div class="code-name">&amp;#xe70e;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe710;</span>
<div class="name">复制</div>
<div class="code-name">&amp;#xe710;</div>
</li>
</ul>
<div class="article markdown">
<h2 id="unicode-">Unicode 引用</h2>
@ -3626,6 +3680,15 @@
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-jianhao"></span>
<div class="name">
减号
</div>
<div class="code-name">.icon-jianhao
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-gongcheng"></span>
<div class="name">
@ -4400,6 +4463,78 @@
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-suoxiao2"></span>
<div class="name">
缩小
</div>
<div class="code-name">.icon-suoxiao2
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-fangda"></span>
<div class="name">
放大
</div>
<div class="code-name">.icon-fangda
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-bianji2"></span>
<div class="name">
编辑
</div>
<div class="code-name">.icon-bianji2
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-gongkai"></span>
<div class="name">
公开
</div>
<div class="code-name">.icon-gongkai
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-jiexi"></span>
<div class="name">
解析
</div>
<div class="code-name">.icon-jiexi
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-shanchu1"></span>
<div class="name">
删除
</div>
<div class="code-name">.icon-shanchu1
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-shitilan"></span>
<div class="name">
试题栏
</div>
<div class="code-name">.icon-shitilan
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-fuzhi3"></span>
<div class="name">
复制
</div>
<div class="code-name">.icon-fuzhi3
</div>
</li>
</ul>
<div class="article markdown">
<h2 id="font-class-">font-class 引用</h2>
@ -6045,6 +6180,14 @@
<div class="code-name">#icon-pinglun</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-jianhao"></use>
</svg>
<div class="name">减号</div>
<div class="code-name">#icon-jianhao</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-gongcheng"></use>
@ -6733,6 +6876,70 @@
<div class="code-name">#icon-zhiding</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-suoxiao2"></use>
</svg>
<div class="name">缩小</div>
<div class="code-name">#icon-suoxiao2</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-fangda"></use>
</svg>
<div class="name">放大</div>
<div class="code-name">#icon-fangda</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-bianji2"></use>
</svg>
<div class="name">编辑</div>
<div class="code-name">#icon-bianji2</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-gongkai"></use>
</svg>
<div class="name">公开</div>
<div class="code-name">#icon-gongkai</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-jiexi"></use>
</svg>
<div class="name">解析</div>
<div class="code-name">#icon-jiexi</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-shanchu1"></use>
</svg>
<div class="name">删除</div>
<div class="code-name">#icon-shanchu1</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-shitilan"></use>
</svg>
<div class="name">试题栏</div>
<div class="code-name">#icon-shitilan</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-fuzhi3"></use>
</svg>
<div class="name">复制</div>
<div class="code-name">#icon-fuzhi3</div>
</li>
</ul>
<div class="article markdown">
<h2 id="symbol-">Symbol 引用</h2>

@ -397,9 +397,9 @@ label.infolabel{display: block;float: left;width: 56px;text-align: right;margin-
.task-colspan{min-width:25%;text-align: left;display: block;float: left;color: #999; }
.colspan-grey{border-radius: 12px;background-color: #E6E6E6;padding: 3px 10px;color: #747A7F}
/*新建任务*/
.challenge_nav{padding: 40px 20px 0px 20px;border-bottom: 1px solid #eee;}
.challenge_nav li{width: auto;float: left;margin-right: 40px;position: relative}
.challenge_nav li.active:after{position: absolute;content: '';width: 50%;background-color: #4CACFF;height: 3px;border-radius: 2px;left: 25%;bottom: 0px;}
.challenge_nav{padding: 20px 20px 0px 20px;border-bottom: 1px solid #eee;}
.challenge_nav li{width: auto;float: left;margin-right: 20px;position: relative}
.challenge_nav li.active:after{position: absolute;content: '';width: 76%;background-color: #4CACFF;height: 3px;border-radius: 2px;left: 25%;bottom: 0px;}
.challenge_nav li a{display: block;width: 100%;padding-bottom: 20px;}
.add_choose_type{width: 60px;height: 20px;line-height: 19px;border-radius: 2px;background-color: #eaeaea;color: #999!important;display: block;float: left;text-align: center;margin-top: 4px;}
@ -524,7 +524,7 @@ li.li-width15{width: 15%;text-align: left}
li.li-width7{width: 7%;text-align: left}
/*-----------------------------在线课堂动态----------------------------------*/
.courseHead{width: 100%;margin-bottom:40px;background-size: 100% 100%;background-image: url("/images/educoder/course-detail.jpg");height: 240px;
.courseHead{width: 100%;margin-bottom:40px;background-size: 100% 100%;background-image: url("/images/educoder/courtailsbdpicture.jpg");height: 240px;
justify-content: center;align-items: center;display: -webkit-flex;
background-size: cover;
background-position: center;
@ -3483,4 +3483,17 @@ a.singlepublishtwo{
.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;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1419,6 +1419,13 @@
"unicode": "e6c8",
"unicode_decimal": 59080
},
{
"icon_id": "7556166",
"name": "减号",
"font_class": "jianhao",
"unicode": "e70f",
"unicode_decimal": 59151
},
{
"icon_id": "7587940",
"name": "工程",
@ -2020,6 +2027,62 @@
"font_class": "zhiding",
"unicode": "e6d9",
"unicode_decimal": 59097
},
{
"icon_id": "12403050",
"name": "缩小",
"font_class": "suoxiao2",
"unicode": "e701",
"unicode_decimal": 59137
},
{
"icon_id": "12403054",
"name": "放大",
"font_class": "fangda",
"unicode": "e707",
"unicode_decimal": 59143
},
{
"icon_id": "12491363",
"name": "编辑",
"font_class": "bianji2",
"unicode": "e709",
"unicode_decimal": 59145
},
{
"icon_id": "12491366",
"name": "公开",
"font_class": "gongkai",
"unicode": "e70b",
"unicode_decimal": 59147
},
{
"icon_id": "12491369",
"name": "解析",
"font_class": "jiexi",
"unicode": "e70c",
"unicode_decimal": 59148
},
{
"icon_id": "12491370",
"name": "删除",
"font_class": "shanchu1",
"unicode": "e70d",
"unicode_decimal": 59149
},
{
"icon_id": "12491850",
"name": "试题栏",
"font_class": "shitilan",
"unicode": "e70e",
"unicode_decimal": 59150
},
{
"icon_id": "12568379",
"name": "复制",
"font_class": "fuzhi3",
"unicode": "e710",
"unicode_decimal": 59152
}
]
}

@ -626,6 +626,9 @@ Created by iconfont
<glyph glyph-name="pinglun" unicode="&#59080;" d="M896 704H128c-35.2 0-64-28.8-64-64v-448c0-35.2 28.8-64 64-64h256l128-64 128 64h256c35.2 0 64 28.8 64 64V640c0 35.2-28.8 64-64 64zM304 368c-26.5 0-48 21.5-48 48s21.5 48 48 48 48-21.5 48-48-21.5-48-48-48z m208 0c-26.5 0-48 21.5-48 48s21.5 48 48 48 48-21.5 48-48-21.5-48-48-48z m208 0c-26.5 0-48 21.5-48 48s21.5 48 48 48 48-21.5 48-48-21.5-48-48-48z" horiz-adv-x="1024" />
<glyph glyph-name="jianhao" unicode="&#59151;" d="M768 341.333333H256c-25.6 0-42.666667 17.066667-42.666667 42.666667s17.066667 42.666667 42.666667 42.666667h512c25.6 0 42.666667-17.066667 42.666667-42.666667s-17.066667-42.666667-42.666667-42.666667z" horiz-adv-x="1024" />
<glyph glyph-name="gongcheng" unicode="&#58895;" d="M141.9 476.8L454.1 298c18.2-10.6 38.9-16.3 59.9-16.3 21.2 0 41.7 5.6 59.4 16.3l312.4 178.6c21.7 11.8 35.2 36.5 34.5 63.1-0.8 26.2-15.4 50.2-37.4 61.2L567.3 758.4c-33.9 16.9-72.8 16.9-106.6 0L144.9 600.8c-22.5-11.6-36.4-34.5-37.2-61.1-0.8-26.3 12.3-50.4 34.2-62.9z m22.3 85.9l315.6 157.5c10.9 5.4 22.5 8.2 34.2 8.2 11.7 0 23.4-2.7 34.2-8.2l315.5-157.5c8.1-4 13.5-13.6 13.8-24.2 0.3-10.6-4.5-20.2-12.2-24.3L552 335l-0.5-0.3c-11-6.7-24-10.2-37.5-10.2s-26.7 3.6-38.5 10.5L163.1 513.8c-8 4.6-13 14.3-12.7 24.6 0.3 10.9 5.6 20 13.8 24.3zM888.4 249.7l-369-211c-3.5-2-7.1-2-10.7 0.1L139.6 249.7c-10.3 5.9-23.3 2.3-29.1-7.9-5.9-10.2-2.3-23.3 7.9-29.1l368.8-210.8c8.4-4.9 17.6-7.3 26.7-7.3 9.2 0 18.3 2.4 26.6 7.2l368.9 210.9c10.2 5.9 13.8 18.9 7.9 29.1-5.6 10.2-18.7 13.8-28.9 7.9zM888.4 387.1l-369-211c-3.5-2-7.1-2-10.7 0.1L139.6 387.1c-10.3 5.9-23.3 2.3-29.1-7.9-5.9-10.2-2.3-23.3 7.9-29.1l368.8-210.8c8.4-4.9 17.6-7.3 26.7-7.3 9.2 0 18.3 2.4 26.6 7.2L909.6 350c10.2 5.9 13.8 18.9 7.9 29.1-5.8 10.3-18.9 13.8-29.1 8z" horiz-adv-x="1024" />
@ -884,6 +887,30 @@ Created by iconfont
<glyph glyph-name="zhiding" unicode="&#59097;" d="M496.0256 671.232L129.024 212.48A20.48 20.48 0 0 1 144.9984 179.2H337.92c11.264 0 20.48-9.216 20.48-20.48v-266.24c0-11.264 9.216-20.48 20.48-20.48h266.24a20.48 20.48 0 0 1 20.48 20.48V158.72c0 11.264 9.216 20.48 20.48 20.48h192.9216a20.48 20.48 0 0 1 15.9744 33.28l-367.0016 458.752a20.48 20.48 0 0 1-31.9488 0zM153.6 896m51.2 0l614.4 0q51.2 0 51.2-51.2l0 0q0-51.2-51.2-51.2l-614.4 0q-51.2 0-51.2 51.2l0 0q0 51.2 51.2 51.2Z" horiz-adv-x="1024" />
<glyph glyph-name="suoxiao2" unicode="&#59137;" d="M921.6 418.133333h-318.577778c-5.688889 0-17.066667 0-22.755555 5.688889-5.688889 0-11.377778 5.688889-17.066667 11.377778-5.688889 5.688889-11.377778 11.377778-11.377778 17.066667 0 5.688889-5.688889 11.377778-5.688889 22.755555V793.6c0 34.133333 22.755556 56.888889 56.888889 56.888889s56.888889-22.755556 56.888889-56.888889V611.555556L927.288889 878.933333c22.755556 22.755556 56.888889 22.755556 79.644444 0s22.755556-56.888889 0-79.644444L739.555556 531.911111h182.044444c34.133333 0 56.888889-22.755556 56.888889-56.888889s-22.755556-56.888889-56.888889-56.888889zM56.888889-128c-17.066667 0-28.444444 5.688889-39.822222 17.066667-22.755556 22.755556-22.755556 56.888889 0 79.644444L284.444444 236.088889H102.4c-34.133333 0-56.888889 22.755556-56.888889 56.888889s22.755556 56.888889 56.888889 56.888889h318.577778c5.688889 0 17.066667 0 22.755555-5.688889 5.688889 0 11.377778-5.688889 17.066667-11.377778 5.688889-5.688889 11.377778-11.377778 11.377778-17.066667 0-5.688889 5.688889-11.377778 5.688889-22.755555v-318.577778c0-34.133333-22.755556-56.888889-56.888889-56.888889s-56.888889 22.755556-56.888889 56.888889V156.444444l-267.377778-267.377777c-11.377778-11.377778-22.755556-17.066667-39.822222-17.066667z" horiz-adv-x="1024" />
<glyph glyph-name="fangda" unicode="&#59143;" d="M603.022222 418.133333c-17.066667 0-28.444444 5.688889-39.822222 17.066667-22.755556 22.755556-22.755556 56.888889 0 79.644444L830.577778 782.222222h-182.044445c-34.133333 0-56.888889 22.755556-56.888889 56.888889s22.755556 56.888889 56.888889 56.888889H967.111111c5.688889 0 17.066667 0 22.755556-5.688889 5.688889 0 11.377778-5.688889 17.066666-11.377778 5.688889-5.688889 11.377778-11.377778 11.377778-17.066666 5.688889-5.688889 5.688889-17.066667 5.688889-22.755556v-318.577778c0-34.133333-22.755556-56.888889-56.888889-56.888889s-56.888889 22.755556-56.888889 56.888889V702.577778l-267.377778-267.377778c-11.377778-11.377778-22.755556-17.066667-39.822222-17.066667zM375.466667-128H56.888889c-5.688889 0-17.066667 0-22.755556 5.688889-5.688889 0-11.377778 5.688889-17.066666 11.377778-5.688889 5.688889-11.377778 11.377778-11.377778 17.066666-5.688889 5.688889-5.688889 17.066667-5.688889 22.755556v318.577778c0 34.133333 22.755556 56.888889 56.888889 56.888889s56.888889-22.755556 56.888889-56.888889v-182.044445l267.377778 267.377778c22.755556 22.755556 56.888889 22.755556 79.644444 0s22.755556-56.888889 0-79.644444L193.422222-14.222222h182.044445c34.133333 0 56.888889-22.755556 56.888889-56.888889s-22.755556-56.888889-56.888889-56.888889z" horiz-adv-x="1024" />
<glyph glyph-name="bianji2" unicode="&#59145;" d="M704.752941-97.882353H198.776471c-78.305882 0-138.541176 60.235294-138.541177 132.517647V667.105882c0 72.282353 66.258824 132.517647 138.541177 132.517647h319.247058c18.070588 0 30.117647-12.047059 30.117647-30.117647s-12.047059-24.094118-30.117647-24.094117H198.776471c-42.164706 0-78.305882-36.141176-78.305883-72.282353v-632.470588c0-42.164706 36.141176-72.282353 78.305883-72.282353h499.952941c42.164706 0 78.305882 36.141176 78.305882 72.282353V293.647059c0 18.070588 12.047059 30.117647 30.117647 30.117647s30.117647-12.047059 30.117647-30.117647v-259.011765c6.023529-72.282353-60.235294-132.517647-132.517647-132.517647zM313.223529 161.129412c-24.094118 0-54.211765 18.070588-60.235294 48.188235v30.117647l36.141177 126.494118 445.741176 445.741176c48.188235 48.188235 120.470588 48.188235 168.658824 0 48.188235-48.188235 48.188235-120.470588 0-168.658823l-445.741177-445.741177-126.494117-30.117647c-6.023529-6.023529-12.047059-6.023529-18.070589-6.023529z m36.141177 174.682353l-36.141177-114.447059 120.470589 30.117647 433.694117 433.694118c12.047059 12.047059 18.070588 24.094118 18.070589 42.164705 0 18.070588-6.023529 30.117647-18.070589 42.164706-24.094118 24.094118-60.235294 24.094118-84.329411 0L349.364706 335.811765z" horiz-adv-x="1024" />
<glyph glyph-name="gongkai" unicode="&#59147;" d="M512 42.666667C432.355556 42.666667 369.777778 105.244444 369.777778 184.888889S432.355556 327.111111 512 327.111111s142.222222-62.577778 142.222222-142.222222S591.644444 42.666667 512 42.666667z m0 227.555555c-45.511111 0-85.333333-39.822222-85.333333-85.333333S466.488889 99.555556 512 99.555556 597.333333 139.377778 597.333333 184.888889 557.511111 270.222222 512 270.222222zM256 469.333333c-17.066667 0-28.444444 11.377778-28.444444 28.444445V662.755556C244.622222 782.222222 352.711111 867.555556 483.555556 867.555556c142.222222 0 250.311111-96.711111 256-221.866667v-5.688889c0-17.066667-11.377778-28.444444-28.444445-28.444444s-28.444444 11.377778-28.444444 28.444444c-5.688889 96.711111-91.022222 170.666667-199.111111 170.666667-102.4 0-187.733333-68.266667-199.111112-153.6V497.777778c0-17.066667-11.377778-28.444444-28.444444-28.444445zM739.555556-128h-455.111112C176.355556-128 85.333333-36.977778 85.333333 71.111111v227.555556C85.333333 406.755556 176.355556 497.777778 284.444444 497.777778h455.111112c108.088889 0 199.111111-91.022222 199.111111-199.111111v-227.555556c0-108.088889-91.022222-199.111111-199.111111-199.111111z m-455.111112 568.888889C204.8 440.888889 142.222222 378.311111 142.222222 298.666667v-227.555556C142.222222-8.533333 204.8-71.111111 284.444444-71.111111h455.111112c79.644444 0 142.222222 62.577778 142.222222 142.222222v227.555556C881.777778 378.311111 819.2 440.888889 739.555556 440.888889h-455.111112z" horiz-adv-x="1024" />
<glyph glyph-name="jiexi" unicode="&#59148;" d="M506.311111-99.555556c-73.955556 0-147.911111 17.066667-216.177778 51.2-11.377778 5.688889-22.755556 22.755556-11.377777 39.822223 5.688889 11.377778 22.755556 22.755556 39.822222 11.377777 56.888889-28.444444 125.155556-45.511111 187.733333-45.511111 238.933333 0 432.355556 187.733333 432.355556 426.666667 0 85.333333-22.755556 164.977778-73.955556 233.244444-11.377778 11.377778-5.688889 28.444444 5.688889 39.822223 11.377778 11.377778 28.444444 5.688889 39.822222-5.688889 51.2-79.644444 79.644444-170.666667 79.644445-267.377778 5.688889-267.377778-216.177778-483.555556-483.555556-483.555556z m-301.511111 125.155556c-5.688889 0-11.377778 0-17.066667 5.688889C85.333333 122.311111 28.444444 253.155556 28.444444 389.688889 28.444444 651.377778 238.933333 867.555556 500.622222 867.555556c119.466667 0 233.244444-45.511111 318.577778-125.155556 11.377778-11.377778 11.377778-28.444444 0-39.822222-11.377778-11.377778-28.444444-11.377778-39.822222 0-79.644444 73.955556-176.355556 113.777778-278.755556 113.777778-227.555556 0-415.288889-187.733333-415.288889-420.977778 0-125.155556 51.2-238.933333 142.222223-318.577778 11.377778-11.377778 11.377778-28.444444 0-39.822222-5.688889-11.377778-11.377778-11.377778-22.755556-11.377778zM512 31.288889c-56.888889 0-102.4 45.511111-102.4 102.4v34.133333c-62.577778 34.133333-102.4 102.4-102.4 170.666667C307.2 446.577778 398.222222 537.6 512 537.6s204.8-91.022222 204.8-199.111111c0-68.266667-39.822222-136.533333-102.4-170.666667v-34.133333c0-51.2-39.822222-96.711111-91.022222-102.4H512z m0 449.422222c-79.644444 0-147.911111-62.577778-147.911111-142.222222 0-51.2 28.444444-96.711111 73.955555-125.155556l28.444445-17.066666v-68.266667c0-22.755556 17.066667-45.511111 45.511111-45.511111h5.688889c22.755556 0 39.822222 22.755556 39.822222 45.511111v68.266667l28.444445 17.066666c45.511111 22.755556 73.955556 73.955556 73.955555 125.155556 0 73.955556-68.266667 142.222222-147.911111 142.222222zM676.977778 497.777778c-5.688889 0-17.066667 0-22.755556 5.688889-11.377778 11.377778-11.377778 28.444444 0 39.822222L739.555556 628.622222c11.377778 11.377778 28.444444 11.377778 39.822222 0s11.377778-28.444444 0-39.822222l-85.333334-85.333333c-5.688889 0-11.377778-5.688889-17.066666-5.688889zM347.022222 497.777778c-5.688889 0-11.377778 5.688889-17.066666 5.688889L238.933333 594.488889c-11.377778 11.377778-11.377778 28.444444 0 39.822222s28.444444 11.377778 39.822223 0l85.333333-85.333333c11.377778-11.377778 11.377778-28.444444 0-39.822222 0-5.688889-5.688889-11.377778-17.066667-11.377778zM512 560.355556c-17.066667 0-28.444444 11.377778-28.444444 28.444444V685.511111c0 17.066667 11.377778 28.444444 28.444444 28.444445s28.444444-11.377778 28.444444-28.444445v-102.4c0-11.377778-11.377778-22.755556-28.444444-22.755555z" horiz-adv-x="1024" />
<glyph glyph-name="shanchu1" unicode="&#59149;" d="M672-96H358.4c-76.8 0-140.8 57.6-153.6 140.8L96 569.6c0 19.2 6.4 32 25.6 38.4 19.2 6.4 32-6.4 38.4-25.6l102.4-524.8c12.8-51.2 51.2-89.6 96-89.6h313.6c44.8 0 83.2 38.4 96 89.6l102.4 524.8c6.4 19.2 19.2 25.6 38.4 25.6 19.2-6.4 25.6-19.2 25.6-38.4L832 44.8c-19.2-83.2-83.2-140.8-160-140.8zM608 704v6.4c0 51.2-44.8 89.6-96 89.6S416 755.2 416 704h-64C352 793.6 422.4 864 512 864c83.2 0 153.6-64 160-153.6V704h-64zM384 38.4c-12.8 0-25.6 12.8-32 25.6L256 576c0 19.2 12.8 32 25.6 38.4 19.2 0 38.4-12.8 38.4-25.6l96-512c0-19.2-6.4-38.4-32-38.4 6.4 0 0 0 0 0zM640 38.4s-6.4 0 0 0c-25.6 6.4-32 19.2-32 38.4l96 512c0 19.2 19.2 32 38.4 25.6 12.8-6.4 25.6-19.2 25.6-38.4l-96-512c-6.4-12.8-19.2-25.6-32-25.6zM512 38.4c-19.2 0-32 12.8-32 32v512c0 19.2 12.8 32 32 32s32-12.8 32-32v-512c0-19.2-12.8-32-32-32zM992 640H32C12.8 640 0 652.8 0 672S12.8 704 32 704h960c19.2 0 32-12.8 32-32s-12.8-32-32-32z" horiz-adv-x="1024" />
<glyph glyph-name="shitilan" unicode="&#59150;" d="M816.118519-128H184.019753c-69.530864 0-126.419753 56.888889-126.419753 126.419753V756.938272C57.6 826.469136 114.488889 883.358025 184.019753 883.358025h568.888889l189.62963-189.62963v-695.308642c0-69.530864-56.888889-126.419753-126.419753-126.419753zM727.624691 820.148148H184.019753c-37.925926 0-63.209877-25.283951-63.209876-63.209876v-758.518519c0-37.925926 25.283951-63.209877 63.209876-63.209876h632.098766c37.925926 0 63.209877 25.283951 63.209876 63.209876V668.444444L727.624691 820.148148zM955.180247 662.123457h-189.62963c-25.283951 0-44.246914 18.962963-44.246913 44.246913l6.320987 189.62963 227.555556-233.876543z m-170.666667 82.172839v-18.962963h18.962963l-18.962963 18.962963zM670.735802 567.308642H329.402469c-18.962963 0-31.604938 12.641975-31.604938 31.604938S310.439506 630.518519 329.402469 630.518519h341.333333c18.962963 0 31.604938-12.641975 31.604939-31.604939s-12.641975-31.604938-31.604939-31.604938zM670.735802 314.469136H329.402469c-18.962963 0-31.604938 12.641975-31.604938 31.604938S310.439506 377.679012 329.402469 377.679012h341.333333c18.962963 0 31.604938-12.641975 31.604939-31.604938s-12.641975-31.604938-31.604939-31.604938zM670.735802 61.62963H329.402469c-18.962963 0-31.604938 12.641975-31.604938 31.604938s12.641975 31.604938 31.604938 31.604938h341.333333c18.962963 0 31.604938-12.641975 31.604939-31.604938s-12.641975-31.604938-31.604939-31.604938z" horiz-adv-x="1024" />
<glyph glyph-name="fuzhi3" unicode="&#59152;" d="M648.533333-128h-477.866666C75.093333-128 0-52.906667 0 42.666667v477.866666C0 616.106667 75.093333 691.2 170.666667 691.2h477.866666C744.106667 691.2 819.2 616.106667 819.2 520.533333v-477.866666c0-95.573333-75.093333-170.666667-170.666667-170.666667z m-477.866666 750.933333C116.053333 622.933333 68.266667 575.146667 68.266667 520.533333v-477.866666c0-54.613333 47.786667-102.4 102.4-102.4h477.866666c54.613333 0 102.4 47.786667 102.4 102.4v477.866666c0 54.613333-47.786667 102.4-102.4 102.4h-477.866666zM955.733333 110.933333c-20.48 0-34.133333 13.653333-34.133333 34.133334V691.2c0 54.613333-47.786667 102.4-102.4 102.4H273.066667c-20.48 0-34.133333 13.653333-34.133334 34.133333s13.653333 34.133333 34.133334 34.133334h546.133333c95.573333 0 170.666667-75.093333 170.666667-170.666667v-546.133333c0-20.48-13.653333-34.133333-34.133334-34.133334z" horiz-adv-x="1024" />
</font>

Before

Width:  |  Height:  |  Size: 362 KiB

After

Width:  |  Height:  |  Size: 374 KiB

@ -727,7 +727,7 @@ class App extends Component {
(props) => (<RecordDetail {...this.props} {...props} {...this.state} />)
}
/>
<Route path="/myproblems/:id"
<Route path="/myproblems/:id/:tab?"
render={
(props) => (<StudentStudy {...this.props} {...props} {...this.state} />)
} />

@ -27,7 +27,7 @@ function onMessageByLocalStorage(eventName, callback) {
}
window.addEventListener("storage", function(ev) {
const cb = localStorageMap[ev.key];
console.log('storage event:', ev)
// console.log('storage event:', ev)
if (cb) {
cb(JSON.parse(ev.newValue))
}

@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-12-17 17:32:55
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-26 11:11:57
* @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 = () => {
@ -69,7 +71,7 @@ function CommentForm (props) {
props.form.setFieldsValue({'comment': ''});
setCtx('');
// const _html = formatDelta(content.ops);
console.log('保存的内容=====》》》》', content);
// console.log('保存的内容=====》》》》', content);
onSubmit && onSubmit(JSON.stringify(content));
}
});
@ -116,6 +118,7 @@ function CommentForm (props) {
overflow: showQuill ? 'none' : 'hidden',
transition: 'all 0.3s'
}}
autoFocus={focus}
style={{ height: '150px' }}
placeholder="说点儿什么~"
options={options}

@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-12-17 17:35:17
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-26 11:30:32
* @LastEditTime : 2019-12-27 11:05:17
*/
import './index.scss';
import 'quill/dist/quill.core.css'; // 核心样式
@ -36,6 +36,8 @@ function CommentItem ({
const [showItemCount, setShowItemCount] = useState(5);
// 箭头方向
const [arrow, setArrow] = useState(false);
// 上传图片的ulr
const [url, setUrl] = useState('');
const {
author = {}, // 作者
@ -85,6 +87,10 @@ function CommentItem ({
);
};
const handleShowUploadImage = (url) => {
// console.log('==============>>>>>>>>>>>>',url);
setUrl(url);
}
// 评论内容
const commentCtx = (ctx) => {
let _ctx = null;
@ -97,6 +103,7 @@ function CommentItem ({
<QuillForEditor
readOnly={true}
value={_ctx}
showUploadImage={handleShowUploadImage}
/>
)};
@ -181,6 +188,10 @@ function CommentItem ({
}
}
const handleClose = () => {
setUrl('');
}
return (
<li className="comment_item_area">
{commentAvatar(author)}
@ -225,11 +236,19 @@ function CommentItem ({
<div
style={{ display: showQuill ? 'block' : 'none'}}
className="comment_item_quill">
<CommentForm
<CommentForm
onCancel={handleClickCancel}
onSubmit={handleClickSubmit(id)}
/>
</div>
{/* 显示上传的图片信息 */}
<div className="show_upload_image" style={{ display: url ? 'block' : 'none'}}>
<Icon type="close" className="image_close" onClick={handleClose}/>
<div className="image_info">
<img className="image" src={url} alt=""/>
</div>
</div>
</div>
</li>
);

@ -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;
@ -87,6 +89,46 @@ $ml: 20px;
// .comment_item_quill{
// // margin-top: 10px;
// }
.show_upload_image{
position: fixed;
left: 0;
top: 0;
right: 0;
bottom: 0;
z-index: 1000;
&::before{
position: absolute;
height: 100%;
width:100%;
content: '';
background: #000;
opacity: .7;
}
.image_info{
display: flex;
position: absolute;
width: 80%;
height: 80%;
left: 10%;
top: 10%;
justify-content: center;
align-items: center;
// background: green;
.image{
display: block;
width: 100%;
}
}
.image_close{
position: absolute;
right: 20px;
top: 20px;
color: #fff;
cursor: pointer;
}
}
}
.comment_icon_count{
cursor: pointer;

@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-12-16 15:50:45
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-24 09:44:03
* @LastEditTime : 2019-12-27 15:07:11
*/
import Quill from "quill";
@ -15,25 +15,38 @@ export default class ImageBlot extends BlockEmbed {
static create(value) {
const node = super.create();
node.setAttribute('alt', value.alt);
node.setAttribute('src', value.url);
// console.log('~~~~~~~~~~~', node, value);
node.addEventListener('click', function () {
value.onclick(value.url);
}, false);
if (value.width) {
node.setAttribute('width', value.width);
}
if (value.height) {
node.setAttribute('height', value.height);
}
if (value.id) {
node.setAttribute('id', value.id);
}
// 宽度和高度都不存在时,
if (!value.width && !value.height) {
node.setAttribute('display', 'block');
// node.setAttribute('display', 'block');
node.setAttribute('width', '100%');
}
// node.setAttribute('style', { cursor: 'pointer' });
// if (node.onclick) {
// console.log('image 有图片点击事件======》》》》》》');
// // node.setAttribute('onclick', node.onCLick);
// }
// 给图片添加点击事件
node.onclick = () => {
value.onClick && value.onClick(value.url);
}
// node.onclick = () => {
// value.onClick && value.onClick(value.url);
// }
return node;
}
@ -45,7 +58,9 @@ export default class ImageBlot extends BlockEmbed {
onclick: node.onclick,
width: node.width,
height: node.height,
display: node.getAttribute('display')
display: node.getAttribute('display'),
id: node.id,
// style: node.style
};
}
}

@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-12-18 08:49:30
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-26 10:22:26
* @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 = {}, // 指定图片的宽高
@ -116,9 +117,22 @@ function QuillForEditor ({
// 设置值
useEffect(() => {
if (!quill) return
// debugger;
const previous = quill.getContents()
const current = value
if (value && value.hasOwnProperty('ops')) {
// console.log(value.ops);
const ops = value.ops || [];
ops.forEach((item, i) => {
if (item.insert['image']) {
item.insert['image'] = Object.assign({}, item.insert['image'], {style: { cursor: 'pointer' }, onclick: (url) => showUploadImage(url)});
}
});
}
const current = value
// console.log('+++++', current);
if (!deepEqual(previous, current)) {
setSelection(quill.getSelection())
if (typeof value === 'string') {
@ -159,6 +173,12 @@ function QuillForEditor ({
}
}, [quill, handleOnChange]);
useEffect(() => {
if (autoFocus) {
quill.focus();
}
}, [quill, autoFocus]);
// 返回结果
return (
<div className='quill_editor_for_react_area' style={wrapStyle}>

@ -2,4 +2,9 @@
.ql-editing{
left: 0 !important;
}
.ql-editor{
img{
cursor: pointer;
}
}
}

@ -375,19 +375,19 @@ class CoursesBanner extends Component {
}
addTeacher = (isTeacher) => {
this.setState({ isTeacher }, () => {
this.refs.addTeacherModal.setVisible(true)
})
this.refs.addTeacherModal.setVisible(true)
})
}
addStudent = () => {
this.refs.addStudentModal.setVisible(true)
this.refs.addStudentModal.setVisible(true)
}
addTeacherSuccess = (params) => {
trigger('addTeacherSuccess', JSON.stringify(params))
this.updatabanner()
}
addStudentSuccess = (params) => {
trigger('addStudentSuccess', JSON.stringify(params))
trigger('addStudentSuccess', JSON.stringify(params))
this.updatabanner()
}
//退出课堂按钮
@ -721,14 +721,33 @@ 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")}>待审批</a></span>:""}</pre>}>
<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"
}}>
待审批
</span></a></span>:""}</pre>}>
<span className="color-grey-c font-16" onClick={()=>this.setHistoryFun("/courses/"+this.props.match.params.coursesId+"/teachers")}>
<span className={"mr10"}>教师</span>
<span className={"mr10"}>{coursedata.teacher_count}</span>

@ -34,6 +34,7 @@ class NewShixunModel extends Component{
getdatalist=(page,type,newstatus,keyword,order,diff,limit,pagetype,sorts)=>{
let newsort=sorts;
let no_jupyter=undefined;
if(this.props.type==="shixuns"&&type==="mine"){
if(this.props&&this.props.user.course_name===undefined){
newsort="created_at";
@ -41,6 +42,12 @@ class NewShixunModel extends Component{
newsort="publish_time";
}
}
if(this.props.type==="shixuns"){
if(this.props&&this.props.user.course_name===undefined){
}else{
no_jupyter=1;
}
}
this.setState({
isspinning:true
})
@ -51,6 +58,7 @@ class NewShixunModel extends Component{
}else{
url="/subject_lists.json";
}
axios.get(url,{params:{
page:page,
type:type,
@ -59,7 +67,8 @@ class NewShixunModel extends Component{
order:order,
diff:diff,
limit:limit,
sort:newsort
sort:newsort,
no_jupyter:no_jupyter
}}).then((response) => {
if(response.data){
if(pagetype===undefined){

@ -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;
}

@ -9,7 +9,7 @@
import './index.scss';
import React from 'react';
import { Table, Button, Dropdown, Icon, Menu, Card, Input, Select, Tag, Modal } from 'antd';
import { Table, Button, Dropdown, Icon, Menu, Card, Input, Select, Tag } from 'antd';
import { connect } from 'react-redux';
import actions from '../../redux/actions';
import MultipTags from './components/multiptags';
@ -46,9 +46,24 @@ const maps = {
],
'languageMenu': [
{
'key': 'c',
'name': 'C语言',
'value': 'c'
'key': 'C',
'name': 'C',
'value': 'C'
},
{
'key': 'C++',
'name': 'C++',
'value': 'C++'
},
{
'key': 'Python',
'name': 'Python',
'value': 'Python'
},
{
'key': 'Java',
'name': 'Java',
'value': 'Java'
}
],
'difficultMenu': [
@ -105,7 +120,6 @@ const testMaps = {
2: '数据结构与算法'
}
}
class DeveloperHome extends React.PureComponent {
/**
* 表格列
@ -254,7 +268,7 @@ class DeveloperHome extends React.PureComponent {
content: `确定要删除${record.name}吗?`,
onOk () {
// 调用删除接口
console.log(record.identifier);
// console.log(record.identifier);
deleteItem(record.identifier);
}
});
@ -491,7 +505,7 @@ class DeveloperHome extends React.PureComponent {
</div>
</div>
<div className={'card-table'}>
<div bordered={false} className={'filter_ctx_area'}>
<div className={'filter_ctx_area'}>
<div>
<Dropdown className={'dropdonw-style'} placement="bottomLeft" overlay={this.getMenuItems('categoryMenu', this.handleCategoryMenuClick)}>
<span className={'dropdown-span'}>分类 <Icon type="down"/></span>

@ -4,11 +4,11 @@
* @Github:
* @Date: 2019-11-27 16:02:36
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-26 15:17:28
* @LastEditTime : 2019-12-27 18:05:50
*/
import './index.scss';
import React, { useState, useRef, useEffect } from 'react';
import { Tabs, Button, Icon } from 'antd';
import { Tabs, Button, Icon, notification } from 'antd';
import { connect } from 'react-redux';
import InitTabCtx from '../initTabCtx';
import ExecResult from '../execResult';
@ -18,6 +18,8 @@ const { TabPane } = Tabs;
const ControlSetting = (props) => {
const {
hack,
userCode,
inputValue,
loading,
submitLoading,
@ -57,6 +59,13 @@ const ControlSetting = (props) => {
// 调试代码
const handleTestCode = (e) => {
if (!userCode) {
notification.warning({
message: '提示',
description: '代码块内容不能为空'
});
return;
}
// console.log(formRef.current.handleTestCodeFormSubmit);
// 调出控制台界面
setShowTextResult(true);
@ -69,6 +78,13 @@ const ControlSetting = (props) => {
// 提交
const handleSubmit = (e) => {
e.preventDefault();
if (!userCode) {
notification.warning({
message: '提示',
description: '代码块内容不能为空'
});
return;
}
changeSubmitLoadingStatus(true);
onSubmitForm && onSubmitForm();
}
@ -137,8 +153,10 @@ const ControlSetting = (props) => {
const mapStateToProps = (state) => {
const {commonReducer, ojForUserReducer} = state;
const {loading, excuteState, submitLoading, showOrHideControl } = commonReducer;
const { commitTestRecordDetail } = 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';

@ -3,8 +3,8 @@
* @Author: tangjiang
* @Github:
* @Date: 2019-11-27 19:46:14
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-19 10:47:05
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-26 20:07:35
*/
import './index.scss';
import React, { useState, useEffect, useRef, useImperativeHandle, forwardRef } from 'react';
@ -26,7 +26,7 @@ function InitTabCtx (props, ref) {
const { inputValue, onDebuggerCode } = props;
console.log('default value', inputValue);
// console.log('default value', inputValue);
useImperativeHandle(ref, () => ({
handleTestCodeFormSubmit: (cb) => {
// console.log('父组件调用我啦~~~~~~~~~');
@ -34,9 +34,9 @@ function InitTabCtx (props, ref) {
}
}));
useEffect(() => {
console.log('初始值: ========', props);
}, [props]);
// useEffect(() => {
// console.log('初始值: ========', props);
// }, [props]);
// 渲染文本提示信息
const renderText = () => (<span className={'ctx_default'}>请在这里添加测试用例点击调试代码时将从这里读取输入来测试你的代码...</span>);

@ -3,8 +3,8 @@
* @Author: tangjiang
* @Github:
* @Date: 2019-11-25 17:50:33
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-19 19:32:08
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-27 10:36:54
*/
import React, { useState } from 'react';
import { fromStore, toStore } from 'educoder';
@ -68,7 +68,7 @@ const SettingDrawer = (props) => {
);
} else if (Array.isArray(value)) {
const defaultValue = ctx.type === 'font' ? fontSize : theme;
console.log('++', defaultValue);
// console.log('++', defaultValue);
if (type === 'select') {
const child = ctx.value.map((opt, i) => {
return (

@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-11-27 15:02:52
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-26 15:19:34
* @LastEditTime : 2019-12-27 20:49:46
*/
import './index.scss';
import React, { useState, useRef, useEffect } from 'react';
@ -23,12 +23,13 @@ const maps = {
'c': 'main.c',
'c++': 'main.cc',
'java': 'main.java',
'pythone': 'main.py'
'python': 'main.py'
};
function MyMonacoEditor (props, ref) {
const {
const {
code,
notice,
language,
identifier,
@ -41,7 +42,7 @@ function MyMonacoEditor (props, ref) {
} = props;
const [showDrawer, setShowDrawer] = useState(false); // 控制配置滑框
const [editCode, setEditCode] = useState('');
// const [editCode, setEditCode] = useState('');
// const [curLang, setCurLang] = useState('C');
const [fontSize, setFontSize] = useState(() => { // 字体
return +fromStore('oj_fontSize') || 14;
@ -52,11 +53,9 @@ function MyMonacoEditor (props, ref) {
const [ height, setHeight ] = useState('calc(100% - 56px)');
const editorRef = useRef(null);
useEffect(() => {
if (props.code) {
setEditCode(props.code);
}
}, [props]);
// useEffect(() => {
// setEditCode(props.code || '');
// }, [props]);
useEffect(() => {
setHeight(showOrHideControl ? 'calc(100% - 378px)' : 'calc(100% - 56px)');
@ -82,11 +81,12 @@ function MyMonacoEditor (props, ref) {
// 文本框内容变化时,记录文本框内容
const handleEditorChange = (origin, monaco) => {
editorRef.current = monaco; // 获取当前monaco实例
setEditCode(origin); // 保存编辑器初始值
// setEditCode(origin); // 保存编辑器初始值
editorRef.current.onDidChangeModelContent(e => { // 监听编辑器内容的变化
// TODO 需要优化 节流
const val = editorRef.current.getValue();
setEditCode(val);
// setEditCode(val);
// console.log('编辑器代码====>>>>', val);
onCodeChange(val);
// 值一变化保存当前代码值
// saveUserInputCode(val);
@ -125,9 +125,9 @@ function MyMonacoEditor (props, ref) {
}
}
const renderRestore = identifier ? (
<MyIcon type="iconzaicizairu" />
) : '';
// const renderRestore = identifier ? (
// <MyIcon type="iconzaicizairu" />
// ) : '';
// lex_has_save ${hadCodeUpdate} ? : ''
const _classnames = hadCodeUpdate ? `flex_strict flex_has_save` : 'flex_strict';
@ -181,7 +181,7 @@ function MyMonacoEditor (props, ref) {
height={height}
width="100%"
language={language && language.toLowerCase()}
value={editCode}
value={code || ''}
options={editorOptions}
theme={theme} // dark || light
editorDidMount={handleEditorChange}
@ -212,12 +212,12 @@ const mapStateToProps = (state) => {
}
};
const mapDispatchToProps = (dispatch) => ({
// saveUserInputCode: (code) => dispatch(actions.saveUserInputCode(code)),
});
// const mapDispatchToProps = (dispatch) => ({
// // saveUserInputCode: (code) => dispatch(actions.saveUserInputCode(code)),
// });
// MyMonacoEditor = React.forwardRef(MyMonacoEditor);
export default connect(
mapStateToProps,
mapDispatchToProps
// mapDispatchToProps
)(CNotificationHOC() (MyMonacoEditor));

@ -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>
);
}

@ -34,6 +34,7 @@ const NewOrEditTask = (props) => {
startProgramQuestion,
getUserInfoForNew,
handleCancelPublish,
validateOjForm,
// updateTestAndValidate,
} = props;
@ -69,14 +70,20 @@ const NewOrEditTask = (props) => {
// 模拟挑战
const imitationChallenge = () => {
// 调用 start 接口, 成功后跳转到模拟页面
identifier && startProgramQuestion(identifier, props);
// 先调用保存, 再调用 start 接口, 成功后跳转到模拟页面
// identifier && startProgramQuestion(identifier, props);
identifier && validateOjForm(props, 'challenge', () => {
startProgramQuestion(identifier, props);
});
}
// 开始挑战
const startChallenge = () => {
// 调用 start 接口, 成功后跳转到开启实战
// TODO
identifier && startProgramQuestion(identifier, props);
identifier && validateOjForm(props, 'challenge', () => {
startProgramQuestion(identifier, props);
});
// identifier && startProgramQuestion(identifier, props);
}
// 取消
@ -265,7 +272,8 @@ const mapDispatchToProps = (dispatch) => ({
// 开启模拟挑战
startProgramQuestion: (id, props) => dispatch(actions.startProgramQuestion(id, props)),
// 新建时获取信息
getUserInfoForNew: () => dispatch(actions.getUserInfoForNew())
getUserInfoForNew: () => dispatch(actions.getUserInfoForNew()),
validateOjForm: (props, type, cb) => dispatch(actions.validateOjForm(props, type, cb))
});
export default withRouter(connect(

@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-11-21 09:19:38
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-26 15:33:01
* @LastEditTime : 2019-12-27 10:37:41
*/
import './index.scss';
import React from 'react';
@ -134,10 +134,10 @@ const AddTestDemo = (props) => {
// };
// const {input = {}, output = {}} = (testCasesValidate[index] = {});
const activePane = {
defaultActiveKey: [isOpen ? '1' : '']
};
console.log(activePane);
// const activePane = {
// defaultActiveKey: [isOpen ? '1' : '']
// };
// console.log(activePane);
// 切换手风琴
const handleChangeCollapse = () => {
@ -184,7 +184,7 @@ const AddTestDemo = (props) => {
const mapStateToProps = (state) => {
const {identifier, loading} = state.ojFormReducer;
console.log(state.ojFormReducer);
// console.log(state.ojFormReducer);
return {
identifier,
loading,

@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-11-20 10:35:40
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-26 16:00:57
* @LastEditTime : 2019-12-27 14:30:55
*/
import './index.scss';
// import 'katex/dist/katex.css';
@ -175,11 +175,11 @@ class EditTab extends React.Component {
};
// 提交测试用例
const handleSubmitTest = (obj) => {
console.log('提交的测试用例: ', obj);
// console.log('提交的测试用例: ', obj);
};
// 删除测试用例
const handleDeleteTest = (obj) => {
console.log('删除的测试用例: ', obj);
// console.log('删除的测试用例: ', obj);
deleteTestCase(obj);
};
const renderTestCase = () => {
@ -223,10 +223,10 @@ class EditTab extends React.Component {
// 描述信息变化时
const handleContentChange = (content, quill) => {
console.log('描述信息为: ', content);
// if (quill.getText())
console.log('========>>>>>', quill.getText().length);
if (quill.getText().length === 1) {
// console.log('描述信息为: ', content);
const _text = quill.getText();
const reg = /^[\s\S]*.*[^\s][\s\S]*$/;
if (!reg.test(_text)) {
this.handleChangeDescription('');
} else {
// 保存获取的描述信息至redux中

@ -4,10 +4,10 @@
* @Github:
* @Date: 2019-12-01 10:18:35
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-26 13:51:40
* @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';
@ -17,7 +17,9 @@ function RightPane (props, ref) {
const {
// identifier,
// code,
code,
showCode,
language,
// onSubmitForm,
saveOjFormCode
} = props;
@ -44,8 +46,8 @@ function RightPane (props, ref) {
return (
<div className={'right_pane_code_wrap'}>
<MyMonacoEditor
language={props.language}
code={props.code}
language={language}
code={showCode}
onCodeChange={handleCodeChange}/>
{/* <ControlSetting
@ -59,13 +61,13 @@ 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) || '',
}
};
const mapDispatchToProps = (dispatch) => ({

@ -75,11 +75,11 @@ class InitTabCtx extends PureComponent {
handleTestCodeFormSubmit = (cb) => {
const {form, debuggerCode} = this.props;
console.log(debuggerCode);
// console.log(debuggerCode);
form.validateFields((err, values) => {
if (!err) { // 表单验证通过时,调用测试接口
cb && cb(); // 调用回调函数,切换 tab
console.log('表单值:', values);
// console.log('表单值:', values);
debuggerCode(values);
}
});

@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-12-04 08:36:21
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-26 14:04:16
* @LastEditTime : 2019-12-27 21:18:39
*/
import './index.scss';
import React, { useState, useEffect } from 'react';
@ -43,7 +43,7 @@ function RecordDetail (props) {
useEffect(() => {
setDetail(recordDetail);
console.log('详情: ', recordDetail);
// console.log('详情: ', recordDetail);
if (recordDetail) {
const { user, myproblem_identifier, code } = recordDetail;
setUser(user);
@ -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">
@ -99,6 +107,11 @@ function RecordDetail (props) {
<span className="status_label" style={{ visibility: detail.status === 0 ? 'visible' : 'hidden'}}>
执行用时: <span className="status_label_sub">{`${detail.execute_time && Number(detail.execute_time * 1000).toFixed(2)}ms`}</span>
</span>
<span className="status_label pass_case" style={{ display: [-1, 0, 2, 5].includes(detail.status) ? 'inline-block' : 'none'}}>
<span className="status_label_sub">{detail.pass_sets_count}</span>
<span className="pass_case_span"> / {detail.set_count}</span>
个通过测试用例
</span>
</div>
<div className="result_error_area">
<ErrorResult detail={detail}/>
@ -109,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">

@ -1,6 +1,7 @@
@import '../split_pane_resizer.scss';
.record_detail_area{
background: #fff;
.record_detail_ctx{
padding: 0 20px;
.detail_ctx_header{
@ -31,6 +32,13 @@
.status_label_sub{
color: #333333;
}
.pass_case{
float: right;
margin-right: 0;
}
.pass_case_span{
margin-right: 10px;
}
}
.result_code_area{
@ -39,6 +47,9 @@
}
.result_error_area{
margin-top: 15px;
background: rgba(250,250,250,1);
color: #E51C24;
border-radius: 3px;
}
}
}

@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-11-23 10:53:19
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-26 15:02:12
* @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(() => {
@ -90,9 +95,9 @@ function StudentStudy (props) {
const handleClickEditor = (identifier) => {
if (!identifier) return;
changeShowOrHideControl(false);
props.saveEditorCodeForDetail();
props.history.push(`/problems/${identifier}/edit`);
props.saveEditorCodeForDetail('');
props.clearOjForUserReducer();
props.history.push(`/problems/${identifier}/edit`);
}
// 处理退出
const handleClickQuit = () => {
@ -100,7 +105,7 @@ function StudentStudy (props) {
props.clearOjForUserReducer();
// 将控制台关闭
changeShowOrHideControl(false);
props.saveEditorCodeForDetail();
props.saveEditorCodeForDetail('');
props.history.push('/problems');
}
@ -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(

@ -1,6 +1,52 @@
@import '../split_pane_resizer.scss';
.split-pane-area{
height: calc(100vh - 65px);
.right_pane_code_wrap{
position: relative;
.editor_nodte_area,
.student_notes{
position: absolute;
z-index: 100;
}
.student_notes{
right: 0px;
top: 50%;
width: 36px;
height: 36px;
margin-top: -18px;
border-radius: 50%;
background: #5091FF;
color: #fff;
font-size: 18px;
text-align: center;
transform: translateX(18px);
cursor: pointer;
opacity: 0.5;
transition: all .3s;
&:hover{
opacity: 1;
transform: translateX(-10px);
}
}
.editor_nodte_area{
right: 10px;
top: 50%;
width: 450px;
height: 200px;
margin-top: -100px;
background: #fff;
border-radius: 5px;
padding: 14px 10px 0;
// opacity: ;
transform: translateX(500px);
transition: all .3s;
&.active{
transform: translateX(0px);
}
}
}
}
.right_pane_code_wrap{

@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-11-27 09:49:33
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-25 14:45:20
* @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,
@ -105,7 +105,7 @@ const CommitRecord = (props) => {
// expected_output
} = commitRecordDetail;
if (Object.keys(commitRecordDetail).length > 0) {
console.log('当前状态====》》》', status);
// console.log('当前状态====》》》', status);
const classes = status === 0 ? 'record_result_suc' : 'record_result_err';
const showErrorCode = status !== 0 ? `ecord_error_info show_error_code` : `ecord_error_info`;
const showErrorCopy = status !== 0 ? `copy_error show_error_copy` : `copy_error`;
@ -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
}
}

@ -3,15 +3,20 @@
* @Author: tangjiang
* @Github:
* @Date: 2019-11-27 14:59:51
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-20 14:01:57
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-27 19:23:46
*/
import React, { useState, useEffect } from 'react';
import {connect} from 'react-redux';
import MyMonacoEditor from '../../components/myMonacoEditor';
import ControlSetting from '../../components/controlSetting';
import actions from '../../../../redux/actions';
// import QuillForEditor from '../../../../common/quillForEditor';
// import TextArea from 'antd/lib/input/TextArea';
import { Input, Form, Button } from 'antd';
// import FormItem from 'antd/lib/form/FormItem';
const { TextArea } = Input;
const FormItem = Form.Item;
const RightPane = (props) => {
const {
@ -20,6 +25,7 @@ const RightPane = (props) => {
submitUserCode,
input,
hack,
loading,
notice,
updateCode,
hadCodeUpdate,
@ -27,20 +33,26 @@ const RightPane = (props) => {
updateNotice,
saveUserInputCode,
restoreInitialCode,
saveOpacityType,
saveUserCodeForInterval
// saveOpacityType,
saveUserCodeForInterval,
addNotes,
changeLoadingState
} = props;
const [editorCode, setEditorCode] = useState('');
const [editorCode, setEditorCode] = useState(editor_code || hack.code);
const [noteClazz, setNoteClazz] = useState('editor_nodte_area');
const [noteCount] = useState(5000);
// 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]);
let initFlag = true;
useEffect(() => {
if (editor_code) {
setEditorCode(editor_code);
} else {
setEditorCode(hack.code);
}
}, [hack, editor_code]);
const handleSubmitForm = () => {
// 提交时, 先调用提交接口,提交成功后,循环调用测评接口
@ -52,24 +64,18 @@ const RightPane = (props) => {
let timer = null; // 定时器
// 代码块内容变化时
const handleCodeChange = (code) => {
// 保存用户提交的代码块
setEditorCode(code);
// 第一次回填代码内容时不更新;
if (initFlag) {
initFlag = false;
return;
}
const handleCodeChange = (value) => {
saveUserInputCode(value);
setEditorCode(value);
if (!timer) {
timer = setInterval(() => {
timer = setInterval(function () {
clearInterval(timer);
timer = null;
saveUserCodeForInterval && saveUserCodeForInterval(identifier, code);
saveUserCodeForInterval(identifier);
}, 3000);
}
// 保存用户代码块
saveUserInputCode(code);
}
// 代码调试
const handleDebuggerCode = (value) => {
// 调用保存代码块接口,成功后,调用调试接口
@ -86,18 +92,74 @@ const RightPane = (props) => {
updateNotice && updateNotice();
};
const handleClickNote = () => {
setNoteClazz('editor_nodte_area active');
}
const handleCancelNote = () => {
props.form.resetFields();
setNoteClazz('editor_nodte_area');
}
const handleSubmitNote = () => {
props.form.validateFields((err, values) => {
if (!err) {
changeLoadingState(true);
addNotes(identifier, values, function () {
setNoteClazz('editor_nodte_area');
props.form.resetFields();
});
}
});
}
const { getFieldDecorator } = props.form;
return (
<div className={'right_pane_code_wrap'}>
<MyMonacoEditor
notice={notice}
identifier={identifier}
language={hack.language}
code={editorCode}
code={editor_code || hack.code}
hadCodeUpdate={hadCodeUpdate}
onCodeChange={handleCodeChange}
onUpdateNotice={handleUpdateNotice}
onRestoreInitialCode={handleRestoreInitialCode}
/>
<span
className="iconfont icon-biji student_notes"
onClick={handleClickNote}
></span>
{/* <div className="student_notes">
<TextArea rows={5} />
</div> */}
<div className={noteClazz}>
<Form>
<FormItem>
{
getFieldDecorator('notes',{
rules: [
{ required: true, message: '笔记不能为空' },
{ max: noteCount, message: `笔记最大字数为${noteCount}` }
],
initialValue: (hack && hack.notes) || ''
})(<TextArea
max={noteCount}
placeholder="请输入笔记内容"
rows="5"
/>)
}
</FormItem>
<FormItem style={{ textAlign: 'right' }}>
<Button loading={loading} style={{ marginRight: '10px' }} onClick={handleCancelNote}>取消</Button>
<Button type="primary" onClick={handleSubmitNote}>提交</Button>
</FormItem>
</Form>
</div>
<ControlSetting
identifier={identifier}
inputValue={input}
@ -117,10 +179,14 @@ const mapStateToProps = (state) => {
notice,
hadCodeUpdate
} = state.ojForUserReducer;
const {
loading
} = state.commonReducer;
// const { language, code } = hack;
return {
hack,
notice,
loading,
hadCodeUpdate,
editor_code,
input: userTestInput,
@ -141,9 +207,12 @@ const mapDispatchToProps = (dispatch) => ({
// 恢复初始代码
restoreInitialCode: (identifier, msg) => dispatch(actions.restoreInitialCode(identifier, msg)),
// saveOpacityType: (type) => dispatch(actions.saveOpacityType(type))
// 添加笔记
addNotes: (identifier, params, cb) => dispatch(actions.addNotes(identifier, params, cb)),
changeLoadingState: (flag) => dispatch(actions.changeLoadingState(flag))
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(RightPane);
)(Form.create()(RightPane));

@ -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
}

@ -130,16 +130,19 @@ class TPMBanner extends Component {
if(this.props.status===0&&this.props.openknows===false){
if(this.props.shixunsDetails&&this.props.shixunsDetails.shixun_status === 0 && this.props.identity < 5){
if(shixunopenprocess===undefined||shixunopenprocess===false||shixunopenprocess===null){
this.setState({
openknow:true
})
}else{
this.setState({
openknow:false
})
if(this.props.user&&this.props.user.user_id){
if(shixunopenprocess===undefined||shixunopenprocess===false||shixunopenprocess===null){
this.setState({
openknow:true
})
}else{
this.setState({
openknow:false
})
}
}
}
}
}else{
this.setState({
openknow:false
@ -150,14 +153,16 @@ class TPMBanner extends Component {
if(this.props.public===0&&this.props.status>1&&this.props.openknows===false){
if(this.props.shixunsDetails&&this.props.shixunsDetails.shixun_status === 2 && this.props.shixunsDetails&&this.props.shixunsDetails.public===0 && this.props.identity < 5){
if(openopenpublictype===undefined||openopenpublictype===false||openopenpublictype===null){
this.setState({
openshowpublictype:true
})
}else{
this.setState({
openshowpublictype:false
})
if(this.props.user&&this.props.user.user_id) {
if (openopenpublictype === undefined || openopenpublictype === false || openopenpublictype === null) {
this.setState({
openshowpublictype: true
})
} else {
this.setState({
openshowpublictype: false
})
}
}
}
}else{

@ -1,6 +1,6 @@
import React, {Component} from 'react';
import {Redirect} from 'react-router';
import {List, Typography, Tag, Modal, Radio, Checkbox, Table, Pagination,Upload,Button} from 'antd';
import {List, Typography, Tag, Modal, Radio, Checkbox, Table,message, Pagination,Upload,Button} from 'antd';
import { NoneData } from 'educoder'
import TPMRightSection from './component/TPMRightSection';
@ -12,7 +12,29 @@ import moment from 'moment';
import Tpmdatasetmodel from "./tpmmodel/Tpmdatasetmodel";
const confirm = Modal.confirm;
function clearSlct() {
if("getSelection" in window){
window.getSelection().removeAllRanges();
}else{
document.selection.empty();
};
}
function jsCopy(s) {
clearSlct();
const copyEle = document.getElementById(s);
copyEle.select();
const copyStatus=document.execCommand("Copy");
// 对成功与否定进行提示
copyStatuss(copyStatus)
}
function copyStatuss(copyStatus){
if (copyStatus) {
message.success('复制成功');
} else {
message.error('复制失败');
}
}
class TPMDataset extends Component {
constructor(props) {
super(props)
@ -69,6 +91,33 @@ class TPMDataset extends Component {
</div>
)
},
{
title: '操作',
dataIndex: 'operation',
key: 'operation',
align: 'center',
className: "edu-txt-center font-14 ",
render: (text, record) => (
<div style={{
cursor:"pointer",
}} onClick={() => {
jsCopy("file_path"+record.id)
}}>
<i className="iconfont icon-fuzhi3 font-18 ml2 questiontype" style={{
color:"#A0A7B4"
}} ></i>
<div
style={{
overflow: 'hidden',
height: "1px",
width: "1px"
}}
>
<input id={"file_path"+record.id} value={record.file_path}/>
</div>
</div>
)
},
],
page: 1,
limit: 10,
@ -148,6 +197,7 @@ class TPMDataset extends Component {
filesize:datas[i].filesize,
id:datas[i].id,
title:datas[i].title,
file_path:datas[i].file_path,
})
}
this.setState({
@ -203,6 +253,7 @@ class TPMDataset extends Component {
filesize:datas[i].filesize,
id:datas[i].id,
title:datas[i].title,
file_path:datas[i].file_path,
})
}
this.setState({

@ -87,6 +87,11 @@ const TPMchallengesnew = Loadable({
loader: () => import('./challengesnew/TPMchallengesnew'),
loading: Loading,
})
//新建实训
// const TPMchallengesnew = Loadable({
// loader: () => import('./challengesnew/TpmTask/TpmTaskIndex'),
// loading: Loading,
// })
//新建tab2
const TPMevaluation = Loadable({
@ -384,7 +389,6 @@ class TPMIndex extends Component {
let url = window.location.href;
let flag = url.indexOf("add_file")>-1;
console.log(this.state.openknows)
return (
<div className="newMain clearfix">
{/*头部*/}

@ -35,14 +35,14 @@ if (!window['indexHOCLoaded']) {
// $('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" />')
.attr('href', `${_url_origin}/stylesheets/css/edu-common.css?8`));
.attr('href', `${_url_origin}/stylesheets/css/edu-common.css?2020`));
$('head').append($('<link rel="stylesheet" type="text/css" />')
.attr('href', `${_url_origin}/stylesheets/educoder/edu-main.css?8`));
.attr('href', `${_url_origin}/stylesheets/educoder/edu-main.css?2020`));
// index.html有加载
$('head').append($('<link rel="stylesheet" type="text/css" />')
.attr('href', `${_url_origin}/stylesheets/educoder/edu-all.css?8`));
.attr('href', `${_url_origin}/stylesheets/educoder/edu-all.css?2020`));
// $('head').append($('<link rel="stylesheet" type="text/css" />')
@ -635,6 +635,18 @@ export function TPMIndexHOC(WrappedComponent) {
}
}
//跳转道描点的地方
scrollToAnchor = (anchorName) => {
if (anchorName) {
// 找到锚点
let anchorElement = document.getElementById(anchorName);
// 如果对应id的锚点存在就跳转到锚点
if (anchorElement) {
anchorElement.scrollIntoView();
}
}
}
render() {
let{Headertop,Footerdown, isRender, AccountProfiletype,AccountPhoneemailtype}=this.state;
const common = {
@ -670,7 +682,8 @@ export function TPMIndexHOC(WrappedComponent) {
hideGlobalLoading: this.hideGlobalLoading,
yslslowCheckresults:this.yslslowCheckresults,
yslslowCheckresultsNo:this.yslslowCheckresultsNo,
MdifHasAnchorJustScorll:this.MdifHasAnchorJustScorll
MdifHasAnchorJustScorll:this.MdifHasAnchorJustScorll,
scrollToAnchor:this.scrollToAnchor
};
// console.log("this.props.mygetHelmetapi");

@ -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
}
})

@ -1,48 +1,21 @@
import React, {Component} from 'react';
import {Input, InputNumber, Select, Radio, Checkbox, Popconfirm, message, Modal, Tooltip} from 'antd';
import {Input, InputNumber, Button, Tooltip} from 'antd';
import {BrowserRouter as Router, Route, Link, Switch} from "react-router-dom";
// import "antd/dist/antd.css";
import { getImageUrl, toPath, getUrl } from 'educoder';
import axios from 'axios';
import './css/TPMchallengesnew.css';
import TPMMDEditor from './TPMMDEditor';
import Bottomsubmit from "../../modals/Bottomsubmit";
let origin = getUrl();
let path = getUrl("/editormd/lib/")
import './css/TPMchallengesnew.css';
const $ = window.$;
let timeout;
let currentValue;
const Option = Select.Option;
const RadioGroup = Radio.Group;
// const testAnswers = [{
// "id": 4337,
// "name": "解题思路1",
// "contents": "答案的解题思路1",
// "level": 1,
// "score": 25
// },
// {
// "id": 4338,
// "name": "解题思路2",
// "contents": "答案的解题思路2",
// "level": 2,
// "score": 25
// }]
export default class TPManswer extends Component {
constructor(props) {
super(props)
@ -94,7 +67,7 @@ export default class TPManswer extends Component {
}
}
this.setState({
answer:response.data.answer,
answer:response.data.answer,
power: response.data.power,
choice_url: newchoice_url, // 导航中的新建选择题url
practice_url: newpractice_url, //string 导航中新建实践题url
@ -102,10 +75,11 @@ export default class TPManswer extends Component {
position: response.data.position, //int 关卡位置,导航栏中的第几关
prev_challenge: newprev_challenge,
next_challenge: next_challenge,
responsedata:response.data,
})
if(response.data.power===false){
this.props.showSnackbar("没有权限修改");
this.props.showNotification("没有权限修改");
}
// if(response.data.answer===undefined||response.data.answer===null){
// this.answerMD("", "answerMD");
@ -133,7 +107,7 @@ export default class TPManswer extends Component {
// this.refs.md0
const { answers } = this.state;
const answersParams = answers.slice(0)
console.log(answersParams)
// console.log(answersParams)
let isValidate = true;
let totalScore = 0;
answersParams.forEach( (item, index) => {
@ -147,10 +121,10 @@ export default class TPManswer extends Component {
totalScore += item.score;
delete item.id;
if (!item.name) {
this.props.showSnackbar("请先填写参考答案名称");
this.props.showNotification("请先填写参考答案名称");
isValidate = false;
} else if (!mdContnet) {
this.props.showSnackbar("请先填写参考答案内容");
this.props.showNotification("请先填写参考答案内容");
isValidate = false;
}
if (!isValidate) {
@ -161,7 +135,7 @@ export default class TPManswer extends Component {
return;
}
if (answersParams.length != 0 && totalScore != 100) {
this.props.showSnackbar("请先保证占比和为100%");
this.props.showNotification("请先保证占比和为100%");
return;
}
let id = this.props.match.params.shixunId;
@ -174,7 +148,7 @@ export default class TPManswer extends Component {
).then((response) => {
if (response.data) {
if (response.data.message) {
this.props.showSnackbar(response.data.message);
this.props.showNotification(response.data.message);
}
if (response.data.status == 1) {
window.location.href=`/shixuns/${id}/challenges`;
@ -233,12 +207,16 @@ export default class TPManswer extends Component {
}
})
}
gotocheckpoint=(url)=>{
this.props.history.replace(url);
}
render() {
let {
choice_url,
practice_url,
go_back_url,
responsedata,
position,
task_pass_default,
submit_url,
@ -256,60 +234,51 @@ export default class TPManswer extends Component {
return (
<React.Fragment>
<div className="educontent mt30 mb30 tpmAnswer">
<div className="padding10-20 mb10 edu-back-white clearfix">
<span className="fl ring-blue mr10 mt7">
<img src={getImageUrl("images/educoder/icon/code.svg")} data-tip-down="实训任务" className="fl mt2 ml2"/>
</span>
<span className="font-16 task-hide fl TPMtaskName">{position}</span>
<Link to={go_back_url === undefined ? "" : go_back_url}
className="color-grey-6 fr font-15 mt3">返回</Link>
{prev_challenge === undefined ? "" :
<a href={prev_challenge} className="fr color-blue mr15 mt4">上一关</a>
}
{next_challenge === undefined ? "" :
<a href={next_challenge} className="fr color-blue mr15 mt4">下一关</a>
}
<a href={practice_url === undefined ? "" : practice_url}
className="fr color-blue mr15 mt4"
style={{display:this.props.status===2||this.props.status===1?'none':'block'}}
data-tip-down="新增代码编辑类型的任务">+&nbsp;实践类型</a>
<a href={choice_url === undefined ? "" : choice_url}
className="fr color-blue mr15 mt4"
style={{display:this.props.status===2||this.props.status===1?'none':'block'}}
data-tip-down="新增选择题类型的任务">+&nbsp;选择题类型</a>
<div className="TPMchallengesnewtitles edu-back-white clearfix borderbottomf4">
<span className="font-16 task-hide fl TPMtaskName">{position}{responsedata&&responsedata.st === 0 ?"实践题":responsedata&&responsedata.st === 1?"选择题":""}</span>
{this.props.identity>4||this.props.identity===undefined||this.props.status===2||this.props.status===1?"":<a href={practice_url === undefined ? "" : practice_url} className="fr ml15 mt13">
<Button type="primary" className="edu-default-btn edu-greenback-btn "
>新增实践任务</Button></a>}
{this.props.identity>4||this.props.identity===undefined||this.props.status===2||this.props.status===1?"":<Link to={choice_url === undefined ? "" : choice_url}
className="fr ml15 mt13">
<Button type="primary"
className="edu-default-btn edu-greenback-btn mr5"
>新增选择题任务</Button></Link>}
{next_challenge===undefined?"":
<Button type="primary" ghost onClick={()=>this.gotocheckpoint(next_challenge)}
className="edu-default-btn edu-greenback-btn mr5 fr ml15 mt13"
>下一关</Button> }
{prev_challenge===undefined?"":
<Button type="primary" ghost onClick={()=>this.gotocheckpoint(prev_challenge)}
className="edu-default-btn edu-greenback-btn mr5 fr ml15 mt13"
>上一关</Button>}
</div>
<div className="challenge_nav clearfix edu-back-white">
<li>
<Link to={tab1url}>本关任务</Link>
<Link to={tab1url}>1本关任务 </Link>
</li>
{tab2url === "" ? "":<li> > </li>}
<li >
<Link to={tab2url}>评测设置</Link>
<Link to={tab2url} >2评测设置</Link>
</li>
{tab3url === "" ? "":<li> > </li>}
<li className="active">
<Link to={tab3url}>参考答案</Link>
<Link to={tab3url} className={"color-blue"}> 3参考答案</Link>
</li>
</div>
<div className="edu-back-white mb10 clearfix">
<div className="padding30-20">
<p className=" font-12" style={{ paddingBottom: '5px'
, color: '#666666'}}>
可以将参考答案分级设置让学员自行选择级别每级查看后按照比例扣分值学员已完成任务再查看则不影响原因已获得的成绩
<p className=" font-14" style={{ paddingBottom: '5px'
, color: '#333'}}>
可以将参考答案分级设置让学员自行选择级别每级查看后按照比例扣分值学员已完成任务再查看则不影响学员已获得的成绩
</p>
<p className=" font-12 "
style={{ maxWidth: "782px"
, color: '#999999'}}>
示例级别1扣减分值占比25%级别2扣减分值占比35%级别3扣减分值占比40%则学员选择查看级别1的答案将被扣减25%的分值
选择查看级别2的答案将被扣减60%的分值选择查看级别3的答案将被扣减100%的分值
<p className=" font-14 mt15 "
style={{ color: '#888'}}>
<div>示例级别1扣减分值占比25%级别2扣减分值占比35%级别3扣减分值占比40%</div>
<div className={"mt5 ml41"}>若学员选择查看级别1的答案将被扣减25%的分值选择查看级别2的答案将被扣减60%的分值选择查看级别3的答案将被扣减100%的分值</div>
</p>
<style>{`
@ -320,25 +289,31 @@ export default class TPManswer extends Component {
{
answers.map((answer, index) => {
return <div className="levelSection" id={`levelSection${index}`} style={{ clear: 'both' }}>
return <div className="levelSection mt30" id={`levelSection${index}`} style={{ clear: 'both' }}>
<span className="mr4 color-orange pt10">*</span>
<p className="color-grey-6 font-16 mb30 mt10" style={{ display: "inline" }}>级别{index + 1}</p>
<p className="color-grey-6 font-16 mb30 mt10" style={{ display: "inline" }}>级别{index + 1}</p>
<Tooltip title="删除">
<a className="fr sample_icon_remove mr30 mt8" onClick={()=>this.delanswers(index)}>
<i className="fa fa-times-circle color-grey-c font-16 fl" ></i>
<a className="fr sample_icon_remove mr10 mt8" onClick={()=>this.delanswers(index)}>
<i className={"iconfont icon-shanchu_Hover font-16 fl"}></i>
</a>
</Tooltip>
<div className=" color-grey-6 font-16" style={{ marginLeft: "9px", margin: '8px 9px'}}>
<div className=" color-grey-6 font-16 bortopeeetpm pt20 mt20" style={{ marginLeft: "9px", margin: '8px 9px'}}>
<div className=" ">
<span>名称</span>
<Input value={answer.name} onChange={(e) => this.onNameChange(e, index)}></Input>
<span style={{ marginLeft: "20px"}} >扣减分值占比</span>
<InputNumber className="score" step={1} min={1} max={100} defaultValue={answer.score}
onChange={(e) => this.onScoreChange(e, index)} ></InputNumber>%
<div className={"wind500height45"}>
<div className={"fl"} style={{'width':'240px'}}>名称</div>
<div className={"fl"} style={{ marginLeft: "20px"}} >扣减分值占比</div>
</div>
<div className={"wind500height45"}>
<Input value={answer.name} onChange={(e) => this.onNameChange(e, index)}></Input>
<InputNumber className="score" step={1} min={1} max={100} defaultValue={answer.score}
style={{ marginLeft: "32px"}}
onChange={(e) => this.onScoreChange(e, index)} ></InputNumber> %
</div>
</div>
<div className="mt10">
<span>参考答案</span>
<span>内容</span>
<TPMMDEditor ref={`md${index}`} mdID={index} initValue={answer.contents}
onChange={(val) => this.answerOnChange(val, index)}></TPMMDEditor>
</div>
@ -348,19 +323,28 @@ export default class TPManswer extends Component {
}
<div className="clearfix mt20" style={{display:this.props.identity>4||this.props.identity===undefined||power===false?"none":"block"}}>
<a href={"javascript:void(0)"} className="defalutCancelbtn fl" onClick={this.addAnswer}>新增</a>
{/*<a href={"javascript:void(0)"} className="defalutCancelbtn fl" >新增参考答案</a>*/}
<Button type="primary" ghost className="edu-default-btn edu-greenback-btn mt20 mb20 newaddswermargin" onClick={this.addAnswer}>新增参考答案</Button>
</div>
</div>
</div>
<div className="clearfix mt20" style={{display:this.props.identity>4||this.props.identity===undefined||power===false?"none":"block"}}>
<a className="defalutSubmitbtn fl mr20"
onClick={this.challenge_answer_submit}>提交</a>
<a href={"/shixuns/" + shixunId + "/challenges"} className="defalutCancelbtn fl">取消</a>
</div>
</div>
{this.props.identity>4||this.props.identity===undefined||power===false?"":<div className="clearfix mt20" >
{/*<a className="defalutSubmitbtn fl mr20" onClick={this.challenge_answer_submit}>提交</a>*/}
{/*/!*<a href={"/shixuns/" + shixunId + "/challenges"} className="defalutCancelbtn fl">取消</a>*!/*/}
{/*<Link to={"/shixuns/" + shixunId + "/challenges"} className={"defalutCancelbtn fl"}>取消</Link>*/}
<Bottomsubmit url={"/shixuns/" + shixunId + "/challenges"}
bottomvalue={"提交"}
onSubmits={this.challenge_answer_submit}
{...this.props}
{...this.state}
loadings={false}
/>
</div>}
</React.Fragment>
)
}

@ -1,35 +1,30 @@
import React, {Component} from 'react';
import {Input, Select, Radio, Checkbox, Popconfirm, message, Modal} from 'antd';
import {Input, Select, Radio, Badge, message, Button} from 'antd';
import {BrowserRouter as Router, Route, Link, Switch} from "react-router-dom";
// import "antd/dist/antd.css";
import {Link} from "react-router-dom";
import TPMMDEditor from '../../tpm/challengesnew/TPMMDEditor';
import Bottomsubmit from "../../modals/Bottomsubmit";
import axios from 'axios';
import './css/TPMchallengesnew.css';
import { getImageUrl, toPath } from 'educoder';
import {getUrl} from 'educoder';
let origin = getUrl();
let path = getUrl("/editormd/lib/")
const $ = window.$;
let timeout;
let currentValue;
const Option = Select.Option;
const RadioGroup = Radio.Group;
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)
@ -40,12 +35,12 @@ export default class TPMchallengesnew extends Component {
go_back_url: undefined,
task_pass_default: undefined,
submit_url: undefined,
shixunCreatePracticeGroup: 1,
shixunCreatePracticeGroup: undefined,
optionsums:[100,200],
activetype:0,
setopen: false,
shixunCreatePractice: undefined,
onshixunsmarkvalue: 100,
onshixunsmarkvalue: undefined,
shixunsskillvalue: undefined,
shixunsskillvaluelist: [],
tab2url: "",
@ -59,12 +54,13 @@ export default class TPMchallengesnew extends Component {
editPracticesendtype:false,
CreatePracticesendtype:false,
exec_time:20,
shixunExec_timeType:false
shixunExec_timeType:false,
onshixunsmarkvaluetype:false,
shixunCreatePracticeGrouptype:false
}
}
componentDidMount() {
getdatas=()=>{
let id = this.props.match.params.shixunId;
let checkpointId=this.props.match.params.checkpointId;
@ -83,10 +79,11 @@ export default class TPMchallengesnew extends Component {
task_pass_default: response.data.task_pass_default,
submit_url: response.data.submit_url,
checkpointId:checkpointId,
exercisememoMDRefval:response.data.task_pass_default
exercisememoMDRefval:response.data.task_pass_default,
responsedata:response.data
})
this.exercisememoMDRef.current.setValue(response.data.task_pass_default||'')
this.exercisememoMDRef.current.setValue(response.data.task_pass_default||'')
}).catch((error) => {
console.log(error)
});
@ -133,16 +130,18 @@ export default class TPMchallengesnew extends Component {
onshixunsmarkvalue:response.data.score,
shixunsskillvaluelist:response.data.tags,
checkpointId:checkpointId,
exec_time:response.data.exec_time,
tab2url: "/shixuns/" + id + "/challenges/"+checkpointId+"/tab=2",
tab3url: "/shixuns/" + id + "/challenges/"+checkpointId+"/tab=3",
exercisememoMDRefval:response.data.task_pass
exercisememoMDRefval:response.data.task_pass,
responsedata:response.data
})
// exec_time:response.data.exec_time,
if(response.data.power===false){
this.props.showSnackbar("你没有权限修改");
this.props.showNotification("你没有权限修改");
}
this.exercisememoMDRef.current.setValue(response.data.task_pass||'')
this.exercisememoMDRef.current.setValue(response.data.task_pass||'')
}).catch((error) => {
console.log(error)
});
@ -150,8 +149,24 @@ export default class TPMchallengesnew extends Component {
}
}
componentDidUpdate=(prevProps, prevState)=>{
if(prevProps!=this.props){
this.getdatas()
}
}
componentDidMount() {
this.getdatas()
}
onshixunCreatePracticeChange = (e) => {
if(e.target.value===undefined||e.target.value=== ""||e.target.value=== null){
}else{
this.setState({
shixunCreatePracticeGrouptype:false,
onshixunsmarkvaluetype:false
})
}
let optionsum;
let onshixunsmark;
if(e.target.value===1){
@ -172,62 +187,134 @@ export default class TPMchallengesnew extends Component {
}
shixunCreatePractice = (e) => {
if (e.target.value === undefined|| e.target.value== ""){
}else{
this.setState({
shixunCreatePracticetype:false
})
}
this.setState({
shixunCreatePractice: e.target.value
})
}
CreatePracticesend = () => {
const exercise_editormdvalue = this.exercisememoMDRef.current.getValue().trim();
this.setState({
CreatePracticesendtype:true
})
if(this.props.status===2){
this.props.showSnackbar("该实训已经发布不能新建")
this.props.showNotification("该实训已经发布不能新建")
this.setState({
CreatePracticesendtype:false
})
return
}
let {shixunCreatePractice, shixunCreatePracticeGroup, onshixunsmarkvalue, shixunsskillvaluelist,exec_time} = this.state;
if (shixunCreatePractice === undefined||shixunCreatePractice=="") {
this.setState({
shixunCreatePracticetype: true
shixunCreatePracticetype: true,
CreatePracticesendtype:false
})
this.props.showSnackbar("任务名称为空")
$('html').animate({
$('html').animate({
scrollTop: 10
}, 1000);
this.setState({
CreatePracticesendtype:false
})
return
}
if (shixunCreatePractice.match(/^[ ]*$/)) {
this.props.showNotification("任务名称为空,请勿输入空格");
this.setState({
shixunCreatePracticetype: true,
CreatePracticesendtype:false
})
$('html').animate({
scrollTop: 10
}, 1000);
return
}
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,
CreatePracticesendtype:false
})
this.props.scrollToAnchor("shixunCreatePracticeGroupid");
return
}
if(onshixunsmarkvalue===undefined){
this.setState({
onshixunsmarkvaluetype:true,
CreatePracticesendtype:false
})
this.props.scrollToAnchor("input_task_tag");
return
}
if (shixunsskillvaluelist.length === 0) {
this.setState({
shixunsskillvaluelisttype: true,
CreatePracticesendtype:false
CreatePracticesendtype:false
})
this.props.showSnackbar("技能标签为空")
// this.props.showNotification("技能标签为空")
this.props.scrollToAnchor("input_task_tag");
return
}
if(exec_time===null||exec_time===undefined||exec_time===""){
this.setState({
shixunExec_timeType:false
})
return
}
const exercise_editormdvalue = this.exercisememoMDRef.current.getValue().trim();
let id = this.props.match.params.shixunId;
// if(exec_time===null||exec_time===undefined||exec_time === ""){
// this.setState({
// shixunExec_timeType:true,
// CreatePracticesendtype:false
// })
// this.props.scrollToAnchor("exec_time");
// return
// }
// if (exec_time.match(/^[ ]*$/)) {
// this.props.showNotification("评测时限,请勿输入空格");
// this.setState({
// shixunExec_timeType:true,
// CreatePracticesendtype:false
// })
// this.props.scrollToAnchor("exec_time");
// return
// }
let url = "/shixuns/" + id + "/challenges.json";
let id = this.props.match.params.shixunId;
let url = "/shixuns/" + id + "/challenges.json";
// exec_time:exec_time
axios.post(url, {
identifier:id,
subject: shixunCreatePractice,
@ -236,12 +323,12 @@ export default class TPMchallengesnew extends Component {
score: onshixunsmarkvalue,
challenge_tag: shixunsskillvaluelist,
st: 0,
exec_time:exec_time
}).then((response) => {
if (response.data.status === 1) {
// $("html").animate({ scrollTop: 0 })
//window.location.href=`/shixuns/${id}/challenges/${response.data.challenge_id}/editcheckpoint?tab=2`;
window.location.href=`/shixuns/${id}/challenges/${response.data.challenge_id}/tab=2`;
// window.location.href=`/shixuns/${id}/challenges/${response.data.challenge_id}/tab=2`;
this.props.history.replace(`/shixuns/${id}/challenges/${response.data.challenge_id}/tab=2`);
// this.setState({
// setopen: true,
// CreatePracticesendtype:false,
@ -250,7 +337,7 @@ export default class TPMchallengesnew extends Component {
// })
}
// this.props.showSnackbar(response.data.messages);
// this.props.showNotification(response.data.messages);
}).catch((error) => {
console.log(error)
});
@ -287,6 +374,12 @@ export default class TPMchallengesnew extends Component {
let list = shixunsskillvaluelist;
list.push(shixunsskillvalue);
if (list.length> 0) {
this.setState({
shixunsskillvaluelisttype: false,
})
}
this.setState({
shixunsskillvaluelist: list,
shixunsskillvalue: ""
@ -303,51 +396,103 @@ 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({
// shixunCreatePracticetype: true
// })
this.props.showSnackbar("任务名称为空")
this.setState({
shixunCreatePracticetype: true,
editPracticesendtype:false
})
// this.props.showNotification("任务名称为空")
$('html').animate({
scrollTop: 10
}, 1000);
return
}
if (shixunCreatePractice.match(/^[ ]*$/)) {
this.props.showNotification("任务名称为空,请勿输入空格");
this.setState({
editPracticesendtype:false
shixunCreatePracticetype: true,
editPracticesendtype:false
})
$('html').animate({
scrollTop: 10
}, 1000);
return
}
if (shixunsskillvaluelist.length === 0) {
// this.setState({
// shixunsskillvaluelisttype: true
// })
this.props.showSnackbar("技能标签为空")
if (exercise_editormdvalue === undefined||exercise_editormdvalue==""||exercise_editormdvalue===null) {
this.setState({
editPracticesendtype:false
tpmcourseMessageMDType:true,
editPracticesendtype:false
})
this.props.scrollToAnchor("tpmcourseMessageMD");
return
}
if(exec_time===null||exec_time===undefined||exec_time===""){
if(isNulltpm(exercise_editormdvalue)){
this.setState({
tpmcourseMessageMDType:true,
editPracticesendtype:false
})
this.props.scrollToAnchor("tpmcourseMessageMD");
this.props.showNotification("过关任务,请勿输入空格");
return
}
this.setState({
shixunExec_timeType:false
})
return
}
if(shixunCreatePracticeGroup===undefined){
this.setState({
shixunCreatePracticeGrouptype:true,
editPracticesendtype:false
})
this.props.scrollToAnchor("shixunCreatePracticeGroupid");
return
}
if(onshixunsmarkvalue===undefined){
this.setState({
onshixunsmarkvaluetype:true,
editPracticesendtype:false
})
this.props.scrollToAnchor("input_task_tag");
return
}
if (shixunsskillvaluelist.length === 0) {
this.setState({
shixunsskillvaluelisttype: true,
editPracticesendtype:false,
})
this.props.scrollToAnchor("input_task_tag");
return
}
// if(exec_time===null||exec_time===undefined||exec_time === ""){
// this.setState({
// shixunExec_timeType:true,
// editPracticesendtype:false
// })
// this.props.scrollToAnchor("exec_time");
// return
// }
// if (exec_time.match(/^[ ]*$/)) {
// this.props.showNotification("评测时限,请勿输入空格");
// this.setState({
// shixunExec_timeType:true,
// editPracticesendtype:false
// })
// this.props.scrollToAnchor("exec_time");
// return
// }
// exec_time:exec_time
axios.put(url, {
tab:0,
identifier:id,
@ -357,19 +502,19 @@ export default class TPMchallengesnew extends Component {
task_pass: exercise_editormdvalue,
difficulty: shixunCreatePracticeGroup,
score: onshixunsmarkvalue,
exec_time:exec_time
},
challenge_tag:shixunsskillvaluelist
}).then((response) => {
this.props.showSnackbar(response.data.messages);
this.props.showNotification(response.data.messages);
if (response.data.status === 1) {
window.location.href=`/shixuns/${id}/challenges/${checkpointId}/tab=2`;
// window.location.href=`/shixuns/${id}/challenges/${checkpointId}/tab=2`;
this.setState({
setopen: true,
editPracticesendtype:false,
tab2url: "/shixuns/" + id + "/challenges/"+checkpointId+"/tab=2",
tab3url: "/shixuns/" + id + "/challenges/"+checkpointId+"/tab=3",
})
this.props.history.replace(`/shixuns/${id}/challenges/${checkpointId}/tab=2`);
// window.location.href = "/shixuns/" + id + "/challenges/"+response.data.challenge_id+"/tab=2"
}
}).catch((error) => {
@ -396,12 +541,16 @@ export default class TPMchallengesnew extends Component {
exec_time:e.target.value
})
}
gotocheckpoint=(url)=>{
this.props.history.replace(url);
}
render() {
let shixuntype = this.props.match.params.type;
let {marktype,
let {responsedata,
shixunCreatePracticetype, shixunsskillvaluelisttype,
choice_url, practice_url, go_back_url, position, task_pass_default, submit_url, setopen,checkpointId,prev_challenge,next_challenge,power,
shixunCreatePractice, shixunCreatePracticeGroup, onshixunsmarkvalue, shixunsskillvalue, shixunsskillvaluelist, tab2url, tab3url,optionsums,
@ -417,142 +566,146 @@ export default class TPMchallengesnew extends Component {
})
}
// console.log(this.props)
// console.log(this.state)
//a console.log(shixunCreatePractice)
return (
<React.Fragment>
<div className="educontent mt30 mb30">
<div className="padding10-20 mb10 edu-back-white clearfix">
<span className="fl ring-blue mr10 mt7">
<img src={getImageUrl("images/educoder/icon/code.svg")} data-tip-down="实训任务" className="fl mt2 ml2"/>
</span>
<span className="font-16 task-hide fl TPMtaskName">{position}</span>
<Link to={go_back_url === undefined ? "" : go_back_url}
className="color-grey-6 fr font-15 mt3">返回</Link>
{ next_challenge===undefined?"":
<a href={next_challenge}className="fr color-blue mr15 mt4">下一关</a>
}
{ prev_challenge===undefined?"":
<a href={prev_challenge} className="fr color-blue mr15 mt4">上一关</a>
}
<a href={practice_url === undefined ? "" : practice_url}
className="fr color-blue mr15 mt4"
style={{display:this.props.identity>4||this.props.identity===undefined||this.props.status===2||this.props.status===1?"none":'block'}}
data-tip-down="新增代码编辑类型的任务">+&nbsp;实践类型</a>
<a href={choice_url === undefined ? "" : choice_url}
className="fr color-blue mr15 mt4"
style={{display:this.props.identity>4||this.props.identity===undefined||this.props.status===2||this.props.status===1?"none":'block'}}
data-tip-down="新增选择题类型的任务">+&nbsp;选择题类型</a>
<div className="TPMchallengesnewtitles edu-back-white clearfix borderbottomf4">
<span className="font-16 task-hide fl TPMtaskName">{position}{responsedata&&responsedata.st === 0 ?"实践题":responsedata&&responsedata.st === 1?"选择题":""}</span>
{this.props.identity>4||this.props.identity===undefined||this.props.status===2||this.props.status===1?"":<a href={practice_url === undefined ? "" : practice_url} className="fr ml15 mt13">
<Button type="primary" className="edu-default-btn edu-greenback-btn "
>新增实践任务</Button></a>}
{this.props.identity>4||this.props.identity===undefined||this.props.status===2||this.props.status===1?"":<Link to={choice_url === undefined ? "" : choice_url}
className="fr ml15 mt13">
<Button type="primary"
className="edu-default-btn edu-greenback-btn mr5"
>新增选择题任务</Button></Link>}
{next_challenge===undefined?"":
<Button type="primary" ghost onClick={()=>this.gotocheckpoint(next_challenge)}
className="edu-default-btn edu-greenback-btn mr5 fr ml15 mt13"
>下一关</Button> }
{prev_challenge===undefined?"":
<Button type="primary" ghost onClick={()=>this.gotocheckpoint(prev_challenge)}
className="edu-default-btn edu-greenback-btn mr5 fr ml15 mt13"
>上一关</Button>}
</div>
<div className="challenge_nav clearfix edu-back-white">
<li className="active">
<a>本关任务</a>
<a className={"color-blue"}>1本关任务 </a>
</li>
{tab2url === "" ? "":<li> > </li>}
<li className="">
{tab2url === "" ? <span>评测设置</span> : <Link to={tab2url}></Link>}
{tab2url === "" ? <span></span> : <Link to={tab2url}>2</Link>}
</li>
{tab3url === "" ? "":<li> > </li>}
<li className="">
{tab3url === "" ? <span>参考答案</span> : <Link to={tab3url}></Link>}
{tab3url === "" ? <span></span> : <Link to={tab3url}> 3</Link>}
</li>
</div>
<div className="edu-back-white mb10 clearfix">
<div className="padding40-20">
<p className="color-grey-6 font-16 mb30">任务名称</p>
<div className="df">
<span className="mr30 color-orange pt10">*</span>
<div className="flex1 mr20">
<input type="text"
// className="input-100-45 greyInput"
className={shixunCreatePracticetype===true?"input-100-45 greyInpus wind100":"input-100-45 greyInput "}
maxLength="50"
name="challenge[subject]"
value={shixunCreatePractice}
<div className="edu-back-white clearfix">
<div className="newpadding1020">
<p className="color-grey-6 font-16 mb10"> <span className="mr5 color-red">*</span></p>
<div>
<div className="flex1">
<Input placeholder="请输入任务名称最大限制60个字符此信息将在实训发布后展示给学员计算学生的课程成绩绩点"
maxLength="60"
className={shixunCreatePracticetype === true ? "bor-red":"newViewAfter"}
onInput={this.shixunCreatePractice}
placeholder="请输入任务名称(此信息将提前展示给学员),例:计算学生的课程成绩绩点"/>
value={shixunCreatePractice}
addonAfter={`${String(!shixunCreatePractice? 0 : shixunCreatePractice.length)}/${60}`}
/>
</div>
<div style={{width: '57px'}}>
<span
className={shixunCreatePracticetype === true ? "color-orange mt8 fl block" : "color-orange mt8 fl none"}
id="new_shixun_name"><i
className="fa fa-exclamation-circle mr3"></i></span>
<div>
<span className={shixunCreatePracticetype === true ? "color-red mt8 fl block" : "color-red mt8 fl none"} id="new_shixun_name">必填项不能为空</span>
</div>
</div>
</div>
</div>
<div className="edu-back-white padding40-20 mb20">
<div className="edu-back-white newpadding02020">
<p className="color-grey-6 font-16 mb30">过关任务</p>
<p className="color-grey-6 font-16 mb10" id={"tpmcourseMessageMD"}><span className="mr5 color-red">*</span></p>
<style>
{
`
.markdown-body img {
max-width: 80%;
margin: 0 auto;
display: block;
width: auto;
height: auto;
max-height: 80%;
}
`
}
</style>
<TPMMDEditor ref={this.exercisememoMDRef} placeholder="请输入选择题的题干内容" mdID={'exercisememoMD'} refreshTimeout={1500}
<TPMMDEditor ref={this.exercisememoMDRef} placeholder="请输入选择题的题干内容" mdID={'exercisememoMD'} refreshTimeout={1500}
watch={true} className="courseMessageMD" initValue={this.state.exercisememoMDRefval} height={700}></TPMMDEditor>
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>
</div>
{this.state.tpmcourseMessageMDType===true?<div className="color-red mt7 ml5 font-14" >必填项不能为空</div>:""}
</div>
<div className="edu-back-white padding40-20 mb20">
<p className="color-grey-6 font-16 mb30">难度系数</p>
<div className="clearfix mb40">
<RadioGroup value={shixunCreatePracticeGroup} className="fl mr40"
disabled={this.props.status===2?true:false}
onChange={this.props.status===2?"":this.onshixunCreatePracticeChange}>
<div className="edu-back-white newpadding02020">
<p className="color-grey-6 font-16 mb20">
<span className="fl color-red mr5">*</span>
难度系数
<RadioGroup value={shixunCreatePracticeGroup}
className={"ml10"}
id={"shixunCreatePracticeGroupid"}
disabled={this.props.status===2?true:false}
onChange={this.props.status===2?"":this.onshixunCreatePracticeChange}>
<Radio value={1}>简单</Radio>
<Radio value={2}>中等</Radio>
<Radio value={3}>困难</Radio>
</RadioGroup>
</div>
<p className="color-grey-6 font-16 mb30">奖励经验值</p>
<div className="clearfix"
// onMouseLeave={this.props.status===2?"":this.onshixunsmarkss}
>
<span className="fl mr30 color-orange pt10">*</span>
<Select style={{width: 120}} className="winput-240-40 fl"
{this.state.shixunCreatePracticeGrouptype===true?<div className="color-red mt7 ml5 font-14" id="ex_value_notice">
必选项不能为空</div>:""}
</p>
<p className="color-grey-6 font-16 mb10"> <span className="fl mr5 color-red">*</span> <span className={"color-grey-8 font-14"}> (+100+100)</span></p>
<div className="clearfix">
{this.state.onshixunsmarkvaluetype===true?<style>
{
`
.ant-select-selection{
border:1px solid red;
}
`
}
</style>:""}
<Select style={{width: 252}}
className={"winput-240-40 ml3"}
id="challenge_score"
onChange={this.props.status===2?"":this.onshixunsmark}
// onMouseEnter={this.props.status===2?"":this.onshixunsmarks}
disabled={this.props.status===2?true:false}
// open={marktype}
value={onshixunsmarkvalue}
getPopupContainer={triggerNode => triggerNode.parentNode}
>
{options}
</Select>
<p className="fl color-grey-9 font-12 ml20">
如果学员答题错误则不能得到相应的经验值<br/>
如果学员成功得到经验值那么将同时获得等值的金币奖励+10经验值+10金币
</p>
<span className="color-orange mt7 fl ml20 none" id="ex_value_notice"><i
className="fa fa-exclamation-circle mr3"></i></span>
{this.state.onshixunsmarkvaluetype===true?<div className="color-red mt7 ml5" id="ex_value_notice">
必选项不能为空</div>:""}
</div>
</div>
<div className="edu-back-white padding40-20 mb20">
<p className="color-grey-6 font-16 mb30">技能标签</p>
<div className="clearfix df">
<span className="mr30 color-orange pt10">*</span>
<div className="edu-back-white newpadding02020">
<p className="color-grey-6 font-16 mb10"><span className="mr5 color-red">*</span><span className={"color-grey-8 font-14"}> ()</span></p>
<div className="clearfix">
<div className="flex1">
<Input type="text"
className="winput-240-40 fl mr20 winput-240-40s"
className={shixunsskillvaluelisttype === true ?"winput-240-40 fl mr20 winput-240-40s ml10 bor-red":"winput-240-40 fl mr20 winput-240-40s ml10"}
id="input_task_tag"
placeholder="添加标签"
onInput={this.shixunsskill}
@ -560,54 +713,59 @@ export default class TPMchallengesnew extends Component {
onPressEnter={this.clickshixunsskill}
onBlur={this.clickshixunsskill}
/>
{/*<a className="white-btn orange-btn fl mt1 use_scope-btn ml20 mt5 mr20"*/}
{/*onClick={this.clickshixunsskill}>+ 添加</a>*/}
<div className="ml15 color-grey-9 mt5">学员答题正确将获得技能否则不能获得技能</div>
<div className="ml15 color-grey-9 pt5 font-14">(回车添加标签)</div>
<div className="mt20 clearfix" id="task_tag_content">
{
shixunsskillvaluelist===undefined?"":shixunsskillvaluelist.length === 0 ? "" : shixunsskillvaluelist.map((itme, key) => {
return (
<li className="task_tag_span" key={key}><span>{itme}</span>
<a onClick={() => this.delshixunsskilllist(key)}>×</a>
</li>
<li key={key} className={"fl ml10 mr10"}>
<Badge className={"tpmpointer"} count={"x"} onClick={(key) => this.delshixunsskilllist(key)}>
<Button type="primary" ghost className={"Permanentban "}>
{itme}
</Button>
</Badge>
</li>
)
})
}
</div>
</div>
<span
className={shixunsskillvaluelisttype === true ? "color-orange mt7 fl ml20 block" : " color-orange mt7 fl ml20 none"}
id="stage_name_notice">
<i className="fa fa-exclamation-circle mr3"></i></span>
<div className={shixunsskillvaluelisttype === true ? "color-red ml10 mt5 block" : "none"}
id="stage_name_notice">必选项不能为空</div>
</div>
</div>
<div className="edu-back-white padding40-20 mb20">
<p className="color-grey-6 font-16 mb30">服务配置</p>
<div className="clearfix mb5">
<span className="color-orange pt10 fl">*</span>
<label className="panel-form-label fl">评测时限(S)</label>
<div className="pr fl with80 status_con">
<input value={this.state.exec_time} className="panel-box-sizing task-form-100 task-height-40" placeholder="请输入类别名称" onInput={this.setexec_time}/>
</div>
<span
className={this.state.shixunExec_timeType === true ? "color-orange mt8 fl block ml20" : "color-orange mt8 fl none"}
id="new_shixun_name"><i className="fa fa-exclamation-circle mr3"></i></span>
<div className="cl"></div>
</div>
</div>
<div className="clearfix mt30"
style={{display:this.props.identity>4||this.props.identity===undefined?"none":'block'}}
>
{checkpointId===undefined?<a className="defalutSubmitbtn fl mr20" onClick={CreatePracticesendtype===true?"":this.CreatePracticesend}>提交</a>:
<a className="defalutSubmitbtn fl mr20" onClick={editPracticesendtype===true?"":this.editPracticesend}>提交</a>}
<a href={go_back_url === undefined ? "" : go_back_url} className="defalutCancelbtn fl">取消</a>
</div>
{/*<div className="edu-back-white newpadding02020">*/}
{/* <p className="color-grey-6 font-16 mb20"> <span className="color-orange mr5 fl">*</span> 服务配置:评测时限(S)</p>*/}
{/* <div className="clearfix mb5 ml10">*/}
{/* <div className="pr status_con" id={"exec_timeid"}>*/}
{/* /!*<label className="panel-form-label fl"></label>*!/*/}
{/* <input value={this.state.exec_time}*/}
{/* className={this.state.shixunExec_timeType === true ?"panel-box-sizing task-form-100 task-height-40 bor-red":"panel-box-sizing task-form-100 task-height-40" }*/}
{/* placeholder="请输入类别名称" onInput={this.setexec_time}/>*/}
{/* </div>*/}
{/* <div*/}
{/* className={this.state.shixunExec_timeType === true ? "color-red mt8 block ml5" : " none"}*/}
{/* id="new_shixun_name">必填项:不能为空</div>*/}
{/* </div>*/}
{/*</div>*/}
</div>
{this.props.identity>4||this.props.identity===undefined?"":<div className="clearfix mt30"
// style={{display:this.props.identity>4||this.props.identity===undefined?"none":'block'}}
>
{/*{checkpointId===undefined?<a className="defalutSubmitbtn fl mr20" onClick={CreatePracticesendtype===true?"":this.CreatePracticesend}>提交</a>:*/}
{/*<a className="defalutSubmitbtn fl mr20" onClick={editPracticesendtype===true?"":this.editPracticesend}>提交</a>}*/}
{/*<a href={go_back_url === undefined ? "" : go_back_url} className="defalutCancelbtn fl">取消</a>*/}
{/*<Link to={go_back_url === undefined ? "" : go_back_url} className={"defalutCancelbtn fl"}>取消</Link>*/}
<Bottomsubmit url={go_back_url === undefined ? "" : go_back_url}
{...this.props}
{...this.state}
bottomvalue={"提交"}
onSubmits={checkpointId===undefined?()=>this.CreatePracticesend():()=>this.editPracticesend()}
loadings={CreatePracticesendtype===true?true:editPracticesendtype===true?true:false}/>
</div>}
</React.Fragment>
)
}

@ -1,97 +1,32 @@
import React, {Component} from 'react';
import {Input, Select, Radio, Checkbox, Popconfirm, message, Modal,Button,Icon,Tooltip} from 'antd';
import {Input, Select, Radio, Checkbox, Modal,Button,Tooltip} from 'antd';
import {BrowserRouter as Router, Route, Link, Switch} from "react-router-dom";
// import "antd/dist/antd.css";
import { Link} from "react-router-dom";
import axios from 'axios';
import { getImageUrl, toPath } from 'educoder';
import './css/TPMchallengesnew.css';
import Bottomsubmit from "../../modals/Bottomsubmit";
import {getUrl} from 'educoder';
import { getImageUrl } from 'educoder';
let origin = getUrl();
let path = getUrl("/editormd/lib/")
import './css/TPMchallengesnew.css';
const $ = window.$;
let timeout;
let currentValue;
const Option = Select.Option;
const RadioGroup = Radio.Group;
const { TextArea } = Input;
function create_editorMD(id, width, high, placeholder, imageUrl, callback) {
var editorName = window.editormd(id, {
width: width,
height: high,
path: path, // "/editormd/lib/"
syncScrolling: "single",
tex: true,
tocm: true,
emoji: true,
taskList: true,
codeFold: true,
searchReplace: true,
htmlDecode: "style,script,iframe",
sequenceDiagram: true,
autoFocus: false,
toolbarIcons: function () {
// Or return editormd.toolbarModes[name]; // full, simple, mini
// Using "||" set icons align right.
return ["bold", "italic", "|", "list-ul", "list-ol", "|", "code", "code-block", "|", "testIcon", "testIcon1", '|', "image", "table", '|', "watch", "clear"]
},
toolbarCustomIcons: {
testIcon: "<a type=\"inline\" class=\"latex\" ><div class='zbg'></div></a>",
testIcon1: "<a type=\"latex\" class=\"latex\" ><div class='zbg_latex'></div></a>"
},
//这个配置在simple.html中并没有但是为了能够提交表单使用这个配置可以让构造出来的HTML代码直接在第二个隐藏的textarea域中方便post提交表单。
saveHTMLToTextarea: true,
// 用于增加自定义工具栏的功能可以直接插入HTML标签不使用默认的元素创建图标
dialogMaskOpacity: 0.6,
placeholder: placeholder,
imageUpload: true,
imageFormats: ["jpg", "jpeg", "gif", "png", "bmp", "webp", "JPG", "JPEG", "GIF", "PNG", "BMP", "WEBP"],
imageUploadURL: imageUrl,//url
onload: function () {
// this.previewing();
$("#" + id + " [type=\"latex\"]").bind("click", function () {
editorName.cm.replaceSelection("```latex");
editorName.cm.replaceSelection("\n");
editorName.cm.replaceSelection("\n");
editorName.cm.replaceSelection("```");
var __Cursor = editorName.cm.getDoc().getCursor();
editorName.cm.setCursor(__Cursor.line - 1, 0);
});
$("#" + id + " [type=\"inline\"]").bind("click", function () {
editorName.cm.replaceSelection("`$$$$`");
var __Cursor = editorName.cm.getDoc().getCursor();
editorName.cm.setCursor(__Cursor.line, __Cursor.ch - 3);
editorName.cm.focus();
});
$("[type=\"inline\"]").attr("title", "行内公式");
$("[type=\"latex\"]").attr("title", "多行公式");
window.md_elocalStorage(editorName, `exercise__${id}`, "Memochallengesnew");
callback && callback()
}
});
return editorName;
function isNulltpm( str ){
if ( str == "" ) return true;
var regu = "^[ ]+$";
var re = new RegExp(regu);
return re.test(str);
}
export default class TPMevaluation extends Component {
constructor(props) {
super(props)
@ -127,39 +62,11 @@ export default class TPMevaluation extends Component {
scorevalue:false,
markvalue:true,
scoretype:undefined,
web_route:null
web_route:null,
exec_time:undefined
}
}
exerciseMD(initValue, id) {
this.contentChanged = false;
const placeholder = "";
// amp;
// 编辑时要传memoId
const imageUrl = `/api/attachments.json`;
// 创建editorMd
const exercise_editormd = create_editorMD(id, '100%', 400, placeholder, imageUrl, () => {
setTimeout(() => {
exercise_editormd.resize()
exercise_editormd.cm && exercise_editormd.cm.refresh()
}, 500)
if (initValue != undefined) {
exercise_editormd.setValue(initValue)
}
exercise_editormd.cm.on("change", (_cm, changeObj) => {
console.log('....contentChanged')
this.contentChanged = true;
})
});
this.exercise_editormd = exercise_editormd;
window.exercise_editormd = exercise_editormd;
}
componentDidMount() {
let id = this.props.match.params.shixunId;
let checkpointId=this.props.match.params.checkpointId;
@ -193,8 +100,7 @@ export default class TPMevaluation extends Component {
let newevaluationlist=[]
if(response.data.test_sets.length===0){
let newlist=[
{hidden:0,input:"",output:"",score:50},
{hidden:0,input:"",output:"",score:50}
{hidden:0,input:"",output:"",score:100},
]
newevaluationlist=newlist
}else{
@ -219,18 +125,16 @@ export default class TPMevaluation extends Component {
scorevalue:response.data.test_set_score,
markvalue:response.data.test_set_average,
web_route:response.data.web_route,
has_web_route:response.data.has_web_route
has_web_route:response.data.has_web_route,
responsedata:response.data,
exec_time:response.data.exec_time,
})
this.evaluationoninputvalueonload();
if(response.data.power===false){
this.props.showSnackbar("你没有权限修改");
}
if(response.data.answer===undefined){
this.answerMD("", "answerMD");
}else{
this.answerMD(response.data.answer, "answerMD");
this.props.showNotification("你没有权限修改");
}
}).catch((error) => {
console.log(error)
});
@ -249,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);
}
@ -379,34 +283,6 @@ export default class TPMevaluation extends Component {
}
// delesavegetfilepath=(value)=>{
// let {selectpatharr} = this.state
// let newarr =selectpatharr;
// let newselectpath="";
// for(var i=0; i<newarr.length;i++){
// if(newarr[i]===value){
//
// newarr.splice(i,1);
// console.log(newarr)
// console.log(value)
// }
// }
//
//
//
//
// for(var z=0; z<newarr.length;z++){
// newselectpath=newselectpath+newarr[z]+ ""
// }
// this.setState({
// selectpatharr:newarr,
// selectpath: newselectpath
// })
// }
savegetfilepath=(value)=>{
let {selectpath,saveshixunfilepath,pathtype} = this.state
@ -438,30 +314,6 @@ export default class TPMevaluation extends Component {
})
}
// let newarr =selectpatharr;
// let arrtype=false;
// let arrsum=0;
// let newselectpath="";
// newarr.push(value)
// if(newarr.length>1&&arrtype===false){
// for(var i=0; i<newarr.length;i++){
// if(newarr[i]===value){
// arrsum=arrsum+1;
// if(arrsum===2){
// newarr.splice(i,1);
// arrtype=true;
// }
// }
// }
// }
// for(var z=0; z<newarr.length;z++){
// newselectpath=newselectpath+newarr[z]+ ""
// }
}
evaluationenter=()=>{
@ -505,12 +357,6 @@ export default class TPMevaluation extends Component {
}else{
newtype=1;
}
// newevaluationlist[key].is_public=newtype;
// for(var i=0; i<newevaluationlist.length; i++){
// if(i===key){
//
// }
// }
newevaluationlist[key].hidden=newtype;
this.setState({
@ -597,7 +443,7 @@ export default class TPMevaluation extends Component {
$('textarea[autoHeight]').autoHeight();
}
submitarbitrationevaluation=()=>{
let{evaluationlist,shixunfilepath,shixunfilepathplay,shixunfileexpectpicturepath,shixunfilestandardpicturepath,shixunfilepicturepath,pathoptionvalue,scorevalue,markvalue,web_route}=this.state;
let{exec_time,evaluationlist,shixunfilepath,shixunfilepathplay,shixunfileexpectpicturepath,shixunfilestandardpicturepath,shixunfilepicturepath,pathoptionvalue,scorevalue,markvalue,web_route}=this.state;
let newscorevalue;
@ -610,7 +456,7 @@ export default class TPMevaluation extends Component {
let sum=0;
for(var i=0; i<evaluationlist.length; i++){
if(evaluationlist[i].score>100){
this.props.showSnackbar("测试集的评分占比不能大于100");
this.props.showNotification("测试集的评分占比不能大于100");
this.setState({
scoretype:i
})
@ -620,36 +466,52 @@ export default class TPMevaluation extends Component {
}
if(sum>100||sum<100){
this.props.showSnackbar("测试集的评分占比之和必须等于100");
this.props.showNotification("测试集的评分占比之和必须等于100");
return
}
}
if(exec_time===null||exec_time===undefined||exec_time === ""){
this.setState({
shixunExec_timeType:true,
})
this.props.scrollToAnchor("exec_timeid");
return
}
if (isNulltpm(exec_time)) {
this.props.showNotification("评测时长,请勿输入空格");
this.setState({
shixunExec_timeType:true,
})
this.props.scrollToAnchor("exec_timeid");
return
}
if(shixunfilepath===undefined||shixunfilepath===""||shixunfilepath===null){
this.props.showSnackbar("学员任务文件路径为空");
// this.props.showSnackbar("学员任务文件路径为空");
this.setState({
StudentTaskPapers:true
})
$('html').animate({
scrollTop: 120
}, 1000);
this.props.scrollToAnchor("Studenttaskfile");
return
}
if(shixunfilepathplay===undefined||shixunfilepathplay===""||shixunfilepathplay===null){
this.props.showSnackbar("评测执行文件路径为空");
// this.props.showSnackbar("评测执行文件路径为空");
this.setState({
StudentTaskDocs:true
})
$('html').animate({
scrollTop: 130
}, 1000);
this.props.scrollToAnchor("Benchmarkexecutable");
return
}
if(evaluationlist.length===0){
this.props.showSnackbar("测试集不能为空");
this.props.scrollToAnchor("Thetestset");
return
}
let id = this.props.match.params.shixunId;
@ -664,7 +526,8 @@ export default class TPMevaluation extends Component {
picture_path:pathoptionvalue===-1?undefined:shixunfilepicturepath===undefined?null:shixunfilepicturepath,
test_set_score:newscorevalue,
test_set_average:markvalue,
web_route:web_route===null?undefined:web_route
web_route:web_route===null?undefined:web_route,
exec_time:exec_time
}
axios.put(url,{
tab:1,
@ -672,7 +535,7 @@ export default class TPMevaluation extends Component {
test_set:evaluationlist
}
).then((response) => {
this.props.showSnackbar(response.data.messages);
this.props.showNotification(response.data.messages);
window.location.href=`/shixuns/${id}/challenges/${response.data.challenge_id}/tab=3`;
// if(response.data.status===1){
// window.location.href = "/shixuns/" + id + "/challenges/"+response.data.challenge_id+"/tab=3"
@ -681,16 +544,7 @@ export default class TPMevaluation extends Component {
console.log(error)
});
}
handpathoptionvalues=()=>{
this.setState({
handpathopt:true
})
}
handpathoptionvaluess=()=>{
this.setState({
handpathopt:false
})
}
saveselectpath=(e)=>{
this.setState({
@ -768,6 +622,24 @@ export default class TPMevaluation extends Component {
web_route:e.target.value
})
}
gotocheckpoint=(url)=>{
this.props.history.replace(url);
}
setexec_time=(e)=>{
if(e.target.value===null||e.target.value===undefined||e.target.value === ""||e.target.value.match(/^[ ]*$/)){
}else{
this.setState({
shixunExec_timeType:false,
})
}
this.setState({
exec_time:e.target.value
})
}
render() {
let {
@ -799,7 +671,8 @@ export default class TPMevaluation extends Component {
scorevalue,
markvalue,
scoretype,
has_web_route
has_web_route,
responsedata
} = this.state;
let tab1url="/shixuns/" + shixunId + "/challenges/"+checkpointId+"/editcheckpoint";
@ -812,64 +685,115 @@ export default class TPMevaluation extends Component {
lineHeight: '30px',
marginLeft: '20px',
};
return (
<React.Fragment>
<div className="educontent mt30 mb30">
<div className="padding10-20 mb10 edu-back-white clearfix">
<span className="fl ring-blue mr10 mt7">
<img src={getImageUrl("images/educoder/icon/code.svg")} data-tip-down="实训任务" className="fl mt2 ml2"/>
</span>
<span className="font-16 task-hide fl TPMtaskName">{position}</span>
<Link to={go_back_url === undefined ? "" : go_back_url}
className="color-grey-6 fr font-15 mt3">返回</Link>
{prev_challenge === undefined ? "" :
<a href={prev_challenge} className="fr color-blue mr15 mt4">上一关</a>
}
{next_challenge === undefined ? "" :
<a href={next_challenge} className="fr color-blue mr15 mt4">下一关</a>
}
<a href={practice_url === undefined ? "" : practice_url}
className="fr color-blue mr15 mt4"
style={{display:this.props.identity>4||this.props.identity===undefined||this.props.status===2||this.props.status===1? "none":'block'}}
data-tip-down="新增代码编辑类型的任务">+&nbsp;实践类型</a>
<a href={choice_url === undefined ? "" : choice_url}
className="fr color-blue mr15 mt4"
style={{display:this.props.identity>4||this.props.identity===undefined||this.props.status===2||this.props.status===1?"none":'block'}}
data-tip-down="新增选择题类型的任务">+&nbsp;选择题类型</a>
<div className="TPMchallengesnewtitles edu-back-white clearfix borderbottomf4">
<span className="font-16 task-hide fl TPMtaskName">{position}{responsedata&&responsedata.st === 0 ?"实践题":responsedata&&responsedata.st === 1?"选择题":""}</span>
{this.props.identity>4||this.props.identity===undefined||this.props.status===2||this.props.status===1?"":<a href={practice_url === undefined ? "" : practice_url} className="fr ml15 mt13">
<Button type="primary" className="edu-default-btn edu-greenback-btn "
>新增实践任务</Button></a>}
{this.props.identity>4||this.props.identity===undefined||this.props.status===2||this.props.status===1?"":<Link to={choice_url === undefined ? "" : choice_url}
className="fr ml15 mt13">
<Button type="primary"
className="edu-default-btn edu-greenback-btn mr5"
>新增选择题任务</Button></Link>}
{next_challenge===undefined?"":
<Button type="primary" ghost onClick={()=>this.gotocheckpoint(next_challenge)}
className="edu-default-btn edu-greenback-btn mr5 fr ml15 mt13"
>下一关</Button> }
{prev_challenge===undefined?"":
<Button type="primary" ghost onClick={()=>this.gotocheckpoint(prev_challenge)}
className="edu-default-btn edu-greenback-btn mr5 fr ml15 mt13"
>上一关</Button>}
</div>
<div className="challenge_nav clearfix edu-back-white">
<li>
<Link to={tab1url}>本关任务</Link>
<Link to={tab1url}>1本关任务 </Link>
</li>
{tab2url === "" ? "":<li> > </li>}
<li className="active">
<Link to={tab2url}>评测设置</Link>
<Link to={tab2url} className={"color-blue"}>2评测设置</Link>
</li>
{tab3url === "" ? "":<li> > </li>}
<li className="">
<Link to={tab3url}>参考答案</Link>
<Link to={tab3url}> 3参考答案</Link>
</li>
</div>
<p className="color-orange-tip font-12 padding20">
请先上传本关任务的所有代码文件标准图片等所有必要的文件到
<a href={"/shixuns/" + shixunId + "/repository"} className="color-bule-tip decoration" target="_blank">版本库</a>
<p className="color-orange-tip font-14 padding10 edu-back-white text-centers">
<div className={"bor25510211"}>
请先上传本关任务的所有代码文件标准图片等所有必要的文件到
<a href={"/shixuns/" + shixunId + "/repository"} className="color-bule-tip decoration" target="_blank">版本库</a>
</div>
</p>
<div className="edu-back-white newpadding02020" id={"exec_timeid"} >
<p className="color-grey-6 font-16 mb20"> <span className="color-red mr5 fl">*</span> <span className={"color-grey-8 font-14"}></span></p>
<div className="clearfix mb5">
<div className="pr status_con" style={{'width':'233px'}}>
<Input value={this.state.exec_time}
className={this.state.shixunExec_timeType === true ?"panel-box-sizing task-form-100 task-height-40 bor-red":"panel-box-sizing task-form-100 task-height-40" }
placeholder="请输入评测时长" onInput={this.setexec_time}/>
</div>
<div
className={this.state.shixunExec_timeType === true ? "color-red mt8 block ml5" : " none"}
id="new_shixun_name">必填项不能为空</div>
</div>
</div>
<div className="edu-back-white mb10 clearfix">
<div className="padding40-20">
<p className="color-grey-6 font-16 mb20">学员任务文件</p>
<div className="df">
<span className="mr30 color-orange pt10">*</span>
<div className="flex1 mr20">
<input type="text" className="input-100-45 greyInput change" id="shixun_file_path"
<div className="edu-back-white clearfix">
<div className="padding1020tpms mb10">
<p className="color-grey-6 font-16 mb20"><span className="color-red mr5 fl">*</span> <span className={"color-grey-8 font-14"}></span></p>
<div className="pr">
<Select className="winput-240-40"
value={pathoptionvalue}
onChange={this.handpathoptionvalue}>
<Option value={-1}></Option>
<Option value={1}>图片</Option>
<Option value={2}>apk/exe</Option>
<Option value={3}>txt</Option>
<Option value={4}>html</Option>
<Option value={5}>mp3</Option>
<Option value={6}>mp4</Option>
</Select>
<a className="ml10" onClick={()=>this.showrepositoryurltip(1)}><img src={getImageUrl("images/educoder/problem.png")}/></a>
<div className="invite-tip clearfix repository_url_tippostion" style={{display:showrepositoryurltiptype===true?"block":"none"}} id="repository_url_tip"
>
<span className="top-black-trangleft"></span>
<div className="padding20 invitecontent clearfix">
<p className="font-12 edu-txt-left">
图片处理或输出图片类型的任务请选填此项<br/>
可以通过设置图片路径和学员答案文件路径展示代码对应的图片效果<br/><br/>
apk/exe写可执行文件的任务请选填此项<br/>
可以通过设置学员答案文件路径展示二维码以供扫码下载<br/><br/>
txt输出txt文档类型的任务请选填此项<br/>
可以通过学员答案文件路径设置展示txt文件内容<br/><br/>
htmlweb类型的任务请选填此项<br/>
可以通过Web路由设置展示html效果预览页<br/><br/>
mp3/mp4mp3/mp4文件类型的任务请选填此项<br/>
可以通过学员答案文件路径设置展示mp3/mp4文件内容<br/><br/>
</p></div>
<p className="inviteTipbtn with100"><a onClick={()=>this.showrepositoryurltip(2)}
>知道了</a>
</p>
</div>
</div>
</div>
</div>
<div className="edu-back-white clearfix">
<div className="padding1020tpms mb10" id={"Studenttaskfile"}>
<p className="color-grey-6 font-16 mb20"><span className="color-red mr5 fl">*</span> <span className={"color-grey-8 font-14"}></span></p>
<div>
<div className="flex1">
<input type="text"
className={StudentTaskPapers===true?"input-100-45 greyInput change bor-red":"input-100-45 greyInput change"}
id="shixun_file_path"
name="challenge[path]" autoComplete="off"
placeholder="请选择版本库中的代码文件。例: src/step1/HelloWorld.java"
value={shixunfilepath}
@ -877,15 +801,16 @@ export default class TPMevaluation extends Component {
onInput={(e)=>this.updatepath(e,"shixunfilepath",1)}
onClick={(e)=>this.getfilepath(e,"shixunfilepath",1)}
/>
<p className="color-grey-9 mt15">该文件将直接显示给学生需要学生在其中填写代码</p>
</div>
<div style={{width: '57px'}}>
<span className={StudentTaskPapers===true?"color-orange mt8 fl":"color-orange mt8 fl none"} id="student_task_name"><i
className="fa fa-exclamation-circle mr3"></i></span>
<div>
<span className={StudentTaskPapers===true?"color-red mt8 fl":" none"} id="student_task_name"> 必选项不能为空</span>
</div>
</div>
</div>
</div>
<Modal
keyboard={false}
title="文件路径"
@ -914,9 +839,6 @@ export default class TPMevaluation extends Component {
{path+item.name}</a>:<a data-remote="true">
<i className="iconfont icon-zuoye color-blue mr2"></i>
<span onClick={()=>this.savegetfilepath(path+item.name,item.type)}>{path+item.name}</span>
{/*<Tooltip placement="bottom" title={"点击删除下方所选文件路径"}>*/}
{/*<Icon className={"fr mt4"} type="close-circle" onClick={()=>this.delesavegetfilepath(path+item.name)}/>*/}
{/*</Tooltip>*/}
</a>
}
</div>
@ -942,13 +864,12 @@ export default class TPMevaluation extends Component {
</div>
</Modal>
<div className="edu-back-white mb10 clearfix">
<div className="padding40-20">
<p className="color-grey-6 font-16 mb20">评测执行文件</p>
<div className="df">
<span className="mr30 color-orange pt10">*</span>
<div className="flex1 mr20">
<input type="text" className="input-100-45 greyInput" id="shixun_file_path_play"
<div className="edu-back-white clearfix">
<div className="padding1020tpms mb10" id={"Benchmarkexecutable"}>
<p className="color-grey-6 font-16 mb20"><span className="color-red mr5 fl">*</span><span className={"color-grey-8 font-14"}>使</span></p>
<div>
<div className="flex1">
<input type="text" className={StudentTaskDocs===true?"bor-red input-100-45 greyInput":"input-100-45 greyInput"} id="shixun_file_path_play"
name="challenge[exec_path]" autoComplete="off"
placeholder="请选择版本库中的代码文件。例src/step1/HelloWorldTest.java"
value={shixunfilepathplay}
@ -956,59 +877,19 @@ export default class TPMevaluation extends Component {
onInput={(e)=>this.updatepath(e,"shixunfilepathplay",1)}
onClick={(e)=>this.getfilepath(e,"shixunfilepathplay",1)}
/>
<p className="color-grey-9 mt15">该文件由平台执行用来测试平台学员代码是否正确</p>
</div>
<div style={{width: '57px'}}>
<span className={StudentTaskDocs===true?"color-orange mt8 fl":"color-orange mt8 fl none"} id="student_task_name"><i
className="fa fa-exclamation-circle mr3"></i></span>
</div>
</div>
</div>
</div>
<div className="edu-back-white mb10 clearfix">
<div className="padding40-20">
<p className="color-grey-6 font-16 mb20">效果展现方式</p>
<div className="pr">
<Select className="winput-240-40"
value={pathoptionvalue}
onChange={this.handpathoptionvalue}>
<Option value={-1}>请选择效果展现方式</Option>
<Option value={1}>图片</Option>
<Option value={2}>apk/exe</Option>
<Option value={3}>txt</Option>
<Option value={4}>html</Option>
<Option value={5}>mp3</Option>
<Option value={6}>mp4</Option>
</Select>
<a className="ml10" onClick={()=>this.showrepositoryurltip(1)}><img src={getImageUrl("images/educoder/problem.png")}/></a>
<div className="invite-tip clearfix repository_url_tippostion" style={{display:showrepositoryurltiptype===true?"block":"none"}} id="repository_url_tip"
>
<span className="top-black-trangleft"></span>
<div className="padding20 invitecontent clearfix">
<p className="font-12 edu-txt-left">
图片处理或输出图片类型的任务请选填此项<br/>
可以通过设置图片路径和学员答案文件路径展示代码对应的图片效果<br/><br/>
apk/exe写可执行文件的任务请选填此项<br/>
可以通过设置学员答案文件路径展示二维码以供扫码下载<br/><br/>
txt输出txt文档类型的任务请选填此项<br/>
可以通过学员答案文件路径设置展示txt文件内容<br/><br/>
htmlweb类型的任务请选填此项<br/>
可以通过Web路由设置展示html效果预览页
</p></div>
<p className="inviteTipbtn with100"><a onClick={()=>this.showrepositoryurltip(2)}
>知道了</a>
</p>
<div>
<span className={StudentTaskDocs===true?"color-red mt8 fl":"none"} id="student_task_name">
必选项不能为空
</span>
</div>
</div>
<p className="color-grey-9 mt15">该选项用来配置学员评测本关任务时查看效果页上需要展现的文件类型</p>
</div>
</div>
{pathoptionvalue===4&&web_route!=null||pathoptionvalue===4&&has_web_route===true?<div className="edu-back-white mb10 clearfix">
<div className="padding40-20">
<p className="color-grey-6 font-16 mb20">Web路由</p>
{pathoptionvalue===4&&web_route!=null||pathoptionvalue===4&&has_web_route===true?<div className="edu-back-white clearfix">
<div className="padding1020tpms mb10">
<p className="color-grey-6 font-16 mb20">Web路由<span className={"color-grey-8 font-14"}>请注意将服务器程序的端口号映射到8080端口</span></p>
<div className="df">
<div className="flex1 mr20">
<input type="text" className="input-100-45 change" autoComplete="off"
@ -1021,9 +902,9 @@ export default class TPMevaluation extends Component {
</div>
</div>:""}
{pathoptionvalue===1||pathoptionvalue===5||pathoptionvalue===6?<div className="edu-back-white mb10 clearfix">
<div className="padding40-20">
<p className="color-grey-6 font-16 mb20">待处理文件路径</p>
{pathoptionvalue===1||pathoptionvalue===5||pathoptionvalue===6?<div className="edu-back-white clearfix">
<div className="padding1020tpms mb10">
<p className="color-grey-6 font-16 mb20">待处理文件路径<span className={"color-grey-8 font-14"}>该路径下的文件将在学员评测本关任务时作为原始文件显示在查看效果页供学员参考请注意与程序文件所在文件夹分开</span></p>
<div className="df">
<div className="flex1 mr20">
<input type="text" className="input-100-45" autoComplete="off"
@ -1033,9 +914,6 @@ export default class TPMevaluation extends Component {
onInput={(e)=>this.updatepath(e,"shixunfileexpectpicturepath",2)}
onClick={(e)=>this.getfilepath(e,"shixunfileexpectpicturepath",2)}
/>
<p className="color-grey-9 mt15">
该路径下的文件将在学员评测本关任务时作为原始文件显示在查看效果页供学员参考任务为文件处理时请指定该路径并注意与程序文件所在文件夹分开
</p>
</div>
<div></div>
</div>
@ -1043,9 +921,9 @@ export default class TPMevaluation extends Component {
</div>:""}
{pathoptionvalue===1||pathoptionvalue===5||pathoptionvalue===6? <div className="edu-back-white mb10 clearfix">
<div className="padding40-20">
<p className="color-grey-6 font-16 mb20">标准答案文件路径</p>
{pathoptionvalue===1||pathoptionvalue===5||pathoptionvalue===6? <div className="edu-back-white clearfix">
<div className="padding1020tpms mb10">
<p className="color-grey-6 font-16 mb20">标准答案文件路径<span className={"color-grey-8 font-14"}>该路径下的文件将在学员评测本关任务时作为参考答案显示在查看效果页供学员参考请注意与程序文件所在文件夹分开</span></p>
<div className="df">
<div className="flex1 mr20">
<input type="text" className="input-100-45" autoComplete="off"
@ -1055,9 +933,6 @@ export default class TPMevaluation extends Component {
onInput={(e)=>this.updatepath(e,"shixunfilestandardpicturepath",2)}
onClick={(e)=>this.getfilepath(e,"shixunfilestandardpicturepath",2)}
/>
<p className="color-grey-9 mt15">
该路径下的文件将在学员评测本关任务时作为参考答案显示在查看效果页供学员参考任务输出结果为文件时请指定该路径并注意与程序文件所在文件夹分开
</p>
</div>
<div></div>
</div>
@ -1065,9 +940,9 @@ export default class TPMevaluation extends Component {
</div>:""}
{pathoptionvalue===-1?"":<div className="edu-back-white mb10 clearfix">
<div className="padding40-20">
<p className="color-grey-6 font-16 mb20">学员答案文件路径</p>
{pathoptionvalue===-1?"":<div className="edu-back-white clearfix">
<div className="padding1020tpms mb10">
<p className="color-grey-6 font-16 mb20">学员答案文件路径<span className={"color-grey-8 font-14"}>学员评测本关任务时生成的文件将保存在该路径下并作为实际输出显示在查看效果页供学员确认请注意与程序文件所在文件夹分开</span></p>
<div className="df">
<div className="flex1 mr20">
<input type="text" className="input-100-45 change" autoComplete="off"
@ -1076,9 +951,6 @@ export default class TPMevaluation extends Component {
onInput={(e)=>this.updatepath(e,"shixunfilepicturepath",2)}
onClick={(e)=>this.getfilepath(e,"shixunfilepicturepath",2)}
placeholder="请在版本库中指定用来保存学员代码实际输出结果的路径。例src/step1/outputfiles"/>
<p className="color-grey-9 mt15">
学员评测本关任务时生成的文件将保存在该路径下并作为实际输出显示在查看效果页供学员确认任务输出结果为文件时请指定该路径并注意与程序文件所在文件夹分开
</p>
</div>
<div></div>
</div>
@ -1086,10 +958,10 @@ export default class TPMevaluation extends Component {
</div>}
<div className="edu-back-white mb10 clearfix">
<div className="padding40-20">
<div className="edu-back-white clearfix" id={"Thetestset"}>
<div className="padding1020tpms mb20">
{/*<p className="color-grey-6 font-16">测试集</p>*/}
<p className="color-grey-6 font-16">测试集和系统评分规则</p>
<p className="color-grey-6 font-16 height40pxtpm borbottomeeetpm">测试集和系统评分规则</p>
<p className="color-grey-9 mt20"
style={{width:'100%',height:'60px'}}
>
@ -1132,9 +1004,9 @@ export default class TPMevaluation extends Component {
{evaluationlist===undefined?"":evaluationlist.length===0?"":evaluationlist.map((item,key)=>{
return(
<div className="test_array_item mt30" key={key}>
<div className="test_array_item mt30 borbottomeeetpm pb20" key={key}>
<p className="clearfix pr mb20">
<span className="fl mt5 mr10 color-orange">*</span>
<span className="fl mr10 color-red">*</span>
<span className="color-blue font-16 fl" name="sample_inputs_label">{key+1}</span>
<span className="fl ml20 color-grey-6">
{/*checked={item.is_public===1?false:true}*/}
@ -1143,19 +1015,19 @@ export default class TPMevaluation extends Component {
style={{width: '25%',display:scorevalue===true?'inline-block':'none'}}
onInput={(e)=>this.editpercentage(e,key)}
value={item.score} />
<span className="mr15"
<span className="mr15 ml10"
style={{display:scorevalue===true?'inline-block':'none'}}
>%</span>
<Checkbox onChange={()=>this.evaluationonChange(item.hidden,key)} checked={item.hidden===1?true:false}>隐藏</Checkbox>
<Checkbox onChange={()=>this.evaluationonChange(item.hidden,key)} checked={item.hidden===1?true:false}>隐藏<span className={"color-grey-8 font-14"}>选中则对学员隐藏本测试集内容</span></Checkbox>
</span>
<Tooltip placement="bottom" title={"删除"}>
<a className="fr del_array sample_icon_remove mr30" style={{display:key===0?"none":"block"}}
<div className="fr sample_icon_remove " style={{display:key===0?"none":"block"}}
onClick={()=>this.del_test_array(key)}>
<i className="fa fa-times-circle color-grey-c font-16 fl"></i>
</a>
<i className={"iconfont icon-shanchu_Hover font-16 fl"}></i>
</div>
</Tooltip>
</p>
<TextArea className="textareavalue mb15" name="test_set[input][]"
@ -1174,11 +1046,11 @@ export default class TPMevaluation extends Component {
rows={5}
onInput={(e)=>this.evaluationoninputvalue(e,key,"yq")}
></TextArea>
<div className="clearfix lineh-30">
<div className="clearfix lineh-30 mt20">
<span className="fl mr10 color-grey-6">匹配规则</span>
<RadioGroup className="fl" value={item.match_rule} onChange={(e)=>this.changeEvaluationRule(e,key)}>
<Radio value='full'>完全匹配</Radio>
<Radio value='last'>末尾匹配</Radio>
<Radio value='full'>完全匹配<span className={"color-grey-8 font-14"}>实际输出与预期输出完全相同</span></Radio>
<Radio value='last'>末尾匹配<span className={"color-grey-8 font-14"}>实际输出的末尾内容与预期输出完全相同</span></Radio>
</RadioGroup>
</div>
</div>
@ -1189,23 +1061,28 @@ export default class TPMevaluation extends Component {
</div>
<p className="clearfix" onClick={this.addevaluationon}>
<a className="fl edu-default-btn edu-greyline-btn mt20 mb20 sample_icon_add">
新增测试集
</a>
<Button type="primary" ghost className="edu-default-btn edu-greenback-btn mt20 mb20">新增测试集</Button>
</p>
<p className="color-grey-9">温馨提示建议公开测试集和隐藏测试集结合使用降低作弊的几率隐藏测试集提交评测时也将被自动检测</p>
<p className="color-grey-9">温馨提示公开测试集和隐藏测试集结合使用可以降低作弊的几率隐藏测试集提交评测时也将被系统自动检测</p>
</div>
</div>
</div>
<div className="clearfix mt30" style={{display:this.props.identity>4||this.props.identity===undefined||power===false?"none":"block"}}>
<a className="defalutSubmitbtn fl mr20" onClick={this.submitarbitrationevaluation}>提交</a>
<a href={"/shixuns/" + shixunId + "/challenges"} className="defalutCancelbtn fl">取消</a>
</div>
</div>
{this.props.identity>4||this.props.identity===undefined||power===false?"":<div className="clearfix mt30">
{/*<a className="defalutSubmitbtn fl mr20" onClick={this.submitarbitrationevaluation}>提交</a>*/}
{/*/!*<a href={"/shixuns/" + shixunId + "/challenges"} className="defalutCancelbtn fl">取消</a>*!/*/}
{/*<Link to={"/shixuns/" + shixunId + "/challenges"} className="defalutCancelbtn fl">取消</Link>*/}
<Bottomsubmit url={"/shixuns/" + shixunId + "/challenges"}
bottomvalue={"提交"}
onSubmits={this.submitarbitrationevaluation}
{...this.props}
{...this.state}
loadings={false}
/>
</div>}
</React.Fragment>
)
}

@ -212,9 +212,9 @@ export default class TpmQuestionEdit extends Component {
<div className="clearfix mt30" style={{display:this.props.identity>4||this.props.identity===undefined||this.props.power===false?"none":"block"}}>
<a className="defalutSubmitbtn fl mr20"
onClick={()=>this.props.answer_subit()}>提交</a>
<a href={this.props.go_back_url}
className="defalutCancelbtn fl">取消</a>
{/*<a href={this.props.go_back_url}*/}
{/* className="defalutCancelbtn fl">取消</a>*/}
<Link to={this.props.go_back_url} className="defalutCancelbtn fl">取消</Link>
<a onClick={()=>this.delecbtns()}
className="delectshixuncdbtn fr">删除</a>
</div>

@ -69,9 +69,9 @@ export default class TpmQuestionMain extends Component {
style={{display: this.props.identity > 4 || this.props.identity === undefined || this.props.power === false ? "none" : "block"}}>
<a className="defalutSubmitbtn fl mr20"
onClick={this.props.sumittype === true ? "" : this.props.clickquestionsumit}>提交</a>
<a href={this.props.go_back_url}
className="defalutCancelbtn fl">取消</a>
{/*<a href={this.props.go_back_url}*/}
{/* className="defalutCancelbtn fl">取消</a>*/}
<Link to={this.props.go_back_url} className="defalutCancelbtn fl">取消</Link>
</div>
</div>

@ -205,8 +205,10 @@ export default class TpmQuestionNew extends Component {
<div className="clearfix mt30" style={{display:this.props.identity>4||this.props.identity===undefined||this.props.power===false?"none":"block"}}>
<a className="defalutSubmitbtn fl mr20"
onClick={this.props.answer_subit}>提交</a>
<a href={this.props.go_back_url}
className="defalutCancelbtn fl">取消</a>
<Link to={this.props.go_back_url}
className="defalutCancelbtn fl">取消</Link>
{/*<a href={this.props.go_back_url}*/}
{/* className="defalutCancelbtn fl">取消</a>*/}
</div>
</div>

@ -0,0 +1,55 @@
import React, {Component} from 'react';
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
import Loadable from 'react-loadable';
import Loading from "../../../../Loading";
import Bottomsubmit from "../../../modals/Bottomsubmit";
const TPMchallengestask = Loadable({
loader: () => import('../../challengesnew/TPMchallengesnew'),
loading: Loading,
})
export default class TpmTaskIndex extends Component {
constructor(props) {
super(props)
this.state = {
}
}
componentDidMount() {
}
render() {
// console.log(a.indexOf("vnc"))
// console.log(b.indexOf("vnc"))
return (
<div>
<Switch {...this.props}>
{/*新建关卡*/}
<Route path="/shixuns/:shixunId/challenges/new" render={
(props) => (<TPMchallengestask {...this.props} {...props} {...this.state}/>)
}></Route>
{/*编辑关卡*/}
<Route path="/shixuns/:shixunId/challenges/:checkpointId/editcheckpoint" render={
(props) => (<TPMchallengestask {...this.props} {...props} {...this.state} />)
}></Route>
</Switch>
</div>
);
}
}

@ -266,4 +266,66 @@ a{
height: 32px;
line-height: 20px;
font-family: "微软雅黑","宋体";
}
.borderbottomf4{
border-bottom:1px solid #F4F4F4;
}
.TPMchallengesnewtitles{
height: 76px;
line-height: 56px;
padding: 10px 20px;
}
.newpadding1020{
padding: 20px 20px 20px;
box-sizing: border-box;
}
.newpadding02020{
padding: 0px 20px 20px;
}
.mb10 {
margin-bottom: 10px !important;
}
.tpmpointer{
cursor: pointer;
}
.text-centers{text-align:center}
.bor25510211{
width: 1180px;
height: 34px;
border: 1px solid rgba(255,102,1,1);
line-height: 34px;
}
.padding1020tpms{
padding: 10px 20px;
box-sizing: border-box;
}
.bortopeeetpm{
border-top: 1px solid #eee;
}
.borbottomeeetpm {
border-bottom: 1px solid #eee;
}
.height40pxtpm{
height:40px
}
.ml41{
margin-left: 41px;
}
.wind500height45{
width: 500px;
height: 45px;
}
.newaddswermargin{
margin: 0 auto;
}

@ -10,7 +10,7 @@ import { getImageUrl, toPath, getUrl } from 'educoder';
import axios from 'axios';
import './css/TPMchallengesnew.css';
import '../css/TPMchallengesnew.css';
let origin = getUrl();
@ -355,7 +355,8 @@ export default class TPManswer extends Component {
<div className="clearfix mt20" style={{display:this.props.identity>4||this.props.identity===undefined||power===false?"none":"block"}}>
<a className="defalutSubmitbtn fl mr20"
onClick={this.challenge_answer_submit}>提交</a>
<a href={"/shixuns/" + shixunId + "/challenges"} className="defalutCancelbtn fl">取消</a>
{/*<a href={"/shixuns/" + shixunId + "/challenges"} className="defalutCancelbtn fl">取消</a>*/}
<Link to={"/shixuns/" + shixunId + "/challenges"} className={"defalutCancelbtn fl"}>取消</Link>
</div>
</div>
</React.Fragment>

@ -0,0 +1,617 @@
import React, {Component} from 'react';
import {Input, Select, Radio, Checkbox, Popconfirm, message, Modal} from 'antd';
import {BrowserRouter as Router, Route, Link, Switch} from "react-router-dom";
// import "antd/dist/antd.css";
import TPMMDEditor from '../TPMMDEditor';
import axios from 'axios';
import '../css/TPMchallengesnew.css';
import { getImageUrl, toPath } from 'educoder';
import {getUrl} from 'educoder';
let origin = getUrl();
let path = getUrl("/editormd/lib/")
const $ = window.$;
let timeout;
let currentValue;
const Option = Select.Option;
const RadioGroup = Radio.Group;
export default class TPMchallengesnew extends Component {
constructor(props) {
super(props)
this.exercisememoMDRef=React.createRef();
this.state = {
choice_url: undefined,
practice_url: undefined,
go_back_url: undefined,
task_pass_default: undefined,
submit_url: undefined,
shixunCreatePracticeGroup: 1,
optionsums:[100,200],
activetype:0,
setopen: false,
shixunCreatePractice: undefined,
onshixunsmarkvalue: 100,
shixunsskillvalue: undefined,
shixunsskillvaluelist: [],
tab2url: "",
tab3url: "",
prev_challenge:undefined,
next_challenge:undefined,
power: false,
shixunCreatePracticetype: false,
shixunsskillvaluelisttype: false,
marktype:false,
editPracticesendtype:false,
CreatePracticesendtype:false,
exec_time:20,
shixunExec_timeType:false
}
}
componentDidMount() {
let id = this.props.match.params.shixunId;
let checkpointId=this.props.match.params.checkpointId;
let newchoice_url= "/shixuns/"+id+"/challenges/newquestion";
let newpractice_url= "/shixuns/"+id+"/challenges/new";
let newgo_back_url="/shixuns/"+id+"/challenges"
if(checkpointId===undefined){
//新建模式
let url = "/shixuns/" + id + "/challenges/new.json"
axios.get(url).then((response) => {
this.setState({
choice_url: newchoice_url,
practice_url: newpractice_url,
go_back_url: newgo_back_url,
position: response.data.position,
task_pass_default: response.data.task_pass_default,
submit_url: response.data.submit_url,
checkpointId:checkpointId,
exercisememoMDRefval:response.data.task_pass_default
})
this.exercisememoMDRef.current.setValue(response.data.task_pass_default||'')
}).catch((error) => {
console.log(error)
});
}else{
//编辑模式
let url="/shixuns/"+id+"/challenges/"+checkpointId+".json?tab=0";
axios.get(url).then((response) => {
let optionsum;
if(response.data.difficulty===1){
optionsum=[100,200];
}else if(response.data.difficulty===2){
optionsum=[300,400,500,600];
}else if(response.data.difficulty===3){
optionsum=[700,800,900,1000]
}
let newprev_challenge=response.data.prev_challenge;
let next_challenge=response.data.next_challenge;
if (newprev_challenge != undefined) {
if(newprev_challenge.st===0){
newprev_challenge = "/shixuns/" + id + "/challenges/" + newprev_challenge.id + "/editcheckpoint";
}else{
newprev_challenge = "/shixuns/" + id + "/challenges/" + newprev_challenge.id + "/editquestion";
}
}
if (next_challenge != undefined) {
if(next_challenge.st===0){
next_challenge = "/shixuns/" + id + "/challenges/" + next_challenge.id+ "/editcheckpoint";
}else{
next_challenge = "/shixuns/" + id + "/challenges/" + next_challenge.id+ "/editquestion";
}
}
this.setState({
power: response.data.power,
prev_challenge:newprev_challenge,
next_challenge:next_challenge,
choice_url: newchoice_url,
practice_url: newpractice_url,
go_back_url: newgo_back_url,
shixunCreatePractice:response.data.subject,
position:response.data.position,
shixunCreatePracticeGroup:response.data.difficulty,
optionsums:optionsum,
onshixunsmarkvalue:response.data.score,
shixunsskillvaluelist:response.data.tags,
checkpointId:checkpointId,
exec_time:response.data.exec_time,
tab2url: "/shixuns/" + id + "/challenges/"+checkpointId+"/tab=2",
tab3url: "/shixuns/" + id + "/challenges/"+checkpointId+"/tab=3",
exercisememoMDRefval:response.data.task_pass
})
if(response.data.power===false){
this.props.showSnackbar("你没有权限修改");
}
this.exercisememoMDRef.current.setValue(response.data.task_pass||'')
}).catch((error) => {
console.log(error)
});
}
}
onshixunCreatePracticeChange = (e) => {
let optionsum;
let onshixunsmark;
if(e.target.value===1){
optionsum=[100,200];
onshixunsmark=100;
}else if(e.target.value===2){
optionsum=[300,400,500,600];
onshixunsmark=300;
}else if(e.target.value===3){
optionsum=[700,800,900,1000]
onshixunsmark=700;
}
this.setState({
shixunCreatePracticeGroup: e.target.value,
optionsums:optionsum,
onshixunsmarkvalue:onshixunsmark
})
}
shixunCreatePractice = (e) => {
this.setState({
shixunCreatePractice: e.target.value
})
}
CreatePracticesend = () => {
this.setState({
CreatePracticesendtype:true
})
if(this.props.status===2){
this.props.showSnackbar("该实训已经发布不能新建")
this.setState({
CreatePracticesendtype:false
})
return
}
let {shixunCreatePractice, shixunCreatePracticeGroup, onshixunsmarkvalue, shixunsskillvaluelist,exec_time} = this.state;
if (shixunCreatePractice === undefined||shixunCreatePractice=="") {
this.setState({
shixunCreatePracticetype: true
})
this.props.showSnackbar("任务名称为空")
$('html').animate({
scrollTop: 10
}, 1000);
this.setState({
CreatePracticesendtype:false
})
return
}
if (shixunsskillvaluelist.length === 0) {
this.setState({
shixunsskillvaluelisttype: true,
CreatePracticesendtype:false
})
this.props.showSnackbar("技能标签为空")
return
}
if(exec_time===null||exec_time===undefined||exec_time===""){
this.setState({
shixunExec_timeType:false
})
return
}
const exercise_editormdvalue = this.exercisememoMDRef.current.getValue().trim();
let id = this.props.match.params.shixunId;
let url = "/shixuns/" + id + "/challenges.json";
axios.post(url, {
identifier:id,
subject: shixunCreatePractice,
task_pass: exercise_editormdvalue,
difficulty: shixunCreatePracticeGroup,
score: onshixunsmarkvalue,
challenge_tag: shixunsskillvaluelist,
st: 0,
exec_time:exec_time
}).then((response) => {
if (response.data.status === 1) {
// $("html").animate({ scrollTop: 0 })
//window.location.href=`/shixuns/${id}/challenges/${response.data.challenge_id}/editcheckpoint?tab=2`;
window.location.href=`/shixuns/${id}/challenges/${response.data.challenge_id}/tab=2`;
// this.setState({
// setopen: true,
// CreatePracticesendtype:false,
// tab2url: "/shixuns/" + id + "/challenges/"+response.data.challenge_id+"/tab=2",
// tab3url: "/shixuns/" + id + "/challenges/"+response.data.challenge_id+"/tab=3",
// })
}
// this.props.showSnackbar(response.data.messages);
}).catch((error) => {
console.log(error)
});
}
onshixunsmark = (value) => {
this.setState({
onshixunsmarkvalue: value
})
}
shixunsskill = (e) => {
this.setState({
shixunsskillvalue: e.target.value
})
}
clickshixunsskill = () => {
let {shixunsskillvalue, shixunsskillvaluelist} = this.state;
if (shixunsskillvalue === "") {
return
} else if (shixunsskillvalue === undefined) {
return
}
if(shixunsskillvalue == "" || shixunsskillvalue == undefined || shixunsskillvalue == null || (shixunsskillvalue.length>0 && shixunsskillvalue.trim().length == 0)){
message.error("输入为空,不能保存!");
return
}
let list = shixunsskillvaluelist;
list.push(shixunsskillvalue);
this.setState({
shixunsskillvaluelist: list,
shixunsskillvalue: ""
})
}
delshixunsskilllist = (key) => {
let {shixunsskillvaluelist} = this.state;
let newshixunsskillvaluelist = shixunsskillvaluelist;
newshixunsskillvaluelist.splice(key, 1);
this.setState({
shixunsskillvaluelist: newshixunsskillvaluelist
})
}
editPracticesend=()=>{
this.setState({
editPracticesendtype:true
})
let {shixunCreatePractice, shixunCreatePracticeGroup, onshixunsmarkvalue, shixunsskillvaluelist,checkpointId,exec_time} = this.state;
const exercise_editormdvalue = this.exercisememoMDRef.current.getValue().trim();
let id = this.props.match.params.shixunId;
let url = "/shixuns/"+id+"/challenges/"+checkpointId+".json";
if (shixunCreatePractice === undefined||shixunCreatePractice=="") {
// this.setState({
// shixunCreatePracticetype: true
// })
this.props.showSnackbar("任务名称为空")
$('html').animate({
scrollTop: 10
}, 1000);
this.setState({
editPracticesendtype:false
})
return
}
if (shixunsskillvaluelist.length === 0) {
// this.setState({
// shixunsskillvaluelisttype: true
// })
this.props.showSnackbar("技能标签为空")
this.setState({
editPracticesendtype:false
})
return
}
if(exec_time===null||exec_time===undefined||exec_time===""){
this.setState({
shixunExec_timeType:false
})
return
}
axios.put(url, {
tab:0,
identifier:id,
id:checkpointId,
challenge:{
subject: shixunCreatePractice,
task_pass: exercise_editormdvalue,
difficulty: shixunCreatePracticeGroup,
score: onshixunsmarkvalue,
exec_time:exec_time
},
challenge_tag:shixunsskillvaluelist
}).then((response) => {
this.props.showSnackbar(response.data.messages);
if (response.data.status === 1) {
window.location.href=`/shixuns/${id}/challenges/${checkpointId}/tab=2`;
this.setState({
setopen: true,
editPracticesendtype:false,
tab2url: "/shixuns/" + id + "/challenges/"+checkpointId+"/tab=2",
tab3url: "/shixuns/" + id + "/challenges/"+checkpointId+"/tab=3",
})
// window.location.href = "/shixuns/" + id + "/challenges/"+response.data.challenge_id+"/tab=2"
}
}).catch((error) => {
console.log(error)
});
}
onshixunsmarks=()=> {
this.setState({
marktype:true
})
}
onshixunsmarkss=()=> {
this.setState({
marktype:false
})
}
setexec_time=(e)=>{
this.setState({
exec_time:e.target.value
})
}
render() {
let shixuntype = this.props.match.params.type;
let {marktype,
shixunCreatePracticetype, shixunsskillvaluelisttype,
choice_url, practice_url, go_back_url, position, task_pass_default, submit_url, setopen,checkpointId,prev_challenge,next_challenge,power,
shixunCreatePractice, shixunCreatePracticeGroup, onshixunsmarkvalue, shixunsskillvalue, shixunsskillvaluelist, tab2url, tab3url,optionsums,
CreatePracticesendtype,editPracticesendtype
} = this.state;
let options;
if(optionsums!=undefined){
options = optionsums.map((d, k) => {
return (
<Option key={d} id={k}>{d}</Option>
)
})
}
return (
<React.Fragment>
<div className="educontent mt30 mb30">
<div className="padding10-20 mb10 edu-back-white clearfix">
<span className="fl ring-blue mr10 mt7">
<img src={getImageUrl("images/educoder/icon/code.svg")} data-tip-down="实训任务" className="fl mt2 ml2"/>
</span>
<span className="font-16 task-hide fl TPMtaskName">{position}</span>
<Link to={go_back_url === undefined ? "" : go_back_url}
className="color-grey-6 fr font-15 mt3">返回</Link>
{ next_challenge===undefined?"":
<a href={next_challenge}className="fr color-blue mr15 mt4">下一关</a>
}
{ prev_challenge===undefined?"":
<a href={prev_challenge} className="fr color-blue mr15 mt4">上一关</a>
}
<a href={practice_url === undefined ? "" : practice_url}
className="fr color-blue mr15 mt4"
style={{display:this.props.identity>4||this.props.identity===undefined||this.props.status===2||this.props.status===1?"none":'block'}}
data-tip-down="新增代码编辑类型的任务">+&nbsp;实践类型</a>
<a href={choice_url === undefined ? "" : choice_url}
className="fr color-blue mr15 mt4"
style={{display:this.props.identity>4||this.props.identity===undefined||this.props.status===2||this.props.status===1?"none":'block'}}
data-tip-down="新增选择题类型的任务">+&nbsp;选择题类型</a>
</div>
<div className="challenge_nav clearfix edu-back-white">
<li className="active">
<a>本关任务</a>
</li>
<li className="">
{tab2url === "" ? <span>评测设置</span> : <Link to={tab2url}></Link>}
</li>
<li className="">
{tab3url === "" ? <span>参考答案</span> : <Link to={tab3url}></Link>}
</li>
</div>
<div className="edu-back-white mb10 clearfix">
<div className="padding40-20">
<p className="color-grey-6 font-16 mb30">任务名称</p>
<div className="df">
<span className="mr30 color-orange pt10">*</span>
<div className="flex1 mr20">
<input type="text"
// className="input-100-45 greyInput"
className={shixunCreatePracticetype===true?"input-100-45 greyInpus wind100":"input-100-45 greyInput "}
maxLength="50"
name="challenge[subject]"
value={shixunCreatePractice}
onInput={this.shixunCreatePractice}
placeholder="请输入任务名称(此信息将提前展示给学员),例:计算学生的课程成绩绩点"/>
</div>
<div style={{width: '57px'}}>
<span
className={shixunCreatePracticetype === true ? "color-orange mt8 fl block" : "color-orange mt8 fl none"}
id="new_shixun_name"><i
className="fa fa-exclamation-circle mr3"></i></span>
</div>
</div>
</div>
</div>
<div className="edu-back-white padding40-20 mb20">
<p className="color-grey-6 font-16 mb30">过关任务</p>
<TPMMDEditor ref={this.exercisememoMDRef} placeholder="请输入选择题的题干内容" mdID={'exercisememoMD'} refreshTimeout={1500}
watch={true} className="courseMessageMD" initValue={this.state.exercisememoMDRefval} height={700}></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>
</div>
<div className="edu-back-white padding40-20 mb20">
<p className="color-grey-6 font-16 mb30">难度系数</p>
<div className="clearfix mb40">
<RadioGroup value={shixunCreatePracticeGroup} className="fl mr40"
disabled={this.props.status===2?true:false}
onChange={this.props.status===2?"":this.onshixunCreatePracticeChange}>
<Radio value={1}>简单</Radio>
<Radio value={2}>中等</Radio>
<Radio value={3}>困难</Radio>
</RadioGroup>
</div>
<p className="color-grey-6 font-16 mb30">奖励经验值</p>
<div className="clearfix"
// onMouseLeave={this.props.status===2?"":this.onshixunsmarkss}
>
<span className="fl mr30 color-orange pt10">*</span>
<Select style={{width: 120}} className="winput-240-40 fl"
id="challenge_score"
onChange={this.props.status===2?"":this.onshixunsmark}
// onMouseEnter={this.props.status===2?"":this.onshixunsmarks}
disabled={this.props.status===2?true:false}
// open={marktype}
value={onshixunsmarkvalue}
getPopupContainer={triggerNode => triggerNode.parentNode}
>
{options}
</Select>
<p className="fl color-grey-9 font-12 ml20">
如果学员答题错误则不能得到相应的经验值<br/>
如果学员成功得到经验值那么将同时获得等值的金币奖励+10经验值+10金币
</p>
<span className="color-orange mt7 fl ml20 none" id="ex_value_notice"><i
className="fa fa-exclamation-circle mr3"></i></span>
</div>
</div>
<div className="edu-back-white padding40-20 mb20">
<p className="color-grey-6 font-16 mb30">技能标签</p>
<div className="clearfix df">
<span className="mr30 color-orange pt10">*</span>
<div className="flex1">
<Input type="text"
className="winput-240-40 fl mr20 winput-240-40s"
id="input_task_tag"
placeholder="添加标签"
onInput={this.shixunsskill}
value={shixunsskillvalue}
onPressEnter={this.clickshixunsskill}
onBlur={this.clickshixunsskill}
/>
{/*<a className="white-btn orange-btn fl mt1 use_scope-btn ml20 mt5 mr20"*/}
{/*onClick={this.clickshixunsskill}>+ 添加</a>*/}
<div className="ml15 color-grey-9 mt5">学员答题正确将获得技能否则不能获得技能</div>
<div className="mt20 clearfix" id="task_tag_content">
{
shixunsskillvaluelist===undefined?"":shixunsskillvaluelist.length === 0 ? "" : shixunsskillvaluelist.map((itme, key) => {
return (
<li className="task_tag_span" key={key}><span>{itme}</span>
<a onClick={() => this.delshixunsskilllist(key)}>×</a>
</li>
)
})
}
</div>
</div>
<span
className={shixunsskillvaluelisttype === true ? "color-orange mt7 fl ml20 block" : " color-orange mt7 fl ml20 none"}
id="stage_name_notice">
<i className="fa fa-exclamation-circle mr3"></i></span>
</div>
</div>
<div className="edu-back-white padding40-20 mb20">
<p className="color-grey-6 font-16 mb30">服务配置</p>
<div className="clearfix mb5">
<span className="color-orange pt10 fl">*</span>
<label className="panel-form-label fl">评测时限(S)</label>
<div className="pr fl with80 status_con">
<input value={this.state.exec_time} className="panel-box-sizing task-form-100 task-height-40" placeholder="请输入类别名称" onInput={this.setexec_time}/>
</div>
<span
className={this.state.shixunExec_timeType === true ? "color-orange mt8 fl block ml20" : "color-orange mt8 fl none"}
id="new_shixun_name"><i className="fa fa-exclamation-circle mr3"></i></span>
<div className="cl"></div>
</div>
</div>
<div className="clearfix mt30"
style={{display:this.props.identity>4||this.props.identity===undefined?"none":'block'}}
>
{checkpointId===undefined?<a className="defalutSubmitbtn fl mr20" onClick={CreatePracticesendtype===true?"":this.CreatePracticesend}>提交</a>:
<a className="defalutSubmitbtn fl mr20" onClick={editPracticesendtype===true?"":this.editPracticesend}>提交</a>}
{/*<a href={go_back_url === undefined ? "" : go_back_url} className="defalutCancelbtn fl">取消</a>*/}
<Link to={go_back_url === undefined ? "" : go_back_url} className={"defalutCancelbtn fl"}>取消</Link>
</div>
</div>
</React.Fragment>
)
}
}

@ -77,6 +77,15 @@ function JupyterTPI (props) {
const emptyCtx = (
<div className="jupyter_empty">
<style>
{ `
.ant-empty{
margin-top:80px;
color:#fff;
}
`
}
</style>
<Empty />
</div>
);
@ -88,6 +97,15 @@ function JupyterTPI (props) {
const [myIdentifier, setMyIdentifier] = useState('');
const [renderCtx, setRenderCtx] = useState(() => (emptyCtx));
let newHandletype=false
const newHandle = function (event) {
if(newHandletype===false){
newHandletype=true
saveJupyterTpi(event);
setTimeout(()=>{newHandletype=false},500)
}
}
// 保存代码
const addEventListeners = () => {
window.addEventListener('message', (e) => {
@ -95,12 +113,10 @@ function JupyterTPI (props) {
if(e){
if(e.data){
if(e.data==="jupytermessage"){
saveJupyterTpi();
newHandle()
}
}
}
})
}
@ -152,8 +168,7 @@ function JupyterTPI (props) {
title: '更新通知',
content: (<div className="update_notice">
{stopposttpip(1)}
<p className="update_txt">该实训已更新更新后您编写的实训代码将会丢失</p>
<p className="update_txt">如有需要请先导出代码再进行更新</p>
<p className="update_txt">该实训已更新您选择更新后之前编写的实训代码将会丢失如有需要请先使用jupyter中-文件-下载保存代码再进行更新</p>
{/*<p className="update_txt">还未完成评测的任务代码,请自行保存</p>*/}
</div>),
okText: '立即更新',
@ -172,6 +187,7 @@ function JupyterTPI (props) {
// 重置实训
const handleClickResetTpi = () => {
stopposttpip(1)
updataspinning(true)
Modal.confirm({
title: '重置实训',
content: (
@ -190,6 +206,7 @@ function JupyterTPI (props) {
},
onCancel() {
stopposttpip(2)
updataspinning(false)
},
})
}
@ -203,7 +220,6 @@ function JupyterTPI (props) {
title: '重置环境',
content: (
<p style={{ lineHeight: '24px' }}>
你在本文件中修改的内容将丢失,<br />
是否确定重置环境
</p>
),
@ -261,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}`}>
@ -294,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>
);
@ -308,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, '重置成功');
}
})
}
@ -332,12 +355,12 @@ function JupyterTPI (props) {
</p>
<p className="jupyter_btn">
{/*sync | poweroff */}
{/*<Button*/}
{/* className="btn_common"*/}
{/* type="link"*/}
{/* icon="history"*/}
{/* onClick={handleClickResetTpi}*/}
{/*>重置实训</Button>*/}
<Button
className="btn_common"
type="link"
icon="history"
onClick={handleClickResetTpi}
>重置实训</Button>
<Button
className="btn_common"
@ -393,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 maxnamewidth200 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;
}
@ -215,13 +221,13 @@ line-height: 50px !important;
background: #070F1A !important;
}
.maxnamewidth200{
max-width: 200px;
.maxnamewidth186JUPYTER{
max-width: 186px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
cursor: default;
width: 200px;
width: 186px;
}
.maxnamewidth181{
@ -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('重置实训成功!');
}
});
}
@ -360,11 +401,10 @@ class Challengesjupyter extends Component {
let id=this.props.match.params.shixunId;
let that=this;
Modal.confirm({
title: '重置实训',
title: '重置环境',
content: (
<p style={{ lineHeight: '24px' }}>
你在本文件中修改的内容将丢失,<br />
是否确定重新加载初始代码
是否确定重置环境
</p>
),
okText: '确定',
@ -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;
@ -424,7 +481,34 @@ class Challengesjupyter extends Component {
};
return (
<React.Fragment>
<div className="">
<div >
<style>
{
`
.ant-notification{
position: fixed !important;
z-index: 3000 !important;
}
.ant-modal-wrap {
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>
@ -488,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 "}>
@ -541,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?
@ -579,7 +692,7 @@ class Challengesjupyter extends Component {
<p className="challenbaocuntest" type="upload" >导入</p>
</div>
</Upload>
{/*<button type="button" className="ant-btn deletebuttom chongzhistyles" onClick={this.handleClickResetTpi}><span>重置环境</span></button>*/}
<button type="button" className="ant-btn deletebuttom chongzhistyles" onClick={this.handleClickResetTpi}><span>重置环境</span></button>
</div>
@ -624,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>
@ -648,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>*/}
{/* :""*/}
{/* )*/}
{/* :""*/}
{/*}*/}

@ -198,7 +198,7 @@
position: fixed;
top: 0px;
left: 0px;
z-index: 999999;
z-index: 2800;
right: 0px;
}
@ -210,10 +210,14 @@
margin-top: 63px;
bottom: 0px;
left: 0px;
z-index: 999999;
z-index: 2800;
right: 0px;
}
.fangdatwoswidth{
border-top: 1px solid #eeee;
}
.jupyterswidth{
width: 1140px;
}

@ -127,3 +127,14 @@
background: #FFFFFF;
}
.file_path_input{
position: absolute;
right: -50%;
}
.questiontype:hover{
color: #4CACFF !important;
}
.questiontype:active{
color: #4CACFF !important;
}

@ -56,7 +56,8 @@ const types = {
CLEAR_OJ_FOR_USER_REDUCER: 'CLEAR_OJ_FOR_USER_REDUCER', // 退出时清空 ojForUserReducer保存内容
ADD_OJ_LIKE_COUNT: 'ADD_OJ_LIKE_COUNT', // 增加点赞数
CHANGE_RECORD_PAGINATION_PAGE: 'CHANGE_RECORD_PAGINATION_PAGE', // 改变提交分页
UPDATE_OJ_FOR_USER_COMMENT_COUNT: 'UPDATE_OJ_FOR_USER_COMMENT_COUNT', // 更新 hack 中的评论数
UPDATE_OJ_FOR_USER_COMMENT_COUNT: 'UPDATE_OJ_FOR_USER_COMMENT_COUNT', // 更新 hack 中的评论数,
UPDATE_NOTE_CONTENT: 'UPDATE_NOTE_CONTENT', // 更新笔记内容
/*** jupyter */
GET_JUPYTER_DATA_SETS: 'GET_JUPYTER_DATA_SETS', // jupyter 数据集
GET_JUPYTER_TPI_URL: 'GET_JUPYTER_TPI_URL', // 获取 jupyter url

@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-12-23 10:53:25
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-25 17:06:57
* @LastEditTime : 2019-12-27 11:07:02
*/
import types from "./actionTypes";
@ -42,7 +42,7 @@ export const getCommentLists = (identifier) => {
limit,
page
}).then(res => {
console.log('获取评论列表: ====>>>>', res);
// console.log('获取评论列表: ====>>>>', res);
if (res.status === 200) {
const {data} = res;
dispatch({

@ -50,7 +50,8 @@ import {
saveEditorCodeForDetail,
saveOpacityType,
clearOjForUserReducer,
changeRecordPagination
changeRecordPagination,
addNotes
// isUpdateCodeCtx
} from './ojForUser';
@ -137,6 +138,7 @@ export default {
saveOpacityType,
clearOjForUserReducer,
changeRecordPagination,
addNotes,
// jupyter
getJupyterTpiDataSet,
getJupyterTpiUrl,

@ -7,7 +7,7 @@
* @LastEditTime: 2019-12-13 23:03:27
*/
import types from "./actionTypes";
import { message } from 'antd';
import { message ,Modal} from 'antd';
import {
fetchJupyterTpiDataSet,
fetchJupyterTpiUrl,
@ -15,7 +15,8 @@ import {
fetchSyncJupyterCode,
fetchreset_with_tpi,
fetchSaveJupyterTpi,
fetactive_with_tpi
fetactive_with_tpi,
timeinfo_with_tpis
} from "../../services/jupyterServer";
// 获取 jupyter 相关信息
@ -76,7 +77,9 @@ export const getJupyterTpiUrl = (obj) => {
console.log('获取url', res);
if (res.status === 200) {
const { status, url = '', port } = res.data;
addjypertime(Date.now() +3600 * 1000)
dispatch(updataspinning(false))
//setTimeout(()=>{ dispatch(addjypertime(Date.now() +3600 * 1000))},500)
timeinfo_with_tpi(id,dispatch)
dispatch({
type: types.GET_JUPYTER_TPI_URL,
payload: {
@ -106,7 +109,7 @@ export const syncJupyterCode = (identifier, msg) => {
const {status} = res.data
if (status === 0) {
message.success(msg);
updataspinning(false)
dispatch(updataspinning(false))
setTimeout(() => {
window.location.reload();
}, 300);
@ -131,7 +134,7 @@ export const reset_with_tpi = (identifier, msg) => {
const {status} = res.data
if (status === 0) {
message.success(msg);
updataspinning(false)
dispatch(updataspinning(false))
setTimeout(() => {
window.location.reload();
}, 300);
@ -156,7 +159,7 @@ export const active_with_tpi = (identifier, msg) => {
const {status} = res.data
if (status === 0) {
message.success(msg);
addjypertime(Date.now() + 900 * 1000);
dispatch(addjypertime(Date.now() + 900 * 1000))
}
}
})
@ -171,6 +174,7 @@ export const changeGetJupyterUrlState = (status) => {
payload: status
}
}
// 保存 jupyter tpi
export const saveJupyterTpi = () => {
return (dispatch, getState) => {
@ -234,3 +238,34 @@ export const updataspinning=(type)=>{
}
}
// 获取重置实训后的时间
export const timeinfo_with_tpi = (identifier, dispatch) => {
const params = {
identifier: identifier
};
timeinfo_with_tpis(params).then(res => {
if (res.data.status === 401) return;
if (res.status === 200) {
if(res.data.status===0){
if(res.data.useSeconds===null){
Modal.confirm({
title: '重置环境',
content:" 是否确定重置环境?" ,
okText: '确定',
cancelText: '取消',
onOk () {
reset_with_tpi(identifier, '重置成功');
},
onCancel() {}
})
}else{
let useSeconds=res.data.useSeconds;
let summain=3600 * 1000;
let sums= useSeconds * 1000;
let sum=summain-sums;
setTimeout(()=>{ dispatch(addjypertime(Date.now() +sum))},500);
}
}
}
})
}

@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-11-27 13:42:11
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-25 14:27:58
* @LastEditTime : 2019-12-27 11:06:09
*/
import types from "./actionTypes";
import { Base64 } from 'js-base64';
@ -17,7 +17,8 @@ import {
fetchUserCommitRecordDetail,
fetchUpdateCode,
fetchUserCodeSubmit,
fetchRestoreInitialCode
fetchRestoreInitialCode,
fetchAddNotes
} from "../../services/ojService";
import { notification } from "antd";
@ -107,25 +108,31 @@ export const getUserProgramDetail = (identifier, type) => {
}
export const saveUserCodeForInterval = (identifier, code) => {
return (dispatch) => {
return (dispatch, getState) => {
const { userCode } = getState().ojForUserReducer;
dispatch({
type: types.AUTO_UPDATE_CODE,
payload: true
});
// console.log('+++', userCode);
fetchUpdateCode(identifier, {
code: Base64.encode(code)
code: userCode
}).then(res => {
if (res.data.status === 401) {
return;
};
dispatch({
type: types.RESTORE_INITIAL_CODE,
payload: userCode
});
setTimeout(() => {
dispatch({
type: types.AUTO_UPDATE_CODE,
payload: false
})
}, 1000);
console.log('代码保存成功', res);
// console.log('代码保存成功', res);
}).catch(() => {
dispatch({
type: types.AUTO_UPDATE_CODE,
@ -488,3 +495,33 @@ export const changeRecordPagination = (page) => {
}
}
// 更新通知状态
// 添加笔记
export const addNotes = (identifier, params, cb) => {
return (dispatch) => {
fetchAddNotes(identifier, params).then(res => {
// console.log('添加笔记成功===>>', res);
dispatch({
type: types.LOADING_STATUS,
payload: false
});
const { data } = res;
if (data.status === 0) {
cb && cb();
notification.success({
message: '提示',
description: '添加笔记成功'
});
dispatch({
type: types.UPDATE_NOTE_CONTENT,
payload: params.notes
})
}
}).catch(() => {
dispatch({
type: types.LOADING_STATUS,
payload: false
});
})
}
}

@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-11-20 16:35:46
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-26 15:45:28
* @LastEditTime : 2019-12-27 22:19:15
*/
import types from './actionTypes';
import CONST from '../../constants';
@ -17,6 +17,7 @@ import {
import { Base64 } from 'js-base64';
import { notification } from 'antd';
import { toStore } from 'educoder';
// import { startProgramQuestion } from ''
const { jcLabel } = CONST;
// 表单字段映射
const maps = {
@ -99,7 +100,7 @@ const payloadInfo = (key, value, errMsg, validateInfo) => ({
// }
// 表单提交验证
export const validateOjForm = (props, type) => {
export const validateOjForm = (props, type, cb) => {
return (dispatch, getState) => {
const {ojForm, testCases, identifier, code } = getState().ojFormReducer;
// console.log('code', code);
@ -247,66 +248,141 @@ export const validateOjForm = (props, type) => {
paramsObj['identifier'] = identifier;
}
// 调用保存或更新
if (type === 'publish') {
// 提示发布信息
publishTask(identifier).then(res => {
dispatch({
type: types.PUBLISH_LOADING_STATUS,
payload: false
});
// 先调用保存接口
fetchPostOjForm(paramsObj).then(res => {
if (res.status === 200) { // 保存成功后,重新跳转至列表页
if (res.data.status === 0) {
// message.success('发布成功!');
notification.success({
message: '提示',
description: '发布成功!'
});
// linkToDev(dispatch, props);
// 改变发布状态值 0 => 1
// 改变按钮loading状态
dispatch({
type: types.CHANGE_PUBLISH_VALUE,
payload: 1
type: types.SUBMIT_LOADING_STATUS,
payload: false
});
}
}).catch(() => {
dispatch({
type: types.PUBLISH_LOADING_STATUS,
payload: false
});
});
} else {
// 调用更新
fetchPostOjForm(paramsObj).then(res => {
if (res.status === 200) { // 保存成功后,重新跳转至列表页
if (res.data.status === 0) {
// 改变按钮loading状态
dispatch({
type: types.SUBMIT_LOADING_STATUS,
payload: false
if (type === 'publish') {
publishTask(identifier).then(res => {
dispatch({
type: types.PUBLISH_LOADING_STATUS,
payload: false
});
if (res.data.status === 0) {
// message.success('发布成功!');
notification.success({
message: '提示',
description: '发布成功!'
});
// linkToDev(dispatch, props);
// 改变发布状态值 0 => 1
dispatch({
type: types.CHANGE_PUBLISH_VALUE,
payload: 1
});
}
}).catch(() => {
dispatch({
type: types.PUBLISH_LOADING_STATUS,
payload: false
});
});
} 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
});
// 保存或更新后调用start接口
// linkToDev(dispatch, props);
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`);
};
}
}}
).catch(err => {
dispatch({
type: types.SUBMIT_LOADING_STATUS,
payload: false
});
// 保存或更新后调用start接口
// linkToDev(dispatch, props);
}
}}
).catch(err => {
dispatch({
type: types.SUBMIT_LOADING_STATUS,
payload: false
});
}
dispatch({
type: types.PUBLISH_LOADING_STATUS,
payload: false
});
});
// 调用保存或更新
// if (type === 'publish') {
// // 提示发布信息
// publishTask(identifier).then(res => {
// dispatch({
// type: types.PUBLISH_LOADING_STATUS,
// payload: false
// });
// if (res.data.status === 0) {
// // message.success('发布成功!');
// notification.success({
// message: '提示',
// description: '发布成功!'
// });
// // linkToDev(dispatch, props);
// // 改变发布状态值 0 => 1
// dispatch({
// type: types.CHANGE_PUBLISH_VALUE,
// payload: 1
// });
// }
// }).catch(() => {
// dispatch({
// type: types.PUBLISH_LOADING_STATUS,
// payload: false
// });
// });
// } else {
// // 调用更新
// fetchPostOjForm(paramsObj).then(res => {
// if (res.status === 200) { // 保存成功后,重新跳转至列表页
// if (res.data.status === 0) {
// // 改变按钮loading状态
// dispatch({
// type: types.SUBMIT_LOADING_STATUS,
// payload: false
// });
// // 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
// });
// // 保存或更新后调用start接口
// // linkToDev(dispatch, props);
// }
// }}
// ).catch(err => {
// dispatch({
// type: types.SUBMIT_LOADING_STATUS,
// payload: false
// });
// });
// }
}
}
};
@ -434,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

@ -16,7 +16,7 @@ const initialState = {
publishLoading: false, // 发布
isMySource: false,
drawervisible:false,
jupytertime:Date.now() + 3600 * 1000,
jupytertime:0,
spinning:false
}

@ -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-26 13:39:41
* @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;
@ -94,11 +95,10 @@ const ojForUserReducer = (state = initialState, action) => {
}
case types.SAVE_USER_CODE:
let curCode = Base64.encode(action.payload);
return {
...state,
userCode: curCode,
isUpdateCode: true
isUpdateCode: true,
}
case types.IS_UPDATE_CODE:
return {
@ -133,11 +133,14 @@ const ojForUserReducer = (state = initialState, action) => {
let restoreCode = action.payload
if (restoreCode) {
curHack['code'] = Base64.decode(restoreCode);
} else {
curHack['code'] = '';
}
console.log('当前的代码内容:', curHack);
console.log(curHack);
return {
...state,
hack: Object.assign({}, curHack)
hack: Object.assign({}, state.hack, curHack),
editor_code: curHack['code']
}
case types.SAVE_HACK_IDENTIFIER:
return {
@ -178,7 +181,7 @@ const ojForUserReducer = (state = initialState, action) => {
commitTestRecordDetail: {}, // 调试代码执行结果
commitRecordDetail: {}, // 提交成功后记录提交的详情
commitRecord: [], // 提交记录
userCode: '', // 保存当前用户输入的代码
// userCode: '', // 保存当前用户输入的代码
isUpdateCode: false, // 是否更新了代码内容
userCodeTab: 'task', // 学员测评tab位置: task | record | comment
userTestInput: '', // 用户自定义输入值
@ -218,6 +221,13 @@ const ojForUserReducer = (state = initialState, action) => {
...state,
hack: Object.assign({}, state.hack, { comments_count: _comments_count })
}
// 修改笔记内容
case types.UPDATE_NOTE_CONTENT:
const _hack1 = Object.assign({}, state.hack, {notes: action.payload });
return {
...state,
hack: _hack1
}
default:
return state;
}

@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-11-20 16:40:32
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-23 10:12:59
* @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(测试完成)
@ -174,10 +175,16 @@ const ojFormReducer = (state = initialState, action) => {
* 7. 添加测试用例验证
*/
const { code = '', description, language, name, hack_sets = [], time_limit, difficult, category, status } = action.payload;
let desc = null;
try {
desc = JSON.parse(description)
} catch (error) {
desc = description;
}
const currentOjForm = {
name, // 任务名称
language,
description: JSON.parse(description),
description: desc,
difficult,
category,
openOrNot: 1,
@ -210,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,16 +137,21 @@ class SearchPage extends Component{
margin-right: 4px;
font-size: 16px !important;
}
.shixundetailtopcss{
}
`}</style>
<div className="headersear" >
<div style={{height:"53px"}}></div>
<Search
style={{ width: "800px", marginTop:"53px"}}
className="packinput"
value={this.state.keywords}
enterButton={<span><Icon type="search" className="mr5"/> 搜索</span>}
onInput={(e)=>this.setdatafunsval(e)}
onSearch={ (value)=>this.setdatafuns(value)} />
<div className="shixunDetail_top shixundetailtopcss" >
{/*<div style={{height:"53px"}}></div>*/}
<div className="intermediatecenter" style={{ width: "100%"}}>
<Search
style={{ width: "800px", marginTop:"53px"}}
className="packinput"
value={this.state.keywords}
enterButton={<span><Icon type="search" className="mr5"/> 搜索</span>}
onInput={(e)=>this.setdatafunsval(e)}
onSearch={ (value)=>this.setdatafuns(value)} />
</div>
</div>
<div className="tabtitle">

@ -3,8 +3,6 @@
margin-top: 53px;
}
.headersear{
height: 160px;
background: #EAF2F9;
display: flex;
justify-content: center;
}
@ -15,6 +13,12 @@
/*color: #681616 !important;*/
border-color: #E1EDF8 !important;
}
.intermediatecenter{
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.packinput .ant-input-group-addon .ant-btn{
width:137px !important;
@ -174,3 +178,10 @@
.ml9{
margin-left: 9px;
}
.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;
}

@ -44,4 +44,11 @@ export async function fetchreset_with_tpi (params) {
export async function fetactive_with_tpi(params) {
const url = `/jupyters/active_with_tpi.json`;
return axios.get(url, { params });
}
//获取tpi重置实训的time
export async function timeinfo_with_tpis(params){
const url = `/jupyters/timeinfo_with_tpi.json`;
return axios.get(url, { params });
}

@ -4,13 +4,13 @@
* @Github:
* @Date: 2019-11-20 10:55:38
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-25 14:27:30
* @LastEditTime : 2019-12-27 11:06:27
*/
import axios from 'axios';
export async function fetchOJList (params) {
console.log('传递的参数: ', params);
// console.log('传递的参数: ', params);
const obj = {};
Object.keys(params).forEach(key => {
if (params[key]) {
@ -137,3 +137,9 @@ export async function fetchUploadImageUrl (id) {
const url = `/attachments/${id}`;
return axios.get(url);
}
// 添加笔记
export async function fetchAddNotes (identifier, params) {
const url = `/myproblems/${identifier}/add_notes.json`;
return axios.post(url, params);
}

@ -401,9 +401,9 @@ label.infolabel{display: block;float: left;width: 56px;text-align: right;margin-
.task-colspan{min-width:25%;text-align: left;display: block;float: left;color: #999; }
.colspan-grey{border-radius: 12px;background-color: #E6E6E6;padding: 3px 10px;color: #747A7F}
/*新建任务*/
.challenge_nav{padding: 40px 20px 0px 20px;border-bottom: 1px solid #eee;}
.challenge_nav li{width: auto;float: left;margin-right: 40px;position: relative}
.challenge_nav li.active:after{position: absolute;content: '';width: 50%;background-color: #4CACFF;height: 3px;border-radius: 2px;left: 25%;bottom: 0px;}
.challenge_nav{padding: 20px 20px 0px 20px;border-bottom: 1px solid #eee;}
.challenge_nav li{width: auto;float: left;margin-right: 20px;position: relative}
.challenge_nav li.active:after{position: absolute;content: '';width:76%;background-color: #4CACFF;height: 3px;border-radius: 2px;left: 25%;bottom: 0px;}
.challenge_nav li a{display: block;width: 100%;padding-bottom: 20px;}
.add_choose_type{width: 60px;height: 20px;line-height: 19px;border-radius: 2px;background-color: #eaeaea;color: #999!important;display: block;float: left;text-align: center;margin-top: 4px;}
@ -528,7 +528,7 @@ li.li-width15{width: 15%;text-align: left}
li.li-width7{width: 7%;text-align: left}
/*-----------------------------在线课堂动态----------------------------------*/
.courseHead{width: 100%;margin-bottom:40px;background-size: 100% 100%;background-image: url("/images/educoder/course-detail.jpg");height: 240px;
.courseHead{width: 100%;margin-bottom:40px;background-size: 100% 100%;background-image: url("/images/educoder/courtailsbdpicture.jpg");height: 240px;
justify-content: center;align-items: center;display: -webkit-flex;
background-size: cover;
background-position: center;
@ -3803,4 +3803,17 @@ a.singlepublishtwo{
.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;
}

@ -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;
}

@ -1242,6 +1242,12 @@
<div class="code-name">&amp;#xe6c8;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe70f;</span>
<div class="name">减号</div>
<div class="code-name">&amp;#xe70f;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe60f;</span>
<div class="name">工程</div>
@ -1758,6 +1764,54 @@
<div class="code-name">&amp;#xe6d9;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe701;</span>
<div class="name">缩小</div>
<div class="code-name">&amp;#xe701;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe707;</span>
<div class="name">放大</div>
<div class="code-name">&amp;#xe707;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe709;</span>
<div class="name">编辑</div>
<div class="code-name">&amp;#xe709;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe70b;</span>
<div class="name">公开</div>
<div class="code-name">&amp;#xe70b;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe70c;</span>
<div class="name">解析</div>
<div class="code-name">&amp;#xe70c;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe70d;</span>
<div class="name">删除</div>
<div class="code-name">&amp;#xe70d;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe70e;</span>
<div class="name">试题栏</div>
<div class="code-name">&amp;#xe70e;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe710;</span>
<div class="name">复制</div>
<div class="code-name">&amp;#xe710;</div>
</li>
</ul>
<div class="article markdown">
<h2 id="unicode-">Unicode 引用</h2>
@ -3626,6 +3680,15 @@
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-jianhao"></span>
<div class="name">
减号
</div>
<div class="code-name">.icon-jianhao
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-gongcheng"></span>
<div class="name">
@ -4400,6 +4463,78 @@
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-suoxiao2"></span>
<div class="name">
缩小
</div>
<div class="code-name">.icon-suoxiao2
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-fangda"></span>
<div class="name">
放大
</div>
<div class="code-name">.icon-fangda
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-bianji2"></span>
<div class="name">
编辑
</div>
<div class="code-name">.icon-bianji2
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-gongkai"></span>
<div class="name">
公开
</div>
<div class="code-name">.icon-gongkai
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-jiexi"></span>
<div class="name">
解析
</div>
<div class="code-name">.icon-jiexi
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-shanchu1"></span>
<div class="name">
删除
</div>
<div class="code-name">.icon-shanchu1
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-shitilan"></span>
<div class="name">
试题栏
</div>
<div class="code-name">.icon-shitilan
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-fuzhi3"></span>
<div class="name">
复制
</div>
<div class="code-name">.icon-fuzhi3
</div>
</li>
</ul>
<div class="article markdown">
<h2 id="font-class-">font-class 引用</h2>
@ -6045,6 +6180,14 @@
<div class="code-name">#icon-pinglun</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-jianhao"></use>
</svg>
<div class="name">减号</div>
<div class="code-name">#icon-jianhao</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-gongcheng"></use>
@ -6733,6 +6876,70 @@
<div class="code-name">#icon-zhiding</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-suoxiao2"></use>
</svg>
<div class="name">缩小</div>
<div class="code-name">#icon-suoxiao2</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-fangda"></use>
</svg>
<div class="name">放大</div>
<div class="code-name">#icon-fangda</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-bianji2"></use>
</svg>
<div class="name">编辑</div>
<div class="code-name">#icon-bianji2</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-gongkai"></use>
</svg>
<div class="name">公开</div>
<div class="code-name">#icon-gongkai</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-jiexi"></use>
</svg>
<div class="name">解析</div>
<div class="code-name">#icon-jiexi</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-shanchu1"></use>
</svg>
<div class="name">删除</div>
<div class="code-name">#icon-shanchu1</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-shitilan"></use>
</svg>
<div class="name">试题栏</div>
<div class="code-name">#icon-shitilan</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-fuzhi3"></use>
</svg>
<div class="name">复制</div>
<div class="code-name">#icon-fuzhi3</div>
</li>
</ul>
<div class="article markdown">
<h2 id="symbol-">Symbol 引用</h2>

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save