diff --git a/README.md b/README.md index 8dcb6d131..90f519de4 100644 --- a/README.md +++ b/README.md @@ -1,69 +1,70 @@ -# README - -This README would normally document whatever steps are necessary to get the -application up and running. - -Things you may want to cover: - -* Ruby version - -* System dependencies - -* Configuration - -* Database creation - -* Database initialization - -* How to run the test suite - -* Services (job queues, cache servers, search engines, etc.) - -* Deployment instructions - -* ... -#### Jbuilder介绍 -Jbuilder: https://github.com/rails/jbuilder - -#### Rails5 介绍 -rails guide: https://ruby-china.github.io/rails-guides/v5.0/ - -#### API设计文档 -doc for api: https://www.showdoc.cc/web/#/127895880302646?page_id=729221359592009 -user:Hjqreturn PW:12345678 - -#### 测试版访问地址:https://testeduplus2.educoder.net - -#### 实训平台繁忙 - 仓库异常:繁忙等级(81) - -#### 新版域名跳转规则 -新版域名要求总结:testeduplus2.educoder.net/(主要提供实训、实训课堂等业务) -目前有两个域名testbdweb.educoder.net(老版:主要提供课堂、项目、个人主页、后台等服务) - -要求: -1、两服务域名都应该启动‘提供服务 - -2、如果请求链接包含以下的形式,则域名跳至testeduplus2.educoder.net -testeduplus2.educoder.net/shixuns -testeduplus2.educoder.net/shixuns/* -testeduplus2.educoder.net/paths -testeduplus2.educoder.net/paths/* -testeduplus2.educoder.net/myshixuns/ -testeduplus2.educoder.net/tasks/* -testeduplus2.educoder.net/games/* - -如果不满足上述需求的,域名全部跳转至testbdweb.educoder.net -比如:门户首页,如果访问:testeduplus2.educoder.net 应为没包含上述链接。则调制testbdweb.educoder.net -在比如:testeduplus2.educoder.net /users/Hjqreturn没包含上述规则,则跳转到testbdweb.educoder.net/users/Hjqreturn - - -# 需要重构user_extensions 相关sql语句的地方标记 REDO:Extention - -# 文件上传:ActiveStorage -# 新能:bootsnap - -# 注意事项: -# 第一次部署需要执行一些rake任务 -# 配置redis地址 +# README +https://www.trustie.net/issues/24719 +[云上实验室] Logo、导航、底部备案信息定制化 +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... +#### Jbuilder介绍 +Jbuilder: https://github.com/rails/jbuilder + +#### Rails5 介绍 +rails guide: https://ruby-china.github.io/rails-guides/v5.0/ + +#### API设计文档 +doc for api: https://www.showdoc.cc/web/#/127895880302646?page_id=729221359592009 +user:Hjqreturn PW:12345678 + +#### 测试版访问地址:https://testeduplus2.educoder.net + +#### 实训平台繁忙 + 仓库异常:繁忙等级(81) + +#### 新版域名跳转规则 +新版域名要求总结:testeduplus2.educoder.net/(主要提供实训、实训课堂等业务) +目前有两个域名testbdweb.educoder.net(老版:主要提供课堂、项目、个人主页、后台等服务) + +要求: +1、两服务域名都应该启动‘提供服务 + +2、如果请求链接包含以下的形式,则域名跳至testeduplus2.educoder.net +testeduplus2.educoder.net/shixuns +testeduplus2.educoder.net/shixuns/* +testeduplus2.educoder.net/paths +testeduplus2.educoder.net/paths/* +testeduplus2.educoder.net/myshixuns/ +testeduplus2.educoder.net/tasks/* +testeduplus2.educoder.net/games/* + +如果不满足上述需求的,域名全部跳转至testbdweb.educoder.net +比如:门户首页,如果访问:testeduplus2.educoder.net 应为没包含上述链接。则调制testbdweb.educoder.net +在比如:testeduplus2.educoder.net /users/Hjqreturn没包含上述规则,则跳转到testbdweb.educoder.net/users/Hjqreturn + + +# 需要重构user_extensions 相关sql语句的地方标记 REDO:Extention + +# 文件上传:ActiveStorage +# 新能:bootsnap + +# 注意事项: +# 第一次部署需要执行一些rake任务 +# 配置redis地址 # 配置gitlab/intializers/gitlab_config.yml \ No newline at end of file diff --git a/app/controllers/admins/competitions_controller.rb b/app/controllers/admins/competitions_controller.rb new file mode 100644 index 000000000..3d6bef819 --- /dev/null +++ b/app/controllers/admins/competitions_controller.rb @@ -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 \ No newline at end of file diff --git a/app/controllers/boards_controller.rb b/app/controllers/boards_controller.rb index 1081a82ce..2bcc8d8f6 100644 --- a/app/controllers/boards_controller.rb +++ b/app/controllers/boards_controller.rb @@ -2,7 +2,7 @@ class BoardsController < ApplicationController before_action :require_login, :check_auth before_action :find_course, only: [:create] before_action :set_board, except: [:create] - before_action :teacher_or_admin_allowed + before_action :teacher_allowed def index @boards = @course.boards.includes(messages: [:last_reply, :author]) diff --git a/app/controllers/course_groups_controller.rb b/app/controllers/course_groups_controller.rb index 0e16d1bac..bfdb959b4 100644 --- a/app/controllers/course_groups_controller.rb +++ b/app/controllers/course_groups_controller.rb @@ -2,7 +2,7 @@ class CourseGroupsController < ApplicationController before_action :require_login, :check_auth before_action :set_group, except: [:create] before_action :find_course, only: [:create] - before_action :teacher_or_admin_allowed + before_action :teacher_allowed def create tip_exception("分班名称不能为空") if params[:name].blank? diff --git a/app/controllers/course_modules_controller.rb b/app/controllers/course_modules_controller.rb index 6e8afd525..0bef519fd 100644 --- a/app/controllers/course_modules_controller.rb +++ b/app/controllers/course_modules_controller.rb @@ -2,7 +2,8 @@ class CourseModulesController < ApplicationController before_action :require_login, :check_auth before_action :set_module, except: [:unhidden_modules] before_action :find_course, only: [:unhidden_modules] - before_action :teacher_or_admin_allowed + before_action :teacher_or_admin_allowed, except: [:add_second_category] + before_action :teacher_allowed, only: [:add_second_category] # 模块置顶 def sticky_module @@ -48,9 +49,9 @@ class CourseModulesController < ApplicationController tip_exception("已存在同名子目录") if @course_module.course_second_categories.exists?(name: params[:name].strip) ActiveRecord::Base.transaction do 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) - normal_status(0, "添加成功") + render :json => {category_id: category.id, status: 0, message: "添加成功"} rescue Exception => e uid_logger_error(e.message) tip_exception("添加子目录失败") diff --git a/app/controllers/course_second_categories_controller.rb b/app/controllers/course_second_categories_controller.rb index e5c3366cd..2de1637f2 100644 --- a/app/controllers/course_second_categories_controller.rb +++ b/app/controllers/course_second_categories_controller.rb @@ -1,7 +1,7 @@ class CourseSecondCategoriesController < ApplicationController before_action :require_login, :check_auth before_action :set_category - before_action :teacher_or_admin_allowed + before_action :teacher_allowed # 目录重命名 def rename_category diff --git a/app/controllers/courses_controller.rb b/app/controllers/courses_controller.rb index 0c643d15c..0b3e35519 100644 --- a/app/controllers/courses_controller.rb +++ b/app/controllers/courses_controller.rb @@ -35,7 +35,7 @@ class CoursesController < ApplicationController :transfer_to_course_group, :delete_from_course, :export_member_scores_excel, :search_users, :add_students_by_search, :get_historical_courses, :add_teacher_popup, :add_teacher, :export_couser_info, :export_member_act_score, - :update_informs, :new_informs, :delete_informs] + :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, :set_course_group, :create_group_by_importing_file, :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) tip_exception("切换失败") if course_member.STUDENT? - 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_student.update_attributes(is_active: 1) + course_student = CourseMember.find_by(user_id: current_user.id, role: %i[STUDENT], course_id: @course.id) + course_member.update_attributes!(is_active: 0) + 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, "切换成功") rescue => e uid_logger_error("switch_to_student error: #{e.message}") - tip_exception("切换失败") + tip_exception(e.message) raise ActiveRecord::Rollback end end @@ -1127,7 +1133,7 @@ class CoursesController < ApplicationController def top_banner @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 @course.increment!(:visits) end diff --git a/app/controllers/files_controller.rb b/app/controllers/files_controller.rb index 791d145c2..117475894 100644 --- a/app/controllers/files_controller.rb +++ b/app/controllers/files_controller.rb @@ -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 :validate_upload_params, only: %i[upload import] 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] def index sort = params[:sort] || 0 # 0: 降序;1: 升序 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 - @attachments = course_second_category_id.to_i == 0 ? @course.attachments : @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 = @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(author: [:user_extension, :course_members]) .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 @publish_count = @attachments.published.size @unpublish_count = @total_count - @publish_count @@ -137,9 +138,9 @@ class FilesController < ApplicationController def upload attachment_ids = params[:attachment_ids] course_second_category_id = params[:course_second_category_id] || 0 # 0: 为主目录, 其他为次目录id - is_unified_setting = params.has_key?(:is_unified_setting) ? params[:is_unified_setting] : true - publish_time = params[:publish_time] - course_group_publish_times = params[:course_group_publish_times] || [] + # is_unified_setting = params.has_key?(:is_unified_setting) ? params[:is_unified_setting] : true + # publish_time = params[:publish_time] + # course_group_publish_times = params[:course_group_publish_times] || [] begin attachment_ids.each do |attchment_id| @@ -148,9 +149,12 @@ class FilesController < ApplicationController attachment.container = @course attachment.course_second_category_id = course_second_category_id attachment.description = params[:description] - attachment.is_public = params[:is_public] ? 1 : 0 - 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.is_public = params[:is_public] && @course.is_public == 1 ? 1 : 0 + attachment.is_publish = @atta_is_publish + attachment.delay_publish = @atta_delay_publish + attachment.publish_time = @atta_publish_time + # attachment.set_publish_time(publish_time) if is_unified_setting + # attachment.set_course_group_publish_time(@course, course_group_publish_times) if @course.course_groups.size > 0 && !is_unified_setting && publish_time.blank? attachment.save! end end @@ -188,8 +192,9 @@ class FilesController < ApplicationController attach_copied_obj.created_on = Time.now attach_copied_obj.author = current_user attach_copied_obj.is_public = 0 - attach_copied_obj.is_publish = 1 - attach_copied_obj.publish_time = Time.now + attach_copied_obj.is_publish = @atta_is_publish + 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.copy_from = ori.copy_from.nil? ? ori.id : ori.copy_from if attach_copied_obj.attachtype == nil @@ -209,11 +214,7 @@ class FilesController < ApplicationController def update 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] - course_group_publish_times = params[:course_group_publish_times] || [] @old_attachment = @file @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_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.save! @new_attachment.delete 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 @old_attachment.description = params[:description] end - @old_attachment.set_public(is_public) + # @old_attachment.set_public(is_public) - if is_unified_setting - @old_attachment.set_publish_time(publish_time) - @old_attachment.attachment_group_settings.destroy_all - end + # if is_unified_setting + # @old_attachment.set_publish_time(publish_time) + # @old_attachment.attachment_group_settings.destroy_all + # end - if publish_time.blank? && @course.course_groups.size > 0 && !is_unified_setting - @old_attachment.set_course_group_publish_time(@course, course_group_publish_times) - end + # if publish_time.blank? && @course.course_groups.size > 0 && !is_unified_setting + # @old_attachment.set_course_group_publish_time(@course, course_group_publish_times) + # end @old_attachment.save! rescue Exception => e @@ -304,11 +309,19 @@ class FilesController < ApplicationController end 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 def validate_upload_params find_attachment_ids find_course_second_category_id 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 diff --git a/app/models/attachment.rb b/app/models/attachment.rb index ae28e7d52..8b7034ab9 100644 --- a/app/models/attachment.rb +++ b/app/models/attachment.rb @@ -9,6 +9,8 @@ class Attachment < ApplicationRecord belongs_to :course, foreign_key: :container_id, optional: true has_many :attachment_group_settings, :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", :search => "%#{keywords.split(" ").join('|')}%") unless keywords.blank? } @@ -96,7 +98,7 @@ class Attachment < ApplicationRecord def become_history 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, version: history.nil? ? 1 : history.version + 1, )) @@ -104,7 +106,7 @@ class Attachment < ApplicationRecord end 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 def set_public(is_public) diff --git a/app/models/competition_mode_setting.rb b/app/models/competition_mode_setting.rb new file mode 100644 index 000000000..b6bafa7c3 --- /dev/null +++ b/app/models/competition_mode_setting.rb @@ -0,0 +1,3 @@ +class CompetitionModeSetting < ApplicationRecord + belongs_to :course +end diff --git a/app/models/laboratory.rb b/app/models/laboratory.rb index 53e66ece0..f319ace80 100644 --- a/app/models/laboratory.rb +++ b/app/models/laboratory.rb @@ -19,7 +19,7 @@ class Laboratory < ApplicationRecord return if subdomain.blank? 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) end diff --git a/app/services/admins/save_laboratory_setting_service.rb b/app/services/admins/save_laboratory_setting_service.rb index 00e202cd9..f2a5c151e 100644 --- a/app/services/admins/save_laboratory_setting_service.rb +++ b/app/services/admins/save_laboratory_setting_service.rb @@ -30,7 +30,7 @@ class Admins::SaveLaboratorySettingService < ApplicationService hash = {} hash[:name] = strip nav[:name] hash[:link] = strip nav[:link] - hash[:hidden] = nav[:hidden].to_s == 0 + hash[:hidden] = nav[:hidden].to_s != '0' hash end end diff --git a/app/views/admins/competitions/index.html.erb b/app/views/admins/competitions/index.html.erb new file mode 100644 index 000000000..8fa238181 --- /dev/null +++ b/app/views/admins/competitions/index.html.erb @@ -0,0 +1,7 @@ +<% define_admin_breadcrumbs do %> + <% add_admin_breadcrumb('竞赛列表', admins_competitions_path) %> +<% end %> + +
+ <%= render partial: 'admins/shixuns/shared/list', locals: { shixuns: @shixuns } %> +
diff --git a/app/views/admins/shared/_sidebar.html.erb b/app/views/admins/shared/_sidebar.html.erb index 145910928..ca6fb2a46 100644 --- a/app/views/admins/shared/_sidebar.html.erb +++ b/app/views/admins/shared/_sidebar.html.erb @@ -66,6 +66,8 @@ <% end %> +
  • <%= sidebar_item(admins_competitions_path, '竞赛', icon: 'trophy', controller: 'admins-competitions') %>
  • +
  • <%= sidebar_item_group('#setting-submenu', '网站建设', icon: 'cogs') do %>
  • <%= sidebar_item(admins_carousels_path, '轮播图', icon: 'image', controller: 'admins-carousels') %>
  • diff --git a/app/views/attachments/_attachment.json.jbuilder b/app/views/attachments/_attachment.json.jbuilder index a8ad0a286..a21bf31c4 100644 --- a/app/views/attachments/_attachment.json.jbuilder +++ b/app/views/attachments/_attachment.json.jbuilder @@ -4,10 +4,11 @@ json.is_public attachment.publiced? # json.is_lock attachment.locked?(@is_member) json.is_lock !attachment.publiced? json.is_publish attachment.published? +json.delay_publish attachment.delay_publish json.publish_time attachment.publish_time json.unified_setting attachment.unified_setting json.filesize number_to_human_size(attachment.filesize) -json.quotes attachment.quotes_count +# json.quotes attachment.quotes_count json.description attachment.description json.downloads_count attachment.downloads_count json.created_on attachment.created_on diff --git a/app/views/competitions/competitions/index.json.jbuilder b/app/views/competitions/competitions/index.json.jbuilder index f0d70f69e..400f17379 100644 --- a/app/views/competitions/competitions/index.json.jbuilder +++ b/app/views/competitions/competitions/index.json.jbuilder @@ -20,7 +20,7 @@ json.competitions do if section json.current_stage do - json.name = section.competition_stage.name + json.name section.competition_stage.name json.start_time section.display_start_time json.end_time section.display_end_time end diff --git a/app/views/courses/left_banner.json.jbuilder b/app/views/courses/left_banner.json.jbuilder index 681145769..f3b80b4f5 100644 --- a/app/views/courses/left_banner.json.jbuilder +++ b/app/views/courses/left_banner.json.jbuilder @@ -11,7 +11,7 @@ json.course_modules @course_modules.each do |mod| case mod.module_type when "course_group" # json.none_group_count @course.none_group_count - json.second_category left_group_info @course + # json.second_category left_group_info @course when "board" course_board = @course.course_board if course_board.present? diff --git a/app/views/courses/mine.json.jbuilder b/app/views/courses/mine.json.jbuilder index c82e31f6b..fc6a5becc 100644 --- a/app/views/courses/mine.json.jbuilder +++ b/app/views/courses/mine.json.jbuilder @@ -1,5 +1,6 @@ json.partial! "commons/success" -json.data do - json.array! @courses, :id, :name, :updated_at +json.data @courses do |course| + json.(course, :id, :name, :updated_at, :end_date) + json.created_at course.created_at.strftime("%Y-%m-%d") end diff --git a/app/views/courses/top_banner.json.jbuilder b/app/views/courses/top_banner.json.jbuilder index 877ffcdf1..9a0554585 100644 --- a/app/views/courses/top_banner.json.jbuilder +++ b/app/views/courses/top_banner.json.jbuilder @@ -15,7 +15,7 @@ json.is_admin @user_course_identity < Course::PROFESSOR json.is_public @course.is_public == 1 json.code_halt @course.invite_code_halt == 1 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_assistant switch_assistant_role(@is_student, @course, @user) #json.join_course !@user.member_of_course?(@course) diff --git a/app/views/files/index.json.jbuilder b/app/views/files/index.json.jbuilder index 7fe3bf5b7..0002cf299 100644 --- a/app/views/files/index.json.jbuilder +++ b/app/views/files/index.json.jbuilder @@ -13,7 +13,10 @@ json.data do json.author do json.partial! "users/user_simple", user: attachment.author 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 diff --git a/app/views/files/show.json.jbuilder b/app/views/files/show.json.jbuilder index 941e66619..71359ccfd 100644 --- a/app/views/files/show.json.jbuilder +++ b/app/views/files/show.json.jbuilder @@ -1,3 +1,3 @@ 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 \ No newline at end of file diff --git a/app/views/homework_commons/show.json.jbuilder b/app/views/homework_commons/show.json.jbuilder index e78166fe0..74b60af48 100644 --- a/app/views/homework_commons/show.json.jbuilder +++ b/app/views/homework_commons/show.json.jbuilder @@ -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.description @homework.description - # 实训作业才有说明 if @homework.homework_type == "practice" json.explanation @homework.explanation +# else +# json.description @homework.description end # 附件 diff --git a/config/routes.rb b/config/routes.rb index 32725e8e9..f6f8db066 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -980,6 +980,8 @@ Rails.application.routes.draw do resource :laboratory_setting, only: [:show, :update] resource :laboratory_user, only: [:create, :destroy] end + + resources :competitions, only: [:index, :destroy] end resources :colleges, only: [] do diff --git a/db/migrate/20191014061301_migrate_course_atta.rb b/db/migrate/20191014061301_migrate_course_atta.rb new file mode 100644 index 000000000..04d085c0d --- /dev/null +++ b/db/migrate/20191014061301_migrate_course_atta.rb @@ -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 diff --git a/db/migrate/20191015013924_add_new_column_to_competitions.rb b/db/migrate/20191015013924_add_new_column_to_competitions.rb new file mode 100644 index 000000000..616a46059 --- /dev/null +++ b/db/migrate/20191015013924_add_new_column_to_competitions.rb @@ -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 diff --git a/db/migrate/20191015015723_create_competition_mode_settings.rb b/db/migrate/20191015015723_create_competition_mode_settings.rb new file mode 100644 index 000000000..5d170eeab --- /dev/null +++ b/db/migrate/20191015015723_create_competition_mode_settings.rb @@ -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 diff --git a/public/react/public/index.html b/public/react/public/index.html index f6eef196a..9b757d2c4 100755 --- a/public/react/public/index.html +++ b/public/react/public/index.html @@ -13,7 +13,7 @@ - + - EduCoder + + diff --git a/public/react/src/App.js b/public/react/src/App.js index 34b5d1a4f..fd945914a 100644 --- a/public/react/src/App.js +++ b/public/react/src/App.js @@ -9,7 +9,7 @@ import { Route, Switch } from 'react-router-dom'; - +import axios from 'axios'; import '@icedesign/base/dist/ICEDesignBase.css'; import '@icedesign/base/index.scss'; @@ -287,6 +287,7 @@ class App extends Component { Addcoursestypes:false, mydisplay:false, occupation:0, + mygetHelmetapi:undefined, } } @@ -327,7 +328,6 @@ class App extends Component { } componentDidMount() { this.disableVideoContextMenu(); - // force an update if the URL changes history.listen(() => { this.forceUpdate() @@ -336,7 +336,8 @@ class App extends Component { $("html").animate({ scrollTop: $('html').scrollTop() - 0 }) }); - initAxiosInterceptors(this.props) + initAxiosInterceptors(this.props); + this.getAppdata(); // // axios.interceptors.response.use((response) => { // // console.log("response"+response); @@ -362,15 +363,78 @@ class App extends Component { this.setState({ 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 ( + + this.Modifyloginvalue()}> @@ -413,10 +477,22 @@ class App extends Component { { + + return () + } + } /> { + + return () + } + } /> { + + return () + } + } /> {/*课堂*/} - + {/* */} @@ -502,7 +584,12 @@ class App extends Component { render={ (props)=>() }/> - + () + } + /> @@ -625,4 +712,4 @@ moment.defineLocale('zh-cn', { doy: 4 // The week that contains Jan 4th is the first week of the year. } }); -export default SnackbarHOC()(App); \ No newline at end of file +export default SnackbarHOC()(App) ; \ No newline at end of file diff --git a/public/react/src/AppConfig.js b/public/react/src/AppConfig.js index e1d5da561..9cf68503d 100644 --- a/public/react/src/AppConfig.js +++ b/public/react/src/AppConfig.js @@ -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; } + } // 非file_update请求 if (config.url.indexOf('update_file') === -1) { requestMap[config.url] = true; diff --git a/public/react/src/modules/courses/Resource/Fileslistitem.js b/public/react/src/modules/courses/Resource/Fileslistitem.js index d364f7ada..2610656cc 100644 --- a/public/react/src/modules/courses/Resource/Fileslistitem.js +++ b/public/react/src/modules/courses/Resource/Fileslistitem.js @@ -209,6 +209,9 @@ class Fileslistitem extends Component{ text-overflow:ellipsis; white-space:nowrap } + .mt2{ + margin-top:2px; + } `}
    window.$(`.sourceitem${index} input`).click() }>
    this.eventStop(event)}> @@ -248,6 +251,29 @@ class Fileslistitem extends Component{ :"" } {discussMessage.is_publish===false?:""} + + {this.props.isAdmin? + this.eventStop(event)}> + + this.settingList()}>设置 + + :""} + + {this.props.isStudent===true&&this.props.current_user.login===discussMessage.author.login? + this.eventStop(event)}> + + + this.settingList()}>设置 + + + + this.onDelete(discussMessage.id)}>删除 + + + :""}
    }

    - {title} + {title}

  • { firstRowRight }
  • diff --git a/public/react/src/modules/courses/coursesPublic/SelectResource.js b/public/react/src/modules/courses/coursesPublic/SelectResource.js index c323d1bae..0e76059c8 100644 --- a/public/react/src/modules/courses/coursesPublic/SelectResource.js +++ b/public/react/src/modules/courses/coursesPublic/SelectResource.js @@ -1,17 +1,34 @@ 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 {handleDateString} from 'educoder'; import NoneData from "../coursesPublic/NoneData"; import Modals from '../../modals/Modals'; - +import moment from 'moment'; const Option = Select.Option; const Search = Input.Search; - +const dateFormat ="YYYY-MM-DD HH:mm" function formatDate(date) { var dateee = new Date(date).toJSON(); 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{ constructor(props){ super(props); @@ -23,7 +40,9 @@ class Selectresource extends Component{ Resourcelist:undefined, hometypepvisible:true, getallfiles:false, - searchtype:'getallfiles' + searchtype:'getallfiles', + Radiovalue:0, + datatime:undefined } } componentDidMount() { @@ -32,11 +51,7 @@ class Selectresource extends Component{ componentDidUpdate = (prevProps) => { - let {getallfiles}=this.state; - - if ( prevProps.visible != this.props.visible ) { - } } @@ -197,7 +212,7 @@ class Selectresource extends Component{ savecouseShixunModal=()=>{ - let {patheditarry}=this.state; + let {patheditarry,datatime,Radiovalue}=this.state; let {coursesId,attachmentId}=this.props; 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, { course_id:coursesId, attachment_ids:patheditarry, 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) => { if(response.data.status===0){ - // this.setState({ - // Modalstype:true, - // Modalstopval:response.data.message, - // ModalSave:this.ModalCancelModalCancel, - // loadtype:true - // }) this.ModalCancelModalCancel(); this.props.updataleftNavfun(); 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({ - category_id:value + Radiovalue: e.target.value, + }); + } + + onChangeTimepublish= (date, dateString) => { + + this.setState({ + datatime:handleDateString(dateString), }) + } render(){ - let {Searchvalue,type,category_id,Resourcelist,hometypepvisible,patheditarry}=this.state; - let {visible,shixunmodallist}=this.props; + let {Searchvalue,type,Resourcelist,hometypepvisible,patheditarry,datatime}=this.state; + let {visible}=this.props; const antIcon = ; + const radioStyle = { + display: 'block', + height: '30px', + lineHeight: '30px', + }; return(
    {/*提示*/} @@ -373,10 +415,36 @@ class Selectresource extends Component{ }
    - +
    + 发布设置: + + + 立即发布 + + + 延迟发布 + this.onChangeTimepublish(e,index,undefined,1)} + disabledTime={disabledDateTime} + disabledDate={disabledDate} + disabled={this.state.Radiovalue===1?false:true} + /> + + (按照设置的时间定时发布) + +
    {this.state.patheditarrytype===true?

    请选择资源

    :""} - + {this.state.Radiovaluetype===true?

    发布时间不能为空

    :""}
    取消 确定 diff --git a/public/react/src/modules/courses/coursesPublic/SelectSetting.js b/public/react/src/modules/courses/coursesPublic/SelectSetting.js index 37b22c205..ff5751cc6 100644 --- a/public/react/src/modules/courses/coursesPublic/SelectSetting.js +++ b/public/react/src/modules/courses/coursesPublic/SelectSetting.js @@ -1,5 +1,5 @@ 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 {getUrl,handleDateString,appendFileSizeToUploadFileAll} from 'educoder'; import locale from 'antd/lib/date-picker/locale/zh_CN'; @@ -36,9 +36,10 @@ class Selectsetting extends Component{ course_groups:undefined, attachment_histories:undefined, datatime:undefined, - unified_setting:true, fileList:[], - fileListtype:false + fileListtype:false, + is_public:false, + Radiovaluetype:false } } @@ -54,53 +55,13 @@ class Selectsetting extends Component{ }) .then((response) => { 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({ datalist:response.data, description: response.data.description, - is_public: response.data.is_public, - unified_setting: response.data.unified_setting, + is_public:response.data.is_public, 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 - 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() } - } - 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)=>{ @@ -180,13 +109,26 @@ class Selectsetting extends Component{ } savecouseShixunModal=()=>{ - let {fileList,is_public,unified_setting,description,datatime,course_groups}=this.state; + let {fileList,is_public,description,datatime,Radiovalue}=this.state; let newfileList=[]; for(var list of fileList){ 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){ }else if(description.length>100){ @@ -196,29 +138,6 @@ class Selectsetting extends Component{ 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 attachmentId=this.props.attachmentId; let url="/files/"+this.props.discussMessageid+".json"; @@ -226,14 +145,12 @@ class Selectsetting extends Component{ axios.put(url,{ course_id:coursesId, 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_unified_setting:unified_setting, - publish_time:unified_setting===true?datatime===undefined?moment(new Date()).format('YYYY-MM-DD HH'):datatime:undefined, + publish_time:Radiovalue===0?undefined:datatime===undefined?moment(new Date(),dateFormat):datatime, description:description, - course_group_publish_times:unified_setting===false?course_groups:undefined + delay_publish:Radiovalue }).then((result)=>{ - if(result.data.status===0){ this.props.setupdate(attachmentId) this.props.showNotification("设置资源成功"); @@ -244,7 +161,6 @@ class Selectsetting extends Component{ } onChangeTimepublish= (date, dateString) => { - // console.log('startValue', dateString); this.setState({ 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) => { @@ -309,14 +200,7 @@ class Selectsetting extends Component{ fileListtype:false, 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:[] }) } - // const url = `/attachments/${file.response ? file.response.id : file.uid}.json` - } - onChangeTimepublishs= (date, dateString,key) => { - let {course_groups}=this.state; - let newgroup_publish=course_groups; - for(var i=0; i{ this.setState({ - course_groups:newgroup_publish, + is_public:e.target.checked }) } - - - selectassigngroups=(e,index,key)=>{ - let {course_groups}=this.state; - let newgroup_publish=course_groups; - for(var i=0; i{ + if(e.target.value===0){ + this.setState({ + datatime:undefined + }) } this.setState({ - course_groups:newgroup_publish, - }) - } - 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 - }) + Radiovalue: e.target.value, + }); } 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 = { width: 600, - // https://github.com/ant-design/ant-design/issues/15505 - // showUploadList={false},然后外部拿到 fileList 数组自行渲染列表。 - // showUploadList: false, action: `${getUrl()}/api/attachments.json`, onChange: this.handleChange, onRemove: this.onAttachmentRemove, @@ -401,9 +250,13 @@ class Selectsetting extends Component{ return isLt150M; }, }; + const radioStyle = { + display: 'block', + height: '30px', + lineHeight: '30px', + }; - - // console.log(this.props.has_course_groups) + console.log(this.state.Radiovalue) return(
      -
    • 资源名称
    • +
    • 资源名称
    • 下载
    • -
    • 引用
    • + {/*
    • 引用
    • */}
    • 版本号
    @@ -490,7 +343,7 @@ class Selectsetting extends Component{ `}
    -
  • +
  • {datalist&&datalist.title} {datalist&&datalist.attachment_histories.length===0?"":当前版本}
  • @@ -505,13 +358,13 @@ class Selectsetting extends Component{ {datalist&&datalist.attachment_histories.map((item,key)=>{ return(
    -
  • +
  • {item.title} {/*当前版本*/}
  • {item.downloads_count}
  • -
  • {item.quotes}
  • + {/*
  • {item.quotes}
  • */}
  • {moment(item.created_on).format('YYYY-MM-DD HH:mm')==="Invalid date"?"":moment(item.created_on).format('YYYY-MM-DD HH:mm')}
  • @@ -607,61 +460,15 @@ class Selectsetting extends Component{

    - {/**/} - {/*{this.state.fileList.length===0?"":this.state.fileList.map((item,key)=>{*/} - {/*return(*/} - {/*

    */} - {/**/} - {/**/} - {/**/} - {/**/} - {/*{item.name}*/} - {/**/} - {/**/} - {/*{item.response===undefined?"":isNaN(bytesToSize(item.filesize))?"123":bytesToSize(item.filesize)}*/} - {/**/} - {/*this.onAttachmentRemove(item.response===undefined?"":item.response.id&&item.response.id)}>*/} - {/*

    */} - {/*)*/} - {/*})}*/} - {this.state.newfileListtypes===true?

    请先上传资源

    :""} -

    +

    - - {/*

    */} - {/**/} - {/*勾选后所有用户可见,否则仅课堂成员可见*/} - {/**/} - {/*
    */} - {/*{this.props.has_course_groups&&this.props.has_course_groups===true?:""}*/} - {this.state.course_groupss&&this.state.course_groupss.length>0? - 统一设置(选中则所有分班使用相同的发布设置,否则各个单独设置) - :""} - - - - {/*this.props.has_course_groups&&this.props.has_course_groups===true?:""*/} -
    - {unified_setting===false? - this.state.course_groups&&this.state.course_groups.map((item,key)=>{ - return( -
    - - - - - - this.onChangeTimepublishs(e,index,key)} - // onChange={ this.onChangeTimepublish } - disabledTime={disabledDateTime} - disabledDate={disabledDate} - /> - - {key!=0?this.deletegrouppublish(key)}>:""} - {key===course_groups.length-1?:""} -
    - ) - }):""} -
    - + {this.props.course_is_public===true?
    + 公开:this.onChangepublic(e)}> + 选中,所有用户可见,否则课堂成员可见 + +
    :""}

    - {unified_setting===true? -

    - - - -

    :""} - {/*{this.state.course_group_idtypes===true?

    请选择分班

    :""}*/} - - {/*{course_group_publish_timestype===true?

    请填写完整

    :""}*/} + +
    + 发布设置: + this.RadioonChange(e)} value={this.state.Radiovalue} style={{'width': '460px'}}> + + 立即发布 + + + 延迟发布 + + + (按照设置的时间定时发布) + +
    + {this.state.descriptiontypes===true?

    描述不能超过最大限制:100个字符

    :""} + {this.state.Radiovaluetype===true?

    发布时间不能为空

    :""}
    diff --git a/public/react/src/modules/courses/coursesPublic/SendToFilesModal.js b/public/react/src/modules/courses/coursesPublic/SendToFilesModal.js index d14d5d267..c3f2db8c5 100644 --- a/public/react/src/modules/courses/coursesPublic/SendToFilesModal.js +++ b/public/react/src/modules/courses/coursesPublic/SendToFilesModal.js @@ -1,9 +1,11 @@ import React, { Component } from "react"; 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 InfiniteScroll from 'react-infinite-scroller'; +const dateFormat ="YYYY-MM-DD HH:mm" const Search = Input.Search const pageCount = 15; class Sendtofilesmodal extends Component{ @@ -170,7 +172,12 @@ class Sendtofilesmodal extends Component{ bottom: 93px; width: 82%; text-align: center; - }`} + } + .ModalWrappertitle{ + background: #D0E8FC; + padding: 10px; + } + `}

    选择的{moduleName}发送到指定课堂

    @@ -183,7 +190,12 @@ class Sendtofilesmodal extends Component{ >
    - {/* https://github.com/CassetteRocks/react-infinite-scroller/issues/70 */} + +

    +

    课堂名称
    +
    创建时间
    +
    结束时间
    +

    - +
    {course.name}
    +
    {moment(course.created_at).format('YYYY-MM-DD')}
    +
    {course.end_date}

    ) }) } - {loading && hasMore && ( -
    - -
    - )} - {/* TODO */} - {/* { - !hasMore &&
    没有更多了。。
    - } */} +
    diff --git a/public/react/src/modules/courses/coursesPublic/sendResource.js b/public/react/src/modules/courses/coursesPublic/sendResource.js index fbc2ebeb2..48677a8e1 100644 --- a/public/react/src/modules/courses/coursesPublic/sendResource.js +++ b/public/react/src/modules/courses/coursesPublic/sendResource.js @@ -1,5 +1,5 @@ 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 Modals from '../../modals/Modals'; import {getUrl,handleDateString,bytesToSize,appendFileSizeToUploadFileAll} from 'educoder'; @@ -40,7 +40,6 @@ class Sendresource extends Component{ ModalSave:"", fileListtype:false, loadtype:false, - is_unified_setting:true, is_public:false, datatime:undefined, // moment(new Date()).format('YYYY-MM-DD HH:mm:ss'), @@ -50,30 +49,15 @@ class Sendresource extends Component{ publish_time :"" }], course_groups:undefined, - course_groups_count:undefined + course_groups_count:undefined, + Radiovalue:0, + Radiovaluetype:false } } 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) => { if(!file.percent || file.percent == 100){ const url = `/attachments/${file.response ? file.response.id : file.uid}.json` @@ -174,8 +127,7 @@ class Sendresource extends Component{ } Saves=()=>{ - let id=this.props.categoryid; - let {fileList,description,is_public,is_unified_setting,datatime,course_group_publish_times} =this.state; + let {fileList,description,is_public,datatime,Radiovalue} =this.state; let newfileList=[]; for(var list of fileList){ @@ -188,17 +140,19 @@ class Sendresource extends Component{ }) return } - // if(is_unified_setting===false){ - // course_group_publish_times.forEach((item,key)=>{ - // if(item.course_group_id===undefined||item.publish_time===undefined){ - // this.setState({ - // course_group_publish_timestype:true - // }) - // return - // } - // }) - // - // } + + if(this.state.Radiovalue===1){ + if(datatime===undefined||datatime===null||datatime=== ""){ + this.setState({ + Radiovaluetype:true + }) + 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, attachment_ids:newfileList, is_public:is_public, - is_unified_setting:is_unified_setting, - publish_time:is_unified_setting===true?datatime===undefined? moment(new Date()).format('YYYY-MM-DD HH:mm'):datatime:undefined, + publish_time:Radiovalue===1?datatime===undefined? undefined:datatime:undefined, description:description, - course_group_publish_times:is_unified_setting===false?course_group_publish_times:undefined + delay_publish:Radiovalue, }).then((result)=>{ if(result.data.status===0){ - // this.setState({ - // Modalstype:true, - // Modalstopval:result.data.message, - // ModalSave:this.ModalCancelModalCancel, - // loadtype:true - // }) this.ModalCancelModalCancel(); this.props.updataleftNavfun(); - // this.props.showNotification(result.data.message); this.props.showNotification("上传资源成功"); 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)=>{ this.setState({ @@ -289,50 +227,20 @@ class Sendresource extends Component{ } - selectassigngroups=(e,index,key)=>{ - let {course_group_publish_times}=this.state; - let newgroup_publish=course_group_publish_times; - for(var i=0; i{ + if(e.target.value===0){ + this.setState({ + datatime:undefined + }) } this.setState({ - 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(){ - let {settextarea,newfileListtype,descriptiontype, - course_group_publish_timestype, - Modalstopval, - ModalCancel, - ModalSave, - loadtype, - is_unified_setting, + let { newfileListtype,descriptiontype, is_public, datatime, - course_group_publish_times, - course_groups }=this.state; const uploadProps = { @@ -350,7 +258,11 @@ class Sendresource extends Component{ return isLt150M; }, }; - + const radioStyle = { + display: 'block', + height: '30px', + lineHeight: '30px', + }; return(
    {/*提示*/} @@ -389,6 +301,7 @@ class Sendresource extends Component{ margin-right: 5px; } .ant-upload-list-item:hover .ant-upload-list-item-info{ + padding: 0 12px 0 0px; background-color:#fff; } .upload_1 .ant-upload-list { @@ -437,42 +350,12 @@ class Sendresource extends Component{ - (单个文件最大150M) + (单个文件最大150M) :""}

    - {/**/} - {/*{this.state.fileList.length===0?"":this.state.fileList.map((item,key)=>{*/} - {/*debugger*/} - {/*return(*/} - {/*

    */} - {/**/} - {/**/} - {/**/} - {/**/} - {/*{item.name}*/} - {/**/} - {/**/} - {/*{item.response===undefined?"":isNaN(bytesToSize(item.filesize))?"":bytesToSize(item.filesize)}*/} - {/**/} - {/*this.onAttachmentRemove(item.response===undefined?"":item.response.id&&item.response.id)}>*/} - {/*

    */} - {/*)*/} - {/*})}*/} + {newfileListtype===true&&this.state.fileListtype===false?

    请先上传资源

    :""} @@ -484,13 +367,12 @@ class Sendresource extends Component{ } `} - {/*
    */} - {/*勾选后所有用户可见,否则仅课堂成员可见*/} - {/**/} + {this.props.course_is_public===true?
    + 公开: + 选中,所有用户可见,否则课堂成员可见 + +
    :""} - {this.state.course_groups_count&&this.state.course_groups_count>0? - 统一设置(选中则所有分班使用相同的发布设置,否则各个单独设置) - :""} -
    - {is_unified_setting===false? - course_group_publish_times.map((item,key)=>{ - return( -
    - - - - this.onChangeTimepublish(e,index,key,2)} - // onChange={ this.onChangeTimepublish } - disabledTime={disabledDateTime} - disabledDate={disabledDate} - /> - {key!=0?this.deletegrouppublish(key)}>:""} - {key===course_group_publish_times.length-1&&key:""} -
    - ) - }) - - :""} -
    -

    - {is_unified_setting===true?

    - - this.onChangeTimepublish(e,index,undefined,1)} - disabledTime={disabledDateTime} - disabledDate={disabledDate} - /> - -

    :""} + +
    + 发布设置: + + + 立即发布 + + + 延迟发布 + this.onChangeTimepublish(e,index,undefined,1)} + disabledTime={disabledDateTime} + disabledDate={disabledDate} + disabled={this.state.Radiovalue===1?false:true} + /> + + (按照设置的时间定时发布) + +
    + {/*{course_group_publish_timestype===true?

    请填写完整

    :""}*/} {descriptiontype===true?

    请输入资源描述,最大限制100个字符

    :""} + {this.state.Radiovaluetype===true?

    发布时间不能为空

    :""}
    {this.props.Cancelname} this.Saves()}>{this.props.Savesname} diff --git a/public/react/src/modules/courses/exercise/Studentshavecompletedthelist.js b/public/react/src/modules/courses/exercise/Studentshavecompletedthelist.js index e1a1f17f9..ae5a50e6d 100644 --- a/public/react/src/modules/courses/exercise/Studentshavecompletedthelist.js +++ b/public/react/src/modules/courses/exercise/Studentshavecompletedthelist.js @@ -2666,8 +2666,11 @@ class Studentshavecompletedthelist extends Component { .ysltableows2 .ant-table-thead > tr > th, .ant-table-tbody > tr > td { padding: 9px; } + mysjysltable1 .ant-table-thead > tr > th, .ant-table-tbody > tr > td { + padding: 9px; + } `} -
    +
    {data === undefined ? "" : div > .ant-spin .ant-spin-dot { 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; } `} @@ -2823,7 +2829,10 @@ class Studentshavecompletedthelist extends Component { .ysltableows .ant-table-tbody > tr > td{ 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; } ` @@ -2834,7 +2843,7 @@ class Studentshavecompletedthelist extends Component { {data === undefined ? "" :
    tr > th, .ant-table-tbody > tr > td { padding: 9px; } + mysjysltable4 .ant-table-thead > tr > th, .ant-table-tbody > tr > td { + padding: 9px; + } `}
    {datas === undefined ? "" :
    { - setCheckBoxRoles(member_roles) - }, [member_roles]) + // useEffect(() => { + // if (checkBoxRoles.length != member_roles.length) { // 死循环 + // setCheckBoxRoles(member_roles) + // } + // }, [member_roles]) function onCheckBoxChange(val) { console.log(val) @@ -73,8 +75,8 @@ function ChangeRolePop({ member_roles = [], record, courseId, onChangeRoleSucces } > - 修改角色 + 修改角色 ) } -export default ChangeRolePop \ No newline at end of file +export default memo(ChangeRolePop) \ No newline at end of file diff --git a/public/react/src/modules/courses/members/CourseGroupChooser.js b/public/react/src/modules/courses/members/CourseGroupChooser.js index 125f10b51..655754dc4 100644 --- a/public/react/src/modules/courses/members/CourseGroupChooser.js +++ b/public/react/src/modules/courses/members/CourseGroupChooser.js @@ -89,7 +89,7 @@ function CourseGroupChooser({ course_groups, isAdminOrCreator = true, item, inde

    trigger('groupAdd')} - >添加分班 + >新建分班

    ) diff --git a/public/react/src/modules/courses/members/CourseGroupList.js b/public/react/src/modules/courses/members/CourseGroupList.js index ec0b23fb3..6c0e915cc 100644 --- a/public/react/src/modules/courses/members/CourseGroupList.js +++ b/public/react/src/modules/courses/members/CourseGroupList.js @@ -152,7 +152,7 @@ function CourseGroupList(props) { } { // pageType !== TYPE_STUDENTS && - !isCourseEnd && isAdmin && isParent && addDir()}>新建分班 } + !isCourseEnd && isAdmin && addDir()}>新建分班 } {/* { isAdmin && !isParent && course_group_id != 0 && deleteDir()}>删除分班 } */} {/* { @@ -210,13 +210,13 @@ function CourseGroupList(props) { onPressEnter={onPressEnter} > -
    + {!!none_group_member_count &&
    未分班: {none_group_member_count}个学生 {props.history.push(`/courses/${courseId}/course_groups/0`)}}>查看 -
    +
    } {course_groups && !!course_groups.length ? diff --git a/public/react/src/modules/courses/members/CourseGroupListTable.js b/public/react/src/modules/courses/members/CourseGroupListTable.js index 4645cf838..656ae67bc 100644 --- a/public/react/src/modules/courses/members/CourseGroupListTable.js +++ b/public/react/src/modules/courses/members/CourseGroupListTable.js @@ -28,7 +28,6 @@ function CourseGroupListTable(props) { } course_groups.forEach((record) => { const id = record.id - debugger; let _clipboard = new ClipboardJS(`.copyBtn_${id}`); _clipboard.on('success', (e) => { props.showNotification('复制成功') @@ -135,14 +134,14 @@ function CourseGroupListTable(props) { {isAdmin && 复制邀请码 } {isStudent && addToDir(record)} style={''}>加入分班} - onGoDetail(record)} style={''}>查看 + onGoDetail(record)} style={''}>查看 } }) return columns } - const addToDir = async (record) => { + const doAddToDir = async (record) => { const courseId = props.match.params.coursesId const url = `/courses/${courseId}/join_course_group.json` const course_group_id = record.id @@ -151,11 +150,27 @@ function CourseGroupListTable(props) { course_group_id }) if (response && response.data.status == 0) { - props.showNotification('加入成功') + props.showNotification(`已加入分班:${record.name}`) props.updataleftNavfun() props.onOperationSuccess && props.onOperationSuccess() } } + const addToDir = (record) => { + props.confirm({ + + content: `是否确认加入分班: ${record.name}?`, + + okText: '确认', + cancelText: '取消', + + onOk: () => { + doAddToDir(record) + }, + onCancel() { + console.log('Cancel'); + }, + }); + } function onDelete(record) { props.confirm({ diff --git a/public/react/src/modules/courses/members/studentsList.js b/public/react/src/modules/courses/members/studentsList.js index 9acc4c0bf..a63509c59 100644 --- a/public/react/src/modules/courses/members/studentsList.js +++ b/public/react/src/modules/courses/members/studentsList.js @@ -107,7 +107,7 @@ const buildColumns = (that,isParent) => { } ]; if (course_groups && course_groups.length) { - columns.push({ + this.isStudentPage && columns.push({ title: '分班', dataIndex: 'course_group_name', key: 'course_group_name', @@ -130,7 +130,7 @@ const buildColumns = (that,isParent) => { } const isAdmin = that.props.isAdmin() if (isAdmin) { - columns.unshift({ + !that.isStudentPage && columns.unshift({ title: '', dataIndex: 'check', key: 'check', @@ -148,8 +148,9 @@ const buildColumns = (that,isParent) => { render: (text, record) => { return ( - that.onDelete(record)} style={'grey'}>删除学生 - that.onDelete(record)} style={'grey'}>删除学生 + {record.member_roles && record.member_roles.length && { showNotification={that.props.showNotification} getUserId={that.props.isUserid} fetchUser={that.props.fetchUser} - > + >} ) }, @@ -319,6 +320,9 @@ class studentsList extends Component{ isAdmin && on('updateNavSuccess', this.updateNavSuccess) } componentWillUnmount() { + if (this.clipboard) { + this.clipboard.destroy() + } const isAdmin = this.props.isAdmin() if (isAdmin) { off('addStudentSuccess', this.addStudentSuccessListener) @@ -330,6 +334,7 @@ class studentsList extends Component{ } updateNavSuccess = () => { this.fetchCourseGroups() + this.fetchAll() } addStudentSuccessListener=(e, data)=>{ @@ -418,12 +423,14 @@ class studentsList extends Component{ invite_code: result.data.invite_code, isSpin:false }, () => { - if (!this.clipboard) { - const clipboard = new ClipboardJS('.copybtn'); - clipboard.on('success', (e) => { - this.props.showNotification('复制成功') - }); - this.clipboard = clipboard + if (course_group_id) { + if (!this.clipboard) { + const clipboard = new ClipboardJS('.copybtn'); + clipboard.on('success', (e) => { + this.props.showNotification('复制成功') + }); + this.clipboard = clipboard + } } }) } @@ -547,7 +554,7 @@ class studentsList extends Component{ addDir = () => { trigger('groupAdd', this.props.coursesids) } - addToDir = async () => { + doAddToDir = async () => { const courseId = this.props.match.params.coursesId const url = `/courses/${courseId}/join_course_group.json` const course_group_id = this.props.match.params.course_group_id @@ -556,11 +563,27 @@ class studentsList extends Component{ course_group_id }) if (response && response.data.status == 0) { - this.props.showNotification('加入成功') + this.props.showNotification(`已加入分班:${this.state.course_group_name}`) this.props.updataleftNavfun() this.fetchAll() } } + addToDir = (record) => { + this.props.confirm({ + + content: `是否确认加入分班: ${this.state.course_group_name}?`, + + okText: '确认', + cancelText: '取消', + + onOk: () => { + this.doAddToDir() + }, + onCancel() { + console.log('Cancel'); + }, + }); + } renameDir = () => { const course_group_id = this.props.match.params.course_group_id trigger('groupRename', { id: parseInt(course_group_id), name: this.state.course_group_name}) @@ -572,15 +595,15 @@ class studentsList extends Component{
    是否确认删除?
    , onOk: () => { - // const cid = this.props.match.params.coursesId 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` axios.delete(url) .then((response) => { if (response.data.status == 0) { this.props.showNotification('删除成功') - this.props.history.push(response.data.right_url) + this.props.history.push(`/courses/${courseId}/course_groups`) } }) .catch(function (error) { @@ -666,11 +689,14 @@ class studentsList extends Component{ if (this.props.match.path.endsWith('students')) { } else if (course_group_id) { - pageType = TYPE_COURSE_GOURP_PARENT - } else { 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( @@ -683,7 +709,12 @@ class studentsList extends Component{ - {course_group_name || '未分班'} + + + { this.props.history.push(`/courses/${courseId}/course_groups`)}} + style={{color: '#212121', verticalAlign: 'initial', marginRight: '14px' }} + > + {course_group_name || '未分班'} {isAdmin && invite_code && 邀请码: @@ -708,23 +739,24 @@ class studentsList extends Component{ searchPlaceholder={ '请输入姓名、学号进行搜索' } firstRowRight={ - { + {/* { // pageType !== TYPE_STUDENTS && - isSuperAdmin && + !isStudentPage && isSuperAdmin && this.refs['createGroupByImportModal'].setVisible(true)}>导入创建分班 - } + } */} + { - // pageType !== TYPE_STUDENTS && - !isCourseEnd && isAdmin && isParent && this.addDir()}>添加分班 } + !isStudentPage && isAdmin && !isParent && course_group_id != 0 && this.deleteDir()}>删除分班 } { - isStudent && !isParent && course_group_id != 0 && this.addToDir()}>加入分班 } + !isStudentPage && isAdmin && !isParent && course_group_id != 0 && this.renameDir()}>分班重命名 } { - isAdmin && !isParent && course_group_id != 0 && this.deleteDir()}>删除分班 } + !isStudentPage && !isCourseEnd && isAdmin && this.addDir()}>新建分班 } + { - isAdmin && !isParent && course_group_id != 0 && this.renameDir()}>分班重命名 } + !isStudentPage && isStudent && !isParent && course_group_id != 0 && this.addToDir()}>加入分班 } + }

    - {datas&&datas.category_name===undefined||datas&&datas.category_name===null?datas&&datas.main_category_name:datas&&datas.category_name+" 作业列表"} + + {datas&&datas.category_name===undefined||datas&&datas.category_name===null?datas&&datas.main_category_name: + {datas&&datas.category_name} + 作业列表 + } +

  • {datas===undefined?"":datas.homeworks && datas.homeworks.length>1?this.props.isAdminOrCreator()===true?datas&&datas.category_name===undefined||datas&&datas.category_name===null? diff --git a/public/react/src/modules/forums/MemoTechShare.js b/public/react/src/modules/forums/MemoTechShare.js index de6ba074c..d32bd2e2f 100644 --- a/public/react/src/modules/forums/MemoTechShare.js +++ b/public/react/src/modules/forums/MemoTechShare.js @@ -1,116 +1,116 @@ -import React, { Component } from 'react'; -import { Redirect } from 'react-router'; - -import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom"; - -import PropTypes from 'prop-types'; - -import classNames from 'classnames' - -import Pagination from 'rc-pagination'; - -import { postPaginationHOC } from './PostPaginationHOC' - -import PostItem from './PostItem' - -import ForumsNavTab from './ForumsNavTab' - -// import queryString from 'query-string' -import { queryString } from 'educoder' - -import MemoList from './MemoList' - - -class MemoTechShare extends Component { - constructor(props) { - super(props) - - this.handleLocationChange = this.handleLocationChange.bind(this); - - this.state = { - - } - } - - onPaginationChange(pageNum, pageSize) { - this.props.onPaginationChange(pageNum, pageSize) - } - - componentDidMount() { - // this.handleLocationChange(this.props.history.location); - // this.unlisten = this.props.history.listen(this.handleLocationChange); - } - - componentWillUnmount() { - // this.unlisten(); - } - componentDidUpdate(prevProps) { - if(this.props.match.params.memoType !== prevProps.match.params.memoType) { - // do something - console.log(`memoType changed`) - this.props.fetchMemos(); - } - } - - componentWillReceiveProps(newProps, newContext) { - if (newProps.match.url === this.props.match.url) { - const oldParsed = queryString.parse(this.props.location.search); - const newParsed = queryString.parse(newProps.location.search); - if (!newParsed.page && oldParsed.page || - (oldParsed.order && newParsed.order && oldParsed.order != newParsed.order)) { - this.props.fetchMemos(); - } - console.log('componentWillReceiveProps...') - } - } - - handleLocationChange(location) { - console.log(`- - - location: '${location.pathname}'`); - if (location.pathname) { - if (location.pathname.indexOf('/forums/categories/all') != -1 - && this.props.location.search && this.props.location.search.indexOf('order=') != -1 - && location.search.indexOf('order=') != -1) { - const oldParsed = queryString.parse(this.props.location.search); - const newParsed = queryString.parse(location.search); - if (oldParsed.order != newParsed.order) { // 只有在热门和最新间跳转时,才需要处理 - this.props.fetchMemos(); - } - } - } - } - - renderMemoList() { - - - // const { memo_list, user } = this.props; - // if (!memo_list) { - // return '' - // } - // return memo_list.map( (item, index) => { - - // return ( - // this.setTop(memo)} - // setDown={(memo)=>this.setDown(memo)} memo={item} - // > - // ) - // }) - return this.props.renderMemoList(); - } - - render() { - const { match, history, currentPage, memo_count ,memo_list } = this.props - - return ( - - - this.renderMemoList()} - onPaginationChange={ (pageNum, pageSize) => this.props.onPaginationChange(pageNum, pageSize) } - > - - - ); - } -} - -export default postPaginationHOC() ( MemoTechShare ); +import React, { Component } from 'react'; +import { Redirect } from 'react-router'; + +import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom"; + +import PropTypes from 'prop-types'; + +import classNames from 'classnames' + +import Pagination from 'rc-pagination'; + +import { postPaginationHOC } from './PostPaginationHOC' + +import PostItem from './PostItem' + +import ForumsNavTab from './ForumsNavTab' + +// import queryString from 'query-string' +import { queryString } from 'educoder' + +import MemoList from './MemoList' + + +class MemoTechShare extends Component { + constructor(props) { + super(props) + + this.handleLocationChange = this.handleLocationChange.bind(this); + + this.state = { + + } + } + + onPaginationChange(pageNum, pageSize) { + this.props.onPaginationChange(pageNum, pageSize) + } + + componentDidMount() { + // this.handleLocationChange(this.props.history.location); + // this.unlisten = this.props.history.listen(this.handleLocationChange); + } + + componentWillUnmount() { + // this.unlisten(); + } + componentDidUpdate(prevProps) { + if(this.props.match.params.memoType !== prevProps.match.params.memoType) { + // do something + console.log(`memoType changed`) + this.props.fetchMemos(); + } + } + + componentWillReceiveProps(newProps, newContext) { + if (newProps.match.url === this.props.match.url) { + const oldParsed = queryString.parse(this.props.location.search); + const newParsed = queryString.parse(newProps.location.search); + if (!newParsed.page && oldParsed.page || + (oldParsed.order && newParsed.order && oldParsed.order != newParsed.order)) { + this.props.fetchMemos(); + } + // console.log('componentWillReceiveProps...') + } + } + + handleLocationChange(location) { + console.log(`- - - location: '${location.pathname}'`); + if (location.pathname) { + if (location.pathname.indexOf('/forums/categories/all') != -1 + && this.props.location.search && this.props.location.search.indexOf('order=') != -1 + && location.search.indexOf('order=') != -1) { + const oldParsed = queryString.parse(this.props.location.search); + const newParsed = queryString.parse(location.search); + if (oldParsed.order != newParsed.order) { // 只有在热门和最新间跳转时,才需要处理 + this.props.fetchMemos(); + } + } + } + } + + renderMemoList() { + + + // const { memo_list, user } = this.props; + // if (!memo_list) { + // return '' + // } + // return memo_list.map( (item, index) => { + + // return ( + // this.setTop(memo)} + // setDown={(memo)=>this.setDown(memo)} memo={item} + // > + // ) + // }) + return this.props.renderMemoList(); + } + + render() { + const { match, history, currentPage, memo_count ,memo_list } = this.props + + return ( + + + this.renderMemoList()} + onPaginationChange={ (pageNum, pageSize) => this.props.onPaginationChange(pageNum, pageSize) } + > + + + ); + } +} + +export default postPaginationHOC() ( MemoTechShare ); diff --git a/public/react/src/modules/login/EducoderLogin.js b/public/react/src/modules/login/EducoderLogin.js index a6600b1e0..680c4bbc7 100644 --- a/public/react/src/modules/login/EducoderLogin.js +++ b/public/react/src/modules/login/EducoderLogin.js @@ -19,6 +19,8 @@ import { notification } from "antd"; 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/common/formCommon.css" import '../courses/css/Courses.css'; @@ -108,7 +110,8 @@ class EducoderLogin extends Component { } componentDidMount() { - + // console.log("EducoderLogin"); + // console.log(this.props); } Setlogins=(i)=>{ @@ -137,6 +140,9 @@ class EducoderLogin extends Component { render() { let {showbool,loginstatus,logini} = this.state; + console.log("EducoderLogingetHelmetapi"); + console.log(this.props); + // console.log(this.props.mygetHelmetapi); return (
    @@ -148,7 +154,13 @@ class EducoderLogin extends Component { "width": "100%" }}>
    - this.gohome()} src={educodernet}/> + { + this.props.mygetHelmetapi===undefined||this.props.mygetHelmetapi.login_logo_url===null|| this.props.mygetHelmetapi.login_logo_url===undefined? + this.gohome()} src={educodernet}/> + : + this.gohome()} src={getImageUrl(this.props.mygetHelmetapi.login_logo_url)}/> + } +
    @@ -196,8 +208,7 @@ class EducoderLogin extends Component { } } - -export default EducoderLogin; +export default EducoderLogin ; // showbool === 2 ? //
    :""} {isRender===true?
    -
    {this.handleDialogClose()}}> +
    {this.handleDialogClose()}}>
    diff --git a/public/react/src/modules/tpm/NewFooter.js b/public/react/src/modules/tpm/NewFooter.js index be1a1ed29..5d2403a04 100644 --- a/public/react/src/modules/tpm/NewFooter.js +++ b/public/react/src/modules/tpm/NewFooter.js @@ -39,16 +39,23 @@ class NewFooter extends Component {
    -

    - © 2019 EduCoder - 湘ICP备17009477号 - - 湘公网安备43019002000962号 - - Trustie   &   IntelliDE inside. + © 2019 EduCoder + 湘ICP备17009477号 + + 湘公网安备43019002000962号 + + Trustie   &   IntelliDE inside. 版权所有 湖南智擎科技有限公司 -

    +

    + : +
    + + } +
    diff --git a/public/react/src/modules/tpm/NewHeader.js b/public/react/src/modules/tpm/NewHeader.js index de8fade26..330573f81 100644 --- a/public/react/src/modules/tpm/NewHeader.js +++ b/public/react/src/modules/tpm/NewHeader.js @@ -65,13 +65,26 @@ class NewHeader extends Component { showTrial:false, setevaluatinghides:false, occupation:0, - mydisplay:false + mydisplay:false, + headtypesonClickbool:false, + headtypess:"/", + mygetHelmetapi2:undefined, } - // console.log("176") + console.log("176") // 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() { + console.log("componentDidMount1"); + this.getAppdata(); window._header_componentHandler = this; //下拉框的显示隐藏 @@ -633,11 +646,80 @@ submittojoinclass=(value)=>{ this.setState({ 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() { const isLogin = true; // 这里不会出现未登录的情况,服务端在服务端路由时发现如果是未登录,则跳转到登录页了。 - const {match ,} = this.props; + const {match,} = this.props; let {Addcoursestypes, tojoinitemtype, @@ -655,35 +737,127 @@ submittojoinclass=(value)=>{ user, isRender, showSearchOpentype, + headtypesonClickbool, + headtypess, + mygetHelmetapi2, }=this.state; /* 用户名称 用户头像url */ - let activeIndex = false; - let activeForums = false; - let activeShixuns = false; - let activePaths = false; - let coursestype=false; + let activeIndex = false; + let activeForums = false; + let activeShixuns = false; + let activePaths = false; + let coursestype=false; let activePackages=false; let activeMoopCases=false; - if (match.path === '/forums') { - activeForums = true; - } else if (match.path.startsWith('/shixuns')) { - activeShixuns = true; - }else if (match.path.startsWith('/paths')) { - activePaths = true; - } else if (match.path.startsWith('/courses')) { - coursestype = true; - }else if (match.path.startsWith('/crowdsourcing')) { + if (match.path === '/forums') { + activeForums = true; + } else if (match.path.startsWith('/shixuns')) { + activeShixuns = true; + }else if (match.path.startsWith('/paths')) { + activePaths = true; + } else if (match.path.startsWith('/courses')) { + coursestype = true; + }else if (match.path.startsWith('/crowdsourcing')) { activePackages = true; - }else if(match.path.startsWith('/moop_cases')){ - activeMoopCases = true; - }else { - activeIndex = true; - } + }else if(match.path.startsWith('/moop_cases')){ + activeMoopCases = true; + }else { + 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 @@ -699,9 +873,14 @@ submittojoinclass=(value)=>{ {...this.props} {...this.state} />:""} - - 高校智能化教学与实训平台 - + this.headtypesonClick("/",false)} className={"fl mr30 ml25 mt10"}> + { + mygetHelmetapi2===undefined||mygetHelmetapi2.nav_logo_url===null||mygetHelmetapi2.nav_logo_url===undefined? + 高校智能化教学与实训平台 + : + 高校智能化教学与实训平台 + } + -
    - {/*<%= 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? +
    +
      + {/*
    • 首页
    • */} + {/*
    • 实训路径
    • */} + { + 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( +
    • 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? + {item.name} + : + {item.name} + } +
    • + ) + }) + } + {/*
    • */} + {/* 实践课程*/} + {/*
    • */} + + {/*
    • 课堂
    • */} + {/*
    • */} + {/* /!*课堂*!/*/} + {/* 翻转课堂*/} + {/*
    • */} + + {/*
    • */} + {/* 实训项目*/} + {/* */} + {/* */} + {/*
    • */} + + + {/*
    • 教学案例
    • */} + {/*
    • */} + {/* 在线竞赛*/} + {/* */} + {/*
    • */} + {/*
    • 教学案例
    • */} + {/*
    • */} + {/*众包创新*/} + {/*
    • */} + {/*
    • 交流问答
    • */} + {/*工程认证*/} + + + + +
    • 0 ? 'block' : 'none'}}> + 职业路径 +
      0 ? 'block' : 'none'}}> +
        + {this.props.Headertop === undefined ? "" : this.props.Headertop.career_url.map((item, key) => { + return( +
      • {item.name}
      • + ) + }) + } +
      +
      +
    • +
    +
    + // :mygetHelmetapi2===undefined||mygetHelmetapi2.navbar===null||mygetHelmetapi2.navbar===undefined||mygetHelmetapi2.navbar.length===0? + //
    + // + //
      + // {/*
    • 首页
    • */} + // + // {/*
    • 实训路径
    • */} + //
    • + // 实践课程 + //
    • + // + // {/*
    • 课堂
    • */} + //
    • + // {/*课堂*/} + // 翻转课堂 + //
    • + // + //
    • + // 实训项目 + // {/**/} + // {/**/} + //
    • + // + //
    • 0 ? 'block' : 'none'}}> + // 职业路径 + //
      0 ? 'block' : 'none'}}> + //
        + // {this.props.Headertop === undefined ? "" : this.props.Headertop.career_url.map((item, key) => { + // return( + //
      • {item.name}
      • + // ) + // }) + // } + //
      + //
      + //
    • + // + // {/*
    • 教学案例
    • */} + //
    • + // 在线竞赛 + // {/**/} + //
    • + //
    • 教学案例
    • + // {/*
    • */} + // {/*众包创新*/} + // {/*
    • */} + //
    • 交流问答
    • + //
    • 工程认证
    • + //
    + //
    + : +
    + +
      + {/*
    • 首页
    • */} + + {/*
    • 实训路径
    • */} +
    • + 实践课程 +
    • + + {/*
    • 课堂
    • */} +
    • + {/*课堂*/} + 翻转课堂 +
    • + +
    • + 实训项目 + {/**/} + {/**/} +
    • + +
    • 0 ? 'block' : 'none'}}> + 职业路径 +
      0 ? 'block' : 'none'}}> +
        + {this.props.Headertop === undefined ? "" : this.props.Headertop.career_url.map((item, key) => { + return( +
      • {item.name}
      • + ) + }) + } +
      +
      +
    • + + {/*
    • 教学案例
    • */} +
    • + 在线竞赛 + {/**/} +
    • +
    • 教学案例
    • + {/*
    • */} + {/*众包创新*/} + {/*
    • */} +
    • 交流问答
    • +
    • 工程认证
    • +
    +
    + } -
    -
      - {/*
    • 首页
    • */} - {/*
    • 实训路径
    • */} -
    • - 实践课程 -
    • - {/*
    • 课堂
    • */} -
    • - {/*课堂*/} - 翻转课堂 -
    • -
    • - 实训项目 - - -
    • - -
    • 0 ? 'block' : 'none'}}> - 职业路径 -
      0 ? 'block' : 'none'}}> -
        - {this.props.Headertop === undefined ? "" : this.props.Headertop.career_url.map((item, key) => { - return( -
      • {item.name}
      • - ) - }) - } -
      -
      -
    • - - {/*
    • 教学案例
    • */} -
    • - 在线竞赛 - -
    • -
    • 教学案例
    • - {/*
    • */} - {/*众包创新*/} - {/*
    • */} -
    • 交流问答
    • -
    • 工程认证
    • -
    - - -
    -