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

competitions
杨树林 6 years ago
commit 21e046cb6e

@ -0,0 +1,20 @@
class Admins::CompetitionSettingsController < Admins::BaseController
def show
@competition = current_competition
end
def update
Admins::SaveLaboratorySettingService.call(current_competition, form_params)
render_ok
end
private
def current_competition
@_current_competition ||= Competition.find(params[:competition_id])
end
def form_params
params.permit(:identifier, :name, :nav_logo, :login_logo, :tab_logo, :footer, navbar: %i[name link hidden])
end
end

@ -1,4 +1,6 @@
class Admins::CompetitionsController < Admins::BaseController class Admins::CompetitionsController < Admins::BaseController
include CustomSortable
before_action :find_competition, except: [:index]
def index def index
params[:sort_by] = params[:sort_by].presence || 'created_on' params[:sort_by] = params[:sort_by].presence || 'created_on'
@ -6,10 +8,39 @@ class Admins::CompetitionsController < Admins::BaseController
@competitions = custom_sort Competition.all, params[:sort_by], params[:sort_direction] @competitions = custom_sort Competition.all, params[:sort_by], params[:sort_direction]
@params_page = params[:page] || 1 @params_page = params[:page] || 1
@competitions = paginate @competitions @competitions = paginate @competitions
ids = @competitions.map(&:id)
@member_count_map = TeamMember.where(competition_id: ids).group(:competition_id).count
respond_to do |format| respond_to do |format|
format.js format.js
format.html format.html
end end
end end
def publish
@competition.update_attributes!(:published_at, Time.now)
end
def unpublish
@competition.update_attributes!(:published_at, nil)
end
def online_switch
if @competition.status
@competition.update_attributes!(status: false)
else
@competition.update_attributes!(status: true, online_time: Time.now)
end
end
def enroll_list
end
private
def find_competition
@competition = Competition.find_by(id: params[:id])
end
end end

@ -0,0 +1,34 @@
class Weapps::BaseController < ApplicationController
private
def require_wechat_login!
return if session_unionid.present?
render_error('请先进行微信授权')
end
def weapp_session_key
Wechat::Weapp.session_key(session_openid)
end
def set_weapp_session_key(session_key)
Wechat::Weapp.write_session_key(session_openid, session_key)
end
def session_openid
session[:openid]
end
def set_session_openid(openid)
session[:openid] = openid
end
def session_unionid
session[:unionid]
end
def set_session_unionid(unionid)
session[:unionid] = unionid
end
end

@ -0,0 +1,24 @@
class Weapps::CodeSessionsController < Weapps::BaseController
def create
return render_error('code不能为空') if params[:code].blank?
result = Wechat::Weapp.jscode2session(params[:code])
set_session_openid(result['openid'])
set_weapp_session_key(result['session_key']) # weapp session_key写入缓存 后续解密需要
# 已授权,绑定过账号
open_user = OpenUser::Wechat.find_by(uid: result['unionid'])
if open_user.present? && open_user.user
set_session_unionid(result['unionid'])
successful_authentication(open_user.user)
else
# 新用户
user_info = Wechat::Weapp.decrypt(result['session_key'], params[:encrypted_data], params[:iv])
set_session_unionid(user_info['unionId'])
end
render_ok(openid: result['openid'])
end
end

@ -0,0 +1,12 @@
class Weapps::HomesController < Weapps::BaseController
def show
# banner图
@images = PortalImage.where(status: true).order(position: :asc)
# 热门实训
@shixuns = Shixun.where(homepage_show: true).includes(:tag_repertoires, :challenges).limit(4)
# 热门实践课程
@subjects = Subject.where(homepage_show: true).includes(:shixuns, :repertoire).limit(4)
end
end

@ -0,0 +1,63 @@
class Weapps::RegistersController < Weapps::BaseController
before_action :require_wechat_login!
def create
# 查询验证码是否正确;type只可能是1或者8
type = phone_mail_type(params[:login].strip)
code = params[:code].strip
if type == 1
uid_logger("start register by phone: type is #{type}")
pre = 'p'
email = nil
phone = params[:login]
verifi_code = VerificationCode.where(phone: phone, code: code, code_type: 1).last
else
uid_logger("start register by email: type is #{type}")
pre = 'm'
email = params[:login]
phone = nil
verifi_code = VerificationCode.where(email: email, code: code, code_type: 8).last
end
uid_logger("start register: verifi_code is #{verifi_code}, code is #{code}, time is #{Time.now.to_i - verifi_code.try(:created_at).to_i}")
# check_code = (verifi_code.try(:code) == code.strip && (Time.now.to_i - verifi_code.created_at.to_i) <= 10*60)
# todo 上线前请删除万能验证码"513231"
unless code == "513231" && request.subdomain == "test-newweb"
return render_error('验证码不正确') if verifi_code.try(:code) != code.strip
return render_error('验证码已失效') if !verifi_code&.effective?
end
login = User.generate_login(pre)
@user = User.new(admin: false, login: login, mail: email, phone: phone, type: 'User')
@user.password = params[:password]
# 现在因为是验证码,所以在注册的时候就可以激活
@user.activate
# 必须要用save操作密码的保存是在users中
ActiveRecord::Base.transaction do
@user.save!
UserExtension.create!(user_id: @user.id)
# 绑定微信号
OpenUsers::Wechat.create!(user: @user, uid: session_unionid)
# 注册完成手机号或邮箱想可以奖励500金币
RewardGradeService.call(
@user,
container_id: @user.id,
container_type: pre == 'p' ? 'Phone' : 'Mail',
score: 500
)
end
successful_authentication(@user)
session[:user_id] = @user.id
render_ok
end
private
# 1 手机类型0 邮箱类型
# 注意新版的login是自动名生成的
def phone_mail_type value
value =~ /^1\d{10}$/ ? 1 : 0
end
end

@ -0,0 +1,24 @@
class Weapps::SessionsController < Weapps::BaseController
before_action :require_wechat_login!
def create
return render_error('重复登录') if current_user.present? && current_user.logged?
user = User.try_to_login(params[:login], params[:password])
return render_error('错误的账号或密码') if user.blank?
return render_error('违反平台使用规范,账号已被锁定') if user.locked?
return render_error('错误的账号或密码') unless user.check_password?(params[:password].to_s)
if user.wechat_open_user && user.wechat_open_user.uid != session_unionid
render_error('该账号已被其它微信号绑定')
return
end
# 绑定微信号
OpenUsers::Wechat.create!(user: user, uid: session_unionid) if user.wechat_open_user.blank?
successful_authentication(user)
render_ok
end
end

@ -0,0 +1,8 @@
class Weapps::VerifiesController < Weapps::BaseController
before_action :require_wechat_login!
def create
valid = Wechat::Weapp.verify?(session_openid, params[:verify_string], params[:signature])
render_ok(valid: valid)
end
end

@ -1,4 +1,4 @@
class Wechat::App class Wechat::Weapp
class << self class << self
attr_accessor :appid, :secret attr_accessor :appid, :secret
@ -7,5 +7,41 @@ class Wechat::App
def client def client
@_client ||= Wechat::Client.new(appid, secret) @_client ||= Wechat::Client.new(appid, secret)
end end
def session_key(openid)
Rails.cache.read(session_key_cache_key(openid))
end
def write_session_key(openid, session_key)
Rails.cache.write(session_key_cache_key(openid), session_key)
end
def verify?(openid, str, signature)
session_key = session_key(openid)
Digest::SHA1.hexdigest("#{str}#{session_key}") == signature
end
def decrypt(session_key, encrypted_data, iv)
session_key = Base64.decode64(session_key)
encrypted_data = Base64.decode64(encrypted_data)
iv = Base64.decode64(iv)
cipher = OpenSSL::Cipher::AES.new(128, :CBC)
cipher.decrypt
cipher.padding = 0
cipher.key = session_key
cipher.iv = iv
data = cipher.update(encrypted_data) << cipher.final
result = JSON.parse(data[0...-data.last.ord])
raise Wechat::Error, '解密错误' if result.dig('watermark', 'appid') != appid
result
end
private
def session_key_cache_key(openid)
"weapp:#{appid}:#{openid}:session_key"
end
end end
end end

@ -18,6 +18,29 @@ class Competition < ApplicationRecord
after_create :create_competition_modules after_create :create_competition_modules
def mode_type
case mode
when 1
"课堂"
when 2
"实训"
when 3
"教学"
when 4
"托管"
else
"--"
end
end
def teacher_staff_num
teacher_staff ? "#{teacher_staff.minimum}~#{teacher_staff.maximum}" : "--"
end
def member_staff_num
member_staff ? "#{member_staff.minimum}~#{member_staff.maximum}" : "--"
end
# 是否上架 # 是否上架
def published? def published?
status? status?

@ -3,5 +3,7 @@
<% end %> <% end %>
<div class="box competitions-list-container"> <div class="box competitions-list-container">
<%= render partial: 'admins/shixuns/shared/list', locals: { shixuns: @shixuns } %> <%= render partial: 'admins/competitions/shared/list', locals: { competitions: @competitions } %>
</div> </div>
<%= render partial: 'admins/shared/modal/upload_file_modal', locals: { title: '上传图片' } %>

@ -0,0 +1,30 @@
<table class="table text-center shixun-settings-list-table">
<thead class="thead-light">
<th width="6%">序号</th>
<th width="14%" class="text-left">竞赛主标题</th>
<th width="10%">竞赛副标题</th>
<th width="8%">模式</th>
<th width="8%">报名人数</th>
<th width="8%">指导老师</th>
<th width="8%">参赛者</th>
<th width="14%">主题图片796*397</th>
<th width="8%">创建时间</th>
<th>
操作
</th>
</thead>
<tbody>
<% if competitions.present? %>
<% competitions.each_with_index do |competition, index| %>
<tr id="competition-item-<%= competition.id %>">
<% page_no = list_index_no(@params_page.to_i, index) %>
<%= render partial: "admins/competitions/shared/td",locals: {competition: competition, page_no: page_no} %>
</tr>
<% end %>
<% else %>
<%= render 'admins/shared/no_data_for_table' %>
<% end %>
</tbody>
</table>
<%= render partial: 'admins/shared/paginate', locals: { objects: competitions } %>

@ -0,0 +1,27 @@
<td><%= page_no %></td>
<td class="text-left">
<span><%= link_to competition.name, enroll_list_admins_competition_path(competition), :target => "_blank", :title => competition.name %></span>
</td>
<td><%= competition.sub_title %></td>
<td><%= competition.mode_type %></td>
<td><%= @member_count_map&.fetch(competition.id, 0) || competition.team_members.count %></td>
<td><%= competition.teacher_staff_num %></td>
<td><%= competition.member_staff_num %></td>
<td class="shixun-setting-image">
<% imageExists = File.exist?(disk_filename("Competition", competition.id)) %>
<% imageUrl = imageExists ? '/' + url_to_avatar(competition) + "?#{Time.now.to_i}" : '' %>
<%= image_tag(imageUrl, width: 60, height: 40, class: "preview-image competition-image-#{competition.id}", data: { toggle: 'tooltip', title: '点击预览' }, style: imageExists ? '' : 'display:none') %>
<%= javascript_void_link imageExists ? '重新上传' : '上传图片', class: 'action upload-competition-image-action', data: { source_id: competition.id, source_type: 'Competition', toggle: 'modal', target: '.admin-upload-file-modal' } %>
</td>
<td><%= competition.created_at.strftime('%Y-%m-%d %H:%M') %></td>
<td class="action-container">
<%= link_to '配置', admins_competition_competition_setting_path(competition), class: 'action edit-action' %>
<% if !competition.status? && competition.published_at.blank? %>
<%= link_to '发布', publish_admins_competition_path(competition), class: 'action publish-action', method: :post, remote: true %>
<% else %>
<%= link_to '取消发布', unpublish_admins_competition_path(competition), class: 'action unpublish-action', method: :post, remote: true %>
<% end %>
<%= link_to competition.published? ? "下架" : "上架", online_switch_admins_competition_path(competition), class: 'action online-action', method: :post, remote: true %>
</td>

@ -0,0 +1,14 @@
json.images do
json.array! @images do |image|
json.path image.link
json.image_url Util::FileManage.source_disk_file_url(image)
end
end
json.shixuns do
json.partial! 'shixuns/shixun', locals: { shixuns: @shixuns }
end
json.subjects do
json.partial! 'subjects/subject', locals: { subjects: @subjects }
end

@ -18,6 +18,9 @@ defaults: &defaults
wechat: wechat:
appid: 'test' appid: 'test'
secret: 'test' secret: 'test'
weapp:
appid: 'test'
secret: 'test'
development: development:
<<: *defaults <<: *defaults

@ -1,9 +1,12 @@
wechat_config = {} wechat_config = {}
weapp_config = {}
begin begin
config = Rails.application.config_for(:configuration) config = Rails.application.config_for(:configuration)
wechat_config = config['wechat'] wechat_config = config['wechat']
weapp_config = config['weapp']
raise 'wechat config missing' if wechat_config.blank? raise 'wechat config missing' if wechat_config.blank?
raise 'weapp config missing' if weapp_config.blank?
rescue => ex rescue => ex
raise ex if Rails.env.production? raise ex if Rails.env.production?
@ -12,5 +15,10 @@ rescue => ex
wechat_config = {} wechat_config = {}
end end
# 网站应用
Wechat::OfficialAccount.appid = wechat_config['appid'] Wechat::OfficialAccount.appid = wechat_config['appid']
Wechat::OfficialAccount.secret = wechat_config['secret'] Wechat::OfficialAccount.secret = wechat_config['secret']
# 小程序
Wechat::Weapp.appid = weapp_config['appid']
Wechat::Weapp.secret = weapp_config['secret']

@ -829,6 +829,14 @@ Rails.application.routes.draw do
get '/auth/qq/callback', to: 'oauth/qq#create' get '/auth/qq/callback', to: 'oauth/qq#create'
get '/auth/wechat/callback', to: 'oauth/wechat#create' get '/auth/wechat/callback', to: 'oauth/wechat#create'
resource :bind_user, only: [:create] resource :bind_user, only: [:create]
namespace :weapps do
resource :home, only: [:show]
resource :session, only: [:create]
resource :register, only: [:create]
resource :code_session, only: [:create]
resource :verify, only: [:create]
end
end end
namespace :admins do namespace :admins do
@ -981,7 +989,15 @@ Rails.application.routes.draw do
resource :laboratory_user, only: [:create, :destroy] resource :laboratory_user, only: [:create, :destroy]
end end
resources :competitions, only: [:index, :destroy] resources :competitions, only: [:index, :destroy] do
member do
post :publish
post :unpublish
post :online_switch
get :enroll_list
end
resource :competition_setting, only: [:show, :update]
end
end end
resources :colleges, only: [] do resources :colleges, only: [] do

@ -28,7 +28,7 @@ class Fileslists extends Component{
pagesize: 15, pagesize: 15,
tagname:undefined, tagname:undefined,
search:undefined, search:undefined,
sort:undefined, sort:"desc",
sorttype:"created_on", sorttype:"created_on",
coursesecondcategoryid:undefined, coursesecondcategoryid:undefined,
filesId:undefined, filesId:undefined,
@ -49,16 +49,19 @@ class Fileslists extends Component{
checkBoxValues:[], checkBoxValues:[],
checkAllValue:false checkAllValue:false
}) })
if(this.props.match.params.main_id){ if(this.props.match.params.main_id){
this.seactall();
this.setState({ this.setState({
child:false, child:false,
sort:"desc"
}) })
this.seactall(undefined,"desc");
}else if(this.props.match.params.Id){ }else if(this.props.match.params.Id){
this.seactall(parseInt(this.props.match.params.Id),1)
this.setState({ this.setState({
child:true, child:true,
sort:"desc"
}) })
this.seactall(parseInt(this.props.match.params.Id),"desc")
} }
this.updadatalist(); this.updadatalist();
on('updateNavSuccess', this.updateNavSuccess) on('updateNavSuccess', this.updateNavSuccess)
@ -66,13 +69,14 @@ class Fileslists extends Component{
} }
updateNavSuccess=()=>{ updateNavSuccess=()=>{
let{sort}=this.state;
this.setState({ this.setState({
isSpin:true isSpin:true
}) })
if(this.props.match.params.main_id){ if(this.props.match.params.main_id){
this.seactall(); this.seactall(undefined,sort);
}else if(this.props.match.params.Id){ }else if(this.props.match.params.Id){
this.seactall(parseInt(this.props.match.params.Id),1) this.seactall(parseInt(this.props.match.params.Id),sort)
} }
} }
componentDidUpdate = (prevProps) => { componentDidUpdate = (prevProps) => {
@ -85,8 +89,9 @@ class Fileslists extends Component{
if(this.props.match.params.main_id!=undefined){ if(this.props.match.params.main_id!=undefined){
this.setState({ this.setState({
child:false, child:false,
sort:"desc"
}) })
this.seactall(); this.seactall(undefined,"desc");
} }
} }
if(prevProps.match.params.Id != this.props.match.params.Id){ if(prevProps.match.params.Id != this.props.match.params.Id){
@ -98,8 +103,9 @@ class Fileslists extends Component{
if(this.props.match.params.Id!=undefined){ if(this.props.match.params.Id!=undefined){
this.setState({ this.setState({
child:true, child:true,
sort:"desc"
}) })
this.seactall(parseInt(this.props.match.params.Id),1) this.seactall(parseInt(this.props.match.params.Id),"desc")
} }
} }
} }
@ -138,29 +144,42 @@ class Fileslists extends Component{
} }
updatafiled=()=>{ updatafiled=()=>{
let{sort}=this.state;
if(this.props.match.params.main_id){ if(this.props.match.params.main_id){
this.seactall(); this.seactall(undefined,sort);
}else if(this.props.match.params.Id){ }else if(this.props.match.params.Id){
this.seactall(parseInt(this.props.match.params.Id),1) this.seactall(parseInt(this.props.match.params.Id),sort)
} }
} }
seactall=(coursesecondcategoryid,type)=>{ seactall=(coursesecondcategoryid,sort)=>{
this.setState({ this.setState({
coursesecondcategoryid:coursesecondcategoryid, coursesecondcategoryid:coursesecondcategoryid,
isSpin:true isSpin:true
}) })
let{pagesize,page,tagname,searchValue,sort,sorttype}=this.state; let{pagesize,page,tagname,searchValue,sorttype}=this.state;
this.getfileslist(pagesize,page,tagname,searchValue,sort,sorttype,coursesecondcategoryid); this.getfileslist(pagesize,page,tagname,searchValue,sort,sorttype,coursesecondcategoryid);
} }
onSortTypeChange=(sorttype)=>{ onSortTypeChange=(sorttype)=>{
let{pagesize,page,tagname,searchValue,sort,coursesecondcategoryid}=this.state; let{pagesize,page,tagname,searchValue,sort,coursesecondcategoryid,}=this.state;
this.setState({ let newsort="desc";
sorttype:sorttype if(sort==="desc"){
}) this.setState({
this.getfileslist(pagesize,page,tagname,searchValue,sort,sorttype,coursesecondcategoryid); sorttype:sorttype,
sort:"asc"
})
newsort="asc"
}else{
this.setState({
sorttype:sorttype,
sort:"desc"
})
newsort="desc"
}
this.getfileslist(pagesize,page,tagname,searchValue,newsort,sorttype,coursesecondcategoryid);
} }
getfileslist=(pagesize,page,tagname,searchValue,sort,sorttype,coursesecondcategoryid)=>{ getfileslist=(pagesize,page,tagname,searchValue,sort,sorttype,coursesecondcategoryid)=>{
@ -176,7 +195,7 @@ class Fileslists extends Component{
page:page, page:page,
tag_name:tagname, tag_name:tagname,
search:searchValue, search:searchValue,
sort:sort, sort:sort==="desc"?0:1,
sort_type:sorttype, sort_type:sorttype,
course_second_category_id:id course_second_category_id:id
} }
@ -353,7 +372,7 @@ class Fileslists extends Component{
Modalstype:false, Modalstype:false,
}) })
let {checkBoxValues} = this.state; let {checkBoxValues,sort} = this.state;
const cid = this.props.match.params.coursesId; const cid = this.props.match.params.coursesId;
let url="/files/bulk_public.json"; let url="/files/bulk_public.json";
@ -363,7 +382,7 @@ class Fileslists extends Component{
}) })
.then((response) => { .then((response) => {
if (response.data.status == 0) { if (response.data.status == 0) {
this.seactall(); this.updatafiled()
//:response.data.message //:response.data.message
this.props.showNotification("更新成功"); this.props.showNotification("更新成功");
this.setState({ this.setState({
@ -680,7 +699,8 @@ class Fileslists extends Component{
shixunmodal, shixunmodal,
course_is_public, course_is_public,
filesId, filesId,
child child,
sort
} = this.state; } = this.state;
let category_id= this.props.match.params.category_id; let category_id= this.props.match.params.category_id;
@ -753,7 +773,7 @@ class Fileslists extends Component{
patheditarry={this.state.patheditarry} patheditarry={this.state.patheditarry}
coursesecondcategoryid={this.state.coursesecondcategoryid} coursesecondcategoryid={this.state.coursesecondcategoryid}
hidecouseShixunModal={this.hidecouseShixunModal} hidecouseShixunModal={this.hidecouseShixunModal}
setupdate={(id)=>this.seactall(id)} setupdate={(id)=>this.seactall(id,sort)}
attachmentId={this.state.coursesecondcategoryid} attachmentId={this.state.coursesecondcategoryid}
/>:""} />:""}
@ -768,7 +788,7 @@ class Fileslists extends Component{
Savesname={"确认"} Savesname={"确认"}
Cancel={this.Cancelvisible} Cancel={this.Cancelvisible}
categoryid={category_id} categoryid={category_id}
setupdate={(id)=>this.seactall(id)} setupdate={(id)=>this.seactall(id,sort)}
has_course_groups={this.state.has_course_groups} has_course_groups={this.state.has_course_groups}
attachmentId={this.state.coursesecondcategoryid} attachmentId={this.state.coursesecondcategoryid}
/>:""} />:""}
@ -779,7 +799,7 @@ class Fileslists extends Component{
Settingtype={Settingtype} Settingtype={Settingtype}
discussMessageid={discussMessageid} discussMessageid={discussMessageid}
course_id={this.props.match.params.coursesId} course_id={this.props.match.params.coursesId}
setupdate={(id)=>this.seactall(id)} setupdate={(id)=>this.seactall(id,sort)}
Cancel={this.Cancelvisible} Cancel={this.Cancelvisible}
has_course_groups={this.state.has_course_groups} has_course_groups={this.state.has_course_groups}
attachmentId={this.state.coursesecondcategoryid} attachmentId={this.state.coursesecondcategoryid}
@ -896,16 +916,24 @@ class Fileslists extends Component{
</li>:""} </li>:""}
<style>
{this.props.isAdmin()||this.props.isStudent()? <li className="drop_down"> {
{sorttype === 'created_on' ? '更新时间排序':sorttype === 'downloads' ?'下载次数排序':'引用次数排序'} `
<i className="iconfont icon-xiajiantou font-12 ml2"></i> .fiilssort{
<ul className="drop_down_normal" style={{width:'130px'}}> position: absolute;
{/*className={sorttype === 'created_on'?"none":""} className={sorttype === 'quotes'?"none":""} className={sorttype === 'downloads'?"none":""} */} top: -10px;
<li style={{width:'130px'}} onClick={() => this.onSortTypeChange('created_on')}>更新时间排序</li> }
<li style={{width:'130px'}} onClick={() => this.onSortTypeChange('downloads')}>下载次数排序</li> `
{/*<li style={{width:'130px'}} onClick={() => this.onSortTypeChange('quotes')}>引用次数排序</li>*/} }
</ul> </style>
{this.props.isAdmin()||this.props.isStudent()? <li className="drop_down" onClick={() => this.onSortTypeChange('created_on')}>
更新时间
<sapn className="relativef ml5"style={{"top":"2px"}} >
<i className={sort==="asc"?
"iconfont icon-sanjiaoxing-up font-12 color-blue fiilssort" :"iconfont icon-sanjiaoxing-up font-12 fiilssort"}></i>
<i className={sort==="desc"?
"iconfont icon-sanjiaoxing-down font-12 yslbottomsj color-blue":"iconfont icon-sanjiaoxing-down font-12 yslbottomsj"}></i>
</sapn>
</li>:""} </li>:""}
</div> </div>
</div> </div>

@ -1128,7 +1128,9 @@ class CommonWorkSetting extends Component{
{<div className={"publicTimeTip color-red ml30"}>{publicTimeTip}</div>} {<div className={"publicTimeTip color-red ml30"}>{publicTimeTip}</div>}
</React.Fragment> : </React.Fragment> :
adaptered_group_settings && !!adaptered_group_settings.length && <PollDetailTabForthRules adaptered_group_settings && !!adaptered_group_settings.length && <PollDetailTabForthRules
{...this.props}
{...this.state}
ref="pollDetailTabForthRules" ref="pollDetailTabForthRules"
rules={rules} rules={rules}
course_group={adaptered_group_settings} course_group={adaptered_group_settings}

@ -61,7 +61,8 @@ class Titlesearchsection extends Component{
<p className="clearfix padding30 bor-bottom-greyE"> <p className="clearfix padding30 bor-bottom-greyE">
<p style={{height: '20px'}}> <p style={{height: '20px'}}>
<span className="font-18 fl color-dark-21 filesnameslist" title={title}>{title}</span> {/* title={title} */}
<span className="font-18 fl color-dark-21 filesnameslist" >{title}</span>
<li className="fr font-16"> <li className="fr font-16">
{ firstRowRight } { firstRowRight }
</li> </li>

@ -248,8 +248,8 @@ class CoursesBanner extends Component {
} }
} }
if (i ===5) { if (i ===5) {
s = "复制将在后台执行,作业、资源、试卷都将复制到新课堂平台"; s = "复制”功能将会为您创建一个新的课堂旧课堂的作业、资源、试卷";
ss = "将为你创建一个新的同名课堂,请问是否继续"; ss = "都将被复制到新的课堂里面请问是否继续?";
this.showActionPoll(i,s,ss) this.showActionPoll(i,s,ss)
} }

@ -350,6 +350,7 @@ class Exercisesetting extends Component{
this.commitSetting((result)=>{ this.commitSetting((result)=>{
console.log(result)
if(result.status==200){ if(result.status==200){
this.props.showNotification(`${result.data.message}`); this.props.showNotification(`${result.data.message}`);
this.getSettingInfo(); this.getSettingInfo();
@ -369,6 +370,7 @@ class Exercisesetting extends Component{
} }
this.commitSetting((result)=>{ this.commitSetting((result)=>{
console.log(result)
if(result.status==200){ if(result.status==200){
this.props.showNotification(`${result.data.message}`); this.props.showNotification(`${result.data.message}`);
this.cancelEdit(); this.cancelEdit();
@ -702,7 +704,9 @@ class Exercisesetting extends Component{
</div> </div>
: :
<PollDetailTabForthRules <PollDetailTabForthRules
ref="pollDetailTabForthRules" {...this.props}
{...this.state}
ref="pollDetailTabForthRules"
rules={rules} rules={rules}
type={"Exercise"} type={"Exercise"}
course_group={course_group} course_group={course_group}

@ -257,6 +257,15 @@ class Testpapersettinghomepage extends Component{
if(tab[0]==="0"){ if(tab[0]==="0"){
this.child.Teacherliststudentlist(); this.child.Teacherliststudentlist();
} }
if(tab[0]==="1"){
this.child.Teacherliststudentlist();
}
if(tab[0]==="2"){
this.child.Teacherliststudentlist();
}
if(tab[0]==="3"){
this.child.getSettingInfo();
}
}catch (e) { }catch (e) {
} }

@ -710,7 +710,7 @@ class studentsList extends Component{
title={isParent ? (pageType == TYPE_STUDENTS ? "全部学生" : "学生列表"): title={isParent ? (pageType == TYPE_STUDENTS ? "全部学生" : "学生列表"):
<React.Fragment> <React.Fragment>
<span> <span>
<Tooltip title="返回"> <Tooltip title="返回至分班列表">
<i className="icon-zuojiantou iconfont font-14" onClick={() => { this.props.history.push(`/courses/${courseId}/course_groups`)}} <i className="icon-zuojiantou iconfont font-14" onClick={() => { this.props.history.push(`/courses/${courseId}/course_groups`)}}
style={{color: '#212121', verticalAlign: 'initial', marginRight: '14px' }} style={{color: '#212121', verticalAlign: 'initial', marginRight: '14px' }}
></i> ></i>

@ -49,6 +49,24 @@ class PollDetailIndex extends Component{
}).catch((error)=>{ }).catch((error)=>{
console.log(error); console.log(error);
}) })
let{tab}=this.state;
try {
if(tab[0]==="0"){
this.child.Teacherliststudentlist();
}
if(tab[0]==="1"){
this.child.Teacherliststudentlist();
}
if(tab[0]==="2"){
this.child.Teacherliststudentlist();
}
if(tab[0]==="3"){
this.child.getSettingInfo();
}
}catch (e) {
}
} }
componentDidMount(){ componentDidMount(){
@ -110,6 +128,7 @@ class PollDetailIndex extends Component{
DownloadMessageval:undefined DownloadMessageval:undefined
}) })
} }
bindRef = ref => { this.child = ref };
render(){ render(){
let {tab,pollDetail,user_permission,polls_status}=this.state; let {tab,pollDetail,user_permission,polls_status}=this.state;
const { current_user } = this.props; const { current_user } = this.props;
@ -235,7 +254,7 @@ class PollDetailIndex extends Component{
} }
{ {
//设置 //设置
parseInt(tab[0])==3 && <PollTabForth {...this.props} {...this.state} user_permission={user_permission} getPollInfo={this.getPollInfo}></PollTabForth> parseInt(tab[0])==3 && <PollTabForth {...this.props} {...this.state} triggerRef={this.bindRef} user_permission={user_permission} getPollInfo={this.getPollInfo}></PollTabForth>
} }
</div> </div>

@ -90,6 +90,11 @@ class PollDetailTabForth extends Component{
if(this.props.isAdmin() === false){ if(this.props.isAdmin() === false){
this.cancelEdit() this.cancelEdit()
} }
try {
this.props.triggerRef(this);
}catch (e) {
}
} }
componentDidUpdate = (prevProps) => { componentDidUpdate = (prevProps) => {
if(prevProps.pollDetail!= this.props.pollDetail){ if(prevProps.pollDetail!= this.props.pollDetail){
@ -610,6 +615,8 @@ class PollDetailTabForth extends Component{
</div> </div>
: :
<PollDetailTabForthRules <PollDetailTabForthRules
{...this.props}
{...this.state}
ref="pollDetailTabForthRules" ref="pollDetailTabForthRules"
rules={rules} rules={rules}
course_group={course_group} course_group={course_group}

@ -342,7 +342,7 @@ class PollDetailTabForthRules extends Component{
} }
render(){ render(){
let {rules,course_group,flagPageEdit}=this.state let {rules,course_group,flagPageEdit}=this.state
console.log(rules) let isAdmin=this.props.isAdmin();
return( return(
<div className="bor-top-greyE pt20"> <div className="bor-top-greyE pt20">
<p className="clearfix mb10"> <p className="clearfix mb10">
@ -350,6 +350,12 @@ class PollDetailTabForthRules extends Component{
<span className="fl pr20 color-grey-c with25">(学生收到{this.props.moduleName || (this.props.type==="Exercise"?"试卷":"问卷")}的时间)</span> <span className="fl pr20 color-grey-c with25">(学生收到{this.props.moduleName || (this.props.type==="Exercise"?"试卷":"问卷")}的时间)</span>
<span className="fl color-grey-c">({this.props.moduleName == '作业' ? '学生“按时”提交作品的时间截点' : '学生可以答题的时间截点'})</span> <span className="fl color-grey-c">({this.props.moduleName == '作业' ? '学生“按时”提交作品的时间截点' : '学生可以答题的时间截点'})</span>
</p> </p>
{/* item宽度超长 */}
<style>{`
.setInfo .ant-select-selection--multiple .ant-select-selection__choice__content {
max-width: 300px;
}
`}</style>
{ {
rules && rules.length > 0 && rules.map((rule,r)=>{ rules && rules.length > 0 && rules.map((rule,r)=>{
@ -383,28 +389,34 @@ class PollDetailTabForthRules extends Component{
`.ant-select{ `.ant-select{
min-width:200px, min-width:200px,
min-heigth:200px min-heigth:200px
}` }
`
} }
</style> </style>
<Select <Tooltip placement="bottom"
placeholder="请选择分班名称" title={
className={rule.class_flag && rule.class_flag!=""?"noticeTip setInfo":"setInfo" } rule.p_timeflag===undefined?moment(rule.publish_time,dataformat) <= moment()?isAdmin===true?"发布时间已过,不能再修改":"":"": rule.e_timeflag ===undefined?rule.publish_time===null?"":!flagPageEdit:rule.p_timeflag == true ?isAdmin===true?"发布时间已过,不能再修改":"" : ""
mode="multiple" }>
filterOption={(input, option) => <Select
option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0 placeholder="请选择分班名称"
} className={rule.class_flag && rule.class_flag!=""?"noticeTip setInfo":"setInfo" }
value={rule.course_group_id} mode="multiple"
onChange={(value,option)=>this.changeClasses(value,option,r)} filterOption={(input, option) =>
disabled={ rule.e_timeflag ===undefined?rule.publish_time===null?false:!flagPageEdit:rule.p_timeflag == true ? true : !flagPageEdit} option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
> }
{ value={rule.course_group_id}
courseGroup && courseGroup.length > 0 && courseGroup.map((team,t)=>{ onChange={(value,option)=>this.changeClasses(value,option,r)}
return( disabled={rule.p_timeflag===undefined?moment(rule.publish_time,dataformat) <= moment()?true:!flagPageEdit: rule.e_timeflag ===undefined?rule.publish_time===null?false:!flagPageEdit:rule.p_timeflag == true ? true : !flagPageEdit}
<Option value={team.course_group_id} key={t} style={{display:`${team.course_choosed==0 ? "" : "none"}`}}>{team.course_group_name}</Option> >
) {
}) courseGroup && courseGroup.length > 0 && courseGroup.map((team,t)=>{
} return(
</Select> <Option value={team.course_group_id} key={t} style={{display:`${team.course_choosed==0 ? "" : "none"}`}}>{team.course_group_name}</Option>
)
})
}
</Select>
</Tooltip>
<p className="color-orange-tip lineh-25 clearfix" style={{height:"25px"}}> <p className="color-orange-tip lineh-25 clearfix" style={{height:"25px"}}>
{ {
rule.class_flag && rule.class_flag!=""?<span className="fl color-red">{rule.class_flag}</span>:"" rule.class_flag && rule.class_flag!=""?<span className="fl color-red">{rule.class_flag}</span>:""
@ -413,7 +425,9 @@ class PollDetailTabForthRules extends Component{
</div> </div>
</div> </div>
<div className="fl pr20 with25 yskspickersy"> <div className="fl pr20 with25 yskspickersy">
<Tooltip placement="bottom" title={rule.e_timeflag ? this.props.isAdmin()?"发布时间已过,不能再修改":"":""}> <Tooltip placement="bottom" title={
rule.p_timeflag===undefined?moment(rule.publish_time,dataformat) <= moment()?isAdmin===true?"发布时间已过,不能再修改":"":"": rule.e_timeflag ===undefined?rule.publish_time===null?"":!flagPageEdit:rule.p_timeflag == true ? isAdmin===true?"发布时间已过,不能再修改":"" : ""
}>
<span> <span>
<DatePicker <DatePicker
showToday={false} showToday={false}
@ -427,7 +441,7 @@ class PollDetailTabForthRules extends Component{
format="YYYY-MM-DD HH:mm" format="YYYY-MM-DD HH:mm"
disabledTime={disabledDateTime} disabledTime={disabledDateTime}
disabledDate={disabledDate} disabledDate={disabledDate}
disabled={ rule.e_timeflag ===undefined?rule.publish_time===null?false:!flagPageEdit:rule.p_timeflag == true ? true : !flagPageEdit} disabled={ rule.p_timeflag===undefined?moment(rule.publish_time,dataformat) <= moment()?true:!flagPageEdit: rule.e_timeflag ===undefined?rule.publish_time===null?false:!flagPageEdit:rule.p_timeflag == true ? true : !flagPageEdit}
style={{"height":"42px",width:'100%'}} style={{"height":"42px",width:'100%'}}
></DatePicker> ></DatePicker>
</span> </span>

@ -2261,6 +2261,8 @@ class Trainingjobsetting extends Component {
className="ml40" className="ml40"
> >
<PollDetailTabForthRules <PollDetailTabForthRules
{...this.props}
{...this.state}
rules={rules} rules={rules}
moduleName={"作业"} moduleName={"作业"}
course_group={rulest} course_group={rulest}

@ -913,7 +913,7 @@ submittojoinclass=(value)=>{
strbool=false strbool=false
} }
} }
console.log(item.hidden); // console.log(item.hidden);
return( return(
<li key={key} onClick={()=>this.headtypesonClick(item.link,true)} className={`${headtypes===undefined?'pr':headtypes===item.link?'pr active':'pr'}`} style={item.hidden==false?{display: 'block'}:{display: 'none'}}> <li key={key} onClick={()=>this.headtypesonClick(item.link,true)} className={`${headtypes===undefined?'pr':headtypes===item.link?'pr active':'pr'}`} style={item.hidden==false?{display: 'block'}:{display: 'none'}}>
{ {

@ -131,7 +131,7 @@ function create_editorMD(id, width, high, placeholder, imageUrl, callback, initV
// Or return editormd.toolbarModes[name]; // full, simple, mini // Or return editormd.toolbarModes[name]; // full, simple, mini
// Using "||" set icons align right. // Using "||" set icons align right.
const icons = ["bold", "italic", "|", "list-ul", "list-ol", "|", "code", "code-block", "|", "testIcon", "testIcon1", '|', "image", "table", '|', "watch", "clear"]; const icons = ["bold", "italic", "|", "list-ul", "list-ol", "|", "code", "code-block", "link", "|", "testIcon", "testIcon1", '|', "image", "table", '|', "watch", "clear"];
if (__that.props.showNullButton) { if (__that.props.showNullButton) {
icons.push('nullBtton') icons.push('nullBtton')
} }

Loading…
Cancel
Save