Merge branch 'dev_aliyun' of https://bdgit.educoder.net/Hjqreturn/educoder into dev_aliyun

dev_aliyun_beta
杨树林 5 years ago
commit fa5caf6687

@ -25,6 +25,12 @@ $.fn.select2.defaults.set('language', 'zh-CN');
Turbolinks.setProgressBarDelay(200);
$.notifyDefaults({
type: 'success',
z_index: 9999,
delay: 2000
});
$(document).on('turbolinks:load', function(){
$('[data-toggle="tooltip"]').tooltip();
$('[data-toggle="popover"]').popover();

@ -0,0 +1,173 @@
$(document).on('turbolinks:load', function() {
if ($('body.admins-departments-index-page').length > 0) {
var $searchContainer = $('.department-list-form');
var $searchForm = $searchContainer.find('form.search-form');
var $list = $('.department-list-container');
$searchContainer.on('change', '.form-check-input', function(){
$searchForm.find('input[type="submit"]').trigger('click');
});
// ============== 新建部门 ===============
var $modal = $('.modal.admin-create-department-modal');
var $form = $modal.find('form.admin-create-department-form');
var $departmentNameInput = $form.find('input[name="department_name"]');
var $schoolSelect = $modal.find('.school-select');
$form.validate({
errorElement: 'span',
errorClass: 'danger text-danger',
rules: {
school_id: {
required: true
},
department_name: {
required: true
}
},
messages: {
school_id: {
required: '请选择所属单位'
}
}
});
// modal ready fire
$modal.on('show.bs.modal', function () {
$departmentNameInput.val('');
$schoolSelect.select2('val', ' ');
});
// ************** 学校选择 *************
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) {
$schoolSelect.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) {
$('#school_id').val(item.id);
}
return item.name || item.text;
},
matcher: matcherFunc
});
}
$.ajax({
url: '/api/schools/for_option.json',
dataType: 'json',
type: 'GET',
success: function(data) {
defineSchoolSelect(data.schools);
}
});
$modal.on('click', '.submit-btn', function(){
$form.find('.error').html('');
if ($form.valid()) {
var url = $form.data('url');
$.ajax({
method: 'POST',
dataType: 'json',
url: url,
data: $form.serialize(),
success: function(){
$.notify({ message: '创建成功' });
$modal.modal('hide');
setTimeout(function(){
window.location.reload();
}, 500);
},
error: function(res){
var data = res.responseJSON;
$form.find('.error').html(data.message);
}
});
}
});
// ============= 添加部门管理员 ==============
var $addMemberModal = $('.admin-add-department-member-modal');
var $addMemberForm = $addMemberModal.find('.admin-add-department-member-form');
var $memberSelect = $addMemberModal.find('.department-member-select');
var $departmentIdInput = $addMemberForm.find('input[name="department_id"]')
$addMemberModal.on('show.bs.modal', function(event){
var $link = $(event.relatedTarget);
var departmentId = $link.data('department-id');
$departmentIdInput.val(departmentId);
$memberSelect.select2('val', ' ');
});
$memberSelect.select2({
theme: 'bootstrap4',
placeholder: '请输入要添加的管理员姓名',
multiple: true,
minimumInputLength: 1,
ajax: {
delay: 500,
url: '/admins/users',
dataType: 'json',
data: function(params){
return { name: params.term };
},
processResults: function(data){
return { results: data.users }
}
},
templateResult: function (item) {
if(!item.id || item.id === '') return item.text;
return item.real_name;
},
templateSelection: function(item){
if (item.id) {
}
return item.real_name || item.text;
}
});
$addMemberModal.on('click', '.submit-btn', function(){
$addMemberForm.find('.error').html('');
var departmentId = $departmentIdInput.val();
var memberIds = $memberSelect.val();
if (departmentId && memberIds && memberIds.length > 0) {
$.ajax({
method: 'POST',
dataType: 'script',
url: '/admins/departments/' + departmentId + '/department_member',
data: { user_ids: memberIds }
});
} else {
$addMemberModal.modal('hide');
}
});
}
});

@ -0,0 +1,34 @@
$(document).on('turbolinks:load', function() {
$('.admin-modal-container').on('show.bs.modal', '.modal.admin-edit-department-modal', function(){
var $modal = $('.modal.admin-edit-department-modal');
var $form = $modal.find('form.admin-edit-department-form');
$form.validate({
errorElement: 'span',
errorClass: 'danger text-danger',
rules: {
'department[name]': {
required: true,
maxlength: 20
},
'department[host_count]': {
digits: true
}
}
});
$modal.on('click', '.submit-btn', function(){
$form.find('.error').html('');
var url = $form.attr('action');
if ($form.valid()) {
$.ajax({
method: 'PATCH',
dataType: 'script',
url: url,
data: $form.serialize()
});
}
});
})
});

@ -0,0 +1,110 @@
$(document).on('turbolinks:load', function() {
var $modal = $('.modal.admin-merge-department-modal');
if ($modal.length > 0) {
var $form = $modal.find('form.admin-merge-department-form');
var $schoolIdInput = $form.find('input[name="school_id"]');
var $originDepartmentIdInput = $form.find('input[name="origin_department_id"]');
var $departmentSelect = $modal.find('.department-select');
$form.validate({
errorElement: 'span',
errorClass: 'danger text-danger',
rules: {
department_id: {
required: true
}
},
messages: {
department_id: {
required: '请选择部门'
}
}
});
// ************** 学校选择 *************
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 defineDepartmentSelect = function(departments) {
$departmentSelect.empty();
$departmentSelect.select2({
theme: 'bootstrap4',
placeholder: '请选择所属部门',
data: departments,
templateResult: function (item) {
if(!item.id || item.id === '') return item.text;
return item.name;
},
templateSelection: function(item){
if (item.id) {
$form.find('#department_id').val(item.id);
}
return item.name || item.text;
},
matcher: matcherFunc
});
$departmentSelect.select2('val', ' ');
};
// modal ready fire
$modal.on('show.bs.modal', function (event) {
var $link = $(event.relatedTarget);
var schoolId = $link.data('schoolId');
$schoolIdInput.val(schoolId);
$originDepartmentIdInput.val($link.data('departmentId'));
$.ajax({
url: '/api/schools/' + schoolId + '/departments/for_option.json',
dataType: 'json',
type: 'GET',
success: function(data) {
defineDepartmentSelect(data.departments);
}
});
});
$modal.on('click', '.submit-btn', function(){
$form.find('.error').html('');
if ($form.valid()) {
var url = $form.data('url');
$.ajax({
method: 'POST',
dataType: 'json',
url: url,
data: $form.serialize(),
success: function(){
$.notify({ message: '操作成功' });
$modal.modal('hide');
setTimeout(function(){
window.location.reload();
}, 500);
},
error: function(res){
var data = res.responseJSON;
$form.find('.error').html(data.message);
}
});
}
});
}
});

@ -46,6 +46,10 @@ label.error {
}
}
input.form-control {
font-size: 14px;
}
.flex-1 {
flex: 1;
}

@ -0,0 +1,24 @@
.admins-departments-index-page {
.department-list-table {
.member-container {
.member-user {
display: flex;
justify-content: center;
flex-wrap: wrap;
.member-user-item {
display: flex;
align-items: center;
height: 22px;
line-height: 22px;
padding: 2px 5px;
margin: 2px 2px;
border: 1px solid #91D5FF;
background-color: #E6F7FF;
color: #91D5FF;
border-radius: 4px;
}
}
}
}
}

@ -0,0 +1,20 @@
class Admins::DepartmentMembersController < Admins::BaseController
helper_method :current_department
def create
Admins::AddDepartmentMemberService.call(current_department, params)
current_department.reload
end
def destroy
@member = current_department.department_members.find_by(user_id: params[:user_id])
@member.destroy! if @member.present?
end
private
def current_department
@_current_department ||= Department.find(params[:department_id])
end
end

@ -0,0 +1,95 @@
class Admins::DepartmentsController < Admins::BaseController
helper_method :current_department
def index
params[:sort_by] ||= 'created_at'
params[:sort_direction] ||= 'desc'
departments = Admins::DepartmentQuery.call(params)
@departments = paginate departments.preload(:school, :member_users)
department_ids = @departments.map(&:id)
@users_count = UserExtension.where(department_id: department_ids).group(:department_id).count
@professional_auth_count = UserExtension.where(department_id: department_ids)
.joins(:user).where(users: { professional_certification: true })
.group(:department_id).count
end
def create
department_name = params[:department_name].to_s.strip
school = School.find(params[:school_id])
return render_error('部门名称重复') if school.departments.exists?(name: department_name)
ActiveRecord::Base.transaction do
department = school.departments.create!(name: department_name, is_auth: 1)
ApplyAddDepartment.create!(school_id: school.id, status: 1, name: department.name,
department_id: department.id, user_id: current_user.id)
end
render_ok
end
def edit
end
def update
identifier = update_params.delete(:identifier).presence
if identifier && Department.where.not(id: current_department.id).exists?(identifier: identifier)
return render_error('统计链接重复', type: :notify)
end
current_department.update!(update_params.merge(identifier: identifier))
end
def destroy
ActiveRecord::Base.transaction do
current_department.apply_add_departments.update_all(status: 2)
user_ids = current_department.user_extensions.pluck(:user_id)
if user_ids.present?
DeleteDepartmentNotifyJob.perform_later(current_department.id, 0, user_ids)
current_department.soft_delete!
else
current_department.destroy!
end
end
render_delete_success
end
def merge
return render_error('请选择其它部门') if params[:origin_department_id].to_s == params[:department_id].to_s
origin_department = Department.find(params[:origin_department_id])
to_department = Department.find(params[:department_id])
return render_error('部门所属单位不相同') if origin_department.school_id != to_department.school_id
ActiveRecord::Base.transaction do
origin_department.apply_add_departments.delete_all
origin_department.user_extensions.update_all(department_id: to_department.id)
if to_department.identifier.blank? && origin_department.identifier.present?
to_department.update!(identifier: origin_department.identifier)
end
origin_department.destroy!
end
render_ok
end
private
def current_department
@_current_department ||= Department.find(params[:id])
end
def update_params
params.require(:department).permit(:name, :identifier, :host_count)
end
end

@ -17,9 +17,9 @@ module Admins::RenderHelper
json: -> { render status: 404, json: { message: '资源未找到' } })
end
def render_unprocessable_entity(message)
def render_unprocessable_entity(message, type: :alert)
render_by_format(html: -> { render 'admins/shared/422' },
js: -> { render_js_error(message) },
js: -> { render_js_error(message, type: type) },
json: -> { render status: 422, json: { message: message } })
end
alias_method :render_error, :render_unprocessable_entity
@ -40,7 +40,11 @@ module Admins::RenderHelper
end
alias_method :render_success_js, :render_delete_success
def render_js_error(message)
def render_js_error(message, type: :alert)
if type == :notify
render js: "$.notify({ message: '#{message}' },{ type: 'danger', delay: 5000 });"
else
render_js_template 'admins/shared/error', locals: { message: message }
end
end
end

@ -0,0 +1,21 @@
# 删除部门 消息通知
class DeleteDepartmentNotifyJob < ApplicationJob
queue_as :notify
def perform(department_id, operator_id, user_ids)
department = Department.unscoped.find_by(id: department_id)
return if department.blank? || user_ids.blank?
attrs = %i[ user_id trigger_user_id container_id container_type tiding_type status created_at updated_at]
same_attrs = {
trigger_user_id: operator_id, container_id: department.id, container_type: 'Department',
status: 4, tiding_type: 'System'
}
Tiding.bulk_insert(*attrs) do |worker|
user_ids.each do |user_id|
worker.add same_attrs.merge(user_id: user_id)
end
end
end
end

@ -2,6 +2,14 @@ class Department < ApplicationRecord
belongs_to :school
has_many :department_members, dependent: :destroy
has_many :member_users, through: :department_members, source: :user
has_many :user_extensions, dependent: :nullify
has_many :apply_add_departments
scope :without_deleted, -> { where(is_delete: false) }
def soft_delete!
update!(is_delete: true)
end
end

@ -0,0 +1,32 @@
class Admins::DepartmentQuery < ApplicationQuery
include CustomSortable
attr_reader :params
sort_columns :created_at, default_by: :created_at, default_direction: :desc
def initialize(params)
@params = params
end
def call
departments = Department.where(is_auth: true).without_deleted
keyword = params[:keyword].to_s.strip
if keyword.present?
departments = departments.joins(:school)
.where('schools.name LIKE :keyword OR departments.name LIKE :keyword', keyword: keyword)
end
if params[:with_member].to_s == 'true'
subquery = DepartmentMember.where('department_id = departments.id').select('1 AS one').to_sql
departments = departments.where("EXISTS(#{subquery})")
end
if params[:with_identifier].to_s == 'true'
departments = departments.where.not(identifier: nil).where.not(identifier: '')
end
custom_sort(departments, params[:sort_by], params[:sort_direction])
end
end

@ -28,7 +28,13 @@ class Admins::UserQuery < ApplicationQuery
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)
users = users.where(sql, keyword: "%#{keyword}%")
end
# 姓名
name = params[:name].to_s.strip.presence
if name.present?
users = users.where('CONCAT(lastname, firstname) LIKE :name', name: "%#{name}%")
end
# 学校名称

@ -0,0 +1,20 @@
class Admins::AddDepartmentMemberService < ApplicationService
attr_reader :department, :params
def initialize(department, params)
@department = department
@params = params
end
def call
columns = %i[]
DepartmentMember.bulk_insert(*columns) do |worker|
Array.wrap(params[:user_ids]).compact.each do |user_id|
next if department.department_members.exists?(user_id: user_id)
worker.add(department_id: department.id, user_id: user_id)
end
end
end
end

@ -5,7 +5,7 @@
<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') %>
<%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %>
<% end %>
<%#= link_to '导出Excel', export_admins_daily_school_statistics_path(format: :xlsx), class: 'btn btn-outline-primary export-action' %>

@ -0,0 +1,4 @@
$('.modal.admin-add-department-member-modal').modal('hide');
$.notify({ message: '操作成功' });
$('.department-list-table .department-item-<%= current_department.id %>').html("<%= j(render partial: 'admins/departments/shared/department_item', locals: { department: current_department }) %>")

@ -0,0 +1,2 @@
$.notify({ message: '操作成功' });
$('.department-list-container .department-item-<%= current_department.id %> .member-user-item-<%= @member.user_id %>').remove();

@ -0,0 +1,2 @@
$('.admin-modal-container').html("<%= j( render partial: 'admins/departments/shared/edit_department_modal', locals: { department: current_department } ) %>");
$('.modal.admin-edit-department-modal').modal('show');

@ -0,0 +1,33 @@
<% define_admin_breadcrumbs do %>
<% add_admin_breadcrumb('部门列表') %>
<% end %>
<div class="box search-form-container department-list-form">
<%= form_tag(admins_departments_path, method: :get, class: 'form-inline search-form flex-1', remote: true) do %>
<div class="form-check mr-3">
<%= hidden_field_tag(:with_member, false) %>
<%= check_box_tag(:with_member, true, params[:with_member].to_s == 'true', class: 'form-check-input') %>
<label class="form-check-label" for="with_member">有部门管理员</label>
</div>
<div class="form-check mr-3">
<%= hidden_field_tag(:with_identifier, false) %>
<%= check_box_tag(:with_identifier, true, params[:with_identifier].to_s == 'true', class: 'form-check-input') %>
<label class="form-check-label" for="with_member">有统计链接</label>
</div>
<%= text_field_tag(:keyword, params[:keyword], class: 'form-control col-sm-2 ml-3', placeholder: '部门/单位名称检索') %>
<%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %>
<% end %>
<%= javascript_void_link '新建部门', class: 'btn btn-primary', data: { toggle: 'modal', target: '.admin-create-department-modal' } %>
</div>
<div class="box department-list-container">
<%= render partial: 'admins/departments/shared/list',
locals: { departments: @departments, users_count: @users_count, professional_auth_count: @professional_auth_count } %>
</div>
<%= render 'admins/departments/shared/create_department_modal' %>
<%= render 'admins/departments/shared/add_department_member_modal' %>
<%= render 'admins/departments/shared/merge_department_modal' %>

@ -0,0 +1 @@
$('.department-list-container').html("<%= j(render partial: 'admins/departments/shared/list', locals: { departments: @departments, users_count: @users_count, professional_auth_count: @professional_auth_count }) %>");

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

@ -0,0 +1,35 @@
<div class="modal fade admin-create-department-modal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">新建部门</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form class="admin-create-department-form" data-url="<%= admins_departments_path %>">
<div class="form-group d-flex">
<label for="school_id" class="col-form-label">所属单位:</label>
<div class="d-flex flex-column-reverse w-75">
<select id="school_id" name="school_id" class="form-control school-select"></select>
</div>
</div>
<div class="form-group d-flex">
<label for="new_mirror_id" class="col-form-label">部门名称:</label>
<div class="w-75 d-flex flex-column">
<%= text_field_tag(:department_name, nil, class: 'form-control', placeholder: '请输入部门名称') %>
</div>
</div>
<div class="error text-danger"></div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
<button type="button" class="btn btn-primary submit-btn">确认</button>
</div>
</div>
</div>
</div>

@ -0,0 +1,28 @@
<% not_list = defined?(:users_count) %>
<td class="text-left"><%= overflow_hidden_span department.name, width: 150 %></td>
<td class="text-left"><%= overflow_hidden_span department.school.name, width: 150 %></td>
<% if not_list %>
<td><%= department.user_extensions.count %></td>
<td><%= department.user_extensions.joins(:user).where(users: { professional_certification: true }).count %></td>
<% else %>
<td><%= users_count.fetch(department.id, 0) %></td>
<td><%= professional_auth_count.fetch(department.id, 0) %></td>
<% end %>
<td class="member-container">
<%= render partial: 'admins/departments/shared/member_users', locals: { department: department } %>
</td>
<td><%= link_to department.identifier.to_s, '#', target: '_blank' %></td>
<td><%= department.host_count %></td>
<td><%= department.created_at&.strftime('%Y-%m-%d %H:%M') %></td>
<td class="action-container">
<%= link_to '编辑', edit_admins_department_path(department), remote: true, class: 'action' %>
<%= javascript_void_link '添加管理员', class: 'action', data: { department_id: department.id, toggle: 'modal', target: '.admin-add-department-member-modal' } %>
<%= javascript_void_link '更改', class: 'action', data: { school_id: department.school_id, department_id: department.id, toggle: 'modal', target: '.admin-merge-department-modal' } %>
<%= delete_link '删除', admins_department_path(department, element: ".department-item-#{department.id}"), class: 'delete-department-action' %>
</td>

@ -0,0 +1,25 @@
<div class="modal fade admin-edit-department-modal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">编辑部门信息</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<%= simple_form_for([:admins, department], html: { class: 'admin-edit-department-form' }, defaults: { wrapper_html: { class: 'offset-md-1 col-md-10' } }) do |f| %>
<%= f.input :name, as: :string, label: '名称' %>
<%= f.input :identifier, as: :string, label: '统计链接' %>
<%= f.input :host_count, as: :integer, label: '云主机数' %>
<div class="error text-danger"></div>
<% end %>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
<button type="button" class="btn btn-primary submit-btn">确认</button>
</div>
</div>
</div>
</div>

@ -0,0 +1,28 @@
<table class="table table-hover text-center department-list-table">
<thead class="thead-light">
<tr>
<th width="14%" class="text-left">部门名称</th>
<th width="14%" class="text-left">单位名称</th>
<th width="6%">用户数</th>
<th width="10%">已职业认证</th>
<th width="20%">部门管理员</th>
<th width="8%">统计链接</th>
<th width="8%">云主机数</th>
<th width="10%"><%= sort_tag('创建时间', name: 'created_at', path: admins_departments_path) %></th>
<th width="14%">操作</th>
</tr>
</thead>
<tbody>
<% if departments.present? %>
<% departments.each do |department| %>
<tr class="department-item-<%= department.id %>">
<%= render 'admins/departments/shared/department_item', department: department %>
</tr>
<% end %>
<% else %>
<%= render 'admins/shared/no_data_for_table' %>
<% end %>
</tbody>
</table>
<%= render partial: 'admins/shared/paginate', locals: { objects: departments } %>

@ -0,0 +1,12 @@
<div class="member-user">
<% department.member_users.each do |user| %>
<span class="member-user-item member-user-item-<%= user.id %>">
<%= link_to user.real_name, "/users/#{user.login}", target: '_blank', data: { toggle: 'tooltip', title: '个人主页' } %>
<%= link_to(admins_department_department_member_path(department, user_id: user.id),
method: :delete, remote: true, class: 'ml-1 delete-member-action',
data: { confirm: '确认删除吗?' }) do %>
<i class="fa fa-close"></i>
<% end %>
</span>
<% end %>
</div>

@ -0,0 +1,31 @@
<div class="modal fade admin-merge-department-modal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">更改部门</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form class="admin-merge-department-form" data-url="<%= merge_admins_departments_path %>">
<%= hidden_field_tag(:school_id, nil) %>
<%= hidden_field_tag(:origin_department_id, nil) %>
<div class="form-group d-flex">
<label for="school_id" class="col-form-label">更改为:</label>
<div class="d-flex flex-column-reverse w-75">
<select id="department_id" name="department_id" class="form-control department-select"></select>
</div>
</div>
<div class="error text-danger"></div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
<button type="button" class="btn btn-primary submit-btn">确认</button>
</div>
</div>
</div>
</div>

@ -0,0 +1,4 @@
$('.modal.admin-edit-department-modal').modal('hide');
$.notify({ message: '操作成功' });
$('.department-list-table .department-item-<%= current_department.id %>').html("<%= j(render partial: 'admins/departments/shared/department_item', locals: { department: current_department }) %>")

@ -21,7 +21,7 @@
<%= select_tag(:status, options_for_select(status_options), class: 'form-control') %>
</div>
<%= text_field_tag(:keyword, params[:keyword], class: 'form-control col-sm-2 ml-3', placeholder: '姓名/学校/单位检索') %>
<%= submit_tag('搜索', class: 'btn btn-primary ml-3') %>
<%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %>
<% end %>
</div>

@ -21,7 +21,7 @@
<%= select_tag(:status, options_for_select(status_options), class: 'form-control') %>
</div>
<%= text_field_tag(:keyword, params[:keyword], class: 'form-control col-sm-2 ml-3', placeholder: '姓名/学校/单位检索') %>
<%= submit_tag('搜索', class: 'btn btn-primary ml-3') %>
<%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %>
<% end %>
</div>

@ -26,6 +26,12 @@
<% end %>
</li>
<li>
<%= sidebar_item_group('#schools-submenu', '单位管理', icon: 'building') do %>
<li><%= sidebar_item(admins_departments_path, '部门列表', icon: 'sitemap', controller: 'admins-departments') %></li>
<% end %>
</li>
<!-- <li>-->
<%#= sidebar_item_group('#course-submenu', '课堂+', icon: 'mortar-board') do %>
<!-- <li><%#= sidebar_item('#', '课程列表', icon: 'calendar', controller: '') %></li>-->

@ -21,7 +21,7 @@
<%= select_tag(:status, options_for_select(status_options), class: 'form-control') %>
</div>
<%= text_field_tag(:keyword, params[:keyword], class: 'form-control col-sm-2 ml-3', placeholder: '实训名称检索') %>
<%= submit_tag('搜索', class: 'btn btn-primary ml-3') %>
<%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %>
<% end %>
</div>

@ -21,7 +21,7 @@
<%= select_tag(:status, options_for_select(status_options), class: 'form-control') %>
</div>
<%= text_field_tag(:keyword, params[:keyword], class: 'form-control col-sm-2 ml-3', placeholder: '实训课程名称检索') %>
<%= submit_tag('搜索', class: 'btn btn-primary ml-3') %>
<%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %>
<% end %>
</div>

@ -24,7 +24,7 @@
<%= 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') %>
<%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %>
<% end %>
</div>

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

@ -2,7 +2,7 @@
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLongTitle">奖励金币</h5>
<h5 class="modal-title">奖励金币</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>

@ -809,6 +809,11 @@ Rails.application.routes.draw do
resources :mirror_scripts, only: [:index, :new, :create, :edit, :update, :destroy]
end
resources :choose_mirror_repositories, only: [:new, :create]
resources :departments, only: [:index, :create, :edit, :update, :destroy] do
resource :department_member, only: [:create, :update, :destroy]
post :merge, on: :collection
end
end
#git 认证回调

File diff suppressed because one or more lines are too long

@ -37635,6 +37635,179 @@ $(document).on('turbolinks:load', function(){
}
})
;
$(document).on('turbolinks:load', function() {
if ($('body.admins-departments-index-page').length > 0) {
var $searchContainer = $('.department-list-form');
var $searchForm = $searchContainer.find('form.search-form');
var $list = $('.department-list-container');
$searchContainer.on('change', '.form-check-input', function(){
$searchForm.find('input[type="submit"]').trigger('click');
});
// ============== 新建部门 ===============
var $modal = $('.modal.admin-create-department-modal');
var $form = $modal.find('form.admin-create-department-form');
var $departmentNameInput = $form.find('input[name="department_name"]');
var $schoolSelect = $modal.find('.school-select');
$form.validate({
errorElement: 'span',
errorClass: 'danger text-danger',
rules: {
school_id: {
required: true
},
department_name: {
required: true
}
},
messages: {
school_id: {
required: '请选择所属单位'
}
}
});
// modal ready fire
$modal.on('show.bs.modal', function () {
$departmentNameInput.val('');
$schoolSelect.select2('val', ' ');
});
// ************** 学校选择 *************
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) {
$schoolSelect.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) {
$('#school_id').val(item.id);
}
return item.name || item.text;
},
matcher: matcherFunc
});
}
$.ajax({
url: '/api/schools/for_option.json',
dataType: 'json',
type: 'GET',
success: function(data) {
defineSchoolSelect(data.schools);
}
});
$modal.on('click', '.submit-btn', function(){
$form.find('.error').html('');
if ($form.valid()) {
var url = $form.data('url');
$.ajax({
method: 'POST',
dataType: 'json',
url: url,
data: $form.serialize(),
success: function(){
$.notify({ message: '创建成功' });
$modal.modal('hide');
setTimeout(function(){
window.location.reload();
}, 500);
},
error: function(res){
var data = res.responseJSON;
$form.find('.error').html(data.message);
}
});
}
});
// ============= 添加部门管理员 ==============
var $addMemberModal = $('.admin-add-department-member-modal');
var $addMemberForm = $addMemberModal.find('.admin-add-department-member-form');
var $memberSelect = $addMemberModal.find('.department-member-select');
var $departmentIdInput = $addMemberForm.find('input[name="department_id"]')
$addMemberModal.on('show.bs.modal', function(event){
var $link = $(event.relatedTarget);
var departmentId = $link.data('department-id');
$departmentIdInput.val(departmentId);
$memberSelect.select2('val', ' ');
});
$memberSelect.select2({
theme: 'bootstrap4',
placeholder: '请输入要添加的管理员姓名',
multiple: true,
minimumInputLength: 1,
ajax: {
delay: 500,
url: '/admins/users',
dataType: 'json',
data: function(params){
return { name: params.term };
},
processResults: function(data){
return { results: data.users }
}
},
templateResult: function (item) {
if(!item.id || item.id === '') return item.text;
return item.real_name;
},
templateSelection: function(item){
if (item.id) {
}
return item.real_name || item.text;
}
});
$addMemberModal.on('click', '.submit-btn', function(){
$addMemberForm.find('.error').html('');
var departmentId = $departmentIdInput.val();
var memberIds = $memberSelect.val();
if (departmentId && memberIds && memberIds.length > 0) {
$.ajax({
method: 'POST',
dataType: 'script',
url: '/admins/departments/' + departmentId + '/department_member',
data: { user_ids: memberIds }
});
} else {
$addMemberModal.modal('hide');
}
});
}
});
$(document).on('turbolinks:load', function() {
if ($('body.admins-identity-authentications-index-page').length > 0) {
var $searchFrom = $('.identity-authentication-list-form');
@ -37744,6 +37917,150 @@ $(document).on('turbolinks:load', function() {
});
})
});
$(document).on('turbolinks:load', function() {
$('.admin-modal-container').on('show.bs.modal', '.modal.admin-edit-department-modal', function(){
var $modal = $('.modal.admin-edit-department-modal');
var $form = $modal.find('form.admin-edit-department-form');
$form.validate({
errorElement: 'span',
errorClass: 'danger text-danger',
rules: {
'department[name]': {
required: true,
maxlength: 20
},
'department[host_count]': {
digits: true
}
}
});
$modal.on('click', '.submit-btn', function(){
$form.find('.error').html('');
var url = $form.attr('action');
if ($form.valid()) {
$.ajax({
method: 'PATCH',
dataType: 'script',
url: url,
data: $form.serialize()
});
}
});
})
});
$(document).on('turbolinks:load', function() {
var $modal = $('.modal.admin-merge-department-modal');
if ($modal.length > 0) {
var $form = $modal.find('form.admin-merge-department-form');
var $schoolIdInput = $form.find('input[name="school_id"]');
var $originDepartmentIdInput = $form.find('input[name="origin_department_id"]');
var $departmentSelect = $modal.find('.department-select');
$form.validate({
errorElement: 'span',
errorClass: 'danger text-danger',
rules: {
department_id: {
required: true
}
},
messages: {
department_id: {
required: '请选择部门'
}
}
});
// ************** 学校选择 *************
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 defineDepartmentSelect = function(departments) {
$departmentSelect.empty();
$departmentSelect.select2({
theme: 'bootstrap4',
placeholder: '请选择所属部门',
data: departments,
templateResult: function (item) {
if(!item.id || item.id === '') return item.text;
return item.name;
},
templateSelection: function(item){
if (item.id) {
$form.find('#department_id').val(item.id);
}
return item.name || item.text;
},
matcher: matcherFunc
});
$departmentSelect.select2('val', ' ');
};
// modal ready fire
$modal.on('show.bs.modal', function (event) {
var $link = $(event.relatedTarget);
var schoolId = $link.data('schoolId');
$schoolIdInput.val(schoolId);
$originDepartmentIdInput.val($link.data('departmentId'));
$.ajax({
url: '/api/schools/' + schoolId + '/departments/for_option.json',
dataType: 'json',
type: 'GET',
success: function(data) {
defineDepartmentSelect(data.departments);
}
});
});
$modal.on('click', '.submit-btn', function(){
$form.find('.error').html('');
if ($form.valid()) {
var url = $form.data('url');
$.ajax({
method: 'POST',
dataType: 'json',
url: url,
data: $form.serialize(),
success: function(){
$.notify({ message: '操作成功' });
$modal.modal('hide');
setTimeout(function(){
window.location.reload();
}, 500);
},
error: function(res){
var data = res.responseJSON;
$form.find('.error').html(data.message);
}
});
}
});
}
});
$(document).on('turbolinks:load', function() {
var $modal = $('.modal.admin-replace-mirror-modal');
if ($modal.length > 0) {
@ -38362,6 +38679,12 @@ $.fn.select2.defaults.set('language', 'zh-CN');
Turbolinks.setProgressBarDelay(200);
$.notifyDefaults({
type: 'success',
z_index: 9999,
delay: 2000
});
$(document).on('turbolinks:load', function(){
$('[data-toggle="tooltip"]').tooltip();
$('[data-toggle="popover"]').popover();

@ -18563,6 +18563,31 @@ span.CodeMirror-selectedtext {
text-align: center;
}
/* line 4, app/assets/stylesheets/admins/departments.scss */
.admins-departments-index-page .department-list-table .member-container .member-user {
display: -webkit-box;
display: flex;
-webkit-box-pack: center;
justify-content: center;
flex-wrap: wrap;
}
/* line 9, app/assets/stylesheets/admins/departments.scss */
.admins-departments-index-page .department-list-table .member-container .member-user .member-user-item {
display: -webkit-box;
display: flex;
-webkit-box-align: center;
align-items: center;
height: 22px;
line-height: 22px;
padding: 2px 5px;
margin: 2px 2px;
border: 1px solid #91D5FF;
background-color: #E6F7FF;
color: #91D5FF;
border-radius: 4px;
}
/* line 4, app/assets/stylesheets/admins/identity_authentications.scss */
.admins-identity-authentications-index-page .identity-authentication-list-container span.apply-status-1 {
color: #28a745;
@ -19005,27 +19030,32 @@ label.error {
}
/* line 49, app/assets/stylesheets/admin.scss */
input.form-control {
font-size: 14px;
}
/* line 53, app/assets/stylesheets/admin.scss */
.flex-1 {
-webkit-box-flex: 1;
flex: 1;
}
/* line 53, app/assets/stylesheets/admin.scss */
/* line 57, app/assets/stylesheets/admin.scss */
.font-12 {
font-size: 12px !important;
}
/* line 54, app/assets/stylesheets/admin.scss */
/* line 58, app/assets/stylesheets/admin.scss */
.font-14 {
font-size: 14px !important;
}
/* line 55, app/assets/stylesheets/admin.scss */
/* line 59, app/assets/stylesheets/admin.scss */
.font-16 {
font-size: 16px !important;
}
/* line 56, app/assets/stylesheets/admin.scss */
/* line 60, app/assets/stylesheets/admin.scss */
.font-18 {
font-size: 18px !important;
}

@ -18563,6 +18563,31 @@ span.CodeMirror-selectedtext {
text-align: center;
}
/* line 4, app/assets/stylesheets/admins/departments.scss */
.admins-departments-index-page .department-list-table .member-container .member-user {
display: -webkit-box;
display: flex;
-webkit-box-pack: center;
justify-content: center;
flex-wrap: wrap;
}
/* line 9, app/assets/stylesheets/admins/departments.scss */
.admins-departments-index-page .department-list-table .member-container .member-user .member-user-item {
display: -webkit-box;
display: flex;
-webkit-box-align: center;
align-items: center;
height: 22px;
line-height: 22px;
padding: 2px 5px;
margin: 2px 2px;
border: 1px solid #91D5FF;
background-color: #E6F7FF;
color: #91D5FF;
border-radius: 4px;
}
/* line 4, app/assets/stylesheets/admins/identity_authentications.scss */
.admins-identity-authentications-index-page .identity-authentication-list-container span.apply-status-1 {
color: #28a745;
@ -19005,27 +19030,32 @@ label.error {
}
/* line 49, app/assets/stylesheets/admin.scss */
input.form-control {
font-size: 14px;
}
/* line 53, app/assets/stylesheets/admin.scss */
.flex-1 {
-webkit-box-flex: 1;
flex: 1;
}
/* line 53, app/assets/stylesheets/admin.scss */
/* line 57, app/assets/stylesheets/admin.scss */
.font-12 {
font-size: 12px !important;
}
/* line 54, app/assets/stylesheets/admin.scss */
/* line 58, app/assets/stylesheets/admin.scss */
.font-14 {
font-size: 14px !important;
}
/* line 55, app/assets/stylesheets/admin.scss */
/* line 59, app/assets/stylesheets/admin.scss */
.font-16 {
font-size: 16px !important;
}
/* line 56, app/assets/stylesheets/admin.scss */
/* line 60, app/assets/stylesheets/admin.scss */
.font-18 {
font-size: 18px !important;
}
@ -19174,6 +19204,30 @@ label.error {
.admins-daily-school-statistics-index-page .daily-school-statistic-list-container {
text-align: center;
}
/* line 4, app/assets/stylesheets/admins/departments.scss */
.admins-departments-index-page .department-list-table .member-container .member-user {
display: -webkit-box;
display: flex;
-webkit-box-pack: center;
justify-content: center;
flex-wrap: wrap;
}
/* line 9, app/assets/stylesheets/admins/departments.scss */
.admins-departments-index-page .department-list-table .member-container .member-user .member-user-item {
display: -webkit-box;
display: flex;
-webkit-box-align: center;
align-items: center;
height: 22px;
line-height: 22px;
padding: 2px 5px;
margin: 2px 2px;
border: 1px solid #91D5FF;
background-color: #E6F7FF;
color: #91D5FF;
border-radius: 4px;
}
/* line 4, app/assets/stylesheets/admins/identity_authentications.scss */
.admins-identity-authentications-index-page .identity-authentication-list-container span.apply-status-1 {
color: #28a745;

File diff suppressed because one or more lines are too long

@ -53,7 +53,7 @@ class ShiXunPostItem extends Component
</div>
<p className="clearfix mt5">
<span className="fl color-grey-9">{memo.username}</span>
<span className="fl color-grey-9 ml40">{moment(memo.updated_at).fromNow()}</span>
{/* <span className="fl color-grey-9 ml40">{moment(memo.updated_at).fromNow()}</span> */}
{ !!tagStr && <span className="fl color-grey-9 ml40">来自 {tagStr}</span>}
{ !!memo.praises_count && <span className="fr color-grey-6 ml20 font-12">{memo.praises_count} </span>}
{ !!memo.replies_count && <span className="fr color-grey-6 font-12">{memo.replies_count} 回复</span>}

@ -550,7 +550,7 @@ class AccountBasic extends Component {
)}
<span>{ showRealName ? '(显示:平台将显示您的真实姓名)' : '(隐藏:平台将显示你的昵称)' }</span>
</React.Fragment> :
<div className="df" style={{ 'justify-content': 'center' }}>
<div className="df" style={{}}>
<Tooltip title="已完成实名认证,不能修改">
<span className="mr8" >{showRealName ? this.props.basicInfo.name : getHiddenName(this.props.basicInfo.name)}</span>
</Tooltip>

@ -3763,6 +3763,6 @@ a.singlepublishtwo{
/*}*/
.topicsItem{
max-width: 1138px;
height: 110px;
max-height: 110px;
overflow-y: auto;
}
Loading…
Cancel
Save