video_transcode
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -0,0 +1,5 @@
|
||||
class CourseAttendanceGroup < ApplicationRecord
|
||||
belongs_to :course
|
||||
belongs_to :course_attendance
|
||||
belongs_to :course_group, optional: true
|
||||
end
|
@ -1,4 +1,4 @@
|
||||
class EcloudProductpara < ActiveRecord::Base
|
||||
attr_accessible :key, :value, :ecloud_id
|
||||
# attr_accessible :key, :value, :ecloud_id
|
||||
belongs_to :ecloud
|
||||
end
|
||||
|
@ -0,0 +1,4 @@
|
||||
class TeacherGroupRecord < ApplicationRecord
|
||||
belongs_to :user
|
||||
belongs_to :course
|
||||
end
|
@ -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
|
@ -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
|
||||
|
@ -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');
|
@ -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)
|
@ -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
|
@ -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
|
@ -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…
Reference in new issue