diff --git a/.ipynb_checkpoints/未命名-checkpoint.ipynb b/.ipynb_checkpoints/未命名-checkpoint.ipynb new file mode 100644 index 000000000..2fd64429b --- /dev/null +++ b/.ipynb_checkpoints/未命名-checkpoint.ipynb @@ -0,0 +1,6 @@ +{ + "cells": [], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/.ipynb_checkpoints/未命名1-checkpoint.ipynb b/.ipynb_checkpoints/未命名1-checkpoint.ipynb new file mode 100644 index 000000000..2fd64429b --- /dev/null +++ b/.ipynb_checkpoints/未命名1-checkpoint.ipynb @@ -0,0 +1,6 @@ +{ + "cells": [], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Gemfile.lock b/Gemfile.lock deleted file mode 100644 index 4b7902353..000000000 --- a/Gemfile.lock +++ /dev/null @@ -1,426 +0,0 @@ -PATH - remote: lib/gitlab-cli - specs: - gitlab (3.2.0) - httparty - terminal-table - -GEM - remote: https://gems.ruby-china.com/ - specs: - aasm (5.0.5) - concurrent-ruby (~> 1.0) - actioncable (5.2.1) - actionpack (= 5.2.1) - nio4r (~> 2.0) - websocket-driver (>= 0.6.1) - actionmailer (5.2.1) - actionpack (= 5.2.1) - actionview (= 5.2.1) - activejob (= 5.2.1) - mail (~> 2.5, >= 2.5.4) - rails-dom-testing (~> 2.0) - actionpack (5.2.1) - actionview (= 5.2.1) - activesupport (= 5.2.1) - rack (~> 2.0) - rack-test (>= 0.6.3) - rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (5.2.1) - activesupport (= 5.2.1) - builder (~> 3.1) - erubi (~> 1.4) - rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.0, >= 1.0.3) - active_decorator (1.2.0) - activejob (5.2.1) - activesupport (= 5.2.1) - globalid (>= 0.3.6) - activemodel (5.2.1) - activesupport (= 5.2.1) - activerecord (5.2.1) - activemodel (= 5.2.1) - activesupport (= 5.2.1) - arel (>= 9.0) - activestorage (5.2.1) - actionpack (= 5.2.1) - activerecord (= 5.2.1) - marcel (~> 0.3.1) - activesupport (5.2.1) - concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (>= 0.7, < 2) - minitest (~> 5.1) - tzinfo (~> 1.1) - acts-as-taggable-on (6.0.0) - activerecord (~> 5.0) - addressable (2.7.0) - public_suffix (>= 2.0.2, < 5.0) - archive-zip (0.11.0) - io-like (~> 0.3.0) - arel (9.0.0) - autoprefixer-rails (9.6.1) - execjs - awesome_print (1.8.0) - axlsx (3.0.0.pre) - htmlentities (~> 4.3, >= 4.3.4) - mimemagic (~> 0.3) - nokogiri (~> 1.8, >= 1.8.2) - rubyzip (~> 1.2, >= 1.2.1) - axlsx_rails (0.5.2) - actionpack (>= 3.1) - axlsx (>= 2.0.1) - bindex (0.5.0) - bootsnap (1.3.1) - msgpack (~> 1.0) - bootstrap (4.3.1) - autoprefixer-rails (>= 9.1.0) - popper_js (>= 1.14.3, < 2) - sassc-rails (>= 2.0.0) - builder (3.2.3) - bulk_insert (1.7.0) - activerecord (>= 3.2.0) - byebug (10.0.2) - capybara (3.5.1) - addressable - mini_mime (>= 0.1.3) - nokogiri (~> 1.8) - rack (>= 1.6.0) - rack-test (>= 0.6.3) - xpath (~> 3.1) - childprocess (0.9.0) - ffi (~> 1.0, >= 1.0.11) - chromedriver-helper (1.2.0) - archive-zip (~> 0.10) - nokogiri (~> 1.8) - chunky_png (1.3.10) - concurrent-ruby (1.0.5) - connection_pool (2.2.2) - crass (1.0.4) - diff-lcs (1.3) - diffy (3.3.0) - elasticsearch (7.2.0) - elasticsearch-api (= 7.2.0) - elasticsearch-transport (= 7.2.0) - elasticsearch-api (7.2.0) - multi_json - elasticsearch-transport (7.2.0) - faraday - multi_json - enumerize (2.3.1) - activesupport (>= 3.2) - erubi (1.7.1) - execjs (2.7.0) - faraday (0.15.4) - multipart-post (>= 1.2, < 3) - ffi (1.9.25) - font-awesome-sass (4.7.0) - sass (>= 3.2) - globalid (0.4.1) - activesupport (>= 4.2.0) - grape-entity (0.7.1) - activesupport (>= 4.0) - multi_json (>= 1.3.2) - hashie (3.5.7) - htmlentities (4.3.4) - httparty (0.16.2) - multi_xml (>= 0.5.2) - i18n (1.1.0) - concurrent-ruby (~> 1.0) - io-like (0.3.0) - jbuilder (2.7.0) - activesupport (>= 4.2.0) - multi_json (>= 1.2) - jquery-rails (4.3.5) - rails-dom-testing (>= 1, < 3) - railties (>= 4.2.0) - thor (>= 0.14, < 2.0) - jwt (2.1.0) - kaminari (1.1.1) - activesupport (>= 4.1.0) - kaminari-actionview (= 1.1.1) - kaminari-activerecord (= 1.1.1) - kaminari-core (= 1.1.1) - kaminari-actionview (1.1.1) - actionview - kaminari-core (= 1.1.1) - kaminari-activerecord (1.1.1) - activerecord - kaminari-core (= 1.1.1) - kaminari-core (1.1.1) - listen (3.1.5) - rb-fsevent (~> 0.9, >= 0.9.4) - rb-inotify (~> 0.9, >= 0.9.7) - ruby_dep (~> 1.2) - loofah (2.2.2) - crass (~> 1.0.2) - nokogiri (>= 1.5.9) - mail (2.7.0) - mini_mime (>= 0.1.1) - marcel (0.3.2) - mimemagic (~> 0.3.2) - method_source (0.9.0) - mimemagic (0.3.2) - mini_mime (1.0.0) - mini_portile2 (2.3.0) - minitest (5.11.3) - msgpack (1.2.4) - multi_json (1.13.1) - multi_xml (0.6.0) - multipart-post (2.0.0) - mustermann (1.0.3) - mysql2 (0.5.2) - nio4r (2.3.1) - nokogiri (1.8.4) - mini_portile2 (~> 2.3.0) - oauth2 (1.4.1) - faraday (>= 0.8, < 0.16.0) - jwt (>= 1.0, < 3.0) - multi_json (~> 1.3) - multi_xml (~> 0.5) - rack (>= 1.2, < 3) - omniauth (1.9.0) - hashie (>= 3.4.6, < 3.7.0) - rack (>= 1.6.2, < 3) - omniauth-oauth2 (1.6.0) - oauth2 (~> 1.1) - omniauth (~> 1.9) - pdfkit (0.8.4.1) - popper_js (1.14.5) - public_suffix (4.0.1) - puma (3.12.0) - rack (2.0.5) - rack-cors (1.0.2) - rack-protection (2.0.5) - rack - rack-test (1.1.0) - rack (>= 1.0, < 3) - rails (5.2.1) - actioncable (= 5.2.1) - actionmailer (= 5.2.1) - actionpack (= 5.2.1) - actionview (= 5.2.1) - activejob (= 5.2.1) - activemodel (= 5.2.1) - activerecord (= 5.2.1) - activestorage (= 5.2.1) - activesupport (= 5.2.1) - bundler (>= 1.3.0) - railties (= 5.2.1) - sprockets-rails (>= 2.0.0) - rails-dom-testing (2.0.3) - activesupport (>= 4.2.0) - nokogiri (>= 1.6) - rails-html-sanitizer (1.0.4) - loofah (~> 2.2, >= 2.2.2) - rails-i18n (5.1.3) - i18n (>= 0.7, < 2) - railties (>= 5.0, < 6) - railties (5.2.1) - actionpack (= 5.2.1) - activesupport (= 5.2.1) - method_source - rake (>= 0.8.7) - thor (>= 0.19.0, < 2.0) - rake (12.3.1) - rb-fsevent (0.10.3) - rb-inotify (0.9.10) - ffi (>= 0.5.0, < 2) - rchardet (1.8.0) - redcarpet (3.4.0) - redis (4.1.0) - redis-actionpack (5.0.2) - actionpack (>= 4.0, < 6) - redis-rack (>= 1, < 3) - redis-store (>= 1.1.0, < 2) - redis-activesupport (5.0.7) - activesupport (>= 3, < 6) - redis-store (>= 1.3, < 2) - redis-rack (2.0.5) - rack (>= 1.5, < 3) - redis-store (>= 1.2, < 2) - redis-rails (5.0.2) - redis-actionpack (>= 5.0, < 6) - redis-activesupport (>= 5.0, < 6) - redis-store (>= 1.2, < 2) - redis-store (1.6.0) - redis (>= 2.2, < 5) - roo (2.8.2) - nokogiri (~> 1) - rubyzip (>= 1.2.1, < 2.0.0) - roo-xls (1.2.0) - nokogiri - roo (>= 2.0.0, < 3) - spreadsheet (> 0.9.0) - rqrcode (0.10.1) - chunky_png (~> 1.0) - rqrcode_png (0.1.5) - chunky_png - rqrcode - rspec-core (3.8.0) - rspec-support (~> 3.8.0) - rspec-expectations (3.8.1) - diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.8.0) - rspec-mocks (3.8.0) - diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.8.0) - rspec-rails (3.8.0) - actionpack (>= 3.0) - activesupport (>= 3.0) - railties (>= 3.0) - rspec-core (~> 3.8.0) - rspec-expectations (~> 3.8.0) - rspec-mocks (~> 3.8.0) - rspec-support (~> 3.8.0) - rspec-support (3.8.0) - ruby-ole (1.2.12.2) - ruby_dep (1.5.0) - rubyzip (1.2.1) - sass (3.5.7) - sass-listen (~> 4.0.0) - sass-listen (4.0.0) - rb-fsevent (~> 0.9, >= 0.9.4) - rb-inotify (~> 0.9, >= 0.9.7) - sass-rails (5.0.7) - railties (>= 4.0.0, < 6) - sass (~> 3.1) - sprockets (>= 2.8, < 4.0) - sprockets-rails (>= 2.0, < 4.0) - tilt (>= 1.1, < 3) - sassc (2.0.1) - ffi (~> 1.9) - rake - sassc-rails (2.1.2) - railties (>= 4.0.0) - sassc (>= 2.0) - sprockets (> 3.0) - sprockets-rails - tilt - searchkick (3.1.3) - activemodel (>= 4.2) - elasticsearch (>= 5) - hashie - selenium-webdriver (3.14.0) - childprocess (~> 0.5) - rubyzip (~> 1.2) - sidekiq (5.2.7) - connection_pool (~> 2.2, >= 2.2.2) - rack (>= 1.5.0) - rack-protection (>= 1.5.0) - redis (>= 3.3.5, < 5) - simple_form (4.1.0) - actionpack (>= 5.0) - activemodel (>= 5.0) - simple_xlsx_reader (1.0.4) - nokogiri - rubyzip - sinatra (2.0.5) - mustermann (~> 1.0) - rack (~> 2.0) - rack-protection (= 2.0.5) - tilt (~> 2.0) - spreadsheet (1.2.3) - ruby-ole (>= 1.0) - spring (2.0.2) - activesupport (>= 4.2) - spring-watcher-listen (2.0.1) - listen (>= 2.7, < 4.0) - spring (>= 1.2, < 3.0) - sprockets (3.7.2) - concurrent-ruby (~> 1.0) - rack (> 1, < 3) - sprockets-rails (3.2.1) - actionpack (>= 4.0) - activesupport (>= 4.0) - sprockets (>= 3.0.0) - terminal-table (1.8.0) - unicode-display_width (~> 1.1, >= 1.1.1) - thor (0.20.0) - thread_safe (0.3.6) - tilt (2.0.8) - turbolinks (5.2.0) - turbolinks-source (~> 5.2) - turbolinks-source (5.2.0) - tzinfo (1.2.5) - thread_safe (~> 0.1) - uglifier (4.1.17) - execjs (>= 0.3.0, < 3) - unicode-display_width (1.4.0) - web-console (3.6.2) - actionview (>= 5.0) - activemodel (>= 5.0) - bindex (>= 0.4.0) - railties (>= 5.0) - websocket-driver (0.7.0) - websocket-extensions (>= 0.1.0) - websocket-extensions (0.1.3) - wkhtmltopdf-binary (0.12.4) - xpath (3.1.0) - nokogiri (~> 1.8) - -PLATFORMS - ruby - -DEPENDENCIES - aasm - active_decorator - acts-as-taggable-on (~> 6.0) - awesome_print - axlsx (~> 3.0.0.pre) - axlsx_rails (~> 0.5.2) - bootsnap (>= 1.1.0) - bootstrap (~> 4.3.1) - bulk_insert - byebug - capybara (>= 2.15, < 4.0) - chromedriver-helper - diffy - enumerize - faraday (~> 0.15.4) - font-awesome-sass (= 4.7.0) - gitlab! - grape-entity (~> 0.7.1) - jbuilder (~> 2.5) - jquery-rails - kaminari (~> 1.1, >= 1.1.1) - listen (>= 3.0.5, < 3.2) - mysql2 (>= 0.4.4, < 0.6.0) - oauth2 - omniauth (~> 1.9.0) - omniauth-oauth2 (~> 1.6.0) - pdfkit - puma (~> 3.11) - rack-cors - rails (~> 5.2.0) - rails-i18n (~> 5.1) - rchardet (~> 1.8) - redcarpet (~> 3.4) - redis-rails - roo-xls - rqrcode (~> 0.10.1) - rqrcode_png - rspec-rails (~> 3.8) - ruby-ole - rubyzip - sass-rails (~> 5.0) - searchkick - selenium-webdriver - sidekiq - simple_form - simple_xlsx_reader - sinatra - spreadsheet - spring - spring-watcher-listen (~> 2.0.0) - turbolinks (~> 5) - tzinfo-data - uglifier (>= 1.3.0) - web-console (>= 3.3.0) - wkhtmltopdf-binary - -RUBY VERSION - ruby 2.3.7p456 - -BUNDLED WITH - 1.17.3 diff --git a/app/assets/javascripts/admins/laboratories/edit.js b/app/assets/javascripts/admins/laboratories/edit.js index 63b26bbe0..5c2e87681 100644 --- a/app/assets/javascripts/admins/laboratories/edit.js +++ b/app/assets/javascripts/admins/laboratories/edit.js @@ -3,7 +3,7 @@ $(document).on('turbolinks:load', function() { var $container = $('.edit-laboratory-setting-container'); var $form = $container.find('.edit_laboratory'); - $('.logo-item-left').on("change", 'input[type="file"]', function () { + $('.logo-item-left, .banner-item-bottom').on("change", 'input[type="file"]', function () { var $fileInput = $(this); var file = this.files[0]; var imageType = /image.*/; diff --git a/app/assets/javascripts/admins/laboratory_subjects/index.js b/app/assets/javascripts/admins/laboratory_subjects/index.js index b5fa3bffb..04e82bb2a 100644 --- a/app/assets/javascripts/admins/laboratory_subjects/index.js +++ b/app/assets/javascripts/admins/laboratory_subjects/index.js @@ -85,8 +85,8 @@ $(document).on('turbolinks:load', function() { $subjectSelect.select2({ theme: 'bootstrap4', placeholder: '请输入课程名称/创建者检索', - multiple: true, - closeOnSelect: false, + multiple: false, + closeOnSelect: true, ajax: { delay: 500, url: '/admins/laboratories/' + laboratoryId + '/subjects_for_select', @@ -132,7 +132,7 @@ $(document).on('turbolinks:load', function() { method: 'POST', dataType: 'json', url: '/admins/laboratories/' + laboratoryId + '/laboratory_subjects', - data: { subject_ids: subjectIds }, + data: { subject_id: subjectIds }, success: function(){ show_success_flash(); window.location.reload(); diff --git a/app/assets/javascripts/cooperative/competition_settings/index.js b/app/assets/javascripts/cooperative/competition_settings/index.js new file mode 100644 index 000000000..66a73cbb3 --- /dev/null +++ b/app/assets/javascripts/cooperative/competition_settings/index.js @@ -0,0 +1,803 @@ +$(document).on('turbolinks:load', function(){ + if ($('body.cooperative-competition-settings-index-page').length > 0) { + + var dateOptions = { + autoclose: true, + language: 'zh-CN', + format: 'yyyy-mm-dd', + startDate: '2017-04-01' + }; + + var timeOptions = { + autoclose: 1, + language: 'zh-CN', + format: 'yyyy-mm-dd hh:ii', + minuteStep: 30 + }; + + var defineDateRangeSelect = function (element) { + var options = $.extend({inputs: $(element).find('.start-date, .end-date')}, dateOptions); + $(element).datepicker(options); + + $(element).find('.start-date').datepicker().on('changeDate', function (e) { + $(element).find('.end-date').datepicker('setStartDate', e.date); + }); + }; + $(".competition-start-end-date .start-date").datetimepicker(timeOptions); + + $(".competition-start-end-date .end-date").datetimepicker(timeOptions); + + $(".nav-setting-form .enroll_end_time").datetimepicker(timeOptions); + + $(".stage-update-form .section-start-time").datetimepicker(timeOptions); + $(".stage-update-form .section-end-time").datetimepicker(timeOptions); + + defineDateRangeSelect('.teaching-mode-date'); + // defineTimeRangeSelect('.competition-start-end-date'); + + var $basicForm = $('form.basic-setting-form'); + + $basicForm.validate({ + errorElement: 'span', + errorClass: 'danger text-danger', + rules: { + name: "required", + subTitle: "required", + startTime: "required", + endTime: "required", + mode: "required", + identifier: "required" + } + }); + + // 保存按钮 + $basicForm.on('click', ".submit-btn", function () { + $basicForm.find('.submit-btn').attr('disabled', 'disabled'); + $basicForm.find('.error').html(''); + var valid = $basicForm.valid(); + + if ($("input[name='mode']:checked").val() == 2) { + var $courseId = $("input[name='course_id']"); + if ($courseId.val() === undefined || $courseId.val().length === 0) { + $courseId.addClass('danger text-danger'); + valid = false; + } else { + $courseId.removeClass('danger text-danger'); + } + } else if ($("input[name='mode']:checked").val() == 3) { + var $techStartTime = $("input[name='teach_start_time']"); + var $techEndTime = $("input[name='teach_end_time']"); + if ($techStartTime.val() === undefined || $techStartTime.val().length === 0) { + $techStartTime.addClass('danger text-danger'); + valid = false; + } else { + $techStartTime.removeClass('danger text-danger'); + } + + if ($techEndTime.val() === undefined || $techEndTime.val().length === 0) { + $techEndTime.addClass('danger text-danger'); + valid = false; + } else { + $techEndTime.removeClass('danger text-danger'); + } + } else { + $("input[name='course_id']").removeClass('danger text-danger'); + $("input[name='teach_start_time']").removeClass('danger text-danger'); + $("input[name='teach_end_time']").removeClass('danger text-danger'); + } + + if (!valid) return; + $.ajax({ + method: 'POST', + dataType: 'json', + url: $basicForm.attr('action'), + data: new FormData($basicForm[0]), + processData: false, + contentType: false, + success: function (data) { + $.notify({message: '保存成功'}); + // window.location.reload(); + }, + error: function (res) { + var data = res.responseJSON; + $basicForm.find('.error').html(data.message); + }, + complete: function () { + $basicForm.find('.submit-btn').attr('disabled', false); + } + }); + }); + + var selectOptions = { + theme: 'bootstrap4', + placeholder: '请输入要添加的单位名称', + multiple: true, + 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 || item.text; + }, + templateSelection: function(item){ + return item.name || item.text; + } + }; + + $('.sponsor-select').select2(selectOptions); + $('.allow-school-select').select2(selectOptions); + + $('.manager-select').select2({ + theme: 'bootstrap4', + placeholder: '请输入要添加的管理员姓名', + multiple: true, + minimumInputLength: 1, + ajax: { + delay: 500, + url: '/cooperative/users', + dataType: 'json', + data: function(params){ + return { keyword: params.term }; + }, + processResults: function(data){ + return { results: data.users } + } + }, + templateResult: function (item) { + if(!item.id || item.id === '') return item.text; + return $("
" + item.real_name + "" + item.school_name + "" + item.hidden_phone + "
"); + }, + templateSelection: function(item){ + if (item.id) { + } + return item.real_name || item.text; + } + }); + + + // 排行榜 + //链接 + $(".nav-setting-form").on("click",".add_linkBtn",function () { + var length=$(".nav-setting-form").find(".linkFormItem").length + 1; + var html='
\n' + + '
\n' + + ' \n' + + '
\n' + + '
\n' + + '
\n' + + '
\n' + + '
\n' + + ' +\n' + + ' ×\n' + + '
'; + $(this).parents(".linkFormItem").after(html); + }); + + $(".nav-setting-form").on("click", ".del_linkBtn", function () { + $(this).parents(".linkFormItem").remove(); + }); + + //有关报名要求 + $(".addRequireBtn").on("click",function () { + var length=$("#requireForm").find(".requireForm_item").length + 1; + var html='
\n' + + '
  
\n' + + '
\n' + + ' \n' + + '
\n' + + ' ~\n' + + '
\n' + + ' \n' + + '
\n' + + ' \n' + + '
\n' + + ' \n' + + '
\n' + + '
\n' + + ' \n' + + '
\n' + + '
\n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + '
\n' + + '
'; + $("#requireForm").append(html); + }); + + $("#requireForm").on("click",".delRequrieBtn",function () { + $(this).parents(".requireForm_item").remove(); + }); + + $('.nav-setting-form').on('click', '.module_hidden', function(){ + var checkEle = $(this); + if (checkEle.is(':checked')) { + checkEle.prev().val(0); + } else { + checkEle.prev().val(1); + } + }); + + $('.competition-staff-settings').on('click', '.mutiple-limited-radio', function(){ + var radio = $(this); + if (radio.is(':checked')) { + radio.parent().parent().siblings().find('.mutiple-limited-radio').attr('checked', false) + } else { + radio.parent().parent().siblings().find('.mutiple-limited-radio').attr('checked', true) + } + }); + + var $navForm = $('form.nav-setting-form'); + $navForm.on('click', ".submit-btn", function () { + $navForm.find('.submit-btn').attr('disabled', 'disabled'); + $navForm.find('.error').html(''); + var valid = $navForm.valid(); + + if (!valid) return; + $.ajax({ + method: 'POST', + dataType: 'json', + url: $navForm.attr('action'), + data: new FormData($navForm[0]), + processData: false, + contentType: false, + success: function (data) { + $.notify({message: '保存成功'}); + // window.location.reload(); + }, + error: function (res) { + var data = res.responseJSON; + $navForm.find('.error').html(data.message); + }, + complete: function () { + $navForm.find('.submit-btn').attr('disabled', false); + } + }); + }); + +// 排行榜设置 + //删除小阶段 + $("#large_panel").on("click",".small_panel_item_del",function () { + var list = $(this).parents(".small_panel"); + $(this).parents(".small_panel_item").remove(); + + for(var i=0;i < $(list).find(".subName").length;i++){ + console.log(i); + $(list).find(".subName").eq(i).html("第"+parseInt(i+1)+"阶段"); + } + }); + + // $('form.stage-update-form').validate({ + // errorElement: 'span', + // errorClass: 'danger text-danger', + // rules: { + // stage_name: "required", + // "stage[][start_time]": "required", + // "stage[][end_time]": "required", + // "stage[][mission_count]": { + // required: true, + // min: 1 + // }, + // "stage[][entry]": { + // required: true, + // min: 1 + // }, + // score_rate: { + // required: true, + // range: [0, 100] + // } + // }, + // messages: { + // "stage[][mission_count]": { + // min: ">=1" + // }, + // "stage[][entry]": { + // min: ">=1" + // }, + // } + // }); + + $('.competition-chart-setting').on('click', ".update-stage", function () { + var updateForm = $(this).parents("form"); + $(this).attr('disabled', 'disabled'); + updateForm.find('.error').html(''); + // var valid = updateForm.valid(); + var valid = true; + + var $stageName = updateForm.find('input[name="stage_name"]'); + if($stageName.val() === undefined || $stageName.val().length === 0){ + $stageName.addClass('danger text-danger'); + valid = false; + } else { + $stageName.removeClass('danger text-danger'); + } + + var $scoreRate = updateForm.find('input[name="score_rate"]'); + if($scoreRate.val() === undefined || $scoreRate.val().length === 0){ + $scoreRate.addClass('danger text-danger'); + valid = false; + } else if (parseInt($scoreRate.val()) > 100 || parseInt($scoreRate.val()) < 0) { + $scoreRate.addClass('danger text-danger'); + $scoreRate.after('0-100之间的数值'); + valid = false; + } else { + $scoreRate.removeClass('danger text-danger'); + $scoreRate.siblings().remove(); + } + + updateForm.find('input[name="stage[][start_time]"]').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'); + } + }); + + updateForm.find('input[name="stage[][end_time]"]').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'); + } + }); + + updateForm.find('input[name="stage[][mission_count]"]').each(function(i, e){ + var $ele = $(e); + var $entry = updateForm.find('input[name="stage[][entry]"]').eq(i); + if($ele.val() === undefined || $ele.val().length === 0){ + $ele.addClass('danger text-danger'); + valid = false; + } else if (parseInt($ele.val()) < 1) { + $ele.addClass('danger text-danger'); + $ele.after('大于等于1'); + valid = false; + } else if (parseInt($ele.val()) > parseInt($entry.val())) { + $ele.addClass('danger text-danger'); + $ele.after('不能大于总任务数'); + valid = false; + } else { + $ele.removeClass('danger text-danger'); + $ele.siblings().remove(); + } + }); + + updateForm.find('input[name="stage[][entry]"]').each(function(_, e){ + var $ele = $(e); + if($ele.val() === undefined || $ele.val().length === 0){ + $ele.addClass('danger text-danger'); + valid = false; + } else if (parseInt($ele.val()) < 1) { + $ele.addClass('danger text-danger'); + $ele.after('大于等于1'); + valid = false; + } else { + $ele.removeClass('danger text-danger'); + $ele.siblings().remove(); + } + }); + + updateForm.find('input[name="stage[][identifiers][]"]').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; + + updateForm.find('input[name="stage[][mission_count]"]').each(function(_, e){ + var $missionCount = $(e); + var $entryCount = $(e).parents("div.row").find('input[name="stage[][mission_count]"]'); + if(parseInt($missionCount.val()) > parseInt($entryCount.val()) ){ + $missionCount.addClass('danger text-danger'); + $missionCount.after('不能大于总任务数'); + valid = false; + } else { + $missionCount.removeClass('danger text-danger'); + $missionCount.siblings().remove(); + } + }); + + $.ajax({ + method: 'POST', + dataType: 'json', + url: updateForm.attr('action'), + data: new FormData(updateForm[0]), + processData: false, + contentType: false, + success: function (data) { + $.notify({message: '保存成功'}); + window.location.reload(); + }, + error: function (res) { + var data = res.responseJSON; + $navForm.find('.error').html(data.message); + }, + complete: function () { + $navForm.find('.submit-btn').attr('disabled', false); + } + }); + }); + + $(".competition-chart-stages").on("click", ".add-new-tab", function () { + if($(".new-stage-form").length > 0){ + alert("请先保存上一个tab"); + } else { + var count = parseInt($("#large_panel").find(".large_panel_part").length)+1; + var html = '
' + + '
\n' + + ' tab标题\n' + + '
\n' + + ' \n' + + '
\n' + + ' 总排行榜占比:\n' + + '
\n' + + ' \n' + + '
%\n' + + '
\n' + + ' 新增子阶段\n' + + '
\n' + + ' 删除\n' + + ' 保存\n' + + '
\n' + + '
\n' + + '
\n' + + ' 第1阶段\n' + + '
\n' + + '
\n' + + '
有效时间:\n' + + '
\n' + + ' \n' + + '
\n' + + ' ~\n' + + '
\n' + + ' \n' + + '
\n' + + '
总任务数:\n' + + '
\n' + + ' \n' + + '
\n' + + '
成绩来源:\n' + + '
\n' + + ' \n' + + '
\n' + + '
\n' + + '
\n' + + '
\n' + + ' 任务1\n' + + '
\n' + + ' \n' + + '
\n' + + '
\n' + + '
\n' + + ' 任务2\n' + + '
\n' + + ' \n' + + '
\n' + + '
\n' + + '
\n' + + ' 任务3\n' + + '
\n' + + ' \n' + + '
\n' + + '
\n' + + '
\n' + + '
\n' + + ' \n' + + ' 删除\n' + + ' \n' + + '
\n' + + '
'; + $("#large_panel").append(html); + + $(".stage-update-form .section-start-time").datetimepicker(timeOptions); + $(".stage-update-form .section-end-time").datetimepicker(timeOptions); + } + }); + + //新增子阶段 + $(".competition-chart-stages").on("click", ".add-task-sub", function () { + var index = $(this).parents(".large_panel_part").attr("attr_line"); + var count= 0; + + console.log("sdfsf"); + console.log($("#small_panel_"+index).find(".small_panel_item").length > 0); + + if($("#small_panel_"+index).find(".small_panel_item").length > 0){ + count = parseInt($("#small_panel_"+index).find(".small_panel_item").last().attr("count")) + 1; + + console.log($("#small_panel_"+index).find(".small_panel_item").last().attr("count")); + }else{ + count = 1; + } + + var showCount=parseInt($("#small_panel_"+index).find(".small_panel_item").length) + 1; + + + var html='
\n' + + ' 第'+showCount+'阶段\n' + + '
\n' + + '
\n' + + '
有效时间:\n' + + '
\n' + + ' \n' + + '
\n' + + ' ~\n' + + '
\n' + + ' \n' + + '
\n' + + '
总任务数:\n' + + '
\n' + + ' \n' + + '
\n' + + '
成绩来源:\n' + + '
\n' + + ' \n' + + '
\n' + + '
\n' + + '
\n'+ + '
\n' + + ' 任务1\n' + + '
\n' + + ' \n' + + '
\n' + + '
\n' + + '
\n' + + ' 任务2\n' + + '
\n' + + ' \n' + + '
\n' + + '
\n' + + '
\n' + + ' 任务3\n' + + '
\n' + + ' \n' + + '
\n' + + '
\n' + + '
\n' + + '
\n' + + ' \n' + + ' 删除\n' + + ' \n' + + '
'; + $("#small_panel_"+index).append(html); + + $(".stage-update-form .section-start-time").datetimepicker(timeOptions); + $(".stage-update-form .section-end-time").datetimepicker(timeOptions); + }); + + // 奖项设置 + var $prizeContainer = $('#competition-prize-card'); + var competitionId = $prizeContainer.data('id'); + $(document).on('prize.save.success', function(){ + $.ajax({ + method: 'GET', + url: '/cooperative/competitions/' + competitionId + '/competition_prizes', + dataType: 'script' + }) + }); + + $('.modal.cooperative-upload-file-modal').on('upload:success', function(e, data){ + var $imageElement; + if(data.suffix === '_member'){ + $imageElement = $('.prize-member-image-' + data.source_id); + } else if(data.suffix === '_team'){ + $imageElement = $('.prize-team-image-' + data.source_id); + } else { + $imageElement = $('.prize-teacher-image-' + data.source_id); + } + $imageElement.attr('src', data.url); + $imageElement.show(); + $imageElement.next().html('重新上传'); + }) + + // 生成获奖记录 + $prizeContainer.on('click', '.generate-prize-user-action', function(){ + var $link = $(this); + + var generateRequest = function(){ + return $.ajax({ + method: 'POST', + url: '/cooperative/competitions/' + competitionId + '/competition_prize_users', + dataType: 'json', + success: function(data){ + if(data && data.status === 0){ + show_success_flash(); + $link.remove(); + } else { + showErrorNotify(data.message); + } + }, + error: function(res){ + var data = res.responseJSON; + showErrorNotify(data.message); + } + }) + } + + customConfirm({ + content: '确认生成吗?', + ok: function () { + customLoading({ + ajax: generateRequest + }) + } + }) + }); + } else { + $(document).unbind('prize.save.success'); + } +}); + +//添加主办方或者开放范围 +function addSponsor(item){ + var html=''; + $(item).parents(".sponsorPanel").append(html); +} +//删除 +function del_sponsor(item){ + $(item).parents(".sponsor_label").remove(); +} + +// 小阶段修改总任务数 +function change_total(item) { + var count=parseInt($(item).val()); + + + var index = $(item).parents(".small_panel_item").attr("attr_line"); + var indexLarge = $(item).parents(".large_panel_part").attr("attr_line"); + console.log(indexLarge); + console.log(index); + + var divCount=parseInt($("#task_Input_"+index).find(".task_Input_div").length); + + + var html = ""; + if(count > divCount){ + for(var i=0;i < count-divCount ;i++){ + html+='
任务'+(divCount+i+1)+'\n' + + '
\n' + + '\n' + + '
\n' + + '
'; + } + $("#task_Input_"+index).append(html); + }else{ + var delCount = divCount - count ; + console.log(divCount); + console.log(count); + var _max=parseInt($("#task_Input_"+index).find(".task_Input_div:last").index()); + + console.log(_max); + var _get= _max - delCount; + + console.log(_get); + if(count == 0){ + $("#task_Input_"+index).empty(); + }else{ + $("#task_Input_"+index).find(".task_Input_div:gt("+_get+")").remove(); + } + + } + +} + +//删除tab +function Del_tab(item) { + $(item).parents(".large_panel_part").remove(); +} +//新增tab +function addNewTab(competition_id) { + if($(".new-stage-form").length > 0){ + alert("请先保存上一个tab"); + } else { + var count = parseInt($("#large_panel").find(".large_panel_part").length)+1; + var html = '
' + + '
\n' + + ' tab标题\n' + + '
\n' + + ' \n' + + '
\n' + + ' 总排行榜占比:\n' + + '
\n' + + ' \n' + + '
%\n' + + '
\n' + + ' 新增子阶段\n' + + '
\n' + + ' 删除\n' + + ' 保存\n' + + '
\n' + + '
\n' + + '
\n' + + ' 第1阶段\n' + + '
\n' + + '
\n' + + '
有效时间:\n' + + '
\n' + + ' \n' + + '
\n' + + ' ~\n' + + '
\n' + + ' \n' + + '
\n' + + '
总任务数:\n' + + '
\n' + + ' \n' + + '
\n' + + '
成绩来源:\n' + + '
\n' + + ' \n' + + '
\n' + + '
\n' + + '
\n' + + '
\n' + + ' 任务1\n' + + '
\n' + + ' \n' + + '
\n' + + '
\n' + + '
\n' + + ' 任务2\n' + + '
\n' + + ' \n' + + '
\n' + + '
\n' + + '
\n' + + ' 任务3\n' + + '
\n' + + ' \n' + + '
\n' + + '
\n' + + '
\n' + + '
\n' + + ' \n' + + ' 删除\n' + + ' \n' + + '
\n' + + '
'; + $("#large_panel").append(html); + } +} diff --git a/app/assets/javascripts/cooperative/competitions/index.js b/app/assets/javascripts/cooperative/competitions/index.js new file mode 100644 index 000000000..20ba586da --- /dev/null +++ b/app/assets/javascripts/cooperative/competitions/index.js @@ -0,0 +1,148 @@ +$(document).on('turbolinks:load', function() { + if ($('body.cooperative-competitions-index-page').length > 0) { + $('.modal.cooperative-upload-file-modal').on('upload:success', function(e, data){ + var $imageElement = $('.competition-image-' + data.source_id); + $imageElement.attr('src', data.url); + $imageElement.show(); + $imageElement.next().html('重新上传'); + }); + } + + $(".cooperative-competition-list-form").on("change", '.competitions-hot-select', function () { + var s_value = $(this).get(0).checked ? 1 : 0; + var json = {}; + json["hot"] = s_value; + $.ajax({ + url: "/cooperative/competitions/hot_setting", + type: "POST", + dataType:'json', + data: json, + success: function(){ + $.notify({ message: '操作成功' }); + } + }); + }); + + // ============== 新增竞赛 =============== + var $modal = $('.modal.cooperative-create-competition-modal'); + var $form = $modal.find('form.cooperative-create-competition-form'); + var $competitionNameInput = $form.find('input[name="competition_name"]'); + + $form.validate({ + errorElement: 'span', + errorClass: 'danger text-danger', + rules: { + competition_name: { + required: true + } + } + }); + + // modal ready fire + $modal.on('show.bs.modal', function () { + $competitionNameInput.val(''); + }); + + $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 $importScoreModal = $('.modal.cooperative-import-competition-score-modal'); + var $importScoreForm = $importScoreModal.find('form.cooperative-import-competition-score-form'); + var $competitionIdInput = $importScoreForm.find('input[name="competition_id"]'); + + $importScoreModal.on('show.bs.modal', function(event){ + resetFileInputFunc($importScoreModal.find('.upload-file-input')); + $importScoreModal.find('.file-names').html('选择文件'); + $importScoreModal.find('.upload-file-input').trigger('click'); + + var $link = $(event.relatedTarget); + var competitionId = $link.data('competition-id'); + $competitionIdInput.val(competitionId); + }); + + $importScoreModal.on('change', '.upload-file-input', function(e){ + var file = $(this)[0].files[0]; + $importScoreModal.find('.file-names').html(file ? file.name : '请选择文件'); + }); + + var importUserFormValid = function(){ + if($importScoreForm.find('input[name="file"]').val() == undefined || $importScoreForm.find('input[name="file"]').val().length == 0){ + $importScoreForm.find('.error').html('请选择文件'); + return false; + } + + return true; + }; + + var buildResultMessage = function(data){ + var messageHtml = "
导入结果:成功" + data.success + "条,失败"+ data.fail.length + "条
"; + + if(data.fail.length > 0){ + messageHtml += ''; + + data.fail.forEach(function(item){ + messageHtml += ''; + }); + + messageHtml += '
数据失败原因
' + item.data + '' + item.message + '
' + } + + return messageHtml; + }; + + $importScoreModal.on('click', '.submit-btn', function(){ + $importScoreForm.find('.error').html(''); + + if (importUserFormValid()) { + $('body').mLoading({ text: '正在导入...' }); + + $.ajax({ + method: 'POST', + dataType: 'json', + url: '/cooperative/import_competition_scores', + data: new FormData($importScoreForm[0]), + processData: false, + contentType: false, + success: function(data){ + $('body').mLoading('destroy'); + $importScoreModal.modal('hide'); + + showMessageModal(buildResultMessage(data), function(){ + window.location.reload(); + }); + }, + error: function(res){ + $('body').mLoading('destroy'); + var data = res.responseJSON; + $importScoreForm.find('.error').html(data.message); + } + }); + } + }); +}); + diff --git a/app/assets/javascripts/cooperative/enroll_lists/index.js b/app/assets/javascripts/cooperative/enroll_lists/index.js new file mode 100644 index 000000000..bf5e953e3 --- /dev/null +++ b/app/assets/javascripts/cooperative/enroll_lists/index.js @@ -0,0 +1,9 @@ +$(document).on('turbolinks:load', function() { + if($('body.cooperative-enroll-lists-index-page').length > 0){ + var search_form = $(".search-form"); + //导出 + $(".competition-enroll-list-form").on("click","#enroll-lists-export",function () { + window.location.href = "/cooperative/competitions/"+$(this).attr("data-competition-id")+"/enroll_lists/export.xlsx?" + search_form.serialize(); + }); + } +}); \ No newline at end of file diff --git a/app/assets/javascripts/cooperative/laboratory_settings/edit.js b/app/assets/javascripts/cooperative/laboratory_settings/edit.js index 50bb96ac9..bb6f3e3ad 100644 --- a/app/assets/javascripts/cooperative/laboratory_settings/edit.js +++ b/app/assets/javascripts/cooperative/laboratory_settings/edit.js @@ -3,7 +3,7 @@ $(document).on('turbolinks:load', function() { var $container = $('.edit-laboratory-setting-container'); var $form = $container.find('.edit_laboratory'); - $('.logo-item-left').on("change", 'input[type="file"]', function () { + $('.logo-item-left, .banner-item-bottom').on("change", 'input[type="file"]', function () { var $fileInput = $(this); var file = this.files[0]; var imageType = /image.*/; diff --git a/app/assets/javascripts/cooperative/laboratory_users/index.js b/app/assets/javascripts/cooperative/laboratory_users/index.js index 19385f003..66475b88c 100644 --- a/app/assets/javascripts/cooperative/laboratory_users/index.js +++ b/app/assets/javascripts/cooperative/laboratory_users/index.js @@ -16,7 +16,7 @@ $(document).on('turbolinks:load', function() { minimumInputLength: 1, ajax: { delay: 500, - url: '/cooperative/users', + url: '/cooperative/users/for_select', dataType: 'json', data: function(params){ return { name: params.term }; diff --git a/app/assets/javascripts/hack_user_lastest_codes.js b/app/assets/javascripts/hack_user_lastest_codes.js new file mode 100644 index 000000000..dee720fac --- /dev/null +++ b/app/assets/javascripts/hack_user_lastest_codes.js @@ -0,0 +1,2 @@ +// Place all the behaviors and hooks related to the matching controller here. +// All this logic will automatically be available in application.js. diff --git a/app/assets/javascripts/hacks.js b/app/assets/javascripts/hacks.js new file mode 100644 index 000000000..dee720fac --- /dev/null +++ b/app/assets/javascripts/hacks.js @@ -0,0 +1,2 @@ +// Place all the behaviors and hooks related to the matching controller here. +// All this logic will automatically be available in application.js. diff --git a/app/assets/stylesheets/admins/laboratories.scss b/app/assets/stylesheets/admins/laboratories.scss index 69f4586d1..9dc219f6a 100644 --- a/app/assets/stylesheets/admins/laboratories.scss +++ b/app/assets/stylesheets/admins/laboratories.scss @@ -96,5 +96,76 @@ font-size: 14px; } } + + .banner-item { + margin-bottom: 15px; + display: flex; + flex-direction: column; + + &-img { + display: block; + width: 300px; + height: 80px; + background: #f0f0f0; + } + + &-upload { + cursor: pointer; + position: absolute; + top: 0; + width: 300px; + height: 80px; + background: #F5F5F5; + border: 1px solid #E5E5E5; + + &::before { + content: ''; + position: absolute; + top: 27px; + left: 149px; + width: 2px; + height: 26px; + background: #E5E5E5; + } + + &::after { + content: ''; + position: absolute; + top: 39px; + left: 137px; + width: 26px; + height: 2px; + background: #E5E5E5; + } + } + + &-top { + margin-bottom: 10px; + } + + &-bottom { + position: relative; + width: 300px; + height: 80px; + + &.has-img { + .banner-item-upload { + display: none; + } + + &:hover { + .banner-item-upload { + display: block; + background: rgba(145, 145, 145, 0.8); + } + } + } + } + + &-title { + color: #23272B; + font-size: 14px; + } + } } } \ No newline at end of file diff --git a/app/assets/stylesheets/admins/sidebar.scss b/app/assets/stylesheets/admins/sidebar.scss index db71591ef..fe1a47def 100644 --- a/app/assets/stylesheets/admins/sidebar.scss +++ b/app/assets/stylesheets/admins/sidebar.scss @@ -86,8 +86,11 @@ align-items: center; & > img { - width: 40px; - height: auto; + //width: 40px; + //height: auto; + max-width: 130px !important; + max-height: 40px !important; + overflow: hidden; } & > .logo-label { diff --git a/app/assets/stylesheets/cooperative.scss b/app/assets/stylesheets/cooperative.scss index 56984b96b..decbd0bb4 100644 --- a/app/assets/stylesheets/cooperative.scss +++ b/app/assets/stylesheets/cooperative.scss @@ -7,6 +7,7 @@ @import "bootstrap-datepicker.standalone"; @import "jquery.mloading"; @import "jquery-confirm.min"; +@import "bootstrap-datetimepicker.min"; @import "codemirror/lib/codemirror"; @import "editormd/css/editormd.min"; diff --git a/app/assets/stylesheets/cooperative/competition_settings.scss b/app/assets/stylesheets/cooperative/competition_settings.scss new file mode 100644 index 000000000..deaf08452 --- /dev/null +++ b/app/assets/stylesheets/cooperative/competition_settings.scss @@ -0,0 +1,116 @@ +.cooperative-competition-settings-index-page { + .competition-mode-container { + .row { + height: 35px; + } + + .des-row { + height: auto; + } + + .form-control { + font-size: 14px; + } + + //.mode-input { + // input { + // width: 40%; + // } + //} + } + + .col-md-label{ + -webkit-box-flex: 0; + flex: 0 0 10%; + max-width: 10%; + min-width: 30px; + padding-right: 15px; + padding-left: 15px; + position: relative; + } + .col-md-label-s{ + -webkit-box-flex: 0; + flex: 0 0 30px; + padding-right: 15px; + padding-left: 15px; + position: relative; + } + .setBtn_s{ + height: 35px; + line-height: 20px; + } + + .sponsor_label{ + border:1px solid #4CACFF; + border-radius: 5px; + background-color: rgba(76,172,255,0.3); + color: #333; + padding:0px 4px; + height: 30px; + line-height: 30px; + float: left; + margin: 4px 5px; + + span{ + display: block; + float: left; + height: 28px; + line-height: 28px; + margin-right: 5px; + } + + a{ + font-size: 18px; + float: left; + height: 28px; + line-height: 28px; + } + } + + .large_panel{ + padding:0px 15px; + + .large_panel_part{ + border-top: 1px solid #eaeaea; + } + .large_panel_part:first-child{ + border:none; + } + + .large_panel_part >.row ,.small_panel >.row{ + border-bottom: 1px solid #eaeaea; + padding:20px 0px; + } + .small_panel{ + margin-left: 20px; + } + .row:last-child{ + border:none; + } + + .task_Input_div:nth-child(3n-2) > span.col-4{ + flex: 0 0 81px; + max-width: 81px; + } + .task_Input_div:nth-child(3n-2){ + flex: 0 0 50%; + max-width: 50%; + } + .task_Input_div:nth-child(3n-1){ + flex: 0 0 25%; + max-width: 25%; + } + .task_Input_div:nth-child(3n){ + flex: 0 0 25%; + max-width: 25%; + } + .task_Input_div:nth-child(3n) > span.col-4{ + flex: 0 0 33.3%; + max-width: 33.3%; + } + .task_Input_div:nth-child(3n) > div.col-6{ + flex: 0 0 50%; + max-width: 50%; + } + } +} \ No newline at end of file diff --git a/app/assets/stylesheets/cooperative/laboratory_settings.scss b/app/assets/stylesheets/cooperative/laboratory_settings.scss index fde0cddc3..4047abb83 100644 --- a/app/assets/stylesheets/cooperative/laboratory_settings.scss +++ b/app/assets/stylesheets/cooperative/laboratory_settings.scss @@ -72,5 +72,76 @@ font-size: 14px; } } + + .banner-item { + margin-bottom: 15px; + display: flex; + flex-direction: column; + + &-img { + display: block; + width: 300px; + height: 80px; + background: #f0f0f0; + } + + &-upload { + cursor: pointer; + position: absolute; + top: 0; + width: 300px; + height: 80px; + background: #F5F5F5; + border: 1px solid #E5E5E5; + + &::before { + content: ''; + position: absolute; + top: 27px; + left: 149px; + width: 2px; + height: 26px; + background: #E5E5E5; + } + + &::after { + content: ''; + position: absolute; + top: 39px; + left: 137px; + width: 26px; + height: 2px; + background: #E5E5E5; + } + } + + &-top { + margin-bottom: 10px; + } + + &-bottom { + position: relative; + width: 300px; + height: 80px; + + &.has-img { + .banner-item-upload { + display: none; + } + + &:hover { + .banner-item-upload { + display: block; + background: rgba(145, 145, 145, 0.8); + } + } + } + } + + &-title { + color: #23272B; + font-size: 14px; + } + } } } \ No newline at end of file diff --git a/app/assets/stylesheets/cooperative/sidebar.scss b/app/assets/stylesheets/cooperative/sidebar.scss index e943acd90..9879f2442 100644 --- a/app/assets/stylesheets/cooperative/sidebar.scss +++ b/app/assets/stylesheets/cooperative/sidebar.scss @@ -86,8 +86,11 @@ align-items: center; & > img { - width: 40px; - height: auto; + //width: 40px; + //height: auto; + max-width: 130px !important; + max-height: 40px !important; + overflow: hidden; } & > .logo-label { diff --git a/app/assets/stylesheets/hack_user_lastest_codes.scss b/app/assets/stylesheets/hack_user_lastest_codes.scss new file mode 100644 index 000000000..37e16a552 --- /dev/null +++ b/app/assets/stylesheets/hack_user_lastest_codes.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the HackUserLastestCodes controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/hacks.scss b/app/assets/stylesheets/hacks.scss new file mode 100644 index 000000000..e93f4cad4 --- /dev/null +++ b/app/assets/stylesheets/hacks.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the hacks controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/controllers/admins/base_controller.rb b/app/controllers/admins/base_controller.rb index ad56afbf7..f90c8a1ed 100644 --- a/app/controllers/admins/base_controller.rb +++ b/app/controllers/admins/base_controller.rb @@ -6,7 +6,6 @@ class Admins::BaseController < ApplicationController layout 'admin' skip_before_action :verify_authenticity_token - skip_before_action :setup_laboratory before_action :require_login, :require_admin! @@ -38,4 +37,9 @@ class Admins::BaseController < ApplicationController append_js = ERB.new(File.open(path).read).result response.body += append_js end + + # 重写此方法,防止影响超级管理员端云上实验室功能,因为那里重写了:current_laboratory方法 + def setup_laboratory + Laboratory.current = Laboratory.find_by_subdomain(request.subdomain) || Laboratory.find(1) + 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 index f9676bfd3..a65b13f59 100644 --- a/app/controllers/admins/laboratory_settings_controller.rb +++ b/app/controllers/admins/laboratory_settings_controller.rb @@ -15,6 +15,9 @@ class Admins::LaboratorySettingsController < Admins::BaseController end def form_params - params.permit(:identifier, :name, :nav_logo, :login_logo, :tab_logo, :footer, navbar: %i[name link hidden]) + params.permit(:identifier, :name, + :nav_logo, :login_logo, :tab_logo, + :subject_banner, :course_banner, :competition_banner, :moop_cases_banner, + :footer, navbar: %i[name link hidden]) 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 index 60572110c..866a20a76 100644 --- a/app/controllers/admins/laboratory_subjects_controller.rb +++ b/app/controllers/admins/laboratory_subjects_controller.rb @@ -9,15 +9,8 @@ class Admins::LaboratorySubjectsController < Admins::BaseController 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 + subject = Subject.find(params[:subject_id]) + Subjects::CopySubjectService.call(subject, current_user, current_laboratory) render_ok end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index db72590ee..1bc2bad7d 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -395,6 +395,50 @@ class ApplicationController < ActionController::Base end end + # 处理返回非0就报错的请求 + def interface_post(uri, params, status, message) + begin + uid_logger_dubug("--uri_exec: params is #{params}, url is #{uri}") + uri = URI.parse(URI.encode(uri.strip)) + res = Net::HTTP.post_form(uri, params).body + uid_logger_dubug("--uri_exec: .....res is #{res}") + res = JSON.parse(res) + if (res && res['code'] != 0) + tip_exception(status, message) + else + res + end + rescue Exception => e + uid_logger("--uri_exec: exception #{e.message}") + raise Educoder::TipException.new("实训平台繁忙(繁忙等级:84)") + end + end + + # json格式请求 + def interface_json_post(uri, params, status, message) + begin + uid_logger_dubug("--uri_exec: params is #{params}, url is #{uri}") + uri = URI.parse(URI.encode(uri.strip)) + res = Net::HTTP.start(uri.host, uri.port) do |http| + req = Net::HTTP::Post.new(uri) + req['Content-Type'] = 'application/json' + req.body = params.to_json + http.request(req) + end + uid_logger_dubug("--uri_exec: .....res is #{res.body}") + res = JSON.parse(res.body) + if (res && res['code'] != 0) + tip_exception(status, message) + else + res + end + rescue Exception => e + uid_logger("--uri_exec: exception #{e.message}") + raise Educoder::TipException.new("服务器繁忙") + end + end + + # 适用与已经用url_safe编码后,回调字符串形式 def tran_base64_decode64(str) s_size = str.size % 4 diff --git a/app/controllers/competitions/competitions_controller.rb b/app/controllers/competitions/competitions_controller.rb index 2161ab937..72f53d1e2 100644 --- a/app/controllers/competitions/competitions_controller.rb +++ b/app/controllers/competitions/competitions_controller.rb @@ -9,7 +9,8 @@ class Competitions::CompetitionsController < Competitions::BaseController def index # 已上架 或者 即将上架 - competitions = Competition.where(status: true).or(Competition.where.not(published_at: nil)) + competitions = current_laboratory.competitions + competitions = competitions.where(status: true).or(competitions.where.not(published_at: nil)) competitions = case params[:category] @@ -142,7 +143,7 @@ class Competitions::CompetitionsController < Competitions::BaseController } end else - @records = @records.includes(:team_members, competition_prize_users: :competition_prize, user: :user_extension).limit(@competition.awards_count) + @records = @records.includes(:team_members, competition_prize_users: :competition_prize, user: :user_extension).limit(@competition.charts_count) end end @@ -169,7 +170,7 @@ class Competitions::CompetitionsController < Competitions::BaseController def allow_visit return if current_competition.published? || admin_or_business? - return if current_competition.nearly_published? && current_competition.manager?(current_user) + return if current_competition.manager?(current_user) render_forbidden end @@ -181,7 +182,7 @@ class Competitions::CompetitionsController < Competitions::BaseController def check_manager_permission! return if current_user.admin_or_business? - return if current_competition.nearly_published? && current_competition.manager?(current_user) + return if current_competition.manager?(current_user) render_forbidden end diff --git a/app/controllers/concerns/base/error_rescue_handler.rb b/app/controllers/concerns/base/error_rescue_handler.rb index d64ce4356..24e732152 100644 --- a/app/controllers/concerns/base/error_rescue_handler.rb +++ b/app/controllers/concerns/base/error_rescue_handler.rb @@ -18,6 +18,7 @@ module Base::ErrorRescueHandler render_unprocessable_entity(ex.model.errors.full_messages.join(',')) end rescue_from ActiveRecord::RecordInvalid do |ex| + ex.backtrace.each { |msg| Rails.logger.error(msg) } render_unprocessable_entity(ex.record.errors.full_messages.join(',')) end end diff --git a/app/controllers/concerns/git_helper.rb b/app/controllers/concerns/git_helper.rb index 9242b87ac..085fec360 100644 --- a/app/controllers/concerns/git_helper.rb +++ b/app/controllers/concerns/git_helper.rb @@ -50,7 +50,7 @@ module GitHelper raise Educoder::TipException.new("fork源路径为空,fork失败!") if original_rep_path.blank? # 将要生成的仓库名字 new_repo_name = "#{username.try(:strip)}/#{container.try(:identifier)}#{ Time.now.strftime("%Y%m%d%H%M%S")}" - uid_logger("start fork container: repo_name is #{new_repo_name}") + # uid_logger("start fork container: repo_name is #{new_repo_name}") GitService.fork_repository(repo_path: original_rep_path, fork_repository_path: (new_repo_name + ".git")) container.update_attributes!(:repo_name => new_repo_name) end diff --git a/app/controllers/cooperative/base_controller.rb b/app/controllers/cooperative/base_controller.rb index 556cd7aa9..51af05ed2 100644 --- a/app/controllers/cooperative/base_controller.rb +++ b/app/controllers/cooperative/base_controller.rb @@ -17,6 +17,7 @@ class Cooperative::BaseController < ApplicationController def current_laboratory @_current_laboratory ||= Laboratory.find_by_subdomain(request.subdomain) + # @_current_laboratory ||= Laboratory.find 1 end def current_setting_or_default(name) diff --git a/app/controllers/cooperative/competition_prize_users_controller.rb b/app/controllers/cooperative/competition_prize_users_controller.rb new file mode 100644 index 000000000..8f350e06c --- /dev/null +++ b/app/controllers/cooperative/competition_prize_users_controller.rb @@ -0,0 +1,51 @@ +class Cooperative::CompetitionPrizeUsersController < Cooperative::BaseController + def index + @competition = current_competition + + prize_users = Admins::CompetitionPrizeUserQuery.call(params.merge(competition_id: current_competition.id)) + include_class = [:competition_team, :competition_prize, :approver, + user: [:process_real_name_apply, :process_professional_apply, user_extension: :school]] + @prize_users = paginate(prize_users.preload(include_class)) + + respond_to do |format| + format.js + format.html + format.xlsx do + @all_prize_users = prize_users + filename = "#{@competition.name}竞赛获奖人信息列表_#{Time.current.strftime('%Y%m%d%H%M%S')}.xlsx" + render xlsx: 'index', filename: filename + end + end + end + + def create + Admins::CreateCompetitionPrizeUsersService.call(current_competition) + render_ok + rescue ApplicationService::Error => ex + render_error(ex.message) + end + + def approve + Admins::ApproveCompetitionPrizeUserService.call(current_prize_user, current_user) + @prize_user = current_prize_user + rescue ApplicationService::Error => ex + render_js_error(ex.message, type: :notify) + end + + def unapprove + Admins::UnapproveCompetitionPrizeUserService.call(current_prize_user, current_user) + @prize_user = current_prize_user + rescue ApplicationService::Error => ex + render_js_error(ex.message, type: :notify) + end + + private + + def current_prize_user + @_current_prize_user ||= current_competition.competition_prize_users.find(params[:id]) + end + + def current_competition + @_current_competition ||= current_laboratory.competitions.find(params[:competition_id]) + end +end \ No newline at end of file diff --git a/app/controllers/cooperative/competition_prizes_controller.rb b/app/controllers/cooperative/competition_prizes_controller.rb new file mode 100644 index 000000000..a7e78e376 --- /dev/null +++ b/app/controllers/cooperative/competition_prizes_controller.rb @@ -0,0 +1,43 @@ +class Cooperative::CompetitionPrizesController < Cooperative::BaseController + def index + @competition = current_competition + end + + def new + @prize = current_competition.competition_prizes.new + end + + def create + @prize = current_competition.competition_prizes.create!(save_params) + render_ok + end + + def edit + @prize = current_competition_prize + end + + def update + current_competition_prize.update!(save_params) + render_ok + end + + def destroy + current_competition_prize.destroy! + + render_delete_success + end + + private + + def current_competition_prize + @_current_competition_prize ||= current_competition.competition_prizes.find(params[:id]) + end + + def current_competition + @_current_competition ||= current_laboratory.competitions.find(params[:competition_id]) + end + + def save_params + params.require(:competition_prize).permit(:name, :category, :num) + end +end \ No newline at end of file diff --git a/app/controllers/cooperative/competition_settings_controller.rb b/app/controllers/cooperative/competition_settings_controller.rb new file mode 100644 index 000000000..08a40a83c --- /dev/null +++ b/app/controllers/cooperative/competition_settings_controller.rb @@ -0,0 +1,33 @@ +class Cooperative::CompetitionSettingsController < Cooperative::BaseController + def index + @competition = current_competition + end + + def basic_setting + Admins::CompetitionBasicSettingService.call(current_competition, basic_form_params) + render_ok + end + + def nav_setting + Admins::CompetitionNavSettingService.call(current_competition, nav_form_params) + render_ok + end + + private + + def current_competition + @_current_competition ||= current_laboratory.competitions.find(params[:competition_id]) + end + + def basic_form_params + params.permit(:identifier, :name, :sub_title, :start_time, :end_time, :mode, + :identifier, :bonus, :awards_count, :description, :course_id, :teach_start_time, + :teach_end_time, sponsor_schools: [], region_schools: [], manager_ids: []) + end + + def nav_form_params + params.permit(:enroll_end_time, + competition_staffs: %i[category minimum maximum mutiple_limited], + navbar: %i[module_type module_id name hidden position url]) + end +end \ No newline at end of file diff --git a/app/controllers/cooperative/competition_stages_controller.rb b/app/controllers/cooperative/competition_stages_controller.rb new file mode 100644 index 000000000..544fe4981 --- /dev/null +++ b/app/controllers/cooperative/competition_stages_controller.rb @@ -0,0 +1,194 @@ +class Cooperative::CompetitionStagesController < Cooperative::BaseController + + def create + Admins::CompetitionStageCreateService.call(current_competition, update_form_params) + render_ok + end + + def update + Admins::CompetitionStageUpdateService.call(current_competition, update_form_params, current_stage) + render_ok + end + + def destroy + current_stage.destroy! + end + + def calculate_stage_score + if current_stage.max_end_time && current_stage.max_end_time < Time.now + + ActiveRecord::Base.transaction do + begin + + current_stage.competition_scores.destroy_all + + if current_stage.competition_stage_sections.size > 0 + # 是否只有老师参赛 + only_teacher = current_competition.member_staff.blank? + stage_sections = current_stage.competition_stage_sections.includes(:competition_entries) + shixuns = Shixun.where(identifier: current_stage.competition_entries.pluck(:shixun_identifier).reject(&:blank?)) + challenges = Challenge.where(shixun_id: shixuns.pluck(:id)) + + # 计算每个战队的成绩 + current_competition.competition_teams.each do |team| + totoal_score = 0 + total_time = 0 + # 只有老师参赛则计算所有参赛队员的成绩,否则只计算学生的成绩 + user_ids = only_teacher ? team.team_members.pluck(:user_id) : team.team_members.where(is_teacher: 0).pluck(:user_id) + + stage_sections.each do |section| + shixun_identifiers = section.competition_entries.pluck(:shixun_identifier).reject(&:blank?) + shixun_ids = shixuns.select{ |shixun| shixun_identifiers.include?(shixun.identifier) }.map(&:id) + section_challenges = challenges.select{ |challenge| shixun_ids.include?(challenge.shixun_id) } + if section.score_source == 0 + result1 = chart_stage_score user_ids, section.start_time, section.end_time, section_challenges, section_challenges.length/shixun_ids.length + else + result1 = chart_stage_rate user_ids, section.start_time, section.end_time, section_challenges, section_challenges.length/shixun_ids.length + end + score = result1[0] + time = result1[1] + + totoal_score += score + total_time += time + end + + # 比赛已截止且未有分数纪录 则创建 + unless team.competition_scores.exists?(competition_id: current_competition.id, competition_stage_id: current_stage.id) + CompetitionScore.create!(user_id: team.user_id, competition_team_id: team.id, competition_id: current_competition.id, + competition_stage_id: current_stage.id, score: totoal_score, cost_time: total_time) + end + end + + # 如果计算的是最后一个阶段,则同时计算总成绩(只有一个阶段则不需计算) + if current_stage.max_end_time == current_competition.max_stage_end_time && current_competition.competition_stages.size > 1 + calculate_total_score current_competition + end + end + + rescue Exception => e + uid_logger_error(e.message) + @message = "#{e.message}" + end + end + + @message = "计算成功" + else + @message = "#{current_stage.name}还未结束" + end + end + + def send_message + if current_stage.max_end_time && current_stage.max_end_time > Time.now + User.where(id: TeamMember.where(competition_team_id: current_competition.competition_teams.pluck(:id)).pluck(:user_id).uniq).each do |user| + name = current_competition.name + "#{current_competition.sub_title}(#{stage.name})" + begin + if user.phone.present? + Educoder::Sms.send(mobile: user.phone.to_s, code: '1', send_type:'competition_start', user_name:user.show_name, + name:name, result:section.start_time.strftime('%Y-%m-%d %H:%M:%S')) + end + rescue => e + logger_error(e) + render_error("发送验证码出错") + end + end + else + render_error("#{current_stage.name}已结束") + end + end + + private + + def current_competition + @_current_competition ||= current_laboratory.competitions.find(params[:competition_id]) + end + + def current_stage + @_current_stage ||= CompetitionStage.find_by!(competition_id: params[:competition_id], id: params[:id]) + end + + def update_form_params + params.permit(:stage_name, :score_rate, stage: [:start_time, :end_time, :entry, :score_source, identifiers: []]) + end + + + # challenges 每阶段的所有关卡 + # s_time 阶段开始时间 e_time 阶段结束时间 + # rate 关卡经验值与分数的比值 + # challenge_count 每个实训的关卡数 + # 对三个实训的所有关卡循环: 找到在比赛时间内通关的最低耗时 + def chart_stage_score user_ids, s_time, e_time, challenges, challenge_count + total_score = 0 + total_time = 0 + length = challenge_count #每个实训的关卡数 + for i in 1..length + score = 0 + time = 0 + challenges.select{|challenge| challenge.position == i}.each do |challenge| + Game.where(:challenge_id => challenge.id, :user_id => user_ids, :status => 2).select{|game| game.open_time >= s_time && game.end_time <= e_time }.each do |game| + game_score = challenge.score + cost_time = (game.end_time.to_i - s_time.to_i) > 0 ? (game.end_time.to_i - s_time.to_i) : 0 + if score < game_score + score = game_score + time = cost_time + elsif score == game_score + time = cost_time > time ? time : cost_time + end + end + end + total_score += score + total_time += time + end + return [total_score, total_time] + end + + def chart_stage_rate user_ids, s_time, e_time, challenges, challenge_count + # 第三阶段的得分和耗时 + total_score = 0 + total_time = 0 + length = challenge_count #每个实训的关卡数 + for i in 1..length + score3 = 0 + time3 = 0 + + challenges.select{|challenge| challenge.position == i}.each do |challenge| + Game.where(:challenge_id => challenge.id, :user_id => user_ids, :status => 2).select{|game| game.open_time >= s_time && game.end_time <= e_time }.each do |game| + outputs = game.outputs.select{|output| !output.text_scor.nil? && output.created_at <= e_time } + if outputs.present? + outputs = outputs.sort { |a, b| b[:text_scor].to_f <=> a[:text_scor].to_f } + myshixun_score = outputs.first.text_scor.to_f + myshixun_time = outputs.first.created_at.to_i - s_time.to_i + if score3 < myshixun_score + score3 = myshixun_score + time3 = myshixun_time + elsif score3 == myshixun_score + time3 = myshixun_time > time3 ? time3 : myshixun_time + end + end + end + end + + total_score += score3 + total_time += time3 + end + return [total_score, total_time] + end + + def calculate_total_score competition + competition.competition_scores.where(competition_stage_id: 0).destroy_all + competition.competition_teams.each do |team| + total_score = 0 + total_time = 0 + + competition.competition_stages.where("score_rate > 0").each do |stage| + stage_score = team.competition_scores.where(competition_stage_id: stage.id).take + total_score += stage_score.try(:score).to_f * stage.score_rate + total_time += stage_score.try(:cost_time).to_i + end + + unless team.competition_scores.exists?(competition_id: competition.id, competition_stage_id: 0) + CompetitionScore.create!(user_id: team.user_id, competition_team_id: team.id, competition_id: competition.id, + competition_stage_id: 0, score: total_score, cost_time: total_time) + end + end + end +end \ No newline at end of file diff --git a/app/controllers/cooperative/competitions_controller.rb b/app/controllers/cooperative/competitions_controller.rb new file mode 100644 index 000000000..891f997f4 --- /dev/null +++ b/app/controllers/cooperative/competitions_controller.rb @@ -0,0 +1,57 @@ +class Cooperative::CompetitionsController < Cooperative::BaseController + before_action :find_competition, except: [:index] + + def index + # params[:sort_by] = params[:sort_by].presence || 'created_at' + # params[:sort_direction] = params[:sort_direction].presence || 'desc' + @competitions = current_laboratory.competitions.order("created_at desc") + @params_page = params[:page] || 1 + @competitions = paginate @competitions + ids = @competitions.map(&:id) + @member_count_map = TeamMember.where(competition_id: ids).group(:competition_id).count + + @competition_hot = ModuleSetting.exists?(module_type: "Competition", property: "hot") + respond_to do |format| + format.js + format.html + end + end + + def create + name = params[:competition_name].to_s.strip + Competition.create!(name: name) + render_ok + end + + def hot_setting + if params[:hot].to_i == 1 && !ModuleSetting.exists?(module_type: "Competition", property: "hot") + ModuleSetting.create!(module_type: "Competition", property: "hot") + elsif params[:hot].to_i == 0 && ModuleSetting.exists?(module_type: "Competition", property: "hot") + ModuleSetting.where(module_type: "Competition", property: "hot").destroy_all + end + render_ok + end + + def publish + @competition.update_attributes!(published_at: Time.now) + end + + def unpublish + @competition.update_attributes!(published_at: nil) + end + + def online_switch + if @competition.status + @competition.update_attributes!(status: false) + else + @competition.update_attributes!(status: true, online_time: Time.now) + end + end + + private + + def find_competition + @competition = current_laboratory.competitions.find_by(id: params[:id]) + end + +end \ No newline at end of file diff --git a/app/controllers/cooperative/enroll_lists_controller.rb b/app/controllers/cooperative/enroll_lists_controller.rb new file mode 100644 index 000000000..c228150b9 --- /dev/null +++ b/app/controllers/cooperative/enroll_lists_controller.rb @@ -0,0 +1,33 @@ +class Cooperative::EnrollListsController < Cooperative::BaseController + + def index + @competition = current_competition + default_sort('created_at', 'desc') + enroll_lists = Admins::CompetitionEnrollListQuery.call(@competition, params) + + @params_page = params[:page] || 1 + @enroll_lists = paginate enroll_lists.preload(competition_team: [:user, :teachers], user: { user_extension: :school }) + @personal = @competition.personal? + + respond_to do |format| + format.js + format.html + end + end + + def export + default_sort('created_at', 'desc') + @enroll_lists = Admins::CompetitionEnrollListQuery.call(current_competition, params) + @enroll_lists = @enroll_lists.preload(competition_team: [:user, :teachers], user: { user_extension: :school }) + @competition_scores = current_competition.competition_scores.where(competition_stage_id: 0).order("score desc, cost_time desc").pluck(:competition_team_id) + @personal = current_competition.personal? + filename = ["#{current_competition.name}竞赛报名列表", Time.zone.now.strftime('%Y-%m-%d%H:%M:%S')].join('-') << '.xlsx' + render xlsx: 'export', filename: filename + end + + private + def current_competition + @_current_competition ||= current_laboratory.competitions.find(params[:competition_id]) + end + +end \ No newline at end of file diff --git a/app/controllers/cooperative/laboratory_settings_controller.rb b/app/controllers/cooperative/laboratory_settings_controller.rb index d9ba70d9d..a5a1a80bb 100644 --- a/app/controllers/cooperative/laboratory_settings_controller.rb +++ b/app/controllers/cooperative/laboratory_settings_controller.rb @@ -9,6 +9,9 @@ class Cooperative::LaboratorySettingsController < Cooperative::BaseController end def form_params - params.permit(:identifier, :name, :nav_logo, :login_logo, :tab_logo, :footer, navbar: %i[name link hidden]) + params.permit(:identifier, :name, + :nav_logo, :login_logo, :tab_logo, + :subject_banner, :course_banner, :competition_banner, :moop_cases_banner, + :footer, navbar: %i[name link hidden]) end end \ No newline at end of file diff --git a/app/controllers/cooperative/users_controller.rb b/app/controllers/cooperative/users_controller.rb index 4c6539147..c97a73b49 100644 --- a/app/controllers/cooperative/users_controller.rb +++ b/app/controllers/cooperative/users_controller.rb @@ -1,7 +1,13 @@ class Cooperative::UsersController < Cooperative::BaseController def index - params[:sort_by] = params[:sort_by].presence || 'created_on' - params[:sort_direction] = params[:sort_direction].presence || 'desc' + default_sort('created_on', 'desc') + + users = Admins::UserQuery.call(search_params.merge(laboratory_id: current_laboratory.id)) + @users = paginate users.includes(user_extension: :school) + end + + def for_select + default_sort('created_on', 'desc') users = Admins::UserQuery.call(search_params) @users = paginate users.includes(user_extension: :school) @@ -10,6 +16,6 @@ class Cooperative::UsersController < Cooperative::BaseController private def search_params - params.permit(:name, :sort_by, :sort_direction) + params.permit(:identity, :name, :keyword, :school_name, :sort_by, :sort_direction) end end \ No newline at end of file diff --git a/app/controllers/courses_controller.rb b/app/controllers/courses_controller.rb index 723f4e0da..7e2432fc4 100644 --- a/app/controllers/courses_controller.rb +++ b/app/controllers/courses_controller.rb @@ -61,12 +61,13 @@ class CoursesController < ApplicationController @user = current_user # 根据分类查询课堂(全部,我的,最新,最热) @order = params[:order].present? ? params[:order] : "all" + @courses = current_laboratory.courses.not_deleted if @order == "visits" order_str = "courses.id = 1309 DESC, courses.visits DESC" - @courses = Course.where(is_delete: 0, is_hidden: 0) + @courses = @courses.where(is_hidden: 0) else order_str = "courses.id = 1309 DESC, courses.homepage_show DESC, courses.created_at desc" - @courses = Course.where(is_delete: 0, is_hidden: 0, is_end: 0) + @courses = @courses.where(is_hidden: 0, is_end: 0) end # 金课未开课的不显示在首页 @@ -467,6 +468,7 @@ class CoursesController < ApplicationController # @users = User.where.not(id: user_ids_of_course_members) @users = User.where(status: User::STATUS_ACTIVE) + @users = @users.where(laboratory_id: current_laboratory.id) unless current_laboratory.main_site? @users = @users.where("concat(users.lastname, users.firstname) like '%#{name}%'") if name.present? # REDO:Extension @users = @users.joins(user_extension: :school).where("schools.name like '%#{school_name}%'") if school_name.present? @@ -631,6 +633,9 @@ class CoursesController < ApplicationController 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) + # 如果有未审批的申请教师/助教的记录,则修改状态为已审批 + apply_teacher = CourseMessage.where(course_id: @course.id, course_message_id: params[:user_id], status: 0).last + apply_teacher.update!(status: 1, apply_user_id: current_user.id) 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") @@ -794,18 +799,15 @@ class CoursesController < ApplicationController if approval == 1 course_message.pass! - new_teacher = CourseMember.new(course_id: @course.id, user_id: applier_user.id) content = course_message.content.to_i - if content == 3 || content == 7 - tip_exception("已存在教师/助教身份") if CourseMember.where(course_id: @course.id, user_id: applier_user.id, role: 3).any? - new_teacher.ASSISTANT_PROFESSOR! - elsif content == 2 || content == 9 - tip_exception("已存在教师/助教身份") if CourseMember.where(course_id: @course.id, user_id: applier_user.id, role: 2).any? - new_teacher.PROFESSOR! + role = (content == 3 || content == 7) ? 3 : ((content == 2 || content == 9) ? 2 : nil) + if role + tip_exception("已存在教师/助教身份") if CourseMember.where(course_id: @course.id, user_id: applier_user.id, role: [1, 2 ,3]).any? else tip_exception("申请角色错误") end + new_teacher = CourseMember.new(course_id: @course.id, user_id: applier_user.id, role: role) new_teacher.save! # 课堂管理员才有分配权限,且课堂分班数大于0 @@ -828,7 +830,7 @@ class CoursesController < ApplicationController normal_status(0, "操作成功") rescue => e uid_logger_error(e.message) - tip_exception("操作失败") + tip_exception(e.message) raise ActiveRecord::Rollback end end @@ -1083,6 +1085,7 @@ class CoursesController < ApplicationController # REDO:Extension @users = User.where(status: User::STATUS_ACTIVE) + @users = @users.where(laboratory_id: current_laboratory.id) unless current_laboratory.main_site? @users = @users.where("concat(users.lastname, users.firstname) like '%#{name}%'") if name.present? # REDO:Extension @users = @users.joins(user_extension: :school).where("schools.name like '%#{school_name}%'") if school_name.present? @@ -1102,12 +1105,12 @@ class CoursesController < ApplicationController # 邀请码验证 return normal_status(-1, "邀请码不能为空") if params[:invite_code].blank? invite_code = params[:invite_code] - course = Course.find_by(invite_code: invite_code, is_delete: 0, invite_code_halt: 0) + course = Course.find_by(invite_code: invite_code, is_delete: 0, invite_code_halt: 0, laboratory_id: current_laboratory.id) course_group = CourseGroup.find_by(invite_code: invite_code) if course.blank? return normal_status(-1, "邀请码无效") if course_group.blank? - course = Course.find_by(id: course_group.course_id, is_delete: 0, invite_code_halt: 0) + course = Course.find_by(id: course_group.course_id, is_delete: 0, invite_code_halt: 0, laboratory_id: current_laboratory.id) return normal_status(-1, "邀请码无效") if course.blank? end diff --git a/app/controllers/exercises_controller.rb b/app/controllers/exercises_controller.rb index 102469043..fff320323 100644 --- a/app/controllers/exercises_controller.rb +++ b/app/controllers/exercises_controller.rb @@ -601,7 +601,7 @@ class ExercisesController < ApplicationController end rescue Exception => e uid_logger_error(e.message) - tip_exception("试卷提交失败") + tip_exception(e.message) raise ActiveRecord::Rollback end end @@ -850,10 +850,11 @@ class ExercisesController < ApplicationController g_course = params[:group_ids] if g_course.present? teacher_course_group_ids = @course.charge_group_ids(current_user) - if g_course.map(&:to_i).sort == teacher_course_group_ids.sort #开始为统一设置 + all_course_group_ids = @course.course_groups.pluck(:id) + if exercise.unified_setting && g_course.map(&:to_i).sort == all_course_group_ids.sort #开始为统一设置 exercise.exercise_group_settings.destroy_all new_ex_status = set_exercise_status(exercise.publish_time,Time.now) - exercise.update_attributes(:end_time => Time.now,:unified_setting => true,:exercise_status => new_ex_status) + exercise.update_attributes(:end_time => Time.now,:exercise_status => new_ex_status) exercise_users = exercise.exercise_users else course_members_ids = course_students.course_find_by_ids("course_group_id",g_course).pluck(:user_id).uniq #该班级的全部学生 @@ -1627,12 +1628,14 @@ class ExercisesController < ApplicationController ex_and_user = user_groups_id & ex_group_settings #用户已设置的分班 unpublish_group = unpublish_group + ex_and_user - ex_ended_groups #已发布的全部班级减去截止的全部班级 else + ex_ended_groups = ex_all_group_settings.exercise_group_ended.pluck(:course_group_id).uniq ex_and_user = user_groups_id & ex_group_settings #用户已设置的分班 - unpublish_group = unpublish_group + ex_and_user + unpublish_group = unpublish_group + ex_and_user - ex_ended_groups end end end end + Rails.logger.info("#####____________unpublish_group_______#######{unpublish_group}") unpublish_group = unpublish_group.uniq if unpublish_group.count > 0 course_groups = CourseGroup.by_group_ids(unpublish_group) diff --git a/app/controllers/gits_controller.rb b/app/controllers/gits_controller.rb index e94c197ed..b3ab4c13f 100644 --- a/app/controllers/gits_controller.rb +++ b/app/controllers/gits_controller.rb @@ -49,11 +49,12 @@ class GitsController < ApplicationController shixunname = git_url.split("/")[1].split(".")[0] repo_name = username + "/" + shixunname uid_logger("git start: repo_name is #{repo_name}") - shixun = Shixun.select([:id, :user_id, :repo_name, :identifier]).where(repo_name: repo_name).first + shixun = Shixun.select([:id, :user_id, :repo_name, :identifier]).where(repo_name: repo_name, laboratory_id: nil).first uid_logger("git start auth: shixun identifier is #{shixun.try(:identifier)}") uid_logger("git start auth: systemuser is #{system_user.try(:login)}") if shixun.present? + logger.info("#######{system_user.manager_of_shixun?(shixun)}") if system_user.present? && system_user.manager_of_shixun?(shixun) result = true else @@ -72,7 +73,6 @@ class GitsController < ApplicationController authenticate_or_request_with_http_basic do |username, password| result - logger.info("1111111 git auth end: code is #{rand_code}, time is #{Time.now}") end end diff --git a/app/controllers/hack_user_lastest_codes_controller.rb b/app/controllers/hack_user_lastest_codes_controller.rb new file mode 100644 index 000000000..bbe94233f --- /dev/null +++ b/app/controllers/hack_user_lastest_codes_controller.rb @@ -0,0 +1,170 @@ +class HackUserLastestCodesController < ApplicationController + before_action :require_login, except: [:listen_result] + before_action :find_my_hack, only: [:show, :code_debug, :code_submit, :update_code, :listen_result, :result] + before_action :update_user_hack_status, only: [:code_debug, :code_submit] + before_action :require_auth_identity, only: [:update_code] + before_action :require_manager_identity, only: [:update_code] + + def show + @my_hack.update_attribute(:status, 0) if @my_hack.status == 1 + end + + def update_code + @my_hack.update_attribute(:code, params[:code]) + end + + # 调试代码 + def code_debug + exec_mode = "debug" + error_status = 501 + error_msg = "debug_error" + oj_evaluate exec_mode, error_status, error_msg + render_ok + end + + # 提交 + def code_submit + exec_mode = "submit" + error_status = 502 + error_msg = "submit_error" + oj_evaluate exec_mode, error_status, error_msg + render_ok + end + + # 提交结果显示 + def result + return if @my_hack.status == 1 + + end + + # 接收中间件返回结果接口 + # 调试模式: status: 0 表示评测无错误,其他 表示错误(如编译出错,执行出错,超时等) + def listen_result + logger.info("###########listen_result:#{params}") + begin + ojEvaResult = JSON.parse(params[:ojEvaResult]) + testCase = ojEvaResult['testCase'] + # 只有编译出错时,才正则匹配错误行数 + error_line= + if params[:status] == "-4" + regular_match_error_line ojEvaResult['outPut'], @my_hack.hack.language + end + # debug 与submit 公用的参数 + + ds_params = {input: testCase['input'], output: testCase['output'], hack_id: @hack.id, + code: ojEvaResult['codeFileContent'], user_id: @my_hack.user_id, error_line: error_line, + status: ojEvaResult['status'], error_msg: ojEvaResult['outPut'], + execute_time: ojEvaResult['executeTime'], execute_memory: ojEvaResult['executeMem']} + ActiveRecord::Base.transaction do + # debug模式与submit模式 + if ojEvaResult['execMode'] == "debug" + save_debug_data ds_params + elsif ojEvaResult['execMode'] == "submit" + save_submit_data ds_params + end + # 评测完成后,还原评测中的状态 + @my_hack.update_attribute(:submit_status, 0) + end + render_ok + rescue Exception => e + logger.error("#########listen_result: #{e.message}") + end + + end + + private + def find_my_hack + @my_hack = HackUserLastestCode.find_by(identifier: params[:identifier]) + @hack = @my_hack.hack + end + + def oj_evaluate exec_mode, error_status, error_msg + request_url = "#{edu_setting('cloud_bridge')}/bridge/ojs/evaluate" + test_sets = + if exec_mode == "submit" + @hack.hack_sets.map{|set| {input: set.input, output: set.output, caseId: set.id}} + else + {input: params[:input]} + end + testCases = Base64.urlsafe_encode64(test_sets.to_json) + #codeFileContent = Base64.urlsafe_encode64(@my_hack.code) + debug_params = {execMode: exec_mode, + tpiID: @my_hack.identifier, + testCases: testCases, + platform: @my_hack.language, + codeFileContent: @my_hack.code, + timeLimit: @hack.time_limit, + sec_key: Time.now.to_i} + interface_json_post request_url, debug_params, error_status, error_msg + # 每次评测提交数增加 + @hack.increment!(:submit_num) + end + + # 正则错误行数 + def regular_match_error_line content, language + case language + when 'Java' + content.scan(/.java.\d+/).map{|s| s.match(/\d+/)[0].to_i}.min + when 'C', 'C++' + content.scan(/\d:\d+: error/).map{|s| s.match(/\d+/)[0]}.min + when 'Python' + content.scan(/line \d+/).map{|s| s.match(/\d+/)[0].to_i}.min + end + end + + # 存储debug数据 + def save_debug_data debug_params + if @my_hack.hack_user_debug.present? + @my_hack.hack_user_debug.update_attributes!(debug_params) + else + @my_hack.hack_user_debug.create!(debug_params) + end + end + + # 存储submit数据 + def save_submit_data submit_params + # 通关 + if submit_params[:status] == "0" + # 编程题已经发布,且之前未通关奖励积分 + if @hack.status == 1 && !@my_hack.passed? + reward_attrs = { container_id: game.id, container_type: 'Hack', score: @hack.score } + RewardGradeService.call(@my_hack.user, reward_attrs) + RewardExperienceService.call(@my_hack.user, reward_attrs) + # 评测完成更新通过数 + @hack.increment!(:pass_num) + @my_hack.update_attribute(:passed, true) + end + end + # 创建用户评测记录 + logger.info("###########submit_params:#{submit_params}") + query_index = @my_hack.hack_user_codes.count +1 + @my_hack.hack_user_codes.create!(submit_params.merge(query_index: query_index)) + end + + # 调试或提交改变状态 + def update_user_hack_status + @my_hack.update_attribute(:submit_status, 1) + end + + # 只有自己才能改动代码 + def require_identity + if @my_hack.user_id != current_user.id + tip_exception(403, "..") + end + end + + # 老师、自己、管理可以查看他人的编程题 + def require_manager_identity + unless current_user.certification_teacher? || admin_or_business? || @my_hack.user_id == current_user.id + tip_exception(403, "..") + end + end + + # 只有自己才能评测 + def require_auth_identity + unless @my_hack.user_id == current_user.id + tip_exception(403, "..") + end + end + +end diff --git a/app/controllers/hacks_controller.rb b/app/controllers/hacks_controller.rb new file mode 100644 index 000000000..9fa8e26e3 --- /dev/null +++ b/app/controllers/hacks_controller.rb @@ -0,0 +1,180 @@ +class HacksController < ApplicationController + before_action :require_login, except: [:index] + before_action :require_teacher_identity, only: [:create, :edit, :update] + before_action :require_auth_identity, only: [:update, :edit, :publish] + before_action :find_hack, only: [:edit, :update, :publish, :start] + + # 开启编程,如果第一次开启,创建一条记录,如果已经开启过的话,直接返回标识即可 + def start + # 未发布的编程题,只能作者、或管理员访问 + start_hack_auth + user_hack = @hack.hack_user_lastest_codes.mine(current_user.id) + identifier = + if user_hack.present? + user_hack.identifier + else + user_identifier = generate_identifier HackUserLastestCode, 12 + user_code = {user_id: current_user.id, code: @hack.code, + identifier: user_identifier, language: @hack.language} + @hack.hack_user_lastest_codes.create!(user_code) + user_identifier + end + render_ok(data: {identifier: identifier}) + end + + # 首页 + def index + # 筛选过滤与排序 + params_filter_or_order + # 我解决的编程题数 + user_codes = HackUserLastestCode.mine(current_user).passed.joins(:hack) + @simple_count = user_codes.where(hacks: {difficult: 1}).count + @medium_count = user_codes.where(hacks: {difficult: 2}).count + @diff_count = user_codes.where(hacks: {difficult: 3}).count + @pass_count = @simple_count + @medium_count + @diff_count + + @hacks_count = @hacks.count("hacks.id") + @hacks = paginate @hacks + end + + def create + begin + logger.info("##########{hack_params}") + hack = Hack.new(hack_params) + ActiveRecord::Base.transaction do + hack.user_id = current_user.id + hack.identifier = generate_identifier Hack, 8 + hack.save! + # 创建测试集与代码 + hack.hack_sets.create!(hack_sets_params) + hack.hack_codes.create!(hack_code_params) + end + render_ok({identifier: hack.identifier}) + rescue Exception => e + logger.error("########create_hack_error: #{e.message}") + render_error("创建失败") + end + end + + def update + begin + ActiveRecord::Base.transaction do + @hack.update_attributes!(hack_params) + set_ids = @hack.hack_sets.pluck(:id) + # 更新 + param_update_sets params[:update_hack_sets], set_ids + # 新建 + @hack.hack_sets.create!(hack_sets_params) + # 更新代码 + @hack.hack_codes.create!(hack_code_params) + end + render_ok + rescue Exception => e + logger.error("####update_hack_error: #{e.message}") + render_error("更新失败") + end + end + + # 发布功能 + def publish + @hack.update_attribute(:status, 1) + render_ok + end + + # 发布列表 + def unpulished_list + limit = params[:limit] || 16 + page = params[:page] || 1 + hacks = Hack.where(user_id: current_user.id, status: 0) + @hacks_count = hacks.count + @hacks = hacks.includes(:hack_sets).page(page).per(limit) + end + + def edit;end + + private + # 实名认证老师,管理员与运营人员权限 + def require_teacher_identity + unless current_user.certification_teacher? || admin_or_business? + tip_exception(403, "..") + end + end + + # 只有自己,或者管理员才能更新 + def require_auth_identity + unless @hack.user_id == current_user.id || admin_or_business? + tip_exception(403, "..") + end + end + + def find_hack + @hack = Hack.find_by_identifier(params[:identifier]) + end + + def hack_params + params.require(:hack).permit(:name, :description, :difficult, :category, :open_or_not, :time_limit, :score) + end + + def hack_sets_params + params.permit(hack_sets: [:input, :output, :position])[:hack_sets] + end + + def hack_code_params + params.require(:hack_codes).permit(:code, :language) + end + + def publish_params + params.require(:hack).permit(:difficult, :category, :open_or_not, :time_limit, :score) + end + + def param_update_sets sets, all_sets_id + delete_set_ids = all_sets_id - sets.map{|set|set[:id]} + @hack.hack_sets.where(id: delete_set_ids).destroy_all + sets.each do |set| + if all_sets_id.include?(set[:id]) + update_attrs = {input: set[:input], output: set[:output], position: set[:position]} + @hack.hack_sets.find_by!(id: set[:id]).update_attributes(update_attrs) + end + end + end + + def params_filter_or_order + # 如果有来源,就不管发布公开私有 + select_sql = "hacks.*, if(hacks.hack_user_lastest_codes_count=0, 0, hacks.pass_num/hacks.hack_user_lastest_codes_count) passed_rate" + if params[:come_from] + hacks = Hack.select(select_sql).mine(current_user.id) + else + hacks = Hack.select(select_sql).published.opening + end + # 搜索 + if params[:search] + hacks = hacks.where("name like ?", "%#{params[:search]}%") + end + # 难度 + if params[:difficult] + hacks = hacks.where(difficult: params[:difficult]) + end + # 状态 + if params[:status] + user_hacks = HackUserLastestCode.where(user_id: current_user.id) + if params[:status].to_i == -1 + if user_hacks.present? + hacks = hacks.where.not(id: user_hacks.pluck(:hack_id)) + end + else + hacks = hacks.joins(:hack_user_lastest_code).where(hack_user_lastest_code: {status: params[:status]}) + end + end + # 排序 + sort_by = params[:sort_by] || "hack_user_lastest_codes_count" + sort_direction = params[:sort_direction] || "desc" + @hacks = hacks.order("#{sort_by} #{sort_direction}") + end + + def start_hack_auth + return true if @hack == 1 + require_auth_identity + end + + +end diff --git a/app/controllers/homework_commons_controller.rb b/app/controllers/homework_commons_controller.rb index a09db6308..94ced56fd 100644 --- a/app/controllers/homework_commons_controller.rb +++ b/app/controllers/homework_commons_controller.rb @@ -532,7 +532,7 @@ class HomeworkCommonsController < ApplicationController # 如果该发布规则 没有已发布的分班则需判断发布时间 tip_exception("发布时间不能早于等于当前时间") if setting[:publish_time] <= strf_time(Time.now) && group_settings.group_published.count == 0 - tip_exception("截止时间不能早于等于当前时间") if setting[:end_time] <= strf_time(Time.now) + tip_exception("截止时间不能早于等于当前时间") if setting[:end_time] <= strf_time(Time.now) && group_settings.none_end.count > 0 tip_exception("截止时间不能早于发布时间") if setting[:publish_time] > setting[:end_time] tip_exception("截止时间不能晚于课堂结束时间(#{@course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")})") if @course.end_date.present? && setting[:end_time] > strf_time(@course.end_date.end_of_day) diff --git a/app/controllers/libraries_controller.rb b/app/controllers/libraries_controller.rb index a2e70d95a..883f8a3aa 100644 --- a/app/controllers/libraries_controller.rb +++ b/app/controllers/libraries_controller.rb @@ -7,7 +7,7 @@ class LibrariesController < ApplicationController helper_method :current_library, :library_manageable? def index - libraries = Library.all + libraries = current_laboratory.libraries libraries = if User.current&.logged? && params[:type] == 'mine' diff --git a/app/controllers/shixun_lists_controller.rb b/app/controllers/shixun_lists_controller.rb index b57f0af21..d0bfe3d88 100644 --- a/app/controllers/shixun_lists_controller.rb +++ b/app/controllers/shixun_lists_controller.rb @@ -1,6 +1,6 @@ class ShixunListsController < ApplicationController def index - @results = ShixunSearchService.call(search_params) + @results = ShixunSearchService.call(search_params, current_laboratory) end private diff --git a/app/controllers/shixuns_controller.rb b/app/controllers/shixuns_controller.rb index 15ee2a712..30f6d1bd3 100644 --- a/app/controllers/shixuns_controller.rb +++ b/app/controllers/shixuns_controller.rb @@ -38,6 +38,9 @@ class ShixunsController < ApplicationController ## 云上实验室过滤 unless current_laboratory.main_site? @shixuns = @shixuns.joins(:laboratory_shixuns).where(laboratory_shixuns: { laboratory_id: current_laboratory.id }) + else + not_shixun_ids = Shixun.joins(:laboratory_shixuns).where("laboratory_shixuns.laboratory_id != #{current_laboratory.id}") + @shixuns = @shixuns.where.not(id: not_shixun_ids) end ## 方向 @@ -486,10 +489,7 @@ class ShixunsController < ApplicationController ShixunMirrorRepository.create(:shixun_id => @shixun.id, :mirror_repository_id => mirror) end end - logger.info("#########shixun_params#{shixun_params}") @shixun.update_attributes(shixun_params) - logger.info("##########shixun_info_params: #{shixun_info_params}") - logger.info("##########params[:shixun_info][:evaluate_script]: #{params[:shixun_info][:evaluate_script]}") @shixun.shixun_info.update_attributes(shixun_info_params) @shixun.shixun_schools.delete_all # scope_partment: 高校的名称 @@ -916,6 +916,7 @@ class ShixunsController < ApplicationController else @users = User.none end + @users = @users.where(laboratory_id: current_laboratory.id) unless current_laboratory.main_site? page = params[:page] || 1 limit = params[:limit] || 20 @user_count = @users.count @@ -974,8 +975,14 @@ class ShixunsController < ApplicationController end - @course_count = course_ids.length - @courses = Course.where(:id => course_ids).page(page).per(limit) + @courses = Course.where(:id => course_ids) + ## 云上实验室过滤 + unless current_laboratory.main_site? + @courses = @courses.where(laboratory_id: current_laboratory.id ) + end + + @course_count = @courses.count + @courses = @courses.page(page).per(limit) end # 将实训发送到课程 diff --git a/app/controllers/subject_lists_controller.rb b/app/controllers/subject_lists_controller.rb index c8a523d79..ef85ccd70 100644 --- a/app/controllers/subject_lists_controller.rb +++ b/app/controllers/subject_lists_controller.rb @@ -1,6 +1,6 @@ class SubjectListsController < ApplicationController def index - @results = SubjectSearchService.call(search_params) + @results = SubjectSearchService.call(search_params, current_laboratory) end private diff --git a/app/controllers/subjects_controller.rb b/app/controllers/subjects_controller.rb index c1a8b15cd..d4f1281a2 100644 --- a/app/controllers/subjects_controller.rb +++ b/app/controllers/subjects_controller.rb @@ -6,6 +6,7 @@ class SubjectsController < ApplicationController before_action :allowed, only: [:update, :edit, :destroy, :publish, :cancel_publish, :cancel_has_publish, :search_members, :add_subject_members, :statistics, :shixun_report, :school_report, :up_member_position, :down_member_position, :update_team_title] + before_action :require_admin, only: [:copy_subject] include ApplicationHelper include SubjectsHelper @@ -23,18 +24,27 @@ class SubjectsController < ApplicationController # 最热排序 if reorder == "myshixun_count" - laboratory_join = current_laboratory.main_site? ? '' : " JOIN laboratory_subjects ls ON ls.subject_id = subjects.id AND ls.laboratory_id = #{current_laboratory.id} " + if current_laboratory.main_site? + not_subject_ids = Subject.joins(:laboratory_subjects).where("laboratory_subjects.laboratory_id != #{current_laboratory.id}").pluck(:id) + not_subject_ids = not_subject_ids.length > 0 ? "(" + not_subject_ids.join(",") + ")" : "(-1)" + laboratory_join = " AND subjects.id not in #{not_subject_ids} " + else + subject_ids = Subject.joins(:laboratory_subjects).where(laboratory_subjects: { laboratory_id: current_laboratory.id }).pluck(:id) + subject_ids = subject_ids.length > 0 ? "(" + subject_ids.join(",") + ")" : "(-1)" + laboratory_join = " AND subjects.id in #{subject_ids} " + end + if select @subjects = Subject.find_by_sql("SELECT subjects.id, subjects.user_id, subjects.name, subjects.stages_count, subjects.repertoire_id, subjects.status, subjects.shixuns_count, subjects.excellent, sum(shixuns.myshixuns_count) AS myshixun_member_count FROM subjects join stage_shixuns - on stage_shixuns.subject_id = subjects.id join shixuns on shixuns.id = stage_shixuns.shixun_id #{laboratory_join} where - subjects.hidden = 0 AND subjects.status = 2 AND subjects.name like '%#{search}%' + on stage_shixuns.subject_id = subjects.id join shixuns on shixuns.id = stage_shixuns.shixun_id where + subjects.hidden = 0 AND subjects.status = 2 AND subjects.name like '%#{search}%' #{laboratory_join} AND subjects.repertoire_id = #{select} GROUP BY subjects.id ORDER BY myshixun_member_count DESC") else @subjects = Subject.find_by_sql("SELECT subjects.id, subjects.user_id, subjects.name, subjects.stages_count, subjects.repertoire_id, subjects.status, subjects.shixuns_count, subjects.excellent, sum(shixuns.myshixuns_count) AS myshixun_member_count FROM subjects join stage_shixuns - on stage_shixuns.subject_id = subjects.id join shixuns on shixuns.id = stage_shixuns.shixun_id #{laboratory_join} where - subjects.hidden = 0 AND subjects.status = 2 AND subjects.name like '%#{search}%' + on stage_shixuns.subject_id = subjects.id join shixuns on shixuns.id = stage_shixuns.shixun_id where + subjects.hidden = 0 AND subjects.status = 2 AND subjects.name like '%#{search}%' #{laboratory_join} GROUP BY subjects.id ORDER BY myshixun_member_count DESC") end else @@ -56,6 +66,9 @@ class SubjectsController < ApplicationController # 云上实验室过滤 unless current_laboratory.main_site? @subjects = @subjects.joins(:laboratory_subjects).where(laboratory_subjects: { laboratory_id: current_laboratory.id }) + else + not_subject_ids = Subject.joins(:laboratory_subjects).where("laboratory_subjects.laboratory_id != #{current_laboratory.id}") + @subjects = @subjects.where.not(id: not_subject_ids) end # 类型 @@ -204,6 +217,10 @@ class SubjectsController < ApplicationController WHERE m.course_id = c.id AND m.role in (1,2,3) AND m.user_id=#{current_user.id} AND c.is_delete = 0 AND c.is_end = 0").map(&:id) @courses = Course.where(id: course_ids) + ## 云上实验室过滤 + unless current_laboratory.main_site? + @courses = @courses.where(laboratory_id: current_laboratory.id ) + end @none_shixun_ids = ShixunSchool.where("school_id != #{current_user.user_extension.try(:school_id).to_i}").pluck(:shixun_id) end @@ -285,6 +302,7 @@ class SubjectsController < ApplicationController member_ids = @subject.subject_members.map(&:user_id).join(',') condition = "%#{params[:search].strip}%".gsub(" ","") @users = User.where("id not in (?) and status = 1 and LOWER(concat(lastname, ifnull(firstname, ''), login)) LIKE ?", member_ids, "#{condition}") + @users = @users.where(laboratory_id: current_laboratory.id) unless current_laboratory.main_site? @users = @users.page(page).per(10) @users = @users.includes(:user_extension) @@ -444,6 +462,13 @@ class SubjectsController < ApplicationController end end + + # 复制实践课程 + def copy + + end + + private def subject_params tip_exception("实训路径名称不能为空") if params[:name].blank? @@ -494,4 +519,6 @@ class SubjectsController < ApplicationController end + + end diff --git a/app/controllers/users/courses_controller.rb b/app/controllers/users/courses_controller.rb index 2c5e29d2b..4198e17ba 100644 --- a/app/controllers/users/courses_controller.rb +++ b/app/controllers/users/courses_controller.rb @@ -2,6 +2,8 @@ class Users::CoursesController < Users::BaseController def index courses = Users::CourseService.new(observed_user, query_params).call + courses = courses.where(laboratory_id: current_laboratory.id) + @count = courses.count @courses = paginate(courses.includes(teacher: { user_extension: :school }), special: observed_user.is_teacher?) end diff --git a/app/controllers/users/recent_contacts_controller.rb b/app/controllers/users/recent_contacts_controller.rb index bc4b8ea8f..2576385b2 100644 --- a/app/controllers/users/recent_contacts_controller.rb +++ b/app/controllers/users/recent_contacts_controller.rb @@ -3,6 +3,7 @@ class Users::RecentContactsController < Users::BaseController def index contacts = observed_user.recent_contacts.distinct + contacts = contacts.where(laboratory_id: current_laboratory.id) unless current_laboratory.main_site? @contacts = contacts.order('private_messages.created_at DESC').limit(10).includes(:user_extension) end end \ No newline at end of file diff --git a/app/controllers/users/shixuns_controller.rb b/app/controllers/users/shixuns_controller.rb index 5d8da9684..fcf9e3618 100644 --- a/app/controllers/users/shixuns_controller.rb +++ b/app/controllers/users/shixuns_controller.rb @@ -2,6 +2,14 @@ class Users::ShixunsController < Users::BaseController def index shixuns = Users::ShixunService.new(observed_user, query_params).call + ## 云上实验室过滤 + if current_laboratory.main_site? + not_shixun_ids = Shixun.joins(:laboratory_shixuns).where("laboratory_shixuns.laboratory_id != #{current_laboratory.id}") + shixuns = shixuns.where.not(id: not_shixun_ids) + else + shixuns = shixuns.joins(:laboratory_shixuns).where(laboratory_shixuns: { laboratory_id: current_laboratory.id }) + end + @count = shixuns.count @shixuns = paginate(shixuns.includes(:first_tag_repertoire), special: observed_user.is_teacher?) diff --git a/app/controllers/users/subjects_controller.rb b/app/controllers/users/subjects_controller.rb index 2f8f308df..8c1e35425 100644 --- a/app/controllers/users/subjects_controller.rb +++ b/app/controllers/users/subjects_controller.rb @@ -2,6 +2,14 @@ class Users::SubjectsController < Users::BaseController def index subjects = Users::SubjectService.new(observed_user, query_params).call + ## 云上实验室过滤 + if current_laboratory.main_site? + not_subject_ids = Subject.joins(:laboratory_subjects).where("laboratory_subjects.laboratory_id != #{current_laboratory.id}") + subjects = subjects.where.not(id: not_subject_ids) + else + subjects = subjects.joins(:laboratory_subjects).where(laboratory_subjects: { laboratory_id: current_laboratory.id }) + end + @count = subjects.count @subjects = paginate(subjects.includes(:user, :repertoire), special: observed_user.is_teacher?) end diff --git a/app/controllers/users_for_private_messages_controller.rb b/app/controllers/users_for_private_messages_controller.rb index bbd5682a1..610bf5d52 100644 --- a/app/controllers/users_for_private_messages_controller.rb +++ b/app/controllers/users_for_private_messages_controller.rb @@ -3,6 +3,7 @@ class UsersForPrivateMessagesController < ApplicationController def index users = User.active.where.not(id: current_user.id) + users = users.where(laboratory_id: current_laboratory.id) unless current_laboratory.main_site? keyword = params[:keyword].to_s.strip if keyword.blank? diff --git a/app/controllers/weapps/courses_controller.rb b/app/controllers/weapps/courses_controller.rb index 41e00f63e..d29411823 100644 --- a/app/controllers/weapps/courses_controller.rb +++ b/app/controllers/weapps/courses_controller.rb @@ -1,8 +1,158 @@ class Weapps::CoursesController < Weapps::BaseController - before_action :require_wechat_login! + before_action :require_login + before_action :user_course_identity, except: [:create] + before_action :teacher_allowed, only: [:edit, :update] + before_action :teacher_or_admin_allowed, only: [:change_member_roles, :delete_course_teachers] def create return render_error("只有老师身份才能创建课堂") unless current_user.is_teacher? + course = Course.new(tea_id: current_user.id) + Weapps::CreateCourseService.call(course, course_params) + render_ok + rescue ApplicationService::Error => ex + render_error(ex.message) + end + + def edit + @course = current_course + end + + def update + Weapps::UpdateCourseService.call(current_course, update_course_params) + render_ok + end + + def show + @course = current_course + @current_user = current_user + end + + def shixun_homework_category + @categories = current_course.shixun_course_modules.first&.course_second_categories + end + + # 教师列表 + def teachers + @course = current_course + if @course.try(:id) != 1309 || current_user.admin? || current_user.try(:id) == 15582 + @teacher_list = @course.course_members.joins(:user).where("course_members.role in (1, 2, 3)") + else + @teacher_list = @course.course_members.joins(:user).where("(course_members.role in (1, 3) or (course_members.user_id = #{current_user.id} + and course_members.role = 2))") + end + + @teacher_list_size = @teacher_list.size + + @applications_size = CourseMessage.unhandled_join_course_requests_by_course(@course).size + + @teacher_list = @teacher_list.preload(user: [user_extension: :school]).order("CONVERT(CONCAT(users.lastname, users.firstname) USING gbk) COLLATE gbk_chinese_ci asc") + end + + # 批量删除教师或助教 + def delete_course_teachers + begin + @course = current_course + course_members = @course.course_members.where(id: params[:course_member_ids], role: %i[PROFESSOR ASSISTANT_PROFESSOR]) + user_ids = course_members.pluck(:user_id) + course_members.destroy_all + CourseDeleteStudentNotifyJob.perform_later(@course.id, user_ids, current_user.id) + @course.students.where(user_id: user_ids).update_all(is_active: 1) + normal_status(0, "删除成功") + rescue => e + uid_logger_error(e.message) + tip_exception("删除失败") + end + end + + def students + + end + + # 批量修改角色 + def change_member_roles + tip_exception("请至少选择一个角色") if params[:roles].blank? + tip_exception("不能具有老师、助教两种角色") if params[:roles].include?("PROFESSOR") && params[:roles].include?("ASSISTANT_PROFESSOR") + + params[:user_ids].each do |user_id| + course_members = @course.course_members.where(user_id: 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[CREATOR PROFESSOR ASSISTANT_PROFESSOR]) + teacher_member = CourseMember.create!(course_id: @course.id, user_id: user_id, role: params[:roles].include?("PROFESSOR") ? 2 : 3) + # 如果有未审批的申请教师/助教的记录,则修改状态为已审批 + apply_teacher = CourseMessage.where(course_id: @course.id, course_message_id: user_id, status: 0).last + apply_teacher.update!(status: 1, apply_user_id: current_user.id) + 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: user_id, is_active: 1, course_id: @course.id, role: %i[CREATOR PROFESSOR ASSISTANT_PROFESSOR]) + new_student = CourseMember.new(user_id: 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, 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, user_id) + # CourseDeleteStudentNotifyJob.perform_later(@course.id, [params[:user_id]], current_user.id) + elsif params[:roles].include?("STUDENT") && student_member.present? && !params[:roles].include?("PROFESSOR") && !params[:roles].include?("ASSISTANT_PROFESSOR") + # 学生身份存在且学生没有教师身份时更新is_active + student_member.update_attributes!(is_active: 1) + end + end + end + normal_status(0, "修改成功") + end + + private + + def course_params + params.permit(:name, :course_list_name, :credit, course_module_types: []) + end + + def update_course_params + params.permit(:name, :course_list_name, :credit) + end + + def current_course + @_current_course = Course.find params[:id] + end + + def teacher_allowed + return render_forbidden unless @user_course_identity < Course::STUDENT + end + + # 课堂教师,课堂管理员以及超级管理员的权限判断 + def teacher_or_admin_allowed + unless @user_course_identity < Course::ASSISTANT_PROFESSOR + tip_exception(403, "..") + end end end \ No newline at end of file diff --git a/app/controllers/weapps/homes_controller.rb b/app/controllers/weapps/homes_controller.rb index a164adcfc..00b955f1b 100644 --- a/app/controllers/weapps/homes_controller.rb +++ b/app/controllers/weapps/homes_controller.rb @@ -1,5 +1,5 @@ class Weapps::HomesController < Weapps::BaseController - # before_action :require_wechat_login! + before_action :require_login def show # banner diff --git a/app/forms/weapps/create_course_form.rb b/app/forms/weapps/create_course_form.rb new file mode 100644 index 000000000..9244096ab --- /dev/null +++ b/app/forms/weapps/create_course_form.rb @@ -0,0 +1,20 @@ +class Weapps::CreateCourseForm + include ActiveModel::Model + + attr_accessor :course + attr_accessor :name, :course_list_name, :credit, :course_module_types + + validates :name, presence: true + validates :course_list_name, presence: true + + validate :course_name_prefix + validate :check_course_modules + + def course_name_prefix + raise '课堂名称应以课程名称开头' unless name.index(course_list_name) && name.index(course_list_name) == 0 + end + + def check_course_modules + raise '请至少添加一个课堂模块' if course_module_types.blank? + end +end \ No newline at end of file diff --git a/app/forms/weapps/update_course_form.rb b/app/forms/weapps/update_course_form.rb new file mode 100644 index 000000000..6fb1d81d9 --- /dev/null +++ b/app/forms/weapps/update_course_form.rb @@ -0,0 +1,15 @@ +class Weapps::UpdateCourseForm + include ActiveModel::Model + + attr_accessor :course + attr_accessor :name, :course_list_name, :credit + + validates :name, presence: true + validates :course_list_name, presence: true + + validate :course_name_prefix + + def course_name_prefix + raise '课堂名称应以课程名称开头' unless name.index(course_list_name) && name.index(course_list_name) == 0 + end +end \ No newline at end of file diff --git a/app/helpers/hack_user_lastest_codes_helper.rb b/app/helpers/hack_user_lastest_codes_helper.rb new file mode 100644 index 000000000..13350a8f6 --- /dev/null +++ b/app/helpers/hack_user_lastest_codes_helper.rb @@ -0,0 +1,2 @@ +module HackUserLastestCodesHelper +end diff --git a/app/helpers/hacks_helper.rb b/app/helpers/hacks_helper.rb new file mode 100644 index 000000000..13f5ac76d --- /dev/null +++ b/app/helpers/hacks_helper.rb @@ -0,0 +1,2 @@ +module HacksHelper +end diff --git a/app/libs/util/uuid.rb b/app/libs/util/uuid.rb index 2f6757139..8147ff3a3 100644 --- a/app/libs/util/uuid.rb +++ b/app/libs/util/uuid.rb @@ -2,8 +2,26 @@ module Util module UUID module_function + DCODES = %W(2 3 4 5 6 7 8 9 a b c f e f g h i j k l m n o p q r s t u v w x y z) + def time_uuid(format: '%Y%m%d%H%M%S', suffix: 8) "#{Time.zone.now.strftime(format)}#{Random.rand(10**suffix).to_i}" end + + # 随机生成字符 + def generate_identifier(container, num, pre='') + code = DCODES.sample(num).join + if container == User + while container.exists?(login: pre+code) do + code = DCODES.sample(num).join + end + else + while container.exists?(identifier: code) do + code = DCODES.sample(num).join + end + end + code + end + end end diff --git a/app/models/competition.rb b/app/models/competition.rb index fa1267025..23fa268ec 100644 --- a/app/models/competition.rb +++ b/app/models/competition.rb @@ -1,4 +1,5 @@ class Competition < ApplicationRecord + belongs_to :laboratory, optional: true has_many :competition_modules, dependent: :destroy has_many :unhidden_competition_modules, -> { where(hidden: false) }, class_name: 'CompetitionModule' @@ -32,6 +33,7 @@ class Competition < ApplicationRecord has_many :competition_prizes, dependent: :destroy has_many :competition_prize_users, dependent: :destroy + before_save :set_laboratory after_create :create_competition_modules def mode_type @@ -147,9 +149,9 @@ class Competition < ApplicationRecord competition_stages.map(&:max_end_time).max end - # def awards_count - # competition_awards.pluck(:num)&.sum > 0 ? competition_awards.pluck(:num)&.sum : 20 - # end + def charts_count + competition_prizes&.pluck(:num).sum.to_i > 0 ? competition_prizes&.pluck(:num).sum.to_i : awards_count + end def manager?(user) user && competition_managers.exists?(user_id: user.id) @@ -180,4 +182,10 @@ class Competition < ApplicationRecord end end end + + def set_laboratory + return unless new_record? + + self.laboratory = Laboratory.current if laboratory_id.blank? + end end diff --git a/app/models/course.rb b/app/models/course.rb index aafc35af4..9e252b02f 100644 --- a/app/models/course.rb +++ b/app/models/course.rb @@ -7,6 +7,8 @@ class Course < ApplicationRecord belongs_to :school, class_name: 'School', foreign_key: :school_id #定义一个方法school,该方法通过school_id来调用School表 belongs_to :course_list, optional: true + belongs_to :laboratory, optional: true + # 所属实践课程 belongs_to :subject, optional: true has_many :informs, as: :container, dependent: :destroy @@ -105,6 +107,7 @@ class Course < ApplicationRecord validates :name, presence: true, length: { maximum: 60 } + before_save :set_laboratory after_create :create_board_sync, :act_as_course_activity, :send_tiding def course_member? user_id, role @@ -409,4 +412,10 @@ class Course < ApplicationRecord else 100 end end + + def set_laboratory + return unless new_record? # 新记录才需要标记 + + self.laboratory = Laboratory.current if laboratory_id.blank? + end end diff --git a/app/models/course_activity.rb b/app/models/course_activity.rb index b2ea0b146..6c0aaaf48 100644 --- a/app/models/course_activity.rb +++ b/app/models/course_activity.rb @@ -5,7 +5,7 @@ class CourseActivity < ApplicationRecord belongs_to :exercise belongs_to :poll - after_create :add_course_lead + # after_create :add_course_lead # 发布新课导语 # 导语要放置在课程创建信息之后 diff --git a/app/models/hack.rb b/app/models/hack.rb new file mode 100644 index 000000000..1256aa53f --- /dev/null +++ b/app/models/hack.rb @@ -0,0 +1,38 @@ +class Hack < ApplicationRecord + # status: 0 未发布; 1已发布 + # diffcult: 难度 1:简单;2:中等; 3:困难 + # 编程题 + validates_length_of :name, maximum: 60 + # 测试集 + has_many :hack_sets, ->{order("position asc")}, :dependent => :destroy + # 代码 + has_many :hack_codes, :dependent => :destroy + has_many :hack_user_lastest_codes, :dependent => :destroy + belongs_to :user + + scope :published, -> { where(status: 1) } + scope :opening, -> {where(open_or_not: 1)} + scope :mine, -> (author_id){ where(user_id: author_id) } + + def language + if hack_codes.count == 1 + hack_codes.first.language + else + hack_codes.pluck(:language).first + end + end + + def code + if hack_codes.count == 1 + tran_base64_decode64(hack_codes.first.code) + else + tran_base64_decode64(hack_codes.pluck(:code)) + end + end + + # 用于用户调试的第一个测试用例 + def input_test_case + hack_sets.first&.input + end + +end diff --git a/app/models/hack_code.rb b/app/models/hack_code.rb new file mode 100644 index 000000000..19de5e4a4 --- /dev/null +++ b/app/models/hack_code.rb @@ -0,0 +1,3 @@ +class HackCode < ApplicationRecord + # 编程题代码相关 +end diff --git a/app/models/hack_set.rb b/app/models/hack_set.rb new file mode 100644 index 000000000..d0518a5b4 --- /dev/null +++ b/app/models/hack_set.rb @@ -0,0 +1,4 @@ +class HackSet < ApplicationRecord + # 编程题测试集 + belongs_to :hack +end diff --git a/app/models/hack_user_code.rb b/app/models/hack_user_code.rb new file mode 100644 index 000000000..d9d2dff77 --- /dev/null +++ b/app/models/hack_user_code.rb @@ -0,0 +1,4 @@ +class HackUserCode < ApplicationRecord + # 用户编程题的信息 + belongs_to :hack +end diff --git a/app/models/hack_user_debug.rb b/app/models/hack_user_debug.rb new file mode 100644 index 000000000..d44081b52 --- /dev/null +++ b/app/models/hack_user_debug.rb @@ -0,0 +1,4 @@ +class HackUserDebug < ApplicationRecord + belongs_to :hack + belongs_to :hack_user_lastest_code +end diff --git a/app/models/hack_user_lastest_code.rb b/app/models/hack_user_lastest_code.rb new file mode 100644 index 000000000..0a9e1131c --- /dev/null +++ b/app/models/hack_user_lastest_code.rb @@ -0,0 +1,13 @@ +class HackUserLastestCode < ApplicationRecord + # passed: 用户之前评测是否通过 + # status: 最新评测状态: -1测试用例结果不匹配; 0: 评测通过; ;2 评测超时;3 创建pod失败; 4 编译失败;5 执行失败 + # submit_status: 0: 可以评测, 1:评测中 + # 编程题最新代码 + belongs_to :hack, counter_cache: true + belongs_to :user + has_many :hack_user_codes, dependent: :destroy + has_one :hack_user_debug + scope :mine, ->(author_id){ find_by(user_id: author_id) } + scope :passed, -> {where(status: 1)} + +end diff --git a/app/models/laboratory.rb b/app/models/laboratory.rb index 0c32114b0..466e6d4d8 100644 --- a/app/models/laboratory.rb +++ b/app/models/laboratory.rb @@ -9,7 +9,14 @@ class Laboratory < ApplicationRecord has_many :portal_images, dependent: :destroy has_many :laboratory_shixuns, dependent: :destroy + # has_many :shixuns, through: :laboratory_shixuns, source: :shixun + has_many :laboratory_subjects, dependent: :destroy + # has_many :subjects, through: :laboratory_subjects, source: :subject + + has_many :courses, dependent: :destroy + has_many :competitions, dependent: :destroy + has_many :libraries, dependent: :destroy validates :identifier, uniqueness: { case_sensitive: false }, allow_nil: true diff --git a/app/models/laboratory_setting.rb b/app/models/laboratory_setting.rb index ca62f5c91..416020836 100644 --- a/app/models/laboratory_setting.rb +++ b/app/models/laboratory_setting.rb @@ -15,15 +15,31 @@ class LaboratorySetting < ApplicationRecord end def login_logo_url - logo_url('login') + image_url('login') end def nav_logo_url - logo_url('nav') + image_url('nav') end def tab_logo_url - logo_url('tab') + image_url('tab') + end + + def subject_banner_url + image_url('_subject_banner') + end + + def course_banner_url + image_url('_course_banner') + end + + def competition_banner_url + image_url('_competition_banner') + end + + def moop_cases_banner_url + image_url('_moop_cases_banner') end def default_navbar @@ -32,7 +48,7 @@ class LaboratorySetting < ApplicationRecord private - def logo_url(type) + def image_url(type) return nil unless Util::FileManage.exists?(self, type) Util::FileManage.source_disk_file_url(self, type) end diff --git a/app/models/library.rb b/app/models/library.rb index e2bc20989..743959d30 100644 --- a/app/models/library.rb +++ b/app/models/library.rb @@ -3,6 +3,7 @@ class Library < ApplicationRecord belongs_to :user belongs_to :cover, class_name: 'Attachment', foreign_key: :cover_id, optional: true + belongs_to :laboratory, optional: true has_many :library_applies, dependent: :delete_all has_many :library_library_tags, dependent: :delete_all @@ -34,6 +35,13 @@ class Library < ApplicationRecord end end + before_save :set_laboratory + private def set_laboratory + return unless new_record? + + self.laboratory = Laboratory.current if laboratory_id.blank? + end + def increment_visited_count!(num = 1) increment_column!(:visited_count, num) end diff --git a/app/models/searchable/course.rb b/app/models/searchable/course.rb index a82496ad8..c11ab2220 100644 --- a/app/models/searchable/course.rb +++ b/app/models/searchable/course.rb @@ -13,6 +13,7 @@ module Searchable::Course def search_data { + laboratory_id: laboratory_id, name: name, author_name: teacher&.real_name } diff --git a/app/models/user.rb b/app/models/user.rb index ab8d8ee7b..74d9b11d2 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -30,6 +30,8 @@ class User < ApplicationRecord LOGIN_CHARS = %W(2 3 4 5 6 7 8 9 a b c f e f g h i j k l m n o p q r s t u v w x y z).freeze + belongs_to :laboratory, optional: true + has_one :user_extension, dependent: :destroy has_many :open_users, dependent: :destroy has_one :wechat_open_user, class_name: 'OpenUsers::Wechat' @@ -147,6 +149,9 @@ class User < ApplicationRecord # 客户管理 has_many :partner_managers, dependent: :destroy + # OJ编程题 + has_many :hacks, dependent: :destroy + has_many :hack_user_lastest_codes, dependent: :destroy # Groups and active users scope :active, lambda { where(status: STATUS_ACTIVE) } @@ -155,7 +160,7 @@ class User < ApplicationRecord delegate :gender, :department_id, :school_id, :location, :location_city, :technical_title, to: :user_extension, allow_nil: true - before_save :update_hashed_password + before_save :update_hashed_password, :set_laboratory after_create do SyncTrustieJob.perform_later("user", 1) if allow_sync_to_trustie? end @@ -329,6 +334,7 @@ class User < ApplicationRecord # 实训管理员:实训合作者、admin def manager_of_shixun?(shixun) + logger.info("############id: #{id}") shixun.shixun_members.exists?(role: [1,2], user_id: id) || admin? || business? end @@ -704,6 +710,12 @@ class User < ApplicationRecord raise('密码长度不能超过16位') end end + + def set_laboratory + return unless new_record? + + self.laboratory = Laboratory.current if laboratory_id.blank? + end end diff --git a/app/models/user_extension.rb b/app/models/user_extension.rb index 0a2249308..916404c88 100644 --- a/app/models/user_extension.rb +++ b/app/models/user_extension.rb @@ -6,7 +6,17 @@ class UserExtension < ApplicationRecord belongs_to :school, optional: true belongs_to :department, optional: true + before_save :set_laboratory_school + def identity_text I18n.t("user.identity.#{identity}") end + + private + + def set_laboratory_school + return unless new_record? + + self.school_id = Laboratory.current.school_id if school_id.blank? && !Laboratory.current.main_site? + end end diff --git a/app/queries/admins/user_query.rb b/app/queries/admins/user_query.rb index 749ba2110..cdf158c67 100644 --- a/app/queries/admins/user_query.rb +++ b/app/queries/admins/user_query.rb @@ -12,6 +12,9 @@ class Admins::UserQuery < ApplicationQuery def call users = User.where(type: 'User') + # 云上实验室 + users = users.where(laboratory_id: params[:laboratory_id]) if params[:laboratory_id].present? + # 状态 status = params[:status] users = users.where(status: status) if status.present? diff --git a/app/services/admins/save_laboratory_setting_service.rb b/app/services/admins/save_laboratory_setting_service.rb index f2a5c151e..b35323608 100644 --- a/app/services/admins/save_laboratory_setting_service.rb +++ b/app/services/admins/save_laboratory_setting_service.rb @@ -17,7 +17,7 @@ class Admins::SaveLaboratorySettingService < ApplicationService laboratory.save! laboratory_setting.save! - deal_logo_file + deal_image_file end laboratory @@ -35,13 +35,17 @@ class Admins::SaveLaboratorySettingService < ApplicationService 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') + def deal_image_file + save_image_file(params[:nav_logo], 'nav') + save_image_file(params[:login_logo], 'login') + save_image_file(params[:tab_logo], 'tab') + save_image_file(params[:subject_banner], '_subject_banner') + save_image_file(params[:course_banner], '_course_banner') + save_image_file(params[:competition_banner], '_competition_banner') + save_image_file(params[:moop_cases_banner], '_moop_cases_banner') end - def save_logo_file(file, type) + def save_image_file(file, type) return unless file.present? && file.is_a?(ActionDispatch::Http::UploadedFile) file_path = Util::FileManage.source_disk_filename(laboratory_setting, type) diff --git a/app/services/search_service.rb b/app/services/search_service.rb index 418021cc0..350048c2e 100644 --- a/app/services/search_service.rb +++ b/app/services/search_service.rb @@ -8,34 +8,57 @@ class SearchService < ApplicationService end def call - Searchkick.search(keyword, search_options) + # return [] if keyword.blank? + + modal_name.search(keyword, search_options) end private + def modal_name + @_modal_name ||= + case params[:type].to_s.strip + when 'shixun' then Shixun + when 'course' then Course + when 'subject' then Subject + when 'memo' then Memo + else Shixun + end + end + def search_options model_options = { - index_name: index_names, - model_includes: model_includes + includes: modal_name.searchable_includes } - model_options.merge(where: { status: 2 }) if index_names == [Shixun] - model_options.merge(default_options) - end + model_options.deep_merge!(where: { status: 2 }) if modal_name == Shixun + model_options.deep_merge!(extra_options) - def index_names - @_index_names ||= - case params[:type].to_s.strip - when 'shixun' then [Shixun] - when 'course' then [Course] - when 'subject' then [Subject] - when 'memo' then [Memo] - else [Shixun, Course, Subject, Memo] - end + model_options.deep_merge!(default_options) + model_options end - def model_includes - index_names.each_with_object({}) do |klass, obj| - obj[klass] = klass.searchable_includes + def extra_options + case params[:type].to_s.strip + when 'shixun' then + if Laboratory.current.main_site? + not_shixun_ids = Shixun.joins(:laboratory_shixuns).where("laboratory_shixuns.laboratory_id != #{Laboratory.current.id}") + shixun_ids = Shixun.where.not(id: not_shixun_ids).pluck(:id) + else + shixun_ids = Laboratory.current.shixuns.pluck(:id) + end + { where: { id: shixun_ids } } + when 'subject' then + if Laboratory.current.main_site? + not_subject_ids = Subject.joins(:laboratory_subjects).where("laboratory_subjects.laboratory_id != #{Laboratory.current.id}") + subject_ids = Subject.where.not(id: not_subject_ids).pluck(:id) + else + subject_ids = Laboratory.current.subjects.pluck(:id) + end + { where: { id: subject_ids } } + when 'course' then + { where: { laboratory_id: Laboratory.current.id } } + else + {} end end end \ No newline at end of file diff --git a/app/services/shixun_search_service.rb b/app/services/shixun_search_service.rb index 911f341f8..63e10d6b0 100644 --- a/app/services/shixun_search_service.rb +++ b/app/services/shixun_search_service.rb @@ -1,10 +1,11 @@ class ShixunSearchService < ApplicationService include ElasticsearchAble - attr_reader :params + attr_reader :params, :laboratory - def initialize(params) + def initialize(params, laboratory) @params = params + @laboratory = laboratory end def call @@ -35,6 +36,17 @@ class ShixunSearchService < ApplicationService @shixuns = @shixuns.where(trainee: params[:diff]) end + ## 云上实验室过滤 + if laboratory.main_site? + not_shixun_ids = Shixun.joins(:laboratory_shixuns).where("laboratory_shixuns.laboratory_id != #{laboratory.id}") + @shixuns = @shixuns.where.not(id: not_shixun_ids) + else + @shixuns = @shixuns.joins(:laboratory_shixuns).where(laboratory_shixuns: { laboratory_id: laboratory.id }) + end + + # laboratory = Laboratory.find_by_subdomain(subdomain) + # @shixuns = @shixuns.where(id: laboratory.shixuns) if laboratory + Shixun.search(keyword, search_options) end diff --git a/app/services/subject_search_service.rb b/app/services/subject_search_service.rb index f69c56c88..101a31085 100644 --- a/app/services/subject_search_service.rb +++ b/app/services/subject_search_service.rb @@ -1,10 +1,11 @@ class SubjectSearchService < ApplicationService include ElasticsearchAble - attr_reader :params + attr_reader :params, :laboratory - def initialize(params) + def initialize(params, laboratory) @params = params + @laboratory = laboratory end def call @@ -17,6 +18,17 @@ class SubjectSearchService < ApplicationService @subjects = Subject.visible.unhidden end + # laboratory = Laboratory.find_by_subdomain(subdomain) + # @subjects = @subjects.where(id: laboratory.subjects) if laboratory + + ## 云上实验室过滤 + if laboratory.main_site? + not_subject_ids = Subject.joins(:laboratory_subjects).where("laboratory_subjects.laboratory_id != #{laboratory.id}") + @subjects = @subjects.where.not(id: not_subject_ids) + else + @subjects = @subjects.joins(:laboratory_subjects).where(laboratory_subjects: { laboratory_id: laboratory.id }) + end + Subject.search(keyword, search_options) end diff --git a/app/services/subjects/copy_subject_service.rb b/app/services/subjects/copy_subject_service.rb new file mode 100644 index 000000000..5f8481cae --- /dev/null +++ b/app/services/subjects/copy_subject_service.rb @@ -0,0 +1,217 @@ +class Subjects::CopySubjectService < ApplicationService + attr_reader :subject, :to_subject, :user, :laboratory + + def initialize(subject, user, laboratory=nil) + @subject = subject + @user = user + @laboratory = laboratory + subject_params = subject.attributes.dup.except('id', 'copy_subject_id', 'user_id', 'homepage_show') + @to_subject = Subject.new(subject_params) + end + + def call + return if subject.blank? + ActiveRecord::Base.transaction do + copy_subject! + end + end + + + private + # 复制实践课程表 + def copy_subject! + to_subject.copy_subject_id = subject.id + to_subject.user_id = user.id + to_subject.save! + + copy_stages_data!(subject, to_subject) + copy_subject_members_data(to_subject) + laboratory.laboratory_subjects.create(subject: to_subject) if laboratory + end + + # 复制章节需要的章节 + def copy_stages_data!(subject, to_subject) + subject.stages.each do |stage| + to_stage = to_subject.stages.new + to_stage.attributes = stage.attributes.dup.except('id', 'subject_id', 'user_id') + to_stage.user_id = user.id + to_stage.save! + + copy_stage_shixuns_data!(stage, to_stage) + end + end + + # 创建实践课程关联实训表 + def copy_stage_shixuns_data!(stage, to_stage) + stage.stage_shixuns.each do |stage_shixun| + to_shixun = copy_shixun_data!(stage_shixun) + to_stage_shixun = to_stage.stage_shixuns.new + to_stage_shixun.attributes = stage_shixun.attributes.dup.except('id', 'subject_id', 'stage_id', 'shixun_id') + to_stage_shixun.subject_id = to_stage.subject_id + to_stage_shixun.shixun_id = to_shixun.id + to_stage_shixun.save! + + end + end + + # 复制实训数据 + def copy_shixun_data!(stage_shixun) + shixun = stage_shixun.shixun + to_shixun = Shixun.new + to_shixun.attributes = shixun.attributes.dup.except('id', 'user_id', 'identifier', 'homepage_show', + 'use_scope', 'averge_star', 'myshixuns_count') + to_shixun.identifier = Util::UUID.generate_identifier(Shixun, 8) + to_shixun.user_id = user.id + if laboratory + to_shixun.laboratory_id = laboratory.id + end + # 复制版本库 + fork_repository_name = "#{user.login}/#{to_shixun.identifier}" + GitService.fork_repository(repo_path: "#{shixun.repo_name}.git", + fork_repository_path: (fork_repository_name + ".git")) + to_shixun.repo_name = fork_repository_name + to_shixun.save! + + copy_shixun_info_data!(shixun, to_shixun) + copy_shixun_mirror_repositories_data!(shixun, to_shixun) + copy_shixun_tag_repertoires_data!(shixun, to_shixun) + copy_shixun_service_configs_data!(shixun, to_shixun) + copy_challenges_data!(shixun, to_shixun) + copy_shixun_members_data!(to_shixun) + + # 云上实验室 + if laboratory + laboratory.laboratory_shixuns.create(shixun: to_shixun) + end + to_shixun + end + + # 创建实训长字段内容 + def copy_shixun_info_data!(shixun, to_shixun) + to_shixun_info = ShixunInfo.new + to_shixun_info.attributes = shixun.shixun_info.attributes.except('id', 'shixun_id') + to_shixun_info.shixun_id = to_shixun.id + to_shixun_info.save! + end + + # 创建实训镜像标签 + def copy_shixun_mirror_repositories_data!(shixun, to_shixun) + shixun.shixun_mirror_repositories.each do |shixun_mirror_repository| + to_shixun_mirror_repository = to_shixun.shixun_mirror_repositories.new + to_shixun_mirror_repository.attributes = shixun_mirror_repository.attributes.dup.except('id', 'shixun_id') + to_shixun_mirror_repository.shixun_id = to_shixun.id + to_shixun_mirror_repository.save! + end + end + + # 创建实训tag标签 + def copy_shixun_tag_repertoires_data!(shixun, to_shixun) + shixun.shixun_tag_repertoires.each do |shixun_tag_repertoire| + to_shixun_tag_repertoire = to_shixun.shixun_tag_repertoires.new + to_shixun_tag_repertoire.attributes = shixun_tag_repertoire.attributes.dup.except('id', 'shixun_id') + to_shixun_tag_repertoire.shixun_id = to_shixun.id + to_shixun_tag_repertoire.save! + end + end + + # 复制实训服务配置 + def copy_shixun_service_configs_data!(shixun, to_shixun) + shixun.shixun_service_configs.each do |shixun_service_config| + to_shixun_service_config = to_shixun.shixun_service_configs.new + to_shixun_service_config.attributes = shixun_service_config.attributes.dup.except('id', 'shixun_id') + to_shixun_service_config.shixun_id = to_shixun.id + to_shixun_service_config.save! + end + end + + # 复制关卡信息 + def copy_challenges_data!(shixun, to_shixun) + shixun.challenges.each do |challenge| + to_challenge = to_shixun.challenges.new + to_challenge.attributes = challenge.attributes.dup.except('id', 'shixun_id', 'praises_count', 'user_id', 'visits') + to_challenge.user_id = user.id + to_challenge.shixun_id = to_shixun.id + to_challenge.save! + + copy_challenge_answers_data!(challenge, to_challenge) + copy_challenge_tags_data!(challenge, to_challenge) + copy_test_sets_data!(challenge, to_challenge) + copy_challenge_chooses_data!(challenge, to_challenge) + end + end + + # 复制答案数据 + def copy_challenge_answers_data!(challenge, to_challenge) + challenge.challenge_answers.each do |challenge_answer| + to_challenge_answer = to_challenge.challenge_answers.new + to_challenge_answer.attributes = challenge_answer.attributes.dup.except('id', 'challenge_id') + to_challenge_answer.challenge_id = to_challenge.id + to_challenge_answer.save! + end + end + + # 复制关卡标签数据 + def copy_challenge_tags_data!(challenge, to_challenge) + challenge.challenge_tags.each do |challenge_tag| + to_challenge_tag = to_challenge.challenge_tags.new + to_challenge_tag.attributes = challenge_tag.attributes.dup.except('id', 'challenge_id') + to_challenge_tag.challenge_id = to_challenge.id + to_challenge_tag.save! + end + end + + # 复制测试集 + def copy_test_sets_data!(challenge, to_challenge) + challenge.test_sets.each do |test_set| + to_test_set = to_challenge.test_sets.new + to_test_set.attributes = test_set.attributes.dup.except('id', 'challenge_id') + to_test_set.challenge_id = to_challenge.id + to_test_set.save! + end + end + + # 复制选择题关卡 + def copy_challenge_chooses_data!(challenge, to_challenge) + challenge.challenge_chooses.each do |challenge_choose| + to_challenge_choose = to_challenge.challenge_chooses.new + to_challenge_choose.attributes = challenge_choose.attributes.dup.except('id', 'challenge_id') + to_challenge_choose.challenge_id = to_challenge.id + to_challenge_choose.save! + + copy_challenge_questions_data!(challenge_choose, to_challenge_choose) + copy_challenge_choose_tags_data!(challenge_choose, to_challenge_choose) + + end + end + + # 复制选择题问题 + def copy_challenge_questions_data!(challenge_choose, to_challenge_choose) + challenge_choose.challenge_questions.each do |challenge_question| + to_challenge_question = to_challenge_choose.challenge_questions.new + to_challenge_question.attributes = challenge_question.attributes.dup.except('id', 'challenge_choose_id') + to_challenge_question.challenge_choose_id = to_challenge_choose.id + to_challenge_question.save! + end + end + + # 复制选择题标签 + def copy_challenge_choose_tags_data!(challenge_choose, to_challenge_choose) + challenge_choose.challenge_tags.each do |challenge_tag| + to_challenge_tag = to_challenge_choose.challenge_tags.new + to_challenge_tag.attributes = challenge_tag.attributes.dup.except('id', 'challenge_choose_id') + to_challenge_tag.challenge_choose_id = to_challenge_choose.id + to_challenge_tag.save! + end + end + + # 创建实训成员 + def copy_shixun_members_data!(to_shixun) + to_shixun.shixun_members.create!(user_id: user.id, role: 1) + end + + # 创建课程成员 + def copy_subject_members_data(to_subject) + to_subject.subject_members.create!(user_id: user.id, role: 1) + end + +end diff --git a/app/services/weapps/create_course_service.rb b/app/services/weapps/create_course_service.rb new file mode 100644 index 000000000..196533bb6 --- /dev/null +++ b/app/services/weapps/create_course_service.rb @@ -0,0 +1,37 @@ +class Weapps::CreateCourseService < ApplicationService + attr_reader :course, :params + + def initialize(course, params) + @course = course + @params = params + end + + def call + Weapps::CreateCourseForm.new(form_params).validate! + + ActiveRecord::Base.transaction do + course.name = params[:name].to_s.strip + course.school_id = course.teacher&.school_id + course.is_public = 0 + course.credit = params[:credit].blank? ? nil : params[:credit] + course_list = CourseList.find_by(name: params[:course_list_name].to_s.strip) + if course_list + course.course_list_id = course_list.id + else + new_course_list = CourseList.create!(name: params[:course_list_name].to_s.strip, user_id: course.tea_id, is_admin: 0) + course.course_list_id = new_course_list.id + end + course.save! + + course.generate_invite_code + CourseMember.create!(course_id: course.id, user_id: course.tea_id, role: 1) + course.create_course_modules(params[:course_module_types]) + end + end + + private + + def form_params + params.merge(course: course) + end +end \ No newline at end of file diff --git a/app/services/weapps/update_course_service.rb b/app/services/weapps/update_course_service.rb new file mode 100644 index 000000000..4f2fa4676 --- /dev/null +++ b/app/services/weapps/update_course_service.rb @@ -0,0 +1,31 @@ +class Weapps::UpdateCourseService < ApplicationService + attr_reader :course, :params + + def initialize(course, params) + @course = course + @params = params + end + + def call + Weapps::UpdateCourseForm.new(form_params).validate! + + ActiveRecord::Base.transaction do + course.name = params[:name].to_s.strip + course.credit = params[:credit].blank? ? nil : params[:credit] + course_list = CourseList.find_by(name: params[:course_list_name].to_s.strip) + if course_list + course.course_list_id = course_list.id + else + new_course_list = CourseList.create!(name: params[:course_list_name].to_s.strip, user_id: course.tea_id, is_admin: 0) + course.course_list_id = new_course_list.id + end + course.save! + end + end + + private + + def form_params + params.merge(course: course) + end +end \ No newline at end of file diff --git a/app/views/admins/identity_authentications/shared/_list.html.erb b/app/views/admins/identity_authentications/shared/_list.html.erb index e1c603215..607feb93a 100644 --- a/app/views/admins/identity_authentications/shared/_list.html.erb +++ b/app/views/admins/identity_authentications/shared/_list.html.erb @@ -43,6 +43,9 @@ <%= link_to "/users/#{user.login}", class: 'identity-authentication-avatar', target: '_blank', data: { toggle: 'tooltip', title: '个人主页' } do %> <% end %> + <% if user.from_sub_site? %> + 合作 + <% end %> <%= user.real_name %> <%= user.ID_number %> diff --git a/app/views/admins/laboratory_settings/show.html.erb b/app/views/admins/laboratory_settings/show.html.erb index a30ec8b71..b99d6f022 100644 --- a/app/views/admins/laboratory_settings/show.html.erb +++ b/app/views/admins/laboratory_settings/show.html.erb @@ -86,6 +86,52 @@ +
+
Banner设置
+ +
+ + + + + + + +
+
+
导航设置
diff --git a/app/views/admins/professional_authentications/shared/_list.html.erb b/app/views/admins/professional_authentications/shared/_list.html.erb index 0bf8ea4a3..6ec6355ba 100644 --- a/app/views/admins/professional_authentications/shared/_list.html.erb +++ b/app/views/admins/professional_authentications/shared/_list.html.erb @@ -41,6 +41,9 @@ <%= link_to "/users/#{user.login}", class: 'professional-authentication-avatar', target: '_blank', data: { toggle: 'tooltip', title: '个人主页' } do %> <% end %> + <% if user.from_sub_site? %> + 合作 + <% end %> <%= user.real_name %> <%= raw [user.school_name.presence, user.department_name.presence].compact.join('
') %> diff --git a/app/views/competitions/competitions/common_header.json.jbuilder b/app/views/competitions/competitions/common_header.json.jbuilder index 0d0f3f4ca..8c89e2de2 100644 --- a/app/views/competitions/competitions/common_header.json.jbuilder +++ b/app/views/competitions/competitions/common_header.json.jbuilder @@ -31,6 +31,6 @@ if @competition.mode == 2 end json.permission do - json.editable @user.admin_or_business? || (@competition.nearly_published? && @competition.manager?(@user)) + json.editable @user.admin_or_business? || @competition.manager?(@user) end diff --git a/app/views/competitions/competitions/index.json.jbuilder b/app/views/competitions/competitions/index.json.jbuilder index b7a3f20e0..2640c535e 100644 --- a/app/views/competitions/competitions/index.json.jbuilder +++ b/app/views/competitions/competitions/index.json.jbuilder @@ -30,7 +30,7 @@ json.competitions do # end json.permission do - json.editable current_user.admin_or_business? || (competition.nearly_published? && competition.manager?(current_user)) + json.editable current_user.admin_or_business? || competition.manager?(current_user) end end end \ No newline at end of file diff --git a/app/views/cooperative/carousels/index.html.erb b/app/views/cooperative/carousels/index.html.erb index 4b7c0bcc5..5f8957865 100644 --- a/app/views/cooperative/carousels/index.html.erb +++ b/app/views/cooperative/carousels/index.html.erb @@ -12,7 +12,7 @@