diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index b7a74cbc1..90a5e494e 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -321,7 +321,7 @@ class ApplicationController < ActionController::Base end if !User.current.logged? && Rails.env.development? - User.current = User.find 3117 + User.current = User.find 1 end diff --git a/app/controllers/weapps/attendances_controller.rb b/app/controllers/weapps/attendances_controller.rb index f61cc95c2..2127abc12 100644 --- a/app/controllers/weapps/attendances_controller.rb +++ b/app/controllers/weapps/attendances_controller.rb @@ -1,9 +1,10 @@ class Weapps::AttendancesController < ApplicationController before_action :require_login - before_action :find_course, only: [:create, :index, :student_attendances] - before_action :find_attendance, except: [:create, :index, :student_attendances] + 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 @@ -13,8 +14,10 @@ class Weapps::AttendancesController < ApplicationController 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_later(attendance.id, [0]) end render_ok({attendance_id: attendance.id}) end @@ -25,7 +28,7 @@ class Weapps::AttendancesController < ApplicationController end def student_attendances - tip_exception(403, "") if @user_course_identity != Course::STUDENT + tip_exception("学生身份的签到列表") if @user_course_identity != Course::STUDENT member = @course.students.find_by(user_id: current_user.id) current_date = Date.current current_end_time = Time.current.strftime("%H:%M:%S") @@ -49,8 +52,8 @@ class Weapps::AttendancesController < ApplicationController @leave_count = 0 @absence_count = 0 else - @normal_count = @course.course_member_attendances.where(course_attendance_id: student_attendance_ids, attendance_status: 1).size - @leave_count = @course.course_member_attendances.where(course_attendance_id: student_attendance_ids, attendance_status: 2).size + @normal_count = @course.course_member_attendances.where(course_attendance_id: student_attendance_ids, attendance_status: "NORMAL").size + @leave_count = @course.course_member_attendances.where(course_attendance_id: student_attendance_ids, attendance_status: "LEAVE").size @absence_count = student_attendance_ids.uniq.size - @normal_count - @leave_count end @@ -59,17 +62,48 @@ class Weapps::AttendancesController < ApplicationController 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 + @groups = @course.course_groups + else + @groups = @course.course_groups.where(id: @attendance.course_attendance_groups.pluck(:course_group_id)) + end + + @groups = @groups.includes(:course_members) if @_is_current_attendance + + @all_attendances = @attendance.course_member_attendances end def update - tip_exception(403, "") unless @user_course_identity < Course::PROFESSOR || @attendance.user_id == current_user.id @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 + tip_exception("该签到不在签到时间内,无法截止") unless @attendance.current_attendance? + @attendance.update!(end_time: Time.current) + render_ok end private @@ -81,4 +115,8 @@ class Weapps::AttendancesController < ApplicationController @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 \ No newline at end of file diff --git a/app/controllers/weapps/course_member_attendances_controller.rb b/app/controllers/weapps/course_member_attendances_controller.rb index 9eca18d4b..d4183c512 100644 --- a/app/controllers/weapps/course_member_attendances_controller.rb +++ b/app/controllers/weapps/course_member_attendances_controller.rb @@ -1,9 +1,21 @@ 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] + @member_attendances = attendance.course_member_attendances + if params[:group_ids].present? + @member_attendances = @member_attendances.joins(:course_member).where(course_members: {course_group_id: params[:group_ids]}) + end + @member_attendances = @member_attendances.where(attendance_status: params[:attendance_status]) if params[:attendance_status].present? + @member_attendances = @member_attendances.joins(user: :user_extension).order("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参数不对") if [1, 2].include?(params[:attendance_mode]) + 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? @@ -11,19 +23,38 @@ class Weapps::CourseMemberAttendancesController < ApplicationController member = attendance.course.students.find_by(user_id: current_user.id) tip_exception("签到码输入有误") if member.blank? - start_time = "#{attendance.attendance_date} #{attendance.start_time}".to_time - end_time = "#{attendance.attendance_date} #{attendance.end_time}".to_time - Rails.logger.info("##############{start_time} #{end_time}") - tip_exception("不在签到时间内") unless start_time < Time.current && Time.current < end_time + tip_exception("不在签到时间内") unless attendance.current_attendance? - current_attendance = attendance.course_member_attendances.find_by(user_id: current_user.id) - tip_exception("请勿重复签到") if current_attendance.present? && current_attendance.attendance_status == 1 - tip_exception("您当前是请假状态,无法签到") if current_attendance.present? && current_attendance.attendance_status == 2 - tip_exception("您当前是旷课状态,无法签到") if current_attendance.present? && current_attendance.attendance_status == 0 + 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" - unless current_attendance.present? + 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: 1, attendance_mode: params[:attendance_mode] || 2) + 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 diff --git a/app/helpers/weapps/attendances_helper.rb b/app/helpers/weapps/attendances_helper.rb index 087084288..60a9cfe26 100644 --- a/app/helpers/weapps/attendances_helper.rb +++ b/app/helpers/weapps/attendances_helper.rb @@ -2,6 +2,11 @@ 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 : 0 + st_attendance.present? ? st_attendance.attendance_status : "ABSENCE" + end + + def group_attendance_count attendances, group + course_member_ids = group.course_members.pluck(:id) + attendances.select{|attendance| course_member_ids.include?(attendance.course_member_id) && attendance.attendance_status == "NORMAL"}.size end end \ No newline at end of file diff --git a/app/jobs/create_student_attendance_record_job.rb b/app/jobs/create_student_attendance_record_job.rb new file mode 100644 index 000000000..83a353565 --- /dev/null +++ b/app/jobs/create_student_attendance_record_job.rb @@ -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 diff --git a/app/jobs/student_join_attendance_record_job.rb b/app/jobs/student_join_attendance_record_job.rb new file mode 100644 index 000000000..f1b33c492 --- /dev/null +++ b/app/jobs/student_join_attendance_record_job.rb @@ -0,0 +1,28 @@ +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_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) + + + 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| + worker.add same_attrs.merge(course_attendance_id: attendance_id) + end + end + end +end diff --git a/app/models/course_attendance.rb b/app/models/course_attendance.rb index f3bcffc56..fd6710fff 100644 --- a/app/models/course_attendance.rb +++ b/app/models/course_attendance.rb @@ -1,5 +1,8 @@ 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 @@ -14,6 +17,27 @@ class CourseAttendance < ApplicationRecord after_create :generate_attendance_code + # 正常签到人数 + 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 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 attendance_code return generate_attendance_code diff --git a/app/models/course_member.rb b/app/models/course_member.rb index 4772f0c36..ec326a7ca 100644 --- a/app/models/course_member.rb +++ b/app/models/course_member.rb @@ -23,6 +23,12 @@ class CourseMember < ApplicationRecord # after_destroy :delete_works # after_create :work_operation + after_create :create_attendance_record + + def create_attendance_record + StudentJoinAttendanceRecordJob.perform_later(id) + end + def delete_works if self.role == "STUDENT" course = self.course diff --git a/app/models/course_member_attendance.rb b/app/models/course_member_attendance.rb index 3b8aafda0..152bb48b6 100644 --- a/app/models/course_member_attendance.rb +++ b/app/models/course_member_attendance.rb @@ -1,6 +1,8 @@ class CourseMemberAttendance < ApplicationRecord - # attendance_mode :1 二维码签到,2 数字签到,3 老师签到 + # 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 diff --git a/app/views/weapps/attendances/history_attendances.json.jbuilder b/app/views/weapps/attendances/history_attendances.json.jbuilder new file mode 100644 index 000000000..1199338ed --- /dev/null +++ b/app/views/weapps/attendances/history_attendances.json.jbuilder @@ -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 \ No newline at end of file diff --git a/app/views/weapps/attendances/show.json.jbuilder b/app/views/weapps/attendances/show.json.jbuilder new file mode 100644 index 000000000..fa725a878 --- /dev/null +++ b/app/views/weapps/attendances/show.json.jbuilder @@ -0,0 +1,10 @@ +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.edit_auth @user_course_identity < Course::PROFESSOR || @attendance.user_id == User.current.id +json.course_groups @groups do |group| + json.(group, :id, :name, :course_members_count) + json.attendance_count group_attendance_count(@all_attendances, group) if @_is_current_attendance +end \ No newline at end of file diff --git a/app/views/weapps/course_member_attendances/index.json.jbuilder b/app/views/weapps/course_member_attendances/index.json.jbuilder new file mode 100644 index 000000000..d6d953af8 --- /dev/null +++ b/app/views/weapps/course_member_attendances/index.json.jbuilder @@ -0,0 +1,5 @@ +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 \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 5ef805f21..883005189 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1061,11 +1061,15 @@ Rails.application.routes.draw do 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] + resources :course_member_attendances, only: [:create, :index] do + post :update_status, on: :collection + end resources :homework_commons do post :update_settings, on: :member diff --git a/spec/jobs/create_student_attendance_record_job_spec.rb b/spec/jobs/create_student_attendance_record_job_spec.rb new file mode 100644 index 000000000..7b66a7376 --- /dev/null +++ b/spec/jobs/create_student_attendance_record_job_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe CreateStudentAttendanceRecordJob, type: :job do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/jobs/student_join_attendance_record_job_spec.rb b/spec/jobs/student_join_attendance_record_job_spec.rb new file mode 100644 index 000000000..f4a452e1a --- /dev/null +++ b/spec/jobs/student_join_attendance_record_job_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe StudentJoinAttendanceRecordJob, type: :job do + pending "add some examples to (or delete) #{__FILE__}" +end