diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 15e795bdb..fa4648852 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -330,7 +330,7 @@ class ApplicationController < ActionController::Base
end
if !User.current.logged? && Rails.env.development?
- User.current = User.find 1
+ User.current = User.find 3117
end
diff --git a/app/controllers/challenges_controller.rb b/app/controllers/challenges_controller.rb
index 103c33aab..c69f5bbfb 100644
--- a/app/controllers/challenges_controller.rb
+++ b/app/controllers/challenges_controller.rb
@@ -155,8 +155,14 @@ class ChallengesController < ApplicationController
def index
uid_logger("identifier: #{params}")
-
- @challenges = @shixun.challenges.fields_for_list
+ base_columns = "challenges.id, challenges.subject, challenges.st, challenges.score, challenges.position,
+ challenges.shixun_id, games.identifier, games.status"
+ join_sql = "LEFT JOIN games ON games.challenge_id = challenges.id AND games.user_id = #{current_user.id}"
+ # 下面2个参数是为了解决列表获取通关人数与正在游玩人数的问题
+ @pass_games_map = @shixun.challenges.joins(:games).where(games: {status:2}).group(:challenge_id).reorder(nil).count
+ @play_games_map = @shixun.challenges.joins(:games).where(games: {status:[0,1]}).group(:challenge_id).reorder(nil).count
+
+ @challenges = @shixun.challenges.joins(join_sql).select(base_columns)
@editable = @shixun.status == 0 # before_action:有判断权限,如果没发布,则肯定是管理人员
@user = current_user
diff --git a/app/controllers/course_modules_controller.rb b/app/controllers/course_modules_controller.rb
index 0bef519fd..bea248b52 100644
--- a/app/controllers/course_modules_controller.rb
+++ b/app/controllers/course_modules_controller.rb
@@ -2,9 +2,13 @@ class CourseModulesController < ApplicationController
before_action :require_login, :check_auth
before_action :set_module, except: [:unhidden_modules]
before_action :find_course, only: [:unhidden_modules]
- before_action :teacher_or_admin_allowed, except: [:add_second_category]
+ before_action :teacher_or_admin_allowed, except: [:show, :add_second_category]
before_action :teacher_allowed, only: [:add_second_category]
+ def show
+
+ end
+
# 模块置顶
def sticky_module
# position为1则不做处理,否则该模块的position置为1,position小于当前模块的position加1
diff --git a/app/controllers/course_videos_controller.rb b/app/controllers/course_videos_controller.rb
new file mode 100644
index 000000000..090c7e29a
--- /dev/null
+++ b/app/controllers/course_videos_controller.rb
@@ -0,0 +1,35 @@
+class CourseVideosController < ApplicationController
+ before_action :require_login
+ before_action :validate_params
+ before_action :find_course, only: [:create]
+ before_action :find_video, only: [:update]
+ before_action :teacher_allowed
+
+ def create
+ title = params[:name].strip
+ link = params[:link].strip
+ course_second_category_id = params[:category_id] || 0
+ @course.course_videos.create!(title: title, link: link, is_link: 1, user_id: current_user.id, course_second_category_id: course_second_category_id)
+ render_ok
+ end
+
+ def update
+ title = params[:name].strip
+ link = params[:link].strip
+ @video.update!(title: title, link: link)
+ render_ok
+ end
+
+ private
+
+ def validate_params
+ tip_exception("视频名称不能为空") if params[:name].blank?
+ tip_exception("链接地址不能为空") if params[:link].blank?
+ end
+
+ def find_video
+ @video = CourseVideo.find params[:id]
+ @course = @video.course
+ end
+
+end
\ No newline at end of file
diff --git a/app/controllers/courses_controller.rb b/app/controllers/courses_controller.rb
index 3283595e5..2e94e435d 100644
--- a/app/controllers/courses_controller.rb
+++ b/app/controllers/courses_controller.rb
@@ -30,14 +30,14 @@ class CoursesController < ApplicationController
:informs, :update_informs, :online_learning, :update_task_position, :tasks_list,
:join_excellent_course, :export_couser_info, :export_member_act_score, :new_informs,
:delete_informs, :change_member_role, :course_groups, :join_course_group, :statistics,
- :work_score, :act_score, :calculate_all_shixun_scores]
+ :work_score, :act_score, :calculate_all_shixun_scores, :move_to_category]
before_action :user_course_identity, except: [:join_excellent_course, :index, :create, :new, :apply_to_join_course,
:search_course_list, :get_historical_course_students, :mine, :search_slim, :board_list]
before_action :teacher_allowed, only: [:update, :destroy, :settings, :search_teacher_candidate,
:transfer_to_course_group, :delete_from_course, :export_member_scores_excel,
:search_users, :add_students_by_search, :get_historical_courses, :add_teacher_popup,
:add_teacher, :export_couser_info, :export_member_act_score,
- :update_informs, :new_informs, :delete_informs, :switch_to_student]
+ :update_informs, :new_informs, :delete_informs, :switch_to_student, :move_to_category]
before_action :admin_allowed, only: [:set_invite_code_halt, :set_public_or_private, :change_course_admin,
:set_course_group, :create_group_by_importing_file,
:update_task_position, :tasks_list]
@@ -102,22 +102,50 @@ class CoursesController < ApplicationController
end
def course_videos
- logger.info("########[#{@course}")
- videos = @course.videos
+ videos = @course.course_videos
+ @video_module = @course.course_modules.find_by(module_type: "video")
+ if params[:category_id].present? && params[:category_id].to_i != 0
+ @category = @video_module&.course_second_categories.find_by(id: params[:category_id])
+ tip_exception("子目录id有误") if !@category.present?
+ videos = videos.where(course_second_category_id: params[:category_id].to_i)
+ end
+
videos = custom_sort(videos, params[:sort_by], params[:sort_direction])
@count = videos.count
- @videos = paginate videos.includes(user: :user_extension)
+ @videos = paginate videos.includes(video: [user: :user_extension], user: :user_extension)
end
def delete_course_video
- video = Video.find_by(id: params[:video_id])
- tip_exception(404, "找不到资源") if video.blank?
- tip_exception(403, "...") unless (video.user_id == current_user.id || current_user.admin_or_business?)
- video.destroy!
- AliyunVod::Service.delete_video([video.uuid]) rescue nil
+ if params[:is_link]
+ video = @course.course_videos.find_by!(id: params[:video_id])
+ tip_exception(403, "...") unless (video.user_id == current_user.id || current_user.admin_or_business?)
+ video.destroy!
+ else
+ video = Video.find_by(id: params[:video_id])
+ tip_exception(404, "找不到资源") if video.blank?
+ tip_exception(403, "...") unless (video.user_id == current_user.id || current_user.admin_or_business?)
+ video.destroy!
+ AliyunVod::Service.delete_video([video.uuid]) rescue nil
+ end
+
render_ok
end
+ # 视频移动到目录
+ def move_to_category
+ tip_exception("请选择要移动的目录") if params[:new_category_id].blank?
+
+ category = @course.course_second_categories.find_by(id: params[:new_category_id])
+ if params[:new_category_id].to_i == 0 || category.present?
+ videos = @course.course_videos.where(video_id: params[:video_ids]).or(@course.course_videos.where(id: params[:video_ids]))
+
+ videos.update_all(course_second_category_id: params[:new_category_id])
+ normal_status(0, "操作成功")
+ else
+ normal_status(-1, "目录不存在")
+ end
+ end
+
def visits_plus_one
new_visits = @course.visits + 1
@course.update_visits(new_visits)
@@ -1259,7 +1287,7 @@ class CoursesController < ApplicationController
@is_teacher = @user_course_identity < Course::ASSISTANT_PROFESSOR
@course_modules = @course.course_modules.where(hidden: 0)
@hidden_modules = @course.course_modules.where(hidden: 1)
- @second_category_type = ["shixun_homework", "graduation", "attachment", "board", "course_group"]
+ @second_category_type = ["shixun_homework", "graduation", "attachment", "board", "course_group", "video"]
end
def board_list
diff --git a/app/controllers/files_controller.rb b/app/controllers/files_controller.rb
index 25e0de44a..427545716 100644
--- a/app/controllers/files_controller.rb
+++ b/app/controllers/files_controller.rb
@@ -2,13 +2,13 @@ class FilesController < ApplicationController
include MessagesHelper
before_action :require_login, :check_auth, except: %i[index]
- before_action :find_course, except: %i[public_with_course_and_project mine_with_course_and_project]
+ before_action :find_course, except: %i[public_with_course_and_project mine_with_course_and_project update_visits]
before_action :find_ids, only: %i[bulk_delete bulk_send bulk_move bulk_public bulk_publish]
before_action :file_validate_sort_type, only: :index
before_action :validate_send_message_to_course_params, only: :bulk_send
before_action :set_pagination, only: %i[index public_with_course_and_project mine_with_course_and_project]
- before_action :validate_upload_params, only: %i[upload import]
- before_action :find_file, only: %i[show setting update]
+ before_action :validate_upload_params, only: %i[import]
+ before_action :find_file, only: %i[show setting update update_visits]
before_action :publish_params, only: %i[upload import update]
SORT_TYPE = %w[created_on downloads quotes]
@@ -163,6 +163,7 @@ class FilesController < ApplicationController
# 上传资源
def upload
+ find_course_second_category_id
attachment_ids = params[:attachment_ids]
course_second_category_id = params[:course_second_category_id] || 0 # 0: 为主目录, 其他为次目录id
# is_unified_setting = params.has_key?(:is_unified_setting) ? params[:is_unified_setting] : true
@@ -170,25 +171,48 @@ class FilesController < ApplicationController
# course_group_publish_times = params[:course_group_publish_times] || []
begin
- attachment_ids.each do |attchment_id|
- attachment = Attachment.find_by_id attchment_id
- unless attachment.nil?
- attachment.container = @course
- attachment.course_second_category_id = course_second_category_id
- attachment.description = params[:description]
- attachment.is_public = params[:is_public] && @course.is_public == 1 ? 1 : 0
- attachment.is_publish = @atta_is_publish
- attachment.delay_publish = @atta_delay_publish
- attachment.publish_time = @atta_publish_time
- attachment.unified_setting = @unified_setting
- if @unified_setting == 0
- attachment_group_setting attachment, params[:group_settings]
+ if attachment_ids.present?
+ attachment_ids.each do |attchment_id|
+ attachment = Attachment.find_by_id attchment_id
+ unless attachment.nil?
+ attachment.container = @course
+ attachment.course_second_category_id = course_second_category_id
+ attachment.description = params[:description]
+ attachment.is_public = params[:is_public] && @course.is_public == 1 ? 1 : 0
+ attachment.is_publish = @atta_is_publish
+ attachment.delay_publish = @atta_delay_publish
+ attachment.publish_time = @atta_publish_time
+ attachment.unified_setting = @unified_setting
+ if @unified_setting == 0
+ attachment_group_setting attachment, params[:group_settings]
+ end
+ # attachment.set_publish_time(publish_time) if is_unified_setting
+ # attachment.set_course_group_publish_time(@course, course_group_publish_times) if @course.course_groups.size > 0 && !is_unified_setting && publish_time.blank?
+ attachment.save!
end
- # attachment.set_publish_time(publish_time) if is_unified_setting
- # attachment.set_course_group_publish_time(@course, course_group_publish_times) if @course.course_groups.size > 0 && !is_unified_setting && publish_time.blank?
- attachment.save!
end
+ else
+ tip_exception("资源名称不能为空") if params[:name].blank?
+ tip_exception("资源名称不能超过60个字符") if params[:name].strip.length > 60
+ tip_exception("链接地址不能为空") if params[:link].blank?
+ attachment = Attachment.new
+ attachment.container = @course
+ attachment.course_second_category_id = course_second_category_id
+ attachment.author_id = current_user.id
+ attachment.filename = params[:name].strip
+ attachment.link = params[:link].strip
+ attachment.description = params[:description]
+ attachment.is_public = params[:is_public] && @course.is_public == 1 ? 1 : 0
+ attachment.is_publish = @atta_is_publish
+ attachment.delay_publish = @atta_delay_publish
+ attachment.publish_time = @atta_publish_time
+ attachment.unified_setting = @unified_setting
+ if @unified_setting == 0
+ attachment_group_setting attachment, params[:group_settings]
+ end
+ attachment.save!
end
+
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
@@ -265,6 +289,11 @@ class FilesController < ApplicationController
@old_attachment.save!
@new_attachment.delete
end
+ if params[:name].present? && params[:link].present?
+ tip_exception("资源名称不能超过60个字符") if params[:name].strip.length > 60
+ @old_attachment.filename = params[:name].strip
+ @old_attachment.link = params[:link].strip
+ end
@old_attachment.is_public = is_public == true && @course.is_public == 1 ? 1 : 0
@old_attachment.is_publish = @atta_is_publish
@old_attachment.delay_publish = @atta_delay_publish
@@ -326,6 +355,11 @@ class FilesController < ApplicationController
end
end
+ def update_visits
+ @file.increment!(:downloads)
+ render_ok
+ end
+
private
def find_file
@file = Attachment.find params[:id]
diff --git a/app/controllers/homework_commons_controller.rb b/app/controllers/homework_commons_controller.rb
index 415207707..4515e5482 100644
--- a/app/controllers/homework_commons_controller.rb
+++ b/app/controllers/homework_commons_controller.rb
@@ -6,7 +6,7 @@ class HomeworkCommonsController < ApplicationController
before_action :require_login, :check_auth, except: [:index, :choose_category]
before_action :find_course, only: [:index, :create, :new, :shixuns, :subjects, :create_shixun_homework, :publish_homework,
- :end_homework, :set_public, :choose_category, :move_to_category, :choose_category,
+ :end_homework, :set_public, :move_to_category, :choose_category,
:create_subject_homework, :multi_destroy, :add_to_homework_bank]
before_action :find_homework, only: [:edit, :show, :update, :group_list, :homework_code_repeat, :code_review_results,
:code_review_detail, :show_comment, :settings, :works_list, :update_settings,
diff --git a/app/controllers/shixuns_controller.rb b/app/controllers/shixuns_controller.rb
index 8f74f0474..54eb19474 100644
--- a/app/controllers/shixuns_controller.rb
+++ b/app/controllers/shixuns_controller.rb
@@ -182,7 +182,7 @@ class ShixunsController < ApplicationController
select m.user_id, u.login, u.lastname, m.updated_at,
(select sum(cost_time) from games g where g.myshixun_id = m.id) as time,
(select sum(final_score) from games g where g.myshixun_id = m.id) as score
- from (users u left join myshixuns m on m.user_id = u.id) where m.shixun_id = #{@shixun.id} and m.status = 1
+ from (users u left join myshixuns m on m.user_id = u.id) where u.is_test =0 and m.shixun_id = #{@shixun.id} and m.status = 1
order by score desc, time asc limit 10
"
@myshixuns = Myshixun.find_by_sql(sql)
diff --git a/app/controllers/users/videos_controller.rb b/app/controllers/users/videos_controller.rb
index 0ae240dd7..32f81f6ed 100644
--- a/app/controllers/users/videos_controller.rb
+++ b/app/controllers/users/videos_controller.rb
@@ -1,6 +1,6 @@
class Users::VideosController < Users::BaseController
before_action :private_user_resources!, :check_account
- before_action :require_teacher!
+ before_action :require_teacher!, except: [:destroy]
before_action :require_auth_teacher!, except: [:index, :review]
helper_method :current_video
@@ -53,6 +53,19 @@ class Users::VideosController < Users::BaseController
render_error(ex.message)
end
+ def destroy
+ video = Video.find_by(id: params[:id])
+ return render_forbidden unless video.user_id == current_user.id || current_user.admin_or_business?
+ return render_not_found if video.blank?
+ return render_error('该状态下不能删除视频') unless video.published?
+
+ video.destroy!
+
+ AliyunVod::Service.delete_video([video.uuid]) rescue nil
+
+ render_ok
+ end
+
private
def current_video
@@ -72,6 +85,6 @@ class Users::VideosController < Users::BaseController
end
def batch_publish_params
- params.permit(videos: %i[video_id title course_id])
+ params.permit(videos: %i[video_id title course_id category_id])
end
end
\ No newline at end of file
diff --git a/app/controllers/weapps/attendances_controller.rb b/app/controllers/weapps/attendances_controller.rb
index 3f0eec248..7da852393 100644
--- a/app/controllers/weapps/attendances_controller.rb
+++ b/app/controllers/weapps/attendances_controller.rb
@@ -42,6 +42,7 @@ class Weapps::AttendancesController < ApplicationController
end
def student_attendances
+ tip_exception(403) if @user_course_identity > Course::STUDENT
# tip_exception("学生身份的签到列表") if @user_course_identity != Course::STUDENT
member = @course.students.find_by(user_id: current_user.id)
if member.present?
@@ -58,12 +59,18 @@ class Weapps::AttendancesController < ApplicationController
@history_attendances = @course.course_attendances.where(id: history_attendance_ids.uniq).
where("attendance_date < '#{current_date}' or (attendance_date = '#{current_date}' and end_time < '#{current_end_time}')").order("id desc")
- @current_attendance = @course.course_attendances.where(id: all_attendance_ids.uniq).
+ @current_attendances = @course.course_attendances.where(id: all_attendance_ids.uniq).
where("attendance_date = '#{current_date}' and start_time <= '#{current_end_time}' and end_time > '#{current_end_time}'")
@history_count = @history_attendances.size
+ # 当前签到如果存在快捷签到,则直接签到(不在这里处理)
+ # quick_attendances = @current_attendances.where(mode: "QUICK")
+ # if quick_attendances.present?
+ # student_direct_attendance quick_attendances, member
+ # end
+
student_attendance_ids = @history_attendances.pluck(:id)
- student_attendance_ids += @current_attendance.present? ? @current_attendance.pluck(:id) : []
+ student_attendance_ids += @current_attendances.present? ? @current_attendances.pluck(:id) : []
if student_attendance_ids.uniq.blank?
@normal_count = 0
@@ -141,4 +148,16 @@ class Weapps::AttendancesController < ApplicationController
def edit_auth
tip_exception(403, "") unless @user_course_identity < Course::PROFESSOR || @attendance.user_id == current_user.id
end
+
+ def student_direct_attendance quick_attendances, member
+ quick_attendances.each do |attendance|
+ current_attendance = attendance.course_member_attendances.find_by(user_id: member.user_id)
+ if current_attendance.present?
+ current_attendance.update!(attendance_status: "NORMAL", attendance_mode: "QUICK")
+ else
+ attendance.course_member_attendances.create!(course_member_id: member.id, user_id: member.user_id, course_id: attendance.course_id,
+ course_group_id: member.course_group_id, attendance_status: "NORMAL", attendance_mode: "QUICK")
+ end
+ end
+ end
end
\ No newline at end of file
diff --git a/app/controllers/weapps/course_member_attendances_controller.rb b/app/controllers/weapps/course_member_attendances_controller.rb
index 7e315fc85..5e92d5928 100644
--- a/app/controllers/weapps/course_member_attendances_controller.rb
+++ b/app/controllers/weapps/course_member_attendances_controller.rb
@@ -28,19 +28,24 @@ class Weapps::CourseMemberAttendancesController < ApplicationController
end
def create
- tip_exception("签到码不能为空") if params[:code].blank?
- tip_exception("attendance_mode参数不对") unless ["NUMBER", "QRCODE"].include?(params[:attendance_mode])
+ tip_exception("签到码不能为空") if params[:attendance_mode] != "QUICK" && params[:code].blank?
+ tip_exception("attendance_mode参数不对") unless ["NUMBER", "QRCODE", "QUICK"].include?(params[:attendance_mode])
- attendance = CourseAttendance.find_by(attendance_code: params[:code])
- tip_exception("签到码输入有误") if attendance.blank? || attendance.course.blank?
+ if params[:attendance_mode] == "QUICK"
+ attendance = CourseAttendance.find_by(id: params[:attendance_id])
+ else
+ attendance = CourseAttendance.find_by(attendance_code: params[:code])
+ end
+ tip_exception("该签到不存在") if attendance.blank? || attendance.course.blank?
member = attendance.course.students.find_by(user_id: current_user.id)
- tip_exception("签到码输入有误") if member.blank?
+ tip_exception("该签到不存在") if member.blank?
tip_exception("不在签到时间内") unless attendance.current_attendance?
- tip_exception("只支持数字签到") if attendance.mode != "ALL" && attendance.mode == "NUMBER" && params[:attendance_mode] == "QRCODE"
- tip_exception("只支持二维码签到") if attendance.mode != "ALL" && attendance.mode == "QRCODE" && params[:attendance_mode] == "NUMBER"
+ tip_exception("只支持数字签到") if attendance.mode != "ALL" && attendance.mode == "NUMBER" && params[:attendance_mode] != "NUMBER"
+ tip_exception("只支持二维码签到") if attendance.mode != "ALL" && attendance.mode == "QRCODE" && params[:attendance_mode] != "QRCODE"
+ tip_exception("只支持快捷签到") if attendance.mode == "QUICK" && params[:attendance_mode] != "QUICK"
current_attendance = attendance.course_member_attendances.find_by(user_id: current_user.id)
if current_attendance.present?
diff --git a/app/helpers/courses_helper.rb b/app/helpers/courses_helper.rb
index 0e79f11de..ed76a4b0c 100644
--- a/app/helpers/courses_helper.rb
+++ b/app/helpers/courses_helper.rb
@@ -87,16 +87,18 @@ module CoursesHelper
# 子目录对应的url
def category_url category, course
case category.category_type
- when "shixun_homework"
- "/courses/#{course.id}/shixun_homework/#{category.id}"
- when "graduation"
- if category.name == "毕设选题"
- "/courses/#{course.id}/graduation_topics/#{category.course_module_id}"
- else
- "/courses/#{course.id}/graduation_tasks/#{category.course_module_id}"
- end
- when "attachment"
- "/courses/#{course.id}/file/#{category.id}"
+ when "shixun_homework"
+ "/courses/#{course.id}/shixun_homework/#{category.id}"
+ when "graduation"
+ if category.name == "毕设选题"
+ "/courses/#{course.id}/graduation_topics/#{category.course_module_id}"
+ else
+ "/courses/#{course.id}/graduation_tasks/#{category.course_module_id}"
+ end
+ when "attachment"
+ "/courses/#{course.id}/file/#{category.id}"
+ when "video"
+ "/courses/#{course.id}/course_video/#{category.id}"
end
end
@@ -113,6 +115,8 @@ module CoursesHelper
end
when "attachment"
get_attachment_count(course, category.id)
+ when "video"
+ get_video_count(course, category.id)
end
end
@@ -237,6 +241,11 @@ module CoursesHelper
category_id.to_i == 0 ? course.attachments.size : course.attachments.where(course_second_category_id: category_id).size
end
+ # 获取课堂的视频数
+ def get_video_count(course, category_id)
+ category_id.to_i == 0 ? course.course_videos.size : course.course_videos.where(course_second_category_id: category_id).size
+ end
+
# 获取课堂的作业数
def get_homework_commons_count(course, type, category_id)
category_id == 0 ? HomeworkCommon.where(course_id: course.id, homework_type: type).size :
diff --git a/app/models/challenge.rb b/app/models/challenge.rb
index 70fac990b..5646da363 100644
--- a/app/models/challenge.rb
+++ b/app/models/challenge.rb
@@ -69,12 +69,13 @@ class Challenge < ApplicationRecord
end
# 开启挑战
- def open_game user_id, shixun
- game = self.games.where(user_id: user_id).first
- if game.present?
- shixun.task_pass || game.status != 3 ? "/tasks/#{game.identifier}" : ""
+ def open_game shixun
+ # 这里的identifier,status是关联了games取了games的identifier,status
+ identifier = self.identifier
+ if identifier.present?
+ shixun.task_pass || self.status != 3 ? "/tasks/#{identifier}" : ""
else
- "/api/shixuns/#{shixun.identifier}/shixun_exec"
+ self.position == 1 ? "/api/shixuns/#{shixun.identifier}/shixun_exec" : ""
end
end
@@ -92,16 +93,16 @@ class Challenge < ApplicationRecord
# end
## 用户关卡状态 0: 不能开启实训; 1:直接开启; 2表示已完成
- def user_tpi_status user_id
+ def user_tpi_status shixun
# todo: 以前没加索引导致相同关卡,同一用户有多个games
# 允许跳关则直接开启
- game = games.where(user_id: user_id).take
- if game.blank?
- position == 1 ? 1 : 0
+ identifier = self.identifier
+ if identifier.blank?
+ self.position == 1 ? 1 : 0
else
- if game.status == 3
+ if status == 3
shixun.task_pass ? 1 : 0
- elsif game.status == 2
+ elsif status == 2
2
else
1
diff --git a/app/models/course_attendance.rb b/app/models/course_attendance.rb
index 1bd96fc29..3b7e07fdf 100644
--- a/app/models/course_attendance.rb
+++ b/app/models/course_attendance.rb
@@ -1,7 +1,7 @@
class CourseAttendance < ApplicationRecord
# status: 0: 未开启,1:已开启,2:已截止
- # mode: 0 两种签到,1 二维码签到,2 数字签到
- enum mode: { ALL: 0, QRCODE: 1, NUMBER: 2 }
+ # mode: 0 两种签到,1 二维码签到,2 数字签到,3 快捷签到
+ enum mode: { ALL: 0, QRCODE: 1, NUMBER: 2, QUICK: 3 }
belongs_to :course
belongs_to :user
diff --git a/app/models/course_member_attendance.rb b/app/models/course_member_attendance.rb
index 152bb48b6..b854acfe7 100644
--- a/app/models/course_member_attendance.rb
+++ b/app/models/course_member_attendance.rb
@@ -1,6 +1,6 @@
class CourseMemberAttendance < ApplicationRecord
# attendance_mode :0 初始数据,1 二维码签到,2 数字签到,3 老师签到
- enum attendance_mode: { DEFAULT: 0, QRCODE: 1, NUMBER: 2, TEACHER: 3}
+ enum attendance_mode: { DEFAULT: 0, QRCODE: 1, NUMBER: 2, QUICK: 3, TEACHER: 4}
# attendance_status :1 正常签到,2 请假,0 旷课
enum attendance_status: { NORMAL: 1, LEAVE: 2, ABSENCE: 0 }
belongs_to :course_member
diff --git a/app/models/course_video.rb b/app/models/course_video.rb
index e61a439dc..246be34fd 100644
--- a/app/models/course_video.rb
+++ b/app/models/course_video.rb
@@ -1,4 +1,7 @@
class CourseVideo < ApplicationRecord
belongs_to :course
- belongs_to :video
+ belongs_to :video, optional: true
+ belongs_to :user, optional: true
+
+ validates :title, length: { maximum: 60, too_long: "不能超过60个字符" }
end
diff --git a/app/services/videos/batch_publish_service.rb b/app/services/videos/batch_publish_service.rb
index 0523097a2..9ddcae146 100644
--- a/app/services/videos/batch_publish_service.rb
+++ b/app/services/videos/batch_publish_service.rb
@@ -41,7 +41,8 @@ class Videos::BatchPublishService < ApplicationService
# 如果是课堂上传则创建课堂记录
Rails.logger.info("#####param: #{ param[:course_id]}")
if param[:course_id].present?
- video.course_videos.create!(course_id: param[:course_id])
+ course_second_category_id = params[:category_id] || 0
+ video.course_videos.create!(course_id: param[:course_id], course_second_category_id: course_second_category_id)
end
end
end
diff --git a/app/views/attachments/_attachment.json.jbuilder b/app/views/attachments/_attachment.json.jbuilder
index b30869d57..c87f8372e 100644
--- a/app/views/attachments/_attachment.json.jbuilder
+++ b/app/views/attachments/_attachment.json.jbuilder
@@ -1,5 +1,6 @@
json.id attachment.id
json.title attachment.title
+json.link attachment.link
json.is_public attachment.publiced?
# json.is_lock attachment.locked?(@is_member)
json.is_lock !attachment.publiced?
@@ -15,4 +16,4 @@ json.created_on attachment.created_on
json.content_type attachment.content_type
json.is_pdf attachment.is_pdf?
json.url attachment.is_pdf? ? download_url(attachment,disposition:"inline") : download_url(attachment)
-json.play_url attachment_show_users_path(file_name: local_path(attachment))
+json.play_url attachment.link.present? ? nil : attachment_show_users_path(file_name: local_path(attachment))
diff --git a/app/views/challenges/index.json.jbuilder b/app/views/challenges/index.json.jbuilder
index c53ab9c58..d4f2a7f59 100644
--- a/app/views/challenges/index.json.jbuilder
+++ b/app/views/challenges/index.json.jbuilder
@@ -16,10 +16,12 @@ if @challenges.present?
json.st challenge.st
json.name challenge.subject
json.score challenge.score
- json.passed_count challenge.user_passed_count
- json.playing_count challenge.playing_count
+ json.passed_count @pass_games_map.fetch(challenge.id, 0)
+ #json.passed_count challenge.user_passed_count
+ json.playing_count @play_games_map.fetch(challenge.id, 0)
+ #json.playing_count challenge.playing_count
json.name_url shixun_challenge_path(challenge, shixun_identifier: @shixun.identifier)
- #json.open_game challenge.open_game(@user.id, @shixun)
+ json.open_game challenge.open_game(@shixun)
if @editable
json.edit_url edit_shixun_challenge_path(challenge, shixun_identifier: @shixun.identifier)
json.delete_url shixun_challenge_path(challenge, shixun_identifier: @shixun.identifier)
@@ -27,6 +29,6 @@ if @challenges.present?
json.down_url index_down_shixun_challenge_path(challenge, :shixun_identifier => @shixun.identifier) if @shixun.challenges_count != challenge.position
end
#json.passed challenge.has_passed?(@user.id)
- json.status challenge.user_tpi_status @user.id
+ json.status challenge.user_tpi_status(@shixun)
end
end
diff --git a/app/views/course_modules/show.json.jbuilder b/app/views/course_modules/show.json.jbuilder
new file mode 100644
index 000000000..9d70797b8
--- /dev/null
+++ b/app/views/course_modules/show.json.jbuilder
@@ -0,0 +1,8 @@
+json.course_module do
+ json.id @course_module.id
+ json.module_name @course_module.module_name
+ json.module_type @course_module.module_type
+ json.course_second_categories do
+ json.array! @course_module.course_second_categories, :id, :name
+ end
+end
\ No newline at end of file
diff --git a/app/views/courses/course_videos.json.jbuilder b/app/views/courses/course_videos.json.jbuilder
index 807ff92bb..bee5e89cb 100644
--- a/app/views/courses/course_videos.json.jbuilder
+++ b/app/views/courses/course_videos.json.jbuilder
@@ -1,3 +1,22 @@
json.count @count
-json.videos @videos, partial: 'users/videos/video', as: :video
-json.course_id @course.id
\ No newline at end of file
+
+json.videos @videos do |video|
+ if video.is_link
+ json.(video, :id, :title, :link, :user_id)
+
+ user = video.user
+ json.user_name user&.real_name
+ json.user_img url_to_avatar(user)
+ json.user_login user&.login
+ else
+ json.partial! 'users/videos/video', locals: { video: video.video }
+ end
+end
+
+json.course_id @course.id
+if @category.present?
+ json.category_id @category.id
+ json.category_name @category.name
+end
+json.course_module_id @video_module&.id
+json.has_category @video_module.course_second_categories.size > 0
\ No newline at end of file
diff --git a/app/views/weapps/attendances/_student_attendance.json.jbuilder b/app/views/weapps/attendances/_student_attendance.json.jbuilder
index 9461c4976..6fd5e9d70 100644
--- a/app/views/weapps/attendances/_student_attendance.json.jbuilder
+++ b/app/views/weapps/attendances/_student_attendance.json.jbuilder
@@ -1,4 +1,4 @@
-json.(attendance, :name, :mode)
+json.(attendance, :id, :name, :mode)
json.attendance_date attendance.attendance_date.strftime("%Y/%m/%d")
json.start_time attendance.start_time.strftime("%H:%M")
json.end_time attendance.end_time.strftime("%H:%M")
diff --git a/app/views/weapps/attendances/index.json.jbuilder b/app/views/weapps/attendances/index.json.jbuilder
index 34317d08d..da8be3c8d 100644
--- a/app/views/weapps/attendances/index.json.jbuilder
+++ b/app/views/weapps/attendances/index.json.jbuilder
@@ -1,15 +1,17 @@
json.current_attendance @current_attendance do |attendance|
- json.(attendance, :id, :normal_count, :all_count)
- json.attendance_date attendance.attendance_date.strftime("%Y/%m/%d")
+ json.(attendance, :id, :name, :normal_count, :all_count)
+ json.attendance_date attendance.attendance_date.strftime("%Y-%m-%d")
json.start_time attendance.start_time.strftime("%H:%M")
json.end_time attendance.end_time.strftime("%H:%M")
end
all_normal_rate = []
all_absence_rate = []
+all_leave_rate = []
json.history_attendances @history_attendances.each_with_index.to_a do |attendance, index|
normal_count = history_member_count(@all_member_attendances, "NORMAL", attendance.id)
absence_count = history_member_count(@all_member_attendances, "ABSENCE", attendance.id)
+ leave_count = history_member_count(@all_member_attendances, "LEAVE", attendance.id)
all_count = @all_member_attendances.select{|member_attendance| member_attendance.course_attendance_id == attendance.id}.size
json.index index + 1
@@ -17,8 +19,11 @@ json.history_attendances @history_attendances.each_with_index.to_a do |attendanc
all_normal_rate << cal_rate(normal_count, all_count)
json.absence_rate cal_rate(absence_count, all_count)
all_absence_rate << cal_rate(absence_count, all_count)
+ json.leave_rate cal_rate(leave_count, all_count)
+ all_leave_rate << cal_rate(leave_count, all_count)
end
json.all_history_count @all_history_count
json.avg_normal_rate @all_history_count == 0 ? 0 : all_normal_rate.sum / @all_history_count
json.avg_absence_rate @all_history_count == 0 ? 0 : all_absence_rate.sum / @all_history_count
+json.avg_leave_rate @all_history_count == 0 ? 0 : all_leave_rate.sum / @all_history_count
diff --git a/app/views/weapps/attendances/show.json.jbuilder b/app/views/weapps/attendances/show.json.jbuilder
index 1eb73347e..b3f13ca60 100644
--- a/app/views/weapps/attendances/show.json.jbuilder
+++ b/app/views/weapps/attendances/show.json.jbuilder
@@ -5,7 +5,8 @@ json.all_count @all_count
json.code @attendance.attendance_code
json.mode @attendance.mode
json.edit_auth @user_course_identity < Course::PROFESSOR || @attendance.user_id == User.current.id
-json.attendance_date @attendance.attendance_date.strftime("%Y/%m/%d")
+json.name @attendance.name
+json.attendance_date @attendance.attendance_date.strftime("%Y-%m-%d")
json.start_time @attendance.start_time.strftime("%H:%M")
json.end_time @attendance.end_time.strftime("%H:%M")
diff --git a/app/views/weapps/attendances/student_attendances.json.jbuilder b/app/views/weapps/attendances/student_attendances.json.jbuilder
index c2b9fca12..f0ee4c8f8 100644
--- a/app/views/weapps/attendances/student_attendances.json.jbuilder
+++ b/app/views/weapps/attendances/student_attendances.json.jbuilder
@@ -1,4 +1,4 @@
-json.current_attendance @current_attendance do |attendance|
+json.current_attendance @current_attendances do |attendance|
json.partial! 'student_attendance', locals: {attendance: attendance}
end
diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml
index f9671eec1..4c5c808ac 100644
--- a/config/locales/zh-CN.yml
+++ b/config/locales/zh-CN.yml
@@ -183,6 +183,9 @@ zh-CN:
attendance_date: '签到日期'
start_time: '开始时间'
end_time: '结束时间'
+ course_video:
+ title: '视频名称'
+ link: '链接地址'
diff --git a/config/routes.rb b/config/routes.rb
index 2bbdd6c3c..9c6b73ddc 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -195,7 +195,7 @@ Rails.application.routes.draw do
resource :unread_message_info, only: [:show]
# 视频
- resources :videos, only: [:index, :update] do
+ resources :videos, only: [:index, :update, :destroy] do
collection do
get :review
post :batch_publish
@@ -464,6 +464,7 @@ Rails.application.routes.draw do
end
member do
get :histories
+ post :update_visits
end
end
@@ -524,6 +525,7 @@ Rails.application.routes.draw do
get 'statistics'
get 'course_videos'
delete 'delete_course_video'
+ post :move_to_category
post :inform_up
post :inform_down
get :calculate_all_shixun_scores
@@ -537,6 +539,8 @@ Rails.application.routes.draw do
get 'search_slim'
end
+ resources :course_videos, only:[:create, :update], shallow: true
+
resources :course_stages, shallow: true do
member do
post :up_position
diff --git a/db/migrate/20200309015735_add_course_second_category_id_to_course_videos.rb b/db/migrate/20200309015735_add_course_second_category_id_to_course_videos.rb
new file mode 100644
index 000000000..cdc2dcd20
--- /dev/null
+++ b/db/migrate/20200309015735_add_course_second_category_id_to_course_videos.rb
@@ -0,0 +1,5 @@
+class AddCourseSecondCategoryIdToCourseVideos < ActiveRecord::Migration[5.2]
+ def change
+ add_column :course_videos, :course_second_category_id, :integer, index: true, default: 0
+ end
+end
diff --git a/db/migrate/20200309071103_migrate_member_attendance_mode.rb b/db/migrate/20200309071103_migrate_member_attendance_mode.rb
new file mode 100644
index 000000000..41f81444a
--- /dev/null
+++ b/db/migrate/20200309071103_migrate_member_attendance_mode.rb
@@ -0,0 +1,5 @@
+class MigrateMemberAttendanceMode < ActiveRecord::Migration[5.2]
+ def change
+ CourseMemberAttendance.where(attendance_mode: 3).update_all(attendance_mode: 4)
+ end
+end
diff --git a/db/migrate/20200309101753_add_link_to_course_videos.rb b/db/migrate/20200309101753_add_link_to_course_videos.rb
new file mode 100644
index 000000000..d5580d92e
--- /dev/null
+++ b/db/migrate/20200309101753_add_link_to_course_videos.rb
@@ -0,0 +1,8 @@
+class AddLinkToCourseVideos < ActiveRecord::Migration[5.2]
+ def change
+ add_column :course_videos, :is_link, :boolean, default: 0
+ add_column :course_videos, :title, :string
+ add_column :course_videos, :link, :string
+ add_column :course_videos, :user_id, :integer, index: true
+ end
+end
diff --git a/db/migrate/20200309123121_add_link_to_attachments.rb b/db/migrate/20200309123121_add_link_to_attachments.rb
new file mode 100644
index 000000000..23510be26
--- /dev/null
+++ b/db/migrate/20200309123121_add_link_to_attachments.rb
@@ -0,0 +1,5 @@
+class AddLinkToAttachments < ActiveRecord::Migration[5.2]
+ def change
+ add_column :attachments, :link, :string
+ end
+end
diff --git a/public/images/educoder/xcx/fenxiangs.png b/public/images/educoder/xcx/fenxiangs.png
new file mode 100755
index 000000000..f5b170bed
Binary files /dev/null and b/public/images/educoder/xcx/fenxiangs.png differ
diff --git a/public/images/educoder/xcx/xuesqiandao.png b/public/images/educoder/xcx/xuesqiandao.png
new file mode 100755
index 000000000..7124615fd
Binary files /dev/null and b/public/images/educoder/xcx/xuesqiandao.png differ
diff --git a/public/react/public/css/demo_index.html b/public/react/public/css/demo_index.html
index 281ac40d0..7b0854698 100644
--- a/public/react/public/css/demo_index.html
+++ b/public/react/public/css/demo_index.html
@@ -30,6 +30,54 @@
+ -
+
+
移动
+ 
+
+
+ -
+
+
下移2
+ 
+
+
+ -
+
+
上移2
+ 
+
+
+ -
+
+
下移
+ 
+
+
+ -
+
+
上移
+ 
+
+
+ -
+
+
编辑
+ 
+
+
+ -
+
+
删除
+ 
+
+
+ -
+
+
选择
+ 
+
+
-
编辑
@@ -2012,6 +2060,78 @@
+ -
+
+
+ 移动
+
+ .icon-yidong
+
+
+
+ -
+
+
+ 下移2
+
+ .icon-xiayi1
+
+
+
+ -
+
+
+ 上移2
+
+ .icon-shangyi1
+
+
+
+ -
+
+
+ 下移
+
+ .icon-xiayi
+
+
+
+ -
+
+
+ 上移
+
+ .icon-shangyi
+
+
+
+ -
+
+
+ 编辑
+
+ .icon-bianji5
+
+
+
+ -
+
+
+ 删除
+
+ .icon-shanchu3
+
+
+
+ -
+
+
+ 选择
+
+ .icon-xuanze
+
+
+
-
@@ -4939,6 +5059,70 @@
+ -
+
+
移动
+ #icon-yidong
+
+
+ -
+
+
下移2
+ #icon-xiayi1
+
+
+ -
+
+
上移2
+ #icon-shangyi1
+
+
+ -
+
+
下移
+ #icon-xiayi
+
+
+ -
+
+
上移
+ #icon-shangyi
+
+
+ -
+
+
编辑
+ #icon-bianji5
+
+
+ -
+
+
删除
+ #icon-shanchu3
+
+
+ -
+
+
选择
+ #icon-xuanze
+
+
-
- );
+ );
};
const handleShowUploadImage = (url) => {
- // console.log('==============>>>>>>>>>>>>',url);
setUrl(url);
}
// 评论内容
@@ -105,7 +99,8 @@ function CommentItem ({
value={_ctx}
showUploadImage={handleShowUploadImage}
/>
- )};
+ )
+ };
// 加载更多
const handleOnLoadMore = (len) => {
@@ -154,7 +149,7 @@ function CommentItem ({
- handleOnLoadMore(len)}>
展开其余{lastTxt}条评论
-
+
@@ -169,7 +164,7 @@ function CommentItem ({
const handleClickLick = (id) => {
likeComment && likeComment(id);
}
-
+
// 点击评论icon
const handleClickMessage = () => {
setShowQuill(true);
@@ -198,33 +193,33 @@ function CommentItem ({
{commentInfo(id, author, time, can_delete)}
{commentCtx(content)}
-
+
{commentAppend(children)}
handleShowOrHide(id, !hidden ? 1 : 0)}
/>
deleteComment(id)}
/>
{/* 回复 */}
-
{/* 点赞 */}
-
- {/* 显示上传的图片信息 */}
-
-
+
+
-

+
@@ -254,4 +248,4 @@ function CommentItem ({
);
}
-export default CNotificationHOC() (CommentItem);
+export default CNotificationHOC()(CommentItem);
diff --git a/public/react/src/common/components/comment/index.js b/public/react/src/common/components/comment/index.js
index 5efa8c5ad..1ff164062 100644
--- a/public/react/src/common/components/comment/index.js
+++ b/public/react/src/common/components/comment/index.js
@@ -7,39 +7,28 @@
* @LastEditTime : 2019-12-24 18:03:21
*/
import React from 'react';
-// import CommentForm from './CommentForm';
import CommentList from './CommentList';
-function Comment (props) {
+function Comment(props) {
- const {
+ const {
commentLists,
- // addComment,
- // cancelComment,
isAdmin,
addChildComment,
likeComment,
showOrHideComment,
submitDeleteComment
} = props;
-
- // const handleCancelComment = () => {
- // cancelComment && cancelComment();
- // };
+
return (
-
- {/* */}
-
-
+
+
);
}
diff --git a/public/react/src/common/quillForEditor/FillBlot.js b/public/react/src/common/quillForEditor/FillBlot.js
index 5e5e2aa77..07b8b4a47 100644
--- a/public/react/src/common/quillForEditor/FillBlot.js
+++ b/public/react/src/common/quillForEditor/FillBlot.js
@@ -8,19 +8,15 @@
*/
import Quill from 'quill';
let Inline = Quill.import('blots/inline');
-// const BlockEmbed = Quill.import('blots/embed');
class FillBlot extends Inline {
- static create (value) {
+ static create(value) {
const node = super.cerate(value);
- // node.classList.add('icon icon-bianji2');
- // node.setAttribute('data-fill', 'fill');
- console.log('编辑器值===》》》》》', value);
node.setAttribute('data_index', value.data_index);
- node.nodeValue = value.text;
+ node.nodeValue = value.text;
return node;
}
-
- static value (node) {
+
+ static value(node) {
return {
// dataSet: node.getAttribute('data-fill'),
data_index: node.getAttribute('data_index')
diff --git a/public/react/src/common/quillForEditor/ImageBlot.js b/public/react/src/common/quillForEditor/ImageBlot.js
index 5ff84b249..0a9bec733 100644
--- a/public/react/src/common/quillForEditor/ImageBlot.js
+++ b/public/react/src/common/quillForEditor/ImageBlot.js
@@ -17,7 +17,6 @@ export default class ImageBlot extends BlockEmbed {
const node = super.create();
node.setAttribute('alt', value.alt);
node.setAttribute('src', value.url);
- // console.log('~~~~~~~~~~~', node, value);
node.addEventListener('click', function () {
value.onclick(value.url);
}, false);
@@ -33,25 +32,14 @@ export default class ImageBlot extends BlockEmbed {
}
// 宽度和高度都不存在时,
if (!value.width && !value.height) {
- // node.setAttribute('display', 'block');
node.setAttribute('width', '100%');
}
- // node.setAttribute('style', { cursor: 'pointer' });
-
- // if (node.onclick) {
- // console.log('image 有图片点击事件======》》》》》》');
- // // node.setAttribute('onclick', node.onCLick);
- // }
- // 给图片添加点击事件
- // node.onclick = () => {
- // value.onClick && value.onClick(value.url);
- // }
return node;
}
// 获取节点值
- static value (node) {
+ static value(node) {
return {
alt: node.getAttribute('alt'),
@@ -61,7 +49,6 @@ export default class ImageBlot extends BlockEmbed {
height: node.height,
display: node.getAttribute('display'),
id: node.id,
- // style: node.style
};
}
}
diff --git a/public/react/src/common/quillForEditor/index.js b/public/react/src/common/quillForEditor/index.js
index ba37059ba..46b02b94e 100644
--- a/public/react/src/common/quillForEditor/index.js
+++ b/public/react/src/common/quillForEditor/index.js
@@ -20,16 +20,17 @@ import { fetchUploadImage } from '../../services/ojService.js';
import { getImageUrl } from 'educoder'
import ImageBlot from './ImageBlot';
import FillBlot from './FillBlot';
+import LinkBlot from './link-blot'
var Size = Quill.import('attributors/style/size');
-// const Color = Quill.import('attributes/style/color');
Size.whitelist = ['14px', '16px', '18px', '20px', false];
-var fonts = ['Microsoft-YaHei','SimSun', 'SimHei','KaiTi','FangSong'];
+var fonts = ['Microsoft-YaHei', 'SimSun', 'SimHei', 'KaiTi', 'FangSong'];
var Font = Quill.import('formats/font');
Font.whitelist = fonts; //将字体加入到白名单
window.Quill = Quill;
window.katex = katex;
Quill.register(ImageBlot);
Quill.register(Size);
+Quill.register(LinkBlot);
Quill.register(Font, true);
// Quill.register({'modules/toolbar': Toolbar});
Quill.register({
@@ -38,7 +39,7 @@ Quill.register({
// Quill.register(Color);
-function QuillForEditor ({
+function QuillForEditor({
placeholder,
readOnly,
autoFocus = false,
@@ -51,17 +52,16 @@ function QuillForEditor ({
onContentChange,
addFill, // 点击填空成功的回调
deleteFill // 删除填空,返回删除的下标
- // getQuillContent
}) {
// toolbar 默认值
const defaultConfig = [
'bold', 'italic', 'underline',
- {size: ['14px', '16px', '18px', '20px']},
- {align: []}, {list: 'ordered'}, {list: 'bullet'}, // 列表
- {script: 'sub'}, {script: 'super'},
+ { size: ['14px', '16px', '18px', '20px'] },
+ { align: [] }, { list: 'ordered' }, { list: 'bullet' }, // 列表
+ { script: 'sub' }, { script: 'super' },
{ 'color': [] }, { 'background': [] },
- { 'font': []},
- {header: [1,2,3,4,5,false]},
+ { 'font': [] },
+ { header: [1, 2, 3, 4, 5, false] },
'blockquote', 'code-block',
'link', 'image', 'video',
'formula',
@@ -77,7 +77,6 @@ function QuillForEditor ({
// 文本内容变化时
const handleOnChange = content => {
- // getQuillContent && getQuillContent(quill);
onContentChange && onContentChange(content, quill);
};
@@ -86,9 +85,7 @@ function QuillForEditor ({
const bindings = {
tab: {
key: 9,
- handler: function () {
- console.log('调用了tab=====>>>>');
- }
+ handler: function () { }
},
backspace: {
key: 'Backspace',
@@ -104,11 +101,10 @@ function QuillForEditor ({
* index: 删除元素的位置
* length: 删除元素的个数
*/
- const {index, length} = range;
+ const { index, length } = range;
const _start = length === 0 ? index - 1 : index;
const _length = length || 1;
let delCtx = this.quill.getText(_start, _length); // 删除的元素
- // aa
const reg = /▁/g;
const delArrs = delCtx.match(reg);
if (delArrs) {
@@ -216,7 +212,7 @@ function QuillForEditor ({
const ops = value.ops || [];
ops.forEach((item, i) => {
if (item.insert['image']) {
- item.insert['image'] = Object.assign({}, item.insert['image'], {style: { cursor: 'pointer' }, onclick: (url) => showUploadImage(url)});
+ item.insert['image'] = Object.assign({}, item.insert['image'], { style: { cursor: 'pointer' }, onclick: (url) => showUploadImage(url) });
}
});
}
@@ -225,7 +221,7 @@ function QuillForEditor ({
if (!deepEqual(previous, current)) {
setSelection(quill.getSelection())
if (typeof value === 'string' && value) {
- // debugger
+ // debugger
quill.clipboard.dangerouslyPasteHTML(value, 'api');
if (autoFocus) {
quill.focus();
@@ -273,9 +269,9 @@ function QuillForEditor ({
// 返回结果
return (
-
+
);
}
diff --git a/public/react/src/common/quillForEditor/link-blot.js b/public/react/src/common/quillForEditor/link-blot.js
new file mode 100644
index 000000000..8f508dd34
--- /dev/null
+++ b/public/react/src/common/quillForEditor/link-blot.js
@@ -0,0 +1,21 @@
+import Quill from "quill";
+const Inline = Quill.import('blots/inline');
+
+export default class LinkBlot extends Inline {
+ static create(value) {
+ let node = super.create()
+ let rs = value
+ if (rs.indexOf('http://') < 0) {
+ rs = 'http://' + rs
+ }
+ node.setAttribute('href', rs)
+ node.setAttribute('target', '_blank')
+ return node;
+ }
+
+ static formats(node) {
+ return node.getAttribute('href');
+ }
+}
+LinkBlot.blotName = 'link'
+LinkBlot.tagName = 'a'
\ No newline at end of file
diff --git a/public/react/src/common/reactQuill/ImageBlot.js b/public/react/src/common/reactQuill/ImageBlot.js
deleted file mode 100644
index 091bd2c1f..000000000
--- a/public/react/src/common/reactQuill/ImageBlot.js
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * @Description: 重写图片
- * @Author: tangjiang
- * @Github:
- * @Date: 2019-12-16 15:50:45
- * @LastEditors: tangjiang
- * @LastEditTime: 2019-12-17 16:44:48
- */
-import Quill from "quill";
-
-const BlockEmbed = Quill.import('blots/block/embed');
-
-export default class ImageBlot extends BlockEmbed {
-
- static create(value) {
-
- const node = super.create();
-
- node.setAttribute('alt', value.alt);
- node.setAttribute('src', value.url);
-
- if (value.width) {
- node.setAttribute('width', value.width);
- }
- if (value.height) {
- node.setAttribute('height', value.height);
- }
- // 宽度和高度都不存在时,
- if (!value.width && !value.height) {
- node.setAttribute('display', 'block');
- node.setAttribute('width', '100%');
- }
- // 给图片添加点击事件
- node.onclick = () => {
- value.onClick && value.onClick(value.url);
- }
- return node;
- }
-
- static value (node) {
-
- return {
- alt: node.getAttribute('alt'),
- url: node.getAttribute('src'),
- onclick: node.onclick,
- // width: node.width,
- // height: node.height,
- display: node.getAttribute('display')
- };
- }
-}
-
-ImageBlot.blotName = 'image';
-ImageBlot.tagName = 'img';
\ No newline at end of file
diff --git a/public/react/src/common/reactQuill/ReactQuill.js b/public/react/src/common/reactQuill/ReactQuill.js
deleted file mode 100644
index 1b4209409..000000000
--- a/public/react/src/common/reactQuill/ReactQuill.js
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * @Description:
- * @Author: tangjiang
- * @Github:
- * @Date: 2019-12-09 09:09:42
- * @LastEditors: tangjiang
- * @LastEditTime: 2019-12-18 08:46:20
- */
-import 'quill/dist/quill.core.css'; // 核心样式
-import 'quill/dist/quill.snow.css'; // 有工具栏
-import 'quill/dist/quill.bubble.css'; // 无工具栏
-import 'katex/dist/katex.min.css'; // katex 表达式样式
-import React, { useState, useReducer, useEffect } from 'react';
-import useQuill from './useQuill';
-
-function ReactQuill ({
- disallowColors, // 不可见时颜色
- placeholder, // 提示信息
- uploadImage, // 图片上传
- onChange, // 内容变化时
- options, // 配置信息
- value, // 显示的内容
- style,
- showUploadImage // 显示上传图片
-}) {
-
- const [element, setElement] = useState(); // quill 渲染节点
-
- useQuill({
- disallowColors,
- placeholder,
- uploadImage,
- onChange,
- options,
- value,
- showUploadImage,
- element
- });
-
- return (
-
- );
-}
-
-export default ReactQuill;
diff --git a/public/react/src/common/reactQuill/deepEqual.js b/public/react/src/common/reactQuill/deepEqual.js
deleted file mode 100644
index 6f2b276bf..000000000
--- a/public/react/src/common/reactQuill/deepEqual.js
+++ /dev/null
@@ -1,47 +0,0 @@
-function deepEqual (prev, current) {
- if (prev === current) { // 基本类型比较,值,类型都相同 或者同为 null or undefined
- return true;
- }
-
- if ((!prev && current)
- || (prev && !current)
- || (!prev && !current)
- ) {
- return false;
- }
-
- if (Array.isArray(prev)) {
- if (!Array.isArray(current)) return false;
- if (prev.length !== current.length) return false;
-
- for (let i = 0; i < prev.length; i++) {
- if (!deepEqual(current[i], prev[i])) {
- return false;
- }
- }
- return true;
- }
-
- if (typeof current === 'object') {
- if (typeof prev !== 'object') return false;
- const prevKeys = Object.keys(prev);
- const curKeys = Object.keys(current);
-
- if (prevKeys.length !== curKeys.length) return false;
-
- prevKeys.sort();
- curKeys.sort();
-
- for (let i = 0; i < prevKeys.length; i++) {
- if (prevKeys[i] !== curKeys[i]) return false;
- const key = prevKeys[i];
- if (!deepEqual(prev[key], current[key])) return false;
- }
-
- return true;
- }
-
- return false;
-}
-
-export default deepEqual;
diff --git a/public/react/src/common/reactQuill/flatten.js b/public/react/src/common/reactQuill/flatten.js
deleted file mode 100644
index 237cb543f..000000000
--- a/public/react/src/common/reactQuill/flatten.js
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * @Description: 将多维数组转变成一维数组
- * @Author: tangjiang
- * @Github:
- * @Date: 2019-12-09 09:35:01
- * @LastEditors: tangjiang
- * @LastEditTime: 2019-12-16 11:36:22
- */
-function flatten (array) {
- return flatten.rec(array, []);
-}
-
-flatten.rec = function flatten (array, result) {
-
- for (let item of array) {
- if (Array.isArray(item)) {
- flatten(item, result);
- } else {
- result.push(item);
- }
- }
-
- return result;
-}
-
-export default flatten;
diff --git a/public/react/src/common/reactQuill/index.js b/public/react/src/common/reactQuill/index.js
deleted file mode 100644
index 56a1a8d1f..000000000
--- a/public/react/src/common/reactQuill/index.js
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * @Description: 入口文件
- * @Author: tangjiang
- * @Github:
- * @Date: 2019-12-17 10:41:48
- * @LastEditors: tangjiang
- * @LastEditTime: 2019-12-17 20:34:40
- */
-import React, { useState, useCallback, useEffect } from 'react';
-import ReactQuill from './lib';
-
-function Wrapper (props) {
- // 默认工具栏配置项
- const toolbarConfig = [
- ['bold', 'italic', 'underline'],
- [{align: []}, {list: 'ordered'}, {list: 'bullet'}], // 列表
- [{script: 'sub'}, {script: 'super'}],
- [{header: [1,2,3,4,5,false]}],
- ['blockquote', 'code-block'],
- ['link', 'image', 'video'],
- ['formula'],
- ['clean']
- ];
-
- const [placeholder] = useState(props.placeholder || 'placeholder');
- const [disableBold] = useState(false);
- const [value, setValue] = useState(props.value || '');
- const [toolbar, setToolbar] = useState(toolbarConfig);
- const [theme, setTheme] = useState(props.theme || 'snow');
- const [readOnly] = useState(props.readOnly || false);
-
- const {
- onContentChagne, // 当编辑器内容变化时调用该函数
- showUploadImage, // 显示上传图片, 返回url,主要用于点击图片放大
- } = props;
-
- // 配置信息
- const options = {
- modules: {
- toolbar: toolbar,
- clipboard: {
- matchVisual: false
- }
- },
- readOnly: readOnly,
- theme: theme
- }
- // 配置信息
- useEffect (() => {
- if (props.options) {
- setToolbar(props.options);
- }
- setTheme(props.theme || 'snow');
- setValue(props.value);
- }, [props]);
-
- // 当内容变化时
- const handleOnChange = useCallback(
- contents => {
- if (disableBold) {
- setValue({
- ops: contents.ops.map(x => {
- x = {...x};
- if (x && x.attributes && x.attributes.bold) {
- x.attributes = { ...x.attributes };
- delete x.attributes.bold;
- if (!Object.keys(x.attributes).length) {
- delete x.attributes;
- }
- }
- return x;
- })
- });
- } else {
- setValue(contents);
- }
- onContentChagne && onContentChagne(contents);
- }, [disableBold]
- );
-
- // 图片上传
- const handleUploadImage = (files) => {
- console.log('选择的图片信息', files);
- }
-
- // 显示图片
- const handleShowUploadImage = (url) => {
- // console.log('上传的图片url:', url);
- showUploadImage && showUploadImage(url);
- }
-
- return (
-
- handleShowUploadImage(url)}
- />
-
- );
-}
-
-export default Wrapper;
-// ReactDOM.render(
, document.querySelector('#root'));
diff --git a/public/react/src/common/reactQuill/index.scss b/public/react/src/common/reactQuill/index.scss
deleted file mode 100644
index b6da52bf5..000000000
--- a/public/react/src/common/reactQuill/index.scss
+++ /dev/null
@@ -1,32 +0,0 @@
-#quill-toolbar{
- .quill-btn{
- vertical-align: middle;
- }
- .quill_image{
- display: inline-block;
- position: relative;
- vertical-align: middle;
- width: 28px;
- height: 24px;
- overflow: hidden;
- .image_input{
- position: absolute;
- left: 0;
- right: 0;
- top: 0;
- bottom: 0;
- opacity: 0;
- }
- .ql-image{
- position: relative;
- left: 0;
- top: 0;
- }
- }
-}
-
-.react_quill_area{
- .ql-toolbar:not(:last-child) {
- display: none;
- }
-}
\ No newline at end of file
diff --git a/public/react/src/common/reactQuill/lib.js b/public/react/src/common/reactQuill/lib.js
deleted file mode 100644
index 430a95bb7..000000000
--- a/public/react/src/common/reactQuill/lib.js
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * @Description: 导出 ReactQuill
- * @Author: tangjiang
- * @Github:
- * @Date: 2019-12-09 09:08:24
- * @LastEditors: tangjiang
- * @LastEditTime: 2019-12-16 11:37:13
- */
-import ReactQuill from './ReactQuill';
-import useQuill from './useQuill';
-
-export default ReactQuill;
-export { useQuill };
diff --git a/public/react/src/common/reactQuill/useDeepEqualMemo.js b/public/react/src/common/reactQuill/useDeepEqualMemo.js
deleted file mode 100644
index 948e21781..000000000
--- a/public/react/src/common/reactQuill/useDeepEqualMemo.js
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * @Description:
- * @Author: tangjiang
- * @Github:
- * @Date: 2019-12-12 19:48:55
- * @LastEditors: tangjiang
- * @LastEditTime: 2019-12-16 11:38:16
- */
-import { useState, useEffect } from 'react';
-import deepEqual from './deepEqual';
-
-function useDeepEqual (input) {
-
- const [value, setValue] = useState(input);
-
- useEffect(() => {
-
- if (!deepEqual(input, value)) {
- setValue(input)
- }
-
- }, [input, value]);
-
- return value;
-}
-
-export default useDeepEqual;
diff --git a/public/react/src/common/reactQuill/useMountQuill.js b/public/react/src/common/reactQuill/useMountQuill.js
deleted file mode 100644
index c2313c480..000000000
--- a/public/react/src/common/reactQuill/useMountQuill.js
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * @Description: 创建 reactQuill实例
- * @Author: tangjiang
- * @Github:
- * @Date: 2019-12-09 09:31:42
- * @LastEditors: tangjiang
- * @LastEditTime: 2019-12-17 20:42:05
- */
-import Quill from 'quill'; // 导入quill
-import { useState, useEffect, useMemo } from 'react';
-import flatten from './flatten.js';
-import useDeepEqualMemo from './useDeepEqualMemo';
-import Katex from 'katex';
-import ImageBlot from './ImageBlot';
-import { fetchUploadImage } from '../../services/ojService.js';
-import { getImageUrl } from 'educoder'
-window.katex = Katex;
-
-Quill.register(ImageBlot);
-
-function useMountQuill ({
- element,
- options: passedOptions,
- uploadImage,
- showUploadImage,
- imgAttrs = {} // 指定图片的宽高属性
-}) {
-
- // 是否引入 katex
- const [katexLoaded, setKatexLoaded] = useState(Boolean(window.katex))
- const [quill, setQuill] = useState(null);
-
- const options = useDeepEqualMemo(passedOptions);
- console.log('use mount quill: ', passedOptions);
-
- // 判断options中是否包含公式
- const requireKatex = useMemo(() => {
- return flatten(options.modules.toolbar).includes('formula');
- }, [options]);
-
- // 加载katex
- useEffect(() => {
- if (!requireKatex) return;
- if (katexLoaded) return;
-
- const interval = setInterval(() => {
- if (window.katex) {
- setKatexLoaded(true);
- clearInterval(interval);
- }
- });
-
- return () => { // 定义回调清除定时器
- clearInterval(interval);
- }
-
- }, [
- setKatexLoaded,
- katexLoaded,
- requireKatex
- ]);
-
- // 加载 quill
- useEffect(() => {
- if (!element) return;
- if (requireKatex && !katexLoaded) {
- element.innerHTML = `
-
- Loading Katex...
-
- `
- }
- // 清空内容
- element.innerHTML = '';
- console.log(element);
- // 创建 quill 节点
- const quillNode = document.createElement('div');
- element.appendChild(quillNode); // 将quill节点追回到 element 元素中
-
- const quill = new Quill(element, options);
- setQuill(quill);
- // 加载上传图片功能
- if (typeof uploadImage === 'function') {
- quill.getModule('toolbar').addHandler('image', (e) => {
- // 创建type类型输入框加载本地图片
- const input = document.createElement('input');
- input.setAttribute('type', 'file');
- input.setAttribute('accept', 'image/*');
- input.click();
-
- input.onchange = async (e) => {
- const file = input.files[0]; // 获取文件信息
- const formData = new FormData();
- formData.append('file', file);
-
- // const reader = new FileReader();
- // reader.readAsDataURL(file);
- // console.log('文件信息===>>', reader);
- // reader.onload = function (e) {
- // debugger;
- // console.log('文件信息===>>', e.target.result);
- // const image = new Image();
- // image.src = e.target.result;
-
- // image.onload = function () {
- // // file.width =
- // console.log(image.width, image.height);
- // }
- // }
-
- const range = quill.getSelection(true);
- let fileUrl = ''; // 保存上传成功后图片的url
- // 上传文件
- const result = await fetchUploadImage(formData);
- // 获取上传图片的url
- if (result.data && result.data.id) {
- fileUrl = getImageUrl(`api/attachments/${result.data.id}`);
- }
- // 根据id获取文件路径
- const { width, height } = imgAttrs;
- // console.log('上传图片的url:', fileUrl);
- if (fileUrl) {
- quill.insertEmbed(range.index, 'image', {
- url: fileUrl,
- alt: '',
- onClick: showUploadImage,
- width,
- height
- });
- }
- }
- });
- }
-
- return () => {
- element.innerHTML = '';
- }
- }, [
- element,
- options,
- requireKatex,
- katexLoaded,
- ]);
-
- return quill;
-}
-
-export default useMountQuill;
diff --git a/public/react/src/common/reactQuill/useQuill.js b/public/react/src/common/reactQuill/useQuill.js
deleted file mode 100644
index b959dbc52..000000000
--- a/public/react/src/common/reactQuill/useQuill.js
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * @Description:
- * @Author: tangjiang
- * @Github:
- * @Date: 2019-12-09 09:09:50
- * @LastEditors: tangjiang
- * @LastEditTime: 2019-12-17 15:46:50
- */
-import useQuillPlaceholder from './useQuillPlaceholder';
-import useQuillValueSync from './useQuillValueSync';
-import useQuillOnChange from './useQuillOnChange';
-import useMountQuill from './useMountQuill';
-import { useEffect } from 'react';
-
-function useQuill ({
- disallowColors,
- placeholder,
- uploadImage,
- onChange,
- options,
- value,
- element,
- showUploadImage
-}) {
-
- // 获取 quill 实例
- const quill = useMountQuill({
- element,
- options,
- uploadImage,
- showUploadImage
- });
-
- useEffect(() => {
- if (disallowColors && quill) {
- quill.clipboard.addMatcher(Node.ELEMENT_NODE, (node, delta) => {
- delta.ops = delta.ops.map(op => {
- if (op.attributes && op.attributes.color) {
- const { color, ...attributes } = op.attributes;
- return {
- ...op,
- attributes
- }
- }
- return op;
- });
- return delta;
- });
- }
- }, [
- disallowColors,
- quill
- ]);
-
- useQuillPlaceholder(quill, placeholder);
- useQuillValueSync(quill, value);
- useQuillOnChange(quill, onChange);
-}
-
-export default useQuill;
diff --git a/public/react/src/common/reactQuill/useQuillOnChange.js b/public/react/src/common/reactQuill/useQuillOnChange.js
deleted file mode 100644
index 45333a4e1..000000000
--- a/public/react/src/common/reactQuill/useQuillOnChange.js
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * @Description:
- * @Author: tangjiang
- * @Github:
- * @Date: 2019-12-12 19:49:11
- * @LastEditors: tangjiang
- * @LastEditTime: 2019-12-16 11:39:27
- */
-import { useEffect } from 'react';
-
-function useQuillOnChange (quill, onChange) {
-
- useEffect(() => {
-
- if (!quill) return;
- if (typeof onChange !== 'function') return;
-
- let handler;
-
- quill.on(
- 'text-change',
- (handler = () => {
- onChange(quill.getContents()); // getContents: 检索编辑器内容
- })
- );
-
- return () => {
- quill.off('text-change', handler);
- }
- }, [quill, onChange]);
-}
-
-export default useQuillOnChange;
diff --git a/public/react/src/common/reactQuill/useQuillPlaceholder.js b/public/react/src/common/reactQuill/useQuillPlaceholder.js
deleted file mode 100644
index ccc341568..000000000
--- a/public/react/src/common/reactQuill/useQuillPlaceholder.js
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * @Description:
- * @Author: tangjiang
- * @Github:
- * @Date: 2019-12-09 09:28:34
- * @LastEditors: tangjiang
- * @LastEditTime: 2019-12-16 11:39:48
- */
-import { useEffect } from 'react'
-
-function useQuillPlaceholder (
- quill,
- placeholder
-) {
-
- useEffect(() => {
- if (!quill || !quill.root) return;
- quill.root.dataset.placeholder = placeholder;
- }, [quill, placeholder]);
-}
-
-export default useQuillPlaceholder;
diff --git a/public/react/src/common/reactQuill/useQuillValueSync.js b/public/react/src/common/reactQuill/useQuillValueSync.js
deleted file mode 100644
index 696d88949..000000000
--- a/public/react/src/common/reactQuill/useQuillValueSync.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import { useEffect, useState } from 'react'
-import deepEqual from './deepEqual.js'
-
-function useQuillValueSync(quill, value) {
- const [selection, setSelection] = useState(null)
-
- useEffect(() => {
- if (!quill) return
-
- const previous = quill.getContents()
- const current = value
-
- if (!deepEqual(previous, current)) {
- setSelection(quill.getSelection())
- if (typeof value === 'string') {
- quill.clipboard.dangerouslyPasteHTML(value, 'api')
- } else {
- quill.setContents(value)
- }
- }
- }, [quill, value, setSelection])
-
- useEffect(() => {
- if (quill && selection) {
- quill.setSelection(selection)
- setSelection(null)
- }
- }, [quill, selection, setSelection])
-}
-
-export default useQuillValueSync
diff --git a/public/react/src/modules/courses/Index.js b/public/react/src/modules/courses/Index.js
index dc935ab1c..8a21e76da 100644
--- a/public/react/src/modules/courses/Index.js
+++ b/public/react/src/modules/courses/Index.js
@@ -10,7 +10,7 @@ import { CNotificationHOC } from './common/CNotificationHOC'
import {ImageLayerOfCommentHOC} from '../page/layers/ImageLayerOfCommentHOC'
import "./css/Courses.css"
//引入对应跳转的组件
-
+//里面有资源
const ListPageIndex = Loadable({
loader: () => import('./ListPageIndex'),
loading:Loading,
@@ -508,12 +508,16 @@ class CoursesIndex extends Component{
}
>
{/*视频列表*/}
-
+
()
+ }
+ >
()
}
- >
+ >
{/* 资源列表页 */}
{/*视频列表*/}
-
+
()
+ }
+ >
()
diff --git a/public/react/src/modules/courses/Resource/Fileslistitem.js b/public/react/src/modules/courses/Resource/Fileslistitem.js
index 53f607b2e..cb2198486 100644
--- a/public/react/src/modules/courses/Resource/Fileslistitem.js
+++ b/public/react/src/modules/courses/Resource/Fileslistitem.js
@@ -1,6 +1,6 @@
-import React,{ Component } from "react";
-import { WordsBtn } from 'educoder';
-import {Tooltip,message} from 'antd';
+import React, {Component} from "react";
+import {WordsBtn} from 'educoder';
+import {Tooltip, message} from 'antd';
import {Link} from 'react-router-dom';
import {getImageUrl} from 'educoder';
import axios from 'axios'
@@ -10,25 +10,40 @@ import CoursesListType from '../coursesPublic/CoursesListType';
import Showoldfiles from "../coursesPublic/Showoldfiles";
import Modals from '../../modals/Modals';
-class Fileslistitem extends Component{
- constructor(props){
+class Fileslistitem extends Component {
+ constructor(props) {
super(props);
- this.state = {
-
- }
+ this.state = {}
}
- settingList=()=>{
- let {discussMessage}=this.props
+ settingList = (bools) => {
+ let {discussMessage} = this.props
this.setState({
- discussMessageid:discussMessage.id
+ discussMessageid: discussMessage.id
})
- this.props.Settingtypes(discussMessage.id)
- }
+ if (bools === true) {
+ this.props.Settingtypes(discussMessage.id)
+ } else {
+ this.props.Settingtypess(discussMessage.id,discussMessage.title,discussMessage.link)
+ }
- showfiles=(list)=>{
- if(this.props.checkIfLogin()===false){
+ }
+ //外链
+ showfiless = (url,id) => {
+ window.open(url)
+ let urls=`/files/${id}/update_visits.json`;
+ axios.post(urls,{
+ }).then((result)=>{
+ if(result.data.status===0){
+ this.props.Updateresourcepage()
+ }else{
+ this.props.showNotification(result.data.message);
+ }
+ })
+ }
+ showfiles = (list) => {
+ if (this.props.checkIfLogin() === false) {
this.props.showLoginDialog()
return
}
@@ -43,21 +58,21 @@ class Fileslistitem extends Component{
// return
// }
- if(list.is_history_file===false){
+ if (list.is_history_file === false) {
// this.props.DownloadFileA(list.title,list.url)
//window.location.href=list.url;
window.open(list.url, '_blank');
- }else{
- let {discussMessage,coursesId}=this.props
- let file_id=discussMessage.id
- let url="/files/"+file_id+"/histories.json"
- axios.get(url,{
- params:{
- course_id:coursesId
+ } else {
+ let {discussMessage, coursesId} = this.props
+ let file_id = discussMessage.id
+ let url = "/files/" + file_id + "/histories.json"
+ axios.get(url, {
+ params: {
+ course_id: coursesId
},
- }).then((result)=>{
+ }).then((result) => {
- if(result.data.attachment_histories.length===0){
+ if (result.data.attachment_histories.length === 0) {
// if(result.data.is_pdf===true){
// this.props.ShowOnlinePdf(result.data.url)
// //预览pdf
@@ -66,64 +81,66 @@ class Fileslistitem extends Component{
// }
// this.props.DownloadFileA(result.data.title,result.data.url)
window.open(list.url, '_blank');
- }else{
+ } else {
this.setState({
- Showoldfiles:true,
- allfiles:result.data
+ Showoldfiles: true,
+ allfiles: result.data
})
}
- }).catch((error)=>{
+ }).catch((error) => {
console.log(error)
})
}
}
- closaoldfilesprops=()=>{
+ closaoldfilesprops = () => {
this.setState({
- Showoldfiles:false,
+ Showoldfiles: false,
})
}
onDelete = (id) => {
this.setState({
- Modalstype:true,
- Modalstopval:"是否确认删除?",
- ModalCancel:this.cancelmodel,
- ModalSave:()=>this.savedelete(id),
+ Modalstype: true,
+ Modalstopval: "是否确认删除?",
+ ModalCancel: this.cancelmodel,
+ ModalSave: () => this.savedelete(id),
})
}
- cancelmodel=()=>{
+ cancelmodel = () => {
this.setState({
- Modalstype:false,
- Loadtype:false,
- Modalstopval:"",
- ModalCancel:"",
- ModalSave:"",
- checkBoxValues:[],
+ Modalstype: false,
+ Loadtype: false,
+ Modalstopval: "",
+ ModalCancel: "",
+ ModalSave: "",
+ checkBoxValues: [],
})
}
- savedelete=(id)=>{
+ savedelete = (id) => {
this.setState({
- Modalstype:false,
+ Modalstype: false,
})
const cid = this.props.match.params.coursesId
const url = `/files/bulk_delete.json`;
- axios.delete(url, { data: {
- course_id:cid,
+ axios.delete(url, {
+ data: {
+ course_id: cid,
ids: [id],
- }})
+ }
+ })
.then((response) => {
if (response.data.status == 0) {
//Modalstopval:response.data.message,
@@ -132,11 +149,11 @@ class Fileslistitem extends Component{
this.setState({
// Modalstype:true,
// Modalstopval:"删除成功",
- ModalsBottomval:"",
+ ModalsBottomval: "",
// ModalSave:this.cancelmodel,
// Loadtype:true,
- checkBoxValues:[],
- checkAllValue:false
+ checkBoxValues: [],
+ checkAllValue: false
})
this.props.showNotification("删除成功");
@@ -147,28 +164,30 @@ class Fileslistitem extends Component{
});
}
- eventStop = (event) =>{
+ eventStop = (event) => {
event.stopPropagation()
}
- render(){
+ render() {
- const { checkBox,
- discussMessage,index
+ const {
+ checkBox,
+ discussMessage, index
} = this.props;
- return(
+ let bools = discussMessage.link && discussMessage.link ? false : true;
+ return (
{/*提示*/}
- {this.state.Modalstype&&this.state.Modalstype===true?
:""}
+ /> : ""}
- window.$(`.sourceitem${index} input`).click() }>
-
this.eventStop(event)}>
+ window.$(`.sourceitem${index} input`).click()}>
+
-
-
资源描述 :{discussMessage.description===null?"暂无描述":discussMessage.description}
+
资源描述 :{discussMessage.description === null ? "暂无描述" : discussMessage.description}
{/*
*/}
{/*/!**!/*/}
{/**/}
@@ -365,4 +466,5 @@ class Fileslistitem extends Component{
)
}
}
+
export default Fileslistitem;
diff --git a/public/react/src/modules/courses/Resource/index.js b/public/react/src/modules/courses/Resource/index.js
index 8187cd5af..787865219 100644
--- a/public/react/src/modules/courses/Resource/index.js
+++ b/public/react/src/modules/courses/Resource/index.js
@@ -6,6 +6,8 @@ import Modals from '../../modals/Modals';
import Sendtofilesmodal from "../coursesPublic/SendToFilesModal";
import Selectresource from "../coursesPublic/SelectResource";
import Sendresource from "../coursesPublic/sendResource";
+import SendResources from "../coursesPublic/sendResources";
+
import Selectsetting from "../coursesPublic/SelectSetting";
import HomeworkModal from "../coursesPublic/HomeworkModal";
import Fileslistitem from './Fileslistitem';
@@ -34,12 +36,16 @@ class Fileslists extends Component{
name:"",
sendTotype:false,
Accessoryvisible:false,
- discussMessageid:undefined,
+ Addanexternallink:false,
+ Exterchainname:"添加外链",
+ discussMessageid:undefined,
course_modules:undefined,
has_course_groups:false,
course_is_public:undefined,
isSpin:false,
- course_second_categories:[]
+ course_second_categories:[],
+ title: "",
+ link: ""
}
}
@@ -229,16 +235,15 @@ class Fileslists extends Component{
filesId:list.id,
name:list.name,
course_is_public:result.data.data.course_is_public,
- isSpin:false,
+
page:page
})
}
}
- }else{
- this.setState({
+ }
+ this.setState({
isSpin:false
})
- }
}).catch((error)=>{
console.log(error)
this.setState({
@@ -570,8 +575,48 @@ class Fileslists extends Component{
})
}
+ //添加外链资源设置
+ sendResourcessls = (ints,bool) => {
+ if(bool===true){
+
+ if(ints===1){
+ this.setState({
+ Addanexternallink:true,
+ Exterchainname:"添加外链"
+ })
+
+ }else{
+ this.setState({
+ Addanexternallink:true,
+ Exterchainname:"资源设置"
+ })
+
+ }
+
+
+ }else{
+ this.setState({
+ Addanexternallink:false,
+ title: "",
+ link: "",
+ discussMessageid:null,
+ })
+ if(ints===1){
+ this.Updateresourcepage();
+ }
+
+ }
+
+ }
+
+
+ Updateresourcepage=()=>{
+ let{pagesize,tagname,searchValue,page,sort,sorttype,coursesecondcategoryid}=this.state;
+ this.getfileslist(pagesize,page,tagname,searchValue,sort,sorttype,coursesecondcategoryid);
+ }
- Cancelvisible=()=>{
+
+ Cancelvisible=()=>{
this.setState({
Accessoryvisible:false,
@@ -587,6 +632,17 @@ class Fileslists extends Component{
})
}
+ Settingtypess=(id,title,link)=>{
+ debugger
+ this.setState({
+ Addanexternallink:true,
+ Exterchainname:"资源设置",
+ discussMessageid:id,
+ title: title,
+ link: link
+ })
+ }
+
moveTos=(id)=>{
let {checkBoxValues} = this.state;
@@ -729,7 +785,11 @@ class Fileslists extends Component{
course_is_public,
filesId,
child,
- sort
+ sort,
+ Addanexternallink,
+ Exterchainname,
+ title,
+ link,
} = this.state;
let category_id= this.props.match.params.category_id;
@@ -781,7 +841,7 @@ class Fileslists extends Component{
loadtype={Loadtype}
/>:""}
{
- shixunmodal===true||Accessoryvisible===true||Settingtype===true?
+
+ {
+ list && list.map((item,key)=>{
+ return(
+
+ {item.name}
+
+ )
+ })
+ }
+
+
+
+
+ )
+ }
+}
+export default MoveBox;
\ No newline at end of file
diff --git a/public/react/src/modules/courses/Video/Video.js b/public/react/src/modules/courses/Video/Video.js
index 0827c74e0..b082ef25a 100644
--- a/public/react/src/modules/courses/Video/Video.js
+++ b/public/react/src/modules/courses/Video/Video.js
@@ -5,7 +5,8 @@ import { NoneData, ActionBtn } from 'educoder';
import VideoUploadList from '../../user/usersInfo/video/VideoUploadList';
import VideoInReviewItem from '../../user/usersInfo/video/VideoInReviewItem';
import HeadlessModal from '../../user/usersInfo/common/HeadlessModal';
-import EditVideoModal from '../../user/usersInfo/video/EditVideoModal'
+import EditVideoModal from '../../user/usersInfo/video/EditVideoModal';
+import MoveBox from './MoveBox';
import ClipboardJS from 'clipboard'
import VideoPanel from './video-play'
@@ -28,7 +29,10 @@ class Video extends Component {
videoId: undefined,
videoVisible: false,
- visible: false
+ visible: false,
+
+ moveVisible:false,
+ moveVideoId:undefined
}
}
@@ -69,7 +73,7 @@ class Video extends Component {
// 编辑成功后回调的方法
editSuccess = () => {
- this.props.showNotification("视频名称修改成功!");
+ this.props.showNotification("视频信息修改成功!");
const { listFunc, page } = this.props;
listFunc && listFunc(page);
}
@@ -77,7 +81,8 @@ class Video extends Component {
onEditVideo = (item) => {
let videoId = {
videoId: item.id,
- title: item.title
+ title: item.title,
+ link:item.link
}
this.setState({
videoId,
@@ -142,7 +147,8 @@ class Video extends Component {
const url = `/courses/${CourseId}/delete_course_video.json`;
axios.delete(url, {
params: {
- video_id: item.id
+ video_id: item.id,
+ is_link:item.link ? true : undefined
}
}).then(result => {
if (result) {
@@ -161,9 +167,25 @@ class Video extends Component {
});
}
+ // 移动到
+ moveVideo=(id)=>{
+ this.setState({
+ moveVisible:true,
+ moveVideoId:id
+ })
+ }
+ setMoveVisible=(flag)=>{
+ this.setState({
+ moveVisible:flag,
+ moveVideoId:undefined
+ })
+ }
+
render() {
- const { visible, videoVisible, videoId } = this.state;
+ const { visible, videoVisible, videoId , moveVisible , moveVideoId } = this.state;
const CourseId = this.props.match.params.coursesId;
+ const VID=this.props.match.params.videoId;
+
const login = this.props.user && this.props.user.login;
const _inputValue = videoId && this.getCopyText(videoId.file_url, videoId.cover_url);
@@ -171,13 +193,21 @@ class Video extends Component {
const { videos, upload, uploadVideo, videoData, changePage, pageSize, page } = this.props;
- const operation = admin || business || (is_teacher && this.props.checkIfProfessionalCertification())
+ const operation = admin || business;
return (
+
this.setMoveVisible(flag)}
+ successFunc={()=>uploadVideo()}
+ id={moveVideoId}
+ >
{
upload ?
- uploadVideo()}>
+ uploadVideo()}>
:
{
@@ -215,8 +245,9 @@ class Video extends Component {
onEditVideo={this.onEditVideo}
onMaskClick={this.onMaskClick}
getCopyText={this.getCopyText}
- operation={operation}
+ operation={operation || item.user_id === user_id}
deleteVideo={(admin || item.user_id === user_id) ? this.deleteVideo : undefined}
+ moveVideo={videoData && videoData.has_category && (operation || item.user_id === user_id) ? ()=>this.moveVideo(item.id):undefined}
>
)
diff --git a/public/react/src/modules/courses/Video/VideoIndex.js b/public/react/src/modules/courses/Video/VideoIndex.js
index d58a2f187..15372e2cc 100644
--- a/public/react/src/modules/courses/Video/VideoIndex.js
+++ b/public/react/src/modules/courses/Video/VideoIndex.js
@@ -1,13 +1,13 @@
import React,{ Component } from "react";
+import { WordsBtn,on, trigger ,publicSearchs} from 'educoder';
import { Menu, Spin } from 'antd';
-import { WordsBtn } from 'educoder';
import axios from 'axios';
import Videos from './Video';
import Lives from './Live';
import LivesNew from './LiveNew';
-
+import VideoLink from './VideoLink';
import './video.css';
import '../css/Courses.css';
@@ -28,6 +28,7 @@ class VideoIndex extends Component{
upload:false,
videos:undefined,
videoData:undefined,
+ otherLinkVisible:false,
type:"video",
isSpining:false,
@@ -37,6 +38,7 @@ class VideoIndex extends Component{
liveId:undefined,
liveVisible:false
+
}
}
@@ -69,6 +71,15 @@ class VideoIndex extends Component{
this.checkType("video",page);
}
}
+ componentDidUpdate = (prevProps) => {
+ if(this.props.match.params.videoId !== prevProps.match.params.videoId ){
+ this.setState({
+ upload:false
+ })
+ const { page } = this.state;
+ this.checkType("video",page);
+ }
+ }
// 获取直播列表
getLiveList=(page)=>{
const CourseId=this.props.match.params.coursesId;
@@ -93,12 +104,13 @@ class VideoIndex extends Component{
// 获取视频列表
getList=(page)=>{
- const CourseId=this.props.match.params.coursesId;
- const fetchUrl = `/courses/${CourseId}/course_videos.json`;
+ const { coursesId , videoId }=this.props.match.params;
+ const fetchUrl = `/courses/${coursesId}/course_videos.json`;
axios.get(fetchUrl, {
params: {
page,
limit: PAGE_SIZE,
+ category_id:videoId
}
})
.then((response) => {
@@ -141,6 +153,7 @@ class VideoIndex extends Component{
this.setVisible(true);
}
uploadVideo=(upload)=>{
+
this.setState({
upload,
isSpining:true
@@ -200,12 +213,45 @@ class VideoIndex extends Component{
})
this.setliveVisibel(true);
}
+
+ // 新增目录
+ addDir=()=>{
+ let {videoData}=this.state;
+ trigger('videoAdd', parseInt(videoData.course_module_id));
+ }
+ // 目录重命名
+ editDir=(name,id)=>{
+ let data={id,name,update:this.getList}
+ trigger('editVideo',data);
+ }
+ // 增加外链
+ setLinkeVisible=(flag,refresh)=>{
+ this.setState({
+ otherLinkVisible:flag
+ })
+ if(refresh){
+ const { page } = this.state;
+ this.getList(page);
+ }
+ }
render(){
- const { videos , upload , videoData , type , liveData , lives , page , liveVisible , isSpining , liveId } = this.state;
+ const { videos , upload , videoData , type , liveData , lives , page , liveVisible , isSpining , liveId , otherLinkVisible } = this.state;
const { admin , is_teacher , business } = this.props.user;
- // console.log("p",this.props);
+ const { coursesId , videoId }=this.props.match.params;
+
+ const {course_identity} = this.props.coursedata;
+ const flag = parseInt(course_identity) < 4;
+ const newOperation = flag;
+ const new_upload = flag && (is_teacher && this.props.checkIfProfessionalCertification());
return(
+
-
-
-
{
- (admin || is_teacher || business) &&
-
-
- {
- type === "video" ?
-
+ videoData && videoData.category_name && type === "video" ?
+ {videoData.category_name}
+ :
+
+
+
+ }
+ -
+ {
+ type === "video" ?
+
+ {
+ newOperation ?
+
{
- upload ?
- this.uploadVideo(false)}>取消
+ videoId ?
+ this.editDir(videoData && videoData.category_name,videoId)} className={"mr30 font-16"}>目录重命名
:
- 上传视频
+ 新建目录
}
-
- :
- 添加直播
- }
-
- }
+ this.setLinkeVisible(true)}>增加外链
+ :""
+ }
+ {
+ new_upload ?
+
+ {
+ upload ?
+ this.uploadVideo(false)}>取消
+ :
+ 上传视频
+ }
+ :""
+ }
+
+ :
+ 添加直播
+ }
+
diff --git a/public/react/src/modules/courses/Video/VideoLink.js b/public/react/src/modules/courses/Video/VideoLink.js
new file mode 100644
index 000000000..3aa8b6725
--- /dev/null
+++ b/public/react/src/modules/courses/Video/VideoLink.js
@@ -0,0 +1,96 @@
+import React,{ Component } from "react";
+import { Modal , Form , Input , Spin , Select , AutoComplete , DatePicker , InputNumber } from 'antd';
+import axios from 'axios';
+
+class VideoLink extends Component{
+
+ componentDidUpdate=(prevProps)=>{
+ if(prevProps.visible !== this.props.visible){
+ this.props.form.setFieldsValue({
+ name:undefined,
+ link:undefined
+ })
+ }
+ }
+ cancelNew=()=>{
+ const { setVisible } = this.props;
+ setVisible && setVisible(false);
+ }
+ validateDesc= (rule, value, callback) => {
+ if(!value){
+ callback();
+ }
+ if (value.length > 60) {
+ callback("视频名称不能超过60个字!");
+ }else{
+ callback();
+ }
+ }
+ // 提交
+ handleSubmit=()=>{
+ this.props.form.validateFields((err, values) => {
+ if(!err){
+ const { coursesId , videoId } = this.props;
+ const url = `/courses/${coursesId}/course_videos.json`;
+ axios.post(url,{
+ ...values,
+ category_id:videoId
+ }).then(result=>{
+ if(result){
+ const { notification , setVisible } = this.props;
+ notification && notification('视频外链新增成功!');
+ setVisible && setVisible(false,true);
+ }
+ }).catch(error=>{
+ console.log(error);
+ })
+ }
+ })
+ }
+ render(){
+ const {getFieldDecorator} = this.props.form;
+
+ const { visible } = this.props;
+ const layout = {
+ labelCol: { span: 5 },
+ wrapperCol: { span: 19 },
+ }
+ return(
+
+
+
+ )
+ }
+}
+const WrappedVideoLink = Form.create({name: 'VideoLink'})(VideoLink);
+export default WrappedVideoLink;
\ No newline at end of file
diff --git a/public/react/src/modules/courses/coursesDetail/CoursesLeftNav.js b/public/react/src/modules/courses/coursesDetail/CoursesLeftNav.js
index 999ae4e15..75b788e16 100644
--- a/public/react/src/modules/courses/coursesDetail/CoursesLeftNav.js
+++ b/public/react/src/modules/courses/coursesDetail/CoursesLeftNav.js
@@ -61,6 +61,8 @@ class Coursesleftnav extends Component{
sandiantypes:undefined,
antIcon:false,
chapterupdate:false,
+
+ successFunc:undefined
}
}
@@ -138,61 +140,68 @@ class Coursesleftnav extends Component{
off('shixun_homeworkadd',this.addshixunchild)
off('editshixunname',this.editshixunchild)
off('editshixunmainname',this.editshixunmainname)
+ off('videoAdd',this.addVideo)
+ off('editVideo',this.editVideo)
}
addshixunchild=(e, data)=>{
- this.Navmodalnames(e,1,"shixun_homework",data)
+ this.Navmodalnames(e,1,"shixun_homework",data);
}
editshixunchild=(e, data)=>{
- this.Navmodalnames(e,4,"editSecondname",data.id,data.name)
+ this.Navmodalnames(e,4,"editSecondname",data.id,data.name);
}
editshixunmainname=(e, data)=>{
- this.Navmodalnames(e,3,"editname",data.id,data.name)
+ this.Navmodalnames(e,3,"editname",data.id,data.name);
}
boardAddListener = (e, data) => {
- this.Navmodalnames(e,6,"board", data)
+ this.Navmodalnames(e,6,"board", data);
+ }
+ addVideo=(e,id)=>{
+ this.Navmodalnames(e,1,"video",id);
+ }
+ editVideo=(e,data)=>{
+ this.setState({
+ successFunc:data.update
+ })
+ this.Navmodalnames(e,4,"editSecondname",data.id,data.name);
}
boardRenameListener = (e, data) => {
- this.Navmodalnames(e,7,"editSecondname", data.category_id, data.category_name)
+ this.Navmodalnames(e,7,"editSecondname", data.category_id, data.category_name);
}
groupAddListener = (e, data) => {
- this.Navmodalnames(e,2,"course_group", data)
+ this.Navmodalnames(e,2,"course_group", data);
}
groupRenameListener = (e, data) => {
- this.Navmodalnames(e,5,"editSecondname", data.id, data.name)
+ this.Navmodalnames(e,5,"editSecondname", data.id, data.name);
}
attachmentAddlog=(e,data)=>{
- this.Navmodalnames(e,1,"attachment",data)
+ this.Navmodalnames(e,1,"attachment",data);
}
flieseditDir=(e, data)=>{
- this.Navmodalnames(e,4,"editSecondname",data.id,data.name)
+ this.Navmodalnames(e,4,"editSecondname",data.id,data.name);
}
componentDidMount() {
-
this.setState({
url:this.props.match.url
})
- on('boardAdd', this.boardAddListener)
- on('boardRename', this.boardRenameListener)
- on('groupAdd', this.groupAddListener)
- on('groupRename', this.groupRenameListener)
- on('attachmentAddlog', this.attachmentAddlog)
- on('flieseditDir', this.flieseditDir)
- on('shixun_homeworkadd',this.addshixunchild)
- on('editshixunname',this.editshixunchild)
- on('editshixunmainname',this.editshixunmainname)
+ on('boardAdd', this.boardAddListener);
+ on('boardRename', this.boardRenameListener);
+ on('groupAdd', this.groupAddListener);
+ on('groupRename', this.groupRenameListener);
+ on('attachmentAddlog', this.attachmentAddlog);
+ on('flieseditDir', this.flieseditDir);
+ on('shixun_homeworkadd',this.addshixunchild);
+ on('editshixunname',this.editshixunchild);
+ on('editshixunmainname',this.editshixunmainname);
+ on('videoAdd',this.addVideo);
+ on('editVideo',this.editVideo)
- // this.props.updataleftNavfun();
- // this.props.getleftNavid && this.props.getleftNavid("shixun_homework");
- // const position =parseInt(this.props.match.params.position);
let courstype=this.props.match.url;
- courstype = courstype.split('/');
-
- courstype=courstype[3];
+ courstype = courstype.split('/');
- // console.log(courstype)
+ courstype=courstype[3];
const query =this.props.location.search;
@@ -520,7 +529,9 @@ class Coursesleftnav extends Component{
// loadtype:true,
// NavmodalValue:""
// })
- navidtype=true
+ navidtype=true;
+ const { successFunc } = this.state;
+ successFunc && successFunc(1);
}
saveNavmodapost=(url,value,positiontype,coursesId)=>{
@@ -658,32 +669,28 @@ class Coursesleftnav extends Component{
updatadeleteSecondary=(url)=>{
this.props.updataleftNavfun();
- // this.setState({
- // ModalsType:true,
- // Modalstopval:"删除成功",
- // loadtype:true,
- // })
- // notification.open({
- // message: "删除成功",
- // });
-
- // this.props.history.replace(url);
- window.location.href = url;
+ this.setState({
+ ModalsType:false,
+ Modalstopval:"",
+ loadtype:false,
+ })
+ notification.open({
+ message: "删除成功",
+ });
+
+ this.props.history.replace(url);
+
+ // window.location.href = url;
}
deletenavchilds=(url,mainurl)=>{
- this.setState({
- antIcon:true
- })
+ console.log(this.props);
+ this.setState({
+ antIcon:true
+ })
axios.delete(url).then((result)=>{
if(result.data.status===0){
-
- if(mainurl===undefined){
- this.updatadeleteSecondary(result.data.right_url)
- }else{
- this.updatadeleteSecondary(mainurl)
- }
-
+ this.updatadeleteSecondary(mainurl || result.data.right_url);
}
}).catch((error)=>{
console.log(error)
@@ -698,8 +705,8 @@ class Coursesleftnav extends Component{
ModalsType:true,
Modalstopval:"该目录下的内容将被移动到父目录,",
ModalsBottomval:"是否确认删除?",
- ModalSave:()=>this.deletenavchilds(url),
-
+ ModalSave:()=>this.deletenavchilds(url,mainurl),
+ loadtype:false
})
}else if(type===2){
@@ -709,7 +716,7 @@ class Coursesleftnav extends Component{
Modalstopval:"该分班的学生将被移动到“未分班”,",
ModalsBottomval:"是否确认删除?",
ModalSave:()=>this.deletenavchilds(url),
-
+ loadtype:false
})
}else if(type===3){
let url="/boards/"+id+".json"
@@ -718,7 +725,7 @@ class Coursesleftnav extends Component{
Modalstopval:"该目录下的内容将被移动到父目录,",
ModalsBottomval:"是否确认删除?",
ModalSave:()=>this.deletenavchilds(url,mainurl),
-
+ loadtype:false
})
}
@@ -838,6 +845,8 @@ class Coursesleftnav extends Component{
{item.type==="shixun_homework"?this.Navmodalnames(e,1,"shixun_homework",item.id)}>新建目录
:""}
{/*资源*/}
{item.type==="attachment"?this.Navmodalnames(e,1,"attachment",item.id)}>新建目录
:""}
+ {/* 视频 */}
+ {item.type==="video"?this.Navmodalnames(e,1,"video",item.id)}>新建目录
:""}
{/*毕业设计*/}
{/*{item.type==="graduation"?this.Navmodalnames(1,"attachment",item.id)}>添加目录
:""}*/}
{/*讨论区*/}
@@ -872,6 +881,9 @@ class Coursesleftnav extends Component{
{/*讨论区*/}
{item.type==="board"?this.Navmodalnames(e,7,"editSecondname",iem.category_id,iem.category_name)}>重命名
:""}
{item.type==="board"?this.deleteSecondary(e,3,iem.category_id,item.category_url)}>删除
:""}
+ {/*视频*/}
+ {item.type==="video"?this.Navmodalnames(e,4,"editSecondname",iem.category_id,iem.category_name)}>重命名
:""}
+ {item.type==="video"?this.deleteSecondary(e,1,iem.category_id,item.category_url)}>删除
:""}
)
};
diff --git a/public/react/src/modules/courses/coursesPublic/sendResources.js b/public/react/src/modules/courses/coursesPublic/sendResources.js
new file mode 100644
index 000000000..75726a51f
--- /dev/null
+++ b/public/react/src/modules/courses/coursesPublic/sendResources.js
@@ -0,0 +1,585 @@
+import React,{ Component } from "react";
+import { Modal,Checkbox,Upload,Button,Icon,message,DatePicker,Select,Tooltip,Radio,Input} from "antd";
+import axios from 'axios';
+import Modals from '../../modals/Modals';
+import {getUploadActionUrl,handleDateString,appendFileSizeToUploadFileAll} from 'educoder';
+import locale from 'antd/lib/date-picker/locale/zh_CN';
+import moment from 'moment';
+const CheckboxGroup = Checkbox.Group;
+const Option = Select.Option;
+function range(start, end) {
+ const result = [];
+ for (let i = start; i < end; i++) {
+ result.push(i);
+ }
+ return result;
+}
+function disabledDateTime() {
+ return {
+ // disabledHours: () => range(0, 24).splice(4, 20),
+ disabledMinutes: () => range(1, 30).concat(range(31, 60)),
+ // disabledSeconds: () => [0, 60],
+ };
+}
+
+function disabledDate(current) {
+ return current && current < moment().endOf('day').subtract(1, 'days');
+}
+
+
+const dateFormat="YYYY-MM-DD HH:mm";
+class sendResources extends Component{
+ constructor(props){
+ super(props);
+ this.state={
+ group_ids:[],
+ fileList:[],
+ Modalstype:false,
+ Modalstopval:"",
+ ModalCancel:"",
+ ModalSave:"",
+ fileListtype:false,
+ loadtype:false,
+ is_public:false,
+ datatime:undefined,
+ resourcesname:"",
+ resourceurl:"",
+ addonAfteronelens3:0,
+ // moment(new Date()).format('YYYY-MM-DD HH:mm:ss'),
+ course_group_publish_times:[
+ {
+ course_group_id : undefined,
+ publish_time :""
+ }],
+ course_groups:undefined,
+ course_groups_count:undefined,
+ Radiovalue:0,
+ Radiovaluetype:false,
+ resourceurlbool:false,
+ resourcesnamebool:false,
+ }
+ }
+
+
+ componentDidMount() {
+ let {discussMessageid} =this.props;
+ try {
+ this.setState({
+ resourcesname:this.props.title,
+ resourceurl:this.props.link,
+ addonAfteronelens3:this.props.title.length,
+ })
+ }catch (e) {
+
+ }
+ console.log(discussMessageid);
+ try {
+ if(discussMessageid){
+ this.getalldata();
+ }
+ }catch (e) {
+
+ }
+
+
+ }
+
+ getalldata=()=>{
+ let {discussMessageid} =this.props;
+ let course_id=this.props.course_id;
+ let url="/files/"+discussMessageid+".json";
+ axios.get(url, {
+ params:{
+ course_id:course_id,
+ }
+ })
+ .then((response) => {
+ if(response.status===200){
+ this.setState({
+ datalist:response.data,
+ description: response.data.description,
+ is_public:response.data.is_public,
+ datatime:response.data.publish_time,
+ Radiovalue:response.data.delay_publish==false?0:1,
+ //attachment_histories:response.data.attachment_histories
+ })
+
+ }
+ })
+ .catch(function (error) {
+ console.log(error);
+ });
+
+ }
+ //勾选实训
+ shixunhomeworkedit=(list)=>{
+
+ this.setState({
+ group_ids:list
+ })
+
+ }
+ // 附件相关 START
+ handleChange = (info) => {
+ console.log(info)
+
+ if (info.file.status === 'uploading' || info.file.status === 'done' || info.file.status === 'removed') {
+ let fileList = info.fileList;
+ if (info.file.status != "removed") {
+ this.setState({
+ fileList: appendFileSizeToUploadFileAll(fileList),
+ fileListtype: true
+ });
+ } else {
+ this.setState({
+ fileList: appendFileSizeToUploadFileAll(fileList),
+ });
+ }
+ }
+ }
+
+ onAttachmentRemove = (file) => {
+ if(!file.percent || file.percent == 100){
+ const url = `/attachments/${file.response ? file.response.id : file.uid}.json`
+ axios.delete(url, {
+ })
+ .then((response) => {
+ if (response.data) {
+ const { status } = response.data;
+ if (status == 0) {
+ this.setState({
+ fileListtype:false,
+ fileList:[]
+ })
+ }
+
+ }
+ })
+ .catch(function (error) {
+ console.log(error);
+ });
+ this.setState({
+ fileListtype:false,
+ })
+ }else{
+ this.setState({
+ fileListtype:false,
+ fileList:[]
+ })
+ }
+ }
+
+ ModalCancelModalCancel=()=>{
+ this.setState({
+ Modalstype:false,
+ Modalstopval:"",
+ ModalSave:this.ModalCancelModalCancel,
+ loadtype:false
+ })
+ this.props.Cancel()
+ }
+ Saves=()=>{
+
+
+ let {resourcesname,resourceurl,description,is_public,datatime,Radiovalue} =this.state;
+ const reg = /^[\s\S]*.*[^\s][\s\S]*$/;
+
+ if (!reg.test(resourcesname)) {
+ this.setState({
+ resourcesnamebool:true
+ })
+ return;
+ }
+ if (!reg.test(resourceurl)) {
+ this.setState({
+ resourceurlbool:true
+ })
+ return;
+ }
+
+
+
+ if(this.state.Radiovalue===1){
+ if(datatime===undefined||datatime===null||datatime=== ""){
+ this.setState({
+ Radiovaluetype:true
+ })
+ return
+ }else{
+ this.setState({
+ Radiovaluetype:false
+ })
+ }
+ }
+
+
+
+ if(description===undefined){
+
+ }else if(description.length>100){
+
+ this.setState({
+ descriptiontype:true
+ })
+ return
+ }
+
+ if(this.props.Exterchainname==="资源设置"){
+ //设置
+ let coursesId=this.props.match.params.coursesId;
+ let attachmentId=this.props.attachmentId;
+ let url="/files/"+this.props.discussMessageid+".json";
+
+ axios.put(url,{
+ name:resourcesname,
+ link:resourceurl,
+ course_id:coursesId,
+ course_second_category_id:this.props.coursesidtype===undefined||this.props.coursesidtype==="node"?0:attachmentId,
+ is_public:is_public,
+ publish_time:Radiovalue===1?datatime===undefined? undefined:datatime:undefined,
+ description:description,
+ delay_publish:Radiovalue,
+ }).then((result)=>{
+ if(result.data.status===0){
+ this.ModalCancelModalCancel();
+ this.props.updataleftNavfun();
+ this.props.showNotification("设置资源成功");
+ this.props.setupdate(1,false)
+ }else{
+ this.props.showNotification(result.data.message);
+ }
+ })
+
+ }else{
+ let coursesId=this.props.match.params.coursesId;
+ let attachmentId=this.props.attachmentId;
+ let url="/files/upload.json";
+
+
+ axios.post(url,{
+ name:resourcesname,
+ link:resourceurl,
+ course_id:coursesId,
+ course_second_category_id:this.props.coursesidtype===undefined||this.props.coursesidtype==="node"?0:attachmentId,
+ is_public:is_public,
+ publish_time:Radiovalue===1?datatime===undefined? undefined:datatime:undefined,
+ description:description,
+ delay_publish:Radiovalue,
+ }).then((result)=>{
+
+
+ if(result.data.status===0){
+ this.ModalCancelModalCancel();
+ this.props.updataleftNavfun();
+ this.props.showNotification("上传资源成功");
+ this.props.setupdate(1,false)
+ }else{
+ this.props.showNotification(result.data.message);
+ }
+ })
+
+ }
+
+
+
+ }
+
+ settextarea=(e)=>{
+ this.setState({
+ description:e.target.value
+ })
+ }
+
+ onChangepublic=(e)=>{
+
+ this.setState({
+ is_public:e.target.checked
+ })
+
+ }
+
+ onChangeTimepublish= (date, dateString,key,type) => {
+ if(type===1){
+ this.setState({
+ datatime:handleDateString(dateString),
+ })
+ }else if(type===2){
+ let {course_group_publish_times}=this.state;
+ let newgroup_publish=course_group_publish_times;
+ for(var i=0; i{
+ if(e.target.value===0){
+ this.setState({
+ datatime:undefined
+ })
+ }
+ this.setState({
+ Radiovalue: e.target.value,
+ });
+ }
+
+ handleChanges=(e)=>{
+ let les=e.target.value.length;
+
+ if(e.target.value.length>=61){
+
+
+ }else{
+ this.setState({
+ resourcesname:e.target.value,
+ addonAfteronelens3:les,
+ resourcesnamebool:false,
+
+ })
+
+ }
+
+ }
+
+ handleChangess=(e)=>{
+ this.setState({
+ resourceurl:e.target.value,
+ resourceurlbool:false,
+ })
+ }
+
+
+
+ render(){
+ let { newfileListtype,descriptiontype,
+ is_public,
+ datatime,
+ resourcesname,
+ resourceurl,
+ addonAfteronelens3,
+ resourceurlbool,
+ resourcesnamebool,
+ }=this.state;
+
+ const uploadProps = {
+ width: 600,
+ // showUploadList:false,
+ action: `${getUploadActionUrl()}`,
+ onChange: this.handleChange,
+ onRemove: this.onAttachmentRemove,
+ beforeUpload: (file) => {
+ // console.log('beforeUpload', file.name);
+ const isLt150M = file.size / 1024 / 1024 < 150;
+ if (!isLt150M) {
+ this.props.showNotification('文件大小必须小于150MB!');
+ }
+ return isLt150M;
+ },
+ };
+ const radioStyle = {
+ display: 'block',
+ height: '30px',
+ lineHeight: '30px',
+ };
+
+
+
+ return(
+
+ {/*提示*/}
+
+
+
+
+
+
+
+
+
+
+
+
+ 资源名称:
+
+
+
+
+ {
+ resourcesnamebool?
+
请输入资源名称
+ :
+ ""
+ }
+
+ 链接地址:
+
+
+ {
+ resourceurlbool?
+
请输入外链url
+ :
+ ""
+ }
+
+
+
+
+
+ {this.props.course_is_public===true?
+ 公开:
+ 选中,所有用户可见,否则课堂成员可见
+
+
:""}
+
+
+
+
+
+
+ 发布设置:
+
+
+ 立即发布
+
+
+
+ 延期发布
+ this.onChangeTimepublish(e,index,undefined,1)}
+ disabledTime={disabledDateTime}
+ disabledDate={disabledDate}
+ disabled={this.state.Radiovalue===1?false:true}
+ />
+
+
+ (按照设置的时间定时发布)
+
+
+
+
资源描述:
+ {/*{course_group_publish_timestype===true?
请填写完整
:""}*/}
+
+
+
+ {descriptiontype===true?
请输入资源描述,最大限制100个字符
:""}
+ {this.state.Radiovaluetype===true?
发布时间不能为空
:""}
+
+
+
+
+
+ )
+ }
+}
+export default sendResources;
diff --git a/public/react/src/modules/developer/studentStudy/rightpane/index.js b/public/react/src/modules/developer/studentStudy/rightpane/index.js
index 628524063..a90e8e348 100644
--- a/public/react/src/modules/developer/studentStudy/rightpane/index.js
+++ b/public/react/src/modules/developer/studentStudy/rightpane/index.js
@@ -50,7 +50,6 @@ const RightPane = (props) => {
let timer = null; // 定时器
// 代码块内容变化时
const handleCodeChange = (value) => {
- // console.log('编辑器代码 ======》》》》》》》》》++++++++++', value);
saveUserInputCode(value);
// setEditorCode(value);
if (!timer) {
diff --git a/public/react/src/modules/question/Question.js b/public/react/src/modules/question/Question.js
index 772a75fb1..87d05f71a 100644
--- a/public/react/src/modules/question/Question.js
+++ b/public/react/src/modules/question/Question.js
@@ -742,9 +742,6 @@ class Question extends Component {
}
// 撤销
getitem_basketss=(id)=>{
- this.setState({
-
- })
if(Undoclickable===true){
Undoclickable=false;
//选用题型可以上传单个 或者多个题型
diff --git a/public/react/src/modules/question/component/Contentpart.js b/public/react/src/modules/question/component/Contentpart.js
index f4fba7d5f..e3f5259e5 100644
--- a/public/react/src/modules/question/component/Contentpart.js
+++ b/public/react/src/modules/question/component/Contentpart.js
@@ -232,39 +232,6 @@ class Contentpart extends Component {
}
- const content = (
-
-
this.props.setitem_types(null)}>全部
-
-
this.props.setitem_types("SINGLE")}>单选题
-
-
this.props.setitem_types("MULTIPLE")}>多选题
-
-
this.props.setitem_types("JUDGMENT")}>判断题
-
-
this.props.setitem_types("PROGRAM")}>编程题
-
-
-
- );
- const contents = (
-
-
this.props.setoj_status(null)}>全部
-
-
this.props.setoj_status(0)}>未发布
-
-
this.props.setoj_status(1)}>已发布
-
-
- );
-
-
// console.log("Contentpart.js");
// console.log(this.props.current_user.professional_certification);
@@ -381,22 +348,6 @@ class Contentpart extends Component {
:""
}
- {item_type==="PROGRAM"?
- defaultActiveKey===0||defaultActiveKey==="0"?
- trigger.parentNode} placement="bottom" trigger="hover" content={contents} onVisibleChange={()=>this.props.handleVisibleChange(true)}>
-
-
- :
- "":""
- }
-
-
{
this.props.Isitapopup&&this.props.Isitapopup==="true"?
{
return (
{
items.item_type==="PROGRAM"?
- this.seturls(`/problems/${items.program_attr.identifier}/edit`)} className="ml10 flex1 mt2">
-
-
+ (
+ this.props.defaultActiveKeys&&this.props.defaultActiveKeys==="0"?
+ this.seturls(`/problems/${items.program_attr.identifier}/edit`)} className="ml10 flex1 mt2 xiaoshou">
+
+
+ :
+
+
+
+ )
+
:
diff --git a/public/react/src/modules/question/component/QuestionModal.js b/public/react/src/modules/question/component/QuestionModal.js
index de7614f37..87338faa7 100644
--- a/public/react/src/modules/question/component/QuestionModal.js
+++ b/public/react/src/modules/question/component/QuestionModal.js
@@ -28,11 +28,21 @@ class QuestionModal extends Component {
width="442px"
>
-
-
+ {this.props.titilesm?
+
+
+ :
+ ""
+ }
+ {
+ this.props.titiless?
+
+ :
+ ""
+ }
diff --git a/public/react/src/modules/testpaper/Paperlibraryseeid.js b/public/react/src/modules/testpaper/Paperlibraryseeid.js
index d81a0afa7..ce529c05e 100644
--- a/public/react/src/modules/testpaper/Paperlibraryseeid.js
+++ b/public/react/src/modules/testpaper/Paperlibraryseeid.js
@@ -19,6 +19,7 @@ import '../tpm/newshixuns/css/Newshixuns.css';
import Bottomsubmit from "../../modules/modals/Bottomsubmit";
import Seeoagertit from "./component/Seeoagertit";
import Paperlibraryseeid_item from './component/Paperlibraryseeid_item';
+import QuestionModal from "../question/component/QuestionModal";
//人工组卷预览
class Paperlibraryseeid extends Component {
constructor(props) {
@@ -27,8 +28,10 @@ class Paperlibraryseeid extends Component {
this.state = {
paperlibrartdata:[],
defaultActiveKey:"0",
-
-
+ modalsType:false,
+ titilesm:"",
+ titiless:"",
+ boolok:"知道了"
}
@@ -91,7 +94,11 @@ class Paperlibraryseeid extends Component {
}
preservation = () => {
//保存试卷
-
+ this.setState({
+ modalsType: true,
+ titilesm: "功能正在内测中,敬请期待",
+ titiless: "",
+ })
@@ -109,13 +116,34 @@ class Paperlibraryseeid extends Component {
getcontentMdRef = (Ref) => {
this.contentMdRef = Ref;
}
+
+ modalCancel =()=>{
+ this.setState({
+ modalsType: false,
+ })
+
+ }
+
+ setDownload =()=>{
+ this.setState({
+ modalsType: false,
+ })
+
+ }
+
render() {
- let {paperlibrartdata,defaultActiveKey} = this.state;
+ let {paperlibrartdata,defaultActiveKey,titilesm,titiless,boolok,modalsType} = this.state;
const params = this.props && this.props.match && this.props.match.params;
// ////console.log(params);
let urlsysl=`/paperlibrary?defaultActiveKey=${defaultActiveKey}`;
return (
+ {
+ modalsType===true?
+
this.modalCancel()}
+ setDownload={() => this.setDownload()}>
+ :""
+ }
diff --git a/public/react/src/modules/tpm/shixuns/shixun-search-bar/index.jsx b/public/react/src/modules/tpm/shixuns/shixun-search-bar/index.jsx
index 29a3b8485..c936de66d 100644
--- a/public/react/src/modules/tpm/shixuns/shixun-search-bar/index.jsx
+++ b/public/react/src/modules/tpm/shixuns/shixun-search-bar/index.jsx
@@ -91,7 +91,7 @@ export default ({ StatusEnquiry, allUpdatashixunlist, Updatasearchlist }) => {
方向:
-
全部
+
- 全部
{
navs.map((item, key) => {
return (
diff --git a/public/react/src/modules/user/usersInfo/video/AliyunUploaderManager.js b/public/react/src/modules/user/usersInfo/video/AliyunUploaderManager.js
index 3312473c4..ef2eaceda 100644
--- a/public/react/src/modules/user/usersInfo/video/AliyunUploaderManager.js
+++ b/public/react/src/modules/user/usersInfo/video/AliyunUploaderManager.js
@@ -73,7 +73,7 @@ function doCreateUploader (options) {
const _random = '' // Math.random().toString().substring(3, 6)+'-'
axios.post(createUrl, {
title: _random+fileName,
- file_name: _random+fileName
+ file_name: _random+fileName,
}).then((response) => {
// if (response.data.status == )
if(response){
diff --git a/public/react/src/modules/user/usersInfo/video/EditVideoModal.js b/public/react/src/modules/user/usersInfo/video/EditVideoModal.js
index 25aadd119..43486f43c 100644
--- a/public/react/src/modules/user/usersInfo/video/EditVideoModal.js
+++ b/public/react/src/modules/user/usersInfo/video/EditVideoModal.js
@@ -8,10 +8,12 @@ function EditVideoModal (props) {
const modalEl = useRef(null);
const theme = useContext(ThemeContext);
const { history, videoId, cover_url, title, created_at, isReview, onEditVideo, visible, setVisible,
- form, editSuccess } = props;
+ form, editSuccess , link } = props;
const getFieldDecorator = form.getFieldDecorator
let username = props.match.params.username
const _title = form.getFieldsValue().title;
+ const _link = form.getFieldsValue().link;
+
if(props.CourseUser){
username = props.CourseUser;
@@ -27,9 +29,14 @@ function EditVideoModal (props) {
form.validateFieldsAndScroll((err, values) => {
if (!err) {
- const url = `/users/${username}/videos/${videoId}.json`
- axios.put(url, {
- title: _title
+ const url = link?`/course_videos/${videoId}.json`:`/users/${username}/videos/${videoId}.json`;
+
+ axios.put(url, link ? {
+ name:_title,
+ link:_link
+ }:{
+ title: _title,
+ link:_link
}).then((response) => {
if (response.data) {
onCancel()
@@ -54,7 +61,7 @@ function EditVideoModal (props) {
}, [visible])
useEffect(() => {
visible && form.setFieldsValue({
- title,
+ title,link
})
}, [visible])
return (
@@ -71,10 +78,9 @@ function EditVideoModal (props) {
{
`
.exercicenewinputysl .ant-input{
- border-right: none !important;
- height: 40px !important;
- }
-
+ border-right: none !important;
+ height: 40px !important;
+ }
`
}
@@ -93,7 +99,24 @@ function EditVideoModal (props) {
)}
-
+
+ {
+ link ?
+
+
+ {getFieldDecorator('link', {
+ rules: [{
+ required: true, message: '请输入视频链接',
+ }],
+ })(
+
+ )}
+
+ :""
+ }
)
}
diff --git a/public/react/src/modules/user/usersInfo/video/InfosVideo.css b/public/react/src/modules/user/usersInfo/video/InfosVideo.css
index fd17ac49c..a28f7cf5d 100644
--- a/public/react/src/modules/user/usersInfo/video/InfosVideo.css
+++ b/public/react/src/modules/user/usersInfo/video/InfosVideo.css
@@ -142,4 +142,26 @@
.videoItem:hover{
box-shadow:0px 4px 10px 0px rgba(3,7,45,0.1);
border-radius:12px;
+}
+.otherLink{
+ position: absolute;
+ height:30px;
+ line-height: 30px;
+ padding:0px 18px;
+ background:rgba(249,117,26,1);
+ border-radius:0px 100px 100px 0px;
+ display: block;
+ left: 0;
+ top:32px;
+ color: #fff;
+ z-index:2;
+}
+.otherLinkPanel{
+ display: block;
+ position: absolute;
+ width: 100%;
+ top:0px;
+ left:0px;
+ height: 220px;
+ z-index: 1;
}
\ No newline at end of file
diff --git a/public/react/src/modules/user/usersInfo/video/VideoInReviewItem.js b/public/react/src/modules/user/usersInfo/video/VideoInReviewItem.js
index 5c0647ea1..b045f54b8 100644
--- a/public/react/src/modules/user/usersInfo/video/VideoInReviewItem.js
+++ b/public/react/src/modules/user/usersInfo/video/VideoInReviewItem.js
@@ -5,7 +5,8 @@ import axios from 'axios'
import moment from 'moment'
import playIcon from './images/play.png'
import ClipboardJS from 'clipboard'
-
+import defaultImg from './images/default.png';
+import './InfosVideo.css';
/**
cover_url: "http://video.educoder.net/f6ba49c3944b43ee98736898e31b7d88/snapshots/12da3f7df07c499b8f0fc6dc410094e9-00005.jpg"
created_at: "2019-08-12 13:48:26"
@@ -20,7 +21,7 @@ const clipboardMap = {}
function VideoInReviewItem (props) {
const theme = useContext(ThemeContext);
const { history, file_url, cover_url, title, created_at, published_at, isReview, id
- , onEditVideo, onMaskClick, getCopyText, showNotification,vv,play_duration,operation , deleteVideo} = props;
+ , onEditVideo, onMaskClick, getCopyText, showNotification,vv,play_duration,operation , deleteVideo , moveVideo ,link} = props;
useEffect(()=> {
if (!isReview) {
_clipboard = new ClipboardJS(`.copybtn_item_${id}`);
@@ -46,12 +47,16 @@ function VideoInReviewItem (props) {
return (
-

- {!isReview &&
onMaskClick(props)}>
+

+ { link ?
+
+ 外链
+
+ : ""
+ }
-
}
- {!isReview &&
+ {!isReview &&
onMaskClick(props)}>
}
+ {!isReview && !link &&
onMaskClick(props)}>

{play_duration===0?"":
累计学习时长:{play_duration} h
}
@@ -68,11 +73,19 @@ function VideoInReviewItem (props) {
{/* 2019-09-01 10:00:22 */}
- {vv===0?"":
+ {!vv || (vv && vv)===0 ? "" :
- } {vv===0?"":vv}
+ } {!vv || (vv && vv)===0?"":vv}
{ isReview != true &&
+ {
+ moveVideo &&
+
+ moveVideo(props)}
+ style={{ marginTop: '1px', display: 'inline-block'}}
+ >
+
+ }
{
deleteVideo &&
@@ -90,9 +103,13 @@ function VideoInReviewItem (props) {
>
}
-
-
-
+ {
+ !link ?
+
+
+ :""
+ }
+
}
diff --git a/public/react/src/modules/user/usersInfo/video/VideoUploadList.js b/public/react/src/modules/user/usersInfo/video/VideoUploadList.js
index 49529bdd8..7855fc39a 100644
--- a/public/react/src/modules/user/usersInfo/video/VideoUploadList.js
+++ b/public/react/src/modules/user/usersInfo/video/VideoUploadList.js
@@ -226,7 +226,7 @@ function VideoUploadList (props) {
}
function onPublish() {
// 下列这些参数只有是课堂里面上传视频才会有
- const { CourseId , CourseUser ,flag , successFunc } = props;
+ const { CourseId , CourseUser ,flag , successFunc , videoId } = props;
if (state.videos.length == 0) {
showNotification('请先上传视频')
return;
@@ -238,7 +238,8 @@ function VideoUploadList (props) {
video_id: item.videoId,
// todo
title: item.title,
- course_id:CourseId
+ course_id:CourseId,
+ category_id:videoId
}
})
}).then((response) => {
@@ -268,7 +269,6 @@ function VideoUploadList (props) {
:
上传内容协议
const protocolLine =
上传视频,即表示您已同意{urls},不得上传未经他人授权的作品
-
return (
{
* @param {*} inputValue 输入值: 自定义 | 系统返回的
* @param {*} type 测评类型 debug | submit
*/
-//原来的方法未能区分从编辑入口进来的情况,这时代码也是更新了的。
+//原来的方法未能区分从编辑入口进来的情况,这时代码也是更新了的。以及ctrl+z undo未能触发chnage事件 monaco-editor的bug。 这里去除isUpdateCode
export const updateCode = (identifier, inputValue, type) => {
return (dispatch, getState) => {
- const { editor_code, isUpdateCode } = getState().ojForUserReducer;
- if (isUpdateCode) {
- fetchUpdateCode(identifier, {
- code: Base64.encode(editor_code)
- }).then(res => {
- if (res) {
- if (res.data.status === 401) {
- dispatch({ // 改变 loading 值
- type: types.LOADING_STATUS,
- payload: false
- });
- return;
- };
- dispatch({
- type: types.IS_UPDATE_CODE,
- flag: false
+ const { editor_code } = getState().ojForUserReducer;
+ fetchUpdateCode(identifier, {
+ code: Base64.encode(editor_code)
+ }).then(res => {
+ if (res) {
+ if (res.data.status === 401) {
+ dispatch({ // 改变 loading 值
+ type: types.LOADING_STATUS,
+ payload: false
});
- dispatch(debuggerCode(identifier, inputValue, type));
- }
- });
- } else {
- // 没有更新时,直接调用调试接口
- dispatch(debuggerCode(identifier, inputValue, type));
- }
+ return;
+ };
+ dispatch({
+ type: types.IS_UPDATE_CODE,
+ flag: false
+ });
+ dispatch(debuggerCode(identifier, inputValue, type));
+ }
+ });
+
}
}
@@ -370,14 +366,6 @@ export const saveUserInputCode = (code) => {
}
}
-// 监听是否更新代码块内容
-// export const isUpdateCodeCtx = (flag) => {
-// return {
-// type: types.IS_UPDATE_CODE,
-// payload: flag
-// };
-// }
-
// 改变学员测评 tab 值
export const changeUserCodeTab = (key) => {
return {
@@ -392,7 +380,7 @@ export const changeUserCodeTab = (key) => {
*/
export const submitUserCode = (identifier, inputValue, type) => {
return (dispatch, getState) => {
- const { editor_code, isUpdateCode, hack } = getState().ojForUserReducer;
+ const { editor_code, hack } = getState().ojForUserReducer;
function userCodeSubmit() {
fetchUserCodeSubmit(identifier).then(res => {
if (res.status === 200) {
@@ -413,32 +401,29 @@ export const submitUserCode = (identifier, inputValue, type) => {
});
});
}
- if (isUpdateCode) {
- fetchUpdateCode(identifier, {
- code: Base64.encode(editor_code)
- }).then(res => {
- // 是否更新了代码, 目的是当代码没有更新时不调用更新代码接口,目录没有实现
- if (res.data.status === 401) {
- dispatch({
- type: types.SUBMIT_LOADING_STATUS,
- payload: false
- });
- return;
- };
- dispatch({
- type: types.IS_UPDATE_CODE,
- flag: false
- });
- userCodeSubmit();
- }).catch(() => {
+ fetchUpdateCode(identifier, {
+ code: Base64.encode(editor_code)
+ }).then(res => {
+ // 是否更新了代码, 目的是当代码没有更新时不调用更新代码接口,目录没有实现
+ if (res.data.status === 401) {
dispatch({
type: types.SUBMIT_LOADING_STATUS,
payload: false
- })
+ });
+ return;
+ };
+ dispatch({
+ type: types.IS_UPDATE_CODE,
+ flag: false
});
- } else {
userCodeSubmit();
- }
+ }).catch(() => {
+ dispatch({
+ type: types.SUBMIT_LOADING_STATUS,
+ payload: false
+ })
+ });
+
}
}
diff --git a/public/react/src/redux/reducers/ojForUserReducer.js b/public/react/src/redux/reducers/ojForUserReducer.js
index d20656513..60c3dc7af 100644
--- a/public/react/src/redux/reducers/ojForUserReducer.js
+++ b/public/react/src/redux/reducers/ojForUserReducer.js
@@ -17,7 +17,6 @@ const initialState = {
commitTestRecordDetail: {}, // 调试代码执行结果
commitRecordDetail: {}, // 提交成功后记录提交的详情
commitRecord: [], // 提交记录
- userCode: '', // 保存当前用户输入的代码
isUpdateCode: false, // 是否更新了代码内容
userCodeTab: 'task', // 学员测评tab位置: task | record | comment
userTestInput: '', // 用户自定义输入值
@@ -59,7 +58,7 @@ const ojForUserReducer = (state = initialState, action) => {
hack: Object.assign({}, hack),
test_case: Object.assign({}, test_case),
comment_identifier: hack.identifier,
- userCode: tempCode
+ editor_code: tempCode
}
case types.COMMIT_RECORD_DETAIL:
let result = action.payload.data;
@@ -127,7 +126,8 @@ const ojForUserReducer = (state = initialState, action) => {
}
return {
...state,
- recordDetail: tempDetail
+ recordDetail: tempDetail,
+ editor_code: tempDetail['code']
}
case types.RESTORE_INITIAL_CODE:
const curHack = state.hack;