diff --git a/app/assets/javascripts/admin.js b/app/assets/javascripts/admin.js index 72a2ff118..196404300 100644 --- a/app/assets/javascripts/admin.js +++ b/app/assets/javascripts/admin.js @@ -32,8 +32,11 @@ $(document).on('turbolinks:load', function(){ // flash alert提示框自动关闭 if($('.admin-alert-container .alert').length > 0){ setTimeout(function(){ - $('.admin-alert-container .alert').alert('close'); + $('.admin-alert-container .alert:not(.alert-danger)').alert('close'); }, 2000); + setTimeout(function(){ + $('.admin-alert-container .alert.alert-danger').alert('close'); + }, 5000); } }); diff --git a/app/assets/javascripts/admins/mirror_repositories/edit.js b/app/assets/javascripts/admins/mirror_repositories/edit.js new file mode 100644 index 000000000..7fb3ad10d --- /dev/null +++ b/app/assets/javascripts/admins/mirror_repositories/edit.js @@ -0,0 +1,19 @@ +$(document).on('turbolinks:load', function() { + if ($('body.admins-mirror-repositories-edit-page, body.admins-mirror-repositories-update-page').length > 0) { + var $form = $('form.edit-mirror'); + + $form.validate({ + errorElement: 'span', + errorClass: 'danger text-danger', + rules: { + "mirror_repository[type_name]": { + required: true + } + } + }); + + $form.submit(function(e){ + if(!$form.valid()){ e.preventDefault(); } + }); + } +}); \ No newline at end of file diff --git a/app/assets/javascripts/admins/mirror_repositories/index.js b/app/assets/javascripts/admins/mirror_repositories/index.js new file mode 100644 index 000000000..2e30bdd94 --- /dev/null +++ b/app/assets/javascripts/admins/mirror_repositories/index.js @@ -0,0 +1,4 @@ +$(document).on('turbolinks:load', function() { + if ($('body.admins-mirror-repositories-index-page').length > 0) { + } +}); \ No newline at end of file diff --git a/app/assets/javascripts/admins/modals/admin-choose-mirror-modal.js b/app/assets/javascripts/admins/modals/admin-choose-mirror-modal.js new file mode 100644 index 000000000..6111b2401 --- /dev/null +++ b/app/assets/javascripts/admins/modals/admin-choose-mirror-modal.js @@ -0,0 +1,32 @@ +$(document).on('turbolinks:load', function() { + $('.admin-modal-container').on('show.bs.modal', '.modal.admin-choose-mirror-modal', function(){ + var $modal = $('.modal.admin-choose-mirror-modal'); + var $form = $modal.find('form.admin-choose-mirror-form'); + + var validateForm = function(){ + var checkedValue = $form.find('input[name="mirror_number"]:checked').val(); + + if(checkedValue == undefined){ + $modal.find('.error').html('必须选择一种镜像保存!'); + return false; + } + return true; + } + + $modal.on('click', '.submit-btn', function(){ + $form.find('.error').html(''); + var url = $form.attr('action'); + + if (validateForm()) { + $.ajax({ + method: 'POST', + dataType: 'script', + url: url, + data: $form.serialize(), + }).done(function(){ + $modal.modal('hide'); + }); + } + }); + }) +}); \ No newline at end of file diff --git a/app/assets/javascripts/admins/modals/admin-replace-mirror-modal.js b/app/assets/javascripts/admins/modals/admin-replace-mirror-modal.js new file mode 100644 index 000000000..8b7a129a6 --- /dev/null +++ b/app/assets/javascripts/admins/modals/admin-replace-mirror-modal.js @@ -0,0 +1,89 @@ +$(document).on('turbolinks:load', function() { + var $modal = $('.modal.admin-replace-mirror-modal'); + if ($modal.length > 0) { + var $form = $modal.find('form.admin-replace-mirror-form'); + var $mirrorIdInput = $modal.find('.modal-body input[name="mirror_id"]'); + var $mirrorSelect = $modal.find('.new-mirror-select'); + + var setMirror = function(id, name){ + $mirrorIdInput.val(id); + $form.find('.mirror-id-container').html(id); + $form.find('.mirror-name-container').html(name); + } + + $form.validate({ + errorElement: 'span', + errorClass: 'danger text-danger', + rules: { + new_mirror_id: { + required: true + }, + }, + messages: { + new_mirror_id: { + required: '请选择新镜像' + } + } + }); + + // modal ready fire + $modal.on('show.bs.modal', function (event) { + var $link = $(event.relatedTarget); + + var mirrorId = $link.data('id'); + var mirrorName = $link.data('name'); + + setMirror(mirrorId, mirrorName); + $mirrorSelect.select2('val', ' '); + }); + $modal.on('hide.bs.modal', function () { + setMirror('', ''); + $mirrorSelect.select2('val', ' '); + $('#new_mirror_id-error').remove(); + }); + + $mirrorSelect.select2({ + theme: 'bootstrap4', + placeholder: '输入要合并的镜像名', + minimumInputLength: 1, + ajax: { + url: '/admins/mirror_repositories/for_select', + dataType: 'json', + data: function(params){ + return { keyword: params.term }; + }, + processResults: function(data){ + return { results: data.mirrors } + } + }, + templateResult: function (item) { + if(!item.id || item.id === '') return item.text; + return item.name; + }, + templateSelection: function(item){ + if (item.id) { + $('#new_mirror_id-error').remove(); + $('#new_mirror_id').val(item.id); + } + return item.name || item.text; + } + }); + + $modal.on('click', '.submit-btn', function(){ + $form.find('.error').html(''); + + if ($form.valid()) { + var url = $form.data('url'); + + $.ajax({ + method: 'POST', + dataType: 'script', + url: url, + data: $form.serialize(), + }).done(function(){ + $modal.modal('hide'); + }); + } + }); + } +}); \ No newline at end of file diff --git a/app/assets/stylesheets/admin.scss b/app/assets/stylesheets/admin.scss index 0aa1329ca..36f1e537f 100644 --- a/app/assets/stylesheets/admin.scss +++ b/app/assets/stylesheets/admin.scss @@ -47,4 +47,9 @@ label.error { .flex-1 { flex: 1; -} \ No newline at end of file +} + +.font-12 { font-size: 12px !important; } +.font-14 { font-size: 14px !important; } +.font-16 { font-size: 16px !important; } +.font-18 { font-size: 18px !important; } \ No newline at end of file diff --git a/app/controllers/admins/choose_mirror_repositories_controller.rb b/app/controllers/admins/choose_mirror_repositories_controller.rb new file mode 100644 index 000000000..c178e0d76 --- /dev/null +++ b/app/controllers/admins/choose_mirror_repositories_controller.rb @@ -0,0 +1,11 @@ +class Admins::ChooseMirrorRepositoriesController < Admins::BaseController + def new + @mirror = MirrorRepository.find(params[:mirror_id]) + @new_mirror = MirrorOperationRecord.where(mirror_repository_id: @mirror.id, status: 1, user_id: -1).first + end + + def create + mirror = MirrorRepository.find(params[:mirror_id]) + Admins::ChooseMirrorService.call(mirror, current_user, params[:mirror_number]) + end +end \ No newline at end of file diff --git a/app/controllers/admins/mirror_repositories_controller.rb b/app/controllers/admins/mirror_repositories_controller.rb new file mode 100644 index 000000000..63e4667d1 --- /dev/null +++ b/app/controllers/admins/mirror_repositories_controller.rb @@ -0,0 +1,96 @@ +class Admins::MirrorRepositoriesController < Admins::BaseController + before_action :check_shixun_mirrors!, only: [:index] + + def index + mirrors = MirrorRepository.all + mirrors = mirrors.reorder(status: :desc, main_type: :desc, type_name: :asc) + + @mirrors = paginate mirrors.includes(:mirror_scripts) + @error_mirror_names = MirrorRepository.where(status: 5).pluck(:name) + end + + def new + @mirror = MirrorRepository.new + end + + def create + @mirror = MirrorRepository.new + Admins::SaveMirrorRepositoryService.call(@mirror, current_user, form_params) + + flash[:success] = '保存成功' + redirect_to edit_admins_mirror_repository_path(@mirror) + rescue ActiveRecord::RecordInvalid + flash.now[:danger] = '保存失败' + render 'new' + rescue Admins::SaveMirrorRepositoryService::Error => ex + flash.now[:danger] = ex.message + render 'new' + end + + def edit + @mirror = current_mirror + end + + def update + @mirror = current_mirror + + Admins::SaveMirrorRepositoryService.call(current_mirror, current_user, form_params) + + flash[:success] = '保存成功' + redirect_to edit_admins_mirror_repository_path(current_mirror) + rescue ActiveRecord::RecordInvalid + flash.now[:danger] = '保存失败' + render 'edit' + rescue Admins::SaveMirrorRepositoryService::Error => ex + flash.now[:danger] = ex.message + render 'edit' + end + + def destroy + return render_js_error('该状态下不允许删除') unless current_mirror.deletable? + + current_mirror.destroy! + + render_delete_success + end + + def for_select + mirrors = MirrorRepository.all + + keyword = params[:keyword].to_s.strip + mirrors = mirrors.where('name LIKE ?', "%#{keyword}%") if keyword.present? + + @mirrors = paginate mirrors + + render_ok(count: @mirrors.total_count, mirrors: @mirrors.as_json(only: %i[id name])) + end + + def merge + origin_mirror = MirrorRepository.find(params[:mirror_id]) + mirror = MirrorRepository.find(params[:new_mirror_id]) + + ActiveRecord::Base.transaction do + origin_mirror.update!(name: mirror.name, mirrorID: mirror.mirrorID) + mirror.destroy! + end + end + + private + + def current_mirror + @_current_mirror ||= MirrorRepository.find(params[:id]) + end + + def form_params + columns = %i[type_name main_type time_limit resource_limit cpu_limit memory_limit description status] + params.require(:mirror_repository).permit(*columns) + end + + def check_shixun_mirrors! + return unless request.format.html? + + Admins::CheckShixunMirrorsService.call + rescue Admins::CheckShixunMirrorsService::Error => e + internal_server_error(e.message) + end +end diff --git a/app/controllers/concerns/admins/render_helper.rb b/app/controllers/concerns/admins/render_helper.rb index 0ccc16a09..80f008b08 100644 --- a/app/controllers/concerns/admins/render_helper.rb +++ b/app/controllers/concerns/admins/render_helper.rb @@ -1,36 +1,34 @@ module Admins::RenderHelper extend ActiveSupport::Concern + def render_by_format(hash) + format = request.format.symbol + hash.key?(format) ? hash[format].call : hash[:html].call + end + def render_forbidden - respond_to do |format| - format.html { redirect_to '/403' } - format.json { super } - end + render_by_format(html: -> { redirect_to '/403' }, + json: -> { render status: 403, json: { messages: I18n.t('error.forbidden') } } ) end def render_not_found - respond_to do |format| - format.html { render 'admins/shared/404' } - format.js { render_js_error('资源未找到') } - format.json { render status: 404, json: { message: '资源未找到' } } - end + render_by_format(html: -> { render 'admins/shared/404' }, + js: -> { render_js_error('资源未找到') }, + json: -> { render status: 404, json: { message: '资源未找到' } }) end def render_unprocessable_entity(message) - respond_to do |format| - format.html { render 'admins/shared/422' } - format.js { render_js_error(message) } - format.json { render status: 422, json: { message: message } } - end + render_by_format(html: -> { render 'admins/shared/422' }, + js: -> { render_js_error(message) }, + json: -> { render status: 422, json: { message: message } }) end alias_method :render_error, :render_unprocessable_entity - def internal_server_error - respond_to do |format| - format.html { render 'admins/shared/500' } - format.js { render_js_error('系统错误') } - format.json { render status: 500, json: { message: '系统错误' } } - end + def internal_server_error(message = '系统错误') + @message = message + render_by_format(html: -> { render 'admins/shared/500' }, + js: -> { render_js_error(message) }, + json: -> { render status: 500, json: { message: message } }) end def render_js_template(template, **opts) diff --git a/app/controllers/files_controller.rb b/app/controllers/files_controller.rb index a916f5351..a6eafe0f3 100644 --- a/app/controllers/files_controller.rb +++ b/app/controllers/files_controller.rb @@ -171,6 +171,7 @@ class FilesController < ApplicationController begin attachment_ids.each do |attachment_id| ori = Attachment.find_by_id(attachment_id) + # 同一个资源可以多次发送到课堂 @course.attachments.each do |att| @exist = false if att.id == ori.id || (!att.copy_from.nil? && !ori.copy_from.nil? && att.copy_from == ori.copy_from) || att.copy_from == ori.id || att.id == ori.copy_from diff --git a/app/controllers/subjects_controller.rb b/app/controllers/subjects_controller.rb index 5b926ee48..2f3bbd21c 100644 --- a/app/controllers/subjects_controller.rb +++ b/app/controllers/subjects_controller.rb @@ -270,7 +270,7 @@ class SubjectsController < ApplicationController page = params[:page] || 1 member_ids = @subject.subject_members.map(&:user_id).join(',') condition = "%#{params[:search].strip}%".gsub(" ","") - @users = User.where("id not in (?) and status = 1 and LOWER(concat(lastname, firstname, login, mail)) LIKE ?", member_ids, "#{condition}") + @users = User.where("id not in (?) and status = 1 and LOWER(concat(lastname, ifnull(firstname, ''), login)) LIKE ?", member_ids, "#{condition}") @users = @users.page(page).per(10) @users = @users.includes(:user_extension) diff --git a/app/helpers/admins/mirror_repositories_helper.rb b/app/helpers/admins/mirror_repositories_helper.rb new file mode 100644 index 000000000..d62494e24 --- /dev/null +++ b/app/helpers/admins/mirror_repositories_helper.rb @@ -0,0 +1,23 @@ +module Admins::MirrorRepositoriesHelper + def mirror_type_tag(mirror) + case mirror.main_type + when '1' then ''.html_safe + when '0' then ''.html_safe + end + end + + def mirror_status_tag(mirror) + case mirror.status + when 0 + ''.html_safe + when 1 + ''.html_safe + when 2, 3 + ''.html_safe + when 4 + ''.html_safe + when 5 + ''.html_safe + end + end +end \ No newline at end of file diff --git a/app/models/mirror_operation_record.rb b/app/models/mirror_operation_record.rb new file mode 100644 index 000000000..39e352a0f --- /dev/null +++ b/app/models/mirror_operation_record.rb @@ -0,0 +1,7 @@ +# status: 0 创建镜像; 1 修改镜像ID; 2 修改镜像name 3 删除镜像 4.从主节点同步镜像到子节点(子节点发生异常), 5. 修改镜像别名, 6. 修改镜像的状态 +# user_id: -1时,证明是非人为因素造成,中间层异常导致 +class MirrorOperationRecord < ActiveRecord::Base + default_scope { order(created_at: :desc) } + + belongs_to :mirror_repository +end diff --git a/app/models/mirror_repository.rb b/app/models/mirror_repository.rb index be26b5ad1..e29b008ad 100644 --- a/app/models/mirror_repository.rb +++ b/app/models/mirror_repository.rb @@ -8,4 +8,8 @@ class MirrorRepository < ApplicationRecord scope :published_mirror, -> { where(status: 1) } scope :published_main_mirror, -> { published_mirror.where(main_type: 1) } scope :published_small_mirror, -> { published_mirror.where(main_type: 0) } + + def deletable? + status != 1 && !shixun_mirror_repositories.exists? + end end diff --git a/app/services/admins/check_shixun_mirrors_service.rb b/app/services/admins/check_shixun_mirrors_service.rb new file mode 100644 index 000000000..868fab042 --- /dev/null +++ b/app/services/admins/check_shixun_mirrors_service.rb @@ -0,0 +1,89 @@ +class Admins::CheckShixunMirrorsService < ApplicationService + Error = Class.new(StandardError) + + def call + bridge_images + + ActiveRecord::Base.transaction do + check_sync_mirrors! + + check_mirrors! + end + end + + private + + def mirrors + bridge_images['images'] + end + + def sync_mirrors + bridge_images['imagesNotSync'] + end + + def check_mirrors! + return if mirrors.blank? + image_names = [] + + mirrors.each do |data| + mirror = JSON.parse(data) + + name_repository = MirrorRepository.find_by(name: mirror['imageName']) + id_repository = MirrorRepository.find_by(mirrorID: mirror['imageID']) + + image_names << mirror['imageName'] + + if name_repository.blank? && id_repository.present? # 镜像名称被修改 + id_repository.update_column(:status, 2) + MirrorOperationRecord.create!(mirror_repository_id: id_repository.id, mirror_id: mirror['imageID'], + mirror_name: mirror['imageName'], status: 2, user_id: -1) + elsif name_repository.blank? # 镜像不存在、创建镜像 + new_repository = MirrorRepository.create!(mirrorID: mirror['imageID'], name: mirror['imageName']) + MirrorOperationRecord.create!(mirror_repository_id: new_repository.id, mirror_id: mirror['imageID'], + mirror_name: mirror['imageName'], status: 0, user_id: -1) + elsif name_repository.mirrorID != mirror['imageID'] # 镜像ID被修改 + name_repository.update_column(:status, 2) + MirrorOperationRecord.create!(mirror_repository_id: name_repository.id, mirror_id: mirror['imageID'], + mirror_name: mirror['imageName'], status: 1, user_id: -1) + end + end + + # 判断中间层镜像是否被删除 + MirrorRepository.find_each do |mirror| + next if mirror&.name.blank? || image_names.index(mirror.name) + + mirror.update_column(:status, 4) + MirrorOperationRecord.create!(mirror_repository_id: mirror.id, mirror_id: mirror&.mirrorID, + mirror_name: mirror.name, status: 3, user_id: -1) + end + end + + def check_sync_mirrors! + return if sync_mirrors.blank? + + sync_mirrors.each do |data| + mirror = JSON.parse(data) + + repository = MirrorRepository.find_by(name: mirror['imageName']) + next if repository.blank? || repository.status != 1 + + repository.update_column(:status, 5) + MirrorOperationRecord.create!(mirror_repository_id: repository.id, mirror_id: mirror['imageID'], + mirror_name: mirror['imageName'], status: 4, user_id: -1) + end + end + + def bridge_images + @_bridge_images ||= begin + url = EduSetting.get('cloud_bridge') + res = Faraday.get(url) + + raise Error, '拉取镜像信息异常' if res && res['code'].nonzero? + + res + rescue => e + Rails.logger.error("get response failed ! #{e.message}") + raise Error, '实训云平台繁忙(繁忙等级:84)' + end + end +end \ No newline at end of file diff --git a/app/services/admins/choose_mirror_service.rb b/app/services/admins/choose_mirror_service.rb new file mode 100644 index 000000000..77d187884 --- /dev/null +++ b/app/services/admins/choose_mirror_service.rb @@ -0,0 +1,21 @@ +class Admins::ChooseMirrorService < ApplicationService + attr_reader :mirror, :user, :number + + def initialize(mirror, user, mirror_number) + @mirror = mirror + @user = user + @number = mirror_number + end + + def call + if mirror.mirrorID == number + mirror.update_column(:status, 1) + return + end + + old_number = mirror.mirrorID + mirror.update!(mirrorID: number, status: 1) + MirrorOperationRecord.create!(mirror_repository_id: mirror.id, mirror_id: number, mirror_name: mirror.name, + status: 1, user_id: user.id, old_tag: old_number, new_tag: mirror.mirrorID) + end +end \ No newline at end of file diff --git a/app/services/admins/save_mirror_repository_service.rb b/app/services/admins/save_mirror_repository_service.rb new file mode 100644 index 000000000..4aff64f66 --- /dev/null +++ b/app/services/admins/save_mirror_repository_service.rb @@ -0,0 +1,37 @@ +class Admins::SaveMirrorRepositoryService < ApplicationService + Error = Class.new(StandardError) + + attr_reader :mirror, :user, :params + + def initialize(mirror, user, params) + @mirror = mirror + @user = user + @params = params + end + + def call + mirror.assign_attributes(params) + + raise Error, '镜像别名重复' if MirrorRepository.where.not(id: mirror.id).exists?(type_name: params[:type_name]) + + ActiveRecord::Base.transaction do + record_operation! if mirror.persisted? + + mirror.save! + end + end + + private + + def record_operation! + if mirror.type_name_changed? + MirrorOperationRecord.create!(mirror_repository_id: mirror.id, status: 5, + user_id: user.id, old_tag: mirror.type_name_in_database, + new_tag: mirror.type_name) + elsif mirror.status_changed? + MirrorOperationRecord.create!(mirror_repository_id: mirror.id, status: 5, + user_id: user.id, old_tag: mirror.status_in_database, + new_tag: mirror.status) + end + end +end \ No newline at end of file diff --git a/app/views/admins/choose_mirror_repositories/create.js.erb b/app/views/admins/choose_mirror_repositories/create.js.erb new file mode 100644 index 000000000..585ecb1af --- /dev/null +++ b/app/views/admins/choose_mirror_repositories/create.js.erb @@ -0,0 +1,5 @@ +$.notify({ message: '操作成功' },{ type: 'success' }); + +setTimeout(function(){ + window.location.reload(); +}, 500) \ No newline at end of file diff --git a/app/views/admins/choose_mirror_repositories/new.js.erb b/app/views/admins/choose_mirror_repositories/new.js.erb new file mode 100644 index 000000000..8603011ab --- /dev/null +++ b/app/views/admins/choose_mirror_repositories/new.js.erb @@ -0,0 +1,2 @@ +$('.admin-modal-container').html("<%= j( render partial: 'admins/mirror_repositories/shared/choose_mirror_modal', locals: { mirror: @mirror, new_mirror: @new_mirror } ) %>"); +$('.modal.admin-choose-mirror-modal').modal('show'); \ No newline at end of file diff --git a/app/views/admins/mirror_repositories/edit.html.erb b/app/views/admins/mirror_repositories/edit.html.erb new file mode 100644 index 000000000..7df580c96 --- /dev/null +++ b/app/views/admins/mirror_repositories/edit.html.erb @@ -0,0 +1,8 @@ +<% + define_admin_breadcrumbs do + add_admin_breadcrumb('镜像管理', admins_mirror_repositories_path) + add_admin_breadcrumb('镜像详情') + end +%> + +<%= render partial: 'admins/mirror_repositories/shared/form', locals: { mirror: @mirror, form_action: 'update' } %> \ No newline at end of file diff --git a/app/views/admins/mirror_repositories/index.html.erb b/app/views/admins/mirror_repositories/index.html.erb new file mode 100644 index 000000000..ac384408f --- /dev/null +++ b/app/views/admins/mirror_repositories/index.html.erb @@ -0,0 +1,23 @@ +<% define_admin_breadcrumbs do %> + <% add_admin_breadcrumb('镜像管理') %> +<% end %> + +
+
+ <%= link_to '新建', new_admins_mirror_repository_path, class: 'btn btn-primary' %> +
+ +<% if @error_mirror_names.present? %> +
+ 以下镜像异常: + <% @error_mirror_names.each do |mirror_name| %> + <%= mirror_name %> + <% end %> +
+<% end %> + +
+ <%= render partial: 'admins/mirror_repositories/shared/list', locals: { mirrors: @mirrors } %> +
+ +<%= render 'admins/mirror_repositories/shared/replace_mirror_modal' %> \ No newline at end of file diff --git a/app/views/admins/mirror_repositories/index.js.erb b/app/views/admins/mirror_repositories/index.js.erb new file mode 100644 index 000000000..58ccb1ef8 --- /dev/null +++ b/app/views/admins/mirror_repositories/index.js.erb @@ -0,0 +1 @@ +$('.mirror-repository-list-container').html("<%= j( render partial: 'admins/mirror_repositories/shared/list', locals: { mirrors: @mirrors } ) %>"); \ No newline at end of file diff --git a/app/views/admins/mirror_repositories/merge.js.erb b/app/views/admins/mirror_repositories/merge.js.erb new file mode 100644 index 000000000..585ecb1af --- /dev/null +++ b/app/views/admins/mirror_repositories/merge.js.erb @@ -0,0 +1,5 @@ +$.notify({ message: '操作成功' },{ type: 'success' }); + +setTimeout(function(){ + window.location.reload(); +}, 500) \ No newline at end of file diff --git a/app/views/admins/mirror_repositories/new.html.erb b/app/views/admins/mirror_repositories/new.html.erb new file mode 100644 index 000000000..792fe0857 --- /dev/null +++ b/app/views/admins/mirror_repositories/new.html.erb @@ -0,0 +1,8 @@ +<% + define_admin_breadcrumbs do + add_admin_breadcrumb('镜像管理', admins_mirror_repositories_path) + add_admin_breadcrumb('新建镜像') + end +%> + +<%= render partial: 'admins/mirror_repositories/shared/form', locals: { mirror: @mirror, form_action: 'create' } %> \ No newline at end of file diff --git a/app/views/admins/mirror_repositories/shared/_choose_mirror_modal.html.erb b/app/views/admins/mirror_repositories/shared/_choose_mirror_modal.html.erb new file mode 100644 index 000000000..99c846c70 --- /dev/null +++ b/app/views/admins/mirror_repositories/shared/_choose_mirror_modal.html.erb @@ -0,0 +1,42 @@ + \ No newline at end of file diff --git a/app/views/admins/mirror_repositories/shared/_form.html.erb b/app/views/admins/mirror_repositories/shared/_form.html.erb new file mode 100644 index 000000000..c8ab2a186 --- /dev/null +++ b/app/views/admins/mirror_repositories/shared/_form.html.erb @@ -0,0 +1,42 @@ +
+ <%= simple_form_for([:admins, mirror], url: { action: form_action }, html: { class: 'edit-mirror col-md-12' }, defaults: { wrapper_html: { class: 'col-md-4' } }) do |f| %> + <% unless mirror.new_record? %> +
+ <%= f.input :mirrorID, label: '镜像ID', input_html: { readonly: true, class: 'form-control-plaintext' } %> + <%= f.input :name, label: '镜像名称', input_html: { readonly: true, class: 'form-control-plaintext' } %> +
+ <% end %> + +
+ <%= f.input :type_name, as: :string, label: '镜像别名 *' %> + +
+ <%= f.label :main_type, label: '类别' %> + <%= f.select :main_type, [['主类别', 1],['小类别', 0]], {}, class: 'form-control optional' %> +
+
+ +
+ <%= f.input :time_limit, as: :integer, label: '评测时限(S)' %> + <%= f.input :resource_limit, as: :integer, label: '磁盘限制(K)' %> +
+ +
+ <%= f.input :cpu_limit, as: :integer, label: 'CPU限制(核)' %> + <%= f.input :memory_limit, as: :integer, label: '内存限制(M)' %> +
+ +
+ <%= f.input :description, as: :text, label: '描述', wrapper_html: { class: 'col-md-8' } %> +
+ +
+ <%= f.input :status, as: :radio_buttons, label: '状态', collection: [%w(未发布 0), %w(已发布 1)], wrapper_html: { class: 'col-md-4' } %> +
+ +
+ <%= f.button :submit, value: '保存', class: 'btn-primary mr-3 px-4', 'data-disable-with': '保存中...' %> + <%= link_to '取消', admins_mirror_repositories_path, class: 'btn btn-secondary px-4' %> +
+ <% end %> +
\ No newline at end of file diff --git a/app/views/admins/mirror_repositories/shared/_list.html.erb b/app/views/admins/mirror_repositories/shared/_list.html.erb new file mode 100644 index 000000000..b4c2df70e --- /dev/null +++ b/app/views/admins/mirror_repositories/shared/_list.html.erb @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + <% if mirrors.present? %> + <% mirrors.each do |mirror| %> + + + + + + + + + + + + <% end %> + <% else %> + <%= render 'admins/shared/no_data_for_table' %> + <% end %> + +
ID类别镜像别名镜像名称镜像描述修改时间脚本状态操作
<%= mirror.id %><%= mirror_type_tag(mirror) %><%= display_text(mirror.type_name) %><%= overflow_hidden_span mirror.name, width: 150 %><%= overflow_hidden_span mirror.description, width: 240 %><%= mirror.updated_at.strftime('%Y-%m-%d %H:%M') %> + <% if mirror.main_type == "1" %> + <%= link_to "/users/modify_script?mirror_id=#{mirror.id}", target: '_blank' do %> + + <% end %> + <% end %> + <%= mirror_status_tag mirror %> + <%= link_to '编辑', edit_admins_mirror_repository_path(mirror), class: 'action edit-action' %> + + <% if mirror.status == 2 %> + <%= link_to '同步', new_admins_choose_mirror_repository_path(mirror_id: mirror.id), remote: true, class: 'action sync-action' %> + <% end %> + + <%= javascript_void_link '替换', class: 'action replace-action', data: { toggle: 'modal', target: '.admin-replace-mirror-modal', id: mirror.id, name: mirror.name } %> + + <% if mirror.deletable? %> + <%= delete_link '删除', admins_mirror_repository_path(mirror, element: ".mirror-repository-item-#{mirror.id}"), class: 'delete-mirror-repository-action' %> + <% end %> +
+ +<%= render partial: 'admins/shared/paginate', locals: { objects: mirrors } %> \ No newline at end of file diff --git a/app/views/admins/mirror_repositories/shared/_replace_mirror_modal.html.erb b/app/views/admins/mirror_repositories/shared/_replace_mirror_modal.html.erb new file mode 100644 index 000000000..f2b2d20c8 --- /dev/null +++ b/app/views/admins/mirror_repositories/shared/_replace_mirror_modal.html.erb @@ -0,0 +1,33 @@ + \ No newline at end of file diff --git a/app/views/admins/shared/500.html.erb b/app/views/admins/shared/500.html.erb index f053f58ec..b1488d6ff 100644 --- a/app/views/admins/shared/500.html.erb +++ b/app/views/admins/shared/500.html.erb @@ -2,5 +2,5 @@
500
-
系统错误
+
<%= @message %>
\ No newline at end of file diff --git a/app/views/admins/shared/_paginate.html.erb b/app/views/admins/shared/_paginate.html.erb index b7e40e879..5c15f762c 100644 --- a/app/views/admins/shared/_paginate.html.erb +++ b/app/views/admins/shared/_paginate.html.erb @@ -1,5 +1,5 @@
- <% if objects.size.nonzero? %> + <% if objects && objects.size.nonzero? %>
<%= page_entries_info objects %>
<% end %> <%= paginate objects, views_prefix: 'admins', remote: true %> diff --git a/app/views/admins/shared/_sidebar.html.erb b/app/views/admins/shared/_sidebar.html.erb index ab30e8bd3..8c995ec45 100644 --- a/app/views/admins/shared/_sidebar.html.erb +++ b/app/views/admins/shared/_sidebar.html.erb @@ -20,6 +20,12 @@ <% end %> +
  • + <%= sidebar_item_group('#shixun-submenu', '实训管理', icon: 'window-restore') do %> +
  • <%= sidebar_item(admins_mirror_repositories_path, '镜像管理', icon: 'cubes', controller: 'admins-mirror_repositories') %>
  • + <% end %> + + <%#= sidebar_item_group('#course-submenu', '课堂+', icon: 'mortar-board') do %> diff --git a/app/views/admins/users/edit.html.erb b/app/views/admins/users/edit.html.erb index 3f9d71b96..22ac1f18e 100644 --- a/app/views/admins/users/edit.html.erb +++ b/app/views/admins/users/edit.html.erb @@ -131,7 +131,7 @@
    <%= f.button :submit, value: '保存', class: 'btn-primary mr-3 px-4' %> - <%= link_to '取消', 'javascript:history.go(-1)', class: 'btn btn-secondary px-4' %> + <%= link_to '取消', admins_users_path, class: 'btn btn-secondary px-4' %>
    <% end %>
    \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 7e2cf72f3..285bb7e1a 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -786,6 +786,13 @@ Rails.application.routes.draw do post :refuse end end + resources :mirror_repositories, only: [:index, :new, :create, :edit, :update, :destroy] do + collection do + post :merge + get :for_select + end + end + resources :choose_mirror_repositories, only: [:new, :create] end #git 认证回调 diff --git a/public/assets/.sprockets-manifest-1c370772f16743f825981ab0e5c94237.json b/public/assets/.sprockets-manifest-1c370772f16743f825981ab0e5c94237.json index 5f5a55fd7..da6cf8633 100644 --- a/public/assets/.sprockets-manifest-1c370772f16743f825981ab0e5c94237.json +++ b/public/assets/.sprockets-manifest-1c370772f16743f825981ab0e5c94237.json @@ -1 +1 @@ -{"files":{"admin-6575f1399953fb1935c037a7b8bd28c4aff07b70bed9b41faf6899a89af4b57d.js":{"logical_path":"admin.js","mtime":"2019-08-26T15:21:11+08:00","size":907839,"digest":"6575f1399953fb1935c037a7b8bd28c4aff07b70bed9b41faf6899a89af4b57d","integrity":"sha256-ZXXxOZlT+xk1wDenuL0oxK/we3C+2bQfr2iZqJr0tX0="},"admin-8a2b03cb8a055dc63f45443b304cae77382331beba55b1570b3d3c8aa42442d5.css":{"logical_path":"admin.css","mtime":"2019-08-26T15:21:47+08:00","size":655571,"digest":"8a2b03cb8a055dc63f45443b304cae77382331beba55b1570b3d3c8aa42442d5","integrity":"sha256-iisDy4oFXcY/RUQ7MEyudzgjMb66VbFXCz08iqQkQtU="},"font-awesome/fontawesome-webfont-7bfcab6db99d5cfbf1705ca0536ddc78585432cc5fa41bbd7ad0f009033b2979.eot":{"logical_path":"font-awesome/fontawesome-webfont.eot","mtime":"2019-08-14T17:22:43+08:00","size":165742,"digest":"7bfcab6db99d5cfbf1705ca0536ddc78585432cc5fa41bbd7ad0f009033b2979","integrity":"sha256-e/yrbbmdXPvxcFygU23ceFhUMsxfpBu9etDwCQM7KXk="},"font-awesome/fontawesome-webfont-2adefcbc041e7d18fcf2d417879dc5a09997aa64d675b7a3c4b6ce33da13f3fe.woff2":{"logical_path":"font-awesome/fontawesome-webfont.woff2","mtime":"2019-08-14T17:22:43+08:00","size":77160,"digest":"2adefcbc041e7d18fcf2d417879dc5a09997aa64d675b7a3c4b6ce33da13f3fe","integrity":"sha256-Kt78vAQefRj88tQXh53FoJmXqmTWdbejxLbOM9oT8/4="},"font-awesome/fontawesome-webfont-ba0c59deb5450f5cb41b3f93609ee2d0d995415877ddfa223e8a8a7533474f07.woff":{"logical_path":"font-awesome/fontawesome-webfont.woff","mtime":"2019-08-14T17:22:43+08:00","size":98024,"digest":"ba0c59deb5450f5cb41b3f93609ee2d0d995415877ddfa223e8a8a7533474f07","integrity":"sha256-ugxZ3rVFD1y0Gz+TYJ7i0NmVQVh33foiPoqKdTNHTwc="},"font-awesome/fontawesome-webfont-aa58f33f239a0fb02f5c7a6c45c043d7a9ac9a093335806694ecd6d4edc0d6a8.ttf":{"logical_path":"font-awesome/fontawesome-webfont.ttf","mtime":"2019-08-14T17:22:43+08:00","size":165548,"digest":"aa58f33f239a0fb02f5c7a6c45c043d7a9ac9a093335806694ecd6d4edc0d6a8","integrity":"sha256-qljzPyOaD7AvXHpsRcBD16msmgkzNYBmlOzW1O3A1qg="},"font-awesome/fontawesome-webfont-ad6157926c1622ba4e1d03d478f1541368524bfc46f51e42fe0d945f7ef323e4.svg":{"logical_path":"font-awesome/fontawesome-webfont.svg","mtime":"2019-08-14T17:22:43+08:00","size":444379,"digest":"ad6157926c1622ba4e1d03d478f1541368524bfc46f51e42fe0d945f7ef323e4","integrity":"sha256-rWFXkmwWIrpOHQPUePFUE2hSS/xG9R5C/g2UX37zI+Q="},"logo-7ff112568709bf97f9898fe87249b7a8f200ff1f48d537d85af87215f1870423.png":{"logical_path":"logo.png","mtime":"2019-08-21T15:10:12+08:00","size":2816,"digest":"7ff112568709bf97f9898fe87249b7a8f200ff1f48d537d85af87215f1870423","integrity":"sha256-f/ESVocJv5f5iY/ockm3qPIA/x9I1TfYWvhyFfGHBCM="},"application-a3a4f3549d68670572bb07700c85a9ac11e536edc73fef6e7489723bf535e533.js":{"logical_path":"application.js","mtime":"2019-08-26T15:21:11+08:00","size":1042232,"digest":"a3a4f3549d68670572bb07700c85a9ac11e536edc73fef6e7489723bf535e533","integrity":"sha256-o6TzVJ1oZwVyuwdwDIWprBHlNu3HP+9udIlyO/U15TM="},"application-a7508b88eb6a69a5b301602bddc14745cec09853ea7d91c6fae856b96e788f46.css":{"logical_path":"application.css","mtime":"2019-08-26T15:21:47+08:00","size":1182859,"digest":"a7508b88eb6a69a5b301602bddc14745cec09853ea7d91c6fae856b96e788f46","integrity":"sha256-p1CLiOtqaaWzAWAr3cFHRc7AmFPqfZHG+uhWuW54j0Y="}},"assets":{"admin.js":"admin-6575f1399953fb1935c037a7b8bd28c4aff07b70bed9b41faf6899a89af4b57d.js","admin.css":"admin-8a2b03cb8a055dc63f45443b304cae77382331beba55b1570b3d3c8aa42442d5.css","font-awesome/fontawesome-webfont.eot":"font-awesome/fontawesome-webfont-7bfcab6db99d5cfbf1705ca0536ddc78585432cc5fa41bbd7ad0f009033b2979.eot","font-awesome/fontawesome-webfont.woff2":"font-awesome/fontawesome-webfont-2adefcbc041e7d18fcf2d417879dc5a09997aa64d675b7a3c4b6ce33da13f3fe.woff2","font-awesome/fontawesome-webfont.woff":"font-awesome/fontawesome-webfont-ba0c59deb5450f5cb41b3f93609ee2d0d995415877ddfa223e8a8a7533474f07.woff","font-awesome/fontawesome-webfont.ttf":"font-awesome/fontawesome-webfont-aa58f33f239a0fb02f5c7a6c45c043d7a9ac9a093335806694ecd6d4edc0d6a8.ttf","font-awesome/fontawesome-webfont.svg":"font-awesome/fontawesome-webfont-ad6157926c1622ba4e1d03d478f1541368524bfc46f51e42fe0d945f7ef323e4.svg","logo.png":"logo-7ff112568709bf97f9898fe87249b7a8f200ff1f48d537d85af87215f1870423.png","application.js":"application-a3a4f3549d68670572bb07700c85a9ac11e536edc73fef6e7489723bf535e533.js","application.css":"application-a7508b88eb6a69a5b301602bddc14745cec09853ea7d91c6fae856b96e788f46.css"}} \ No newline at end of file +{"files":{"admin-6575f1399953fb1935c037a7b8bd28c4aff07b70bed9b41faf6899a89af4b57d.js":{"logical_path":"admin.js","mtime":"2019-08-26T15:21:11+08:00","size":907839,"digest":"6575f1399953fb1935c037a7b8bd28c4aff07b70bed9b41faf6899a89af4b57d","integrity":"sha256-ZXXxOZlT+xk1wDenuL0oxK/we3C+2bQfr2iZqJr0tX0="},"admin-8a2b03cb8a055dc63f45443b304cae77382331beba55b1570b3d3c8aa42442d5.css":{"logical_path":"admin.css","mtime":"2019-08-26T15:21:47+08:00","size":655571,"digest":"8a2b03cb8a055dc63f45443b304cae77382331beba55b1570b3d3c8aa42442d5","integrity":"sha256-iisDy4oFXcY/RUQ7MEyudzgjMb66VbFXCz08iqQkQtU="},"font-awesome/fontawesome-webfont-7bfcab6db99d5cfbf1705ca0536ddc78585432cc5fa41bbd7ad0f009033b2979.eot":{"logical_path":"font-awesome/fontawesome-webfont.eot","mtime":"2019-08-14T17:22:43+08:00","size":165742,"digest":"7bfcab6db99d5cfbf1705ca0536ddc78585432cc5fa41bbd7ad0f009033b2979","integrity":"sha256-e/yrbbmdXPvxcFygU23ceFhUMsxfpBu9etDwCQM7KXk="},"font-awesome/fontawesome-webfont-2adefcbc041e7d18fcf2d417879dc5a09997aa64d675b7a3c4b6ce33da13f3fe.woff2":{"logical_path":"font-awesome/fontawesome-webfont.woff2","mtime":"2019-08-14T17:22:43+08:00","size":77160,"digest":"2adefcbc041e7d18fcf2d417879dc5a09997aa64d675b7a3c4b6ce33da13f3fe","integrity":"sha256-Kt78vAQefRj88tQXh53FoJmXqmTWdbejxLbOM9oT8/4="},"font-awesome/fontawesome-webfont-ba0c59deb5450f5cb41b3f93609ee2d0d995415877ddfa223e8a8a7533474f07.woff":{"logical_path":"font-awesome/fontawesome-webfont.woff","mtime":"2019-08-14T17:22:43+08:00","size":98024,"digest":"ba0c59deb5450f5cb41b3f93609ee2d0d995415877ddfa223e8a8a7533474f07","integrity":"sha256-ugxZ3rVFD1y0Gz+TYJ7i0NmVQVh33foiPoqKdTNHTwc="},"font-awesome/fontawesome-webfont-aa58f33f239a0fb02f5c7a6c45c043d7a9ac9a093335806694ecd6d4edc0d6a8.ttf":{"logical_path":"font-awesome/fontawesome-webfont.ttf","mtime":"2019-08-14T17:22:43+08:00","size":165548,"digest":"aa58f33f239a0fb02f5c7a6c45c043d7a9ac9a093335806694ecd6d4edc0d6a8","integrity":"sha256-qljzPyOaD7AvXHpsRcBD16msmgkzNYBmlOzW1O3A1qg="},"font-awesome/fontawesome-webfont-ad6157926c1622ba4e1d03d478f1541368524bfc46f51e42fe0d945f7ef323e4.svg":{"logical_path":"font-awesome/fontawesome-webfont.svg","mtime":"2019-08-14T17:22:43+08:00","size":444379,"digest":"ad6157926c1622ba4e1d03d478f1541368524bfc46f51e42fe0d945f7ef323e4","integrity":"sha256-rWFXkmwWIrpOHQPUePFUE2hSS/xG9R5C/g2UX37zI+Q="},"logo-7ff112568709bf97f9898fe87249b7a8f200ff1f48d537d85af87215f1870423.png":{"logical_path":"logo.png","mtime":"2019-08-21T15:10:12+08:00","size":2816,"digest":"7ff112568709bf97f9898fe87249b7a8f200ff1f48d537d85af87215f1870423","integrity":"sha256-f/ESVocJv5f5iY/ockm3qPIA/x9I1TfYWvhyFfGHBCM="},"application-a3a4f3549d68670572bb07700c85a9ac11e536edc73fef6e7489723bf535e533.js":{"logical_path":"application.js","mtime":"2019-08-26T15:21:11+08:00","size":1042232,"digest":"a3a4f3549d68670572bb07700c85a9ac11e536edc73fef6e7489723bf535e533","integrity":"sha256-o6TzVJ1oZwVyuwdwDIWprBHlNu3HP+9udIlyO/U15TM="},"application-a7508b88eb6a69a5b301602bddc14745cec09853ea7d91c6fae856b96e788f46.css":{"logical_path":"application.css","mtime":"2019-08-26T15:21:47+08:00","size":1182859,"digest":"a7508b88eb6a69a5b301602bddc14745cec09853ea7d91c6fae856b96e788f46","integrity":"sha256-p1CLiOtqaaWzAWAr3cFHRc7AmFPqfZHG+uhWuW54j0Y="},"admin-7859f34e107ec35880c203a6c71fbd0b6b9dfdd007b9b8741db3c5fafb22d7a5.js":{"logical_path":"admin.js","mtime":"2019-08-27T16:36:09+08:00","size":912415,"digest":"7859f34e107ec35880c203a6c71fbd0b6b9dfdd007b9b8741db3c5fafb22d7a5","integrity":"sha256-eFnzThB+w1iAwgOmxx+9C2ud/dAHubh0HbPF+vsi16U="},"admin-e9352b40346e2c36c1d4de8f6e80405102647430dac1f81e6ad8ef9935505909.css":{"logical_path":"admin.css","mtime":"2019-08-27T10:22:33+08:00","size":655943,"digest":"e9352b40346e2c36c1d4de8f6e80405102647430dac1f81e6ad8ef9935505909","integrity":"sha256-6TUrQDRuLDbB1N6PboBAUQJkdDDawfgeatjvmTVQWQk="},"application-a4d6c5155da5a1dfbb7291faf09f555d557ee42ed9eb2c0c094d10898e35c687.js":{"logical_path":"application.js","mtime":"2019-08-27T16:36:09+08:00","size":1046808,"digest":"a4d6c5155da5a1dfbb7291faf09f555d557ee42ed9eb2c0c094d10898e35c687","integrity":"sha256-pNbFFV2lod+7cpH68J9VXVV+5C7Z6ywMCU0QiY41xoc="},"application-3d0740554f7108bba10d79d34f0cc47dca1a74fa0a1c423fffd5def99c386e17.css":{"logical_path":"application.css","mtime":"2019-08-27T10:22:33+08:00","size":1183231,"digest":"3d0740554f7108bba10d79d34f0cc47dca1a74fa0a1c423fffd5def99c386e17","integrity":"sha256-PQdAVU9xCLuhDXnTTwzEfcoadPoKHEI//9Xe+Zw4bhc="}},"assets":{"admin.js":"admin-7859f34e107ec35880c203a6c71fbd0b6b9dfdd007b9b8741db3c5fafb22d7a5.js","admin.css":"admin-e9352b40346e2c36c1d4de8f6e80405102647430dac1f81e6ad8ef9935505909.css","font-awesome/fontawesome-webfont.eot":"font-awesome/fontawesome-webfont-7bfcab6db99d5cfbf1705ca0536ddc78585432cc5fa41bbd7ad0f009033b2979.eot","font-awesome/fontawesome-webfont.woff2":"font-awesome/fontawesome-webfont-2adefcbc041e7d18fcf2d417879dc5a09997aa64d675b7a3c4b6ce33da13f3fe.woff2","font-awesome/fontawesome-webfont.woff":"font-awesome/fontawesome-webfont-ba0c59deb5450f5cb41b3f93609ee2d0d995415877ddfa223e8a8a7533474f07.woff","font-awesome/fontawesome-webfont.ttf":"font-awesome/fontawesome-webfont-aa58f33f239a0fb02f5c7a6c45c043d7a9ac9a093335806694ecd6d4edc0d6a8.ttf","font-awesome/fontawesome-webfont.svg":"font-awesome/fontawesome-webfont-ad6157926c1622ba4e1d03d478f1541368524bfc46f51e42fe0d945f7ef323e4.svg","logo.png":"logo-7ff112568709bf97f9898fe87249b7a8f200ff1f48d537d85af87215f1870423.png","application.js":"application-a4d6c5155da5a1dfbb7291faf09f555d557ee42ed9eb2c0c094d10898e35c687.js","application.css":"application-3d0740554f7108bba10d79d34f0cc47dca1a74fa0a1c423fffd5def99c386e17.css"}} \ No newline at end of file diff --git a/public/assets/admin-6575f1399953fb1935c037a7b8bd28c4aff07b70bed9b41faf6899a89af4b57d.js b/public/assets/admin-7859f34e107ec35880c203a6c71fbd0b6b9dfdd007b9b8741db3c5fafb22d7a5.js similarity index 99% rename from public/assets/admin-6575f1399953fb1935c037a7b8bd28c4aff07b70bed9b41faf6899a89af4b57d.js rename to public/assets/admin-7859f34e107ec35880c203a6c71fbd0b6b9dfdd007b9b8741db3c5fafb22d7a5.js index 2ff813ff4..e96beedb5 100644 --- a/public/assets/admin-6575f1399953fb1935c037a7b8bd28c4aff07b70bed9b41faf6899a89af4b57d.js +++ b/public/assets/admin-7859f34e107ec35880c203a6c71fbd0b6b9dfdd007b9b8741db3c5fafb22d7a5.js @@ -27721,6 +27721,7 @@ $(document).on('turbolinks:load', function(){ $(document).on('turbolinks:load', function() { if ($('body.admins-identity-authentications-index-page').length > 0) { var $searchFrom = $('.identity-authentication-list-form'); + $searchFrom.find('select[name="status"]').val('pending'); $searchFrom.on('click', '.search-form-tab', function(){ var $link = $(this); @@ -27732,14 +27733,160 @@ $(document).on('turbolinks:load', function() { $searchFrom.find('.status-filter').show(); } else { $searchFrom.find('.status-filter').hide(); + $searchFrom.find('select[name="status"]').val('pending'); } }); } }) ; +$(document).on('turbolinks:load', function() { + if ($('body.admins-mirror-repositories-edit-page, body.admins-mirror-repositories-update-page').length > 0) { + var $form = $('form.edit-mirror'); + + $form.validate({ + errorElement: 'span', + errorClass: 'danger text-danger', + rules: { + "mirror_repository[type_name]": { + required: true + } + } + }); + + $form.submit(function(e){ + if(!$form.valid()){ e.preventDefault(); } + }); + } +}); +$(document).on('turbolinks:load', function() { + if ($('body.admins-mirror-repositories-index-page').length > 0) { + } +}); +$(document).on('turbolinks:load', function() { + $('.admin-modal-container').on('show.bs.modal', '.modal.admin-choose-mirror-modal', function(){ + var $modal = $('.modal.admin-choose-mirror-modal'); + var $form = $modal.find('form.admin-choose-mirror-form'); + + var validateForm = function(){ + var checkedValue = $form.find('input[name="mirror_number"]:checked').val(); + + if(checkedValue == undefined){ + $modal.find('.error').html('必须选择一种镜像保存!'); + return false; + } + return true; + } + + $modal.on('click', '.submit-btn', function(){ + $form.find('.error').html(''); + var url = $form.attr('action'); + + if (validateForm()) { + $.ajax({ + method: 'POST', + dataType: 'script', + url: url, + data: $form.serialize(), + }).done(function(){ + $modal.modal('hide'); + }); + } + }); + }) +}); +$(document).on('turbolinks:load', function() { + var $modal = $('.modal.admin-replace-mirror-modal'); + if ($modal.length > 0) { + var $form = $modal.find('form.admin-replace-mirror-form'); + var $mirrorIdInput = $modal.find('.modal-body input[name="mirror_id"]'); + var $mirrorSelect = $modal.find('.new-mirror-select'); + + var setMirror = function(id, name){ + $mirrorIdInput.val(id); + $form.find('.mirror-id-container').html(id); + $form.find('.mirror-name-container').html(name); + } + + $form.validate({ + errorElement: 'span', + errorClass: 'danger text-danger', + rules: { + new_mirror_id: { + required: true + }, + }, + messages: { + new_mirror_id: { + required: '请选择新镜像' + } + } + }); + + // modal ready fire + $modal.on('show.bs.modal', function (event) { + var $link = $(event.relatedTarget); + + var mirrorId = $link.data('id'); + var mirrorName = $link.data('name'); + + setMirror(mirrorId, mirrorName); + $mirrorSelect.select2('val', ' '); + }); + $modal.on('hide.bs.modal', function () { + setMirror('', ''); + $mirrorSelect.select2('val', ' '); + $('#new_mirror_id-error').remove(); + }); + + $mirrorSelect.select2({ + theme: 'bootstrap4', + placeholder: '输入要合并的镜像名', + minimumInputLength: 1, + ajax: { + url: '/admins/mirror_repositories/for_select', + dataType: 'json', + data: function(params){ + return { keyword: params.term }; + }, + processResults: function(data){ + return { results: data.mirrors } + } + }, + templateResult: function (item) { + if(!item.id || item.id === '') return item.text; + return item.name; + }, + templateSelection: function(item){ + if (item.id) { + $('#new_mirror_id-error').remove(); + $('#new_mirror_id').val(item.id); + } + return item.name || item.text; + } + }); + + $modal.on('click', '.submit-btn', function(){ + $form.find('.error').html(''); + + if ($form.valid()) { + var url = $form.data('url'); + + $.ajax({ + method: 'POST', + dataType: 'script', + url: url, + data: $form.serialize(), + }).done(function(){ + $modal.modal('hide'); + }); + } + }); + } +}); $(document).on('turbolinks:load', function() { if ($('body.admins-professional-authentications-index-page').length > 0) { var $searchFrom = $('.professional-authentication-list-form'); + $searchFrom.find('select[name="status"]').val('pending'); $searchFrom.on('click', '.search-form-tab', function(){ var $link = $(this); @@ -27751,6 +27898,7 @@ $(document).on('turbolinks:load', function() { $searchFrom.find('.status-filter').show(); } else { $searchFrom.find('.status-filter').hide(); + $searchFrom.find('select[name="status"]').val('pending'); } }); } @@ -27905,6 +28053,7 @@ $(document).on('turbolinks:load', function() { $(document).on('turbolinks:load', function() { if ($('body.admins-shixun-authorizations-index-page').length > 0) { var $searchFrom = $('.shixun-authorization-list-form'); + $searchFrom.find('select[name="status"]').val('pending'); $searchFrom.on('click', '.search-form-tab', function(){ var $link = $(this); @@ -27916,6 +28065,7 @@ $(document).on('turbolinks:load', function() { $searchFrom.find('.status-filter').show(); } else { $searchFrom.find('.status-filter').hide(); + $searchFrom.find('select[name="status"]').val('pending'); } }); } @@ -27940,6 +28090,7 @@ $(document).on('turbolinks:load', function(){ $(document).on('turbolinks:load', function() { if ($('body.admins-subject-authorizations-index-page').length > 0) { var $searchFrom = $('.subject-authorization-list-form'); + $searchFrom.find('select[name="status"]').val('pending'); $searchFrom.on('click', '.search-form-tab', function(){ var $link = $(this); @@ -27951,6 +28102,7 @@ $(document).on('turbolinks:load', function() { $searchFrom.find('.status-filter').show(); } else { $searchFrom.find('.status-filter').hide(); + $searchFrom.find('select[name="status"]').val('pending'); } }); } @@ -28267,8 +28419,11 @@ $(document).on('turbolinks:load', function(){ // flash alert提示框自动关闭 if($('.admin-alert-container .alert').length > 0){ setTimeout(function(){ - $('.admin-alert-container .alert').alert('close'); + $('.admin-alert-container .alert:not(.alert-danger)').alert('close'); }, 2000); + setTimeout(function(){ + $('.admin-alert-container .alert.alert-danger').alert('close'); + }, 5000); } }); diff --git a/public/assets/admin-6575f1399953fb1935c037a7b8bd28c4aff07b70bed9b41faf6899a89af4b57d.js.gz b/public/assets/admin-7859f34e107ec35880c203a6c71fbd0b6b9dfdd007b9b8741db3c5fafb22d7a5.js.gz similarity index 93% rename from public/assets/admin-6575f1399953fb1935c037a7b8bd28c4aff07b70bed9b41faf6899a89af4b57d.js.gz rename to public/assets/admin-7859f34e107ec35880c203a6c71fbd0b6b9dfdd007b9b8741db3c5fafb22d7a5.js.gz index dc9ae6dba..1f8df17c9 100644 Binary files a/public/assets/admin-6575f1399953fb1935c037a7b8bd28c4aff07b70bed9b41faf6899a89af4b57d.js.gz and b/public/assets/admin-7859f34e107ec35880c203a6c71fbd0b6b9dfdd007b9b8741db3c5fafb22d7a5.js.gz differ diff --git a/public/assets/admin-8a2b03cb8a055dc63f45443b304cae77382331beba55b1570b3d3c8aa42442d5.css b/public/assets/admin-e9352b40346e2c36c1d4de8f6e80405102647430dac1f81e6ad8ef9935505909.css similarity index 99% rename from public/assets/admin-8a2b03cb8a055dc63f45443b304cae77382331beba55b1570b3d3c8aa42442d5.css rename to public/assets/admin-e9352b40346e2c36c1d4de8f6e80405102647430dac1f81e6ad8ef9935505909.css index cfd303453..25449185a 100644 --- a/public/assets/admin-8a2b03cb8a055dc63f45443b304cae77382331beba55b1570b3d3c8aa42442d5.css +++ b/public/assets/admin-e9352b40346e2c36c1d4de8f6e80405102647430dac1f81e6ad8ef9935505909.css @@ -18403,3 +18403,23 @@ label.error { -webkit-box-flex: 1; flex: 1; } + +/* line 52, app/assets/stylesheets/admin.scss */ +.font-12 { + font-size: 12px !important; +} + +/* line 53, app/assets/stylesheets/admin.scss */ +.font-14 { + font-size: 14px !important; +} + +/* line 54, app/assets/stylesheets/admin.scss */ +.font-16 { + font-size: 16px !important; +} + +/* line 55, app/assets/stylesheets/admin.scss */ +.font-18 { + font-size: 18px !important; +} diff --git a/public/assets/admin-8a2b03cb8a055dc63f45443b304cae77382331beba55b1570b3d3c8aa42442d5.css.gz b/public/assets/admin-e9352b40346e2c36c1d4de8f6e80405102647430dac1f81e6ad8ef9935505909.css.gz similarity index 60% rename from public/assets/admin-8a2b03cb8a055dc63f45443b304cae77382331beba55b1570b3d3c8aa42442d5.css.gz rename to public/assets/admin-e9352b40346e2c36c1d4de8f6e80405102647430dac1f81e6ad8ef9935505909.css.gz index 682386081..d54280d98 100644 Binary files a/public/assets/admin-8a2b03cb8a055dc63f45443b304cae77382331beba55b1570b3d3c8aa42442d5.css.gz and b/public/assets/admin-e9352b40346e2c36c1d4de8f6e80405102647430dac1f81e6ad8ef9935505909.css.gz differ diff --git a/public/assets/application-a7508b88eb6a69a5b301602bddc14745cec09853ea7d91c6fae856b96e788f46.css b/public/assets/application-3d0740554f7108bba10d79d34f0cc47dca1a74fa0a1c423fffd5def99c386e17.css similarity index 99% rename from public/assets/application-a7508b88eb6a69a5b301602bddc14745cec09853ea7d91c6fae856b96e788f46.css rename to public/assets/application-3d0740554f7108bba10d79d34f0cc47dca1a74fa0a1c423fffd5def99c386e17.css index 0a6d821b6..71cce1a19 100644 --- a/public/assets/application-a7508b88eb6a69a5b301602bddc14745cec09853ea7d91c6fae856b96e788f46.css +++ b/public/assets/application-3d0740554f7108bba10d79d34f0cc47dca1a74fa0a1c423fffd5def99c386e17.css @@ -18403,6 +18403,26 @@ label.error { -webkit-box-flex: 1; flex: 1; } + +/* line 52, app/assets/stylesheets/admin.scss */ +.font-12 { + font-size: 12px !important; +} + +/* line 53, app/assets/stylesheets/admin.scss */ +.font-14 { + font-size: 14px !important; +} + +/* line 54, app/assets/stylesheets/admin.scss */ +.font-16 { + font-size: 16px !important; +} + +/* line 55, app/assets/stylesheets/admin.scss */ +.font-18 { + font-size: 18px !important; +} @charset "UTF-8"; /* line 1, app/assets/stylesheets/admins/common.scss */ .admin-body-container { diff --git a/public/assets/application-3d0740554f7108bba10d79d34f0cc47dca1a74fa0a1c423fffd5def99c386e17.css.gz b/public/assets/application-3d0740554f7108bba10d79d34f0cc47dca1a74fa0a1c423fffd5def99c386e17.css.gz new file mode 100644 index 000000000..f6679e254 Binary files /dev/null and b/public/assets/application-3d0740554f7108bba10d79d34f0cc47dca1a74fa0a1c423fffd5def99c386e17.css.gz differ diff --git a/public/assets/application-a3a4f3549d68670572bb07700c85a9ac11e536edc73fef6e7489723bf535e533.js b/public/assets/application-a4d6c5155da5a1dfbb7291faf09f555d557ee42ed9eb2c0c094d10898e35c687.js similarity index 99% rename from public/assets/application-a3a4f3549d68670572bb07700c85a9ac11e536edc73fef6e7489723bf535e533.js rename to public/assets/application-a4d6c5155da5a1dfbb7291faf09f555d557ee42ed9eb2c0c094d10898e35c687.js index 268928474..cde5193e8 100644 --- a/public/assets/application-a3a4f3549d68670572bb07700c85a9ac11e536edc73fef6e7489723bf535e533.js +++ b/public/assets/application-a4d6c5155da5a1dfbb7291faf09f555d557ee42ed9eb2c0c094d10898e35c687.js @@ -27721,6 +27721,7 @@ $(document).on('turbolinks:load', function(){ $(document).on('turbolinks:load', function() { if ($('body.admins-identity-authentications-index-page').length > 0) { var $searchFrom = $('.identity-authentication-list-form'); + $searchFrom.find('select[name="status"]').val('pending'); $searchFrom.on('click', '.search-form-tab', function(){ var $link = $(this); @@ -27732,14 +27733,160 @@ $(document).on('turbolinks:load', function() { $searchFrom.find('.status-filter').show(); } else { $searchFrom.find('.status-filter').hide(); + $searchFrom.find('select[name="status"]').val('pending'); } }); } }) ; +$(document).on('turbolinks:load', function() { + if ($('body.admins-mirror-repositories-edit-page, body.admins-mirror-repositories-update-page').length > 0) { + var $form = $('form.edit-mirror'); + + $form.validate({ + errorElement: 'span', + errorClass: 'danger text-danger', + rules: { + "mirror_repository[type_name]": { + required: true + } + } + }); + + $form.submit(function(e){ + if(!$form.valid()){ e.preventDefault(); } + }); + } +}); +$(document).on('turbolinks:load', function() { + if ($('body.admins-mirror-repositories-index-page').length > 0) { + } +}); +$(document).on('turbolinks:load', function() { + $('.admin-modal-container').on('show.bs.modal', '.modal.admin-choose-mirror-modal', function(){ + var $modal = $('.modal.admin-choose-mirror-modal'); + var $form = $modal.find('form.admin-choose-mirror-form'); + + var validateForm = function(){ + var checkedValue = $form.find('input[name="mirror_number"]:checked').val(); + + if(checkedValue == undefined){ + $modal.find('.error').html('必须选择一种镜像保存!'); + return false; + } + return true; + } + + $modal.on('click', '.submit-btn', function(){ + $form.find('.error').html(''); + var url = $form.attr('action'); + + if (validateForm()) { + $.ajax({ + method: 'POST', + dataType: 'script', + url: url, + data: $form.serialize(), + }).done(function(){ + $modal.modal('hide'); + }); + } + }); + }) +}); +$(document).on('turbolinks:load', function() { + var $modal = $('.modal.admin-replace-mirror-modal'); + if ($modal.length > 0) { + var $form = $modal.find('form.admin-replace-mirror-form'); + var $mirrorIdInput = $modal.find('.modal-body input[name="mirror_id"]'); + var $mirrorSelect = $modal.find('.new-mirror-select'); + + var setMirror = function(id, name){ + $mirrorIdInput.val(id); + $form.find('.mirror-id-container').html(id); + $form.find('.mirror-name-container').html(name); + } + + $form.validate({ + errorElement: 'span', + errorClass: 'danger text-danger', + rules: { + new_mirror_id: { + required: true + }, + }, + messages: { + new_mirror_id: { + required: '请选择新镜像' + } + } + }); + + // modal ready fire + $modal.on('show.bs.modal', function (event) { + var $link = $(event.relatedTarget); + + var mirrorId = $link.data('id'); + var mirrorName = $link.data('name'); + + setMirror(mirrorId, mirrorName); + $mirrorSelect.select2('val', ' '); + }); + $modal.on('hide.bs.modal', function () { + setMirror('', ''); + $mirrorSelect.select2('val', ' '); + $('#new_mirror_id-error').remove(); + }); + + $mirrorSelect.select2({ + theme: 'bootstrap4', + placeholder: '输入要合并的镜像名', + minimumInputLength: 1, + ajax: { + url: '/admins/mirror_repositories/for_select', + dataType: 'json', + data: function(params){ + return { keyword: params.term }; + }, + processResults: function(data){ + return { results: data.mirrors } + } + }, + templateResult: function (item) { + if(!item.id || item.id === '') return item.text; + return item.name; + }, + templateSelection: function(item){ + if (item.id) { + $('#new_mirror_id-error').remove(); + $('#new_mirror_id').val(item.id); + } + return item.name || item.text; + } + }); + + $modal.on('click', '.submit-btn', function(){ + $form.find('.error').html(''); + + if ($form.valid()) { + var url = $form.data('url'); + + $.ajax({ + method: 'POST', + dataType: 'script', + url: url, + data: $form.serialize(), + }).done(function(){ + $modal.modal('hide'); + }); + } + }); + } +}); $(document).on('turbolinks:load', function() { if ($('body.admins-professional-authentications-index-page').length > 0) { var $searchFrom = $('.professional-authentication-list-form'); + $searchFrom.find('select[name="status"]').val('pending'); $searchFrom.on('click', '.search-form-tab', function(){ var $link = $(this); @@ -27751,6 +27898,7 @@ $(document).on('turbolinks:load', function() { $searchFrom.find('.status-filter').show(); } else { $searchFrom.find('.status-filter').hide(); + $searchFrom.find('select[name="status"]').val('pending'); } }); } @@ -27905,6 +28053,7 @@ $(document).on('turbolinks:load', function() { $(document).on('turbolinks:load', function() { if ($('body.admins-shixun-authorizations-index-page').length > 0) { var $searchFrom = $('.shixun-authorization-list-form'); + $searchFrom.find('select[name="status"]').val('pending'); $searchFrom.on('click', '.search-form-tab', function(){ var $link = $(this); @@ -27916,6 +28065,7 @@ $(document).on('turbolinks:load', function() { $searchFrom.find('.status-filter').show(); } else { $searchFrom.find('.status-filter').hide(); + $searchFrom.find('select[name="status"]').val('pending'); } }); } @@ -27940,6 +28090,7 @@ $(document).on('turbolinks:load', function(){ $(document).on('turbolinks:load', function() { if ($('body.admins-subject-authorizations-index-page').length > 0) { var $searchFrom = $('.subject-authorization-list-form'); + $searchFrom.find('select[name="status"]').val('pending'); $searchFrom.on('click', '.search-form-tab', function(){ var $link = $(this); @@ -27951,6 +28102,7 @@ $(document).on('turbolinks:load', function() { $searchFrom.find('.status-filter').show(); } else { $searchFrom.find('.status-filter').hide(); + $searchFrom.find('select[name="status"]').val('pending'); } }); } @@ -28267,8 +28419,11 @@ $(document).on('turbolinks:load', function(){ // flash alert提示框自动关闭 if($('.admin-alert-container .alert').length > 0){ setTimeout(function(){ - $('.admin-alert-container .alert').alert('close'); + $('.admin-alert-container .alert:not(.alert-danger)').alert('close'); }, 2000); + setTimeout(function(){ + $('.admin-alert-container .alert.alert-danger').alert('close'); + }, 5000); } }); diff --git a/public/assets/application-a3a4f3549d68670572bb07700c85a9ac11e536edc73fef6e7489723bf535e533.js.gz b/public/assets/application-a4d6c5155da5a1dfbb7291faf09f555d557ee42ed9eb2c0c094d10898e35c687.js.gz similarity index 80% rename from public/assets/application-a3a4f3549d68670572bb07700c85a9ac11e536edc73fef6e7489723bf535e533.js.gz rename to public/assets/application-a4d6c5155da5a1dfbb7291faf09f555d557ee42ed9eb2c0c094d10898e35c687.js.gz index 120f1b4fd..32521705d 100644 Binary files a/public/assets/application-a3a4f3549d68670572bb07700c85a9ac11e536edc73fef6e7489723bf535e533.js.gz and b/public/assets/application-a4d6c5155da5a1dfbb7291faf09f555d557ee42ed9eb2c0c094d10898e35c687.js.gz differ diff --git a/public/assets/application-a7508b88eb6a69a5b301602bddc14745cec09853ea7d91c6fae856b96e788f46.css.gz b/public/assets/application-a7508b88eb6a69a5b301602bddc14745cec09853ea7d91c6fae856b96e788f46.css.gz deleted file mode 100644 index d437dd106..000000000 Binary files a/public/assets/application-a7508b88eb6a69a5b301602bddc14745cec09853ea7d91c6fae856b96e788f46.css.gz and /dev/null differ diff --git a/public/react/src/common/UrlTool.js b/public/react/src/common/UrlTool.js index e1c9f0c74..12505186a 100644 --- a/public/react/src/common/UrlTool.js +++ b/public/react/src/common/UrlTool.js @@ -1,10 +1,10 @@ const isDev = window.location.port == 3007; -export const TEST_HOST = "http://pre-newweb.educoder.net" +export const TEST_HOST = "https://pre-newweb.educoder.net" export function getImageUrl(path) { // https://www.educoder.net // https://testbdweb.trustie.net // const local = 'http://localhost:3000' - const local = 'http://pre-newweb.educoder.net' + const local = 'https://pre-newweb.educoder.net' if (isDev) { return `${local}/${path}` } @@ -12,7 +12,7 @@ export function getImageUrl(path) { } export function setImagesUrl(path){ - const local = 'http://pre-newweb.educoder.net' + const local = 'https://pre-newweb.educoder.net' let firstStr=path.substr(0,1); // console.log(firstStr); if(firstStr=="/"){ @@ -31,7 +31,7 @@ export function getUrl(path, goTest) { // testbdweb.educoder.net testbdweb.trustie.net // const local = goTest ? 'https://testeduplus2.educoder.net' : 'http://localhost:3000' // const local = 'https://testeduplus2.educoder.net' - const local = 'http://pre-newweb.educoder.net' + const local = 'https://pre-newweb.educoder.net' if (isDev) { return `${local}${path?path:''}` } diff --git a/public/react/src/modules/courses/busyWork/CommonWorkAppraise.js b/public/react/src/modules/courses/busyWork/CommonWorkAppraise.js index ae40fedda..f29204563 100644 --- a/public/react/src/modules/courses/busyWork/CommonWorkAppraise.js +++ b/public/react/src/modules/courses/busyWork/CommonWorkAppraise.js @@ -271,15 +271,19 @@ class CommonWorkAppraise extends Component{ {work_members.map((item, index) => { return {isAdmin ? - this.props.toWorkDetailPage(this.props.match.params, null, item.work_id)} > {item.user_name} - : {item.user_name}} + : {item.user_name}} {item.is_leader && } })} + {isAdmin &&
    + 温馨提示: + 点击其他组员的姓名,可以快速评阅TA的作品 +
    } diff --git a/public/react/src/modules/courses/busyWork/CommonWorkList.js b/public/react/src/modules/courses/busyWork/CommonWorkList.js index 28e54fff3..d6c3d8946 100644 --- a/public/react/src/modules/courses/busyWork/CommonWorkList.js +++ b/public/react/src/modules/courses/busyWork/CommonWorkList.js @@ -430,7 +430,7 @@ class CommonWorkList extends Component{ } _getRequestParams() { - const { search, arg_work_status, arg_teacher_comment, arg_course_group, order, page } = this.state + const { search, arg_work_status, arg_teacher_comment, arg_course_group, order, page, arg_member_work } = this.state return { page, search, @@ -441,6 +441,7 @@ class CommonWorkList extends Component{ limit: PAGE_SIZE, b_order: orderMap[order], group_id:arg_course_group, + member_work: arg_member_work } } fetchData = () => { @@ -488,6 +489,11 @@ class CommonWorkList extends Component{ this.fetchList() }) } + memberWorkChange = (values, isAllChecked) => { + this.setState({arg_member_work: isAllChecked ? '' : values[0], page: 1}, () => { + this.fetchList() + }) + } funorder = (order) => { this.setState({ order }, () => { this.fetchList() @@ -557,7 +563,7 @@ class CommonWorkList extends Component{ late_penalty, absence_penalty, appeal_penalty ,end_immediately ,publish_immediately - , homework_id, visible, work_group, project_info + , homework_id, visible, work_group, project_info, is_leader } =this.state; @@ -581,10 +587,21 @@ class CommonWorkList extends Component{ return { label: `${item.name}(${item.count})`, value: item.id } }) + // 1:组长, 0:组员,“” 不限 + const member_works = [{ + name: '组长', id: 1 + }, { + name: '组员', id: 0 + }] + const options_member_work = member_works.map((item) => { + return { label: `${item.name}`, value: item.id } + }) + const isAdmin = this.props.isAdmin() const isStudent = this.props.isStudent() const isAdminOrStudent = this.props.isAdminOrStudent() + const isGroup = this.props.isGroup(); // work_group let StudentData; @@ -593,7 +610,7 @@ class CommonWorkList extends Component{ }else{ StudentData=isStudent ? [{ id, user_name, user_login, student_id, group_name, work_status, update_time, teacher_score, teaching_asistant_score, student_score, ultimate_score, work_score, student_comment_count, appeal_all_count, appeal_deal_count, - late_penalty, absence_penalty, appeal_penalty, project_info, + late_penalty, absence_penalty, appeal_penalty, project_info, is_leader, work_group, isMine: true }] : [] } const columns = buildColumns(this, student_works, StudentData) @@ -678,6 +695,7 @@ class CommonWorkList extends Component{ + {isGroup && } {options_course_group.length > 1 && } diff --git a/public/react/src/modules/courses/busyWork/CommonWorkPost.js b/public/react/src/modules/courses/busyWork/CommonWorkPost.js index 5ac53a065..9de66ee5f 100644 --- a/public/react/src/modules/courses/busyWork/CommonWorkPost.js +++ b/public/react/src/modules/courses/busyWork/CommonWorkPost.js @@ -1,12 +1,14 @@ import React,{Component} from "React"; import { Form, Select, Input, Button,Checkbox,Upload,Icon,message,Modal,Tooltip} from "antd"; import {Link} from 'react-router-dom'; -import TPMMDEditor from '../../tpm/challengesnew/TPMMDEditor'; -import { WordsBtn, getUploadActionUrl, appendFileSizeToUploadFile, appendFileSizeToUploadFileAll } from 'educoder'; import axios from 'axios'; -import Modals from '../../modals/Modals'; import _ from 'lodash' +import { WordsBtn, getUploadActionUrl, appendFileSizeToUploadFile, appendFileSizeToUploadFileAll, ConditionToolTip } from 'educoder'; +import Modals from '../../modals/Modals'; +import TPMMDEditor from '../../tpm/challengesnew/TPMMDEditor'; +import LeaderIcon from './common/LeaderIcon' + const Search = Input.Search; const CheckboxGroup = Checkbox.Group; @@ -722,21 +724,25 @@ render(){
    -
    {members.map((item,key)=>{ return(
    {item.user_name}
    -
    {item.group_name}
    -
    {item.student_id}
    +
    9 ? item.group_name : ''} + >{item.group_name}
    +
    12 ? item.student_id : ''} + >{item.student_id}
    {item.commit_status===true?已提交 :""}
    ) @@ -753,22 +759,38 @@ render(){ text-overflow:ellipsis; white-space:nowrap } + .members .leaderIcon { + } + .workPost.members { + width: 452px; + } `} -
    +
    {selectmemberslist&&selectmemberslist.map((item,key)=>{ + const _is_leader = (item.is_leader || !this.isEdit && key==0) return(
    - -
    {item.user_name}
    -
    -
    {item.group_name}
    -
    {item.student_id}
    - {item.user_id != this.props.current_user.user_id ?
    this.delecttask_status(item.user_id)}>
    :""} + 5}> +
    5 && _is_leader ? '#4CACFF' : 'inherit'}`}}> + {item.user_name}{ item.user_name.length <= 5 && _is_leader && } +
    +
    + +
    9 ? item.group_name : ''} + >{item.group_name}
    +
    12 ? item.student_id : ''} + >{item.student_id}
    + {item.user_id != this.props.current_user.user_id ? +
    this.delecttask_status(item.user_id)}>
    :""} +
    ) })} diff --git a/public/react/src/modules/courses/busyWork/common/LeaderIcon.js b/public/react/src/modules/courses/busyWork/common/LeaderIcon.js index 526e165c5..7d56d1b24 100644 --- a/public/react/src/modules/courses/busyWork/common/LeaderIcon.js +++ b/public/react/src/modules/courses/busyWork/common/LeaderIcon.js @@ -2,17 +2,20 @@ import React,{Component} from "React"; export default function LeaderIcon(props = {}) { let icon = null; + const { className, style } = props; + const _className = `font-8 blueFull Actionbtn ${className}` if (props.small) { - icon =
    组长
    } else { - icon =
    组长
    + icon =
    组长
    } return icon diff --git a/public/react/src/modules/courses/graduation/tasks/GraduationTaskssettinglist.js b/public/react/src/modules/courses/graduation/tasks/GraduationTaskssettinglist.js index 9718de28a..1b25a5717 100644 --- a/public/react/src/modules/courses/graduation/tasks/GraduationTaskssettinglist.js +++ b/public/react/src/modules/courses/graduation/tasks/GraduationTaskssettinglist.js @@ -711,8 +711,12 @@ class GraduationTaskssettinglist extends Component{ title: '姓名', dataIndex: 'name', key: 'name', - - className:'edu-txt-center' + className:'edu-txt-center', + render: (text, record) => ( + +
    {record.name}
    +
    + ), }, { title: '学号', dataIndex: 'stduynumber', @@ -720,7 +724,7 @@ class GraduationTaskssettinglist extends Component{ className:'edu-txt-center', render: (text, record) => ( - {record.stduynumber} +
    {record.stduynumber}
    ), }, { @@ -935,6 +939,7 @@ class GraduationTaskssettinglist extends Component{ if(taskslistdata&&taskslistdata.have_grouping===false){ + columns.some((item,key)=> { if (item.title === "分组") { columns.splice(key, 1) @@ -961,10 +966,38 @@ class GraduationTaskssettinglist extends Component{ .linbox{ height: 26px; } + .ant-table-tbody>tr>td, .ant-table-thead>tr>th{ + padding: 16px 10px + } + ` } + {taskslistdata&&taskslistdata.have_grouping===true|| + taskslistdata&&taskslistdata.have_project===true|| + taskslistdata&&taskslistdata.cross_comment===true?:""} {/*提示*/} 分班情况: + +
    + this.groupgroup(e,taskslistdata.search_assistants&&taskslistdata.search_assistants.course_group_info.length)} style={{width: '1000px', paddingTop: '4px'}}> + + + {taskslistdata.search_assistants&&taskslistdata.search_assistants.course_group_info.map((item,key)=>{ + return( + + {item.group_group_name} + ({item.count}) + + + ) + })} + +
    - this.groupgroup(e,taskslistdata.search_assistants&&taskslistdata.search_assistants.course_group_info.length)} style={{width: '1000px', paddingTop: '4px'}}> - - this.groupgroup([])}>不限 - - - {taskslistdata.search_assistants&&taskslistdata.search_assistants.course_group_info.map((item,key)=>{ - return( - - {item.group_group_name} - ({item.count}) - - - ) - })} - :""} diff --git a/public/react/src/modules/courses/members/modal/CreateGroupByImportModal.js b/public/react/src/modules/courses/members/modal/CreateGroupByImportModal.js index d5e77da9d..9b3d72e00 100644 --- a/public/react/src/modules/courses/members/modal/CreateGroupByImportModal.js +++ b/public/react/src/modules/courses/members/modal/CreateGroupByImportModal.js @@ -45,6 +45,7 @@ class CreateGroupByImportModal extends Component{ .then((response) => { if (response.data.status == 0) { this.props.showNotification(response.data.message) + this.props.createGroupImportSuccess && this.props.createGroupImportSuccess() this.setVisible(false) } else { diff --git a/public/react/src/modules/courses/members/studentsList.js b/public/react/src/modules/courses/members/studentsList.js index cc7485101..3462438f8 100644 --- a/public/react/src/modules/courses/members/studentsList.js +++ b/public/react/src/modules/courses/members/studentsList.js @@ -234,6 +234,9 @@ class studentsList extends Component{ off('updateNavSuccess', this.updateNavSuccess) } } + createGroupImportSuccess = () => { + this.props.updataleftNavfun() + } updateNavSuccess = () => { this.fetchCourseGroups() } @@ -556,7 +559,9 @@ class studentsList extends Component{ firstRowRight={ { isSuperAdmin && - + this.refs['createGroupByImportModal'].setVisible(true)}>导入创建分班 } { isAdmin && isParent && this.addDir()}>添加分班 } diff --git a/public/react/src/modules/courses/members/teacherList.js b/public/react/src/modules/courses/members/teacherList.js index 06dbe74a8..e3fd4a98d 100644 --- a/public/react/src/modules/courses/members/teacherList.js +++ b/public/react/src/modules/courses/members/teacherList.js @@ -42,6 +42,7 @@ function buildColumns(that) { title: '序号', dataIndex: 'name', key: 'index', + width: 78, render: (content, item, index) => { return index + 1 // return item.isApply == true ? '' : {(that.state.page - 1) * 20 + index + 1 @@ -74,6 +75,7 @@ function buildColumns(that) { dataIndex: 'role', key: 'role', sorter: showSorter, + width: 86, // 'ascend' | 'descend' defaultSortOrder: 'ascend', sortDirections: sortDirections, @@ -160,16 +162,16 @@ function buildColumns(that) { }, }) } - if(isAdminOrTeacher && hasGraduationModule) { - columns.unshift({ - title: '', - dataIndex: 'course_member_id', - key: 'course_member_id', - render: (content, item, index) => { - return content ? : '' - } - }) - } + // if(isAdminOrTeacher && hasGraduationModule) { + // columns.unshift({ + // title: '', + // dataIndex: 'course_member_id', + // key: 'course_member_id', + // render: (content, item, index) => { + // return content ? : '' + // } + // }) + // } return columns } diff --git a/public/react/src/modules/courses/new/CoursesNew.js b/public/react/src/modules/courses/new/CoursesNew.js index edee26a27..cbcb33fc2 100644 --- a/public/react/src/modules/courses/new/CoursesNew.js +++ b/public/react/src/modules/courses/new/CoursesNew.js @@ -45,10 +45,11 @@ class CoursesNew extends Component { fetching:false, boolxinjian:false, checkboxgroup:undefined, + addonAfteronelenone:0, + addonAfteronelentwo:0, checkbofrup:[{module_type:"shixun_homework",module_name:"实训作业"},{module_type:"common_homework",module_name:"普通作业"},{module_type:"group_homework",module_name:"分组作业"} ,{module_type:"exercise",module_name:"试卷"},{module_type:"poll",module_name:"问卷"},{module_type:"graduation",module_name:"毕业设计"} ,{module_type:"board",module_name:"讨论"},{module_type:"attachment",module_name:"资源"},{module_type:"course_group",module_name:"分班"}], - checkbofrups:[], } } componentDidMount() { @@ -66,8 +67,8 @@ class CoursesNew extends Component { this.props.form.setFieldsValue({ course: data.course_list_name, classroom: data.name, - period: data.class_period, - credit: data.credit, + period: data.class_period===undefined?'':data.class_period===null?'':data.class_period===null?'':data.class_period==="null"?'':data.class_period+"", + credit: data.credit===undefined?'':data.credit===null?'':data.credit===null?'':data.credit==="null"?'':data.credit+"", checkboxgroup: data.course_module_types, Realnamecertification: data.authentication, Professionalcertification:data.professional_certification, @@ -81,7 +82,9 @@ class CoursesNew extends Component { is_public: data.is_public === 1 ? true : false, Realnamecertification: data.authentication, Professionalcertification:data.professional_certification, - // checkbofrups:data.course_modules, + addonAfteronelenone: data.class_period===undefined?'':data.class_period===null?'':data.class_period===null?'':data.class_period==="null"?'':data.class_period, + addonAfteronelentwo:data.credit===undefined?'':data.credit===null?'':data.credit===null?'':data.credit==="null"?'':data.credit, + }); // try { // if(data.course_modules===undefined||data.course_modules.length===0){ @@ -94,6 +97,9 @@ class CoursesNew extends Component { // checkbofrups:this.state.checkbofrup, // }); // } + + + this.handleSearchschool(data.school); }).catch((error) => { console.log(error); @@ -469,10 +475,20 @@ class CoursesNew extends Component { const optionschool = this.state.searchlistscholl===undefined?"":this.state.searchlistscholl===null?"":this.state.searchlistscholl==="[]"?"":this.state.searchlistscholl.map(z => ); // console.log(this.props.current_user.user_school) // form合并了 - console.log("获取到的数据"); - console.log(this.state); - console.log(this.props); - console.log(this.props.current_user); + // console.log("获取到的数据"); + // console.log(this.state); + // console.log(this.props); + // console.log(this.props.current_user); + var addonAfterone=this.props.form&&this.props.form.getFieldValue('period'); + var addonAfteronelen=0; + if(addonAfterone){ + addonAfteronelen=String(addonAfterone).length; + } + var addonAftertwo=this.props.form&&this.props.form.getFieldValue('credit'); + var addonAfteronelens=0; + if(addonAftertwo){ + addonAfteronelens=String(addonAftertwo).length; + } return ( @@ -630,6 +646,23 @@ class CoursesNew extends Component { } `} + { - return event.target.value.replace(/\D/g,'') - }} + pattern: new RegExp(/^[0-9]+([.]{1}[0-9]+){0,1}$/, "g"), + message: '必须是数值' + }, + { + max:5, + message: '不能超过5个字符', + }]} )( - + )} @@ -656,15 +689,16 @@ class CoursesNew extends Component { {getFieldDecorator("credit", { rules:[{ - required:false, - pattern: new RegExp(/^[0-9]\d*$/, "g"), - message: '' - }], - getValueFromEvent: (event) => { - return event.target.value.replace(/\D/g,'') - }} + pattern: new RegExp(/^[0-9]+([.]{1}[0-9]+){0,1}$/, "g"), + message: '必须是数值' + }, + { + max:5, + message: '不能超过5个字符', + } + ]} )( - + )} - {getFieldDecorator("checkboxgroup", { initialValue: [ "shixun_homework", "common_homework", "group_homework", "exercise", "attachment", "course_group", diff --git a/public/react/src/modules/courses/new/Goldsubject.js b/public/react/src/modules/courses/new/Goldsubject.js index 80530c7ed..5149d3e5a 100644 --- a/public/react/src/modules/courses/new/Goldsubject.js +++ b/public/react/src/modules/courses/new/Goldsubject.js @@ -27,7 +27,9 @@ function disabledDateTime() { disabledMinutes: () => range(1, 30).concat(range(31, 60)), }; } - +function disabledDate(current) { + return current && current < moment().endOf('day').subtract(1, 'days'); +} // function disabledDate(current) { // console.log(current); // return current && current < moment().endOf('day').subtract(1, 'days'); @@ -49,13 +51,15 @@ class Goldsubject extends Component { fetching:false, subject_id:"", start_date:"", + addonAfteronelenone:"", + addonAfteronelentwo:"", Whethertocreateanewclassroom:true, checkbofrup:[ {module_type:"announcement",module_name:"公告栏"},{module_type:"online_learning",module_name:"在线学习"} ,{module_type:"shixun_homework",module_name:"实训作业"},{module_type:"common_homework",module_name:"普通作业"} ,{module_type:"exercise",module_name:"试卷"},{module_type:"poll",module_name:"问卷"} ,{module_type:"attachment",module_name:"资源"},{module_type:"board",module_name:"讨论"},{module_type:"course_group",module_name:"分班"},], - checkbofrups:[], + } } // disabledEndDate= endValue => { @@ -121,8 +125,8 @@ class Goldsubject extends Component { this.props.form.setFieldsValue({ course: data.course_list_name, classroom: data.name, - period: data.class_period, - credit: data.credit, + period: data.class_period===undefined?'':data.class_period===null?'':data.class_period===null?'':data.class_period==="null"?'':data.class_period+"", + credit: data.credit===undefined?'':data.credit===null?'':data.credit===null?'':data.credit==="null"?'':data.credit+"", checkboxgroup: data.course_module_types, Realnamecertification: data.authentication, Professionalcertification:data.professional_certification, @@ -140,22 +144,13 @@ class Goldsubject extends Component { Professionalcertification:data.professional_certification, name: data.name, class_period: data.class_period, - credit: parseFloat(data.credit), + addonAfteronelenone: data.class_period===undefined?'':data.class_period===null?'':data.class_period===null?'':data.class_period==="null"?'':data.class_period, + credit: parseFloat(data.credit), + addonAfteronelentwo:data.credit===undefined?'':data.credit===null?'':data.credit===null?'':data.credit==="null"?'':data.credit, course_module_types: data.course_module_types, school:data.school, Whethertocreateanewclassroom:false, }); - // try { - // if(data.course_modules===undefined||data.course_modules.length===0){ - // this.setState({ - // checkbofrups:this.state.checkbofrup, - // }); - // } - // }catch (e) { - // this.setState({ - // checkbofrups:this.state.checkbofrup, - // }); - // } this.handleSearchschool(data.school); }).catch((error) => { console.log(error); @@ -607,7 +602,7 @@ class Goldsubject extends Component { this.applyForAddOrgForm.setVisible(true) } render() { - let {datatime,datatimetwo,school,searchlistscholl,Whethertocreateanewclassroom} = this.state; + let {datatime,datatimetwo,school,searchlistscholl,Whethertocreateanewclassroom,addonAfteronelenone,addonAfteronelentwo} = this.state; const {getFieldDecorator} = this.props.form; const propsWithoutForm = Object.assign({}, this.props) delete propsWithoutForm.form @@ -619,6 +614,18 @@ class Goldsubject extends Component { // console.log(this.state); // console.log(this.props); // console.log(this.props.current_user); + var addonAfterone=this.props.form&&this.props.form.getFieldValue('period'); + var addonAfteronelen=0; + if(addonAfterone){ + addonAfteronelen=String(addonAfterone).length; + } + var addonAftertwo=this.props.form&&this.props.form.getFieldValue('credit'); + var addonAfteronelens=0; + if(addonAftertwo){ + addonAfteronelens=String(addonAftertwo).length; + } + console.log(addonAfteronelenone); + console.log(addonAfteronelentwo); return ( @@ -786,6 +793,23 @@ class Goldsubject extends Component { } `} + { - return event.target.value.replace(/\D/g,'') - }} + pattern: new RegExp(/^[0-9]+([.]{1}[0-9]+){0,1}$/, "g"), + message: '必须是数值' + }, + { + max:5, + message: '不能超过5个字符', + }]} )( - + )} - { - return event.target.value.replace(/\D/g,'') - }} + pattern: new RegExp(/^[0-9]+([.]{1}[0-9]+){0,1}$/, "g"), + message: '必须是数值' + }, + { + max:5, + message: '不能超过5个字符', + } + ]} )( - + )} {getFieldDecorator("endtime", { - rules: [{type: 'object',required: true, message: "结束时间不能为空"}], + rules: [{type: 'object', + required: true, message: "结束时间不能为空"}], })( { - - - - } - - - render() { - - return ( -
    - - {/**/} - - {/* ()*/} - {/*}>*/} - - {/**/} - -
    - ) - } -} - -export default SnackbarHOC() (TPMIndexHOC ( TPMIndex )); diff --git a/public/react/src/modules/tpm/challengesnew/TPMquestion.js b/public/react/src/modules/tpm/challengesnew/TPMquestion.js index 82d94f787..8fc2b1133 100644 --- a/public/react/src/modules/tpm/challengesnew/TPMquestion.js +++ b/public/react/src/modules/tpm/challengesnew/TPMquestion.js @@ -411,9 +411,7 @@ export default class TPMquestion extends Component { window.location.href = '/shixuns/'+this.props.match.params.shixunId+'/challenges/'+this.props.match.params.checkpointId+'/editquestion'; } questionadd=()=>{ - $('html').animate({ - scrollTop: 10 - }, 200); + let{questionaddarray}=this.state; let questionaddsums=questionaddarray.length; @@ -431,15 +429,13 @@ export default class TPMquestion extends Component { } }) - - questionaddarrays.push({type:0,choose_id:0}); this.setState({ activetype:0, questionaddarray:questionaddarrays, questionaddtype:true, + editquestionaddtype:false, newquestionaddtype:true, - editquestionaddtype:false, questionlists:[{str:"A",val:"",type:false},{str:"B",val:"",type:false},{str:"C",val:"",type:false},{str:"D",val:"",type:false}], answeshixunsGroup: 1, answeoptions:[10,20], @@ -447,17 +443,17 @@ export default class TPMquestion extends Component { shixunssanswerkillvalue:"", shixunsskillanswerlist:[], contentMdRefval:"", - newquestioMDMdContval:"" + newquestioMDMdContval:"", }) - // setTimeout(() => { - // this.newquestioMDMdCont.current.setValue('') - // this.newquestioMDMdRef.current.setValue('') - // - // }, 2000) - - this.shixunsautoHeight() + setTimeout(() => { + this.newquestioMDMdRef.current.setValue('') + }, 1000) + setTimeout(() => { + this.newquestioMDMdCont.current.setValue('') + }, 1500) + // this.shixunsautoHeight() } editquestionlists=(newquestionlists)=>{ @@ -592,6 +588,10 @@ export default class TPMquestion extends Component { } answer_subit=(sumtype,challenge_choose_id)=>{ + $('html').animate({ + scrollTop:10 + }, 500); + let {challenge_id,questionlists,shixunsskillanswerlist,answeonshixunsmark,answeshixunsGroup,questionaddarray} =this.state; if(challenge_id===undefined){ message.error("关卡id为空"); @@ -679,6 +679,7 @@ export default class TPMquestion extends Component { let id = this.props.match.params.shixunId; + let checkpointId=this.props.match.params.checkpointId let url; if(sumtype==="edit"){ let newquestioMDvalue = this.neweditanswerRef.current.getValue().trim(); @@ -781,7 +782,9 @@ export default class TPMquestion extends Component { description: '新建成功,请点击右侧加号继续添加', }); - // this.getanswer_subitlist() + window.location.href=`/shixuns/${id}/challenges/${checkpointId}/editquestion/${response.data.challenge_choose_id}`; + + // this.getanswer_subitlist() // this.gochooseid("/shixuns/"+this.props.match.params.shixunId+"/challenges/"+this.props.match.params.checkpointId+"/editquestion"+"/"+response.data.challenge_choose_id) }).catch((error) => { console.log(error) @@ -817,7 +820,8 @@ export default class TPMquestion extends Component { neweditanswerRefval:'', editanswersRefval:'' }) - + this.newquestioMDMdRef.current.setValue('') + this.newquestioMDMdCont.current.setValue('') }else{ let id = this.props.match.params.shixunId; let url ='/shixuns/'+id+'/challenges/'+challenge_id+'/edit_choose_question.json?choose_id='+challenge_choose_id; @@ -920,6 +924,7 @@ export default class TPMquestion extends Component { ) }) + return (
    diff --git a/public/react/src/modules/tpm/challengesnew/TpmQuestionEdit.js b/public/react/src/modules/tpm/challengesnew/TpmQuestionEdit.js index 32b56aae1..d0e6f98bd 100644 --- a/public/react/src/modules/tpm/challengesnew/TpmQuestionEdit.js +++ b/public/react/src/modules/tpm/challengesnew/TpmQuestionEdit.js @@ -4,6 +4,8 @@ import {Input, Select, Radio, Checkbox, Popconfirm, message, Modal,Tooltip} from import {BrowserRouter as Router, Route, Link, Switch} from "react-router-dom"; +import axios from 'axios'; + import TPMMDEditor from '../../tpm/challengesnew/TPMMDEditor'; const Option = Select.Option; @@ -21,7 +23,17 @@ export default class TpmQuestionEdit extends Component { componentDidMount() { } - + delecbtns=()=>{ + let url=`/shixuns/${this.props.match.params.shixunId}/challenges/${this.props.match.params.checkpointId}/destroy_challenge_choose.json`; + axios.delete((url), { data: { + choose_id:this.props.match.params.choose_id + }}) + .then((result)=>{ + if(result.data.status===1){ + window.location.href=`/shixuns/${this.props.match.params.shixunId}/challenges/${this.props.match.params.checkpointId}/editquestion`; + } + }) + } render() { @@ -202,6 +214,9 @@ export default class TpmQuestionEdit extends Component { onClick={()=>this.props.answer_subit()}>提交 取消 + + this.delecbtns()} + className="delectshixuncdbtn fr">删除
    diff --git a/public/react/src/modules/tpm/challengesnew/TpmQuestionNew.js b/public/react/src/modules/tpm/challengesnew/TpmQuestionNew.js index 855f6ce53..861c4f879 100644 --- a/public/react/src/modules/tpm/challengesnew/TpmQuestionNew.js +++ b/public/react/src/modules/tpm/challengesnew/TpmQuestionNew.js @@ -35,7 +35,7 @@ export default class TpmQuestionNew extends Component { *
    + needRecreate={true} watch={true} className="courseMessageMD" initValue={this.props.contentMdRefval}>
    @@ -108,7 +108,7 @@ export default class TpmQuestionNew extends Component {
    + needRecreate={true} watch={true} className="courseMessageMD" initValue={this.props.newquestioMDMdContval}>
    必填项 diff --git a/public/react/src/modules/user/usersInfo/Infos.js b/public/react/src/modules/user/usersInfo/Infos.js index 242e25464..cf40e5b29 100644 --- a/public/react/src/modules/user/usersInfo/Infos.js +++ b/public/react/src/modules/user/usersInfo/Infos.js @@ -43,7 +43,10 @@ const InfosVideo = Loadable({ loader: () => import('./video/InfosVideo'), loading:Loading, }) - +const InfosTopics=Loadable({ + loader: () => import('./InfosTopics'), + loading:Loading, +}) const $ = window.$; class Infos extends Component{ @@ -259,15 +262,6 @@ class Infos extends Component{ {/* --------------------------------------------------------------------- */} - - {/* 众包 */} - {/* http://localhost:3007/courses/1309/homework/9300/setting */} - () - } - > - {/* 课堂 */} {/* http://localhost:3007/courses/1309/homework/9300/setting */} - {/* 项目 */} + {/* 众包 */} + {/* http://localhost:3007/courses/1309/homework/9300/setting */} + () + } + > + + {/* 视频 */} () } > + {/* 题库 */} + () + } + > + -
    -
    -

    头像

    -
    -

    - {data && data.name} - { - data && is_current == false && data.identity =="学生" ? "" : - - } -

    -

    - - - - - - -

    -
    -
    -
    - {is_current ? "我":"TA"}的经验值 - {data && data.experience} -
    -
    - {is_current ? "我":"TA"}的金币 - {data && data.grade} -
    - { - is_current ? - - { - data && data.attendance_signed ? - 已签到 - : - 签到 - } - - : - - - 私信 - - - } -
    -
    -
    -
  • - this.setState({moduleName: 'courses'})} - to={`/users/${username}/courses`}>翻转课堂 -
  • -
  • - this.setState({moduleName: 'shixuns'})} - to={`/users/${username}/shixuns`}>开发社区 -
  • -
  • - this.setState({moduleName: 'paths'})} - to={`/users/${username}/paths`}>实践课程 -
  • -
  • - this.setState({moduleName: 'projects'})} - to={`/users/${username}/projects`}>项目 -
  • -
  • - this.setState({moduleName: 'package'})} - to={`/users/${username}/package`}>众包 -
  • - {((is_current && current_user && current_user.is_teacher ) || current_user && current_user.admin) - &&
  • - this.setState({moduleName: 'videos'})} - to={`/users/${username}/videos`}>视频 -
  • } -
    -
    -
    - ) - } -} +import React, { Component } from 'react'; + +import {Link} from 'react-router-dom'; +import {Tooltip,Menu} from 'antd'; +import {getImageUrl} from 'educoder'; + +import "./usersInfo.css" +import "../../courses/css/members.css" +import "../../courses/css/Courses.css" + +import { LinkAfterLogin } from 'educoder' + +class InfosBanner extends Component{ + constructor(props){ + super(props); + } + render(){ + let { + data , + id, + login, + moduleName, + current_user, + }=this.props; + let is_current=this.props.is_current; + let {username}= this.props.match.params; + let {pathname}=this.props.location; + moduleName=pathname.split("/")[3]; + + let user_id=this.props.current_user&&this.props.current_user.user_id; + let user_type=this.props.current_user&&this.props.current_user.user_identity; + let targetuserid=this.props.data&&this.props.data.id; + return( +
    +
    +
    +

    头像

    +
    +

    + {data && data.name} + { + data && is_current == false && data.identity =="学生" ? "" : + + } +

    +

    + + + + + + +

    +
    +
    +
    + {is_current ? "我":"TA"}的经验值 + {data && data.experience} +
    +
    + {is_current ? "我":"TA"}的金币 + {data && data.grade} +
    + { + is_current ? + + { + data && data.attendance_signed ? + 已签到 + : + 签到 + } + + : + + + 私信 + + + } +
    +
    +
    +
  • + this.setState({moduleName: 'courses'})} + to={`/users/${username}/courses`}>翻转课堂 +
  • +
  • + this.setState({moduleName: 'shixuns'})} + to={`/users/${username}/shixuns`}>实训项目 +
  • +
  • + this.setState({moduleName: 'paths'})} + to={`/users/${username}/paths`}>实践课程 +
  • +
  • + this.setState({moduleName: 'projects'})} + to={`/users/${username}/projects`}>开发项目 +
  • +
  • + this.setState({moduleName: 'package'})} + to={`/users/${username}/package`}>众包 +
  • + {((is_current && current_user && current_user.is_teacher ) || current_user && current_user.admin) + &&
  • + this.setState({moduleName: 'videos'})} + to={`/users/${username}/videos`}>视频 +
  • } + + {/*自己的主页且不是学生显示题库按钮*/} + { user_id===targetuserid&&user_type!="学生"?
  • + this.setState({moduleName: 'topics'})} + to={`/users/${username}/topics`}>题库 +
  • :""} + +
    +
    +
    + ) + } +} export default InfosBanner; \ No newline at end of file diff --git a/public/react/src/modules/user/usersInfo/InfosTopics.js b/public/react/src/modules/user/usersInfo/InfosTopics.js new file mode 100644 index 000000000..a462ccbe7 --- /dev/null +++ b/public/react/src/modules/user/usersInfo/InfosTopics.js @@ -0,0 +1,150 @@ +import React, { Component } from 'react'; +import { SnackbarHOC } from 'educoder'; +import {BrowserRouter as Router,Route,Switch} from 'react-router-dom'; +import {Tooltip,Menu,Pagination,Spin} from 'antd'; +import axios from 'axios'; +import {getImageUrl} from 'educoder'; +import Modals from '../../modals/Modals'; +import NoneData from '../../courses/coursesPublic/NoneData'; +import "./usersInfo.css" +import moment from 'moment'; + +class InfosTopics extends Component{ + constructor(props){ + super(props); + this.state={ + isSpin:false + } + } + + componentDidMount=()=>{ + + } + + render(){ + let{ + category, + status, + page, + data, + totalCount, + isSpin + } = this.state; + let is_current=this.props.is_current; + + // console.log(data) + return( +
    + {/*提示*/} + + +
    +
    + 我的题库 + 公共题库 +
    + + +
    + +

    + 共个 + 发布时间 +

    + + + {/*{data===undefined?:data.project_packages.length===0?:data.project_packages.map((item,key)=>{*/} + {/*return(*/} + {/*
    */} + {/*
    */} + + {/*
    */} + {/*图片*/} + {/*
    */} + + {/*
    */} + {/*
    */} + {/*
    */} + {/*{item.title}*/} + {/*
    */} + + {/*
    */} + {/*{item.bidden_status==="pending"?竞标中:""}*/} + {/*{item.bidden_status==="bidding_won"?已中标:""}*/} + {/*{item.bidden_status==="bidding_lost"?未中标:""}*/} + {/*
    */} + + {/*
    */} + {/*
    */} + {/*{item.min_price===null?"":¥{item.min_price}}*/} + {/*{item.max_price===null||item.min_price===null?"":~}*/} + {/*{item.max_price===null?"":¥{item.max_price}}*/} + {/*{item.min_price===null&&item.max_price===null?可议价:""}*/} + {/*
    */} + {/*
    */} + {/*
    */} + {/*
    {item.category_name}
    */} + {/*
    */} + {/*
    */} + {/*
    */} + {/**/} + {/*{item.visit_count}人浏览*/} + {/*
    */} + {/*
    */} + {/**/} + {/*{moment(item.deadline_at).format("YYYY-MM-DD HH:mm")}竞标截止*/} + {/*
    */} + {/*
    */} + {/**/} + {/*{item.bidding_users_count}人竞标*/} + {/*
    */} + {/*
    */} + {/*{item.published_at===null?更新于:{moment(item.updated_at).format("YYYY-MM-DD HH:mm")} :*/} + {/*发布于:{moment(item.published_at).format("YYYY-MM-DD HH:mm")} }*/} + {/*
    */} + {/*
    */} + {/*
    */} + + {/*{category=="manage"?item.operation.can_edit===true&&item.operation.can_delete===true?*/} + {/*:"":""}*/} + + {/*{category=="manage"?item.operation.can_edit===true&&item.operation.can_delete===false?*/} + {/*
    */} + {/**/} + {/**/} + {/**/} + {/*
    :"":""}*/} + + + {/*
    */} + {/*
    */} + {/*)})}*/} + + {/*{*/} + {/*totalCount >20 &&*/} + {/*
    */} + {/**/} + {/*
    */} + {/*}*/} + +
    +
    + ) + } +} +export default InfosTopics; \ No newline at end of file diff --git a/public/react/src/modules/user/usersInfo/usersInfo.css b/public/react/src/modules/user/usersInfo/usersInfo.css index 12df5b404..bc869b458 100644 --- a/public/react/src/modules/user/usersInfo/usersInfo.css +++ b/public/react/src/modules/user/usersInfo/usersInfo.css @@ -249,4 +249,26 @@ color: #4CACFF; font-size: 16px; margin-left: 10px; +} +.topicsbox{ + width: 1200px; + height: 216px; + background: rgba(255,255,255,1); + padding: 0px 40px; +} + +.topicstopfont{ + width:64px; + height:16px; + font-size:16px; + font-family:PingFangSC; + font-weight:400; + color:rgba(51,51,51,1); +} + +.topcschild{ + width:1128px; + height:49px; + line-height: 35px; + border-bottom:1px solid rgba(235,235,235,1); } \ No newline at end of file diff --git a/public/stylesheets/educoder/edu-main.css b/public/stylesheets/educoder/edu-main.css index f59827f45..c66453b4c 100644 --- a/public/stylesheets/educoder/edu-main.css +++ b/public/stylesheets/educoder/edu-main.css @@ -538,6 +538,27 @@ a.edu-greyline-btn:hover,a.edu-greyshallowline-btn:hover{border:1px solid #B2B2B font-weight: 400; color: rgba(255,255,255,1); } + +/*删除按钮*/ +.delectshixuncdbtn{ + display: block; + border: 1px solid #CDCDCD; + background-color: #fafafa; + color: #999!important; + width: 120px; + text-align: center; + height: 30px; + line-height: 30px; + border-radius: 2px; + width: 130px; + height: 40px; + background: rgba(77,124,254,0); + border-radius: 4px; + line-height: 40px; + font-size: 16px; + font-family: MicrosoftYaHei; + font-weight: 400; +} .defalutSubmitbtn:hover{background-color: #459BE6;border: 1px solid #459BE6;} /*-------------------------------------------公用按钮:以white-btn(或者edu-default-btn无padding)为基础,宽度和高度可以用padding填充,颜色用edu-color-btn,end-----------------------------------------*/