Merge branch 'dev_aliyun' into dev_daiao

dev_daiao
daiao 6 years ago
commit f46cee65db

1
.gitignore vendored

@ -59,6 +59,7 @@ vendor/bundle/
.ruby-version .ruby-version
.ruby-gemset .ruby-gemset
/Users
/files /files
/public/images/avatars /public/images/avatars
/public/files /public/files

@ -96,3 +96,9 @@ gem 'searchkick'
gem 'aasm' gem 'aasm'
gem 'enumerize' gem 'enumerize'
gem 'diffy'
# oauth2
gem 'omniauth', '~> 1.9.0'
gem 'omniauth-oauth2', '~> 1.6.0'

@ -54,8 +54,8 @@ GEM
tzinfo (~> 1.1) tzinfo (~> 1.1)
acts-as-taggable-on (6.0.0) acts-as-taggable-on (6.0.0)
activerecord (~> 5.0) activerecord (~> 5.0)
addressable (2.5.2) addressable (2.7.0)
public_suffix (>= 2.0.2, < 4.0) public_suffix (>= 2.0.2, < 5.0)
archive-zip (0.11.0) archive-zip (0.11.0)
io-like (~> 0.3.0) io-like (~> 0.3.0)
arel (9.0.0) arel (9.0.0)
@ -98,6 +98,7 @@ GEM
connection_pool (2.2.2) connection_pool (2.2.2)
crass (1.0.4) crass (1.0.4)
diff-lcs (1.3) diff-lcs (1.3)
diffy (3.3.0)
elasticsearch (7.2.0) elasticsearch (7.2.0)
elasticsearch-api (= 7.2.0) elasticsearch-api (= 7.2.0)
elasticsearch-transport (= 7.2.0) elasticsearch-transport (= 7.2.0)
@ -120,7 +121,7 @@ GEM
grape-entity (0.7.1) grape-entity (0.7.1)
activesupport (>= 4.0) activesupport (>= 4.0)
multi_json (>= 1.3.2) multi_json (>= 1.3.2)
hashie (3.6.0) hashie (3.5.7)
htmlentities (4.3.4) htmlentities (4.3.4)
httparty (0.16.2) httparty (0.16.2)
multi_xml (>= 0.5.2) multi_xml (>= 0.5.2)
@ -178,9 +179,15 @@ GEM
multi_json (~> 1.3) multi_json (~> 1.3)
multi_xml (~> 0.5) multi_xml (~> 0.5)
rack (>= 1.2, < 3) rack (>= 1.2, < 3)
omniauth (1.9.0)
hashie (>= 3.4.6, < 3.7.0)
rack (>= 1.6.2, < 3)
omniauth-oauth2 (1.6.0)
oauth2 (~> 1.1)
omniauth (~> 1.9)
pdfkit (0.8.4.1) pdfkit (0.8.4.1)
popper_js (1.14.5) popper_js (1.14.5)
public_suffix (3.0.2) public_suffix (4.0.1)
puma (3.12.0) puma (3.12.0)
rack (2.0.5) rack (2.0.5)
rack-cors (1.0.2) rack-cors (1.0.2)
@ -368,6 +375,7 @@ DEPENDENCIES
byebug byebug
capybara (>= 2.15, < 4.0) capybara (>= 2.15, < 4.0)
chromedriver-helper chromedriver-helper
diffy
enumerize enumerize
faraday (~> 0.15.4) faraday (~> 0.15.4)
font-awesome-sass (= 4.7.0) font-awesome-sass (= 4.7.0)
@ -379,6 +387,8 @@ DEPENDENCIES
listen (>= 3.0.5, < 3.2) listen (>= 3.0.5, < 3.2)
mysql2 (>= 0.4.4, < 0.6.0) mysql2 (>= 0.4.4, < 0.6.0)
oauth2 oauth2
omniauth (~> 1.9.0)
omniauth-oauth2 (~> 1.6.0)
pdfkit pdfkit
puma (~> 3.11) puma (~> 3.11)
rack-cors rack-cors

@ -1,5 +1,6 @@
# README # README
https://www.trustie.net/issues/24719
[云上实验室] Logo、导航、底部备案信息定制化
This README would normally document whatever steps are necessary to get the This README would normally document whatever steps are necessary to get the
application up and running. application up and running.

@ -9,10 +9,13 @@
//= require bootstrap-notify //= require bootstrap-notify
//= require jquery.cookie.min //= require jquery.cookie.min
//= require select2 //= require select2
//= require moment.min
//= require jquery.cxselect //= require jquery.cxselect
//= require bootstrap-datepicker //= require bootstrap-datepicker
//= require bootstrap-datetimepicker
//= require bootstrap.viewer //= require bootstrap.viewer
//= require jquery.mloading //= require jquery.mloading
//= require jquery-confirm.min
//= require common //= require common
//= require echarts //= require echarts
@ -44,6 +47,14 @@ $.notifyDefaults({
delay: 2000 delay: 2000
}); });
function show_success_flash(){
$.notify({
message: '操作成功'
},{
type: 'success'
});
}
$(document).on('turbolinks:load', function(){ $(document).on('turbolinks:load', function(){
$('[data-toggle="tooltip"]').tooltip({ trigger : 'hover' }); $('[data-toggle="tooltip"]').tooltip({ trigger : 'hover' });
$('[data-toggle="popover"]').popover(); $('[data-toggle="popover"]').popover();

@ -0,0 +1,6 @@
function show_add_manager(id) {
$(".auth-schools-user-add").modal("show");
$(".auth-schools-user-add").find("#school_id_input").val(id)
}

@ -0,0 +1,12 @@
$(document).on('turbolinks:load', function(){
$(document).on('click', '.batch-all-check-box', function(){
var $checkAll = $(this);
$('.batch-check-box').prop('checked', $checkAll.is(':checked'));
})
$(document).on('click', '.batch-check-box', function(){
var allChecked = $('.batch-check-box:checked').length === $('.batch-check-box').length
$('.batch-all-check-box').prop('checked', allChecked);
})
});

@ -0,0 +1,132 @@
$(document).on('turbolinks:load', function() {
if ($('body.admins-carousels-index-page').length > 0) {
var laboratoryId = $('#carousels-container').data('laboratoryId');
var resetNo = function(){
$('#carousels-container .custom-carousel-item-no').each(function(index, ele){
$(ele).html(index + 1);
})
}
// 删除后
$(document).on('delete_success', resetNo);
// ------------ 保存链接 -----------
$('.carousels-card').on('click', '.save-data-btn', function(){
var $link = $(this);
var id = $link.data('id');
var link = $('.custom-carousel-item-' + id).find('.link-input').val();
var name = $('.custom-carousel-item-' + id).find('.name-input').val();
if(!name || name.length == 0){
$.notify({ message: '名称不能为空' },{ type: 'danger' });
return;
}
$link.attr('disabled', true);
$.ajax({
url: '/admins/laboratories/' + laboratoryId + '/carousels/' + id,
method: 'PATCH',
dataType: 'json',
data: { link: link, name: name },
success: function(data){
$.notify({ message: '操作成功' });
},
error: ajaxErrorNotifyHandler,
complete: function(){
$link.removeAttr('disabled');
}
})
});
// -------------- 是否在首页展示 --------------
$('.carousels-card').on('change', '.online-check-box', function(){
var $checkbox = $(this);
var id = $checkbox.data('id');
var checked = $checkbox.is(':checked');
$checkbox.attr('disabled', true);
$.ajax({
url: '/admins/laboratories/' + laboratoryId + '/carousels/' + id,
method: 'PATCH',
dataType: 'json',
data: { status: checked },
success: function(data){
$.notify({ message: '保存成功' });
var box = $('.custom-carousel-item-' + id).find('.drag');
if(checked){
box.removeClass('not_active');
}else{
box.addClass('not_active');
}
},
error: ajaxErrorNotifyHandler,
complete: function(){
$checkbox.removeAttr('disabled');
}
})
});
// ------------ 拖拽 -------------
var onDropFunc = function(el, _target, _source, sibling){
var moveId = $(el).data('id');
var insertId = $(sibling).data('id') || '';
$.ajax({
url: '/admins/laboratories/' + laboratoryId + '/carousels/drag',
method: 'POST',
dataType: 'json',
data: { move_id: moveId, after_id: insertId },
success: function(data){
resetNo();
},
error: function(res){
var data = res.responseJSON;
$.notify({message: '移动失败,原因:' + data.message}, {type: 'danger'});
}
})
};
var ele1 = document.getElementById('carousels-container');
dragula([ele1], { mirrorContainer: ele1 }).on('drop', onDropFunc);
// ----------- 新增 --------------
var $createModal = $('.modal.admin-add-carousel-modal');
var $createForm = $createModal.find('form.admin-add-carousel-form');
$createForm.validate({
errorElement: 'span',
errorClass: 'danger text-danger',
rules: {
"portal_image[image]": {
required: true
},
"portal_image[name]": {
required: true
},
}
});
$createModal.on('show.bs.modal', function(event){
resetFileInputFunc($createModal.find('.img-file-input'));
$createModal.find('.file-names').html('选择文件');
});
$createModal.on('click', '.submit-btn', function() {
$createForm.find('.error').html('');
if ($createForm.valid()) {
$createForm.submit();
} else {
$createForm.find('.error').html('请选择图片');
}
});
$createModal.on('change', '.img-file-input', function(){
var file = $(this)[0].files[0];
$createModal.find('.file-names').html(file ? file.name : '请选择文件');
})
// -------------- 重新上传图片 --------------
//replace_image_url
$('.modal.admin-upload-file-modal').on('upload:success', function(e, data){
var $carouselItem = $('.custom-carousel-item-' + data.source_id);
$carouselItem.find('.custom-carousel-item-img img').attr('src', data.url);
})
}
})

@ -0,0 +1,803 @@
$(document).on('turbolinks:load', function(){
if ($('body.admins-competition-settings-index-page').length > 0) {
var dateOptions = {
autoclose: true,
language: 'zh-CN',
format: 'yyyy-mm-dd',
startDate: '2017-04-01'
};
var timeOptions = {
autoclose: 1,
language: 'zh-CN',
format: 'yyyy-mm-dd hh:ii',
minuteStep: 30
};
var defineDateRangeSelect = function (element) {
var options = $.extend({inputs: $(element).find('.start-date, .end-date')}, dateOptions);
$(element).datepicker(options);
$(element).find('.start-date').datepicker().on('changeDate', function (e) {
$(element).find('.end-date').datepicker('setStartDate', e.date);
});
};
$(".competition-start-end-date .start-date").datetimepicker(timeOptions);
$(".competition-start-end-date .end-date").datetimepicker(timeOptions);
$(".nav-setting-form .enroll_end_time").datetimepicker(timeOptions);
$(".stage-update-form .section-start-time").datetimepicker(timeOptions);
$(".stage-update-form .section-end-time").datetimepicker(timeOptions);
defineDateRangeSelect('.teaching-mode-date');
// defineTimeRangeSelect('.competition-start-end-date');
var $basicForm = $('form.basic-setting-form');
$basicForm.validate({
errorElement: 'span',
errorClass: 'danger text-danger',
rules: {
name: "required",
subTitle: "required",
startTime: "required",
endTime: "required",
mode: "required",
identifier: "required"
}
});
// 保存按钮
$basicForm.on('click', ".submit-btn", function () {
$basicForm.find('.submit-btn').attr('disabled', 'disabled');
$basicForm.find('.error').html('');
var valid = $basicForm.valid();
if ($("input[name='mode']:checked").val() == 2) {
var $courseId = $("input[name='course_id']");
if ($courseId.val() === undefined || $courseId.val().length === 0) {
$courseId.addClass('danger text-danger');
valid = false;
} else {
$courseId.removeClass('danger text-danger');
}
} else if ($("input[name='mode']:checked").val() == 3) {
var $techStartTime = $("input[name='teach_start_time']");
var $techEndTime = $("input[name='teach_end_time']");
if ($techStartTime.val() === undefined || $techStartTime.val().length === 0) {
$techStartTime.addClass('danger text-danger');
valid = false;
} else {
$techStartTime.removeClass('danger text-danger');
}
if ($techEndTime.val() === undefined || $techEndTime.val().length === 0) {
$techEndTime.addClass('danger text-danger');
valid = false;
} else {
$techEndTime.removeClass('danger text-danger');
}
} else {
$("input[name='course_id']").removeClass('danger text-danger');
$("input[name='teach_start_time']").removeClass('danger text-danger');
$("input[name='teach_end_time']").removeClass('danger text-danger');
}
if (!valid) return;
$.ajax({
method: 'POST',
dataType: 'json',
url: $basicForm.attr('action'),
data: new FormData($basicForm[0]),
processData: false,
contentType: false,
success: function (data) {
$.notify({message: '保存成功'});
// window.location.reload();
},
error: function (res) {
var data = res.responseJSON;
$basicForm.find('.error').html(data.message);
},
complete: function () {
$basicForm.find('.submit-btn').attr('disabled', false);
}
});
});
var selectOptions = {
theme: 'bootstrap4',
placeholder: '请输入要添加的单位名称',
multiple: true,
minimumInputLength: 1,
ajax: {
delay: 500,
url: '/api/schools/for_option.json',
dataType: 'json',
data: function(params){
return { keyword: params.term };
},
processResults: function(data){
return { results: data.schools }
}
},
templateResult: function (item) {
if(!item.id || item.id === '') return item.text;
return item.name || item.text;
},
templateSelection: function(item){
return item.name || item.text;
}
};
$('.sponsor-select').select2(selectOptions);
$('.allow-school-select').select2(selectOptions);
$('.manager-select').select2({
theme: 'bootstrap4',
placeholder: '请输入要添加的管理员姓名',
multiple: true,
minimumInputLength: 1,
ajax: {
delay: 500,
url: '/admins/users',
dataType: 'json',
data: function(params){
return { keyword: params.term };
},
processResults: function(data){
return { results: data.users }
}
},
templateResult: function (item) {
if(!item.id || item.id === '') return item.text;
return $("<div class='row px-0'><span class='col-3'>" + item.real_name + "</span><span class='col-5 font-12'>" + item.school_name + "</span><span class='col-4 font-12'>" + item.hidden_phone + "</span></div>");
},
templateSelection: function(item){
if (item.id) {
}
return item.real_name || item.text;
}
});
// 排行榜
//链接
$(".nav-setting-form").on("click",".add_linkBtn",function () {
var length=$(".nav-setting-form").find(".linkFormItem").length + 1;
var html='<div class="row mt-2 align-items-center linkFormItem">\n' +
' <div class="col-1 text-right">\n' +
' <label class="checkbox checkbox-primary mt-1">\n' +
' <input type="checkbox" name="navbar[][hidden]" value="0" hidden class="font-16" checked="checked">\n' +
' <input type="checkbox" value="0" class="font-16 module_hidden" checked="checked">\n' +
' </label>\n' +
' </div>\n' +
' <div class="col-md-label mt-1"><input type="hidden" value="md" name="navbar[][module_type]">\n' +
' <input type="text" name="navbar[][name]" value="" class="form-control" placeholder="模块名称"></div>\n' +
' <div class="col-md-1 mt-1"><input type="text" name="navbar[][position]" value="" class="form-control" placeholder="位置"></div>\n' +
' <div class="col-md-3 mt-1"><input type="text" name="navbar[][url]" value="" class="form-control" placeholder="请输入资料下载地址"></div>\n' +
' <a class="mt-1 btn btn-primary waves-effect waves-light btn-xs setBtn_s add_linkBtn" href="javascript:void(0)">+</a>\n' +
' <a class="mt-1 btn btn-icon waves-effect btn-default waves-light setBtn_s ml10 del_linkBtn" href="javascript:void(0)">×</a>\n' +
' </div>';
$(this).parents(".linkFormItem").after(html);
});
$(".nav-setting-form").on("click", ".del_linkBtn", function () {
$(this).parents(".linkFormItem").remove();
});
//有关报名要求
$(".addRequireBtn").on("click",function () {
var length=$("#requireForm").find(".requireForm_item").length + 1;
var html='<div class="row mt-2 mb-4 requireForm_item">\n' +
' <div class="col-1 text-right">&nbsp;&nbsp;</div>\n' +
' <div class="col-1 text-left mt-1">\n' +
' <input type="text" class="form-control" name="competition_staffs[][minimum]" value="0">\n' +
' </div>\n' +
' <span class="mt-2">~</span>\n' +
' <div class="col-1 mt-1">\n' +
' <input type="text" class="form-control" name="competition_staffs[][maximum]" value="1">\n' +
' </div>\n' +
' <span class="mt-2">人</span>\n' +
' <div class="col-2 mt-1">\n' +
' <select class="form-control" name="competition_staffs[][category]">\n' +
' <option value="student">学生</option>\n' +
' <option value="teacher">教师</option>\n' +
' </select>\n' +
' </div>\n' +
' <div class="col-2 mt-1">\n' +
' <label class="radio checkbox-primary mt-1" value="require_'+length+'_1">\n' +
' <input id="require_'+length+'_1" class="mutiple-limited-radio" value="false" checked name="competition_staffs[][mutiple_limited]" type="checkbox">\n' +
' <label for="require_'+length+'_1">可多次报名</label>\n' +
' </label>\n' +
' </div>\n' +
' <div class="col-2 mt-1">\n' +
' <label class="radio checkbox-primary mt-1" value="require_'+length+'_2">\n' +
' <input id="require_'+length+'_2" class="mutiple-limited-radio" value="true" name="competition_staffs[][mutiple_limited]" type="checkbox">\n' +
' <label for="require_'+length+'_2">不可多次报名</label>\n' +
' </label>\n' +
' <a href="javascript:void(0)" class="ml20 delRequrieBtn">\n' +
' <i class="fa fa-times-circle font-20 color-grey-c"></i>\n' +
' </a>\n' +
' </div>\n' +
' </div>';
$("#requireForm").append(html);
});
$("#requireForm").on("click",".delRequrieBtn",function () {
$(this).parents(".requireForm_item").remove();
});
$('.nav-setting-form').on('click', '.module_hidden', function(){
var checkEle = $(this);
if (checkEle.is(':checked')) {
checkEle.prev().val(0);
} else {
checkEle.prev().val(1);
}
});
$('.competition-staff-settings').on('click', '.mutiple-limited-radio', function(){
var radio = $(this);
if (radio.is(':checked')) {
radio.parent().parent().siblings().find('.mutiple-limited-radio').attr('checked', false)
} else {
radio.parent().parent().siblings().find('.mutiple-limited-radio').attr('checked', true)
}
});
var $navForm = $('form.nav-setting-form');
$navForm.on('click', ".submit-btn", function () {
$navForm.find('.submit-btn').attr('disabled', 'disabled');
$navForm.find('.error').html('');
var valid = $navForm.valid();
if (!valid) return;
$.ajax({
method: 'POST',
dataType: 'json',
url: $navForm.attr('action'),
data: new FormData($navForm[0]),
processData: false,
contentType: false,
success: function (data) {
$.notify({message: '保存成功'});
// window.location.reload();
},
error: function (res) {
var data = res.responseJSON;
$navForm.find('.error').html(data.message);
},
complete: function () {
$navForm.find('.submit-btn').attr('disabled', false);
}
});
});
// 排行榜设置
//删除小阶段
$("#large_panel").on("click",".small_panel_item_del",function () {
var list = $(this).parents(".small_panel");
$(this).parents(".small_panel_item").remove();
for(var i=0;i < $(list).find(".subName").length;i++){
console.log(i);
$(list).find(".subName").eq(i).html("第"+parseInt(i+1)+"阶段");
}
});
// $('form.stage-update-form').validate({
// errorElement: 'span',
// errorClass: 'danger text-danger',
// rules: {
// stage_name: "required",
// "stage[][start_time]": "required",
// "stage[][end_time]": "required",
// "stage[][mission_count]": {
// required: true,
// min: 1
// },
// "stage[][entry]": {
// required: true,
// min: 1
// },
// score_rate: {
// required: true,
// range: [0, 100]
// }
// },
// messages: {
// "stage[][mission_count]": {
// min: ">=1"
// },
// "stage[][entry]": {
// min: ">=1"
// },
// }
// });
$('.competition-chart-setting').on('click', ".update-stage", function () {
var updateForm = $(this).parents("form");
$(this).attr('disabled', 'disabled');
updateForm.find('.error').html('');
// var valid = updateForm.valid();
var valid = true;
var $stageName = updateForm.find('input[name="stage_name"]');
if($stageName.val() === undefined || $stageName.val().length === 0){
$stageName.addClass('danger text-danger');
valid = false;
} else {
$stageName.removeClass('danger text-danger');
}
var $scoreRate = updateForm.find('input[name="score_rate"]');
if($scoreRate.val() === undefined || $scoreRate.val().length === 0){
$scoreRate.addClass('danger text-danger');
valid = false;
} else if (parseInt($scoreRate.val()) > 100 || parseInt($scoreRate.val()) < 0) {
$scoreRate.addClass('danger text-danger');
$scoreRate.after('<span class="danger text-danger">0-100之间的数值</span>');
valid = false;
} else {
$scoreRate.removeClass('danger text-danger');
$scoreRate.siblings().remove();
}
updateForm.find('input[name="stage[][start_time]"]').each(function(_, e){
var $ele = $(e);
if($ele.val() === undefined || $ele.val().length === 0){
$ele.addClass('danger text-danger');
valid = false;
} else {
$ele.removeClass('danger text-danger');
}
});
updateForm.find('input[name="stage[][end_time]"]').each(function(_, e){
var $ele = $(e);
if($ele.val() === undefined || $ele.val().length === 0){
$ele.addClass('danger text-danger');
valid = false;
} else {
$ele.removeClass('danger text-danger');
}
});
updateForm.find('input[name="stage[][mission_count]"]').each(function(i, e){
var $ele = $(e);
var $entry = updateForm.find('input[name="stage[][entry]"]').eq(i);
if($ele.val() === undefined || $ele.val().length === 0){
$ele.addClass('danger text-danger');
valid = false;
} else if (parseInt($ele.val()) < 1) {
$ele.addClass('danger text-danger');
$ele.after('<span class="danger text-danger">大于等于1</span>');
valid = false;
} else if (parseInt($ele.val()) > parseInt($entry.val())) {
$ele.addClass('danger text-danger');
$ele.after('<span class="danger text-danger">不能大于总任务数</span>');
valid = false;
} else {
$ele.removeClass('danger text-danger');
$ele.siblings().remove();
}
});
updateForm.find('input[name="stage[][entry]"]').each(function(_, e){
var $ele = $(e);
if($ele.val() === undefined || $ele.val().length === 0){
$ele.addClass('danger text-danger');
valid = false;
} else if (parseInt($ele.val()) < 1) {
$ele.addClass('danger text-danger');
$ele.after('<span class="danger text-danger">大于等于1</span>');
valid = false;
} else {
$ele.removeClass('danger text-danger');
$ele.siblings().remove();
}
});
updateForm.find('input[name="stage[][identifiers][]"]').each(function(_, e){
var $ele = $(e);
if($ele.val() === undefined || $ele.val().length === 0){
$ele.addClass('danger text-danger');
valid = false;
} else {
$ele.removeClass('danger text-danger');
}
});
if (!valid) return;
updateForm.find('input[name="stage[][mission_count]"]').each(function(_, e){
var $missionCount = $(e);
var $entryCount = $(e).parents("div.row").find('input[name="stage[][mission_count]"]');
if(parseInt($missionCount.val()) > parseInt($entryCount.val()) ){
$missionCount.addClass('danger text-danger');
$missionCount.after('<span class="danger text-danger">不能大于总任务数</span>');
valid = false;
} else {
$missionCount.removeClass('danger text-danger');
$missionCount.siblings().remove();
}
});
$.ajax({
method: 'POST',
dataType: 'json',
url: updateForm.attr('action'),
data: new FormData(updateForm[0]),
processData: false,
contentType: false,
success: function (data) {
$.notify({message: '保存成功'});
window.location.reload();
},
error: function (res) {
var data = res.responseJSON;
$navForm.find('.error').html(data.message);
},
complete: function () {
$navForm.find('.submit-btn').attr('disabled', false);
}
});
});
$(".competition-chart-stages").on("click", ".add-new-tab", function () {
if($(".new-stage-form").length > 0){
alert("请先保存上一个tab");
} else {
var count = parseInt($("#large_panel").find(".large_panel_part").length)+1;
var html = '<form class="stage-update-form new-stage-form flex-1" action="/admins/competitions/'+$(this).attr("data-competition-id")+'/competition_stages" accept-charset="UTF-8" data-remote="true" method="post">' +
'<div class="large_panel_part" attr_line="'+count+'"><div class="row d-flex mt-3">\n' +
' <span class="col-1 mt-2">tab标题</span>\n' +
' <div class="col-2 no_padding">\n' +
' <input type="text" class="form-control" name="stage_name"/>\n' +
' </div>\n' +
' <span class="col-1 text-right mt-2 no_padding">总排行榜占比:</span>\n' +
' <div class="col-1 no_padding">\n' +
' <input type="number" class="form-control" name="score_rate" value="100"/>\n' +
' </div><span class=" mt-2">%</span>\n' +
' <div class="flex-1">\n' +
' <a href="javascript:void(0)"class="btn btn-outline-primary export-action ml20 add-task-sub">新增子阶段</a>\n' +
' </div>\n' +
' <a href="javascript:void(0)" class="btn btn-default ml20" onclick="Del_tab(this)">删除</a>\n' +
' <a href="javascript:void(0)" class="btn btn-outline-primary update-stage export-action ml20">保存</a>\n' +
' </div>\n' +
' <div id="small_panel_'+count+'" class="small_panel">\n' +
' <div class="row d-flex small_panel_item" attr_line="sub_new_new" count="1">\n' +
' <span class="mt-2 subName mr10">第1阶段</span>\n' +
' <div class="flex-1">\n' +
' <div class="row">\n' +
' <div class="row col-6"><span class="mt-2 ml20">有效时间:</span>\n' +
' <div class="col-4 no_padding">\n' +
' <input type="text" name="stage[][start_time]" id="stage__start_time" value="" autocomplete="off" class="section-start-time form-control" placeholder="有效开始时间">\n' +
' </div>\n' +
' <span class="mt-2">~</span>\n' +
' <div class="col-4 no_padding ">\n' +
' <input type="text" name="stage[][end_time]" id="stage__end_time" value="" autocomplete="off" class="section-end-time form-control" placeholder="有效结束时间">\n' +
' </div></div>\n' +
' <div class="row col-3"><span class="col-4 text-right mt-2 no_padding">总任务数:</span>\n' +
' <div class="col-6 no_padding ">\n' +
' <input type="number" class="form-control" onchange="change_total(this)" value="3" name="stage[][entry]">\n' +
' </div></div>\n' +
' <div class="row col-3"><span class="col-4 text-right mt-2 no_padding">成绩来源:</span>\n' +
' <div class="col-6 no_padding ">\n' +
' <select class="form-control" name="stage[][score_source]">\n' +
' <option value="0">经验值</option>\n' +
' <option value="1">预测准确率</option>\n' +
' </select>\n' +
' </div></div>\n' +
' </div>\n' +
' <div class="row mt-2" id="task_Input_sub_new_new">\n' +
' <div class="col-4 row task_Input_div">\n' +
' <span class="col-4 text-right mt-3 no_padding mr10">任务1</span>\n' +
' <div class="col-6 no_padding">\n' +
' <input type="text" class="form-control mt-2" name="stage[][identifiers][]" placeholder="请填写实训ID">\n' +
' </div>\n' +
' </div>\n' +
' <div class="col-4 row task_Input_div">\n' +
' <span class="col-4 text-right mt-3 no_padding mr10">任务2</span>\n' +
' <div class="col-6 no_padding">\n' +
' <input type="text" class="form-control mt-2" name="stage[][identifiers][]" placeholder="请填写实训ID">\n' +
' </div>\n' +
' </div>\n' +
' <div class="col-4 row task_Input_div">\n' +
' <span class="col-4 text-right mt-3 no_padding mr10">任务3</span>\n' +
' <div class="col-6 no_padding">\n' +
' <input type="text" class="form-control mt-2" name="stage[][identifiers][]" placeholder="请填写实训ID">\n' +
' </div>\n' +
' </div>\n' +
' </div>\n' +
' </div>\n' +
' <span>\n' +
' <a href="javascript:void(0)" class="btn btn-default ml20 small_panel_item_del">删除</a>\n' +
' </span>\n' +
' </div>\n' +
'</div></div></form>';
$("#large_panel").append(html);
$(".stage-update-form .section-start-time").datetimepicker(timeOptions);
$(".stage-update-form .section-end-time").datetimepicker(timeOptions);
}
});
//新增子阶段
$(".competition-chart-stages").on("click", ".add-task-sub", function () {
var index = $(this).parents(".large_panel_part").attr("attr_line");
var count= 0;
console.log("sdfsf");
console.log($("#small_panel_"+index).find(".small_panel_item").length > 0);
if($("#small_panel_"+index).find(".small_panel_item").length > 0){
count = parseInt($("#small_panel_"+index).find(".small_panel_item").last().attr("count")) + 1;
console.log($("#small_panel_"+index).find(".small_panel_item").last().attr("count"));
}else{
count = 1;
}
var showCount=parseInt($("#small_panel_"+index).find(".small_panel_item").length) + 1;
var html='<div class="row d-flex small_panel_item" attr_line="sub_'+index+'_'+count+'" count="'+count+'">\n' +
' <span class="mr10 mt-2 subName">第'+showCount+'阶段</span>\n' +
' <div class="flex-1">\n' +
' <div class="row">\n' +
' <div class="row col-6"><span class="mt-2 ml20 mr10">有效时间:</span>\n' +
' <div class="col-4 no_padding ">\n' +
' <input type="text" name="stage[][start_time]" id="stage__start_time" value="" autocomplete="off" class="section-start-time form-control" placeholder="有效开始时间">\n' +
' </div>\n' +
' <span class="mt-2">~</span>\n' +
' <div class="col-4 no_padding ">\n' +
' <input type="text" name="stage[][end_time]" id="stage__end_time" value="" autocomplete="off" class="section-end-time form-control" placeholder="有效结束时间">\n' +
' </div></div>\n' +
' <div class="row col-3"><span class="col-4 text-right mt-2 no_padding mr10">总任务数:</span>\n' +
' <div class="col-6 no_padding ">\n' +
' <input type="number" class="form-control" onchange="change_total(this)" value="3" name="stage[][entry]">\n' +
' </div></div>\n' +
' <div class="row col-3"><span class="col-4 mr10 text-right mt-2 no_padding">成绩来源:</span>\n' +
' <div class="col-6 no_padding ">\n' +
' <select class="form-control" name="stage[][score_source]">\n' +
' <option value="0">经验值</option>\n' +
' <option value="1">预测准确率</option>\n' +
' </select>\n' +
' </div></div>\n' +
' </div>\n' +
' <div class="row mt-2" id="task_Input_sub_'+index+'_'+count+'">\n'+
' <div class="col-4 row task_Input_div">\n' +
' <span class="col-4 text-right mt-3 no_padding mr10">任务1</span>\n' +
' <div class="col-6 no_padding">\n' +
' <input type="text" class="form-control mt-2" name="stage[][identifiers][]" placeholder="请填写实训ID">\n' +
' </div>\n' +
' </div>\n' +
' <div class="col-4 row task_Input_div">\n' +
' <span class="col-4 text-right mt-3 no_padding mr10">任务2</span>\n' +
' <div class="col-6 no_padding">\n' +
' <input type="text" class="form-control mt-2" name="stage[][identifiers][]" placeholder="请填写实训ID">\n' +
' </div>\n' +
' </div>\n' +
' <div class="col-4 row task_Input_div">\n' +
' <span class="col-4 text-right mt-3 no_padding mr10">任务3</span>\n' +
' <div class="col-6 no_padding">\n' +
' <input type="text" class="form-control mt-2" name="stage[][identifiers][]" placeholder="请填写实训ID">\n' +
' </div>\n' +
' </div>\n' +
' </div>\n' +
' </div>\n' +
' <span>\n' +
' <a href="javascript:void(0)" class="btn btn-default ml20 small_panel_item_del">删除</a>\n' +
' </span>\n' +
' </div>';
$("#small_panel_"+index).append(html);
$(".stage-update-form .section-start-time").datetimepicker(timeOptions);
$(".stage-update-form .section-end-time").datetimepicker(timeOptions);
});
// 奖项设置
var $prizeContainer = $('#competition-prize-card');
var competitionId = $prizeContainer.data('id');
$(document).on('prize.save.success', function(){
$.ajax({
method: 'GET',
url: '/admins/competitions/' + competitionId + '/competition_prizes',
dataType: 'script'
})
});
$('.modal.admin-upload-file-modal').on('upload:success', function(e, data){
var $imageElement;
if(data.suffix === '_member'){
$imageElement = $('.prize-member-image-' + data.source_id);
} else if(data.suffix === '_team'){
$imageElement = $('.prize-team-image-' + data.source_id);
} else {
$imageElement = $('.prize-teacher-image-' + data.source_id);
}
$imageElement.attr('src', data.url);
$imageElement.show();
$imageElement.next().html('重新上传');
})
// 生成获奖记录
$prizeContainer.on('click', '.generate-prize-user-action', function(){
var $link = $(this);
var generateRequest = function(){
return $.ajax({
method: 'POST',
url: '/admins/competitions/' + competitionId + '/competition_prize_users',
dataType: 'json',
success: function(data){
if(data && data.status === 0){
show_success_flash();
$link.remove();
} else {
showErrorNotify(data.message);
}
},
error: function(res){
var data = res.responseJSON;
showErrorNotify(data.message);
}
})
}
customConfirm({
content: '确认生成吗?',
ok: function () {
customLoading({
ajax: generateRequest
})
}
})
});
} else {
$(document).unbind('prize.save.success');
}
});
//添加主办方或者开放范围
function addSponsor(item){
var html='<div class="sponsor_label">\n' +
' <input type="hidden" value="school_id" />\n' +
' <span>caicai</span>\n' +
' <a href="javascript:void(0)" onclick="del_sponsor(this)">×</a>\n' +
' </div>';
$(item).parents(".sponsorPanel").append(html);
}
//删除
function del_sponsor(item){
$(item).parents(".sponsor_label").remove();
}
// 小阶段修改总任务数
function change_total(item) {
var count=parseInt($(item).val());
var index = $(item).parents(".small_panel_item").attr("attr_line");
var indexLarge = $(item).parents(".large_panel_part").attr("attr_line");
console.log(indexLarge);
console.log(index);
var divCount=parseInt($("#task_Input_"+index).find(".task_Input_div").length);
var html = "";
if(count > divCount){
for(var i=0;i < count-divCount ;i++){
html+='<div class="col-4 row task_Input_div"><span class="col-4 text-right mt-3 no_padding mr10">任务'+(divCount+i+1)+'</span>\n' +
'<div class="col-6 no_padding">\n' +
'<input type="text" class="form-control mt-2" name="stage[][identifiers][]" placeholder="请填写实训ID">\n' +
'</div>\n' +
'</div>';
}
$("#task_Input_"+index).append(html);
}else{
var delCount = divCount - count ;
console.log(divCount);
console.log(count);
var _max=parseInt($("#task_Input_"+index).find(".task_Input_div:last").index());
console.log(_max);
var _get= _max - delCount;
console.log(_get);
if(count == 0){
$("#task_Input_"+index).empty();
}else{
$("#task_Input_"+index).find(".task_Input_div:gt("+_get+")").remove();
}
}
}
//删除tab
function Del_tab(item) {
$(item).parents(".large_panel_part").remove();
}
//新增tab
function addNewTab(competition_id) {
if($(".new-stage-form").length > 0){
alert("请先保存上一个tab");
} else {
var count = parseInt($("#large_panel").find(".large_panel_part").length)+1;
var html = '<form class="stage-update-form new-stage-form flex-1" action="/admins/competitions/'+competition_id+'/competition_stages" accept-charset="UTF-8" data-remote="true" method="post">' +
'<div class="large_panel_part" attr_line="'+count+'"><div class="row d-flex mt-3">\n' +
' <span class="col-1 mt-2">tab标题</span>\n' +
' <div class="col-2 no_padding">\n' +
' <input type="text" class="form-control" name="stage_name"/>\n' +
' </div>\n' +
' <span class="col-1 text-right mt-2 no_padding">总排行榜占比:</span>\n' +
' <div class="col-1 no_padding">\n' +
' <input type="number" class="form-control" name="score_rate" value="100"/>\n' +
' </div><span class=" mt-2">%</span>\n' +
' <div class="flex-1">\n' +
' <a href="javascript:void(0)"class="btn btn-outline-primary export-action ml20 add-task-sub">新增子阶段</a>\n' +
' </div>\n' +
' <a href="javascript:void(0)" class="btn btn-default ml20" onclick="Del_tab(this)">删除</a>\n' +
' <a href="javascript:void(0)" class="btn btn-outline-primary update-stage export-action ml20">保存</a>\n' +
' </div>\n' +
' <div id="small_panel_'+count+'" class="small_panel">\n' +
' <div class="row d-flex small_panel_item" attr_line="sub_new_new" count="1">\n' +
' <span class="mt-2 subName mr10">第1阶段</span>\n' +
' <div class="flex-1">\n' +
' <div class="row">\n' +
' <div class="row col-6"><span class="mt-2 ml20 mr10">有效时间:</span>\n' +
' <div class="col-4 no_padding ">\n' +
' <input type="text" name="stage[][start_time]" id="stage__start_time" value="" autocomplete="off" class="section-start-time form-control" placeholder="有效开始时间">\n' +
' </div>\n' +
' <span class="mt-2">~</span>\n' +
' <div class="col-4 no_padding input_middle">\n' +
' <input type="text" name="stage[][end_time]" id="stage__end_time" value="" autocomplete="off" class="section-end-time form-control" placeholder="有效结束时间">\n' +
' </div></div>\n' +
' <div class="row col-3"><span class="col-4 text-right mt-2 no_padding mr10">总任务数:</span>\n' +
' <div class="col-6 no_padding ">\n' +
' <input type="number" class="form-control" onchange="change_total(this)" value="3" name="stage[][entry]">\n' +
' </div></div>\n' +
' <div class="row col-3"><span class="col-4 text-right mt-2 no_padding mr10">成绩来源:</span>\n' +
' <div class="col-6 no_padding ">\n' +
' <select class="form-control" name="stage[][score_source]">\n' +
' <option value="0">经验值</option>\n' +
' <option value="1">预测准确率</option>\n' +
' </select>\n' +
' </div></div>\n' +
' </div>\n' +
' <div class="row mt-2" id="task_Input_sub_new_new">\n' +
' <div class="col-4 row task_Input_div">\n' +
' <span class="col-3 text-right mt-3 no_padding mr10">任务1</span>\n' +
' <div class="col-8 no_padding">\n' +
' <input type="text" class="form-control mt-2" name="stage[][identifiers][]" placeholder="请填写实训ID">\n' +
' </div>\n' +
' </div>\n' +
' <div class="col-4 row task_Input_div">\n' +
' <span class="col-3 text-right mt-3 no_padding mr10">任务2</span>\n' +
' <div class="col-8 no_padding">\n' +
' <input type="text" class="form-control mt-2" name="stage[][identifiers][]" placeholder="请填写实训ID">\n' +
' </div>\n' +
' </div>\n' +
' <div class="col-4 row task_Input_div">\n' +
' <span class="col-3 text-right no_padding mr10 mt-3">任务3</span>\n' +
' <div class="col-8 no_padding">\n' +
' <input type="text" class="form-control mt-2" name="stage[][identifiers][]" placeholder="请填写实训ID">\n' +
' </div>\n' +
' </div>\n' +
' </div>\n' +
' </div>\n' +
' <span>\n' +
' <a href="javascript:void(0)" class="btn btn-default ml20 small_panel_item_del">删除</a>\n' +
' </span>\n' +
' </div>\n' +
'</div></div></form>';
$("#large_panel").append(html);
}
}

@ -0,0 +1,73 @@
$(document).on('turbolinks:load', function() {
if ($('body.admins-competitions-index-page').length > 0) {
$('.modal.admin-upload-file-modal').on('upload:success', function(e, data){
var $imageElement = $('.competition-image-' + data.source_id);
$imageElement.attr('src', data.url);
$imageElement.show();
$imageElement.next().html('重新上传');
});
}
$(".admin-competition-list-form").on("change", '.competitions-hot-select', function () {
var s_value = $(this).get(0).checked ? 1 : 0;
var json = {};
json["hot"] = s_value;
$.ajax({
url: "/admins/competitions/hot_setting",
type: "POST",
dataType:'json',
data: json,
success: function(){
$.notify({ message: '操作成功' });
}
});
});
// ============== 新增竞赛 ===============
var $modal = $('.modal.admin-create-competition-modal');
var $form = $modal.find('form.admin-create-competition-form');
var $competitionNameInput = $form.find('input[name="competition_name"]');
$form.validate({
errorElement: 'span',
errorClass: 'danger text-danger',
rules: {
competition_name: {
required: true
}
}
});
// modal ready fire
$modal.on('show.bs.modal', function () {
$competitionNameInput.val('');
});
$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,70 @@
$(document).on('turbolinks:load', function() {
if ($('body.admins-ec-templates-index-page').length > 0) {
var add_modal = $(".ec-templates-new-add");
var template_file_name = add_modal.find(".template-file-upload");
var attachment_id_input = add_modal.find(".template_attachment_id");
var template_container = $(".ec-templates-list-container");
//编辑附件
template_container.on("click", ".edit-template-content", function () {
var t_id = $(this).attr("data-id");
var t_name = $(this).attr("data-name");
var template_name = $(this).attr("data-template-name");
var t_msg = $(this).attr("data-msg");
var template_id = $(this).attr("data-template-id");
add_modal.modal("show");
add_modal.find(".template_add_title").html(t_msg);
attachment_id_input.val(template_id);
add_modal.find(".template_show_id").val(t_id);
add_modal.find("input[name='name']").val(t_name);
add_modal.find("i.delete-template-icon").attr("data-id", template_id);
if(template_id !== "-1"){
template_file_name.find("span.template-file-input").hide();
template_file_name.find("span.template_file_show").show();
template_file_name.find("span.template_file_show_title").html(template_name);
}
});
//删除附件
add_modal.on("click",".delete-template-icon",function () {
var attachment_id = $(this).attr("data-id");
$.ajax({
url: "/api/attachments/" + attachment_id,
type: "delete",
contentType:"application/json",
dataType:"json",
success: function (data) {
template_file_name.find("span.template-file-input").show();
template_file_name.find("span.template_file_show").hide();
attachment_id_input.attr("value","-1")
}
})
});
//上传附件
add_modal.on("change", "#upload_template_file",function () {
var template = document.getElementById('upload_template_file').files[0];
var file_content = new FormData();
file_content.append("file", template);
$.ajax({
type: "POST",
url: "/api/attachments",
data:file_content,
contentType: false,
processData: false,
success: function (data) {
template_file_name.find("span.template-file-input").hide();
template_file_name.find("span.template_file_show").show();
template_file_name.find("span.template_file_show_title").html(template.name);
template_file_name.find("i.delete-template-icon").attr("data-id",data.id);
attachment_id_input.val(data.id)
}
})
})
}
});

@ -0,0 +1,9 @@
$(document).on('turbolinks:load', function() {
if($('body.admins-enroll-lists-index-page').length > 0){
var search_form = $(".search-form");
//导出
$(".competition-enroll-list-form").on("click","#enroll-lists-export",function () {
window.location.href = "/admins/competitions/"+$(this).attr("data-competition-id")+"/enroll_lists/export.xlsx?" + search_form.serialize();
});
}
});

@ -0,0 +1,13 @@
$(document).on('turbolinks:load', function() {
if($(".admins-graduation-standards-index-page").length > 0){
$(".admin-body-container").on("click", ".standard-create-modal", function () {
var content = $(this).attr("data-content");
var g_id = $(this).attr("data-id");
var g_msg = $(this).attr("data-msg");
$("#graduation-modal-type").html(g_msg);
$("#graduation_standard_id").val(g_id);
$("textarea[name='content']").val(content);
})
}
});

@ -10,11 +10,41 @@ $(document).on('turbolinks:load', function() {
$searchFrom.find('select[name="status"]').val('processed'); $searchFrom.find('select[name="status"]').val('processed');
if($link.data('value') === 'processed'){ if($link.data('value') === 'processed'){
$('.batch-action-container').hide();
$searchFrom.find('.status-filter').show(); $searchFrom.find('.status-filter').show();
} else { } else {
$('.batch-action-container').show();
$searchFrom.find('.status-filter').hide(); $searchFrom.find('.status-filter').hide();
$searchFrom.find('select[name="status"]').val('pending'); $searchFrom.find('select[name="status"]').val('pending');
} }
}); });
$('.batch-agree-btn').on('click', function(){
if($('.batch-check-box:checked').length === 0){
$.notify({ message: '请先选择数据' }, { type: 'info' });
return;
}
customConfirm({
content: '确认审核通过?',
ok: function(){
var ids = $('.batch-check-box:checked').map(function(_, e){ return $(e).val() }).get();
$.ajax({
url: '/admins/identity_authentications/batch_agree',
method: 'POST',
dataType: 'json',
data: { ids: ids },
success: function(data){
$.notify({ message: '操作成功' });
window.location.reload();
},
error: function(res){
$.notify({ message: res.responseJSON.message }, { type: 'danger' });
}
})
}
})
})
} }
}) })

@ -0,0 +1,86 @@
$(document).on('turbolinks:load', function() {
if ($('body.admins-laboratory-settings-show-page, body.admins-laboratory-settings-update-page').length > 0) {
var $container = $('.edit-laboratory-setting-container');
var $form = $container.find('.edit_laboratory');
$('.logo-item-left').on("change", 'input[type="file"]', function () {
var $fileInput = $(this);
var file = this.files[0];
var imageType = /image.*/;
if (file && file.type.match(imageType)) {
var reader = new FileReader();
reader.onload = function () {
var $box = $fileInput.parent();
$box.find('img').attr('src', reader.result).css('display', 'block');
$box.addClass('has-img');
};
reader.readAsDataURL(file);
} else {
}
});
createMDEditor('laboratory-footer-editor', { height: 200, placeholder: '请输入备案信息' });
$form.validate({
errorElement: 'span',
errorClass: 'danger text-danger',
errorPlacement:function(error,element){
if(element.parent().hasClass("input-group")){
element.parent().after(error);
}else{
element.after(error)
}
},
rules: {
identifier: {
required: true,
checkSite: true
},
name: {
required: true
}
}
});
$.validator.addMethod("checkSite",function(value,element,params){
var checkSite = /^(?=^.{3,255}$)[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+$/;
return this.optional(element)||(checkSite.test(value + '.educoder.com'));
},"域名不合法!");
$form.on('click', '.submit-btn', function(){
$form.find('.submit-btn').attr('disabled', 'disabled');
$form.find('.error').html('');
var valid = $form.valid();
$('input[name="navbar[][name]"]').each(function(_, e){
var $ele = $(e);
if($ele.val() === undefined || $ele.val().length === 0){
$ele.addClass('danger text-danger');
valid = false;
} else {
$ele.removeClass('danger text-danger');
}
});
if(!valid) return;
$.ajax({
method: 'PATCH',
dataType: 'json',
url: $form.attr('action'),
data: new FormData($form[0]),
processData: false,
contentType: false,
success: function(data){
$.notify({ message: '保存成功' });
window.location.reload();
},
error: function(res){
var data = res.responseJSON;
$form.find('.error').html(data.message);
},
complete: function(){
$form.find('.submit-btn').attr('disabled', false);
}
});
})
}
});

@ -0,0 +1,164 @@
$(document).on('turbolinks:load', function() {
if ($('body.admins-laboratories-index-page').length > 0) {
var $searchContainer = $('.laboratory-list-form');
var $searchForm = $searchContainer.find('form.search-form');
var $list = $('.laboratory-list-container');
// ============== 新建 ===============
var $modal = $('.modal.admin-create-laboratory-modal');
var $form = $modal.find('form.admin-create-laboratory-form');
var $schoolSelect = $modal.find('.school-select');
$form.validate({
errorElement: 'span',
errorClass: 'danger text-danger',
rules: {
school_id: {
required: true
}
},
messages: {
school_id: {
required: '请选择所属单位'
}
}
});
// modal ready fire
$modal.on('show.bs.modal', function () {
$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-laboratory-user-modal');
var $addMemberForm = $addMemberModal.find('.admin-add-laboratory-user-form');
var $memberSelect = $addMemberModal.find('.laboratory-user-select');
var $laboratoryIdInput = $addMemberForm.find('input[name="laboratory_id"]')
$addMemberModal.on('show.bs.modal', function(event){
var $link = $(event.relatedTarget);
var laboratoryId = $link.data('laboratory-id');
$laboratoryIdInput.val(laboratoryId);
$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 $("<span>" + item.real_name + " <span class='font-12'>" + item.school_name + ' ' + item.hidden_phone + "</span></span>");
},
templateSelection: function(item){
if (item.id) {
}
return item.real_name || item.text;
}
});
$addMemberModal.on('click', '.submit-btn', function(){
$addMemberForm.find('.error').html('');
var laboratoryId = $laboratoryIdInput.val();
var memberIds = $memberSelect.val();
if (laboratoryId && memberIds && memberIds.length > 0) {
$.ajax({
method: 'POST',
dataType: 'script',
url: '/admins/laboratories/' + laboratoryId + '/laboratory_user',
data: { user_ids: memberIds }
});
} else {
$addMemberModal.modal('hide');
}
});
}
});

@ -0,0 +1,13 @@
$(document).on('turbolinks:load', function() {
if ($('body.admins-major-informations-index-page').length > 0) {
var box_contain = $(".major-informations-list-container");
box_contain.on("click",".collapse-item",function () {
var a_fa = $(this).find("i");
if(a_fa.hasClass("fa-caret-right")){
a_fa.removeClass("fa-caret-right").addClass("fa-caret-down");
}else{
a_fa.removeClass("fa-caret-down").addClass("fa-caret-right");
}
});
}
});

@ -0,0 +1,18 @@
$(document).on('turbolinks:load', function () {
$('.admin-modal-container').on('show.bs.modal', '.modal.admin-edit-subject-modal', function () {
var $modal = $('.modal.admin-edit-subject-modal');
var $form = $modal.find('form.admin-edit-subject-form');
$modal.on('click', '.submit-btn', function () {
$form.find('.error').html('');
var url = $form.attr('action');
$.ajax({
method: 'PATCH',
dataType: 'script',
url: url,
data: $form.serialize()
});
});
})
});

@ -0,0 +1,46 @@
$(document).on('turbolinks:load', function() {
$('.admin-modal-container').on('show.bs.modal', '.admin-save-competition-prize-modal', function(event){
var $modal = $('.modal.admin-save-competition-prize-modal');
var $form = $modal.find('form.admin-save-competition-prize-form');
$form.validate({
errorElement: 'span',
errorClass: 'danger text-danger',
rules: {
'competition_prize[name]': {
required: true,
maxlength: 10
},
'competition_prize[num]': {
required: true,
digits: true,
min: 1
}
}
});
$modal.on('click', '.submit-btn', function(){
$form.find('.error').html('');
var url = $form.attr('action');
var formMethod = $form.data('form-method')
if ($form.valid()) {
$.ajax({
method: formMethod,
dataType: 'json',
url: url,
data: $form.serialize(),
success: function(data){
if(data && data.status === 0) {
show_success_flash();
$(document).trigger('prize.save.success');
$modal.modal('hide');
} else {
$modal.find('.error').html(data.message)
}
}
});
}
});
})
});

@ -4,14 +4,17 @@ $(document).on('turbolinks:load', function() {
var $form = $modal.find('form.admin-upload-file-form') var $form = $modal.find('form.admin-upload-file-form')
var $sourceIdInput = $modal.find('input[name="source_id"]'); var $sourceIdInput = $modal.find('input[name="source_id"]');
var $sourceTypeInput = $modal.find('input[name="source_type"]'); var $sourceTypeInput = $modal.find('input[name="source_type"]');
var $suffixInput = $modal.find('input[name="suffix"]');
$modal.on('show.bs.modal', function(event){ $modal.on('show.bs.modal', function(event){
var $link = $(event.relatedTarget); var $link = $(event.relatedTarget);
var sourceId = $link.data('sourceId'); var sourceId = $link.data('sourceId');
var sourceType = $link.data('sourceType'); var sourceType = $link.data('sourceType');
var suffix = $link.data('suffix');
$sourceIdInput.val(sourceId); $sourceIdInput.val(sourceId);
$sourceTypeInput.val(sourceType); $sourceTypeInput.val(sourceType);
if(suffix != undefined){ $suffixInput.val(suffix); }
$modal.find('.upload-file-input').trigger('click'); $modal.find('.upload-file-input').trigger('click');
}); });
@ -48,6 +51,7 @@ $(document).on('turbolinks:load', function() {
contentType: false, contentType: false,
success: function(data){ success: function(data){
$.notify({ message: '上传成功' }); $.notify({ message: '上传成功' });
$modal.find('.file-names').html('');
$modal.trigger('upload:success', data); $modal.trigger('upload:success', data);
$modal.modal('hide'); $modal.modal('hide');
}, },

@ -10,11 +10,41 @@ $(document).on('turbolinks:load', function() {
$searchFrom.find('select[name="status"]').val('processed'); $searchFrom.find('select[name="status"]').val('processed');
if($link.data('value') === 'processed'){ if($link.data('value') === 'processed'){
$('.batch-action-container').hide();
$searchFrom.find('.status-filter').show(); $searchFrom.find('.status-filter').show();
} else { } else {
$('.batch-action-container').show();
$searchFrom.find('.status-filter').hide(); $searchFrom.find('.status-filter').hide();
$searchFrom.find('select[name="status"]').val('pending'); $searchFrom.find('select[name="status"]').val('pending');
} }
}); });
$('.batch-agree-btn').on('click', function(){
if($('.batch-check-box:checked').length === 0){
$.notify({ message: '请先选择数据' }, { type: 'info' });
return;
}
customConfirm({
content: '确认审核通过?',
ok: function(){
var ids = $('.batch-check-box:checked').map(function(_, e){ return $(e).val() }).get();
$.ajax({
url: '/admins/professional_authentications/batch_agree',
method: 'POST',
dataType: 'json',
data: { ids: ids },
success: function(data){
$.notify({ message: '操作成功' });
window.location.reload();
},
error: function(res){
$.notify({ message: res.responseJSON.message }, { type: 'danger' });
}
})
}
})
})
} }
}) })

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

@ -34,10 +34,17 @@ $(document).on('turbolinks:load', function() {
}); });
$('.modal.admin-upload-file-modal').on('upload:success', function(e, data){ $('.modal.admin-upload-file-modal').on('upload:success', function(e, data){
if(data.suffix == '_weapp'){
var $imageElement = $('.shixun-weapp-image-' + data.source_id);
$imageElement.attr('src', data.url);
$imageElement.show();
$imageElement.next().html('重新上传');
} else {
var $imageElement = $('.shixun-image-' + data.source_id); var $imageElement = $('.shixun-image-' + data.source_id);
$imageElement.attr('src', data.url); $imageElement.attr('src', data.url);
$imageElement.show(); $imageElement.show();
$imageElement.next().html('重新上传'); $imageElement.next().html('重新上传');
}
}) })
} }
}); });

@ -5,7 +5,7 @@ $(document).on('turbolinks:load', function() {
allowClear: true allowClear: true
}); });
let search_form = $(".search-form"); var search_form = $(".search-form");
//导出 //导出
$(".shixuns-list-form").on("click","#shixuns-export",function () { $(".shixuns-list-form").on("click","#shixuns-export",function () {
window.location.href = "/admins/shixuns.xls?" + search_form.serialize(); window.location.href = "/admins/shixuns.xls?" + search_form.serialize();

@ -0,0 +1,113 @@
$(document).on('turbolinks:load', function () {
if ($('body.admins-subjects-index-page').length > 0) {
var $form = $('.subject-list-form');
// ************** 学校选择 *************
$form.find('.school-select').select2({
theme: 'bootstrap4',
placeholder: '请选择创建者单位',
minimumInputLength: 1,
ajax: {
delay: 500,
url: '/api/schools/for_option.json',
dataType: 'json',
data: function (params) {
return {keyword: params.term};
},
processResults: function (data) {
return {results: data.schools}
}
},
templateResult: function (item) {
if (!item.id || item.id === '') return item.text;
return item.name;
},
templateSelection: function (item) {
if (item.id) {
}
return item.name || item.text;
}
});
// 清空
$form.on('click', '.clear-btn', function () {
$form.find('select[name="status"]').val('');
$form.find('.school-select').val('').trigger('change');
$form.find('input[name="keyword"]').val('');
$form.find('#homepage_show').attr('checked', false);
$form.find('#excellent').attr('checked', false);
$form.find('input[type="submit"]').trigger('click');
})
// 上传图片
$('.modal.admin-upload-file-modal').on('upload:success', function (e, data) {
if(data.suffix == '_qrcode'){
var $imageElement = $('.subject-weapp-image-' + data.source_id);
$imageElement.attr('src', data.url);
$imageElement.show();
$imageElement.next().html('重新上传');
} else {
var $imageElement = $('.subject-image-' + data.source_id);
$imageElement.attr('src', data.url);
$imageElement.show();
$imageElement.next().html('重新上传');
}
});
// 定义状态切换监听事件
var defineStatusChangeFunc = function (doElement, undoElement, url, callback) {
$('.subject-list-container').on('click', doElement, function () {
var $doAction = $(this);
var $undoAction = $doAction.siblings(undoElement);
var subjectId = $doAction.data('id');
customConfirm({
content: '确认进行该操作吗?',
ok: function () {
$.ajax({
url: '/admins/subjects/' + subjectId + url,
method: 'POST',
dataType: 'json',
success: function () {
show_success_flash();
$doAction.hide();
$undoAction.show();
if (callback && typeof callback === "function") {
callback(subjectId, url);
}
}
});
}
});
});
}
// 隐藏与取消隐藏
defineStatusChangeFunc('.hide-action', '.active-action', '/hide');
defineStatusChangeFunc('.active-action', '.hide-action', '/cancel_hide');
// 首页展示与取消首页展示
var homepageShowCallback = function (subjectId, url) {
var $subjectItem = $('.subject-list-container').find('.subject-item-' + subjectId);
if (url === '/homepage_show') {
$subjectItem.find('.homepage-show-badge').show();
} else {
$subjectItem.find('.homepage-show-badge').hide();
}
}
defineStatusChangeFunc('.homepage-show-action', '.homepage-hide-action', '/homepage_show', homepageShowCallback);
defineStatusChangeFunc('.homepage-hide-action', '.homepage-show-action', '/cancel_homepage_show', homepageShowCallback);
// 设为金课与取消金课
var excellentCallback = function (subjectId, url) {
var $subjectItem = $('.subject-list-container').find('.subject-item-' + subjectId);
if (url === '/excellent') {
$subjectItem.find('.excellent-badge').show();
} else {
$subjectItem.find('.excellent-badge').hide();
}
}
defineStatusChangeFunc('.excellent-action', '.cancel-excellent-action', '/excellent', excellentCallback);
defineStatusChangeFunc('.cancel-excellent-action', '.excellent-action', '/cancel_excellent', excellentCallback);
}
});

@ -0,0 +1,73 @@
$(document).on('turbolinks:load', function() {
if ($('body.admins-user-statistics-index-page').length > 0) {
var $form = $('.user-statistic-list-form');
// ************** 学校选择 *************
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) {
$form.find('.school-select').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) {
$form.find('#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);
}
});
// 清空
$form.on('click', '.clear-btn', function(){
$form.find('select[name="date"]').val('');
$form.find('.school-select').val('').trigger('change');
$form.find('input[type="submit"]').trigger('click');
})
// 导出
$('.export-action').on('click', function(){
var form = $(".user-statistic-list-form .search-form")
var exportLink = $(this);
var date = form.find("select[name='date']").val();
var schoolId = form.find('input[name="school_id"]').val();
var url = exportLink.data("url").split('?')[0] + "?date=" + date + "&school_id=" + schoolId;
window.open(url);
});
}
});

@ -15,7 +15,9 @@ $(document).on('turbolinks:load', function(){
var $unlockAction = $lockAction.siblings('.unlock-action'); var $unlockAction = $lockAction.siblings('.unlock-action');
var userId = $lockAction.data('id'); var userId = $lockAction.data('id');
customConfirm({
content: '确认加锁吗?',
ok: function(){
$.ajax({ $.ajax({
url: '/admins/users/' + userId + '/lock', url: '/admins/users/' + userId + '/lock',
method: 'POST', method: 'POST',
@ -26,6 +28,8 @@ $(document).on('turbolinks:load', function(){
$unlockAction.show(); $unlockAction.show();
} }
}); });
}
});
}); });
// unlock user // unlock user
@ -34,7 +38,9 @@ $(document).on('turbolinks:load', function(){
var $lockAction = $unlockAction.siblings('.lock-action'); var $lockAction = $unlockAction.siblings('.lock-action');
var userId = $unlockAction.data('id'); var userId = $unlockAction.data('id');
customConfirm({
content: '确认解锁吗?',
ok: function () {
$.ajax({ $.ajax({
url: '/admins/users/' + userId + '/unlock', url: '/admins/users/' + userId + '/unlock',
method: 'POST', method: 'POST',
@ -45,6 +51,8 @@ $(document).on('turbolinks:load', function(){
$unlockAction.hide(); $unlockAction.hide();
} }
}); });
}
})
}); });
// active user // active user
@ -54,7 +62,9 @@ $(document).on('turbolinks:load', function(){
var $lockAction = $activeAction.siblings('.lock-action'); var $lockAction = $activeAction.siblings('.lock-action');
var userId = $activeAction.data('id'); var userId = $activeAction.data('id');
customConfirm({
content: '确认激活吗?',
ok: function () {
$.ajax({ $.ajax({
url: '/admins/users/' + userId + '/unlock', url: '/admins/users/' + userId + '/unlock',
method: 'POST', method: 'POST',
@ -66,6 +76,23 @@ $(document).on('turbolinks:load', function(){
$unlockAction.hide(); $unlockAction.hide();
} }
}); });
}
})
});
// reset user login times
$('.users-list-container').on('click', '.reset-login-times-action', function(){
var $action = $(this);
var userId = $action.data('id');
$.ajax({
url: '/admins/users/' + userId + '/reset_login_times',
method: 'POST',
dataType: 'json',
success: function() {
showSuccessNotify();
}
});
}); });
// ***************** reward grade modal ***************** // ***************** reward grade modal *****************

@ -0,0 +1,124 @@
$(document).on('turbolinks:load', function() {
if ($('body.admins-weapp-adverts-index-page').length > 0) {
var resetNo = function(){
$('#adverts-container .advert-item-no').each(function(index, ele){
$(ele).html(index + 1);
})
}
// ------------ 保存链接 -----------
$('.adverts-card').on('click', '.save-data-btn', function(){
var $link = $(this);
var id = $link.data('id');
var link = $('.advert-item-' + id).find('.link-input').val();
$link.attr('disabled', true);
$.ajax({
url: '/admins/weapp_adverts/' + id,
method: 'PATCH',
dataType: 'json',
data: { link: link },
success: function(data){
$.notify({ message: '操作成功' });
},
error: ajaxErrorNotifyHandler,
complete: function(){
$link.removeAttr('disabled');
}
})
});
// -------------- 是否在首页展示 --------------
$('.adverts-card').on('change', '.online-check-box', function(){
var $checkbox = $(this);
var id = $checkbox.data('id');
var checked = $checkbox.is(':checked');
$checkbox.attr('disabled', true);
$.ajax({
url: '/admins/weapp_adverts/' + id,
method: 'PATCH',
dataType: 'json',
data: { online: checked },
success: function(data){
$.notify({ message: '保存成功' });
var box = $('.advert-item-' + id).find('.drag');
if(checked){
box.removeClass('not_active');
}else{
box.addClass('not_active');
}
},
error: ajaxErrorNotifyHandler,
complete: function(){
$checkbox.removeAttr('disabled');
}
})
});
// ------------ 拖拽 -------------
var onDropFunc = function(el, _target, _source, sibling){
var moveId = $(el).data('id');
var insertId = $(sibling).data('id') || '';
$.ajax({
url: '/admins/weapp_adverts/drag',
method: 'POST',
dataType: 'json',
data: { move_id: moveId, after_id: insertId },
success: function(data){
resetNo();
},
error: function(res){
var data = res.responseJSON;
$.notify({message: '移动失败,原因:' + data.message}, {type: 'danger'});
}
})
};
var ele1 = document.getElementById('adverts-container');
dragula([ele1], { mirrorContainer: ele1 }).on('drop', onDropFunc);
// ----------- 新增 --------------
var $createModal = $('.modal.admin-add-weapp-advert-modal');
var $createForm = $createModal.find('form.admin-add-weapp-advert-form');
$createForm.validate({
errorElement: 'span',
errorClass: 'danger text-danger',
rules: {
"weapp_settings_advert[image]": {
required: true
}
}
});
$createModal.on('show.bs.modal', function(event){
resetFileInputFunc($createModal.find('.img-file-input'));
$createModal.find('.file-names').html('选择文件');
});
$createModal.on('click', '.submit-btn', function() {
$createForm.find('.error').html('');
if ($createForm.valid()) {
$createForm.submit();
} else {
$createForm.find('.error').html('请选择图片');
}
});
$createModal.on('change', '.img-file-input', function(){
var file = $(this)[0].files[0];
$createModal.find('.file-names').html(file ? file.name : '请选择文件');
})
// -------------- 重新上传图片 --------------
//replace_image_url
$('.modal.admin-upload-file-modal').on('upload:success', function(e, data){
var $advertItem = $('.advert-item-' + data.source_id);
$advertItem.find('.advert-item-img img').attr('src', data.url);
})
// 删除后
$(document).on('delete_success', resetNo)
}
})

@ -0,0 +1,123 @@
$(document).on('turbolinks:load', function() {
if ($('body.admins-weapp-carousels-index-page').length > 0) {
var resetNo = function(){
$('#carousels-container .custom-carousel-item-no').each(function(index, ele){
$(ele).html(index + 1);
})
}
// ------------ 保存链接 -----------
$('.carousels-card').on('click', '.save-data-btn', function(){
var $link = $(this);
var id = $link.data('id');
var link = $('.custom-carousel-item-' + id).find('.link-input').val();
$link.attr('disabled', true);
$.ajax({
url: '/admins/weapp_carousels/' + id,
method: 'PATCH',
dataType: 'json',
data: { link: link },
success: function(data){
$.notify({ message: '操作成功' });
},
error: ajaxErrorNotifyHandler,
complete: function(){
$link.removeAttr('disabled');
}
})
});
// -------------- 是否在首页展示 --------------
$('.carousels-card').on('change', '.online-check-box', function(){
var $checkbox = $(this);
var id = $checkbox.data('id');
var checked = $checkbox.is(':checked');
$checkbox.attr('disabled', true);
$.ajax({
url: '/admins/weapp_carousels/' + id,
method: 'PATCH',
dataType: 'json',
data: { online: checked },
success: function(data){
$.notify({ message: '保存成功' });
var box = $('.custom-carousel-item-' + id).find('.drag');
if(checked){
box.removeClass('not_active');
}else{
box.addClass('not_active');
}
},
error: ajaxErrorNotifyHandler,
complete: function(){
$checkbox.removeAttr('disabled');
}
})
});
// ------------ 拖拽 -------------
var onDropFunc = function(el, _target, _source, sibling){
var moveId = $(el).data('id');
var insertId = $(sibling).data('id') || '';
$.ajax({
url: '/admins/weapp_carousels/drag',
method: 'POST',
dataType: 'json',
data: { move_id: moveId, after_id: insertId },
success: function(data){
resetNo();
},
error: function(res){
var data = res.responseJSON;
$.notify({message: '移动失败,原因:' + data.message}, {type: 'danger'});
}
})
};
var ele1 = document.getElementById('carousels-container');
dragula([ele1], { mirrorContainer: ele1 }).on('drop', onDropFunc);
// ----------- 新增 --------------
var $createModal = $('.modal.admin-add-weapp-carousel-modal');
var $createForm = $createModal.find('form.admin-add-weapp-carousel-form');
$createForm.validate({
errorElement: 'span',
errorClass: 'danger text-danger',
rules: {
"weapp_settings_carousel[image]": {
required: true
}
}
});
$createModal.on('show.bs.modal', function(event){
resetFileInputFunc($createModal.find('.img-file-input'));
$createModal.find('.file-names').html('选择文件');
});
$createModal.on('click', '.submit-btn', function() {
$createForm.find('.error').html('');
if ($createForm.valid()) {
$createForm.submit();
} else {
$createForm.find('.error').html('请选择图片');
}
});
$createModal.on('change', '.img-file-input', function(){
var file = $(this)[0].files[0];
$createModal.find('.file-names').html(file ? file.name : '请选择文件');
})
// -------------- 重新上传图片 --------------
//replace_image_url
$('.modal.admin-upload-file-modal').on('upload:success', function(e, data){
var $carouselItem = $('.custom-carousel-item-' + data.source_id);
$carouselItem.find('.custom-carousel-item-img img').attr('src', data.url);
})
// 删除后
$(document).on('delete_success', resetNo)
}
})

File diff suppressed because it is too large Load Diff

@ -22,9 +22,9 @@ $.fn.bootstrapViewer = function (options) {
' <div class="modal-dialog modal-lg" style="display: inline-block; width: auto;">\n' + ' <div class="modal-dialog modal-lg" style="display: inline-block; width: auto;">\n' +
' <div class="modal-content">\n' + ' <div class="modal-content">\n' +
' <img' + ' <img' +
'\t\t\t class="carousel-inner img-responsive img-rounded img-viewer" \n' + '\t\t\t class="carousel-inner img-responsive img-rounded img-viewer" draggable="false"\n' +
'\t\t\t onclick="$(\'#bootstrapViewer\').modal(\'hide\');setTimeout(function(){$(\'#bootstrapViewer\').remove();},200);"\n' + '\t\t\t onclick="/*$(\'#bootstrapViewer\').modal(\'hide\');setTimeout(function(){$(\'#bootstrapViewer\').remove();},200);*/"\n' +
'\t\t\t onmouseover="this.style.cursor=\'zoom-out\';" \n' + '\t\t\t onmouseover="this.style.cursor=\'move\';" \n' +
'\t\t\t onmouseout="this.style.cursor=\'default\'" \n' + '\t\t\t onmouseout="this.style.cursor=\'default\'" \n' +
'\t\t\t />\n' + '\t\t\t />\n' +
' </div>\n' + ' </div>\n' +
@ -37,13 +37,41 @@ $.fn.bootstrapViewer = function (options) {
} else { } else {
throw "图片不存在" throw "图片不存在"
} }
$('#bootstrapViewer').on('hidden.bs.modal', function(){
$('#bootstrapViewer').remove();
});
var $moveDiv = $('#bootstrapViewer .modal-dialog');
var isMove = false;
var div_x = $moveDiv.offset().left;
var div_y = $moveDiv.offset().top;
var mousedownFunc = function (e) {
if (isMove) {
var left = e.pageX - div_x;
var top = e.pageY - div_y;
if(left < 0){ left = 0}
if(top < 0){ top = 0}
$moveDiv.css({"left": left, "top":top});
}
}
$moveDiv.mousedown(function (e) {
$moveDiv.css({ left: $moveDiv[0].offsetLeft, top: $moveDiv[0].offsetTop, marginTop: 0, position: 'absolute' });
isMove = true;
div_x = e.pageX - $moveDiv.offset().left;
div_y = e.pageY - $moveDiv.offset().top;
$(document).mousemove(mousedownFunc);
}).mouseup(function () {
isMove = false;
$(document).unbind('mousemove', mousedownFunc);
});
}) })
$(this).on('mouseover', function () { $(this).on('mouseover', function () {
$(this).css('cursor', 'zoom-in'); $(this).css('cursor', 'zoom-in');
}) })
} }
$.fn.bootstrapViewer.defaults = { $.fn.bootstrapViewer.defaults = {
src: 'src' src: 'src'

@ -43,3 +43,55 @@ function resetFileInputFunc(file){
file.after(file.clone().val("")); file.after(file.clone().val(""));
file.remove(); file.remove();
} }
function customConfirm(opts){
var okCallback = opts.ok;
var cancelCallback = opts.cancel;
var defaultOpts = {
title: '提示',
buttons: {
ok: {
text: '确认',
btnClass: 'btn btn-primary',
action: okCallback
},
cancel: {
text: '取消',
btnClass: 'btn btn-secondary',
action: cancelCallback
},
}
}
return $.confirm($.extend({}, defaultOpts, opts))
}
function customLoading(opts) {
var loading;
var defaultOpts = {
content: opts.ajax,
contentLoaded: function(){
setTimeout(function(){
loading.close()
}, 200);
}
}
loading = $.confirm($.extend({}, defaultOpts, opts));
return loading;
}
function show_success_flash(message){
$.notify({
message: message || '操作成功'
},{
type: 'success'
});
}
function showErrorNotify(message){
$.notify({
message: message || '操作失败'
},{
type: 'danger'
});
}

@ -0,0 +1,92 @@
//= require rails-ujs
//= require activestorage
//= require turbolinks
//= require jquery3
//= require popper
//= require bootstrap-sprockets
//= require jquery.validate.min
//= require additional-methods.min
//= require bootstrap-notify
//= require jquery.cookie.min
//= require select2
//= require jquery.cxselect
//= require bootstrap-datepicker
//= require bootstrap-datetimepicker
//= require bootstrap.viewer
//= require jquery.mloading
//= require jquery-confirm.min
//= require common
//= require echarts
//= require codemirror/lib/codemirror
//= require codemirror/mode/shell/shell
//= require editormd/editormd
//= require editormd/languages/zh-tw
//= require dragula/dragula
//= require_tree ./i18n
//= require_tree ./cooperative
$.ajaxSetup({
beforeSend: function(xhr) {
xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'));
}
});
// ******** select2 global config ********
$.fn.select2.defaults.set('theme', 'bootstrap4');
$.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({ trigger : 'hover' });
$('[data-toggle="popover"]').popover();
// 图片查看大图
$('img.preview-image').bootstrapViewer();
// flash alert提示框自动关闭
if($('.cooperative-alert-container .alert').length > 0){
setTimeout(function(){
$('.cooperative-alert-container .alert:not(.alert-danger)').alert('close');
}, 2000);
setTimeout(function(){
$('.cooperative-alert-container .alert.alert-danger').alert('close');
}, 5000);
}
});
$(document).on("turbolinks:before-cache", function () {
$('[data-toggle="tooltip"]').tooltip('hide');
$('[data-toggle="popover"]').popover('hide');
});
// var progressBar = new Turbolinks.ProgressBar();
// $(document).on('ajax:send', function(event){
// console.log('ajax send', event);
// progressBar.setValue(0)
// progressBar.show()
// });
//
// $(document).on('ajax:complete', function(event){
// console.log('ajax complete', event);
// progressBar.setValue(1)
// progressBar.hide() // 分页时不触发,奇怪
// });
// $(document).on('ajax:success', function(event){
// console.log('ajax success', event);
// });
// $(document).on('ajax:error', function(event){
// console.log('ajax error', event);
// });
$(function () {
});

@ -0,0 +1,130 @@
$(document).on('turbolinks:load', function() {
if ($('body.cooperative-carousels-index-page').length > 0) {
var resetNo = function(){
$('#carousels-container .custom-carousel-item-no').each(function(index, ele){
$(ele).html(index + 1);
})
}
// 删除后
$(document).on('delete_success', resetNo);
// ------------ 保存链接 -----------
$('.carousels-card').on('click', '.save-data-btn', function(){
var $link = $(this);
var id = $link.data('id');
var link = $('.custom-carousel-item-' + id).find('.link-input').val();
var name = $('.custom-carousel-item-' + id).find('.name-input').val();
if(!name || name.length == 0){
$.notify({ message: '名称不能为空' },{ type: 'danger' });
return;
}
$link.attr('disabled', true);
$.ajax({
url: '/cooperative/carousels/' + id,
method: 'PATCH',
dataType: 'json',
data: { link: link, name: name },
success: function(data){
$.notify({ message: '操作成功' });
},
error: ajaxErrorNotifyHandler,
complete: function(){
$link.removeAttr('disabled');
}
})
});
// -------------- 是否在首页展示 --------------
$('.carousels-card').on('change', '.online-check-box', function(){
var $checkbox = $(this);
var id = $checkbox.data('id');
var checked = $checkbox.is(':checked');
$checkbox.attr('disabled', true);
$.ajax({
url: '/cooperative/carousels/' + id,
method: 'PATCH',
dataType: 'json',
data: { status: checked },
success: function(data){
$.notify({ message: '保存成功' });
var box = $('.custom-carousel-item-' + id).find('.drag');
if(checked){
box.removeClass('not_active');
}else{
box.addClass('not_active');
}
},
error: ajaxErrorNotifyHandler,
complete: function(){
$checkbox.removeAttr('disabled');
}
})
});
// ------------ 拖拽 -------------
var onDropFunc = function(el, _target, _source, sibling){
var moveId = $(el).data('id');
var insertId = $(sibling).data('id') || '';
$.ajax({
url: '/cooperative/carousels/drag',
method: 'POST',
dataType: 'json',
data: { move_id: moveId, after_id: insertId },
success: function(data){
resetNo();
},
error: function(res){
var data = res.responseJSON;
$.notify({message: '移动失败,原因:' + data.message}, {type: 'danger'});
}
})
};
var ele1 = document.getElementById('carousels-container');
dragula([ele1], { mirrorContainer: ele1 }).on('drop', onDropFunc);
// ----------- 新增 --------------
var $createModal = $('.modal.cooperative-add-carousel-modal');
var $createForm = $createModal.find('form.cooperative-add-carousel-form');
$createForm.validate({
errorElement: 'span',
errorClass: 'danger text-danger',
rules: {
"portal_image[image]": {
required: true
},
"portal_image[name]": {
required: true
},
}
});
$createModal.on('show.bs.modal', function(event){
resetFileInputFunc($createModal.find('.img-file-input'));
$createModal.find('.file-names').html('选择文件');
});
$createModal.on('click', '.submit-btn', function() {
$createForm.find('.error').html('');
if ($createForm.valid()) {
$createForm.submit();
} else {
$createForm.find('.error').html('请选择图片');
}
});
$createModal.on('change', '.img-file-input', function(){
var file = $(this)[0].files[0];
$createModal.find('.file-names').html(file ? file.name : '请选择文件');
})
// -------------- 重新上传图片 --------------
//replace_image_url
$('.modal.cooperative-upload-file-modal').on('upload:success', function(e, data){
var $carouselItem = $('.custom-carousel-item-' + data.source_id);
$carouselItem.find('.custom-carousel-item-img img').attr('src', data.url);
})
}
})

@ -0,0 +1,86 @@
$(document).on('turbolinks:load', function() {
if ($('body.cooperative-laboratory-settings-edit-page, body.cooperative-laboratory-settings-update-page').length > 0) {
var $container = $('.edit-laboratory-setting-container');
var $form = $container.find('.edit_laboratory');
$('.logo-item-left').on("change", 'input[type="file"]', function () {
var $fileInput = $(this);
var file = this.files[0];
var imageType = /image.*/;
if (file && file.type.match(imageType)) {
var reader = new FileReader();
reader.onload = function () {
var $box = $fileInput.parent();
$box.find('img').attr('src', reader.result).css('display', 'block');
$box.addClass('has-img');
};
reader.readAsDataURL(file);
} else {
}
});
createMDEditor('laboratory-footer-editor', { height: 200, placeholder: '请输入备案信息' });
$form.validate({
errorElement: 'span',
errorClass: 'danger text-danger',
errorPlacement:function(error,element){
if(element.parent().hasClass("input-group")){
element.parent().after(error);
}else{
element.after(error)
}
},
rules: {
identifier: {
required: true,
checkSite: true
},
name: {
required: true
}
}
});
$.validator.addMethod("checkSite",function(value,element,params){
var checkSite = /^(?=^.{3,255}$)[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+$/;
return this.optional(element)||(checkSite.test(value + '.educoder.com'));
},"域名不合法!");
$form.on('click', '.submit-btn', function(){
$form.find('.submit-btn').attr('disabled', 'disabled');
$form.find('.error').html('');
var valid = $form.valid();
$('input[name="navbar[][name]"]').each(function(_, e){
var $ele = $(e);
if($ele.val() === undefined || $ele.val().length === 0){
$ele.addClass('danger text-danger');
valid = false;
} else {
$ele.removeClass('danger text-danger');
}
});
if(!valid) return;
$.ajax({
method: 'PATCH',
dataType: 'json',
url: $form.attr('action'),
data: new FormData($form[0]),
processData: false,
contentType: false,
success: function(data){
$.notify({ message: '保存成功' });
window.location.reload();
},
error: function(res){
var data = res.responseJSON;
$form.find('.error').html(data.message);
},
complete: function(){
$form.find('.submit-btn').attr('disabled', false);
}
});
})
}
});

@ -0,0 +1,62 @@
$(document).on('turbolinks:load', function() {
if ($('body.cooperative-laboratory-users-index-page').length > 0) {
// ============= 添加管理员 ==============
var $addMemberModal = $('.cooperative-add-laboratory-user-modal');
var $addMemberForm = $addMemberModal.find('.cooperative-add-laboratory-user-form');
var $memberSelect = $addMemberModal.find('.laboratory-user-select');
$addMemberModal.on('show.bs.modal', function(event){
$memberSelect.select2('val', ' ');
});
$memberSelect.select2({
theme: 'bootstrap4',
placeholder: '请输入要添加的管理员姓名',
multiple: true,
minimumInputLength: 1,
ajax: {
delay: 500,
url: '/cooperative/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 $("<span>" + item.real_name + " <span class='font-12'>" + item.school_name + ' ' + item.hidden_phone + "</span></span>");
},
templateSelection: function(item){
if (item.id) {
}
return item.real_name || item.text;
}
});
$addMemberModal.on('click', '.submit-btn', function(){
$addMemberForm.find('.error').html('');
var memberIds = $memberSelect.val();
if (memberIds && memberIds.length > 0) {
$.ajax({
method: 'POST',
dataType: 'json',
url: '/cooperative/laboratory_users',
data: { user_ids: memberIds },
success: function(data){
if(data && data.status == 0){
show_success_flash();
$addMemberModal.modal('hide');
window.location.reload();
}
}
});
} else {
$addMemberModal.modal('hide');
}
});
}
});

@ -0,0 +1,62 @@
$(document).on('turbolinks:load', function() {
var $modal = $('.modal.cooperative-upload-file-modal');
if ($modal.length > 0) {
var $form = $modal.find('form.cooperative-upload-file-form')
var $sourceIdInput = $modal.find('input[name="source_id"]');
var $sourceTypeInput = $modal.find('input[name="source_type"]');
$modal.on('show.bs.modal', function(event){
var $link = $(event.relatedTarget);
var sourceId = $link.data('sourceId');
var sourceType = $link.data('sourceType');
$sourceIdInput.val(sourceId);
$sourceTypeInput.val(sourceType);
$modal.find('.upload-file-input').trigger('click');
});
$modal.find('.upload-file-input').on('change', function(e){
var file = $(this)[0].files[0];
if(file){
$modal.find('.file-names').html(file.name);
$modal.find('.submit-btn').trigger('click');
}
})
var formValid = function(){
if($form.find('input[name="file"]').val() == undefined || $form.find('input[name="file"]').val().length == 0){
$form.find('.error').html('请选择文件');
return false;
}
return true;
};
$modal.on('click', '.submit-btn', function(){
$form.find('.error').html('');
if (formValid()) {
var formDataString = $form.serialize();
$.ajax({
method: 'POST',
dataType: 'json',
url: '/cooperatives/files?' + formDataString,
data: new FormData($form[0]),
processData: false,
contentType: false,
success: function(data){
$.notify({ message: '上传成功' });
$modal.trigger('upload:success', data);
$modal.modal('hide');
},
error: function(res){
var data = res.responseJSON;
$form.find('.error').html(data.message);
}
});
}
});
}
});

@ -0,0 +1,16 @@
$(document).on('turbolinks:load', function(){
$('#sidebarCollapse').on('click', function () {
$(this).toggleClass('active');
$('#sidebar').toggleClass('active');
$.cookie('cooperative_sidebar_collapse', $(this).hasClass('active'), {path: '/cooperative'});
});
var sidebarController = $('#sidebar').data('current-controller');
if (sidebarController.length > 0) {
$('#sidebar a.active').removeClass('active');
$('#sidebar ul.collapse.show').removeClass('show');
var activeLi = $('#sidebar a[data-controller="' + sidebarController + '"]');
activeLi.addClass('active');
activeLi.parent().parent('ul.collapse').addClass('show');
}
});

@ -0,0 +1,2 @@
// Place all the behaviors and hooks related to the matching controller here.
// All this logic will automatically be available in application.js.

@ -0,0 +1,16 @@
/**
* Simplified Chinese translation for bootstrap-datetimepicker
* Yuan Cheung <advanimal@gmail.com>
*/
;(function($){
$.fn.datetimepicker.dates['zh-CN'] = {
days: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"],
daysShort: ["周日", "周一", "周二", "周三", "周四", "周五", "周六", "周日"],
daysMin: ["日", "一", "二", "三", "四", "五", "六", "日"],
months: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],
monthsShort: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],
today: "今天",
suffix: [],
meridiem: ["上午", "下午"]
};
}(jQuery));

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1,2 @@
// Place all the behaviors and hooks related to the matching controller here.
// All this logic will automatically be available in application.js.

@ -6,6 +6,8 @@
@import "bootstrap-datepicker"; @import "bootstrap-datepicker";
@import "bootstrap-datepicker.standalone"; @import "bootstrap-datepicker.standalone";
@import "jquery.mloading"; @import "jquery.mloading";
@import "jquery-confirm.min";
@import "bootstrap-datetimepicker.min";
@import "codemirror/lib/codemirror"; @import "codemirror/lib/codemirror";
@import "editormd/css/editormd.min"; @import "editormd/css/editormd.min";
@ -50,4 +52,4 @@ input.form-control {
right:20px; right:20px;
position: absolute; position: absolute;
} }
.position-r{position:relative;}

@ -0,0 +1,66 @@
.admins-auth-schools-index-page{
.list-item-title{
padding-bottom:5px;
padding-left: 33px;
color: #555;
}
.list-item-title-1{
width: 100px;
display: inline-block;
}
.list-item-title-2{
width: 200px;
display: inline-block;
}
.collegeManage{
float: left;
padding: 0px 8px;
border-radius: 6px;
background-color: #f5f5f5;
margin: 3px 0px 3px 10px;
height: 34px;
line-height: 34px;
a{
color: #05101a;
}
a:hover{
color: #007bff;
}
}
i:hover{
color: #333;
}
.add-manager-i{
float: left;
i{
padding: 10px 5px;
}
}
.auth-schools-new-add, .auth-schools-user-add{
.flex-column{
input{
height: 38px;
}
}
.search-school{
margin-left: 15px;
}
}
.school-search-list{
background: #F4FAFF;
height: 280px;
overflow-y: scroll;
padding: 10px 0;
}
.school-list-item{
padding: 2px 10px;
input{
font-size: 20px;
margin-right: 5px;
}
}
}

@ -0,0 +1,60 @@
.admins-carousels-index-page {
.carousels-card {
.custom-carousel-item {
& > .drag {
cursor: move;
background: #fff;
box-shadow: 1px 2px 5px 3px #f0f0f0;
}
&-no {
font-size: 28px;
text-align: center;
}
&-img {
cursor: pointer;
width: 100%;
height: 60px;
& > img {
display: block;
width: 100%;
height: 60px;
background: #F5F5F5;
}
}
.not_active {
background: #F0F0F0;
}
.delete-btn {
font-size: 20px;
color: red;
cursor: pointer;
}
.save-url-btn {
cursor: pointer;
}
.operate-box {
display: flex;
justify-content: space-between;
align-items: center;
}
.online-check-box {
font-size: 20px;
}
.name-input {
flex: 1;
}
.link-input {
flex: 3;
}
}
}
}

@ -48,9 +48,15 @@
} }
.action-container { .action-container {
.action { & > .action {
padding: 0 3px; padding: 0 3px;
} }
.more-action-dropdown {
.dropdown-item {
font-size: 14px;
}
}
} }
/* 分页 */ /* 分页 */
@ -110,5 +116,11 @@
.CodeMirror { .CodeMirror {
border: 1px solid #ced4da; border: 1px solid #ced4da;
} }
.batch-action-container {
margin-bottom: -15px;
padding: 10px 20px 0;
background: #fff;
}
} }

@ -0,0 +1,116 @@
.admins-competition-settings-index-page {
.competition-mode-container {
.row {
height: 35px;
}
.des-row {
height: auto;
}
.form-control {
font-size: 14px;
}
//.mode-input {
// input {
// width: 40%;
// }
//}
}
.col-md-label{
-webkit-box-flex: 0;
flex: 0 0 10%;
max-width: 10%;
min-width: 30px;
padding-right: 15px;
padding-left: 15px;
position: relative;
}
.col-md-label-s{
-webkit-box-flex: 0;
flex: 0 0 30px;
padding-right: 15px;
padding-left: 15px;
position: relative;
}
.setBtn_s{
height: 35px;
line-height: 20px;
}
.sponsor_label{
border:1px solid #4CACFF;
border-radius: 5px;
background-color: rgba(76,172,255,0.3);
color: #333;
padding:0px 4px;
height: 30px;
line-height: 30px;
float: left;
margin: 4px 5px;
span{
display: block;
float: left;
height: 28px;
line-height: 28px;
margin-right: 5px;
}
a{
font-size: 18px;
float: left;
height: 28px;
line-height: 28px;
}
}
.large_panel{
padding:0px 15px;
.large_panel_part{
border-top: 1px solid #eaeaea;
}
.large_panel_part:first-child{
border:none;
}
.large_panel_part >.row ,.small_panel >.row{
border-bottom: 1px solid #eaeaea;
padding:20px 0px;
}
.small_panel{
margin-left: 20px;
}
.row:last-child{
border:none;
}
.task_Input_div:nth-child(3n-2) > span.col-4{
flex: 0 0 81px;
max-width: 81px;
}
.task_Input_div:nth-child(3n-2){
flex: 0 0 50%;
max-width: 50%;
}
.task_Input_div:nth-child(3n-1){
flex: 0 0 25%;
max-width: 25%;
}
.task_Input_div:nth-child(3n){
flex: 0 0 25%;
max-width: 25%;
}
.task_Input_div:nth-child(3n) > span.col-4{
flex: 0 0 33.3%;
max-width: 33.3%;
}
.task_Input_div:nth-child(3n) > div.col-6{
flex: 0 0 50%;
max-width: 50%;
}
}
}

@ -0,0 +1,22 @@
.admins-ec-templates-index-page{
.template-file-upload{
padding: 10px;
background: #fafafa;
border: 1px dashed #ccc;
text-align: center;
color: #999;
position: relative;
width: 100%;
}
input[name='file']{
opacity: 0;
position: absolute;
display: inline-block;
left: 0;
height: 43px;
top: 0;
width:100%;
cursor: pointer;
}
}

@ -0,0 +1,100 @@
.admins-laboratories-index-page {
.laboratory-list-table {
.member-container {
.laboratory-user {
display: flex;
justify-content: center;
flex-wrap: wrap;
.laboratory-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;
}
}
}
}
}
.admins-laboratory-settings-show-page, .admins-laboratory-settings-update-page {
.edit-laboratory-setting-container {
.logo-item {
display: flex;
&-img {
display: block;
width: 80px;
height: 80px;
background: #f0f0f0;
}
&-upload {
cursor: pointer;
position: absolute;
top: 0;
width: 80px;
height: 80px;
background: #F5F5F5;
border: 1px solid #E5E5E5;
&::before {
content: '';
position: absolute;
top: 27px;
left: 39px;
width: 2px;
height: 26px;
background: #E5E5E5;
}
&::after {
content: '';
position: absolute;
top: 39px;
left: 27px;
width: 26px;
height: 2px;
background: #E5E5E5;
}
}
&-left {
position: relative;
width: 80px;
height: 80px;
&.has-img {
.logo-item-upload {
display: none;
}
&:hover {
.logo-item-upload {
display: block;
background: rgba(145, 145, 145, 0.8);
}
}
}
}
&-right {
display: flex;
flex-direction: column;
justify-content: space-between;
color: #777777;
font-size: 12px;
}
&-title {
color: #23272B;
font-size: 14px;
}
}
}
}

@ -0,0 +1,37 @@
.admins-major-informations-index-page{
.fr{
float:right;
}
.panel-default{
margin-bottom: 10px;
background-color: rgb(245, 245, 245);
.panel-heading{
i{
margin-right:15px;
font-size:16px;
color:rgb(204, 204, 204);
}
a{
padding: 8px 10px;
display: inline-block;
width:100%;
color:rgb(102, 102, 102);
}
}
.panel-collapse{
padding-top: 10px;
background: #fff;
table{
text-align:center;
th,td{
padding: 8px;
}
td{
color:#888;
}
}
}
}
}

@ -0,0 +1,3 @@
.admins-schools-index-page {
}

@ -21,9 +21,12 @@
flex-direction: column; flex-direction: column;
&-logo { &-logo {
padding-left: 5px;
overflow: hidden; overflow: hidden;
margin-bottom: 10px; margin-bottom: 10px;
& > .logo-label {
display: none;
}
} }
} }
@ -76,6 +79,23 @@
display: flex; display: flex;
flex-direction: row; flex-direction: row;
justify-content: space-between; justify-content: space-between;
&-logo {
display: flex;
justify-content: space-between;
align-items: center;
& > img {
width: 40px;
height: auto;
}
& > .logo-label {
font-size: 18px;
color: darkgrey;
margin-left: 10px;
}
}
} }
#sidebarCollapse { #sidebarCollapse {

@ -0,0 +1,60 @@
.admins-weapp-adverts-index-page {
.adverts-card {
.advert-item {
& > .drag {
cursor: move;
background: #fff;
box-shadow: 1px 2px 5px 3px #f0f0f0;
}
&-no {
font-size: 28px;
text-align: center;
}
&-img {
cursor: pointer;
width: 100%;
height: 60px;
& > img {
display: block;
width: 100%;
height: 60px;
background: #F5F5F5;
}
}
.not_active {
background: #F0F0F0;
}
.delete-btn {
font-size: 20px;
color: red;
cursor: pointer;
}
.save-url-btn {
cursor: pointer;
}
.operate-box {
display: flex;
justify-content: space-between;
align-items: center;
}
.online-check-box {
font-size: 20px;
}
.name-input {
flex: 1;
}
.link-input {
flex: 3;
}
}
}
}

@ -0,0 +1,60 @@
.admins-weapp-carousels-index-page {
.carousels-card {
.custom-carousel-item {
& > .drag {
cursor: move;
background: #fff;
box-shadow: 1px 2px 5px 3px #f0f0f0;
}
&-no {
font-size: 28px;
text-align: center;
}
&-img {
cursor: pointer;
width: 100%;
height: 60px;
& > img {
display: block;
width: 100%;
height: 60px;
background: #F5F5F5;
}
}
.not_active {
background: #F0F0F0;
}
.delete-btn {
font-size: 20px;
color: red;
cursor: pointer;
}
.save-url-btn {
cursor: pointer;
}
.operate-box {
display: flex;
justify-content: space-between;
align-items: center;
}
.online-check-box {
font-size: 20px;
}
.name-input {
flex: 1;
}
.link-input {
flex: 3;
}
}
}
}

@ -1,16 +0,0 @@
/*
* This is a manifest file that'll be compiled into application.css, which will include all the files
* listed below.
*
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's
* vendor/assets/stylesheets directory can be referenced here using a relative path.
*
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
* compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
* files in this directory. Styles in this file should be added after the last require_* statement.
* It is generally better to create a new file per style scope.
*
*= require_tree .
*= require_self
*/

File diff suppressed because one or more lines are too long

@ -29,8 +29,30 @@ input.form-control {
.flex-1 { .flex-1 {
flex: 1; flex: 1;
} }
.fl{float: left}
.no_padding{padding: 0px!important;}
.font-12 { font-size: 12px !important; } .font-12 { font-size: 12px !important; }
.font-14 { font-size: 14px !important; } .font-14 { font-size: 14px !important; }
.font-16 { font-size: 16px !important; } .font-16 { font-size: 16px !important; }
.font-18 { font-size: 18px !important; } .font-18 { font-size: 18px !important; }
.font-20 { font-size: 20px !important; }
.font-24 { font-size: 24px !important; }
.padding10-5 { padding: 10px 5px;}
.width100 { width: 100%;}
.mb10 { margin-bottom: 10px ;}
.mt10 { margin-top: 10px ;}
.mr10{ margin-right: 10px; }
.ml10{ margin-left: 10px; }.ml20{ margin-left: 20px; }
.textarea-width-100{width:100%; resize: none; border: 1px solid #ccc;}
.padding10{padding: 10px;}
.padding5-10{padding: 5px 10px;}
.position-r{position:relative;}
.color-grey-c{color:#ccc}
.color-blue{color:#4CACFF}
.color-orange{color: #ff6800}
.inline-block{display:inline-block;}
.hide{display: none;}
.show{display: block;}
.input_small{flex: 0 0 6%!important;}
.input_middle{flex:0 0 13%!important;}

@ -0,0 +1,54 @@
@import "bootstrap";
@import "font-awesome-sprockets";
@import "font-awesome";
@import "select2.min";
@import "select2-bootstrap4.min";
@import "bootstrap-datepicker";
@import "bootstrap-datepicker.standalone";
@import "jquery.mloading";
@import "jquery-confirm.min";
@import "codemirror/lib/codemirror";
@import "editormd/css/editormd.min";
@import "dragula/dragula";
@import "common";
@import "cooperative/*";
body {
width: 100vw;
height: 100vh;
max-width: 100vw;
max-height: 100vh;
display: flex;
align-items: stretch;
font-size: 14px;
background: #efefef;
overflow: hidden;
}
.simple_form {
.form-group {
.collection_radio_buttons {
margin-bottom: 0px;
}
.form-check-inline {
height: calc(1.5em + 0.75rem + 2px)
}
}
}
input.form-control {
font-size: 14px;
}
.btn-default{
color: #666;
background: #e1e1e1!important;
}
.export-absolute{
right:20px;
position: absolute;
}

@ -0,0 +1,60 @@
.cooperative-carousels-index-page {
.carousels-card {
.custom-carousel-item {
& > .drag {
cursor: move;
background: #fff;
box-shadow: 1px 2px 5px 3px #f0f0f0;
}
&-no {
font-size: 28px;
text-align: center;
}
&-img {
cursor: pointer;
width: 100%;
height: 60px;
& > img {
display: block;
width: 100%;
height: 60px;
background: #F5F5F5;
}
}
.not_active {
background: #F0F0F0;
}
.delete-btn {
font-size: 20px;
color: red;
cursor: pointer;
}
.save-url-btn {
cursor: pointer;
}
.operate-box {
display: flex;
justify-content: space-between;
align-items: center;
}
.online-check-box {
font-size: 20px;
}
.name-input {
flex: 1;
}
.link-input {
flex: 3;
}
}
}
}

@ -0,0 +1,126 @@
.cooperative-body-container {
padding: 20px;
flex: 1;
min-height: 100vh;
display: flex;
flex-direction: column;
overflow-y: scroll;
& > .content {
flex: 1;
font-size: 14px;
.box {
padding: 20px;
border-radius: 5px;
background: #fff;
}
}
/* 面包屑 */
.breadcrumb {
padding-left: 5px;
font-size: 20px;
background: unset;
}
/* 内容表格 */
table {
table-layout: fixed;
td {
vertical-align: middle;
}
tr {
&.no-data {
&:hover {
color: darkgrey;
background: unset;
}
& > td {
text-align: center;
height: 300px;
}
}
}
}
.action-container {
& > .action {
padding: 0 3px;
}
.more-action-dropdown {
.dropdown-item {
font-size: 14px;
}
}
}
/* 分页 */
.paginate-container {
margin-top: 20px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.paginate-total {
margin-bottom: 10px;
color: darkgrey;
}
.pagination {
margin-bottom: 0px;
}
}
/* 搜索表单 */
.search-form-container {
display: flex;
margin-bottom: 20px;
.search-form {
flex: 1;
* { font-size: 14px; }
select, input {
margin-right: 10px;
font-size: 14px;
}
}
}
.global-error {
color: grey;
min-height: 300px;
&-code {
font-size: 80px;
}
&-text {
font-size: 24px;
}
}
.nav-tabs {
.nav-link {
padding: 0.5rem 2rem;
}
}
.CodeMirror {
border: 1px solid #ced4da;
}
.batch-action-container {
margin-bottom: -15px;
padding: 10px 20px 0;
background: #fff;
}
}

@ -0,0 +1,76 @@
.cooperative-laboratory-settings-edit-page, .cooperative-laboratory-settings-update-page {
.edit-laboratory-setting-container {
.logo-item {
display: flex;
&-img {
display: block;
width: 80px;
height: 80px;
background: #f0f0f0;
}
&-upload {
cursor: pointer;
position: absolute;
top: 0;
width: 80px;
height: 80px;
background: #F5F5F5;
border: 1px solid #E5E5E5;
&::before {
content: '';
position: absolute;
top: 27px;
left: 39px;
width: 2px;
height: 26px;
background: #E5E5E5;
}
&::after {
content: '';
position: absolute;
top: 39px;
left: 27px;
width: 26px;
height: 2px;
background: #E5E5E5;
}
}
&-left {
position: relative;
width: 80px;
height: 80px;
&.has-img {
.logo-item-upload {
display: none;
}
&:hover {
.logo-item-upload {
display: block;
background: rgba(145, 145, 145, 0.8);
}
}
}
}
&-right {
display: flex;
flex-direction: column;
justify-content: space-between;
color: #777777;
font-size: 12px;
}
&-title {
color: #23272B;
font-size: 14px;
}
}
}
}

@ -0,0 +1,235 @@
#sidebar {
min-width: 200px;
max-width: 200px;
background: #272822;
color: #fff;
transition: all 0.5s;
overflow-y: scroll;
&::-webkit-scrollbar {
display:none
}
&.active {
min-width: 60px;
max-width: 60px;
text-align: center;
.sidebar-header {
padding: 10px;
display: flex;
flex-direction: column;
&-logo {
overflow: hidden;
margin-bottom: 10px;
& > .logo-label {
display: none;
}
}
}
ul li a {
padding: 10px;
text-align: center;
font-size: 0.85em;
display: flex;
justify-content: center;
span { display: none }
i {
margin-right: 0;
display: block;
font-size: 1.8em;
margin-bottom: 5px;
width: 30px;
height: 20px;
}
}
.dropdown-toggle::after {
top: auto;
bottom: 10px;
right: 50%;
-webkit-transform: translateX(50%);
-ms-transform: translateX(50%);
transform: translateX(50%);
}
ul ul a {
padding: 10px !important;
span { display: none }
i {
margin-left: 0px;
display: block;
font-size: 0.8em;
width: 30px;
height: 10px;
}
}
}
.sidebar-header {
padding: 20px;
background: #272822;
display: flex;
flex-direction: row;
justify-content: space-between;
&-logo {
display: flex;
justify-content: space-between;
align-items: center;
& > img {
width: 40px;
height: auto;
}
& > .logo-label {
font-size: 18px;
color: darkgrey;
margin-left: 10px;
}
}
}
#sidebarCollapse {
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
text-align: right;
&.active {
width: 40px;
height: 30px;
background: #3f3f3f;
border: 1px solid grey;
border-radius: 3px;
i.fold { display: none; }
i.unfold { display: block; }
}
i.fold {
display: block;
}
i.unfold { display: none; }
}
a, a:hover, a:focus {
color: inherit;
text-decoration: none;
transition: all 0.3s;
}
& > ul > li > a > i {
width: 14px;
height: 14px;
}
ul {
&.components {
padding: 20px 0;
border-bottom: 1px solid #3f3f3f;
}
p {
color: #fff;
padding: 10px;
}
li > a {
padding: 10px;
font-size: 1em;
display: block;
text-align: left;
i {
margin-right: 10px;
font-size: 1em;
margin-bottom: 5px;
}
}
li a {
&:hover, &.active {
color: #fff;
background: #276891;
}
}
li.active > a, a[aria-expanded="true"] {
color: #fff;
//background: #276891;
}
ul a {
font-size: 0.9em !important;
padding-left: 30px !important;
background: #3f3f3f;
}
}
}
@media (max-width: 768px) {
#sidebar {
&.active {
padding: 10px 5px;
min-width: 40px;
max-width: 40px;
text-align: center;
margin-left: 0;
transform: none;
.sidebar-header {
padding: 0px;
.sidebar-header-logo {
display: none;
}
#sidebarCollapse {
width: 30px;
height: 20px;
}
}
ul li a {
padding: 10px;
font-size: 0.85em;
i {
margin-right: 0;
display: block;
margin-bottom: 5px;
}
}
& > ul > li > a > i {
font-size: 1.8em;
}
ul ul a {
padding: 10px !important;
}
}
.sidebar-header {
}
}
.dropdown-toggle::after {
top: auto;
bottom: 10px;
right: 50%;
-webkit-transform: translateX(50%);
-ms-transform: translateX(50%);
transform: translateX(50%);
}
}

@ -0,0 +1,3 @@
// Place all the styles related to the course_stages controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

File diff suppressed because one or more lines are too long

@ -0,0 +1,3 @@
// Place all the styles related to the subject_lists controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

@ -33,7 +33,7 @@ class AccountsController < ApplicationController
uid_logger("start register: verifi_code is #{verifi_code}, code is #{code}, time is #{Time.now.to_i - verifi_code.try(:created_at).to_i}") uid_logger("start register: verifi_code is #{verifi_code}, code is #{code}, time is #{Time.now.to_i - verifi_code.try(:created_at).to_i}")
# check_code = (verifi_code.try(:code) == code.strip && (Time.now.to_i - verifi_code.created_at.to_i) <= 10*60) # check_code = (verifi_code.try(:code) == code.strip && (Time.now.to_i - verifi_code.created_at.to_i) <= 10*60)
# todo 上线前请删除万能验证码"513231" # todo 上线前请删除万能验证码"513231"
unless code == "513231" && request.subdomain == "pre-newweb" unless code == "513231" && request.subdomain == "test-newweb"
return normal_status(-2, "验证码不正确") if verifi_code.try(:code) != code.strip return normal_status(-2, "验证码不正确") if verifi_code.try(:code) != code.strip
return normal_status(-2, "验证码已失效") if !verifi_code&.effective? return normal_status(-2, "验证码已失效") if !verifi_code&.effective?
end end
@ -73,15 +73,21 @@ class AccountsController < ApplicationController
def login def login
@user = User.try_to_login(params[:login], params[:password]) @user = User.try_to_login(params[:login], params[:password])
if @user return normal_status(-2, "错误的账号或密码") if @user.blank?
# user is already in local database # user is already in local database
return normal_status(-2, "违反平台使用规范,账号已被锁定") if @user.locked? return normal_status(-2, "违反平台使用规范,账号已被锁定") if @user.locked?
return normal_status(-2, "错误的账号或密码") unless @user.check_password?(params[:password].to_s)
else login_control = LimitForbidControl::UserLogin.new(@user)
return normal_status(-2, "登录密码出错已达上限将锁定密码1小时") if login_control.forbid?
password_ok = @user.check_password?(params[:password].to_s)
unless password_ok
login_control.increment!
return normal_status(-2, "错误的账号或密码") return normal_status(-2, "错误的账号或密码")
end end
successful_authentication(@user) successful_authentication(@user)
login_control.clear # 重置每日密码错误次数
session[:user_id] = @user.id session[:user_id] = @user.id
end end
@ -127,21 +133,21 @@ class AccountsController < ApplicationController
# UserDayCertification.create(user_id: user.id, status: 1) # UserDayCertification.create(user_id: user.id, status: 1)
end end
def set_autologin_cookie(user) # def set_autologin_cookie(user)
token = Token.get_or_create_permanent_login_token(user, "autologin") # token = Token.get_or_create_permanent_login_token(user, "autologin")
cookie_options = { # cookie_options = {
:value => token.value, # :value => token.value,
:expires => 1.month.from_now, # :expires => 1.month.from_now,
:path => '/', # :path => '/',
:secure => false, # :secure => false,
:httponly => true # :httponly => true
} # }
if edu_setting('cookie_domain').present? # if edu_setting('cookie_domain').present?
cookie_options = cookie_options.merge(domain: edu_setting('cookie_domain')) # cookie_options = cookie_options.merge(domain: edu_setting('cookie_domain'))
end # end
cookies[autologin_cookie_name] = cookie_options # cookies[autologin_cookie_name] = cookie_options
logger.info("cookies is #{cookies}") # logger.info("cookies is #{cookies}")
end # end
def logout def logout
UserAction.create(action_id: User.current.id, action_type: "Logout", user_id: User.current.id, :ip => request.remote_ip) UserAction.create(action_id: User.current.id, action_type: "Logout", user_id: User.current.id, :ip => request.remote_ip)
@ -183,20 +189,6 @@ class AccountsController < ApplicationController
end end
private private
def autologin_cookie_name
edu_setting('autologin_cookie_name') || 'autologin'
end
def logout_user
if User.current.logged?
if autologin = cookies.delete(autologin_cookie_name)
User.current.delete_autologin_token(autologin)
end
User.current.delete_session_token(session[:tk])
self.logged_user = nil
end
session[:user_id] = nil
end
# type 事件类型 1用户注册 2忘记密码 3: 绑定手机 4: 绑定邮箱, 5: 验证手机号是否有效 # 如果有新的继续后面加 # type 事件类型 1用户注册 2忘记密码 3: 绑定手机 4: 绑定邮箱, 5: 验证手机号是否有效 # 如果有新的继续后面加
# login_type 1手机类型 2邮箱类型 # login_type 1手机类型 2邮箱类型

@ -0,0 +1,58 @@
class Admins::AuthSchoolsController < Admins::BaseController
def index
schools = School.where(ec_auth: 1).includes(:users).order("updated_at desc")
@params_page = params[:page] || 1
@schools = paginate schools
end
def destroy
ActiveRecord::Base.transaction do
school = School.where(id: params[:id]).first
school.destroy
render_success_js
end
end
# 工程认证单位列表搜索学校
def search_school
@schools = School.where("ec_auth != 1 and name like '%#{params[:name]}%'").limit(10)
end
# 添加认证学校
def add_school
all_schools = School.all
all_schools.where(id: params[:school_id]).update_all(ec_auth: 1)
schools = all_schools.where(ec_auth: 1).order("updated_at desc")
@params_page = params[:page] || 1
@schools = paginate schools
end
# 搜索用户
def search_manager
school = School.find_by(id: params[:school_id])
user_ids = school&.ec_school_users&.pluck(:user_id)
@users = User.where.not(id: user_ids).where("concat(lastname, firstname) like ?", "%#{params[:name].strip.to_s}%").limit(10)
end
# 添加认证学校管理员
def add_manager
ActiveRecord::Base.transaction do
user_ids = params[:user_id]
@school_id = params[:school_id]
user_ids.each do |id|
EcSchoolUser.create(user_id: id, school_id: @school_id)
end
@school_users = User.where(id: user_ids)
end
end
# 删除学校管理员
def remove_manager
ActiveRecord::Base.transaction do
manager = EcSchoolUser.where(school_id: params[:school_id], user_id: params[:user_id]).first
manager&.destroy
end
end
end

@ -1,7 +1,7 @@
class Admins::BaseController < ApplicationController class Admins::BaseController < ApplicationController
include Admins::PaginateHelper include Base::PaginateHelper
include Admins::RenderHelper include Admins::RenderHelper
include Admins::ErrorRescueHandler include Base::ErrorRescueHandler
layout 'admin' layout 'admin'

@ -0,0 +1,86 @@
class Admins::CarouselsController < Admins::BaseController
before_action :convert_file!, only: [:create]
helper_method :current_laboratory
def index
@images = current_laboratory.portal_images.order(position: :asc)
end
def create
position = current_laboratory.portal_images.count + 1
ActiveRecord::Base.transaction do
image = current_laboratory.portal_images.create!(create_params.merge(position: position))
file_path = Util::FileManage.disk_filename('PortalImage', image.id)
File.delete(file_path) if File.exist?(file_path) # 删除之前的文件
Util.write_file(@file, file_path)
end
flash[:success] = '保存成功'
redirect_to admins_laboratory_carousels_path(current_laboratory)
end
def update
current_image.update!(update_params)
render_ok
end
def destroy
ActiveRecord::Base.transaction do
current_image.destroy!
# 前移
current_laboratory.portal_images.where('position > ?', current_image.position)
.update_all('position = position - 1')
file_path = Util::FileManage.disk_filename('PortalImage', current_image.id)
File.delete(file_path) if File.exist?(file_path)
end
render_delete_success
end
def drag
move = current_laboratory.portal_images.find_by(id: params[:move_id])
after = current_laboratory.portal_images.find_by(id: params[:after_id])
Admins::DragPortalImageService.call(current_laboratory, move, after)
render_ok
rescue Admins::DragPortalImageService::Error => e
render_error(e.message)
end
private
def current_laboratory
@_current_laboratory ||= Laboratory.find(params[:laboratory_id])
end
def current_image
@_current_image ||= current_laboratory.portal_images.find(params[:id])
end
def create_params
params.require(:portal_image).permit(:name, :link)
end
def update_params
params.permit(:name, :link, :status)
end
def convert_file!
max_size = 10 * 1024 * 1024 # 10M
file = params.dig('portal_image', 'image')
if file.class == ActionDispatch::Http::UploadedFile
@file = file
render_error('请上传文件') if @file.size.zero?
render_error('文件大小超过限制') if @file.size > max_size
else
file = file.to_s.strip
return render_error('请上传正确的图片') if file.blank?
@file = Util.convert_base64_image(file, max_size: max_size)
end
rescue Base64ImageConverter::Error => ex
render_error(ex.message)
end
end

@ -0,0 +1,41 @@
class Admins::CompetitionPrizeUsersController < Admins::BaseController
def index
@competition = current_competition
prize_users = Admins::CompetitionPrizeUserQuery.call(params.merge(competition_id: current_competition.id))
include_class = [:competition_team, :competition_prize, :approver,
user: [:process_real_name_apply, :process_professional_apply, user_extension: :school]]
@prize_users = paginate(prize_users.preload(include_class))
end
def create
Admins::CreateCompetitionPrizeUsersService.call(current_competition)
render_ok
rescue ApplicationService::Error => ex
render_error(ex.message)
end
def approve
Admins::ApproveCompetitionPrizeUserService.call(current_prize_user, current_user)
@prize_user = current_prize_user
rescue ApplicationService::Error => ex
render_js_error(ex.message, type: :notify)
end
def unapprove
Admins::UnapproveCompetitionPrizeUserService.call(current_prize_user, current_user)
@prize_user = current_prize_user
rescue ApplicationService::Error => ex
render_js_error(ex.message, type: :notify)
end
private
def current_prize_user
@_current_prize_user ||= current_competition.competition_prize_users.find(params[:id])
end
def current_competition
@_current_competition ||= Competition.find(params[:competition_id])
end
end

@ -0,0 +1,43 @@
class Admins::CompetitionPrizesController < Admins::BaseController
def index
@competition = current_competition
end
def new
@prize = current_competition.competition_prizes.new
end
def create
@prize = current_competition.competition_prizes.create!(save_params)
render_ok
end
def edit
@prize = current_competition_prize
end
def update
current_competition_prize.update!(save_params)
render_ok
end
def destroy
current_competition_prize.destroy!
render_delete_success
end
private
def current_competition_prize
@_current_competition_prize ||= current_competition.competition_prizes.find(params[:id])
end
def current_competition
@_current_competition ||= Competition.find(params[:competition_id])
end
def save_params
params.require(:competition_prize).permit(:name, :category, :num)
end
end

@ -0,0 +1,33 @@
class Admins::CompetitionSettingsController < Admins::BaseController
def index
@competition = current_competition
end
def basic_setting
Admins::CompetitionBasicSettingService.call(current_competition, basic_form_params)
render_ok
end
def nav_setting
Admins::CompetitionNavSettingService.call(current_competition, nav_form_params)
render_ok
end
private
def current_competition
@_current_competition ||= Competition.find(params[:competition_id])
end
def basic_form_params
params.permit(:identifier, :name, :sub_title, :start_time, :end_time, :mode,
:identifier, :bonus, :awards_count, :description, :course_id, :teach_start_time,
:teach_end_time, sponsor_schools: [], region_schools: [], manager_ids: [])
end
def nav_form_params
params.permit(:enroll_end_time,
competition_staffs: %i[category minimum maximum mutiple_limited],
navbar: %i[module_type module_id name hidden position url])
end
end

@ -0,0 +1,194 @@
class Admins::CompetitionStagesController < Admins::BaseController
def create
Admins::CompetitionStageCreateService.call(current_competition, update_form_params)
render_ok
end
def update
Admins::CompetitionStageUpdateService.call(current_competition, update_form_params, current_stage)
render_ok
end
def destroy
current_stage.destroy!
end
def calculate_stage_score
if current_stage.max_end_time && current_stage.max_end_time < Time.now
ActiveRecord::Base.transaction do
begin
current_stage.competition_scores.destroy_all
if current_stage.competition_stage_sections.size > 0
# 是否只有老师参赛
only_teacher = current_competition.member_staff.blank?
stage_sections = current_stage.competition_stage_sections.includes(:competition_entries)
shixuns = Shixun.where(identifier: current_stage.competition_entries.pluck(:shixun_identifier).reject(&:blank?))
challenges = Challenge.where(shixun_id: shixuns.pluck(:id))
# 计算每个战队的成绩
current_competition.competition_teams.each do |team|
totoal_score = 0
total_time = 0
# 只有老师参赛则计算所有参赛队员的成绩,否则只计算学生的成绩
user_ids = only_teacher ? team.team_members.pluck(:user_id) : team.team_members.where(is_teacher: 0).pluck(:user_id)
stage_sections.each do |section|
shixun_identifiers = section.competition_entries.pluck(:shixun_identifier).reject(&:blank?)
shixun_ids = shixuns.select{ |shixun| shixun_identifiers.include?(shixun.identifier) }.map(&:id)
section_challenges = challenges.select{ |challenge| shixun_ids.include?(challenge.shixun_id) }
if section.score_source == 0
result1 = chart_stage_score user_ids, section.start_time, section.end_time, section_challenges, section_challenges.length/shixun_ids.length
else
result1 = chart_stage_rate user_ids, section.start_time, section.end_time, section_challenges, section_challenges.length/shixun_ids.length
end
score = result1[0]
time = result1[1]
totoal_score += score
total_time += time
end
# 比赛已截止且未有分数纪录 则创建
unless team.competition_scores.exists?(competition_id: current_competition.id, competition_stage_id: current_stage.id)
CompetitionScore.create!(user_id: team.user_id, competition_team_id: team.id, competition_id: current_competition.id,
competition_stage_id: current_stage.id, score: totoal_score, cost_time: total_time)
end
end
# 如果计算的是最后一个阶段,则同时计算总成绩(只有一个阶段则不需计算)
if current_stage.max_end_time == current_competition.max_stage_end_time && current_competition.competition_stages.size > 1
calculate_total_score current_competition
end
end
rescue Exception => e
uid_logger_error(e.message)
@message = "#{e.message}"
end
end
@message = "计算成功"
else
@message = "#{current_stage.name}还未结束"
end
end
def send_message
if current_stage.max_end_time && current_stage.max_end_time > Time.now
User.where(id: TeamMember.where(competition_team_id: current_competition.competition_teams.pluck(:id)).pluck(:user_id).uniq).each do |user|
name = current_competition.name + "#{current_competition.sub_title}#{stage.name}"
begin
if user.phone.present?
Educoder::Sms.send(mobile: user.phone.to_s, code: '1', send_type:'competition_start', user_name:user.show_name,
name:name, result:section.start_time.strftime('%Y-%m-%d %H:%M:%S'))
end
rescue => e
logger_error(e)
render_error("发送验证码出错")
end
end
else
render_error("#{current_stage.name}已结束")
end
end
private
def current_competition
@_current_competition ||= Competition.find(params[:competition_id])
end
def current_stage
@_current_stage ||= CompetitionStage.find_by!(competition_id: params[:competition_id], id: params[:id])
end
def update_form_params
params.permit(:stage_name, :score_rate, stage: [:start_time, :end_time, :entry, :score_source, identifiers: []])
end
# challenges 每阶段的所有关卡
# s_time 阶段开始时间 e_time 阶段结束时间
# rate 关卡经验值与分数的比值
# challenge_count 每个实训的关卡数
# 对三个实训的所有关卡循环: 找到在比赛时间内通关的最低耗时
def chart_stage_score user_ids, s_time, e_time, challenges, challenge_count
total_score = 0
total_time = 0
length = challenge_count #每个实训的关卡数
for i in 1..length
score = 0
time = 0
challenges.select{|challenge| challenge.position == i}.each do |challenge|
Game.where(:challenge_id => challenge.id, :user_id => user_ids, :status => 2).select{|game| game.open_time >= s_time && game.end_time <= e_time }.each do |game|
game_score = challenge.score
cost_time = (game.end_time.to_i - s_time.to_i) > 0 ? (game.end_time.to_i - s_time.to_i) : 0
if score < game_score
score = game_score
time = cost_time
elsif score == game_score
time = cost_time > time ? time : cost_time
end
end
end
total_score += score
total_time += time
end
return [total_score, total_time]
end
def chart_stage_rate user_ids, s_time, e_time, challenges, challenge_count
# 第三阶段的得分和耗时
total_score = 0
total_time = 0
length = challenge_count #每个实训的关卡数
for i in 1..length
score3 = 0
time3 = 0
challenges.select{|challenge| challenge.position == i}.each do |challenge|
Game.where(:challenge_id => challenge.id, :user_id => user_ids, :status => 2).select{|game| game.open_time >= s_time && game.end_time <= e_time }.each do |game|
outputs = game.outputs.select{|output| !output.text_scor.nil? && output.created_at <= e_time }
if outputs.present?
outputs = outputs.sort { |a, b| b[:text_scor].to_f <=> a[:text_scor].to_f }
myshixun_score = outputs.first.text_scor.to_f
myshixun_time = outputs.first.created_at.to_i - s_time.to_i
if score3 < myshixun_score
score3 = myshixun_score
time3 = myshixun_time
elsif score3 == myshixun_score
time3 = myshixun_time > time3 ? time3 : myshixun_time
end
end
end
end
total_score += score3
total_time += time3
end
return [total_score, total_time]
end
def calculate_total_score competition
competition.competition_scores.where(competition_stage_id: 0).destroy_all
competition.competition_teams.each do |team|
total_score = 0
total_time = 0
competition.competition_stages.where("score_rate > 0").each do |stage|
stage_score = team.competition_scores.where(competition_stage_id: stage.id).take
total_score += stage_score.try(:score).to_f * stage.score_rate
total_time += stage_score.try(:cost_time).to_i
end
unless team.competition_scores.exists?(competition_id: competition.id, competition_stage_id: 0)
CompetitionScore.create!(user_id: team.user_id, competition_team_id: team.id, competition_id: competition.id,
competition_stage_id: 0, score: total_score, cost_time: total_time)
end
end
end
end

@ -0,0 +1,57 @@
class Admins::CompetitionsController < Admins::BaseController
before_action :find_competition, except: [:index]
def index
# params[:sort_by] = params[:sort_by].presence || 'created_at'
# params[:sort_direction] = params[:sort_direction].presence || 'desc'
@competitions = Competition.all.order("created_at desc")
@params_page = params[:page] || 1
@competitions = paginate @competitions
ids = @competitions.map(&:id)
@member_count_map = TeamMember.where(competition_id: ids).group(:competition_id).count
@competition_hot = ModuleSetting.exists?(module_type: "Competition", property: "hot")
respond_to do |format|
format.js
format.html
end
end
def create
name = params[:competition_name].to_s.strip
Competition.create!(name: name)
render_ok
end
def hot_setting
if params[:hot].to_i == 1 && !ModuleSetting.exists?(module_type: "Competition", property: "hot")
ModuleSetting.create!(module_type: "Competition", property: "hot")
elsif params[:hot].to_i == 0 && ModuleSetting.exists?(module_type: "Competition", property: "hot")
ModuleSetting.where(module_type: "Competition", property: "hot").destroy_all
end
render_ok
end
def publish
@competition.update_attributes!(published_at: Time.now)
end
def unpublish
@competition.update_attributes!(published_at: nil)
end
def online_switch
if @competition.status
@competition.update_attributes!(status: false)
else
@competition.update_attributes!(status: true, online_time: Time.now)
end
end
private
def find_competition
@competition = Competition.find_by(id: params[:id])
end
end

@ -0,0 +1,41 @@
class Admins::EcTemplatesController < Admins::BaseController
def index
@params_page = params[:page] || 1
templates = EcTemplate.where(nil).includes(:attachments).order("updated_at desc")
@templates = paginate templates
end
def create_template
ActiveRecord::Base.transaction do
if params[:template_id] == "-1"
ec_template = EcTemplate.new(name: params[:name])
ec_template.save
else
ec_template = EcTemplate.find_by(id: params[:template_id])
end
if params[:attachment_id] != "-1"
attachment_id = params[:attachment_id]
attachment_tem = Attachment.find_by(id: attachment_id)
unless attachment_tem.container_id.present? && attachment_tem.container_id == ec_template&.id
attachment_tem.update_attributes(container_id: ec_template&.id, container_type: "EcTemplate")
end
end
@params_page = params[:page] || 1
templates = EcTemplate.where(nil).includes(:attachments).order("updated_at desc")
@templates = paginate templates
end
end
def destroy
ActiveRecord::Base.transaction do
template = EcTemplate.find_by(id: params[:id])
template.destroy
render_success_js
end
end
end

@ -0,0 +1,37 @@
class Admins::EnrollListsController < Admins::BaseController
def index
@competition = current_competition
default_sort('created_at', 'desc')
enroll_lists = Admins::CompetitionEnrollListQuery.call(@competition, params)
@params_page = params[:page] || 1
@enroll_lists = paginate enroll_lists.preload(competition_team: [:user, :teachers], user: { user_extension: :school })
@personal = @competition.personal?
respond_to do |format|
format.js
format.html
format.xls{
filename = "#{@competition.name}竞赛报名列表_#{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 export
default_sort('created_at', 'desc')
@enroll_lists = Admins::CompetitionEnrollListQuery.call(current_competition, params)
@enroll_lists = @enroll_lists.preload(competition_team: [:user, :teachers], user: { user_extension: :school })
@competition_scores = current_competition.competition_scores.where(competition_stage_id: 0).order("score desc, cost_time desc").pluck(:competition_team_id)
@personal = current_competition.personal?
filename = ["#{current_competition.name}竞赛报名列表", Time.zone.now.strftime('%Y-%m-%d%H:%M:%S')].join('-') << '.xlsx'
render xlsx: 'export', filename: filename
end
private
def current_competition
@_current_competition ||= Competition.find(params[:competition_id])
end
end

@ -6,7 +6,12 @@ class Admins::FilesController < Admins::BaseController
Util.write_file(@file, file_path) Util.write_file(@file, file_path)
render_ok(source_id: params[:source_id], source_type: params[:source_type].to_s, url: file_url + "?t=#{Random.rand}") render_ok(
source_id: params[:source_id],
source_type: params[:source_type].to_s,
suffix: params[:suffix].presence,
url: file_url
)
rescue StandardError => ex rescue StandardError => ex
logger_error(ex) logger_error(ex)
render_error('上传失败') render_error('上传失败')
@ -33,14 +38,14 @@ class Admins::FilesController < Admins::BaseController
@_file_path ||= begin @_file_path ||= begin
case params[:source_type].to_s case params[:source_type].to_s
when 'Shixun' then when 'Shixun' then
Util::FileManage.disk_filename('Shixun', params[:source_id]) Util::FileManage.disk_filename('Shixun', params[:source_id], params[:suffix].presence)
else else
Util::FileManage.disk_filename(params[:source_type].to_s, params[:source_id].to_s) Util::FileManage.disk_filename(params[:source_type].to_s, params[:source_id].to_s, params[:suffix].presence)
end end
end end
end end
def file_url def file_url
Util::FileManage.disk_file_url(params[:source_type].to_s, params[:source_id].to_s) Util::FileManage.disk_file_url(params[:source_type].to_s, params[:source_id].to_s, params[:suffix].presence)
end end
end end

@ -0,0 +1,33 @@
class Admins::GraduationStandardsController < Admins::BaseController
def index
standards = EcGraduationStandard.all.order("updated_at desc")
@params_page = params[:page] || 1
@standards = paginate standards
end
def create_standard
ActiveRecord::Base.transaction do
if params[:graduation_id] == "-1"
content = params[:content]
EcGraduationStandard.create(:content => content)
else
graduation = EcGraduationStandard.find_by(id: params[:graduation_id])
graduation.update_attribute(:content, params[:content])
end
standards = EcGraduationStandard.all.order("updated_at desc")
@params_page = params[:page] || 1
@standards = paginate standards
end
end
def destroy
ActiveRecord::Base.transaction do
@graduation = EcGraduationStandard.find_by(id: params[:id])
@graduation.destroy
render_success_js
end
end
end

@ -1,6 +1,7 @@
class Admins::IdentityAuthenticationsController < Admins::BaseController class Admins::IdentityAuthenticationsController < Admins::BaseController
def index def index
params[:status] ||= 'pending' params[:status] ||= 'pending'
params[:sort_direction] = params[:status] == 'pending' ? 'asc' : 'desc'
applies = Admins::ApplyUserAuthenticationQuery.call(params.merge(type: 1)) applies = Admins::ApplyUserAuthenticationQuery.call(params.merge(type: 1))
@ -18,6 +19,24 @@ class Admins::IdentityAuthenticationsController < Admins::BaseController
render_success_js render_success_js
end end
def batch_agree
ApplyUserAuthentication.real_name_auth.where(id: params[:ids]).each do |apply|
begin
Admins::IdentityAuths::AgreeApplyService.call(apply)
rescue => e
Util.logger_error(e)
end
end
render_ok
end
def revoke
Admins::IdentityAuths::RevokeApplyService.call(current_apply)
render_success_js
end
private private
def current_apply def current_apply

@ -0,0 +1,32 @@
class Admins::LaboratoriesController < Admins::BaseController
def index
params[:sort_by] = params[:sort_by].presence || 'id'
params[:sort_direction] = params[:sort_direction].presence || 'desc'
laboratories = Admins::LaboratoryQuery.call(params)
@laboratories = paginate laboratories.preload(:school, :laboratory_users)
end
def create
Admins::CreateLaboratoryService.call(create_params)
render_ok
rescue Admins::CreateLaboratoryService::Error => ex
render_error(ex.message)
end
def destroy
current_laboratory.destroy!
render_delete_success
end
private
def current_laboratory
@_current_laboratory ||= Laboratory.find(params[:id])
end
def create_params
params.permit(:school_id)
end
end

@ -0,0 +1,20 @@
class Admins::LaboratorySettingsController < Admins::BaseController
def show
@laboratory = current_laboratory
end
def update
Admins::SaveLaboratorySettingService.call(current_laboratory, form_params)
render_ok
end
private
def current_laboratory
@_current_laboratory ||= Laboratory.find(params[:laboratory_id])
end
def form_params
params.permit(:identifier, :name, :nav_logo, :login_logo, :tab_logo, :footer, navbar: %i[name link hidden])
end
end

@ -0,0 +1,19 @@
class Admins::LaboratoryUsersController < Admins::BaseController
helper_method :current_laboratory
def create
Admins::AddLaboratoryUserService.call(current_laboratory, params.permit(user_ids: []))
current_laboratory.reload
end
def destroy
@laboratory_user = current_laboratory.laboratory_users.find_by(user_id: params[:user_id])
@laboratory_user.destroy! if @laboratory_user.present?
end
private
def current_laboratory
@_current_laboratory ||= Laboratory.find(params[:laboratory_id])
end
end

@ -0,0 +1,8 @@
class Admins::MajorInformationsController < Admins::BaseController
def index
disciplines = EcDiscipline.includes(ec_discipline_firsts: {ec_majors: :schools}).order("ec_disciplines.code asc")
@disciplines = paginate disciplines
end
end

@ -1,6 +1,7 @@
class Admins::ProfessionalAuthenticationsController < Admins::BaseController class Admins::ProfessionalAuthenticationsController < Admins::BaseController
def index def index
params[:status] ||= 'pending' params[:status] ||= 'pending'
params[:sort_direction] = params[:status] == 'pending' ? 'asc' : 'desc'
applies = Admins::ApplyUserAuthenticationQuery.call(params.merge(type: 2)) applies = Admins::ApplyUserAuthenticationQuery.call(params.merge(type: 2))
@ -18,6 +19,23 @@ class Admins::ProfessionalAuthenticationsController < Admins::BaseController
render_success_js render_success_js
end end
def batch_agree
ApplyUserAuthentication.professional_auth.where(id: params[:ids]).each do |apply|
begin
Admins::ProfessionalAuths::AgreeApplyService.call(apply)
rescue => e
Util.logger_error(e)
end
end
render_ok
end
def revoke
Admins::ProfessionalAuths::RevokeApplyService.call(current_apply)
render_success_js
end
private private
def current_apply def current_apply

@ -0,0 +1,30 @@
class Admins::SchoolsController < Admins::BaseController
def index
params[:sort_by] ||= 'created_at'
params[:sort_direction] ||= 'desc'
schools = Admins::SchoolQuery.call(params)
@schools = paginate schools
school_ids = @schools.map(&:id)
@department_count = Department.where(school_id: school_ids).group(:school_id).count
end
def destroy
users = User.joins(:user_extension).where(user_extensions: { school_id: current_school.id })
ActiveRecord::Base.transaction do
users.update_all(profile_completed: false)
current_school.destroy!
end
render_delete_success
end
private
def current_school
@_current_school ||= School.find(params[:id])
end
end

@ -26,7 +26,7 @@ class Admins::ShixunAuthorizationsController < Admins::BaseController
@applies = paginate applies.includes(user: :user_extension) @applies = paginate applies.includes(user: :user_extension)
shixun_ids = @applies.map(&:container_id) shixun_ids = @applies.map(&:container_id)
@shixun_map = Shixun.where(id: shixun_ids).each_with_object({}) { |s, h| h[s.id] = s } @shixun_map = Shixun.where(id: shixun_ids).includes(:shixun_reviews).each_with_object({}) { |s, h| h[s.id] = s }
end end
def agree def agree

@ -46,7 +46,7 @@ class Admins::ShixunSettingsController < Admins::BaseController
tag_ids.each do |id| tag_ids.each do |id|
unless tag_repertoire_ids.include?(id) unless tag_repertoire_ids.include?(id)
tag_repertoire = @shixun.shixun_tag_repertoires.new(shixun_id:@shixun.id,tag_repertoire_id:id) tag_repertoire = @shixun.shixun_tag_repertoires.new(shixun_id:@shixun.id,tag_repertoire_id:id)
tag_repertoire.save tag_repertoire.save!
end end
end end
else else
@ -92,6 +92,6 @@ class Admins::ShixunSettingsController < Admins::BaseController
end end
def setting_params def setting_params
params.permit(:use_scope,:excute_time,:close,:status,:can_copy,:webssh,:hidden,:homepage_show,:task_pass,:code_hidden,:id,tag_repertoires:[]) params.permit(:use_scope,:excute_time,:close,:status,:can_copy,:webssh,:hidden,:homepage_show,:task_pass,:code_hidden,:page_no, :id,tag_repertoires:[])
end end
end end

@ -0,0 +1,71 @@
class Admins::SubjectsController < Admins::BaseController
def index
default_sort('created_at', 'desc')
subjects = Admins::SubjectQuery.call(params)
@subjects = paginate subjects.includes(:repertoire, :subject_level_system, user: { user_extension: :school })
end
def edit
@subject = current_subject
end
def update
current_subject.update!(update_params)
flash[:success] = '保存成功'
redirect_to admins_subjects_path
end
def destroy
current_subject.destroy!
render_delete_success
end
# 隐藏
def hide
current_subject.update!(hidden: true)
render_ok
end
# 展示
def cancel_hide
current_subject.update!(hidden: false)
render_ok
end
# 设为主页展示
def homepage_show
current_subject.update!(homepage_show: true)
render_ok
end
# 取消主页展示
def cancel_homepage_show
current_subject.update!(homepage_show: false)
render_ok
end
# 设为金课
def excellent
current_subject.update!(excellent: true)
render_ok
end
# 取消金课
def cancel_excellent
current_subject.update!(excellent: false)
render_ok
end
private
def current_subject
@_current_subject ||= Subject.find(params[:id])
end
def update_params
params.require(:subject).permit(:repertoire_id, :subject_level_system_id, :student_count)
end
end

@ -0,0 +1,19 @@
class Admins::UserStatisticsController < Admins::BaseController
def index
default_sort('finish_shixun_count', 'desc')
total_count, users = Admins::UserStatisticQuery.call(params)
@users = paginate users, total_count: total_count
end
def export
default_sort('finish_shixun_count', 'desc')
params[:per_page] = 10000
_count, @users = Admins::UserStatisticQuery.call(params)
filename = ['用户实训情况', Time.zone.now.strftime('%Y%m%d%H%M%S')].join('-') << '.xlsx'
render xlsx: 'export', filename: filename
end
end

@ -32,13 +32,13 @@ class Admins::UsersController < Admins::BaseController
end end
def lock def lock
User.find(params[:user_id]).lock! User.find(params[:id]).lock!
render_ok render_ok
end end
def unlock def unlock
User.find(params[:user_id]).activate! User.find(params[:id]).activate!
render_ok render_ok
end end
@ -52,6 +52,12 @@ class Admins::UsersController < Admins::BaseController
render_ok(grade: user.grade) render_ok(grade: user.grade)
end end
def reset_login_times
User.find(params[:id]).reset_login_times!
render_ok
end
private private
def update_params def update_params

@ -0,0 +1,79 @@
class Admins::WeappAdvertsController < Admins::BaseController
before_action :convert_file!, only: [:create]
def index
@adverts = WeappSettings::Advert.all
end
def create
position = WeappSettings::Advert.count + 1
ActiveRecord::Base.transaction do
advert = WeappSettings::Advert.create!(create_params.merge(position: position))
file_path = Util::FileManage.source_disk_filename(advert)
File.delete(file_path) if File.exist?(file_path) # 删除之前的文件
Util.write_file(@file, file_path)
end
flash[:success] = '保存成功'
redirect_to admins_weapp_adverts_path
end
def update
current_advert.update!(update_params)
render_ok
end
def destroy
ActiveRecord::Base.transaction do
current_advert.destroy!
# 前移
WeappSettings::Advert.where('position > ?', current_advert.position)
.update_all('position = position - 1')
file_path = Util::FileManage.source_disk_filename(current_advert)
File.delete(file_path) if File.exist?(file_path)
end
render_delete_success
end
def drag
move = WeappSettings::Advert.find_by(id: params[:move_id])
after = WeappSettings::Advert.find_by(id: params[:after_id])
Admins::DragWeappAdvertService.call(move, after)
render_ok
rescue ApplicationService::Error => e
render_error(e.message)
end
private
def current_advert
@_current_advert ||= WeappSettings::Advert.find(params[:id])
end
def create_params
params.require(:weapp_settings_advert).permit(:link)
end
def update_params
params.permit(:link, :online)
end
def convert_file!
max_size = 10 * 1024 * 1024 # 10M
file = params.dig('weapp_settings_advert', 'image')
if file.class == ActionDispatch::Http::UploadedFile
@file = file
render_error('请上传文件') if @file.size.zero?
render_error('文件大小超过限制') if @file.size > max_size
else
file = file.to_s.strip
return render_error('请上传正确的图片') if file.blank?
@file = Util.convert_base64_image(file, max_size: max_size)
end
rescue Base64ImageConverter::Error => ex
render_error(ex.message)
end
end

@ -0,0 +1,80 @@
class Admins::WeappCarouselsController < Admins::BaseController
before_action :convert_file!, only: [:create]
def index
@carousels = WeappSettings::Carousel.all
end
def create
position = WeappSettings::Carousel.count + 1
ActiveRecord::Base.transaction do
carousel = WeappSettings::Carousel.create!(create_params.merge(position: position))
file_path = Util::FileManage.source_disk_filename(carousel)
File.delete(file_path) if File.exist?(file_path) # 删除之前的文件
Util.write_file(@file, file_path)
end
flash[:success] = '保存成功'
redirect_to admins_weapp_carousels_path
end
def update
current_carousel.update!(update_params)
render_ok
end
def destroy
ActiveRecord::Base.transaction do
current_carousel.destroy!
# 前移
WeappSettings::Carousel.where('position > ?', current_carousel.position)
.update_all('position = position - 1')
file_path = Util::FileManage.source_disk_filename(current_carousel)
File.delete(file_path) if File.exist?(file_path)
end
render_delete_success
end
def drag
move = WeappSettings::Carousel.find_by(id: params[:move_id])
after = WeappSettings::Carousel.find_by(id: params[:after_id])
Admins::DragWeappCarouselService.call(move, after)
render_ok
rescue ApplicationService::Error => e
render_error(e.message)
end
private
def current_carousel
@_current_carousel ||= WeappSettings::Carousel.find(params[:id])
end
def create_params
params.require(:weapp_settings_carousel).permit(:link)
end
def update_params
params.permit(:link, :online)
end
def convert_file!
max_size = 10 * 1024 * 1024 # 10M
file = params.dig('weapp_settings_carousel', 'image')
if file.class == ActionDispatch::Http::UploadedFile
@file = file
render_error('请上传文件') if @file.size.zero?
render_error('文件大小超过限制') if @file.size > max_size
else
file = file.to_s.strip
return render_error('请上传正确的图片') if file.blank?
@file = Util.convert_base64_image(file, max_size: max_size)
end
rescue Base64ImageConverter::Error => ex
render_error(ex.message)
end
end

@ -7,6 +7,8 @@ class ApplicationController < ActionController::Base
include ControllerRescueHandler include ControllerRescueHandler
include GitHelper include GitHelper
include LoggerHelper include LoggerHelper
include LaboratoryHelper
include LoginHelper
protect_from_forgery prepend: true, unless: -> { request.format.json? } protect_from_forgery prepend: true, unless: -> { request.format.json? }
@ -14,6 +16,7 @@ class ApplicationController < ActionController::Base
#before_action :check_account #before_action :check_account
DCODES = %W(2 3 4 5 6 7 8 9 a b c f e f g h i j k l m n o p q r s t u v w x y z) DCODES = %W(2 3 4 5 6 7 8 9 a b c f e f g h i j k l m n o p q r s t u v w x y z)
OPENKEY = "79e33abd4b6588941ab7622aed1e67e8"
helper_method :current_user helper_method :current_user
@ -83,8 +86,18 @@ class ApplicationController < ActionController::Base
when 8, 3, 5 when 8, 3, 5
# 邮箱类型的发送 # 邮箱类型的发送
sigle_para = {email: value} sigle_para = {email: value}
# 60s内不能重复发送
send_email_limit_cache_key = "send_email_60_second_limit:#{value}"
tip_exception(-1, '请勿频繁操作') if Rails.cache.exist?(send_email_limit_cache_key)
# 短时间内不能大量发送
send_email_control = LimitForbidControl::SendEmailCode.new(value)
tip_exception(-1, '邮件发送太频繁,请稍后再试') if send_email_control.forbid?
begin begin
UserMailer.register_email(value, code).deliver_now UserMailer.register_email(value, code).deliver_now
Rails.cache.write(send_email_limit_cache_key, 1, expires_in: 1.minute)
send_email_control.increment!
# Mailer.run.email_register(code, value) # Mailer.run.email_register(code, value)
rescue Exception => e rescue Exception => e
logger_error(e) logger_error(e)
@ -109,6 +122,8 @@ class ApplicationController < ActionController::Base
"验证码发送次数超过频率" "验证码发送次数超过频率"
when 43 when 43
"一天内同一手机号发送次数超过限制" "一天内同一手机号发送次数超过限制"
when 53
"手机号接收超过频率限制"
end end
end end
@ -233,12 +248,6 @@ class ApplicationController < ActionController::Base
# end # end
end end
def start_user_session(user)
session[:user_id] = user.id
session[:ctime] = Time.now.utc.to_i
session[:atime] = Time.now.utc.to_i
end
def user_setup def user_setup
# reacct静态资源加载不需要走这一步 # reacct静态资源加载不需要走这一步
return if params[:controller] == "main" return if params[:controller] == "main"
@ -246,6 +255,20 @@ class ApplicationController < ActionController::Base
User.current = find_current_user User.current = find_current_user
uid_logger("user_setup: " + (User.current.logged? ? "#{User.current.try(:login)} (id=#{User.current.try(:id)})" : "anonymous")) uid_logger("user_setup: " + (User.current.logged? ? "#{User.current.try(:login)} (id=#{User.current.try(:id)})" : "anonymous"))
# 开放课程通过链接访问的用户
if !User.current.logged? && !params[:chinaoocTimestamp].blank? && !params[:websiteName].blank? && !params[:chinaoocKey].blank?
content = "#{OPENKEY}#{params[:websiteName]}#{params[:chinaoocTimestamp]}"
if Digest::MD5.hexdigest(content) == params[:chinaoocKey]
user = open_class_user
if user
start_user_session(user)
set_autologin_cookie(user)
end
User.current = user
end
end
if !User.current.logged? && Rails.env.development? if !User.current.logged? && Rails.env.development?
User.current = User.find 1 User.current = User.find 1
end end
@ -253,7 +276,7 @@ class ApplicationController < ActionController::Base
# 测试版前端需求 # 测试版前端需求
logger.info("subdomain:#{request.subdomain}") logger.info("subdomain:#{request.subdomain}")
if request.subdomain == "pre-newweb" if request.subdomain == "test-newweb"
if params[:debug] == 'teacher' #todo 为了测试,记得讲debug删除 if params[:debug] == 'teacher' #todo 为了测试,记得讲debug删除
User.current = User.find 81403 User.current = User.find 81403
elsif params[:debug] == 'student' elsif params[:debug] == 'student'
@ -265,17 +288,6 @@ class ApplicationController < ActionController::Base
# User.current = User.find 81403 # User.current = User.find 81403
end end
# Sets the logged in user
def logged_user=(user)
reset_session
if user && user.is_a?(User)
User.current = user
start_user_session(user)
else
User.current = User.anonymous
end
end
# Returns the current user or nil if no user is logged in # Returns the current user or nil if no user is logged in
# and starts a session if needed # and starts a session if needed
def find_current_user def find_current_user
@ -291,10 +303,6 @@ class ApplicationController < ActionController::Base
end end
end end
def autologin_cookie_name
edu_setting('autologin_cookie_name').presence || 'autologin'
end
def try_to_autologin def try_to_autologin
if cookies[autologin_cookie_name] if cookies[autologin_cookie_name]
# auto-login feature starts a new session # auto-login feature starts a new session
@ -340,11 +348,11 @@ class ApplicationController < ActionController::Base
# type 0 创始内容, 1 最新内容 # type 0 创始内容, 1 最新内容
def game_passed_code(path, myshixun, game_id) def game_passed_code(path, myshixun, game_id)
# 如果代码窗口是隐藏的,则不用保存代码 # 如果代码窗口是隐藏的,则不用保存代码
return if myshixun.shixun.hide_code return if myshixun.shixun.hide_code || myshixun.shixun.vnc
file_content = git_fle_content myshixun.repo_path, path file_content = git_fle_content myshixun.repo_path, path
unless file_content.present? #unless file_content.present?
raise("获取文件代码异常") # raise("获取文件代码异常")
end #end
logger.info("#######game_id:#{game_id}, file_content:#{file_content}") logger.info("#######game_id:#{game_id}, file_content:#{file_content}")
game_code = GameCode.where(:game_id => game_id, :path => path).first game_code = GameCode.where(:game_id => game_id, :path => path).first
if game_code.nil? if game_code.nil?
@ -357,10 +365,10 @@ class ApplicationController < ActionController::Base
# Post请求 # Post请求
def uri_post(uri, params) def uri_post(uri, params)
begin begin
uid_logger("--uri_exec: params is #{params}, url is #{uri}") uid_logger_dubug("--uri_exec: params is #{params}, url is #{uri}")
uri = URI.parse(URI.encode(uri.strip)) uri = URI.parse(URI.encode(uri.strip))
res = Net::HTTP.post_form(uri, params).body res = Net::HTTP.post_form(uri, params).body
logger.info("--uri_exec: .....res is #{res}") uid_logger_dubug("--uri_exec: .....res is #{res}")
JSON.parse(res) JSON.parse(res)
rescue Exception => e rescue Exception => e
uid_logger_error("--uri_exec: exception #{e.message}") uid_logger_error("--uri_exec: exception #{e.message}")
@ -371,10 +379,10 @@ class ApplicationController < ActionController::Base
# 处理返回非0就报错的请求 # 处理返回非0就报错的请求
def interface_post(uri, params, status, message) def interface_post(uri, params, status, message)
begin begin
uid_logger("--uri_exec: params is #{params}, url is #{uri}") uid_logger_dubug("--uri_exec: params is #{params}, url is #{uri}")
uri = URI.parse(URI.encode(uri.strip)) uri = URI.parse(URI.encode(uri.strip))
res = Net::HTTP.post_form(uri, params).body res = Net::HTTP.post_form(uri, params).body
logger.info("--uri_exec: .....res is #{res}") uid_logger_dubug("--uri_exec: .....res is #{res}")
res = JSON.parse(res) res = JSON.parse(res)
if (res && res['code'] != 0) if (res && res['code'] != 0)
tip_exception(status, message) tip_exception(status, message)
@ -604,4 +612,36 @@ class ApplicationController < ActionController::Base
def set_export_cookies def set_export_cookies
cookies[:fileDownload] = true cookies[:fileDownload] = true
end end
# 149课程的评审用户数据创建包含创建课堂学生
def open_class_user
user = User.find_by(login: "OpenClassUser")
unless user
ActiveRecord::Base.transaction do
user_params = {status: 1, login: "OpenClassUser", lastname: "开放课程",
nickname: "开放课程", professional_certification: 1, certification: 1, grade: 0,
password: "12345678", phone: "11122223333", profile_completed: 1}
user = User.create!(user_params)
UserExtension.create!(user_id: user.id, gender: 0, school_id: 3396, :identity => 1, :student_id => "openclassuser") # 3396
subject = Subject.find_by(id: 149)
if subject
subject.courses.each do |course|
CourseMember.create!(course_id: course.id, role: 3, user_id: user.id) if !course.course_members.exists?(user_id: user.id)
end
end
end
end
user
end
# 记录热门搜索关键字
def record_search_keyword
keyword = params[:keyword].to_s.strip
return if keyword.blank? || keyword.size <= 1
return unless HotSearchKeyword.available?
HotSearchKeyword.add(keyword)
end
end end

@ -83,6 +83,7 @@ class AttachmentsController < ApplicationController
@file.destroy! @file.destroy!
delete_file(@file_path) delete_file(@file_path)
normal_status("删除成功")
rescue Exception => e rescue Exception => e
uid_logger_error(e.message) uid_logger_error(e.message)
tip_exception(e.message) tip_exception(e.message)

@ -0,0 +1,22 @@
class BindUsersController < ApplicationController
before_action :require_login
def create
user = CreateBindUserService.call(current_user, create_params)
successful_authentication(user) if user.id != current_user.id
render_ok
rescue ApplicationService::Error => ex
render_error(ex.message)
end
def new_user
current_user
end
private
def create_params
params.permit(:username, :password, :type, :not_bind)
end
end

@ -2,7 +2,7 @@ class BoardsController < ApplicationController
before_action :require_login, :check_auth before_action :require_login, :check_auth
before_action :find_course, only: [:create] before_action :find_course, only: [:create]
before_action :set_board, except: [:create] before_action :set_board, except: [:create]
before_action :teacher_or_admin_allowed before_action :teacher_allowed
def index def index
@boards = @course.boards.includes(messages: [:last_reply, :author]) @boards = @course.boards.includes(messages: [:last_reply, :author])
@ -20,9 +20,8 @@ class BoardsController < ApplicationController
new_board.parent_id = board.try(:id) new_board.parent_id = board.try(:id)
new_board.position = board.children.count + 1 new_board.position = board.children.count + 1
new_board.save! new_board.save!
render :json => {category_id: new_board.id, status: 0, message: "添加成功"}
end end
normal_status(0, "添加成功")
end end
# 子目录的拖动 # 子目录的拖动

@ -40,8 +40,8 @@ class CollegesController < ApplicationController
def teachers def teachers
@teachers = User.find_by_sql("SELECT users.id, users.login, users.lastname, users.firstname, users.nickname, IFNULL((SELECT count(shixuns.id) FROM shixuns where shixuns.user_id =users.id group by shixuns.user_id), 0) AS publish_shixun_count, @teachers = User.find_by_sql("SELECT users.id, users.login, users.lastname, users.firstname, users.nickname, IFNULL((SELECT count(shixuns.id) FROM shixuns where shixuns.user_id =users.id group by shixuns.user_id), 0) AS publish_shixun_count,
(SELECT count(c.id) FROM courses c, course_members m WHERE c.id != 1309 and m.course_id = c.id AND m.role in (1,2,3) and c.school_id = #{current_school.id} AND m.user_id=users.id AND c.is_delete = 0) as course_count (SELECT count(c.id) FROM courses c, course_members m WHERE c.id != 1309 and m.course_id = c.id AND m.user_id=users.id AND m.role in (1,2,3) and c.school_id = #{current_school.id} AND c.is_delete = 0) as course_count
FROM `users`, user_extensions ue where users.id=ue.user_id and ue.identity=0 and ue.school_id=#{current_school.id} ORDER BY publish_shixun_count desc, course_count desc, id desc LIMIT 10") FROM `users`, user_extensions ue where ue.school_id=#{current_school.id} and users.id=ue.user_id and ue.identity=0 ORDER BY publish_shixun_count desc, course_count desc, id desc LIMIT 10")
# ).order("publish_shixun_count desc, experience desc").limit(10) # ).order("publish_shixun_count desc, experience desc").limit(10)
@teachers = @teachers =
@teachers.map do |teacher| @teachers.map do |teacher|

@ -51,7 +51,8 @@ class CommonsController < ApplicationController
200 200
end end
when 'journals_for_message' when 'journals_for_message'
if current_user.course_identity(@object.jour.course) >= Course::STUDENT && @object.user != current_user course = @object&.jour_type.to_s == "StudentWorksScore" ? @object.jour&.student_work&.homework_common&.course : @object.jour&.course
if current_user.course_identity(course) >= Course::STUDENT && @object.user != current_user
403 403
else else
200 200

@ -0,0 +1,23 @@
class Competitions::CertificatesController < Competitions::BaseController
def personal
prize_user = CompetitionPrizeUser.find_by!(user: current_user, id: params[:id])
return render_not_found unless prize_user.certificate_exist?
team = prize_user.competition_team
prize = prize_user.competition_prize
filename = "#{current_competition.name}-#{prize.name}-#{team.name}-#{prize_user.user.real_name}.pdf"
send_file prize_user.certificate_path, filename: filename
end
def team
team = CompetitionTeam.find(params[:id])
return render_forbidden unless team.team_members.exists?(user_id: current_user.id)
return render_not_found unless team.certificate_exists?
prize = team.competition_prize_users.first.competition_prize
filename = "#{current_competition.name}-#{prize.name}-#{team.name}.pdf"
send_file team.certificate_path, filename: filename
end
end

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

Loading…
Cancel
Save