Merge branch 'dev_aliyun' into dev_aliyun_beta

dev_aliyun_beta
hjm 6 years ago
commit cbd62bd167

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

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

@ -0,0 +1,4 @@
$(document).on('turbolinks:load', function() {
if ($('body.admins-mirror-repositories-index-page').length > 0) {
}
});

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

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

@ -47,4 +47,9 @@ label.error {
.flex-1 {
flex: 1;
}
}
.font-12 { font-size: 12px !important; }
.font-14 { font-size: 14px !important; }
.font-16 { font-size: 16px !important; }
.font-18 { font-size: 18px !important; }

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

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

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

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

@ -765,7 +765,7 @@ class GamesController < ApplicationController
testset_detail max_query_index.to_i, game_challenge
# 处理生成图片类型文件
picture = (@game.picture_path.nil? ? 0 : @game.id)
picture = (game_challenge.show_type.to_i == -1 || @game.picture_path.nil?) ? 0 : @game.id
# 针对web类型的实训
web_route = game_challenge.try(:web_route)

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

@ -0,0 +1,23 @@
module Admins::MirrorRepositoriesHelper
def mirror_type_tag(mirror)
case mirror.main_type
when '1' then '<i class="fa fa-star text-success font-16" aria-hidden="true" data-toggle="tooltip" data-title="主类别"></i>'.html_safe
when '0' then '<i class="fa fa-star text-secondary font-16" aria-hidden="true" data-toggle="tooltip" data-title="子类别"></i>'.html_safe
end
end
def mirror_status_tag(mirror)
case mirror.status
when 0
'<i class="fa fa-check-circle text-secondary font-16" data-toggle="tooltip" data-title="未发布"></i>'.html_safe
when 1
'<i class="fa fa-check-circle text-success font-16" data-toggle="tooltip" data-title="已发布"></i>'.html_safe
when 2, 3
'<i class="fa fa-exclamation-circle text-danger font-16" data-toggle="tooltip" data-title="被修改"></i>'.html_safe
when 4
'<i class="fa fa-times-circle text-danger font-18" data-toggle="tooltip" data-title="被删除"></i>'.html_safe
when 5
'<i class="fa fa-exclamation-circle text-warning font-16" data-toggle="tooltip" data-title="子节点异常"></i>'.html_safe
end
end
end

@ -40,16 +40,18 @@ class Challenge < ApplicationRecord
## 选择题总分
def choose_score
self.challenge_chooses.pluck(:score).sum
self.score
#self.challenge_chooses.pluck(:score).sum
end
# 关卡总分
def all_score
if self.st == 1
self.choose_score
else
self.score
end
self.score
# if self.st == 1
# self.choose_score
# else
# self.score
# end
end
# 开启挑战

@ -31,7 +31,7 @@ class Game < ApplicationRecord
# 根据得分比例来算实际得分(试卷、实训作业)
def real_score score
((final_score < 0 ? 0 : final_score).to_f / challenge.all_score) * score
((final_score < 0 ? 0 : final_score).to_f / challenge.score) * score
end
# 判断实训是否全部通关

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

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

@ -192,11 +192,7 @@ class Shixun < ApplicationRecord
# 实训关卡的总分(由于大部分是实践题,因此没关联查choose表)
# 提前加载问题由于选择题比较少所以几乎不会触发选择题的查询所以没必要提前载入choose_score
def all_score
sum = 0
challenges.each do |challenge|
sum += challenge.st == 0 ? challenge.score : challenge.choose_score
end
sum
self.challenges.pluck(:score).sum
end
### fork 数量

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

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

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

@ -0,0 +1,5 @@
$.notify({ message: '操作成功' },{ type: 'success' });
setTimeout(function(){
window.location.reload();
}, 500)

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

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

@ -0,0 +1,23 @@
<% define_admin_breadcrumbs do %>
<% add_admin_breadcrumb('镜像管理') %>
<% end %>
<div class="box search-form-container mirror-repository-list-form">
<form class="flex-1"></form>
<%= link_to '新建', new_admins_mirror_repository_path, class: 'btn btn-primary' %>
</div>
<% if @error_mirror_names.present? %>
<div class="box pb-0">
以下镜像异常:
<% @error_mirror_names.each do |mirror_name| %>
<span class="ml-2 text-danger"><%= mirror_name %></span>
<% end %>
</div>
<% end %>
<div class="box mirror-repository-list-container">
<%= render partial: 'admins/mirror_repositories/shared/list', locals: { mirrors: @mirrors } %>
</div>
<%= render 'admins/mirror_repositories/shared/replace_mirror_modal' %>

@ -0,0 +1 @@
$('.mirror-repository-list-container').html("<%= j( render partial: 'admins/mirror_repositories/shared/list', locals: { mirrors: @mirrors } ) %>");

@ -0,0 +1,5 @@
$.notify({ message: '操作成功' },{ type: 'success' });
setTimeout(function(){
window.location.reload();
}, 500)

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

@ -0,0 +1,42 @@
<div class="modal fade admin-choose-mirror-modal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">更新镜像仓库</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<%= form_tag(admins_choose_mirror_repositories_path(mirror_id: mirror.id), method: :post, class: 'admin-choose-mirror-form') do %>
<div class="form-group row">
<div class="col-md-2"></div>
<div class="col-md-5">ID</div>
<div class="col-md-5">名称</div>
</div>
<div class="form-group row">
<div class="col-md-2">旧镜像</div>
<div class="col-md-5 form-check">
<input class="form-check-input" type="radio" name="mirror_number" id="old-mirror-check" value="<%= mirror.mirrorID %>">
<label class="form-check-label" for="old-mirror-check"><%= mirror.mirrorID %></label>
</div>
<div class="col-md-5"><%= mirror.name %></div>
</div>
<div class="form-group row">
<div class="col-md-2">新镜像</div>
<div class="col-md-5 form-check">
<input class="form-check-input" type="radio" name="mirror_number" id="new-mirror-check" value="<%= new_mirror.mirror_id %>">
<label class="form-check-label" for="new-mirror-check"><%= new_mirror.mirror_id %></label>
</div>
<div class="col-md-5"><%= new_mirror.mirror_name %></div>
</div>
<div class="mt-2 error text-danger"></div>
<% end %>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
<button type="button" class="btn btn-primary submit-btn">确认</button>
</div>
</div>
</div>
</div>

@ -0,0 +1,42 @@
<div class="box edit-mirror-repository-container">
<%= 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? %>
<div class="row">
<%= 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' } %>
</div>
<% end %>
<div class="row">
<%= f.input :type_name, as: :string, label: '镜像别名 *' %>
<div class="form-group select optional col-md-4">
<%= f.label :main_type, label: '类别' %>
<%= f.select :main_type, [['主类别', 1],['小类别', 0]], {}, class: 'form-control optional' %>
</div>
</div>
<div class="row">
<%= f.input :time_limit, as: :integer, label: '评测时限(S)' %>
<%= f.input :resource_limit, as: :integer, label: '磁盘限制(K)' %>
</div>
<div class="row">
<%= f.input :cpu_limit, as: :integer, label: 'CPU限制(核)' %>
<%= f.input :memory_limit, as: :integer, label: '内存限制(M)' %>
</div>
<div class="row">
<%= f.input :description, as: :text, label: '描述', wrapper_html: { class: 'col-md-8' } %>
</div>
<div class="row">
<%= f.input :status, as: :radio_buttons, label: '状态', collection: [%w(未发布 0), %w(已发布 1)], wrapper_html: { class: 'col-md-4' } %>
</div>
<div class="row">
<%= 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' %>
</div>
<% end %>
</div>

@ -0,0 +1,54 @@
<table class="table table-hover text-center mirror-repository-list-table">
<thead class="thead-light">
<tr>
<th width="6%">ID</th>
<th width="6%">类别</th>
<th width="12%" class="text-left">镜像别名</th>
<th width="16%" class="text-left">镜像名称</th>
<th width="22%" class="text-left">镜像描述</th>
<th width="14%">修改时间</th>
<th width="6%">脚本</th>
<th width="6%">状态</th>
<th width="12%">操作</th>
</tr>
</thead>
<tbody>
<% if mirrors.present? %>
<% mirrors.each do |mirror| %>
<tr class="mirror-repository-item-<%= mirror.id %>">
<td><%= mirror.id %></td>
<td><%= mirror_type_tag(mirror) %></td>
<td class="text-left"><%= display_text(mirror.type_name) %></td>
<td class="text-left"><%= overflow_hidden_span mirror.name, width: 150 %></td>
<td class="text-left"><%= overflow_hidden_span mirror.description, width: 240 %></td>
<td><%= mirror.updated_at.strftime('%Y-%m-%d %H:%M') %></td>
<td>
<% if mirror.main_type == "1" %>
<%= link_to "/users/modify_script?mirror_id=#{mirror.id}", target: '_blank' do %>
<i class="fa fa-file-text <%= mirror.mirror_scripts.blank? ? 'text-danger' : 'text-success' %>" aria-hidden="true" data-toggle="tooltip" data-title="脚本模板"></i>
<% end %>
<% end %>
</td>
<td><%= mirror_status_tag mirror %></td>
<td class="action-container">
<%= 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 %>
</td>
</tr>
<% end %>
<% else %>
<%= render 'admins/shared/no_data_for_table' %>
<% end %>
</tbody>
</table>
<%= render partial: 'admins/shared/paginate', locals: { objects: mirrors } %>

@ -0,0 +1,33 @@
<div class="modal fade admin-replace-mirror-modal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">镜像替换</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form class="admin-replace-mirror-form" data-url="<%= merge_admins_mirror_repositories_path %>">
<%= hidden_field_tag(:mirror_id, nil) %>
<div class="form-group d-flex">
<div>被替换镜像:</div>
<div class="ml-2">ID<span class="mx-1 text-info mirror-id-container"></span></div>
<div class="ml-2">名称:<span class="mx-1 text-info mirror-name-container"></span></div>
</div>
<div class="form-group d-flex">
<label for="new_mirror_id" class="col-form-label">选择新镜像:</label>
<div class="d-flex flex-column-reverse w-75">
<select id="new_mirror_id" name="new_mirror_id" class="form-control new-mirror-select"></select>
</div>
</div>
<div class="error text-danger"></div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
<button type="button" class="btn btn-primary submit-btn">确认</button>
</div>
</div>
</div>
</div>

@ -2,5 +2,5 @@
<div class="global-error-code">
<span>500</span>
</div>
<div class="global-error-text">系统错误</div>
<div class="global-error-text"><%= @message %></div>
</div>

@ -1,5 +1,5 @@
<div class="paginate-container">
<% if objects.size.nonzero? %>
<% if objects && objects.size.nonzero? %>
<div class="paginate-total"><%= page_entries_info objects %></div>
<% end %>
<%= paginate objects, views_prefix: 'admins', remote: true %>

@ -20,6 +20,12 @@
<% end %>
</li>
<li>
<%= sidebar_item_group('#shixun-submenu', '实训管理', icon: 'window-restore') do %>
<li><%= sidebar_item(admins_mirror_repositories_path, '镜像管理', icon: 'cubes', controller: 'admins-mirror_repositories') %></li>
<% end %>
</li>
<!-- <li>-->
<%#= sidebar_item_group('#course-submenu', '课堂+', icon: 'mortar-board') do %>
<!-- <li><%#= sidebar_item('#', '课程列表', icon: 'calendar', controller: '') %></li>-->

@ -131,7 +131,7 @@
<div class="form-row mt-4">
<%= 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' %>
</div>
<% end %>
</div>

@ -13,7 +13,7 @@ if @challenges.present?
json.position challenge.position
json.st challenge.st
json.name challenge.subject
json.score challenge.all_score
json.score challenge.score
json.passed_count challenge.user_passed_count
json.playing_count challenge.playing_count
json.name_url shixun_challenge_path(challenge, shixun_identifier: @shixun.identifier)

@ -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 认证回调

@ -0,0 +1,10 @@
class ModifyChallnegeScoreForChoose < ActiveRecord::Migration[5.2]
def change
challenges = Challenge.where(st: 1)
challenges.find_each do |c|
puts(c.id)
score = c.challenge_chooses.sum(:score)
c.update_column(:score, score)
end
end
end

File diff suppressed because one or more lines are too long

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

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

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

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

@ -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:''}`
}

@ -271,15 +271,19 @@ class CommonWorkAppraise extends Component{
{work_members.map((item, index) => {
return <React.Fragment>
{isAdmin ?
<a className={`color-blue ${index == 0 ? '' : 'ml10'}`} href="javascript:void(0)"
<a className={`color-blue ${index == 0 ? '' : 'ml12'}`} href="javascript:void(0)"
onClick={() => this.props.toWorkDetailPage(this.props.match.params, null, item.work_id)}
>
{item.user_name}
</a> : <span className={`${index == 0 ? '' : 'ml10'}`} >{item.user_name}</span>}
</a> : <span className={`${index == 0 ? '' : 'ml12'}`} >{item.user_name}</span>}
{item.is_leader && <LeaderIcon small={true} ></LeaderIcon>}
</React.Fragment>
})}
</div>
{isAdmin && <div className="font-12 color-grey-9">
<span >温馨提示</span>
点击其他组员的姓名可以快速评阅TA的作品
</div>}
</div>
</div>

@ -563,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;
@ -610,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)
@ -695,8 +695,8 @@ class CommonWorkList extends Component{
<CheckAllGroup options={options_teacher_comment} label={'你的评阅:'} onChange={this.teacherCommentOptionChange}></CheckAllGroup>
<CheckAllGroup options={options_status} label={'作品状态:'} onChange={this.statusOptionChange}></CheckAllGroup>
{options_course_group.length > 1 && <CheckAllGroup options={options_course_group} label={'分班情况:'} onChange={this.courseGroupOptionChange} checkboxGroupStyle={{width: '980px'}}></CheckAllGroup>}
{isGroup && <CheckAllGroup options={options_member_work} label={'组内角色:'} onChange={this.memberWorkChange}></CheckAllGroup>}
{options_course_group.length > 1 && <CheckAllGroup options={options_course_group} label={'分班情况:'} onChange={this.courseGroupOptionChange} checkboxGroupStyle={{width: '980px'}}></CheckAllGroup>}
{/* value={search} */}

@ -4,7 +4,7 @@ import {Link} from 'react-router-dom';
import axios from 'axios';
import _ from 'lodash'
import { WordsBtn, getUploadActionUrl, appendFileSizeToUploadFile, appendFileSizeToUploadFileAll } from 'educoder';
import { WordsBtn, getUploadActionUrl, appendFileSizeToUploadFile, appendFileSizeToUploadFileAll, ConditionToolTip } from 'educoder';
import Modals from '../../modals/Modals';
import TPMMDEditor from '../../tpm/challengesnew/TPMMDEditor';
import LeaderIcon from './common/LeaderIcon'
@ -724,21 +724,25 @@ render(){
<div className={"ml20"} style={{width:"100%"}}>
<div className={"members fl"}
<div className={"members workPost fl"}
onScroll={this.contentViewScroll}>
<CheckboxGroup value={task_status} onChange={this.funtaskstatus} style={{ paddingTop: '4px'}}>
{members.map((item,key)=>{
return(
<div key={key} style={{
width: '375px',
// width: '375px',
height: '30px'
}}>
<Checkbox value={item.user_id} key={item.user_id} checked={parseInt(task_status[key])===item.user_id?true:false}
disabled={item.commit_status || item.user_id == this.props.current_user.user_id ===true?true:false} className="fl "
></Checkbox>
<Tooltip placement="bottom" title={item.user_nam}><div className={"fl ml5 fonthidden"} style={{width: '70px'}}>{item.user_name}</div></Tooltip>
<div className={"fl ml20 color-grey-9"}>{item.group_name}</div>
<div className={"fl ml20 color-grey-9"}>{item.student_id}</div>
<div className={"fl ml20 color-grey-9 overflowHidden1"} style={{ maxWidth: '147px' }}
title={item.group_name && item.group_name.length > 9 ? item.group_name : ''}
>{item.group_name}</div>
<div className={"fl ml20 color-grey-9 overflowHidden1"} style={{ maxWidth: '99px' }}
title={item.student_id && item.student_id.length > 12 ? item.student_id : ''}
>{item.student_id}</div>
<div className={"fl ml20"}>{item.commit_status===true?<span className={"color-orange"}>已提交</span> :""}</div>
</div>
)
@ -757,23 +761,32 @@ render(){
}
.members .leaderIcon {
}
.workPost.members {
width: 452px;
}
`}</style>
<div className={"members fl"}>
<div className={"members workPost fl"}>
{selectmemberslist&&selectmemberslist.map((item,key)=>{
const _is_leader = (item.is_leader || !this.isEdit && key==0)
return(
<div key={key} style={{
width: '375px',
// width: '375px',
height: '30px',
display:item.user_name===undefined?"none":""
}}>
<Tooltip placement="bottom" title={item.user_nam}>
<div className={"fl ml5 fonthidden"} style={{width: '68px'}}>
{item.user_name}{ (item.is_leader || !this.isEdit && key==0) && <LeaderIcon className="leaderIcon" small={true}></LeaderIcon>}
<ConditionToolTip placement="bottom" title={'组长'} condition={_is_leader && item.user_name.length > 5}>
<div className={"fl ml5 fonthidden"} style={{width: '98px', color: `${item.user_name.length > 5 && _is_leader ? '#4CACFF' : 'inherit'}`}}>
{item.user_name}{ item.user_name.length <= 5 && _is_leader && <LeaderIcon className="leaderIcon" small={true}></LeaderIcon>}
</div>
</Tooltip>
<div className={"fl ml40 color-grey-9"}>{item.group_name}</div>
<div className={"fl ml40 color-grey-9"}>{item.student_id}</div>
</ConditionToolTip>
<div className={"fl ml20 color-grey-9 overflowHidden1"} style={{ maxWidth: '147px' }}
title={item.group_name && item.group_name.length > 9 ? item.group_name : ''}
>{item.group_name}</div>
<div className={"fl ml20 color-grey-9 overflowHidden1"} style={{ maxWidth: '99px' }}
title={item.student_id && item.student_id.length > 12 ? item.student_id : ''}
>{item.student_id}</div>
{item.user_id != this.props.current_user.user_id ?
<div className={"fr"}><i className={"iconfont icon-shanchudiao fl "}
style={{marginTop:'-4px'}} onClick={()=>this.delecttask_status(item.user_id)}></i></div>:""}

@ -8,13 +8,14 @@ export default function LeaderIcon(props = {}) {
icon = <div className={_className} style={{
height: '14px',
'line-height': '14px',
width: '24px',
padding: 0,
// width: '24px',
transform: 'scale(0.833)',
padding: '0px 5px',
'margin-top': '-2px',
'margin-left': '2px',
'vertical-align': 'middle', }}>组长</div>
} else {
icon = <div className={_className} style={{ height: '16px', 'line-height': '16px', width: '30px'}}>组长</div>
icon = <div className={_className} style={{ height: '16px', 'line-height': '16px', transform: 'scale(0.833)'}}>组长</div>
}
return icon

@ -711,8 +711,12 @@ class GraduationTaskssettinglist extends Component{
title: '姓名',
dataIndex: 'name',
key: 'name',
className:'edu-txt-center'
className:'edu-txt-center',
render: (text, record) => (
<span>
<div style={{color:'#9A9A9A'}} className={"studentname"} title={record.name}>{record.name}</div>
</span>
),
}, {
title: '学号',
dataIndex: 'stduynumber',
@ -720,7 +724,7 @@ class GraduationTaskssettinglist extends Component{
className:'edu-txt-center',
render: (text, record) => (
<span>
<a style={{color:'#9A9A9A'}}>{record.stduynumber}</a>
<div style={{color:'#9A9A9A'}} className={"studentnumber"} title={record.stduynumber}>{record.stduynumber}</div>
</span>
),
}, {
@ -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
}
`
}
</style>
{taskslistdata&&taskslistdata.have_grouping===true||
taskslistdata&&taskslistdata.have_project===true||
taskslistdata&&taskslistdata.cross_comment===true?<style>
{
`
.studentnumber{
text-overflow: ellipsis;
white-space: nowrap;
width: 105px;
display: block;
overflow: hidden;
margin: 0px auto;
cursor: default;
}
.studentname{
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
width: 90px;
margin: 0px auto;
}
`
}</style>:""}
{/*提示*/}
<Modals
modalsType={Modalstype}
@ -1207,22 +1240,25 @@ class GraduationTaskssettinglist extends Component{
{taskslistdata.search_assistants&&taskslistdata.search_assistants.course_group_info.length!=0?<li className="clearfix">
<span className="fl mr10 color-grey-8">分班情况</span>
<div className="fl mr25">
<a id="graduation_comment_no_limit" className={course_group===null||course_group===undefined?"pl10 pr10 check_on":"pl10 pr10 "} onClick={()=>this.groupgroup([])}>不限</a>
</div>
<div className="fl groupList" style={{maxWidth: '945px'}}>
<CheckboxGroup value={course_group} onChange={(e)=>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(
<span key={key} className={"mt10"}>
<Checkbox value={item.course_group_id} key={item.course_group_id} className="fl ">{item.group_group_name}
<span>({item.count})</span>
</Checkbox>
</span>
)
})}
</CheckboxGroup>
</div>
<CheckboxGroup value={course_group} onChange={(e)=>this.groupgroup(e,taskslistdata.search_assistants&&taskslistdata.search_assistants.course_group_info.length)} style={{width: '1000px', paddingTop: '4px'}}>
<span className="fl mr25">
<a id="graduation_comment_no_limit" className={course_group===null||course_group===undefined?"pl10 pr10 check_on":"pl10 pr10 "} onClick={()=>this.groupgroup([])}>不限</a>
</span>
{taskslistdata.search_assistants&&taskslistdata.search_assistants.course_group_info.map((item,key)=>{
return(
<span key={key} className={"mt10"}>
<Checkbox value={item.course_group_id} key={item.course_group_id} className="fl ">{item.group_group_name}
<span>({item.count})</span>
</Checkbox>
</span>
)
})}
</CheckboxGroup>
</li>:""}

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

@ -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={
<React.Fragment>
{ isSuperAdmin && <React.Fragment>
<CreateGroupByImportModal ref="createGroupByImportModal" {...this.props}></CreateGroupByImportModal>
<CreateGroupByImportModal ref="createGroupByImportModal" {...this.props}
createGroupImportSuccess={this.createGroupImportSuccess}
></CreateGroupByImportModal>
<WordsBtn style="blue" className="mr30" onClick={()=> this.refs['createGroupByImportModal'].setVisible(true)}>导入创建分班</WordsBtn>
</React.Fragment> }
{ isAdmin && isParent && <WordsBtn style="blue" className="mr30" onClick={()=>this.addDir()}>添加分班</WordsBtn> }

@ -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 ? '' : <a href="javascript:;">{(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 ? <Checkbox value={content}></Checkbox> : ''
}
})
}
// if(isAdminOrTeacher && hasGraduationModule) {
// columns.unshift({
// title: '',
// dataIndex: 'course_member_id',
// key: 'course_member_id',
// render: (content, item, index) => {
// return content ? <Checkbox value={content}></Checkbox> : ''
// }
// })
// }
return columns
}

@ -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 {
<Option key={d} id={k}>{d}</Option>
)
})
return (
<React.Fragment>
<div className="educontent mt30 mb30">

@ -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()}>提交</a>
<a href={this.props.go_back_url}
className="defalutCancelbtn fl">取消</a>
<a onClick={()=>this.delecbtns()}
className="delectshixuncdbtn fr">删除</a>
</div>
</div>

@ -35,7 +35,7 @@ export default class TpmQuestionNew extends Component {
<span className="mr30 color-orange pt10">*</span>
<div className="flex1 mr20">
<TPMMDEditor ref={this.props.newquestioMDMdRef} placeholder="请输入选择题的题干内容" mdID={'newquestioMDid'} refreshTimeout={1500}
watch={true} className="courseMessageMD" initValue={this.props.contentMdRefval}></TPMMDEditor>
needRecreate={true} watch={true} className="courseMessageMD" initValue={this.props.contentMdRefval}></TPMMDEditor>
</div>
@ -108,7 +108,7 @@ export default class TpmQuestionNew extends Component {
<div className={"df"}>
<div className={"flex1 mr20"}>
<TPMMDEditor ref={this.props.newquestioMDMdCont} placeholder="请输入各个选项的具体解析或其他相关信息" mdID={'newquestioMDMdConts'} refreshTimeout={1500}
watch={true} className="courseMessageMD" initValue={this.props.newquestioMDMdContval}></TPMMDEditor>
needRecreate={true} watch={true} className="courseMessageMD" initValue={this.props.newquestioMDMdContval}></TPMMDEditor>
</div>
<div className={"choose_names"} style={{display:this.props.newquestioMDvaluetypes===true?"block":"none"}}>
<span className="color-orange mt8 fl" id="choose_name" style={{display: 'inline'}}><i className="fa fa-exclamation-circle mr3"></i></span>

@ -1,122 +1,124 @@
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];
return(
<div className="bannerPanel mb60">
<div className="educontent">
<div className="clearfix color-white mb25">
<p className="myPhoto mr20 fl"><img alt="头像" src={data && `${getImageUrl('images/'+data.avatar_url)}`}/></p>
<div className="fl">
<p className="clearfix mt20">
<span className="username task-hide" style={{"maxWidth":'370px'}}>{data && data.name}</span>
{
data && is_current == false && data.identity =="学生" ? "" :
<span className="userpost"><label>{data && data.identity}</label></span>
}
</p>
<p className="mt15">
<Tooltip placement='bottom' title={ data && data.professional_certification ?"已职业认证":"未职业认证"}>
<i className={ data && data.professional_certification ? "iconfont icon-shenfenzhenghaomaguizheng font-18 user-colorgrey-green mr20 ml2":"iconfont icon-shenfenzhenghaomaguizheng font-18 user-colorgrey-B8 mr20 ml2"}></i>
</Tooltip>
<Tooltip placement='bottom' title={ data && data.authentication ?"已实名认证":"未实名认证"}>
<i className={ data && data.authentication ? "iconfont icon-renzhengshangjia font-18 user-colorgrey-green":"iconfont icon-renzhengshangjia font-18 user-colorgrey-B8"}></i>
</Tooltip>
</p>
</div>
<div className="fr">
<div class="fl headtab mt20">
<span>{is_current ? "我":"TA"}的经验值</span>
<a style={{"cursor":"default"}}>{data && data.experience}</a>
</div>
<div class="fl headtab mt20 pr leftTransform pl20">
<span>{is_current ? "我":"TA"}的金币</span>
<a style={{"cursor":"default"}}>{data && data.grade}</a>
</div>
{
is_current ?
<span className="fl mt35 ml60">
{
data && data.attendance_signed ?
<span className="user_default_btn user_grey_btn font-18">已签到</span>
:
<a herf="javascript:void(0);" onClick={this.props.signFor} className="user_default_btn user_yellow_btn fl font-18">签到</a>
}
</span>
:
<span className="fl mt35 ml60">
<LinkAfterLogin
{...this.props}
{...this.state}
className="user_default_btn user_yellow_btn fl font-18"
to={`/messages/${login}/message_detail?target_ids=${id}`}
>
私信
</LinkAfterLogin>
</span>
}
</div>
</div>
<div className="userNav">
<li className={`${moduleName == 'courses' ||moduleName == undefined ? 'active' : '' }`}>
<Link
onClick={() => this.setState({moduleName: 'courses'})}
to={`/users/${username}/courses`}>翻转课堂</Link>
</li>
<li className={`${moduleName == 'shixuns' ? 'active' : '' }`}>
<Link
onClick={() => this.setState({moduleName: 'shixuns'})}
to={`/users/${username}/shixuns`}>开发社区</Link>
</li>
<li className={`${moduleName == 'paths' ? 'active' : '' }`}>
<Link
onClick={() => this.setState({moduleName: 'paths'})}
to={`/users/${username}/paths`}>实践课程</Link>
</li>
<li className={`${moduleName == 'projects' ? 'active' : '' }`}>
<Link
onClick={() => this.setState({moduleName: 'projects'})}
to={`/users/${username}/projects`}>项目</Link>
</li>
<li className={`${moduleName == 'package' ? 'active' : '' }`}>
<Link
onClick={() => this.setState({moduleName: 'package'})}
to={`/users/${username}/package`}>众包</Link>
</li>
{((is_current && current_user && current_user.is_teacher ) || current_user && current_user.admin)
&& <li className={`${moduleName == 'videos' ? 'active' : '' }`}>
<Link
onClick={() => this.setState({moduleName: 'videos'})}
to={`/users/${username}/videos`}>视频</Link>
</li>}
</div>
</div>
</div>
)
}
}
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];
return(
<div className="bannerPanel mb60">
<div className="educontent">
<div className="clearfix color-white mb25">
<p className="myPhoto mr20 fl"><img alt="头像" src={data && `${getImageUrl('images/'+data.avatar_url)}`}/></p>
<div className="fl">
<p className="clearfix mt20">
<span className="username task-hide" style={{"maxWidth":'370px'}}>{data && data.name}</span>
{
data && is_current == false && data.identity =="学生" ? "" :
<span className="userpost"><label>{data && data.identity}</label></span>
}
</p>
<p className="mt15">
<Tooltip placement='bottom' title={ data && data.professional_certification ?"已职业认证":"未职业认证"}>
<i className={ data && data.professional_certification ? "iconfont icon-shenfenzhenghaomaguizheng font-18 user-colorgrey-green mr20 ml2":"iconfont icon-shenfenzhenghaomaguizheng font-18 user-colorgrey-B8 mr20 ml2"}></i>
</Tooltip>
<Tooltip placement='bottom' title={ data && data.authentication ?"已实名认证":"未实名认证"}>
<i className={ data && data.authentication ? "iconfont icon-renzhengshangjia font-18 user-colorgrey-green":"iconfont icon-renzhengshangjia font-18 user-colorgrey-B8"}></i>
</Tooltip>
</p>
</div>
<div className="fr">
<div class="fl headtab mt20">
<span>{is_current ? "我":"TA"}的经验值</span>
<a style={{"cursor":"default"}}>{data && data.experience}</a>
</div>
<div class="fl headtab mt20 pr leftTransform pl20">
<span>{is_current ? "我":"TA"}的金币</span>
<a style={{"cursor":"default"}}>{data && data.grade}</a>
</div>
{
is_current ?
<span className="fl mt35 ml60">
{
data && data.attendance_signed ?
<span className="user_default_btn user_grey_btn font-18">已签到</span>
:
<a herf="javascript:void(0);" onClick={this.props.signFor} className="user_default_btn user_yellow_btn fl font-18">签到</a>
}
</span>
:
<span className="fl mt35 ml60">
<LinkAfterLogin
{...this.props}
{...this.state}
className="user_default_btn user_yellow_btn fl font-18"
to={`/messages/${login}/message_detail?target_ids=${id}`}
>
私信
</LinkAfterLogin>
</span>
}
</div>
</div>
<div className="userNav">
<li className={`${moduleName == 'courses' ||moduleName == undefined ? 'active' : '' }`}>
<Link
onClick={() => this.setState({moduleName: 'courses'})}
to={`/users/${username}/courses`}>翻转课堂</Link>
</li>
<li className={`${moduleName == 'shixuns' ? 'active' : '' }`}>
<Link
onClick={() => this.setState({moduleName: 'shixuns'})}
to={`/users/${username}/shixuns`}>实训项目</Link>
</li>
<li className={`${moduleName == 'paths' ? 'active' : '' }`}>
<Link
onClick={() => this.setState({moduleName: 'paths'})}
to={`/users/${username}/paths`}>实践课程</Link>
</li>
<li className={`${moduleName == 'projects' ? 'active' : '' }`}>
<Link
onClick={() => this.setState({moduleName: 'projects'})}
to={`/users/${username}/projects`}>开发项目</Link>
</li>
<li className={`${moduleName == 'package' ? 'active' : '' }`}>
<Link
onClick={() => this.setState({moduleName: 'package'})}
to={`/users/${username}/package`}>众包</Link>
</li>
{((is_current && current_user && current_user.is_teacher ) || current_user && current_user.admin)
&& <li className={`${moduleName == 'videos' ? 'active' : '' }`}>
<Link
onClick={() => this.setState({moduleName: 'videos'})}
to={`/users/${username}/videos`}>视频</Link>
</li>}
</div>
</div>
</div>
)
}
}
export default InfosBanner;

@ -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-btnend-----------------------------------------*/

Loading…
Cancel
Save