Merge branch 'dev_item_bank' of https://bdgit.educoder.net/Hjqreturn/educoder into dev_jupyter

dev_jupyter
杨树林 5 years ago
commit 0a33fc8cfe

2
.gitignore vendored

@ -43,7 +43,7 @@
/public/react/config/stats.json /public/react/config/stats.json
/public/react/stats.json /public/react/stats.json
/public/react/.idea/* /public/react/.idea/*
/public/h5build
/public/npm-debug.log /public/npm-debug.log
# avatars # avatars

@ -14,7 +14,18 @@ $(document).on('turbolinks:load', function() {
} }
}); });
$modal.on('click', '.submit-btn', function(){ $modal.on('click', '.submit-btn', submit_edit_form);
$form.find("#discipline_name").keydown(function (e) {
var ev = e || event;
var keycode = ev.which || ev.keyCode;
if (keycode == 13) {
submit_edit_form();
return false;
}
});
function submit_edit_form() {
$form.find('.error').html(''); $form.find('.error').html('');
var url = $form.attr('action'); var url = $form.attr('action');
@ -26,6 +37,6 @@ $(document).on('turbolinks:load', function() {
data: $form.serialize() data: $form.serialize()
}); });
} }
}); }
}); });
}); });

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

@ -14,7 +14,18 @@ $(document).on('turbolinks:load', function() {
} }
}); });
$modal.on('click', '.submit-btn', function(){ $modal.on('click', '.submit-btn', submit_edit_form);
$form.find("#sub_discipline_name").keydown(function (e) {
var ev = e || event;
var keycode = ev.which || ev.keyCode;
if (keycode == 13) {
submit_edit_form();
return false;
}
});
function submit_edit_form() {
$form.find('.error').html(''); $form.find('.error').html('');
var url = $form.attr('action'); var url = $form.attr('action');
@ -26,6 +37,7 @@ $(document).on('turbolinks:load', function() {
data: $form.serialize() data: $form.serialize()
}); });
} }
}); }
}); });
}); });

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

@ -14,7 +14,18 @@ $(document).on('turbolinks:load', function() {
} }
}); });
$modal.on('click', '.submit-btn', function(){ $modal.on('click', '.submit-btn', submit_edit_form);
$form.find("#tag_discipline_name").keydown(function (e) {
var ev = e || event;
var keycode = ev.which || ev.keyCode;
if (keycode == 13) {
submit_edit_form();
return false;
}
});
function submit_edit_form() {
$form.find('.error').html(''); $form.find('.error').html('');
var url = $form.attr('action'); var url = $form.attr('action');
@ -26,6 +37,6 @@ $(document).on('turbolinks:load', function() {
data: $form.serialize() data: $form.serialize()
}); });
} }
}); }
}); });
}); });

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

@ -0,0 +1,65 @@
$(document).on('turbolinks:load', function() {
if ($('body.admins-repertoires-index-page').length > 0) {
// ============== 新建 ===============
var $modal = $('.modal.admin-create-repertoire-modal');
var $form = $modal.find('form.admin-create-repertoire-form');
var $nameInput = $form.find('input[name="name"]');
$form.validate({
errorElement: 'span',
errorClass: 'danger text-danger',
rules: {
name: {
required: true
}
}
});
// modal ready fire
$modal.on('show.bs.modal', function () {
$nameInput.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);
}
});
}
});
$(".repertoire-list-container").on("change", '.repertoire-source-form', function () {
var s_id = $(this).attr("data-id");
var s_value = $(this).val();
var s_name = $(this).attr("name");
var json = {};
json[s_name] = s_value;
$.ajax({
url: "/admins/repertoires/" + s_id,
type: "PUT",
dataType:'script',
data: json
});
});
}
});

@ -0,0 +1,74 @@
$(document).on('turbolinks:load', function() {
if ($('body.admins-salesmans-index-page').length > 0) {
// ============= 添加销售人员 ==============
var $addMemberModal = $('.admin-add-salesman-customer-user-modal');
var $addMemberForm = $addMemberModal.find('.admin-add-salesman-customer-user-form');
var $memberSelect = $addMemberModal.find('.salesman-user-select');
// var $salesmanIdInput = $addMemberForm.find('input[name="salesman_id"]')
$addMemberModal.on('show.bs.modal', function(event){
var $link = $(event.relatedTarget);
var salesmanId = $link.data('salesman-id');
$salesmanIdInput.val(salesmanId);
$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 salesmanId = $salesmanIdInput.val();
var memberIds = $memberSelect.val();
if (memberIds && memberIds.length > 0) {
$.ajax({
method: 'POST',
dataType: 'json',
url: '/admins/salesman_customers/batch_add',
data: { user_ids: memberIds },
success: function(){
$.notify({ message: '创建成功' });
$addMemberModal.modal('hide');
setTimeout(function(){
window.location.reload();
}, 500);
},
error: function(res){
var data = res.responseJSON;
$form.find('.error').html(data.message);
}
});
} else {
$addMemberModal.modal('hide');
}
});
}
});

@ -0,0 +1,99 @@
$(document).on('turbolinks:load', function() {
if ($('body.admins-salesmans-index-page').length > 0) {
// ============= 添加销售人员 ==============
var $addMemberModal = $('.admin-add-salesman-user-modal');
var $addMemberForm = $addMemberModal.find('.admin-add-salesman-user-form');
var $memberSelect = $addMemberModal.find('.salesman-user-select');
// var $salesmanIdInput = $addMemberForm.find('input[name="salesman_id"]')
$addMemberModal.on('show.bs.modal', function(event){
var $link = $(event.relatedTarget);
// var salesmanId = $link.data('salesman-id');
// $salesmanIdInput.val(salesmanId);
$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 salesmanId = $salesmanIdInput.val();
var memberIds = $memberSelect.val();
if (memberIds && memberIds.length > 0) {
$.ajax({
method: 'POST',
dataType: 'json',
url: '/admins/salesmans/batch_add',
data: { user_ids: memberIds },
success: function(){
$.notify({ message: '创建成功' });
$addMemberModal.modal('hide');
setTimeout(function(){
window.location.reload();
}, 500);
},
error: function(res){
var data = res.responseJSON;
$form.find('.error').html(data.message);
}
});
} else {
$addMemberModal.modal('hide');
}
});
$(".salesman-list-container").on("change", '.salesman-sync-course', function () {
var s_id = $(this).attr("data-id");
var json = {};
$.ajax({
url: "/admins/salesmans/" + s_id + "/update_sync_course",
type: "POST",
dataType:'script',
data: json
})
});
$(".salesman-list-container").on("change", '.salesman-sync-form', function () {
var s_id = $(this).attr("data-id");
var s_value = $(this).val();
var s_name = $(this).attr("name");
var json = {};
json[s_name] = s_value;
$.ajax({
url: "/admins/salesmans/" + s_id,
type: "PUT",
dataType:'script',
data: json
});
});
}
});

@ -30,7 +30,21 @@ $(document).on('turbolinks:load', function() {
type: "PUT", type: "PUT",
dataType:'script', dataType:'script',
data: json data: json
}) });
});
$(".shixun-settings-list-container").on("change", '.repertoire-setting-form', function () {
var s_id = $(this).attr("data-id");
var s_value = $(this).val();
var s_name = $(this).attr("name");
var json = {};
json[s_name] = s_value;
$.ajax({
url: "/admins/shixun_settings/" + s_id + "/update_tag_repertoires",
type: "POST",
dataType:'script',
data: json
});
}); });
$("select#settings-tag-choosed").select2({ $("select#settings-tag-choosed").select2({

@ -21,7 +21,18 @@ $(document).on('turbolinks:load', function() {
$nameInput.val(''); $nameInput.val('');
}); });
$modal.on('click', '.submit-btn', function(){ $modal.on('click', '.submit-btn', submit_create_form);
$nameInput.keydown(function (e) {
var ev = e || event;
var keycode = ev.which || ev.keyCode;
if (keycode == 13) {
submit_create_form();
return false;
}
});
function submit_create_form() {
$form.find('.error').html(''); $form.find('.error').html('');
if ($form.valid()) { if ($form.valid()) {
@ -46,7 +57,7 @@ $(document).on('turbolinks:load', function() {
} }
}); });
} }
}); }
$(".sub-discipline-list-container").on("change", '.sub-discipline-source-form', function () { $(".sub-discipline-list-container").on("change", '.sub-discipline-source-form', function () {
var s_id = $(this).attr("data-id"); var s_id = $(this).attr("data-id");

@ -0,0 +1,65 @@
$(document).on('turbolinks:load', function() {
if ($('body.admins-sub-repertoires-index-page').length > 0) {
// ============== 新建 ===============
var $modal = $('.modal.admin-create-sub-repertoire-modal');
var $form = $modal.find('form.admin-create-sub-repertoire-form');
var $nameInput = $form.find('input[name="name"]');
$form.validate({
errorElement: 'span',
errorClass: 'danger text-danger',
rules: {
name: {
required: true
}
}
});
// modal ready fire
$modal.on('show.bs.modal', function () {
$nameInput.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);
}
});
}
});
$(".sub-repertoire-list-container").on("change", '.sub-repertoire-source-form', function () {
var s_id = $(this).attr("data-id");
var s_value = $(this).val();
var s_name = $(this).attr("name");
var json = {};
json[s_name] = s_value;
$.ajax({
url: "/admins/sub_repertoires/" + s_id,
type: "PUT",
dataType:'script',
data: json
});
});
}
});

@ -0,0 +1,71 @@
$(document).on('turbolinks:load', function () {
if ($('body.admins-subject-settings-index-page').length > 0) {
var $form = $('.subject-setting-list-form');
// ************** 学校选择 *************
$form.find('.school-select').select2({
theme: 'bootstrap4',
placeholder: '请选择创建者单位',
minimumInputLength: 1,
ajax: {
delay: 500,
url: '/api/schools/search.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;
}
});
$(".subject-setting-list-container").on("change", '.subject-setting-form', function () {
var s_id = $(this).attr("data-id");
var s_value = $(this).val();
var s_name = $(this).attr("name");
var json = {};
json[s_name] = s_value;
$.ajax({
url: "/admins/subject_settings/" + s_id,
type: "PUT",
dataType:'script',
data: json
})
});
// 清空
$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('重新上传');
}
});
}
});

@ -37,22 +37,8 @@ $(document).on('turbolinks:load', function () {
$form.find('#homepage_show').attr('checked', false); $form.find('#homepage_show').attr('checked', false);
$form.find('#excellent').attr('checked', false); $form.find('#excellent').attr('checked', false);
$form.find('input[type="submit"]').trigger('click'); $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) { var defineStatusChangeFunc = function (doElement, undoElement, url, callback) {
$('.subject-list-container').on('click', doElement, function () { $('.subject-list-container').on('click', doElement, function () {

@ -21,7 +21,18 @@ $(document).on('turbolinks:load', function() {
$nameInput.val(''); $nameInput.val('');
}); });
$modal.on('click', '.submit-btn', function(){ $modal.on('click', '.submit-btn', submit_create_form);
$nameInput.keydown(function (e) {
var ev = e || event;
var keycode = ev.which || ev.keyCode;
if (keycode == 13) {
submit_create_form();
return false;
}
});
function submit_create_form() {
$form.find('.error').html(''); $form.find('.error').html('');
if ($form.valid()) { if ($form.valid()) {
@ -46,7 +57,7 @@ $(document).on('turbolinks:load', function() {
} }
}); });
} }
}); }
$(".tag-discipline-list-container").on("change", '.tag-discipline-source-form', function () { $(".tag-discipline-list-container").on("change", '.tag-discipline-source-form', function () {
var s_id = $(this).attr("data-id"); var s_id = $(this).attr("data-id");

@ -0,0 +1,65 @@
$(document).on('turbolinks:load', function() {
if ($('body.admins-tag-repertoires-index-page').length > 0) {
// ============== 新建 ===============
var $modal = $('.modal.admin-create-tag-repertoire-modal');
var $form = $modal.find('form.admin-create-tag-repertoire-form');
var $nameInput = $form.find('input[name="name"]');
$form.validate({
errorElement: 'span',
errorClass: 'danger text-danger',
rules: {
name: {
required: true
}
}
});
// modal ready fire
$modal.on('show.bs.modal', function () {
$nameInput.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);
}
});
}
});
$(".tag-repertoire-list-container").on("change", '.tag-repertoire-source-form', function () {
var s_id = $(this).attr("data-id");
var s_value = $(this).val();
var s_name = $(this).attr("name");
var json = {};
json[s_name] = s_value;
$.ajax({
url: "/admins/tag_repertoires/" + s_id,
type: "PUT",
dataType:'script',
data: json
});
});
}
});

@ -167,7 +167,7 @@ class AccountsController < ApplicationController
end end
# 检验邮箱是否已被注册及邮箱或者手机号是否合法 # 检验邮箱是否已被注册及邮箱或者手机号是否合法
# 参数type为事件类型 1注册2忘记密码 # 参数type为事件类型 1注册2忘记密码3绑定
def valid_email_and_phone def valid_email_and_phone
check_mail_and_phone_valid(params[:login], params[:type]) check_mail_and_phone_valid(params[:login], params[:type])
end end

@ -16,7 +16,8 @@ class Admins::DisciplinesController < Admins::BaseController
end end
def update def update
if params[:discipline] && params[:discipline][:name].present? begin
if params[:discipline] && params[:discipline][:name]
name = params[:discipline][:name].to_s.strip name = params[:discipline][:name].to_s.strip
current_discipline.update_attributes!(name: name) current_discipline.update_attributes!(name: name)
else else
@ -30,6 +31,9 @@ class Admins::DisciplinesController < Admins::BaseController
end end
end end
end end
rescue Exception => e
@message = e.message
end
@disciplines = Discipline.all @disciplines = Discipline.all
end end

@ -0,0 +1,36 @@
class Admins::RepertoiresController < Admins::BaseController
def index
@repertoires = Repertoire.all
end
def edit
@repertoire = current_repertoire
end
def update
Rails.logger.info("#################--------")
if params[:repertoire] && params[:repertoire][:name].present?
name = params[:repertoire][:name].to_s.strip
current_repertoire.update_attributes!(name: name)
end
@repertoires = Repertoire.all
end
def create
name = params[:name].to_s.strip
return render_error('名称重复') if Repertoire.where(name: name).exists?
Repertoire.create!(name: name)
render_ok
end
def destroy
@repertoire_id = params[:id]
current_repertoire.destroy!
end
private
def current_repertoire
@_current_repertoire = Repertoire.find params[:id]
end
end

@ -0,0 +1,13 @@
class Admins::SalesmanCustomersController < Admins::BaseController
before_action :set_salesman
def index
@customers = @salesman.salesman_customers.includes(:user, :school)
end
private
def set_salesman
@salesman = Salesman.find params[:salesman_id]
end
end

@ -0,0 +1,29 @@
class Admins::SalesmansController < Admins::BaseController
before_action :set_salesman, except: [:index, :batch_add]
def index
@salesmans = Salesman.all
end
def destroy
@salesman.destroy!
end
# 批量增加销售人员
def batch_add
salesman_user_ids = Salesman.where(id: params[:user_ids]).pluck(:user_id)
user_ids = params[:user_ids] - salesman_user_ids
user_ids.each do |user_id|
user = User.find_by(id: user_id)
next if user.blank?
Salesman.create!(user_id: user.id, name: user.real_name)
end
render_ok
end
private
def set_salesman
@salesman = Salesman.find params[:id]
end
end

@ -47,22 +47,24 @@ class Admins::ShixunSettingsController < Admins::BaseController
@shixun = Shixun.find_by(id:params[:id]) @shixun = Shixun.find_by(id:params[:id])
@page_no = params[:page_no] || "1" @page_no = params[:page_no] || "1"
@shixun_tags = TagRepertoire.order("name asc").pluck(:name,:id) @shixun_tags = TagRepertoire.order("name asc").pluck(:name,:id)
tag_ids = params[:tag_repertoires]
if tag_ids.present?
@shixun&.shixun_tag_repertoires.delete_all
tag_repertoire_ids = @shixun&.tag_repertoires&.pluck(:id)
tag_ids.each do |id|
unless tag_repertoire_ids.include?(id)
tag_repertoire = @shixun.shixun_tag_repertoires.new(shixun_id:@shixun.id,tag_repertoire_id:id)
tag_repertoire.save!
end
end
else
unless @shixun.update_attributes(setting_params) unless @shixun.update_attributes(setting_params)
redirect_to admins_shixun_settings_path redirect_to admins_shixun_settings_path
flash[:danger] = "更新失败" flash[:danger] = "更新失败"
end end
end end
def update_tag_repertoires
shixun = Shixun.find_by(id:params[:id])
tag_repertoire_ids = params[:tag_repertoires] || []
tag_ids = tag_repertoire_ids.reject(&:blank?).map(&:to_i)
old_tag_ids = shixun.shixun_tag_repertoires.pluck(:tag_repertoire_id)
new_ids = tag_ids - old_tag_ids
delete_ids = old_tag_ids - tag_ids
tag_params = new_ids.map{|sub| {tag_repertoire_id: sub}}
ActiveRecord::Base.transaction do
shixun.shixun_tag_repertoires.where(tag_repertoire_id: delete_ids).destroy_all
shixun.shixun_tag_repertoires.create!(tag_params)
end
end end
private private
@ -133,6 +135,6 @@ class Admins::ShixunSettingsController < Admins::BaseController
def setting_params def setting_params
params.permit(:use_scope,:excute_time,:close,:status,:can_copy,:webssh,:hidden,:homepage_show,:task_pass, params.permit(:use_scope,:excute_time,:close,:status,:can_copy,:webssh,:hidden,:homepage_show,:task_pass,
:code_hidden,:vip,:page_no,:id, :is_wechat_support, tag_repertoires:[]) :code_hidden,:vip,:page_no,:id, :is_wechat_support)
end end
end end

@ -7,6 +7,7 @@ class Admins::SubDisciplinesController < Admins::BaseController
def create def create
name = params[:name].to_s.strip name = params[:name].to_s.strip
return render_error('名称不能为空') if name.blank?
return render_error('名称重复') if current_discipline.sub_disciplines.where(name: name).exists? return render_error('名称重复') if current_discipline.sub_disciplines.where(name: name).exists?
SubDiscipline.create!(name: name, discipline_id: current_discipline.id) SubDiscipline.create!(name: name, discipline_id: current_discipline.id)
render_ok render_ok
@ -17,7 +18,8 @@ class Admins::SubDisciplinesController < Admins::BaseController
end end
def update def update
if params[:sub_discipline] && params[:sub_discipline][:name].present? begin
if params[:sub_discipline] && params[:sub_discipline][:name]
name = params[:sub_discipline][:name].to_s.strip name = params[:sub_discipline][:name].to_s.strip
current_sub_discipline.update_attributes!(name: name) current_sub_discipline.update_attributes!(name: name)
else else
@ -28,6 +30,9 @@ class Admins::SubDisciplinesController < Admins::BaseController
end end
end end
end end
rescue Exception => e
@message = e.message
end
@sub_disciplines = current_sub_discipline.discipline&.sub_disciplines @sub_disciplines = current_sub_discipline.discipline&.sub_disciplines
end end

@ -0,0 +1,45 @@
class Admins::SubRepertoiresController < Admins::BaseController
def index
@repertoire = current_repertoire
@sub_repertoires = current_repertoire.sub_repertoires
end
def create
name = params[:name].to_s.strip
return render_error('名称重复') if current_repertoire.sub_repertoires.where(name: name).exists?
SubRepertoire.create!(name: name, repertoire_id: current_repertoire.id)
render_ok
end
def edit
@sub_repertoire = current_sub_repertoire
end
def update
if params[:sub_repertoire] && params[:sub_repertoire][:name].present?
name = params[:sub_repertoire][:name].to_s.strip
current_sub_repertoire.update_attributes!(name: name)
end
@sub_repertoires = current_sub_repertoire.repertoire&.sub_repertoires
end
def destroy
@sub_repertoire_id = params[:id]
current_sub_repertoire.destroy!
end
private
def current_sub_repertoire
@_current_sub_repertoire = SubRepertoire.find params[:id]
end
def current_repertoire
@_current_repertoire = Repertoire.find params[:repertoire_id]
end
def setting_params
params.permit(:shixun, :subject, :question)
end
end

@ -0,0 +1,29 @@
class Admins::SubjectSettingsController < Admins::BaseController
def index
default_sort('created_at', 'desc')
subjects = Admins::SubjectQuery.call(params)
@sub_disciplines = SubDiscipline.where(subject: 1).pluck(:name,:id)
@subjects = paginate subjects.includes(:repertoire, :subject_level_system, :sub_disciplines)
end
def update
sub_discipline_ids = params[:sub_disciplines] || []
sub_ids = sub_discipline_ids.reject(&:blank?).map(&:to_i)
old_sub_ids = current_subject.sub_discipline_containers.pluck(:sub_discipline_id)
new_ids = sub_ids - old_sub_ids
delete_ids = old_sub_ids - sub_ids
sub_params = new_ids.map{|sub| {sub_discipline_id: sub}}
ActiveRecord::Base.transaction do
current_subject.sub_discipline_containers.where(sub_discipline_id: delete_ids).destroy_all
current_subject.sub_discipline_containers.create!(sub_params)
end
end
private
def current_subject
@_current_subject ||= Subject.find(params[:id])
end
end

@ -3,7 +3,7 @@ class Admins::SubjectsController < Admins::BaseController
default_sort('created_at', 'desc') default_sort('created_at', 'desc')
subjects = Admins::SubjectQuery.call(params) subjects = Admins::SubjectQuery.call(params)
@subjects = paginate subjects.includes(:repertoire, :subject_level_system, user: { user_extension: :school }) @subjects = paginate subjects.includes(user: { user_extension: :school })
end end
def edit def edit
@ -14,7 +14,7 @@ class Admins::SubjectsController < Admins::BaseController
current_subject.update!(update_params) current_subject.update!(update_params)
flash[:success] = '保存成功' flash[:success] = '保存成功'
redirect_to admins_subjects_path redirect_to admins_subject_settings_path
end end
def destroy def destroy

@ -17,12 +17,16 @@ class Admins::TagDisciplinesController < Admins::BaseController
end end
def update def update
if params[:tag_discipline] && params[:tag_discipline][:name].present? begin
if params[:tag_discipline] && params[:tag_discipline][:name]
name = params[:tag_discipline][:name].to_s.strip name = params[:tag_discipline][:name].to_s.strip
current_tag_discipline.update_attributes!(name: name) current_tag_discipline.update_attributes!(name: name)
else else
current_tag_discipline.update_attributes!(setting_params) current_tag_discipline.update_attributes!(setting_params)
end end
rescue Exception => e
@message = e.message
end
@tag_disciplines = current_tag_discipline.sub_discipline&.tag_disciplines @tag_disciplines = current_tag_discipline.sub_discipline&.tag_disciplines
end end

@ -0,0 +1,43 @@
class Admins::TagRepertoiresController < Admins::BaseController
def index
@sub_repertoire = current_sub_repertoire
@tag_repertoires = current_sub_repertoire.tag_repertoires
end
def create
name = params[:name].to_s.strip
return render_error('名称重复') if current_sub_repertoire.tag_repertoires.where(name: name).exists?
TagRepertoire.create!(name: name, sub_repertoire_id: current_sub_repertoire.id)
render_ok
end
def edit
@tag_repertoire = current_tag_repertoire
end
def update
if params[:tag_repertoire] && params[:tag_repertoire][:name].present?
name = params[:tag_repertoire][:name].to_s.strip
current_tag_repertoire.update_attributes!(name: name)
end
@tag_repertoires = current_tag_repertoire.sub_repertoire&.tag_repertoires
end
def destroy
@tag_repertoire_id = params[:id]
current_tag_repertoire.destroy!
end
private
def current_sub_repertoire
@_current_sub_repertoire = SubRepertoire.find params[:sub_repertoire_id]
end
def current_tag_repertoire
@_current_tag_repertoire = TagRepertoire.find params[:id]
end
end

@ -92,7 +92,7 @@ class ApplicationController < ActionController::Base
# 判断用户的邮箱或者手机是否可用 # 判断用户的邮箱或者手机是否可用
# params[:type] 1: 注册2忘记密码 # params[:type] 1: 注册2忘记密码3绑定
def check_mail_and_phone_valid login, type def check_mail_and_phone_valid login, type
unless login =~ /^[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/ || login =~ /^1\d{10}$/ || unless login =~ /^[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/ || login =~ /^1\d{10}$/ ||
login =~ /^[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])$/ login =~ /^[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])$/
@ -104,6 +104,8 @@ class ApplicationController < ActionController::Base
tip_exception(-2, "该手机号码或邮箱已被注册") tip_exception(-2, "该手机号码或邮箱已被注册")
elsif type.to_i == 2 && user.nil? elsif type.to_i == 2 && user.nil?
tip_exception(-2, "该手机号码或邮箱未注册") tip_exception(-2, "该手机号码或邮箱未注册")
elsif type.to_i == 3 && user.present?
tip_exception(-2, "该手机号码或邮箱已绑定")
end end
sucess_status sucess_status
end end
@ -218,7 +220,7 @@ class ApplicationController < ActionController::Base
# 未授权的捕捉407弹试用申请弹框 # 未授权的捕捉407弹试用申请弹框
def require_login def require_login
#6.13 -hs #6.13 -hs
tip_exception(401, "..") unless User.current.logged? tip_exception(401, "请登录后再操作") unless User.current.logged?
end end
# 异常提醒 # 异常提醒
@ -306,7 +308,7 @@ class ApplicationController < ActionController::Base
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 8686
end end
@ -632,7 +634,8 @@ class ApplicationController < ActionController::Base
end end
def paginate(relation) def paginate(relation)
limit = (params[:limit].to_i.zero? || params[:limit].to_i > 20) ? 20 : params[:limit].to_i limit = params[:limit] || params[:per_page]
limit = (limit.to_i.zero? || limit.to_i > 20) ? 20 : limit.to_i
page = params[:page].to_i.zero? ? 1 : params[:page].to_i page = params[:page].to_i.zero? ? 1 : params[:page].to_i
offset = (page - 1) * limit offset = (page - 1) * limit
@ -643,6 +646,8 @@ class ApplicationController < ActionController::Base
end end
end end
def strf_time(time) def strf_time(time)
time.blank? ? '' : time.strftime("%Y-%m-%d %H:%M:%S") time.blank? ? '' : time.strftime("%Y-%m-%d %H:%M:%S")
end end

@ -17,9 +17,11 @@ class AttachmentsController < ApplicationController
redirect_to @file.cloud_url and return redirect_to @file.cloud_url and return
end end
pdf_attachment = params[:disposition] || "attachment" type_attachment = params[:disposition] || "attachment"
if pdf_attachment == "inline" if type_attachment == "inline"
send_file absolute_path(local_path(@file)),filename: @file.title, disposition: 'inline',type: 'application/pdf' send_file absolute_path(local_path(@file)),filename: @file.title, disposition: 'inline',type: 'application/pdf'
elsif type_attachment == "MP4"
send_file_with_range absolute_path(local_path(@file)), disposition: 'inline', type: "video/mp4", range: true
else else
send_file(absolute_path(local_path(@file)), filename: @file.title,stream:false, type: @file.content_type.presence || 'application/octet-stream') send_file(absolute_path(local_path(@file)), filename: @file.title,stream:false, type: @file.content_type.presence || 'application/octet-stream')
end end
@ -202,4 +204,31 @@ class AttachmentsController < ApplicationController
end end
end end
def send_file_with_range(path, options = {})
logger.info("########request.headers: #{request.headers}")
logger.info("########request.headers: #{File.exist?(path)}")
if File.exist?(path)
size = File.size(path)
logger.info("########request.headers: #{request.headers}")
if !request.headers["Range"]
status_code = 200 # 200 OK
offset = 0
length = File.size(path)
else
status_code = 206 # 206 Partial Content
bytes = Rack::Utils.byte_ranges(request.headers, size)[0]
offset = bytes.begin
length = bytes.end - bytes.begin
end
response.header["Accept-Ranges"] = "bytes"
response.header["Content-Range"] = "bytes #{bytes.begin}-#{bytes.end}/#{size}" if bytes
response.header["status"] = status_code
send_data IO.binread(path, length, offset), options
else
raise ActionController::MissingFile, "Cannot read file #{path}."
end
end
end end

@ -181,7 +181,7 @@ class ChallengesController < ApplicationController
begin begin
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
tab = params[:tab].to_i tab = params[:tab].to_i
@challenge.update_attributes(challenge_params) @challenge.update_attributes!(challenge_params)
if tab == 0 && @challenge.st == 0 if tab == 0 && @challenge.st == 0
@challenge.challenge_tags.delete_all @challenge.challenge_tags.delete_all
if params[:challenge_tag].present? if params[:challenge_tag].present?
@ -211,7 +211,7 @@ class ChallengesController < ApplicationController
# last 末尾匹配, full: 全完匹配 # last 末尾匹配, full: 全完匹配
logger.info("set: #{set}; match_rule : #{set[:match_rule]}") logger.info("set: #{set}; match_rule : #{set[:match_rule]}")
match_rule = set[:match_rule] == 'last' ? 'last' : 'full' match_rule = set[:match_rule] == 'last' ? 'last' : 'full'
TestSet.create(:challenge_id => @challenge.id, TestSet.create!(:challenge_id => @challenge.id,
:input => "#{set[:input]}", :input => "#{set[:input]}",
:output => "#{set[:output]}", :output => "#{set[:output]}",
:is_public => params_hidden[index], :is_public => params_hidden[index],
@ -227,8 +227,11 @@ class ChallengesController < ApplicationController
@challenge.update_attributes(picture_path: nil, web_route: nil, expect_picture_path: nil, original_picture_path: nil) @challenge.update_attributes(picture_path: nil, web_route: nil, expect_picture_path: nil, original_picture_path: nil)
end end
# 关卡评测执行文件如果被修改,需要修改脚本内容 # 关卡评测执行文件如果被修改,需要修改脚本内容
logger.info("############shixun_publiced:#{@shixun.public == 0}")
if @shixun.public == 0
script = modify_shixun_script @shixun, @shixun.evaluate_script script = modify_shixun_script @shixun, @shixun.evaluate_script
@shixun.shixun_info.update_column(:evaluate_script, script) @shixun.shixun_info.update_column(:evaluate_script, script)
end
# TODO: # TODO:
# if path != params[:challenge][:path] # if path != params[:challenge][:path]
# shixun_modify_status_without_publish(@shixun, 1) # shixun_modify_status_without_publish(@shixun, 1)
@ -237,9 +240,9 @@ class ChallengesController < ApplicationController
end end
end end
rescue => e rescue Exception => e
logger_error("##update_challenges: ##{e.message}") logger.error("##update_challenges: ##{e.message}")
tip_exception("更新失败!") tip_exception("#{e.message}")
end end
end end
@ -262,7 +265,7 @@ class ChallengesController < ApplicationController
params[:challenge_answer].each_with_index do |answer, index| params[:challenge_answer].each_with_index do |answer, index|
# 内容为空不保存 # 内容为空不保存
next if answer[:contents].blank? next if answer[:contents].blank?
ChallengeAnswer.create(name: answer[:name], contents: answer[:contents], ChallengeAnswer.create!(name: answer[:name], contents: answer[:contents],
level: index+1, score: answer[:score], challenge_id: @challenge.id) level: index+1, score: answer[:score], challenge_id: @challenge.id)
end end
end end

@ -136,22 +136,22 @@ class CollegesController < ApplicationController
private private
def require_login # def require_login
return if User.current.logged? # return if User.current.logged?
#
redirect_to "/login?back_url=#{CGI::escape(request.fullpath)}" # redirect_to "/login?back_url=#{CGI::escape(request.fullpath)}"
end # end
def check_college_present! def check_college_present!
return if current_college.present? return if current_college.present?
redirect_to '/404' tip_exception(404, "")
end end
def check_manage_permission! def check_manage_permission!
return if can_manage_college? return if can_manage_college?
redirect_to '/403' tip_exception(403, "")
end end
def can_manage_college? def can_manage_college?
@ -160,7 +160,7 @@ class CollegesController < ApplicationController
return true if current_user.is_teacher? && current_user.school_id == current_school.id # 学校老师 return true if current_user.is_teacher? && current_user.school_id == current_school.id # 学校老师
# return true if current_school.customers.exists? && current_user.partner&.partner_customers&.exists?(customer_id: current_school.customer_id) # return true if current_school.customers.exists? && current_user.partner&.partner_customers&.exists?(customer_id: current_school.customer_id)
false tip_exception(403, "")
end end
def current_school def current_school

@ -6,12 +6,17 @@ module ControllerRescueHandler
Util.logger_error e Util.logger_error e
render json: {status: -1, message: e.message} render json: {status: -1, message: e.message}
end end
rescue_from ActiveRecord::StatementInvalid do |e|
Util.logger_error e
render json: {status: -1, message: "接口数据异常"}
end
# rescue_from ActionView::MissingTemplate, with: :object_not_found # rescue_from ActionView::MissingTemplate, with: :object_not_found
# rescue_from ActiveRecord::RecordNotFound, with: :object_not_found # rescue_from ActiveRecord::RecordNotFound, with: :object_not_found
rescue_from Educoder::TipException, with: :tip_show rescue_from Educoder::TipException, with: :tip_show
rescue_from ::ActionView::MissingTemplate, with: :missing_template rescue_from ::ActionView::MissingTemplate, with: :missing_template
rescue_from ActiveRecord::RecordNotFound, with: :object_not_found rescue_from ActiveRecord::RecordNotFound, with: :object_not_found
rescue_from ActionController::ParameterMissing, with: :render_parameter_missing rescue_from ActionController::ParameterMissing, with: :render_parameter_missing
# form validation error # form validation error
rescue_from ActiveModel::ValidationError do |ex| rescue_from ActiveModel::ValidationError do |ex|
render_error(ex.model.errors.full_messages.join(',')) render_error(ex.model.errors.full_messages.join(','))
@ -19,5 +24,9 @@ module ControllerRescueHandler
rescue_from ActiveRecord::RecordInvalid do |ex| rescue_from ActiveRecord::RecordInvalid do |ex|
render_error(ex.record.errors.full_messages.join(',')) render_error(ex.record.errors.full_messages.join(','))
end end
# rescue_from RuntimeError do |ex|
# Util.logger_error "#######ex:#{ex}"
# render_error(ex.message)
# end
end end
end end

@ -16,7 +16,7 @@ module LoginHelper
:expires => 1.month.from_now, :expires => 1.month.from_now,
:path => '/', :path => '/',
:secure => false, :secure => false,
:httponly => true :httponly => false
} }
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'))

@ -1,6 +1,7 @@
class CoursesController < ApplicationController class CoursesController < ApplicationController
include MessagesHelper include MessagesHelper
include ExportHelper include ExportHelper
include CustomSortable
# model validation error # model validation error
rescue_from ActiveRecord::RecordInvalid do |ex| rescue_from ActiveRecord::RecordInvalid do |ex|
@ -23,8 +24,8 @@ class CoursesController < ApplicationController
:course_group_list, :set_course_group, :change_course_admin, :change_course_teacher, :course_group_list, :set_course_group, :change_course_admin, :change_course_teacher,
:delete_course_teacher, :teacher_application_review, :students, :all_course_groups, :delete_course_teacher, :teacher_application_review, :students, :all_course_groups,
:transfer_to_course_group, :delete_from_course, :search_users, :add_students_by_search, :transfer_to_course_group, :delete_from_course, :search_users, :add_students_by_search,
:base_info, :get_historical_courses, :create_group_by_importing_file, :base_info, :get_historical_courses, :create_group_by_importing_file, :course_videos,
:attahcment_category_list,:export_member_scores_excel, :duplicate_course, :attahcment_category_list,:export_member_scores_excel, :duplicate_course, :delete_course_video,
:switch_to_teacher, :switch_to_assistant, :switch_to_student, :exit_course, :switch_to_teacher, :switch_to_assistant, :switch_to_student, :exit_course,
:informs, :update_informs, :online_learning, :update_task_position, :tasks_list, :informs, :update_informs, :online_learning, :update_task_position, :tasks_list,
:join_excellent_course, :export_couser_info, :export_member_act_score, :new_informs, :join_excellent_course, :export_couser_info, :export_member_act_score, :new_informs,
@ -100,6 +101,23 @@ class CoursesController < ApplicationController
@courses = @courses.preload(:school, :none_hidden_course_modules, teacher: :user_extension) @courses = @courses.preload(:school, :none_hidden_course_modules, teacher: :user_extension)
end end
def course_videos
logger.info("########[#{@course}")
videos = @course.videos
videos = custom_sort(videos, params[:sort_by], params[:sort_direction])
@count = videos.count
@videos = paginate videos
end
def delete_course_video
video = Video.find_by(id: params[:video_id])
tip_exception(404, "找不到资源") if video.blank?
tip_exception(403, "...") unless (video.user_id == current_user.id || current_user.admin_or_business?)
video.destroy!
AliyunVod::Service.delete_video([video.uuid]) rescue nil
render_ok
end
def visits_plus_one def visits_plus_one
new_visits = @course.visits + 1 new_visits = @course.visits + 1
@course.update_visits(new_visits) @course.update_visits(new_visits)
@ -377,6 +395,7 @@ class CoursesController < ApplicationController
def destroy def destroy
if @course.is_delete == 0 if @course.is_delete == 0
@course.delete! @course.delete!
Tiding.where(belong_container: @course).update_all(is_delete: 1)
Tiding.create!(user_id: current_user.id, trigger_user_id: current_user.id, container_id: @course.id, Tiding.create!(user_id: current_user.id, trigger_user_id: current_user.id, container_id: @course.id,
container_type: 'DeleteCourse', tiding_type: 'System', belong_container: @course, extra: @course.name) container_type: 'DeleteCourse', tiding_type: 'System', belong_container: @course, extra: @course.name)
normal_status(0, "成功") normal_status(0, "成功")
@ -1146,6 +1165,7 @@ class CoursesController < ApplicationController
if existing_student.present? if existing_student.present?
# 如果在该课堂已经存在学生身份,且邀请码为分班邀请码,则将其直接加入分班 # 如果在该课堂已经存在学生身份,且邀请码为分班邀请码,则将其直接加入分班
existing_student.update!(course_group_id: course_group.id) if course_group.present? existing_student.update!(course_group_id: course_group.id) if course_group.present?
message = "您已是课堂成员"
else else
correspond_teacher_exist = current_user.none_admin_teacher_of_course? course correspond_teacher_exist = current_user.none_admin_teacher_of_course? course
new_student = CourseMember.new(user_id: current_user.id, course_id: course.id, role: 4) new_student = CourseMember.new(user_id: current_user.id, course_id: course.id, role: 4)
@ -1156,9 +1176,9 @@ class CoursesController < ApplicationController
CourseAddStudentCreateWorksJob.perform_later(course.id, [current_user.id]) CourseAddStudentCreateWorksJob.perform_later(course.id, [current_user.id])
StudentJoinCourseNotifyJob.perform_later(current_user.id, course.id) StudentJoinCourseNotifyJob.perform_later(current_user.id, course.id)
end
student_role = 1 student_role = 1
end end
end
# 创建教师身份 # 创建教师身份
if (params[:professor].present? && params[:professor].to_i == 1) || (params[:assistant_professor].present? && params[:assistant_professor].to_i == 1) if (params[:professor].present? && params[:professor].to_i == 1) || (params[:assistant_professor].present? && params[:assistant_professor].to_i == 1)
@ -1194,9 +1214,9 @@ class CoursesController < ApplicationController
teacher_role = 1 teacher_role = 1
end end
if teacher_role && student_role if (teacher_role && student_role) || message.to_s == "您已是课堂成员"
render json: { status: 0, message: message, course_id: course.id} render json: { status: 0, message: message, course_id: course.id}
elsif student_role elsif student_role.to_i == 1
render json: { status: 0, message: "加入成功", course_id: course.id} render json: { status: 0, message: "加入成功", course_id: course.id}
else else
normal_status(message) normal_status(message)

@ -24,7 +24,6 @@ class ExerciseQuestionsController < ApplicationController
#question_type 0为单选题1为多选题2为判断题3为填空题单空和多空4为简答题5为实训题 #question_type 0为单选题1为多选题2为判断题3为填空题单空和多空4为简答题5为实训题
def create def create
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
begin
question_options = { question_options = {
:question_title => params[:question_title], :question_title => params[:question_title],
:question_type => params[:question_type].present? ? params[:question_type].to_i : 0, #默认为单选题 :question_type => params[:question_type].present? ? params[:question_type].to_i : 0, #默认为单选题
@ -141,11 +140,6 @@ class ExerciseQuestionsController < ApplicationController
@exercise_question.update!(:question_score => question_score, :shixun_name => shixun_name) @exercise_question.update!(:question_score => question_score, :shixun_name => shixun_name)
end end
end end
rescue Exception => e
uid_logger_error(e.message)
tip_exception("试卷问题创建失败!")
raise ActiveRecord::Rollback
end
end end
end end
@ -164,20 +158,13 @@ class ExerciseQuestionsController < ApplicationController
def edit def edit
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
begin
@exercise_choices = @exercise_question.exercise_choices @exercise_choices = @exercise_question.exercise_choices
@exercise_question_shixun = @exercise_question.exercise_shixun_challenges @exercise_question_shixun = @exercise_question.exercise_shixun_challenges
rescue Exception => e
uid_logger_error(e.message)
tip_exception("页面调用失败!")
raise ActiveRecord::Rollback
end
end end
end end
def update def update
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
begin
standard_answer_change = false standard_answer_change = false
# 更新试卷题目的内容 # 更新试卷题目的内容
question_options = { question_options = {
@ -375,12 +362,6 @@ class ExerciseQuestionsController < ApplicationController
else else
normal_status(0, "试卷更新成功!") normal_status(0, "试卷更新成功!")
end end
rescue Exception => e
uid_logger_error(e.message)
tip_exception("页面调用失败!")
raise ActiveRecord::Rollback
end
end end
end end
@ -493,7 +474,6 @@ class ExerciseQuestionsController < ApplicationController
#老师调分窗口 #老师调分窗口
def adjust_score def adjust_score
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
begin
ex_all_scores = @exercise.exercise_questions.pluck(:question_score).sum ex_all_scores = @exercise.exercise_questions.pluck(:question_score).sum
ex_obj_score = @exercise_current_user.objective_score #全部客观题得分 ex_obj_score = @exercise_current_user.objective_score #全部客观题得分
ex_subj_score = @exercise_current_user.subjective_score < 0.0 ? 0.0 : @exercise_current_user.subjective_score #全部主观题得分 ex_subj_score = @exercise_current_user.subjective_score < 0.0 ? 0.0 : @exercise_current_user.subjective_score #全部主观题得分
@ -668,11 +648,6 @@ class ExerciseQuestionsController < ApplicationController
end end
end end
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
raise ActiveRecord::Rollback
end
end end
end end

@ -1168,7 +1168,7 @@ class ExercisesController < ApplicationController
#班级的选择 #班级的选择
if params[:exercise_group_id].present? if params[:exercise_group_id].present?
group_id = params[:exercise_group_id] group_id = params[:exercise_group_id]
exercise_students = @course_all_members.course_find_by_ids("course_group_id", group_id) #试卷所分班的全部人数 exercise_students = @course_all_members.course_find("course_group_id", group_id) #试卷所分班的全部人数
user_ids = exercise_students.pluck(:user_id).reject(&:blank?) user_ids = exercise_students.pluck(:user_id).reject(&:blank?)
@exercise_users_list = @exercise_users_list.exercise_commit_users(user_ids) @exercise_users_list = @exercise_users_list.exercise_commit_users(user_ids)
end end

@ -368,6 +368,7 @@ class HomeworkCommonsController < ApplicationController
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
begin begin
@homework = HomeworkCommon.new(homework_params) @homework = HomeworkCommon.new(homework_params)
@homework.reference_answer = params[:reference_answer].to_s.strip
@homework.homework_type = @homework_type @homework.homework_type = @homework_type
@homework.user_id = current_user.id @homework.user_id = current_user.id
@homework.course_id = @course.id @homework.course_id = @course.id
@ -417,6 +418,7 @@ class HomeworkCommonsController < ApplicationController
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
begin begin
@homework.update_attributes!(homework_params) @homework.update_attributes!(homework_params)
@homework.reference_answer = params[:reference_answer].to_s.strip
if @homework.homework_type == "group" if @homework.homework_type == "group"
homework_detail_group = @homework.homework_detail_group homework_detail_group = @homework.homework_detail_group
@ -497,7 +499,7 @@ class HomeworkCommonsController < ApplicationController
# tip_exception("challenge_id参数的长度与challenge_score参数的长度不匹配") if # tip_exception("challenge_id参数的长度与challenge_score参数的长度不匹配") if
# params[:challenge_settings][:challenge_score].length != params[:challenge_settings][:challenge_id].length # params[:challenge_settings][:challenge_score].length != params[:challenge_settings][:challenge_id].length
sum_challenge_score = params[:challenge_settings].pluck(:challenge_score).reject(&:blank?).map{|score| score.to_f}.sum sum_challenge_score = params[:challenge_settings].pluck(:challenge_score).reject(&:blank?)&.map{|score| score.to_f}.sum
total_score = params[:work_efficiency] ? (params[:eff_score].to_f + sum_challenge_score) : sum_challenge_score total_score = params[:work_efficiency] ? (params[:eff_score].to_f + sum_challenge_score) : sum_challenge_score
tip_exception("分值之和必须等于总分值:#{params[:total_score]}") if params[:total_score].to_f.round(2) != total_score.to_f.round(2) tip_exception("分值之和必须等于总分值:#{params[:total_score]}") if params[:total_score].to_f.round(2) != total_score.to_f.round(2)
@ -910,7 +912,7 @@ class HomeworkCommonsController < ApplicationController
def publish_homework def publish_homework
tip_exception("请至少选择一个分班") if params[:group_ids].blank? && @course.course_groups.size != 0 tip_exception("请至少选择一个分班") if params[:group_ids].blank? && @course.course_groups.size != 0
group_ids = params[:group_ids]&.reject(&:blank?).map(&:to_i) group_ids = params[:group_ids]&.reject(&:blank?)&.map(&:to_i)
if params[:detail].blank? if params[:detail].blank?
tip_exception("缺少截止时间参数") if params[:end_time].blank? tip_exception("缺少截止时间参数") if params[:end_time].blank?
tip_exception("截止时间不能早于当前时间") if params[:end_time] <= strf_time(Time.now) tip_exception("截止时间不能早于当前时间") if params[:end_time] <= strf_time(Time.now)
@ -918,7 +920,7 @@ class HomeworkCommonsController < ApplicationController
@course.end_date.present? && params[:end_time] > strf_time(@course.end_date.end_of_day) @course.end_date.present? && params[:end_time] > strf_time(@course.end_date.end_of_day)
else else
tip_exception("缺少分班截止时间参数") if params[:group_end_times].blank? tip_exception("缺少分班截止时间参数") if params[:group_end_times].blank?
group_end_times = params[:group_end_times].reject(&:blank?).map{|time| time.to_time} group_end_times = params[:group_end_times].reject(&:blank?)&.map{|time| time.to_time}
tip_exception("截止时间和分班参数的个数不一致") if group_end_times.length != group_ids.length tip_exception("截止时间和分班参数的个数不一致") if group_end_times.length != group_ids.length
group_end_times.each do |time| group_end_times.each do |time|
tip_exception("分班截止时间不能早于当前时间") if time <= Time.now tip_exception("分班截止时间不能早于当前时间") if time <= Time.now
@ -1049,7 +1051,7 @@ class HomeworkCommonsController < ApplicationController
homeworks = homeworks.published_no_end.includes(:homework_group_settings, :homework_detail_manual, :homework_challenge_settings) homeworks = homeworks.published_no_end.includes(:homework_group_settings, :homework_detail_manual, :homework_challenge_settings)
course_students = @course.students course_students = @course.students
charge_group_ids = @course.charge_group_ids(current_user) charge_group_ids = @course.charge_group_ids(current_user)
group_ids = params[:group_ids]&.reject(&:blank?).map(&:to_i) group_ids = params[:group_ids]&.reject(&:blank?)&.map(&:to_i)
end_groups = charge_group_ids & group_ids if group_ids end_groups = charge_group_ids & group_ids if group_ids
begin begin
@ -1404,8 +1406,8 @@ class HomeworkCommonsController < ApplicationController
end end
def homework_params def homework_params
tip_exception("name参数不能为空") if params[:name].blank? tip_exception("标题不能为空") if params[:name].blank?
tip_exception("description参数不能为空") if params[:description].blank? tip_exception("内容不能为空") if params[:description].blank?
params.require(:homework_common).permit(:name, :description, :reference_answer) params.require(:homework_common).permit(:name, :description, :reference_answer)
end end

@ -0,0 +1,69 @@
class LiveLinksController < ApplicationController
before_action :require_login
before_action :find_course, only: [:index, :create]
before_action :user_course_identity, :teacher_allowed, only: [:create]
before_action :edit_auth, only: [:edit, :update]
before_action :delete_auth, only: [:destroy]
def index
lives = @course.live_links
order_str = "on_status desc, live_time desc"
@total_count = lives.size
@my_live_id = @course.live_links.find_by(user_id: current_user.id)&.id
# order_str = "live_links.id = #{@my_live_id} desc, #{order_str}" if @my_live_id.present?
lives = lives.order("#{order_str}")
@lives = paginate lives.includes(user: :user_extension)
end
def create
on_status = params[:live_time].present? && params[:live_time].to_time <= Time.now ? 1 : 0
@course.live_links.create!(create_params.merge(user_id: current_user.id, on_status: on_status))
render_ok
end
def edit
@live = current_live
end
def update
if params[:on_status]
tip_exception("请勿重复开启") if current_live.on_status && params[:on_status].to_i == 1
ActiveRecord::Base.transaction do
current_live.update!(on_status: params[:on_status])
# 开启时发送消息,关闭直播时删除对应的消息
if params[:on_status].to_i == 1
LivePublishJob.perform_later(current_live.id)
end
end
else
on_status = params[:live_time].present? && params[:live_time].to_time <= Time.now ? 1 : 0
current_live.update!(create_params.merge(on_status: on_status))
end
render_ok
end
def destroy
current_live.destroy!
render_ok
end
private
def create_params
params.permit(:url, :description, :course_name, :platform, :live_time, :duration)
end
def current_live
@_current_live = LiveLink.find params[:id]
end
def edit_auth
tip_exception(403, "无权限操作") unless current_user.id == current_live.user_id || current_user.admin_or_business?
end
def delete_auth
tip_exception(403, "无权限操作") unless current_user.id == current_live.user_id || current_user.admin?
end
end

@ -8,6 +8,27 @@ class MainController < ApplicationController
end end
def index def index
domain_session = params[:_educoder_session]
if domain_session
uid_logger("main start domain_session is #{domain_session}")
if cookies[:_educoder_session] != domain_session
cookies[:_educoder_session] = nil
cookies[:_educoder_session] = domain_session
end
uid_logger("main start is #{cookies[:_educoder_session]}")
end
if params[:path] && params[:path]&.include?("educoderh5") && params[:path].split("/").first == "educoderh5"
render file: 'public/h5build/index.html', :layout => false
# TODO: 这块之后需要整合到上面去或者架构重新变化统一跳转到index后再路由分发
elsif params[:path] && params[:path]&.include?("h5educoderbuild") && params[:path].split("/").first == "h5educoderbuild"
render file: 'public/h5educoderbuild/index.html', :layout => false
else
render file: 'public/react/build/index.html', :layout => false render file: 'public/react/build/index.html', :layout => false
end end
end
end end

@ -270,7 +270,9 @@ class MyshixunsController < ApplicationController
uid_logger_dubug("-- game build: file update #{@sec_key}, record id is #{record.id}, time is **** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}") uid_logger_dubug("-- game build: file update #{@sec_key}, record id is #{record.id}, time is **** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}")
end end
# 隐藏代码文件 和 VNC的都不需要走版本库 # 隐藏代码文件 和 VNC的都不需要走版本库
unless @hide_code || (@myshixun.shixun&.vnc_evaluate && params[:evaluate].present?) vnc = @myshixun.shixun&.vnc
unless @hide_code || (vnc && params[:evaluate].present?)
# 远程版本库文件内容 # 远程版本库文件内容
last_content = GitService.file_content(repo_path: @repo_path, path: path)["content"] last_content = GitService.file_content(repo_path: @repo_path, path: path)["content"]
@ -280,8 +282,8 @@ class MyshixunsController < ApplicationController
else else
params[:content] params[:content]
end end
uid_logger_dubug("###11222333####{content}") uid_logger_dubug("content_#{@myshixun.identifier}: #{content}")
uid_logger_dubug("###222333####{last_content}") uid_logger_dubug("###last_content_#{@myshixun.identifier}####{last_content}")
if content != last_content if content != last_content
@content_modified = 1 @content_modified = 1
@ -291,6 +293,7 @@ class MyshixunsController < ApplicationController
message = params[:evaluate] == 0 ? "System automatically submitted" : "User submitted" message = params[:evaluate] == 0 ? "System automatically submitted" : "User submitted"
uid_logger_dubug("112233#{author_name}") uid_logger_dubug("112233#{author_name}")
uid_logger_dubug("112233#{author_email}") uid_logger_dubug("112233#{author_email}")
uid_logger_dubug("daiao_debug_#{@myshixun.identifier}: #{@repo_path}: #{path}; #{message}; #{content}; ")
@content = GitService.update_file(repo_path: @repo_path, @content = GitService.update_file(repo_path: @repo_path,
file_path: path, file_path: path,
message: message, message: message,

@ -25,7 +25,6 @@ class PollQuestionsController < ApplicationController
# 创建题目和选择的答案 # 创建题目和选择的答案
def create def create
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
begin
poll_options = { poll_options = {
:question_title => params[:question_title], :question_title => params[:question_title],
:question_type => params[:question_type], :question_type => params[:question_type],
@ -69,11 +68,6 @@ class PollQuestionsController < ApplicationController
end end
end end
end end
rescue Exception => e
uid_logger_error(e.message)
tip_exception("问卷的问题创建失败!")
raise ActiveRecord::Rollback
end
end end
end end
@ -103,7 +97,6 @@ class PollQuestionsController < ApplicationController
def update def update
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
begin
if @poll_question.question_type < 3 #当为单选题或多选题时 if @poll_question.question_type < 3 #当为单选题或多选题时
p_answer = params[:question_answers] p_answer = params[:question_answers]
p_other_answer = params[:question_other_answer] p_other_answer = params[:question_other_answer]
@ -143,11 +136,6 @@ class PollQuestionsController < ApplicationController
end end
@poll_question.update!(poll_questions_params) @poll_question.update!(poll_questions_params)
rescue Exception => e
uid_logger_error(e.message)
tip_exception("更新失败")
raise ActiveRecord::Rollback
end
end end
end end

@ -6,7 +6,6 @@ class PollVotesController < ApplicationController
def create #每一次答案的点击,请求一次 def create #每一次答案的点击,请求一次
begin
question_votes = @poll_question.poll_votes question_votes = @poll_question.poll_votes
question_type = @poll_question.question_type question_type = @poll_question.question_type
question_answer_id = params[:poll_answer_id] ? params[:poll_answer_id] : -1 #该答案的id question_answer_id = params[:poll_answer_id] ? params[:poll_answer_id] : -1 #该答案的id
@ -115,11 +114,6 @@ class PollVotesController < ApplicationController
@current_question_status = 1 @current_question_status = 1
end end
end end
rescue Exception => e
uid_logger_error(e.message)
tip_exception("页面调用失败!")
raise ActiveRecord::Rollback
end
end end

@ -126,7 +126,6 @@ class PollsController < ApplicationController
# un_anonymous 是否实名默认为false即不公开 # un_anonymous 是否实名默认为false即不公开
def create def create
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
begin
poll_name = params[:polls_name] poll_name = params[:polls_name]
poll_desc = params[:polls_description] poll_desc = params[:polls_description]
poll_options = { poll_options = {
@ -138,11 +137,6 @@ class PollsController < ApplicationController
:polls_type => "Course", :polls_type => "Course",
} }
@poll = Poll.create!(poll_options) @poll = Poll.create!(poll_options)
rescue Exception => e
uid_logger_error(e.message)
tip_exception("问卷创建失败!")
raise ActiveRecord::Rollback
end
end end
end end
@ -160,7 +154,6 @@ class PollsController < ApplicationController
def update def update
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
begin
poll_name = params[:polls_name] poll_name = params[:polls_name]
poll_des = params[:polls_description] poll_des = params[:polls_description]
poll_params = { poll_params = {
@ -169,11 +162,6 @@ class PollsController < ApplicationController
} }
@poll.update!(poll_params) @poll.update!(poll_params)
normal_status(0, "问卷更新成功!") normal_status(0, "问卷更新成功!")
rescue Exception => e
uid_logger_error(e.message)
tip_exception("没有权限")
raise ActiveRecord::Rollback
end
end end
end end
@ -258,16 +246,14 @@ class PollsController < ApplicationController
if params[:detail].blank? if params[:detail].blank?
tip_exception("缺少截止时间参数") if params[:end_time].blank? tip_exception("缺少截止时间参数") if params[:end_time].blank?
tip_exception("截止时间不能早于当前时间") if params[:end_time] <= strf_time(Time.now) tip_exception("截止时间不能早于当前时间") if params[:end_time] <= strf_time(Time.now)
tip_exception("截止时间不能晚于课堂结束时间(#{@course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")}") if tip_exception("截止时间不能晚于课堂结束时间(#{@course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")}") if @course.end_date.present? && params[:end_time] > strf_time(@course.end_date.end_of_day)
@course.end_date.present? && params[:end_time] > strf_time(@course.end_date.end_of_day)
else else
group_end_times = params[:group_end_times].reject(&:blank?).map {|time| time.to_time} group_end_times = params[:group_end_times].reject(&:blank?).map {|time| time.to_time}
tip_exception("缺少截止时间参数") if group_end_times.blank? tip_exception("缺少截止时间参数") if group_end_times.blank?
tip_exception("截止时间和分班参数的个数不一致") if group_end_times.length != group_ids.length tip_exception("截止时间和分班参数的个数不一致") if group_end_times.length != group_ids.length
group_end_times.each do |time| group_end_times.each do |time|
tip_exception("分班截止时间不能早于当前时间") if time <= Time.now tip_exception("分班截止时间不能早于当前时间") if time <= Time.now
tip_exception("分班截止时间不能晚于课堂结束时间(#{@course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")}") if tip_exception("分班截止时间不能晚于课堂结束时间(#{@course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")}") if @course.end_date.present? && time > @course.end_date.end_of_day
@course.end_date.present? && time > @course.end_date.end_of_day
end end
end end
@ -725,8 +711,7 @@ class PollsController < ApplicationController
tip_exception("发布时间不能为空") if params[:publish_time].blank? tip_exception("发布时间不能为空") if params[:publish_time].blank?
tip_exception("截止时间不能为空") if params[:end_time].blank? tip_exception("截止时间不能为空") if params[:end_time].blank?
tip_exception("截止时间必须晚于发布时间") if params[:publish_time].to_time >= params[:end_time].to_time tip_exception("截止时间必须晚于发布时间") if params[:publish_time].to_time >= params[:end_time].to_time
tip_exception("截止时间不能晚于课堂结束时间(#{@course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")}") if tip_exception("截止时间不能晚于课堂结束时间(#{@course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")}") if @course.end_date.present? && params[:end_time].to_time > @course.end_date.end_of_day
@course.end_date.present? && params[:end_time].to_time > @course.end_date.end_of_day
params_publish_time = params[:publish_time].to_time params_publish_time = params[:publish_time].to_time
params_end_time = params[:end_time].to_time params_end_time = params[:end_time].to_time
@ -761,8 +746,7 @@ class PollsController < ApplicationController
tip_exception("发布时间不能为空") if t[:publish_time].blank? tip_exception("发布时间不能为空") if t[:publish_time].blank?
tip_exception("截止时间不能为空") if t[:end_time].blank? tip_exception("截止时间不能为空") if t[:end_time].blank?
tip_exception("截止时间不能早于发布时间") if t[:publish_time].to_time > t[:end_time].to_time tip_exception("截止时间不能早于发布时间") if t[:publish_time].to_time > t[:end_time].to_time
tip_exception("截止时间不能晚于课堂结束时间(#{@course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")}") if tip_exception("截止时间不能晚于课堂结束时间(#{@course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")}") if @course.end_date.present? && t[:end_time].to_time > @course.end_date.end_of_day
@course.end_date.present? && t[:end_time].to_time > @course.end_date.end_of_day
course_id = t[:course_group_id] course_id = t[:course_group_id]
poll_publish_time = t[:publish_time].to_time poll_publish_time = t[:publish_time].to_time

@ -26,7 +26,7 @@ class ShixunsController < ApplicationController
before_action :special_allowed, only: [:send_to_course, :search_user_courses] before_action :special_allowed, only: [:send_to_course, :search_user_courses]
before_action :shixun_marker, only: [:new, :create] before_action :shixun_marker, only: [:new, :create]
before_action :validate_wachat_support, only: [:shixun_exec] #before_action :validate_wachat_support, only: [:shixun_exec]
skip_before_action :check_sign, only: [:download_file] skip_before_action :check_sign, only: [:download_file]
## 获取课程列表 ## 获取课程列表
@ -475,7 +475,7 @@ class ShixunsController < ApplicationController
if params[:shixun][:vnc] if params[:shixun][:vnc]
shixun_params.merge(vnc_evaluate: 1) shixun_params.merge(vnc_evaluate: 1)
else else
shixun_params shixun_params.merge(vnc_evaluate: 0)
end end
@shixun.update_attributes!(update_params) @shixun.update_attributes!(update_params)
end end
@ -1187,11 +1187,11 @@ private
md5.hexdigest md5.hexdigest
end end
def validate_wachat_support # def validate_wachat_support
#
if (params[:wechat].present? && !@shixun.is_wechat_support?) # if (params[:wechat].present? && !@shixun.is_wechat_support?)
tip_exception(-5, "..") # tip_exception(-5, "..")
end # end
end # end
end end

@ -72,7 +72,7 @@ class SubjectsController < ApplicationController
end end
# 排序 # 排序
order_str = reorder == "publish_time" ? "status = 2 desc, publish_time asc" : "updated_at desc" order_str = (reorder == "publish_time" ? "homepage_show desc, excellent desc, status = 2 desc, publish_time asc" : "homepage_show desc, excellent desc, updated_at desc")
@subjects = @subjects.reorder(order_str) @subjects = @subjects.reorder(order_str)
end end
@ -242,13 +242,13 @@ class SubjectsController < ApplicationController
## 云上实验室过滤 ## 云上实验室过滤
@courses = @courses.where(id: current_laboratory.all_courses) @courses = @courses.where(id: current_laboratory.all_courses)
@none_shixun_ids = ShixunSchool.where("school_id != #{current_user.user_extension.try(:school_id).to_i}").pluck(:shixun_id) @none_shixun_ids = @subject.shixuns.joins(:shixun_schools).where("school_id != #{current_user.user_extension.try(:school_id).to_i}").where(use_scope: 1).pluck(:id)
end end
def send_to_course def send_to_course
@course = Course.find_by!(id: params[:course_id]) @course = Course.find_by!(id: params[:course_id])
stages = @subject.stages.where(id: @subject.stage_shixuns.where(shixun_id: params[:shixun_ids]).pluck(:stage_id)) stages = @subject.stages.where(id: @subject.stage_shixuns.where(shixun_id: params[:shixun_ids]).pluck(:stage_id)).reorder("stages.position DESC")
order_ids = params[:shixun_ids].size > 0 ? params[:shixun_ids].reverse.join(',') : -1
course_module = @course.course_modules.where(module_type: "shixun_homework").first course_module = @course.course_modules.where(module_type: "shixun_homework").first
homework_ids = [] homework_ids = []
@ -259,7 +259,8 @@ class SubjectsController < ApplicationController
CourseSecondCategory.create!(name: stage.name, course_id: @course.id, category_type: "shixun_homework", CourseSecondCategory.create!(name: stage.name, course_id: @course.id, category_type: "shixun_homework",
course_module_id: course_module.id, position: course_module.course_second_categories.count + 1) course_module_id: course_module.id, position: course_module.course_second_categories.count + 1)
stage.shixuns.no_jupyter.where(id: params[:shixun_ids], status: 2).each do |shixun| shixuns = stage.shixuns.no_jupyter.published.where(id: params[:shixun_ids]).reorder("field(shixuns.id, #{order_ids})")
shixuns.each do |shixun|
homework = HomeworksService.new.create_homework shixun, @course, category, current_user homework = HomeworksService.new.create_homework shixun, @course, category, current_user
homework_ids << homework.id homework_ids << homework.id
end end

@ -2,8 +2,6 @@ class TagDisciplinesController < ApplicationController
before_action :require_login before_action :require_login
def create def create
tip_exception("请输入知识点") if params[:name].blank?
tip_exception("输入字符长度限制在15个以内") if params[:name].length > 15
sub_discipline = SubDiscipline.find_by!(id: params[:sub_discipline_id]) sub_discipline = SubDiscipline.find_by!(id: params[:sub_discipline_id])
tip_exception("重复的知识点") if sub_discipline.tag_disciplines.exists?(name: params[:name].to_s.strip) tip_exception("重复的知识点") if sub_discipline.tag_disciplines.exists?(name: params[:name].to_s.strip)
tag_discipline = TagDiscipline.create!(name: params[:name].to_s.strip, sub_discipline: sub_discipline, user_id: current_user.id) tag_discipline = TagDiscipline.create!(name: params[:name].to_s.strip, sub_discipline: sub_discipline, user_id: current_user.id)

@ -5,7 +5,7 @@ class TidingsController < ApplicationController
after_action :update_onclick_time!, only: [:index] after_action :update_onclick_time!, only: [:index]
def index def index
tidings = current_user.tidings tidings = current_user.tidings.visible
@onclick_time = current_user.click_time @onclick_time = current_user.click_time
tiding_types = tiding_types =
@ -19,8 +19,9 @@ class TidingsController < ApplicationController
end end
tidings = tidings.where(tiding_type: tiding_types) if tiding_types.present? tidings = tidings.where(tiding_type: tiding_types) if tiding_types.present?
tidings = tidings.where(container_type: 'JoinCourse') if params[:type] == 'course_apply' tidings = tidings.where(container_type: 'JoinCourse', status: 0) if params[:type] == 'course_apply'
@course_apply_count = tidings.where("created_at > '#{@onclick_time}'").where(container_type: 'JoinCourse').count # @course_apply_count = tidings.where("created_at > '#{@onclick_time}'").where(container_type: 'JoinCourse', status: 0).count
@course_apply_count = tidings.where(container_type: 'JoinCourse', status: 0).count
tidings = tidings.where(container_type: 'ProjectPackage') if params[:type] == 'project_package' tidings = tidings.where(container_type: 'ProjectPackage') if params[:type] == 'project_package'

@ -13,7 +13,7 @@ class Users::VideosController < Users::BaseController
end end
def update def update
return render_error('该状态下不能编辑视频信息') unless current_video.published? return render_error('该状态下不能编辑视频信息') unless (current_video.published? || current_video.course_videos.present?)
current_video.update!(title: params[:title]) current_video.update!(title: params[:title])
@ -39,6 +39,13 @@ class Users::VideosController < Users::BaseController
@videos = paginate videos @videos = paginate videos
end end
def get_video_data
start_time = params[:start_time].to_time.utc.strftime('%Y-%m-%dT%H:%M:%SZ')
end_time = params[:end_time].to_time.utc.strftime('%Y-%m-%dT%H:%M:%SZ')
result = AliyunVod::Service.video_data(current_video.uuid, start_time, end_time)
render :json => {data: result}
end
def batch_publish def batch_publish
Videos::BatchPublishService.call(observed_user, batch_publish_params) Videos::BatchPublishService.call(observed_user, batch_publish_params)
render_ok render_ok
@ -50,6 +57,14 @@ class Users::VideosController < Users::BaseController
def current_video def current_video
@_current_video ||= observed_user.videos.find_by(id: params[:id]) @_current_video ||= observed_user.videos.find_by(id: params[:id])
if @_current_video.nil?
video = Video.find_by(id: params[:id])
if video.course_videos.present?
video
end
else
@_current_video
end
end end
def search_params def search_params
@ -57,6 +72,6 @@ class Users::VideosController < Users::BaseController
end end
def batch_publish_params def batch_publish_params
params.permit(videos: %i[video_id title]) params.permit(videos: %i[video_id title course_id])
end end
end end

@ -52,7 +52,7 @@ class UsersController < ApplicationController
def attachment_show def attachment_show
file_name = params[:file_name] file_name = params[:file_name]
path = params[:path] path = params[:path] || edu_setting('attachment_folder')
send_file "#{path}/#{file_name}", :filename => "#{file_name}", send_file "#{path}/#{file_name}", :filename => "#{file_name}",
:type => 'game', :type => 'game',
:disposition => 'attachment' #inline can open in browser :disposition => 'attachment' #inline can open in browser

@ -0,0 +1,26 @@
class Weapps::ChallengesController < Weapps::BaseController
before_action :require_login
before_action :set_challenge
def is_play
# 关卡有展示效果 || 选择题 || jupyter实训 || vnc || 隐藏代码窗口 || html+css实训
# @challenge.show_type != -1 || @challenge.st == 1 || @shixun.is_jupyter? || @shixun.vnc ||
# @shixun.hide_code? || (@shixun.small_mirror_name & ["Css", "Html", "Web"]).present?
play = @challenge.st == 1 || @shixun.is_jupyter? || @shixun.vnc ||
@shixun.hide_code? || (@shixun.small_mirror_name & ["Css", "Html", "Web"]).present?
if play
normal_status(-5, "该关卡暂不支持小程序")
else
render_ok
end
end
private
def set_challenge
@challenge = Challenge.find_by!(id: params[:id])
@shixun = @challenge.shixun
end
end

@ -1,7 +1,8 @@
class Weapps::CoursesController < Weapps::BaseController class Weapps::CoursesController < Weapps::BaseController
before_action :require_login before_action :require_login
before_action :set_course, :user_course_identity, except: [:create] before_action :set_course, except: [:create, :check_invite_code]
before_action :check_account, only: [:create] before_action :user_course_identity, except: [:basic_info, :create, :check_invite_code]
before_action :check_account, only: [:create, :check_invite_code]
before_action :teacher_allowed, only: [:edit, :update] before_action :teacher_allowed, only: [:edit, :update]
before_action :teacher_or_admin_allowed, only: [:change_member_roles, :delete_course_teachers] before_action :teacher_or_admin_allowed, only: [:change_member_roles, :delete_course_teachers]
@ -9,19 +10,23 @@ class Weapps::CoursesController < Weapps::BaseController
# return render_error("只有老师身份才能创建课堂") unless current_user.is_teacher? # return render_error("只有老师身份才能创建课堂") unless current_user.is_teacher?
course = Course.new(tea_id: current_user.id) course = Course.new(tea_id: current_user.id)
Weapps::CreateCourseService.call(course, course_params) Weapps::CreateCourseService.call(course, course_params)
render_ok render_ok(id: course.id)
rescue ApplicationService::Error => ex rescue ApplicationService::Error => ex
render_error(ex.message) render_error(ex.message)
end end
def basic_info
@course = current_course
end
def edit def edit
@course = current_course @course = current_course
end end
def update def update
Weapps::UpdateCourseService.call(current_course, update_course_params) course = Weapps::UpdateCourseService.call(current_course, update_course_params)
render_ok render_ok(id: course.id)
end end
def show def show
@ -33,6 +38,23 @@ class Weapps::CoursesController < Weapps::BaseController
@categories = current_course.shixun_course_modules.first&.course_second_categories @categories = current_course.shixun_course_modules.first&.course_second_categories
end end
def check_invite_code
tip_exception(-1, "邀请码不能为空") if params[:invite_code].blank?
invite_code = params[:invite_code]
course = Course.find_by(invite_code: invite_code, is_delete: 0, invite_code_halt: 0)
course_group = CourseGroup.find_by(invite_code: invite_code)
if course.blank?
tip_exception(-1, "邀请码无效") if course_group.blank?
course = Course.find_by(id: course_group.course_id, is_delete: 0, invite_code_halt: 0)
tip_exception(-1, "邀请码无效") if course.blank?
end
tip_exception(-1, "课堂已结束,无法加入") if course.is_end
render_ok
end
# 教师列表 # 教师列表
def teachers def teachers
@course = current_course @course = current_course
@ -179,11 +201,11 @@ class Weapps::CoursesController < Weapps::BaseController
private private
def course_params def course_params
params.permit(:name, :course_list_name, :credit, course_module_types: []) params.permit(:name, :course_list_name, :credit, :end_date, course_module_types: [])
end end
def update_course_params def update_course_params
params.permit(:name, :course_list_name, :credit) params.permit(:name, :course_list_name, :credit, :end_date)
end end
def current_course def current_course

@ -17,7 +17,13 @@ class Weapps::SessionsController < Weapps::BaseController
# session[:wechat_user_extra].delete(:nickName) # session[:wechat_user_extra].delete(:nickName)
# 绑定微信号 # 绑定微信号
OpenUsers::Wechat.create!(user: user, uid: session_unionid) if user.wechat_open_user.blank? # open_user = OpenUsers::Wechat.find_by(uid: session_unionid)
# if open_user.present? && open_user.user_id.nil?
# open_user.update!(user_id: user.id)
# els
if user.wechat_open_user.blank?
OpenUsers::Wechat.create!(user: user, uid: session_unionid)
end
successful_authentication(user) successful_authentication(user)
end end

@ -0,0 +1,15 @@
class Weapps::ShixunListsController < ApplicationController
before_action :require_login
def index
results = Weapps::ShixunSearchService.call(search_params, current_laboratory)
@total_count = results.size
@results = paginate results
end
private
def search_params
params.permit(:keyword, :type, :page, :limit, :order, :status, :diff, :sort, :no_jupyter)
end
end

@ -0,0 +1,28 @@
class Weapps::SubjectsController < Weapps::BaseController
before_action :require_login
before_action :find_subject, except: [:index]
# 首页
def index
subjects = Weapps::SubjectQuery.call(current_laboratory, params)
@subject_count = subjects.map(&:id).size
@subjects = paginate subjects
end
# 详情
def show
# 合作团队
Rails.logger.info("##########subject: #{@subject.id}")
@members = @subject.subject_members.includes(:user)
shixuns = @subject.shixuns.published.pluck(:id)
challenge_ids = Challenge.where(shixun_id: shixuns).pluck(:id)
# 实训路径中的所有实训标签
@tags = ChallengeTag.where(challenge_id: challenge_ids).pluck(:name).uniq
end
private
def find_subject
@subject = Subject.find(params[:id])
end
end

@ -0,0 +1,16 @@
class Weapps::UnbindAccountsController < Weapps::BaseController
before_action :require_login
def show
@user = current_user
end
def destroy
open_user = OpenUsers::Wechat.find_by!(user_id: current_user.id)
session[:unionid] = open_user.uid
open_user.destroy!
UserAction.create(action_id: current_user.id, action_type: "UnbindWechat", user_id: current_user.id, :ip => request.remote_ip)
logout_user
render_ok
end
end

@ -321,6 +321,10 @@ module TidingDecorator
I18n.t(locale_format(parent_container_type)) % container&.exercise_name I18n.t(locale_format(parent_container_type)) % container&.exercise_name
end end
def live_link_content
I18n.t(locale_format) % container&.course_name
end
def student_graduation_topic_content def student_graduation_topic_content
I18n.t(locale_format) % container&.graduation_topic.try(:name) I18n.t(locale_format) % container&.graduation_topic.try(:name)
end end

@ -7,8 +7,6 @@ class ItemBanks::SaveItemForm
validates :sub_discipline_id, presence: true validates :sub_discipline_id, presence: true
validates :item_type, presence: true, inclusion: {in: %W(SINGLE MULTIPLE JUDGMENT COMPLETION SUBJECTIVE PRACTICAL PROGRAM)} validates :item_type, presence: true, inclusion: {in: %W(SINGLE MULTIPLE JUDGMENT COMPLETION SUBJECTIVE PRACTICAL PROGRAM)}
validates :difficulty, presence: true, inclusion: {in: 1..3}, numericality: { only_integer: true } validates :difficulty, presence: true, inclusion: {in: 1..3}, numericality: { only_integer: true }
validates :name, presence: true, length: { maximum: 1000, too_long: "不能超过1000个字符" }
validates :analysis, length: { maximum: 1000, too_long: "不能超过1000个字符" }
def validate! def validate!
super super
@ -27,7 +25,6 @@ class ItemBanks::SaveItemForm
attr_accessor :choice_text, :is_answer attr_accessor :choice_text, :is_answer
validates :choice_text, presence: true, length: { maximum: 500, too_long: "不能超过500个字符" }
validates :is_answer, presence: true, inclusion: {in: 0..1}, numericality: { only_integer: true } validates :is_answer, presence: true, inclusion: {in: 0..1}, numericality: { only_integer: true }
end end
end end

@ -2,7 +2,7 @@ class Weapps::CreateCourseForm
include ActiveModel::Model include ActiveModel::Model
attr_accessor :course attr_accessor :course
attr_accessor :name, :course_list_name, :credit, :course_module_types attr_accessor :name, :course_list_name, :credit, :course_module_types, :end_date
validates :name, presence: true validates :name, presence: true
validates :course_list_name, presence: true validates :course_list_name, presence: true

@ -2,7 +2,7 @@ class Weapps::UpdateCourseForm
include ActiveModel::Model include ActiveModel::Model
attr_accessor :course attr_accessor :course
attr_accessor :name, :course_list_name, :credit attr_accessor :name, :course_list_name, :credit, :end_date
validates :name, presence: true validates :name, presence: true
validates :course_list_name, presence: true validates :course_list_name, presence: true

@ -65,6 +65,8 @@ module CoursesHelper
"/courses/#{course.id}/course_groups" "/courses/#{course.id}/course_groups"
when "statistics" when "statistics"
"/courses/#{course.id}/statistics" "/courses/#{course.id}/statistics"
when "video"
"/courses/#{course.id}/course_videos"
end end
end end
@ -126,6 +128,8 @@ module CoursesHelper
course.informs.count course.informs.count
when "online_learning" when "online_learning"
course.shixuns.count course.shixuns.count
when "video"
course.course_videos.count + course.live_links.count
end end
end end

@ -171,10 +171,10 @@ module HomeworkCommonsHelper
{status: status, time: time} {status: status, time: time}
end end
# 作品数统计type 1 已提交 0 未提交 # 作品数统计type 1 已提交 0 未提交 2 所有
def studentwork_count homework_common, type, member def studentwork_count homework_common, type, member
student_works = homework_common.teacher_works(member) student_works = homework_common.teacher_works(member)
type == 1 ? student_works.where("work_status != 0").size : student_works.where(work_status: 0).size type == 2 ? student_works.size : (type == 1 ? student_works.where("work_status != 0").size : student_works.where(work_status: 0).size)
end end
# 上次查重的时间 # 上次查重的时间

@ -152,7 +152,7 @@ module ShixunsHelper
challenge_program_name = [] challenge_program_name = []
shixun.challenges.map(&:exec_path).each do |exec_path| shixun.challenges.map(&:exec_path).each do |exec_path|
challenge_program_name << "\"#{exec_path}\"" challenge_program_name << "\"#{exec_path}\""
if shixun.main_mirror_name == "Java" if shixun.main_mirror_name == "Java" || shixun.main_mirror_name == "Openjdk10/VNC"
if exec_path.nil? || exec_path.split("src/")[1].nil? if exec_path.nil? || exec_path.split("src/")[1].nil?
source = "\"\"" source = "\"\""
else else

@ -1,15 +1,16 @@
module Weapps::CoursesHelper module Weapps::CoursesHelper
require 'chinese_pinyin' require 'chinese_pinyin'
def teacher_list teachers def teacher_list teachers, user_course_identity
data = [] data = []
teachers.each do |teacher| teachers.each do |teacher|
if teacher.user.present? if teacher.user.present?
teacher_user = teacher.user teacher_user = teacher.user
name = teacher_user.real_name name = teacher_user.real_name
role = teacher.role == "CREATOR" ? "管理员" : teacher.role == "PROFESSOR" ? "教师" : "助教" role = teacher.role == "CREATOR" ? "管理员" : teacher.role == "PROFESSOR" ? "教师" : "助教"
member_roles = user_course_identity < Course::ASSISTANT_PROFESSOR ? teacher_user.course_role(teacher.course) : []
item = {name: name, course_member_id: teacher.id, login: teacher_user.login, user_id: teacher.user_id, role: role, item = {name: name, course_member_id: teacher.id, login: teacher_user.login, user_id: teacher.user_id, role: role,
school: teacher_user.school_name, image_url: url_to_avatar(teacher_user)} school: teacher_user.school_name, image_url: url_to_avatar(teacher_user), member_roles: member_roles}
pinyin = Pinyin.t(name.strip, splitter: '') pinyin = Pinyin.t(name.strip, splitter: '')
first_char = pinyin[0] first_char = pinyin[0]
letter = first_letter first_char letter = first_letter first_char
@ -28,15 +29,16 @@ module Weapps::CoursesHelper
end end
def student_list students, excellent def student_list students, excellent, user_course_identity
data = [] data = []
students.each do |student| students.each do |student|
if student.user.present? if student.user.present?
student_user = student.user student_user = student.user
name = student_user.real_name name = student_user.real_name
phone = excellent ? "" : student_user.hidden_phone phone = excellent ? "" : student_user.hidden_phone
member_roles = user_course_identity < Course::ASSISTANT_PROFESSOR ? student_user.course_role(student.course) : []
item = {name: name, course_member_id: student.id, login: student_user.login, user_id: student.user_id, item = {name: name, course_member_id: student.id, login: student_user.login, user_id: student.user_id,
student_id: student_user.student_id, image_url: url_to_avatar(student_user), phone: phone} student_id: student_user.student_id, image_url: url_to_avatar(student_user), phone: phone, member_roles: member_roles}
pinyin = Pinyin.t(name.strip, splitter: '') pinyin = Pinyin.t(name.strip, splitter: '')
first_char = pinyin[0] first_char = pinyin[0]
letter = first_letter first_char letter = first_letter first_char

@ -0,0 +1,27 @@
# 直播开启的消息通知
class LivePublishJob < ApplicationJob
queue_as :notify
def perform(live_id)
live = LiveLink.find_by(id: live_id)
return if live.blank? || live.course.blank?
course = live.course
attrs = %i[
user_id trigger_user_id container_id container_type parent_container_id parent_container_type
belong_container_id belong_container_type viewed tiding_type created_at updated_at
]
same_attrs = {
trigger_user_id: live.user_id, container_id: live.id, container_type: 'LiveLink',
parent_container_id: live.id, parent_container_type: 'LiveLink',
belong_container_id: live.course_id, belong_container_type: 'Course',
viewed: 0, tiding_type: 'LiveLink'
}
Tiding.bulk_insert(*attrs) do |worker|
course.students.pluck(:user_id).each do |user_id|
worker.add same_attrs.merge(user_id: user_id)
end
end
end
end

@ -37,4 +37,19 @@ module AliyunVod::Service::VideoManage
result result
end end
# 视频播放数据
def video_data(video_id, start_time, end_time)
params = {
Action: 'DescribePlayVideoStatis',
VideoId: video_id,
StartTime: start_time,
EndTime: end_time,
}.merge(base_params)
puts params
result = request(:post, params)
result
end
end end

@ -4,4 +4,5 @@ module CustomRegexp
LASTNAME = /\A[a-zA-Z0-9\u4e00-\u9fa5]+\z/ LASTNAME = /\A[a-zA-Z0-9\u4e00-\u9fa5]+\z/
NICKNAME = /\A[\u4e00-\u9fa5_a-zA-Z0-9]+\z/ NICKNAME = /\A[\u4e00-\u9fa5_a-zA-Z0-9]+\z/
PASSWORD = /\A[a-z_A-Z0-9\-\.!@#\$%\\\^&\*\)\(\+=\{\}\[\]\/",'_<>~\·`\?:;|]{8,16}\z/ PASSWORD = /\A[a-z_A-Z0-9\-\.!@#\$%\\\^&\*\)\(\+=\{\}\[\]\/",'_<>~\·`\?:;|]{8,16}\z/
URL = /\Ahttps?:\/\/[-A-Za-z0-9+&@#\/%?=~_|!:,.;]+[-A-Za-z0-9+&@#\/%=~_|]\z/
end end

@ -28,7 +28,7 @@ class Challenge < ApplicationRecord
scope :fields_for_list, -> { select([:id, :subject, :st, :score, :position, :shixun_id]) } scope :fields_for_list, -> { select([:id, :subject, :st, :score, :position, :shixun_id]) }
validates :task_pass, length: { maximum: 10000, too_long: "不能超过10000个字符" } validates :task_pass, length: { maximum: 35000, too_long: "不能超过35000个字符" }
after_commit :create_diff_record after_commit :create_diff_record

@ -3,7 +3,7 @@ class ChallengeAnswer < ApplicationRecord
belongs_to :challenge belongs_to :challenge
has_many :game_answers, :dependent => :destroy has_many :game_answers, :dependent => :destroy
validates :contents, length: { maximum: 5000 , too_long: "不能超过5000个字符"} validates :contents, length: { maximum: 25000 , too_long: "不能超过25000个字符"}
def view_answer_time(user_id) def view_answer_time(user_id)
game_answers.where(user_id: user_id).last&.view_time game_answers.where(user_id: user_id).last&.view_time

@ -4,6 +4,6 @@ class ChallengeChoose < ApplicationRecord
has_many :challenge_tags, :dependent => :destroy has_many :challenge_tags, :dependent => :destroy
has_many :challenge_questions, dependent: :destroy has_many :challenge_questions, dependent: :destroy
validates :subject, length: { maximum: 1000, too_long: "不能超过1000个字符" } validates :subject, length: { maximum: 25000, too_long: "不能超过25000个字符" }
end end

@ -81,6 +81,13 @@ class Course < ApplicationRecord
# 老版的members弃用 现用course_members # 老版的members弃用 现用course_members
has_many :members has_many :members
# 视频
has_many :course_videos, dependent: :destroy
has_many :videos, through: :course_videos
# 直播
has_many :live_links, dependent: :destroy
validate :validate_sensitive_string validate :validate_sensitive_string
scope :hidden, ->(is_hidden = true) { where(is_hidden: is_hidden) } scope :hidden, ->(is_hidden = true) { where(is_hidden: is_hidden) }
@ -206,7 +213,7 @@ class Course < ApplicationRecord
end end
def all_course_module_types def all_course_module_types
%w[activity announcement online_learning shixun_homework common_homework group_homework exercise attachment course_group graduation poll board statistics] %w[activity announcement online_learning shixun_homework common_homework group_homework exercise attachment course_group graduation poll board statistics video]
end end
def get_course_module_by_type(type) def get_course_module_by_type(type)
@ -406,6 +413,7 @@ class Course < ApplicationRecord
when 'exercise' then '试卷' when 'exercise' then '试卷'
when 'poll' then '问卷' when 'poll' then '问卷'
when 'attachment' then '资源' when 'attachment' then '资源'
when 'video' then '视频直播'
when 'board' then '讨论' when 'board' then '讨论'
when 'course_group' then '分班' when 'course_group' then '分班'
when 'statistics' then '统计' when 'statistics' then '统计'
@ -425,9 +433,10 @@ class Course < ApplicationRecord
when 'exercise' then 8 when 'exercise' then 8
when 'poll' then 9 when 'poll' then 9
when 'attachment' then 10 when 'attachment' then 10
when 'board' then 11 when 'video' then 11
when 'course_group' then 12 when 'board' then 12
when 'statistics' then 13 when 'course_group' then 13
when 'statistics' then 14
else 100 else 100
end end
end end

@ -0,0 +1,4 @@
class CourseVideo < ApplicationRecord
belongs_to :course
belongs_to :video
end

@ -4,4 +4,7 @@ class Discipline < ApplicationRecord
has_many :shixun_sub_disciplines, -> { where("shixun = 1") }, class_name: "SubDiscipline" has_many :shixun_sub_disciplines, -> { where("shixun = 1") }, class_name: "SubDiscipline"
has_many :subject_sub_disciplines, -> { where("subject = 1") }, class_name: "SubDiscipline" has_many :subject_sub_disciplines, -> { where("subject = 1") }, class_name: "SubDiscipline"
has_many :question_sub_disciplines, -> { where("question = 1") }, class_name: "SubDiscipline" has_many :question_sub_disciplines, -> { where("question = 1") }, class_name: "SubDiscipline"
validates_presence_of :name
end end

@ -35,7 +35,7 @@ class HomeworkCommon < ApplicationRecord
# 学生的查重情况 # 学生的查重情况
has_many :homework_review_results, :dependent => :destroy has_many :homework_review_results, :dependent => :destroy
validates :name, length: { maximum: 60, too_long: "不能超过60个字符" } validates :name, presence: true, length: { maximum: 60, too_long: "不能超过60个字符" }
validates :description, length: { maximum: 15000, too_long: "不能超过15000个字符" } validates :description, length: { maximum: 15000, too_long: "不能超过15000个字符" }
validates :explanation, length: { maximum: 5000, too_long: "不能超过5000个字符" } validates :explanation, length: { maximum: 5000, too_long: "不能超过5000个字符" }
validates :reference_answer, length: { maximum: 15000, too_long: "不能超过15000个字符" } validates :reference_answer, length: { maximum: 15000, too_long: "不能超过15000个字符" }

@ -1,3 +1,4 @@
class ItemAnalysis < ApplicationRecord class ItemAnalysis < ApplicationRecord
belongs_to :item_bank, touch: true belongs_to :item_bank, touch: true
validates :analysis, length: { maximum: 5000, too_long: "不能超过5000个字符" }
end end

@ -13,6 +13,7 @@ class ItemBank < ApplicationRecord
has_many :tag_disciplines, through: :tag_discipline_containers has_many :tag_disciplines, through: :tag_discipline_containers
belongs_to :container, polymorphic: true, optional: true belongs_to :container, polymorphic: true, optional: true
validates :name, presence: true, length: { maximum: 1000, too_long: "不能超过1000个字符" }
def analysis def analysis
item_analysis&.analysis item_analysis&.analysis

@ -1,3 +1,5 @@
class ItemChoice < ApplicationRecord class ItemChoice < ApplicationRecord
belongs_to :item_bank, touch: true belongs_to :item_bank, touch: true
validates :choice_text, presence: true, length: { maximum: 500, too_long: "不能超过500个字符" }
end end

@ -0,0 +1,21 @@
class LiveLink < ApplicationRecord
belongs_to :course
belongs_to :user
has_many :tidings, as: :container, dependent: :destroy
# validates :url, format: { with: CustomRegexp::URL, message: "必须为网址超链接" }
validates :description, length: { maximum: 100, too_long: "不能超过100个字符" }
validates :course_name, presence: true
validates :platform, presence: true
# validates :live_time, presence: true
validates :duration, numericality: { only_integer: true, greater_than: 0}, allow_blank: true
def op_auth?
user == User.current || User.current.admin_or_business?
end
def delete_auth?
user == User.current || User.current.admin?
end
end

@ -8,6 +8,7 @@ class MirrorRepository < ApplicationRecord
scope :published_mirror, -> { where(status: [1,2,3,5]) } scope :published_mirror, -> { where(status: [1,2,3,5]) }
scope :published_main_mirror, -> { published_mirror.where(main_type: 1) } scope :published_main_mirror, -> { published_mirror.where(main_type: 1) }
scope :published_small_mirror, -> { published_mirror.where(main_type: 0) } scope :published_small_mirror, -> { published_mirror.where(main_type: 0) }
scope :small_mirror, -> { where(main_type: 0) }
def deletable? def deletable?
status != 1 && !shixun_mirror_repositories.exists? status != 1 && !shixun_mirror_repositories.exists?

@ -0,0 +1,7 @@
class Salesman < ApplicationRecord
belongs_to :user
# 渠道
has_many :salesman_channels, dependent: :destroy
# 客户
has_many :salesman_customers, dependent: :destroy
end

@ -0,0 +1,3 @@
class SalesmanChannel < ApplicationRecord
belongs_to :salesman, :touch => true, counter_cache: true
end

@ -0,0 +1,22 @@
class SalesmanCustomer < ApplicationRecord
belongs_to :salesman, :touch => true, counter_cache: true
belongs_to :school
belongs_to :user
def name
user.real_name
end
def school_name
school.name
end
def courses_count
CourseMember.where(user_id: id).teachers_and_admin.count
end
def shixuns_count
ShixunMember.where(user_id: id, role: [1, 2]).count
end
end

@ -171,7 +171,8 @@ class Shixun < ApplicationRecord
# 实训对应的镜像小类别名(已选) # 实训对应的镜像小类别名(已选)
def small_mirror_name def small_mirror_name
mirror_repositories.published_small_mirror.map(&:type_name) names = mirror_repositories.small_mirror.map(&:type_name)
names.blank? ? [] : names
end end
def small_mirror_id def small_mirror_id

@ -111,6 +111,7 @@ class StudentWork < ApplicationRecord
# 作品总体评价 # 作品总体评价
def overall_appraisal def overall_appraisal
return "--" if work_status == 0
case (self.work_score.to_f / homework_common.total_score).round(2) case (self.work_score.to_f / homework_common.total_score).round(2)
when (0.90..1.00) when (0.90..1.00)
'优秀' '优秀'

@ -1,9 +1,13 @@
class SubDiscipline < ApplicationRecord class SubDiscipline < ApplicationRecord
belongs_to :discipline belongs_to :discipline
has_many :tag_disciplines, dependent: :destroy has_many :tag_disciplines, dependent: :destroy
has_many :sub_discipline_containers, dependent: :destroy
has_one :hack has_one :hack
has_many :shixun_tag_disciplines, -> { where("shixun = 1") }, class_name: "TagDiscipline" has_many :shixun_tag_disciplines, -> { where("shixun = 1") }, class_name: "TagDiscipline"
has_many :subject_tag_disciplines, -> { where("subject = 1") }, class_name: "TagDiscipline" has_many :subject_tag_disciplines, -> { where("subject = 1") }, class_name: "TagDiscipline"
has_many :question_tag_disciplines, -> { where("question = 1") }, class_name: "TagDiscipline" has_many :question_tag_disciplines, -> { where("question = 1") }, class_name: "TagDiscipline"
validates_presence_of :name
end end

@ -0,0 +1,5 @@
class SubDisciplineContainer < ApplicationRecord
belongs_to :sub_discipline
belongs_to :container, polymorphic: true, optional: true, touch: true
end

@ -30,6 +30,8 @@ class Subject < ApplicationRecord
has_many :subject_course_records, dependent: :destroy has_many :subject_course_records, dependent: :destroy
has_many :subject_shixun_infos, dependent: :destroy has_many :subject_shixun_infos, dependent: :destroy
has_many :subject_user_infos, dependent: :destroy has_many :subject_user_infos, dependent: :destroy
has_many :sub_discipline_containers, as: :container, dependent: :destroy
has_many :sub_disciplines, through: :sub_discipline_containers
validates :name, length: { maximum: 60, too_long: "不能超过60个字符" } validates :name, length: { maximum: 60, too_long: "不能超过60个字符" }
validates :description, length: { maximum: 8000, too_long: "不能超过8000个字符" } validates :description, length: { maximum: 8000, too_long: "不能超过8000个字符" }
@ -63,6 +65,10 @@ class Subject < ApplicationRecord
excellent ? CourseMember.where(role: 4, course_id: courses.pluck(:id)).pluck(:user_id).length : shixuns.pluck(:myshixuns_count).sum excellent ? CourseMember.where(role: 4, course_id: courses.pluck(:id)).pluck(:user_id).length : shixuns.pluck(:myshixuns_count).sum
end end
def myshixuns_count
shixuns.pluck(:myshixuns_count).sum
end
def all_score def all_score
subject_shixun_score + subject_shixun_choose_score subject_shixun_score + subject_shixun_choose_score
end end

@ -4,6 +4,7 @@ class TagDiscipline < ApplicationRecord
has_many :tag_discipline_containers, dependent: :destroy has_many :tag_discipline_containers, dependent: :destroy
validates_presence_of :name validates_presence_of :name
validates :name, length: { maximum: 15, too_long: "不能超过15个字符" }
def discipline def discipline
sub_discipline&.discipline sub_discipline&.discipline

@ -1,7 +1,7 @@
class TestSet < ApplicationRecord class TestSet < ApplicationRecord
# match_rule: 匹配规则: full 完全匹配, last 末尾匹配 # match_rule: 匹配规则: full 完全匹配, last 末尾匹配
# #
validates :input, length: { maximum: 5000, too_long: "不能超过5000个字符" } validates :input, length: { maximum: 65000, too_long: "不能超过65000个字符" }
validates :output, length: { maximum: 5000, too_long: "不能超过5000个字符" } validates :output, length: { maximum: 65000, too_long: "不能超过65000个字符" }
end end

@ -7,6 +7,8 @@ class Tiding < ApplicationRecord
has_many :attachments, as: :container has_many :attachments, as: :container
scope :visible, -> { where(is_delete: 0) }
def identifier def identifier
value = nil value = nil

@ -4,6 +4,7 @@ class Video < ApplicationRecord
belongs_to :user belongs_to :user
has_many :video_applies, dependent: :destroy has_many :video_applies, dependent: :destroy
has_many :course_videos, dependent: :destroy
has_one :processing_video_apply, -> { where(status: :pending) }, class_name: 'VideoApply' has_one :processing_video_apply, -> { where(status: :pending) }, class_name: 'VideoApply'
aasm(:status) do aasm(:status) do
@ -33,4 +34,8 @@ class Video < ApplicationRecord
transitions from: :uploading, to: :uploaded transitions from: :uploading, to: :uploaded
end end
end end
def video_play_duration
(play_duration / (60*60.0)).ceil
end
end end

@ -0,0 +1,37 @@
class Weapps::SubjectQuery < ApplicationQuery
include CustomSortable
attr_reader :params
def initialize(current_laboratory, params)
@current_laboratory = current_laboratory
@params = params
end
def call
subjects = @current_laboratory.subjects.unhidden.visible
# 课程体系的过滤
if params[:sub_discipline_id].present?
subjects = subjects.joins(:sub_disciplines).where(sub_disciplines: {id: params[:sub_discipline_id]})
elsif params[:discipline_id].present?
subjects = subjects.joins(:sub_disciplines).where(sub_disciplines: {discipline_id: params[:discipline_id]})
else
subjects = subjects.joins(:sub_discipline_containers).where(sub_discipline_containers: {container_type: "Subject"})
end
subjects = subjects.left_joins(:shixuns).select('subjects.id, subjects.name, subjects.excellent, subjects.stages_count, subjects.status, subjects.homepage_show,
subjects.shixuns_count, subjects.updated_at, IFNULL(sum(shixuns.myshixuns_count), 0) myshixuns_count')
.group('subjects.id').order("subjects.homepage_show #{sort_type}, #{order_type} #{sort_type}")
subjects
end
private
def order_type
params[:order] || "updated_at"
end
def sort_type
params[:sort] || "desc"
end
end

@ -36,10 +36,10 @@ class Admins::ImportCourseMemberService < ApplicationService
member = course.course_members.find_by(user_id: user.id, role: data.role.to_i) member = course.course_members.find_by(user_id: user.id, role: data.role.to_i)
# 如果已是课堂成员且是学生身份and不在指定的分班则移动到该分班 # 如果已是课堂成员且是学生身份and不在指定的分班则移动到该分班
if member.present? && member.role == 'STUDENT' && course_group && member.course_group_id != course_group&.id if member.present? && member.role == 'STUDENT' && course_group && member.course_group_id != course_group&.id.to_i
member.update!(course_group_id: course_group&.id) member.update!(course_group_id: course_group&.id.to_i)
elsif member.blank? elsif member.blank?
course.course_members.create!(user_id: user.id, role: data.role.to_i, course_group_id: course_group&.id) course.course_members.create!(user_id: user.id, role: data.role.to_i, course_group_id: course_group&.id.to_i)
extra = extra =
case data.role.to_i case data.role.to_i
when 2 then 9 when 2 then 9

@ -60,7 +60,7 @@ class Subjects::CopySubjectService < ApplicationService
shixun = stage_shixun.shixun shixun = stage_shixun.shixun
to_shixun = Shixun.new to_shixun = Shixun.new
to_shixun.attributes = shixun.attributes.dup.except('id', 'user_id', 'identifier', 'homepage_show', to_shixun.attributes = shixun.attributes.dup.except('id', 'user_id', 'identifier', 'homepage_show',
'use_scope', 'averge_star', 'myshixuns_count', 'challenges_count', "public") 'use_scope', 'averge_star', 'myshixuns_count', 'challenges_count')
to_shixun.identifier = Util::UUID.generate_identifier(Shixun, 8) to_shixun.identifier = Util::UUID.generate_identifier(Shixun, 8)
to_shixun.user_id = user.id to_shixun.user_id = user.id
if laboratory if laboratory

@ -22,7 +22,7 @@ class Subjects::CourseUsedInfoService < ApplicationService
# choice_shixun_frequency: 选用该课程实训的次数 # choice_shixun_frequency: 选用该课程实训的次数
course_info = [] course_info = []
schools.find_in_batches do |s| schools.find_in_batches do |s|
Parallel.each(s) do |school| s.each do |school|
name = school.name name = school.name
course_count = school.course_count course_count = school.course_count
student_count = school.courses.joins(:course_members).where(course_members: {role: 4, course_id: course_ids}).size student_count = school.courses.joins(:course_members).where(course_members: {role: 4, course_id: course_ids}).size

@ -11,7 +11,7 @@ class Subjects::ShixunUsedInfoService < ApplicationService
position = stage.position position = stage.position
shixuns = stage.shixuns.includes(myshixuns: :games, homework_commons: :course) shixuns = stage.shixuns.includes(myshixuns: :games, homework_commons: :course)
shixuns.find_in_batches(batch_size: 1000) do |s| shixuns.find_in_batches(batch_size: 1000) do |s|
Parallel.each_with_index(s, in_processes: 2) do |shixun, index| s.each_with_index do |shixun, index|
stage = "#{position}-#{index+1}" stage = "#{position}-#{index+1}"
name = shixun.name name = shixun.name
myshixuns = shixun.myshixuns myshixuns = shixun.myshixuns

@ -13,7 +13,7 @@ class Subjects::UserUsedInfoService < ApplicationService
users_info = [] users_info = []
users = User.includes(myshixuns: :games).where(myshixuns: {shixun_id: shixun_ids}, games: {status: 2}, users: {is_test: false}) users = User.includes(myshixuns: :games).where(myshixuns: {shixun_id: shixun_ids}, games: {status: 2}, users: {is_test: false})
users.find_in_batches(batch_size: 500) do |u| users.find_in_batches(batch_size: 500) do |u|
Parallel.each(u, in_processes: 2) do |user| u.each do |user|
myshixuns = user.myshixuns.select{|m| shixun_ids.include?(m.shixun_id)} myshixuns = user.myshixuns.select{|m| shixun_ids.include?(m.shixun_id)}
name = "#{user.lastname}#{user.firstname}" name = "#{user.lastname}#{user.firstname}"
passed_myshixun_count = myshixuns.select{|m| m.status == 1}.size passed_myshixun_count = myshixuns.select{|m| m.status == 1}.size

@ -11,22 +11,38 @@ class Videos::BatchPublishService < ApplicationService
def call def call
video_params = Array.wrap(params[:videos]).compact video_params = Array.wrap(params[:videos]).compact
return if video_params.blank? return if video_params.blank?
Rails.logger.info("#####video_course: #{video_params}")
video_ids = [] video_ids = []
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
video_params.each do |param| video_params.each do |param|
video = user.videos.find_by(uuid: param[:video_id]) video = user.videos.find_by(uuid: param[:video_id])
Rails.logger.info("video.processing_video_apply:#{video}")
Rails.logger.info("video.processing_video_apply:#{video.blank? || video.processing_video_apply}")
next if video.blank? || video.processing_video_apply.present? next if video.blank? || video.processing_video_apply.present?
raise Error, '视频还未上传完成' if video.vod_uploading? raise Error, '视频还未上传完成' if video.vod_uploading?
video.title = param[:title].to_s.strip.presence || video.title video.title = param[:title].to_s.strip.presence || video.title
video.apply_publish video.apply_publish
if param[:course_id].present?
video.status = "published"
end
video.save! video.save!
if param[:course_id].present?
video.video_applies.create!(status: "agreed")
else
video.video_applies.create! video.video_applies.create!
end
video_ids << video.id video_ids << video.id
# 如果是课堂上传则创建课堂记录
Rails.logger.info("#####param: #{ param[:course_id]}")
if param[:course_id].present?
video.course_videos.create!(course_id: param[:course_id])
end
end end
end end

@ -20,6 +20,9 @@ class Videos::DispatchCallbackService < ApplicationService
return if video.cover_url.present? return if video.cover_url.present?
video.update!(cover_url: params['CoverUrl']) video.update!(cover_url: params['CoverUrl'])
when 'TranscodeComplete' then # 转码完成
return if video.play_url.present?
video.update!(play_url: params['FileUrl'])
end end
rescue => ex rescue => ex

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

Loading…
Cancel
Save