diff --git a/app/controllers/admins/import_course_members_controller.rb b/app/controllers/admins/import_course_members_controller.rb new file mode 100644 index 000000000..42022b710 --- /dev/null +++ b/app/controllers/admins/import_course_members_controller.rb @@ -0,0 +1,10 @@ +class Admins::ImportCourseMembersController < Admins::BaseController + def create + return render_error('请上传正确的文件') if params[:file].blank? || !params[:file].is_a?(ActionDispatch::Http::UploadedFile) + + result = Admins::ImportCourseMemberService.call(params[:file].to_io) + render_ok(result) + rescue Admins::ImportCourseMemberService::Error => ex + render_error(ex) + end +end \ No newline at end of file diff --git a/app/controllers/student_works_controller.rb b/app/controllers/student_works_controller.rb index 519bb7e7d..99a02106c 100644 --- a/app/controllers/student_works_controller.rb +++ b/app/controllers/student_works_controller.rb @@ -541,7 +541,7 @@ class StudentWorksController < ApplicationController def destroy_score score = @work.student_works_scores.find_by(id: params[:score_id]) tip_exception("该评阅记录不存在") unless score.present? - tip_exception("该评阅记录不能删除") unless score.allow_delete(@current_user, @user_course_identity) + tip_exception("该评阅记录不能删除") unless score.allow_delete(current_user) begin score.destroy normal_status(0,"删除成功") diff --git a/app/imports/admins/import_course_member_excel.rb b/app/imports/admins/import_course_member_excel.rb new file mode 100644 index 000000000..ddd3b01a1 --- /dev/null +++ b/app/imports/admins/import_course_member_excel.rb @@ -0,0 +1,20 @@ +class Admins::ImportCourseMemberExcel < BaseImportXlsx + Data = Struct.new(:student_id, :name, :course_id, :role, :course_group_name, :school_id) + + def read_each(&block) + sheet.each_row_streaming(pad_cells: true, offset: 1) do |row| + data = row.map(&method(:cell_value))[0..5] + block.call Data.new(*data) + end + end + + private + + def check_sheet_valid! + raise_import_error('请按照模板格式导入') if sheet.row(1).size != 6 + end + + def cell_value(obj) + obj&.cell_value&.to_s&.strip + end +end diff --git a/app/models/student_works_score.rb b/app/models/student_works_score.rb index f6c7b3e33..19043f7f8 100644 --- a/app/models/student_works_score.rb +++ b/app/models/student_works_score.rb @@ -13,9 +13,8 @@ belongs_to :student_work identity < Course::STUDENT || self.user == user || self.reviewer_role != 3 end - def allow_delete current_user, identity - self.is_invalid && (current_user == self.user || identity < Course::STUDENT) || - (self.score.nil? && current_user == self.user) + def allow_delete current_user + (self.is_invalid || self.score.nil?) && (current_user == self.user || current_user.admin?) end # 匿评分 diff --git a/app/services/admins/import_course_member_service.rb b/app/services/admins/import_course_member_service.rb new file mode 100644 index 000000000..8f162902f --- /dev/null +++ b/app/services/admins/import_course_member_service.rb @@ -0,0 +1,63 @@ +class Admins::ImportCourseMemberService < ApplicationService + Error = Class.new(StandardError) + + attr_reader :file, :result + + def initialize(file) + @file = file + @result = { success: 0, fail: [] } + end + + def call + raise Error, '文件不存在' if file.blank? + + excel = Admins::ImportCourseMemberExcel.new(file) + excel.read_each(&method(:create_course_member)) + + result + rescue ApplicationImport::Error => ex + raise Error, ex.message + end + + private + + def create_course_member(data) + raise '课堂角色必须为 2、3、4' unless [2, 3, 4].include?(data.role.to_i) + + user = User.joins(:user_extension).where(user_extensions: { student_id: data.student_id, school_id: data.school_id }).first + raise '该学号的用户不存在' if user.blank? + course = Course.find_by(id: data.course_id) + raise '该课堂不存在' if course.blank? + + course_group = nil + if data.course_group_name.present? + course_group = course.course_groups.find_or_create_by!(name: data.course_group_name) + end + + member = course.course_members.find_by(user_id: user.id, role: data.role.to_i) + # 如果已是课堂成员且是学生身份and不在指定的分班则移动到该分班 + if member.present? && member.role == :STUDENT && course_group && member.course_group_id != course_group&.id + member.update!(course_group_id: course_group&.id) + elsif member.blank? + course.course_members.create!(user_id: user.id, role: data.role.to_i, course_group_id: course_group&.id) + extra = + case data.role.to_i + when 2 then 9 + when 3 then 7 + else 10 + end + + Tiding.create!(user_id: user.id, trigger_user_id: course.tea_id, container_id: course.id, + container_type: 'TeacherJoinCourse', belong_container_id: course.id, + belong_container_type: 'Course', tiding_type: 'System', extra: extra) + end + + result[:success] += 1 + rescue Exception => ex + fail_data = data.as_json + fail_data[:data] = fail_data.values.join(',') + fail_data[:message] = ex.message + + result[:fail] << fail_data + end +end \ No newline at end of file diff --git a/app/views/graduation_works/comment_list.json.jbuilder b/app/views/graduation_works/comment_list.json.jbuilder index 51595c55b..77898c91d 100644 --- a/app/views/graduation_works/comment_list.json.jbuilder +++ b/app/views/graduation_works/comment_list.json.jbuilder @@ -15,7 +15,7 @@ json.comment_scores @comment_scores do |score| json.score score.score json.content score.comment json.is_invalid score.is_invalid - json.delete @current_user == score.user && (score.is_invalid || score.score.nil?) + json.delete (@current_user == score.user || @current_user.admin?) && (score.is_invalid || score.score.nil?) json.attachments score.attachments do |atta| json.partial! "attachments/attachment_simple", locals: {attachment: atta, delete: false} end diff --git a/app/views/student_works/comment_list.json.jbuilder b/app/views/student_works/comment_list.json.jbuilder index b14de2f31..1a089587b 100644 --- a/app/views/student_works/comment_list.json.jbuilder +++ b/app/views/student_works/comment_list.json.jbuilder @@ -23,7 +23,7 @@ json.comment_scores @comment_scores do |score| json.content score.comment json.appeal_status score.appeal_status json.is_invalid score.is_invalid - json.delete score.allow_delete(@current_user, @user_course_identity) + json.delete score.allow_delete(@current_user) json.attachments score.attachments do |atta| json.partial! "attachments/attachment_simple", locals: {attachment: atta, delete: false} end diff --git a/config/routes.rb b/config/routes.rb index c2da5fc63..22808ba10 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -804,6 +804,7 @@ Rails.application.routes.draw do end end resource :import_users, only: [:create] + resource :import_course_members, only: [:create] resources :library_applies, only: [:index] do member do diff --git a/public/react/src/modules/courses/poll/PollNew.js b/public/react/src/modules/courses/poll/PollNew.js index 9c00ae30d..372a79ae6 100644 --- a/public/react/src/modules/courses/poll/PollNew.js +++ b/public/react/src/modules/courses/poll/PollNew.js @@ -2774,8 +2774,13 @@ class PollNew extends Component { className="color-grey-9 fl">{item.question.question_type === 1 ? "(单选题)" : item.question.question_type === 2 ? "(多选题)" : "(主观题)"} {item.question.is_necessary === 1 ? "必答" : item.question.question_type === 2 ? "选答" : "选答"} - {(item.question.min_choices === undefined && item.question.max_choices === undefined ? "不限制" : item.question.min_choices === null && item.question.max_choices === null ? "不限制" : item.question.min_choices === 0 && item.question.max_choices === 0 ? "": item.question.min_choices === "null" && item.question.max_choices === "null" ? "不限制" : "可选" +(item.question.min_choices===undefined||item.question.min_choices===null||item.question.min_choices===""||item.question.min_choices==="null"?2:item.question.min_choices) + "-" + (item.question.max_choices===undefined||item.question.max_choices===null||item.question.max_choices===""||item.question.max_choices==="null"?item.question.answers.length:item.question.max_choices) + "项")} + { + item.question.question_type === 2? + {(item.question.min_choices === undefined && item.question.max_choices === undefined ? "不限制" : item.question.min_choices === null && item.question.max_choices === null ? "不限制" : item.question.min_choices === 0 && item.question.max_choices === 0 ? "": item.question.min_choices === "null" && item.question.max_choices === "null" ? "不限制" : "可选" +(item.question.min_choices===undefined||item.question.min_choices===null||item.question.min_choices===""||item.question.min_choices==="null"?2:item.question.min_choices) + "-" + (item.question.max_choices===undefined||item.question.max_choices===null||item.question.max_choices===""||item.question.max_choices==="null"?item.question.answers.length:item.question.max_choices) + "项")} + : "" + } + { polls_status === undefined || polls_status === 1 ? diff --git a/public/react/src/modules/tpm/TPMIndexHOC.js b/public/react/src/modules/tpm/TPMIndexHOC.js index a81a273bb..52eda5901 100644 --- a/public/react/src/modules/tpm/TPMIndexHOC.js +++ b/public/react/src/modules/tpm/TPMIndexHOC.js @@ -471,6 +471,9 @@ export function TPMIndexHOC(WrappedComponent) { .indexHOC > .ant-spin-nested-loading { background: #000; } + .indexHOC > .ant-spin-nested-loading > div > .ant-spin .ant-spin-dot { + top: 50% !important; + } .globalSpin .ant-spin-text { text-shadow: none !important;