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

dev_aliyun_beta
杨树林 5 years ago
commit 0d7367064b

@ -890,7 +890,7 @@ class CoursesController < ApplicationController
name = worksheet.cell(row, 1).to_s name = worksheet.cell(row, 1).to_s
if @course.course_groups.where(:name => name).blank? if @course.course_groups.where(:name => name).blank?
@course.course_groups << CourseGroup.new(:name => name) @course.course_groups << CourseGroup.new(:name => name, :position => @course.course_groups_count + 1)
group_count += 1 group_count += 1
end end
end end

@ -124,6 +124,7 @@ class ExerciseBankQuestionsController < ApplicationController
@exercise_question.update_attributes(:question_score => question_score, :shixun_name=> shixun_name) @exercise_question.update_attributes(:question_score => question_score, :shixun_name=> shixun_name)
end end
end end
normal_status("创建成功")
rescue Exception => e rescue Exception => e
uid_logger_error(e.message) uid_logger_error(e.message)
tip_exception("试卷问题创建失败!") tip_exception("试卷问题创建失败!")
@ -185,7 +186,6 @@ class ExerciseBankQuestionsController < ApplicationController
if @exercise_question.question_type <= Exercise::JUDGMENT #选择题/判断题,标准答案为一个或多个 if @exercise_question.question_type <= Exercise::JUDGMENT #选择题/判断题,标准答案为一个或多个
exercise_standard_choices = @exercise_answers_array.pluck(:exercise_bank_choice_id) #问题以前的全部标准答案选项位置 exercise_standard_choices = @exercise_answers_array.pluck(:exercise_bank_choice_id) #问题以前的全部标准答案选项位置
if exercise_standard_choices.sort != standard_answer.sort #表示答案有更改的 if exercise_standard_choices.sort != standard_answer.sort #表示答案有更改的
standard_answer_change = true
common_standard_choices = standard_answer & exercise_standard_choices # 传入的标准答案的选项位置和以前的并集,即表示不用做更改的 common_standard_choices = standard_answer & exercise_standard_choices # 传入的标准答案的选项位置和以前的并集,即表示不用做更改的
old_left_standard_choices = exercise_standard_choices - common_standard_choices # 以前的差集共同的,剩余的表示需要删掉 old_left_standard_choices = exercise_standard_choices - common_standard_choices # 以前的差集共同的,剩余的表示需要删掉
new_left_standard_choices = standard_answer - common_standard_choices # 传入的标准答案差集共同的,剩余的表示需要新建 new_left_standard_choices = standard_answer - common_standard_choices # 传入的标准答案差集共同的,剩余的表示需要新建
@ -216,7 +216,6 @@ class ExerciseBankQuestionsController < ApplicationController
if old_ex_answer_choice_texts != new_ex_answer_choice_texts #填空题标准答案有更改时,才会更新标准答案 if old_ex_answer_choice_texts != new_ex_answer_choice_texts #填空题标准答案有更改时,才会更新标准答案
new_ex_answer_choice_ids = standard_answer.map {|a| a[:choice_id]}.uniq #新传入的答案数组序号 new_ex_answer_choice_ids = standard_answer.map {|a| a[:choice_id]}.uniq #新传入的答案数组序号
old_ex_answer_choice_ids = old_ex_answer.pluck(:exercise_bank_choice_id).uniq #全部的答案数组序号 old_ex_answer_choice_ids = old_ex_answer.pluck(:exercise_bank_choice_id).uniq #全部的答案数组序号
standard_answer_change = true
#删除多余的选项 #删除多余的选项
if old_ex_answer_choice_ids.count > new_ex_answer_choice_ids.count #有减少的填空 if old_ex_answer_choice_ids.count > new_ex_answer_choice_ids.count #有减少的填空
delete_ex_answer_choice_ids = old_ex_answer_choice_ids - new_ex_answer_choice_ids delete_ex_answer_choice_ids = old_ex_answer_choice_ids - new_ex_answer_choice_ids
@ -300,7 +299,7 @@ class ExerciseBankQuestionsController < ApplicationController
elsif @exercise_question.question_type == Exercise::PRACTICAL elsif @exercise_question.question_type == Exercise::PRACTICAL
question_score = 0 question_score = 0
shixun_name = params[:shixun_name] || @exercise_question.shixun_name shixun_name = params[:shixun_name] || @exercise_question.shixun_name
@exercise_question.exercise_shixun_challenges.each_with_index do |challenge, index| @exercise_question.exercise_bank_shixun_challenges.each_with_index do |challenge, index|
challenge.question_score = params[:question_scores][index].to_f.round(1) challenge.question_score = params[:question_scores][index].to_f.round(1)
challenge.save challenge.save
question_score += params[:question_scores][index].to_f.round(1) question_score += params[:question_scores][index].to_f.round(1)
@ -309,32 +308,63 @@ class ExerciseBankQuestionsController < ApplicationController
@exercise_question.shixun_name = shixun_name @exercise_question.shixun_name = shixun_name
@exercise_question.save @exercise_question.save
end end
normal_status(0,"试卷更新成功")
rescue Exception => e
uid_logger_error(e.message)
tip_exception("页面调用失败!")
raise ActiveRecord::Rollback
end
end
end
#当试卷已发布时(试卷的总状态),当标准答案修改时,如有已提交的学生,需重新计算分数. def up_down
ActiveRecord::Base.transaction do
if standard_answer_change && @exercise.exercise_status >= Exercise::PUBLISHED begin
# ex_users_committed = @exercise.exercise_users.exercise_user_committed opr = params[:opr]
# if ex_users_committed.size > 0 current_q_p = @exercise_question.question_number.to_i #问题的当前位置
# ex_users_committed.each do |ex_user| if opr.present?
# update_objective_score = update_single_score(@exercise_question,ex_user.user_id,standard_answer) if opr.to_s == "up"
# if update_objective_score != 0 last_q_p = @exercise.exercise_bank_questions.find_by(question_number: (current_q_p - 1)) # 当前问题的前一个问题
# objective_score = ex_user.objective_score if last_q_p.present?
# new_objective_score = objective_score + update_objective_score @exercise_question.update_attribute('question_number', (current_q_p - 1))
# total_score = ex_user.score + update_objective_score last_q_p.update_attribute('question_number', current_q_p) # 重新获取当前问题的位置
# total_score = total_score < 0.0 ? 0.0 : total_score normal_status(0, "问题上移成功!")
# ex_user.update_attributes(objective_score:new_objective_score,score:total_score) else
# end normal_status(-1, "移动失败,已经是第一个问题了!")
# end end
# end elsif opr.to_s == "down"
normal_status(3,"修改了标准答案\n是否重新计算学生答题的成绩?") next_q_p = @exercise.exercise_bank_questions.find_by(question_number: (current_q_p + 1)) # 当前问题的前一个问题
if next_q_p.present?
@exercise_question.update_attribute('question_number', (current_q_p + 1))
next_q_p.update_attribute('question_number', current_q_p)
normal_status(0, "问题下移成功!")
else
normal_status(-1, "移动失败,已经是最后一个问题了!")
end
end
else else
normal_status(0,"试卷更新成功!") normal_status(-1, "移动失败,请输入参数")
end end
rescue Exception => e
uid_logger_error(e.message)
tip_exception("问题移动失败!")
end
end
end
#试卷问题的删除
def destroy
ActiveRecord::Base.transaction do
begin
question_d_id = @exercise_question.question_number.to_i #问题的当前位置
exercise_questions = @exercise.exercise_bank_questions
left_questions = exercise_questions.where("question_number > ?", question_d_id)
left_questions.update_all("question_number = question_number - 1") if left_questions
@exercise_question.destroy
normal_status(0, "删除成功")
rescue Exception => e rescue Exception => e
uid_logger_error(e.message) uid_logger_error(e.message)
tip_exception("页面调用失败!") tip_exception("删除失败")
raise ActiveRecord::Rollback
end end
end end
end end

@ -1,8 +1,9 @@
#encoding: UTF-8 #encoding: UTF-8
class ExerciseBanksController < ApplicationController class ExerciseBanksController < ApplicationController
before_action :require_login before_action :require_login
before_action :find_bank before_action :find_bank, except: [:choose_shixun]
before_action :bank_admin, only: [:update] before_action :bank_admin, only: [:update]
before_action :commit_shixun_present, only: [:commit_shixun]
def show def show
@exercise_questions = @bank.exercise_bank_questions&.includes(:exercise_bank_choices, :exercise_bank_shixun_challenges, @exercise_questions = @bank.exercise_bank_questions&.includes(:exercise_bank_choices, :exercise_bank_shixun_challenges,
@ -47,6 +48,38 @@ class ExerciseBanksController < ApplicationController
normal_status(0,"试卷更新成功!") normal_status(0,"试卷更新成功!")
end end
def choose_shixun
search = params[:search]
if !current_user.admin? #当不为管理员的时候
user_school_id = current_user.school_id #当前用户的学校id
if user_school_id.present?
none_shixun_ids = ShixunSchool.where("school_id != #{user_school_id}").pluck(:shixun_id)
@publish_shixuns = Shixun.where.not(id: none_shixun_ids).unhidden
end
else
@publish_shixuns = Shixun.unhidden
end
if search.present?
@publish_shixuns = @publish_shixuns.search_by_name(search)
end
@shixuns = @publish_shixuns.joins(:challenges).where("challenges.st != 0").distinct
# 全部页面,需返回
@shixuns_count = @shixuns.count
# 分页
@page = params[:page] || 1
@limit = params[:limit] || 8
@shixuns = @shixuns.page(@page).per(@limit)
end
#确认实训的选择
def commit_shixun
@shixun_challenges = @shixun.challenges
@shixun_challenges_count = @shixun_challenges.size
end
private private
def find_bank def find_bank
@ -57,4 +90,17 @@ class ExerciseBanksController < ApplicationController
def bank_admin def bank_admin
tip_exception(403, "无权限") unless (current_user.certification_teacher? && @bank.user_id == current_user.id) || current_user.admin? tip_exception(403, "无权限") unless (current_user.certification_teacher? && @bank.user_id == current_user.id) || current_user.admin?
end end
#判断实训是否已选择
def commit_shixun_present
question_shixun_ids = @exercise.exercise_bank_questions.pluck(:shixun_id).reject(&:blank?)
shixun_id = params[:shixun_id]
@shixun = Shixun.find_by(id: shixun_id)
if shixun_id.present? && question_shixun_ids.include?(shixun_id)
normal_status(-1,"该实训已选择!")
elsif @shixun.blank?
normal_status(-1,"该实训不存在!")
end
end
end end

@ -901,9 +901,9 @@ class PollsController < ApplicationController
error_question = [] error_question = []
@poll_multi_questions.each do |q| @poll_multi_questions.each do |q|
poll_user_votes = current_user.poll_votes.where(poll_question_id:q.id)&.size poll_user_votes = current_user.poll_votes.where(poll_question_id:q.id)&.size
if q.max_choices.present? && (poll_user_votes > q.max_choices) if q.max_choices.present? && (q.max_choices > 0) && (poll_user_votes > q.max_choices)
error_messages = "#{q.question_number}题:超过最大选项限制" error_messages = "#{q.question_number}题:超过最大选项限制"
elsif q.min_choices.present? && (poll_user_votes < q.min_choices) elsif q.min_choices.present? && (q.min_choices > 0)&& (poll_user_votes < q.min_choices)
error_messages = "#{q.question_number}题:不得少于最小选项限制" error_messages = "#{q.question_number}题:不得少于最小选项限制"
else else
error_messages = nil error_messages = nil
@ -936,7 +936,7 @@ class PollsController < ApplicationController
def commit_result def commit_result
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
begin begin
@poll_users = @poll.all_poll_users(current_user.id) @poll_users = @poll.all_poll_users(current_user.id).where(commit_status:1) # 问卷已提交的用户
@poll_commit_ids = @poll_users.commit_by_status(1).pluck(:user_id) #问卷提交用户的id @poll_commit_ids = @poll_users.commit_by_status(1).pluck(:user_id) #问卷提交用户的id
@page = params[:page] || 1 @page = params[:page] || 1
@limit = params[:limit] || 10 @limit = params[:limit] || 10

@ -1,6 +1,7 @@
class QuestionBanksController < ApplicationController class QuestionBanksController < ApplicationController
before_action :require_login, :check_auth before_action :require_login, :check_auth
before_action :params_filter, except: [:my_courses] before_action :params_filter, except: [:my_courses]
before_action :teacher_or_admin, except: [:bank_list]
# 题库选用列表 # 题库选用列表
# object_type: # normal 普通作业题库; group 分组作业题库; poll问卷题库 exercise试卷题库; gtask 毕设选题题库gtopic 毕设任务 # object_type: # normal 普通作业题库; group 分组作业题库; poll问卷题库 exercise试卷题库; gtask 毕设选题题库gtopic 毕设任务
@ -81,24 +82,29 @@ class QuestionBanksController < ApplicationController
def my_courses def my_courses
@courses = current_user.manage_courses.where(is_delete: 0, is_end: 0) @courses = current_user.manage_courses.where(is_delete: 0, is_end: 0)
unless params[:search].blank?
@courses = @courses.where("name like ?", "%#{params[:search].strip}%")
end
end end
def send_to_course def send_to_course
bank = current_bank banks = object_banks
course = current_user.manage_courses.find_by(id: params[:course_id]) course = current_user.manage_courses.find_by!(id: params[:course_id])
case @object_type banks.each do |bank|
when 'HomeworkBank' # 作业 case @object_type
quote_homework_bank bank, course when 'HomeworkBank' # 作业
when 'ExerciseBank' quote_homework_bank bank, course
if bank.container_type == 'Exercise' # 试卷 when 'ExerciseBank'
quote_exercise_bank bank, course if bank.container_type == 'Exercise' # 试卷
else # 问卷 quote_exercise_bank bank, course
quote_poll_bank bank, course else # 问卷
quote_poll_bank bank, course
end
when 'GtaskBank'
quote_gtask_bank bank, course
when 'GtopicBank'
quote_gtopic_bank bank, course
end end
when 'GtaskBank'
quote_gtask_bank bank, course
when 'GtopicBank'
quote_gtopic_bank bank, course
end end
normal_status("发送成功") normal_status("发送成功")
end end
@ -106,7 +112,7 @@ class QuestionBanksController < ApplicationController
def destroy def destroy
bank = current_bank bank = current_bank
unless user.admin? || bank.user_id == user.id unless current_user.admin? || bank.user_id == current_user.id
render_forbidden render_forbidden
return return
end end
@ -121,11 +127,32 @@ class QuestionBanksController < ApplicationController
render_ok render_ok
end end
def multi_delete
@objects = object_banks
@objects.destroy_all
normal_status("删除成功")
end
def multi_public
@objects = object_banks
@objects.update_all(is_public: true)
normal_status("更新成功")
end
private private
def object_banks
banks ||= @object_type.classify.constantize.where(@object_filter).where(id: params[:object_id])
unless current_user.admin?
banks = banks.where(user_id: current_user.id)
end
banks
end
def current_bank def current_bank
@_current_bank ||= @object_type.classify.constantize.where(@object_filter).find(params[:id]) @_current_bank ||= @object_type.classify.constantize.where(@object_filter).find(params[:id])
end end
def params_filter def params_filter
type = ["normal", "group", "poll", "exercise", "gtask", "gtopic"] type = ["normal", "group", "poll", "exercise", "gtask", "gtopic"]
tip_exception("object_type类型不正确") unless type.include?(params[:object_type]) tip_exception("object_type类型不正确") unless type.include?(params[:object_type])
@ -152,6 +179,10 @@ class QuestionBanksController < ApplicationController
end end
end end
def teacher_or_admin
tip_exception(403, "无权限操作") unless current_user.is_certification_teacher || current_user.admin?
end
def quote_homework_bank homework, course def quote_homework_bank homework, course
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
# 复制作业的基本信息 # 复制作业的基本信息

@ -8,7 +8,7 @@ class Users::QuestionBanksController < Users::BaseController
@count = question_banks.count @count = question_banks.count
@course_lists = service.course_lists @course_lists = service.course_lists
@question_banks = paginate(question_banks.includes(:user, :course_list), special: true) @question_banks = paginate(question_banks.includes(:user, :course_list))
load_question_banks_solve_count # for solve n + 1 load_question_banks_solve_count # for solve n + 1
end end
@ -18,8 +18,8 @@ class Users::QuestionBanksController < Users::BaseController
def load_question_banks_solve_count def load_question_banks_solve_count
question_bank_ids = @question_banks.map(&:id) question_bank_ids = @question_banks.map(&:id)
@solve_count_map = @solve_count_map =
case params[:category] case params[:object_type]
when 'common', 'group' then when 'normal', 'group' then
StudentWork.where(is_delete: false, work_status: [1, 2, 3]).joins(:homework_common) StudentWork.where(is_delete: false, work_status: [1, 2, 3]).joins(:homework_common)
.where(homework_commons: { homework_bank_id: question_bank_ids }) .where(homework_commons: { homework_bank_id: question_bank_ids })
.group('homework_commons.homework_bank_id').count .group('homework_commons.homework_bank_id').count
@ -42,14 +42,14 @@ class Users::QuestionBanksController < Users::BaseController
end end
def query_params def query_params
params.permit(:type, :category, :course_list_id, :sort_by, :sort_direction) params.permit(:type, :object_type, :course_list_id, :sort_by, :sort_direction)
end end
def check_query_params! def check_query_params!
params[:type] = 'personal' if params[:type].blank? || !%w(personal publicly).include?(params[:type]) params[:type] = 'personal' if params[:type].blank? || !%w(personal publicly).include?(params[:type])
if params[:category].blank? || !%w(common group exercise poll gtask gtopic).include?(params[:category]) if params[:object_type].blank? || !%w(normal group exercise poll gtask gtopic).include?(params[:object_type])
params[:category] = 'common' params[:object_type] = 'normal'
end end
if params[:sort_by].blank? || !%w(updated_at name contributor).include?(params[:sort_by]) if params[:sort_by].blank? || !%w(updated_at name contributor).include?(params[:sort_by])

@ -22,8 +22,8 @@ class Users::QuestionBankService
course_lists = CourseList.joins(relation_name).where.not(relation_name => { id: nil }) course_lists = CourseList.joins(relation_name).where.not(relation_name => { id: nil })
category_condition = category_condition =
case params[:category] case params[:object_type]
when 'common' then { homework_type: 1 } when 'normal' then { homework_type: 1 }
when 'group' then { homework_type: 3 } when 'group' then { homework_type: 3 }
when 'exercise' then { container_type: 'Exercise' } when 'exercise' then { container_type: 'Exercise' }
when 'poll' then { container_type: 'Poll' } when 'poll' then { container_type: 'Poll' }
@ -47,8 +47,8 @@ class Users::QuestionBankService
def class_name def class_name
@_class_name ||= begin @_class_name ||= begin
case params[:category] case params[:object_type]
when 'common', 'group' then 'HomeworkBank' when 'normal', 'group' then 'HomeworkBank'
when 'exercise', 'poll' then 'ExerciseBank' when 'exercise', 'poll' then 'ExerciseBank'
when 'gtask' then 'GtaskBank' when 'gtask' then 'GtaskBank'
when 'gtopic' then 'GtopicBank' when 'gtopic' then 'GtopicBank'
@ -58,8 +58,8 @@ class Users::QuestionBankService
end end
def category_filter(relations) def category_filter(relations)
case params[:category] case params[:object_type]
when 'common' then when 'normal' then
relations.where(homework_type: 1) relations.where(homework_type: 1)
when 'group' then when 'group' then
relations.where(homework_type: 3) relations.where(homework_type: 3)

@ -17,15 +17,16 @@
</td> </td>
<td> <td>
<!-- 图片上传,稍后添加--> <!-- 图片上传,稍后添加-->
--
<a href="javascript:void(0);" id="object_upload_img_<%= shixun.id %>" onclick="$('#upload_img_<%= shixun.id %>').click();"> <!-- <a href="javascript:void(0);" id="object_upload_img_<%#= shixun.id %>" onclick="$('#upload_img_<%= shixun.id %>').click();">-->
<%= File.exist?(disk_filename("Shixun",shixun.id)) ? "重新上传" : "上传图片" %> <%#= File.exist?(disk_filename("Shixun",shixun.id)) ? "重新上传" : "上传图片" %>
</a> <!-- </a>-->
<% if File.exist?(disk_filename("Shixun",shixun.id)) %> <%# if File.exist?(disk_filename("Shixun",shixun.id)) %>
<%= image_tag(url_to_avatar(shixun), :class => "w80 h80 fl ml5 shixun_image_show", :id => "shixun_image_show_#{shixun.id}") %> <%#= image_tag(url_to_avatar(shixun), :class => "w80 h80 fl ml5 shixun_image_show", :id => "shixun_image_show_#{shixun.id}") %>
<% else %> <%# else %>
<img src="" class="w80 h80 fl ml5 shixun_image_show none" id="shixun_image_show_<%= shixun.id %>"/> <!-- <img src="" class="w80 h80 fl ml5 shixun_image_show none" id="shixun_image_show_<%#= shixun.id %>"/>-->
<% end %> <%# end %>
</td> </td>
<td><%= link_to shixun.owner.try(:show_real_name),"/users/#{shixun.owner.login}",target:'_blank' %></td> <td><%= link_to shixun.owner.try(:show_real_name),"/users/#{shixun.owner.login}",target:'_blank' %></td>

@ -0,0 +1,10 @@
json.shixun_counts @shixuns_count
json.shixuns do
json.array! @shixuns do |s|
json.shixun_id s.id
json.shixun_name s.name
json.shixun_user s.user.real_name
json.shixun_user_count s.myshixuns_count
end
end

@ -0,0 +1,10 @@
json.shixun_id @shixun.id
json.shixun_name @shixun.name
json.challenges do
json.array! @shixun_challenges do |s|
json.challenge_name s.subject
end
end
json.challenge_counts @shixun_challenges_count

@ -31,6 +31,11 @@ else
json.question_status @question_status json.question_status @question_status
end end
exercise_type = 3
if @t_user_exercise_status == 3 && @exercise.answer_open
exercise_type = 4
end
json.partial! "exercises/exercise_scores" json.partial! "exercises/exercise_scores"
json.exercise_questions do json.exercise_questions do
@ -57,7 +62,7 @@ json.exercise_questions do
shixun_challenges: question.exercise_shixun_challenges, shixun_challenges: question.exercise_shixun_challenges,
user_answer: question_info[:answered_content], user_answer: question_info[:answered_content],
choices:question.exercise_choices, choices:question.exercise_choices,
exercise_type:3, exercise_type:exercise_type,
shixun_type:question_info[:shixun_type], shixun_type:question_info[:shixun_type],
ques_position: q[:ques_number], ques_position: q[:ques_number],
edit_type:nil edit_type:nil

@ -14,7 +14,7 @@ if @poll_questions_count > 0
json.array! @poll_questions do |question| json.array! @poll_questions do |question|
json.partial! "polls/commit_answers_result", question: question, json.partial! "polls/commit_answers_result", question: question,
answers:question.poll_answers, answers:question.poll_answers,
question_votes:question.poll_votes #问题的全部答案 question_votes:question.poll_votes.where(user_id:@poll_commit_ids) #问题的全部答案
end end
end end
else else

@ -632,6 +632,8 @@ Rails.application.routes.draw do
post :save_banks post :save_banks
get :my_courses get :my_courses
post :send_to_course post :send_to_course
delete :multi_delete
post :multi_public
end end
end end
@ -643,7 +645,23 @@ Rails.application.routes.draw do
resources :gtopic_banks resources :gtopic_banks
resources :task_banks resources :task_banks
resources :exercise_banks
resources :exercise_banks do
collection do
get :choose_shixun
end
member do
get :commit_shixun
end
end
resources :exercise_bank_questions do
member do
post :up_down
get :choose_shixun
end
end
resources :attachments resources :attachments

@ -0,0 +1,5 @@
class MigrateGtopicBankIsPublic < ActiveRecord::Migration[5.2]
def change
change_column :gtopic_banks, :is_public, :boolean, default: 0
end
end

@ -0,0 +1,11 @@
class MigrateCourseGroupPosition < ActiveRecord::Migration[5.2]
def change
Course.all.each do |course|
if course.course_groups.exists?(position: 0)
course.course_groups.each_with_index do |group, index|
group.update_attributes(position: index+1)
end
end
end
end
end

File diff suppressed because one or more lines are too long

@ -38362,46 +38362,37 @@ $(document).on('turbolinks:load', function() {
; ;
$(document).on('turbolinks:load', function() { $(document).on('turbolinks:load', function() {
if ($('body.admins-shixun-settings-index-page').length > 0) { if ($('body.admins-shixun-settings-index-page').length > 0) {
$(".shixun-settings-select").on("change", function () {
var s_value = $(this).val();
var s_name = $(this).attr("name");
var json = {};
json[s_name] = s_value;
$.ajax({
url: "/admins/shixun_settings",
type: "GET",
dataType:'script',
data: json
})
});
$(".shixun-setting-form").on("change",function () {
var s_id = $(this).attr("data-id");
var s_value = $(this).val();
var s_name = $(this).attr("name");
var json = {};
var s_index = $(this).parent("td").siblings(".shixun-line-no").text();
json[s_name] = s_value;
json["page_no"] = s_index;
$.ajax({
url: "/admins/shixun_settings/" + s_id,
type: "PUT",
dataType:'script',
data: json
})
})
} }
}); });
function update_change(target) {
var s_id = $(target).attr("data-id");
var s_value = $(target).val();
var s_name = $(target).attr("name");
var json = {};
var s_index = $(target).parent("td").siblings(".shixun-line-no").text();
json[s_name] = s_value;
json["page_no"] = s_index;
$.ajax({
url: "/admins/shixun_settings/" + s_id,
type: "PUT",
dataType:'script',
data: json,
success: function (data) {
}
})
}
function select_change(target) {
var s_value = $(target).val();
var s_name = $(target).attr("name");
var json = {};
json[s_name] = s_value;
$.ajax({
url: "/admins/shixun_settings/",
type: "GET",
dataType:'script',
data: json,
success: function (data) {
}
})
}
;
$(document).on('turbolinks:load', function() { $(document).on('turbolinks:load', function() {
$('select#tag-choosed').select2({ $('select#tag-choosed').select2({
placeholder: "请选择分类", placeholder: "请选择分类",

@ -18726,6 +18726,13 @@ input[type="checkbox"] {
border: 1px solid #eee !important; border: 1px solid #eee !important;
} }
/* line 10, app/assets/stylesheets/admins/shixun_settings.scss */
.setting-chosen {
font-weight: 400;
font-size: 10px;
color: #333;
}
/* line 1, app/assets/stylesheets/admins/sidebar.scss */ /* line 1, app/assets/stylesheets/admins/sidebar.scss */
#sidebar { #sidebar {
min-width: 200px; min-width: 200px;

@ -38362,46 +38362,37 @@ $(document).on('turbolinks:load', function() {
; ;
$(document).on('turbolinks:load', function() { $(document).on('turbolinks:load', function() {
if ($('body.admins-shixun-settings-index-page').length > 0) { if ($('body.admins-shixun-settings-index-page').length > 0) {
$(".shixun-settings-select").on("change", function () {
var s_value = $(this).val();
var s_name = $(this).attr("name");
var json = {};
json[s_name] = s_value;
$.ajax({
url: "/admins/shixun_settings",
type: "GET",
dataType:'script',
data: json
})
});
$(".shixun-setting-form").on("change",function () {
var s_id = $(this).attr("data-id");
var s_value = $(this).val();
var s_name = $(this).attr("name");
var json = {};
var s_index = $(this).parent("td").siblings(".shixun-line-no").text();
json[s_name] = s_value;
json["page_no"] = s_index;
$.ajax({
url: "/admins/shixun_settings/" + s_id,
type: "PUT",
dataType:'script',
data: json
})
})
} }
}); });
function update_change(target) {
var s_id = $(target).attr("data-id");
var s_value = $(target).val();
var s_name = $(target).attr("name");
var json = {};
var s_index = $(target).parent("td").siblings(".shixun-line-no").text();
json[s_name] = s_value;
json["page_no"] = s_index;
$.ajax({
url: "/admins/shixun_settings/" + s_id,
type: "PUT",
dataType:'script',
data: json,
success: function (data) {
}
})
}
function select_change(target) {
var s_value = $(target).val();
var s_name = $(target).attr("name");
var json = {};
json[s_name] = s_value;
$.ajax({
url: "/admins/shixun_settings/",
type: "GET",
dataType:'script',
data: json,
success: function (data) {
}
})
}
;
$(document).on('turbolinks:load', function() { $(document).on('turbolinks:load', function() {
$('select#tag-choosed').select2({ $('select#tag-choosed').select2({
placeholder: "请选择分类", placeholder: "请选择分类",

@ -18726,6 +18726,13 @@ input[type="checkbox"] {
border: 1px solid #eee !important; border: 1px solid #eee !important;
} }
/* line 10, app/assets/stylesheets/admins/shixun_settings.scss */
.setting-chosen {
font-weight: 400;
font-size: 10px;
color: #333;
}
/* line 1, app/assets/stylesheets/admins/sidebar.scss */ /* line 1, app/assets/stylesheets/admins/sidebar.scss */
#sidebar { #sidebar {
min-width: 200px; min-width: 200px;
@ -19421,6 +19428,13 @@ input[type="checkbox"] {
.select2 .select2-selection__choice { .select2 .select2-selection__choice {
border: 1px solid #eee !important; border: 1px solid #eee !important;
} }
/* line 10, app/assets/stylesheets/admins/shixun_settings.scss */
.setting-chosen {
font-weight: 400;
font-size: 10px;
color: #333;
}
/* line 1, app/assets/stylesheets/admins/sidebar.scss */ /* line 1, app/assets/stylesheets/admins/sidebar.scss */
#sidebar { #sidebar {
min-width: 200px; min-width: 200px;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -55,6 +55,9 @@ html, body {
.markdown-body p { .markdown-body p {
white-space: pre-wrap; white-space: pre-wrap;
} }
.markdown-body > p {
line-height: 25px;
}
/* https://www.educoder.net/courses/2346/group_homeworks/34405/question */ /* https://www.educoder.net/courses/2346/group_homeworks/34405/question */
.renderAsHtml.markdown-body p { .renderAsHtml.markdown-body p {
white-space: inherit; white-space: inherit;

@ -222,6 +222,12 @@ const InfosIndex = Loadable({
loader: () => import('./modules/user/usersInfo/InfosIndex'), loader: () => import('./modules/user/usersInfo/InfosIndex'),
loading: Loading, loading: Loading,
}) })
// 题库
const BanksIndex = Loadable({
loader: () => import('./modules/user/usersInfo/banks/BanksIndex'),
loading: Loading,
})
// 教学案例 // 教学案例
const MoopCases = Loadable({ const MoopCases = Loadable({
@ -365,6 +371,13 @@ class App extends Component {
} }
}></Route> }></Route>
<Route path="/banks"
render={
(props) => {
return (<BanksIndex {...this.props} {...props} {...this.state} />)
}
}></Route>
<Route <Route
path="/changepassword" component={EducoderLogin} path="/changepassword" component={EducoderLogin}
/> />

@ -493,7 +493,8 @@ class Fileslists extends Component{
let selectpagetype=selectpage===page?true:false let selectpagetype=selectpage===page?true:false
this.setState({ this.setState({
page:page, page:page,
checkAllValue:selectpagetype checkAllValue:selectpagetype,
checkBoxValues:[]
}) })
let{pagesize,tagname,searchValue,sort,sorttype,coursesecondcategoryid}=this.state; let{pagesize,tagname,searchValue,sort,sorttype,coursesecondcategoryid}=this.state;
@ -801,7 +802,7 @@ class Fileslists extends Component{
{this.props.isAdmin()? files===undefined?'' :files.length===0? "":<div className="mt20 edu-back-white padding20-30" style={{display:this.props.isAdmin()||this.props.isStudent()?"":"none"}}> {this.props.isAdmin()? files===undefined?'' :files.length===0? "":<div className="mt20 edu-back-white padding20-30" style={{display:this.props.isAdmin()||this.props.isStudent()?"":"none"}}>
<div className="clearfix"> <div className="clearfix">
{this.props.isAdmin()? <Checkbox className="fl" onChange={this.onCheckAll} checked={checkAllValue}>已选 {checkBoxValues.length} </Checkbox>:""} {this.props.isAdmin()? <Checkbox className="fl" onChange={this.onCheckAll} checked={checkAllValue}>已选 {checkBoxValues.length} 不支持跨页勾选</Checkbox>:""}
<div className="studentList_operation_ul"> <div className="studentList_operation_ul">
{this.props.isAdmin()?<li className="li_line"><a href="javascript:void(0)" className="color-grey-9" onClick={this.onDelete}>删除</a></li>:""} {this.props.isAdmin()?<li className="li_line"><a href="javascript:void(0)" className="color-grey-9" onClick={this.onDelete}>删除</a></li>:""}
{this.props.isAdmin()?<li className="li_line"><a href="javascript:void(0)" className="color-grey-9" onClick={this.onSend}>发送</a></li>:""} {this.props.isAdmin()?<li className="li_line"><a href="javascript:void(0)" className="color-grey-9" onClick={this.onSend}>发送</a></li>:""}

@ -283,6 +283,9 @@ class Boards extends Component{
console.log('checked = ', checkedValues); console.log('checked = ', checkedValues);
} }
onPageChange = (pageNumber) => { onPageChange = (pageNumber) => {
this.setState({
checkBoxValues:[]
})
this.fetchAll(null, pageNumber) this.fetchAll(null, pageNumber)
} }
@ -365,7 +368,7 @@ class Boards extends Component{
{messages&&messages.length == 0?"": isAdmin && <div className="mt20 edu-back-white padding20-30"> {messages&&messages.length == 0?"": isAdmin && <div className="mt20 edu-back-white padding20-30">
<div className="clearfix"> <div className="clearfix">
{isAdmin&&<Checkbox className="fl" onChange={this.onCheckAll} checked={checkAllValue}>已选 {checkBoxValues.length} </Checkbox>} {isAdmin&&<Checkbox className="fl" onChange={this.onCheckAll} checked={checkAllValue}>已选 {checkBoxValues.length} 不支持跨页勾选</Checkbox>}
<div className="studentList_operation_ul"> <div className="studentList_operation_ul">
{ !!isAdmin && { !!isAdmin &&
<React.Fragment> <React.Fragment>

@ -3,11 +3,11 @@ import { Input, InputNumber, Form, Button, Checkbox, Upload, Icon, message, Moda
import axios from 'axios' import axios from 'axios'
import '../css/busyWork.css' import '../css/busyWork.css'
import '../css/Courses.css' import '../css/Courses.css'
import { WordsBtn, getUrl, ConditionToolTip, appendFileSizeToUploadFile, appendFileSizeToUploadFileAll } from 'educoder' import { WordsBtn, getUrl, ConditionToolTip } from 'educoder'
import TPMMDEditor from '../../tpm/challengesnew/TPMMDEditor';
import CBreadcrumb from '../common/CBreadcrumb' import CBreadcrumb from '../common/CBreadcrumb'
import NewWorkForm from './NewWorkForm'
const confirm = Modal.confirm;
const $ = window.$ const $ = window.$
const MAX_TITLE_LENGTH = 60; const MAX_TITLE_LENGTH = 60;
class NewWork extends Component{ class NewWork extends Component{
@ -17,15 +17,6 @@ class NewWork extends Component{
this.answerMdRef = React.createRef(); this.answerMdRef = React.createRef();
this.state={ this.state={
title_value:"",
title_num: 0,
contentFileList: [],
answerFileList: [],
workLoaded: false,
base_on_project: true,
category: {},
min_num: 2,
max_num: 10,
} }
} }
componentDidMount () { componentDidMount () {
@ -50,7 +41,6 @@ class NewWork extends Component{
course_id: data.course_id, course_id: data.course_id,
course_name: data.course_name, course_name: data.course_name,
category: data.category, category: data.category,
}) })
} }
}) })
@ -65,56 +55,13 @@ class NewWork extends Component{
.then((response) => { .then((response) => {
if (response.data.name) { if (response.data.name) {
const data = response.data; const data = response.data;
data.isEdit = true;
const contentFileList = data.attachments.map(item => {
return {
id: item.id,
uid: item.id,
name: appendFileSizeToUploadFile(item),
url: item.url,
filesize: item.filesize,
status: 'done'
}
})
const answerFileList = data.ref_attachments.map(item => {
return {
id: item.id,
uid: item.id,
name: appendFileSizeToUploadFile(item),
url: item.url,
filesize: item.filesize,
status: 'done'
}
})
this.setState({ this.setState({
...data, category: data.category,
// course_id: data.course_id, course_id: data.course_id,
// course_name: data.course_name, course_name: data.course_name,
// category: data.category,
title_num: parseInt(data.name.length),
workLoaded: true,
init_min_num: data.min_num,
init_max_num: data.max_num,
// description: data.description,
reference_answer: data.reference_answer,
contentFileList,
answerFileList,
}, () => {
setTimeout(() => {
this.contentMdRef.current.setValue(data.description || '')
this.answerMdRef.current.setValue(data.reference_answer || '')
}, 2000)
this.props.form.setFieldsValue({
title: data.name,
description: data.description || '',
reference_answer: data.reference_answer || '',
});
}) })
this.newWorkFormRef.initValue(data);
} }
}) })
.catch(function (error) { .catch(function (error) {
@ -122,72 +69,12 @@ class NewWork extends Component{
}); });
} }
// 输入title doEdit = (params) => {
changeTitle=(e)=>{
console.log(e.target.value.length);
this.setState({
title_num: parseInt(e.target.value.length)
})
}
handleSubmit = () => {
const courseId = this.state.course_id || this.props.match.params.coursesId ;
this.props.form.validateFieldsAndScroll((err, values) => {
console.log(values)
const mdContnet = this.contentMdRef.current.getValue().trim();
console.log(mdContnet)
values.description = mdContnet;
// return;
{/* max={has_commit ? init_min_num : null } */}
{/* min={has_commit ? init_max_num : (min_num == undefined ? 2 : min_num + 1) } */}
// 已有提交作品,人数范围只能扩大
const { has_commit, max_num, init_max_num, min_num, init_min_num } = this.state;
if (has_commit) {
if (max_num < init_max_num || min_num > init_min_num) {
this.props.showNotification(`已有提交作品,人数范围只能扩大(原设置为:${init_min_num} - ${init_max_num})`)
return;
}
}
// const errKeys = Object.keys(err); // || errKeys.length == 1 && errKeys[0] == 'content' && mdContnet
if (!err) {
if (this.isEdit) {
this.doEdit(courseId, values)
} else {
this.doNew(courseId, values)
}
} else {
$("html").animate({ scrollTop: $('html').scrollTop() - 100 })
}
})
}
doEdit = (courseId, values) => {
const workId = this.props.match.params.workId const workId = this.props.match.params.workId
const newUrl = `/homework_commons/${workId}.json` const newUrl = `/homework_commons/${workId}.json`
let attachment_ids = this.state.contentFileList.map(item => {
return item.response ? item.response.id : item.id
})
let reference_attachment_ids = this.state.answerFileList.map(item => {
return item.response ? item.response.id : item.id
})
const { min_num, max_num, base_on_project, category } = this.state
const isGroup = this.props.isGroup() const isGroup = this.props.isGroup()
axios.put(newUrl, { axios.put(newUrl, params)
type: isGroup ? 3 : 1,
name: values.title,
description: values.description,
reference_answer: values.reference_answer,
attachment_ids,
reference_attachment_ids,
min_num,
max_num,
base_on_project
})
.then((response) => { .then((response) => {
if (response.data.status == 0) { if (response.data.status == 0) {
this.props.showNotification('保存成功') this.props.showNotification('保存成功')
@ -198,30 +85,11 @@ class NewWork extends Component{
console.log(error); console.log(error);
}); });
} }
doNew = (courseId, values) => { doNew = (params) => {
const courseId = this.props.match.params.coursesId ;
const newUrl = `/courses/${courseId}/homework_commons.json` const newUrl = `/courses/${courseId}/homework_commons.json`
let attachment_ids = this.state.contentFileList.map(item => { axios.post(newUrl, params)
return item.response ? item.response.id : item.id
})
let reference_attachment_ids = this.state.answerFileList.map(item => {
return item.response ? item.response.id : item.id
})
const isGroup = this.props.isGroup()
const { min_num, max_num, base_on_project, category } = this.state
axios.post(newUrl, {
type: isGroup ? 3 : 1,
name: values.title,
description: values.description,
reference_answer: values.reference_answer,
attachment_ids,
reference_attachment_ids,
min_num,
max_num,
base_on_project
})
.then((response) => { .then((response) => {
if (response.data.status == 0) { if (response.data.status == 0) {
this.props.showNotification('保存成功') this.props.showNotification('保存成功')
@ -233,143 +101,25 @@ class NewWork extends Component{
}); });
} }
handleContentUploadChange = (info) => {
let contentFileList = info.fileList;
this.setState({ contentFileList: appendFileSizeToUploadFileAll(contentFileList) });
}
handleAnswerUploadChange = (info) => {
let answerFileList = info.fileList;
this.setState({ answerFileList: appendFileSizeToUploadFileAll(answerFileList) });
}
onAttachmentRemove = (file, stateName) => {
this.props.confirm({
content: '是否确认删除?',
onOk: () => {
this.deleteAttachment(file, stateName)
},
onCancel() {
console.log('Cancel');
},
});
return false;
}
deleteAttachment = (file, stateName) => {
// 初次上传不能直接取uid
const url = `/attachments/${file.response ? file.response.id : file.uid}.json`
axios.delete(url, {
})
.then((response) => {
if (response.data) {
const { status } = response.data;
if (status == 0) {
console.log('--- success')
this.setState((state) => {
const index = state[stateName].indexOf(file);
const newFileList = state[stateName].slice();
newFileList.splice(index, 1);
return {
[stateName]: newFileList,
};
});
}
}
})
.catch(function (error) {
console.log(error);
});
}
max_num_change = (val) => {
if (val < 2) {
this.setState({
max_num: 2,
})
return;
}
const { min_num } = this.state;
this.setState({
max_num: val,
min_num: val <= min_num ? val - 1 : min_num
})
}
min_num_change = (val) => {
this.setState({ min_num: val })
}
base_on_project_change = () => {
this.setState({ base_on_project: !this.state.base_on_project })
}
render(){ render(){
let {typeId,coursesId,pageType}=this.props.match.params; let {typeId,coursesId,pageType}=this.props.match.params;
const { getFieldDecorator } = this.props.form;
const isGroup = this.props.isGroup() const isGroup = this.props.isGroup()
const moduleName = !isGroup? "普通作业":"分组作业"; const moduleName = !isGroup? "普通作业":"分组作业";
const moduleEngName = this.props.getModuleName() const moduleEngName = this.props.getModuleName()
let{ let{
title_value, contentFileList, answerFileList, max_num, min_num, base_on_project, category
init_max_num, init_min_num,
title_num, course_name, category, has_commit, has_project
}=this.state }=this.state
const { current_user } = this.props const { current_user } = this.props
const courseId = this.state.course_id || this.props.match.params.coursesId ; const courseId = this.props.match.params.coursesId ;
const isEdit = this.isEdit; const isEdit = this.isEdit;
if ((isEdit == undefined || isEdit) && !this.state.workLoaded) {
return ''
}
const uploadProps = {
width: 600,
fileList: contentFileList,
multiple: true,
// https://github.com/ant-design/ant-design/issues/15505
// showUploadList={false},然后外部拿到 fileList 数组自行渲染列表。
// showUploadList: false,
action: `${getUrl()}/api/attachments.json`,
onChange: this.handleContentUploadChange,
onRemove: (file) => this.onAttachmentRemove(file, 'contentFileList'),
beforeUpload: (file) => {
console.log('beforeUpload', file.name);
const isLt150M = file.size / 1024 / 1024 < 150;
if (!isLt150M) {
message.error('文件大小必须小于150MB!');
}
return isLt150M;
},
};
const answerUploadProps = {
width: 600,
fileList: answerFileList,
multiple: true,
// https://github.com/ant-design/ant-design/issues/15505
// showUploadList={false},然后外部拿到 fileList 数组自行渲染列表。
// showUploadList: false,
action: `${getUrl()}/api/attachments.json`,
onChange: this.handleAnswerUploadChange,
onRemove: (file) => this.onAttachmentRemove(file, 'answerFileList'),
beforeUpload: (file) => {
console.log('beforeUpload', file.name);
const isLt150M = file.size / 1024 / 1024 < 150;
if (!isLt150M) {
message.error('文件大小必须小于150MB!');
}
return isLt150M;
},
};
return( return(
<div className="newMain"> <div className="newMain">
<div className="educontent mt20 mb50"> <div className="educontent mt20 mb50">
{/* <p className="clearfix">
<WordsBtn style="grey" className="fl">{course_name}</WordsBtn>
<span className="color-grey-9 fl ml3 mr3">&gt;</span>
<WordsBtn style="grey" className="fl">{typeId==1 ?"普通作业":"分组作业"}</WordsBtn>
<span className="color-grey-9 fl ml3 mr3">&gt;</span>
<span>{pageType==="new"?"新建":"编辑"}</span>
</p> */}
<CBreadcrumb items={[ <CBreadcrumb items={[
{ to: current_user && current_user.first_category_url, name: this.state.course_name}, { to: current_user && current_user.first_category_url, name: this.state.course_name},
{ to: `/courses/${courseId}/${moduleEngName}/${category && category.category_id ? category.category_id : ''}` { to: `/courses/${courseId}/${moduleEngName}/${category && category.category_id ? category.category_id : ''}`
@ -388,161 +138,16 @@ class NewWork extends Component{
</a> </a>
</p> </p>
<div> <div>
{/* onSubmit={this.handleSubmit} */} <NewWorkForm wrappedComponentRef={(ref) => {this.newWorkFormRef = ref}}
<style> {...this.props}
{ onSave={this.onSave}
` doNew={this.doNew}
.yslnewworkinputaddonAfter .ant-input{ doEdit={this.doEdit}
border-right: none !important; ></NewWorkForm>
height: 40px !important;
}
`
}
</style>
<Form className="courseForm">
<Form.Item
label="标题"
className="AboutInputForm"
>
{getFieldDecorator('title', {
rules: [{
required: true, message: '请输入标题'
}],
})(
<Input placeholder="请输入作业标题最大限制60个字符" onInput={this.changeTitle} className="searchView yslnewworkinputaddonAfter searchViewAfter" style={{"width":"100%"}} maxLength={MAX_TITLE_LENGTH} addonAfter={`${String(title_num)}/${MAX_TITLE_LENGTH}`}/>
)}
</Form.Item>
<style>{`
.uploadBtn.ant-btn {
border: none;
color: #4CACFF;
box-shadow: none;
background: transparent;
padding: 0 6px;
}
.ant-upload-list-item:hover .ant-upload-list-item-info{
background-color:#fff;
}
.upload_1 .ant-upload-list {
width: 350px;
}
.ant-input-number {
height: 40px;
line-height: 40px;
}
.workContent.AboutInputForm.ant-form-item {
border-bottom: none;
padding-bottom: 0px !important;
}
.newWorkUpload {
padding: 0px 30px 30px 30px!important;
background: #fff;
width: 100%;
display: inline-block;
border-bottom: 1px solid #EDEDED;
}
`}</style>
{ <Form.Item
label="内容"
className="AboutInputForm workContent mdInForm"
>
{getFieldDecorator('description', {
rules: [{
required: true, message: '请输入作业内容和要求'
}],
})(
<TPMMDEditor ref={this.contentMdRef} placeholder="请在此输入作业内容和要求,最大限制5000个字符" mdID={'courseContentMD'} refreshTimeout={1500}
className="courseMessageMD" initValue={this.state.description}></TPMMDEditor>
)}
</Form.Item> }
<Upload {...uploadProps} className="upload_1 newWorkUpload">
<Button className="uploadBtn">
<Icon type="upload" /> 上传附件
</Button>
(单个文件150M以内)
</Upload>
{ isGroup &&
<Form.Item
label="分组设置"
className="AboutInputForm"
>
{getFieldDecorator('personNum', {
rules: [{
required: false
// required: true, message: '请输入最小人数和最大人数'
}],
})(
<div>
<p className="clearfix">
<ConditionToolTip condition={has_commit} title={'已有提交作品,人数范围只能扩大'}>
{/* max={has_commit ? init_min_num : null } */}
<InputNumber placeholder="请填写每组最小人数" min={1} className="winput-240-40" value={min_num}
onChange={this.min_num_change} style={{width:'180px'}} />
</ConditionToolTip>
<span className="ml15 mr15">~</span>
{/* min={has_commit ? init_max_num : (min_num == undefined ? 2 : min_num + 1) } */}
<ConditionToolTip condition={has_commit} title={'已有提交作品,人数范围只能扩大'}>
<InputNumber className="winput-240-40" placeholder="请填写每组最大人数" value={max_num} max={10}
onChange={this.max_num_change} style={{width:'180px'}} />
</ConditionToolTip>
<label className="color-grey-9 ml20 font-14">项目管理员角色的成员都可以提交作品提交作品时需要关联同组成员组内成员作品共享</label>
</p>
<p className="mt20">
<ConditionToolTip condition={has_commit || has_project} title={'已有关联项目或作品,不能修改'}>
<Checkbox checked={base_on_project} onChange={this.base_on_project_change}
disabled={has_project || has_commit}
>基于项目实施</Checkbox>
</ConditionToolTip>
<label className="color-grey-9 ml12 font-14">勾选后各小组必须在educoder平台创建项目教师可随时观察平台对各小组最新进展的实时统计</label>
</p>
</div>
)}
</Form.Item>
}
<Form.Item
label="参考答案"
className="AboutInputForm"
style={{"borderBottom":"none"}}
>
{getFieldDecorator('reference_answer', {
rules: [{
required: false
}],
})(
<TPMMDEditor ref={this.answerMdRef} placeholder="请在此输入作业的参考答案,最大限制5000个字符" mdID={'workAnswerMD'}
className="courseMessageMD" refreshTimeout={1500} initValue={this.state.reference_answer || ''}></TPMMDEditor>
)}
<Upload {...answerUploadProps} className="upload_1">
<Button className="uploadBtn">
<Icon type="upload" /> 上传附件
</Button>
(单个文件150M以内)
</Upload>
</Form.Item>
<Form.Item>
<div className="clearfix mt30 mb30">
{/* htmlType="submit" */}
<Button type="primary" onClick={this.handleSubmit} className="defalutSubmitbtn fl mr20">提交</Button>
<a className="defalutCancelbtn fl" onClick={() => this.props.toListPage(this.props.match.params, category.category_id)}>取消</ a>
</div>
</Form.Item>
</Form>
</div> </div>
</div> </div>
</div> </div>
) )
} }
} }
const WrappedBoardsNew = Form.create({ name: 'NewWork' })(NewWork); export default NewWork;
export default WrappedBoardsNew;

@ -0,0 +1,466 @@
import React,{ Component } from "react";
import { Input, InputNumber, Form, Button, Checkbox, Upload, Icon, message, Modal } from "antd";
import axios from 'axios'
import '../css/busyWork.css'
import '../css/Courses.css'
import { WordsBtn, getUrl, ConditionToolTip, appendFileSizeToUploadFile, appendFileSizeToUploadFileAll } from 'educoder'
import TPMMDEditor from '../../tpm/challengesnew/TPMMDEditor';
import CBreadcrumb from '../common/CBreadcrumb'
const confirm = Modal.confirm;
const $ = window.$
const MAX_TITLE_LENGTH = 60;
class NewWorkForm extends Component{
constructor(props){
super(props);
this.contentMdRef = React.createRef();
this.answerMdRef = React.createRef();
this.state={
title_value:"",
title_num: 0,
contentFileList: [],
answerFileList: [],
workLoaded: false,
base_on_project: true,
category: {},
min_num: 2,
max_num: 10,
}
}
initValue = (data) => {
if (data.isEdit) {
const contentFileList = data.attachments.map(item => {
return {
id: item.id,
uid: item.id,
name: appendFileSizeToUploadFile(item),
url: item.url,
filesize: item.filesize,
status: 'done'
}
})
const answerFileList = data.ref_attachments.map(item => {
return {
id: item.id,
uid: item.id,
name: appendFileSizeToUploadFile(item),
url: item.url,
filesize: item.filesize,
status: 'done'
}
})
this.setState({
...data,
// course_id: data.course_id,
// course_name: data.course_name,
// category: data.category,
title_num: parseInt(data.name.length),
workLoaded: true,
init_min_num: data.min_num,
init_max_num: data.max_num,
// description: data.description,
reference_answer: data.reference_answer,
contentFileList,
answerFileList,
}, () => {
setTimeout(() => {
this.contentMdRef.current.setValue(data.description || '')
this.answerMdRef.current.setValue(data.reference_answer || '')
}, 2000)
this.props.form.setFieldsValue({
title: data.name,
description: data.description || '',
reference_answer: data.reference_answer || '',
});
})
} else { // new
}
}
// 输入title
changeTitle=(e)=>{
console.log(e.target.value.length);
this.setState({
title_num: parseInt(e.target.value.length)
})
}
handleSubmit = () => {
const courseId = this.state.course_id || this.props.match.params.coursesId ;
this.props.form.validateFieldsAndScroll((err, values) => {
console.log(values)
const mdContnet = this.contentMdRef.current.getValue().trim();
console.log(mdContnet)
values.description = mdContnet;
// return;
{/* max={has_commit ? init_min_num : null } */}
{/* min={has_commit ? init_max_num : (min_num == undefined ? 2 : min_num + 1) } */}
// 已有提交作品,人数范围只能扩大
const { has_commit, max_num, init_max_num, min_num, init_min_num } = this.state;
if (has_commit) {
if (max_num < init_max_num || min_num > init_min_num) {
this.props.showNotification(`已有提交作品,人数范围只能扩大(原设置为:${init_min_num} - ${init_max_num})`)
return;
}
}
// const errKeys = Object.keys(err); // || errKeys.length == 1 && errKeys[0] == 'content' && mdContnet
if (!err) {
if (this.state.isEdit) {
this.doEdit(courseId, values)
} else {
this.doNew(courseId, values)
}
} else {
$("html").animate({ scrollTop: $('html').scrollTop() - 100 })
}
})
}
doEdit = (courseId, values) => {
let attachment_ids = this.state.contentFileList.map(item => {
return item.response ? item.response.id : item.id
})
let reference_attachment_ids = this.state.answerFileList.map(item => {
return item.response ? item.response.id : item.id
})
const { min_num, max_num, base_on_project, category } = this.state
const isGroup = this.props.isGroup()
const params = {
type: isGroup ? 3 : 1,
name: values.title,
description: values.description,
reference_answer: values.reference_answer,
attachment_ids,
reference_attachment_ids,
min_num,
max_num,
base_on_project
}
this.props.doEdit && this.props.doEdit(params)
}
doNew = (courseId, values) => {
let attachment_ids = this.state.contentFileList.map(item => {
return item.response ? item.response.id : item.id
})
let reference_attachment_ids = this.state.answerFileList.map(item => {
return item.response ? item.response.id : item.id
})
const isGroup = this.props.isGroup()
const { min_num, max_num, base_on_project, category } = this.state
const params = {
type: isGroup ? 3 : 1,
name: values.title,
description: values.description,
reference_answer: values.reference_answer,
attachment_ids,
reference_attachment_ids,
min_num,
max_num,
base_on_project
}
this.props.doNew && this.props.doNew(params)
}
handleContentUploadChange = (info) => {
let contentFileList = info.fileList;
this.setState({ contentFileList: appendFileSizeToUploadFileAll(contentFileList) });
}
handleAnswerUploadChange = (info) => {
let answerFileList = info.fileList;
this.setState({ answerFileList: appendFileSizeToUploadFileAll(answerFileList) });
}
onAttachmentRemove = (file, stateName) => {
this.props.confirm({
content: '是否确认删除?',
onOk: () => {
this.deleteAttachment(file, stateName)
},
onCancel() {
console.log('Cancel');
},
});
return false;
}
deleteAttachment = (file, stateName) => {
// 初次上传不能直接取uid
const url = `/attachments/${file.response ? file.response.id : file.uid}.json`
axios.delete(url, {
})
.then((response) => {
if (response.data) {
const { status } = response.data;
if (status == 0) {
console.log('--- success')
this.setState((state) => {
const index = state[stateName].indexOf(file);
const newFileList = state[stateName].slice();
newFileList.splice(index, 1);
return {
[stateName]: newFileList,
};
});
}
}
})
.catch(function (error) {
console.log(error);
});
}
max_num_change = (val) => {
if (val < 2) {
this.setState({
max_num: 2,
})
return;
}
const { min_num } = this.state;
this.setState({
max_num: val,
min_num: val <= min_num ? val - 1 : min_num
})
}
min_num_change = (val) => {
this.setState({ min_num: val })
}
base_on_project_change = () => {
this.setState({ base_on_project: !this.state.base_on_project })
}
render(){
let {typeId,coursesId,pageType}=this.props.match.params;
const { getFieldDecorator } = this.props.form;
const isGroup = this.props.isGroup()
const moduleName = !isGroup? "普通作业":"分组作业";
const moduleEngName = this.props.getModuleName()
let{
title_value, contentFileList, answerFileList, max_num, min_num, base_on_project,
init_max_num, init_min_num,
title_num, course_name, category, has_commit, has_project,
isEdit
}=this.state
const { current_user } = this.props
const courseId = this.state.course_id || this.props.match.params.coursesId ;
if ((isEdit) && !this.state.workLoaded) {
return ''
}
const uploadProps = {
width: 600,
fileList: contentFileList,
multiple: true,
// https://github.com/ant-design/ant-design/issues/15505
// showUploadList={false},然后外部拿到 fileList 数组自行渲染列表。
// showUploadList: false,
action: `${getUrl()}/api/attachments.json`,
onChange: this.handleContentUploadChange,
onRemove: (file) => this.onAttachmentRemove(file, 'contentFileList'),
beforeUpload: (file) => {
console.log('beforeUpload', file.name);
const isLt150M = file.size / 1024 / 1024 < 150;
if (!isLt150M) {
message.error('文件大小必须小于150MB!');
}
return isLt150M;
},
};
const answerUploadProps = {
width: 600,
fileList: answerFileList,
multiple: true,
// https://github.com/ant-design/ant-design/issues/15505
// showUploadList={false},然后外部拿到 fileList 数组自行渲染列表。
// showUploadList: false,
action: `${getUrl()}/api/attachments.json`,
onChange: this.handleAnswerUploadChange,
onRemove: (file) => this.onAttachmentRemove(file, 'answerFileList'),
beforeUpload: (file) => {
console.log('beforeUpload', file.name);
const isLt150M = file.size / 1024 / 1024 < 150;
if (!isLt150M) {
message.error('文件大小必须小于150MB!');
}
return isLt150M;
},
};
return(
<React.Fragment>
<style>
{
`
.yslnewworkinputaddonAfter .ant-input{
border-right: none !important;
height: 40px !important;
}
`
}
</style>
<Form className="courseForm">
<Form.Item
label="标题"
className="AboutInputForm"
>
{getFieldDecorator('title', {
rules: [{
required: true, message: '请输入标题'
}],
})(
<Input placeholder="请输入作业标题最大限制60个字符" onInput={this.changeTitle} className="searchView yslnewworkinputaddonAfter searchViewAfter" style={{"width":"100%"}} maxLength={MAX_TITLE_LENGTH} addonAfter={`${String(title_num)}/${MAX_TITLE_LENGTH}`}/>
)}
</Form.Item>
<style>{`
.uploadBtn.ant-btn {
border: none;
color: #4CACFF;
box-shadow: none;
background: transparent;
padding: 0 6px;
}
.ant-upload-list-item:hover .ant-upload-list-item-info{
background-color:#fff;
}
.upload_1 .ant-upload-list {
width: 350px;
}
.ant-input-number {
height: 40px;
line-height: 40px;
}
.workContent.AboutInputForm.ant-form-item {
border-bottom: none;
padding-bottom: 0px !important;
}
.newWorkUpload {
padding: 0px 30px 30px 30px!important;
background: #fff;
width: 100%;
display: inline-block;
border-bottom: 1px solid #EDEDED;
}
`}</style>
{ <Form.Item
label="内容"
className="AboutInputForm workContent mdInForm"
>
{getFieldDecorator('description', {
rules: [{
required: true, message: '请输入作业内容和要求'
}],
})(
<TPMMDEditor ref={this.contentMdRef} placeholder="请在此输入作业内容和要求,最大限制5000个字符" mdID={'courseContentMD'} refreshTimeout={1500}
className="courseMessageMD" initValue={this.state.description}></TPMMDEditor>
)}
</Form.Item> }
<Upload {...uploadProps} className="upload_1 newWorkUpload">
<Button className="uploadBtn">
<Icon type="upload" /> 上传附件
</Button>
(单个文件150M以内)
</Upload>
{ isGroup &&
<Form.Item
label="分组设置"
className="AboutInputForm"
>
{getFieldDecorator('personNum', {
rules: [{
required: false
// required: true, message: '请输入最小人数和最大人数'
}],
})(
<div>
<p className="clearfix">
<ConditionToolTip condition={has_commit} title={'已有提交作品,人数范围只能扩大'}>
{/* max={has_commit ? init_min_num : null } */}
<InputNumber placeholder="请填写每组最小人数" min={1} className="winput-240-40" value={min_num}
onChange={this.min_num_change} style={{width:'180px'}} />
</ConditionToolTip>
<span className="ml15 mr15">~</span>
{/* min={has_commit ? init_max_num : (min_num == undefined ? 2 : min_num + 1) } */}
<ConditionToolTip condition={has_commit} title={'已有提交作品,人数范围只能扩大'}>
<InputNumber className="winput-240-40" placeholder="请填写每组最大人数" value={max_num} max={10}
onChange={this.max_num_change} style={{width:'180px'}} />
</ConditionToolTip>
<label className="color-grey-9 ml20 font-14">项目管理员角色的成员都可以提交作品提交作品时需要关联同组成员组内成员作品共享</label>
</p>
<p className="mt20">
<ConditionToolTip condition={has_commit || has_project} title={'已有关联项目或作品,不能修改'}>
<Checkbox checked={base_on_project} onChange={this.base_on_project_change}
disabled={has_project || has_commit}
>基于项目实施</Checkbox>
</ConditionToolTip>
<label className="color-grey-9 ml12 font-14">勾选后各小组必须在educoder平台创建项目教师可随时观察平台对各小组最新进展的实时统计</label>
</p>
</div>
)}
</Form.Item>
}
<Form.Item
label="参考答案"
className="AboutInputForm"
style={{"borderBottom":"none"}}
>
{getFieldDecorator('reference_answer', {
rules: [{
required: false
}],
})(
<TPMMDEditor ref={this.answerMdRef} placeholder="请在此输入作业的参考答案,最大限制5000个字符" mdID={'workAnswerMD'}
className="courseMessageMD" refreshTimeout={1500} initValue={this.state.reference_answer || ''}></TPMMDEditor>
)}
<Upload {...answerUploadProps} className="upload_1">
<Button className="uploadBtn">
<Icon type="upload" /> 上传附件
</Button>
(单个文件150M以内)
</Upload>
</Form.Item>
<Form.Item>
<div className="clearfix mt30 mb30">
{/* htmlType="submit" */}
<Button type="primary" onClick={this.handleSubmit} className="defalutSubmitbtn fl mr20">提交</Button>
<a className="defalutCancelbtn fl" onClick={() => this.props.toListPage(this.props.match.params, category.category_id)}>取消</ a>
</div>
</Form.Item>
</Form>
</React.Fragment>
)
}
}
const WrappedWorkForm = Form.create({ name: 'NewWorkForm' })(NewWorkForm);
export default WrappedWorkForm;

@ -153,7 +153,8 @@ class commonWork extends Component{
onPageChange=(pageNumber)=>{ onPageChange=(pageNumber)=>{
this.setState({ this.setState({
page:pageNumber page:pageNumber,
checkBoxValues:[]
}) })
let {search,order}=this.state; let {search,order}=this.state;
this.getList(pageNumber,search,order); this.getList(pageNumber,search,order);
@ -430,7 +431,7 @@ class commonWork extends Component{
mainList && mainList.course_identity < 5 && mainList.homeworks.length>0 && mainList && mainList.course_identity < 5 && mainList.homeworks.length>0 &&
<div className="mt20 edu-back-white padding20-30"> <div className="mt20 edu-back-white padding20-30">
<div className="clearfix" > <div className="clearfix" >
<Checkbox className="fl" onChange={this.changeAll} checked={checkAll}>已选 {checkBoxValues.length} </Checkbox> <Checkbox className="fl" onChange={this.changeAll} checked={checkAll}>已选 {checkBoxValues.length} 不支持跨页勾选</Checkbox>
<div className="studentList_operation_ul"> <div className="studentList_operation_ul">
<li className="li_line"> <li className="li_line">
<a href="javascript:void(0)" className="color-grey-9" <a href="javascript:void(0)" className="color-grey-9"

@ -150,8 +150,7 @@ class Startshixuntask extends Component{
keyboard={false} keyboard={false}
> >
<div className="task-popup-content"> <div className="task-popup-content">
<p className="task-popup-text-center font-16 pb20">本实训的开启时间{shixunsmessage} <br/>开启时间之前不能挑战 <p className="task-popup-text-center font-16 pb20">目前该实训项目尚在内测中将于{shixunsmessage}之后开放谢谢</p>
</p>
</div> </div>
<div className="task-popup-submit clearfix"> <div className="task-popup-submit clearfix">
{/*<a onClick={this.hidestartshixunCombattype} className="task-btn fl">取消</a>*/} {/*<a onClick={this.hidestartshixunCombattype} className="task-btn fl">取消</a>*/}

@ -1566,7 +1566,7 @@ samp {
padding-left: 5px; padding-left: 5px;
} }
.padding10200{ .padding10200{
padding: 10px 20px 0px; padding: 10px 20px;
} }
.padding1020{ .padding1020{
padding: 10px 20px 10px; padding: 10px 20px 10px;

@ -293,7 +293,7 @@ class Elearning extends Component{
footer={null} footer={null}
> >
<div className="task-popup-content"> <div className="task-popup-content">
<p className="task-popup-text-center font-16 pb20">本实训的开启时间{this.state.shixunsmessages} <br/>开启时间之前不能挑战 </p> <p className="task-popup-text-center font-16 pb20">目前该实训项目尚在内测中将于{this.state.shixunsmessages}之后开放谢谢</p>
</div> </div>
<div className="task-popup-submit clearfix"> <div className="task-popup-submit clearfix">
{/*<a onClick={this.hidestartshixunCombattype} className="task-btn fl">取消</a>*/} {/*<a onClick={this.hidestartshixunCombattype} className="task-btn fl">取消</a>*/}

@ -141,7 +141,7 @@ class YslDetailCards extends Component{
footer={null} footer={null}
> >
<div className="task-popup-content"> <div className="task-popup-content">
<p className="task-popup-text-center font-16 pb20">本实训的开启时间{this.state.shixunsmessage} <br/>开启时间之前不能挑战 </p> <p className="task-popup-text-center font-16 pb20">目前该实训项目尚在内测中将于{this.state.shixunsmessage}之后开放谢谢</p>
</div> </div>
<div className="task-popup-submit clearfix"> <div className="task-popup-submit clearfix">
{/*<a onClick={this.hidestartshixunCombattype} className="task-btn fl">取消</a>*/} {/*<a onClick={this.hidestartshixunCombattype} className="task-btn fl">取消</a>*/}

@ -130,7 +130,8 @@ class Exercise extends Component{
//切换分页 //切换分页
changePage=(pageNumber)=>{ changePage=(pageNumber)=>{
this.setState({ this.setState({
page:pageNumber page:pageNumber,
checkBoxValues:[]
}) })
let{type,StudentList_value,limit}=this.state let{type,StudentList_value,limit}=this.state
this.InitList(type,StudentList_value,pageNumber,limit); this.InitList(type,StudentList_value,pageNumber,limit);
@ -522,7 +523,7 @@ class Exercise extends Component{
<Spin size="large" spinning={this.state.isSpin}> <Spin size="large" spinning={this.state.isSpin}>
{this.props.isAdmin()?exercises && exercises.length ===0?"":<div className="mt20 mb20 edu-back-white padding20-30"> {this.props.isAdmin()?exercises && exercises.length ===0?"":<div className="mt20 mb20 edu-back-white padding20-30">
<div className="clearfix"> <div className="clearfix">
<Checkbox className="fl" onChange={this.onCheckAll} checked={checkAllValue}>已选 {checkBoxValues.length} </Checkbox> <Checkbox className="fl" onChange={this.onCheckAll} checked={checkAllValue}>已选 {checkBoxValues.length} 不支持跨页勾选</Checkbox>
<div className="studentList_operation_ul"> <div className="studentList_operation_ul">
<li className="li_line"><a className="color-grey-9" onClick={()=>this.ActionPoll("delete")}>删除</a></li> <li className="li_line"><a className="color-grey-9" onClick={()=>this.ActionPoll("delete")}>删除</a></li>
<li className="li_line"> <li className="li_line">

@ -129,7 +129,7 @@ class fillEmpty extends Component{
} }
{ {
// 答案公开,且试卷已经截止 // 答案公开,且试卷已经截止
isAdmin && questionType.standard_answer &&
<div> <div>
<p className="bor-top-greyE pt20 mt20 font-16 mb10">参考答案</p> <p className="bor-top-greyE pt20 mt20 font-16 mb10">参考答案</p>
{ questionType.standard_answer && questionType.standard_answer.map((item,k)=>{ { questionType.standard_answer && questionType.standard_answer.map((item,k)=>{

@ -85,9 +85,9 @@ class simpleAnswer extends Component{
</div> </div>
} }
{ {
isStudent && exercise.answer_open==true && exercise.exercise_status == 3 ? isStudent && questionType.standard_answer ?
<div className="bor-top-greyE pt20 mt20 standardAnswer"> <div className="bor-top-greyE pt20 mt20 standardAnswer">
<p>参考答案</p> <p className="mb10 font-16">参考答案</p>
{/* <li className="markdown-body answerStyle" dangerouslySetInnerHTML={{__html: markdownToHTML1(questionType.standard_answer && questionType.standard_answer[0])}}></li> */} {/* <li className="markdown-body answerStyle" dangerouslySetInnerHTML={{__html: markdownToHTML1(questionType.standard_answer && questionType.standard_answer[0])}}></li> */}
<MarkdownToHtml content={questionType.standard_answer && questionType.standard_answer[0]} selector={'simgle_standard2_' + (this.props.index + 1)} <MarkdownToHtml content={questionType.standard_answer && questionType.standard_answer[0]} selector={'simgle_standard2_' + (this.props.index + 1)}
className="answerStyle" className="answerStyle"

@ -360,7 +360,8 @@ class GraduationTasks extends Component{
let selectpagetype=selectpage===page?true:false let selectpagetype=selectpage===page?true:false
this.setState({ this.setState({
page:page, page:page,
checkAllValue:selectpagetype checkAllValue:selectpagetype,
checkBoxValues:[]
}) })
this.fetchAll(search,page,order); this.fetchAll(search,page,order);
@ -700,7 +701,7 @@ class GraduationTasks extends Component{
{this.props.isAdmin()?all_count===undefined?'' :all_count===0?"": <div className="mt20 edu-back-white padding20-30"> {this.props.isAdmin()?all_count===undefined?'' :all_count===0?"": <div className="mt20 edu-back-white padding20-30">
<div className="clearfix"> <div className="clearfix">
<Checkbox className="fl" onChange={this.onCheckAll} checked={checkAllValue}>已选 {checkBoxValues.length} </Checkbox> <Checkbox className="fl" onChange={this.onCheckAll} checked={checkAllValue}>已选 {checkBoxValues.length} 不支持跨页勾选</Checkbox>
<div className="studentList_operation_ul"> <div className="studentList_operation_ul">
<li className="li_line"><a className="color-grey-9" onClick={this.onDelete}>删除</a></li> <li className="li_line"><a className="color-grey-9" onClick={this.onDelete}>删除</a></li>

@ -1,28 +1,19 @@
import React,{ Component } from "react"; import React,{ Component } from "react";
import { import { Select, Modal } from 'antd';
Form, Input, InputNumber, Switch, Radio,
Slider, Button, Upload, Icon, Rate, Checkbox, message,
Row, Col, Select, Modal,Cascader
} from 'antd';
import TPMMDEditor from '../../../tpm/challengesnew/TPMMDEditor';
import axios from 'axios' import axios from 'axios'
import {getUrl} from 'educoder';
import "../../common/formCommon.css" import "../../common/formCommon.css"
import '../style.css' import '../style.css'
import '../../css/Courses.css' import '../../css/Courses.css'
import { WordsBtn, City } from 'educoder' import { WordsBtn } from 'educoder'
import {Link} from 'react-router-dom' import {Link} from 'react-router-dom'
// import City from './City'
// import './board.css' import GraduateTopicNewFrom from './GraduateTopicNewFrom'
// import { RouteHOC } from './common.js'
const confirm = Modal.confirm;
const $ = window.$ const $ = window.$
const { Option } = Select;
const NAME_COUNT=60;
// 新建毕设选题 // 新建毕设选题
// https://lanhuapp.com/web/#/item/project/board/detail?pid=a3bcd4b1-99ce-4e43-8ead-5b8b0a410807&project_id=a3bcd4b1-99ce-4e43-8ead-5b8b0a410807&image_id=c6d9b36f-7701-4035-afdb-62404681108c // https://lanhuapp.com/web/#/item/project/board/detail?pid=a3bcd4b1-99ce-4e43-8ead-5b8b0a410807&project_id=a3bcd4b1-99ce-4e43-8ead-5b8b0a410807&image_id=c6d9b36f-7701-4035-afdb-62404681108c
class GraduateTopicNew extends Component{ class GraduateTopicNew extends Component{
@ -33,14 +24,12 @@ class GraduateTopicNew extends Component{
this.state = { this.state = {
fileList: [], fileList: [],
boards: [],
teacherList:[], teacherList:[],
topic_property_first:[], topic_property_first:[],
topic_property_second:[], topic_property_second:[],
topic_repeat:[], topic_repeat:[],
topic_source:[], topic_source:[],
topic_type:[], topic_type:[],
attachments:undefined,
addonAfter:0, addonAfter:0,
left_banner_id:undefined, left_banner_id:undefined,
course_name:undefined course_name:undefined
@ -53,21 +42,11 @@ class GraduateTopicNew extends Component{
axios.get((url)).then((result)=>{ axios.get((url)).then((result)=>{
if(result.status==200){ if(result.status==200){
this.setState({ this.setState({
teacherList:result.data.teacher_list,
left_banner_id:result.data.left_banner_id, left_banner_id:result.data.left_banner_id,
course_name:result.data.course_name, course_name:result.data.course_name,
left_banner_name:result.data.left_banner_name, left_banner_name:result.data.left_banner_name
topic_property_first:result.data.topic_property_first,
topic_property_second:result.data.topic_property_second,
topic_repeat:result.data.topic_repeat,
topic_source:result.data.topic_source,
topic_type:result.data.topic_type
})
console.log("sdfds");
console.log(this.props.current_user && this.props.current_user.user_id);
this.props.form.setFieldsValue({
tea_id:this.props.current_user && this.props.current_user.user_id
}) })
this.GraduateTopicNewFromRef.initNewInfo(result);
} }
}).catch((error)=>{ }).catch((error)=>{
console.log(error); console.log(error);
@ -87,236 +66,91 @@ class GraduateTopicNew extends Component{
//编辑,信息显示 //编辑,信息显示
getEditInfo=()=>{ getEditInfo=()=>{
const cid = this.props.match.params.coursesId const cid = this.props.match.params.coursesId
let topicId=this.props.match.params.topicId let topicId=this.props.match.params.topicId;
let url=`/courses/${cid}/graduation_topics/${topicId}/edit.json`; if(topicId){
axios.get((url)).then((result)=>{ let url=`/courses/${cid}/graduation_topics/${topicId}/edit.json`;
if(result){ axios.get((url)).then((result)=>{
this.setState({ if(result){
left_banner_id:result.data.left_banner_id, this.setState({
course_name:result.data.course_name, left_banner_id:result.data.left_banner_id,
left_banner_name:result.data.left_banner_name, course_name:result.data.course_name,
teacherList:result.data.teacher_list, left_banner_name:result.data.left_banner_name
topic_property_first:result.data.topic_property_first, })
topic_property_second:result.data.topic_property_second, this.GraduateTopicNewFromRef.initValue(result);
topic_repeat:result.data.topic_repeat,
topic_source:result.data.topic_source, }
topic_type:result.data.topic_type, }).catch((error)=>{
attachments:result.data.attachments, console.log(error);
addonAfter:parseInt(result.data.selected_data.name.length) })
}) }
this.props.form.setFieldsValue({
tea_id:result.data.selected_data.tea_id,
name:result.data.selected_data.name,
city: [result.data.selected_data.province,result.data.selected_data.city],
topic_type:result.data.selected_data.topic_type || undefined,
topic_source:result.data.selected_data.topic_source || undefined,
topic_property_first:result.data.selected_data.topic_property_first || undefined,
topic_property_second:result.data.selected_data.topic_property_second || undefined,
source_unit:result.data.selected_data.source_unit,
topic_repeat:result.data.selected_data.topic_repeat || undefined
});
this.mdRef.current.setValue(result.data.selected_data.description)
const _fileList = result.data.attachments.map(item => {
return {
id: item.id,
uid: item.id,
name: item.title,
url: item.url,
status: 'done'
}
})
this.setState({ fileList: _fileList, cityDefaultValue: [result.data.selected_data.province,result.data.selected_data.city] })
}
}).catch((error)=>{
console.log(error);
})
} }
handleSubmit = (e) => { // 编辑保存
e.preventDefault(); editSave = (param,attachments,topicId) =>{
const cid = this.props.match.params.coursesId const cid = this.props.match.params.coursesId
const topicId = this.props.match.params.topicId const editUrl = `/courses/${cid}/graduation_topics/${topicId}.json`
// console.log(this.props); let params = {
graduation_topic:param,
this.props.form.validateFieldsAndScroll((err, values) => { attachment_ids:attachments
if (!err) { }
console.log('Received values of form: ', values); axios.put(editUrl, params).then((response) => {
if (topicId !=undefined) { if (response.status == 200) {
const editTopic = this.editTopic const { id } = response.data;
const editUrl = `/courses/${cid}/graduation_topics/${topicId}.json` if (id) {
this.props.showNotification('保存成功!');
let attachment_ids = undefined this.props.history.push(`/courses/${cid}/graduation_topics/${this.state.left_banner_id}`);
if (this.state.fileList) {
attachment_ids = this.state.fileList.map(item => {
return item.response ? item.response.id : item.id
})
}
axios.put(editUrl, {
graduation_topic:{
...values,
province: values.city==undefined?"":values.city[0],
city: values.city==undefined?"":values.city[1],
},
attachment_ids
}).then((response) => {
if (response.status == 200) {
const { id } = response.data;
if (id) {
this.props.showNotification('保存成功!');
this.props.history.push(`/courses/${cid}/graduation_topics/${this.state.left_banner_id}`);
}
}
}).catch(function (error) {
console.log(error);
});
} else {
const url = `/courses/${cid}/graduation_topics.json`
let attachment_ids = undefined
if (this.state.fileList) {
attachment_ids = this.state.fileList.map(item => {
return item.response.id
})
}
axios.post(url, {
graduation_topic:{
...values,
province: values.city==undefined?"":values.city[0],
city: values.city==undefined?"":values.city[1],
},
attachment_ids,
}).then((response) => {
if (response.data) {
const { id } = response.data;
if (id) {
this.props.showNotification('提交成功!');
this.props.history.push(`/courses/${cid}/graduation_topics/${this.state.left_banner_id}`);
}
}
})
.catch(function (error) {
console.log(error);
});
} }
} else {
$("html").animate({ scrollTop: $('html').scrollTop() - 100 })
} }
}).catch(function (error) {
console.log(error);
}); });
} }
// 选择省市 // 新建提交
ChangeCity=(value, selectedOptions)=>{ newSubmit = (param,attachments,topicId) =>{
console.log(selectedOptions); const cid = this.props.match.params.coursesId
} const url = `/courses/${cid}/graduation_topics.json`
let params = {
// 附件相关 START graduation_topic:param,
handleChange = (info) => { attachment_ids:attachments
let fileList = info.fileList; }
this.setState({ fileList }); axios.post(url, params).then((response) => {
} if (response.data) {
onAttachmentRemove = (file) => { const { id } = response.data;
confirm({ if (id) {
title: '确定要删除这个附件吗?', this.props.showNotification('提交成功!');
okText: '确定', this.props.history.push(`/courses/${cid}/graduation_topics/${this.state.left_banner_id}`);
cancelText: '取消', }
// content: 'Some descriptions', }
onOk: () => { }).catch(function (error) {
this.deleteAttachment(file) console.log(error);
},
onCancel() {
console.log('Cancel');
},
}); });
return false;
} }
deleteAttachment = (file) => { // 取消编辑或者新建
console.log(file); editCancel = () =>{
let id=file.response ==undefined ? file.id : file.response.id const cid = this.props.match.params.coursesId;
const url = `/attachments/${id}.json` let topicId=this.props.match.params.topicId;
axios.delete(url, { if(topicId){
}) this.props.history.push(`/courses/${cid}/graduation_topics/${topicId}/detail`);
.then((response) => { }else{
if (response.data) { this.props.history.push(`/courses/${cid}/graduation_topics/${this.state.left_banner_id}`);
const { status } = response.data; }
if (status == 0) {
console.log('--- success')
this.setState((state) => {
const index = state.fileList.indexOf(file);
const newFileList = state.fileList.slice();
newFileList.splice(index, 1);
return {
fileList: newFileList,
};
});
}
}
})
.catch(function (error) {
console.log(error);
});
} }
// 附件相关 ------------ END
changeTopicName=(e)=>{
// let num= 60 - parseInt(e.target.value.length);
this.setState({
addonAfter:e.target.value.length
})
}
render() { render() {
let { let {
fileList,
teacherList,
topic_property_first,
topic_property_second,
topic_repeat,
topic_source,
topic_type,
addonAfter,
left_banner_id, left_banner_id,
course_name, course_name,
left_banner_name left_banner_name
} = this.state; } = this.state;
const { current_user } = this.props const { current_user } = this.props
const { getFieldDecorator } = this.props.form;
let{ topicId,coursesId }=this.props.match.params let{ topicId,coursesId }=this.props.match.params
// console.log(this.props); const common={
editSave:this.editSave,
const formItemLayout = { newSubmit:this.newSubmit,
labelCol: { editCancel:this.editCancel
xs: { span: 24 }, }
// sm: { span: 8 },
sm: { span: 24 },
},
wrapperCol: {
xs: { span: 24 },
// sm: { span: 16 },
sm: { span: 24 },
},
};
const uploadProps = {
width: 600,
fileList,
multiple: true,
// https://github.com/ant-design/ant-design/issues/15505
// showUploadList={false},然后外部拿到 fileList 数组自行渲染列表。
// showUploadList: false,
action: `${getUrl()}/api/attachments.json`,
onChange: this.handleChange,
onRemove: this.onAttachmentRemove,
beforeUpload: (file) => {
console.log('beforeUpload', file.name);
const isLt150M = file.size / 1024 / 1024 < 150;
if (!isLt150M) {
message.error('文件大小必须小于150MB!');
}
return isLt150M;
},
};
// console.log("dfsf");
// console.log(this.props);
return( return(
<div className="newMain "> <div className="newMain ">
<style>{` <style>{`
@ -337,292 +171,21 @@ class GraduateTopicNew extends Component{
<Link to={`/courses/${coursesId}/graduation_topics/${left_banner_id}`} className="color-grey-6 fr font-16">返回</Link> <Link to={`/courses/${coursesId}/graduation_topics/${left_banner_id}`} className="color-grey-6 fr font-16">返回</Link>
</div> </div>
<Form {...formItemLayout} onSubmit={this.handleSubmit}> <GraduateTopicNewFrom
<div className="createPage"> {...this.props}
<Form.Item {...this.state}
label="指导老师" {...common}
> wrappedComponentRef={(ref) => this.GraduateTopicNewFromRef = ref}
{getFieldDecorator('tea_id', { topicId={topicId}
rules: [{ teacherName={true}
required: true, message: '请选择指导老师' ></GraduateTopicNewFrom>
}],
})(
<Select style={{"width":"20%"}} placeholder="请选择指导老师">
{
teacherList && teacherList.map((item,key)=>{
return(
<Option value={item.id} id={key}>{item.name}</Option>
)
})
}
</Select>
)}
</Form.Item>
<style>
{
`
.exercicenewinputysl .ant-input{
border-right: none !important;
height: 40px !important;
}
`
}
</style>
<Form.Item
label="选题名称"
className="mt15"
>
{getFieldDecorator('name', {
rules: [{
required: true, message: '请输入选题名称',
}, {
max: 60, message: '最大限制为60个字符',
}],
})(
<Input placeholder="请输入帖子选题名称最大限制60个字符" maxLength="60" onInput={this.changeTopicName} autoComplete="off" addonAfter={`${String(addonAfter)}/${NAME_COUNT}`} className="searchViewAfter exercicenewinputysl" />
)}
</Form.Item>
</div>
<style>{`
.courseMessageMD {
width: 1140px;
}
.uploadBtn.ant-btn {
border: none;
color: #4CACFF;
box-shadow: none;
background: transparent;
padding: 0 6px;
}
.upload_1 .ant-upload-list {
width: 350px;
margin-bottom:10px;
}
.ant-upload-list-item{
margin-top:0px!important;
}
.ant-form-item-children{
position:unset
}
.rememberTip{
position:absolute;
right:0px;
bottom:-10px;
}
.chooseDes .ant-form-explain{
position:absolute;
bottom:-10px;
left:0px;
}
.setUploadStyle .uploadBtn{
height:20px;
line-height:20px;
}
.setUploadStyle .ant-form-item-control{
margin-top:15px!important;
line-height:22px!important;
}
.setUploadStyle .ant-upload-list{
margin-top:5px;
}
`}</style>
<div className="createPage">
<Form.Item
label="选题简介"
style={{"borderBottom":'none'}}
className="chooseDes pr"
>
{getFieldDecorator('description', {
rules: [{
required: true, message: '请输入选题简介',
}, {
max: 10000, message: '最大限制为10000个字符',
}],
})(
<TPMMDEditor ref={this.mdRef} placeholder={'请简要说明选题内容最大限制5000个字符'}
mdID={'courseMessageMD'} initValue={this.editTopic ? this.editTopic.content : ''} className="courseMessageMD"></TPMMDEditor>
)}
</Form.Item>
<Form.Item
className="setUploadStyle"
>
{
getFieldDecorator('file',{
rules:[{
required:false
}]
})(
<Upload {...uploadProps} className="upload_1 ">
<Button className="uploadBtn">
<Icon type="upload" /> 上传附件
</Button>
<span className="color-grey-c">(单个文件150M以内)</span>
</Upload>
)
}
</Form.Item>
<div className="clearfix">
<Form.Item className="fl mr20 with20" style={{"marginRight":"20px"}}>
{getFieldDecorator('topic_type', {
rules: [{
required: false, message: '',
}],
})(
<Select placeholder="请选择选题类型">
{
topic_type && topic_type.map((item,key)=>{
return(
<Option value={item.id} key={key}>{item.name}</Option>
)
})
}
</Select>
)}
</Form.Item>
<Form.Item className="fl mr20 with20" style={{"marginRight":"20px"}}>
{getFieldDecorator('topic_source', {
rules: [{
required: false, message: '',
}],
})(
<Select placeholder="请输入选题来源">
{
topic_source && topic_source.map((item,key)=>{
return(
<Option value={item.id} key={key}>{item.name}</Option>
)
})
}
</Select>
)}
</Form.Item>
<Form.Item className="fl mr20 with20" style={{"marginRight":"20px"}}>
{getFieldDecorator('topic_property_first', {
rules: [{
required: false, message: '',
}],
})(
<Select placeholder="请输入选题性质1">
{
topic_property_first && topic_property_first.map((item,key)=>{
return(
<Option value={item.id} key={key}>{item.name}</Option>
)
})
}
</Select>
)}
</Form.Item>
<Form.Item className="fl mr20 with20" style={{"marginRight":"20px"}}>
{getFieldDecorator('topic_property_second', {
rules: [{
required: false, message: '',
}],
})(
<Select placeholder="请输入选题性质2">
{
topic_property_second && topic_property_second.map((item,key)=>{
return(
<Option value={item.id} key={key}>{item.name}</Option>
)
})
}
</Select>
)}
</Form.Item>
</div>
</div>
<style>{`
.courseForm .flexBlock.formBlock {
align-items: flex-end;
display: flex;
flex-wrap: wrap;
}
.courseForm .flexBlock .tag {
margin-left: 8px;
margin-right: 6px;
margin-bottom: 16px;
}
.flexBlock .ant-row.ant-form-item {
margin-bottom: 6px;
}
.ant-cascader-menu{
min-width:125px!important;
}
`}</style>
<div className="createPage" style={{"borderBottom":"none"}}>
<Form.Item
label="选题来源单位"
className="with22"
>
{getFieldDecorator('source_unit', {
rules: [{
required: false, message: '',
}],
})(
<Input placeholder="请填写来源单位" autoComplete="off" className="searchView"/>
)}
</Form.Item>
<Form.Item
label="选择重复情况"
className="mt15 with22"
>
{getFieldDecorator('topic_repeat', {
rules: [{
required: false, message: '',
}],
})(
<Select placeholder="请选择选题重复情况">
{
topic_repeat && topic_repeat.map((item,key)=>{
return(
<Option value={item.id} key={key}>{item.name}</Option>
)
})
}
</Select>
)}
</Form.Item>
<Form.Item
label="调研或实习地点"
className="mt15 with22 setAreaStyle"
>
{getFieldDecorator('city', {
rules: [{
initialValue: this.state.cityDefaultValue,
type: 'array',
required: false, message: '',
}],
})(
<City ></City>
)}
</Form.Item>
</div>
<Form.Item>
<div className="clearfix mt30 mb30">
<Button type="primary" htmlType="submit" className="defalutSubmitbtn fl mr20">{topicId==undefined?"提交":"保存"}</Button>
<a className="defalutCancelbtn fl" onClick={()=>this.props.history.goBack()}>取消</ a>
</div>
</Form.Item>
</Form>
</div> </div>
</div> </div>
) )
} }
} }
const WrappedGraduateTopicNew = Form.create({ name: 'topicPostWorksNew' })(GraduateTopicNew); // const WrappedGraduateTopicNew = Form.create({ name: 'topicPostWorksNew' })(GraduateTopicNew);
// RouteHOC() // RouteHOC()
export default (WrappedGraduateTopicNew); export default GraduateTopicNew;

@ -0,0 +1,519 @@
import React,{ Component } from "react";
import {
Form, Input, Button, Upload, Icon , message, Select
} from 'antd';
import TPMMDEditor from '../../../tpm/challengesnew/TPMMDEditor';
import axios from 'axios'
import { City , getUploadActionUrl , appendFileSizeToUploadFileAll } from 'educoder';
const NAME_COUNT=60;
class GraduateTopicNewForm extends Component{
constructor(props){
super(props);
this.mdRef = React.createRef();
this.state = {
fileList: [],
teacherList:[],
topic_property_first:[],
topic_property_second:[],
topic_repeat:[],
topic_source:[],
topic_type:[],
addonAfter:0,
cityDefaultValue:undefined
}
}
// init编辑信息
initValue=(result)=>{
this.setState({
teacherList:result.data.teacher_list,
topic_property_first:result.data.topic_property_first,
topic_property_second:result.data.topic_property_second,
topic_repeat:result.data.topic_repeat,
topic_source:result.data.topic_source,
topic_type:result.data.topic_type,
addonAfter:parseInt(result.data.selected_data.name.length)
})
this.props.form.setFieldsValue({
tea_id:result.data.selected_data.tea_id,
name:result.data.selected_data.name,
city: [result.data.selected_data.province,result.data.selected_data.city],
topic_type:result.data.selected_data.topic_type || undefined,
topic_source:result.data.selected_data.topic_source || undefined,
topic_property_first:result.data.selected_data.topic_property_first || undefined,
topic_property_second:result.data.selected_data.topic_property_second || undefined,
source_unit:result.data.selected_data.source_unit,
topic_repeat:result.data.selected_data.topic_repeat || undefined
});
this.mdRef.current.setValue(result.data.selected_data.description)
const _fileList = result.data.attachments.map(item => {
return {
id: item.id,
uid: item.id,
name: item.title,
url: item.url,
status: 'done'
}
})
this.setState({ fileList: _fileList, cityDefaultValue: [result.data.selected_data.province,result.data.selected_data.city] })
}
//init新建信息
initNewInfo=(result)=>{
this.setState({
teacherList:result.data.teacher_list,
topic_property_first:result.data.topic_property_first,
topic_property_second:result.data.topic_property_second,
topic_repeat:result.data.topic_repeat,
topic_source:result.data.topic_source,
topic_type:result.data.topic_type
})
this.props.form.setFieldsValue({
tea_id:this.props.current_user && this.props.current_user.user_id
})
}
// 附件相关 START
handleChange = (info) => {
if (info.file.status === 'done' || info.file.status === 'uploading') {
let contentFileList = info.fileList;
// this.setState({ fileList: appendFileSizeToUploadFileAll(contentFileList)});
// let list = appendFileSizeToUploadFileAll(contentFileList);
// let arr = list.map(item=>{
// return ( item.response && item.response.id )
// })
this.setState({
fileList:contentFileList
});
}
}
onAttachmentRemove = (file) => {
this.props.confirm({
content: '确定要删除这个附件吗?',
onOk: () => {
this.deleteAttachment(file)
},
onCancel() {
console.log('Cancel');
},
});
return false;
}
deleteAttachment = (file) => {
console.log(file);
let id=file.response ==undefined ? file.id : file.response.id
const url = `/attachments/${id}.json`
axios.delete(url).then((response) => {
if (response.data) {
const { status } = response.data;
if (status == 0) {
console.log('--- success')
this.setState((state) => {
const index = state.fileList.indexOf(file);
const newFileList = state.fileList.slice();
newFileList.splice(index, 1);
return {
fileList: newFileList,
};
});
}
}
})
.catch(function (error) {
console.log(error);
});
}
changeTopicName=(e)=>{
// let num= 60 - parseInt(e.target.value.length);
this.setState({
addonAfter:e.target.value.length
})
}
handleSubmit = (e) => {
e.preventDefault();
const topicId = this.props.topicId
this.props.form.validateFieldsAndScroll((err, values) => {
if (!err) {
if (topicId !=undefined) {
// 编辑
// const editTopic = this.editTopic
let attachment_ids = undefined
if (this.state.fileList) {
attachment_ids = this.state.fileList.map(item => {
return item.response ? item.response.id : item.id
})
}
const param = {
...values,
province: values.city==undefined?"":values.city[0],
city: values.city==undefined?"":values.city[1],
}
this.props.editSave && this.props.editSave(param,attachment_ids,topicId);
} else {
// 新建
let attachment_ids = undefined
if (this.state.fileList) {
attachment_ids = this.state.fileList.map(item => {
return item.response.id
})
}
const param ={
...values,
province: values.city==undefined?"":values.city[0],
city: values.city==undefined?"":values.city[1],
}
this.props.newSubmit && this.props.newSubmit(param,attachment_ids,topicId);
}
} else {
$("html").animate({ scrollTop: $('html').scrollTop() - 100 })
}
});
}
// 附件相关 ------------ END
render(){
let{
fileList,
teacherList,
topic_property_first,
topic_property_second,
topic_repeat,
topic_source,
topic_type,
addonAfter,
cityDefaultValue
}=this.state;
const { getFieldDecorator } = this.props.form;
const formItemLayout = {
labelCol: {
xs: { span: 24 },
// sm: { span: 8 },
sm: { span: 24 },
},
wrapperCol: {
xs: { span: 24 },
// sm: { span: 16 },
sm: { span: 24 },
},
};
const uploadProps = {
width: 600,
fileList,
multiple: true,
action: `${getUploadActionUrl()}`,
onChange: this.handleChange,
onRemove: this.onAttachmentRemove,
beforeUpload: (file) => {
const isLt150M = file.size / 1024 / 1024 < 150;
if (!isLt150M) {
//message.error('文件大小必须小于150MB!');
this.props.define({
title:'提示',
content:"该文件无法上传。超过文件大小限制(150MB),建议上传到百度云等其它共享工具里然后再txt文档里给出链接以及共享密码并上传"
})
return isLt150M;
}
}
};
let { topicId , teacherName }=this.props;
return(
<React.Fragment>
<Form {...formItemLayout} onSubmit={this.handleSubmit}>
<div className="createPage">
{
teacherName &&
<Form.Item
label="指导老师"
>
{getFieldDecorator('tea_id', {
rules: [{
required: true, message: '请选择指导老师'
}],
})(
<Select style={{"width":"20%"}} placeholder="请选择指导老师">
{
teacherList && teacherList.map((item,key)=>{
return(
<Option value={item.id} id={key}>{item.name}</Option>
)
})
}
</Select>
)}
</Form.Item>
}
<style>
{
`
.exercicenewinputysl .ant-input{
border-right: none !important;
height: 40px !important;
}
`
}
</style>
<Form.Item
label="选题名称"
className="mt15"
>
{getFieldDecorator('name', {
rules: [{
required: true, message: '请输入选题名称',
}, {
max: 60, message: '最大限制为60个字符',
}],
})(
<Input placeholder="请输入帖子选题名称最大限制60个字符" maxLength="60" onInput={this.changeTopicName} autoComplete="off" addonAfter={`${String(addonAfter)}/${NAME_COUNT}`} className="searchViewAfter exercicenewinputysl" />
)}
</Form.Item>
</div>
<style>{`
.courseMessageMD {
width: 1140px;
}
.uploadBtn.ant-btn {
border: none;
color: #4CACFF;
box-shadow: none;
background: transparent;
padding: 0 6px;
}
.upload_1 .ant-upload-list {
width: 350px;
margin-bottom:10px;
}
.ant-upload-list-item{
margin-top:0px!important;
}
.ant-form-item-children{
position:unset
}
.rememberTip{
position:absolute;
right:0px;
bottom:-10px;
}
.chooseDes .ant-form-explain{
position:absolute;
bottom:-10px;
left:0px;
}
.setUploadStyle .uploadBtn{
height:20px;
line-height:20px;
}
.setUploadStyle .ant-form-item-control{
margin-top:15px!important;
line-height:22px!important;
}
.setUploadStyle .ant-upload-list{
margin-top:5px;
}
`}</style>
<div className="createPage">
<Form.Item
label="选题简介"
style={{"borderBottom":'none'}}
className="chooseDes pr"
>
{getFieldDecorator('description', {
rules: [{
required: true, message: '请输入选题简介',
}, {
max: 10000, message: '最大限制为10000个字符',
}],
})(
// initValue={this.editTopic ? this.editTopic.content : ''}
<TPMMDEditor ref={this.mdRef} placeholder={'请简要说明选题内容最大限制5000个字符'}
mdID={'courseMessageMD'} className="courseMessageMD"></TPMMDEditor>
)}
</Form.Item>
<Form.Item
className="setUploadStyle"
>
{
getFieldDecorator('file',{
rules:[{
required:false
}]
})(
<Upload {...uploadProps} className="upload_1 ">
<Button className="uploadBtn">
<Icon type="upload" /> 上传附件
</Button>
<span className="color-grey-c">(单个文件150M以内)</span>
</Upload>
)
}
</Form.Item>
<div className="clearfix">
<Form.Item className="fl mr20 with20" style={{"marginRight":"20px"}}>
{getFieldDecorator('topic_type', {
rules: [{
required: false, message: '',
}],
})(
<Select placeholder="请选择选题类型">
{
topic_type && topic_type.map((item,key)=>{
return(
<Option value={item.id} key={key}>{item.name}</Option>
)
})
}
</Select>
)}
</Form.Item>
<Form.Item className="fl mr20 with20" style={{"marginRight":"20px"}}>
{getFieldDecorator('topic_source', {
rules: [{
required: false, message: '',
}],
})(
<Select placeholder="请输入选题来源">
{
topic_source && topic_source.map((item,key)=>{
return(
<Option value={item.id} key={key}>{item.name}</Option>
)
})
}
</Select>
)}
</Form.Item>
<Form.Item className="fl mr20 with20" style={{"marginRight":"20px"}}>
{getFieldDecorator('topic_property_first', {
rules: [{
required: false, message: '',
}],
})(
<Select placeholder="请输入选题性质1">
{
topic_property_first && topic_property_first.map((item,key)=>{
return(
<Option value={item.id} key={key}>{item.name}</Option>
)
})
}
</Select>
)}
</Form.Item>
<Form.Item className="fl mr20 with20" style={{"marginRight":"20px"}}>
{getFieldDecorator('topic_property_second', {
rules: [{
required: false, message: '',
}],
})(
<Select placeholder="请输入选题性质2">
{
topic_property_second && topic_property_second.map((item,key)=>{
return(
<Option value={item.id} key={key}>{item.name}</Option>
)
})
}
</Select>
)}
</Form.Item>
</div>
</div>
<style>{`
.courseForm .flexBlock.formBlock {
align-items: flex-end;
display: flex;
flex-wrap: wrap;
}
.courseForm .flexBlock .tag {
margin-left: 8px;
margin-right: 6px;
margin-bottom: 16px;
}
.flexBlock .ant-row.ant-form-item {
margin-bottom: 6px;
}
.ant-cascader-menu{
min-width:125px!important;
}
`}</style>
<div className="createPage" style={{"borderBottom":"none"}}>
<Form.Item
label="选题来源单位"
className="with22"
>
{getFieldDecorator('source_unit', {
rules: [{
required: false, message: '',
}],
})(
<Input placeholder="请填写来源单位" autoComplete="off" className="searchView"/>
)}
</Form.Item>
<Form.Item
label="选择重复情况"
className="mt15 with22"
>
{getFieldDecorator('topic_repeat', {
rules: [{
required: false, message: '',
}],
})(
<Select placeholder="请选择选题重复情况">
{
topic_repeat && topic_repeat.map((item,key)=>{
return(
<Option value={item.id} key={key}>{item.name}</Option>
)
})
}
</Select>
)}
</Form.Item>
<Form.Item
label="调研或实习地点"
className="mt15 with22 setAreaStyle"
>
{getFieldDecorator('city', {
rules: [{
initialValue: cityDefaultValue,
type: 'array',
required: false, message: '',
}],
})(
<City ></City>
)}
</Form.Item>
</div>
<Form.Item>
<div className="clearfix mt30 mb30">
<Button type="primary" htmlType="submit" className="defalutSubmitbtn fl mr20">{topicId==undefined?"提交":"保存"}</Button>
<a className="defalutCancelbtn fl" onClick={this.props.editCancel}>取消</ a>
</div>
</Form.Item>
</Form>
</React.Fragment>
)
}
}
const WrappedGraduateTopicNewForm = Form.create({ name: 'topicPostWorksNew' })(GraduateTopicNewForm);
// RouteHOC()
export default (WrappedGraduateTopicNewForm);

@ -153,7 +153,8 @@ class Boards extends Component{
// 分页 // 分页
onChangePage=(pageNum)=>{ onChangePage=(pageNum)=>{
this.setState({ this.setState({
page:pageNum page:pageNum,
checkBoxValues:[]
}) })
let {status,searchValue}=this.state; let {status,searchValue}=this.state;
this.fetchAll(searchValue,pageNum,status); this.fetchAll(searchValue,pageNum,status);
@ -430,7 +431,7 @@ onBoardsNew=()=>{
// 超级管理员、教师、助教 // 超级管理员、教师、助教
isAdmin ? isAdmin ?
<div className="clearfix mt20 edu-back-white padding20-30"> <div className="clearfix mt20 edu-back-white padding20-30">
<Checkbox className="fl" onChange={this.onCheckAll} checked={checkAllValue}>已选 {checkBoxValues.length} </Checkbox> <Checkbox className="fl" onChange={this.onCheckAll} checked={checkAllValue}>已选 {checkBoxValues.length} 不支持跨页勾选</Checkbox>
<div className="studentList_operation_ul"> <div className="studentList_operation_ul">
<li className="li_line"><a href="javascript:void(0)" className="color-grey-9" onClick={()=>this.onDelete(1)}>删除</a></li> <li className="li_line"><a href="javascript:void(0)" className="color-grey-9" onClick={()=>this.onDelete(1)}>删除</a></li>
{ {

@ -152,16 +152,16 @@ class studentsList extends Component{
} }
}else { }else {
this.props.showNotification(`正在下载中`); this.props.showNotification(`正在下载中`);
// window.open("/api"+url, '_blank'); window.open("/api"+url, '_blank');
downloadFile({ // downloadFile({
url: url, // url: url,
successCallback: (url) => { // successCallback: (url) => {
console.log('successCallback') // console.log('successCallback')
}, // },
failCallback: (responseHtml, url) => { // failCallback: (responseHtml, url) => {
console.log('failCallback') // console.log('failCallback')
} // }
}) // })
} }
}).catch((error) => { }).catch((error) => {
console.log(error) console.log(error)

@ -606,7 +606,7 @@ class CoursesNew extends Component {
`} `}
</style> </style>
<div className="stud-class-set bor-bottom-greyE padding10200 "> <div className="stud-class-set bor-bottom-greyE padding1020 ">
<div className={"TabsWarpcourse"}> <div className={"TabsWarpcourse"}>
<style>{ <style>{
` `
@ -624,21 +624,7 @@ class CoursesNew extends Component {
background-color: #fafafa!important; background-color: #fafafa!important;
} }
.yslzxueshis .ant-select-dropdown{
width: 655px !important;
height:160px !important;
}
.yslzxueshisy .ant-select-dropdown{
width: 655px !important;
height:160px !important;
}
.yslzxueshis .ant-select-dropdown-menu{
width: 655px !important;
}
.ant-select-dropdown{
width: 655px !important;
height:160px !important;
}
` `
}</style> }</style>
<Form.Item label="课程名称"> <Form.Item label="课程名称">
@ -647,7 +633,7 @@ class CoursesNew extends Component {
})( })(
<AutoComplete <AutoComplete
style={{ width: 720}} style={{ width: 704}}
onSearch={this.handleSearch} onSearch={this.handleSearch}
onSelect={this.handleSearchsysl} onSelect={this.handleSearchsysl}
className="fl construction yslzxueshis " className="fl construction yslzxueshis "
@ -693,7 +679,7 @@ class CoursesNew extends Component {
} }
.yslzxueshiskmc .ant-input-group{ .yslzxueshiskmc .ant-input-group{
width: 720px !important; width: 704px !important;
} }
.yslzxueshisy span .ant-input-group-addon{ .yslzxueshisy span .ant-input-group-addon{
width: 65px !important; width: 65px !important;
@ -704,10 +690,10 @@ class CoursesNew extends Component {
background-color: #fafafa!important; background-color: #fafafa!important;
} }
.yslzxueshiskmc .ant-input-group-wrapper{ .yslzxueshiskmc .ant-input-group-wrapper{
width: 720px !important; width: 704px !important;
} }
.yslzxueshiskmcs .ant-input-group-wrapper{ .yslzxueshiskmcs .ant-input-group-wrapper{
width: 720px !important; width: 704px !important;
} }
` `
}</style> }</style>
@ -884,7 +870,7 @@ class CoursesNew extends Component {
<AutoComplete style={{ width: 280 }} <AutoComplete style={{ width: 280 }}
onSearch={this.handleSearchschool} onSearch={this.handleSearchschool}
// onChange={this.handleChangeschools} // onChange={this.handleChangeschools}
className={"fl construction mr10 "} className={"fl construction mr10 yslzxueshis2"}
placeholder="请输入并选择课本堂的所属单位" placeholder="请输入并选择课本堂的所属单位"
> >
{optionschool} {optionschool}

@ -795,17 +795,6 @@ class Goldsubject extends Component {
background-color: #fafafa!important; background-color: #fafafa!important;
} }
.yslzxueshis .ant-select-dropdown{
width: 655px !important;
height:160px !important;
}
.yslzxueshis .ant-select-dropdown-menu{
width: 655px !important;
}
.ant-select-dropdown{
width: 655px !important;
height:160px !important;
}
` `
}</style> }</style>
<style> <style>
@ -828,7 +817,7 @@ class Goldsubject extends Component {
})( })(
<AutoComplete <AutoComplete
style={{width: 720}} style={{width: 704}}
onSearch={this.handleSearch} onSearch={this.handleSearch}
className={"fl construction yslzxueshis "} className={"fl construction yslzxueshis "}
dataSource={options} dataSource={options}
@ -1029,6 +1018,7 @@ class Goldsubject extends Component {
{/*</div>*/} {/*</div>*/}
<div className="stud-class-set padding10200 mb20"> <div className="stud-class-set padding10200 mb20">
<Form.Item label="课堂所属单位"> <Form.Item label="课堂所属单位">
{getFieldDecorator('school', { {getFieldDecorator('school', {
rules: [{required: true, message: "不能为空"}], rules: [{required: true, message: "不能为空"}],
@ -1036,7 +1026,7 @@ class Goldsubject extends Component {
<AutoComplete style={{ width: 280 }} <AutoComplete style={{ width: 280 }}
onSearch={this.handleSearchschool} onSearch={this.handleSearchschool}
// onChange={this.handleChangeschools} // onChange={this.handleChangeschools}
className={"fl construction mr10 "} className={"fl construction mr10 yslzxueshis2 "}
placeholder="请输入并选择课本堂的所属单位" placeholder="请输入并选择课本堂的所属单位"
> >
{optionschool} {optionschool}

@ -151,7 +151,8 @@ class Poll extends Component{
changePage=(pageNumber)=>{ changePage=(pageNumber)=>{
this.setState({ this.setState({
page:pageNumber page:pageNumber,
checkBoxValues:[]
}) })
let{type,StudentList_value}=this.state let{type,StudentList_value}=this.state
this.InitList(type,StudentList_value,pageNumber); this.InitList(type,StudentList_value,pageNumber);
@ -543,7 +544,7 @@ class Poll extends Component{
pollsList && pollsList.length > 0 && isAdmin && pollsList && pollsList.length > 0 && isAdmin &&
<div className="mt20 edu-back-white padding20-30"> <div className="mt20 edu-back-white padding20-30">
<div className="clearfix"> <div className="clearfix">
<Checkbox className="fl" onChange={this.onCheckAll} checked={checkAllValue}>已选 {checkBoxValues.length} </Checkbox> <Checkbox className="fl" onChange={this.onCheckAll} checked={checkAllValue}>已选 {checkBoxValues.length} 不支持跨页勾选</Checkbox>
<div className="studentList_operation_ul"> <div className="studentList_operation_ul">
<li className="li_line"><a className="color-grey-9" onClick={()=>this.ActionPoll("delete")}>删除</a></li> <li className="li_line"><a className="color-grey-9" onClick={()=>this.ActionPoll("delete")}>删除</a></li>
<li className="li_line"> <li className="li_line">

@ -66,12 +66,14 @@ class PollDetailTabThird extends Component{
{ {
pollDetail && pollDetail.questions.map((item,key)=>{ pollDetail && pollDetail.questions.map((item,key)=>{
console.log("ddd");
console.log(item.question.min_choices);
return( return(
<div className="previewList"> <div className="previewList">
<p className="pl30 pr30 pt30 pb15 font-16 clearfix"> <p className="pl30 pr30 pt30 pb15 font-16 clearfix">
<span className="color-blue mr8 fl">{item.question.question_number}{map[item.question.question_type]}</span> <span className="color-blue mr8 fl">{item.question.question_number}{map[item.question.question_type]}</span>
{ item.question.is_necessary==1 ? <span className="mustAnswer fl ml10 mr10">必答</span>:<span className="mustAnswer fl ml10 mr10"></span> } { item.question.is_necessary==1 ? <span className="mustAnswer fl ml10 mr10">必答</span>:<span className="mustAnswer fl ml10 mr10"></span> }
{ item.question.question_type == 2 && item.question.min_choices && item.question.max_choices ? { item.question.question_type == 2 && item.question.min_choices != undefined && item.question.min_choices != null && item.question.max_choices != undefined && item.question.max_choices != null ?
<span className="color-grey-9 font-14 fl mt2"> <span className="color-grey-9 font-14 fl mt2">
{ {
item.question.min_choices == item.question.max_choices ? "可选"+item.question.max_choices+"项" : item.question.min_choices == item.question.max_choices ? "可选"+item.question.max_choices+"项" :

@ -54,7 +54,7 @@ class PollListItem extends Component{
} }
</p> </p>
<p className="color-grey-9 clearfix"> <p className="color-grey-9 clearfix">
{ item.author && <span className="mr20 fl">{item.author}</span> } { item.author && <span className="mr20 fl mt3">{item.author}</span> }
{ {
item.polls_status !=1 && item.polls_status !=1 &&
<span className="fl mt3"> <span className="fl mt3">

@ -2123,7 +2123,7 @@ class PollNew extends Component {
//最小值 //最小值
HandleGradationGroupChangee = (value, index, max, length) => { HandleGradationGroupChangee = (value, index, max, length) => {
// debugger
var minbool = false; var minbool = false;
var maxbool = false; var maxbool = false;
let arr = this.state.adddom; let arr = this.state.adddom;

@ -185,7 +185,7 @@
width: 100%; width: 100%;
} }
.answerList li:hover{ .answerList li:hover{
background: #F8F8F8; background: #F0F8FF;
} }
textarea:read-only{ textarea:read-only{
background: #f3f3f3; background: #f3f3f3;

@ -218,8 +218,7 @@ class ShixunhomeWorkItem extends Component{
footer={null} footer={null}
> >
<div className="task-popup-content"> <div className="task-popup-content">
<p className="task-popup-text-center font-16 pb20">本实训的开启时间{shixunsmessage} <br/>开启时间之前不能挑战 <p className="task-popup-text-center font-16 pb20">目前该实训项目尚在内测中将于{shixunsmessage}之后开放谢谢</p>
</p>
</div> </div>
<div className="task-popup-submit clearfix"> <div className="task-popup-submit clearfix">
{/*<a onClick={this.hidestartshixunCombattype} className="task-btn fl">取消</a>*/} {/*<a onClick={this.hidestartshixunCombattype} className="task-btn fl">取消</a>*/}

@ -559,7 +559,8 @@ class ShixunHomework extends Component{
let {Coursename,order}=this.state; let {Coursename,order}=this.state;
this.setState({ this.setState({
page:pageNumber page:pageNumber,
checkBoxValues:[]
}) })
this.homeworkupdatalist(Coursename,pageNumber,order); this.homeworkupdatalist(Coursename,pageNumber,order);
@ -1070,7 +1071,7 @@ class ShixunHomework extends Component{
<div className="mt20 edu-back-white padding20-30"> <div className="mt20 edu-back-white padding20-30">
<div className="clearfix"> <div className="clearfix">
<Checkbox className="fl" style={{marginTop:'0px'}}checked={checkedtype} onClick={this.funselect}>已选 {checkBoxValues&&checkBoxValues.length} </Checkbox> <Checkbox className="fl" style={{marginTop:'0px'}}checked={checkedtype} onClick={this.funselect}>已选 {checkBoxValues&&checkBoxValues.length} 不支持跨页勾选</Checkbox>
<div className="studentList_operation_ul"> <div className="studentList_operation_ul">
<li className="li_line"><a className="color-grey-9" onClick={this.onDelete}>删除</a></li> <li className="li_line"><a className="color-grey-9" onClick={this.onDelete}>删除</a></li>
<li className="li_line"><a className="color-grey-9" onClick={this.homeworkstart}>立即发布</a></li> <li className="li_line"><a className="color-grey-9" onClick={this.homeworkstart}>立即发布</a></li>

@ -0,0 +1,165 @@
import React,{ Component } from "react";
import { Modal,Radio,Input,Tooltip,Checkbox,Select, Row,Col } from "antd";
import axios from 'axios';
const { Search } = Input;
class SendTopics extends Component{
constructor(props){
super(props);
this.state={
courses:[],
search:null,
Radiolist:undefined,
showcheck:false
}
}
componentDidMount(){
let{search}=this.state;
this.onupdatalist(search)
}
onupdatalist=(search)=>{
let url="/question_banks/my_courses.json";
axios.get(url,{params:{
search
}
}).then((result)=>{
this.setState({
courses:result.data.courses
})
}).catch((error)=>{
console.log(error);
})
}
onSearchChange=(e)=>{
this.setState({
search:e.target.value
})
// this.onupdatalist(e.target.value)
}
onSearch=(search)=>{
this.onupdatalist(search)
}
onChange=(e)=>{
this.setState({
Radiolist:e.target.value
})
}
submitInfo=()=>{
let{Radiolist}=this.state;
let url=`/question_banks/send_to_course.json`;
let object_id=this.props.checkBoxValues;
let object_type=this.props.category;
if(Radiolist===undefined){
this.setState({
showcheck:true
})
}else{
axios.post(url,{
object_id: object_id,
object_type:object_type,
course_id:Radiolist
}
).then((result)=>{
if(result.data.status===0){
this.props.updataslist()
this.props.topicscancelmodel()
this.props.showNotification(result.data.message)
}else{
this.props.showNotification(result.data.message)
}
}).catch((error)=>{
console.log(error)
})
}
}
render(){
let{courses,Radiolist,showcheck}= this.state;
const radioStyle = {
display: 'block',
height: '30px',
lineHeight: '30px',
};
return(
<div>
<style>
{
`
.ant-modal-body{
padding:20px 40px;
}
.onSearchtopics input{
height:40px;
}
.over221{
height:221px;
overflow-y: auto;
}
`
}
</style>
<Modal
keyboard={false}
title="发送至课堂"
visible={this.props.visible}
closable={false}
footer={null}
destroyOnClose={true}
width={600}
>
<div className="newupload_conbox">
<div className="mb15 font-14 edu-txt-center color-orange-tip">
温馨提示选择的题将会发送到指定课堂
</div>
<div className="mb5"
// onMouseLeave={this.closeList}
>
<Search
className="mb14 onSearchtopics"
placeholder="请输入课堂名称进行搜索"
onChange={this.onSearchChange}
onSearch={this.onSearch}
></Search>
</div>
<div className="edu-back-skyblue pl15 pr15 clearfix over221 pt5">
<Radio.Group onChange={this.onChange} value={Radiolist}>
{
courses && courses.map((item,key)=>{
return(
<div className="mt5" key={key}>
<Radio style={radioStyle} value={item.course_id} key={item.course_id}>
{item.course_name}
</Radio>
</div>
)
})
}
</Radio.Group>
</div>
{showcheck===true?<div className={"color-red mt10"}>请先选择课堂</div>:""}
<div className="mt20 clearfix edu-txt-center">
<a onClick={()=>this.props.topicscancelmodel()} className="pop_close task-btn mr30">取消</a>
<a className="task-btn task-btn-orange" onClick={()=>this.submitInfo()}>确定</a>
</div>
</div>
</Modal>
</div>
)
}
}
export default SendTopics;

@ -361,7 +361,7 @@ class DetailCards extends Component{
footer={null} footer={null}
> >
<div className="task-popup-content"> <div className="task-popup-content">
<p className="task-popup-text-center font-16 pb20">本实训的开启时间{this.state.shixunsmessage} <br/>开启时间之前不能挑战 </p> <p className="task-popup-text-center font-16 pb20">目前该实训项目尚在内测中将于{this.state.shixunsmessage}之后开放谢谢</p>
</div> </div>
<div className="task-popup-submit clearfix"> <div className="task-popup-submit clearfix">
{/*<a onClick={this.hidestartshixunCombattype} className="task-btn fl">取消</a>*/} {/*<a onClick={this.hidestartshixunCombattype} className="task-btn fl">取消</a>*/}

@ -295,11 +295,11 @@
.topsj{ .topsj{
position: absolute; position: absolute;
top: -6px; top: -3px;
} }
.bottomsj{ .bottomsj{
position: absolute; position: absolute;
bottom: -6px; bottom: -5px;
} }
.touchSelect .ant-spin-dot-spin{ .touchSelect .ant-spin-dot-spin{
margin-top: 30% !important; margin-top: 30% !important;

@ -731,8 +731,7 @@ class TPMBanner extends Component {
footer={null} footer={null}
> >
<div className="task-popup-content"> <div className="task-popup-content">
<p className="task-popup-text-center font-16 pb20">本实训的开启时间{shixunsmessage} <br/>开启时间之前不能挑战 <p className="task-popup-text-center font-16 pb20">目前该实训项目尚在内测中将于{shixunsmessage}之后开放谢谢</p>
</p>
</div> </div>
<div className="task-popup-submit clearfix"> <div className="task-popup-submit clearfix">
{/*<a onClick={this.hidestartshixunCombattype} className="task-btn fl">取消</a>*/} {/*<a onClick={this.hidestartshixunCombattype} className="task-btn fl">取消</a>*/}

@ -587,7 +587,7 @@ class Challenges extends Component {
footer={null} footer={null}
> >
<div className="task-popup-content"> <div className="task-popup-content">
<p className="task-popup-text-center font-16 pb20">本实训的开启时间{shixunsmessage} <br/>开启时间之前不能挑战 </p> <p className="task-popup-text-center font-16 pb20">目前该实训项目尚在内测中将于{shixunsmessage}之后开放谢谢 </p>
</div> </div>
<div className="task-popup-submit clearfix"> <div className="task-popup-submit clearfix">
{/*<a onClick={this.hidestartshixunCombattype} className="task-btn fl">取消</a>*/} {/*<a onClick={this.hidestartshixunCombattype} className="task-btn fl">取消</a>*/}

@ -43,7 +43,10 @@ const InfosVideo = Loadable({
loader: () => import('./video/InfosVideo'), loader: () => import('./video/InfosVideo'),
loading:Loading, loading:Loading,
}) })
const InfosTopics=Loadable({
loader: () => import('./InfosTopics'),
loading:Loading,
})
const $ = window.$; const $ = window.$;
class Infos extends Component{ class Infos extends Component{
@ -258,13 +261,10 @@ class Infos extends Component{
<Switch {...this.props}> <Switch {...this.props}>
{/* --------------------------------------------------------------------- */} {/* --------------------------------------------------------------------- */}
{/* 题库 */}
<Route exact path="/users/:username/topics/:topicstype"
{/* 众包 */}
{/* http://localhost:3007/courses/1309/homework/9300/setting */}
<Route exact path="/users/:username/package"
render={ render={
(props) => (<InfosPackage {...this.props} {...props} {...this.state} {..._commonProps}/>) (props) => (<InfosTopics {...this.props} {...props} {...this.state} {..._commonProps}/>)
} }
></Route> ></Route>
@ -297,7 +297,15 @@ class Infos extends Component{
} }
></Route> ></Route>
{/* 项目 */} {/* 众包 */}
{/* http://localhost:3007/courses/1309/homework/9300/setting */}
<Route exact path="/users/:username/package"
render={
(props) => (<InfosPackage {...this.props} {...props} {...this.state} {..._commonProps}/>)
}
></Route>
{/* 视频 */}
<Route exact path="/users/:username/videos" <Route exact path="/users/:username/videos"
render={ render={
(props) => (<InfosVideo {...this.props} {...props} {...this.state} {..._commonProps}/>) (props) => (<InfosVideo {...this.props} {...props} {...this.state} {..._commonProps}/>)
@ -305,6 +313,7 @@ class Infos extends Component{
></Route> ></Route>
<Route exact path="/users/:username" <Route exact path="/users/:username"
render={ render={
(props) => (<InfosCourse {...this.props} {...props} {...this.state} {..._commonProps}/>) (props) => (<InfosCourse {...this.props} {...props} {...this.state} {..._commonProps}/>)

@ -27,6 +27,9 @@ class InfosBanner extends Component{
let {pathname}=this.props.location; let {pathname}=this.props.location;
moduleName=pathname.split("/")[3]; moduleName=pathname.split("/")[3];
let user_id=this.props.current_user&&this.props.current_user.user_id;
let user_type=this.props.current_user&&this.props.current_user.user_identity;
let targetuserid=this.props.data&&this.props.data.id;
return( return(
<div className="bannerPanel mb60"> <div className="bannerPanel mb60">
<div className="educontent"> <div className="educontent">
@ -115,6 +118,13 @@ class InfosBanner extends Component{
to={`/users/${username}/videos`}>视频</Link> to={`/users/${username}/videos`}>视频</Link>
</li>} </li>}
{/*自己的主页且不是学生显示题库按钮*/}
{ user_id===targetuserid&&user_type!="学生"?<li className={`${moduleName == 'topics' ? 'active' : '' }`}>
<Link
onClick={() => this.setState({moduleName: 'topics'})}
to={`/users/${username}/topics/personal`}>题库</Link>
</li>:""}
</div> </div>
</div> </div>
</div> </div>

@ -0,0 +1,489 @@
import React, { Component } from 'react';
import { SnackbarHOC } from 'educoder';
import {BrowserRouter as Router,Route,Switch,Link} from 'react-router-dom';
import {Tooltip,Menu,Pagination,Spin, Dropdown,Checkbox} from 'antd';
import axios from 'axios';
import {getImageUrl,WordsBtn} from 'educoder';
import moment from 'moment';
import Modals from '../../modals/Modals';
import SendTopics from '../../modals/SendTopics'
import NoneData from '../../courses/coursesPublic/NoneData';
import "./usersInfo.css";
import Withoutpermission from './Withoutpermission.png';
class InfosTopics extends Component{
constructor(props){
super(props);
this.state={
isSpin:false,
category:"normal",
course_list_id:undefined,
sort_by:"updated_at",
sort_direction:"desc",
page:1,
data:undefined,
checkBoxValues:[],
per_page:15,
isshowprofes:false
}
}
componentDidMount(){
let types=this.props.match.params.topicstype;
let professional_certification=this.props.current_user&&this.props.current_user.professional_certification;
console.log(professional_certification)
if(professional_certification===false&&types==="publicly"){
this.setState({
isshowprofes:true
})
}else{
this.updataslist()
}
}
updataslist=()=>{
let types=this.props.match.params.topicstype;
let { category,course_list_id,sort_by,sort_direction,page}=this.state;
this.searchAlldata(types,category,course_list_id,sort_by,sort_direction,page)
}
searchAlldata=(type,category,course_list_id,sort_by,sort_direction,page)=>{
let user_id=this.props.current_user&&this.props.current_user.user_id;
if(user_id!=undefined){
let {per_page}=this.state;
let url=`/users/${user_id}/question_banks.json`;
axios.get(url,{params:{
type,
category,
course_list_id,
sort_by,
sort_direction,
page,
per_page
}
}).then((response) => {
this.setState({
data:response.data
})
}).catch((error) => {
});
}
}
searchCategory=(type)=>{
this.setState({
category:type
})
let types=this.props.match.params.topicstype;
let { category,course_list_id,sort_by,sort_direction,page}=this.state;
this.searchAlldata(types,type,course_list_id,sort_by,sort_direction,page)
}
searchCourselistid=(id)=>{
this.setState({
course_list_id:id
})
let types=this.props.match.params.topicstype;
let { category,course_list_id,sort_by,sort_direction,page}=this.state;
this.searchAlldata(types,category,id,sort_by,sort_direction,page)
}
onCheckBoxChange=(checkedValues)=>{
if(checkedValues.length>15){
this.props.showNotification("选择条数不能大于15条")
}else{
this.setState({
checkBoxValues:checkedValues
})
}
}
updatedlist=(updatedtype)=>{
let types=this.props.match.params.topicstype;
let { category,course_list_id,sort_by,sort_direction,page}=this.state;
if(updatedtype===sort_by){
if(sort_direction==="desc"){
this.setState({
sort_direction:"asc",
sort_by:updatedtype
})
this.searchAlldata(types,category,course_list_id,updatedtype,"asc",page)
}else{
this.setState({
sort_direction:"desc",
sort_by:updatedtype
})
this.searchAlldata(types,category,course_list_id,updatedtype,"desc",page)
}
}else{
this.setState({
sort_direction:"desc",
sort_by:updatedtype
})
this.searchAlldata(types,category,course_list_id,updatedtype,"desc",page)
}
}
changePage=(pageNumber)=>{
let types=this.props.match.params.topicstype;
let { category,course_list_id,sort_by,sort_direction,page}=this.state;
this.searchAlldata(types,category,course_list_id,sort_by,sort_direction,pageNumber)
this.setState({
page:pageNumber,
checkBoxValues:[]
})
}
deletecheckBoxValues=()=>{
let {checkBoxValues}=this.state;
if(checkBoxValues.length===0){
this.props.showNotification("请选择题库")
}
this.setState({
Modalstype:true,
Modalstopval:"是否确认删除?",
ModalCancel:this.topicscancelmodel,
ModalSave:this.topicssavedelete,
})
}
topicssavedelete=()=>{
let {checkBoxValues,category}=this.state;
const url = `/question_banks/multi_delete.json`;
axios.delete(url, { data: {
object_id: checkBoxValues,
object_type:category
}})
.then((response) => {
if(response.data.status===0){
this.updataslist()
this.props.showNotification(response.data.message)
}else{
this.props.showNotification(response.data.message)
}
})
.catch(function (error) {
console.log(error);
});
this.topicscancelmodel()
}
topicscancelmodel=()=>{
this.setState({
Modalstype:false,
Loadtype:false,
visible:false,
Modalstopval:"",
ModalCancel:"",
ModalSave:"",
checkBoxValues:[],
checkedtype:false
})
}
openTopics=(id)=>{
this.setState({
Modalstype:true,
Modalstopval:"公开后不能重设为私有",
ModalsBottomval:"是否确认设为公开?",
ModalCancel:this.topicscancelmodel,
ModalSave:()=>this.topicssaveonOpen(id),
})
}
topicssaveonOpen=(id)=>{
let {category}=this.state;
const url = `/question_banks/multi_public.json`;
axios.post(url,{
object_id:[id],
object_type:category
}).then((response) => {
if(response.data.status===0){
this.updataslist()
this.props.showNotification(response.data.message)
}else{
this.props.showNotification(response.data.message)
}
}).catch(function (error) {
console.log(error);
});
this.topicscancelmodel()
}
sendTopics=()=>{
let {checkBoxValues}=this.state;
if(checkBoxValues.length===0){
this.props.showNotification("请选择题库")
}else{
this.setState({
visible:true
})
}
}
render(){
let{
category,
course_list_id,
isSpin,
data,
page,
sort_direction,
sort_by,
checkBoxValues,
Modalstype,
visible,
isshowprofes
} = this.state;
let categorylist=[
{val:"普通作业",type:"normal"},
{val:"分组作业",type:"group"},
{val:"毕设选题",type:"gtopic"},
{val:"毕设任务",type:"gtask"},
{val:"试卷",type:"exercise"},
{val:"问卷",type:"poll"},
]
let types=this.props.match.params.topicstype;
console.log(isshowprofes)
//types===publicly 公共
//types===personal 私有
let user_id=this.props.current_user&&this.props.current_user.user_id;
let user_type=this.props.current_user&&this.props.current_user.user_identity;
let targetuserid=this.props.data&&this.props.data.id;
const menu = (
<Menu>
<Menu.Item onClick={()=>this.updatedlist("updated_at")}>
最近更新
</Menu.Item>
<Menu.Item onClick={()=>this.updatedlist("name")}>
题目更新
</Menu.Item>
{types==="publicly"?<Menu.Item onClick={()=>this.updatedlist("contributor")}>
贡献者
</Menu.Item>:""}
</Menu>
);
return(
<div className="educontent mb50">
{/*提示*/}
{Modalstype&&Modalstype===true?<Modals
modalsType={this.state.Modalstype}
modalsTopval={this.state.Modalstopval}
modalCancel={this.state.ModalCancel}
modalSave={this.state.ModalSave}
modalsBottomval={this.state.ModalsBottomval}
loadtype={this.state.Loadtype}
/>:""}
{/*发送至弹窗*/}
{
visible&&visible===true?
<SendTopics
{...this.state}
{...this.props}
visible={visible}
updataslist={()=>this.updataslist()}
topicscancelmodel={()=>this.topicscancelmodel()}
/>:""
}
<style>
{
`
.shaiContent li.shaiItem {
padding: 3px 15px;
float: left;
border-radius: 4px;
color: #4C4C4C;
cursor: pointer;
margin-right: 20px;
display: block;
margin-bottom: 5px;
}
.mr38{
margin-right:38px;
}
.maxwidth900{
max-width: 900px;
overflow:hidden;
text-overflow:ellipsis;
white-space:nowrap
}
.homepagePostSettingname{
width:192px !important;
}
.homepagePostSettingbox{
width:139px !important;
}
`
}
</style>
<Spin size="large" spinning={isSpin}>
<div className="clearfix topicsbox">
{types==="publicly"?<div className={"topcschild"}>
<a className={types==="personal"?"topicstopfont fr topcsactive":"topicstopfont fr"}
href={`/users/innov/topics/personal`}>个人题库</a>
<a className={types==="publicly"?"topicstopfont fl topcsactive":"topicstopfont fl"}
href={`/users/innov/topics/publicly`}
>公共题库</a>
</div>:<div className={"topcschild"}>
<a className={types==="personal"?"topicstopfont fl topcsactive":"topicstopfont fl"}
href={`/users/innov/topics/personal`}>我的题库</a>
<a className={types==="publicly"?"topicstopfont fr topcsactive":"topicstopfont fr"}
href={`/users/innov/topics/publicly`}
>公共题库</a>
</div>}
{isshowprofes===false?
<div>
<div className={"topcsmid"}>
{categorylist.map((item,key)=>{
return(
<span key={key} className={category===item.type?"topicsmidfont fl mr38 topcsactive":"topicsmidfont fl mr38"} onClick={()=>this.searchCategory(item.type)}>{item.val}</span>
)
})}
</div>
<div className={"shaiContent"}>
<div className="fl pr topicsItem pagetype mb20">
<li className={course_list_id===undefined?"shaiItem shixun_repertoire active":"shaiItem shixun_repertoire"} onClick={()=>this.searchCourselistid(undefined)}>全部</li>
{data===undefined?"":data.course_list===undefined||data.course_list.length===0?"":data.course_list.map((item,key)=>{
return(
<li key={key} className={course_list_id===item.id?"shaiItem shixun_repertoire active":"shaiItem shixun_repertoire"} onClick={()=>this.searchCourselistid(item.id)}>{item.name}</li>
)
})}
</div>
</div>
</div>:<div className={"professional_certificationbox"}>
<p className="clearfix ">
<div className={"stud-class-set pd115200 coursenavbox edu-back-white"}>
<div className={"sumbtongs mb10"}><img className={"topicsItemimg"} src={Withoutpermission}/></div>
<div className={"terraces mb5 topicsItemfont"}>通过职业认证的教师才能访问公共题库</div>
<div className="clearfix mt30 mb30 padding251">
<a className="defalutSubmitbtn fl ml60 defalutSubmitbtns" target="_blank" href="/account/certification">立即认证</a>
</div>
</div>
</p>
</div>}
</div>
{isshowprofes===false?<div className="clearfix font-12 mt20">
<p className="font-12 alltopisc ml25 fl">
<span className="fl color-grey-9"> <span className={"color-orange"}>{data&&data.count===undefined?0:data&&data.count}</span> </span>
<span className="fr color-grey-9">已选择 <span className={"color-orange"}>{checkBoxValues.length}</span> ()</span>
</p>
<p className="font-12 alltopiscright ml25 fr">
<Dropdown overlay={menu}>
<span className="fr color-grey-9 mr10 pointer">
{sort_by==="updated_at"?'最近更新':sort_by==="name"?'题目更新':sort_by==="contributor"?"贡献者":""}
<sapn className="relativef ml20">
<i className={sort_direction==="asc"?
"iconfont icon-sanjiaoxing-up font-12 topsj color-blue" :"iconfont icon-sanjiaoxing-up font-12 topsj"}></i>
<i className={sort_direction==="desc"?
"iconfont icon-sanjiaoxing-down font-12 bottomsj color-blue":"iconfont icon-sanjiaoxing-down font-12 bottomsj"}></i>
</sapn>
</span>
</Dropdown>
{user_type!="学生"?<span className="fr mr30 topcsactive pointer" onClick={()=>this.sendTopics()}>发送</span>:""}
{types==="personal"?user_id===targetuserid&&user_type!="学生"?<span className="fr mr30 topcsactive pointer" onClick={()=>this.deletecheckBoxValues()}>删除</span>:"":""}
</p>
</div>:""}
{isshowprofes===true?"":data===undefined?<NoneData></NoneData>:data.question_banks===undefined||data.question_banks.length===0?<NoneData></NoneData>:
<Checkbox.Group style={{ width: '100%' }} onChange={this.onCheckBoxChange} value={checkBoxValues}>
{data.question_banks.map((item,key)=>{
return(
<div className="mt20 edu-back-white pd1323 relativef" key={key} >
<div className="clearfix">
<div className="item-body">
<div className="clearfix ds pr pt5 contentSection" >
{user_type!="学生"?<Checkbox value={item.id} key={item.id} className={"fl mt5"}></Checkbox>:""}
<a title={item.name} className="ml10 fl mt3 font-16 color-dark maxwidth900">
{item.name}
</a>
{item.is_public===true?<span className="edu-filter-btn ml15 fl typestyle mt3 topiscfilterbtn">公开</span>:""}
{types==="personal"&&item.is_public===false?user_id===targetuserid&&user_type!="学生"?<a className="btn colorblue mr25 fr font-16" onClick={()=>this.openTopics(item.id)}>设为公开</a>:"":""}
<div className="cl"></div>
<p className="color-grey panel-lightgrey mt16 fl">
<span className={types==="personal"?"topicswidth300":"topicswidth400"}>
{types==="publicly"?<span className="topsics100 color-grey9">{item.creator_name}</span>:""}
<span className="mr50 color-grey9">{item.quotes_count} 次引用</span>
<span className="mr50 color-grey9">{item.solve_count} 次答题</span>
<span className="mr50 color-grey9">{moment(item.updated_at).fromNow()}</span>
</span>
<span className="topicsbtn">{item.course_list_name}</span>
</p>
<div className="homepagePostSetting homepagePostSettingname topscisright">
{types==="personal"?user_id===targetuserid&&user_type!="学生"?
<a className="btn colorblue mr25 font-16 fr"
href={category==="normal"?`/courses/ordinarywork/${item.id}?tab=0`:
category==="group"?`/courses/groupingwork/${item.id}?tab=0`:
category==="poll"?`/courses/poll/${item.id}`:
category==="exercise"?`/courses/poll/${item.id}`:
category==="gtask"?`/courses/completetask/${item.id}`:
category==="gtopic"?`/courses/completetopic/${item.id}`:""
}
>编辑</a>
:"":""}
</div>
</div>
</div>
</div>
</div>
)})}
</Checkbox.Group>
}
{
isshowprofes===true?"":data&&data.count >15 &&
<div className="mt30 mb50 edu-txt-center">
<Pagination showQuickJumper total={data&&data.count} onChange={this.changePage} pageSize={15} current={page}/>
</div>
}
</Spin>
</div>
)
}
}
export default InfosTopics;

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

@ -0,0 +1,100 @@
import React, { Component } from 'react';
import {BrowserRouter as Router,Route,Switch} from 'react-router-dom';
import { Breadcrumb } from 'antd';
import { SnackbarHOC } from 'educoder';
import { TPMIndexHOC } from '../../../tpm/TPMIndexHOC';
import { CNotificationHOC } from '../../../courses/common/CNotificationHOC'
import "../usersInfo.css"
import "../../../courses/css/members.css"
import "../../../courses/css/Courses.css"
import Loadable from 'react-loadable';
import Loading from '../../../../Loading';
// 毕设选题
const GtopicBanks = Loadable({
loader: () => import('./GtopicBanks'),
loading: Loading,
})
const BanksTabIndex = Loadable({
loader: () => import('./BanksTabIndex'),
loading: Loading,
})
const GtopicBanksEdit = Loadable({
loader: () => import('./GtopicBanksEdit'),
loading: Loading,
})
class BanksIndex extends Component{
constructor(props){
super(props);
this.state={
crumbData:undefined
}
}
initPublic = (crumbData) =>{
this.setState({
crumbData
})
}
render(){
let { crumbData }=this.state
const common = {
initPublic:this.initPublic
}
return(
<div className="newMain">
<div className="educontent">
{
crumbData &&
<Breadcrumb separator=">" className="breadcrumb">
<Breadcrumb.Item href="/users/innov/banks">题库</Breadcrumb.Item>
{
crumbData.crumbArray && crumbData.crumbArray.map((item,key)=>{
return(
<Breadcrumb.Item href={item.to || ""}>{item.content}</Breadcrumb.Item>
)
})
}
</Breadcrumb>
}
<p className="clearfix mt20 mb20">
<span className="fl font-24 color-grey-3 task-hide lineh-30" style={{maxWidth:'800px'}}>{crumbData && crumbData.title}</span>
{
crumbData && crumbData.is_public && <span className="bank_is_public">{crumbData.is_public == true ? '公开':'私有'}</span>
}
</p>
<Switch {...this.props}>
<Route path='/banks/gtopic/:bankId/edit'
render={
(props) => {
return (<GtopicBanksEdit {...this.props} {...props} {...this.state} {...common}/>)
}
}></Route>
<Route path='/banks/gtopic/:bankId'
render={
(props) => {
return (<BanksTabIndex {...this.props} {...props} {...this.state} {...common}/>)
}
}></Route>
</Switch>
</div>
</div>
)
}
}
export default CNotificationHOC() ( SnackbarHOC() ( TPMIndexHOC(BanksIndex) ));

@ -0,0 +1,65 @@
import React, { Component } from 'react';
import {BrowserRouter as Router,Route,Switch} from 'react-router-dom';
import Loadable from 'react-loadable';
import Loading from '../../../../Loading';
import BanksMenu from './banksMenu'
// 毕设选题
const GtopicBanks = Loadable({
loader: () => import('./GtopicBanks'),
loading: Loading,
})
class BanksTabIndex extends Component{
constructor(props){
super(props);
this.state={
banksMenu:undefined
}
}
initPublic = (crumbData,menuData) =>{
this.setState({
banksMenu:menuData
})
this.props.initPublic(crumbData);
}
render(){
let{
banksMenu
}=this.state
const common={
initPublic:this.initPublic,
}
return(
<React.Fragment>
{
banksMenu &&
<BanksMenu
banksMenu={banksMenu}
{...this.props}
{...this.state}
{...common}
></BanksMenu>
}
<Switch {...this.props}>
<Route path='/banks/gtopic/:bankId'
render={
(props) => {
return (<GtopicBanks {...this.props} {...props} {...this.state} {...common} />)
}
}></Route>
</Switch>
</React.Fragment>
)
}
}
export default (BanksTabIndex);

@ -0,0 +1,36 @@
import React, { Component } from 'react';
class GtopicBanks extends Component{
constructor(props){
super(props);
}
componentDidMount = () =>{
let bankId = this.props.match.params.bankId
const crumbData={
title:'MySQL数据库编程开发实训基础篇111',
is_public:true,
crumbArray:[
{content:'详情'},
]
}
const menuData={
tab:'0',//tab选中的index
menuArray:[//tab以及tab路由
{to:'/banks/gtopic/1',content:'内容详情'},
// {to:'/banks/gtopic/1/answer',content:'参考答案'},
],
category:'topic',//毕设选题
id:bankId
}
this.props.initPublic(crumbData,menuData);
}
render(){
return(
<div>
</div>
)
}
}
export default GtopicBanks;

@ -0,0 +1,88 @@
import React, { Component } from 'react';
import axios from 'axios'
import GraduateTopicNewFrom from '../../../courses/graduation/topics/GraduateTopicNewFrom'
class GtopicBanksEdit extends Component{
constructor(props){
super(props);
this.state = {
isPublic:undefined
}
}
componentDidMount = () =>{
let bankId = this.props.match.params.bankId;
this.initData(bankId);
}
initData = (bankId) =>{
let url = `/gtopic_banks/${bankId}/edit.json`;
axios.get(url).then((result)=>{
if(result){
const crumbData={
title:'编辑',
is_public:result && result.selected_data && result.selected_data.is_public,
crumbArray:[
{to:`/banks/gtopic/${bankId}/edit`,content:'详情'},
{content:'编辑'}
]
}
this.props.initPublic(crumbData);
this.GraduateTopicNewFromRef.initValue(result);
}
}).catch((error)=>{
console.log(error)
})
}
// 编辑保存
editSave = (param,attachments,bankId) =>{
const url = `/gtopic_banks/${bankId}.json`;
let params = {
gtopic_bank:param,
attachment_ids:attachments
}
axios.put(url,params).then((result)=>{
if(result){
this.props.showNotification('保存成功!');
this.props.history.push(`/banks/gtopic/${bankId}`);
}
}).catch((error)=>{
console.log(error);
})
}
// 取消
editCancel = () =>{
this.props.history.push(`/banks/gtopic/${this.props.match.params.bankId}`);
}
render(){
let { bankId } = this.props.match.params
const common = {
editSave:this.editSave,
editCancel:this.editCancel
}
return(
<div className="courseForm">
<style>
{`
.courseForm .ant-col-sm-24{
text-align:left;
}
`}
</style>
<GraduateTopicNewFrom
{...this.props}
{...this.state}
{...common}
wrappedComponentRef={(ref) => this.GraduateTopicNewFromRef = ref}
topicId={bankId}
></GraduateTopicNewFrom>
</div>
)
}
}
export default GtopicBanksEdit;

@ -0,0 +1,42 @@
import React, { Component } from 'react';
import { Menu } from 'antd'
import { Link } from 'react-router-dom'
import { WordsBtn } from 'educoder'
import "../usersInfo.css"
import "../../../courses/css/Courses.css"
import "../../../courses/css/busyWork.css"
class BanksMenu extends Component{
constructor(props){
super(props);
}
render(){
let { banksMenu } = this.props;
return(
<div className="clearfix bor-bottom-greyE edu-back-white" style={{padding:"2px 30px"}}>
{
banksMenu &&
<div className="task_menu_ul fl">
<Menu mode="horizontal" selectedKeys={[`${banksMenu && banksMenu.tab}`]}>
{
banksMenu.menuArray && banksMenu.menuArray.map((item,key)=>{
return(
<Menu.Item key={key}><Link to={`${item.to}`}>{item.content}</Link></Menu.Item>
)
})
}
</Menu>
</div>
}
<span className="fr mt18">
<WordsBtn to={''} style="blue" className="ml20 font-16">删除</WordsBtn>
<WordsBtn to={''} style="blue" className="ml20 font-16">编辑</WordsBtn>
<WordsBtn to={''} style="blue" className="ml20 font-16">发送</WordsBtn>
</span>
</div>
)
}
}
export default BanksMenu;

@ -227,3 +227,157 @@
left:0px; left:0px;
background: #4CACFF; background: #4CACFF;
} }
/* 题库相关 */
.breadcrumb{
height: 18px;
line-height: 18px;
margin:10px 0px 0px;
}
.breadcrumb .ant-breadcrumb-separator{
margin:0px 2px!important;
}
.breadcrumb span.ant-breadcrumb-link{
cursor: default;
}
.bank_is_public{
background: #E4F2FE;
float: left;
height: 30px;
line-height: 30px;
padding:0px 20px;
color: #4CACFF;
font-size: 16px;
margin-left: 10px;
}
.topicsbox{
width: 1200px;
/*min-height: 216px;*/
background: rgba(255,255,255,1);
padding: 0px 30px 0px 40px;
}
.topicstopfont{
width:64px;
height:16px;
font-size:16px;
font-family:PingFangSC;
font-weight:400;
color:rgba(51,51,51,1);
cursor: pointer;
}
.topcschild{
width:1128px;
height:55px;
line-height: 54px;
border-bottom:1px solid rgba(235,235,235,1);
}
.topcsmid{
width:1128px;
height:55px;
line-height: 55px;
}
.topcsactive{
color: #4CACFF !important;
}
.topicsmidfont{
max-width: 56px;
height: 55px;
font-size: 14px;
font-family: PingFangSC;
font-weight: 400;
cursor: pointer;
line-height: 55px;
}
.alltopisc{
width:230px;
height:20px;
font-size:14px;
font-family:PingFangSC;
font-weight:400;
color:rgba(153,153,153,1);
line-height:20px;
}
.alltopiscright{
/* width: 141px; */
height: 20px;
font-size: 14px;
font-family: PingFangSC;
font-weight: 400;
color: rgba(153,153,153,1);
line-height: 20px;
}
.topicsbtn{
padding: 3px 15px;
border-radius: 2px;
color: #4C4C4C;
cursor: pointer;
display: inline-block;
background-color: #4CACFF!important;
color: #fff!important;
}
.pd1323{
padding: 10px 6px 25px 40px;
cursor: pointer;
}
.pd1323:hover {
box-shadow: 0px 2px 6px rgba(51,51,51,0.09);
opacity: 1;
border-radius: 2px;
}
.topicswidth400{
width: 400px;
display: inline-block;
}
.topicswidth300{
width: 300px;
display: inline-block;
}
.topiscfilterbtn{
font-size: 14px;
color: #4CACFF !important;
border-radius: 5px;
border: 1px solid #4CACFF !important;
line-height: 23px !important;
}
.topscisright{
right: 0px;
top: 50px;
display: block;
position: absolute;
}
.topsics100{
width: 100px;
display: inline-block;
}
.professional_certificationbox{
height:431px;
background:rgba(255,255,255,1);
}
.pd115200{
padding: 55px 200px 0px 200px;
}
.topicsItemimg{
width:150px;
}
.topicsItemfont{
font-size: 18px;
font-family: PingFang-SC;
font-weight: 400;
color: rgba(51,51,51,1);
line-height: 35px;
}
Loading…
Cancel
Save