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

dev_aliyun_beta
daiao 6 years ago
commit 2ecee37ae9

@ -11,6 +11,7 @@
//= require select2
//= require jquery.cxselect
//= require bootstrap-datepicker
//= require bootstrap.viewer
//= require_tree ./i18n
//= require_tree ./admins
@ -25,6 +26,9 @@ $(document).on('turbolinks:load', function(){
$('[data-toggle="tooltip"]').tooltip();
$('[data-toggle="popover"]').popover();
// 图片查看大图
$('img.preview-image').bootstrapViewer();
// flash alert提示框自动关闭
if($('.admin-alert-container .alert').length > 0){
setTimeout(function(){
@ -33,10 +37,25 @@ $(document).on('turbolinks:load', function(){
}
});
$(document).on("turbolinks:before-cache", function () {
$('[data-toggle="tooltip"]').tooltip('hide');
$('[data-toggle="popover"]').popover('hide');
});
// var progressBar = new Turbolinks.ProgressBar();
// $(document).on('ajax:send', function(event){
// console.log('ajax send', event);
// progressBar.setValue(0)
// progressBar.show()
// });
//
// $(document).on('ajax:complete', function(event){
// console.log('ajax complete', event);
// progressBar.setValue(1)
// progressBar.hide() // 分页时不触发,奇怪
// });
// $(document).on('ajax:success', function(event){
// console.log('ajax success', event);
// });
// $(document).on('ajax:error', function(event){
// console.log('ajax error', event);
// });
$(function () {
});

@ -0,0 +1,54 @@
$(document).on('turbolinks:load', function() {
var $refuseModal = $('.admin-common-refuse-modal');
if ($refuseModal.length > 0) {
var $form = $refuseModal.find('form.admin-common-refuse-form');
var $applyIdInput = $refuseModal.find('.modal-body input[name="apply_id"]');
$form.validate({
errorElement: 'span',
errorClass: 'danger text-danger',
rules: {
reason: {
required: true,
maxlength: 200
},
}
});
// modal ready fire
$refuseModal.on('show.bs.modal', function (event) {
var $link = $(event.relatedTarget);
var applyId = $link.data('id');
var url = $link.data('url');
$applyIdInput.val(applyId);
$form.data('url', url);
});
// modal visited fire
$refuseModal.on('shown.bs.modal', function(){
$refuseModal.find('.modal-body input[name="reason"]').focus();
});
$refuseModal.on('hide.bs.modal', function () {
$applyIdInput.val('');
$form.data('url', '');
})
$refuseModal.on('click', '.submit-btn', function(){
$form.find('.error').html('');
if ($form.valid()) {
var url = $form.data('url');
$.ajax({
method: 'POST',
dataType: 'script',
url: url,
data: $form.serialize(),
}).done(function(){
$refuseModal.modal('hide');
});
}
});
}
});

@ -0,0 +1,18 @@
$(document).on('turbolinks:load', function() {
if ($('body.admins-identity-authentications-index-page').length > 0) {
var $searchFrom = $('.identity-authentication-list-form');
$searchFrom.on('click', '.search-form-tab', function(){
var $link = $(this);
$searchFrom.find('input[name="keyword"]').val('');
$searchFrom.find('select[name="status"]').val('processed');
if($link.data('value') === 'processed'){
$searchFrom.find('.status-filter').show();
} else {
$searchFrom.find('.status-filter').hide();
}
});
}
})

@ -0,0 +1,18 @@
$(document).on('turbolinks:load', function() {
if ($('body.admins-professional-authentications-index-page').length > 0) {
var $searchFrom = $('.professional-authentication-list-form');
$searchFrom.on('click', '.search-form-tab', function(){
var $link = $(this);
$searchFrom.find('input[name="keyword"]').val('');
$searchFrom.find('select[name="status"]').val('processed');
if($link.data('value') === 'processed'){
$searchFrom.find('.status-filter').show();
} else {
$searchFrom.find('.status-filter').hide();
}
});
}
})

@ -0,0 +1,10 @@
$(document).on('turbolinks:load', function() {
var $tabs = $('.search-form-container .search-form-tabs');
if ($tabs.length > 0) {
$tabs.on('click', '.search-form-tab', function(){
var $activeTab = $(this);
$tabs.find('.search-form-tab').removeClass('active');
$activeTab.addClass('active');
});
}
});

@ -0,0 +1,18 @@
$(document).on('turbolinks:load', function() {
if ($('body.admins-shixun-authorizations-index-page').length > 0) {
var $searchFrom = $('.shixun-authorization-list-form');
$searchFrom.on('click', '.search-form-tab', function(){
var $link = $(this);
$searchFrom.find('input[name="keyword"]').val('');
$searchFrom.find('select[name="status"]').val('processed');
if($link.data('value') === 'processed'){
$searchFrom.find('.status-filter').show();
} else {
$searchFrom.find('.status-filter').hide();
}
});
}
})

@ -0,0 +1,18 @@
$(document).on('turbolinks:load', function() {
if ($('body.admins-subject-authorizations-index-page').length > 0) {
var $searchFrom = $('.subject-authorization-list-form');
$searchFrom.on('click', '.search-form-tab', function(){
var $link = $(this);
$searchFrom.find('input[name="keyword"]').val('');
$searchFrom.find('select[name="status"]').val('processed');
if($link.data('value') === 'processed'){
$searchFrom.find('.status-filter').show();
} else {
$searchFrom.find('.status-filter').hide();
}
});
}
})

@ -0,0 +1,50 @@
/*
* Copyright 2018-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* WebSite: http://bootstrap-viewer.leftso.com
*/
$.fn.bootstrapViewer = function (options) {
$(this).on('click', function () {
var opts = $.extend({}, $.fn.bootstrapViewer.defaults, options);
var viewer = $('<div class="modal fade bs-example-modal-lg text-center" id="bootstrapViewer" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel" >\n' +
' <div class="modal-dialog modal-lg" style="display: inline-block; width: auto;">\n' +
' <div class="modal-content">\n' +
' <img' +
'\t\t\t class="carousel-inner img-responsive img-rounded img-viewer" \n' +
'\t\t\t onclick="$(\'#bootstrapViewer\').modal(\'hide\');setTimeout(function(){$(\'#bootstrapViewer\').remove();},200);"\n' +
'\t\t\t onmouseover="this.style.cursor=\'zoom-out\';" \n' +
'\t\t\t onmouseout="this.style.cursor=\'default\'" \n' +
'\t\t\t />\n' +
' </div>\n' +
' </div>\n' +
' </div>');
$('body').append(viewer);
if ($(this).attr(opts.src)) {
$("#bootstrapViewer").find(".img-viewer").attr("src", $(this).attr(opts.src));
$("#bootstrapViewer").modal();
} else {
throw "图片不存在"
}
})
$(this).on('mouseover', function () {
$(this).css('cursor', 'zoom-in');
})
}
$.fn.bootstrapViewer.defaults = {
src: 'src'
}

@ -25,7 +25,7 @@ a {
}
}
input.danger {
textarea.danger, input.danger {
border-color: #dc3545!important;
}
@ -43,4 +43,8 @@ label.error {
height: calc(1.5em + 0.75rem + 2px)
}
}
}
.flex-1 {
flex: 1;
}

@ -100,5 +100,11 @@
font-size: 24px;
}
}
.nav-tabs {
.nav-link {
padding: 0.5rem 2rem;
}
}
}

@ -0,0 +1,9 @@
.admins-identity-authentications-index-page {
.identity-authentication-list-container {
span {
&.apply-status-1 { color: #28a745; }
&.apply-status-2 { color: #dc3545; }
&.apply-status-3 { color: #6c757d; }
}
}
}

@ -0,0 +1,9 @@
.admins-professional-authentications-index-page {
.professional-authentication-list-container {
span {
&.apply-status-1 { color: #28a745; }
&.apply-status-2 { color: #dc3545; }
&.apply-status-3 { color: #6c757d; }
}
}
}

@ -0,0 +1,9 @@
.admins-shixun-authorizations-index-page {
.shixun-authorization-list-container {
span {
&.apply-status-1 { color: #28a745; }
&.apply-status-2 { color: #dc3545; }
&.apply-status-3 { color: #6c757d; }
}
}
}

@ -0,0 +1,9 @@
.admins-subject-authorizations-index-page {
.subject-authorization-list-container {
span {
&.apply-status-1 { color: #28a745; }
&.apply-status-2 { color: #dc3545; }
&.apply-status-3 { color: #6c757d; }
}
}
}

@ -0,0 +1,26 @@
class Admins::IdentityAuthenticationsController < Admins::BaseController
def index
params[:status] ||= 'pending'
applies = Admins::ApplyUserAuthenticationQuery.call(params.merge(type: 1))
@applies = paginate applies.preload(user: { user_extension: [:school, :department] })
end
def agree
Admins::IdentityAuths::AgreeApplyService.call(current_apply)
render_success_js
end
def refuse
Admins::IdentityAuths::RefuseApplyService.call(current_apply, params)
render_success_js
end
private
def current_apply
@_current_apply ||= ApplyUserAuthentication.real_name_auth.find(params[:id])
end
end

@ -0,0 +1,26 @@
class Admins::ProfessionalAuthenticationsController < Admins::BaseController
def index
params[:status] ||= 'pending'
applies = Admins::ApplyUserAuthenticationQuery.call(params.merge(type: 2))
@applies = paginate applies.preload(user: { user_extension: [:school, :department] })
end
def agree
Admins::ProfessionalAuths::AgreeApplyService.call(current_apply)
render_success_js
end
def refuse
Admins::ProfessionalAuths::RefuseApplyService.call(current_apply, params)
render_success_js
end
private
def current_apply
@_current_apply ||= ApplyUserAuthentication.professional_auth.find(params[:id])
end
end

@ -0,0 +1,48 @@
class Admins::ShixunAuthorizationsController < Admins::BaseController
def index
params[:status] ||= 'pending'
applies = ApplyAction.where(container_type: 'ApplyShixun')
status =
case params[:status]
when 'pending' then 0
when 'processed' then [1, 2]
when 'agreed' then 1
when 'refused' then 2
else 0
end
applies = applies.where(status: status) if status.present?
# 关键字模糊查询
keyword = params[:keyword].to_s.strip
if keyword.present?
applies = applies.joins('JOIN shixuns ON shixuns.id = apply_actions.container_id')
.where('shixuns.name LIKE :keyword', keyword: "%#{keyword}%")
end
applies = applies.order(updated_at: :desc)
@applies = paginate applies.includes(user: :user_extension)
shixun_ids = @applies.map(&:container_id)
@shixun_map = Shixun.where(id: shixun_ids).each_with_object({}) { |s, h| h[s.id] = s }
end
def agree
Admins::ShixunAuths::AgreeApplyService.call(current_apply, current_user)
render_success_js
end
def refuse
Admins::ShixunAuths::RefuseApplyService.call(current_apply, current_user, params)
render_success_js
end
private
def current_apply
@_current_apply ||= ApplyAction.where(container_type: 'ApplyShixun').find(params[:id])
end
end

@ -0,0 +1,49 @@
class Admins::SubjectAuthorizationsController < Admins::BaseController
def index
params[:status] ||= 'pending'
applies = ApplyAction.where(container_type: 'ApplySubject')
status =
case params[:status]
when 'pending' then 0
when 'processed' then [1, 2]
when 'agreed' then 1
when 'refused' then 2
else 0
end
applies = applies.where(status: status) if status.present?
# 关键字模糊查询
keyword = params[:keyword].to_s.strip
if keyword.present?
applies = applies.joins('JOIN subjects ON subjects.id = apply_actions.container_id')
.where('subjects.name LIKE :keyword', keyword: "%#{keyword}%")
end
applies = applies.order(updated_at: :desc)
@applies = paginate applies.includes(user: :user_extension)
subject_ids = @applies.map(&:container_id)
@subject_map = Subject.where(id: subject_ids).each_with_object({}) { |s, h| h[s.id] = s }
@challenge_count_map = Challenge.joins(shixun: :stage_shixuns).where(st: 0, stage_shixuns: { subject_id: subject_ids}).group('subject_id').count
end
def agree
Admins::SubjectAuths::AgreeApplyService.call(current_apply, current_user)
render_success_js
end
def refuse
Admins::SubjectAuths::RefuseApplyService.call(current_apply, current_user, params)
render_success_js
end
private
def current_apply
@_current_apply ||= ApplyAction.where(container_type: 'ApplySubject').find(params[:id])
end
end

@ -2,7 +2,7 @@ module Admins::ErrorRescueHandler
extend ActiveSupport::Concern
included do
rescue_from Exception, Educoder::TipException do |e|
rescue_from Exception do |e|
raise e if Rails.env.development?
Util.logger_error e

@ -28,7 +28,7 @@ module Admins::RenderHelper
def internal_server_error
respond_to do |format|
format.html { render 'admins/shared/500' }
format.js { render_js_error(message) }
format.js { render_js_error('系统错误') }
format.json { render status: 500, json: { message: '系统错误' } }
end
end
@ -40,6 +40,7 @@ module Admins::RenderHelper
def render_delete_success
render_js_template 'admins/shared/delete'
end
alias_method :render_success_js, :render_delete_success
def render_js_error(message)
render_js_template 'admins/shared/error', locals: { message: message }

@ -0,0 +1,102 @@
module Admins::BaseHelper
def sidebar_item_group(url, text, **opts)
link_opts = url.start_with?('/') ? {} : { 'data-toggle': 'collapse', 'aria-expanded': false }
content =
link_to url, link_opts do
content_tag(:i, '', class: "fa fa-#{opts[:icon]}", 'data-toggle': 'tooltip', 'data-placement': 'right', 'data-boundary': 'window', title: text) +
content_tag(:span, text)
end
content +=
content_tag(:ul, id: url[1..-1], class: 'collapse list-unstyled', "data-parent": '#sidebar') do
yield
end
raw content
end
def sidebar_item(url, text, **opts)
content =
link_to url, 'data-controller': opts[:controller] do
content_tag(:i, '', class: "fa fa-#{opts[:icon]}", 'data-toggle': 'tooltip', 'data-placement': 'right', 'data-boundary': 'window', title: text) +
content_tag(:span, text)
end
raw content
end
def admin_sidebar_controller
key = params[:controller].to_s.gsub(/\//, '-')
SidebarUtil.controller_name(key) || key
end
def define_admin_breadcrumbs(&block)
content_for(:setup_admin_breadcrumb, &block)
end
def add_admin_breadcrumb(text, url = nil)
@_admin_breadcrumbs ||= []
@_admin_breadcrumbs << OpenStruct.new(text: text, url: url)
end
def display_text(str, default = '--')
str.presence || default
end
def overflow_hidden_span(text, width: 300)
opts = { class: 'd-inline-block text-truncate', style: "max-width: #{width}px" }
opts.merge!('data-toggle': 'tooltip', title: text) if text != '--'
content_tag(:span, text, opts)
end
def sort_tag(content = '', **opts)
options = {}
options[:sort_by] = opts.delete(:name)
is_current_sort = params[:sort_by].to_s == options[:sort_by]
options[:sort_direction] = is_current_sort && params[:sort_direction].to_s == 'desc' ? 'asc' : 'desc'
path = opts.delete(:path) + "?" + unsafe_params.merge(options).to_query
arrow_class = case params[:sort_direction].to_s
when 'desc' then 'fa-sort-amount-desc'
when 'asc' then 'fa-sort-amount-asc'
else ''
end
opts[:style] = "#{opts[:style]} ;position: relative;"
content_tag(:span, opts) do
link_to path, remote: true do
content = content_tag(:span) { yield } if block_given?
content += content_tag(:i, '', class: "fa color-light-green ml-1 #{arrow_class}", style: 'position: absolute;top:0;') if is_current_sort
raw content
end
end
end
def javascript_void_link(name, **opts)
raw link_to(name, 'javascript:void(0)', opts)
end
def agree_link(name, url, **opts)
klass = ['action agree-action', opts.delete(:class)].compact.join(' ')
refresh_url_data = "refresh_url=#{CGI::escape(request.fullpath)}"
url = url + (url.index('?') ? '&' : '?') + refresh_url_data
raw link_to(name, url, { method: :post, remote: true, class: klass, 'data-confirm': '确认审核通过?'}.merge(opts))
end
def delete_link(name, url, **opts)
klass = ['action delete-action', opts.delete(:class)].compact.join(' ')
refresh_url_data = "refresh_url=#{CGI::escape(request.fullpath)}"
url = url + (url.index('?') ? '&' : '?') + refresh_url_data
raw link_to(name, url, { method: :delete, remote: true, class: klass, 'data-confirm': '确认删除?'}.merge(opts))
end
def unsafe_params
params.except(:controller, :action).to_unsafe_h
end
end

@ -158,10 +158,22 @@ module ApplicationHelper
disk_auth_filename('UserAuthentication', source_id, 'ID')
end
def auth_file_url(source_type, source_id, type)
File.join('/images', relative_path, source_type, "#{source_id}#{type}")
end
def real_name_auth_file_url(source_id)
auth_file_url('UserAuthentication', source_id, 'ID')
end
def disk_professional_auth_filename(source_id)
disk_auth_filename('UserAuthentication', source_id, 'PRO')
end
def professional_auth_file_url(source_id)
auth_file_url('UserAuthentication', source_id, 'PRO')
end
def shixun_url_to_avatar(shixun)
if File.exist?(disk_filename(shixun.class, shixun.id))
File.join("images/#{relative_path}", "#{shixun.class}", "#{shixun.id}")
@ -386,95 +398,6 @@ module ApplicationHelper
m_t&.include?("src=\"") ? m_t&.gsub("src=\"","src=\"#{origin_url}") : m_t
end
# =========== Admin Helpers Begin ===========
def sidebar_item_group(url, text, **opts)
link_opts = url.start_with?('/') ? {} : { 'data-toggle': 'collapse', 'aria-expanded': false }
content =
link_to url, link_opts do
content_tag(:i, '', class: "fa fa-#{opts[:icon]}", 'data-toggle': 'tooltip', 'data-placement': 'right', 'data-boundary': 'window', title: text) +
content_tag(:span, text)
end
content +=
content_tag(:ul, id: url[1..-1], class: 'collapse list-unstyled', "data-parent": '#sidebar') do
yield
end
raw content
end
def sidebar_item(url, text, **opts)
content =
link_to url, 'data-controller': opts[:controller] do
content_tag(:i, '', class: "fa fa-#{opts[:icon]}", 'data-toggle': 'tooltip', 'data-placement': 'right', 'data-boundary': 'window', title: text) +
content_tag(:span, text)
end
raw content
end
def admin_sidebar_controller
key = params[:controller].to_s.gsub(/\//, '-')
SidebarUtil.controller_name(key) || key
end
def define_admin_breadcrumbs(&block)
content_for(:setup_admin_breadcrumb, &block)
end
def add_admin_breadcrumb(text, url = nil)
@_admin_breadcrumbs ||= []
@_admin_breadcrumbs << OpenStruct.new(text: text, url: url)
end
def display_text(str, default = '--')
str.presence || default
end
def overflow_hidden_span(text, width: 300)
opts = { class: 'd-inline-block text-truncate', style: "max-width: #{width}px" }
opts.merge!('data-toggle': 'tooltip', title: text) if text != '--'
content_tag(:span, text, opts)
end
def sort_tag(content = '', **opts)
options = {}
options[:sort_by] = opts.delete(:name)
is_current_sort = params[:sort_by].to_s == options[:sort_by]
options[:sort_direction] = is_current_sort && params[:sort_direction].to_s == 'desc' ? 'asc' : 'desc'
path = opts.delete(:path) + "?" + params.slice(:action, :controller).merge(options).to_unsafe_h.to_query
arrow_class = case params[:sort_direction].to_s
when 'desc' then 'fa-sort-amount-desc'
when 'asc' then 'fa-sort-amount-asc'
else ''
end
opts[:style] = "#{opts[:style]} ;position: relative;"
content_tag(:span, opts) do
link_to path, remote: true do
content = content_tag(:span) { yield } if block_given?
content += content_tag(:i, '', class: "fa color-light-green ml-1 #{arrow_class}", style: 'position: absolute;top:0;') if is_current_sort
raw content
end
end
end
def javascript_void_link(name, **opts)
raw link_to(name, 'javascript:void(0)', opts)
end
def delete_link(name, url, **opts)
klass = ['action delete-action', opts.delete(:class)].compact.join(' ')
refresh_url_data = "refresh_url=#{CGI::escape(request.fullpath)}"
url = url + (url.index('?') ? '&' : '?') + refresh_url_data
raw link_to(name, url, { method: :delete, remote: true, class: klass, 'data-confirm': '确认删除?'}.merge(opts))
end
# =========== Admin Helpers End ===========
end

@ -0,0 +1,40 @@
module Util::FileManage
module_function
# 不同的类型扩展不同的目录
def relative_path
"avatars"
end
def storage_path
File.join(Rails.root, "public", "images", relative_path)
end
def disk_filename(source_type,source_id,image_file=nil)
File.join(storage_path, "#{source_type}", "#{source_id}")
end
def disk_auth_filename(source_type, source_id, type)
File.join(storage_path, "#{source_type}", "#{source_id}#{type}")
end
def disk_real_name_auth_filename(source_id)
disk_auth_filename('UserAuthentication', source_id, 'ID')
end
def auth_file_url(source_type, source_id, type)
File.join('/images', relative_path, source_type, "#{source_id}#{type}")
end
def real_name_auth_file_url(source_id)
auth_file_url('UserAuthentication', source_id, 'ID')
end
def disk_professional_auth_filename(source_id)
disk_auth_filename('UserAuthentication', source_id, 'PRO')
end
def professional_auth_file_url(source_id)
auth_file_url('UserAuthentication', source_id, 'PRO')
end
end

@ -1,8 +1,16 @@
# 申请消息
class ApplyAction < ApplicationRecord
belongs_to :user
has_many :tidings, :as => :container, :dependent => :destroy
after_create :send_tiding
def status_text
I18n.t!("apply_action.status.#{status}")
rescue I18n::MissingTranslationData
nil
end
def send_tiding
if container_type == 'TrialAuthorization' && status == 1
tidings.create(user_id: user_id, trigger_user_id: 0, status: 1, viewed: 0, tiding_type: 'System',

@ -12,6 +12,12 @@ class ApplyUserAuthentication < ApplicationRecord
after_create :send_tiding
def status_text
I18n.t!("apply_user_authentication.status.#{status}")
rescue I18n::MissingTranslationData
nil
end
private
def send_tiding

@ -0,0 +1,34 @@
class Admins::ApplyUserAuthenticationQuery < ApplicationQuery
include CustomSortable
attr_reader :params
sort_columns :updated_at, default_by: :updated_at, default_direction: :desc
def initialize(params)
@params = params
end
def call
applies = ApplyUserAuthentication.where(auth_type: params[:type].presence || 1)
status =
case params[:status]
when 'pending' then 0
when 'processed' then [1, 2]
when 'agreed' then 1
when 'refused' then 2
else 0
end
applies = applies.where(status: status) if status.present?
# 关键字模糊查询
keyword = params[:keyword].to_s.strip
if keyword.present?
applies = applies.joins(user: { user_extension: :school })
.where('CONCAT(lastname,firstname) LIKE :keyword OR schools.name LIKE :keyword', keyword: "%#{keyword}%")
end
custom_sort(applies, params[:sort_by], params[:sort_direction])
end
end

@ -0,0 +1,38 @@
class Admins::IdentityAuths::AgreeApplyService < ApplicationService
attr_reader :apply, :user
def initialize(apply)
@apply = apply
@user = apply.user
end
def call
ActiveRecord::Base.transaction do
apply.update!(status: 1)
user.update!(authentication: true)
RewardGradeService.call(user, container_id: user.id, container_type: 'Authentication', score: 500)
deal_tiding!
delete_auth_file!
end
end
private
def deal_tiding!
apply.tidings.where(tiding_type: 'Apply').update_all(status: 1)
Tiding.create!(user_id: apply.user_id, trigger_user_id: 0,
container_id: apply.id, container_type: 'ApplyUserAuthentication',
belong_container_id: apply.user_id, belong_container_type: 'User',
status: 1, tiding_type: 'System')
end
def delete_auth_file!
path = Util::FileManage.disk_real_name_auth_filename(user.id)
File.delete(path) if File.exists?(path)
apply.update!(is_delete: true)
end
end

@ -0,0 +1,40 @@
class Admins::IdentityAuths::RefuseApplyService < ApplicationService
attr_reader :apply, :user, :params
def initialize(apply, params)
@apply = apply
@user = apply.user
@params = params
end
def call
ActiveRecord::Base.transaction do
apply.update!(status: 2, remarks: reason)
deal_tiding!
delete_auth_file!
end
end
private
def reason
params[:reason].to_s.strip
end
def deal_tiding!
apply.tidings.where(tiding_type: 'Apply').update_all(status: 1)
Tiding.create!(user_id: apply.user_id, trigger_user_id: 0,
container_id: apply.id, container_type: 'ApplyUserAuthentication',
belong_container_id: apply.user_id, belong_container_type: 'User',
status: 2, tiding_type: 'System')
end
def delete_auth_file!
path = Util::FileManage.disk_real_name_auth_filename(user.id)
File.delete(path) if File.exists?(path)
apply.update!(is_delete: true)
end
end

@ -0,0 +1,38 @@
class Admins::ProfessionalAuths::AgreeApplyService < ApplicationService
attr_reader :apply, :user
def initialize(apply)
@apply = apply
@user = apply.user
end
def call
ActiveRecord::Base.transaction do
apply.update!(status: 1)
user.update!(professional_certification: true)
RewardGradeService.call(user, container_id: user.id, container_type: 'Professional', score: 500)
deal_tiding!
delete_auth_file!
end
end
private
def deal_tiding!
apply.tidings.where(tiding_type: 'Apply').update_all(status: 1)
Tiding.create!(user_id: apply.user_id, trigger_user_id: 0,
container_id: apply.id, container_type: 'ApplyUserAuthentication',
belong_container_id: apply.user_id, belong_container_type: 'User',
status: 1, tiding_type: 'System')
end
def delete_auth_file!
path = Util::FileManage.disk_professional_auth_filename(user.id)
File.delete(path) if File.exists?(path)
apply.update!(is_delete: true)
end
end

@ -0,0 +1,40 @@
class Admins::ProfessionalAuths::RefuseApplyService < ApplicationService
attr_reader :apply, :user, :params
def initialize(apply, params)
@apply = apply
@user = apply.user
@params = params
end
def call
ActiveRecord::Base.transaction do
apply.update!(status: 2, remarks: reason)
deal_tiding!
delete_auth_file!
end
end
private
def reason
params[:reason].to_s.strip
end
def deal_tiding!
apply.tidings.where(tiding_type: 'Apply').update_all(status: 1)
Tiding.create!(user_id: apply.user_id, trigger_user_id: 0,
container_id: apply.id, container_type: 'ApplyUserAuthentication',
belong_container_id: apply.user_id, belong_container_type: 'User',
status: 2, tiding_type: 'System')
end
def delete_auth_file!
path = Util::FileManage.disk_professional_auth_filename(user.id)
File.delete(path) if File.exists?(path)
apply.update!(is_delete: true)
end
end

@ -0,0 +1,43 @@
class Admins::ShixunAuths::AgreeApplyService < ApplicationService
attr_reader :apply, :user, :shixun
def initialize(apply, user)
@apply = apply
@user = user
@shixun = Shixun.find(apply.container_id)
end
def call
ActiveRecord::Base.transaction do
apply.update!(status: 1, dealer_id: user.id)
shixun.update!(status: 2, publish_time: Time.now)
# 奖励金币、经验
reward_grade_and_experience!
deal_tiding!
end
end
private
def reward_grade_and_experience!
score = shixun.all_score
shixun_creator = shixun.user
RewardGradeService.call(shixun_creator, container_id: shixun.id, container_type: 'shixunPublish', score: score)
Experience.create!(user_id: shixun_creator.id, container_id: shixun.id, container_type: 'shixunPublish', score: score)
shixun_creator.update_column(:experience, shixun_creator.experience.to_i + score)
end
def deal_tiding!
apply.tidings.where(tiding_type: 'Apply', status: 0).update_all(status: 1)
Tiding.create!(user_id: apply.user_id, trigger_user_id: 0,
container_id: apply.id, container_type: 'ApplyAction',
parent_container_id: apply.container_id, parent_container_type: apply.container_type,
belong_container_id: apply.container_id, belong_container_type: 'Shixun',
status: 1, tiding_type: 'System')
end
end

@ -0,0 +1,35 @@
class Admins::ShixunAuths::RefuseApplyService < ApplicationService
attr_reader :apply, :user, :shixun, :params
def initialize(apply, user, params)
@apply = apply
@user = user
@shixun = Shixun.find(apply.container_id)
@params = params
end
def call
ActiveRecord::Base.transaction do
shixun.update!(status: 0)
apply.update!(status: 2, reason: reason, dealer_id: user.id)
deal_tiding!
end
end
private
def reason
params[:reason].to_s.strip
end
def deal_tiding!
apply.tidings.where(tiding_type: 'Apply', status: 0).update_all(status: 1)
Tiding.create!(user_id: apply.user_id, trigger_user_id: 0,
container_id: apply.id, container_type: 'ApplyAction',
parent_container_id: apply.container_id, parent_container_type: apply.container_type,
belong_container_id: apply.container_id, belong_container_type: 'Shixun',
status: 2, tiding_type: 'System')
end
end

@ -0,0 +1,30 @@
class Admins::SubjectAuths::AgreeApplyService < ApplicationService
attr_reader :apply, :user, :subject
def initialize(apply, user)
@apply = apply
@user = user
@subject = Subject.find(apply.container_id)
end
def call
ActiveRecord::Base.transaction do
apply.update!(status: 1, dealer_id: user.id)
subject.update!(status: 2, publish_time: Time.now)
deal_tiding!
end
end
private
def deal_tiding!
apply.tidings.where(tiding_type: 'Apply', status: 0).update_all(status: 1)
Tiding.create!(user_id: apply.user_id, trigger_user_id: 0,
container_id: apply.id, container_type: 'ApplyAction',
parent_container_id: apply.container_id, parent_container_type: apply.container_type,
belong_container_id: apply.container_id, belong_container_type: 'Subject',
status: 1, tiding_type: 'System')
end
end

@ -0,0 +1,35 @@
class Admins::SubjectAuths::RefuseApplyService < ApplicationService
attr_reader :apply, :user, :subject, :params
def initialize(apply, user, params)
@apply = apply
@user = user
@subject = Subject.find(apply.container_id)
@params = params
end
def call
ActiveRecord::Base.transaction do
subject.update!(status: 0)
apply.update!(status: 2, reason: reason, dealer_id: user.id)
deal_tiding!
end
end
private
def reason
params[:reason].to_s.strip
end
def deal_tiding!
apply.tidings.where(tiding_type: 'Apply', status: 0).update_all(status: 1)
Tiding.create!(user_id: apply.user_id, trigger_user_id: 0,
container_id: apply.id, container_type: 'ApplyAction',
parent_container_id: apply.container_id, parent_container_type: apply.container_type,
belong_container_id: apply.container_id, belong_container_type: 'Subject',
status: 2, tiding_type: 'System')
end
end

@ -0,0 +1,32 @@
<% define_admin_breadcrumbs do %>
<% add_admin_breadcrumb('实名认证') %>
<% end %>
<div class="box search-form-container flex-column mb-0 pb-0 identity-authentication-list-form">
<ul class="nav nav-tabs w-100 search-form-tabs">
<li class="nav-item">
<%= link_to '待审批', admins_identity_authentications_path(status: :pending), remote: true, 'data-value': 'pending',
class: "nav-link search-form-tab #{params[:status] == 'pending' ? 'active' : ''}" %>
</li>
<li class="nav-item">
<%= link_to '已审批', admins_identity_authentications_path(status: :processed), remote: true, 'data-value': 'processed',
class: "nav-link search-form-tab #{params[:status] != 'pending' ? 'active' : ''}" %>
</li>
</ul>
<%= form_tag(admins_identity_authentications_path(unsafe_params), method: :get, class: 'form-inline search-form justify-content-end mt-3', remote: true) do %>
<div class="form-group status-filter" style="<%= params[:status] != 'pending' ? '' : 'display: none;' %>">
<label for="status">审核状态:</label>
<% status_options = [['全部', 'processed'], ['已同意', 'agreed'], ['已拒绝', 'refused']] %>
<%= 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') %>
<% end %>
</div>
<div class="box identity-authentication-list-container">
<%= render(partial: 'admins/identity_authentications/shared/list', locals: { applies: @applies }) %>
</div>
<%= render(partial: 'admins/shared/admin_common_refuse_modal') %>

@ -0,0 +1 @@
$('.identity-authentication-list-container').html("<%= j( render partial: 'admins/identity_authentications/shared/list', locals: { applies: @applies } ) %>");

@ -0,0 +1,74 @@
<% is_processed = params[:status].to_s != 'pending' %>
<table class="table table-hover text-center identity-authentication-list-table">
<thead class="thead-light">
<tr>
<th width="8%">头像</th>
<th width="10%">姓名</th>
<th width="14%">身份证号</th>
<th width="20%">学校/单位</th>
<th width="12%">职称</th>
<% unless is_processed %>
<th width="8%">
照片
<i class="fa fa-question-circle" data-toggle="tooltip" data-html="true" data-placement="top" title="审核完成后自动删除图片"></i>
</th>
<% end %>
<th width="16%">时间</th>
<% if is_processed %>
<th width="14%">拒绝原因</th>
<th width="8%">状态</th>
<% else %>
<th width="20%">操作</th>
<% end %>
</tr>
</thead>
<tbody>
<% if applies.present? %>
<% applies.each do |apply| %>
<% user = apply.user %>
<tr class="identity-authentication-item identity-authentication-<%= apply.id %>">
<td>
<%= link_to "/users/#{user.login}", class: 'identity-authentication-avatar', target: '_blank', data: { toggle: 'tooltip', title: '个人主页' } do %>
<img src="/images/<%= url_to_avatar(user) %>" class="rounded-circle" width="40" height="40" />
<% end %>
</td>
<td><%= user.real_name %></td>
<td><%= user.ID_number %></td>
<td><%= raw [user.school_name.presence, user.department_name.presence].compact.join('<br/>') %></td>
<td><%= user.identity %> <%= raw user.user_extension.student? && user.student_id ? "<br/>#{user.student_id}" : '' %></td>
<% unless is_processed %>
<td>
<% if File.exists?(disk_real_name_auth_filename(user.id)) %>
<%= image_tag(real_name_auth_file_url(user.id).to_s + "?#{Time.now.to_i}", width: 40, height: 40, class: 'preview-image auth-image', data: { toggle: 'tooltip', title: '点击预览' }) %>
<% else %>
<%= content_tag(:span, '图片已删除', class: 'text-secondary') %>
<% end %>
</td>
<% end %>
<td><%= apply.updated_at.strftime('%Y-%m-%d %H:%M') %></td>
<% if is_processed %>
<td class="text-secondary"><%= overflow_hidden_span apply.remarks, width: 140 %></td>
<td><span class="apply-status-<%= apply.status %>"><%= apply.status_text %></span></td>
<% else %>
<td class="action-container">
<%= agree_link '同意', agree_admins_identity_authentication_path(apply, element: ".identity-authentication-#{apply.id}"), 'data-confirm': '确认审核通过?' %>
<%= javascript_void_link('拒绝', class: 'action refuse-action',
data: {
toggle: 'modal', target: '.admin-common-refuse-modal', id: apply.id,
url: refuse_admins_identity_authentication_path(apply, element: ".identity-authentication-#{apply.id}")
}) %>
</td>
<% end %>
</tr>
<% end %>
<% else %>
<%= render 'admins/shared/no_data_for_table' %>
<% end %>
</tbody>
</table>
<%= render partial: 'admins/shared/paginate', locals: { objects: applies } %>

@ -0,0 +1,32 @@
<% define_admin_breadcrumbs do %>
<% add_admin_breadcrumb('职业认证') %>
<% end %>
<div class="box search-form-container flex-column mb-0 pb-0 professional-authentication-list-form">
<ul class="nav nav-tabs w-100 search-form-tabs">
<li class="nav-item">
<%= link_to '待审批', admins_professional_authentications_path(status: :pending), remote: true, 'data-value': 'pending',
class: "nav-link search-form-tab #{params[:status] == 'pending' ? 'active' : ''}" %>
</li>
<li class="nav-item">
<%= link_to '已审批', admins_professional_authentications_path(status: :processed), remote: true, 'data-value': 'processed',
class: "nav-link search-form-tab #{params[:status] != 'pending' ? 'active' : ''}" %>
</li>
</ul>
<%= form_tag(admins_professional_authentications_path(unsafe_params), method: :get, class: 'form-inline search-form justify-content-end mt-3', remote: true) do %>
<div class="form-group status-filter" style="<%= params[:status] != 'pending' ? '' : 'display: none;' %>">
<label for="status">审核状态:</label>
<% status_options = [['全部', 'processed'], ['已同意', 'agreed'], ['已拒绝', 'refused']] %>
<%= 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') %>
<% end %>
</div>
<div class="box professional-authentication-list-container">
<%= render(partial: 'admins/professional_authentications/shared/list', locals: { applies: @applies }) %>
</div>
<%= render(partial: 'admins/shared/admin_common_refuse_modal') %>

@ -0,0 +1 @@
$('.professional-authentication-list-container').html("<%= j( render partial: 'admins/professional_authentications/shared/list', locals: { applies: @applies } ) %>");

@ -0,0 +1,72 @@
<% is_processed = params[:status].to_s != 'pending' %>
<table class="table table-hover text-center professional-authentication-list-table">
<thead class="thead-light">
<tr>
<th width="8%">头像</th>
<th width="14%">姓名</th>
<th width="28%">学校/单位</th>
<th width="12%">职称</th>
<% unless is_processed %>
<th width="10%">
照片
<i class="fa fa-question-circle" data-toggle="tooltip" data-html="true" data-placement="top" title="审核完成后自动删除图片"></i>
</th>
<% end %>
<th width="16%">时间</th>
<% if is_processed %>
<th width="14%">拒绝原因</th>
<th width="8%">状态</th>
<% else %>
<th width="18%">操作</th>
<% end %>
</tr>
</thead>
<tbody>
<% if applies.present? %>
<% applies.each do |apply| %>
<% user = apply.user %>
<tr class="professional-authentication-item professional-authentication-<%= apply.id %>">
<td>
<%= link_to "/users/#{user.login}", class: 'professional-authentication-avatar', target: '_blank', data: { toggle: 'tooltip', title: '个人主页' } do %>
<img src="/images/<%= url_to_avatar(user) %>" class="rounded-circle" width="40" height="40" />
<% end %>
</td>
<td><%= user.real_name %></td>
<td><%= raw [user.school_name.presence, user.department_name.presence].compact.join('<br/>') %></td>
<td><%= user.identity %> <%= raw user.user_extension.student? && user.student_id ? "<br/>#{user.student_id}" : '' %></td>
<% unless is_processed %>
<td>
<% if File.exists?(disk_professional_auth_filename(user.id)) %>
<%= image_tag(professional_auth_file_url(user.id).to_s + "?#{Time.now.to_i}", width: 40, height: 40, class: 'preview-image auth-image', data: { toggle: 'tooltip', title: '点击预览' }) %>
<% else %>
<%= content_tag(:span, '图片已删除', class: 'text-secondary') %>
<% end %>
</td>
<% end %>
<td><%= apply.updated_at.strftime('%Y-%m-%d %H:%M') %></td>
<% if is_processed %>
<td class="text-secondary"><%= overflow_hidden_span apply.remarks, width: 140 %></td>
<td><span class="apply-status-<%= apply.status %>"><%= apply.status_text %></span></td>
<% else %>
<td class="action-container">
<%= agree_link '同意', agree_admins_professional_authentication_path(apply, element: ".professional-authentication-#{apply.id}"), 'data-confirm': '确认审核通过?' %>
<%= javascript_void_link('拒绝', class: 'action refuse-action',
data: {
toggle: 'modal', target: '.admin-common-refuse-modal', id: apply.id,
url: refuse_admins_professional_authentication_path(apply, element: ".professional-authentication-#{apply.id}")
}) %>
</td>
<% end %>
</tr>
<% end %>
<% else %>
<%= render 'admins/shared/no_data_for_table' %>
<% end %>
</tbody>
</table>
<%= render partial: 'admins/shared/paginate', locals: { objects: applies } %>

@ -32,9 +32,9 @@
<div class="type-box ml-3">
<%= hidden_field_tag :data_type, params[:data_type] || 'grow' %>
<%= javascript_void_link '时段对比', class: "btn btn-outline-primary btn-sm contrast-btn #{params[:data_type] == 'contrast' ? 'active' : ''}",
<%= javascript_void_link '时段对比', class: "btn btn-outline-info btn-sm contrast-btn #{params[:data_type] == 'contrast' ? 'active' : ''}",
data: { toggle: 'tooltip', trigger: 'hover', title: '请在左侧分别选择需进行对比的两个时段具体从当日5:00开始计算下表显示两时段选定指标两时段变化情况对比' } %>
<%= javascript_void_link '数据变化', class: "btn btn-outline-primary btn-sm grow-btn #{params[:data_type] == 'contrast' ? '' : 'active'}",
<%= javascript_void_link '数据变化', class: "btn btn-outline-info btn-sm grow-btn #{params[:data_type] == 'contrast' ? '' : 'active'}",
data: { toggle: 'tooltip', trigger: 'hover', title: '请在左侧选择时间段具体从当日5:00开始计算下表显示选定时间段内各项指标数据变化情况' } %>
</div>

@ -0,0 +1,26 @@
<div class="modal fade admin-common-refuse-modal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLongTitle">拒绝原因</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form class="admin-common-refuse-form">
<%= hidden_field_tag(:apply_id, nil) %>
<div class="form-group">
<label for="reason" class="col-form-label">原因:</label>
<%= text_area_tag(:reason, nil, class: 'form-control', placeholder: '我得说点儿什么最多200字') %>
</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>

@ -37,6 +37,15 @@
<% end %>
</li>
<li>
<%= sidebar_item_group('#apply-review-submenu', '审核', icon: 'gavel') do %>
<li><%= sidebar_item(admins_identity_authentications_path, '实名认证', icon: 'id-card-o', controller: 'admins-identity_authentications') %></li>
<li><%= sidebar_item(admins_professional_authentications_path, '职业认证', icon: 'drivers-license', controller: 'admins-professional_authentications') %></li>
<li><%= sidebar_item(admins_shixun_authorizations_path, '实训发布', icon: 'object-ungroup', controller: 'admins-shixun_authorizations') %></li>
<li><%= sidebar_item(admins_subject_authorizations_path, '实践课程发布', icon: 'object-group', controller: 'admins-subject_authorizations') %></li>
<% end %>
</li>
<li><%= sidebar_item('/', '返回主站', icon: 'sign-out', controller: 'root') %></li>
</ul>
</nav>

@ -1,3 +1,4 @@
;
$('[data-toggle="tooltip"]').tooltip();
$('[data-toggle="popover"]').popover();
$('[data-toggle="popover"]').popover();
$('img.preview-image').bootstrapViewer();

@ -1,6 +1,8 @@
var deleteRow = $('<%= params[:element] %>');
var refreshUrl = '<%= params[:refresh_url] %>';
$.notify({ message: '操作成功' },{ type: 'success' });
var refreshFunc = function(url) {
$.ajax({
url: url.length > 0 ? url : window.location.href,

@ -4,4 +4,7 @@ setTimeout(function() {
if ($('.admin-alert-container button.close').length > 0) {
$('.admin-alert-container button.close').trigger('click');
}
}, 2000)
}, 5000)
$(".admin-body-container").animate({
scrollTop: 0
}, 200);

@ -0,0 +1,32 @@
<% define_admin_breadcrumbs do %>
<% add_admin_breadcrumb('实训发布') %>
<% end %>
<div class="box search-form-container flex-column mb-0 pb-0 shixun-authorization-list-form">
<ul class="nav nav-tabs w-100 search-form-tabs">
<li class="nav-item">
<%= link_to '待审批', admins_shixun_authorizations_path(status: :pending), remote: true, 'data-value': 'pending',
class: "nav-link search-form-tab #{params[:status] == 'pending' ? 'active' : ''}" %>
</li>
<li class="nav-item">
<%= link_to '已审批', admins_shixun_authorizations_path(status: :processed), remote: true, 'data-value': 'processed',
class: "nav-link search-form-tab #{params[:status] != 'pending' ? 'active' : ''}" %>
</li>
</ul>
<%= form_tag(admins_shixun_authorizations_path(unsafe_params), method: :get, class: 'form-inline search-form justify-content-end mt-3', remote: true) do %>
<div class="form-group status-filter" style="<%= params[:status] != 'pending' ? '' : 'display: none;' %>">
<label for="status">审核状态:</label>
<% status_options = [['全部', 'processed'], ['已同意', 'agreed'], ['已拒绝', 'refused']] %>
<%= 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') %>
<% end %>
</div>
<div class="box shixun-authorization-list-container">
<%= render(partial: 'admins/shixun_authorizations/shared/list', locals: { applies: @applies, shixun_map: @shixun_map }) %>
</div>
<%= render(partial: 'admins/shared/admin_common_refuse_modal') %>

@ -0,0 +1 @@
$('.shixun-authorization-list-container').html("<%= j( render partial: 'admins/shixun_authorizations/shared/list', locals: { applies: @applies, shixun_map: @shixun_map } ) %>");

@ -0,0 +1,60 @@
<% is_processed = params[:status].to_s != 'pending' %>
<table class="table table-hover text-center shixun-authorization-list-table">
<thead class="thead-light">
<tr>
<th width="8%">头像</th>
<th width="14%">创建者</th>
<th width="28%" class="text-left">实训名称</th>
<th width="12%">任务数</th>
<th width="16%">时间</th>
<% if is_processed %>
<th width="14%">拒绝原因</th>
<th width="8%">状态</th>
<% else %>
<th width="22%">操作</th>
<% end %>
</tr>
</thead>
<tbody>
<% if applies.present? %>
<% applies.each do |apply| %>
<% user = apply.user %>
<% shixun = shixun_map[apply.container_id] %>
<tr class="shixun-authorization-item shixun-authorization-<%= apply.id %>">
<td>
<%= link_to "/users/#{user.login}", class: 'shixun-authorization-avatar', target: '_blank', data: { toggle: 'tooltip', title: '个人主页' } do %>
<img src="/images/<%= url_to_avatar(user) %>" class="rounded-circle" width="40" height="40" />
<% end %>
</td>
<td><%= user.real_name %></td>
<td class="text-left">
<%= link_to "/shixuns/#{shixun.identifier}", target: '_blank' do %>
<%= overflow_hidden_span shixun.name, width: 300 %>
<% end %>
</td>
<td><%= shixun.challenges_count %></td>
<td><%= apply.updated_at.strftime('%Y-%m-%d %H:%M') %></td>
<% if is_processed %>
<td class="text-secondary"><%= overflow_hidden_span apply.reason, width: 140 %></td>
<td><span class="apply-status-<%= apply.status %>"><%= apply.status_text %></span></td>
<% else %>
<td class="action-container">
<%= agree_link '同意', agree_admins_shixun_authorization_path(apply, element: ".shixun-authorization-#{apply.id}"), 'data-confirm': '确认审核通过?' %>
<%= javascript_void_link('拒绝', class: 'action refuse-action',
data: {
toggle: 'modal', target: '.admin-common-refuse-modal', id: apply.id,
url: refuse_admins_shixun_authorization_path(apply, element: ".shixun-authorization-#{apply.id}")
}) %>
</td>
<% end %>
</tr>
<% end %>
<% else %>
<%= render 'admins/shared/no_data_for_table' %>
<% end %>
</tbody>
</table>
<%= render partial: 'admins/shared/paginate', locals: { objects: applies } %>

@ -0,0 +1,33 @@
<% define_admin_breadcrumbs do %>
<% add_admin_breadcrumb('实践课程发布') %>
<% end %>
<div class="box search-form-container flex-column mb-0 pb-0 subject-authorization-list-form">
<ul class="nav nav-tabs w-100 search-form-tabs">
<li class="nav-item">
<%= link_to '待审批', admins_subject_authorizations_path(status: :pending), remote: true, 'data-value': 'pending',
class: "nav-link search-form-tab #{params[:status] == 'pending' ? 'active' : ''}" %>
</li>
<li class="nav-item">
<%= link_to '已审批', admins_subject_authorizations_path(status: :processed), remote: true, 'data-value': 'processed',
class: "nav-link search-form-tab #{params[:status] != 'pending' ? 'active' : ''}" %>
</li>
</ul>
<%= form_tag(admins_subject_authorizations_path(unsafe_params), method: :get, class: 'form-inline search-form justify-content-end mt-3', remote: true) do %>
<div class="form-group status-filter" style="<%= params[:status] != 'pending' ? '' : 'display: none;' %>">
<label for="status">审核状态:</label>
<% status_options = [['全部', 'processed'], ['已同意', 'agreed'], ['已拒绝', 'refused']] %>
<%= 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') %>
<% end %>
</div>
<div class="box 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>
<%= render(partial: 'admins/shared/admin_common_refuse_modal') %>

@ -0,0 +1 @@
$('.subject-authorization-list-container').html("<%= j( render partial: 'admins/subject_authorizations/shared/list', locals: { applies: @applies, subject_map: @subject_map, challenge_count_map: @challenge_count_map } ) %>");

@ -0,0 +1,64 @@
<% is_processed = params[:status].to_s != 'pending' %>
<table class="table table-hover text-center subject-authorization-list-table">
<thead class="thead-light">
<tr>
<th width="8%">头像</th>
<th width="10%">创建者</th>
<th width="28%" class="text-left">实践课程名称</th>
<th width="6%">阶段数</th>
<th width="6%">实训数</th>
<th width="6%">关卡数</th>
<th width="14%">时间</th>
<% if is_processed %>
<th width="14%">拒绝原因</th>
<th width="8%">状态</th>
<% else %>
<th width="22%">操作</th>
<% end %>
</tr>
</thead>
<tbody>
<% if applies.present? %>
<% applies.each do |apply| %>
<% user = apply.user %>
<% subject = subject_map[apply.container_id] %>
<tr class="subject-authorization-item subject-authorization-<%= apply.id %>">
<td>
<%= link_to "/users/#{user.login}", class: 'subject-authorization-avatar', target: '_blank', data: { toggle: 'tooltip', title: '个人主页' } do %>
<img src="/images/<%= url_to_avatar(user) %>" class="rounded-circle" width="40" height="40" />
<% end %>
</td>
<td><%= user.real_name %></td>
<td class="text-left">
<%= link_to "/paths/#{subject.id}", target: '_blank' do %>
<%= overflow_hidden_span subject.name, width: 300 %>
<% end %>
</td>
<td><%= subject.stages_count %></td>
<td><%= subject.shixuns_count %></td>
<td><%= challenge_count_map.fetch(subject.id, 0) %></td>
<td><%= apply.updated_at.strftime('%Y-%m-%d %H:%M') %></td>
<% if is_processed %>
<td class="text-secondary"><%= overflow_hidden_span apply.reason, width: 140 %></td>
<td><span class="apply-status-<%= apply.status %>"><%= apply.status_text %></span></td>
<% else %>
<td class="action-container">
<%= agree_link '同意', agree_admins_subject_authorization_path(apply, element: ".subject-authorization-#{apply.id}"), 'data-confirm': '确认审核通过?' %>
<%= javascript_void_link('拒绝', class: 'action refuse-action',
data: {
toggle: 'modal', target: '.admin-common-refuse-modal', id: apply.id,
url: refuse_admins_subject_authorization_path(apply, element: ".subject-authorization-#{apply.id}")
}) %>
</td>
<% end %>
</tr>
<% end %>
<% else %>
<%= render 'admins/shared/no_data_for_table' %>
<% end %>
</tbody>
</table>
<%= render partial: 'admins/shared/paginate', locals: { objects: applies } %>

@ -1,29 +1,23 @@
<table class="table table-hover users-list-table">
<thead class="thead-light">
<tr>
<th width="10%">ID</th>
<th width="10%">真实姓名</th>
<th width="10%" class="text-left">真实姓名</th>
<th width="16%">邮件地址</th>
<th width="10%">手机号码</th>
<th width="14%">单位</th>
<th width="12%"><%= sort_tag('创建于', name: 'created_on', path: admins_users_path) %></th>
<th width="12%"><%= sort_tag('最后登录', name: 'last_login_on', path: admins_users_path) %></th>
<th width="10%"><%= sort_tag('经验值', name: 'experience', path: admins_users_path) %></th>
<th width="8%"><%= sort_tag('金币', name: 'grade', path: admins_users_path) %></th>
<th width="14%">操作</th>
<th width="10%"><%= sort_tag('创建于', name: 'created_on', path: admins_users_path) %></th>
<th width="10%"><%= sort_tag('最后登录', name: 'last_login_on', path: admins_users_path) %></th>
<th width="6%"><%= sort_tag('经验值', name: 'experience', path: admins_users_path) %></th>
<th width="6%"><%= sort_tag('金币', name: 'grade', path: admins_users_path) %></th>
<th width="20%">操作</th>
</tr>
</thead>
<tbody>
<% if users.present? %>
<% users.each do |user| %>
<tr class="user-item-<%= user.id %>">
<td>
<td class="text-left">
<%= link_to "/users/#{user.login}", target: '_blank' do %>
<%= overflow_hidden_span user.login, width: 100 %>
<% end %>
</td>
<td>
<%= link_to edit_admins_user_path(user) do %>
<%= overflow_hidden_span user.real_name, width: 100 %>
<% end %>
</td>
@ -35,6 +29,8 @@
<td><%= user.experience.to_i %></td>
<td class="grade-content"><%= user.grade.to_i %></td>
<td class="action-container">
<%= link_to '编辑', edit_admins_user_path(user), class: 'action' %>
<%= javascript_void_link('奖励', class: 'action reward-grade-action', data: { toggle: 'modal', target: '.admin-users-reward-grade-modal', id: user.id }) %>
<%= javascript_void_link '解锁', class: 'action unlock-action', data: { id: user.id, confirm: '确认解锁吗?' }, style: user.locked? ? '' : 'display: none;' %>

@ -0,0 +1,7 @@
zh-CN:
apply_action:
status:
'0': '待处理'
'1': '已同意'
'2': '已拒绝'
'3': '已撤销'

@ -0,0 +1,7 @@
zh-CN:
apply_user_authentication:
status:
'0': '待处理'
'1': '已同意'
'2': '已拒绝'
'3': '已撤销'

@ -753,7 +753,7 @@ Rails.application.routes.draw do
get :contrast, on: :collection
end
resources :users, only: [:index, :edit, :update] do
resources :users, only: [:index, :edit, :update, :destroy] do
member do
post :reward_grade
post :lock
@ -761,6 +761,31 @@ Rails.application.routes.draw do
post :active
end
end
resources :identity_authentications, only: [:index] do
member do
post :agree
post :refuse
end
end
resources :professional_authentications, only: [:index] do
member do
post :agree
post :refuse
end
end
resources :shixun_authorizations, only: [:index] do
member do
post :agree
post :refuse
end
end
resources :subject_authorizations, only: [:index] do
member do
post :agree
post :refuse
end
end
end
#git 认证回调

@ -337,6 +337,17 @@ class BoardsNew extends Component{
<span style={{ "padding-left": 0, "padding-right": 0 }}></span>
</React.Fragment>
}
<style>
{
`
.yslboardsnewinputaddonAfter .ant-input{
border-right: none !important;
height: 40px !important;
}
`
}
</style>
<Form.Item
label="标题"
className="topicTitle "
@ -349,8 +360,8 @@ class BoardsNew extends Component{
max: MAX_TITLE_LENGTH, message: `最大限制为${MAX_TITLE_LENGTH}个字符`,
}],
})(
<Input placeholder={`请输入帖子标题,最大限制${MAX_TITLE_LENGTH}个字符 `}className="searchViewAfter" maxLength={MAX_TITLE_LENGTH}
onInput={this.changeTitle} suffix={`${title_num}/${MAX_TITLE_LENGTH}`} />
<Input placeholder={`请输入帖子标题,最大限制${MAX_TITLE_LENGTH}个字符 `}className="searchViewAfter yslboardsnewinputaddonAfter" maxLength={MAX_TITLE_LENGTH}
onInput={this.changeTitle} addonAfter={`${title_num}/${MAX_TITLE_LENGTH}`} />
)}
</Form.Item>

@ -91,7 +91,7 @@ class CommonWorkQuestion extends Component{
{/* 内容区 */}
<div className="padding40 memoContent new_li">
<MarkdownToHtml content={description} selector="work_content"></MarkdownToHtml>
<MarkdownToHtml content={description} selector="work_content" className="mb10"></MarkdownToHtml>
{ attachments && attachments.map((item) => {
return ( <div className="color-grey">

@ -389,6 +389,17 @@ class NewWork extends Component{
</p>
<div>
{/* onSubmit={this.handleSubmit} */}
<style>
{
`
.yslnewworkinputaddonAfter .ant-input{
border-right: none !important;
height: 40px !important;
}
`
}
</style>
<Form className="courseForm">
<Form.Item
label="标题"
@ -399,7 +410,7 @@ class NewWork extends Component{
required: true, message: '请输入标题'
}],
})(
<Input placeholder="请输入作业标题最大限制60个字符" onInput={this.changeTitle} className="searchView searchViewAfter" style={{"width":"100%"}} maxLength={MAX_TITLE_LENGTH} suffix={`${String(title_num)}/${MAX_TITLE_LENGTH}`}/>
<Input placeholder="请输入作业标题最大限制60个字符" onInput={this.changeTitle} className="searchView yslnewworkinputaddonAfter searchViewAfter" style={{"width":"100%"}} maxLength={MAX_TITLE_LENGTH} addonAfter={`${String(title_num)}/${MAX_TITLE_LENGTH}`}/>
)}
</Form.Item>
<style>{`

@ -481,8 +481,19 @@ class ExerciceNew extends Component{
max: 20, message: '最大限制为20个字符',
}],
})( */}
<Input placeholder={`请输入试卷标题,最大限制${TITLE_MAX_LENGTH}个字符`} maxLength={TITLE_MAX_LENGTH} className="mt5" value={exercise_name}
onChange={this.exercise_name_change} suffix={`${exercise_name ? exercise_name.length : 0}/${TITLE_MAX_LENGTH}`}
<style>
{
`
.exercicenewinputysl .ant-input{
border-right: none !important;
height: 40px !important;
}
`
}
</style>
<Input placeholder={`请输入试卷标题,最大限制${TITLE_MAX_LENGTH}个字符`} maxLength={TITLE_MAX_LENGTH} className="mt5 exercicenewinputysl" value={exercise_name}
onChange={this.exercise_name_change} addonAfter={`${exercise_name ? exercise_name.length : 0}/${TITLE_MAX_LENGTH}`}
/>
{/* )} */}
</Form.Item>

@ -218,11 +218,19 @@ class Bullsubdirectory extends Component{
<span className="yslduincolorred">*</span>
</div>
<div className="yslduinleft">
<style>{
`
.ant-input{
border-right: none !important;
height: 40px !important;
}
`
}</style>
<Input placeholder="请在此输入标题最多60个字符" maxLength="60"
style={{ textAlign: "left",width:"100%",}}
onInput={this.changeTopicName}
autoComplete="off"
suffix={String(addonAfter)+"/60"}
addonAfter={String(addonAfter)+"/60"}
value={eduintits}
className="searchViewAfter"></Input>
</div>

@ -287,11 +287,19 @@ class Eduinforms extends Component{
<span className="yslduincolorred">*</span>
</div>
<div className="yslduinleft">
<style>{
`
.ant-input{
border-right: none !important;
height: 40px !important;
}
`
}</style>
<Input placeholder="请在此输入标题最多60个字符" maxLength={60}
style={{ textAlign: "left",width:"100%",}}
onInput={this.changeTopicName}
autoComplete="off"
suffix={String(addonAfter)+"/60"}
addonAfter={String(addonAfter)+"/60"}
value={eduintits}
className="searchViewAfter"></Input>
</div>

@ -375,11 +375,21 @@ class GraduationTasksedit extends Component{
<input type="hidden" id='tasktypes' />
<span className={"newcoursestitle"}>选择确认后无法修改</span>
</Form.Item>
<style>
{
`
.yslgraduainputedit .ant-input{
border-right: none !important;
height: 40px !important;
}
`
}
</style>
<Form.Item label="任务标题" >
{getFieldDecorator('name', {
rules: [{ required: true, message: "请输入标题" }],
})(<Input placeholder="请输入任务名称最大限制60个字符" value={name} onInput={this.changeTitle} className="searchView searchViewAfter" style={{"width":"100%"}} maxLength="60" suffix={String(title_num)+"/60"}/>)}
})(<Input placeholder="请输入任务名称最大限制60个字符" value={name} onInput={this.changeTitle} className="searchView searchViewAfter yslgraduainputedit" style={{"width":"100%"}} maxLength="60" addonAfter={String(title_num)+"/60"}/>)}
</Form.Item>
<input type="hidden" id='nametypes' />
</div>

@ -377,15 +377,23 @@ class GraduationTasksnew extends Component {
margin-top: 0px;
margin-bottom: 0px;
}
.yslgts .ant-input{
border-right: none !important;
height: 40px !important;
}
`
}
</style>
<Form.Item label="任务标题" className={"taskname"} >
{getFieldDecorator('name', {
rules: [{required: true, message: "不能为空"}],
})(<Input placeholder="请输入任务名称最大限制60个字符" value={title_value} onInput={this.changeTitle}
className="searchView searchViewAfter h40" style={{"width": "100%"}} maxLength="60"
suffix={String(title_num)+"/60"}/>)}
})(
<Input placeholder="请输入任务名称最大限制60个字符" value={title_value} onInput={this.changeTitle}
className="searchView searchViewAfter h40 yslgts" style={{"width": "100%"}} maxLength="60"
addonAfter={String(title_num)+"/60"}/>
)}
</Form.Item>
<input type="hidden" id='nametypes' />
</div>

@ -358,6 +358,17 @@ class GraduateTopicNew extends Component{
</Select>
)}
</Form.Item>
<style>
{
`
.exercicenewinputysl .ant-input{
border-right: none !important;
height: 40px !important;
}
`
}
</style>
<Form.Item
label="选题名称"
className="mt15"
@ -369,7 +380,7 @@ class GraduateTopicNew extends Component{
max: 60, message: '最大限制为60个字符',
}],
})(
<Input placeholder="请输入帖子选题名称最大限制60个字符" maxLength="60" onInput={this.changeTopicName} autoComplete="off" suffix={`${String(addonAfter)}/${NAME_COUNT}`} className="searchViewAfter" />
<Input placeholder="请输入帖子选题名称最大限制60个字符" maxLength="60" onInput={this.changeTopicName} autoComplete="off" addonAfter={`${String(addonAfter)}/${NAME_COUNT}`} className="searchViewAfter exercicenewinputysl" />
)}
</Form.Item>
</div>

@ -1,11 +1,12 @@
import React, {Component} from "React";
import {Form, Select, Input, Button, Checkbox, DatePicker,Spin,Icon,AutoComplete,InputNumber} from "antd";
import {Form, Select, Input, Button, Checkbox, DatePicker,Spin,Icon,AutoComplete,InputNumber,Breadcrumb} from "antd";
import ApplyForAddOrgModal from '../../user/modal/ApplyForAddOrgModal';
import axios from 'axios';
import "../css/Courses.css";
import locale from 'antd/lib/date-picker/locale/zh_CN';
import moment from 'moment';
import Modals from '../../modals/Modals';
import {WordsBtn, ActionBtn} from 'educoder';
@ -44,7 +45,9 @@ class CoursesNew extends Component {
fetching:false,
boolxinjian:false,
checkboxgroup:undefined,
checkbofrup:["shixun_homework","common_homework","group_homework","exercise","attachment","course_group","graduation","poll","board"],
checkbofrup:[{module_type:"shixun_homework",module_name:"实训作业"},{module_type:"common_homework",module_name:"普通作业"},{module_type:"group_homework",module_name:"分组作业"}
,{module_type:"exercise",module_name:"试卷"},{module_type:"poll",module_name:"问卷"},{module_type:"graduation",module_name:"毕业设计"}
,{module_type:"board",module_name:"讨论"},{module_type:"attachment",module_name:"资源"},{module_type:"course_group",module_name:"分班"}],
checkbofrups:[],
}
}
@ -78,32 +81,22 @@ class CoursesNew extends Component {
is_public: data.is_public === 1 ? true : false,
Realnamecertification: data.authentication,
Professionalcertification:data.professional_certification,
checkbofrups:data.course_modules,
});
try {
var datasysl=[];
var dataysl2=[];
var dataysl3=[];
var checkbofrup =this.state.checkbofrup;
dataysl2=data.course_module_types;
datasysl=checkbofrup;
for (var k=0;k<datasysl.length;k++){
for (var i=0;i<data.course_module_types.length;i++){
if(datasysl[k]===data.course_module_type[i]){
datasysl.slice(k,1);
}
}
}
dataysl3 = dataysl2.concat(datasysl);
this.setState({
checkboxgroup: dataysl3,
})
if(data.course_modules===undefined||data.course_modules.length===0){
this.setState({
checkbofrups:this.state.checkbofrup,
});
}
}catch (e) {
this.setState({
checkboxgroup:this.state.checkbofrup,
})
this.setState({
checkbofrups:this.state.checkbofrup,
});
}
this.handleSearchschool(data.school);
}).catch((error) => {
console.log(error);
@ -450,6 +443,7 @@ class CoursesNew extends Component {
search: value
}
}).then((result)=>{
if(result){
if (result.data.status===0) {
this.setState({
searchlistscholl: result.data.school_names,
@ -461,6 +455,7 @@ class CoursesNew extends Component {
})
}
}
}
}).catch((error)=>{
console.log(error)
})
@ -469,7 +464,7 @@ class CoursesNew extends Component {
this.applyForAddOrgForm.setVisible(true)
}
render() {
let {datatime,school,searchlistscholl,checkboxgroup} = this.state;
let {datatime,school,searchlistscholl,checkbofrups} = this.state;
const {getFieldDecorator} = this.props.form;
const propsWithoutForm = Object.assign({}, this.props)
delete propsWithoutForm.form
@ -509,8 +504,22 @@ class CoursesNew extends Component {
/>
<div className="newMain clearfix">
<div className={"educontent mb20"}>
{/*<Breadcrumb className="mt10" separator=">">*/}
{/* <Breadcrumb.Item>*/}
{/* <a href="/courses">翻转课堂</a>*/}
{/* </Breadcrumb.Item>*/}
{/* <Breadcrumb.Item>{this.props.match.params.coursesId === undefined ?"新建课堂":"编辑课堂"}</Breadcrumb.Item>*/}
{/*</Breadcrumb>*/}
<p className="clearfix mb20 mt10">
<a className="btn colorgrey fl hovercolorblue " href="/courses">翻转课堂</a>
<span className="color-grey-9 fl ml3 mr3">&gt;</span>
<WordsBtn className="fl">{this.props.match.params.coursesId === undefined ?"新建课堂":"编辑课堂"}</WordsBtn>
</p>
<div style={{width: '100%', height: '70px'}}>
<p className="ml15 fl color-black mt30 summaryname">{this.props.match.params.coursesId === undefined ? "新建课堂" : "编辑课堂"}</p>
<p className=" fl color-black mt18 summaryname">{this.props.match.params.coursesId === undefined ? "新建课堂" : "编辑课堂"}</p>
<a onClick={this.goback} className="color-grey-6 fr font-16 ml30 mt18 mr20">返回</a>
</div>
<style>
@ -699,27 +708,15 @@ class CoursesNew extends Component {
this.props.match.params.coursesId != undefined?
<Checkbox.Group style={{width: "800px", marginTop: "10px"}}>
{
checkboxgroup===undefined?"":checkboxgroup.length===0?"":checkboxgroup.map((item,key)=>{
checkbofrups===undefined?"":checkbofrups.length===0?"":checkbofrups.map((item,key)=>{
return(
item ==="shixun_homework"?
<Checkbox value={"shixun_homework"} className="fl">实训作业</Checkbox>
:item ==="common_homework"?
<Checkbox value={"common_homework"} className="fl">普通作业</Checkbox>
:item ==="group_homework"?
<Checkbox value={"group_homework"} className="fl">分组作业</Checkbox>
:item ==="exercise"?
<Checkbox value={"exercise"} className="fl">试卷</Checkbox>
:item ==="attachment"?
<Checkbox value={"attachment"} className="fl">资源</Checkbox>
:item ==="course_group"?
<Checkbox value={"course_group"} className="fl">分班</Checkbox>
:item ==="graduation"?
<Checkbox value={"graduation"} className="fl">毕业设计</Checkbox>
:item ==="poll"?
<Checkbox value={"poll"} className="fl">问卷</Checkbox>
:item ==="board"?
<Checkbox value={"board"} className="fl">讨论</Checkbox>
:""
item.module_type==="announcement"?
""
:
item.module_type==="online_learning"?
""
:
<Checkbox key={key} value={item.module_type} className="fl">{item.module_name}</Checkbox>
)
})
}
@ -729,16 +726,13 @@ class CoursesNew extends Component {
<Checkbox value={"shixun_homework"} className="fl">实训作业</Checkbox>
<Checkbox value={"common_homework"} className="fl">普通作业</Checkbox>
<Checkbox value={"group_homework"} className="fl">分组作业</Checkbox>
<Checkbox value={"exercise"} className="fl">试卷</Checkbox>
<Checkbox value={"attachment"} className="fl">资源</Checkbox>
<Checkbox value={"course_group"} className="fl">分班</Checkbox>
<Checkbox value={"graduation"} className="fl">毕业设计</Checkbox>
<Checkbox value={"exercise"} className="fl">试卷</Checkbox>
<Checkbox value={"poll"} className="fl">问卷</Checkbox>
<Checkbox value={"attachment"} className="fl">资源</Checkbox>
<Checkbox value={"board"} className="fl">讨论</Checkbox>
<Checkbox value={"course_group"} className="fl">分班</Checkbox>
</Checkbox.Group>
)}
</Form.Item>
</div>

@ -6,7 +6,7 @@ import "../css/Courses.css";
import locale from 'antd/lib/date-picker/locale/zh_CN';
import moment from 'moment';
import Modals from '../../modals/Modals';
import {WordsBtn, ActionBtn} from 'educoder';
const { Option } = Select;
@ -50,7 +50,12 @@ class Goldsubject extends Component {
subject_id:"",
start_date:"",
Whethertocreateanewclassroom:true,
checkbofrup:[
{module_type:"announcement",module_name:"公告栏"},{module_type:"online_learning",module_name:"在线学习"}
,{module_type:"shixun_homework",module_name:"实训作业"},{module_type:"common_homework",module_name:"普通作业"}
,{module_type:"exercise",module_name:"试卷"},{module_type:"poll",module_name:"问卷"}
,{module_type:"attachment",module_name:"资源"},{module_type:"board",module_name:"讨论"},{module_type:"course_group",module_name:"分班"},],
checkbofrups:[],
}
}
// disabledEndDate= endValue => {
@ -139,7 +144,20 @@ class Goldsubject extends Component {
course_module_types: data.course_module_types,
school:data.school,
Whethertocreateanewclassroom:false,
checkbofrups:data.course_modules,
});
try {
if(data.course_modules===undefined||data.course_modules.length===0){
this.setState({
checkbofrups:this.state.checkbofrup,
});
}
}catch (e) {
this.setState({
checkbofrups:this.state.checkbofrup,
});
}
this.handleSearchschool(data.school);
}).catch((error) => {
console.log(error);
@ -591,7 +609,7 @@ class Goldsubject extends Component {
this.applyForAddOrgForm.setVisible(true)
}
render() {
let {datatime,datatimetwo,school,searchlistscholl,Whethertocreateanewclassroom} = this.state;
let {datatime,datatimetwo,school,searchlistscholl,Whethertocreateanewclassroom,checkbofrups} = this.state;
const {getFieldDecorator} = this.props.form;
const propsWithoutForm = Object.assign({}, this.props)
delete propsWithoutForm.form
@ -633,12 +651,18 @@ class Goldsubject extends Component {
<div className="newMain clearfix">
<div className={"educontent mb20"}>
<Breadcrumb className="mt10" separator=">">
<Breadcrumb.Item>
<a href="/">首页</a>
</Breadcrumb.Item>
<Breadcrumb.Item>{Whethertocreateanewclassroom===true?"新建课堂":"编辑课堂"}</Breadcrumb.Item>
</Breadcrumb>
{/*<Breadcrumb className="mt10" separator=">">*/}
{/* <Breadcrumb.Item>*/}
{/* <a href="/courses">翻转课堂</a>*/}
{/* </Breadcrumb.Item>*/}
{/* <Breadcrumb.Item>{Whethertocreateanewclassroom===true?"新建课堂":"编辑课堂"}</Breadcrumb.Item>*/}
{/*</Breadcrumb>*/}
<p className="clearfix mb20 mt10">
<a className="btn colorgrey fl hovercolorblue " href="/courses">翻转课堂</a>
<span className="color-grey-9 fl ml3 mr3">&gt;</span>
<WordsBtn className="fl">{Whethertocreateanewclassroom===true?"新建课堂":"编辑课堂"}</WordsBtn>
</p>
<div style={{width: '100%', height: '70px'}}>
<p className=" fl color-black mt18 summaryname">{Whethertocreateanewclassroom===true ? "新建课堂" : "编辑课堂"}</p>
<a onClick={this.goback} className="color-grey-6 fr font-16 ml30 mt18 mr20"></a>
@ -860,6 +884,25 @@ class Goldsubject extends Component {
"announcement","online_learning","shixun_homework","common_homework",
],
})(
this.props.match.params.coursesId != undefined?
<Checkbox.Group style={{width: "800px", marginTop: "10px"}}>
{
checkbofrups===undefined?"":checkbofrups.length===0?"":checkbofrups.map((item,key)=>{
return(
item.module_type==="announcement"?
<Checkbox value={"announcement"} className="fl" defaultChecked disabled>公告栏</Checkbox>
:
item.module_type==="online_learning"?
<Checkbox value={"online_learning"} className="fl" defaultChecked disabled>在线学习</Checkbox>
:
item.module_type==="graduation"?"":
item.module_type==="group_homework"?"":
<Checkbox key={key} value={item.module_type} className="fl">{item.module_name}</Checkbox>
)
})
}
</Checkbox.Group>
:
<Checkbox.Group style={{width: "800px", marginTop: "10px"}}>
<Checkbox value={"announcement"} className="fl" defaultChecked disabled>公告栏</Checkbox>
<Checkbox value={"online_learning"} className="fl" defaultChecked disabled>在线学习</Checkbox>

@ -2529,14 +2529,24 @@ class PollNew extends Component {
</div>
{/*suffix={String(addonAfter)}*/}
<style>
{
`
.yslpollls .ant-input{
border-right: none !important;
height: 40px !important;
}
`
}
</style>
<Input placeholder="请输入问卷标题最大限制60个字符" maxLength="60"
style={{"margin-top": "15px", "text-align": "left"}}
onInput={this.changeTopicName}
readOnly={readOnlys}
autoComplete="off"
suffix={String(addonAfter)+"/60"}
addonAfter={String(addonAfter)+"/60"}
value={this.state.polls_nametest}
className="searchViewAfter"></Input>
className="searchViewAfter yslpollls"></Input>
</div>
<div style={{

@ -115,7 +115,7 @@ class SiderBar extends Component {
`
}
</style>
<img src={getImageUrl("images/edu_user/EWM.jpg")} width="158px" height="158px" />
<img src={getImageUrl("images/educoder/EWM.jpg")} width="158px" height="158px" />
<p className={"WeChatstyle"}>微信扫一扫</p>
<p className={"WeChatstyle"}>关注公众号</p>
<span className="trangle_right"></span>

@ -1103,6 +1103,10 @@ class LoginRegisterComponent extends Component {
right: 12px;
height: 20px;
}
.ant-input{
border-right: none !important;
height: 40px !important;
}
`
}
</style>
@ -1112,7 +1116,7 @@ class LoginRegisterComponent extends Component {
autoComplete="new-password"
onClick={this.changeType}
value={this.state.passwords} onChange={this.passwordonChanges}
suffix={
addonAfter={
<img className={"mt5"} src={passopens} onClick={(key) => this.Showandhide(key)}>
</img>
}></Input>

@ -492,7 +492,17 @@ class AccountBasic extends Component {
}
`}</style>
<div className="title">基本信息</div>
<style>
{
`
.exercicenewinputysl .ant-input{
border-right: none !important;
height: 40px !important;
}
`
}
</style>
<Form onSubmit={this.handleSubmit}>
<Form.Item
label="昵称"
@ -505,12 +515,22 @@ class AccountBasic extends Component {
message: '请输入您的昵称',
}],
})(
<Input placeholder={`请输入您的昵称,最大限制${MAX_NICKNAME_LENGTH}个字符`} onInput={this.changeNickName} maxLength={MAX_NICKNAME_LENGTH} suffix ={
<Input placeholder={`请输入您的昵称,最大限制${MAX_NICKNAME_LENGTH}个字符`} className="exercicenewinputysl" onInput={this.changeNickName} maxLength={MAX_NICKNAME_LENGTH} addonAfter ={
<span className="color-grey-6 font-13">{String(nameLength)}/{MAX_NICKNAME_LENGTH}</span>
}></Input>
)}
</Form.Item>
<style>
{
`
.yslgraduainputedit .ant-input{
border-right: none !important;
height: 40px !important;
}
`
}
</style>
<Form.Item
label="姓名"
className="formItemInline"
@ -523,7 +543,7 @@ class AccountBasic extends Component {
validator: this.checkNameLength
}],
})(
<Input placeholder={`请输入真实姓名,最大限制${MAX_NAME_LENGTH}个字符`} disabled={!showRealName && this.state.forDisable == true } suffix={
<Input placeholder={`请输入真实姓名,最大限制${MAX_NAME_LENGTH}个字符`} className="yslgraduainputedit" disabled={!showRealName && this.state.forDisable == true } addonAfter={
<i className={showRealName?"iconfont icon-xianshi font-18 color-blue":"iconfont icon-yincang font-18 color-blue"}
onClick={()=>this.showOrHide(showRealName)}></i>
}></Input>

@ -63,7 +63,17 @@ function EditVideoModal (props) {
onOk={onOk}
onCancel={onCancel}
className="editVideoModal"
>
> <style>
{
`
.exercicenewinputysl .ant-input{
border-right: none !important;
height: 40px !important;
}
`
}
</style>
<Form.Item
label="视频标题"
className="title formItemInline"
@ -76,8 +86,8 @@ function EditVideoModal (props) {
max: MAX_LENGTH, message: '最大限制为30个字符',
}],
})(
<Input placeholder="" className="titleInput" maxLength={MAX_LENGTH}
suffix={String(_title ? `${String(_title.length)}/${MAX_LENGTH}` : 0)} />
<Input placeholder="" className="titleInput exercicenewinputysl" maxLength={MAX_LENGTH}
addonAfter={String(_title ? `${String(_title.length)}/${MAX_LENGTH}` : 0)} />
)}
</Form.Item>
</ModalWrapper>

@ -36,13 +36,23 @@ function VideoUpload (props) {
<ActionBtn className="" onClick={() => cancelUpload(index, loaded == '100' )}>{loaded == '100' ? "删除" : "取消上传"}</ActionBtn>
</div>
</div>
<style>
{
`
.titleInputysl .ant-input{
border-right: none !important;
height: 40px !important;
}
`
}
</style>
<div className="courseForm">
<span className="titleLabel">标题</span>
<Input placeholder={`标题支持最多${MAX_LENGTH}个字符`} onInput={titleChange} maxLength={MAX_LENGTH} suffix={
<Input placeholder={`标题支持最多${MAX_LENGTH}个字符`} onInput={titleChange} maxLength={MAX_LENGTH} addonAfter={
<span className="color-grey-6 font-13">{String(title.length)}/{MAX_LENGTH}</span>
}
className="titleInput"
className="titleInput titleInputysl"
></Input>
</div>
</div>

Loading…
Cancel
Save