Merge branches 'dev_aliyun' and 'dev_ysm' of https://bdgit.educoder.net/Hjqreturn/educoder into dev_ysm

dev_ysm
杨树明 5 years ago
commit ff3ce54608

@ -69,5 +69,80 @@ $(document).on('turbolinks:load', function() {
});
}
});
// 导入学生
var $importScoreModal = $('.modal.admin-import-competition-score-modal');
var $importScoreForm = $importScoreModal.find('form.admin-import-competition-score-form');
var $competitionIdInput = $importScoreForm.find('input[name="competition_id"]');
$importScoreModal.on('show.bs.modal', function(event){
resetFileInputFunc($importScoreModal.find('.upload-file-input'));
$importScoreModal.find('.file-names').html('选择文件');
$importScoreModal.find('.upload-file-input').trigger('click');
var $link = $(event.relatedTarget);
var competitionId = $link.data('competition-id');
$competitionIdInput.val(competitionId);
});
$importScoreModal.on('change', '.upload-file-input', function(e){
var file = $(this)[0].files[0];
$importScoreModal.find('.file-names').html(file ? file.name : '请选择文件');
});
var importUserFormValid = function(){
if($importScoreForm.find('input[name="file"]').val() == undefined || $importScoreForm.find('input[name="file"]').val().length == 0){
$importScoreForm.find('.error').html('请选择文件');
return false;
}
return true;
};
var buildResultMessage = function(data){
var messageHtml = "<div>导入结果:成功" + data.success + "条,失败"+ data.fail.length + "条</div>";
if(data.fail.length > 0){
messageHtml += '<table class="table"><thead class="thead-light"><tr><th>数据</th><th>失败原因</th></tr></thead><tbody>';
data.fail.forEach(function(item){
messageHtml += '<tr><td>' + item.data + '</td><td>' + item.message + '</td></tr>';
});
messageHtml += '</tbody></table>'
}
return messageHtml;
};
$importScoreModal.on('click', '.submit-btn', function(){
$importScoreForm.find('.error').html('');
if (importUserFormValid()) {
$('body').mLoading({ text: '正在导入...' });
$.ajax({
method: 'POST',
dataType: 'json',
url: '/admins/import_competition_scores',
data: new FormData($importScoreForm[0]),
processData: false,
contentType: false,
success: function(data){
$('body').mLoading('destroy');
$importScoreModal.modal('hide');
showMessageModal(buildResultMessage(data), function(){
window.location.reload();
});
},
error: function(res){
$('body').mLoading('destroy');
var data = res.responseJSON;
$importScoreForm.find('.error').html(data.message);
}
});
}
});
});

@ -3,13 +3,24 @@
//= require jquery3
//= require popper
//= require bootstrap-sprockets
//= require jquery.validate.min
//= require additional-methods.min
//= require bootstrap-notify
//= require select2
//= require common
//= require echarts
//= require ./i18n/jquery-validate-message-zh
//= require ./i18n/select2-i18n.zh-CN
//= require_tree ./colleges
Turbolinks.setProgressBarDelay(200);
// ******** 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();

@ -0,0 +1,28 @@
$(document).on('turbolinks:load', function() {
if ($('body.partners-customers-page').length > 0) {
var $customerContainer = $('.customer-list-container');
var partnerId = $customerContainer.find('.customer-list-body').data('id');
$customerContainer.on('change', '.manager-group-select', function(){
console.log('manager-group-select change', $(this).val());
var $select = $(this);
var customerId = $select.data('id');
var managerGroupId = $select.val();
$.ajax({
url: '/partners/' + partnerId + '/customer_manager_group.json',
method: 'POST',
dataType: 'json',
data: { customer_id: customerId, manager_group_id: managerGroupId },
success: function(){
showSuccessFlash();
$select.data('last', managerGroupId);
},
error: function(res){
showErrorNotify(res.responseJSON.message);
$select.val($select.data('last'));
}
})
})
}
});

@ -0,0 +1,125 @@
$(document).on('turbolinks:load', function() {
if ($('body.partners-partner-manager-groups-page').length > 0) {
var $container = $('.manager-group-list-container');
var partnerId = $container.find('.manager-group-list-body').data('id');
// ------- 新建编辑权限组弹窗 --------
var $managerGroupModal = $('.modal.partner-save-manager-group-modal');
var $managerGroupForm = $managerGroupModal.find('form.partner-save-manager-group-form');
var $managerGroupIdInput = $managerGroupForm.find('input[name="manager_group_id"]');
var $managerGroupNameInput = $managerGroupForm.find('input[name="manager_group_name"]');
$managerGroupForm.validate({
errorElement: 'span',
errorClass: 'danger text-danger',
rules: {
manager_group_name: {
required: true,
maxlength: 20
},
}
});
$managerGroupModal.on('show.bs.modal', function(event){
var $link = $(event.relatedTarget);
var managerGroupId = $link.data('id');
var managerGroupName = $link.data('name');
if(managerGroupId && managerGroupId !== ''){
$managerGroupModal.find('.modal-title').html('重命名');
$managerGroupIdInput.val(managerGroupId);
$managerGroupNameInput.val(managerGroupName)
} else {
$managerGroupModal.find('.modal-title').html('新建');
$managerGroupIdInput.val('');
$managerGroupNameInput.val('');
}
});
$managerGroupModal.on('hide.bs.modal', function(){
$managerGroupIdInput.val('');
$managerGroupNameInput.val('');
});
$managerGroupModal.on('click', '.submit-btn', function(){
$managerGroupForm.find('.error').html('');
var url = $managerGroupForm.data('url');
if ($managerGroupForm.valid()) {
$.ajax({
method: 'POST',
dataType: 'script',
url: url,
data: $managerGroupForm.serialize()
});
}
});
// ---------- 添加管理员弹窗 ------------
var $partnerManagerModal = $('.modal.partner-add-partner-manager-modal');
var $partnerManagerForm = $partnerManagerModal.find('form.partner-add-partner-manager-form');
var $managerGroupIdInput = $partnerManagerForm.find('input[name="manager_group_id"]');
var $userSelect = $partnerManagerForm.find('.partner-manager-select');
$userSelect.select2({
theme: 'bootstrap4',
placeholder: '请输入要添加的管理员姓名',
multiple: true,
closeOnSelect: false,
minimumInputLength: 1,
ajax: {
delay: 500,
url: '/api/users_for_partners',
dataType: 'json',
data: function(params){
return { name: params.term, partner_id: partnerId, page: params.page || 1, per_page: 20 };
},
processResults: function(data, params){
params.page = params.page || 1;
return {
results: data.users,
pagination: {
more: (params.page * 20) < data.count
}
};
}
},
templateResult: function (item) {
if(!item.id || item.id === '') return item.text;
return $("<span>" + item.real_name + " <span class='font-12'>" + item.school_name + ' ' + item.identity + "</span></span>");
},
templateSelection: function(item){
if (item.id) {
}
return item.real_name || item.text;
}
});
$partnerManagerModal.on('show.bs.modal', function(event){
var $link = $(event.relatedTarget);
var managerGroupId = $link.data('id');
$managerGroupIdInput.val(managerGroupId);
$userSelect.select2('val', ' ');
$partnerManagerModal.find('.error').html('');
});
$partnerManagerModal.on('click', '.submit-btn', function(){
$partnerManagerModal.find('.error').html('');
var managerGroupId = $managerGroupIdInput.val();
var userIds = $userSelect.val();
if (userIds && userIds.length > 0) {
$.ajax({
method: 'POST',
dataType: 'script',
url: '/partners/' + partnerId + '/partner_managers',
data: { user_ids: userIds, manager_group_id: managerGroupId }
});
} else {
$partnerManagerModal.modal('hide');
}
});
}
});

@ -88,6 +88,14 @@ function show_success_flash(message){
});
}
function showSuccessFlash(message){
$.notify({
message: message || '操作成功'
},{
type: 'success'
});
}
function showErrorNotify(message){
$.notify({
message: message || '操作失败'

@ -24,7 +24,7 @@
background: unset;
}
/* 内容表格 */
/* 内容表格 */
table {
table-layout: fixed;
@ -100,6 +100,14 @@
}
}
.admin-list-container {
overflow-x: scroll;
& > table {
min-width: 900px;
}
}
.global-error {
color: grey;
min-height: 300px;
@ -124,7 +132,6 @@
}
.batch-action-container {
margin-bottom: -15px;
padding: 10px 20px 0;
background: #fff;
}

@ -1,6 +1,8 @@
@import "bootstrap";
@import "font-awesome-sprockets";
@import "font-awesome";
@import "select2.min";
@import "select2-bootstrap4.min";
@import "common";
@ -10,4 +12,34 @@
.navbar-dark .navbar-nav .nav-link {
color: rgba(255, 255, 255, 1);
font-size: 16px;
}
.box {
padding: 20px;
border-radius: 5px;
background: #fff;
}
.custom-nav {
padding: 0 1rem;
display: flex;
border-bottom: 1px solid #EBEBEB;
&-item {
padding: 0 0.5rem;
}
&-link {
display: block;
margin-bottom: 2px;
padding: 0.8rem 0.5rem;
color: #495057;
font-size: 16px;
&.active {
margin-bottom: 0px;
color: #007bff;
border-bottom: 2px solid #007bff;
}
}
}

@ -0,0 +1,131 @@
.college-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;
}
}
}
}
.image-preview-container {
display: flex;
flex-direction: column;
align-items: center;
}
.action-container {
& > .action {
padding: 0 3px;
}
.more-action-dropdown {
.dropdown-item {
font-size: 14px;
}
}
}
/* 分页 */
.paginate-container {
margin-top: 20px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.paginate-total {
margin-bottom: 10px;
color: darkgrey;
}
.pagination {
margin-bottom: 0px;
}
}
/* 搜索表单 */
.search-form-container {
display: flex;
margin-bottom: 20px;
.search-form {
flex: 1;
* { font-size: 14px; }
select, input {
margin-right: 10px;
font-size: 14px;
}
}
}
.global-error {
color: grey;
min-height: 300px;
&-code {
font-size: 80px;
}
&-text {
font-size: 24px;
}
}
.nav-tabs {
.nav-link {
padding: 0.5rem 2rem;
}
}
.CodeMirror {
border: 1px solid #ced4da;
}
.batch-action-container {
padding: 10px 20px 0;
background: #fff;
}
}

@ -0,0 +1,5 @@
.partners-customers-page {
.customer-list-body {
min-height: 300px;
}
}

@ -0,0 +1,104 @@
.partners-partner-manager-groups-page {
.customer-list-form {
padding: 10px 20px;
align-items: center;
}
.manager-group-item {
margin-bottom: 20px;
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
&-left {
flex: 1;
}
&-right {
.action {
}
}
}
}
.partner-manager {
&-body {
display: flex;
flex-wrap: wrap;
align-items: flex-start;
}
&-item {
padding: 5px 10px;
display: flex;
flex-direction: column;
align-items: center;
position: relative;
.remove-partner-manager-action {
display: none;
position: absolute;
z-index: 100;
right: 10px;
top: 0;
font-size: 24px;
& > i {
color: #dc3545;
}
}
&:hover {
.remove-partner-manager-action {
display: block;
}
}
&-avatar {
cursor: pointer;
width: 80px;
height: 80px;
overflow: hidden;
border-radius: 50%;
position: relative;
& > img {
width: 80px;
height: 80px;
}
}
&.add-partner-manager-item {
.partner-manager-item-avatar {
background: #E4E4E4;
&:hover {
background: #D0D0D0;
}
&::before {
content: '';
position: absolute;
top: 39px;
left: 20px;
width: 40px;
height: 2px;
background: #fff;
}
&::after {
content: '';
position: absolute;
top: 20px;
left: 39px;
width: 2px;
height: 40px;
background: #fff;
}
}
}
}
}
}

@ -1,5 +1,7 @@
.colleges-statistics-page {
.college-body-container {
padding: 0;
.statistic-header {
width: 100%;
height: 240px;

@ -124,7 +124,6 @@
}
.batch-action-container {
margin-bottom: -15px;
padding: 10px 20px 0;
background: #fff;
}

@ -0,0 +1,14 @@
class Admins::ImportCompetitionScoresController < Admins::BaseController
def create
return render_error('请上传正确的文件') if params[:file].blank? || !params[:file].is_a?(ActionDispatch::Http::UploadedFile)
result = Admins::ImportCompetitionScoreService.call(params[:file].to_io, current_competition)
render_ok(result)
rescue Admins::ImportCompetitionScoreService::Error => ex
render_error(ex)
end
def current_competition
competition = Competition.find_by!(id: params[:competition_id])
end
end

@ -1,5 +1,5 @@
class CollegesController < ApplicationController
include Admins::PaginateHelper
include PaginateHelper
layout 'college'
@ -154,7 +154,7 @@ class CollegesController < ApplicationController
return true if current_user.admin_or_business? # 超级管理员|运营
return true if current_college.is_a?(Department) && current_college.member?(current_user) # 部门管理员
return true if current_user.is_teacher? && current_user.school_id == current_school.id # 学校老师
return true if current_school.customer_id && current_user.partner&.partner_customers&.exists?(customer_id: current_school.customer_id)
return true if current_school.customers.exists? && current_user.partner&.partner_customers&.exists?(customer_id: current_school.customer_id)
false
end

@ -1,4 +1,6 @@
class Competitions::CompetitionStaffsController < Competitions::BaseController
skip_before_action :require_login
def show
end
end

@ -46,7 +46,7 @@ class Competitions::CompetitionTeamsController < Competitions::BaseController
.where("exists(select 1 from homework_commons hcs where hcs.course_id = courses.id and hcs.publish_time is not null and hcs.publish_time < NOW() and hcs.homework_type = 4 and exists(#{subquery}))")
.joins('join course_members on course_members.course_id = courses.id and course_members.role in (1,2,3)')
.where(course_members: { user_id: @team_user_ids }).pluck(:id)
courses = Course.where(id: course_ids).joins(:practice_homeworks).where('homework_commons.publish_time < now()')
courses = Course.where(id: course_ids).joins(:practice_homeworks).where('homework_commons.publish_time < ?', end_time)
@courses = courses.select('courses.id, courses.name, courses.members_count, count(*) shixun_homework_count')
.group('courses.id').order('shixun_homework_count desc').having('shixun_homework_count > 0')

@ -123,26 +123,41 @@ class Competitions::CompetitionsController < Competitions::BaseController
@stage = @competition.competition_stages.take
end
@records = @competition.competition_teams.joins(:competition_scores).where(competition_scores: {competition_stage_id: @stage&.id.to_i})
@all_records = @competition.competition_teams.joins(:competition_scores).where(competition_scores: {competition_stage_id: @stage&.id.to_i})
.select("competition_teams.*, score, cost_time").order("score desc, cost_time desc")
current_team_ids = @competition.team_members.where(user_id: current_user.id).pluck(:competition_team_id).uniq
@user_ranks = @records.select{|com_team| current_team_ids.include?(com_team.id)}
@records = @records.where("score > 0")
@user_ranks = @all_records.select{|com_team| current_team_ids.include?(com_team.id)}
@records = @all_records.where("score > 0")
@record_ids = @records.pluck(:id)
if params[:format] == "xlsx"
@records = @records.includes(user: [user_extension: :school], team_members: :user)
respond_to do |format|
format.xlsx{
set_export_cookies
chart_to_xlsx(@records, @competition)
chart_to_xlsx(@all_records, @competition)
exercise_export_name = "#{@competition.name}比赛成绩"
render xlsx: "#{exercise_export_name.strip}",template: "competitions/competitions/chart_list.xlsx.axlsx",locals:
{table_columns: @competition_head_cells, chart_lists: @competition_cells_column}
}
end
else
@records = @records.includes(:team_members, user: :user_extension).limit(@competition.awards_count)
@records = @records.includes(:team_members, competition_prize_users: :competition_prize, user: :user_extension).limit(@competition.awards_count)
end
end
def export_extra_course_statistics
@competition = current_competition
@all_records = @competition.competition_teams.joins(:competition_scores, user: [user_extension: :school])
.select("competition_teams.*, competition_scores.score, cost_time").order("score desc, cost_time desc")
respond_to do |format|
format.xlsx{
extra_chart_to_xlsx(@all_records)
exercise_export_name = "#{@competition.name}比赛成绩"
render xlsx: "#{exercise_export_name.strip}",template: "competitions/competitions/chart_list.xlsx.axlsx",locals:
{table_columns: @competition_head_cells, chart_lists: @competition_cells_column}
}
end
end
@ -219,4 +234,67 @@ class Competitions::CompetitionsController < Competitions::BaseController
@competition_cells_column.push(row_cells_column)
end
end
def extra_chart_to_xlsx records
@competition_head_cells = []
@competition_cells_column = []
@competition_head_cells = %w(序号 姓名 id 学校 实训数 学习人数 被fork发布的学习人数 实训有效作品数 实训应用值 课堂数 学生数量 发布的实训作业数 有效作品数 课堂应用值 总分)
records.each_with_index do |record, index|
row_cells_column = []
row_cells_column << index + 1
record_user = record.user
row_cells_column << record_user.real_name
row_cells_column << record_user.login
row_cells_column << record_user.school_name
total_score = 0
shixun_count = 0
shixun_member_count = 0
shixun_fork_member_count = 0
shixun_valid_count = 0
shixun_score = 0
shixun_records = record.competition_course_records.where(type: 'CompetitionCourseShixunRecord')
shixun_records.each do |shixun|
shixun_count += 1
shixun_member_count += shixun.snapshot['myshixuns_count'].to_i
shixun_fork_member_count += shixun.snapshot['forked_myshixun_count'].to_i
shixun_valid_count += shixun.snapshot['valid_myshixun_count'].to_i
shixun_score += shixun.score.to_i
end
row_cells_column << shixun_count
row_cells_column << shixun_member_count
row_cells_column << shixun_fork_member_count
row_cells_column << shixun_valid_count
row_cells_column << shixun_score
total_score += shixun_score
course_count = 0
course_member_count = 0
course_homework_count = 0
course_valid_count = 0
course_score = 0
course_records = record.competition_course_records.where(type: 'CompetitionCourseCourseRecord')
course_records.each do |course|
course_count += 1
course_member_count += course.snapshot['members_count'].to_i
course_homework_count += course.snapshot['shixun_homework_count'].to_i
course_valid_count += course.snapshot['valid_myshixun_count'].to_i
course_score += course.score.to_i
end
row_cells_column << course_count
row_cells_column << course_member_count
row_cells_column << course_homework_count
row_cells_column << course_valid_count
row_cells_column << course_score
total_score += course_score
row_cells_column << total_score
@competition_cells_column.push(row_cells_column)
end
end
end

@ -2,7 +2,7 @@ class Competitions::PrizeLeaderAccountsController < Competitions::BaseController
before_action :require_prize_team_leader!
def update
Competitions::SavePrizeTeamAccountService.call(current_competition, current_user, update_params)
Competitions::SavePrizeTeamAccountService.call(current_competition, current_prize_user, update_params)
render_ok
rescue ApplicationService::Error => ex
render_error(ex.message)
@ -13,8 +13,8 @@ class Competitions::PrizeLeaderAccountsController < Competitions::BaseController
def require_prize_team_leader!
prize_user = current_competition.competition_prize_users.joins(:competition_prize)
.where(competition_prizes: { category: :bonus })
.find_by(leader: true, user_id: current_user.id)
return if prize_user.present?
.find_by(leader: true, user_id: current_prize_user.id)
return if prize_user.present? && (current_user.admin_or_business? || current_user.id == current_prize_user.id)
render_forbidden
end
@ -22,4 +22,8 @@ class Competitions::PrizeLeaderAccountsController < Competitions::BaseController
def update_params
params.permit(:bank, :second_bank, :card_no)
end
def current_prize_user
@_current_prize_user ||= User.find(params[:user_id])
end
end

@ -7,8 +7,8 @@ class Competitions::PrizesController < Competitions::BaseController
self_prizes = current_competition.competition_prize_users.where(user_id: current_prize_user.id).includes(:competition_team).order(:competition_prize_id)
@leader = self_prizes.any?{ |prize_user| prize_user.leader? && prize_user.competition_prize.category == 'bonus' } # 是否为队长并且有奖金奖励
if @leader
@bank_account = self_prizes.find(&:leader?).extra
if @leader || current_user.admin_or_business?
@bank_account = self_prizes.find(&:leader?)&.extra
@bank_account_editable = self_prizes.select(&:leader?).all?(&:pending?)
end

@ -1539,7 +1539,7 @@ class CoursesController < ApplicationController
end
def course_statistics course, max_exp, limit
max_rate = 20.0 / max_exp
max_rate = max_exp.nil? ? 0 : 20.0 / max_exp
sql_select = %Q{ SELECT a.*, (message_num*0.2 + message_reply_num*0.1 + resource_num*0.5 + homework_journal_num*0.1 + graduation_num +
homework_num + exercise_num + poll_num*0.7 + exercise_score * 0.7 + graduation_score * 0.7 + homework_score * 0.7 + exp*#{max_rate})

@ -11,20 +11,7 @@ class HomeController < ApplicationController
end
# 目录分级
repertoires = Repertoire.includes(sub_repertoires: :tag_repertoires).order("updated_at asc")
@rep_list = []
repertoires.each do |rep|
sub_rep_list = []
rep.sub_repertoires.each do |sub_rep|
tag_rep_list = []
sub_rep.tag_repertoires.each do |tag_rep|
tag_rep_list << {tag_id: tag_rep.id, tag_name: tag_rep.name}
end
sub_rep_list << {sub_rep_id: sub_rep.id, sub_rep_name: sub_rep.name, tag_rep_list: tag_rep_list}
end
@rep_list << {rep_id: rep.id, rep_name: rep.name, sub_rep_list: sub_rep_list}
end
@rep_list = current_laboratory.shixun_repertoires
shixuns = current_laboratory.shixuns
subjects = current_laboratory.subjects

@ -0,0 +1,137 @@
class PartnersController < ApplicationController
include Base::PaginateHelper
include Admins::RenderHelper
layout 'college'
before_action :require_login, :check_partner_present!, :check_permission!
before_action :check_admin_manager_group_permission!, except: [:customers]
helper_method :current_partner, :manager_permission?
def customers
customers = CustomerQuery.call(current_partner, current_user, params)
@customers = paginate(customers.includes(:school))
load_customer_extra_statistic_data
end
def partner_manager_groups
@manager_groups = current_partner.partner_manager_groups.includes(users: :user_extension).to_a
end
def manager_group
name = params[:manager_group_name].to_s.strip
if params[:manager_group_id].present?
# 重命名
@manager_group = current_partner.partner_manager_groups.find(params[:manager_group_id])
return render_error('不能修改管理者权限组名称') if @manager_group.admin?
@manager_group.update!(name: name)
else
# 新建
@manager_group = current_partner.partner_manager_groups.create!(name: name)
end
end
def remove_manager_group
manager_group = current_partner.partner_manager_groups.find(params[:manager_group_id])
return render_error('不能删除管理者权限组') if manager_group.admin?
manager_group.destroy!
render_delete_success
end
def partner_managers
user_ids = Array.wrap(params[:user_ids])
@manager_group = current_partner.partner_manager_groups.find(params[:manager_group_id])
ActiveRecord::Base.transaction do
User.where(id: user_ids).pluck(:id).each do |user_id|
next if current_partner.partner_managers.exists?(partner_manager_group: @manager_group, user_id: user_id)
current_partner.partner_managers.create!(partner_manager_group: @manager_group, user_id: user_id)
end
end
@manager_group.reload
end
def remove_partner_manager
partner_manager = current_partner.partner_managers.find(params[:manager_id])
return render_error('不能删除自己') if partner_manager.user_id == current_user.id && partner_manager.partner_manager_group.admin?
partner_manager.destroy!
render_delete_success
end
def customer_manager_group
customer = current_partner.customers.find(params[:customer_id])
if params[:manager_group_id].present?
manager_group = current_partner.partner_manager_groups.find(params[:manager_group_id])
customer.update!(partner_manager_group: manager_group)
else
customer.update!(partner_manager_group_id: nil)
end
render_ok
end
private
def current_partner
@_current_partner ||= Partner.find(params[:id].presence || params[:partner_id])
end
def check_partner_present!
return if current_partner.present?
redirect_to '/404'
end
def manager_permission?
admin_or_business? || current_user.partner_managers.exists?(partner_id: current_partner.id)
end
def check_permission!
return if manager_permission?
redirect_to '/403'
end
def check_admin_manager_group_permission!
return if admin_or_business?
return if current_partner.admin_partner_manager_group.partner_managers.exists?(user: current_user)
render_forbidden
end
def load_customer_extra_statistic_data
school_ids = @customers.map(&:school_id)
teacher_map = UserExtension.where(school_id: school_ids, identity: 0).group(:school_id).count
student_map = UserExtension.where(school_id: school_ids, identity: 1).group(:school_id).count
course_map = Course.where(school_id: school_ids, is_delete: 0).where.not(id: 1309).group(:school_id).count
shixun_map = Shixun.visible.joins('left join user_extensions on user_extensions.user_id = shixuns.user_id')
.where(user_extensions: { school_id: school_ids }).group('user_extensions.school_id').count
shixun_report_map = StudentWork.where(work_status: [1, 2]).where('myshixun_id != 0')
.joins('left join user_extensions on user_extensions.user_id = student_works.user_id')
.where(user_extensions: { school_id: school_ids })
.group('user_extensions.school_id').count
course_time_map = Course.where(school_id: school_ids, is_delete: 0)
.where.not(id: 1309).group(:school_id).maximum(:updated_at)
@customers.each do |customer|
customer._extra_data = {
teacher_count: teacher_map[customer.school_id],
student_count: student_map[customer.school_id],
course_count: course_map[customer.school_id],
shixun_count: shixun_map[customer.school_id],
shixun_report_count: shixun_report_map[customer.school_id],
course_time: course_time_map[customer.school_id]
}
end
end
end

@ -154,22 +154,7 @@ class ShixunsController < ApplicationController
## 获取顶部菜单
def menus
where_sql = ShixunTagRepertoire.where("shixun_tag_repertoires.tag_repertoire_id = tag_repertoires.id")
# 云上实验室过滤
unless current_laboratory.main_site?
where_sql = where_sql.joins('JOIN laboratory_shixuns ls ON ls.shixun_id = shixun_tag_repertoires.shixun_id')
end
where_sql = where_sql.select('1').to_sql
tags = TagRepertoire.where("EXISTS(#{where_sql})").distinct.includes(sub_repertoire: :repertoire)
@tags_map = tags.group_by(&:sub_repertoire)
@sub_reps_map = @tags_map.keys.group_by(&:repertoire)
# @repertoires = Repertoire.includes(sub_repertoires: [:tag_repertoires]).order("updated_at asc")
# respond_with @repertoires
render_json
@repertoires = current_laboratory.shixun_repertoires
end
## 实训详情

@ -11,7 +11,7 @@ class SubjectsController < ApplicationController
include SubjectsHelper
def index
@tech_system = Repertoire.where(nil).order("updated_at desc")
@tech_system = current_laboratory.subject_repertoires
select = params[:select] # 路径导航类型
reorder = params[:order] || "publish_time"
search = params[:search]

@ -17,6 +17,6 @@ class Users::AuthenticationAppliesController < Users::BaseAccountController
private
def create_params
params.permit(:name, :gender, :id_number, :upload_image, attachment_ids: [])
params.permit(:name, :show_realname, :gender, :id_number, :upload_image, attachment_ids: [])
end
end

@ -0,0 +1,27 @@
class UsersForPartnersController < ApplicationController
include Base::PaginateHelper
before_action :check_partner_manager_permission!
def index
params[:sort_by] = params[:sort_by].presence || 'created_on'
params[:sort_direction] = params[:sort_direction].presence || 'desc'
users = Admins::UserQuery.call(search_params)
@users = paginate users.includes(user_extension: :school)
end
private
def search_params
params.permit(:name, :sort_by, :sort_direction)
end
def check_partner_manager_permission!
partner = Partner.find(params[:partner_id])
return if admin_or_business?
return if partner.admin_partner_manager_group.partner_managers.exists?(user: current_user)
render_forbidden
end
end

@ -1,7 +1,7 @@
class Users::ApplyAuthenticationForm
include ActiveModel::Model
attr_accessor :name, :id_number, :gender, :upload_image, :attachment_ids
attr_accessor :name, :show_realname, :id_number, :gender, :upload_image, :attachment_ids
validates :name, presence: true
validate :validate_ID_number

@ -47,7 +47,7 @@ module CompetitionsHelper
end
statistic_stages.each do |stage|
if stage.max_end_time && stage.max_end_time < Time.now
if (stage.max_end_time && stage.max_end_time < Time.now) || stage.max_end_time.nil?
stages << {id: stage.id, name: "#{stage.name}排行榜", rate: stage.score_rate, start_time: stage.min_start_time, end_time: stage.max_end_time}
end
end

@ -48,9 +48,10 @@ module ManageBackHelper
str.presence || default
end
def overflow_hidden_span(text, width: 300)
def overflow_hidden_span(text, width: 300, placement: nil)
opts = { class: 'd-inline-block text-truncate', style: "max-width: #{width}px" }
opts.merge!('data-toggle': 'tooltip', title: text) if text != '--'
opts.merge!('data-placement': placement) if placement
content_tag(:span, text, opts)
end

@ -0,0 +1,20 @@
class Admins::ImportCompetitionScoreExcel < BaseImportXlsx
Data = Struct.new(:competition_team_id, :score)
def read_each(&block)
sheet.each_row_streaming(pad_cells: true, offset: 1) do |row|
data = row.map(&method(:cell_value))[0..1]
block.call Data.new(*data)
end
end
private
def check_sheet_valid!
raise_import_error('请按照模板格式导入') if sheet.row(1).size != 2
end
def cell_value(obj)
obj&.cell_value&.to_s&.strip
end
end

@ -45,7 +45,7 @@ class LimitForbidControl::Base
end
def remain_times
allow_times - error_times
allow_times.to_i - error_times
end
def clear

@ -0,0 +1,2 @@
class CompetitionCourseCourseRecord < CompetitionCourseRecord
end

@ -0,0 +1,6 @@
class CompetitionCourseRecord < ApplicationRecord
belongs_to :competition
belongs_to :competition_team
serialize :snapshot, JSON
end

@ -0,0 +1,2 @@
class CompetitionCourseShixunRecord < CompetitionCourseRecord
end

@ -12,11 +12,16 @@ class CompetitionTeam < ApplicationRecord
has_many :teachers, -> { only_teachers }, class_name: 'TeamMember'
has_many :competition_prize_users, dependent: :destroy
has_many :competition_course_records, dependent: :destroy
def group_team_type?
team_type.zero?
end
def competition_prize
competition_prize_users.take&.competition_prize&.name
end
def personal_team_type?
team_type == 1
end

@ -2,6 +2,7 @@ class Customer < ApplicationRecord
default_scope { order(created_at: :desc) }
belongs_to :school
belongs_to :partner_manager_group, optional: true
has_many :partner_customers, dependent: :destroy
has_many :partners, through: :partner_customers

@ -47,6 +47,42 @@ class Laboratory < ApplicationRecord
main_site? ? Subject.all : Subject.joins(:laboratory_subjects).where(laboratory_subjects: { laboratory_id: id })
end
def shixun_repertoires
where_sql = ShixunTagRepertoire.where("shixun_tag_repertoires.tag_repertoire_id = tag_repertoires.id")
# 云上实验室过滤
unless main_site?
where_sql = where_sql.joins("JOIN laboratory_shixuns ls ON ls.shixun_id = shixun_tag_repertoires.shixun_id "\
"AND ls.laboratory_id = #{id}")
end
where_sql = where_sql.select('1').to_sql
tags = TagRepertoire.where("EXISTS(#{where_sql})").distinct.includes(sub_repertoire: :repertoire)
tags_map = tags.group_by(&:sub_repertoire)
sub_reps_map = tags_map.keys.group_by(&:repertoire)
sub_reps_map.keys.sort_by(&:updated_at).reverse.map do |repertoire|
repertoire_hash = repertoire.as_json(only: %i[id name])
repertoire_hash[:sub_repertoires] =
sub_reps_map[repertoire].sort_by(&:updated_at).reverse.map do |sub_repertoire|
sub_repertoire_hash = sub_repertoire.as_json(only: %i[id name])
sub_repertoire_hash[:tags] = tags_map[sub_repertoire].sort_by(&:updated_at).reverse.map { |tag| tag.as_json(only: %i[id name]) }
sub_repertoire_hash
end
repertoire_hash
end
end
def subject_repertoires
exist_sql = Subject.where('subjects.repertoire_id = repertoires.id')
unless main_site?
exist_sql = exist_sql.joins(:laboratory_subjects).where(laboratory_subjects: { laboratory_id: id })
end
Repertoire.where("EXISTS(#{exist_sql.select('1').to_sql})").order(updated_at: :desc).distinct
end
# 是否为主站
def main_site?
id == 1

@ -1,7 +1,10 @@
class Partner < ApplicationRecord
belongs_to :school, optional: true
has_many :users
has_many :partner_customers, dependent: :destroy
has_many :customers, through: :partner_customers
has_many :partner_manager_groups, dependent: :destroy
has_one :admin_partner_manager_group, -> { where(admin: true) }, class_name: 'PartnerManagerGroup'
has_many :partner_managers, dependent: :destroy
end

@ -0,0 +1,5 @@
class PartnerManager < ApplicationRecord
belongs_to :user
belongs_to :partner
belongs_to :partner_manager_group
end

@ -0,0 +1,10 @@
class PartnerManagerGroup < ApplicationRecord
belongs_to :partner
has_many :customers, dependent: :nullify
has_many :partner_managers, dependent: :destroy
has_many :users, through: :partner_managers, source: :user
scope :without_admin, -> { where(admin: false) }
end

@ -14,7 +14,7 @@ class School < ApplicationRecord
has_many :courses
has_many :customers, dependent: :destroy
has_many :partners, dependent: :destroy
has_one :partner, dependent: :destroy
has_many :apply_add_departments, dependent: :destroy
has_many :user_extensions, dependent: :nullify

@ -18,6 +18,8 @@ module Searchable::Subject
def search_data
{
name: name,
status: status,
hidden: hidden,
description: Util.extract_content(description)[0..Searchable::MAXIMUM_LENGTH],
shixuns_count: shixuns_count,
myshixuns_count: member_count,

@ -293,7 +293,7 @@ class Shixun < ApplicationRecord
# 所属实践课程
def relation_path
subjects.where(hidden: 0).uniq
subjects.visible.unhidden.uniq
end
private

@ -146,7 +146,7 @@ class User < ApplicationRecord
has_many :videos, dependent: :destroy
# 客户管理
belongs_to :partner, optional: true
has_many :partner_managers, dependent: :destroy
# Groups and active users
scope :active, lambda { where(status: STATUS_ACTIVE) }

@ -0,0 +1,30 @@
class CustomerQuery < ApplicationQuery
attr_reader :partner, :user, :params
def initialize(partner, user, params)
@partner = partner
@user = user
@params = params
end
def call
customers = manager_group_scope
keyword = params[:keyword].to_s.strip.presence
customers = customers.joins(:school).where('schools.name LIKE ?', "%#{keyword}%") if keyword
customers
end
private
def manager_group_scope
# 超级管理员 或者 管理员
if user.admin_or_business? || partner.admin_partner_manager_group.partner_managers.exists?(user: user)
partner.customers
else
manager_group_ids = user.partner_managers.where(partner: partner).joins(:partner_manager_group).pluck('partner_manager_groups.id')
partner.customers.where(partner_manager_group_id: manager_group_ids)
end
end
end

@ -0,0 +1,59 @@
class Admins::ImportCompetitionScoreService < ApplicationService
Error = Class.new(StandardError)
attr_reader :file, :competition, :result
def initialize(file, competition)
@file = file
@competition = competition
@result = { success: 0, fail: [] }
end
def call
raise Error, '文件不存在' if file.blank?
# 创建所有战队的得分记录
create_all_records
excel = Admins::ImportCompetitionScoreExcel.new(file)
excel.read_each(&method(:update_competition_score)) # 更新单个战队成绩
result
rescue ApplicationImport::Error => ex
raise Error, ex.message
end
private
def update_competition_score(data)
team = competition.competition_scores.find_by(competition_team_id: data.competition_team_id)
raise "id为#{data.id}的战队不存在" if team.blank?
team.update!(score: data.score)
result[:success] += 1
rescue Exception => ex
fail_data = data.as_json
fail_data[:data] = fail_data.values.join(',')
fail_data[:message] = ex.message
result[:fail] << fail_data
end
def create_all_records
competition.competition_scores.destroy_all
stage = competition.competition_stages.first
attrs = %i[
competition_id competition_stage_id score cost_time user_id competition_team_id created_at updated_at
]
CompetitionScore.bulk_insert(*attrs) do |worker|
base_attr = { competition_id: competition.id, competition_stage_id: stage&.id.to_i,
score: 0, cost_time: 0 }
competition.competition_teams.each do |team|
worker.add(base_attr.merge(user_id: team.user_id).merge(competition_team_id: team.id))
end
end
end
end

@ -15,6 +15,7 @@ class Users::ApplyAuthenticationService < ApplicationService
user.lastname = params[:name].to_s.strip
user.firstname = ''
user.ID_number = params[:id_number].to_s.strip.presence
user.show_realname = params[:show_realname].to_s == 'true' if params[:show_realname].to_s.present?
ActiveRecord::Base.transaction do
user.authentication = false

@ -6,7 +6,7 @@
<%= javascript_void_link '新增', class: 'btn btn-primary', data: { toggle: 'modal', target: '.auth-schools-new-add' } %>
</div>
<div class="box auth-schools-list-container">
<div class="box admin-list-container auth-schools-list-container">
<%= render(partial: 'admins/auth_schools/shared/list', locals: { schools: @schools }) %>
</div>

@ -14,7 +14,7 @@
<div class="input-group-prepend">
<span class="input-group-text">图片</span>
</div>
<div class="custom-file flex-row-reverse">
<div class="custom-file flex-row-reverse" style="overflow: hidden">
<input type="file" name="portal_image[image]" class="img-file-input" id="img-file-input" accept="image/*">
<label class="custom-file-label file-names" for="img-file-input">选择文件</label>
</div>

@ -59,6 +59,6 @@
</div>
</div>
<div class="box competition-prize-user-list-container">
<div class="box admin-list-container competition-prize-user-list-container">
<%= render(partial: 'admins/competition_prize_users/shared/list', locals: { prize_users: @prize_users }) %>
</div>

@ -17,7 +17,11 @@
<% if prize_user.leader? && prize_user.competition_prize.category == 'bonus' %>
<% bank_content = [prize_user.extra&.[]('bank'), prize_user.extra&.[]('second_bank'), prize_user.extra&.[]('card_no')].compact.join('<br>').presence || '无' %>
<%= javascript_void_link('查看银行账户', data: { toggle: 'tooltip', title: bank_content.html_safe, html: true, placement: 'left', trigger: 'click' }) %>
<% end %>
<% prize_module = prize_user.competition&.competition_modules.find_by(module_type: 'certificate') %>
<% if prize_module %>
<%= link_to('编辑', EduSetting.get("host_name").to_s + "/competitions/#{prize_user.competition&.identifier}?menu=#{prize_module&.id}&user_id=#{user.id}", target: "_blank") %>
<% end %>
<% end %>
<% if prize_user.pending? %>
<%= link_to('审批通过', approve_admins_competition_competition_prize_user_path(prize_user.competition, prize_user),

@ -25,9 +25,10 @@
</div>
</div>
<div class="box competitions-list-container">
<div class="box admin-list-container competitions-list-container">
<%= render partial: 'admins/competitions/shared/list', locals: { competitions: @competitions } %>
</div>
<%= render 'admins/competitions/shared/create_competition_modal' %>
<%= render partial: 'admins/shared/modal/upload_file_modal', locals: { title: '上传图片' } %>
<%= render partial: 'admins/shared/modal/upload_file_modal', locals: { title: '上传图片' } %>
<%= render partial: 'admins/competitions/shared/import_competition_score_modal' %>

@ -0,0 +1,32 @@
<div class="modal fade admin-import-competition-score-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-import-competition-score-form" enctype="multipart/form-data">
<%= hidden_field_tag(:competition_id, nil) %>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text">文件</span>
</div>
<div class="custom-file">
<input type="file" name="file" class="upload-file-input" id="import-competition-score-input" accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet">
<label class="custom-file-label file-names" for="import-user-input">选择文件</label>
</div>
</div>
<div class="error text-danger"></div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
<button type="button" class="btn btn-primary submit-btn">确认</button>
</div>
</div>
</div>
</div>

@ -24,4 +24,8 @@
<% end %>
<%= link_to competition.published? ? "下架" : "上架", online_switch_admins_competition_path(competition), class: 'action online-action', method: :post, remote: true %>
<% if competition.mode != 1 %>
<%= javascript_void_link '导入成绩', class: 'action', data: { competition_id: competition.id, toggle: 'modal', target: '.admin-import-competition-score-modal'} %>
<% end %>
</td>

@ -12,7 +12,7 @@
<%= javascript_void_link('添加', class: 'btn btn-primary', data: { toggle: 'modal', target: '.admin-select-school-modal' }) %>
</div>
<div class="box customer-list-container">
<div class="box admin-list-container customer-list-container">
<%= render 'admins/customers/shared/list', customers: @customers %>
</div>

@ -24,6 +24,6 @@
其它作业总数<span class="text-danger"><%= @other_homework_total %></span>个
</div>
<div class="box daily-school-statistic-list-container">
<div class="box admin-list-container daily-school-statistic-list-container">
<%= render partial: 'admins/daily_school_statistics/shared/list', locals: { statistics: @statistics } %>
</div>

@ -10,7 +10,7 @@
<% end %>
</div>
<div class="box department-applies-list-container">
<div class="box admin-list-container department-applies-list-container">
<%= render(partial: 'admins/department_applies/shared/list', locals: { applies: @depart_applies }) %>
</div>

@ -23,7 +23,7 @@
<%= javascript_void_link '新建部门', class: 'btn btn-primary', data: { toggle: 'modal', target: '.admin-create-department-modal' } %>
</div>
<div class="box department-list-container">
<div class="box admin-list-container department-list-container">
<%= render partial: 'admins/departments/shared/list',
locals: { departments: @departments, users_count: @users_count, professional_auth_count: @professional_auth_count } %>
</div>

@ -7,7 +7,7 @@
</div>
<div class="box ec-templates-list-container">
<div class="box admin-list-container ec-templates-list-container">
<%= render(partial: 'admins/ec_templates/shared/list', locals: { templates: @templates }) %>
</div>

@ -14,14 +14,14 @@ wb.add_worksheet(name: '报名列表') do |sheet|
@personal ? "--" : team.teachers_info,
member_user.real_name,
member_user.identity,
member_user.phone,
member_user.phone.present? ? (member_user.phone.to_s + "\t") : "--",
member_user.mail,
member_user.student_id,
member_user.student_id.present? ? (member_user.student_id.to_s + "\t") : "--",
member_user.authentication ? "√" : "",
member_user.professional_certification ? "√" : "",
member_user.school_name,
member_user.school_province,
member.created_at.strftime('%Y-%m-%d %H:%M'),
team.created_at&.strftime('%Y-%m-%d %H:%M'),
rank
]
sheet.add_row(data)

@ -28,6 +28,6 @@
</div>
</div>
<div class="box competition-enroll-list-container">
<div class="box admin-list-container competition-enroll-list-container">
<%= render(partial: 'admins/enroll_lists/list', locals: { enroll_lists: @enroll_lists }) %>
</div>

@ -7,7 +7,7 @@
id: "-1", content: "", msg: "添加" } %>
</div>
<div class="box graduation-standards-list-container">
<div class="box admin-list-container graduation-standards-list-container">
<%= render(partial: 'admins/graduation_standards/shared/list', locals: { standards: @standards }) %>
</div>

@ -29,7 +29,7 @@
<%= javascript_void_link '批量同意', class: 'btn btn-outline-primary btn-sm batch-agree-btn' %>
</div>
<div class="box identity-authentication-list-container">
<div class="box admin-list-container identity-authentication-list-container">
<%= render(partial: 'admins/identity_authentications/shared/list', locals: { applies: @applies }) %>
</div>

@ -11,7 +11,7 @@
<%= javascript_void_link '新建', class: 'btn btn-primary', data: { toggle: 'modal', target: '.admin-create-laboratory-modal' } %>
</div>
<div class="box laboratory-list-container">
<div class="box admin-list-container laboratory-list-container">
<%= render(partial: 'admins/laboratories/shared/list', locals: { laboratories: @laboratories }) %>
</div>

@ -38,7 +38,7 @@
<%= javascript_void_link('添加实训', class: 'btn btn-primary', data: { toggle: 'modal', target: '.admin-add-laboratory-shixun-modal' }) %>
</div>
<div class="box laboratory-shixun-list-container" data-id="<%= current_laboratory.id %>">
<div class="box admin-list-container laboratory-shixun-list-container" data-id="<%= current_laboratory.id %>">
<%= render partial: 'admins/laboratory_shixuns/shared/list', locals: { laboratory_shixuns: @laboratory_shixuns } %>
</div>

@ -38,7 +38,7 @@
<%= javascript_void_link('添加课程', class: 'btn btn-primary', data: { toggle: 'modal', target: '.admin-add-laboratory-subject-modal' }) %>
</div>
<div class="box laboratory-subject-list-container" data-id="<%= current_laboratory.id %>">
<div class="box admin-list-container laboratory-subject-list-container" data-id="<%= current_laboratory.id %>">
<%= render partial: 'admins/laboratory_subjects/shared/list', locals: { laboratory_subjects: @laboratory_subjects } %>
</div>

@ -25,7 +25,7 @@
<% end %>
</div>
<div class="box library-applies-list-container">
<div class="box admin-list-container library-applies-list-container">
<%= render(partial: 'admins/library_applies/shared/list', locals: { applies: @library_applies }) %>
</div>

@ -2,6 +2,6 @@
<% add_admin_breadcrumb('本科专业目录') %>
<% end %>
<div class="box major-informations-list-container">
<div class="box admin-list-container major-informations-list-container">
<%= render(partial: 'admins/major_informations/shared/list', locals: { majors: @disciplines }) %>
</div>

@ -16,7 +16,7 @@
</div>
<% end %>
<div class="box mirror-repository-list-container">
<div class="box admin-list-container mirror-repository-list-container">
<%= render partial: 'admins/mirror_repositories/shared/list', locals: { mirrors: @mirrors } %>
</div>

@ -9,6 +9,6 @@
<%= link_to '新建', new_admins_mirror_repository_mirror_script_path(current_mirror), class: 'btn btn-primary' %>
</div>
<div class="box mirror-script-list-container">
<div class="box admin-list-container mirror-script-list-container">
<%= render partial: 'admins/mirror_scripts/shared/list', locals: { mirror: current_mirror, scripts: @scripts } %>
</div>

@ -9,6 +9,6 @@
<% end %>
</div>
<div class="box myshixun-list-container">
<div class="box admin-list-container myshixun-list-container">
<%= render(partial: 'admins/myshixuns/shared/list', locals: { myshixuns: @myshixuns, finish_game_count: @finish_game_count, total_score: @total_score }) %>
</div>

@ -11,7 +11,7 @@
<%= javascript_void_link('添加', class: 'btn btn-primary', data: { toggle: 'modal', target: '.admin-select-school-modal' }) %>
</div>
<div class="box partner-list-container">
<div class="box admin-list-container partner-list-container">
<%= render 'admins/partners/shared/list', partners: @partners %>
</div>

@ -10,7 +10,9 @@
<% if partners.present? %>
<% partners.each do |partner| %>
<tr class="partner-item-<%= partner.id %>">
<td class="text-left"><%= partner.school&.name || partner.name %></td>
<td class="text-left">
<%= link_to partner.school&.name || partner.name, customers_partner_path(partner), target: '_blank' %>
</td>
<td><%= partner.created_at&.strftime('%Y-%m-%d %H:%M') %></td>
<td>
<%= link_to '查看', admins_partner_customers_path(partner), class: 'action' %>

@ -29,7 +29,7 @@
<%= javascript_void_link '批量同意', class: 'btn btn-outline-primary btn-sm batch-agree-btn' %>
</div>
<div class="box professional-authentication-list-container">
<div class="box admin-list-container professional-authentication-list-container">
<%= render(partial: 'admins/professional_authentications/shared/list', locals: { applies: @applies }) %>
</div>

@ -25,7 +25,7 @@
<% end %>
</div>
<div class="box project-package-applies-list-container">
<div class="box admin-list-container project-package-applies-list-container">
<%= render(partial: 'admins/project_package_applies/shared/list', locals: { applies: @package_applies}) %>
</div>

@ -44,6 +44,6 @@
</form>
</div>
<div class="box school-statistic-list-container">
<div class="box admin-list-container school-statistic-list-container">
<%= render partial: 'admins/school_statistics/shared/list', locals: { statistics: @statistics } %>
</div>

@ -11,6 +11,6 @@
<%#= javascript_void_link '新建单位', class: 'btn btn-primary', data: { toggle: 'modal', target: '.admin-create-school-modal' } %>
</div>
<div class="box school-list-container">
<div class="box admin-list-container school-list-container">
<%= render partial: 'admins/schools/shared/list', locals: { schools: @schools } %>
</div>

@ -25,7 +25,7 @@
<% end %>
</div>
<div class="box shixun-authorization-list-container">
<div class="box admin-list-container shixun-authorization-list-container">
<%= render(partial: 'admins/shixun_authorizations/shared/list', locals: { applies: @applies, shixun_map: @shixun_map }) %>
</div>

@ -69,7 +69,7 @@
<% end %>
</div>
<div class="box shixun-settings-list-container">
<div class="box admin-list-container shixun-settings-list-container">
<%= render partial: 'admins/shixun_settings/shared/list', locals: { shixun_settings: @shixun_settings } %>
</div>

@ -27,6 +27,6 @@
<a href="javascript:void(0)" class="btn btn-primary" id="shixuns-export" data-disable-with = '导出中...'>导出</a>
</div>
<div class="box shixuns-list-container">
<div class="box admin-list-container shixuns-list-container">
<%= render partial: 'admins/shixuns/shared/list', locals: { shixuns: @shixuns } %>
</div>

@ -25,7 +25,7 @@
<% end %>
</div>
<div class="box subject-authorization-list-container">
<div class="box admin-list-container subject-authorization-list-container">
<%= render(partial: 'admins/subject_authorizations/shared/list',
locals: { applies: @applies, subject_map: @subject_map, challenge_count_map: @challenge_count_map }) %>
</div>

@ -34,7 +34,7 @@
<% end %>
</div>
<div class="box subject-list-container">
<div class="box admin-list-container subject-list-container">
<%= render partial: 'admins/subjects/shared/list', locals: { subjects: @subjects } %>
</div>

@ -22,6 +22,6 @@
<%= javascript_void_link '导出', class: 'btn btn-outline-primary export-action', 'data-url': export_admins_user_statistics_path(format: :xlsx) %>
</div>
<div class="box user-statistic-list-container">
<div class="box admin-list-container user-statistic-list-container">
<%= render partial: 'admins/user_statistics/shared/list', locals: { users: @users } %>
</div>

@ -31,7 +31,7 @@
<%= javascript_void_link '导入课堂成员', class: 'btn btn-secondary btn-sm ml-2', data: { toggle: 'modal', target: '.admin-import-course-member-modal'} %>
</div>
<div class="box users-list-container">
<div class="box admin-list-container users-list-container">
<%= render partial: 'admins/users/shared/user_list', locals: { users: @users } %>
</div>

@ -25,7 +25,7 @@
<% end %>
</div>
<div class="box video-applies-list-container">
<div class="box admin-list-container video-applies-list-container">
<%= render(partial: 'admins/video_applies/shared/list', locals: { applies: @video_applies}) %>
</div>

@ -14,7 +14,7 @@
<li class="nav-item"><a class="nav-link" href="/shixuns">实训项目</a></li>
<li class="nav-item"><a class="nav-link" href="/competitions">在线竞赛</a></li>
<li class="nav-item"><a class="nav-link" href="/moop_cases">教学案例</a></li>
<li class="nav-item"><a class="nav-link" href="/crowdsourcing">众包创新</a></li>
<!-- <li class="nav-item"><a class="nav-link" href="/crowdsourcing">众包创新</a></li>-->
<li class="nav-item"><a class="nav-link" href="/forums">交流问答</a></li>
</ul>
</div>

@ -6,6 +6,7 @@ json.user_ranks @user_ranks.each do |user_rank|
json.user_name user_rank.user.real_name
json.cost_time rank == 0 && user_rank.cost_time ? "--" : com_spend_time(user_rank.cost_time)
json.score rank == 0 ? "--" : user_rank.score.round(2)
json.competition_prize user_rank.competition_prize
end
json.teams @records.each do |record|
@ -18,4 +19,5 @@ json.teams @records.each do |record|
json.school_name school_name
json.score record&.score&.round(2)
json.spend_time record.cost_time ? com_spend_time(record.cost_time) : "--"
json.competition_prize record.competition_prize
end

@ -1,6 +1,6 @@
json.leader @leader
if @leader
if @leader || User.current.admin_or_business?
json.bank_account @bank_account
json.bank_account_editable @bank_account_editable
end

@ -35,7 +35,7 @@
<% end %>
</div>
<div class="box laboratory-shixun-list-container">
<div class="box admin-list-container laboratory-shixun-list-container">
<%= render partial: 'cooperative/laboratory_shixuns/shared/list', locals: { laboratory_shixuns: @laboratory_shixuns } %>
</div>

@ -35,7 +35,7 @@
<% end %>
</div>
<div class="box laboratory-subject-list-container">
<div class="box admin-list-container laboratory-subject-list-container">
<%= render partial: 'cooperative/laboratory_subjects/shared/list', locals: { laboratory_subjects: @laboratory_subjects } %>
</div>

@ -7,7 +7,7 @@
<%= javascript_void_link '添加管理员', class: 'btn btn-primary btn-sm', data: { toggle: 'modal', target: '.cooperative-add-laboratory-user-modal'} %>
</div>
<div class="box laboratory-user-list-container">
<div class="box admin-list-container laboratory-user-list-container">
<%= render partial: 'cooperative/laboratory_users/shared/list', locals: { laboratory_users: @laboratory_users } %>
</div>

@ -13,7 +13,7 @@
<%= javascript_include_tag 'college', 'data-turbolinks-track': 'reload' %>
</head>
<% body_class = [params[:controller].gsub(/\//, '-').gsub('_', '-'), params[:action], 'page'].join('-') %>
<% body_class = [params[:controller].gsub(/\//, '-').gsub('_', '-'), params[:action].gsub(/\//, '-').gsub('_', '-'), 'page'].join('-') %>
<body class="<%= body_class %>">
<%= render 'colleges/shared/navbar' %>
<!-- Page Content -->

@ -0,0 +1,25 @@
<div class="container mt-3 px-0 bg-white">
<div class="custom-nav">
<div class="custom-nav-item">
<%= link_to '客户列表', customers_partner_path(current_partner), class: 'custom-nav-link active' %>
</div>
<% if manager_permission? %>
<div class="custom-nav-item">
<%= link_to '权限管理', partner_manager_groups_partner_path(current_partner), class: 'custom-nav-link' %>
</div>
<% end %>
</div>
<div class="customer-list-container">
<div class="box customer-list-form">
<%= form_tag(customers_partner_path(current_partner), method: :get, class: 'form-inline search-form', remote: true) do %>
<%= text_field_tag(:keyword, params[:keyword], class: 'form-control col-md-4 ml-3', placeholder: '单位名称检索') %>
<%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %>
<% end %>
</div>
<div class="customer-list-body" data-id="<%= current_partner.id %>">
<%= render partial: 'partners/shared/customer_list', locals: { customers: @customers } %>
</div>
</div>
</div>

@ -0,0 +1 @@
$('.customer-list-body').html("<%= j(render partial: 'partners/shared/customer_list', locals: { customers: @customers }) %>");

@ -0,0 +1,11 @@
var $container = $('.manager-group-list-body');
var $managerGroupItem = $container.find('.manager-group-item-<%= @manager_group.id %>');
if($managerGroupItem.length > 0){
$managerGroupItem.find('.manager-group-name').html('<%= @manager_group.name %>');
} else {
$container.append('<%= j(render partial: 'partners/shared/manager_group_item', locals: { manager_group: @manager_group }) %>');
}
$('.partner-save-manager-group-modal').modal('hide');
showSuccessFlash();

@ -0,0 +1,25 @@
<div class="container mt-3 px-0">
<div class="custom-nav bg-white">
<div class="custom-nav-item">
<%= link_to '客户列表', customers_partner_path(current_partner), class: 'custom-nav-link' %>
</div>
<div class="custom-nav-item">
<%= link_to '权限管理', partner_manager_groups_partner_path(current_partner), class: 'custom-nav-link active' %>
</div>
</div>
<div class="manager-group-list-container">
<div class="box search-form-container customer-list-form bg-white">
<div class="flex-1">共<span class="text-danger px-1"><%= @manager_groups.size %></span>个权限组</div>
<%= javascript_void_link('新增权限组', class: 'btn btn-primary btn-sm add-manager-group-btn',
data: { toggle: 'modal', target: '.partner-save-manager-group-modal' }) %>
</div>
<div class="manager-group-list-body" data-id="<%= current_partner.id %>">
<%= render partial: 'partners/shared/manager_group_item', collection: @manager_groups, as: :manager_group %>
</div>
</div>
</div>
<%= render partial: 'partners/shared/save_manager_group_modal' %>
<%= render partial: 'partners/shared/add_partner_manager_modal' %>

@ -0,0 +1,6 @@
var $managerGroupContainer = $('.manager-group-list-body .manager-group-item-<%= @manager_group.id %>');
$managerGroupContainer.find('.partner-manager-body')
.html('<%= j(render partial: 'partners/shared/partner_managers', locals: { manager_group: @manager_group }) %>');
showSuccessFlash();
$('.partner-add-partner-manager-modal').modal('hide');

@ -0,0 +1,30 @@
<div class="modal fade partner-add-partner-manager-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="partner-add-partner-manager-form">
<%= hidden_field_tag(:manager_group_id, nil, id: nil) %>
<div class="form-group d-flex">
<label class="col-form-label">管理员:</label>
<div class="d-flex flex-column-reverse w-75">
<select id="user_ids" name="user_ids" class="form-control partner-manager-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,53 @@
<% can_manager = manager_permission? %>
<table class="table table-hover text-center customer-list-table">
<thead class="thead-light">
<tr>
<% if can_manager %>
<th width="15%" class="text-left">单位名称</th>
<th width="10%">权限控制</th>
<% else %>
<th width="25%" class="text-left">单位名称</th>
<% end %>
<th width="6%">教师</th>
<th width="6%">学生</th>
<th width="6%">课堂</th>
<th width="8%">发布实训</th>
<th width="10%">实训报告</th>
<th width="14%">最新课堂动态时间</th>
<th width="10%">使用详情</th>
</tr>
</thead>
<tbody>
<% if customers.present? %>
<%- manager_group_options = current_partner.partner_manager_groups.without_admin.map{ |g| [g.name, g.id] }.unshift(['选择权限组', '']) -%>
<% customers.each do |customer| %>
<tr class="customer-item-<%= customer.id %>">
<% if can_manager %>
<td class="text-left"><%= customer.school.name %></td>
<td>
<%= select_tag(:manager_group, options_for_select(manager_group_options, customer.partner_manager_group_id),
data: { id: customer.id, last: customer.partner_manager_group_id },
id: nil, class: 'form-control manager-group-select') %>
</td>
<% else %>
<td class="text-left"><%= customer.school.name %></td>
<% end %>
<td><%= display_text customer.display_extra_data(:teacher_count) %></td>
<td><%= display_text customer.display_extra_data(:student_count) %></td>
<td><%= display_text customer.display_extra_data(:course_count) %></td>
<td><%= display_text customer.display_extra_data(:shixun_count) %></td>
<td><%= display_text customer.display_extra_data(:shixun_report_count) %></td>
<td><%= display_text customer.display_extra_data(:course_time)&.strftime('%Y-%m-%d %H:%M') %></td>
<td>
<%= link_to('查看', statistics_college_path(customer.school), target: '_blank') %>
</td>
</tr>
<% end %>
<% else %>
<%= render 'admins/shared/no_data_for_table' %>
<% end %>
</tbody>
</table>
<%= render partial: 'admins/shared/paginate', locals: { objects: customers } %>

@ -0,0 +1,29 @@
<div class="card manager-group-item manager-group-item-<%= manager_group.id %>">
<div class="card-header">
<div class="card-header-left">
<span class="manager-group-name"><%= manager_group.name %></span>
<% if manager_group.admin? %>
<span class="text-secondary font-12">(访问权限范围:客户列表中的全部客户)</span>
<% else %>
<span class="text-secondary font-12">(访问权限范围:客户列表中“权限控制”勾选了本组的客户)</span>
<% end %>
</div>
<% unless manager_group.admin? %>
<%= link_to 'javascript:void(0)', class: 'action',
data: { toggle: 'modal', target: '.partner-save-manager-group-modal', id: manager_group.id, name: manager_group.name } do %>
<i class="fa fa-lg fa-fw fa-pencil"></i>
<% end %>
<%= delete_link '删除', remove_manager_group_partner_path(current_partner, manager_group_id: manager_group.id, element: ".manager-group-item-#{manager_group.id}"), class: 'action text-danger' do %>
<i class="fa fa-lg fa-fw fa-trash-o"></i>
<% end %>
<% end %>
</div>
<div class="card-body">
<div class="partner-manager-body">
<%= render partial: 'partners/shared/partner_managers', locals: { manager_group: manager_group } %>
</div>
</div>
</div>

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

Loading…
Cancel
Save