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

dev_aliyun_beta
cxt 5 years ago
commit 334466ef91

@ -25,6 +25,12 @@ $.fn.select2.defaults.set('language', 'zh-CN');
Turbolinks.setProgressBarDelay(200);
$.notifyDefaults({
type: 'success',
z_index: 9999,
delay: 2000
});
$(document).on('turbolinks:load', function(){
$('[data-toggle="tooltip"]').tooltip();
$('[data-toggle="popover"]').popover();

@ -0,0 +1,173 @@
$(document).on('turbolinks:load', function() {
if ($('body.admins-departments-index-page').length > 0) {
var $searchContainer = $('.department-list-form');
var $searchForm = $searchContainer.find('form.search-form');
var $list = $('.department-list-container');
$searchContainer.on('change', '.form-check-input', function(){
$searchForm.find('input[type="submit"]').trigger('click');
});
// ============== 新建部门 ===============
var $modal = $('.modal.admin-create-department-modal');
var $form = $modal.find('form.admin-create-department-form');
var $departmentNameInput = $form.find('input[name="department_name"]');
var $schoolSelect = $modal.find('.school-select');
$form.validate({
errorElement: 'span',
errorClass: 'danger text-danger',
rules: {
school_id: {
required: true
},
department_name: {
required: true
}
},
messages: {
school_id: {
required: '请选择所属单位'
}
}
});
// modal ready fire
$modal.on('show.bs.modal', function () {
$departmentNameInput.val('');
$schoolSelect.select2('val', ' ');
});
// ************** 学校选择 *************
var matcherFunc = function(params, data){
if ($.trim(params.term) === '') {
return data;
}
if (typeof data.text === 'undefined') {
return null;
}
if (data.name && data.name.indexOf(params.term) > -1) {
var modifiedData = $.extend({}, data, true);
return modifiedData;
}
// Return `null` if the term should not be displayed
return null;
};
var defineSchoolSelect = function(schools) {
$schoolSelect.select2({
theme: 'bootstrap4',
placeholder: '请选择所属单位',
minimumInputLength: 1,
data: schools,
templateResult: function (item) {
if(!item.id || item.id === '') return item.text;
return item.name;
},
templateSelection: function(item){
if (item.id) {
$('#school_id').val(item.id);
}
return item.name || item.text;
},
matcher: matcherFunc
});
}
$.ajax({
url: '/api/schools/for_option.json',
dataType: 'json',
type: 'GET',
success: function(data) {
defineSchoolSelect(data.schools);
}
});
$modal.on('click', '.submit-btn', function(){
$form.find('.error').html('');
if ($form.valid()) {
var url = $form.data('url');
$.ajax({
method: 'POST',
dataType: 'json',
url: url,
data: $form.serialize(),
success: function(){
$.notify({ message: '创建成功' });
$modal.modal('hide');
setTimeout(function(){
window.location.reload();
}, 500);
},
error: function(res){
var data = res.responseJSON;
$form.find('.error').html(data.message);
}
});
}
});
// ============= 添加部门管理员 ==============
var $addMemberModal = $('.admin-add-department-member-modal');
var $addMemberForm = $addMemberModal.find('.admin-add-department-member-form');
var $memberSelect = $addMemberModal.find('.department-member-select');
var $departmentIdInput = $addMemberForm.find('input[name="department_id"]')
$addMemberModal.on('show.bs.modal', function(event){
var $link = $(event.relatedTarget);
var departmentId = $link.data('department-id');
$departmentIdInput.val(departmentId);
$memberSelect.select2('val', ' ');
});
$memberSelect.select2({
theme: 'bootstrap4',
placeholder: '请输入要添加的管理员姓名',
multiple: true,
minimumInputLength: 1,
ajax: {
delay: 500,
url: '/admins/users',
dataType: 'json',
data: function(params){
return { name: params.term };
},
processResults: function(data){
return { results: data.users }
}
},
templateResult: function (item) {
if(!item.id || item.id === '') return item.text;
return item.real_name;
},
templateSelection: function(item){
if (item.id) {
}
return item.real_name || item.text;
}
});
$addMemberModal.on('click', '.submit-btn', function(){
$addMemberForm.find('.error').html('');
var departmentId = $departmentIdInput.val();
var memberIds = $memberSelect.val();
if (departmentId && memberIds && memberIds.length > 0) {
$.ajax({
method: 'POST',
dataType: 'script',
url: '/admins/departments/' + departmentId + '/department_member',
data: { user_ids: memberIds }
});
} else {
$addMemberModal.modal('hide');
}
});
}
});

@ -0,0 +1,21 @@
$(document).on('turbolinks:load', function() {
if ($('body.admins-library-applies-index-page').length > 0) {
var $searchFrom = $('.library-applies-list-form');
$searchFrom.find('select[name="status"]').val('pending');
$searchFrom.on('click', '.search-form-tab', function(){
var $link = $(this);
$searchFrom.find('input[name="keyword"]').val('');
$searchFrom.find('select[name="status"]').val('processed');
if($link.data('value') === 'processed'){
$searchFrom.find('.status-filter').show();
} else {
$searchFrom.find('.status-filter').hide();
$searchFrom.find('select[name="status"]').val('pending');
}
});
}
})

@ -0,0 +1,34 @@
$(document).on('turbolinks:load', function() {
$('.admin-modal-container').on('show.bs.modal', '.modal.admin-edit-department-modal', function(){
var $modal = $('.modal.admin-edit-department-modal');
var $form = $modal.find('form.admin-edit-department-form');
$form.validate({
errorElement: 'span',
errorClass: 'danger text-danger',
rules: {
'department[name]': {
required: true,
maxlength: 20
},
'department[host_count]': {
digits: true
}
}
});
$modal.on('click', '.submit-btn', function(){
$form.find('.error').html('');
var url = $form.attr('action');
if ($form.valid()) {
$.ajax({
method: 'PATCH',
dataType: 'script',
url: url,
data: $form.serialize()
});
}
});
})
});

@ -0,0 +1,110 @@
$(document).on('turbolinks:load', function() {
var $modal = $('.modal.admin-merge-department-modal');
if ($modal.length > 0) {
var $form = $modal.find('form.admin-merge-department-form');
var $schoolIdInput = $form.find('input[name="school_id"]');
var $originDepartmentIdInput = $form.find('input[name="origin_department_id"]');
var $departmentSelect = $modal.find('.department-select');
$form.validate({
errorElement: 'span',
errorClass: 'danger text-danger',
rules: {
department_id: {
required: true
}
},
messages: {
department_id: {
required: '请选择部门'
}
}
});
// ************** 学校选择 *************
var matcherFunc = function(params, data){
if ($.trim(params.term) === '') {
return data;
}
if (typeof data.text === 'undefined') {
return null;
}
if (data.name && data.name.indexOf(params.term) > -1) {
var modifiedData = $.extend({}, data, true);
return modifiedData;
}
// Return `null` if the term should not be displayed
return null;
};
var defineDepartmentSelect = function(departments) {
$departmentSelect.empty();
$departmentSelect.select2({
theme: 'bootstrap4',
placeholder: '请选择所属部门',
data: departments,
templateResult: function (item) {
if(!item.id || item.id === '') return item.text;
return item.name;
},
templateSelection: function(item){
if (item.id) {
$form.find('#department_id').val(item.id);
}
return item.name || item.text;
},
matcher: matcherFunc
});
$departmentSelect.select2('val', ' ');
};
// modal ready fire
$modal.on('show.bs.modal', function (event) {
var $link = $(event.relatedTarget);
var schoolId = $link.data('schoolId');
$schoolIdInput.val(schoolId);
$originDepartmentIdInput.val($link.data('departmentId'));
$.ajax({
url: '/api/schools/' + schoolId + '/departments/for_option.json',
dataType: 'json',
type: 'GET',
success: function(data) {
defineDepartmentSelect(data.departments);
}
});
});
$modal.on('click', '.submit-btn', function(){
$form.find('.error').html('');
if ($form.valid()) {
var url = $form.data('url');
$.ajax({
method: 'POST',
dataType: 'json',
url: url,
data: $form.serialize(),
success: function(){
$.notify({ message: '操作成功' });
$modal.modal('hide');
setTimeout(function(){
window.location.reload();
}, 500);
},
error: function(res){
var data = res.responseJSON;
$form.find('.error').html(data.message);
}
});
}
});
}
});

@ -0,0 +1,33 @@
$(document).on('turbolinks:load', function() {
if ($('body.admins-shixun-settings-index-page').length > 0) {
$(".shixun-settings-select").on("change", function () {
var s_value = $(this).val();
var s_name = $(this).attr("name");
var json = {};
json[s_name] = s_value;
$.ajax({
url: "/admins/shixun_settings",
type: "GET",
dataType:'script',
data: json
})
});
$(".shixun-setting-form").on("change",function () {
var s_id = $(this).attr("data-id");
var s_value = $(this).val();
var s_name = $(this).attr("name");
var json = {};
var s_index = $(this).parent("td").siblings(".shixun-line-no").text();
json[s_name] = s_value;
json["page_no"] = s_index;
$.ajax({
url: "/admins/shixun_settings/" + s_id,
type: "PUT",
dataType:'script',
data: json
})
})
}
});

@ -0,0 +1,6 @@
$(document).on('turbolinks:load', function() {
$('select#tag-choosed').select2({
placeholder: "请选择分类",
allowClear: true
});
});

@ -46,11 +46,24 @@ label.error {
}
}
input.form-control {
font-size: 14px;
}
.flex-1 {
flex: 1;
}
.btn-default{
color: #666;
background: #e1e1e1!important;
}
.export-absolute{
right:20px;
position: absolute;
}
.position-r{position:relative;}
.font-12 { font-size: 12px !important; }
.font-14 { font-size: 14px !important; }
.font-16 { font-size: 16px !important; }
.font-18 { font-size: 18px !important; }
.font-18 { font-size: 18px !important; }

@ -0,0 +1,24 @@
.admins-departments-index-page {
.department-list-table {
.member-container {
.member-user {
display: flex;
justify-content: center;
flex-wrap: wrap;
.member-user-item {
display: flex;
align-items: center;
height: 22px;
line-height: 22px;
padding: 2px 5px;
margin: 2px 2px;
border: 1px solid #91D5FF;
background-color: #E6F7FF;
color: #91D5FF;
border-radius: 4px;
}
}
}
}
}

@ -0,0 +1,9 @@
.admins-library-applies-index-page {
.library-applies-list-container {
span {
&.apply-status-agreed { color: #28a745; }
&.apply-status-refused { color: #dc3545; }
&.apply-status-processed { color: #6c757d; }
}
}
}

@ -0,0 +1,7 @@
.admins-shixuns-index-page{
.shixuns-list-container{
.shixuns-status-1 { color: #6c757d; }
.shixuns-status-2 { color: #28a745; }
.shixuns-status-3 { color: #dc3545; }
}
}

@ -0,0 +1,14 @@
input[type="checkbox"]{
font-size:18px;
}
.select2 input::-webkit-input-placeholder{
color:#ccc;
}
.select2 .select2-selection__choice{
border: 1px solid #eee !important;
}
.setting-chosen{
font-weight: 400;
font-size: 10px;
color:#333;
}

@ -1 +1 @@
.select2-container--bootstrap4 .select2-selection--single{height:calc(1.5em + .75rem + 2px)!important}.select2-container--bootstrap4 .select2-selection--single .select2-selection__placeholder{color:#757575;line-height:calc(1.5em + .75rem)}.select2-container--bootstrap4 .select2-selection--single .select2-selection__arrow{position:absolute;top:50%;right:3px;width:20px}.select2-container--bootstrap4 .select2-selection--single .select2-selection__arrow b{top:60%;border-color:#343a40 transparent transparent;border-style:solid;border-width:5px 4px 0;width:0;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute}.select2-container--bootstrap4 .select2-selection--single .select2-selection__rendered{line-height:calc(1.5em + .75rem)}.select2-search--dropdown .select2-search__field{border:1px solid #ced4da;border-radius:.25rem}.select2-results__message{color:#6c757d}.select2-container--bootstrap4 .select2-selection--multiple{min-height:calc(1.5em + .75rem + 2px)!important}.select2-container--bootstrap4 .select2-selection--multiple .select2-selection__rendered{-webkit-box-sizing:border-box;box-sizing:border-box;list-style:none;margin:0;padding:0 5px;width:100%}.select2-container--bootstrap4 .select2-selection--multiple .select2-selection__choice{color:#343a40;border:1px solid #bdc6d0;border-radius:.2rem;padding:0 5px 0 0;cursor:pointer;float:left;margin-top:.3em;margin-right:5px}.select2-container--bootstrap4 .select2-selection--multiple .select2-selection__choice__remove{color:#bdc6d0;font-weight:700;margin-left:3px;margin-right:1px;padding-right:3px;padding-left:3px;float:left}.select2-container--bootstrap4 .select2-selection--multiple .select2-selection__choice__remove:hover{color:#343a40}.select2-container{display:block}.select2-container :focus{outline:0}.input-group .select2-container--bootstrap4{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1}.input-group-prepend~.select2-container--bootstrap4 .select2-selection{border-top-left-radius:0;border-bottom-left-radius:0}.select2-container--bootstrap4 .select2-selection{border:1px solid #ced4da;border-radius:.25rem;width:100%}.select2-container--bootstrap4.select2-container--focus .select2-selection{border-color:#17a2b8;-webkit-box-shadow:0 0 0 .2rem rgba(0,123,255,.25);box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.select2-container--bootstrap4.select2-container--focus.select2-container--open .select2-selection{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--bootstrap4.select2-container--disabled.select2-container--focus .select2-selection,.select2-container--bootstrap4.select2-container--disabled .select2-selection{background-color:#e9ecef;cursor:not-allowed;border-color:#ced4da;-webkit-box-shadow:none;box-shadow:none}.select2-container--bootstrap4.select2-container--disabled.select2-container--focus .select2-search__field,.select2-container--bootstrap4.select2-container--disabled .select2-search__field{background-color:transparent}form.was-validated select:invalid~.select2-container--bootstrap4 .select2-selection,select.is-invalid~.select2-container--bootstrap4 .select2-selection{border-color:#dc3545}form.was-validated select:valid~.select2-container--bootstrap4 .select2-selection,select.is-valid~.select2-container--bootstrap4 .select2-selection{border-color:#28a745}.select2-container--bootstrap4 .select2-dropdown{border-color:#ced4da;border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-container--bootstrap4 .select2-dropdown.select2-dropdown--above{border-top:1px solid #ced4da;border-top-left-radius:.25rem;border-top-right-radius:.25rem}.select2-container--bootstrap4 .select2-dropdown .select2-results__option[aria-selected=true]{background-color:#e9ecef}.select2-container--bootstrap4 .select2-results__option--highlighted,.select2-container--bootstrap4 .select2-results__option--highlighted.select2-results__option[aria-selected=true]{background-color:#007bff;color:#f8f9fa}.select2-container--bootstrap4 .select2-results__option[role=group]{padding:0}.select2-container--bootstrap4 .select2-results>.select2-results__options{max-height:15em;overflow-y:auto}.select2-container--bootstrap4 .select2-results__group{padding:6px;display:list-item;color:#6c757d}.select2-container--bootstrap4 .select2-selection__clear{width:1.2em;height:1.2em;line-height:1.15em;padding-left:.3em;margin-top:.5em;border-radius:100%;background-color:#6c757d;color:#f8f9fa;float:right;margin-right:.3em}.select2-container--bootstrap4 .select2-selection__clear:hover{background-color:#343a40}
.select2-container--bootstrap4 .select2-selection--single{height:calc(1.5em + .75rem + 2px)!important}.select2-container--bootstrap4 .select2-selection--single .select2-selection__placeholder{color:#757575;line-height:calc(1.5em + .75rem)}.select2-container--bootstrap4 .select2-selection--single .select2-selection__arrow{position:absolute;top:50%;right:3px;width:20px}.select2-container--bootstrap4 .select2-selection--single .select2-selection__arrow b{top:60%;border-color:#343a40 transparent transparent;border-style:solid;border-width:5px 4px 0;width:0;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute}.select2-container--bootstrap4 .select2-selection--single .select2-selection__rendered{line-height:calc(1.5em + .75rem)}.select2-search--dropdown .select2-search__field{border:1px solid #ced4da;border-radius:.25rem}.select2-results__message{color:#6c757d}.select2-container--bootstrap4 .select2-selection--multiple{min-height:calc(1.5em + .75rem + 2px)!important}.select2-container--bootstrap4 .select2-selection--multiple .select2-selection__rendered{-webkit-box-sizing:border-box;box-sizing:border-box;list-style:none;margin:0;padding:0 5px;width:100%}.select2-container--bootstrap4 .select2-selection--multiple .select2-selection__choice{color:#343a40;border:1px solid #bdc6d0;border-radius:.2rem;padding:0 5px 0 0;cursor:pointer;float:left;margin-top:.3em;margin-right:5px}.select2-container--bootstrap4 .select2-selection--multiple .select2-selection__choice__remove{color:#bdc6d0;font-weight:700;margin-left:3px;margin-right:1px;padding-right:3px;padding-left:3px;float:left}.select2-container--bootstrap4 .select2-selection--multiple .select2-selection__choice__remove:hover{color:#343a40}.select2-container{display:block}.select2-container :focus{outline:0}.input-group .select2-container--bootstrap4{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1}.input-group-prepend~.select2-container--bootstrap4 .select2-selection{border-top-left-radius:0;border-bottom-left-radius:0}.select2-container--bootstrap4 .select2-selection{border:1px solid #ced4da;border-radius:.25rem;width:100%}.select2-container--bootstrap4.select2-container--focus .select2-selection{border-color:#17a2b8;-webkit-box-shadow:0 0 0 .2rem rgba(0,123,255,.25);box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.select2-container--bootstrap4.select2-container--focus.select2-container--open .select2-selection{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--bootstrap4.select2-container--disabled.select2-container--focus .select2-selection,.select2-container--bootstrap4.select2-container--disabled .select2-selection{background-color:#e9ecef;cursor:not-allowed;border-color:#ced4da;-webkit-box-shadow:none;box-shadow:none}.select2-container--bootstrap4.select2-container--disabled.select2-container--focus .select2-search__field,.select2-container--bootstrap4.select2-container--disabled .select2-search__field{background-color:transparent}form.was-validated select:invalid~.select2-container--bootstrap4 .select2-selection,select.is-invalid~.select2-container--bootstrap4 .select2-selection{border-color:#dc3545}form.was-validated select:valid~.select2-container--bootstrap4 .select2-selection,select.is-valid~.select2-container--bootstrap4 .select2-selection{border-color:#28a745}.select2-container--bootstrap4 .select2-dropdown{border-color:#ced4da;border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-container--bootstrap4 .select2-dropdown.select2-dropdown--above{border-top:1px solid #ced4da;border-top-left-radius:.25rem;border-top-right-radius:.25rem}.select2-container--bootstrap4 .select2-dropdown .select2-results__option[aria-selected=true]{background-color:#e9ecef}.select2-container--bootstrap4 .select2-results__option--highlighted,.select2-container--bootstrap4 .select2-results__option--highlighted.select2-results__option[aria-selected=true]{background-color:#007bff;color:#f8f9fa}.select2-container--bootstrap4 .select2-results__option[role=group]{padding:0}.select2-container--bootstrap4 .select2-results>.select2-results__options{max-height:15em;overflow-y:auto}.select2-container--bootstrap4 .select2-results__group{padding:6px;display:list-item;color:#6c757d}.select2-container--bootstrap4 .select2-selection__clear{width:1.2em;height:1.2em;line-height:1.15em;padding-left:.3em;margin-top:.5em;border-radius:100%;background-color:#ccc;color:#f8f9fa;float:right;margin-right:.3em}.select2-container--bootstrap4 .select2-selection__clear:hover{background-color:#343a40}

@ -0,0 +1,20 @@
class Admins::DepartmentMembersController < Admins::BaseController
helper_method :current_department
def create
Admins::AddDepartmentMemberService.call(current_department, params)
current_department.reload
end
def destroy
@member = current_department.department_members.find_by(user_id: params[:user_id])
@member.destroy! if @member.present?
end
private
def current_department
@_current_department ||= Department.find(params[:department_id])
end
end

@ -0,0 +1,95 @@
class Admins::DepartmentsController < Admins::BaseController
helper_method :current_department
def index
params[:sort_by] ||= 'created_at'
params[:sort_direction] ||= 'desc'
departments = Admins::DepartmentQuery.call(params)
@departments = paginate departments.preload(:school, :member_users)
department_ids = @departments.map(&:id)
@users_count = UserExtension.where(department_id: department_ids).group(:department_id).count
@professional_auth_count = UserExtension.where(department_id: department_ids)
.joins(:user).where(users: { professional_certification: true })
.group(:department_id).count
end
def create
department_name = params[:department_name].to_s.strip
school = School.find(params[:school_id])
return render_error('部门名称重复') if school.departments.exists?(name: department_name)
ActiveRecord::Base.transaction do
department = school.departments.create!(name: department_name, is_auth: 1)
ApplyAddDepartment.create!(school_id: school.id, status: 1, name: department.name,
department_id: department.id, user_id: current_user.id)
end
render_ok
end
def edit
end
def update
identifier = update_params.delete(:identifier).presence
if identifier && Department.where.not(id: current_department.id).exists?(identifier: identifier)
return render_error('统计链接重复', type: :notify)
end
current_department.update!(update_params.merge(identifier: identifier))
end
def destroy
ActiveRecord::Base.transaction do
current_department.apply_add_departments.update_all(status: 2)
user_ids = current_department.user_extensions.pluck(:user_id)
if user_ids.present?
DeleteDepartmentNotifyJob.perform_later(current_department.id, 0, user_ids)
current_department.soft_delete!
else
current_department.destroy!
end
end
render_delete_success
end
def merge
return render_error('请选择其它部门') if params[:origin_department_id].to_s == params[:department_id].to_s
origin_department = Department.find(params[:origin_department_id])
to_department = Department.find(params[:department_id])
return render_error('部门所属单位不相同') if origin_department.school_id != to_department.school_id
ActiveRecord::Base.transaction do
origin_department.apply_add_departments.delete_all
origin_department.user_extensions.update_all(department_id: to_department.id)
if to_department.identifier.blank? && origin_department.identifier.present?
to_department.update!(identifier: origin_department.identifier)
end
origin_department.destroy!
end
render_ok
end
private
def current_department
@_current_department ||= Department.find(params[:id])
end
def update_params
params.require(:department).permit(:name, :identifier, :host_count)
end
end

@ -0,0 +1,25 @@
class Admins::LibraryAppliesController < Admins::BaseController
def index
params[:status] ||= 'pending'
applies = Admins::LibraryApplyQuery.call(params)
@library_applies = paginate applies.preload(library: :user)
end
def agree
Libraries::AgreeApplyService.new(current_library_apply, current_user).call
render_success_js
end
def refuse
Libraries::RefuseApplyService.new(current_library_apply, current_user, reason: params[:reason]).call
render_success_js
end
private
def current_library_apply
@_current_library_apply ||= LibraryApply.find(params[:id])
end
end

@ -0,0 +1,86 @@
class Admins::ShixunSettingsController < Admins::BaseController
def index
params[:sort_by] = params[:sort_by].presence || 'created_on'
params[:sort_direction] = params[:sort_direction].presence || 'desc'
shixun_settings = Admins::ShixunSettingsQuery.call(params)
@editing_shixuns = shixun_settings.where(status:0).size
@pending_shixuns = shixun_settings.where(status:1).size
@processed_shixuns = shixun_settings.where(status:2).size
@closed_shixuns = shixun_settings.where(status:3).size
@shixuns_type_check = MirrorRepository.pluck(:type_name,:id)
@shixun_tags = TagRepertoire.order("name asc").pluck(:name,:id)
@params_page = params[:page] || 1
@shixun_settings = paginate shixun_settings.preload(:user,:tag_repertoires)
respond_to do |format|
format.js
format.html
format.xls{
filename = "实训详情_#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}.xls"
send_data(shixun_list_xls(shixun_settings), :type => 'application/octet-stream', :filename => filename_for_content_disposition(filename))
}
end
end
def update
@shixun = Shixun.find_by(id:params[:id])
@page_no = params[:page_no] || "1"
@shixun_tags = TagRepertoire.order("name asc").pluck(:name,:id)
tag_ids = params[:tag_repertoires]
if tag_ids.present?
@shixun&.shixun_tag_repertoires.delete_all
tag_repertoire_ids = @shixun&.tag_repertoires&.pluck(:id)
tag_ids.each do |id|
unless tag_repertoire_ids.include?(id)
tag_repertoire = @shixun.shixun_tag_repertoires.new(shixun_id:@shixun.id,tag_repertoire_id:id)
tag_repertoire.save
end
end
else
unless @shixun.update_attributes(setting_params)
redirect_to admins_shixun_settings_path
flash[:danger] = "更新失败"
end
end
end
private
def shixun_list_xls shixuns
xls_report = StringIO.new
book = Spreadsheet::Workbook.new
sheet1 = book.create_worksheet :name => "sheet"
blue = Spreadsheet::Format.new :color => :blue, :weight => :bold, :size => 10
sheet1.row(0).default_format = blue
sheet1.row(0).concat(["实训ID","实训名称","技术平台", "Fork源", "实践任务","选择题任务","挑战人数", "通关人数", "状态","创建者", "单位", "职业", "关卡序号","关卡名称","技能标签"])
count_row = 1
shixuns.find_each do |shixun|
sheet1[count_row, 0] = shixun.identifier
sheet1[count_row, 1] = shixun.name
sheet1[count_row, 2] = shixun.shixun_main_name
sheet1[count_row, 3] = shixun.fork_identifier
sheet1[count_row, 4] = shixun.challenges.practice_type.count
sheet1[count_row, 5] = shixun.challenges.choose_type.count
sheet1[count_row, 6] = shixun.myshixuns.count
sheet1[count_row, 7] = shixun.myshixuns.finished.count
sheet1[count_row, 8] = shixun.shixun_status
sheet1[count_row, 9] = shixun.owner.show_real_name
sheet1[count_row, 10] = shixun.owner.school_name
sheet1[count_row, 11] = shixun.owner.identity
shixun.challenges.each do |challenge|
sheet1[count_row, 12] = "#{challenge.position}"
sheet1[count_row, 13] = challenge.subject
sheet1[count_row, 14] = challenge.tags_show
count_row += 1
end
count_row += 1
end
book.write xls_report
xls_report.string
end
def setting_params
params.permit(:use_scope,:excute_time,:close,:status,:can_copy,:webssh,:hidden,:homepage_show,:task_pass,:code_hidden,:id,tag_repertoires:[])
end
end

@ -0,0 +1,64 @@
class Admins::ShixunsController < Admins::BaseController
def index
params[:sort_by] = params[:sort_by].presence || 'created_on'
params[:sort_direction] = params[:sort_direction].presence || 'desc'
shixuns = Admins::ShixunQuery.call(params)
@editing_shixuns = shixuns.where(status:0).size
@pending_shixuns = shixuns.where(status:1).size
@processed_shixuns = shixuns.where(status:2).size
@closed_shixuns = shixuns.where(status:3).size
@shixuns_type_check = MirrorRepository.pluck(:type_name,:id)
@params_page = params[:page] || 1
@shixuns = paginate shixuns.preload(:user,:challenges)
respond_to do |format|
format.js
format.html
format.xls{
filename = "实训详情_#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}.xls"
send_data(shixun_list_xls(shixuns), :type => 'application/octet-stream', :filename => filename_for_content_disposition(filename))
}
end
end
def destroy
Shixun.find(params[:id]).destroy!
render_delete_success
end
private
def shixun_list_xls shixuns
xls_report = StringIO.new
book = Spreadsheet::Workbook.new
sheet1 = book.create_worksheet :name => "sheet"
blue = Spreadsheet::Format.new :color => :blue, :weight => :bold, :size => 10
sheet1.row(0).default_format = blue
sheet1.row(0).concat(["实训ID","实训名称","技术平台", "Fork源", "实践任务","选择题任务","挑战人数", "通关人数", "状态","创建者", "单位", "职业", "关卡序号","关卡名称","技能标签"])
count_row = 1
shixuns.find_each do |shixun|
sheet1[count_row, 0] = shixun.identifier
sheet1[count_row, 1] = shixun.name
sheet1[count_row, 2] = shixun.shixun_main_name
sheet1[count_row, 3] = shixun.fork_identifier
sheet1[count_row, 4] = shixun.challenges.practice_type.count
sheet1[count_row, 5] = shixun.challenges.choose_type.count
sheet1[count_row, 6] = shixun.myshixuns.count
sheet1[count_row, 7] = shixun.myshixuns.finished.count
sheet1[count_row, 8] = shixun.shixun_status
sheet1[count_row, 9] = shixun.owner.show_real_name
sheet1[count_row, 10] = shixun.owner.school_name
sheet1[count_row, 11] = shixun.owner.identity
shixun.challenges.each do |challenge|
sheet1[count_row, 12] = "#{challenge.position}"
sheet1[count_row, 13] = challenge.subject
sheet1[count_row, 14] = challenge.tags_show
count_row += 1
end
count_row += 1
end
book.write xls_report
xls_report.string
end
end

@ -17,9 +17,9 @@ module Admins::RenderHelper
json: -> { render status: 404, json: { message: '资源未找到' } })
end
def render_unprocessable_entity(message)
def render_unprocessable_entity(message, type: :alert)
render_by_format(html: -> { render 'admins/shared/422' },
js: -> { render_js_error(message) },
js: -> { render_js_error(message, type: type) },
json: -> { render status: 422, json: { message: message } })
end
alias_method :render_error, :render_unprocessable_entity
@ -40,7 +40,11 @@ module Admins::RenderHelper
end
alias_method :render_success_js, :render_delete_success
def render_js_error(message)
render_js_template 'admins/shared/error', locals: { message: message }
def render_js_error(message, type: :alert)
if type == :notify
render js: "$.notify({ message: '#{message}' },{ type: 'danger', delay: 5000 });"
else
render_js_template 'admins/shared/error', locals: { message: message }
end
end
end

@ -14,6 +14,19 @@ module ShixunsHelper
%W(未发布 已发布 已关闭)[status-1]
end
def shixun_authentication_status shixun
case shixun.try(:status)
when 0,nil
"编辑中"
when 1
"待审核"
when 2
"已发布"
when 3
"已关闭"
end
end
# 已完成实训所获得的经验值
def myshixun_exp myshixun
score = 0

@ -0,0 +1,21 @@
# 删除部门 消息通知
class DeleteDepartmentNotifyJob < ApplicationJob
queue_as :notify
def perform(department_id, operator_id, user_ids)
department = Department.unscoped.find_by(id: department_id)
return if department.blank? || user_ids.blank?
attrs = %i[ user_id trigger_user_id container_id container_type tiding_type status created_at updated_at]
same_attrs = {
trigger_user_id: operator_id, container_id: department.id, container_type: 'Department',
status: 4, tiding_type: 'System'
}
Tiding.bulk_insert(*attrs) do |worker|
user_ids.each do |user_id|
worker.add same_attrs.merge(user_id: user_id)
end
end
end
end

@ -95,6 +95,14 @@ class Challenge < ApplicationRecord
end
end
def tags_show
if self.challenge_tags.nil?
"--"
else
self.try(:challenge_tags).map(&:name).join(";")
end
end
## 选择题答案
def choose_answer
result = []

@ -2,6 +2,14 @@ class Department < ApplicationRecord
belongs_to :school
has_many :department_members, dependent: :destroy
has_many :member_users, through: :department_members, source: :user
has_many :user_extensions, dependent: :nullify
has_many :apply_add_departments
scope :without_deleted, -> { where(is_delete: false) }
def soft_delete!
update!(is_delete: true)
end
end

@ -16,4 +16,8 @@ class LibraryApply < ApplicationRecord
transitions from: :pending, to: :agreed
end
end
def status_i18n
end
end

@ -78,6 +78,29 @@ class Shixun < ApplicationRecord
shixun_info.try(:evaluate_script)
end
def fork_identifier
self.fork_from.nil? ? "--" : Shixun.where(id: self.fork_from).first.try(:identifier)
end
def shixun_status
status = ""
case self.status
when 0
status = "编辑中"
when 1
status = "审核中"
when 2
status = "已发布"
when 3
status = "已关闭"
end
status
end
def is_tag_used?(id)
tag_repertoires.map(&:id).include?(id)
end
# 实训用户tag
def user_tags_name(user = User.current)
Shixun.joins(challenges: [:challenge_tags, :games]).where(games: {status: 2, user_id: user.id}, shixuns: {id:id})
@ -133,6 +156,10 @@ class Shixun < ApplicationRecord
User.find(self.user_id)
end
def shixun_main_name
self.mirror_repositories.published_main_mirror.first.try(:type_name)
end
def is_published?
status > 1
end

@ -0,0 +1,32 @@
class Admins::DepartmentQuery < ApplicationQuery
include CustomSortable
attr_reader :params
sort_columns :created_at, default_by: :created_at, default_direction: :desc
def initialize(params)
@params = params
end
def call
departments = Department.where(is_auth: true).without_deleted
keyword = params[:keyword].to_s.strip
if keyword.present?
departments = departments.joins(:school)
.where('schools.name LIKE :keyword OR departments.name LIKE :keyword', keyword: keyword)
end
if params[:with_member].to_s == 'true'
subquery = DepartmentMember.where('department_id = departments.id').select('1 AS one').to_sql
departments = departments.where("EXISTS(#{subquery})")
end
if params[:with_identifier].to_s == 'true'
departments = departments.where.not(identifier: nil).where.not(identifier: '')
end
custom_sort(departments, params[:sort_by], params[:sort_direction])
end
end

@ -0,0 +1,29 @@
class Admins::LibraryApplyQuery < ApplicationQuery
include CustomSortable
attr_reader :params
sort_columns :updated_at, default_by: :updated_at, default_direction: :desc
def initialize(params)
@params = params
end
def call
status =
case params[:status]
when 'processed' then %w(agreed refused)
else params[:status]
end
applies = LibraryApply.where(status: status) if status.present?
# 关键字模糊查询
keyword = params[:keyword].to_s.strip
if keyword.present?
applies = applies.joins(:library)
.where('title LIKE :keyword OR uuid LIKE :keyword', keyword: "%#{keyword}%")
end
custom_sort(applies, params[:sort_by], params[:sort_direction])
end
end

@ -0,0 +1,48 @@
class Admins::ShixunQuery < ApplicationQuery
include CustomSortable
attr_reader :params
sort_columns :created_at, default_by: :created_at, default_direction: :desc
def initialize(params)
@params = params
end
def call
all_shixuns = Shixun.all
status =
case params[:status]
when "editing" then [0]
when "pending" then [1]
when "processed" then [2]
when "closed" then [3]
else
[0,1,2,3]
end
all_shixuns = all_shixuns.where(status: status) if status.present?
if params[:tag].present?
all_shixuns = all_shixuns.joins(:mirror_repositories).where("mirror_repositories.id = ?",params[:tag].to_i)
end
# 关键字模糊查询
keyword = params[:keyword].to_s.strip
if keyword.present?
search_type = params[:search_type] || "0"
case search_type
when "0"
all_shixuns = all_shixuns.joins(:user)
.where('CONCAT(lastname, firstname) like :keyword', keyword: "%#{keyword}%")
when "1"
all_shixuns = all_shixuns.where('name like :keyword', keyword: "%#{keyword}%")
else
all_shixuns = all_shixuns.joins(user: {user_extension: :school}).where('schools.name LIKE ?', "%#{keyword}%")
end
end
custom_sort(all_shixuns, params[:sort_by], params[:sort_direction])
end
end

@ -0,0 +1,54 @@
class Admins::ShixunSettingsQuery < ApplicationQuery
include CustomSortable
attr_reader :params
sort_columns :created_at, default_by: :created_at, default_direction: :desc
def initialize(params)
@params = params
end
def call
all_shixuns = Shixun.all
status =
case params[:status]
when "editing" then [0]
when "pending" then [1]
when "processed" then [2]
when "closed" then [3]
else
[0,1,2,3]
end
all_shixuns = all_shixuns.where(status: status) if status.present?
if params[:tag].present?
all_shixuns = all_shixuns.joins(:mirror_repositories).where("mirror_repositories.id = ?",params[:tag].to_i)
end
# 关键字模糊查询
keyword = params[:keyword].to_s.strip
if keyword.present?
search_type = params[:search_type] || "0"
case search_type
when "0"
all_shixuns = all_shixuns.joins(:user)
.where('CONCAT(lastname, firstname) like :keyword', keyword: "%#{keyword}%")
when "1"
all_shixuns = all_shixuns.where('name like :keyword', keyword: "%#{keyword}%")
else
all_shixuns = all_shixuns.joins(user: {user_extension: :school}).where('schools.name LIKE ?', "%#{keyword}%")
end
end
all_shixuns = all_shixuns.where(can_copy: params[:can_copy]) if params[:can_copy]
all_shixuns = all_shixuns.where(webssh: params[:webssh]) if params[:webssh]
all_shixuns = all_shixuns.where(hidden: params[:hidden]) if params[:hidden]
all_shixuns = all_shixuns.where(homepage_show: params[:homepage_show]) if params[:homepage_show]
all_shixuns = all_shixuns.where(task_pass: params[:task_pass]) if params[:task_pass]
all_shixuns = all_shixuns.where(code_hidden: params[:code_hidden]) if params[:code_hidden]
custom_sort(all_shixuns, params[:sort_by], params[:sort_direction])
end
end

@ -28,7 +28,13 @@ class Admins::UserQuery < ApplicationQuery
keyword = params[:keyword].to_s.strip.presence
if keyword
sql = 'CONCAT(lastname, firstname) LIKE :keyword OR login LIKE :keyword OR mail LIKE :keyword OR phone LIKE :keyword'
users = users.where(sql, keyword: keyword)
users = users.where(sql, keyword: "%#{keyword}%")
end
# 姓名
name = params[:name].to_s.strip.presence
if name.present?
users = users.where('CONCAT(lastname, firstname) LIKE :name', name: "%#{name}%")
end
# 学校名称

@ -0,0 +1,20 @@
class Admins::AddDepartmentMemberService < ApplicationService
attr_reader :department, :params
def initialize(department, params)
@department = department
@params = params
end
def call
columns = %i[]
DepartmentMember.bulk_insert(*columns) do |worker|
Array.wrap(params[:user_ids]).compact.each do |user_id|
next if department.department_members.exists?(user_id: user_id)
worker.add(department_id: department.id, user_id: user_id)
end
end
end
end

@ -5,7 +5,7 @@
<div class="box search-form-container daily-school-statistic-list-form">
<%= form_tag(admins_daily_school_statistics_path, method: :get, class: 'form-inline search-form', remote: true) do %>
<%= text_field_tag(:keyword, params[:keyword], class: 'form-control col-sm-2 ml-3', placeholder: 'ID/单位名称搜索') %>
<%= submit_tag('搜索', class: 'btn btn-primary ml-3') %>
<%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %>
<% end %>
<%#= link_to '导出Excel', export_admins_daily_school_statistics_path(format: :xlsx), class: 'btn btn-outline-primary export-action' %>

@ -0,0 +1,4 @@
$('.modal.admin-add-department-member-modal').modal('hide');
$.notify({ message: '操作成功' });
$('.department-list-table .department-item-<%= current_department.id %>').html("<%= j(render partial: 'admins/departments/shared/department_item', locals: { department: current_department }) %>")

@ -0,0 +1,2 @@
$.notify({ message: '操作成功' });
$('.department-list-container .department-item-<%= current_department.id %> .member-user-item-<%= @member.user_id %>').remove();

@ -0,0 +1,2 @@
$('.admin-modal-container').html("<%= j( render partial: 'admins/departments/shared/edit_department_modal', locals: { department: current_department } ) %>");
$('.modal.admin-edit-department-modal').modal('show');

@ -0,0 +1,33 @@
<% define_admin_breadcrumbs do %>
<% add_admin_breadcrumb('部门列表') %>
<% end %>
<div class="box search-form-container department-list-form">
<%= form_tag(admins_departments_path, method: :get, class: 'form-inline search-form flex-1', remote: true) do %>
<div class="form-check mr-3">
<%= hidden_field_tag(:with_member, false) %>
<%= check_box_tag(:with_member, true, params[:with_member].to_s == 'true', class: 'form-check-input') %>
<label class="form-check-label" for="with_member">有部门管理员</label>
</div>
<div class="form-check mr-3">
<%= hidden_field_tag(:with_identifier, false) %>
<%= check_box_tag(:with_identifier, true, params[:with_identifier].to_s == 'true', class: 'form-check-input') %>
<label class="form-check-label" for="with_member">有统计链接</label>
</div>
<%= text_field_tag(:keyword, params[:keyword], class: 'form-control col-sm-2 ml-3', placeholder: '部门/单位名称检索') %>
<%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %>
<% end %>
<%= javascript_void_link '新建部门', class: 'btn btn-primary', data: { toggle: 'modal', target: '.admin-create-department-modal' } %>
</div>
<div class="box department-list-container">
<%= render partial: 'admins/departments/shared/list',
locals: { departments: @departments, users_count: @users_count, professional_auth_count: @professional_auth_count } %>
</div>
<%= render 'admins/departments/shared/create_department_modal' %>
<%= render 'admins/departments/shared/add_department_member_modal' %>
<%= render 'admins/departments/shared/merge_department_modal' %>

@ -0,0 +1 @@
$('.department-list-container').html("<%= j(render partial: 'admins/departments/shared/list', locals: { departments: @departments, users_count: @users_count, professional_auth_count: @professional_auth_count }) %>");

@ -0,0 +1,30 @@
<div class="modal fade admin-add-department-member-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-add-department-member-form">
<%= hidden_field_tag(:department_id, nil) %>
<div class="form-group d-flex">
<label for="school_id" class="col-form-label">部门管理员:</label>
<div class="d-flex flex-column-reverse w-75">
<select id="user_ids" name="user_ids" class="form-control department-member-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>

@ -0,0 +1,35 @@
<div class="modal fade admin-create-department-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-create-department-form" data-url="<%= admins_departments_path %>">
<div class="form-group d-flex">
<label for="school_id" class="col-form-label">所属单位:</label>
<div class="d-flex flex-column-reverse w-75">
<select id="school_id" name="school_id" class="form-control school-select"></select>
</div>
</div>
<div class="form-group d-flex">
<label for="new_mirror_id" class="col-form-label">部门名称:</label>
<div class="w-75 d-flex flex-column">
<%= text_field_tag(:department_name, nil, class: 'form-control', placeholder: '请输入部门名称') %>
</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>

@ -0,0 +1,28 @@
<% not_list = defined?(:users_count) %>
<td class="text-left"><%= overflow_hidden_span department.name, width: 150 %></td>
<td class="text-left"><%= overflow_hidden_span department.school.name, width: 150 %></td>
<% if not_list %>
<td><%= department.user_extensions.count %></td>
<td><%= department.user_extensions.joins(:user).where(users: { professional_certification: true }).count %></td>
<% else %>
<td><%= users_count.fetch(department.id, 0) %></td>
<td><%= professional_auth_count.fetch(department.id, 0) %></td>
<% end %>
<td class="member-container">
<%= render partial: 'admins/departments/shared/member_users', locals: { department: department } %>
</td>
<td><%= link_to department.identifier.to_s, '#', target: '_blank' %></td>
<td><%= department.host_count %></td>
<td><%= department.created_at&.strftime('%Y-%m-%d %H:%M') %></td>
<td class="action-container">
<%= link_to '编辑', edit_admins_department_path(department), remote: true, class: 'action' %>
<%= javascript_void_link '添加管理员', class: 'action', data: { department_id: department.id, toggle: 'modal', target: '.admin-add-department-member-modal' } %>
<%= javascript_void_link '更改', class: 'action', data: { school_id: department.school_id, department_id: department.id, toggle: 'modal', target: '.admin-merge-department-modal' } %>
<%= delete_link '删除', admins_department_path(department, element: ".department-item-#{department.id}"), class: 'delete-department-action' %>
</td>

@ -0,0 +1,25 @@
<div class="modal fade admin-edit-department-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">
<%= simple_form_for([:admins, department], html: { class: 'admin-edit-department-form' }, defaults: { wrapper_html: { class: 'offset-md-1 col-md-10' } }) do |f| %>
<%= f.input :name, as: :string, label: '名称' %>
<%= f.input :identifier, as: :string, label: '统计链接' %>
<%= f.input :host_count, as: :integer, label: '云主机数' %>
<div class="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,28 @@
<table class="table table-hover text-center department-list-table">
<thead class="thead-light">
<tr>
<th width="14%" class="text-left">部门名称</th>
<th width="14%" class="text-left">单位名称</th>
<th width="6%">用户数</th>
<th width="10%">已职业认证</th>
<th width="20%">部门管理员</th>
<th width="8%">统计链接</th>
<th width="8%">云主机数</th>
<th width="10%"><%= sort_tag('创建时间', name: 'created_at', path: admins_departments_path) %></th>
<th width="14%">操作</th>
</tr>
</thead>
<tbody>
<% if departments.present? %>
<% departments.each do |department| %>
<tr class="department-item-<%= department.id %>">
<%= render 'admins/departments/shared/department_item', department: department %>
</tr>
<% end %>
<% else %>
<%= render 'admins/shared/no_data_for_table' %>
<% end %>
</tbody>
</table>
<%= render partial: 'admins/shared/paginate', locals: { objects: departments } %>

@ -0,0 +1,12 @@
<div class="member-user">
<% department.member_users.each do |user| %>
<span class="member-user-item member-user-item-<%= user.id %>">
<%= link_to user.real_name, "/users/#{user.login}", target: '_blank', data: { toggle: 'tooltip', title: '个人主页' } %>
<%= link_to(admins_department_department_member_path(department, user_id: user.id),
method: :delete, remote: true, class: 'ml-1 delete-member-action',
data: { confirm: '确认删除吗?' }) do %>
<i class="fa fa-close"></i>
<% end %>
</span>
<% end %>
</div>

@ -0,0 +1,31 @@
<div class="modal fade admin-merge-department-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-merge-department-form" data-url="<%= merge_admins_departments_path %>">
<%= hidden_field_tag(:school_id, nil) %>
<%= hidden_field_tag(:origin_department_id, nil) %>
<div class="form-group d-flex">
<label for="school_id" class="col-form-label">更改为:</label>
<div class="d-flex flex-column-reverse w-75">
<select id="department_id" name="department_id" class="form-control department-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>

@ -0,0 +1,4 @@
$('.modal.admin-edit-department-modal').modal('hide');
$.notify({ message: '操作成功' });
$('.department-list-table .department-item-<%= current_department.id %>').html("<%= j(render partial: 'admins/departments/shared/department_item', locals: { department: current_department }) %>")

@ -21,7 +21,7 @@
<%= select_tag(:status, options_for_select(status_options), class: 'form-control') %>
</div>
<%= text_field_tag(:keyword, params[:keyword], class: 'form-control col-sm-2 ml-3', placeholder: '姓名/学校/单位检索') %>
<%= submit_tag('搜索', class: 'btn btn-primary ml-3') %>
<%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %>
<% end %>
</div>

@ -0,0 +1,32 @@
<% define_admin_breadcrumbs do %>
<% add_admin_breadcrumb('教学案例发布') %>
<% end %>
<div class="box search-form-container flex-column mb-0 pb-0 library-applies-list-form">
<ul class="nav nav-tabs w-100 search-form-tabs">
<li class="nav-item">
<%= link_to '待审批', admins_library_applies_path(status: :pending), remote: true, 'data-value': 'pending',
class: "nav-link search-form-tab #{params[:status] == 'pending' ? 'active' : ''}" %>
</li>
<li class="nav-item">
<%= link_to '已审批', admins_library_applies_path(status: :processed), remote: true, 'data-value': 'processed',
class: "nav-link search-form-tab #{params[:status] != 'pending' ? 'active' : ''}" %>
</li>
</ul>
<%= form_tag(admins_library_applies_path(unsafe_params), method: :get, class: 'form-inline search-form justify-content-end mt-3', remote: true) do %>
<div class="form-group status-filter" style="<%= params[:status] != 'pending' ? '' : 'display: none;' %>">
<label for="status">审核状态:</label>
<% status_options = [['全部', 'processed'], ['已同意', 'agreed'], ['已拒绝', 'refused']] %>
<%= select_tag(:status, options_for_select(status_options) ,class: 'form-control') %>
</div>
<%= text_field_tag(:keyword, params[:keyword], class: 'form-control col-sm-2 ml-3', placeholder: '编号/名称检索') %>
<%= submit_tag('搜索', class: 'btn btn-primary ml-3') %>
<% end %>
</div>
<div class="box library-applies-list-container">
<%= render(partial: 'admins/library_applies/shared/list', locals: { applies: @library_applies }) %>
</div>
<%= render(partial: 'admins/shared/admin_common_refuse_modal') %>

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

@ -0,0 +1,56 @@
<% is_processed = params[:status].to_s != 'pending' %>
<table class="table table-hover text-center library_applies-list-table">
<thead class="thead-light">
<tr>
<th width="8%">头像</th>
<th width="14%">姓名</th>
<th width="26%" class="text-left">教学案例</th>
<th width="26%" class="text-left">案例描述</th>
<th width="16%">时间</th>
<% if is_processed %>
<th width="16%">拒绝原因</th>
<th width="8%">状态</th>
<% else %>
<th width="20%">操作</th>
<% end %>
</tr>
</thead>
<tbody>
<% if applies.present? %>
<% applies.each do |apply| %>
<% user = apply.library.user %>
<% library = apply.library %>
<tr class="library_applies-item library_applies-<%= apply.id %>">
<td>
<%= link_to "/users/#{user.login}", class: 'professional-authentication-avatar', target: '_blank', data: { toggle: 'tooltip', title: '个人主页' } do %>
<img src="/images/<%= url_to_avatar(user) %>" class="rounded-circle" width="40" height="40" />
<% end %>
</td>
<td><%= user.real_name %></td>
<td class="text-left"><%= link_to library.title, library_path(library), :target => "_blank" %></td>
<td class="text-left"><%= overflow_hidden_span library.content[0..50] + "..."%></td>
<td><%= apply.updated_at.strftime('%Y-%m-%d %H:%M') %></td>
<% if is_processed %>
<td class="text-secondary"><%= overflow_hidden_span apply.reason %></td>
<td><span class="apply-status-<%= apply.status %>"><%= t("library_apply.status.#{apply.status}") %></span></td>
<% else %>
<td class="action-container">
<%= agree_link '同意', agree_admins_library_apply_path(apply, element: ".library_applies-#{apply.id}"), 'data-confirm': '确认审核通过?' %>
<%= javascript_void_link('拒绝', class: 'action refuse-action',
data: {
toggle: 'modal', target: '.admin-common-refuse-modal', id: apply.id,
url: refuse_admins_library_apply_path(apply, element: ".library_applies-#{apply.id}")
}) %>
</td>
<% end %>
</tr>
<% end %>
<% else %>
<%= render 'admins/shared/no_data_for_table' %>
<% end %>
</tbody>
</table>
<%= render partial: 'admins/shared/paginate', locals: { objects: applies } %>

@ -21,7 +21,7 @@
<%= select_tag(:status, options_for_select(status_options), class: 'form-control') %>
</div>
<%= text_field_tag(:keyword, params[:keyword], class: 'form-control col-sm-2 ml-3', placeholder: '姓名/学校/单位检索') %>
<%= submit_tag('搜索', class: 'btn btn-primary ml-3') %>
<%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %>
<% end %>
</div>

@ -22,10 +22,18 @@
<li>
<%= sidebar_item_group('#shixun-submenu', '实训管理', icon: 'window-restore') do %>
<li><%= sidebar_item(admins_shixuns_path, '实训列表', icon: 'jsfiddle', controller: 'admins-shixuns') %></li>
<li><%= sidebar_item(admins_shixun_settings_path, '实训配置', icon: 'cog', controller: 'admins-shixun_settings') %></li>
<li><%= sidebar_item(admins_mirror_repositories_path, '镜像管理', icon: 'cubes', controller: 'admins-mirror_repositories') %></li>
<% end %>
</li>
<li>
<%= sidebar_item_group('#schools-submenu', '单位管理', icon: 'building') do %>
<li><%= sidebar_item(admins_departments_path, '部门列表', icon: 'sitemap', controller: 'admins-departments') %></li>
<% end %>
</li>
<!-- <li>-->
<%#= sidebar_item_group('#course-submenu', '课堂+', icon: 'mortar-board') do %>
<!-- <li><%#= sidebar_item('#', '课程列表', icon: 'calendar', controller: '') %></li>-->
@ -48,7 +56,8 @@
<li><%= sidebar_item(admins_identity_authentications_path, '实名认证', icon: 'id-card-o', controller: 'admins-identity_authentications') %></li>
<li><%= sidebar_item(admins_professional_authentications_path, '职业认证', icon: 'drivers-license', controller: 'admins-professional_authentications') %></li>
<li><%= sidebar_item(admins_shixun_authorizations_path, '实训发布', icon: 'object-ungroup', controller: 'admins-shixun_authorizations') %></li>
<li><%= sidebar_item(admins_subject_authorizations_path, '实践课程发布', icon: 'object-group', controller: 'admins-subject_authorizations') %></li>
<li><%= sidebar_item(admins_subject_authorizations_path, '实践课程发布', icon: 'object-group', controller: 'admins-subject_authorizations') %></li>
<li><%= sidebar_item(admins_library_applies_path, '教学案例发布', icon: 'language', controller: 'admins-library_applies') %></li>
<% end %>
</li>

@ -21,7 +21,7 @@
<%= select_tag(:status, options_for_select(status_options), class: 'form-control') %>
</div>
<%= text_field_tag(:keyword, params[:keyword], class: 'form-control col-sm-2 ml-3', placeholder: '实训名称检索') %>
<%= submit_tag('搜索', class: 'btn btn-primary ml-3') %>
<%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %>
<% end %>
</div>

@ -0,0 +1,76 @@
<% define_admin_breadcrumbs do %>
<% add_admin_breadcrumb('实训配置', admins_shixun_settings_path) %>
<% end %>
<div class="box search-form-container shixun-settings-list-form">
<%= form_tag(admins_shixun_settings_path, method: :get, class: 'form-inline search-form', remote: true) do %>
<div class="d-flex flex-column w-100">
<div class="d-flex position-r">
<div class="form-group mr-2">
<label for="status">状态:</label>
<% status_options = [['全部', ''], ["编辑中(#{@editing_shixuns})", "editing"], ["待审核(#{@pending_shixuns})", 'pending'], ["已发布(#{@processed_shixuns})", 'processed'],["已关闭(#{@closed_shixuns})",'closed']] %>
<%= select_tag(:status, options_for_select(status_options), class: 'form-control') %>
</div>
<div class="form-group mr-2">
<label for="tag-choosed">技术平台:</label>
<%= select_tag(:tag, options_for_select(@shixuns_type_check.unshift(["",nil])), class: 'form-control',id:"tag-choosed") %>
</div>
<div class="form-group mr-2">
<label>搜索类型:</label>
<% auto_trial_options = [['创建者姓名', 0], ['实训名称', 1], ['学校名称', 2]] %>
<%= select_tag(:search_type, options_for_select(auto_trial_options), class: 'form-control') %>
</div>
<%= text_field_tag(:keyword, params[:keyword], class: 'form-control col-sm-2 ml-3', placeholder: '输入关键字搜索') %>
<%= submit_tag('搜索', class: 'btn btn-primary ml-3') %>
<%= link_to "清除",admins_shixun_settings_path(status:nil,tag:nil,search_type:nil,keyword:nil),class: "btn btn-default" %>
<div class="">
<a href="<%= admins_shixun_settings_path( :format => "xls") %>" class="btn btn-primary export-absolute" id="shixun_xls">导出</a>
</div>
</div>
<div class="d-flex mt-3">
<div class="mr-5">
<label for="can_copy">
<%= check_box_tag :can_copy,true,false,remote:true,class:"shixun-settings-select" %>
<span class="only_view">只看可复制</span>
</label>
</div>
<div class="mr-5">
<label for="webssh">
<%= check_box_tag :webssh,1,false,remote:true, class:"shixun-settings-select" %>
<span class="only_view">只看可ssh</span>
</label>
</div>
<div class="mr-5">
<label for="hidden">
<%= check_box_tag :hidden,true,false,remote:true, class:"shixun-settings-select" %>
<span class="only_view">只看已隐藏</span>
</label>
</div>
<div class="mr-5">
<label for="homepage_show">
<%= check_box_tag :homepage_show,true,false,remote:true, class:"shixun-settings-select" %>
<span class="only_view">只看首页显示</span>
</label>
</div>
<div class="mr-5">
<label for="task_pass">
<%= check_box_tag :task_pass, true, false, remote:true, class:"shixun-settings-select" %>
<span class="only_view">只看可跳关</span>
</label>
</div>
<div class="mr-5">
<label for="code_hidden">
<%= check_box_tag :code_hidden, true, false, remote:true, class:"shixun-settings-select" %>
<span class="only_view">只看已隐藏文件目录</span>
</label>
</div>
</div>
</div>
<% end %>
</div>
<div class="box shixun-settings-list-container">
<%= render partial: 'admins/shixun_settings/shared/list', locals: { shixun_settings: @shixun_settings } %>
</div>

@ -0,0 +1 @@
$(".shixun-settings-list-container").html("<%= j render partial: "admins/shixun_settings/shared/list",locals: {shixun_settings:@shixun_settings} %>")

@ -0,0 +1,31 @@
<table class="table text-center shixun-settings-list-table">
<thead>
<th width="4%">序号</th>
<th width="8%">ID</th>
<th width="12%" class="text-left">实训名称</th>
<th width="8%">技术平台</th>
<th width="8%">权限</th>
<th width="15%">技术体系</th>
<th width="12%">上传图片</th>
<th width="5%">创建者</th>
<th width="5%">关闭</th>
<th width="4%">复制</th>
<th width="7%">代码执行时间</th>
<th>
操作
<div class="setting-chosen">
ssh/隐藏/首页/跳关/隐藏目录
</div>
</th>
</thead>
<tbody>
<% shixun_settings.each_with_index do |shixun,index| %>
<tr id="setting-item-<%= shixun.id %>">
<% page_no = (@params_page.to_i - 1) * 20 + index + 1 %>
<%= render partial: "admins/shixun_settings/shared/td",locals: {shixun: shixun,page_no:page_no} %>
</tr>
<% end %>
</tbody>
</table>
<%= render partial: 'admins/shared/paginate', locals: { objects: shixun_settings } %>

@ -0,0 +1,58 @@
<td class="shixun-line-no"><%= page_no %></td>
<td><%= shixun.identifier %></td>
<td class="text-left">
<span>
<%= link_to overflow_hidden_span(shixun.name,width:160), "/shixuns/#{shixun.identifier}", :target => "_blank", :title => shixun.name %>
</span>
</td>
<td>
<%= display_text shixun.shixun_main_name %>
</td>
<td>
<% status_options = [['超级管理员', '0'], ["合作团队", "1"]] %>
<%= select_tag(:use_scope, options_for_select(status_options,shixun.use_scope),class:"form-control shixun-setting-form",data:{id:shixun.id}) %>
</td>
<td>
<%= select_tag(:tag_repertoires, options_for_select(@shixun_tags,shixun.tag_repertoires.pluck(:id)),multiple:true,class:"form-control shixun-setting-form",data:{id:shixun.id},id:"tags-chosen-#{shixun.id}") %>
</td>
<td>
<!-- 图片上传,稍后添加-->
<a href="javascript:void(0);" id="object_upload_img_<%= shixun.id %>" onclick="$('#upload_img_<%= shixun.id %>').click();">
<%= File.exist?(disk_filename("Shixun",shixun.id)) ? "重新上传" : "上传图片" %>
</a>
<% if File.exist?(disk_filename("Shixun",shixun.id)) %>
<%= image_tag(url_to_avatar(shixun), :class => "w80 h80 fl ml5 shixun_image_show", :id => "shixun_image_show_#{shixun.id}") %>
<% else %>
<img src="" class="w80 h80 fl ml5 shixun_image_show none" id="shixun_image_show_<%= shixun.id %>"/>
<% end %>
</td>
<td><%= link_to shixun.owner.try(:show_real_name),"/users/#{shixun.owner.login}",target:'_blank' %></td>
<td>
<% if shixun.status.to_i < 3 %>
<%= link_to "关闭", admins_shixun_setting_path(shixun,status:3,page_no:page_no),method: :put, :class => "", :remote => true %>
<% else %>
<span>已关闭</span>
<% end %>
</td>
<td>
<%= check_box_tag :can_copy,!shixun.can_copy,shixun.can_copy,remote:true,data:{id:shixun.id},class:"shixun-setting-form" %>
</td>
<td>
<input name="excute_time" value="<%= shixun.excute_time %>" class="form-control shixun-setting-form" data-id="<%= shixun.id %>">
</td>
<td class="operate">
<%= check_box_tag :webssh,(shixun.webssh == 1 ? 0 : 1),(shixun.webssh == 1 ? true : false),remote:true,data:{id:shixun.id,toggle:"tooltip",placement:"top"},class:"shixun-setting-form",title:"ssh" %>
<%= check_box_tag :hidden,!shixun.hidden,shixun.hidden,remote:true,data:{id:shixun.id,toggle:"tooltip",placement:"top"},class:"shixun-setting-form" ,title:"隐藏"%>
<%= check_box_tag :homepage_show,!shixun.homepage_show,shixun.homepage_show,remote:true,data:{id:shixun.id,toggle:"tooltip",placement:"top"},class:"shixun-setting-form",title:"首页" %>
<%= check_box_tag :task_pass,!shixun.task_pass,shixun.task_pass,remote:true,data:{id:shixun.id,toggle:"tooltip",placement:"top"},class:"shixun-setting-form" ,title:"跳关"%>
<%= check_box_tag :code_hidden,!shixun.code_hidden,shixun.code_hidden,remote:true,data:{id:shixun.id,toggle:"tooltip",placement:"top"},class:"shixun-setting-form" ,title:"隐藏目录"%>
</td>
<script>
$("#tags-chosen-<%= shixun.id %>").select2({
multiple: true,
maximumSelectionLength: 3,
placeholder: '请选择技术体系'});
</script>

@ -0,0 +1 @@
$("#setting-item-<%= @shixun.id %>").html("<%= j render partial: "admins/shixun_settings/shared/td",locals: {shixun: @shixun,page_no:@page_no} %>")

@ -0,0 +1,33 @@
<% define_admin_breadcrumbs do %>
<% add_admin_breadcrumb('实训列表', admins_shixuns_path) %>
<% end %>
<div class="box search-form-container shixuns-list-form">
<%= form_tag(admins_shixuns_path, method: :get, class: 'form-inline search-form', remote: true) do %>
<div class="form-group mr-2">
<label for="status">状态:</label>
<% status_options = [['全部', ''], ["编辑中(#{@editing_shixuns})", "editing"], ["待审核(#{@pending_shixuns})", 'pending'], ["已发布(#{@processed_shixuns})", 'processed'],["已关闭(#{@closed_shixuns})",'closed']] %>
<%= select_tag(:status, options_for_select(status_options), class: 'form-control') %>
</div>
<div class="form-group mr-2">
<label for="tag-choosed">技术平台:</label>
<%= select_tag(:tag, options_for_select(@shixuns_type_check.unshift(["",nil])), class: 'form-control',id:"tag-choosed") %>
</div>
<div class="form-group ml-3">
<label>搜索类型:</label>
<% auto_trial_options = [['创建者姓名', 0], ['实训名称', 1], ['学校名称', 2]] %>
<%= select_tag(:search_type, options_for_select(auto_trial_options), class: 'form-control') %>
</div>
<%= text_field_tag(:keyword, params[:keyword], class: 'form-control col-sm-2 ml-3', placeholder: '输入关键字搜索') %>
<%= submit_tag('搜索', class: 'btn btn-primary ml-3') %>
<%= link_to "清除",admins_shixuns_path(status:nil,tag:nil,search_type:nil,keyword:nil),class: "btn btn-default" %>
<% end %>
<a href="<%= admins_shixuns_path( :format => "xls") %>" class="btn btn-primary" id="shixun_xls">导出</a>
</div>
<div class="box shixuns-list-container">
<%= render partial: 'admins/shixuns/shared/list', locals: { shixuns: @shixuns } %>
</div>

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

@ -0,0 +1,51 @@
<table class="table table-hover text-center shixuns-list-table">
<thead class="thead-light">
<th width="4%">序号</th>
<th width="8%">ID</th>
<th width="28%" class="text-left">实训名称</th>
<th width="8%">技术平台</th>
<th width="5%">Fork源</th>
<th width="5%">实践</th>
<th width="5%">选择</th>
<th width="6%">状态</th>
<th width="7%">创建者</th>
<th class="eud-pointer" width="13%"><%= sort_tag('创建于', name: 'created_at', path: admins_shixuns_path) %></th>
<th width="5%">单测</th>
<th width="6%">操作</th>
</thead>
<tbody>
<% shixuns.each_with_index do |shixun,index| %>
<tr>
<td><%= (@params_page.to_i - 1) * 20 + index + 1%></td>
<td><%= shixun.identifier %></td>
<td class="text-left"><span><%= link_to overflow_hidden_span(shixun.name), "/shixuns/#{shixun.identifier}", :target => "_blank", :title => shixun.name %></span></td>
<td>
<%= shixun.shixun_main_name.nil? ? "--" : shixun.shixun_main_name %>
</td>
<td>
<% if shixun.try(:fork_from).nil? %>
--
<% else%>
<%= link_to shixun.try(:identifier), shixun_path(shixun.try(:identifier)), target: '_blank'%>
<% end%>
</td>
<td><%= shixun.challenges.where(:st => 0).size %></td>
<td><%= shixun.challenges.where(:st => 1).size %></td>
<td class="shixuns-status-<%= shixun.status %>"><%= shixun_authentication_status shixun %></td>
<td><%= link_to shixun.owner.try(:show_real_name),"/users/#{shixun.owner.try(:login)}",target:'_blank' %></td>
<td><%= format_time shixun.created_at %></td>
<td class="homepage_teacher">
<input type="checkbox" name="sigle_show" value="<%= shixun.id %>" <%= shixun.sigle_training ? "checked" : "" %> class="ml-3 mr5 magic-checkbox" id="join_teacher_homepage_<%= shixun.id %>">
<label style="top:-14px;" class="ml20" for="join_teacher_homepage_<%= shixun.id %>"></label>
</td>
<td class="operate">
<% if shixun.status == 0 %>
<%= link_to(l(:button_delete), admins_shixun_path(shixun), :method => :delete, :data => { confirm: "您确定要删除吗?" } ) %>
<% end %>
</td>
</tr>
<% end %>
</tbody>
</table>
<%= render partial: 'admins/shared/paginate', locals: { objects: shixuns } %>

@ -21,7 +21,7 @@
<%= select_tag(:status, options_for_select(status_options), class: 'form-control') %>
</div>
<%= text_field_tag(:keyword, params[:keyword], class: 'form-control col-sm-2 ml-3', placeholder: '实训课程名称检索') %>
<%= submit_tag('搜索', class: 'btn btn-primary ml-3') %>
<%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %>
<% end %>
</div>

@ -24,7 +24,7 @@
<%= text_field_tag(:keyword, params[:keyword], class: 'form-control col-sm-2 ml-3', placeholder: 'ID/姓名/邮箱/手机号检索') %>
<%= text_field_tag(:school_name, params[:school_name], class: 'form-control col-sm-2', placeholder: '学校/单位检索') %>
<%= submit_tag('搜索', class: 'btn btn-primary ml-3') %>
<%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %>
<% end %>
</div>

@ -0,0 +1,6 @@
json.count @users.total_count
json.users do
json.array! @users.each do |user|
json.extract! user, :id, :login, :real_name, :identity, :school_name
end
end

@ -2,7 +2,7 @@
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLongTitle">奖励金币</h5>
<h5 class="modal-title">奖励金币</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>

@ -9,6 +9,7 @@ json.question_type question.question_type
json.question_score question.question_score.round(1).to_s
if question.question_type <= 2 #当为选择题或判断题时,只显示选项的位置
standard_answers_array = question.get_standard_answer_ids
ex_choice_random_boolean = (exercise_type.present? && exercise_type == 3 && (question.exercise.choice_random)) ? true : false #问题的选项随机打乱
if ex_choice_random_boolean
exercise_choices = choices.order("RAND()")

@ -0,0 +1,7 @@
zh-CN:
library_apply:
status:
'pending': '待审批'
'processed': '已审批'
'refused': '已拒绝'
'agreed': '已同意'

@ -1,5 +1,9 @@
'zh-CN':
zh-CN:
error:
record_not_found: 您访问的页面不存在或已被删除
forbidden: 您没有权限进行该操作
unauthorized: 未登录
unauthorized: 未登录
button_test: 测试
button_edit: 编辑
button_delete: 删除

@ -792,6 +792,12 @@ Rails.application.routes.draw do
end
end
resources :library_applies, only: [:index] do
member do
post :agree
post :refuse
end
end
resources :identity_authentications, only: [:index] do
member do
post :agree
@ -816,6 +822,14 @@ Rails.application.routes.draw do
post :refuse
end
end
resources :project_package_applies, only: [:index] do
member do
post :agree
post :refuse
end
end
resources :shixuns, only: [:index,:destroy]
resources :shixun_settings, only: [:index,:update]
resources :mirror_repositories, only: [:index, :new, :create, :edit, :update, :destroy] do
collection do
post :merge
@ -825,6 +839,11 @@ Rails.application.routes.draw do
resources :mirror_scripts, only: [:index, :new, :create, :edit, :update, :destroy]
end
resources :choose_mirror_repositories, only: [:new, :create]
resources :departments, only: [:index, :create, :edit, :update, :destroy] do
resource :department_member, only: [:create, :update, :destroy]
post :merge, on: :collection
end
end
#git 认证回调

File diff suppressed because one or more lines are too long

@ -37635,6 +37635,179 @@ $(document).on('turbolinks:load', function(){
}
})
;
$(document).on('turbolinks:load', function() {
if ($('body.admins-departments-index-page').length > 0) {
var $searchContainer = $('.department-list-form');
var $searchForm = $searchContainer.find('form.search-form');
var $list = $('.department-list-container');
$searchContainer.on('change', '.form-check-input', function(){
$searchForm.find('input[type="submit"]').trigger('click');
});
// ============== 新建部门 ===============
var $modal = $('.modal.admin-create-department-modal');
var $form = $modal.find('form.admin-create-department-form');
var $departmentNameInput = $form.find('input[name="department_name"]');
var $schoolSelect = $modal.find('.school-select');
$form.validate({
errorElement: 'span',
errorClass: 'danger text-danger',
rules: {
school_id: {
required: true
},
department_name: {
required: true
}
},
messages: {
school_id: {
required: '请选择所属单位'
}
}
});
// modal ready fire
$modal.on('show.bs.modal', function () {
$departmentNameInput.val('');
$schoolSelect.select2('val', ' ');
});
// ************** 学校选择 *************
var matcherFunc = function(params, data){
if ($.trim(params.term) === '') {
return data;
}
if (typeof data.text === 'undefined') {
return null;
}
if (data.name && data.name.indexOf(params.term) > -1) {
var modifiedData = $.extend({}, data, true);
return modifiedData;
}
// Return `null` if the term should not be displayed
return null;
};
var defineSchoolSelect = function(schools) {
$schoolSelect.select2({
theme: 'bootstrap4',
placeholder: '请选择所属单位',
minimumInputLength: 1,
data: schools,
templateResult: function (item) {
if(!item.id || item.id === '') return item.text;
return item.name;
},
templateSelection: function(item){
if (item.id) {
$('#school_id').val(item.id);
}
return item.name || item.text;
},
matcher: matcherFunc
});
}
$.ajax({
url: '/api/schools/for_option.json',
dataType: 'json',
type: 'GET',
success: function(data) {
defineSchoolSelect(data.schools);
}
});
$modal.on('click', '.submit-btn', function(){
$form.find('.error').html('');
if ($form.valid()) {
var url = $form.data('url');
$.ajax({
method: 'POST',
dataType: 'json',
url: url,
data: $form.serialize(),
success: function(){
$.notify({ message: '创建成功' });
$modal.modal('hide');
setTimeout(function(){
window.location.reload();
}, 500);
},
error: function(res){
var data = res.responseJSON;
$form.find('.error').html(data.message);
}
});
}
});
// ============= 添加部门管理员 ==============
var $addMemberModal = $('.admin-add-department-member-modal');
var $addMemberForm = $addMemberModal.find('.admin-add-department-member-form');
var $memberSelect = $addMemberModal.find('.department-member-select');
var $departmentIdInput = $addMemberForm.find('input[name="department_id"]')
$addMemberModal.on('show.bs.modal', function(event){
var $link = $(event.relatedTarget);
var departmentId = $link.data('department-id');
$departmentIdInput.val(departmentId);
$memberSelect.select2('val', ' ');
});
$memberSelect.select2({
theme: 'bootstrap4',
placeholder: '请输入要添加的管理员姓名',
multiple: true,
minimumInputLength: 1,
ajax: {
delay: 500,
url: '/admins/users',
dataType: 'json',
data: function(params){
return { name: params.term };
},
processResults: function(data){
return { results: data.users }
}
},
templateResult: function (item) {
if(!item.id || item.id === '') return item.text;
return item.real_name;
},
templateSelection: function(item){
if (item.id) {
}
return item.real_name || item.text;
}
});
$addMemberModal.on('click', '.submit-btn', function(){
$addMemberForm.find('.error').html('');
var departmentId = $departmentIdInput.val();
var memberIds = $memberSelect.val();
if (departmentId && memberIds && memberIds.length > 0) {
$.ajax({
method: 'POST',
dataType: 'script',
url: '/admins/departments/' + departmentId + '/department_member',
data: { user_ids: memberIds }
});
} else {
$addMemberModal.modal('hide');
}
});
}
});
$(document).on('turbolinks:load', function() {
if ($('body.admins-identity-authentications-index-page').length > 0) {
var $searchFrom = $('.identity-authentication-list-form');
@ -37656,6 +37829,28 @@ $(document).on('turbolinks:load', function() {
}
})
;
$(document).on('turbolinks:load', function() {
if ($('body.admins-library-applies-index-page').length > 0) {
var $searchFrom = $('.library-applies-list-form');
$searchFrom.find('select[name="status"]').val('pending');
$searchFrom.on('click', '.search-form-tab', function(){
var $link = $(this);
$searchFrom.find('input[name="keyword"]').val('');
$searchFrom.find('select[name="status"]').val('processed');
if($link.data('value') === 'processed'){
$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');
@ -37744,6 +37939,150 @@ $(document).on('turbolinks:load', function() {
});
})
});
$(document).on('turbolinks:load', function() {
$('.admin-modal-container').on('show.bs.modal', '.modal.admin-edit-department-modal', function(){
var $modal = $('.modal.admin-edit-department-modal');
var $form = $modal.find('form.admin-edit-department-form');
$form.validate({
errorElement: 'span',
errorClass: 'danger text-danger',
rules: {
'department[name]': {
required: true,
maxlength: 20
},
'department[host_count]': {
digits: true
}
}
});
$modal.on('click', '.submit-btn', function(){
$form.find('.error').html('');
var url = $form.attr('action');
if ($form.valid()) {
$.ajax({
method: 'PATCH',
dataType: 'script',
url: url,
data: $form.serialize()
});
}
});
})
});
$(document).on('turbolinks:load', function() {
var $modal = $('.modal.admin-merge-department-modal');
if ($modal.length > 0) {
var $form = $modal.find('form.admin-merge-department-form');
var $schoolIdInput = $form.find('input[name="school_id"]');
var $originDepartmentIdInput = $form.find('input[name="origin_department_id"]');
var $departmentSelect = $modal.find('.department-select');
$form.validate({
errorElement: 'span',
errorClass: 'danger text-danger',
rules: {
department_id: {
required: true
}
},
messages: {
department_id: {
required: '请选择部门'
}
}
});
// ************** 学校选择 *************
var matcherFunc = function(params, data){
if ($.trim(params.term) === '') {
return data;
}
if (typeof data.text === 'undefined') {
return null;
}
if (data.name && data.name.indexOf(params.term) > -1) {
var modifiedData = $.extend({}, data, true);
return modifiedData;
}
// Return `null` if the term should not be displayed
return null;
};
var defineDepartmentSelect = function(departments) {
$departmentSelect.empty();
$departmentSelect.select2({
theme: 'bootstrap4',
placeholder: '请选择所属部门',
data: departments,
templateResult: function (item) {
if(!item.id || item.id === '') return item.text;
return item.name;
},
templateSelection: function(item){
if (item.id) {
$form.find('#department_id').val(item.id);
}
return item.name || item.text;
},
matcher: matcherFunc
});
$departmentSelect.select2('val', ' ');
};
// modal ready fire
$modal.on('show.bs.modal', function (event) {
var $link = $(event.relatedTarget);
var schoolId = $link.data('schoolId');
$schoolIdInput.val(schoolId);
$originDepartmentIdInput.val($link.data('departmentId'));
$.ajax({
url: '/api/schools/' + schoolId + '/departments/for_option.json',
dataType: 'json',
type: 'GET',
success: function(data) {
defineDepartmentSelect(data.departments);
}
});
});
$modal.on('click', '.submit-btn', function(){
$form.find('.error').html('');
if ($form.valid()) {
var url = $form.data('url');
$.ajax({
method: 'POST',
dataType: 'json',
url: url,
data: $form.serialize(),
success: function(){
$.notify({ message: '操作成功' });
$modal.modal('hide');
setTimeout(function(){
window.location.reload();
}, 500);
},
error: function(res){
var data = res.responseJSON;
$form.find('.error').html(data.message);
}
});
}
});
}
});
$(document).on('turbolinks:load', function() {
var $modal = $('.modal.admin-replace-mirror-modal');
if ($modal.length > 0) {
@ -38021,6 +38360,54 @@ $(document).on('turbolinks:load', function() {
}
})
;
$(document).on('turbolinks:load', function() {
if ($('body.admins-shixun-settings-index-page').length > 0) {
}
});
function update_change(target) {
var s_id = $(target).attr("data-id");
var s_value = $(target).val();
var s_name = $(target).attr("name");
var json = {};
var s_index = $(target).parent("td").siblings(".shixun-line-no").text();
json[s_name] = s_value;
json["page_no"] = s_index;
$.ajax({
url: "/admins/shixun_settings/" + s_id,
type: "PUT",
dataType:'script',
data: json,
success: function (data) {
}
})
}
function select_change(target) {
var s_value = $(target).val();
var s_name = $(target).attr("name");
var json = {};
json[s_name] = s_value;
$.ajax({
url: "/admins/shixun_settings/",
type: "GET",
dataType:'script',
data: json,
success: function (data) {
}
})
}
;
$(document).on('turbolinks:load', function() {
$('select#tag-choosed').select2({
placeholder: "请选择分类",
allowClear: true
});
});
$(document).on('turbolinks:load', function(){
$('#sidebarCollapse').on('click', function () {
$(this).toggleClass('active');
@ -38362,6 +38749,12 @@ $.fn.select2.defaults.set('language', 'zh-CN');
Turbolinks.setProgressBarDelay(200);
$.notifyDefaults({
type: 'success',
z_index: 9999,
delay: 2000
});
$(document).on('turbolinks:load', function(){
$('[data-toggle="tooltip"]').tooltip();
$('[data-toggle="popover"]').popover();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -26,12 +26,13 @@ const env = getClientEnvironment(publicUrl);
// This is the development configuration.
// It is focused on developer experience and fast rebuilds.
// The production configuration is different and lives in a separate file.
// 测试用的
module.exports = {
// You may want 'eval' instead if you prefer to see the compiled output in DevTools.
// See the discussion in https://github.com/facebookincubator/create-react-app/issues/343.s
// devtool: "cheap-module-eval-source-map",
// 开启调试
devtool: "source-map", // 开启调试
// devtool: "source-map", // 开启调试
// These are the "entry points" to our application.
// This means they will be the "root" imports that are included in JS bundle.
// The first two entry points enable "hot" CSS and auto-refreshes for JS.

@ -51,9 +51,12 @@ const extractTextPluginOptions = shouldUseRelativeAssetPaths
// This is the production configuration.
// It compiles slowly and is focused on producing a fast and minimal bundle.
// The development configuration is different and lives in a separate file.
// 上线用的
// console.log('publicPath ', publicPath)
module.exports = {
// externals: {
// 'react': 'window.React'
// },
// Don't attempt to continue if there are any errors.
bail: true,
// We generate sourcemaps in production. This is slow but gives good results.

@ -3453,4 +3453,4 @@ a.singlepublishtwo{
/*.ant-notification{*/
/*width: auto !important;*/
/*max-width: 600px !important;*/
/*}*/
/*}*/

@ -3601,6 +3601,13 @@
return text;
};
markedRenderer.em = function (text) {
if (text && text.indexOf('$$') != -1) {
return text;
} else {
return '<em>' + text + '</em>';
}
};
markedRenderer.paragraph = function(text) {
var isTeXInline = /\$\$(.*)\$\$/g.test(text);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -15,17 +15,10 @@ class AttachmentsList extends Component{
<p key={key} className="clearfix mb3">
<a className="color-grey fl">
<i className="font-14 color-green iconfont icon-fujian mr8"></i>
</a>
{
item.is_pdf && item.is_pdf == true ?
<ConditionToolTip title={item.title} condition={item.title && item.title.length > 30 }>
<a href={item.url} className="mr12 fl task-hide" length="58" target="_blank" style={{"maxWidth":"432px"}}>{item.title}</a>
</ConditionToolTip>
:
<ConditionToolTip title={item.title} condition={item.title && item.title.length > 30 }>
<a href={item.url} className="mr12 fl task-hide" length="58" style={{"maxWidth":"432px"}}>{item.title}</a>
</ConditionToolTip>
}
</a>
<ConditionToolTip title={item.title} condition={item.title && item.title.length > 30 }>
<a href={item.url} className="mr12 fl task-hide" length="58" target={ item.is_pdf && item.is_pdf == true ? "_blank" : "_self" } style={{"maxWidth":"432px"}}>{item.title}</a>
</ConditionToolTip>
<span className="color-grey mt2 color-grey-6 font-12">{item.filesize}</span>
</p>
)

@ -7,7 +7,6 @@ import axios from 'axios';
import { TPMIndexHOC } from '../tpm/TPMIndexHOC';
import { CNotificationHOC } from './common/CNotificationHOC'
import {ImageLayerOfCommentHOC} from '../page/layers/ImageLayerOfCommentHOC'
import "./css/Courses.css"
//引入对应跳转的组件
@ -264,9 +263,26 @@ const GraduationTasksSubmiteditApp=Loadable({
loader: () => import('./graduation/tasks/GraduationTasksSubmitedit'),
loading: Loading,
})
//普通作业题库详情
const Generaljobbankdetails =Loadable({
loader: () => import('../../modules/courses/questionbank/Generaljobbankdetails'),
loading: Loading,
});
//分组作业题库详情
const GroupjobbankPage =Loadable({
loader: () => import('../../modules/courses/groupjobbank/GroupjobbankPage'),
loading: Loading,
});
//毕设选题详情
const CompletetopicdePage =Loadable({
loader: () => import('../../modules/courses/comtopicdetails/CompletetopicdePage'),
loading: Loading,
});
//毕设任务详情
const Completetaskpage =Loadable({
loader: () => import('../../modules/courses/completetaskdetails/Completetaskpage'),
loading: Loading,
});
class CoursesIndex extends Component{
constructor(props) {
super(props)
@ -445,7 +461,32 @@ class CoursesIndex extends Component{
// console.log(commons)
return (
<Switch {...this.props}>
{/*毕设任务题库详情*/}
<Route path="/courses/completetask/:workid"
render={
(props) => (<Completetaskpage {...this.props} {...props} {...this.state} />)
}
></Route>
{/*毕设内容题库详情*/}
<Route path="/courses/completetopic/:workid"
render={
(props) => (<CompletetopicdePage {...this.props} {...props} {...this.state} />)
}
></Route>
{/*GroupjobbankPage*/}
{/*分组作业题库详情*/}
<Route path="/courses/groupingwork/:workid"
render={
(props) => (<GroupjobbankPage {...this.props} {...props} {...this.state} />)
}
></Route>
{/*Generaljobbankdetails*/}
{/* 普通作业题库详情*/}
<Route path="/courses/ordinarywork/:workid"
render={
(props) => (<Generaljobbankdetails {...this.props} {...props} {...this.state} />)
}
></Route>
{/* 资源列表页 */}
<Route path="/courses/:coursesId/file/:Id" exact
render={

@ -177,6 +177,7 @@ class CommonWorkItem extends Component{
} */}
</p>
<p className="color-grey-9 clearfix">
{ item.author && <span className="mr20 fl">{item.author}</span> }
{item.commit_count===undefined?"":<span className="mr20 fl">{item.commit_count} 已交</span>}
{item.uncommit_count===undefined?"":<span className="mr20 fl">{item.uncommit_count} 未交</span>}
{

@ -0,0 +1,84 @@
import React, {Component} from "react";
import { WordsBtn,on, off, trigger,markdownToHTML,getImageUrl} from 'educoder';
import {
Button,
Checkbox,
message,
InputNumber,
DatePicker,
Radio,
Tooltip,
notification,
} from "antd";
import './completetaskdetails.css';
import GroupPackage from "../groupjobbank/GroupPackage";
import GroupPackage2 from "../groupjobbank/GroupPackage2";
class Groupjobbandetails extends Component {
constructor(props) {
super(props);
this.state = {
}
}
componentDidMount() {
console.log("Groupjobbandetails");
console.log("componentDidMount");
// let query = this.props.location.pathname;
// const type = query.split('/');
// this.setState({
// shixuntypes:type[3]
// })
// this.props.triggerRef(this);
}
// 获取数据地方
getTrainingjobsetting = () => {
var homeworkid = this.props.match.params.homeworkid;
}
//跳转道描点的地方
scrollToAnchor = (anchorName) => {
if (anchorName) {
// 找到锚点
let anchorElement = document.getElementById(anchorName);
// 如果对应id的锚点存在就跳转到锚点
if(anchorElement) { anchorElement.scrollIntoView(); }
}
};
render() {
return (
<div className=" clearfix edu-back-white" ref='targetElementTrainingjobsetting' style={{margin: "auto", minWidth:"1200px"}}>
<div className="yslquestionbank1">
<div id="MakedownHTML"className="markdown-body yslquesHeigth yslquesmarkdowntext" dangerouslySetInnerHTML={{__html: markdownToHTML("C++是C语言的面向对象扩展是C语言的一个超集同时也是历史最悠久、最受欢迎的程序设计语言之一。根据C++创始人Stroustrup的自述C++是一个“更好的C语言”。\n" +
"\n" +
"输入输出是计算机程序的基本功能。程序本质上是对数据进行处理的一系列操作,一般程序都可以分解为:“数据输入”、“数据处理”和“数据输出”三个步骤。标准输入输出(键盘输入和显示器输出)是程序的重要组成部分。\n" +
"\n" +
"本实训项目的主要目标是学习和掌握C++程序的基本结构和基本输入输出主要内容包括标准C语言自有的单个字符的输入输出、格式化的输入输出以及C++扩展的使用流对象的输入输出").replace(/▁/g, "▁▁▁")}}/>
<GroupPackage></GroupPackage>
<GroupPackage2></GroupPackage2>
</div>
</div>
)
}
}
export default Groupjobbandetails;

@ -0,0 +1,138 @@
import React, {Component} from "react";
import {Link, NavLink} from 'react-router-dom';
import {WordsBtn, ActionBtn} from 'educoder';
import axios from 'axios';
import {
notification
} from "antd";
import CoursesListType from '../coursesPublic/CoursesListType';
import Completetaskdetails from './Completetaskdetails';
import '../css/members.css';
import "../common/formCommon.css";
import '../css/Courses.css';
import '../css/busyWork.css';
import '../poll/pollStyle.css';
class Completetaskpage extends Component {
//分组作业内容详情
constructor(props) {
super(props);
// this.answerMdRef = React.createRef();
this.setState({
workid:1,
isSpin:false,
datas:[],
})
}
componentDidMount() {
// console.log("父组件加载框");
if( this.props.match.params.workid){
this.setState({
workid: this.props.match.params.workid,
})
}
this.getdata(this.props.match.params.workid);
}
// 获取数据的地方
getdata=(workid)=>{
var workids= workid;
if(workids){
}else{
workids=this.state.workid;
}
this.setState({
isSpin:true,
})
let url = `/homework_banks/${workids}.json`;
//
axios.get(url).then((response) => {
if(response){
if(response.data){
this.setState({
datas:response.data.informs,
})
}else {
this.setState({
datas:[],
})
}
}else {
this.setState({
datas:[],
})
}
this.setState({
isSpin:false,
})
}).catch((error) => {
console.log(error)
this.setState({
datas:[],
isSpin:false,
})
});
}
bindRef = ref => { this.child = ref }
///////////////教师截止
render() {
const isAdmin = this.props.isAdmin();
// console.log(119)
return (
<div className="newMain clearfix ">
<div className={"educontent mt10 mb20"} style={{width: "1200px"}}>
<div className="educontent mb20">
<p className="clearfix mb20 mt10">
<a className="btn colorgrey fl hovercolorblue ">题库</a>
<span className="color-grey-9 fl ml3 mr3">&gt;</span>
<a
className=" btn colorgrey fl hovercolorblue "
>详情</a>
</p>
</div>
<div className="educontent mb20">
<p className=" fl color-black summaryname" style={{heigth: "33px"}}>
MySQL数据库编程开发实训基础篇
</p>
<CoursesListType
typelist={["公开"]}
/>
</div>
<div className="edu-back-white ">
<div className="stud-class-set bor-bottom-greyE ">
<div className=" clearfix edu-back-white poll_list">
<a className={"active ml12"}>内容详情</a>
<a className="fr color-blue font-16" >发送</a>
<a className="fr color-blue font-16" >编辑</a>
<a className="fr color-blue font-16" >删除</a>
</div>
</div>
</div>
<Completetaskdetails/>
</div>
</div>
)
}
}
export default Completetaskpage;

@ -0,0 +1,58 @@
.yslquestionbank1{
padding-top: 30px !important;
padding-right: 30px !important;
padding-left: 30px !important;
}
.yslquesHeigth{
min-height: 500px !important;
}
.yslquesmarkdowntext{
font-size: 16px;
color: #707070;
}
.yslquesmat26{
margin-top: 26px;
padding-bottom: 33px !important;
}
.ysltextcolor9999{
color: #999999;
font-size: 14px;
}
.ysltextcolor66{
color: #666666;
font-size: 14px;
}
.ysltextcolor05{
color: #05101A;
font-size: 14px;
}
.ml47text{
margin-left: 17px;
padding-bottom: 37px;
}
.ysltextcolor99999{
color: #999999;
font-size: 16px;
}
.yslboomdivs{
display: flex;
justify-content:flex-start;
}
.yslboomdivs p{
width: 282px;
}
.yslboomdivs p span {
text-align: left;
}
.yslboomdivsy{
color: #999999;
font-size: 14px;
}
.yslboomdivsys{
color: #666666;
font-size: 14px;
}

@ -0,0 +1,141 @@
import React, {Component} from "react";
import {Link, NavLink} from 'react-router-dom';
import {WordsBtn, ActionBtn} from 'educoder';
import { Input,Checkbox,Table, Pagination, Modal,Menu, Tooltip,Spin,Button,Form } from "antd";
import axios from 'axios';
import {
notification
} from "antd";
import CoursesListType from '../coursesPublic/CoursesListType';
import Completetopicdetails from './Completetopicdetails';
import '../css/members.css';
import "../common/formCommon.css";
import '../css/Courses.css';
import '../css/busyWork.css';
import '../poll/pollStyle.css';
class CompletetopicdePage extends Component {
//毕设选题内容详情
constructor(props) {
super(props);
// this.answerMdRef = React.createRef();
this.setState({
workid:1,
isSpin:false,
datas:[],
})
}
componentDidMount() {
if( this.props.match.params.workid){
this.setState({
workid: this.props.match.params.workid,
})
}
this.getdata(this.props.match.params.workid);
}
//获取数据的地方
getdata=(workid)=>{
var workids= workid;
if(workids){
}else{
workids=this.state.workid;
}
this.setState({
isSpin:true,
})
let url = `/homework_banks/${workids}.json`;
//
axios.get(url).then((response) => {
if(response){
if(response.data){
this.setState({
datas:response.data.informs,
})
}else {
this.setState({
datas:[],
})
}
}else {
this.setState({
datas:[],
})
}
this.setState({
isSpin:false,
})
}).catch((error) => {
console.log(error)
this.setState({
datas:[],
isSpin:false,
})
});
}
/// 确认是否下载
bindRef = ref => { this.child = ref }
///////////////教师截止
render() {
const isAdmin = this.props.isAdmin();
// console.log(119)
return (
<div className="newMain clearfix ">
<div className={"educontent mt10 mb20"} style={{width: "1200px"}}>
<div className="educontent mb20">
<p className="clearfix mb20 mt10">
<a className="btn colorgrey fl hovercolorblue ">题库</a>
<span className="color-grey-9 fl ml3 mr3">&gt;</span>
<a
className=" btn colorgrey fl hovercolorblue "
>详情</a>
</p>
</div>
<div className="educontent mb20">
<p className=" fl color-black summaryname" style={{heigth: "33px"}}>
MySQL数据库编程开发实训基础篇
</p>
<CoursesListType
typelist={["公开"]}
/>
</div>
<div className="edu-back-white ">
<div className="stud-class-set bor-bottom-greyE ">
<div className=" clearfix edu-back-white poll_list">
<a className="active ml12" >内容详情</a>
<a className="fr color-blue font-16" >发送</a>
<a className="fr color-blue font-16" >编辑</a>
<a className="fr color-blue font-16" >删除</a>
</div>
</div>
</div>
<Completetopicdetails/>
{/*{parseInt(tab) === 1 ? <Completetopicdeswer/>:""}*/}
</div>
</div>
)
}
}
export default CompletetopicdePage;

@ -0,0 +1,115 @@
import React, {Component} from "react";
import { WordsBtn,on, off, trigger,markdownToHTML,getImageUrl} from 'educoder';
import {
Button,
Checkbox,
message,
InputNumber,
DatePicker,
Radio,
Tooltip,
notification,
} from "antd";
import GroupPackage from '../groupjobbank/GroupPackage'
import './completetopicde.css';
class Completetopicdetails extends Component {
constructor(props) {
super(props);
this.state = {
}
}
componentDidMount() {
console.log("Generaljobdetails");
console.log("componentDidMount");
// let query = this.props.location.pathname;
// const type = query.split('/');
// this.setState({
// shixuntypes:type[3]
// })
// this.props.triggerRef(this);
}
// 获取数据地方
getTrainingjobsetting = () => {
var homeworkid = this.props.match.params.homeworkid;
}
//跳转道描点的地方
scrollToAnchor = (anchorName) => {
if (anchorName) {
// 找到锚点
let anchorElement = document.getElementById(anchorName);
// 如果对应id的锚点存在就跳转到锚点
if(anchorElement) { anchorElement.scrollIntoView(); }
}
};
render() {
return (
<div className=" clearfix edu-back-white " ref='targetElementTrainingjobsetting' style={{margin: "auto", minWidth:"1200px"}}>
<div className="bor-bottom-greyE">
<div className="yslquestionbank1">
<div id="MakedownHTML"className="markdown-body yslquesHeigth yslquesmarkdowntext" dangerouslySetInnerHTML={{__html: markdownToHTML("C++是C语言的面向对象扩展是C语言的一个超集同时也是历史最悠久、最受欢迎的程序设计语言之一。根据C++创始人Stroustrup的自述C++是一个“更好的C语言”。\n" +
"\n" +
"输入输出是计算机程序的基本功能。程序本质上是对数据进行处理的一系列操作,一般程序都可以分解为:“数据输入”、“数据处理”和“数据输出”三个步骤。标准输入输出(键盘输入和显示器输出)是程序的重要组成部分。\n" +
"\n" +
"本实训项目的主要目标是学习和掌握C++程序的基本结构和基本输入输出主要内容包括标准C语言自有的单个字符的输入输出、格式化的输入输出以及C++扩展的使用流对象的输入输出").replace(/▁/g, "▁▁▁")}}/>
<GroupPackage></GroupPackage>
</div>
</div>
<div style={{width:"100%", padding: "36px"}}>
<div className="yslboomdivs">
<p>
<span className="yslboomdivsy">课题类型</span>
<span className="yslboomdivsys">设计</span>
</p>
<p>
<span className="yslboomdivsy">课题来源</span>
<span className="yslboomdivsys">生产/社会实践</span>
</p>
<p>
<span className="yslboomdivsy">课题性质1</span>
<span className="yslboomdivsys">设计</span>
</p>
<p>
<span className="yslboomdivsy">课题性质2</span>
<span className="yslboomdivsys">设计</span>
</p>
</div>
<div className="yslboomdivs">
<p>
<span className="yslboomdivsy">课题重复情况 </span>
<span className="yslboomdivsys">新需求</span>
</p>
<p>
<span className="yslboomdivsy">调研或实习地点</span>
<span className="yslboomdivsys">长沙</span>
</p>
<p style={{width:"564px"}}>
<span className="yslboomdivsy">课题单位来源</span>
<span className="yslboomdivsys">湖南省据C++创始人Stroustrup有限公司</span>
</p>
</div>
</div>
</div>
)
}
}
export default Completetopicdetails;

@ -0,0 +1,58 @@
.yslquestionbank1{
padding-top: 30px !important;
padding-right: 30px !important;
padding-left: 30px !important;
}
.yslquesHeigth{
min-height: 500px !important;
}
.yslquesmarkdowntext{
font-size: 16px;
color: #707070;
}
.yslquesmat26{
margin-top: 26px;
padding-bottom: 33px !important;
}
.ysltextcolor9999{
color: #999999;
font-size: 14px;
}
.ysltextcolor66{
color: #666666;
font-size: 14px;
}
.ysltextcolor05{
color: #05101A;
font-size: 14px;
}
.ml47text{
margin-left: 17px;
padding-bottom: 37px;
}
.ysltextcolor99999{
color: #999999;
font-size: 16px;
}
.yslboomdivs{
display: flex;
justify-content:flex-start;
}
.yslboomdivs p{
width: 282px;
}
.yslboomdivs p span {
text-align: left;
}
.yslboomdivsy{
color: #999999;
font-size: 14px;
}
.yslboomdivsys{
color: #666666;
font-size: 14px;
}

@ -1061,8 +1061,14 @@ samp {
.newcoursestitle{
font-size: 12px;
color: #989898;
margin-left: 10px;
margin-left: 40px;
}
.newcoursestitleysl{
font-size: 12px;
color: #989898;
margin-left: 51px;
}
.coursenavbox .ant-form-item-label{
margin-left:10px;

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save