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
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
end
end

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

@ -1,8 +1,9 @@
#encoding: UTF-8
class ExerciseBanksController < ApplicationController
before_action :require_login
before_action :find_bank
before_action :find_bank, except: [:choose_shixun]
before_action :bank_admin, only: [:update]
before_action :commit_shixun_present, only: [:commit_shixun]
def show
@exercise_questions = @bank.exercise_bank_questions&.includes(:exercise_bank_choices, :exercise_bank_shixun_challenges,
@ -47,6 +48,38 @@ class ExerciseBanksController < ApplicationController
normal_status(0,"试卷更新成功!")
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
def find_bank
@ -57,4 +90,17 @@ class ExerciseBanksController < ApplicationController
def bank_admin
tip_exception(403, "无权限") unless (current_user.certification_teacher? && @bank.user_id == current_user.id) || current_user.admin?
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

@ -901,9 +901,9 @@ class PollsController < ApplicationController
error_question = []
@poll_multi_questions.each do |q|
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}题:超过最大选项限制"
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}题:不得少于最小选项限制"
else
error_messages = nil
@ -936,7 +936,7 @@ class PollsController < ApplicationController
def commit_result
ActiveRecord::Base.transaction do
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
@page = params[:page] || 1
@limit = params[:limit] || 10

@ -1,6 +1,7 @@
class QuestionBanksController < ApplicationController
before_action :require_login, :check_auth
before_action :params_filter, except: [:my_courses]
before_action :teacher_or_admin, except: [:bank_list]
# 题库选用列表
# object_type: # normal 普通作业题库; group 分组作业题库; poll问卷题库 exercise试卷题库; gtask 毕设选题题库gtopic 毕设任务
@ -81,11 +82,15 @@ class QuestionBanksController < ApplicationController
def my_courses
@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
def send_to_course
bank = current_bank
course = current_user.manage_courses.find_by(id: params[:course_id])
banks = object_banks
course = current_user.manage_courses.find_by!(id: params[:course_id])
banks.each do |bank|
case @object_type
when 'HomeworkBank' # 作业
quote_homework_bank bank, course
@ -100,13 +105,14 @@ class QuestionBanksController < ApplicationController
when 'GtopicBank'
quote_gtopic_bank bank, course
end
end
normal_status("发送成功")
end
def destroy
bank = current_bank
unless user.admin? || bank.user_id == user.id
unless current_user.admin? || bank.user_id == current_user.id
render_forbidden
return
end
@ -121,11 +127,32 @@ class QuestionBanksController < ApplicationController
render_ok
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
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
@_current_bank ||= @object_type.classify.constantize.where(@object_filter).find(params[:id])
end
def params_filter
type = ["normal", "group", "poll", "exercise", "gtask", "gtopic"]
tip_exception("object_type类型不正确") unless type.include?(params[:object_type])
@ -152,6 +179,10 @@ class QuestionBanksController < ApplicationController
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
ActiveRecord::Base.transaction do
# 复制作业的基本信息

@ -8,7 +8,7 @@ class Users::QuestionBanksController < Users::BaseController
@count = question_banks.count
@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
end
@ -18,8 +18,8 @@ class Users::QuestionBanksController < Users::BaseController
def load_question_banks_solve_count
question_bank_ids = @question_banks.map(&:id)
@solve_count_map =
case params[:category]
when 'common', 'group' then
case params[:object_type]
when 'normal', 'group' then
StudentWork.where(is_delete: false, work_status: [1, 2, 3]).joins(:homework_common)
.where(homework_commons: { homework_bank_id: question_bank_ids })
.group('homework_commons.homework_bank_id').count
@ -42,14 +42,14 @@ class Users::QuestionBanksController < Users::BaseController
end
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
def check_query_params!
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])
params[:category] = 'common'
if params[:object_type].blank? || !%w(normal group exercise poll gtask gtopic).include?(params[:object_type])
params[:object_type] = 'normal'
end
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 })
category_condition =
case params[:category]
when 'common' then { homework_type: 1 }
case params[:object_type]
when 'normal' then { homework_type: 1 }
when 'group' then { homework_type: 3 }
when 'exercise' then { container_type: 'Exercise' }
when 'poll' then { container_type: 'Poll' }
@ -47,8 +47,8 @@ class Users::QuestionBankService
def class_name
@_class_name ||= begin
case params[:category]
when 'common', 'group' then 'HomeworkBank'
case params[:object_type]
when 'normal', 'group' then 'HomeworkBank'
when 'exercise', 'poll' then 'ExerciseBank'
when 'gtask' then 'GtaskBank'
when 'gtopic' then 'GtopicBank'
@ -58,8 +58,8 @@ class Users::QuestionBankService
end
def category_filter(relations)
case params[:category]
when 'common' then
case params[:object_type]
when 'normal' then
relations.where(homework_type: 1)
when 'group' then
relations.where(homework_type: 3)

@ -17,15 +17,16 @@
</td>
<td>
<!-- 图片上传,稍后添加-->
--
<a href="javascript:void(0);" id="object_upload_img_<%= shixun.id %>" onclick="$('#upload_img_<%= shixun.id %>').click();">
<%= File.exist?(disk_filename("Shixun",shixun.id)) ? "重新上传" : "上传图片" %>
</a>
<% 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}") %>
<% else %>
<img src="" class="w80 h80 fl ml5 shixun_image_show none" id="shixun_image_show_<%= shixun.id %>"/>
<% end %>
<!-- <a href="javascript:void(0);" id="object_upload_img_<%#= shixun.id %>" onclick="$('#upload_img_<%= shixun.id %>').click();">-->
<%#= File.exist?(disk_filename("Shixun",shixun.id)) ? "重新上传" : "上传图片" %>
<!-- </a>-->
<%# 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}") %>
<%# else %>
<!-- <img src="" class="w80 h80 fl ml5 shixun_image_show none" id="shixun_image_show_<%#= shixun.id %>"/>-->
<%# end %>
</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
end
exercise_type = 3
if @t_user_exercise_status == 3 && @exercise.answer_open
exercise_type = 4
end
json.partial! "exercises/exercise_scores"
json.exercise_questions do
@ -57,7 +62,7 @@ json.exercise_questions do
shixun_challenges: question.exercise_shixun_challenges,
user_answer: question_info[:answered_content],
choices:question.exercise_choices,
exercise_type:3,
exercise_type:exercise_type,
shixun_type:question_info[:shixun_type],
ques_position: q[:ques_number],
edit_type:nil

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

@ -632,6 +632,8 @@ Rails.application.routes.draw do
post :save_banks
get :my_courses
post :send_to_course
delete :multi_delete
post :multi_public
end
end
@ -643,7 +645,23 @@ Rails.application.routes.draw do
resources :gtopic_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

@ -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() {
if ($('body.admins-shixun-settings-index-page').length > 0) {
}
});
function update_change(target) {
var s_id = $(target).attr("data-id");
var s_value = $(target).val();
var s_name = $(target).attr("name");
$(".shixun-settings-select").on("change", function () {
var s_value = $(this).val();
var s_name = $(this).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",
url: "/admins/shixun_settings",
type: "GET",
dataType:'script',
data: json,
success: function (data) {
}
data: json
})
}
});
function select_change(target) {
var s_value = $(target).val();
var s_name = $(target).attr("name");
$(".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/",
type: "GET",
url: "/admins/shixun_settings/" + s_id,
type: "PUT",
dataType:'script',
data: json,
success: function (data) {
}
data: json
})
})
}
;
});
$(document).on('turbolinks:load', function() {
$('select#tag-choosed').select2({
placeholder: "请选择分类",

@ -18726,6 +18726,13 @@ input[type="checkbox"] {
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 */
#sidebar {
min-width: 200px;

@ -38362,46 +38362,37 @@ $(document).on('turbolinks:load', function() {
;
$(document).on('turbolinks:load', function() {
if ($('body.admins-shixun-settings-index-page').length > 0) {
}
});
function update_change(target) {
var s_id = $(target).attr("data-id");
var s_value = $(target).val();
var s_name = $(target).attr("name");
$(".shixun-settings-select").on("change", function () {
var s_value = $(this).val();
var s_name = $(this).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",
url: "/admins/shixun_settings",
type: "GET",
dataType:'script',
data: json,
success: function (data) {
}
data: json
})
}
});
function select_change(target) {
var s_value = $(target).val();
var s_name = $(target).attr("name");
$(".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/",
type: "GET",
url: "/admins/shixun_settings/" + s_id,
type: "PUT",
dataType:'script',
data: json,
success: function (data) {
}
data: json
})
})
}
;
});
$(document).on('turbolinks:load', function() {
$('select#tag-choosed').select2({
placeholder: "请选择分类",

@ -18726,6 +18726,13 @@ input[type="checkbox"] {
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 */
#sidebar {
min-width: 200px;
@ -19421,6 +19428,13 @@ input[type="checkbox"] {
.select2 .select2-selection__choice {
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 */
#sidebar {
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 {
white-space: pre-wrap;
}
.markdown-body > p {
line-height: 25px;
}
/* https://www.educoder.net/courses/2346/group_homeworks/34405/question */
.renderAsHtml.markdown-body p {
white-space: inherit;

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

@ -493,7 +493,8 @@ class Fileslists extends Component{
let selectpagetype=selectpage===page?true:false
this.setState({
page:page,
checkAllValue:selectpagetype
checkAllValue:selectpagetype,
checkBoxValues:[]
})
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"}}>
<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">
{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>:""}

@ -283,6 +283,9 @@ class Boards extends Component{
console.log('checked = ', checkedValues);
}
onPageChange = (pageNumber) => {
this.setState({
checkBoxValues:[]
})
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">
<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">
{ !!isAdmin &&
<React.Fragment>

@ -3,11 +3,11 @@ import { Input, InputNumber, Form, Button, Checkbox, Upload, Icon, message, Moda
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 { WordsBtn, getUrl, ConditionToolTip } from 'educoder'
import CBreadcrumb from '../common/CBreadcrumb'
import NewWorkForm from './NewWorkForm'
const confirm = Modal.confirm;
const $ = window.$
const MAX_TITLE_LENGTH = 60;
class NewWork extends Component{
@ -17,15 +17,6 @@ class NewWork extends Component{
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,
}
}
componentDidMount () {
@ -50,7 +41,6 @@ class NewWork extends Component{
course_id: data.course_id,
course_name: data.course_name,
category: data.category,
})
}
})
@ -65,56 +55,13 @@ class NewWork extends Component{
.then((response) => {
if (response.data.name) {
const data = response.data;
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'
}
})
data.isEdit = true;
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 || '',
});
category: data.category,
course_id: data.course_id,
course_name: data.course_name,
})
this.newWorkFormRef.initValue(data);
}
})
.catch(function (error) {
@ -122,72 +69,12 @@ class NewWork extends Component{
});
}
// 输入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.isEdit) {
this.doEdit(courseId, values)
} else {
this.doNew(courseId, values)
}
} else {
$("html").animate({ scrollTop: $('html').scrollTop() - 100 })
}
})
}
doEdit = (courseId, values) => {
doEdit = (params) => {
const workId = this.props.match.params.workId
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()
axios.put(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
})
axios.put(newUrl, params)
.then((response) => {
if (response.data.status == 0) {
this.props.showNotification('保存成功')
@ -198,30 +85,11 @@ class NewWork extends Component{
console.log(error);
});
}
doNew = (courseId, values) => {
doNew = (params) => {
const courseId = this.props.match.params.coursesId ;
const newUrl = `/courses/${courseId}/homework_commons.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 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
})
axios.post(newUrl, params)
.then((response) => {
if (response.data.status == 0) {
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(){
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
category
}=this.state
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;
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(
<div className="newMain">
<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={[
{ to: current_user && current_user.first_category_url, name: this.state.course_name},
{ to: `/courses/${courseId}/${moduleEngName}/${category && category.category_id ? category.category_id : ''}`
@ -388,161 +138,16 @@ class NewWork extends Component{
</a>
</p>
<div>
{/* onSubmit={this.handleSubmit} */}
<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>
<NewWorkForm wrappedComponentRef={(ref) => {this.newWorkFormRef = ref}}
{...this.props}
onSave={this.onSave}
doNew={this.doNew}
doEdit={this.doEdit}
></NewWorkForm>
</div>
</div>
</div>
)
}
}
const WrappedBoardsNew = Form.create({ name: 'NewWork' })(NewWork);
export default WrappedBoardsNew;
export default NewWork;

@ -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)=>{
this.setState({
page:pageNumber
page:pageNumber,
checkBoxValues:[]
})
let {search,order}=this.state;
this.getList(pageNumber,search,order);
@ -430,7 +431,7 @@ class commonWork extends Component{
mainList && mainList.course_identity < 5 && mainList.homeworks.length>0 &&
<div className="mt20 edu-back-white padding20-30">
<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">
<li className="li_line">
<a href="javascript:void(0)" className="color-grey-9"

@ -150,8 +150,7 @@ class Startshixuntask extends Component{
keyboard={false}
>
<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 className="task-popup-submit clearfix">
{/*<a onClick={this.hidestartshixunCombattype} className="task-btn fl">取消</a>*/}

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

@ -293,7 +293,7 @@ class Elearning extends Component{
footer={null}
>
<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 className="task-popup-submit clearfix">
{/*<a onClick={this.hidestartshixunCombattype} className="task-btn fl">取消</a>*/}

@ -141,7 +141,7 @@ class YslDetailCards extends Component{
footer={null}
>
<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 className="task-popup-submit clearfix">
{/*<a onClick={this.hidestartshixunCombattype} className="task-btn fl">取消</a>*/}

@ -130,7 +130,8 @@ class Exercise extends Component{
//切换分页
changePage=(pageNumber)=>{
this.setState({
page:pageNumber
page:pageNumber,
checkBoxValues:[]
})
let{type,StudentList_value,limit}=this.state
this.InitList(type,StudentList_value,pageNumber,limit);
@ -522,7 +523,7 @@ class Exercise extends Component{
<Spin size="large" spinning={this.state.isSpin}>
{this.props.isAdmin()?exercises && exercises.length ===0?"":<div className="mt20 mb20 edu-back-white padding20-30">
<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">
<li className="li_line"><a className="color-grey-9" onClick={()=>this.ActionPoll("delete")}>删除</a></li>
<li className="li_line">

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

@ -85,9 +85,9 @@ class simpleAnswer extends Component{
</div>
}
{
isStudent && exercise.answer_open==true && exercise.exercise_status == 3 ?
isStudent && questionType.standard_answer ?
<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> */}
<MarkdownToHtml content={questionType.standard_answer && questionType.standard_answer[0]} selector={'simgle_standard2_' + (this.props.index + 1)}
className="answerStyle"

@ -360,7 +360,8 @@ class GraduationTasks extends Component{
let selectpagetype=selectpage===page?true:false
this.setState({
page:page,
checkAllValue:selectpagetype
checkAllValue:selectpagetype,
checkBoxValues:[]
})
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">
<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">
<li className="li_line"><a className="color-grey-9" onClick={this.onDelete}>删除</a></li>

@ -1,28 +1,19 @@
import React,{ Component } from "react";
import {
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 { Select, Modal } from 'antd';
import axios from 'axios'
import {getUrl} from 'educoder';
import "../../common/formCommon.css"
import '../style.css'
import '../../css/Courses.css'
import { WordsBtn, City } from 'educoder'
import { WordsBtn } from 'educoder'
import {Link} from 'react-router-dom'
// import City from './City'
// import './board.css'
// import { RouteHOC } from './common.js'
import GraduateTopicNewFrom from './GraduateTopicNewFrom'
const confirm = Modal.confirm;
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
class GraduateTopicNew extends Component{
@ -33,14 +24,12 @@ class GraduateTopicNew extends Component{
this.state = {
fileList: [],
boards: [],
teacherList:[],
topic_property_first:[],
topic_property_second:[],
topic_repeat:[],
topic_source:[],
topic_type:[],
attachments:undefined,
addonAfter:0,
left_banner_id:undefined,
course_name:undefined
@ -53,21 +42,11 @@ class GraduateTopicNew extends Component{
axios.get((url)).then((result)=>{
if(result.status==200){
this.setState({
teacherList:result.data.teacher_list,
left_banner_id:result.data.left_banner_id,
course_name:result.data.course_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
left_banner_name:result.data.left_banner_name
})
this.GraduateTopicNewFromRef.initNewInfo(result);
}
}).catch((error)=>{
console.log(error);
@ -87,78 +66,34 @@ class GraduateTopicNew extends Component{
//编辑,信息显示
getEditInfo=()=>{
const cid = this.props.match.params.coursesId
let topicId=this.props.match.params.topicId
let topicId=this.props.match.params.topicId;
if(topicId){
let url=`/courses/${cid}/graduation_topics/${topicId}/edit.json`;
axios.get((url)).then((result)=>{
if(result){
this.setState({
left_banner_id:result.data.left_banner_id,
course_name:result.data.course_name,
left_banner_name:result.data.left_banner_name,
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,
attachments:result.data.attachments,
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'
}
left_banner_name:result.data.left_banner_name
})
this.setState({ fileList: _fileList, cityDefaultValue: [result.data.selected_data.province,result.data.selected_data.city] })
this.GraduateTopicNewFromRef.initValue(result);
}
}).catch((error)=>{
console.log(error);
})
}
}
handleSubmit = (e) => {
e.preventDefault();
// 编辑保存
editSave = (param,attachments,topicId) =>{
const cid = this.props.match.params.coursesId
const topicId = this.props.match.params.topicId
// console.log(this.props);
this.props.form.validateFieldsAndScroll((err, values) => {
if (!err) {
console.log('Received values of form: ', values);
if (topicId !=undefined) {
const editTopic = this.editTopic
const editUrl = `/courses/${cid}/graduation_topics/${topicId}.json`
let attachment_ids = undefined
if (this.state.fileList) {
attachment_ids = this.state.fileList.map(item => {
return item.response ? item.response.id : item.id
})
let params = {
graduation_topic:param,
attachment_ids:attachments
}
axios.put(editUrl, {
graduation_topic:{
...values,
province: values.city==undefined?"":values.city[0],
city: values.city==undefined?"":values.city[1],
},
attachment_ids
}).then((response) => {
axios.put(editUrl, params).then((response) => {
if (response.status == 200) {
const { id } = response.data;
if (id) {
@ -169,23 +104,17 @@ class GraduateTopicNew extends Component{
}).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) => {
// 新建提交
newSubmit = (param,attachments,topicId) =>{
const cid = this.props.match.params.coursesId
const url = `/courses/${cid}/graduation_topics.json`
let params = {
graduation_topic:param,
attachment_ids:attachments
}
axios.post(url, params).then((response) => {
if (response.data) {
const { id } = response.data;
if (id) {
@ -193,130 +122,35 @@ class GraduateTopicNew extends Component{
this.props.history.push(`/courses/${cid}/graduation_topics/${this.state.left_banner_id}`);
}
}
})
.catch(function (error) {
}).catch(function (error) {
console.log(error);
});
}
// 取消编辑或者新建
editCancel = () =>{
const cid = this.props.match.params.coursesId;
let topicId=this.props.match.params.topicId;
if(topicId){
this.props.history.push(`/courses/${cid}/graduation_topics/${topicId}/detail`);
}else{
$("html").animate({ scrollTop: $('html').scrollTop() - 100 })
}
});
}
// 选择省市
ChangeCity=(value, selectedOptions)=>{
console.log(selectedOptions);
}
// 附件相关 START
handleChange = (info) => {
let fileList = info.fileList;
this.setState({ fileList });
}
onAttachmentRemove = (file) => {
confirm({
title: '确定要删除这个附件吗?',
okText: '确定',
cancelText: '取消',
// content: 'Some descriptions',
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,
};
});
}
this.props.history.push(`/courses/${cid}/graduation_topics/${this.state.left_banner_id}`);
}
})
.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() {
let {
fileList,
teacherList,
topic_property_first,
topic_property_second,
topic_repeat,
topic_source,
topic_type,
addonAfter,
left_banner_id,
course_name,
left_banner_name
} = this.state;
const { current_user } = this.props
const { getFieldDecorator } = this.props.form;
let{ topicId,coursesId }=this.props.match.params
// console.log(this.props);
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,
// 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!');
const common={
editSave:this.editSave,
newSubmit:this.newSubmit,
editCancel:this.editCancel
}
return isLt150M;
},
};
// console.log("dfsf");
// console.log(this.props);
return(
<div className="newMain ">
<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>
</div>
<Form {...formItemLayout} onSubmit={this.handleSubmit}>
<div className="createPage">
<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>
<GraduateTopicNewFrom
{...this.props}
{...this.state}
{...common}
wrappedComponentRef={(ref) => this.GraduateTopicNewFromRef = ref}
topicId={topicId}
teacherName={true}
></GraduateTopicNewFrom>
<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>
)
}
}
const WrappedGraduateTopicNew = Form.create({ name: 'topicPostWorksNew' })(GraduateTopicNew);
// const WrappedGraduateTopicNew = Form.create({ name: 'topicPostWorksNew' })(GraduateTopicNew);
// 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)=>{
this.setState({
page:pageNum
page:pageNum,
checkBoxValues:[]
})
let {status,searchValue}=this.state;
this.fetchAll(searchValue,pageNum,status);
@ -430,7 +431,7 @@ onBoardsNew=()=>{
// 超级管理员、教师、助教
isAdmin ?
<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">
<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 {
this.props.showNotification(`正在下载中`);
// window.open("/api"+url, '_blank');
downloadFile({
url: url,
successCallback: (url) => {
console.log('successCallback')
},
failCallback: (responseHtml, url) => {
console.log('failCallback')
}
})
window.open("/api"+url, '_blank');
// downloadFile({
// url: url,
// successCallback: (url) => {
// console.log('successCallback')
// },
// failCallback: (responseHtml, url) => {
// console.log('failCallback')
// }
// })
}
}).catch((error) => {
console.log(error)

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

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

@ -151,7 +151,8 @@ class Poll extends Component{
changePage=(pageNumber)=>{
this.setState({
page:pageNumber
page:pageNumber,
checkBoxValues:[]
})
let{type,StudentList_value}=this.state
this.InitList(type,StudentList_value,pageNumber);
@ -543,7 +544,7 @@ class Poll extends Component{
pollsList && pollsList.length > 0 && isAdmin &&
<div className="mt20 edu-back-white padding20-30">
<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">
<li className="li_line"><a className="color-grey-9" onClick={()=>this.ActionPoll("delete")}>删除</a></li>
<li className="li_line">

@ -66,12 +66,14 @@ class PollDetailTabThird extends Component{
{
pollDetail && pollDetail.questions.map((item,key)=>{
console.log("ddd");
console.log(item.question.min_choices);
return(
<div className="previewList">
<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>
{ 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">
{
item.question.min_choices == item.question.max_choices ? "可选"+item.question.max_choices+"项" :

@ -54,7 +54,7 @@ class PollListItem extends Component{
}
</p>
<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 &&
<span className="fl mt3">

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

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

@ -218,8 +218,7 @@ class ShixunhomeWorkItem extends Component{
footer={null}
>
<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 className="task-popup-submit clearfix">
{/*<a onClick={this.hidestartshixunCombattype} className="task-btn fl">取消</a>*/}

@ -559,7 +559,8 @@ class ShixunHomework extends Component{
let {Coursename,order}=this.state;
this.setState({
page:pageNumber
page:pageNumber,
checkBoxValues:[]
})
this.homeworkupdatalist(Coursename,pageNumber,order);
@ -1070,7 +1071,7 @@ class ShixunHomework extends Component{
<div className="mt20 edu-back-white padding20-30">
<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">
<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>

@ -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}
>
<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 className="task-popup-submit clearfix">
{/*<a onClick={this.hidestartshixunCombattype} className="task-btn fl">取消</a>*/}

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

@ -731,8 +731,7 @@ class TPMBanner extends Component {
footer={null}
>
<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 className="task-popup-submit clearfix">
{/*<a onClick={this.hidestartshixunCombattype} className="task-btn fl">取消</a>*/}

@ -587,7 +587,7 @@ class Challenges extends Component {
footer={null}
>
<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 className="task-popup-submit clearfix">
{/*<a onClick={this.hidestartshixunCombattype} className="task-btn fl">取消</a>*/}

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

@ -27,6 +27,9 @@ class InfosBanner extends Component{
let {pathname}=this.props.location;
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(
<div className="bannerPanel mb60">
<div className="educontent">
@ -115,6 +118,13 @@ class InfosBanner extends Component{
to={`/users/${username}/videos`}>视频</Link>
</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>

@ -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;
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