diff --git a/Gemfile b/Gemfile index 28df2328c..ac2778c59 100644 --- a/Gemfile +++ b/Gemfile @@ -96,3 +96,5 @@ gem 'searchkick' gem 'aasm' gem 'enumerize' + +gem 'diffy' diff --git a/app/assets/javascripts/admins/laboratories/edit.js b/app/assets/javascripts/admins/laboratories/edit.js new file mode 100644 index 000000000..63b26bbe0 --- /dev/null +++ b/app/assets/javascripts/admins/laboratories/edit.js @@ -0,0 +1,86 @@ +$(document).on('turbolinks:load', function() { + if ($('body.admins-laboratory-settings-show-page, body.admins-laboratory-settings-update-page').length > 0) { + var $container = $('.edit-laboratory-setting-container'); + var $form = $container.find('.edit_laboratory'); + + $('.logo-item-left').on("change", 'input[type="file"]', function () { + var $fileInput = $(this); + var file = this.files[0]; + var imageType = /image.*/; + if (file && file.type.match(imageType)) { + var reader = new FileReader(); + reader.onload = function () { + var $box = $fileInput.parent(); + $box.find('img').attr('src', reader.result).css('display', 'block'); + $box.addClass('has-img'); + }; + reader.readAsDataURL(file); + } else { + } + }); + + createMDEditor('laboratory-footer-editor', { height: 200, placeholder: '请输入备案信息' }); + + $form.validate({ + errorElement: 'span', + errorClass: 'danger text-danger', + errorPlacement:function(error,element){ + if(element.parent().hasClass("input-group")){ + element.parent().after(error); + }else{ + element.after(error) + } + }, + rules: { + identifier: { + required: true, + checkSite: true + }, + name: { + required: true + } + } + }); + $.validator.addMethod("checkSite",function(value,element,params){ + var checkSite = /^(?=^.{3,255}$)[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+$/; + return this.optional(element)||(checkSite.test(value + '.educoder.com')); + },"域名不合法!"); + + $form.on('click', '.submit-btn', function(){ + $form.find('.submit-btn').attr('disabled', 'disabled'); + $form.find('.error').html(''); + var valid = $form.valid(); + + $('input[name="navbar[][name]"]').each(function(_, e){ + var $ele = $(e); + if($ele.val() === undefined || $ele.val().length === 0){ + $ele.addClass('danger text-danger'); + valid = false; + } else { + $ele.removeClass('danger text-danger'); + } + }); + + if(!valid) return; + $.ajax({ + method: 'PATCH', + dataType: 'json', + url: $form.attr('action'), + data: new FormData($form[0]), + processData: false, + contentType: false, + success: function(data){ + $.notify({ message: '保存成功' }); + window.location.reload(); + }, + error: function(res){ + var data = res.responseJSON; + $form.find('.error').html(data.message); + }, + complete: function(){ + $form.find('.submit-btn').attr('disabled', false); + } + }); + }) + } +}); \ No newline at end of file diff --git a/app/assets/javascripts/admins/laboratories/index.js b/app/assets/javascripts/admins/laboratories/index.js new file mode 100644 index 000000000..abb7cb72d --- /dev/null +++ b/app/assets/javascripts/admins/laboratories/index.js @@ -0,0 +1,164 @@ +$(document).on('turbolinks:load', function() { + if ($('body.admins-laboratories-index-page').length > 0) { + var $searchContainer = $('.laboratory-list-form'); + var $searchForm = $searchContainer.find('form.search-form'); + var $list = $('.laboratory-list-container'); + + // ============== 新建 =============== + var $modal = $('.modal.admin-create-laboratory-modal'); + var $form = $modal.find('form.admin-create-laboratory-form'); + var $schoolSelect = $modal.find('.school-select'); + + $form.validate({ + errorElement: 'span', + errorClass: 'danger text-danger', + rules: { + school_id: { + required: true + } + }, + messages: { + school_id: { + required: '请选择所属单位' + } + } + }); + + // modal ready fire + $modal.on('show.bs.modal', function () { + $schoolSelect.select2('val', ' '); + }); + + // ************** 学校选择 ************* + var matcherFunc = function(params, data){ + if ($.trim(params.term) === '') { + return data; + } + if (typeof data.text === 'undefined') { + return null; + } + + if (data.name && data.name.indexOf(params.term) > -1) { + var modifiedData = $.extend({}, data, true); + return modifiedData; + } + + // Return `null` if the term should not be displayed + return null; + }; + + var defineSchoolSelect = function(schools) { + $schoolSelect.select2({ + theme: 'bootstrap4', + placeholder: '请选择单位', + minimumInputLength: 1, + data: schools, + templateResult: function (item) { + if(!item.id || item.id === '') return item.text; + return item.name; + }, + templateSelection: function(item){ + if (item.id) { + $('#school_id').val(item.id); + } + return item.name || item.text; + }, + matcher: matcherFunc + }); + } + + $.ajax({ + url: '/api/schools/for_option.json', + dataType: 'json', + type: 'GET', + success: function(data) { + defineSchoolSelect(data.schools); + } + }); + + $modal.on('click', '.submit-btn', function(){ + $form.find('.error').html(''); + + if ($form.valid()) { + var url = $form.data('url'); + + $.ajax({ + method: 'POST', + dataType: 'json', + url: url, + data: $form.serialize(), + success: function(){ + $.notify({ message: '创建成功' }); + $modal.modal('hide'); + + setTimeout(function(){ + window.location.reload(); + }, 500); + }, + error: function(res){ + var data = res.responseJSON; + $form.find('.error').html(data.message); + } + }); + } + }); + + // ============= 添加管理员 ============== + var $addMemberModal = $('.admin-add-laboratory-user-modal'); + var $addMemberForm = $addMemberModal.find('.admin-add-laboratory-user-form'); + var $memberSelect = $addMemberModal.find('.laboratory-user-select'); + var $laboratoryIdInput = $addMemberForm.find('input[name="laboratory_id"]') + + $addMemberModal.on('show.bs.modal', function(event){ + var $link = $(event.relatedTarget); + var laboratoryId = $link.data('laboratory-id'); + $laboratoryIdInput.val(laboratoryId); + + $memberSelect.select2('val', ' '); + }); + + $memberSelect.select2({ + theme: 'bootstrap4', + placeholder: '请输入要添加的管理员姓名', + multiple: true, + minimumInputLength: 1, + ajax: { + delay: 500, + url: '/admins/users', + dataType: 'json', + data: function(params){ + return { name: params.term }; + }, + processResults: function(data){ + return { results: data.users } + } + }, + templateResult: function (item) { + if(!item.id || item.id === '') return item.text; + return item.real_name; + }, + templateSelection: function(item){ + if (item.id) { + } + return item.real_name || item.text; + } + }); + + $addMemberModal.on('click', '.submit-btn', function(){ + $addMemberForm.find('.error').html(''); + + var laboratoryId = $laboratoryIdInput.val(); + var memberIds = $memberSelect.val(); + if (laboratoryId && memberIds && memberIds.length > 0) { + $.ajax({ + method: 'POST', + dataType: 'script', + url: '/admins/laboratories/' + laboratoryId + '/laboratory_user', + data: { user_ids: memberIds } + }); + } else { + $addMemberModal.modal('hide'); + } + }); + } +}); \ No newline at end of file diff --git a/app/assets/stylesheets/admins/laboratories.scss b/app/assets/stylesheets/admins/laboratories.scss new file mode 100644 index 000000000..ad5c8c5a8 --- /dev/null +++ b/app/assets/stylesheets/admins/laboratories.scss @@ -0,0 +1,99 @@ +.admins-laboratories-index-page { + .laboratory-list-table { + .member-container { + .laboratory-user { + display: flex; + justify-content: center; + flex-wrap: wrap; + + .laboratory-user-item { + display: flex; + align-items: center; + height: 22px; + line-height: 22px; + padding: 2px 5px; + margin: 2px 2px; + border: 1px solid #91D5FF; + background-color: #E6F7FF; + color: #91D5FF; + border-radius: 4px; + } + } + } + } +} +.admins-laboratory-settings-show-page, .admins-laboratory-settings-update-page { + .edit-laboratory-setting-container { + .logo-item { + display: flex; + + &-img { + display: block; + width: 80px; + height: 80px; + } + + &-upload { + cursor: pointer; + position: absolute; + top: 0; + width: 80px; + height: 80px; + background: #F5F5F5; + border: 1px solid #E5E5E5; + + &::before { + content: ''; + position: absolute; + top: 27px; + left: 39px; + width: 2px; + height: 26px; + background: #E5E5E5; + } + + &::after { + content: ''; + position: absolute; + top: 39px; + left: 27px; + width: 26px; + height: 2px; + background: #E5E5E5; + } + } + + &-left { + position: relative; + width: 80px; + height: 80px; + + &.has-img { + .logo-item-upload { + display: none; + } + + &:hover { + .logo-item-upload { + display: block; + background: rgba(145, 145, 145, 0.8); + } + } + } + } + + &-right { + display: flex; + flex-direction: column; + justify-content: space-between; + color: #777777; + font-size: 12px; + } + + &-title { + color: #23272B; + font-size: 14px; + } + } + } +} \ No newline at end of file diff --git a/app/controllers/admins/carousels_controller.rb b/app/controllers/admins/carousels_controller.rb index 67518174c..cd693d2fd 100644 --- a/app/controllers/admins/carousels_controller.rb +++ b/app/controllers/admins/carousels_controller.rb @@ -77,4 +77,4 @@ class Admins::CarouselsController < Admins::BaseController rescue Base64ImageConverter::Error => ex render_error(ex.message) end -end \ No newline at end of file +end diff --git a/app/controllers/admins/laboratories_controller.rb b/app/controllers/admins/laboratories_controller.rb new file mode 100644 index 000000000..e393c6677 --- /dev/null +++ b/app/controllers/admins/laboratories_controller.rb @@ -0,0 +1,32 @@ +class Admins::LaboratoriesController < Admins::BaseController + def index + params[:sort_by] = params[:sort_by].presence || 'id' + params[:sort_direction] = params[:sort_direction].presence || 'desc' + + laboratories = Admins::LaboratoryQuery.call(params) + @laboratories = paginate laboratories.preload(:school, :laboratory_users) + end + + def create + Admins::CreateLaboratoryService.call(create_params) + render_ok + rescue Admins::CreateLaboratoryService::Error => ex + render_error(ex.message) + end + + def destroy + current_laboratory.destroy! + + render_delete_success + end + + private + + def current_laboratory + @_current_laboratory ||= Laboratory.find(params[:id]) + end + + def create_params + params.permit(:school_id) + end +end \ No newline at end of file diff --git a/app/controllers/admins/laboratory_settings_controller.rb b/app/controllers/admins/laboratory_settings_controller.rb new file mode 100644 index 000000000..f9676bfd3 --- /dev/null +++ b/app/controllers/admins/laboratory_settings_controller.rb @@ -0,0 +1,20 @@ +class Admins::LaboratorySettingsController < Admins::BaseController + def show + @laboratory = current_laboratory + end + + def update + Admins::SaveLaboratorySettingService.call(current_laboratory, form_params) + render_ok + end + + private + + def current_laboratory + @_current_laboratory ||= Laboratory.find(params[:laboratory_id]) + end + + def form_params + params.permit(:identifier, :name, :nav_logo, :login_logo, :tab_logo, :footer, navbar: %i[name link hidden]) + end +end \ No newline at end of file diff --git a/app/controllers/admins/laboratory_users_controller.rb b/app/controllers/admins/laboratory_users_controller.rb new file mode 100644 index 000000000..36e389a3e --- /dev/null +++ b/app/controllers/admins/laboratory_users_controller.rb @@ -0,0 +1,19 @@ +class Admins::LaboratoryUsersController < Admins::BaseController + helper_method :current_laboratory + + def create + Admins::AddLaboratoryUserService.call(current_laboratory, params.permit(user_ids: [])) + current_laboratory.reload + end + + def destroy + @laboratory_user = current_laboratory.laboratory_users.find_by(user_id: params[:user_id]) + @laboratory_user.destroy! if @laboratory_user.present? + end + + private + + def current_laboratory + @_current_laboratory ||= Laboratory.find(params[:laboratory_id]) + end +end \ No newline at end of file diff --git a/app/controllers/admins/shixun_settings_controller.rb b/app/controllers/admins/shixun_settings_controller.rb index 0ccd5725d..9202ccce6 100644 --- a/app/controllers/admins/shixun_settings_controller.rb +++ b/app/controllers/admins/shixun_settings_controller.rb @@ -92,6 +92,6 @@ class Admins::ShixunSettingsController < Admins::BaseController end def setting_params - params.permit(:use_scope,:excute_time,:close,:status,:can_copy,:webssh,:hidden,:homepage_show,:task_pass,:code_hidden,:id,tag_repertoires:[]) + params.permit(:use_scope,:excute_time,:close,:status,:can_copy,:webssh,:hidden,:homepage_show,:task_pass,:code_hidden,:page_no, :id,tag_repertoires:[]) end end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 72405739c..53e1be6e7 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -7,6 +7,7 @@ class ApplicationController < ActionController::Base include ControllerRescueHandler include GitHelper include LoggerHelper + include LaboratoryHelper protect_from_forgery prepend: true, unless: -> { request.format.json? } @@ -354,7 +355,7 @@ class ApplicationController < ActionController::Base # 通关后,把最后一次成功的代码存到数据库 # type 0 创始内容, 1 最新内容 def game_passed_code(path, myshixun, game_id) - # 如果代码窗口是隐藏的或者是vnc实训,则不用保存通关代码 + # 如果代码窗口是隐藏的,则不用保存代码 return if myshixun.shixun.hide_code || myshixun.shixun.vnc file_content = git_fle_content myshixun.repo_path, path unless file_content.present? diff --git a/app/controllers/concerns/laboratory_helper.rb b/app/controllers/concerns/laboratory_helper.rb new file mode 100644 index 000000000..fbb18b36d --- /dev/null +++ b/app/controllers/concerns/laboratory_helper.rb @@ -0,0 +1,15 @@ +module LaboratoryHelper + extend ActiveSupport::Concern + + included do + helper_method :default_setting + end + + def current_laboratory + @_current_laboratory ||= (Laboratory.find_by_subdomain(request.subdomain) || Laboratory.find(1)) + end + + def default_setting + @_default_setting ||= LaboratorySetting.find_by(laboratory_id: 1) + end +end \ No newline at end of file diff --git a/app/controllers/courses_controller.rb b/app/controllers/courses_controller.rb index 4bfc236a1..0c643d15c 100644 --- a/app/controllers/courses_controller.rb +++ b/app/controllers/courses_controller.rb @@ -12,10 +12,10 @@ class CoursesController < ApplicationController end before_action :require_login, except: [:index, :show, :students, :teachers, :board_list, :mine, :all_course_groups, - :left_banner, :top_banner, :informs, :online_learning] + :left_banner, :top_banner, :informs, :online_learning, :course_groups] before_action :check_account, only: [:new, :create, :apply_to_join_course, :join_excellent_course] before_action :check_auth, except: [:index, :show, :students, :teachers, :board_list, :mine, :all_course_groups, - :left_banner, :top_banner, :apply_to_join_course, :exit_course] + :left_banner, :top_banner, :apply_to_join_course, :exit_course, :course_groups] before_action :set_course, only: [:show, :update, :destroy, :settings, :set_invite_code_halt, :set_public_or_private, :search_teacher_candidate, :teachers, :apply_teachers, :top_banner, :left_banner, :add_teacher_popup, :add_teacher, @@ -27,7 +27,8 @@ class CoursesController < ApplicationController :attahcment_category_list,:export_member_scores_excel, :duplicate_course, :switch_to_teacher, :switch_to_assistant, :switch_to_student, :exit_course, :informs, :update_informs, :online_learning, :update_task_position, :tasks_list, - :join_excellent_course, :export_couser_info, :export_member_act_score, :new_informs, :delete_informs] + :join_excellent_course, :export_couser_info, :export_member_act_score, :new_informs, + :delete_informs, :change_member_role, :course_groups, :join_course_group] before_action :user_course_identity, except: [:join_excellent_course, :index, :create, :new, :apply_to_join_course, :search_course_list, :get_historical_course_students, :mine, :search_slim, :board_list] before_action :teacher_allowed, only: [:update, :destroy, :settings, :search_teacher_candidate, @@ -39,7 +40,7 @@ class CoursesController < ApplicationController :set_course_group, :create_group_by_importing_file, :update_task_position, :tasks_list] before_action :teacher_or_admin_allowed, only: [:graduation_group_list, :create_graduation_group, :join_graduation_group, - :change_course_teacher, :course_group_list, + :change_course_teacher, :course_group_list, :change_member_role, :teacher_application_review, :apply_teachers, :delete_course_teacher] before_action :validate_course_name, only: [:create, :update] before_action :find_board, only: :board_list @@ -340,8 +341,8 @@ class CoursesController < ApplicationController @has_graduation_design = @course.course_modules.graduation_module_not_hidden.any? - sort = params[:sort] || "desc" - @order = params[:order].to_i + sort = params[:sort] || "asc" + @order = params[:order] ? params[:order].to_i : 1 if @order.present? case @order when 1 @@ -547,6 +548,61 @@ class CoursesController < ApplicationController end end + # 修改角色 + def change_member_role + tip_exception("请至少选择一个角色") if params[:roles].blank? + tip_exception("不能具有老师、助教两种角色") if params[:roles].include?("PROFESSOR") && params[:roles].include?("ASSISTANT_PROFESSOR") + tip_exception("管理员不能切换为助教或老师") if params[:user_id].to_i == @course.tea_id && + (params[:roles].include?("PROFESSOR") || params[:roles].include?("ASSISTANT_PROFESSOR")) + + course_members = @course.course_members.where(user_id: params[:user_id]) + tip_exception("非课堂成员不能修改角色") if course_members.blank? + + ActiveRecord::Base.transaction do + # 第一次修改为教师或助教身份时直接创建数据 + if params[:roles].include?("CREATOR") + teacher_member = course_members.where(role: %i[CREATOR]).take + elsif (params[:roles].include?("PROFESSOR") || params[:roles].include?("ASSISTANT_PROFESSOR")) && !course_members.exists?(role: %i[PROFESSOR ASSISTANT_PROFESSOR]) + teacher_member = CourseMember.create!(course_id: @course.id, user_id: params[:user_id], role: params[:roles].include?("PROFESSOR") ? 2 : 3) + elsif course_members.exists?(role: %i[PROFESSOR ASSISTANT_PROFESSOR]) + teacher_member = course_members.where(role: %i[PROFESSOR ASSISTANT_PROFESSOR]).take + if params[:roles].include?("PROFESSOR") || params[:roles].include?("ASSISTANT_PROFESSOR") + # 如果之前有老师身份且老师身份要调整时,只需要修改role字段 + if !params[:roles].include?(teacher_member.role) && params[:roles].include?("PROFESSOR") + teacher_member.PROFESSOR! + elsif !params[:roles].include?(teacher_member.role) && params[:roles].include?("ASSISTANT_PROFESSOR") + teacher_member.ASSISTANT_PROFESSOR! + end + teacher_member.save! + else + # 不含教师的参数时删除记录 + teacher_member.destroy! + # CourseDeleteStudentNotifyJob.perform_later(@course.id, [teacher_member.user_id], current_user.id) + end + end + + # 学生身份的处理 + student_member = course_members.where(role: %i[STUDENT]).take + if params[:roles].include?("STUDENT") && student_member.blank? + correspond_teacher_exist = CourseMember.exists?(user_id: params[:user_id], is_active: 1, course_id: @course.id, role: %i[CREATOR PROFESSOR ASSISTANT_PROFESSOR]) + new_student = CourseMember.new(user_id: params[:user_id], course_id: @course.id, role: 4) + new_student.is_active = 0 if correspond_teacher_exist + new_student.save! + + CourseAddStudentCreateWorksJob.perform_later(@course.id, [params[:user_id]]) + # StudentJoinCourseNotifyJob.perform_later(current_user.id, course.id) + elsif !params[:roles].include?("STUDENT") && student_member.present? + # 删除学生身份时激活老师身份 + teacher_member.update_attributes!(is_active: 1) if student_member.is_active && teacher_member.present? + student_member.destroy! + CourseDeleteStudentDeleteWorksJob.perform_later(@course.id, [params[:user_id]]) + # CourseDeleteStudentNotifyJob.perform_later(@course.id, [params[:user_id]], current_user.id) + end + + normal_status(0, "修改成功") + end + end + # 教师和助教角色转换的接口 def change_course_teacher begin @@ -715,8 +771,8 @@ class CoursesController < ApplicationController # 学生列表(包括各个子分班的学生列表)及搜索 def students search = params[:search].present? ? params[:search].strip : nil - order = params[:order].present? ? params[:order].to_i : 0 - sort = params[:sort].present? ? params[:sort] : "desc" + order = params[:order].present? ? params[:order].to_i : 1 + sort = params[:sort].present? ? params[:sort] : "asc" course_group_id = params[:course_group_id].present? ? params[:course_group_id].to_i : nil @students = CourseMember.students(@course) @@ -766,6 +822,26 @@ class CoursesController < ApplicationController end end + # 分班列表 + def course_groups + @course_groups = @course.course_groups + @course_groups = @course_groups.where("name like ?", "%#{params[:search]}%") unless params[:search].blank? + @all_group_count = @course_groups.size + @teachers = @course.teachers.includes(:user, :teacher_course_groups) if @user_course_identity < Course::NORMAL + @current_group_id = @course.students.where(user_id: current_user.id).take&.course_group_id if @user_course_identity == Course::STUDENT + end + + # 学生自动加入分班 + def join_course_group + tip_exception("学生才能加入分班") if @user_course_identity != Course::STUDENT + course_group = CourseGroup.find_by!(id: params[:course_group_id], course_id: @course.id) + member = CourseMember.find_by!(user_id: current_user.id, course_id: @course.id, role: 4) + if course_group && member + member.update_attributes!(course_group_id: course_group.id) + normal_status(0, "加入成功") + end + end + # 将学生批量移动到某个分班 def transfer_to_course_group ActiveRecord::Base.transaction do diff --git a/app/controllers/ecs/course_achievement_methods_controller.rb b/app/controllers/ecs/course_achievement_methods_controller.rb index 389169258..4a9968fb2 100644 --- a/app/controllers/ecs/course_achievement_methods_controller.rb +++ b/app/controllers/ecs/course_achievement_methods_controller.rb @@ -1,17 +1,22 @@ class Ecs::CourseAchievementMethodsController < Ecs::CourseBaseController def show - include_associations = { ec_course_achievement_methods: [:ec_course_evaluation, :ec_course_evaluation_subitems] } + include_associations = { ec_course_achievement_methods: + [:ec_course_evaluation, ec_achievement_evaluation_relates: :ec_course_evaluation_subitem] } @course_targets = current_course.ec_course_targets.includes(include_associations) end def create - @course_target = Ecs::CreateCourseAchievementMethodsService.call(current_course_target, create_params) + Ecs::CreateCourseAchievementMethodsService.call(current_course_target, create_params) + render_ok end private def create_params - params.permit(course_achievement_methods: %i[id course_evaluation_id course_evaluation_subitem_ids score percentage]) + params.permit(course_achievement_methods: [ + :id, :course_evaluation_id, :score, :percentage, + course_evaluation_relates: %i[:subitem_id position] + ]) end def current_course_target diff --git a/app/controllers/ecs/course_managers_controller.rb b/app/controllers/ecs/course_managers_controller.rb index 714dac580..132a212d7 100644 --- a/app/controllers/ecs/course_managers_controller.rb +++ b/app/controllers/ecs/course_managers_controller.rb @@ -3,7 +3,8 @@ class Ecs::CourseManagersController < Ecs::CourseBaseController before_action :check_major_manager_permission!, only: [:create, :destroy] def create - @user = Ecs::CreateCourseManagerService.call(current_course, params[:user_id]) + Ecs::CreateCourseManagerService.call(current_course, params[:user_ids]) + render_ok rescue Ecs::CreateCourseManagerService::Error => ex render_error(ex.message) end diff --git a/app/controllers/ecs/course_targets_controller.rb b/app/controllers/ecs/course_targets_controller.rb index e5ac4b36e..bcd09f64a 100644 --- a/app/controllers/ecs/course_targets_controller.rb +++ b/app/controllers/ecs/course_targets_controller.rb @@ -20,8 +20,8 @@ class Ecs::CourseTargetsController < Ecs::CourseBaseController def with_achievement_methods @course_targets = current_course.ec_course_targets - .includes(:ec_graduation_subitems, - ec_course_achievement_methods: [:ec_course_evaluation, :ec_course_evaluation_subitems]) + .includes(ec_course_achievement_methods: + [:ec_course_evaluation, ec_achievement_evaluation_relates: :ec_course_evaluation_subitem]) end private diff --git a/app/controllers/ecs/evaluations_controller.rb b/app/controllers/ecs/evaluations_controller.rb index 18a78e1c9..09151132f 100644 --- a/app/controllers/ecs/evaluations_controller.rb +++ b/app/controllers/ecs/evaluations_controller.rb @@ -5,8 +5,9 @@ class Ecs::EvaluationsController < Ecs::CourseBaseController render_ok( course_targets: service.course_targets, course_achievement: service.course_achievement, + course_rate: service.course_rate, graduation_subitem_evaluations: service.graduation_subitem_evaluations, - score_levels_map: service.score_levels_map + score_levels: service.score_levels ) end diff --git a/app/controllers/exercises_controller.rb b/app/controllers/exercises_controller.rb index f2e8508f0..191825cc3 100644 --- a/app/controllers/exercises_controller.rb +++ b/app/controllers/exercises_controller.rb @@ -46,8 +46,8 @@ class ExercisesController < ApplicationController @exercises = member_show_exercises.exists? ? member_show_exercises.unified_setting : [] else #已分班级的成员,可以查看统一设置和单独设置(试卷是发布在该班级)试卷 # 已发布 当前用户班级分组的 试卷id - not_exercise_ids = @course.exercise_group_settings.exercise_group_not_published.where("course_group_id = #{@member_group_id}").pluck(:exercise_id) - @exercises = member_show_exercises.where.not(id: not_exercise_ids) + publish_exercise_ids = @course.exercise_group_settings.exercise_group_published.where("course_group_id = #{@member_group_id}").pluck(:exercise_id) + @exercises = member_show_exercises.unified_setting.or(member_show_exercises.where(id: publish_exercise_ids)) end else #用户未登陆或不是该课堂成员,仅显示统一设置的(已发布的/已截止的),如有公开,则不显示锁,不公开,则显示锁 @is_teacher_or = 0 @@ -683,12 +683,34 @@ class ExercisesController < ApplicationController end end + # 详情页的立即发布弹框 + def publish_groups + @current_user = current_user + # 可立即发布的分班:当前用户管理的分班去除已发布的分班 + group_ids = @course.charge_group_ids(@current_user) - @exercise.exercise_group_settings.exercise_group_published.pluck(:course_group_id) + @course_groups = @course.course_groups.where(id: group_ids) + @group_settings = @exercise.exercise_group_settings.where(course_group_id: group_ids) + end + #首页批量或单独 立即发布,应是跳出弹窗,设置开始时间和截止时间。 def publish - tip_exception("缺少截止时间参数") if params[:end_time].blank? - tip_exception("截止时间不能早于当前时间") if params[:end_time] <= strf_time(Time.now) - tip_exception("截止时间不能晚于课堂结束时间(#{@course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")})") if - @course.end_date.present? && params[:end_time] > strf_time(@course.end_date.end_of_day) + group_ids = params[:group_ids]&.reject(&:blank?) + if params[:detail].blank? + tip_exception("缺少截止时间参数") if params[:end_time].blank? + tip_exception("截止时间不能早于当前时间") if params[:end_time] <= strf_time(Time.now) + tip_exception("截止时间不能晚于课堂结束时间(#{@course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")})") if + @course.end_date.present? && params[:end_time] > strf_time(@course.end_date.end_of_day) + else + group_end_times = params[:group_end_times].reject(&:blank?).map{|time| time.to_time} + tip_exception("缺少截止时间参数") if group_end_times.blank? + tip_exception("截止时间和分班参数的个数不一致") if group_end_times.length != group_ids.length + group_end_times.each do |time| + tip_exception("分班截止时间不能早于当前时间") if time <= Time.now + tip_exception("分班截止时间不能晚于课堂结束时间(#{@course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")})") if + @course.end_date.present? && time > @course.end_date.end_of_day + end + end + ActiveRecord::Base.transaction do begin check_ids = Exercise.where(id: params[:check_ids]) @@ -702,28 +724,30 @@ class ExercisesController < ApplicationController .exercise_group_not_published.present? ? 1 : 0 end if ex_status == 1 #如果试卷存在已发布的,或者是已截止的,那么则直接跳过 - g_course = params[:group_ids] #表示是否传入分班参数,如果传入分班的参数,那么试卷的统一设置需修改 + g_course = group_ids #表示是否传入分班参数,如果传入分班的参数,那么试卷的统一设置需修改 tiding_group_ids = g_course if g_course - user_course_groups = @course.charge_group_ids(current_user) - if g_course.map(&:to_i).sort == user_course_groups.sort # 如果是设置为全部班级,则试卷不用分组,且试卷设定为统一设置,否则则分组设置 + user_course_groups = @course.course_groups.pluck(:id) + if g_course.map(&:to_i).sort == user_course_groups.sort && + ((params[:detail] && group_end_times.min == group_end_times.max) || params[:detail].blank?) # 如果是设置为全部班级,则试卷不用分组,且试卷设定为统一设置,否则则分组设置 exercise.exercise_group_settings.destroy_all ex_unified = true - e_time = ex_end_time + e_time = params[:detail] ? group_end_times.max : ex_end_time tiding_group_ids = [] else ex_unified = false - g_course.each do |i| + g_course.each_with_index do |i, index| exercise_group_setting = exercise.exercise_group_settings.find_in_exercise_group("course_group_id",i).first #根据课堂分班的id,寻找试卷所在的班级 + group_end_time = params[:detail] ? group_end_times[index] : ex_end_time if exercise_group_setting #如果该试卷分组存在,则更新,否则新建 - exercise_group_setting.update_attributes(publish_time:Time.now,end_time:ex_end_time) + exercise_group_setting.update_attributes(publish_time: Time.now, end_time: group_end_time) else p_course_group = { :exercise_id => exercise.id, :course_group_id => i, :course_id => exercise.course.id, :publish_time => Time.now, - :end_time => ex_end_time, + :end_time => group_end_time, } new_exercise_group = exercise.exercise_group_settings.new p_course_group new_exercise_group.save @@ -954,7 +978,8 @@ class ExercisesController < ApplicationController :status => nil, :commit_status => 0, :objective_score => 0.0, - :subjective_score => -1.0 + :subjective_score => -1.0, + :commit_method => 0 } redo_exercise_users = @exercise_users.exercise_commit_users(user_ids) redo_exercise_users.update_all(redo_option) @@ -1077,22 +1102,40 @@ class ExercisesController < ApplicationController def commit_exercise ActiveRecord::Base.transaction do begin - if @user_course_identity > Course::ASSISTANT_PROFESSOR #为学生时 - objective_score = calculate_student_score(@exercise,current_user)[:total_score] - subjective_score = @answer_committed_user.subjective_score - total_score_subjective_score = subjective_score < 0.0 ? 0.0 : subjective_score - total_score = objective_score + total_score_subjective_score - commit_option = { + can_commit_exercise = false + user_left_time = nil + if @user_course_identity > Course::ASSISTANT_PROFESSOR #为学生时 + if params[:commit_method].to_i == 2 #自动提交时 + user_left_time = get_exercise_left_time(@exercise,current_user) + Rails.logger.info("######__________auto_commit_user_left_time_________################{user_left_time}") + if user_left_time.to_i <= 0 + can_commit_exercise = true + end + else + can_commit_exercise = true + end + if can_commit_exercise + objective_score = calculate_student_score(@exercise,current_user)[:total_score] + subjective_score = @answer_committed_user.subjective_score + total_score_subjective_score = subjective_score < 0.0 ? 0.0 : subjective_score + total_score = objective_score + total_score_subjective_score + commit_option = { :status => 1, :commit_status => 1, :end_at => Time.now, :objective_score => objective_score, :score => total_score, - :subjective_score => subjective_score - } - @answer_committed_user.update_attributes(commit_option) - CommitExercsieNotifyJobJob.perform_later(@exercise.id, current_user.id) - normal_status(0,"试卷提交成功!") + :subjective_score => subjective_score, + :commit_method => @answer_committed_user&.commit_method.to_i > 0 ? @answer_committed_user&.commit_method.to_i : params[:commit_method].to_i + } + @answer_committed_user.update_attributes(commit_option) + CommitExercsieNotifyJobJob.perform_later(@exercise.id, current_user.id) + normal_status(0,"试卷提交成功!") + else + normal_status(-2,"#{user_left_time.to_i}") + end + else + normal_status(-1,"提交失败,当前用户不为课堂学生!") end rescue Exception => e uid_logger_error(e.message) diff --git a/app/controllers/home_controller.rb b/app/controllers/home_controller.rb index 665eaa294..2ed82f1b5 100644 --- a/app/controllers/home_controller.rb +++ b/app/controllers/home_controller.rb @@ -5,7 +5,7 @@ class HomeController < ApplicationController images = PortalImage.where(status: true).order("position asc") @images_url = [] images.each do |image| - @images_url << {path: image.link, image_url: "/images/avatars/PortalImage/#{image.id}"} + @images_url << {path: image.link, image_url: Util::FileManage.disk_file_url('PortalImage', image.id)} end # 目录分级 diff --git a/app/controllers/homework_commons_controller.rb b/app/controllers/homework_commons_controller.rb index 06ee8feee..83b80bec4 100644 --- a/app/controllers/homework_commons_controller.rb +++ b/app/controllers/homework_commons_controller.rb @@ -159,8 +159,13 @@ class HomeworkCommonsController < ApplicationController end # 作品状态 0: 未提交, 1 按时提交, 2 延迟提交 - unless params[:work_status].blank? - @student_works = @student_works.where(work_status: params[:work_status]) + if params[:work_status].present? + work_status = params[:work_status].map{|status| status.to_i} + all_student_works = @student_works.left_joins(:myshixun) + @student_works = all_student_works.where(work_status: work_status) + + @student_works = @student_works.or(all_student_works.where(work_status: 0)).or(all_student_works.where(myshixuns: {status: 0})) if work_status.include?(3) + @student_works = @student_works.or(all_student_works.where(myshixuns: {status: 1})) if work_status.include?(4) end # 分班情况 @@ -201,12 +206,12 @@ class HomeworkCommonsController < ApplicationController page = params[:page] || 1 limit = params[:limit] || 20 @student_works = @student_works.page(page).per(limit) - @students = @course.students.where(user_id: @student_works.pluck(:user_id)).preload(:course_group) if @homework.homework_type == "practice" @student_works = @student_works.includes(:student_works_scores, user: :user_extension, myshixun: :games) else @student_works = @student_works.includes(:student_works_scores, :project, user: :user_extension) end + @students = @course.students.preload(:course_group) end if params[:format] == "xlsx" @@ -1036,6 +1041,7 @@ class HomeworkCommonsController < ApplicationController # 可立即发布的分班:当前用户管理的分班去除已发布的分班 group_ids = @course.charge_group_ids(@current_user) - @homework.homework_group_settings.group_published.pluck(:course_group_id) @course_groups = @course.course_groups.where(id: group_ids) + @group_settings = @homework.homework_group_settings.where(course_group_id: group_ids) else tip_exception("没有可发布的分班") end @@ -1043,16 +1049,28 @@ class HomeworkCommonsController < ApplicationController def publish_homework tip_exception("请至少选择一个分班") if params[:group_ids].blank? && @course.course_groups.size != 0 - tip_exception("缺少截止时间参数") if params[:end_time].blank? - tip_exception("截止时间不能早于当前时间") if params[:end_time] <= strf_time(Time.now) - tip_exception("截止时间不能晚于课堂结束时间(#{@course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")})") if - @course.end_date.present? && params[:end_time] > strf_time(@course.end_date.end_of_day) + group_ids = params[:group_ids]&.reject(&:blank?) + if params[:detail].blank? + tip_exception("缺少截止时间参数") if params[:end_time].blank? + tip_exception("截止时间不能早于当前时间") if params[:end_time] <= strf_time(Time.now) + tip_exception("截止时间不能晚于课堂结束时间(#{@course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")})") if + @course.end_date.present? && params[:end_time] > strf_time(@course.end_date.end_of_day) + else + group_end_times = params[:group_end_times].reject(&:blank?).map{|time| time.to_time} + tip_exception("缺少截止时间参数") if group_end_times.blank? + tip_exception("截止时间和分班参数的个数不一致") if group_end_times.length != group_ids.length + group_end_times.each do |time| + tip_exception("分班截止时间不能早于当前时间") if time <= Time.now + tip_exception("分班截止时间不能晚于课堂结束时间(#{@course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")})") if + @course.end_date.present? && time > @course.end_date.end_of_day + end + end homeworks = @course.homework_commons.where(id: params[:homework_ids]) homeworks = homeworks.includes(:homework_group_settings, :homework_detail_manual) charge_group_ids = @course.charge_group_ids(current_user) - publish_groups = charge_group_ids & params[:group_ids] if params[:group_ids] + publish_groups = charge_group_ids & group_ids if group_ids # ActiveRecord::Base.transaction do begin @@ -1062,18 +1080,26 @@ class HomeworkCommonsController < ApplicationController if !params[:group_ids].blank? # 全选即统一设置,unified_setting为true - if @course.course_groups.where(id: publish_groups).size == @course.course_groups.size + if @course.course_groups.where(id: publish_groups).size == @course.course_groups.size && + ((params[:detail] && group_end_times.min == group_end_times.max) || params[:detail].blank?) homework.homework_group_settings.destroy_all homework.unified_setting = true - homework.end_time = params[:end_time] + homework.end_time = params[:detail] ? group_end_times.max : params[:end_time] else homework.unified_setting = false # 创建作业分班设置:homework_group_setting create_homework_group_settings(homework) # 选中的分班设置的发布时间改为当前时间,截止时间改为传的截止时间参数 - homework.homework_group_settings.where(course_group_id: publish_groups).update_all(publish_time: Time.now, - end_time: params[:end_time]) + if params[:detail] + group_ids.each_with_index do |group_id, index| + homework.homework_group_settings.find_by(course_group_id: group_id)&.update_attributes!(publish_time: Time.now, + end_time: group_end_times[index]) + end + else + homework.homework_group_settings.where(course_group_id: publish_groups).update_all(publish_time: Time.now, + end_time: params[:end_time]) + end # 发消息 tiding_group_ids = publish_groups end @@ -1086,7 +1112,7 @@ class HomeworkCommonsController < ApplicationController # 截止时间的处理 if homework.end_time.nil? - homework.end_time = params[:end_time] + homework.end_time = params[:detail] ? group_end_times.max : params[:end_time] elsif homework.max_group_end_time homework.end_time = homework.max_group_end_time end @@ -1101,12 +1127,22 @@ class HomeworkCommonsController < ApplicationController create_homework_group_settings(homework) none_publish_settings = homework.homework_group_settings.where(course_group_id: publish_groups).none_published - none_publish_settings.update_all(publish_time: Time.now, end_time: params[:end_time]) + if params[:detail] + group_ids.each_with_index do |group_id, index| + none_publish_settings.find_by(course_group_id: group_id)&.update_attributes!(publish_time: Time.now, + end_time: group_end_times[index]) + end + else + none_publish_settings.update_all(publish_time: Time.now, end_time: params[:end_time]) + end + if homework.max_group_end_time homework.end_time = homework.max_group_end_time end HomeworkCommonPushNotifyJob.perform_later(homework.id, none_publish_settings.pluck(:course_group_id)) end + + if homework.end_time > Time.now && homework.homework_detail_manual.try(:comment_status) > 1 homework.homework_detail_manual.update_attribute("comment_status", 1) end diff --git a/app/controllers/memos_controller.rb b/app/controllers/memos_controller.rb index 88139fe7e..d2c386681 100644 --- a/app/controllers/memos_controller.rb +++ b/app/controllers/memos_controller.rb @@ -25,9 +25,9 @@ class MemosController < ApplicationController !search.blank? ? "forum_id = #{forum_id} and root_id is null and subject like '%#{search}%'" : "forum_id = #{forum_id} and root_id is null" elsif !search.blank? - "forum_id in(3, 5) and root_id is null and subject like '%#{search}%'" + "forum_id in(3, 5, 16) and root_id is null and subject like '%#{search}%'" else - "forum_id in(3, 5) and root_id is null" + "forum_id in(3, 5, 16) and root_id is null" end if tag_repertoire_id diff --git a/app/controllers/myshixuns_controller.rb b/app/controllers/myshixuns_controller.rb index bf067b389..74f02f1ab 100644 --- a/app/controllers/myshixuns_controller.rb +++ b/app/controllers/myshixuns_controller.rb @@ -326,7 +326,7 @@ class MyshixunsController < ApplicationController if edu_css.present? css_path = edu_css.split(",") css_path.each do |path| - file_content = GitService.file_content(repo_path: @repo_path, path: path)["content"] + file_content = git_fle_content(@repo_path, path)["content"] file_content = tran_base64_decode64(file_content) unless file_content.blank? @contents = @contents.sub(/EDUCODERCSS/, "") end @@ -335,7 +335,7 @@ class MyshixunsController < ApplicationController if edu_js.present? js_path = edu_js.split(",") js_path.each do |path| - file_content = GitService.file_content(repo_path: @repo_path, path: path)["content"] + file_content = git_fle_content(@repo_path, path)["content"] file_content = tran_base64_decode64(file_content) unless file_content.blank? @contents = @contents.sub(/EDUCODERJS/, "") end diff --git a/app/controllers/polls_controller.rb b/app/controllers/polls_controller.rb index 6ffe277a3..da5917e1b 100644 --- a/app/controllers/polls_controller.rb +++ b/app/controllers/polls_controller.rb @@ -2,10 +2,10 @@ class PollsController < ApplicationController # before_action :check_poll_status 问卷的发消息和定时任务没有做 before_action :require_login, :check_auth,except: [:index] before_action :find_course, except: [:show,:poll_setting,:commit_setting,:edit,:update,:start_answer,:commit_poll, - :commit_result,:poll_lists,:cancel_publish,:cancel_publish_modal,:common_header] + :commit_result,:poll_lists,:cancel_publish,:cancel_publish_modal,:common_header,:publish_groups] before_action :get_poll_and_course, only: [:show,:poll_setting,:commit_setting,:edit,:update,:start_answer, :commit_poll,:commit_result,:poll_lists,:cancel_publish, - :cancel_publish_modal,:common_header] + :cancel_publish_modal,:common_header, :publish_groups] before_action :user_course_identity before_action :is_course_teacher, except: [:index,:start_answer,:poll_setting,:commit_poll,:commit_result,:poll_lists,:common_header] #判断是否为课堂老师 before_action :check_user_status @@ -242,12 +242,35 @@ class PollsController < ApplicationController end end end + + # 详情页的立即发布弹框 + def publish_groups + @current_user = current_user + # 可立即发布的分班:当前用户管理的分班去除已发布的分班 + group_ids = @course.charge_group_ids(@current_user) - @poll.poll_group_settings.poll_group_published.pluck(:course_group_id) + @course_groups = @course.course_groups.where(id: group_ids) + @group_settings = @poll.poll_group_settings.where(course_group_id: group_ids) + end + #首页批量或单独 立即发布,应是跳出弹窗,设置开始时间和截止时间。 def publish - tip_exception("缺少截止时间参数") if params[:end_time].blank? - tip_exception("截止时间不能早于当前时间") if params[:end_time] <= strf_time(Time.now) - tip_exception("截止时间不能晚于课堂结束时间(#{@course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")})") if - @course.end_date.present? && params[:end_time] > strf_time(@course.end_date.end_of_day) + group_ids = params[:group_ids]&.reject(&:blank?) + if params[:detail].blank? + tip_exception("缺少截止时间参数") if params[:end_time].blank? + tip_exception("截止时间不能早于当前时间") if params[:end_time] <= strf_time(Time.now) + tip_exception("截止时间不能晚于课堂结束时间(#{@course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")})") if + @course.end_date.present? && params[:end_time] > strf_time(@course.end_date.end_of_day) + else + group_end_times = params[:group_end_times].reject(&:blank?).map{|time| time.to_time} + tip_exception("缺少截止时间参数") if group_end_times.blank? + tip_exception("截止时间和分班参数的个数不一致") if group_end_times.length != group_ids.length + group_end_times.each do |time| + tip_exception("分班截止时间不能早于当前时间") if time <= Time.now + tip_exception("分班截止时间不能晚于课堂结束时间(#{@course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")})") if + @course.end_date.present? && time > @course.end_date.end_of_day + end + end + ActiveRecord::Base.transaction do begin check_ids = Poll.where(id: params[:check_ids]) @@ -259,26 +282,28 @@ class PollsController < ApplicationController pl_status = poll.poll_group_settings.find_in_poll_group("course_group_id",params[:group_ids]).poll_group_not_published.present? ? 1 : 0 #立即发布针对分组设置的全部未发布的班级才生效 end if pl_status == 1 #如果问卷存在已发布的,或者是已截止的,那么则直接跳过 - g_course = params[:group_ids] #表示是否传入分班参数,如果传入分班的参数,那么poll的统一设置需修改 + g_course = group_ids #表示是否传入分班参数,如果传入分班的参数,那么poll的统一设置需修改 if g_course - user_course_groups = @course.charge_group_ids(current_user) - if g_course.map(&:to_i).sort == user_course_groups.sort # 如果是设置为全部班级,则问卷不用分组,且问卷设定为统一设置,否则则分组设置 + user_course_groups = @course.course_groups.pluck(:id) + if g_course.map(&:to_i).sort == user_course_groups.sort && + ((params[:detail] && group_end_times.min == group_end_times.max) || params[:detail].blank?) # 如果是设置为全部班级,则问卷不用分组,且问卷设定为统一设置,否则则分组设置 poll.poll_group_settings.destroy_all poll_unified = true - e_time = ex_end_time + e_time = params[:detail] ? group_end_times.max : ex_end_time else poll_unified = false - g_course.each do |i| + g_course.each_with_index do |i, index| poll_group_setting = poll.poll_group_settings.find_in_poll_group("course_group_id",i).first #根据课堂分班的id,寻找问卷所在的班级 + group_end_time = params[:detail] ? group_end_times[index] : ex_end_time if poll_group_setting #如果该问卷分组存在,则更新,否则新建 - poll_group_setting.update_attributes(publish_time:Time.now,end_time:ex_end_time) + poll_group_setting.update_attributes(publish_time: Time.now, end_time: group_end_time) else p_course_group = { :poll_id => poll.id, :course_group_id => i, :course_id => poll.course.id, :publish_time => Time.now, - :end_time => ex_end_time, + :end_time => group_end_time, } new_poll_group = poll.poll_group_settings.new p_course_group new_poll_group.save @@ -692,7 +717,7 @@ class PollsController < ApplicationController else unified_setting = @poll.unified_setting end - show_result = params[:show_result].to_i + show_result = params[:show_result] un_anonymous = params[:un_anonymous] ? true : false # 统一设置或者分班为0,则更新问卷,并删除问卷分组 if unified_setting || (course_group_ids.size == 0) @@ -1318,7 +1343,7 @@ class PollsController < ApplicationController poll_ques_titles = poll_questions.pluck(:question_title).map {|k| ActionController::Base.helpers.strip_tags(k) if k.present?} poll_un_anony = poll.un_anonymous if poll_un_anony #是否匿名,默认为false - user_info = %w(登陆名 真实姓名 邮箱 学号) + user_info = %w(登陆名 真实姓名 邮箱 学号 学员单位) else user_info = [] end @@ -1392,7 +1417,8 @@ class PollsController < ApplicationController user_login = u_user.login user_name = u_user.real_name.present? ? u_user.real_name : "--" user_student_id = u_user.student_id.present? ? u_user.student_id : "--" - user_cell += [user_login,user_name, u_user.mail, user_student_id] + user_school_name = u_user.school_name.present? ? u_user.school_name : "--" + user_cell += [user_login,user_name, u_user.mail, user_student_id, user_school_name] end all_user_cell = user_cell + user_answer_array user_commit.push(all_user_cell) diff --git a/app/controllers/question_banks_controller.rb b/app/controllers/question_banks_controller.rb index 47181bd46..f6b321e1b 100644 --- a/app/controllers/question_banks_controller.rb +++ b/app/controllers/question_banks_controller.rb @@ -90,23 +90,25 @@ class QuestionBanksController < ApplicationController def send_to_course banks = @object_type.classify.constantize.where(id: params[:object_id]) course = current_user.manage_courses.find_by!(id: params[:course_id]) + task_ids = [] banks.each do |bank| case @object_type when 'HomeworkBank' # 作业 - quote_homework_bank bank, course + task = quote_homework_bank bank, course when 'ExerciseBank' if bank.container_type == 'Exercise' # 试卷 - quote_exercise_bank bank, course + task = quote_exercise_bank bank, course else # 问卷 - quote_poll_bank bank, course + task = quote_poll_bank bank, course end when 'GtaskBank' - quote_gtask_bank bank, course + task = quote_gtask_bank bank, course when 'GtopicBank' - quote_gtopic_bank bank, course + task = quote_gtopic_bank bank, course end + task_ids << task.id if task end - normal_status("发送成功") + render :json => {task_ids: task_ids, status: 0, message: "发送成功"} end def destroy diff --git a/app/controllers/settings_controller.rb b/app/controllers/settings_controller.rb new file mode 100644 index 000000000..ce5481147 --- /dev/null +++ b/app/controllers/settings_controller.rb @@ -0,0 +1,5 @@ +class SettingsController < ApplicationController + def show + @laboratory = current_laboratory + end +end \ No newline at end of file diff --git a/app/controllers/shixuns_controller.rb b/app/controllers/shixuns_controller.rb index 07107b91f..d0bd4fb0d 100644 --- a/app/controllers/shixuns_controller.rb +++ b/app/controllers/shixuns_controller.rb @@ -2,6 +2,7 @@ class ShixunsController < ApplicationController include ShixunsHelper include ApplicationHelper include ElasticsearchAble + include CoursesHelper before_action :require_login, :check_auth, except: [:download_file, :index, :menus, :show, :show_right, :ranking_list, :discusses, :collaborators, :fork_list, :propaedeutics] diff --git a/app/controllers/templates_controller.rb b/app/controllers/templates_controller.rb new file mode 100644 index 000000000..efb114bdc --- /dev/null +++ b/app/controllers/templates_controller.rb @@ -0,0 +1,5 @@ +class TemplatesController < ApplicationController + def show + @template = EcTemplate.find_by_name!(params[:name]) + end +end \ No newline at end of file diff --git a/app/controllers/wechats/js_sdk_signatures_controller.rb b/app/controllers/wechats/js_sdk_signatures_controller.rb index 0b66cc263..4ed1680b0 100644 --- a/app/controllers/wechats/js_sdk_signatures_controller.rb +++ b/app/controllers/wechats/js_sdk_signatures_controller.rb @@ -2,10 +2,10 @@ class Wechats::JsSdkSignaturesController < ApplicationController def create timestamp = Time.now.to_i noncestr = ('A'..'z').to_a.sample(8).join - signature = Util::Wechat.js_sdk_signature(params[:url], noncestr, timestamp) + signature = Wechat::OfficialAccount.js_sdk_signature(params[:url], noncestr, timestamp) - render_ok(appid: Util::Wechat.appid, timestamp: timestamp, noncestr: noncestr, signature: signature) - rescue Util::Wechat::Error => ex + render_ok(appid: Wechat::OfficialAccount.appid, timestamp: timestamp, noncestr: noncestr, signature: signature) + rescue Wechat::Error => ex render_error(ex.message) end end \ No newline at end of file diff --git a/app/helpers/courses_helper.rb b/app/helpers/courses_helper.rb index d670614d5..fb7bd1a88 100644 --- a/app/helpers/courses_helper.rb +++ b/app/helpers/courses_helper.rb @@ -1,6 +1,18 @@ module CoursesHelper - # 是否有切换为学生的入口 + def member_manager group, teachers + str = "" + members = teachers.select{|teacher| teacher.teacher_course_groups.pluck(:course_group_id).include?(group.id) || teacher.teacher_course_groups.size == 0} + str = members.uniq.size == teachers.size ? "全部教师" : members.map{|member| member.user.real_name}.join("、") + str + # teachers.each do |member| + # if member.teacher_course_groups.exists?(course_group_id: group.id) || member.teacher_course_groups.size == 0 + # str << member.user.real_name + # end + # end + end + + # 是否有切换为学生的入口 def switch_student_role is_teacher, course, user is_teacher && course.course_members.where(user_id: user.id, role: %i(STUDENT)).exists? end diff --git a/app/helpers/exercises_helper.rb b/app/helpers/exercises_helper.rb index 98a580ecc..ef9261990 100644 --- a/app/helpers/exercises_helper.rb +++ b/app/helpers/exercises_helper.rb @@ -148,7 +148,7 @@ module ExercisesHelper :choice_position => c.choice_position, :choice_text => c.choice_text, :choice_users_count => answer_users_count, - :choice_percent => answer_percent.round(1).to_s, + :choice_percent => answer_percent.round(2).to_s, :right_answer => right_answer } question_answer_infos.push(answer_option) @@ -174,7 +174,7 @@ module ExercisesHelper :choice_position => index+1, :choice_text => s_choice_text, :choice_users_count => user_count, - :choice_percent => answer_percent.round(1).to_s, + :choice_percent => answer_percent.round(2).to_s, :right_answer => true } question_answer_infos.push(answer_option) @@ -194,7 +194,7 @@ module ExercisesHelper :choice_position => (standard_answer_count + 1), :choice_text => "wrong", :choice_users_count => user_wrong_count, - :choice_percent => wrong_percent.round(1).to_s, + :choice_percent => wrong_percent.round(2).to_s, :right_answer => false } question_answer_infos.push(wrong_answer_position) @@ -220,7 +220,7 @@ module ExercisesHelper :choice_position => index+1, :choice_text => index+1, :choice_users_count => s, - :choice_percent => score_percent.round(1).to_s, + :choice_percent => score_percent.round(2).to_s, :right_answer => right_answer } question_answer_infos.push(answer_option) @@ -246,7 +246,7 @@ module ExercisesHelper :choice_position => index+1, :choice_text => index+1, :choice_users_count => s, - :choice_percent => score_percent.round(1).to_s, + :choice_percent => score_percent.round(2).to_s, :right_answer => right_answer } shixun_chas.push(answer_option) @@ -256,7 +256,7 @@ module ExercisesHelper :cha_name => c.challenge.subject, :cha_position => c.position, :cha_details => shixun_chas, - :cha_percent => game_percent.round(1).to_s + :cha_percent => game_percent.round(2).to_s } question_answer_infos.push(shixun_new_chas) end @@ -266,7 +266,7 @@ module ExercisesHelper :ques_less_title => ques_less_title, #副标题,仅实训题才有 :type => ex.question_type, :position => ex.question_number, - :percent => percent.round(1).to_s, + :percent => percent.round(2).to_s, :ques_effictive_counts => effictive_users_count, :ques_details => question_answer_infos } diff --git a/app/helpers/homework_commons_helper.rb b/app/helpers/homework_commons_helper.rb index cc23d05d6..efc14dc5e 100644 --- a/app/helpers/homework_commons_helper.rb +++ b/app/helpers/homework_commons_helper.rb @@ -222,9 +222,17 @@ module HomeworkCommonsHelper [{ id: 0 ,name: "未评", count: homework.uncomment_count(user_id)}, {id: 1, name: "已评", count: homework.comment_count(user_id)}] end + # 作品状态 + def practice_homework_status homework, member + [{id: 3, name: "未通关", count: homework.un_complete_count(member)}, + {id: 4, name: "已通关", count: homework.complete_count(member)}, + {id: 1, name: "按时完成", count: homework.finished_count(member)}, + {id: 2, name: "延时完成", count: homework.delay_finished_count(member)}] + end + # 作品状态 def homework_status homework, member - [{id: 0, name: "未提交", count: homework.unfinished_count(member)}, + [{id: 0, name: "未提交", count: homework.unfinished_count(member)}, {id: 1, name: "按时提交", count: homework.finished_count(member)}, {id: 2, name: "延时提交", count: homework.delay_finished_count(member)}] end diff --git a/app/helpers/memos_helper.rb b/app/helpers/memos_helper.rb index 434d9b66a..ea84ec2c1 100644 --- a/app/helpers/memos_helper.rb +++ b/app/helpers/memos_helper.rb @@ -1,6 +1,6 @@ module MemosHelper def forum_list - [{id: 5, name: "技术分享"}, {id: 3, name: "操作指南"}] + [{id: 5, name: "技术分享"}, {id: 3, name: "操作指南"}, {id: 16, name: "通知公告"}] end end diff --git a/app/jobs/create_diff_record_job.rb b/app/jobs/create_diff_record_job.rb new file mode 100644 index 000000000..fbe8cbff2 --- /dev/null +++ b/app/jobs/create_diff_record_job.rb @@ -0,0 +1,12 @@ +class CreateDiffRecordJob < ApplicationJob + queue_as :default + + def perform(user_id, obj_id, obj_klass, column_name, before, after) + user = User.find_by(id: user_id) + obj = obj_klass.constantize.find_by(id: obj_id) + + return if user.blank? || obj.blank? + + CreateDiffRecordService.call(user, obj, column_name, before, after) + end +end \ No newline at end of file diff --git a/app/jobs/end_exercise_calculate_job.rb b/app/jobs/end_exercise_calculate_job.rb index 39d8bb1db..b6d8e491e 100644 --- a/app/jobs/end_exercise_calculate_job.rb +++ b/app/jobs/end_exercise_calculate_job.rb @@ -19,7 +19,8 @@ class EndExerciseCalculateJob < ApplicationJob :end_at => Time.now, :objective_score => objective_score, :score => total_score, - :subjective_score => user_sub_score + :subjective_score => user_sub_score, + :commit_method => user&.commit_method.to_i > 0 ? user&.commit_method.to_i : 4 } user.update_attributes(commit_option) end diff --git a/app/libs/util.rb b/app/libs/util.rb index ae2e4b80b..72e728ab9 100644 --- a/app/libs/util.rb +++ b/app/libs/util.rb @@ -48,8 +48,8 @@ module Util return if str.blank? case type - when :phone then "#{str[0..2]}***#{str[-4..-1]}" - when :email then "#{str[0..2]}***#{str[str.rindex('@')..-1]}" + when :phone then "#{str[0..2]}***#{str[-3..-1]}" + when :email then "#{str[0]}***#{str[(str.rindex('@')-1)..-1]}" else "#{str[0..2]}***#{str[-3..-1]}" end end diff --git a/app/libs/util/file_manage.rb b/app/libs/util/file_manage.rb index b6cd79e57..2f87a3e86 100644 --- a/app/libs/util/file_manage.rb +++ b/app/libs/util/file_manage.rb @@ -10,24 +10,35 @@ module Util::FileManage File.join(Rails.root, "public", "images", relative_path) end - def disk_filename(source_type, source_id,image_file=nil) - File.join(storage_path, "#{source_type}", "#{source_id}") + def disk_filename(source_type, source_id, suffix=nil) + File.join(storage_path, "#{source_type}", "#{source_id}#{suffix}") end - def exist?(source_type, source_id) - File.exist?(disk_filename(source_type, source_id)) + def source_disk_filename(source, suffix=nil) + disk_filename(source.class.name, source.id, suffix) end - def exists?(source) - File.exist?(disk_filename(source.class, source.id)) + def exist?(source_type, source_id, suffix=nil) + File.exist?(disk_filename(source_type, source_id, suffix)) end - def disk_file_url(source_type, source_id) - File.join('/images', relative_path, "#{source_type}", "#{source_id}") + def exists?(source, suffix=nil) + File.exist?(disk_filename(source.class, source.id, suffix)) end - def source_disk_file_url(source) - File.join('/images', relative_path, "#{source.class}", "#{source.id}") + def disk_file_url(source_type, source_id, suffix = nil) + t = ctime(source_type, source_id, suffix) + File.join('/images', relative_path, "#{source_type}", "#{source_id}#{suffix}") + "?t=#{t}" + end + + def source_disk_file_url(source, suffix=nil) + disk_file_url(source.class, source.id, suffix) + end + + def ctime(source_type, source_id, suffix) + return nil unless exist?(source_type, source_id, suffix) + + File.ctime(disk_filename(source_type, source_id, suffix)).to_i end def disk_auth_filename(source_type, source_id, type) @@ -39,7 +50,7 @@ module Util::FileManage end def auth_file_url(source_type, source_id, type) - File.join('/images', relative_path, source_type, "#{source_id}#{type}") + disk_file_url(source_type, source_id, type) end def real_name_auth_file_url(source_id) diff --git a/app/libs/util/wechat.rb b/app/libs/util/wechat.rb deleted file mode 100644 index 1b064ba94..000000000 --- a/app/libs/util/wechat.rb +++ /dev/null @@ -1,75 +0,0 @@ -module Util::Wechat - BASE_SITE = 'https://api.weixin.qq.com'.freeze - - Error = Class.new(StandardError) - - class << self - attr_accessor :appid, :secret - - def js_sdk_signature(url, noncestr, timestamp) - data = { jsapi_ticket: jsapi_ticket, noncestr: noncestr, timestamp: timestamp, url: url } - str = data.map { |k, v| "#{k}=#{v}" }.join('&') - Digest::SHA1.hexdigest(str) - end - - def access_token - # 7200s 有效时间 - Rails.cache.fetch(access_token_cache_key, expires_in: 100.minutes) do - result = request(:get, '/cgi-bin/token', appid: appid, secret: secret, grant_type: 'client_credential') - result['access_token'] - end - end - - def refresh_access_token - Rails.cache.delete(access_token_cache_key) - access_token - end - - def jsapi_ticket - # 7200s 有效时间 - Rails.cache.fetch(jsapi_ticket_cache_key, expires_in: 100.minutes) do - result = request(:get, '/cgi-bin/ticket/getticket', access_token: access_token, type: 'jsapi') - result['ticket'] - end - end - - def refresh_jsapi_ticket - Rails.cache.delete(jsapi_ticket_cache_key) - jsapi_ticket - end - - def access_token_cache_key - "#{base_cache_key}/access_token" - end - - def jsapi_ticket_cache_key - "#{base_cache_key}/jsapi_ticket" - end - - def base_cache_key - "wechat/#{appid}" - end - - private - - def request(method, url, **params) - Rails.logger.error("[wechat] request: #{method} #{url} #{params.inspect}") - - client = Faraday.new(url: BASE_SITE) - response = client.public_send(method, url, params) - result = JSON.parse(response.body) - - Rails.logger.error("[wechat] response:#{response.status} #{result.inspect}") - - if response.status != 200 - raise Error, result.inspect - end - - if result['errcode'].present? && result['errcode'].to_i.nonzero? - raise Error, result.inspect - end - - result - end - end -end \ No newline at end of file diff --git a/app/libs/wechat.rb b/app/libs/wechat.rb new file mode 100644 index 000000000..68e2c06b8 --- /dev/null +++ b/app/libs/wechat.rb @@ -0,0 +1,2 @@ +module Wechat +end \ No newline at end of file diff --git a/app/libs/wechat/app.rb b/app/libs/wechat/app.rb new file mode 100644 index 000000000..54f60fa2a --- /dev/null +++ b/app/libs/wechat/app.rb @@ -0,0 +1,11 @@ +class Wechat::App + class << self + attr_accessor :appid, :secret + + delegate :access_token, :jscode2session, to: :client + + def client + @_client ||= Wechat::Client.new(appid, secret) + end + end +end \ No newline at end of file diff --git a/app/libs/wechat/client.rb b/app/libs/wechat/client.rb new file mode 100644 index 000000000..5ac0a28f2 --- /dev/null +++ b/app/libs/wechat/client.rb @@ -0,0 +1,74 @@ +class Wechat::Client + BASE_SITE = 'https://api.weixin.qq.com'.freeze + + attr_reader :appid, :secret + + def initialize(appid, secret) + @appid = appid + @secret = secret + end + + def access_token + # 7200s 有效时间 + Rails.cache.fetch(access_token_cache_key, expires_in: 100.minutes) do + result = request(:get, '/cgi-bin/token', appid: appid, secret: secret, grant_type: 'client_credential') + result['access_token'] + end + end + + def refresh_access_token + Rails.cache.delete(access_token_cache_key) + access_token + end + + def jsapi_ticket + # 7200s 有效时间 + Rails.cache.fetch(jsapi_ticket_cache_key, expires_in: 100.minutes) do + result = request(:get, '/cgi-bin/ticket/getticket', access_token: access_token, type: 'jsapi') + result['ticket'] + end + end + + def refresh_jsapi_ticket + Rails.cache.delete(jsapi_ticket_cache_key) + jsapi_ticket + end + + def jscode2session(code) + request(:get, '/sns/jscode2session', appid: appid, secret: secret, js_code: code, grant_type: 'authorization_code') + end + + def access_token_cache_key + "#{base_cache_key}/access_token" + end + + def jsapi_ticket_cache_key + "#{base_cache_key}/jsapi_ticket" + end + + def base_cache_key + "wechat/#{appid}" + end + + private + + def request(method, url, **params) + Rails.logger.error("[wechat] request: #{method} #{url} #{params.except(:secret).inspect}") + + client = Faraday.new(url: BASE_SITE) + response = client.public_send(method, url, params) + result = JSON.parse(response.body) + + Rails.logger.error("[wechat] response:#{response.status} #{result.inspect}") + + if response.status != 200 + raise Wechat::Error.parse(result) + end + + if result['errcode'].present? && result['errcode'].to_i.nonzero? + raise Wechat::Error.parse(result) + end + + result + end +end \ No newline at end of file diff --git a/app/libs/wechat/error.rb b/app/libs/wechat/error.rb new file mode 100644 index 000000000..f693fb41b --- /dev/null +++ b/app/libs/wechat/error.rb @@ -0,0 +1,14 @@ +class Wechat::Error < StandardError + attr_reader :code + + def initialize(code, message) + super message + @code = code + end + + class << self + def parse(result) + new(result['errcode'], result['errmsg']) + end + end +end \ No newline at end of file diff --git a/app/libs/wechat/official_account.rb b/app/libs/wechat/official_account.rb new file mode 100644 index 000000000..88208d6f3 --- /dev/null +++ b/app/libs/wechat/official_account.rb @@ -0,0 +1,17 @@ +class Wechat::OfficialAccount + class << self + attr_accessor :appid, :secret + + delegate :access_token, :jsapi_ticket, to: :client + + def js_sdk_signature(url, noncestr, timestamp) + data = { jsapi_ticket: jsapi_ticket, noncestr: noncestr, timestamp: timestamp, url: url } + str = data.map { |k, v| "#{k}=#{v}" }.join('&') + Digest::SHA1.hexdigest(str) + end + + def client + @_client ||= Wechat::Client.new(appid, secret) + end + end +end \ No newline at end of file diff --git a/app/models/challenge.rb b/app/models/challenge.rb index 455fd1b6a..da88b0fca 100644 --- a/app/models/challenge.rb +++ b/app/models/challenge.rb @@ -28,6 +28,8 @@ class Challenge < ApplicationRecord scope :fields_for_list, -> { select([:id, :subject, :st, :score, :position, :shixun_id]) } + after_commit :create_diff_record + def next_challenge position = self.position + 1 Challenge.where(:position => position, :shixun_id => self.shixun).first @@ -126,4 +128,11 @@ class Challenge < ApplicationRecord end # 关卡评测文件 + + private + + def create_diff_record + return unless task_pass_previously_changed? + CreateDiffRecordJob.perform_later(User.current.id, id, 'Challenge', 'task_pass', task_pass_before_last_save, task_pass) + end end diff --git a/app/models/diff_record.rb b/app/models/diff_record.rb new file mode 100644 index 000000000..afbb9dd9c --- /dev/null +++ b/app/models/diff_record.rb @@ -0,0 +1,8 @@ +class DiffRecord < ApplicationRecord + belongs_to :user + belongs_to :container, polymorphic: true + + has_one :diff_record_content, dependent: :destroy + + delegate :content, to: :diff_record_content +end \ No newline at end of file diff --git a/app/models/diff_record_content.rb b/app/models/diff_record_content.rb new file mode 100644 index 000000000..ce5e1d354 --- /dev/null +++ b/app/models/diff_record_content.rb @@ -0,0 +1,3 @@ +class DiffRecordContent < ApplicationRecord + belongs_to :diff_record +end \ No newline at end of file diff --git a/app/models/ec_course.rb b/app/models/ec_course.rb index 6f5480ea8..5aefa2699 100644 --- a/app/models/ec_course.rb +++ b/app/models/ec_course.rb @@ -6,7 +6,7 @@ class EcCourse < ApplicationRecord has_many :ec_graduation_subitem_course_targets, through: :ec_course_targets # 课程负责教师 has_many :ec_course_users - has_many :course_managers, through: :ec_course_users, class_name: 'User' + has_many :course_managers, through: :ec_course_users, source: :user # 课程考核标准 has_many :ec_course_evaluations, dependent: :destroy # 课程等级 @@ -21,7 +21,7 @@ class EcCourse < ApplicationRecord has_many :courses, through: :ec_major_courses # 课程目标达成方法 - # has_many :ec_course_achievement_methods + has_many :ec_course_achievement_methods accepts_nested_attributes_for :ec_course_targets, :ec_score_levels, allow_destroy: true end diff --git a/app/models/ec_course_evaluation.rb b/app/models/ec_course_evaluation.rb index e96f1c98b..40fd10dfa 100644 --- a/app/models/ec_course_evaluation.rb +++ b/app/models/ec_course_evaluation.rb @@ -16,4 +16,23 @@ class EcCourseEvaluation < ApplicationRecord def imported? import_status? end + + def evaluation_relates + # 总成绩支撑只有课程考核标准的名称, 分项成绩支撑是课程考核标准名称与考核分项的笛卡尔积 + if status == 1 + return evaluation_count.times.map { |index| { id: -1, name: "#{name}(#{index + 1})", position: index + 1 } } + end + + if is_course_type? + ec_course_evaluation_subitems.map.with_index { |item, index| { id: item.id, name: item.name, position: index + 1 } } + else + data = [] + ec_course_evaluation_subitems.each do |item| + evaluation_count.times do |i| + data << { id: item.id, name: "#{name}(#{i + 1})#{item.name}", position: i + 1 } + end + end + data + end + end end diff --git a/app/models/exercise.rb b/app/models/exercise.rb index 825f7cd9f..8469d25b6 100644 --- a/app/models/exercise.rb +++ b/app/models/exercise.rb @@ -131,7 +131,7 @@ class Exercise < ApplicationRecord status = 4 else if user.present? && user.student_of_course?(course) #当为学生的时候,需根据分班来判断试卷状态 - ex_time = get_exercise_times(user_id,false) + ex_time = get_exercise_times(user.id,false) pb_time = ex_time[:publish_time] ed_time = ex_time[:end_time] if pb_time.present? && ed_time.present? && pb_time <= Time.now && ed_time > Time.now diff --git a/app/models/exercise_user.rb b/app/models/exercise_user.rb index 84f042b25..0f2e8456e 100644 --- a/app/models/exercise_user.rb +++ b/app/models/exercise_user.rb @@ -1,4 +1,5 @@ class ExerciseUser < ApplicationRecord + # commit_method 0 为默认, 1为学生的手动提交,2为倒计时结束后自动提交,3为试卷定时截止的自动提交, 4为教师手动的立即截止 belongs_to :user belongs_to :exercise diff --git a/app/models/forum.rb b/app/models/forum.rb index 88aafa676..cd9b76a96 100644 --- a/app/models/forum.rb +++ b/app/models/forum.rb @@ -1,2 +1,3 @@ class Forum < ApplicationRecord + has_many :memos, dependent: :destroy end diff --git a/app/models/homework_common.rb b/app/models/homework_common.rb index 40de5a87c..fc2dd3ea4 100644 --- a/app/models/homework_common.rb +++ b/app/models/homework_common.rb @@ -136,7 +136,7 @@ class HomeworkCommon < ApplicationRecord # 作业查看最新成绩 def update_score identity - identity < Course::NORMAL && publish_time.present? && publish_time < Time.now && !course.is_end + identity < Course::NORMAL && publish_time.present? && publish_time < Time.now && !end_or_late_none_group end # 作业能否立即发布 @@ -240,6 +240,16 @@ class HomeworkCommon < ApplicationRecord self.teacher_works(member).delay_finished.count end + # 未通关数 + def un_complete_count member + teacher_works(member).count - complete_count(member) + end + + # 通关数 + def complete_count member + Myshixun.where(id: self.teacher_works(member).pluck(:myshixun_id), status: 1).count + end + # 分组作业的最大分组id def max_group_id self.student_works.has_committed.maximum(:group_id).to_i + 1 diff --git a/app/models/laboratory.rb b/app/models/laboratory.rb new file mode 100644 index 000000000..53e66ece0 --- /dev/null +++ b/app/models/laboratory.rb @@ -0,0 +1,26 @@ +class Laboratory < ApplicationRecord + belongs_to :school, optional: true + + has_many :laboratory_users, dependent: :destroy + has_many :users, through: :laboratory_users, source: :user + + has_one :laboratory_setting, dependent: :destroy + + validates :identifier, uniqueness: { case_sensitive: false }, allow_nil: true + + def site + rails_env = EduSetting.get('rails_env') + suffix = rails_env && rails_env != 'production' ? ".#{rails_env}.educoder.net" : '.educoder.net' + + identifier ? "#{identifier}#{suffix}" : '' + end + + def self.find_by_subdomain(subdomain) + return if subdomain.blank? + + rails_env = EduSetting.get('rails_env') + subdomain = subdomain.slice(0, subdomain.size - rails_env.size - 1) if subdomain.end_with?(rails_env) # winse.dev => winse + + find_by_identifier(subdomain) + end +end \ No newline at end of file diff --git a/app/models/laboratory_setting.rb b/app/models/laboratory_setting.rb new file mode 100644 index 000000000..32848dca2 --- /dev/null +++ b/app/models/laboratory_setting.rb @@ -0,0 +1,54 @@ +class LaboratorySetting < ApplicationRecord + belongs_to :laboratory + + serialize :config, JSON + + %i[name navbar footer].each do |method_name| + define_method method_name do + config&.[](method_name.to_s) + end + + define_method "#{method_name}=" do |value| + self.config ||= {} + config.[]=(method_name.to_s, value) + end + end + + def login_logo_url + logo_url('login') + end + + def nav_logo_url + logo_url('nav') + end + + def tab_logo_url + logo_url('tab') + end + + def default_navbar + self.class.default_config[:navbar] + end + + private + + def logo_url(type) + return nil unless Util::FileManage.exists?(self, type) + Util::FileManage.source_disk_file_url(self, type) + end + + def self.default_config + { + name: nil, + navbar: [ + { 'name' => '实践课程', 'link' => '/paths', 'hidden' => false }, + { 'name' => '翻转课堂', 'link' => '/courses', 'hidden' => false }, + { 'name' => '实现项目', 'link' => '/shixuns', 'hidden' => false }, + { 'name' => '在线竞赛', 'link' => '/competitions', 'hidden' => false }, + { 'name' => '教学案例', 'link' => '/moop_cases', 'hidden' => false }, + { 'name' => '交流问答', 'link' => '/forums', 'hidden' => false }, + ], + footer: nil + } + end +end \ No newline at end of file diff --git a/app/models/laboratory_user.rb b/app/models/laboratory_user.rb new file mode 100644 index 000000000..be6c0c4dd --- /dev/null +++ b/app/models/laboratory_user.rb @@ -0,0 +1,4 @@ +class LaboratoryUser < ApplicationRecord + belongs_to :laboratory + belongs_to :user +end \ No newline at end of file diff --git a/app/models/mirror_repository.rb b/app/models/mirror_repository.rb index e29b008ad..96a92e5e7 100644 --- a/app/models/mirror_repository.rb +++ b/app/models/mirror_repository.rb @@ -5,7 +5,7 @@ class MirrorRepository < ApplicationRecord - scope :published_mirror, -> { where(status: 1) } + scope :published_mirror, -> { where(status: [1,2,3,5]) } scope :published_main_mirror, -> { published_mirror.where(main_type: 1) } scope :published_small_mirror, -> { published_mirror.where(main_type: 0) } diff --git a/app/models/shixun.rb b/app/models/shixun.rb index 4912ea15a..0cdb2e82b 100644 --- a/app/models/shixun.rb +++ b/app/models/shixun.rb @@ -1,5 +1,6 @@ class Shixun < ApplicationRecord include Searchable::Shixun + attr_accessor :page_no #管理员页面 实训配置更新状态时,需要接受page_no参数 # status: 0:编辑 1:申请发布 2:正式发布 3:关闭 -1:软删除 # hide_code: 隐藏代码窗口 diff --git a/app/models/shixun_info.rb b/app/models/shixun_info.rb index 542e0222d..74a49412e 100644 --- a/app/models/shixun_info.rb +++ b/app/models/shixun_info.rb @@ -2,4 +2,13 @@ class ShixunInfo < ApplicationRecord belongs_to :shixun validates_uniqueness_of :shixun_id validates_presence_of :shixun_id + + after_commit :create_diff_record + + private + + def create_diff_record + return unless description_previously_changed? + CreateDiffRecordJob.perform_later(User.current.id, id, 'ShixunInfo', 'description', description_before_last_save, description) + end end diff --git a/app/queries/admins/laboratory_query.rb b/app/queries/admins/laboratory_query.rb new file mode 100644 index 000000000..21020216b --- /dev/null +++ b/app/queries/admins/laboratory_query.rb @@ -0,0 +1,23 @@ +class Admins::LaboratoryQuery < ApplicationQuery + include CustomSortable + + attr_reader :params + + sort_columns :id, default_by: :id, default_direction: :desc + + def initialize(params) + @params = params + end + + def call + laboratories = Laboratory.all + + keyword = strip_param(:keyword) + if keyword.present? + like_sql = 'schools.name LIKE :keyword OR laboratories.identifier LIKE :keyword' + laboratories = laboratories.joins(:school).where(like_sql, keyword: "%#{keyword}%") + end + + custom_sort laboratories, params[:sort_by], params[:sort_direction] + end +end \ No newline at end of file diff --git a/app/services/admins/add_laboratory_user_service.rb b/app/services/admins/add_laboratory_user_service.rb new file mode 100644 index 000000000..16df30880 --- /dev/null +++ b/app/services/admins/add_laboratory_user_service.rb @@ -0,0 +1,19 @@ +class Admins::AddLaboratoryUserService < ApplicationService + attr_reader :laboratory, :params + + def initialize(laboratory, params) + @laboratory = laboratory + @params = params + end + + def call + columns = %i[] + LaboratoryUser.bulk_insert(*columns) do |worker| + Array.wrap(params[:user_ids]).compact.each do |user_id| + next if laboratory.laboratory_users.exists?(user_id: user_id) + + worker.add(laboratory_id: laboratory.id, user_id: user_id) + end + end + end +end \ No newline at end of file diff --git a/app/services/admins/create_laboratory_service.rb b/app/services/admins/create_laboratory_service.rb new file mode 100644 index 000000000..98300d5af --- /dev/null +++ b/app/services/admins/create_laboratory_service.rb @@ -0,0 +1,20 @@ +class Admins::CreateLaboratoryService < ApplicationService + Error = Class.new(StandardError) + + attr_reader :params + + def initialize(params) + @params = params + end + + def call + raise Error, '单位不能为空' if params[:school_id].blank? + raise Error, '该单位已存在' if Laboratory.exists?(school_id: params[:school_id]) + + ActiveRecord::Base.transaction do + laboratory = Laboratory.create!(school_id: params[:school_id]) + + laboratory.create_laboratory_setting! + end + end +end \ No newline at end of file diff --git a/app/services/admins/drag_portal_image_service.rb b/app/services/admins/drag_portal_image_service.rb index 6fe1ea86d..9f8adea38 100644 --- a/app/services/admins/drag_portal_image_service.rb +++ b/app/services/admins/drag_portal_image_service.rb @@ -14,7 +14,7 @@ class Admins::DragPortalImageService < ApplicationService images = PortalImage.all ActiveRecord::Base.transaction do - if after.blank? # 移动至末尾 + if after.blank? || move.id == after.id # 移动至末尾 total = images.count images.where('position > ?', move.position).update_all('position = position - 1') @@ -26,8 +26,8 @@ class Admins::DragPortalImageService < ApplicationService images.where('position >= ? AND position < ?', after.position, move.position).update_all('position = position + 1') move.update!(position: after.position) else # 后移 - images.where('position > ? AND position <= ?', move.position, after.position).update_all('position = position - 1') - move.update!(position: after.position) + images.where('position > ? AND position < ?', move.position, after.position).update_all('position = position - 1') + move.update!(position: after.position - 1) end end end diff --git a/app/services/admins/save_laboratory_setting_service.rb b/app/services/admins/save_laboratory_setting_service.rb new file mode 100644 index 000000000..00e202cd9 --- /dev/null +++ b/app/services/admins/save_laboratory_setting_service.rb @@ -0,0 +1,51 @@ +class Admins::SaveLaboratorySettingService < ApplicationService + attr_reader :laboratory, :laboratory_setting, :params + + def initialize(laboratory, params) + @params = params + @laboratory = laboratory + @laboratory_setting = laboratory.laboratory_setting + end + + def call + ActiveRecord::Base.transaction do + laboratory.identifier = strip params[:identifier] + laboratory_setting.name = strip params[:name] + laboratory_setting.navbar = navbar_config + laboratory_setting.footer = strip params[:footer] + + laboratory.save! + laboratory_setting.save! + + deal_logo_file + end + + laboratory + end + + private + + def navbar_config + params[:navbar].map do |nav| + hash = {} + hash[:name] = strip nav[:name] + hash[:link] = strip nav[:link] + hash[:hidden] = nav[:hidden].to_s == 0 + hash + end + end + + def deal_logo_file + save_logo_file(params[:nav_logo], 'nav') + save_logo_file(params[:login_logo], 'login') + save_logo_file(params[:tab_logo], 'tab') + end + + def save_logo_file(file, type) + return unless file.present? && file.is_a?(ActionDispatch::Http::UploadedFile) + + file_path = Util::FileManage.source_disk_filename(laboratory_setting, type) + File.delete(file_path) if File.exist?(file_path) # 删除之前的文件 + Util.write_file(file, file_path) + end +end \ No newline at end of file diff --git a/app/services/application_service.rb b/app/services/application_service.rb index c6f66c098..8b3819017 100644 --- a/app/services/application_service.rb +++ b/app/services/application_service.rb @@ -1,3 +1,9 @@ class ApplicationService include Callable + + private + + def strip(str) + str.to_s.strip.presence + end end \ No newline at end of file diff --git a/app/services/create_diff_record_service.rb b/app/services/create_diff_record_service.rb new file mode 100644 index 000000000..8365404e2 --- /dev/null +++ b/app/services/create_diff_record_service.rb @@ -0,0 +1,46 @@ +class CreateDiffRecordService < ApplicationService + attr_reader :user, :obj, :column_name, :after, :before + + def initialize(user, obj, column_name, before, after) + @user = user + @obj = obj + @before = before + @after = after + @column_name = column_name + end + + def call + ActiveRecord::Base.transaction do + diff_record = DiffRecord.create!(user: user, container: obj, column_name: column_name) + diff_record.create_diff_record_content!(content: diff_content) + end + end + + private + + def diff_content + content = '' + + arr = [] + index = 0 + fragment_size = 1 + Diffy::Diff.new(before, after).each do |line| + unless line =~ /^[\+-]/ + if arr.empty? && index < fragment_size + content += line + index += 1 + else + index = 0 + arr << line + arr.shift if arr.size > fragment_size + end + next + end + + content += arr.join('') if arr.present? + content += line + arr.clear + end + content + end +end \ No newline at end of file diff --git a/app/services/ecs/create_course_achievement_method_service.rb b/app/services/ecs/create_course_achievement_method_service.rb index 01f09ff2b..d71fc9c97 100644 --- a/app/services/ecs/create_course_achievement_method_service.rb +++ b/app/services/ecs/create_course_achievement_method_service.rb @@ -31,8 +31,8 @@ class Ecs::CreateCourseAchievementMethodsService < ApplicationService # 创建新的评价方法时,全部为新建 if item[:id].blank? || course_target.ec_course_achievement_methods.find_by(id: item[:id]).blank? item[:ec_achievement_evaluation_relates_attributes] = - Array(*item[:course_evaluation_subitem_ids]).uniq.map do |subitem_id| - { ec_course_evaluation_subitem_id: subitem_id.to_i } + item[:course_evaluation_relates].map do |relate| + { ec_course_evaluation_subitem_id: relate[:subitem_id].to_i, position: relate[:position] } end return end @@ -41,22 +41,22 @@ class Ecs::CreateCourseAchievementMethodsService < ApplicationService relates = achievement_method.ec_achievement_evaluation_relates # 获取传入的 subitem id数组和已存在的 subitem id数组 - old_subitem_ids = relates.map(&:ec_course_evaluation_subitem_id).uniq - new_subitem_ids = Array(*item[:course_evaluation_subitem_ids]).map(&:to_i).uniq + old_data = relates.map { |e| [e.ec_course_evaluation_subitem_id, e.position] } + new_data = item[:course_evaluation_relates].map { |e| [e[:subitem_id, e[:position]]] } # 分别得到需要移除的 subitem ID数组和需要创建的 subitem ID数组 - destroy_subitem_ids = old_subitem_ids - new_subitem_ids - create_subitem_ids = new_subitem_ids - old_subitem_ids + destroy_data = old_data - new_data + create_data = new_data - old_data # 生成需要创建关系的 subitem id 数据 - create_attributes = create_subitem_ids.map { |item_id| { ec_course_evaluation_subitem_id: item_id } } + create_attributes = create_data.map { |arr| { ec_course_target_id: course_target.id, ec_course_evaluation_subitem_id: arr[0], position: arr[1] } } # 处理需要更新或者删除的记录 exists_attributes = relates.map do |relate| - if destroy_subitem_ids.include?(relate.ec_course_evaluation_subitem_id) + if destroy_data.include?([relate.ec_course_evaluation_subitem_id, relate.position]) { id: relate.id, _destroy: true } else - relate.as_json(only: %i[id ec_course_evaluation_subitem_id ec_course_achievement_method_id]) + relate.as_json(only: %i[id ec_course_target_id ec_course_evaluation_subitem_id ec_course_achievement_method_id position]) end end diff --git a/app/services/ecs/create_course_manager_service.rb b/app/services/ecs/create_course_manager_service.rb index 58e803bcf..4d3633bfd 100644 --- a/app/services/ecs/create_course_manager_service.rb +++ b/app/services/ecs/create_course_manager_service.rb @@ -3,27 +3,29 @@ class Ecs::CreateCourseManagerService < ApplicationService COURSE_MANAGER_COUNT_LIMIT = 2 # 课程管理员数量限制 - attr_reader :ec_course, :user_id + attr_reader :ec_course, :user_ids - def initialize(ec_course, user_id) + def initialize(ec_course, user_ids) @ec_course = ec_course - @user_id = user_id + @user_ids = user_ids end def call - user = User.find_by(id: params[:user_id]) - raise Error, '该用户不存在' if user.blank? + users_count = User.where(id: user_ids).count + raise Error, '用户不存在' if users_count != user_ids.size - if ec_course.ec_course_users.exists?(user_id: user.id) - raise Error, '该用户已经是该课程的管理员了' + if ec_course.ec_course_users.exists?(user_id: user_ids) + raise Error, '用户已经是该课程的管理员' end - if ec_course.ec_course_users.count >= COURSE_MANAGER_COUNT_LIMIT - raise Error, '该课程管理员数量已达上限' + if ec_course.ec_course_users.count + user_ids.size > COURSE_MANAGER_COUNT_LIMIT + raise Error, "课程管理员数量过多(最多#{COURSE_MANAGER_COUNT_LIMIT})" end - ec_course.ec_course_users.create!(user: user) - - user + ActiveRecord::Base.transaction do + user_ids.each do |user_id| + ec_course.ec_course_users.create!(user_id: user_id) + end + end end end \ No newline at end of file diff --git a/app/services/ecs/query_course_evaluation_service.rb b/app/services/ecs/query_course_evaluation_service.rb index fd1619076..9b3587d78 100644 --- a/app/services/ecs/query_course_evaluation_service.rb +++ b/app/services/ecs/query_course_evaluation_service.rb @@ -4,6 +4,7 @@ class Ecs::QueryCourseEvaluationService < ApplicationService def initialize(ec_course) @ec_course = ec_course @_course_achievement = 0 + @_course_rate = 0 end def course_targets @@ -16,6 +17,12 @@ class Ecs::QueryCourseEvaluationService < ApplicationService @_course_achievement.round(2) end + def course_rate + course_targets + + @_course_rate.round(2) + end + def graduation_subitem_evaluations student_scores = ec_course.ec_course_student_scores.joins(ec_student_score_targets: :ec_course_target).group(:ec_course_target_id) student_scores = student_scores.select('AVG(score) as average_score, ec_course_target_id') @@ -58,10 +65,10 @@ class Ecs::QueryCourseEvaluationService < ApplicationService end end - def score_levels_map - @_score_levels_map ||= begin + def score_levels + @_score_levels ||= begin index = 0 - ec_course.ec_score_levels.each_with_object({}) do |level, obj| + ec_course.ec_score_levels.map do |level| hash = level.as_json(only: %i[id position score level]) hash[:description] = @@ -72,7 +79,7 @@ class Ecs::QueryCourseEvaluationService < ApplicationService end index += 1 - obj[level.id.to_s] = hash + hash end end end @@ -96,6 +103,7 @@ class Ecs::QueryCourseEvaluationService < ApplicationService # 计算总评成绩 @_course_achievement += data[:average_score].to_f * course_target.weight.to_f + @_course_rate += course_target.weight.to_f # 计算学生成绩分布区间 student_count = 0 diff --git a/app/services/users/apply_authentication_service.rb b/app/services/users/apply_authentication_service.rb index 9e0901ef4..d6da2d1fb 100644 --- a/app/services/users/apply_authentication_service.rb +++ b/app/services/users/apply_authentication_service.rb @@ -25,10 +25,10 @@ class Users::ApplyAuthenticationService < ApplicationService user.apply_user_authentication.create!(auth_type: 1, status: 0) move_image_file! unless params[:upload_image].to_s == 'false' - - sms_notify_admin end + sms_notify_admin + user end diff --git a/app/services/users/apply_professional_auth_service.rb b/app/services/users/apply_professional_auth_service.rb index cc6f36fff..ea9f3e0d1 100644 --- a/app/services/users/apply_professional_auth_service.rb +++ b/app/services/users/apply_professional_auth_service.rb @@ -37,13 +37,9 @@ class Users::ApplyProfessionalAuthService < ApplicationService user.apply_user_authentication.create!(auth_type: 2, status: 0) move_image_file! unless params[:upload_image].to_s == 'false' - - sms_cache = Rails.cache.read("apply_pro_certification") - if sms_cache.nil? - sms_notify_admin - Rails.cache.write("apply_pro_certification", 1, expires_in: 5.minutes) - end end + + sms_notify_admin end private @@ -61,7 +57,11 @@ class Users::ApplyProfessionalAuthService < ApplicationService end def sms_notify_admin - Educoder::Sms.notify_admin(send_type: 'apply_pro_certification') + sms_cache = Rails.cache.read('apply_pro_certification') + if sms_cache.nil? + Educoder::Sms.notify_admin(send_type: 'apply_pro_certification') + Rails.cache.write('apply_pro_certification', 1, expires_in: 5.minutes) + end rescue => ex Util.logger_error(ex) end diff --git a/app/tasks/exercise_publish_task.rb b/app/tasks/exercise_publish_task.rb index 220512664..a7b533d05 100644 --- a/app/tasks/exercise_publish_task.rb +++ b/app/tasks/exercise_publish_task.rb @@ -66,7 +66,8 @@ class ExercisePublishTask :end_at => Time.now, :objective_score => s_score, :score => total_score, - :subjective_score => subjective_score + :subjective_score => subjective_score, + :commit_method => exercise_user&.commit_method.to_i > 0 ? exercise_user&.commit_method.to_i : 3 } exercise_user.update_attributes(commit_option) end @@ -108,7 +109,8 @@ class ExercisePublishTask :end_at => Time.now, :objective_score => s_score, :score => total_score, - :subjective_score => subjective_score + :subjective_score => subjective_score, + :commit_method => exercise_user&.commit_method.to_i > 0 ? exercise_user&.commit_method.to_i : 3 } exercise_user.update_attributes(commit_option) end diff --git a/app/views/admins/laboratories/index.html.erb b/app/views/admins/laboratories/index.html.erb new file mode 100644 index 000000000..012eed792 --- /dev/null +++ b/app/views/admins/laboratories/index.html.erb @@ -0,0 +1,19 @@ +<% define_admin_breadcrumbs do %> + <% add_admin_breadcrumb('云上实验室') %> +<% end %> + +
+ <%= form_tag(admins_laboratories_path(unsafe_params), method: :get, class: 'form-inline search-form flex-1', remote: true) do %> + <%= text_field_tag(:keyword, params[:keyword], class: 'form-control col-6 col-md-4 ml-3', placeholder: '学校名称/二级域名前缀检索') %> + <%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %> + <% end %> + + <%= javascript_void_link '新建', class: 'btn btn-primary', data: { toggle: 'modal', target: '.admin-create-laboratory-modal' } %> +
+ +
+ <%= render(partial: 'admins/laboratories/shared/list', locals: { laboratories: @laboratories }) %> +
+ +<%= render 'admins/laboratories/shared/create_laboratory_modal' %> +<%= render 'admins/laboratories/shared/add_laboratory_user_modal' %> \ No newline at end of file diff --git a/app/views/admins/laboratories/index.js.erb b/app/views/admins/laboratories/index.js.erb new file mode 100644 index 000000000..dc17c6a6d --- /dev/null +++ b/app/views/admins/laboratories/index.js.erb @@ -0,0 +1 @@ +$('.laboratory-list-container').html("<%= j(render partial: 'admins/laboratories/shared/list', locals: { laboratories: @laboratories }) %>"); \ No newline at end of file diff --git a/app/views/admins/laboratories/shared/_add_laboratory_user_modal.html.erb b/app/views/admins/laboratories/shared/_add_laboratory_user_modal.html.erb new file mode 100644 index 000000000..a13565cd6 --- /dev/null +++ b/app/views/admins/laboratories/shared/_add_laboratory_user_modal.html.erb @@ -0,0 +1,30 @@ + \ No newline at end of file diff --git a/app/views/admins/laboratories/shared/_create_laboratory_modal.html.erb b/app/views/admins/laboratories/shared/_create_laboratory_modal.html.erb new file mode 100644 index 000000000..0a77477d3 --- /dev/null +++ b/app/views/admins/laboratories/shared/_create_laboratory_modal.html.erb @@ -0,0 +1,28 @@ + \ No newline at end of file diff --git a/app/views/admins/laboratories/shared/_laboratory_item.html.erb b/app/views/admins/laboratories/shared/_laboratory_item.html.erb new file mode 100644 index 000000000..5dd97b549 --- /dev/null +++ b/app/views/admins/laboratories/shared/_laboratory_item.html.erb @@ -0,0 +1,40 @@ +<% school = laboratory.school %> +<%= school&.name || 'EduCoder主站' %> + + <% if laboratory.identifier %> + <%= link_to laboratory.site, "https://#{laboratory.site}", target: '_blank' %> + <% else %> + -- + <% end %> + + + <% if school && school.identifier.present? %> + <%= link_to school.identifier.to_s, statistics_college_path(school.identifier), target: '_blank' %> + <% else %> + -- + <% end %> + + +
+ <% laboratory.users.each do |user| %> + + <%= link_to user.real_name, "/users/#{user.login}", target: '_blank', data: { toggle: 'tooltip', title: '个人主页' } %> + <%= link_to(admins_laboratory_laboratory_user_path(laboratory, user_id: user.id), + method: :delete, remote: true, class: 'ml-1 delete-laboratory-user-action', + data: { confirm: '确认删除吗?' }) do %> + + <% end %> + + <% end %> +
+ +<%= laboratory.created_at.strftime('%Y-%m-%d %H:%M') %> + + <%= link_to '定制', admins_laboratory_laboratory_setting_path(laboratory) %> + + <% if school.present? && laboratory.id != 1 %> + <%= javascript_void_link '添加管理员', class: 'action', data: { laboratory_id: laboratory.id, toggle: 'modal', target: '.admin-add-laboratory-user-modal' } %> + + <%= delete_link '删除', admins_laboratory_path(laboratory, element: ".laboratory-item-#{laboratory.id}"), class: 'delete-laboratory-action' %> + <% end %> + \ No newline at end of file diff --git a/app/views/admins/laboratories/shared/_list.html.erb b/app/views/admins/laboratories/shared/_list.html.erb new file mode 100644 index 000000000..33a47eed7 --- /dev/null +++ b/app/views/admins/laboratories/shared/_list.html.erb @@ -0,0 +1,25 @@ + + + + + + + + + + + + + <% if laboratories.present? %> + <% laboratories.each do |laboratory| %> + + <%= render 'admins/laboratories/shared/laboratory_item', laboratory: laboratory %> + + <% end %> + <% else %> + <%= render 'admins/shared/no_data_for_table' %> + <% end %> + +
单位名称域名统计链接管理员<%= sort_tag('创建时间', name: 'id', path: admins_laboratories_path) %>操作
+ +<%= render partial: 'admins/shared/paginate', locals: { objects: laboratories } %> \ No newline at end of file diff --git a/app/views/admins/laboratory_settings/show.html.erb b/app/views/admins/laboratory_settings/show.html.erb new file mode 100644 index 000000000..120bba6cb --- /dev/null +++ b/app/views/admins/laboratory_settings/show.html.erb @@ -0,0 +1,131 @@ +<% define_admin_breadcrumbs do %> + <% add_admin_breadcrumb('云上实验室', admins_laboratories_path) %> + <% add_admin_breadcrumb('单位定制') %> +<% end %> + +
+ <%= simple_form_for(@laboratory, url: admins_laboratory_laboratory_setting_path(@laboratory), method: 'patch', html: { enctype: 'multipart/form-data' }) do |f| %> + <% setting = @laboratory.laboratory_setting %> + +
+
网站域名设置
+ +
+
+
+ https:// +
+ <%= text_field_tag :identifier, @laboratory.identifier, + maxlength: 15, class: 'form-control font-16', + 'onKeyUp': 'value=value.replace(/[^\w\.\-\/]/ig,"").toLowerCase()', + style: 'text-transform:lowercase'%> +
+ <% rails_env = EduSetting.get('rails_env') %> + <%= rails_env && rails_env != 'production' ? ".#{rails_env}.educoder.net" : '.educoder.net' %> +
+
+ <%# if @laboratory.errors && @laboratory.errors.key?(:identifier) %> + + <%# end %> +
+
+ +
+
网站名称设置
+ +
+ <%= text_field_tag :name, setting.name, placeholder: '输入20个字以内的网站名称', maxlength: 20, class: 'form-control col-12 col-md-4' %> +
+
+ +
+
Logo设置
+ +
+
+ <% nav_logo_img = setting.nav_logo_url %> + +
+
网站导航logo
+
格式:PNG、JPG
+
尺寸:高度38px以内,宽等比例缩放
+
+
+ +
+ <% login_logo_img = setting.login_logo_url %> + +
+
登录页面logo
+
格式:PNG、JPG
+
尺寸:高度90px以内,宽等比例缩放
+
+
+ +
+ <% tab_logo_img = setting.tab_logo_url %> +
+ + <%= file_field_tag(:tab_logo, accept: 'image/x-icon', style: 'display: none', value: params[:tab_logo]) %> + +
+
+
浏览器导航栏logo
+
格式:ico
+
尺寸:16*16 32*32 48*48 64*64
+
+
+
+
+ +
+
导航设置
+ +
+ + + + + + + + + + <% (setting.navbar || setting.default_navbar).each do |nav| %> + + + + + + <% end %> + +
导航名称导航链接是否展示
<%= text_field_tag('navbar[][name]', nav['name'], id: nil, class: 'form-control') %><%= text_field_tag('navbar[][link]', nav['link'], id: nil, class: 'form-control') %> + <%= check_box_tag('navbar[][hidden]', 0, !nav['hidden'], id: nil, class: 'font-16') %> +
+
+
+ +
+
底部备案信息设置
+ + +
+ +
+ +
+ <%= javascript_void_link '保存', class: 'btn btn-primary mr-3 px-4 submit-btn' %> + <%= link_to '取消', admins_laboratories_path, class: 'btn btn-secondary px-4' %> +
+ <% end %> +
\ No newline at end of file diff --git a/app/views/admins/laboratory_users/create.js.erb b/app/views/admins/laboratory_users/create.js.erb new file mode 100644 index 000000000..f43fd7887 --- /dev/null +++ b/app/views/admins/laboratory_users/create.js.erb @@ -0,0 +1,4 @@ +$('.modal.admin-add-laboratory-user-modal').modal('hide'); +$.notify({ message: '操作成功' }); + +$('.laboratory-list-table .laboratory-item-<%= current_laboratory.id %>').html("<%= j(render partial: 'admins/laboratories/shared/laboratory_item', locals: { laboratory: current_laboratory }) %>") \ No newline at end of file diff --git a/app/views/admins/laboratory_users/destroy.js.erb b/app/views/admins/laboratory_users/destroy.js.erb new file mode 100644 index 000000000..16ef62910 --- /dev/null +++ b/app/views/admins/laboratory_users/destroy.js.erb @@ -0,0 +1,2 @@ +$.notify({ message: '操作成功' }); +$('.laboratory-list-container .laboratory-item-<%= current_laboratory.id %> .laboratory-user-item-<%= @laboratory_user.user_id %>').remove(); \ No newline at end of file diff --git a/app/views/admins/schools/shared/_list.html.erb b/app/views/admins/schools/shared/_list.html.erb index 74df29cee..b1453f1a1 100644 --- a/app/views/admins/schools/shared/_list.html.erb +++ b/app/views/admins/schools/shared/_list.html.erb @@ -7,7 +7,7 @@ 单位名称 地区 城市 - 详细地址 + 详细地址 <%= sort_tag('用户数', name: 'users_count', path: admins_schools_path) %> 部门数 <%= sort_tag('创建时间', name: 'created_at', path: admins_schools_path) %> diff --git a/app/views/admins/shared/_sidebar.html.erb b/app/views/admins/shared/_sidebar.html.erb index 553820e69..145910928 100644 --- a/app/views/admins/shared/_sidebar.html.erb +++ b/app/views/admins/shared/_sidebar.html.erb @@ -33,23 +33,13 @@ <%= sidebar_item_group('#schools-submenu', '单位管理', icon: 'building') do %>
  • <%= sidebar_item(admins_schools_path, '单位列表', icon: 'university', controller: 'admins-schools') %>
  • <%= sidebar_item(admins_departments_path, '部门列表', icon: 'sitemap', controller: 'admins-departments') %>
  • +
  • <%= sidebar_item(admins_laboratories_path, '云上实验室', icon: 'cloud', controller: 'admins-laboratories') %>
  • <% end %> - - <%#= sidebar_item_group('#course-submenu', '课堂+', icon: 'mortar-board') do %> - - - - - <%# end %> - -
  • <%= sidebar_item_group('#user-submenu', '用户', icon: 'user') do %>
  • <%= sidebar_item(admins_users_path, '用户列表', icon: 'user', controller: 'admins-users') %>
  • - - <% end %> diff --git a/app/views/colleges/_teacher_rank.html.erb b/app/views/colleges/_teacher_rank.html.erb index 66b46ba74..426b9792c 100644 --- a/app/views/colleges/_teacher_rank.html.erb +++ b/app/views/colleges/_teacher_rank.html.erb @@ -1,12 +1,7 @@ <% if @teachers.present? %> <% @teachers.each_with_index do |teacher, index| %> - - <% if index < 3 %> - - <% else %> - <%= index + 1 %> - <% end %> + <%= index + 1 %> <%= teacher['real_name'] %> <%= teacher['course_count'] %> <%= teacher['shixun_work_count'] %> diff --git a/app/views/courses/course_groups.json.jbuilder b/app/views/courses/course_groups.json.jbuilder new file mode 100644 index 000000000..48a5922a6 --- /dev/null +++ b/app/views/courses/course_groups.json.jbuilder @@ -0,0 +1,11 @@ +json.course_groups @course_groups.each do |group| + json.(group, :id, :course_members_count, :name) + json.invite_code group.invite_code if @user_course_identity < Course::STUDENT + json.member_manager member_manager(group, @teachers) if @user_course_identity < Course::NORMAL +end + +if @user_course_identity == Course::STUDENT + json.current_group_id @current_group_id +end +json.none_group_member_count @course.none_group_count +json.group_count @all_group_count \ No newline at end of file diff --git a/app/views/courses/students.json.jbuilder b/app/views/courses/students.json.jbuilder index a7585672f..0b5d7fe71 100644 --- a/app/views/courses/students.json.jbuilder +++ b/app/views/courses/students.json.jbuilder @@ -1,12 +1,17 @@ json.students do json.array! @students do |student| json.user_id student.user_id - json.login student.user.try(:login) + # json.login student.user.try(:login) json.name student.user.try(:real_name) json.name_link user_path(student.user) json.student_id student.user.try(:student_id) json.course_group_name student.course_group.try(:name) json.course_member_id student.id + if @user_course_identity < Course::ASSISTANT_PROFESSOR && !params[:course_group_id].present? + json.member_roles student.user.course_role(@course) + end + json.user_phone student.user.hidden_phone + json.user_mail student.user.hidden_mail end end json.students_count @students_count diff --git a/app/views/courses/teachers.json.jbuilder b/app/views/courses/teachers.json.jbuilder index 040ffb2aa..19a92790d 100644 --- a/app/views/courses/teachers.json.jbuilder +++ b/app/views/courses/teachers.json.jbuilder @@ -16,6 +16,9 @@ json.teacher_list do end json.graduation_group teacher.graduation_group.try(:name) json.graduation_group_id teacher.graduation_group.try(:id) + if @user_course_identity < Course::ASSISTANT_PROFESSOR + json.member_roles teacher.user.course_role(@course) + end end end json.teacher_list_size @teacher_list_size diff --git a/app/views/courses/top_banner.json.jbuilder b/app/views/courses/top_banner.json.jbuilder index 916fccb05..877ffcdf1 100644 --- a/app/views/courses/top_banner.json.jbuilder +++ b/app/views/courses/top_banner.json.jbuilder @@ -24,5 +24,4 @@ json.course_identity @user_course_identity json.excellent @course.excellent if @course.is_end == 0 json.days_remaining (@course.end_date.to_date - Time.now.to_date).to_i -end - +end \ No newline at end of file diff --git a/app/views/ecs/course_achievement_methods/show.json.jbuilder b/app/views/ecs/course_achievement_methods/show.json.jbuilder index 9105c9615..77d1ce5a7 100644 --- a/app/views/ecs/course_achievement_methods/show.json.jbuilder +++ b/app/views/ecs/course_achievement_methods/show.json.jbuilder @@ -1,3 +1,32 @@ json.course_targets @course_targets, partial: 'ecs/course_targets/shared/ec_course_target_with_achievement_methods', as: :ec_course_target +json.course_targets do + json.array! @course_targets do |course_target| + json.extract! course_target, :id, :position, :content + + json.course_achievement_methods do + json.array! course_target.ec_course_achievement_methods do |achievement_method| + evaluation = achievement_method.ec_course_evaluation + json.extract! achievement_method, :id, :score, :percentage + + json.course_evaluation do + json.partial! 'ecs/course_evaluations/shared/ec_course_evaluation_only', ec_course_evaluation: evaluation + end + + json.course_evaluation_relates do + json.array! achievement_method.ec_achievement_evaluation_relates do |relate| + json.extract! relate, :id, :position, :ec_course_evaluation_subitem_id + + subitem = relate.ec_course_evaluation_subitem + if evaluation.is_course_type? + json.name subitem&.name + else + json.name subitem&.name ? "#{evaluation.name}(#{relate.position}):#{subitem&.name}" : "#{evaluation.name}(#{relate.position})" + end + end + end + end + end + end +end \ No newline at end of file diff --git a/app/views/ecs/course_evaluations/slimmer.json.jbuilder b/app/views/ecs/course_evaluations/slimmer.json.jbuilder index 6e0faef3e..1f4dc0cc0 100644 --- a/app/views/ecs/course_evaluations/slimmer.json.jbuilder +++ b/app/views/ecs/course_evaluations/slimmer.json.jbuilder @@ -1 +1,7 @@ -json.course_evaluations @course_evaluations, partial: 'ecs/course_evaluations/shared/ec_course_evaluation_slim', as: :ec_course_evaluation +json.course_evaluations do + json.array! @course_evaluations do |course_evaluation| + json.partial! 'ecs/course_evaluations/shared/ec_course_evaluation_slim', ec_course_evaluation: course_evaluation + + json.evaluation_relates course_evaluation.evaluation_relates + end +end \ No newline at end of file diff --git a/app/views/ecs/course_managers/create.json.jbuilder b/app/views/ecs/course_managers/create.json.jbuilder deleted file mode 100644 index ff7ff01e5..000000000 --- a/app/views/ecs/course_managers/create.json.jbuilder +++ /dev/null @@ -1 +0,0 @@ -json.partial! 'ecs/shared/user', user: @user diff --git a/app/views/ecs/course_targets/with_achievement_methods.json.jbuilder b/app/views/ecs/course_targets/with_achievement_methods.json.jbuilder index 689504ec3..210151499 100644 --- a/app/views/ecs/course_targets/with_achievement_methods.json.jbuilder +++ b/app/views/ecs/course_targets/with_achievement_methods.json.jbuilder @@ -1,2 +1,29 @@ +json.course_targets do + json.array! @course_targets do |course_target| + json.extract! course_target, :id, :position, :content -json.course_targets @course_targets, partial: 'ecs/course_targets/shared/ec_course_target_with_achievement_methods', as: :ec_course_target + json.course_achievement_methods do + json.array! course_target.ec_course_achievement_methods do |achievement_method| + evaluation = achievement_method.ec_course_evaluation + json.extract! achievement_method, :id, :score, :percentage + + json.course_evaluation do + json.partial! 'ecs/course_evaluations/shared/ec_course_evaluation_only', ec_course_evaluation: evaluation + end + + json.course_evaluation_relates do + json.array! achievement_method.ec_achievement_evaluation_relates do |relate| + json.extract! relate, :id, :position, :ec_course_evaluation_subitem_id + + subitem = relate.ec_course_evaluation_subitem + if evaluation.is_course_type? + json.name subitem&.name + else + json.name subitem&.name ? "#{evaluation.name}(#{relate.position}):#{subitem&.name}" : "#{evaluation.name}(#{relate.position})" + end + end + end + end + end + end +end \ No newline at end of file diff --git a/app/views/exercises/_exercise_user.json.jbuilder b/app/views/exercises/_exercise_user.json.jbuilder index d41fb9e20..5f00bbd70 100644 --- a/app/views/exercises/_exercise_user.json.jbuilder +++ b/app/views/exercises/_exercise_user.json.jbuilder @@ -8,6 +8,7 @@ json.user_group_name ex_user_info[:user_group_name] json.student_id ex_user_info[:student_id] json.commit_status ex_user_info[:commit_status] json.end_at ex_user_info[:end_at] +json.commit_method exercise_user&.commit_method.to_i if subjective_type == 1 json.objective_score ex_user_info[:ex_object_score] json.subjective_score ex_user_info[:ex_subject_score] diff --git a/app/views/exercises/_user_exercise_info.json.jbuilder b/app/views/exercises/_user_exercise_info.json.jbuilder index 0d21cc593..bdac3a985 100644 --- a/app/views/exercises/_user_exercise_info.json.jbuilder +++ b/app/views/exercises/_user_exercise_info.json.jbuilder @@ -9,6 +9,7 @@ json.exercise_answer_user do json.user_id ex_answerer.id json.login ex_answerer.login if exercise_user.present? + json.commit_method exercise_user&.commit_method.to_i json.start_at exercise_user.start_at json.score exercise_user.score.present? ? exercise_user.score.round(1).to_s : "0.0" end diff --git a/app/views/exercises/common_header.json.jbuilder b/app/views/exercises/common_header.json.jbuilder index 5d33aca66..d43d7c3f8 100644 --- a/app/views/exercises/common_header.json.jbuilder +++ b/app/views/exercises/common_header.json.jbuilder @@ -1,6 +1,6 @@ json.course_is_end @course.is_end # true表示已结束,false表示未结束 json.extract! @exercise, :id,:exercise_name,:exercise_description,:show_statistic -json.time @user_left_time +json.time (@user_left_time.to_i / 60) json.exercise_status @ex_status diff --git a/app/views/exercises/publish_groups.json.jbuilder b/app/views/exercises/publish_groups.json.jbuilder new file mode 100644 index 000000000..72cefdd1a --- /dev/null +++ b/app/views/exercises/publish_groups.json.jbuilder @@ -0,0 +1,6 @@ +json.course_groups @course_groups do |group| + json.id group.id + json.name group.name + json.end_time @group_settings.select{|group_setting| group_setting.course_group_id == group.id}.first&.end_time +end +json.end_time @exercise.end_time \ No newline at end of file diff --git a/app/views/graduation_tasks/_public_navigation.json.jbuilder b/app/views/graduation_tasks/_public_navigation.json.jbuilder index 00280c31b..992d03fd8 100644 --- a/app/views/graduation_tasks/_public_navigation.json.jbuilder +++ b/app/views/graduation_tasks/_public_navigation.json.jbuilder @@ -2,4 +2,5 @@ json.partial! "graduation_topics/show_navigation", locals: {course: course, grad json.task_status task_curr_status(graduation, course)[:status] json.task_name graduation.name json.task_id graduation.id -json.status graduation.status \ No newline at end of file +json.status graduation.status +json.end_time graduation.end_time \ No newline at end of file diff --git a/app/views/homework_commons/publish_groups.json.jbuilder b/app/views/homework_commons/publish_groups.json.jbuilder index 67722bb04..f3a99dbca 100644 --- a/app/views/homework_commons/publish_groups.json.jbuilder +++ b/app/views/homework_commons/publish_groups.json.jbuilder @@ -1,4 +1,6 @@ json.course_groups @course_groups do |group| json.id group.id json.name group.name -end \ No newline at end of file + json.end_time @group_settings.select{|group_setting| group_setting.course_group_id == group.id}.first&.end_time +end +json.end_time @homework.end_time \ No newline at end of file diff --git a/app/views/homework_commons/works_list.json.jbuilder b/app/views/homework_commons/works_list.json.jbuilder index e567ea79a..839b40bfd 100644 --- a/app/views/homework_commons/works_list.json.jbuilder +++ b/app/views/homework_commons/works_list.json.jbuilder @@ -23,7 +23,7 @@ if @user_course_identity < Course::STUDENT if @homework.homework_type != "practice" json.teacher_comment teacher_comment @homework, @current_user.id end - json.task_status homework_status @homework, @member + json.task_status @homework.homework_type != "practice" ? homework_status(@homework, @member) : practice_homework_status(@homework, @member) json.course_group_info course_group_info @course, @current_user.id elsif @user_course_identity == Course::STUDENT diff --git a/app/views/polls/publish_groups.json.jbuilder b/app/views/polls/publish_groups.json.jbuilder new file mode 100644 index 000000000..f63a2ea90 --- /dev/null +++ b/app/views/polls/publish_groups.json.jbuilder @@ -0,0 +1,6 @@ +json.course_groups @course_groups do |group| + json.id group.id + json.name group.name + json.end_time @group_settings.select{|group_setting| group_setting.course_group_id == group.id}.first&.end_time +end +json.end_time @poll.end_time \ No newline at end of file diff --git a/app/views/settings/show.json.jbuilder b/app/views/settings/show.json.jbuilder new file mode 100644 index 000000000..0765e303b --- /dev/null +++ b/app/views/settings/show.json.jbuilder @@ -0,0 +1,12 @@ +json.setting do + setting = @laboratory.laboratory_setting + + json.name setting.name || default_setting.name + json.nav_logo_url setting.nav_logo_url || default_setting.nav_logo_url + json.login_logo_url setting.login_logo_url || default_setting.login_logo_url + json.tab_logo_url setting.tab_logo_url || default_setting.tab_logo_url + + json.navbar setting.navbar || default_setting.navbar + + json.footer setting.footer || default_setting.footer +end \ No newline at end of file diff --git a/app/views/shixuns/send_to_course.json.jbuilder b/app/views/shixuns/send_to_course.json.jbuilder index b2e30f985..13b221d75 100644 --- a/app/views/shixuns/send_to_course.json.jbuilder +++ b/app/views/shixuns/send_to_course.json.jbuilder @@ -1,3 +1,4 @@ json.status 1 json.message "发送成功" -json.course_id @course.id \ No newline at end of file +json.course_id @course.id +json.first_category_url module_url(@course.none_hidden_course_modules.first, @course) \ No newline at end of file diff --git a/app/views/templates/show.json.jbuilder b/app/views/templates/show.json.jbuilder new file mode 100644 index 000000000..cff89037b --- /dev/null +++ b/app/views/templates/show.json.jbuilder @@ -0,0 +1,3 @@ +json.template do + json.partial! 'attachments/attachment_simple', attachment: @template.attachments.last +end \ No newline at end of file diff --git a/app/views/users/accounts/show.json.jbuilder b/app/views/users/accounts/show.json.jbuilder index 6b28bda55..ec81cc6bf 100644 --- a/app/views/users/accounts/show.json.jbuilder +++ b/app/views/users/accounts/show.json.jbuilder @@ -1,5 +1,7 @@ -json.extract! observed_user, :id, :nickname, :phone, :mail, :show_realname +json.extract! observed_user, :id, :nickname, :show_realname +json.phone observed_user.hidden_phone +json.mail observed_user.hidden_mail json.avatar_url url_to_avatar(observed_user) user = ActiveDecorator::Decorator.instance.decorate(observed_user) json.name user.name diff --git a/config/admins/sidebar.yml b/config/admins/sidebar.yml index 30af794b7..9da34a014 100644 --- a/config/admins/sidebar.yml +++ b/config/admins/sidebar.yml @@ -1 +1,2 @@ -admins-mirror_scripts: 'admins-mirror_repositories' \ No newline at end of file +admins-mirror_scripts: 'admins-mirror_repositories' +admins-laboratory_settings: 'admins-laboratories' \ No newline at end of file diff --git a/config/initializers/util_wechat_init.rb b/config/initializers/wechat_init.rb similarity index 79% rename from config/initializers/util_wechat_init.rb rename to config/initializers/wechat_init.rb index cb39afcaf..946e5f638 100644 --- a/config/initializers/util_wechat_init.rb +++ b/config/initializers/wechat_init.rb @@ -12,5 +12,5 @@ rescue => ex wechat_config = {} end -Util::Wechat.appid = wechat_config['appid'] -Util::Wechat.secret = wechat_config['secret'] +Wechat::OfficialAccount.appid = wechat_config['appid'] +Wechat::OfficialAccount.secret = wechat_config['secret'] diff --git a/config/locales/laboratories/zh-CN.yml b/config/locales/laboratories/zh-CN.yml new file mode 100644 index 000000000..42127f0a1 --- /dev/null +++ b/config/locales/laboratories/zh-CN.yml @@ -0,0 +1,7 @@ +zh-CN: + activerecord: + models: + laboratory: '' + attributes: + laboratory: + identifier: '二级域名' \ No newline at end of file diff --git a/db/migrate/20190930020534_migrate_forum_name.rb b/db/migrate/20190930020534_migrate_forum_name.rb new file mode 100644 index 000000000..102d8c9a0 --- /dev/null +++ b/db/migrate/20190930020534_migrate_forum_name.rb @@ -0,0 +1,9 @@ +class MigrateForumName < ActiveRecord::Migration[5.2] + def change + forum = Forum.find_by(id: 16) + if forum.present? + forum.update_attributes(name: "通知公告") + forum.memos.destroy_all + end + end +end diff --git a/db/migrate/20190930032241_create_diff_records.rb b/db/migrate/20190930032241_create_diff_records.rb new file mode 100644 index 000000000..3e02e0a2b --- /dev/null +++ b/db/migrate/20190930032241_create_diff_records.rb @@ -0,0 +1,11 @@ +class CreateDiffRecords < ActiveRecord::Migration[5.2] + def change + create_table :diff_records do |t| + t.references :user + t.references :container, polymorphic: true + t.string :column_name + + t.timestamps + end + end +end diff --git a/db/migrate/20190930032255_create_diff_record_contents.rb b/db/migrate/20190930032255_create_diff_record_contents.rb new file mode 100644 index 000000000..f3d56b8b2 --- /dev/null +++ b/db/migrate/20190930032255_create_diff_record_contents.rb @@ -0,0 +1,9 @@ +class CreateDiffRecordContents < ActiveRecord::Migration[5.2] + def change + create_table :diff_record_contents do |t| + t.references :diff_record + + t.text :content + end + end +end diff --git a/db/migrate/20191007010405_resort_portal_image_data.rb b/db/migrate/20191007010405_resort_portal_image_data.rb new file mode 100644 index 000000000..665b48466 --- /dev/null +++ b/db/migrate/20191007010405_resort_portal_image_data.rb @@ -0,0 +1,7 @@ +class ResortPortalImageData < ActiveRecord::Migration[5.2] + def change + PortalImage.order(position: :asc).each_with_index do |image, index| + image.update!(position: index + 1) + end + end +end diff --git a/db/migrate/20191010011844_create_laboratories.rb b/db/migrate/20191010011844_create_laboratories.rb new file mode 100644 index 000000000..3dfb442f0 --- /dev/null +++ b/db/migrate/20191010011844_create_laboratories.rb @@ -0,0 +1,12 @@ +class CreateLaboratories < ActiveRecord::Migration[5.2] + def change + create_table :laboratories do |t| + t.references :school + t.string :identifier + + t.timestamps + + t.index :identifier, unique: true + end + end +end diff --git a/db/migrate/20191010012226_create_laboratory_users.rb b/db/migrate/20191010012226_create_laboratory_users.rb new file mode 100644 index 000000000..1b7ae762d --- /dev/null +++ b/db/migrate/20191010012226_create_laboratory_users.rb @@ -0,0 +1,8 @@ +class CreateLaboratoryUsers < ActiveRecord::Migration[5.2] + def change + create_table :laboratory_users do |t| + t.references :laboratory + t.references :user + end + end +end diff --git a/db/migrate/20191010063403_create_laboratory_settings.rb b/db/migrate/20191010063403_create_laboratory_settings.rb new file mode 100644 index 000000000..7f0a5f015 --- /dev/null +++ b/db/migrate/20191010063403_create_laboratory_settings.rb @@ -0,0 +1,9 @@ +class CreateLaboratorySettings < ActiveRecord::Migration[5.2] + def change + create_table :laboratory_settings do |t| + t.references :laboratory + + t.text :config + end + end +end diff --git a/db/migrate/20191011025619_init_edu_coder_laboratory.rb b/db/migrate/20191011025619_init_edu_coder_laboratory.rb new file mode 100644 index 000000000..831ca3985 --- /dev/null +++ b/db/migrate/20191011025619_init_edu_coder_laboratory.rb @@ -0,0 +1,22 @@ +class InitEduCoderLaboratory < ActiveRecord::Migration[5.2] + def change + ActiveRecord::Base.transaction do + laboratory = Laboratory.create!(id: 1, identifier: 'www') + setting = laboratory.build_laboratory_setting + footer = %Q{ + + } + config = setting.class.default_config.merge(name: 'EduCoder', footer: footer) + setting.config = config + setting.save! + end + end +end diff --git a/db/migrate/20191011030441_add_commit_method_to_exercise_user.rb b/db/migrate/20191011030441_add_commit_method_to_exercise_user.rb new file mode 100644 index 000000000..060e5eb5f --- /dev/null +++ b/db/migrate/20191011030441_add_commit_method_to_exercise_user.rb @@ -0,0 +1,5 @@ +class AddCommitMethodToExerciseUser < ActiveRecord::Migration[5.2] + def change + add_column :exercise_users, :commit_method, :integer, :default => 0 + end +end diff --git a/public/assets/.sprockets-manifest-4627fa5586ef7fed55ca286af7c028e9.json b/public/assets/.sprockets-manifest-4627fa5586ef7fed55ca286af7c028e9.json new file mode 100644 index 000000000..b8b49cc9d --- /dev/null +++ b/public/assets/.sprockets-manifest-4627fa5586ef7fed55ca286af7c028e9.json @@ -0,0 +1 @@ +{"files":{"admin-cd9ca8bacc973ce2dbace30c97f6c40bc08e2c2ee44972f668e738e1902c0121.js":{"logical_path":"admin.js","mtime":"2019-09-11T16:20:07+08:00","size":4350881,"digest":"cd9ca8bacc973ce2dbace30c97f6c40bc08e2c2ee44972f668e738e1902c0121","integrity":"sha256-zZyousyXPOLbrOMMl/bEC8COLC7kSXL2aOc44ZAsASE="},"admin-a1b3356efe50ff4717cf22475639b5333c5354ba03fd107c9b7a8d4ae76f47aa.css":{"logical_path":"admin.css","mtime":"2019-09-11T16:20:07+08:00","size":773445,"digest":"a1b3356efe50ff4717cf22475639b5333c5354ba03fd107c9b7a8d4ae76f47aa","integrity":"sha256-obM1bv5Q/0cXzyJHVjm1MzxTVLoD/RB8m3qNSudvR6o="},"font-awesome/fontawesome-webfont-7bfcab6db99d5cfbf1705ca0536ddc78585432cc5fa41bbd7ad0f009033b2979.eot":{"logical_path":"font-awesome/fontawesome-webfont.eot","mtime":"2019-08-14T17:22:43+08:00","size":165742,"digest":"7bfcab6db99d5cfbf1705ca0536ddc78585432cc5fa41bbd7ad0f009033b2979","integrity":"sha256-e/yrbbmdXPvxcFygU23ceFhUMsxfpBu9etDwCQM7KXk="},"font-awesome/fontawesome-webfont-2adefcbc041e7d18fcf2d417879dc5a09997aa64d675b7a3c4b6ce33da13f3fe.woff2":{"logical_path":"font-awesome/fontawesome-webfont.woff2","mtime":"2019-08-14T17:22:43+08:00","size":77160,"digest":"2adefcbc041e7d18fcf2d417879dc5a09997aa64d675b7a3c4b6ce33da13f3fe","integrity":"sha256-Kt78vAQefRj88tQXh53FoJmXqmTWdbejxLbOM9oT8/4="},"font-awesome/fontawesome-webfont-ba0c59deb5450f5cb41b3f93609ee2d0d995415877ddfa223e8a8a7533474f07.woff":{"logical_path":"font-awesome/fontawesome-webfont.woff","mtime":"2019-08-14T17:22:43+08:00","size":98024,"digest":"ba0c59deb5450f5cb41b3f93609ee2d0d995415877ddfa223e8a8a7533474f07","integrity":"sha256-ugxZ3rVFD1y0Gz+TYJ7i0NmVQVh33foiPoqKdTNHTwc="},"font-awesome/fontawesome-webfont-aa58f33f239a0fb02f5c7a6c45c043d7a9ac9a093335806694ecd6d4edc0d6a8.ttf":{"logical_path":"font-awesome/fontawesome-webfont.ttf","mtime":"2019-08-14T17:22:43+08:00","size":165548,"digest":"aa58f33f239a0fb02f5c7a6c45c043d7a9ac9a093335806694ecd6d4edc0d6a8","integrity":"sha256-qljzPyOaD7AvXHpsRcBD16msmgkzNYBmlOzW1O3A1qg="},"font-awesome/fontawesome-webfont-ad6157926c1622ba4e1d03d478f1541368524bfc46f51e42fe0d945f7ef323e4.svg":{"logical_path":"font-awesome/fontawesome-webfont.svg","mtime":"2019-08-14T17:22:43+08:00","size":444379,"digest":"ad6157926c1622ba4e1d03d478f1541368524bfc46f51e42fe0d945f7ef323e4","integrity":"sha256-rWFXkmwWIrpOHQPUePFUE2hSS/xG9R5C/g2UX37zI+Q="},"college-18f5e8400331634e898a35acc2187815c096c25e0ab74aba341ae916166cd287.js":{"logical_path":"college.js","mtime":"2019-09-26T14:40:40+08:00","size":3352744,"digest":"18f5e8400331634e898a35acc2187815c096c25e0ab74aba341ae916166cd287","integrity":"sha256-GPXoQAMxY06JijWswhh4FcCWwl4Kt0q6NBrpFhZs0oc="},"college-944d4273f62c7538368b9017fdd3387b5e3bea31a87873770eb231324546d4d9.css":{"logical_path":"college.css","mtime":"2019-09-11T16:20:07+08:00","size":546841,"digest":"944d4273f62c7538368b9017fdd3387b5e3bea31a87873770eb231324546d4d9","integrity":"sha256-lE1Cc/YsdTg2i5AX/dM4e1476jGoeHN3DrIxMkVG1Nk="},"logo-7ff112568709bf97f9898fe87249b7a8f200ff1f48d537d85af87215f1870423.png":{"logical_path":"logo.png","mtime":"2019-09-03T08:55:53+08:00","size":2816,"digest":"7ff112568709bf97f9898fe87249b7a8f200ff1f48d537d85af87215f1870423","integrity":"sha256-f/ESVocJv5f5iY/ockm3qPIA/x9I1TfYWvhyFfGHBCM="},"application-9cfbc3d792599a1d0de5c7b84209e1c2b2e60336f0f01e19f0581663918708fb.js":{"logical_path":"application.js","mtime":"2019-09-26T14:40:40+08:00","size":600706,"digest":"9cfbc3d792599a1d0de5c7b84209e1c2b2e60336f0f01e19f0581663918708fb","integrity":"sha256-nPvD15JZmh0N5ce4QgnhwrLmAzbw8B4Z8FgWY5GHCPs="},"application-5eb87c6e13676d0183317debce17fade27e68c4acee28c419438da15d53c94f2.css":{"logical_path":"application.css","mtime":"2019-09-11T16:20:07+08:00","size":1844002,"digest":"5eb87c6e13676d0183317debce17fade27e68c4acee28c419438da15d53c94f2","integrity":"sha256-Xrh8bhNnbQGDMX3rzhf63ifmjErO4oxBlDjaFdU8lPI="},"admin-c9e5ebe6191548550e27514196ea125cfbb402820ec125a0c9acf99d2d378fe4.js":{"logical_path":"admin.js","mtime":"2019-09-21T15:28:08+08:00","size":4382031,"digest":"c9e5ebe6191548550e27514196ea125cfbb402820ec125a0c9acf99d2d378fe4","integrity":"sha256-yeXr5hkVSFUOJ1FBluoSXPu0AoIOwSWgyaz5nS03j+Q="},"admin-59c59f8cae8bef4a8359286c985458110c9d03ea121516595c988943f4717c38.css":{"logical_path":"admin.css","mtime":"2019-09-21T14:49:04+08:00","size":840093,"digest":"59c59f8cae8bef4a8359286c985458110c9d03ea121516595c988943f4717c38","integrity":"sha256-WcWfjK6L70qDWShsmFRYEQydA+oSFRZZXJiJQ/RxfDg="},"college-38f953d6ba5b85d3fab63cb3c2bbf0d057ccc6454d07cfaafac3b06da37b8437.css":{"logical_path":"college.css","mtime":"2019-09-16T13:56:09+08:00","size":579109,"digest":"38f953d6ba5b85d3fab63cb3c2bbf0d057ccc6454d07cfaafac3b06da37b8437","integrity":"sha256-OPlT1rpbhdP6tjyzwrvw0FfMxkVNB8+q+sOwbaN7hDc="},"application-646b1158a4e8c1f13e684d6fe9025abc75f8d3ba5256e440802c0398223374f3.css":{"logical_path":"application.css","mtime":"2019-09-21T14:49:04+08:00","size":1988767,"digest":"646b1158a4e8c1f13e684d6fe9025abc75f8d3ba5256e440802c0398223374f3","integrity":"sha256-ZGsRWKTowfE+aE1v6QJavHX407pSVuRAgCwDmCIzdPM="},"admin-a47e37c0ec7cf5f22380249776d1e82d65b6b6aa272ed7389185aa200fa40751.js":{"logical_path":"admin.js","mtime":"2019-09-25T15:33:05+08:00","size":4383107,"digest":"a47e37c0ec7cf5f22380249776d1e82d65b6b6aa272ed7389185aa200fa40751","integrity":"sha256-pH43wOx89fIjgCSXdtHoLWW2tqonLtc4kYWqIA+kB1E="},"admin-432c4eac09b036c57ff1e88d902b8aa7df81164e4b419bac557cf1366c1d3ad9.js":{"logical_path":"admin.js","mtime":"2019-09-25T15:35:20+08:00","size":4383103,"digest":"432c4eac09b036c57ff1e88d902b8aa7df81164e4b419bac557cf1366c1d3ad9","integrity":"sha256-QyxOrAmwNsV/8eiNkCuKp9+BFk5LQZusVXzxNmwdOtk="},"admin-978e5ce607f77c26814a174f480da79ac246c2201868ef84654aa03bb6727b5a.js":{"logical_path":"admin.js","mtime":"2019-09-30T14:43:41+08:00","size":4387200,"digest":"978e5ce607f77c26814a174f480da79ac246c2201868ef84654aa03bb6727b5a","integrity":"sha256-l45c5gf3fCaBShdPSA2nmsJGwiAYaO+EZUqgO7Zye1o="},"admin-896281f4731722b0c084dbb1af21d0f34a5bc142d58aff57b391864ab71ddca7.css":{"logical_path":"admin.css","mtime":"2019-09-30T14:43:41+08:00","size":842269,"digest":"896281f4731722b0c084dbb1af21d0f34a5bc142d58aff57b391864ab71ddca7","integrity":"sha256-iWKB9HMXIrDAhNuxryHQ80pbwULViv9Xs5GGSrcd3Kc="},"application-97f313e9bb7d25476649f7d7215959cf421480fd0a3785d1956953bf94a1e8bd.css":{"logical_path":"application.css","mtime":"2019-09-30T14:43:41+08:00","size":1993118,"digest":"97f313e9bb7d25476649f7d7215959cf421480fd0a3785d1956953bf94a1e8bd","integrity":"sha256-l/MT6bt9JUdmSffXIVlZz0IUgP0KN4XRlWlTv5Sh6L0="},"admin-2cdb23442fa735025385b88f2900df04fef38b61530041a6dbe375ef0f0ae888.js":{"logical_path":"admin.js","mtime":"2019-10-11T14:38:33+08:00","size":4394616,"digest":"2cdb23442fa735025385b88f2900df04fef38b61530041a6dbe375ef0f0ae888","integrity":"sha256-LNsjRC+nNQJThbiPKQDfBP7zi2FTAEGm2+N17w8K6Ig="},"admin-2c2854b9a02158ded5a809aaf7144a8630b10354ab4e56fecc4dffcc713796cc.css":{"logical_path":"admin.css","mtime":"2019-10-10T17:12:05+08:00","size":846514,"digest":"2c2854b9a02158ded5a809aaf7144a8630b10354ab4e56fecc4dffcc713796cc","integrity":"sha256-LChUuaAhWN7VqAmq9xRKhjCxA1SrTlb+zE3/zHE3lsw="},"application-50059ae929866043b47015128702fcfba53d32a2df148e64e1d961c10651c6af.css":{"logical_path":"application.css","mtime":"2019-10-10T17:12:05+08:00","size":2001607,"digest":"50059ae929866043b47015128702fcfba53d32a2df148e64e1d961c10651c6af","integrity":"sha256-UAWa6SmGYEO0cBUShwL8+6U9MqLfFI5k4dlhwQZRxq8="}},"assets":{"admin.js":"admin-2cdb23442fa735025385b88f2900df04fef38b61530041a6dbe375ef0f0ae888.js","admin.css":"admin-2c2854b9a02158ded5a809aaf7144a8630b10354ab4e56fecc4dffcc713796cc.css","font-awesome/fontawesome-webfont.eot":"font-awesome/fontawesome-webfont-7bfcab6db99d5cfbf1705ca0536ddc78585432cc5fa41bbd7ad0f009033b2979.eot","font-awesome/fontawesome-webfont.woff2":"font-awesome/fontawesome-webfont-2adefcbc041e7d18fcf2d417879dc5a09997aa64d675b7a3c4b6ce33da13f3fe.woff2","font-awesome/fontawesome-webfont.woff":"font-awesome/fontawesome-webfont-ba0c59deb5450f5cb41b3f93609ee2d0d995415877ddfa223e8a8a7533474f07.woff","font-awesome/fontawesome-webfont.ttf":"font-awesome/fontawesome-webfont-aa58f33f239a0fb02f5c7a6c45c043d7a9ac9a093335806694ecd6d4edc0d6a8.ttf","font-awesome/fontawesome-webfont.svg":"font-awesome/fontawesome-webfont-ad6157926c1622ba4e1d03d478f1541368524bfc46f51e42fe0d945f7ef323e4.svg","college.js":"college-18f5e8400331634e898a35acc2187815c096c25e0ab74aba341ae916166cd287.js","college.css":"college-38f953d6ba5b85d3fab63cb3c2bbf0d057ccc6454d07cfaafac3b06da37b8437.css","logo.png":"logo-7ff112568709bf97f9898fe87249b7a8f200ff1f48d537d85af87215f1870423.png","application.js":"application-9cfbc3d792599a1d0de5c7b84209e1c2b2e60336f0f01e19f0581663918708fb.js","application.css":"application-50059ae929866043b47015128702fcfba53d32a2df148e64e1d961c10651c6af.css"}} \ No newline at end of file diff --git a/public/assets/admin-83f62f1d834d6b6790a87ca6927274c3729fe20d37db68a54bb547269fa72dc7.css b/public/assets/admin-2c2854b9a02158ded5a809aaf7144a8630b10354ab4e56fecc4dffcc713796cc.css similarity index 99% rename from public/assets/admin-83f62f1d834d6b6790a87ca6927274c3729fe20d37db68a54bb547269fa72dc7.css rename to public/assets/admin-2c2854b9a02158ded5a809aaf7144a8630b10354ab4e56fecc4dffcc713796cc.css index e6e9d196b..5b6bef77a 100644 --- a/public/assets/admin-83f62f1d834d6b6790a87ca6927274c3729fe20d37db68a54bb547269fa72dc7.css +++ b/public/assets/admin-2c2854b9a02158ded5a809aaf7144a8630b10354ab4e56fecc4dffcc713796cc.css @@ -25274,6 +25274,114 @@ input.form-control { color: #6c757d; } +/* line 4, app/assets/stylesheets/admins/laboratories.scss */ +.admins-laboratories-index-page .laboratory-list-table .member-container .laboratory-user { + display: -webkit-box; + display: flex; + -webkit-box-pack: center; + justify-content: center; + flex-wrap: wrap; +} + +/* line 9, app/assets/stylesheets/admins/laboratories.scss */ +.admins-laboratories-index-page .laboratory-list-table .member-container .laboratory-user .laboratory-user-item { + display: -webkit-box; + display: flex; + -webkit-box-align: center; + align-items: center; + height: 22px; + line-height: 22px; + padding: 2px 5px; + margin: 2px 2px; + border: 1px solid #91D5FF; + background-color: #E6F7FF; + color: #91D5FF; + border-radius: 4px; +} + +/* line 27, app/assets/stylesheets/admins/laboratories.scss */ +.admins-laboratory-settings-show-page .edit-laboratory-setting-container .logo-item, .admins-laboratory-settings-update-page .edit-laboratory-setting-container .logo-item { + display: -webkit-box; + display: flex; +} + +/* line 30, app/assets/stylesheets/admins/laboratories.scss */ +.admins-laboratory-settings-show-page .edit-laboratory-setting-container .logo-item-img, .admins-laboratory-settings-update-page .edit-laboratory-setting-container .logo-item-img { + display: block; + width: 80px; + height: 80px; +} + +/* line 36, app/assets/stylesheets/admins/laboratories.scss */ +.admins-laboratory-settings-show-page .edit-laboratory-setting-container .logo-item-upload, .admins-laboratory-settings-update-page .edit-laboratory-setting-container .logo-item-upload { + cursor: pointer; + position: absolute; + top: 0; + width: 80px; + height: 80px; + background: #F5F5F5; + border: 1px solid #E5E5E5; +} + +/* line 45, app/assets/stylesheets/admins/laboratories.scss */ +.admins-laboratory-settings-show-page .edit-laboratory-setting-container .logo-item-upload::before, .admins-laboratory-settings-update-page .edit-laboratory-setting-container .logo-item-upload::before { + content: ''; + position: absolute; + top: 27px; + left: 39px; + width: 2px; + height: 26px; + background: #E5E5E5; +} + +/* line 55, app/assets/stylesheets/admins/laboratories.scss */ +.admins-laboratory-settings-show-page .edit-laboratory-setting-container .logo-item-upload::after, .admins-laboratory-settings-update-page .edit-laboratory-setting-container .logo-item-upload::after { + content: ''; + position: absolute; + top: 39px; + left: 27px; + width: 26px; + height: 2px; + background: #E5E5E5; +} + +/* line 66, app/assets/stylesheets/admins/laboratories.scss */ +.admins-laboratory-settings-show-page .edit-laboratory-setting-container .logo-item-left, .admins-laboratory-settings-update-page .edit-laboratory-setting-container .logo-item-left { + position: relative; + width: 80px; + height: 80px; +} + +/* line 72, app/assets/stylesheets/admins/laboratories.scss */ +.admins-laboratory-settings-show-page .edit-laboratory-setting-container .logo-item-left.has-img .logo-item-upload, .admins-laboratory-settings-update-page .edit-laboratory-setting-container .logo-item-left.has-img .logo-item-upload { + display: none; +} + +/* line 77, app/assets/stylesheets/admins/laboratories.scss */ +.admins-laboratory-settings-show-page .edit-laboratory-setting-container .logo-item-left.has-img:hover .logo-item-upload, .admins-laboratory-settings-update-page .edit-laboratory-setting-container .logo-item-left.has-img:hover .logo-item-upload { + display: block; + background: rgba(145, 145, 145, 0.8); +} + +/* line 85, app/assets/stylesheets/admins/laboratories.scss */ +.admins-laboratory-settings-show-page .edit-laboratory-setting-container .logo-item-right, .admins-laboratory-settings-update-page .edit-laboratory-setting-container .logo-item-right { + display: -webkit-box; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + flex-direction: column; + -webkit-box-pack: justify; + justify-content: space-between; + color: #777777; + font-size: 12px; +} + +/* line 93, app/assets/stylesheets/admins/laboratories.scss */ +.admins-laboratory-settings-show-page .edit-laboratory-setting-container .logo-item-title, .admins-laboratory-settings-update-page .edit-laboratory-setting-container .logo-item-title { + color: #23272B; + font-size: 14px; +} + /* line 4, app/assets/stylesheets/admins/library_applies.scss */ .admins-library-applies-index-page .library-applies-list-container span.apply-status-agreed { color: #28a745; @@ -25699,39 +25807,35 @@ input.form-control { #sidebar.active .sidebar-header { padding: 0px; } - /* line 172, app/assets/stylesheets/admins/sidebar.scss */ + /* line 173, app/assets/stylesheets/admins/sidebar.scss */ #sidebar.active .sidebar-header .sidebar-header-logo { display: none; } - /* line 174, app/assets/stylesheets/admins/sidebar.scss */ - #sidebar.active .sidebar-header .sidebar-header-logo img { - width: 93%; - } - /* line 179, app/assets/stylesheets/admins/sidebar.scss */ + /* line 177, app/assets/stylesheets/admins/sidebar.scss */ #sidebar.active .sidebar-header #sidebarCollapse { width: 30px; height: 20px; } - /* line 185, app/assets/stylesheets/admins/sidebar.scss */ + /* line 183, app/assets/stylesheets/admins/sidebar.scss */ #sidebar.active ul li a { padding: 10px; font-size: 0.85em; } - /* line 189, app/assets/stylesheets/admins/sidebar.scss */ + /* line 187, app/assets/stylesheets/admins/sidebar.scss */ #sidebar.active ul li a i { margin-right: 0; display: block; margin-bottom: 5px; } - /* line 196, app/assets/stylesheets/admins/sidebar.scss */ + /* line 194, app/assets/stylesheets/admins/sidebar.scss */ #sidebar.active > ul > li > a > i { font-size: 1.8em; } - /* line 200, app/assets/stylesheets/admins/sidebar.scss */ + /* line 198, app/assets/stylesheets/admins/sidebar.scss */ #sidebar.active ul ul a { padding: 10px !important; } - /* line 211, app/assets/stylesheets/admins/sidebar.scss */ + /* line 207, app/assets/stylesheets/admins/sidebar.scss */ .dropdown-toggle::after { top: auto; bottom: 10px; diff --git a/public/assets/admin-83f62f1d834d6b6790a87ca6927274c3729fe20d37db68a54bb547269fa72dc7.css.gz b/public/assets/admin-2c2854b9a02158ded5a809aaf7144a8630b10354ab4e56fecc4dffcc713796cc.css.gz similarity index 77% rename from public/assets/admin-83f62f1d834d6b6790a87ca6927274c3729fe20d37db68a54bb547269fa72dc7.css.gz rename to public/assets/admin-2c2854b9a02158ded5a809aaf7144a8630b10354ab4e56fecc4dffcc713796cc.css.gz index da1a9e3f3..bfac93da9 100644 Binary files a/public/assets/admin-83f62f1d834d6b6790a87ca6927274c3729fe20d37db68a54bb547269fa72dc7.css.gz and b/public/assets/admin-2c2854b9a02158ded5a809aaf7144a8630b10354ab4e56fecc4dffcc713796cc.css.gz differ diff --git a/public/assets/admin-978e5ce607f77c26814a174f480da79ac246c2201868ef84654aa03bb6727b5a.js b/public/assets/admin-2cdb23442fa735025385b88f2900df04fef38b61530041a6dbe375ef0f0ae888.js similarity index 99% rename from public/assets/admin-978e5ce607f77c26814a174f480da79ac246c2201868ef84654aa03bb6727b5a.js rename to public/assets/admin-2cdb23442fa735025385b88f2900df04fef38b61530041a6dbe375ef0f0ae888.js index 49e1025c7..6203a3ce8 100644 --- a/public/assets/admin-978e5ce607f77c26814a174f480da79ac246c2201868ef84654aa03bb6727b5a.js +++ b/public/assets/admin-2cdb23442fa735025385b88f2900df04fef38b61530041a6dbe375ef0f0ae888.js @@ -134528,6 +134528,256 @@ $(document).on('turbolinks:load', function() { } }) ; +$(document).on('turbolinks:load', function() { + if ($('body.admins-laboratory-settings-show-page, body.admins-laboratory-settings-update-page').length > 0) { + var $container = $('.edit-laboratory-setting-container'); + var $form = $container.find('.edit_laboratory'); + + $('.logo-item-left').on("change", 'input[type="file"]', function () { + var $fileInput = $(this); + var file = this.files[0]; + var imageType = /image.*/; + if (file && file.type.match(imageType)) { + var reader = new FileReader(); + reader.onload = function () { + var $box = $fileInput.parent(); + $box.find('img').attr('src', reader.result).css('display', 'block'); + $box.addClass('has-img'); + }; + reader.readAsDataURL(file); + } else { + } + }); + + createMDEditor('laboratory-footer-editor', { height: 200, placeholder: '请输入备案信息' }); + + $form.validate({ + errorElement: 'span', + errorClass: 'danger text-danger', + errorPlacement:function(error,element){ + if(element.parent().hasClass("input-group")){ + element.parent().after(error); + }else{ + element.after(error) + } + }, + rules: { + identifier: { + required: true, + checkSite: true + }, + name: { + required: true + } + } + }); + $.validator.addMethod("checkSite",function(value,element,params){ + var checkSite = /^(?=^.{3,255}$)[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+$/; + return this.optional(element)||(checkSite.test(value + '.educoder.com')); + },"域名不合法!"); + + $form.on('click', '.submit-btn', function(){ + $form.find('.submit-btn').attr('disabled', 'disabled'); + $form.find('.error').html(''); + var valid = $form.valid(); + + $('input[name="navbar[][name]"]').each(function(_, e){ + var $ele = $(e); + if($ele.val() === undefined || $ele.val().length === 0){ + $ele.addClass('danger text-danger'); + valid = false; + } else { + $ele.removeClass('danger text-danger'); + } + }); + + if(!valid) return; + $.ajax({ + method: 'PATCH', + dataType: 'json', + url: $form.attr('action'), + data: new FormData($form[0]), + processData: false, + contentType: false, + success: function(data){ + $.notify({ message: '保存成功' }); + window.location.reload(); + }, + error: function(res){ + var data = res.responseJSON; + $form.find('.error').html(data.message); + }, + complete: function(){ + $form.find('.submit-btn').attr('disabled', false); + } + }); + }) + } +}); +$(document).on('turbolinks:load', function() { + if ($('body.admins-laboratories-index-page').length > 0) { + var $searchContainer = $('.laboratory-list-form'); + var $searchForm = $searchContainer.find('form.search-form'); + var $list = $('.laboratory-list-container'); + + // ============== 新建 =============== + var $modal = $('.modal.admin-create-laboratory-modal'); + var $form = $modal.find('form.admin-create-laboratory-form'); + var $schoolSelect = $modal.find('.school-select'); + + $form.validate({ + errorElement: 'span', + errorClass: 'danger text-danger', + rules: { + school_id: { + required: true + } + }, + messages: { + school_id: { + required: '请选择所属单位' + } + } + }); + + // modal ready fire + $modal.on('show.bs.modal', function () { + $schoolSelect.select2('val', ' '); + }); + + // ************** 学校选择 ************* + var matcherFunc = function(params, data){ + if ($.trim(params.term) === '') { + return data; + } + if (typeof data.text === 'undefined') { + return null; + } + + if (data.name && data.name.indexOf(params.term) > -1) { + var modifiedData = $.extend({}, data, true); + return modifiedData; + } + + // Return `null` if the term should not be displayed + return null; + }; + + var defineSchoolSelect = function(schools) { + $schoolSelect.select2({ + theme: 'bootstrap4', + placeholder: '请选择单位', + minimumInputLength: 1, + data: schools, + templateResult: function (item) { + if(!item.id || item.id === '') return item.text; + return item.name; + }, + templateSelection: function(item){ + if (item.id) { + $('#school_id').val(item.id); + } + return item.name || item.text; + }, + matcher: matcherFunc + }); + } + + $.ajax({ + url: '/api/schools/for_option.json', + dataType: 'json', + type: 'GET', + success: function(data) { + defineSchoolSelect(data.schools); + } + }); + + $modal.on('click', '.submit-btn', function(){ + $form.find('.error').html(''); + + if ($form.valid()) { + var url = $form.data('url'); + + $.ajax({ + method: 'POST', + dataType: 'json', + url: url, + data: $form.serialize(), + success: function(){ + $.notify({ message: '创建成功' }); + $modal.modal('hide'); + + setTimeout(function(){ + window.location.reload(); + }, 500); + }, + error: function(res){ + var data = res.responseJSON; + $form.find('.error').html(data.message); + } + }); + } + }); + + // ============= 添加管理员 ============== + var $addMemberModal = $('.admin-add-laboratory-user-modal'); + var $addMemberForm = $addMemberModal.find('.admin-add-laboratory-user-form'); + var $memberSelect = $addMemberModal.find('.laboratory-user-select'); + var $laboratoryIdInput = $addMemberForm.find('input[name="laboratory_id"]') + + $addMemberModal.on('show.bs.modal', function(event){ + var $link = $(event.relatedTarget); + var laboratoryId = $link.data('laboratory-id'); + $laboratoryIdInput.val(laboratoryId); + + $memberSelect.select2('val', ' '); + }); + + $memberSelect.select2({ + theme: 'bootstrap4', + placeholder: '请输入要添加的管理员姓名', + multiple: true, + minimumInputLength: 1, + ajax: { + delay: 500, + url: '/admins/users', + dataType: 'json', + data: function(params){ + return { name: params.term }; + }, + processResults: function(data){ + return { results: data.users } + } + }, + templateResult: function (item) { + if(!item.id || item.id === '') return item.text; + return item.real_name; + }, + templateSelection: function(item){ + if (item.id) { + } + return item.real_name || item.text; + } + }); + + $addMemberModal.on('click', '.submit-btn', function(){ + $addMemberForm.find('.error').html(''); + + var laboratoryId = $laboratoryIdInput.val(); + var memberIds = $memberSelect.val(); + if (laboratoryId && memberIds && memberIds.length > 0) { + $.ajax({ + method: 'POST', + dataType: 'script', + url: '/admins/laboratories/' + laboratoryId + '/laboratory_user', + data: { user_ids: memberIds } + }); + } else { + $addMemberModal.modal('hide'); + } + }); + } +}); $(document).on('turbolinks:load', function() { if ($('body.admins-library-applies-index-page').length > 0) { var $searchFrom = $('.library-applies-list-form'); diff --git a/public/assets/admin-978e5ce607f77c26814a174f480da79ac246c2201868ef84654aa03bb6727b5a.js.gz b/public/assets/admin-2cdb23442fa735025385b88f2900df04fef38b61530041a6dbe375ef0f0ae888.js.gz similarity index 98% rename from public/assets/admin-978e5ce607f77c26814a174f480da79ac246c2201868ef84654aa03bb6727b5a.js.gz rename to public/assets/admin-2cdb23442fa735025385b88f2900df04fef38b61530041a6dbe375ef0f0ae888.js.gz index 68781bc40..492769a78 100644 Binary files a/public/assets/admin-978e5ce607f77c26814a174f480da79ac246c2201868ef84654aa03bb6727b5a.js.gz and b/public/assets/admin-2cdb23442fa735025385b88f2900df04fef38b61530041a6dbe375ef0f0ae888.js.gz differ diff --git a/public/assets/application-3aaf730b0754ed5e84bd381bc42b3bc84fcdba125481dbe380a6533c05f22f3c.css b/public/assets/application-50059ae929866043b47015128702fcfba53d32a2df148e64e1d961c10651c6af.css similarity index 99% rename from public/assets/application-3aaf730b0754ed5e84bd381bc42b3bc84fcdba125481dbe380a6533c05f22f3c.css rename to public/assets/application-50059ae929866043b47015128702fcfba53d32a2df148e64e1d961c10651c6af.css index 6072f27a5..f62f2f56d 100644 --- a/public/assets/application-3aaf730b0754ed5e84bd381bc42b3bc84fcdba125481dbe380a6533c05f22f3c.css +++ b/public/assets/application-50059ae929866043b47015128702fcfba53d32a2df148e64e1d961c10651c6af.css @@ -25274,6 +25274,114 @@ input.form-control { color: #6c757d; } +/* line 4, app/assets/stylesheets/admins/laboratories.scss */ +.admins-laboratories-index-page .laboratory-list-table .member-container .laboratory-user { + display: -webkit-box; + display: flex; + -webkit-box-pack: center; + justify-content: center; + flex-wrap: wrap; +} + +/* line 9, app/assets/stylesheets/admins/laboratories.scss */ +.admins-laboratories-index-page .laboratory-list-table .member-container .laboratory-user .laboratory-user-item { + display: -webkit-box; + display: flex; + -webkit-box-align: center; + align-items: center; + height: 22px; + line-height: 22px; + padding: 2px 5px; + margin: 2px 2px; + border: 1px solid #91D5FF; + background-color: #E6F7FF; + color: #91D5FF; + border-radius: 4px; +} + +/* line 27, app/assets/stylesheets/admins/laboratories.scss */ +.admins-laboratory-settings-show-page .edit-laboratory-setting-container .logo-item, .admins-laboratory-settings-update-page .edit-laboratory-setting-container .logo-item { + display: -webkit-box; + display: flex; +} + +/* line 30, app/assets/stylesheets/admins/laboratories.scss */ +.admins-laboratory-settings-show-page .edit-laboratory-setting-container .logo-item-img, .admins-laboratory-settings-update-page .edit-laboratory-setting-container .logo-item-img { + display: block; + width: 80px; + height: 80px; +} + +/* line 36, app/assets/stylesheets/admins/laboratories.scss */ +.admins-laboratory-settings-show-page .edit-laboratory-setting-container .logo-item-upload, .admins-laboratory-settings-update-page .edit-laboratory-setting-container .logo-item-upload { + cursor: pointer; + position: absolute; + top: 0; + width: 80px; + height: 80px; + background: #F5F5F5; + border: 1px solid #E5E5E5; +} + +/* line 45, app/assets/stylesheets/admins/laboratories.scss */ +.admins-laboratory-settings-show-page .edit-laboratory-setting-container .logo-item-upload::before, .admins-laboratory-settings-update-page .edit-laboratory-setting-container .logo-item-upload::before { + content: ''; + position: absolute; + top: 27px; + left: 39px; + width: 2px; + height: 26px; + background: #E5E5E5; +} + +/* line 55, app/assets/stylesheets/admins/laboratories.scss */ +.admins-laboratory-settings-show-page .edit-laboratory-setting-container .logo-item-upload::after, .admins-laboratory-settings-update-page .edit-laboratory-setting-container .logo-item-upload::after { + content: ''; + position: absolute; + top: 39px; + left: 27px; + width: 26px; + height: 2px; + background: #E5E5E5; +} + +/* line 66, app/assets/stylesheets/admins/laboratories.scss */ +.admins-laboratory-settings-show-page .edit-laboratory-setting-container .logo-item-left, .admins-laboratory-settings-update-page .edit-laboratory-setting-container .logo-item-left { + position: relative; + width: 80px; + height: 80px; +} + +/* line 72, app/assets/stylesheets/admins/laboratories.scss */ +.admins-laboratory-settings-show-page .edit-laboratory-setting-container .logo-item-left.has-img .logo-item-upload, .admins-laboratory-settings-update-page .edit-laboratory-setting-container .logo-item-left.has-img .logo-item-upload { + display: none; +} + +/* line 77, app/assets/stylesheets/admins/laboratories.scss */ +.admins-laboratory-settings-show-page .edit-laboratory-setting-container .logo-item-left.has-img:hover .logo-item-upload, .admins-laboratory-settings-update-page .edit-laboratory-setting-container .logo-item-left.has-img:hover .logo-item-upload { + display: block; + background: rgba(145, 145, 145, 0.8); +} + +/* line 85, app/assets/stylesheets/admins/laboratories.scss */ +.admins-laboratory-settings-show-page .edit-laboratory-setting-container .logo-item-right, .admins-laboratory-settings-update-page .edit-laboratory-setting-container .logo-item-right { + display: -webkit-box; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + flex-direction: column; + -webkit-box-pack: justify; + justify-content: space-between; + color: #777777; + font-size: 12px; +} + +/* line 93, app/assets/stylesheets/admins/laboratories.scss */ +.admins-laboratory-settings-show-page .edit-laboratory-setting-container .logo-item-title, .admins-laboratory-settings-update-page .edit-laboratory-setting-container .logo-item-title { + color: #23272B; + font-size: 14px; +} + /* line 4, app/assets/stylesheets/admins/library_applies.scss */ .admins-library-applies-index-page .library-applies-list-container span.apply-status-agreed { color: #28a745; @@ -25699,39 +25807,35 @@ input.form-control { #sidebar.active .sidebar-header { padding: 0px; } - /* line 172, app/assets/stylesheets/admins/sidebar.scss */ + /* line 173, app/assets/stylesheets/admins/sidebar.scss */ #sidebar.active .sidebar-header .sidebar-header-logo { display: none; } - /* line 174, app/assets/stylesheets/admins/sidebar.scss */ - #sidebar.active .sidebar-header .sidebar-header-logo img { - width: 93%; - } - /* line 179, app/assets/stylesheets/admins/sidebar.scss */ + /* line 177, app/assets/stylesheets/admins/sidebar.scss */ #sidebar.active .sidebar-header #sidebarCollapse { width: 30px; height: 20px; } - /* line 185, app/assets/stylesheets/admins/sidebar.scss */ + /* line 183, app/assets/stylesheets/admins/sidebar.scss */ #sidebar.active ul li a { padding: 10px; font-size: 0.85em; } - /* line 189, app/assets/stylesheets/admins/sidebar.scss */ + /* line 187, app/assets/stylesheets/admins/sidebar.scss */ #sidebar.active ul li a i { margin-right: 0; display: block; margin-bottom: 5px; } - /* line 196, app/assets/stylesheets/admins/sidebar.scss */ + /* line 194, app/assets/stylesheets/admins/sidebar.scss */ #sidebar.active > ul > li > a > i { font-size: 1.8em; } - /* line 200, app/assets/stylesheets/admins/sidebar.scss */ + /* line 198, app/assets/stylesheets/admins/sidebar.scss */ #sidebar.active ul ul a { padding: 10px !important; } - /* line 211, app/assets/stylesheets/admins/sidebar.scss */ + /* line 207, app/assets/stylesheets/admins/sidebar.scss */ .dropdown-toggle::after { top: auto; bottom: 10px; @@ -26250,6 +26354,113 @@ input.form-control { .admins-identity-authentications-index-page .identity-authentication-list-container span.apply-status-3 { color: #6c757d; } +/* line 4, app/assets/stylesheets/admins/laboratories.scss */ +.admins-laboratories-index-page .laboratory-list-table .member-container .laboratory-user { + display: -webkit-box; + display: flex; + -webkit-box-pack: center; + justify-content: center; + flex-wrap: wrap; +} + +/* line 9, app/assets/stylesheets/admins/laboratories.scss */ +.admins-laboratories-index-page .laboratory-list-table .member-container .laboratory-user .laboratory-user-item { + display: -webkit-box; + display: flex; + -webkit-box-align: center; + align-items: center; + height: 22px; + line-height: 22px; + padding: 2px 5px; + margin: 2px 2px; + border: 1px solid #91D5FF; + background-color: #E6F7FF; + color: #91D5FF; + border-radius: 4px; +} + +/* line 27, app/assets/stylesheets/admins/laboratories.scss */ +.admins-laboratory-settings-show-page .edit-laboratory-setting-container .logo-item, .admins-laboratory-settings-update-page .edit-laboratory-setting-container .logo-item { + display: -webkit-box; + display: flex; +} + +/* line 30, app/assets/stylesheets/admins/laboratories.scss */ +.admins-laboratory-settings-show-page .edit-laboratory-setting-container .logo-item-img, .admins-laboratory-settings-update-page .edit-laboratory-setting-container .logo-item-img { + display: block; + width: 80px; + height: 80px; +} + +/* line 36, app/assets/stylesheets/admins/laboratories.scss */ +.admins-laboratory-settings-show-page .edit-laboratory-setting-container .logo-item-upload, .admins-laboratory-settings-update-page .edit-laboratory-setting-container .logo-item-upload { + cursor: pointer; + position: absolute; + top: 0; + width: 80px; + height: 80px; + background: #F5F5F5; + border: 1px solid #E5E5E5; +} + +/* line 45, app/assets/stylesheets/admins/laboratories.scss */ +.admins-laboratory-settings-show-page .edit-laboratory-setting-container .logo-item-upload::before, .admins-laboratory-settings-update-page .edit-laboratory-setting-container .logo-item-upload::before { + content: ''; + position: absolute; + top: 27px; + left: 39px; + width: 2px; + height: 26px; + background: #E5E5E5; +} + +/* line 55, app/assets/stylesheets/admins/laboratories.scss */ +.admins-laboratory-settings-show-page .edit-laboratory-setting-container .logo-item-upload::after, .admins-laboratory-settings-update-page .edit-laboratory-setting-container .logo-item-upload::after { + content: ''; + position: absolute; + top: 39px; + left: 27px; + width: 26px; + height: 2px; + background: #E5E5E5; +} + +/* line 66, app/assets/stylesheets/admins/laboratories.scss */ +.admins-laboratory-settings-show-page .edit-laboratory-setting-container .logo-item-left, .admins-laboratory-settings-update-page .edit-laboratory-setting-container .logo-item-left { + position: relative; + width: 80px; + height: 80px; +} + +/* line 72, app/assets/stylesheets/admins/laboratories.scss */ +.admins-laboratory-settings-show-page .edit-laboratory-setting-container .logo-item-left.has-img .logo-item-upload, .admins-laboratory-settings-update-page .edit-laboratory-setting-container .logo-item-left.has-img .logo-item-upload { + display: none; +} + +/* line 77, app/assets/stylesheets/admins/laboratories.scss */ +.admins-laboratory-settings-show-page .edit-laboratory-setting-container .logo-item-left.has-img:hover .logo-item-upload, .admins-laboratory-settings-update-page .edit-laboratory-setting-container .logo-item-left.has-img:hover .logo-item-upload { + display: block; + background: rgba(145, 145, 145, 0.8); +} + +/* line 85, app/assets/stylesheets/admins/laboratories.scss */ +.admins-laboratory-settings-show-page .edit-laboratory-setting-container .logo-item-right, .admins-laboratory-settings-update-page .edit-laboratory-setting-container .logo-item-right { + display: -webkit-box; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + flex-direction: column; + -webkit-box-pack: justify; + justify-content: space-between; + color: #777777; + font-size: 12px; +} + +/* line 93, app/assets/stylesheets/admins/laboratories.scss */ +.admins-laboratory-settings-show-page .edit-laboratory-setting-container .logo-item-title, .admins-laboratory-settings-update-page .edit-laboratory-setting-container .logo-item-title { + color: #23272B; + font-size: 14px; +} /* line 4, app/assets/stylesheets/admins/library_applies.scss */ .admins-library-applies-index-page .library-applies-list-container span.apply-status-agreed { color: #28a745; @@ -26667,39 +26878,35 @@ input.form-control { #sidebar.active .sidebar-header { padding: 0px; } - /* line 172, app/assets/stylesheets/admins/sidebar.scss */ + /* line 173, app/assets/stylesheets/admins/sidebar.scss */ #sidebar.active .sidebar-header .sidebar-header-logo { display: none; } - /* line 174, app/assets/stylesheets/admins/sidebar.scss */ - #sidebar.active .sidebar-header .sidebar-header-logo img { - width: 93%; - } - /* line 179, app/assets/stylesheets/admins/sidebar.scss */ + /* line 177, app/assets/stylesheets/admins/sidebar.scss */ #sidebar.active .sidebar-header #sidebarCollapse { width: 30px; height: 20px; } - /* line 185, app/assets/stylesheets/admins/sidebar.scss */ + /* line 183, app/assets/stylesheets/admins/sidebar.scss */ #sidebar.active ul li a { padding: 10px; font-size: 0.85em; } - /* line 189, app/assets/stylesheets/admins/sidebar.scss */ + /* line 187, app/assets/stylesheets/admins/sidebar.scss */ #sidebar.active ul li a i { margin-right: 0; display: block; margin-bottom: 5px; } - /* line 196, app/assets/stylesheets/admins/sidebar.scss */ + /* line 194, app/assets/stylesheets/admins/sidebar.scss */ #sidebar.active > ul > li > a > i { font-size: 1.8em; } - /* line 200, app/assets/stylesheets/admins/sidebar.scss */ + /* line 198, app/assets/stylesheets/admins/sidebar.scss */ #sidebar.active ul ul a { padding: 10px !important; } - /* line 211, app/assets/stylesheets/admins/sidebar.scss */ + /* line 207, app/assets/stylesheets/admins/sidebar.scss */ .dropdown-toggle::after { top: auto; bottom: 10px; diff --git a/public/assets/application-50059ae929866043b47015128702fcfba53d32a2df148e64e1d961c10651c6af.css.gz b/public/assets/application-50059ae929866043b47015128702fcfba53d32a2df148e64e1d961c10651c6af.css.gz new file mode 100644 index 000000000..f5162f95a Binary files /dev/null and b/public/assets/application-50059ae929866043b47015128702fcfba53d32a2df148e64e1d961c10651c6af.css.gz differ diff --git a/public/assets/application-9cfbc3d792599a1d0de5c7b84209e1c2b2e60336f0f01e19f0581663918708fb.js.gz b/public/assets/application-9cfbc3d792599a1d0de5c7b84209e1c2b2e60336f0f01e19f0581663918708fb.js.gz index a2349edcf..d17b8f444 100644 Binary files a/public/assets/application-9cfbc3d792599a1d0de5c7b84209e1c2b2e60336f0f01e19f0581663918708fb.js.gz and b/public/assets/application-9cfbc3d792599a1d0de5c7b84209e1c2b2e60336f0f01e19f0581663918708fb.js.gz differ diff --git a/public/assets/college-18f5e8400331634e898a35acc2187815c096c25e0ab74aba341ae916166cd287.js.gz b/public/assets/college-18f5e8400331634e898a35acc2187815c096c25e0ab74aba341ae916166cd287.js.gz index 096ec98e4..d4b8b22dc 100644 Binary files a/public/assets/college-18f5e8400331634e898a35acc2187815c096c25e0ab74aba341ae916166cd287.js.gz and b/public/assets/college-18f5e8400331634e898a35acc2187815c096c25e0ab74aba341ae916166cd287.js.gz differ diff --git a/public/react/package.json b/public/react/package.json index 673ca7dfb..63954be7f 100644 --- a/public/react/package.json +++ b/public/react/package.json @@ -79,7 +79,7 @@ "react-url-query": "^1.4.0", "redux": "^4.0.0", "redux-thunk": "2.3.0", - "showdown": "^1.8.6", + "rsuite": "^4.0.1", "store": "^2.0.12", "style-loader": "0.19.0", "styled-components": "^4.1.3", diff --git a/public/react/src/AppConfig.js b/public/react/src/AppConfig.js index 4229ac70e..0107358a5 100644 --- a/public/react/src/AppConfig.js +++ b/public/react/src/AppConfig.js @@ -22,14 +22,14 @@ let hashTimeout // TODO 开发期多个身份切换 let debugType ="" if (isDev) { - const _search = window.location.search; - let parsed = {}; - if (_search) { - parsed = queryString.parse(_search); - } - debugType = window.location.search.indexOf('debug=t') != -1 ? 'teacher' : - window.location.search.indexOf('debug=s') != -1 ? 'student' : - window.location.search.indexOf('debug=a') != -1 ? 'admin' : parsed.debug || 'admin' + const _search = window.location.search; + let parsed = {}; + if (_search) { + parsed = queryString.parse(_search); + } + debugType = window.location.search.indexOf('debug=t') != -1 ? 'teacher' : + window.location.search.indexOf('debug=s') != -1 ? 'student' : + window.location.search.indexOf('debug=a') != -1 ? 'admin' : parsed.debug || 'admin' } window._debugType = debugType; export function initAxiosInterceptors(props) { @@ -215,12 +215,12 @@ function initOnlineOfflineListener() { $(window).bind("online", () => { notification.destroy() notification.success({ - duration: null, + duration: 2, message: '网络恢复正常', description: '网络恢复正常,感谢使用。', }) - }); + }); $(window).bind("offline", () => { notification.destroy() diff --git a/public/react/src/common/course/WordsBtn.js b/public/react/src/common/course/WordsBtn.js index 521a16ddd..85a85cfb6 100644 --- a/public/react/src/common/course/WordsBtn.js +++ b/public/react/src/common/course/WordsBtn.js @@ -1,24 +1,31 @@ -import React, { Component } from 'react'; -import {Link} from 'react-router-dom' - -const map={"blue":"colorblue","white":"colorwhite","grey":"colorgrey", 'orange': "color-orange"} -class WordsBtn extends Component { - constructor(props) { - super(props); - } - - render() { - let{to, href}=this.props - return( - - { - to==undefined ? - {this.props.children} - : - {this.props.children} - } - - ) - } -} +import React, { Component } from 'react'; +import {Link} from 'react-router-dom' + +const map={"blue":"colorblue","white":"colorwhite","grey":"colorgrey", 'orange': "color-orange"} +class WordsBtn extends Component { + constructor(props) { + super(props); + } + + render() { + let{to, href,targets, style2 }=this.props + return( + + { + to==undefined&&targets==undefined ? + {this.props.children}: + targets!=undefined? {this.props.children} + : + {this.props.children} + } + + ) + } +} export default WordsBtn; \ No newline at end of file diff --git a/public/react/src/modules/courses/Index.js b/public/react/src/modules/courses/Index.js index c414df55a..70cc43f4c 100644 --- a/public/react/src/modules/courses/Index.js +++ b/public/react/src/modules/courses/Index.js @@ -661,6 +661,11 @@ class CoursesIndex extends Component{ (props) => () } > + () + } + > {/* 普通作业 */} () } > + () + } + > + :"" @@ -329,7 +329,19 @@ class Fileslistitem extends Component{

    -

    资源描述 :{discussMessage.description===null?"暂无描述":discussMessage.description}
    + + 资源描述 :{discussMessage.description===null?"暂无描述":discussMessage.description} {/**/} {/*/!**!/*/} {/**/} diff --git a/public/react/src/modules/courses/Resource/index.js b/public/react/src/modules/courses/Resource/index.js index 02b1d5be1..1fea29f84 100644 --- a/public/react/src/modules/courses/Resource/index.js +++ b/public/react/src/modules/courses/Resource/index.js @@ -593,7 +593,7 @@ class Fileslists extends Component{ modalname:"立即发布", visible:true, typs:"start", - Topval:"学生将能立即查看和下载发布资源", + Topval:"学生将能立即收到资源", // Botvalleft:"暂不发布", // Botval:`本操作只对"未发布"的分班有效`, // starttime:"发布时间:"+moment(moment(new Date())).format("YYYY-MM-DD HH:mm"), diff --git a/public/react/src/modules/courses/boards/BoardsListItem.js b/public/react/src/modules/courses/boards/BoardsListItem.js index 021a41b7a..2b9c05126 100644 --- a/public/react/src/modules/courses/boards/BoardsListItem.js +++ b/public/react/src/modules/courses/boards/BoardsListItem.js @@ -70,7 +70,7 @@ class BoardsListItem extends Component{ { !!discussMessage.sticky && 置顶 } { - discussMessage.is_public == false ? ( + discussMessage.is_public == false ? ( ) : "" } diff --git a/public/react/src/modules/courses/busyWork/CommonWorkDetailIndex.js b/public/react/src/modules/courses/busyWork/CommonWorkDetailIndex.js index 8985aa07e..7ba231b99 100644 --- a/public/react/src/modules/courses/busyWork/CommonWorkDetailIndex.js +++ b/public/react/src/modules/courses/busyWork/CommonWorkDetailIndex.js @@ -308,15 +308,11 @@ class CommonWorkDetailIndex extends Component{ onClick={() => this.setState({moduleName: '参考答案'})} className={`${childModuleName == '参考答案' ? 'active' : '' } `} to={`/courses/${courseId}/${moduleEngName}/${workId}/answer`}>参考答案} - - {this.props.isAdmin() ? this.setState({moduleName: '设置'})} className={`${childModuleName == '设置' ? 'active' : '' } `} - style={{paddingLeft:'38px'}} - to={`/courses/${courseId}/${moduleEngName}/${workId}/setting`}>设置: - "" - } + style={{paddingLeft:this.props.isAdmin()?'38px':'20px'}} + to={`/courses/${courseId}/${moduleEngName}/${workId}/setting`}>{this.props.isAdmin()?"设置":"得分规则"} {/* { this.props.tabRightComponents } */} diff --git a/public/react/src/modules/courses/busyWork/CommonWorkItem.js b/public/react/src/modules/courses/busyWork/CommonWorkItem.js index c92d91c48..75676557a 100644 --- a/public/react/src/modules/courses/busyWork/CommonWorkItem.js +++ b/public/react/src/modules/courses/busyWork/CommonWorkItem.js @@ -175,7 +175,7 @@ class CommonWorkItem extends Component{ {/* 只有非课堂成员且作业是私有的情况下才会为true */} { item.private_icon===true ? - ( + ( ) : "" } diff --git a/public/react/src/modules/courses/busyWork/CommonWorkSetting.js b/public/react/src/modules/courses/busyWork/CommonWorkSetting.js index 9f36996ef..ad25f553f 100644 --- a/public/react/src/modules/courses/busyWork/CommonWorkSetting.js +++ b/public/react/src/modules/courses/busyWork/CommonWorkSetting.js @@ -167,7 +167,12 @@ class CommonWorkSetting extends Component{ } on('commonwork_fetch_all', this.fetchAllListener) - } + + + if(this.props.isAdmin()===true){ + this.setState({startEditFlag: true}) + } + } componentWillUnmount() { off('commonwork_fetch_all', this.fetchAllListener) } @@ -1029,8 +1034,9 @@ class CommonWorkSetting extends Component{ 发布设置 { !startEditFlag && isAdmin ? - { this.setState({startEditFlag: true}) }}> - + { this.setState({startEditFlag: true}) }}> + 编辑设置 + {/**/} :"" } @@ -1054,7 +1060,7 @@ class CommonWorkSetting extends Component{ {/* */} - + 截止时间: {/* */} - + 开启时间: - - + + */} - + 匿评数量: - + 缺评扣分: - + 结束时间: {/* */} - + 违规匿评扣分: - +
    - + 普通模式(选中,则取各助教最终评分的平均分) diff --git a/public/react/src/modules/courses/busyWork/common.js b/public/react/src/modules/courses/busyWork/common.js index 7f54a0623..b1828997b 100644 --- a/public/react/src/modules/courses/busyWork/common.js +++ b/public/react/src/modules/courses/busyWork/common.js @@ -1,184 +1,184 @@ -import React, { Component } from 'react'; -export const STATUS_UN_PUBLISH = "未发布" -// homework_status: ["提交中", "未开启补交"] -export const STATUS_SUBMIT = "提交中" -// export const STATUS_UN_PUBLISH = "未发布" - -// homework_status: ["提交中"] 未发布 未开启补交 - - -export function RouteHOC(options = {}) { - return function wrap(WrappedComponent) { - return class Wrapper extends Component { - constructor(props) { - super(props); - - this.state = { - - } - } - toCreateProject = () => { - let url = '/projects/new' - if (window.location.port == 3007) { - // window.location.href - url = '/testbdweb.educoder.net/projects/new' - } - window.open( - url, - '_blank' // <- This is what makes it open in a new window. - ); - } - // common_homework group_homework - // 是否是分组作业 - isGroup = () => { - return window.location.pathname.indexOf('group_homeworks') != -1 - } - getModuleName = (isChinese) => { - const isGroup = this.isGroup() - if (isChinese) { - let chName = isGroup ? '分组作业' : '普通作业' - return chName; - } - const secondName = isGroup ? 'group_homeworks' : 'common_homeworks' - return secondName; - } - getModuleType = () => { - const isGroup = this.isGroup() - return isGroup ? 3 : 1 - } - toDetailPage = (_courseId, workId, topicId) => { - if (typeof _courseId == "object") { - const topicId = _courseId.topicId - const workId = _courseId.workId - const courseId = _courseId.coursesId - this.props.history.push(`/courses/${courseId}/boards/${workId}/messages/${topicId}`) - } else { - this.props.history.push(`/courses/${_courseId}/boards/${workId}/messages/${topicId}`) - } - - } - toEditPage = (_courseId, _workId) => { - const secondName = this.getModuleName() - if (typeof _courseId == "object") { - const workId = _courseId.workId - const courseId = _courseId.coursesId - this.props.history.push(`/courses/${courseId}/${secondName}/${_workId || workId}/edit`) - } else { - this.props.history.push(`/courses/${_courseId}/${secondName}/${_workId}/edit`) - } - } - toWorkDetailPage = (_courseId, _workId, _studentWorkId) => { - const secondName = this.getModuleName() - if (typeof _courseId == "object") { - const workId = _courseId.workId - const courseId = _courseId.coursesId - const studentWorkId = _courseId.studentWorkId - this.props.history.push(`/courses/${courseId}/${secondName}/${_workId || workId}/${_studentWorkId || studentWorkId}/appraise`) - } else { - this.props.history.push(`/courses/${_courseId}/${secondName}/${_workId}/${_studentWorkId}/appraise`) - } - } - toNewPage = (courseId) => { - const secondName = this.getModuleName() - this.props.history.push(`/courses/${courseId.coursesId}/${secondName}/${courseId.category_id}/new`) - } - toListPage = (_courseId, _workId) => { - const secondName = this.getModuleName() - if (typeof _courseId == "object") { - const workId = _courseId.workId - const courseId = _courseId.coursesId - this.props.history.push(`/courses/${courseId}/${secondName}/${_workId || workId}`) - } else { - this.props.history.push(`/courses/${_courseId}/${secondName}${_workId ? '/' + _workId : ''}`) - } - } - - - toWorkPostPage = (_courseId, _workId, isEdit, _studentWorkId) => { - const secondName = this.getModuleName() - if (typeof _courseId == "object") { - const workId = _courseId.workId - const courseId = _courseId.coursesId - const studentWorkId = _courseId.studentWorkId - this.props.history.push(`/courses/${courseId}/${secondName}/${_workId || workId}/${isEdit? `${_studentWorkId || studentWorkId}/post_edit` : 'post'}`) - } else { - this.props.history.push(`/courses/${_courseId}/${secondName}/${_workId}/${isEdit? `${_studentWorkId}/post_edit` : 'post'}`) - } - } - toWorkListPage = (_courseId, _workId) => { - const secondName = this.getModuleName() - if (typeof _courseId == "object") { - const workId = _courseId.workId - const courseId = _courseId.coursesId - this.props.history.push(`/courses/${courseId}/${secondName}/${_workId || workId}/list`) - } else { - this.props.history.push(`/courses/${_courseId}/${secondName}/${_workId}/list`) - } - } - toWorkAnswerPage = (_courseId, _workId) => { - const secondName = this.getModuleName() - if (typeof _courseId == "object") { - const workId = _courseId.workId - const courseId = _courseId.coursesId - this.props.history.push(`/courses/${courseId}/${secondName}/${workId}/answer`) - } else { - this.props.history.push(`/courses/${_courseId}/${secondName}/${_workId}/answer`) - } - } - - toWorkQuestionPage = (_courseId, _workId) => { - const secondName = this.getModuleName() - if (typeof _courseId == "object") { - const workId = _workId || _courseId.workId - const courseId = _courseId.coursesId - this.props.history.push(`/courses/${courseId}/${secondName}/${workId}/question`) - } else { - this.props.history.push(`/courses/${_courseId}/${secondName}/${_workId}/question`) - } - } - - toWorkSettingPage = (_courseId, _workId) => { - const secondName = this.getModuleName() - if (typeof _courseId == "object") { - const workId = _courseId.workId - const courseId = _courseId.coursesId - this.props.history.push(`/courses/${courseId}/${secondName}/${_workId || workId}/setting`) - } else { - this.props.history.push(`/courses/${_courseId}/${secondName}/${_workId}/setting`) - } - } - - - - render() { - const { snackbarOpen} = this.state; - return ( - - - - - - ) - } - } - } +import React, { Component } from 'react'; +export const STATUS_UN_PUBLISH = "未发布" +// homework_status: ["提交中", "未开启补交"] +export const STATUS_SUBMIT = "提交中" +// export const STATUS_UN_PUBLISH = "未发布" + +// homework_status: ["提交中"] 未发布 未开启补交 + + +export function RouteHOC(options = {}) { + return function wrap(WrappedComponent) { + return class Wrapper extends Component { + constructor(props) { + super(props); + + this.state = { + + } + } + toCreateProject = () => { + let url = '/projects/new' + if (window.location.port == 3007) { + // window.location.href + url = '/testbdweb.educoder.net/projects/new' + } + window.open( + url, + '_blank' // <- This is what makes it open in a new window. + ); + } + // common_homework group_homework + // 是否是分组作业 + isGroup = () => { + return window.location.pathname.indexOf('group_homeworks') != -1 + } + getModuleName = (isChinese) => { + const isGroup = this.isGroup() + if (isChinese) { + let chName = isGroup ? '分组作业' : '普通作业' + return chName; + } + const secondName = isGroup ? 'group_homeworks' : 'common_homeworks' + return secondName; + } + getModuleType = () => { + const isGroup = this.isGroup() + return isGroup ? 3 : 1 + } + toDetailPage = (_courseId, workId, topicId) => { + if (typeof _courseId == "object") { + const topicId = _courseId.topicId + const workId = _courseId.workId + const courseId = _courseId.coursesId + this.props.history.push(`/courses/${courseId}/boards/${workId}/messages/${topicId}`) + } else { + this.props.history.push(`/courses/${_courseId}/boards/${workId}/messages/${topicId}`) + } + + } + toEditPage = (_courseId, _workId) => { + const secondName = this.getModuleName() + if (typeof _courseId == "object") { + const workId = _courseId.workId + const courseId = _courseId.coursesId + this.props.history.push(`/courses/${courseId}/${secondName}/${_workId || workId}/edit`) + } else { + this.props.history.push(`/courses/${_courseId}/${secondName}/${_workId}/edit`) + } + } + toWorkDetailPage = (_courseId, _workId, _studentWorkId) => { + const secondName = this.getModuleName() + if (typeof _courseId == "object") { + const workId = _courseId.workId + const courseId = _courseId.coursesId + const studentWorkId = _courseId.studentWorkId + window.open(`/courses/${courseId}/${secondName}/${_workId || workId}/${_studentWorkId || studentWorkId}/appraise`); + } else { + window.open(`/courses/${_courseId}/${secondName}/${_workId}/${_studentWorkId}/appraise`); + } + } + toNewPage = (courseId) => { + const secondName = this.getModuleName() + this.props.history.push(`/courses/${courseId.coursesId}/${secondName}/${courseId.category_id}/new`) + } + toListPage = (_courseId, _workId) => { + const secondName = this.getModuleName() + if (typeof _courseId == "object") { + const workId = _courseId.workId + const courseId = _courseId.coursesId + this.props.history.push(`/courses/${courseId}/${secondName}/${_workId || workId}`) + } else { + this.props.history.push(`/courses/${_courseId}/${secondName}${_workId ? '/' + _workId : ''}`) + } + } + + + toWorkPostPage = (_courseId, _workId, isEdit, _studentWorkId) => { + const secondName = this.getModuleName() + if (typeof _courseId == "object") { + const workId = _courseId.workId + const courseId = _courseId.coursesId + const studentWorkId = _courseId.studentWorkId + this.props.history.push(`/courses/${courseId}/${secondName}/${_workId || workId}/${isEdit? `${_studentWorkId || studentWorkId}/post_edit` : 'post'}`) + } else { + this.props.history.push(`/courses/${_courseId}/${secondName}/${_workId}/${isEdit? `${_studentWorkId}/post_edit` : 'post'}`) + } + } + toWorkListPage = (_courseId, _workId) => { + const secondName = this.getModuleName() + if (typeof _courseId == "object") { + const workId = _courseId.workId + const courseId = _courseId.coursesId + this.props.history.push(`/courses/${courseId}/${secondName}/${_workId || workId}/list`) + } else { + this.props.history.push(`/courses/${_courseId}/${secondName}/${_workId}/list`) + } + } + toWorkAnswerPage = (_courseId, _workId) => { + const secondName = this.getModuleName() + if (typeof _courseId == "object") { + const workId = _courseId.workId + const courseId = _courseId.coursesId + this.props.history.push(`/courses/${courseId}/${secondName}/${workId}/answer`) + } else { + this.props.history.push(`/courses/${_courseId}/${secondName}/${_workId}/answer`) + } + } + + toWorkQuestionPage = (_courseId, _workId) => { + const secondName = this.getModuleName() + if (typeof _courseId == "object") { + const workId = _workId || _courseId.workId + const courseId = _courseId.coursesId + this.props.history.push(`/courses/${courseId}/${secondName}/${workId}/question`) + } else { + this.props.history.push(`/courses/${_courseId}/${secondName}/${_workId}/question`) + } + } + + toWorkSettingPage = (_courseId, _workId) => { + const secondName = this.getModuleName() + if (typeof _courseId == "object") { + const workId = _courseId.workId + const courseId = _courseId.coursesId + this.props.history.push(`/courses/${courseId}/${secondName}/${_workId || workId}/setting`) + } else { + this.props.history.push(`/courses/${_courseId}/${secondName}/${_workId}/setting`) + } + } + + + + render() { + const { snackbarOpen} = this.state; + return ( + + + + + + ) + } + } + } } \ No newline at end of file diff --git a/public/react/src/modules/courses/busyWork/common/WorkDetailPageHeader.js b/public/react/src/modules/courses/busyWork/common/WorkDetailPageHeader.js index 68a16d89e..82f1f8d2e 100644 --- a/public/react/src/modules/courses/busyWork/common/WorkDetailPageHeader.js +++ b/public/react/src/modules/courses/busyWork/common/WorkDetailPageHeader.js @@ -144,13 +144,11 @@ class WorkDetailPageHeader extends Component{ {view_answer == true && 参考答案} - {this.props.isAdmin()? + 设置: - "" - } + style={{paddingLeft:this.props.isAdmin()?'38px':'20px'}} + to={`/courses/${courseId}/${moduleEngName}/${workId}/setting`}>{this.props.isAdmin()?"设置":"得分规则"} { this.props.tabRightComponents } diff --git a/public/react/src/modules/courses/busyWork/commonWork.js b/public/react/src/modules/courses/busyWork/commonWork.js index f8042d476..f6a989354 100644 --- a/public/react/src/modules/courses/busyWork/commonWork.js +++ b/public/react/src/modules/courses/busyWork/commonWork.js @@ -33,6 +33,7 @@ class commonWork extends Component{ modalsBottomval:"", modalCancel:"", mainList:undefined, + selectedKeys: 'all', order:"", page:1, search:"", @@ -77,7 +78,9 @@ class commonWork extends Component{ componentDidUpdate(prevProps, prevState) { if (prevProps.match.path != this.props.match.path) { this.clearSelection() - this._getList() + this.setState({ selectedKeys: 'all', order: '' }, () => { + this._getList() + }) } } @@ -143,6 +146,7 @@ class commonWork extends Component{ this.clearSelection() this.setState({ order:e.key==="all"?"":e.key, + selectedKeys: e.key, page:1, isSpin:true, checkBoxValues:[], @@ -403,7 +407,7 @@ class commonWork extends Component{ } secondRowBotton={
    - + 全部 {isAdmin && 未发布} 提交中 diff --git a/public/react/src/modules/courses/coursesDetail/CoursesBanner.js b/public/react/src/modules/courses/coursesDetail/CoursesBanner.js index 437471436..ce891bced 100644 --- a/public/react/src/modules/courses/coursesDetail/CoursesBanner.js +++ b/public/react/src/modules/courses/coursesDetail/CoursesBanner.js @@ -55,9 +55,13 @@ class CoursesBanner extends Component { } } componentDidMount() { - this.onloadupdatabanner() on('updatabanner', this.updatabanner) + if(this.props.match.path==="/courses/:coursesId"){ + if(this.props.user!=undefined){ + this.props.history.push(this.props.user.first_category_url) + } + } axios.interceptors.response.use((response) => { if (response != undefined) if (response && response.data.status === 410) { @@ -69,9 +73,17 @@ class CoursesBanner extends Component { } return response; }, (error) => { - }); } + componentDidUpdate(prevProps) { + if(prevProps.user!=this.props.user){ + if(this.props.match.path==="/courses/:coursesId"){ + if(this.props.user!=undefined){ + this.props.history.push(this.props.user.first_category_url) + } + } + } + } componentWillUnmount() { off('updatabanner', this.updatabanner) } diff --git a/public/react/src/modules/courses/coursesDetail/CoursesLeftNav.js b/public/react/src/modules/courses/coursesDetail/CoursesLeftNav.js index 70794be19..e47f83c1f 100644 --- a/public/react/src/modules/courses/coursesDetail/CoursesLeftNav.js +++ b/public/react/src/modules/courses/coursesDetail/CoursesLeftNav.js @@ -57,6 +57,7 @@ class Coursesleftnav extends Component{ positiontype:undefined, toopvisible:false, toopvisibleindex:undefined, + toopvisibleindexs:undefined, sandiantypes:undefined, antIcon:false, chapterupdate:false, @@ -314,7 +315,11 @@ class Coursesleftnav extends Component{ twosandianshow=(e,key,type)=>{ + // console.log("twosandianshow"); + // console.log(key); + // console.log(type); this.setState({ + toopvisibleindexs:key, twosandiantype:key, toopvisible:false, toopvisibleindex:undefined, @@ -322,11 +327,29 @@ class Coursesleftnav extends Component{ }) e.stopPropagation();//阻止冒泡 } - + twosandianshowys=(e,key,type)=>{ + // console.log("twosandianshow"); + // console.log(key); + // console.log(type); + this.setState({ + toopvisibleindexs:key, + }) + e.stopPropagation();//阻止冒泡 + } + twosandianshowyss=(e,key,type)=>{ + // console.log("twosandianshow"); + // console.log(key); + // console.log(type); + this.setState({ + toopvisibleindexs:undefined, + }) + e.stopPropagation();//阻止冒泡 + } twosandianhide=(e,index,type)=>{ // console.log(index) this.setState({ + toopvisibleindexs:undefined, twosandiantype:undefined, twosandiantypenum:undefined, toopvisible:true, @@ -336,6 +359,13 @@ class Coursesleftnav extends Component{ e.stopPropagation();//阻止冒泡 } + twosandianhideys=(e,index,type)=>{ + // console.log(index) + this.setState({ + toopvisibleindexs:undefined, + }) + e.stopPropagation();//阻止冒泡 + } //置顶 editSetup=(e,id)=>{ @@ -820,6 +850,7 @@ class Coursesleftnav extends Component{ ModalSave, loadtype, twosandiantypes, + toopvisibleindexs }=this.state; let {course_modules,hidden_modules,is_teacher} =this.props; @@ -992,6 +1023,8 @@ class Coursesleftnav extends Component{ } } } + // console.log(iem.category_name); + // console.log(iem.category_name.length); return( {(provided, snapshot) => ( {/*"/courses/"+this.props.match.params.coursesId+"/"+item.type+"/"+iem.category_type+"/"+iem.category_id*/} - -
  • this.selectnavids(e,key,iem.category_id,item.type+"child",iem.second_category_url,key)} onMouseLeave={(e)=>this.twosandianhide(e,index,item.type)} onMouseEnter={(e)=>this.twosandianshow(e,index,item.type)} + +
  • this.selectnavids(e,key,iem.category_id,item.type+"child",iem.second_category_url,key)} onMouseLeave={(e)=>this.twosandianhide(e,index,item.type)} onMouseEnter={(e)=>this.twosandianshow(e,index,item.type)} key={index} ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps} - title={iem.category_name.length<10?"":iem.category_name} + // title={iem.category_name.length<10?"":iem.category_name} > - - {iem.category_name} + this.twosandianshowys(e,index,item.type)}>{iem.category_name} + {iem.category_count===0?"":iem.category_count} {item.type===twosandiantypes&&twosandiantype===index? iem.category_id===0?"": iem.category_type==="graduation_topics"||iem.category_type==="graduation_tasks"? - {iem.category_count===0?"":iem.category_count} - : + ( + iem.category_name&&iem.category_name.length<13? + {iem.category_count===0?"":iem.category_count} + : + + {iem.category_count===0?"":iem.category_count} + + ) + : + ( + iem.category_name&&iem.category_name.length<13? + this.twosandianshowyss(e)}> + + + : + + this.twosandianshowyss(e)}> - :""} + + + ) + :""} - {provided.placeholder} +
  • +
    )} @@ -1087,17 +1140,35 @@ class Coursesleftnav extends Component{ } } } + // console.log(iem.category_name); + // console.log(iem.category_name.length);一开始是10 显示是13 return( -
  • - this.selectnavids(e,key,iem.category_id,item.type+"child",iem.second_category_url,key)} > - - {/*{iem.category_name}*/} - {iem.category_name} - - {iem.category_count===0?"":iem.category_count} - + {/*title={iem.category_name.length<10?"":iem.category_name}*/} + +
  • + { + iem.category_name&&iem.category_name.length<13? + this.selectnavids(e,key,iem.category_id,item.type+"child",iem.second_category_url,key)} > + {/*{iem.category_name}*/} + {/*{iem.category_name.length<10?"":*/} + {/* iem.category_name}*/} + {iem.category_name} + {iem.category_count===0?"":iem.category_count} + + : + + this.selectnavids(e,key,iem.category_id,item.type+"child",iem.second_category_url,key)} > + {/*{iem.category_name}*/} + {/*{iem.category_name.length<10?"":*/} + {/* iem.category_name}*/} + {iem.category_name} + {iem.category_count===0?"":iem.category_count} + + + }
  • + ) }) diff --git a/public/react/src/modules/courses/coursesPublic/AppraiseModal.js b/public/react/src/modules/courses/coursesPublic/AppraiseModal.js index 120e57b2b..a943e9655 100644 --- a/public/react/src/modules/courses/coursesPublic/AppraiseModal.js +++ b/public/react/src/modules/courses/coursesPublic/AppraiseModal.js @@ -153,7 +153,7 @@ class AppraiseModal extends Component{

    - 可见:(学生可查看老师的评阅内容) + 可见(学生可查看老师的评阅内容)

    {/**/} {/*可见 (学生查看老师的评阅内容)*/} @@ -167,7 +167,7 @@ class AppraiseModal extends Component{ />

    - 不可见:(仅对课堂老师可见) + 不可见(仅对课堂老师可见)

    原因不能为空
    -
  • + + + +
  • - 上次学至{last_shixun} + 上次学习内容{last_shixun}
    diff --git a/public/react/src/modules/courses/elearning/YslDetailCards.js b/public/react/src/modules/courses/elearning/YslDetailCards.js index 4b295f118..3c6b5daff 100644 --- a/public/react/src/modules/courses/elearning/YslDetailCards.js +++ b/public/react/src/modules/courses/elearning/YslDetailCards.js @@ -94,10 +94,10 @@ class YslDetailCards extends Component{ startshixunCombattype:true, }) } else { - console.log("开始学习了"); + // console.log("开始学习了"); window.open("/tasks/" + response.data.game_identifier,'_blank'); //这个是传过来 调用刷新 - this.props.Myreload(); + this.props.getPathCardsList(); // window.location.href = path // let path="/tasks/"+response.data.game_identifier; // this.props.history.push(path); @@ -109,6 +109,7 @@ class YslDetailCards extends Component{ }; componentDidMount(){ + // console.log("YslDetailCards start"); let pathid=this.props.match.params.coursesId; this.setState({ pathid:pathid @@ -116,6 +117,11 @@ class YslDetailCards extends Component{ } + Pathlisteditundefined=()=>{ + this.setState({ + pathlistedit:undefined + }) + }; hidestartshixunsreplace=(url)=>{ this.setState({ isSpin:true, @@ -521,6 +527,7 @@ class YslDetailCards extends Component{ ysldetailcards={"ysldetailcards"} pathid={subject_id} coursesId={pathid} + Pathlisteditundefined={this.Pathlisteditundefined} > :"" } diff --git a/public/react/src/modules/courses/exercise/Exercise.js b/public/react/src/modules/courses/exercise/Exercise.js index 65377bb19..20213c931 100644 --- a/public/react/src/modules/courses/exercise/Exercise.js +++ b/public/react/src/modules/courses/exercise/Exercise.js @@ -119,12 +119,13 @@ class Exercise extends Component{ changeType=(e)=>{ this.setState({ - type:e.key, + type:e.key==="0"?undefined:e.key, + page:1, checkAllValue:false, checkBoxValues:[] }) let{StudentList_value,page,limit}=this.state; - this.InitList(e.key==="0"?undefined:e.key,StudentList_value,page,limit) + this.InitList(e.key==="0"?undefined:e.key,StudentList_value,1,limit) } //切换分页 diff --git a/public/react/src/modules/courses/exercise/ExerciseListItem.js b/public/react/src/modules/courses/exercise/ExerciseListItem.js index 07606bd58..ef500ba0b 100644 --- a/public/react/src/modules/courses/exercise/ExerciseListItem.js +++ b/public/react/src/modules/courses/exercise/ExerciseListItem.js @@ -134,7 +134,7 @@ class ExerciseListItem extends Component{ { item.lock_status === 0 ? - + :"" @@ -213,7 +213,7 @@ class ExerciseListItem extends Component{ IsStudent &&
    {item.current_status ===0&&item.exercise_status>1?
  • 继续答题
  • : - item.current_status ===1&&item.exercise_status>1?
  • 查看答题
  • : + item.current_status ===1&&item.exercise_status>1?
  • 查看答题
  • : item.current_status ===2&&item.exercise_status>1?
  • this.setgameexercise(`/courses/${coursesId}/exercises/${item.id}/users/${this.props.current_user.login}`)}>开始答题
  • :""}
    } diff --git a/public/react/src/modules/courses/exercise/ExerciseReviewAndAnswer.js b/public/react/src/modules/courses/exercise/ExerciseReviewAndAnswer.js index f45de9b64..75da4f2fe 100644 --- a/public/react/src/modules/courses/exercise/ExerciseReviewAndAnswer.js +++ b/public/react/src/modules/courses/exercise/ExerciseReviewAndAnswer.js @@ -96,8 +96,8 @@ class ExerciseReviewAndAnswer extends Component{ //window.addEventListener('scroll', this.handleScroll); } - remainTime=()=>{ - let { time } = this.state; + remainTime=(time)=>{ + // let { time } = this.state; let h=moment(parseInt(time)*1000).hour()-8; let m=moment(parseInt(time)*1000).minutes(); let s=moment(parseInt(time)*1000).seconds(); @@ -127,22 +127,31 @@ class ExerciseReviewAndAnswer extends Component{ } //自动交卷 autoCommitExercise=()=>{ - let eId=this.props.match.params.Id; - let url=`/exercises/${eId}/commit_exercise.json`; - axios.post(url).then((result)=>{ - if(result){ - this.setState({ - Modalstype:true, - Modalstopval:'答题结束了,系统已自动提交试卷', - modalsBottomval:"不能再修改答题", - ModalCancel:undefined, - ModalSave:this.sureCommit, - Loadtype:true - }) - } - }).catch((error)=>{ - console.log(error); - }) + let eId=this.props.match.params.Id; + let url=`/exercises/${eId}/commit_exercise.json`; + axios.post(url,{ + commit_method:2 + }).then((result)=>{ + if(result){ + if(result.data.status===0){ + this.setState({ + Modalstype:true, + Modalstopval:'答题结束了,系统已自动提交试卷', + modalsBottomval:"不能再修改答题", + ModalCancel:undefined, + ModalSave:this.sureCommit, + Loadtype:true + }) + this.props.showNotification(`${result.data.message}`); + } + + if(result.data.status===-2){ + this.remainTime(parseInt(result.data.message)) + } + } + }).catch((error)=>{ + console.log(error); + }) } sureCommit=()=>{ @@ -235,7 +244,7 @@ class ExerciseReviewAndAnswer extends Component{ isSpin:false }) if(result.data.exercise.left_time != null){ - this.remainTime(); + this.remainTime(result.data.exercise.left_time); } } }).catch((error)=>{ @@ -485,7 +494,9 @@ class ExerciseReviewAndAnswer extends Component{ //交卷 let eId=this.props.match.params.Id; let url=`/exercises/${eId}/commit_exercise.json`; - axios.post(url).then((result)=>{ + axios.post(url,{ + commit_method:1 + }).then((result)=>{ if(result){ this.setState({ Modalstype:false, diff --git a/public/react/src/modules/courses/exercise/Exercisesetting.js b/public/react/src/modules/courses/exercise/Exercisesetting.js index 96cc17ca8..7b3732c9f 100644 --- a/public/react/src/modules/courses/exercise/Exercisesetting.js +++ b/public/react/src/modules/courses/exercise/Exercisesetting.js @@ -93,13 +93,28 @@ class Exercisesetting extends Component{ //加载 componentDidMount=()=>{ this.getSettingInfo(); + // window.addEventListener('click', this.handleClick); try { this.props.triggerRef(this); }catch (e) { } + + if(this.props.Commonheadofthetestpaper!=undefined){ + this.editSetting() + } + + if(this.props.isAdmin() === false){ + this.cancelEdit() + } } + componentDidUpdate = (prevProps) => { + if(prevProps.Commonheadofthetestpaper!= this.props.Commonheadofthetestpaper){ + this.editSetting() + } + } + _getRequestParams() { const { order, exercise_group_id,searchtext, page ,limit} = this.state return { @@ -607,10 +622,11 @@ class Exercisesetting extends Component{ 发布设置 { !flagPageEdit&&this.props.isAdmin()===true ? - - - - + + 编辑设置 + {/**/} + {/**/} + {/**/} :"" } diff --git a/public/react/src/modules/courses/exercise/Exercisetablesmubu.js b/public/react/src/modules/courses/exercise/Exercisetablesmubu.js index d2d6103b8..501a7ebf5 100644 --- a/public/react/src/modules/courses/exercise/Exercisetablesmubu.js +++ b/public/react/src/modules/courses/exercise/Exercisetablesmubu.js @@ -96,7 +96,7 @@ class Exercisetablesmubus extends Component { '0%': '#29BD8B', '100%': '#29BD8B', }} - percent={record.max_score*100} showInfo={false}/>
    {record.max_score*100}%
    } + percent={(record.max_score*100).toFixed()} showInfo={false}/>
    {(record.max_score*100).toFixed()}%
    }
    ), }]; diff --git a/public/react/src/modules/courses/exercise/Studentshavecompletedthelist.js b/public/react/src/modules/courses/exercise/Studentshavecompletedthelist.js index 57f574ac4..438c07aeb 100644 --- a/public/react/src/modules/courses/exercise/Studentshavecompletedthelist.js +++ b/public/react/src/modules/courses/exercise/Studentshavecompletedthelist.js @@ -823,6 +823,7 @@ class Studentshavecompletedthelist extends Component { -- : {record.operating} } @@ -1020,6 +1021,7 @@ class Studentshavecompletedthelist extends Component { >--
    : {record.finalscore} } @@ -1210,6 +1212,7 @@ class Studentshavecompletedthelist extends Component { >--
    : {record.finalscore} } diff --git a/public/react/src/modules/courses/graduation/tasks/GraduateTaskItem.js b/public/react/src/modules/courses/graduation/tasks/GraduateTaskItem.js index 2b27571e2..39a2f0876 100644 --- a/public/react/src/modules/courses/graduation/tasks/GraduateTaskItem.js +++ b/public/react/src/modules/courses/graduation/tasks/GraduateTaskItem.js @@ -256,7 +256,7 @@ class GraduateTaskItem extends Component{ { this.props.discussMessage.private_icon===true? - + : @@ -346,7 +346,7 @@ class GraduateTaskItem extends Component{ {item==="查看作品"? - 查看作品 + 查看作品 :""} diff --git a/public/react/src/modules/courses/graduation/tasks/GraduationAcross.js b/public/react/src/modules/courses/graduation/tasks/GraduationAcross.js index 46b1533f7..18dac8041 100644 --- a/public/react/src/modules/courses/graduation/tasks/GraduationAcross.js +++ b/public/react/src/modules/courses/graduation/tasks/GraduationAcross.js @@ -189,7 +189,8 @@ class GraduationAcross extends Component{ cross_teachers: item.cross_teachers, student_id:item.student_id, user_name:item.user_name, - work_id:item.work_id + work_id:item.work_id, + cross_groups:item.cross_groups } return list; }), @@ -337,7 +338,7 @@ class GraduationAcross extends Component{ chooseCount, chooseId, AcrossTeamIds, - searchValue,showflag + searchValue,showflag, } = this.state; let { modalVisible } = this.props; let courseId = this.props.match.params.coursesId; @@ -372,7 +373,8 @@ class GraduationAcross extends Component{ // 筛选下拉列表 const teacherList = searchValue ? teachers&&teachers.filter(e=>e.user_name.indexOf(searchValue)>-1) : teachers; const course_groupsList = searchValue ? course_groups&&course_groups.filter(e=>e.name.indexOf(searchValue)>-1) : course_groups; - return( + const graduation_groupslist =searchValue ? graduation_groups&&graduation_groups.filter(e=>e.name.indexOf(searchValue)>-1) : graduation_groups; + return( :""} -
    this.props.modalCloss()}> +
    @@ -741,7 +788,7 @@ class studentsList extends Component{
    }
    } -
    +
    {combineArray.length ? {/* pagination={{ current: page, total: total_count, pageSize:20, onChange: this.onPageChange }} */} diff --git a/public/react/src/modules/courses/poll/Poll.js b/public/react/src/modules/courses/poll/Poll.js index e7846e3fa..2831611c5 100644 --- a/public/react/src/modules/courses/poll/Poll.js +++ b/public/react/src/modules/courses/poll/Poll.js @@ -96,11 +96,12 @@ class Poll extends Component{ changeType=(e)=>{ this.setState({ type:e.key, + page:1, checkBoxValues:[], checkAllValue:false }) let{StudentList_value,page}=this.state; - this.InitList(e.key,StudentList_value,page); + this.InitList(e.key,StudentList_value,1); } // 获取列表数据 InitList=(type,search,page,bank_checkValue)=>{ diff --git a/public/react/src/modules/courses/poll/PollDetailTabFirst.js b/public/react/src/modules/courses/poll/PollDetailTabFirst.js index 59e8b924c..a03328c7a 100644 --- a/public/react/src/modules/courses/poll/PollDetailTabFirst.js +++ b/public/react/src/modules/courses/poll/PollDetailTabFirst.js @@ -228,7 +228,7 @@ class PollDetailTabFirst extends Component{ width:120, render:(operation,item,index)=>{ return( - item.status == 1 ? 查看:-- + item.status == 1 ? 查看:-- ) } }]; diff --git a/public/react/src/modules/courses/poll/PollDetailTabForth.js b/public/react/src/modules/courses/poll/PollDetailTabForth.js index 22205b188..98598a445 100644 --- a/public/react/src/modules/courses/poll/PollDetailTabForth.js +++ b/public/react/src/modules/courses/poll/PollDetailTabForth.js @@ -83,8 +83,19 @@ class PollDetailTabForth extends Component{ componentDidMount=()=>{ this.getSettingInfo(); //window.addEventListener('click', this.handleClick); - } + if(this.props.pollDetail!=undefined){ + this.editSetting(); + } + if(this.props.isAdmin() === false){ + this.cancelEdit() + } + } + componentDidUpdate = (prevProps) => { + if(prevProps.pollDetail!= this.props.pollDetail){ + this.editSetting(); + } + } handleClick=(e)=>{ console.log(e); } @@ -511,7 +522,10 @@ class PollDetailTabForth extends Component{ { !flagPageEdit && isAdmin ? - + + 编辑设置 + {/**/} + :"" }

    @@ -536,7 +550,7 @@ class PollDetailTabForth extends Component{
    发布时间:
    - +
    - + + :"" @@ -98,7 +98,7 @@ class PollListItem extends Component{ } { - isStudent ? + isStudent ? { item.current_status == 0 && "继续答题" } diff --git a/public/react/src/modules/courses/shixunHomework/Listofworksstudentone.js b/public/react/src/modules/courses/shixunHomework/Listofworksstudentone.js index 944d84f01..d73136b41 100644 --- a/public/react/src/modules/courses/shixunHomework/Listofworksstudentone.js +++ b/public/react/src/modules/courses/shixunHomework/Listofworksstudentone.js @@ -22,10 +22,10 @@ import './style.css'; import 'moment/locale/zh-cn'; import axios from 'axios'; import moment from 'moment'; -import '../css/members.css' -import '../css/busyWork.css' -import '../poll/pollStyle.css' -import './Challenges.css' +import '../css/members.css'; +import '../css/busyWork.css'; +import '../poll/pollStyle.css'; +import './Challenges.css'; import {getImageUrl} from 'educoder'; import TraineetraininginformationModal from "./TraineetraininginformationModal"; import DownloadMessageysl from '../../modals/DownloadMessageysl'; @@ -33,7 +33,7 @@ import Startshixuntask from "../coursesPublic/Startshixuntask"; import ModulationModal from "../coursesPublic/ModulationModal"; import HomeworkModal from "../coursesPublic/HomeworkModal"; import ShixunWorkModal from "./Shixunworkdetails/ShixunWorkModal"; -import NoneData from '../../../modules/courses/coursesPublic/NoneData' +import NoneData from '../../../modules/courses/coursesPublic/NoneData'; const Search = Input.Search; const RadioGroup = Radio.Group; @@ -1490,12 +1490,12 @@ class Listofworksstudentone extends Component { isupdatas = () => { var homeworkid = this.props.match.params.homeworkid; // this.Gettitleinformation(homeworkid); - this.Getalistofworks(homeworkid); + this.Getalistofworks(homeworkid,false); } Isupdatass = () => { var homeworkid = this.props.match.params.homeworkid; // this.Gettitleinformation(homeworkid); - this.Getalistofworks(homeworkid); + this.Getalistofworks(homeworkid,false); } /////////老师操作 // tearchar=()=>{ @@ -1515,7 +1515,7 @@ class Listofworksstudentone extends Component { // debugger var homeworkid = this.props.match.params.homeworkid; - this.Getalistofworks(homeworkid); + this.Getalistofworks(homeworkid,true); let query = this.props.location.pathname; const type = query.split('/'); this.setState({ @@ -1531,10 +1531,11 @@ class Listofworksstudentone extends Component { } // 获取作品列表 - Getalistofworks = (homeworkid) => { + Getalistofworks = (homeworkid,bool) => { // console.log("获取作品列表"); // console.log("935"); // debugger + let searchtype=this.props.history.location.search; let urll = `/homework_commons/${homeworkid}/works_list.json`; var datasysl = { search: this.state.searchtext, @@ -1546,7 +1547,7 @@ class Listofworksstudentone extends Component { course_group: this.state.checkedValuesineinfo, } axios.post(urll, datasysl).then((result) => { - console.log("980000000____________________"); + // console.log("980000000____________________"); if(result === undefined){ return @@ -1573,6 +1574,7 @@ class Listofworksstudentone extends Component { loadingstate: false, computeTimetype:true, homework_status:result.data.homework_status, + update_score:result.data.update_score }); this.seacthdatat(result.data,result.data.student_works,result.data.work_efficiency,result.data.course_group_info,1); @@ -1581,6 +1583,26 @@ class Listofworksstudentone extends Component { } else { this.seacthdatas(result.data, result.data.student_works); } + //开始自动计算成绩刷新 老师才有权限 + try { + if(this.props.isAdmin() === true){ + if(result.data.update_score===true){ + if(bool===true){ + if(searchtype==="?tab=0"){ + try { + this.props.yslslowCheckresults(); + }catch (e) { + + } + this.setComputeTimet(); + } + } + } + } + }catch (e) { + + } + this.props.Getdataback(result,result.data); }).catch((error) => { @@ -2183,10 +2205,17 @@ class Listofworksstudentone extends Component { axios.get(url).then((response) => { if(response){ if(response.data.status===0) { - this.props.showNotification(`${response.data.message}`); - // var homeworkid = this.props.match.params.homeworkid; - this.Getalistofworks(homeworkid); - // this.props.history.replace(matchurl); + setTimeout(()=>{ + this.props.showNotification(`${response.data.message}`); + // var homeworkid = this.props.match.params.homeworkid; + this.Getalistofworks(homeworkid,false); + // this.props.history.replace(matchurl); + try{ + this.props.yslslowCheckresultsNo(); + }catch (e) { + + } + }, 2500); } } // this.Getalistofworkstwo("", "", "", "", 1, 20); @@ -2598,9 +2627,11 @@ class Listofworksstudentone extends Component { // return // } this.setState({ - loadingstate: true + loadingstate: true, + page:1, + limit:20, }) - this.Startsortingt(this.state.orders, this.state.course_groupyslstwo, this.state.checkedValuesineinfo, value, this.state.page, this.state.limit); + this.Startsortingt(this.state.orders, this.state.course_groupyslstwo, this.state.checkedValuesineinfo, value, 1,20); // console.log(value) @@ -2612,9 +2643,11 @@ class Listofworksstudentone extends Component { // this.onSearch(); // console.log("使用了回车键"); this.setState({ - loadingstate: true + loadingstate: true, + page:1, + limit:20, }) - this.Startsortingt(this.state.orders, this.state.course_groupyslstwo, this.state.checkedValuesineinfo, this.state.searchtext, this.state.page, this.state.limit); + this.Startsortingt(this.state.orders, this.state.course_groupyslstwo, this.state.checkedValuesineinfo, this.state.searchtext, 1,20); } } //排序 @@ -2943,12 +2976,12 @@ class Listofworksstudentone extends Component { } setComputeTimet=()=>{ - + // console.log("老师开始计算成绩了1111111"); let matchurl = this.props.match.url; - this.setState({ - computeTimetype:false - }) + // this.setState({ + // computeTimetype:false + // }) let homeworkid = this.props.match.params.homeworkid; let url = "/homework_commons/"+homeworkid+"/update_score.json"; @@ -2958,11 +2991,23 @@ class Listofworksstudentone extends Component { // if(response.data.message!==undefined){ // return; // } - this.setState({ - loadingstate: true - }) - this.Getalistofworks(homeworkid); - this.props.showNotification(`${response.data.message}`); + setTimeout(()=>{ + this.setState({ + loadingstate: true + }) + this.Getalistofworks(homeworkid,false); + try { + this.props.showNotification(`${response.data.message}`); + }catch (e) { + + } + try{ + this.props.yslslowCheckresultsNo(); + }catch (e) { + + } + + }, 2500); } // this.props.history.replace( matchurl ); } @@ -3204,21 +3249,25 @@ class Listofworksstudentone extends Component { {/*作品状态GraduationTaskssettinglist*/}
    @@ -3762,24 +3808,24 @@ class Listofworksstudentone extends Component {
    - 计算成绩时间:{teacherdata&&teacherdata.calculation_time==null?"--": moment(teacherdata&&teacherdata.calculation_time).format('YYYY-MM-DD HH:mm')} - { course_is_end===true?"":teacherdata&&teacherdata.task_operation&&teacherdata.task_operation[0]==="开启挑战"?"": - {computeTimetype===true? - - (this.props.isNotMember()===false? - ( - teacherdata&&teacherdata.update_score===true? -
    - 查看最新成绩 -
    :"" - ) - :""): - teacherdata&&teacherdata.homework_status!==undefined&&teacherdata.homework_status[0]=== "未发布"? "": - (this.props.isNotMember()===false?
    - 查看最新成绩 -
    :"") - } -
    } + {/*计算成绩时间:{teacherdata&&teacherdata.calculation_time==null?"--": moment(teacherdata&&teacherdata.calculation_time).format('YYYY-MM-DD HH:mm')}*/} + {/* { course_is_end===true?"":teacherdata&&teacherdata.task_operation&&teacherdata.task_operation[0]==="开启挑战"?"":*/} + {/* {computeTimetype===true?*/} + + {/* (this.props.isNotMember()===false?*/} + {/* (*/} + {/* teacherdata&&teacherdata.update_score===true?*/} + {/*
    */} + {/* 查看最新成绩*/} + {/*
    :""*/} + {/* )*/} + {/* :""):*/} + {/* teacherdata&&teacherdata.homework_status!==undefined&&teacherdata.homework_status[0]=== "未发布"? "":*/} + {/* (this.props.isNotMember()===false?
    */} + {/* 查看最新成绩*/} + {/*
    :"")*/} + {/* }*/} + {/*
    }*/}
    diff --git a/public/react/src/modules/courses/shixunHomework/ShixunHomeworkPage.js b/public/react/src/modules/courses/shixunHomework/ShixunHomeworkPage.js index 66b7b89dc..3d364f677 100644 --- a/public/react/src/modules/courses/shixunHomework/ShixunHomeworkPage.js +++ b/public/react/src/modules/courses/shixunHomework/ShixunHomeworkPage.js @@ -236,7 +236,7 @@ class ShixunHomeworkPage extends Component { {/* onClick={(e) => this.ChangeTab(2)}>*/} {/* 代码查重 : ""}*/} {parseInt(tab) === 3? - :""} - {this.props.isAdmin() ? + this.ChangeTab(3)} - >设置:""} + >{this.props.isAdmin()?"设置":"得分规则"} {/*{this.props.isAdmin() ? { if(response.status===200){ - this.setState({ - - }) this.setState({ modalname:"立即截止", modaltype:response.data.course_groups===null||response.data.course_groups.length===0?2:1, diff --git a/public/react/src/modules/courses/shixunHomework/ShixunhomeWorkItem.js b/public/react/src/modules/courses/shixunHomework/ShixunhomeWorkItem.js index e08fb7d8e..88d143011 100644 --- a/public/react/src/modules/courses/shixunHomework/ShixunhomeWorkItem.js +++ b/public/react/src/modules/courses/shixunHomework/ShixunhomeWorkItem.js @@ -337,7 +337,7 @@ class ShixunhomeWorkItem extends Component{ { this.props.discussMessage.private_icon===true? - + : @@ -354,8 +354,8 @@ class ShixunhomeWorkItem extends Component{ {/* {discussMessage.author.name} */} { discussMessage.author && {discussMessage.author} } - {discussMessage.commit_count===undefined?"":{discussMessage.commit_count} 已交} - {discussMessage.uncommit_count===undefined?"":{discussMessage.uncommit_count} 未交} + {discussMessage.commit_count===undefined?"":已开始做题 {discussMessage.commit_count}人} + {discussMessage.uncommit_count===undefined?"":未开始做题 {discussMessage.uncommit_count}人} {/*{discussMessage.replies_count} 3 未评*/} { @@ -381,7 +381,7 @@ class ShixunhomeWorkItem extends Component{ { discussMessage && discussMessage.upper_category_name && 22 }> - { {discussMessage.upper_category_name}} + { {discussMessage.upper_category_name}} } diff --git a/public/react/src/modules/courses/shixunHomework/Trainingjobsetting.js b/public/react/src/modules/courses/shixunHomework/Trainingjobsetting.js index 8b71a6a33..c3fe18b58 100644 --- a/public/react/src/modules/courses/shixunHomework/Trainingjobsetting.js +++ b/public/react/src/modules/courses/shixunHomework/Trainingjobsetting.js @@ -149,7 +149,9 @@ class Trainingjobsetting extends Component { - + if(this.props.isAdmin() === false){ + this.cancelEdit() + } } // componentWillReceiveProps(nextProps) { // // console.log("+++++++++916"); @@ -1013,18 +1015,17 @@ class Trainingjobsetting extends Component { //完成效率评分占比 onChangeeffectiveness = (e) => { if( e.target.checked === true){ - this.state.latedeductiontwo=20; this.setState({ completionefficiencyscore: e.target.checked, work_efficiencys:e.target.checked, - latedeductiontwo: 20, + latedeductiontwo: 0, }) //均分比例 if(this.state.proportion==="均分比例"){ - this.Equalproportion(20); + this.Equalproportion(0); }else if(this.state.proportion==="经验值比例"){ - this.Empiricalvalueratio(20); + this.Empiricalvalueratio(0); } @@ -1723,17 +1724,17 @@ class Trainingjobsetting extends Component { flagPageEditsthrees:deadline, flagPageEditsfor:endtime, completionefficiencyscore:true, - work_efficiencys:true, + work_efficiencys:this.state.work_efficiencys, unifiedsetting:this.state.unifiedsetting, - latedeductiontwo:20, + latedeductiontwo:this.state.latedeductiontwo, }); //均分比例 try { if(this.state.proportion==="均分比例"){ - this.Equalproportion(20); + this.Equalproportion(this.state.latedeductiontwo); }else if(this.state.proportion==="经验值比例"){ - this.Empiricalvalueratio(20); + this.Empiricalvalueratio(this.state.latedeductiontwo); } }catch (e) { @@ -1838,19 +1839,19 @@ class Trainingjobsetting extends Component { flagPageEditstwo:releasetime, flagPageEditsthrees:deadline, flagPageEditsfor:endtime, - completionefficiencyscore:true, - work_efficiencys:true, + completionefficiencyscore:false, + work_efficiencys:datas.data.work_efficiency, unifiedsetting:datas.data.unified_setting, - latedeductiontwo:20, + latedeductiontwo:datas.data.eff_score, }); //均分比例 // result.data.shixun_evaluation === 0 ? "均分比例" : result.data.shixun_evaluation === 1 ? "经验值比例" : result.data.shixun_evaluation === 2 ? try { if(datas.data.shixun_evaluation === 0){ - this.Equalproportion(20); + this.Equalproportion(datas.data.eff_score); }else if(datas.data.shixun_evaluation === 1){ - this.Empiricalvalueratio(20); + this.Empiricalvalueratio(datas.data.eff_score); } }catch (e) { @@ -2078,7 +2079,10 @@ class Trainingjobsetting extends Component { // console.log(this.props.isAdmin()) // console.log(this.state.code_review===false) // console.log("引入的分值"); - // console.log(this.state.work_efficiencys); + console.log(this.state.work_efficiencys); + + + return (
    {/*{this.state.showmodel===true?

    - 发布设置 + 发布设置 { !flagPageEdit && this.props.isAdmin() === true ? - + + 编辑设置 + {/**/} + : "" }

    { group_settings&&group_settings.length>0?
    - 统一设置(选中则所有分班使用相同的发布设置,否则各个分班单独设置) + className={"font-14 ml15 color-grey-c"} style={{textAlign:"left"}}>(选中则所有分班使用相同的发布设置,否则各个分班单独设置)
    :
    } @@ -2179,8 +2186,8 @@ class Trainingjobsetting extends Component { unifiedsetting === undefined ? "" : unifiedsetting=== true ?
    - 发布时间: - + 发布时间: +
    - (学生收到作业的时间) + (学生收到作业的时间)

    { @@ -2212,8 +2219,8 @@ class Trainingjobsetting extends Component { }

    - 截止时间: - + 截止时间: +
    - (学生“按时”提交作品的时间截点) + (学生“按时”提交作品的时间截点)

    { @@ -2266,16 +2273,16 @@ class Trainingjobsetting extends Component { {/*补交设置*/}

    -
    补交设置
    +
    补交设置
    {/*value={this.state.allowreplenishment}*/}
    开启补交 (选中,则允许学生延时提交作品) + className={"font-14 ml10 color-grey-c"} style={{textAlign:"left",fontSize:"14px"}} >(选中,则允许学生延时提交作品)
    - 迟交扣分: + 迟交扣分: - (延时提交作品时,学生成绩将被扣减的分值) + (延时提交作品时,学生成绩将被扣减的分值) {/*{latepenaltytype===true?
    :""}*/}
    { @@ -2310,7 +2317,7 @@ class Trainingjobsetting extends Component { :"" }
    - 结束时间: + 结束时间: - (学生“延时”提交作品的时间截点) + (学生“延时”提交作品的时间截点) {/*{latetimetype===true?
    结束时间不能小于截止时间
    :""}*/} { Spintype===false?graduation_list.map((item,key)=>{ if(key===0){ return( -

    5 ? (76*(ec_course_targets_count+4)+380+15):1200+"px"}}> - 毕业要求 - {item.ec_subitem_content} - 达成结果 - 达成目标值 - 达成实际值 - 课程权重 +

  • 5 ? (76*(ec_course_targets_count+4)+380+15):1200+"px"}}> +
    + 毕业要求 +
    + {item.ec_subitem_content} +
    {TargetresList(ec_course_targets_count)} -

    +
    +
    + 课程权重 + 达成目标值 + 达成实际值 + 达成结果 +
    +
  • ) } }):"" } + {/*mynewtarget_scoreclassysls*/} + +
    + { + Spintype===false?graduation_list.map((item,key)=>{ + + return( + +
  • 5 ? (76*(ec_course_targets_count+4)+380+15):1200+"px"}}> +
    + {key+1} +
    + {item.content} +
    + {TargetresContentList(target_list,item.support_course_target_ids)} +
    +
    + {item.weights===null||item.weights===undefined||item.weights==="0.00"||item.weights===0.00||item.weights===0?立即配置:{item.weights}} + {item.actually_achievement===null?0:item.actually_achievement} + {item.objective_achievement===null?0:item.objective_achievement} + {item.status==="not_achieved"?"未完成":"完成"} +
    +
  • + + + //
  • 5 ? (76*(ec_course_targets_count+4)+380):1200+"px"}}> + // {/* {item.ec_graduation_name} */} + // {key+1} + // {item.content} + // {item.status==="not_achieved"?"未完成":"完成"} + // {item.objective_achievement===null?0:item.objective_achievement} + // {item.actually_achievement===null?0:item.actually_achievement} + // {item.weights===null||item.weights===0?立即配置:{item.weights}} + // {TargetresContentList(ec_course_targets_count,item.target_position)} + //
  • + ) + + }):"" + } + + +
    - - { - Spintype===false?graduation_list.map((item,key)=>{ - - return( -
  • 5 ? (76*(ec_course_targets_count+4)+380):1200+"px"}}> - {/* {item.ec_graduation_name} */} - {key+1} - {item.ec_subitem_content} - {item.result} - {item.reach_target===null?0:item.reach_target} - {item.reach_real_target===null?0:item.reach_real_target} - {item.weight===null||item.weight===0?立即配置:{item.weight}} - {TargetresContentList(ec_course_targets_count,item.target_position)} -
  • - ) - - }):"" - }
    + {/*课程总评成绩表*/}
    @@ -652,9 +757,9 @@ class EcCompletionCalculation extends Component { {/* 平均数 */} {/* 平均数 */} {Total_rate_dataList(course_total_score)} - { - course_total_score.length===0? --:"" - } + { + course_rate===undefined||course_rate===null||course_rate===""||course_rate==="0"||course_rate===0? --:{course_rate} + } :"" } {/*style={{width: 113*(total_rate_data+4)>1136?113*(total_rate_data+4):1136+"px"}}*/} @@ -687,7 +792,7 @@ class EcCompletionCalculation extends Component { {newTotal_rate_dataList(course_total_score-1,course_total_score)} {/* {course_total_score.length===0?"":course_total_score[course_total_score-1].total_score} */} { - course_total_score.length===0? --:{course_total_scoreaverage} + course_achievement===undefined||course_achievement===null||course_achievement===""||course_achievement==="0"||course_achievement===0? --:{course_achievement} } :"" } @@ -716,47 +821,63 @@ class EcCompletionCalculation extends Component { 平均分 最高分数 最低分数 - 90分以上 - 80-89分 - 70-79分 - 60-69分 - 50-59分 - 低于50分 + { + score_levels&&score_levels.map((i,k)=>{ + return( + {i.description} + ) + }) + }

    { - Spintype===false?target_score.map((i,k)=>{ + Spintype===false?target_list.map((i,k)=>{ return(
  • {k+1} - {i.average_score} - {i.top_score} - {i.low_score} - -
    {i.from90[0]}人
    -
    {(i.from90[1]).toFixed(2)}%
    -
    - -
    {i.from80[0]}人
    -
    {(i.from80[1]).toFixed(2)}%
    -
    - -
    {i.from70[0]}人
    -
    {(i.from70[1]).toFixed(2)}%
    -
    - -
    {i.from60[0]}人
    -
    {(i.from60[1]).toFixed(2)}%
    -
    - -
    {i.from50[0]}人
    -
    {(i.from50[1]).toFixed(2)}%
    -
    - -
    {i.from_down[0]}人
    -
    {(i.from_down[1]).toFixed(2)}%
    -
    + {i.standard_grade} + {i.maximum_score===null || i.maximum_score===undefined ||i.maximum_score===""?"--":i.maximum_score} + {i.minimum_score===null || i.minimum_score===undefined || i.minimum_score===""?"--":i.minimum_score} + { + i.score_levels.map((j,l)=>{ + + return( + +
    {j.count}人
    +
    {j.rate===null||j.rate===undefined||j.rate===""||j.rate===0?0.00:j.rate}%
    +
    + ) + } + ) + } + + {/*}*/} + {/**/} + {/*
    {i.from90[0]}人
    */} + {/*
    {(i.from90[1]).toFixed(2)}%
    */} + {/*
    */} + {/**/} + {/*
    {i.from80[0]}人
    */} + {/*
    {(i.from80[1]).toFixed(2)}%
    */} + {/*
    */} + {/**/} + {/*
    {i.from70[0]}人
    */} + {/*
    {(i.from70[1]).toFixed(2)}%
    */} + {/*
    */} + {/**/} + {/*
    {i.from60[0]}人
    */} + {/*
    {(i.from60[1]).toFixed(2)}%
    */} + {/*
    */} + {/**/} + {/*
    {i.from50[0]}人
    */} + {/*
    {(i.from50[1]).toFixed(2)}%
    */} + {/*
    */} + {/**/} + {/*
    {i.from_down[0]}人
    */} + {/*
    {(i.from_down[1]).toFixed(2)}%
    */} + {/*
    */} +
  • ) @@ -764,8 +885,8 @@ class EcCompletionCalculation extends Component { } { Spintype===true?}/>:"" } - - {target_score.length===0&&Spintype===false? + + {target_list.length===0&&Spintype===false?
  • -- -- diff --git a/public/react/src/modules/ecs/subroute/ecCourseEvaluations/EcCourseEvaluationsbottom.js b/public/react/src/modules/ecs/subroute/ecCourseEvaluations/EcCourseEvaluationsbottom.js index 6e27711b2..013357d44 100644 --- a/public/react/src/modules/ecs/subroute/ecCourseEvaluations/EcCourseEvaluationsbottom.js +++ b/public/react/src/modules/ecs/subroute/ecCourseEvaluations/EcCourseEvaluationsbottom.js @@ -16,7 +16,7 @@ import 'antd/dist/antd.css'; import '../../css/ecCourseEvaluations.css'; import EcTitleCourseEvaluations from "../../ecTitle/ecTitle"; - +import './eccourseevalut.css' const $ = window.$; // 课程目标评价方法 @@ -48,21 +48,24 @@ class EcCourseEvaluationsbottom extends Component { meweacoursetype:false, newshowredvalue:false, percentagetype:false, - ismanager:false + ismanager:true } } getec_course_achievement_methods=()=>{ const {newec_course_idbottom}=this.state; if(newec_course_idbottom!=undefined){ - const url = `/ec_course_achievement_methods?ec_course_id=`+newec_course_idbottom; + // const url ='ec_courses/:course_id/course_targets.json'; + // const url = `/ec_course_achievement_methods?ec_course_id=`+newec_course_idbottom; + const course_id = 706 + const url =`/ec_courses/${course_id}/course_targets/course_achievement_methods.json`; axios.get(url, { withCredentials: true, }) .then((response)=>{ this.setState({ - achievement_list:response.data.achievement_list, + achievement_list:response.data.course_targets, spinningstate:false, - ismanager:response.data.is_manager + ismanager:true }) }).catch(function (error) { console.log(error); @@ -70,11 +73,11 @@ class EcCourseEvaluationsbottom extends Component { } // this.setState({ // achievement_list:[ - // {target_evaluate_data: [ + // {course_achievement_methods: [ // { // evaluate_id: 24, // evaluate_name: "期末考试", - // evaluation_relates_data: [ + // course_evaluation_subitems: [ // {evaluation_relates_id: 31, evaluation_relates_name: "期末考试1目标1考题"}, // {evaluation_relates_id: 32, evaluation_relates_name: "期末考试1目标2考题"} // ], @@ -113,25 +116,27 @@ class EcCourseEvaluationsbottom extends Component { }); } componentDidMount(){ - let ec_course_id=this.props.match.params.ec_course_id; - const url = `/ec_course_achievement_methods?ec_course_id=`+ec_course_id; - axios.get(url, { - withCredentials: true, - }) + let ec_course_id=this.props.match.params.ec_course_id; + const course_id = 706 + const url =`/ec_courses/${course_id}/course_targets/with_achievement_methods.json`; + // /ec_courses//course_targets/course_achievement_methods.json + // const url = `/ec_course_achievement_methods?ec_course_id=`+course_id; + axios.get(url) .then((response)=>{ this.setState({ - achievement_list:response.data.achievement_list, + achievement_list:response.data.course_targets, spinningstate:false, - ismanager:response.data.is_manager + ismanager:true }) }).catch(function (error) { console.log(error); }); - this.getNavigationData(ec_course_id); + // this.getNavigationData(ec_course_id); this.setState({ - newec_course_idbottom:ec_course_id + newec_course_idbottom:course_id }) + this.props.Ontitine("evaluation_methods"); } editecCourseEvaluationslist=(e)=>{ let id =e.target.getAttribute("target_id"); @@ -226,7 +231,7 @@ class EcCourseEvaluationsbottom extends Component { newec_course_target_id:id, methodologytype:true, ec_course_target_name:response.data.ec_course_target_name, - ismanager:response.data.is_manager + ismanager:true }) // this.setState({ @@ -427,15 +432,16 @@ class EcCourseEvaluationsbottom extends Component { EvaluationsSaveonloadgetdata=(id)=>{ - const url = `/ec_course_achievement_methods?ec_course_id=`+id + const course_id = 706; + const url = `/ec_courses/${course_id}/course_targets/with_achievement_methods.json`; axios.get(url, { withCredentials: true, }) .then((response)=>{ this.setState({ - achievement_list:response.data.achievement_list, + achievement_list:response.data.course_targets, spinningstate:false, - ismanager:response.data.is_manager + ismanager:true }) }).catch(function (error) { @@ -554,7 +560,9 @@ class EcCourseEvaluationsbottom extends Component { } - var Url = '/ec_course_achievement_methods/create_evaluation_methods'; + // var Url = '/ec_course_achievement_methods/create_evaluation_methods'; + var Url = '/ec_courses/:course_id/course_targets/:target_id/course_achievement_methods.json'; + axios.post(Url, { ec_course_target_id: newec_course_target_id, achievement_methods:achievement_methods @@ -575,7 +583,7 @@ class EcCourseEvaluationsbottom extends Component { achievement_methods:undefined, eacoursesavetypes:false, newshowredvalue:false, - ismanager:response.data.is_manager + ismanager:true }) // $("#ecCourseEvaluationsbottomsubmit").hide(); // $("#SystemParametersbottom").hide(); @@ -662,6 +670,8 @@ class EcCourseEvaluationsbottom extends Component { percentagetype, ismanager } = this.state; + // console.log("EcCourseEvaluationsbottom12345"); + // console.log(achievement_list); return (
    @@ -760,35 +770,35 @@ class EcCourseEvaluationsbottom extends Component {

    { - achievement_list.length===0?}/>:achievement_list.map((item,key)=>{ + achievement_list===undefined?"":achievement_list&&achievement_list.length===0?}/>:achievement_list&&achievement_list.map((item,key)=>{ return(
    { - item.target_evaluate_data.length===0? -
  • -
    - {key+1} + item.course_achievement_methods.length===0? +
  • +
    + {key+1} - + - +
    - +
    - +
    - +
    @@ -797,9 +807,9 @@ class EcCourseEvaluationsbottom extends Component { {/* 修改start*/}
    -
    +
    {/*
    */} -
    +
    {/* 课程目标{sequenceid}:{ec_course_target_name} */} 课程目标{key+1}:{ec_course_target_name} @@ -883,20 +893,20 @@ class EcCourseEvaluationsbottom extends Component {
  • - :item.target_evaluate_data.map((i,k)=>{ + :item.course_achievement_methods.map((i,k)=>{ return( -
  • -
    - {key-k===key?key+1:""} +
  • +
    + {key-k===key?key+1:""} - - {i.evaluate_name} + + {i.course_evaluation.name} - + { - i.evaluation_relates_data.map((y,e)=>{ + i.course_evaluation_subitems.map((y,e)=>{ return( -
    {y.evaluation_relates_name+" "}
    +
    {y.name+" "}
    ) }) } @@ -919,11 +929,11 @@ class EcCourseEvaluationsbottom extends Component { } - +
    {i.percentage+"%"}
    - +
    {i.score}
    @@ -931,8 +941,8 @@ class EcCourseEvaluationsbottom extends Component {
    {/* 修改start*/}
    -
    -
    +
    +
    {/* 课程目标{sequenceid}:{ec_course_target_name} */} 课程目标{key+1}:{ec_course_target_name} diff --git a/public/react/src/modules/ecs/subroute/ecCourseEvaluations/eccourseevalut.css b/public/react/src/modules/ecs/subroute/ecCourseEvaluations/eccourseevalut.css new file mode 100644 index 000000000..c9a05d7ec --- /dev/null +++ b/public/react/src/modules/ecs/subroute/ecCourseEvaluations/eccourseevalut.css @@ -0,0 +1,8 @@ +.yslinitials{ + + display: flex; + flex-direction:initial; +} +.yslpadding{ + padding: 0px 30px; +} \ No newline at end of file diff --git a/public/react/src/modules/ecs/subroute/ecCourseSupportSetting/EditableCourseSupportSetting.js b/public/react/src/modules/ecs/subroute/ecCourseSupportSetting/EditableCourseSupportSetting.js new file mode 100644 index 000000000..70b39241c --- /dev/null +++ b/public/react/src/modules/ecs/subroute/ecCourseSupportSetting/EditableCourseSupportSetting.js @@ -0,0 +1,476 @@ +import React, { Component } from 'react'; + +import moment from 'moment' +import { getUrl } from 'educoder' +import { Form, Input, Icon, Button, Select, InputNumber } from 'antd'; +const { TextArea } = Input; +const { Option } = Select; + +let _url_origin = getUrl() +const $ = window.$ +// https://www.educoder.net/stylesheets/css/common.css?1546618720 +if (!window['EcLoaded']) { + $('head').append( $('') + .attr('href', `${_url_origin}/stylesheets/css/common.css?1525440977`) ); + window['EcLoaded'] = true +} + +let id = 0; + + +/** + target_id + position + target_weight + target_contents + + subitem_id + index + subitem_contents + +*/ +const data = +[{"position":0,"target_weight":0.02,"target_contents":"12","standard_grade":2,"subitem_id":"65"},{"position":3,"target_id":"0","target_weight":0.1,"target_contents":"理解数据管理技术和数据库技术的发展,区分不同数据模型的作用和特点,描述数据库系统的类型、结构、数据独立性。","standard_grade":60,"subitem_id":"66"},{"position":4,"target_weight":1,"target_contents":"22","standard_grade":33,"subitem_id":"66"},{"position":11,"target_id":"1","target_weight":0.1,"target_contents":"理解数据管理技术和数据库技术的发展,区分不同数据模型的作用和特点,描述数据库系统的类型、结构、数据独立性。","standard_grade":61,"subitem_id":"65"}] +; +let _data = [ + { + target_id: 0, + position: 1, + target_weight: 0.1, + target_contents: '理解数据管理技术和数据库技术的发展,区分不同数据模型的作用和特点,描述数据库系统的类型、结构、数据独立性。', + standard_grade: 60, + // biyeYaoqiuZhibiaodian: ':能够运用相关的工程基础和专业知识辨别材料生产中出现的技术、工艺、质量等问题', + "subitem_id": 64, + "index": "1-1", + "subitem_contents": "能够运用相关的工程基础和专业知识辨别材料生产中出现的技术、工艺、质量等问题" + }, + { + target_id: 1, + position: 2, + target_weight: 0.1, + target_contents: '理解数据管理技术和数据库技术的发展,区分不同数据模型的作用和特点,描述数据库系统的类型、结构、数据独立性。', + standard_grade: 61, + // biyeYaoqiuZhibiaodian: ':能够运用相关的工程基础和专业知识辨别材料生产中出现的技术、工艺、质量等问题', + "subitem_id": 65, + "index": "1-2", + "subitem_contents": "222能够运用相关的工程基础和专业知识辨别材料生产中出现的技术、工艺、质量等问题" + } +] +const item = {} + +class EditableCourseSupportSetting extends Component { + constructor(props) { + super(props) + this.state = { + addOrDeleting: false, + errorMsg: '' + } + } + onRemove = (k) => { + let fValues = this.props.form.getFieldsValue(); + if ( + // fValues.standard_grade[k] && fValues.standard_grade[k] != 75 + // || fValues.subitem_id[k] + // || + fValues.target_contents[k] + // || fValues.target_weight[k] + ) { + this.props.showModal('提示', '确定要删除吗?', () => { + this.remove(k) + }) + } else { + this.remove(k) + } + } + remove = (k) => { + const { form } = this.props; + // can use data-binding to get + const keys = form.getFieldValue('keys'); + // We need at least one passenger + // if (keys.length === 1) { + // return; + // } + if (keys.length === 1) { + this.setState({ errorMsg: '至少得保留一条数据' }) + return; + } + // 清除悬浮tip + window.$('.data-tip-down').hide() + + console.log('remove :' , k , this.position2Target_idMap[k]) + delete this.position2Target_idMap[k] + // can use data-binding to set + form.setFieldsValue({ + keys: keys.filter(key => key !== k), + }); + } + _reverseMap = (map) => { + let newMap = {} + for (var k in map) { + newMap[map[k]] = k; + } + return newMap + } + addIfNewKeyExist = (newKey, index_arg) => { + this.setState({ addOrDeleting: true }) + const { form } = this.props; + const keys = form.getFieldValue('keys'); + /** + [0,1,2,3] + ['11', '22', '33', '44'] + -> + [0,1,2,3,4] + ['11', '22', empty, '33', '44'] + + */ + const target_weight = form.getFieldValue('target_weight'); + const target_contents = form.getFieldValue('target_contents'); + const standard_grade = form.getFieldValue('standard_grade'); + const subitem_id = form.getFieldValue('subitem_id'); + keys.splice(index_arg, 0, newKey); + + // position2Target_idMap + // {1:2, 2:3, 3:4, 4:6 } --> {1:2, 2:3, 3:7, 4:4, 5:6 } + // 更新key/position 映射到target_id的map + // 两次revers,用这个结构,达到给position加1的效果 + let reverseMap = this._reverseMap(this.position2Target_idMap); + for (let i = index_arg ; i < keys.length; i++) { + if(keys[i] === keys[i+1]) { // 找到开始+1的行 + continue; + } + let target_id = this.position2Target_idMap[keys[i]]; + reverseMap[target_id] = parseInt(reverseMap[target_id]) + 1; + keys[i] = keys[i] + 1; + } + for (let i = 0 ; i < keys.length - 1; i++) { + if (keys[i] == keys[i + 1]) { + debugger; + } + } + this.position2Target_idMap = this._reverseMap(reverseMap); + + + target_weight.splice(newKey, 0, undefined); + target_contents.splice(newKey, 0, undefined); + standard_grade.splice(newKey, 0, undefined); + subitem_id.splice(newKey, 0, undefined); + + setTimeout(() => { + form.setFieldsValue({ + target_weight, + target_contents, + standard_grade, + subitem_id + }); + window.$('.data-tip-down').hide() + this.setState({ addOrDeleting: false }) + + }, 300) + form.setFieldsValue({ + keys: keys + }); + + } + add = (k, index) => { + this.setState({ errorMsg: '' }) + + const { form } = this.props; + // can use data-binding to get + const keys = form.getFieldValue('keys'); + let nextKeys ; + let newKey = k + 1; + + const newKeyIndex = keys.indexOf(newKey) + if (newKeyIndex != -1) { + // 新key存在,将新key位置及以后的row后移,直到找到一个之后的空位置 + this.addIfNewKeyExist(newKey, index) + } else { // 如果这个新key不存在 + // keys[newIndex] = newKey + keys.splice(index === 0 && k === -1 ? 0 : index, 0, newKey); + } + // can use data-binding to set + // important! notify form to detect changes + form.setFieldsValue({ + keys: keys, + }); + } + + handleSubmit = (e) => { + if (!this.props.is_manager) { + this.props.showModal('提示', '您没权限编辑,请联系管理员。') + return; + } + this.setState({ errorMsg: '' }) + e.preventDefault && e.preventDefault(); + this.props.form.validateFieldsAndScroll((err, values) => { + if (!err) { + let keysLen = values.keys.length + if (keysLen < 1) { + this.setState({ errorMsg: '至少得保留一条数据' }) + } + var data = [] + while( keysLen-- ) { + data.push({}) + } + for (var valKey in values) { + + let dataIndex = 0 + values[valKey].forEach( (item,index) => { + let _val = values[valKey][index]; + if (_val || _val == 0) { + data[dataIndex][valKey === 'keys' ? 'position' : valKey] = _val + if (valKey === 'keys' && (this.position2Target_idMap[_val] || this.position2Target_idMap[_val] === 0) ) { + data[dataIndex].target_id = this.position2Target_idMap[_val] + } + dataIndex++; + } + }) + } + + console.log('Received values of form: ', values, data); + + let totalWeight = 0; + values.target_weight.forEach(item => { + if (item) { + totalWeight += item + } + }) + // 精度问题 0.2 + 0.7 = 0.8999999999 + if (parseInt((totalWeight * 100).toFixed(1)) != 100) { + this.setState({ errorMsg: '请先保证权重和等于1' }) + return; + } + + this.props.updateCourseTargets(data) + } else { + + const keyRowNumMap = {} + let rowNum = 1; + for (var key in values.target_contents) { + keyRowNumMap[key] = rowNum; + rowNum++; + } + + // err.target_contents[1].errors[0] + // {message: "请填入目标内容", field: "target_contents[1]"} + for (var key in err) { + for (var _k in err[key]) { + let errorObj = err[key][_k].errors[0]; + + let _key = errorObj.field.match(`[(0-9)]`) + this.setState({ errorMsg: `第${keyRowNumMap[_key]}行,${errorObj.message}` }) + return; + // console.log(`第${keyRowNumMap[_key]}行,${errorObj.message}`); + } + } + } + + + }); + } + + componentDidMount = () => { + this.position2Target_idMap = {} + const { form } = this.props; + + const data = this.props.course_targets + + let target_weight = [] + let target_contents = [] + let standard_grade = [] + // let biyeYaoqiuZhibiaodian = [] + let subitem_id = [] + let keys = [] + + data.forEach(item => { + keys.push(item.position); + target_weight[item.position] = (item.target_weight) + target_contents[item.position] = (item.target_contents); + standard_grade[item.position] = (item.standard_grade); + // biyeYaoqiuZhibiaodian[item.position] = (item.biyeYaoqiuZhibiaodian); + + subitem_id[item.position] = item.subitem_id ? (item.subitem_id).toString() : item.subitem_id; + + this.position2Target_idMap[item.position] = item.target_id + }) + form.setFieldsValue({ + keys + }); + setTimeout(() => { + form.setFieldsValue({ + // keys, + target_weight, + target_contents, + standard_grade, + // biyeYaoqiuZhibiaodian, + subitem_id, + }); + // this.forceUpdate() + }, 3000) + + + } + + + render() { + const { getFieldDecorator, getFieldValue } = this.props.form; + const { requirements } = this.props; + const { addOrDeleting } = this.state; + const formItemLayout = { + labelCol: { + xs: { span: 24 }, + sm: { span: 4 }, + }, + wrapperCol: { + xs: { span: 24 }, + sm: { span: 20 }, + }, + }; + const formItemLayoutWithOutLabel = { + wrapperCol: { + xs: { span: 24, offset: 0 }, + sm: { span: 20, offset: 4 }, + }, + }; + getFieldDecorator('keys', { initialValue: [] }); + const keys = getFieldValue('keys'); + const formItems = keys.map((k, index) => ( +
  • + + { index + 1 } + + {getFieldDecorator(`target_weight[${k}]`, { + // validateTrigger: ['onChange', 'onBlur'], + rules: [{ + required: true, + whitespace: true, + type: 'number', + message: "请填入权重", + }], + })( + + )} + + + {getFieldDecorator(`target_contents[${k}]`, { + // validateTrigger: ['onChange', 'onBlur'], + rules: [{ + required: true, + // whitespace: true, + message: "请填入目标内容", + }], + })( +