Merge branch 'dev_aliyun' of http://bdgit.educoder.net/Hjqreturn/educoder into dev_aliyun

dev_forum
cxt 5 years ago
commit bb9487f57d

@ -89,3 +89,5 @@ gem 'sinatra'
# batch insert # batch insert
gem 'bulk_insert' gem 'bulk_insert'
# elasticsearch
# gem 'searchkick'

@ -47,7 +47,7 @@ class ExerciseQuestionsController < ApplicationController
if @exercise_question.save if @exercise_question.save
#为选择题(包括单选和多选)的时候,创建问题选项 #为选择题(包括单选和多选)的时候,创建问题选项
ques_type = @exercise_question.question_type ques_type = @exercise_question.question_type
if ques_type <= 1 if ques_type <= Exercise::MULTIPLE
choices_array = params[:question_choices] choices_array = params[:question_choices]
choices_count= choices_array.count choices_count= choices_array.count
standard_answer = params[:standard_answers] #为数组格式,因为可能会有单选和多选,标准答案,已提前判断不能为空, standard_answer = params[:standard_answers] #为数组格式,因为可能会有单选和多选,标准答案,已提前判断不能为空,
@ -70,13 +70,13 @@ class ExerciseQuestionsController < ApplicationController
} }
question_standard_answer = ExerciseStandardAnswer.new(standard_option) question_standard_answer = ExerciseStandardAnswer.new(standard_option)
question_standard_answer.save question_standard_answer.save
if standard_answer.count > 1 && ques_type == 0 #当标准答案数大于1且不为多选时修改为多选 if standard_answer.count > 1 && ques_type == Exercise::SINGLE #当标准答案数大于1且不为多选时修改为多选
@exercise_question.update_attribute("question_type",1) @exercise_question.update_attribute("question_type",Exercise::MULTIPLE)
elsif standard_answer.count == 1 && ques_type == 1 elsif standard_answer.count == 1 && ques_type == Exercise::MULTIPLE
@exercise_question.update_attribute("question_type",0) @exercise_question.update_attribute("question_type",Exercise::SINGLE)
end end
end end
elsif ques_type == 2 #这个为判断题 elsif ques_type == Exercise::JUDGMENT #这个为判断题
choices_array = params[:question_choices] #判断的选项,对/错等等 choices_array = params[:question_choices] #判断的选项,对/错等等
choices_count= choices_array.count choices_count= choices_array.count
(1..choices_count).each do |c| (1..choices_count).each do |c|
@ -95,7 +95,7 @@ class ExerciseQuestionsController < ApplicationController
} }
question_standard_answer = ExerciseStandardAnswer.new(standard_option) question_standard_answer = ExerciseStandardAnswer.new(standard_option)
question_standard_answer.save question_standard_answer.save
elsif ques_type == 3 #填空题,每空的参考答案有多个,那么以位置对应 elsif ques_type == Exercise::COMPLETION #填空题,每空的参考答案有多个,那么以位置对应
standard_answer = params[:standard_answers] standard_answer = params[:standard_answers]
standard_answer.each do |a| standard_answer.each do |a|
null_choice_id = a[:choice_id] null_choice_id = a[:choice_id]
@ -110,7 +110,7 @@ class ExerciseQuestionsController < ApplicationController
question_standard_answer.save question_standard_answer.save
end end
end end
elsif ques_type == 4 #简答题 elsif ques_type == Exercise::SUBJECTIVE #简答题
if params[:standard_answers].present? && params[:standard_answers].reject(&:blank?).count > 0 if params[:standard_answers].present? && params[:standard_answers].reject(&:blank?).count > 0
standard_answer = params[:standard_answers] standard_answer = params[:standard_answers]
standard_answer.each do |a| standard_answer.each do |a|
@ -122,7 +122,7 @@ class ExerciseQuestionsController < ApplicationController
question_standard_answer.save question_standard_answer.save
end end
end end
elsif ques_type == 5 #实训题 elsif ques_type == Exercise::PRACTICAL #实训题
shixun = Shixun.find_by(id: params[:shixun_id]) shixun = Shixun.find_by(id: params[:shixun_id])
shixun_scores = params[:question_scores] #试卷有多个的分值有多个分数表,所以为分数的数组 shixun_scores = params[:question_scores] #试卷有多个的分值有多个分数表,所以为分数的数组
shixun_name = params[:shixun_name] || shixun.name shixun_name = params[:shixun_name] || shixun.name
@ -225,7 +225,7 @@ class ExerciseQuestionsController < ApplicationController
#试卷未发布时,当标准答案存在时,可修改标准答案内容,可增删标准答案,否则只能修改标准答案,不能增删标准答案 #试卷未发布时,当标准答案存在时,可修改标准答案内容,可增删标准答案,否则只能修改标准答案,不能增删标准答案
@exercise_answers_array = @exercise_question.exercise_standard_answers #问卷的全部标准答案 @exercise_answers_array = @exercise_question.exercise_standard_answers #问卷的全部标准答案
if standard_answer.present? if standard_answer.present?
if @exercise_question.question_type <= 2 #选择题/判断题,标准答案为一个或多个 if @exercise_question.question_type <= Exercise::JUDGMENT #选择题/判断题,标准答案为一个或多个
exercise_standard_choices = @exercise_answers_array.pluck(:exercise_choice_id) #问题以前的全部标准答案选项位置 exercise_standard_choices = @exercise_answers_array.pluck(:exercise_choice_id) #问题以前的全部标准答案选项位置
common_standard_choices = standard_answer & exercise_standard_choices # 传入的标准答案的选项位置和以前的并集,即表示不用做更改的 common_standard_choices = standard_answer & exercise_standard_choices # 传入的标准答案的选项位置和以前的并集,即表示不用做更改的
old_left_standard_choices = exercise_standard_choices - common_standard_choices # 以前的差集共同的,剩余的表示需要删掉 old_left_standard_choices = exercise_standard_choices - common_standard_choices # 以前的差集共同的,剩余的表示需要删掉
@ -244,12 +244,12 @@ class ExerciseQuestionsController < ApplicationController
end end
end end
if standard_answer.count > 1 && @exercise_question.question_type == 0 #当标准答案数大于1且不为多选时修改为多选 if standard_answer.count > 1 && @exercise_question.question_type == Exercise::SINGLE #当标准答案数大于1且不为多选时修改为多选
@exercise_question.update_attribute("question_type",1) @exercise_question.update_attribute("question_type",Exercise::MULTIPLE)
elsif standard_answer.count == 1 && @exercise_question.question_type == 1 elsif standard_answer.count == 1 && @exercise_question.question_type == Exercise::MULTIPLE
@exercise_question.update_attribute("question_type",0) @exercise_question.update_attribute("question_type",Exercise::SINGLE)
end end
elsif @exercise_question.question_type == 3 #填空题 elsif @exercise_question.question_type == Exercise::COMPLETION #填空题
old_ex_answer = @exercise_question.exercise_standard_answers #当前问题的全部标准答案 old_ex_answer = @exercise_question.exercise_standard_answers #当前问题的全部标准答案
old_ex_answer_choice_ids = old_ex_answer.pluck(:exercise_choice_id).uniq #全部的答案数组序号 old_ex_answer_choice_ids = old_ex_answer.pluck(:exercise_choice_id).uniq #全部的答案数组序号
new_ex_answer_choice_ids = standard_answer.map {|a| a[:choice_id]}.uniq #新传入的答案数组序号 new_ex_answer_choice_ids = standard_answer.map {|a| a[:choice_id]}.uniq #新传入的答案数组序号
@ -321,7 +321,7 @@ class ExerciseQuestionsController < ApplicationController
end end
end end
end end
if @exercise_question.question_type == 4 #主观题 if @exercise_question.question_type == Exercise::SUBJECTIVE #主观题
main_standard_answer = standard_answer.present? ? standard_answer.first : nil main_standard_answer = standard_answer.present? ? standard_answer.first : nil
if @exercise_answers_array.present? if @exercise_answers_array.present?
@exercise_answers_array.first.update_attribute("answer_text",main_standard_answer) @exercise_answers_array.first.update_attribute("answer_text",main_standard_answer)
@ -333,7 +333,7 @@ class ExerciseQuestionsController < ApplicationController
question_standard_answer = ExerciseStandardAnswer.new(standard_option) question_standard_answer = ExerciseStandardAnswer.new(standard_option)
question_standard_answer.save question_standard_answer.save
end end
elsif @exercise_question.question_type == 5 elsif @exercise_question.question_type == Exercise::PRACTICAL
question_score = 0 question_score = 0
shixun_name = params[:shixun_name] || @exercise_question.shixun_name shixun_name = params[:shixun_name] || @exercise_question.shixun_name
@exercise_question.exercise_shixun_challenges.each_with_index do |challenge, index| @exercise_question.exercise_shixun_challenges.each_with_index do |challenge, index|
@ -347,7 +347,7 @@ class ExerciseQuestionsController < ApplicationController
#当试卷已发布时(试卷的总状态),当标准答案修改时,如有已提交的学生,需重新计算分数. #当试卷已发布时(试卷的总状态),当标准答案修改时,如有已提交的学生,需重新计算分数.
if @exercise.exercise_status == 2 if @exercise.exercise_status == Exercise::PUBLISHED
ex_users_committed = @exercise.exercise_users.exercise_user_committed ex_users_committed = @exercise.exercise_users.exercise_user_committed
if ex_users_committed.size > 0 if ex_users_committed.size > 0
ex_users_committed.each do |ex_user| ex_users_committed.each do |ex_user|
@ -375,7 +375,7 @@ class ExerciseQuestionsController < ApplicationController
begin begin
opr = params[:opr] opr = params[:opr]
current_q_p = @exercise_question.question_number.to_i #问题的当前位置 current_q_p = @exercise_question.question_number.to_i #问题的当前位置
if @exercise.exercise_status.to_i == 1 if @exercise.exercise_status.to_i == Exercise::UNPUBLISHED
if opr.present? if opr.present?
if opr.to_s == "up" if opr.to_s == "up"
last_q_p = @exercise.exercise_questions.find_by(question_number: (current_q_p - 1)) # 当前问题的前一个问题 last_q_p = @exercise.exercise_questions.find_by(question_number: (current_q_p - 1)) # 当前问题的前一个问题
@ -457,7 +457,7 @@ class ExerciseQuestionsController < ApplicationController
ex_obj_score = @exercise_current_user.objective_score #全部客观题得分 ex_obj_score = @exercise_current_user.objective_score #全部客观题得分
ex_subj_score = @exercise_current_user.subjective_score < 0.0 ? 0.0 : @exercise_current_user.subjective_score #全部主观题得分 ex_subj_score = @exercise_current_user.subjective_score < 0.0 ? 0.0 : @exercise_current_user.subjective_score #全部主观题得分
ex_answers = @exercise_question.exercise_answers.search_answer_users("user_id",@user_id) #当前用户答案的得分 ex_answers = @exercise_question.exercise_answers.search_answer_users("user_id",@user_id) #当前用户答案的得分
if @exercise_question.question_type == 3 #当为填空题,更新问题的总分, if @exercise_question.question_type == Exercise::COMPLETION #当为填空题,更新问题的总分,
ex_answer_old = ex_answers.score_reviewed.pluck(:score).sum #每一关的得分总和 ex_answer_old = ex_answers.score_reviewed.pluck(:score).sum #每一关的得分总和
each_right_score = (@c_score / ex_answers.count.to_f) #调分后,平均每关的分数 each_right_score = (@c_score / ex_answers.count.to_f) #调分后,平均每关的分数
new_obj_score = ex_obj_score - ex_answer_old + @c_score new_obj_score = ex_obj_score - ex_answer_old + @c_score
@ -468,8 +468,8 @@ class ExerciseQuestionsController < ApplicationController
} }
@exercise_current_user.update_attributes(ex_scores) @exercise_current_user.update_attributes(ex_scores)
ex_answers.update_all(:score => each_right_score) #所有的正确选项需重新更新 ex_answers.update_all(:score => each_right_score) #所有的正确选项需重新更新
elsif @exercise_question.question_type == 4 #当为主观题时 elsif @exercise_question.question_type == Exercise::SUBJECTIVE #当为主观题时
if ex_answers.present? if ex_answers.exists?
ex_answers_old_score = ex_answers.first.score > 0.0 ? ex_answers.first.score : 0.0 #原分数小于0取0 ex_answers_old_score = ex_answers.first.score > 0.0 ? ex_answers.first.score : 0.0 #原分数小于0取0
new_sub_score = ex_subj_score - ex_answers_old_score + @c_score #原全部主观题总分减去原该主观题得分再加调分后的分数,即为当前全部主观题得分 new_sub_score = ex_subj_score - ex_answers_old_score + @c_score #原全部主观题总分减去原该主观题得分再加调分后的分数,即为当前全部主观题得分
ex_answers.first.update_attribute("score",@c_score) ex_answers.first.update_attribute("score",@c_score)
@ -481,7 +481,7 @@ class ExerciseQuestionsController < ApplicationController
:answer_text => "" :answer_text => ""
} }
ExerciseAnswer.create(answer_option) ExerciseAnswer.create(answer_option)
new_sub_score = @c_score new_sub_score = ex_subj_score + @c_score
end end
total_scores = ex_obj_score + new_sub_score total_scores = ex_obj_score + new_sub_score
ex_scores = { ex_scores = {
@ -490,8 +490,7 @@ class ExerciseQuestionsController < ApplicationController
} }
@exercise_current_user.update_attributes(ex_scores) @exercise_current_user.update_attributes(ex_scores)
elsif @exercise_question.question_type == 5 elsif @exercise_question.question_type == Exercise::PRACTICAL
# ex_answers = @exercise_question.exercise_shixun_answers.search_shixun_answers("user_id",@user_id).search_shixun_answers("exercise_shixun_challenge_id",@shixun_a_id)
ex_answers = @exercise_question.exercise_shixun_answers.where(user_id:@user_id,exercise_shixun_challenge_id:@shixun_a_id) ex_answers = @exercise_question.exercise_shixun_answers.where(user_id:@user_id,exercise_shixun_challenge_id:@shixun_a_id)
if ex_answers.present? #当为实训题时 if ex_answers.present? #当为实训题时
@ -622,13 +621,13 @@ class ExerciseQuestionsController < ApplicationController
end end
def check_exercise_status def check_exercise_status
normal_status(-1,"不能更改试卷问题!") if @exercise.exercise_status != 1 normal_status(-1,"不能更改试卷问题!") if @exercise.exercise_status != Exercise::UNPUBLISHED
end end
#更新时不能修改的内容 #更新时不能修改的内容
def cannot_change_column def cannot_change_column
#已发布的/已截止的/评阅中的状态时,不能修改分数,不能增删问题和答案,不能修改标准答案,可以修改选项内容/题目内容,这里仅指单个问题 #已发布的/已截止的/评阅中的状态时,不能修改分数,不能增删问题和答案,不能修改标准答案,可以修改选项内容/题目内容,这里仅指单个问题
if @exercise.exercise_status != 1 if @exercise.exercise_status != Exercise::UNPUBLISHED
question_score = @exercise_question.question_score #原来的分数 question_score = @exercise_question.question_score #原来的分数
update_question_score = params[:question_score].to_f.round(1) #传入的分数 update_question_score = params[:question_score].to_f.round(1) #传入的分数
choices_count = @exercise_question.exercise_choices.size #原来的选项个数 choices_count = @exercise_question.exercise_choices.size #原来的选项个数
@ -641,12 +640,12 @@ class ExerciseQuestionsController < ApplicationController
elsif update_choices_count != choices_count #选项个数有修改 elsif update_choices_count != choices_count #选项个数有修改
normal_status(-1,"已发布/已截止,不允许增删答案!") normal_status(-1,"已发布/已截止,不允许增删答案!")
elsif standard_answer.present? elsif standard_answer.present?
if @exercise_question.question_type == 3 if @exercise_question.question_type == Exercise::COMPLETION
exercise_answers_text = standard_answer.map{|a| a[:answer_text]}.sum.uniq exercise_answers_text = standard_answer.map{|a| a[:answer_text]}.sum.uniq
unless (standard_answer.count == exercise_choice_ids.count) && (standard_answers_text.count == exercise_answers_text.count) unless (standard_answer.count == exercise_choice_ids.count) && (standard_answers_text.count == exercise_answers_text.count)
normal_status(-1,"已发布/已截止,不允许增删标准答案!") normal_status(-1,"已发布/已截止,不允许增删标准答案!")
end end
elsif @exercise_question.question_type == 4 elsif @exercise_question.question_type == Exercise::SUBJECTIVE
unless standard_answers_text.count == standard_answer.count unless standard_answers_text.count == standard_answer.count
normal_status(-1,"已发布/已截止,不允许增删标准答案!") normal_status(-1,"已发布/已截止,不允许增删标准答案!")
end end
@ -663,13 +662,13 @@ class ExerciseQuestionsController < ApplicationController
normal_status(-1,"用户不存在!") normal_status(-1,"用户不存在!")
elsif @c_score.blank? elsif @c_score.blank?
normal_status(-1,"分数不能为空!") normal_status(-1,"分数不能为空!")
elsif @exercise_question.question_type <= 1 || @exercise_question.question_type == 2 elsif @exercise_question.question_type <= Exercise::JUDGMENT
normal_status(-1,"选择题/判断题不能调分!") normal_status(-1,"选择题/判断题不能调分!")
elsif params[:comment].present? && params[:comment].length > 100 elsif params[:comment].present? && params[:comment].length > 100
normal_status(-1,"评语不能超过100个字符!") normal_status(-1,"评语不能超过100个字符!")
else else
@shixun_a_id = params[:shixun_challenge_id] @shixun_a_id = params[:shixun_challenge_id]
if @exercise_question.question_type == 5 #当为实训题时,为关卡的分数 if @exercise_question.question_type == Exercise::PRACTICAL #当为实训题时,为关卡的分数
@shixun_challenge = @exercise_question.exercise_shixun_challenges.cha_id_find(@shixun_a_id) @shixun_challenge = @exercise_question.exercise_shixun_challenges.cha_id_find(@shixun_a_id)
if @shixun_challenge.present? if @shixun_challenge.present?
@old_ques_score = @shixun_challenge.first.question_score @old_ques_score = @shixun_challenge.first.question_score

@ -1005,19 +1005,6 @@ class ExercisesController < ApplicationController
@exercise_user_current.update_attribute("start_at",Time.now) @exercise_user_current.update_attribute("start_at",Time.now)
end end
end end
# ex_time = @exercise.time
# if ex_time > 0
# time_mill = ex_time * 60 #转为秒
# exercise_end_time = @exercise.end_time.present? ? @exercise.end_time.to_i : 0
# exercise_user_start = @exercise_user_current.present? ? @exercise_user_current.start_at.to_i : 0
# if (exercise_user_start + time_mill) > exercise_end_time
# time_mill = exercise_end_time - exercise_user_start #如果开始答题时间加试卷的限时长大于试卷的截止时间,则以试卷的截止时间到开始答题时间为试卷的限时
# end
# exercise_user_left_time = Time.now.to_i - exercise_user_start #用户已回答的时间
# @user_left_time = (time_mill < exercise_user_left_time) ? nil : (time_mill - exercise_user_left_time) #当前用户对试卷的回答剩余时间
# end
@t_user_exercise_status = @exercise.get_exercise_status(current_user) @t_user_exercise_status = @exercise.get_exercise_status(current_user)
@user_left_time = nil @user_left_time = nil
@ -1029,10 +1016,7 @@ class ExercisesController < ApplicationController
@user_exercise_status = 0 #可编辑 @user_exercise_status = 0 #可编辑
end end
@exercise_questions = @exercise.exercise_questions.includes(:exercise_shixun_challenges, @exercise_questions = @exercise.exercise_questions
:exercise_shixun_answers,
:exercise_answers,
:exercise_standard_answers)
if @exercise.question_random if @exercise.question_random
@exercise_questions = @exercise_questions.order("RAND()") @exercise_questions = @exercise_questions.order("RAND()")
@ -1040,7 +1024,10 @@ class ExercisesController < ApplicationController
@exercise_questions = @exercise_questions.order("question_number ASC") @exercise_questions = @exercise_questions.order("question_number ASC")
end end
# 判断问题是否已回答还是未回答 # 判断问题是否已回答还是未回答
@exercise_questions = @exercise_questions.includes(:exercise_stand_answers,:exercise_answers,:exercise_shixun_answers) @exercise_questions = @exercise_questions.includes(:exercise_shixun_challenges,
:exercise_shixun_answers,
:exercise_answers,
:exercise_standard_answers)
if @t_user_exercise_status == 3 if @t_user_exercise_status == 3
get_each_student_exercise(@exercise.id,@exercise_questions,@exercise_current_user_id) get_each_student_exercise(@exercise.id,@exercise_questions,@exercise_current_user_id)
@ -1127,14 +1114,14 @@ class ExercisesController < ApplicationController
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
begin begin
# 1 老师权限0 学生权限 # 1 老师权限0 学生权限
@is_teacher_or = @user_course_identity < Course::STUDENT ? 1 : 0 @is_teacher_or = (@user_course_identity < Course::STUDENT) ? 1 : 0
@student_status = 2 @student_status = 2
# @exercise_answerer = User.find_by(id:@exercise_current_user_id) #试卷回答者
@exercise_questions = @exercise.exercise_questions.includes(:exercise_shixun_challenges,:exercise_standard_answers,:exercise_answers,:exercise_shixun_answers).order("question_number ASC") @exercise_questions = @exercise.exercise_questions.includes(:exercise_shixun_challenges,:exercise_standard_answers,:exercise_answers,:exercise_shixun_answers).order("question_number ASC")
@question_status = [] @question_status = []
get_exercise_status = @exercise.get_exercise_status(current_user) get_exercise_status = @exercise.get_exercise_status(current_user) #当前用户的试卷状态
@ex_answer_status = @exercise.get_exercise_status(@ex_user) #当前试卷用户的试卷状态
if @ex_user.present? && @is_teacher_or == 0 if @ex_user.present? && @is_teacher_or == 0
if get_exercise_status == 2 #当前用户已提交,且试卷未截止 if get_exercise_status == Exercise::PUBLISHED #当前用户已提交,且试卷未截止
if @ex_user.commit_status == 0 #学生未提交,且当前为学生 if @ex_user.commit_status == 0 #学生未提交,且当前为学生
@student_status = 0 @student_status = 0
else else
@ -1164,69 +1151,65 @@ class ExercisesController < ApplicationController
@course_all_members = @course.students @course_all_members = @course.students
@c_group_counts = @course.course_groups_count @c_group_counts = @course.course_groups_count
question_types = @exercise.exercise_questions.pluck(:question_type).uniq question_types = @exercise.exercise_questions.pluck(:question_type).uniq
@exercise_publish_count = get_user_permission_course(exercise_ids,2).count #判断是否有已发布的分班 @exercise_publish_count = get_user_permission_course(exercise_ids,Exercise::PUBLISHED).count #判断是否有已发布的分班
@exercise_unpublish_count = get_user_permission_course(exercise_ids,1).count #判断是否有未发布的分班 @exercise_unpublish_count = get_user_permission_course(exercise_ids,Exercise::UNPUBLISHED).count #判断是否有未发布的分班
if (question_types.size > 1) && question_types.include?(4) #是否包含主观题,或者是否大于1 if (question_types.size > 1) && question_types.include?(Exercise::SUBJECTIVE) #是否包含主观题,或者是否大于1
@subjective_type = 1 @subjective_type = 1
else else
@subjective_type = 0 @subjective_type = 0
end end
#初始化值
@exercise_users_list = [] #答题用户列表
@exercise_course_groups = [] #当前用户有权限的班级
@exercise_unanswers = 0 # 未答用户数
@exercise_answers = 0 #已答用户数
@exercise_users_count = 0 #全部用户数
@teacher_review_count = 0 #已评数
@teacher_unreview_count = 0 #未评数
#试卷的答题列表页的显示用户
if @user_course_identity < Course::STUDENT #当前为老师,而且老师只能查看自己班级的/课堂的试卷 if @user_course_identity < Course::STUDENT #当前为老师,而且老师只能查看自己班级的/课堂的试卷
@exercise_current_user_status = 0 @exercise_current_user_status = 0
if @exercise_status == 1 unless @exercise_status == 1
@exercise_users_list = []
@exercise_course_groups = []
@exercise_unanswers = 0
@exercise_answers = 0
else
ex_common_ids = @exercise.common_published_ids(current_user.id) ex_common_ids = @exercise.common_published_ids(current_user.id)
@exercise_course_groups = @course.get_ex_published_course(ex_common_ids) @exercise_course_groups = @course.get_ex_published_course(ex_common_ids)
@exercise_users_list = @exercise.all_exercise_users(current_user.id) #当前老师所在班级的全部学生 @exercise_users_list = @exercise.all_exercise_users(current_user.id) #当前老师所在班级的全部学生
get_exercise_answers(@exercise_users_list, @exercise_status) get_exercise_answers(@exercise_users_list, @exercise_status)
end end
elsif @user_course_identity > Course::ASSISTANT_PROFESSOR #当前为学生或者有过答题的(提交/未提交) else #当前为学生或者有过答题的
@ex_user_end_time = @exercise.get_exercise_end_time(current_user.id) #当前用户所看到的剩余时间 @ex_user_end_time = @exercise.get_exercise_end_time(current_user.id) #当前用户所看到的剩余时间
@exercise_all_users = @exercise.get_stu_exercise_users @exercise_all_users = @exercise.get_stu_exercise_users
get_exercise_answers(@exercise_all_users, @exercise_status) # 未答和已答的 get_exercise_answers(@exercise_all_users, @exercise_status) # 未答和已答的
exercise_current_user = @exercise_all_users.exercise_commit_users(current_user.id) #当前用户是否开始做试卷(提交/未提交/没做) exercise_current_user = @exercise_all_users.exercise_commit_users(current_user.id)
if exercise_current_user.present? if exercise_current_user.exists? #表示为课堂学生或已回答的
@exercise_current_user_status = 1 #当前用户的状态,为学生 @exercise_current_user_status = 1
if @exercise.score_open && @exercise_status == 3 && exercise_current_user.present? #勾选了成绩公开且试卷已截止的 if @exercise.score_open && @exercise_status == 3 #勾选了成绩公开且试卷已截止的
all_user_ids = @exercise_all_users.pluck(:user_id) all_user_ids = @exercise_all_users.pluck(:user_id)
all_user_ids.delete(current_user.id) #删除了当前用户的ID all_user_ids.delete(current_user.id) #删除了当前用户的ID
@exercise_users_list = @exercise_all_users.exercise_commit_users(all_user_ids).distinct @exercise_users_list = @exercise_all_users.exercise_commit_users(all_user_ids).distinct
@current_user_ex_answers = exercise_current_user #当前用户的回答 @current_user_ex_answers = exercise_current_user #当前用户的回答
else else
@exercise_users_list = exercise_current_user.present? ? exercise_current_user.distinct : [] @exercise_users_list = exercise_current_user
end end
else else #表示为未回答的,或未非课堂成员的
@exercise_all_users = @exercise.get_stu_exercise_users
get_exercise_answers(@exercise_all_users, @exercise_status) # 未答和已答的
@exercise_current_user_status = 2 #当前用户非课堂成员 @exercise_current_user_status = 2 #当前用户非课堂成员
@exercise_users_list = []
end end
end end
if @exercise_users_list.present? && @exercise_users_list.count > 0
@exercise_users_count = @exercise_users_list.count #当前显示的全部成员数量
else
@exercise_users_count = 0
end
if @exercise_unanswers < 0 if @exercise_unanswers < 0
@exercise_unanswers = 0 @exercise_unanswers = 0
end end
@teacher_review_count = 0
@teacher_unreview_count = 0
#筛选/分类,排序 #筛选/分类,排序
order = params[:order] order = params[:order]
if @exercise_users_list.present? && @exercise_users_list.size > 0 if @exercise_users_list.exists? && @exercise_users_list.size > 0
@exercise_users_count = @exercise_users_list.size #当前显示的全部成员数量
teacher_reviews = @exercise_users_list.exercise_review teacher_reviews = @exercise_users_list.exercise_review
teacher_unreviews = @exercise_users_list.exercise_unreview teacher_unreviews = @exercise_users_list.exercise_unreview
@teacher_review_count = teacher_reviews.count #已评阅 @teacher_review_count = teacher_reviews.size #已评阅
@teacher_unreview_count = teacher_unreviews.count #未评阅 @teacher_unreview_count = teacher_unreviews.size #未评阅
#是否评阅 #是否评阅
if params[:review].present? if params[:review].present?
@ -1284,7 +1267,7 @@ class ExercisesController < ApplicationController
if params[:format] == "xlsx" if params[:format] == "xlsx"
if @user_course_identity > Course::ASSISTANT_PROFESSOR if @user_course_identity > Course::ASSISTANT_PROFESSOR
tip_exception(403,"无权限操作") tip_exception(403,"无权限操作")
elsif @exercise_status == 1 elsif @exercise_status == Exercise::UNPUBLISHED
normal_status(-1,"试卷未发布") normal_status(-1,"试卷未发布")
elsif (@exercise_users_size == 0) || ( @export_ex_users&.exercise_user_committed.size == 0) elsif (@exercise_users_size == 0) || ( @export_ex_users&.exercise_user_committed.size == 0)
normal_status(-1,"暂无用户提交") normal_status(-1,"暂无用户提交")
@ -1530,30 +1513,22 @@ class ExercisesController < ApplicationController
def get_user_permission_course(exercise_ids,status) def get_user_permission_course(exercise_ids,status)
exercise_status = status.to_i #传入的试卷发布状态 exercise_status = status.to_i #传入的试卷发布状态
unpublish_group = [] unpublish_group = []
# g_course_ids = @course.teacher_course_groups.get_user_groups(current_user.id).pluck(:course_group_id).reject(&:blank?).uniq #当前用户有权限的分班 course_groups = []
# #用户的班级,理论上用户的班级要大于等于试卷设置的班级
# if g_course_ids.blank? || g_course_ids.include?(0)
# user_groups_id = @course.course_groups.pluck(:id)
# else
# user_groups_id = g_course_ids
# end
user_groups_id = @course.charge_group_ids(current_user) user_groups_id = @course.charge_group_ids(current_user)
exercises_all = Exercise.where(id:exercise_ids) exercises_all = Exercise.includes(:exercise_group_settings).where(id:exercise_ids)
exercises_all.each do |exercise| exercises_all.each do |exercise|
if exercise.present? if exercise.present?
if exercise.unified_setting #统一设置只有两种情况,全部发布,全部截止 if exercise.unified_setting #统一设置只有两种情况,全部发布,全部截止
exercise_user_status = exercise.get_exercise_status(current_user) #当前用户的能看到的试卷 exercise_user_status = exercise.get_exercise_status(current_user) #当前用户的能看到的试卷
if (exercise_user_status == exercise_status) || exercise_status == 3 #未发布的情况 if (exercise_user_status == exercise_status) || exercise_status == Exercise::ENDED #未发布的情况
unpublish_group = unpublish_group + user_groups_id unpublish_group = unpublish_group + user_groups_id
else
unpublish_group = []
end end
else else
ex_all_group_settings = exercise.exercise_group_settings ex_all_group_settings = exercise.exercise_group_settings
ex_group_settings = ex_all_group_settings.exercise_group_published.pluck(:course_group_id).uniq #问卷设置的班级 ex_group_settings = ex_all_group_settings.exercise_group_published.pluck(:course_group_id).uniq #问卷设置的班级
if exercise_status == 1 if exercise_status == Exercise::UNPUBLISHED
unpublish_group = user_groups_id - ex_group_settings unpublish_group = user_groups_id - ex_group_settings
elsif exercise_status == 3 elsif exercise_status == Exercise::ENDED
ex_ended_groups = ex_all_group_settings.exercise_group_ended.pluck(:course_group_id).uniq ex_ended_groups = ex_all_group_settings.exercise_group_ended.pluck(:course_group_id).uniq
ex_and_user = user_groups_id & ex_group_settings #用户已设置的分班 ex_and_user = user_groups_id & ex_group_settings #用户已设置的分班
unpublish_group = unpublish_group + ex_and_user - ex_ended_groups #已发布的全部班级减去截止的全部班级 unpublish_group = unpublish_group + ex_and_user - ex_ended_groups #已发布的全部班级减去截止的全部班级
@ -1567,8 +1542,6 @@ class ExercisesController < ApplicationController
unpublish_group = unpublish_group.uniq unpublish_group = unpublish_group.uniq
if unpublish_group.count > 0 if unpublish_group.count > 0
course_groups = CourseGroup.by_group_ids(unpublish_group) course_groups = CourseGroup.by_group_ids(unpublish_group)
else
course_groups = []
end end
course_groups course_groups
end end
@ -1641,7 +1614,7 @@ class ExercisesController < ApplicationController
ex_status = @exercise.get_exercise_status(current_user) ex_status = @exercise.get_exercise_status(current_user)
@ex_user = @exercise.exercise_users.find_by(user_id:@exercise_current_user_id) #该试卷的回答者 @ex_user = @exercise.exercise_users.find_by(user_id:@exercise_current_user_id) #该试卷的回答者
if @user_course_identity > Course::ASSISTANT_PROFESSOR if @user_course_identity > Course::ASSISTANT_PROFESSOR
if ex_status == 1 if ex_status == Exercise::UNPUBLISHED
normal_status(-1,"试卷未发布") normal_status(-1,"试卷未发布")
elsif @ex_user.present? && @ex_user.commit_status == 0 elsif @ex_user.present? && @ex_user.commit_status == 0
normal_status(-1,"试卷未提交") normal_status(-1,"试卷未提交")
@ -1655,7 +1628,7 @@ class ExercisesController < ApplicationController
def check_exercise_public def check_exercise_public
if @user_course_identity > Course::ASSISTANT_PROFESSOR #当前为学生,试卷公开统计,且已截止,且已提交 if @user_course_identity > Course::ASSISTANT_PROFESSOR #当前为学生,试卷公开统计,且已截止,且已提交
ex_user = @exercise.exercise_users.exercise_commit_users(current_user.id).first ex_user = @exercise.exercise_users.exercise_commit_users(current_user.id).first
unless @exercise.get_exercise_status(current_user) == 3 && ex_user.present? && ex_user.commit_status == 1 && unless @exercise.get_exercise_status(current_user) == Exercise::ENDED && ex_user.present? && ex_user.commit_status == 1 &&
@exercise.show_statistic @exercise.show_statistic
normal_status(-1,"学生暂不能查看") normal_status(-1,"学生暂不能查看")
end end
@ -1678,19 +1651,19 @@ class ExercisesController < ApplicationController
ex_question_random = exercise.question_random ex_question_random = exercise.question_random
question_answered = 0 question_answered = 0
exercise_questions.each_with_index do |q,index| exercise_questions.each_with_index do |q,index|
if ex_question_random && exercise_user_status != 3 if ex_question_random && exercise_user_status != Exercise::ENDED
ques_number = index + 1 ques_number = index + 1
else else
ques_number = q.question_number ques_number = q.question_number
end end
if q.question_type != 5 if q.question_type != Exercise::PRACTICAL
ques_vote = q.exercise_answers.search_exercise_answer("user_id",user_id) ques_vote = q.exercise_answers.search_exercise_answer("user_id",user_id)
else else
ques_vote = q.exercise_shixun_answers.search_shixun_answers("user_id",user_id) ques_vote = q.exercise_shixun_answers.search_shixun_answers("user_id",user_id)
end end
ques_status = 0 ques_status = 0
if ques_vote.present? if ques_vote.present?
if q.question_type == 5 if q.question_type == Exercise::PRACTICAL
if ques_vote.pluck(:exercise_shixun_challenge_id).sort == q.exercise_shixun_challenges.pluck(:id).sort #用户的总得分等于问题的分数 if ques_vote.pluck(:exercise_shixun_challenge_id).sort == q.exercise_shixun_challenges.pluck(:id).sort #用户的总得分等于问题的分数
ques_status = 1 #全部回答了,才算已答 ques_status = 1 #全部回答了,才算已答
question_answered += 1 question_answered += 1
@ -1698,12 +1671,12 @@ class ExercisesController < ApplicationController
else #其他题目,需回答的有内容,才会为已答,否则如内容为空,视为未答 else #其他题目,需回答的有内容,才会为已答,否则如内容为空,视为未答
vote_answer_id = ques_vote.pluck(:exercise_choice_id).reject(&:blank?) vote_answer_id = ques_vote.pluck(:exercise_choice_id).reject(&:blank?)
vote_text_count = ques_vote.pluck(:answer_text).reject(&:blank?).size vote_text_count = ques_vote.pluck(:answer_text).reject(&:blank?).size
if q.question_type <= 2 #选择题和判断题的时候,需要有选项,才算回答 if q.question_type <= Exercise::JUDGMENT #选择题和判断题的时候,需要有选项,才算回答
if vote_answer_id.size > 0 if vote_answer_id.size > 0
ques_status = 1 ques_status = 1
question_answered += 1 question_answered += 1
end end
elsif q.question_type == 3 #填空题的时候,需要有选项和内容,才算回答 elsif q.question_type == Exercise::COMPLETION #填空题的时候,需要有选项和内容,才算回答
if vote_answer_id.uniq.sort == q.exercise_standard_answers.pluck(:exercise_choice_id).uniq.sort if vote_answer_id.uniq.sort == q.exercise_standard_answers.pluck(:exercise_choice_id).uniq.sort
ques_status = 1 ques_status = 1
question_answered += 1 question_answered += 1

@ -410,10 +410,8 @@ class HomeworkCommonsController < ApplicationController
homework_detail_group = @homework.homework_detail_group homework_detail_group = @homework.homework_detail_group
param_min = params[:min_num].to_i param_min = params[:min_num].to_i
param_max = params[:max_num].to_i param_max = params[:max_num].to_i
homework_detail_group.min_num = @homework.has_commit_work ? (param_min > homework_detail_group.min_num ? homework_detail_group.min_num : homework_detail_group.min_num = @homework.has_commit_work ? [param_min, homework_detail_group.min_num].min : param_min
param_min) : param_min homework_detail_group.max_num = @homework.has_commit_work ? [param_max, homework_detail_group.max_num].max : param_max
homework_detail_group.max_num = @homework.has_commit_work ? (param_max < homework_detail_group.max_num ? homework_detail_group.max_num :
param_max) : param_max
homework_detail_group.base_on_project = params[:base_on_project] unless @homework.has_relate_project homework_detail_group.base_on_project = params[:base_on_project] unless @homework.has_relate_project
homework_detail_group.save! homework_detail_group.save!
end end

@ -0,0 +1,10 @@
class SearchsController < ApplicationController
def index
@results = SearchService.call(search_params)
end
private
def search_params
params.permit(:keyword, :type, :page, :per_page)
end
end

@ -1,4 +1,7 @@
class ShixunsController < ApplicationController class ShixunsController < ApplicationController
include ShixunsHelper
include ApplicationHelper
before_action :require_login, :check_auth, except: [:download_file, :index, :menus] before_action :require_login, :check_auth, except: [:download_file, :index, :menus]
before_action :check_auth, except: [:download_file, :index, :menus] before_action :check_auth, except: [:download_file, :index, :menus]
@ -14,9 +17,6 @@ class ShixunsController < ApplicationController
before_action :special_allowed, only: [:send_to_course, :search_user_courses] before_action :special_allowed, only: [:send_to_course, :search_user_courses]
include ShixunsHelper
include ApplicationHelper
## 获取课程列表 ## 获取课程列表
def index def index
## 我的实训 ## 我的实训
@ -59,7 +59,7 @@ class ShixunsController < ApplicationController
end end
## 筛选 难度 ## 筛选 难度
if params[:diff].present? && params[:diff].to_i != 0 if params[:diff].present? && params[:diff].to_i != 0
@shixuns = @shixuns.where(trainee: params[:diff]) @shixuns = @shixuns.where(trainee: params[:diff])
end end
@ -84,6 +84,12 @@ class ShixunsController < ApplicationController
limit = params[:limit] || 16 limit = params[:limit] || 16
@shixuns = @shixuns.includes(:tag_repertoires, :challenges).page(page).per(limit) @shixuns = @shixuns.includes(:tag_repertoires, :challenges).page(page).per(limit)
@tag_name_map = TagRepertoire.joins(:shixun_tag_repertoires)
.where(shixun_tag_repertoires: { shixun_id: @shixuns.map(&:id) })
.group('shixun_tag_repertoires.shixun_id')
.select('shixun_id, tag_repertoires.name')
.each_with_object({}) { |r, obj| obj[r.shixun_id] = r.name }
end end
## 获取顶部菜单 ## 获取顶部菜单

@ -4,7 +4,7 @@ module ExercisesHelper
#获取每个学生对每个题的答案状态 #获取每个学生对每个题的答案状态
def get_each_student_exercise(exercise_id,exercise_questions,user_id) def get_each_student_exercise(exercise_id,exercise_questions,user_id)
@exercise_user = ExerciseUser.current_exercise_user(user_id,exercise_id).first @exercise_user = ExerciseUser.current_exercise_user(user_id,exercise_id)&.first
exercise_obj_status = exercise_questions.find_objective_questions exercise_obj_status = exercise_questions.find_objective_questions
@ex_obj_array = [] @ex_obj_array = []
exercise_obj_status.each do |q| exercise_obj_status.each do |q|
@ -259,10 +259,9 @@ module ExercisesHelper
#获取试卷的已答/未答人数 #获取试卷的已答/未答人数
def get_exercise_answers(ex_users, status) def get_exercise_answers(ex_users, status)
if status == 1 @exercise_answers = 0
@exercise_answers = 0 @exercise_unanswers = 0
@exercise_unanswers = 0 unless status == Exercise::UNPUBLISHED
else
@exercise_answers = ex_users.commit_exercise_by_status(1).size #表示已经提交了的用户 @exercise_answers = ex_users.commit_exercise_by_status(1).size #表示已经提交了的用户
course_all_members_count = ex_users.size course_all_members_count = ex_users.size
@exercise_unanswers = (course_all_members_count - @exercise_answers) @exercise_unanswers = (course_all_members_count - @exercise_answers)

@ -33,4 +33,12 @@ module Util
Rails.logger.error(exception.message) Rails.logger.error(exception.message)
exception.backtrace.each { |message| Rails.logger.error(message) } exception.backtrace.each { |message| Rails.logger.error(message) }
end end
def map_or_pluck(relation, name)
relation.is_a?(Array) || relation.loaded? ? relation.map(&name.to_sym) : relation.pluck(name)
end
def extract_content(str)
str.gsub(/<\/?.*?>/, '').gsub(/[\n\t\r]/, '').gsub(/&nbsp;/, '')
end
end end

@ -116,5 +116,4 @@ class Challenge < ApplicationRecord
end end
# 关卡评测文件 # 关卡评测文件
end end

@ -1,4 +1,6 @@
class ChallengeTag < ApplicationRecord class ChallengeTag < ApplicationRecord
# TODO: ES feature
# include Searchable::Dependents::ChallengeTag
belongs_to :challenge, counter_cache: true belongs_to :challenge, counter_cache: true
belongs_to :challenge_choose, optional: true belongs_to :challenge_choose, optional: true

@ -1,4 +1,7 @@
class Course < ApplicationRecord class Course < ApplicationRecord
# TODO: ES feature
# include Searchable::Course
has_many :boards, dependent: :destroy has_many :boards, dependent: :destroy
belongs_to :teacher, class_name: 'User', foreign_key: :tea_id # 定义一个方法teacher该方法通过tea_id来调用User表 belongs_to :teacher, class_name: 'User', foreign_key: :tea_id # 定义一个方法teacher该方法通过tea_id来调用User表
@ -22,6 +25,8 @@ class Course < ApplicationRecord
has_many :graduation_groups, dependent: :destroy has_many :graduation_groups, dependent: :destroy
has_many :course_members, dependent: :destroy has_many :course_members, dependent: :destroy
has_many :teacher_course_members, -> { teachers_and_admin }, class_name: 'CourseMember'
has_many :teacher_users, through: :teacher_course_members, source: :user
has_many :course_messages, dependent: :destroy has_many :course_messages, dependent: :destroy
has_many :homework_commons, dependent: :destroy has_many :homework_commons, dependent: :destroy
has_many :homework_group_settings has_many :homework_group_settings

@ -23,6 +23,21 @@ class Exercise < ApplicationRecord
after_create :create_exercise_list after_create :create_exercise_list
# 试卷的问题类型
SINGLE = 0 #单选题
MULTIPLE = 1 #多选题
JUDGMENT = 2 #判断题
COMPLETION = 3 # 填空题
SUBJECTIVE = 4 # 主观题
PRACTICAL = 5 #实训题
# 试卷的状态
UNPUBLISHED = 1 #未发布
PUBLISHED = 2 #已发布
DEADLINE = 3 #已截止
ENDED = 4 #课堂已结束
def create_exercise_list def create_exercise_list
str = "" str = ""
# TODO: 一次性为所有学生创建数据是否存在问题? # TODO: 一次性为所有学生创建数据是否存在问题?
@ -93,8 +108,6 @@ class Exercise < ApplicationRecord
def common_published_ids(user_id) def common_published_ids(user_id)
current_user_groups = course.teacher_course_ids(user_id) current_user_groups = course.teacher_course_ids(user_id)
if unified_setting if unified_setting
# un_group_ids = (course.none_group_count > 0) ? [0] : []
# published_group_ids = (current_user_groups + un_group_ids).uniq #统一设置时为当前用户的分班id及未分班
published_group_ids = current_user_groups published_group_ids = current_user_groups
else else
ex_group_setting = exercise_group_settings.select(:course_group_id).pluck("course_group_id").uniq ex_group_setting = exercise_group_settings.select(:course_group_id).pluck("course_group_id").uniq
@ -118,13 +131,12 @@ class Exercise < ApplicationRecord
ex_time = get_exercise_times(user_id,false) ex_time = get_exercise_times(user_id,false)
pb_time = ex_time[:publish_time] pb_time = ex_time[:publish_time]
ed_time = ex_time[:end_time] ed_time = ex_time[:end_time]
if pb_time.present? && ed_time.present? && pb_time <= Time.now && ed_time > Time.now if pb_time.present? && ed_time.present? && pb_time <= Time.now && ed_time > Time.now
status = 2 status = Exercise::PUBLISHED
elsif ed_time.present? && ed_time <= Time.now elsif ed_time.present? && ed_time <= Time.now
status = 3 status = Exercise::ENDED
else else
status = 1 status = Exercise::UNPUBLISHED
end end
else else
status = exercise_status #当为老师的时候,则为试卷的总状态 status = exercise_status #当为老师的时候,则为试卷的总状态

@ -1,4 +1,6 @@
class Memo < ApplicationRecord class Memo < ApplicationRecord
# TODO: ES feature
# include Searchable::Memo
has_many :memo_tag_repertoires, :dependent => :destroy has_many :memo_tag_repertoires, :dependent => :destroy
has_many :tag_repertoires, :through => :memo_tag_repertoires has_many :tag_repertoires, :through => :memo_tag_repertoires
@ -9,6 +11,9 @@ class Memo < ApplicationRecord
belongs_to :author, class_name: 'User', foreign_key: 'author_id' belongs_to :author, class_name: 'User', foreign_key: 'author_id'
belongs_to :parent, class_name: 'Memo', foreign_key: 'parent_id' belongs_to :parent, class_name: 'Memo', foreign_key: 'parent_id'
has_many :descendants, foreign_key: :root_id, class_name: 'Memo'
has_many :children, foreign_key: :parent_id, class_name: 'Memo'
scope :field_for_list, lambda{ scope :field_for_list, lambda{
select([:id, :subject, :author_id, :sticky, :updated_at, :language, :reward, :all_replies_count, :viewed_count, :forum_id]) select([:id, :subject, :author_id, :sticky, :updated_at, :language, :reward, :all_replies_count, :viewed_count, :forum_id])
} }

@ -0,0 +1,3 @@
module Searchable
MAXIMUM_LENGTH = 10922 # 最大字节数为32766 一个汉字3个字节
end

@ -0,0 +1,37 @@
module Searchable::Course
extend ActiveSupport::Concern
included do
searchkick language: 'chinese', callbacks: :async
scope :search_import, -> { includes(:teacher_users, teacher: { user_extension: :school } ) }
end
def searchable_title
name
end
def search_data
{
name: name,
author_name: teacher&.real_name
}
end
def to_searchable_json
{
id: id,
author_name: teacher.real_name,
author_school_name: teacher.school_name,
visits_count: visits,
members_count: members_count,
is_public: is_public == 1
}
end
module ClassMethods
def searchable_includes
{ teacher: { user_extension: :school } }
end
end
end

@ -0,0 +1,2 @@
module Searchable::Dependents
end

@ -0,0 +1,16 @@
module Searchable::Dependents::ChallengeTag
extend ActiveSupport::Concern
included do
after_create_commit :check_searchable_dependents
after_update_commit :check_searchable_dependents
end
private
def check_searchable_dependents
if new_record? || name_previously_changed?
challenge.shixun.reindex(:searchable_challenge_data)
end
end
end

@ -0,0 +1,15 @@
module Searchable::Dependents::Stage
extend ActiveSupport::Concern
included do
after_update_commit :check_searchable_dependents
end
private
def check_searchable_dependents
if name_previously_changed? || description_previously_changed?
subject.reindex(:searchable_stages_data)
end
end
end

@ -0,0 +1,22 @@
module Searchable::Dependents::User
extend ActiveSupport::Concern
included do
after_update_commit :check_searchable_dependents
end
private
def check_searchable_dependents
if firstname_previously_changed? || lastname_previously_changed? || user_extension.school_id_previously_changed?
# reindex shixun
created_shixuns.each{ |shixun| shixun.reindex(:searchable_user_data) }
# reindex course
manage_courses.each(&:reindex)
# reindex subject
created_subjects.each { |subject| subject.reindex(:searchable_user_data) }
end
end
end

@ -0,0 +1,46 @@
module Searchable::Memo
extend ActiveSupport::Concern
included do
searchkick language: 'chinese', callbacks: :async
scope :search_import, -> { includes(:descendants) }
end
def searchable_title
subject
end
def should_index?
hidden.zero? && root_id.blank? && parent_id.blank?
end
def search_data
{
name: subject,
content: Util.extract_content(content)[0..Searchable::MAXIMUM_LENGTH],
}.merge!(searchable_descendants_data)
end
def searchable_descendants_data
{
descendants_contents: Util.map_or_pluck(descendants, :content)
.map { |content| Util.extract_content(content)[0..Searchable::MAXIMUM_LENGTH] }
}
end
def to_searchable_json
{
id: id,
author_name: author.full_name,
visits_count: viewed_count,
all_replies_count: all_replies_count
}
end
module ClassMethods
def searchable_includes
[:author]
end
end
end

@ -0,0 +1,58 @@
module Searchable::Shixun
extend ActiveSupport::Concern
included do
searchkick language: 'chinese'#, callbacks: :async
scope :search_import, -> { includes(:shixun_info, :challenges, :challenge_tags, :users, user: { user_extension: :school }) }
end
def searchable_title
name
end
def search_data
{
name: name,
description: Util.extract_content(description)[0..Searchable::MAXIMUM_LENGTH]
}.merge!(searchable_user_data)
.merge!(searchable_challenge_data)
end
def searchable_user_data
{
author_name: user.real_name,
author_school_name: user.school_name,
}
end
def searchable_challenge_data
challenge_names = Util.map_or_pluck(challenges, :subject)
.each_with_index.map { |subject, index| "#{index + 1}#{subject}" }
{
challenge_names: challenge_names,
challenge_tag_names: Util.map_or_pluck(challenge_tags, :name).uniq.join(' ')
}
end
def should_index?
status == 2 # published
end
def to_searchable_json
{
id: id,
author_name: user.real_name,
author_school_name: user.school_name,
visits_count: visits,
challenges_count: challenges_count
}
end
module ClassMethods
def searchable_includes
{ user: { user_extension: :school } }
end
end
end

@ -0,0 +1,61 @@
module Searchable::Subject
extend ActiveSupport::Concern
included do
searchkick language: 'chinese', callbacks: :async
scope :search_import, -> { includes(:users, :stages, user: { user_extension: :school }) }
end
def searchable_title
name
end
def should_index?
!hidden? && status == 2 # published
end
def search_data
{
name: name,
description: Util.extract_content(description)[0..Searchable::MAXIMUM_LENGTH]
}.merge!(searchable_user_data)
.merge!(searchable_stages_data)
end
def searchable_user_data
{
author_name: user.real_name,
author_school_name: user.school_name,
}
end
def searchable_stages_data
subject_stages =
stages.map do |stage|
{
name: stage.name,
description: Util.extract_content(stage.description)[0..Searchable::MAXIMUM_LENGTH]
}
end
{ subject_stages: subject_stages}
end
def to_searchable_json
{
id: id,
author_name: user.real_name,
author_school_name: user.school_name,
visits_count: visits,
stage_count: stages_count,
stage_shixuns_count: stage_shixuns_count
}
end
module ClassMethods
def searchable_includes
{ user: { user_extension: :school } }
end
end
end

@ -1,8 +1,12 @@
class Shixun < ApplicationRecord class Shixun < ApplicationRecord
# TODO: ES feature
# include Searchable::Shixun
# status: 0编辑 1申请发布 2正式发布 3关闭 -1软删除 # status: 0编辑 1申请发布 2正式发布 3关闭 -1软删除
# hide_code 隐藏代码窗口 # hide_code 隐藏代码窗口
# code_hidden: 隐藏代码目录 # code_hidden: 隐藏代码目录
has_many :challenges, dependent: :destroy has_many :challenges, dependent: :destroy
has_many :challenge_tags, through: :challenges
has_many :myshixuns, :dependent => :destroy has_many :myshixuns, :dependent => :destroy
has_many :shixun_members, dependent: :destroy has_many :shixun_members, dependent: :destroy
has_many :users, through: :shixun_members has_many :users, through: :shixun_members
@ -35,7 +39,6 @@ class Shixun < ApplicationRecord
# 实训服务配置 # 实训服务配置
has_many :shixun_service_configs, :dependent => :destroy has_many :shixun_service_configs, :dependent => :destroy
scope :search_by_name, ->(keyword) { where("name like ? or description like ? ", scope :search_by_name, ->(keyword) { where("name like ? or description like ? ",
"%#{keyword}%", "%#{keyword}%") } "%#{keyword}%", "%#{keyword}%") }

@ -1,4 +1,7 @@
class Stage < ApplicationRecord class Stage < ApplicationRecord
# TODO: ES feature
# include Searchable::Dependents::Stage
belongs_to :subject, counter_cache: true belongs_to :subject, counter_cache: true
has_many :stage_shixuns, -> { order("stage_shixuns.position ASC") }, dependent: :destroy has_many :stage_shixuns, -> { order("stage_shixuns.position ASC") }, dependent: :destroy

@ -2,6 +2,9 @@
# 可以在初始创建的时候 # 可以在初始创建的时候
class Subject < ApplicationRecord class Subject < ApplicationRecord
# TODO: ES feature
# include Searchable::Subject
#status :0 编辑中 1 审核中 2 发布 #status :0 编辑中 1 审核中 2 发布
belongs_to :repertoire belongs_to :repertoire
belongs_to :user belongs_to :user

@ -1,5 +1,8 @@
class User < ApplicationRecord class User < ApplicationRecord
include Watchable include Watchable
# TODO: ES feature
# include Searchable::Dependents::User
# Account statuses # Account statuses
STATUS_ANONYMOUS = 0 STATUS_ANONYMOUS = 0
STATUS_ACTIVE = 1 STATUS_ACTIVE = 1
@ -28,6 +31,7 @@ class User < ApplicationRecord
accepts_nested_attributes_for :user_extension, update_only: true accepts_nested_attributes_for :user_extension, update_only: true
has_many :memos, foreign_key: 'author_id' has_many :memos, foreign_key: 'author_id'
has_many :created_shixuns, class_name: 'Shixun'
has_many :shixun_members, :dependent => :destroy has_many :shixun_members, :dependent => :destroy
has_many :shixuns, :through => :shixun_members has_many :shixuns, :through => :shixun_members
has_many :myshixuns, :dependent => :destroy has_many :myshixuns, :dependent => :destroy
@ -55,6 +59,7 @@ class User < ApplicationRecord
has_many :tidings, :dependent => :destroy has_many :tidings, :dependent => :destroy
has_many :games, :dependent => :destroy has_many :games, :dependent => :destroy
has_many :created_subjects
has_many :subjects, :through => :subject_members has_many :subjects, :through => :subject_members
has_many :subject_members, :dependent => :destroy has_many :subject_members, :dependent => :destroy
has_many :grades, :dependent => :destroy has_many :grades, :dependent => :destroy

@ -2,7 +2,7 @@ class UserExtension < ApplicationRecord
# identity 0: 教师教授 1: 学生, 2: 专业人士, 3: 开发者 # identity 0: 教师教授 1: 学生, 2: 专业人士, 3: 开发者
enum identity: { teacher: 0, student: 1, professional: 2, developer: 3 } enum identity: { teacher: 0, student: 1, professional: 2, developer: 3 }
belongs_to :user belongs_to :user, touch: true
belongs_to :school belongs_to :school
belongs_to :department, optional: true belongs_to :department, optional: true

@ -0,0 +1,41 @@
module ElasticsearchAble
extend ActiveSupport::Concern
private
def default_options
{
debug: Rails.env.development?,
highlight: highlight_options,
body_options: body_options,
page: page,
per_page: per_page
}
end
def keyword
params[:keyword].to_s.strip.presence || '*'
end
def highlight_options
{
fragment_size: EduSetting.get('es_highlight_fragment_size') || 30,
tag: '<span>'
}
end
def body_options
{
min_score: EduSetting.get('es_min_score') || 10
}
end
def per_page
per_page = params[:per_page].to_s.strip.presence || params[:limit].to_s.strip.presence
per_page.to_i <= 0 ? 20 : per_page.to_i
end
def page
params[:page].to_i <= 0 ? 1 : params[:page].to_i
end
end

@ -0,0 +1,39 @@
class SearchService < ApplicationService
include ElasticsearchAble
attr_reader :params
def initialize(params)
@params = params
end
def call
Searchkick.search(keyword, search_options)
end
private
def search_options
{
index_name: index_names,
model_includes: model_includes
}.merge(default_options)
end
def index_names
@_index_names ||=
case params[:type].to_s.strip
when 'shixun' then [Shixun]
when 'course' then [Course]
when 'subject' then [Subject]
when 'memo' then [Memo]
else [Shixun, Course, Subject, Memo]
end
end
def model_includes
index_names.each_with_object({}) do |klass, obj|
obj[klass] = klass.searchable_includes
end
end
end

@ -0,0 +1,96 @@
class SearchShixunService < ApplicationService
include ElasticsearchAble
attr_reader :user, :params
def initialize(user, params)
@user = user
@params = params
end
def call
Shixun.search(keyword,
fields: search_fields,
where: where_clauses,
order: order_clauses,
includes: includes_clauses,
page: page,
per_page: per_page)
end
private
def tag_filter_shixun_ids
return [] if params[:tag_level].to_i == 0 || params[:tag_id].blank?
case params[:tag_level].to_i
when 1 then
Repertoire.find(params[:tag_id]).tag_repertoires.joins(:shixun_tag_repertoires)
.pluck('shixun_tag_repertoires.shixun_id')
when 2 then
SubRepertoire.find(params[:tag_id]).tag_repertoires.joins(:shixun_tag_repertoires)
.pluck('shixun_tag_repertoires.shixun_id')
when 3 then
TagRepertoire.find(params[:tag_id]).shixun_tag_repertoires.pluck(:shixun_id)
else
[]
end
end
def user_filter_shixun_ids
return [] if params[:order_by] != 'mine'
user.shixun_members.pluck(:shixun_id) + user.myshixuns.pluck(:shixun_id)
end
def keyword
params[:keyword].to_s.strip.presence || '*'
end
def search_fields
%w(name^10 author_name challenge_names description challenge_tag_names)
end
def where_clauses
hash = {}
ids = user_filter_shixun_ids + tag_filter_shixun_ids
hash[:id] = ids if ids.present?
if params[:order_by] == 'mine'
hash[:status] = { not: -1 }
else
hash.merge!(hidden: false, status: 2)
end
unless params[:status].to_i.zero?
params[:status] = [0, 1] if params[:status].to_i == 1
hash[:status] = params[:status]
end
hash[:trainee] = params[:diff].to_i unless params[:diff].to_i.zero?
hash
end
def includes_clauses
[]
end
def order_clauses
hash = { _score: :desc }
publish_order = { type: 'number', order: :desc, script: 'doc["status"].value=="2" ? 1 : 0' }
sort = params[:sort].to_s.strip == 'asc' ? 'asc' : 'desc'
clauses =
case params[:order_by].presence
when 'new' then { _script: publish_order, created_at: sort }
when 'hot' then { _script: publish_order, myshixuns_count: sort }
when 'mine' then { created_at: sort }
else { _script: publish_order, publish_time: sort }
end
hash.merge!(clauses)
hash
end
end

@ -36,10 +36,10 @@ elsif student_status == 1
json.question_status question_status json.question_status question_status
end end
exercise_status = exercise.get_exercise_status(ex_answerer) # exercise_status = exercise.get_exercise_status(ex_answerer)
#当前为老师,或为学生,但在试卷截止后且答案选择公开的 #当前为老师,或为学生,但在试卷截止后且答案选择公开的
if is_teacher_or == 1 || (exercise_status == 3 && exercise.answer_open) if is_teacher_or == 1 || (ex_answer_status == Exercise::ENDED && exercise.answer_open)
ex_type = 4 ex_type = 4
else else
ex_type = 3 ex_type = 3
@ -47,7 +47,7 @@ end
json.exercise_questions do json.exercise_questions do
json.array! exercise_questions do |q| json.array! exercise_questions do |q|
user_ques_answers = user_question_answers(q,ex_answerer.id,student_status,is_teacher_or,exercise_status,q.question_type,ex_type) user_ques_answers = user_question_answers(q,ex_answerer.id,student_status,is_teacher_or,ex_answer_status,q.question_type,ex_type)
user_ques_comments = user_ques_answers[:question_comment] user_ques_comments = user_ques_answers[:question_comment]
if all_question_status.size > 0 if all_question_status.size > 0
this_ques_status = all_question_status.detect {|f| f[:q_id] == q.id} this_ques_status = all_question_status.detect {|f| f[:q_id] == q.id}

@ -8,5 +8,6 @@ json.partial! "exercises/user_exercise_info",locals:{exercise:@exercise,
ex_sub_array:@ex_sub_array, ex_sub_array:@ex_sub_array,
exercise_questions:@exercise_questions, exercise_questions:@exercise_questions,
student_status:@student_status, student_status:@student_status,
question_status:@question_status question_status:@question_status,
ex_answer_status:@ex_answer_status
} }

@ -1,18 +0,0 @@
json.total_counts @total_exercise_counts
json.total_user_exercises do
json.array! @all_exercise_stu_array do |a|
json.student_exercise do
json.partial! "exercises/user_exercise_info",locals:{exercise:@exercise,
is_teacher_or:a[:is_teacher],
ex_answerer:a[:ex_answerer],
exercise_user:a[:ex_user],
ex_obj_array:a[:ex_obj_array],
ex_sub_array:a[:ex_sub_array],
exercise_questions:@exercise_questions,
student_status:@student_status,
question_status:@question_status
}
end
end
end

@ -0,0 +1,10 @@
json.count @results.total_count
json.results do
json.array! @results.with_highlights(multiple: true) do |obj, highlights|
json.merge! obj.to_searchable_json
json.type obj.class.name.downcase
json.title highlights.delete(:name)&.join('...') || obj.searchable_title
json.description highlights.values[0,5].each { |arr| arr.is_a?(Array) ? arr.join('...') : arr }.join('<br/>')
end
end

@ -15,7 +15,7 @@ json.array! shixuns do |shixun|
json.status shixun.status json.status shixun.status
json.power (current_user.shixun_permission(shixun)) # 现在首页只显示已发布的实训 json.power (current_user.shixun_permission(shixun)) # 现在首页只显示已发布的实训
# REDO: 局部缓存 # REDO: 局部缓存
json.tag_name shixun.tag_repertoires.first.try(:name) json.tag_name @tag_name_map&.fetch(shixun.id) || shixun.tag_repertoires.first.try(:name)
json.myshixuns_count shixun.myshixuns_count json.myshixuns_count shixun.myshixuns_count
json.stu_num shixun.myshixuns_count json.stu_num shixun.myshixuns_count
json.score_info shixun.averge_star json.score_info shixun.averge_star

@ -28,7 +28,7 @@
<div style="width: 598px; background:#fff; margin:20px auto; font-size:14px; "> <div style="width: 598px; background:#fff; margin:20px auto; font-size:14px; ">
<div style="height:50px; width: 578px; background:#46484c; padding:9px 10px 6px;border:1px solid #ddd; border-bottom:none;"> <div style="height:50px; width: 578px; background:#46484c; padding:9px 10px 6px;border:1px solid #ddd; border-bottom:none;">
<a href="https://www.educoder.net"> <a href="https://www.educoder.net">
<img src="/images/educoder/headNavLogo.png" width="36" style="float:left; margin-top: 8px;" > <img src="https://www.educoder.net/images/educoder/headNavLogo.png" width="36" style="float:left; margin-top: 8px;" >
</a> </a>
<div style="clear:both; overflow:hidden;"></div> <div style="clear:both; overflow:hidden;"></div>
</div> </div>

@ -9,6 +9,8 @@ Rails.application.routes.draw do
get 'home/index' get 'home/index'
get 'home/search' get 'home/search'
get 'search', to: 'searchs#index'
post 'praise_tread/like', to: 'praise_tread#like' post 'praise_tread/like', to: 'praise_tread#like'
delete 'praise_tread/unlike', to: 'praise_tread#unlike' delete 'praise_tread/unlike', to: 'praise_tread#unlike'

Loading…
Cancel
Save