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

competitions
杨树林 6 years ago
commit ee2890aed1

@ -1,5 +1,6 @@
# README # README
https://www.trustie.net/issues/24719
[云上实验室] Logo、导航、底部备案信息定制化
This README would normally document whatever steps are necessary to get the This README would normally document whatever steps are necessary to get the
application up and running. application up and running.

@ -0,0 +1,15 @@
class Admins::CompetitionsController < Admins::BaseController
def index
params[:sort_by] = params[:sort_by].presence || 'created_on'
params[:sort_direction] = params[:sort_direction].presence || 'desc'
@competitions = custom_sort Competition.all, params[:sort_by], params[:sort_direction]
@params_page = params[:page] || 1
@competitions = paginate @competitions
respond_to do |format|
format.js
format.html
end
end
end

@ -2,7 +2,7 @@ class BoardsController < ApplicationController
before_action :require_login, :check_auth before_action :require_login, :check_auth
before_action :find_course, only: [:create] before_action :find_course, only: [:create]
before_action :set_board, except: [:create] before_action :set_board, except: [:create]
before_action :teacher_or_admin_allowed before_action :teacher_allowed
def index def index
@boards = @course.boards.includes(messages: [:last_reply, :author]) @boards = @course.boards.includes(messages: [:last_reply, :author])

@ -2,7 +2,7 @@ class CourseGroupsController < ApplicationController
before_action :require_login, :check_auth before_action :require_login, :check_auth
before_action :set_group, except: [:create] before_action :set_group, except: [:create]
before_action :find_course, only: [:create] before_action :find_course, only: [:create]
before_action :teacher_or_admin_allowed before_action :teacher_allowed
def create def create
tip_exception("分班名称不能为空") if params[:name].blank? tip_exception("分班名称不能为空") if params[:name].blank?

@ -2,7 +2,8 @@ class CourseModulesController < ApplicationController
before_action :require_login, :check_auth before_action :require_login, :check_auth
before_action :set_module, except: [:unhidden_modules] before_action :set_module, except: [:unhidden_modules]
before_action :find_course, only: [:unhidden_modules] before_action :find_course, only: [:unhidden_modules]
before_action :teacher_or_admin_allowed before_action :teacher_or_admin_allowed, except: [:add_second_category]
before_action :teacher_allowed, only: [:add_second_category]
# 模块置顶 # 模块置顶
def sticky_module def sticky_module
@ -48,9 +49,9 @@ class CourseModulesController < ApplicationController
tip_exception("已存在同名子目录") if @course_module.course_second_categories.exists?(name: params[:name].strip) tip_exception("已存在同名子目录") if @course_module.course_second_categories.exists?(name: params[:name].strip)
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
begin begin
@course_module.course_second_categories.create!(name: params[:name].strip, category_type: @course_module.module_type, category = @course_module.course_second_categories.create!(name: params[:name].strip, category_type: @course_module.module_type,
course_id: @course.id, position: @course_module.course_second_categories.count + 1) course_id: @course.id, position: @course_module.course_second_categories.count + 1)
normal_status(0, "添加成功") render :json => {category_id: category.id, status: 0, message: "添加成功"}
rescue Exception => e rescue Exception => e
uid_logger_error(e.message) uid_logger_error(e.message)
tip_exception("添加子目录失败") tip_exception("添加子目录失败")

@ -1,7 +1,7 @@
class CourseSecondCategoriesController < ApplicationController class CourseSecondCategoriesController < ApplicationController
before_action :require_login, :check_auth before_action :require_login, :check_auth
before_action :set_category before_action :set_category
before_action :teacher_or_admin_allowed before_action :teacher_allowed
# 目录重命名 # 目录重命名
def rename_category def rename_category

@ -35,7 +35,7 @@ class CoursesController < ApplicationController
:transfer_to_course_group, :delete_from_course, :export_member_scores_excel, :transfer_to_course_group, :delete_from_course, :export_member_scores_excel,
:search_users, :add_students_by_search, :get_historical_courses, :add_teacher_popup, :search_users, :add_students_by_search, :get_historical_courses, :add_teacher_popup,
:add_teacher, :export_couser_info, :export_member_act_score, :add_teacher, :export_couser_info, :export_member_act_score,
:update_informs, :new_informs, :delete_informs] :update_informs, :new_informs, :delete_informs, :switch_to_student]
before_action :admin_allowed, only: [:set_invite_code_halt, :set_public_or_private, :change_course_admin, before_action :admin_allowed, only: [:set_invite_code_halt, :set_public_or_private, :change_course_admin,
:set_course_group, :create_group_by_importing_file, :set_course_group, :create_group_by_importing_file,
:update_task_position, :tasks_list] :update_task_position, :tasks_list]
@ -681,13 +681,19 @@ class CoursesController < ApplicationController
course_member = @course.course_members.find_by!(user_id: current_user.id, is_active: 1) course_member = @course.course_members.find_by!(user_id: current_user.id, is_active: 1)
tip_exception("切换失败") if course_member.STUDENT? tip_exception("切换失败") if course_member.STUDENT?
course_student = CourseMember.find_by!(user_id: current_user.id, role: %i[STUDENT], course_id: @course.id) course_student = CourseMember.find_by(user_id: current_user.id, role: %i[STUDENT], course_id: @course.id)
course_member.update_attributes(is_active: 0) course_member.update_attributes!(is_active: 0)
course_student.update_attributes(is_active: 1) if course_student
course_student.update_attributes!(is_active: 1)
else
# 学生身份不存在则创建
CourseMember.create!(user_id: current_user.id, role: 4, course_id: @course.id)
CourseAddStudentCreateWorksJob.perform_later(@course.id, [current_user.id])
end
normal_status(0, "切换成功") normal_status(0, "切换成功")
rescue => e rescue => e
uid_logger_error("switch_to_student error: #{e.message}") uid_logger_error("switch_to_student error: #{e.message}")
tip_exception("切换失败") tip_exception(e.message)
raise ActiveRecord::Rollback raise ActiveRecord::Rollback
end end
end end
@ -1127,7 +1133,7 @@ class CoursesController < ApplicationController
def top_banner def top_banner
@user = current_user @user = current_user
@is_teacher = @user_course_identity < Course::STUDENT @switch_student = Course::BUSINESS < @user_course_identity && @user_course_identity < Course::STUDENT
@is_student = @user_course_identity == Course::STUDENT @is_student = @user_course_identity == Course::STUDENT
@course.increment!(:visits) @course.increment!(:visits)
end end

@ -9,19 +9,20 @@ class FilesController < ApplicationController
before_action :set_pagination, only: %i[index public_with_course_and_project mine_with_course_and_project] 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 :validate_upload_params, only: %i[upload import]
before_action :find_file, only: %i[show setting update] before_action :find_file, only: %i[show setting update]
before_action :publish_params, only: %i[upload import update]
SORT_TYPE = %w[created_on downloads quotes] SORT_TYPE = %w[created_on downloads quotes]
def index def index
sort = params[:sort] || 0 # 0: 降序1: 升序 sort = params[:sort] || 0 # 0: 降序1: 升序
sort_type = params[:sort_type] || 'created_on' # created_on时间排序 downloads下载次数排序; quotes: 引用次数排序 sort_type = params[:sort_type] || 'created_on' # created_on时间排序 downloads下载次数排序; quotes: 引用次数排序
course_second_category_id = params[:course_second_category_id] || 0 # 0: 为主目录, 其他为次目录id @course_second_category_id = params[:course_second_category_id] || 0 # 0: 为主目录, 其他为次目录id
@user = current_user @user = current_user
@attachments = course_second_category_id.to_i == 0 ? @course.attachments : @course.attachments.by_course_second_category_id(course_second_category_id) @attachments = @course_second_category_id.to_i == 0 ? @course.attachments.includes(:course_second_category) : @course.attachments.by_course_second_category_id(@course_second_category_id)
@attachments = @attachments.includes(attachment_group_settings: :course_group, author: [:user_extension, :course_members]) @attachments = @attachments.includes(author: [:user_extension, :course_members])
.ordered(sort: sort.to_i, sort_type: sort_type.strip) .ordered(sort: sort.to_i, sort_type: sort_type.strip)
get_category(@course, course_second_category_id) get_category(@course, @course_second_category_id)
@total_count = @attachments.size @total_count = @attachments.size
@publish_count = @attachments.published.size @publish_count = @attachments.published.size
@unpublish_count = @total_count - @publish_count @unpublish_count = @total_count - @publish_count
@ -137,9 +138,9 @@ class FilesController < ApplicationController
def upload def upload
attachment_ids = params[:attachment_ids] attachment_ids = params[:attachment_ids]
course_second_category_id = params[:course_second_category_id] || 0 # 0: 为主目录, 其他为次目录id 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 # is_unified_setting = params.has_key?(:is_unified_setting) ? params[:is_unified_setting] : true
publish_time = params[:publish_time] # publish_time = params[:publish_time]
course_group_publish_times = params[:course_group_publish_times] || [] # course_group_publish_times = params[:course_group_publish_times] || []
begin begin
attachment_ids.each do |attchment_id| attachment_ids.each do |attchment_id|
@ -148,9 +149,12 @@ class FilesController < ApplicationController
attachment.container = @course attachment.container = @course
attachment.course_second_category_id = course_second_category_id attachment.course_second_category_id = course_second_category_id
attachment.description = params[:description] attachment.description = params[:description]
attachment.is_public = params[:is_public] ? 1 : 0 attachment.is_public = params[:is_public] && @course.is_public == 1 ? 1 : 0
attachment.set_publish_time(publish_time) if is_unified_setting attachment.is_publish = @atta_is_publish
attachment.set_course_group_publish_time(@course, course_group_publish_times) if @course.course_groups.size > 0 && !is_unified_setting && publish_time.blank? attachment.delay_publish = @atta_delay_publish
attachment.publish_time = @atta_publish_time
# 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! attachment.save!
end end
end end
@ -188,8 +192,9 @@ class FilesController < ApplicationController
attach_copied_obj.created_on = Time.now attach_copied_obj.created_on = Time.now
attach_copied_obj.author = current_user attach_copied_obj.author = current_user
attach_copied_obj.is_public = 0 attach_copied_obj.is_public = 0
attach_copied_obj.is_publish = 1 attach_copied_obj.is_publish = @atta_is_publish
attach_copied_obj.publish_time = Time.now attach_copied_obj.delay_publish = @atta_delay_publish
attach_copied_obj.publish_time = @atta_publish_time
attach_copied_obj.course_second_category_id = course_second_category_id attach_copied_obj.course_second_category_id = course_second_category_id
attach_copied_obj.copy_from = ori.copy_from.nil? ? ori.id : ori.copy_from attach_copied_obj.copy_from = ori.copy_from.nil? ? ori.id : ori.copy_from
if attach_copied_obj.attachtype == nil if attach_copied_obj.attachtype == nil
@ -209,11 +214,7 @@ class FilesController < ApplicationController
def update def update
return normal_status(403, "您没有权限进行该操作") if current_user.course_identity(@course) >= 5 && @file.author != current_user return normal_status(403, "您没有权限进行该操作") if current_user.course_identity(@course) >= 5 && @file.author != current_user
is_unified_setting = params[:is_unified_setting]
publish_time = params[:publish_time]
publish_time = format_time(Time.parse(publish_time)) unless publish_time.blank?
is_public = params[:is_public] is_public = params[:is_public]
course_group_publish_times = params[:course_group_publish_times] || []
@old_attachment = @file @old_attachment = @file
@new_attachment = Attachment.find_by_id params[:new_attachment_id] @new_attachment = Attachment.find_by_id params[:new_attachment_id]
@ -225,25 +226,29 @@ class FilesController < ApplicationController
old_course_second_category_id = @old_attachment.course_second_category_id old_course_second_category_id = @old_attachment.course_second_category_id
@old_attachment.copy_attributes_from_new_attachment(@new_attachment) @old_attachment.copy_attributes_from_new_attachment(@new_attachment)
@old_attachment.is_public = is_public == true ? 1 : 0 if is_public
@old_attachment.course_second_category_id = old_course_second_category_id @old_attachment.course_second_category_id = old_course_second_category_id
@old_attachment.save! @old_attachment.save!
@new_attachment.delete @new_attachment.delete
end 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
@old_attachment.publish_time = @atta_publish_time
if params[:description] && !params[:description].strip.blank? && params[:description] != @old_attachment.description if params[:description] && !params[:description].strip.blank? && params[:description] != @old_attachment.description
@old_attachment.description = params[:description] @old_attachment.description = params[:description]
end end
@old_attachment.set_public(is_public) # @old_attachment.set_public(is_public)
if is_unified_setting # if is_unified_setting
@old_attachment.set_publish_time(publish_time) # @old_attachment.set_publish_time(publish_time)
@old_attachment.attachment_group_settings.destroy_all # @old_attachment.attachment_group_settings.destroy_all
end # end
if publish_time.blank? && @course.course_groups.size > 0 && !is_unified_setting # if publish_time.blank? && @course.course_groups.size > 0 && !is_unified_setting
@old_attachment.set_course_group_publish_time(@course, course_group_publish_times) # @old_attachment.set_course_group_publish_time(@course, course_group_publish_times)
end # end
@old_attachment.save! @old_attachment.save!
rescue Exception => e rescue Exception => e
@ -304,11 +309,19 @@ class FilesController < ApplicationController
end end
def file_validate_sort_type def file_validate_sort_type
normal_status(-2, "参数sort_tyope暂时只支持 'created_on', 'quotes', 'downloads'") if params.has_key?(:sort_type) && !SORT_TYPE.include?(params[:sort_type].strip) normal_status(-2, "参数sort_type暂时只支持 'created_on', 'quotes', 'downloads'") if params.has_key?(:sort_type) && !SORT_TYPE.include?(params[:sort_type].strip)
end end
def validate_upload_params def validate_upload_params
find_attachment_ids find_attachment_ids
find_course_second_category_id find_course_second_category_id
end end
def publish_params
tip_exception("缺少发布参数") if params[:delay_publish].blank?
tip_exception("缺少延期发布的时间参数") if params[:delay_publish].to_i == 1 && params[:publish_time].blank?
@atta_is_publish = params[:delay_publish].to_i == 1 && params[:publish_time].to_time > Time.now ? 0 : 1
@atta_delay_publish = params[:delay_publish].to_i
@atta_publish_time = params[:delay_publish].to_i == 1 && params[:publish_time] ? params[:publish_time] : Time.now
end
end end

@ -9,6 +9,8 @@ class Attachment < ApplicationRecord
belongs_to :course, foreign_key: :container_id, optional: true belongs_to :course, foreign_key: :container_id, optional: true
has_many :attachment_group_settings, :dependent => :destroy has_many :attachment_group_settings, :dependent => :destroy
has_many :attachment_histories, -> { order(version: :desc) }, :dependent => :destroy has_many :attachment_histories, -> { order(version: :desc) }, :dependent => :destroy
# 二级目录
belongs_to :course_second_category, optional: true
scope :by_filename_or_user_name, -> (keywords) { joins(:author).where("filename like :search or LOWER(concat(users.lastname, users.firstname)) LIKE :search", scope :by_filename_or_user_name, -> (keywords) { joins(:author).where("filename like :search or LOWER(concat(users.lastname, users.firstname)) LIKE :search",
:search => "%#{keywords.split(" ").join('|')}%") unless keywords.blank? } :search => "%#{keywords.split(" ").join('|')}%") unless keywords.blank? }
@ -96,7 +98,7 @@ class Attachment < ApplicationRecord
def become_history def become_history
history = self.attachment_histories.first history = self.attachment_histories.first
new_attachment_history = AttachmentHistory.new(self.attributes.except("id", "resource_bank_id", "unified_setting", "course_second_category_id").merge( new_attachment_history = AttachmentHistory.new(self.attributes.except("id", "resource_bank_id", "unified_setting", "course_second_category_id", "delay_publish").merge(
attachment_id: self.id, attachment_id: self.id,
version: history.nil? ? 1 : history.version + 1, version: history.nil? ? 1 : history.version + 1,
)) ))
@ -104,7 +106,7 @@ class Attachment < ApplicationRecord
end end
def copy_attributes_from_new_attachment(new_attachment) def copy_attributes_from_new_attachment(new_attachment)
self.attributes = new_attachment.attributes.dup.except("id","container_id","container_type","is_public","downloads", "quotes",'is_publish','publish_time') self.attributes = new_attachment.attributes.dup.except("id","container_id","container_type","is_public","downloads", "quotes",'is_publish','publish_time', "delay_publish")
end end
def set_public(is_public) def set_public(is_public)

@ -0,0 +1,3 @@
class CompetitionModeSetting < ApplicationRecord
belongs_to :course
end

@ -19,7 +19,7 @@ class Laboratory < ApplicationRecord
return if subdomain.blank? return if subdomain.blank?
rails_env = EduSetting.get('rails_env') rails_env = EduSetting.get('rails_env')
subdomain = subdomain.slice(0, subdomain.size - rails_env.size - 1) if subdomain.end_with?(rails_env) # winse.dev => winse subdomain = subdomain.slice(0, subdomain.size - rails_env.size - 1) if rails_env && subdomain.end_with?(rails_env) # winse.dev => winse
find_by_identifier(subdomain) find_by_identifier(subdomain)
end end

@ -30,7 +30,7 @@ class Admins::SaveLaboratorySettingService < ApplicationService
hash = {} hash = {}
hash[:name] = strip nav[:name] hash[:name] = strip nav[:name]
hash[:link] = strip nav[:link] hash[:link] = strip nav[:link]
hash[:hidden] = nav[:hidden].to_s == 0 hash[:hidden] = nav[:hidden].to_s != '0'
hash hash
end end
end end

@ -0,0 +1,7 @@
<% define_admin_breadcrumbs do %>
<% add_admin_breadcrumb('竞赛列表', admins_competitions_path) %>
<% end %>
<div class="box competitions-list-container">
<%= render partial: 'admins/shixuns/shared/list', locals: { shixuns: @shixuns } %>
</div>

@ -66,6 +66,8 @@
<% end %> <% end %>
</li> </li>
<li><%= sidebar_item(admins_competitions_path, '竞赛', icon: 'trophy', controller: 'admins-competitions') %></li>
<li> <li>
<%= sidebar_item_group('#setting-submenu', '网站建设', icon: 'cogs') do %> <%= sidebar_item_group('#setting-submenu', '网站建设', icon: 'cogs') do %>
<li><%= sidebar_item(admins_carousels_path, '轮播图', icon: 'image', controller: 'admins-carousels') %></li> <li><%= sidebar_item(admins_carousels_path, '轮播图', icon: 'image', controller: 'admins-carousels') %></li>

@ -4,10 +4,11 @@ json.is_public attachment.publiced?
# json.is_lock attachment.locked?(@is_member) # json.is_lock attachment.locked?(@is_member)
json.is_lock !attachment.publiced? json.is_lock !attachment.publiced?
json.is_publish attachment.published? json.is_publish attachment.published?
json.delay_publish attachment.delay_publish
json.publish_time attachment.publish_time json.publish_time attachment.publish_time
json.unified_setting attachment.unified_setting json.unified_setting attachment.unified_setting
json.filesize number_to_human_size(attachment.filesize) json.filesize number_to_human_size(attachment.filesize)
json.quotes attachment.quotes_count # json.quotes attachment.quotes_count
json.description attachment.description json.description attachment.description
json.downloads_count attachment.downloads_count json.downloads_count attachment.downloads_count
json.created_on attachment.created_on json.created_on attachment.created_on

@ -20,7 +20,7 @@ json.competitions do
if section if section
json.current_stage do json.current_stage do
json.name = section.competition_stage.name json.name section.competition_stage.name
json.start_time section.display_start_time json.start_time section.display_start_time
json.end_time section.display_end_time json.end_time section.display_end_time
end end

@ -11,7 +11,7 @@ json.course_modules @course_modules.each do |mod|
case mod.module_type case mod.module_type
when "course_group" when "course_group"
# json.none_group_count @course.none_group_count # json.none_group_count @course.none_group_count
json.second_category left_group_info @course # json.second_category left_group_info @course
when "board" when "board"
course_board = @course.course_board course_board = @course.course_board
if course_board.present? if course_board.present?

@ -1,5 +1,6 @@
json.partial! "commons/success" json.partial! "commons/success"
json.data do json.data @courses do |course|
json.array! @courses, :id, :name, :updated_at json.(course, :id, :name, :updated_at, :end_date)
json.created_at course.created_at.strftime("%Y-%m-%d")
end end

@ -15,7 +15,7 @@ json.is_admin @user_course_identity < Course::PROFESSOR
json.is_public @course.is_public == 1 json.is_public @course.is_public == 1
json.code_halt @course.invite_code_halt == 1 json.code_halt @course.invite_code_halt == 1
json.invite_code @course.invite_code_halt == 0 ? @course.generate_invite_code : "" json.invite_code @course.invite_code_halt == 0 ? @course.generate_invite_code : ""
json.switch_to_student switch_student_role(@is_teacher, @course, @user) json.switch_to_student @switch_student
json.switch_to_teacher switch_teacher_role(@is_student, @course, @user) json.switch_to_teacher switch_teacher_role(@is_student, @course, @user)
json.switch_to_assistant switch_assistant_role(@is_student, @course, @user) json.switch_to_assistant switch_assistant_role(@is_student, @course, @user)
#json.join_course !@user.member_of_course?(@course) #json.join_course !@user.member_of_course?(@course)

@ -13,7 +13,10 @@ json.data do
json.author do json.author do
json.partial! "users/user_simple", user: attachment.author json.partial! "users/user_simple", user: attachment.author
end end
json.partial! "files/course_groups", attachment_group_settings: attachment.attachment_group_settings # json.partial! "files/course_groups", attachment_group_settings: attachment.attachment_group_settings
if @course_second_category_id.to_i == 0
json.category_name attachment.course_second_category&.name
end
end end
end end
end end

@ -1,3 +1,3 @@
json.partial! 'attachments/attachment', attachment: @file json.partial! 'attachments/attachment', attachment: @file
json.partial! "files/course_groups", attachment_group_settings: @file.attachment_group_settings # json.partial! "files/course_groups", attachment_group_settings: @file.attachment_group_settings
json.partial! "attachment_histories/list", attachment_histories: @attachment_histories json.partial! "attachment_histories/list", attachment_histories: @attachment_histories

@ -5,10 +5,11 @@ json.partial! "homework_btn_check", locals: {identity: @user_course_identity, ho
json.partial! "student_btn_check", locals: {identity: @user_course_identity, homework: @homework, work: @work} json.partial! "student_btn_check", locals: {identity: @user_course_identity, homework: @homework, work: @work}
json.description @homework.description json.description @homework.description
# 实训作业才有说明 # 实训作业才有说明
if @homework.homework_type == "practice" if @homework.homework_type == "practice"
json.explanation @homework.explanation json.explanation @homework.explanation
# else
# json.description @homework.description
end end
# 附件 # 附件

@ -980,6 +980,8 @@ Rails.application.routes.draw do
resource :laboratory_setting, only: [:show, :update] resource :laboratory_setting, only: [:show, :update]
resource :laboratory_user, only: [:create, :destroy] resource :laboratory_user, only: [:create, :destroy]
end end
resources :competitions, only: [:index, :destroy]
end end
resources :colleges, only: [] do resources :colleges, only: [] do

@ -0,0 +1,7 @@
class MigrateCourseAtta < ActiveRecord::Migration[5.2]
def change
add_column :attachments, :delay_publish, :boolean, default: 0
Attachment.where(container_type: "Course").where(is_publish: 0).where("publish_time > '#{(Time.now).strftime("%Y-%m-%d %H:%M:%S")}'").update_all(delay_publish: 1)
end
end

@ -0,0 +1,6 @@
class AddNewColumnToCompetitions < ActiveRecord::Migration[5.2]
def change
add_column :competitions, :bonus, :integer, default: 0
add_column :competitions, :mode, :integer, default: 0
end
end

@ -0,0 +1,11 @@
class CreateCompetitionModeSettings < ActiveRecord::Migration[5.2]
def change
create_table :competition_mode_settings do |t|
t.references :course
t.datetime :start_time
t.datetime :end_time
t.timestamps
end
end
end

@ -13,7 +13,7 @@
<meta http-equiv="Expires" content="0" /> <meta http-equiv="Expires" content="0" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json"> <link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico"> <!-- <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">-->
<!-- <!--
Notice the use of %PUBLIC_URL% in the tags above. Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build. It will be replaced with the URL of the `public` folder during the build.
@ -23,7 +23,8 @@
work correctly both with client-side routing and a non-root public URL. work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`. Learn how to configure a non-root public URL by running `npm run build`.
--> -->
<title>EduCoder</title> <!-- <title>EduCoder</title>-->
<!--react-ssr-head-->
<script type="text/javascript"> <script type="text/javascript">
window.__isR = true; window.__isR = true;

@ -10,7 +10,7 @@
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/ homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
--> -->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json"> <link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico"> <!-- <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">-->
<!-- <!--
Notice the use of %PUBLIC_URL% in the tags above. Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build. It will be replaced with the URL of the `public` folder during the build.
@ -20,7 +20,8 @@
work correctly both with client-side routing and a non-root public URL. work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`. Learn how to configure a non-root public URL by running `npm run build`.
--> -->
<title>Educoder</title> <!-- <title>Educoder</title>-->
<!--react-ssr-head-->
<script type="text/javascript"> <script type="text/javascript">
window.__isR = true; window.__isR = true;
</script> </script>

@ -9,7 +9,7 @@ import {
Route, Route,
Switch Switch
} from 'react-router-dom'; } from 'react-router-dom';
import axios from 'axios';
import '@icedesign/base/dist/ICEDesignBase.css'; import '@icedesign/base/dist/ICEDesignBase.css';
import '@icedesign/base/index.scss'; import '@icedesign/base/index.scss';
@ -287,6 +287,7 @@ class App extends Component {
Addcoursestypes:false, Addcoursestypes:false,
mydisplay:false, mydisplay:false,
occupation:0, occupation:0,
mygetHelmetapi:undefined,
} }
} }
@ -327,7 +328,6 @@ class App extends Component {
} }
componentDidMount() { componentDidMount() {
this.disableVideoContextMenu(); this.disableVideoContextMenu();
// force an update if the URL changes // force an update if the URL changes
history.listen(() => { history.listen(() => {
this.forceUpdate() this.forceUpdate()
@ -336,7 +336,8 @@ class App extends Component {
$("html").animate({ scrollTop: $('html').scrollTop() - 0 }) $("html").animate({ scrollTop: $('html').scrollTop() - 0 })
}); });
initAxiosInterceptors(this.props) initAxiosInterceptors(this.props);
this.getAppdata();
// //
// axios.interceptors.response.use((response) => { // axios.interceptors.response.use((response) => {
// // console.log("response"+response); // // console.log("response"+response);
@ -362,15 +363,78 @@ class App extends Component {
this.setState({ this.setState({
isRender:false, isRender:false,
}) })
} };
//获取当前定制信息
render() { getAppdata=()=>{
let url = "/setting.json";
axios.get(url).then((response) => {
// console.log("app.js开始请求/setting.json");
// console.log("获取当前定制信息");
if(response){
if(response.data){
this.setState({
mygetHelmetapi:response.data.setting
});
document.title = response.data.setting.name;
var link = document.createElement('link'),
oldLink = document.getElementById('dynamic-favicon');
link.id = 'dynamic-favicon';
link.rel = 'shortcut icon';
link.href = '/'+response.data.setting.tab_logo_url;
if (oldLink) {
document.head.removeChild(oldLink);
}
document.head.appendChild(link);
}else {
document.title = "EduCoder";
var link = document.createElement('link'),
oldLink = document.getElementById('dynamic-favicon');
link.id = 'dynamic-favicon';
link.rel = 'shortcut icon';
link.href = "/react/build/./favicon.ico";
if (oldLink) {
document.head.removeChild(oldLink);
}
document.head.appendChild(link);
}
}else{
document.title = "EduCoder";
var link = document.createElement('link'),
oldLink = document.getElementById('dynamic-favicon');
link.id = 'dynamic-favicon';
link.rel = 'shortcut icon';
link.href = "/react/build/./favicon.ico";
if (oldLink) {
document.head.removeChild(oldLink);
}
document.head.appendChild(link);
}
}).catch((error) => {
document.title = "EduCoder";
var link = document.createElement('link'),
oldLink = document.getElementById('dynamic-favicon');
link.id = 'dynamic-favicon';
link.rel = 'shortcut icon';
link.href = "/react/build/./favicon.ico";
if (oldLink) {
document.head.removeChild(oldLink);
}
document.head.appendChild(link);
});
};
render() {
let{mygetHelmetapi}=this.state;
// console.log("appappapp");
// console.log(mygetHelmetapi);
return ( return (
<LocaleProvider locale={zhCN}> <LocaleProvider locale={zhCN}>
<MuiThemeProvider theme={theme}> <MuiThemeProvider theme={theme}>
<LoginDialog {...this.props} {...this.state} Modifyloginvalue={()=>this.Modifyloginvalue()}></LoginDialog> <LoginDialog {...this.props} {...this.state} Modifyloginvalue={()=>this.Modifyloginvalue()}></LoginDialog>
<Notcompletedysl {...this.props} {...this.state}></Notcompletedysl> <Notcompletedysl {...this.props} {...this.state}></Notcompletedysl>
@ -413,10 +477,22 @@ class App extends Component {
<Route path="/compatibility" component={CompatibilityPageLoadable}/> <Route path="/compatibility" component={CompatibilityPageLoadable}/>
<Route <Route
path="/login" component={EducoderLogin} path="/login"
render={
(props) => {
return (<EducoderLogin {...this.props} {...props} {...this.state} />)
}
}
/> />
<Route <Route
path="/register" component={EducoderLogin} path="/register"
render={
(props) => {
return (<EducoderLogin {...this.props} {...props} {...this.state} />)
}
}
/> />
<Route <Route
path="/otherloginstart" component={Otherloginstart} path="/otherloginstart" component={Otherloginstart}
@ -440,7 +516,13 @@ class App extends Component {
}></Route> }></Route>
<Route <Route
path="/changepassword" component={EducoderLogin} path="/changepassword"
render={
(props) => {
return (<EducoderLogin {...this.props} {...props} {...this.state} />)
}
}
/> />
<Route <Route
path="/interesse" component={Interestpage} path="/interesse" component={Interestpage}
@ -468,7 +550,7 @@ class App extends Component {
></Route> ></Route>
{/*课堂*/} {/*课堂*/}
<Route path="/courses" component={CoursesIndex} {...this.props}></Route> <Route path="/courses" component={CoursesIndex} {...this.props} {...this.state}></Route>
{/* <Route path="/forums" component={ForumsIndexComponent}> {/* <Route path="/forums" component={ForumsIndexComponent}>
</Route> */} </Route> */}
@ -502,7 +584,12 @@ class App extends Component {
render={ render={
(props)=>(<Ecs {...this.props} {...props} {...this.state}></Ecs>) (props)=>(<Ecs {...this.props} {...props} {...this.state}></Ecs>)
}/> }/>
<Route exact path="/" component={ShixunsHome}/> <Route exact path="/"
// component={ShixunsHome}
render={
(props)=>(<ShixunsHome {...this.props} {...props} {...this.state}></ShixunsHome>)
}
/>
<Route component={Shixunnopage}/> <Route component={Shixunnopage}/>
@ -625,4 +712,4 @@ moment.defineLocale('zh-cn', {
doy: 4 // The week that contains Jan 4th is the first week of the year. doy: 4 // The week that contains Jan 4th is the first week of the year.
} }
}); });
export default SnackbarHOC()(App); export default SnackbarHOC()(App) ;

@ -94,9 +94,15 @@ export function initAxiosInterceptors(props) {
} }
} }
if (requestMap[config.url] === true) { // 避免重复的请求 if (config.method === "post") {
if (requestMap[config.url] === true) { // 避免重复的请求 导致页面f5刷新 也会被阻止 显示这个方法会影响到定制信息定制信息是get 请求
// console.log(config);
// console.log(JSON.parse(config));
// console.log(config.url);
// console.log("被阻止了是重复请求=================================");
return false; return false;
} }
}
// 非file_update请求 // 非file_update请求
if (config.url.indexOf('update_file') === -1) { if (config.url.indexOf('update_file') === -1) {
requestMap[config.url] = true; requestMap[config.url] = true;

@ -209,6 +209,9 @@ class Fileslistitem extends Component{
text-overflow:ellipsis; text-overflow:ellipsis;
white-space:nowrap white-space:nowrap
} }
.mt2{
margin-top:2px;
}
`}</style> `}</style>
<div className="clearfix ds pr contentSection" style={{cursor : this.props.isAdmin ? "pointer" : "default"}} onClick={() => window.$(`.sourceitem${index} input`).click() }> <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)}> <h6 onClick={(event)=>this.eventStop(event)}>
@ -248,6 +251,29 @@ class Fileslistitem extends Component{
:"" :""
} }
{discussMessage.is_publish===false?<CoursesListType typelist={["未发布"]} typesylename={""}/>:""} {discussMessage.is_publish===false?<CoursesListType typelist={["未发布"]} typesylename={""}/>:""}
{this.props.isAdmin?
<span className={"fr mr10 mt2"} onClick={(event)=>this.eventStop(event)}>
<WordsBtn style="blue" className="colorblue font-16 mr20 fr">
<a className="btn colorblue"
onClick={()=>this.settingList()}>设置</a>
</WordsBtn>
</span>:""}
{this.props.isStudent===true&&this.props.current_user.login===discussMessage.author.login?
<span className={"fr mr10 mt2"} onClick={(event)=>this.eventStop(event)}>
<WordsBtn style="blue" className="colorblue font-16 mr20 fr">
<a className="btn colorblue"
onClick={()=>this.settingList()}>设置</a>
</WordsBtn>
<WordsBtn style="blue" className="colorblue font-16 mr20 fr">
<a className="btn colorblue"
onClick={()=>this.onDelete(discussMessage.id)}>删除</a>
</WordsBtn>
</span>:""}
</h6> </h6>
<style> <style>
{ {
@ -303,33 +329,14 @@ class Fileslistitem extends Component{
{ 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?moment(discussMessage.publish_time).fromNow():moment(discussMessage.publish_time).format('YYYY-MM-DD HH:mm')}
</span> </span>
</span> </span>
{this.props.isAdmin? {discussMessage&&discussMessage.category_name===null?"":this.props.child===false?<div className="color-grey9 task-hide fr mr60" title={discussMessage&&discussMessage.category_name}
<span className={"fr mrf2 mr10"} onClick={(event)=>this.eventStop(event)}> style={{"max-width":"268px"}}>所属目录{discussMessage&&discussMessage.category_name}
<WordsBtn style="blue" className="colorblue font-16 mr20 fr"> </div>:""}
<a className="btn colorblue" </p>
onClick={()=>this.settingList()}>设置</a>
</WordsBtn>
</span>:""}
{this.props.isStudent===true&&this.props.current_user.login===discussMessage.author.login?
<span className={"fr mrf2 mr10"} onClick={(event)=>this.eventStop(event)}>
<WordsBtn style="blue" className="colorblue font-16 mr20 fr">
<a className="btn colorblue"
onClick={()=>this.settingList()}>设置</a>
</WordsBtn>
<WordsBtn style="blue" className="colorblue font-16 mr20 fr"> <p className={this.props.isAdmin===true?"color-grey panel-lightgrey mt8 fl ml30":"color-grey panel-lightgrey mt8 fl ml13"} style={{width:'94%'}}>
<a className="btn colorblue"
onClick={()=>this.onDelete(discussMessage.id)}>删除</a>
</WordsBtn>
</span>:""}
</p>
<p className={this.props.isAdmin===true?"color-grey panel-lightgrey mt8 fl ml30":"color-grey panel-lightgrey mt8 fl ml13"} style={{width:'100%'}}>
<style> <style>
{ {
` `

@ -745,6 +745,7 @@ class Fileslists extends Component{
{/*选择资源*/} {/*选择资源*/}
{shixunmodal&&shixunmodal===true?<Selectresource {shixunmodal&&shixunmodal===true?<Selectresource
{...this.props} {...this.props}
{...this.state}
visible={this.state.shixunmodal} visible={this.state.shixunmodal}
shixunmodallist={this.state.shixunmodallist} shixunmodallist={this.state.shixunmodallist}
newshixunmodallist={this.state.newshixunmodallist} newshixunmodallist={this.state.newshixunmodallist}
@ -760,6 +761,7 @@ class Fileslists extends Component{
{/*上传资源*/} {/*上传资源*/}
{Accessoryvisible&&Accessoryvisible===true?<Sendresource {Accessoryvisible&&Accessoryvisible===true?<Sendresource
{...this.props} {...this.props}
{...this.state}
modalname={"上传资源"} modalname={"上传资源"}
visible={Accessoryvisible} visible={Accessoryvisible}
Cancelname={"取消"} Cancelname={"取消"}
@ -770,9 +772,10 @@ class Fileslists extends Component{
has_course_groups={this.state.has_course_groups} has_course_groups={this.state.has_course_groups}
attachmentId={this.state.coursesecondcategoryid} attachmentId={this.state.coursesecondcategoryid}
/>:""} />:""}
{/*设置资源*/}
{Settingtype&&Settingtype===true?<Selectsetting {Settingtype&&Settingtype===true?<Selectsetting
{...this.props} {...this.props}
{...this.state}
Settingtype={Settingtype} Settingtype={Settingtype}
discussMessageid={discussMessageid} discussMessageid={discussMessageid}
course_id={this.props.match.params.coursesId} course_id={this.props.match.params.coursesId}
@ -781,7 +784,18 @@ class Fileslists extends Component{
has_course_groups={this.state.has_course_groups} has_course_groups={this.state.has_course_groups}
attachmentId={this.state.coursesecondcategoryid} attachmentId={this.state.coursesecondcategoryid}
/>:""} />:""}
{child===false?"":<style>
{
`
.filesnameslist{
max-width: 486px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
`
}
</style>}
<Titlesearchsection <Titlesearchsection
title={child===false?"全部资源":name} title={child===false?"全部资源":name}
searchValue={ searchValue } searchValue={ searchValue }
@ -923,6 +937,7 @@ class Fileslists extends Component{
<div key={index}> <div key={index}>
<Fileslistitem <Fileslistitem
{...this.props} {...this.props}
{...this.state}
discussMessage={item} discussMessage={item}
isAdmin={this.props.isAdmin()} isAdmin={this.props.isAdmin()}
isStudent={this.props.isStudent()} isStudent={this.props.isStudent()}

@ -61,7 +61,7 @@ class Titlesearchsection extends Component{
<p className="clearfix padding30 bor-bottom-greyE"> <p className="clearfix padding30 bor-bottom-greyE">
<p style={{height: '20px'}}> <p style={{height: '20px'}}>
<span className="font-18 fl color-dark-21">{title}</span> <span className="font-18 fl color-dark-21 filesnameslist" title={title}>{title}</span>
<li className="fr font-16"> <li className="fr font-16">
{ firstRowRight } { firstRowRight }
</li> </li>

@ -1,17 +1,34 @@
import React,{ Component } from "react"; import React,{ Component } from "react";
import { Modal,Checkbox,Select,Input,Spin,Icon} from "antd"; import { Modal,Checkbox,Select,Input,Spin,Icon,Radio,DatePicker} from "antd";
import locale from 'antd/lib/date-picker/locale/zh_CN';
import axios from'axios'; import axios from'axios';
import {handleDateString} from 'educoder';
import NoneData from "../coursesPublic/NoneData"; import NoneData from "../coursesPublic/NoneData";
import Modals from '../../modals/Modals'; import Modals from '../../modals/Modals';
import moment from 'moment';
const Option = Select.Option; const Option = Select.Option;
const Search = Input.Search; const Search = Input.Search;
const dateFormat ="YYYY-MM-DD HH:mm"
function formatDate(date) { function formatDate(date) {
var dateee = new Date(date).toJSON(); var dateee = new Date(date).toJSON();
return new Date(+new Date(dateee) + 8 * 3600 * 1000).toISOString().replace(/T/g, ' ').replace(/\.[\d]{3}Z/, '') return new Date(+new Date(dateee) + 8 * 3600 * 1000).toISOString().replace(/T/g, ' ').replace(/\.[\d]{3}Z/, '')
} }
function range(start, end) {
const result = [];
for (let i = start; i < end; i++) {
result.push(i);
}
return result;
}
function disabledDateTime() {
return {
disabledMinutes: () => range(1, 30).concat(range(31, 60)),
// disabledSeconds: () => range(1,60)
}
}
function disabledDate(current) {
return current && current < moment().endOf('day').subtract(1, 'days');
}
class Selectresource extends Component{ class Selectresource extends Component{
constructor(props){ constructor(props){
super(props); super(props);
@ -23,7 +40,9 @@ class Selectresource extends Component{
Resourcelist:undefined, Resourcelist:undefined,
hometypepvisible:true, hometypepvisible:true,
getallfiles:false, getallfiles:false,
searchtype:'getallfiles' searchtype:'getallfiles',
Radiovalue:0,
datatime:undefined
} }
} }
componentDidMount() { componentDidMount() {
@ -32,11 +51,7 @@ class Selectresource extends Component{
componentDidUpdate = (prevProps) => { componentDidUpdate = (prevProps) => {
let {getallfiles}=this.state;
if ( prevProps.visible != this.props.visible ) {
}
} }
@ -197,7 +212,7 @@ class Selectresource extends Component{
savecouseShixunModal=()=>{ savecouseShixunModal=()=>{
let {patheditarry}=this.state; let {patheditarry,datatime,Radiovalue}=this.state;
let {coursesId,attachmentId}=this.props; let {coursesId,attachmentId}=this.props;
let url="/files/import.json"; let url="/files/import.json";
@ -212,19 +227,28 @@ class Selectresource extends Component{
}) })
} }
if(this.state.Radiovalue===1){
if(datatime===undefined||datatime===null||datatime=== ""){
this.setState({
Radiovaluetype:true
})
return
}else{
this.setState({
Radiovaluetype:false
})
}
}
axios.post(url, { axios.post(url, {
course_id:coursesId, course_id:coursesId,
attachment_ids:patheditarry, attachment_ids:patheditarry,
course_second_category_id:this.props.coursesidtype===undefined||this.props.coursesidtype==="node"?0:attachmentId, course_second_category_id:this.props.coursesidtype===undefined||this.props.coursesidtype==="node"?0:attachmentId,
delay_publish:Radiovalue,
publish_time:Radiovalue===1?datatime:undefined
} }
).then((response) => { ).then((response) => {
if(response.data.status===0){ if(response.data.status===0){
// this.setState({
// Modalstype:true,
// Modalstopval:response.data.message,
// ModalSave:this.ModalCancelModalCancel,
// loadtype:true
// })
this.ModalCancelModalCancel(); this.ModalCancelModalCancel();
this.props.updataleftNavfun(); this.props.updataleftNavfun();
this.props.showNotification("选用资源成功"); this.props.showNotification("选用资源成功");
@ -236,15 +260,33 @@ class Selectresource extends Component{
} }
selectCloseList=(value)=>{ RadioonChange=(e)=>{
if(e.target.value===0){
this.setState({
datatime:undefined
})
}
this.setState({ this.setState({
category_id:value Radiovalue: e.target.value,
});
}
onChangeTimepublish= (date, dateString) => {
this.setState({
datatime:handleDateString(dateString),
}) })
} }
render(){ render(){
let {Searchvalue,type,category_id,Resourcelist,hometypepvisible,patheditarry}=this.state; let {Searchvalue,type,Resourcelist,hometypepvisible,patheditarry,datatime}=this.state;
let {visible,shixunmodallist}=this.props; let {visible}=this.props;
const antIcon = <Icon type="loading" style={{ fontSize: 24 }} spin />; const antIcon = <Icon type="loading" style={{ fontSize: 24 }} spin />;
const radioStyle = {
display: 'block',
height: '30px',
lineHeight: '30px',
};
return( return(
<div> <div>
{/*提示*/} {/*提示*/}
@ -373,10 +415,36 @@ class Selectresource extends Component{
} }
</div> </div>
<div className={"mt10"}>
<span className={"color-ooo fl mt6 ml20"}>发布设置</span>
<Radio.Group onChange={this.RadioonChange} value={this.state.Radiovalue} style={{'width': '460px'}}>
<Radio style={radioStyle} value={0}>
立即发布
</Radio>
<Radio style={radioStyle} value={1} className={"fl"}>
<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>
<span className={"fl mt5 color-grey-c"}>(按照设置的时间定时发布)</span>
</Radio.Group>
</div>
{this.state.patheditarrytype===true?<p className={"color-red ml20"}>请选择资源</p>:""} {this.state.patheditarrytype===true?<p className={"color-red ml20"}>请选择资源</p>:""}
{this.state.Radiovaluetype===true?<p className={"color-red ml20"}>发布时间不能为空</p>:""}
<div className="mt20 marginauto clearfix edu-txt-center"> <div className="mt20 marginauto clearfix edu-txt-center">
<a className="pop_close task-btn mr30 margin-tp26" onClick={this.hidecouseShixunModal}>取消</a> <a className="pop_close task-btn mr30 margin-tp26" onClick={this.hidecouseShixunModal}>取消</a>
<a className="task-btn task-btn-orange margin-tp26" id="submit_send_shixun" onClick={this.savecouseShixunModal}>确定</a> <a className="task-btn task-btn-orange margin-tp26" id="submit_send_shixun" onClick={this.savecouseShixunModal}>确定</a>

@ -1,5 +1,5 @@
import React,{ Component } from "react"; import React,{ Component } from "react";
import { Modal,Checkbox,Select,Input,Upload,Button,Icon,message,DatePicker,Tooltip} from "antd"; import { Modal,Checkbox,Select,Input,Upload,Button,Icon,message,DatePicker,Tooltip,Radio} from "antd";
import axios from'axios'; import axios from'axios';
import {getUrl,handleDateString,appendFileSizeToUploadFileAll} from 'educoder'; import {getUrl,handleDateString,appendFileSizeToUploadFileAll} from 'educoder';
import locale from 'antd/lib/date-picker/locale/zh_CN'; import locale from 'antd/lib/date-picker/locale/zh_CN';
@ -36,9 +36,10 @@ class Selectsetting extends Component{
course_groups:undefined, course_groups:undefined,
attachment_histories:undefined, attachment_histories:undefined,
datatime:undefined, datatime:undefined,
unified_setting:true,
fileList:[], fileList:[],
fileListtype:false fileListtype:false,
is_public:false,
Radiovaluetype:false
} }
} }
@ -54,53 +55,13 @@ class Selectsetting extends Component{
}) })
.then((response) => { .then((response) => {
if(response.status===200){ if(response.status===200){
let newcourse_groups=[];
let list =response.data.course_groups;
// let list=[
// {
// "course_group_id": 820,
// "course_group_name": "示例A班",
// "course_group_publish_time": "2019-04-18T17:00:00.000+08:00"
// },
// {
// "course_group_id": 821,
// "course_group_name": "示例B班",
// "course_group_publish_time": "2019-04-19T19:00:00.000+08:00"
// },
// {
// "course_group_id": 822,
// "course_group_name": "示例C班",
// "course_group_publish_time": "2019-04-10T19:00:00.000+08:00"
// }
// ]
if(list.length!=0){
list.forEach((item,key)=>{
newcourse_groups.push ({
course_group_id:item.course_group_id,
course_group_name:item.course_group_id,
publish_time:moment(item.course_group_publish_time).format(dateFormat)
})
})
}else{
newcourse_groups.push ({
course_group_id:undefined,
course_group_name:undefined,
publish_time:""
})
}
this.setState({ this.setState({
datalist:response.data, datalist:response.data,
description: response.data.description, description: response.data.description,
is_public: response.data.is_public, is_public:response.data.is_public,
unified_setting: response.data.unified_setting,
datatime:response.data.publish_time, datatime:response.data.publish_time,
// is_public:response.data.course_groups, Radiovalue:response.data.delay_publish==false?0:1,
//attachment_histories:response.data.attachment_histories //attachment_histories:response.data.attachment_histories
course_groups:newcourse_groups
}) })
} }
@ -110,23 +71,6 @@ class Selectsetting extends Component{
}); });
let coursesId=this.props.match.params.coursesId;
if(this.props.isAdmin()){
let url = `/courses/${coursesId}/all_course_groups.json`
axios.get(url, {
})
.then((response) => {
this.setState({
course_groupss: response.data.course_groups,
})
})
.catch(function (error) {
console.log(error);
});
}
} }
@ -145,21 +89,6 @@ class Selectsetting extends Component{
this.getalldata() this.getalldata()
} }
}
onChangepublics=(e)=>{
console.log(e.target.checked)
this.setState({
is_public:e.target.checked
})
}
onChangesettings=(e)=>{
console.log(e.target.checked)
this.setState({
unified_setting:e.target.checked
})
} }
settextarea=(e)=>{ settextarea=(e)=>{
@ -180,13 +109,26 @@ class Selectsetting extends Component{
} }
savecouseShixunModal=()=>{ savecouseShixunModal=()=>{
let {fileList,is_public,unified_setting,description,datatime,course_groups}=this.state; let {fileList,is_public,description,datatime,Radiovalue}=this.state;
let newfileList=[]; let newfileList=[];
for(var list of fileList){ for(var list of fileList){
newfileList.push(list.response.id) newfileList.push(list.response.id)
} }
if(this.state.Radiovalue===1){
if(datatime===undefined||datatime===null||datatime=== ""){
this.setState({
Radiovaluetype:true
})
return
}else{
this.setState({
Radiovaluetype:false
})
}
}
if(description===undefined||description===null){ if(description===undefined||description===null){
}else if(description.length>100){ }else if(description.length>100){
@ -196,29 +138,6 @@ class Selectsetting extends Component{
return return
} }
// course_groups.forEach((item,key)=>{
// if(item.course_group_id===undefined||item.publish_time===undefined){
// this.setState({
// course_group_publish_timestype:true
// })
// return
// }
// })
// if(unified_setting===false){
//
// course_groups.forEach((item,key)=>{
// if(item.course_group_id===undefined){
// this.setState({
// course_group_idtypes:true
// })
// return
// }
// })
//
// }
let coursesId=this.props.match.params.coursesId; let coursesId=this.props.match.params.coursesId;
let attachmentId=this.props.attachmentId; let attachmentId=this.props.attachmentId;
let url="/files/"+this.props.discussMessageid+".json"; let url="/files/"+this.props.discussMessageid+".json";
@ -226,14 +145,12 @@ class Selectsetting extends Component{
axios.put(url,{ axios.put(url,{
course_id:coursesId, course_id:coursesId,
new_attachment_id:newfileList.length===0?undefined:newfileList, new_attachment_id:newfileList.length===0?undefined:newfileList,
course_second_category_id:this.props.coursesidtype===undefined||this.props.coursesidtype==="node"?0:attachmentId, course_second_category_id:this.props.coursesidtype===undefined||this.props.coursesidtype==="node"?0:attachmentId,
is_public:is_public, is_public:is_public,
is_unified_setting:unified_setting, publish_time:Radiovalue===0?undefined:datatime===undefined?moment(new Date(),dateFormat):datatime,
publish_time:unified_setting===true?datatime===undefined?moment(new Date()).format('YYYY-MM-DD HH'):datatime:undefined,
description:description, description:description,
course_group_publish_times:unified_setting===false?course_groups:undefined delay_publish:Radiovalue
}).then((result)=>{ }).then((result)=>{
if(result.data.status===0){ if(result.data.status===0){
this.props.setupdate(attachmentId) this.props.setupdate(attachmentId)
this.props.showNotification("设置资源成功"); this.props.showNotification("设置资源成功");
@ -244,7 +161,6 @@ class Selectsetting extends Component{
} }
onChangeTimepublish= (date, dateString) => { onChangeTimepublish= (date, dateString) => {
// console.log('startValue', dateString);
this.setState({ this.setState({
datatime:handleDateString(dateString), datatime:handleDateString(dateString),
}) })
@ -268,31 +184,6 @@ class Selectsetting extends Component{
} }
} }
// onAttachmentRemove = (file) => {
// // confirm({
// // title: '确定要删除这个附件吗?',
// // okText: '确定',
// // cancelText: '取消',
// // // content: 'Some descriptions',
// // onOk: () => {
// // this.deleteAttachment(file)
// // },
// // onCancel() {
// // console.log('Cancel');
// // },
// // });
// // return false;
//
// // this.setState({
// // Modalstype:true,
// // Modalstopval:'确定要删除这个附件吗?',
// // ModalSave: ()=>this.deleteAttachment(file),
// // ModalCancel:this.cancelAttachment
// // })
// // return false;
//
// this.deleteAttachment(file);
// }
onAttachmentRemove = (file) => { onAttachmentRemove = (file) => {
@ -309,14 +200,7 @@ class Selectsetting extends Component{
fileListtype:false, fileListtype:false,
fileList:[] fileList:[]
}) })
// this.setState((state) => {
// const index = state.fileList.indexOf(file);
// const newFileList = state.fileList.slice();
// newFileList.splice(index, 1);
// return {
// fileList: newFileList,
// };
// });
} }
} }
}) })
@ -332,63 +216,28 @@ class Selectsetting extends Component{
fileList:[] fileList:[]
}) })
} }
// const url = `/attachments/${file.response ? file.response.id : file.uid}.json`
} }
onChangeTimepublishs= (date, dateString,key) => { onChangepublic=(e)=>{
let {course_groups}=this.state;
let newgroup_publish=course_groups;
for(var i=0; i<newgroup_publish.length; i++){
if(i===parseInt(key)){
newgroup_publish[i].publish_time=handleDateString(dateString);
}
}
this.setState({ this.setState({
course_groups:newgroup_publish, is_public:e.target.checked
}) })
} }
RadioonChange=(e)=>{
if(e.target.value===0){
selectassigngroups=(e,index,key)=>{ this.setState({
let {course_groups}=this.state; datatime:undefined
let newgroup_publish=course_groups; })
for(var i=0; i<newgroup_publish.length; i++){
if(i===parseInt(key)){
newgroup_publish[i].course_group_id=index.props.value;
}
} }
this.setState({ this.setState({
course_groups:newgroup_publish, Radiovalue: e.target.value,
}) });
}
deletegrouppublish=(key)=>{
let newlist=this.state.course_groups;
newlist.splice(key,1);
this.setState({
course_groups:newlist
})
}
addgrouppublish=()=>{
let newlist=this.state.course_groups;
newlist.push( {
course_group_id : undefined,
publish_time :""
// moment(new Date()).format('YYYY-MM-DD HH:mm')
})
this.setState({
course_groups:newlist
})
} }
render(){ render(){
let {is_public,unified_setting,course_groups,datatime,description,datalist,course_group_publish_timestype}=this.state; let {datatime,description,datalist}=this.state;
const uploadProps = { const uploadProps = {
width: 600, width: 600,
// https://github.com/ant-design/ant-design/issues/15505
// showUploadList={false},然后外部拿到 fileList 数组自行渲染列表。
// showUploadList: false,
action: `${getUrl()}/api/attachments.json`, action: `${getUrl()}/api/attachments.json`,
onChange: this.handleChange, onChange: this.handleChange,
onRemove: this.onAttachmentRemove, onRemove: this.onAttachmentRemove,
@ -401,9 +250,13 @@ class Selectsetting extends Component{
return isLt150M; return isLt150M;
}, },
}; };
const radioStyle = {
display: 'block',
height: '30px',
lineHeight: '30px',
};
console.log(this.state.Radiovalue)
// console.log(this.props.has_course_groups)
return( return(
<div> <div>
<style> <style>
@ -461,9 +314,9 @@ class Selectsetting extends Component{
.fontlefts{text-align: left; text-align: center;} .fontlefts{text-align: left; text-align: center;}
`}</style> `}</style>
<ul className="clearfix greybackHead edu-txt-center"> <ul className="clearfix greybackHead edu-txt-center">
<li className="fl paddingleft22 fontlefts" style={{width:'220px'}}>资源名称</li> <li className="fl paddingleft22 fontlefts" style={{width:'330px'}}>资源名称</li>
<li className="fl edu-txt-left" style={{width:'80px'}}>下载</li> <li className="fl edu-txt-left" style={{width:'80px'}}>下载</li>
<li className="fl" style={{width:'100px'}}>引用</li> {/*<li className="fl" style={{width:'100px'}}>引用</li>*/}
<li className="fl" style={{width:'130px'}}>版本号</li> <li className="fl" style={{width:'130px'}}>版本号</li>
</ul> </ul>
@ -490,7 +343,7 @@ class Selectsetting extends Component{
`}</style> `}</style>
<div className="pl20 pr20 settingbox"> <div className="pl20 pr20 settingbox">
<div className="clearfix edu-txt-center lineh-40 bor-bottom-greyE"> <div className="clearfix edu-txt-center lineh-40 bor-bottom-greyE">
<li className="fl" style={{width: '241px'}}> <li className="fl" style={{width: '350px'}}>
<span className={"isabox"} title={datalist&&datalist.title}> {datalist&&datalist.title} </span> <span className={"isabox"} title={datalist&&datalist.title}> {datalist&&datalist.title} </span>
{datalist&&datalist.attachment_histories.length===0?"":<span className={"newcolor-orange fl"}>当前版本</span>} {datalist&&datalist.attachment_histories.length===0?"":<span className={"newcolor-orange fl"}>当前版本</span>}
</li> </li>
@ -505,13 +358,13 @@ class Selectsetting extends Component{
{datalist&&datalist.attachment_histories.map((item,key)=>{ {datalist&&datalist.attachment_histories.map((item,key)=>{
return( return(
<div className="clearfix edu-txt-center lineh-40 bor-bottom-greyE" key={key}> <div className="clearfix edu-txt-center lineh-40 bor-bottom-greyE" key={key}>
<li className="fl" style={{width: '241px'}}> <li className="fl" style={{width: '350px'}}>
<span className={"isabox"} title={item.title}> {item.title} </span> <span className={"isabox"} title={item.title}> {item.title} </span>
{/*<span className={"newcolor-orange fl"}>当前版本</span>*/} {/*<span className={"newcolor-orange fl"}>当前版本</span>*/}
</li> </li>
<li className="fl edu-txt-left task-hide paddingl5 " <li className="fl edu-txt-left task-hide paddingl5 "
style={{width: '76px'}}> {item.downloads_count} </li> style={{width: '76px'}}> {item.downloads_count} </li>
<li className="fl paddingl10 " style={{width: '100px'}}> {item.quotes} </li> {/*<li className="fl paddingl10 " style={{width: '100px'}}> {item.quotes} </li>*/}
<li className="fl paddingl10 datastyle"> <li className="fl paddingl10 datastyle">
{moment(item.created_on).format('YYYY-MM-DD HH:mm')==="Invalid date"?"":moment(item.created_on).format('YYYY-MM-DD HH:mm')} {moment(item.created_on).format('YYYY-MM-DD HH:mm')==="Invalid date"?"":moment(item.created_on).format('YYYY-MM-DD HH:mm')}
</li> </li>
@ -607,61 +460,15 @@ class Selectsetting extends Component{
</Upload> </Upload>
</p> </p>
{/*<style>*/}
{/*{*/}
{/*`*/}
{/*.maxwidth400{*/}
{/*max-width: 400px;*/}
{/*overflow: hidden;*/}
{/*text-overflow: ellipsis;*/}
{/*white-space: nowrap;*/}
{/*}*/}
{/*`*/}
{/*}*/}
{/*</style>*/}
{/*{this.state.fileList.length===0?"":this.state.fileList.map((item,key)=>{*/}
{/*return(*/}
{/*<p className="color-grey mt10" key={key} >*/}
{/*<a className="color-grey fl">*/}
{/*<i className="font-14 color-green iconfont icon-fujian mr8" aria-hidden="true"></i>*/}
{/*</a>*/}
{/*<span className="mr12 color9B9B maxwidth400 fl" length="58">*/}
{/*{item.name}*/}
{/*</span>*/}
{/*<span className="color656565 mt2 color-grey-6 font-12 mr8">*/}
{/*{item.response===undefined?"":isNaN(bytesToSize(item.filesize))?"123":bytesToSize(item.filesize)}*/}
{/*</span>*/}
{/*<i className="font-14 iconfont icon-guanbi "*/}
{/*id={item.response===undefined?"":item.response.id}*/}
{/*aria-hidden="true" onClick={()=>this.onAttachmentRemove(item.response===undefined?"":item.response.id&&item.response.id)}></i>*/}
{/*</p>*/}
{/*)*/}
{/*})}*/}
{this.state.newfileListtypes===true?<p className={"color-red"}>请先上传资源</p>:""} {this.state.newfileListtypes===true?<p className={"color-red"}>请先上传资源</p>:""}
<p className={this.state.fileListtype===true?"mt15":""}> <p className={this.state.fileListtype===true?"mt15 selecboxfilas":"selecboxfilas"}>
<style>{` <style>{`
.ant-checkbox-wrapper{ .selecboxfilas .ant-checkbox-wrapper{
margin-left:0px !important; margin-left:0px !important;
margin-top:10px; margin-top:10px;
} }
`}</style> `}</style>
{/*<div className={this.state.fileListtype===true?"mt30":""}>*/}
{/*<Checkbox*/}
{/*checked={is_public}*/}
{/*onChange={this.onChangepublics}>*/}
{/*<span className={"font-14"}>勾选后所有用户可见,否则仅课堂成员可见</span>*/}
{/*</Checkbox>*/}
{/*</div>*/}
{/*{this.props.has_course_groups&&this.props.has_course_groups===true?:""}*/}
{this.state.course_groupss&&this.state.course_groupss.length>0?<Checkbox
checked={unified_setting}
onChange={this.onChangesettings}>
<span>统一设置</span><span className={"font-14 color-grey-9"}>(使)</span>
</Checkbox>:""}
<style> <style>
{` {`
.Selectleft20{ .Selectleft20{
@ -675,53 +482,11 @@ class Selectsetting extends Component{
} }
`} `}
</style> </style>
{this.props.course_is_public===true?<div>
<span className={"color-ooo"}>公开</span><Checkbox checked={this.state.is_public} onChange={(e)=>this.onChangepublic(e)}>
{/*this.props.has_course_groups&&this.props.has_course_groups===true?:""*/} <span className={"font-14 color-ooo"}>选中所有用户可见否则课堂成员可见</span>
<div className={"resourcebox"}> </Checkbox>
{unified_setting===false? </div>:""}
this.state.course_groups&&this.state.course_groups.map((item,key)=>{
return(
<div className={"mt10 "} key={key}>
<Select placeholder="请选择分班名称"
value={item.course_group_id}
style={{ width: 200 }}
onChange={(e,index)=>this.selectassigngroups(e,index,key)}
>
{ this.state.course_groupss&&this.state.course_groupss.map((item,key)=>{
return(
<Option value={item.id} key={key}>{item.name}</Option>
)
})}
</Select>
<DatePicker
showToday={false}
dropdownClassName="hideDisable"
showTime={{ format: 'HH:mm' }}
format="YYYY-MM-DD HH:mm"
locale={locale}
placeholder="请选择发布时间"
id={"startimes"}
className={"Selectleft20"}
width={"200px"}
value={item.publish_time===undefined||item.publish_time===""?"":item.publish_time===null?"":moment(item.publish_time, dateFormat)}
onChange={(e,index)=>this.onChangeTimepublishs(e,index,key)}
// onChange={ this.onChangeTimepublish }
disabledTime={disabledDateTime}
disabledDate={disabledDate}
/>
{key!=0?<i className="iconfont icon-shanchu color-grey-c font-14 font-n ml20" onClick={()=>this.deletegrouppublish(key)}></i>:""}
{key===course_groups.length-1?<i className="iconfont icon-tianjiafangda color-green ml15" onClick={this.addgrouppublish}></i>:""}
</div>
)
}):""}
</div>
</p> </p>
<style> <style>
{` {`
@ -730,28 +495,36 @@ class Selectsetting extends Component{
} }
`} `}
</style> </style>
{unified_setting===true?
<p className={"mt10"}> <div className={this.props.course_is_public===true?"mt10":""}>
<span> <span className={"color-ooo fl mt6"}>发布设置</span>
<DatePicker <Radio.Group onChange={(e)=>this.RadioonChange(e)} value={this.state.Radiovalue} style={{'width': '460px'}}>
showToday={false} <Radio style={radioStyle} value={0}>
dropdownClassName="hideDisable" 立即发布
showTime={{ format: 'HH:mm' }} </Radio>
format="YYYY-MM-DD HH:mm" <Radio style={radioStyle} value={1} className={"fl"}>
locale={locale} <span className={"mr5"}>延迟发布</span>
placeholder="请选择发布时间" <DatePicker
id={"startime"}
width={"210px"} showToday={false}
value={datatime===undefined||datatime===""?"":moment(datatime, dateFormat)} dropdownClassName="hideDisable"
onChange={this.onChangeTimepublish} showTime={{ format: 'HH:mm' }}
disabledTime={disabledDateTime} format="YYYY-MM-DD HH:mm"
disabledDate={disabledDate} locale={locale}
/> placeholder="请选择发布时间"
</span> id={"startime"}
</p>:""} width={"210px"}
{/*{this.state.course_group_idtypes===true?<p className={"color-red"}>请选择分班</p>:""}*/} value={datatime===undefined||datatime===""?"":moment(datatime, dateFormat)}
onChange={this.onChangeTimepublish}
{/*{course_group_publish_timestype===true?<p className={"color-red mt10"}>请填写完整</p>:""}*/} disabledTime={disabledDateTime}
disabledDate={disabledDate}
disabled={this.state.Radiovalue===1?false:true}
/>
</Radio>
<span className={"fl mt5 color-grey-c"}>(按照设置的时间定时发布)</span>
</Radio.Group>
</div>
<textarea placeholder="请输入资源描述最大限制100个字符" className={"mt10"} value={description} onInput={this.settextarea} style={{ <textarea placeholder="请输入资源描述最大限制100个字符" className={"mt10"} value={description} onInput={this.settextarea} style={{
width: '100%', width: '100%',
@ -760,6 +533,7 @@ class Selectsetting extends Component{
padding: '10px' padding: '10px'
}}></textarea> }}></textarea>
{this.state.descriptiontypes===true?<p className={"color-red"}>描述不能超过最大限制100个字符</p>:""} {this.state.descriptiontypes===true?<p className={"color-red"}>描述不能超过最大限制100个字符</p>:""}
{this.state.Radiovaluetype===true?<p className={"color-red"}>发布时间不能为空</p>:""}
</div> </div>
<div className="mt20 marginauto clearfix edu-txt-center"> <div className="mt20 marginauto clearfix edu-txt-center">

@ -1,9 +1,11 @@
import React, { Component } from "react"; import React, { Component } from "react";
import { Modal, Checkbox, Input, Spin} from "antd"; import { Modal, Checkbox, Input, Spin} from "antd";
import axios from 'axios' import axios from 'axios';
import moment from 'moment';
import ModalWrapper from "../common/ModalWrapper"; import ModalWrapper from "../common/ModalWrapper";
import InfiniteScroll from 'react-infinite-scroller'; import InfiniteScroll from 'react-infinite-scroller';
const dateFormat ="YYYY-MM-DD HH:mm"
const Search = Input.Search const Search = Input.Search
const pageCount = 15; const pageCount = 15;
class Sendtofilesmodal extends Component{ class Sendtofilesmodal extends Component{
@ -170,7 +172,12 @@ class Sendtofilesmodal extends Component{
bottom: 93px; bottom: 93px;
width: 82%; width: 82%;
text-align: center; text-align: center;
}`} }
.ModalWrappertitle{
background: #D0E8FC;
padding: 10px;
}
`}
</style> </style>
<p className="color-grey-6 mb20 edu-txt-center" style={{ fontWeight: "bold" }} >选择的{moduleName}发送到<span className="color-orange-tip">指定课堂</span></p> <p className="color-grey-6 mb20 edu-txt-center" style={{ fontWeight: "bold" }} >选择的{moduleName}发送到<span className="color-orange-tip">指定课堂</span></p>
@ -183,7 +190,12 @@ class Sendtofilesmodal extends Component{
></Search> ></Search>
<div> <div>
{/* https://github.com/CassetteRocks/react-infinite-scroller/issues/70 */}
<p className="clearfix ModalWrappertitle">
<div className="task-hide fl pagemancenter" style={{"width":'215px'}}>课堂名称</div>
<div className="task-hide fl pagemancenter" style={{"width":'140px'}}>创建时间</div>
<div className="task-hide fl pagemancenter" style={{"width":'110px'}}>结束时间</div>
</p>
<div className="edu-back-skyblue padding15" style={{"height":"300px", overflowY: "scroll", overflowAnchor: 'none' }}> <div className="edu-back-skyblue padding15" style={{"height":"300px", overflowY: "scroll", overflowAnchor: 'none' }}>
<InfiniteScroll <InfiniteScroll
threshold={10} threshold={10}
@ -199,20 +211,14 @@ class Sendtofilesmodal extends Component{
return ( return (
<p className="clearfix mb7" key={course.id}> <p className="clearfix mb7" key={course.id}>
<Checkbox className="fl" value={course.id} key={course.id} ></Checkbox> <Checkbox className="fl" value={course.id} key={course.id} ></Checkbox>
<span className="fl with45"><label className="task-hide fl" style={{"maxWidth":"208px;"}}>{course.name}</label></span> <div className="task-hide fl" style={{"width":'224px'}} title={course.name}>{course.name}</div>
<div className="task-hide fl" style={{"width":'130px'}}>{moment(course.created_at).format('YYYY-MM-DD')}</div>
<div className="task-hide fl" style={{"width":'110px'}}>{course.end_date}</div>
</p> </p>
) )
}) } }) }
</Checkbox.Group> </Checkbox.Group>
{loading && hasMore && (
<div className="demo-loading-container">
<Spin />
</div>
)}
{/* TODO */}
{/* {
!hasMore && <div>没有更多了</div>
} */}
</InfiniteScroll> </InfiniteScroll>
</div> </div>

@ -1,5 +1,5 @@
import React,{ Component } from "react"; import React,{ Component } from "react";
import { Modal,Checkbox,Upload,Button,Icon,message,DatePicker,Select,Tooltip} from "antd"; import { Modal,Checkbox,Upload,Button,Icon,message,DatePicker,Select,Tooltip,Radio} from "antd";
import axios from 'axios'; import axios from 'axios';
import Modals from '../../modals/Modals'; import Modals from '../../modals/Modals';
import {getUrl,handleDateString,bytesToSize,appendFileSizeToUploadFileAll} from 'educoder'; import {getUrl,handleDateString,bytesToSize,appendFileSizeToUploadFileAll} from 'educoder';
@ -40,7 +40,6 @@ class Sendresource extends Component{
ModalSave:"", ModalSave:"",
fileListtype:false, fileListtype:false,
loadtype:false, loadtype:false,
is_unified_setting:true,
is_public:false, is_public:false,
datatime:undefined, datatime:undefined,
// moment(new Date()).format('YYYY-MM-DD HH:mm:ss'), // moment(new Date()).format('YYYY-MM-DD HH:mm:ss'),
@ -50,30 +49,15 @@ class Sendresource extends Component{
publish_time :"" publish_time :""
}], }],
course_groups:undefined, course_groups:undefined,
course_groups_count:undefined course_groups_count:undefined,
Radiovalue:0,
Radiovaluetype:false
} }
} }
componentDidMount() { componentDidMount() {
let coursesId=this.props.match.params.coursesId;
if(this.props.isAdmin()){
let url = `/courses/${coursesId}/all_course_groups.json`
axios.get(url, {
})
.then((response) => {
this.setState({
course_groups: response.data.course_groups,
course_groups_count:response.data.course_groups_count
})
})
.catch(function (error) {
console.log(error);
});
}
} }
//勾选实训 //勾选实训
@ -101,37 +85,6 @@ class Sendresource extends Component{
} }
} }
// onAttachmentRemove = (file) => {
//
// this.setState({
// fileListtype:false,
// })
// // confirm({
// // title: '确定要删除这个附件吗?',
// // okText: '确定',
// // cancelText: '取消',
// // // content: 'Some descriptions',
// // onOk: () => {
// // this.deleteAttachment(file)
// // },
// // onCancel() {
// // console.log('Cancel');
// // },
// // });
// // return false;
//
// // this.setState({
// // Modalstype:true,
// // Modalstopval:'确定要删除这个附件吗?',
// // ModalSave: ()=>this.deleteAttachment(file),
// // ModalCancel:this.cancelAttachment
// // })
// // return false;
//
// this.deleteAttachment(file);
// }
onAttachmentRemove = (file) => { onAttachmentRemove = (file) => {
if(!file.percent || file.percent == 100){ if(!file.percent || file.percent == 100){
const url = `/attachments/${file.response ? file.response.id : file.uid}.json` const url = `/attachments/${file.response ? file.response.id : file.uid}.json`
@ -174,8 +127,7 @@ class Sendresource extends Component{
} }
Saves=()=>{ Saves=()=>{
let id=this.props.categoryid; let {fileList,description,is_public,datatime,Radiovalue} =this.state;
let {fileList,description,is_public,is_unified_setting,datatime,course_group_publish_times} =this.state;
let newfileList=[]; let newfileList=[];
for(var list of fileList){ for(var list of fileList){
@ -188,17 +140,19 @@ class Sendresource extends Component{
}) })
return return
} }
// if(is_unified_setting===false){
// course_group_publish_times.forEach((item,key)=>{ if(this.state.Radiovalue===1){
// if(item.course_group_id===undefined||item.publish_time===undefined){ if(datatime===undefined||datatime===null||datatime=== ""){
// this.setState({ this.setState({
// course_group_publish_timestype:true Radiovaluetype:true
// }) })
// return return
// } }else{
// }) this.setState({
// Radiovaluetype:false
// } })
}
}
@ -222,22 +176,14 @@ class Sendresource extends Component{
course_second_category_id:this.props.coursesidtype===undefined||this.props.coursesidtype==="node"?0:attachmentId, course_second_category_id:this.props.coursesidtype===undefined||this.props.coursesidtype==="node"?0:attachmentId,
attachment_ids:newfileList, attachment_ids:newfileList,
is_public:is_public, is_public:is_public,
is_unified_setting:is_unified_setting, publish_time:Radiovalue===1?datatime===undefined? undefined:datatime:undefined,
publish_time:is_unified_setting===true?datatime===undefined? moment(new Date()).format('YYYY-MM-DD HH:mm'):datatime:undefined,
description:description, description:description,
course_group_publish_times:is_unified_setting===false?course_group_publish_times:undefined delay_publish:Radiovalue,
}).then((result)=>{ }).then((result)=>{
if(result.data.status===0){ if(result.data.status===0){
// this.setState({
// Modalstype:true,
// Modalstopval:result.data.message,
// ModalSave:this.ModalCancelModalCancel,
// loadtype:true
// })
this.ModalCancelModalCancel(); this.ModalCancelModalCancel();
this.props.updataleftNavfun(); this.props.updataleftNavfun();
// this.props.showNotification(result.data.message);
this.props.showNotification("上传资源成功"); this.props.showNotification("上传资源成功");
this.props.setupdate(this.props.attachmentId) this.props.setupdate(this.props.attachmentId)
} }
@ -253,14 +199,6 @@ class Sendresource extends Component{
}) })
} }
onChangesetting=(e)=>{
this.setState({
is_unified_setting:e.target.checked
})
}
onChangepublic=(e)=>{ onChangepublic=(e)=>{
this.setState({ this.setState({
@ -289,50 +227,20 @@ class Sendresource extends Component{
} }
selectassigngroups=(e,index,key)=>{ RadioonChange=(e)=>{
let {course_group_publish_times}=this.state; if(e.target.value===0){
let newgroup_publish=course_group_publish_times; this.setState({
for(var i=0; i<newgroup_publish.length; i++){ datatime:undefined
if(i===parseInt(key)){ })
newgroup_publish[i].course_group_id=index.props.value;
}
} }
this.setState({ this.setState({
course_group_publish_times:newgroup_publish, Radiovalue: e.target.value,
}) });
} }
deletegrouppublish=(key)=>{
let newlist=this.state.course_group_publish_times;
newlist.splice(key,1);
this.setState({
course_group_publish_times:newlist
})
}
addgrouppublish=()=>{
let newlist=this.state.course_group_publish_times;
newlist.push( {
course_group_id : undefined,
publish_time :undefined
})
this.setState({
course_group_publish_times:newlist
})
}
render(){ render(){
let {settextarea,newfileListtype,descriptiontype, let { newfileListtype,descriptiontype,
course_group_publish_timestype,
Modalstopval,
ModalCancel,
ModalSave,
loadtype,
is_unified_setting,
is_public, is_public,
datatime, datatime,
course_group_publish_times,
course_groups
}=this.state; }=this.state;
const uploadProps = { const uploadProps = {
@ -350,7 +258,11 @@ class Sendresource extends Component{
return isLt150M; return isLt150M;
}, },
}; };
const radioStyle = {
display: 'block',
height: '30px',
lineHeight: '30px',
};
return( return(
<div> <div>
{/*提示*/} {/*提示*/}
@ -389,6 +301,7 @@ class Sendresource extends Component{
margin-right: 5px; margin-right: 5px;
} }
.ant-upload-list-item:hover .ant-upload-list-item-info{ .ant-upload-list-item:hover .ant-upload-list-item-info{
padding: 0 12px 0 0px;
background-color:#fff; background-color:#fff;
} }
.upload_1 .ant-upload-list { .upload_1 .ant-upload-list {
@ -437,42 +350,12 @@ class Sendresource extends Component{
<Button className="uploadBtn"> <Button className="uploadBtn">
<Icon type="upload" /> 选择文件 <Icon type="upload" /> 选择文件
</Button> </Button>
<span className={"ml10"}>(单个文件最大150M)</span> <span className={"ml10 color-ooo"}>(单个文件最大150M)</span>
</span>:""} </span>:""}
</Upload> </Upload>
</p> </p>
{/*<style>*/}
{/*{*/}
{/*`*/}
{/*.maxwidth400{*/}
{/*max-width: 400px;*/}
{/*overflow: hidden;*/}
{/*text-overflow: ellipsis;*/}
{/*white-space: nowrap;*/}
{/*}*/}
{/*`*/}
{/*}*/}
{/*</style>*/}
{/*{this.state.fileList.length===0?"":this.state.fileList.map((item,key)=>{*/}
{/*debugger*/}
{/*return(*/}
{/*<p className="color-grey mt10" key={key} >*/}
{/*<a className="color-grey fl">*/}
{/*<i className="font-14 color-green iconfont icon-fujian mr8" aria-hidden="true"></i>*/}
{/*</a>*/}
{/*<span className="mr12 color9B9B maxwidth400 fl" length="58">*/}
{/*{item.name}*/}
{/*</span>*/}
{/*<span className="color656565 mt2 color-grey-6 font-12 mr8">*/}
{/*{item.response===undefined?"":isNaN(bytesToSize(item.filesize))?"":bytesToSize(item.filesize)}*/}
{/*</span>*/}
{/*<i className="font-14 iconfont icon-guanbi "*/}
{/*id={item.response===undefined?"":item.response.id}*/}
{/*aria-hidden="true" onClick={()=>this.onAttachmentRemove(item.response===undefined?"":item.response.id&&item.response.id)}></i>*/}
{/*</p>*/}
{/*)*/}
{/*})}*/}
{newfileListtype===true&&this.state.fileListtype===false?<p className={"color-red"}>请先上传资源</p>:""} {newfileListtype===true&&this.state.fileListtype===false?<p className={"color-red"}>请先上传资源</p>:""}
@ -484,13 +367,12 @@ class Sendresource extends Component{
} }
`}</style> `}</style>
{/*<div className={this.state.fileListtype===true?"mt30":""}></div><Checkbox checked={is_public} onChange={this.onChangepublic}>*/} {this.props.course_is_public===true?<div>
{/*<span className={"font-14"}>勾选后所有用户可见,否则仅课堂成员可见</span>*/} <span className={"color-ooo"}>公开</span><Checkbox checked={is_public} onChange={this.onChangepublic}>
{/*</Checkbox>*/} <span className={"font-14 color-ooo"}>选中所有用户可见否则课堂成员可见</span>
</Checkbox>
</div>:""}
{this.state.course_groups_count&&this.state.course_groups_count>0?<Checkbox checked={is_unified_setting} onChange={this.onChangesetting}>
<span>统一设置</span><span className={"font-14 color-grey-9"}>(使)</span>
</Checkbox>:""}
<style>{` <style>{`
.Selectleft20{ .Selectleft20{
margin-left: 20px !important; margin-left: 20px !important;
@ -505,69 +387,38 @@ class Sendresource extends Component{
overflow: auto; overflow: auto;
} }
`}</style> `}</style>
<div className={"resourcebox"}>
{is_unified_setting===false?
course_group_publish_times.map((item,key)=>{
return(
<div className={"mt10"} key={key}>
<Select placeholder="请选择分班名称"
value={item.course_group_id}
style={{ width: 200 }}
onChange={(e,index)=>this.selectassigngroups(e,index,key)}
>
{course_groups&&course_groups.map((item,key)=>{
return(
<Option value={item.id} key={key}>{item.name}</Option>
)
})}
</Select>
<DatePicker
dropdownClassName="hideDisable"
showTime={{ format: 'HH:mm' }}
locale={locale}
showToday={false}
format={dateFormat}
placeholder="请选择发布时间"
id={"startimes"}
className={"Selectleft20 "}
width={"200px"}
value={item.publish_time===undefined||item.publish_time===""?undefined:moment(item.publish_time, dateFormat)}
onChange={(e,index)=>this.onChangeTimepublish(e,index,key,2)}
// onChange={ this.onChangeTimepublish }
disabledTime={disabledDateTime}
disabledDate={disabledDate}
/>
{key!=0?<i className="iconfont icon-shanchu color-grey-c font-14 font-n ml20" onClick={()=>this.deletegrouppublish(key)}></i>:""}
{key===course_group_publish_times.length-1&&key<this.state.course_groups_count-1?<i className="iconfont icon-tianjiafangda color-green ml15" onClick={this.addgrouppublish}></i>:""}
</div>
)
})
:""}
</div>
</p> </p>
{is_unified_setting===true?<p className={"mt10"}>
<span> <div className={this.props.course_is_public===true?"mt10":""}>
<DatePicker <span className={"color-ooo fl mt6"}>发布设置</span>
dropdownClassName="hideDisable" <Radio.Group onChange={this.RadioonChange} value={this.state.Radiovalue} style={{'width': '460px'}}>
showTime={{ format: 'HH:mm' }} <Radio style={radioStyle} value={0}>
locale={locale} 立即发布
format={dateFormat} </Radio>
placeholder="请选择发布时间" <Radio style={radioStyle} value={1} className={"fl"}>
id={"startime"} <span className={"mr5"}>延迟发布</span>
showToday={false} <DatePicker
width={"210px"}
value={datatime===undefined||datatime===""?undefined:moment(datatime, dateFormat)} dropdownClassName="hideDisable"
onChange={(e,index)=>this.onChangeTimepublish(e,index,undefined,1)} showTime={{ format: 'HH:mm' }}
disabledTime={disabledDateTime} locale={locale}
disabledDate={disabledDate} format={dateFormat}
/> placeholder="请选择发布时间"
</span> id={"startime"}
</p>:""} 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>
<span className={"fl mt5 color-grey-c"}>(按照设置的时间定时发布)</span>
</Radio.Group>
</div>
{/*{course_group_publish_timestype===true?<p className={"color-red mt10"}>请填写完整</p>:""}*/} {/*{course_group_publish_timestype===true?<p className={"color-red mt10"}>请填写完整</p>:""}*/}
<textarea placeholder="请在此输入资源描述最大限制100个字符" className={"mt10"} value={this.state.description} onInput={this.settextarea} style={{ <textarea placeholder="请在此输入资源描述最大限制100个字符" className={"mt10"} value={this.state.description} onInput={this.settextarea} style={{
@ -577,6 +428,7 @@ class Sendresource extends Component{
padding: '10px' padding: '10px'
}}></textarea> }}></textarea>
{descriptiontype===true?<p className={"color-red"}>请输入资源描述最大限制100个字符</p>:""} {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"> <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 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> <a className="task-btn task-btn-orange" onClick={()=>this.Saves()}>{this.props.Savesname}</a>

@ -2666,8 +2666,11 @@ class Studentshavecompletedthelist extends Component {
.ysltableows2 .ant-table-thead > tr > th, .ant-table-tbody > tr > td { .ysltableows2 .ant-table-thead > tr > th, .ant-table-tbody > tr > td {
padding: 9px; padding: 9px;
} }
mysjysltable1 .ant-table-thead > tr > th, .ant-table-tbody > tr > td {
padding: 9px;
}
`}</style> `}</style>
<div className="edu-table edu-back-white"> <div className="edu-table edu-back-white ysltableows2">
{data === undefined ? "" : <Table {data === undefined ? "" : <Table
dataSource={data} dataSource={data}
columns={columnsys} columns={columnsys}
@ -2770,7 +2773,10 @@ class Studentshavecompletedthelist extends Component {
.ant-spin-nested-loading > div > .ant-spin .ant-spin-dot { .ant-spin-nested-loading > div > .ant-spin .ant-spin-dot {
top: 72%;} top: 72%;}
} }
.ysltableows2 .ant-table-thead > tr > th, .ant-table-tbody > tr > td { .ysltableows2 .ant-table-thead > tr > th, .ant-table-tbody > tr > td {
padding: 9px;
}
mysjysltable2 .ant-table-thead > tr > th, .ant-table-tbody > tr > td {
padding: 9px; padding: 9px;
} }
`}</style> `}</style>
@ -2823,7 +2829,10 @@ class Studentshavecompletedthelist extends Component {
.ysltableows .ant-table-tbody > tr > td{ .ysltableows .ant-table-tbody > tr > td{
height: 58px; height: 58px;
} }
.ysltableows .ant-table-thead > tr > th, .ant-table-tbody > tr > td { .ysltableows .ant-table-thead > tr > th, .ant-table-tbody > tr > td {
padding: 9px;
}
mysjysltable3 .ant-table-thead > tr > th, .ant-table-tbody > tr > td {
padding: 9px; padding: 9px;
} }
` `
@ -2834,7 +2843,7 @@ class Studentshavecompletedthelist extends Component {
{data === undefined ? "" : <Table {data === undefined ? "" : <Table
dataSource={data} dataSource={data}
columns={columnstwo} columns={columnstwo}
className="mysjysltable3" className="mysjysltable3 "
pagination={false} pagination={false}
loading={false} loading={false}
showHeader={false} showHeader={false}
@ -2917,6 +2926,9 @@ class Studentshavecompletedthelist extends Component {
.ysltableowss .ant-table-thead > tr > th, .ant-table-tbody > tr > td { .ysltableowss .ant-table-thead > tr > th, .ant-table-tbody > tr > td {
padding: 9px; padding: 9px;
} }
mysjysltable4 .ant-table-thead > tr > th, .ant-table-tbody > tr > td {
padding: 9px;
}
`}</style> `}</style>
<div className="edu-table edu-back-white minH-560 ysltableowss"> <div className="edu-table edu-back-white minH-560 ysltableowss">
{datas === undefined ? "" : <Table {datas === undefined ? "" : <Table

@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react' import React, { useState, useEffect, memo } from 'react'
import { trigger, WordsBtn } from 'educoder' import { trigger, WordsBtn } from 'educoder'
import { Input, Checkbox, Popconfirm } from "antd"; import { Input, Checkbox, Popconfirm } from "antd";
import axios from 'axios' import axios from 'axios'
@ -6,11 +6,13 @@ import axios from 'axios'
/** /**
角色数组, CREATOR: 创建者, PROFESSOR: 教师, ASSISTANT_PROFESSOR: 助教, STUDENT: 学生 角色数组, CREATOR: 创建者, PROFESSOR: 教师, ASSISTANT_PROFESSOR: 助教, STUDENT: 学生
*/ */
function ChangeRolePop({ member_roles = [], record, courseId, onChangeRoleSuccess, showNotification, getUserId, fetchUser }) { function ChangeRolePop({ member_roles = [], record, courseId, onChangeRoleSuccess, showNotification, getUserId, fetchUser, style }) {
const [checkBoxRoles, setCheckBoxRoles] = useState(member_roles) const [checkBoxRoles, setCheckBoxRoles] = useState(member_roles)
useEffect(() => { // useEffect(() => {
setCheckBoxRoles(member_roles) // if (checkBoxRoles.length != member_roles.length) { // 死循环
}, [member_roles]) // setCheckBoxRoles(member_roles)
// }
// }, [member_roles])
function onCheckBoxChange(val) { function onCheckBoxChange(val) {
console.log(val) console.log(val)
@ -73,8 +75,8 @@ function ChangeRolePop({ member_roles = [], record, courseId, onChangeRoleSucces
</Checkbox.Group> </Checkbox.Group>
} }
> >
<WordsBtn style={'blue'}>修改角色</WordsBtn> <WordsBtn style={'blue'} style2={style}>修改角色</WordsBtn>
</Popconfirm> </Popconfirm>
) )
} }
export default ChangeRolePop export default memo(ChangeRolePop)

@ -89,7 +89,7 @@ function CourseGroupChooser({ course_groups, isAdminOrCreator = true, item, inde
<p className="drop_down_btn"> <p className="drop_down_btn">
<a href="javascript:void(0)" className="color-grey-6" <a href="javascript:void(0)" className="color-grey-6"
onClick={() => trigger('groupAdd')} onClick={() => trigger('groupAdd')}
>添加分班</a> >新建分班</a>
</p> </p>
</ul> </ul>
) )

@ -152,7 +152,7 @@ function CourseGroupList(props) {
</React.Fragment> } </React.Fragment> }
{ {
// pageType !== TYPE_STUDENTS && // pageType !== TYPE_STUDENTS &&
!isCourseEnd && isAdmin && isParent && <WordsBtn style="blue" className="mr30" onClick={()=>addDir()}>新建分班</WordsBtn> } !isCourseEnd && isAdmin && <WordsBtn style="blue" className="mr30" onClick={()=>addDir()}>新建分班</WordsBtn> }
{/* { {/* {
isAdmin && !isParent && course_group_id != 0 && <WordsBtn style="blue" className="mr30" onClick={()=>deleteDir()}>删除分班</WordsBtn> } */} isAdmin && !isParent && course_group_id != 0 && <WordsBtn style="blue" className="mr30" onClick={()=>deleteDir()}>删除分班</WordsBtn> } */}
{/* { {/* {
@ -210,13 +210,13 @@ function CourseGroupList(props) {
onPressEnter={onPressEnter} onPressEnter={onPressEnter}
></Titlesearchsection> ></Titlesearchsection>
<div className="mt20 edu-back-white padding20-30 "> {!!none_group_member_count && <div className="mt20 edu-back-white padding20-30 ">
<span>未分班</span> <span>未分班</span>
<span style={{color: '#999999'}}>{none_group_member_count}个学生</span> <span style={{color: '#999999'}}>{none_group_member_count}个学生</span>
<WordsBtn style="blue" className="fr " <WordsBtn style="blue" className="fr "
onClick={() => {props.history.push(`/courses/${courseId}/course_groups/0`)}}>查看</WordsBtn> onClick={() => {props.history.push(`/courses/${courseId}/course_groups/0`)}}>查看</WordsBtn>
</div> </div>}
<Spin size="large" spinning={isSpin}> <Spin size="large" spinning={isSpin}>
{course_groups && !!course_groups.length ? {course_groups && !!course_groups.length ?

@ -28,7 +28,6 @@ function CourseGroupListTable(props) {
} }
course_groups.forEach((record) => { course_groups.forEach((record) => {
const id = record.id const id = record.id
debugger;
let _clipboard = new ClipboardJS(`.copyBtn_${id}`); let _clipboard = new ClipboardJS(`.copyBtn_${id}`);
_clipboard.on('success', (e) => { _clipboard.on('success', (e) => {
props.showNotification('复制成功') props.showNotification('复制成功')
@ -135,14 +134,14 @@ function CourseGroupListTable(props) {
{isAdmin && <WordsBtn style2={{ marginRight: '12px' }} data-clipboard-text={record.invite_code} {isAdmin && <WordsBtn style2={{ marginRight: '12px' }} data-clipboard-text={record.invite_code}
className={`copyBtn_${record.id}`} style={''}>复制邀请码</WordsBtn> } className={`copyBtn_${record.id}`} style={''}>复制邀请码</WordsBtn> }
{isStudent && <WordsBtn style2={{ marginRight: '12px' }} onClick={() => addToDir(record)} style={''}>加入分班</WordsBtn>} {isStudent && <WordsBtn style2={{ marginRight: '12px' }} onClick={() => addToDir(record)} style={''}>加入分班</WordsBtn>}
<WordsBtn style2={{ marginRight: '12px' }} onClick={() => onGoDetail(record)} style={''}>查看</WordsBtn> <WordsBtn onClick={() => onGoDetail(record)} style={''}>查看</WordsBtn>
</React.Fragment> </React.Fragment>
} }
}) })
return columns return columns
} }
const addToDir = async (record) => { const doAddToDir = async (record) => {
const courseId = props.match.params.coursesId const courseId = props.match.params.coursesId
const url = `/courses/${courseId}/join_course_group.json` const url = `/courses/${courseId}/join_course_group.json`
const course_group_id = record.id const course_group_id = record.id
@ -151,11 +150,27 @@ function CourseGroupListTable(props) {
course_group_id course_group_id
}) })
if (response && response.data.status == 0) { if (response && response.data.status == 0) {
props.showNotification('加入成功') props.showNotification(`已加入分班:${record.name}`)
props.updataleftNavfun() props.updataleftNavfun()
props.onOperationSuccess && props.onOperationSuccess() props.onOperationSuccess && props.onOperationSuccess()
} }
} }
const addToDir = (record) => {
props.confirm({
content: `是否确认加入分班: ${record.name}?`,
okText: '确认',
cancelText: '取消',
onOk: () => {
doAddToDir(record)
},
onCancel() {
console.log('Cancel');
},
});
}
function onDelete(record) { function onDelete(record) {
props.confirm({ props.confirm({

@ -107,7 +107,7 @@ const buildColumns = (that,isParent) => {
} }
]; ];
if (course_groups && course_groups.length) { if (course_groups && course_groups.length) {
columns.push({ this.isStudentPage && columns.push({
title: '分班', title: '分班',
dataIndex: 'course_group_name', dataIndex: 'course_group_name',
key: 'course_group_name', key: 'course_group_name',
@ -130,7 +130,7 @@ const buildColumns = (that,isParent) => {
} }
const isAdmin = that.props.isAdmin() const isAdmin = that.props.isAdmin()
if (isAdmin) { if (isAdmin) {
columns.unshift({ !that.isStudentPage && columns.unshift({
title: '', title: '',
dataIndex: 'check', dataIndex: 'check',
key: 'check', key: 'check',
@ -148,8 +148,9 @@ const buildColumns = (that,isParent) => {
render: (text, record) => { render: (text, record) => {
return ( return (
<React.Fragment> <React.Fragment>
<WordsBtn style2={{ marginRight: '12px' }} onClick={() => that.onDelete(record)} style={'grey'}>删除学生</WordsBtn> <WordsBtn onClick={() => that.onDelete(record)} style={'grey'}>删除学生</WordsBtn>
<ChangeRolePop {record.member_roles && record.member_roles.length && <ChangeRolePop
style={{ marginLeft: '12px' }}
courseId={courseId} courseId={courseId}
record={record} record={record}
member_roles={record.member_roles} member_roles={record.member_roles}
@ -157,7 +158,7 @@ const buildColumns = (that,isParent) => {
showNotification={that.props.showNotification} showNotification={that.props.showNotification}
getUserId={that.props.isUserid} getUserId={that.props.isUserid}
fetchUser={that.props.fetchUser} fetchUser={that.props.fetchUser}
></ChangeRolePop> ></ChangeRolePop>}
</React.Fragment> </React.Fragment>
) )
}, },
@ -319,6 +320,9 @@ class studentsList extends Component{
isAdmin && on('updateNavSuccess', this.updateNavSuccess) isAdmin && on('updateNavSuccess', this.updateNavSuccess)
} }
componentWillUnmount() { componentWillUnmount() {
if (this.clipboard) {
this.clipboard.destroy()
}
const isAdmin = this.props.isAdmin() const isAdmin = this.props.isAdmin()
if (isAdmin) { if (isAdmin) {
off('addStudentSuccess', this.addStudentSuccessListener) off('addStudentSuccess', this.addStudentSuccessListener)
@ -330,6 +334,7 @@ class studentsList extends Component{
} }
updateNavSuccess = () => { updateNavSuccess = () => {
this.fetchCourseGroups() this.fetchCourseGroups()
this.fetchAll()
} }
addStudentSuccessListener=(e, data)=>{ addStudentSuccessListener=(e, data)=>{
@ -418,12 +423,14 @@ class studentsList extends Component{
invite_code: result.data.invite_code, invite_code: result.data.invite_code,
isSpin:false isSpin:false
}, () => { }, () => {
if (!this.clipboard) { if (course_group_id) {
const clipboard = new ClipboardJS('.copybtn'); if (!this.clipboard) {
clipboard.on('success', (e) => { const clipboard = new ClipboardJS('.copybtn');
this.props.showNotification('复制成功') clipboard.on('success', (e) => {
}); this.props.showNotification('复制成功')
this.clipboard = clipboard });
this.clipboard = clipboard
}
} }
}) })
} }
@ -547,7 +554,7 @@ class studentsList extends Component{
addDir = () => { addDir = () => {
trigger('groupAdd', this.props.coursesids) trigger('groupAdd', this.props.coursesids)
} }
addToDir = async () => { doAddToDir = async () => {
const courseId = this.props.match.params.coursesId const courseId = this.props.match.params.coursesId
const url = `/courses/${courseId}/join_course_group.json` const url = `/courses/${courseId}/join_course_group.json`
const course_group_id = this.props.match.params.course_group_id const course_group_id = this.props.match.params.course_group_id
@ -556,11 +563,27 @@ class studentsList extends Component{
course_group_id course_group_id
}) })
if (response && response.data.status == 0) { if (response && response.data.status == 0) {
this.props.showNotification('加入成功') this.props.showNotification(`已加入分班:${this.state.course_group_name}`)
this.props.updataleftNavfun() this.props.updataleftNavfun()
this.fetchAll() this.fetchAll()
} }
} }
addToDir = (record) => {
this.props.confirm({
content: `是否确认加入分班: ${this.state.course_group_name}?`,
okText: '确认',
cancelText: '取消',
onOk: () => {
this.doAddToDir()
},
onCancel() {
console.log('Cancel');
},
});
}
renameDir = () => { renameDir = () => {
const course_group_id = this.props.match.params.course_group_id const course_group_id = this.props.match.params.course_group_id
trigger('groupRename', { id: parseInt(course_group_id), name: this.state.course_group_name}) trigger('groupRename', { id: parseInt(course_group_id), name: this.state.course_group_name})
@ -572,15 +595,15 @@ class studentsList extends Component{
<div>是否确认删除?</div> <div>是否确认删除?</div>
</div>, </div>,
onOk: () => { onOk: () => {
// const cid = this.props.match.params.coursesId
const course_group_id = this.props.match.params.course_group_id const course_group_id = this.props.match.params.course_group_id
const courseId = this.props.match.params.coursesId
const url = `/course_groups/${course_group_id}.json` const url = `/course_groups/${course_group_id}.json`
axios.delete(url) axios.delete(url)
.then((response) => { .then((response) => {
if (response.data.status == 0) { if (response.data.status == 0) {
this.props.showNotification('删除成功') this.props.showNotification('删除成功')
this.props.history.push(response.data.right_url) this.props.history.push(`/courses/${courseId}/course_groups`)
} }
}) })
.catch(function (error) { .catch(function (error) {
@ -666,11 +689,14 @@ class studentsList extends Component{
if (this.props.match.path.endsWith('students')) { if (this.props.match.path.endsWith('students')) {
} else if (course_group_id) { } else if (course_group_id) {
pageType = TYPE_COURSE_GOURP_PARENT
} else {
pageType = TYPE_COURSE_GOURP_CHILD pageType = TYPE_COURSE_GOURP_CHILD
} else {
pageType = TYPE_COURSE_GOURP_PARENT
} }
// 本页面有2个状态学生列表、具体分班
const isStudentPage = pageType == TYPE_STUDENTS
this.isStudentPage = isStudentPage
const isGroupChildPage = pageType == TYPE_COURSE_GOURP_CHILD
return( return(
<React.Fragment > <React.Fragment >
@ -683,7 +709,12 @@ class studentsList extends Component{
<Titlesearchsection <Titlesearchsection
title={isParent ? (pageType == TYPE_STUDENTS ? "全部学生" : "学生列表"): title={isParent ? (pageType == TYPE_STUDENTS ? "全部学生" : "学生列表"):
<React.Fragment> <React.Fragment>
<span>{course_group_name || '未分班'}</span> <span>
<Tooltip title="返回">
<i className="icon-zuojiantou iconfont font-14" onClick={() => { this.props.history.push(`/courses/${courseId}/course_groups`)}}
style={{color: '#212121', verticalAlign: 'initial', marginRight: '14px' }}
></i>
</Tooltip>{course_group_name || ''}</span>
{isAdmin && invite_code && <React.Fragment> {isAdmin && invite_code && <React.Fragment>
<span className="color-grey-9 font-16 ml10">邀请码</span> <span className="color-grey-9 font-16 ml10">邀请码</span>
<span className="color-orange font-16"> <span className="color-orange font-16">
@ -708,23 +739,24 @@ class studentsList extends Component{
searchPlaceholder={ '请输入姓名、学号进行搜索' } searchPlaceholder={ '请输入姓名、学号进行搜索' }
firstRowRight={ firstRowRight={
<React.Fragment> <React.Fragment>
{ {/* {
// pageType !== TYPE_STUDENTS && // pageType !== TYPE_STUDENTS &&
isSuperAdmin && <React.Fragment> !isStudentPage && isSuperAdmin && <React.Fragment>
<CreateGroupByImportModal ref="createGroupByImportModal" {...this.props} <CreateGroupByImportModal ref="createGroupByImportModal" {...this.props}
createGroupImportSuccess={this.createGroupImportSuccess} createGroupImportSuccess={this.createGroupImportSuccess}
></CreateGroupByImportModal> ></CreateGroupByImportModal>
<WordsBtn style="blue" className="mr30" onClick={()=> this.refs['createGroupByImportModal'].setVisible(true)}>导入创建分班</WordsBtn> <WordsBtn style="blue" className="mr30" onClick={()=> this.refs['createGroupByImportModal'].setVisible(true)}>导入创建分班</WordsBtn>
</React.Fragment> } </React.Fragment> } */}
{ {
// pageType !== TYPE_STUDENTS && !isStudentPage && isAdmin && !isParent && course_group_id != 0 && <WordsBtn style="blue" className="mr30" onClick={()=>this.deleteDir()}>删除分班</WordsBtn> }
!isCourseEnd && isAdmin && isParent && <WordsBtn style="blue" className="mr30" onClick={()=>this.addDir()}>添加分班</WordsBtn> }
{ {
isStudent && !isParent && course_group_id != 0 && <WordsBtn style="blue" className="mr30" onClick={()=>this.addToDir()}>加入分班</WordsBtn> } !isStudentPage && isAdmin && !isParent && course_group_id != 0 && <WordsBtn style="blue" className="mr30" onClick={()=>this.renameDir()}>分班重命名</WordsBtn> }
{ {
isAdmin && !isParent && course_group_id != 0 && <WordsBtn style="blue" className="mr30" onClick={()=>this.deleteDir()}>删除分班</WordsBtn> } !isStudentPage && !isCourseEnd && isAdmin && <WordsBtn style="blue" className="mr30" onClick={()=>this.addDir()}>新建分班</WordsBtn> }
{ {
isAdmin && !isParent && course_group_id != 0 && <WordsBtn style="blue" className="mr30" onClick={()=>this.renameDir()}>分班重命名</WordsBtn> } !isStudentPage && isStudent && !isParent && course_group_id != 0 && <WordsBtn style="blue" className="" onClick={()=>this.addToDir()}>加入分班</WordsBtn> }
<style>{` <style>{`
.drop_down_menu li a { .drop_down_menu li a {
padding: 0px; padding: 0px;
@ -779,11 +811,11 @@ class studentsList extends Component{
{ {
total_count > 0 || this.state.isSpin == true ? total_count > 0 || this.state.isSpin == true ?
<div className="mt20 edu-back-white padding20"> <div className="mt20 edu-back-white padding20">
<div className="clearfix stu_head" style={{paddingLeft: '15px'}}> <div className="clearfix stu_head" style={{paddingLeft: '5px'}}>
{isAdmin && <Checkbox className="fl" onChange={this.onCheckAll} checked={checkAllValue} >已选 {checkBoxValues.length} </Checkbox>} {isAdmin && !isStudentPage && <Checkbox className="fl" onChange={this.onCheckAll} checked={checkAllValue} >已选 {checkBoxValues.length} </Checkbox>}
<div className="studentList_operation_ul"> <div className="studentList_operation_ul">
{/* {isAdmin && <li className="li_line"><a href="javascript:void(0)" className="color-grey-9" onClick={this.onDelete}>删除</a></li>} */} {/* {isAdmin && <li className="li_line"><a href="javascript:void(0)" className="color-grey-9" onClick={this.onDelete}>删除</a></li>} */}
{isAdmin && <li className="drop_down"> {isAdmin && !isStudentPage && <li className="drop_down">
移动到...<i className="iconfont icon-xiajiantou font-12 ml2"></i> 移动到...<i className="iconfont icon-xiajiantou font-12 ml2"></i>
<ul className="drop_down_menu" style={{"right":"0px","left":"unset", width: '200px', maxHeight: '324px', overflowY: 'auto'}}> <ul className="drop_down_menu" style={{"right":"0px","left":"unset", width: '200px', maxHeight: '324px', overflowY: 'auto'}}>
{ {
@ -810,7 +842,7 @@ class studentsList extends Component{
<p className="drop_down_btn"> <p className="drop_down_btn">
<a href="javascript:void(0)" className="color-grey-6" <a href="javascript:void(0)" className="color-grey-6"
onClick={()=>this.addDir()} onClick={()=>this.addDir()}
>添加分班...</a> >新建分班...</a>
</p> </p>
} }

@ -200,7 +200,8 @@ function buildColumns(that) {
}, },
}) })
} }
if(isAdminOrTeacher && hasGraduationModule) { // 待审批不需要
if(filterKey == '1' && isAdminOrTeacher && hasGraduationModule) {
columns.unshift({ columns.unshift({
title: '', title: '',
dataIndex: 'course_member_id', dataIndex: 'course_member_id',

@ -1725,7 +1725,7 @@ class Trainingjobsetting extends Component {
flagPageEditstwo:releasetime, flagPageEditstwo:releasetime,
flagPageEditsthrees:deadline, flagPageEditsthrees:deadline,
flagPageEditsfor:endtime, flagPageEditsfor:endtime,
completionefficiencyscore:true, completionefficiencyscore:false,
work_efficiencys:this.state.work_efficiencys, work_efficiencys:this.state.work_efficiencys,
unifiedsetting:this.state.unifiedsetting, unifiedsetting:this.state.unifiedsetting,
latedeductiontwo:this.state.latedeductiontwo, latedeductiontwo:this.state.latedeductiontwo,
@ -1841,7 +1841,7 @@ class Trainingjobsetting extends Component {
flagPageEditstwo:releasetime, flagPageEditstwo:releasetime,
flagPageEditsthrees:deadline, flagPageEditsthrees:deadline,
flagPageEditsfor:endtime, flagPageEditsfor:endtime,
completionefficiencyscore:true, completionefficiencyscore:datas.data.work_efficiency===true?true:false,
work_efficiencys:datas.data.work_efficiency, work_efficiencys:datas.data.work_efficiency,
unifiedsetting:datas.data.unified_setting, unifiedsetting:datas.data.unified_setting,
latedeductiontwo:datas.data.eff_score, latedeductiontwo:datas.data.eff_score,

@ -1142,11 +1142,38 @@ class ShixunHomework extends Component{
addsave={addsave} addsave={addsave}
/> />
{
datas&&datas.category_name===undefined||datas&&datas.category_name===null?"":
<style>
{
`
.category_namehome{
max-width: 558px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: inline-block;
margin-right: 5px;
}
.category_namehomelist{
display: inline-block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
`
}
</style>
}
<div className="edu-back-white"> <div className="edu-back-white">
<p className="clearfix padding30 bor-bottom-greyE"> <p className="clearfix padding30 bor-bottom-greyE">
<p style={{height: '20px'}}> <p style={{height: '20px'}}>
<span className="font-18 fl color-dark-21">{datas&&datas.category_name===undefined||datas&&datas.category_name===null?datas&&datas.main_category_name:datas&&datas.category_name+" 作业列表"}</span> <span className="font-18 fl color-dark-21">
{datas&&datas.category_name===undefined||datas&&datas.category_name===null?datas&&datas.main_category_name:<span>
<span className={"category_namehome"}>{datas&&datas.category_name} </span>
<span className={"category_namehomelist"}> 作业列表</span>
</span>}
</span>
<li className="fr"> <li className="fr">
{datas===undefined?"":datas.homeworks && datas.homeworks.length>1?this.props.isAdminOrCreator()===true?datas&&datas.category_name===undefined||datas&&datas.category_name===null? {datas===undefined?"":datas.homeworks && datas.homeworks.length>1?this.props.isAdminOrCreator()===true?datas&&datas.category_name===undefined||datas&&datas.category_name===null?
<span> <span>

@ -60,7 +60,7 @@ class MemoTechShare extends Component {
(oldParsed.order && newParsed.order && oldParsed.order != newParsed.order)) { (oldParsed.order && newParsed.order && oldParsed.order != newParsed.order)) {
this.props.fetchMemos(); this.props.fetchMemos();
} }
console.log('componentWillReceiveProps...') // console.log('componentWillReceiveProps...')
} }
} }

@ -19,6 +19,8 @@ import {
notification notification
} from "antd"; } from "antd";
import {Link, Switch, Route, Redirect} from 'react-router-dom'; import {Link, Switch, Route, Redirect} from 'react-router-dom';
import { SnackbarHOC,getImageUrl } from 'educoder';
import { TPMIndexHOC } from '../tpm/TPMIndexHOC';
import '../courses/css/members.css'; import '../courses/css/members.css';
import "../courses/common/formCommon.css" import "../courses/common/formCommon.css"
import '../courses/css/Courses.css'; import '../courses/css/Courses.css';
@ -108,7 +110,8 @@ class EducoderLogin extends Component {
} }
componentDidMount() { componentDidMount() {
// console.log("EducoderLogin");
// console.log(this.props);
} }
Setlogins=(i)=>{ Setlogins=(i)=>{
@ -137,6 +140,9 @@ class EducoderLogin extends Component {
render() { render() {
let {showbool,loginstatus,logini} = this.state; let {showbool,loginstatus,logini} = this.state;
console.log("EducoderLogingetHelmetapi");
console.log(this.props);
// console.log(this.props.mygetHelmetapi);
return ( return (
<div style={newContainer} className=" clearfix" > <div style={newContainer} className=" clearfix" >
@ -148,7 +154,13 @@ class EducoderLogin extends Component {
"width": "100%" "width": "100%"
}}> }}>
<div style={{cursor:"pointer"}}> <div style={{cursor:"pointer"}}>
<img style={{cursor:"pointer"}} onClick={()=>this.gohome()} src={educodernet}/> {
this.props.mygetHelmetapi===undefined||this.props.mygetHelmetapi.login_logo_url===null|| this.props.mygetHelmetapi.login_logo_url===undefined?
<img style={{cursor:"pointer"}} onClick={()=>this.gohome()} src={educodernet}/>
:
<img style={{cursor:"pointer"}} onClick={()=>this.gohome()} src={getImageUrl(this.props.mygetHelmetapi.login_logo_url)}/>
}
</div> </div>
@ -196,8 +208,7 @@ class EducoderLogin extends Component {
} }
} }
export default EducoderLogin ;
export default EducoderLogin;
// showbool === 2 ? // showbool === 2 ?
// <div style={{ // <div style={{
// display: "flex", // display: "flex",

@ -103,8 +103,13 @@
} }
#closeIcon{ #closeIcon{
position: absolute;
top: -30px;
right: -27px;
z-index: 100000;
}
#logincloseIcon{
position: absolute; position: absolute;
top: -100px; top: -100px;
right: -27px; right: -27px;

@ -568,7 +568,7 @@ class LoginDialog extends Component {
</style>:""} </style>:""}
{isRender===true? {isRender===true?
<div className={dialogBox}> <div className={dialogBox}>
<div id="closeIcon" onClick={()=>{this.handleDialogClose()}}> <div id="closeIcon" className={"logincloseIcon"} onClick={()=>{this.handleDialogClose()}}>
<i className="iconfont icon-shanchudiao"></i> <i className="iconfont icon-shanchudiao"></i>
</div> </div>

@ -39,16 +39,23 @@ class NewFooter extends Component {
</ul> </ul>
</div> </div>
<div> <div>
<p className="footer_con-p inline lineh-30 font-14"> {
<span className="font-18 fl">©</span>&nbsp;2019&nbsp;EduCoder this.props.mygetHelmetapi===undefined|| this.props.mygetHelmetapi.footer===null||this.props.mygetHelmetapi.footer===undefined?
<a style={{"color":"#888"}} target="_blank" href="http://beian.miit.gov.cn/" className="ml15 mr15">湘ICP备17009477号</a> <p className="footer_con-p inline lineh-30 font-14">
<a style={{"color":"#888"}} target="_blank" href="http://www.beian.gov.cn/portal/registerSystemInfo?recordcode=43019002000962" className="mr15"> <span className="font-18 fl">©</span>&nbsp;2019&nbsp;EduCoder
<img className="vertical4" src={require('./beian.png')}/>湘公网安备43019002000962号 <a style={{"color":"#888"}} target="_blank" href="http://beian.miit.gov.cn/" className="ml15 mr15">湘ICP备17009477号</a>
</a> <a style={{"color":"#888"}} target="_blank" href="http://www.beian.gov.cn/portal/registerSystemInfo?recordcode=43019002000962" className="mr15">
<a href="https://team.trustie.net" style={{"color":"#888"}} <img className="vertical4" src={require('./beian.png')}/>湘公网安备43019002000962号
target="_blank">Trustie</a>&nbsp;&nbsp;&nbsp;&amp;&nbsp;&nbsp;&nbsp;IntelliDE inside. <span </a>
<a href="https://team.trustie.net" style={{"color":"#888"}}
target="_blank">Trustie</a>&nbsp;&nbsp;&nbsp;&amp;&nbsp;&nbsp;&nbsp;IntelliDE inside. <span
className="mr15">版权所有 湖南智擎科技有限公司</span> className="mr15">版权所有 湖南智擎科技有限公司</span>
</p> </p>
:
<div dangerouslySetInnerHTML={{__html: this.props.mygetHelmetapi.footer}}></div>
}
</div> </div>
<div className="cl"></div> <div className="cl"></div>
</div> </div>

@ -65,13 +65,26 @@ class NewHeader extends Component {
showTrial:false, showTrial:false,
setevaluatinghides:false, setevaluatinghides:false,
occupation:0, occupation:0,
mydisplay:false mydisplay:false,
headtypesonClickbool:false,
headtypess:"/",
mygetHelmetapi2:undefined,
} }
// console.log("176") console.log("176")
// console.log(props); // console.log(props);
// console.log("NewHeader1234567890");
// console.log(this.props);
} }
componentDidUpdate = (prevProps) => {
// console.log("componentDidMount2");
// console.log(this.state.mygetHelmetapi2);
if(this.state.mygetHelmetapi2===undefined){
this.getAppdata();
}
}
componentDidMount() { componentDidMount() {
console.log("componentDidMount1");
this.getAppdata();
window._header_componentHandler = this; window._header_componentHandler = this;
//下拉框的显示隐藏 //下拉框的显示隐藏
@ -633,11 +646,80 @@ submittojoinclass=(value)=>{
this.setState({ this.setState({
AccountProfiletype:false AccountProfiletype:false
}) })
};
headtypesonClick=(url,bool)=>{
this.setState({
headtypess:url,
headtypesonClickbool:bool,
})
} }
getAppdata=()=>{
// console.log("开始刷新数据了")
let url = "/setting.json";
axios.get(url).then((response) => {
// console.log("axios.get");
// console.log(response);
if(response){
if(response.data){
this.setState({
mygetHelmetapi2:response.data.setting
});
document.title = response.data.setting.name;
var link = document.createElement('link'),
oldLink = document.getElementById('dynamic-favicon');
link.id = 'dynamic-favicon';
link.rel = 'shortcut icon';
link.href = '/'+response.data.setting.tab_logo_url;
if (oldLink) {
document.head.removeChild(oldLink);
}
document.head.appendChild(link);
}else {
document.title = "EduCoder";
var link = document.createElement('link'),
oldLink = document.getElementById('dynamic-favicon');
link.id = 'dynamic-favicon';
link.rel = 'shortcut icon';
link.href = "/react/build/./favicon.ico";
if (oldLink) {
document.head.removeChild(oldLink);
}
document.head.appendChild(link);
}
}else{
document.title = "EduCoder";
var link = document.createElement('link'),
oldLink = document.getElementById('dynamic-favicon');
link.id = 'dynamic-favicon';
link.rel = 'shortcut icon';
link.href = "/react/build/./favicon.ico";
if (oldLink) {
document.head.removeChild(oldLink);
}
document.head.appendChild(link);
}
}).catch((error) => {
console.log("开始刷新定制数据了但报错了");
console.log(error);
document.title = "EduCoder";
var link = document.createElement('link'),
oldLink = document.getElementById('dynamic-favicon');
link.id = 'dynamic-favicon';
link.rel = 'shortcut icon';
link.href = "/react/build/./favicon.ico";
if (oldLink) {
document.head.removeChild(oldLink);
}
document.head.appendChild(link);
});
};
render() { render() {
const isLogin = true; // 这里不会出现未登录的情况,服务端在服务端路由时发现如果是未登录,则跳转到登录页了。 const isLogin = true; // 这里不会出现未登录的情况,服务端在服务端路由时发现如果是未登录,则跳转到登录页了。
const {match ,} = this.props; const {match,} = this.props;
let {Addcoursestypes, let {Addcoursestypes,
tojoinitemtype, tojoinitemtype,
@ -655,35 +737,127 @@ submittojoinclass=(value)=>{
user, user,
isRender, isRender,
showSearchOpentype, showSearchOpentype,
headtypesonClickbool,
headtypess,
mygetHelmetapi2,
}=this.state; }=this.state;
/* /*
用户名称 用户头像url 用户名称 用户头像url
*/ */
let activeIndex = false; let activeIndex = false;
let activeForums = false; let activeForums = false;
let activeShixuns = false; let activeShixuns = false;
let activePaths = false; let activePaths = false;
let coursestype=false; let coursestype=false;
let activePackages=false; let activePackages=false;
let activeMoopCases=false; let activeMoopCases=false;
if (match.path === '/forums') { if (match.path === '/forums') {
activeForums = true; activeForums = true;
} else if (match.path.startsWith('/shixuns')) { } else if (match.path.startsWith('/shixuns')) {
activeShixuns = true; activeShixuns = true;
}else if (match.path.startsWith('/paths')) { }else if (match.path.startsWith('/paths')) {
activePaths = true; activePaths = true;
} else if (match.path.startsWith('/courses')) { } else if (match.path.startsWith('/courses')) {
coursestype = true; coursestype = true;
}else if (match.path.startsWith('/crowdsourcing')) { }else if (match.path.startsWith('/crowdsourcing')) {
activePackages = true; activePackages = true;
}else if(match.path.startsWith('/moop_cases')){ }else if(match.path.startsWith('/moop_cases')){
activeMoopCases = true; activeMoopCases = true;
}else { }else {
activeIndex = true; activeIndex = true;
} }
let headtypes='/';
// console.log("mygetHelmetapi2");
// console.log(mygetHelmetapi2);
if(mygetHelmetapi2){
if(mygetHelmetapi2.navbar){
if(mygetHelmetapi2.navbar.length>0){
// console.log("mygetHelmetapi2.navbar.length>0====-=-=--=-=-=-=");
//
// console.log(match.path);
if(match.path==='/'){
if(headtypesonClickbool===false){
headtypes=undefined;
}else{
headtypes=headtypess;
}
}else {
for(var i=0;i<mygetHelmetapi2.navbar.length;i++){
if(match.path===mygetHelmetapi2.navbar[i].link){
headtypes=mygetHelmetapi2.navbar[i].link;
break;
}
}
}
}else{
if (match.path === '/forums') {
headtypes = '/forums';
} else if (match.path.startsWith('/shixuns')) {
headtypes = '/shixuns';
}else if (match.path.startsWith('/paths')) {
headtypes = '/paths';
} else if (match.path.startsWith('/courses')) {
headtypes = '/courses';
}else if (match.path.startsWith('/competitions')) {
headtypes = '/competitions';
}else if (match.path.startsWith('/crowdsourcing')) {
headtypes = '/crowdsourcing';
}else if(match.path.startsWith('/moop_cases')){
headtypes = '/moop_cases';
}else {
headtypes = '/';
}
}
}else{
if (match.path === '/forums') {
headtypes = '/forums';
} else if (match.path.startsWith('/shixuns')) {
headtypes = '/shixuns';
}else if (match.path.startsWith('/paths')) {
headtypes = '/paths';
} else if (match.path.startsWith('/courses')) {
headtypes = '/courses';
}else if (match.path.startsWith('/competitions')) {
headtypes = '/competitions';
}else if (match.path.startsWith('/crowdsourcing')) {
headtypes = '/crowdsourcing';
}else if(match.path.startsWith('/moop_cases')){
headtypes = '/moop_cases';
}else {
headtypes = '/';
}
}
}else{
if (match.path === '/forums') {
headtypes = '/forums';
} else if (match.path.startsWith('/shixuns')) {
headtypes = '/shixuns';
}else if (match.path.startsWith('/paths')) {
headtypes = '/paths';
} else if (match.path.startsWith('/courses')) {
headtypes = '/courses';
}else if (match.path.startsWith('/competitions')) {
headtypes = '/competitions';
}else if (match.path.startsWith('/crowdsourcing')) {
headtypes = '/crowdsourcing';
}else if(match.path.startsWith('/moop_cases')){
headtypes = '/moop_cases';
}else {
headtypes = '/';
}
}
// console.log("NewHeadergetHelmetapi432423423423");
// console.log(mygetHelmetapi2);
// console.log("NewHeadermygetHelmetapi123123123123");
// console.log(mygetHelmetapi2);
// console.log(this.props);
return ( return (
<div className="newHeaders" id="nHeader" > <div className="newHeaders" id="nHeader" >
@ -699,9 +873,14 @@ submittojoinclass=(value)=>{
{...this.props} {...this.props}
{...this.state} {...this.state}
/>:""} />:""}
<Link to="/" className={"fl mr30 ml25 mt10"}> <a href={"/"} onClick={()=>this.headtypesonClick("/",false)} className={"fl mr30 ml25 mt10"}>
<img alt="高校智能化教学与实训平台" className="logoimg" src={getImageUrl("images/educoder/headNavLogo.png?1526520218")}></img> {
</Link> mygetHelmetapi2===undefined||mygetHelmetapi2.nav_logo_url===null||mygetHelmetapi2.nav_logo_url===undefined?
<img alt="高校智能化教学与实训平台" className="logoimg" style={{heigth:"40px"}} src={getImageUrl("images/educoder/headNavLogo.png?1526520218")}></img>
:
<img alt="高校智能化教学与实训平台" className="logoimg" style={{heigth:"40px"}} src={getImageUrl(mygetHelmetapi2.nav_logo_url)}></img>
}
</a>
<style> <style>
{ {
@ -714,70 +893,219 @@ submittojoinclass=(value)=>{
` `
} }
</style> </style>
<div className="educontents fl"> {
{/*<%= link_to image_tag("/images/educoder/logo.png", alt:"高校智能化教学与实训平台", className:"logoimg"), home_path %>*/} mygetHelmetapi2!==undefined&&mygetHelmetapi2.navbar!==null&&mygetHelmetapi2.navbar!==undefined&&mygetHelmetapi2.navbar.length>0?
<div className="head-nav pr" id={"head-navpre1"}>
<ul id="header-nav">
{/*<li className={`${activeIndex === true ? 'active' : ''}`}><a href="/">首页</a></li>*/}
{/*<li><a href={this.props.Headertop===undefined?"":this.props.Headertop.shixun_paths_url}>实训路径</a></li>*/}
{
mygetHelmetapi2.navbar && mygetHelmetapi2.navbar.map((item,key)=>{
// console.log("headtypes");
// console.log(headtypes);hidden
var str=new RegExp("http");
var strbool=false;
//test方法返回值为(true或者false)
if(item.link){
if(str.test(item.link)===true){
strbool=true
}else{
strbool=false
}
}
console.log(item.hidden);
return(
<li key={key} onClick={()=>this.headtypesonClick(item.link,true)} className={`${headtypes===undefined?'pr':headtypes===item.link?'pr active':'pr'}`} style={item.hidden==false?{display: 'block'}:{display: 'none'}}>
{
strbool===true?
<a href={item.link}>{item.name}</a>
:
<Link to={item.link}>{item.name}</Link>
}
</li>
)
})
}
{/*<li className={`${activePaths === true ? 'pr active' : 'pr'}`}>*/}
{/* <Link to={this.props.Headertop===undefined?"":'/paths'}>实践课程</Link>*/}
{/*</li>*/}
{/*<li><a href={this.props.Headertop===undefined?"":'/courses'}>课堂</a></li>*/}
{/*<li className={`${coursestype === true ? 'pr active' : 'pr'}`}>*/}
{/* /!*<a href={this.props.Headertop===undefined?"":this.props.Headertop.course_url}>课堂</a>*!/*/}
{/* <Link to={this.props.Headertop===undefined?"":'/courses'}>翻转课堂</Link>*/}
{/*</li>*/}
{/*<li className={`${activeShixuns === true ? 'pr active' : 'pr'}`}>*/}
{/* <Link to="/shixuns">实训项目</Link>*/}
{/* <img src={getImageUrl("images/educoder/hot-h.png")} className="nav-img">*/}
{/* </img>*/}
{/*</li>*/}
{/*<li className=""><a href={"/libraries"}>教学案例</a></li>*/}
{/*<li className="">*/}
{/* <a href={this.props.Headertop===undefined?"":this.props.Headertop.competitions_url}>在线竞赛</a>*/}
{/* <img className="roundedRectangles"*/}
{/* src={require('./roundedRectangle.png')}*/}
{/* />*/}
{/*</li>*/}
{/*<li className={`${activeMoopCases === true ? 'pr active' : 'pr'}`}> <Link to={`/moop_cases`}>教学案例</Link></li>*/}
{/*<li className={`${activePackages === true ? 'pr active' : 'pr'}`}>*/}
{/*<Link to={'/crowdsourcing'}>众包创新</Link>*/}
{/*</li>*/}
{/*<li className={`${activeForums === true ? 'active' : ''}`}> <Link to={this.props.Headertop===undefined?"":this.props.Headertop.topic_url}>交流问答</Link></li>*/}
{/*<li*/}
{/* style={{display: this.props.Headertop === undefined ? 'none' : this.props.Headertop.auth===null? 'none' : 'block'}}*/}
{/*><a href={this.props.Headertop===undefined?"":this.props.Headertop.auth}>工程认证</a></li>*/}
<li className="fl edu-menu-panel careershover "
style={{display: this.props.Headertop === undefined ?'none' : this.props.Headertop.career_url.length > 0 ? 'block' : 'none'}}>
<a>职业路径</a>
<div
style={{display: this.props.Headertop === undefined ?'none' : this.props.Headertop.career_url.length > 0 ? 'block' : 'none'}}>
<ul className="edu-menu-list edu-menu-listnew " style={{top:'60px'}}>
{this.props.Headertop === undefined ? "" : this.props.Headertop.career_url.map((item, key) => {
return(
<li key={key}><i className="iconfont icon-java left careersiconfont"
style={{color: '#000 important'}}
></i><a style={{width: '83%'}}
href={item.url}>{item.name}</a></li>
)
})
}
</ul>
</div>
</li>
</ul>
</div>
// :mygetHelmetapi2===undefined||mygetHelmetapi2.navbar===null||mygetHelmetapi2.navbar===undefined||mygetHelmetapi2.navbar.length===0?
// <div className="head-nav pr" id={"head-navpre2"}>
//
// <ul id="header-nav">
// {/*<li className={`${activeIndex === true ? 'active' : ''}`}><a href="/">首页</a></li>*/}
//
// {/*<li><a href={this.props.Headertop===undefined?"":this.props.Headertop.shixun_paths_url}>实训路径</a></li>*/}
// <li className={`${activePaths === true ? 'pr active' : 'pr'}`}>
// <Link to={this.props.Headertop===undefined?"":'/paths'}>实践课程</Link>
// </li>
//
// {/*<li><a href={this.props.Headertop===undefined?"":'/courses'}>课堂</a></li>*/}
// <li className={`${coursestype === true ? 'pr active' : 'pr'}`}>
// {/*<a href={this.props.Headertop===undefined?"":this.props.Headertop.course_url}>课堂</a>*/}
// <Link to={this.props.Headertop===undefined?"":'/courses'}>翻转课堂</Link>
// </li>
//
// <li className={`${activeShixuns === true ? 'pr active' : 'pr'}`}>
// <Link to="/shixuns">实训项目</Link>
// {/*<img src={getImageUrl("images/educoder/hot-h.png")} className="nav-img">*/}
// {/*</img>*/}
// </li>
//
// <li className="fl edu-menu-panel careershover "
// style={{display: this.props.Headertop === undefined ?'none' : this.props.Headertop.career_url.length > 0 ? 'block' : 'none'}}>
// <a>职业路径</a>
// <div
// style={{display: this.props.Headertop === undefined ?'none' : this.props.Headertop.career_url.length > 0 ? 'block' : 'none'}}>
// <ul className="edu-menu-list edu-menu-listnew " style={{top:'60px'}}>
// {this.props.Headertop === undefined ? "" : this.props.Headertop.career_url.map((item, key) => {
// return(
// <li key={key}><i className="iconfont icon-java left careersiconfont"
// style={{color: '#000 important'}}
// ></i><a style={{width: '83%'}}
// href={item.url}>{item.name}</a></li>
// )
// })
// }
// </ul>
// </div>
// </li>
//
// {/*<li className=""><a href={"/libraries"}>教学案例</a></li>*/}
// <li className="">
// <a href={this.props.Headertop===undefined?"":this.props.Headertop.competitions_url}>在线竞赛</a>
// {/*<img className="roundedRectangles"*/}
// {/* src={require('./roundedRectangle.png')}*/}
// {/*/>*/}
// </li>
// <li className={`${activeMoopCases === true ? 'pr active' : 'pr'}`}> <Link to={`/moop_cases`}>教学案例</Link></li>
// {/*<li className={`${activePackages === true ? 'pr active' : 'pr'}`}>*/}
// {/*<Link to={'/crowdsourcing'}>众包创新</Link>*/}
// {/*</li>*/}
// <li className={`${activeForums === true ? 'active' : ''}`}> <Link to={this.props.Headertop===undefined?"":this.props.Headertop.topic_url}>交流问答</Link></li>
// <li
// style={{display: this.props.Headertop === undefined ? 'none' : this.props.Headertop.auth===null? 'none' : 'block'}}
// ><a href={this.props.Headertop===undefined?"":this.props.Headertop.auth}>工程认证</a></li>
// </ul>
// </div>
:
<div className="head-nav pr" id={"head-navpre3"}>
<ul id="header-nav">
{/*<li className={`${activeIndex === true ? 'active' : ''}`}><a href="/">首页</a></li>*/}
{/*<li><a href={this.props.Headertop===undefined?"":this.props.Headertop.shixun_paths_url}>实训路径</a></li>*/}
<li className={`${activePaths === true ? 'pr active' : 'pr'}`}>
<Link to={this.props.Headertop===undefined?"":'/paths'}>实践课程</Link>
</li>
{/*<li><a href={this.props.Headertop===undefined?"":'/courses'}>课堂</a></li>*/}
<li className={`${coursestype === true ? 'pr active' : 'pr'}`}>
{/*<a href={this.props.Headertop===undefined?"":this.props.Headertop.course_url}>课堂</a>*/}
<Link to={this.props.Headertop===undefined?"":'/courses'}>翻转课堂</Link>
</li>
<li className={`${activeShixuns === true ? 'pr active' : 'pr'}`}>
<Link to="/shixuns">实训项目</Link>
{/*<img src={getImageUrl("images/educoder/hot-h.png")} className="nav-img">*/}
{/*</img>*/}
</li>
<li className="fl edu-menu-panel careershover "
style={{display: this.props.Headertop === undefined ?'none' : this.props.Headertop.career_url.length > 0 ? 'block' : 'none'}}>
<a>职业路径</a>
<div
style={{display: this.props.Headertop === undefined ?'none' : this.props.Headertop.career_url.length > 0 ? 'block' : 'none'}}>
<ul className="edu-menu-list edu-menu-listnew " style={{top:'60px'}}>
{this.props.Headertop === undefined ? "" : this.props.Headertop.career_url.map((item, key) => {
return(
<li key={key}><i className="iconfont icon-java left careersiconfont"
style={{color: '#000 important'}}
></i><a style={{width: '83%'}}
href={item.url}>{item.name}</a></li>
)
})
}
</ul>
</div>
</li>
{/*<li className=""><a href={"/libraries"}>教学案例</a></li>*/}
<li className="">
<a href={this.props.Headertop===undefined?"":this.props.Headertop.competitions_url}>在线竞赛</a>
{/*<img className="roundedRectangles"*/}
{/* src={require('./roundedRectangle.png')}*/}
{/*/>*/}
</li>
<li className={`${activeMoopCases === true ? 'pr active' : 'pr'}`}> <Link to={`/moop_cases`}>教学案例</Link></li>
{/*<li className={`${activePackages === true ? 'pr active' : 'pr'}`}>*/}
{/*<Link to={'/crowdsourcing'}>众包创新</Link>*/}
{/*</li>*/}
<li className={`${activeForums === true ? 'active' : ''}`}> <Link to={this.props.Headertop===undefined?"":this.props.Headertop.topic_url}>交流问答</Link></li>
<li
style={{display: this.props.Headertop === undefined ? 'none' : this.props.Headertop.auth===null? 'none' : 'block'}}
><a href={this.props.Headertop===undefined?"":this.props.Headertop.auth}>工程认证</a></li>
</ul>
</div>
}
<div className="head-nav pr">
<ul id="header-nav">
{/*<li className={`${activeIndex === true ? 'active' : ''}`}><a href="/">首页</a></li>*/}
{/*<li><a href={this.props.Headertop===undefined?"":this.props.Headertop.shixun_paths_url}>实训路径</a></li>*/}
<li className={`${activePaths === true ? 'pr active' : 'pr'}`}>
<Link to={this.props.Headertop===undefined?"":'/paths'}>实践课程</Link>
</li>
{/*<li><a href={this.props.Headertop===undefined?"":'/courses'}>课堂</a></li>*/}
<li className={`${coursestype === true ? 'pr active' : 'pr'}`}>
{/*<a href={this.props.Headertop===undefined?"":this.props.Headertop.course_url}>课堂</a>*/}
<Link to={this.props.Headertop===undefined?"":'/courses'}>翻转课堂</Link>
</li>
<li className={`${activeShixuns === true ? 'pr active' : 'pr'}`}>
<Link to="/shixuns">实训项目</Link>
<img src={getImageUrl("images/educoder/hot-h.png")} className="nav-img">
</img>
</li>
<li className="fl edu-menu-panel careershover "
style={{display: this.props.Headertop === undefined ?'none' : this.props.Headertop.career_url.length > 0 ? 'block' : 'none'}}>
<a>职业路径</a>
<div
style={{display: this.props.Headertop === undefined ?'none' : this.props.Headertop.career_url.length > 0 ? 'block' : 'none'}}>
<ul className="edu-menu-list edu-menu-listnew " style={{top:'60px'}}>
{this.props.Headertop === undefined ? "" : this.props.Headertop.career_url.map((item, key) => {
return(
<li key={key}><i className="iconfont icon-java left careersiconfont"
style={{color: '#000 important'}}
></i><a style={{width: '83%'}}
href={item.url}>{item.name}</a></li>
)
})
}
</ul>
</div>
</li>
{/*<li className=""><a href={"/libraries"}>教学案例</a></li>*/}
<li className="">
<a href={this.props.Headertop===undefined?"":this.props.Headertop.competitions_url}>在线竞赛</a>
<img className="roundedRectangles"
src={require('./roundedRectangle.png')}
/>
</li>
<li className={`${activeMoopCases === true ? 'pr active' : 'pr'}`}> <Link to={`/moop_cases`}>教学案例</Link></li>
{/*<li className={`${activePackages === true ? 'pr active' : 'pr'}`}>*/}
{/*<Link to={'/crowdsourcing'}>众包创新</Link>*/}
{/*</li>*/}
<li className={`${activeForums === true ? 'active' : ''}`}> <Link to={this.props.Headertop===undefined?"":this.props.Headertop.topic_url}>交流问答</Link></li>
<li
style={{display: this.props.Headertop === undefined ? 'none' : this.props.Headertop.auth===null? 'none' : 'block'}}
><a href={this.props.Headertop===undefined?"":this.props.Headertop.auth}>工程认证</a></li>
</ul>
</div>
</div>
<style> <style>
{ {

@ -7,8 +7,8 @@ import NewFooter from './NewFooter'
import SiderBar from './SiderBar' import SiderBar from './SiderBar'
import { getUrl, downloadFile } from 'educoder' import { getUrl, downloadFile } from 'educoder'
import axios from 'axios'; import axios from 'axios';
import { Spin } from 'antd' import { Spin } from 'antd';
import './TPMIndex.css' import './TPMIndex.css';
import LoginDialog from '../login/LoginDialog'; import LoginDialog from '../login/LoginDialog';
import AccountProfile from '../user/AccountProfile'; import AccountProfile from '../user/AccountProfile';
@ -83,7 +83,8 @@ export function TPMIndexHOC(WrappedComponent) {
globalLoading: false, globalLoading: false,
dataquerys:{}, dataquerys:{},
isloginCancel:undefined isloginCancel:undefined,
mygetHelmetapi:undefined,
} }
} }
@ -147,6 +148,8 @@ export function TPMIndexHOC(WrappedComponent) {
} }
componentDidMount() { componentDidMount() {
// console.log("TPMIndexHOC========");
// console.log(this.props);
window.addEventListener('keyup', this.keyupListener) window.addEventListener('keyup', this.keyupListener)
if(this.props.match.path==="/"){ if(this.props.match.path==="/"){
@ -198,6 +201,8 @@ export function TPMIndexHOC(WrappedComponent) {
axios.get(url, { axios.get(url, {
}).then((response) => { }).then((response) => {
// console.log("开始请求/get_navigation_info.json");
// console.log(response);
if(response!=undefined){ if(response!=undefined){
if(response.status===200){ if(response.status===200){
this.setState({ this.setState({
@ -207,7 +212,8 @@ export function TPMIndexHOC(WrappedComponent) {
} }
} }
}); });
///请求定制化的信息
this.getAppdata();
} }
/** /**
课堂权限相关方法暂时写这里了 ----------------------------------------START 课堂权限相关方法暂时写这里了 ----------------------------------------START
@ -277,7 +283,67 @@ export function TPMIndexHOC(WrappedComponent) {
// //
// } // }
//获取当前定制信息
//获取当前定制信息
getAppdata=()=>{
let url = "/setting.json";
axios.get(url).then((response) => {
// console.log("app.js开始请求/setting.json");
// console.log("获取当前定制信息");
if(response){
if(response.data){
this.setState({
mygetHelmetapi:response.data.setting
});
document.title = response.data.setting.name;
var link = document.createElement('link'),
oldLink = document.getElementById('dynamic-favicon');
link.id = 'dynamic-favicon';
link.rel = 'shortcut icon';
link.href = '/'+response.data.setting.tab_logo_url;
if (oldLink) {
document.head.removeChild(oldLink);
}
document.head.appendChild(link);
}else {
document.title = "EduCoder";
var link = document.createElement('link'),
oldLink = document.getElementById('dynamic-favicon');
link.id = 'dynamic-favicon';
link.rel = 'shortcut icon';
link.href = "/react/build/./favicon.ico";
if (oldLink) {
document.head.removeChild(oldLink);
}
document.head.appendChild(link);
}
}else{
document.title = "EduCoder";
var link = document.createElement('link'),
oldLink = document.getElementById('dynamic-favicon');
link.id = 'dynamic-favicon';
link.rel = 'shortcut icon';
link.href = "/react/build/./favicon.ico";
if (oldLink) {
document.head.removeChild(oldLink);
}
document.head.appendChild(link);
}
}).catch((error) => {
document.title = "EduCoder";
var link = document.createElement('link'),
oldLink = document.getElementById('dynamic-favicon');
link.id = 'dynamic-favicon';
link.rel = 'shortcut icon';
link.href = "/react/build/./favicon.ico";
if (oldLink) {
document.head.removeChild(oldLink);
}
document.head.appendChild(link);
});
};
/** /**
课堂权限相关方法暂时写这里了 ----------------------------------------END 课堂权限相关方法暂时写这里了 ----------------------------------------END
*/ */
@ -535,7 +601,7 @@ export function TPMIndexHOC(WrappedComponent) {
this.setState({ globalLoading: false }) this.setState({ globalLoading: false })
} }
render() { render() {
let{Headertop,Footerdown, isRender, AccountProfiletype}=this.state; let{Headertop,Footerdown, isRender, AccountProfiletype,mygetHelmetapi}=this.state;
const common = { const common = {
isSuperAdmin:this.isSuperAdmin, isSuperAdmin:this.isSuperAdmin,
isAdminOrCreator:this.isAdminOrCreator, isAdminOrCreator:this.isAdminOrCreator,
@ -569,10 +635,12 @@ export function TPMIndexHOC(WrappedComponent) {
yslslowCheckresults:this.yslslowCheckresults, yslslowCheckresults:this.yslslowCheckresults,
yslslowCheckresultsNo:this.yslslowCheckresultsNo, yslslowCheckresultsNo:this.yslslowCheckresultsNo,
} };
// console.log("this.props.mygetHelmetapi");
// console.log(this.props.mygetHelmetapi);
return ( return (
<div className="indexHOC"> <div className="indexHOC">
{isRender===true ? <LoginDialog {isRender===true ? <LoginDialog
Modifyloginvalue={()=>this.hideLoginDialog()} Modifyloginvalue={()=>this.hideLoginDialog()}
{...this.props} {...this.props}
{...this.state} {...this.state}
@ -644,6 +712,7 @@ export function TPMIndexHOC(WrappedComponent) {
</Spin> </Spin>
<NewFooter <NewFooter
{...this.state} {...this.props}
Footerdown={Footerdown} Footerdown={Footerdown}
/> />

@ -17,7 +17,7 @@ class LoginRegisterPage extends Component {
// newMain clearfix // newMain clearfix
return ( return (
<div className=""> <div className="">
login
<LoginRegisterComponent {...this.props} {...this.state}></LoginRegisterComponent> <LoginRegisterComponent {...this.props} {...this.state}></LoginRegisterComponent>
<br></br> <br></br>
<br></br> <br></br>

@ -197,6 +197,7 @@ input::-ms-clear{display:none;}
.color-white{color: #ffffff!important;} .color-white{color: #ffffff!important;}
/*黑色*/ /*黑色*/
.color-dark{color: #05101a!important;} .color-dark{color: #05101a!important;}
.color-ooo{color: #000!important;}
/*灰色*/ /*灰色*/
.color-grey-name{color: #1A0B00!important;} .color-grey-name{color: #1A0B00!important;}
.color-grey-fa{color: #FAFAFA!important;} .color-grey-fa{color: #FAFAFA!important;}

@ -0,0 +1,5 @@
require 'rails_helper'
RSpec.describe CompetitionModeSetting, type: :model do
pending "add some examples to (or delete) #{__FILE__}"
end
Loading…
Cancel
Save