video_transcode
杨树林 5 years ago
commit 09722d238c

@ -0,0 +1,2 @@
web: cd client && npm start
api: bundle exec rails s -p 3001

File diff suppressed because it is too large Load Diff

@ -0,0 +1,81 @@
$(document).on('turbolinks:load', function() {
if ($('body.admins-user-schools-statistics-index-page').length > 0) {
var $form = $('.user-schools-statistic-list-form');
// ************** 学校选择 *************
var matcherFunc = function(params, data){
if ($.trim(params.term) === '') {
return data;
}
if (typeof data.text === 'undefined') {
return null;
}
if (data.name && data.name.indexOf(params.term) > -1) {
var modifiedData = $.extend({}, data, true);
return modifiedData;
}
// Return `null` if the term should not be displayed
return null;
}
var defineSchoolSelect = function (schools) {
$form.find('.school-select').select2({
theme: 'bootstrap4',
placeholder: '选择学校/单位',
minimumInputLength: 1,
data: schools,
templateResult: function (item) {
if(!item.id || item.id === '') return item.text;
return item.name;
},
templateSelection: function(item){
if (item.id) {
$form.find('#school_id').val(item.id);
}
return item.name || item.text;
},
matcher: matcherFunc
});
};
// 初始化学校选择器
$.ajax({
url: '/api/schools/for_option.json',
dataType: 'json',
type: 'GET',
success: function(data) {
defineSchoolSelect(data.schools);
}
});
// 清空
$form.on('click', '.clear-btn', function(){
$form.find('select[name="date"]').val('');
$form.find('select[name="province"]').val('');
$form.find('.school-select').val('').trigger('change');
$form.find('input[type="submit"]').trigger('click');
})
// 导出
$('.export-action').on('click', function(){
var form = $(".user-schools-statistic-list-form")
var exportLink = $(this);
var date = form.find("select[name='date']").val();
var schoolId = form.find('input[name="school_id"]').val();
var province = form.find('input[name="province"]').val();
console.log(province)
if(province == "" || province == null){
alert("只能按省份导出");
return;
}
var url = exportLink.data("url").split('?')[0] + "?date=" + date + "&school_id=" + schoolId + "&province=" + province;
window.open(url);
});
}
});

@ -0,0 +1,25 @@
$(document).on('turbolinks:load', function() {
if ($('.weapp-banner-setting-container').length > 0) {
var $form = $('#course_form');
$('.course.banner-item-bottom').on("change", 'input[type="file"]', function() {
var $fileInput = $(this);
var file = this.files[0];
var imageType = /image.*/;
if (file && file.type.match(imageType)) {
$form.ajaxSubmit()
}
});
var $shixunform = $('#shixun_form');
$('.shixun.banner-item-bottom').on("change", 'input[type="file"]', function() {
var $fileInput = $(this);
var file = this.files[0];
var imageType = /image.*/;
if (file && file.type.match(imageType)) {
$shixunform.ajaxSubmit()
}
});
}
})

@ -1,171 +1,154 @@
.admins-laboratories-index-page {
.laboratory-list-table {
.member-container {
.laboratory-user {
display: flex;
justify-content: center;
flex-wrap: wrap;
.laboratory-user-item {
display: flex;
align-items: center;
height: 22px;
line-height: 22px;
padding: 2px 5px;
margin: 2px 2px;
border: 1px solid #91D5FF;
background-color: #E6F7FF;
color: #91D5FF;
border-radius: 4px;
.laboratory-list-table {
.member-container {
.laboratory-user {
display: flex;
justify-content: center;
flex-wrap: wrap;
.laboratory-user-item {
display: flex;
align-items: center;
height: 22px;
line-height: 22px;
padding: 2px 5px;
margin: 2px 2px;
border: 1px solid #91D5FF;
background-color: #E6F7FF;
color: #91D5FF;
border-radius: 4px;
}
}
}
}
}
}
}
.admins-laboratory-settings-show-page, .admins-laboratory-settings-update-page {
.edit-laboratory-setting-container {
.logo-item {
display: flex;
&-img {
display: block;
width: 80px;
height: 80px;
background: #f0f0f0;
}
&-upload {
cursor: pointer;
position: absolute;
top: 0;
width: 80px;
height: 80px;
background: #F5F5F5;
border: 1px solid #E5E5E5;
&::before {
content: '';
position: absolute;
top: 27px;
left: 39px;
width: 2px;
height: 26px;
background: #E5E5E5;
}
&::after {
content: '';
position: absolute;
top: 39px;
left: 27px;
width: 26px;
height: 2px;
background: #E5E5E5;
}
}
&-left {
position: relative;
width: 80px;
height: 80px;
&.has-img {
.logo-item-upload {
display: none;
}
&:hover {
.logo-item-upload {
display: block;
background: rgba(145, 145, 145, 0.8);
.admins-laboratory-settings-show-page,
.admins-laboratory-settings-update-page,
.weapp-banner-setting-container {
.edit-laboratory-setting-container {
.logo-item {
display: flex;
&-img {
display: block;
width: 80px;
height: 80px;
background: #f0f0f0;
}
&-upload {
cursor: pointer;
position: absolute;
top: 0;
width: 80px;
height: 80px;
background: #F5F5F5;
border: 1px solid #E5E5E5;
&::before {
content: '';
position: absolute;
top: 27px;
left: 39px;
width: 2px;
height: 26px;
background: #E5E5E5;
}
&::after {
content: '';
position: absolute;
top: 39px;
left: 27px;
width: 26px;
height: 2px;
background: #E5E5E5;
}
}
&-left {
position: relative;
width: 80px;
height: 80px;
&.has-img {
.logo-item-upload {
display: none;
}
&:hover {
.logo-item-upload {
display: block;
background: rgba(145, 145, 145, 0.8);
}
}
}
}
&-right {
display: flex;
flex-direction: column;
justify-content: space-between;
color: #777777;
font-size: 12px;
}
&-title {
color: #23272B;
font-size: 14px;
}
}
}
}
&-right {
display: flex;
flex-direction: column;
justify-content: space-between;
color: #777777;
font-size: 12px;
}
&-title {
color: #23272B;
font-size: 14px;
}
}
.banner-item {
margin-bottom: 15px;
display: flex;
flex-direction: column;
&-img {
display: block;
width: 300px;
height: 80px;
background: #f0f0f0;
}
&-upload {
cursor: pointer;
position: absolute;
top: 0;
width: 300px;
height: 80px;
background: #F5F5F5;
border: 1px solid #E5E5E5;
&::before {
content: '';
position: absolute;
top: 27px;
left: 149px;
width: 2px;
height: 26px;
background: #E5E5E5;
}
&::after {
content: '';
position: absolute;
top: 39px;
left: 137px;
width: 26px;
height: 2px;
background: #E5E5E5;
}
}
&-top {
margin-bottom: 10px;
}
&-bottom {
position: relative;
width: 300px;
height: 80px;
&.has-img {
.banner-item-upload {
display: none;
}
&:hover {
.banner-item-upload {
display: block;
background: rgba(145, 145, 145, 0.8);
.banner-item {
margin-bottom: 15px;
display: flex;
flex-direction: column;
&-img {
display: block;
width: 300px;
height: 80px;
background: #f0f0f0;
}
&-upload {
cursor: pointer;
position: absolute;
top: 0;
width: 300px;
height: 80px;
background: #F5F5F5;
border: 1px solid #E5E5E5;
&::before {
content: '';
position: absolute;
top: 27px;
left: 149px;
width: 2px;
height: 26px;
background: #E5E5E5;
}
&::after {
content: '';
position: absolute;
top: 39px;
left: 137px;
width: 26px;
height: 2px;
background: #E5E5E5;
}
}
&-top {
margin-bottom: 10px;
}
&-bottom {
position: relative;
width: 300px;
height: 80px;
&.has-img {
.banner-item-upload {
display: none;
}
&:hover {
.banner-item-upload {
display: block;
background: rgba(145, 145, 145, 0.8);
}
}
}
}
&-title {
color: #23272B;
font-size: 14px;
}
}
}
}
&-title {
color: #23272B;
font-size: 14px;
}
}
}
}

@ -5,6 +5,16 @@ class Admins::DashboardsController < Admins::BaseController
@month_active_user_count = User.where(last_login_on: current_month).count
@new_user_count = User.where(created_on: current_month).count
unless Rails.env.development?
shixun_tomcat = edu_setting('cloud_bridge')
uri = "#{shixun_tomcat}/bridge/monitor/getPodsInfo"
res = interface_get uri, 502, "数据接口延迟"
if res['code'] == 0
@pod_num = res['sum'] || 0
end
end
end
def month_active_user

@ -16,7 +16,7 @@ class Admins::LaboratorySettingsController < Admins::BaseController
def form_params
params.permit(:identifier, :name,
:nav_logo, :login_logo, :tab_logo, :oj_banner,
:nav_logo, :login_logo, :tab_logo, :oj_banner, :shixun_banner,
:subject_banner, :course_banner, :competition_banner, :moop_cases_banner,
:footer, navbar: %i[name link hidden])
end

@ -0,0 +1,18 @@
class Admins::UserSchoolsStatisticsController < Admins::BaseController
def export
params[:per_page] = 500
_count, @schools = Admins::UserSchoolsStatisticQuery.call(params)
filename = ['用户运营统计', Time.zone.now.strftime('%Y%m%d%H%M%S')].join('-') << '.xlsx'
render xlsx: 'export', filename: filename
end
def index
default_sort('cnt', 'desc')
total_count, schools = Admins::UserSchoolsStatisticQuery.call(params)
@schools = paginate schools, total_count: total_count
end
end

@ -0,0 +1,52 @@
class Admins::WeappBannersController < Admins::BaseController
def index
@shixun = WeappSettings::ShixunBanner.first
@course = WeappSettings::CourseBanner.first
end
def create
ActiveRecord::Base.transaction do
old_carouse = WeappSettings::CourseBanner.first
if old_carouse.present?
old_carouse.destroy!
file_path = Util::FileManage.source_disk_filename(old_carouse)
File.delete(file_path) if File.exist?(file_path) # 删除之前的文件
end
@course = WeappSettings::CourseBanner.create!
save_image_file(params[:course_banner], @course)
end
end
def shixun_banner
ActiveRecord::Base.transaction do
old_shixun = WeappSettings::ShixunBanner.first
if old_shixun.present?
old_shixun.destroy!
file_path = Util::FileManage.source_disk_filename(old_shixun)
File.delete(file_path) if File.exist?(file_path) # 删除之前的文件
end
@shixun = WeappSettings::ShixunBanner.create!
save_image_file(params[:shixun_banner], @shixun)
end
end
private
def save_image_file(file, model)
return unless file.present? && file.is_a?(ActionDispatch::Http::UploadedFile)
file_path = Util::FileManage.source_disk_filename(model)
File.delete(file_path) if File.exist?(file_path) # 删除之前的文件
Util.write_file(file, file_path)
end
end

@ -72,6 +72,15 @@ class ApplicationController < ActionController::Base
if !current_user.shixun_permission(@shixun)
tip_exception(403, "..")
end
# if !current_user.shixun_permission(@shixun)
# if @shixun.user_scope == 1
# school_id = @shixun.shixun_schools.first&.school_id
# name = School.find_by(id: school_id)&.name
# tip_exception(-5, "当前实训只对#{name}等单位开放")
# else
# tip_exception(403, "..")
# end
# end
end
def admin_or_business?
@ -448,6 +457,25 @@ class ApplicationController < ActionController::Base
end
end
# 无参类型处理
def interface_get(uri, status, message)
begin
uid_logger_dubug("--uri_exec: url is #{uri}")
uri = URI.parse(URI.encode(uri.strip))
res = Net::HTTP.get(uri)
uid_logger_dubug("--uri_exec: .....res is #{res}")
res = JSON.parse(res)
if (res && res['code'] != 0)
tip_exception(status, message)
else
res
end
rescue Exception => e
uid_logger("--uri_exec: exception #{e.message}")
raise Educoder::TipException.new(message)
end
end
# json格式请求
def interface_json_post(uri, params, status, message)
begin

@ -230,7 +230,7 @@ class ChallengesController < ApplicationController
logger.info("############shixun_publiced:#{@shixun.public == 0}")
if @shixun.public == 0
script = modify_shixun_script @shixun, @shixun.evaluate_script
@shixun.shixun_info.update_column(:evaluate_script, script)
@shixun.shixun_info.update_column(:evaluate_script, script) if script.present?
end
# TODO:
# if path != params[:challenge][:path]

@ -6,10 +6,12 @@ module ControllerRescueHandler
Util.logger_error e
render json: {status: -1, message: e.message}
end
rescue_from ActiveRecord::StatementInvalid do |e|
Util.logger_error e
render json: {status: -1, message: "接口数据异常"}
end
rescue_from NoMethodError do |e|
Util.logger_error e
render json: {status: -1, message: "接口方法异常"}
@ -18,6 +20,7 @@ module ControllerRescueHandler
rescue_from ActionController::UnknownFormat do |e|
render json: {status: -1, message: "接口调用非JSON格式"}
end
# rescue_from ActionView::MissingTemplate, with: :object_not_found
# rescue_from ActiveRecord::RecordNotFound, with: :object_not_found
rescue_from Educoder::TipException, with: :tip_show
@ -32,6 +35,7 @@ module ControllerRescueHandler
rescue_from ActiveRecord::RecordInvalid do |ex|
render_error(ex.record.errors.full_messages.join(','))
end
# rescue_from RuntimeError do |ex|
# Util.logger_error "#######ex:#{ex}"
# render_error(ex.message)

@ -13,7 +13,7 @@ module GitHelper
content = GitService.file_content(repo_path: repo_path, path: path)
Rails.logger.info("git file content: content is #{content}")
#Rails.logger.info("git file content: content is #{content}")
decode_content = nil
if content.present?
content = content["content"] #6.24 -hs 这个为新增,因为当实训题里含有选择题时,这里会报错,undefined method `[]' for nil:NilClass
@ -25,6 +25,8 @@ module GitHelper
decode_content =
if cd["encoding"] == 'GB18030' && cd['confidence'] > 0.8
content.encode('UTF-8', 'GBK', {:invalid => :replace, :undef => :replace, :replace => ' '})
elsif cd['encoding'].blank?
raise("ERROR_UTF8")
else
content.force_encoding('UTF-8')
end
@ -34,7 +36,9 @@ module GitHelper
rescue Exception => e
Rails.logger.error(e.message)
raise Educoder::TipException.new("文档内容获取异常")
error_msg = e.message == "ERROR_UTF8" ? "文件无法预览" : "文档内容获取异常"
error_status = e.message == "ERROR_UTF8" ? -2 : -1
raise Educoder::TipException.new(error_status, error_msg)
end
end
@ -53,13 +57,17 @@ module GitHelper
end
# 添加目录
def git_add_folder(folder_path, author_name, author_email, message)
GitService.add_tree(file_path: folder_path, message: message, author_name: author_name, author_email: author_email)
def git_add_folder(repo_path, tree_path, author_name, author_email, message)
Rails.logger.info("#####repo_path:#{repo_path}, tree_path: #{tree_path}")
GitService.add_tree(repo_path: repo_path, tree_path: tree_path, message: message, author_name: author_name,
author_email: author_email)
end
# 删除文件
def git_delete_file(file_path, author_name, author_email, message)
GitService.delete_file(file_path: file_path, message: message, author_name: author_name, author_email: author_email)
def git_delete_file(repo_path, tree_path, author_name, author_email, message)
Rails.logger.info("#####repo_path:#{repo_path}, tree_path: #{tree_path}")
GitService.delete_file(repo_path: repo_path, tree_path: tree_path, message: message, author_name: author_name,
author_email: author_email)
end
# 版本库Fork功能

@ -35,6 +35,7 @@ module LoginHelper
UserAction.create(action_id: user&.id, action_type: 'Login', user_id: user&.id, ip: request.remote_ip)
user.update_column(:last_login_on, Time.now)
# 注册完成后有一天的试用申请(先去掉)
# UserDayCertification.create(user_id: user.id, status: 1)
end
@ -44,6 +45,8 @@ module LoginHelper
if autologin = cookies.delete(autologin_cookie_name)
User.current.delete_autologin_token(autologin)
end
UserOnline.logout(User.current.id)
User.current.delete_session_token(session[:tk])
self.logged_user = nil
end
@ -52,6 +55,7 @@ module LoginHelper
default_yun_session = "#{laboratory.try(:identifier).split('.').first}_user_id"
# end
session[:"#{default_yun_session}"] = nil
session[:request_user_id] = nil
end
# Sets the logged in user
@ -78,6 +82,8 @@ module LoginHelper
# # end
# session[:user_id] = user.id
UserOnline.login(user.id)
session[:request_user_id] = user.id
session[:"#{default_yun_session}"] = user.id
session[:ctime] = Time.now.utc.to_i
session[:atime] = Time.now.utc.to_i

@ -106,7 +106,7 @@ class CoursesController < ApplicationController
videos = @course.videos
videos = custom_sort(videos, params[:sort_by], params[:sort_direction])
@count = videos.count
@videos = paginate videos
@videos = paginate videos.includes(user: :user_extension)
end
def delete_course_video
@ -747,6 +747,12 @@ class CoursesController < ApplicationController
ActiveRecord::Base.transaction do
course_student.destroy!
course_teacher.update!(is_active: 1)
teacher_course_record = @course.teacher_group_records.find_by(user_id: current_user.id)
if teacher_course_record.present?
teacher_course_record.update!(group_id: course_student.course_group_id)
else
TeacherGroupRecord.create!(user_id: current_user.id, course_id: @course.id, group_id: course_student.course_group_id)
end
CourseDeleteStudentDeleteWorksJob.perform_later(@course.id, [current_user.id])
end
normal_status(0, "切换成功")
@ -766,6 +772,12 @@ class CoursesController < ApplicationController
ActiveRecord::Base.transaction do
course_student.destroy!
course_teacher.update!(is_active: 1)
teacher_course_record = @course.teacher_group_records.find_by(user_id: current_user.id)
if teacher_course_record.present?
teacher_course_record.update!(group_id: course_student.course_group_id)
else
TeacherGroupRecord.create!(user_id: current_user.id, course_id: @course.id, group_id: course_student.course_group_id)
end
CourseDeleteStudentDeleteWorksJob.perform_later(@course.id, [current_user.id])
end
normal_status(0, "切换成功")
@ -788,7 +800,9 @@ class CoursesController < ApplicationController
course_student.update_attributes!(is_active: 1)
else
# 学生身份不存在则创建
CourseMember.create!(user_id: current_user.id, role: 4, course_id: @course.id)
course_group_id = @course.teacher_group_records.find_by(user_id: current_user.id)&.group_id.to_i
course_group_id = @course.course_groups.find_by(id: course_group_id)&.id.to_i
CourseMember.create!(user_id: current_user.id, role: 4, course_id: @course.id, course_group_id: course_group_id)
CourseAddStudentCreateWorksJob.perform_later(@course.id, [current_user.id])
end
normal_status(0, "切换成功")

@ -46,7 +46,7 @@ class DiscussesController < ApplicationController
end
sql = "select d.id from discusses d join shixuns s on d.dis_id = s.id where s.status = 2 and s.hidden = false and d.root_id is null
and d.hidden = false #{sql1} #{sql2} order by d.created_at desc"
and d.hidden = false and d.dis_type = 'Shixun' #{sql1} #{sql2} order by d.created_at desc"
memo_ids = Discuss.find_by_sql(sql).pluck(:id)
@memo_count = memo_ids.size
@ -81,8 +81,7 @@ class DiscussesController < ApplicationController
begin
@discuss = Discuss.create!(:dis_id => params[:container_id], :dis_type => params[:container_type],
:content => params[:content].gsub("&nbsp\;", "").strip, :user_id => current_user.id,
:praise_count => 0, :position => params[:position], :challenge_id => params[:challenge_id],
:hidden => !current_user.admin?) # 管理员回复的能够显示
:praise_count => 0, :position => params[:position], :challenge_id => params[:challenge_id])
rescue Exception => e
uid_logger_error("create discuss failed : #{e.message}")
raise Educoder::TipException.new("评论异常,原因:#{e.message}")

@ -16,8 +16,8 @@ require 'digest'
class EcloudController < ApplicationController
before_filter :save_para
before_filter :check_sign_key, only: [:ps_new, :ps_update, :bs_new, :bs_update]
before_action :save_para
before_action :check_sign_key, only: [:ps_new, :ps_update, :bs_new, :bs_update]
def index
@ -239,57 +239,60 @@ class EcloudController < ApplicationController
end
def ecloud_login_callback
if params[:test]
user_info = decode '{"userid":2147,"custid":2104,"custcode":"E0002018042810010054","custtype":2,"status":2,"username":"15111030087@QW_er","useralias":"15111030087","isadmin":true,"entprise":"04**004","departments":"","departmentnames":"","mobile":"15365386520","email":"15111030087@139.com"}'
else
res = request_ecloud_authorization
unless params["test"] == 'true'
#获取code
logger.info "oauth2 login_callback: #{params}"
raise "没有code" unless params[:code]
url = "#{SERVER_URL}/oauth2/authorization?grant_type=authorization_code" +
"&client_id=#{CLIENT_ID}&scope=&redirect_uri=&code=#{params[:code]}"
res = post(url)
logger.info "oauth2 authorization resp: #{res}"
# {"access_token":"ae673b2d-88b4-46cc-aa74-0b031f24b76f","expires":6,"refresh_token":"7380cc67-a59c-4c21-9000-70e12a58d175","username":"15111030087@QW_er","uid":2147}
raise '登录失败' unless res["access_token"]
body = decode(res)
raise '登录失败' unless body["access_token"]
user_info = decode get_ecloud_user(res)
logger.info "oauth2 get user info: #{user_info}"
end
#获取此用户信息
res = get("#{SERVER_URL}/user/info?access_token=#{body['access_token']}&userid=#{body['uid']}")
logger.info "oauth2 get user info: #{res}"
# {"userid":2147,"custid":2104,"custcode":"E0002018042810010054","custtype":2,"status":2,"username":"15111030087@QW_er","useralias":"15111030087","isadmin":true,"entprise":"04**004","departments":"","departmentnames":"","mobile":"15365386520","email":"15111030087@139.com"}
else
res = '{"userid":2147,"custid":2104,"custcode":"E0002018042810010054","custtype":2,"status":2,"username":"15111030087@QW_er","useralias":"15111030087","isadmin":true,"entprise":"04**004","departments":"","departmentnames":"","mobile":"15365386520","email":"15111030087@139.com"}'
open_user = OpenUsers::Ecloud.find_or_initialize_by(uid: user_info['userid']) do |u|
u.extra = user_info
end
redirect_to "/users/#{open_user.user.login}/courses" and return if open_user.persisted?
ActiveRecord::Base.transaction do
user = User.find_or_initialize_by(phone: user_info["mobile"]) do |u|
u.login = "ecoder_#{user_info['mobile']}"
u.type ='User'
u.status = User::STATUS_ACTIVE
u.nickname = user_info['username']
u.lastname = user_info['username']
end
if !user.persisted?
user.mail = user_info["email"] unless user_info["email"].blank? || User.find_by_mail(user_info["email"])
user.save!
user.create_user_extension!
end
# 同步用户
info = decode(res)
open_user.user = user
open_user.save!
successful_authentication(user)
user = User.find_by_ecoder_user_id(info["userid"])
unless user
#新建用户
user = User.create_with_ecoder!(info)
redirect_to "/users/#{user.login}/courses"
end
rescue Exception => e
render :json => {code: 500, msg: "#{e.message}"}
end
self.logged_user = user
user = UserExtension.where(:user_id => User.current.id).first
# if user.gender.nil? || user.school_id.nil? || User.current.lastname.nil?
# redirect_to my_account_path
# elsif user.identity == 3 && user.school_id.nil?
# redirect_to my_account_path
# else
# redirect_to User.current
# end
redirect_to User.current
private
def request_ecloud_authorization
url = "#{SERVER_URL}/oauth2/authorization?grant_type=authorization_code&client_id=#{CLIENT_ID}&scope=&redirect_uri=&code=#{params[:code]}"
decode post(url)
end
def get_ecloud_user(body)
res = get("#{SERVER_URL}/user/info?access_token=#{body['access_token']}&userid=#{body['uid']}")
end
private
def get(url)
uri = URI(url)

@ -749,6 +749,8 @@ class GamesController < ApplicationController
# 针对web类型的实训
web_route = game_challenge.try(:web_route)
server_url = @game.get_server_url if web_route.present?
mirror_name = @shixun.mirror_name
e_record = EvaluateRecord.where(:identifier => sec_key).first
@ -776,7 +778,7 @@ class GamesController < ApplicationController
@base_date = {grade: grade, gold: score, experience: experience, status: game_status, had_done: had_done,
position: game_challenge.position, port: port, record_consume_time: record_consume_time,
mirror_name: mirror_name, picture: picture, web_route: web_route, star: @game.star,
next_game: next_game, prev_game: prev_game, max_mem: max_mem}
next_game: next_game, prev_game: prev_game, max_mem: max_mem, server_url: server_url}
end
# 记录实训花费的时间
@ -971,6 +973,7 @@ class GamesController < ApplicationController
if res && res['code'].to_i != 0
raise("实训云平台繁忙繁忙等级99")
end
# @vnc_url = res['showServer']
@vnc_url =
if request.subdomain == "pre-newweb" || request.subdomain == "test-newweb"
# 无域名版本

@ -1210,7 +1210,7 @@ class HomeworkCommonsController < ApplicationController
rescue Exception => e
uid_logger(e.message)
tip_exception("删除失败")
tip_exception(e.message)
raise ActiveRecord::Rollback
end
end
@ -1433,7 +1433,7 @@ class HomeworkCommonsController < ApplicationController
def require_id_params
tip_exception("请至少选择一个作业") if params[:homework_ids].blank?
tip_exception("批量设置不能超过15个") if params[:homework_ids].length > 15
tip_exception("批量设置不能超过15个") if params[:homework_ids].length > 15 && params[:type].blank?
end
def validate_min_max_num

@ -4,6 +4,7 @@ class MainController < ApplicationController
skip_before_action :setup_laboratory
def first_stamp
UserOnline.login(session[:request_user_id]) if session[:request_user_id]
render :json => { status: 0, message: Time.now.to_i }
end

@ -99,6 +99,7 @@ class MyshixunsController < ApplicationController
status = jsonTestDetails['status']
game_id = jsonTestDetails['buildID']
sec_key = jsonTestDetails['sec_key']
server_url = jsonTestDetails['showServer']
#uid_logger_dubug("training_task_status start-#{game_id}-1#{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}")
resubmit = jsonTestDetails['resubmit']
@ -117,6 +118,10 @@ class MyshixunsController < ApplicationController
pics = params[:tpiRepoPath]
game.update_column(:picture_path, pics)
end
# 如果启动了服务则存在redis中供前端访问
if server_url.present?
game.set_server_key(server_url)
end
max_query_index = game.outputs ? (game.outputs.first.try(:query_index).to_i + 1) : 1
test_set_score = 0
unless jenkins_testsets.blank?

@ -3,6 +3,7 @@ class ShixunsController < ApplicationController
include ApplicationHelper
include ElasticsearchAble
include CoursesHelper
include GitCommon
before_action :require_login, :check_auth, except: [:download_file, :index, :menus, :show, :show_right, :ranking_list,
:discusses, :collaborators, :fork_list, :propaedeutics]
@ -16,7 +17,7 @@ class ShixunsController < ApplicationController
:propaedeutics, :departments, :apply_shixun_mirror, :jupyter_exec,
:get_mirror_script, :download_file, :shixun_list, :batch_send_to_course]
before_action :find_repo_name, only: [:repository, :commits, :file_content, :update_file, :shixun_exec, :copy,
:add_file, :jupyter_exec]
:add_file, :jupyter_exec, :upload_git_file, :delete_git_file, :upload_git_folder]
before_action :allowed, only: [:update, :close, :update_propaedeutics, :settings, :publish, :apply_public, :upload_git_folder,
:shixun_members_added, :change_manager, :collaborators_delete, :upload_git_file,
@ -417,8 +418,8 @@ class ShixunsController < ApplicationController
logger.info("#########service_update_params: #{service_update_params}")
begin
ActiveRecord::Base.transaction do
@shixun.update_attributes(shixun_params)
@shixun.shixun_info.update_attributes(shixun_info_params)
@shixun.update_attributes!(shixun_params)
@shixun.shixun_info.update_attributes!(shixun_info_params)
# 镜像变动
@shixun.shixun_mirror_repositories.where.not(mirror_repository_id: old_mirror_ids).destroy_all
@shixun.shixun_mirror_repositories.create!(new_mirror_id) if new_mirror_id.present?
@ -878,7 +879,7 @@ class ShixunsController < ApplicationController
end
end
include GitCommon
def update_file
content = params[:content]
@ -897,7 +898,8 @@ class ShixunsController < ApplicationController
author_email = current_user.git_mail
message = params[:message] || "upload file by browser"
uid_logger("-----author_email: #{author_email}")
update_file_base64_content(content, @repo_path, @path, author_email, author_name, message)
path = @path.present? ? "#{@path}/#{upload_file.original_filename}" : "#{upload_file.original_filename}"
update_file_base64_content(content, @repo_path, path, author_email, author_name, message)
render_ok
end
@ -906,7 +908,7 @@ class ShixunsController < ApplicationController
author_name = current_user.real_name
author_email = current_user.git_mail
message = params[:message] || "upload folder by browser"
git_add_folder(@path, author_name, author_email, message)
git_add_folder(@repo_path, @path, author_name, author_email, message)
render_ok
end
@ -914,7 +916,7 @@ class ShixunsController < ApplicationController
author_name = current_user.real_name
author_email = current_user.git_mail
message = params[:message] || "delete file by browser"
git_delete_file(@path, author_name, author_email, message)
git_delete_file(@repo_path, @path, author_name, author_email, message)
render_ok
end
@ -1096,9 +1098,8 @@ private
@repo_path = if params[:secret_repository]
@shixun.shixun_secret_repository&.repo_path
else
@shixun.try(:repo_path)
@shixun.repo_path
end
logger.info("######{@repo_path}")
@path = params[:path]
end

@ -360,6 +360,7 @@ class StudentWorksController < ApplicationController
# 给作品评分
def add_score
tip_exception("该学生的分数已经过调整,不能再评阅") if @work.ultimate_score
tip_exception("学生匿评时分数为必填") if params[:score].blank? && @user_course_identity == Course::STUDENT
tip_exception("分数和评语不能都为空") if params[:score].blank? && params[:comment].blank?
tip_exception("分数不能超过0-100") if params[:score] && (params[:score].to_f < 0 || params[:score].to_f > 100)

@ -0,0 +1,144 @@
class Weapps::AttendancesController < ApplicationController
before_action :require_login
before_action :find_course, only: [:create, :index, :student_attendances, :history_attendances]
before_action :find_attendance, except: [:create, :index, :student_attendances, :history_attendances]
before_action :user_course_identity
before_action :teacher_allowed, only: [:create]
before_action :edit_auth, only: [:update, :destroy, :end]
def create
ActiveRecord::Base.transaction do
attendance = @course.course_attendances.create!(create_params.merge(user_id: current_user.id))
unless params[:group_ids].blank? || @course.course_groups.where(id: params[:group_ids]).count == @course.course_groups.count
group_ids = @course.charge_group_ids(current_user) & params[:group_ids].map(&:to_i)
group_ids.each do |group_id|
@course.course_attendance_groups.create!(course_group_id: group_id, course_attendance: attendance)
end
CreateStudentAttendanceRecordJob.perform_now(attendance.id, group_ids)
else
@course.course_attendance_groups.create!(course_group_id: 0, course_attendance: attendance)
CreateStudentAttendanceRecordJob.perform_now(attendance.id, [0])
end
render_ok({attendance_id: attendance.id})
end
end
def index
tip_exception(403) if @user_course_identity >= Course::STUDENT
current_date = Date.current
current_end_time = Time.current.strftime("%H:%M:%S")
@current_attendance = @course.course_attendances.where("attendance_date = '#{current_date}' and end_time > '#{current_end_time}'")
.order("attendance_date asc, start_time asc")
all_attendances = @course.course_attendances.where("attendance_date < '#{current_date}' or (attendance_date = '#{current_date}' and end_time < '#{current_end_time}')")
@all_member_attendances = CourseMemberAttendance.where(course_attendance_id: all_attendances)
if params[:group_id].present?
all_attendances = all_attendances.joins(:course_attendance_groups).where(course_attendance_groups: {course_group_id: [params[:group_id], 0]})
@all_member_attendances = @all_member_attendances.joins(:course_member).where(course_members: {course_group_id: params[:group_id]})
end
@history_attendances = all_attendances.order("id asc")
@all_history_count = @history_attendances.size
end
def student_attendances
# tip_exception("学生身份的签到列表") if @user_course_identity != Course::STUDENT
member = @course.students.find_by(user_id: current_user.id)
if member.present?
current_date = Date.current
current_end_time = Time.current.strftime("%H:%M:%S")
# 先算出该学生所在分班的签到id
# 分班id为0 表示签到不限制分班
group_ids = [member&.course_group_id.to_i, 0]
all_attendance_ids = @course.course_attendance_groups.where(course_group_id: group_ids).pluck(:course_attendance_id)
# 学生的历史签到只统计加入课堂后创建的签到
history_attendance_ids = member.course_member_attendances.where(course_id: @course.id).pluck(:course_attendance_id)
@history_attendances = @course.course_attendances.where(id: history_attendance_ids.uniq).
where("attendance_date < '#{current_date}' or (attendance_date = '#{current_date}' and end_time < '#{current_end_time}')").order("id desc")
@current_attendance = @course.course_attendances.where(id: all_attendance_ids.uniq).
where("attendance_date = '#{current_date}' and start_time <= '#{current_end_time}' and end_time > '#{current_end_time}'")
@history_count = @history_attendances.size
student_attendance_ids = @history_attendances.pluck(:id)
student_attendance_ids += @current_attendance.present? ? @current_attendance.pluck(:id) : []
if student_attendance_ids.uniq.blank?
@normal_count = 0
@leave_count = 0
@absence_count = 0
else
@normal_count = @course.course_member_attendances.where(course_member_id: member&.id, course_attendance_id: student_attendance_ids, attendance_status: "NORMAL").size
@leave_count = @course.course_member_attendances.where(course_member_id: member&.id, course_attendance_id: student_attendance_ids, attendance_status: "LEAVE").size
# 旷课只统计历史签到的
@absence_count = @course.course_member_attendances.where(course_member_id: member&.id, course_attendance_id: @history_attendances.pluck(:id), attendance_status: "ABSENCE").size
end
@all_history_count = @history_attendances.size
@history_attendances = paginate @history_attendances.includes(:course_member_attendances)
end
end
def show
@normal_count = @attendance.normal_count
@leave_count = @attendance.leave_count
@absence_count = @attendance.absence_count
@all_count = @attendance.course_member_attendances.size
@_is_current_attendance = @attendance.current_attendance?
if @attendance.course_attendance_groups.first&.course_group_id.to_i == 0
@group_ids = @course.course_groups.pluck(:id) + [0]
else
@group_ids = @attendance.course_attendance_groups.pluck(:course_group_id)
end
@groups = @course.course_groups.where(id: @group_ids)
@course_members = @course.students if @_is_current_attendance
@all_attendances = @attendance.course_member_attendances
end
def update
@attendance.update!(name: params[:name])
render_ok
end
def destroy
@attendance.destroy!
render_ok
end
def history_attendances
current_date = Date.current
current_end_time = Time.current.strftime("%H:%M:%S")
@history_attendances = @course.course_attendances.where("attendance_date < '#{current_date}' or
(attendance_date = '#{current_date}' and end_time < '#{current_end_time}')").order("id desc")
@all_history_count = @history_attendances.size
@history_attendances = paginate @history_attendances.includes(:course_member_attendances)
end
def end
a_end_time = "#{@attendance.attendance_date} #{@attendance.end_time}".to_time
tip_exception("该签到已截止") unless @attendance.current_attendance?
@attendance.update!(end_time: Time.current)
render_ok
end
private
def create_params
params.permit(:name, :mode, :attendance_date, :start_time, :end_time)
end
def find_attendance
@attendance = CourseAttendance.find params[:id]
@course = @attendance.course
end
def edit_auth
tip_exception(403, "") unless @user_course_identity < Course::PROFESSOR || @attendance.user_id == current_user.id
end
end

@ -0,0 +1,12 @@
class Weapps::BannersController < Weapps::BaseController
def index
shixun = WeappSettings::ShixunBanner.first
course = WeappSettings::CourseBanner.first
render json: {
shixun_img: shixun ? Util::FileManage.source_disk_file_url(shixun) : '',
course_img: course ? Util::FileManage.source_disk_file_url(course) : ''
}
end
end

@ -0,0 +1,76 @@
class Weapps::CourseMemberAttendancesController < ApplicationController
before_action :require_login
before_action :find_course, :user_course_identity, only: [:update_status]
def index
attendance = CourseAttendance.find params[:attendance_id]
if attendance.course_attendance_groups.first&.course_group_id.to_i == 0
@members = attendance.course.students
else
@members = attendance.course.students.where(course_group_id: attendance.course_attendance_groups.pluck(:course_group_id))
end
@member_attendances = attendance.course_member_attendances
if params[:group_ids].present?
@members = @members.where(course_group_id: params[:group_ids])
end
if params[:attendance_status].present?
@members = @members.joins(:course_member_attendances).where(course_member_attendances: {course_attendance_id: attendance.id, attendance_status: params[:attendance_status]})
end
@members = @members.joins(:course_member_attendances).order("attendance_status=1 desc, course_member_attendances.updated_at desc")
@members_count = @members.uniq.count
@members = paginate @members.preload(user: :user_extension).uniq
# @member_attendances = @member_attendances.where(attendance_status: params[:attendance_status]) if params[:attendance_status].present?
# @member_attendances = @member_attendances.joins(user: :user_extension).order("attendance_status=1 desc, course_member_attendances.updated_at desc, user_extensions.student_id asc")
# @member_attendances = paginate @member_attendances.preload(user: :user_extension)
end
def create
tip_exception("签到码不能为空") if params[:code].blank?
tip_exception("attendance_mode参数不对") unless ["NUMBER", "QRCODE"].include?(params[:attendance_mode])
attendance = CourseAttendance.find_by(attendance_code: params[:code])
tip_exception("签到码输入有误") if attendance.blank? || attendance.course.blank?
member = attendance.course.students.find_by(user_id: current_user.id)
tip_exception("签到码输入有误") if member.blank?
tip_exception("不在签到时间内") unless attendance.current_attendance?
tip_exception("只支持数字签到") if attendance.mode != "ALL" && attendance.mode == "NUMBER" && params[:attendance_mode] == "QRCODE"
tip_exception("只支持二维码签到") if attendance.mode != "ALL" && attendance.mode == "QRCODE" && params[:attendance_mode] == "NUMBER"
current_attendance = attendance.course_member_attendances.find_by(user_id: current_user.id)
if current_attendance.present?
tip_exception("请勿重复签到") if current_attendance.attendance_status == "NORMAL"
tip_exception("您当前是请假状态,无法签到") if current_attendance.attendance_status == "LEAVE"
tip_exception("您当前是旷课状态,无法签到") if current_attendance.attendance_status == "ABSENCE" && current_attendance.attendance_mode == "TEACHER"
current_attendance.update!(attendance_status: "NORMAL", attendance_mode: params[:attendance_mode])
else
attendance.course_member_attendances.create!(course_member_id: member.id, user_id: current_user.id, course_id: attendance.course_id,
course_group_id: member.course_group_id, attendance_status: "NORMAL", attendance_mode: params[:attendance_mode])
end
render_ok
end
def update_status
tip_exception("user_id不能为空") if params[:user_id].blank?
tip_exception(403, "无权限调整签到状态") if @user_course_identity > Course::ASSISTANT_PROFESSOR
tip_exception("attendance_status参数不对") unless ["NORMAL", "LEAVE", "ABSENCE"].include?(params[:attendance_status])
attendance = @course.course_attendances.find_by!(id: params[:attendance_id])
current_attendance = attendance.course_member_attendances.find_by(user_id: params[:user_id])
if current_attendance.present?
current_attendance.update!(attendance_status: params[:attendance_status], attendance_mode: "TEACHER")
else
member = attendance.course.students.find_by(user_id: params[:user_id])
tip_exception( "该用户非课堂学生") if member.blank?
attendance.course_member_attendances.create!(course_member_id: member.id, user_id: params[:user_id], course_id: attendance.course_id,
course_group_id: member.course_group_id, attendance_status: params[:attendance_status], attendance_mode: "TEACHER")
end
render_ok
end
end

@ -8,18 +8,32 @@ class Weapps::CoursesController < Weapps::BaseController
def course_activities
@course = current_course
homework_commons = @course.homework_commons.where(homework_type: ["practice", "normal"]).homework_published
member = @course.course_members.find_by(user_id: current_user.id, is_active: 1)
# 签到数据
attendances = @course.course_attendances
current_date = Date.current
current_end_time = Time.current.strftime("%H:%M:%S")
if @user_course_identity == Course::STUDENT
attendances = attendances.joins(:course_attendance_groups).where(course_attendance_groups: {course_group_id: [member.try(:course_group_id).to_i, 0]})
.where("attendance_date < '#{current_date}' or (attendance_date = '#{current_date}' and start_time < '#{current_end_time}')")
end
attendance_ids = attendances.blank? ? "(-1)" : "(" + attendances.pluck(:id).join(",") + ")"
homework_commons = @course.homework_commons.where(homework_type: ["practice", "normal"]).homework_published
if (@user_course_identity == Course::STUDENT && member.try(:course_group_id).to_i == 0) || @user_course_identity > Course::STUDENT
homework_commons = homework_commons.unified_setting
elsif @user_course_identity == Course::STUDENT
not_homework_ids = @course.homework_group_settings.none_published.where("course_group_id = #{member.try(:course_group_id)}").pluck(:homework_common_id)
not_homework_ids = @course.homework_group_settings.none_published.where("course_group_id = #{member.try(:course_group_id)}")
.pluck(:homework_common_id)
homework_commons = homework_commons.where.not(id: not_homework_ids)
end
homework_ids = homework_commons.blank? ? "(-1)" : "(" + homework_commons.pluck(:id).join(",") + ")"
activities = @course.course_activities.where("course_act_type in ('Course', 'CourseMessage') or
(course_act_type = 'HomeworkCommon' and course_act_id in #{homework_ids})").order("id desc")
(course_act_type = 'HomeworkCommon' and course_act_id in #{homework_ids}) or
(course_act_type = 'CourseAttendance' and course_act_id in #{attendance_ids})").order("id desc")
@activities_count = activities.size
@activities = paginate activities.includes(:course_act, user: :user_extension)
end

@ -0,0 +1,20 @@
module Weapps::AttendancesHelper
def student_attendance_status attendance, user
st_attendance = attendance.course_member_attendances.find_by(user_id: user.id)
st_attendance.present? ? st_attendance.attendance_status : "ABSENCE"
end
def group_attendance_count attendances, member_ids
# course_member_ids = group.course_members.pluck(:id)
attendances.select{|attendance| member_ids.include?(attendance.course_member_id) && attendance.attendance_status == "NORMAL"}.size
end
def history_member_count member_attendances, status, attendance_id
member_attendances.select{|member_attendance| member_attendance.attendance_status == status && member_attendance.course_attendance_id == attendance_id}.size
end
def cal_rate base, sum
sum == 0 ? 0 : (base.to_f / sum)
end
end

@ -0,0 +1,26 @@
class CreateStudentAttendanceRecordJob < ApplicationJob
queue_as :default
def perform(attendance_id, group_ids)
attendance = CourseAttendance.find_by(id: attendance_id)
course = attendance.course
return if attendance.blank? || course.blank?
if group_ids.include?(0)
students = course.students
else
students = course.students.where(course_group_id: group_ids)
end
attrs = %i[course_attendance_id user_id course_member_id course_id course_group_id created_at updated_at]
same_attrs = {course_attendance_id: attendance.id, course_id: course.id}
CourseMemberAttendance.bulk_insert(*attrs) do |worker|
students.each do |student|
worker.add same_attrs.merge(user_id: student.user_id, course_member_id: student.id, course_group_id: student.course_group_id)
end
end
end
end

@ -14,7 +14,9 @@ class CreateStudentWorkJob < ApplicationJob
student_ids = course.students.pluck(:user_id)
student_ids.each do |user_id|
worker.add same_attrs.merge(user_id: user_id)
unless StudentWork.where(user_id: user_id, homework_common_id: homework.id).exists?
worker.add same_attrs.merge(user_id: user_id)
end
end
end
end

@ -22,7 +22,7 @@ class HomeworkEndUpdateScoreJob < ApplicationJob
challenge_settings = homework.homework_challenge_settings
myshixuns.find_each(batch_size: 100) do |myshixun|
work = student_works.select{|work| work.user_id == myshixun.user_id}.first
if work && myshixun && (work.update_time.nil? || work.update_time < myshixun.updated_at)
if work.present? && myshixun
games = myshixun.games.where(challenge_id: challenge_settings.pluck(:challenge_id))
HomeworksService.new.update_myshixun_work_score work, myshixun, games, homework, challenge_settings
end

@ -0,0 +1,32 @@
class StudentJoinAttendanceRecordJob < ApplicationJob
queue_as :default
def perform(member_id)
member = CourseMember.find_by(id: member_id)
course = member&.course
return if member.blank? || course.blank?
current_date = Date.current
current_end_time = Time.current.strftime("%H:%M:%S")
group_ids = member.course_group_id == 0 ? [0] : [member.course_group_id, 0]
current_attendance_ids = course.course_attendances.joins(:course_attendance_groups).where(course_attendance_groups: {course_group_id: group_ids}).
where("(attendance_date = '#{current_date}' and start_time <= '#{current_end_time}' and end_time > '#{current_end_time}') or (attendance_date > '#{current_date}')").pluck(:id)
all_group_attendance_ids = course.course_attendances.joins(:course_attendance_groups).where(course_attendance_groups: {course_group_id: 0}).pluck(:id)
member.course_member_attendances.where.not(course_attendance_id: all_group_attendance_ids+current_attendance_ids).delete_all
attrs = %i[course_attendance_id user_id course_member_id course_id course_group_id created_at updated_at]
same_attrs = {course_member_id: member_id, course_id: course.id, user_id: member.user_id, course_group_id: member.course_group_id}
CourseMemberAttendance.bulk_insert(*attrs) do |worker|
current_attendance_ids.each do |attendance_id|
unless course.course_member_attendances.where(course_member_id: member_id, course_attendance_id: attendance_id).exists?
worker.add same_attrs.merge(course_attendance_id: attendance_id)
end
end
end
end
end

@ -0,0 +1,41 @@
module UserOnline
class << self
def login(user_id)
set_bit(user_id, 1)
end
def logout(user_id)
set_bit(user_id, 0)
end
def set_bit(user_id, flag)
if !Rails.cache.data.exists(cache_key)
Rails.cache.data.setbit(cache_key, user_id, flag)
Rails.cache.data.expire(cache_key, 20 * 60 + 10)
else
Rails.cache.data.setbit(cache_key, user_id, flag)
end
end
def count
if Rails.cache.is_a?(ActiveSupport::Cache::RedisStore)
Rails.cache.data.bitcount(cache_key)
else
0
end
end
def cache_key
if Rails.cache.is_a?(ActiveSupport::Cache::RedisStore)
# 10分钟为一段记录用户在线, 统计范围为20分钟内的线用户
# TODO 更精确时长
begin_hour = Time.now.beginning_of_hour
minutes_piece = (Time.now - begin_hour) / 600
time = begin_hour.since((minutes_piece.to_i - 1) * 600).strftime("%H-%M")
"online_user_#{time}"
else
raise '请配置config.cache_store = redis_store'
end
end
end
end

@ -90,6 +90,13 @@ class Course < ApplicationRecord
# 直播
has_many :live_links, dependent: :destroy
# 签到
has_many :course_attendances, dependent: :destroy
has_many :course_attendance_groups
has_many :course_member_attendances
has_many :teacher_group_records, dependent: :destroy
validate :validate_sensitive_string
scope :hidden, ->(is_hidden = true) { where(is_hidden: is_hidden) }

@ -2,10 +2,11 @@ class CourseActivity < ApplicationRecord
belongs_to :course_act, polymorphic: true
belongs_to :course
belongs_to :user
belongs_to :exercise
belongs_to :poll
belongs_to :course_message
belongs_to :homework_common
belongs_to :exercise, optional: true
belongs_to :poll, optional: true
belongs_to :course_message, optional: true
belongs_to :homework_common, optional: true
belongs_to :course_attendance, optional: true
# after_create :add_course_lead

@ -0,0 +1,69 @@
class CourseAttendance < ApplicationRecord
# status: 0: 未开启1已开启2已截止
# mode: 0 两种签到1 二维码签到2 数字签到
enum mode: { ALL: 0, QRCODE: 1, NUMBER: 2 }
belongs_to :course
belongs_to :user
has_many :course_attendance_groups, dependent: :destroy
has_many :course_member_attendances, dependent: :destroy
has_one :course_act, class_name: 'CourseActivity', as: :course_act, dependent: :destroy
validates :name, presence: true, length: { maximum: 60, too_long: "不能超过60个字符" }
validates :mode, presence: true
validates :attendance_date, presence: true
validates :start_time, presence: true
validates :end_time, presence: true
after_create :generate_attendance_code, :act_as_course_activity
# 正常签到人数
def normal_count
course_member_attendances.select{|member_attendance| member_attendance.attendance_status == "NORMAL"}.size
end
# 请假人数
def leave_count
course_member_attendances.select{|member_attendance| member_attendance.attendance_status == "LEAVE"}.size
end
# 旷课人数
def absence_count
course_member_attendances.select{|member_attendance| member_attendance.attendance_status == "ABSENCE"}.size
end
# 总人数
def all_count
course_member_attendances.size
end
def current_attendance?
a_start_time = "#{attendance_date} #{start_time}".to_time
a_end_time = "#{attendance_date} #{end_time}".to_time
a_start_time < Time.current && Time.current < a_end_time
end
#课程动态公共表记录
def act_as_course_activity
CourseActivity.create(user_id: user_id, course_id: course_id, course_act: self)
end
# 延迟生成邀请码
def attendance_code
return generate_attendance_code
end
# 生成邀请码
CODES = %W(2 3 4 5 6 7 8 9 A B C D E F G H J K L N M O P Q R S T U V W X Y Z)
def generate_attendance_code
code = read_attribute(:attendance_code)
if !code || code.size < 4
code = CODES.sample(4).join
return generate_attendance_code if CourseAttendance.where(attendance_code: code).present?
update_attribute(:attendance_code, code)
end
code
end
end

@ -0,0 +1,5 @@
class CourseAttendanceGroup < ApplicationRecord
belongs_to :course
belongs_to :course_attendance
belongs_to :course_group, optional: true
end

@ -9,6 +9,8 @@ class CourseGroup < ApplicationRecord
has_many :homework_group_settings, :dependent => :destroy
scope :by_group_ids, lambda { |ids| where(id: ids)}
has_many :course_attendance_groups, dependent: :destroy
validates :name, length: { maximum: 60, too_long: "不能超过60个字符" }
validates_uniqueness_of :name, scope: :course_id, message: "不能创建相同名称的分班"

@ -8,6 +8,7 @@ class CourseMember < ApplicationRecord
belongs_to :course_group, counter_cache: true, optional: true
belongs_to :graduation_group, optional: true
has_many :teacher_course_groups, dependent: :destroy
has_many :course_member_attendances, dependent: :destroy
scope :teachers_and_admin, -> { where(role: %i[CREATOR PROFESSOR ASSISTANT_PROFESSOR]) }
scope :students, ->(course) { where(course_id: course.id, role: %i[STUDENT])}
@ -22,6 +23,10 @@ class CourseMember < ApplicationRecord
# after_destroy :delete_works
# after_create :work_operation
after_create :create_attendance_record
after_commit :create_attendance_record
def delete_works
if self.role == "STUDENT"
course = self.course
@ -156,4 +161,11 @@ class CourseMember < ApplicationRecord
end
teachers
end
private
def create_attendance_record
StudentJoinAttendanceRecordJob.perform_later(id)
end
end

@ -0,0 +1,11 @@
class CourseMemberAttendance < ApplicationRecord
# attendance_mode 0 初始数据1 二维码签到2 数字签到3 老师签到
enum attendance_mode: { DEFAULT: 0, QRCODE: 1, NUMBER: 2, TEACHER: 3}
# attendance_status 1 正常签到2 请假0 旷课
enum attendance_status: { NORMAL: 1, LEAVE: 2, ABSENCE: 0 }
belongs_to :course_member
belongs_to :user
belongs_to :course
belongs_to :course_attendance
belongs_to :course_group
end

@ -1,8 +1,8 @@
#encoding=utf-8
class Ecloud < ActiveRecord::Base
attr_accessible :applyno, :begintime, :bossorderid, :custcode, :custid, :custname, :custtype, :ecordercode, :endtime,
:mobile, :opttype, :productcode, :registersource, :string, :trial, :useralias, :userid, :username, :email,
:effecttime, :operatime
# attr_accessible :applyno, :begintime, :bossorderid, :custcode, :custid, :custname, :custtype, :ecordercode, :endtime,
# :mobile, :opttype, :productcode, :registersource, :string, :trial, :useralias, :userid, :username, :email,
# :effecttime, :operatime
has_many :ecloud_services, :dependent => :destroy # 业务列表
has_many :ecloud_productparas, :dependent => :destroy # 开通参数列表

@ -1,4 +1,4 @@
class EcloudProductpara < ActiveRecord::Base
attr_accessible :key, :value, :ecloud_id
# attr_accessible :key, :value, :ecloud_id
belongs_to :ecloud
end

@ -1,6 +1,6 @@
# 操作代码 0新增业务1注销业务2修改业务
class EcloudService < ActiveRecord::Base
attr_accessible :begintime, :code, :endtime, :opttype, :ecloud_id, :packagecode, :bossorderid
# attr_accessible :begintime, :code, :endtime, :opttype, :ecloud_id, :packagecode, :bossorderid
belongs_to :ecloud
has_many :ecloud_serviece_serviceparas
end

@ -1,5 +1,5 @@
# ket值license表示人数对应企业版duration表示月数对应个人版
class EcloudServieceServicepara < ActiveRecord::Base
attr_accessible :key, :value, :ecloud_service_id
# attr_accessible :key, :value, :ecloud_service_id
belongs_to :ecloud_service
end

@ -1,4 +1,4 @@
class EcloudUser < ActiveRecord::Base
# opttype: # user['opttype']: 操作类型0开通1变更3: 取消授权4暂停5恢复
attr_accessible :begintime, :email, :endtime, :mobile, :opttype, :paras, :useralias, :userid, :username, :custid
# attr_accessible :begintime, :email, :endtime, :mobile, :opttype, :paras, :useralias, :userid, :username, :custid
end

@ -29,6 +29,19 @@ class Game < ApplicationRecord
validates :identifier, uniqueness: true
# 服务器uri+port的redis的key
def server_key
"game_server_url_#{id}"
end
def set_server_key(server_url)
Rails.cache.write("#{server_key}", server_url, expires_in: 5.minute)
end
def get_server_url
Rails.cache.read(server_key)
end
# 根据得分比例来算实际得分(试卷、实训作业)
def real_score score
((final_score < 0 ? 0 : final_score).to_f / challenge.score) * score

@ -12,5 +12,5 @@ class HomeworkBank < ApplicationRecord
validates :name, length: { maximum: 60, too_long: "不能超过60个字符" }
validates :description, length: { maximum: 15000, too_long: "不能超过15000个字符" }
validates :reference_answer, length: { maximum: 15000, too_long: "不能超过15000个字符" }
validates :reference_answer, length: { maximum: 25000, too_long: "不能超过25000个字符" }
end

@ -38,7 +38,7 @@ class HomeworkCommon < ApplicationRecord
validates :name, presence: true, length: { maximum: 60, too_long: "不能超过60个字符" }
validates :description, length: { maximum: 15000, too_long: "不能超过15000个字符" }
validates :explanation, length: { maximum: 5000, too_long: "不能超过5000个字符" }
validates :reference_answer, length: { maximum: 15000, too_long: "不能超过15000个字符" }
validates :reference_answer, length: { maximum: 25000, too_long: "不能超过25000个字符" }
# after_update :update_activity
before_destroy :update_homework_bank_quotes
@ -104,7 +104,7 @@ class HomeworkCommon < ApplicationRecord
end
def user_work user_id
work = self.student_works.find_by_user_id(user_id) || StudentWork.create!(homework_common_id: id, user_id: user_id)
work = StudentWork.find_by(homework_common_id: id, user_id: user_id) || StudentWork.create!(homework_common_id: id, user_id: user_id)
end
# 是否在补交阶段内

@ -30,6 +30,10 @@ class LaboratorySetting < ApplicationRecord
image_url('_subject_banner')
end
def shixun_banner_url
image_url('_shixun_banner')
end
def course_banner_url
image_url('_course_banner')
end
@ -62,7 +66,7 @@ class LaboratorySetting < ApplicationRecord
name: nil,
navbar: [
{ 'name' => '实践课程', 'link' => '/paths', 'hidden' => false },
{ 'name' => '翻转课堂', 'link' => '/courses', 'hidden' => false },
{ 'name' => '教学课堂', 'link' => '/courses', 'hidden' => false },
{ 'name' => '实训项目', 'link' => '/shixuns', 'hidden' => false },
{ 'name' => '在线竞赛', 'link' => '/competitions', 'hidden' => false },
{ 'name' => '教学案例', 'link' => '/moop_cases', 'hidden' => false },

@ -2,9 +2,11 @@ class ShixunInfo < ApplicationRecord
belongs_to :shixun
validates_uniqueness_of :shixun_id
validates_length_of :fork_reason, maximum: 60, message: "不能超过60个字符"
# validates_presence_of :evaluate_script, message: "实训脚本不能为空"
after_commit :create_diff_record
validates :description, length: { maximum: 5000, too_long: "不能超过5000个字符" }
validates :description, length: { maximum: 10000, too_long: "不能超过10000个字符" }
private

@ -0,0 +1,20 @@
class StaAll < ApplicationRecord
# t.integer :school_id 学校ID
# t.integer :tea_count 老师数
# t.integer :stu_count 学生数
# t.integer :active_users_count 活跃用户数3个月内有登录
# t.integer :courses_count 总课堂数
# t.integer :curr_courses_count 正在进行的课堂数
# t.integer :homw_shixuns_count 实训作业数
# t.integer :homw_other_count 其它类型作业数
# t.integer :sources_count 资源数
# t.integer :videos_count 视频总个数
# t.integer :shixuns_count 制作实训总数
# t.integer :myshixuns_count 挑战实训总数
# t.integer :mys_passed_count 通关的实训总数
# t.integer :games_count 挑战的总关卡数
# t.integer :games_passed_count 通关的总关卡数
# t.integer :build_count 评测总数
belongs_to :school
end

@ -0,0 +1,4 @@
class TeacherGroupRecord < ApplicationRecord
belongs_to :user
belongs_to :course
end

@ -160,6 +160,8 @@ class User < ApplicationRecord
has_many :examination_banks, dependent: :destroy
has_many :examination_intelligent_settings, dependent: :destroy
has_many :teacher_group_records, dependent: :destroy
# Groups and active users
scope :active, lambda { where(status: STATUS_ACTIVE) }

@ -0,0 +1,3 @@
class WeappSettings::CourseBanner < WeappSetting
default_scope { order(position: :asc) }
end

@ -0,0 +1,3 @@
class WeappSettings::ShixunBanner < WeappSetting
default_scope { order(position: :asc) }
end

@ -0,0 +1,114 @@
class Admins::UserSchoolsStatisticQuery < ApplicationQuery
include CustomSortable
attr_reader :params
sort_columns :cnt,
default_by: :cnt, default_direction: :desc
def initialize(params)
@params = params
end
def call
schools = School
if params[:province].present?
schools = schools.where("province like ?", "%#{params[:province]}%")
end
if params[:school_id].present?
schools = schools.where(id: params[:school_id])
end
total = schools.count
# 根据排序字段进行查询
schools = query_by_sort_column(schools.group(:id), params[:sort_by])
#schools = custom_sort(schools, params[:sort_by], params[:sort_direction])
schools = schools.limit(page_size).offset(offset).to_a
# 查询并组装其它数据
schools = package_other_data(schools)
[total, schools]
end
private
def package_other_data(schools)
ids = schools.map(&:id)
user_e = UserExtension.where(school_id: schools.map(&:id))
#study_myshixun = Myshixun.joins("join user_extensions ue on ue.user_id = myshixuns.user_id").where(ue: {school_id: ids})
#finish_myshixun = Myshixun.joins("join user_extensions ue on ue.user_id = myshixuns.user_id")
# .where(ue: {school_id: ids}, myshixuns: {status: 1})
study_challenge = Game.joins("join user_extensions ue on ue.user_id = games.user_id")
.where(ue: {school_id: ids},).where( games:{status: [0, 1, 2]})
finish_challenge = Game.joins("join user_extensions ue on ue.user_id = games.user_id")
.where(ue: {school_id: ids}).where(games: {status: 2})
reg_teacher = user_e.where(identity: 'teacher')
reg_student = user_e.where.not(identity: 'teacher')
if time_range.present?
#study_myshixun = study_myshixun.where(updated_at: time_range)
#finish_myshixun = finish_myshixun.where(updated_at: time_range)
study_challenge = study_challenge.where(updated_at: time_range)
finish_challenge = finish_challenge.where(updated_at: time_range)
reg_teacher = reg_teacher.where(created_at: time_range)
reg_student = reg_student.where(created_at: time_range)
user_e = user_e.joins(:user).where(users: {last_login_on: time_range})
end
#study_myshixun_map = study_myshixun.reorder(nil).group(:school_id).count
#finish_myshixun_map = finish_myshixun.reorder(nil).group(:school_id).count
study_challenge_map = study_challenge.reorder(nil).group(:school_id).count
finish_challenge_map = finish_challenge.reorder(nil).group(:school_id).count
evaluate_count_map = study_challenge.reorder(nil).group(:school_id).sum(:evaluate_count)
reg_teacher_map = reg_teacher.reorder(nil).group(:school_id).count
reg_student_map = reg_student.reorder(nil).group(:school_id).count
user_e_map = user_e.reorder(nil).group(:school_id).count
schools.each do |school|
school._extra_data = {
#study_shixun_count: study_myshixun_map.fetch(schools.id, 0),
#finish_shixun_count: finish_myshixun_map.fetch(schools.id, 0),
study_challenge_count: study_challenge_map.fetch(school.id, 0),
finish_challenge_count: finish_challenge_map.fetch(school.id, 0),
evaluate_count: evaluate_count_map.fetch(school.id, 0),
reg_teacher_count: reg_teacher_map.fetch(school.id, 0),
reg_student_count: reg_student_map.fetch(school.id, 0),
user_active_count: user_e_map.fetch(school.id, 0)
}
end
schools
end
def query_by_sort_column(schools, sort_by_column)
#base_query_column = 'schools.*'
case sort_by_column.to_s
when 'cnt' then
schools.left_joins(:user_extensions).select("schools.*, count(*) cnt").order("cnt desc")
else
schools
end
end
def time_range
@_time_range ||= begin
case params[:date]
when 'dayly' then 1.days.ago..Time.now
when 'weekly' then 1.weeks.ago..Time.now
when 'monthly' then 1.months.ago..Time.now
when 'quarterly' then 3.months.ago..Time.now
when 'yearly' then 1.years.ago..Time.now
else ''
end
end
end
def page_size
params[:per_page].to_i.zero? ? 20 : params[:per_page].to_i
end
def offset
(params[:page].to_i.zero? ? 0 : params[:page].to_i - 1) * page_size
end
end

@ -19,6 +19,11 @@ class Weapps::SubjectQuery < ApplicationQuery
subjects = subjects.joins(:sub_discipline_containers).where(sub_discipline_containers: {container_type: "Subject"})
end
# 搜索
if params[:keyword].present?
subjects = subjects.where("subjects.name like '%#{params[:keyword]}%'")
end
subjects = subjects.left_joins(:shixuns, :repertoire).select('subjects.id, subjects.name, subjects.excellent, subjects.stages_count, subjects.status, subjects.homepage_show,
subjects.shixuns_count, subjects.repertoire_id, subjects.updated_at, IFNULL(sum(shixuns.myshixuns_count), 0) myshixuns_count')
.group('subjects.id').order("subjects.homepage_show #{sort_type}, #{order_type} #{sort_type}")

@ -40,6 +40,7 @@ class Admins::SaveLaboratorySettingService < ApplicationService
save_image_file(params[:login_logo], 'login')
save_image_file(params[:tab_logo], 'tab')
save_image_file(params[:subject_banner], '_subject_banner')
save_image_file(params[:shixun_banner], '_shixun_banner')
save_image_file(params[:course_banner], '_course_banner')
save_image_file(params[:competition_banner], '_competition_banner')
save_image_file(params[:moop_cases_banner], '_moop_cases_banner')

@ -9,6 +9,10 @@ class ApplicationService
content.gsub(regex, '')
end
def convert_https content
content.gsub("http:", "https:")
end
private
def strip(str)

@ -0,0 +1,100 @@
class Schools::SchoolStatisticService < ApplicationService
attr_reader :school
def initialize(school)
@school = school.includes(:courses, user_extensions: :user)
@user_extensions = school.user_extensions
end
# 学校老师数量
def teacher_count
@user_extensions.map{|ue| ue.identity == 0 }.size
end
# 学校学生数
def student_count
@user_extensions.map{|ue| ue.identity == 1 }.size
end
# 活跃用户近1天有登录
def acitve_user_1_day_count
@user_extensions.map{|ue| ue.user.last_login_on&.between?(1.days.ago, Time.now)}.size
end
# 活跃用户近1个周有登录
def acitve_user_1_week_count
@user_extensions.map{|ue| ue.user.last_login_on&.between?(1.weeks.ago, Time.now)}.size
end
# 活跃用户近3个月有登录
def acitve_user_1_months_count
@user_extensions.map{|ue| ue.user.last_login_on&.between?(1.months.ago, Time.now)}.size
end
# 活跃用户近3个月有登录
def acitve_user_3_months_count
@user_extensions.map{|ue| ue.user.last_login_on&.between?(3.months.ago, Time.now)}.size
end
# 活跃用户(进半年有登录记录)
def acitve_user_6_months_count
@user_extensions.map{|ue| ue.user.last_login_on&.between?(6.months.ago, Time.now)}.size
end
# 课堂总数(上层记得Include)
def courses_count
@school.courses.size
end
# 正在进行的课堂数
def curr_courses_count
@school.courses.map{|c| c.is_end == false && c.is_delete != 0}.size
end
# 实训作业数目
def hom_shixuns_count
@school.courses.joins(:homework_commons).where(homework_commons: {homework_type: 'practice'}).size
end
# 资源数
def sources_count
@school.courses.joins(:attachments).size
end
# 视频总数
def videos_count
@school.courses.joins(:course_videos).size
end
# 制作实训数
def shixun_count
@user_extensions.joins(user: :shixuns).size
end
# 挑战实训总数
def myshixuns_count
@user_extensions.joins("join myshixuns on myshixuns.user_id = user_extensions.user_id").size
end
# 通过的实训总数
def pass_myshixun_count
@user_extensions.joins("join myshixuns on myshixuns.user_id = user_extensions.user_id").where(myshixuns: {status: 1}).size
end
# 挑战的关卡数
def games_count
@user_extensions.joins("join games on games.user_id = user_extensions.user_id").where(games: {status: 0..2})
end
# 通关的关卡数
def pass_games_count
@user_extensions.joins("join games on games.user_id = user_extensions.user_id").where(games: {status: 2})
end
# 评测总数
def evalute_count
@user_extensions.joins("join games on games.user_id = user_extensions.user_id").sum(:evalute_count)
end
end

@ -12,7 +12,7 @@ class Videos::DispatchCallbackService < ApplicationService
# TODO:: 拆分事件分发
case params['EventType']
when 'FileUploadComplete' then # 视频上传完成
video.file_url = params['FileUrl']
video.file_url = convert_https(params['FileUrl'])
video.filesize = params['Size']
video.upload_success
video.save!

@ -1,20 +1,20 @@
class StatisticSchoolReportTask
def call
School.find_each do |school|
evaluate_count = Game.joins(:challenge)
.joins('LEFT JOIN course_members ON course_members.user_id = games.user_id')
.joins('LEFT JOIN homework_commons_shixuns hcs ON hcs.shixun_id = challenges.shixun_id')
.joins('LEFT JOIN homework_commons hc ON hcs.homework_common_id = hc.id AND hc.homework_type = 4')
.joins('LEFT JOIN courses ON hc.course_id = courses.id AND course_members.course_id = courses.id')
.where(courses: { school_id: school.id })
.sum(:evaluate_count)
report = SchoolReport.find_or_initialize_by(school_id: school.id)
report.school_name = school.name
report.shixun_evaluate_count = evaluate_count
report.save
end
# School.find_each do |school|
# evaluate_count = Game.joins(:challenge)
# .joins('LEFT JOIN course_members ON course_members.user_id = games.user_id')
# .joins('LEFT JOIN homework_commons_shixuns hcs ON hcs.shixun_id = challenges.shixun_id')
# .joins('LEFT JOIN homework_commons hc ON hcs.homework_common_id = hc.id AND hc.homework_type = 4')
# .joins('LEFT JOIN courses ON hc.course_id = courses.id AND course_members.course_id = courses.id')
# .where(courses: { school_id: school.id })
# .sum(:evaluate_count)
#
# report = SchoolReport.find_or_initialize_by(school_id: school.id)
#
# report.school_name = school.name
# report.shixun_evaluate_count = evaluate_count
#
# report.save
# end
end
end

@ -11,7 +11,7 @@
<th width="13%">
<%= sort_tag(name: 'shixun_evaluate_count', path: admins_daily_school_statistics_path) do %>
实训评测总数
<i class="fa fa-question-circle" data-toggle="tooltip" data-html="true" data-placement="top" title="数据更新时间为<br/>当日6点、12点、18点、24点"></i>
<i class="fa fa-question-circle" data-toggle="tooltip" data-html="true" data-placement="top" title="数据每晚4点更新"></i>
<% end %>
</th>
<th width="11%"><%= sort_tag('实训作业总数', name: 'homework_count', path: admins_daily_school_statistics_path) %></th>

@ -42,10 +42,7 @@
</div>
</div>
</div>
<!-- <p class="mt-3 mb-0 text-muted text-sm">-->
<!-- <span class="text-danger mr-2"><i class="fas fa-arrow-down"></i> 3.48%</span>-->
<!-- <span class="text-nowrap">Since last week</span>-->
<!-- </p>-->
</div>
</div>
</div>
@ -63,13 +60,11 @@
</div>
</div>
</div>
<!-- <p class="mt-3 mb-0 text-muted text-sm">-->
<!-- <span class="text-warning mr-2"><i class="fas fa-arrow-down"></i> 1.10%</span>-->
<!-- <span class="text-nowrap">Since yesterday</span>-->
<!-- </p>-->
</div>
</div>
</div>
<div class="col-xl-3 col-lg-6">
<div class="card card-stats mb-4 mb-xl-0">
<div class="card-body">
@ -91,6 +86,45 @@
</div>
</div>
</div>
<div class="col-xl-3 col-lg-6" style="padding-top: 15px;">
<div class="card card-stats mb-4 mb-xl-0">
<div class="card-body">
<div class="row">
<div class="col">
<h5 class="card-title text-uppercase text-muted mb-0">当前在线用户数</h5>
<span class="h2 font-weight-bold mb-0"><%= UserOnline.count %></span>
</div>
<div class="col-auto">
<div class="icon icon-shape rounded-circle shadow">
<i class="fa fa-users"></i>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-3 col-lg-6" style="padding-top: 15px;">
<div class="card card-stats mb-4 mb-xl-0">
<div class="card-body">
<div class="row">
<div class="col">
<h5 class="card-title text-uppercase text-muted mb-0">当前Pod总数</h5>
<span class="h2 font-weight-bold mb-0"><%= @pod_num.to_i %></span>
</div>
<div class="col-auto">
<div class="icon icon-shape rounded-circle shadow">
<i class="fa fa-users"></i>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
@ -100,14 +134,6 @@
<div class="row mt-5">
<div class="col-xl-8 mb-5 mb-xl-0">
<div class="card shadow">
<!-- <div class="card-header border-0">-->
<!-- <div class="row align-items-center">-->
<!-- <h5 class="mb-0">近7天评测次数</h5>-->
<!-- </div>-->
<!-- </div>-->
<!-- <div class="table-responsive">-->
<!-- <div id="evaluate-pie" class="pie"></div>-->
<!-- </div>-->
</div>
</div>
@ -127,92 +153,3 @@
</div>
<!--<div class="container-fluid mt--7">-->
<!-- <div class="row mt-5">-->
<!-- <div class="col-xl-8 mb-5 mb-xl-0">-->
<!-- <div class="card shadow">-->
<!-- <div class="card-header border-0">-->
<!-- <div class="row align-items-center">-->
<!-- <div class="col">-->
<!-- <h3 class="mb-0">Page visits</h3>-->
<!-- </div>-->
<!-- <div class="col text-right">-->
<!-- <a href="#!" class="btn btn-sm btn-primary">Test</a>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- <div class="table-responsive">-->
<!-- <table class="table align-items-center table-flush">-->
<!-- <thead class="thead-light">-->
<!-- <tr>-->
<!-- <th scope="col">Test</th>-->
<!-- <th scope="col">Test</th>-->
<!-- <th scope="col">Test</th>-->
<!-- <th scope="col">Test</th>-->
<!-- </tr>-->
<!-- </thead>-->
<!-- <tbody>-->
<%# 5.times do %>
<!-- <tr>-->
<!-- <th scope="row">/test/</th>-->
<!-- <td>4,569</td>-->
<!-- <td>340</td>-->
<!-- <td>-->
<!-- <i class="fas fa-arrow-up text-success mr-3"></i> 46,53%-->
<!-- </td>-->
<!-- </tr>-->
<%# end %>
<!-- </tbody>-->
<!-- </table>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- <div class="col-xl-4">-->
<!-- <div class="card shadow">-->
<!-- <div class="card-header border-0">-->
<!-- <div class="row align-items-center">-->
<!-- <div class="col">-->
<!-- <h3 class="mb-0">Test</h3>-->
<!-- </div>-->
<!-- <div class="col text-right">-->
<!-- <a href="#!" class="btn btn-sm btn-primary">Test</a>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- <div class="table-responsive">-->
<!-- <table class="table align-items-center table-flush">-->
<!-- <thead class="thead-light">-->
<!-- <tr>-->
<!-- <th scope="col">Test</th>-->
<!-- <th scope="col">Test</th>-->
<!-- <th scope="col"></th>-->
<!-- </tr>-->
<!-- </thead>-->
<!-- <tbody>-->
<%# 5.times do %>
<!-- <tr>-->
<!-- <th scope="row">-->
<!-- Test-->
<!-- </th>-->
<!-- <td>-->
<!-- 1,480-->
<!-- </td>-->
<!-- <td>-->
<!-- <div class="d-flex align-items-center">-->
<!-- <span class="mr-2">60%</span>-->
<!-- <div>-->
<!-- <div class="progress">-->
<!-- <div class="progress-bar bg-gradient-danger" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100" style="width: 60%;"></div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </td>-->
<!-- </tr>-->
<%# end %>
<!-- </tbody>-->
<!-- </table>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!--</div>-->

@ -100,9 +100,19 @@
</div>
</div>
<div class="col-12 col-md-4 banner-item">
<%- shixun_banner = setting.shixun_banner_url -%>
<div class="banner-item-top">实训项目</div>
<div class="banner-item-bottom <%= shixun_banner ? 'has-img' : '' %>">
<img class="banner-item-img shixun-banner-img" src="<%= shixun_banner %>" style="<%= shixun_banner.present? ? '' : 'display: none' %>"/>
<%= file_field_tag(:shixun_banner, accept: 'image/*', style: 'display: none', value: params[:shixun_banner]) %>
<label for="shixun_banner" class="banner-item-upload" data-toggle="tooltip" data-title="选择图片"></label>
</div>
</div>
<div class="col-12 col-md-4 banner-item">
<%- course_banner = setting.course_banner_url -%>
<div class="banner-item-top">翻转课堂</div>
<div class="banner-item-top">教学课堂</div>
<div class="banner-item-bottom <%= course_banner ? 'has-img' : '' %>">
<img class="banner-item-img course-banner-img" src="<%= course_banner %>" style="<%= course_banner.present? ? '' : 'display: none' %>"/>
<%= file_field_tag(:course_banner, accept: 'image/*', style: 'display: none', value: params[:course_banner]) %>

@ -23,13 +23,13 @@
<td class="text-left">
<% if myshixun.shixun.is_jupyter? %>
<%= link_to "/tasks/#{myshixun.identifier}/jupyter", target: '_blank' do %>
<%= overflow_hidden_span myshixun.shixun.name, width: 280 %>
<%= overflow_hidden_span myshixun.shixun.name, width: 200 %>
<% end %>
<% else %>
<% current_task = myshixun.last_executable_task || myshixun.last_task %>
<% if current_task %>
<%= link_to "/tasks/#{current_task.identifier}", target: '_blank' do %>
<%= overflow_hidden_span myshixun.shixun.name, width: 280 %>
<%= overflow_hidden_span myshixun.shixun.name, width: 200 %>
<% end %>
<% end %>
<% end %>

@ -17,7 +17,7 @@
<li>
<%= sidebar_item_group('#school-submenu', '学校统计', icon: 'area-chart') do %>
<li><%= sidebar_item(admins_daily_school_statistics_path, '统计总表', icon: 'bar-chart', controller: 'admins-daily_school_statistics') %></li>
<li><%= sidebar_item(admins_school_statistics_path, '数据变化报表', icon: 'line-chart', controller: 'admins-school_statistics') %></li>
<li><%= sidebar_item(admins_school_statistics_path, '数据变化报表', icon: 'line-chart', controller: 'admins-schools') %></li>
<% end %>
</li>
@ -62,6 +62,7 @@
<%= sidebar_item_group('#user-submenu', '用户', icon: 'user') do %>
<li><%= sidebar_item(admins_users_path, '用户列表', icon: 'user', controller: 'admins-users') %></li>
<li><%= sidebar_item(admins_user_statistics_path, '用户实训情况', icon: 'area-chart', controller: 'admins-user_statistics') %></li>
<li><%= sidebar_item(admins_user_schools_statistics_path, '用户运营统计', icon: 'user-md', controller: 'admins-user_schools_statistics') %></li>
<% end %>
</li>
@ -125,6 +126,7 @@
<%= sidebar_item_group('#weapp-setting-submenu', '小程序设置', icon: 'id-badge') do %>
<li><%= sidebar_item(admins_weapp_carousels_path, '轮播图', icon: 'image', controller: 'admins-weapp_carousels') %></li>
<li><%= sidebar_item(admins_weapp_adverts_path, '广告栏', icon: 'paper-plane', controller: 'admins-weapp_adverts') %></li>
<li><%= sidebar_item(admins_weapp_banners_path, 'banner', icon: 'image', controller: 'admins-weapp_banners') %></li>
<% end %>
</li>

@ -0,0 +1,18 @@
wb = xlsx_package.workbook
wb.add_worksheet(name: '用户运营统计') do |sheet|
sheet.add_row %w(单位名称 省份 注册老师数量 注册学生数量 活跃用户 学习关卡数 完成关卡数 评测次数)
@schools.each do |school|
data = [
school.name,
school.province,
school.display_extra_data(:reg_teacher_count),
school.display_extra_data(:reg_student_count),
school.display_extra_data(:user_active_count),
school.display_extra_data(:study_challenge_count),
school.display_extra_data(:finish_challenge_count),
school.display_extra_data(:evaluate_count),
]
sheet.add_row(data)
end
end

@ -0,0 +1,30 @@
<% define_admin_breadcrumbs do %>
<% add_admin_breadcrumb('用户运营情况') %>
<% end %>
<div class="box search-form-container user-schools-statistic-list-form">
<%= form_tag(admins_user_schools_statistics_path, method: :get, class: 'form-inline search-form flex-1', remote: true) do %>
<div class="form-group col-12 col-md-auto">
<label for="status">时间范围:</label>
<% data_arrs = [['不限', ''],['最近一天', 'dayly'], ['最近一周', 'weekly'], ['最近一个月', 'monthly'],
['最近三个月', 'quarterly'], ['最近一年', 'yearly']] %>
<%= select_tag(:date, options_for_select(data_arrs, params[:date]), class: 'form-control') %>
</div>
<div class="form-group col-12 col-md-3">
<label for="school_name">所属单位:</label>
<%= hidden_field_tag(:school_id, params[:school_id]) %>
<%= select_tag :school_name, options_for_select([''], params[:school_id]), class: 'form-control school-select flex-1' %>
</div>
<%= text_field_tag(:province, params[:province], class: 'form-control col-sm-2 ml-3', placeholder: '所属省份') %>
<%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %>
<input type="reset" class="btn btn-secondary clear-btn" value="清空"/>
<% end %>
<%= javascript_void_link '导出', class: 'btn btn-outline-primary export-action', 'data-url': export_admins_user_schools_statistics_path(format: :xlsx) %>
</div>
<div class="box admin-list-container user-schools-statistic-list-container">
<%= render partial: 'admins/user_schools_statistics/shared/list', locals: { schools: @schools } %>
</div>

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

@ -0,0 +1,38 @@
<table class="table table-hover text-center user-statistic-list-table">
<thead class="thead-light">
<tr>
<th width="6%">序号</th>
<th width="22%" class="text-left">单位名称</th>
<th width="8%" class="text-left">省份</th>
<th width="10%">注册老师数量<%#= sort_tag('学习关卡数', name: 'study_challenge_count', path: admins_user_statistics_path) %></th>
<th width="10%">注册学生数量<%#= sort_tag('完成关卡数', name: 'finish_challenge_count', path: admins_user_statistics_path) %></th>
<th width="10%">活跃用户<%#= sort_tag('活跃用户', name: 'user_active_count', path: admins_user_schools_statistics_path) %></th>
<th width="10%">学习关卡数<%#= sort_tag('学习关卡数', name: 'finish_shixun_count', path: admins_user_schools_statistics_path) %></th>
<th width="10%">完成关卡数</th>
<th width="14%">评测次数</th>
</tr>
</thead>
<tbody>
<% if schools.present? %>
<% schools.each_with_index do |school, index| %>
<tr class="user-statistic-item-<%= school.id %>">
<td><%= list_index_no((params[:page] || 1).to_i, index) %></td>
<td class="text-left">
<%= school.name %>
</td>
<td class="text-left"><%= school.province %></td>
<td><%= school.display_extra_data(:reg_teacher_count) %></td>
<td><%= school.display_extra_data(:reg_student_count) %></td>
<td><%= school.display_extra_data(:user_active_count) %></td>
<td><%= school.display_extra_data(:study_challenge_count) %></td>
<td><%= school.display_extra_data(:finish_challenge_count) %></td>
<td><%= school.display_extra_data(:evaluate_count) %></td>
</tr>
<% end %>
<% else %>
<%= render 'admins/shared/no_data_for_table' %>
<% end %>
</tbody>
</table>
<%= render partial: 'admins/shared/paginate', locals: { objects: schools } %>

@ -0,0 +1,2 @@
$("#course_img")[0].innerHTML = "<%= escape_javascript(image_tag Util::FileManage.source_disk_file_url(@course), class: 'banner-item-img course-banner-img') %>";
$("#course_img_banner").addClass('has-img');

@ -0,0 +1,40 @@
<% define_admin_breadcrumbs do %>
<% add_admin_breadcrumb('banner设置') %>
<% end %>
<div class="box weapp-banner-setting-container">
<div class="form-group px-2 setting-item edit-laboratory-setting-container">
<div class="pl-0 py-3 row setting-item-body">
<%= form_with(url: '/admins/weapp_banners', html: { id: 'course_form', enctype: 'multipart/form-data' }) do |f| %>
<div class="col-12 col-md-4 banner-item">
<div class="banner-item-top">实践课程</div>
<div class="course banner-item-bottom <%= @course ? 'has-img' : '' %>" id="course_img_banner">
<div id="course_img">
<% if @course %>
<img class="banner-item-img course-banner-img" src="<%= Util::FileManage.exists?(@course) ? Util::FileManage.source_disk_file_url(@course) : '' %>"/>
<% end %>
</div>
<%= file_field_tag(:course_banner, accept: 'image/*', style: 'display: none', value: '') %>
<label for="course_banner" class="banner-item-upload" data-toggle="tooltip" data-title="选择图片"></label>
</div>
</div>
<% end %>
<%= form_with(url: '/admins/weapp_banners/shixun_banner', html: { id: 'shixun_form', enctype: 'multipart/form-data' }) do |f| %>
<div class="col-12 col-md-4 banner-item">
<div class="banner-item-top">实训项目</div>
<div class="shixun banner-item-bottom <%= @shixun ? 'has-img' : '' %>" id="shixun_img_banner">
<div id="shixun_img">
<% if @shixun %>
<img class="banner-item-img shixun-banner-img" src="<%= Util::FileManage.exists?(@shixun) ? Util::FileManage.source_disk_file_url(@shixun) : '' %>"/>
<% end %>
</div>
<%= file_field_tag(:shixun_banner, accept: 'image/*', style: 'display: none', value: '') %>
<label for="shixun_banner" class="banner-item-upload" data-toggle="tooltip" data-title="选择图片"></label>
</div>
</div>
<% end %>
</div>
</div>
</div>

@ -0,0 +1,2 @@
$("#shixun_img")[0].innerHTML = "<%= escape_javascript(image_tag Util::FileManage.source_disk_file_url(@shixun), class: 'banner-item-img course-banner-img') %>";
$("#shixun_img_banner").addClass('has-img');

@ -10,7 +10,7 @@
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item"><a class="nav-link" href="/paths">实践课程</a></li>
<li class="nav-item"><a class="nav-link" href="/courses">翻转课堂</a></li>
<li class="nav-item"><a class="nav-link" href="/courses">教学课堂</a></li>
<li class="nav-item"><a class="nav-link" href="/shixuns">实训项目</a></li>
<li class="nav-item"><a class="nav-link" href="/competitions">在线竞赛</a></li>
<li class="nav-item"><a class="nav-link" href="/moop_cases">教学案例</a></li>

@ -101,7 +101,7 @@
<div class="col-12 col-md-4 banner-item">
<%- course_banner = setting.course_banner_url -%>
<div class="banner-item-top">翻转课堂</div>
<div class="banner-item-top">教学课堂</div>
<div class="banner-item-bottom <%= course_banner ? 'has-img' : '' %>">
<img class="banner-item-img course-banner-img" src="<%= course_banner %>" style="<%= course_banner.present? ? '' : 'display: none' %>"/>
<%= file_field_tag(:course_banner, accept: 'image/*', style: 'display: none', value: params[:course_banner]) %>

@ -7,6 +7,7 @@ json.setting do
json.tab_logo_url (setting.tab_logo_url || default_setting.tab_logo_url)&.[](1..-1)
json.subject_banner_url (setting.subject_banner_url || default_setting.subject_banner_url)&.[](1..-1)
json.shixun_banner_url (setting.shixun_banner_url || default_setting.shixun_banner_url)&.[](1..-1)
json.course_banner_url (setting.course_banner_url || default_setting.course_banner_url)&.[](1..-1)
json.competition_banner_url (setting.competition_banner_url || default_setting.competition_banner_url)&.[](1..-1)
json.moop_cases_banner_url (setting.moop_cases_banner_url || default_setting.moop_cases_banner_url)&.[](1..-1)

@ -13,7 +13,7 @@ json.identifier shixun.identifier
json.name shixun.name
json.stu_num shixun.myshixuns_count
json.experience shixun.all_score
json.diffcult diff_to_s(shixun.trainee)
json.diffcult level_to_s(shixun.trainee)
json.score_info shixun.shixun_preference_info # todo: 这块可以改成只显示实训的平均分,不用每次都去取每种星的分数了。
json.is_jupyter shixun.is_jupyter
# 用于是否显示导航栏中的'背景知识'

@ -1,4 +1,4 @@
json.status 1
json.message "发送成功"
json.course_id @course.id
json.first_category_url module_url(@course.none_hidden_course_modules.first, @course)
json.first_category_url module_url(@course.shixun_course_modules.first, @course)

@ -1,3 +1,3 @@
json.status 1
json.message "发送成功"
json.url module_url(@course.none_hidden_course_modules.first, @course)
json.url module_url(@course.shixun_course_modules.first, @course)

@ -42,7 +42,7 @@ json.top do
# 云上实验室管理权限
laboratory_user = current_laboratory.laboratory_users.exists?(user_id: @user&.id) || @user&.admin_or_business?
json.laboratory_user laboratory_user
# json.laboratory_user laboratory_user
json.laboratory_admin_url laboratory_user ? "/cooperative" : nil
end

@ -3,4 +3,8 @@ json.extract! video, :id, :title, :cover_url, :file_url, :play_url, :vv, :user_i
json.play_duration video.video_play_duration
json.published_at video.display_published_at
json.created_at video.display_created_at
json.updated_at video.display_updated_at
json.updated_at video.display_updated_at
user = video.user
json.user_name user&.real_name
json.user_img url_to_avatar(user)
json.user_login user&.login

@ -0,0 +1,5 @@
json.(attendance, :name, :mode)
json.attendance_date attendance.attendance_date.strftime("%Y/%m/%d")
json.start_time attendance.start_time.strftime("%H:%M")
json.end_time attendance.end_time.strftime("%H:%M")
json.attendance_status student_attendance_status(attendance, User.current)

@ -0,0 +1,9 @@
json.history_attendances @history_attendances do |attendance|
json.(attendance, :id, :name)
json.created_at attendance.created_at.strftime("%Y/%m/%d %H:%M")
json.normal_count attendance.normal_count
json.leave_count attendance.leave_count
json.absence_count attendance.absence_count
json.edit_auth @user_course_identity < Course::PROFESSOR || attendance.user_id == User.current.id
end
json.all_history_count @all_history_count

@ -0,0 +1,24 @@
json.current_attendance @current_attendance do |attendance|
json.(attendance, :id, :normal_count, :all_count)
json.attendance_date attendance.attendance_date.strftime("%Y/%m/%d")
json.start_time attendance.start_time.strftime("%H:%M")
json.end_time attendance.end_time.strftime("%H:%M")
end
all_normal_rate = []
all_absence_rate = []
json.history_attendances @history_attendances.each_with_index.to_a do |attendance, index|
normal_count = history_member_count(@all_member_attendances, "NORMAL", attendance.id)
absence_count = history_member_count(@all_member_attendances, "ABSENCE", attendance.id)
all_count = @all_member_attendances.select{|member_attendance| member_attendance.course_attendance_id == attendance.id}.size
json.index index + 1
json.normal_rate cal_rate(normal_count, all_count)
all_normal_rate << cal_rate(normal_count, all_count)
json.absence_rate cal_rate(absence_count, all_count)
all_absence_rate << cal_rate(absence_count, all_count)
end
json.all_history_count @all_history_count
json.avg_normal_rate @all_history_count == 0 ? 0 : all_normal_rate.sum / @all_history_count
json.avg_absence_rate @all_history_count == 0 ? 0 : all_absence_rate.sum / @all_history_count

@ -0,0 +1,30 @@
json.normal_count @normal_count
json.leave_count @leave_count
json.absence_count @absence_count
json.all_count @all_count
json.code @attendance.attendance_code
json.mode @attendance.mode
json.edit_auth @user_course_identity < Course::PROFESSOR || @attendance.user_id == User.current.id
json.attendance_date @attendance.attendance_date.strftime("%Y/%m/%d")
json.start_time @attendance.start_time.strftime("%H:%M")
json.end_time @attendance.end_time.strftime("%H:%M")
# json.course_groups @group_ids do |group|
# json.(group, :id, :name, :course_members_count)
# json.attendance_count group_attendance_count(@all_attendances, group) if @_is_current_attendance
# end
json.course_groups @group_ids do |group_id|
if group_id != 0
group = @groups.select{|group| group.id == group_id}.first
json.(group, :id, :name, :course_members_count)
else
json.id 0
json.name "未分班"
json.course_members_count @course.none_group_count
end
if @_is_current_attendance
member_ids = @course_members.select{|member| member.course_group_id == group_id}.map(&:id)
json.attendance_count group_attendance_count(@all_attendances, member_ids)
end
end

@ -0,0 +1,12 @@
json.current_attendance @current_attendance do |attendance|
json.partial! 'student_attendance', locals: {attendance: attendance}
end
json.history_attendances @history_attendances do |attendance|
json.partial! 'student_attendance', locals: {attendance: attendance}
end
json.all_history_count @all_history_count
json.normal_count @normal_count
json.leave_count @leave_count
json.absence_count @absence_count

@ -0,0 +1,14 @@
# json.member_attendances @member_attendances.each do |member|
# json.(member, :user_id, :attendance_status)
# json.user_name member.user&.real_name
# json.student_id member.user&.student_id
# end
json.member_attendances @members.each do |member|
json.(member, :user_id)
json.user_name member.user&.real_name
json.student_id member.user&.student_id
json.attendance_status @member_attendances.select{|attendance| attendance.course_member_id == member.id}.first&.attendance_status || "ABSENCE"
end
json.members_count @members_count

@ -177,6 +177,12 @@ zh-CN:
platform: '直播平台'
live_time: '开播时间'
duration: '直播时长'
course_attendance:
name: '签到名称'
mode: '签到方式'
attendance_date: '签到日期'
start_time: '开始时间'
end_time: '结束时间'

@ -9,6 +9,9 @@ Rails.application.routes.draw do
get 'auth/qq/callback', to: 'oauth/qq#create'
get 'auth/failure', to: 'oauth/base#auth_failure'
get 'auth/cas/callback', to: 'oauth/cas#create'
get 'ecloud/ecloud_login', to: 'ecloud#ecloud_login_callback'
resources :edu_settings
@ -867,6 +870,7 @@ Rails.application.routes.draw do
collection do
get :school_list
get :for_option
get :for_province_option
get :search
end
@ -1025,6 +1029,8 @@ Rails.application.routes.draw do
resource :check_account, only: [:create]
resource :unbind_accounts, only: [:show, :destroy]
resources :banners, only: [:index]
resources :searchs, only: [:index]
resources :course_stickies, only: [:create] do
post :cancel_sticky, on: :collection
@ -1052,6 +1058,18 @@ Rails.application.routes.draw do
collection do
get :check_invite_code
end
resources :attendances, only: [:index, :update, :create, :show, :destroy], shallow: true do
collection do
get :student_attendances
get :history_attendances
end
post :end, on: :member
end
end
resources :course_member_attendances, only: [:create, :index] do
post :update_status, on: :collection
end
resources :homework_commons do
@ -1146,6 +1164,9 @@ Rails.application.routes.draw do
resources :user_statistics, only: [:index] do
get :export, on: :collection
end
resources :user_schools_statistics, only: [:index] do
get :export, on: :collection
end
resources :library_applies, only: [:index] do
member do
post :agree
@ -1328,6 +1349,12 @@ Rails.application.routes.draw do
resources :weapp_adverts, only: [:index, :create, :update, :destroy] do
post :drag, on: :collection
end
resources :weapp_banners, only: [:index, :create] do
collection do
post :shixun_banner
end
end
resources :subject_settings, only: [:index, :update] do
post :update_mobile_show, on: :collection

@ -0,0 +1,16 @@
class CreateCourseAttendances < ActiveRecord::Migration[5.2]
def change
create_table :course_attendances do |t|
t.references :course, index: true
t.references :user, index: true
t.string :name
t.integer :mode, limit: 1, default: 0
t.date :attendance_date
t.time :start_time
t.time :end_time
t.string :attendance_code
t.timestamps
end
end
end

@ -0,0 +1,14 @@
class CreateCourseAttendanceGroups < ActiveRecord::Migration[5.2]
def change
create_table :course_attendance_groups do |t|
t.references :course, index: true
t.references :course_attendance
t.references :course_group, index: true
t.timestamps
end
add_index :course_attendance_groups, [:course_attendance_id, :course_group_id, :course_id], name: "course_group_attendance", unique: true
end
end

@ -0,0 +1,17 @@
class CreateCourseMemberAttendances < ActiveRecord::Migration[5.2]
def change
create_table :course_member_attendances do |t|
t.references :course_member, index: true
t.references :user
t.references :course, index: true
t.references :course_attendance
t.references :course_group, index: true
t.integer :attendance_mode, default: 0
t.integer :attendance_status, default: 0
t.timestamps
end
add_index :course_member_attendances, [:course_attendance_id, :user_id], unique: true, name: "index_on_user_attendance"
end
end

@ -0,0 +1,5 @@
class ModidyHiddenDefaultForDiscusses < ActiveRecord::Migration[5.2]
def change
change_column :discusses, :hidden, :boolean, :default => false
end
end

@ -0,0 +1,25 @@
class CreateStaAlls < ActiveRecord::Migration[5.2]
def change
create_table :sta_alls do |t|
t.integer :school_id, default: 0
t.integer :tea_count, default: 0
t.integer :stu_count, default: 0
t.integer :active_users_count, default: 0
t.integer :courses_count, default: 0
t.integer :curr_courses_count, default: 0
t.integer :homw_shixuns_count, default: 0
t.integer :homw_other_count, default: 0
t.integer :sources_count, default: 0
t.integer :videos_count, default: 0
t.integer :shixuns_count, default: 0
t.integer :myshixuns_count, default: 0
t.integer :mys_passed_count, default: 0
t.integer :games_count, default: 0
t.integer :games_passed_count, default: 0
t.integer :build_count, default: 0
t.timestamps
end
end
end

@ -0,0 +1,13 @@
class CreateTeacherGroupRecords < ActiveRecord::Migration[5.2]
def change
create_table :teacher_group_records do |t|
t.references :user
t.references :course
t.integer :group_id
t.timestamps
end
add_index :teacher_group_records, [:user_id, :course_id], unique: true
end
end

@ -29,6 +29,24 @@ namespace :video do
end
end
desc "将http修改成http"
task modify_http_to_https_file_url: :environment do
p "s"
if ENV['args']
course_id = ENV['args'].split(",")[0]
video_ids = CourseVideo.where(course_id: course_id).pluck(:video_id)
videos = Video.where(id: video_ids)
if videos
videos.each do |v|
if v.file_url
file_url = v.file_url.gsub("http:", "https:")
v.update_column(:file_url, file_url)
end
end
end
end
end
# 执行示例 bundle exec rake video:sample args=2933,'2019-08-19 00:00:00','2019-11-09 23:59:59'
task :sample => :environment do
if ENV['args']

@ -17,7 +17,7 @@ namespace :homework_evaluation do
homework_detail_manuals.each do |homework_detail_manual|
homework_common = homework_detail_manual.homework_common
if homework_common.anonymous_comment
if homework_common.homework_group_settings.where("end_time is null or end_time > '#{Time.now}'").count == 0
if homework_common.homework_group_settings.where("end_time > '#{Time.now}'").count == 0
if homework_common.homework_type == "group"
student_works = homework_common.student_works.where("work_status != 0").group(:group_id)
else
@ -25,9 +25,8 @@ namespace :homework_evaluation do
end
if student_works.present? && student_works.length >= 2
HomeworkEvaluationCommentAssginJob.perform_later(homework_common.id)
homework_detail_manual.update_column('comment_status', 3)
HomeworkEvaluationCommentAssginJob.perform_later(homework_common.id)
else
#作业数小于2启动失败, 只给老师和助教发
extra = "作品数量低于两个,无法开启匿评"
@ -35,12 +34,12 @@ namespace :homework_evaluation do
else
extra = "存在尚未截止的分班,无法开启匿评"
end
HomeworkEvaluationStartNotifyJob.perform_later(homework_common.id, extra)
if extra.present?
homework_detail_manual.update_attributes(:evaluation_start => nil, :evaluation_end => nil, :absence_penalty => 0,
:evaluation_num => 0, :appeal_time => nil, :appeal_penalty => 0)
homework_common.update_attributes(:anonymous_comment => 0, :anonymous_appeal => 0)
end
HomeworkEvaluationStartNotifyJob.perform_later(homework_common.id, extra)
end
end

@ -0,0 +1,8 @@
#coding=utf-8
desc "同步高校数据"
namespace :school_statistic do
task sync_records: :environment do
end
end

@ -0,0 +1,16 @@
desc "统计每个学校使用数据"
namespace :static_all do
task :repo => :environment do
School.find_each(batch_size: 100) do |school|
User.joins(:user_extension).where(school_id: school.id)
report = StaAll.find_or_initialize_by(school_id: school.id)
report.shixun_evaluate_count = evaluate_count
report.save
end
end
end

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

Loading…
Cancel
Save