Merge branch 'dev_aliyun' of http://bdgit.educoder.net/Hjqreturn/educoder into dev_aliyun
commit
0d1256a6d8
After Width: | Height: | Size: 2.8 KiB |
File diff suppressed because one or more lines are too long
@ -0,0 +1,40 @@
|
||||
//= 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_tree ./i18n
|
||||
//= require_tree ./admins
|
||||
|
||||
// ******** select2 global config ********
|
||||
$.fn.select2.defaults.set('theme', 'bootstrap4');
|
||||
$.fn.select2.defaults.set('language', 'zh-CN');
|
||||
|
||||
$(document).on('turbolinks:load', function(){
|
||||
$('[data-toggle="tooltip"]').tooltip();
|
||||
$('[data-toggle="popover"]').popover();
|
||||
|
||||
// flash alert提示框自动关闭
|
||||
if($('.admin-alert-container .alert').length > 0){
|
||||
setTimeout(function(){
|
||||
$('.admin-alert-container .alert').alert('close');
|
||||
}, 2000);
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on("turbolinks:before-cache", function () {
|
||||
$('[data-toggle="tooltip"]').tooltip('hide');
|
||||
$('[data-toggle="popover"]').popover('hide');
|
||||
});
|
||||
|
||||
$(function () {
|
||||
});
|
@ -0,0 +1,12 @@
|
||||
$(document).on('turbolinks:load', function(){
|
||||
if ($('body.admins-daily-school-statistics-index-page').length > 0) {
|
||||
$('.export-action').on('click', function(){
|
||||
var form = $(".daily-school-statistic-list-form .search-form")
|
||||
var exportLink = $(this);
|
||||
var keyword = form.find("input[name='keyword']").val();
|
||||
|
||||
var url = exportLink.data("url").split('?')[0] + "?keyword=" + keyword;
|
||||
window.open(url);
|
||||
});
|
||||
}
|
||||
})
|
@ -0,0 +1,135 @@
|
||||
$(document).on('turbolinks:load', function(){
|
||||
if ($('body.admins-school-statistics-index-page').length > 0) {
|
||||
var searchForm = $(".school-statistic-list-form .search-form");
|
||||
var growFormUrl = searchForm.data('grow-form-url');
|
||||
var contrastFormUrl = searchForm.data('contrast-form-url');
|
||||
|
||||
var dataTypeInput = searchForm.find("input[name='data_type']");
|
||||
var keywordInput = searchForm.find("input[name='keyword']");
|
||||
var contrastBtn = searchForm.find(".contrast-btn");
|
||||
var growBtn = searchForm.find(".grow-btn");
|
||||
var contrastDateContainer = searchForm.find('.contrast-date-container');
|
||||
var growDateContainer = searchForm.find('.grow-date-container');
|
||||
|
||||
// 数据对比日期输入框
|
||||
var beginDateInput = searchForm.find("input[name='begin_date']");
|
||||
var endDateInput = searchForm.find("input[name='end_date']");
|
||||
var otherBeginDateInput = searchForm.find("input[name='other_begin_date']");
|
||||
var otherEndDateInput = searchForm.find("input[name='other_end_date']");
|
||||
|
||||
// 新增数据日期输入框
|
||||
var growBeginDateInput = searchForm.find("input[name='grow_begin_date']");
|
||||
var growEndDateInput = searchForm.find("input[name='grow_end_date']");
|
||||
|
||||
// 数据展示切换: 数据对比、新增数据
|
||||
searchForm.on('click', ".contrast-btn", function(){
|
||||
if(contrastBtn.hasClass("active")) { return }
|
||||
changeDataType("contrast");
|
||||
submitForm();
|
||||
});
|
||||
searchForm.on('click', ".grow-btn", function(){
|
||||
if(growBtn.hasClass("active")) { return }
|
||||
changeDataType("grow");
|
||||
submitForm();
|
||||
});
|
||||
|
||||
// 搜索按钮
|
||||
searchForm.on('click', ".search-btn", function(){
|
||||
console.log('submit');
|
||||
submitForm();
|
||||
});
|
||||
|
||||
$('.school-statistic-list-container').on('change', '.contrast-column-select', function() {
|
||||
searchForm.find("input[name='contrast_column']").val($('.contrast-column-select').val());
|
||||
submitForm();
|
||||
});
|
||||
|
||||
var submitForm = function(){
|
||||
if(!validateFrom()) { return }
|
||||
|
||||
var form = searchForm;
|
||||
var url = dataTypeInput.val() == "contrast" ? contrastFormUrl : growFormUrl;
|
||||
|
||||
$.ajax({
|
||||
url: url,
|
||||
data: form.serialize(),
|
||||
dataType: "script"
|
||||
})
|
||||
};
|
||||
|
||||
var validateFrom = function(){
|
||||
if (dataTypeInput.val() != "contrast") { return true; }
|
||||
|
||||
// 全部为空时,需要展示空数据页
|
||||
if (beginDateInput.val() == "" && endDateInput.val() == "" &&
|
||||
otherBeginDateInput.val() == "" && otherBeginDateInput.val() == "") {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (beginDateInput.val() != "" && endDateInput.val() != "" &&
|
||||
otherBeginDateInput.val() != "" && otherBeginDateInput.val() != "") {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
var changeDataType = function(dataType){
|
||||
if (dataTypeInput.val() == dataType) { return }
|
||||
|
||||
if (dataType == "contrast") {
|
||||
contrastBtn.addClass("active");
|
||||
growBtn.removeClass("active");
|
||||
dataTypeInput.val('contrast');
|
||||
growDateContainer.hide();
|
||||
contrastDateContainer.show();
|
||||
|
||||
clearGrowDateInput();
|
||||
} else {
|
||||
contrastBtn.removeClass("active");
|
||||
growBtn.addClass("active");
|
||||
dataTypeInput.val('grow');
|
||||
growDateContainer.show();
|
||||
contrastDateContainer.hide();
|
||||
|
||||
clearContrastDateInput();
|
||||
}
|
||||
};
|
||||
|
||||
var clearGrowDateInput = function() {
|
||||
searchForm.find("input[name='grow_begin_date']").val('');
|
||||
searchForm.find("input[name='grow_end_date']").val('');
|
||||
searchForm.find("input[name='grow_date_input']").val('');
|
||||
};
|
||||
|
||||
var clearContrastDateInput = function(){
|
||||
searchForm.find("input[name='begin_date']").val('');
|
||||
searchForm.find("input[name='end_date']").val('');
|
||||
searchForm.find("input[name='other_begin_date']").val('');
|
||||
searchForm.find("input[name='other_end_date']").val('');
|
||||
searchForm.find("input[name='date_input']").val('');
|
||||
searchForm.find("input[name='other_date_input']").val('');
|
||||
};
|
||||
|
||||
var baseOptions = {
|
||||
autoclose: true,
|
||||
language: 'zh-CN',
|
||||
format: 'yyyy-mm-dd',
|
||||
startDate: '2017-04-01',
|
||||
endDate: '-1d'
|
||||
}
|
||||
|
||||
var defineDateRangeSelect = function(element){
|
||||
var options = $.extend({inputs: $(element).find('.start-date, .end-date')}, baseOptions);
|
||||
$(element).datepicker(options);
|
||||
|
||||
$(element).find('.start-date').datepicker().on('changeDate', function(e){
|
||||
$(element).find('.end-date').datepicker('setStartDate', e.date);
|
||||
})
|
||||
};
|
||||
|
||||
defineDateRangeSelect('.grow-date-input-daterange');
|
||||
defineDateRangeSelect('.date-input-daterange');
|
||||
defineDateRangeSelect('.other-date-input-daterange');
|
||||
}
|
||||
})
|
@ -0,0 +1,16 @@
|
||||
$(document).on('turbolinks:load', function(){
|
||||
$('#sidebarCollapse').on('click', function () {
|
||||
$(this).toggleClass('active');
|
||||
$('#sidebar').toggleClass('active');
|
||||
$.cookie('admin_sidebar_collapse', $(this).hasClass('active'), {path: '/admins'});
|
||||
});
|
||||
|
||||
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');
|
||||
}
|
||||
});
|
@ -0,0 +1,156 @@
|
||||
$(document).on('turbolinks:load', function() {
|
||||
if ($('body.admins-users-edit-page, body.admins-users-update-page').length > 0) {
|
||||
var initDepartmentSelect = true;
|
||||
|
||||
// ************** 学校选择 *************
|
||||
var matcherFunc = function(params, data){
|
||||
if ($.trim(params.term) === '') {
|
||||
return data;
|
||||
}
|
||||
if (typeof data.text === 'undefined') {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (data.name && data.name.indexOf(params.term) > -1) {
|
||||
var modifiedData = $.extend({}, data, true);
|
||||
return modifiedData;
|
||||
}
|
||||
|
||||
// Return `null` if the term should not be displayed
|
||||
return null;
|
||||
}
|
||||
|
||||
var defineSchoolSelect = function (schools) {
|
||||
$('.school-select').select2({
|
||||
theme: 'bootstrap4',
|
||||
placeholder: '查询学校/单位',
|
||||
minimumInputLength: 1,
|
||||
data: schools,
|
||||
templateResult: function (item) {
|
||||
if(!item.id || item.id === '') return item.text;
|
||||
return item.name;
|
||||
},
|
||||
templateSelection: function(item){
|
||||
if (item.id) {
|
||||
$('#user_school_id').val(item.id);
|
||||
getDepartmentsData(item.id, defineDepartmentSelect2);
|
||||
}
|
||||
return item.name || item.text;
|
||||
},
|
||||
matcher: matcherFunc
|
||||
});
|
||||
};
|
||||
|
||||
var defineDepartmentSelect2 = function(departments){
|
||||
departments.unshift({ id: '-1', name: '未选择' }); // 可不选
|
||||
|
||||
if (!initDepartmentSelect) { $('.department-select').empty(); } // 为了能够回填部门
|
||||
initDepartmentSelect = false;
|
||||
|
||||
$('.department-select').select2({
|
||||
theme: 'bootstrap4',
|
||||
placeholder: '查询学院/部门',
|
||||
minimumInputLength: 0,
|
||||
data: departments,
|
||||
templateResult: function (item) {
|
||||
if(!item.id || item.id === '') return item.text;
|
||||
return item.name;
|
||||
},
|
||||
templateSelection: function(item){
|
||||
if (item.id) {
|
||||
$('#user_department_id').val(item.id);
|
||||
}
|
||||
return item.name || item.text;
|
||||
},
|
||||
matcher: matcherFunc
|
||||
});
|
||||
};
|
||||
|
||||
var getDepartmentsData = function(school_id, callback){
|
||||
$.ajax({
|
||||
url: '/api/schools/' + school_id + '/departments/for_option.json',
|
||||
dataType: 'json',
|
||||
type: 'GET',
|
||||
success: function(data) {
|
||||
callback(data.departments);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 初始化学校选择器
|
||||
$.ajax({
|
||||
url: '/api/schools/for_option.json',
|
||||
dataType: 'json',
|
||||
type: 'GET',
|
||||
success: function(data) {
|
||||
defineSchoolSelect(data.schools);
|
||||
}
|
||||
});
|
||||
|
||||
// **************** 地区选择 ****************
|
||||
$('.province-city-select').cxSelect({
|
||||
url: '/javascripts/educoder/province-data.json',
|
||||
selects: ['province-select', 'city-select']
|
||||
});
|
||||
|
||||
// *********** 职业选择 ************
|
||||
var identityData = [
|
||||
{
|
||||
"v": "teacher",
|
||||
"n": "教师",
|
||||
"s": [{"n": "教授", "v": "教授"},{"n": "副教授", "v": "副教授"},{"n": "讲师", "v": "讲师"},{"n": "助教", "v": "助教"}]
|
||||
},
|
||||
{
|
||||
"v": "student",
|
||||
"n": "学生",
|
||||
"s": []
|
||||
},
|
||||
{
|
||||
"v": "professional",
|
||||
"n": "专业人士",
|
||||
"s": [{"n": "企业管理者", "v": "企业管理者"},{"n": "部门管理者", "v": "部门管理者"},{"n": "高级工程师", "v": "高级工程师"},{"n": "工程师", "v": "工程师"},{"n": "助理工程师", "v": "助理工程师"}]
|
||||
}
|
||||
];
|
||||
$('.user-identity-select').cxSelect({
|
||||
data: identityData,
|
||||
jsonValue: 'v',
|
||||
selects: ['identity-select', 'technical-title-select']
|
||||
});
|
||||
$('.identity-select').on('change', function(){
|
||||
if($(this).val() === 'student'){
|
||||
$('.technical-title-select-wrapper').hide();
|
||||
$('.form-group.user_student_id').show();
|
||||
} else {
|
||||
$('.technical-title-select-wrapper').show();
|
||||
$('.form-group.user_student_id').hide();
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
var $form = $('form.edit_user')
|
||||
$form.validate({
|
||||
errorElement: 'span',
|
||||
errorClass: 'danger text-danger',
|
||||
rules: {
|
||||
"user[password]": {
|
||||
required: false,
|
||||
minlength: 5
|
||||
},
|
||||
"user[password_confirmation]": {
|
||||
required: false,
|
||||
minlength: 5,
|
||||
equalTo: "#user_password"
|
||||
},
|
||||
},
|
||||
messages: {
|
||||
"user[password_confirmation]": {
|
||||
equalTo: "两次密码输入不一致"
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
$form.submit(function(e){
|
||||
if(!$form.valid()){ e.preventDefault(); }
|
||||
})
|
||||
}
|
||||
});
|
@ -0,0 +1,121 @@
|
||||
$(document).on('turbolinks:load', function(){
|
||||
if ($('body.admins-users-index-page').length > 0) {
|
||||
|
||||
var showSuccessNotify = function() {
|
||||
$.notify({
|
||||
message: '操作成功'
|
||||
},{
|
||||
type: 'success'
|
||||
});
|
||||
}
|
||||
|
||||
// lock user
|
||||
$('.users-list-container').on('click', '.lock-action', function(){
|
||||
var $lockAction = $(this);
|
||||
var $unlockAction = $lockAction.siblings('.unlock-action');
|
||||
|
||||
var userId = $lockAction.data('id');
|
||||
|
||||
$.ajax({
|
||||
url: '/admins/users/' + userId + '/lock',
|
||||
method: 'POST',
|
||||
dataType: 'json',
|
||||
success: function() {
|
||||
showSuccessNotify();
|
||||
$lockAction.hide();
|
||||
$unlockAction.show();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// unlock user
|
||||
$('.users-list-container').on('click', '.unlock-action', function(){
|
||||
var $unlockAction = $(this);
|
||||
var $lockAction = $unlockAction.siblings('.lock-action');
|
||||
|
||||
var userId = $unlockAction.data('id');
|
||||
|
||||
$.ajax({
|
||||
url: '/admins/users/' + userId + '/unlock',
|
||||
method: 'POST',
|
||||
dataType: 'json',
|
||||
success: function() {
|
||||
showSuccessNotify();
|
||||
$lockAction.show();
|
||||
$unlockAction.hide();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// active user
|
||||
$('.users-list-container').on('click', '.active-action', function(){
|
||||
var $activeAction = $(this);
|
||||
var $unlockAction = $activeAction.siblings('.unlock-action');
|
||||
var $lockAction = $activeAction.siblings('.lock-action');
|
||||
|
||||
var userId = $activeAction.data('id');
|
||||
|
||||
$.ajax({
|
||||
url: '/admins/users/' + userId + '/unlock',
|
||||
method: 'POST',
|
||||
dataType: 'json',
|
||||
success: function() {
|
||||
showSuccessNotify();
|
||||
$activeAction.hide();
|
||||
$lockAction.show();
|
||||
$unlockAction.hide();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// ***************** reward grade modal *****************
|
||||
var $rewardGradeModal = $('.admin-users-reward-grade-modal');
|
||||
var $form = $rewardGradeModal.find('form.admin-users-reward-grade-form');
|
||||
|
||||
$form.validate({
|
||||
errorElement: 'span',
|
||||
errorClass: 'danger text-danger',
|
||||
rules: {
|
||||
grade: {
|
||||
required: true,
|
||||
digits: true
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
// modal ready fire
|
||||
$rewardGradeModal.on('show.bs.modal', function (event) {
|
||||
var $link = $(event.relatedTarget);
|
||||
|
||||
var userId = $link.data('id');
|
||||
$rewardGradeModal.find('.modal-body input[name="user_id"]').val(userId);
|
||||
});
|
||||
// modal visited fire
|
||||
$rewardGradeModal.on('shown.bs.modal', function(){
|
||||
$rewardGradeModal.find('.modal-body input[name="grade"]').focus();
|
||||
});
|
||||
|
||||
$('.admin-users-reward-grade-modal .submit-btn').on('click', function(){
|
||||
$form.find('.error').html('');
|
||||
|
||||
if ($form.valid()) {
|
||||
var userId = $form.find('input[name="user_id"]').val();
|
||||
|
||||
$.ajax({
|
||||
method: 'POST',
|
||||
dataType: 'json',
|
||||
url: "/admins/users/" + userId + "/reward_grade",
|
||||
data: $form.serialize(),
|
||||
success: function(data) {
|
||||
showSuccessNotify();
|
||||
$('.users-list-container .user-item-' + userId + ' td.grade-content').html(data.grade);
|
||||
$rewardGradeModal.modal('hide');
|
||||
},
|
||||
error: function(res) {
|
||||
$rewardGradeModal.find('.error').html(res.responseJSON.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,350 @@
|
||||
/*
|
||||
* Project: Bootstrap Notify = v3.1.3
|
||||
* Description: Turns standard Bootstrap alerts into "Growl-like" notifications.
|
||||
* Author: Mouse0270 aka Robert McIntosh
|
||||
* License: MIT License
|
||||
* Website: https://github.com/mouse0270/bootstrap-growl
|
||||
*/
|
||||
(function (factory) {
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
// AMD. Register as an anonymous module.
|
||||
define(['jquery'], factory);
|
||||
} else if (typeof exports === 'object') {
|
||||
// Node/CommonJS
|
||||
factory(require('jquery'));
|
||||
} else {
|
||||
// Browser globals
|
||||
factory(jQuery);
|
||||
}
|
||||
}(function ($) {
|
||||
// Create the defaults once
|
||||
var defaults = {
|
||||
element: 'body',
|
||||
position: null,
|
||||
type: "info",
|
||||
allow_dismiss: true,
|
||||
newest_on_top: false,
|
||||
showProgressbar: false,
|
||||
placement: {
|
||||
from: "top",
|
||||
align: "right"
|
||||
},
|
||||
offset: 20,
|
||||
spacing: 10,
|
||||
z_index: 1031,
|
||||
delay: 1000,
|
||||
timer: 1000,
|
||||
url_target: '_blank',
|
||||
mouse_over: null,
|
||||
animate: {
|
||||
enter: 'animated fadeInDown',
|
||||
exit: 'animated fadeOutUp'
|
||||
},
|
||||
onShow: null,
|
||||
onShown: null,
|
||||
onClose: null,
|
||||
onClosed: null,
|
||||
icon_type: 'class',
|
||||
template: '<div data-notify="container" class="col-xs-4 col-sm-2 alert alert-{0}" role="alert"><button type="button" aria-hidden="true" class="close" data-notify="dismiss">×</button><span data-notify="icon"></span> <span data-notify="title">{1}</span> <span data-notify="message">{2}</span><div class="progress" data-notify="progressbar"><div class="progress-bar progress-bar-{0}" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%;"></div></div><a href="{3}" target="{4}" data-notify="url"></a></div>'
|
||||
};
|
||||
|
||||
String.format = function() {
|
||||
var str = arguments[0];
|
||||
for (var i = 1; i < arguments.length; i++) {
|
||||
str = str.replace(RegExp("\\{" + (i - 1) + "\\}", "gm"), arguments[i]);
|
||||
}
|
||||
return str;
|
||||
};
|
||||
|
||||
function Notify ( element, content, options ) {
|
||||
// Setup Content of Notify
|
||||
var content = {
|
||||
content: {
|
||||
message: typeof content == 'object' ? content.message : content,
|
||||
title: content.title ? content.title : '',
|
||||
icon: content.icon ? content.icon : '',
|
||||
url: content.url ? content.url : '#',
|
||||
target: content.target ? content.target : '-'
|
||||
}
|
||||
};
|
||||
|
||||
options = $.extend(true, {}, content, options);
|
||||
this.settings = $.extend(true, {}, defaults, options);
|
||||
this._defaults = defaults;
|
||||
if (this.settings.content.target == "-") {
|
||||
this.settings.content.target = this.settings.url_target;
|
||||
}
|
||||
this.animations = {
|
||||
start: 'webkitAnimationStart oanimationstart MSAnimationStart animationstart',
|
||||
end: 'webkitAnimationEnd oanimationend MSAnimationEnd animationend'
|
||||
}
|
||||
|
||||
if (typeof this.settings.offset == 'number') {
|
||||
this.settings.offset = {
|
||||
x: this.settings.offset,
|
||||
y: this.settings.offset
|
||||
};
|
||||
}
|
||||
|
||||
this.init();
|
||||
};
|
||||
|
||||
$.extend(Notify.prototype, {
|
||||
init: function () {
|
||||
var self = this;
|
||||
|
||||
this.buildNotify();
|
||||
if (this.settings.content.icon) {
|
||||
this.setIcon();
|
||||
}
|
||||
if (this.settings.content.url != "#") {
|
||||
this.styleURL();
|
||||
}
|
||||
this.placement();
|
||||
this.bind();
|
||||
|
||||
this.notify = {
|
||||
$ele: this.$ele,
|
||||
update: function(command, update) {
|
||||
var commands = {};
|
||||
if (typeof command == "string") {
|
||||
commands[command] = update;
|
||||
}else{
|
||||
commands = command;
|
||||
}
|
||||
for (var command in commands) {
|
||||
switch (command) {
|
||||
case "type":
|
||||
this.$ele.removeClass('alert-' + self.settings.type);
|
||||
this.$ele.find('[data-notify="progressbar"] > .progress-bar').removeClass('progress-bar-' + self.settings.type);
|
||||
self.settings.type = commands[command];
|
||||
this.$ele.addClass('alert-' + commands[command]).find('[data-notify="progressbar"] > .progress-bar').addClass('progress-bar-' + commands[command]);
|
||||
break;
|
||||
case "icon":
|
||||
var $icon = this.$ele.find('[data-notify="icon"]');
|
||||
if (self.settings.icon_type.toLowerCase() == 'class') {
|
||||
$icon.removeClass(self.settings.content.icon).addClass(commands[command]);
|
||||
}else{
|
||||
if (!$icon.is('img')) {
|
||||
$icon.find('img');
|
||||
}
|
||||
$icon.attr('src', commands[command]);
|
||||
}
|
||||
break;
|
||||
case "progress":
|
||||
var newDelay = self.settings.delay - (self.settings.delay * (commands[command] / 100));
|
||||
this.$ele.data('notify-delay', newDelay);
|
||||
this.$ele.find('[data-notify="progressbar"] > div').attr('aria-valuenow', commands[command]).css('width', commands[command] + '%');
|
||||
break;
|
||||
case "url":
|
||||
this.$ele.find('[data-notify="url"]').attr('href', commands[command]);
|
||||
break;
|
||||
case "target":
|
||||
this.$ele.find('[data-notify="url"]').attr('target', commands[command]);
|
||||
break;
|
||||
default:
|
||||
this.$ele.find('[data-notify="' + command +'"]').html(commands[command]);
|
||||
};
|
||||
}
|
||||
var posX = this.$ele.outerHeight() + parseInt(self.settings.spacing) + parseInt(self.settings.offset.y);
|
||||
self.reposition(posX);
|
||||
},
|
||||
close: function() {
|
||||
self.close();
|
||||
}
|
||||
};
|
||||
},
|
||||
buildNotify: function () {
|
||||
var content = this.settings.content;
|
||||
this.$ele = $(String.format(this.settings.template, this.settings.type, content.title, content.message, content.url, content.target));
|
||||
this.$ele.attr('data-notify-position', this.settings.placement.from + '-' + this.settings.placement.align);
|
||||
if (!this.settings.allow_dismiss) {
|
||||
this.$ele.find('[data-notify="dismiss"]').css('display', 'none');
|
||||
}
|
||||
if ((this.settings.delay <= 0 && !this.settings.showProgressbar) || !this.settings.showProgressbar) {
|
||||
this.$ele.find('[data-notify="progressbar"]').remove();
|
||||
}
|
||||
},
|
||||
setIcon: function() {
|
||||
if (this.settings.icon_type.toLowerCase() == 'class') {
|
||||
this.$ele.find('[data-notify="icon"]').addClass(this.settings.content.icon);
|
||||
}else{
|
||||
if (this.$ele.find('[data-notify="icon"]').is('img')) {
|
||||
this.$ele.find('[data-notify="icon"]').attr('src', this.settings.content.icon);
|
||||
}else{
|
||||
this.$ele.find('[data-notify="icon"]').append('<img src="'+this.settings.content.icon+'" alt="Notify Icon" />');
|
||||
}
|
||||
}
|
||||
},
|
||||
styleURL: function() {
|
||||
this.$ele.find('[data-notify="url"]').css({
|
||||
backgroundImage: 'url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)',
|
||||
height: '100%',
|
||||
left: '0px',
|
||||
position: 'absolute',
|
||||
top: '0px',
|
||||
width: '100%',
|
||||
zIndex: this.settings.z_index + 1
|
||||
});
|
||||
this.$ele.find('[data-notify="dismiss"]').css({
|
||||
position: 'absolute',
|
||||
right: '10px',
|
||||
top: '5px',
|
||||
zIndex: this.settings.z_index + 2
|
||||
});
|
||||
},
|
||||
placement: function() {
|
||||
var self = this,
|
||||
offsetAmt = this.settings.offset.y,
|
||||
css = {
|
||||
display: 'inline-block',
|
||||
margin: '0px auto',
|
||||
position: this.settings.position ? this.settings.position : (this.settings.element === 'body' ? 'fixed' : 'absolute'),
|
||||
transition: 'all .5s ease-in-out',
|
||||
zIndex: this.settings.z_index
|
||||
},
|
||||
hasAnimation = false,
|
||||
settings = this.settings;
|
||||
|
||||
$('[data-notify-position="' + this.settings.placement.from + '-' + this.settings.placement.align + '"]:not([data-closing="true"])').each(function() {
|
||||
return offsetAmt = Math.max(offsetAmt, parseInt($(this).css(settings.placement.from)) + parseInt($(this).outerHeight()) + parseInt(settings.spacing));
|
||||
});
|
||||
if (this.settings.newest_on_top == true) {
|
||||
offsetAmt = this.settings.offset.y;
|
||||
}
|
||||
css[this.settings.placement.from] = offsetAmt+'px';
|
||||
|
||||
switch (this.settings.placement.align) {
|
||||
case "left":
|
||||
case "right":
|
||||
css[this.settings.placement.align] = this.settings.offset.x+'px';
|
||||
break;
|
||||
case "center":
|
||||
css.left = 0;
|
||||
css.right = 0;
|
||||
break;
|
||||
}
|
||||
this.$ele.css(css).addClass(this.settings.animate.enter);
|
||||
$.each(Array('webkit', 'moz', 'o', 'ms', ''), function(index, prefix) {
|
||||
self.$ele[0].style[prefix+'AnimationIterationCount'] = 1;
|
||||
});
|
||||
|
||||
$(this.settings.element).append(this.$ele);
|
||||
|
||||
if (this.settings.newest_on_top == true) {
|
||||
offsetAmt = (parseInt(offsetAmt)+parseInt(this.settings.spacing)) + this.$ele.outerHeight();
|
||||
this.reposition(offsetAmt);
|
||||
}
|
||||
|
||||
if ($.isFunction(self.settings.onShow)) {
|
||||
self.settings.onShow.call(this.$ele);
|
||||
}
|
||||
|
||||
this.$ele.one(this.animations.start, function(event) {
|
||||
hasAnimation = true;
|
||||
}).one(this.animations.end, function(event) {
|
||||
if ($.isFunction(self.settings.onShown)) {
|
||||
self.settings.onShown.call(this);
|
||||
}
|
||||
});
|
||||
|
||||
setTimeout(function() {
|
||||
if (!hasAnimation) {
|
||||
if ($.isFunction(self.settings.onShown)) {
|
||||
self.settings.onShown.call(this);
|
||||
}
|
||||
}
|
||||
}, 600);
|
||||
},
|
||||
bind: function() {
|
||||
var self = this;
|
||||
|
||||
this.$ele.find('[data-notify="dismiss"]').on('click', function() {
|
||||
self.close();
|
||||
})
|
||||
|
||||
this.$ele.mouseover(function(e) {
|
||||
$(this).data('data-hover', "true");
|
||||
}).mouseout(function(e) {
|
||||
$(this).data('data-hover', "false");
|
||||
});
|
||||
this.$ele.data('data-hover', "false");
|
||||
|
||||
if (this.settings.delay > 0) {
|
||||
self.$ele.data('notify-delay', self.settings.delay);
|
||||
var timer = setInterval(function() {
|
||||
var delay = parseInt(self.$ele.data('notify-delay')) - self.settings.timer;
|
||||
if ((self.$ele.data('data-hover') === 'false' && self.settings.mouse_over == "pause") || self.settings.mouse_over != "pause") {
|
||||
var percent = ((self.settings.delay - delay) / self.settings.delay) * 100;
|
||||
self.$ele.data('notify-delay', delay);
|
||||
self.$ele.find('[data-notify="progressbar"] > div').attr('aria-valuenow', percent).css('width', percent + '%');
|
||||
}
|
||||
if (delay <= -(self.settings.timer)) {
|
||||
clearInterval(timer);
|
||||
self.close();
|
||||
}
|
||||
}, self.settings.timer);
|
||||
}
|
||||
},
|
||||
close: function() {
|
||||
var self = this,
|
||||
$successors = null,
|
||||
posX = parseInt(this.$ele.css(this.settings.placement.from)),
|
||||
hasAnimation = false;
|
||||
|
||||
this.$ele.data('closing', 'true').addClass(this.settings.animate.exit);
|
||||
self.reposition(posX);
|
||||
|
||||
if ($.isFunction(self.settings.onClose)) {
|
||||
self.settings.onClose.call(this.$ele);
|
||||
}
|
||||
|
||||
this.$ele.one(this.animations.start, function(event) {
|
||||
hasAnimation = true;
|
||||
}).one(this.animations.end, function(event) {
|
||||
$(this).remove();
|
||||
if ($.isFunction(self.settings.onClosed)) {
|
||||
self.settings.onClosed.call(this);
|
||||
}
|
||||
});
|
||||
|
||||
setTimeout(function() {
|
||||
if (!hasAnimation) {
|
||||
self.$ele.remove();
|
||||
if (self.settings.onClosed) {
|
||||
self.settings.onClosed(self.$ele);
|
||||
}
|
||||
}
|
||||
}, 600);
|
||||
},
|
||||
reposition: function(posX) {
|
||||
var self = this,
|
||||
notifies = '[data-notify-position="' + this.settings.placement.from + '-' + this.settings.placement.align + '"]:not([data-closing="true"])',
|
||||
$elements = this.$ele.nextAll(notifies);
|
||||
if (this.settings.newest_on_top == true) {
|
||||
$elements = this.$ele.prevAll(notifies);
|
||||
}
|
||||
$elements.each(function() {
|
||||
$(this).css(self.settings.placement.from, posX);
|
||||
posX = (parseInt(posX)+parseInt(self.settings.spacing)) + $(this).outerHeight();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$.notify = function ( content, options ) {
|
||||
var plugin = new Notify( this, content, options );
|
||||
return plugin.notify;
|
||||
};
|
||||
$.notifyDefaults = function( options ) {
|
||||
defaults = $.extend(true, {}, defaults, options);
|
||||
return defaults;
|
||||
};
|
||||
$.notifyClose = function( command ) {
|
||||
if (typeof command === "undefined" || command == "all") {
|
||||
$('[data-notify]').find('[data-notify="dismiss"]').trigger('click');
|
||||
}else{
|
||||
$('[data-notify-position="'+command+'"]').find('[data-notify="dismiss"]').trigger('click');
|
||||
}
|
||||
};
|
||||
|
||||
}));
|
File diff suppressed because one or more lines are too long
@ -0,0 +1 @@
|
||||
!function(a){a.fn.datepicker.dates["zh-CN"]={days:["星期日","星期一","星期二","星期三","星期四","星期五","星期六"],daysShort:["周日","周一","周二","周三","周四","周五","周六"],daysMin:["日","一","二","三","四","五","六"],months:["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月"],monthsShort:["1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月"],today:"今天",monthsTitle:"选择月份",clear:"清除",format:"yyyy-mm-dd",titleFormat:"yyyy年mm月",weekStart:1}}(jQuery);
|
@ -0,0 +1,33 @@
|
||||
(function( factory ) {
|
||||
if ( typeof define === "function" && define.amd ) {
|
||||
define( ["jquery", "../jquery.validate"], factory );
|
||||
} else {
|
||||
factory( jQuery );
|
||||
}
|
||||
}(function( $ ) {
|
||||
|
||||
/*
|
||||
* Translated default messages for the jQuery validation plugin.
|
||||
* Locale: ZH (Chinese, 中文 (Zhōngwén), 汉语, 漢語)
|
||||
*/
|
||||
$.extend($.validator.messages, {
|
||||
required: "这是必填字段",
|
||||
remote: "请修正此字段",
|
||||
email: "请输入有效的电子邮件地址",
|
||||
url: "请输入有效的网址",
|
||||
date: "请输入有效的日期",
|
||||
dateISO: "请输入有效的日期 (YYYY-MM-DD)",
|
||||
number: "请输入有效的数字",
|
||||
digits: "只能输入数字",
|
||||
creditcard: "请输入有效的信用卡号码",
|
||||
equalTo: "你的输入不相同",
|
||||
extension: "请输入有效的后缀",
|
||||
maxlength: $.validator.format("最多可以输入 {0} 个字符"),
|
||||
minlength: $.validator.format("最少要输入 {0} 个字符"),
|
||||
rangelength: $.validator.format("请输入长度在 {0} 到 {1} 之间的字符串"),
|
||||
range: $.validator.format("请输入范围在 {0} 到 {1} 之间的数值"),
|
||||
max: $.validator.format("请输入不大于 {0} 的数值"),
|
||||
min: $.validator.format("请输入不小于 {0} 的数值")
|
||||
});
|
||||
|
||||
}));
|
@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.8 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/zh-CN",[],function(){return{errorLoading:function(){return"无法载入结果。"},inputTooLong:function(n){return"请删除"+(n.input.length-n.maximum)+"个字符"},inputTooShort:function(n){return"请再输入至少"+(n.minimum-n.input.length)+"个字符"},loadingMore:function(){return"载入更多结果…"},maximumSelected:function(n){return"最多只能选择"+n.maximum+"个项目"},noResults:function(){return"未找到结果"},searching:function(){return"搜索中…"},removeAllItems:function(){return"删除所有项目"}}}),n.define,n.require}();
|
@ -0,0 +1,2 @@
|
||||
/*! jquery.cookie v1.4.1 | MIT */
|
||||
!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof exports?a(require("jquery")):a(jQuery)}(function(a){function b(a){return h.raw?a:encodeURIComponent(a)}function c(a){return h.raw?a:decodeURIComponent(a)}function d(a){return b(h.json?JSON.stringify(a):String(a))}function e(a){0===a.indexOf('"')&&(a=a.slice(1,-1).replace(/\\"/g,'"').replace(/\\\\/g,"\\"));try{return a=decodeURIComponent(a.replace(g," ")),h.json?JSON.parse(a):a}catch(b){}}function f(b,c){var d=h.raw?b:e(b);return a.isFunction(c)?c(d):d}var g=/\+/g,h=a.cookie=function(e,g,i){if(void 0!==g&&!a.isFunction(g)){if(i=a.extend({},h.defaults,i),"number"==typeof i.expires){var j=i.expires,k=i.expires=new Date;k.setTime(+k+864e5*j)}return document.cookie=[b(e),"=",d(g),i.expires?"; expires="+i.expires.toUTCString():"",i.path?"; path="+i.path:"",i.domain?"; domain="+i.domain:"",i.secure?"; secure":""].join("")}for(var l=e?void 0:{},m=document.cookie?document.cookie.split("; "):[],n=0,o=m.length;o>n;n++){var p=m[n].split("="),q=c(p.shift()),r=p.join("=");if(e&&e===q){l=f(r,g);break}e||void 0===(r=f(r))||(l[q]=r)}return l};h.defaults={},a.removeCookie=function(b,c){return void 0===a.cookie(b)?!1:(a.cookie(b,"",a.extend({},c,{expires:-1})),!a.cookie(b))}});
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@ -0,0 +1,46 @@
|
||||
@import "bootstrap";
|
||||
@import "font-awesome-sprockets";
|
||||
@import "font-awesome";
|
||||
@import "select2.min";
|
||||
@import "select2-bootstrap4.min";
|
||||
@import "bootstrap-datepicker";
|
||||
@import "bootstrap-datepicker.standalone";
|
||||
|
||||
@import "admins/*";
|
||||
|
||||
body {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
max-width: 100vw;
|
||||
max-height: 100vh;
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
font-size: 14px;
|
||||
background: #efefef;
|
||||
}
|
||||
|
||||
a {
|
||||
&:hover {
|
||||
text-decoration: unset;
|
||||
}
|
||||
}
|
||||
|
||||
input.danger {
|
||||
border-color: #dc3545!important;
|
||||
}
|
||||
|
||||
label.error {
|
||||
color: #dc3545!important;
|
||||
}
|
||||
|
||||
.simple_form {
|
||||
.form-group {
|
||||
.collection_radio_buttons {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.form-check-inline {
|
||||
height: calc(1.5em + 0.75rem + 2px)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,104 @@
|
||||
.admin-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;
|
||||
}
|
||||
}
|
||||
|
||||
/* 分页 */
|
||||
.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,5 @@
|
||||
.admins-daily-school-statistics-index-page {
|
||||
.daily-school-statistic-list-container {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
.admins-school-statistics-index-page {
|
||||
.school-statistic-list-form {
|
||||
.time-select {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.type-box {
|
||||
.btn { margin: 0 5px; }
|
||||
}
|
||||
|
||||
.search-input {
|
||||
width: 220px;
|
||||
}
|
||||
|
||||
.contrast-date-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
.school-statistic-list-container {
|
||||
.contrast-column-select {
|
||||
position: absolute;
|
||||
right: 30px;
|
||||
top: 15px;
|
||||
width: 130px;
|
||||
}
|
||||
|
||||
.relative {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.right-border::after {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 0;
|
||||
content: '';
|
||||
width: 0;
|
||||
height: 20px;
|
||||
border-right: 1px solid #000;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,215 @@
|
||||
#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 {
|
||||
padding-left: 5px;
|
||||
overflow: hidden;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#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%);
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
.admins-users-index-page {
|
||||
.user-list-form {
|
||||
}
|
||||
|
||||
.users-list-container {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
.admins-users-edit-page, .admins-users-update-page {
|
||||
.user-edit-container {
|
||||
.user-info {
|
||||
&-content {
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
height: 80px;
|
||||
}
|
||||
|
||||
&-name {
|
||||
flex: 2;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
&-auth {
|
||||
flex: 1;
|
||||
|
||||
i.fa {
|
||||
margin-right: 10px;
|
||||
font-size: 16px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
@import "bootstrap";
|
@ -0,0 +1,477 @@
|
||||
/*!
|
||||
* Datepicker for Bootstrap v1.9.0 (https://github.com/uxsolutions/bootstrap-datepicker)
|
||||
*
|
||||
* Licensed under the Apache License v2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
||||
*/
|
||||
|
||||
.datepicker {
|
||||
padding: 4px;
|
||||
-webkit-border-radius: 4px;
|
||||
-moz-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
direction: ltr;
|
||||
}
|
||||
.datepicker-inline {
|
||||
width: 220px;
|
||||
}
|
||||
.datepicker-rtl {
|
||||
direction: rtl;
|
||||
}
|
||||
.datepicker-rtl.dropdown-menu {
|
||||
left: auto;
|
||||
}
|
||||
.datepicker-rtl table tr td span {
|
||||
float: right;
|
||||
}
|
||||
.datepicker-dropdown {
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
.datepicker-dropdown:before {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
border-left: 7px solid transparent;
|
||||
border-right: 7px solid transparent;
|
||||
border-bottom: 7px solid #999;
|
||||
border-top: 0;
|
||||
border-bottom-color: rgba(0, 0, 0, 0.2);
|
||||
position: absolute;
|
||||
}
|
||||
.datepicker-dropdown:after {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
border-left: 6px solid transparent;
|
||||
border-right: 6px solid transparent;
|
||||
border-bottom: 6px solid #fff;
|
||||
border-top: 0;
|
||||
position: absolute;
|
||||
}
|
||||
.datepicker-dropdown.datepicker-orient-left:before {
|
||||
left: 6px;
|
||||
}
|
||||
.datepicker-dropdown.datepicker-orient-left:after {
|
||||
left: 7px;
|
||||
}
|
||||
.datepicker-dropdown.datepicker-orient-right:before {
|
||||
right: 6px;
|
||||
}
|
||||
.datepicker-dropdown.datepicker-orient-right:after {
|
||||
right: 7px;
|
||||
}
|
||||
.datepicker-dropdown.datepicker-orient-bottom:before {
|
||||
top: -7px;
|
||||
}
|
||||
.datepicker-dropdown.datepicker-orient-bottom:after {
|
||||
top: -6px;
|
||||
}
|
||||
.datepicker-dropdown.datepicker-orient-top:before {
|
||||
bottom: -7px;
|
||||
border-bottom: 0;
|
||||
border-top: 7px solid #999;
|
||||
}
|
||||
.datepicker-dropdown.datepicker-orient-top:after {
|
||||
bottom: -6px;
|
||||
border-bottom: 0;
|
||||
border-top: 6px solid #fff;
|
||||
}
|
||||
.datepicker table {
|
||||
margin: 0;
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
.datepicker td,
|
||||
.datepicker th {
|
||||
text-align: center;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
-webkit-border-radius: 4px;
|
||||
-moz-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
border: none;
|
||||
}
|
||||
.table-striped .datepicker table tr td,
|
||||
.table-striped .datepicker table tr th {
|
||||
background-color: transparent;
|
||||
}
|
||||
.datepicker table tr td.day:hover,
|
||||
.datepicker table tr td.day.focused {
|
||||
background: #eee;
|
||||
cursor: pointer;
|
||||
}
|
||||
.datepicker table tr td.old,
|
||||
.datepicker table tr td.new {
|
||||
color: #999;
|
||||
}
|
||||
.datepicker table tr td.disabled,
|
||||
.datepicker table tr td.disabled:hover {
|
||||
background: none;
|
||||
color: #999;
|
||||
cursor: default;
|
||||
}
|
||||
.datepicker table tr td.highlighted {
|
||||
background: #d9edf7;
|
||||
border-radius: 0;
|
||||
}
|
||||
.datepicker table tr td.today,
|
||||
.datepicker table tr td.today:hover,
|
||||
.datepicker table tr td.today.disabled,
|
||||
.datepicker table tr td.today.disabled:hover {
|
||||
background-color: #fde19a;
|
||||
background-image: -moz-linear-gradient(to bottom, #fdd49a, #fdf59a);
|
||||
background-image: -ms-linear-gradient(to bottom, #fdd49a, #fdf59a);
|
||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fdd49a), to(#fdf59a));
|
||||
background-image: -webkit-linear-gradient(to bottom, #fdd49a, #fdf59a);
|
||||
background-image: -o-linear-gradient(to bottom, #fdd49a, #fdf59a);
|
||||
background-image: linear-gradient(to bottom, #fdd49a, #fdf59a);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fdd49a', endColorstr='#fdf59a', GradientType=0);
|
||||
border-color: #fdf59a #fdf59a #fbed50;
|
||||
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
|
||||
color: #000;
|
||||
}
|
||||
.datepicker table tr td.today:hover,
|
||||
.datepicker table tr td.today:hover:hover,
|
||||
.datepicker table tr td.today.disabled:hover,
|
||||
.datepicker table tr td.today.disabled:hover:hover,
|
||||
.datepicker table tr td.today:active,
|
||||
.datepicker table tr td.today:hover:active,
|
||||
.datepicker table tr td.today.disabled:active,
|
||||
.datepicker table tr td.today.disabled:hover:active,
|
||||
.datepicker table tr td.today.active,
|
||||
.datepicker table tr td.today:hover.active,
|
||||
.datepicker table tr td.today.disabled.active,
|
||||
.datepicker table tr td.today.disabled:hover.active,
|
||||
.datepicker table tr td.today.disabled,
|
||||
.datepicker table tr td.today:hover.disabled,
|
||||
.datepicker table tr td.today.disabled.disabled,
|
||||
.datepicker table tr td.today.disabled:hover.disabled,
|
||||
.datepicker table tr td.today[disabled],
|
||||
.datepicker table tr td.today:hover[disabled],
|
||||
.datepicker table tr td.today.disabled[disabled],
|
||||
.datepicker table tr td.today.disabled:hover[disabled] {
|
||||
background-color: #fdf59a;
|
||||
}
|
||||
.datepicker table tr td.today:active,
|
||||
.datepicker table tr td.today:hover:active,
|
||||
.datepicker table tr td.today.disabled:active,
|
||||
.datepicker table tr td.today.disabled:hover:active,
|
||||
.datepicker table tr td.today.active,
|
||||
.datepicker table tr td.today:hover.active,
|
||||
.datepicker table tr td.today.disabled.active,
|
||||
.datepicker table tr td.today.disabled:hover.active {
|
||||
background-color: #fbf069 \9;
|
||||
}
|
||||
.datepicker table tr td.today:hover:hover {
|
||||
color: #000;
|
||||
}
|
||||
.datepicker table tr td.today.active:hover {
|
||||
color: #fff;
|
||||
}
|
||||
.datepicker table tr td.range,
|
||||
.datepicker table tr td.range:hover,
|
||||
.datepicker table tr td.range.disabled,
|
||||
.datepicker table tr td.range.disabled:hover {
|
||||
background: #eee;
|
||||
-webkit-border-radius: 0;
|
||||
-moz-border-radius: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
.datepicker table tr td.range.today,
|
||||
.datepicker table tr td.range.today:hover,
|
||||
.datepicker table tr td.range.today.disabled,
|
||||
.datepicker table tr td.range.today.disabled:hover {
|
||||
background-color: #f3d17a;
|
||||
background-image: -moz-linear-gradient(to bottom, #f3c17a, #f3e97a);
|
||||
background-image: -ms-linear-gradient(to bottom, #f3c17a, #f3e97a);
|
||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f3c17a), to(#f3e97a));
|
||||
background-image: -webkit-linear-gradient(to bottom, #f3c17a, #f3e97a);
|
||||
background-image: -o-linear-gradient(to bottom, #f3c17a, #f3e97a);
|
||||
background-image: linear-gradient(to bottom, #f3c17a, #f3e97a);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f3c17a', endColorstr='#f3e97a', GradientType=0);
|
||||
border-color: #f3e97a #f3e97a #edde34;
|
||||
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
|
||||
-webkit-border-radius: 0;
|
||||
-moz-border-radius: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
.datepicker table tr td.range.today:hover,
|
||||
.datepicker table tr td.range.today:hover:hover,
|
||||
.datepicker table tr td.range.today.disabled:hover,
|
||||
.datepicker table tr td.range.today.disabled:hover:hover,
|
||||
.datepicker table tr td.range.today:active,
|
||||
.datepicker table tr td.range.today:hover:active,
|
||||
.datepicker table tr td.range.today.disabled:active,
|
||||
.datepicker table tr td.range.today.disabled:hover:active,
|
||||
.datepicker table tr td.range.today.active,
|
||||
.datepicker table tr td.range.today:hover.active,
|
||||
.datepicker table tr td.range.today.disabled.active,
|
||||
.datepicker table tr td.range.today.disabled:hover.active,
|
||||
.datepicker table tr td.range.today.disabled,
|
||||
.datepicker table tr td.range.today:hover.disabled,
|
||||
.datepicker table tr td.range.today.disabled.disabled,
|
||||
.datepicker table tr td.range.today.disabled:hover.disabled,
|
||||
.datepicker table tr td.range.today[disabled],
|
||||
.datepicker table tr td.range.today:hover[disabled],
|
||||
.datepicker table tr td.range.today.disabled[disabled],
|
||||
.datepicker table tr td.range.today.disabled:hover[disabled] {
|
||||
background-color: #f3e97a;
|
||||
}
|
||||
.datepicker table tr td.range.today:active,
|
||||
.datepicker table tr td.range.today:hover:active,
|
||||
.datepicker table tr td.range.today.disabled:active,
|
||||
.datepicker table tr td.range.today.disabled:hover:active,
|
||||
.datepicker table tr td.range.today.active,
|
||||
.datepicker table tr td.range.today:hover.active,
|
||||
.datepicker table tr td.range.today.disabled.active,
|
||||
.datepicker table tr td.range.today.disabled:hover.active {
|
||||
background-color: #efe24b \9;
|
||||
}
|
||||
.datepicker table tr td.selected,
|
||||
.datepicker table tr td.selected:hover,
|
||||
.datepicker table tr td.selected.disabled,
|
||||
.datepicker table tr td.selected.disabled:hover {
|
||||
background-color: #9e9e9e;
|
||||
background-image: -moz-linear-gradient(to bottom, #b3b3b3, #808080);
|
||||
background-image: -ms-linear-gradient(to bottom, #b3b3b3, #808080);
|
||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#b3b3b3), to(#808080));
|
||||
background-image: -webkit-linear-gradient(to bottom, #b3b3b3, #808080);
|
||||
background-image: -o-linear-gradient(to bottom, #b3b3b3, #808080);
|
||||
background-image: linear-gradient(to bottom, #b3b3b3, #808080);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#b3b3b3', endColorstr='#808080', GradientType=0);
|
||||
border-color: #808080 #808080 #595959;
|
||||
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
|
||||
color: #fff;
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
.datepicker table tr td.selected:hover,
|
||||
.datepicker table tr td.selected:hover:hover,
|
||||
.datepicker table tr td.selected.disabled:hover,
|
||||
.datepicker table tr td.selected.disabled:hover:hover,
|
||||
.datepicker table tr td.selected:active,
|
||||
.datepicker table tr td.selected:hover:active,
|
||||
.datepicker table tr td.selected.disabled:active,
|
||||
.datepicker table tr td.selected.disabled:hover:active,
|
||||
.datepicker table tr td.selected.active,
|
||||
.datepicker table tr td.selected:hover.active,
|
||||
.datepicker table tr td.selected.disabled.active,
|
||||
.datepicker table tr td.selected.disabled:hover.active,
|
||||
.datepicker table tr td.selected.disabled,
|
||||
.datepicker table tr td.selected:hover.disabled,
|
||||
.datepicker table tr td.selected.disabled.disabled,
|
||||
.datepicker table tr td.selected.disabled:hover.disabled,
|
||||
.datepicker table tr td.selected[disabled],
|
||||
.datepicker table tr td.selected:hover[disabled],
|
||||
.datepicker table tr td.selected.disabled[disabled],
|
||||
.datepicker table tr td.selected.disabled:hover[disabled] {
|
||||
background-color: #808080;
|
||||
}
|
||||
.datepicker table tr td.selected:active,
|
||||
.datepicker table tr td.selected:hover:active,
|
||||
.datepicker table tr td.selected.disabled:active,
|
||||
.datepicker table tr td.selected.disabled:hover:active,
|
||||
.datepicker table tr td.selected.active,
|
||||
.datepicker table tr td.selected:hover.active,
|
||||
.datepicker table tr td.selected.disabled.active,
|
||||
.datepicker table tr td.selected.disabled:hover.active {
|
||||
background-color: #666666 \9;
|
||||
}
|
||||
.datepicker table tr td.active,
|
||||
.datepicker table tr td.active:hover,
|
||||
.datepicker table tr td.active.disabled,
|
||||
.datepicker table tr td.active.disabled:hover {
|
||||
background-color: #006dcc;
|
||||
background-image: -moz-linear-gradient(to bottom, #08c, #0044cc);
|
||||
background-image: -ms-linear-gradient(to bottom, #08c, #0044cc);
|
||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#08c), to(#0044cc));
|
||||
background-image: -webkit-linear-gradient(to bottom, #08c, #0044cc);
|
||||
background-image: -o-linear-gradient(to bottom, #08c, #0044cc);
|
||||
background-image: linear-gradient(to bottom, #08c, #0044cc);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#08c', endColorstr='#0044cc', GradientType=0);
|
||||
border-color: #0044cc #0044cc #002a80;
|
||||
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
|
||||
color: #fff;
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
.datepicker table tr td.active:hover,
|
||||
.datepicker table tr td.active:hover:hover,
|
||||
.datepicker table tr td.active.disabled:hover,
|
||||
.datepicker table tr td.active.disabled:hover:hover,
|
||||
.datepicker table tr td.active:active,
|
||||
.datepicker table tr td.active:hover:active,
|
||||
.datepicker table tr td.active.disabled:active,
|
||||
.datepicker table tr td.active.disabled:hover:active,
|
||||
.datepicker table tr td.active.active,
|
||||
.datepicker table tr td.active:hover.active,
|
||||
.datepicker table tr td.active.disabled.active,
|
||||
.datepicker table tr td.active.disabled:hover.active,
|
||||
.datepicker table tr td.active.disabled,
|
||||
.datepicker table tr td.active:hover.disabled,
|
||||
.datepicker table tr td.active.disabled.disabled,
|
||||
.datepicker table tr td.active.disabled:hover.disabled,
|
||||
.datepicker table tr td.active[disabled],
|
||||
.datepicker table tr td.active:hover[disabled],
|
||||
.datepicker table tr td.active.disabled[disabled],
|
||||
.datepicker table tr td.active.disabled:hover[disabled] {
|
||||
background-color: #0044cc;
|
||||
}
|
||||
.datepicker table tr td.active:active,
|
||||
.datepicker table tr td.active:hover:active,
|
||||
.datepicker table tr td.active.disabled:active,
|
||||
.datepicker table tr td.active.disabled:hover:active,
|
||||
.datepicker table tr td.active.active,
|
||||
.datepicker table tr td.active:hover.active,
|
||||
.datepicker table tr td.active.disabled.active,
|
||||
.datepicker table tr td.active.disabled:hover.active {
|
||||
background-color: #003399 \9;
|
||||
}
|
||||
.datepicker table tr td span {
|
||||
display: block;
|
||||
width: 23%;
|
||||
height: 54px;
|
||||
line-height: 54px;
|
||||
float: left;
|
||||
margin: 1%;
|
||||
cursor: pointer;
|
||||
-webkit-border-radius: 4px;
|
||||
-moz-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.datepicker table tr td span:hover,
|
||||
.datepicker table tr td span.focused {
|
||||
background: #eee;
|
||||
}
|
||||
.datepicker table tr td span.disabled,
|
||||
.datepicker table tr td span.disabled:hover {
|
||||
background: none;
|
||||
color: #999;
|
||||
cursor: default;
|
||||
}
|
||||
.datepicker table tr td span.active,
|
||||
.datepicker table tr td span.active:hover,
|
||||
.datepicker table tr td span.active.disabled,
|
||||
.datepicker table tr td span.active.disabled:hover {
|
||||
background-color: #006dcc;
|
||||
background-image: -moz-linear-gradient(to bottom, #08c, #0044cc);
|
||||
background-image: -ms-linear-gradient(to bottom, #08c, #0044cc);
|
||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#08c), to(#0044cc));
|
||||
background-image: -webkit-linear-gradient(to bottom, #08c, #0044cc);
|
||||
background-image: -o-linear-gradient(to bottom, #08c, #0044cc);
|
||||
background-image: linear-gradient(to bottom, #08c, #0044cc);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#08c', endColorstr='#0044cc', GradientType=0);
|
||||
border-color: #0044cc #0044cc #002a80;
|
||||
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
|
||||
color: #fff;
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
.datepicker table tr td span.active:hover,
|
||||
.datepicker table tr td span.active:hover:hover,
|
||||
.datepicker table tr td span.active.disabled:hover,
|
||||
.datepicker table tr td span.active.disabled:hover:hover,
|
||||
.datepicker table tr td span.active:active,
|
||||
.datepicker table tr td span.active:hover:active,
|
||||
.datepicker table tr td span.active.disabled:active,
|
||||
.datepicker table tr td span.active.disabled:hover:active,
|
||||
.datepicker table tr td span.active.active,
|
||||
.datepicker table tr td span.active:hover.active,
|
||||
.datepicker table tr td span.active.disabled.active,
|
||||
.datepicker table tr td span.active.disabled:hover.active,
|
||||
.datepicker table tr td span.active.disabled,
|
||||
.datepicker table tr td span.active:hover.disabled,
|
||||
.datepicker table tr td span.active.disabled.disabled,
|
||||
.datepicker table tr td span.active.disabled:hover.disabled,
|
||||
.datepicker table tr td span.active[disabled],
|
||||
.datepicker table tr td span.active:hover[disabled],
|
||||
.datepicker table tr td span.active.disabled[disabled],
|
||||
.datepicker table tr td span.active.disabled:hover[disabled] {
|
||||
background-color: #0044cc;
|
||||
}
|
||||
.datepicker table tr td span.active:active,
|
||||
.datepicker table tr td span.active:hover:active,
|
||||
.datepicker table tr td span.active.disabled:active,
|
||||
.datepicker table tr td span.active.disabled:hover:active,
|
||||
.datepicker table tr td span.active.active,
|
||||
.datepicker table tr td span.active:hover.active,
|
||||
.datepicker table tr td span.active.disabled.active,
|
||||
.datepicker table tr td span.active.disabled:hover.active {
|
||||
background-color: #003399 \9;
|
||||
}
|
||||
.datepicker table tr td span.old,
|
||||
.datepicker table tr td span.new {
|
||||
color: #999;
|
||||
}
|
||||
.datepicker .datepicker-switch {
|
||||
width: 145px;
|
||||
}
|
||||
.datepicker .datepicker-switch,
|
||||
.datepicker .prev,
|
||||
.datepicker .next,
|
||||
.datepicker tfoot tr th {
|
||||
cursor: pointer;
|
||||
}
|
||||
.datepicker .datepicker-switch:hover,
|
||||
.datepicker .prev:hover,
|
||||
.datepicker .next:hover,
|
||||
.datepicker tfoot tr th:hover {
|
||||
background: #eee;
|
||||
}
|
||||
.datepicker .prev.disabled,
|
||||
.datepicker .next.disabled {
|
||||
visibility: hidden;
|
||||
}
|
||||
.datepicker .cw {
|
||||
font-size: 10px;
|
||||
width: 12px;
|
||||
padding: 0 2px 0 5px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.input-append.date .add-on,
|
||||
.input-prepend.date .add-on {
|
||||
cursor: pointer;
|
||||
}
|
||||
.input-append.date .add-on i,
|
||||
.input-prepend.date .add-on i {
|
||||
margin-top: 3px;
|
||||
}
|
||||
.input-daterange input {
|
||||
text-align: center;
|
||||
}
|
||||
.input-daterange input:first-child {
|
||||
-webkit-border-radius: 3px 0 0 3px;
|
||||
-moz-border-radius: 3px 0 0 3px;
|
||||
border-radius: 3px 0 0 3px;
|
||||
}
|
||||
.input-daterange input:last-child {
|
||||
-webkit-border-radius: 0 3px 3px 0;
|
||||
-moz-border-radius: 0 3px 3px 0;
|
||||
border-radius: 0 3px 3px 0;
|
||||
}
|
||||
.input-daterange .add-on {
|
||||
display: inline-block;
|
||||
width: auto;
|
||||
min-width: 16px;
|
||||
height: 18px;
|
||||
padding: 4px 5px;
|
||||
font-weight: normal;
|
||||
line-height: 18px;
|
||||
text-align: center;
|
||||
text-shadow: 0 1px 0 #fff;
|
||||
vertical-align: middle;
|
||||
background-color: #eee;
|
||||
border: 1px solid #ccc;
|
||||
margin-left: -5px;
|
||||
margin-right: -5px;
|
||||
}
|
||||
/*# sourceMappingURL=bootstrap-datepicker.css.map */
|
@ -0,0 +1,510 @@
|
||||
/*!
|
||||
* Datepicker for Bootstrap v1.9.0 (https://github.com/uxsolutions/bootstrap-datepicker)
|
||||
*
|
||||
* Licensed under the Apache License v2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
||||
*/
|
||||
|
||||
.datepicker {
|
||||
padding: 4px;
|
||||
-webkit-border-radius: 4px;
|
||||
-moz-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
direction: ltr;
|
||||
}
|
||||
.datepicker-inline {
|
||||
width: 220px;
|
||||
}
|
||||
.datepicker-rtl {
|
||||
direction: rtl;
|
||||
}
|
||||
.datepicker-rtl.dropdown-menu {
|
||||
left: auto;
|
||||
}
|
||||
.datepicker-rtl table tr td span {
|
||||
float: right;
|
||||
}
|
||||
.datepicker-dropdown {
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
.datepicker-dropdown:before {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
border-left: 7px solid transparent;
|
||||
border-right: 7px solid transparent;
|
||||
border-bottom: 7px solid #999;
|
||||
border-top: 0;
|
||||
border-bottom-color: rgba(0, 0, 0, 0.2);
|
||||
position: absolute;
|
||||
}
|
||||
.datepicker-dropdown:after {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
border-left: 6px solid transparent;
|
||||
border-right: 6px solid transparent;
|
||||
border-bottom: 6px solid #fff;
|
||||
border-top: 0;
|
||||
position: absolute;
|
||||
}
|
||||
.datepicker-dropdown.datepicker-orient-left:before {
|
||||
left: 6px;
|
||||
}
|
||||
.datepicker-dropdown.datepicker-orient-left:after {
|
||||
left: 7px;
|
||||
}
|
||||
.datepicker-dropdown.datepicker-orient-right:before {
|
||||
right: 6px;
|
||||
}
|
||||
.datepicker-dropdown.datepicker-orient-right:after {
|
||||
right: 7px;
|
||||
}
|
||||
.datepicker-dropdown.datepicker-orient-bottom:before {
|
||||
top: -7px;
|
||||
}
|
||||
.datepicker-dropdown.datepicker-orient-bottom:after {
|
||||
top: -6px;
|
||||
}
|
||||
.datepicker-dropdown.datepicker-orient-top:before {
|
||||
bottom: -7px;
|
||||
border-bottom: 0;
|
||||
border-top: 7px solid #999;
|
||||
}
|
||||
.datepicker-dropdown.datepicker-orient-top:after {
|
||||
bottom: -6px;
|
||||
border-bottom: 0;
|
||||
border-top: 6px solid #fff;
|
||||
}
|
||||
.datepicker table {
|
||||
margin: 0;
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
.datepicker td,
|
||||
.datepicker th {
|
||||
text-align: center;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
-webkit-border-radius: 4px;
|
||||
-moz-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
border: none;
|
||||
}
|
||||
.table-striped .datepicker table tr td,
|
||||
.table-striped .datepicker table tr th {
|
||||
background-color: transparent;
|
||||
}
|
||||
.datepicker table tr td.day:hover,
|
||||
.datepicker table tr td.day.focused {
|
||||
background: #eee;
|
||||
cursor: pointer;
|
||||
}
|
||||
.datepicker table tr td.old,
|
||||
.datepicker table tr td.new {
|
||||
color: #999;
|
||||
}
|
||||
.datepicker table tr td.disabled,
|
||||
.datepicker table tr td.disabled:hover {
|
||||
background: none;
|
||||
color: #999;
|
||||
cursor: default;
|
||||
}
|
||||
.datepicker table tr td.highlighted {
|
||||
background: #d9edf7;
|
||||
border-radius: 0;
|
||||
}
|
||||
.datepicker table tr td.today,
|
||||
.datepicker table tr td.today:hover,
|
||||
.datepicker table tr td.today.disabled,
|
||||
.datepicker table tr td.today.disabled:hover {
|
||||
background-color: #fde19a;
|
||||
background-image: -moz-linear-gradient(to bottom, #fdd49a, #fdf59a);
|
||||
background-image: -ms-linear-gradient(to bottom, #fdd49a, #fdf59a);
|
||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fdd49a), to(#fdf59a));
|
||||
background-image: -webkit-linear-gradient(to bottom, #fdd49a, #fdf59a);
|
||||
background-image: -o-linear-gradient(to bottom, #fdd49a, #fdf59a);
|
||||
background-image: linear-gradient(to bottom, #fdd49a, #fdf59a);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fdd49a', endColorstr='#fdf59a', GradientType=0);
|
||||
border-color: #fdf59a #fdf59a #fbed50;
|
||||
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
|
||||
color: #000;
|
||||
}
|
||||
.datepicker table tr td.today:hover,
|
||||
.datepicker table tr td.today:hover:hover,
|
||||
.datepicker table tr td.today.disabled:hover,
|
||||
.datepicker table tr td.today.disabled:hover:hover,
|
||||
.datepicker table tr td.today:active,
|
||||
.datepicker table tr td.today:hover:active,
|
||||
.datepicker table tr td.today.disabled:active,
|
||||
.datepicker table tr td.today.disabled:hover:active,
|
||||
.datepicker table tr td.today.active,
|
||||
.datepicker table tr td.today:hover.active,
|
||||
.datepicker table tr td.today.disabled.active,
|
||||
.datepicker table tr td.today.disabled:hover.active,
|
||||
.datepicker table tr td.today.disabled,
|
||||
.datepicker table tr td.today:hover.disabled,
|
||||
.datepicker table tr td.today.disabled.disabled,
|
||||
.datepicker table tr td.today.disabled:hover.disabled,
|
||||
.datepicker table tr td.today[disabled],
|
||||
.datepicker table tr td.today:hover[disabled],
|
||||
.datepicker table tr td.today.disabled[disabled],
|
||||
.datepicker table tr td.today.disabled:hover[disabled] {
|
||||
background-color: #fdf59a;
|
||||
}
|
||||
.datepicker table tr td.today:active,
|
||||
.datepicker table tr td.today:hover:active,
|
||||
.datepicker table tr td.today.disabled:active,
|
||||
.datepicker table tr td.today.disabled:hover:active,
|
||||
.datepicker table tr td.today.active,
|
||||
.datepicker table tr td.today:hover.active,
|
||||
.datepicker table tr td.today.disabled.active,
|
||||
.datepicker table tr td.today.disabled:hover.active {
|
||||
background-color: #fbf069 \9;
|
||||
}
|
||||
.datepicker table tr td.today:hover:hover {
|
||||
color: #000;
|
||||
}
|
||||
.datepicker table tr td.today.active:hover {
|
||||
color: #fff;
|
||||
}
|
||||
.datepicker table tr td.range,
|
||||
.datepicker table tr td.range:hover,
|
||||
.datepicker table tr td.range.disabled,
|
||||
.datepicker table tr td.range.disabled:hover {
|
||||
background: #eee;
|
||||
-webkit-border-radius: 0;
|
||||
-moz-border-radius: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
.datepicker table tr td.range.today,
|
||||
.datepicker table tr td.range.today:hover,
|
||||
.datepicker table tr td.range.today.disabled,
|
||||
.datepicker table tr td.range.today.disabled:hover {
|
||||
background-color: #f3d17a;
|
||||
background-image: -moz-linear-gradient(to bottom, #f3c17a, #f3e97a);
|
||||
background-image: -ms-linear-gradient(to bottom, #f3c17a, #f3e97a);
|
||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f3c17a), to(#f3e97a));
|
||||
background-image: -webkit-linear-gradient(to bottom, #f3c17a, #f3e97a);
|
||||
background-image: -o-linear-gradient(to bottom, #f3c17a, #f3e97a);
|
||||
background-image: linear-gradient(to bottom, #f3c17a, #f3e97a);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f3c17a', endColorstr='#f3e97a', GradientType=0);
|
||||
border-color: #f3e97a #f3e97a #edde34;
|
||||
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
|
||||
-webkit-border-radius: 0;
|
||||
-moz-border-radius: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
.datepicker table tr td.range.today:hover,
|
||||
.datepicker table tr td.range.today:hover:hover,
|
||||
.datepicker table tr td.range.today.disabled:hover,
|
||||
.datepicker table tr td.range.today.disabled:hover:hover,
|
||||
.datepicker table tr td.range.today:active,
|
||||
.datepicker table tr td.range.today:hover:active,
|
||||
.datepicker table tr td.range.today.disabled:active,
|
||||
.datepicker table tr td.range.today.disabled:hover:active,
|
||||
.datepicker table tr td.range.today.active,
|
||||
.datepicker table tr td.range.today:hover.active,
|
||||
.datepicker table tr td.range.today.disabled.active,
|
||||
.datepicker table tr td.range.today.disabled:hover.active,
|
||||
.datepicker table tr td.range.today.disabled,
|
||||
.datepicker table tr td.range.today:hover.disabled,
|
||||
.datepicker table tr td.range.today.disabled.disabled,
|
||||
.datepicker table tr td.range.today.disabled:hover.disabled,
|
||||
.datepicker table tr td.range.today[disabled],
|
||||
.datepicker table tr td.range.today:hover[disabled],
|
||||
.datepicker table tr td.range.today.disabled[disabled],
|
||||
.datepicker table tr td.range.today.disabled:hover[disabled] {
|
||||
background-color: #f3e97a;
|
||||
}
|
||||
.datepicker table tr td.range.today:active,
|
||||
.datepicker table tr td.range.today:hover:active,
|
||||
.datepicker table tr td.range.today.disabled:active,
|
||||
.datepicker table tr td.range.today.disabled:hover:active,
|
||||
.datepicker table tr td.range.today.active,
|
||||
.datepicker table tr td.range.today:hover.active,
|
||||
.datepicker table tr td.range.today.disabled.active,
|
||||
.datepicker table tr td.range.today.disabled:hover.active {
|
||||
background-color: #efe24b \9;
|
||||
}
|
||||
.datepicker table tr td.selected,
|
||||
.datepicker table tr td.selected:hover,
|
||||
.datepicker table tr td.selected.disabled,
|
||||
.datepicker table tr td.selected.disabled:hover {
|
||||
background-color: #9e9e9e;
|
||||
background-image: -moz-linear-gradient(to bottom, #b3b3b3, #808080);
|
||||
background-image: -ms-linear-gradient(to bottom, #b3b3b3, #808080);
|
||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#b3b3b3), to(#808080));
|
||||
background-image: -webkit-linear-gradient(to bottom, #b3b3b3, #808080);
|
||||
background-image: -o-linear-gradient(to bottom, #b3b3b3, #808080);
|
||||
background-image: linear-gradient(to bottom, #b3b3b3, #808080);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#b3b3b3', endColorstr='#808080', GradientType=0);
|
||||
border-color: #808080 #808080 #595959;
|
||||
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
|
||||
color: #fff;
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
.datepicker table tr td.selected:hover,
|
||||
.datepicker table tr td.selected:hover:hover,
|
||||
.datepicker table tr td.selected.disabled:hover,
|
||||
.datepicker table tr td.selected.disabled:hover:hover,
|
||||
.datepicker table tr td.selected:active,
|
||||
.datepicker table tr td.selected:hover:active,
|
||||
.datepicker table tr td.selected.disabled:active,
|
||||
.datepicker table tr td.selected.disabled:hover:active,
|
||||
.datepicker table tr td.selected.active,
|
||||
.datepicker table tr td.selected:hover.active,
|
||||
.datepicker table tr td.selected.disabled.active,
|
||||
.datepicker table tr td.selected.disabled:hover.active,
|
||||
.datepicker table tr td.selected.disabled,
|
||||
.datepicker table tr td.selected:hover.disabled,
|
||||
.datepicker table tr td.selected.disabled.disabled,
|
||||
.datepicker table tr td.selected.disabled:hover.disabled,
|
||||
.datepicker table tr td.selected[disabled],
|
||||
.datepicker table tr td.selected:hover[disabled],
|
||||
.datepicker table tr td.selected.disabled[disabled],
|
||||
.datepicker table tr td.selected.disabled:hover[disabled] {
|
||||
background-color: #808080;
|
||||
}
|
||||
.datepicker table tr td.selected:active,
|
||||
.datepicker table tr td.selected:hover:active,
|
||||
.datepicker table tr td.selected.disabled:active,
|
||||
.datepicker table tr td.selected.disabled:hover:active,
|
||||
.datepicker table tr td.selected.active,
|
||||
.datepicker table tr td.selected:hover.active,
|
||||
.datepicker table tr td.selected.disabled.active,
|
||||
.datepicker table tr td.selected.disabled:hover.active {
|
||||
background-color: #666666 \9;
|
||||
}
|
||||
.datepicker table tr td.active,
|
||||
.datepicker table tr td.active:hover,
|
||||
.datepicker table tr td.active.disabled,
|
||||
.datepicker table tr td.active.disabled:hover {
|
||||
background-color: #006dcc;
|
||||
background-image: -moz-linear-gradient(to bottom, #08c, #0044cc);
|
||||
background-image: -ms-linear-gradient(to bottom, #08c, #0044cc);
|
||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#08c), to(#0044cc));
|
||||
background-image: -webkit-linear-gradient(to bottom, #08c, #0044cc);
|
||||
background-image: -o-linear-gradient(to bottom, #08c, #0044cc);
|
||||
background-image: linear-gradient(to bottom, #08c, #0044cc);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#08c', endColorstr='#0044cc', GradientType=0);
|
||||
border-color: #0044cc #0044cc #002a80;
|
||||
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
|
||||
color: #fff;
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
.datepicker table tr td.active:hover,
|
||||
.datepicker table tr td.active:hover:hover,
|
||||
.datepicker table tr td.active.disabled:hover,
|
||||
.datepicker table tr td.active.disabled:hover:hover,
|
||||
.datepicker table tr td.active:active,
|
||||
.datepicker table tr td.active:hover:active,
|
||||
.datepicker table tr td.active.disabled:active,
|
||||
.datepicker table tr td.active.disabled:hover:active,
|
||||
.datepicker table tr td.active.active,
|
||||
.datepicker table tr td.active:hover.active,
|
||||
.datepicker table tr td.active.disabled.active,
|
||||
.datepicker table tr td.active.disabled:hover.active,
|
||||
.datepicker table tr td.active.disabled,
|
||||
.datepicker table tr td.active:hover.disabled,
|
||||
.datepicker table tr td.active.disabled.disabled,
|
||||
.datepicker table tr td.active.disabled:hover.disabled,
|
||||
.datepicker table tr td.active[disabled],
|
||||
.datepicker table tr td.active:hover[disabled],
|
||||
.datepicker table tr td.active.disabled[disabled],
|
||||
.datepicker table tr td.active.disabled:hover[disabled] {
|
||||
background-color: #0044cc;
|
||||
}
|
||||
.datepicker table tr td.active:active,
|
||||
.datepicker table tr td.active:hover:active,
|
||||
.datepicker table tr td.active.disabled:active,
|
||||
.datepicker table tr td.active.disabled:hover:active,
|
||||
.datepicker table tr td.active.active,
|
||||
.datepicker table tr td.active:hover.active,
|
||||
.datepicker table tr td.active.disabled.active,
|
||||
.datepicker table tr td.active.disabled:hover.active {
|
||||
background-color: #003399 \9;
|
||||
}
|
||||
.datepicker table tr td span {
|
||||
display: block;
|
||||
width: 23%;
|
||||
height: 54px;
|
||||
line-height: 54px;
|
||||
float: left;
|
||||
margin: 1%;
|
||||
cursor: pointer;
|
||||
-webkit-border-radius: 4px;
|
||||
-moz-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.datepicker table tr td span:hover,
|
||||
.datepicker table tr td span.focused {
|
||||
background: #eee;
|
||||
}
|
||||
.datepicker table tr td span.disabled,
|
||||
.datepicker table tr td span.disabled:hover {
|
||||
background: none;
|
||||
color: #999;
|
||||
cursor: default;
|
||||
}
|
||||
.datepicker table tr td span.active,
|
||||
.datepicker table tr td span.active:hover,
|
||||
.datepicker table tr td span.active.disabled,
|
||||
.datepicker table tr td span.active.disabled:hover {
|
||||
background-color: #006dcc;
|
||||
background-image: -moz-linear-gradient(to bottom, #08c, #0044cc);
|
||||
background-image: -ms-linear-gradient(to bottom, #08c, #0044cc);
|
||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#08c), to(#0044cc));
|
||||
background-image: -webkit-linear-gradient(to bottom, #08c, #0044cc);
|
||||
background-image: -o-linear-gradient(to bottom, #08c, #0044cc);
|
||||
background-image: linear-gradient(to bottom, #08c, #0044cc);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#08c', endColorstr='#0044cc', GradientType=0);
|
||||
border-color: #0044cc #0044cc #002a80;
|
||||
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
|
||||
color: #fff;
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
.datepicker table tr td span.active:hover,
|
||||
.datepicker table tr td span.active:hover:hover,
|
||||
.datepicker table tr td span.active.disabled:hover,
|
||||
.datepicker table tr td span.active.disabled:hover:hover,
|
||||
.datepicker table tr td span.active:active,
|
||||
.datepicker table tr td span.active:hover:active,
|
||||
.datepicker table tr td span.active.disabled:active,
|
||||
.datepicker table tr td span.active.disabled:hover:active,
|
||||
.datepicker table tr td span.active.active,
|
||||
.datepicker table tr td span.active:hover.active,
|
||||
.datepicker table tr td span.active.disabled.active,
|
||||
.datepicker table tr td span.active.disabled:hover.active,
|
||||
.datepicker table tr td span.active.disabled,
|
||||
.datepicker table tr td span.active:hover.disabled,
|
||||
.datepicker table tr td span.active.disabled.disabled,
|
||||
.datepicker table tr td span.active.disabled:hover.disabled,
|
||||
.datepicker table tr td span.active[disabled],
|
||||
.datepicker table tr td span.active:hover[disabled],
|
||||
.datepicker table tr td span.active.disabled[disabled],
|
||||
.datepicker table tr td span.active.disabled:hover[disabled] {
|
||||
background-color: #0044cc;
|
||||
}
|
||||
.datepicker table tr td span.active:active,
|
||||
.datepicker table tr td span.active:hover:active,
|
||||
.datepicker table tr td span.active.disabled:active,
|
||||
.datepicker table tr td span.active.disabled:hover:active,
|
||||
.datepicker table tr td span.active.active,
|
||||
.datepicker table tr td span.active:hover.active,
|
||||
.datepicker table tr td span.active.disabled.active,
|
||||
.datepicker table tr td span.active.disabled:hover.active {
|
||||
background-color: #003399 \9;
|
||||
}
|
||||
.datepicker table tr td span.old,
|
||||
.datepicker table tr td span.new {
|
||||
color: #999;
|
||||
}
|
||||
.datepicker .datepicker-switch {
|
||||
width: 145px;
|
||||
}
|
||||
.datepicker .datepicker-switch,
|
||||
.datepicker .prev,
|
||||
.datepicker .next,
|
||||
.datepicker tfoot tr th {
|
||||
cursor: pointer;
|
||||
}
|
||||
.datepicker .datepicker-switch:hover,
|
||||
.datepicker .prev:hover,
|
||||
.datepicker .next:hover,
|
||||
.datepicker tfoot tr th:hover {
|
||||
background: #eee;
|
||||
}
|
||||
.datepicker .prev.disabled,
|
||||
.datepicker .next.disabled {
|
||||
visibility: hidden;
|
||||
}
|
||||
.datepicker .cw {
|
||||
font-size: 10px;
|
||||
width: 12px;
|
||||
padding: 0 2px 0 5px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.input-append.date .add-on,
|
||||
.input-prepend.date .add-on {
|
||||
cursor: pointer;
|
||||
}
|
||||
.input-append.date .add-on i,
|
||||
.input-prepend.date .add-on i {
|
||||
margin-top: 3px;
|
||||
}
|
||||
.input-daterange input {
|
||||
text-align: center;
|
||||
}
|
||||
.input-daterange input:first-child {
|
||||
-webkit-border-radius: 3px 0 0 3px;
|
||||
-moz-border-radius: 3px 0 0 3px;
|
||||
border-radius: 3px 0 0 3px;
|
||||
}
|
||||
.input-daterange input:last-child {
|
||||
-webkit-border-radius: 0 3px 3px 0;
|
||||
-moz-border-radius: 0 3px 3px 0;
|
||||
border-radius: 0 3px 3px 0;
|
||||
}
|
||||
.input-daterange .add-on {
|
||||
display: inline-block;
|
||||
width: auto;
|
||||
min-width: 16px;
|
||||
height: 20px;
|
||||
padding: 4px 5px;
|
||||
font-weight: normal;
|
||||
line-height: 20px;
|
||||
text-align: center;
|
||||
text-shadow: 0 1px 0 #fff;
|
||||
vertical-align: middle;
|
||||
background-color: #eee;
|
||||
border: 1px solid #ccc;
|
||||
margin-left: -5px;
|
||||
margin-right: -5px;
|
||||
}
|
||||
.datepicker.dropdown-menu {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
z-index: 1000;
|
||||
float: left;
|
||||
display: none;
|
||||
min-width: 160px;
|
||||
list-style: none;
|
||||
background-color: #fff;
|
||||
border: 1px solid #ccc;
|
||||
border: 1px solid rgba(0, 0, 0, 0.2);
|
||||
-webkit-border-radius: 5px;
|
||||
-moz-border-radius: 5px;
|
||||
border-radius: 5px;
|
||||
-webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
|
||||
-moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
|
||||
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
|
||||
-webkit-background-clip: padding-box;
|
||||
-moz-background-clip: padding;
|
||||
background-clip: padding-box;
|
||||
*border-right-width: 2px;
|
||||
*border-bottom-width: 2px;
|
||||
color: #333333;
|
||||
font-size: 13px;
|
||||
line-height: 20px;
|
||||
}
|
||||
.datepicker.dropdown-menu th,
|
||||
.datepicker.datepicker-inline th,
|
||||
.datepicker.dropdown-menu td,
|
||||
.datepicker.datepicker-inline td {
|
||||
padding: 4px 5px;
|
||||
}
|
||||
/*# sourceMappingURL=bootstrap-datepicker.standalone.css.map */
|
@ -0,0 +1 @@
|
||||
.select2-container--bootstrap4 .select2-selection--single{height:calc(1.5em + .75rem + 2px)!important}.select2-container--bootstrap4 .select2-selection--single .select2-selection__placeholder{color:#757575;line-height:calc(1.5em + .75rem)}.select2-container--bootstrap4 .select2-selection--single .select2-selection__arrow{position:absolute;top:50%;right:3px;width:20px}.select2-container--bootstrap4 .select2-selection--single .select2-selection__arrow b{top:60%;border-color:#343a40 transparent transparent;border-style:solid;border-width:5px 4px 0;width:0;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute}.select2-container--bootstrap4 .select2-selection--single .select2-selection__rendered{line-height:calc(1.5em + .75rem)}.select2-search--dropdown .select2-search__field{border:1px solid #ced4da;border-radius:.25rem}.select2-results__message{color:#6c757d}.select2-container--bootstrap4 .select2-selection--multiple{min-height:calc(1.5em + .75rem + 2px)!important}.select2-container--bootstrap4 .select2-selection--multiple .select2-selection__rendered{-webkit-box-sizing:border-box;box-sizing:border-box;list-style:none;margin:0;padding:0 5px;width:100%}.select2-container--bootstrap4 .select2-selection--multiple .select2-selection__choice{color:#343a40;border:1px solid #bdc6d0;border-radius:.2rem;padding:0 5px 0 0;cursor:pointer;float:left;margin-top:.3em;margin-right:5px}.select2-container--bootstrap4 .select2-selection--multiple .select2-selection__choice__remove{color:#bdc6d0;font-weight:700;margin-left:3px;margin-right:1px;padding-right:3px;padding-left:3px;float:left}.select2-container--bootstrap4 .select2-selection--multiple .select2-selection__choice__remove:hover{color:#343a40}.select2-container{display:block}.select2-container :focus{outline:0}.input-group .select2-container--bootstrap4{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1}.input-group-prepend~.select2-container--bootstrap4 .select2-selection{border-top-left-radius:0;border-bottom-left-radius:0}.select2-container--bootstrap4 .select2-selection{border:1px solid #ced4da;border-radius:.25rem;width:100%}.select2-container--bootstrap4.select2-container--focus .select2-selection{border-color:#17a2b8;-webkit-box-shadow:0 0 0 .2rem rgba(0,123,255,.25);box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.select2-container--bootstrap4.select2-container--focus.select2-container--open .select2-selection{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--bootstrap4.select2-container--disabled.select2-container--focus .select2-selection,.select2-container--bootstrap4.select2-container--disabled .select2-selection{background-color:#e9ecef;cursor:not-allowed;border-color:#ced4da;-webkit-box-shadow:none;box-shadow:none}.select2-container--bootstrap4.select2-container--disabled.select2-container--focus .select2-search__field,.select2-container--bootstrap4.select2-container--disabled .select2-search__field{background-color:transparent}form.was-validated select:invalid~.select2-container--bootstrap4 .select2-selection,select.is-invalid~.select2-container--bootstrap4 .select2-selection{border-color:#dc3545}form.was-validated select:valid~.select2-container--bootstrap4 .select2-selection,select.is-valid~.select2-container--bootstrap4 .select2-selection{border-color:#28a745}.select2-container--bootstrap4 .select2-dropdown{border-color:#ced4da;border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-container--bootstrap4 .select2-dropdown.select2-dropdown--above{border-top:1px solid #ced4da;border-top-left-radius:.25rem;border-top-right-radius:.25rem}.select2-container--bootstrap4 .select2-dropdown .select2-results__option[aria-selected=true]{background-color:#e9ecef}.select2-container--bootstrap4 .select2-results__option--highlighted,.select2-container--bootstrap4 .select2-results__option--highlighted.select2-results__option[aria-selected=true]{background-color:#007bff;color:#f8f9fa}.select2-container--bootstrap4 .select2-results__option[role=group]{padding:0}.select2-container--bootstrap4 .select2-results>.select2-results__options{max-height:15em;overflow-y:auto}.select2-container--bootstrap4 .select2-results__group{padding:6px;display:list-item;color:#6c757d}.select2-container--bootstrap4 .select2-selection__clear{width:1.2em;height:1.2em;line-height:1.15em;padding-left:.3em;margin-top:.5em;border-radius:100%;background-color:#6c757d;color:#f8f9fa;float:right;margin-right:.3em}.select2-container--bootstrap4 .select2-selection__clear:hover{background-color:#343a40}
|
File diff suppressed because one or more lines are too long
@ -1,3 +0,0 @@
|
||||
// Place all the styles related to the users/banks controller here.
|
||||
// They will automatically be included in application.css.
|
||||
// You can use Sass (SCSS) here: http://sass-lang.com/
|
@ -1,8 +0,0 @@
|
||||
class AdminController < ApplicationController
|
||||
layout 'admin'
|
||||
before_action :require_admin
|
||||
|
||||
def index
|
||||
|
||||
end
|
||||
end
|
@ -0,0 +1,24 @@
|
||||
class Admins::BaseController < ApplicationController
|
||||
include Admins::PaginateHelper
|
||||
include Admins::RenderHelper
|
||||
include Admins::ErrorRescueHandler
|
||||
|
||||
layout 'admin'
|
||||
|
||||
before_action :require_login, :require_admin!
|
||||
|
||||
private
|
||||
|
||||
def require_login
|
||||
return if User.current.logged?
|
||||
|
||||
redirect_to "/login?back_url=#{CGI::escape(request.fullpath)}"
|
||||
end
|
||||
|
||||
def require_admin!
|
||||
return if current_user.blank? || !current_user.logged?
|
||||
return if current_user.admin_or_business?
|
||||
|
||||
render_forbidden
|
||||
end
|
||||
end
|
@ -0,0 +1,36 @@
|
||||
class Admins::DailySchoolStatisticsController < Admins::BaseController
|
||||
def index
|
||||
params[:sort_by] = params[:sort_by].presence || :teacher_count
|
||||
params[:sort_direction] = params[:sort_direction].presence || :desc
|
||||
|
||||
total_count, statistics = Admins::SchoolDailyStatisticService.call(params)
|
||||
|
||||
@statistics = paginate statistics, total_count: total_count
|
||||
|
||||
respond_to do |format|
|
||||
format.html { load_statistic_total }
|
||||
format.js
|
||||
end
|
||||
end
|
||||
|
||||
def export
|
||||
params[:per_page] = 10000
|
||||
_count, @schools = Admins::SchoolDailyStatisticService.call(params)
|
||||
|
||||
filename = ['学校统计总表', params[:keyword], Time.zone.now.strftime('%Y%m%d%H%M%S')].join('-') << '.xlsx'
|
||||
render xlsx: 'export', filename: filename
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def load_statistic_total
|
||||
@teacher_total = User.joins(:user_extension).where(user_extensions: { identity: :teacher }).count
|
||||
@student_total = User.joins(:user_extension).where(user_extensions: { identity: :student }).count
|
||||
@course_total = Course.count
|
||||
@active_course_total = Course.where(is_end: false).count
|
||||
@shixun_homework_total = HomeworkCommon.where(homework_type: 4).count
|
||||
@other_homework_total = HomeworkCommon.where(homework_type: [1, 3]).count
|
||||
@shixun_total = Shixun.count
|
||||
@shixun_evaluate_total = SchoolReport.sum(:shixun_evaluate_count)
|
||||
end
|
||||
end
|
@ -0,0 +1,4 @@
|
||||
class Admins::DashboardsController < Admins::BaseController
|
||||
def index
|
||||
end
|
||||
end
|
@ -0,0 +1,49 @@
|
||||
class Admins::SchoolStatisticsController < Admins::BaseController
|
||||
before_action :contrast_column_select_options, only: [:contrast]
|
||||
|
||||
def index
|
||||
params[:data_type] ||= 'grow'
|
||||
params[:sort_by] = params[:sort_by].presence || :teacher_increase_count
|
||||
params[:sort_direction] = params[:sort_direction].presence || :desc
|
||||
|
||||
service = Admins::StatisticSchoolDataGrowService.new(params)
|
||||
@grow_summary = service.grow_summary
|
||||
|
||||
total_count, statistics = service.call
|
||||
|
||||
@statistics = paginate statistics, total_count: total_count
|
||||
end
|
||||
|
||||
def contrast
|
||||
params[:contrast_column] = params[:contrast_column].presence || :teacher_increase_count
|
||||
params[:sort_direction] ||= :desc
|
||||
params[:sort_by] = :percentage
|
||||
|
||||
# 无对比日期时直接返回无数据页面
|
||||
if useless_contrast_date_parameter?
|
||||
@total_count = 0
|
||||
@statistics = paginate([])
|
||||
return
|
||||
end
|
||||
|
||||
total_count, statistics = Admins::StatisticSchoolContrastDataService.call(params)
|
||||
|
||||
@statistics = paginate statistics, total_count: total_count
|
||||
rescue Admins::StatisticSchoolContrastDataService::ParameterError
|
||||
render_unprocessable_entity('参数错误')
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def useless_contrast_date_parameter?
|
||||
params[:begin_date].blank? && params[:end_date].blank? &&
|
||||
params[:other_begin_date].blank? &¶ms[:other_end_date].blank?
|
||||
end
|
||||
|
||||
def contrast_column_select_options
|
||||
@select_options =
|
||||
Admins::StatisticSchoolContrastDataService::CONTRAST_COLUMN_LIST.map do |column|
|
||||
[I18n.t("school_daily_report.#{column}"), column]
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,62 @@
|
||||
class Admins::UsersController < Admins::BaseController
|
||||
def index
|
||||
params[:sort_by] = params[:sort_by].presence || 'created_on'
|
||||
params[:sort_direction] = params[:sort_direction].presence || 'desc'
|
||||
|
||||
users = Admins::UserQuery.call(params)
|
||||
@users = paginate users.includes(user_extension: :school)
|
||||
end
|
||||
|
||||
def edit
|
||||
@user = User.find(params[:id])
|
||||
end
|
||||
|
||||
def update
|
||||
@user = User.find(params[:id])
|
||||
|
||||
Admins::UpdateUserService.call(@user, update_params)
|
||||
flash[:success] = '保存成功'
|
||||
redirect_to edit_admins_user_path(@user)
|
||||
rescue ActiveRecord::RecordInvalid
|
||||
flash.now[:danger] = '保存失败'
|
||||
render 'edit'
|
||||
rescue Admins::UpdateUserService::Error => ex
|
||||
flash.now[:danger] = ex.message
|
||||
render 'edit'
|
||||
end
|
||||
|
||||
def destroy
|
||||
User.find(params[:id]).destroy!
|
||||
|
||||
render_delete_success
|
||||
end
|
||||
|
||||
def lock
|
||||
User.find(params[:user_id]).lock!
|
||||
|
||||
render_ok
|
||||
end
|
||||
|
||||
def unlock
|
||||
User.find(params[:user_id]).activate!
|
||||
|
||||
render_ok
|
||||
end
|
||||
|
||||
def reward_grade
|
||||
user = User.find(params[:user_id])
|
||||
return render_unprocessable_entity('金币数量必须大于0') if params[:grade].to_i <= 0
|
||||
|
||||
RewardGradeService.call(user, container_id: user.id, container_type: 'Feedback', score: params[:grade].to_i, not_unique: true)
|
||||
|
||||
render_ok(grade: user.grade)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def update_params
|
||||
params.require(:user).permit(%i[lastname nickname gender identity technical_title student_id
|
||||
mail phone location location_city school_id department_id admin business is_test
|
||||
password professional_certification authentication])
|
||||
end
|
||||
end
|
@ -0,0 +1,24 @@
|
||||
module Admins::ErrorRescueHandler
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
rescue_from Exception, Educoder::TipException do |e|
|
||||
raise e if Rails.env.development?
|
||||
|
||||
Util.logger_error e
|
||||
internal_server_error
|
||||
end
|
||||
|
||||
rescue_from ActionView::MissingTemplate, ActiveRecord::RecordNotFound, with: :render_not_found
|
||||
rescue_from ActionController::ParameterMissing do
|
||||
render_unprocessable_entity('参数缺失')
|
||||
end
|
||||
# form validation error
|
||||
rescue_from ActiveModel::ValidationError do |ex|
|
||||
render_unprocessable_entity(ex.model.errors.full_messages.join(','))
|
||||
end
|
||||
rescue_from ActiveRecord::RecordInvalid do |ex|
|
||||
render_unprocessable_entity(ex.record.errors.full_messages.join(','))
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,24 @@
|
||||
module Admins::PaginateHelper
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def offset
|
||||
(page - 1) * per_page
|
||||
end
|
||||
|
||||
def page
|
||||
params[:page].to_i <= 0 ? 1 : params[:page].to_i
|
||||
end
|
||||
|
||||
def per_page
|
||||
params[:per_page].to_i <= 0 || params[:per_page].to_i > 100 ? 20 : params[:per_page].to_i
|
||||
end
|
||||
alias_method :limit, :per_page
|
||||
|
||||
def paginate(relations, total_count: nil)
|
||||
if relations.is_a?(Array)
|
||||
Kaminari.paginate_array(relations, limit: limit, offset: offset, total_count: total_count)
|
||||
else
|
||||
relations.page(page).per(per_page)
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,47 @@
|
||||
module Admins::RenderHelper
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def render_forbidden
|
||||
respond_to do |format|
|
||||
format.html { redirect_to '/403' }
|
||||
format.json { super }
|
||||
end
|
||||
end
|
||||
|
||||
def render_not_found
|
||||
respond_to do |format|
|
||||
format.html { render 'admins/shared/404' }
|
||||
format.js { render_js_error('资源未找到') }
|
||||
format.json { render status: 404, json: { message: '资源未找到' } }
|
||||
end
|
||||
end
|
||||
|
||||
def render_unprocessable_entity(message)
|
||||
respond_to do |format|
|
||||
format.html { render 'admins/shared/422' }
|
||||
format.js { render_js_error(message) }
|
||||
format.json { render status: 422, json: { message: message } }
|
||||
end
|
||||
end
|
||||
alias_method :render_error, :render_unprocessable_entity
|
||||
|
||||
def internal_server_error
|
||||
respond_to do |format|
|
||||
format.html { render 'admins/shared/500' }
|
||||
format.js { render_js_error(message) }
|
||||
format.json { render status: 500, json: { message: '系统错误' } }
|
||||
end
|
||||
end
|
||||
|
||||
def render_js_template(template, **opts)
|
||||
render({ template: template, formats: :js }.merge(opts))
|
||||
end
|
||||
|
||||
def render_delete_success
|
||||
render_js_template 'admins/shared/delete'
|
||||
end
|
||||
|
||||
def render_js_error(message)
|
||||
render_js_template 'admins/shared/error', locals: { message: message }
|
||||
end
|
||||
end
|
@ -0,0 +1,11 @@
|
||||
class SidebarUtil
|
||||
class << self
|
||||
def controller_name(name)
|
||||
sidebar_controller_map[name]
|
||||
end
|
||||
|
||||
def sidebar_controller_map
|
||||
@_sidebar_controller_map ||= YAML.load_file(Rails.root.join('config/admins', 'sidebar.yml'))
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,3 @@
|
||||
class SchoolDailyActiveUser < ApplicationRecord
|
||||
belongs_to :school_daily_report
|
||||
end
|
@ -0,0 +1,5 @@
|
||||
class SchoolDailyReport < ApplicationRecord
|
||||
belongs_to :school
|
||||
|
||||
has_many :school_daily_active_users, dependent: :delete_all
|
||||
end
|
@ -0,0 +1,3 @@
|
||||
class SchoolReport < ApplicationRecord
|
||||
belongs_to :school
|
||||
end
|
@ -0,0 +1,40 @@
|
||||
class Admins::UserQuery < ApplicationQuery
|
||||
include CustomSortable
|
||||
|
||||
attr_reader :params
|
||||
|
||||
sort_columns :created_on, :last_login_on, :experience, :grade, default_by: :created_on, default_direction: :desc
|
||||
|
||||
def initialize(params)
|
||||
@params = params
|
||||
end
|
||||
|
||||
def call
|
||||
users = User.where(type: 'User')
|
||||
|
||||
# 状态
|
||||
status = params[:status]
|
||||
users = users.where(status: status) if status.present?
|
||||
|
||||
# 职业
|
||||
users = users.joins(:user_extension).where(user_extensions: { identity: params[:identity] }) if params[:identity].present?
|
||||
|
||||
# 授权类型
|
||||
if params[:auto_trial].present?
|
||||
users = users.joins(user_extension: :school).where(schools: { auto_users_trial: params[:auto_trial].to_i == 1 })
|
||||
end
|
||||
|
||||
# 关键字检索
|
||||
keyword = params[:keyword].to_s.strip.presence
|
||||
if keyword
|
||||
sql = 'CONCAT(lastname, firstname) LIKE :keyword OR login LIKE :keyword OR mail LIKE :keyword OR phone LIKE :keyword'
|
||||
users = users.where(sql, keyword: keyword)
|
||||
end
|
||||
|
||||
# 学校名称
|
||||
school_name = params[:school_name].to_s.strip.presence
|
||||
users = users.joins(user_extension: :school).where('schools.name LIKE ?', "%#{school_name}%") if school_name
|
||||
|
||||
custom_sort(users, params[:sort_by], params[:sort_direction])
|
||||
end
|
||||
end
|
@ -0,0 +1,123 @@
|
||||
class Admins::SchoolDailyStatisticService < ApplicationService
|
||||
include CustomSortable
|
||||
|
||||
attr_reader :params
|
||||
|
||||
sort_columns :student_count, :teacher_count, :homework_count, :other_homework_count,
|
||||
:course_count, :active_course_count, :nearly_course_time, :shixun_count, :shixun_evaluate_count,
|
||||
default_by: :teacher_count, default_direction: :desc
|
||||
|
||||
def initialize(params)
|
||||
@params = params
|
||||
end
|
||||
|
||||
def call
|
||||
schools = School.group('schools.id')
|
||||
|
||||
keyword = params[:keyword].try(:to_s).try(:strip)
|
||||
if keyword.present?
|
||||
schools = schools.where("schools.name LIKE :keyword OR schools.id LIKE :keyword", keyword: "%#{keyword}%")
|
||||
end
|
||||
|
||||
count = schools.count.count
|
||||
|
||||
# 根据排序字段进行查询
|
||||
schools = query_by_sort_column(schools, params[:sort_by])
|
||||
schools = custom_sort(schools, params[:sort_by], params[:sort_direction])
|
||||
|
||||
schools = schools.limit(page_size).offset(offset)
|
||||
# 查询并组装其它数据
|
||||
schools = package_other_data(schools)
|
||||
|
||||
[count, schools]
|
||||
end
|
||||
|
||||
def package_other_data(schools)
|
||||
ids = schools.map(&:id)
|
||||
|
||||
student_map = UserExtension.where(school_id: ids, identity: :student).group(:school_id).count
|
||||
teacher_map = UserExtension.where(school_id: ids, identity: :teacher).group(:school_id).count
|
||||
|
||||
homeworks = HomeworkCommon.joins(:course)
|
||||
shixun_homework_map = homeworks.where(homework_type: 4, courses: { school_id: ids }).group('school_id').count
|
||||
other_homework_map = homeworks.where(homework_type: [1, 3], courses: { school_id: ids }).group('school_id').count
|
||||
|
||||
courses = Course.where(is_delete: 0, school_id: ids).group('school_id')
|
||||
course_map = courses.count
|
||||
nearly_course_time_map = courses.joins(:course_acts).maximum('course_activities.updated_at')
|
||||
active_course_map = courses.where(is_end: false).count
|
||||
|
||||
shixun_map = Shixun.joins(user: :user_extension).where(user_extensions: { identity: :teacher, school_id: ids })
|
||||
.where(fork_from: nil).group('school_id').count
|
||||
|
||||
reports = SchoolReport.where(school_id: ids)
|
||||
evaluate_count_map = reports.each_with_object({}) { |report, obj| obj[report.school_id] = report.shixun_evaluate_count }
|
||||
|
||||
schools.map do |school|
|
||||
{
|
||||
id: school.id,
|
||||
name: school.name,
|
||||
teacher_count: teacher_map[school.id],
|
||||
student_count: student_map[school.id],
|
||||
homework_count: shixun_homework_map[school.id],
|
||||
other_homework_count: other_homework_map[school.id],
|
||||
course_count: course_map[school.id],
|
||||
nearly_course_time: nearly_course_time_map[school.id],
|
||||
active_course_count: active_course_map[school.id],
|
||||
shixun_count: shixun_map.fetch(school.id, 0),
|
||||
shixun_evaluate_count: evaluate_count_map.fetch(school.id, 0)
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def query_by_sort_column(schools, sort_by_column)
|
||||
base_query_column = 'schools.id, schools.name'
|
||||
|
||||
case sort_by_column.to_s
|
||||
when 'teacher_count' then
|
||||
schools.joins('LEFT JOIN user_extensions ue ON ue.school_id = schools.id AND ue.identity = 0')
|
||||
.select("#{base_query_column}, COUNT(*) teacher_count")
|
||||
when 'student_count' then
|
||||
schools.joins('LEFT JOIN user_extensions ue ON ue.school_id = schools.id AND ue.identity = 1')
|
||||
.select("#{base_query_column}, COUNT(*) student_count")
|
||||
when 'homework_count' then
|
||||
schools.joins('LEFT JOIN courses ON courses.school_id = schools.id')
|
||||
.joins('LEFT JOIN homework_commons hc ON hc.course_id = courses.id AND hc.homework_type = 4')
|
||||
.select("#{base_query_column}, COUNT(*) homework_count")
|
||||
when 'other_homework_count' then
|
||||
schools.joins('LEFT JOIN courses ON courses.school_id = schools.id')
|
||||
.joins('LEFT JOIN homework_commons hc ON hc.course_id = courses.id AND hc.homework_type IN (1, 3)')
|
||||
.select("#{base_query_column}, COUNT(*) other_homework_count")
|
||||
when 'course_count' then
|
||||
schools.joins('LEFT JOIN courses cs ON cs.school_id = schools.id AND cs.is_delete = 0')
|
||||
.select("#{base_query_column}, COUNT(*) course_count")
|
||||
when 'shixun_count' then
|
||||
schools.joins('LEFT JOIN user_extensions ue ON ue.school_id = schools.id AND ue.identity = 0')
|
||||
.joins('LEFT JOIN users ON users.id = ue.user_id')
|
||||
.joins('LEFT JOIN shixuns sx ON sx.user_id = users.id AND sx.fork_from IS NULL')
|
||||
.select("#{base_query_column}, COUNT(*) shixun_count")
|
||||
when 'shixun_evaluate_count' then
|
||||
schools.joins('LEFT JOIN school_reports ON school_reports.school_id = schools.id')
|
||||
.select("#{base_query_column}, shixun_evaluate_count")
|
||||
when 'nearly_course_time' then
|
||||
schools.joins('LEFT JOIN courses cs ON cs.school_id = schools.id AND cs.is_delete = 0')
|
||||
.joins('LEFT JOIN course_activities acs ON acs.course_id = cs.id')
|
||||
.select("#{base_query_column}, MAX(acs.updated_at) nearly_course_time")
|
||||
when 'active_course_count' then
|
||||
schools.joins('LEFT JOIN courses cs ON cs.school_id = schools.id AND cs.is_delete = 0 AND cs.is_end = false')
|
||||
.select("#{base_query_column}, COUNT(*) active_course_count")
|
||||
else
|
||||
schools.joins('LEFT JOIN user_extensions ue ON ue.school_id = schools.id AND ue.identity = 0')
|
||||
.select("#{base_query_column}, COUNT(*) teacher_count")
|
||||
end
|
||||
end
|
||||
|
||||
def page_size
|
||||
params[:per_page] || 20
|
||||
end
|
||||
|
||||
def offset
|
||||
(params[:page].to_i.zero? ? 0 : params[:page].to_i - 1) * page_size
|
||||
end
|
||||
end
|
@ -0,0 +1,80 @@
|
||||
class Admins::StatisticSchoolContrastDataService < ApplicationService
|
||||
ParameterError = Class.new(StandardError)
|
||||
|
||||
PAGE_SIZE = 20
|
||||
CONTRAST_COLUMN_LIST = %w(
|
||||
teacher_increase_count student_increase_count course_increase_count
|
||||
shixun_increase_count active_user_count shixun_homework_count shixun_evaluate_count
|
||||
).freeze
|
||||
|
||||
attr_reader :params, :sort_direction, :contrast_column
|
||||
|
||||
def initialize(params)
|
||||
@params = params
|
||||
@sort_direction = params[:sort_direction].to_s
|
||||
@contrast_column = params[:contrast_column].to_s
|
||||
end
|
||||
|
||||
def call
|
||||
validate_parameter!
|
||||
reports = School.joins(:school_daily_reports).select(select_columns)
|
||||
|
||||
keyword = params[:keyword].try(:to_s).try(:strip)
|
||||
if keyword.present?
|
||||
reports = reports.where("schools.name LIKE :keyword OR schools.id LIKE :keyword", keyword: "%#{keyword}%")
|
||||
end
|
||||
|
||||
count = reports.count('distinct(schools.id)')
|
||||
|
||||
sql = query_report_sql(reports.group('schools.id').to_sql)
|
||||
reports = SchoolDailyReport.find_by_sql(sql)
|
||||
|
||||
[count, reports]
|
||||
end
|
||||
|
||||
private
|
||||
def validate_parameter!
|
||||
if %i[begin_date end_date other_begin_date other_end_date].any? { |key| params[key].blank? }
|
||||
raise ParameterError
|
||||
end
|
||||
|
||||
unless %w(desc asc).include?(sort_direction)
|
||||
raise ParameterError
|
||||
end
|
||||
|
||||
unless CONTRAST_COLUMN_LIST.include?(contrast_column)
|
||||
raise ParameterError
|
||||
end
|
||||
end
|
||||
|
||||
def format_date(date)
|
||||
Time.zone.parse(date).strftime("%Y-%m-%d")
|
||||
end
|
||||
|
||||
def offset
|
||||
(params[:page].to_i.zero? ? 0 : params[:page].to_i - 1) * PAGE_SIZE
|
||||
end
|
||||
|
||||
def select_columns
|
||||
if contrast_column != 'active_user_count'
|
||||
"schools.id school_id, schools.name school_name,"\
|
||||
"(SUM(IF(date BETWEEN '#{format_date(params[:begin_date])}' AND '#{format_date(params[:end_date])}', #{contrast_column}, 0))) total,"\
|
||||
"(SUM(IF(date BETWEEN '#{format_date(params[:other_begin_date])}' AND '#{format_date(params[:other_end_date])}', #{contrast_column}, 0))) other_total"
|
||||
else
|
||||
# 活跃用户对比时处理方法不同
|
||||
relations = SchoolDailyActiveUser.select('COUNT(distinct user_id)').joins(:school_daily_report)
|
||||
.where('school_id = schools.id')
|
||||
total_subquery = relations.where("date BETWEEN '#{format_date(params[:begin_date])}' AND '#{format_date(params[:end_date])}'").to_sql
|
||||
other_total_subquery = relations.where("date BETWEEN '#{format_date(params[:other_begin_date])}' AND '#{format_date(params[:other_end_date])}'").to_sql
|
||||
|
||||
"schools.id school_id, schools.name school_name, (#{total_subquery}) AS total, (#{other_total_subquery}) AS other_total"
|
||||
end
|
||||
end
|
||||
|
||||
def query_report_sql(from_sql)
|
||||
order_by = "(total = 0 AND other_total != 0) #{sort_direction}, (percentage != 0) #{sort_direction}, percentage #{sort_direction}"
|
||||
|
||||
"SELECT reports.*, (other_total - total) increase, (IF(other_total - total = 0, 0.0, round((other_total - total) / IF(total = 0, 1, total), 5))) percentage "\
|
||||
"FROM (#{from_sql}) reports ORDER BY #{order_by} LIMIT #{PAGE_SIZE} OFFSET #{offset}"
|
||||
end
|
||||
end
|
@ -0,0 +1,52 @@
|
||||
class Admins::UpdateUserService < ApplicationService
|
||||
Error = Class.new(StandardError)
|
||||
|
||||
attr_reader :user, :params
|
||||
|
||||
def initialize(user, params)
|
||||
@user = user
|
||||
@params = params
|
||||
end
|
||||
|
||||
def call
|
||||
user.assign_attributes(user_attributes)
|
||||
user.firstname = ''
|
||||
user.password = password if params[:password].present?
|
||||
|
||||
if params[:identity].to_s == 'student'
|
||||
params[:technical_title] = nil
|
||||
else
|
||||
params[:student_id] = nil
|
||||
end
|
||||
user.user_extension.assign_attributes(user_extension_attributes)
|
||||
|
||||
ActiveRecord::Base.transaction do
|
||||
user.save!
|
||||
user.user_extension.save!
|
||||
|
||||
update_gitlab_password if params[:password].present?
|
||||
end
|
||||
|
||||
user
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def user_attributes
|
||||
params.slice(*%i[lastname nickname mail phone admin business is_test
|
||||
professional_certification authentication])
|
||||
end
|
||||
|
||||
def user_extension_attributes
|
||||
params.slice(*%i[gender identity technical_title student_id location location_city school_id department_id])
|
||||
end
|
||||
|
||||
def update_gitlab_password
|
||||
return if user.gid.blank?
|
||||
# 同步修改gitlab密码
|
||||
Gitlab.client.edit_user(user.gid, password: params[:password])
|
||||
rescue Exception => ex
|
||||
Util.logger_error(ex)
|
||||
raise Error, '保存失败'
|
||||
end
|
||||
end
|
@ -0,0 +1,69 @@
|
||||
class StatisticSchoolDailyReportTask
|
||||
def call
|
||||
School.find_each do |school|
|
||||
# 新增教师和学生
|
||||
users = User.joins(:user_extension)
|
||||
.where(user_extensions: { school_id: school.id })
|
||||
|
||||
teacher_count = users.where(created_on: yesterday, user_extensions: { identity: :teacher }).count
|
||||
student_count = users.where(created_on: yesterday, user_extensions: { identity: :student }).count
|
||||
|
||||
# 活跃用户
|
||||
active_user_ids = users.where(last_login_on: yesterday).pluck(:id)
|
||||
active_user_count = active_user_ids.size
|
||||
|
||||
|
||||
# 新增课堂
|
||||
course_count = school.courses.where(created_at: yesterday).count
|
||||
|
||||
# 新增实训
|
||||
shixun_count = Shixun.joins(user: :user_extension)
|
||||
.where(user_extensions: { identity: :teacher, school_id: school.id })
|
||||
.where(created_at: yesterday).count
|
||||
# 新增实训作业数
|
||||
shixun_homework_count = HomeworkCommon.joins(:course).where(courses: { school_id: school.id })
|
||||
.where(homework_type: 4, created_at: yesterday).count
|
||||
|
||||
# 新增实训评测数量
|
||||
shixun_evaluate_count = EvaluateRecord.joins('LEFT JOIN homework_commons_shixuns hcs ON hcs.shixun_id = evaluate_records.shixun_id')
|
||||
.joins('LEFT JOIN homework_commons hc ON hcs.homework_common_id = hc.id AND hc.homework_type = 4')
|
||||
.joins('LEFT JOIN members ON members.user_id = evaluate_records.user_id')
|
||||
.joins('LEFT JOIN courses ON members.course_id = courses.id AND hc.course_id = courses.id')
|
||||
.where(courses: { school_id: school.id })
|
||||
.where(created_at: yesterday).reorder(nil).count
|
||||
|
||||
# 无有效数据时不记录
|
||||
data = [teacher_count, student_count, course_count, shixun_count, active_user_count,
|
||||
shixun_homework_count, shixun_evaluate_count]
|
||||
next if data.all?(&:zero?)
|
||||
|
||||
create_params = {
|
||||
school_id: school.id, school_name: school.name, teacher_increase_count: teacher_count,
|
||||
student_increase_count: student_count, course_increase_count: course_count,
|
||||
shixun_homework_count: shixun_homework_count, shixun_evaluate_count: shixun_evaluate_count,
|
||||
shixun_increase_count: shixun_count, active_user_count: active_user_count, date: current_date
|
||||
}
|
||||
report = SchoolDailyReport.create!(create_params)
|
||||
|
||||
if active_user_ids.present?
|
||||
values = '(' + active_user_ids.join(", #{report.id}),(") + ", #{report.id})"
|
||||
user_sql = "INSERT INTO school_daily_active_users(user_id, school_daily_report_id) VALUES#{values}"
|
||||
SchoolDailyActiveUser.connection.execute(user_sql)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def current_date
|
||||
@_current_date ||= Time.zone.now.beginning_of_day - 1.day
|
||||
end
|
||||
|
||||
def yesterday
|
||||
@_yesterday ||= begin
|
||||
# 每日凌晨5点为节点
|
||||
end_time = Time.zone.now.beginning_of_day + 5.hour
|
||||
begin_time = end_time - 1.day
|
||||
begin_time..end_time
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,20 @@
|
||||
class StatisticSchoolReportTask
|
||||
def call
|
||||
School.find_each do |school|
|
||||
evaluate_count = Game.joins(:challenge)
|
||||
.joins('LEFT JOIN members ON members.user_id = games.user_id')
|
||||
.joins('LEFT JOIN homework_commons_shixuns hcs ON hcs.shixun_id = challenges.shixun_id')
|
||||
.joins('LEFT JOIN homework_commons hc ON hcs.homework_common_id = hc.id AND hc.homework_type = 4')
|
||||
.joins('LEFT JOIN courses ON hc.course_id = courses.id AND members.course_id = courses.id')
|
||||
.where(courses: { school_id: school.id })
|
||||
.sum(:evaluate_count)
|
||||
|
||||
report = SchoolReport.find_or_initialize_by(school_id: school.id)
|
||||
|
||||
report.school_name = school.name
|
||||
report.shixun_evaluate_count = evaluate_count
|
||||
|
||||
report.save
|
||||
end
|
||||
end
|
||||
end
|
@ -1,619 +0,0 @@
|
||||
2222222222z
|
||||
<!-- Start right content -->
|
||||
<div class="content-page">
|
||||
<!-- ============================================================== -->
|
||||
<!-- Start Content here -->
|
||||
<!-- ============================================================== -->
|
||||
<div class="content">
|
||||
<!-- Start info box -->
|
||||
<div class="row top-summary">
|
||||
<div class="col-lg-3 col-md-6">
|
||||
<div class="widget green-1 animated fadeInDown">
|
||||
<div class="widget-content padding">
|
||||
<div class="widget-icon">
|
||||
<i class="icon-globe-inv"></i>
|
||||
</div>
|
||||
<div class="text-box">
|
||||
<p class="maindata">TOTAL <b>VISITORS</b></p>
|
||||
<h2><span class="animate-number" data-value="25153" data-duration="3000">0</span></h2>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="widget-footer">
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<i class="fa fa-caret-up rel-change"></i> <b>39%</b> increase in traffic
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-3 col-md-6">
|
||||
<div class="widget darkblue-2 animated fadeInDown">
|
||||
<div class="widget-content padding">
|
||||
<div class="widget-icon">
|
||||
<i class="icon-bag"></i>
|
||||
</div>
|
||||
<div class="text-box">
|
||||
<p class="maindata">TOTAL <b>SALES</b></p>
|
||||
<h2><span class="animate-number" data-value="6399" data-duration="3000">0</span></h2>
|
||||
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="widget-footer">
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<i class="fa fa-caret-down rel-change"></i> <b>11%</b> decrease in sales
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-3 col-md-6">
|
||||
<div class="widget orange-4 animated fadeInDown">
|
||||
<div class="widget-content padding">
|
||||
<div class="widget-icon">
|
||||
<i class="fa fa-dollar"></i>
|
||||
</div>
|
||||
<div class="text-box">
|
||||
<p class="maindata">OVERALL <b>INCOME</b></p>
|
||||
<h2>$<span class="animate-number" data-value="70389" data-duration="3000">0</span></h2>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="widget-footer">
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<i class="fa fa-caret-down rel-change"></i> <b>7%</b> decrease in income
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-3 col-md-6">
|
||||
<div class="widget lightblue-1 animated fadeInDown">
|
||||
<div class="widget-content padding">
|
||||
<div class="widget-icon">
|
||||
<i class="fa fa-users"></i>
|
||||
</div>
|
||||
<div class="text-box">
|
||||
<p class="maindata">TOTAL <b>USERS</b></p>
|
||||
<h2><span class="animate-number" data-value="18648" data-duration="3000">0</span></h2>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="widget-footer">
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<i class="fa fa-caret-up rel-change"></i> <b>6%</b> increase in users
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!-- End of info box -->
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-8 portlets">
|
||||
<div id="website-statistics1" class="widget">
|
||||
<div class="widget-header transparent">
|
||||
<h2><i class="icon-chart-line"></i> <strong>Website</strong> Statistics</h2>
|
||||
<div class="additional-btn">
|
||||
<a href="#" class="hidden reload"><i class="icon-ccw-1"></i></a>
|
||||
<a class="hidden" id="dropdownMenu1" data-toggle="dropdown">
|
||||
<i class="fa fa-cogs"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu pull-right" role="menu" aria-labelledby="dropdownMenu1">
|
||||
<li><a href="#">Action</a></li>
|
||||
<li><a href="#">Another action</a></li>
|
||||
<li><a href="#">Something else here</a></li>
|
||||
<li class="divider"></li>
|
||||
<li><a href="#">Separated link</a></li>
|
||||
</ul>
|
||||
<a href="#" class="widget-popout hidden tt" title="Pop Out/In"><i class="icon-publish"></i></a>
|
||||
<a href="#" class="widget-maximize hidden"><i class="icon-resize-full-1"></i></a>
|
||||
<a href="#" class="widget-toggle"><i class="icon-down-open-2"></i></a>
|
||||
<a href="#" class="widget-close"><i class="icon-cancel-3"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="widget-content">
|
||||
<div id="website-statistic" class="statistic-chart">
|
||||
<div class="row stacked">
|
||||
<div class="col-sm-12">
|
||||
<div class="toolbar">
|
||||
<div class="pull-left">
|
||||
<div class="btn-group">
|
||||
<a href="#" class="btn btn-default btn-xs">Daily</a>
|
||||
<a href="#" class="btn btn-default btn-xs active">Monthly</a>
|
||||
<a href="#" class="btn btn-default btn-xs">Yearly</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pull-right">
|
||||
<div class="btn-group">
|
||||
<a class="btn btn-default btn-xs dropdown-toggle" data-toggle="dropdown">
|
||||
Export <i class="icon-down-open-2"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu pull-right" role="menu">
|
||||
<li><a href="#">Export as PDF</a></li>
|
||||
<li><a href="#">Export as CSV</a></li>
|
||||
<li><a href="#">Export as PNG</a></li>
|
||||
<li class="divider"></li>
|
||||
<li><a href="#">Separated link</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<a href="#" class="btn btn-primary btn-xs"><i class="icon-cog-2"></i></a>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
<div id="morris-home" class="morris-chart" style="height: 270px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<div class="col-lg-4 portlets">
|
||||
<div class="widget darkblue-3">
|
||||
<div class="widget-header transparent">
|
||||
<h2><strong>Server</strong> Status</h2>
|
||||
<div class="additional-btn">
|
||||
<a href="#" class="hidden reload"><i class="icon-ccw-1"></i></a>
|
||||
<a class="hidden" id="dropdownMenu1" data-toggle="dropdown">
|
||||
<i class="fa fa-cogs"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu pull-right" role="menu" aria-labelledby="dropdownMenu1">
|
||||
<li><a href="#">Action</a></li>
|
||||
<li><a href="#">Another action</a></li>
|
||||
<li><a href="#">Something else here</a></li>
|
||||
<li class="divider"></li>
|
||||
<li><a href="#">Separated link</a></li>
|
||||
</ul>
|
||||
<a href="#" class="widget-popout hidden tt" title="Pop Out/In"><i class="icon-publish"></i></a>
|
||||
<a href="#" class="widget-maximize hidden"><i class="icon-resize-full-1"></i></a>
|
||||
<a href="#" class="widget-toggle"><i class="icon-down-open-2"></i></a>
|
||||
<a href="#" class="widget-close"><i class="icon-cancel-3"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="widget-content">
|
||||
<div id="website-statistic2" class="statistic-chart">
|
||||
|
||||
<div class="col-sm-12 stacked">
|
||||
<h4><i class="fa fa-circle-o text-green-1"></i> Server Loads</h4>
|
||||
<div class="col-sm-8 status-data">
|
||||
|
||||
<div class="col-xs-12">
|
||||
<div class="row stacked">
|
||||
<div class="col-xs-4 text-center right-border">
|
||||
Processes<br>
|
||||
<span class="animate-number" data-value="322" data-duration="3000">0</span>
|
||||
</div>
|
||||
<div class="col-xs-4 text-center right-border">
|
||||
Connections<br>
|
||||
<span class="animate-number" data-value="4789" data-duration="3000">0</span>
|
||||
</div>
|
||||
<div class="col-xs-4 text-center">
|
||||
Avg. Load<br>
|
||||
<span class="animate-number" data-value="76" data-duration="3000">0</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
<div class="progress progress-xs">
|
||||
<div style="width: 72%" aria-valuemax="100" aria-valuemin="0" aria-valuenow="72" role="progressbar" class="progress-bar bg-orange-2" title="Average Load: 76%" data-placement="right" data-toggle="tooltip">
|
||||
<span class="sr-only">72% Complete (success)</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-4 text-center">
|
||||
<div class="ws-load echart" data-percent="50"><span class="percent"></span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
<div id="home-chart-2"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-8 portlets">
|
||||
<div class="widget">
|
||||
<div class="widget-header">
|
||||
<h2><i class="icon-chart-pie-1"></i> <strong>Sales</strong> Report</h2>
|
||||
<div class="additional-btn">
|
||||
<a href="#" class="hidden reload"><i class="icon-ccw-1"></i></a>
|
||||
<a class="hidden" id="dropdownMenu1" data-toggle="dropdown">
|
||||
<i class="fa fa-cogs"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu pull-right" role="menu" aria-labelledby="dropdownMenu1">
|
||||
<li><a href="#">Action</a></li>
|
||||
<li><a href="#">Another action</a></li>
|
||||
<li><a href="#">Something else here</a></li>
|
||||
<li class="divider"></li>
|
||||
<li><a href="#">Separated link</a></li>
|
||||
</ul>
|
||||
<a href="#" class="widget-popout hidden tt" title="Pop Out/In"><i class="icon-publish"></i></a>
|
||||
<a href="#" class="widget-maximize hidden"><i class="icon-resize-full-1"></i></a>
|
||||
<a href="#" class="widget-toggle"><i class="icon-down-open-2"></i></a>
|
||||
<a href="#" class="widget-close"><i class="icon-cancel-3"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="widget-content">
|
||||
<div class="row stacked">
|
||||
<div class="col-sm-5 mini-stats">
|
||||
<div id="morris-bar-home" class="morris-chart" style="height: 170px;"></div>
|
||||
<div class="sales-report-data">
|
||||
<span class="pull-left">Completed Sales</span><span class="pull-right">65 / 174</span>
|
||||
<div class="progress progress-xs">
|
||||
<div style="width: 38%;" class="progress-bar bg-blue-1"></div>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
<span class="pull-left">Return(s) Processed</span><span class="pull-right">22 / 25</span>
|
||||
<div class="progress progress-xs">
|
||||
<div style="width: 88%;" class="progress-bar bg-lightblue-1"></div>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
<span class="pull-left">Shipped Products</span><span class="pull-right">418 / 624</span>
|
||||
<div class="progress progress-xs">
|
||||
<div style="width: 58%;" class="progress-bar"></div>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
<span class="pull-left">Overall Product Stock</span><span class="pull-right">19%</span>
|
||||
<div class="progress progress-xs">
|
||||
<div style="width: 19%;" class="progress-bar bg-pink-1"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-7">
|
||||
<div id="vector-map" style="height:370px"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
<div id="sales-report" class="collapse in hidden-xs">
|
||||
<div class="table-responsive">
|
||||
<table data-sortable class="table table-striped">
|
||||
<thead>
|
||||
<tr><th width="70">No</th><th data-sortable="false" width="40"><input type="checkbox" id="select-all-rows"></th><th width="120">Order ID</th><th>Buyer</th><th width="100">Status</th><th width="150">Location</th><th width="120">Total</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td>1</td><td><input type="checkbox" class="rows-check"></td><td>#0021</td><td><a href="#">John Doe</a></td><td><span class="label label-primary">Order</span></td><td>Yogyakarta, ID</td><td><strong class="text-primary">$ 1,245</strong></td></tr>
|
||||
<tr><td>2</td><td><input type="checkbox" class="rows-check"></td><td>#0022</td><td><a href="#">Johnny Depp</a></td><td><span class="label label-success">Payment</span></td><td>London, UK</td><td><strong class="text-success">$ 1,245</strong></td></tr>
|
||||
<tr><td>3</td><td><input type="checkbox" class="rows-check"></td><td>#0023</td><td><a href="#">Scarlett Johansson</a></td><td><span class="label label-success">Payment</span></td><td>Canbera, AU</td><td><strong class="text-success">$ 1,245</strong></td></tr>
|
||||
<tr><td>4</td><td><input type="checkbox" class="rows-check"></td><td>#0024</td><td><a href="#">Hanna Barbara</a></td><td><span class="label label-danger">Cancel</span></td><td>Bali, ID</td><td><strong class="text-danger">$ 1,245</strong></td></tr>
|
||||
<tr><td>5</td><td><input type="checkbox" class="rows-check"></td><td>#0025</td><td><a href="#">Ali Larter</a></td><td><span class="label label-primary">Order</span></td><td>Bandung, ID</td><td><strong class="text-primary">$ 1,245</strong></td></tr>
|
||||
<tr><td>6</td><td><input type="checkbox" class="rows-check"></td><td>#0026</td><td><a href="#">Willy Wonka</a></td><td><span class="label label-danger">Cancel</span></td><td>Semarang, ID</td><td><strong class="text-danger">$ 1,245</strong></td></tr>
|
||||
<tr><td>7</td><td><input type="checkbox" class="rows-check"></td><td>#0027</td><td><a href="#">Chris Isaac</a></td><td><span class="label label-warning">Waiting</span></td><td>New York, US</td><td><strong class="text-warning">$ 1,245</strong></td></tr>
|
||||
<tr><td>8</td><td><input type="checkbox" class="rows-check"></td><td>#0028</td><td><a href="#">Jenny Doe</a></td><td><span class="label label-primary">Order</span></td><td>Boston, US</td><td><strong class="text-primary">$ 1,245</strong></td></tr>
|
||||
<tr><td>9</td><td><input type="checkbox" class="rows-check"></td><td>#0029</td><td><a href="#">Ban ki moon</a></td><td><span class="label label-danger">Cancel</span></td><td>Boston, US</td><td><strong class="text-danger">$ 1,245</strong></td></tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4 portlets">
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div id="todo-app" class="widget">
|
||||
<div class="widget-header centered">
|
||||
<div class="left-btn"><a class="btn btn-sm btn-default add-todo"><i class="fa fa-plus"></i></a></div>
|
||||
<h2>Todo List</h2>
|
||||
<div class="additional-btn">
|
||||
<a href="#" class="hidden reload"><i class="icon-ccw-1"></i></a>
|
||||
<a href="#" class="widget-popout hidden tt" title="Pop Out/In"><i class="icon-publish"></i></a>
|
||||
<a href="#" class="widget-maximize hidden"><i class="icon-resize-full-1"></i></a>
|
||||
<a href="#" class="widget-toggle"><i class="icon-down-open-2"></i></a>
|
||||
<a href="#" class="widget-close"><i class="icon-cancel-3"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="widget-content padding-sm">
|
||||
<ul class="todo-list">
|
||||
<li>
|
||||
<span class="check-icon"><input type="checkbox" /></span>
|
||||
<span class="todo-item">Generate monthly sales report for John</span>
|
||||
<span class="todo-options pull-right">
|
||||
<a href="javascript:;" class="todo-delete"><i class="icon-cancel-3"></i></a>
|
||||
</span>
|
||||
<span class="todo-tags pull-right">
|
||||
<div class="label label-success">New</div>
|
||||
</span>
|
||||
</li>
|
||||
<li class="high">
|
||||
<span class="check-icon"><input type="checkbox" /></span>
|
||||
<span class="todo-item">Mail those reports to John</span>
|
||||
<span class="todo-options pull-right">
|
||||
<a href="javascript:;" class="todo-delete"><i class="icon-cancel-3"></i></a>
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<span class="check-icon"><input type="checkbox" /></span>
|
||||
<span class="todo-item">Don't forget to send those reports to John</span>
|
||||
<span class="todo-options pull-right">
|
||||
<a href="javascript:;" class="todo-delete"><i class="icon-cancel-3"></i></a>
|
||||
</span>
|
||||
</li>
|
||||
<li class="medium">
|
||||
<span class="check-icon"><input type="checkbox" /></span>
|
||||
<span class="todo-item">If you forgot, go back to office to pick them up</span>
|
||||
<span class="todo-options pull-right">
|
||||
<a href="javascript:;" class="todo-delete"><i class="icon-cancel-3"></i></a>
|
||||
</span>
|
||||
<span class="todo-tags pull-right">
|
||||
<div class="label label-info">Today</div>
|
||||
</span>
|
||||
</li>
|
||||
<li class="low">
|
||||
<span class="check-icon"><input type="checkbox" /></span>
|
||||
<span class="todo-item">Deliver reports by hand to John</span>
|
||||
<span class="todo-options pull-right">
|
||||
<a href="javascript:;" class="todo-delete"><i class="icon-cancel-3"></i></a>
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<span class="check-icon"><input type="checkbox" /></span>
|
||||
<span class="todo-item">Say John that you are sorry</span>
|
||||
<span class="todo-options pull-right">
|
||||
<a href="javascript:;" class="todo-delete"><i class="icon-cancel-3"></i></a>
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<span class="check-icon"><input type="checkbox" /></span>
|
||||
<span class="todo-item">Beg for your job...</span>
|
||||
<span class="todo-options pull-right">
|
||||
<a href="javascript:;" class="todo-delete"><i class="icon-cancel-3"></i></a>
|
||||
</span>
|
||||
<span class="todo-tags pull-right">
|
||||
<div class="label label-danger">Important</div>
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<span class="check-icon"><input type="checkbox" /></span>
|
||||
<span class="todo-item">Look for a new job</span>
|
||||
<span class="todo-options pull-right">
|
||||
<a href="javascript:;" class="todo-delete"><i class="icon-cancel-3"></i></a>
|
||||
</span>
|
||||
<span class="todo-tags pull-right">
|
||||
<div class="label label-warning"><i class="icon-search"></i></div>
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div id="notes-app" class="widget">
|
||||
<div class="notes-line"></div>
|
||||
<div class="widget-header centered transparent">
|
||||
<div class="left-btn btn-group"><a class="btn btn-sm btn-primary add-note"><i class="fa fa-plus"></i></a><a class="btn btn-sm btn-primary back-note-list"><i class="icon-align-justify"></i></a></div>
|
||||
<h2>Notes</h2>
|
||||
<div class="additional-btn">
|
||||
<a href="#" class="hidden reload"><i class="icon-ccw-1"></i></a>
|
||||
<a href="#" class="widget-popout hidden tt" title="Pop Out/In"><i class="icon-publish"></i></a>
|
||||
<a href="#" class="widget-maximize hidden"><i class="icon-resize-full-1"></i></a>
|
||||
<a href="#" class="widget-toggle"><i class="icon-down-open-2"></i></a>
|
||||
<a href="#" class="widget-close"><i class="icon-cancel-3"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="widget-content padding-sm">
|
||||
<div id="notes-list">
|
||||
<div class="scroller">
|
||||
<ul class="list-unstyled">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div id="note-data">
|
||||
<form>
|
||||
<textarea class="form-control" id="note-text" placeholder="Your note..."></textarea>
|
||||
</form>
|
||||
</div>
|
||||
<div class="status-indicator">Saved</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-4 col-md-6 portlets">
|
||||
<div id="weather-widget" class="widget">
|
||||
<div class="widget-header transparent">
|
||||
<h2><strong>Weather</strong> Widget</h2>
|
||||
<div class="additional-btn">
|
||||
<a href="#" class="hidden reload"><i class="icon-ccw-1"></i></a>
|
||||
<a class="hidden" id="dropdownMenu1" data-toggle="dropdown">
|
||||
<i class="fa fa-cogs"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu pull-right" role="menu" aria-labelledby="dropdownMenu1">
|
||||
<li><a href="#">Action</a></li>
|
||||
<li><a href="#">Another action</a></li>
|
||||
<li><a href="#">Something else here</a></li>
|
||||
<li class="divider"></li>
|
||||
<li><a href="#">Separated link</a></li>
|
||||
</ul>
|
||||
<a href="#" class="widget-popout hidden tt" title="Pop Out/In"><i class="icon-publish"></i></a>
|
||||
<a href="#" class="widget-maximize hidden"><i class="icon-resize-full-1"></i></a>
|
||||
<a href="#" class="widget-toggle"><i class="icon-down-open-2"></i></a>
|
||||
<a href="#" class="widget-close"><i class="icon-cancel-3"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<div id="weather" class="widget-content">
|
||||
|
||||
</div><i class="wi-day-rain-mix"></i>
|
||||
<button class="js-geolocation btn btn-sm btn-default" style="display: none;">Use Your Location</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-4 col-md-6 portlets">
|
||||
<div id="calendar-widget2" class="widget blue-1">
|
||||
<div class="widget-header transparent">
|
||||
<h2><strong>Calendar</strong> Widget</h2>
|
||||
<div class="additional-btn">
|
||||
<a href="#" class="hidden reload"><i class="icon-ccw-1"></i></a>
|
||||
<a href="#" class="widget-popout hidden tt" title="Pop Out/In"><i class="icon-publish"></i></a>
|
||||
<a href="#" class="widget-toggle"><i class="icon-down-open-2"></i></a>
|
||||
<a href="#" class="widget-close"><i class="icon-cancel-3"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<div id="calendar-box2" class="widget-content col-sm-12">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4 col-md-6 portlets">
|
||||
<div id="calc" class="widget darkblue-2">
|
||||
<div class="widget-header">
|
||||
<div class="additional-btn left-toolbar">
|
||||
<div class="btn-group">
|
||||
<a class="additional-icon" id="dropdownMenu2" data-toggle="dropdown">
|
||||
Calculator <i class="fa fa-angle-down"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu2">
|
||||
<li><a href="#">Save</a></li>
|
||||
<li><a href="#">Export</a></li>
|
||||
<li class="divider"></li>
|
||||
<li><a href="#">Quit</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="additional-btn">
|
||||
<a href="#" class="hidden reload"><i class="icon-ccw-1"></i></a>
|
||||
|
||||
<a href="#" class="widget-popout hidden tt" title="Pop Out/In"><i class="icon-publish"></i></a>
|
||||
<a href="#" class="widget-close"><i class="icon-cancel-3"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<div id="calculator" class="widget-content">
|
||||
<div class="calc-top col-xs-12">
|
||||
<div class="row">
|
||||
<div class="col-xs-3"><span class="calc-clean">C</span></div>
|
||||
<div class="col-xs-9"><div class="calc-screen"></div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="calc-keys col-xs-12">
|
||||
<div class="row">
|
||||
<div class="col-xs-3"><span>7</span></div>
|
||||
<div class="col-xs-3"><span>8</span></div>
|
||||
<div class="col-xs-3"><span>9</span></div>
|
||||
<div class="col-xs-3"><span class="calc-operator">+</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-3"><span>4</span></div>
|
||||
<div class="col-xs-3"><span>5</span></div>
|
||||
<div class="col-xs-3"><span>6</span></div>
|
||||
<div class="col-xs-3"><span class="calc-operator">-</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-3"><span>1</span></div>
|
||||
<div class="col-xs-3"><span>2</span></div>
|
||||
<div class="col-xs-3"><span>3</span></div>
|
||||
<div class="col-xs-3"><span class="calc-operator">÷</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-3"><span>0</span></div>
|
||||
<div class="col-xs-3"><span>.</span></div>
|
||||
<div class="col-xs-3"><span class="calc-eval">=</span></div>
|
||||
<div class="col-xs-3"><span class="calc-operator">x</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-8 col-md-6 portlets">
|
||||
|
||||
</div>
|
||||
<div class="col-lg-4 col-md-6 portlets">
|
||||
<div id="stock-app" class="widget green-3">
|
||||
<div class="widget-header transparent">
|
||||
<h2><strong>Stock</strong> Markets</h2>
|
||||
<div class="additional-btn">
|
||||
<a href="#" class="hidden reload"><i class="icon-ccw-1"></i></a>
|
||||
<a class="hidden" id="dropdownMenu1" data-toggle="dropdown">
|
||||
<i class="fa fa-cogs"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu pull-right" role="menu" aria-labelledby="dropdownMenu1">
|
||||
<li><a href="#">Action</a></li>
|
||||
<li><a href="#">Another action</a></li>
|
||||
<li><a href="#">Something else here</a></li>
|
||||
<li class="divider"></li>
|
||||
<li><a href="#">Separated link</a></li>
|
||||
</ul>
|
||||
<a href="#" class="widget-popout hidden tt" title="Pop Out/In"><i class="icon-publish"></i></a>
|
||||
<a href="#" class="widget-maximize hidden"><i class="icon-resize-full-1"></i></a>
|
||||
<a href="#" class="widget-toggle"><i class="icon-down-open-2"></i></a>
|
||||
<a href="#" class="widget-close"><i class="icon-cancel-3"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="widget-content">
|
||||
<div id="website-statistic3" class="statistic-chart">
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<h2>NASDAQ</h2>
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<label id="nasdaq-status" class="stock-status"></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<h2>DOW JONES</h2>
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<label id="dow-status" class="stock-status"></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<h2>S&P</h2>
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<label id="sp-status" class="stock-status"></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="home-chart-3"></div>
|
||||
</div>
|
||||
<div class="widget-footer">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Footer Start -->
|
||||
<footer>
|
||||
Huban Creative © 2014
|
||||
<div class="footer-links pull-right">
|
||||
<a href="#">About</a><a href="#">Support</a><a href="#">Terms of Service</a><a href="#">Legal</a><a href="#">Help</a><a href="#">Contact Us</a>
|
||||
</div>
|
||||
</footer>
|
||||
<!-- Footer End -->
|
||||
</div>
|
||||
<!-- ============================================================== -->
|
||||
<!-- End content here -->
|
||||
<!-- ============================================================== -->
|
||||
|
||||
</div>
|
||||
<!-- End right content -->
|
@ -0,0 +1,13 @@
|
||||
wb = xlsx_package.workbook
|
||||
wb.add_worksheet(name: '统计总表') do |sheet|
|
||||
sheet.add_row %w(ID 单位名称 教师总人数 学生总人数 课堂总数 正在进行课堂数 总实训数 实训评测总数 实训作业总数 其它作业总数 动态时间)
|
||||
|
||||
@schools.each do |school|
|
||||
sheet.add_row([
|
||||
school[:id].to_s, school[:name].to_s, (school[:teacher_count] || 0).to_s, (school[:student_count] || 0).to_s,
|
||||
(school[:course_count] || 0).to_s, (school[:active_course_count] || 0).to_s,
|
||||
(school[:shixun_count] || 0).to_s,(school[:shixun_evaluate_count] || 0).to_s, (school[:homework_count] || 0).to_s,
|
||||
(school[:other_homework_count] || 0).to_s, format_time(school[:nearly_course_time])
|
||||
])
|
||||
end
|
||||
end
|
@ -0,0 +1,29 @@
|
||||
<% define_admin_breadcrumbs do %>
|
||||
<% add_admin_breadcrumb('统计总表', admins_daily_school_statistics_path) %>
|
||||
<% end %>
|
||||
|
||||
<div class="box search-form-container daily-school-statistic-list-form">
|
||||
<%= form_tag(admins_daily_school_statistics_path, method: :get, class: 'form-inline search-form', remote: true) do %>
|
||||
<%= text_field_tag(:keyword, params[:keyword], class: 'form-control col-sm-2 ml-3', placeholder: 'ID/单位名称搜索') %>
|
||||
<%= submit_tag('搜索', class: 'btn btn-primary ml-3') %>
|
||||
<% end %>
|
||||
|
||||
<%#= link_to '导出Excel', export_admins_daily_school_statistics_path(format: :xlsx), class: 'btn btn-outline-primary export-action' %>
|
||||
<%= javascript_void_link '导出Excel', class: 'btn btn-outline-primary export-action', 'data-url': export_admins_daily_school_statistics_path(format: :xlsx) %>
|
||||
</div>
|
||||
|
||||
<div class="box py-0 pt-4 pl-4">
|
||||
统计总计:
|
||||
教师总人数<span class="text-danger"><%= @teacher_total %></span>人,
|
||||
学生总人数<span class="text-danger"><%= @student_total %></span>人,
|
||||
课堂总数<span class="text-danger"><%= @course_total %></span>个,
|
||||
正在进行课堂总数<span class="text-danger"><%= @active_course_total %></span>个,
|
||||
实训总数<span class="text-danger"><%= @shixun_total %></span>个,
|
||||
实训评测总数<span class="text-danger"><%= @shixun_evaluate_total %></span>个,
|
||||
实训作业总数<span class="text-danger"><%= @shixun_homework_total %></span>个,
|
||||
其它作业总数<span class="text-danger"><%= @other_homework_total %></span>个
|
||||
</div>
|
||||
|
||||
<div class="box daily-school-statistic-list-container">
|
||||
<%= render partial: 'admins/daily_school_statistics/shared/list', locals: { statistics: @statistics } %>
|
||||
</div>
|
@ -0,0 +1 @@
|
||||
$(".daily-school-statistic-list-container").html("<%= j(render partial: 'admins/daily_school_statistics/shared/list', locals: { statistics: @statistics }) %>")
|
@ -0,0 +1,46 @@
|
||||
<table class="table table-hover daily-school-statistic-list-table">
|
||||
<thead class="thead-light">
|
||||
<tr>
|
||||
<th width="18%" class="edu-txt-left">单位名称</th>
|
||||
|
||||
<th width="10%"><%= sort_tag('教师总人数', name: 'teacher_count', path: admins_daily_school_statistics_path) %></th>
|
||||
<th width="10%"><%= sort_tag('学生总人数', name: 'student_count', path: admins_daily_school_statistics_path) %></th>
|
||||
<th width="10%"><%= sort_tag('课堂总数', name: 'course_count', path: admins_daily_school_statistics_path) %></th>
|
||||
<th width="10%"><%= sort_tag('正在进行课堂数', name: 'active_course_count', path: admins_daily_school_statistics_path) %></th>
|
||||
<th width="10%"><%= sort_tag('实训总数', name: 'shixun_count', path: admins_daily_school_statistics_path) %></th>
|
||||
<th width="12%">
|
||||
<%= sort_tag('实训评测总数', name: 'shixun_evaluate_count', path: admins_daily_school_statistics_path) %>
|
||||
<i class="fa fa-question-circle" data-toggle="tooltip" data-html="true" data-placement="top" title="数据更新时间为<br/>当日6点、12点、18点、24点"></i>
|
||||
</th>
|
||||
<th width="10%"><%= sort_tag('实训作业总数', name: 'homework_count', path: admins_daily_school_statistics_path) %></th>
|
||||
<th width="10%"><%= sort_tag('其它作业总数', name: 'other_homework_count', path: admins_daily_school_statistics_path) %></th>
|
||||
<th width="14%"><%= sort_tag('动态时间', name: 'nearly_course_time', path: admins_daily_school_statistics_path) %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% if statistics.present? %>
|
||||
<% statistics.each do |statistic| %>
|
||||
<tr>
|
||||
<td class="edu-txt-left">
|
||||
<%= link_to '#' do %>
|
||||
<%= overflow_hidden_span statistic[:name], width: '200px' %>
|
||||
<% end %>
|
||||
</td>
|
||||
<td><%= statistic[:teacher_count].to_i %></td>
|
||||
<td><%= statistic[:student_count].to_i %></td>
|
||||
<td><%= statistic[:course_count].to_i %></td>
|
||||
<td><%= statistic[:active_course_count].to_i %></td>
|
||||
<td><%= statistic[:shixun_count].to_i %></td>
|
||||
<td><%= statistic[:shixun_evaluate_count].to_i %></td>
|
||||
<td><%= statistic[:homework_count].to_i %></td>
|
||||
<td><%= statistic[:other_homework_count].to_i %></td>
|
||||
<td><%= statistic[:nearly_course_time]&.strftime('%Y-%m-%d %H:%M') %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<%= render 'admins/shared/no_data_for_table' %>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<%= render partial: 'admins/shared/paginate', locals: { objects: statistics } %>
|
@ -0,0 +1,188 @@
|
||||
<% define_admin_breadcrumbs do %>
|
||||
<% add_admin_breadcrumb('概览', admins_path) %>
|
||||
<% end %>
|
||||
|
||||
<div class="header bg-gradient-primary pb-8 pt-md-8">
|
||||
<div class="container-fluid">
|
||||
<div class="header-body">
|
||||
<!-- Card stats -->
|
||||
<div class="row">
|
||||
<div class="col-xl-3 col-lg-6">
|
||||
<div class="card card-stats mb-4 mb-xl-0">
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h5 class="card-title text-uppercase text-muted mb-0">Traffic</h5>
|
||||
<span class="h2 font-weight-bold mb-0">350,897</span>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<div class="icon icon-shape bg-danger text-white rounded-circle shadow">
|
||||
<i class="fas fa-pie-chart"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="mt-3 mb-0 text-muted text-sm">
|
||||
<span class="text-success mr-2"><i class="fa fa-arrow-up"></i> 3.48%</span>
|
||||
<span class="text-nowrap">Since last month</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-lg-6">
|
||||
<div class="card card-stats mb-4 mb-xl-0">
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h5 class="card-title text-uppercase text-muted mb-0">New users</h5>
|
||||
<span class="h2 font-weight-bold mb-0">2,356</span>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<div class="icon icon-shape bg-warning text-white rounded-circle shadow">
|
||||
<i class="fas fa-pie-chart"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="mt-3 mb-0 text-muted text-sm">
|
||||
<span class="text-danger mr-2"><i class="fas fa-arrow-down"></i> 3.48%</span>
|
||||
<span class="text-nowrap">Since last week</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-lg-6">
|
||||
<div class="card card-stats mb-4 mb-xl-0">
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h5 class="card-title text-uppercase text-muted mb-0">Sales</h5>
|
||||
<span class="h2 font-weight-bold mb-0">924</span>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<div class="icon icon-shape bg-yellow text-white rounded-circle shadow">
|
||||
<i class="fas fa-user"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="mt-3 mb-0 text-muted text-sm">
|
||||
<span class="text-warning mr-2"><i class="fas fa-arrow-down"></i> 1.10%</span>
|
||||
<span class="text-nowrap">Since yesterday</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-lg-6">
|
||||
<div class="card card-stats mb-4 mb-xl-0">
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h5 class="card-title text-uppercase text-muted mb-0">Performance</h5>
|
||||
<span class="h2 font-weight-bold mb-0">49,65%</span>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<div class="icon icon-shape bg-info text-white rounded-circle shadow">
|
||||
<i class="fas fa-pie-chart"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="mt-3 mb-0 text-muted text-sm">
|
||||
<span class="text-success mr-2"><i class="fas fa-arrow-up"></i> 12%</span>
|
||||
<span class="text-nowrap">Since last month</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container-fluid mt--7">
|
||||
<div class="row mt-5">
|
||||
<div class="col-xl-8 mb-5 mb-xl-0">
|
||||
<div class="card shadow">
|
||||
<div class="card-header border-0">
|
||||
<div class="row align-items-center">
|
||||
<div class="col">
|
||||
<h3 class="mb-0">Page visits</h3>
|
||||
</div>
|
||||
<div class="col text-right">
|
||||
<a href="#!" class="btn btn-sm btn-primary">Test</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<!-- Projects table -->
|
||||
<table class="table align-items-center table-flush">
|
||||
<thead class="thead-light">
|
||||
<tr>
|
||||
<th scope="col">Test</th>
|
||||
<th scope="col">Test</th>
|
||||
<th scope="col">Test</th>
|
||||
<th scope="col">Test</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% 5.times do %>
|
||||
<tr>
|
||||
<th scope="row">/test/</th>
|
||||
<td>4,569</td>
|
||||
<td>340</td>
|
||||
<td>
|
||||
<i class="fas fa-arrow-up text-success mr-3"></i> 46,53%
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-4">
|
||||
<div class="card shadow">
|
||||
<div class="card-header border-0">
|
||||
<div class="row align-items-center">
|
||||
<div class="col">
|
||||
<h3 class="mb-0">Test</h3>
|
||||
</div>
|
||||
<div class="col text-right">
|
||||
<a href="#!" class="btn btn-sm btn-primary">Test</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<!-- Projects table -->
|
||||
<table class="table align-items-center table-flush">
|
||||
<thead class="thead-light">
|
||||
<tr>
|
||||
<th scope="col">Test</th>
|
||||
<th scope="col">Test</th>
|
||||
<th scope="col"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% 5.times do %>
|
||||
<tr>
|
||||
<th scope="row">
|
||||
Test
|
||||
</th>
|
||||
<td>
|
||||
1,480
|
||||
</td>
|
||||
<td>
|
||||
<div class="d-flex align-items-center">
|
||||
<span class="mr-2">60%</span>
|
||||
<div>
|
||||
<div class="progress">
|
||||
<div class="progress-bar bg-gradient-danger" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100" style="width: 60%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -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 @@
|
||||
$(".school-statistic-list-container").html("<%= j(render partial: 'admins/school_statistics/shared/contrast_list', locals: { statistics: @statistics, select_options: @select_options }) %>")
|
@ -0,0 +1 @@
|
||||
$(".school-statistic-list-container").html("<%= j(render partial: 'admins/school_statistics/shared/list', locals: { statistics: @statistics }) %>")
|
@ -0,0 +1,6 @@
|
||||
<div class="d-flex flex-column align-items-center justify-content-center global-error">
|
||||
<div class="global-error-code">
|
||||
<span>404</span>
|
||||
</div>
|
||||
<div class="global-error-text">资源未找到</div>
|
||||
</div>
|
@ -0,0 +1,6 @@
|
||||
<div class="d-flex flex-column align-items-center justify-content-center global-error">
|
||||
<div class="global-error-code">
|
||||
<span>422</span>
|
||||
</div>
|
||||
<div class="global-error-text"><%= @message %></div>
|
||||
</div>
|
@ -0,0 +1,6 @@
|
||||
<div class="d-flex flex-column align-items-center justify-content-center global-error">
|
||||
<div class="global-error-code">
|
||||
<span>500</span>
|
||||
</div>
|
||||
<div class="global-error-text">系统错误</div>
|
||||
</div>
|
@ -0,0 +1,6 @@
|
||||
<div class="alert alert-danger alert-dismissible fade show" role="alert">
|
||||
<%= message %>
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
@ -0,0 +1,13 @@
|
||||
<% if @_admin_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 %>
|
||||
<li class="breadcrumb-item"><%= link_to item.text, item.url %></li>
|
||||
<% else %>
|
||||
<li class="breadcrumb-item active" aria-current="page"><%= item.text %></li>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</ol>
|
||||
</nav>
|
||||
<% end %>
|
@ -0,0 +1,20 @@
|
||||
<% flash.each do |k, v| %>
|
||||
<% next unless %w(success danger warning info).include?(k.to_s) %>
|
||||
|
||||
<div class="alert alert-<%= k %> alert-dismissible fade show" role="alert">
|
||||
<%= v %>
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<% end %>
|
||||
<% flash.now.as_json.each do |k, v| %>
|
||||
<% next unless %w(success danger warning info).include?(k.to_s) %>
|
||||
|
||||
<div class="alert alert-<%= k %> alert-dismissible fade show" role="alert">
|
||||
<%= v %>
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<% end %>
|
@ -0,0 +1 @@
|
||||
<tr class="no-data"><td colspan="100">暂无数据</td></tr>
|
@ -0,0 +1,6 @@
|
||||
<div class="paginate-container">
|
||||
<% if objects.size.nonzero? %>
|
||||
<div class="paginate-total"><%= page_entries_info objects %></div>
|
||||
<% end %>
|
||||
<%= paginate objects, views_prefix: 'admins', remote: true %>
|
||||
</div>
|
@ -0,0 +1,42 @@
|
||||
<% sidebar_collapse = request.cookies['admin_sidebar_collapse'].to_s == 'true' %>
|
||||
<nav id="sidebar" class="<%= sidebar_collapse ? 'active' : '' %>" data-current-controller="<%= admin_sidebar_controller %>">
|
||||
<div class="sidebar-header">
|
||||
<a href="/" class="sidebar-header-logo" data-toggle="tooltip" title="返回主站">
|
||||
<%= image_tag('logo.png') %>
|
||||
</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(admins_path, '概览', icon: 'dashboard', controller: 'admins-dashboards') %></li>
|
||||
<li>
|
||||
<%= sidebar_item_group('#school-submenu', '学校统计', icon: 'area-chart') do %>
|
||||
<li><%= sidebar_item(admins_daily_school_statistics_path, '统计总表', icon: 'bar-chart', controller: 'admins-daily_school_statistics') %></li>
|
||||
<li><%= sidebar_item(admins_school_statistics_path, '数据变化报表', icon: 'line-chart', controller: 'admins-school_statistics') %></li>
|
||||
<% end %>
|
||||
</li>
|
||||
|
||||
<!-- <li>-->
|
||||
<%#= sidebar_item_group('#course-submenu', '课堂+', icon: 'mortar-board') do %>
|
||||
<!-- <li><%#= sidebar_item('#', '课程列表', icon: 'calendar', controller: '') %></li>-->
|
||||
<!-- <li><%#= sidebar_item('#', '课堂列表', icon: 'book', controller: '') %></li>-->
|
||||
<!-- <li><%#= sidebar_item('#', '实训作业', icon: 'file-code-o', controller: '') %></li>-->
|
||||
<!-- <li><%#= sidebar_item('#', '项目列表', icon: 'sitemap', controller: '') %></li>-->
|
||||
<%# end %>
|
||||
<!-- </li>-->
|
||||
|
||||
<li>
|
||||
<%= sidebar_item_group('#user-submenu', '用户', icon: 'user') do %>
|
||||
<li><%= sidebar_item(admins_users_path, '用户列表', icon: 'user', controller: 'admins-users') %></li>
|
||||
<!-- <li><%#= sidebar_item('#', '试用授权列表', icon: 'id-card-o', controller: '') %></li>-->
|
||||
<!-- <li><%#= sidebar_item('#', '自动授权列表', icon: 'id-card', controller: '') %></li>-->
|
||||
<% end %>
|
||||
</li>
|
||||
|
||||
<li><%= sidebar_item('/', '返回主站', icon: 'sign-out', controller: 'root') %></li>
|
||||
</ul>
|
||||
</nav>
|
@ -0,0 +1,20 @@
|
||||
var deleteRow = $('<%= params[:element] %>');
|
||||
var refreshUrl = '<%= params[:refresh_url] %>';
|
||||
|
||||
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);
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
$('.admin-alert-container').html('<%= j( render partial: 'admins/shared/alert', locals: { message: message } ) %>');
|
||||
|
||||
setTimeout(function() {
|
||||
if ($('.admin-alert-container button.close').length > 0) {
|
||||
$('.admin-alert-container button.close').trigger('click');
|
||||
}
|
||||
}, 2000)
|
@ -0,0 +1,137 @@
|
||||
<%
|
||||
define_admin_breadcrumbs do
|
||||
add_admin_breadcrumb('用户管理', admins_users_path)
|
||||
add_admin_breadcrumb('用户详情')
|
||||
end
|
||||
%>
|
||||
|
||||
<div class="box user-edit-container">
|
||||
<div class="user-info mb-4 row">
|
||||
<%= link_to "/users/#{@user.login}", class: 'user-info-avatar col-md-1', target: '_blank', data: { toggle: 'tooltip', title: '个人中心' } do %>
|
||||
<img src="/images/<%= url_to_avatar(@user) %>" class="rounded-circle" width="80" height="80" />
|
||||
<% end %>
|
||||
<div class="d-flex flex-column justify-content-between col-md-3 user-info-content">
|
||||
<div class="user-info-name flex"><%= @user.real_name %> | <%= @user.id %> | <%= @user.login %></div>
|
||||
|
||||
<div class="d-flex flex-row user-info-auth">
|
||||
<% if @user.authentication? %>
|
||||
<i class="fa fa-user text-success" data-toggle="tooltip" data-placement="bottom" title="已实名认证"></i>
|
||||
<% elsif @user.process_real_name_apply.present? %>
|
||||
<i class="fa fa-user text-danger" data-toggle="tooltip" data-placement="bottom" title="实名认证中"></i>
|
||||
<% else %>
|
||||
<i class="fa fa-user text-muted" data-toggle="tooltip" data-placement="bottom" title="未实名认证"></i>
|
||||
<% end %>
|
||||
|
||||
<% if @user.professional_certification %>
|
||||
<i class="fa fa-list-alt text-success" data-toggle="tooltip" data-placement="bottom" title="已职业认证"></i>
|
||||
<% elsif @user.process_professional_apply.present? %>
|
||||
<i class="fa fa-list-alt text-danger" data-toggle="tooltip" data-placement="bottom" title="职业认证中"></i>
|
||||
<% else %>
|
||||
<i class="fa fa-list-alt text-muted" data-toggle="tooltip" data-placement="bottom" title="未职业认证"></i>
|
||||
<% end %>
|
||||
|
||||
<% if @user.phone.present? %>
|
||||
<i class="fa fa-mobile text-success" data-toggle="tooltip" data-placement="bottom" title="已绑定手机"></i>
|
||||
<% else %>
|
||||
<i class="fa fa-mobile text-muted" data-toggle="tooltip" data-placement="bottom" title="未绑定手机"></i>
|
||||
<% end %>
|
||||
|
||||
<% if @user.mail.present? %>
|
||||
<i class="fa fa-envelope text-success" data-toggle="tooltip" data-placement="bottom" title="已绑定邮箱"></i>
|
||||
<% else %>
|
||||
<i class="fa fa-envelope text-muted" data-toggle="tooltip" data-placement="bottom" title="未绑定邮箱"></i>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="user-info-last-login">最近登录:<%= @user.last_login_on&.strftime('%Y-%m-%d %H:%M') %></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%= simple_form_for(@user, url: admins_user_path(@user)) do |f| %>
|
||||
|
||||
<div><h6>基本信息</h6></div>
|
||||
<div class="form-group px-2">
|
||||
<div class="form-row">
|
||||
<%= f.input :lastname, label: '姓名', wrapper_html: { class: 'col-md-3' }, input_html: { class: 'col-md-11', value: @user.only_real_name } %>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<%= f.input :nickname, label: '昵称', wrapper_html: { class: 'col-md-3' }, input_html: { class: 'col-md-11' } %>
|
||||
<%= f.input :gender, as: :radio_buttons, label: '性别', collection: [%w(男 0), %w(女 1)], wrapper_html: { class: 'col-md-3' } %>
|
||||
</div>
|
||||
|
||||
<div class="form-row user-identity-select">
|
||||
<div class="form-group select optional col-md-1">
|
||||
<%= f.label :identity, label: '职业' %>
|
||||
<%= select_tag('user[identity]', [], class: 'form-control identity-select optional', 'data-value': @user.user_extension&.identity, 'data-first-title': '请选择') %>
|
||||
</div>
|
||||
<div class="form-group technical-title-select-wrapper optional col-md-1" style="<%= @user.user_extension.student? ? 'display:none;' : '' %>">
|
||||
<%= f.label :technical_title, label: '职称' %>
|
||||
<%= select_tag('user[technical_title]', [], class: 'form-control technical-title-select optional', 'data-value': @user.technical_title) %>
|
||||
</div>
|
||||
|
||||
<%= f.input :student_id, as: :tel, label: '学号', wrapper_html: { class: 'col-md-2', style: @user.user_extension.student? ? '' : 'display:none;' }, input_html: { class: 'student-id-input' } %>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<%= f.input :mail, as: :email, label: '邮箱地址', wrapper_html: { class: 'col-md-3' }, input_html: { class: 'col-sm-11' } %>
|
||||
<%= f.input :phone, as: :tel, label: '手机号', wrapper_html: { class: 'col-md-3' }, input_html: { class: 'col-sm-11' } %>
|
||||
</div>
|
||||
|
||||
<div class="form-row province-city-select">
|
||||
<div class="form-group select optional col-md-2">
|
||||
<%= f.label :location, label: '省份' %>
|
||||
<%= select_tag('user[location]', [], class: 'form-control province-select optional', 'data-value': @user.location, 'data-first-title': '请选择') %>
|
||||
</div>
|
||||
<div class="form-group select optional col-md-2">
|
||||
<%= f.label :location_city, label: '城市' %>
|
||||
<%= select_tag('user[location_city]', [], class: 'form-control city-select optional', 'data-value': @user.location_city) %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<%= f.input :school_id, as: :hidden %>
|
||||
<%= f.input :department_id, as: :hidden %>
|
||||
<div class="form-group select optional col-md-2">
|
||||
<%= f.label :school_name, label: '所属学校/单位' %>
|
||||
<%= f.select :school_name, [@user.school_id], {}, class: 'form-control school-select optional' %>
|
||||
</div>
|
||||
<div class="form-group select optional col-md-2">
|
||||
<%= f.label :department_name, label: '所属学院/部门' %>
|
||||
<%= f.select :department_name, [@user.department_id], {}, class: 'form-control department-select optional' %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4"><h6>管理</h6></div>
|
||||
<div class="form-group px-2">
|
||||
<% if current_user.admin? %>
|
||||
<div class="form-group check_boxes optional">
|
||||
<%= f.label :role, label: '角色' %>
|
||||
<div class="d-flex">
|
||||
<%= f.input :admin, as: :boolean, label: '管理员', checked_value: 1, unchecked_value: 0 %>
|
||||
<%= f.input :business, as: :boolean, label: '运营人员', wrapper_html: { class: 'ml-3' }, checked_value: 1, unchecked_value: 0 %>
|
||||
<%= f.input :is_test, as: :boolean, label: '测试账号', wrapper_html: { class: 'ml-3' }, checked_value: 1, unchecked_value: 0 %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="form-group check_boxes optional">
|
||||
<%= f.label :role, label: '认证信息' %>
|
||||
<div class="d-flex">
|
||||
<%= f.input :professional_certification, as: :boolean, label: '职业认证', checked_value: 1, unchecked_value: 0 %>
|
||||
<%= f.input :authentication, as: :boolean, label: '实名认证', wrapper_html: { class: 'ml-3' }, checked_value: 1, unchecked_value: 0 %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<%= f.input :password, as: :password, label: '修改密码', wrapper_html: { class: 'col-md-3' }, input_html: { class: 'col-sm-11' } %>
|
||||
<%= f.input :password_confirmation, as: :password, label: '确认密码', wrapper_html: { class: 'col-md-3' }, input_html: { class: 'col-sm-11' } %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row mt-4">
|
||||
<%= f.button :submit, value: '保存', class: 'btn-primary mr-3 px-4' %>
|
||||
<%= link_to '取消', 'javascript:history.go(-1)', class: 'btn btn-secondary px-4' %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
@ -0,0 +1,35 @@
|
||||
<% define_admin_breadcrumbs do %>
|
||||
<% add_admin_breadcrumb('用户管理', admins_users_path) %>
|
||||
<% end %>
|
||||
|
||||
<div class="box search-form-container user-list-form">
|
||||
<%= form_tag(admins_users_path, method: :get, class: 'form-inline search-form', remote: true) do %>
|
||||
<div class="form-group mr-2">
|
||||
<label for="status">状态:</label>
|
||||
<% status_options = [['全部', ''], ['正常', User::STATUS_ACTIVE], ['未激活', User::STATUS_REGISTERED], ['已锁定', User::STATUS_LOCKED]] %>
|
||||
<%= select_tag(:status, options_for_select(status_options), class: 'form-control') %>
|
||||
</div>
|
||||
|
||||
<div class="form-group mr-2">
|
||||
<label for="identity">职业:</label>
|
||||
<% identity_options = [['全部', '']] + UserExtension.identities.map { |k, v| [I18n.t("user.identity.#{k}"), v] } %>
|
||||
<%= select_tag(:identity, options_for_select(identity_options), class: 'form-control') %>
|
||||
</div>
|
||||
|
||||
<div class="form-group mr-2">
|
||||
<label for="identity">授权类型:</label>
|
||||
<% auto_trial_options = [['全部', ''], ['自动授权', 1], ['手动授权', 0]] %>
|
||||
<%= select_tag(:auto_trial, options_for_select(auto_trial_options), class: 'form-control') %>
|
||||
</div>
|
||||
|
||||
<%= text_field_tag(:keyword, params[:keyword], class: 'form-control col-sm-2 ml-3', placeholder: 'ID/姓名/邮箱/手机号检索') %>
|
||||
<%= text_field_tag(:school_name, params[:school_name], class: 'form-control col-sm-2', placeholder: '学校/单位检索') %>
|
||||
<%= submit_tag('搜索', class: 'btn btn-primary ml-3') %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="box users-list-container">
|
||||
<%= render partial: 'admins/users/shared/user_list', locals: { users: @users } %>
|
||||
</div>
|
||||
|
||||
<%= render partial: 'admins/users/shared/reward_grade_modal' %>
|
@ -0,0 +1 @@
|
||||
$('.users-list-container').html("<%= j( render partial: 'admins/users/shared/user_list', locals: { users: @users } ) %>");
|
@ -0,0 +1,26 @@
|
||||
<div class="modal fade admin-users-reward-grade-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" id="exampleModalLongTitle">奖励金币</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form class="admin-users-reward-grade-form">
|
||||
<%= hidden_field_tag(:user_id, nil) %>
|
||||
<div class="form-group">
|
||||
<label for="grade" class="col-form-label">金币数量:</label>
|
||||
<%= number_field_tag(:grade, nil, class: 'form-control') %>
|
||||
</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,60 @@
|
||||
<table class="table table-hover users-list-table">
|
||||
<thead class="thead-light">
|
||||
<tr>
|
||||
<th width="10%">ID</th>
|
||||
<th width="10%">真实姓名</th>
|
||||
<th width="16%">邮件地址</th>
|
||||
<th width="10%">手机号码</th>
|
||||
<th width="14%">单位</th>
|
||||
<th width="12%"><%= sort_tag('创建于', name: 'created_on', path: admins_users_path) %></th>
|
||||
<th width="12%"><%= sort_tag('最后登录', name: 'last_login_on', path: admins_users_path) %></th>
|
||||
<th width="10%"><%= sort_tag('经验值', name: 'experience', path: admins_users_path) %></th>
|
||||
<th width="8%"><%= sort_tag('金币', name: 'grade', path: admins_users_path) %></th>
|
||||
<th width="14%">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% if users.present? %>
|
||||
<% users.each do |user| %>
|
||||
<tr class="user-item-<%= user.id %>">
|
||||
<td>
|
||||
<%= link_to "/users/#{user.login}", target: '_blank' do %>
|
||||
<%= overflow_hidden_span user.login, width: 100 %>
|
||||
<% end %>
|
||||
</td>
|
||||
<td>
|
||||
<%= link_to edit_admins_user_path(user) 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><%= overflow_hidden_span display_text(user.school_name), width: 150 %></td>
|
||||
<td><%= display_text(user.created_on&.strftime('%Y-%m-%d %H:%M')) %></td>
|
||||
<td><%= display_text(user.last_login_on&.strftime('%Y-%m-%d %H:%M')) %></td>
|
||||
<td><%= user.experience.to_i %></td>
|
||||
<td class="grade-content"><%= user.grade.to_i %></td>
|
||||
<td class="action-container">
|
||||
<%= javascript_void_link('奖励', class: 'action reward-grade-action', data: { toggle: 'modal', target: '.admin-users-reward-grade-modal', id: user.id }) %>
|
||||
|
||||
<%= javascript_void_link '解锁', class: 'action unlock-action', data: { id: user.id, confirm: '确认解锁吗?' }, style: user.locked? ? '' : 'display: none;' %>
|
||||
|
||||
<% if user.registered? %>
|
||||
<%= javascript_void_link '激活', class: 'action active-action', data: { id: user.id, confirm: '确认激活吗?' } %>
|
||||
<% end %>
|
||||
|
||||
<% if user.id != current_user.id %>
|
||||
<%= javascript_void_link '加锁', class: 'action lock-action', data: { id: user.id, confirm: '确认加锁吗?' }, style: user.locked? || user.registered? ? 'display: none;' : '' %>
|
||||
<% end %>
|
||||
|
||||
<%= delete_link '删除', admins_user_path(user, element: ".user-item-#{user.id}"), class: 'delete-user-action' %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<%= render 'admins/shared/no_data_for_table' %>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<%= render partial: 'admins/shared/paginate', locals: { objects: users } %>
|
@ -0,0 +1,6 @@
|
||||
<% define_admin_breadcrumbs do %>
|
||||
<% add_admin_breadcrumb('用户管理', admins_users_path) %>
|
||||
<% add_admin_breadcrumb('用户详情') %>
|
||||
<% end %>
|
||||
|
||||
<h3>Users Show</h3>
|
@ -0,0 +1 @@
|
||||
admins-users: admins-users
|
@ -0,0 +1,22 @@
|
||||
defaults: &defaults
|
||||
access_key_id: 'test'
|
||||
access_key_secret: 'test'
|
||||
base_url: 'http://vod.cn-shanghai.aliyuncs.com'
|
||||
cate_id: '-1'
|
||||
callback_url: 'http://47.96.87.25:48080/api/callbacks/aliyun_vod.json'
|
||||
signature_key: 'test12345678'
|
||||
|
||||
development:
|
||||
<<: *defaults
|
||||
access_key_id: 'LTAI4kRL1DxQPdM2'
|
||||
access_key_secret: 'yiz68rxE6imziBTITggWcOeSqjUeUu'
|
||||
cate_id: '1000068305'
|
||||
base_url: 'http://vod.cn-shanghai.aliyuncs.com'
|
||||
callback_url: 'http://47.96.87.25:48080/api/callbacks/aliyun_vod.json'
|
||||
signature_key: 'sdgdfDGH14DHD5g465123'
|
||||
|
||||
test:
|
||||
<<: *defaults
|
||||
|
||||
production:
|
||||
<<: *defaults
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue