Merge branch 'dev_aliyun' into dev_static

merge aliyun
dev_static
tangjiang 5 years ago
commit e76f048fab

@ -12,7 +12,7 @@ class Admins::ExaminationAuthenticationsController < Admins::BaseController
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
exam = ExaminationBank.find current_apply.container_id exam = ExaminationBank.find current_apply.container_id
current_apply.update!(status: 1) current_apply.update!(status: 1)
exam.update!(public: 0) exam.update!(public: 1)
end end
render_success_js render_success_js
end end

@ -16,7 +16,7 @@ class Admins::ItemAuthenticationsController < Admins::BaseController
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
item = ItemBank.find current_apply.container_id item = ItemBank.find current_apply.container_id
current_apply.update!(status: 1) current_apply.update!(status: 1)
item.update!(public: 0) item.update!(public: 1)
end end
render_success_js render_success_js
end end

@ -85,8 +85,8 @@ class ApplicationController < ActionController::Base
# 题库的访问权限 # 题库的访问权限
def bank_visit_auth def bank_visit_auth
tip_exception(-2,"未通过职业认证") if current_user.is_teacher? && !current_user.certification_teacher? && !current_user.admin? && @bank.user_id != current_user.id && @bank.is_public tip_exception(-2,"未通过职业认证") if current_user.is_teacher? && !current_user.certification_teacher? && !current_user.admin_or_business? && @bank.user_id != current_user.id && @bank.is_public
tip_exception(403, "无权限") unless @bank.user_id == current_user.id || current_user.admin? || tip_exception(403, "无权限") unless @bank.user_id == current_user.id || current_user.admin_or_business? ||
(current_user.certification_teacher? && @bank.is_public) (current_user.certification_teacher? && @bank.is_public)
end end
@ -165,7 +165,7 @@ class ApplicationController < ActionController::Base
def find_course def find_course
return normal_status(2, '缺少course_id参数') if params[:course_id].blank? return normal_status(2, '缺少course_id参数') if params[:course_id].blank?
@course = Course.find(params[:course_id]) @course = Course.find(params[:course_id])
tip_exception(404, "") if @course.is_delete == 1 && !current_user.admin? tip_exception(404, "") if @course.is_delete == 1 && !current_user.admin_or_business?
rescue Exception => e rescue Exception => e
tip_exception(e.message) tip_exception(e.message)
end end

@ -58,7 +58,7 @@ class CommonsController < ApplicationController
200 200
end end
else else
current_user.admin? ? 200 : 403 current_user.admin_or_business? ? 200 : 403
end end
return normal_status(code, "你没有权限操作!") if code == 403 return normal_status(code, "你没有权限操作!") if code == 403
end end

@ -396,7 +396,7 @@ class CoursesController < ApplicationController
def teachers def teachers
@search_str = params[:search].present? ? params[:search].strip : "" @search_str = params[:search].present? ? params[:search].strip : ""
if @course.try(:id) != 1309 || current_user.admin? || current_user.try(:id) == 15582 if @course.try(:id) != 1309 || current_user.admin_or_business? || current_user.try(:id) == 15582
@teacher_list = @course.course_members.joins(:user).where("course_members.role in (1, 2, 3) @teacher_list = @course.course_members.joins(:user).where("course_members.role in (1, 2, 3)
and LOWER(concat(users.lastname, users.firstname)) LIKE ?", "%#{@search_str}%") and LOWER(concat(users.lastname, users.firstname)) LIKE ?", "%#{@search_str}%")
else else
@ -441,7 +441,7 @@ class CoursesController < ApplicationController
@applications = CourseMessage.unhandled_join_course_requests_by_course(@course). @applications = CourseMessage.unhandled_join_course_requests_by_course(@course).
joins("join users on course_messages.course_message_id=users.id"). joins("join users on course_messages.course_message_id=users.id").
where("LOWER(concat(users.lastname, users.firstname)) LIKE ?", "%#{search_str}%") where("LOWER(concat(users.lastname, users.firstname)) LIKE ?", "%#{search_str}%")
if @course.try(:id) != 1309 || current_user.admin? || current_user.try(:id) == 15582 if @course.try(:id) != 1309 || current_user.admin_or_business? || current_user.try(:id) == 15582
teacher_list = @course.course_members.where("course_members.role in (1, 2, 3)") teacher_list = @course.course_members.where("course_members.role in (1, 2, 3)")
else else
teacher_list = @course.course_members.where("(course_members.role in (1, 3) or (course_members.user_id = #{current_user.id} teacher_list = @course.course_members.where("(course_members.role in (1, 3) or (course_members.user_id = #{current_user.id}
@ -838,7 +838,7 @@ class CoursesController < ApplicationController
# 已通过职业认证的教师复制课堂 # 已通过职业认证的教师复制课堂
def duplicate_course def duplicate_course
return tip_exception("没有复制权限") unless current_user.admin? || current_user.is_teacher? || current_user.teacher_of_course?(@course) return tip_exception("没有复制权限") unless current_user.admin_or_business? || current_user.is_teacher? || current_user.teacher_of_course?(@course)
return tip_exception("教师职业认证未通过") unless current_user.pro_certification? return tip_exception("教师职业认证未通过") unless current_user.pro_certification?
new_course = @course.self_duplicate new_course = @course.self_duplicate
@ -1280,7 +1280,7 @@ class CoursesController < ApplicationController
end end
if @all_members.size == 0 if @all_members.size == 0
normal_status(-1,"课堂暂时没有学生") normal_status(-1,"暂无学生数据")
elsif params[:export].present? && params[:export] elsif params[:export].present? && params[:export]
normal_status(0,"正在下载中") normal_status(0,"正在下载中")
else else
@ -1308,7 +1308,7 @@ class CoursesController < ApplicationController
end end
if @all_members.length == 0 if @all_members.length == 0
normal_status(-1,"课堂暂时没有学生") normal_status(-1,"暂无学生数据")
elsif params[:export].present? && params[:export] elsif params[:export].present? && params[:export]
normal_status(0,"正在下载中") normal_status(0,"正在下载中")
else else
@ -1404,7 +1404,7 @@ class CoursesController < ApplicationController
# Use callbacks to share common setup or constraints between actions. # Use callbacks to share common setup or constraints between actions.
def set_course def set_course
@course = Course.find_by!(id: params[:id]) @course = Course.find_by!(id: params[:id])
tip_exception(404, "") if @course.is_delete == 1 && !current_user.admin? tip_exception(404, "") if @course.is_delete == 1 && !current_user.admin_or_business?
end end
# Never trust parameters from the scary internet, only allow the white list through. # Never trust parameters from the scary internet, only allow the white list through.

@ -50,8 +50,11 @@ class ExaminationBanksController < ApplicationController
end end
def destroy def destroy
@exam.destroy! ActiveRecord::Base.transaction do
render_ok ApplyAction.where(container_type: "ExaminationBank", container_id: @exam.id).destroy_all
@exam.destroy!
render_ok
end
end end
def set_public def set_public

@ -372,7 +372,7 @@ class ExerciseBankQuestionsController < ApplicationController
private private
def bank_admin def bank_admin
tip_exception(403, "无权限") unless @exercise.user_id == current_user.id || current_user.admin? tip_exception(403, "无权限") unless @exercise.user_id == current_user.id || current_user.admin_or_business?
end end
def get_exercise def get_exercise

@ -26,7 +26,7 @@ class ExerciseBanksController < ApplicationController
search = params[:search] search = params[:search]
type = params[:type] type = params[:type]
# 超级管理员用户显示所有未隐藏的实训、非管理员显示所有已发布的实训(对本单位公开且未隐藏未关闭) # 超级管理员用户显示所有未隐藏的实训、非管理员显示所有已发布的实训(对本单位公开且未隐藏未关闭)
if current_user.admin? if current_user.admin_or_business?
@shixuns = Shixun.unhidden @shixuns = Shixun.unhidden
else else
none_shixun_ids = ShixunSchool.where("school_id != #{current_user.school_id}").pluck(:shixun_id) none_shixun_ids = ShixunSchool.where("school_id != #{current_user.school_id}").pluck(:shixun_id)
@ -67,7 +67,7 @@ class ExerciseBanksController < ApplicationController
end end
def bank_admin def bank_admin
tip_exception(403, "无权限") unless @bank.user_id == current_user.id || current_user.admin? tip_exception(403, "无权限") unless @bank.user_id == current_user.id || current_user.admin_or_business?
end end
#判断实训是否已选择 #判断实训是否已选择

@ -382,6 +382,7 @@ class GraduationWorksController < ApplicationController
tip_exception("成绩不能为空") if params[:score].blank? tip_exception("成绩不能为空") if params[:score].blank?
tip_exception("成绩不能小于零") if params[:score].to_f < 0 tip_exception("成绩不能小于零") if params[:score].to_f < 0
tip_exception("成绩不能大于100") if params[:score].to_f.round(1) > 100 tip_exception("成绩不能大于100") if params[:score].to_f.round(1) > 100
tip_exception("调分原因不能超过100个字符") if params[:comment].present? && params[:comment].length > 100
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
begin begin
# 分数不为空的历史评阅都置为失效 # 分数不为空的历史评阅都置为失效
@ -410,7 +411,7 @@ class GraduationWorksController < ApplicationController
# 删除教师/教辅的评分记录 # 删除教师/教辅的评分记录
def delete_score def delete_score
score = @work.graduation_work_scores.where(id: params[:comment_id]).first score = @work.graduation_work_scores.where(id: params[:comment_id]).first
if score.present? && (score.is_invalid || score.score.nil?) && (score.user == current_user || current_user.admin?) if score.present? && (score.is_invalid || score.score.nil?) && (score.user == current_user || current_user.admin_or_business?)
begin begin
score.destroy score.destroy
normal_status("删除成功") normal_status("删除成功")

@ -26,7 +26,7 @@ class GtopicBanksController < ApplicationController
end end
def bank_admin def bank_admin
tip_exception(403, "无权限") unless @bank.user_id == current_user.id || current_user.admin? tip_exception(403, "无权限") unless @bank.user_id == current_user.id || current_user.admin_or_business?
end end
def gtopic_bank_params def gtopic_bank_params

@ -47,7 +47,7 @@ class HomeworkBanksController < ApplicationController
end end
def bank_admin def bank_admin
tip_exception(403, "无权限") unless @bank.user_id == current_user.id || current_user.admin? tip_exception(403, "无权限") unless @bank.user_id == current_user.id || current_user.admin_or_business?
end end
def bank_params def bank_params

@ -145,7 +145,7 @@ class HomeworkCommonsController < ApplicationController
@student_works = @homework.teacher_works(@member) @student_works = @homework.teacher_works(@member)
@all_member_count = @student_works.size @all_member_count = @student_works.size
@score_open = true @score_open = true
elsif @user_course_identity > Course::STUDENT && @homework.work_public elsif @user_course_identity > Course::STUDENT
@student_works = student_works @student_works = student_works
@score_open = false @score_open = false
else else
@ -757,7 +757,7 @@ class HomeworkCommonsController < ApplicationController
search = params[:search] search = params[:search]
type = params[:type] type = params[:type]
# 超级管理员用户显示所有未隐藏的实训、非管理员显示所有已发布的实训(对本单位公开且未隐藏未关闭) # 超级管理员用户显示所有未隐藏的实训、非管理员显示所有已发布的实训(对本单位公开且未隐藏未关闭)
if current_user.admin? if current_user.admin_or_business?
@shixuns = Shixun.unhidden @shixuns = Shixun.unhidden
else else
none_shixun_ids = ShixunSchool.where("school_id != #{current_user.school_id}").pluck(:shixun_id) none_shixun_ids = ShixunSchool.where("school_id != #{current_user.school_id}").pluck(:shixun_id)

@ -31,8 +31,11 @@ class ItemBanksController < ApplicationController
end end
def destroy def destroy
@item.destroy! ActiveRecord::Base.transaction do
render_ok ApplyAction.where(container_type: "ItemBank", container_id: @item.id).destroy_all
@item.destroy!
render_ok
end
end end
def set_public def set_public

@ -144,6 +144,7 @@ class MemosController < ApplicationController
def reply def reply
tip_exception("parent_id不能为空") if params[:parent_id].blank? tip_exception("parent_id不能为空") if params[:parent_id].blank?
tip_exception("content不能为空") if params[:content].blank? tip_exception("content不能为空") if params[:content].blank?
tip_exception("content不能超过1000字符") if params[:content].length > 1000
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
begin begin

@ -63,6 +63,7 @@ class MessagesController < ApplicationController
def reply def reply
return normal_status(2, "回复内容不能为空") if params[:content].blank? return normal_status(2, "回复内容不能为空") if params[:content].blank?
return normal_status(2, "回复内容不能超过1000字符") if params[:content].length > 1000
@reply = Message.create!(board: @message.board, root_id: @message.root_id || @message.id, @reply = Message.create!(board: @message.board, root_id: @message.root_id || @message.id,
author: current_user, parent: @message, author: current_user, parent: @message,
message_detail_attributes: { message_detail_attributes: {
@ -126,7 +127,7 @@ class MessagesController < ApplicationController
end end
def create def create
return normal_status(403, "您没有权限进行该操作") unless current_user.admin? || current_user.member_of_course?(@board.course) return normal_status(403, "您没有权限进行该操作") unless current_user.admin_or_business? || current_user.member_of_course?(@board.course)
begin begin
@message = Message.new(message_params) @message = Message.new(message_params)

@ -114,7 +114,7 @@ class PollBankQuestionsController < ApplicationController
private private
def bank_admin def bank_admin
tip_exception(403, "无权限") unless @poll.user_id == current_user.id || current_user.admin? tip_exception(403, "无权限") unless @poll.user_id == current_user.id || current_user.admin_or_business?
end end
def get_poll def get_poll

@ -10,7 +10,7 @@ class QuestionBanksController < ApplicationController
def bank_list def bank_list
page = params[:page] || 1 page = params[:page] || 1
limit = params[:limit] || 15 limit = params[:limit] || 15
@certification_teacher = current_user.is_certification_teacher || current_user.admin? @certification_teacher = current_user.is_certification_teacher || current_user.admin_or_business?
@objects = @object_type.classify.constantize.where(@object_filter) @objects = @object_type.classify.constantize.where(@object_filter)
@objects = @objects =
if params[:search] if params[:search]
@ -134,7 +134,7 @@ class QuestionBanksController < ApplicationController
def destroy def destroy
bank = current_bank bank = current_bank
unless current_user.admin? || bank.user_id == current_user.id unless current_user.admin_or_business? || bank.user_id == current_user.id
render_forbidden render_forbidden
return return
end end
@ -165,7 +165,7 @@ class QuestionBanksController < ApplicationController
def object_banks def object_banks
banks ||= @object_type.classify.constantize.where(@object_filter).where(id: params[:object_id]) banks ||= @object_type.classify.constantize.where(@object_filter).where(id: params[:object_id])
unless current_user.admin? unless current_user.admin_or_business?
banks = banks.where(user_id: current_user.id) banks = banks.where(user_id: current_user.id)
end end
banks banks
@ -202,7 +202,7 @@ class QuestionBanksController < ApplicationController
end end
def teacher_or_admin def teacher_or_admin
tip_exception(403, "无权限操作") unless current_user.is_certification_teacher || current_user.admin? tip_exception(403, "无权限操作") unless current_user.is_certification_teacher || current_user.admin_or_business?
end end
def quote_homework_bank homework, course def quote_homework_bank homework, course

@ -546,6 +546,7 @@ class StudentWorksController < ApplicationController
tip_exception("成绩不能为空") if params[:score].blank? tip_exception("成绩不能为空") if params[:score].blank?
tip_exception("成绩不能小于零") if params[:score].to_f < 0 tip_exception("成绩不能小于零") if params[:score].to_f < 0
tip_exception("成绩不能大于100") if params[:score].to_f.round(1) > 100 tip_exception("成绩不能大于100") if params[:score].to_f.round(1) > 100
tip_exception("调分原因不能超过100个字符") if params[:comment].present? && params[:comment].length > 100
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
begin begin
# 分数不为空的历史评阅都置为失效 # 分数不为空的历史评阅都置为失效

@ -456,6 +456,25 @@ class SubjectsController < ApplicationController
end end
end end
def statistics_new
# data = Subjects::DataStatisticService.new(@subject)
# Rails.logger.info("study_count: #{data.study_count}")
# Rails.logger.info("course_study_count: #{ data.course_study_count}")
# Rails.logger.info("passed_count: #{data.passed_count}")
# Rails.logger.info("course_used_count: #{data.course_used_count}")
# Rails.logger.info("school_used_count: #{data.school_used_count}")
# data_1 = Subjects::CourseUsedInfoService.call(@subject)
# Rails.logger.info("study_count: #{data_1}")
# data_2 = Subjects::ShixunUsedInfoService.call(@subject)
# Rails.logger.info("study_count: #{data_2}")
data_3 = Subjects::UserUsedInfoService.call(@subject)
Rails.logger.info("study_count: #{data_3}")
render_ok()
end
def shixun_report def shixun_report
end end

@ -29,7 +29,7 @@ class TaskBanksController < ApplicationController
end end
def bank_admin def bank_admin
tip_exception(403, "无权限") unless @bank.user_id == current_user.id || current_user.admin? tip_exception(403, "无权限") unless @bank.user_id == current_user.id || current_user.admin_or_business?
end end
def gtask_bank_params def gtask_bank_params

@ -66,9 +66,9 @@ class Users::QuestionBanksController < Users::BaseController
def check_user_permission! def check_user_permission!
if params[:type] == 'publicly' if params[:type] == 'publicly'
normal_status(-2,"未通过职业认证") unless User.current.admin? || User.current.certification_teacher? normal_status(-2,"未通过职业认证") unless User.current.admin_or_business? || User.current.certification_teacher?
else else
render_forbidden unless User.current.admin? || User.current.is_teacher? render_forbidden unless User.current.admin_or_business? || User.current.is_teacher?
end end
end end
end end

@ -39,7 +39,7 @@ class Weapps::CoursesController < Weapps::BaseController
@page = (params[:page] || 1).to_i @page = (params[:page] || 1).to_i
@limit = (params[:limit] || 20).to_i @limit = (params[:limit] || 20).to_i
search = params[:search].present? ? params[:search].strip : "" search = params[:search].present? ? params[:search].strip : ""
if @course.try(:id) != 1309 || current_user.admin? || current_user.try(:id) == 15582 if @course.try(:id) != 1309 || current_user.admin_or_business? || current_user.try(:id) == 15582
@teacher_list = @course.course_members.joins(:user).where("course_members.role in (1, 2, 3)") @teacher_list = @course.course_members.joins(:user).where("course_members.role in (1, 2, 3)")
else else
@teacher_list = @course.course_members.joins(:user).where("(course_members.role in (1, 3) or (course_members.user_id = #{current_user.id} @teacher_list = @course.course_members.joins(:user).where("(course_members.role in (1, 3) or (course_members.user_id = #{current_user.id}
@ -203,6 +203,6 @@ class Weapps::CoursesController < Weapps::BaseController
def set_course def set_course
@course = Course.find_by!(id: params[:id]) @course = Course.find_by!(id: params[:id])
tip_exception(404, "") if @course.is_delete == 1 && !current_user.admin? tip_exception(404, "") if @course.is_delete == 1 && !current_user.admin_or_business?
end end
end end

@ -47,9 +47,10 @@ module ExportHelper
user_name = user.real_name user_name = user.real_name
user_mail = user.mail user_mail = user.mail
user_stu_id = user.student_id.present? ? (user.student_id.to_s + "\t") : "--" user_stu_id = user.student_id.present? ? (user.student_id.to_s + "\t") : "--"
user_grade = user.grade
user_school = user.school_name user_school = user.school_name
user_course_group = u.course_group_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_info_array = [user_name,user_login,user_mail,user_stu_id,user_grade,user_school,user_course_group] #用户的信息集合
user_work_scores = [] user_work_scores = []
#学生总成绩 #学生总成绩
@ -150,7 +151,7 @@ module ExportHelper
course_user_score_title = "学生总成绩" course_user_score_title = "学生总成绩"
score_title_cells = shixun_titles + common_titles + group_titles + task_titles + exercise_titles score_title_cells = shixun_titles + common_titles + group_titles + task_titles + exercise_titles
score_title_counts = [shixun_titles.count,common_titles.count,group_titles.count,task_titles.count,exercise_titles.count] score_title_counts = [shixun_titles.count,common_titles.count,group_titles.count,task_titles.count,exercise_titles.count]
score_cell_head = %w(序号 真实姓名 登录名 邮箱 学号 学校 分班 个人总成绩) + score_title_cells score_cell_head = %w(序号 真实姓名 登录名 邮箱 学号 金币 学校 分班 个人总成绩) + score_title_cells
@course_user_scores = [course_user_score_title,score_cell_head,score_title_counts,total_user_score_array] @course_user_scores = [course_user_score_title,score_cell_head,score_title_counts,total_user_score_array]
#作业的全部集合 #作业的全部集合

@ -28,6 +28,9 @@ class Challenge < ApplicationRecord
scope :fields_for_list, -> { select([:id, :subject, :st, :score, :position, :shixun_id]) } scope :fields_for_list, -> { select([:id, :subject, :st, :score, :position, :shixun_id]) }
validates :task_pass, length: { maximum: 10000 }
after_commit :create_diff_record after_commit :create_diff_record
def next_challenge def next_challenge

@ -3,6 +3,8 @@ class ChallengeAnswer < ApplicationRecord
belongs_to :challenge belongs_to :challenge
has_many :game_answers, :dependent => :destroy has_many :game_answers, :dependent => :destroy
validates :contents, length: { maximum: 5000 }
def view_answer_time(user_id) def view_answer_time(user_id)
game_answers.where(user_id: user_id).last&.view_time game_answers.where(user_id: user_id).last&.view_time
end end

@ -3,4 +3,7 @@ class ChallengeChoose < ApplicationRecord
belongs_to :challenge, optional: true belongs_to :challenge, optional: true
has_many :challenge_tags, :dependent => :destroy has_many :challenge_tags, :dependent => :destroy
has_many :challenge_questions, dependent: :destroy has_many :challenge_questions, dependent: :destroy
validates :subject, length: { maximum: 1000 }
end end

@ -1,3 +1,6 @@
class ChallengeQuestion < ApplicationRecord class ChallengeQuestion < ApplicationRecord
belongs_to :challenge_choose belongs_to :challenge_choose
validates :option_name, length: { maximum: 500 }
end end

@ -33,6 +33,8 @@ class Competition < ApplicationRecord
has_many :competition_prizes, dependent: :destroy has_many :competition_prizes, dependent: :destroy
has_many :competition_prize_users, dependent: :destroy has_many :competition_prize_users, dependent: :destroy
validates :introduction, length: { maximum: 500 }
before_save :set_laboratory before_save :set_laboratory
after_create :create_competition_modules after_create :create_competition_modules

@ -5,4 +5,6 @@ class CompetitionModuleMdContent < ApplicationRecord
# validates :name, presence: true # validates :name, presence: true
validates :content, presence: true validates :content, presence: true
validates :content, length: { maximum: 10000 }
end end

@ -251,7 +251,7 @@ class Course < ApplicationRecord
member = course_member(user.id) member = course_member(user.id)
group_ids = if member.present? group_ids = if member.present?
member.teacher_course_groups.size > 0 ? member.teacher_course_groups.pluck(:course_group_id) : course_groups.pluck(:id) member.teacher_course_groups.size > 0 ? member.teacher_course_groups.pluck(:course_group_id) : course_groups.pluck(:id)
elsif user.admin? elsif user.admin_or_business?
course_groups.pluck(:id) course_groups.pluck(:id)
else else
[] []

@ -13,6 +13,8 @@ class Discuss < ApplicationRecord
belongs_to :challenge, optional: true belongs_to :challenge, optional: true
validate :validate_sensitive_string validate :validate_sensitive_string
validates :content, length: { maximum: 1000 }
after_create :send_tiding after_create :send_tiding
scope :children, -> (discuss_id){ where(parent_id: discuss_id).includes(:user).reorder(created_at: :asc) } scope :children, -> (discuss_id){ where(parent_id: discuss_id).includes(:user).reorder(created_at: :asc) }

@ -20,6 +20,7 @@ class Exercise < ApplicationRecord
where("exercise_name LIKE ?", "%#{keywords}%") unless keywords.blank?} where("exercise_name LIKE ?", "%#{keywords}%") unless keywords.blank?}
validates :exercise_name, length: { maximum: 60, too_long: "60 characters is the maximum allowed" } validates :exercise_name, length: { maximum: 60, too_long: "60 characters is the maximum allowed" }
validates :exercise_description, length: { maximum: 100 }
after_create :create_exercise_list after_create :create_exercise_list

@ -11,4 +11,6 @@ class ExerciseAnswer < ApplicationRecord
scope :exercise_answer_is_right, -> {where("score > ?",0.0)} #判断答案是否正确根据分数总和大于0 scope :exercise_answer_is_right, -> {where("score > ?",0.0)} #判断答案是否正确根据分数总和大于0
scope :score_reviewed, lambda {where("score >= ?",0.0)} #是否评分,用于判断主观题的 scope :score_reviewed, lambda {where("score >= ?",0.0)} #是否评分,用于判断主观题的
validates :answer_text, length: { maximum: 5000 }
end end

@ -6,4 +6,6 @@ class ExerciseAnswerComment < ApplicationRecord
belongs_to :exercise_answer, optional: true belongs_to :exercise_answer, optional: true
scope :search_answer_comments, lambda {|name,ids| where("#{name}":ids)} scope :search_answer_comments, lambda {|name,ids| where("#{name}":ids)}
validates :comment, length: { maximum: 100 }
end end

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

@ -11,6 +11,8 @@ class ExerciseBankQuestion < ApplicationRecord
scope :left_question_choose, lambda {|k,v| where("#{k} > ?",v)} #根据传入的参数查找问题 scope :left_question_choose, lambda {|k,v| where("#{k} > ?",v)} #根据传入的参数查找问题
scope :find_objective_questions, -> {where("question_type != ?",4)} #查找全部客观题 scope :find_objective_questions, -> {where("question_type != ?",4)} #查找全部客观题
validates :question_title, length: { maximum: 1000 }
def question_type_name def question_type_name
case self.question_type case self.question_type
when 0 when 0

@ -3,4 +3,7 @@ class ExerciseBankStandardAnswer < ApplicationRecord
belongs_to :exercise_bank_choice belongs_to :exercise_bank_choice
#attr_accessible :answer_text #attr_accessible :answer_text
scope :standard_by_ids, lambda { |s| where(exercise_bank_choice_id: s) } scope :standard_by_ids, lambda { |s| where(exercise_bank_choice_id: s) }
validates :answer_text, length: { maximum: 5000 }
end end

@ -7,4 +7,6 @@ class ExerciseChoice < ApplicationRecord
scope :find_choice_custom, lambda {|k,v| where("#{k} = ?",v)} #根据传入的参数查找问题 scope :find_choice_custom, lambda {|k,v| where("#{k} = ?",v)} #根据传入的参数查找问题
scope :left_choice_choose, lambda {|k,v| where("#{k} > ?",v)} #根据传入的参数查找问题 scope :left_choice_choose, lambda {|k,v| where("#{k} > ?",v)} #根据传入的参数查找问题
validates :choice_text, length: { maximum: 500 }
end end

@ -16,6 +16,8 @@ class ExerciseQuestion < ApplicationRecord
scope :left_question_choose, lambda {|k,v| where("#{k} > ?",v)} #根据传入的参数查找问题 scope :left_question_choose, lambda {|k,v| where("#{k} > ?",v)} #根据传入的参数查找问题
scope :find_objective_questions, -> {where("question_type != ?",4)} #查找全部客观题 scope :find_objective_questions, -> {where("question_type != ?",4)} #查找全部客观题
validates :question_title, length: { maximum: 1000 }
def question_type_name def question_type_name
case self.question_type case self.question_type

@ -6,5 +6,5 @@ class ExerciseStandardAnswer < ApplicationRecord
scope :find_standard_answer_custom, lambda {|k,v| where("#{k} = ?",v)} #根据传入的参数查找问题 scope :find_standard_answer_custom, lambda {|k,v| where("#{k} = ?",v)} #根据传入的参数查找问题
scope :standard_by_ids, lambda { |s| where(exercise_choice_id: s) } scope :standard_by_ids, lambda { |s| where(exercise_choice_id: s) }
validates :answer_text, length: { maximum: 5000 }
end end

@ -55,7 +55,7 @@ class GraduationWork < ApplicationRecord
end end
def delete_atta atta def delete_atta atta
last_score = graduation_work_scores.where.not(score: nil).last last_score = graduation_work_scores.last
(atta.author_id == User.current.id) && (last_score.blank? || last_score.try(:created_at) < atta.created_on) (atta.author_id == User.current.id) && (last_score.blank? || last_score.try(:created_at) < atta.created_on)
end end

@ -5,5 +5,5 @@ class GraduationWorkScore < ApplicationRecord
belongs_to :graduation_task belongs_to :graduation_task
has_many :attachments, as: :container, dependent: :destroy has_many :attachments, as: :container, dependent: :destroy
validates :comment, length: { maximum: 2000 } validates :comment, length: { maximum: 1000 }
end end

@ -9,4 +9,6 @@ class GtaskBank < ApplicationRecord
scope :myself, ->(user_id) { where(user_id: user_id)} scope :myself, ->(user_id) { where(user_id: user_id)}
scope :is_public, -> { where(:is_public => true) } scope :is_public, -> { where(:is_public => true) }
validates :name, length: { maximum: 60 }
validates :description, length: { maximum: 5000 }
end end

@ -7,4 +7,11 @@ class GtopicBank < ApplicationRecord
has_many :graduation_topics, dependent: :nullify has_many :graduation_topics, dependent: :nullify
scope :myself, ->(user_id) { where(user_id: user_id)} scope :myself, ->(user_id) { where(user_id: user_id)}
# 课题名称和描述字段长度限制
validates :name, length: { maximum: 60,
too_long: "60 characters is the maximum allowed" }
validates :description, length: { maximum: 5000,
too_long: "5000 characters is the maximum allowed" }
end end

@ -3,6 +3,7 @@ class Hack < ApplicationRecord
# diffcult: 难度 1简单2中等 3困难 # diffcult: 难度 1简单2中等 3困难
# 编程题 # 编程题
validates_length_of :name, maximum: 60 validates_length_of :name, maximum: 60
validates_length_of :description, maximum: 5000
validates :description, presence: { message: "描述不能为空" } validates :description, presence: { message: "描述不能为空" }
validates :name, presence: { message: "名称不能为空" } validates :name, presence: { message: "名称不能为空" }
# 测试集 # 测试集

@ -1,4 +1,6 @@
class HackSet < ApplicationRecord class HackSet < ApplicationRecord
validates_length_of :input, maximum: 500
validates_length_of :output, maximum: 500
validates :input, presence: { message: "测试集输入不能为空" } validates :input, presence: { message: "测试集输入不能为空" }
validates :output, presence: { message: "测试集输出不能为空" } validates :output, presence: { message: "测试集输出不能为空" }
validates_uniqueness_of :input, scope: [:hack_id, :input], message: "多个测试集的输入不能相同" validates_uniqueness_of :input, scope: [:hack_id, :input], message: "多个测试集的输入不能相同"

@ -10,4 +10,7 @@ class HomeworkBank < ApplicationRecord
scope :is_public, -> { where(is_public: true)} scope :is_public, -> { where(is_public: true)}
scope :myself, ->(user_id) { where(user_id: user_id)} scope :myself, ->(user_id) { where(user_id: user_id)}
validates :name, length: { maximum: 60 }
validates :description, length: { maximum: 15000 }
validates :reference_answer, length: { maximum: 15000 }
end end

@ -24,7 +24,9 @@ class JournalsForMessage < ApplicationRecord
# "m_reply_count", # 留言的回复数量 # "m_reply_count", # 留言的回复数量
# "m_reply_id" , # 回复某留言的留言id(a留言回复了b留言这是b留言的id) # "m_reply_id" , # 回复某留言的留言id(a留言回复了b留言这是b留言的id)
# "is_comprehensive_evaluation", # 1 教师评论、2 匿评、3 留言 # "is_comprehensive_evaluation", # 1 教师评论、2 匿评、3 留言
# "hidden", 隐藏 # "hidden", 隐藏、
validates :notes, length: { maximum: 1000 }
after_create :send_tiding after_create :send_tiding

@ -13,6 +13,7 @@ class Library < ApplicationRecord
has_one :praise_tread_cache, foreign_key: :object_id has_one :praise_tread_cache, foreign_key: :object_id
has_many :praise_treads, as: :praise_tread_object, dependent: :destroy has_many :praise_treads, as: :praise_tread_object, dependent: :destroy
validates :content, length: { maximum: 5000 }
validates :uuid, presence: true, uniqueness: true validates :uuid, presence: true, uniqueness: true

@ -27,6 +27,8 @@ class Memo < ApplicationRecord
scope :hot, -> { order("all_replies_count desc, updated_at desc") } scope :hot, -> { order("all_replies_count desc, updated_at desc") }
scope :posts, -> { where(root_id: nil, forum_id: [3, 5]) } scope :posts, -> { where(root_id: nil, forum_id: [3, 5]) }
validates :content, length: { maximum: 10000 }
after_create :send_tiding after_create :send_tiding
# 帖子的回复 # 帖子的回复
@ -39,6 +41,13 @@ class Memo < ApplicationRecord
Memo.where(parent_id: id).includes(:author).reorder("created_at asc") Memo.where(parent_id: id).includes(:author).reorder("created_at asc")
end end
# 主贴的名称
def main_subject
memo = Memo.find_by(root_id: id)
Rails.logger.info("###############memo: #{memo&.subject}")
memo ? memo.subject : subject
end
private private
def send_tiding def send_tiding

@ -39,6 +39,12 @@ class Message < ApplicationRecord
message_detail.update_attributes(content: content) message_detail.update_attributes(content: content)
end end
# 主贴的名称
def main_subject
Rails.logger.info("##########parent: #{parent&.subject}")
parent.present? ? parent.subject : subject
end
def copy_attachments_to_new_message(new_message, user) def copy_attachments_to_new_message(new_message, user)
attachments.each do |attach| attachments.each do |attach|
new_message.attachments << Attachment.new(attach.attributes.except("id").merge( new_message.attachments << Attachment.new(attach.attributes.except("id").merge(

@ -1,4 +1,5 @@
class MessageDetail < ApplicationRecord class MessageDetail < ApplicationRecord
belongs_to :message, :touch => true belongs_to :message, :touch => true
validates :content, length: { maximum: 5000 }
end end

@ -5,6 +5,7 @@ class Myshixun < ApplicationRecord
has_one :shixun_modify, :dependent => :destroy has_one :shixun_modify, :dependent => :destroy
belongs_to :user belongs_to :user
belongs_to :user_extension, foreign_key: :user_id
belongs_to :shixun, counter_cache: true belongs_to :shixun, counter_cache: true
has_one :last_executable_task, -> { where(status: [0, 1]).reorder(created_at: :asc) }, class_name: 'Game' has_one :last_executable_task, -> { where(status: [0, 1]).reorder(created_at: :asc) }, class_name: 'Game'
@ -21,7 +22,7 @@ class Myshixun < ApplicationRecord
end end
def output_times def output_times
games.pluck(:evaluate_count).sum.to_i games.map(&:evaluate_count).sum.to_i
end end
def repo_path def repo_path

@ -25,6 +25,7 @@ class Poll < ApplicationRecord
where("polls_name LIKE ?", "%#{keywords}%") unless keywords.blank?} where("polls_name LIKE ?", "%#{keywords}%") unless keywords.blank?}
validates :polls_name, length: { maximum: 60, too_long: "60 characters is the maximum allowed" } validates :polls_name, length: { maximum: 60, too_long: "60 characters is the maximum allowed" }
validates :polls_description, length: { maximum: 100 }
after_create :create_polls_list after_create :create_polls_list

@ -8,4 +8,6 @@ class PollAnswer < ApplicationRecord
scope :find_answer_by_custom, lambda {|k,v| where("#{k}":v)} #根据传入的参数查找问题 scope :find_answer_by_custom, lambda {|k,v| where("#{k}":v)} #根据传入的参数查找问题
scope :left_answer_choose, lambda {|k,v| where("#{k} > ?",v)} #根据传入的参数查找问题 scope :left_answer_choose, lambda {|k,v| where("#{k} > ?",v)} #根据传入的参数查找问题
validates :answer_text, length: { maximum: 500 }
end end

@ -9,6 +9,8 @@ class PollQuestion < ApplicationRecord
scope :ques_necessary, -> {where("is_necessary = ?",1)} scope :ques_necessary, -> {where("is_necessary = ?",1)}
scope :insert_question, lambda {|k| where("question_number > ?",k)} scope :insert_question, lambda {|k| where("question_number > ?",k)}
validates :question_title, length: { maximum: 1000 }
def question_type_name def question_type_name
case self.question_type case self.question_type
when 1 when 1

@ -8,4 +8,7 @@ class PollVote < ApplicationRecord
scope :find_current_vote,lambda {|k,v| where("#{k}": v)} scope :find_current_vote,lambda {|k,v| where("#{k}": v)}
scope :find_vote_text,-> {where("vote_text IS NOT NULL")} scope :find_vote_text,-> {where("vote_text IS NOT NULL")}
validates :vote_text, length: { maximum: 5000 }
end end

@ -30,6 +30,8 @@ class Shixun < ApplicationRecord
has_one :first_tag_repertoire, through: :first_shixun_tag_repertoire, source: :tag_repertoire has_one :first_tag_repertoire, through: :first_shixun_tag_repertoire, source: :tag_repertoire
has_many :homework_commons_shixuns, class_name: 'HomeworkCommonsShixun' has_many :homework_commons_shixuns, class_name: 'HomeworkCommonsShixun'
has_many :homework_commons, through: :homework_commons_shixuns
has_many :fork_shixuns, foreign_key: "fork_from", class_name: 'Shixun' has_many :fork_shixuns, foreign_key: "fork_from", class_name: 'Shixun'
#实训的关卡 #实训的关卡
@ -59,6 +61,9 @@ class Shixun < ApplicationRecord
# Jupyter数据集,附件 # Jupyter数据集,附件
has_many :data_sets, ->{where(attachtype: 2)}, class_name: 'Attachment', as: :container, dependent: :destroy has_many :data_sets, ->{where(attachtype: 2)}, class_name: 'Attachment', as: :container, dependent: :destroy
# 试卷的实训题
has_many :exercise_questions
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}%") }

@ -4,6 +4,8 @@ class ShixunInfo < ApplicationRecord
validates_length_of :fork_reason, maximum: 60 validates_length_of :fork_reason, maximum: 60
after_commit :create_diff_record after_commit :create_diff_record
validates :description, length: { maximum: 5000 }
private private
def create_diff_record def create_diff_record

@ -2,4 +2,6 @@ class ShixunWorkComment < ApplicationRecord
belongs_to :student_work belongs_to :student_work
belongs_to :user belongs_to :user
belongs_to :challenge, optional: true belongs_to :challenge, optional: true
validates :comment, length: { maximum: 500 }
validates :hidden_comment, length: { maximum: 500 }
end end

@ -7,5 +7,5 @@ class Stage < ApplicationRecord
has_many :shixuns, :through => :stage_shixuns has_many :shixuns, :through => :stage_shixuns
validates :name, length: { maximum: 60 } validates :name, length: { maximum: 60 }
validates :description, length: { maximum: 300 } validates :description, length: { maximum: 1000 }
end end

@ -105,7 +105,7 @@ class StudentWork < ApplicationRecord
end end
def delete_atta atta def delete_atta atta
last_score = student_works_scores.where.not(score: nil).last last_score = student_works_scores.last
(atta.author_id == User.current.id) && (last_score.blank? || last_score.try(:created_at) < atta.created_on) (atta.author_id == User.current.id) && (last_score.blank? || last_score.try(:created_at) < atta.created_on)
end end

@ -7,7 +7,7 @@ class StudentWorksScore < ApplicationRecord
has_many :tidings, as: :container, dependent: :destroy has_many :tidings, as: :container, dependent: :destroy
has_many :attachments, as: :container, dependent: :destroy has_many :attachments, as: :container, dependent: :destroy
validates :comment, length: { maximum: 2000 } validates :comment, length: { maximum: 1000 }
scope :shixun_comment, lambda { where(is_ultimate: 0) } scope :shixun_comment, lambda { where(is_ultimate: 0) }
@ -17,7 +17,7 @@ class StudentWorksScore < ApplicationRecord
end end
def allow_delete current_user def allow_delete current_user
(self.is_invalid || self.score.nil?) && (current_user == self.user || current_user.admin?) (self.is_invalid || self.score.nil?) && (current_user == self.user || current_user.admin_or_business?)
end end
# 匿评分 # 匿评分

@ -25,6 +25,11 @@ class Subject < ApplicationRecord
has_many :courses, -> { where("is_delete = 0").order("courses.created_at ASC") } has_many :courses, -> { where("is_delete = 0").order("courses.created_at ASC") }
has_many :laboratory_subjects, dependent: :destroy has_many :laboratory_subjects, dependent: :destroy
# 学习统计
has_one :subject_record, dependent: :destroy
has_many :subject_course_records, dependent: :destroy
has_many :subject_shixun_infos, dependent: :destroy
has_many :subject_user_infos, dependent: :destroy
validates :name, length: { maximum: 60 } validates :name, length: { maximum: 60 }
validates :description, length: { maximum: 8000 } validates :description, length: { maximum: 8000 }

@ -0,0 +1,3 @@
class SubjectCourseRecord < ApplicationRecord
belongs_to :subject
end

@ -0,0 +1,3 @@
class SubjectRecord < ApplicationRecord
belongs_to :subject
end

@ -0,0 +1,3 @@
class SubjectShixunInfo < ApplicationRecord
belongs_to :subject
end

@ -0,0 +1,3 @@
class SubjectUserInfo < ApplicationRecord
belongs_to :subject
end

@ -1,3 +1,7 @@
class TestSet < ApplicationRecord class TestSet < ApplicationRecord
# match_rule: 匹配规则: full 完全匹配, last 末尾匹配 # match_rule: 匹配规则: full 完全匹配, last 末尾匹配
#
validates :input, length: { maximum: 5000 }
validates :input, length: { maximum: 5000 }
end end

@ -43,6 +43,7 @@ class User < ApplicationRecord
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
has_many :games, :dependent => :destroy
has_many :study_shixuns, through: :myshixuns, source: :shixun # 已学习的实训 has_many :study_shixuns, through: :myshixuns, source: :shixun # 已学习的实训
has_many :course_messages has_many :course_messages
has_many :courses, foreign_key: 'tea_id', dependent: :destroy has_many :courses, foreign_key: 'tea_id', dependent: :destroy

@ -58,7 +58,7 @@ class DiscussesService
praise_count: 0, position: params[:position], challenge_id: params[:challenge_id], hidden: !current_user.admin? praise_count: 0, position: params[:position], challenge_id: params[:challenge_id], hidden: !current_user.admin?
) )
# 发送手机通知 # 发送手机通知
Educoder::Sms.send(mobile:'18173242757', send_type:'discuss', name:'管理员') # Educoder::Sms.send(mobile:'18173242757', send_type:'discuss', name:'管理员')
rescue Exception => e rescue Exception => e
raise(e.message) raise(e.message)
end end

@ -0,0 +1,40 @@
class Subjects::CourseUsedInfoService < ApplicationService
attr_reader :subject
def initialize(subject)
@subject = subject
@shixun_ids = subject.shixuns.pluck(:id)
end
def call
return if subject.blank?
homework_commons =
HomeworkCommon.joins(:homework_commons_shixun)
.where(homework_type: %i[practice])
.where(homework_commons_shixuns: {shixun_id: @shixun_ids})
course_ids = homework_commons.pluck(:course_id)
homework_common_ids = homework_commons.pluck("homework_commons.id")
schools = School.joins(:courses).where(courses: {id: course_ids}).group("schools.id").select("schools.*, count(courses.id) course_count")
# name将该课程使用到课堂的单位
# course_count: 将该课程使用到课堂的数量
# student_count: 课堂的学生总数(去掉重复)
# choice_shixun_num: 选用该课程实训的个数(去重)
# choice_shixun_frequency: 选用该课程实训的次数
course_info = []
schools.map do |school|
name = school.name
course_count = school.course_count
student_count = school.courses.joins(:course_members).where(course_members: {role: 4, course_id: course_ids}).size
shixun_ids = school.courses.joins(homework_commons: :homework_commons_shixun)
.where(homework_commons: {id: homework_common_ids})
.pluck("homework_commons_shixuns.shixun_id")
choice_shixun_frequency = shixun_ids.size
choice_shixun_num = shixun_ids.uniq.size
course_info << {school_id: school.id, school_name: name, course_count: course_count, student_count: student_count,
choice_shixun_num: choice_shixun_num, choice_shixun_frequency: choice_shixun_frequency}
end
course_info
end
end

@ -0,0 +1,72 @@
class Subjects::DataStatisticService < ApplicationService
attr_reader :subject
def initialize(subject)
@subject = subject
@shixuns = subject.shixuns
@shixun_ids = @shixuns.pluck(:id)
end
# 学习总人数:
# 文案解释:学习该课程的全部人数(学习总人数=课堂学习人数+自主学习人数)
# 开发备注只要点击该课程的任何一个实训生成了tpi都算一个学习人数去重一个人数计算1次
def study_count
@shixuns.joins(:myshixuns).pluck("myshixuns.user_id").uniq.size
end
# 课堂学习人数:
# 文案解释:通过课堂学习该课程的人数
# 开发备注只要通过课堂进入并点击了实训生成了tpi则算一个可以学习人数去重一个人数计算1次
def course_study_count
# 实训作业
sw_user_ids = StudentWork.where.not(myshixun_id: 0).joins(homework_common: :homework_commons_shixun)
.where(homework_commons_shixuns: {shixun_id: @shixun_ids}).pluck("student_works.user_id")
# 试卷的实训题
esa_user_ids = ExerciseShixunAnswer.joins(exercise_shixun_challenge: :shixun)
.where(shixuns: {id: @shixun_ids}).pluck("exercise_shixun_answers.user_id")
(sw_user_ids + esa_user_ids).uniq.size
end
# 自主学习人数:
# 文案解释:通过自主学习该课程的人数
# 开发备注非课程进入生成了实训的tpi去重。一个人数计算1次
def initiative_study
study_count - course_study_count
end
# 通关总人数:
# 文案解释:
# 通关该课程所有实训的人数去重。一个人数计算1次
def passed_count
@shixuns.includes(:myshixuns).where(myshixuns: {status: 1}).pluck("myshixuns.user_id").uniq.size
end
# 使用课堂数:
# 文案解释:使用该课程的课堂数量
# 开发备注课堂加入该课程的实训到自己课堂则算一个使用课堂数。去重一个课堂计算1次
def course_used_count
hc_course_ids =
HomeworkCommon.joins(:homework_commons_shixun)
.where(homework_type: %i[practice])
.where(homework_commons_shixuns: {shixun_id: @shixun_ids}).pluck("homework_commons.course_id").uniq
ex_course_ids =
Exercise.joins(:exercise_questions)
.where(exercise_questions: {question_type: 5, shixun_id: @shixun_ids}).pluck("exercises.course_id").uniq
(hc_course_ids + ex_course_ids).uniq.size
end
# 使用单位数:
# 文案解释:使用该课程的单位数量(包括自主学习者所在单位)
# 开发备注:凡事该单位有使用该课程的实训(自主学习+课堂使用)都算;(去重,一个单位计算一次)
def school_used_count
school_ids.size
end
private
def school_ids
@shixuns.joins(myshixuns: :user_extension).pluck("user_extensions.school_id").uniq
end
end

@ -0,0 +1,30 @@
class Subjects::ShixunUsedInfoService < ApplicationService
attr_reader :subject, :stages
def initialize(subject)
@subject = subject
@stages = subject.stages.includes(shixuns: [myshixuns: :games, homework_commons_shixuns: [homework_common: :course]])
end
def call
shixun_infos = []
stages.each do |stage|
position = stage.position
stage.shixuns.each_with_index do |shixun, index|
stage = "#{position}-#{index+1}"
name = shixun.name
challenge_count = shixun.challenges_count
course_count = shixun.homework_commons.map{|hc| hc.course_id}.uniq.size
school_count = shixun.homework_commons.map{|hc| hc.course&.school_id}.uniq.size
used_count = shixun.myshixuns_count
passed_count = shixun.myshixuns.select{|m| m.status == 1}.size
evaluate_count = shixun.myshixuns.map{|m| m.output_times }.sum
passed_ave_time = passed_count > 0 ? shixun.myshixuns.map{|m| m.total_cost_time}.sum : 0
shixun_infos << {stage: stage, name: name, challenge_count: challenge_count, course_count: course_count,
school_count: school_count, used_count: used_count, passed_count: passed_count,
evaluate_count: evaluate_count, passed_ave_time: passed_ave_time, shixun_id: shixun.id}
end
end
shixun_infos
end
end

@ -0,0 +1,28 @@
class Subjects::UserUsedInfoService < ApplicationService
attr_reader :subject, :shixun_ids
def initialize(subject)
@subject = subject
@shixun_ids = subject.shixuns.pluck(:id)
end
def call
users_info = []
users = User.includes(myshixuns: :games).where(myshixuns: {shixun_id: shixun_ids}, games: {status: 2})
users.each do |user|
myshixuns = user.myshixuns.select{|m| shixun_ids.include?(m.shixun_id)}
name = "#{user.lastname}#{user.firstname}"
passed_myshixun_count = myshixuns.select{|m| m.status == 1}.size
passed_games_count = myshixuns.map{|m| m.games.select{|g| g.status == 2}.size }.size
code_line_count = 0
evaluate_count = myshixuns.map{|m| m.output_times }.sum
cost_time = myshixuns.map{|m|m.total_cost_time }.sum
users_info << {user_id: user.id, name: name, passed_myshixun_count: passed_myshixun_count,
passed_games_count: passed_games_count, code_line_count: code_line_count,
evaluate_count: evaluate_count, cost_time: cost_time}
end
users_info
end
end

@ -23,20 +23,21 @@
<%= select_tag(:search_type, options_for_select(auto_trial_options), class: 'form-control') %> <%= select_tag(:search_type, options_for_select(auto_trial_options), class: 'form-control') %>
</div> </div>
<%= text_field_tag(:keyword, params[:keyword], class: 'form-control col-sm-2 ml-3', placeholder: '输入关键字搜索') %> <%= text_field_tag(:keyword, params[:keyword], class: 'form-control col-sm-2 ml-3', placeholder: '输入关键字搜索') %>
<div class="">
<a href="javascript:void(0)" class="btn btn-primary" id="shixuns-export" data-disable-with = '导出中...'>导出</a>
</div>
</div> </div>
<div class="d-flex mt-3"> <div class="d-flex mt-3">
<div class="form-group"> <div class="form-group flex-1">
<label for="status">fork原因</label> <label for="status">fork原因</label>
<% fork_status_options = [['全部', ''], ["全部fork实训", "Fork"], ["实训内容升级", 'Shixun'], ["课堂教学使用", 'Course'],["实践课程使用",'Subject'],["其他原因",'Other']] %> <% fork_status_options = [['全部', ''], ["全部fork实训", "Fork"], ["实训内容升级", 'Shixun'], ["课堂教学使用", 'Course'],["实践课程使用",'Subject'],["其他原因",'Other']] %>
<%= select_tag(:fork_status, options_for_select(fork_status_options), class: 'form-control') %> <%= select_tag(:fork_status, options_for_select(fork_status_options), class: 'form-control') %>
</div> </div>
<%= submit_tag('搜索', class: 'btn btn-primary ml-3','data-disable-with': '搜索中...') %> <div class="flex-1">
<%= link_to "清除", admins_shixuns_path,class: "btn btn-default",id:"shixuns-clear-search",'data-disable-with': '清除中...' %> <%= submit_tag('搜索', class: 'btn btn-primary ml-3','data-disable-with': '搜索中...') %>
<%= link_to "清除", admins_shixuns_path,class: "btn btn-default",id:"shixuns-clear-search",'data-disable-with': '清除中...' %>
</div>
<a href="javascript:void(0)" class="btn btn-primary" id="shixuns-export" data-disable-with = '导出中...'>导出</a>
</div> </div>
</div> </div>
<% end %> <% end %>

@ -2,7 +2,7 @@ if @bank.container_type == "Exercise"
json.exercise do json.exercise do
json.extract! @bank, :id, :name, :description, :is_public json.extract! @bank, :id, :name, :description, :is_public
end end
json.authorize @bank.user_id == current_user.id || current_user.admin? json.authorize @bank.user_id == current_user.id || current_user.admin_or_business?
json.partial! "exercises/exercise_scores" json.partial! "exercises/exercise_scores"
@ -21,7 +21,7 @@ else
json.poll do json.poll do
json.extract! @bank, :id, :name, :description, :is_public json.extract! @bank, :id, :name, :description, :is_public
end end
json.authorize @bank.user_id == current_user.id || current_user.admin? json.authorize @bank.user_id == current_user.id || current_user.admin_or_business?
json.question_types do json.question_types do
json.q_counts @poll_questions_count json.q_counts @poll_questions_count

@ -1,7 +1,7 @@
json.partial! "public_navigation", locals: {graduation: @task, course: @course} json.partial! "public_navigation", locals: {graduation: @task, course: @course}
json.description @task.description json.description @task.description
json.user_id @task.user_id json.user_id @task.user_id
json.authorize @task.user_id == current_user.id || current_user.admin? json.authorize @task.user_id == current_user.id || current_user.admin_or_business?
# 附件 # 附件
json.attachments @attachments do |attachment| json.attachments @attachments do |attachment|
json.partial! "attachments/attachment_simple", locals: {attachment: attachment} json.partial! "attachments/attachment_simple", locals: {attachment: attachment}

@ -15,7 +15,7 @@ json.comment_scores @comment_scores do |score|
json.score score.score json.score score.score
json.content score.comment json.content score.comment
json.is_invalid score.is_invalid json.is_invalid score.is_invalid
json.delete (@current_user == score.user || @current_user.admin?) && (score.is_invalid || score.score.nil?) json.delete (@current_user == score.user || @current_user.admin_or_business?) && (score.is_invalid || score.score.nil?)
json.attachments score.attachments do |atta| json.attachments score.attachments do |atta|
json.partial! "attachments/attachment_simple", locals: {attachment: atta, delete: false} json.partial! "attachments/attachment_simple", locals: {attachment: atta, delete: false}
end end

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

@ -1,5 +1,5 @@
json.(@bank, :id, :name, :description, :homework_type, :is_public, :min_num, :max_num, :base_on_project, :reference_answer) json.(@bank, :id, :name, :description, :homework_type, :is_public, :min_num, :max_num, :base_on_project, :reference_answer)
json.authorize @bank.user_id == current_user.id || current_user.admin? json.authorize @bank.user_id == current_user.id || current_user.admin_or_business?
json.attachments @bank_attachments do |attachment| json.attachments @bank_attachments do |attachment|
json.partial! "attachments/attachment_simple", locals: {attachment: attachment} json.partial! "attachments/attachment_simple", locals: {attachment: attachment}

@ -21,7 +21,7 @@ json.shixun_list do
json.pic url_to_avatar(obj) json.pic url_to_avatar(obj)
json.content highlights json.content highlights
json.level level_to_s(obj.trainee) json.level level_to_s(obj.trainee)
json.subjects obj.subjects.uniq do |subject| json.subjects obj.subjects.visible.unhidden.uniq do |subject|
json.(subject, :id, :name) json.(subject, :id, :name)
end end
end end

@ -11,7 +11,7 @@ json.update_user_name @is_evaluation ? "匿名" : @work.update_user.try(:real_na
json.update_atta @homework.late_duration && @is_author json.update_atta @homework.late_duration && @is_author
json.attachments @attachments do |atta| json.attachments @attachments do |atta|
json.partial! "attachments/attachment_simple", locals: {attachment: atta, delete: false, } json.partial! "attachments/attachment_simple", locals: {attachment: atta, delete: false }
end end
unless @is_evaluation unless @is_evaluation

@ -1,6 +1,6 @@
json.(@bank, :id, :name, :description, :task_type, :is_public) json.(@bank, :id, :name, :description, :task_type, :is_public)
# 附件 # 附件
json.authorize @bank.user_id == current_user.id || current_user.admin? json.authorize @bank.user_id == current_user.id || current_user.admin_or_business?
json.attachments @bank_attachments do |attachment| json.attachments @bank_attachments do |attachment|
json.partial! "attachments/attachment_simple", locals: {attachment: attachment} json.partial! "attachments/attachment_simple", locals: {attachment: attachment}
end end

@ -14,5 +14,5 @@ json.question_banks @question_banks do |question_bank|
json.course_list_name question_bank.course_list&.name json.course_list_name question_bank.course_list&.name
json.updated_at question_bank.updated_at json.updated_at question_bank.updated_at
json.solve_count @solve_count_map.fetch(question_bank.id, 0) json.solve_count @solve_count_map.fetch(question_bank.id, 0)
json.authorize question_bank.user_id == current_user.id || current_user.admin? json.authorize question_bank.user_id == current_user.id || current_user.admin_or_business?
end end

@ -394,6 +394,7 @@ Rails.application.routes.draw do
get 'cancel_publish' get 'cancel_publish'
get 'cancel_has_publish' get 'cancel_has_publish'
get 'statistics' get 'statistics'
get 'statistics_new'
get 'shixun_report' get 'shixun_report'
get 'school_report' get 'school_report'
post 'update_attr' post 'update_attr'

@ -0,0 +1,14 @@
class CreateSubjectRecords < ActiveRecord::Migration[5.2]
def change
create_table :subject_records do |t|
t.references :subject, unique: true
t.integer :study_count, default: 0
t.integer :course_study_count, default: 0
t.integer :initiative_study, default: 0
t.integer :passed_count, default: 0
t.integer :course_used_count, default: 0
t.integer :school_used_count, default: 0
t.timestamps
end
end
end

@ -0,0 +1,16 @@
class CreateSubjectCourseRecords < ActiveRecord::Migration[5.2]
def change
create_table :subject_course_records do |t|
t.references :subject
t.references :school
t.string :school_name
t.integer :course_count, default: 0
t.integer :student_count, default: 0
t.integer :choice_shixun_num, default: 0
t.integer :choice_shixun_frequency, default: 0
t.timestamps
end
add_index :subject_course_records, [:school_id, :subject_id], unique: true, name: "couse_and_school_index"
end
end

@ -0,0 +1,21 @@
class CreateSubjectShixunInfos < ActiveRecord::Migration[5.2]
def change
create_table :subject_shixun_infos do |t|
t.references :subject
t.references :shixun
t.string :stage
t.string :shixun_name
t.integer :challenge_count, default: 0
t.integer :course_count, default: 0
t.integer :school_count, default: 0
t.integer :used_count, default: 0
t.integer :passed_count, default: 0
t.integer :evaluate_count, default: 0
t.integer :passed_ave_time, default: 0
t.timestamps
end
add_index :subject_shixun_infos, [:shixun_id, :subject_id], unique: true
end
end

@ -0,0 +1,18 @@
class CreateSubjectUserInfos < ActiveRecord::Migration[5.2]
def change
create_table :subject_user_infos do |t|
t.references :user
t.references :subject
t.string :username
t.integer :passed_myshixun_count, default: 0
t.integer :passed_games_count, default: 0
t.integer :code_line_count, default: 0
t.integer :evaluate_count, default: 0
t.integer :cost_time, default: 0
t.timestamps
end
add_index :subject_user_infos, [:user_id, :subject_id], unique: true
end
end

@ -0,0 +1,11 @@
class AddUniqIndexToEvaluationDistribution < ActiveRecord::Migration[5.2]
def change
sql = %Q(delete from student_works_evaluation_distributions where (user_id, student_work_id) in
(select * from (select user_id, student_work_id from student_works_evaluation_distributions group by user_id, student_work_id having count(*) > 1) a)
and id not in (select * from (select min(id) from student_works_evaluation_distributions group by user_id, student_work_id having count(*) > 1 order by id) b))
ActiveRecord::Base.connection.execute sql
add_index :student_works_evaluation_distributions, [:student_work_id, :user_id], name: "index_on_student_work_id_and_user_id", unique: true
remove_index :student_works_evaluation_distributions, :user_id
end
end

@ -0,0 +1,5 @@
class ModifyMyshixunIdForStudentWorks < ActiveRecord::Migration[5.2]
def change
StudentWork.where(myshixun_id: nil).update_all(myshixun_id: 0)
end
end

@ -0,0 +1,111 @@
desc "统计实践课程的学习统计数据"
namespace :subjects do
task data_statistic: :environment do
puts("---------------------data_statistic_begin")
Rails.logger.info("---------------------data_statistic_begin")
subjects = Subject.where(status: 2)
subjects.find_each do |subject|
puts("---------------------data_statistic: #{subject.id}")
Rails.logger.info("---------------------data_statistic: #{subject.id}")
sr = SubjectRecord.find_or_create_by!(subject_id: subject.id)
data = Subjects::DataStatisticService.new(subject)
study_count = data.study_count
# 总人数没有变化的话,不同课堂之类的变化了
course_study_count = (study_count == sr.study_count ? sr.course_study_count : data.course_study_count)
passed_count = (study_count == sr.study_count ? sr.passed_count : data.passed_count)
course_used_count = (study_count == sr.study_count ? sr.course_used_count : data.course_used_count)
school_used_count = (study_count == sr.study_count ? sr.school_used_count : data.school_used_count)
update_params = {
study_count: study_count,
course_study_count: course_study_count,
initiative_study: (study_count - course_study_count),
passed_count: passed_count,
course_used_count: course_used_count,
school_used_count: school_used_count
}
sr.update_attributes!(update_params)
end
puts("---------------------data_statistic_end")
Rails.logger.info("---------------------data_statistic_end")
end
task course_info_statistic: :environment do
puts("---------------------course_info_statistic_begin")
Rails.logger.info("---------------------course_info_statistic_begin")
subjects = Subject.where(status: 2)
subjects.find_each do |subject|
puts("---------------------course_info_statistic: #{subject.id}")
Rails.logger.info("---------------------course_info_statistic: #{subject.id}")
data = Subjects::CourseUsedInfoService.call(subject)
data.each do |key|
scr = SubjectCourseRecord.find_or_create_by!(school_id: key[:school_id], subject_id: subject.id)
update_params = {
school_name: key[:school_name],
course_count: key[:course_count],
student_count: key[:student_count],
choice_shixun_num: key[:choice_shixun_num],
choice_shixun_frequency: key[:choice_shixun_frequency]
}
scr.update_attributes(update_params)
end
end
puts("---------------------course_info_statistic_end")
Rails.logger.info("---------------------course_info_statistic_end")
end
task shixun_info_statistic: :environment do
puts("---------------------shixun_info_statistic_begin")
Rails.logger.info("---------------------shixun_info_statistic_begin")
subjects = Subject.where(status: 2)
subjects.find_each(batch_size: 100) do |subject|
puts("---------------------shixun_info_statistic: #{subject.id}")
Rails.logger.info("---------------------shixun_info_statistic: #{subject.id}")
data = Subjects::ShixunUsedInfoService.call(subject)
data.each do |key|
ssi = SubjectShixunInfo.find_or_create_by!(shixun_id: key[:shixun_id], subject_id: subject.id)
update_params = {
stage: key[:stage],
shixun_name: key[:name],
challenge_count: key[:challenge_count],
course_count: key[:course_count],
school_count: key[:school_count],
used_count: key[:used_count],
passed_count: key[:passed_count],
evaluate_count: key[:evaluate_count],
passed_ave_time: key[:passed_ave_time]
}
ssi.update_attributes(update_params)
end
end
puts("---------------------shixun_info_statistic_end")
Rails.logger.info("---------------------shixun_info_statistic_end")
end
task user_info_statistic: :environment do
puts("---------------------user_info_statistic_begin")
Rails.logger.info("---------------------user_info_statistic_begin")
subjects = Subject.where(status: 2)
subjects.find_each(batch_size: 100) do |subject|
puts("---------------------user_info_statistic: #{subject.id}")
data = Subjects::UserUsedInfoService.call(subject)
data.each do |key|
sui = SubjectUserInfo.find_or_create_by!(user_id: key[:user_id], subject_id: subject.id)
update_params = {
username: key[:name],
passed_myshixun_count: key[:passed_myshixun_count],
passed_games_count: key[:passed_games_count],
code_line_count: key[:code_line_count],
evaluate_count: key[:evaluate_count],
cost_time: key[:cost_time]
}
sui.update_attributes(update_params)
end
end
puts("---------------------user_info_statistic_end")
Rails.logger.info("---------------------user_info_statistic_end")
end
end

@ -7,6 +7,18 @@
<!-- width=device-width, initial-scale=1 , shrink-to-fit=no --> <!-- width=device-width, initial-scale=1 , shrink-to-fit=no -->
<!-- <meta name="viewport" content=""> --> <!-- <meta name="viewport" content=""> -->
<meta name=”Keywords” Content=”EduCoder,信息技术实践教学,精品课程网,慕课MOOC″>
<meta name=”Keywords” Content=”实践课程,项目实战,java实训,python实战,人工智能技术,后端开发学习,移动开发入门″>
<meta name=”Keywords” Content=”翻转课堂,高效课堂创建,教学模式″>
<meta name=”Keywords” Content=”实训项目,python教程,C语言入门,java书,php后端开发,app前端开发,数据库技术″>
<meta name=”Keywords” Content=”在线竞赛,计算机应用大赛,编程大赛,大学生计算机设计大赛,全国高校绿色计算机大赛″>
<meta name=”Description” Content=”EduCoder是信息技术类实践教学平台。EduCoder涵盖了计算机、大数据、云计算、人工智能、软件工程、物联网等专业课程。超10000个实训案例及22000个技能评测点建立学、练、评、测一体化实验环境。”>
<meta name=”Description” Content=”EduCoder实践课程旨在于通过企业级实战实训案例帮助众多程序员提升各项业务能力。解决学生、学员、企业员工等程序设计能力、算法设计能力、问题求解能力、应用开发能力、系统运维能力等。”>
<meta name=”Description” Content=”EduCoder翻转课堂教学模式颠覆了传统教学模式让教师与学生的关系由“权威”变成了“伙伴”。将学习的主动权转交给学生使学生可个性化化学学生的学习主体得到了彰显。”>
<meta name=”Description” Content=”EduCoder实训项目为单个知识点关卡实践训练帮助学生巩固单一弱点强化学习。 >
<meta name=”Description” Content=”EduCoder实践教学平台各类大赛为进一步提高各类学生综合运用高级语言程序设计能力培养创新意识和实践探索精神发掘优秀软件人才。 >
<meta name="theme-color" content="#000000"> <meta name="theme-color" content="#000000">
<!--<meta http-equiv="cache-control" content="no-cache,no-store, must-revalidate" />--> <!--<meta http-equiv="cache-control" content="no-cache,no-store, must-revalidate" />-->
<!--<meta http-equiv="pragma" content="no-cache" />--> <!--<meta http-equiv="pragma" content="no-cache" />-->

@ -4,16 +4,17 @@
* @Github: * @Github:
* @Date: 2020-01-06 09:02:29 * @Date: 2020-01-06 09:02:29
* @LastEditors : tangjiang * @LastEditors : tangjiang
* @LastEditTime : 2020-01-09 11:58:52 * @LastEditTime : 2020-01-09 15:00:13
*/ */
import Quill from 'quill'; import Quill from 'quill';
// let Inline = Quill.import('blots/inline'); // let Inline = Quill.import('blots/inline');
const BlockEmbed = Quill.import('blots/block/embed'); const BlockEmbed = Quill.import('blots/embed');
class FillBlot extends BlockEmbed { class FillBlot extends BlockEmbed {
static create (value) { static create (value) {
const node = super.cerate(); const node = super.cerate(value);
// node.classList.add('icon icon-bianji2'); // node.classList.add('icon icon-bianji2');
// node.setAttribute('data-fill', 'fill'); // node.setAttribute('data-fill', 'fill');
console.log('编辑器值===》》》》》', value);
node.setAttribute('data_index', value.data_index); node.setAttribute('data_index', value.data_index);
node.nodeValue = value.text; node.nodeValue = value.text;
return node; return node;
@ -28,7 +29,7 @@ class FillBlot extends BlockEmbed {
} }
FillBlot.blotName = "fill"; FillBlot.blotName = "fill-blot";
FillBlot.tagName = "span"; FillBlot.tagName = "span";
export default FillBlot; export default FillBlot;

@ -4,7 +4,7 @@
* @Github: * @Github:
* @Date: 2019-12-18 08:49:30 * @Date: 2019-12-18 08:49:30
* @LastEditors : tangjiang * @LastEditors : tangjiang
* @LastEditTime : 2020-01-09 11:56:10 * @LastEditTime : 2020-01-10 15:05:27
*/ */
import './index.scss'; import './index.scss';
import 'quill/dist/quill.core.css'; // 核心样式 import 'quill/dist/quill.core.css'; // 核心样式
@ -31,14 +31,16 @@ Quill.register(ImageBlot);
Quill.register(Size); Quill.register(Size);
Quill.register(Font, true); Quill.register(Font, true);
// Quill.register({'modules/toolbar': Toolbar}); // Quill.register({'modules/toolbar': Toolbar});
Quill.register(FillBlot); Quill.register({
'formats/fill': FillBlot
});
// Quill.register(Color); // Quill.register(Color);
function QuillForEditor ({ function QuillForEditor ({
placeholder, placeholder,
readOnly, readOnly,
autoFocus, autoFocus = false,
options, options,
value, value,
imgAttrs = {}, // 指定图片的宽高 imgAttrs = {}, // 指定图片的宽高
@ -194,10 +196,11 @@ function QuillForEditor ({
}); });
_quill.getModule('toolbar').addHandler('fill', (e) => { _quill.getModule('toolbar').addHandler('fill', (e) => {
// console.log('点击了填空=====>>>>>>', e);
setFillCount(fillCount + 1); setFillCount(fillCount + 1);
const range = _quill.getSelection(true); const range = _quill.getSelection(true);
// _quill.insertText(range.index, '▁', { 'data_index': fillCount }); // _quill.insertText(range.index, '▁', { 'data_index': fillCount });
_quill.insertEmbed(range.index, 'span', { _quill.insertEmbed(range.index, 'fill', {
text: '▁', text: '▁',
'data_index': fillCount 'data_index': fillCount
}); });
@ -229,16 +232,21 @@ function QuillForEditor ({
} }
const current = value const current = value
// console.log('+++++', current);
if (!deepEqual(previous, current)) { if (!deepEqual(previous, current)) {
setSelection(quill.getSelection()) setSelection(quill.getSelection())
if (typeof value === 'string') { if (typeof value === 'string') {
quill.clipboard.dangerouslyPasteHTML(value, 'api') quill.clipboard.dangerouslyPasteHTML(value, 'api');
if (autoFocus) {
quill.focus();
} else {
quill.blur();
}
} else { } else {
quill.setContents(value) quill.setContents(value)
if (autoFocus) quill.focus();
} }
} }
}, [quill, value, setQuill]); }, [quill, value, setQuill, autoFocus]);
// 清除选择区域 // 清除选择区域
useEffect(() => { useEffect(() => {
@ -272,13 +280,6 @@ function QuillForEditor ({
} }
}, [quill, handleOnChange]); }, [quill, handleOnChange]);
useEffect(() => {
if (!quill) return;
if (autoFocus) {
quill.focus();
}
}, [quill, autoFocus]);
// 返回结果 // 返回结果
return ( return (
<div className='quill_editor_for_react_area' style={wrapStyle}> <div className='quill_editor_for_react_area' style={wrapStyle}>

@ -65,7 +65,7 @@ class TopicDetail extends Component {
const topicId = this.props.match.params.topicId const topicId = this.props.match.params.topicId
const bid = this.props.match.params.boardId const bid = this.props.match.params.boardId
const memoUrl = `/messages/${topicId}.json`; const memoUrl = `/messages/${topicId}.json`;
this.setState({ this.setState({
memoLoading: true memoLoading: true
@ -73,7 +73,7 @@ class TopicDetail extends Component {
axios.get(memoUrl,{ axios.get(memoUrl,{
}) })
.then((response) => { .then((response) => {
if (response.data.status === -1) { if (response.data.status === -1) {
setTimeout(() => { setTimeout(() => {
this.props.showNotification('帖子不存在!') this.props.showNotification('帖子不存在!')
@ -81,7 +81,7 @@ class TopicDetail extends Component {
// this.props.toListPage(response.data.data.course_id, bid) // this.props.toListPage(response.data.data.course_id, bid)
return; return;
} else { } else {
this.setState({ this.setState({
memo: Object.assign({}, { memo: Object.assign({}, {
...response.data.data, ...response.data.data,
@ -93,7 +93,7 @@ class TopicDetail extends Component {
// const { memo_replies, memo } = response.data; // const { memo_replies, memo } = response.data;
// let hasMoreComments = false; // let hasMoreComments = false;
// if (memo_replies && memo_replies.length === 10 && memo.total_replies_count > 10) { // if (memo_replies && memo_replies.length === 10 && memo.total_replies_count > 10) {
// // 遍历一遍,计算下是否还有评论未加载 // // 遍历一遍,计算下是否还有评论未加载
// let totalCount = 10; // let totalCount = 10;
// memo_replies.forEach(item=>{ // memo_replies.forEach(item=>{
@ -123,14 +123,14 @@ class TopicDetail extends Component {
}) })
this.fetchReplies() this.fetchReplies()
$('body>#root').on('onMemoDelete', (event) => { $('body>#root').on('onMemoDelete', (event) => {
// const val = $('body>#root').data('onMemoDelete') // const val = $('body>#root').data('onMemoDelete')
const val = window.onMemoDelete ; const val = window.onMemoDelete ;
this.onMemoDelete( JSON.parse(decodeURIComponent(val)) ) this.onMemoDelete( JSON.parse(decodeURIComponent(val)) )
}) })
} }
onPaginationChange = (pageCount) => { onPaginationChange = (pageCount) => {
@ -157,7 +157,7 @@ class TopicDetail extends Component {
this.props.showNotification('删除成功'); this.props.showNotification('删除成功');
const props = Object.assign({}, this.props, {}) const props = Object.assign({}, this.props, {})
this.props.toListPage( Object.assign({}, this.props.match.params, {'coursesId': this.state.memo.course_id} ) ) this.props.toListPage( Object.assign({}, this.props.match.params, {'coursesId': this.state.memo.course_id} ) )
} else if (status === -1) { } else if (status === -1) {
this.props.showNotification('帖子已被删除'); this.props.showNotification('帖子已被删除');
this.props.history.push(`/forums`) this.props.history.push(`/forums`)
@ -168,11 +168,11 @@ class TopicDetail extends Component {
} }
componentDidUpdate(prevProps, prevState, snapshot) { componentDidUpdate(prevProps, prevState, snapshot) {
// if (this.state.memo && this.state.memo.content // if (this.state.memo && this.state.memo.content
// && (!prevProps.memo || prevProps.memo.content != this.state.memo.content) ) { // && (!prevProps.memo || prevProps.memo.content != this.state.memo.content) ) {
if (this.state.memo && this.state.memo.content && prevState.memoLoading === true && this.state.memoLoading === false) { if (this.state.memo && this.state.memo.content && prevState.memoLoading === true && this.state.memoLoading === false) {
// md渲染content等xhr执行完即memoLoading变化memo.content更新后初始化md // md渲染content等xhr执行完即memoLoading变化memo.content更新后初始化md
setTimeout(()=>{ setTimeout(()=>{
// var shixunDescr = window.editormd.markdownToHTML("memo_content_editorMd", { // var shixunDescr = window.editormd.markdownToHTML("memo_content_editorMd", {
// htmlDecode: "style,script,iframe", // you can filter tags decode // htmlDecode: "style,script,iframe", // you can filter tags decode
@ -183,7 +183,7 @@ class TopicDetail extends Component {
// }); // });
}, 200) }, 200)
} }
} }
clickPraise(){ clickPraise(){
@ -192,7 +192,7 @@ class TopicDetail extends Component {
const url = memo.user_praise ? '/praise_tread/unlike.json' : `/praise_tread/like.json`; const url = memo.user_praise ? '/praise_tread/unlike.json' : `/praise_tread/like.json`;
const _method = memo.user_praise ? axios.delete : axios.post const _method = memo.user_praise ? axios.delete : axios.post
let _data = { let _data = {
object_id: memo.id, object_id: memo.id,
object_type: 'message', //Discuss object_type: 'message', //Discuss
} }
if (memo.user_praise) { if (memo.user_praise) {
@ -204,10 +204,10 @@ class TopicDetail extends Component {
..._data ..._data
}, },
{ {
} }
).then((response) => { ).then((response) => {
const newMemo = Object.assign({}, this.state.memo) const newMemo = Object.assign({}, this.state.memo)
newMemo.praises_count = newMemo.user_praise ? newMemo.praises_count - 1 : newMemo.praises_count + 1 newMemo.praises_count = newMemo.user_praise ? newMemo.praises_count - 1 : newMemo.praises_count + 1
newMemo.total_praises_count = newMemo.user_praise ? newMemo.total_praises_count - 1 : newMemo.total_praises_count + 1 newMemo.total_praises_count = newMemo.user_praise ? newMemo.total_praises_count - 1 : newMemo.total_praises_count + 1
@ -248,10 +248,10 @@ class TopicDetail extends Component {
className="mr12 color9B9B overflowHidden1" length="58" style={{maxWidth: '480px'}}> className="mr12 color9B9B overflowHidden1" length="58" style={{maxWidth: '480px'}}>
{fileName} {fileName}
</a> </a>
<span className="color656565 mt2 color-grey-6 font-12 mr8">{item.filesize}</span> <span className="color656565 mt2 color-grey-6 font-12 mr8">{item.filesize}</span>
</div> </div>
) )
}) })
@ -268,7 +268,7 @@ class TopicDetail extends Component {
permission: true, // permission: true, //
children: children, children: children,
child_message_count: reply.total_count, child_message_count: reply.total_count,
hidden: reply.is_hidden, hidden: reply.is_hidden,
id: reply.id, id: reply.id,
image_url: reply.author.image_url, image_url: reply.author.image_url,
reward: null, // reward: null, //
@ -289,7 +289,7 @@ class TopicDetail extends Component {
}) })
.then((response) => { .then((response) => {
const { replies, liked, total_replies_count, total_count } = response.data.data const { replies, liked, total_replies_count, total_count } = response.data.data
const memo = Object.assign({}, this.state.memo) const memo = Object.assign({}, this.state.memo)
memo.user_praise = liked memo.user_praise = liked
memo.total_replies_count = total_replies_count; memo.total_replies_count = total_replies_count;
@ -322,15 +322,15 @@ class TopicDetail extends Component {
return; return;
} }
const url = `/messages/${id}/reply.json`; const url = `/messages/${id}/reply.json`;
const { comments } = this.state; const { comments } = this.state;
const user = this._getUser(); const user = this._getUser();
/* /*
移除末尾的空行 移除末尾的空行
.replace(/(\n<p>\n\t<br \/>\n<\/p>)*$/g,''); .replace(/(\n<p>\n\t<br \/>\n<\/p>)*$/g,'');
*/ */
commentContent = handleContentBeforeCreateSecondLevelComment(commentContent) commentContent = handleContentBeforeCreateSecondLevelComment(commentContent)
if (!commentContent) { if (!commentContent) {
this.props.showNotification('不能为空') this.props.showNotification('不能为空')
@ -340,9 +340,9 @@ class TopicDetail extends Component {
content: commentContent content: commentContent
}, },
{ {
} }
).then((response) => { ).then((response) => {
if (response.data.data.id) { if (response.data.data.id) {
let newId = response.data.data.id; let newId = response.data.data.id;
const commentIndex = this._findById(id, comments); const commentIndex = this._findById(id, comments);
const parentComment = comments[commentIndex] const parentComment = comments[commentIndex]
@ -361,7 +361,7 @@ class TopicDetail extends Component {
memo: newMemo2 memo: newMemo2
}) })
} }
}).catch((error) => { }).catch((error) => {
console.log(error) console.log(error)
}) })
@ -369,14 +369,14 @@ class TopicDetail extends Component {
// 公共接口 --- 删除回复 // 公共接口 --- 删除回复
deleteComment = (parrentComment, childCommentId) => { deleteComment = (parrentComment, childCommentId) => {
handleDeleteComment(this, parrentComment, childCommentId, 'message') handleDeleteComment(this, parrentComment, childCommentId, 'message')
} }
// 公共接口 --- 回复点赞 // 公共接口 --- 回复点赞
commentPraise = (discussId) => { commentPraise = (discussId) => {
handleCommentPraise(this, discussId, 'message', (old_user_praise) => { handleCommentPraise(this, discussId, 'message', (old_user_praise) => {
const newMemo2 = Object.assign({}, this.state.memo); const newMemo2 = Object.assign({}, this.state.memo);
newMemo2.total_praises_count = old_user_praise newMemo2.total_praises_count = old_user_praise
? newMemo2.total_praises_count - 1 : newMemo2.total_praises_count + 1; ? newMemo2.total_praises_count - 1 : newMemo2.total_praises_count + 1;
this.setState({ this.setState({
memo: newMemo2 memo: newMemo2
@ -390,7 +390,7 @@ class TopicDetail extends Component {
createNewComment = (commentContent, id, editor) => { createNewComment = (commentContent, id, editor) => {
let content = handleContentBeforeCreateNew(commentContent); let content = handleContentBeforeCreateNew(commentContent);
const { memo } = this.props; const { memo } = this.props;
const url = `/messages/${id}/reply.json`; const url = `/messages/${id}/reply.json`;
// const url = `/api/v1/memos/${memo.id}/reply`; // const url = `/api/v1/memos/${memo.id}/reply`;
@ -399,7 +399,7 @@ class TopicDetail extends Component {
content: content content: content
}, },
{ {
} }
).then((response) => { ).then((response) => {
if (response.data.status === -1) { if (response.data.status === -1) {
console.error('服务端异常') console.error('服务端异常')
@ -407,15 +407,15 @@ class TopicDetail extends Component {
} }
// this.props.showNotification('帖子发表成功') // this.props.showNotification('帖子发表成功')
if (response.data) { if (response.data) {
const _id = response.data.data.id; const _id = response.data.data.id;
// ke // ke
editor.html && editor.html(''); editor.html && editor.html('');
editor.afterBlur && editor.afterBlur() editor.afterBlur && editor.afterBlur()
// md // md
editor.setValue && editor.setValue('') editor.setValue && editor.setValue('')
const user = this._getUser(); const user = this._getUser();
this.setState({ this.setState({
comments: addNewComment(comments, _id, content, user, this.props.isSuperAdmin(), this) comments: addNewComment(comments, _id, content, user, this.props.isSuperAdmin(), this)
@ -427,8 +427,8 @@ class TopicDetail extends Component {
}) })
this.refs.editor.showEditor(); this.refs.editor.showEditor();
this.refs.editor.close(); this.refs.editor.close();
} }
}).catch((error) => { }).catch((error) => {
console.log(error) console.log(error)
@ -444,7 +444,7 @@ class TopicDetail extends Component {
}) })
.then((response) => { .then((response) => {
const { replies, liked, total_replies_count } = response.data.data const { replies, liked, total_replies_count } = response.data.data
// const memo = Object.assign({}, this.state.memo) // const memo = Object.assign({}, this.state.memo)
// memo.total_replies_count = total_replies_count; // memo.total_replies_count = total_replies_count;
this.setState({ this.setState({
@ -460,19 +460,19 @@ class TopicDetail extends Component {
// 置顶 // 置顶
setTop(memo) { setTop(memo) {
// const params = { // const params = {
// sticky: memo.sticky ? 0 : 1, // sticky: memo.sticky ? 0 : 1,
// } // }
// if (this.state.p_s_order) { // if (this.state.p_s_order) {
// params.order = this.state.p_s_order; // params.order = this.state.p_s_order;
// } // }
// if (this.state.p_forum_id) { // if (this.state.p_forum_id) {
// params.forum_id = this.state.p_forum_id; // params.forum_id = this.state.p_forum_id;
// } // }
// let paramsUrl = urlStringify(params) // let paramsUrl = urlStringify(params)
const set_top_or_down_Url = `/messages/${memo.id}/sticky_top.json`; const set_top_or_down_Url = `/messages/${memo.id}/sticky_top.json`;
// 获取memo list // 获取memo list
axios.put(set_top_or_down_Url, { axios.put(set_top_or_down_Url, {
}) })
.then((response) => { .then((response) => {
const status = response.data.status const status = response.data.status
@ -487,7 +487,7 @@ class TopicDetail extends Component {
console.log(error) console.log(error)
}) })
} }
setRewardDialogVisible = (visible) => { setRewardDialogVisible = (visible) => {
this.setState({ this.setState({
goldRewardDialogOpen: visible goldRewardDialogOpen: visible
@ -512,7 +512,7 @@ class TopicDetail extends Component {
} }
} }
render() { render() {
const { match, history } = this.props const { match, history } = this.props
const { recommend_shixun, current_user,author_info } = this.props; const { recommend_shixun, current_user,author_info } = this.props;
@ -567,7 +567,7 @@ class TopicDetail extends Component {
<div className="padding30 bor-bottom-greyE" style={{paddingBottom: '20px'}}> <div className="padding30 bor-bottom-greyE" style={{paddingBottom: '20px'}}>
<div className="font-16 cdefault clearfix pr pr35"> <div className="font-16 cdefault clearfix pr pr35">
<span className="noteDetailTitle">{memo.subject}</span> <span className="noteDetailTitle">{memo.subject}</span>
{ !!memo.sticky && <span className="btn-cir btn-cir-red ml10" { !!memo.sticky && <span className="btn-cir btn-cir-red ml10"
style={{position: 'relative', bottom: '4px'}}>置顶</span>} style={{position: 'relative', bottom: '4px'}}>置顶</span>}
{ !!memo.reward && <span className="color-orange font-14 ml15" { !!memo.reward && <span className="color-orange font-14 ml15"
data-tip-down={`获得平台奖励金币:${memo.reward}`} > data-tip-down={`获得平台奖励金币:${memo.reward}`} >
@ -578,9 +578,9 @@ class TopicDetail extends Component {
<div className="edu-position-hidebox" style={{position: 'absolute', right: '2px',top:'4px'}}> <div className="edu-position-hidebox" style={{position: 'absolute', right: '2px',top:'4px'}}>
<a href="javascript:void(0);"><i className="fa fa-bars font-16"></i></a> <a href="javascript:void(0);"><i className="fa fa-bars font-16"></i></a>
<ul className="edu-position-hide undis"> <ul className="edu-position-hide undis">
{ ( isCurrentUserTheAuthor || isAdmin ) && { ( isCurrentUserTheAuthor || isAdmin ) &&
<li><a <li><a
onClick={() => this.props.toEditPage( Object.assign({}, this.props.match.params, {'coursesId': this.state.memo.course_id}) ) } onClick={() => this.props.toEditPage( Object.assign({}, this.props.match.params, {'coursesId': this.state.memo.course_id}) ) }
>&nbsp;&nbsp;</a></li>} >&nbsp;&nbsp;</a></li>}
{ isAdmin && { isAdmin &&
@ -590,7 +590,7 @@ class TopicDetail extends Component {
<li><a href="javascript:void(0);" onClick={() => this.setTop(memo)}>&nbsp;&nbsp;</a></li> ) <li><a href="javascript:void(0);" onClick={() => this.setTop(memo)}>&nbsp;&nbsp;</a></li> )
} }
{ isAdmin && { isAdmin &&
<li><a href="javascript:void(0);" onClick={() => this.refs.sendToCourseModal.setVisible(true)}>&nbsp;&nbsp;</a></li> <li><a href="javascript:void(0);" onClick={() => this.refs.sendToCourseModal.setVisible(true)}>&nbsp;&nbsp;</a></li>
} }
{ ( isCurrentUserTheAuthor || isAdmin ) && <li> { ( isCurrentUserTheAuthor || isAdmin ) && <li>
<a href="javascript:void(0)" onClick={() => <a href="javascript:void(0)" onClick={() =>
@ -602,9 +602,9 @@ class TopicDetail extends Component {
</ul> </ul>
</div> </div>
} }
</div> </div>
<div className="df mt20"> <div className="df mt20">
<img src={setImagesUrl(`/images/${author && author.image_url}`)} className="radius mr10 mt2" width="40px" height="40px"/> <img src={setImagesUrl(`/images/${author && author.image_url}`)} className="radius mr10 mt2" width="40px" height="40px"/>
<div className="flex1"> <div className="flex1">
<div className="color-grey-9 lineh-20"> <div className="color-grey-9 lineh-20">
@ -625,7 +625,7 @@ class TopicDetail extends Component {
<span style={{ top: "1px", position: "relative" }}>{memo.visits || '1'}</span> <span style={{ top: "1px", position: "relative" }}>{memo.visits || '1'}</span>
</span> </span>
</Tooltip> </Tooltip>
{ !!memo.total_replies_count && { !!memo.total_replies_count &&
<Tooltip title={"回复数"}> <Tooltip title={"回复数"}>
<a href="javascript:void(0)" className="noteDetailNum"> <a href="javascript:void(0)" className="noteDetailNum">
<i className="iconfont icon-huifu1 mr5" onClick={this.showCommentInput}></i> <i className="iconfont icon-huifu1 mr5" onClick={this.showCommentInput}></i>
@ -633,8 +633,8 @@ class TopicDetail extends Component {
</a> </a>
</Tooltip> </Tooltip>
} }
{!!memo.total_praises_count && {!!memo.total_praises_count &&
<Tooltip title={"点赞数"}> <Tooltip title={"点赞数"}>
<span className={`noteDetailNum `} style={{}}> <span className={`noteDetailNum `} style={{}}>
<i className="iconfont icon-dianzan-xian mr5"></i> <i className="iconfont icon-dianzan-xian mr5"></i>
<span style={{ top: "2px", position: "relative" }}>{ memo.total_praises_count }</span> <span style={{ top: "2px", position: "relative" }}>{ memo.total_praises_count }</span>
@ -654,12 +654,12 @@ class TopicDetail extends Component {
</div> </div>
</div> </div>
<div className="padding30 memoContent new_li" style={{ paddingBottom: '10px'}}> <div className="padding30 memoContent new_li" style={{ paddingBottom: '10px'}}>
{/* <MarkdownToHtml content={memo.content}></MarkdownToHtml> */} {/* <MarkdownToHtml content={memo.content}></MarkdownToHtml> */}
{memo.is_md == true ? {memo.is_md == true ?
<MarkdownToHtml content={memo.content}></MarkdownToHtml> <MarkdownToHtml content={memo.content}></MarkdownToHtml>
: :
<div dangerouslySetInnerHTML={{ __html: memo.content }}></div> <div dangerouslySetInnerHTML={{ __html: memo.content }}></div>
} }
</div> </div>
@ -674,17 +674,17 @@ class TopicDetail extends Component {
</Tooltip> </Tooltip>
</div> </div>
{ memo.attachments && !!memo.attachments.length && { memo.attachments && !!memo.attachments.length &&
<div> <div>
{this.renderAttachment()} {this.renderAttachment()}
</div> </div>
} }
</div> </div>
{!isCourseEnd && <MemoDetailMDEditor ref="editor" memo={memo} usingMockInput={true} placeholder="说点什么" {!isCourseEnd && <MemoDetailMDEditor ref="editor" memo={memo} usingMockInput={true} placeholder="说点什么"
height={160} showError={true} buttonText={'发表'} className={comments && comments.length && 'borderBottom'}></MemoDetailMDEditor>} height={160} showError={true} buttonText={'发表'} className={comments && comments.length && 'borderBottom'}></MemoDetailMDEditor>}
{/* onClick={ this.createNewComment } {/* onClick={ this.createNewComment }
enableReplyTo={true} enableReplyTo={true}
*/} */}
<div className="padding20 memoReplies commentsDelegateParent comments_hideSecondReplyUserHeader" <div className="padding20 memoReplies commentsDelegateParent comments_hideSecondReplyUserHeader"
@ -711,22 +711,22 @@ class TopicDetail extends Component {
onlySuperAdminCouldHide={true} onlySuperAdminCouldHide={true}
></Comments> ></Comments>
{/* { true ? : {/* { true ? :
<div className="memoMore"> <div className="memoMore">
<div className="writeCommentBtn" onClick={this.showCommentInput}>写评论</div> <div className="writeCommentBtn" onClick={this.showCommentInput}>写评论</div>
</div>} */} </div>} */}
</div> </div>
<div className="memoMore" style={{'margin-top': '20px'}}> <div className="memoMore" style={{'margin-top': '20px'}}>
{ total_count > REPLY_PAGE_COUNT && { total_count > REPLY_PAGE_COUNT &&
<Pagination showQuickJumper onChange={this.onPaginationChange} current={pageCount} total={total_count} pageSize={10}/> <Pagination showQuickJumper onChange={this.onPaginationChange} current={pageCount} total={total_count} pageSize={10}/>
} }
{!isCourseEnd && <div className="writeCommentBtn" onClick={this.showCommentInput}>写评论</div>} {!isCourseEnd && <div className="writeCommentBtn" onClick={this.showCommentInput}>写评论</div>}
</div> </div>
</div> </div>
</div> </div>
</div> </div>

@ -18,7 +18,7 @@ import { generateComments, generateChildComments, _findById, handleContentBefore
const REPLY_PAGE_COUNT = 10 const REPLY_PAGE_COUNT = 10
const $ = window.$; const $ = window.$;
/* /*
相比较GraduateTopicReply 改动的地方 相比较GraduateTopicReply 改动的地方
列表接口名 /graduation_tasks/${graduation_topic_id}/show_comment.json?parent_id=${parent.id}&limit=500 列表接口名 /graduation_tasks/${graduation_topic_id}/show_comment.json?parent_id=${parent.id}&limit=500
回复类型名 jour_type: this.props.jour_type, 回复类型名 jour_type: this.props.jour_type,
@ -34,7 +34,7 @@ class CommonReply extends Component{
componentDidMount(){ componentDidMount(){
this.fetchReplies() this.fetchReplies()
} }
_getUser() { _getUser() {
const { current_user } = this.props; const { current_user } = this.props;
@ -58,7 +58,7 @@ class CommonReply extends Component{
// m_parent_id // m_parent_id
reply_id: memo.user_id || this.state.homework_user_id reply_id: memo.user_id || this.state.homework_user_id
} }
} }
).then((response) => { ).then((response) => {
if (response.data.status === -1) { if (response.data.status === -1) {
console.error('服务端异常') console.error('服务端异常')
@ -66,15 +66,15 @@ class CommonReply extends Component{
} }
// this.props.showNotification('帖子发表成功') // this.props.showNotification('帖子发表成功')
if (response.data && response.data.id) { if (response.data && response.data.id) {
const _id = response.data.id; const _id = response.data.id;
// md // md
editor.setValue && editor.setValue('') editor.setValue && editor.setValue('')
this.refs.editor.close && this.refs.editor.close() this.refs.editor.close && this.refs.editor.close()
const user = this._getUser(); const user = this._getUser();
const isSuperAdmin = this.props.isSuperAdmin() const isSuperAdmin = this.props.isSuperAdmin()
this.setState({ this.setState({
comments: addNewComment(this.state.comments, _id, content, user, isSuperAdmin, this), comments: addNewComment(this.state.comments, _id, content, user, isSuperAdmin, this),
total_count: this.state.total_count + 1 total_count: this.state.total_count + 1
@ -98,13 +98,13 @@ class CommonReply extends Component{
return; return;
} }
const url = `/users/reply_message.json`; const url = `/users/reply_message.json`;
const { comments } = this.state; const { comments } = this.state;
const user = this._getUser(); const user = this._getUser();
const graduation_topic_id = this.props.memo.id const graduation_topic_id = this.props.memo.id
const commentIndex = this._findById(id, comments); const commentIndex = this._findById(id, comments);
let comment = comments[commentIndex]; let comment = comments[commentIndex];
commentContent = handleContentBeforeCreateSecondLevelComment(commentContent) commentContent = handleContentBeforeCreateSecondLevelComment(commentContent)
axios.post(url, { axios.post(url, {
journals_for_message: { journals_for_message: {
@ -117,9 +117,9 @@ class CommonReply extends Component{
} }
}, },
{ {
} }
).then((response) => { ).then((response) => {
if (response.data.id) { if (response.data.id) {
let newId = response.data.id; let newId = response.data.id;
const newMemo2 = Object.assign({}, this.props.memo); const newMemo2 = Object.assign({}, this.props.memo);
@ -132,7 +132,7 @@ class CommonReply extends Component{
}) })
} }
}).catch((error) => { }).catch((error) => {
console.log(error) console.log(error)
}) })
@ -146,7 +146,7 @@ class CommonReply extends Component{
}) })
.then((response) => { .then((response) => {
const { comments } = response.data const { comments } = response.data
// const memo = Object.assign({}, this.state.memo) // const memo = Object.assign({}, this.state.memo)
// memo.sum_replies_count = sum_replies_count; // memo.sum_replies_count = sum_replies_count;
@ -164,7 +164,7 @@ class CommonReply extends Component{
this.fetchReplies() this.fetchReplies()
}) })
} }
fetchReplies = () => { fetchReplies = () => {
const graduation_topic_id = this.props.memo.id const graduation_topic_id = this.props.memo.id
const course_id = this.props.course_id const course_id = this.props.course_id
@ -174,7 +174,7 @@ class CommonReply extends Component{
}) })
.then((response) => { .then((response) => {
const { comments, messages_count, homework_user_id, parent_messages_count } = response.data const { comments, messages_count, homework_user_id, parent_messages_count } = response.data
this.setState({ this.setState({
comments: generateComments(comments, this.transformReply), comments: generateComments(comments, this.transformReply),
// : this.state.comments.concat(comments), // : this.state.comments.concat(comments),
@ -185,7 +185,7 @@ class CommonReply extends Component{
console.log(error) console.log(error)
}) })
} }
transformReply = (reply, children = []) => { transformReply = (reply, children = []) => {
const isAdmin = this.props.isAdmin() const isAdmin = this.props.isAdmin()
const isSuperAdmin = this.props.isSuperAdmin() const isSuperAdmin = this.props.isSuperAdmin()
@ -194,7 +194,7 @@ class CommonReply extends Component{
isSuperAdmin: isSuperAdmin, isSuperAdmin: isSuperAdmin,
permission: true, // permission: true, //
children: children, children: children,
hidden: reply.hidden, hidden: reply.hidden,
id: reply.id, id: reply.id,
image_url: reply.author.image_url, image_url: reply.author.image_url,
reward: null, // reward: null, //
@ -249,7 +249,7 @@ class CommonReply extends Component{
padding-bottom: 30px; padding-bottom: 30px;
} }
`}</style> `}</style>
<MemoDetailMDEditor ref="editor" memo={memo} usingMockInput={true} placeholder="说点什么" <MemoDetailMDEditor ref="editor" memo={memo} usingMockInput={true} placeholder="说点什么"
height={160} showError={true} imageExpand={true} height={160} showError={true} imageExpand={true}
replyComment={this.replyComment} replyComment={this.replyComment}
commentsLength={comments ? comments.length : 0} commentsLength={comments ? comments.length : 0}
@ -268,7 +268,7 @@ class CommonReply extends Component{
commentPraise={this.commentPraise} commentPraise={this.commentPraise}
rewardCode={this.rewardCode} rewardCode={this.rewardCode}
hiddenComment={this.hiddenComment} hiddenComment={this.hiddenComment}
usingAntdModal={true} usingAntdModal={true}
isChildCommentPagination={true} isChildCommentPagination={true}
loadMoreChildComments={this.loadMoreChildComments} loadMoreChildComments={this.loadMoreChildComments}
@ -276,15 +276,15 @@ class CommonReply extends Component{
showRewardButton={false} showRewardButton={false}
onlySuperAdminCouldHide={true} onlySuperAdminCouldHide={true}
></Comments> ></Comments>
{/* { true ? : {/* { true ? :
<div className="memoMore"> <div className="memoMore">
<div className="writeCommentBtn" onClick={this.showCommentInput}>写评论</div> <div className="writeCommentBtn" onClick={this.showCommentInput}>写评论</div>
</div>} */} </div>} */}
</div> </div>
{ total_count > REPLY_PAGE_COUNT && { total_count > REPLY_PAGE_COUNT &&
<div className="memoMore"> <div className="memoMore">
<Pagination showQuickJumper onChange={this.onPaginationChange} current={pageCount} total={total_count} pageSize={10}/> <Pagination showQuickJumper onChange={this.onPaginationChange} current={pageCount} total={total_count} pageSize={10}/>
<div className="writeCommentBtn" onClick={this.showCommentInput}>写评论</div> <div className="writeCommentBtn" onClick={this.showCommentInput}>写评论</div>

@ -28,7 +28,7 @@ class GraduateTopicReply extends Component{
componentDidMount(){ componentDidMount(){
this.fetchReplies() this.fetchReplies()
} }
_getUser() { _getUser() {
const { current_user } = this.props; const { current_user } = this.props;
@ -52,7 +52,7 @@ class GraduateTopicReply extends Component{
// m_parent_id // m_parent_id
reply_id: memo.user_id reply_id: memo.user_id
} }
} }
).then((response) => { ).then((response) => {
if (response.data.status === -1) { if (response.data.status === -1) {
console.error('服务端异常') console.error('服务端异常')
@ -60,18 +60,18 @@ class GraduateTopicReply extends Component{
} }
// this.props.showNotification('帖子发表成功') // this.props.showNotification('帖子发表成功')
if (response.data && response.data.id) { if (response.data && response.data.id) {
const _id = response.data.id; const _id = response.data.id;
// md // md
editor.setValue && editor.setValue('') editor.setValue && editor.setValue('')
const user = this._getUser(); const user = this._getUser();
this.setState({ this.setState({
comments: addNewComment(this.state.comments, _id, content, user, this.props.isSuperAdmin(), this), comments: addNewComment(this.state.comments, _id, content, user, this.props.isSuperAdmin(), this),
total_count: this.state.total_count + 1 total_count: this.state.total_count + 1
}) })
this.refs.editor.showEditor(); this.refs.editor.showEditor();
} }
}).catch((error) => { }).catch((error) => {
console.log(error) console.log(error)
@ -89,13 +89,13 @@ class GraduateTopicReply extends Component{
return; return;
} }
const url = `/users/reply_message.json`; const url = `/users/reply_message.json`;
const { comments } = this.state; const { comments } = this.state;
const user = this._getUser(); const user = this._getUser();
const graduation_topic_id = this.props.memo.id const graduation_topic_id = this.props.memo.id
const commentIndex = this._findById(id, comments); const commentIndex = this._findById(id, comments);
let comment = comments[commentIndex]; let comment = comments[commentIndex];
commentContent = handleContentBeforeCreateSecondLevelComment(commentContent) commentContent = handleContentBeforeCreateSecondLevelComment(commentContent)
axios.post(url, { axios.post(url, {
journals_for_message: { journals_for_message: {
@ -107,9 +107,9 @@ class GraduateTopicReply extends Component{
} }
}, },
{ {
} }
).then((response) => { ).then((response) => {
if (response.data.id) { if (response.data.id) {
let newId = response.data.id; let newId = response.data.id;
this.setState({ this.setState({
@ -122,7 +122,7 @@ class GraduateTopicReply extends Component{
memo: newMemo2 memo: newMemo2
}) })
} }
}).catch((error) => { }).catch((error) => {
console.log(error) console.log(error)
}) })
@ -136,7 +136,7 @@ class GraduateTopicReply extends Component{
}) })
.then((response) => { .then((response) => {
const { comments } = response.data const { comments } = response.data
// const memo = Object.assign({}, this.state.memo) // const memo = Object.assign({}, this.state.memo)
// memo.sum_replies_count = sum_replies_count; // memo.sum_replies_count = sum_replies_count;
@ -154,7 +154,7 @@ class GraduateTopicReply extends Component{
this.fetchReplies() this.fetchReplies()
}) })
} }
fetchReplies = () => { fetchReplies = () => {
const graduation_topic_id = this.props.memo.id const graduation_topic_id = this.props.memo.id
const course_id = this.props.course_id const course_id = this.props.course_id
@ -164,7 +164,7 @@ class GraduateTopicReply extends Component{
}) })
.then((response) => { .then((response) => {
const { comments, messages_count } = response.data const { comments, messages_count } = response.data
this.setState({ this.setState({
comments: generateComments(comments, this.transformReply), comments: generateComments(comments, this.transformReply),
// : this.state.comments.concat(comments), // : this.state.comments.concat(comments),
@ -174,7 +174,7 @@ class GraduateTopicReply extends Component{
console.log(error) console.log(error)
}) })
} }
transformReply = (reply, children = []) => { transformReply = (reply, children = []) => {
const isAdmin = this.props.isAdmin() const isAdmin = this.props.isAdmin()
const isSuperAdmin = this.props.isSuperAdmin() const isSuperAdmin = this.props.isSuperAdmin()
@ -184,7 +184,7 @@ class GraduateTopicReply extends Component{
permission: true, // permission: true, //
children: children, children: children,
child_message_count: reply.child_message_count, child_message_count: reply.child_message_count,
hidden: reply.hidden, hidden: reply.hidden,
id: reply.id, id: reply.id,
image_url: reply.author.image_url, image_url: reply.author.image_url,
reward: null, // reward: null, //
@ -226,7 +226,7 @@ class GraduateTopicReply extends Component{
return( return(
<React.Fragment> <React.Fragment>
<MemoDetailMDEditor ref="editor" memo={memo} usingMockInput={true} placeholder="说点什么" <MemoDetailMDEditor ref="editor" memo={memo} usingMockInput={true} placeholder="说点什么"
height={160} showError={true}></MemoDetailMDEditor> height={160} showError={true}></MemoDetailMDEditor>
<div className="padding40 bor-bottom-greyE memoReplies commentsDelegateParent" <div className="padding40 bor-bottom-greyE memoReplies commentsDelegateParent"
@ -242,7 +242,7 @@ class GraduateTopicReply extends Component{
commentPraise={this.commentPraise} commentPraise={this.commentPraise}
rewardCode={this.rewardCode} rewardCode={this.rewardCode}
hiddenComment={this.hiddenComment} hiddenComment={this.hiddenComment}
usingAntdModal={true} usingAntdModal={true}
isChildCommentPagination={true} isChildCommentPagination={true}
loadMoreChildComments={this.loadMoreChildComments} loadMoreChildComments={this.loadMoreChildComments}
@ -251,15 +251,15 @@ class GraduateTopicReply extends Component{
onlySuperAdminCouldHide={true} onlySuperAdminCouldHide={true}
></Comments> ></Comments>
{/* { true ? : {/* { true ? :
<div className="memoMore"> <div className="memoMore">
<div className="writeCommentBtn" onClick={this.showCommentInput}>写评论</div> <div className="writeCommentBtn" onClick={this.showCommentInput}>写评论</div>
</div>} */} </div>} */}
</div> </div>
{ total_count > REPLY_PAGE_COUNT && { total_count > REPLY_PAGE_COUNT &&
<div className="memoMore"> <div className="memoMore">
<Pagination showQuickJumper onChange={this.onPaginationChange} current={pageCount} total={total_count} pageSize={10}/> <Pagination showQuickJumper onChange={this.onPaginationChange} current={pageCount} total={total_count} pageSize={10}/>
<div className="writeCommentBtn" onClick={this.showCommentInput}>写评论</div> <div className="writeCommentBtn" onClick={this.showCommentInput}>写评论</div>

@ -4,7 +4,7 @@
* @Github: * @Github:
* @Date: 2019-11-20 10:35:40 * @Date: 2019-11-20 10:35:40
* @LastEditors : tangjiang * @LastEditors : tangjiang
* @LastEditTime : 2020-01-09 14:18:37 * @LastEditTime : 2020-01-10 15:06:23
*/ */
import './index.scss'; import './index.scss';
// import 'katex/dist/katex.css'; // import 'katex/dist/katex.css';
@ -453,6 +453,7 @@ class EditTab extends React.Component {
colon={ false } colon={ false }
> >
<QuillForEditor <QuillForEditor
autoFocus={true}
style={{ height: '200px' }} style={{ height: '200px' }}
placeholder="请输入描述信息" placeholder="请输入描述信息"
onContentChange={handleContentChange} onContentChange={handleContentChange}

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

Loading…
Cancel
Save