Merge branches 'dev_aliyun' and 'dev_aliyun2' of https://bdgit.educoder.net/Hjqreturn/educoder into dev_aliyun2

dev_aliyun2
杨树明 5 years ago
commit 8eef510ceb

@ -18,7 +18,7 @@ class Admins::ShixunSettingsController < Admins::BaseController
task_pass: params[:task_pass].present? ? params[:task_pass] : false, task_pass: params[:task_pass].present? ? params[:task_pass] : false,
code_hidden: params[:code_hidden].present? ? params[:code_hidden] : false, code_hidden: params[:code_hidden].present? ? params[:code_hidden] : false,
vip: params[:vip].present? ? params[:vip] : false, vip: params[:vip].present? ? params[:vip] : false,
no_subject: params[:no_subject].present? ? params[:no_subject] : false is_wechat_support: params[:is_wechat_support].present? ? params[:is_wechat_support] : false
} }
@shixuns_type_check = MirrorRepository.pluck(:type_name,:id) @shixuns_type_check = MirrorRepository.pluck(:type_name,:id)
@ -135,6 +135,6 @@ class Admins::ShixunSettingsController < Admins::BaseController
def setting_params def setting_params
params.permit(:use_scope,:excute_time,:close,:status,:can_copy,:webssh,:hidden,:homepage_show,:task_pass, params.permit(:use_scope,:excute_time,:close,:status,:can_copy,:webssh,:hidden,:homepage_show,:task_pass,
:code_hidden,:vip,:page_no,:id, :no_subject) :code_hidden,:vip,:page_no,:id, :is_wechat_support, tag_repertoires:[])
end end
end end

@ -1242,7 +1242,7 @@ class ExercisesController < ApplicationController
normal_status(0, "正在下载中") normal_status(0, "正在下载中")
else else
set_export_cookies set_export_cookies
render exam_pdf: 'exercise_export/blank_exercise', filename: filename_, stylesheets: stylesheets, disposition: 'inline', type: "pdf_attachment.content_type", stream: false render pdf: 'exercise_export/blank_exercise', filename: filename_, stylesheets: stylesheets, disposition: 'inline', type: "pdf_attachment.content_type", stream: false
end end
end end

@ -924,7 +924,7 @@ class HomeworkCommonsController < ApplicationController
def publish_homework def publish_homework
tip_exception("请至少选择一个分班") if params[:group_ids].blank? && @course.course_groups.size != 0 tip_exception("请至少选择一个分班") if params[:group_ids].blank? && @course.course_groups.size != 0
group_ids = params[:group_ids]&.reject(&:blank?)&.map(&:to_i) group_ids = params[:group_ids]&.reject(&:blank?).map(&:to_i)
if params[:detail].blank? if params[:detail].blank?
tip_exception("缺少截止时间参数") if params[:end_time].blank? tip_exception("缺少截止时间参数") if params[:end_time].blank?
tip_exception("截止时间不能早于当前时间") if params[:end_time] <= strf_time(Time.now) tip_exception("截止时间不能早于当前时间") if params[:end_time] <= strf_time(Time.now)
@ -1070,7 +1070,7 @@ class HomeworkCommonsController < ApplicationController
homeworks = homeworks.published_no_end.includes(:homework_group_settings, :homework_detail_manual, :homework_challenge_settings) homeworks = homeworks.published_no_end.includes(:homework_group_settings, :homework_detail_manual, :homework_challenge_settings)
course_students = @course.students course_students = @course.students
charge_group_ids = @course.charge_group_ids(current_user) charge_group_ids = @course.charge_group_ids(current_user)
group_ids = params[:group_ids]&.reject(&:blank?)&.map(&:to_i) group_ids = params[:group_ids]&.reject(&:blank?).map(&:to_i)
end_groups = charge_group_ids & group_ids if group_ids end_groups = charge_group_ids & group_ids if group_ids
homeworks.each do |homework| homeworks.each do |homework|

@ -712,7 +712,8 @@ class PollsController < ApplicationController
tip_exception("发布时间不能为空") if params[:publish_time].blank? tip_exception("发布时间不能为空") if params[:publish_time].blank?
tip_exception("截止时间不能为空") if params[:end_time].blank? tip_exception("截止时间不能为空") if params[:end_time].blank?
tip_exception("截止时间必须晚于发布时间") if params[:publish_time].to_time >= params[:end_time].to_time tip_exception("截止时间必须晚于发布时间") if params[:publish_time].to_time >= params[:end_time].to_time
tip_exception("截止时间不能晚于课堂结束时间(#{@course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")}") if @course.end_date.present? && params[:end_time].to_time > @course.end_date.end_of_day tip_exception("截止时间不能晚于课堂结束时间(#{@course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")}") if
@course.end_date.present? && params[:end_time].to_time > @course.end_date.end_of_day
params_publish_time = params[:publish_time].to_time params_publish_time = params[:publish_time].to_time
params_end_time = params[:end_time].to_time params_end_time = params[:end_time].to_time

@ -26,7 +26,7 @@ class ShixunsController < ApplicationController
before_action :special_allowed, only: [:send_to_course, :search_user_courses] before_action :special_allowed, only: [:send_to_course, :search_user_courses]
before_action :shixun_marker, only: [:new, :create] before_action :shixun_marker, only: [:new, :create]
#before_action :validate_wachat_support, only: [:shixun_exec] before_action :validate_wachat_support, only: [:shixun_exec]
skip_before_action :check_sign, only: [:download_file] skip_before_action :check_sign, only: [:download_file]
## 获取课程列表 ## 获取课程列表
@ -1187,11 +1187,11 @@ private
md5.hexdigest md5.hexdigest
end end
# def validate_wachat_support def validate_wachat_support
#
# if (params[:wechat].present? && !@shixun.is_wechat_support?) if (params[:wechat].present? && !@shixun.is_wechat_support?)
# tip_exception(-5, "..") tip_exception(-5, "..")
# end end
# end end
end end

@ -17,13 +17,7 @@ class Weapps::SessionsController < Weapps::BaseController
# session[:wechat_user_extra].delete(:nickName) # session[:wechat_user_extra].delete(:nickName)
# 绑定微信号 # 绑定微信号
# open_user = OpenUsers::Wechat.find_by(uid: session_unionid) OpenUsers::Wechat.create!(user: user, uid: session_unionid) if user.wechat_open_user.blank?
# if open_user.present? && open_user.user_id.nil?
# open_user.update!(user_id: user.id)
# els
if user.wechat_open_user.blank?
OpenUsers::Wechat.create!(user: user, uid: session_unionid)
end
successful_authentication(user) successful_authentication(user)
end end

@ -1,7 +1,7 @@
module SubjectsHelper module SubjectsHelper
# 实训路径的发布状态 # 实训路径的发布状态
def publish_status subject, is_manager def publish_status subject, is_manager, user
status = -1 status = -1
if is_manager if is_manager
status = 0 if subject.status == 0 status = 0 if subject.status == 0

@ -51,10 +51,7 @@ class Admins::ShixunSettingsQuery < ApplicationQuery
all_shixuns = all_shixuns.where(task_pass: params[:task_pass]) if params[:task_pass] all_shixuns = all_shixuns.where(task_pass: params[:task_pass]) if params[:task_pass]
all_shixuns = all_shixuns.where(code_hidden: params[:code_hidden]) if params[:code_hidden] all_shixuns = all_shixuns.where(code_hidden: params[:code_hidden]) if params[:code_hidden]
all_shixuns = all_shixuns.where(vip: params[:vip]) if params[:vip] all_shixuns = all_shixuns.where(vip: params[:vip]) if params[:vip]
if params[:no_subject] all_shixuns = all_shixuns.where(is_wechat_support: params[:is_wechat_support]) if params[:is_wechat_support]
shixun_ids = StageShixun.pluck(:shixun_id).uniq
all_shixuns = all_shixuns.published.where.not(id: shixun_ids)
end
custom_sort(all_shixuns, params[:sort_by], params[:sort_direction]) custom_sort(all_shixuns, params[:sort_by], params[:sort_direction])
end end

@ -22,7 +22,7 @@ class Subjects::CourseUsedInfoService < ApplicationService
# choice_shixun_frequency: 选用该课程实训的次数 # choice_shixun_frequency: 选用该课程实训的次数
course_info = [] course_info = []
schools.find_in_batches do |s| schools.find_in_batches do |s|
s.each do |school| Parallel.each(s) do |school|
name = school.name name = school.name
course_count = school.course_count course_count = school.course_count
student_count = school.courses.joins(:course_members).where(course_members: {role: 4, course_id: course_ids}).size student_count = school.courses.joins(:course_members).where(course_members: {role: 4, course_id: course_ids}).size

@ -11,7 +11,7 @@ class Subjects::ShixunUsedInfoService < ApplicationService
position = stage.position position = stage.position
shixuns = stage.shixuns.includes(myshixuns: :games, homework_commons: :course) shixuns = stage.shixuns.includes(myshixuns: :games, homework_commons: :course)
shixuns.find_in_batches(batch_size: 1000) do |s| shixuns.find_in_batches(batch_size: 1000) do |s|
s.each_with_index do |shixun, index| Parallel.each_with_index(s, in_processes: 2) do |shixun, index|
stage = "#{position}-#{index+1}" stage = "#{position}-#{index+1}"
name = shixun.name name = shixun.name
myshixuns = shixun.myshixuns myshixuns = shixun.myshixuns

@ -13,7 +13,7 @@ class Subjects::UserUsedInfoService < ApplicationService
users_info = [] users_info = []
users = User.includes(myshixuns: :games).where(myshixuns: {shixun_id: shixun_ids}, games: {status: 2}, users: {is_test: false}) users = User.includes(myshixuns: :games).where(myshixuns: {shixun_id: shixun_ids}, games: {status: 2}, users: {is_test: false})
users.find_in_batches(batch_size: 500) do |u| users.find_in_batches(batch_size: 500) do |u|
u.each do |user| Parallel.each(u, in_processes: 2) do |user|
myshixuns = user.myshixuns.select{|m| shixun_ids.include?(m.shixun_id)} myshixuns = user.myshixuns.select{|m| shixun_ids.include?(m.shixun_id)}
name = "#{user.lastname}#{user.firstname}" name = "#{user.lastname}#{user.firstname}"
passed_myshixun_count = myshixuns.select{|m| m.status == 1}.size passed_myshixun_count = myshixuns.select{|m| m.status == 1}.size

@ -73,8 +73,8 @@
</div> </div>
<div class="mr-5"> <div class="mr-5">
<label for="is_wechat_support"> <label for="is_wechat_support">
<%= check_box_tag :no_subject, !@sort_json[:no_subject],@sort_json[:no_subject], class:"shixun-settings-select" %> <%= check_box_tag :is_wechat_support, !@sort_json[:is_wechat_support],@sort_json[:is_wechat_support], class:"shixun-settings-select" %>
<span class="only_view">已发布没关联课程</span> <span class="only_view">只看小程序可用</span>
</label> </label>
</div> </div>

@ -8,8 +8,7 @@ json.member_count @subject.member_count
json.is_collect @user&.is_collect?(@subject) json.is_collect @user&.is_collect?(@subject)
json.allow_delete (@subject.status != 2 && @is_creator) || @user.admin? json.allow_delete (@subject.status != 2 && @is_creator) || @user.admin?
json.publish_status publish_status(@subject, @is_manager) json.publish_status publish_status(@subject, @is_manager, @user)
json.public_status public_status(@subject, @is_manager, @user)
json.allow_statistics @is_manager json.allow_statistics @is_manager
json.allow_send @user.logged? json.allow_send @user.logged?
json.allow_visit @subject.status > 1 || @is_manager json.allow_visit @subject.status > 1 || @is_manager

@ -5,14 +5,12 @@ namespace :subjects do
puts("---------------------data_statistic_begin") puts("---------------------data_statistic_begin")
Rails.logger.info("---------------------data_statistic_begin") Rails.logger.info("---------------------data_statistic_begin")
subjects = Subject.where(status: 2, hidden: 0) subjects = Subject.where(status: 2, hidden: 0)
if ENV['subject_id'].present? str = ""
subjects = subjects.where(id:ENV['subject_id']) buffer_size = 0
end
column_value = "subject_id, study_count, course_study_count, initiative_study, passed_count, course_used_count, " + column_value = "subject_id, study_count, course_study_count, initiative_study, passed_count, course_used_count, " +
"school_used_count, created_at, updated_at" "school_used_count, created_at, updated_at"
subjects.find_in_batches(batch_size: 50) do |s| subjects.find_in_batches(batch_size: 50) do |s, index|
str = [] Parallel.each_with_index(s, in_processes: 4) do |subject|
Parallel.each_with_index(s, in_threads: 4) do |subject, index|
puts("---------------------data_statistic: #{subject.id}") puts("---------------------data_statistic: #{subject.id}")
Rails.logger.info("---------------------data_statistic: #{subject.id}") Rails.logger.info("---------------------data_statistic: #{subject.id}")
data = Subjects::DataStatisticService.new(subject) data = Subjects::DataStatisticService.new(subject)
@ -20,16 +18,18 @@ namespace :subjects do
next if study_count == 0 next if study_count == 0
course_study_count = data.course_study_count course_study_count = data.course_study_count
initiative_study = study_count - course_study_count initiative_study = study_count - course_study_count
str << ("(#{subject.id}, #{study_count}, #{course_study_count}, #{initiative_study}, " + str += ", " unless str.empty?
str += ("(#{subject.id}, #{study_count}, #{course_study_count}, #{initiative_study}, " +
"#{data.passed_count}, #{data.course_used_count}, #{data.school_used_count}, " + "#{data.passed_count}, #{data.course_used_count}, #{data.school_used_count}, " +
"'#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')") "'#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')")
puts "index: #{index}; worker_number: #{Parallel.worker_number}" buffer_size += 1
puts "####str: #{str}" if buffer_size == 1000 || subjects.count == (index+1)
end sql = "REPLACE INTO subject_records(#{column_value}) VALUES #{str}"
if str.size > 0
sql = "REPLACE INTO subject_records(#{column_value}) VALUES #{str.uniq.join(",")}"
puts sql puts sql
ActiveRecord::Base.connection.execute sql ActiveRecord::Base.connection.execute sql
str = ""
buffer_size = 0
end
end end
end end
@ -41,33 +41,30 @@ namespace :subjects do
puts("---------------------course_info_statistic_begin") puts("---------------------course_info_statistic_begin")
Rails.logger.info("---------------------course_info_statistic_begin") Rails.logger.info("---------------------course_info_statistic_begin")
subjects = Subject.where(status: 2, hidden: 0) subjects = Subject.where(status: 2, hidden: 0)
str = ""
buffer_size = 0
column_value = "subject_id, school_id, school_name, course_count, student_count, choice_shixun_num, " + column_value = "subject_id, school_id, school_name, course_count, student_count, choice_shixun_num, " +
"choice_shixun_frequency, created_at, updated_at" "choice_shixun_frequency, created_at, updated_at"
if ENV['subject_id'].present?
subjects = subjects.where(id:ENV['subject_id']) subjects.find_in_batches(batch_size: 50) do |s|
end Parallel.each(s, in_processes: 4) do |subject|
subjects.find_in_batches(batch_size: 20) do |s|
Parallel.each_with_index(s, in_processes: 4) do |subject, index, str = []|
puts("---------------------course_info_statistic: #{subject.id}") puts("---------------------course_info_statistic: #{subject.id}")
Rails.logger.info("---------------------course_info_statistic: #{subject.id}") Rails.logger.info("---------------------course_info_statistic: #{subject.id}")
data = Subjects::CourseUsedInfoService.call(subject) data = Subjects::CourseUsedInfoService.call(subject)
data.each do |key| Parallel.map_with_index(data) do |key, index|
next if key[:school_id].nil? next if key[:school_id].nil?
str << ("(#{subject.id}, #{key[:school_id]}, '#{key[:school_name]}', #{key[:course_count]}, " + str += ", " unless str.empty?
str += ("(#{subject.id}, #{key[:school_id]}, '#{key[:school_name]}', #{key[:course_count]}, " +
"#{key[:student_count]}, #{key[:choice_shixun_num]}, #{key[:choice_shixun_frequency]}, " + "#{key[:student_count]}, #{key[:choice_shixun_num]}, #{key[:choice_shixun_frequency]}, " +
"'#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')") "'#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')")
# if str.size == 1000 buffer_size += 1
# sql = "REPLACE INTO subject_course_records(#{column_value}) VALUES #{str.uniq.join(",")}" if buffer_size == 1000 || (index + 1) == data.size
# str_c = str sql = "REPLACE INTO subject_course_records(#{column_value}) VALUES #{str}"
# puts sql
# ActiveRecord::Base.connection.execute sql
# str -= str_c
# end
end
if str.size > 0
sql = "REPLACE INTO subject_course_records(#{column_value}) VALUES #{str.uniq.join(",")}"
puts sql puts sql
ActiveRecord::Base.connection.execute sql ActiveRecord::Base.connection.execute sql
str = ""
buffer_size = 0
end
end end
end end
end end
@ -79,32 +76,30 @@ namespace :subjects do
puts("---------------------shixun_info_statistic_begin") puts("---------------------shixun_info_statistic_begin")
Rails.logger.info("---------------------shixun_info_statistic_begin") Rails.logger.info("---------------------shixun_info_statistic_begin")
subjects = Subject.where(status: 2, hidden: 0) subjects = Subject.where(status: 2, hidden: 0)
if ENV['subject_id'].present? str = ""
subjects = subjects.where(id:ENV['subject_id']) buffer_size = 0
end
column_value = "subject_id, shixun_id, stage, shixun_name, challenge_count, course_count, " + column_value = "subject_id, shixun_id, stage, shixun_name, challenge_count, course_count, " +
"school_count, used_count, passed_count, evaluate_count, passed_ave_time, created_at, updated_at" "school_count, used_count, passed_count, evaluate_count, passed_ave_time, created_at, updated_at"
subjects.find_in_batches(batch_size: 20) do |s| subjects.find_in_batches(batch_size: 50) do |s|
Parallel.each_with_index(s, in_processes: 4) do |subject, index, str = []| Parallel.each_with_index(s, in_processes: 4) do |subject|
puts("---------------------shixun_info_statistic: #{subject.id}") puts("---------------------shixun_info_statistic: #{subject.id}")
Rails.logger.info("---------------------shixun_info_statistic: #{subject.id}") Rails.logger.info("---------------------shixun_info_statistic: #{subject.id}")
data = Subjects::ShixunUsedInfoService.call(subject) data = Subjects::ShixunUsedInfoService.call(subject)
data.each do |key| data.each_with_index do |key, index|
next if key[:shixun_id].nil? next if key[:shixun_id].nil?
str << ("(#{subject.id}, #{key[:shixun_id]}, '#{key[:stage]}', '#{key[:name]}', #{key[:challenge_count]}, " + str += ", " unless str.empty?
str += ("(#{subject.id}, #{key[:shixun_id]}, '#{key[:stage]}', '#{key[:name]}', #{key[:challenge_count]}, " +
"#{key[:course_count]}, #{key[:school_count]}, #{key[:used_count]}, #{key[:passed_count]}, " + "#{key[:course_count]}, #{key[:school_count]}, #{key[:used_count]}, #{key[:passed_count]}, " +
"#{key[:evaluate_count]}, #{key[:passed_ave_time]}, " + "#{key[:evaluate_count]}, #{key[:passed_ave_time]}, " +
"'#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')") "'#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')")
# if str.size == 1000 buffer_size += 1
# sql = "REPLACE INTO subject_shixun_infos(#{column_value}) VALUES #{str.join(",")}" if buffer_size == 1000 || (index+1) == data.size
# puts sql sql = "REPLACE INTO subject_shixun_infos(#{column_value}) VALUES #{str}"
# ActiveRecord::Base.connection.execute sql
# end
end
if str.size > 0
sql = "REPLACE INTO subject_shixun_infos(#{column_value}) VALUES #{str.join(",")}"
puts sql puts sql
ActiveRecord::Base.connection.execute sql ActiveRecord::Base.connection.execute sql
str = ""
buffer_size = 0
end
end end
end end
end end
@ -116,26 +111,28 @@ namespace :subjects do
puts("---------------------user_info_statistic_begin") puts("---------------------user_info_statistic_begin")
Rails.logger.info("---------------------user_info_statistic_begin") Rails.logger.info("---------------------user_info_statistic_begin")
subjects = Subject.where(status: 2, hidden: 0) subjects = Subject.where(status: 2, hidden: 0)
str = ""
buffer_size = 0
column_value = "user_id, subject_id, username, passed_myshixun_count, passed_games_count, " + column_value = "user_id, subject_id, username, passed_myshixun_count, passed_games_count, " +
"code_line_count, evaluate_count, cost_time, created_at, updated_at" "code_line_count, evaluate_count, cost_time, created_at, updated_at"
subjects.find_in_batches(batch_size: 20) do |s|
Parallel.each_with_index(s, in_processes: 4) do |subject, index, str = []| subjects.find_in_batches(batch_size: 50) do |s|
Parallel.each_with_index(s, in_processes: 4) do |subject, index|
puts("---------------------user_info_statistic: #{subject.id}") puts("---------------------user_info_statistic: #{subject.id}")
data = Subjects::UserUsedInfoService.call(subject) data = Subjects::UserUsedInfoService.call(subject)
data.each do |key| data.each do |key|
str << ("(#{key[:user_id]}, #{subject.id}, '#{key[:name].gsub(/'/, '"')}', #{key[:passed_myshixun_count]}, " + next if key[:user_id].nil?
str += ", " unless str.empty?
str += ("(#{key[:user_id]}, #{subject.id}, '#{key[:name].gsub(/'/, '"')}', #{key[:passed_myshixun_count]}, " +
"#{key[:passed_games_count]}, #{key[:code_line_count]}, #{key[:evaluate_count]}, #{key[:cost_time]}, " + "#{key[:passed_games_count]}, #{key[:code_line_count]}, #{key[:evaluate_count]}, #{key[:cost_time]}, " +
"'#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')") "'#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')")
# if str.size == 1000 buffer_size += 1
# sql = "REPLACE INTO subject_user_infos(#{column_value}) VALUES #{str.join(",")}" if buffer_size == 1000 || (index+1 == data.size)
# ActiveRecord::Base.connection.execute sql sql = "REPLACE INTO subject_user_infos(#{column_value}) VALUES #{str}"
# str = []
# end
end
if str.size > 0
sql = "REPLACE INTO subject_user_infos(#{column_value}) VALUES #{str.join(",")}"
puts sql
ActiveRecord::Base.connection.execute sql ActiveRecord::Base.connection.execute sql
str = ""
buffer_size = 0
end
end end
end end
end end

@ -0,0 +1 @@
GENERATE_SOURCEMAP=false

@ -0,0 +1,23 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# production
/build
/dist
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*

@ -0,0 +1,68 @@
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
## Available Scripts
In the project directory, you can run:
### `npm start`
Runs the app in the development mode.<br />
Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
The page will reload if you make edits.<br />
You will also see any lint errors in the console.
### `npm test`
Launches the test runner in the interactive watch mode.<br />
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
### `npm run build`
Builds the app for production to the `build` folder.<br />
It correctly bundles React in production mode and optimizes the build for the best performance.
The build is minified and the filenames include the hashes.<br />
Your app is ready to be deployed!
See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
### `npm run eject`
**Note: this is a one-way operation. Once you `eject`, you cant go back!**
If you arent satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point youre on your own.
You dont have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldnt feel obligated to use this feature. However we understand that this tool wouldnt be useful if you couldnt customize it when you are ready for it.
## Learn More
You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
To learn React, check out the [React documentation](https://reactjs.org/).
### Code Splitting
This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting
### Analyzing the Bundle Size
This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size
### Making a Progressive Web App
This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app
### Advanced Configuration
This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration
### Deployment
This section has moved here: https://facebook.github.io/create-react-app/docs/deployment
### `npm run build` fails to minify
This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify

@ -1,34 +0,0 @@
新版tpi改动的文件
Index.js
contex/TPIContextProvider.js
page/main/LeftViewContainer.js
taskList/TaskList.js
TPMIndexHOC.js
App.js
CodeRepositoryViewContainer.js
Index.js
choose={context.chooses}
TPIContextProvider.js
LeftViewContainer.js
TaskList.js
TPMIndexHOC.js
MainContentContainer
rep_content返回值多了一层 {content: '...'}
TODO
待同步
1、timer图标样式更换
index.html
WebSSHTimer.css
WebSSHTimer.js

@ -0,0 +1,83 @@
const {
override,
addLessLoader,
disableEsLint,
addBundleVisualizer,
addWebpackAlias,
fixBabelImports,
addWebpackPlugin
} = require("customize-cra")
const path = require('path');
const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin')
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin')
const HardSourceWebpackPlugin = require('hard-source-webpack-plugin')
let instance = new HardSourceWebpackPlugin({
// Either an absolute path or relative to webpack's options.context.
cacheDirectory: 'node_modules/.cache/hard-source/[confighash]',
// Either a string of object hash function given a webpack config.
configHash: function (webpackConfig) {
// node-object-hash on npm can be used to build this.
return require('node-object-hash')({ sort: false }).hash(webpackConfig);
},
// Either false, a string, an object, or a project hashing function.
environmentHash: {
root: process.cwd(),
directories: [],
files: ['package-lock.json', 'yarn.lock'],
},// How to launch the extra processes. Default:
fork: (fork, compiler, webpackBin) => fork(
webpackBin(),
['--config', __filename], {
silent: true,
}
),
// Number of workers to spawn. Default:
numWorkers: () => require('os').cpus().length,
// Number of modules built before launching parallel building. Default:
minModules: 10,
// An object.
info: {
// 'none' or 'test'.
mode: 'none',
// 'debug', 'log', 'info', 'warn', or 'error'.
level: 'debug',
},
// Clean up large, old caches automatically.
cachePrune: {
// Caches younger than `maxAge` are not considered for deletion. They must
// be at least this (default: 2 days) old in milliseconds.
maxAge: 2 * 24 * 60 * 60 * 1000,
// All caches together must be larger than `sizeThreshold` before any
// caches will be deleted. Together they must be at least this
// (default: 50 MB) big in bytes.
sizeThreshold: 50 * 1024 * 1024
},
})
module.exports = override(
disableEsLint(),
// addBundleVisualizer(),
addWebpackAlias({
"educoder": path.resolve(__dirname, 'src/common/educoder.js')
}),
addLessLoader({
javascriptEnabled: true
}),
fixBabelImports('import', {
libraryName: 'antd',
libraryDirectory: 'es',
style: true
}),
addWebpackPlugin(new MonacoWebpackPlugin({})),
// addWebpackPlugin(instance),
(config) => {
config.resolve.plugins = config.resolve.plugins.filter(plugin => !(plugin instanceof ModuleScopePlugin));
if (process.env.NODE_ENV !== "development") {
config.output.publicPath = `/react/build/`;
}
return config
}
);

@ -1,93 +0,0 @@
'use strict';
const fs = require('fs');
const path = require('path');
const paths = require('./paths');
// Make sure that including paths.js after env.js will read .env variables.
delete require.cache[require.resolve('./paths')];
const NODE_ENV = process.env.NODE_ENV;
if (!NODE_ENV) {
throw new Error(
'The NODE_ENV environment variable is required but was not specified.'
);
}
// https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use
var dotenvFiles = [
`${paths.dotenv}.${NODE_ENV}.local`,
`${paths.dotenv}.${NODE_ENV}`,
// Don't include `.env.local` for `test` environment
// since normally you expect tests to produce the same
// results for everyone
NODE_ENV !== 'test' && `${paths.dotenv}.local`,
paths.dotenv,
].filter(Boolean);
// Load environment variables from .env* files. Suppress warnings using silent
// if this file is missing. dotenv will never modify any environment variables
// that have already been set. Variable expansion is supported in .env files.
// https://github.com/motdotla/dotenv
// https://github.com/motdotla/dotenv-expand
dotenvFiles.forEach(dotenvFile => {
if (fs.existsSync(dotenvFile)) {
require('dotenv-expand')(
require('dotenv').config({
path: dotenvFile,
})
);
}
});
// We support resolving modules according to `NODE_PATH`.
// This lets you use absolute paths in imports inside large monorepos:
// https://github.com/facebookincubator/create-react-app/issues/253.
// It works similar to `NODE_PATH` in Node itself:
// https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders
// Note that unlike in Node, only *relative* paths from `NODE_PATH` are honored.
// Otherwise, we risk importing Node.js core modules into an app instead of Webpack shims.
// https://github.com/facebookincubator/create-react-app/issues/1023#issuecomment-265344421
// We also resolve them to make sure all tools using them work consistently.
const appDirectory = fs.realpathSync(process.cwd());
process.env.NODE_PATH = (process.env.NODE_PATH || '')
.split(path.delimiter)
.filter(folder => folder && !path.isAbsolute(folder))
.map(folder => path.resolve(appDirectory, folder))
.join(path.delimiter);
// Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be
// injected into the application via DefinePlugin in Webpack configuration.
const REACT_APP = /^REACT_APP_/i;
function getClientEnvironment(publicUrl) {
const raw = Object.keys(process.env)
.filter(key => REACT_APP.test(key))
.reduce(
(env, key) => {
env[key] = process.env[key];
return env;
},
{
// Useful for determining whether were running in production mode.
// Most importantly, it switches React into the correct mode.
NODE_ENV: process.env.NODE_ENV || 'development',
// Useful for resolving the correct path to static assets in `public`.
// For example, <img src={process.env.PUBLIC_URL + '/img/logo.png'} />.
// This should only be used as an escape hatch. Normally you would put
// images into the `src` and `import` them in code to get their paths.
PUBLIC_URL: '/react/build/.',
}
);
// Stringify all values so we can feed into Webpack DefinePlugin
const stringified = {
'process.env': Object.keys(raw).reduce((env, key) => {
env[key] = JSON.stringify(raw[key]);
return env;
}, {}),
};
return { raw, stringified };
}
module.exports = getClientEnvironment;

@ -1,14 +0,0 @@
'use strict';
// This is a custom Jest transformer turning style imports into empty objects.
// http://facebook.github.io/jest/docs/en/webpack.html
module.exports = {
process() {
return 'module.exports = {};';
},
getCacheKey() {
// The output is always the same.
return 'cssTransform';
},
};

@ -1,12 +0,0 @@
'use strict';
const path = require('path');
// This is a custom Jest transformer turning file imports into filenames.
// http://facebook.github.io/jest/docs/en/webpack.html
module.exports = {
process(src, filename) {
return `module.exports = ${JSON.stringify(path.basename(filename))};`;
},
};

@ -1,55 +0,0 @@
'use strict';
const path = require('path');
const fs = require('fs');
const url = require('url');
// Make sure any symlinks in the project folder are resolved:
// https://github.com/facebookincubator/create-react-app/issues/637
const appDirectory = fs.realpathSync(process.cwd());
const resolveApp = relativePath => path.resolve(appDirectory, relativePath);
const envPublicUrl = process.env.PUBLIC_URL;
function ensureSlash(path, needsSlash) {
const hasSlash = path.endsWith('/');
if (hasSlash && !needsSlash) {
return path.substr(path, path.length - 1);
} else if (!hasSlash && needsSlash) {
return `${path}/`;
} else {
return path;
}
}
const getPublicUrl = appPackageJson =>
envPublicUrl || require(appPackageJson).homepage;
// We use `PUBLIC_URL` environment variable or "homepage" field to infer
// "public path" at which the app is served.
// Webpack needs to know it to put the right <script> hrefs into HTML even in
// single-page apps that may serve index.html for nested URLs like /todos/42.
// We can't use a relative path in HTML because we don't want to load something
// like /todos/42/static/js/bundle.7289d.js. We have to know the root.
function getServedPath(appPackageJson) {
const publicUrl = getPublicUrl(appPackageJson);
const servedUrl =
envPublicUrl || (publicUrl ? url.parse(publicUrl).pathname : '/');
return ensureSlash(servedUrl, true);
}
// config after eject: we're in ./config/
module.exports = {
dotenv: resolveApp('.env'),
appBuild: resolveApp('build'),
appPublic: resolveApp('public'),
appHtml: resolveApp('public/index.html'),
appIndexJs: resolveApp('src/index.js'),
appPackageJson: resolveApp('package.json'),
appSrc: resolveApp('src'),
yarnLockFile: resolveApp('yarn.lock'),
testsSetup: resolveApp('src/setupTests.js'),
appNodeModules: resolveApp('node_modules'),
publicUrl: getPublicUrl(resolveApp('package.json')),
servedPath: getServedPath(resolveApp('package.json')),
};

@ -1,22 +0,0 @@
'use strict';
if (typeof Promise === 'undefined') {
// Rejection tracking prevents a common issue where React gets into an
// inconsistent state due to an error, but it gets swallowed by a Promise,
// and the user has no idea what causes React's erratic future behavior.
require('promise/lib/rejection-tracking').enable();
window.Promise = require('promise/lib/es6-extensions.js');
}
// fetch() polyfill for making API calls.
require('whatwg-fetch');
// Object.assign() is commonly used with React.
// It will use the native implementation if it's present and isn't buggy.
Object.assign = require('object-assign');
// In tests, polyfill requestAnimationFrame since jsdom doesn't provide it yet.
// We don't polyfill it in the browser--this is user's responsibility.
if (process.env.NODE_ENV === 'test') {
require('raf').polyfill(global);
}

@ -9,7 +9,7 @@ const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
const WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin'); const WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin');
const eslintFormatter = require('react-dev-utils/eslintFormatter'); const eslintFormatter = require('react-dev-utils/eslintFormatter');
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin'); const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
// const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin'); const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');
const getClientEnvironment = require('./env'); const getClientEnvironment = require('./env');
const paths = require('./paths'); const paths = require('./paths');
@ -30,9 +30,9 @@ const env = getClientEnvironment(publicUrl);
module.exports = { module.exports = {
// You may want 'eval' instead if you prefer to see the compiled output in DevTools. // 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 // 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", // 开启调试 //devtool: "source-map", // 开启调试
// These are the "entry points" to our application. // These are the "entry points" to our application.
// This means they will be the "root" imports that are included in JS bundle. // This means they will be the "root" imports that are included in JS bundle.
// The first two entry points enable "hot" CSS and auto-refreshes for JS. // The first two entry points enable "hot" CSS and auto-refreshes for JS.
@ -267,7 +267,7 @@ module.exports = {
// https://github.com/jmblog/how-to-optimize-momentjs-with-webpack // https://github.com/jmblog/how-to-optimize-momentjs-with-webpack
// You can remove this if you don't use Moment.js: // You can remove this if you don't use Moment.js:
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/), new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
// new MonacoWebpackPlugin(), new MonacoWebpackPlugin(),
], ],
// Some libraries import Node modules but don't use them in the browser. // Some libraries import Node modules but don't use them in the browser.
// Tell Webpack to provide empty mocks for them so importing them works. // Tell Webpack to provide empty mocks for them so importing them works.

@ -1,95 +0,0 @@
'use strict';
const errorOverlayMiddleware = require('react-dev-utils/errorOverlayMiddleware');
const noopServiceWorkerMiddleware = require('react-dev-utils/noopServiceWorkerMiddleware');
const ignoredFiles = require('react-dev-utils/ignoredFiles');
const config = require('./webpack.config.dev');
const paths = require('./paths');
const protocol = process.env.HTTPS === 'true' ? 'https' : 'http';
const host = process.env.HOST || '0.0.0.0';
module.exports = function(proxy, allowedHost) {
return {
// WebpackDevServer 2.4.3 introduced a security fix that prevents remote
// websites from potentially accessing local content through DNS rebinding:
// https://github.com/webpack/webpack-dev-server/issues/887
// https://medium.com/webpack/webpack-dev-server-middleware-security-issues-1489d950874a
// However, it made several existing use cases such as development in cloud
// environment or subdomains in development significantly more complicated:
// https://github.com/facebookincubator/create-react-app/issues/2271
// https://github.com/facebookincubator/create-react-app/issues/2233
// While we're investigating better solutions, for now we will take a
// compromise. Since our WDS configuration only serves files in the `public`
// folder we won't consider accessing them a vulnerability. However, if you
// use the `proxy` feature, it gets more dangerous because it can expose
// remote code execution vulnerabilities in backends like Django and Rails.
// So we will disable the host check normally, but enable it if you have
// specified the `proxy` setting. Finally, we let you override it if you
// really know what you're doing with a special environment variable.
disableHostCheck:
!proxy || process.env.DANGEROUSLY_DISABLE_HOST_CHECK === 'true',
// Enable gzip compression of generated files.
compress: true,
// Silence WebpackDevServer's own logs since they're generally not useful.
// It will still show compile warnings and errors with this setting.
clientLogLevel: 'none',
// By default WebpackDevServer serves physical files from current directory
// in addition to all the virtual build products that it serves from memory.
// This is confusing because those files wont automatically be available in
// production build folder unless we copy them. However, copying the whole
// project directory is dangerous because we may expose sensitive files.
// Instead, we establish a convention that only files in `public` directory
// get served. Our build script will copy `public` into the `build` folder.
// In `index.html`, you can get URL of `public` folder with %PUBLIC_URL%:
// <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
// In JavaScript code, you can access it with `process.env.PUBLIC_URL`.
// Note that we only recommend to use `public` folder as an escape hatch
// for files like `favicon.ico`, `manifest.json`, and libraries that are
// for some reason broken when imported through Webpack. If you just want to
// use an image, put it in `src` and `import` it from JavaScript instead.
contentBase: paths.appPublic,
// By default files from `contentBase` will not trigger a page reload.
watchContentBase: true,
// Enable hot reloading server. It will provide /sockjs-node/ endpoint
// for the WebpackDevServer client so it can learn when the files were
// updated. The WebpackDevServer client is included as an entry point
// in the Webpack development configuration. Note that only changes
// to CSS are currently hot reloaded. JS changes will refresh the browser.
hot: true,
// It is important to tell WebpackDevServer to use the same "root" path
// as we specified in the config. In development, we always serve from /.
publicPath: config.output.publicPath,
// WebpackDevServer is noisy by default so we emit custom message instead
// by listening to the compiler events with `compiler.plugin` calls above.
quiet: true,
// Reportedly, this avoids CPU overload on some systems.
// https://github.com/facebookincubator/create-react-app/issues/293
// src/node_modules is not ignored to support absolute imports
// https://github.com/facebookincubator/create-react-app/issues/1065
watchOptions: {
ignored: ignoredFiles(paths.appSrc),
},
// Enable HTTPS if the HTTPS environment variable is set to 'true'
https: protocol === 'https',
host: host,
overlay: false,
historyApiFallback: {
// Paths with dots should still use the history fallback.
// See https://github.com/facebookincubator/create-react-app/issues/387.
disableDotRule: true,
},
public: allowedHost,
proxy,
before(app) {
// This lets us open files from the runtime error overlay.
app.use(errorOverlayMiddleware());
// This service worker file is effectively a 'no-op' that will reset any
// previous service worker registered for the same host:port combination.
// We do this in development to avoid hitting the production cache if
// it used the same host and port.
// https://github.com/facebookincubator/create-react-app/issues/2272#issuecomment-302832432
app.use(noopServiceWorkerMiddleware());
},
};
};

@ -1,46 +0,0 @@
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import './indexPlus.css';
import App from './App';
// 加之前main.js 18.1MB
// import { message } from 'antd';
import message from 'antd/lib/message';
import 'antd/lib/message/style/css';
import { AppContainer } from 'react-hot-loader';
import registerServiceWorker from './registerServiceWorker';
import { configureUrlQuery } from 'react-url-query';
import history from './history';
// link the history used in our app to url-query so it can update the URL with it.
configureUrlQuery({ history });
// ----------------------------------------------------------------------------------- 请求配置
window.__useKindEditor = false;
const render = (Component) => {
ReactDOM.render(
<AppContainer {...this.props} {...this.state}>
<Component {...this.props} {...this.state}/>
</AppContainer>,
document.getElementById('root')
);
}
// ReactDOM.render(
// ,
// document.getElementById('root'));
// registerServiceWorker();
render(App);
if (module.hot) {
module.hot.accept('./App', () => { render(App) });
}

File diff suppressed because it is too large Load Diff

@ -1,192 +1,94 @@
{ {
"name": "educoder", "name": "h5",
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"homepage": "/react/build/",
"dependencies": { "dependencies": {
"@icedesign/base": "^0.2.5", "@loadable/component": "^5.12.0",
"@monaco-editor/react": "^2.3.0",
"@novnc/novnc": "^1.1.0", "@novnc/novnc": "^1.1.0",
"antd": "^3.23.2", "antd": "^3.26.12",
"array-flatten": "^2.1.2", "axios": "^0.19.2",
"autoprefixer": "7.1.6",
"axios": "^0.18.0",
"babel-core": "6.26.0",
"babel-eslint": "7.2.3",
"babel-jest": "20.0.3",
"babel-loader": "7.1.2",
"babel-plugin-syntax-dynamic-import": "^6.18.0",
"babel-preset-react-app": "^3.1.1",
"babel-runtime": "6.26.0",
"bizcharts": "^3.5.5", "bizcharts": "^3.5.5",
"bundle-loader": "^0.5.6",
"case-sensitive-paths-webpack-plugin": "2.1.1",
"chalk": "1.1.3", "chalk": "1.1.3",
"classnames": "^2.2.5", "classnames": "^2.2.5",
"clipboard": "^2.0.4", "clipboard": "^2.0.4",
"codemirror": "^5.46.0", "codemirror": "^5.52.2",
"connected-react-router": "4.4.1", "echarts": "^4.7.0",
"css-loader": "0.28.7",
"dotenv": "4.0.0",
"dotenv-expand": "4.2.0",
"echarts": "^4.2.0-rc.2",
"editor.md": "^1.5.0", "editor.md": "^1.5.0",
"eslint": "4.10.0", "flvplayer": "^1.1.5",
"eslint-config-react-app": "^2.1.0", "immutability-helper": "^3.0.1",
"eslint-loader": "1.9.0", "js-base64": "^2.5.2",
"eslint-plugin-flowtype": "2.39.1",
"eslint-plugin-import": "2.8.0",
"eslint-plugin-jsx-a11y": "5.1.1",
"eslint-plugin-react": "7.4.0",
"extract-text-webpack-plugin": "3.0.2",
"file-loader": "1.1.5",
"flv.js": "^1.5.0",
"fs-extra": "3.0.1",
"html-webpack-plugin": "2.29.0",
"immutability-helper": "^2.6.6",
"install": "^0.12.2",
"jest": "20.0.4",
"js-base64": "^2.5.1",
"katex": "^0.11.1", "katex": "^0.11.1",
"lodash": "^4.17.5", "lodash": "^4.17.5",
"loglevel": "^1.6.1", "loglevel": "^1.6.1",
"material-ui": "^1.0.0-beta.40",
"md5": "^2.2.1", "md5": "^2.2.1",
"moment": "^2.23.0", "moment": "^2.23.0",
"monaco-editor": "^0.15.6", "monaco-editor": "^0.20.0",
"monaco-editor-webpack-plugin": "^1.7.0", "monaco-editor-webpack-plugin": "^1.9.0",
"npm": "^6.10.1",
"numeral": "^2.0.6", "numeral": "^2.0.6",
"object-assign": "4.1.1", "object-assign": "4.1.1",
"postcss-flexbugs-fixes": "3.2.0",
"postcss-loader": "2.0.8",
"promise": "8.0.1", "promise": "8.0.1",
"prop-types": "^15.6.1", "prop-types": "^15.6.1",
"qrcode.react": "^1.0.0", "qrcode.react": "^1.0.0",
"qs": "^6.6.0", "qs": "^6.9.2",
"quill": "^1.3.7", "quill": "^1.3.7",
"quill-delta-to-html": "^0.11.0", "quill-delta-to-html": "^0.11.0",
"raf": "3.4.0", "react": "^16.13.1",
"rc-form": "^2.1.7",
"rc-pagination": "^1.16.2",
"rc-rate": "^2.4.0",
"rc-select": "^8.0.12",
"rc-tree": "^1.7.11",
"rc-upload": "^2.5.1",
"react": "^16.9.0",
"react-beautiful-dnd": "^10.0.4", "react-beautiful-dnd": "^10.0.4",
"react-codemirror": "^1.0.0", "react-codemirror2": "^6.0.1",
"react-codemirror2": "^6.0.0",
"react-content-loader": "^3.1.1", "react-content-loader": "^3.1.1",
"react-cookie": "^4.0.3",
"react-cookies": "^0.1.1", "react-cookies": "^0.1.1",
"react-datepicker": "^2.14.0", "react-dom": "^16.13.1",
"react-dev-utils": "^5.0.0",
"react-dom": "^16.9.0",
"react-hot-loader": "^4.0.0",
"react-infinite-scroller": "^1.2.4", "react-infinite-scroller": "^1.2.4",
"react-loadable": "^5.3.1",
"react-monaco-editor": "^0.25.1",
"react-player": "^1.11.1", "react-player": "^1.11.1",
"react-redux": "5.0.7", "react-redux": "5.0.7",
"react-router": "^4.2.0", "react-router": "^5.1.2",
"react-router-dom": "^4.2.2", "react-router-dom": "^5.1.2",
"react-scripts": "3.4.0",
"react-split-pane": "^0.1.89", "react-split-pane": "^0.1.89",
"react-url-query": "^1.4.0", "react-url-query": "^1.4.0",
"react-zmage": "^0.8.5-beta.31", "react-zmage": "^0.8.5-beta.31",
"redux": "^4.0.0", "redux": "^4.0.0",
"redux-thunk": "2.3.0", "redux-thunk": "^2.3.0",
"rsuite": "^4.0.1", "rsuite": "^4.3.2",
"sass-loader": "7.3.1",
"scroll-into-view": "^1.12.3", "scroll-into-view": "^1.12.3",
"showdown": "^1.9.1", "showdown": "^1.9.1",
"showdown-katex": "^0.6.0", "showdown-katex": "^0.6.0",
"store": "^2.0.12", "store": "^2.0.12",
"style-loader": "0.19.0", "styled-components": "^5.0.1",
"styled-components": "^4.1.3",
"sw-precache-webpack-plugin": "0.11.4",
"url-loader": "0.6.2",
"webpack": "3.8.1",
"webpack-dev-server": "2.9.4",
"webpack-manifest-plugin": "1.3.2",
"webpack-parallel-uglify-plugin": "^1.1.0",
"whatwg-fetch": "2.0.3", "whatwg-fetch": "2.0.3",
"wrap-md-editor": "^0.2.20" "wrap-md-editor": "^0.2.20"
}, },
"scripts": { "scripts": {
"start": "node --max_old_space_size=15360 scripts/start.js", "start": "PORT=3007 react-app-rewired start",
"build": "node --max_old_space_size=15360 scripts/build.js", "build": "react-app-rewired --max_old_space_size=8192 build ",
"concat": "node scripts/concat.js", "test": "react-scripts test",
"gen_stats": "NODE_ENV=production webpack --profile --config=./config/webpack.config.prod.js --json > stats.json", "eject": "react-scripts eject"
"ana": "webpack-bundle-analyzer ./stats.json",
"analyze": "npm run build -- --stats && webpack-bundle-analyzer build/bundle-stats.json",
"analyz": "NODE_ENV=production npm_config_report=true npm run build"
}, },
"jest": { "eslintConfig": {
"collectCoverageFrom": [ "extends": "react-app"
"src/**/*.{js,jsx,mjs}"
],
"setupFiles": [
"<rootDir>/config/polyfills.js"
],
"testMatch": [
"<rootDir>/src/**/__tests__/**/*.{js,jsx,mjs}",
"<rootDir>/src/**/?(*.)(spec|test).{js,jsx,mjs}"
],
"testEnvironment": "node",
"testURL": "http://localhost",
"transform": {
"^.+\\.(js|jsx|mjs)$": "<rootDir>/node_modules/babel-jest",
"^.+\\.css$": "<rootDir>/config/jest/cssTransform.js",
"^(?!.*\\.(js|jsx|mjs|css|json)$)": "<rootDir>/config/jest/fileTransform.js"
},
"transformIgnorePatterns": [
"[/\\\\]node_modules[/\\\\].+\\.(js|jsx|mjs)$"
],
"moduleNameMapper": {
"^react-native$": "react-native-web"
},
"moduleFileExtensions": [
"web.js",
"mjs",
"js",
"json",
"web.jsx",
"jsx",
"node"
]
},
"babel": {
"presets": [
"react",
"react-app"
],
"plugins": [
[
"import",
{
"libraryName": "antd",
"libraryDirectory": "lib",
"style": "css"
}, },
"ant" "browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
], ],
"syntax-dynamic-import" "development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
] ]
}, },
"eslintConfig": {
"extends": "react-app"
},
"proxy": "http://localhost:3000",
"port": "3007",
"devDependencies": { "devDependencies": {
"@babel/runtime": "7.0.0-beta.51", "babel-plugin-import": "^1.13.0",
"babel-plugin-import": "^1.11.0", "customize-cra": "^0.5.0",
"compression-webpack-plugin": "^1.1.12", "hard-source-webpack-plugin": "^0.13.1",
"concat": "^1.0.3", "less": "^3.11.1",
"happypack": "^5.0.1", "less-loader": "^5.0.0",
"mockjs": "^1.1.0", "react-app-rewired": "^2.1.5",
"node-sass": "^4.12.0", "uglifyjs-webpack-plugin": "^2.2.0",
"reqwest": "^2.0.5", "webpack-bundle-analyzer": "^3.6.0"
"webpack-bundle-analyzer": "^3.0.3",
"webpack-parallel-uglify-plugin": "^1.1.0"
} }
} }

File diff suppressed because it is too large Load Diff

@ -859,8 +859,12 @@
content: "\e678"; content: "\e678";
} }
.icon-VPN:before { .icon-guolvqi:before {
content: "\e601"; content: "\e71b";
}
.icon-congshulianjie:before {
content: "\e6ee";
} }
.icon-jquery:before { .icon-jquery:before {
@ -1359,3 +1363,10 @@
content: "\e640"; content: "\e640";
} }
.icon-chushihua:before {
content: "\e71c";
}
.icon-ceshiji:before {
content: "\e71e";
}

@ -1476,11 +1476,18 @@
"unicode_decimal": 59237 "unicode_decimal": 59237
}, },
{ {
"icon_id": "1881547", "icon_id": "5327531",
"name": "大数据存储", "name": "过滤器",
"font_class": "dashujucunchu", "font_class": "guolvqi",
"unicode": "e678", "unicode": "e71b",
"unicode_decimal": 59000 "unicode_decimal": 59163
},
{
"icon_id": "5379378",
"name": "20从属连接",
"font_class": "congshulianjie",
"unicode": "e6ee",
"unicode_decimal": 59118
}, },
{ {
"icon_id": "2584358", "icon_id": "2584358",
@ -2351,11 +2358,25 @@
"unicode_decimal": 58967 "unicode_decimal": 58967
}, },
{ {
"icon_id": "4187234", "icon_id": "12621396",
"name": "文件夹", "name": "加上2",
"font_class": "wenjianjia", "font_class": "jiashang1",
"unicode": "e640", "unicode": "e719",
"unicode_decimal": 58944 "unicode_decimal": 59161
},
{
"icon_id": "12826208",
"name": "初始化",
"font_class": "chushihua",
"unicode": "e71c",
"unicode_decimal": 59164
},
{
"icon_id": "12826211",
"name": "测试集",
"font_class": "ceshiji",
"unicode": "e71e",
"unicode_decimal": 59166
} }
] ]
} }

@ -614,7 +614,10 @@ Created by iconfont
<glyph glyph-name="reset" unicode="&#59390;" d="M256 384H170.666667c0-185.002667 156.288-341.333333 341.333333-341.333333s341.333333 156.330667 341.333333 341.333333-156.288 341.333333-341.333333 341.333333V810.666667L342.4 682.666667 512 554.666667V640c138.752 0 256-117.248 256-256s-117.248-256-256-256-256 117.248-256 256zM640 384c0 71.210667-56.704 128-128 128s-128-56.789333-128-128 56.704-128 128-128 128 56.789333 128 128z" horiz-adv-x="1024" /> <glyph glyph-name="reset" unicode="&#59390;" d="M256 384H170.666667c0-185.002667 156.288-341.333333 341.333333-341.333333s341.333333 156.330667 341.333333 341.333333-156.288 341.333333-341.333333 341.333333V810.666667L342.4 682.666667 512 554.666667V640c138.752 0 256-117.248 256-256s-117.248-256-256-256-256 117.248-256 256zM640 384c0 71.210667-56.704 128-128 128s-128-56.789333-128-128 56.704-128 128-128 128 56.789333 128 128z" horiz-adv-x="1024" />
<glyph glyph-name="zhongzhi1" unicode="&#58889;" d="M511.99872 892.544C229.93792 892.544 1.28 664.86016 1.28 384.00256 1.28 103.13984 229.93792-124.544 511.99872-124.544 794.06592-124.544 1022.72 103.13984 1022.72 384.00256 1022.72 664.86016 794.06592 892.544 511.99872 892.544L511.99872 892.544zM520.3072 23.71968c-188.20096 0-341.3312 152.47616-341.3312 339.87584 0 187.3984 153.13024 339.87456 341.3312 339.87456l0.02816 0L520.33536 777.35552l178.08384-118.21696-178.08384-118.21952L520.33536 614.8096l-0.02816 0c-139.10784 0-252.28544-112.69376-252.28544-251.21536 0-138.5152 113.1776-251.21152 252.28544-251.21152s252.28672 112.69632 252.28672 251.21152c0 24.50432 19.91168 44.33152 44.52224 44.33152 24.60928 0 44.52224-19.8272 44.52224-44.33152C861.63712 176.19584 708.50304 23.71968 520.3072 23.71968L520.3072 23.71968zM520.3072 23.71968" horiz-adv-x="1024" /> <glyph glyph-name="guolvqi" unicode="&#59163;" d="M908.6 761.3c6.5-15.5 3.8-28.8-8-39.7L620.9 441.9V21c0-15.8-7.4-27.1-22.1-33.5-4.9-2-9.7-2.9-14.2-2.9-10.3 0-18.7 3.6-25.5 10.7L413.8 140.8c-7.2 7.2-10.7 15.7-10.7 25.5V441.9L123.4 721.6c-11.7 11-14.3 24.2-8 39.7 6.5 14.8 17.5 22.1 33.5 22.1H875c16 0.1 27.2-7.3 33.6-22.1z" horiz-adv-x="1024" />
<glyph glyph-name="congshulianjie" unicode="&#59118;" d="M844.8 230.4a128 128 0 0 1-125.44-102.4H358.4a102.4 102.4 0 0 0 0 204.8h307.2a153.6 153.6 0 0 1 0 307.2H304.64a128 128 0 1 1 0-51.2H665.6a102.4 102.4 0 0 0 0-204.8H358.4a153.6 153.6 0 0 1 0-307.2h360.96a128 128 0 1 1 125.44 153.6z m0-204.8a76.8 76.8 0 1 0 76.8 76.8 76.8 76.8 0 0 0-76.8-76.8z" horiz-adv-x="1024" />
<glyph glyph-name="default" unicode="&#59007;" d="M512.020 822.323c-239.75 0-434.093-195.721-434.093-437.159s194.342-437.159 434.093-437.159 434.112 195.721 434.112 437.159-194.362 437.159-434.112 437.159zM729.087 372.55c0-18.589-14.961-33.649-33.397-33.649h-367.321c-18.434 0-33.377 15.058-33.377 33.649v33.61c0 18.59 14.941 33.649 33.377 33.649h367.321c18.435 0 33.397-15.058 33.397-33.649v-33.61z" horiz-adv-x="1024" /> <glyph glyph-name="default" unicode="&#59007;" d="M512.020 822.323c-239.75 0-434.093-195.721-434.093-437.159s194.342-437.159 434.093-437.159 434.112 195.721 434.112 437.159-194.362 437.159-434.112 437.159zM729.087 372.55c0-18.589-14.961-33.649-33.397-33.649h-367.321c-18.434 0-33.377 15.058-33.377 33.649v33.61c0 18.59 14.941 33.649 33.377 33.649h367.321c18.435 0 33.397-15.058 33.397-33.649v-33.61z" horiz-adv-x="1024" />
@ -1028,6 +1031,12 @@ Created by iconfont
<glyph glyph-name="wenjianjia" unicode="&#58944;" d="M957.3 464.4v56.7c0 57.8-47 104.8-104.8 104.8H510.1v46.8c0 57.8-47 104.8-104.8 104.8H172.6c-57.8 0-104.8-47-104.8-104.8v-208.3h889.5zM67.8 394.8v-304.5c0-57.8 47-104.8 104.8-104.8h680c57.8 0 104.8 47 104.8 104.8V394.8H67.8z" horiz-adv-x="1024" /> <glyph glyph-name="wenjianjia" unicode="&#58944;" d="M957.3 464.4v56.7c0 57.8-47 104.8-104.8 104.8H510.1v46.8c0 57.8-47 104.8-104.8 104.8H172.6c-57.8 0-104.8-47-104.8-104.8v-208.3h889.5zM67.8 394.8v-304.5c0-57.8 47-104.8 104.8-104.8h680c57.8 0 104.8 47 104.8 104.8V394.8H67.8z" horiz-adv-x="1024" />
<glyph glyph-name="chushihua" unicode="&#59164;" d="M511.682434-128A468.457376 468.457376 0 0 0 44.559694 340.457376a66.73182 66.73182 0 0 0 133.46364 0A333.6591 333.6591 0 1 1 511.682434 675.451113a330.989827 330.989827 0 0 1-235.785764-98.095776 66.73182 66.73182 0 0 0-111.2197 66.73182l60.503517 203.309612a66.798552 66.798552 0 1 0 128.125094-37.814698l-9.564894-31.808835A468.234937 468.234937 0 1 0 511.682434-128zM600.658194 183.41516h-133.46364a66.73182 66.73182 0 0 0-66.73182 66.73182V472.58638a66.73182 66.73182 0 0 0 133.46364 0v-155.70758h66.73182a66.73182 66.73182 0 0 0 0-133.46364z" horiz-adv-x="1024" />
<glyph glyph-name="ceshiji" unicode="&#59166;" d="M536.332172 333.97898a75.330291 75.330291 0 0 0-29.985844 6.338471l-463.195967 207.95061a73.136205 73.136205 0 0 0 0 133.351681l463.195967 207.95061a73.136205 73.136205 0 0 0 59.971688 0l463.195966-207.95061a73.136205 73.136205 0 0 0 0-133.351681l-463.195966-207.95061a75.330291 75.330291 0 0 0-29.985844-6.338471zM251.832333 614.822008L536.332172 487.321224l284.499838 127.500784L536.332172 742.56658zM536.332172 102.868571a73.136205 73.136205 0 0 0-31.204781 7.069834l-463.195967 219.408615a73.184963 73.184963 0 0 0 62.409562 132.376532L536.332172 257.429752l431.259823 215.020443a73.136205 73.136205 0 0 0 65.33501-130.913807l-463.195966-230.866621a73.136205 73.136205 0 0 0-33.398867-7.801196zM536.332172-127.99805a73.136205 73.136205 0 0 0-31.204781 7.069833l-463.195967 219.408616a73.136205 73.136205 0 0 0 62.409562 131.888957L536.332172 26.319343l431.259823 215.264231a73.136205 73.136205 0 0 0 65.33501-130.913807l-463.195966-230.866621A73.136205 73.136205 0 0 0 536.332172-127.99805z" horiz-adv-x="1073" />
</font> </font>

Before

Width:  |  Height:  |  Size: 410 KiB

After

Width:  |  Height:  |  Size: 412 KiB

@ -2,12 +2,7 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<!--<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">-->
<!-- width=device-width, initial-scale=1 , shrink-to-fit=no -->
<!-- <meta name="viewport" content=""> -->
<meta name=”Keywords” Content=”EduCoder,信息技术实践教学,精品课程网,慕课MOOC″> <meta name=”Keywords” Content=”EduCoder,信息技术实践教学,精品课程网,慕课MOOC″>
<meta name=”Keywords” Content=”实践课程,项目实战,java实训,python实战,人工智能技术,后端开发学习,移动开发入门″> <meta name=”Keywords” Content=”实践课程,项目实战,java实训,python实战,人工智能技术,后端开发学习,移动开发入门″>
<meta name=”Keywords” Content=”翻转课堂,高效课堂创建,教学模式″> <meta name=”Keywords” Content=”翻转课堂,高效课堂创建,教学模式″>
@ -21,30 +16,13 @@
Content=”EduCoder翻转课堂教学模式颠覆了传统教学模式让教师与学生的关系由“权威”变成了“伙伴”。将学习的主动权转交给学生使学生可个性化化学学生的学习主体得到了彰显。”> Content=”EduCoder翻转课堂教学模式颠覆了传统教学模式让教师与学生的关系由“权威”变成了“伙伴”。将学习的主动权转交给学生使学生可个性化化学学生的学习主体得到了彰显。”>
<meta name=”Description” Content=”EduCoder实训项目为单个知识点关卡实践训练帮助学生巩固单一弱点强化学习。 > <meta name=”Description” Content=”EduCoder实训项目为单个知识点关卡实践训练帮助学生巩固单一弱点强化学习。 >
<meta name=”Description” Content=”EduCoder实践教学平台各类大赛为进一步提高各类学生综合运用高级语言程序设计能力培养创新意识和实践探索精神发掘优秀软件人才。 > <meta name=”Description” Content=”EduCoder实践教学平台各类大赛为进一步提高各类学生综合运用高级语言程序设计能力培养创新意识和实践探索精神发掘优秀软件人才。 >
<!-- <meta name="viewport" id="viewport" content="width=device-width, initial-scale=0.3, maximum-scale=0.3, user-scalable=no">--> <meta name="viewport" id="viewport" content="width=device-width, initial-scale=0.3, maximum-scale=0.3">
<!-- <meta name="viewport" id="viewport" content="width=device-width, initial-scale=0.3, maximum-scale=0.3">-->
<meta name="theme-color" content="#000000"> <meta name="theme-color" content="#000000">
<!--<meta http-equiv="cache-control" content="no-cache,no-store, must-revalidate" />-->
<!--<meta http-equiv="pragma" content="no-cache" />-->
<!--<meta http-equiv="Expires" content="0" />-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json"> <link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<!-- <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">-->
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<!-- <title>EduCoder</title>-->
<!--react-ssr-head-->
<script type="text/javascript"> <script type="text/javascript">
window.__isR = true; window.__isR = true;
// 不支持ie9 ie10 // 不支持ie9 ie10
if ( if (
@ -52,60 +30,15 @@
|| navigator.userAgent.indexOf('MSIE 10') != -1) || navigator.userAgent.indexOf('MSIE 10') != -1)
&& &&
location.pathname.indexOf("/compatibility") == -1) { location.pathname.indexOf("/compatibility") == -1) {
debugger;
// location.href = './compatibility'
location.href = '/compatibility.html' location.href = '/compatibility.html'
} }
// const isMobile = (/android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(navigator.userAgent.toLowerCase()));
const isWeiXin = (/MicroMessenger/i.test(navigator.userAgent.toLowerCase()));
if (isWeiXin) {
document.write('<script type="text/javascript" src="/javascripts/wx/jweixin-1.3.0.js"><\/script>');
}
</script> </script>
<!-- <link rel="stylesheet" type="text/css" href="/css/edu-common.css">
<link rel="stylesheet" type="text/css" href="/css/edu-public.css">
<link rel="stylesheet" type="text/css" href="/css/taskstyle.css">
<link rel="stylesheet" type="text/css" href="/css/font-awesome.css">
<link rel="stylesheet" type="text/css" href="/css/editormd.min.css">
<link rel="stylesheet" type="text/css" href="/css/merge.css"> -->
<link rel="stylesheet" type="text/css" href="/css/css_min_all.css">
<!--<link rel="stylesheet" type="text/css" href="/css/css_min_all.css">-->
<!--<link rel="stylesheet" type="text/css" href="//at.alicdn.com/t/font_653600_nm6lho7nxxq.css">-->
<!-- <link href="/react/build/css/iconfont.css" rel="stylesheet" type="text/css"> -->
<!--<link href="http://47.96.87.25:48080/stylesheets/educoder/edu-all.css" rel="stylesheet" type="text/css">-->
<!--<link href="https://pandao.github.io/editor.md/examples/css/style.css" rel="stylesheet" type="text/css">-->
<!--<link href="https://pandao.github.io/editor.md/css/editormd.preview.css" rel="stylesheet" type="text/css">--> <link rel="stylesheet" type="text/css" href="%PUBLIC_URL%/css/css_min_all.css">
<!-- <link href="https://testeduplus2.educoder.net/stylesheets/css/edu-common.css" rel="stylesheet" type="text/css"> <link rel="stylesheet" type="text/css" href="%PUBLIC_URL%/css/iconfont.css">
<link href="https://testeduplus2.educoder.net/stylesheets/educoder/edu-main.css" rel="stylesheet" type="text/css">
<link href="https://testeduplus2.educoder.net/stylesheets/educoder/antd.min.css" rel="stylesheet" type="text/css"> -->
<!-- <link rel="stylesheet" type="text/css" href="https://www.educoder.net/stylesheets/css/font-awesome.css?1510652321"> -->
<!--<link rel="stylesheet" type="text/css" href="http://47.96.87.25:48080/stylesheets/educoder/iconfont/iconfont.css">-->
<!--需要去build js配置-->
<link rel="stylesheet" type="text/css" href="/css/iconfont.css">
<link rel="stylesheet" type="text/css" href="https://cdn.bootcss.com/quill/1.3.7/quill.core.min.css"> <link rel="stylesheet" type="text/css" href="https://cdn.bootcss.com/quill/1.3.7/quill.core.min.css">
<style>
/*<!--去除浏览器点击操作后有蓝色的底块-->*/
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
</style>
</head> </head>
@ -115,73 +48,12 @@
</noscript> </noscript>
<!--用于markdown转html --> <!--用于markdown转html -->
<div id="md_div" style="display: none;"></div> <div id="md_div" style="display: none;"></div>
<div id="root" class="page -layout-v -fit widthunit"> <div id="root" class="page -layout-v -fit widthunit"></div>
<!--<div class="d2-home">-->
<!--<div class="d2-home__main">-->
<!--&lt;!&ndash;<img class="d2-home__loading"&ndash;&gt;-->
<!--&lt;!&ndash;src="loading-spin.svg"&ndash;&gt;-->
<!--&lt;!&ndash;alt="loading">&ndash;&gt;-->
<!--<div class="lds-ripple"><div></div><div></div></div>-->
<!--<div class="d2-home__title">-->
<!--正在加载资源-->
<!--</div>-->
<!--<div class="d2-home__sub-title">-->
<!--加载资源可能需要较多时间 请耐心等待-->
<!--</div>-->
<!--</div>-->
<!--<div class="d2-home__footer">-->
<!--&lt;!&ndash;<a href="www.educoder.net"&ndash;&gt;-->
<!--&lt;!&ndash;target="_blank">&ndash;&gt;-->
<!--&lt;!&ndash;&ndash;&gt;-->
<!--&lt;!&ndash;</a>&ndash;&gt;-->
<!--EduCoder-->
<!--</div>-->
<!--</div>-->
</div>
<div id="picture_display" style="display: none;"></div> <div id="picture_display" style="display: none;"></div>
<!-- js css合并 文件优先级的问题 --> <!-- js css合并 文件优先级的问题 -->
<script type="text/javascript" src="/js/js_min_all.js"></script> <script type="text/javascript" src="%PUBLIC_URL%/js/js_min_all.js"></script>
<script type="text/javascript" src="/js/flv.min.js"></script> <script type="text/javascript" src="%PUBLIC_URL%/js/flv.min.js"></script>
<!-- 在tpi js里加载这3个脚本 -->
<script>
(function () { // Scoping function to avoid globals
var href = location.href;
if (window.location.port === "3007") {
if (href.indexOf('/tasks/') != -1) {
document.write('<script type="text/javascript" src="https://newweb.educoder.net/assets/kindeditor/kindeditor.js"><\/script>');
// build.js中会将这个url附加一个前缀 react/build
document.write('<script type="text/javascript" src="/js/create_kindeditor.js"><\/script>');
document.write('<script type="text/javascript" src="https://newweb.educoder.net/javascripts/educoder/edu_application.js"><\/script>');
} else if (href.indexOf('/paths/') != -1) {
document.write('<script type="text/javascript" src="https://newweb.educoder.net/javascripts/educoder/edu_application.js"><\/script>');
}
} else {
if (href.indexOf('/tasks/') != -1) {
document.write('<script type="text/javascript" src="/assets/kindeditor/kindeditor.js"><\/script>');
// build.js中会将这个url附加一个前缀 react/build
document.write('<script type="text/javascript" src="/js/create_kindeditor.js"><\/script>');
document.write('<script type="text/javascript" src="/javascripts/educoder/edu_application.js"><\/script>');
} else if (href.indexOf('/paths/') != -1) {
document.write('<script type="text/javascript" src="/javascripts/educoder/edu_application.js"><\/script>');
}
}
})();
</script>
<!-- <script type="text/javascript" src="https://testeduplus2.educoder.net/assets/kindeditor/kindeditor.js"></script>
<script type="text/javascript" src="/js/create_kindeditor.js"></script>
<script type="text/javascript" src="https://testeduplus2.educoder.net/javascripts/educoder/edu_application.js"></script> -->
<script type="text/javascript" src="https://cdn.bootcss.com/quill/1.3.7/quill.core.min.js"></script> <script type="text/javascript" src="https://cdn.bootcss.com/quill/1.3.7/quill.core.min.js"></script>
<!-- <script>-->
<!-- document.body.addEventListener('touchmove', function (e) {-->
<!-- e.preventDefault(); //阻止默认的处理方式(阻止下拉滑动的效果)-->
<!-- }, {passive: false});-->
<!-- </script>-->
</body> </body>
</html> </html>

@ -313,16 +313,10 @@ $(function(){
window.top.__updateWebsshRows && window.top.__updateWebsshRows(rows) window.top.__updateWebsshRows && window.top.__updateWebsshRows(rows)
} }
window.refresh_editor_monaco = function(height) { window.refresh_editor_monaco = function(height) {
console.log('refresh_editor_monaco')
if (window.editor_monaco) { if (window.editor_monaco) {
height && $('#codetab_con_1').height(height) height && $('#codetab_con_1').height(height)
window.editor_monaco.layout(); window.editor_monaco.layout();
} }
// if ($('#game_operate_action').width() < 720) {
// $('#game_operate_action .time_limit').hide()
// } else {
// $('#game_operate_action .time_limit').show()
// }
} }
// end; // end;
//解決IE瀏覽器大小改變時webssh佈局變亂。 //解決IE瀏覽器大小改變時webssh佈局變亂。

@ -1,172 +0,0 @@
其他的文档位置:
/educoder/public/react/public/js/readme.txt 关于js_min_all
/educoder/educoder/public/react/scripts/readme-cdn.txt 关于CDN
/educoder/public/react/src/modules/page/readme.txt 关于TPI
/educoder/public/editormd/lib/readme-marked.txt 关于md编辑器 marked.js
1、 安装node v6.9.x此安装包含了node和npm。
2、 安装cnpm命令行 npm install -g cnpm --registry=https://registry.npm.taobao.org
3、 安装依赖的js库public/react目录下<即项目package.json所在目录>,开启命令行): cnpm install
4、 如果你的ruby服务使用的是3000端口则需要在package.json中修改"port"参数的值
5、 启动服务(命令行-目录同3 npm start
6、 build初始化 npm run build
注意:
1、cnpm install 之前先需要修改下ruby mine的一个settings防止ruby mine对node_modules目录里的内容建索引详情见线上文档-react开发环境搭建
线上文档-react开发环境搭建 地址: https://www.trustie.net/boards/6862/topics/46425
2、package.json中配置
"proxy": "http://localhost:3000",
"port": "3007"
目前暂时必须写为和上面的一样ruby服务端口为3000node服务端口为3007当当前端口为3007时程序会将axios发出的请求转到localhost:3000上进行跨域请求。
3、静态js加载问题
editormd源码改动注释掉了564行 加载codemirror/codemirror.min的js代码。因为codemirror 已经加载了codemirror对象会带有插件重复加载会覆盖全局codemirror对象使得之前加载的插件失效
----------------------------------------------------------------------------------------------
React开发相关知识点
需要了解的ES6的知识 https://www.trustie.net/boards/6862/topics/46427
----------------------------------------------------------------------------------------------
新加入的lib有 axios、material-ui、lodash、classnames、moment、immutability-helper
rc-tree、rc-form 、rc-rate、rc-pagination、rc-select 、showdown
考虑替代删除确认弹出框的组件http://react-component.github.io/tooltip/examples/onVisibleChange.html
----------------------------------------------------------------------------------------------
TPI State整理 START
----------------------------------------------------------------------------------------------
TPIContextProvider 详情接口的所有state
Index.js
taskListLoading
challenges
challengesDrawerOpen
MainContentContainer.js
repositoryCode: '',
currentPath: '', // 当前所选的path可能是一个只读的path只读path的话challenge.athIndex为-1
isEditablePath // 是否是可以编辑的path
open: false, // 繁忙等级等提示用Dialog TODO 考虑重构封装到根组件
gameBuilding: false, // 评测中标志
codeStatus: 2, // 0 已修改 1 保存中 2 已保存 3 保存失败
codeLoading: false, // code加载中
resetCodeDialogOpen: false, // TODO考虑重构封装到根组件
resetPassedCodeDialogOpen: false, // TODO考虑重构封装到根组件
LeftViewContainer.js
tabIndex: 0, 页签index
dialogOpen: false,
gameAnswer: '', 答案
snackbarOpen: false,
comments: [], 评论
comment_count_without_reply: 0, 评论数量 TODO 和详情接口字段重复
// 默认pageSize为10
currentPage: 1, 评论分页
loadingComments: true, 评论加载中
gotNewReply: false, 新的回复
CodeRepositoryViewContainer.js
drawerOpen: false,
loadingFirstRepoFiles: false, drawer里的loading状态
fileTreeData: "", 文件树
codeRepositoryViewExpanded: false, 展开状态
CodeEvaluateView.js
testSetsInitedArray: testSetsExpandedArrayInitVal.slice(0), 测试集是否初始化标志
evaluateViewExpanded: false,
tabIndex: 1, 页签index
----------------------------------------------------------------------------------------------
TPI State整理 END
----------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------
重要TPI实现时修改的js库的记录 START
----------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------
重要TPI实现时修改的js库的记录 END
----------------------------------------------------------------------------------------------
create_kindeditor.js __isR 表示是react环境react环境下采用事件通知react组件来处理
if (window['__isR'] === true) {
$(document).trigger("onReply", { commentContent:tContents, id:id, editor:params.editor } );
} else {
params.form.submit();
}
editormd.min.js 直接注释掉了codemirror.min的加载应该改成有codeMirror了则不加载
// codemirror 已经加载了codemirror会有插件重复加载会使得之前加载的插件失效
// editormd.loadScript(loadPath + "codemirror/codemirror.min", function() {
对应提交项
Revision: 73d95ce266d5d7e55a3a88d08d1247b3a08c7caf
Date: 2018/4/2 16:12:21
Message: 切下一题时更新左侧editormd里的内容更新右侧codemirror内容。
js_min_all.js 最后面手动加入了若干js代码还没做分离、再合并处理 date:180507
is_cdn_link tpi_html_show方法
----------------------------------------------------------------------------------------------
TPM使用react实现的利弊 START
----------------------------------------------------------------------------------------------
1、全部使用react重写
做法第一屏使用新接口之前的js脚本还是继续使用有必要的话需要局部刷新的将部分jquery实现改为react实现
利:
tpi中评论组件、文件树组件方便复用
js、css库管理方便
暂时不依赖于react的状态管理
之前的ajax请求还是可以暂时复用
弊:
接口评估?
rails模板要改成jsx语法
头部功能区域、底部静态链接区域会存在重复代码 react版和非react版
codemirror等组件的使用会不会有问题
学习成本
目前决定新页面或者评论组件所在页面使用react实现
----------------------------------------------------------------------------------------------
TPM使用react实现的利弊 END
----------------------------------------------------------------------------------------------
其他方式comments组件build到新入口后将代码copy到rails页面
----------------------------------------------------------------------------------------------
不错的库 START
----------------------------------------------------------------------------------------------
https://livicons.com/icons-original -- 收费 动画icon
https://github.com/maxwellito/vivus -- 让SVG标签动起来
http://ianlunn.github.io/Hover/ -- hover 动画
https://github.com/legomushroom/mojs
https://github.com/juliangarnier/anime --js动画
https://codepen.io/juliangarnier/pen/gmOwJX
https://github.com/daneden/animate.css
A responsive tour snippet, with a step-by-step guide(onboarding) to help users understand how to use your website.
https://github.com/sorich87/bootstrap-tour
https://github.com/linkedin/hopscotch
https://github.com/Robophil/Product-Tour
code editor
https://microsoft.github.io/monaco-editor/

@ -228,6 +228,7 @@ function generateNewIndexJsp() {
// ${cdnHost} 加了cdn后这个文件里的字体文件加载会有跨域的报错 ../fonts/fontawesome-webfont.eot // ${cdnHost} 加了cdn后这个文件里的字体文件加载会有跨域的报错 ../fonts/fontawesome-webfont.eot
// TODO tpi 评测结果关闭也使用了fontawesome // TODO tpi 评测结果关闭也使用了fontawesome
.replace(flvMinAllRegex,``)
.replace('/css/css_min_all.css', `${cdnHost}/react/build/css/css_min_all.css?v=${newVersion}`) .replace('/css/css_min_all.css', `${cdnHost}/react/build/css/css_min_all.css?v=${newVersion}`)
.replace('/css/iconfont.css', `${cdnHost}/react/build/css/iconfont.css?v=${newVersion}`) .replace('/css/iconfont.css', `${cdnHost}/react/build/css/iconfont.css?v=${newVersion}`)
.replace(/\/js\/create_kindeditor.js/g, `${cdnHost}/react/build/js/create_kindeditor.js?v=${newVersion}`) .replace(/\/js\/create_kindeditor.js/g, `${cdnHost}/react/build/js/create_kindeditor.js?v=${newVersion}`)

@ -1,98 +0,0 @@
var fs = require('fs');
var uglify = require("uglify-js");
var path = require('path');
var concat = require('concat')
var results = [];
var walk = function(dir, done) {
fs.readdir(dir, function(err, list) {
console.log(list)
if (err) return done(err);
var pending = list.length;
if (!pending) return done(null, results);
list.forEach(function(file) {
file = path.resolve(dir, file);
fs.stat(file, function(err, stat) {
if (stat && stat.isDirectory()) {
walk(file, function(err, res) {
// results = results.concat(res);
if (!--pending) done(null, results);
});
} else {
results.push(file);
if (!--pending) done(null, results);
}
});
});
});
};
// 需要输出文件名数组时改为true
var jsDir = './public/js/';
var cssDir = './public/css'
// true &&
false &&
walk(cssDir, function() {
console.log('results', results.length, results)
})
// return;
// ----------------------------------------------------------------------------- CSS
var cssResults = [
'D:\\Code\\trustieplus\\public\\react\\public\\css\\edu-common.css',
'D:\\Code\\trustieplus\\public\\react\\public\\css\\edu-public.css',
'D:\\Code\\trustieplus\\public\\react\\public\\css\\taskstyle.css' ,
'D:\\Code\\trustieplus\\public\\react\\public\\css\\font-awesome.css',
'D:\\Code\\trustieplus\\public\\react\\public\\css\\editormd.min.css',
'D:\\Code\\trustieplus\\public\\react\\public\\css\\merge.css',
]
concat(cssResults, './public/css/css_min_all.css')
return;
// ----------------------------------------------------------------------------- JS
var _results = [
'D:\\Code\\trustieplus\\public\\react\\public\\js\\jquery-1.8.3.min.js',
'D:\\Code\\trustieplus\\public\\react\\public\\js\\editormd\\underscore.min.js',
'D:\\Code\\trustieplus\\public\\react\\public\\js\\editormd\\marked.min.js',
'D:\\Code\\trustieplus\\public\\react\\public\\js\\editormd\\prettify.min.js',
'D:\\Code\\trustieplus\\public\\react\\public\\js\\editormd\\raphael.min.js',
'D:\\Code\\trustieplus\\public\\react\\public\\js\\editormd\\sequence-diagram.min.js',
'D:\\Code\\trustieplus\\public\\react\\public\\js\\editormd\\flowchart.min.js',
'D:\\Code\\trustieplus\\public\\react\\public\\js\\editormd\\jquery.flowchart.min.js',
'D:\\Code\\trustieplus\\public\\react\\public\\js\\editormd\\editormd.min.js',
'D:\\Code\\trustieplus\\public\\react\\public\\js\\codemirror\\codemirror.js',
'D:\\Code\\trustieplus\\public\\react\\public\\js\\codemirror\\mode\\javascript.js',
'D:\\Code\\trustieplus\\public\\react\\public\\js\\diff_match_patch.js',
'D:\\Code\\trustieplus\\public\\react\\public\\js\\merge.js',
'D:\\Code\\trustieplus\\public\\react\\public\\js\\edu_tpi.js',
]
concat(_results, './public/js/js_min_all.js')
// var uglified = uglify.minify(['./public/js/merge.js']);
// console.log('uglified', uglified)
// fs.writeFile('concat.min.js', uglified.code, function (err){
// if(err) {
// console.log(err);
// } else {
// console.log("Script generated and saved:", 'concat.min.js');
// }
// });
// var uglified = uglify.minify(['file1.js', 'file2.js', 'file3.js']);

@ -1,23 +0,0 @@
var fs2 = require('fs');
function generateNewIndexJsp() {
var filePath = './build/index.html';
var outputPath = filePath
fs2.readFile(filePath, 'utf8', function (err,data) {
if (err) {
return console.log(err);
}
var result = data
.replace('/js/create_kindeditor.js', '/react/build/js/create_kindeditor.js')
.replace(/https:\/\/testeduplus2.educoder.net/g, '');
// .replace(/http:\/\/testbdweb.educoder.net/g, '');
.replace('/css/css_min_all.css', '/react/build/css/css_min_all.css');
fs2.writeFile(outputPath, result, 'utf8', function (err) {
if (err) return console.log(err);
});
});
}

@ -1,16 +0,0 @@
目前是判断域名的方式动态访问对应的cdn资源
静态资源处理在build.js中如下代码
if (window.location.host == 'pre-newweb.educoder.net') {
_host = 'https://testali-cdn.educoder.net/react/build/'
} else if (window.location.host == 'www.educoder.net') {
_host = 'https://ali-cdn.educoder.net/react/build/'
}
只对预上线和正式版做了处理
动态的chunk资源处理在public-path.js中如下代码
if ( window.location.host == 'pre-newweb.educoder.net') {
__webpack_public_path__ = 'https://testali-cdn.educoder.net/react/build/'
} else if ( window.location.host == 'www.educoder.net') {
__webpack_public_path__ = 'https://ali-cdn.educoder.net/react/build/'
}

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

@ -1,27 +0,0 @@
'use strict';
// Do this as the first thing so that any code reading it knows the right env.
process.env.BABEL_ENV = 'test';
process.env.NODE_ENV = 'test';
process.env.PUBLIC_URL = '';
// Makes the script crash on unhandled rejections instead of silently
// ignoring them. In the future, promise rejections that are not handled will
// terminate the Node.js process with a non-zero exit code.
process.on('unhandledRejection', err => {
throw err;
});
// Ensure environment variables are read.
require('../config/env');
const jest = require('jest');
const argv = process.argv.slice(2);
// Watch unless on CI or in coverage mode
if (!process.env.CI && argv.indexOf('--coverage') < 0) {
argv.push('--watch');
}
jest.run(argv);

@ -1,17 +1,13 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import './public-path'; import './public-path';
import './App.css';
import { ConfigProvider } from 'antd'
import zhCN from 'antd/lib/locale-provider/zh_CN'; import zhCN from 'antd/lib/locale-provider/zh_CN';
import { ConfigProvider } from 'antd'
import { import {
BrowserRouter as Router, BrowserRouter as Router,
Route, Route,
Switch Switch
} from 'react-router-dom'; } from 'react-router-dom';
import axios from 'axios'; import axios from 'axios';
import '@icedesign/base/dist/ICEDesignBase.css';
import '@icedesign/base/index.scss';
import LoginDialog from './modules/login/LoginDialog'; import LoginDialog from './modules/login/LoginDialog';
import Notcompletedysl from './modules/user/Notcompletedysl'; import Notcompletedysl from './modules/user/Notcompletedysl';
@ -21,42 +17,18 @@ import Addcourses from "./modules/courses/coursesPublic/Addcourses";
import AccountProfile from "./modules/user/AccountProfile"; import AccountProfile from "./modules/user/AccountProfile";
import Accountnewprofile from './modules/user/Accountnewprofile'; import Accountnewprofile from './modules/user/Accountnewprofile';
import Certifiedprofessional from './modules/modals/Certifiedprofessional'; import Certifiedprofessional from './modules/modals/Certifiedprofessional';
import Loading from './Loading' import Loading from './Loading'
import Loadable from 'react-loadable';
import moment from 'moment' import moment from 'moment'
import { MuiThemeProvider, createMuiTheme } from 'material-ui/styles';
// import './AppConfig'
import history from './history'; import history from './history';
import { SnackbarHOC } from 'educoder' import { SnackbarHOC,Loadable } from 'educoder'
import { initAxiosInterceptors } from './AppConfig' import { initAxiosInterceptors } from './AppConfig'
import { Provider } from 'react-redux'; import { Provider } from 'react-redux';
import configureStore from './redux/stores/configureStore'; import configureStore from './redux/stores/configureStore';
// tpi需要这个来加载css
import { TPMIndexHOC } from './modules/tpm/TPMIndexHOC';
const store = configureStore(); const store = configureStore();
const theme = createMuiTheme({
palette: {
primary: {
main: '#4CACFF',
contrastText: 'rgba(255, 255, 255, 0.87)'
},
secondary: { main: '#4CACFF' }, // #11cb5f This is just green.A700 as hex.
},
});
//
// const Trialapplication= Loadable({
// loader: () =>import('./modules/login/Trialapplication'),
// loading:Loading,
// })
//登入 //登入
const EducoderLogin = Loadable({ const EducoderLogin = Loadable({
loader: () => import('./modules/login/EducoderLogin'), loader: () => import('./modules/login/EducoderLogin'),
@ -85,10 +57,6 @@ const Otherloginsqq = Loadable({
loader: () => import('./modules/login/Otherloginqq'), loader: () => import('./modules/login/Otherloginqq'),
loading: Loading, loading: Loading,
}) })
// const TestIndex = Loadable({
// loader: () => import('./modules/test'),
// loading: Loading,
// })
const IndexWrapperComponent = Loadable({ const IndexWrapperComponent = Loadable({
loader: () => import('./modules/page/IndexWrapper'), loader: () => import('./modules/page/IndexWrapper'),
@ -125,49 +93,12 @@ const SearchPage = Loadable({
loading: Loading, loading: Loading,
}) })
// 课堂讨论
// const BoardIndex = Loadable({
// loader: () => import('./modules/courses/boards/BoardIndex'),
// loading:Loading,
// })
// //课堂普通作业&分组作业
// const CoursesWorkIndex = Loadable({
// loader: () => import('./modules/courses/busyWork/Index'),
// loading:Loading,
// })
//
// const TPMShixunchildIndexComponent = Loadable({
// loader: () => import('./modules/tpm/shixunchild/ShixunChildIndex'),
// loading: Loading,
// })
// const TPMshixunfork_listIndexComponent = Loadable({
// loader: () => import('./modules/tpm/shixunchild/Shixunfork_list'),
// loading: Loading,
// })
const ForumsIndexComponent = Loadable({ const ForumsIndexComponent = Loadable({
loader: () => import('./modules/forums/ForumsIndex'), loader: () => import('./modules/forums/ForumsIndex'),
loading: Loading, loading: Loading,
}) })
// trustie plus forum
// const TPForumsIndexComponent = Loadable({
// loader: () => import('./modules/tp-forums/TPForumsIndex'),
// loading: Loading,
// })
// const TestPageComponent = Loadable({
// loader: () => import('./modules/page/Index'),
// loading: Loading,
// })
//新建实训 //新建实训
const Newshixuns = Loadable({ const Newshixuns = Loadable({
loader: () => import('./modules/tpm/newshixuns/Newshixuns'), loader: () => import('./modules/tpm/newshixuns/Newshixuns'),
@ -177,7 +108,7 @@ const Newshixuns = Loadable({
//实训首页 //实训首页
const ShixunsHome = Loadable({ const ShixunsHome = Loadable({
loader: () => import('./modules/home/shixunsHome'), loader: () => import('./modules/home'),
loading: Loading, loading: Loading,
}) })
@ -206,21 +137,11 @@ const http500 = Loadable({
loading: Loading, loading: Loading,
}) })
// 登录注册
const LoginRegisterPage = Loadable({
loader: () => import('./modules/user/LoginRegisterPage'),
loading: Loading,
})
const AccountPage = Loadable({ const AccountPage = Loadable({
loader: () => import('./modules/user/AccountPage'), loader: () => import('./modules/user/AccountPage'),
loading: Loading, loading: Loading,
}) })
// 个人主页
const UsersInfo = Loadable({
loader: () => import('./modules/user/usersInfo/Infos'),
loading: Loading,
})
const InfosIndex = Loadable({ const InfosIndex = Loadable({
loader: () => import('./modules/user/usersInfo/InfosIndex'), loader: () => import('./modules/user/usersInfo/InfosIndex'),
loading: Loading, loading: Loading,
@ -238,17 +159,6 @@ const MoopCases = Loadable({
loading: Loading, loading: Loading,
}) })
// 兴趣页面
const Interestpage = Loadable({
loader: () => import('./modules/login/EducoderInteresse'),
loading: Loading,
})
//众包创新
// const ProjectPackages=Loadable({
// loader: () => import('./modules/projectPackages/ProjectPackageIndex'),
// loading: Loading,
// })
//竞赛 //竞赛
const NewCompetitions = Loadable({ const NewCompetitions = Loadable({
@ -352,16 +262,6 @@ const JupyterTPI = Loadable({
loader: () => import('./modules/tpm/jupyter'), loader: () => import('./modules/tpm/jupyter'),
loading: Loading loading: Loading
}); });
// 微信代码编辑器
// const WXCode = Loadable({
// loader: () => import('./modules/wxcode'),
// loading: Loading
// });
// //个人竞赛报名
// const PersonalCompetit = Loadable({
// loader: () => import('./modules/competition/personal/PersonalCompetit.js'),
// loading: Loading,
// });
class App extends Component { class App extends Component {
constructor(props) { constructor(props) {
super(props) super(props)
@ -422,20 +322,6 @@ class App extends Component {
initAxiosInterceptors(this.props); initAxiosInterceptors(this.props);
this.getAppdata(); this.getAppdata();
//
// axios.interceptors.response.use((response) => {
// // console.log("response"+response);
// if(response!=undefined)
// // console.log("response"+response.data.statu);
// if (response&&response.data.status === 407) {
// this.setState({
// isRenders: true,
// })
// }
// return response;
// }, (error) => {
// //TODO 这里如果样式变了会出现css不加载的情况
// });
window.addEventListener('error', (event) => { window.addEventListener('error', (event) => {
const msg = `${event.type}: ${event.message}`; const msg = `${event.type}: ${event.message}`;
@ -522,13 +408,10 @@ class App extends Component {
}; };
render() { render() {
let { mygetHelmetapi } = this.state;
// console.log("appappapp");
// console.log(mygetHelmetapi);
return ( return (
<Provider store={store}> <Provider store={store}>
<ConfigProvider locale={zhCN}> <ConfigProvider locale={zhCN}>
<MuiThemeProvider theme={theme}>
<Accountnewprofile {...this.props}{...this.state} /> <Accountnewprofile {...this.props}{...this.state} />
<LoginDialog {...this.props} {...this.state} Modifyloginvalue={() => this.Modifyloginvalue()}></LoginDialog> <LoginDialog {...this.props} {...this.state} Modifyloginvalue={() => this.Modifyloginvalue()}></LoginDialog>
<Notcompletedysl {...this.props} {...this.state}></Notcompletedysl> <Notcompletedysl {...this.props} {...this.state}></Notcompletedysl>
@ -596,19 +479,18 @@ class App extends Component {
render={ render={
(props) => { (props) => {
return (<EducoderLogin {...this.props} {...props} {...this.state} />) return (<Topicbank {...this.props} {...props} {...this.state} />)
}
} }
/> }></Route>
<Route {/*/!*众包创新*!/*/}
path="/register" {/*<Route path={"/crowdsourcing"} component={ProjectPackages}/>*/}
{/*竞赛*/}
<Route path={"/competitions"}
render={ render={
(props) => { (props) => {
return (<EducoderLogin {...this.props} {...props} {...this.state} />) return (<NewCompetitions {...this.props} {...props} {...this.state} />)
} }} />
}
/>
<Route <Route
path="/otherloginstart" component={Otherloginstart} path="/otherloginstart" component={Otherloginstart}
/> />
@ -822,9 +704,10 @@ class App extends Component {
</Switch> </Switch>
</Router> </Router>
</MuiThemeProvider>
</ConfigProvider> </ConfigProvider>
</Provider> </Provider >
); );
} }
} }

@ -1,9 +0,0 @@
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
it('renders without crashing', () => {
const div = document.createElement('div');
ReactDOM.render(<App />, div);
ReactDOM.unmountComponentAtNode(div);
});

@ -139,7 +139,7 @@ export function initAxiosInterceptors(props) {
proxy = "https://test-newweb.educoder.net" proxy = "https://test-newweb.educoder.net"
// proxy="https://test-jupyterweb.educoder.net" // proxy="https://test-jupyterweb.educoder.net"
// proxy="https://test-newweb.educoder.net" // proxy="https://test-newweb.educoder.net"
// proxy="https://test-jupyterweb.educoder.net" proxy="https://test-jupyterweb.educoder.net"
//proxy="https://test-jupyterweb.educoder.net/" //proxy="https://test-jupyterweb.educoder.net/"

@ -1,12 +0,0 @@
import Loadable from 'react-loadable';
import Loading from "./Loading";
const CustomLoadable = (loader, loading = Loading) => {
return Loadable({
loader,
loading
})
}
export default CustomLoadable

@ -1,21 +1,9 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import { Spin } from 'antd';
class Loading extends Component { class Loading extends Component {
componentDidUpdate(prevProps, prevState) {
if (!prevProps.error && this.props.error) {
console.log(this.props.error)
window.location.reload()
}
}
render() { render() {
// Loading
return ( return (
<div className="App" style={{minHeight: '800px',width:"100%"}}> <div className="App" style={{ minHeight: '800px', width: "100%" }}>
<style> <style>
{ {
` `
@ -25,7 +13,7 @@ class Loading extends Component {
` `
} }
</style> </style>
<Spin size="large" className={"margintop"}/> <p>loading...</p>
</div> </div>
); );
} }

@ -1,6 +1,6 @@
import React, { Component } from 'react'; import React, { Component } from 'react'
import { BrowserRouter as Router, Route, Link } from "react-router-dom"; import { Link } from "react-router-dom"
class NotFoundPage extends Component { class NotFoundPage extends Component {
render() { render() {
@ -8,29 +8,28 @@ class NotFoundPage extends Component {
<div className="App"> <div className="App">
404 Page 404 Page
<br></br> <br></br>
 
<Link to="/tasks/ixq5euhgrf7y">Index</Link> <Link to="/tasks/ixq5euhgrf7y">Index</Link>
|  |
<Link to="/shixuns/uznmbg54/challenges">tpm challenges</Link> <Link to="/shixuns/uznmbg54/challenges">tpm challenges</Link>
|  |
<Link to="/shixuns/uznmbg54/shixun_discuss">tpm discuss</Link> <Link to="/shixuns/uznmbg54/shixun_discuss">tpm discuss</Link>
|  |
<Link to="/forums/categories/all">forums</Link> <Link to="/forums/categories/all">forums</Link>
 |  |
<Link to="/comment">Comment</Link> <Link to="/comment">Comment</Link>
 |  |
<Link to="/testMaterial">testMaterial</Link> <Link to="/testMaterial">testMaterial</Link>
 |  |
<Link to="/testCodeMirror">testCodeMirror</Link> <Link to="/testCodeMirror">testCodeMirror</Link>
 |  |
<Link to="/taskList">taskList</Link> <Link to="/taskList">taskList</Link>
 |  |
<Link to="/testRCComponent">testRCComponent</Link> <Link to="/testRCComponent">testRCComponent</Link>
|  |
<Link to="/tpforums">tpforums</Link> <Link to="/tpforums">tpforums</Link>
|  |
<Link to="/testUrlQuery">url-query test</Link> <Link to="/testUrlQuery">url-query test</Link>
</div> </div>

@ -1,20 +1,17 @@
import React, {Component} from "react"; import React, {Component} from "react"
import {Link, NavLink} from 'react-router-dom'; import {SnackbarHOC,getImageUrl} from 'educoder'
import {WordsBtn, ActionBtn,SnackbarHOC,getImageUrl} from 'educoder'; import axios from 'axios'
import axios from 'axios';
import { import {
notification,
Spin, Spin,
Table, Table,
Pagination, Pagination,
} from "antd"; } from "antd"
import Colleagechart from './colleagechart/Colleagechart' import Colleagechart from './colleagechart/Colleagechart'
import Colleagechartzu from './colleagechart/Colleagechartzu' import Colleagechartzu from './colleagechart/Colleagechartzu'
import {TPMIndexHOC} from "../modules/tpm/TPMIndexHOC"; import TPMIndexHOC from "../modules/tpm/TPMIndexHOC"
import NoneData from './../modules/courses/coursesPublic/NoneData'; import NoneData from './../modules/courses/coursesPublic/NoneData'
import './colleagecss/colleage.css'; import './colleagecss/colleage.css';
import Shixunechart from "../modules/courses/shixunHomework/shixunreport/Shixunechart";
class College extends Component { class College extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
@ -1199,24 +1196,10 @@ class College extends Component {
className="mysjysltable1" className="mysjysltable1"
pagination={false} pagination={false}
loading={studentsloading} loading={studentsloading}
// onChange={this.TablePaginationsy}
/>} />}
</div> </div>
</div> </div>
} }
{/*<div style={{*/}
{/* width:'100%',*/}
{/* padding:'40px'*/}
{/*}}>*/}
{/* <div className="edu-txt-center ">*/}
{/* <Pagination showQuickJumper current={pagess} onChange={this.paginationonChangess}*/}
{/* pageSize={limitss}*/}
{/* total={student_count}></Pagination>*/}
{/* </div>*/}
{/*</div>*/}
</div> </div>
<div className="" style={{ <div className="" style={{
@ -1259,3 +1242,4 @@ class College extends Component {
export default SnackbarHOC() (TPMIndexHOC ( College )); export default SnackbarHOC() (TPMIndexHOC ( College ));

@ -1,5 +1,5 @@
import md5 from 'md5'; import md5 from 'md5';
export function setmiyah(logins){ export default function setmiyah(logins) {
const opens ="79e33abd4b6588941ab7622aed1e67e8"; const opens = "79e33abd4b6588941ab7622aed1e67e8";
return md5(opens+logins); return md5(opens + logins);
} }

@ -4,7 +4,7 @@ export function trigger(eventName, data) {
} }
export function on(eventName, callback) { export function on(eventName, callback) {
$(window).on(eventName, (event, data)=>{ $(window).on(eventName, (event, data) => {
callback && callback(event, data) callback && callback(event, data)
}); });
} }
@ -25,7 +25,7 @@ function onMessageByLocalStorage(eventName, callback) {
console.log('storage event register:', eventName) console.log('storage event register:', eventName)
localStorageMap[eventName] = callback; localStorageMap[eventName] = callback;
} }
window.addEventListener("storage", function(ev) { window.addEventListener("storage", function (ev) {
const cb = localStorageMap[ev.key]; const cb = localStorageMap[ev.key];
// console.log('storage event:', ev) // console.log('storage event:', ev)
if (cb) { if (cb) {
@ -64,7 +64,6 @@ export function broadcastChannelOnmessage(eventName, callback) {
bc = broadcastChannelMap[eventName] bc = broadcastChannelMap[eventName]
} }
bc.onmessage = function (ev) { bc.onmessage = function (ev) {
console.log(ev);
callback && callback(ev) callback && callback(ev)
} }
} }

@ -1,9 +1,9 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { SnackbarHOC } from 'educoder'; import { SnackbarHOC } from 'educoder';
import { TPMIndexHOC } from '../modules/tpm/TPMIndexHOC'; import TPMIndexHOC from '../modules/tpm/TPMIndexHOC';
import {Spin,Alert} from 'antd'; import { Spin, Alert } from 'antd';
class ShowSpin extends Component{ class ShowSpin extends Component {
constructor(props) { constructor(props) {
super(props) super(props)
} }
@ -11,7 +11,7 @@ class ShowSpin extends Component{
render() { render() {
let marigin={ let marigin = {
width: '100%', width: '100%',
minHeight: '500px', minHeight: '500px',
} }
@ -30,4 +30,4 @@ class ShowSpin extends Component{
} }
} }
export default SnackbarHOC() ( TPMIndexHOC(ShowSpin) ); export default SnackbarHOC()(TPMIndexHOC(ShowSpin));

@ -1,13 +1,13 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import Snackbar from 'material-ui/Snackbar'; import { notification, Alert } from 'antd'
import Fade from 'material-ui/transitions/Fade';
import { notification } from 'antd' export default function SnackbarHOC(options = {}) {
export function SnackbarHOC(options = {}) {
return function wrap(WrappedComponent) { return function wrap(WrappedComponent) {
return class Wrapper extends Component { return class Wrapper extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.showSnackbar = this.showSnackbar.bind(this) this.showSnackbar = this.showSnackbar.bind(this)
this.handleSnackbarClose = this.handleSnackbarClose.bind(this)
this.state = { this.state = {
snackbarText: '', snackbarText: '',
snackbarOpen: false, snackbarOpen: false,
@ -22,24 +22,6 @@ export function SnackbarHOC(options = {}) {
}) })
} }
// 全局的snackbar this.props.showSnackbar调用即可
// showSnackbar(description, message = "提示",icon) {
// // this.setState({
// // snackbarOpen: true,
// // snackbarText: text,
// // snackbarVertical: vertical,
// // snackbarHorizontal: horizontal,
// // })
// const data = {
// message,
// description
// }
// if (icon) {
// data.icon = icon;
// }
// notification.open(data);
// }
showSnackbar(text, vertical, horizontal) { showSnackbar(text, vertical, horizontal) {
this.setState({ this.setState({
snackbarOpen: true, snackbarOpen: true,
@ -60,27 +42,12 @@ export function SnackbarHOC(options = {}) {
notification.open(data); notification.open(data);
} }
render() { render() {
const { snackbarOpen, snackbarText, snackbarHorizontal, snackbarVertical } = this.state; const { snackbarOpen, snackbarText } = this.state
return ( return (
<React.Fragment> <React.Fragment>
<Snackbar {snackbarOpen ? <Alert messagg={snackbarText} onClose={this.handleSnackbarClose} /> : null}
className={"rootSnackbar"} <WrappedComponent {...this.props} showSnackbar={this.showSnackbar} showNotification={this.showNotification} >
style={{zIndex:30000}}
open={this.state.snackbarOpen}
autoHideDuration={3000}
anchorOrigin={{ vertical: this.state.snackbarVertical || 'top'
, horizontal: this.state.snackbarHorizontal || 'center' }}
onClose={() => this.handleSnackbarClose()}
transition={Fade}
SnackbarContentProps={{
'aria-describedby': 'message-id',
}}
resumeHideDuration={2000}
message={<span id="message-id">{this.state.snackbarText}</span>}
/>
<WrappedComponent {...this.props} showSnackbar={ this.showSnackbar } showNotification= { this.showNotification } >
</WrappedComponent> </WrappedComponent>
</React.Fragment> </React.Fragment>

@ -1,44 +1,21 @@
import { bytesToSize, getUrl, getUrl2 } from 'educoder'; import { bytesToSize, getUrl, getUrl2 } from 'educoder';
const $ = window.$ const $ = window.$
import showdown from 'showdown'
import showdownKatex from './showdown-katex/showdown-katex'
export function isImageExtension(fileName) { export function isImageExtension(fileName) {
return fileName ? !!(fileName.match(/.(jpg|jpeg|png|gif)$/i)) : false return fileName ? !!(fileName.match(/.(jpg|jpeg|png|gif)$/i)) : false
} }
const katex = showdownKatex()
const converter = new showdown.Converter({
extensions: [katex]
})
export function markdownToHTML(oldContent, selector) { export function markdownToHTML(oldContent) {
window.$('#md_div').html('') if (oldContent) {
// markdown to html return converter.makeHtml(oldContent)
if (selector && oldContent && oldContent.startsWith('<p')) { // 普通html处理
window.$('#' + selector).addClass('renderAsHtml')
window.$('#' + selector).html(oldContent)
} else {
try {
$("#"+selector).html('')
// selector ||
var markdwonParser = window.editormd.markdownToHTML(selector || "md_div", {
markdown: oldContent, // .replace(/▁/g,"▁▁▁"),
emoji: true,
htmlDecode: "style,script,iframe", // you can filter tags decode
taskList: true,
tex: true, // 默认不解析
flowChart: true, // 默认不解析
sequenceDiagram: true // 默认不解析
});
} catch(e) {
console.error(e)
}
// selector = '.' + selector
if (selector) {
return;
}
const content = window.$('#md_div').html()
if (selector) {
window.$(selector).html(content)
}
return content
} }
return oldContent
} }
function _doDownload(options) { function _doDownload(options) {
$.fileDownload(getUrl() + "/api" + options.url, { $.fileDownload(getUrl() + "/api" + options.url, {
@ -66,7 +43,7 @@ export function appendFileSizeToUploadFile(item) {
export function appendFileSizeToUploadFileAll(fileList) { export function appendFileSizeToUploadFileAll(fileList) {
return fileList.map(item => { return fileList.map(item => {
if (item.name.indexOf(uploadNameSizeSeperator) == -1) { if (item.name.indexOf(uploadNameSizeSeperator) == -1) {
return Object.assign({}, item, {name: `${item.name}${uploadNameSizeSeperator}${bytesToSize(item.size)}`}) return Object.assign({}, item, { name: `${item.name}${uploadNameSizeSeperator}${bytesToSize(item.size)}` })
} }
return item return item
}) })
@ -76,4 +53,4 @@ export const uploadNameSizeSeperator = '  '
export const sortDirections = ["ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", export const sortDirections = ["ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend",
"ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend",
"ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend",
"ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", ] "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend",]

@ -1,15 +1,12 @@
import React from "react"; import React from "react";
import md5 from 'md5'; import md5 from 'md5';
import {Input} from "antd"; import { Input } from "antd";
const { Search } = Input; const { Search } = Input;
const $ = window.$; const $ = window.$;
const isDev = window.location.port == 3007; const isDev = window.location.port == 3007;
export const TEST_HOST = "https://test-newweb.educoder.net" export const TEST_HOST = "https://test-newweb.educoder.net"
export function getImageUrl(path) { export function getImageUrl(path) {
// https://www.educoder.net
// https://testbdweb.trustie.net
// const local = 'http://localhost:3000'
const local = 'https://test-newweb.educoder.net' const local = 'https://test-newweb.educoder.net'
if (isDev) { if (isDev) {
return `${local}/${path}` return `${local}/${path}`
@ -17,47 +14,30 @@ export function getImageUrl(path) {
return `/${path}`; return `/${path}`;
} }
export function setImagesUrl(path){ export function setImagesUrl(path) {
const local = 'https://test-newweb.educoder.net' const local = 'https://test-newweb.educoder.net'
let firstStr=path.substr(0,1); let firstStr = path.substr(0, 1);
// console.log(firstStr); if (firstStr == "/") {
if(firstStr=="/"){ return isDev ? `${local}${path}` : `${path}`;
return isDev?`${local}${path}`:`${path}`; } else {
}else{ return isDev ? `${local}/${path}` : `/${path}`;
return isDev?`${local}/${path}`:`/${path}`;
} }
} }
export function getUrl(path, goTest) { export function getUrl(path) {
// https://www.educoder.net
// https://testbdweb.trustie.net
// 如果想所有url定位到测试版可以反注释掉下面这行
//goTest = true
// testbdweb.educoder.net testbdweb.trustie.net
// const local = goTest ? 'https://testeduplus2.educoder.net' : 'http://localhost:3000'
// const local = 'https://testeduplus2.educoder.net'
const local = 'https://test-newweb.educoder.net' const local = 'https://test-newweb.educoder.net'
if (isDev) { if (isDev) {
return `${local}${path?path:''}` return `${local}${path ? path : ''}`
} }
return `${path ? path: ''}`; return `${path ? path : ''}`;
} }
export function getUrlmys(path, goTest) { export function getUrlmys(path, goTest) {
// https://www.educoder.net
// https://testbdweb.trustie.net
// 如果想所有url定位到测试版可以反注释掉下面这行
//goTest = true
// testbdweb.educoder.net testbdweb.trustie.net
// const local = goTest ? 'https://testeduplus2.educoder.net' : 'http://localhost:3000'
// const local = 'https://testeduplus2.educoder.net'
const local = 'https://test-jupyterweb.educoder.net' const local = 'https://test-jupyterweb.educoder.net'
if (isDev) { if (isDev) {
return `${local}${path?path:''}` return `${local}${path ? path : ''}`
} }
return `${path ? path: ''}`; return `${path ? path : ''}`;
} }
export function getStaticUrl() { export function getStaticUrl() {
const local = TEST_HOST; const local = TEST_HOST;
@ -70,25 +50,27 @@ export function getStaticUrl() {
export function getUrl2(path, goTest) { export function getUrl2(path, goTest) {
const local = 'http://localhost:3000' const local = 'http://localhost:3000'
if (isDev) { if (isDev) {
return `${local}${path?path:''}` return `${local}${path ? path : ''}`
} }
return `${path ? path: ''}`; return `${path ? path : ''}`;
} }
const newopens ="79e33abd4b6588941ab7622aed1e67e8"; const newopens = "79e33abd4b6588941ab7622aed1e67e8";
let newtimestamp; let newtimestamp;
let checkSubmitFlgs = false; let checkSubmitFlgs = false;
function railsgettimess(proxy) { function railsgettimess(proxy) {
if(checkSubmitFlgs===false){ if (checkSubmitFlgs === false) {
$.ajax({url:proxy, $.ajax({
async:false,success:function(data){ url: proxy,
if(data.status===0){ async: false, success: function (data) {
newtimestamp=data.message; if (data.status === 0) {
newtimestamp = data.message;
checkSubmitFlgs = true; checkSubmitFlgs = true;
} }
}}) }
})
window.setTimeout(function () { window.setTimeout(function () {
checkSubmitFlgs=false; checkSubmitFlgs = false;
}, 2500); }, 2500);
} }
} }
@ -107,19 +89,19 @@ export function getmyUrl(geturl) {
export function getUploadActionUrl(path, goTest) { export function getUploadActionUrl(path, goTest) {
Railsgettimes() Railsgettimes()
let anewopens=md5(newopens+newtimestamp); let anewopens = md5(newopens + newtimestamp);
return `${getUrl()}/api/attachments.json${isDev ? `?debug=${window._debugType || 'admin'}&randomcode=${newtimestamp}&client_key=${anewopens}` : `?randomcode=${newtimestamp}&client_key=${anewopens}`}`; return `${getUrl()}/api/attachments.json${isDev ? `?debug=${window._debugType || 'admin'}&randomcode=${newtimestamp}&client_key=${anewopens}` : `?randomcode=${newtimestamp}&client_key=${anewopens}`}`;
} }
export function getUploadActionUrltwo(id) { export function getUploadActionUrltwo(id) {
Railsgettimes() Railsgettimes()
let anewopens=md5(newopens+newtimestamp); let anewopens = md5(newopens + newtimestamp);
return `${getUrlmys()}/api/shixuns/${id}/upload_data_sets.json${isDev ? `?debug=${window._debugType || 'admin'}&randomcode=${newtimestamp}&client_key=${anewopens}` : `?randomcode=${newtimestamp}&client_key=${anewopens}`}` return `${getUrlmys()}/api/shixuns/${id}/upload_data_sets.json${isDev ? `?debug=${window._debugType || 'admin'}&randomcode=${newtimestamp}&client_key=${anewopens}` : `?randomcode=${newtimestamp}&client_key=${anewopens}`}`
} }
export function getUploadActionUrlthree() { export function getUploadActionUrlthree() {
Railsgettimes() Railsgettimes()
let anewopens=md5(newopens+newtimestamp); let anewopens = md5(newopens + newtimestamp);
return `${getUrlmys()}/api/jupyters/import_with_tpm.json${isDev ? `?debug=${window._debugType || 'admin'}&randomcode=${newtimestamp}&client_key=${anewopens}` : `?randomcode=${newtimestamp}&client_key=${anewopens}`}` return `${getUrlmys()}/api/jupyters/import_with_tpm.json${isDev ? `?debug=${window._debugType || 'admin'}&randomcode=${newtimestamp}&client_key=${anewopens}` : `?randomcode=${newtimestamp}&client_key=${anewopens}`}`
} }
@ -132,14 +114,14 @@ export function getupload_git_file(id) {
export function getUploadActionUrlOfAuth(id) { export function getUploadActionUrlOfAuth(id) {
Railsgettimes() Railsgettimes()
let anewopens=md5(newopens+newtimestamp); let anewopens = md5(newopens + newtimestamp);
return `${getUrl()}/api/users/accounts/${id}/auth_attachment.json${isDev ? `?debug=${window._debugType || 'admin'}&randomcode=${newtimestamp}&client_key=${anewopens}` : `?randomcode=${newtimestamp}&client_key=${anewopens}`}` return `${getUrl()}/api/users/accounts/${id}/auth_attachment.json${isDev ? `?debug=${window._debugType || 'admin'}&randomcode=${newtimestamp}&client_key=${anewopens}` : `?randomcode=${newtimestamp}&client_key=${anewopens}`}`
} }
export function getRandomNumber(type) { export function getRandomNumber(type) {
Railsgettimes() Railsgettimes()
let anewopens=md5(newopens+newtimestamp); let anewopens = md5(newopens + newtimestamp);
return type===true?`randomcode=${newtimestamp}&client_key=${anewopens}`:`?randomcode=${newtimestamp}&client_key=${anewopens}` return type === true ? `randomcode=${newtimestamp}&client_key=${anewopens}` : `?randomcode=${newtimestamp}&client_key=${anewopens}`
} }
export function test(path) { export function test(path) {
@ -157,11 +139,11 @@ export function getTaskUrlById(id) {
export function getRandomcode(url) { export function getRandomcode(url) {
Railsgettimes() Railsgettimes()
let anewopens=md5(newopens+newtimestamp); let anewopens = md5(newopens + newtimestamp);
if (url.indexOf('?') == -1) { if (url.indexOf('?') == -1) {
return `${url}?randomcode=${newtimestamp}&client_key=${anewopens}` return `${url}?randomcode=${newtimestamp}&client_key=${anewopens}`
}else { } else {
return `${url}&randomcode=${newtimestamp}&client_key=${anewopens}` return `${url}&randomcode=${newtimestamp}&client_key=${anewopens}`
} }
@ -181,14 +163,14 @@ export function htmlEncode(str) {
return s; return s;
} }
export function publicSearchs(Placeholder,onSearch,onInputs,onChanges,loadings) { export function publicSearchs(Placeholder, onSearch, onInputs, onChanges, loadings) {
return(<Search return (<Search
placeholder= { Placeholder || "请输入内容进行搜索" } placeholder={Placeholder || "请输入内容进行搜索"}
onSearch={onSearch} onSearch={onSearch}
// value={searchValue} // value={searchValue}
onInput={onInputs} onInput={onInputs}
onChange={onChanges} onChange={onChanges}
loading={loadings||false} loading={loadings || false}
allowClear={true} allowClear={true}
></Search>) ></Search>)
} }

@ -2,7 +2,7 @@ import React, { Component } from 'react';
import { Modal } from 'antd'; import { Modal } from 'antd';
export function ModalHOC(options = {}) { export default function ModalHOC(options = {}) {
return function wrap(WrappedComponent) { return function wrap(WrappedComponent) {
return class Wrapper extends Component { return class Wrapper extends Component {
constructor(props) { constructor(props) {
@ -39,7 +39,7 @@ export function ModalHOC(options = {}) {
onCancel = () => { onCancel = () => {
this.setState({ this.setState({
Modallisttype:false Modallisttype: false
}) })
} }
hidemodeldelete = () => { hidemodeldelete = () => {
@ -66,7 +66,7 @@ export function ModalHOC(options = {}) {
<div className="task-popup-content" > <div className="task-popup-content" >
<div className="task-popup-text-center font-14">{Modallist}</div> <div className="task-popup-text-center font-14">{Modallist}</div>
</div> </div>
{ singleButton ? <div className="task-popup-submit clearfix" {singleButton ? <div className="task-popup-submit clearfix"
style={{ textAlign: 'center' }}> style={{ textAlign: 'center' }}>
<a className="task-btn task-btn-orange" <a className="task-btn task-btn-orange"
onClick={this.onCancel} onClick={this.onCancel}
@ -76,11 +76,11 @@ export function ModalHOC(options = {}) {
<a className="task-btn task-btn-orange fr" <a className="task-btn task-btn-orange fr"
onClick={this.hidemodeldelete} onClick={this.hidemodeldelete}
>确定</a> >确定</a>
</div> } </div>}
</Modal> </Modal>
<WrappedComponent {...this.props} <WrappedComponent {...this.props}
showModal={ this.showModal } showModal={this.showModal}
showSingleButtonModal={ this.showSingleButtonModal } showSingleButtonModal={this.showSingleButtonModal}
> >
</WrappedComponent> </WrappedComponent>

@ -1,6 +1,6 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { Modal } from 'antd'; import { Modal } from 'antd';
export function SetAppModel(options={}) { export default function SetAppModel(options = {}) {
return function wrap(WrappedComponent) { return function wrap(WrappedComponent) {
return class Wrapper extends Component { return class Wrapper extends Component {
constructor(props) { constructor(props) {
@ -10,14 +10,14 @@ export function SetAppModel(options={}) {
} }
} }
modalCancel=()=>{ modalCancel = () => {
window.location.href = "/"; window.location.href = "/";
} }
setDownload=()=>{ setDownload = () => {
window.location.href ='/account/profile'; window.location.href = '/account/profile';
} }
componentDidMount(){ componentDidMount() {
console.log(this.props) console.log(this.props)
} }
@ -38,8 +38,8 @@ export function SetAppModel(options={}) {
<div className={"tabeltext-alignleft mt10"}><p>您尚未完善个人资料</p></div> <div className={"tabeltext-alignleft mt10"}><p>您尚未完善个人资料</p></div>
<div className={"tabeltext-alignleft mt10"}><p>请在完成资料后提交试用申请</p></div> <div className={"tabeltext-alignleft mt10"}><p>请在完成资料后提交试用申请</p></div>
<div className="clearfix mt30 edu-txt-center"> <div className="clearfix mt30 edu-txt-center">
<a className="task-btn mr30" onClick={()=>this.modalCancel()}>取消</a> <a className="task-btn mr30" onClick={() => this.modalCancel()}>取消</a>
<a className="task-btn task-btn-orange" onClick={()=>this.setDownload()}>立即完善资料</a> <a className="task-btn task-btn-orange" onClick={() => this.setDownload()}>立即完善资料</a>
</div> </div>
</div> </div>
</Modal> </Modal>

@ -6,7 +6,7 @@
* @LastEditors : tangjiang * @LastEditors : tangjiang
* @LastEditTime : 2020-01-06 18:42:09 * @LastEditTime : 2020-01-06 18:42:09
*/ */
import './index.scss'; import './index.less';
import React, { useState } from 'react'; import React, { useState } from 'react';
import { Form, Button, Input } from 'antd'; import { Form, Button, Input } from 'antd';
import QuillForEditor from '../../quillForEditor'; import QuillForEditor from '../../quillForEditor';

@ -6,11 +6,11 @@
* @LastEditors : tangjiang * @LastEditors : tangjiang
* @LastEditTime : 2019-12-25 10:03:21 * @LastEditTime : 2019-12-25 10:03:21
*/ */
import './index.scss'; import './index.less';
import React from 'react'; import React from 'react';
// import { Icon } from 'antd'; // import { Icon } from 'antd';
// import MyIcon from '../MyIcon'; // import MyIcon from '../MyIcon';
function CommentIcon ({ function CommentIcon({
type, // 图标类型 type, // 图标类型
count, // 评论数 count, // 评论数
iconClick, iconClick,
@ -30,11 +30,11 @@ function CommentIcon ({
<span <span
style={props.style} style={props.style}
className={`comment_icon_count ${props.className}`} className={`comment_icon_count ${props.className}`}
onClick={ handleSpanClick } onClick={handleSpanClick}
> >
{/* <Icon className="comment_icon" type={type} style={{ color: iconColor }} theme={theme}/> */} {/* <Icon className="comment_icon" type={type} style={{ color: iconColor }} theme={theme}/> */}
<span className={_classIcon} style={{ color: iconColor }}></span> <span className={_classIcon} style={{ color: iconColor }}></span>
<span className={_className}>{ count }</span> <span className={_className}>{count}</span>
</span> </span>
) )
} }

@ -6,7 +6,7 @@
* @LastEditors : tangjiang * @LastEditors : tangjiang
* @LastEditTime : 2019-12-27 11:05:17 * @LastEditTime : 2019-12-27 11:05:17
*/ */
import './index.scss'; import './index.less';
import React, { useState } from 'react'; import React, { useState } from 'react';
import CommentIcon from './CommentIcon'; import CommentIcon from './CommentIcon';
import { getImageUrl, CNotificationHOC } from 'educoder' import { getImageUrl, CNotificationHOC } from 'educoder'
@ -16,7 +16,6 @@ import QuillForEditor from '../../quillForEditor';
function CommentItem({ function CommentItem({
isAdmin, isAdmin,
options,
confirm, confirm,
comment, comment,
submitDeleteComment, submitDeleteComment,

@ -6,11 +6,11 @@
* @LastEditors : tangjiang * @LastEditors : tangjiang
* @LastEditTime : 2019-12-24 18:08:07 * @LastEditTime : 2019-12-24 18:08:07
*/ */
import './index.scss'; import './index.less';
import React from 'react'; import React from 'react';
import CommentItem from './CommentItem'; import CommentItem from './CommentItem';
import { Empty } from 'antd'; import { Empty } from 'antd';
function CommentList (props) { function CommentList(props) {
const { const {
isAdmin, isAdmin,
commentLists, // 评论列表 commentLists, // 评论列表
@ -20,7 +20,7 @@ function CommentList (props) {
showOrHideComment showOrHideComment
} = props; } = props;
const {comments = []} = commentLists; const { comments = [] } = commentLists;
const renderLi = () => { const renderLi = () => {
if (comments.length > 0) { if (comments.length > 0) {

@ -1,87 +1,98 @@
$bdColor: rgba(244,244,244,1); @bdColor: rgba(244, 244, 244, 1);
$bgColor: rgba(250,250,250,1); @bgColor: rgba(250, 250, 250, 1);
$lh14: 14px; @lh14: 14px;
$lh22: 22px; @lh22: 22px;
$fz14: 14px; @fz14: 14px;
$fz12: 12px; @fz12: 12px;
$ml: 20px; @ml: 20px;
.comment_list_wrapper{ .comment_list_wrapper {
box-sizing: border-box; box-sizing: border-box;
// border-top: 1px solid $bdColor;
.empty_comment{ // border-top: 1px solid @bdColor;
.empty_comment {
display: flex; display: flex;
height: calc(100vh - 200px); height: calc(100vh - 200px);
width: 100%; width: 100%;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
} }
.comment_item_show{
.comment_item_show {
display: block; display: block;
} }
.comment_item_hide{
.comment_item_hide {
display: none; display: none;
} }
.comment_item_area{
.comment_item_area {
display: flex; display: flex;
padding: 20px 0; padding: 20px 0;
box-sizing: border-box; box-sizing: border-box;
border-bottom: 1px solid $bdColor; border-bottom: 1px solid @bdColor;
.comment_child_item_area:hover{ .comment_child_item_area:hover {
.item-close{ .item-close {
display: inline-block; display: inline-block;
} }
} }
.flex-image{ .flex-image {
width: 48px; width: 48px;
height: 48px; height: 48px;
border-radius: 50%; border-radius: 50%;
} }
.item-desc{
.item-desc {
flex: 1; flex: 1;
// margin-left: $ml; // margin-left: @ml;
margin-left: 5px; margin-left: 5px;
} }
.item-header{
font-size: $fz14; .item-header {
line-height: $lh14; font-size: @fz14;
line-height: @lh14;
color: #333; color: #333;
margin-left: 15px; margin-left: 15px;
.item-time{
font-size: $fz12; .item-time {
line-height: $lh14; font-size: @fz12;
margin-left: $ml; line-height: @lh14;
margin-left: @ml;
} }
.item-close{
.item-close {
display: none; display: none;
cursor: pointer; cursor: pointer;
float: right; float: right;
} }
.item-close.hide{ .item-close.hide {
display: none; display: none;
} }
} }
.item-ctx{
.item-ctx {
position: relative; position: relative;
line-height: $lh22; line-height: @lh22;
font-size: $fz12; font-size: @fz12;
color: #333; color: #333;
margin-top: 10px; margin-top: 10px;
vertical-align: top; vertical-align: top;
} }
.comment_icon_area{
.comment_icon_area {
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
margin-top: 10px; margin-top: 10px;
.comment-icon-margin{ .comment-icon-margin {
margin-left: 20px; margin-left: 20px;
} }
.comment-icon-margin-10{
.comment-icon-margin-10 {
margin-left: 10px; margin-left: 10px;
} }
} }
@ -89,23 +100,24 @@ $ml: 20px;
// .comment_item_quill{ // .comment_item_quill{
// // margin-top: 10px; // // margin-top: 10px;
// } // }
.show_upload_image{ .show_upload_image {
position: fixed; position: fixed;
left: 0; left: 0;
top: 0; top: 0;
right: 0; right: 0;
bottom: 0; bottom: 0;
z-index: 1000; z-index: 1000;
&::before{
&::before {
position: absolute; position: absolute;
height: 100%; height: 100%;
width:100%; width: 100%;
content: ''; content: '';
background: #000; background: #000;
opacity: .7; opacity: .7;
} }
.image_info{ .image_info {
display: flex; display: flex;
position: absolute; position: absolute;
width: 80%; width: 80%;
@ -114,14 +126,15 @@ $ml: 20px;
top: 10%; top: 10%;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
// background: green; // background: green;
.image{ .image {
display: block; display: block;
width: 100%; width: 100%;
} }
} }
.image_close{ .image_close {
position: absolute; position: absolute;
right: 20px; right: 20px;
top: 20px; top: 20px;
@ -130,40 +143,47 @@ $ml: 20px;
} }
} }
} }
.comment_icon_count{
.comment_icon_count {
cursor: pointer; cursor: pointer;
font-size: 12px; font-size: 12px;
line-height: 1.5; line-height: 1.5;
.comment_icon{ .comment_icon {
color: #333; color: #333;
} }
.comment_count{
.comment_count {
color: #999999; color: #999999;
margin-left: 10px; margin-left: 10px;
transition: color .3s; transition: color .3s;
} }
.comment_count_none{
.comment_count_none {
margin-left: 0; margin-left: 0;
} }
&:hover{ &:hover {
.comment_icon, .comment_icon,
.comment_count{ .comment_count {
color: #5091FF; color: #5091FF;
} }
} }
} }
.comment_item_append_list{
.comment_item_append_list {
display: none; display: none;
position: relative; position: relative;
background-color: $bgColor; background-color: @bgColor;
border-radius: 5px; border-radius: 5px;
padding: 0 15px 10px; padding: 0 15px 10px;
margin: 15px 0; margin: 15px 0;
&.active{
&.active {
display: block; display: block;
} }
&::before { &::before {
position: absolute; position: absolute;
left: 15px; left: 15px;
@ -173,53 +193,57 @@ $ml: 20px;
content: ''; content: '';
// border: 5px solid transparent; // border: 5px solid transparent;
border: 10px solid transparent; border: 10px solid transparent;
border-bottom-color: $bgColor; border-bottom-color: @bgColor;
} }
.comment_item_loadmore{ .comment_item_loadmore {
display: none; display: none;
padding-top: 10px; padding-top: 10px;
cursor: pointer; cursor: pointer;
.loadmore-txt, .loadmore-txt,
.loadmore-icon{ .loadmore-icon {
color: #999; color: #999;
text-align: center; text-align: center;
font-size: $fz12; font-size: @fz12;
} }
&.show{ &.show {
display: block; display: block;
} }
} }
} }
.icon_font_size_14{ .icon_font_size_14 {
font-size: 14px !important; font-size: 14px !important;
} }
} }
.comment_form_area, .comment_form_area,
.comment_form_bottom_area{ .comment_form_bottom_area {
width: 100%; width: 100%;
} }
.comment_form_area{
.comment_form_area {
position: relative; position: relative;
background: #fff; background: #fff;
// top: 10px; // top: 10px;
.ant-form-explain{ .ant-form-explain {
padding-left: 0px; padding-left: 0px;
} }
.show_input{
.show_input {
margin-top: 10px; margin-top: 10px;
} }
} }
.comment_form_bottom_area{ .comment_form_bottom_area {
position: relative; position: relative;
background: #fff; background: #fff;
top: 10px; top: 10px;
&.active{ &.active {
position: absolute; position: absolute;
background: #fff; background: #fff;
left: 0px; left: 0px;

@ -1,18 +1,19 @@
//import { from } from '_array-flatten@2.1.2@array-flatten';
// export { default as OrderStateUtil } from '../routes/Order/components/OrderStateUtil'; export {
getImageUrl as getImageUrl, getmyUrl as getmyUrl, getRandomNumber as getRandomNumber, getUrl as getUrl, publicSearchs as publicSearchs, getRandomcode as getRandomcode, getUrlmys as getUrlmys, getUrl2 as getUrl2, setImagesUrl as setImagesUrl
, getUploadActionUrl as getUploadActionUrl, getUploadActionUrltwo as getUploadActionUrltwo, getUploadActionUrlthree as getUploadActionUrlthree, getUploadActionUrlOfAuth as getUploadActionUrlOfAuth
, getTaskUrlById as getTaskUrlById, TEST_HOST, htmlEncode as htmlEncode, getupload_git_file as getupload_git_file
} from './UrlTool';
export { getImageUrl as getImageUrl,getmyUrl as getmyUrl, getRandomNumber as getRandomNumber,getUrl as getUrl, publicSearchs as publicSearchs,getRandomcode as getRandomcode,getUrlmys as getUrlmys, getUrl2 as getUrl2, setImagesUrl as setImagesUrl export { default as setmiyah } from './Component';
, getUploadActionUrl as getUploadActionUrl,getUploadActionUrltwo as getUploadActionUrltwo ,getUploadActionUrlthree as getUploadActionUrlthree, getUploadActionUrlOfAuth as getUploadActionUrlOfAuth
, getTaskUrlById as getTaskUrlById, TEST_HOST ,htmlEncode as htmlEncode ,getupload_git_file as getupload_git_file} from './UrlTool';
export {setmiyah as setmiyah} from './Component';
export { default as queryString } from './UrlTool2'; export { default as queryString } from './UrlTool2';
export { SnackbarHOC as SnackbarHOC } from './SnackbarHOC'; export { default as SnackbarHOC } from './SnackbarHOC';
export { trigger as trigger, on as on, off as off export {
, broadcastChannelPostMessage, broadcastChannelOnmessage } from './EventUtil'; trigger as trigger, on as on, off as off
, broadcastChannelPostMessage, broadcastChannelOnmessage
} from './EventUtil';
export { updatePageParams as updatePageParams } from './RouterUtil'; export { updatePageParams as updatePageParams } from './RouterUtil';
@ -22,31 +23,32 @@ export { markdownToHTML, uploadNameSizeSeperator, appendFileSizeToUploadFile, ap
downloadFile, sortDirections } from './TextUtil' downloadFile, sortDirections } from './TextUtil'
export { handleDateString, getNextHalfHourOfMoment,formatDuring,formatSeconds} from './DateUtil' export { handleDateString, getNextHalfHourOfMoment,formatDuring,formatSeconds} from './DateUtil'
export { configShareForIndex, configShareForPaths, configShareForShixuns, configShareForCourses, configShareForCustom } from './util/ShareUtil'
export { isDev as isDev, isMobile } from './Env' export { isDev as isDev, isMobile } from './Env'
export { toStore as toStore, fromStore as fromStore } from './Store' export { toStore as toStore, fromStore as fromStore } from './Store'
export { trace_collapse, trace, debug, info, warn, error, trace_c, debug_c, info_c, warn_c, error_c } from './LogUtil' export { trace_collapse, trace, debug, info, warn, error, trace_c, debug_c, info_c, warn_c, error_c } from './LogUtil'
export { EDU_ADMIN, EDU_BUSINESS, EDU_SHIXUN_MANAGER, EDU_SHIXUN_MEMBER, EDU_CERTIFICATION_TEACHER export {
, EDU_GAME_MANAGER, EDU_TEACHER, EDU_NORMAL} from './Const' EDU_ADMIN, EDU_BUSINESS, EDU_SHIXUN_MANAGER, EDU_SHIXUN_MEMBER, EDU_CERTIFICATION_TEACHER
, EDU_GAME_MANAGER, EDU_TEACHER, EDU_NORMAL
} from './Const'
export { default as AttachmentList } from './components/attachment/AttachmentList' export { default as AttachmentList } from './components/attachment/AttachmentList'
export { themes, ThemeContext } from './context/ThemeContext' export { themes, ThemeContext } from './context/ThemeContext'
export { ModalHOC } from './components/ModalHOC' export { default as ModalHOC } from './components/ModalHOC'
export { SetAppModel } from './components/SetAppModel' export { default as SetAppModel } from './components/SetAppModel'
export { default as LinkAfterLogin } from './components/LinkAfterLogin' export { default as LinkAfterLogin } from './components/LinkAfterLogin'
export { default as Cropper } from './components/Cropper' export { default as Cropper } from './components/Cropper'
export { default as ConditionToolTip } from './components/ConditionToolTip' export { default as ConditionToolTip } from './components/ConditionToolTip'
// export { default as DragValidator } from './components/DragValidator' // export { default as DragValidator } from './components/DragValidator'
export { configShareForIndex, configShareForPaths, configShareForShixuns, configShareForCourses, configShareForCustom } from './util/ShareUtil'
export { default as PopInstruction } from './components/instruction/PopInstruction' export { default as PopInstruction } from './components/instruction/PopInstruction'
export { default as City } from './components/form/City' export { default as City } from './components/form/City'
@ -54,24 +56,27 @@ export { default as City } from './components/form/City'
// course // course
export { default as WordsBtn } from './course/WordsBtn' export { default as WordsBtn } from './course/WordsBtn'
export { default as ActionBtn } from './course/ActionBtn' export { default as ActionBtn } from './course/ActionBtn'
export { default as MarkdownToHtml } from './components/markdown/MarkdownToHtml' export { default as MarkdownToHtml } from './components/markdown/MarkdownToHtml'
export { default as DMDEditor } from './components/markdown/DMDEditor' export { default as DMDEditor } from './components/markdown/DMDEditor'
export { default as Clappr } from './components/media/Clappr' export { default as Clappr } from './components/media/Clappr'
export { default as AliyunUploader } from './components/media/AliyunUploader' export { default as AliyunUploader } from './components/media/AliyunUploader'
export { default as ImageLayer2 } from './hooks/ImageLayer2' export { default as ImageLayer2 } from './hooks/ImageLayer2'
// 外部 // 外部
export { default as CBreadcrumb } from '../modules/courses/common/CBreadcrumb' export { default as CBreadcrumb } from '../modules/courses/common/CBreadcrumb'
export { CNotificationHOC as CNotificationHOC } from '../modules/courses/common/CNotificationHOC' export { default as CNotificationHOC } from '../modules/courses/common/CNotificationHOC'
export { default as ModalWrapper } from '../modules/courses/common/ModalWrapper' export { default as ModalWrapper } from '../modules/courses/common/ModalWrapper'
export { default as NoneData } from '../modules/courses/coursesPublic/NoneData' export { default as NoneData } from '../modules/courses/coursesPublic/NoneData'
export {default as WordNumberTextarea} from '../modules/modals/WordNumberTextarea' export { default as WordNumberTextarea } from '../modules/modals/WordNumberTextarea'
import loadable from '@loadable/component'
import defaultLoading from '../Loading'
export function Loadable({ loader, loading = defaultLoading }) {
return loadable(loader, {
fallback: loading
})
}

@ -6,7 +6,7 @@
* @LastEditors : tangjiang * @LastEditors : tangjiang
* @LastEditTime : 2020-02-05 11:23:03 * @LastEditTime : 2020-02-05 11:23:03
*/ */
import './index.scss'; import './index.less';
import 'quill/dist/quill.core.css'; // 核心样式 import 'quill/dist/quill.core.css'; // 核心样式
import 'quill/dist/quill.snow.css'; // 有工具栏 import 'quill/dist/quill.snow.css'; // 有工具栏
import 'quill/dist/quill.bubble.css'; // 无工具栏 import 'quill/dist/quill.bubble.css'; // 无工具栏
@ -32,11 +32,9 @@ Quill.register(ImageBlot);
Quill.register(Size); Quill.register(Size);
Quill.register(LinkBlot); Quill.register(LinkBlot);
Quill.register(Font, true); Quill.register(Font, true);
// Quill.register({'modules/toolbar': Toolbar});
Quill.register({ Quill.register({
'formats/fill': FillBlot 'formats/fill': FillBlot
}); });
// Quill.register(Color);
function QuillForEditor({ function QuillForEditor({

File diff suppressed because it is too large Load Diff

@ -0,0 +1,28 @@
import test from 'ava';
import asciimathToTex from './asciimath-to-tex';
test('just a number', t => {
t.is(asciimathToTex('5'), '{5}');
});
test('x=5', t => {
t.is(asciimathToTex('x=5'), '{x}={5}');
});
test('x=5+2', t => {
t.is(asciimathToTex('x=5+2'), '{x}={5}+{2}');
});
test('x = (-b+-sqrt(b^2-4ac))/(2a)', t => {
t.is(
asciimathToTex('x = (-b+-sqrt(b^2-4ac))/(2a)'),
'{x}=\\frac{{-{b}\\pm\\sqrt{{{b}^{{2}}-{4}{a}{c}}}}}{{{2}{a}}}',
);
});
test('{x}=(-b+-sqrt(b^2-4ac))/(2a)', t => {
t.is(
asciimathToTex('{x}=(-b+-sqrt(b^2-4ac))/(2a)'),
'{\\left\\lbrace{x}\\right\\rbrace}=\\frac{{-{b}\\pm\\sqrt{{{b}^{{2}}-{4}{a}{c}}}}}{{{2}{a}}}',
);
});

@ -0,0 +1,121 @@
import katex from 'katex';
import renderMathInElement from 'katex/dist/contrib/auto-render';
import showdown from 'showdown';
import asciimathToTex from './asciimath-to-tex';
if (process.env.TARGET === 'cjs') {
const { JSDOM } = require('jsdom');
const jsdom = new JSDOM();
global.DOMParser = jsdom.window.DOMParser;
global.document = jsdom.window.document;
}
/**
* @param {object} opts
* @param {NodeListOf<Element>} opts.elements
* @param opts.config
* @param {boolean} opts.isAsciimath
*/
function renderBlockElements({ elements, config, isAsciimath }) {
if (!elements.length) {
return;
}
elements.forEach(element => {
const input = element.textContent || element.innerText;
const latex = isAsciimath ? asciimathToTex(input) : input;
const html = katex.renderToString(latex, config);
element.parentNode.outerHTML = `<span title="${input.trim()}">${html}</span>`;
});
}
/**
* https://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex
* @param {string} str
* @returns {string} regexp escaped string
*/
function escapeRegExp(str) {
return str.replace(/[-[\]/{}()*+?.\\$^|]/g, '\\$&');
}
// katex config
const getConfig = (config = {}) => ({
displayMode: true,
throwOnError: false, // fail silently
errorColor: '#ff0000',
...config,
delimiters: [
{ left: '$$', right: '$$', display: false, asciimath: false },
{ left: '~', right: '~', display: false, asciimath: true },
].concat(config.delimiters || []),
});
const showdownKatex = userConfig => () => {
const parser = new DOMParser();
const config = getConfig(userConfig);
const asciimathDelimiters = config.delimiters
.filter(item => item.asciimath)
.map(({ left, right }) => {
const l = escapeRegExp(left)
const r = escapeRegExp(right)
const test = new RegExp(
`(?:${l})([^${l}${r}]+)(?:${r})`,
'g',
);
const replacer = (match, asciimath) => {
return `${left}${asciimathToTex(asciimath)}${right}`;
};
return { test, replacer };
});
return [
{
type: 'output',
filter(html = '') {
const wrapper = parser.parseFromString(html, 'text/html').body;
if (asciimathDelimiters.length) {
wrapper.querySelectorAll(':not(code):not(pre)').forEach(el => {
const textNodes = [...el.childNodes].filter(
node => {
if (node.nodeName === '#text') {
return node.nodeValue.trim()
}
if (node.nodeName === 'CODE') {
return node.innerText.trim()
}
},
)
textNodes.forEach(node => {
const newText = asciimathDelimiters.reduce(
(acc, { test, replacer }) => acc.replace(test, replacer),
node.nodeValue || node.innerText
)
if (node.nodeName === '#text') {
node.nodeValue = newText
} else {
node.innerText = newText;
}
})
})
}
// find the math in code blocks
const latex = wrapper.querySelectorAll('code.latex.language-latex');
const asciimath = wrapper.querySelectorAll(
'code.asciimath.language-asciimath',
);
renderBlockElements({ elements: latex, config });
renderBlockElements({ elements: asciimath, config, isAsciimath: true });
renderMathInElement(wrapper, config);
return wrapper.innerHTML;
},
},
];
};
// register extension with default config
showdown.extension('showdown-katex', showdownKatex());
export default showdownKatex;

@ -0,0 +1,21 @@
import test from 'ava';
import showdown from 'showdown';
import katex from '../lib/showdown-katex';
const input = '# hello, markdown!';
const output = '<h1 id="hellomarkdown">hello, markdown!</h1>';
test('string extension', t => {
const converter = new showdown.Converter({
extensions: ['showdown-katex'],
});
t.is(converter.makeHtml(input), output);
});
test('function extension', t => {
const converter = new showdown.Converter({
extensions: [katex()],
});
t.is(converter.makeHtml(input), output);
});

@ -0,0 +1,13 @@
import React from 'react'
import './index.less'
export default ({ children, style = {} }) => {
return (
<div className="dialog-container-wrapper">
<div className="dialog-body" style={style}>
{children}
</div>
</div>
)
}

@ -0,0 +1,21 @@
.dialog-container-wrapper {
display: flex;
position: fixed;
bottom: 0;
right: 0;
top: 0;
left: 0;
z-index: 300;
background: rgba(0, 0, 0, .7);
flex-flow: column nowrap;
justify-content: center;
align-items: center;
}
.dialog-body {
width: 405px;
height: auto;
background: #fff;
position: relative;
}

@ -0,0 +1,26 @@
import React from 'react'
export default class ErrorBoundary extends React.Component {
constructor(props) {
super(props)
this.state = { hasError: false }
}
static getDerivedStateFromError(error) {
// Update state so the next render will show the fallback UI.
return { hasError: true }
}
componentDidCatch(error, errorInfo) {
// You can also log the error to an error reporting service
console.log(error, errorInfo)
}
render() {
if (this.state.hasError) {
// You can render any custom fallback UI
return <h1>Something went wrong.</h1>
}
return this.props.children
}
}

@ -0,0 +1,10 @@
import React from 'react'
import './loading.less'
export default () => {
return <div className="loading-tip">
<p>
loading ...
</p>
</div>
}

@ -0,0 +1,9 @@
.loading-tip {
display: flex;
flex-flow: column nowrap;
justify-content: center;
align-items: center;
height: 100%;
background: #213857;
color: #fff;
}

@ -1,5 +1,5 @@
import React, { useState } from 'react' import React, { useState } from 'react'
import './index.scss' import './index.less'
function noop() { } function noop() { }
export default ({ current, defaultCurrent, total, pageSize, onChange = noop }) => { export default ({ current, defaultCurrent, total, pageSize, onChange = noop }) => {

@ -0,0 +1,65 @@
.mini-pagination {
display: flex;
flex-flow: row nowrap;
justify-content: center;
align-items: center;
a {
display: block;
padding: 0 10px 0 22px;
border-width: 1px;
border-radius: 3px;
margin-right: 4px;
font-size: 12px;
line-height: 30px;
cursor: pointer;
border-style: solid;
outline: none;
border-color: #c4c6cf;
background: #fff;
color: #333;
position: relative;
&:hover {
background-color: #f2f3f7;
border-color: #a0a2ad;
text-decoration: none;
}
&:before {
position: absolute;
content: ' ';
width: 8px;
top: 10px;
left: 10px;
height: 8px;
transform: rotate(-45deg);
border-top: 1px solid #333;
border-left: 1px solid #333;
}
&:last-child {
padding: 0 22px 0 10px;
margin: 0 0 0 4px;
&:before {
left: auto;
right: 10px;
transform: rotate(135deg);
}
}
&.disabled {
cursor: not-allowed;
background-color: #f7f8fa;
border-color: #e6e7eb;
color: #e0e0e0;
&:before {
border-top: 1px solid #e0e0e0;
border-left: 1px solid #e0e0e0;
}
}
}
}

@ -0,0 +1,21 @@
import React from 'react'
import { createPortal } from 'react-dom'
export default class Dialog extends React.Component {
constructor(props) {
super(props)
const doc = window.document
this.node = doc.createElement('div')
doc.body.appendChild(this.node)
}
render() {
const { children } = this.props
return createPortal(children, this.node)
}
componentWillUnmount() {
window.document.body.removeChild(this.node);
}
}

@ -64,7 +64,7 @@ function getLanguageByMirrorName(mirror_name) {
export default ({ export default ({
width = '100%', width = '100%',
height = '100%', height = '445px',
value, value,
language = 'javascript', language = 'javascript',
options = {}, options = {},
@ -78,20 +78,9 @@ export default ({
const [init, setInit] = useState(false) const [init, setInit] = useState(false)
function onLayout() { function onLayout() {
if (window.ResizeObserver) {
const ro = new window.ResizeObserver(entries => {
for (let entry of entries) {
if (entry.target.offsetHeight > 0) {
editor.current.instance.layout()
}
}
})
ro.observe(editorEl.current.parentElement)
} else {
setTimeout(() => { setTimeout(() => {
editor.current.instance.layout() editor.current.instance.layout()
}, 100); }, 100)
}
} }
useEffect(() => { useEffect(() => {

@ -0,0 +1,14 @@
import React from 'react'
import { getUrl } from 'educoder'
import './index.less'
export default ({ height = 400 }) => {
return (
<div className="nodata-panel-wrapper" style={{ height }}>
<div className="nodata-panel">
<img width='128' src={getUrl("/images/educoder/nodata.png")} alt='no-data' />
<p>暂时还没有相关数据哦</p>
</div>
</div>
)
}

@ -0,0 +1,22 @@
.nodata-panel-wrapper {
display: flex;
flex-flow: column nowrap;
justify-content: center;
align-items: center;
width: 100%;
.nodata-panel {
width: 100%;
}
img {
display: block;
margin: 0 auto 20px auto;
}
p {
font-size: 20px;
text-align: center;
color: #999;
}
}

@ -0,0 +1,75 @@
import React, { Fragment } from 'react'
import { getImageUrl, setImagesUrl } from 'educoder';
import { Link } from 'react-router-dom'
import { Tooltip, Rate } from 'antd';
import './index.less'
export default ({ list = [] }) => {
return (
<Fragment>
{list.map((item, key) => {
const { id, tag_name, is_jupyter, power, identifier, pic, name, score_info, stu_num, level, challenges_count } = item
return (
<div className="square-Item" key={id} id={id}>
{
tag_name === null ? null :
<div className="tag-green">
<span className="tag-name"> {tag_name}</span>
</div>
}
{
is_jupyter === true ?
<div className="tag-org">
<p className="tag-org-name intermediatecenter"> <span className="tag-org-name-test">Jupyter</span></p>
</div>
: null
}
{power ? null
: <div className="closeSquare">
<img src={getImageUrl("images/educoder/icon/lockclose.svg")}
className="mt80 mb25" />
<p className="font-14 color-white">非试用内容需要授权</p>
</div>
}
<Link to={"/shixuns/" + identifier + "/challenges"} className="square-img" target="_blank">
<img src={setImagesUrl(`${pic}`)} />
</Link>
<div className="square-main">
<p className="task-hide">
<Link to={"/shixuns/" + identifier + "/challenges"} className="justify color-grey-name" title={name} target="_blank">
{name}
</Link>
</p>
<p className="clearfix mt8 ml-3">
<span className="rateYoStar fl" style={{ padding: '0px', height: '20px', lineHeight: '19px', cursor: 'default' }} title="">
<Rate key={key} allowHalf defaultValue={score_info === null ? 5 : score_info} disabled />
</span>
<span className="fl ml25 font-12 color-grey-9 lineh-12 mt5">{score_info === null ? "5分" : score_info + "分"}</span>
</p>
<p className="clearfix mt8 font-12 color-grey-B4">
{is_jupyter === false ? <Tooltip placement="bottom" title={"关卡"}>
<span className="mr10 fl squareIconSpan">
<i className="iconfont icon-shixunguanqia fl mr3"></i>{challenges_count}
</span>
</Tooltip> : ""}
{stu_num === 0 ? null :
<Tooltip placement="bottom" title={"学习人数"}>
<span className="mr10 fl squareIconSpan">
<i className="iconfont icon-chengyuan fl mr3"></i>{stu_num}
</span>
</Tooltip>
}
<span className="fr color-grey-B3 squareIconSpan">{level}</span>
</p>
</div>
</div>
)
})}
</Fragment>
)
}

@ -0,0 +1,36 @@
.tag-green {
position: absolute;
left: 10px;
bottom: 125px;
}
.tag-org {
position: absolute;
left: 0px;
top: 20px;
}
.tag-org-name {
width: 66px;
height: 28px;
background: #FF6802;
width: 66px;
height: 28px;
border-radius: 0px 20px 20px 0px;
}
.tag-org-name-test {
width: 45px;
height: 23px;
font-size: 14px;
color: #FFFFFF;
line-height: 19px;
margin-right: 6px;
}
.intermediatecenter {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}

@ -0,0 +1,10 @@
import React, { Fragment } from 'react';
import TPMMDEditor from '../modules/tpm/challengesnew/TPMMDEditor';
export default () => {
return (
<Fragment >
<TPMMDEditor />
</Fragment>
)
}

@ -1,21 +1,9 @@
import React, { Component } from 'react'; import React, { Component, Fragment } from 'react';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import axios from 'axios'; import axios from 'axios';
import Snackbar from 'material-ui/Snackbar';
import Fade from 'material-ui/transitions/Fade';
import update from 'immutability-helper' import update from 'immutability-helper'
import { Modal, Button, Alert } from 'antd'
import Dialog, {
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
} from 'material-ui/Dialog';
import Button from 'material-ui/Button';
import EvaluateSuccessEffectDisplay from './EvaluateSuccessEffectDisplay' import EvaluateSuccessEffectDisplay from './EvaluateSuccessEffectDisplay'
import _ from 'lodash' import _ from 'lodash'
@ -31,23 +19,10 @@ import _ from 'lodash'
*/ */
import TPIContext from './TPIContext' import TPIContext from './TPIContext'
import { EDU_ADMIN, EDU_SHIXUN_MANAGER, EDU_SHIXUN_MEMBER, EDU_CERTIFICATION_TEACHER import {
, EDU_GAME_MANAGER, EDU_TEACHER, EDU_NORMAL, EDU_BUSINESS, CNotificationHOC ,getRandomNumber} from 'educoder' EDU_ADMIN, EDU_SHIXUN_MANAGER, EDU_SHIXUN_MEMBER, EDU_CERTIFICATION_TEACHER
import { MuiThemeProvider, createMuiTheme, withStyles } from 'material-ui/styles'; , EDU_TEACHER, EDU_NORMAL, EDU_BUSINESS, CNotificationHOC, getRandomNumber
import MUIDialogStyleUtil from '../modules/page/component/MUIDialogStyleUtil' } from 'educoder'
const styles = MUIDialogStyleUtil.getTwoButtonStyle()
// 主题自定义
const theme = createMuiTheme({
palette: {
primary: {
main: '#4CACFF',
contrastText: 'rgba(255, 255, 255, 0.87)'
},
secondary: { main: '#4CACFF' }, // This is just green.A700 as hex.
},
});
const testSetsExpandedArrayInitVal = [false, false, false, false, false, const testSetsExpandedArrayInitVal = [false, false, false, false, false,
false, false, false, false, false, false, false, false, false, false,
@ -109,7 +84,7 @@ class TPIContextProvider extends Component {
} }
onShowUpdateDialog() { onShowUpdateDialog() {
this.setState({showUpdateDialog: true}) this.setState({ showUpdateDialog: true })
} }
// updateNowSuccess true 立即更新成功 // updateNowSuccess true 立即更新成功
// TODO updateDialogClose方法名不对 改为updateDialogCallback // TODO updateDialogClose方法名不对 改为updateDialogCallback
@ -138,19 +113,18 @@ class TPIContextProvider extends Component {
} }
componentWillUnmount() { componentWillUnmount() {
this._updateCostTime();
this.costTimeInterval && window.clearInterval(this.costTimeInterval) this.costTimeInterval && window.clearInterval(this.costTimeInterval)
} }
componentDidMount() { componentDidMount() {
// TODO 登录状态的判断? // TODO 登录状态的判断?
// request
// var shixunId = this.props.match.params.shixunId;
var stageId = this.props.match.params.stageId; var stageId = this.props.match.params.stageId;
window.__fetchAllFlag = false; window.__fetchAllFlag = false;
this.fetchAll(stageId); this.fetchAll(stageId);
this.costTimeInterval = window.setInterval(()=> { this.costTimeInterval = window.setInterval(() => {
const { game } = this.state; const { game } = this.state;
if (!game || game.status === 2) { // 已完成的任务不需要计时 if (!game || game.status === 2) { // 已完成的任务不需要计时
return; return;
@ -158,32 +132,12 @@ class TPIContextProvider extends Component {
if (game.cost_time || game.cost_time === 0) { if (game.cost_time || game.cost_time === 0) {
// game.cost_time += 1; // game.cost_time += 1;
this.setState({ this.setState({
game: update(game, {cost_time: { $set: (game.cost_time+1) }}) game: update(game, { cost_time: { $set: (game.cost_time + 1) } })
}) })
} }
}, 1000) }, 1000)
// // 页面离开时存下用户的任务耗时
window.$(window).bind('beforeunload',()=>{
this._updateCostTime();
})
// window.$(window).unload( ()=>{
// this._updateCostTime();
// });
// // 页面离开时存下用户的任务耗时
// window.$(window).unload( ()=>{
// this._updateCostTime();
// });
} }
// force 评测通过后异步执行该方法强制同步costTime到服务端 // force 评测通过后异步执行该方法强制同步costTime到服务端
_updateCostTime(async = false, force) { _updateCostTime(async = false, force) {
const { game, loading } = this.state; const { game, loading } = this.state;
@ -196,7 +150,7 @@ class TPIContextProvider extends Component {
testPath = 'http://test-newweb.educoder.net' testPath = 'http://test-newweb.educoder.net'
} }
// var url = `${testPath}/api/v1/games/${ game.identifier }/cost_time` // var url = `${testPath}/api/v1/games/${ game.identifier }/cost_time`
var url = `${testPath}/api/tasks/${ game.identifier }/cost_time${getRandomNumber()}` var url = `${testPath}/api/tasks/${game.identifier}/cost_time${getRandomNumber()}`
window.$.ajax({ window.$.ajax({
type: 'get', type: 'get',
url: url, url: url,
@ -214,7 +168,7 @@ class TPIContextProvider extends Component {
// 随便给个分以免重新评测时又出现评星组件注意目前game.star没有显示在界面上如果有则不能这么做 // 随便给个分以免重新评测时又出现评星组件注意目前game.star没有显示在界面上如果有则不能这么做
// game.star = 6; // game.star = 6;
this.setState({ this.setState({
game: update(game, {star: { $set: 6 }}), game: update(game, { star: { $set: 6 } }),
currentGamePassed: !!passed currentGamePassed: !!passed
}) })
} }
@ -251,16 +205,6 @@ class TPIContextProvider extends Component {
} }
// praise_tread/praise_plus?obj_id=569&obj_type=Challenge&horizontal=true&game_praise=true
/*
TODO 旧的接口在未登录时的返回值
//获取登录页面地址
var signinPath = '/';
var htmlvalue = '<div class="task-popup" style="width:480px;"><div class="task-popup-title clearfix"><h3 class="fl color-grey3">提示</h3></div>'+
'<div class="task-popup-content"><p class="task-popup-text-center font-16 mt10 mb10">您还没有登录,请登录后再执行此操作,谢谢!</p></div><div class="task-popup-right-sure clearfix">'+
'<a href="javascript:void(0);" onclick="hideModal();" class="task-btn">取消</a><a href="' + signinPath + '" class="task-btn task-btn-orange ml15">登录</a></div></div>';
pop_box_new(htmlvalue, 480, 182);
*/
praisePlus() { praisePlus() {
const { challenge, game } = this.state; const { challenge, game } = this.state;
let praise = true; let praise = true;
@ -273,7 +217,8 @@ pop_box_new(htmlvalue, 480, 182);
const { praise_count, praise } = response.data; const { praise_count, praise } = response.data;
// challenge.praise_count = praise_tread_count; // challenge.praise_count = praise_tread_count;
// challenge.user_praise = praise; // challenge.user_praise = praise;
this.setState({ challenge: update(challenge, this.setState({
challenge: update(challenge,
{ {
praise_count: { $set: praise_count }, praise_count: { $set: praise_count },
user_praise: { $set: praise }, user_praise: { $set: praise },
@ -292,7 +237,7 @@ pop_box_new(htmlvalue, 480, 182);
// challenge = Object.assign({}, challenge) // challenge = Object.assign({}, challenge)
// challenge.pathIndex = index; // challenge.pathIndex = index;
this.setState({ this.setState({
challenge: update(challenge, {pathIndex: { $set: index }}), challenge: update(challenge, { pathIndex: { $set: index } }),
}, () => { }, () => {
callback && callback() callback && callback()
}) })
@ -310,15 +255,16 @@ pop_box_new(htmlvalue, 480, 182);
challenge.path = path; challenge.path = path;
const newChallenge = this.handleChallengePath(challenge); const newChallenge = this.handleChallengePath(challenge);
this.setState({ challenge: newChallenge, this.setState({
myshixun: update(myshixun, {system_tip: { $set: false }}), challenge: newChallenge,
myshixun: update(myshixun, { system_tip: { $set: false } }),
}) })
} }
handleChallengePath(challenge) { handleChallengePath(challenge) {
if (challenge.path && typeof challenge.path === "string") { // 多path的处理 if (challenge.path && typeof challenge.path === "string") { // 多path的处理
let path = challenge.path.split(''); let path = challenge.path.split('');
_.remove(path, (item)=> !item) _.remove(path, (item) => !item)
if (path.length > 1) { if (path.length > 1) {
challenge.path = path; challenge.path = path;
challenge.multiPath = true; challenge.multiPath = true;
@ -351,13 +297,6 @@ pop_box_new(htmlvalue, 480, 182);
// newResData.output_sets.had_passed_testsests_error_count = newResData.sets_error_count // newResData.output_sets.had_passed_testsests_error_count = newResData.sets_error_count
newResData.output_sets.had_passed_testsests_error_count = newResData.test_sets_count newResData.output_sets.had_passed_testsests_error_count = newResData.test_sets_count
- newResData.sets_error_count - newResData.sets_error_count
// allowed_hidden_testset
// sets_error_count
// test_sets_count
// test_sets
// had_passed_testsests_error_count
// test_sets
// test_sets
return newResData return newResData
} }
@ -396,10 +335,10 @@ pop_box_new(htmlvalue, 480, 182);
} else { // 选择题 } else { // 选择题
// 选择题题干markdown初始化 // 选择题题干markdown初始化
const $ = window.$ const $ = window.$
window.setTimeout(()=>{ window.setTimeout(() => {
var lens = $("#choiceRepositoryView textarea").length; var lens = $("#choiceRepositoryView textarea").length;
for(var i = 1; i <= lens; i++){ for (var i = 1; i <= lens; i++) {
window.editormd.markdownToHTML("choose_subject_" + i, { window.editormd.markdownToHTML("choose_subject_" + i, {
htmlDecode: "style,script,iframe", // you can filter tags decode htmlDecode: "style,script,iframe", // you can filter tags decode
taskList: true, taskList: true,
@ -522,7 +461,7 @@ pop_box_new(htmlvalue, 480, 182);
fetchAll(stageId, noTimeout) { fetchAll(stageId, noTimeout) {
if (window.__fetchAllFlag == true ) { if (window.__fetchAllFlag == true) {
console.log('TPIContextProvider call fetchAll repeatly!') console.log('TPIContextProvider call fetchAll repeatly!')
return; return;
} }
@ -595,7 +534,7 @@ pop_box_new(htmlvalue, 480, 182);
if (resData.final_score) { if (resData.final_score) {
var game = this.state.game; var game = this.state.game;
this.setState({ this.setState({
game: update(game, {final_score: { $set: resData.final_score }}), game: update(game, { final_score: { $set: resData.final_score } }),
grade: resData.grade grade: resData.grade
}) })
} else { } else {
@ -609,7 +548,7 @@ pop_box_new(htmlvalue, 480, 182);
this.setState({ this.setState({
game: (this.state.game.status == 2 ? update(this.state.game, { game: (this.state.game.status == 2 ? update(this.state.game, {
isPassThrough: { $set: true }, isPassThrough: { $set: true },
}) : this.state.game) , }) : this.state.game),
currentGamePassed: false currentGamePassed: false
}) })
} }
@ -645,7 +584,8 @@ pop_box_new(htmlvalue, 480, 182);
window.clearTimeout(this.showWebDisplayButtonTimeout) window.clearTimeout(this.showWebDisplayButtonTimeout)
} }
this.showWebDisplayButtonTimeout = window.setTimeout(() => { this.showWebDisplayButtonTimeout = window.setTimeout(() => {
this.setState({ challenge: update(challenge, this.setState({
challenge: update(challenge,
{ {
showWebDisplayButton: { $set: false }, showWebDisplayButton: { $set: false },
}) })
@ -677,7 +617,7 @@ pop_box_new(htmlvalue, 480, 182);
language_display(data) { language_display(data) {
const { game, tomcat_url } = this.state; const { game, tomcat_url } = this.state;
const challenge = Object.assign({}, this.state.challenge) const challenge = Object.assign({}, this.state.challenge)
if(challenge.isWeb && data.port != -1) { if (challenge.isWeb && data.port != -1) {
// var $result = $("#php_display"); // var $result = $("#php_display");
challenge.showWebDisplayButton = true; // ActionView处是否出现查看效果按钮 challenge.showWebDisplayButton = true; // ActionView处是否出现查看效果按钮
this.initDisplayInterval() this.initDisplayInterval()
@ -687,34 +627,10 @@ pop_box_new(htmlvalue, 480, 182);
challenge.webDisplayUrl = webDisplayUrl challenge.webDisplayUrl = webDisplayUrl
challenge.showLanguagePictrue = true; // 评测通过弹出层是否出现查看效果按钮 challenge.showLanguagePictrue = true; // 评测通过弹出层是否出现查看效果按钮
} }
// else if(challenge.isAndroid && data.picture != 0){ else if (data.picture != 0) {
// // https://www.educoder.net/shixuns/qrcode?game_id=218589&_=1525571882782
// $.ajax({
// url: `/shixuns/qrcode?game_id=${game.id}`,
// dataType: 'script'
// });
// challenge.showLanguagePictrue = true;
// }
else if(data.picture != 0){
// 对应服务端erb文件为 _picture_display.html.erb
// $.ajax({
// url: "/users/picture_show?game_id="+data.picture,
// cache: false,
// dataType: 'script'
// });
/**
{
"type": "image",
"orignal_picture": [],
"user_picture": [],
"answer_picture": []
}
*/
const url = `/tasks/${game.identifier}/picture_display.json` const url = `/tasks/${game.identifier}/picture_display.json`
axios.get(url) axios.get(url)
.then((response) => { .then((response) => {
// response.data.type qrcode_str
this.showEffectDisplay(response.data) this.showEffectDisplay(response.data)
}) })
@ -730,7 +646,7 @@ pop_box_new(htmlvalue, 480, 182);
, had_test_count, had_passed_testsests_error_count, had_passed_testsests_hidden_count , had_test_count, had_passed_testsests_error_count, had_passed_testsests_hidden_count
, had_passed_testsests_public_count, final_score, gold, experience, latest_output, status , had_passed_testsests_public_count, final_score, gold, experience, latest_output, status
, had_done, score, tag_count, power, record, next_game, grade, picture, , had_done, score, tag_count, power, record, next_game, grade, picture,
sets_error_count, last_compile_output, record_consume_time} = response; sets_error_count, last_compile_output, record_consume_time } = response;
const { game } = this.state; const { game } = this.state;
@ -832,7 +748,7 @@ pop_box_new(htmlvalue, 480, 182);
this.setState({ this.setState({
output_sets: output_sets, output_sets: output_sets,
grade: this.state.grade + deltaScore, grade: this.state.grade + deltaScore,
game : update(game, {test_sets_view: { $set: true }}), game: update(game, { test_sets_view: { $set: true } }),
testSetsExpandedArray: testSetsExpandedArrayInitVal.slice(0) testSetsExpandedArray: testSetsExpandedArrayInitVal.slice(0)
}) })
this.handleGdialogClose(); this.handleGdialogClose();
@ -884,9 +800,6 @@ pop_box_new(htmlvalue, 480, 182);
onGdialogOkBtnClick() { onGdialogOkBtnClick() {
this.dialogOkCallback && this.dialogOkCallback(); this.dialogOkCallback && this.dialogOkCallback();
// this.setState({
// gDialogOpen: true
// })
} }
handleGdialogClose = () => { handleGdialogClose = () => {
this.setState({ this.setState({
@ -894,7 +807,6 @@ pop_box_new(htmlvalue, 480, 182);
}) })
} }
render() { render() {
const { classes } = this.props;
return ( return (
<TPIContext.Provider <TPIContext.Provider
value={{ value={{
@ -929,61 +841,53 @@ pop_box_new(htmlvalue, 480, 182);
match: this.props.match match: this.props.match
}} }}
> >
<Dialog <Modal
id="tpi-dialog" id="tpi-dialog"
open={this.state.gDialogOpen} title='提示'
disableEscapeKeyDown={true} visible={this.state.gDialogOpen}
onClose={() => this.handleGdialogClose()} onCancel={() => this.handleGdialogClose()}
> footer={
<DialogTitle id="alert-dialog-title">{"提示"}</DialogTitle> <Fragment>
<DialogContent id="dialog-content"> {this.isSingleButton ? <div className="task-popup-submit clearfix"
<DialogContentText id="alert-dialog-description" style={{textAlign: 'center'}}> style={{ textAlign: 'center', 'margin-bottom': '14px' }}>
{this.state.gDialogContentText}
</DialogContentText>
</DialogContent>
{/* mb20 加了有样式问题 */}
<DialogActions className={""} id="dialog-actions">
{ this.isSingleButton ? <div className="task-popup-submit clearfix"
style={{ textAlign: 'center', 'margin-bottom': '14px'}}>
<a className="task-btn task-btn-orange" <a className="task-btn task-btn-orange"
onClick={this.handleGdialogClose} onClick={this.handleGdialogClose}
>知道啦</a> >知道啦</a>
</div> : </div> :
<React.Fragment> <React.Fragment>
<Button onClick={() => this.handleGdialogClose()} color="primary" <Button onClick={() => this.handleGdialogClose()} color="primary">
className={`${classes.button} ${classes.buttonGray} ${classes.borderRadiusNone}`}>
关闭 关闭
</Button> </Button>
<Button variant="raised" className={`${classes.button} ${classes.borderRadiusNone}`} <Button variant="raised"
onClick={() => this.onGdialogOkBtnClick() } color="primary" autoFocus> onClick={() => this.onGdialogOkBtnClick()} color="primary" autoFocus>
{ this.okButtonText ? this.okButtonText : '确定' } {this.okButtonText ? this.okButtonText : '确定'}
</Button> </Button>
</React.Fragment> } </React.Fragment>}
{this.moreButtonsRender && this.moreButtonsRender()} {this.moreButtonsRender && this.moreButtonsRender()}
</DialogActions>
</Dialog>
<Snackbar </Fragment>
}
>
<div id="alert-dialog-description" style={{ textAlign: 'center' }}>
{this.state.gDialogContentText}
</div>
</Modal>
{this.state.snackbarOpen ?
<Alert
className={"rootSnackbar"} className={"rootSnackbar"}
open={this.state.snackbarOpen}
autoHideDuration={3000}
anchorOrigin={{ vertical: this.state.snackbarVertical || 'top'
, horizontal: this.state.snackbarHorizontal || 'center' }}
onClose={() => this.handleSnackbarClose()} onClose={() => this.handleSnackbarClose()}
transition={Fade}
SnackbarContentProps={{
'aria-describedby': 'message-id',
}}
resumeHideDuration={2000}
message={<span id="message-id">{this.state.snackbarText}</span>} message={<span id="message-id">{this.state.snackbarText}</span>}
/> /> : null
}
{this.props.children} {this.props.children}
</TPIContext.Provider> </TPIContext.Provider>
) )
} }
} }
export default CNotificationHOC() (withStyles(styles) (TPIContextProvider)); export default CNotificationHOC()(TPIContextProvider);

@ -2,11 +2,13 @@ body {
margin: 0; margin: 0;
padding: 0; padding: 0;
font-family: sans-serif; font-family: sans-serif;
user-select: none;
} }
.page--header { .page--header {
z-index: 101 !important; z-index: 101 !important;
} }
.ant-popover-buttons { .ant-popover-buttons {
text-align: center !important; text-align: center !important;
} }
@ -17,24 +19,118 @@ body {
z-index: 1; z-index: 1;
} }
/* 隐藏newMessage提示按钮 */ #root,
#shixun_comment_block .buttons > p:last-child { .app {
display: none !important; width: 100%;
height: 100%;
}
p,
h2,
h3,
h4 {
margin: 0;
padding: 0;
}
ul {
list-style: none;
}
/* md
codermirror maybeUpdateLineNumberWidth
*/
.editormd .CodeMirror-linenumbers {
padding: 0;
}
.editormd-html-preview hr,
.editormd-preview-container hr {
/* 颜色加深 */
border-top: 1px solid #ccc;
}
/* 重置掉antd的一些样式 */
html,
body {
-webkit-font-smoothing: auto !important;
font-size: 16px;
}
.ant-progress-textyes {
color: #52c41a;
}
.ant-progress-textno {
color: #f5222d;
}
/* md多空格 */
.markdown-body p {
white-space: pre-wrap;
font-size: 16px !important
} }
.ant-message{ .markdown-body>p {
z-index: 20000; line-height: 25px;
} }
/*.ant-modal-header{*/
/*border-radius: 10px;*/ /* https://www.educoder.net/courses/2346/group_homeworks/34405/question */
/*}*/ .renderAsHtml.markdown-body p {
.ant-upload-list-item-info .anticon-loading, .ant-upload-list-item-info .anticon-paper-clip{ white-space: inherit;
color: #29bd8b !important; }
/* resize */
.editormd .CodeMirror {
border-right: none !important;
} }
.anticon anticon-paper-clip{
color: #29bd8b !important; .editormd-preview {
border-left: 1px solid rgb(221, 221, 221);
/* 某些情况下被cm盖住了 */
z-index: 99;
}
/* 图片点击放大的场景,隐藏图片链接 */
.editormd-image-click-expand .editormd-image-dialog {
height: 234px !important;
} }
.MuiModal-root-15{ .editormd-image-click-expand .editormd-image-dialog .image-link {
z-index: 1000 !important; display: none;
}
/* 解决鼠标框选时,左边第一列没高亮的问题 */
.CodeMirror .CodeMirror-lines pre.CodeMirror-line,
.CodeMirror .CodeMirror-lines pre.CodeMirror-line-like {
padding: 0 12px;
}
/* antd扩展 */
.formItemInline.ant-form-item {
display: flex;
}
.formItemInline .ant-form-item-control-wrapper {
flex: 1;
}
/* AutoComplete placeholder 不显示的问题 */
.ant-select-auto-complete.ant-select .ant-select-selection__placeholder {
z-index: 2;
}
/* 兼容性 */
/* 火狐有滚动条时高度问题 */
@-moz-document url-prefix() {
.newContainers {
min-height: calc(100% - 60px) !important;
}
}
.indexHOC {
position: relative;
} }

@ -1,46 +1,13 @@
import React from 'react'; import React from 'react'
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom'
import './index.css'
import './index.css'; import App from './App'
import './indexPlus.css'; import * as serviceWorker from './serviceWorker'
import App from './App';
// 加之前main.js 18.1MB
// import { message } from 'antd';
import message from 'antd/lib/message';
import 'antd/lib/message/style/css';
import { AppContainer } from 'react-hot-loader';
import registerServiceWorker from './registerServiceWorker';
import { configureUrlQuery } from 'react-url-query';
import history from './history';
// link the history used in our app to url-query so it can update the URL with it.
configureUrlQuery({ history });
// ----------------------------------------------------------------------------------- 请求配置
window.__useKindEditor = false; window.__useKindEditor = false;
ReactDOM.render(<App />, document.getElementById('root'))
// If you want your app to work offline and load faster, you can change
const render = (Component) => { // unregister() to register() below. Note this comes with some pitfalls.
ReactDOM.render( // Learn more about service workers: https://bit.ly/CRA-PWA
<AppContainer {...this.props} {...this.state}> serviceWorker.unregister()
<Component {...this.props} {...this.state}/>
</AppContainer>,
document.getElementById('root')
);
}
// ReactDOM.render(
// ,
// document.getElementById('root'));
// registerServiceWorker();
render(App);
if (module.hot) {
module.hot.accept('./App', () => { render(App) });
}

@ -1,4 +0,0 @@
/* material ui 给body加了个6px padding */
body {
padding-right: 0px !important;
}

@ -0,0 +1,7 @@
<svg xmlns="https://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3">
<g fill="#61DAFB">
<path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/>
<circle cx="420.9" cy="296.5" r="45.7"/>
<path d="M520.5 78.1z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

@ -1,4 +1,4 @@
<svg xmlns="https://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3">
<g fill="#61DAFB"> <g fill="#61DAFB">
<path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/> <path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/>
<circle cx="420.9" cy="296.5" r="45.7"/> <circle cx="420.9" cy="296.5" r="45.7"/>

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

@ -1,14 +1,9 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
import Loading from '../../Loading'; import TPMIndexHOC from '../tpm/TPMIndexHOC';
import Loadable from 'react-loadable'; import { SnackbarHOC, getImageUrl } from 'educoder';
import { TPMIndexHOC } from '../tpm/TPMIndexHOC';
import { SnackbarHOC,getImageUrl } from 'educoder';
class Shixunauthority extends Component { class Shixunauthority extends Component {
render() { render() {
@ -34,4 +29,4 @@ class Shixunauthority extends Component {
} }
} }
export default SnackbarHOC() (TPMIndexHOC ( Shixunauthority )); export default SnackbarHOC()(TPMIndexHOC(Shixunauthority));

@ -4,11 +4,11 @@ import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
import Loading from '../../Loading'; import Loading from '../../Loading';
import Loadable from 'react-loadable'; import { Loadable } from 'educoder';
import { TPMIndexHOC } from '../tpm/TPMIndexHOC'; import TPMIndexHOC from '../tpm/TPMIndexHOC';
import { SnackbarHOC,getImageUrl } from 'educoder'; import { SnackbarHOC, getImageUrl } from 'educoder';
class http500 extends Component { class http500 extends Component {
render() { render() {
@ -34,4 +34,4 @@ class http500 extends Component {
} }
} }
export default SnackbarHOC() (TPMIndexHOC ( http500 )); export default SnackbarHOC()(TPMIndexHOC(http500));

@ -4,11 +4,11 @@ import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
import Loading from '../../Loading'; import Loading from '../../Loading';
import Loadable from 'react-loadable'; import { Loadable } from 'educoder';
import { TPMIndexHOC } from '../tpm/TPMIndexHOC'; import TPMIndexHOC from '../tpm/TPMIndexHOC';
import { SnackbarHOC,getImageUrl } from 'educoder'; import { SnackbarHOC, getImageUrl } from 'educoder';
class Shixunnopage extends Component { class Shixunnopage extends Component {
render() { render() {
@ -34,4 +34,4 @@ class Shixunnopage extends Component {
} }
} }
export default SnackbarHOC() (TPMIndexHOC ( Shixunnopage )); export default SnackbarHOC()(TPMIndexHOC(Shixunnopage));

@ -1,98 +1,51 @@
import React, { Component } from 'react'; import React, { Component } from 'react'
import Tooltip from 'material-ui/Tooltip';
import { Tooltip } from 'antd'
import './Comment.css' import './Comment.css'
import messageImg from '../../images/tpi/message.svg'
import messagegreyImg from '../../images/tpi/messagegrey.svg'
const $ = window.$;
function pasteListener(event) {
if (event.clipboardData.types[0] === 'Files' ) {
event.preventDefault();
// event.stopPropagation();
}
}
/*
*/
class CommentInput extends Component { class CommentInput extends Component {
componentDidMount() {
const { challenge } = this.props;
}
componentWillReceiveProps(newProps, newContext) {
// TODO 暂没有切实训的场景
if (newProps.challenge && newProps.challenge.shixun_id
&& (!this.props.challenge.shixun_id || newProps.challenge.shixun_id != this.props.challenge.shixun_id)) {
setTimeout(()=>{
window.sd_create_editor_from_shixun_data(newProps.challenge.shixun_id, null, "100%", "Shixun");
if ( $.browser.mozilla ) {
setTimeout(() => {
const _body = $('.ke-edit-iframe')[0].contentWindow.document.body;
_body.removeEventListener('paste', pasteListener)
_body.addEventListener('paste', pasteListener)
}, 4200)
}
}, 100)
}
}
render() { render() {
const { createNewComment, editedComment, commentOnChange, challenge, shixun, loading, praisePlus, gotNewReply, showNewReply} = this.props; const { createNewComment, editedComment, commentOnChange, challenge, shixun, loading, praisePlus, gotNewReply, showNewReply } = this.props;
/*
onclick="game_praise('<%= @game_challenge.id %>', '<%= @game_challenge.class %>')"
onclick="game_tread('<%= @game_challenge.id %>')"
style={{display: 'none'}}
*/
return ( return (
<li className="comment-input fl" id="shixun_comment_block"> <li className="comment-input fl" id="shixun_comment_block">
{ !challenge.shixun_id ? '' : {!challenge.shixun_id ? '' :
<div nhname={`new_message_${challenge.shixun_id}`} className="fr" style={{ width: '99%'}}> <div nhname={`new_message_${challenge.shixun_id}`} className="fr" style={{ width: '99%' }}>
<form acceptCharset="UTF-8" action="/discusses?challenge_id=118&dis_id=61&dis_type=Shixun" className="df" data-remote="true" id="new_comment_form" method="post"> <form acceptCharset="UTF-8" action="/discusses?challenge_id=118&dis_id=61&dis_type=Shixun" className="df" data-remote="true" id="new_comment_form" method="post">
<div className="fl" style={{flex: 1,marginTop:'7px'}} id="editor_panel"> <div className="fl" style={{ flex: 1, marginTop: '7px' }} id="editor_panel">
<div nhname={`toolbar_container_${challenge.shixun_id}`}></div> <div nhname={`toolbar_container_${challenge.shixun_id}`}></div>
{/*有问题或有建议,请直接给我留言吧!*/} {/*有问题或有建议,请直接给我留言吧!*/}
<textarea id={`comment_news_${challenge.shixun_id}`} <textarea id={`comment_news_${challenge.shixun_id}`}
nhname={`new_message_textarea_${challenge.shixun_id}`} name="content" nhname={`new_message_textarea_${challenge.shixun_id}`} name="content"
value={ editedComment } onChange={ commentOnChange } className="none"> value={editedComment} onChange={commentOnChange} className="none">
</textarea> </textarea>
</div> </div>
<div className="tips" <div className="tips"
style={{ 'float': 'left', 'marginTop': '6px', 'fontSize': '12px', 'color': '#ff6800'}}> style={{ 'float': 'left', 'marginTop': '6px', 'fontSize': '12px', 'color': '#ff6800' }}>
请勿粘贴答案否则将造成账号禁用等后果 请勿粘贴答案否则将造成账号禁用等后果
</div> </div>
<div className="fr buttons" style={{ minWidth:'25px', height: '32px' }}> <div className="fr buttons" style={{ minWidth: '25px', height: '32px' }}>
<a id={`new_message_submit_btn_${challenge.shixun_id}`} href="javascript:void(0)" <a id={`new_message_submit_btn_${challenge.shixun_id}`} href="javascript:void(0)"
style={{display: 'none'}} onClick={ createNewComment } className="commentsbtn task-btn task-btn-blue fr"> style={{ display: 'none' }} onClick={createNewComment} className="commentsbtn task-btn task-btn-blue fr">
发送 发送
</a> </a>
<p className="fr ml10" style={{minWidth:'25px'}} > <p className="fr ml10" style={{ minWidth: '25px' }} >
<Tooltip title={ challenge.user_praise ? "取消点赞" : "点赞"}> <Tooltip title={challenge.user_praise ? "取消点赞" : "点赞"}>
<span id="game_praise_tread" className="color-grey mr20" onClick={praisePlus}> <span id="game_praise_tread" className="color-grey mr20" onClick={praisePlus}>
<i className={`mr3 ${ challenge.user_praise ? "iconfont icon-dianzan color-orange03" : "iconfont icon-dianzan-xian" } `} alt="赞" ></i> <i className={`mr3 ${challenge.user_praise ? "iconfont icon-dianzan color-orange03" : "iconfont icon-dianzan-xian"} `} alt="赞" ></i>
{ challenge.praise_count ? {challenge.praise_count ?
<span className="font-16" id="game_praise_count">{challenge.praise_count}</span> : ''} <span className="font-16" id="game_praise_count">{challenge.praise_count}</span> : ''}
</span> </span>
</Tooltip> </Tooltip>
</p> </p>
<p className="fr ml10" style={{minWidth:'25px'}} > <p className="fr ml10" style={{ minWidth: '25px' }} >
{ gotNewReply ? {gotNewReply ?
<React.Fragment> <React.Fragment>
<i className={`replyIcon newReplyIcon iconfont icon-tpixiaoxitixing`} onClick={showNewReply}></i> <i className={`replyIcon newReplyIcon iconfont icon-tpixiaoxitixing`} onClick={showNewReply}></i>
<span className="dot blink"></span> <span className="dot blink"></span>
</React.Fragment> </React.Fragment>
: :
<Tooltip title={ "暂无新消息" }> <Tooltip title={"暂无新消息"}>
<i className={`replyIcon iconfont icon-tpixiaoxitixing`}></i> <i className={`replyIcon iconfont icon-tpixiaoxitixing`}></i>
</Tooltip> </Tooltip>
} }
@ -106,26 +59,4 @@ class CommentInput extends Component {
} }
} }
/*
<img src={messagegreyImg}/>
<span data-tip-top={ tread ? "踩" : "取消踩" } id="game_tread" className="color-grey" style={{paddingTop:'7px'}}>
<i className={`fa fa-thumbs-down font-20 mr3 ${ tread ? "" : "color-orange03" } `} ></i>
<span className="font-12 font-bd" id="game_tread_count">{tread_count}</span>
</span>
<div className="clearfix with100">
<textarea className="commentTxt"></textarea>
<p className="clearfix">
<a href="javascript:void(0)" className="fl uploadImg mt2">
<img src="/images/sendimg.svg" className="fl mr3 mt6"/><span className="up">上传图片</span>
</a>
<a href="javascript:void(0)" className="commentsbtn task-btn task-btn-blue fr">评论</a>
<span className="fr mr15 mt3"><i className="fa fa-thumbs-up color-dark-grey mr3 font-18"></i>20</span>
<img src="/images/message.svg" className="fr mr15 mt8"/>
</p>
</div>
*/
export default CommentInput; export default CommentInput;

@ -1,72 +0,0 @@
import React, { Component } from 'react';
import { Redirect } from 'react-router';
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
import PropTypes from 'prop-types';
import classNames from 'classnames'
const $ = window.$;
const _origin = window.location.origin;
class CommentItemKEEditor extends Component {
componentDidUpdate(prevProps) {
const { item, currentReplyComment } = this.props;
if ( prevProps.showReplyEditorFlag != this.props.showReplyEditorFlag &&
currentReplyComment && currentReplyComment.id == item.id ) {
this.showOrHideEditor(currentReplyComment)
}
}
// 如果未初始化,会先初始化
showOrHideEditor = (comment) => {
const { user } = this.props;
console.log('initReply ', comment)
const $ = window.$;
var id = comment.id
var reply_message_el = `#reply_message_${id}`
var reply_iconup_el = `#reply_iconup_${id}`
if($(reply_message_el).html() == "") {
$(".reply_to_message").html("");
$(reply_message_el).html(`<div className=\"orig_reply_box borderBottomNone reply_to_message\" id=\"reply_to_message_${id}\">\n <div class=\"homepagePostReplyPortrait mr15 imageFuzzy fl\" id=\"reply_image_${id}\"><a href=\"${user.user_url}\" target=\"_blank\" alt=\"用户头像\"><img alt=\"0?1442652658\" height=\"33\" src=\"${_origin}/images/${user.image_url}\" width=\"33\" /><\/a><\/div>\n <div class=\"orig_textarea fl\" style=\"margin-bottom: 0px\">\n <div nhname=\'new_message_${id}\'>\n <form accept-charset=\"UTF-8\" action=\"/discusses?challenge_id=118&amp;dis_id=61&amp;dis_type=Shixun\" data-remote=\"true\" id=\"new_comment_form\" method=\"post\"><div style=\"margin:0;padding:0;display:inline\"><input name=\"utf8\" type=\"hidden\" value=\"&#x2713;\" /><input name=\"authenticity_token\" type=\"hidden\" value=\"HJTbMpfI8LKUpwghfkvgB2SaMmcIVyVdAezyKmzJ7FU=\" /><\/div>\n <input type=\"hidden\" id=\"dis_reply_id\" name=\"reply_id\" value=\"${id}\">\n <div nhname=\'toolbar_container_${id}\'><\/div>\n <textarea placeholder=\"有问题或有建议,请直接给我留言吧!\" id=\"comment_news_${id}\" style=\"display: none\" nhname=\'new_message_textarea_${id}\' name=\"content\"><\/textarea>\n <a id=\"new_message_submit_btn_${id}\" href=\"javascript:void(0)\" onclick=\"this.style.display=\'none\'\" class=\"mt10 task-btn task-btn-orange fr\">发送<\/a>\n <div class=\"cl\"><\/div>\n <p nhname=\'contentmsg_${id}\'><\/p>\n<\/form> <\/div>\n <div class=\"cl\"><\/div>\n <\/div>\n <div class=\"cl\"><\/div>\n<\/div>\n`); //" ide语法识别
$(reply_iconup_el).show();
$(function(){
window.sd_create_editor_from_data(id ,null,"100%", "Discuss");
});
}else {
if ($(reply_message_el).is(':visible')) {
$(reply_message_el).hide();
} else {
$(reply_message_el).show();
}
// $(reply_message_el).html("");
// $(reply_iconup_el).hide();
}
// 自动focus
setTimeout(()=>{
var iframe =$(`#reply_to_message_${id}`).find('iframe')[0]
iframe && iframe.contentDocument.body.focus()
}, 200)
}
render() {
const { match, history, item, user } = this.props
if (!item) {
return <div></div>
}
return (
<div>
<div className="cl"></div>
<div id={`reply_message_${item.id}`} className="reply_to_message"></div>
</div>
);
}
}
export default ( CommentItemKEEditor );

@ -7,8 +7,8 @@ class CommentItemMDEditor extends Component {
componentDidUpdate(prevProps) { componentDidUpdate(prevProps) {
const { item, currentReplyComment } = this.props; const { item, currentReplyComment } = this.props;
if ( prevProps.showReplyEditorFlag != this.props.showReplyEditorFlag && if (prevProps.showReplyEditorFlag != this.props.showReplyEditorFlag &&
currentReplyComment && currentReplyComment.id == item.id ) { currentReplyComment && currentReplyComment.id == item.id) {
this.showOrHideEditor(currentReplyComment) this.showOrHideEditor(currentReplyComment)
} }
} }
@ -24,7 +24,7 @@ class CommentItemMDEditor extends Component {
const initMD_ID = `reply_message_editorMd_${commentId}` const initMD_ID = `reply_message_editorMd_${commentId}`
const view_selector = `.commentItemMDEditorView_${commentId}` const view_selector = `.commentItemMDEditorView_${commentId}`
const commitBtnSelector = `#commitBtn_${commentId}` const commitBtnSelector = `#commitBtn_${commentId}`
if( $(`#${initMD_ID} textarea`).length === 1 ) { // 没有初始化 if ($(`#${initMD_ID} textarea`).length === 1) { // 没有初始化
const placeholder = '我要回复...' const placeholder = '我要回复...'
// const imageUrl = `/upload_with_markdown?container_id=${commentId}&container_type=Memo`; // const imageUrl = `/upload_with_markdown?container_id=${commentId}&container_type=Memo`;
const imageUrl = `${getUploadActionUrl()}`; const imageUrl = `${getUploadActionUrl()}`;
@ -60,9 +60,9 @@ class CommentItemMDEditor extends Component {
$('.commentItemMDEditorView').hide(); $('.commentItemMDEditorView').hide();
$(view_selector).show(); $(view_selector).show();
}else { // 初始化了,显示隐藏切换 } else { // 初始化了,显示隐藏切换
if ($(reply_message_el).is(':visible')) { if ($(reply_message_el).is(':visible')) {
$( view_selector ).hide() $(view_selector).hide()
} else { } else {
$('.commentItemMDEditorView').hide(); $('.commentItemMDEditorView').hide();
@ -71,7 +71,7 @@ class CommentItemMDEditor extends Component {
window._currentChildcommentMDEditor && window._currentChildcommentMDEditor.resize() window._currentChildcommentMDEditor && window._currentChildcommentMDEditor.resize()
// 自动focus // 自动focus
setTimeout(()=>{ setTimeout(() => {
this.commentMDEditor && this.commentMDEditor.cm && this.commentMDEditor.cm.focus() this.commentMDEditor && this.commentMDEditor.cm && this.commentMDEditor.cm.focus()
this.commentMDEditor.resize() // 解决切换显示、隐藏多次后出现的样式错乱的问题 this.commentMDEditor.resize() // 解决切换显示、隐藏多次后出现的样式错乱的问题
}, 200) }, 200)
@ -82,8 +82,10 @@ class CommentItemMDEditor extends Component {
} }
onCommit = () => { onCommit = () => {
window.$(document).trigger("onReply", { commentContent: this.commentMDEditor.getValue() window.$(document).trigger("onReply", {
, id: this.props.item.id, editor: this.commentMDEditor } ); commentContent: this.commentMDEditor.getValue()
, id: this.props.item.id, editor: this.commentMDEditor
});
} }
render() { render() {
@ -93,7 +95,7 @@ class CommentItemMDEditor extends Component {
} }
return ( return (
<div className={`commentItemMDEditorView commentItemMDEditorView_${item.id}`} style={{display:'none'}}> <div className={`commentItemMDEditorView commentItemMDEditorView_${item.id}`} style={{ display: 'none' }}>
<div className="homepagePostReplyPortrait mr15 fl imageFuzzy" id="reply_image_3097" <div className="homepagePostReplyPortrait mr15 fl imageFuzzy" id="reply_image_3097"
style={{ marginTop: '2px', marginRight: '-20px' }} > style={{ marginTop: '2px', marginRight: '-20px' }} >
<a href={`${user.user_url}`} target="_blank" alt="用户头像"> <a href={`${user.user_url}`} target="_blank" alt="用户头像">
@ -104,17 +106,17 @@ class CommentItemMDEditor extends Component {
<div id={`reply_message_${item.id}`} className="reply_to_message commentItemMDEditor editormd-image-click-expand" <div id={`reply_message_${item.id}`} className="reply_to_message commentItemMDEditor editormd-image-click-expand"
style={{ paddingTop: '0px', paddingBottom: '0px', marginTop: '36px' }} style={{ paddingTop: '0px', paddingBottom: '0px', marginTop: '36px' }}
> >
<div id={`reply_message_editorMd_${item.id}`} className="editorMD" style={{ marginBottom: '0px'}}> <div id={`reply_message_editorMd_${item.id}`} className="editorMD" style={{ marginBottom: '0px' }}>
<textarea style={{'display': 'none'}}> <textarea style={{ 'display': 'none' }}>
</textarea> </textarea>
</div> </div>
<div className="editor__resize" href="javascript:void(0);" style={{display: ''}}>调整高度</div> <div className="editor__resize" href="javascript:void(0);" style={{ display: '' }}>调整高度</div>
<div class="clearfix"> <div class="clearfix">
<a id={`commitBtn_${item.id}`} href="javascript:void(0)" <a id={`commitBtn_${item.id}`} href="javascript:void(0)"
onClick={this.onCommit} style={{ marginRight: '44px' }} onClick={this.onCommit} style={{ marginRight: '44px' }}
className="commentsbtn task-btn task-btn-blue fr " style={{display: ''}}> className="commentsbtn task-btn task-btn-blue fr " style={{ display: '' }}>
{ buttonText || '发送'} {buttonText || '发送'}
</a> </a>
</div> </div>
@ -124,6 +126,6 @@ class CommentItemMDEditor extends Component {
} }
} }
export default ( CommentItemMDEditor ); export default (CommentItemMDEditor);
// style={{ margin: '10px 44px', marginBottom: '0px'}} // style={{ margin: '10px 44px', marginBottom: '0px'}}

@ -1,29 +1,12 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { Tooltip, Modal } from 'antd'
import { getImageUrl } from 'educoder';
import Dialog, {
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
} from 'material-ui/Dialog';
import Button from 'material-ui/Button';
import Tooltip from 'material-ui/Tooltip';
import Pagination from 'rc-pagination';
import 'rc-pagination/assets/index.css';
import { getImageUrl, toPath } from 'educoder';
import Input, { InputLabel } from 'material-ui/Input';
import { FormControl, FormHelperText } from 'material-ui/Form';
import CommentItemKEEditor from './CommentItemKEEditor';
import CommentItemMDEditor from './CommentItemMDEditor'; import CommentItemMDEditor from './CommentItemMDEditor';
import './Comment.css' import './Comment.css'
import Modals from '../modals/Modals' import Modals from '../modals/Modals'
import { InputNumber } from 'antd' import { InputNumber, Pagination } from 'antd'
/* /*
-------------------------- 样式相关 -------------------------- 样式相关
@ -104,10 +87,10 @@ class Comments extends Component {
$(document).off("onReply"); $(document).off("onReply");
} }
componentDidMount() { componentDidMount() {
setTimeout(()=>{ setTimeout(() => {
const $ = window.$; const $ = window.$;
// 绑定后会自动off 加timeout试试 // 绑定后会自动off 加timeout试试
$(document).on("onReply", (e, args)=>{ $(document).on("onReply", (e, args) => {
const { commentContent, id, editor } = args; const { commentContent, id, editor } = args;
this.props.replyComment(commentContent, id, editor) this.props.replyComment(commentContent, id, editor)
@ -117,43 +100,10 @@ class Comments extends Component {
} }
initReply(comment) { initReply(comment) {
this.props.initReply && this.props.initReply(comment) this.props.initReply && this.props.initReply(comment)
// 如果配置的使用kindEditor
if (window.__useKindEditor === true) {
const { user } = this.props;
console.log('initReply ', comment)
const $ = window.$;
var id = comment.id
var reply_message_el = `#reply_message_${id}`
var reply_iconup_el = `#reply_iconup_${id}`
if($(reply_message_el).html() == "") {
$(".reply_to_message").html("");
$(reply_message_el).html(`<div className=\"orig_reply_box borderBottomNone reply_to_message\" id=\"reply_to_message_${id}\">\n <div class=\"homepagePostReplyPortrait mr15 imageFuzzy fl\" id=\"reply_image_${id}\"><a href=\"${user.user_url}\" target=\"_blank\" alt=\"用户头像\"><img alt=\"0?1442652658\" height=\"33\" src=\"${_origin}/images/${user.image_url}\" width=\"33\" /><\/a><\/div>\n <div class=\"orig_textarea fl\" style=\"margin-bottom: 0px\">\n <div nhname=\'new_message_${id}\'>\n <form accept-charset=\"UTF-8\" action=\"/discusses?challenge_id=118&amp;dis_id=61&amp;dis_type=Shixun\" data-remote=\"true\" id=\"new_comment_form\" method=\"post\"><div style=\"margin:0;padding:0;display:inline\"><input name=\"utf8\" type=\"hidden\" value=\"&#x2713;\" /><input name=\"authenticity_token\" type=\"hidden\" value=\"HJTbMpfI8LKUpwghfkvgB2SaMmcIVyVdAezyKmzJ7FU=\" /><\/div>\n <input type=\"hidden\" id=\"dis_reply_id\" name=\"reply_id\" value=\"${id}\">\n <div nhname=\'toolbar_container_${id}\'><\/div>\n <textarea placeholder=\"有问题或有建议,请直接给我留言吧!\" id=\"comment_news_${id}\" style=\"display: none\" nhname=\'new_message_textarea_${id}\' name=\"content\"><\/textarea>\n <a id=\"new_message_submit_btn_${id}\" href=\"javascript:void(0)\" onclick=\"this.style.display=\'none\'\" class=\"mt10 task-btn task-btn-orange fr\">${this.props.buttonText || '发送'}<\/a>\n <div class=\"cl\"><\/div>\n <p nhname=\'contentmsg_${id}\'><\/p>\n<\/form> <\/div>\n <div class=\"cl\"><\/div>\n <\/div>\n <div class=\"cl\"><\/div>\n<\/div>\n`); //" ide语法识别
$(reply_iconup_el).show();
$(function(){
window.sd_create_editor_from_data(id ,null,"100%", "Discuss");
});
}else {
if ($(reply_message_el).is(':visible')) {
$(reply_message_el).hide();
} else {
$(reply_message_el).show();
}
// $(reply_message_el).html("");
// $(reply_iconup_el).hide();
}
} else { // MD
this.setState({ this.setState({
currentReplyComment: comment, currentReplyComment: comment,
showReplyEditorFlag: !this.state.showReplyEditorFlag showReplyEditorFlag: !this.state.showReplyEditorFlag
}) })
}
}
// enableReplyTo
// onClick={() => this.replyTo(item.user_id)}
replyTo = (toUserId) => {
} }
renderChildenComments(comment) { renderChildenComments(comment) {
@ -161,7 +111,7 @@ class Comments extends Component {
return '' return ''
} }
const { user } = this.props; const { user } = this.props;
let childCommentsElement = comment.children.map((item, index) =>{ let childCommentsElement = comment.children.map((item, index) => {
let _content = this.parseCommentContent(item.content); let _content = this.parseCommentContent(item.content);
return ( return (
@ -175,11 +125,11 @@ class Comments extends Component {
{/* { item.position ? <span className="fl color-light-green font-14 ml15">[第{item.position}关]</span> : ""} */} {/* { item.position ? <span className="fl color-light-green font-14 ml15">[第{item.position}关]</span> : ""} */}
{ {
item.reward ? item.reward ?
<Tooltip title={ `已奖励金币${item.reward}` } disableFocusListener={true}> <Tooltip title={`已奖励金币${item.reward}`} disableFocusListener={true}>
<a href="javascript:void(0);" style={{ marginLeft: '20px', cursor: 'default'}} <a href="javascript:void(0);" style={{ marginLeft: '20px', cursor: 'default' }}
className={`rewarded color-grey-8 font-12 fl ${ item.admin === true ? '': 'normalUser'}`} className={`rewarded color-grey-8 font-12 fl ${item.admin === true ? '' : 'normalUser'}`}
> >
<i className="iconfont icon-gift mr5 color-orange fl" style={{display: 'inline'}}></i><span className="fl">{item.reward}</span> <i className="iconfont icon-gift mr5 color-orange fl" style={{ display: 'inline' }}></i><span className="fl">{item.reward}</span>
</a> </a>
</Tooltip> : '' </Tooltip> : ''
} }
@ -190,59 +140,39 @@ class Comments extends Component {
</span> </span>
{this.props.showRewardButton != false && comment.admin === true ? {this.props.showRewardButton != false && comment.admin === true ?
<a href="javascript:void(0);" className="color-grey-8" onClick={() => this.showGoldRewardDialog(comment, item) }> <a href="javascript:void(0);" className="color-grey-8" onClick={() => this.showGoldRewardDialog(comment, item)}>
<Tooltip title={ "给TA奖励金币" } disableFocusListener={true}> <Tooltip title={"给TA奖励金币"} disableFocusListener={true}>
<i className="iconfont icon-jiangli fl"></i> <i className="iconfont icon-jiangli fl"></i>
</Tooltip> </Tooltip>
</a> </a>
:""} : ""}
{/*子回复还没hidden字段*/} {/*子回复还没hidden字段*/}
{false && comment.admin === true ? {false && comment.admin === true ?
<Tooltip title={ item.hidden ? "取消隐藏" : "隐藏评论" }> <Tooltip title={item.hidden ? "取消隐藏" : "隐藏评论"}>
<a href="javascript:void(0);" className="color-grey-8" onClick={() => this.onCommentBtnClick(comment, item, item.hidden ? 'hiddenCancel' : 'hidden') }> <a href="javascript:void(0);" className="color-grey-8" onClick={() => this.onCommentBtnClick(comment, item, item.hidden ? 'hiddenCancel' : 'hidden')}>
<i className={`fa ${item.hidden ? 'fa-eye' : 'fa-eye-slash'} mr5`}></i> <i className={`fa ${item.hidden ? 'fa-eye' : 'fa-eye-slash'} mr5`}></i>
</a> </a>
</Tooltip> </Tooltip>
:""} : ""}
{/* 新版user_id不准获取方式不对 */} {/* 新版user_id不准获取方式不对 */}
{ comment.admin === true || item.can_delete || item.user_id === user.user_id || item.user_login == user.login ? {comment.admin === true || item.can_delete || item.user_id === user.user_id || item.user_login == user.login ?
<a href="javascript:void(0);" className="color-grey-8" id="delete_reply_118_952" onClick={() => this.onCommentBtnClick(comment, item, 'delete') }> <a href="javascript:void(0);" className="color-grey-8" id="delete_reply_118_952" onClick={() => this.onCommentBtnClick(comment, item, 'delete')}>
<Tooltip title={ "删除" } disableFocusListener={true}> <Tooltip title={"删除"} disableFocusListener={true}>
<i className="iconfont icon-shanchu mr5"></i> <i className="iconfont icon-shanchu mr5"></i>
</Tooltip> </Tooltip>
</a> </a>
: ''} : ''}
{/*
<span className="ml5 mr5 color-grey-8">|</span>
<span className="reply_praise_count_952">
<a href="/praise_tread/praise_plus?obj_id=952&amp;obj_type=Discuss&amp;type=reply&amp;user_activity_id=952" data-remote="true" className="fr mr5 color-grey-8" data-tip-down="点赞">
<i className="fa fa-thumbs-up mr5"></i>
<span className="ml5 fr"></span>
</a>
</span>*/}
</p> </p>
{/* currentUser.id == item.creator_user.id && (
<p className="fr mr10 orig_repll">
<span id={`hidden_discuss_btn_${item.id}`}>
<a href="javascript:void(0);" className="color-grey-8" onClick={ this.onCommentBtnClick(comment, item, 'delete') } >
<i className="far fa-trash-alt mr5"></i>
</a>
<span className="ml5 mr5 color-grey-8">|</span>
</span>
</p>
)*/}
</div> </div>
<div className="comment_content clearfix" id={`reply_content_${item.id}`}> <div className="comment_content clearfix" id={`reply_content_${item.id}`}>
<div className="color-grey-3" id={`reply_content_${item.id}`}> <div className="color-grey-3" id={`reply_content_${item.id}`}>
<div className={"break_word_comments markdown-body"} dangerouslySetInnerHTML={{__html: _content}}></div> <div className={"break_word_comments markdown-body"} dangerouslySetInnerHTML={{ __html: _content }}></div>
<div className="cl"></div> <div className="cl"></div>
</div> </div>
</div> </div>
@ -291,13 +221,13 @@ class Comments extends Component {
<div className="comment_item_cont df clearfix" key={index}> <div className="comment_item_cont df clearfix" key={index}>
<div className="J_Comment_Face fl"> <div className="J_Comment_Face fl">
<a href={`${_origin}/users/${item.user_login}`} target="_blank"> <a href={`${_origin}/users/${item.user_login}`} target="_blank">
<img alt="用户头像" height="50" src={getImageUrl(`images/${item.image_url}`)} width="50"/> <img alt="用户头像" height="50" src={getImageUrl(`images/${item.image_url}`)} width="50" />
</a> </a>
</div> </div>
<div className="t_content fl"> <div className="t_content fl">
<div className="J_Comment_Reply"> <div className="J_Comment_Reply">
<div className="comment_orig_content" style={{ margin:"0px" }}> <div className="comment_orig_content" style={{ margin: "0px" }}>
<div className="J_Comment_Info clearfix mt3"> <div className="J_Comment_Info clearfix mt3">
@ -306,9 +236,9 @@ class Comments extends Component {
{item.username} {item.username}
</a> </a>
<span className="t_area fl">{item.time}</span> <span className="t_area fl">{item.time}</span>
{ item.position && <span className="fl color-light-green font-14 ml15">[{item.position}]</span> } {item.position && <span className="fl color-light-green font-14 ml15">[{item.position}]</span>}
{ item.game_url ? {item.game_url ?
<Tooltip title={ `点击查看TA的代码页面` } disableFocusListener={true}> <Tooltip title={`点击查看TA的代码页面`} disableFocusListener={true}>
<a href={item.game_url} target="_blank" className="fl font-14 ml15" <a href={item.game_url} target="_blank" className="fl font-14 ml15"
style={{ color: "#4CACFF", cursor: "pointer" }} style={{ color: "#4CACFF", cursor: "pointer" }}
>查看</a> >查看</a>
@ -316,9 +246,9 @@ class Comments extends Component {
{ {
item.reward ? item.reward ?
<Tooltip title={ `已奖励金币${item.reward}` } disableFocusListener={true}> <Tooltip title={`已奖励金币${item.reward}`} disableFocusListener={true}>
<a href="javascript:void(0);" style={{ marginLeft: '20px', cursor: 'default'}} <a href="javascript:void(0);" style={{ marginLeft: '20px', cursor: 'default' }}
className={`rewarded color-grey-8 font-12 fl ${ item.admin === true ? '': 'normalUser'}`} className={`rewarded color-grey-8 font-12 fl ${item.admin === true ? '' : 'normalUser'}`}
> >
<i className="iconfont icon-gift mr5 color-orange fl"></i><span className="fl">{item.reward}</span> <i className="iconfont icon-gift mr5 color-orange fl"></i><span className="fl">{item.reward}</span>
</a> </a>
@ -326,79 +256,60 @@ class Comments extends Component {
} }
</div> </div>
{/* currentUser.id == item.creator_user.id && (
<p className="fr mr10 orig_repll">
<span id={`hidden_discuss_btn_${item.id}`}>
<a href="javascript:void(0);" className="color-grey-8" onClick={ deleteComment.bind(this, item, index) } >
<i className="far fa-trash-alt mr5"></i>
</a>
<span className="ml5 mr5 color-grey-8">|</span>
</span>
</p>
)*/}
</div> </div>
<div className="comment_content clearfix" id={`reply_content_${item.id}`}> <div className="comment_content clearfix" id={`reply_content_${item.id}`}>
<div className="color-grey-3" id={`reply_content_${item.id}`}> <div className="color-grey-3" id={`reply_content_${item.id}`}>
{/* 改成后端返回了的都是要显示的不管hidden的值是true还是false */} <div className={"break_word_comments markdown-body"} dangerouslySetInnerHTML={{ __html: _content }}></div>
{/* { item.hidden && ((this.props.onlySuperAdminCouldHide && !item.isSuperAdmin)
|| !this.props.onlySuperAdminCouldHide && item.admin === false && (item.manager === false || item.manager == undefined))
? <p className="color-orange font-16">违规评论已被屏蔽</p>
: */}
<div className={"break_word_comments markdown-body"} dangerouslySetInnerHTML={{__html: _content}}></div>
{/* } */}
<div className="cl"></div> <div className="cl"></div>
</div> </div>
</div> </div>
<div className="childrenCommentsView"> <div className="childrenCommentsView">
{(item && item.children && item.children.length) ? <div className="trangle"></div>: ''} {(item && item.children && item.children.length) ? <div className="trangle"></div> : ''}
{this.renderChildenComments(item)} {this.renderChildenComments(item)}
{ item.isAllChildrenLoaded != true && item.children && this.props.isChildCommentPagination == true && item.child_message_count > 5? {item.isAllChildrenLoaded != true && item.children && this.props.isChildCommentPagination == true && item.child_message_count > 5 ?
<Tooltip title={ "点击查看更多回复" } disableFocusListener={true}> <Tooltip title={"点击查看更多回复"} disableFocusListener={true}>
<div className="loadMoreChildComments" onClick={() => {this.props.loadMoreChildComments && this.props.loadMoreChildComments(item)}}> <div className="loadMoreChildComments" onClick={() => { this.props.loadMoreChildComments && this.props.loadMoreChildComments(item) }}>
<i className="iconfont icon-xiajiantou"></i> <i className="iconfont icon-xiajiantou"></i>
</div> </div>
</Tooltip> </Tooltip>
: ''} : ''}
</div> </div>
{/*mr10 */}
<p className="fr orig_reply"> <p className="fr orig_reply">
<span id="hidden_discuss_btn_952"> <span id="hidden_discuss_btn_952">
</span> </span>
{/* && !item.reward */}
{this.props.showRewardButton != false && item.admin === true ? {this.props.showRewardButton != false && item.admin === true ?
<a href="javascript:void(0);" className="color-grey-8 fl mt2" onClick={() => this.showGoldRewardDialog(item) }> <a href="javascript:void(0);" className="color-grey-8 fl mt2" onClick={() => this.showGoldRewardDialog(item)}>
<Tooltip title={ "给TA奖励金币" } disableFocusListener={true}> <Tooltip title={"给TA奖励金币"} disableFocusListener={true}>
<i className="iconfont icon-jiangli mr5 fl"></i> <i className="iconfont icon-jiangli mr5 fl"></i>
</Tooltip> </Tooltip>
</a> </a>
:""} : ""}
{ this.props.showHiddenButton == true {this.props.showHiddenButton == true
&& (this.props.onlySuperAdminCouldHide && item.isSuperAdmin || !this.props.onlySuperAdminCouldHide && item.admin === true) ? && (this.props.onlySuperAdminCouldHide && item.isSuperAdmin || !this.props.onlySuperAdminCouldHide && item.admin === true) ?
<Tooltip title={ item.hidden ? "取消隐藏" : "隐藏评论" } disableFocusListener={true}> <Tooltip title={item.hidden ? "取消隐藏" : "隐藏评论"} disableFocusListener={true}>
<a href="javascript:void(0);" className="color-grey-8 fl mt1" onClick={() => this.onCommentBtnClick(item, '', item.hidden ? 'hiddenCancel' : 'hidden') }> <a href="javascript:void(0);" className="color-grey-8 fl mt1" onClick={() => this.onCommentBtnClick(item, '', item.hidden ? 'hiddenCancel' : 'hidden')}>
<i className={` ${item.hidden ? 'iconfont icon-yincangbiyan' : 'fa fa-eye'} mr5`}></i> <i className={` ${item.hidden ? 'iconfont icon-yincangbiyan' : 'fa fa-eye'} mr5`}></i>
</a> </a>
</Tooltip> </Tooltip>
:""} : ""}
{ item.admin && ( !item.children || item.children.length === 0 )? {item.admin && (!item.children || item.children.length === 0) ?
<a href="javascript:void(0);" className="color-grey-8" onClick={() => this.onCommentBtnClick(item, '', 'delete') }> <a href="javascript:void(0);" className="color-grey-8" onClick={() => this.onCommentBtnClick(item, '', 'delete')}>
<Tooltip title={ "删除" } disableFocusListener={true}> <Tooltip title={"删除"} disableFocusListener={true}>
<i className="iconfont icon-shanchu mr5"></i> <i className="iconfont icon-shanchu mr5"></i>
</Tooltip> </Tooltip>
</a> : '' } </a> : ''}
{/* <span className="ml5 mr5 color-grey-8">|</span>*/} {/* <span className="ml5 mr5 color-grey-8">|</span>*/}
{(this.props.showReply == undefined || this.props.showReply == true) && <a href={`javascript:void(0)`} className="color-grey-8" {(this.props.showReply == undefined || this.props.showReply == true) && <a href={`javascript:void(0)`} className="color-grey-8"
onClick={() => this.initReply(item) } > onClick={() => this.initReply(item)} >
<Tooltip title={ "回复" }> <Tooltip title={"回复"}>
<i className="iconfont icon-huifu1 mr5"></i> <i className="iconfont icon-huifu1 mr5"></i>
</Tooltip> </Tooltip>
</a>} </a>}
@ -406,23 +317,16 @@ class Comments extends Component {
{/* <span className="ml5 mr5 color-grey-8">|</span>*/} {/* <span className="ml5 mr5 color-grey-8">|</span>*/}
<span className="reply_praise_count_952"> <span className="reply_praise_count_952">
<Tooltip title={ item.user_praise ? "取消点赞" : "点赞" }> <Tooltip title={item.user_praise ? "取消点赞" : "点赞"}>
<a href={`javascript:void(0)`} className={`fr mr5 ${item.user_praise ? 'color-orange03' : 'color-grey-8'}`} onClick={()=>commentPraise(item.id)}> <a href={`javascript:void(0)`} className={`fr mr5 ${item.user_praise ? 'color-orange03' : 'color-grey-8'}`} onClick={() => commentPraise(item.id)}>
<i className={ item.user_praise ? "iconfont icon-dianzan mr3" : "iconfont icon-dianzan-xian mr3" }></i> <i className={item.user_praise ? "iconfont icon-dianzan mr3" : "iconfont icon-dianzan-xian mr3"}></i>
<span className="fr font-14" style={{ marginTop: '1px'}}>{item.praise_count?item.praise_count:''}</span> <span className="fr font-14" style={{ marginTop: '1px' }}>{item.praise_count ? item.praise_count : ''}</span>
</a> </a>
</Tooltip> </Tooltip>
</span> </span>
</p> </p>
{/* __useKindEditor暂时没用到了TODO 可以去掉 */} {/* __useKindEditor暂时没用到了TODO 可以去掉 */}
{ window.__useKindEditor ? <CommentItemKEEditor showReplyEditorFlag={showReplyEditorFlag}
currentReplyComment={currentReplyComment}
item={item}
user={user}
>
</CommentItemKEEditor>
:
<CommentItemMDEditor showReplyEditorFlag={showReplyEditorFlag} <CommentItemMDEditor showReplyEditorFlag={showReplyEditorFlag}
currentReplyComment={currentReplyComment} currentReplyComment={currentReplyComment}
item={item} item={item}
@ -430,8 +334,6 @@ class Comments extends Component {
buttonText={this.props.buttonText} buttonText={this.props.buttonText}
> >
</CommentItemMDEditor> </CommentItemMDEditor>
}
{/* <div id={`reply_message_${item.id}`} className="reply_to_message"></div> */}
</div> </div>
</div> </div>
@ -439,22 +341,13 @@ class Comments extends Component {
</div> </div>
) )
}) })
/*
/users/reply_to?reply_id=${item.id}&amp;type=Challenge&amp;user_activity_id=118
*/
/*
onclick="delete_confirm_box_2('<%= discuss_path(comment, :challenge_id => @game_challenge) %>', '确定要删除该条回复吗?')"
delete按钮
id=`delete_reply_<%=@game_challenge.id %>_<%=comment.id %>`
*/
return commentsElement; return commentsElement;
} }
onCommentBtnClick(comment, childComment, dialogType) { onCommentBtnClick(comment, childComment, dialogType) {
this.comment = comment; this.comment = comment;
this.childComment = childComment; this.childComment = childComment;
this.setState({dialogOpen: true, dialogType: dialogType}) this.setState({ dialogOpen: true, dialogType: dialogType })
} }
handleDialogClose() { handleDialogClose() {
this.setState({ this.setState({
@ -467,18 +360,18 @@ class Comments extends Component {
const { dialogType } = this.state; const { dialogType } = this.state;
if (dialogType === 'delete') { if (dialogType === 'delete') {
deleteComment(this.comment, this.childComment ? this.childComment.id : '') deleteComment(this.comment, this.childComment ? this.childComment.id : '')
} else if (dialogType === 'hidden' || dialogType === 'hiddenCancel' ) { } else if (dialogType === 'hidden' || dialogType === 'hiddenCancel') {
hiddenComment(this.comment, this.childComment ? this.childComment.id : '') hiddenComment(this.comment, this.childComment ? this.childComment.id : '')
} }
this.setState({dialogOpen: false}) this.setState({ dialogOpen: false })
} }
showGoldRewardDialog(comment, childComment) { showGoldRewardDialog(comment, childComment) {
if (comment.admin === true) { if (comment.admin === true) {
this.comment = comment; this.comment = comment;
this.childComment = childComment; this.childComment = childComment;
this.setState({goldRewardDialogOpen: true}) this.setState({ goldRewardDialogOpen: true })
} }
} }
handleGoldRewardDialogClose() { handleGoldRewardDialogClose() {
@ -490,11 +383,11 @@ class Comments extends Component {
console.log('onGoldRewardDialogOkBtnClick') console.log('onGoldRewardDialogOkBtnClick')
const { goldRewardInput } = this.state; const { goldRewardInput } = this.state;
// || goldRewardInput.indexOf('-') !== -1 // || goldRewardInput.indexOf('-') !== -1
if (!goldRewardInput || goldRewardInput === '0' ) { if (!goldRewardInput || goldRewardInput === '0') {
this.setState({ goldRewardInputError: true}) this.setState({ goldRewardInputError: true })
return; return;
} else { } else {
this.setState({goldRewardDialogOpen: false}) this.setState({ goldRewardDialogOpen: false })
this.props.rewardCode(this.comment, this.childComment, goldRewardInput) this.props.rewardCode(this.comment, this.childComment, goldRewardInput)
} }
} }
@ -510,13 +403,11 @@ class Comments extends Component {
const { deleteComment, onPaginationChange, comment_count_without_reply, currentPage, comments, usingAntdModal } = this.props; const { deleteComment, onPaginationChange, comment_count_without_reply, currentPage, comments, usingAntdModal } = this.props;
const { dialogOpen, goldRewardDialogOpen, dialogType, goldRewardInputError } = this.state; const { dialogOpen, goldRewardDialogOpen, dialogType, goldRewardInputError } = this.state;
const goldRewardInputErrorObj = goldRewardInputError ? {'error': 'error'} : {}
return ( return (
<div className="fit -scroll" style={{ 'overflow-x': 'hidden'}}> <div className="fit -scroll" style={{ 'overflow-x': 'hidden' }}>
{ usingAntdModal ? <Modals {usingAntdModal ? <Modals
modalsType={dialogOpen} modalsType={dialogOpen}
modalsTopval={ modalsTopval={
dialogType === 'delete' ? '确定要删除该条回复吗?' dialogType === 'delete' ? '确定要删除该条回复吗?'
@ -528,62 +419,29 @@ class Comments extends Component {
modalSave={this.onDialogOkBtnClick} modalSave={this.onDialogOkBtnClick}
> >
</Modals> : </Modals> :
<Dialog <Modal
open={dialogOpen} title="提示"
disableEscapeKeyDown={true} visible={dialogOpen}
onClose={this.handleDialogClose} onOk={this.onDialogOkBtnClick.bind(this)}
onCancel={this.handleDialogClose}
> >
<DialogTitle id="alert-dialog-title">{"提示"}</DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-description" style={{textAlign: 'center'}}>
{ {
dialogType === 'delete' ? '确定要删除该条回复吗?' dialogType === 'delete' ? '确定要删除该条回复吗?'
: dialogType === 'hidden' ? '确定要隐藏该条回复吗?' : dialogType === 'hidden' ? '确定要隐藏该条回复吗?'
: dialogType === 'hiddenCancel' ? '确定要取消隐藏该条回复吗?' : '' : dialogType === 'hiddenCancel' ? '确定要取消隐藏该条回复吗?' : ''
} }
</DialogContentText> </Modal>
</DialogContent>
<DialogActions>
<Button onClick={this.handleDialogClose} color="primary">
取消
</Button>
<Button variant="raised"
onClick={() => this.onDialogOkBtnClick() } color="primary" autoFocus>
确定
</Button>
</DialogActions>
</Dialog>
} }
<Dialog <Modal
open={goldRewardDialogOpen} title="奖励设置"
disableEscapeKeyDown={true} visible={goldRewardDialogOpen}
onClose={this.handleGoldRewardDialogClose} onOk={this.onGoldRewardDialogOkBtnClick.bind(this)}
onCancel={this.handleGoldRewardDialogClose}
> >
<DialogTitle id="alert-dialog-title">{"奖励设置"}</DialogTitle>
<DialogContent>
<InputNumber placeholder="请输入奖励的金币数量" id="goldReward" type="number" value={this.state.goldRewardInput} <InputNumber placeholder="请输入奖励的金币数量" id="goldReward" type="number" value={this.state.goldRewardInput}
onChange={(e) => this.onGoldRewardInputChange(e)} width={228} style={{ width: '228px'}} /> onChange={(e) => this.onGoldRewardInputChange(e)} width={228} style={{ width: '228px' }} />
</Modal>
{/* <FormControl { ...goldRewardInputErrorObj } aria-describedby="name-error-text">
<InputLabel htmlFor="goldReward">请输入奖励的金币数量</InputLabel>
<Input id="goldReward" type="number" value={this.state.goldRewardInput} onChange={(e) => this.onGoldRewardInputChange(e)} />
{ goldRewardInputError ? <FormHelperText id="name-error-text">奖励金币不能为空或负数</FormHelperText> : ''}
</FormControl> */}
{/*<DialogContentText id="alert-dialog-description" style={{textAlign: 'center'}}> </DialogContentText>*/}
</DialogContent>
<DialogActions>
<Button onClick={this.handleGoldRewardDialogClose} color="primary">
取消
</Button>
<Button variant="raised"
onClick={() => this.onGoldRewardDialogOkBtnClick() } color="primary" autoFocus>
确定
</Button>
</DialogActions>
</Dialog>
<div className="-layout-v -fit"> <div className="-layout-v -fit">
@ -592,12 +450,12 @@ class Comments extends Component {
{this.renderComments()} {this.renderComments()}
</div> </div>
{ (comment_count_without_reply > 10 ) ? {(comment_count_without_reply > 10) ?
<div className="paginationSection"> <div className="paginationSection">
<Pagination showQuickJumper onChange={onPaginationChange} current={currentPage} total={comment_count_without_reply} /> <Pagination showQuickJumper onChange={onPaginationChange} current={currentPage} total={comment_count_without_reply} />
</div> </div>
: '' } : ''}
{ (comment_count_without_reply == 0) ? <div> {(comment_count_without_reply == 0) ? <div>
<div className="edu-tab-con-box clearfix edu-txt-center"> <div className="edu-tab-con-box clearfix edu-txt-center">
<img className="edu-nodata-img mb20" <img className="edu-nodata-img mb20"
@ -605,7 +463,7 @@ class Comments extends Component {
<p className="edu-nodata-p mb20">暂时还没有相关数据哦</p> <p className="edu-nodata-p mb20">暂时还没有相关数据哦</p>
</div> </div>
</div> </div>
: '' } : ''}
</div> </div>
</div> </div>

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

Loading…
Cancel
Save