Merge branch 'dev_aliyun' into develop

dev_local_2
daiao 5 years ago
commit d87776038e

@ -65,3 +65,11 @@ function customConfirm(opts){
}
return $.confirm($.extend({}, defaultOpts, opts))
}
function show_success_flash(){
$.notify({
message: '操作成功'
},{
type: 'success'
});
}

@ -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 () {
});

@ -0,0 +1,125 @@
$(document).on('turbolinks:load', function() {
if ($('body.cooperative-carousels-index-page').length > 0) {
// ------------ 保存链接 -----------
$('.carousels-card').on('click', '.save-data-btn', function(){
var $link = $(this);
var id = $link.data('id');
var link = $('.custom-carousel-item-' + id).find('.link-input').val();
var name = $('.custom-carousel-item-' + id).find('.name-input').val();
if(!name || name.length == 0){
$.notify({ message: '名称不能为空' },{ type: 'danger' });
return;
}
$link.attr('disabled', true);
$.ajax({
url: '/cooperative/carousels/' + id,
method: 'PATCH',
dataType: 'json',
data: { link: link, name: name },
success: function(data){
$.notify({ message: '操作成功' });
},
error: ajaxErrorNotifyHandler,
complete: function(){
$link.removeAttr('disabled');
}
})
});
// -------------- 是否在首页展示 --------------
$('.carousels-card').on('change', '.online-check-box', function(){
var $checkbox = $(this);
var id = $checkbox.data('id');
var checked = $checkbox.is(':checked');
$checkbox.attr('disabled', true);
$.ajax({
url: '/cooperative/carousels/' + id,
method: 'PATCH',
dataType: 'json',
data: { status: checked },
success: function(data){
$.notify({ message: '保存成功' });
var box = $('.custom-carousel-item-' + id).find('.drag');
if(checked){
box.removeClass('not_active');
}else{
box.addClass('not_active');
}
},
error: ajaxErrorNotifyHandler,
complete: function(){
$checkbox.removeAttr('disabled');
}
})
});
// ------------ 拖拽 -------------
var onDropFunc = function(el, _target, _source, sibling){
var moveId = $(el).data('id');
var insertId = $(sibling).data('id') || '';
$.ajax({
url: '/cooperative/carousels/drag',
method: 'POST',
dataType: 'json',
data: { move_id: moveId, after_id: insertId },
success: function(data){
$('#carousels-container .custom-carousel-item-no').each(function(index, ele){
$(ele).html(index + 1);
})
},
error: function(res){
var data = res.responseJSON;
$.notify({message: '移动失败,原因:' + data.message}, {type: 'danger'});
}
})
};
var ele1 = document.getElementById('carousels-container');
dragula([ele1], { mirrorContainer: ele1 }).on('drop', onDropFunc);
// ----------- 新增 --------------
var $createModal = $('.modal.cooperative-add-carousel-modal');
var $createForm = $createModal.find('form.cooperative-add-carousel-form');
$createForm.validate({
errorElement: 'span',
errorClass: 'danger text-danger',
rules: {
"portal_image[image]": {
required: true
},
"portal_image[name]": {
required: true
},
}
});
$createModal.on('show.bs.modal', function(event){
resetFileInputFunc($createModal.find('.img-file-input'));
$createModal.find('.file-names').html('选择文件');
});
$createModal.on('click', '.submit-btn', function() {
$createForm.find('.error').html('');
if ($createForm.valid()) {
$createForm.submit();
} else {
$createForm.find('.error').html('请选择图片');
}
});
$createModal.on('change', '.img-file-input', function(){
var file = $(this)[0].files[0];
$createModal.find('.file-names').html(file ? file.name : '请选择文件');
})
// -------------- 重新上传图片 --------------
//replace_image_url
$('.modal.cooperative-upload-file-modal').on('upload:success', function(e, data){
var $carouselItem = $('.custom-carousel-item-' + data.source_id);
$carouselItem.find('.custom-carousel-item-img img').attr('src', data.url);
})
}
})

@ -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);
}
});
})
}
});

@ -0,0 +1,62 @@
$(document).on('turbolinks:load', function() {
if ($('body.cooperative-laboratory-users-index-page').length > 0) {
// ============= 添加管理员 ==============
var $addMemberModal = $('.cooperative-add-laboratory-user-modal');
var $addMemberForm = $addMemberModal.find('.cooperative-add-laboratory-user-form');
var $memberSelect = $addMemberModal.find('.laboratory-user-select');
$addMemberModal.on('show.bs.modal', function(event){
$memberSelect.select2('val', ' ');
});
$memberSelect.select2({
theme: 'bootstrap4',
placeholder: '请输入要添加的管理员姓名',
multiple: true,
minimumInputLength: 1,
ajax: {
delay: 500,
url: '/cooperative/users',
dataType: 'json',
data: function(params){
return { name: params.term };
},
processResults: function(data){
return { results: data.users }
}
},
templateResult: function (item) {
if(!item.id || item.id === '') return item.text;
return item.real_name + "--" + item.identity;
},
templateSelection: function(item){
if (item.id) {
}
return item.real_name || item.text;
}
});
$addMemberModal.on('click', '.submit-btn', function(){
$addMemberForm.find('.error').html('');
var memberIds = $memberSelect.val();
if (memberIds && memberIds.length > 0) {
$.ajax({
method: 'POST',
dataType: 'json',
url: '/cooperative/laboratory_users',
data: { user_ids: memberIds },
success: function(data){
if(data && data.status == 0){
show_success_flash();
$addMemberModal.modal('hide');
window.location.reload();
}
}
});
} else {
$addMemberModal.modal('hide');
}
});
}
});

@ -0,0 +1,62 @@
$(document).on('turbolinks:load', function() {
var $modal = $('.modal.cooperative-upload-file-modal');
if ($modal.length > 0) {
var $form = $modal.find('form.cooperative-upload-file-form')
var $sourceIdInput = $modal.find('input[name="source_id"]');
var $sourceTypeInput = $modal.find('input[name="source_type"]');
$modal.on('show.bs.modal', function(event){
var $link = $(event.relatedTarget);
var sourceId = $link.data('sourceId');
var sourceType = $link.data('sourceType');
$sourceIdInput.val(sourceId);
$sourceTypeInput.val(sourceType);
$modal.find('.upload-file-input').trigger('click');
});
$modal.find('.upload-file-input').on('change', function(e){
var file = $(this)[0].files[0];
if(file){
$modal.find('.file-names').html(file.name);
$modal.find('.submit-btn').trigger('click');
}
})
var formValid = function(){
if($form.find('input[name="file"]').val() == undefined || $form.find('input[name="file"]').val().length == 0){
$form.find('.error').html('请选择文件');
return false;
}
return true;
};
$modal.on('click', '.submit-btn', function(){
$form.find('.error').html('');
if (formValid()) {
var formDataString = $form.serialize();
$.ajax({
method: 'POST',
dataType: 'json',
url: '/cooperatives/files?' + formDataString,
data: new FormData($form[0]),
processData: false,
contentType: false,
success: function(data){
$.notify({ message: '上传成功' });
$modal.trigger('upload:success', data);
$modal.modal('hide');
},
error: function(res){
var data = res.responseJSON;
$form.find('.error').html(data.message);
}
});
}
});
}
});

@ -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');
}
});

@ -31,6 +31,7 @@
display: block;
width: 80px;
height: 80px;
background: #f0f0f0;
}
&-upload {

@ -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
*/

@ -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;
}

@ -0,0 +1,60 @@
.cooperative-carousels-index-page {
.carousels-card {
.custom-carousel-item {
& > .drag {
cursor: move;
background: #fff;
box-shadow: 1px 2px 5px 3px #f0f0f0;
}
&-no {
font-size: 28px;
text-align: center;
}
&-img {
cursor: pointer;
width: 100%;
height: 60px;
& > img {
display: block;
width: 100%;
height: 60px;
background: #F5F5F5;
}
}
.not_active {
background: #F0F0F0;
}
.delete-btn {
font-size: 20px;
color: red;
cursor: pointer;
}
.save-url-btn {
cursor: pointer;
}
.operate-box {
display: flex;
justify-content: space-between;
align-items: center;
}
.online-check-box {
font-size: 20px;
}
.name-input {
flex: 1;
}
.link-input {
flex: 3;
}
}
}
}

@ -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;
}
}

@ -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;
}
}
}
}

@ -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%);
}
}

@ -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'

@ -338,9 +338,9 @@ class ApplicationController < ActionController::Base
# 如果代码窗口是隐藏的,则不用保存代码
return if myshixun.shixun.hide_code || myshixun.shixun.vnc
file_content = git_fle_content myshixun.repo_path, path
unless file_content.present?
raise("获取文件代码异常")
end
#unless file_content.present?
# raise("获取文件代码异常")
#end
logger.info("#######game_id:#{game_id}, file_content:#{file_content}")
game_code = GameCode.where(:game_id => game_id, :path => path).first
if game_code.nil?

@ -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'

@ -1,4 +1,4 @@
module Admins::ErrorRescueHandler
module Base::ErrorRescueHandler
extend ActiveSupport::Concern
included do

@ -1,4 +1,4 @@
module Admins::PaginateHelper
module Base::PaginateHelper
extend ActiveSupport::Concern
def offset

@ -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

@ -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

@ -10,6 +10,10 @@ module LaboratoryHelper
@_current_laboratory ||= (Laboratory.find_by_subdomain(request.subdomain) || Laboratory.find(1))
end
def default_laboratory
@_default_laboratory ||= Laboratory.find(1)
end
def default_setting
@_default_setting ||= LaboratorySetting.find_by(laboratory_id: 1)
end

@ -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 '/403'
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

@ -0,0 +1,80 @@
class Cooperative::CarouselsController < Cooperative::BaseController
before_action :convert_file!, only: [:create]
def index
@images = current_laboratory.portal_images.order(position: :asc)
end
def create
position = current_laboratory.portal_images.count + 1
ActiveRecord::Base.transaction do
image = current_laboratory.portal_images.create!(create_params.merge(position: position))
file_path = Util::FileManage.disk_filename('PortalImage', image.id)
File.delete(file_path) if File.exist?(file_path) # 删除之前的文件
Util.write_file(@file, file_path)
end
flash[:success] = '保存成功'
redirect_to cooperative_carousels_path(current_laboratory)
end
def update
current_image.update!(update_params)
render_ok
end
def destroy
ActiveRecord::Base.transaction do
current_image.destroy!
# 前移
current_laboratory.portal_images.where('position > ?', current_image.position)
.update_all('position = position - 1')
file_path = Util::FileManage.disk_filename('PortalImage', current_image.id)
File.delete(file_path) if File.exist?(file_path)
end
render_delete_success
end
def drag
move = current_laboratory.portal_images.find_by(id: params[:move_id])
after = current_laboratory.portal_images.find_by(id: params[:after_id])
Admins::DragPortalImageService.call(current_laboratory, move, after)
render_ok
rescue Admins::DragPortalImageService::Error => e
render_error(e.message)
end
private
def current_image
@_current_image ||= current_laboratory.portal_images.find(params[:id])
end
def create_params
params.require(:portal_image).permit(:name, :link)
end
def update_params
params.permit(:name, :link, :status)
end
def convert_file!
max_size = 10 * 1024 * 1024 # 10M
file = params.dig('portal_image', 'image')
if file.class == ActionDispatch::Http::UploadedFile
@file = file
render_error('请上传文件') if @file.size.zero?
render_error('文件大小超过限制') if @file.size > max_size
else
file = file.to_s.strip
return render_error('请上传正确的图片') if file.blank?
@file = Util.convert_base64_image(file, max_size: max_size)
end
rescue Base64ImageConverter::Error => ex
render_error(ex.message)
end
end

@ -0,0 +1,4 @@
class Cooperative::DashboardsController < Cooperative::BaseController
def show
end
end

@ -0,0 +1,46 @@
class Cooperative::FilesController < Cooperative::BaseController
before_action :convert_file!, only: [:create]
def create
File.delete(file_path) if File.exist?(file_path) # 删除之前的文件
Util.write_file(@file, file_path)
render_ok(source_id: params[:source_id], source_type: params[:source_type].to_s, url: file_url + "?t=#{Random.rand}")
rescue StandardError => ex
logger_error(ex)
render_error('上传失败')
end
private
def convert_file!
max_size = 10 * 1024 * 1024 # 10M
if params[:file].class == ActionDispatch::Http::UploadedFile
@file = params[:file]
render_error('请上传文件') if @file.size.zero?
render_error('文件大小超过限制') if @file.size > max_size
else
file = params[:file].to_s.strip
return render_error('请上传正确的图片') if file.blank?
@file = Util.convert_base64_image(file, max_size: max_size)
end
rescue Base64ImageConverter::Error => ex
render_error(ex.message)
end
def file_path
@_file_path ||= begin
case params[:source_type].to_s
when 'Shixun' then
Util::FileManage.disk_filename('Shixun', params[:source_id])
else
Util::FileManage.disk_filename(params[:source_type].to_s, params[:source_id].to_s)
end
end
end
def file_url
Util::FileManage.disk_file_url(params[:source_type].to_s, params[:source_id].to_s)
end
end

@ -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

@ -0,0 +1,23 @@
class Cooperative::LaboratoryUsersController < Cooperative::BaseController
def index
laboratory_users = current_laboratory.laboratory_users
@laboratory_users = paginate laboratory_users.includes(user: { user_extension: [:school, :department] })
end
def create
Admins::AddLaboratoryUserService.call(current_laboratory, params.permit(user_ids: []))
render_ok
end
def destroy
current_laboratory_user.destroy!
render_delete_success
end
private
def current_laboratory_user
@_current_laboratory_user ||= current_laboratory.laboratory_users.find(params[:id])
end
end

@ -0,0 +1,10 @@
class Cooperative::UsersController < Cooperative::BaseController
def index
params[:sort_by] = params[:sort_by].presence || 'created_on'
params[:sort_direction] = params[:sort_direction].presence || 'desc'
params[:school_id] = current_laboratory.school_id
users = Admins::UserQuery.call(params)
@users = paginate users.includes(user_extension: :school)
end
end

@ -3,6 +3,8 @@ class HomeController < ApplicationController
def index
# banner图
images = current_laboratory.portal_images.only_online.order(position: :asc)
images = default_laboratory.portal_images.only_online.order(position: :asc) if images.blank? # 未设置时使用EduCoder的轮播图
@images_url = []
images.each do |image|
@images_url << {path: image.link, image_url: Util::FileManage.source_disk_file_url(image)}

@ -0,0 +1,13 @@
class Users::OpenUsersController < Users::BaseAccountController
def destroy
current_open_users.destroy!
render_ok
end
private
def current_open_users
@_current_third_party ||= observed_user.open_users.find(params[:id])
end
end

@ -9,7 +9,7 @@ class Weapps::CodeSessionsController < Weapps::BaseController
set_weapp_session_key(result['session_key']) # weapp session_key写入缓存 后续解密需要
# 已授权,绑定过账号
open_user = OpenUser::Wechat.find_by(uid: result['unionid'])
open_user = OpenUsers::Wechat.find_by(uid: result['unionid'])
if open_user.present? && open_user.user
set_session_unionid(result['unionid'])
successful_authentication(open_user.user)

@ -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

@ -0,0 +1,3 @@
module Cooperative::BaseHelper
include ManageBackHelper
end

@ -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

@ -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'

@ -3,6 +3,8 @@ class OpenUser < ApplicationRecord
validates :uid, presence: true, uniqueness: { scope: :type }
serialize :extra, JSON
def can_bind_cache_key
"open_user:#{type}:#{uid}:can_bind"
end

@ -1,3 +1,9 @@
class OpenUsers::QQ < OpenUser
def nickname
extra&.[]('nickname')
end
def en_type
'qq'
end
end

@ -1,3 +1,9 @@
class OpenUsers::Wechat < OpenUser
def nickname
extra&.[]('nickname')
end
def en_type
'qq'
end
end

@ -37,6 +37,9 @@ class Admins::UserQuery < ApplicationQuery
users = users.where('CONCAT(lastname, firstname) LIKE :name', name: "%#{name}%")
end
# 单位ID
users = users.joins(:user_extension).where(user_extensions: { school_id: params[:school_id] }) if params[:school_id].present?
# 学校名称
school_name = params[:school_name].to_s.strip.presence
users = users.joins(user_extension: :school).where('schools.name LIKE ?', "%#{school_name}%") if school_name

@ -28,7 +28,7 @@ class Oauth::CreateOrFindQqAccountService < ApplicationService
user.create_user_extension!(gender: gender)
end
new_open_user = OpenUsers::QQ.create!(user: user, uid: params['uid'])
new_open_user = OpenUsers::QQ.create!(user: user, uid: params['uid'], extra: params.dig('extra', 'raw_info'))
Rails.cache.write(new_open_user.can_bind_cache_key, 1, expires_in: 1.hours) if new_user # 方便后面进行账号绑定
end

@ -39,7 +39,7 @@ class Oauth::CreateOrFindWechatAccountService < ApplicationService
Util.download_file(result['headimgurl'], avatar_path)
end
new_open_user= OpenUsers::Wechat.create!(user: user, uid: result['unionid'])
new_open_user= OpenUsers::Wechat.create!(user: user, uid: result['unionid'], extra: result)
Rails.cache.write(new_open_user.can_bind_cache_key, 1, expires_in: 1.hours) if new_user # 方便后面进行账号绑定
end

@ -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) {

@ -0,0 +1,41 @@
<% define_breadcrumbs do %>
<% add_breadcrumb('轮播图设置') %>
<% end %>
<div class="card mb-5 carousels-card">
<div class="card-header d-flex justify-content-between align-items-center">
<span class="flex-1">首页轮播图<span class="text-secondary font-12">(拖动排序)</span></span>
<%= javascript_void_link '添加', class: 'btn btn-primary btn-sm add-btn', data: { toggle: 'modal', target: '.cooperative-add-carousel-modal' } %>
</div>
<div class="card-body row" id="carousels-container">
<% @images.each_with_index do |image, index| %>
<div class="col-12 custom-carousel-item custom-carousel-item-<%= image.id %>" data-id="<%= image.id %>">
<div class="border rounded relative p-3 mb-3 drag row align-items-center <%= image.online? ? '' : 'not_active' %>">
<div class="col-2 col-md-1 custom-carousel-item-no"><%= index + 1 %></div>
<div class="col-10 col-md-3 custom-carousel-item-img" data-source-id="<%= image.id %>" data-source-type="PortalImage" data-toggle="modal" data-target=".admin-upload-file-modal">
<img src="<%= Util::FileManage.exist?('PortalImage', image.id) ? Util::FileManage.disk_file_url('PortalImage', image.id) : '' %>" data-toggle="tooltip" data-title="重新上传"/>
</div>
<div class="col-10 col-md-7">
<div class="input-group">
<input type="text" value="<%= image.name %>" class="form-control name-input" placeholder="请输入名称" />
<input type="text" value="<%= image.link %>" class="form-control link-input" placeholder="请输入跳转地址">
<div class="input-group-prepend">
<button class="input-group-text save-data-btn" data-id="<%= image.id %>">保存</button>
</div>
</div>
</div>
<div class="col-2 col-md-1 operate-box">
<%= check_box_tag(:online, 1, image.online?, id: nil, class: 'online-check-box', data: { id: image.id, toggle: 'tooltip', title: '首页展示' }) %>
<%= delete_link '删除', cooperative_carousel_path(image, laboratory_id: image.laboratory_id, element: ".custom-carousel-item-#{image.id}", not_refresh: true), class: 'delete-btn' do %>
<i class="fa fa-trash-o" data-id="<%= image.id %>"></i>
<% end %>
</div>
</div>
</div>
<% end %>
</div>
</div>
<%= render partial: 'cooperative/carousels/shared/add_carousel_modal', locals: { laboratory_id: current_laboratory } %>
<%= render partial: 'cooperative/shared/modal/upload_file_modal' %>

@ -0,0 +1,36 @@
<div class="modal fade cooperative-add-carousel-modal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">添加轮播图</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<%= simple_form_for(PortalImage.new, url: cooperative_carousels_path(laboratory_id: laboratory_id), html: { class: 'cooperative-add-carousel-form', enctype: 'multipart/form-data' }) do |f| %>
<div class="form-group">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text">图片</span>
</div>
<div class="custom-file flex-row-reverse">
<input type="file" name="portal_image[image]" class="img-file-input" id="img-file-input" accept="image/*">
<label class="custom-file-label file-names" for="img-file-input">选择文件</label>
</div>
</div>
</div>
<%= f.input :name, label: '名称', placeholder: '请输入名称' %>
<%= f.input :link, as: :url, label: '跳转地址', placeholder: '请输入跳转地址' %>
<div class="error text-danger"></div>
<% end %>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
<button type="button" class="btn btn-primary submit-btn">确认</button>
</div>
</div>
</div>
</div>

@ -0,0 +1,3 @@
<% define_breadcrumbs do %>
<% add_breadcrumb('概览') %>
<% end %>

@ -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
-%>
<li class="page-item first-page">
<%= link_to_unless current_page.first?, t('views.pagination.first').html_safe, url, remote: remote, class: 'page-link' %>
</li>

@ -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
-%>
<li class="page-item">
<%= link_to 'javascript:void(0)', { class: 'page-link' } do %>
<%= t('views.pagination.truncate').html_safe %>
<span class="sr-only">(current)</span>
<% end %>
</li>

@ -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
-%>
<li class="page-item last-page">
<%= link_to_unless(current_page.last?, t('views.pagination.last').html_safe, url, remote: remote, class: 'page-link') %>
<li class="page-item last-page">

@ -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
-%>
<li class="page-item next">
<%= link_to_unless current_page.last?, t('views.pagination.next').html_safe, url, rel: 'next', remote: remote, class: 'page-link' %>
</li>

@ -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
-%>
<li class="page-item page<%= ' current active' if page.current? %>">
<% if page.current? %>
<%= link_to url, {remote: remote, rel: page.rel, class: 'page-link'} do %>
<%= page %>
<span class="sr-only">(current)</span>
<% end %>
<% else %>
<%= link_to page, url, {remote: remote, rel: page.rel, class: 'page-link'} %>
<% end %>
</li>

@ -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 -%>
<nav aria-label="Page navigation">
<ul class="pagination justify-content-center">
<%= first_page_tag unless current_page.first? %>
<%= prev_page_tag unless current_page.first? %>
<% each_page do |page| -%>
<% if page.display_tag? -%>
<%= page_tag page %>
<% elsif !page.was_truncated? -%>
<%= gap_tag %>
<% end -%>
<% end -%>
<% unless current_page.out_of_range? %>
<%= next_page_tag unless current_page.last? %>
<%= last_page_tag unless current_page.last? %>
<% end %>
</ul>
</nav>
<% end -%>

@ -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
-%>
<li class="page-item prev">
<%= link_to_unless current_page.first?, t('views.pagination.previous').html_safe, url, rel: 'prev', remote: remote, class: 'page-link' %>
</li>

@ -0,0 +1,129 @@
<% define_breadcrumbs do %>
<% add_breadcrumb('网站设置') %>
<% end %>
<div class="box edit-laboratory-setting-container">
<%= simple_form_for(@laboratory, url: cooperative_laboratory_setting_path(@laboratory), method: 'patch', html: { enctype: 'multipart/form-data' }) do |f| %>
<% setting = @laboratory.laboratory_setting %>
<div class="form-group px-2 setting-item">
<div class="setting-item-head"><h6>网站域名设置</h6></div>
<div class="dropdown-divider"></div>
<div class="pl-0 py-3 setting-item-body">
<div class="input-group col-12 col-md-4 px-0">
<div class="input-group-prepend">
<span class="input-group-text">https://</span>
</div>
<%= text_field_tag :identifier, @laboratory.identifier,
maxlength: 15, class: 'form-control font-16',
'onKeyUp': 'value=value.replace(/[^\w\.\-\/]/ig,"").toLowerCase()',
style: 'text-transform:lowercase'%>
<div class="input-group-append">
<% rails_env = EduSetting.get('rails_env') %>
<span class="input-group-text font-14" id="site-prefix"><%= rails_env && rails_env != 'production' ? ".#{rails_env}.educoder.net" : '.educoder.net' %></span>
</div>
</div>
<%# if @laboratory.errors && @laboratory.errors.key?(:identifier) %>
<!-- <span id="identifier-error" class="danger text-danger">二级域名已被使用</span>-->
<%# end %>
</div>
</div>
<div class="form-group px-2 setting-item">
<div class="setting-item-head"><h6>网站名称设置</h6></div>
<div class="dropdown-divider"></div>
<div class="pl-0 py-3 setting-item-body">
<%= text_field_tag :name, setting.name, placeholder: '输入20个字以内的网站名称', maxlength: 20, class: 'form-control col-12 col-md-4' %>
</div>
</div>
<div class="form-group px-2 setting-item">
<div class="setting-item-head"><h6>Logo设置</h6></div>
<div class="dropdown-divider"></div>
<div class="pl-0 py-3 row setting-item-body">
<div class="col-12 col-md-4 logo-item">
<% nav_logo_img = setting.nav_logo_url %>
<div class="logo-item-left mr-3 <%= nav_logo_img ? 'has-img' : '' %>">
<img class="logo-item-img nav-logo-img" src="<%= nav_logo_img %>" style="<%= nav_logo_img.present? ? '' : 'display: none' %>"/>
<%= file_field_tag(:nav_logo, accept: 'image/png,image/jpg,image/jpeg', style: 'display: none', value: params[:nav_logo]) %>
<label for="nav_logo" class="logo-item-upload" data-toggle="tooltip" data-title="选择图片"></label>
</div>
<div class="logo-item-right">
<div class="logo-item-title flex-1">网站导航logo</div>
<div>格式PNG、JPG</div>
<div>尺寸高度38px以内宽等比例缩放</div>
</div>
</div>
<div class="col-12 col-md-4 logo-item">
<% login_logo_img = setting.login_logo_url %>
<div class="logo-item-left mr-3 <%= login_logo_img ? 'has-img' : '' %>">
<img class="logo-item-img login-logo-img" src="<%= login_logo_img %>" style="<%= login_logo_img.present? ? '' : 'display: none' %>"/>
<%= file_field_tag(:login_logo, accept: 'image/png,image/jpg,image/jpeg', style: 'display: none', value: params[:login_logo]) %>
<label for="login_logo" class="logo-item-upload" data-toggle="tooltip" data-title="选择图片"></label>
</div>
<div class="logo-item-right">
<div class="logo-item-title flex-1">登录页面logo</div>
<div>格式PNG、JPG</div>
<div>尺寸高度90px以内宽等比例缩放</div>
</div>
</div>
<div class="col-12 col-md-4 logo-item">
<% tab_logo_img = setting.tab_logo_url %>
<div class="logo-item-left mr-3 <%= tab_logo_img ? 'has-img' : '' %>">
<img class="logo-item-img tab-logo-img" src="<%= tab_logo_img %>" style="<%= tab_logo_img.present? ? '' : 'display: none' %>"/>
<%= file_field_tag(:tab_logo, accept: 'image/x-icon', style: 'display: none', value: params[:tab_logo]) %>
<label for="tab_logo" class="logo-item-upload" data-toggle="tooltip" data-title="选择图片"></label>
</div>
<div class="logo-item-right">
<div class="logo-item-title flex-1">浏览器导航栏logo</div>
<div>格式ico</div>
<div>尺寸16*16 32*32 48*48 64*64 </div>
</div>
</div>
</div>
</div>
<div class="form-group px-2 setting-item">
<div class="setting-item-head"><h6>导航设置</h6></div>
<div class="dropdown-divider"></div>
<div class="pl-0 py-3 setting-item-body">
<table class="table">
<thead class="thead-light">
<tr>
<th width="35%">导航名称</th>
<th width="50%">导航链接</th>
<th width="15%" class="text-center">是否展示</th>
</tr>
</thead>
<tbody>
<% (setting.navbar || setting.default_navbar).each do |nav| %>
<tr>
<td><%= text_field_tag('navbar[][name]', nav['name'], id: nil, class: 'form-control') %></td>
<td><%= text_field_tag('navbar[][link]', nav['link'], id: nil, class: 'form-control') %></td>
<td class="text-center">
<%= check_box_tag('navbar[][hidden]', 0, !nav['hidden'], id: nil, class: 'font-16') %>
</td>
</tr>
<% end %>
</tbody>
</table>
</div>
</div>
<div class="form-group px-2 setting-item">
<div class="setting-item-head"><h6>底部备案信息设置</h6></div>
<div class="dropdown-divider"></div>
<div class="pl-0 my-3 setting-item-body" id="laboratory-footer-editor">
<%= text_area_tag(:footer, setting.footer, placeholder: '请输入备案信息', class: 'form-control', style: 'display: none;') %>
</div>
</div>
<div class="error my-2 danger text-danger"></div>
<div class="form-group mt-4">
<%= javascript_void_link '保存', class: 'btn btn-primary mr-3 px-4 submit-btn' %>
</div>
<% end %>
</div>

@ -0,0 +1,14 @@
<% define_breadcrumbs do %>
<% add_breadcrumb('管理员列表', cooperative_laboratory_users_path) %>
<% end %>
<div class="box search-form-container laboratory-user-list-form">
<div></div>
<%= javascript_void_link '添加管理员', class: 'btn btn-primary btn-sm', data: { toggle: 'modal', target: '.cooperative-add-laboratory-user-modal'} %>
</div>
<div class="box users-list-container">
<%= render partial: 'cooperative/laboratory_users/shared/list', locals: { laboratory_users: @laboratory_users } %>
</div>
<%= render 'cooperative/laboratory_users/shared/add_laboratory_user_modal' %>

@ -0,0 +1,28 @@
<div class="modal fade cooperative-add-laboratory-user-modal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">添加管理员</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form class="cooperative-add-laboratory-user-form">
<div class="form-group d-flex">
<label class="col-form-label">管理员:</label>
<div class="d-flex flex-column-reverse w-75">
<select id="user_ids" name="user_ids" class="form-control laboratory-user-select"></select>
</div>
</div>
<div class="error text-danger"></div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
<button type="button" class="btn btn-primary submit-btn">确认</button>
</div>
</div>
</div>
</div>

@ -0,0 +1,41 @@
<table class="table table-hover laboratory-user-list-table">
<thead class="thead-light">
<tr>
<th width="8%">头像</th>
<th width="12%" class="text-left">真实姓名</th>
<th width="20%">邮件地址</th>
<th width="20%">手机号码</th>
<th width="30%">单位部门</th>
<th width="10%">操作</th>
</tr>
</thead>
<tbody>
<% if laboratory_users.present? %>
<% laboratory_users.each do |laboratory_user| %>
<% user = laboratory_user.user %>
<tr class="laboratory-user-item-<%= laboratory_user.id %>">
<td class="text-left">
<%= link_to "/users/#{user.login}", target: '_blank' do %>
<img src="/images/<%= url_to_avatar(user) %>" class="rounded-circle" width="40" height="40" />
<% end %>
</td>
<td class="text-left">
<%= link_to "/users/#{user.login}", target: '_blank' do %>
<%= overflow_hidden_span user.real_name, width: 100 %>
<% end %>
</td>
<td><%= overflow_hidden_span display_text(user.mail), width: 150 %></td>
<td><%= overflow_hidden_span display_text(user.phone), width: 100 %></td>
<td><%= [user.school_name.presence, user.department_name.presence].compact.join('-') %></td>
<td class="action-container">
<%= delete_link '删除', cooperative_laboratory_user_path(laboratory_user, element: ".laboratory-user-item-#{laboratory_user.id}"), class: 'delete-laboratory-user-action' %>
</td>
</tr>
<% end %>
<% else %>
<%= render 'admins/shared/no_data_for_table' %>
<% end %>
</tbody>
</table>
<%= render partial: 'cooperative/shared/paginate', locals: { objects: laboratory_users } %>

@ -0,0 +1 @@
<tr class="no-data"><td colspan="100">暂无数据</td></tr>

@ -0,0 +1,6 @@
<div class="paginate-container">
<% if objects && objects.size.nonzero? %>
<div class="paginate-total"><%= page_entries_info objects %></div>
<% end %>
<%= paginate objects, views_prefix: 'cooperative', remote: true %>
</div>

@ -0,0 +1,22 @@
<% sidebar_collapse = request.cookies['cooperative_sidebar_collapse'].to_s == 'true' %>
<nav id="sidebar" class="<%= sidebar_collapse ? 'active' : '' %>" data-current-controller="<%= sidebar_controller %>">
<div class="sidebar-header">
<a href="/" class="sidebar-header-logo" data-toggle="tooltip" title="返回主页">
<img src="<%= current_setting_or_default(:nav_logo_url) %>"/>
<span class="logo-label">后台管理</span>
</a>
<div id="sidebarCollapse" class="navbar-btn <%= sidebar_collapse ? 'active' : '' %>">
<i class="fa fa-chevron-left fold" data-toggle="tooltip" data-placement="right" data-boundary="window" title="收起"></i>
<i class="fa fa-bars unfold" data-toggle="tooltip" data-placement="right" data-boundary="window" title="展开"></i>
</div>
</div>
<!-- Sidebar Links -->
<ul class="list-unstyled components">
<!-- <li><%#= sidebar_item(cooperative_path, '概览', icon: 'dashboard', controller: 'cooperative-dashboards') %></li>-->
<li><%= sidebar_item(edit_cooperative_laboratory_setting_path, '网站设置', icon: 'cogs', controller: 'cooperative-laboratory_settings') %></li>
<li><%= sidebar_item(cooperative_carousels_path, '轮播图设置', icon: 'image', controller: 'cooperative-carousels') %></li>
<li><%= sidebar_item(cooperative_laboratory_users_path, '管理员列表', icon: 'user', controller: 'cooperative-laboratory_users') %></li>
<li><%= sidebar_item('/', '返回主页', icon: 'sign-out', controller: 'root') %></li>
</ul>
</nav>

@ -0,0 +1,4 @@
;
$('[data-toggle="tooltip"]').tooltip({ trigger : 'hover' });
$('[data-toggle="popover"]').popover();
$('img.preview-image').bootstrapViewer();

@ -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();
}

@ -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);

@ -0,0 +1,18 @@
<div class="modal fade cooperative-message-modal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">消息</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body" style="max-height: 300px; overflow-y: scroll;">
保存成功
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary submit-btn" data-dismiss="modal">确认</button>
</div>
</div>
</div>
</div>

@ -0,0 +1,32 @@
<div class="modal fade cooperative-upload-file-modal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title"><%= title ||= '上传文件' %></h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form class="cooperative-upload-file-form" enctype="multipart/form-data">
<%= hidden_field_tag(:source_type, nil) %>
<%= hidden_field_tag(:source_id, nil) %>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text">文件</span>
</div>
<div class="custom-file">
<input type="file" name="file" class="upload-file-input" id="upload-file-input">
<label class="custom-file-label file-names" for="upload-file-input">选择文件</label>
</div>
</div>
<div class="error text-danger"></div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
<button type="button" class="btn btn-primary submit-btn" data-disable-with="上传中...">上传</button>
</div>
</div>
</div>
</div>

@ -0,0 +1,6 @@
json.count @users.total_count
json.users do
json.array! @users.each do |user|
json.extract! user, :id, :login, :real_name, :identity, :school_name
end
end

@ -21,12 +21,12 @@
<!-- Page Content -->
<div class="admin-body-container">
<div class="admin-alert-container">
<%= render 'admins/shared/flash_notice' %>
<%= render 'shared/flash_notice' %>
</div>
<div class="breadcrumb-container">
<%= yield :setup_admin_breadcrumb %>
<%= render(partial: 'admins/shared/breadcrumb') %>
<%= render(partial: 'shared/breadcrumb') %>
</div>
<div class="content">

@ -0,0 +1,42 @@
<!DOCTYPE html>
<html>
<head>
<title><%= current_laboratory.school&.name || 'EduCoder' %>-后台管理</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel='shortcut icon' type='image/x-icon' href='<%= current_setting_or_default(:tab_logo_url) %>' />
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= stylesheet_link_tag 'cooperative', media: 'all','data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'cooperative', 'data-turbolinks-track': 'reload' %>
</head>
<% body_class = [params[:controller].gsub(/\//, '-').gsub('_', '-'), params[:action], 'page'].join('-') %>
<body class="<%= body_class %>">
<!-- Sidebar -->
<%= render partial: 'cooperative/shared/sidebar' %>
<!-- Page Content -->
<div class="cooperative-body-container">
<div class="cooperative-alert-container">
<%= render 'shared/flash_notice' %>
</div>
<div class="cooperative-breadcrumb-container">
<%= yield :setup_breadcrumb %>
<%= render(partial: 'shared/breadcrumb') %>
</div>
<div class="content">
<%= yield %>
</div>
</div>
<div class="cooperative-modal-container"></div>
<!-- message modal -->
<%= render 'cooperative/shared/modal/message_modal' %>
</body>
</html>

@ -1,8 +1,8 @@
<% if @_admin_breadcrumbs.present? %>
<% if @_breadcrumbs.present? %>
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<% @_admin_breadcrumbs&.each_with_index do |item, index| %>
<% if item.url.present? && index != @_admin_breadcrumbs.size - 1 %>
<% @_breadcrumbs&.each_with_index do |item, index| %>
<% if item.url.present? && index != @_breadcrumbs.size - 1 %>
<li class="breadcrumb-item"><%= link_to item.text, item.url %></li>
<% else %>
<li class="breadcrumb-item active" aria-current="page"><%= item.text %></li>

@ -27,3 +27,9 @@ json.base_info_completed user.profile_completed?
json.all_certified user.all_certified?
json.has_password user.hashed_password.present?
json.open_users do
json.array! user.open_users do |open_user|
json.extract! open_user, :id, :en_type, :nickname
end
end

@ -39,6 +39,9 @@ json.top do
json.college_identifier @user.college_identifier
# 旧版的域名
json.old_url @old_domain
# 云上实验室管理权限
json.laboratory_user current_laboratory.laboratory_users.exists?(user_id: @user&.id) || @user&.admin_or_business?
end
json.down do

@ -12,5 +12,5 @@ Rails.application.config.assets.paths << Rails.root.join('vendor/assets')
# Precompile additional assets.
# application.js, application.css, and all non-JS/CSS in the app/assets
# folder are already added.
Rails.application.config.assets.precompile += %w( admin.js admin.css college.js college.css )
Rails.application.config.assets.precompile += %w( admin.js admin.css college.js college.css cooperative.js cooperative.css )

@ -116,6 +116,7 @@ Rails.application.routes.draw do
resource :auth_attachment, only: [:create]
resource :authentication_apply, only: [:create]
resource :professional_auth_apply, only: [:create]
resources :open_users, only: [:destroy]
end
end
end
@ -1005,6 +1006,17 @@ Rails.application.routes.draw do
end
end
namespace :cooperative do
# get '/', to: 'dashboards#show'
get '/', to: 'laboratory_settings#edit'
resources :users, only: [:index]
resources :laboratory_users, only: [:index, :create, :destroy]
resource :laboratory_setting, only: [:edit, :update]
resources :carousels, only: [:index, :create, :update, :destroy] do
post :drag, on: :collection
end
end
resources :colleges, only: [] do
member do
get :statistics

@ -0,0 +1,5 @@
class AddExtraToOpenUsers < ActiveRecord::Migration[5.2]
def change
add_column :open_users, :extra, :text
end
end

File diff suppressed because one or more lines are too long

@ -25315,9 +25315,10 @@ input.form-control {
display: block;
width: 80px;
height: 80px;
background: #f0f0f0;
}
/* line 36, app/assets/stylesheets/admins/laboratories.scss */
/* line 37, app/assets/stylesheets/admins/laboratories.scss */
.admins-laboratory-settings-show-page .edit-laboratory-setting-container .logo-item-upload, .admins-laboratory-settings-update-page .edit-laboratory-setting-container .logo-item-upload {
cursor: pointer;
position: absolute;
@ -25328,7 +25329,7 @@ input.form-control {
border: 1px solid #E5E5E5;
}
/* line 45, app/assets/stylesheets/admins/laboratories.scss */
/* line 46, app/assets/stylesheets/admins/laboratories.scss */
.admins-laboratory-settings-show-page .edit-laboratory-setting-container .logo-item-upload::before, .admins-laboratory-settings-update-page .edit-laboratory-setting-container .logo-item-upload::before {
content: '';
position: absolute;
@ -25339,7 +25340,7 @@ input.form-control {
background: #E5E5E5;
}
/* line 55, app/assets/stylesheets/admins/laboratories.scss */
/* line 56, app/assets/stylesheets/admins/laboratories.scss */
.admins-laboratory-settings-show-page .edit-laboratory-setting-container .logo-item-upload::after, .admins-laboratory-settings-update-page .edit-laboratory-setting-container .logo-item-upload::after {
content: '';
position: absolute;
@ -25350,25 +25351,25 @@ input.form-control {
background: #E5E5E5;
}
/* line 66, app/assets/stylesheets/admins/laboratories.scss */
/* line 67, app/assets/stylesheets/admins/laboratories.scss */
.admins-laboratory-settings-show-page .edit-laboratory-setting-container .logo-item-left, .admins-laboratory-settings-update-page .edit-laboratory-setting-container .logo-item-left {
position: relative;
width: 80px;
height: 80px;
}
/* line 72, app/assets/stylesheets/admins/laboratories.scss */
/* line 73, app/assets/stylesheets/admins/laboratories.scss */
.admins-laboratory-settings-show-page .edit-laboratory-setting-container .logo-item-left.has-img .logo-item-upload, .admins-laboratory-settings-update-page .edit-laboratory-setting-container .logo-item-left.has-img .logo-item-upload {
display: none;
}
/* line 77, app/assets/stylesheets/admins/laboratories.scss */
/* line 78, app/assets/stylesheets/admins/laboratories.scss */
.admins-laboratory-settings-show-page .edit-laboratory-setting-container .logo-item-left.has-img:hover .logo-item-upload, .admins-laboratory-settings-update-page .edit-laboratory-setting-container .logo-item-left.has-img:hover .logo-item-upload {
display: block;
background: rgba(145, 145, 145, 0.8);
}
/* line 85, app/assets/stylesheets/admins/laboratories.scss */
/* line 86, app/assets/stylesheets/admins/laboratories.scss */
.admins-laboratory-settings-show-page .edit-laboratory-setting-container .logo-item-right, .admins-laboratory-settings-update-page .edit-laboratory-setting-container .logo-item-right {
display: -webkit-box;
display: flex;
@ -25381,7 +25382,7 @@ input.form-control {
font-size: 12px;
}
/* line 93, app/assets/stylesheets/admins/laboratories.scss */
/* line 94, app/assets/stylesheets/admins/laboratories.scss */
.admins-laboratory-settings-show-page .edit-laboratory-setting-container .logo-item-title, .admins-laboratory-settings-update-page .edit-laboratory-setting-container .logo-item-title {
color: #23272B;
font-size: 14px;

@ -27922,6 +27922,14 @@ function customConfirm(opts){
}
return $.confirm($.extend({}, defaultOpts, opts))
}
function show_success_flash(){
$.notify({
message: '操作成功'
},{
type: 'success'
});
}
;
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :

File diff suppressed because one or more lines are too long

@ -238,7 +238,7 @@ function generateNewIndexJsp() {
fs2.writeFile(outputPath, result, 'utf8', function (err) {
if (err) return console.log(err);
commitAndPush();
// commitAndPush();
});
});
}

@ -287,7 +287,7 @@ class App extends Component {
Addcoursestypes:false,
mydisplay:false,
occupation:0,
mygetHelmetapi:undefined,
mygetHelmetapi: null,
}
}
@ -386,6 +386,9 @@ class App extends Component {
}
document.head.appendChild(link);
}else {
this.setState({
mygetHelmetapi: undefined
});
document.title = "EduCoder";
var link = document.createElement('link'),
oldLink = document.getElementById('dynamic-favicon');
@ -399,6 +402,9 @@ class App extends Component {
}
}else{
this.setState({
mygetHelmetapi: undefined
});
document.title = "EduCoder";
var link = document.createElement('link'),
oldLink = document.getElementById('dynamic-favicon');
@ -412,6 +418,9 @@ class App extends Component {
}
}).catch((error) => {
this.setState({
mygetHelmetapi: undefined
});
document.title = "EduCoder";
var link = document.createElement('link'),
oldLink = document.getElementById('dynamic-favicon');

@ -241,7 +241,7 @@ class CoursesBanner extends Component {
if (i ===5) {
s = `“复制”功能将会为您创建一个新的课堂`;
ss = "请问是否继续?";
let mid="旧课堂的作业、资源、试卷都将被复制到新的课堂里面 ";
let mid="旧课堂的作业、资源、试卷都将被复制到新的课堂里面";
this.showActionPoll(i,s,ss,mid)
}

@ -140,8 +140,8 @@ class EducoderLogin extends Component {
render() {
let {showbool,loginstatus,logini} = this.state;
console.log("EducoderLogingetHelmetapi");
console.log(this.props);
// console.log("EducoderLogingetHelmetapi");
// console.log(this.props);
// console.log(this.props.mygetHelmetapi);
return (
<div style={newContainer} className=" clearfix" >
@ -154,7 +154,8 @@ class EducoderLogin extends Component {
"width": "100%"
}}>
<div style={{cursor:"pointer"}}>
{
{this.props.mygetHelmetapi === null ? ""
:
this.props.mygetHelmetapi===undefined||this.props.mygetHelmetapi.login_logo_url===null|| this.props.mygetHelmetapi.login_logo_url===undefined?
<img style={{cursor:"pointer"}} onClick={()=>this.gohome()} src={educodernet}/>
:

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save