dev_aliyun_beta
杨树明 6 years ago
commit adee752481

@ -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,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;
}
@ -44,3 +44,7 @@ label.error {
}
}
}
.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,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

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

@ -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,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,13 @@
<% 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>
<% 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();
$('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,

@ -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_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,19 @@ 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
end
#git 认证回调

@ -31,6 +31,7 @@ module.exports = {
// See the discussion in https://github.com/facebookincubator/create-react-app/issues/343.s
// devtool: "cheap-module-eval-source-map",
// 开启调试
devtool: "source-map", // 开启调试
// These are the "entry points" to our application.
// This means they will be the "root" imports that are included in JS bundle.
// The first two entry points enable "hot" CSS and auto-refreshes for JS.

@ -195,7 +195,29 @@ function generateNewIndexJsp() {
let cdnHost = 'https://shixun.educoder.net'
cdnHost = 'https://ali-cdn.educoder.net'
cdnHost = ''
var result = data.replace('/js/js_min_all.js', `${cdnHost}/react/build/js/js_min_all.js?v=${newVersion}`)
var mainRegex = /<script type="text\/javascript" src="\/react\/build\/.\/static\/js\/main.([a-zA-Z0-9]{8,}).js"><\/script>/
var matchResult = data.match(mainRegex)
var code = `
<script>
(function() {
var _host = ''
if (window.location.host == 'pre-newweb.educoder.net') {
_host = 'https://testali-cdn.educoder.net/react/build/'
} else if (window.location.host == 'www.educoder.net') {
_host = 'https://ali-newweb.educoder.net/react/build/'
}
document.write('<script type="text/javascript" src="' + _host + 'js/js_min_all.js"><\\/script>');
document.write('<script type="text/javascript" src="' + _host + 'static/js/main.${matchResult[1]}.js"><\\/script>');
})()
</script>
`
var jsMinAllRegex = /<script type="text\/javascript" src="\/js\/js_min_all.js"><\/script>/
// <script type="text/javascript" src="/js/js_min_all.js"></script>
var result = data
.replace(jsMinAllRegex, code)
// .replace('/js/js_min_all.js', `${cdnHost}/react/build/js/js_min_all.js?v=${newVersion}`)
// .replace('/js/js_min_all_2.js', `${cdnHost}/react/build/js/js_min_all_2.js?v=${newVersion}`)
// ${cdnHost} 加了cdn后这个文件里的字体文件加载会有跨域的报错 ../fonts/fontawesome-webfont.eot
@ -204,10 +226,11 @@ function generateNewIndexJsp() {
.replace('/css/iconfont.css', `${cdnHost}/react/build/css/iconfont.css?v=${newVersion}`)
.replace(/\/js\/create_kindeditor.js/g, `${cdnHost}/react/build/js/create_kindeditor.js?v=${newVersion}`)
.replace(mainRegex, '')
// .replace('/react/build/./static/css/main', `${cdnHost}/react/build/./static/css/main`)
// .replace('/react/build/./static/js/main', `${cdnHost}/react/build/./static/js/main`)
.replace(/https:\/\/testeduplus2.educoder.net/g, '');
// .replace(/https:\/\/testeduplus2.educoder.net/g, '');
// .replace(/http:\/\/testbdweb.educoder.net/g, '');
// .replace('/css/css_min_all.css', '/react/build/css/css_min_all.css');

@ -55,6 +55,10 @@ html, body {
.markdown-body p {
white-space: pre-wrap;
}
/* https://www.educoder.net/courses/2346/group_homeworks/34405/question */
.renderAsHtml.markdown-body p {
white-space: inherit;
}
/* resize */
.editormd .CodeMirror {
border-right: none !important;

@ -1,4 +1,5 @@
import React, {Component} from 'react';
import './public-path';
import logo from './logo.svg';
import './App.css';
import {LocaleProvider} from 'antd'

@ -9,6 +9,7 @@ export function markdownToHTML(oldContent, selector) {
window.$('#md_div').html('')
// markdown to html
if (selector && oldContent && oldContent.startsWith('<p')) { // 普通html处理
window.$('#' + selector).addClass('renderAsHtml')
window.$('#' + selector).html(oldContent)
} else {
try {

@ -1,4 +1,5 @@
import React,{ Component } from "react";
import { ConditionToolTip } from 'educoder'
class AttachmentsList extends Component{
constructor(props){
@ -12,14 +13,18 @@ class AttachmentsList extends Component{
attachments.map((item,key)=>{
return(
<p key={key}>
<a className="color-grey">
<a className="color-grey fl">
<i className="font-14 color-green iconfont icon-fujian mr8"></i>
</a>
{
item.is_pdf && item.is_pdf == true ?
<a href={item.url} className="mr12" length="58" target="_blank">{item.title}</a>
<ConditionToolTip title={item.title} condition={item.title && item.title.length > 30 }>
<a href={item.url} className="mr12 fl task-hide" length="58" target="_blank" style={{"maxWidth":"432px"}}>{item.title}</a>
</ConditionToolTip>
:
<a href={item.url} className="mr12" length="58">{item.title}</a>
<ConditionToolTip title={item.title} condition={item.title && item.title.length > 30 }>
<a href={item.url} className="mr12 fl task-hide" length="58" style={{"maxWidth":"432px"}}>{item.title}</a>
</ConditionToolTip>
}
<span className="color-grey mt2 color-grey-6 font-12">{item.filesize}</span>
</p>

@ -131,10 +131,14 @@ class Fileslistitem extends Component{
});
}
eventStop = (event) =>{
event.stopPropagation()
}
render(){
const { checkBox,
discussMessage,
discussMessage,index
} = this.props;
return(
@ -190,9 +194,9 @@ class Fileslistitem extends Component{
white-space:nowrap
}
`}</style>
<div className="clearfix ds pr contentSection">
<h6>
<span className="fl mr12 mt3">
<div className="clearfix ds pr contentSection" style={{cursor : this.props.isAdmin ? "pointer" : "default"}} onClick={() => window.$(`.sourceitem${index} input`).click() }>
<h6 onClick={(event)=>this.eventStop(event)}>
<span className={`sourceitem${index} fl mr12 mt3`}>
{checkBox}
</span>
{
@ -283,8 +287,7 @@ class Fileslistitem extends Component{
</span>
</span>
{this.props.isAdmin?
<span className={"fr mrf2 mr10"}>
<span className={"fr mrf2 mr10"} onClick={(event)=>this.eventStop(event)}>
<WordsBtn style="blue" className="colorblue font-16 mr20 fr">
<a className="btn colorblue"
onClick={()=>this.settingList()}>设置</a>
@ -292,7 +295,7 @@ class Fileslistitem extends Component{
</span>:""}
{this.props.isStudent===true&&this.props.current_user.login===discussMessage.author.login?
<span className={"fr mrf2 mr10"}>
<span className={"fr mrf2 mr10"} onClick={(event)=>this.eventStop(event)}>
<WordsBtn style="blue" className="colorblue font-16 mr20 fr">
<a className="btn colorblue"

@ -919,6 +919,7 @@ class Fileslists extends Component{
Settingtypes={(id)=>this.Settingtypes(id)}
coursesId={this.props.match.params.coursesId}
updatafiledfun={()=>this.updatafiled()}
index={index}
></Fileslistitem>
</div>
</div>

@ -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>
@ -365,10 +376,15 @@ class BoardsNew extends Component{
dropdownRender={menu => (
<div>
{menu}
{
isAdmin &&
<React.Fragment>
<Divider style={{ margin: '4px 0' }} />
<div style={{ padding: '8px', cursor: 'pointer' }} onMouseDown={() => this.refs['addDirModal'].open()}>
<Icon type="plus" /> 添加目录
</div>
</React.Fragment>
}
</div>
)}
>

@ -24,7 +24,7 @@ import '../../forums/RightSection.css'
import './TopicDetail.css'
import '../common/courseMessage.css'
import { Pagination, Tooltip } from 'antd'
import { bytesToSize, ConditionToolTip, markdownToHTML, MarkdownToHtml } from 'educoder'
import { bytesToSize, ConditionToolTip, markdownToHTML, MarkdownToHtml , setImagesUrl } from 'educoder'
import SendToCourseModal from '../coursesPublic/modal/SendToCourseModal'
import CBreadcrumb from '../common/CBreadcrumb'
import { generateComments, generateChildComments, _findById, handleContentBeforeCreateNew, addNewComment
@ -57,6 +57,7 @@ class TopicDetail extends Component {
pageCount: 1,
comments: [],
goldRewardDialogOpen: false,
author:undefined
}
}
componentDidMount() {
@ -85,7 +86,8 @@ class TopicDetail extends Component {
memo: Object.assign({}, {
...response.data.data,
replies_count: response.data.data.total_replies_count
}, {...this.state.memo})
}, {...this.state.memo}),
author:response.data.data.author
}, () => {
})
@ -514,7 +516,7 @@ class TopicDetail extends Component {
render() {
const { match, history } = this.props
const { recommend_shixun, current_user,author_info } = this.props;
const { memo, comments, hasMoreComments, goldRewardDialogOpen, pageCount, total_count } = this.state;
const { memo, comments, hasMoreComments, goldRewardDialogOpen, pageCount, total_count , author } = this.state;
const messageId = match.params.topicId
if (this.state.memoLoading || !current_user) {
return <div className="edu-back-white" id="forum_index_list"></div>
@ -599,11 +601,12 @@ class TopicDetail extends Component {
}
</div>
<div className="color-grey-9 clearfix">
<span className="fl" style={{marginTop: "2px"}}>{moment(memo.created_on).fromNow()} 发布</span>
<div className="fr">
</div>
<div className="df mt20">
<img src={setImagesUrl(`/images/${author && author.image_url}`)} className="radius mr10 mt2" width="40px" height="40px"/>
<div className="flex1">
<div className="color-grey-9 lineh-20">
<span class="color-grey-3 mr20 fl" style={{"fontWeight":"400"}}>{author && author.name}</span>
<span className="fl">{moment(memo.created_on).fromNow()} 发布</span>
</div>
<div className="color-grey-9 clearfix">
@ -627,11 +630,11 @@ class TopicDetail extends Component {
</a>
</Tooltip>
}
{!!memo.praises_count &&
{!!memo.total_praises_count &&
<Tooltip title={"点赞数"}>
<span className={`noteDetailNum `} style={{}}>
<i className="iconfont icon-dianzan-xian mr5"></i>
<span style={{ top: "2px", position: "relative" }}>{ memo.praises_count }</span>
<span style={{ top: "2px", position: "relative" }}>{ memo.total_praises_count }</span>
</span>
</Tooltip>
}
@ -645,6 +648,8 @@ class TopicDetail extends Component {
</div>
</div>
</div>
</div>
</div>
<div className="padding30 memoContent new_li" style={{ paddingBottom: '10px'}}>

@ -15,7 +15,7 @@ import WorkDetailPageHeader from './common/WorkDetailPageHeader'
import CommonWorkAppraiseReply from './reply/CommonWorkAppraiseReply'
import Example from './TestHooks'
import CommonWorkAppraiseReviseAttachments from './CommonWorkAppraiseReviseAttachments'
import LeaderIcon from './common/LeaderIcon'
const { Option} = Select;
const CheckboxGroup = Checkbox.Group;
const confirm = Modal.confirm;
@ -88,6 +88,14 @@ class CommonWorkAppraise extends Component{
console.log(error)
})
}
componentDidUpdate(prevProps, prevState) {
if (this.props.match.params.studentWorkId != prevProps.match.params.studentWorkId) {
this.getWork();
this.getReviseAttachments()
this.commonWorkAppraiseReply && this.commonWorkAppraiseReply.fetchAllComments()
}
}
componentDidMount() {
this.getWork();
this.getReviseAttachments()
@ -156,12 +164,13 @@ class CommonWorkAppraise extends Component{
attachments, homework_id, project_info, work_members, is_evaluation,
description, update_user_name, update_time, commit_time, author_name,
revise_attachments, revise_reason, atta_update_user, atta_update_time, atta_update_user_login,
Modalstype,Modalstopval,ModalCancel,ModalSave,loadtype
Modalstype,Modalstopval,ModalCancel,ModalSave,loadtype, is_leader_work
} =this.state;
let courseId=this.props.match.params.coursesId;
let category_id=this.props.match.params.category_id;
let studentWorkId=this.props.match.params.studentWorkId;
const isAdmin = this.props.isAdmin()
return(
<WorkDetailPageHeader
{...this.props} {...this.state}
@ -251,13 +260,28 @@ class CommonWorkAppraise extends Component{
{is_evaluation != true && work_members && !!work_members.length && <div className={"stud-class-set bor-top-greyE edu-back-white padding20-30"}>
<div className={"color-grey-6 mb10"}>
其他组员
全部组员
</div>
<div className={"ml20"}>
<div className={"ml20 color-grey-6"}>
<div className="">
当前组员{author_name} {is_leader_work && <LeaderIcon small={true} ></LeaderIcon>}
</div>
<div>
其他组员
{work_members.map((item, index) => {
return item.user_name + ' '
return <React.Fragment>
{isAdmin ?
<a className={`color-blue ${index == 0 ? '' : 'ml10'}`} href="javascript:void(0)"
onClick={() => this.props.toWorkDetailPage(this.props.match.params, null, item.work_id)}
>
{item.user_name}
</a> : <span className={`${index == 0 ? '' : 'ml10'}`} >{item.user_name}</span>}
{item.is_leader && <LeaderIcon small={true} ></LeaderIcon>}
</React.Fragment>
})}
</div>
</div>
</div>
}
</div>
@ -266,6 +290,7 @@ class CommonWorkAppraise extends Component{
{/* task_type={datalist&&datalist.task_type} */}
<CommonWorkAppraiseReply {...this.props} task_id={studentWorkId}
onReplySuccess={this.onReplySuccess} {...this.state}
wrappedComponentRef={(ref) => {this.commonWorkAppraiseReply = ref}}
></CommonWorkAppraiseReply>
</div>

@ -15,7 +15,7 @@ import WorkDetailPageHeader from './common/WorkDetailPageHeader'
import PublishRightnow from './PublishRightnow'
import ModulationModal from "../coursesPublic/ModulationModal";
import AccessoryModal from "../coursesPublic/AccessoryModal";
import LeaderIcon from './common/LeaderIcon'
const { Option} = Select;
const CheckboxGroup = Checkbox.Group;
const confirm = Modal.confirm;
@ -97,7 +97,12 @@ function buildColumns(that, student_works, studentData) {
}} title={text && text.length > 5 ? text : ''}>
{/* <Tooltip placement="bottom" title={text}>
</Tooltip> */}
{text}
{record.is_leader ?
<div style={{ display: 'flex', 'flex-direction': 'column', 'align-items': 'center'}}>
<div >{text}</div>
<LeaderIcon></LeaderIcon>
</div>
: <React.Fragment>{text}</React.Fragment>}
</div>
),
}]

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

@ -0,0 +1,19 @@
import React,{Component} from "React";
export default function LeaderIcon(props = {}) {
let icon = null;
if (props.small) {
icon = <div className="font-8 blueFull Actionbtn" style={{
height: '14px',
'line-height': '14px',
width: '24px',
padding: 0,
'margin-top': '-2px',
'margin-left': '2px',
'vertical-align': 'middle', }}>组长</div>
} else {
icon = <div className="font-8 blueFull Actionbtn" style={{ height: '16px', 'line-height': '16px', width: '30px'}}>组长</div>
}
return icon
}

@ -85,8 +85,7 @@ class WorkDetailPageHeader extends Component{
background: #fff;
}
.workDetailPageHeader .summaryname {
line-height: 20px;
margin-top: 13px;
line-height:30px
}
`}</style>
<CBreadcrumb items={[
@ -99,18 +98,18 @@ class WorkDetailPageHeader extends Component{
// { name: childModuleName }
]}></CBreadcrumb>
<div style={{ width:'100%',height:'52px'}} >
<span className=" fl color-black summaryname" style={{height: 'auto'}}>
<div className="clearfix mt20 mb20" >
<span className=" fl color-black summaryname">
{homework_name}
{/* <Link to={"/courses/"+courseId+"/graduation"+"/graduation_tasks/"}>{homework_name}</Link> */}
</span>
<CoursesListType
typelist={homework_status}
typesylename={"mt12"}
typesylename={"mt3"}
/>
{category && <a className="color-grey-6 fr font-16 ml30 mt7 mr20" onClick={this.goback} style={{ marginRight: '26px'}}>返回</a>}
{category && <a className="color-grey-6 fr font-16 ml30 mr30 lineh-25" onClick={this.goback}>返回</a>}
{this.props.update_atta &&
<React.Fragment>

@ -143,7 +143,9 @@ class commonWork extends Component{
this.setState({
order:e.key==="all"?"":e.key,
page:1,
isSpin:true
isSpin:true,
checkBoxValues:[],
checkAll:false
})
let {search}=this.state;
this.getList(1,search,e.key==="all"?"":e.key);

@ -1,5 +1,5 @@
import React, { Component } from 'react';
import {getImageUrl} from 'educoder';
import { getImageUrl , getUrl } from 'educoder';
class NoneData extends Component{
constructor(props) {
@ -9,7 +9,20 @@ class NoneData extends Component{
const { style } = this.props;
return(
<div className="edu-tab-con-box clearfix edu-txt-center" style={style}>
<img className="edu-nodata-img mb20" src={getImageUrl("images/educoder/nodata.png")}/>
<style>
{`
.edu-tab-con-box{
padding:100px 0px;
}
.ant-modal-body .edu-tab-con-box{
padding:0px!important;
}
img.edu-nodata-img{
margin: 40px auto 20px;
}
`}
</style>
<img className="edu-nodata-img mb20" src={getUrl("/images/educoder/nodata.png")}/>
<p className="edu-nodata-p mb20">暂时还没有相关数据哦</p>
</div>
)

@ -572,7 +572,7 @@ class Exercise extends Component{
{...this.props}
{...this.state}
item={item}
key={key}
index={key}
onItemClick={this.onItemClick}
checkBox={<Checkbox value={item.id} key={item.id}
></Checkbox>}

@ -52,17 +52,17 @@ class ExerciseListItem extends Component{
})
}
render(){
let{item,checkBox}=this.props;
let{item,checkBox,index}=this.props;
let {coursesId,Id}=this.props.match.params
const IsAdmin =this.props.isAdmin();
const IsStudent =this.props.isStudent();
// console.log(this.props.current_user.user_id)
return(
<div className="workList_Item" style={{padding:"30px"}} onClick={() => this.props.onItemClick(this.props.item)}>
<div className="workList_Item" style={{cursor : IsAdmin ? "pointer" : "default",padding:"30px" }} onClick={() => this.props.onItemClick(this.props.item)}>
{
IsAdmin &&
<span className="fl mr12">
<span className={`exerciseitem${index} fl mr12`}>
{checkBox}
</span>
}
@ -96,20 +96,20 @@ class ExerciseListItem extends Component{
{/*<Link to={`/courses/${coursesId}/exercises/${item.id}/exercises/student_exercise_list?tab=0`} className="fl font-16 font-bd mt2 color-grey-3 task-hide" style={{"maxWidth":"600px"}}>{item.exercise_name}</Link>*/}
{
this.props.isAdmin()? <a className="fl font-16 font-bd mt2 color-grey-3 task-hide comnonwidth580"
this.props.isAdmin()? <Link className="fl font-16 font-bd mt2 color-grey-3 task-hide comnonwidth580"
title={item.exercise_name}
href={`/courses/${coursesId}/exercises/${item.id}/student_exercise_list?tab=0`}>{item.exercise_name}</a>:""
to={`/courses/${coursesId}/exercises/${item.id}/student_exercise_list?tab=0`}>{item.exercise_name}</Link>:""
}
{
this.props.isStudent()?
<a className="fl font-16 font-bd mt2 color-grey-3 task-hide comnonwidth580" title={item.exercise_name} href={`/courses/${coursesId}/exercises/${item.id}/student_exercise_list?tab=0`}>{item.exercise_name}</a>:""
<Link className="fl font-16 font-bd mt2 color-grey-3 task-hide comnonwidth580" title={item.exercise_name} to={`/courses/${coursesId}/exercises/${item.id}/student_exercise_list?tab=0`}>{item.exercise_name}</Link>:""
}
{
this.props.isNotMember()? item.lock_status === 0 ?
<span className="fl mt3 font-16 font-bd color-dark comnonwidth580" title={item.exercise_name}>{item.exercise_name}</span>
: <a className="fl font-16 font-bd mt2 color-grey-3 task-hide comnonwidth580" title={item.exercise_name} href={`/courses/${coursesId}/exercises/${item.id}/student_exercise_list?tab=0`}>{item.exercise_name}</a>:""
: <Link className="fl font-16 font-bd mt2 color-grey-3 task-hide comnonwidth580" title={item.exercise_name} to={`/courses/${coursesId}/exercises/${item.id}/student_exercise_list?tab=0`}>{item.exercise_name}</Link>:""
}
{
@ -165,8 +165,8 @@ class ExerciseListItem extends Component{
{ IsAdmin &&<div className="homepagePostSetting" style={{"right":"-17px","top":"51px","display":"block","width":"100px"}}>
<a className="btn colorblue font-16" href={`/courses/${coursesId}/exercises/${item.id}/edit`}>编辑</a>
<a className="btn colorblue ml20 font-16" href={`/courses/${coursesId}/exercises/${item.id}/student_exercise_list?tab=3`}>设置</a>
<Link className="btn colorblue font-16" to={`/courses/${coursesId}/exercises/${item.id}/edit`}>编辑</Link>
<Link className="btn colorblue ml20 font-16" to={`/courses/${coursesId}/exercises/${item.id}/student_exercise_list?tab=3`}>设置</Link>
</div> }
</p>

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

@ -541,6 +541,18 @@ class ExerciseReviewAndAnswer extends Component{
.inputNumber30 .ant-input-number-input-wrap .ant-input-number-input{
height: 28px;
}
.setRadioStyle{
width:100%;
cursor:pointer;
}
.setRadioStyle span:last-child{
flex:1;
display:flex;
}
.setRadioStyle .ant-radio,.setRadioStyle .ant-checkbox{
height:16px;
margin-top:2px;
}
`}</style>
{/*<p style={{height:"60px"}}></p>*/}
<Modals

@ -44,19 +44,19 @@ class Multiple extends Component{
console.log(questionType);
return(
<div className="pl30 pr30 singleDisplay">
<Checkbox.Group disabled={ user_exercise_status == 1 ? true : false } onChange={this.saveId} value={questionType.user_answer}>
<Checkbox.Group className="with100" disabled={ user_exercise_status == 1 ? true : false } onChange={this.saveId} value={questionType.user_answer}>
{
questionType.question_choices && questionType.question_choices.map((item,key)=>{
let prefix = `${tagArray[key]}.`
return(
<p className="clearfix mb15 df">
<Checkbox className="fl lineh-15 df mr8 mt2" value={item.choice_id} key={item.choice_id}>{prefix}</Checkbox>
{/* <span class="fl lineh-20 mt1"></span> */}
{/* <span style={{display:"inline-block"}} className="markdown-body " dangerouslySetInnerHTML={{__html: markdownToHTML1(item.choice_text)}}></span> */}
<Checkbox className="lineh-15 df mr8 setRadioStyle" value={item.choice_id}>
<span className="fl mr3 lineh-20">{prefix}</span>
<MarkdownToHtml content={item.choice_text} selector={'multiple_' + (this.props.index + 1) + (key + 1)}
className="" style={{display:"inline-block"}}
className="flex1" style={{display:"inline-block"}}
></MarkdownToHtml>
</Checkbox>
</p>
)
})

@ -40,18 +40,18 @@ class single extends Component{
let isJudge = questionType.question_type == 2
return(
<div className="pl30 pr30 singleDisplay">
<Radio.Group disabled={ user_exercise_status == 1 ? true : false } value={questionType.user_answer[0]} onChange={this.changeItem}>
<Radio.Group className="with100" disabled={ user_exercise_status == 1 ? true : false } value={questionType.user_answer[0]} onChange={this.changeItem}>
{
questionType.question_choices && questionType.question_choices.map((item,key)=>{
let prefix = isJudge ? undefined : `${tagArray[key]}.`
return(
<p className={parseInt(questionType.question_type) == 0 ? "clearfix mb15 df" : "fl mr40 df"}>
<Radio className="fl lineh-20" value={item.choice_id}>{prefix}</Radio>
{/* <span className="fl lineh-20 mr3 "></span> */}
{/* <span style={{display:"inline-block", 'margin-top': '-1px'}} className="markdown-body fl " dangerouslySetInnerHTML={{__html: markdownToHTML1(item.choice_text)}}></span> */}
<p className={parseInt(questionType.question_type) == 0 ? "clearfix mb15" : "fl mr40"}>
<Radio className="df lineh-20 setRadioStyle" value={item.choice_id}>
<span className="fl mr3">{prefix}</span>
<MarkdownToHtml content={item.choice_text} selector={'single_' + (this.props.index + 1) + (key + 1)}
className="fl" style={{display:"inline-block", 'margin-top': '-1px'}}
className="flex1" style={{display:"inline-block", 'margin-top': '-1px'}}
></MarkdownToHtml>
</Radio>
</p>
)
})

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

@ -151,16 +151,12 @@ class GraduateTaskItem extends Component{
coursesId,
categoryid,
taskid,
index,
isAdmin
} = this.props;
// console.log(discussMessage)
return(
<div className="graduateTopicList boardsList">
<div className="graduateTopicList boardsList" style={{cursor : isAdmin ? "pointer" : "default" }} onClick={() => window.$(`.taskitem${index} input`).click() }>
<Modals
modalsType={Modalstype}
modalsTopval={Modalstopval}
@ -193,8 +189,9 @@ class GraduateTaskItem extends Component{
margin-right: 15px;
}
`}</style>
<span className={`taskitem${index} fl`} style={{"height":"59px"}}>
{ checkBox }
</span>
{/*
style={{borderTop:data===undefined?"":data.course_identity<4?'1px solid #EBEBEB':'1px solid transparent'}}
*/}

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

@ -393,7 +393,9 @@ class GraduationTasks extends Component{
this.setState({
order: e.key,
isSpin:true
isSpin:true,
checkBoxValues:[],
checkAllValue:false
});
let newkey=e.key;
@ -738,7 +740,7 @@ class GraduationTasks extends Component{
{ tasks&&tasks.map((item, index) => {
// console.log(item)
return (
<div className="mt20 edu-back-white padding02010" key={index} onClick={()=>this.onItemClick(item)}>
<div className="mt20 edu-back-white pt10 pl30 pr30" key={index} onClick={()=>this.onItemClick(item)}>
<div className="clearfix">
<GraduateTaskItem
discussMessage={item}
@ -755,6 +757,7 @@ class GraduationTasks extends Component{
coursesId={this.props.match.params.coursesId}
categoryid={this.props.match.params.Id}
workid={item.work_id}
index={index}
></GraduateTaskItem>
</div>
</div>

@ -6,7 +6,7 @@ import '../style.css'
import axios from "axios";
import GraduateTopicReply from './GraduateTopicReply'
import { ConditionToolTip,MarkdownToHtml } from 'educoder'
import { ConditionToolTip , MarkdownToHtml , AttachmentList } from 'educoder'
const $=window.$;
const type={1: "设计",2: "论文", 3: "创作"}
@ -60,9 +60,10 @@ class GraduateTopicDetailTable extends Component{
{
topicInfo && topicInfo.attachment_list.length>0 &&
<p className="mt30">
{
{/* {
topicInfo.attachment_list.map((item,key)=>{
return(
<li className="clearfix mb8" key={key}>
<i className="iconfont icon-fujian color-green font-16 mr8 fl"></i>
<ConditionToolTip title={item.title} condition={item.title && item.title.length > 30 }>
@ -72,7 +73,8 @@ class GraduateTopicDetailTable extends Component{
</li>
)
})
}
} */}
<AttachmentList {...this.props} {...this.state} attachments = {topicInfo.attachment_list}></AttachmentList>
</p>
}
</div>

@ -47,7 +47,7 @@ class GraduateTopicItem extends Component{
}
</style>
<div className="graduateTopicList boardsList mb20">
<div className="graduateTopicList boardsList mb20" style={{cursor : isAdmin ? "pointer" : "default" }} onClick={() => window.$(`.topicItem${index} input`).click() }>
<style>{`
.graduateTopicList .ant-checkbox-input {s
@ -58,7 +58,7 @@ class GraduateTopicItem extends Component{
padding: 17px 30px 20px!important;
}
`}</style>
{ isAdmin ? checkBox : ""}
{ isAdmin ? <span className={`topicItem${index} fl`} style={{"height":"64px"}}>{checkBox}</span> : ""}
<div className="clearfix ds pr flex1">
<style>{`
.maxwidth580{

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

@ -13,12 +13,15 @@ class CreateGroupByImportModal extends Component{
constructor(props){
super(props);
this.state={
errorTip:undefined
}
}
fetchMemberList = (arg_page) => {
}
componentDidMount() {
onSendOk = () => {
}
onSendOk = () => {
const courseId = this.props.match.params.coursesId
let url = `/courses/${courseId}/create_group_by_importing_file.json`
@ -109,7 +112,7 @@ class CreateGroupByImportModal extends Component{
render(){
const { candidates, checkBoxValues, loading, hasMore, name, school_name, school_names
, graduationGroup, graduation_groups, courseGroup, course_groups , fileList , errorTip } = this.state
, graduationGroup, graduation_groups, courseGroup, course_groups , fileList } = this.state
const { moduleName } = this.props
const props = {
@ -138,9 +141,6 @@ class CreateGroupByImportModal extends Component{
单个文件最大150MB
</p>
</Dragger>
<p className="color-red lineh-25 edu-txt-left" style={{height:"25px"}}>
<span className={ errorTip ? "" : "none" }>{errorTip}</span>
</p>
</ModalWrapper>
)
}

@ -44,7 +44,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 +80,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);
if(data.course_modules===undefined||data.course_modules.length===0){
this.setState({
checkboxgroup: dataysl3,
})
checkbofrups:this.state.checkbofrup,
});
}
}catch (e) {
this.setState({
checkboxgroup:this.state.checkbofrup,
})
checkbofrups:this.state.checkbofrup,
});
}
this.handleSearchschool(data.school);
}).catch((error) => {
console.log(error);
@ -450,6 +442,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 +454,7 @@ class CoursesNew extends Component {
})
}
}
}
}).catch((error)=>{
console.log(error)
})
@ -469,7 +463,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
@ -699,27 +693,9 @@ 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>
:""
<Checkbox key={key} value={item.module_type} className="fl">{item.module_name}</Checkbox>
)
})
}
@ -729,16 +705,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>

@ -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
@ -860,6 +878,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>

@ -288,6 +288,7 @@ class Poll extends Component{
})
let{type,StudentList_value}=this.state
this.InitList(type,StudentList_value,1);
this.props.updataleftNavfun();
}
}).catch((error)=>{
console.log(error);
@ -595,7 +596,7 @@ class Poll extends Component{
{...this.state}
courseType={course_types}
item={item}
key={key}
index={key}
onItemClick={this.onItemClick}
checkBox={<Checkbox value={item.id} key={item.id} onClick={() => this.onItemClick(item)}></Checkbox>}
></PollListItem>

@ -16,7 +16,7 @@ class PollListItem extends Component{
super(props);
}
render(){
let{item,checkBox,courseType}=this.props;
let{item,checkBox,courseType,index}=this.props;
let {coursesId}=this.props.match.params;
const IsAdmin =this.props.isAdmin();
@ -28,10 +28,10 @@ class PollListItem extends Component{
let canNotLink = !isAdminOrStudent && item.lock_status == 0
return(
<div className="workList_Item polllisthover" style={{padding:"30px"}} onClick={() => this.props.onItemClick(this.props.item)}>
<div className="workList_Item polllisthover" style={{cursor : IsAdmin ? "pointer" : "default",padding:"30px" }} onClick={() => this.props.onItemClick(this.props.item)}>
{
IsAdmin &&
<span className="fl mr12">
<span className={`pollitem${index} fl mr12`}>
{checkBox}
</span>
}

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

@ -124,13 +124,19 @@ class ShixunhomeWorkItem extends Component{
})
}
editname = (name,id) => {
// 实训详情,阻止冒泡
stopPro = (event) => {
event.stopPropagation()
}
editname = (name,id,event) => {
this.setState({
ModalsRenametype:true,
NavmodalValue:name,
Navmodalname:"重命名",
url:`/homework_commons/${id}/alter_name.json`
})
event.stopPropagation()
}
cannerNavmoda=()=>{
this.setState({
@ -157,23 +163,12 @@ class ShixunhomeWorkItem extends Component{
const { checkBox,
discussMessage,
taskid,
taskid,index
} = this.props;
//
// allow_late: true //是否开启补交
// homework_id: 9250
// shixun_identifier: "25ykhpvl"
//
// console.log("this.props.isAdmin");
return(
<div className="graduateTopicList boardsList">
{this.state.ModalsRenametype===true?
<React.Fragment>
{
this.state.ModalsRenametype===true?
<ModalsRename
{...this.props}
Navmodalnametype={this.state.ModalsRenametype}
@ -184,7 +179,6 @@ class ShixunhomeWorkItem extends Component{
cannerNavmoda={()=>this.cannerNavmoda()}
/>
:""}
<Modals
modalsType={Modalstype}
modalsTopval={Modalstopval}
@ -193,7 +187,6 @@ class ShixunhomeWorkItem extends Component{
modalSave={cardsModalsavetype}
loadtype={loadtype}
/>
{visible===true?<Associationmodel
modalname={modalname}
visible={visible}
@ -201,8 +194,6 @@ class ShixunhomeWorkItem extends Component{
taskid={taskid}
funlist={this.props.funlist}
/>:""}
<Modal
keyboard={false}
title="提示"
@ -218,6 +209,7 @@ class ShixunhomeWorkItem extends Component{
onClick={() => this.hidestartshixunsreplace(hidestartshixunsreplacevalue)}>知道了</a>
</div>
</Modal>
<Modal
keyboard={false}
title="提示"
@ -238,7 +230,7 @@ class ShixunhomeWorkItem extends Component{
{/*</p>*/}
</Modal>
<div className="graduateTopicList boardsList" style={{cursor : this.props.isAdmin ? "pointer" : "default"}} onClick={() => window.$(`.shixunitem${index} input`).click() } >
<style>{`
.boardsList .ant-checkbox-wrapper{
margin-top: -35px;
@ -284,7 +276,11 @@ class ShixunhomeWorkItem extends Component{
`}</style>
{this.props.isAdmin?checkBox:""}
{this.props.isAdmin?
<span className={`shixunitem${index} fl`} style={{"height":"55px"}}>{checkBox}</span>
:
""
}
<div className="clearfix ds pr pt5 contentSection" >
<style>{`
@ -299,23 +295,23 @@ class ShixunhomeWorkItem extends Component{
{/*to={`/courses/${this.props.match.params.coursesId}/${discussMessage.homework_id}/jobsettings`}*/}
{
this.props.isAdmin?<a href={"/courses/"+this.props.match.params.coursesId+"/"+this.state.shixuntypes+"/"+discussMessage.homework_id+"/list?tab=0"}
this.props.isAdmin?<Link to={"/courses/"+this.props.match.params.coursesId+"/"+this.state.shixuntypes+"/"+discussMessage.homework_id+"/list?tab=0"}
title={discussMessage.name}
className="fl mt3 font-16 font-bd color-dark maxwidth580">{discussMessage.name}</a>:""
className="fl mt3 font-16 font-bd color-dark maxwidth580">{discussMessage.name}</Link>:""
}
{
this.props.isStudent? <a href={`/courses/${this.props.match.params.coursesId}/${this.state.shixuntypes}/${discussMessage.homework_id}/list?tab=0`}
this.props.isStudent? <Link to={`/courses/${this.props.match.params.coursesId}/${this.state.shixuntypes}/${discussMessage.homework_id}/list?tab=0`}
title={discussMessage.name}
className="fl mt3 font-16 font-bd color-dark maxwidth580">{discussMessage.name}</a>:""
className="fl mt3 font-16 font-bd color-dark maxwidth580">{discussMessage.name}</Link>:""
}
{
this.props.isNotMember===true? this.props.discussMessage.private_icon===true?
<span className="fl mt3 font-16 font-bd color-dark maxwidth580" title={discussMessage.name}>{discussMessage.name}</span>
: <a href={`/courses/${this.props.match.params.coursesId}/${this.state.shixuntypes}/${discussMessage.homework_id}/list?tab=0`}
: <Link to={`/courses/${this.props.match.params.coursesId}/${this.state.shixuntypes}/${discussMessage.homework_id}/list?tab=0`}
title={discussMessage.name}
className="fl mt3 font-16 font-bd color-dark maxwidth580">{discussMessage.name}</a>:""
className="fl mt3 font-16 font-bd color-dark maxwidth580">{discussMessage.name}</Link>:""
}
@ -383,9 +379,9 @@ class ShixunhomeWorkItem extends Component{
`
}
</style>
{this.props.isAdmin?<div className={this.props.isAdminOrCreator()?"homepagePostSetting homepagePostSettingname":"homepagePostSetting homepagePostSettingbox"} style={{"right":"-2px","top":"44px","display":"block"}}>
<a className="btn colorblue font-16" href={"/shixuns/"+discussMessage.shixun_identifier+"/challenges"} target={"_blank"}>实训详情</a>
{this.props.isAdminOrCreator()?<a onClick={()=>this.editname(discussMessage.name,discussMessage.homework_id)} className={"btn colorblue ml20 font-16"}>重命名</a>:""}
{this.props.isAdmin?<div onClick={(event)=>this.stopPro(event)} className={this.props.isAdminOrCreator()?"homepagePostSetting homepagePostSettingname":"homepagePostSetting homepagePostSettingbox"} style={{"right":"-2px","top":"44px","display":"block"}}>
<Link className="btn colorblue font-16" to={"/shixuns/"+discussMessage.shixun_identifier+"/challenges"} target={"_blank"}>实训详情</Link>
{this.props.isAdminOrCreator()?<a onClick={(event)=>this.editname(discussMessage.name,discussMessage.homework_id,event)} className={"btn colorblue ml20 font-16"}>重命名</a>:""}
{/*<WordsBtn className="btn colorblue ml20 font-16" to={`/courses/${this.props.match.params.coursesId}/${this.state.shixuntypes}/${discussMessage.homework_id}/settings?tab=3`} > 设置</WordsBtn>*/}
<WordsBtn className="btn colorblue font-16 ml15" to={`/courses/${this.props.match.params.coursesId}/${this.state.shixuntypes}/${discussMessage.homework_id}/settings?tab=3`} > 设置</WordsBtn>
</div>:""}
@ -408,6 +404,7 @@ class ShixunhomeWorkItem extends Component{
</div>
</div>
</React.Fragment>
)
}
}

@ -587,6 +587,8 @@ class ShixunHomework extends Component{
let {Coursename,page}=this.state;
this.setState({
order: e.key,
checkBoxValues:[],
checkedtype:false,
isSpin:true
});
let newkey=e.key;
@ -1029,8 +1031,8 @@ class ShixunHomework extends Component{
<div className="edu-back-white">
<p className="clearfix padding30 bor-bottom-greyE">
<p style={{height: '20px'}}>
<span className="font-18 fl color-dark-21">{datas&&datas.category_name===undefined||datas&&datas.category_name===null?datas&&datas.main_category_name:datas&&datas.category_name+" 作业列表"}</span>
{/* <span className="font-18 fl color-dark-21">实训作业</span>*/}
{/*<span className="font-18 fl color-dark-21">{datas&&datas.category_name===undefined||datas&&datas.category_name===null?datas&&datas.main_category_name:datas&&datas.category_name+" 作业列表"}</span>*/}
<span className="font-18 fl color-dark-21">实训作业</span>
<li className="fr">
{this.props.isAdmin()===true?datas&&datas.category_name===undefined||datas&&datas.category_name===null?
<span>
@ -1175,6 +1177,7 @@ class ShixunHomework extends Component{
isClassManagement={this.props.isClassManagement()}
checkBox={this.props.isAdmin()?<Checkbox value={item.homework_id} key={item.homework_id}></Checkbox>:""}
match={this.props.match}
index={index}
coursedata={this.props.coursedata}
coursupdata={()=>this.homeworkupdatalist(Coursename,page,order)}
course_identity={datas.course_identity}

@ -224,12 +224,15 @@ class MainContentContainer extends Component {
}
componentDidUpdate(prevProps, prevState, snapshot) {
const { game } = this.props
const { game, challenge } = this.props
if (game && prevProps.game
&& prevProps.game.identifier !== game.identifier) {
// 切换关卡时,停止轮训
this.oldGameIdentifier = prevProps.game.identifier;
this.doFileUpdateRequestOnCodeMirrorBlur(prevProps)
} else if (challenge && (challenge.pathIndex || prevProps.challenge.pathIndex) && challenge.pathIndex != prevProps.challenge.pathIndex) {
this.doFileUpdateRequestOnCodeMirrorBlur(prevProps)
}
}
@ -386,8 +389,8 @@ class MainContentContainer extends Component {
}
doFileUpdateRequestOnCodeMirrorBlur = () => {
var fileUpdatePromise = this.doFileUpdateRequest(true)
doFileUpdateRequestOnCodeMirrorBlur = (props) => {
var fileUpdatePromise = this.doFileUpdateRequest(true, undefined, props)
if (fileUpdatePromise) {
fileUpdatePromise.then((resData) => {
if (resData.status === -1) { // 保存文件出现异常
@ -496,7 +499,8 @@ class MainContentContainer extends Component {
}
// forTest true 是评测时触发的file_update
doFileUpdateRequest(checkIfCodeChanged, forTest) {
doFileUpdateRequest(checkIfCodeChanged, forTest, props) {
const _props = props || this.props;
const { codeStatus } = this.state;
if (!forTest && codeStatus !== UPDATED) { // 已修改状态才能保存
return;
@ -521,7 +525,7 @@ class MainContentContainer extends Component {
})
return null;
}
const { challenge, output_sets, onRunCodeTestFinish, myshixun } = this.props
const { challenge, output_sets, onRunCodeTestFinish, myshixun } = _props
// var url = `${locationPath}/file_update?path=${encodeURIComponent(challenge.path)}`
var url = `/myshixuns/${myshixun.identifier}/update_file.json`

@ -37,6 +37,8 @@ export function ImageLayerOfCommentHOC(options = {}) {
}
// jQuery._data( $('.newMain')[0], "events" )
componentDidMount() {
this.props.wrappedComponentRef && this.props.wrappedComponentRef(this.refs['wrappedComponentRef'])
// commentsDelegateParent #game_left_contents #tab_con_4
setTimeout(() => {
$(options.parentSelector || ".commentsDelegateParent")
@ -60,7 +62,7 @@ export function ImageLayerOfCommentHOC(options = {}) {
<React.Fragment>
<ImageLayer {...this.state} onImageLayerClose={this.onImageLayerClose}></ImageLayer>
<WrappedComponent {...this.props} >
<WrappedComponent {...this.props} ref="wrappedComponentRef">
</WrappedComponent>
</React.Fragment>
)

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

@ -8,7 +8,7 @@ import "./usersInfo.css"
import "../../courses/css/members.css"
import "../../courses/css/Courses.css"
import banner from '../../../images/account/infobanner.png'
import { LinkAfterLogin } from 'educoder'
class InfosBanner extends Component{
constructor(props){
@ -69,7 +69,14 @@ class InfosBanner extends Component{
</span>
:
<span className="fl mt35 ml60">
<a href={`/messages/${login}/message_detail?target_ids=${id}`} className="user_default_btn user_yellow_btn fl font-18">私信</a>
<LinkAfterLogin
{...this.props}
{...this.state}
className="user_default_btn user_yellow_btn fl font-18"
to={`/messages/${login}/message_detail?target_ids=${id}`}
>
私信
</LinkAfterLogin>
</span>
}
</div>
@ -83,7 +90,7 @@ class InfosBanner extends Component{
<li className={`${moduleName == 'shixuns' ? 'active' : '' }`}>
<Link
onClick={() => this.setState({moduleName: 'shixuns'})}
to={`/users/${username}/shixuns`}>实训项目</Link>
to={`/users/${username}/shixuns`}>开发社区</Link>
</li>
<li className={`${moduleName == 'paths' ? 'active' : '' }`}>
<Link
@ -93,7 +100,7 @@ class InfosBanner extends Component{
<li className={`${moduleName == 'projects' ? 'active' : '' }`}>
<Link
onClick={() => this.setState({moduleName: 'projects'})}
to={`/users/${username}/projects`}>开发项目</Link>
to={`/users/${username}/projects`}>项目</Link>
</li>
<li className={`${moduleName == 'package' ? 'active' : '' }`}>
<Link

@ -130,7 +130,7 @@ class InfosCourse extends Component{
this.props.current_user && this.props.current_user.user_identity != "学生" ? <Create href={"/courses/new"} name={"新建课堂"} index="1"></Create> : ""
}
{
(!data || data.courses.length==0) && (!is_current || (this.props.current_user && this.props.current_user.user_identity === "学生" )) && <NoneData></NoneData>
(!data || (data && data.courses.length==0)) && category && <NoneData></NoneData>
}
{
data && data.courses && data.courses.map((item,key)=>{

@ -152,7 +152,7 @@ class InfosPath extends Component{
this.props.current_user && this.props.current_user.user_identity != "学生" ? <Create href={"/paths/new"} name={"新建实践课程"} index="3"></Create>:""
}
{
(!data || data.subjects.length==0) && (!is_current || (this.props.current_user && this.props.current_user.user_identity === "学生" )) && <NoneData></NoneData>
(!data || (data && data.subjects.length==0)) && category && <NoneData></NoneData>
}
{
data && data.subjects && data.subjects.map((item,key)=>{

@ -125,7 +125,7 @@ class InfosProject extends Component{
<Create href={`${this.props.Headertop && this.props.Headertop.old_url}/projects/new`} name={"新建开发项目"} index="4"></Create>:""
}
{
(!data || data.projects.length==0) && (!is_current || (this.props.current_user && this.props.current_user.user_identity === "学生" )) && <NoneData></NoneData>
(!data || (data && data.projects.length==0)) && category && <NoneData></NoneData>
}
{
data && data.projects && data.projects.map((item,key)=>{

@ -1,14 +1,11 @@
import React, { Component } from 'react';
import { SnackbarHOC } from 'educoder';
import {BrowserRouter as Router,Route,Switch} from 'react-router-dom';
import {Tooltip,Menu,Pagination,Spin} from 'antd';
import Loadable from 'react-loadable';
import Loading from '../../../Loading';
import { Pagination , Spin } from 'antd';
import NoneData from '../../courses/coursesPublic/NoneData'
import axios from 'axios';
import {getImageUrl,setImagesUrl} from 'educoder';
import { TPMIndexHOC } from '../../tpm/TPMIndexHOC';
import { CNotificationHOC } from '../../courses/common/CNotificationHOC'
import { setImagesUrl } from 'educoder';
import "./usersInfo.css"
import Create from './publicCreatNew'
@ -115,7 +112,7 @@ class InfosShixun extends Component{
totalCount,
isSpin
} = this.state;
let isStudent = this.props.isStudent();
let is_current=this.props.is_current;
return(
<div className="educontent">
@ -161,16 +158,14 @@ class InfosShixun extends Component{
<Create href={"/shixuns/new"} name={"新建实训"} index="2"></Create>:""
}
{
(!data || data.shixuns.length==0) && (!is_current || (this.props.current_user && this.props.current_user.user_identity === "学生" )) && <NoneData></NoneData>
(!data || (data && data.shixuns.length==0)) && category && <NoneData></NoneData>
}
{
data && data.shixuns && data.shixuns.map((item,key)=>{
return(
<div className="square-Item" onClick={()=>this.turnToCourses(`/shixuns/${item.identifier}/challenges`)}>
{
item.tag && <div className="tag-green"><span className="tag-name">{item.tag}</span>
{/*<img className="fl" src={setImagesUrl("images/educoder/tag2.png")}/>*/}
</div>
item.tag && <div className="tag-green"><span className="tag-name">{item.tag}</span><img className="fl" src={setImagesUrl("images/educoder/tag2.png")}/></div>
}
<a href="javascript:void(0)" className="square-img">
<img src={setImagesUrl(`${item.image_url}`)}/>

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

@ -0,0 +1,6 @@
/*global __webpack_public_path__ */
if (window.location.host == 'pre-newweb.educoder.net') {
__webpack_public_path__ = 'http://testali-cdn.educoder.net/react/build/'
} else if (window.location.host == 'www.educoder.net') {
__webpack_public_path__ = 'https://ali-newweb.educoder.net/react/build/'
}
Loading…
Cancel
Save