Merge branch 'topic_bank' of https://bdgit.educoder.net/Hjqreturn/educoder into topic_bank
# Conflicts: # public/react/src/modules/user/usersInfo/usersInfo.cssdev_aliyun_beta
commit
7efde2abe3
@ -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');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
@ -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
|
@ -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
|
@ -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">×</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 } %>
|
@ -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 %>
|
||||
|
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,50 +0,0 @@
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
|
||||
|
||||
import Loading from '../../Loading';
|
||||
|
||||
import Loadable from 'react-loadable';
|
||||
|
||||
import { TPMIndexHOC } from './TPMIndexHOC';
|
||||
|
||||
import { SnackbarHOC } from 'educoder';
|
||||
|
||||
import axios from 'axios';
|
||||
|
||||
|
||||
class TPMIndex extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount = () => {
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
|
||||
return (
|
||||
<div className="newMain clearfix">
|
||||
|
||||
{/*<Switch {...this.props}>*/}
|
||||
|
||||
{/*<Route path="/shixuns/:shixunId/repository/:repoId/commits" render={*/}
|
||||
{/*(props) => (<TPMRepositoryCommits {...this.props} {...this.state} {...props}*/}
|
||||
{/*/>)*/}
|
||||
{/*}></Route>*/}
|
||||
|
||||
{/*</Switch>*/}
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default SnackbarHOC() (TPMIndexHOC ( TPMIndex ));
|
@ -1,122 +1,134 @@
|
||||
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];
|
||||
|
||||
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(
|
||||
<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>}
|
||||
|
||||
{/*自己的主页且不是学生显示题库按钮*/}
|
||||
{ user_id===targetuserid&&user_type!="学生"?<li className={`${moduleName == 'topics' ? 'active' : '' }`}>
|
||||
<Link
|
||||
onClick={() => this.setState({moduleName: 'topics'})}
|
||||
to={`/users/${username}/topics`}>题库</Link>
|
||||
</li>:""}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
export default InfosBanner;
|
@ -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(
|
||||
<div className="educontent mb50">
|
||||
{/*提示*/}
|
||||
<Modals
|
||||
modalsType={this.state.Modalstype}
|
||||
modalsTopval={this.state.Modalstopval}
|
||||
modalCancel={this.state.ModalCancel}
|
||||
modalSave={this.state.ModalSave}
|
||||
/>
|
||||
<Spin size="large" spinning={isSpin}>
|
||||
<div className="clearfix topicsbox">
|
||||
<div className={"topcschild"}>
|
||||
<span className={"topicstopfont fl"}>我的题库</span>
|
||||
<span className={"topicstopfont fr"}>公共题库</span>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<p className="pl25 pr25 clearfix font-12 mb20 mt20">
|
||||
<span className="fl color-grey-9">共个</span>
|
||||
<span className="fr color-grey-9">发布时间</span>
|
||||
</p>
|
||||
|
||||
|
||||
{/*{data===undefined?<NoneData></NoneData>:data.project_packages.length===0?<NoneData></NoneData>:data.project_packages.map((item,key)=>{*/}
|
||||
{/*return(*/}
|
||||
{/*<div className="educontent project-packages-list" key={key}>*/}
|
||||
{/*<div className="project-package-item with-operator project-package-11">*/}
|
||||
|
||||
{/*<div className="item-image">*/}
|
||||
{/*<img alt="图片" src={`/images/educoder/project_packages/${setcategorylist(item.category_name)}.png`} />*/}
|
||||
{/*</div>*/}
|
||||
|
||||
{/*<div className="item-body">*/}
|
||||
{/*<div className="item-head">*/}
|
||||
{/*<div className="item-head-title" title={item.title}>*/}
|
||||
{/*<a href={`/crowdsourcing/${item.id}`}>{item.title}</a>*/}
|
||||
{/*</div>*/}
|
||||
|
||||
{/*<div className="item-head-tags">*/}
|
||||
{/*{item.bidden_status==="pending"?<span className="pending">竞标中</span>:""}*/}
|
||||
{/*{item.bidden_status==="bidding_won"?<span className="bidding_won">已中标</span>:""}*/}
|
||||
{/*{item.bidden_status==="bidding_lost"?<span className="bidding_lost">未中标</span>:""}*/}
|
||||
{/*</div>*/}
|
||||
|
||||
{/*<div className="item-head-blank"></div>*/}
|
||||
{/*<div className="item-head-price mtf15">*/}
|
||||
{/*{item.min_price===null?"":<span>¥{item.min_price}</span>}*/}
|
||||
{/*{item.max_price===null||item.min_price===null?"":<span>~</span>}*/}
|
||||
{/*{item.max_price===null?"":<span>¥{item.max_price}</span>}*/}
|
||||
{/*{item.min_price===null&&item.max_price===null?<span>可议价</span>:""}*/}
|
||||
{/*</div>*/}
|
||||
{/*</div>*/}
|
||||
{/*<div className="item-category">*/}
|
||||
{/*<div className="item-category-item">{item.category_name}</div>*/}
|
||||
{/*</div>*/}
|
||||
{/*<div className="item-other">*/}
|
||||
{/*<div className="item-group item-other-visit">*/}
|
||||
{/*<span className="item-group-icon mr10"><i className="fa fa-eye"></i></span>*/}
|
||||
{/*<span className="item-group-text">{item.visit_count}人浏览</span>*/}
|
||||
{/*</div>*/}
|
||||
{/*<div className="item-group item-other-deadline">*/}
|
||||
{/*<span className="item-group-icon mr10"><i className="fa fa-clock-o"></i></span>*/}
|
||||
{/*<span className="item-group-text">{moment(item.deadline_at).format("YYYY-MM-DD HH:mm")}竞标截止</span>*/}
|
||||
{/*</div>*/}
|
||||
{/*<div className="item-group item-other-bidding pagemancenter">*/}
|
||||
{/*<span className="item-group-icon mr10"><i className="fa fa-user"></i></span>*/}
|
||||
{/*<span className="item-group-text">{item.bidding_users_count}人竞标</span>*/}
|
||||
{/*</div>*/}
|
||||
{/*<div className="item-group item-other-publish-at">*/}
|
||||
{/*{item.published_at===null?<span className="item-group-text">更新于:{moment(item.updated_at).format("YYYY-MM-DD HH:mm")} </span>:*/}
|
||||
{/*<span className=" item-group-text">发布于:{moment(item.published_at).format("YYYY-MM-DD HH:mm")} </span>}*/}
|
||||
{/*</div>*/}
|
||||
{/*</div>*/}
|
||||
{/*</div>*/}
|
||||
|
||||
{/*{category=="manage"?item.operation.can_edit===true&&item.operation.can_delete===true?*/}
|
||||
{/*<div className="item-operator none">*/}
|
||||
|
||||
{/*<a href={`/crowdsourcing/${item.id}/edit`} title="编辑">*/}
|
||||
{/*<i className="fa fa-pencil"></i>*/}
|
||||
{/*</a>*/}
|
||||
|
||||
{/*<a className="delete-project-package-btn" onClick={()=>this.delectprojectModal(item.id)} data-id="10" title="删除">*/}
|
||||
{/*<i className="fa fa-trash-o"></i>*/}
|
||||
{/*</a>*/}
|
||||
|
||||
{/*</div>:"":""}*/}
|
||||
|
||||
{/*{category=="manage"?item.operation.can_edit===true&&item.operation.can_delete===false?*/}
|
||||
{/*<div className="item-operator none">*/}
|
||||
{/*<a href={`/crowdsourcing/${item.id}/edit`} title="编辑">*/}
|
||||
{/*<i className="fa fa-pencil"></i>*/}
|
||||
{/*</a>*/}
|
||||
{/*</div>:"":""}*/}
|
||||
|
||||
|
||||
{/*</div>*/}
|
||||
{/*</div>*/}
|
||||
{/*)})}*/}
|
||||
|
||||
{/*{*/}
|
||||
{/*totalCount >20 &&*/}
|
||||
{/*<div className="mt30 mb50 edu-txt-center">*/}
|
||||
{/*<Pagination showQuickJumper total={totalCount} onChange={this.changePage} pageSize={20} current={page}/>*/}
|
||||
{/*</div>*/}
|
||||
{/*}*/}
|
||||
|
||||
</Spin>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
export default InfosTopics;
|
Loading…
Reference in new issue