Merge branches 'dev_aliyun' and 'topic_bank' of https://bdgit.educoder.net/Hjqreturn/educoder into topic_bank

dev_aliyun_beta
杨树明 6 years ago
commit 3a445e8159

@ -0,0 +1,2 @@
// Place all the behaviors and hooks related to the matching controller here.
// All this logic will automatically be available in application.js.

@ -0,0 +1,3 @@
// Place all the styles related to the homework_banks controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

@ -426,9 +426,9 @@ class ApplicationController < ActionController::Base
# 小类别列表
def shixun_small_type
list = []
mirrors = MirrorRepository.select([:id, :type_name]).published_small_mirror
mirrors = MirrorRepository.select([:id, :type_name, :description]).published_small_mirror
mirrors.try(:each) do |mirror|
list << {id: mirror.id, type_name: mirror.type_name}
list << {id: mirror.id, type_name: mirror.type_name, description: mirror.description}
end
list
end

@ -26,17 +26,19 @@ class CoursesController < ApplicationController
:base_info, :get_historical_courses, :create_group_by_importing_file,
:attahcment_category_list,:export_member_scores_excel, :duplicate_course,
:switch_to_teacher, :switch_to_assistant, :switch_to_student, :exit_course,
:informs, :update_informs, :new_informs, :online_learning, :update_task_position, :tasks_list, :join_excellent_course]
:informs, :update_informs, :online_learning, :update_task_position, :tasks_list,
:join_excellent_course, :export_couser_info, :export_member_act_score]
before_action :user_course_identity, except: [:join_excellent_course, :index, :create, :new, :apply_to_join_course,
:search_course_list, :get_historical_course_students, :mine, :search_slim, :board_list]
before_action :teacher_allowed, only: [:update, :destroy, :settings, :search_teacher_candidate,
:transfer_to_course_group, :delete_from_course,
:search_users, :add_students_by_search, :get_historical_courses, :add_teacher_popup, :add_teacher]
:transfer_to_course_group, :delete_from_course, :export_member_scores_excel,
:search_users, :add_students_by_search, :get_historical_courses, :add_teacher_popup,
:add_teacher, :export_couser_info, :export_member_act_score]
before_action :admin_allowed, only: [:set_invite_code_halt, :set_public_or_private, :change_course_admin,
:set_course_group, :create_group_by_importing_file, :update_informs, :new_informs,
:update_task_position, :tasks_list]
before_action :teacher_or_admin_allowed, only: [:graduation_group_list, :create_graduation_group, :join_graduation_group,
:change_course_teacher, :export_member_scores_excel, :course_group_list,
:change_course_teacher, :course_group_list,
:teacher_application_review, :apply_teachers, :delete_course_teacher]
before_action :validate_course_name, only: [:create, :update]
before_action :find_board, only: :board_list
@ -1081,44 +1083,64 @@ class CoursesController < ApplicationController
@courses= @courses.page(@page).per(@page_size)
end
# 导出课堂信息
def export_couser_info
set_export_cookies
course_info_to_xlsx @course
filename_ = "#{current_user.real_name}_#{@course.name}_课堂信息_#{Time.now.strftime('%Y%m%d_%H%M%S')}"
render xlsx: "#{format_sheet_name filename_.strip}",template: "courses/export_course_info.xlsx.axlsx",
locals: {course_info: @course_info}
end
# 导出活跃度
def export_member_act_score
search = params[:search] ? "#{params[:search].strip}" : "" #用户名或学生学号id搜索
group_id = params[:group_id] #分班的班级id
@all_members = student_act_score group_id, search
if @all_members.size == 0
normal_status(-1,"课堂暂时没有学生")
elsif params[:export].present? && params[:export]
normal_status(0,"正在下载中")
else
set_export_cookies
act_score_to_xlsx(@all_members)
filename_ = "#{current_user.real_name}_#{@course.name}_活跃度_#{Time.now.strftime('%Y%m%d_%H%M%S')}"
render xlsx: "#{format_sheet_name filename_.strip}",template: "courses/export_member_act_score.xlsx.axlsx",
locals: {activity_level:@user_activity_level}
end
end
# 导出学生成绩
def export_member_scores_excel
ActiveRecord::Base.transaction do
begin
@all_members = @course.students
search = params[:search] ? "#{params[:search].strip}" : "" #用户名或学生学号id搜索
group_id = params[:group_id] #分班的班级id
# if group_id && group_id != "0" && group_id != "-1"
# @all_members = @course.students.course_find_by_ids("course_group_id",group_id)
# elsif group_id && group_id == "0" # 未分班
# @all_members = @course.course_members.ungroup_students
# else
# @all_members = @course.students
# end
# if name.present?
# @all_members = @all_members.joins(user: [:user_extension]).where('concat(users.lastname, users.firstname) like ? or user_extensions.student_id like ?',"%#{name}%","%#{name}%")
# end
@all_members = student_act_score group_id, search
@all_members = @all_members.where(course_group_id: group_id) unless group_id.blank?
unless search.blank?
@all_members = @all_members.joins(user: [:user_extension]).where('concat(users.lastname, users.firstname) like ? or user_extensions.student_id like ?',"%#{search}%","%#{search}%")
end
@c_homeworks = @course.homework_commons.homework_published.order("homework_commons.publish_time asc, homework_commons.created_at asc")
@c_exercises = @course.exercises.is_exercise_published.order("exercises.publish_time asc, exercises.created_at asc")
# @c_polls = @course.polls.publish_or_not.order("polls.publish_time asc, polls.created_at asc")
@c_tasks = @course.graduation_tasks.task_published.order("graduation_tasks.publish_time asc, graduation_tasks.created_at asc")
if @user_course_identity > Course::ASSISTANT_PROFESSOR
tip_exception(403,"无权限操作")
elsif @all_members.size == 0
if @all_members.length == 0
normal_status(-1,"课堂暂时没有学生")
elsif params[:export].present? && params[:export]
normal_status(0,"正在下载中")
normal_status(0,"正在下载中")
else
@c_homeworks = @course.homework_commons.homework_published.order("homework_commons.publish_time asc, homework_commons.created_at asc")
@c_exercises = @course.exercises.is_exercise_published.order("exercises.publish_time asc, exercises.created_at asc")
# @c_polls = @course.polls.publish_or_not.order("polls.publish_time asc, polls.created_at asc")
@c_tasks = @course.graduation_tasks.task_published.order("graduation_tasks.publish_time asc, graduation_tasks.created_at asc")
set_export_cookies
member_to_xlsx(@course, @all_members, @c_homeworks, @c_exercises, @c_tasks)
filename_ = "#{current_user.real_name}_#{@course.name}_全部成绩_#{Time.now.strftime('%Y%m%d_%H%M%S')}"
filename_ = "#{current_user.real_name}_#{@course.name}_成绩_#{Time.now.strftime('%Y%m%d_%H%M%S')}"
render xlsx: "#{format_sheet_name filename_.strip}",template: "courses/export_member_scores_excel.xlsx.axlsx",
locals: {course_info:@course_info, activity_level:@user_activity_level,
course_scores:@course_user_scores,shixun_works:@shixun_work_arrays,
locals: {course_scores:@course_user_scores,shixun_works:@shixun_work_arrays,
common_works:@common_work_arrays,group_works:@group_work_arrays,task_works:@task_work_arrays,
exercise_works:@exercise_work_arrays}
end
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
@ -1291,13 +1313,7 @@ class CoursesController < ApplicationController
# end
def student_act_score group_id, search
sql_select = %Q{SELECT cm.*,(
SELECT SUM(student_works.work_score)
FROM student_works,homework_commons
WHERE student_works.homework_common_id = homework_commons.id
AND homework_commons.course_id = #{@course.id}
AND student_works.user_id = cm.user_id
) AS score,
sql_select = %Q{SELECT cm.*,
(SELECT max(student_id) FROM user_extensions WHERE user_extensions.user_id = cm.user_id) AS student_id,
(SELECT count(messages.id) FROM messages join boards on messages.board_id = boards.id WHERE boards.course_id = #{@course.id}
AND messages.author_id = cm.user_id and messages.parent_id is null) AS message_num,
@ -1318,52 +1334,25 @@ class CoursesController < ApplicationController
FROM course_members cm}
if search.present? && group_id.present?
sql_select += %Q{ join users on cm.user_id = users.id
joins user_extensions ue on ue.user_id = users.id
join user_extensions ue on ue.user_id = users.id
WHERE cm.role = 4 and cm.course_id = #{@course.id} and cm.course_group_id = #{group_id} and
(concat(users.lastname, users.firstname) like '%#{search}%' or ue.student_id like '%#{search}%') ORDER BY score desc}
(concat(users.lastname, users.firstname) like '%#{search}%' or ue.student_id like '%#{search}%')}
elsif search.present?
sql_select += %Q{ join users on cm.user_id = users.id
joins user_extensions ue on ue.user_id = users.id
join user_extensions ue on ue.user_id = users.id
WHERE cm.role = 4 and
(concat(users.lastname, users.firstname) like '%#{search}%' or ue.student_id like '%#{search}%') ORDER BY score desc}
(concat(users.lastname, users.firstname) like '%#{search}%' or ue.student_id like '%#{search}%')}
elsif group_id.present?
sql_select += %Q{ WHERE cm.role = 4 and cm.course_id = #{@course.id} and cm.course_group_id = #{group_id} ORDER BY score desc}
sql_select += %Q{ WHERE cm.role = 4 and cm.course_id = #{@course.id} and cm.course_group_id = #{group_id}}
else
sql_select += %Q{ WHERE cm.role = 4 and cm.course_id = #{@course.id} ORDER BY score desc}
sql_select += %Q{ WHERE cm.role = 4 and cm.course_id = #{@course.id}}
end
act_scores = CourseMember.find_by_sql(sql_select)
act_scores
end
def member_to_xlsx(course,all_members,homeworks,exercises,tasks)
#课堂的作业信息
shixun_homeworks = homeworks.search_homework_type(4) #全部实训作业
shixun_titles = shixun_homeworks.pluck(:name) + ["总得分"]
# 更新实训作业成绩
shixun_homeworks.includes(:homework_challenge_settings, :published_settings, :homework_commons_shixun).each do |homework|
homework.update_homework_work_score
end
shixun_homeworks = shixun_homeworks&.includes(score_student_works: :user)
common_homeworks = homeworks.search_homework_type(1) #全部普通作业
common_titles = common_homeworks.pluck(:name)+ ["总得分"]
common_homeworks = common_homeworks&.includes(score_student_works: :user)
group_homeworks = homeworks.search_homework_type(3) #全部分组作业
group_titles = group_homeworks.pluck(:name)+ ["总得分"]
group_homeworks = group_homeworks&.includes(score_student_works: :user)
task_titles = tasks.pluck(:name) + ["总得分"]
tasks = tasks&.includes(user: :user_extension, score_graduation_works: :user)
exercise_titles = exercises.pluck(:exercise_name) + ["总得分"]
exercises = exercises&.includes(user: :user_extension, score_exercise_users: :user)
total_user_score_array = [] #学生总成绩集合
def course_info_to_xlsx course
#课堂信息
@course_info = []
course_info_title = "课堂信息概要"
@ -1411,7 +1400,9 @@ class CoursesController < ApplicationController
end
course_group_info = [course_group_info_head,course_group_info_body]
@course_info += [course_info_title,course_main_info,course_group_info]
end
def act_score_to_xlsx all_members
#课堂活跃度
@user_activity_level = []
course_user_level = []
@ -1426,8 +1417,6 @@ class CoursesController < ApplicationController
user_stu_id = u.student_id.present? ? (u.student_id.to_s + "\t") : "--"
user_school = user.school_name
user_course_group = u.course_group_name
user_info_array = [user_login,user_name,user_mail,user_stu_id,user_school,user_course_group] #用户的信息集合
user_work_scores = []
#课堂活跃度统计
user_homeworks_num = u.homework_num.to_i #完成的作业数
@ -1446,23 +1435,69 @@ class CoursesController < ApplicationController
c_reply_num = user_reply_num
user_activity_levels = c_works_num + c_exercise_num + c_poll_num + c_file_num + c_message_num + c_reply_num + user_work_reply_num
user_ac_level = {
u_1: user_name,
u_2: user_login,
u_2_1: user_mail,
u_3: user_stu_id,
u_4: user_school,
u_5: user_course_group,
u_6: c_works_num,
u_7: c_exercise_num,
u_8: c_poll_num,
u_9: c_file_num,
u_10: c_message_num,
u_11: c_reply_num,
u_12: user_work_reply_num,
u_13: user_activity_levels
u_1: user_name,
u_2: user_login,
u_2_1: user_mail,
u_3: user_stu_id,
u_4: user_school,
u_5: user_course_group,
u_6: c_works_num,
u_7: c_exercise_num,
u_8: c_poll_num,
u_9: c_file_num,
u_10: c_message_num,
u_11: c_reply_num,
u_12: user_work_reply_num,
u_13: user_activity_levels
}
course_user_level.push(user_ac_level)
#.课堂活跃度统计的集合
course_user_level = course_user_level.sort_by {|k| k[:u_13]}.reverse
@user_activity_level = [course_activity_title,user_cell_head,course_user_level]
end
end
def member_to_xlsx(course,all_members,homeworks,exercises,tasks)
#课堂的作业信息
shixun_homeworks = homeworks.search_homework_type(4) #全部实训作业
shixun_titles = shixun_homeworks.pluck(:name) + ["总得分"]
# 更新实训作业成绩
shixun_homeworks.includes(:homework_challenge_settings, :published_settings, :homework_commons_shixun).each do |homework|
homework.update_homework_work_score
end
shixun_homeworks = shixun_homeworks&.includes(score_student_works: :user)
common_homeworks = homeworks.search_homework_type(1) #全部普通作业
common_titles = common_homeworks.pluck(:name)+ ["总得分"]
common_homeworks = common_homeworks&.includes(score_student_works: :user)
group_homeworks = homeworks.search_homework_type(3) #全部分组作业
group_titles = group_homeworks.pluck(:name)+ ["总得分"]
group_homeworks = group_homeworks&.includes(score_student_works: :user)
task_titles = tasks.pluck(:name) + ["总得分"]
tasks = tasks&.includes(user: :user_extension, score_graduation_works: :user)
exercise_titles = exercises.pluck(:exercise_name) + ["总得分"]
exercises = exercises&.includes(user: :user_extension, score_exercise_users: :user)
total_user_score_array = [] #学生总成绩集合
all_members.each do |u|
#用户的基本信息
user = u.user
user_login = user.login
user_name = user.real_name
user_mail = user.mail
user_stu_id = user.student_id.present? ? (user.student_id.to_s + "\t") : "--"
user_school = user.school_name
user_course_group = u.course_group_name
user_info_array = [user_name,user_login,user_mail,user_stu_id,user_school,user_course_group] #用户的信息集合
user_work_scores = []
#学生总成绩
shixun_score = 0.0 # 实训作业的总分
common_score = 0.0 #普通作业的总分
@ -1560,10 +1595,6 @@ class CoursesController < ApplicationController
total_user_score_array.push(user_work_scores) # 全部成员的集合
end
#1.课堂活跃度统计的集合
course_user_level = course_user_level.sort_by {|k| k[:u_12]}.reverse
@user_activity_level = [course_activity_title,user_cell_head,course_user_level]
#2.学生总成绩的集合
## 作业标题的集合
course_user_score_title = "学生总成绩"

@ -0,0 +1,388 @@
class ExerciseBankQuestionsController < ApplicationController
before_action :require_login, :check_auth #用户需登陆
before_action :get_exercise, only:[:create] #获取试卷
before_action :get_exercise_question, except: [:create] #获取试卷的问题及试卷
before_action :bank_admin #是否为老师
before_action :validate_params, only: [:create, :update] #传入参数的验证
def create
ActiveRecord::Base.transaction do
begin
question_options = {
:question_title => params[:question_title],
:question_type => params[:question_type].present? ? params[:question_type].to_i : 0, #默认为单选题
:question_number => @exercise.exercise_bank_questions.count + 1,
:question_score => params[:question_score].present? ? params[:question_score].to_f.round(1) : 5.0,
:shixun_id => params[:shixun_id].blank? ? "" : params[:shixun_id],
:is_ordered => params[:is_ordered] # 填空题的答案是否为一一对应关系,默认为true即为一一对应
}
@exercise_question = @exercise.exercise_bank_questions.new(question_options)
#插入问题时那么从插入的这个id以后的question_num都将要+1
if params[:insert_id].present?
insert_exercise = @exercise.exercise_bank_questions.find_by(id: params[:insert_id])
if insert_exercise.present? #如果该问题存在的话,意思是如果是第一题,那么就不存在插入
ques_num = insert_exercise.question_number.to_i
@exercise_question.question_number = ques_num + 1 #更新了问题的位置
@exercise.exercise_bank_questions.insert_question_ex(ques_num).update_all("question_number = question_number + 1")
end
end
if @exercise_question.save
#为选择题(包括单选和多选)的时候,创建问题选项
ques_type = @exercise_question.question_type
if ques_type <= Exercise::MULTIPLE
choices_array = params[:question_choices]
choices_count= choices_array.count
standard_answer = params[:standard_answers] #为数组格式,因为可能会有单选和多选,标准答案,已提前判断不能为空,
standard_answer = standard_answer.uniq.reject(&:blank?)
(1..choices_count).each do |c|
choice = choices_array[c-1] #每一个选项的内容
choice_option = {
:choice_position => c,
:choice_text => choice.strip
}
question_choices = @exercise_question.exercise_bank_choices.new(choice_option)
question_choices.save
end
#标准答案的存储,如:["1","2","3"..]等1对应A2对应B3对应C。。。
standard_answer.each do |a|
choice_id = a.to_i
standard_option = {
:exercise_bank_question_id => @exercise_question.id,
:exercise_bank_choice_id => choice_id #即为选择的位置参数
}
question_standard_answer = ExerciseBankStandardAnswer.new(standard_option)
question_standard_answer.save
if standard_answer.count > 1 && ques_type == Exercise::SINGLE #当标准答案数大于1且不为多选时修改为多选
@exercise_question.update_attribute("question_type",Exercise::MULTIPLE)
elsif standard_answer.count == 1 && ques_type == Exercise::MULTIPLE
@exercise_question.update_attribute("question_type",Exercise::SINGLE)
end
end
elsif ques_type == Exercise::JUDGMENT #这个为判断题
choices_array = params[:question_choices] #判断的选项,对/错等等
choices_count= choices_array.count
(1..choices_count).each do |c|
choice = choices_array[c-1] #每一个选项的内容
choice_option = {
:choice_position => c,
:choice_text => choice.strip
}
question_choices = @exercise_question.exercise_bank_choices.create(choice_option)
question_choices.save
end
standard_answer = params[:standard_answers] #对应选项的id
standard_option = {
:exercise_bank_question_id => @exercise_question.id,
:exercise_bank_choice_id => standard_answer.first.to_i
}
question_standard_answer = ExerciseBankStandardAnswer.new(standard_option)
question_standard_answer.save
elsif ques_type == Exercise::COMPLETION #填空题,每空的参考答案有多个,那么以位置对应
standard_answer = params[:standard_answers]
standard_answer.each do |a|
null_choice_id = a[:choice_id]
null_choice_text = a[:answer_text]
null_choice_text.each do |n|
standard_option = {
:exercise_bank_question_id => @exercise_question.id,
:exercise_bank_choice_id => null_choice_id,
:answer_text => n
}
question_standard_answer = ExerciseBankStandardAnswer.new(standard_option)
question_standard_answer.save
end
end
elsif ques_type == Exercise::SUBJECTIVE #简答题
if params[:standard_answers].present? && params[:standard_answers].reject(&:blank?).count > 0
standard_answer = params[:standard_answers]
standard_answer.each do |a|
standard_option = {
:exercise_bank_question_id => @exercise_question.id,
:answer_text => a,
}
question_standard_answer = ExerciseBankStandardAnswer.new(standard_option)
question_standard_answer.save
end
end
elsif ques_type == Exercise::PRACTICAL #实训题
shixun = Shixun.find_by(id: params[:shixun_id])
shixun_scores = params[:question_scores] #试卷有多个的分值有多个分数表,所以为分数的数组
shixun_name = params[:shixun_name] || shixun.name
question_score = 0
shixun.challenges.try(:each_with_index) do |challenge,index|
shixun_option = {
:challenge_id => challenge.id,
:shixun_id => shixun.id,
:exercise_bank_question_id => @exercise_question.id,
:position => (index + 1),
:question_score => shixun_scores[index].present? ? shixun_scores[index].to_f.round(1) : 5
}
ex_shixun_challenge = ExerciseBankShixunChallenge.create(shixun_option)
question_score += ex_shixun_challenge.question_score # 问题的分数,为各个关卡分数的总和
end
@exercise_question.update_attributes(:question_score => question_score, :shixun_name=> shixun_name)
end
end
rescue Exception => e
uid_logger_error(e.message)
tip_exception("试卷问题创建失败!")
raise ActiveRecord::Rollback
end
end
end
def update
ActiveRecord::Base.transaction do
begin
# 更新试卷题目的内容
question_options = {
:question_title => params[:question_title],
:is_ordered => params[:is_ordered], # 填空题的答案是否为一一对应关系,默认为true即为一一对应
:question_score => params[:question_score].present? ? params[:question_score].to_f.round(1) : 5.0 #不可修改分数
}
choices_array = params[:question_choices]
stan_answer_params = params[:standard_answers]
standard_answer = stan_answer_params.present? ? stan_answer_params.uniq.reject(&:blank?) : []
@exercise_question.update_attributes(question_options)
#当选项存在时,可修改选项内容,但是不能更改选项的位置(即不能增删选项)
if choices_array.present?
ex_choices = @exercise_question.exercise_bank_choices
ex_choice_count = ex_choices.count
choice_array_count = choices_array.count
ex_choice_count_array = (1..ex_choice_count).to_a
choice_array_count_array = (1..choice_array_count).to_a
if ex_choice_count > choice_array_count #如果选项有减少的,那么只更新传入的,删除以前的
choice_array_count_array.each do |c|
choice = choices_array[c-1] #每一个选项的内容
exercise_choice = @exercise_question.exercise_bank_choices.find_choice_custom("choice_position",(c))
exercise_choice.update(choice_text:choice)
end
drop_ex_choice = @exercise_question.exercise_bank_choices.left_choice_choose("choice_position",(choice_array_count))
drop_ex_choice.destroy_all
else
ex_choice_count_array.each do |c|
choice = choices_array[c-1] #每一个选项的内容
exercise_choice = @exercise_question.exercise_bank_choices.find_choice_custom("choice_position",(c))
exercise_choice.update(choice_text:choice)
end
new_add_choice = choice_array_count_array - ex_choice_count_array #新传入的需新增
if new_add_choice.count > 0
new_add_choice.each do |i|
choice_option = {
:choice_position => i,
:choice_text => choices_array[i-1].strip
}
question_choices = @exercise_question.exercise_bank_choices.new(choice_option)
question_choices.save
end
end
end
end
#试卷未发布时,当标准答案存在时,可修改标准答案内容,可增删标准答案,否则只能修改标准答案,不能增删标准答案
@exercise_answers_array = @exercise_question.exercise_bank_standard_answers #问卷的全部标准答案
if standard_answer.present?
if @exercise_question.question_type <= Exercise::JUDGMENT #选择题/判断题,标准答案为一个或多个
exercise_standard_choices = @exercise_answers_array.pluck(:exercise_bank_choice_id) #问题以前的全部标准答案选项位置
if exercise_standard_choices.sort != standard_answer.sort #表示答案有更改的
standard_answer_change = true
common_standard_choices = standard_answer & exercise_standard_choices # 传入的标准答案的选项位置和以前的并集,即表示不用做更改的
old_left_standard_choices = exercise_standard_choices - common_standard_choices # 以前的差集共同的,剩余的表示需要删掉
new_left_standard_choices = standard_answer - common_standard_choices # 传入的标准答案差集共同的,剩余的表示需要新建
if old_left_standard_choices.count > 0
@exercise_answers_array.standard_by_ids(old_left_standard_choices).destroy_all
end
if new_left_standard_choices.count > 0 #新建标准答案
new_left_standard_choices.each do |s|
standard_option = {
:exercise_bank_question_id => @exercise_question.id,
:exercise_bank_choice_id => s.to_i #即为选择的位置参数
}
question_standard_answer = ExerciseBankStandardAnswer.new(standard_option)
question_standard_answer.save
end
end
if standard_answer.count > 1 && @exercise_question.question_type == Exercise::SINGLE #当标准答案数大于1且不为多选时修改为多选
@exercise_question.update_attribute("question_type",Exercise::MULTIPLE)
elsif standard_answer.count == 1 && @exercise_question.question_type == Exercise::MULTIPLE
@exercise_question.update_attribute("question_type",Exercise::SINGLE)
end
end
elsif @exercise_question.question_type == Exercise::COMPLETION #填空题
old_ex_answer = @exercise_question.exercise_bank_standard_answers #当前问题的全部标准答案
old_ex_answer_choice_texts = old_ex_answer.pluck(:answer_text).uniq.sort
new_ex_answer_choice_texts = standard_answer.pluck(:answer_text).sum.uniq.sort
if old_ex_answer_choice_texts != new_ex_answer_choice_texts #填空题标准答案有更改时,才会更新标准答案
new_ex_answer_choice_ids = standard_answer.map {|a| a[:choice_id]}.uniq #新传入的答案数组序号
old_ex_answer_choice_ids = old_ex_answer.pluck(:exercise_bank_choice_id).uniq #全部的答案数组序号
standard_answer_change = true
#删除多余的选项
if old_ex_answer_choice_ids.count > new_ex_answer_choice_ids.count #有减少的填空
delete_ex_answer_choice_ids = old_ex_answer_choice_ids - new_ex_answer_choice_ids
old_ex_answer.standard_by_ids(delete_ex_answer_choice_ids).destroy_all
end
standard_answer.each do |aa|
null_choice_id = aa[:choice_id]
null_choice_text = aa[:answer_text]
null_choice_text_count = null_choice_text.count #当前传入的答案数量
null_choice_text_count_array = (1..null_choice_text_count).to_a
ex_answer_pre = old_ex_answer.standard_by_ids(null_choice_id) #当前问题的全部答案
ex_answer_pre_count = ex_answer_pre.count
ex_answer_pre_count_array = (1..ex_answer_pre_count).to_a
if old_ex_answer_choice_ids.include?(null_choice_id) #以前的填空题答案包含有现在的填空序号
if null_choice_text_count >= ex_answer_pre_count
new_add_choice = null_choice_text_count_array - ex_answer_pre_count_array
ex_answer_pre_count_array.each do |n|
standard_option = {
:exercise_bank_question_id => @exercise_question.id,
:exercise_bank_choice_id => null_choice_id,
:answer_text => null_choice_text[n-1]
}
ex_answer_pre[n-1].update(standard_option)
end
if new_add_choice.count > 0 #表示有新增的
new_add_choice.each do |i|
standard_option = {
:exercise_bank_question_id => @exercise_question.id,
:exercise_bank_choice_id => null_choice_id,
:answer_text => null_choice_text[i-1]
}
question_standard_answer = ExerciseBankStandardAnswer.new(standard_option)
question_standard_answer.save
end
end
else
new_delete_choice = ex_answer_pre_count_array - null_choice_text_count_array
null_choice_text.each_with_index do |n,index|
standard_option = {
:exercise_bank_question_id => @exercise_question.id,
:exercise_bank_choice_id => null_choice_id,
:answer_text => n
}
ex_answer_pre[index].update(standard_option)
end
if new_delete_choice.count > 0 #表示填空题的答案有删减的
new_delete_choice.each do |d|
ex_answer_pre[d-1].destroy
end
end
end
else
null_choice_text.each do |n|
standard_option = {
:exercise_bank_question_id => @exercise_question.id,
:exercise_bank_choice_id => null_choice_id,
:answer_text => n
}
question_standard_answer = ExerciseBankStandardAnswer.new(standard_option)
question_standard_answer.save
end
end
end
end
end
end
if @exercise_question.question_type == Exercise::SUBJECTIVE #主观题
main_standard_answer = standard_answer.present? ? standard_answer.first : nil
if @exercise_answers_array.present?
@exercise_answers_array.first.update_attribute("answer_text",main_standard_answer)
else
standard_option = {
:exercise_bank_question_id => @exercise_question.id,
:answer_text => main_standard_answer,
}
question_standard_answer = ExerciseBankStandardAnswer.new(standard_option)
question_standard_answer.save
end
elsif @exercise_question.question_type == Exercise::PRACTICAL
question_score = 0
shixun_name = params[:shixun_name] || @exercise_question.shixun_name
@exercise_question.exercise_shixun_challenges.each_with_index do |challenge, index|
challenge.question_score = params[:question_scores][index].to_f.round(1)
challenge.save
question_score += params[:question_scores][index].to_f.round(1)
end
@exercise_question.question_score = question_score
@exercise_question.shixun_name = shixun_name
@exercise_question.save
end
#当试卷已发布时(试卷的总状态),当标准答案修改时,如有已提交的学生,需重新计算分数.
if standard_answer_change && @exercise.exercise_status >= Exercise::PUBLISHED
# ex_users_committed = @exercise.exercise_users.exercise_user_committed
# if ex_users_committed.size > 0
# ex_users_committed.each do |ex_user|
# update_objective_score = update_single_score(@exercise_question,ex_user.user_id,standard_answer)
# if update_objective_score != 0
# objective_score = ex_user.objective_score
# new_objective_score = objective_score + update_objective_score
# total_score = ex_user.score + update_objective_score
# total_score = total_score < 0.0 ? 0.0 : total_score
# ex_user.update_attributes(objective_score:new_objective_score,score:total_score)
# end
# end
# end
normal_status(3,"修改了标准答案\n是否重新计算学生答题的成绩?")
else
normal_status(0,"试卷更新成功!")
end
rescue Exception => e
uid_logger_error(e.message)
tip_exception("页面调用失败!")
raise ActiveRecord::Rollback
end
end
end
private
def bank_admin
tip_exception(403, "无权限") unless (current_user.certification_teacher? && @bank.user_id == current_user.id) || current_user.admin?
end
def get_exercise
@exercise = ExerciseBank.find_by!(id:params[:exercise_bank_id])
end
def get_exercise_question
@exercise_question = ExerciseBankQuestion.find_by!(id: params[:id])
@exercise = @exercise_question.exercise_bank
end
def validate_params
normal_status(-1,"题目不允许为空!") if (params[:question_title].blank? && params[:question_type].to_i != Exercise::PRACTICAL ) #除了实训题,其余题目必需有题干
normal_status(-1,"问题类型不允许为空!" ) if params[:question_type].blank?
normal_status(-1,"分值不允许为空!" ) if params[:question_score].blank? && params[:question_scores].blank? #分值的数组或参数必需存在一个
if params[:question_score].present? && params[:question_score].to_f <= 0.0 #问题类型存在,则分值不能为空,且必需大于0
normal_status(-1,"分值必需大于0")
elsif (params[:question_score].present? && params[:question_score].to_f.round(1) > 100.0) || (params[:question_scores].present? && (params[:question_scores].map{|a| a.to_f.round(1)}.max > 100.0))
normal_status(-1,"分值不能超过100分")
elsif params[:question_scores].present? && params[:question_scores].include?(0.0) #如果有负数,则自动取绝对值,#多个分数值,针对实训题的
normal_status(-1,"分值必需大于0")
elsif params[:standard_answers].present? && params[:question_choices].present? && (params[:standard_answers].count > params[:question_choices].count)
normal_status(-1,"标准答案数不能大于选项数!")
elsif [0,1,2,3].include?(params[:question_type].to_i) && (params[:standard_answers].blank? || params[:standard_answers].include?("")) #选择题/判断题/填空题 问题选项/标准答案不能为空,也不能包含空的内容
normal_status(-1,"标准答案不能为空!")
elsif params[:question_type].to_i == 2 && (params[:standard_answers].count > 1 || params[:question_choices].blank? || params[:question_choices].include?("")) #判断题的标准答案不能大于1个选项不能为空
normal_status(-1,"判断题选项不能为空/标准答案不能大于1个")
elsif params[:question_type].to_i <= 1 && (params[:question_choices].blank? || params[:question_choices].include?("") || params[:question_choices].count < 2) #选择题选项不能为空,且不能小于2
normal_status(-1,"选择题选项内容不能为空且不能少于2个")
elsif params[:question_type].to_i == 3 && (params[:standard_answers].blank? || params[:standard_answers].count > 5 ) #填空题选项最多为5个,且如果为1个的话不允许修改is_ordered
normal_status(-1,"填空题标准答案不能为空/不能超过5个")
elsif params[:question_type].to_i == 4 && params[:standard_answers].count > 2 #简单题参考答案最多为1个
normal_status(-1,"简答题的参考答案不能大于2个")
elsif params[:question_type].to_i == 5
if params[:shixun_id].blank? #实训题的id不能为空
normal_status(-1,"实训题id不能为空")
elsif params[:shixun_name].blank?
normal_status(-1,"实训题名称不能为空!")
end
end
end
end

@ -0,0 +1,60 @@
#encoding: UTF-8
class ExerciseBanksController < ApplicationController
before_action :require_login
before_action :find_bank
before_action :bank_admin, only: [:update]
def show
@exercise_questions = @bank.exercise_bank_questions&.includes(:exercise_bank_choices, :exercise_bank_shixun_challenges,
:exercise_bank_standard_answers).order("question_number ASC")
@exercise_ques_count = @exercise_questions.size # 全部的题目数
@exercise_ques_scores = @exercise_questions.pluck(:question_score).sum
#单选题的数量及分数
exercise_single_ques = @exercise_questions.find_by_custom("question_type", Exercise::SINGLE)
@exercise_single_ques_count = exercise_single_ques.size
@exercise_single_ques_scores = exercise_single_ques.pluck(:question_score).sum
#多选题的数量及分数
exercise_double_ques = @exercise_questions.find_by_custom("question_type", Exercise::MULTIPLE)
@exercise_double_ques_count = exercise_double_ques.size
@exercise_double_ques_scores = exercise_double_ques.pluck(:question_score).sum
# 判断题数量及分数
exercise_ques_judge = @exercise_questions.find_by_custom("question_type", Exercise::JUDGMENT)
@exercise_ques_judge_count = exercise_ques_judge.size
@exercise_ques_judge_scores = exercise_ques_judge.pluck(:question_score).sum
#填空题数量及分数
exercise_ques_null = @exercise_questions.find_by_custom("question_type", Exercise::COMPLETION)
@exercise_ques_null_count = exercise_ques_null.size
@exercise_ques_null_scores = exercise_ques_null.pluck(:question_score).sum
#简答题数量及分数
exercise_ques_main = @exercise_questions.find_by_custom("question_type", Exercise::SUBJECTIVE)
@exercise_ques_main_count = exercise_ques_main.size
@exercise_ques_main_scores = exercise_ques_main.pluck(:question_score).sum
#实训题数量及分数
exercise_ques_shixun = @exercise_questions.find_by_custom("question_type", Exercise::PRACTICAL)
@exercise_ques_shixun_count = exercise_ques_shixun.size
@exercise_ques_shixun_scores = exercise_ques_shixun.pluck(:question_score).sum
end
def update
tip_exception("试卷标题不能为空!") if params[:exercise_name].blank?
@bank.update_attributes!(name: params[:exercise_name], description: params[:exercise_description])
normal_status(0,"试卷更新成功!")
end
private
def find_bank
@bank = ExerciseBank.find_by!(id: params[:id])
tip_exception(403, "无权限") unless (current_user.certification_teacher? && (@bank.is_public || @bank.user_id == current_user.id)) || current_user.admin?
end
def bank_admin
tip_exception(403, "无权限") unless (current_user.certification_teacher? && @bank.user_id == current_user.id) || current_user.admin?
end
end

@ -0,0 +1,39 @@
class GtopicBanksController < ApplicationController
before_action :require_login
before_action :find_bank
before_action :bank_admin, only: [:edit, :update]
def show
@bank_attachments = @bank.attachments
end
def edit
@attachments = @bank.attachments
end
def update
ActiveRecord::Base.transaction do
@bank.update_attributes(gtopic_bank_params)
Attachment.associate_container(params[:attachment_ids], @bank.id, @bank.class) if params[:attachment_ids]
normal_status(0, "更新成功")
end
end
private
def find_bank
@bank = GtopicBank.find_by!(id: params[:id])
tip_exception(403, "无权限") unless (current_user.certification_teacher? && (@bank.is_public || @bank.user_id == current_user.id)) || current_user.admin?
end
def bank_admin
tip_exception(403, "无权限") unless (current_user.certification_teacher? && @bank.user_id == current_user.id) || current_user.admin?
end
def gtopic_bank_params
tip_exception("name参数不能为空") if params[:gtopic_bank][:name].blank?
tip_exception("description参数不能为空") if params[:gtopic_bank][:description].blank?
params.require(:gtopic_bank).permit(:name, :topic_type, :topic_source, :topic_property_first, :description,
:topic_property_second, :source_unit, :topic_repeat, :province, :city)
end
end

@ -0,0 +1,63 @@
class HomeworkBanksController < ApplicationController
before_action :require_login
before_action :find_bank
before_action :bank_params, only: [:update]
before_action :bank_admin, only: [:update, :destroy, :set_public]
def show
@bank_attachments = @bank.attachments.where(attachtype: 1)
@reference_attachments = @bank.attachments.where(attachtype: 2)
end
def update
ActiveRecord::Base.transaction do
@bank.update_attributes(name: params[:name], description: params[:description], reference_answer: params[:reference_answer])
# 作业描述的附件
Attachment.associate_container(params[:attachment_ids], @bank.id, @bank.class) if params[:attachment_ids]
# 作业参考答案的附件
Attachment.associate_container(params[:reference_attachment_ids], @bank.id, @bank.class, 2) if params[:reference_attachment_ids]
normal_status(0, "更新成功")
end
end
def destroy
ActiveRecord::Base.transaction do
@bank.homework_commons.update_all(homework_bank_id: nil)
@bank.destroy!
normal_status("删除成功")
end
end
def set_public
@bank.update_attributes(is_public: 1)
normal_status("更新成功")
end
private
def find_bank
@bank = HomeworkBank.find_by!(id: params[:id])
tip_exception(403, "无权限") unless (current_user.certification_teacher? && (@bank.is_public || @bank.user_id == current_user.id)) || current_user.admin?
end
def bank_admin
tip_exception(403, "无权限") unless (current_user.certification_teacher? && @bank.user_id == current_user.id) || current_user.admin?
end
def bank_params
tip_exception("name参数不能为空") if params[:homework_bank][:name].blank?
tip_exception("description参数不能为空") if params[:homework_bank][:description].blank?
if @bank.homework_type == 3
tip_exception("base_on_project参数不能为空") if params[:homework_bank][:base_on_project].nil?
tip_exception("min_num参数不能为空") if params[:homework_bank][:min_num].blank?
tip_exception("max_num参数不能为空") if params[:homework_bank][:max_num].blank?
tip_exception("最小人数不能小于1") if params[:homework_bank][:min_num].to_i < 1
tip_exception("最大人数不能小于最小人数") if params[:homework_bank][:max_num].to_i < params[:homework_bank][:min_num].to_i
end
params.require(:homework_bank).permit(:name, :description, :reference_answer) if @bank.homework_type == 1
params.require(:homework_bank).permit(:name, :description, :reference_answer, :min_num, :max_num, :base_on_project) if @bank.homework_type == 3
end
end

@ -1,6 +1,6 @@
class QuestionBanksController < ApplicationController
before_action :require_login, :check_auth
before_action :params_filter
before_action :params_filter, except: [:my_courses]
# 题库选用列表
# object_type: # normal 普通作业题库; group 分组作业题库; poll问卷题库 exercise试卷题库; gtask 毕设选题题库gtopic 毕设任务
@ -79,6 +79,30 @@ class QuestionBanksController < ApplicationController
end
end
def my_courses
@courses = current_user.manage_courses.where(is_delete: 0, is_end: 0)
end
def send_to_course
bank = current_bank
course = current_user.manage_courses.find_by(id: params[:course_id])
case @object_type
when 'HomeworkBank' # 作业
quote_homework_bank bank, course
when 'ExerciseBank'
if bank.container_type == 'Exercise' # 试卷
quote_exercise_bank bank, course
else # 问卷
quote_poll_bank bank, course
end
when 'GtaskBank'
quote_gtask_bank bank, course
when 'GtopicBank'
quote_gtopic_bank bank, course
end
normal_status("发送成功")
end
def destroy
bank = current_bank

@ -348,7 +348,8 @@ class ShixunsController < ApplicationController
sub_type.each do |mirror|
ShixunMirrorRepository.create!(:shixun_id => @shixun.id, :mirror_repository_id => mirror)
# 实训子镜像服务配置
ShixunServiceConfig.create!(:shixun_id => @shixun.id, :mirror_repository_id => mirror)
name = MirrorRepository.find_by(id: mirror).try(:name) #查看镜像是否有名称,如果没有名称就不用服务配置
ShixunServiceConfig.create!(:shixun_id => @shixun.id, :mirror_repository_id => mirror) if name.present?
end
end
@ -422,7 +423,12 @@ class ShixunsController < ApplicationController
# 超级管理员和运营人员才能保存 中间层服务器pod信息的配置
if current_user.admin? || current_user.business?
@shixun.shixun_service_configs.destroy_all
@shixun.shixun_service_configs.create!(service_config_params[:shixun_service_configs])
service_config_params[:shixun_service_configs].each do |config|
logger.info("####{config[:mirror_repository_id]}")
name = MirrorRepository.find_by_id(config[:mirror_repository_id])&.name
# 不保存没有镜像的配置
@shixun.shixun_service_configs.create!(config) if name.present?
end
end
rescue Exception => e
uid_logger_error(e.message)

@ -0,0 +1,48 @@
class TaskBanksController < ApplicationController
before_action :require_login
before_action :find_bank
before_action :bank_admin, only: [:update]
def show
@bank_attachments = @bank.attachments
end
def update
ActiveRecord::Base.transaction do
begin
@bank.update_attributes(gtask_bank_params)
Attachment.associate_container(params[:attachment_ids], @bank.id, @bank.class) if params[:attachment_ids]
normal_status(0, "更新成功")
rescue Exception => e
uid_logger(e.message)
tip_exception(e.message)
raise ActiveRecord::Rollback
end
end
end
private
def find_bank
@bank = GtaskBank.find_by!(id: params[:id])
tip_exception(403, "无权限") unless (current_user.certification_teacher? && (@bank.is_public || @bank.user_id == current_user.id)) || current_user.admin?
end
def bank_admin
tip_exception(403, "无权限") unless (current_user.certification_teacher? && @bank.user_id == current_user.id) || current_user.admin?
end
def gtask_bank_params
tip_exception("name参数不能为空") if params[:gtask_bank][:name].blank?
tip_exception("description参数不能为空") if params[:gtask_bank][:description].blank?
if @bank.homework_type == 3
tip_exception("base_on_project参数不能为空") if params[:gtask_bank][:base_on_project].nil?
tip_exception("min_num参数不能为空") if params[:gtask_bank][:min_num].blank?
tip_exception("max_num参数不能为空") if params[:gtask_bank][:max_num].blank?
tip_exception("最小人数不能小于1") if params[:gtask_bank][:min_num].to_i < 1
tip_exception("最大人数不能小于最小人数") if params[:gtask_bank][:max_num].to_i < params[:gtask_bank][:min_num].to_i
end
params.require(:gtask_bank).permit(:name, :description) if @bank.task_type == 1
params.require(:gtask_bank).permit(:name, :description, :min_num, :max_num, :base_on_project) if @bank.task_type == 2
end
end

@ -36,8 +36,8 @@ class Users::QuestionBanksController < Users::BaseController
.group('graduation_tasks.gtask_bank_id').count
when 'gtopic' then
StudentGraduationTopic.joins(:graduation_topic)
.where(gtopic_banks: { gtopic_bank_id: question_bank_ids }).where('status != 0')
.group('gtopic_banks.gtopic_bank_id').count
.where(graduation_topics: { gtopic_bank_id: question_bank_ids }).where('student_graduation_topics.status = 1')
.group('graduation_topics.gtopic_bank_id').count
end
end

@ -0,0 +1,2 @@
module ExerciseBankQuestionsHelper
end

@ -0,0 +1,2 @@
module HomeworkBanksHelper
end

@ -18,4 +18,7 @@ class ExerciseBank < ApplicationRecord
scope :exercise_bank_search, lambda { |keywords|
where("name LIKE ?", "%#{keywords}%") unless keywords.blank?}
validates :name, length: { maximum: 60, too_long: "60 characters is the maximum allowed" }
validates :description, length: { maximum: 100, too_long: "100 characters is the maximum allowed" }
end

@ -1,4 +1,7 @@
class ExerciseBankChoice < ApplicationRecord
belongs_to :exercise_bank_question
has_many :exercise_bank_standard_answers
scope :find_choice_custom, lambda {|k,v| where("#{k} = ?",v)} #根据传入的参数查找问题
scope :left_choice_choose, lambda {|k,v| where("#{k} > ?",v)} #根据传入的参数查找问题
end

@ -6,12 +6,19 @@ class ExerciseBankQuestion < ApplicationRecord
has_many :exercise_bank_standard_answers, :dependent => :destroy
#attr_accessible :question_number, :question_score, :question_title, :question_type
scope :insert_question_ex, lambda {|k| where("question_number > ?",k)}
scope :find_by_custom, lambda {|k,v| where("#{k} = ?",v)} #根据传入的参数查找问题
scope :left_question_choose, lambda {|k,v| where("#{k} > ?",v)} #根据传入的参数查找问题
scope :find_objective_questions, -> {where("question_type != ?",4)} #查找全部客观题
def question_type_name
case self.question_type
when 1
when 0
"单选题"
when 2
when 1
"多选题"
when 2
"判断题"
when 3
"填空题"
when 4
@ -20,4 +27,14 @@ class ExerciseBankQuestion < ApplicationRecord
"实训题"
end
end
#获取问题的全部标准答案
def get_standard_answer_ids
exercise_bank_standard_answers.pluck(:exercise_bank_choice_id)
end
def get_standard_answer_text
exercise_bank_standard_answers.pluck(:answer_text)
end
end

@ -2,4 +2,5 @@ class ExerciseBankStandardAnswer < ApplicationRecord
belongs_to :exercise_bank_question
belongs_to :exercise_bank_choice
#attr_accessible :answer_text
scope :standard_by_ids, lambda { |s| where(exercise_bank_choice_id: s) }
end

@ -0,0 +1,29 @@
wb = xlsx_package.workbook
wb.use_shared_strings = true
wb.styles do |s|
no_wrap_sz = s.add_style :border => { :style => :thin, :color =>"000000" },:alignment => {wrap_text: false,:horizontal => :center,:vertical => :center }
sz_all = s.add_style :border => { :style => :thin, :color =>"000000" },:alignment => {wrap_text: true,:horizontal => :center,:vertical => :center }
row_cell = s.add_style :bg_color=> "FAEBDC",:border => { :style => :thin, :color =>"000000" },alignment: {wrap_text: true,:horizontal => :center,:vertical => :center }
blue_cell = s.add_style :bg_color => "FAEBDC", :sz => 10,:height => 25,:b => true, :border => { :style => :thin, :color =>"000000" },:alignment => {wrap_text: true,:horizontal => :center,:vertical => :center}
#课堂信息摘要
wb.add_worksheet(name:course_info[0]) do |sheet|
sheet.sheet_view.show_grid_lines = false
course_main_info = course_info[1]
course_group_info = course_info[2]
group_info_d = course_group_info[0]
group_info_detail = course_group_info[1]
course_main_info.each do |c|
sheet.add_row c, :style => sz_all #用户id
end
sheet["A1:A7"].each { |c| c.style = row_cell }
sheet.add_row [],:style => sz_all
if group_info_detail.count > 0
sheet.add_row group_info_d, :style => blue_cell
group_info_detail.each do |group|
sheet.add_row group, :style => sz_all #用户id
end
sheet.column_info.second.width = 40
end
end #add_worksheet
end

@ -0,0 +1,25 @@
wb = xlsx_package.workbook
wb.use_shared_strings = true
wb.styles do |s|
no_wrap_sz = s.add_style :border => { :style => :thin, :color =>"000000" },:alignment => {wrap_text: false,:horizontal => :center,:vertical => :center }
sz_all = s.add_style :border => { :style => :thin, :color =>"000000" },:alignment => {wrap_text: true,:horizontal => :center,:vertical => :center }
row_cell = s.add_style :bg_color=> "FAEBDC",:border => { :style => :thin, :color =>"000000" },alignment: {wrap_text: true,:horizontal => :center,:vertical => :center }
blue_cell = s.add_style :bg_color => "FAEBDC", :sz => 10,:height => 25,:b => true, :border => { :style => :thin, :color =>"000000" },:alignment => {wrap_text: true,:horizontal => :center,:vertical => :center}
#课堂活跃度统计
wb.add_worksheet(name:activity_level[0]) do |sheet|
sheet.sheet_view.show_grid_lines = false
sheet_title = activity_level[1]
sheet_content = activity_level[2]
sheet.add_row sheet_title, :height => 25,:style => blue_cell
if sheet_content.count > 0
sheet_content.each_with_index do |c,index|
c_1 = (index+1)
c_2 = [c_1] + c.values
sheet.add_row c_2, :height => 25, :style => sz_all #用户id
end
sheet.column_widths *([20]*sheet.column_info.count)
sheet.column_info.first.width = 8
end
end #add_worksheet
end

@ -6,44 +6,6 @@ wb.styles do |s|
row_cell = s.add_style :bg_color=> "FAEBDC",:border => { :style => :thin, :color =>"000000" },alignment: {wrap_text: true,:horizontal => :center,:vertical => :center }
blue_cell = s.add_style :bg_color => "FAEBDC", :sz => 10,:height => 25,:b => true, :border => { :style => :thin, :color =>"000000" },:alignment => {wrap_text: true,:horizontal => :center,:vertical => :center}
#课堂信息摘要
wb.add_worksheet(name:course_info[0]) do |sheet|
sheet.sheet_view.show_grid_lines = false
course_main_info = course_info[1]
course_group_info = course_info[2]
group_info_d = course_group_info[0]
group_info_detail = course_group_info[1]
course_main_info.each do |c|
sheet.add_row c, :style => sz_all #用户id
end
sheet["A1:A7"].each { |c| c.style = row_cell }
sheet.add_row [],:style => sz_all
if group_info_detail.count > 0
sheet.add_row group_info_d, :style => blue_cell
group_info_detail.each do |group|
sheet.add_row group, :style => sz_all #用户id
end
sheet.column_info.second.width = 40
end
end #add_worksheet
#课堂活跃度统计
wb.add_worksheet(name:activity_level[0]) do |sheet|
sheet.sheet_view.show_grid_lines = false
sheet_title = activity_level[1]
sheet_content = activity_level[2]
sheet.add_row sheet_title, :height => 25,:style => blue_cell
if sheet_content.count > 0
sheet_content.each_with_index do |c,index|
c_1 = (index+1)
c_2 = [c_1] + c.values
sheet.add_row c_2, :height => 25, :style => sz_all #用户id
end
sheet.column_widths *([20]*sheet.column_info.count)
sheet.column_info.first.width = 8
end
end #add_worksheet
#学生总成绩
wb.add_worksheet(name:course_scores[0]) do |sheet|
sheet.sheet_view.show_grid_lines = false

@ -0,0 +1,72 @@
json.question_id question.id
q_positon = question.question_number
if ques_position.present?
q_positon = ques_position
end
json.q_position q_positon
json.question_title question.question_title
json.question_type question.question_type
json.question_score question.question_score.round(1).to_s
if question.question_type <= 2 #当为选择题或判断题时,只显示选项的位置
standard_answers_array = question.get_standard_answer_ids
exercise_choices = choices.order("choice_position ASC")
json.question_choices exercise_choices.each do |a|
#TODO: 旧版本来一个题只有一个标准答案的新版又做成了一个题有多个标准答案exercise_choice_id存放的是标准答案的位置..
standard_answer_b = standard_answers_array.join("").include?(a.choice_position.to_s)
choice_text = a.choice_text
if question.question_type == 2
if choice_text == "对"
choice_text = "正确"
end
if choice_text == "错"
choice_text = "错误"
end
end
json.choice_id a.id
# json.choice_text (edit_type.present? || question.question_type == 2) ? a.choice_text : "#{(index+65).chr}.#{a.choice_text}"
json.choice_text choice_text
json.choice_position a.choice_position
json.standard_boolean standard_answer_b
end
json.standard_answer standard_answers_array
if question.question_type == 2 #返回答案的文字
standard_text = standard_answers_array.first.to_i == 1 ? "正确" : "错误"
else
if question.question_type == 1 && standard_answers_array.size == 1
standard_answers_array = standard_answers_array.first.to_s.split("")
end
array_text_answer = []
standard_answers_array.each{|a| array_text_answer.push((a.to_i+64).chr)}
standard_text = array_text_answer.join("")
end
json.standard_answer_show standard_text
elsif question.question_type == 3 #当为填空题时
standard_answers_count = question.exercise_bank_standard_answers
standard_answer_ex = standard_answers_count.pluck(:exercise_bank_choice_id).uniq
json.is_ordered question.is_ordered
json.multi_count standard_answer_ex.size #有几个填空
json.standard_answer do
json.array! standard_answer_ex.each do |a|
s_answer_text = standard_answers_count.standard_by_ids(a).pluck(:answer_text)
json.choice_id a
json.answer_text s_answer_text
end
end
elsif question.question_type == 4 #简答题时
json.standard_answer question.exercise_bank_standard_answers.pluck(:answer_text)
elsif question.question_type == 5
json.shixun_id question.shixun_id
json.shixun_name question.shixun_name.present? ? question.shixun_name : ""
json.shixun_identifier question.shixun.identifier
json.shixun do
json.array! shixun_challenges do |s|
json.challenge_id s.challenge_id
json.challenge_position s.position
json.challenge_name s.challenge.subject
json.challenge_score s.question_score.round(1).to_s
end
end
end

@ -0,0 +1,16 @@
json.exercise do
json.extract! @bank, :id, :name, :description, :is_public
end
json.partial! "exercises/exercise_scores"
json.exercise_questions do
json.array! @exercise_questions do |q|
json.partial! "exercise_bank_questions/exercise_bank_questions",
question: q,
choices:q.exercise_bank_choices,
shixun_challenges: q.exercise_bank_shixun_challenges,
ques_position:nil,
edit_type:nil
end
end

@ -49,8 +49,11 @@ if question.question_type <= 2 #当为选择题或判断题时,只显示选
if question.question_type == 2 #返回答案的文字
standard_text = standard_answers_array.first.to_i == 1 ? "正确" : "错误"
else
if question.question_type == 1 && standard_answers_array.size == 1
standard_answers_array = standard_answers_array.first.to_s.split("")
end
array_text_answer = []
standard_answers_array.each{|a| array_text_answer.push((a+64).chr)}
standard_answers_array.each{|a| array_text_answer.push((a.to_i+64).chr)}
standard_text = array_text_answer.join("")
end
json.standard_answer_show standard_text

@ -7,6 +7,7 @@ if @exercises_count > 0
second_left = get_exercise_left_time(exercise,@current_user_)
json.time second_left.present? ? (second_left / 60) : nil
end
json.author exercise.user.real_name
ex_index = exercise_index_show(exercise,@course,@is_teacher_or,@current_user_)
json.exercise_status ex_index[:ex_status]
json.lock_status ex_index[:lock_icon]

@ -0,0 +1,15 @@
json.topic_type topic_type
json.topic_source topic_source
json.topic_property_first topic_property_first
json.topic_property_second topic_property_second
json.topic_repeat topic_repeat
json.selected_data do
json.(@bank, :name, :topic_type, :topic_source, :topic_property_first,
:description, :topic_property_second, :source_unit, :topic_repeat,
:province, :city, :is_public)
end
json.attachments @attachments do |attachment|
json.partial! "attachments/attachment_simple", locals: {attachment: attachment}
end

@ -0,0 +1,6 @@
json.(@bank, :id, :name, :description, :is_public, :topic_type, :topic_source, :topic_property_first, :topic_property_second,
:source_unit, :topic_repeat, :province, :city)
json.attachment_list @bank_attachments do |attachment|
json.partial! "attachments/attachment_simple", locals: {attachment: attachment}
end

@ -0,0 +1,9 @@
json.(@bank, :id, :name, :description, :homework_type, :is_public, :min_num, :max_num, :base_on_project, :reference_answer)
json.attachments @bank_attachments do |attachment|
json.partial! "attachments/attachment_simple", locals: {attachment: attachment}
end
json.reference_attachments @reference_attachments do |attachment|
json.partial! "attachments/attachment_simple", locals: {attachment: attachment}
end

@ -17,6 +17,7 @@ json.homeworks @homework_commons.each do |homework|
json.status_time curr_status[:time]
json.time_status curr_status[:time_status]
json.allow_late homework.allow_late
json.author homework.user.real_name
# 只有在主目录才显示
json.upper_category_name homework.course_second_category&.name unless params[:category]

@ -5,6 +5,7 @@ if @polls_count > 0
json.array! @polls do |poll|
poll_index_array = poll_index_show(poll,@course,@is_teacher_or,@current_user_)
json.extract! poll, :id, :polls_name,:is_public,:created_at
json.author poll.user.real_name
json.polls_status poll_index_array[:polls_status]
json.lock_status poll_index_array[:lock_icon]
json.publish_time poll_index_array[:publish_time] # 问卷的发布时间

@ -0,0 +1,4 @@
json.courses @courses do |course|
json.course_id course.id
json.course_name course.name
end

@ -0,0 +1,14 @@
json.(@bank, :id, :name, :description, :task_type, :is_public)
# 附件
json.attachments @bank_attachments do |attachment|
json.partial! "attachments/attachment_simple", locals: {attachment: attachment}
end
# 分组要求
if @bank.task_type == 2
json.group_info do
json.max_number @bank.max_num
json.min_number @bank.min_num
json.base_on_project @bank.base_on_project
end
end

@ -343,6 +343,8 @@ Rails.application.routes.draw do
get 'base_info'
get 'attahcment_category_list'
get 'export_member_scores_excel' #导出课堂信息
get 'export_couser_info'
get 'export_member_act_score'
post 'switch_to_teacher'
post 'switch_to_assistant'
post 'switch_to_student'
@ -569,14 +571,6 @@ Rails.application.routes.draw do
resource :poll_votes,only:[:create,:destroy]
end
resources :question_banks do
collection do
get :bank_list
post :save_banks
end
end
resources :exercises do
member do
get :choose_shixun
@ -631,6 +625,26 @@ Rails.application.routes.draw do
end
end
resources :question_banks do
collection do
get :bank_list
post :save_banks
get :my_courses
post :send_to_course
end
end
resources :homework_banks do
member do
post :set_public
end
end
resources :gtopic_banks
resources :task_banks
resources :exercise_banks
resources :attachments
resources :schools do

@ -0,0 +1,5 @@
class AddIsOrderedToExerciseBankQuestion < ActiveRecord::Migration[5.2]
def change
add_column :exercise_bank_questions, :is_ordered, :boolean, :default => true
end
end

@ -55,12 +55,12 @@ class Index extends Component {
window.$('#root').css('position', 'absolute')
// TPI浏览器缩放
setTimeout(() => {
const agent = navigator.userAgent;
if (agent.indexOf('Mac OS') == -1) {
window._initZoomCheck()
}
}, 800)
// setTimeout(() => {
// const agent = navigator.userAgent;
// if (agent.indexOf('Mac OS') == -1) {
// window._initZoomCheck()
// }
// }, 800)
this.onDrawerButtonClick = this.onDrawerButtonClick.bind(this)

@ -146,23 +146,25 @@ class TPICodeSetting extends Component {
{/* <a href="https://github.com/Microsoft/monaco-editor/wiki/Monaco-Editor-Accessibility-Guide"></a> */}
</h3>
<div className="-padding-24 " style={{ marginBottom: '40px' }}>
<Tooltip title={ task_pass ? "允许学员跳关挑战实训" : "禁止学员跳关挑战实训"} disableFocusListener={true}>
<Tooltip title={ task_pass ? "允许学员跳关挑战" : "不允许学员跳关挑战"} disableFocusListener={true}>
<div className="-layout-h -center -justify-between">
<div className="ide-settings--item-key">跳关</div>
<div className="ide-settings--item-value">{ task_pass ? '允许' : '不允许'}</div>
</div>
</Tooltip>
<Tooltip title={ test_set_permission ? "允许学员通过金币解锁查看测试集内容"
: "禁止学员通过金币解锁查看测试集内容"} disableFocusListener={true}>
: "不允许学员通过金币解锁查看测试集内容"} disableFocusListener={true}>
<div className="-layout-h -center -justify-between">
<div className="ide-settings--item-key">测试集解锁</div>
<div className="ide-settings--item-value">{ test_set_permission ? '允许' : '不允许'}</div>
</div>
</Tooltip>
<Tooltip title={ forbid_copy ? "禁用页面复制和粘贴功能"
: "启用页面复制和粘贴功能"} disableFocusListener={true}>
<Tooltip title={ forbid_copy ? "不允许学员复制和粘贴代码"
: "允许学员复制和粘贴代码"} disableFocusListener={true}>
<div className="-layout-h -center -justify-between">
<div className="ide-settings--item-key">代码复制粘贴</div>

@ -0,0 +1,35 @@
/**
<!-- 微信sdk https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115 -->
<script src="https://res.wx.qq.com/open/js/jweixin-1.4.0.js"></script>
*/
if(window.wx) {
wx.ready(function () { //需在用户可能点击分享按钮前就先调用
alert('got wx1')
wx.updateAppMessageShareData({
title: ' title', // 分享标题
desc: 'hello world', // 分享描述
link: 'https://www.educoder.net', // 分享链接该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl: 'https://pre-newweb.educoder.net/images/educoder/headNavLogo.png', // 分享图标
success: function () {
// 设置成功
}
})
});
// wx.onMenuShareAppMessage({
//             title:' title', // 分享标题
//             desc:'hello world', // 分享描述
//             link: 'https://www.educoder.net', //location.href, // 分享链接
//             imgUrl: 'https://pre-newweb.educoder.net/images/educoder/headNavLogo.png', // 分享图标
//             type: '', // 分享类型,music、video或link不填默认为link
//             dataUrl: '', // 如果type是music或video则要提供数据链接默认为空
//             success: function () { 
//                 // 用户确认分享后执行的回调函数
//             },
//             cancel: function () { 
//                 // 用户取消分享后执行的回调函数
//             }
//         });
}

@ -560,13 +560,32 @@ export default class TPMsettings extends Component {
}
bigClass = (value) => {
// choice_main_type
// choice_small_type
let {settingsData,shixun_service_configs,choice_main_type,choice_small_type}=this.state;
let list=[]
list.push(choice_main_type)
choice_small_type.map((item,key)=>{
list.push(item)
})
let newshixun_service_configs=shixun_service_configs;
let newshixun_service_configsagin=[]
newshixun_service_configs.map((item,key)=>{
list.map((its,index)=>{
if(item.mirror_repository_id===its){
newshixun_service_configsagin.push(item)
}
})
})
let {settingsData,shixun_service_configs}=this.state;
let newshixun_service_configs=shixun_service_configs;
settingsData.shixun.main_type.some((item,key)=> {
if (item.id === value) {
newshixun_service_configs[0]={
newshixun_service_configsagin[0]={
mirror_repository_id:value,
name:item.type_name,
cpu_limit:1,
@ -586,8 +605,8 @@ export default class TPMsettings extends Component {
choice_main_type: value,
standard_scripts:response.data,
choice_standard_scripts:null,
shixun_service_configs:newshixun_service_configs,
shixun_service_configlist:newshixun_service_configs,
shixun_service_configs:newshixun_service_configsagin,
shixun_service_configlist:newshixun_service_configsagin,
})
}
}).catch((error) => {
@ -628,7 +647,7 @@ export default class TPMsettings extends Component {
}
littleClass = (value) => {
let {settingsData,shixun_service_configs,choice_small_type}=this.state;
let {settingsData,shixun_service_configs,choice_small_type,choice_main_type}=this.state;
let newshixun_service_configs=shixun_service_configs;
let newchoice_small_type=choice_small_type;
// if(Array.isArray(value)===true){
@ -649,9 +668,26 @@ export default class TPMsettings extends Component {
// )
// })
// }
let list=[]
list.push(choice_main_type)
choice_small_type.map((item,key)=>{
list.push(item)
})
let newshixun_service_configsagin=[]
newshixun_service_configs.map((item,key)=>{
list.map((its,index)=>{
if(item.mirror_repository_id===its){
newshixun_service_configsagin.push(item)
}
})
})
settingsData.shixun.small_type.some((items,keys)=> {
if (items.id === value) {
newshixun_service_configs.push({
newshixun_service_configsagin.push({
mirror_repository_id:value,
name:items.type_name,
cpu_limit:1,
@ -668,8 +704,8 @@ export default class TPMsettings extends Component {
this.setState({
choice_small_type: newchoice_small_type,
shixun_service_configs:newshixun_service_configs,
shixun_service_configlist:newshixun_service_configs,
shixun_service_configs:newshixun_service_configsagin,
shixun_service_configlist:newshixun_service_configsagin,
})
}
onPodExistTimeChange = (e) => {
@ -1609,7 +1645,7 @@ export default class TPMsettings extends Component {
settingsData === undefined ? "" : settingsData.shixun.main_type.map((item, key) => {
return (
<Option value={item.id} key={key} >
<Tooltip placement="right" title={item.description} >
<Tooltip placement="right" title={item.description=== ""?"无描述":item.description} >
{item.type_name}
</Tooltip>
</Option>
@ -1738,7 +1774,11 @@ export default class TPMsettings extends Component {
{
settingsData === undefined ? "" : settingsData.shixun.small_type.map((item, key) => {
return(
<Option value={item.id} key={key}>{item.type_name}</Option>
<Option value={item.id} key={key}>
<Tooltip placement="right" title={item.description=== ""?"无描述":item.description} >
{item.type_name}
</Tooltip>
</Option>
)
})
}
@ -2179,19 +2219,18 @@ export default class TPMsettings extends Component {
</div>:""}
</div>
{/*"name": "我是镜像名", # 镜像名称*/}
{/*"cpu_limit": 1, # cpu核*/}
{/*"lower_cpu_limit": 0.1, # 最低cpu核 浮点数*/}
{/*"memory_limit": 1024 ,#内存限制*/}
{/*"request_limit": 10, # 内存要求*/}
{/*"mirror_repository_id": 12, # 镜像id*/}
{this.props.identity<3?<div className="edu-back-white padding40-20 mb20">
<p className="color-grey-6 font-16 mb30">服务配置</p>
{ shixun_service_configs&&shixun_service_configs.map((item,key)=>{
return(
<div key={key}>
<div id="5">
<p className="color-grey-6 font-16 mt30 mb20" id="shixun_scenario_type_name">{item.name}</p>
<p className="color-grey-6 font-16 mt30 mb20" id="shixun_scenario_type_name">
<span className={"fl"}>{item.name}</span>
{/*<span className={"fr mr40"} onClick={()=>this.Deselectlittle(item.mirror_repository_id)}><i className="fa fa-times-circle color-grey-c font-16 fl"></i></span>*/}
</p>
<div className="clearfix mb5">
<label className="panel-form-label fl">CPU()</label>
<div className="pr fl with80 status_con">

@ -994,7 +994,7 @@ class Newshixuns extends Component {
newshixunlist === undefined ? "" : newshixunlist.main_type.map((item, key) => {
return (
<Option value={item.id} key={key} >
<Tooltip placement="right" title={item.description} >
<Tooltip placement="right" title={item.description=== ""?"无描述":item.description} >
{item.type_name}
</Tooltip>
</Option>
@ -1119,7 +1119,11 @@ class Newshixuns extends Component {
{
newshixunlist === undefined ? "" : newshixunlist.small_type.map((item, key) => {
return (
<Option value={item.id} key={key}>{item.type_name}</Option>
<Option value={item.id} key={key}>
<Tooltip placement="right" title={item.description=== ""?"无描述":item.description} >
{item.type_name}
</Tooltip>
</Option>
)
})
}

@ -1,189 +0,0 @@
'use strict';
// Do this as the first thing so that any code reading it knows the right env.
process.env.BABEL_ENV = 'production';
process.env.NODE_ENV = 'production';
// Makes the script crash on unhandled rejections instead of silently
// ignoring them. In the future, promise rejections that are not handled will
// terminate the Node.js process with a non-zero exit code.
process.on('unhandledRejection', err => {
throw err;
});
// Ensure environment variables are read.
require('../config/env');
const path = require('path');
const chalk = require('chalk');
const fs = require('fs-extra');
const webpack = require('webpack');
const config = require('../config/webpack.config.prod');
const paths = require('../config/paths');
const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
const formatWebpackMessages = require('react-dev-utils/formatWebpackMessages');
const printHostingInstructions = require('react-dev-utils/printHostingInstructions');
const FileSizeReporter = require('react-dev-utils/FileSizeReporter');
const printBuildError = require('react-dev-utils/printBuildError');
var CombinedStream = require('combined-stream');
var fs2 = require('fs');
const measureFileSizesBeforeBuild =
FileSizeReporter.measureFileSizesBeforeBuild;
const printFileSizesAfterBuild = FileSizeReporter.printFileSizesAfterBuild;
const useYarn = fs.existsSync(paths.yarnLockFile);
// These sizes are pretty large. We'll warn for bundles exceeding them.
const WARN_AFTER_BUNDLE_GZIP_SIZE = 512 * 1024;
const WARN_AFTER_CHUNK_GZIP_SIZE = 1024 * 1024;
// Warn and crash if required files are missing
if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
process.exit(1);
}
// First, read the current file sizes in build directory.
// This lets us display how much they changed later.
measureFileSizesBeforeBuild(paths.appBuild)
.then(previousFileSizes => {
// Remove all content but keep the directory so that
// if you're in it, you don't end up in Trash
fs.emptyDirSync(paths.appBuild);
// Merge with the public folder
copyPublicFolder();
// Start the webpack build
return build(previousFileSizes);
})
.then(
({ stats, previousFileSizes, warnings }) => {
if (warnings.length) {
console.log(chalk.yellow('Compiled with warnings.\n'));
console.log(warnings.join('\n\n'));
console.log(
'\nSearch for the ' +
chalk.underline(chalk.yellow('keywords')) +
' to learn more about each warning.'
);
console.log(
'To ignore, add ' +
chalk.cyan('// eslint-disable-next-line') +
' to the line before.\n'
);
} else {
console.log(chalk.green('Compiled successfully.\n'));
}
console.log('File sizes after gzip:\n');
printFileSizesAfterBuild(
stats,
previousFileSizes,
paths.appBuild,
WARN_AFTER_BUNDLE_GZIP_SIZE,
WARN_AFTER_CHUNK_GZIP_SIZE
);
console.log();
const appPackage = require(paths.appPackageJson);
const publicUrl = paths.publicUrl;
const publicPath = config.output.publicPath;
const buildFolder = path.relative(process.cwd(), paths.appBuild);
printHostingInstructions(
appPackage,
publicUrl,
publicPath,
buildFolder,
useYarn
);
},
err => {
console.log(chalk.red('Failed to compile.\n'));
printBuildError(err);
process.exit(1);
}
);
// Create the production build and print the deployment instructions.
function build(previousFileSizes) {
console.log('Creating an optimized production build...');
let compiler = webpack(config);
return new Promise((resolve, reject) => {
compiler.run((err, stats) => {
if (err) {
return reject(err);
}
const messages = formatWebpackMessages(stats.toJson({}, true));
if (messages.errors.length) {
// Only keep the first error. Others are often indicative
// of the same problem, but confuse the reader with noise.
if (messages.errors.length > 1) {
messages.errors.length = 1;
}
return reject(new Error(messages.errors.join('\n\n')));
}
if (
process.env.CI &&
(typeof process.env.CI !== 'string' ||
process.env.CI.toLowerCase() !== 'false') &&
messages.warnings.length
) {
console.log(
chalk.yellow(
'\nTreating warnings as errors because process.env.CI = true.\n' +
'Most CI servers set it automatically.\n'
)
);
return reject(new Error(messages.warnings.join('\n\n')));
}
generateNewIndexJsp();
return resolve({
stats,
previousFileSizes,
warnings: messages.warnings,
});
});
});
}
function copyPublicFolder() {
fs.copySync(paths.appPublic, paths.appBuild, {
dereference: true,
filter: file => file !== paths.appHtml,
});
}
function generateNewIndexJsp() {
// var combinedStream = CombinedStream.create();
var filePath = paths.appBuild + '/index.html';
// var htmlContent = fs2.createReadStream( filePath )
// stream没有replace方法
// htmlContent = htmlContent.replace('/js/js_min_all.js', '/react/build/js/js_min_all.js')
// htmlContent = htmlContent.replace('/css/css_min_all.css', '/react/build/css/css_min_all.css')
// combinedStream.append(htmlContent);
// combinedStream.pipe(fs2.createWriteStream( filePath ));
var outputPath = paths.appBuild + '/../../../app/views/common/index.html.erb'
fs2.readFile(filePath, 'utf8', function (err,data) {
if (err) {
return console.log(err);
}
var result = data.replace('/js/js_min_all.js', '/react/build/js/js_min_all.js')
.replace('/js/js_min_all_2.js', '/react/build/js/js_min_all_2.js')
.replace('/css/css_min_all.css', '/react/build/css/css_min_all.css')
.replace('/js/create_kindeditor.js', '/react/build/js/create_kindeditor.js')
.replace(/http:\/\/localhost:3000/g, '');
// .replace('/css/css_min_all.css', '/react/build/css/css_min_all.css');
fs2.writeFile(outputPath, result, 'utf8', function (err) {
if (err) return console.log(err);
});
});
}

@ -1,169 +0,0 @@
var fs = require('fs');
var uglify = require("uglify-js");
var path = require('path');
var concat = require('concat')
var results = [];
var walk = function(dir, done) {
fs.readdir(dir, function(err, list) {
console.log(list)
if (err) return done(err);
var pending = list.length;
if (!pending) return done(null, results);
list.forEach(function(file) {
file = path.resolve(dir, file);
fs.stat(file, function(err, stat) {
if (stat && stat.isDirectory()) {
walk(file, function(err, res) {
// results = results.concat(res);
if (!--pending) done(null, results);
});
} else {
results.push(file);
if (!--pending) done(null, results);
}
});
});
});
};
// 需要输出文件名数组时改为true
var jsDir = './public/js/';
var cssDir = './public/css'
// true &&
false &&
walk(cssDir, function() {
console.log('results', results.length, results)
})
// return;
// ----------------------------------------------------------------------------- CSS
var cssResults = [
'D:\\Code\\trustieplus\\public\\react\\public\\css\\edu-common.css',
'D:\\Code\\trustieplus\\public\\react\\public\\css\\edu-public.css',
'D:\\Code\\trustieplus\\public\\react\\public\\css\\taskstyle.css' ,
'D:\\Code\\trustieplus\\public\\react\\public\\css\\font-awesome.css',
'D:\\Code\\trustieplus\\public\\react\\public\\css\\editormd.min.css',
'D:\\Code\\trustieplus\\public\\react\\public\\css\\merge.css',
]
concat(cssResults, './public/css/css_min_all.css')
return;
// ----------------------------------------------------------------------------- JS
var _results = [
'D:\\Code\\trustieplus\\public\\react\\public\\js\\jquery-1.8.3.min.js',
'D:\\Code\\trustieplus\\public\\react\\public\\js\\editormd\\underscore.min.js',
'D:\\Code\\trustieplus\\public\\react\\public\\js\\editormd\\marked.min.js',
'D:\\Code\\trustieplus\\public\\react\\public\\js\\editormd\\prettify.min.js',
'D:\\Code\\trustieplus\\public\\react\\public\\js\\editormd\\raphael.min.js',
'D:\\Code\\trustieplus\\public\\react\\public\\js\\editormd\\sequence-diagram.min.js',
'D:\\Code\\trustieplus\\public\\react\\public\\js\\editormd\\flowchart.min.js',
'D:\\Code\\trustieplus\\public\\react\\public\\js\\editormd\\jquery.flowchart.min.js',
'D:\\Code\\trustieplus\\public\\react\\public\\js\\editormd\\editormd.min.js',
'D:\\Code\\trustieplus\\public\\react\\public\\js\\codemirror\\codemirror.js',
'D:\\Code\\trustieplus\\public\\react\\public\\js\\codemirror\\mode\\javascript.js',
'D:\\Code\\trustieplus\\public\\react\\public\\js\\diff_match_patch.js',
'D:\\Code\\trustieplus\\public\\react\\public\\js\\merge.js',
'D:\\Code\\trustieplus\\public\\react\\public\\js\\edu_tpi.js',
]
// 合并js时需确保每个js都正常结束未正常结束的需要在js文件结尾加一个;好,不然会出现脚本错。
concat(_results, './public/js/js_min_all.js')
// var uglified = uglify.minify(['./public/js/merge.js']);
// console.log('uglified', uglified)
// fs.writeFile('concat.min.js', uglified.code, function (err){
// if(err) {
// console.log(err);
// } else {
// console.log("Script generated and saved:", 'concat.min.js');
// }
// });
// var uglified = uglify.minify(['file1.js', 'file2.js', 'file3.js']);
/**
优化
underscore被单独加载了去掉'D:\\Code\\trustieplus\\public\\react\\public\\js\\editormd\\underscore.min.js',
marked
raphaeljs sequence diagrams 1.0.4
统计 js_min_all加载的js
https://github.com/paulmillr/es6-shim
jQuery v1.8.3 jquery.com
Underscore.js 1.8.2
marked v0.3.3
Raphaël 2.1.3 - JavaScript Vector Library
flowchart, v1.3.4
editormd.js
// Codemirror单独放置哪些地方还在使用Codemirror
// 新版使用了Monaco 无需一些Codemirror插件了
CodeMirror
cm active-line.js
cm mode javascript
cm merge.js
CodeMirror addon hint
cm showHint
cm anyword-hint
CodeMirror python
CodeMirror c-like(java)
CodeMirror matchbrackets
余下
CodeMirror
diff
merge
移除的在js_min_cm.js
/**
active-line.js
mode javascript
fuzzysort
showHint
javascript-hint
anyword-hint
CodeMirror python
CodeMirror c-like(java)
CodeMirror matchbrackets
/
>
// Copyright (C) 2006 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
去掉了
marked v0.3.3 去不了去掉后 这句代码会报错window.editormd.markdownToHTML TODO 看能否去掉单独加载marked的地方
*/

@ -1,114 +0,0 @@
'use strict';
// Do this as the first thing so that any code reading it knows the right env.
process.env.BABEL_ENV = 'development';
process.env.NODE_ENV = 'development';
// Makes the script crash on unhandled rejections instead of silently
// ignoring them. In the future, promise rejections that are not handled will
// terminate the Node.js process with a non-zero exit code.
process.on('unhandledRejection', err => {
throw err;
});
// Ensure environment variables are read.
require('../config/env');
const fs = require('fs');
const chalk = require('chalk');
const webpack = require('webpack');
const WebpackDevServer = require('webpack-dev-server');
const clearConsole = require('react-dev-utils/clearConsole');
const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
const {
choosePort,
createCompiler,
prepareProxy,
prepareUrls,
} = require('react-dev-utils/WebpackDevServerUtils');
const openBrowser = require('react-dev-utils/openBrowser');
const paths = require('../config/paths');
const config = require('../config/webpack.config.dev');
const createDevServerConfig = require('../config/webpackDevServer.config');
const useYarn = fs.existsSync(paths.yarnLockFile);
const isInteractive = process.stdout.isTTY;
const portSetting = require(paths.appPackageJson).port
if ( portSetting ) {
process.env.port = portSetting
}
// Warn and crash if required files are missing
if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
process.exit(1);
}
// Tools like Cloud9 rely on this.
const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3000;
const HOST = process.env.HOST || '0.0.0.0';
if (process.env.HOST) {
console.log(
chalk.cyan(
`Attempting to bind to HOST environment variable: ${chalk.yellow(
chalk.bold(process.env.HOST)
)}`
)
);
console.log(
`If this was unintentional, check that you haven't mistakenly set it in your shell.`
);
console.log(`Learn more here: ${chalk.yellow('http://bit.ly/2mwWSwH')}`);
console.log();
}
// We attempt to use the default port but if it is busy, we offer the user to
// run on a different port. `choosePort()` Promise resolves to the next free port.
choosePort(HOST, DEFAULT_PORT)
.then(port => {
if (port == null) {
// We have not found a port.
return;
}
const protocol = process.env.HTTPS === 'true' ? 'https' : 'http';
const appName = require(paths.appPackageJson).name;
const urls = prepareUrls(protocol, HOST, port);
// Create a webpack compiler that is configured with custom messages.
const compiler = createCompiler(webpack, config, appName, urls, useYarn);
// Load proxy config
const proxySetting = require(paths.appPackageJson).proxy;
console.log('-------------------------proxySetting:', proxySetting)
const proxyConfig = prepareProxy(proxySetting, paths.appPublic);
// Serve webpack assets generated by the compiler over a web sever.
const serverConfig = createDevServerConfig(
proxyConfig,
urls.lanUrlForConfig
);
const devServer = new WebpackDevServer(compiler, serverConfig);
// Launch WebpackDevServer.
devServer.listen(port, HOST, err => {
if (err) {
return console.log(err);
}
if (isInteractive) {
clearConsole();
}
console.log(chalk.cyan('Starting the development server...\n'));
openBrowser(urls.localUrlForBrowser);
});
['SIGINT', 'SIGTERM'].forEach(function(sig) {
process.on(sig, function() {
devServer.close();
process.exit();
});
});
})
.catch(err => {
if (err && err.message) {
console.log(err.message);
}
process.exit(1);
});

@ -1,27 +0,0 @@
'use strict';
// Do this as the first thing so that any code reading it knows the right env.
process.env.BABEL_ENV = 'test';
process.env.NODE_ENV = 'test';
process.env.PUBLIC_URL = '';
// Makes the script crash on unhandled rejections instead of silently
// ignoring them. In the future, promise rejections that are not handled will
// terminate the Node.js process with a non-zero exit code.
process.on('unhandledRejection', err => {
throw err;
});
// Ensure environment variables are read.
require('../config/env');
const jest = require('jest');
const argv = process.argv.slice(2);
// Watch unless on CI or in coverage mode
if (!process.env.CI && argv.indexOf('--coverage') < 0) {
argv.push('--watch');
}
jest.run(argv);

@ -3760,4 +3760,9 @@ a.singlepublishtwo{
/*.ant-notification{*/
/*width: auto !important;*/
/*max-width: 600px !important;*/
/*}*/
/*}*/
.topicsItem{
max-width: 1138px;
height: 110px;
overflow-y: auto;
}

@ -0,0 +1,5 @@
require 'rails_helper'
RSpec.describe HomeworkBanksController, type: :controller do
end

@ -0,0 +1,15 @@
require 'rails_helper'
# Specs in this file have access to a helper object that includes
# the HomeworkBanksHelper. For example:
#
# describe HomeworkBanksHelper do
# describe "string concat" do
# it "concats two strings with spaces" do
# expect(helper.concat_strings("this","that")).to eq("this that")
# end
# end
# end
RSpec.describe HomeworkBanksHelper, type: :helper do
pending "add some examples to (or delete) #{__FILE__}"
end
Loading…
Cancel
Save