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

newyslclassrooms
anke1460 5 years ago
commit 65761f15f5

@ -159,11 +159,12 @@ class ChallengesController < ApplicationController
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
#@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)
#@challenges = @shixun.challenges.fields_for_list
@editable = @shixun.status == 0 # before_action有判断权限如果没发布则肯定是管理人员
@user = current_user
@shixun.increment!(:visits)

@ -8,7 +8,8 @@ class CourseVideosController < ApplicationController
def create
title = params[:name].strip
link = params[:link].strip
@course.course_videos.create!(title: title, link: link, is_link: 1, user_id: current_user.id)
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

@ -137,7 +137,7 @@ class CoursesController < ApplicationController
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])
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, "操作成功")

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

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

@ -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?
@ -62,11 +63,11 @@ class Weapps::AttendancesController < ApplicationController
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
# 当前签到如果存在快捷签到,则直接签到(不在这里处理)
# 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_attendances.present? ? @current_attendances.pluck(:id) : []

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

@ -70,6 +70,8 @@ module ApplicationHelper
# shixun开启挑战对应的行为名及url
def task_operation_url current_myshixun, shixun
return ["开启挑战", "/shixuns/#{shixun.identifier}/shixun_exec"] unless current_user.logged?
if current_myshixun.blank?
name = shixun.status == 0 ? "模拟实战" : "开启挑战"
url = "/shixuns/#{shixun.identifier}/shixun_exec"

@ -79,20 +79,34 @@ class Challenge < ApplicationRecord
end
end
# # 开启挑战
# def open_game(user_id, shixun)
#
#
# game = self.games.select([:status, :identifier]).where(user_id: user_id).first
# game = self.games.select{|game| game.user_id == user_id}
# def open_game shixun, user_id
# game = self.games.map{|g| g.user_id == user_id}.first
# if game.present?
# shixun.task_pass || game.status != 3 ? "/tasks/#{game.identifier}" : ""
# else
# "/api/shixuns/#{shixun.identifier}/shixun_exec"
# self.position == 1 ? "/api/shixuns/#{shixun.identifier}/shixun_exec" : ""
# end
# end
## 用户关卡状态 0: 不能开启实训; 1:直接开启; 2表示已完成
# def user_tpi_status shixun, user_id
# # todo: 以前没加索引导致相同关卡,同一用户有多个games
# # 允许跳关则直接开启
# game = games.where(user_id: user_id).take
# if game.blank?
# position == 1 ? 1 : 0
# else
# if game.status == 3
# shixun.task_pass ? 1 : 0
# elsif game.status == 2
# 2
# else
# 1
# end
# end
# end
# ## 用户关卡状态 0: 不能开启实训; 1:直接开启; 2表示已完成
def user_tpi_status shixun
# todo: 以前没加索引导致相同关卡,同一用户有多个games
# 允许跳关则直接开启
@ -128,12 +142,14 @@ class Challenge < ApplicationRecord
# 关卡用户通关数
def user_passed_count
games.where(status: 2).count
#games.map{|g| g.status == 2}.count
self.games.where(status: 1).count
end
# 关卡用户正在挑战的人数
def playing_count
games.where(status: [0, 1]).count
#games.map{|g| g.status == 0 || g.status == 1}.count
self.games.where(status: [0,1]).count
end
def last_challenge

@ -3,5 +3,6 @@ class CourseVideo < ApplicationRecord
belongs_to :video, optional: true
belongs_to :user, optional: true
validates :title, length: { maximum: 60, too_long: "不能超过60个字符" }
validates :title, length: { maximum: 60, too_long: "不能超过60个字符" }, allow_blank: true
validates :link, format: { with: CustomRegexp::URL, message: "必须为网址超链接" }, allow_blank: true
end

@ -210,8 +210,9 @@ class Shixun < ApplicationRecord
end
# 当前用户开启的实训
def current_myshixun(user_id)
myshixuns.find_by(user_id: user_id)
def current_myshixun(user)
return nil unless user.logged?
myshixuns.find_by(user_id: user.id)
end
# 实训技术平台
@ -264,7 +265,7 @@ class Shixun < ApplicationRecord
# 实训关卡的总分(由于大部分是实践题,因此没关联查choose表)
# 提前加载问题由于选择题比较少所以几乎不会触发选择题的查询所以没必要提前载入choose_score
def all_score
self.challenges.pluck(:score).sum
self.challenges.sum(:score)
end
### fork 数量

@ -339,7 +339,7 @@ class User < ApplicationRecord
# 实训管理员实训合作者、admin
def manager_of_shixun?(shixun)
logger.info("############id: #{id}")
shixun.shixun_members.exists?(role: [1,2], user_id: id) || admin? || business?
shixun.shixun_members.exists?(user_id: id, role: [1,2]) || admin? || business?
end
# 实训管理员

@ -49,7 +49,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

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

@ -16,12 +16,14 @@ if @challenges.present?
json.st challenge.st
json.name challenge.subject
json.score challenge.score
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.passed_count @pass_games_map.fetch(challenge.id, 0)
user_passed_count = challenge.user_passed_count
json.passed_count user_passed_count
#json.playing_count @play_games_map.fetch(challenge.id, 0)
json.playing_count (challenge.games.count - user_passed_count)
json.name_url shixun_challenge_path(challenge, shixun_identifier: @shixun.identifier)
json.open_game challenge.open_game(@shixun)
#json.open_game challenge.open_game(@shixun, @user.id)
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)
@ -29,6 +31,7 @@ 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(@shixun, @user.id)
json.status challenge.user_tpi_status(@shixun)
end
end

@ -14,7 +14,7 @@ json.name shixun.name
json.stu_num shixun.myshixuns_count
json.experience shixun.all_score
json.diffcult level_to_s(shixun.trainee)
json.score_info shixun.shixun_preference_info # todo: 这块可以改成只显示实训的平均分,不用每次都去取每种星的分数了。
json.score_info shixun.averge_star # todo: 这块可以改成只显示实训的平均分,不用每次都去取每种星的分数了。
json.is_jupyter shixun.is_jupyter
# 用于是否显示导航栏中的'背景知识'
json.propaedeutics shixun.propaedeutics.present?

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

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

@ -0,0 +1,5 @@
class AddLinkToAttachments < ActiveRecord::Migration[5.2]
def change
add_column :attachments, :link, :string
end
end

@ -30,6 +30,54 @@
<div class="content unicode" style="display: block;">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont">&#xe734;</span>
<div class="name">移动</div>
<div class="code-name">&amp;#xe734;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe732;</span>
<div class="name">下移2</div>
<div class="code-name">&amp;#xe732;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe731;</span>
<div class="name">上移2</div>
<div class="code-name">&amp;#xe731;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe730;</span>
<div class="name">下移</div>
<div class="code-name">&amp;#xe730;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe72f;</span>
<div class="name">上移</div>
<div class="code-name">&amp;#xe72f;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe72e;</span>
<div class="name">编辑</div>
<div class="code-name">&amp;#xe72e;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe72d;</span>
<div class="name">删除</div>
<div class="code-name">&amp;#xe72d;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe72c;</span>
<div class="name">选择</div>
<div class="code-name">&amp;#xe72c;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe72a;</span>
<div class="name">编辑</div>
@ -2012,6 +2060,78 @@
<div class="content font-class">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont icon-yidong"></span>
<div class="name">
移动
</div>
<div class="code-name">.icon-yidong
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-xiayi1"></span>
<div class="name">
下移2
</div>
<div class="code-name">.icon-xiayi1
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-shangyi1"></span>
<div class="name">
上移2
</div>
<div class="code-name">.icon-shangyi1
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-xiayi"></span>
<div class="name">
下移
</div>
<div class="code-name">.icon-xiayi
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-shangyi"></span>
<div class="name">
上移
</div>
<div class="code-name">.icon-shangyi
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-bianji5"></span>
<div class="name">
编辑
</div>
<div class="code-name">.icon-bianji5
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-shanchu3"></span>
<div class="name">
删除
</div>
<div class="code-name">.icon-shanchu3
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-xuanze"></span>
<div class="name">
选择
</div>
<div class="code-name">.icon-xuanze
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-bianji4"></span>
<div class="name">
@ -4939,6 +5059,70 @@
<div class="content symbol">
<ul class="icon_lists dib-box">
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-yidong"></use>
</svg>
<div class="name">移动</div>
<div class="code-name">#icon-yidong</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-xiayi1"></use>
</svg>
<div class="name">下移2</div>
<div class="code-name">#icon-xiayi1</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-shangyi1"></use>
</svg>
<div class="name">上移2</div>
<div class="code-name">#icon-shangyi1</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-xiayi"></use>
</svg>
<div class="name">下移</div>
<div class="code-name">#icon-xiayi</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-shangyi"></use>
</svg>
<div class="name">上移</div>
<div class="code-name">#icon-shangyi</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-bianji5"></use>
</svg>
<div class="name">编辑</div>
<div class="code-name">#icon-bianji5</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-shanchu3"></use>
</svg>
<div class="name">删除</div>
<div class="code-name">#icon-shanchu3</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-xuanze"></use>
</svg>
<div class="name">选择</div>
<div class="code-name">#icon-xuanze</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-bianji4"></use>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -5,6 +5,62 @@
"css_prefix_text": "icon-",
"description": "",
"glyphs": [
{
"icon_id": "13353315",
"name": "移动",
"font_class": "yidong",
"unicode": "e734",
"unicode_decimal": 59188
},
{
"icon_id": "13247262",
"name": "下移2",
"font_class": "xiayi1",
"unicode": "e732",
"unicode_decimal": 59186
},
{
"icon_id": "13247261",
"name": "上移2",
"font_class": "shangyi1",
"unicode": "e731",
"unicode_decimal": 59185
},
{
"icon_id": "13247178",
"name": "下移",
"font_class": "xiayi",
"unicode": "e730",
"unicode_decimal": 59184
},
{
"icon_id": "13247175",
"name": "上移",
"font_class": "shangyi",
"unicode": "e72f",
"unicode_decimal": 59183
},
{
"icon_id": "13247173",
"name": "编辑",
"font_class": "bianji5",
"unicode": "e72e",
"unicode_decimal": 59182
},
{
"icon_id": "13247168",
"name": "删除",
"font_class": "shanchu3",
"unicode": "e72d",
"unicode_decimal": 59181
},
{
"icon_id": "13183780",
"name": "选择",
"font_class": "xuanze",
"unicode": "e72c",
"unicode_decimal": 59180
},
{
"icon_id": "2077714",
"name": "编辑",

@ -20,6 +20,30 @@ Created by iconfont
/>
<missing-glyph />
<glyph glyph-name="yidong" unicode="&#59188;" d="M855.341176-121.976471H174.682353c-90.352941 0-156.611765 72.282353-156.611765 156.611765V721.317647C18.070588 811.670588 90.352941 877.929412 174.682353 877.929412h680.658823c90.352941 0 156.611765-72.282353 156.611765-156.611765v-78.305882h-90.352941V721.317647c0 36.141176-30.117647 66.258824-66.258824 66.258824H174.682353c-36.141176 0-66.258824-30.117647-66.258824-66.258824v-680.658823c0-36.141176 30.117647-66.258824 66.258824-66.258824h680.658823c36.141176 0 66.258824 30.117647 66.258824 66.258824v78.305882h90.352941v-78.305882c6.023529-90.352941-66.258824-162.635294-156.611765-162.635295zM951.717647 299.670588H271.058824c-24.094118 0-48.188235 18.070588-48.188236 48.188236s18.070588 48.188235 48.188236 48.188235h680.658823c24.094118 0 48.188235-18.070588 48.188235-48.188235s-24.094118-48.188235-48.188235-48.188236zM1084.235294 347.858824L921.6 173.176471V534.588235L1084.235294 359.905882v-12.047058z" horiz-adv-x="1084" />
<glyph glyph-name="xiayi1" unicode="&#59186;" d="M512 384m-481.882353 0a481.882353 481.882353 0 1 1 963.764706 0 481.882353 481.882353 0 1 1-963.764706 0ZM512-128C228.894118-128 0 100.894118 0 384S228.894118 896 512 896 1024 667.105882 1024 384 795.105882-128 512-128z m0 963.764706C265.035294 835.764706 60.235294 630.964706 60.235294 384S265.035294-67.764706 512-67.764706 963.764706 137.035294 963.764706 384 758.964706 835.764706 512 835.764706zM502.964706 143.058824c-18.070588 0-30.117647 12.047059-30.117647 30.117647V588.8c0 18.070588 12.047059 30.117647 30.117647 30.117647s30.117647-12.047059 30.117647-30.117647V173.176471c0-18.070588-12.047059-30.117647-30.117647-30.117647zM502.964706 88.847059c-6.023529 0-12.047059 0-18.070588 6.023529l-144.564706 132.517647c-12.047059 12.047059-12.047059 30.117647 0 42.164706 12.047059 12.047059 30.117647 12.047059 42.164706 0l126.494117-108.423529 132.517647 108.423529c12.047059 12.047059 30.117647 12.047059 42.164706-6.023529 6.023529-6.023529 6.023529-30.117647-12.047059-36.141177l-150.588235-132.517647c-6.023529 0-12.047059-6.023529-18.070588-6.023529z" horiz-adv-x="1024" />
<glyph glyph-name="shangyi1" unicode="&#59185;" d="M512 384m-481.882353 0a481.882353 481.882353 0 1 1 963.764706 0 481.882353 481.882353 0 1 1-963.764706 0ZM512-128C228.894118-128 0 100.894118 0 384S228.894118 896 512 896 1024 667.105882 1024 384 795.105882-128 512-128z m0 963.764706C265.035294 835.764706 60.235294 630.964706 60.235294 384S265.035294-67.764706 512-67.764706 963.764706 137.035294 963.764706 384 758.964706 835.764706 512 835.764706zM502.964706 106.917647c-18.070588 0-30.117647 12.047059-30.117647 30.117647V552.658824c0 18.070588 12.047059 30.117647 30.117647 30.117647s30.117647-12.047059 30.117647-30.117647v-415.62353c0-18.070588-12.047059-30.117647-30.117647-30.117647zM653.552941 444.235294c-6.023529 0-12.047059 0-18.070588 6.02353l-132.517647 114.447058-126.494118-108.423529c-12.047059-12.047059-30.117647-12.047059-42.164706 0-12.047059 12.047059-12.047059 30.117647 0 42.164706l144.564706 126.494117c12.047059 12.047059 30.117647 12.047059 42.164706 0l150.588235-126.494117c12.047059-12.047059 12.047059-30.117647 6.02353-42.164706-6.023529-6.023529-12.047059-12.047059-24.094118-12.047059z" horiz-adv-x="1024" />
<glyph glyph-name="xiayi" unicode="&#59184;" d="M512 384m-481.882353 0a481.882353 481.882353 0 1 1 963.764706 0 481.882353 481.882353 0 1 1-963.764706 0ZM512-128C228.894118-128 0 100.894118 0 384S228.894118 896 512 896 1024 667.105882 1024 384 795.105882-128 512-128z m0 963.764706C265.035294 835.764706 60.235294 630.964706 60.235294 384S265.035294-67.764706 512-67.764706 963.764706 137.035294 963.764706 384 758.964706 835.764706 512 835.764706zM502.964706 143.058824c-18.070588 0-30.117647 12.047059-30.117647 30.117647V588.8c0 18.070588 12.047059 30.117647 30.117647 30.117647s30.117647-12.047059 30.117647-30.117647V173.176471c0-18.070588-12.047059-30.117647-30.117647-30.117647zM502.964706 88.847059c-6.023529 0-12.047059 0-18.070588 6.023529l-144.564706 132.517647c-12.047059 12.047059-12.047059 30.117647 0 42.164706 12.047059 12.047059 30.117647 12.047059 42.164706 0l126.494117-108.423529 132.517647 108.423529c12.047059 12.047059 30.117647 12.047059 42.164706-6.023529 6.023529-6.023529 6.023529-30.117647-12.047059-36.141177l-150.588235-132.517647c-6.023529 0-12.047059-6.023529-18.070588-6.023529z" horiz-adv-x="1024" />
<glyph glyph-name="shangyi" unicode="&#59183;" d="M512 384m-481.882353 0a481.882353 481.882353 0 1 1 963.764706 0 481.882353 481.882353 0 1 1-963.764706 0ZM512-128C228.894118-128 0 100.894118 0 384S228.894118 896 512 896 1024 667.105882 1024 384 795.105882-128 512-128z m0 963.764706C265.035294 835.764706 60.235294 630.964706 60.235294 384S265.035294-67.764706 512-67.764706 963.764706 137.035294 963.764706 384 758.964706 835.764706 512 835.764706zM502.964706 106.917647c-18.070588 0-30.117647 12.047059-30.117647 30.117647V552.658824c0 18.070588 12.047059 30.117647 30.117647 30.117647s30.117647-12.047059 30.117647-30.117647v-415.62353c0-18.070588-12.047059-30.117647-30.117647-30.117647zM653.552941 444.235294c-6.023529 0-12.047059 0-18.070588 6.02353l-132.517647 114.447058-126.494118-108.423529c-12.047059-12.047059-30.117647-12.047059-42.164706 0-12.047059 12.047059-12.047059 30.117647 0 42.164706l144.564706 126.494117c12.047059 12.047059 30.117647 12.047059 42.164706 0l150.588235-126.494117c12.047059-12.047059 12.047059-30.117647 6.02353-42.164706-6.023529-6.023529-12.047059-12.047059-24.094118-12.047059z" horiz-adv-x="1024" />
<glyph glyph-name="bianji5" unicode="&#59182;" d="M704.752941-97.882353H198.776471c-78.305882 0-138.541176 60.235294-138.541177 132.517647V667.105882c0 72.282353 66.258824 132.517647 138.541177 132.517647h319.247058c18.070588 0 30.117647-12.047059 30.117647-30.117647s-12.047059-24.094118-30.117647-24.094117H198.776471c-42.164706 0-78.305882-36.141176-78.305883-72.282353v-632.470588c0-42.164706 36.141176-72.282353 78.305883-72.282353h499.952941c42.164706 0 78.305882 36.141176 78.305882 72.282353V293.647059c0 18.070588 12.047059 30.117647 30.117647 30.117647s30.117647-12.047059 30.117647-30.117647v-259.011765c6.023529-72.282353-60.235294-132.517647-132.517647-132.517647zM313.223529 161.129412c-24.094118 0-54.211765 18.070588-60.235294 48.188235v30.117647l36.141177 126.494118 445.741176 445.741176c48.188235 48.188235 120.470588 48.188235 168.658824 0 48.188235-48.188235 48.188235-120.470588 0-168.658823l-445.741177-445.741177-126.494117-30.117647c-6.023529-6.023529-12.047059-6.023529-18.070589-6.023529z m36.141177 174.682353l-36.141177-114.447059 120.470589 30.117647 433.694117 433.694118c12.047059 12.047059 18.070588 24.094118 18.070589 42.164705 0 18.070588-6.023529 30.117647-18.070589 42.164706-24.094118 24.094118-60.235294 24.094118-84.329411 0L349.364706 335.811765z" horiz-adv-x="1024" />
<glyph glyph-name="shanchu3" unicode="&#59181;" d="M654.222222-99.555556H375.466667c-68.266667 0-125.155556 56.888889-136.533334 142.222223L142.222222 571.733333c0 17.066667 5.688889 28.444444 22.755556 34.133334 17.066667 0 28.444444-5.688889 34.133333-22.755556l91.022222-534.755555c11.377778-51.2 45.511111-91.022222 85.333334-91.022223h278.755555c39.822222 0 73.955556 39.822222 85.333334 91.022223l91.022222 534.755555c0 17.066667 17.066667 28.444444 34.133333 22.755556 17.066667 0 28.444444-17.066667 22.755556-34.133334L796.444444 42.666667c-17.066667-85.333333-73.955556-142.222222-142.222222-142.222223zM597.333333 708.266667v5.688889c0 51.2-39.822222 96.711111-85.333333 96.711111s-85.333333-45.511111-85.333333-102.4h-56.888889C369.777778 793.6 432.355556 867.555556 512 867.555556c73.955556 0 136.533333-68.266667 142.222222-147.911112v-5.688888l-56.888889-5.688889zM398.222222 36.977778c-11.377778 0-28.444444 11.377778-28.444444 22.755555L284.444444 577.422222c0 17.066667 11.377778 34.133333 22.755556 34.133334 17.066667 5.688889 34.133333-5.688889 34.133333-22.755556l85.333334-517.688889c0-17.066667-5.688889-34.133333-28.444445-34.133333 5.688889 0 0 0 0 0zM625.777778 36.977778s-5.688889 0 0 0c-22.755556 5.688889-28.444444 17.066667-28.444445 34.133333L682.666667 588.8c0 17.066667 17.066667 28.444444 34.133333 22.755556 11.377778 0 22.755556-17.066667 22.755556-34.133334l-85.333334-517.688889c0-11.377778-17.066667-22.755556-28.444444-22.755555zM512 36.977778c-17.066667 0-28.444444 11.377778-28.444444 28.444444V583.111111c0 17.066667 11.377778 28.444444 28.444444 28.444445s28.444444-11.377778 28.444444-28.444445v-517.688889c0-17.066667-11.377778-28.444444-28.444444-28.444444zM938.666667 645.688889H85.333333c-17.066667 0-28.444444 17.066667-28.444444 28.444444s11.377778 28.444444 28.444444 28.444445h853.333334c17.066667 0 28.444444-11.377778 28.444444-28.444445s-11.377778-28.444444-28.444444-28.444444z" horiz-adv-x="1024" />
<glyph glyph-name="xuanze" unicode="&#59180;" d="M870.4 896H153.6C66.56 896 0 829.44 0 742.4v-716.8c0-87.04 66.56-153.6 153.6-153.6h716.8c87.04 0 153.6 66.56 153.6 153.6V742.4c0 87.04-66.56 153.6-153.6 153.6z m-40.96-394.24l-337.92-358.4c-10.24-10.24-25.6-15.36-40.96-15.36-10.24 0-20.48 5.12-30.72 10.24L174.08 332.8c-20.48 15.36-25.6 51.2-10.24 71.68 15.36 20.48 51.2 25.6 71.68 10.24l209.92-163.84 307.2 327.68c20.48 20.48 51.2 20.48 71.68 0 20.48-20.48 25.6-56.32 5.12-76.8z" horiz-adv-x="1024" />
<glyph glyph-name="bianji4" unicode="&#59178;" d="M934.724189 617.173271L834.414864 516.863946 653.380212 697.898598l100.394659 100.351991A42.257063 42.257063 0 0 0 783.769535 810.666588c6.527999 0 19.157332-1.621333 29.951997-12.415999l121.002657-121.002656a42.538663 42.538663 0 0 0 0-60.074662zM299.374908-18.176009l-200.661316-19.626665 19.669331 200.661316L593.049551 637.52527 774.084202 456.533285l-474.709294-474.709294z m695.679942 755.79727L874.09486 858.581251A127.317323 127.317323 0 0 1 783.769535 895.999915c-32.725331 0-65.407995-12.458666-90.367993-37.418664l-646.229279-646.229279c-7.082666-7.082666-11.434666-16.469332-12.287999-26.495998l-26.197331-267.818645c-2.133333-25.002665 17.706665-46.037329 42.239996-46.037329 1.194667 0 2.432 0.042667 3.626666 0.128l267.818645 26.239998a42.12053 42.12053 0 0 1 26.495998 12.287999l646.186612 646.186613c49.919996 49.919996 49.919996 130.858656 0 180.778651z" horiz-adv-x="1032" />

Before

Width:  |  Height:  |  Size: 394 KiB

After

Width:  |  Height:  |  Size: 404 KiB

@ -10,11 +10,9 @@ import './index.scss';
import React, { useState } from 'react';
import { Form, Button, Input } from 'antd';
import QuillForEditor from '../../quillForEditor';
// import { QuillDeltaToHtmlConverter } from 'quill-delta-to-html'
// import {formatDelta} from './util';
const FormItem = Form.Item;
function CommentForm (props) {
function CommentForm(props) {
const {
onCancel,
@ -28,9 +26,6 @@ function CommentForm (props) {
const [focus, setFocus] = useState(false);
const options = [
// ['bold', 'italic', 'underline'],
// [{header: [1,2,3,false]}],
'code-block',
'link',
'image',
'formula'
@ -52,12 +47,10 @@ function CommentForm (props) {
// 编辑器内容变化时
const handleContentChange = (content) => {
console.log('编辑器内容', content);
setCtx(content);
try {
// const _html = new QuillDeltaToHtmlConverter(content.ops, {}).convert();
// props.form.setFieldsValue({'comment': _html.replace(/<\/?[^>]*>/g, '')});
props.form.setFieldsValue({'comment': content});
props.form.setFieldsValue({ 'comment': content });
} catch (error) {
console.log(error);
}
@ -69,7 +62,7 @@ function CommentForm (props) {
if (!err) {
setShowQuill(false);
const content = ctx;
props.form.setFieldsValue({'comment': ''});
props.form.setFieldsValue({ 'comment': '' });
setCtx('');
// const _html = formatDelta(content.ops);
// console.log('保存的内容=====》》》》', content);
@ -95,7 +88,7 @@ function CommentForm (props) {
{
getFieldDecorator('comment', {
rules: [
{ required: true, message: '评论内容不能为空'}
{ required: true, message: '评论内容不能为空' }
],
})(
<Input
@ -112,7 +105,7 @@ function CommentForm (props) {
}
<QuillForEditor
imgAttrs={{width: '60px', height: '30px'}}
imgAttrs={{ width: '60px', height: '30px' }}
wrapStyle={{
height: showQuill ? 'auto' : '0px',
opacity: showQuill ? 1 : 0,
@ -130,7 +123,7 @@ function CommentForm (props) {
</FormItem>
<FormItem style={{ textAlign: 'right', display: showQuill ? 'block' : 'none' }}>
<Button onClick={handleCancle}>取消</Button>
<Button onClick={handleSubmit} type="primary" style={{ marginLeft: '10px'}}>发送</Button>
<Button onClick={handleSubmit} type="primary" style={{ marginLeft: '10px' }}>发送</Button>
</FormItem>
</Form>
);

@ -237,7 +237,6 @@ function CommentItem({
/>
</div>
{/* 显示上传的图片信息 */}
<div className="show_upload_image" style={{ display: url ? 'block' : 'none' }}>
<Icon type="close" className="image_close" onClick={handleClose} />
<div className="image_info">

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

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

@ -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 (
<div className='quill_editor_for_react_area' style={wrapStyle}>
<div ref={editorRef} style={style}></div>
</div>
<div className='quill_editor_for_react_area' style={wrapStyle}>
<div ref={editorRef} style={style}></div>
</div>
);
}

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

@ -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{
}
></Route>
{/*视频列表*/}
<Route path="/courses/:coursesId/course_video/:videoId"
render={
(props) => (<ListPageIndex {...this.props} {...props} {...this.state} />)
}
></Route>
<Route path="/courses/:coursesId/course_videos"
render={
(props) => (<ListPageIndex {...this.props} {...props} {...this.state} />)
}
></Route>
></Route>
{/* 资源列表页 */}
<Route path="/courses/:coursesId/file/:Id" exact
render={
@ -960,4 +964,4 @@ class CoursesIndex extends Component{
}
}
export default withRouter(ImageLayerOfCommentHOC({imgSelector: '.imageLayerParent img, .imageLayerParent .imageTarget', parentSelector: '.newMain'}) (CNotificationHOC() ( SnackbarHOC() ( TPMIndexHOC(CoursesIndex) ))));
export default withRouter(ImageLayerOfCommentHOC({imgSelector: '.imageLayerParent img, .imageLayerParent .imageTarget', parentSelector: '.newMain'}) (CNotificationHOC() ( SnackbarHOC() ( TPMIndexHOC(CoursesIndex) ))));

@ -244,7 +244,11 @@ class ListPageIndex extends Component{
}
></Route>
{/*视频列表*/}
<Route path="/courses/:coursesId/course_video/:videoId"
render={
(props) => (<CourseVideo {...this.props} {...props} {...this.state} />)
}
></Route>
<Route path="/courses/:coursesId/course_videos"
render={
(props) => (<CourseVideo {...this.props} {...props} {...this.state} />)

@ -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 (
<div className="graduateTopicList boardsList">
{/*提示*/}
{this.state.Modalstype&&this.state.Modalstype===true?<Modals
{this.state.Modalstype && this.state.Modalstype === true ? <Modals
modalsType={this.state.Modalstype}
modalsTopval={this.state.Modalstopval}
modalCancel={this.state.ModalCancel}
modalSave={this.state.ModalSave}
modalsBottomval={this.state.ModalsBottomval}
loadtype={this.state.Loadtype}
/>:""}
/> : ""}
<Showoldfiles
{...this.props}
visible={this.state.Showoldfiles}
@ -213,67 +232,132 @@ class Fileslistitem extends Component{
margin-top:2px;
}
`}</style>
<div className="clearfix ds pr contentSection" style={{cursor : this.props.isAdmin ? "pointer" : "default"}} onClick={() => window.$(`.sourceitem${index} input`).click() }>
<h6 onClick={(event)=>this.eventStop(event)}>
<div className="clearfix ds pr contentSection" style={{cursor: this.props.isAdmin ? "pointer" : "default"}}
onClick={() => window.$(`.sourceitem${index} input`).click()}>
<h6 onClick={(event) => this.eventStop(event)}>
<span className={`sourceitem${index} fl mr12 mt3`}>
{checkBox}
</span>
{
this.props.isAdmin ? <a
// href={"/courses/" + coursesId + "/graduation/graduation_tasks/" + categoryid + "/" + taskid + "/list"}
onClick={()=>this.showfiles(discussMessage)}
title={discussMessage.title}
className="fl mt3 font-16 font-bd color-dark maxwidth580">{discussMessage.title}</a> : ""
this.props.isAdmin ?
(bools === true ?
<a
// href={"/courses/" + coursesId + "/graduation/graduation_tasks/" + categoryid + "/" + taskid + "/list"}
onClick={() => this.showfiles(discussMessage)}
title={discussMessage.title}
className="fl mt3 font-16 font-bd color-dark maxwidth580">{discussMessage.title}</a>
:
<a
// href={"/courses/" + coursesId + "/graduation/graduation_tasks/" + categoryid + "/" + taskid + "/list"}
onClick={() => this.showfiless(discussMessage.link,discussMessage.id)}
title={discussMessage.title}
className="fl mt3 font-16 font-bd color-dark maxwidth580">{discussMessage.title}</a>
)
: ""
}
{
this.props.isStudent? <a
onClick={()=>this.showfiles(discussMessage)}
title={discussMessage.title}
className="fl mt3 font-16 font-bd color-dark maxwidth580">{discussMessage.title}</a> :""
this.props.isStudent ?
(bools === true ?
<a
onClick={() => this.showfiles(discussMessage)}
title={discussMessage.title}
className="fl mt3 font-16 font-bd color-dark maxwidth580">{discussMessage.title}</a>
:
<a
onClick={() => this.showfiless(discussMessage.link,discussMessage.id)}
title={discussMessage.title}
className="fl mt3 font-16 font-bd color-dark maxwidth580">{discussMessage.title}</a>
)
: ""
}
{
this.props.isNotMember===true?
this.props.isNotMember === true ?
discussMessage.is_lock === true ?
<span className="fl mt3 font-16 font-bd color-dark maxwidth580 pointer" title={"私有属性,非课堂成员不能访问"}>{discussMessage.title}</span>
:<a
onClick={()=>this.showfiles(discussMessage)}
title={discussMessage.title}
className="fl mt3 font-16 font-bd color-dark maxwidth580">{discussMessage.title}</a>:""
<span className="fl mt3 font-16 font-bd color-dark maxwidth580 pointer"
title={"私有属性,非课堂成员不能访问"}>{discussMessage.title}</span>
:
(bools === true ?
<a
onClick={() => this.showfiles(discussMessage)}
title={discussMessage.title}
className="fl mt3 font-16 font-bd color-dark maxwidth580">{discussMessage.title}</a> :
<a
onClick={() =>this.showfiless(discussMessage.link,discussMessage.id)}
title={discussMessage.title}
className="fl mt3 font-16 font-bd color-dark maxwidth580">{discussMessage.title}</a>
)
: ""
}
{
discussMessage.is_lock === true ?
<Tooltip title={"私有属性,非课堂成员不能访问"} placement="bottom">
<Tooltip title={"私有属性,非课堂成员不能访问"} placement="bottom">
<i className="iconfont icon-guansuo color-grey-c ml10 font-16 fl mt4"></i>
</Tooltip>
:""
: ""
}
<style>
{
`
.fwlz{
width:40px;
height:20px;
border-radius:2px;
border:1px solid rgba(250,100,0,1);
font-size:12px;
font-family:MicrosoftYaHei;
color:rgba(250,100,0,1);
text-align: center;
margin-left: 15px;
}
`
}
</style>
{
discussMessage.link && discussMessage.link ?
<p className="fl mt3 fwlz " style={{
cursor:"auto"
}}>外链</p>
:
""
}
{discussMessage.is_publish===false?<CoursesListType typelist={["未发布"]} typesylename={""}/>:""}
{this.props.isAdmin?
<span className={"fr mt2"} onClick={(event)=>this.eventStop(event)}>
{discussMessage.is_publish === false ? <CoursesListType typelist={["未发布"]} typesylename={""}/> : ""}
{this.props.isAdmin ?
<span className={"fr mt2"} onClick={(event) => this.eventStop(event)}>
<WordsBtn style="blue" className="colorblue font-16 ml20 fr">
<a className="btn colorblue fontweight400"
onClick={()=>this.settingList()}>设置</a>
onClick={() => this.settingList(bools)}>设置</a>
</WordsBtn>
</span>:""}
</span> : ""}
{this.props.isStudent===true&&this.props.current_user.login===discussMessage.author.login?
<span className={"fr mt2"} onClick={(event)=>this.eventStop(event)}>
{this.props.isStudent === true && this.props.current_user.login === discussMessage.author.login ?
<span className={"fr mt2"} onClick={(event) => this.eventStop(event)}>
<WordsBtn style="blue" className="colorblue font-16 ml20 fr">
<a className="btn colorblue fontweight400"
onClick={()=>this.settingList()}>设置</a>
onClick={() => this.settingList(bools)}>设置</a>
</WordsBtn>
<WordsBtn style="blue" className="colorblue font-16 ml20 fr">
<a className="btn colorblue fontweight400"
onClick={()=>this.onDelete(discussMessage.id)}>删除</a>
onClick={() => this.onDelete(discussMessage.id)}>删除</a>
</WordsBtn>
</span>:""}
</span> : ""}
</h6>
<style>
{
@ -288,7 +372,6 @@ class Fileslistitem extends Component{
</style>
<style>
{
`
@ -315,28 +398,45 @@ class Fileslistitem extends Component{
{/*</p>}*/}
<p className={this.props.isAdmin===true?"color-grey panel-lightgrey mt8 fl ml30":"color-grey panel-lightgrey mt8 fl ml13"} style={{width:'100%'}}>
<p
className={this.props.isAdmin === true ? "color-grey panel-lightgrey mt8 fl ml30" : "color-grey panel-lightgrey mt8 fl ml13"}
style={{width: '100%'}}>
<span className="mr50">
<span className="mr15 color-dark">{discussMessage.author.name}</span>
<span className="mr15 color-grey9">大小 {discussMessage.filesize}</span>
<span className="mr15 color-grey9">下载 {discussMessage.downloads_count}</span>
{
bools ?
<span className="mr15 color-grey9">大小 {discussMessage.filesize}</span>
:
""
}
{
bools ?
<span className="mr15 color-grey9">下载 {discussMessage.downloads_count}</span>
:
<span className="mr15 color-grey9">点击次数{discussMessage.downloads_count}</span>
}
{/*<span className="mr15 color-grey9">引用 {discussMessage.quotes}</span>*/}
<span className="mr15 color-grey-c">
{/*{moment(discussMessage.publish_time).format('YYYY-MM-DD HH:mm:ss')}*/}
{/*{moment(discussMessage.publish_time).fromNow()}*/}
{ discussMessage.publish_time===null?"":
discussMessage.is_publish===true?"":"发布于"}
{ discussMessage.publish_time===null?"":discussMessage.is_publish===true?moment(discussMessage.publish_time).fromNow():moment(discussMessage.publish_time).format('YYYY-MM-DD HH:mm')}
{discussMessage.publish_time === null ? "" :
discussMessage.is_publish === true ? "" : "发布于"}
{discussMessage.publish_time === null ? "" : discussMessage.is_publish === true ? moment(discussMessage.publish_time).fromNow() : moment(discussMessage.publish_time).format('YYYY-MM-DD HH:mm')}
</span>
</span>
{discussMessage&&discussMessage.category_name===null?"":this.props.child===false?<div className="color-grey9 task-hide fr mr30" title={discussMessage&&discussMessage.category_name}
style={{"max-width":"268px"}}>所属目录{discussMessage&&discussMessage.category_name}
</div>:""}
{discussMessage && discussMessage.category_name === null ? "" : this.props.child === false ?
<div className="color-grey9 task-hide fr mr30" title={discussMessage && discussMessage.category_name}
style={{"max-width": "268px"}}>所属目录{discussMessage && discussMessage.category_name}
</div> : ""}
</p>
<p className={this.props.isAdmin===true?"color-grey panel-lightgrey mt8 fl ml30":"color-grey panel-lightgrey mt8 fl ml13"} style={{width:'94%'}}>
<p
className={this.props.isAdmin === true ? "color-grey panel-lightgrey mt8 fl ml30" : "color-grey panel-lightgrey mt8 fl ml13"}
style={{width: '94%'}}>
<style>
{
`
@ -349,7 +449,8 @@ class Fileslistitem extends Component{
`
}
</style>
<span className="color-dark isspans">资源描述 :{discussMessage.description===null?"暂无描述":discussMessage.description}</span>
<span
className="color-dark isspans">资源描述 :{discussMessage.description === null ? "暂无描述" : discussMessage.description}</span>
{/*<span className="mr50">*/}
{/*/!*<span className="mr15 color-dark"></span>*!/*/}
{/*<span className="mr15 color-dark">*/}
@ -365,4 +466,5 @@ class Fileslistitem extends Component{
)
}
}
export default Fileslistitem;

@ -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?<style>
shixunmodal===true||Accessoryvisible===true||Settingtype===true||Addanexternallink===true?<style>
{
`
body {
@ -821,6 +881,25 @@ class Fileslists extends Component{
has_course_groups={this.state.has_course_groups}
attachmentId={this.state.coursesecondcategoryid}
/>:""}
{/*添加外链*/}
{Addanexternallink&&Addanexternallink===true?<SendResources
{...this.props}
{...this.state}
title={title}
link={link}
modalname={Exterchainname}
visible={Addanexternallink}
discussMessageid={discussMessageid}
Cancelname={"取消"}
Savesname={"确认"}
Cancel={()=>this.sendResourcessls(2,false)}
categoryid={category_id}
setupdate={(ints,bool)=>this.sendResourcessls(ints,bool)}
has_course_groups={this.state.has_course_groups}
course_id={this.props.match.params.coursesId}
attachmentId={this.state.coursesecondcategoryid}
/>:""}
{/*设置资源*/}
{Settingtype&&Settingtype===true?<Selectsetting
{...this.props}
@ -858,8 +937,10 @@ class Fileslists extends Component{
{this.props.isAdmin()?parseInt(this.props.match.params.main_id)!=parseInt(this.props.coursesids)?<WordsBtn style="blue" onClick={()=>this.editDir(name)} className={"mr30 font-16"}>目录重命名</WordsBtn>:"":""}
{this.props.isAdmin()||this.props.isStudent() ? this.props.user&&this.props.user.main_site===true? <WordsBtn style="blue" className="mr30 font-16" onClick={()=>this.addResource()}>选用资源</WordsBtn>:"":""}
{this.props.isAdmin()||this.props.isStudent() ? <WordsBtn style="blue" className=" font-16" onClick={()=>this.sendResources()}>上传资源</WordsBtn>:""}
</React.Fragment>
{this.props.isAdmin()||this.props.isStudent() ? <WordsBtn style="blue" className="mr30 font-16" onClick={()=>this.sendResources()}>上传资源</WordsBtn>:""}
{this.props.isAdmin()||this.props.isStudent() ? <WordsBtn style="blue" className=" font-16" onClick={()=>this.sendResourcessls(1,true)}>添加外链</WordsBtn>:""}
</React.Fragment>
}
secondRowLeft={
@ -997,11 +1078,13 @@ class Fileslists extends Component{
{...this.props}
{...this.state}
discussMessage={item}
Updateresourcepage={()=>this.Updateresourcepage()}
isAdmin={this.props.isAdmin()}
isStudent={this.props.isStudent()}
isNotMember={this.props.isNotMember()}
checkBox={this.props.isAdmin()?<Checkbox value={item.id} key={item.id}></Checkbox>:""}
Settingtypes={(id)=>this.Settingtypes(id)}
Settingtypess={(id,t,l)=>this.Settingtypess(id,t,l)}
coursesId={this.props.match.params.coursesId}
updatafiledfun={()=>this.updatafiled()}
index={index}

@ -0,0 +1,128 @@
import React,{ Component } from "react";
import { Radio , Modal } from 'antd';
import './video.css';
import axios from 'axios';
class MoveBox extends Component{
constructor(props){
super(props);
this.state={
data:undefined,
selectSubId:undefined
}
}
componentDidUpdate=(prevProps)=>{
if(this.props.id && this.props.visible && this.props.id !== prevProps.id){
this.getSubList(this.props.mainId);
}
}
getSubList=(id)=>{
const url = `/course_modules/${id}.json`;
axios.get(url).then(result=>{
if(result){
let list = result.data.course_module && result.data.course_module.course_second_categories;
let defaultId = list.length>0 ? list[0].id : undefined;
this.setState({
data:result.data.course_module,
selectSubId:defaultId
})
}
}).catch(error=>{
console.log(error);
})
}
cancelMove=()=>{
const { setMoveVisible } = this.props;
setMoveVisible && setMoveVisible(false);
}
// 选择子目录
selectSub=(e)=>{
this.setState({
selectSubId:e.target.value
})
}
handleSubmit=()=>{
const CourseId = this.props.match.params.coursesId;
const { id } = this.props;
const { selectSubId } = this.state;
const url = `/courses/${CourseId}/move_to_category.json`;
axios.post(url,{
video_ids:[id],
new_category_id:selectSubId
}).then(result=>{
if(result){
const { setMoveVisible , successFunc , updataleftNavfun} = this.props;
updataleftNavfun && updataleftNavfun();
setMoveVisible && setMoveVisible(false);
successFunc && successFunc();
}
}).catch(error=>{
console.log(error);
})
}
render(){
const { visible , id } = this.props;
const { data , selectSubId } = this.state;
let list = data && data.course_second_categories && data.course_second_categories.length>0?data.course_second_categories:undefined;
return(
<Modal
visible={visible}
width="560px"
title={'移动到'}
footer={null}
closable={false}
>
<div>
<style>
{
`
.ant-radio-group.ant-radio-group-outline{
display: flex;
flex-direction: column;
}
.ant-radio-wrapper{
margin-bottom:5px;
display:flex;
}
.ant-radio{
margin-top:2px;
}
.ant-radio-group.ant-radio-group-outline span:last-child{
max-height: 450px;
display: block;
flex: 1;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
`
}
</style>
<Radio.Group onChange={this.selectSub} value={selectSubId}>
{
list && list.map((item,key)=>{
return(
<Radio value={item.id} key={item.id}>
{item.name}
</Radio>
)
})
}
</Radio.Group>
<div className="clearfix mt30 edu-txt-center">
<a onClick={this.cancelMove} className="task-btn mr30">取消</a>
<a type="submit" onClick={this.handleSubmit} className="task-btn task-btn-orange">确定</a>
</div>
</div>
</Modal>
)
}
}
export default MoveBox;

@ -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 (
<div>
<EditVideoModal {...this.props} visible={visible} setVisible={this.setVisible}
editSuccess={this.editSuccess}
{...videoId} CourseUser={login}
></EditVideoModal>
<MoveBox
{...this.props}
visible={moveVisible}
mainId={videoData && videoData.course_module_id}
setMoveVisible={(flag)=>this.setMoveVisible(flag)}
successFunc={()=>uploadVideo()}
id={moveVideoId}
></MoveBox>
<HeadlessModal
visible={videoVisible}
setVisible={this.setVideoVisible}
@ -196,7 +226,7 @@ class Video extends Component {
<div className="videoPanel">
{
upload ?
<VideoUploadList {...this.props} flag={true} CourseId={CourseId} CourseUser={login} successFunc={() => uploadVideo()}></VideoUploadList>
<VideoUploadList {...this.props} flag={true} CourseId={CourseId} videoId={VID} CourseUser={login} successFunc={() => uploadVideo()}></VideoUploadList>
:
<React.Fragment>
{
@ -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}
>
</VideoInReviewItem>
)

@ -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) < 5;
const newOperation = flag;
const new_upload = flag && (is_teacher && this.props.checkIfProfessionalCertification());
return(
<React.Fragment>
<VideoLink
coursesId={coursesId}
videoId={videoId}
visible={otherLinkVisible}
notification={this.props.showNotification}
setVisible={this.setLinkeVisible}
></VideoLink>
<LivesNew
visible={liveVisible}
liveId={liveId}
@ -235,30 +281,49 @@ class VideoIndex extends Component{
<div className="edu-back-white" style={{marginBottom:"1px"}}>
<div className="clearfix pl30 pr30 menuDiv">
<div className="task_menu_ul fl">
<Menu mode="horizontal" selectedKeys={[type]} onClick={this.changeType}>
<Menu.Item key="video">视频</Menu.Item>
<Menu.Item key="live">直播</Menu.Item>
</Menu>
</div>
{
(admin || is_teacher || business) &&
<li className="fr mt18">
{
type === "video" ?
<React.Fragment>
videoData && videoData.category_name && type === "video" ?
<span className="font-18 fl color-dark-21 mt20 mb20">{videoData.category_name}</span>
:
<div className="task_menu_ul fl mt2" style={{width:"400px"}}>
<Menu mode="horizontal" selectedKeys={[type]} onClick={this.changeType}>
<Menu.Item key="video">视频</Menu.Item>
<Menu.Item key="live">直播</Menu.Item>
</Menu>
</div>
}
<li className="fr mt20 mb20">
{
type === "video" ?
<React.Fragment>
{
newOperation ?
<span>
{
upload ?
<WordsBtn style="grey" className="font-16" onClick={()=>this.uploadVideo(false)}>取消</WordsBtn>
videoId ?
<WordsBtn style="blue" onClick={()=>this.editDir(videoData && videoData.category_name,videoId)} className={"mr30 font-16"}>目录重命名</WordsBtn>
:
<WordsBtn style="blue" className="font-16" onClick={this.toUpload}>上传视频</WordsBtn>
<WordsBtn style="blue" className="mr30 font-16" onClick={this.addDir}>新建目录</WordsBtn>
}
</React.Fragment>
:
<WordsBtn style="blue" className="font-16 ml30" onClick={this.liveSetting}>添加直播</WordsBtn>
}
</li>
}
<WordsBtn style="blue" className="mr30 font-16" onClick={()=>this.setLinkeVisible(true)}>增加外链</WordsBtn>
</span>:""
}
{
new_upload ?
<span>
{
upload ?
<WordsBtn style="grey" className="font-16" onClick={()=>this.uploadVideo(false)}>取消</WordsBtn>
:
<WordsBtn style="blue" className="font-16" onClick={this.toUpload}>上传视频</WordsBtn>
}
</span>:""
}
</React.Fragment>
:
<WordsBtn style="blue" className="font-16 ml30" onClick={this.liveSetting}>添加直播</WordsBtn>
}
</li>
</div>
</div>
<Spin spinning={isSpining}>

@ -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(
<Modal
visible={visible}
width="560px"
title={'添加外链'}
footer={null}
closable={false}
centered={true}
>
<div className="task-popup-content">
<Form onSubmit={this.handleSubmit} {...layout}>
<Form.Item label={`视频名称:`}>
{getFieldDecorator('name', {
rules: [{required: true, message: "请输入名称"},{
validator: this.validateDesc,
}],
})(
<Input placeholder="请输入名称最大限制60个字符" />
)}
</Form.Item>
<Form.Item label={`链接地址:`}>
{getFieldDecorator('link', {
rules: [{required: true, message: "请输入链接地址"}],
})(
<Input placeholder="请输入链接地址" />
)}
</Form.Item>
<div className="clearfix mt30 edu-txt-center">
<a onClick={this.cancelNew} className="task-btn mr30">取消</a>
<a type="submit" onClick={this.handleSubmit} className="task-btn task-btn-orange">确定</a>
</div>
</Form>
</div>
</Modal>
)
}
}
const WrappedVideoLink = Form.create({name: 'VideoLink'})(VideoLink);
export default WrappedVideoLink;

@ -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"?<div onClick={e=>this.Navmodalnames(e,1,"shixun_homework",item.id)}>新建目录</div>:""}
{/*资源*/}
{item.type==="attachment"?<div onClick={e=>this.Navmodalnames(e,1,"attachment",item.id)}>新建目录</div>:""}
{/* 视频 */}
{item.type==="video"?<div onClick={e=>this.Navmodalnames(e,1,"video",item.id)}>新建目录</div>:""}
{/*毕业设计*/}
{/*{item.type==="graduation"?<div onClick={()=>this.Navmodalnames(1,"attachment",item.id)}>添加目录</div>:""}*/}
{/*讨论区*/}
@ -872,6 +881,9 @@ class Coursesleftnav extends Component{
{/*讨论区*/}
{item.type==="board"?<div onClick={e=>this.Navmodalnames(e,7,"editSecondname",iem.category_id,iem.category_name)}>重命名</div>:""}
{item.type==="board"?<div onClick={e=>this.deleteSecondary(e,3,iem.category_id,item.category_url)}>删除</div>:""}
{/*视频*/}
{item.type==="video"?<div onClick={e=>this.Navmodalnames(e,4,"editSecondname",iem.category_id,iem.category_name)}>重命名</div>:""}
{item.type==="video"?<div onClick={e=>this.deleteSecondary(e,1,iem.category_id,item.category_url)}>删除</div>:""}
</div>)
};

@ -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<newgroup_publish.length; i++){
if(i===parseInt(key)){
newgroup_publish[i].publish_time=handleDateString(dateString);
}
}
this.setState({
course_group_publish_times:newgroup_publish,
})
}
}
RadioonChange=(e)=>{
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(
<div>
{/*提示*/}
<Modals
modalsType={this.state.Modalstype}
modalsTopval={this.state.Modalstopval}
modalCancel={this.state.ModalCancel}
modalSave={this.state.ModalSave}
loadtype= {this.state.loadtype}
/>
<Modal
keyboard={false}
className={"HomeworkModal"}
title={this.props.modalname}
visible={this.props.visible}
closable={false}
footer={null}
destroyOnClose={true}
>
<div className="task-popup-content">
<p className="task-popup-text-center font-16">
<span className={"color-blue underline"}> </span>
</p>
<style>{`
.uploadBtn.ant-btn {
border: none;
color: #4CACFF;
box-shadow: none;
background: transparent;
border:1px solid #4CACFF;
padding-left: 6px;
margin-right: 5px;
}
.ant-upload-list-item:hover .ant-upload-list-item-info{
padding: 0 12px 0 0px;
background-color:#fff;
}
.upload_1 .ant-upload-list {
width: 350px;
}
.ant-upload-select{
float: left;
}
.winth540{
width: 540px;
height: 34px;
}
.winth540 .ant-input-group-wrapper{
width: 86% !important;
}
.flexoo .ant-input{
width: 86% !important;
}
`}</style>
<p className={"winth540"} style={{
width: '100%',
display: "flex",
flexDirection:"row",
}}>
<span className="color-ooo fl mt6">资源名称</span>
<Input className="" placeholder="请输入资源名称最大限制60字符" value={resourcesname} onChange={this.handleChanges} addonAfter={String(addonAfteronelens3)+"/60"} maxLength={60} />
</p>
{
resourcesnamebool?
<p className=" color-red" style={{
marginLeft: "13%"
}}>请输入资源名称</p>
:
""
}
<p className={resourcesnamebool===true?"winth540 flexoo mt10":"winth540 flexoo mt16"} style={{
width: '100%',
display: "flex",
flexDirection:"row",
}}>
<span className="color-ooo fl mt6">链接地址</span>
<Input className="" placeholder="请输入外链url" value={resourceurl} onChange={this.handleChangess} />
</p>
{
resourceurlbool?
<p className=" color-red" style={{
marginLeft: "13%"
}}>请输入外链url</p>
:
""
}
<p className={this.state.fileListtype===true?"mt25":""}>
<style>{`
.ant-checkbox-wrapper{
margin-left:0px !important;
margin-top:10px;
}
`}</style>
{this.props.course_is_public===true?<div>
<span className={"color-ooo"}>公开</span><Checkbox checked={is_public} onChange={this.onChangepublic}>
<span className={"font-14 color-ooo"}>选中所有用户可见否则课堂成员可见</span>
</Checkbox>
</div>:""}
<style>{`
.Selectleft20{
margin-left: 20px !important;
width: 176px;
height: 40px;
}
#startimes .ant-calendar-picker-icon{
margin-top:-11px;
}
.resourcebox{
max-height:150px;
overflow: auto;
}
`}</style>
</p>
<div className={this.props.course_is_public===true?"mt10":""}>
<span className={"color-ooo fl mt6"}>发布设置</span>
<Radio.Group onChange={this.RadioonChange} value={this.state.Radiovalue} style={{'width': '460px'}}>
<Radio style={radioStyle} value={0}>
立即发布
</Radio>
<Tooltip placement="bottom" title={this.props.isStudent()===true?"不支持学生延迟发布":""}>
<Radio style={radioStyle} value={1} className={"fl"} disabled={this.props.isStudent()}>
<span className={"mr5"}>延期发布</span>
<DatePicker
dropdownClassName="hideDisable"
showTime={{ format: 'HH:mm' }}
locale={locale}
format={dateFormat}
placeholder="请选择发布时间"
id={"startime"}
showToday={false}
width={"210px"}
value={this.state.Radiovalue===1?datatime===undefined||datatime===""?undefined:moment(datatime, dateFormat):undefined}
onChange={(e,index)=>this.onChangeTimepublish(e,index,undefined,1)}
disabledTime={disabledDateTime}
disabledDate={disabledDate}
disabled={this.state.Radiovalue===1?false:true}
/>
</Radio>
</Tooltip>
<span className={"fl mt5 color-grey-c"}>(按照设置的时间定时发布)</span>
</Radio.Group>
</div>
<div className="mt10" style={{
width: '100%',
display: "flex",
flexDirection:"row",
}}>
<span className="color-ooo fl mt6">资源描述</span>
{/*{course_group_publish_timestype===true?<p className={"color-red mt10"}>请填写完整</p>:""}*/}
<textarea placeholder="请在此输入资源描述最大限制100个字符" className={"mt10"} value={this.state.description} onInput={this.settextarea} style={{
width: '86%',
height:'120px',
border:'1px solid rgba(234,234,234,1)',
padding: '10px'
}}></textarea>
</div>
{descriptiontype===true?<p className={"color-red"}>请输入资源描述最大限制100个字符</p>:""}
{this.state.Radiovaluetype===true?<p className={"color-red"}>发布时间不能为空</p>:""}
<div className="clearfix mt30 edu-txt-center mb10">
<a className="task-btn color-white mr70" onClick={this.props.Cancel}>{this.props.Cancelname}</a>
<a className="task-btn task-btn-orange" onClick={()=>this.Saves()}>{this.props.Savesname}</a>
</div>
</div>
</Modal>
</div>
)
}
}
export default sendResources;

@ -112,7 +112,7 @@ const NewOrEditTask = (props) => {
content: (<p>发布后即可应用到自己管理的课堂<br /> 是否确认发布?</p>),
onOk() {
changePublishLoadingStatus(true);
handlePublish(props, 'publish');
props.handlePublish(props, 'publish');
}
});
}

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

@ -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;
}
`
}
</style>
@ -93,7 +99,24 @@ function EditVideoModal (props) {
<Input placeholder="" className="titleInput exercicenewinputysl" maxLength={MAX_LENGTH}
addonAfter={String(_title ? `${String(_title.length)}/${MAX_LENGTH}` : 0)} />
)}
</Form.Item>
</Form.Item>
{
link ?
<Form.Item
label="视频链接"
className="title formItemInline"
>
{getFieldDecorator('link', {
rules: [{
required: true, message: '请输入视频链接',
}],
})(
<Input placeholder="请输入视频链接" className="titleInput exercicenewinputysl" />
)}
</Form.Item>
:""
}
</ModalWrapper>
)
}

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

@ -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 (
<div className={`${isReview ? 'videoInReviewItem' : 'nItem'} videoItem`}>
<img className="cover" src={cover_url || "http://video.educoder.net/e7d18970482a46d2a6f0e951b504256c/snapshots/491e113950d74f1dab276097dae287dd-00005.jpg"}
></img>
{!isReview && <div className="mask" onClick={() => onMaskClick(props)}>
<img className="cover" src={cover_url || defaultImg} alt=""></img>
{ link ?
<a href={link} target='_blank' className="otherLinkPanel">
<span className="otherLink">外链</span>
</a>
: ""
}
</div>}
{!isReview &&
{!isReview && <div className="mask" onClick={() => onMaskClick(props)}></div>}
{!isReview && !link &&
<div className="playWrap" onClick={() => onMaskClick(props)}>
<img className="play mp23" src={playIcon}></img>
{play_duration===0?"":<div className={"play_duration"}>累计学习时长{play_duration} h</div>}
@ -68,11 +73,19 @@ function VideoInReviewItem (props) {
<div className="df buttonRow">
{/* 2019-09-01 10:00:22 */}
<span className={"dianjilianicon"}>
{vv===0?"":<Tooltip title="播放次数" placement="bottom">
{!vv || (vv && vv)===0 ? "" : <Tooltip title="播放次数" placement="bottom">
<i className={`icon-dianjiliang iconfont dianjilianicon`}></i>
</Tooltip> } {vv===0?"":vv}
</Tooltip> } {!vv || (vv && vv)===0?"":vv}
</span>
{ isReview != true && <div>
{
moveVideo &&
<Tooltip title="移动到" placement="bottom">
<i className="icon-yidong iconfont font-15" onClick={() => moveVideo(props)}
style={{ marginTop: '1px', display: 'inline-block'}}
></i>
</Tooltip>
}
{
deleteVideo &&
<Tooltip title="删除" placement="bottom">
@ -90,9 +103,13 @@ function VideoInReviewItem (props) {
></i>
</Tooltip>
}
<Tooltip title="复制视频地址" placement="bottom">
<i className={`icon-fuzhi iconfont copybtn_item_${id}`} data-clipboard-text={getCopyText(file_url, cover_url)}></i>
</Tooltip>
{
!link ?
<Tooltip title="复制视频地址" placement="bottom">
<i className={`icon-fuzhi iconfont copybtn_item_${id}`} data-clipboard-text={getCopyText(file_url, cover_url)}></i>
</Tooltip>:""
}
</div> }
</div>
</div>

@ -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) {
:
<Link to={`/users/${username}/videos/protocol`} style={{color: theme.foreground_select}}>上传内容协议</Link>
const protocolLine = <div>上传视频即表示您已同意{urls}不得上传未经他人授权的作品</div>
return (
<div className={flag?"edu-back-white pb100 videoUploadList":"educontent videoUploadList"} style={{ marginBottom: `${flag?"0px":"200px"}` }}>
<Prompt

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

@ -222,38 +222,63 @@ export const validateOjForm = (props, type, cb) => {
}
try {
let boolflad=false;
try {
if(ojForm.sub_discipline_id.length===0){
hasSuccess = false;
notification['error']({
message: '提示',
description: '课程必须选择!'
});
boolflad=true;
}else if(ojForm.timeLimit===null){
hasSuccess = false;
notification['error']({
message: '提示',
description: '时间限制必须输入!'
});
} else if(ojForm.name.length===0){
boolflad=true;
} else if(ojForm.name.length===0){
hasSuccess = false;
notification['error']({
message: '提示',
description: '任务名称必须输入!'
});
boolflad=true;
}else if(ojForm.description.length===0){
hasSuccess = false;
notification['error']({
message: '提示',
description: '描述必须输入!'
});
}
boolflad=true;
}
}catch (e) {
}
try {
if( hasSuccess === false){
if(boolflad===true){
props.changeSubmitLoadingStatus(false);
}
}
}catch (e) {
}
try {
if( hasSuccess === false){
if(boolflad===true){
props.changePublishLoadingStatus(false);
}
}
}catch (e) {
}

Loading…
Cancel
Save