diff --git a/app/assets/javascripts/common.js b/app/assets/javascripts/common.js index 8ff5c7bb7..66158b17e 100644 --- a/app/assets/javascripts/common.js +++ b/app/assets/javascripts/common.js @@ -64,4 +64,12 @@ function customConfirm(opts){ } } return $.confirm($.extend({}, defaultOpts, opts)) +} + +function show_success_flash(){ + $.notify({ + message: '操作成功' + },{ + type: 'success' + }); } \ No newline at end of file diff --git a/app/assets/javascripts/cooperative.js b/app/assets/javascripts/cooperative.js new file mode 100644 index 000000000..77e0477eb --- /dev/null +++ b/app/assets/javascripts/cooperative.js @@ -0,0 +1,91 @@ +//= require rails-ujs +//= require activestorage +//= require turbolinks +//= require jquery3 +//= require popper +//= require bootstrap-sprockets +//= require jquery.validate.min +//= require additional-methods.min +//= require bootstrap-notify +//= require jquery.cookie.min +//= require select2 +//= require jquery.cxselect +//= require bootstrap-datepicker +//= require bootstrap.viewer +//= require jquery.mloading +//= require jquery-confirm.min +//= require common + +//= require echarts +//= require codemirror/lib/codemirror +//= require codemirror/mode/shell/shell +//= require editormd/editormd +//= require editormd/languages/zh-tw +//= require dragula/dragula + +//= require_tree ./i18n +//= require_tree ./cooperative + + +$.ajaxSetup({ + beforeSend: function(xhr) { + xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content')); + } +}); + +// ******** select2 global config ******** +$.fn.select2.defaults.set('theme', 'bootstrap4'); +$.fn.select2.defaults.set('language', 'zh-CN'); + +Turbolinks.setProgressBarDelay(200); + +$.notifyDefaults({ + type: 'success', + z_index: 9999, + delay: 2000 +}); + +$(document).on('turbolinks:load', function(){ + $('[data-toggle="tooltip"]').tooltip({ trigger : 'hover' }); + $('[data-toggle="popover"]').popover(); + + // 图片查看大图 + $('img.preview-image').bootstrapViewer(); + + // flash alert提示框自动关闭 + if($('.cooperative-alert-container .alert').length > 0){ + setTimeout(function(){ + $('.cooperative-alert-container .alert:not(.alert-danger)').alert('close'); + }, 2000); + setTimeout(function(){ + $('.cooperative-alert-container .alert.alert-danger').alert('close'); + }, 5000); + } +}); + +$(document).on("turbolinks:before-cache", function () { + $('[data-toggle="tooltip"]').tooltip('hide'); + $('[data-toggle="popover"]').popover('hide'); +}); +// var progressBar = new Turbolinks.ProgressBar(); + +// $(document).on('ajax:send', function(event){ +// console.log('ajax send', event); +// progressBar.setValue(0) +// progressBar.show() +// }); +// +// $(document).on('ajax:complete', function(event){ +// console.log('ajax complete', event); +// progressBar.setValue(1) +// progressBar.hide() // 分页时不触发,奇怪 +// }); +// $(document).on('ajax:success', function(event){ +// console.log('ajax success', event); +// }); +// $(document).on('ajax:error', function(event){ +// console.log('ajax error', event); +// }); + +$(function () { +}); diff --git a/app/assets/javascripts/cooperative/laboratory_settings/edit.js b/app/assets/javascripts/cooperative/laboratory_settings/edit.js new file mode 100644 index 000000000..50bb96ac9 --- /dev/null +++ b/app/assets/javascripts/cooperative/laboratory_settings/edit.js @@ -0,0 +1,86 @@ +$(document).on('turbolinks:load', function() { + if ($('body.cooperative-laboratory-settings-edit-page, body.cooperative-laboratory-settings-update-page').length > 0) { + var $container = $('.edit-laboratory-setting-container'); + var $form = $container.find('.edit_laboratory'); + + $('.logo-item-left').on("change", 'input[type="file"]', function () { + var $fileInput = $(this); + var file = this.files[0]; + var imageType = /image.*/; + if (file && file.type.match(imageType)) { + var reader = new FileReader(); + reader.onload = function () { + var $box = $fileInput.parent(); + $box.find('img').attr('src', reader.result).css('display', 'block'); + $box.addClass('has-img'); + }; + reader.readAsDataURL(file); + } else { + } + }); + + createMDEditor('laboratory-footer-editor', { height: 200, placeholder: '请输入备案信息' }); + + $form.validate({ + errorElement: 'span', + errorClass: 'danger text-danger', + errorPlacement:function(error,element){ + if(element.parent().hasClass("input-group")){ + element.parent().after(error); + }else{ + element.after(error) + } + }, + rules: { + identifier: { + required: true, + checkSite: true + }, + name: { + required: true + } + } + }); + $.validator.addMethod("checkSite",function(value,element,params){ + var checkSite = /^(?=^.{3,255}$)[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+$/; + return this.optional(element)||(checkSite.test(value + '.educoder.com')); + },"域名不合法!"); + + $form.on('click', '.submit-btn', function(){ + $form.find('.submit-btn').attr('disabled', 'disabled'); + $form.find('.error').html(''); + var valid = $form.valid(); + + $('input[name="navbar[][name]"]').each(function(_, e){ + var $ele = $(e); + if($ele.val() === undefined || $ele.val().length === 0){ + $ele.addClass('danger text-danger'); + valid = false; + } else { + $ele.removeClass('danger text-danger'); + } + }); + + if(!valid) return; + $.ajax({ + method: 'PATCH', + dataType: 'json', + url: $form.attr('action'), + data: new FormData($form[0]), + processData: false, + contentType: false, + success: function(data){ + $.notify({ message: '保存成功' }); + window.location.reload(); + }, + error: function(res){ + var data = res.responseJSON; + $form.find('.error').html(data.message); + }, + complete: function(){ + $form.find('.submit-btn').attr('disabled', false); + } + }); + }) + } +}); \ No newline at end of file diff --git a/app/assets/javascripts/cooperative/sidebar.js b/app/assets/javascripts/cooperative/sidebar.js new file mode 100644 index 000000000..dea677d54 --- /dev/null +++ b/app/assets/javascripts/cooperative/sidebar.js @@ -0,0 +1,16 @@ +$(document).on('turbolinks:load', function(){ + $('#sidebarCollapse').on('click', function () { + $(this).toggleClass('active'); + $('#sidebar').toggleClass('active'); + $.cookie('cooperative_sidebar_collapse', $(this).hasClass('active'), {path: '/cooperative'}); + }); + + var sidebarController = $('#sidebar').data('current-controller'); + if (sidebarController.length > 0) { + $('#sidebar a.active').removeClass('active'); + $('#sidebar ul.collapse.show').removeClass('show'); + var activeLi = $('#sidebar a[data-controller="' + sidebarController + '"]'); + activeLi.addClass('active'); + activeLi.parent().parent('ul.collapse').addClass('show'); + } +}); \ No newline at end of file diff --git a/app/assets/stylesheets/admins/laboratories.scss b/app/assets/stylesheets/admins/laboratories.scss index ad5c8c5a8..69f4586d1 100644 --- a/app/assets/stylesheets/admins/laboratories.scss +++ b/app/assets/stylesheets/admins/laboratories.scss @@ -31,6 +31,7 @@ display: block; width: 80px; height: 80px; + background: #f0f0f0; } &-upload { diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css deleted file mode 100644 index fad1eb25d..000000000 --- a/app/assets/stylesheets/application.css +++ /dev/null @@ -1,16 +0,0 @@ -/* - * This is a manifest file that'll be compiled into application.css, which will include all the files - * listed below. - * - * Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's - * vendor/assets/stylesheets directory can be referenced here using a relative path. - * - * You're free to add application-wide styles to this file and they'll appear at the bottom of the - * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS - * files in this directory. Styles in this file should be added after the last require_* statement. - * It is generally better to create a new file per style scope. - * - *= require_tree . - *= require_self - - */ diff --git a/app/assets/stylesheets/cooperative.scss b/app/assets/stylesheets/cooperative.scss new file mode 100644 index 000000000..56984b96b --- /dev/null +++ b/app/assets/stylesheets/cooperative.scss @@ -0,0 +1,54 @@ +@import "bootstrap"; +@import "font-awesome-sprockets"; +@import "font-awesome"; +@import "select2.min"; +@import "select2-bootstrap4.min"; +@import "bootstrap-datepicker"; +@import "bootstrap-datepicker.standalone"; +@import "jquery.mloading"; +@import "jquery-confirm.min"; + +@import "codemirror/lib/codemirror"; +@import "editormd/css/editormd.min"; +@import "dragula/dragula"; + +@import "common"; +@import "cooperative/*"; + +body { + width: 100vw; + height: 100vh; + max-width: 100vw; + max-height: 100vh; + display: flex; + align-items: stretch; + font-size: 14px; + background: #efefef; + overflow: hidden; +} + +.simple_form { + .form-group { + .collection_radio_buttons { + margin-bottom: 0px; + } + + .form-check-inline { + height: calc(1.5em + 0.75rem + 2px) + } + } +} + +input.form-control { + font-size: 14px; +} + +.btn-default{ + color: #666; + background: #e1e1e1!important; +} +.export-absolute{ + right:20px; + position: absolute; +} + diff --git a/app/assets/stylesheets/cooperative/common.scss b/app/assets/stylesheets/cooperative/common.scss new file mode 100644 index 000000000..488dd4caa --- /dev/null +++ b/app/assets/stylesheets/cooperative/common.scss @@ -0,0 +1,126 @@ +.cooperative-body-container { + padding: 20px; + flex: 1; + min-height: 100vh; + display: flex; + flex-direction: column; + overflow-y: scroll; + + & > .content { + flex: 1; + font-size: 14px; + + .box { + padding: 20px; + border-radius: 5px; + background: #fff; + } + } + + /* 面包屑 */ + .breadcrumb { + padding-left: 5px; + font-size: 20px; + background: unset; + } + + /* 内容表格 */ + table { + table-layout: fixed; + + td { + vertical-align: middle; + } + + tr { + &.no-data { + &:hover { + color: darkgrey; + background: unset; + } + + & > td { + text-align: center; + height: 300px; + } + } + } + } + + .action-container { + & > .action { + padding: 0 3px; + } + + .more-action-dropdown { + .dropdown-item { + font-size: 14px; + } + } + } + + /* 分页 */ + .paginate-container { + margin-top: 20px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + + .paginate-total { + margin-bottom: 10px; + color: darkgrey; + } + + .pagination { + margin-bottom: 0px; + } + } + + /* 搜索表单 */ + .search-form-container { + display: flex; + margin-bottom: 20px; + + .search-form { + flex: 1; + + * { font-size: 14px; } + + select, input { + margin-right: 10px; + font-size: 14px; + } + } + } + + .global-error { + color: grey; + min-height: 300px; + + &-code { + font-size: 80px; + } + + &-text { + font-size: 24px; + } + } + + .nav-tabs { + .nav-link { + padding: 0.5rem 2rem; + } + } + + .CodeMirror { + border: 1px solid #ced4da; + } + + .batch-action-container { + margin-bottom: -15px; + padding: 10px 20px 0; + background: #fff; + } +} + diff --git a/app/assets/stylesheets/cooperative/laboratory_settings.scss b/app/assets/stylesheets/cooperative/laboratory_settings.scss new file mode 100644 index 000000000..fde0cddc3 --- /dev/null +++ b/app/assets/stylesheets/cooperative/laboratory_settings.scss @@ -0,0 +1,76 @@ +.cooperative-laboratory-settings-edit-page, .cooperative-laboratory-settings-update-page { + .edit-laboratory-setting-container { + .logo-item { + display: flex; + + &-img { + display: block; + width: 80px; + height: 80px; + background: #f0f0f0; + } + + &-upload { + cursor: pointer; + position: absolute; + top: 0; + width: 80px; + height: 80px; + background: #F5F5F5; + border: 1px solid #E5E5E5; + + &::before { + content: ''; + position: absolute; + top: 27px; + left: 39px; + width: 2px; + height: 26px; + background: #E5E5E5; + } + + &::after { + content: ''; + position: absolute; + top: 39px; + left: 27px; + width: 26px; + height: 2px; + background: #E5E5E5; + } + } + + &-left { + position: relative; + width: 80px; + height: 80px; + + &.has-img { + .logo-item-upload { + display: none; + } + + &:hover { + .logo-item-upload { + display: block; + background: rgba(145, 145, 145, 0.8); + } + } + } + } + + &-right { + display: flex; + flex-direction: column; + justify-content: space-between; + color: #777777; + font-size: 12px; + } + + &-title { + color: #23272B; + font-size: 14px; + } + } + } +} \ No newline at end of file diff --git a/app/assets/stylesheets/cooperative/sidebar.scss b/app/assets/stylesheets/cooperative/sidebar.scss new file mode 100644 index 000000000..e943acd90 --- /dev/null +++ b/app/assets/stylesheets/cooperative/sidebar.scss @@ -0,0 +1,235 @@ +#sidebar { + min-width: 200px; + max-width: 200px; + background: #272822; + color: #fff; + transition: all 0.5s; + overflow-y: scroll; + + &::-webkit-scrollbar { + display:none + } + + &.active { + min-width: 60px; + max-width: 60px; + text-align: center; + + .sidebar-header { + padding: 10px; + display: flex; + flex-direction: column; + + &-logo { + overflow: hidden; + margin-bottom: 10px; + + & > .logo-label { + display: none; + } + } + } + + ul li a { + padding: 10px; + text-align: center; + font-size: 0.85em; + display: flex; + justify-content: center; + + span { display: none } + + i { + margin-right: 0; + display: block; + font-size: 1.8em; + margin-bottom: 5px; + width: 30px; + height: 20px; + } + } + + .dropdown-toggle::after { + top: auto; + bottom: 10px; + right: 50%; + -webkit-transform: translateX(50%); + -ms-transform: translateX(50%); + transform: translateX(50%); + } + + ul ul a { + padding: 10px !important; + + span { display: none } + + i { + margin-left: 0px; + display: block; + font-size: 0.8em; + width: 30px; + height: 10px; + } + } + } + + .sidebar-header { + padding: 20px; + background: #272822; + display: flex; + flex-direction: row; + justify-content: space-between; + + &-logo { + display: flex; + justify-content: space-between; + align-items: center; + + & > img { + width: 40px; + height: auto; + } + + & > .logo-label { + font-size: 18px; + color: darkgrey; + margin-left: 10px; + } + } + } + + #sidebarCollapse { + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + text-align: right; + + &.active { + width: 40px; + height: 30px; + background: #3f3f3f; + border: 1px solid grey; + border-radius: 3px; + + i.fold { display: none; } + i.unfold { display: block; } + } + + i.fold { + display: block; + } + i.unfold { display: none; } + } + + a, a:hover, a:focus { + color: inherit; + text-decoration: none; + transition: all 0.3s; + } + + & > ul > li > a > i { + width: 14px; + height: 14px; + } + + ul { + &.components { + padding: 20px 0; + border-bottom: 1px solid #3f3f3f; + } + + p { + color: #fff; + padding: 10px; + } + + li > a { + padding: 10px; + font-size: 1em; + display: block; + text-align: left; + + i { + margin-right: 10px; + font-size: 1em; + margin-bottom: 5px; + } + } + + li a { + &:hover, &.active { + color: #fff; + background: #276891; + } + } + + li.active > a, a[aria-expanded="true"] { + color: #fff; + //background: #276891; + } + + ul a { + font-size: 0.9em !important; + padding-left: 30px !important; + background: #3f3f3f; + } + } +} + +@media (max-width: 768px) { + #sidebar { + &.active { + padding: 10px 5px; + min-width: 40px; + max-width: 40px; + text-align: center; + margin-left: 0; + transform: none; + + .sidebar-header { + padding: 0px; + + .sidebar-header-logo { + display: none; + } + + #sidebarCollapse { + width: 30px; + height: 20px; + } + } + + ul li a { + padding: 10px; + font-size: 0.85em; + + i { + margin-right: 0; + display: block; + margin-bottom: 5px; + } + } + + & > ul > li > a > i { + font-size: 1.8em; + } + + ul ul a { + padding: 10px !important; + } + } + + .sidebar-header { + } + } + + .dropdown-toggle::after { + top: auto; + bottom: 10px; + right: 50%; + -webkit-transform: translateX(50%); + -ms-transform: translateX(50%); + transform: translateX(50%); + } +} diff --git a/app/controllers/admins/base_controller.rb b/app/controllers/admins/base_controller.rb index 345df3e31..e2e3babae 100644 --- a/app/controllers/admins/base_controller.rb +++ b/app/controllers/admins/base_controller.rb @@ -1,7 +1,7 @@ class Admins::BaseController < ApplicationController - include Admins::PaginateHelper + include Base::PaginateHelper include Admins::RenderHelper - include Admins::ErrorRescueHandler + include Base::ErrorRescueHandler layout 'admin' diff --git a/app/controllers/concerns/admins/render_helper.rb b/app/controllers/concerns/admins/render_helper.rb index 0f136b62d..a43a094d3 100644 --- a/app/controllers/concerns/admins/render_helper.rb +++ b/app/controllers/concerns/admins/render_helper.rb @@ -1,39 +1,7 @@ module Admins::RenderHelper extend ActiveSupport::Concern - def render_by_format(hash) - format = request.format.symbol - hash.key?(format) ? hash[format].call : hash[:html].call - end - - def render_forbidden - render_by_format(html: -> { current_user&.business? ? render('admins/shared/403') : redirect_to('/403') }, - json: -> { render status: 403, json: { messages: I18n.t('error.forbidden') } } ) - end - - def render_not_found - render_by_format(html: -> { render 'admins/shared/404' }, - js: -> { render_js_error('资源未找到') }, - json: -> { render status: 404, json: { message: '资源未找到' } }) - end - - def render_unprocessable_entity(message, type: :alert) - render_by_format(html: -> { render 'admins/shared/422' }, - js: -> { render_js_error(message, type: type) }, - json: -> { render status: 422, json: { message: message } }) - end - alias_method :render_error, :render_unprocessable_entity - - def internal_server_error(message = '系统错误') - @message = message - render_by_format(html: -> { render 'admins/shared/500' }, - js: -> { render_js_error(message) }, - json: -> { render status: 500, json: { message: message } }) - end - - def render_js_template(template, **opts) - render({ template: template, formats: :js }.merge(opts)) - end + include Base::RenderHelper def render_delete_success render_js_template 'admins/shared/delete' diff --git a/app/controllers/concerns/admins/error_rescue_handler.rb b/app/controllers/concerns/base/error_rescue_handler.rb similarity index 94% rename from app/controllers/concerns/admins/error_rescue_handler.rb rename to app/controllers/concerns/base/error_rescue_handler.rb index ceb810f36..d64ce4356 100644 --- a/app/controllers/concerns/admins/error_rescue_handler.rb +++ b/app/controllers/concerns/base/error_rescue_handler.rb @@ -1,4 +1,4 @@ -module Admins::ErrorRescueHandler +module Base::ErrorRescueHandler extend ActiveSupport::Concern included do diff --git a/app/controllers/concerns/admins/paginate_helper.rb b/app/controllers/concerns/base/paginate_helper.rb similarity index 94% rename from app/controllers/concerns/admins/paginate_helper.rb rename to app/controllers/concerns/base/paginate_helper.rb index da7652584..a10d7eb2e 100644 --- a/app/controllers/concerns/admins/paginate_helper.rb +++ b/app/controllers/concerns/base/paginate_helper.rb @@ -1,4 +1,4 @@ -module Admins::PaginateHelper +module Base::PaginateHelper extend ActiveSupport::Concern def offset diff --git a/app/controllers/concerns/base/render_helper.rb b/app/controllers/concerns/base/render_helper.rb new file mode 100644 index 000000000..e0aa49ac1 --- /dev/null +++ b/app/controllers/concerns/base/render_helper.rb @@ -0,0 +1,37 @@ +module Base::RenderHelper + extend ActiveSupport::Concern + + def render_by_format(hash) + format = request.format.symbol + hash.key?(format) ? hash[format].call : hash[:html].call + end + + def render_forbidden + render_by_format(html: -> { current_user&.business? ? render('shared/403') : redirect_to('/403') }, + json: -> { render status: 403, json: { messages: I18n.t('error.forbidden') } } ) + end + + def render_not_found + render_by_format(html: -> { render 'shared/404' }, + js: -> { render_js_error('资源未找到') }, + json: -> { render status: 404, json: { message: '资源未找到' } }) + end + + def render_unprocessable_entity(message, type: :alert) + render_by_format(html: -> { render 'shared/422' }, + js: -> { render_js_error(message, type: type) }, + json: -> { render status: 422, json: { message: message } }) + end + alias_method :render_error, :render_unprocessable_entity + + def internal_server_error(message = '系统错误') + @message = message + render_by_format(html: -> { render 'shared/500' }, + js: -> { render_js_error(message) }, + json: -> { render status: 500, json: { message: message } }) + end + + def render_js_template(template, **opts) + render({ template: template, formats: :js }.merge(opts)) + end +end \ No newline at end of file diff --git a/app/controllers/concerns/cooperative/render_helper.rb b/app/controllers/concerns/cooperative/render_helper.rb new file mode 100644 index 000000000..3110ca304 --- /dev/null +++ b/app/controllers/concerns/cooperative/render_helper.rb @@ -0,0 +1,16 @@ +module Cooperative::RenderHelper + include Base::RenderHelper + + def render_delete_success + render_js_template 'cooperative/shared/delete' + end + alias_method :render_success_js, :render_delete_success + + def render_js_error(message, type: :alert) + if type == :notify + render js: "$.notify({ message: '#{message}' },{ type: 'danger', delay: 5000 });" + else + render_js_template 'cooperative/shared/error', locals: { message: message } + end + end +end \ No newline at end of file diff --git a/app/controllers/cooperative/base_controller.rb b/app/controllers/cooperative/base_controller.rb new file mode 100644 index 000000000..e91f52b91 --- /dev/null +++ b/app/controllers/cooperative/base_controller.rb @@ -0,0 +1,58 @@ +class Cooperative::BaseController < ApplicationController + include Base::PaginateHelper + include Cooperative::RenderHelper + include Base::ErrorRescueHandler + + layout 'cooperative' + + skip_before_action :verify_authenticity_token + + before_action :laboratory_exist!, :require_login, :require_cooperative_manager! + + after_action :rebind_event_if_ajax_render_partial + + helper_method :current_laboratory, :current_setting_or_default + + private + + def current_laboratory + @_current_laboratory ||= Laboratory.find_by_subdomain(request.subdomain) + end + + def current_setting_or_default(name) + current_laboratory.public_send(name) || default_setting.public_send(name) + end + + def laboratory_exist! + return if current_laboratory.present? + + redirect_to '/nopage' + end + + def require_login + return if User.current.logged? + + redirect_to "/login?back_url=#{CGI::escape(request.fullpath)}" + end + + def require_cooperative_manager! + return if current_user.blank? || !current_user.logged? + return if current_user.admin_or_business? + return if current_laboratory.laboratory_users.exists?(user_id: current_user.id) + + render_forbidden + end + + # 触发after ajax render partial hooks,执行一些因为局部刷新后失效的绑定事件 + def rebind_event_if_ajax_render_partial + return if request.format.symbol != :js + return if response.content_type != 'text/javascript' + + path = Rails.root.join('app/views/shared/after_render_js_hook.js.erb') + return unless File.exists?(path) + + append_js = ERB.new(File.open(path).read).result + response.body += append_js + end + +end \ No newline at end of file diff --git a/app/controllers/cooperative/dashboards_controller.rb b/app/controllers/cooperative/dashboards_controller.rb new file mode 100644 index 000000000..4a9a11330 --- /dev/null +++ b/app/controllers/cooperative/dashboards_controller.rb @@ -0,0 +1,4 @@ +class Cooperative::DashboardsController < Cooperative::BaseController + def show + 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 new file mode 100644 index 000000000..d9ba70d9d --- /dev/null +++ b/app/controllers/cooperative/laboratory_settings_controller.rb @@ -0,0 +1,14 @@ +class Cooperative::LaboratorySettingsController < Cooperative::BaseController + def edit + @laboratory = current_laboratory + end + + def update + Admins::SaveLaboratorySettingService.call(current_laboratory, form_params) + render_ok + end + + def form_params + params.permit(:identifier, :name, :nav_logo, :login_logo, :tab_logo, :footer, navbar: %i[name link hidden]) + end +end \ No newline at end of file diff --git a/app/helpers/admins/base_helper.rb b/app/helpers/admins/base_helper.rb index d79456ac8..95e54db46 100644 --- a/app/helpers/admins/base_helper.rb +++ b/app/helpers/admins/base_helper.rb @@ -1,110 +1,3 @@ module Admins::BaseHelper - def sidebar_item_group(url, text, **opts) - link_opts = url.start_with?('/') ? {} : { 'data-toggle': 'collapse', 'aria-expanded': false } - content = - link_to url, link_opts do - content_tag(:i, '', class: "fa fa-#{opts[:icon]}", 'data-toggle': 'tooltip', 'data-placement': 'right', 'data-boundary': 'window', title: text) + - content_tag(:span, text) - end - - content += - content_tag(:ul, id: url[1..-1], class: 'collapse list-unstyled', "data-parent": '#sidebar') do - yield - end - - raw content - end - - def sidebar_item(url, text, **opts) - content = - link_to url, 'data-controller': opts[:controller] do - content_tag(:i, '', class: "fa fa-#{opts[:icon]} fa-fw", 'data-toggle': 'tooltip', 'data-placement': 'right', 'data-boundary': 'window', title: text) + - content_tag(:span, text) - end - - raw content - end - - def admin_sidebar_controller - key = params[:controller].to_s.gsub(/\//, '-') - SidebarUtil.controller_name(key) || key - end - - def define_admin_breadcrumbs(&block) - content_for(:setup_admin_breadcrumb, &block) - end - - def add_admin_breadcrumb(text, url = nil) - @_admin_breadcrumbs ||= [] - @_admin_breadcrumbs << OpenStruct.new(text: text, url: url) - end - - def display_text(str, default = '--') - str.presence || default - end - - def overflow_hidden_span(text, width: 300) - opts = { class: 'd-inline-block text-truncate', style: "max-width: #{width}px" } - opts.merge!('data-toggle': 'tooltip', title: text) if text != '--' - - content_tag(:span, text, opts) - end - - def sort_tag(content = '', **opts) - options = {} - options[:sort_by] = opts.delete(:name) - is_current_sort = params[:sort_by].to_s == options[:sort_by] - options[:sort_direction] = is_current_sort && params[:sort_direction].to_s == 'desc' ? 'asc' : 'desc' - - path = opts.delete(:path) + "?" + unsafe_params.merge(options).to_query - arrow_class = case params[:sort_direction].to_s - when 'desc' then 'fa-sort-amount-desc' - when 'asc' then 'fa-sort-amount-asc' - else '' - end - opts[:style] = "#{opts[:style]} ;position: relative;" - - content_tag(:span, opts) do - link_to path, remote: true do - content = content_tag(:span) { yield } if block_given? - - content += content_tag(:i, '', class: "fa color-light-green ml-1 #{arrow_class}", style: 'position: absolute;top:0;') if is_current_sort - raw content - end - end - end - - def javascript_void_link(name, **opts) - raw link_to(name, 'javascript:void(0)', opts) - end - - def agree_link(name, url, **opts) - klass = ['action agree-action', opts.delete(:class)].compact.join(' ') - - refresh_url_data = "refresh_url=#{CGI::escape(request.fullpath)}" - url = url + (url.index('?') ? '&' : '?') + refresh_url_data - - raw link_to(name, url, { method: :post, remote: true, class: klass, 'data-confirm': '确认审核通过?'}.merge(opts)) - end - - def delete_link(name, url, **opts, &block) - klass = ['action delete-action', opts.delete(:class)].compact.join(' ') - - refresh_url_data = "refresh_url=#{CGI::escape(request.fullpath)}" - url = url + (url.index('?') ? '&' : '?') + refresh_url_data - - if block_given? - raw link_to(url, { method: :delete, remote: true, class: klass, 'data-confirm': '确认删除?'}.merge(opts), &block) - else - raw link_to(name, url, { method: :delete, remote: true, class: klass, 'data-confirm': '确认删除?'}.merge(opts)) - end - end - - def unsafe_params - params.except(:controller, :action).to_unsafe_h - end - - def list_index_no(page,index) - (page - 1) * 20 + index + 1 - end + include ManageBackHelper end \ No newline at end of file diff --git a/app/helpers/cooperative/base_helper.rb b/app/helpers/cooperative/base_helper.rb new file mode 100644 index 000000000..de95813f1 --- /dev/null +++ b/app/helpers/cooperative/base_helper.rb @@ -0,0 +1,3 @@ +module Cooperative::BaseHelper + include ManageBackHelper +end \ No newline at end of file diff --git a/app/helpers/manage_back_helper.rb b/app/helpers/manage_back_helper.rb new file mode 100644 index 000000000..cfc67d714 --- /dev/null +++ b/app/helpers/manage_back_helper.rb @@ -0,0 +1,115 @@ +module ManageBackHelper + extend ActiveSupport::Concern + + def sidebar_item_group(url, text, **opts) + link_opts = url.start_with?('/') ? {} : { 'data-toggle': 'collapse', 'aria-expanded': false } + content = + link_to url, link_opts do + content_tag(:i, '', class: "fa fa-#{opts[:icon]}", 'data-toggle': 'tooltip', 'data-placement': 'right', 'data-boundary': 'window', title: text) + + content_tag(:span, text) + end + + content += + content_tag(:ul, id: url[1..-1], class: 'collapse list-unstyled', "data-parent": '#sidebar') do + yield + end + + raw content + end + + def sidebar_item(url, text, **opts) + content = + link_to url, 'data-controller': opts[:controller] do + content_tag(:i, '', class: "fa fa-#{opts[:icon]} fa-fw", 'data-toggle': 'tooltip', 'data-placement': 'right', 'data-boundary': 'window', title: text) + + content_tag(:span, text) + end + + raw content + end + + def admin_sidebar_controller + key = params[:controller].to_s.gsub(/\//, '-') + SidebarUtil.controller_name(key) || key + end + alias_method :sidebar_controller, :admin_sidebar_controller + + def define_admin_breadcrumbs(&block) + content_for(:setup_admin_breadcrumb, &block) + end + alias_method :define_breadcrumbs, :define_admin_breadcrumbs + + def add_admin_breadcrumb(text, url = nil) + @_breadcrumbs ||= [] + @_breadcrumbs << OpenStruct.new(text: text, url: url) + end + alias_method :add_breadcrumb, :add_admin_breadcrumb + + def display_text(str, default = '--') + str.presence || default + end + + def overflow_hidden_span(text, width: 300) + opts = { class: 'd-inline-block text-truncate', style: "max-width: #{width}px" } + opts.merge!('data-toggle': 'tooltip', title: text) if text != '--' + + content_tag(:span, text, opts) + end + + def sort_tag(content = '', **opts) + options = {} + options[:sort_by] = opts.delete(:name) + is_current_sort = params[:sort_by].to_s == options[:sort_by] + options[:sort_direction] = is_current_sort && params[:sort_direction].to_s == 'desc' ? 'asc' : 'desc' + + path = opts.delete(:path) + "?" + unsafe_params.merge(options).to_query + arrow_class = case params[:sort_direction].to_s + when 'desc' then 'fa-sort-amount-desc' + when 'asc' then 'fa-sort-amount-asc' + else '' + end + opts[:style] = "#{opts[:style]} ;position: relative;" + + content_tag(:span, opts) do + link_to path, remote: true do + content = content_tag(:span) { yield } if block_given? + + content += content_tag(:i, '', class: "fa color-light-green ml-1 #{arrow_class}", style: 'position: absolute;top:0;') if is_current_sort + raw content + end + end + end + + def javascript_void_link(name, **opts) + raw link_to(name, 'javascript:void(0)', opts) + end + + def agree_link(name, url, **opts) + klass = ['action agree-action', opts.delete(:class)].compact.join(' ') + + refresh_url_data = "refresh_url=#{CGI::escape(request.fullpath)}" + url = url + (url.index('?') ? '&' : '?') + refresh_url_data + + raw link_to(name, url, { method: :post, remote: true, class: klass, 'data-confirm': '确认审核通过?'}.merge(opts)) + end + + def delete_link(name, url, **opts, &block) + klass = ['action delete-action', opts.delete(:class)].compact.join(' ') + + refresh_url_data = "refresh_url=#{CGI::escape(request.fullpath)}" + url = url + (url.index('?') ? '&' : '?') + refresh_url_data + + if block_given? + raw link_to(url, { method: :delete, remote: true, class: klass, 'data-confirm': '确认删除?'}.merge(opts), &block) + else + raw link_to(name, url, { method: :delete, remote: true, class: klass, 'data-confirm': '确认删除?'}.merge(opts)) + end + end + + def unsafe_params + params.except(:controller, :action).to_unsafe_h + end + + def list_index_no(page,index) + (page - 1) * 20 + index + 1 + end +end \ No newline at end of file diff --git a/app/models/laboratory.rb b/app/models/laboratory.rb index 00f5adabf..35965dc0d 100644 --- a/app/models/laboratory.rb +++ b/app/models/laboratory.rb @@ -10,6 +10,8 @@ class Laboratory < ApplicationRecord validates :identifier, uniqueness: { case_sensitive: false }, allow_nil: true + delegate :name, :navbar, :footer, :login_logo_url, :nav_logo_url, :tab_logo_url, :default_navbar, to: :laboratory_setting + def site rails_env = EduSetting.get('rails_env') suffix = rails_env && rails_env != 'production' ? ".#{rails_env}.educoder.net" : '.educoder.net' diff --git a/app/views/admins/shared/error.js.erb b/app/views/admins/shared/error.js.erb index 261796d0b..93d1752e7 100644 --- a/app/views/admins/shared/error.js.erb +++ b/app/views/admins/shared/error.js.erb @@ -1,4 +1,4 @@ -$('.admin-alert-container').html('<%= j( render partial: 'admins/shared/alert', locals: { message: message } ) %>'); +$('.admin-alert-container').html('<%= j( render partial: 'shared/alert', locals: { message: message } ) %>'); setTimeout(function() { if ($('.admin-alert-container button.close').length > 0) { diff --git a/app/views/cooperative/dashboards/show.html.erb b/app/views/cooperative/dashboards/show.html.erb new file mode 100644 index 000000000..790e830a7 --- /dev/null +++ b/app/views/cooperative/dashboards/show.html.erb @@ -0,0 +1,3 @@ +<% define_breadcrumbs do %> + <% add_breadcrumb('概览') %> +<% end %> \ No newline at end of file diff --git a/app/views/cooperative/kaminari/_first_page.html.erb b/app/views/cooperative/kaminari/_first_page.html.erb new file mode 100644 index 000000000..148fc3f1c --- /dev/null +++ b/app/views/cooperative/kaminari/_first_page.html.erb @@ -0,0 +1,11 @@ +<%# Link to the "First" page + - available local variables + url: url to the first page + current_page: a page object for the currently displayed page + total_pages: total number of pages + per_page: number of items to fetch per page + remote: data-remote +-%> +
  • + <%= link_to_unless current_page.first?, t('views.pagination.first').html_safe, url, remote: remote, class: 'page-link' %> +
  • diff --git a/app/views/cooperative/kaminari/_gap.html.erb b/app/views/cooperative/kaminari/_gap.html.erb new file mode 100644 index 000000000..59236c8f6 --- /dev/null +++ b/app/views/cooperative/kaminari/_gap.html.erb @@ -0,0 +1,13 @@ +<%# Non-link tag that stands for skipped pages... + - available local variables + current_page: a page object for the currently displayed page + total_pages: total number of pages + per_page: number of items to fetch per page + remote: data-remote +-%> +
  • + <%= link_to 'javascript:void(0)', { class: 'page-link' } do %> + <%= t('views.pagination.truncate').html_safe %> + (current) + <% end %> +
  • diff --git a/app/views/cooperative/kaminari/_last_page.html.erb b/app/views/cooperative/kaminari/_last_page.html.erb new file mode 100644 index 000000000..3e8a524a0 --- /dev/null +++ b/app/views/cooperative/kaminari/_last_page.html.erb @@ -0,0 +1,11 @@ +<%# Link to the "Last" page + - available local variables + url: url to the last page + current_page: a page object for the currently displayed page + total_pages: total number of pages + per_page: number of items to fetch per page + remote: data-remote +-%> +
  • + <%= link_to_unless(current_page.last?, t('views.pagination.last').html_safe, url, remote: remote, class: 'page-link') %> +
  • diff --git a/app/views/cooperative/kaminari/_next_page.html.erb b/app/views/cooperative/kaminari/_next_page.html.erb new file mode 100644 index 000000000..211ddd423 --- /dev/null +++ b/app/views/cooperative/kaminari/_next_page.html.erb @@ -0,0 +1,11 @@ +<%# Link to the "Next" page + - available local variables + url: url to the next page + current_page: a page object for the currently displayed page + total_pages: total number of pages + per_page: number of items to fetch per page + remote: data-remote +-%> +
  • diff --git a/app/views/cooperative/kaminari/_page.html.erb b/app/views/cooperative/kaminari/_page.html.erb new file mode 100644 index 000000000..10a8374c7 --- /dev/null +++ b/app/views/cooperative/kaminari/_page.html.erb @@ -0,0 +1,19 @@ +<%# Link showing page number + - available local variables + page: a page object for "this" page + url: url to this page + current_page: a page object for the currently displayed page + total_pages: total number of pages + per_page: number of items to fetch per page + remote: data-remote +-%> +
  • + <% if page.current? %> + <%= link_to url, {remote: remote, rel: page.rel, class: 'page-link'} do %> + <%= page %> + (current) + <% end %> + <% else %> + <%= link_to page, url, {remote: remote, rel: page.rel, class: 'page-link'} %> + <% end %> +
  • diff --git a/app/views/cooperative/kaminari/_paginator.html.erb b/app/views/cooperative/kaminari/_paginator.html.erb new file mode 100644 index 000000000..8d090b129 --- /dev/null +++ b/app/views/cooperative/kaminari/_paginator.html.erb @@ -0,0 +1,27 @@ +<%# The container tag + - available local variables + current_page: a page object for the currently displayed page + total_pages: total number of pages + per_page: number of items to fetch per page + remote: data-remote + paginator: the paginator that renders the pagination tags inside +-%> +<%= paginator.render do -%> + +<% end -%> diff --git a/app/views/cooperative/kaminari/_prev_page.html.erb b/app/views/cooperative/kaminari/_prev_page.html.erb new file mode 100644 index 000000000..90c38dd36 --- /dev/null +++ b/app/views/cooperative/kaminari/_prev_page.html.erb @@ -0,0 +1,11 @@ +<%# Link to the "Previous" page + - available local variables + url: url to the previous page + current_page: a page object for the currently displayed page + total_pages: total number of pages + per_page: number of items to fetch per page + remote: data-remote +-%> + diff --git a/app/views/cooperative/laboratory_settings/edit.html.erb b/app/views/cooperative/laboratory_settings/edit.html.erb new file mode 100644 index 000000000..c070ee014 --- /dev/null +++ b/app/views/cooperative/laboratory_settings/edit.html.erb @@ -0,0 +1,129 @@ +<% define_breadcrumbs do %> + <% add_breadcrumb('网站设置') %> +<% end %> + +
    + <%= simple_form_for(@laboratory, url: cooperative_laboratory_setting_path(@laboratory), method: 'patch', html: { enctype: 'multipart/form-data' }) do |f| %> + <% setting = @laboratory.laboratory_setting %> + +
    +
    网站域名设置
    + +
    +
    +
    + https:// +
    + <%= text_field_tag :identifier, @laboratory.identifier, + maxlength: 15, class: 'form-control font-16', + 'onKeyUp': 'value=value.replace(/[^\w\.\-\/]/ig,"").toLowerCase()', + style: 'text-transform:lowercase'%> +
    + <% rails_env = EduSetting.get('rails_env') %> + <%= rails_env && rails_env != 'production' ? ".#{rails_env}.educoder.net" : '.educoder.net' %> +
    +
    + <%# if @laboratory.errors && @laboratory.errors.key?(:identifier) %> + + <%# end %> +
    +
    + +
    +
    网站名称设置
    + +
    + <%= text_field_tag :name, setting.name, placeholder: '输入20个字以内的网站名称', maxlength: 20, class: 'form-control col-12 col-md-4' %> +
    +
    + +
    +
    Logo设置
    + +
    +
    + <% nav_logo_img = setting.nav_logo_url %> + +
    +
    网站导航logo
    +
    格式:PNG、JPG
    +
    尺寸:高度38px以内,宽等比例缩放
    +
    +
    + +
    + <% login_logo_img = setting.login_logo_url %> + +
    +
    登录页面logo
    +
    格式:PNG、JPG
    +
    尺寸:高度90px以内,宽等比例缩放
    +
    +
    + +
    + <% tab_logo_img = setting.tab_logo_url %> +
    + + <%= file_field_tag(:tab_logo, accept: 'image/x-icon', style: 'display: none', value: params[:tab_logo]) %> + +
    +
    +
    浏览器导航栏logo
    +
    格式:ico
    +
    尺寸:16*16 32*32 48*48 64*64
    +
    +
    +
    +
    + +
    +
    导航设置
    + +
    + + + + + + + + + + <% (setting.navbar || setting.default_navbar).each do |nav| %> + + + + + + <% end %> + +
    导航名称导航链接是否展示
    <%= text_field_tag('navbar[][name]', nav['name'], id: nil, class: 'form-control') %><%= text_field_tag('navbar[][link]', nav['link'], id: nil, class: 'form-control') %> + <%= check_box_tag('navbar[][hidden]', 0, !nav['hidden'], id: nil, class: 'font-16') %> +
    +
    +
    + +
    +
    底部备案信息设置
    + + +
    + +
    + +
    + <%= javascript_void_link '保存', class: 'btn btn-primary mr-3 px-4 submit-btn' %> +
    + <% end %> +
    \ No newline at end of file diff --git a/app/views/cooperative/shared/_no_data_for_table.html.erb b/app/views/cooperative/shared/_no_data_for_table.html.erb new file mode 100644 index 000000000..1899f8d2e --- /dev/null +++ b/app/views/cooperative/shared/_no_data_for_table.html.erb @@ -0,0 +1 @@ +暂无数据 \ No newline at end of file diff --git a/app/views/cooperative/shared/_paginate.html.erb b/app/views/cooperative/shared/_paginate.html.erb new file mode 100644 index 000000000..47f7ff580 --- /dev/null +++ b/app/views/cooperative/shared/_paginate.html.erb @@ -0,0 +1,6 @@ +
    + <% if objects && objects.size.nonzero? %> +
    <%= page_entries_info objects %>
    + <% end %> + <%= paginate objects, views_prefix: 'cooperative', remote: true %> +
    \ No newline at end of file diff --git a/app/views/cooperative/shared/_sidebar.html.erb b/app/views/cooperative/shared/_sidebar.html.erb new file mode 100644 index 000000000..a39a84e3a --- /dev/null +++ b/app/views/cooperative/shared/_sidebar.html.erb @@ -0,0 +1,20 @@ +<% sidebar_collapse = request.cookies['cooperative_sidebar_collapse'].to_s == 'true' %> + \ No newline at end of file diff --git a/app/views/cooperative/shared/after_render_js_hook.js.erb b/app/views/cooperative/shared/after_render_js_hook.js.erb new file mode 100644 index 000000000..b0823d34a --- /dev/null +++ b/app/views/cooperative/shared/after_render_js_hook.js.erb @@ -0,0 +1,4 @@ +; +$('[data-toggle="tooltip"]').tooltip({ trigger : 'hover' }); +$('[data-toggle="popover"]').popover(); +$('img.preview-image').bootstrapViewer(); \ No newline at end of file diff --git a/app/views/cooperative/shared/delete.js.erb b/app/views/cooperative/shared/delete.js.erb new file mode 100644 index 000000000..0da435fd7 --- /dev/null +++ b/app/views/cooperative/shared/delete.js.erb @@ -0,0 +1,27 @@ +var deleteRow = $('<%= params[:element] %>'); +var refreshUrl = '<%= params[:refresh_url] %>'; +var notRefresh = <%= !!params[:not_refresh] %>; + +$.notify({ message: '操作成功' },{ type: 'success' }); + +if (!notRefresh) { + var refreshFunc = function(url) { + $.ajax({ + url: url.length > 0 ? url : window.location.href, + method: 'GET', + dataType: "script" + }) + } + + if(deleteRow.length > 0){ + var needRefresh = deleteRow.siblings().length == 0; + + deleteRow.remove(); + + if(needRefresh){ refreshFunc(refreshUrl); } + } else { + refreshFunc(refreshUrl); + } +} else { + deleteRow.remove(); +} \ No newline at end of file diff --git a/app/views/cooperative/shared/error.js.erb b/app/views/cooperative/shared/error.js.erb new file mode 100644 index 000000000..4fdc69021 --- /dev/null +++ b/app/views/cooperative/shared/error.js.erb @@ -0,0 +1,10 @@ +$('.cooperative-alert-container').html('<%= j( render partial: 'shared/alert', locals: { message: message } ) %>'); + +setTimeout(function() { + if ($('.cooperative-alert-container button.close').length > 0) { + $('.cooperative-alert-container button.close').trigger('click'); + } +}, 5000) +$(".cooperative-body-container").animate({ + scrollTop: 0 +}, 200); \ No newline at end of file diff --git a/app/views/cooperative/shared/modal/_message_modal.html.erb b/app/views/cooperative/shared/modal/_message_modal.html.erb new file mode 100644 index 000000000..70f16c1ae --- /dev/null +++ b/app/views/cooperative/shared/modal/_message_modal.html.erb @@ -0,0 +1,18 @@ + \ No newline at end of file diff --git a/app/views/cooperative/shared/modal/_upload_file_modal.html.erb b/app/views/cooperative/shared/modal/_upload_file_modal.html.erb new file mode 100644 index 000000000..036f1122a --- /dev/null +++ b/app/views/cooperative/shared/modal/_upload_file_modal.html.erb @@ -0,0 +1,32 @@ + \ No newline at end of file diff --git a/app/views/layouts/admin.html.erb b/app/views/layouts/admin.html.erb index 330ca8fc0..f61aaba4f 100644 --- a/app/views/layouts/admin.html.erb +++ b/app/views/layouts/admin.html.erb @@ -21,12 +21,12 @@
    - <%= render 'admins/shared/flash_notice' %> + <%= render 'shared/flash_notice' %>
    diff --git a/app/views/layouts/cooperative.html.erb b/app/views/layouts/cooperative.html.erb new file mode 100644 index 000000000..bc6050b7b --- /dev/null +++ b/app/views/layouts/cooperative.html.erb @@ -0,0 +1,42 @@ + + + + <%= current_laboratory.school&.name %>-后台管理 + + + + + <%= csrf_meta_tags %> + <%= csp_meta_tag %> + + <%= stylesheet_link_tag 'cooperative', media: 'all','data-turbolinks-track': 'reload' %> + <%= javascript_include_tag 'cooperative', 'data-turbolinks-track': 'reload' %> + + + <% body_class = [params[:controller].gsub(/\//, '-').gsub('_', '-'), params[:action], 'page'].join('-') %> + + + <%= render partial: 'cooperative/shared/sidebar' %> + + +
    +
    + <%= render 'shared/flash_notice' %> +
    + +
    + <%= yield :setup_breadcrumb %> + <%= render(partial: 'shared/breadcrumb') %> +
    + +
    + <%= yield %> +
    +
    + +
    + + + <%= render 'cooperative/shared/modal/message_modal' %> + + diff --git a/app/views/admins/shared/403.html.erb b/app/views/shared/403.html.erb similarity index 100% rename from app/views/admins/shared/403.html.erb rename to app/views/shared/403.html.erb diff --git a/app/views/admins/shared/404.html.erb b/app/views/shared/404.html.erb similarity index 100% rename from app/views/admins/shared/404.html.erb rename to app/views/shared/404.html.erb diff --git a/app/views/admins/shared/422.html.erb b/app/views/shared/422.html.erb similarity index 100% rename from app/views/admins/shared/422.html.erb rename to app/views/shared/422.html.erb diff --git a/app/views/admins/shared/500.html.erb b/app/views/shared/500.html.erb similarity index 100% rename from app/views/admins/shared/500.html.erb rename to app/views/shared/500.html.erb diff --git a/app/views/admins/shared/_alert.html.erb b/app/views/shared/_alert.html.erb similarity index 100% rename from app/views/admins/shared/_alert.html.erb rename to app/views/shared/_alert.html.erb diff --git a/app/views/admins/shared/_breadcrumb.html.erb b/app/views/shared/_breadcrumb.html.erb similarity index 61% rename from app/views/admins/shared/_breadcrumb.html.erb rename to app/views/shared/_breadcrumb.html.erb index 8aea89871..e811b414e 100644 --- a/app/views/admins/shared/_breadcrumb.html.erb +++ b/app/views/shared/_breadcrumb.html.erb @@ -1,8 +1,8 @@ -<% if @_admin_breadcrumbs.present? %> +<% if @_breadcrumbs.present? %>