diff --git a/app/assets/javascripts/admins/laboratory_shixuns/index.js b/app/assets/javascripts/admins/laboratory_shixuns/index.js new file mode 100644 index 000000000..f7f41c4d8 --- /dev/null +++ b/app/assets/javascripts/admins/laboratory_shixuns/index.js @@ -0,0 +1,119 @@ +$(document).on('turbolinks:load', function() { + if ($('body.admins-laboratory-shixuns-index-page').length > 0) { + var $searchForm = $('.laboratory-shixun-list-form .search-form'); + var laboratoryId = $('.laboratory-shixun-list-container').data('id'); + + $searchForm.find('select#tag_id').select2({ + placeholder: "请选择", + allowClear: true + }); + + // 定义状态切换监听事件 + var defineStatusChangeFunc = function (doElement, undoElement, url, callback) { + $('.laboratory-shixun-list-container').on('click', doElement, function () { + var $doAction = $(this); + var $undoAction = $doAction.siblings(undoElement); + + var laboratoryShixunId = $doAction.data('id'); + customConfirm({ + content: '确认进行该操作吗?', + ok: function () { + $.ajax({ + url: '/admins/laboratories/' + laboratoryId + '/laboratory_shixuns/' + laboratoryShixunId + url, + method: 'POST', + dataType: 'json', + success: function () { + show_success_flash(); + $doAction.hide(); + $undoAction.show(); + if (callback && typeof callback === "function") { + callback(laboratoryShixunId, url); + } + } + }); + } + }); + }); + } + + // 首页展示与取消首页展示 + var homepageShowCallback = function (laboratoryShixunId, url) { + var $laboratoryShixunItem = $('.laboratory-shixun-list-container').find('.laboratory-shixun-item-' + laboratoryShixunId); + + if (url === '/homepage') { + $laboratoryShixunItem.find('.homepage-badge').show(); + } else { + $laboratoryShixunItem.find('.homepage-badge').hide(); + } + } + defineStatusChangeFunc('.homepage-show-action', '.homepage-hide-action', '/homepage', homepageShowCallback); + defineStatusChangeFunc('.homepage-hide-action', '.homepage-show-action', '/cancel_homepage', homepageShowCallback); + + // 添加实训功能 + var $addModal = $('.modal.admin-add-laboratory-shixun-modal'); + var $addForm = $addModal.find('form.admin-add-laboratory-user-form'); + var $shixunSelect = $addForm.find('select.shixun-select'); + + $addModal.on('show.bs.modal', function(){ + $addModal.find('.error').html(''); + $shixunSelect.select2('val', ' '); + }); + + $shixunSelect.select2({ + theme: 'bootstrap4', + placeholder: '请输入实训名称/创建者检索', + multiple: true, + minimumInputLength: 1, + ajax: { + delay: 500, + url: '/admins/laboratories/' + laboratoryId + '/shixuns_for_select', + dataType: 'json', + data: function(params){ + return { keyword: params.term }; + }, + processResults: function(data){ + return { results: data.shixuns } + } + }, + templateResult: function (item) { + if(!item.id || item.id === '') return item.text; + var ele = '' + ele += '' + item.name + ''; + ele += ' -- ' + item.creator_name + ''; + ele += ' -- ' + item.status_text+ ''; + ele += ''; + + return $(ele); + }, + templateSelection: function(item){ + if (item.id) { + } + var ele = '' + (item.name || item.text) + ' -- ' + item.creator_name + '' + return $(ele); + } + }); + + $addModal.on('click', '.submit-btn', function(){ + $addModal.find('.error').html(''); + + var shixunIds = $shixunSelect.val(); + if (shixunIds && shixunIds.length > 0) { + $.ajax({ + method: 'POST', + dataType: 'json', + url: '/admins/laboratories/' + laboratoryId + '/laboratory_shixuns', + data: { shixun_ids: shixunIds }, + success: function(){ + show_success_flash(); + window.location.reload(); + }, + error: function(res){ + $addModal.find('.error').html(res.responseJSON.message); + } + }); + } else { + $addModal.find('.error').html('请选择实训'); + } + }); + } +}) \ No newline at end of file diff --git a/app/assets/javascripts/admins/laboratory_subjects/index.js b/app/assets/javascripts/admins/laboratory_subjects/index.js new file mode 100644 index 000000000..fda0d075f --- /dev/null +++ b/app/assets/javascripts/admins/laboratory_subjects/index.js @@ -0,0 +1,141 @@ +$(document).on('turbolinks:load', function() { + if ($('body.admins-laboratory-subjects-index-page').length > 0) { + var $searchForm = $('.laboratory-subject-list-form .search-form'); + var laboratoryId = $('.laboratory-subject-list-container').data('id'); + + // ************** 学校选择 ************* + $searchForm.find('.school-select').select2({ + theme: 'bootstrap4', + placeholder: '请选择创建者单位', + minimumInputLength: 1, + ajax: { + delay: 500, + url: '/api/schools/search.json', + dataType: 'json', + data: function (params) { + return {keyword: params.term}; + }, + processResults: function (data) { + return {results: data.schools} + } + }, + templateResult: function (item) { + if (!item.id || item.id === '') return item.text; + return item.name; + }, + templateSelection: function (item) { + if (item.id) { + } + return item.name || item.text; + } + }); + + // 定义状态切换监听事件 + var defineStatusChangeFunc = function (doElement, undoElement, url, callback) { + $('.laboratory-subject-list-container').on('click', doElement, function () { + var $doAction = $(this); + var $undoAction = $doAction.siblings(undoElement); + + var laboratorySubjectId = $doAction.data('id'); + customConfirm({ + content: '确认进行该操作吗?', + ok: function () { + $.ajax({ + url: '/admins/laboratories/' + laboratoryId + '/laboratory_subjects/' + laboratorySubjectId + url, + method: 'POST', + dataType: 'json', + success: function () { + show_success_flash(); + $doAction.hide(); + $undoAction.show(); + if (callback && typeof callback === "function") { + callback(laboratorySubjectId, url); + } + } + }); + } + }); + }); + } + + // 首页展示与取消首页展示 + var homepageShowCallback = function (laboratoryShixunId, url) { + var $laboratoryShixunItem = $('.laboratory-subject-list-container').find('.laboratory-subject-item-' + laboratoryShixunId); + + if (url === '/homepage') { + $laboratoryShixunItem.find('.homepage-badge').show(); + } else { + $laboratoryShixunItem.find('.homepage-badge').hide(); + } + } + defineStatusChangeFunc('.homepage-show-action', '.homepage-hide-action', '/homepage', homepageShowCallback); + defineStatusChangeFunc('.homepage-hide-action', '.homepage-show-action', '/cancel_homepage', homepageShowCallback); + + // 添加实践课程功能 + var $addModal = $('.modal.admin-add-laboratory-subject-modal'); + var $addForm = $addModal.find('form.admin-add-laboratory-user-form'); + var $subjectSelect = $addForm.find('select.subject-select'); + + $addModal.on('show.bs.modal', function(){ + $addModal.find('.error').html(''); + $subjectSelect.select2('val', ' '); + }); + + $subjectSelect.select2({ + theme: 'bootstrap4', + placeholder: '请输入课程名称/创建者检索', + multiple: true, + minimumInputLength: 1, + ajax: { + delay: 500, + url: '/admins/laboratories/' + laboratoryId + '/subjects_for_select', + dataType: 'json', + data: function(params){ + return { keyword: params.term }; + }, + processResults: function(data){ + return { results: data.subjects } + } + }, + templateResult: function (item) { + if(!item.id || item.id === '') return item.text; + var ele = '' + ele += '' + item.name + ''; + ele += ' -- ' + item.creator_name + ''; + ele += ' -- ' + item.status_text+ ''; + ele += ''; + + return $(ele); + }, + templateSelection: function(item){ + if (item.id) { + } + var ele = '' + (item.name || item.text) + ' -- ' + item.creator_name + '' + return $(ele); + } + }); + + $addModal.on('click', '.submit-btn', function(){ + $addModal.find('.error').html(''); + + var subjectIds = $subjectSelect.val(); + if (subjectIds && subjectIds.length > 0) { + $.ajax({ + method: 'POST', + dataType: 'json', + url: '/admins/laboratories/' + laboratoryId + '/laboratory_subjects', + data: { subject_ids: subjectIds }, + success: function(){ + show_success_flash(); + window.location.reload(); + }, + error: function(res){ + $addModal.find('.error').html(res.responseJSON.message); + } + }); + } else { + $addModal.find('.error').html('请选择课程'); + } + }); + } +}) \ No newline at end of file diff --git a/app/controllers/admins/laboratories_controller.rb b/app/controllers/admins/laboratories_controller.rb index e393c6677..3bc9383cc 100644 --- a/app/controllers/admins/laboratories_controller.rb +++ b/app/controllers/admins/laboratories_controller.rb @@ -20,6 +20,34 @@ class Admins::LaboratoriesController < Admins::BaseController render_delete_success end + def shixuns_for_select + except_shixun_ids = current_laboratory.laboratory_shixuns.pluck(:shixun_id) + + shixuns = Shixun.where.not(id: except_shixun_ids) + + keyword = params[:keyword].to_s.strip + if keyword.present? + like_sql = 'shixuns.name LIKE :keyword OR CONCAT(users.lastname, users.firstname) LIKE :keyword' + shixuns = shixuns.joins(:user).where(like_sql, keyword: "%#{keyword}%") + end + + @shixuns = paginate(shixuns.includes(:user)) + end + + def subjects_for_select + except_subject_ids = current_laboratory.laboratory_subjects.pluck(:subject_id) + + subjects = Subject.where.not(id: except_subject_ids) + + keyword = params[:keyword].to_s.strip + if keyword.present? + like_sql = 'subjects.name LIKE :keyword OR CONCAT(users.lastname, users.firstname) LIKE :keyword' + subjects = subjects.joins(:user).where(like_sql, keyword: "%#{keyword}%") + end + + @subjects = paginate(subjects.includes(:user)) + end + private def current_laboratory diff --git a/app/controllers/admins/laboratory_shixuns_controller.rb b/app/controllers/admins/laboratory_shixuns_controller.rb new file mode 100644 index 000000000..f5c7d5ef3 --- /dev/null +++ b/app/controllers/admins/laboratory_shixuns_controller.rb @@ -0,0 +1,41 @@ +class Admins::LaboratoryShixunsController < Admins::BaseController + helper_method :current_laboratory, :current_laboratory_shixun + + def index + laboratory_shixuns = Admins::LaboratoryShixunQuery.call(current_laboratory, params) + @laboratory_shixuns = paginate laboratory_shixuns.includes(shixun: %i[tag_repertoires user]) + end + + def create + shixun_ids = Array.wrap(params[:shixun_ids]) + shixun_ids = Shixun.where(id: shixun_ids).pluck(:id) + exist_shixun_id = current_laboratory.laboratory_shixuns.where(shixun_id: shixun_ids).pluck(:shixun_id) + + LaboratoryShixun.bulk_insert(*%i[shixun_id laboratory_id created_at updated_at]) do |worker| + (shixun_ids - exist_shixun_id).each do |shixun_id| + worker.add(shixun_id: shixun_id, laboratory_id: current_laboratory.id) + end + end + render_ok + end + + def homepage + current_laboratory_shixun.update!(homepage: true) + render_ok + end + + def cancel_homepage + current_laboratory_shixun.update!(homepage: false) + render_ok + end + + private + + def current_laboratory + @_current_laboratory ||= Laboratory.find(params[:laboratory_id]) + end + + def current_laboratory_shixun + @_current_laboratory_shixun ||= current_laboratory.laboratory_shixuns.find(params[:id]) + end +end \ No newline at end of file diff --git a/app/controllers/admins/laboratory_subjects_controller.rb b/app/controllers/admins/laboratory_subjects_controller.rb new file mode 100644 index 000000000..d6dc4af9d --- /dev/null +++ b/app/controllers/admins/laboratory_subjects_controller.rb @@ -0,0 +1,43 @@ +class Admins::LaboratorySubjectsController < Admins::BaseController + helper_method :current_laboratory, :current_laboratory_subject + + def index + laboratory_subjects = Admins::LaboratorySubjectQuery.call(current_laboratory, params) + + includes_tables = { subject: [:repertoire, :subject_level_system, user: {user_extension: :school}] } + @laboratory_subjects = paginate(laboratory_subjects.includes(includes_tables)) + end + + def create + subject_ids = Array.wrap(params[:subject_ids]) + subject_ids = Subject.where(id: subject_ids).pluck(:id) + exist_subject_id = current_laboratory.laboratory_subjects.where(subject_id: subject_ids).pluck(:subject_id) + + LaboratorySubject.bulk_insert(*%i[subject_id laboratory_id created_at updated_at]) do |worker| + (subject_ids - exist_subject_id).each do |subject_id| + worker.add(subject_id: subject_id, laboratory_id: current_laboratory.id) + end + end + render_ok + end + + def homepage + current_laboratory_subject.update!(homepage: true) + render_ok + end + + def cancel_homepage + current_laboratory_subject.update!(homepage: false) + render_ok + end + + private + + def current_laboratory + @_current_laboratory ||= Laboratory.find(params[:laboratory_id]) + end + + def current_laboratory_subject + @_current_laboratory_subject ||= current_laboratory.laboratory_subjects.find(params[:id]) + end +end \ No newline at end of file diff --git a/app/controllers/concerns/laboratory_helper.rb b/app/controllers/concerns/laboratory_helper.rb index 157957b03..870a1d90e 100644 --- a/app/controllers/concerns/laboratory_helper.rb +++ b/app/controllers/concerns/laboratory_helper.rb @@ -2,6 +2,8 @@ module LaboratoryHelper extend ActiveSupport::Concern included do + before_action :setup_laboratory + helper_method :current_laboratory helper_method :default_setting end @@ -17,4 +19,8 @@ module LaboratoryHelper def default_setting @_default_setting ||= LaboratorySetting.find_by(laboratory_id: 1) end + + def setup_laboratory + Laboratory.current = 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 05c3500ee..e2b78ee4b 100644 --- a/app/controllers/shixuns_controller.rb +++ b/app/controllers/shixuns_controller.rb @@ -335,6 +335,9 @@ class ShixunsController < ApplicationController end end end + + # 将实训标志为该云上实验室建立 + Laboratory.current.laboratory_shixuns.create!(shixun: @shixun, ownership: true) rescue Exception => e uid_logger_error("copy shixun failed ##{e.message}") # 删除版本库 @@ -430,6 +433,9 @@ class ShixunsController < ApplicationController GitService.add_repository(repo_path: repo_path) # todo: 为什么保存的时候要去除后面的.git呢?? @shixun.update_column(:repo_name, repo_path.split(".")[0]) + + # 将实训标志为该云上实验室建立 + Laboratory.current.laboratory_shixuns.create!(shixun: @shixun, ownership: true) rescue Exception => e uid_logger_error(e.message) tip_exception("实训创建失败") diff --git a/app/controllers/subjects_controller.rb b/app/controllers/subjects_controller.rb index cbedf74b2..9c6980b69 100644 --- a/app/controllers/subjects_controller.rb +++ b/app/controllers/subjects_controller.rb @@ -117,6 +117,9 @@ class SubjectsController < ApplicationController @subject.user_id = current_user.id @subject.save! @subject.subject_members.create!(role: 1, user_id: current_user.id) + + # 将实践课程标记为该云上实验室建立 + Laboratory.current.laboratory_subjects.create!(subject: @subject, ownership: true) rescue Exception => e uid_logger_error(e.message) tip_exception("实训路径创建失败") diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index c666f43fc..be633b2cc 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -414,6 +414,14 @@ module ApplicationHelper m_t&.include?("src=\"") ? m_t&.gsub("src=\"","src=\"#{origin_url}") : m_t end + def shixun_status_class(shixun) + case shixun.status + when 0 then 'text-info' + when 1 then 'text-warning' + when 2 then 'text-success' + when 3 then 'text-secondary' + end + end end diff --git a/app/models/laboratory.rb b/app/models/laboratory.rb index 35965dc0d..ff8f89c5e 100644 --- a/app/models/laboratory.rb +++ b/app/models/laboratory.rb @@ -8,6 +8,9 @@ class Laboratory < ApplicationRecord has_many :portal_images, dependent: :destroy + has_many :laboratory_shixuns, dependent: :destroy + has_many :laboratory_subjects, dependent: :destroy + validates :identifier, uniqueness: { case_sensitive: false }, allow_nil: true delegate :name, :navbar, :footer, :login_logo_url, :nav_logo_url, :tab_logo_url, :default_navbar, to: :laboratory_setting @@ -27,4 +30,12 @@ class Laboratory < ApplicationRecord find_by_identifier(subdomain) end + + def self.current=(laboratory) + Thread.current[:current_laboratory] = laboratory + end + + def self.current + Thread.current[:current_laboratory] ||= Laboratory.find(1) + end end \ No newline at end of file diff --git a/app/models/laboratory_shixun.rb b/app/models/laboratory_shixun.rb new file mode 100644 index 000000000..cc4a861eb --- /dev/null +++ b/app/models/laboratory_shixun.rb @@ -0,0 +1,4 @@ +class LaboratoryShixun < ApplicationRecord + belongs_to :laboratory + belongs_to :shixun +end \ No newline at end of file diff --git a/app/models/laboratory_subject.rb b/app/models/laboratory_subject.rb new file mode 100644 index 000000000..fa5862712 --- /dev/null +++ b/app/models/laboratory_subject.rb @@ -0,0 +1,4 @@ +class LaboratorySubject < ApplicationRecord + belongs_to :laboratory + belongs_to :subject +end \ No newline at end of file diff --git a/app/models/shixun.rb b/app/models/shixun.rb index 103c8b68f..c1782fe03 100644 --- a/app/models/shixun.rb +++ b/app/models/shixun.rb @@ -51,6 +51,8 @@ class Shixun < ApplicationRecord # 实训审核记录 has_many :shixun_reviews, -> {order("shixun_reviews.created_at desc")}, :dependent => :destroy + has_many :laboratory_shixuns, dependent: :destroy + scope :search_by_name, ->(keyword) { where("name like ? or description like ? ", "%#{keyword}%", "%#{keyword}%") } diff --git a/app/models/subject.rb b/app/models/subject.rb index e8f592419..28c45e4ba 100644 --- a/app/models/subject.rb +++ b/app/models/subject.rb @@ -24,6 +24,8 @@ class Subject < ApplicationRecord # 开放课堂 has_many :courses, -> { where("is_delete = 0").order("courses.created_at ASC") } + has_many :laboratory_subjects, dependent: :destroy + validates :name, length: { maximum: 60 } validates :description, length: { maximum: 8000 } validates :learning_notes, length: { maximum: 2000 } diff --git a/app/queries/admins/laboratory_shixun_query.rb b/app/queries/admins/laboratory_shixun_query.rb new file mode 100644 index 000000000..d489aed21 --- /dev/null +++ b/app/queries/admins/laboratory_shixun_query.rb @@ -0,0 +1,36 @@ +class Admins::LaboratoryShixunQuery < ApplicationQuery + attr_reader :laboratory, :params + + def initialize(laboratory, params) + @laboratory = laboratory + @params = params + end + + def call + laboratory_shixuns = laboratory.laboratory_shixuns.joins(:shixun) + + keyword = params[:keyword].to_s.strip + if keyword.present? + like_sql = 'shixuns.name LIKE :keyword OR CONCAT(users.lastname, users.firstname) LIKE :keyword' + laboratory_shixuns = laboratory_shixuns.joins(shixun: :user).where(like_sql, keyword: "%#{keyword}%") + end + + # 实训状态 + laboratory_shixuns = laboratory_shixuns.where(shixuns: { status: params[:status] }) if params[:status].present? + + # 技术平台 + if params[:tag_id].present? + laboratory_shixuns = laboratory_shixuns.joins(shixun: :shixun_mirror_repositories) + .where(shixun_mirror_repositories: { mirror_repository_id: params[:tag_id] }) + end + + # 首页展示、单位自建 + %i[homepage ownership].each do |column| + if params[column].present? && params[column].to_s == 'true' + laboratory_shixuns = laboratory_shixuns.where(column => true) + end + end + + laboratory_shixuns + end +end \ No newline at end of file diff --git a/app/queries/admins/laboratory_subject_query.rb b/app/queries/admins/laboratory_subject_query.rb new file mode 100644 index 000000000..316ea9743 --- /dev/null +++ b/app/queries/admins/laboratory_subject_query.rb @@ -0,0 +1,36 @@ +class Admins::LaboratorySubjectQuery < ApplicationQuery + attr_reader :laboratory, :params + + def initialize(laboratory, params) + @laboratory = laboratory + @params = params + end + + def call + laboratory_subjects = laboratory.laboratory_subjects.joins(:subject) + + keyword = params[:keyword].to_s.strip + if keyword.present? + like_sql = 'subjects.name LIKE :keyword OR CONCAT(users.lastname, users.firstname) LIKE :keyword' + laboratory_subjects = laboratory_subjects.joins(subject: :user).where(like_sql, keyword: "%#{keyword}%") + end + + # 状态 + laboratory_subjects = laboratory_subjects.where(subjects: { status: params[:status] }) if params[:status].present? + + # 创建者单位 + if params[:school_id].present? + laboratory_subjects = laboratory_subjects.joins(subjects: { user: :user_extension }) + .where(user_extensions: { school_id: params[:school_id] }) + end + + # 首页展示、单位自建 + %i[homepage ownership].each do |column| + if params[column].present? && params[column].to_s == 'true' + laboratory_subjects = laboratory_subjects.where(column => true) + end + end + + laboratory_subjects + end +end \ No newline at end of file diff --git a/app/queries/admins/shixun_settings_query.rb b/app/queries/admins/shixun_settings_query.rb index 32cfdb8bf..ab871b58e 100644 --- a/app/queries/admins/shixun_settings_query.rb +++ b/app/queries/admins/shixun_settings_query.rb @@ -11,6 +11,9 @@ class Admins::ShixunSettingsQuery < ApplicationQuery def call all_shixuns = Shixun.all + + all_shixuns = all_shixuns.where(id: params[:id]) if params[:id].present? + status = case params[:status] when "editing" then [0] diff --git a/app/queries/admins/subject_query.rb b/app/queries/admins/subject_query.rb index d5b60b8b6..935f52bb3 100644 --- a/app/queries/admins/subject_query.rb +++ b/app/queries/admins/subject_query.rb @@ -12,6 +12,8 @@ class Admins::SubjectQuery < ApplicationQuery def call subjects = Subject.all + subjects = subjects.where(id: params[:id]) if params[:id].present? + # 状态过滤 status = case params[:status].to_s.strip diff --git a/app/views/admins/laboratories/shared/_laboratory_item.html.erb b/app/views/admins/laboratories/shared/_laboratory_item.html.erb index 92b8ef9a9..abfcda349 100644 --- a/app/views/admins/laboratories/shared/_laboratory_item.html.erb +++ b/app/views/admins/laboratories/shared/_laboratory_item.html.erb @@ -41,6 +41,9 @@