Merge branch 'topic_bank' of https://bdgit.educoder.net/Hjqreturn/educoder into topic_bank

dev_aliyun_beta
caicai8 6 years ago
commit a75fa2ec54

@ -1,21 +1,20 @@
$(document).on('turbolinks:load', function() {
if ($('body.admins-library-applies-index-page').length > 0) {
var $searchFrom = $('.library-applies-list-form');
$searchFrom.find('select[name="status"]').val('pending');
$searchFrom.on('click', '.search-form-tab', function(){
var $link = $(this);
if ($('body.admins-library-applies-index-page').length > 0) {
var $searchFrom = $('.library-applies-list-form');
$searchFrom.find('select[name="status"]').val('pending');
$searchFrom.find('input[name="keyword"]').val('');
$searchFrom.find('select[name="status"]').val('processed');
$searchFrom.on('click', '.search-form-tab', function(){
var $link = $(this);
if($link.data('value') === 'processed'){
$searchFrom.find('.status-filter').show();
} else {
$searchFrom.find('.status-filter').hide();
$searchFrom.find('select[name="status"]').val('pending');
}
});
$searchFrom.find('input[name="keyword"]').val('');
$searchFrom.find('select[name="status"]').val('processed');
}
if($link.data('value') === 'processed'){
$searchFrom.find('.status-filter').show();
} else {
$searchFrom.find('.status-filter').hide();
$searchFrom.find('select[name="status"]').val('pending');
}
});
}
})

@ -1,6 +1,6 @@
$(document).on('turbolinks:load', function() {
if ($('body.admins-shixun-settings-index-page').length > 0) {
$(".shixun-settings-select").on("change", function () {
$(".shixun-settings-list-container").on("change", '.shixun-settings-select', function () {
var s_value = $(this).val();
var s_name = $(this).attr("name");
var json = {};
@ -13,7 +13,7 @@ $(document).on('turbolinks:load', function() {
})
});
$(".shixun-setting-form").on("change",function () {
$(".shixun-settings-list-container").on("change", '.shixun-setting-form', function () {
var s_id = $(this).attr("data-id");
var s_value = $(this).val();
var s_name = $(this).attr("name");

@ -1,6 +1,8 @@
$(document).on('turbolinks:load', function() {
if($('body.admins-shixuns-index-page').length > 0){
$('select#tag-choosed').select2({
placeholder: "请选择分类",
allowClear: true
placeholder: "请选择分类",
allowClear: true
});
}
});

@ -0,0 +1,21 @@
//= require rails-ujs
//= require turbolinks
//= require jquery3
//= require popper
//= require bootstrap-sprockets
//= require echarts
//= require_tree ./colleges
Turbolinks.setProgressBarDelay(200);
$(document).on('turbolinks:load', function() {
$('[data-toggle="tooltip"]').tooltip();
$('[data-toggle="popover"]').popover();
})
$(document).on("turbolinks:before-cache", function () {
$('[data-toggle="tooltip"]').tooltip('hide');
$('[data-toggle="popover"]').popover('hide');
});

@ -0,0 +1,156 @@
$(document).on('turbolinks:load', function() {
if($('body.colleges-statistics-page').length > 0) {
var $statisticBody = $('.statistics-body');
var $statisticBase = $('.statistic-base');
var schoolId = $statisticBody.data('id');
var $statisticCourse = $statisticBody.find('.statistic-course')
var $shixunChart = $statisticBody.find('.shixun-chart');
$.get('/colleges/' + schoolId + '/shixun_time', function(data){
$statisticBase.find('.shixun-time').html("<span>" + data.shixun_time + "</span>天");
});
$.get('/colleges/' + schoolId + '/shixun_report_count', function(data){
$statisticBase.find('.shixun-report-count').html("<span>" + data.shixun_report_count + "</span>个");
});
$.ajax({ url: '/colleges/' + schoolId + '/course_statistics', method: 'GET', dataType: 'script' });
$.ajax({ url: '/colleges/' + schoolId + '/teachers', method: 'GET', dataType: 'script' });
var initShixunChart = function(names, data){
var shixunChart = echarts.init(document.getElementById('shixun-chart'));
var options = {
series : [
{
name: '访问来源',
type: 'pie',
radius: '55%',
data: data
}
]
};
shixunChart.setOption(options);
};
$.get('/colleges/' + schoolId + '/shixun_chart_data', function(data){
$statisticBody.find('.shixun-chart-loading').hide();
if (data.data.length > 0) {
$shixunChart.css('height', '400px').css('width', '100%');
initShixunChart(data.names, data.data);
} else {
$statisticBody.find('.shixun-chart-empty').show();
}
});
$.ajax({ url: '/colleges/' + schoolId + '/student_shixun', method: 'GET', dataType: 'script' });
var initHotEvaluating = function(names, values){
var Color = ['#962e66', '#623363', '#CCCCCC', '#9A9A9A', '#FF8080', '#FF80C2', '#B980FF', '#80B9FF', '#6FE9FF', '#4DE8B4', '#F8EF63', '#FFB967'];
var option = {
backgroundColor: '#fff',
grid: {
left: '3%',
right: '4%',
bottom: '10%',
containLabel: true
},
tooltip: {
show: "true",
trigger: 'item',
formatter: '{c0}',
backgroundColor: 'rgba(0,0,0,0.7)', // 背景
padding: [8, 10], //内边距
extraCssText: 'box-shadow: 0 0 3px rgba(255, 255, 255, 0.4);', //添加阴影
axisPointer: { // 坐标轴指示器,坐标轴触发有效
type: 'shadow' // 默认为直线,可选为:'line' | 'shadow'
}
},
xAxis: {
type: 'value',
axisTick: {
show: false
},
axisLine: {
show: true,
lineStyle: {
color: '#CCCCCC'
}
},
splitLine: {
show: false,
lineStyle: {
color: '#CCCCCC'
}
},
axisLabel: {
textStyle: {
color: '#656565',
fontWeight: 'normal',
fontSize: '12'
},
formatter: '{value}'
}
},
yAxis: {
type: 'category',
axisLine: {
lineStyle: {
color: '#cccccc'
}
},
splitLine: {
show: false
},
axisTick: {
show: false
},
splitArea: {
show: false
},
axisLabel: {
inside: false,
textStyle: {
color: '#656565',
fontWeight: 'normal',
fontSize: '12'
}
},
data: names
},
series: [{
name: '',
type: 'bar',
itemStyle: {
normal: {
show: true,
color: function(params) {
return Color[params.dataIndex]
},
barBorderRadius: 50,
borderWidth: 0,
borderColor: '#333'
}
},
barGap: '0%',
barCategoryGap: '50%',
data: values
}
]
};
var myChart = echarts.init(document.getElementById('hot-chart'));
myChart.setOption(option);
}
$.get('/colleges/' + schoolId + '/student_hot_evaluations', function(data){
$statisticBody.find('.hot-chart-loading').hide();
if (data.names.length > 0) {
$statisticBody.find('.hot-chart').css('height', '400px').css('width', '100%');
initHotEvaluating(data.names.reverse(), data.values.reverse());
} else {
$statisticBody.find('.hot-chart-empty').show();
}
})
}
});

@ -7,6 +7,7 @@
@import "bootstrap-datepicker.standalone";
@import "lib/codemirror";
@import "common";
@import "admins/*";
body {
@ -20,20 +21,6 @@ body {
background: #efefef;
}
a {
&:hover {
text-decoration: unset;
}
}
textarea.danger, input.danger {
border-color: #dc3545!important;
}
label.error {
color: #dc3545!important;
}
.simple_form {
.form-group {
.collection_radio_buttons {
@ -50,9 +37,6 @@ input.form-control {
font-size: 14px;
}
.flex-1 {
flex: 1;
}
.btn-default{
color: #666;
background: #e1e1e1!important;
@ -62,8 +46,3 @@ input.form-control {
position: absolute;
}
.position-r{position:relative;}
.font-12 { font-size: 12px !important; }
.font-14 { font-size: 14px !important; }
.font-16 { font-size: 16px !important; }
.font-18 { font-size: 18px !important; }

@ -0,0 +1,13 @@
@import "bootstrap";
@import "font-awesome-sprockets";
@import "font-awesome";
@import "common";
@import "colleges/*";
.navbar-dark .navbar-nav .nav-link {
color: rgba(255, 255, 255, 1);
font-size: 16px;
}

@ -0,0 +1,135 @@
.colleges-statistics-page {
.college-body-container {
.statistic-header {
width: 100%;
height: 240px;
background-image: url('/images/educoder/statistics.jpg');
background-size: 100% 100%;
&-container {
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
}
&-title {
flex: 1;
display: flex;
align-items: center;
color: #4CACFF;
font-size: 32px;
}
&-content {
width: 100%;
display: flex;
justify-content: space-around;
}
&-item {
margin-bottom: 22px;
display: flex;
flex-direction: column;
align-items: center;
color: #fff;
&-label {
color: #989898;
}
&-content {
font-size: 24px;
}
}
}
.statistic-box {
border: unset;
box-shadow: 0px 0px 9px rgba(174, 175, 177, 0.2);
}
.statistic-base {
&-title {
padding: 2rem 1.25rem;
background: #fff;
border-bottom: unset;
}
&-table {
margin: 0;
padding: 0;
}
&-item {
padding: 0;
&-label {
text-align: center;
font-size: 16px;
height: 48px;
line-height: 48px;
color: #686868;
background: #F5F5F5;
border-top: 1px solid #EBEBEB;
border-bottom: 1px solid #EBEBEB;
}
&-content {
height: 100px;
font-size: 16px;
text-align: center;
line-height: 100px;
span {
margin-right: 5px;
font-size: 24px;
}
}
}
}
.statistic-container {
padding: 0;
background: #fff;
border-radius: 3px;
box-shadow: 0px 0px 9px rgba(174, 175, 177, 0.2);
.statistic-label {
padding: 2rem 1.25rem;
font-size: 1.5rem;
}
.statistic-table {
overflow-x: scroll;
table.course-table { min-width: 1100px; }
table.teacher-rank-table { min-width: 640px; }
}
table th {
background: #F5F5F5;
border-color: #EBEBEB;
}
&.statistic-course {
min-height: 400px;
}
&.statistic-teacher-rank, &.statistic-student-rank {
min-height: 500px;
}
}
.statistic-chart {
padding: 0 20px;
height: 400px;
.shixun-chart-loading, .shixun-chart-empty, .hot-chart-loading, .hot-chart-empty {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
}
}
}

@ -0,0 +1,31 @@
body {
font-size: 14px;
background: #efefef;
}
a {
&:hover {
text-decoration: unset;
}
}
textarea.danger, input.danger {
border-color: #dc3545!important;
}
label.error {
color: #dc3545!important;
}
input.form-control {
font-size: 14px;
}
.flex-1 {
flex: 1;
}
.font-12 { font-size: 12px !important; }
.font-14 { font-size: 14px !important; }
.font-16 { font-size: 16px !important; }
.font-18 { font-size: 18px !important; }

@ -0,0 +1,171 @@
class CollegesController < ApplicationController
include Admins::PaginateHelper
layout 'college'
before_action :require_login
before_action :check_college_present!
before_action :check_manage_permission!
helper_method :current_school, :current_college
def statistics
# 教师、学生总数
count_statistic = UserExtension.where(school_id: current_school.id)
.select('SUM(IF(identity=0, 1, 0)) AS teachers_count, SUM(IF(identity=1, 1, 0)) AS students_count').first
@teachers_count = count_statistic['teachers_count']
@students_count = count_statistic['students_count']
# 课堂总数
@courses_count = Course.where(school_id: current_school.id, is_delete: 0).where.not(id: 1309).count
# 实训总数
@shixuns_count = Shixun.visible.joins('left join user_extensions on user_extensions.user_id = shixuns.user_id')
.where(user_extensions: { school_id: current_school.id }).count
end
def shixun_time
time_sum = Game.joins('left join user_extensions on user_extensions.user_id = games.user_id')
.where(user_extensions: { school_id: current_school.id }).sum(:cost_time)
shixun_time_sum = (time_sum / (24 * 60 * 60.0)).ceil
render json: { shixun_time: shixun_time_sum }
end
def shixun_report_count
shixun_report_count = StudentWork.where(work_status: [1, 2]).where('myshixun_id != 0')
.joins('left join user_extensions on user_extensions.user_id = student_works.user_id')
.where(user_extensions: { school_id: current_school.id }).count
render json: { shixun_report_count: shixun_report_count }
end
def teachers
@teachers = User.find_by_sql("SELECT users.id, users.login, users.lastname, users.firstname, users.nickname, IFNULL((SELECT count(shixuns.id) FROM shixuns where shixuns.user_id =users.id group by shixuns.user_id), 0) AS publish_shixun_count,
(SELECT count(c.id) FROM courses c, course_members m WHERE c.id != 1309 and m.course_id = c.id AND m.role in (1,2,3) and c.school_id = #{current_school.id} AND m.user_id=users.id AND c.is_delete = 0) as course_count
FROM `users`, user_extensions ue where users.id=ue.user_id and ue.identity=0 and ue.school_id=#{current_school.id} ORDER BY publish_shixun_count desc, course_count desc, id desc LIMIT 10")
# ).order("publish_shixun_count desc, experience desc").limit(10)
@teachers =
@teachers.map do |teacher|
course_ids = Course.find_by_sql("SELECT c.id FROM courses c, course_members m WHERE c.id != 1309 and m.course_id = c.id AND m.role in (1,2,3) AND m.user_id=#{teacher.id} AND c.is_delete = 0 and c.school_id = #{current_school.id}")
course_count = course_ids.size
homeworks = HomeworkCommon.where(:homework_type => 4, :course_id => course_ids.map(&:id))
un_shixun_work_count = homeworks.where("publish_time > '#{Time.now}' or publish_time is null").count
shixun_work_count = homeworks.size - un_shixun_work_count
student_count = StudentsForCourse.where(:course_id => course_ids.map(&:id)).count
myshixun_ids = StudentWork.select("myshixun_id").where("homework_common_id in (#{homeworks.map(&:id).join(',').strip == "" ? -1 : homeworks.map(&:id).join(',')}) and myshixun_id is not null")
complete_myshixun = Myshixun.select("id").where(:status => 1, :id => myshixun_ids.map(&:myshixun_id)).size
all_myshixun = Myshixun.select("id").where(:id => myshixun_ids.map(&:myshixun_id)).size
complete_rate = all_myshixun == 0 ? 0 : ((complete_myshixun * 100) / all_myshixun).try(:round, 2).to_f
real_name = teacher.show_real_name
teacher = teacher.attributes.dup.merge({
real_name: real_name,
course_count: course_count,
shixun_work_count: shixun_work_count,
un_shixun_work_count: un_shixun_work_count,
student_count: student_count,
complete_rate: complete_rate
}).to_json
JSON.parse(teacher)
end
end
def shixun_chart_data
shixun_ids = HomeworkCommonsShixun.joins(homework_common: :course).where(courses: {school_id: current_school.id, is_delete: 0}).where('courses.id != 1309').pluck('distinct shixun_id')
shixun_count_map = ShixunTagRepertoire.joins(:tag_repertoire).where(shixun_id: shixun_ids).group('tag_repertoires.name').order('count_shixun_id desc').count(:shixun_id)
names = []
data = []
shixun_count_map.each do |name, count|
break if names.size == 9
names << name
data << { value: count, name: name }
end
if shixun_count_map.keys.size > 9
other_count = shixun_count_map.values[9..-1].reduce(:+)
names << 'Others'
data << { name: 'Others', value: other_count }
end
render json: { names: names, data: data }
end
# 在线课堂
def course_statistics
courses = Course.where(school_id: current_school.id, is_delete: 0).where.not(id: 1309)
courses = courses.left_joins(practice_homeworks: { student_works: { myshixun: :games } })
.select('courses.id, courses.name, courses.is_end, sum(games.evaluate_count) evaluating_count')
.group('courses.id').order('is_end asc, evaluating_count desc')
params[:per_page] = 8
@courses = paginate courses
course_ids = @courses.map(&:id)
@student_count = StudentsForCourse.where(course_id: course_ids).group(:course_id).count
@shixun_work_count = HomeworkCommon.where(homework_type: 4, course_id: course_ids).group(:course_id).count
@attachment_count = Attachment.where(container_id: course_ids, container_type: 'Course').group(:container_id).count
@message_count = Message.joins(:board).where(boards: { parent_id: 0, course_id: course_ids }).group('boards.course_id').count
@active_time = CourseActivity.where(course_id: course_ids).group(:course_id).maximum(:created_at)
@exercise_count = Exercise.where(course_id: course_ids).group(:course_id).count
@poll_count = Poll.where(course_id: course_ids).group(:course_id).count
@other_work_count = HomeworkCommon.where(homework_type: [1,3], course_id: course_ids).group(:course_id).count
end
# 学生实训
def student_shixun
@students = User.joins(:user_extension).where(user_extensions: { school_id: current_school.id, identity: 1 }).includes(:user_extension).order('experience desc').limit(10)
student_ids = @students.map(&:id)
@shixun_count = Myshixun.where(user_id: student_ids).group(:user_id).count
@study_shixun_count = Myshixun.where(user_id: student_ids, status: 0).group(:user_id).count
end
def student_hot_evaluations
games = Game.joins(:myshixun).joins('join shixun_tag_repertoires str on str.shixun_id = myshixuns.shixun_id')
games = games.joins('join tag_repertoires tr on tr.id = str.tag_repertoire_id')
games = games.joins("join user_extensions ue on ue.user_id = myshixuns.user_id and ue.school_id = #{current_school.id}")
evaluate_count_map = games.group('tr.name').reorder('sum_games_evaluate_count desc').limit(10).sum('games.evaluate_count')
render json: { names: evaluate_count_map.keys, values: evaluate_count_map.values }
end
private
def require_login
return if User.current.logged?
redirect_to "/login?back_url=#{CGI::escape(request.fullpath)}"
end
def check_college_present!
return if current_college.present?
redirect_to '/404'
end
def check_manage_permission!
return if can_manage_college?
redirect_to '/403'
end
def can_manage_college?
return true if current_user.admin_or_business? # 超级管理员|运营
return true if current_college.is_a?(Department) && current_college.member?(current_user) # 部门管理员
return true if current_user.is_teacher? && current_user.school_id == current_school.id # 学校老师
return true if current_school.customer_id && current_user.partner&.partner_customers&.exists?(customer_id: current_school.customer_id)
false
end
def current_school
current_college.is_a?(School) ? current_college : current_college.school
end
def current_college
@_current_college ||= begin
Department.find_by(identifier: params[:id]) || School.find_by(id: params[:id])
end
end
end

@ -10,7 +10,6 @@ module GitCommon
# ------------------------
# 版本库目录结构
def repository
logger.info("ssssssseeeeeeee#{params}")
begin
@repo_url = repo_url @repo_path
@trees = GitService.file_tree(repo_path: @repo_path, path: @path)
@ -44,4 +43,16 @@ module GitCommon
end
end
# 为版本库添加文件
def add_file
@path, message, content = params[:path].strip, params[:message], params[:content]
author_name, author_email = current_user.real_name, current_user.current_user.git_mail
@content = GitService.update_file(repo_path: @repo_path,
file_path: path,
message: message,
content: content,
author_name: author_name,
author_email: author_email)
end
end

@ -1085,11 +1085,15 @@ class CoursesController < ApplicationController
# 导出课堂信息
def export_couser_info
set_export_cookies
course_info_to_xlsx @course
filename_ = "#{current_user.real_name}_#{@course.name}_课堂信息_#{Time.now.strftime('%Y%m%d_%H%M%S')}"
render xlsx: "#{format_sheet_name filename_.strip}",template: "courses/export_course_info.xlsx.axlsx",
locals: {course_info: @course_info}
if params[:export].present? && params[:export]
normal_status(0,"正在下载中")
else
set_export_cookies
course_info_to_xlsx @course
filename_ = "#{current_user.real_name}_#{@course.name}_课堂信息_#{Time.now.strftime('%Y%m%d_%H%M%S')}"
render xlsx: "#{format_sheet_name filename_.strip}",template: "courses/export_course_info.xlsx.axlsx",
locals: {course_info: @course_info}
end
end
# 导出活跃度

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

@ -8,44 +8,18 @@ class ExerciseBanksController < ApplicationController
def show
@exercise_questions = @bank.exercise_bank_questions&.includes(:exercise_bank_choices, :exercise_bank_shixun_challenges,
:exercise_bank_standard_answers).order("question_number ASC")
@exercise_ques_count = @exercise_questions.size # 全部的题目数
@exercise_ques_scores = @exercise_questions.pluck(:question_score).sum
#单选题的数量及分数
exercise_single_ques = @exercise_questions.find_by_custom("question_type", Exercise::SINGLE)
@exercise_single_ques_count = exercise_single_ques.size
@exercise_single_ques_scores = exercise_single_ques.pluck(:question_score).sum
#多选题的数量及分数
exercise_double_ques = @exercise_questions.find_by_custom("question_type", Exercise::MULTIPLE)
@exercise_double_ques_count = exercise_double_ques.size
@exercise_double_ques_scores = exercise_double_ques.pluck(:question_score).sum
# 判断题数量及分数
exercise_ques_judge = @exercise_questions.find_by_custom("question_type", Exercise::JUDGMENT)
@exercise_ques_judge_count = exercise_ques_judge.size
@exercise_ques_judge_scores = exercise_ques_judge.pluck(:question_score).sum
#填空题数量及分数
exercise_ques_null = @exercise_questions.find_by_custom("question_type", Exercise::COMPLETION)
@exercise_ques_null_count = exercise_ques_null.size
@exercise_ques_null_scores = exercise_ques_null.pluck(:question_score).sum
#简答题数量及分数
exercise_ques_main = @exercise_questions.find_by_custom("question_type", Exercise::SUBJECTIVE)
@exercise_ques_main_count = exercise_ques_main.size
@exercise_ques_main_scores = exercise_ques_main.pluck(:question_score).sum
#实训题数量及分数
exercise_ques_shixun = @exercise_questions.find_by_custom("question_type", Exercise::PRACTICAL)
@exercise_ques_shixun_count = exercise_ques_shixun.size
@exercise_ques_shixun_scores = exercise_ques_shixun.pluck(:question_score).sum
if @bank.container_type == "Exercise"
get_exercise_question_count
else
get_poll_question_count
end
end
def update
tip_exception("试卷标题不能为空!") if params[:exercise_name].blank?
tip_exception("标题不能为空!") if params[:exercise_name].blank?
@bank.update_attributes!(name: params[:exercise_name], description: params[:exercise_description])
normal_status(0,"试卷更新成功")
normal_status(0,"更新成功")
end
def choose_shixun
@ -84,11 +58,12 @@ class ExerciseBanksController < ApplicationController
def find_bank
@bank = ExerciseBank.find_by!(id: params[:id])
tip_exception(403, "无权限") unless (current_user.certification_teacher? && (@bank.is_public || @bank.user_id == current_user.id)) || current_user.admin?
tip_exception(403, "无权限") unless @bank.user_id == current_user.id || current_user.admin? ||
(current_user.certification_teacher? && @bank.is_public)
end
def bank_admin
tip_exception(403, "无权限") unless (current_user.certification_teacher? && @bank.user_id == current_user.id) || current_user.admin?
tip_exception(403, "无权限") unless @bank.user_id == current_user.id || current_user.admin?
end
#判断实训是否已选择
@ -103,4 +78,46 @@ class ExerciseBanksController < ApplicationController
end
end
def get_exercise_question_count
@exercise_ques_count = @exercise_questions.size # 全部的题目数
@exercise_ques_scores = @exercise_questions.pluck(:question_score).sum
#单选题的数量及分数
exercise_single_ques = @exercise_questions.find_by_custom("question_type", Exercise::SINGLE)
@exercise_single_ques_count = exercise_single_ques.size
@exercise_single_ques_scores = exercise_single_ques.pluck(:question_score).sum
#多选题的数量及分数
exercise_double_ques = @exercise_questions.find_by_custom("question_type", Exercise::MULTIPLE)
@exercise_double_ques_count = exercise_double_ques.size
@exercise_double_ques_scores = exercise_double_ques.pluck(:question_score).sum
# 判断题数量及分数
exercise_ques_judge = @exercise_questions.find_by_custom("question_type", Exercise::JUDGMENT)
@exercise_ques_judge_count = exercise_ques_judge.size
@exercise_ques_judge_scores = exercise_ques_judge.pluck(:question_score).sum
#填空题数量及分数
exercise_ques_null = @exercise_questions.find_by_custom("question_type", Exercise::COMPLETION)
@exercise_ques_null_count = exercise_ques_null.size
@exercise_ques_null_scores = exercise_ques_null.pluck(:question_score).sum
#简答题数量及分数
exercise_ques_main = @exercise_questions.find_by_custom("question_type", Exercise::SUBJECTIVE)
@exercise_ques_main_count = exercise_ques_main.size
@exercise_ques_main_scores = exercise_ques_main.pluck(:question_score).sum
#实训题数量及分数
exercise_ques_shixun = @exercise_questions.find_by_custom("question_type", Exercise::PRACTICAL)
@exercise_ques_shixun_count = exercise_ques_shixun.size
@exercise_ques_shixun_scores = exercise_ques_shixun.pluck(:question_score).sum
end
def get_poll_question_count
@poll_questions_count = @exercise_questions&.size # 全部的题目数
@poll_question_singles = @exercise_questions.find_by_custom("question_type", 1).size # 单选题
@poll_question_doubles = @exercise_questions.find_by_custom("question_type", 2).size # 多选题
@poll_question_mains = @exercise_questions.find_by_custom("question_type", 3).size #主观题
end
end

@ -255,8 +255,8 @@ class ExerciseQuestionsController < ApplicationController
end
elsif @exercise_question.question_type == Exercise::COMPLETION #填空题
old_ex_answer = @exercise_question.exercise_standard_answers #当前问题的全部标准答案
old_ex_answer_choice_texts = old_ex_answer.pluck(:answer_text).uniq.sort
new_ex_answer_choice_texts = standard_answer.pluck(:answer_text).sum.uniq.sort
old_ex_answer_choice_texts = old_ex_answer.pluck(:answer_text).sort
new_ex_answer_choice_texts = standard_answer.pluck(:answer_text).sum.sort
if old_ex_answer_choice_texts != new_ex_answer_choice_texts #填空题标准答案有更改时,才会更新标准答案
new_ex_answer_choice_ids = standard_answer.map {|a| a[:choice_id]}.uniq #新传入的答案数组序号
old_ex_answer_choice_ids = old_ex_answer.pluck(:exercise_choice_id).uniq #全部的答案数组序号
@ -280,11 +280,12 @@ class ExerciseQuestionsController < ApplicationController
if null_choice_text_count >= ex_answer_pre_count
new_add_choice = null_choice_text_count_array - ex_answer_pre_count_array
ex_answer_pre_count_array.each do |n|
standard_option = {
:exercise_question_id => @exercise_question.id,
:exercise_choice_id => null_choice_id,
:answer_text => null_choice_text[n-1]
@hash_symbol_null_ = {
:exercise_question_id => @exercise_question.id,
:exercise_choice_id => null_choice_id,
:answer_text => null_choice_text[n - 1]
}
standard_option = @hash_symbol_null_
ex_answer_pre[n-1].update(standard_option)
end
if new_add_choice.count > 0 #表示有新增的
@ -680,8 +681,9 @@ class ExerciseQuestionsController < ApplicationController
normal_status(-1,"已发布/已截止,不允许增删答案!")
elsif standard_answer.present?
if @exercise_question.question_type == Exercise::COMPLETION
exercise_answers_text = standard_answer.map{|a| a[:answer_text]}.sum.uniq
unless (standard_answer.count == exercise_choice_ids.count) && (standard_answers_text.count == exercise_answers_text.count)
# exercise_answers_text = standard_answer.map{|a| a[:answer_text]}.sum.uniq
# unless (standard_answer.count == exercise_choice_ids.count) && (standard_answers_text.count == exercise_answers_text.count)
unless standard_answer.count == exercise_choice_ids.count
normal_status(-1,"已发布/已截止,不允许增删标准答案!")
end
elsif @exercise_question.question_type == Exercise::SUBJECTIVE

@ -392,59 +392,6 @@ class GamesController < ApplicationController
end
end
# # 文件更新;数据评测记录
# # 生成重新评测认证码
# # content_modified:0 表示文件没有更新content_modified:1 表示文件有更新
# def file_update
# path = params[:path].strip unless params[:path].blank?
# myshixun = @game.myshixun
# rev = params[:rev] ? params[:rev] : "master"
# @content_modified = 0
# # params[:evaluate] 实训评测时更新必须给的参数,需要依据该参数做性能统计,其它类型的更新可以跳过
# # 自动保存的时候evaluate为0点评测的时候为1
# if params[:evaluate] == 1
# record = EvaluateRecord.create!(:user_id => current_user.id, :shixun_id => myshixun.shixun_id, :game_id => @game.id)
# uid_logger("-- game is #{@game.id}, record id is #{record.id}, time is **** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}")
# student_work_time = format("%.3f", (Time.now.to_f - record.created_at.to_f)).to_f
# record.update_attributes!(:student_work => student_work_time)
# end
# # 远程版本库文件内容
# last_content = GitService.file_content(repo_path: @repo_path, path: path)["content"]
# last_content = tran_base64_decode64(last_content)
#
# content = if @myshixun.mirror_name.select{|a| a.include?("MachineLearning") || a.include?("Python")}.present? && params[:content].present?
# params[:content].gsub(/\t/, ' ')
# else
# params[:content]
# end
# if content != last_content
# @content_modified = 1
# code_file = @g.edit_file(myshixun.gpid, current_user.login, :content => content, :file_path => path,
# :branch_name => rev, :commit_message => params[:evaluate] == 0 ? "auto commit" : "task commit")
# uid_logger("-- file update #{code_file}")
# # REDO更新失败的处理
# raise("文件更新失败") unless code_file
# end
#
# if record.present?
# consume_time = format("%.3f", (Time.now.to_f - record.created_at.to_f)).to_f
# record.update_attributes!(:file_update => consume_time)
# end
#
# # status为2说明是重新评测
# if @game.status == 2
# code = CODES.sample(8).join
# @resubmit = "#{code}_#{@myshixun.id}"
# end
#
# if content != last_content && code_file.blank?
# raise("实训平台繁忙繁忙等级81请稍后刷新并重试")
# end
# rescue Exception => e
# uid_logger("-- file update failed #{e.message}")
# raise Educoder::TipException.new("#{e.message}")
# end
# 恢复初始代码
# 注意path为当前打开文件的path
def reset_original_code

@ -23,11 +23,12 @@ class GtopicBanksController < ApplicationController
def find_bank
@bank = GtopicBank.find_by!(id: params[:id])
tip_exception(403, "无权限") unless (current_user.certification_teacher? && (@bank.is_public || @bank.user_id == current_user.id)) || current_user.admin?
tip_exception(403, "无权限") unless @bank.user_id == current_user.id || current_user.admin? ||
(current_user.certification_teacher? && @bank.is_public)
end
def bank_admin
tip_exception(403, "无权限") unless (current_user.certification_teacher? && @bank.user_id == current_user.id) || current_user.admin?
tip_exception(403, "无权限") unless @bank.user_id == current_user.id || current_user.admin?
end
def gtopic_bank_params

@ -39,11 +39,12 @@ class HomeworkBanksController < ApplicationController
def find_bank
@bank = HomeworkBank.find_by!(id: params[:id])
tip_exception(403, "无权限") unless (current_user.certification_teacher? && (@bank.is_public || @bank.user_id == current_user.id)) || current_user.admin?
tip_exception(403, "无权限") unless @bank.user_id == current_user.id || current_user.admin? ||
(current_user.certification_teacher? && @bank.is_public)
end
def bank_admin
tip_exception(403, "无权限") unless (current_user.certification_teacher? && @bank.user_id == current_user.id) || current_user.admin?
tip_exception(403, "无权限") unless @bank.user_id == current_user.id || current_user.admin?
end
def bank_params

@ -0,0 +1,157 @@
class PollBankQuestionsController < ApplicationController
before_action :require_login, :check_auth #用户需登陆
before_action :get_poll, only:[:create] #获取试卷
before_action :get_poll_question, except: [:create] #获取试卷的问题及试卷
before_action :bank_admin #是否为老师
before_action :validates_params, only: [:create, :update] #传入参数的验证
def create
ActiveRecord::Base.transaction do
begin
poll_options = {
:question_title => params[:question_title],
:question_type => params[:question_type],
:is_necessary => params[:is_necessary].to_i,
:question_number => @poll.exercise_bank_questions.count + 1,
:max_choices => params[:max_choices] || nil,
:min_choices => params[:min_choices] || nil
}
@poll_question = @poll.exercise_bank_questions.new(poll_options)
if params[:insert_id].present? #插入问题时那么从插入的这个id以后的question_num都将要+1
insert_poll = @poll.exercise_bank_questions.find_by(id: params[:insert_id])
if insert_poll.present? #如果该问题存在的话,意思是如果是第一题,那么就不存在插入
ques_num = insert_poll.question_number.to_i
@poll_question.question_number = ques_num + 1 #更新了问题的位置
@poll.exercise_bank_questions.insert_question_ex(ques_num).update_all("question_number = question_number + 1")
end
end
if @poll_question.save!
if params[:question_type] != 3
p_answer = params[:question_answers]
p_other_answer = params[:question_other_answer]
# 新增选择题答案选择的选项
(1..p_answer.count).each do |i|
answer = p_answer[i-1] # 传入的答案的内容
question_option = {
:choice_position => i,
:choice_text => answer
}
poll_answers = @poll_question.exercise_bank_choices.new question_option
poll_answers.save
end
# 新增答案的其他选项
if p_other_answer
question_option = {
:choice_position => p_answer.count + 1,
:choice_text => ''
}
poll_answers = @poll_question.exercise_bank_choices.new question_option
poll_answers.save
end
end
end
normal_status("创建成功")
rescue Exception => e
uid_logger_error(e.message)
tip_exception("问卷的问题创建失败!")
raise ActiveRecord::Rollback
end
end
end
def update
ActiveRecord::Base.transaction do
begin
if @poll_question.question_type < 3 #当为单选题或多选题时
p_answer = params[:question_answers]
p_other_answer = params[:question_other_answer]
p_answer_count = p_answer.count
@poll_question.exercise_bank_choices.each do |an|
if (p_answer_count < @poll_current_answers) && (p_answer_count..@poll_current_answers).to_a.include?(an.choice_position)
an.destroy
end
end
(1..p_answer_count).each do |i|
answer = @poll_question.exercise_bank_choices.find_by_custom("choice_position",i).first
if answer # 判断该位置的answer是否存在存在则更新.不存在则跳到下一步
answer.choice_text = p_answer[i-1]
answer.choice_position = i
answer.save
else
answer_options = {
:choice_position => i,
:choice_text => p_answer[i-1]
}
@poll_question.exercise_bank_choices.new answer_options
end
end
if p_other_answer #判断答案的其他选项是否存在
other_answer = @poll_question.exercise_bank_choices.find_by_custom("choice_text","").first
if other_answer.blank?
question_option = {
:choice_position => p_answer_count + 1,
:choice_text => ''
}
@poll_question.exercise_bank_choices.new question_option
else
other_answer.choice_position = p_answer_count + 1
other_answer.save
end
end
end
@poll_question.update_attributes(poll_questions_params)
normal_status("问卷更新成功")
rescue Exception => e
uid_logger_error(e.message)
tip_exception("更新失败")
raise ActiveRecord::Rollback
end
end
end
private
def bank_admin
tip_exception(403, "无权限") unless @bank.user_id == current_user.id || current_user.admin?
end
def get_poll
@poll = ExerciseBank.find_by!(id: params[:exercise_bank_id])
end
def get_poll_question
@poll_question = ExerciseBankQuestion.find_by!(id: params[:id])
@poll = @poll_question.exercise_bank
end
def poll_questions_params
params.require(:poll_question).permit(:question_title,:question_type,:is_necessary,:question_number,:max_choices,:min_choices)
end
def validates_params
normal_status(-1, "问题标题不能为空!") if params[:question_title].blank?
normal_status(-1, "是否要求必答的值不能为空!") if params[:is_necessary].blank?
normal_status(-1, "问题类型不能为空!") if params[:question_type].blank?
if params[:min_choices].present? && params[:max_choices].present? && (params[:min_choices].to_i > params[:max_choices].to_i)
normal_status(-1, "最小可选不能大于最大可选!")
elsif params[:question_answers].present? && (params[:max_choices].to_i > params[:question_answers].count)
normal_status(-1, "选择题的最大可选项不能大于答案数!")
elsif [1,3].include?(params[:question_type]) && (params[:max_choices].to_i > 0 || params[:min_choices].to_i > 0)
normal_status(-1, "单选题或主观题不能有最大或最小选择数!")
elsif params[:question_type] == 3 && (params[:question_answers] || params[:question_other_answer])
normal_status(-1, "主观问题不需要可选答案!")
elsif params[:question_type] != 3
if params[:question_answers].present? && params[:question_answers].include?("")
normal_status(-1, "选择题不能有空值!")
elsif params[:question_other_answer].present? && params[:question_other_answer].length > 0
normal_status(-1, "其他选项不能有值!")
elsif params[:question_type] == 1 && params[:question_answers].count < 2
normal_status(-1, "单选题选项不能小于2")
elsif params[:question_type] == 2 && params[:question_answers].count < 3
normal_status(-1, "多选题选项不能小于3")
end
end
end
end

@ -1,7 +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]
# before_action :teacher_or_admin, except: [:bank_list]
# 题库选用列表
# object_type: # normal 普通作业题库; group 分组作业题库; poll问卷题库 exercise试卷题库; gtask 毕设选题题库gtopic 毕设任务

@ -25,11 +25,12 @@ class TaskBanksController < ApplicationController
def find_bank
@bank = GtaskBank.find_by!(id: params[:id])
tip_exception(403, "无权限") unless (current_user.certification_teacher? && (@bank.is_public || @bank.user_id == current_user.id)) || current_user.admin?
tip_exception(403, "无权限") unless @bank.user_id == current_user.id || current_user.admin? ||
(current_user.certification_teacher? && @bank.is_public)
end
def bank_admin
tip_exception(403, "无权限") unless (current_user.certification_teacher? && @bank.user_id == current_user.id) || current_user.admin?
tip_exception(403, "无权限") unless @bank.user_id == current_user.id || current_user.admin?
end
def gtask_bank_params

@ -0,0 +1,10 @@
class Customer < ApplicationRecord
default_scope { order(created_at: :desc) }
belongs_to :school
has_many :partner_customers, dependent: :destroy
has_many :partners, through: :partner_customers
has_many :users
end

@ -9,6 +9,10 @@ class Department < ApplicationRecord
scope :without_deleted, -> { where(is_delete: false) }
def member?(user)
department_members.exists?(user_id: user.id)
end
def soft_delete!
update!(is_delete: true)
end

@ -3,7 +3,7 @@ class HomeworkCommon < ApplicationRecord
enum homework_type: { normal: 1, program: 2, group: 3, practice: 4 }, _suffix: true
has_many :homework_group_settings, dependent: :destroy
has_many :published_settings, -> { group_published }, class_name: "HomeworkGroupSetting"
has_many :student_works, -> { where("is_delete = 0") }
has_many :student_works, -> { where(is_delete: 0) }
has_many :score_student_works, -> { where("is_delete = 0 and work_status != 0").order("work_score desc") }, class_name: "StudentWork"
has_one :homework_detail_manual, dependent: :destroy

@ -1,3 +1,5 @@
class Partner < ApplicationRecord
belongs_to :school, optional: true
has_many :users
end

@ -0,0 +1,4 @@
class PartnerCustomer < ApplicationRecord
belongs_to :partner
belongs_to :customer
end

@ -13,6 +13,9 @@ class School < ApplicationRecord
has_many :school_daily_reports, dependent: :destroy
has_many :courses
has_many :customers, dependent: :destroy
has_many :partners, dependent: :destroy
# 学校管理员
def manager?(user)
ec_school_users.exists?(user_id: user.id)

@ -139,7 +139,7 @@ class User < ApplicationRecord
has_many :videos, dependent: :destroy
# 客户管理
belongs_to :partner
belongs_to :partner, optional: true
# Groups and active users
scope :active, lambda { where(status: STATUS_ACTIVE) }

@ -15,7 +15,7 @@ class Admins::DepartmentQuery < ApplicationQuery
keyword = params[:keyword].to_s.strip
if keyword.present?
departments = departments.joins(:school)
.where('schools.name LIKE :keyword OR departments.name LIKE :keyword', keyword: keyword)
.where('schools.name LIKE :keyword OR departments.name LIKE :keyword', keyword: "%#{keyword}%")
end
if params[:with_member].to_s == 'true'

@ -14,7 +14,13 @@
<td class="member-container">
<%= render partial: 'admins/departments/shared/member_users', locals: { department: department } %>
</td>
<td><%= link_to department.identifier.to_s, '#', target: '_blank' %></td>
<td>
<% if department.identifier.present? %>
<%= link_to department.identifier.to_s, statistics_college_path(department.identifier), target: '_blank' %>
<% else %>
--
<% end %>
</td>
<td><%= department.host_count %></td>
<td><%= department.created_at&.strftime('%Y-%m-%d %H:%M') %></td>
<td class="action-container">

@ -0,0 +1,45 @@
<table class="table text-center course-table">
<thead class="thead-light">
<tr>
<th class="text-left">名称</th>
<th class="text-left">管理教师</th>
<th>评测次数</th>
<th>学生</th>
<th>实训作业</th>
<th>资源</th>
<th>帖子</th>
<th>其它任务</th>
<th>状态</th>
<th>时间</th>
</tr>
</thead>
<tbody>
<% if @courses.present? %>
<% @courses.each do |course| %>
<tr>
<td class="text-left"><a href="/courses/<%= course.id %>/students" target="_blank" class="d-inline-block text-truncate" style="max-width: 220px"><%= course.name %></a></td>
<% teacher_names = course.teacher_users.map(&:real_name).join('、') %>
<td class="text-left">
<span class="d-inline-block text-truncate" style="max-width: 150px" data-toggle="tooltip" title="<%= teacher_names %>">
<%= teacher_names || '--' %>
</span>
</td>
<td><%= course.evaluating_count.to_i %></td>
<td><%= @student_count.fetch(course.id, 0) %></td>
<td><%= @shixun_work_count.fetch(course.id, 0) %></td>
<td><%= @attachment_count.fetch(course.id, 0) %></td>
<td><%= @message_count.fetch(course.id, 0) %></td>
<td><%= @exercise_count.fetch(course.id, 0) + @poll_count.fetch(course.id, 0) + @other_work_count.fetch(course.id, 0) %></td>
<td class="<%= course.is_end ? 'text-secondary' : 'text-warning' %>"><%= course.is_end ? "已结束" : "正在进行" %></td>
<td class="text-secondary"><%= @active_time[course.id]&.strftime('%Y-%m-%d %H:%M') %></td>
</tr>
<% end %>
<% else %>
<tr><td colspan="100">暂无数据</td></tr>
<% end %>
</tbody>
</table>
<div class="d-flex justify-content-center text-center">
<%= render partial: 'admins/shared/paginate', locals: { objects: @courses } %>
</div>

@ -0,0 +1,23 @@
<% if @students.present? %>
<% @students.each_with_index do |student, index| %>
<tr>
<td>
<% if index < 3 %>
<img src="/images/educoder/competition/<%= index + 1 %>.png" width="18px" height="22px" class="mt8"/></td>
<% else %>
<%= index + 1 %>
<% end %>
</td>
<td class="color-dark">
<a href="/users/<%= student.login %>" target="_blank" class="d-inline-block text-truncate" style="max-width: 84px;"><%= student.real_name %></a>
</td>
<td><%= student.student_id %></td>
<td><%= @shixun_count.fetch(student.id, 0) %></td>
<td><%= @study_shixun_count.fetch(student.id, 0) %></td>
<td><%= student.grade %></td>
<td class="text-info"><%= student.experience %></td>
</tr>
<% end %>
<% else %>
<tr><td colspan="100">暂无数据</td></tr>
<% end %>

@ -0,0 +1,21 @@
<% if @teachers.present? %>
<% @teachers.each_with_index do |teacher, index| %>
<tr>
<td class="pl20 pr20">
<% if index < 3 %>
<img src="/images/educoder/competition/<%= index + 1 %>.png" width="18px" height="22px" class="mt8"/></td>
<% else %>
<%= index + 1 %>
<% end %>
<td class="color-dark"><a href="<%= user_path(teacher['login']) %>" target="_blank" class="task-hide" style="max-width: 84px;"><%= teacher['real_name'] %></a></td>
<td><%= teacher['course_count'] %></td>
<td><%= teacher['shixun_work_count'] %></td>
<td><%= teacher['un_shixun_work_count'] %></td>
<td><%= teacher['student_count'] %></td>
<td><%= teacher['complete_rate'] %>%</td>
<td class="color-blue"><%= teacher['publish_shixun_count'].to_i %></td>
</tr>
<% end %>
<% else %>
<tr><td colspan="100">暂无数据</td></tr>
<% end %>

@ -0,0 +1 @@
$(".statistic-course .statistic-table").html("<%= j(render 'colleges/course_statistics') %>");

@ -0,0 +1,21 @@
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<a class="navbar-brand" href="#">
<img src="/images/educoder/headNavLogo.png" width="40" height="40" alt="">
</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item"><a class="nav-link" href="/paths">实践课程</a></li>
<li class="nav-item"><a class="nav-link" href="/courses">翻转课堂</a></li>
<li class="nav-item"><a class="nav-link" href="/shixuns">实训项目</a></li>
<li class="nav-item"><a class="nav-link" href="/competitions">在线竞赛</a></li>
<li class="nav-item"><a class="nav-link" href="/moop_cases">教学案例</a></li>
<li class="nav-item"><a class="nav-link" href="/crowdsourcing">众包创新</a></li>
<li class="nav-item"><a class="nav-link" href="/forums">交流问答</a></li>
</ul>
</div>
</nav>

@ -0,0 +1,164 @@
<div class="statistic-header">
<div class="container statistic-header-container">
<div class="statistic-header-title"><%= current_school.name %></div>
<div class="statistic-header-content">
<div class="statistic-header-item">
<div class="statistic-header-item-label">教师</div>
<div class="statistic-header-item-content"><%= @teachers_count %></div>
</div>
<div class="statistic-header-item">
<div class="statistic-header-item-label">学生</div>
<div class="statistic-header-item-content"><%= @students_count %></div>
</div>
<div class="statistic-header-item">
<div class="statistic-header-item-label">课堂</div>
<div class="statistic-header-item-content"><%= @courses_count %></div>
</div>
<div class="statistic-header-item">
<div class="statistic-header-item-label">共建实训</div>
<div class="statistic-header-item-content"><%= @shixuns_count %></div>
</div>
</div>
</div>
</div>
<div class="container statistics-body my-4" data-id="<%= current_school.id %>">
<div class="card statistic-box statistic-base">
<h4 class="card-header statistic-base-title">基本情况</h4>
<div class="card-body statistic-base-table row">
<div class="col-4 col-md-2 statistic-base-item">
<div class="statistic-base-item-label">教师</div>
<div class="statistic-base-item-content">
<span><%= @teachers_count %></span>人
</div>
</div>
<div class="col-4 col-md-2 statistic-base-item">
<div class="statistic-base-item-label">学生</div>
<div class="statistic-base-item-content">
<span><%= @students_count %></span>人
</div>
</div>
<div class="col-4 col-md-2 statistic-base-item">
<div class="statistic-base-item-label">课堂</div>
<div class="statistic-base-item-content">
<span><%= @courses_count %></span>个
</div>
</div>
<div class="col-4 col-md-2 statistic-base-item">
<div class="statistic-base-item-label">共建实训</div>
<div class="statistic-base-item-content">
<span><%= @shixuns_count %></span>个
</div>
</div>
<div class="col-4 col-md-2 statistic-base-item">
<div class="statistic-base-item-label">实习报告</div>
<div class="statistic-base-item-content shixun-report-count">
加载中...
</div>
</div>
<div class="col-4 col-md-2 statistic-base-item">
<div class="statistic-base-item-label">学员实战时间</div>
<div class="statistic-base-item-content shixun-time">
加载中...
</div>
</div>
</div>
</div>
<div class="statistic-container my-4 statistic-course">
<div class="row">
<div class="col-12">
<div class="statistic-label">课堂</div>
<div class="statistic-table">
<table class="table text-center course-table">
<thead class="thead-light">
<tr>
<th class="text-left">名称</th>
<th class="text-left">管理教师</th>
<th>评测次数</th>
<th>学生</th>
<th>实训作业</th>
<th>资源</th>
<th>帖子</th>
<th>其它任务</th>
<th>状态</th>
<th>时间</th>
</tr>
</thead>
<tbody>
<tr><td colspan="100">加载中...</td></tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<div class="my-4 mx-0 row">
<div class="col-12 col-md-7 statistic-container statistic-teacher-rank">
<div class="statistic-label">教师排名</div>
<div class="statistic-table">
<table class="table text-center teacher-rank-table">
<thead class="thead-light">
<tr>
<th>排名</th>
<th>姓名</th>
<th>管理课堂</th>
<th width="15%">已发布实训作业</th>
<th width="15%">未发布实训作业</th>
<th>学生数</th>
<th>完成率</th>
<th>发布实训</th>
</tr>
</thead>
<tbody>
<tr><td colspan="100">加载中...</td></tr>
</tbody>
</table>
</div>
</div>
<div class="col-12 col-md-5 statistic-container">
<div class="statistic-label">在线实训情况</div>
<div class="statistic-chart">
<div class="shixun-chart-loading">加载中...</div>
<div class="shixun-chart-empty" style="display: none;">无数据</div>
<div class="shixun-chart" id="shixun-chart"></div>
</div>
</div>
</div>
<div class="my-4 mx-0 row">
<div class="col-12 col-md-7 statistic-container statistic-student-rank">
<div class="statistic-label">学生排名</div>
<div class="statistic-table">
<table class="table text-center student-rank-table">
<thead class="thead-light">
<tr>
<th>排名</th>
<th>姓名</th>
<th>学号</th>
<th>完成实训</th>
<th>在学实训</th>
<th>金币</th>
<th>经验值</th>
</tr>
</thead>
<tbody>
<tr><td colspan="100">加载中...</td></tr>
</tbody>
</table>
</div>
</div>
<div class="col-12 col-md-5 statistic-container">
<div class="statistic-label">最热评测</div>
<div class="statistic-chart">
<div class="hot-chart-loading">加载中...</div>
<div class="hot-chart-empty" style="display: none;">无数据</div>
<div class="hot-chart" id="hot-chart"></div>
</div>
</div>
</div>
</div>

@ -0,0 +1 @@
$('.statistic-student-rank table.student-rank-table tbody').html("<%= j(render :partial => 'colleges/student_rank') %>")

@ -0,0 +1 @@
$('.statistic-teacher-rank table.teacher-rank-table tbody').html("<%= j(render :partial => 'colleges/teacher_rank') %>")

@ -0,0 +1,18 @@
json.question do
json.id question.id
json.question_number question.question_number
json.question_title question.question_title
json.question_type question.question_type
json.is_necessary question.is_necessary
if question.question_type == 2
json.max_choices question.max_choices
json.min_choices question.min_choices
end
json.answers do
json.array! answers do | a|
json.answer_id a.id
json.answer_position a.choice_position
json.answer_text a.choice_text.nil? ? "other_choices" : a.choice_text ##
end
end
end

@ -1,16 +1,36 @@
json.exercise do
json.extract! @bank, :id, :name, :description, :is_public
end
if @bank.container_type == "Exercise"
json.exercise do
json.extract! @bank, :id, :name, :description, :is_public
end
json.partial! "exercises/exercise_scores"
json.exercise_questions do
json.array! @exercise_questions do |q|
json.partial! "exercise_bank_questions/exercise_bank_questions",
question: q,
choices:q.exercise_bank_choices,
shixun_challenges: q.exercise_bank_shixun_challenges,
ques_position:nil,
edit_type:nil
end
end
json.partial! "exercises/exercise_scores"
else
json.poll do
json.extract! @bank, :id, :name, :description, :is_public
end
json.question_types do
json.q_counts @poll_questions_count
json.q_singles @poll_question_singles
json.q_doubles @poll_question_doubles
json.q_mains @poll_question_mains
end
json.exercise_questions do
json.array! @exercise_questions do |q|
json.partial! "exercise_bank_questions/exercise_bank_questions",
question: q,
choices:q.exercise_bank_choices,
shixun_challenges: q.exercise_bank_shixun_challenges,
ques_position:nil,
edit_type:nil
json.questions do
json.array! @exercise_questions do | question|
json.partial! "exercise_banks/poll_questions", question: question, answers: question.exercise_bank_choices
end
end
end

@ -4,6 +4,7 @@
<title>EduCoder后台管理</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel='shortcut icon' type='image/x-icon' href='/favicon.ico' />
<%= csrf_meta_tags %>
<%= csp_meta_tag %>

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html>
<head>
<title>EduCoder</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel='shortcut icon' type='image/x-icon' href='/favicon.ico' />
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= stylesheet_link_tag 'college', media: 'all','data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'college', 'data-turbolinks-track': 'reload' %>
</head>
<% body_class = [params[:controller].gsub(/\//, '-').gsub('_', '-'), params[:action], 'page'].join('-') %>
<body class="<%= body_class %>">
<%= render 'colleges/shared/navbar' %>
<!-- Page Content -->
<div class="college-body-container">
<%= yield %>
</div>
</body>
</html>

@ -0,0 +1,2 @@
json.content @content
json.path @path

@ -12,5 +12,5 @@ Rails.application.config.assets.paths << Rails.root.join('vendor/assets')
# Precompile additional assets.
# application.js, application.css, and all non-JS/CSS in the app/assets
# folder are already added.
Rails.application.config.assets.precompile += %w( admin.js admin.css )
Rails.application.config.assets.precompile += %w( admin.js admin.css college.js college.css )

@ -663,6 +663,8 @@ Rails.application.routes.draw do
end
end
resources :poll_bank_questions
resources :attachments
resources :schools do
@ -848,6 +850,19 @@ Rails.application.routes.draw do
end
end
resources :colleges, only: [] do
member do
get :statistics
get :course_statistics
get :student_shixun
get :shixun_time
get :shixun_report_count
get :teachers
get :shixun_chart_data
get :student_hot_evaluations
end
end
#git 认证回调
match 'gitauth/*url', to: 'gits#auth', via: :all

File diff suppressed because one or more lines are too long

@ -37830,25 +37830,24 @@ $(document).on('turbolinks:load', function() {
})
;
$(document).on('turbolinks:load', function() {
if ($('body.admins-library-applies-index-page').length > 0) {
var $searchFrom = $('.library-applies-list-form');
$searchFrom.find('select[name="status"]').val('pending');
$searchFrom.on('click', '.search-form-tab', function(){
var $link = $(this);
if ($('body.admins-library-applies-index-page').length > 0) {
var $searchFrom = $('.library-applies-list-form');
$searchFrom.find('select[name="status"]').val('pending');
$searchFrom.find('input[name="keyword"]').val('');
$searchFrom.find('select[name="status"]').val('processed');
$searchFrom.on('click', '.search-form-tab', function(){
var $link = $(this);
if($link.data('value') === 'processed'){
$searchFrom.find('.status-filter').show();
} else {
$searchFrom.find('.status-filter').hide();
$searchFrom.find('select[name="status"]').val('pending');
}
});
$searchFrom.find('input[name="keyword"]').val('');
$searchFrom.find('select[name="status"]').val('processed');
}
if($link.data('value') === 'processed'){
$searchFrom.find('.status-filter').show();
} else {
$searchFrom.find('.status-filter').hide();
$searchFrom.find('select[name="status"]').val('pending');
}
});
}
})
;
$(document).on('turbolinks:load', function() {
@ -38362,7 +38361,7 @@ $(document).on('turbolinks:load', function() {
;
$(document).on('turbolinks:load', function() {
if ($('body.admins-shixun-settings-index-page').length > 0) {
$(".shixun-settings-select").on("change", function () {
$(".shixun-settings-list-container").on("change", '.shixun-settings-select', function () {
var s_value = $(this).val();
var s_name = $(this).attr("name");
var json = {};
@ -38375,7 +38374,7 @@ $(document).on('turbolinks:load', function() {
})
});
$(".shixun-setting-form").on("change",function () {
$(".shixun-settings-list-container").on("change", '.shixun-setting-form', function () {
var s_id = $(this).attr("data-id");
var s_value = $(this).val();
var s_name = $(this).attr("name");
@ -38394,10 +38393,12 @@ $(document).on('turbolinks:load', function() {
});
$(document).on('turbolinks:load', function() {
if($('body.admins-shixuns-index-page').length > 0){
$('select#tag-choosed').select2({
placeholder: "请选择分类",
allowClear: true
placeholder: "请选择分类",
allowClear: true
});
}
});
$(document).on('turbolinks:load', function(){
$('#sidebarCollapse').on('click', function () {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -32,7 +32,7 @@ module.exports = {
// See the discussion in https://github.com/facebookincubator/create-react-app/issues/343.s
// devtool: "cheap-module-eval-source-map",
// 开启调试
// devtool: "source-map", // 开启调试
// devtool: "source-map", // 开启调试
// These are the "entry points" to our application.
// This means they will be the "root" imports that are included in JS bundle.
// The first two entry points enable "hot" CSS and auto-refreshes for JS.

@ -1,4 +1,4 @@
import { bytesToSize, getUrl2 } from 'educoder';
import { bytesToSize, getUrl, getUrl2 } from 'educoder';
const $ = window.$
export function isImageExtension(fileName) {
@ -41,7 +41,7 @@ export function markdownToHTML(oldContent, selector) {
}
}
function _doDownload(options) {
$.fileDownload("/api" + options.url, {
$.fileDownload(getUrl() + "/api" + options.url, {
successCallback: options.successCallback,
failCallback: options.failCallback
});

@ -37,6 +37,14 @@ export function getUrl(path, goTest) {
}
return `${path ? path: ''}`;
}
export function getStaticUrl() {
const local = TEST_HOST;
if (isDev) {
return local
}
// todo cdn
return ''
}
export function getUrl2(path, goTest) {
const local = 'http://localhost:3000'
if (isDev) {

@ -283,6 +283,11 @@ const Completetaskpage =Loadable({
loader: () => import('../../modules/courses/completetaskdetails/Completetaskpage'),
loading: Loading,
});
//问卷编辑
const PollNewQuestbank =Loadable({
loader: () => import('../../modules/courses/poll/PollNewQuestbank'),
loading: Loading,
});
class CoursesIndex extends Component{
constructor(props) {
super(props)
@ -461,13 +466,19 @@ class CoursesIndex extends Component{
// console.log(commons)
return (
<Switch {...this.props}>
{/*题库问卷编辑详情*/}
<Route path="/courses/questreediting/:workid/edit"
render={
(props) => (<PollNewQuestbank {...this.props} {...props} {...this.state} />)
}
></Route>
{/*毕设任务题库详情*/}
<Route path="/courses/completetask/:workid"
render={
(props) => (<Completetaskpage {...this.props} {...props} {...this.state} />)
}
></Route>
{/*毕设内容题库详情*/}
{/*毕设选题题库详情*/}
<Route path="/courses/completetopic/:workid"
render={
(props) => (<CompletetopicdePage {...this.props} {...props} {...this.state} />)

@ -822,9 +822,7 @@ class Fileslists extends Component{
max-height:350px;
overflow-y: auto;
}
.drop_down_menu li {
overflow: visible;
}
.courseSecond{
margin-left: 10px;
padding: 10px;
@ -838,7 +836,7 @@ class Fileslists extends Component{
{course_modules&&course_modules.course_modules.map((item,key)=>{
return(
filesId&&filesId===item.id?"":<li key={key} id={item.id} onClick={() => this.moveTos(0)}>{item.module_name}</li>
filesId&&filesId===item.id?"":<li key={key} id={item.id} onClick={() => this.moveTos(0)} title={item.module_name}>{item.module_name}</li>
)
})}
@ -848,7 +846,7 @@ class Fileslists extends Component{
return (!this.state.dirSearchValue || item.name.indexOf(this.state.dirSearchValue) != -1)
}).map((itm,k)=>{
return(
filesId&&filesId===itm.id?"":<li key={k} id={itm.id} onClick={() => this.moveTos(itm.id )}>{itm.name}</li>
filesId&&filesId===itm.id?"":<li key={k} id={itm.id} onClick={() => this.moveTos(itm.id )} title={itm.name}>{itm.name}</li>
)
})
})}

@ -186,23 +186,26 @@ class BoardsNew extends Component{
});
}
onAttachmentRemove = (file) => {
confirm({
// title: '确定要删除这个附件吗?',
title: '是否确认删除?',
okText: '确定',
cancelText: '取消',
// content: 'Some descriptions',
onOk: () => {
this.deleteAttachment(file)
},
onCancel() {
console.log('Cancel');
},
});
if(file.response!=undefined){
confirm({
// title: '确定要删除这个附件吗?',
title: '是否确认删除?',
okText: '确定',
cancelText: '取消',
// content: 'Some descriptions',
onOk: () => {
this.deleteAttachment(file)
},
onCancel() {
console.log('Cancel');
},
});
return false;
}
return false;
}
deleteAttachment = (file) => {
// 初次上传不能直接取uid

@ -387,7 +387,7 @@ class Boards extends Component{
boards && boards.filter((item)=> {
return item.id != bid && (!this.state.dirSearchValue || item.name.indexOf(this.state.dirSearchValue) != -1)
}).map( (item) => {
return <li onClick={() => this.moveTo(item)}>{item.name}</li>
return <li onClick={() => this.moveTo(item)} title={item.name}>{item.name}</li>
})
}
{ isAdmin &&

@ -108,7 +108,7 @@ function buildColumns(that, student_works, studentData) {
}]
if (!niPingAndIsStudent && isAdminOrStudent) {
columns.push({
width: 88,
width: isStudent ? undefined : 88,
title: '学号',
dataIndex: 'student_id',
key: 'student_id',
@ -197,7 +197,7 @@ function buildColumns(that, student_works, studentData) {
</span>
)},
}, {
width: 106,
width: 106, // isStudent ? undefined : 106 , // 匿评中 只有这几列: 序号 姓名 提交状态 更新时间 匿评评分 操作
title: '更新时间',
dataIndex: 'update_time',
key: 'update_time',

@ -320,8 +320,11 @@ class CommonWorkPost extends Component{
// ModalSave: ()=>this.deleteAttachment(file),
// ModalCancel:this.cancelAttachment
// })
this.deleteAttachment(file)
return false;
if(file.response!=undefined){
this.deleteAttachment(file)
return false;
}
}
cancelAttachment=()=>{

@ -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 } from 'educoder'
import { WordsBtn, getUrl, ConditionToolTip, appendFileSizeToUploadFile, appendFileSizeToUploadFileAll } from 'educoder'
import TPMMDEditor from '../../tpm/challengesnew/TPMMDEditor';
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,6 +17,15 @@ 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 () {
@ -41,6 +50,7 @@ class NewWork extends Component{
course_id: data.course_id,
course_name: data.course_name,
category: data.category,
})
}
})
@ -55,26 +65,129 @@ class NewWork extends Component{
.then((response) => {
if (response.data.name) {
const data = response.data;
data.isEdit = true;
this.setState({
category: data.category,
course_id: data.course_id,
course_name: data.course_name,
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.newWorkFormRef.initValue(data);
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 || '',
});
})
}
})
.catch(function (error) {
console.log(error);
});
}
doEdit = (params) => {
// 输入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) => {
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, params)
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
})
.then((response) => {
if (response.data.status == 0) {
this.props.showNotification('保存成功')
@ -85,11 +198,30 @@ class NewWork extends Component{
console.log(error);
});
}
doNew = (params) => {
const courseId = this.props.match.params.coursesId ;
doNew = (courseId, values) => {
const newUrl = `/courses/${courseId}/homework_commons.json`
axios.post(newUrl, params)
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
})
.then((response) => {
if (response.data.status == 0) {
this.props.showNotification('保存成功')
@ -100,26 +232,147 @@ class NewWork extends Component{
console.log(error);
});
}
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) => {
if(file.response!=undefined){
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{
category
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
}=this.state
const { current_user } = this.props
const courseId = this.props.match.params.coursesId ;
const courseId = this.state.course_id || 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 : ''}`
@ -138,16 +391,161 @@ class NewWork extends Component{
</a>
</p>
<div>
<NewWorkForm wrappedComponentRef={(ref) => {this.newWorkFormRef = ref}}
{...this.props}
onSave={this.onSave}
doNew={this.doNew}
doEdit={this.doEdit}
></NewWorkForm>
{/* 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>
</div>
</div>
</div>
)
}
}
export default NewWork;
const WrappedBoardsNew = Form.create({ name: 'NewWork' })(NewWork);
export default WrappedBoardsNew;

@ -57,20 +57,22 @@ class Groupjobbandetails extends Component {
render() {
let{datas}=this.props;
return (
<div className=" clearfix edu-back-white" ref='targetElementTrainingjobsetting' style={{margin: "auto", minWidth:"1200px"}}>
<div className="yslquestionbank1">
<div id="MakedownHTML"className="markdown-body yslquesHeigth yslquesmarkdowntext" dangerouslySetInnerHTML={{__html: markdownToHTML("C++是C语言的面向对象扩展是C语言的一个超集同时也是历史最悠久、最受欢迎的程序设计语言之一。根据C++创始人Stroustrup的自述C++是一个“更好的C语言”。\n" +
"\n" +
"输入输出是计算机程序的基本功能。程序本质上是对数据进行处理的一系列操作,一般程序都可以分解为:“数据输入”、“数据处理”和“数据输出”三个步骤。标准输入输出(键盘输入和显示器输出)是程序的重要组成部分。\n" +
"\n" +
"本实训项目的主要目标是学习和掌握C++程序的基本结构和基本输入输出主要内容包括标准C语言自有的单个字符的输入输出、格式化的输入输出以及C++扩展的使用流对象的输入输出").replace(/▁/g, "▁▁▁")}}/>
<div id="MakedownHTML"className="markdown-body yslquesHeigth yslquesmarkdowntext" dangerouslySetInnerHTML={{__html: markdownToHTML(datas&&datas.description).replace(/▁/g, "▁▁▁")}}/>
{datas.attachments === undefined ? "" : datas.attachments.map((item, key) => {
return (
<GroupPackage key={key} attachments={item}></GroupPackage>
)
})}
<GroupPackage2 datas={datas} bool={false}></GroupPackage2>
<GroupPackage></GroupPackage>
<GroupPackage2></GroupPackage2>
</div>

@ -18,17 +18,20 @@ class Completetaskpage extends Component {
constructor(props) {
super(props);
// this.answerMdRef = React.createRef();
this.setState({
this.state={
workid:1,
isSpin:false,
datas:[],
})
}
}
componentDidMount() {
// console.log("父组件加载框");
this.getonedata();
}
getonedata(){
if( this.props.match.params.workid){
this.setState({
workid: this.props.match.params.workid,
@ -47,13 +50,13 @@ class Completetaskpage extends Component {
this.setState({
isSpin:true,
})
let url = `/homework_banks/${workids}.json`;
let url = `/task_banks/${workids}.json`;
//
axios.get(url).then((response) => {
if(response){
if(response.data){
this.setState({
datas:response.data.informs,
datas:response.data,
})
}else {
this.setState({
@ -86,6 +89,7 @@ class Completetaskpage extends Component {
///////////////教师截止
render() {
let{datas}=this.state;
const isAdmin = this.props.isAdmin();
// console.log(119)
@ -108,10 +112,10 @@ class Completetaskpage extends Component {
</div>
<div className="educontent mb20">
<p className=" fl color-black summaryname" style={{heigth: "33px"}}>
MySQL数据库编程开发实训基础篇
{datas&&datas.name}
</p>
<CoursesListType
typelist={["公开"]}
typelist={datas&&datas.is_public?["公开"]:["私有"]}
/>
</div>
@ -126,7 +130,7 @@ class Completetaskpage extends Component {
</div>
</div>
<Completetaskdetails/>
<Completetaskdetails {...this.state} {...this.props} datas={datas}/>
</div>
</div>

@ -19,11 +19,11 @@ class CompletetopicdePage extends Component {
constructor(props) {
super(props);
// this.answerMdRef = React.createRef();
this.setState({
this.state={
workid:1,
isSpin:false,
datas:[],
})
}
}
@ -48,13 +48,13 @@ class CompletetopicdePage extends Component {
this.setState({
isSpin:true,
})
let url = `/homework_banks/${workids}.json`;
let url = `/gtopic_banks/${workids}.json`;
//
axios.get(url).then((response) => {
if(response){
if(response.data){
this.setState({
datas:response.data.informs,
datas:response.data,
})
}else {
this.setState({
@ -88,7 +88,7 @@ class CompletetopicdePage extends Component {
///////////////教师截止
render() {
let{datas}=this.state;
const isAdmin = this.props.isAdmin();
// console.log(119)
@ -110,10 +110,10 @@ class CompletetopicdePage extends Component {
</div>
<div className="educontent mb20">
<p className=" fl color-black summaryname" style={{heigth: "33px"}}>
MySQL数据库编程开发实训基础篇
{datas&&datas.name}
</p>
<CoursesListType
typelist={["公开"]}
typelist={datas&&datas.is_public?["公开"]:["私有"]}
/>
</div>
@ -128,7 +128,7 @@ class CompletetopicdePage extends Component {
</div>
</div>
<Completetopicdetails/>
<Completetopicdetails {...this.state} {...this.props} datas={datas}/>
{/*{parseInt(tab) === 1 ? <Completetopicdeswer/>:""}*/}
</div>

@ -56,52 +56,52 @@ class Completetopicdetails extends Component {
render() {
let{datas}=this.props;
return (
<div className=" clearfix edu-back-white " ref='targetElementTrainingjobsetting' style={{margin: "auto", minWidth:"1200px"}}>
<div className="bor-bottom-greyE">
<div className="yslquestionbank1">
<div id="MakedownHTML"className="markdown-body yslquesHeigth yslquesmarkdowntext" dangerouslySetInnerHTML={{__html: markdownToHTML("C++是C语言的面向对象扩展是C语言的一个超集同时也是历史最悠久、最受欢迎的程序设计语言之一。根据C++创始人Stroustrup的自述C++是一个“更好的C语言”。\n" +
"\n" +
"输入输出是计算机程序的基本功能。程序本质上是对数据进行处理的一系列操作,一般程序都可以分解为:“数据输入”、“数据处理”和“数据输出”三个步骤。标准输入输出(键盘输入和显示器输出)是程序的重要组成部分。\n" +
"\n" +
"本实训项目的主要目标是学习和掌握C++程序的基本结构和基本输入输出主要内容包括标准C语言自有的单个字符的输入输出、格式化的输入输出以及C++扩展的使用流对象的输入输出").replace(/▁/g, "▁▁▁")}}/>
<div id="MakedownHTML"className="markdown-body yslquesHeigth yslquesmarkdowntext" dangerouslySetInnerHTML={{__html: markdownToHTML(datas&&datas.description).replace(/▁/g, "▁▁▁")}}/>
<GroupPackage></GroupPackage>
{datas.attachment_list === undefined ? "" : datas.attachment_list.map((item, key) => {
return (
<GroupPackage key={key} attachments={item}></GroupPackage>
)
})}
</div>
</div>
<div style={{width:"100%", padding: "36px"}}>
<div className="yslboomdivs">
<p>
<span className="yslboomdivsy">课题类型</span>
<span className="yslboomdivsys">设计</span>
<span className="yslboomdivsys">{datas&&datas.topic_type===1?"设计":datas&&datas.topic_type===2?"论文":datas&&datas.topic_type===3?"创作":"设计"}</span>
</p>
<p>
<span className="yslboomdivsy">课题来源</span>
<span className="yslboomdivsys">生产/社会实践</span>
<span className="yslboomdivsys">{datas&&datas.topic_source===1?"生产/社会实际":datas&&datas.topic_source===2?"结合科研":datas&&datas.topic_source===3?"其它":"生产/社会实际"}</span>
</p>
<p>
<span className="yslboomdivsy">课题性质1</span>
<span className="yslboomdivsys">设计</span>
<span className="yslboomdivsys">{datas&&datas.topic_property_first===1?"真题":datas&&datas.topic_property_first===2?"模拟题":"真题"}</span>
</p>
<p>
<span className="yslboomdivsy">课题性质2</span>
<span className="yslboomdivsys">设计</span>
<span className="yslboomdivsys">{datas&&datas.topic_property_second===1?"纵向课题":datas&&datas.topic_property_second===2?"横向课题":datas&&datas.topic_property_second===3?"自选":"纵向课题"}</span>
</p>
</div>
<div className="yslboomdivs">
<p>
<span className="yslboomdivsy">课题重复情况 </span>
<span className="yslboomdivsys">新需求</span>
<span className="yslboomdivsys">{datas&&datas.topic_repeat===1?"新题":datas&&datas.topic_repeat===2?"往届题,有新要求":datas&&datas.topic_repeat===3?"往届题,无新要求":"新题"}</span>
</p>
<p>
<span className="yslboomdivsy">调研或实习地点</span>
<span className="yslboomdivsys">长沙</span>
<span className="yslboomdivsys">{datas&&datas.province}{datas&&datas.city}</span>
</p>
<p style={{width:"564px"}}>
<span className="yslboomdivsy">课题单位来源</span>
<span className="yslboomdivsys">湖南省据C++创始人Stroustrup有限公司</span>
<span className="yslboomdivsys">{datas&&datas.source_unit}</span>
</p>
</div>
</div>

@ -56,7 +56,8 @@ class Coursesleftnav extends Component{
positiontype:undefined,
toopvisible:false,
toopvisibleindex:undefined,
sandiantypes:undefined
sandiantypes:undefined,
antIcon:false
}
}
@ -582,7 +583,9 @@ class Coursesleftnav extends Component{
}
deletenavchilds=(url,mainurl)=>{
this.setState({
antIcon:true
})
axios.delete(url).then((result)=>{
if(result.data.status===0){
@ -809,6 +812,7 @@ class Coursesleftnav extends Component{
modalSave={ModalSave}
modalCancel={this.cannerNavmoda}
loadtype={loadtype}
antIcon={this.state.antIcon}
>
</Modals>

@ -73,8 +73,9 @@ class AccessoryModal extends Component{
// ModalCancel:this.cancelAttachment
// })
// return false;
this.deleteAttachment(file);
if(file.response!=undefined){
this.deleteAttachment(file);
}
}

@ -64,8 +64,10 @@ class AccessoryModal2 extends Component{
// ModalCancel:this.cancelAttachment
// })
// return false;
if(file.response!=undefined){
this.deleteAttachment(file);
}
this.deleteAttachment(file);
}

@ -296,37 +296,44 @@ class Selectsetting extends Component{
onAttachmentRemove = (file) => {
if(file.response!=undefined){
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) {
// const url = `/attachments/${file.response ? file.response.id : file.uid}.json`
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) {
this.setState({
fileListtype:false,
fileList:[]
})
// this.setState((state) => {
// const index = state.fileList.indexOf(file);
// const newFileList = state.fileList.slice();
// newFileList.splice(index, 1);
// return {
// fileList: newFileList,
// };
// });
this.setState({
fileListtype:false,
fileList:[]
})
// 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);
});
this.setState({
fileListtype:false,
})
.catch(function (error) {
console.log(error);
});
this.setState({
fileListtype:false,
})
}else{
this.setState({
fileListtype:false,
fileList:[]
})
}
// const url = `/attachments/${file.response ? file.response.id : file.uid}.json`
}
onChangeTimepublishs= (date, dateString,key) => {

@ -132,28 +132,34 @@ class Sendresource extends Component{
onAttachmentRemove = (file) => {
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) {
this.setState({
fileListtype:false,
fileList:[]
})
}
}
})
.catch(function (error) {
console.log(error);
});
this.setState({
fileListtype:false,
})
if(file.response!=undefined){
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) {
this.setState({
fileListtype:false,
fileList:[]
})
}
}
})
.catch(function (error) {
console.log(error);
});
this.setState({
fileListtype:false,
})
}else{
this.setState({
fileListtype:false,
fileList:[]
})
}
}
ModalCancelModalCancel=()=>{

@ -4,14 +4,14 @@ import {Form,Checkbox,DatePicker,Button,Input,Select,Tooltip} from "antd";
import { handleDateString } from 'educoder';
import PollDetailTabForthRules from '../poll/PollDetailTabForthRules';
import '../css/members.css'
import '../css/busyWork.css'
import '../poll/pollStyle.css'
import '../css/members.css';
import '../css/busyWork.css';
import '../poll/pollStyle.css';
import moment from 'moment'
import moment from 'moment';
import locale from 'antd/lib/date-picker/locale/zh_CN';
import axios from 'axios'
import Modals from '../../modals/Modals'
import axios from 'axios';
import Modals from '../../modals/Modals';
const Search=Input.Search;
const Option=Select.Option;
@ -549,6 +549,7 @@ class Exercisesetting extends Component{
}
//取消编辑
cancelEdit=()=>{
this.getSettingInfo();
this.setState({
flagPageEdit:false
})

@ -157,49 +157,52 @@ class GraduationTasksSubmitedit extends Component{
}
onAttachmentRemove = (file) => {
let {attachments,fileList}=this.state;
const url = `/attachments/${file}.json`
axios.delete(url, {
})
.then((response) => {
if (response.data) {
// const { status } = response.data;
if (response.data.status === 0) {
console.log('--- success')
let newattachments=attachments;
if(file.uid===undefined){
for(var i=0; i<newattachments.length; i++){
if(newattachments[i].id===file.id){
newattachments.splice(i, 1);
}
}
if(file.response!=undefined){
let {attachments,fileList}=this.state;
const url = `/attachments/${file}.json`
axios.delete(url, {
})
.then((response) => {
if (response.data) {
// const { status } = response.data;
if (response.data.status === 0) {
console.log('--- success')
let newattachments=attachments;
if(file.uid===undefined){
for(var i=0; i<newattachments.length; i++){
if(newattachments[i].id===file.id){
newattachments.splice(i, 1);
}
}
}
}
this.setState({
Modalstype:true,
Modalstopval:response.data.message,
ModalSave:this.cancelAttachment,
Loadtype:true,
attachments:newattachments
})
this.setState({
Modalstype:true,
Modalstopval:response.data.message,
ModalSave:this.cancelAttachment,
Loadtype:true,
attachments:newattachments
})
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);
});
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);
});
}
}
inputSearchValue=(e)=>{

@ -146,14 +146,16 @@ class GraduationTasksSubmitnew extends Component{
// },
// });
// return false;
if(file.response!=undefined){
this.setState({
Modalstype:true,
Modalstopval:'确定要删除这个附件吗?',
ModalSave: ()=>this.deleteAttachment(file),
ModalCancel:this.cancelAttachment
})
return false;
}
this.setState({
Modalstype:true,
Modalstopval:'确定要删除这个附件吗?',
ModalSave: ()=>this.deleteAttachment(file),
ModalCancel:this.cancelAttachment
})
return false;
}
cancelAttachment=()=>{

@ -88,21 +88,24 @@ class GraduationTasksappraiseMainEditor extends Component{
this.setState({ fileList });
}
onAttachmentRemove = (file, stateName) => {
this.props.confirm({
content: '确定要删除这个附件吗?',
okText: '确定',
cancelText: '取消',
// content: 'Some descriptions',
onOk: () => {
this.deleteAttachment(file, stateName)
},
onCancel() {
console.log('Cancel');
},
});
if(file.response!=undefined){
this.props.confirm({
content: '确定要删除这个附件吗?',
okText: '确定',
cancelText: '取消',
// content: 'Some descriptions',
onOk: () => {
this.deleteAttachment(file, stateName)
},
onCancel() {
console.log('Cancel');
},
});
return false;
}
return false;
}
deleteAttachment = (file, stateName) => {
// 初次上传不能直接取uid

@ -148,39 +148,42 @@ class GraduationTasksedit extends Component{
}
onAttachmentRemove = (file) => {
// debugger
this.cancelAttachment();
const url = `/attachments/${file.response ? file.response.id : file.uid}.json`
// const url = `/attachments/${file}.json`
axios.delete(url, {
})
.then((response) => {
if (response.data) {
if ( response.data.status === 0) {
this.setState({
Modalstype:false,
Modalstopval:response.data.message,
ModalSave:this.cancelAttachment,
Loadtype:true,
})
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);
});
if(file.response!=undefined){
// debugger
this.cancelAttachment();
const url = `/attachments/${file.response ? file.response.id : file.uid}.json`
// const url = `/attachments/${file}.json`
axios.delete(url, {
})
.then((response) => {
if (response.data) {
if ( response.data.status === 0) {
this.setState({
Modalstype:false,
Modalstopval:response.data.message,
ModalSave:this.cancelAttachment,
Loadtype:true,
})
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);
});
}
}
Commoninterface=(fileList)=>{

@ -172,30 +172,33 @@ class GraduationTasksnew extends Component {
}
onAttachmentRemove = (file) => {
const url = `/attachments/${file.response ? file.response.id : file.uid}.json`
// const url = `/attachments/${file}.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.cancelAttachment()
if(file.response!=undefined){
const url = `/attachments/${file.response ? file.response.id : file.uid}.json`
// const url = `/attachments/${file}.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.cancelAttachment()
}
}
}
})
.catch(function (error) {
console.log(error);
});
})
.catch(function (error) {
console.log(error);
});
}
}
//滚动

@ -778,6 +778,7 @@ class GraduationTaskssettingapp extends Component{
}
isgoback=()=>{
this.getsettings();
this.setState({
flagPageEdit: false,
})

@ -1,19 +1,28 @@
import React,{ Component } from "react";
import { Select, Modal } from 'antd';
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 axios from 'axios'
import {getUrl} from 'educoder';
import "../../common/formCommon.css"
import '../style.css'
import '../../css/Courses.css'
import { WordsBtn } from 'educoder'
import { WordsBtn, City } from 'educoder'
import {Link} from 'react-router-dom'
// import City from './City'
import GraduateTopicNewFrom from './GraduateTopicNewFrom'
// import './board.css'
// import { RouteHOC } from './common.js'
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{
@ -24,12 +33,14 @@ 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
@ -42,11 +53,21 @@ 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
left_banner_name:result.data.left_banner_name,
topic_property_first:result.data.topic_property_first,
topic_property_second:result.data.topic_property_second,
topic_repeat:result.data.topic_repeat,
topic_source:result.data.topic_source,
topic_type:result.data.topic_type
})
console.log("sdfds");
console.log(this.props.current_user && this.props.current_user.user_id);
this.props.form.setFieldsValue({
tea_id:this.props.current_user && this.props.current_user.user_id
})
this.GraduateTopicNewFromRef.initNewInfo(result);
}
}).catch((error)=>{
console.log(error);
@ -66,91 +87,240 @@ class GraduateTopicNew extends Component{
//编辑,信息显示
getEditInfo=()=>{
const cid = this.props.match.params.coursesId
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
})
this.GraduateTopicNewFromRef.initValue(result);
}
}).catch((error)=>{
console.log(error);
})
}
}
// 编辑保存
editSave = (param,attachments,topicId) =>{
const cid = this.props.match.params.coursesId
const editUrl = `/courses/${cid}/graduation_topics/${topicId}.json`
let params = {
graduation_topic:param,
attachment_ids:attachments
}
axios.put(editUrl, params).then((response) => {
if (response.status == 200) {
const { id } = response.data;
if (id) {
this.props.showNotification('保存成功!');
this.props.history.push(`/courses/${cid}/graduation_topics/${this.state.left_banner_id}`);
}
let topicId=this.props.match.params.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'
}
})
this.setState({ fileList: _fileList, cityDefaultValue: [result.data.selected_data.province,result.data.selected_data.city] })
}
}).catch(function (error) {
}).catch((error)=>{
console.log(error);
});
})
}
// 新建提交
newSubmit = (param,attachments,topicId) =>{
handleSubmit = (e) => {
e.preventDefault();
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) {
this.props.showNotification('提交成功!');
this.props.history.push(`/courses/${cid}/graduation_topics/${this.state.left_banner_id}`);
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
})
}
axios.put(editUrl, {
graduation_topic:{
...values,
province: values.city==undefined?"":values.city[0],
city: values.city==undefined?"":values.city[1],
},
attachment_ids
}).then((response) => {
if (response.status == 200) {
const { id } = response.data;
if (id) {
this.props.showNotification('保存成功!');
this.props.history.push(`/courses/${cid}/graduation_topics/${this.state.left_banner_id}`);
}
}
}).catch(function (error) {
console.log(error);
});
} else {
const url = `/courses/${cid}/graduation_topics.json`
let attachment_ids = undefined
if (this.state.fileList) {
attachment_ids = this.state.fileList.map(item => {
return item.response.id
})
}
axios.post(url, {
graduation_topic:{
...values,
province: values.city==undefined?"":values.city[0],
city: values.city==undefined?"":values.city[1],
},
attachment_ids,
}).then((response) => {
if (response.data) {
const { id } = response.data;
if (id) {
this.props.showNotification('提交成功!');
this.props.history.push(`/courses/${cid}/graduation_topics/${this.state.left_banner_id}`);
}
}
})
.catch(function (error) {
console.log(error);
});
}
} else {
$("html").animate({ scrollTop: $('html').scrollTop() - 100 })
}
}).catch(function (error) {
console.log(error);
});
}
// 取消编辑或者新建
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{
this.props.history.push(`/courses/${cid}/graduation_topics/${this.state.left_banner_id}`);
}
// 选择省市
ChangeCity=(value, selectedOptions)=>{
console.log(selectedOptions);
}
// 附件相关 START
handleChange = (info) => {
let fileList = info.fileList;
this.setState({ fileList });
}
onAttachmentRemove = (file) => {
if(file.response!=undefined){
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,
};
});
}
}
})
.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
const common={
editSave:this.editSave,
newSubmit:this.newSubmit,
editCancel:this.editCancel
}
// 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!');
}
return isLt150M;
},
};
// console.log("dfsf");
// console.log(this.props);
return(
<div className="newMain ">
<style>{`
@ -171,21 +341,292 @@ class GraduateTopicNew extends Component{
<Link to={`/courses/${coursesId}/graduation_topics/${left_banner_id}`} className="color-grey-6 fr font-16">返回</Link>
</div>
<GraduateTopicNewFrom
{...this.props}
{...this.state}
{...common}
wrappedComponentRef={(ref) => this.GraduateTopicNewFromRef = ref}
topicId={topicId}
teacherName={true}
></GraduateTopicNewFrom>
<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>
<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 GraduateTopicNew;
export default (WrappedGraduateTopicNew);

@ -163,21 +163,25 @@ class GraduateTopicPostWorksNew extends Component{
this.setState({ fileList });
}
onAttachmentRemove = (file) => {
confirm({
title: '确定要删除这个附件吗?',
okText: '确定',
cancelText: '取消',
// content: 'Some descriptions',
onOk: () => {
this.deleteAttachment(file)
},
onCancel() {
console.log('Cancel');
},
});
if(file.response!=undefined){
confirm({
title: '确定要删除这个附件吗?',
okText: '确定',
cancelText: '取消',
// content: 'Some descriptions',
onOk: () => {
this.deleteAttachment(file)
},
onCancel() {
console.log('Cancel');
},
});
return false;
}
return false;
}
deleteAttachment = (file) => {
const url = `/attachments/${file.id}.json`

@ -21,7 +21,9 @@ class GroupPackage extends Component {
}
}
DownloadOpenPdf=(type,url)=>{
type===true?window.open(url):window.location.href=url;
}
componentDidMount() {
console.log("Groupjobquesanswer");
console.log("componentDidMount");
@ -54,9 +56,9 @@ class GroupPackage extends Component {
render() {
let{attachments}=this.props;
return (
<div className="color-grey df yslquesmat26" key={0} style={{ lineHeight: '17px'}}>
<div className="color-grey df yslquesmat26" key={this.props.key} style={{ lineHeight: '17px'}}>
<a className="color-grey ">
<i className="font-14 color-green iconfont icon-fujian mr8" aria-hidden="true"></i>
</a>
@ -73,11 +75,11 @@ class GroupPackage extends Component {
`
}
</style>
<a href={"/"} title={''}
<a onClick={()=>this.DownloadOpenPdf(attachments.is_pdf,attachments.url)} title={attachments&&attachments.title}
className="mr12 yslahover overflowHidden1" length="58" style={{maxWidth:'480px',fontSize:"16px",}}>
<span>清除浏览器缓存或换个浏览器操作指南更新版本.zip</span>
<span>{attachments&&attachments.title}</span>
</a>
<span className="color656565 color-grey-6 font-12 mr8">{2}</span>
<span className="color656565 color-grey-6 font-12 mr8">{attachments&&attachments.filesize}</span>
</div>
)

@ -54,18 +54,42 @@ class GroupPackage extends Component {
render() {
let{datas,bool}=this.props;
return (
bool===true?
<div className="ml47text">
<p>
<span className="ysltextcolor66">分组要求</span>
<span className="ysltextcolor05">2~ 5学生提交作品时需要关联同组成员组内成员作品共享</span>
</p>
{
datas===undefined?"":datas.min_num===undefined||datas.max_num===undefined?"":datas.min_num===null||datas.max_num===null?"":
<p>
<span className="ysltextcolor66">分组要求</span>
<span className="ysltextcolor05">{datas&&datas.min_num}~ {datas&&datas.max_num}学生提交作品时需要关联同组成员组内成员作品共享</span>
</p>
}
<p>
<span className="ysltextcolor66">基于项目实施</span>
<span className="ysltextcolor05">学生必须在本平台创建项目项目管理员可以提交作品</span>
</p>
</div>
:<div className="ml47text">
{
datas===undefined?"":datas.group_info===undefined?"":datas.group_info.min_number===undefined||datas.group_info.max_number===undefined?"":
datas.group_info.min_number===null||datas.group_info.max_number===null?"":
<p>
<span className="ysltextcolor66">分组要求</span>
<span className="ysltextcolor05">{datas&&datas.group_info&&datas.group_info.min_number}~ {datas&&datas.group_info&&datas.group_info.max_number}学生提交作品时需要关联同组成员组内成员作品共享</span>
</p>
}
{
datas&&datas.group_info&&datas.group_info.base_on_project?
<p>
<span className="ysltextcolor66">基于项目实施</span>
<span className="ysltextcolor05">学生必须在本平台创建项目项目管理员可以提交作品</span>
</p>
:""
}
</div>
)
}
}

@ -57,20 +57,21 @@ class Groupjobbandetails extends Component {
render() {
let{datas}=this.props;
return (
<div className=" clearfix edu-back-white" ref='targetElementTrainingjobsetting' style={{margin: "auto", minWidth:"1200px"}}>
<div className="yslquestionbank1">
<div id="MakedownHTML"className="markdown-body yslquesHeigth yslquesmarkdowntext" dangerouslySetInnerHTML={{__html: markdownToHTML("C++是C语言的面向对象扩展是C语言的一个超集同时也是历史最悠久、最受欢迎的程序设计语言之一。根据C++创始人Stroustrup的自述C++是一个“更好的C语言”。\n" +
"\n" +
"输入输出是计算机程序的基本功能。程序本质上是对数据进行处理的一系列操作,一般程序都可以分解为:“数据输入”、“数据处理”和“数据输出”三个步骤。标准输入输出(键盘输入和显示器输出)是程序的重要组成部分。\n" +
"\n" +
"本实训项目的主要目标是学习和掌握C++程序的基本结构和基本输入输出主要内容包括标准C语言自有的单个字符的输入输出、格式化的输入输出以及C++扩展的使用流对象的输入输出").replace(/▁/g, "▁▁▁")}}/>
<div id="MakedownHTML"className="markdown-body yslquesHeigth yslquesmarkdowntext" dangerouslySetInnerHTML={{__html: markdownToHTML(datas&&(datas.description===null?"无":datas.description==="null"?"无":datas.description)).replace(/▁/g, "▁▁▁")}}/>
<GroupPackage></GroupPackage>
{datas.attachments === undefined ? "" : datas.attachments.map((item, key) => {
return (
<GroupPackage key={key} attachments={item}></GroupPackage>
)
})}
<GroupPackage2></GroupPackage2>
<GroupPackage2 datas={datas} bool={true}></GroupPackage2>
</div>

@ -14,6 +14,7 @@ import "../common/formCommon.css";
import '../css/Courses.css';
import '../css/busyWork.css';
import '../poll/pollStyle.css';
import Generaljobdetails from "../questionbank/Generaljobdetails";
class GroupjobbankPage extends Component {
//分组作业内容详情
@ -43,7 +44,7 @@ class GroupjobbankPage extends Component {
console.log(e);
console.log("44");
}
this.getonedata();
}
@ -64,6 +65,9 @@ class GroupjobbankPage extends Component {
this.setState({
shixuntypes: types[3]
})
this.getonedata();
}
getonedata=()=>{
if( this.props.match.params.workid){
this.setState({
workid: this.props.match.params.workid,
@ -88,7 +92,7 @@ class GroupjobbankPage extends Component {
if(response){
if(response.data){
this.setState({
datas:response.data.informs,
datas:response.data,
})
}else {
this.setState({
@ -120,7 +124,7 @@ class GroupjobbankPage extends Component {
///////////////教师截止
render() {
let {tab} = this.state;
let {tab,datas} = this.state;
const isAdmin = this.props.isAdmin();
// console.log(119)
@ -143,10 +147,10 @@ class GroupjobbankPage extends Component {
</div>
<div className="educontent mb20">
<p className=" fl color-black summaryname" style={{heigth: "33px"}}>
MySQL数据库编程开发实训基础篇
{datas&&datas.name}
</p>
<CoursesListType
typelist={["公开"]}
typelist={datas.is_public===true?["公开"]:["私有"]}
/>
</div>
@ -155,15 +159,15 @@ class GroupjobbankPage extends Component {
<div className=" clearfix edu-back-white poll_list">
<a className={parseInt(tab) === 0 ? "active ml12" : "ml12"} onClick={(e) => this.ChangeTab(0)}>内容详情</a>
<a className={parseInt(tab) === 1 ? "active ml12" : "ml12"} onClick={(e) => this.ChangeTab(1)}>参考答案</a>
<a className="fr color-blue font-16" >发送</a>
<a className="fr color-blue font-16" >编辑</a>
<a className="fr color-blue font-16" >删除</a>
<a className="fr color-blue font-16" >发送</a>
<a className="fr color-blue font-16" >编辑</a>
<a className="fr color-blue font-16" >删除</a>
</div>
</div>
</div>
<Spin size="large" spinning={this.state.isSpin} id={"cdiv"}>
{parseInt(tab) === 0 ? <Groupjobbandetails/>:""}
{parseInt(tab) === 1 ? <Groupjobquesanswer/>:""}
{parseInt(tab) === 0 ? <Groupjobbandetails {...this.props} {...this.state} datas={datas}/>:""}
{parseInt(tab) === 1 ? <Groupjobquesanswer {...this.props} {...this.state} datas={datas}/>:""}
</Spin>
</div>
</div>

@ -56,20 +56,20 @@ class Groupjobquesanswer extends Component {
render() {
let{datas}=this.props;
return (
<div className=" clearfix edu-back-white" ref='targetElementTrainingjobsetting' style={{margin: "auto", minWidth:"1200px"}}>
<div className="yslquestionbank1">
<div id="MakedownHTML"className="markdown-body yslquesHeigth yslquesmarkdowntext" dangerouslySetInnerHTML={{__html: markdownToHTML("C++是C语言的面向对象扩展是C语言的一个超集同时也是历史最悠久、最受欢迎的程序设计语言之一。根据C++创始人Stroustrup的自述C++是一个“更好的C语言”。\n" +
"\n" +
"输入输出是计算机程序的基本功能。程序本质上是对数据进行处理的一系列操作,一般程序都可以分解为:“数据输入”、“数据处理”和“数据输出”三个步骤。标准输入输出(键盘输入和显示器输出)是程序的重要组成部分。\n" +
"\n" +
"本实训项目的主要目标是学习和掌握C++程序的基本结构和基本输入输出主要内容包括标准C语言自有的单个字符的输入输出、格式化的输入输出以及C++扩展的使用流对象的输入输出").replace(/▁/g, "▁▁▁")}}/>
<div id="MakedownHTML"className="markdown-body yslquesHeigth yslquesmarkdowntext" dangerouslySetInnerHTML={{__html: markdownToHTML(datas&&(datas.description===null?"无":datas.description==="null"?"无":datas.description)).replace(/▁/g, "▁▁▁")}}/>
<GroupPackage></GroupPackage>
{datas.attachments === undefined ? "" : datas.attachments.map((item, key) => {
return (
<GroupPackage key={key} attachments={item}></GroupPackage>
)
})}
<GroupPackage2></GroupPackage2>
<GroupPackage2 datas={datas} bool={true}></GroupPackage2>
</div>

@ -73,18 +73,21 @@ class CreateGroupByImportModal extends Component{
}
onAttachmentRemove = (file) => {
this.props.confirm({
content: '是否确认删除?',
onOk: () => {
this.deleteAttachment(file)
},
onCancel() {
console.log('Cancel');
},
});
return false;
if(file.response!=undefined){
this.props.confirm({
content: '是否确认删除?',
onOk: () => {
this.deleteAttachment(file)
},
onCancel() {
console.log('Cancel');
},
});
return false;
}
}
deleteAttachment = (file) => {
const url = `/attachments/${file.response ? file.response.id : file.uid}.json`

@ -7,8 +7,7 @@ import CourseLayoutcomponent from '../common/CourseLayoutComponent'
import Titlesearchsection from '../common/titleSearch/TitleSearchSection'
import ColorCountText from '../common/titleSearch/ColorCountText'
import { WordsBtn, trigger, on, off ,downloadFile} from 'educoder'
import { WordsBtn, trigger, on, off, getUrl, downloadFile } from 'educoder'
import Modals from "../../modals/Modals";
import axios from 'axios'
import _ from 'lodash'
@ -129,7 +128,8 @@ class studentsList extends Component{
}
/// 确认是否下载
confirmysl(url){
axios.get(url).then((response) => {
// this.props.showGlobalLoading('正在生成文件,请稍后...')
axios.get(url + 'export=true').then((response) => {
if(response === undefined){
return
}
@ -151,10 +151,19 @@ class studentsList extends Component{
})
}
}else {
this.props.showNotification(`正在下载中`);
window.open("/api"+url, '_blank');
// this.props.showNotification(`正在下载中`);
// window.open("/api"+url, '_blank');
this.props.slowDownload(url)
// getUrl() + "/api"+
// const fileUrl = url;
// this.props.slowDownload(fileUrl)
// return;
// downloadFile({
// url: url,
// url: fileUrl,
// successCallback: (url) => {
// console.log('successCallback')
// },
@ -162,6 +171,7 @@ class studentsList extends Component{
// console.log('failCallback')
// }
// })
// window.open(fileUrl, "_self");// , '_blank'
}
}).catch((error) => {
console.log(error)
@ -650,7 +660,7 @@ class studentsList extends Component{
return item.id != course_group_id && (!this.state.groupSearchValue || item.name.indexOf(this.state.groupSearchValue) != -1)
}).map( item => {
return (
<li key={item.id} onClick={() => this.moveToGroup(item)}>{item.name}</li>
<li key={item.id} onClick={() => this.moveToGroup(item)} title={item.name}>{item.name}</li>
)
}) }
{ isAdmin &&

@ -126,7 +126,9 @@ function buildColumns(that) {
sortOrder: sortedInfo.columnKey === 'graduation_group' && sortedInfo.order,
render: text => (
<span>
<span className="overflowHidden1" style={{ maxWidth: '160px'}}
title={`${text && text.length > 10 ? text : ''}`}
>
{text}
</span>
),

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

Loading…
Cancel
Save