diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index 47349e219..324e5bde3 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -32,8 +32,11 @@ class AccountsController < ApplicationController 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) - return normal_status(-2, "验证码不正确") if verifi_code.try(:code) != code.strip - return normal_status(-2, "验证码已失效") if !verifi_code&.effective? + # todo 上线前请删除万能验证码"513231" + if code != "513231" + return normal_status(-2, "验证码不正确") if verifi_code.try(:code) != code.strip + return normal_status(-2, "验证码已失效") if !verifi_code&.effective? + end code = generate_identifier User, 8 login = pre + code diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 9fd7dc0b5..cc1fc167e 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,571 +1,563 @@ -require 'oauth2' - -class ApplicationController < ActionController::Base - include CodeExample - include RenderExpand - include RenderHelper - include ControllerRescueHandler - include GitHelper - include LoggerHelper - - protect_from_forgery prepend: true, unless: -> { request.format.json? } - - before_action :user_setup - #before_action :check_account - - DCODES = %W(2 3 4 5 6 7 8 9 a b c f e f g h i j k l m n o p q r s t u v w x y z) - - helper_method :current_user - - # 全局配置参数 - # 返回name对应的value - def edu_setting(name) - EduSetting.get(name) - end - - # 实训的访问权限 - def shixun_access_allowed - if !current_user.shixun_permission(@shixun) - tip_exception(403, "..") - end - end - - def admin_or_business? - User.current.admin? || User.current.business? - end - - # 访问课堂时没权限直接弹加入课堂的弹框 :409 - def user_course_identity - @user_course_identity = current_user.course_identity(@course) - if @user_course_identity > Course::STUDENT && @course.is_public == 0 - tip_exception(409, "您没有权限进入") - end - uid_logger("###############user_course_identity:#{@user_course_identity}") - end - - - # 判断用户的邮箱或者手机是否可用 - # params[:type] 1: 注册;2:忘记密码 - def check_mail_and_phone_valid login, type - unless login =~ /^[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/ || login =~ /^1\d{10}$/ || - login =~ /^[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])$/ - tip_exception(-2, "请输入正确的手机号或邮箱") - end - # 考虑到安全参数问题,多一次查询,去掉Union - user = User.where(phone: login).first || User.where(mail: login).first - if type.to_i == 1 && !user.nil? - tip_exception(-2, "该手机号码或邮箱已被注册") - elsif type.to_i == 2 && user.nil? - tip_exception(-2, "该手机号码或邮箱未注册") - end - sucess_status - end - - # 发送及记录激活码 - # 发送验证码:type 1:注册手机验证码 2:找回密码手机验证码 3:找回密码邮箱验证码 4:绑定手机 5:绑定邮箱 - # 6:手机验证码登录 7:邮箱验证码登录 8:邮箱注册验证码 - def check_verification_code(code, send_type, value) - case send_type - when 1, 2, 4 - # 手机类型的发送 - sigle_para = {phone: value} - status = Educoder::Sms.send(mobile: value, code: code) - tip_exception(-2, code_msg(status)) if status != 0 - when 8, 3, 5 - # 邮箱类型的发送 - sigle_para = {email: value} - begin - UserMailer.register_email(value, code).deliver_now - # Mailer.run.email_register(code, value) - rescue Exception => e - logger_error(e) - tip_exception(-2,"邮件发送失败,请稍后重试") - end - end - ver_params = {code_type: send_type, code: code}.merge(sigle_para) - VerificationCode.create!(ver_params) - end - - def code_msg status - case status - when 0 - "验证码已经发送到您的手机,请注意查收" - when 8 - "同一手机号30秒内重复提交相同的内容" - when 9 - "同一手机号5分钟内重复提交相同的内容超过3次" - when 22 - "1小时内同一手机号发送次数超过限制" - when 33 - "验证码发送次数超过频率" - when 43 - "一天内同一手机号发送次数超过限制" - end - end - - def find_course - return normal_status(2, '缺少course_id参数!') if params[:course_id].blank? - @course = Course.find(params[:course_id]) - rescue Exception => e - tip_exception(e.message) - end - - def course_manager - return normal_status(403, '只有课堂管理员才有权限') if @user_course_identity > Course::CREATOR - end - - def find_board - return normal_status(2, "缺少board_id参数") if params[:board_id].blank? - @board = Board.find(params[:board_id]) - rescue Exception => e - uid_logger_error(e.message) - tip_exception(e.message) - end - - def validate_type(object_type) - normal_status(2, "参数") if params.has_key?(:sort_type) && !SORT_TYPE.include?(params[:sort_type].strip) - end - - def set_pagination - @page = params[:page] || 1 - @page_size = params[:page_size] || 15 - end - - # 课堂教师权限 - def teacher_allowed - logger.info("#####identity: #{current_user.course_identity(@course)}") - unless current_user.course_identity(@course) < Course::STUDENT - normal_status(403, "") - end - end - - # 课堂教师、课堂管理员、超级管理员的权限(不包含助教) - def teacher_or_admin_allowed - unless current_user.course_identity(@course) < Course::ASSISTANT_PROFESSOR - normal_status(403, "") - end - end - - def require_admin - normal_status(403, "") unless User.current.admin? - end - - def require_business - normal_status(403, "") unless admin_or_business? - end - - # 前端会捕捉401,弹登录弹框 - # 未授权的捕捉407,弹试用申请弹框 - def require_login - #6.13 -hs - tip_exception(401, "..") unless User.current.logged? - end - - # 异常提醒 - def tip_exception(status = -1, message) - raise Educoder::TipException.new(status, message) - end - - def missing_template - tip_exception(404, "...") - end - - # 弹框提醒 - def tip_show_exception(status = -2, message) - raise Educoder::TipException.new(status, message) - end - - def normal_status(status = 0, message) - case status - when 403 - message = "您没有权限进行该操作" - when 404 - message = "您访问的页面不存在或已被删除" - end - render :json => { status: status, message: message } - end - - # 系统全局认证 - def check_auth - day_cer = UserDayCertification.find_by(user_id: current_user.id) - # 如果注册超过24小时则需要完善资料及授权 - if (Time.now.to_i - day_cer.try(:created_at).to_i) > 86400 - if !current_user.profile_completed? - info_url = '/account/profile' - tip_exception(402, info_url) - elsif current_user.certification != 1 - if current_user.apply_actions.exists?(container_type: 'TrialAuthorization', status: 0) - tip_exception(408, "您的试用申请正在审核中,请耐心等待") - end - tip_exception(407, "系统未授权") - end - end - - - # if current_user.certification != 1 && current_user.apply_actions.exists?(container_type: 'TrialAuthorization', status: 0) - # tip_exception(408, "您的试用申请正在审核中,请耐心等待") - # elsif (Time.now.to_i - day_cer.try(:created_at).to_i) < 86400 - # if !current_user.profile_completed? - # info_url = '/account/profile' - # tip_exception(402, info_url) - # elsif current_user.certification != 1 - # day_cer = UserDayCertification.find_by(user_id: current_user.id) - # tip_exception(407, "系统未授权") unless (Time.now.to_i - day_cer.try(:created_at).to_i) < 86400 - # end - # end - end - - def start_user_session(user) - session[:user_id] = user.id - session[:ctime] = Time.now.utc.to_i - session[:atime] = Time.now.utc.to_i - end - - def user_setup - # reacct静态资源加载不需要走这一步 - return if params[:controller] == "main" - # Find the current user - User.current = find_current_user - uid_logger("user_setup: " + (User.current.logged? ? "#{User.current.try(:login)} (id=#{User.current.try(:id)})" : "anonymous")) - - if !User.current.logged? && Rails.env.development? - User.current = User.find 12 - end - - # User.current = User.find 81403 - - if params[:debug] == 'teacher' #todo 为了测试,记得讲debug删除 - User.current = User.find 81403 - elsif params[:debug] == 'student' - User.current = User.find 8686 - elsif params[:debug] == 'admin' - User.current = User.find 1 - elsif params[:debug] - User.current = User.find_by_login params[:debug] - end - end - - # Sets the logged in user - def logged_user=(user) - reset_session - if user && user.is_a?(User) - User.current = user - start_user_session(user) - else - User.current = User.anonymous - end - end - - # Returns the current user or nil if no user is logged in - # and starts a session if needed - def find_current_user - uid_logger("user setup start: session[:user_id] is #{session[:user_id]}") - if session[:user_id] - # existing session - (User.active.find(session[:user_id]) rescue nil) - elsif autologin_user = try_to_autologin - autologin_user - elsif params[:format] == 'atom' && params[:key] && request.get? && accept_rss_auth? - # RSS key authentication does not start a session - User.find_by_rss_key(params[:key]) - end - end - - def autologin_cookie_name - edu_setting('autologin_cookie_name').presence || 'autologin' - end - - def try_to_autologin - if cookies[autologin_cookie_name] - # auto-login feature starts a new session - user = User.try_to_autologin(cookies[autologin_cookie_name]) - if user - start_user_session(user) - end - user - end - end - - def api_request? - %w(xml json).include? params[:format] - end - - def current_user - User.current - end - - ## 默认输出json - def render_json - respond_to do |format| - format.json - end - end - - ## 输出错误信息 - def error_status(message = nil) - @status = -1 - @message = message - end - - # 实训等对应的仓库地址 - def repo_ip_url(repo_path) - "#{edu_setting('git_address_ip')}/#{repo_path}" - end - - def repo_url(repo_path) - "#{edu_setting('git_address_domain')}/#{repo_path}" - end - - # 通关后,把最后一次成功的代码存到数据库 - # type 0 创始内容, 1 最新内容 - def game_passed_code(path, myshixun, game_id) - return if myshixun.shixun.hide_code - file_content = git_fle_content myshixun.repo_path, path - unless file_content.present? - raise("获取文件代码异常") - end - game_code = GameCode.where(:game_id => game_id, :path => path).first - if game_code.nil? - GameCode.create!(:game_id => game_id, :new_code => file_content, :path => path) - else - game_code.update_attributes!(:new_code => file_content) - end - end - - # Post请求 - def uri_post(uri, params) - begin - uid_logger("--uri_exec: params is #{params}, url is #{uri}") - uri = URI.parse(URI.encode(uri.strip)) - res = Net::HTTP.post_form(uri, params).body - logger.info("--uri_exec: .....res is #{res}") - JSON.parse(res) - rescue Exception => e - uid_logger("--uri_exec: exception #{e.message}") - raise Educoder::TipException.new("实训平台繁忙(繁忙等级:84)") - end - end - - # 处理返回非0就报错的请求 - def interface_post(uri, params, status, message) - begin - uid_logger("--uri_exec: params is #{params}, url is #{uri}") - uri = URI.parse(URI.encode(uri.strip)) - res = Net::HTTP.post_form(uri, params).body - logger.info("--uri_exec: .....res is #{res}") - res = JSON.parse(res) - if (res && res['code'] != 0) - tip_exception(status, message) - else - res - end - rescue Exception => e - uid_logger("--uri_exec: exception #{e.message}") - raise Educoder::TipException.new("实训平台繁忙(繁忙等级:84)") - end - end - - # 适用与已经用url_safe编码后,回调字符串形式 - def tran_base64_decode64(str) - s_size = str.size % 4 - if s_size != 0 - str += "=" * (4 - s_size) - end - if str.blank? - str - else - Base64.decode64(str.tr("-_", "+/")).force_encoding("utf-8") - end - end - - def sucess_status(message = 'success') - render :json => { status: 1, message: message } - end - - # 随机生成字符 - def generate_identifier(container, num) - code = DCODES.sample(num).join - if container == User - while container.exists?(login: code) do - code = DCODES.sample(num).join - end - else - while container.exists?(identifier: code) do - code = DCODES.sample(num).join - end - end - code - end - - - # 实训主类别列表,自带描述 - def shixun_main_type - list = [] - mirrors = MirrorRepository.select([:id, :type_name]).published_main_mirror - mirrors.try(:each) do |mirror| - list << {id: mirror.id, type_name: mirror.type_name, description: mirror.try(:description)} - end - list - end - - # 小类别列表 - def shixun_small_type - list = [] - mirrors = MirrorRepository.select([:id, :type_name]).published_small_mirror - mirrors.try(:each) do |mirror| - list << {id: mirror.id, type_name: mirror.type_name} - end - list - end - - def container_limit(mirror_repositories) - container = [] - mirror_repositories.each do |mr| - if mr.name.present? - container << {:image => mr.name, :cpuLimit => mr.cpu_limit, :memoryLimit => "#{mr.memory_limit}M", :type => mr.try(:main_type) == "1" ? "main" : "sub"} - end - end - container.to_json - end - - # 实训中间层pod配置 - def shixun_container_limit shixun - container = [] - shixun.shixun_service_configs.each do |config| - mirror = config.mirror_repository - if mirror.name.present? - container << {:image => mirror.name, - :cpuLimit => config.cpu_limit, - :cpuRequest => config.lower_cpu_limit, - :memoryLimit => "#{config.memory_limit}M", - :memoryRequest => "#{config.request_limit}M", - :resourceLimit => "#{config.resource_limit}K", - :type => mirror.try(:main_type) == "1" ? "main" : "sub"} - end - end - container.to_json - end - - # 毕设任务列表的赛选 - def course_work(task, **option) - logger.info("#############{option}") - course = task.course - work_list = task.graduation_works.includes(user: [:user_extension]) - # 教师评阅搜索 0: 未评, 1 已评 - if option[:teacher_comment] - graduation_work_ids = GraduationWorkScore.where(graduation_work_id: work_list.map(&:id)).pluck(:graduation_work_id) - if option[:teacher_comment].zero? - work_list = work_list.where.not(id: graduation_work_ids) - elsif option[:teacher_comment] == 1 - work_list = work_list.where(id: graduation_work_ids).where.not(work_status: 0) - end - end - - # 作品状态 0: 未提交, 1 按时提交, 2 延迟提交 - if option[:task_status] - work_list = work_list.where(work_status: option[:task_status]) - end - - # 分班情况 - if option[:course_group] - group_user_ids = course.course_members.where(course_group_id: option[:course_group]).pluck(:user_id) - # 有分组只可能是老师身份查看列表 - work_list = work_list.where(user_id: group_user_ids) - end - - # 只看我的交叉评阅 - if option[:cross_comment] - graduation_work_id = task.graduation_work_comment_assignations.where(:user_id => current_user.id) - .pluck(:graduation_work_id).uniq if task.graduation_work_comment_assignations - work_list = work_list.where(id: graduation_work_id) - end - - # 输入姓名和学号搜索 - # TODO user_extension 如果修改 请调整 - if option[:search] - work_list = work_list.joins(user: :user_extension).where("concat(lastname, firstname) like ? - or student_id like ?", "%#{option[:search]}%", "%#{option[:search]}%") - end - - # 排序 - rorder = option[:order] || "updated_at" - b_order = option[:b_order] || "desc" - if rorder == "created_at" || rorder == "work_score" - work_list = work_list.order("graduation_works.#{rorder} #{b_order}") - elsif rorder == "student_id" - work_list = work_list.joins(user: :user_extension).order("user_extensions.#{rorder} #{b_order}") - end - work_list - end - - def strip_html(text, len=0, endss="...") - ss = "" - if !text.nil? && text.length>0 - ss=text.gsub(/<\/?.*?>/, '').strip - ss = ss.gsub(/ */, '') - ss = ss.gsub(/\r\n/,'') #新增 - ss = ss.gsub(/\n/,'') #新增 - if len > 0 && ss.length > len - ss = ss[0, len] + endss - elsif len > 0 && ss.length <= len - ss = ss - #ss = truncate(ss, :length => len) - end - end - ss - end - - # Returns a string that can be used as filename value in Content-Disposition header - def filename_for_content_disposition(name) - request.env['HTTP_USER_AGENT'] =~ %r{MSIE|Trident|Edge} ? ERB::Util.url_encode(name) : name - end - - def format_time(time) - time.blank? ? '' : time.strftime("%Y-%m-%d %H:%M") - end - - # 获取Oauth Client - def get_client(site) - client_id = Rails.configuration.educoder['client_id'] - client_secret = Rails.configuration.educoder['client_secret'] - - OAuth2::Client.new(client_id, client_secret, site: site) - end - - def paginate(relation) - limit = params[:limit].to_i.zero? ? 20 : params[:limit].to_i - page = params[:page].to_i.zero? ? 1 : params[:page].to_i - offset = (page - 1) * limit - - if relation.is_a?(Array) - relation[offset, limit] - else - relation.limit(limit).offset(offset) - end - end - - def strf_time(time) - time.blank? ? '' : time.strftime("%Y-%m-%d %H:%M:%S") - end - - def logger_error(error) - Rails.logger.error(error.message) - error.backtrace.each { |msg| Rails.logger.error(msg) } - end - - private - def object_not_found - uid_logger("Missing template or cant't find record, responding with 404") - render json: {message: "您访问的页面不存在或已被删除", status: 404} - false - end - - def tip_show(exception) - uid_logger("Tip show status is #{exception.status}, message is #{exception.message}") - render json: exception.tip_json - end - - def render_parameter_missing - render json: { status: -1, message: '参数缺失' } - end -end +require 'oauth2' + +class ApplicationController < ActionController::Base + include CodeExample + include RenderExpand + include RenderHelper + include ControllerRescueHandler + include GitHelper + include LoggerHelper + + protect_from_forgery prepend: true, unless: -> { request.format.json? } + + before_action :user_setup + #before_action :check_account + + DCODES = %W(2 3 4 5 6 7 8 9 a b c f e f g h i j k l m n o p q r s t u v w x y z) + + helper_method :current_user + + # 全局配置参数 + # 返回name对应的value + def edu_setting(name) + EduSetting.get(name) + end + + # 实训的访问权限 + def shixun_access_allowed + if !current_user.shixun_permission(@shixun) + tip_exception(403, "..") + end + end + + def admin_or_business? + User.current.admin? || User.current.business? + end + + # 访问课堂时没权限直接弹加入课堂的弹框 :409 + def user_course_identity + @user_course_identity = current_user.course_identity(@course) + if @user_course_identity > Course::STUDENT && @course.is_public == 0 + tip_exception(409, "您没有权限进入") + end + uid_logger("###############user_course_identity:#{@user_course_identity}") + end + + + # 判断用户的邮箱或者手机是否可用 + # params[:type] 1: 注册;2:忘记密码 + def check_mail_and_phone_valid login, type + unless login =~ /^[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/ || login =~ /^1\d{10}$/ || + login =~ /^[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])$/ + tip_exception(-2, "请输入正确的手机号或邮箱") + end + # 考虑到安全参数问题,多一次查询,去掉Union + user = User.where(phone: login).first || User.where(mail: login).first + if type.to_i == 1 && !user.nil? + tip_exception(-2, "该手机号码或邮箱已被注册") + elsif type.to_i == 2 && user.nil? + tip_exception(-2, "该手机号码或邮箱未注册") + end + sucess_status + end + + # 发送及记录激活码 + # 发送验证码:type 1:注册手机验证码 2:找回密码手机验证码 3:找回密码邮箱验证码 4:绑定手机 5:绑定邮箱 + # 6:手机验证码登录 7:邮箱验证码登录 8:邮箱注册验证码 + def check_verification_code(code, send_type, value) + case send_type + when 1, 2, 4 + # 手机类型的发送 + sigle_para = {phone: value} + status = Educoder::Sms.send(mobile: value, code: code) + tip_exception(-2, code_msg(status)) if status != 0 + when 8, 3, 5 + # 邮箱类型的发送 + sigle_para = {email: value} + begin + UserMailer.register_email(value, code).deliver_now + # Mailer.run.email_register(code, value) + rescue Exception => e + logger_error(e) + tip_exception(-2,"邮件发送失败,请稍后重试") + end + end + ver_params = {code_type: send_type, code: code}.merge(sigle_para) + VerificationCode.create!(ver_params) + end + + def code_msg status + case status + when 0 + "验证码已经发送到您的手机,请注意查收" + when 8 + "同一手机号30秒内重复提交相同的内容" + when 9 + "同一手机号5分钟内重复提交相同的内容超过3次" + when 22 + "1小时内同一手机号发送次数超过限制" + when 33 + "验证码发送次数超过频率" + when 43 + "一天内同一手机号发送次数超过限制" + end + end + + def find_course + return normal_status(2, '缺少course_id参数!') if params[:course_id].blank? + @course = Course.find(params[:course_id]) + rescue Exception => e + tip_exception(e.message) + end + + def course_manager + return normal_status(403, '只有课堂管理员才有权限') if @user_course_identity > Course::CREATOR + end + + def find_board + return normal_status(2, "缺少board_id参数") if params[:board_id].blank? + @board = Board.find(params[:board_id]) + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + end + + def validate_type(object_type) + normal_status(2, "参数") if params.has_key?(:sort_type) && !SORT_TYPE.include?(params[:sort_type].strip) + end + + def set_pagination + @page = params[:page] || 1 + @page_size = params[:page_size] || 15 + end + + # 课堂教师权限 + def teacher_allowed + logger.info("#####identity: #{current_user.course_identity(@course)}") + unless current_user.course_identity(@course) < Course::STUDENT + normal_status(403, "") + end + end + + # 课堂教师、课堂管理员、超级管理员的权限(不包含助教) + def teacher_or_admin_allowed + unless current_user.course_identity(@course) < Course::ASSISTANT_PROFESSOR + normal_status(403, "") + end + end + + def require_admin + normal_status(403, "") unless User.current.admin? + end + + def require_business + normal_status(403, "") unless admin_or_business? + end + + # 前端会捕捉401,弹登录弹框 + # 未授权的捕捉407,弹试用申请弹框 + def require_login + #6.13 -hs + tip_exception(401, "..") unless User.current.logged? + end + + # 异常提醒 + def tip_exception(status = -1, message) + raise Educoder::TipException.new(status, message) + end + + def missing_template + tip_exception(404, "...") + end + + # 弹框提醒 + def tip_show_exception(status = -2, message) + raise Educoder::TipException.new(status, message) + end + + def normal_status(status = 0, message) + case status + when 403 + message = "您没有权限进行该操作" + when 404 + message = "您访问的页面不存在或已被删除" + end + render :json => { status: status, message: message } + end + + # 系统全局认证 + def check_auth + day_cer = UserDayCertification.find_by(user_id: current_user.id) + # 如果注册超过24小时则需要完善资料及授权 + if (Time.now.to_i - day_cer.try(:created_at).to_i) > 86400 + if !current_user.profile_completed? + info_url = '/account/profile' + tip_exception(402, info_url) + elsif current_user.certification != 1 + if current_user.apply_actions.exists?(container_type: 'TrialAuthorization', status: 0) + tip_exception(408, "您的试用申请正在审核中,请耐心等待") + end + tip_exception(407, "系统未授权") + end + end + + + # if current_user.certification != 1 && current_user.apply_actions.exists?(container_type: 'TrialAuthorization', status: 0) + # tip_exception(408, "您的试用申请正在审核中,请耐心等待") + # elsif (Time.now.to_i - day_cer.try(:created_at).to_i) < 86400 + # if !current_user.profile_completed? + # info_url = '/account/profile' + # tip_exception(402, info_url) + # elsif current_user.certification != 1 + # day_cer = UserDayCertification.find_by(user_id: current_user.id) + # tip_exception(407, "系统未授权") unless (Time.now.to_i - day_cer.try(:created_at).to_i) < 86400 + # end + # end + end + + def start_user_session(user) + session[:user_id] = user.id + session[:ctime] = Time.now.utc.to_i + session[:atime] = Time.now.utc.to_i + end + + def user_setup + # reacct静态资源加载不需要走这一步 + return if params[:controller] == "main" + # Find the current user + User.current = find_current_user + uid_logger("user_setup: " + (User.current.logged? ? "#{User.current.try(:login)} (id=#{User.current.try(:id)})" : "anonymous")) + + if !User.current.logged? && Rails.env.development? + User.current = User.find 12 + end + + # User.current = User.find 81403 + end + + # Sets the logged in user + def logged_user=(user) + reset_session + if user && user.is_a?(User) + User.current = user + start_user_session(user) + else + User.current = User.anonymous + end + end + + # Returns the current user or nil if no user is logged in + # and starts a session if needed + def find_current_user + uid_logger("user setup start: session[:user_id] is #{session[:user_id]}") + if session[:user_id] + # existing session + (User.active.find(session[:user_id]) rescue nil) + elsif autologin_user = try_to_autologin + autologin_user + elsif params[:format] == 'atom' && params[:key] && request.get? && accept_rss_auth? + # RSS key authentication does not start a session + User.find_by_rss_key(params[:key]) + end + end + + def autologin_cookie_name + edu_setting('autologin_cookie_name').presence || 'autologin' + end + + def try_to_autologin + if cookies[autologin_cookie_name] + # auto-login feature starts a new session + user = User.try_to_autologin(cookies[autologin_cookie_name]) + if user + start_user_session(user) + end + user + end + end + + def api_request? + %w(xml json).include? params[:format] + end + + def current_user + User.current + end + + ## 默认输出json + def render_json + respond_to do |format| + format.json + end + end + + ## 输出错误信息 + def error_status(message = nil) + @status = -1 + @message = message + end + + # 实训等对应的仓库地址 + def repo_ip_url(repo_path) + "#{edu_setting('git_address_ip')}/#{repo_path}" + end + + def repo_url(repo_path) + "#{edu_setting('git_address_domain')}/#{repo_path}" + end + + # 通关后,把最后一次成功的代码存到数据库 + # type 0 创始内容, 1 最新内容 + def game_passed_code(path, myshixun, game_id) + # 如果代码窗口是隐藏的,则不用保存代码 + return if myshixun.shixun.hide_code + file_content = git_fle_content myshixun.repo_path, path + unless file_content.present? + raise("获取文件代码异常") + end + logger.info("#######game_id:#{game_id}, file_content:#{file_content}") + game_code = GameCode.where(:game_id => game_id, :path => path).first + if game_code.nil? + GameCode.create!(:game_id => game_id, :new_code => file_content, :path => path) + else + game_code.update_attributes!(:new_code => file_content) + end + end + + # Post请求 + def uri_post(uri, params) + begin + uid_logger("--uri_exec: params is #{params}, url is #{uri}") + uri = URI.parse(URI.encode(uri.strip)) + res = Net::HTTP.post_form(uri, params).body + logger.info("--uri_exec: .....res is #{res}") + JSON.parse(res) + rescue Exception => e + uid_logger("--uri_exec: exception #{e.message}") + raise Educoder::TipException.new("实训平台繁忙(繁忙等级:84)") + end + end + + # 处理返回非0就报错的请求 + def interface_post(uri, params, status, message) + begin + uid_logger("--uri_exec: params is #{params}, url is #{uri}") + uri = URI.parse(URI.encode(uri.strip)) + res = Net::HTTP.post_form(uri, params).body + logger.info("--uri_exec: .....res is #{res}") + res = JSON.parse(res) + if (res && res['code'] != 0) + tip_exception(status, message) + else + res + end + rescue Exception => e + uid_logger("--uri_exec: exception #{e.message}") + raise Educoder::TipException.new("实训平台繁忙(繁忙等级:84)") + end + end + + # 适用与已经用url_safe编码后,回调字符串形式 + def tran_base64_decode64(str) + s_size = str.size % 4 + if s_size != 0 + str += "=" * (4 - s_size) + end + if str.blank? + str + else + Base64.decode64(str.tr("-_", "+/")).force_encoding("utf-8") + end + end + + def sucess_status(message = 'success') + render :json => { status: 1, message: message } + end + + # 随机生成字符 + def generate_identifier(container, num) + code = DCODES.sample(num).join + if container == User + while container.exists?(login: code) do + code = DCODES.sample(num).join + end + else + while container.exists?(identifier: code) do + code = DCODES.sample(num).join + end + end + code + end + + + # 实训主类别列表,自带描述 + def shixun_main_type + list = [] + mirrors = MirrorRepository.select([:id, :type_name]).published_main_mirror + mirrors.try(:each) do |mirror| + list << {id: mirror.id, type_name: mirror.type_name, description: mirror.try(:description)} + end + list + end + + # 小类别列表 + def shixun_small_type + list = [] + mirrors = MirrorRepository.select([:id, :type_name]).published_small_mirror + mirrors.try(:each) do |mirror| + list << {id: mirror.id, type_name: mirror.type_name} + end + list + end + + def container_limit(mirror_repositories) + container = [] + mirror_repositories.each do |mr| + if mr.name.present? + container << {:image => mr.name, :cpuLimit => mr.cpu_limit, :memoryLimit => "#{mr.memory_limit}M", :type => mr.try(:main_type) == "1" ? "main" : "sub"} + end + end + container.to_json + end + + # 实训中间层pod配置 + def shixun_container_limit shixun + container = [] + shixun.shixun_service_configs.each do |config| + mirror = config.mirror_repository + if mirror.name.present? + container << {:image => mirror.name, + :cpuLimit => config.cpu_limit, + :cpuRequest => config.lower_cpu_limit, + :memoryLimit => "#{config.memory_limit}M", + :memoryRequest => "#{config.request_limit}M", + :resourceLimit => "#{config.resource_limit}K", + :type => mirror.try(:main_type) == "1" ? "main" : "sub"} + end + end + container.to_json + end + + # 毕设任务列表的赛选 + def course_work(task, **option) + logger.info("#############{option}") + course = task.course + work_list = task.graduation_works.includes(user: [:user_extension]) + # 教师评阅搜索 0: 未评, 1 已评 + if option[:teacher_comment] + graduation_work_ids = GraduationWorkScore.where(graduation_work_id: work_list.map(&:id)).pluck(:graduation_work_id) + if option[:teacher_comment].zero? + work_list = work_list.where.not(id: graduation_work_ids) + elsif option[:teacher_comment] == 1 + work_list = work_list.where(id: graduation_work_ids).where.not(work_status: 0) + end + end + + # 作品状态 0: 未提交, 1 按时提交, 2 延迟提交 + if option[:task_status] + work_list = work_list.where(work_status: option[:task_status]) + end + + # 分班情况 + if option[:course_group] + group_user_ids = course.course_members.where(course_group_id: option[:course_group]).pluck(:user_id) + # 有分组只可能是老师身份查看列表 + work_list = work_list.where(user_id: group_user_ids) + end + + # 只看我的交叉评阅 + if option[:cross_comment] + graduation_work_id = task.graduation_work_comment_assignations.where(:user_id => current_user.id) + .pluck(:graduation_work_id).uniq if task.graduation_work_comment_assignations + work_list = work_list.where(id: graduation_work_id) + end + + # 输入姓名和学号搜索 + # TODO user_extension 如果修改 请调整 + if option[:search] + work_list = work_list.joins(user: :user_extension).where("concat(lastname, firstname) like ? + or student_id like ?", "%#{option[:search]}%", "%#{option[:search]}%") + end + + # 排序 + rorder = option[:order] || "updated_at" + b_order = option[:b_order] || "desc" + if rorder == "created_at" || rorder == "work_score" + work_list = work_list.order("graduation_works.#{rorder} #{b_order}") + elsif rorder == "student_id" + work_list = work_list.joins(user: :user_extension).order("user_extensions.#{rorder} #{b_order}") + end + work_list + end + + def strip_html(text, len=0, endss="...") + ss = "" + if !text.nil? && text.length>0 + ss=text.gsub(/<\/?.*?>/, '').strip + ss = ss.gsub(/ */, '') + ss = ss.gsub(/\r\n/,'') #新增 + ss = ss.gsub(/\n/,'') #新增 + if len > 0 && ss.length > len + ss = ss[0, len] + endss + elsif len > 0 && ss.length <= len + ss = ss + #ss = truncate(ss, :length => len) + end + end + ss + end + + # Returns a string that can be used as filename value in Content-Disposition header + def filename_for_content_disposition(name) + request.env['HTTP_USER_AGENT'] =~ %r{MSIE|Trident|Edge} ? ERB::Util.url_encode(name) : name + end + + def format_time(time) + time.blank? ? '' : time.strftime("%Y-%m-%d %H:%M") + end + + # 获取Oauth Client + def get_client(site) + client_id = Rails.configuration.educoder['client_id'] + client_secret = Rails.configuration.educoder['client_secret'] + + OAuth2::Client.new(client_id, client_secret, site: site) + end + + def paginate(relation) + limit = params[:limit].to_i.zero? ? 20 : params[:limit].to_i + page = params[:page].to_i.zero? ? 1 : params[:page].to_i + offset = (page - 1) * limit + + if relation.is_a?(Array) + relation[offset, limit] + else + relation.limit(limit).offset(offset) + end + end + + def strf_time(time) + time.blank? ? '' : time.strftime("%Y-%m-%d %H:%M:%S") + end + + def logger_error(error) + Rails.logger.error(error.message) + error.backtrace.each { |msg| Rails.logger.error(msg) } + end + + private + def object_not_found + uid_logger("Missing template or cant't find record, responding with 404") + render json: {message: "您访问的页面不存在或已被删除", status: 404} + false + end + + def tip_show(exception) + uid_logger("Tip show status is #{exception.status}, message is #{exception.message}") + render json: exception.tip_json + end + + def render_parameter_missing + render json: { status: -1, message: '参数缺失' } + end +end diff --git a/app/controllers/myshixuns_controller.rb b/app/controllers/myshixuns_controller.rb index 112b3352a..649516a03 100644 --- a/app/controllers/myshixuns_controller.rb +++ b/app/controllers/myshixuns_controller.rb @@ -90,10 +90,10 @@ class MyshixunsController < ApplicationController # params[:pics] = "a.png,b.png,c.png" def training_task_status - logger.info("##################training_task_status_start#{jsonTestDetails['buildID']}") ActiveRecord::Base.transaction do begin t1 = Time.now + Rails.logger.info("@@@222222#{params[:jsonTestDetails]}") jsonTestDetails = JSON.parse(params[:jsonTestDetails]) timeCost = JSON.parse(params[:timeCost]) brige_end_time = Time.parse(timeCost['evaluateEnd']) if timeCost['evaluateEnd'].present? @@ -130,8 +130,8 @@ class MyshixunsController < ApplicationController # is_public = test_sets.where(:position => j_test_set['caseId']).first.try(:is_public) logger.info "actual_output:################################################# #{actual_output}" - ts_time = format("%.2f", j_test_set['testSetTime'].to_f/1000000000).to_f - ts_mem = format("%.2f", j_test_set['testSetMem'].to_f/1024/1024).to_f + ts_time = format("%.2f", j_test_set['testSetTime'].to_f/1000000000).to_f if j_test_set['testSetTime'] + ts_mem = format("%.2f", j_test_set['testSetMem'].to_f/1024/1024).to_f if j_test_set['testSetMem'] Output.create!(:code => status, :game_id => game_id, :out_put => outPut, :test_set_position => j_test_set['caseId'], :actual_output => actual_output, :result => j_test_set['passed'].to_i, :query_index => max_query_index, @@ -210,10 +210,10 @@ class MyshixunsController < ApplicationController end uid_logger("training_task_status start#4**#{game_id}**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}") sucess_status - rescue Exception => e - tip_exception(e.message) - uid_logger_error("training_task_status error: #{e}") - raise ActiveRecord::Rollback + # rescue Exception => e + # tip_exception(e.message) + # uid_logger_error("training_task_status error: #{e}") + # raise ActiveRecord::Rollback end end end diff --git a/public/react/public/css/edu-all.css b/public/react/public/css/edu-all.css index 216e11266..ed44e1f90 100644 --- a/public/react/public/css/edu-all.css +++ b/public/react/public/css/edu-all.css @@ -171,7 +171,9 @@ em.vertical-line{display: inline-block;width: 2px;background: #999;height: 10px} #log_reg_content{border-radius: 5px;background: #FFFFff;width: 100%;text-align: center;position: absolute;top: 165px; left: 0px;padding: 40px 30px;box-sizing: border-box} .log_nav{border-bottom:1px solid #eaeaea;} -.log_nav li{float: left;text-align: center;font-size: 16px;padding-bottom:15px;margin: 0px 20px;cursor: pointer;} +.log_nav li{float: left;text-align: center;font-size: 16px;padding-bottom:15px; + /*margin: 0px 20px;*/ + cursor: pointer;} .log_nav li.active{border-bottom: 2px solid #459be5;} .log-botton{width: 100%;text-align: center;color: #FFFFff!important;display: block;background: #cbcbcb;height: 45px;line-height: 45px;border-radius: 4px;letter-spacing: 2px;cursor: pointer} .log-botton:hover{color: #FFFFff!important;} diff --git a/public/react/src/AppConfig.js b/public/react/src/AppConfig.js index 02d8c2be5..ddef777d6 100644 --- a/public/react/src/AppConfig.js +++ b/public/react/src/AppConfig.js @@ -2,7 +2,7 @@ import React from "react"; import axios from 'axios'; import { requestProxy } from "./indexEduplus2RequestProxy"; -import { broadcastChannelOnmessage ,SetAppModel} from 'educoder'; +import { broadcastChannelOnmessage ,SetAppModel, isDev, queryString } from 'educoder'; import { notification } from 'antd'; import './index.css' broadcastChannelOnmessage('refreshPage', () => { @@ -18,10 +18,18 @@ function locationurl(list){ } // TODO 开发期多个身份切换 -const debugType ="" -// window.location.search.indexOf('debug=t') != -1 ? 'teacher' : -// window.location.search.indexOf('debug=s') != -1 ? 'student' : 'admin' -// window._debugType = debugType; +let debugType ="" +if (isDev) { + const _search = window.location.search; + let parsed = {}; + if (_search) { + parsed = queryString.parse(_search); + } + debugType = window.location.search.indexOf('debug=t') != -1 ? 'teacher' : + window.location.search.indexOf('debug=s') != -1 ? 'student' : + window.location.search.indexOf('debug=a') != -1 ? 'admin' : parsed.debug || '' +} +window._debugType = debugType; export function initAxiosInterceptors(props) { // TODO 避免重复的请求 https://github.com/axios/axios#cancellation diff --git a/public/react/src/modules/courses/coursesPublic/PathModal.js b/public/react/src/modules/courses/coursesPublic/PathModal.js index 10a298c90..43901c87a 100644 --- a/public/react/src/modules/courses/coursesPublic/PathModal.js +++ b/public/react/src/modules/courses/coursesPublic/PathModal.js @@ -91,7 +91,7 @@ class PathModal extends Component{ this.setState({ type:types, page:1, - newshixunmodallist:[] + newshixunmodallist:undefined }) this.funshixunpathlist(Searchvalue,types,true,1) } @@ -105,7 +105,7 @@ class PathModal extends Component{ SenttotheSearch=(value)=>{ this.setState({ page:1, - newshixunmodallist:[] + newshixunmodallist:undefined }) let{type}=this.state; this.funshixunpathlist(value,type,true,1) @@ -267,12 +267,19 @@ class PathModal extends Component{ margin-top:0px !important; height: 40px; } + `} - { newshixunmodallist&&newshixunmodallist.length===0?"":
:newshixunmodallist&&newshixunmodallist.length===0?
+
+ +

暂时还没有相关数据哦!

+
:
+ style={{height:"204px"}}> { diff --git a/public/react/src/modules/courses/coursesPublic/ShixunModal.js b/public/react/src/modules/courses/coursesPublic/ShixunModal.js index 56cecc51b..1ae63da90 100644 --- a/public/react/src/modules/courses/coursesPublic/ShixunModal.js +++ b/public/react/src/modules/courses/coursesPublic/ShixunModal.js @@ -82,7 +82,6 @@ class ShixunModal extends Component{ //勾选实训 shixunhomeworkedit=(list)=>{ -debugger let newpatheditarry=[]; if (this.props.singleChoose == true) { if (list.length > 0) { @@ -330,7 +329,7 @@ debugger
+ > + this.applyForAddOrgForm = form} schoolName={school} + {...propsWithoutForm}> {/*提示*/} -
- - {getFieldDecorator('school', { - rules: [{required: true, message: "不能为空"}], - })( - - )} - - {/*(输入内容出现匹配的下拉菜单←同账号管理的单位信息填写)*/} - -
-
-
+ {/*
*/} + + {/*
*/}
@@ -456,7 +473,6 @@ class CoursesNew extends Component { > {options} - )} {/*(错误示例:数据结构2017本部;数据结构2017秋季;数据结构2017电子商务1班)*/} @@ -606,7 +622,7 @@ class CoursesNew extends Component {
-
+
(选中后本课堂对所有用户可见,否则仅本课堂成员可见)
+ +
+ + {getFieldDecorator('school', { + rules: [{required: true, message: "不能为空"}], + })( + + )} + + {/*(输入内容出现匹配的下拉菜单←同账号管理的单位信息填写)*/} + +
+
+ + {searchlistscholl.length===0?
+ + 未找到包含“{school}”的高校, + 申请新增 + +
:""} + +
+ + +
- -
+ +
diff --git a/public/react/src/modules/courses/poll/PollNew.js b/public/react/src/modules/courses/poll/PollNew.js index 675e355f3..cf415aa28 100644 --- a/public/react/src/modules/courses/poll/PollNew.js +++ b/public/react/src/modules/courses/poll/PollNew.js @@ -2074,7 +2074,6 @@ class PollNew extends Component { //最小值 HandleGradationGroupChangee = (value, index, max, length) => { - debugger var minbool = false; var maxbool = false; let arr = this.state.adddom; diff --git a/public/react/src/modules/courses/shixunHomework/Listofworksstudentone.js b/public/react/src/modules/courses/shixunHomework/Listofworksstudentone.js index 60a8512d5..db58e95fd 100644 --- a/public/react/src/modules/courses/shixunHomework/Listofworksstudentone.js +++ b/public/react/src/modules/courses/shixunHomework/Listofworksstudentone.js @@ -993,7 +993,7 @@ class Listofworksstudentone extends Component { } axios.post(urll, datasysl).then((result) => { console.log("980000000____________________"); - debugger + if(result === undefined){ return } diff --git a/public/react/src/modules/login/LoginDialog.js b/public/react/src/modules/login/LoginDialog.js index 7629eeef2..d3df6090e 100644 --- a/public/react/src/modules/login/LoginDialog.js +++ b/public/react/src/modules/login/LoginDialog.js @@ -337,6 +337,7 @@ class LoginDialog extends Component { } loginEDU=()=>{ + let {loginValue,passValue,regular,isGoingValue}=this.state; if(regular===1){ return @@ -372,14 +373,16 @@ class LoginDialog extends Component { this.setState({ isRender:false }) + this.props.Modifyloginvalue(); window.location.reload(); + } } - try { - this.props.Modifyloginvalue(); - }catch (e) { - - } + // try { + // this.props.Modifyloginvalue(); + // }catch (e) { + // + // } }).catch((error) => { console.log("356"); console.log(error) @@ -408,6 +411,7 @@ class LoginDialog extends Component { this.handleDialogClose()} > {isRender===true? @@ -474,7 +478,7 @@ class LoginDialog extends Component { 登录
-

+

+

{ isRenders === false ? "" : diff --git a/public/react/src/modules/login/Trialapplicationysl.js b/public/react/src/modules/login/Trialapplicationysl.js index dc9755fbe..ee4d6a9f9 100644 --- a/public/react/src/modules/login/Trialapplicationysl.js +++ b/public/react/src/modules/login/Trialapplicationysl.js @@ -394,7 +394,7 @@ class Trialapplicationysl extends Component { // console.log(this.props); return ( -
+
{ isRenders === false ? "" : diff --git a/public/react/src/modules/paths/PathDetail/DetailCardsEditAndAdd.js b/public/react/src/modules/paths/PathDetail/DetailCardsEditAndAdd.js index fc0a0fea9..5534dd415 100644 --- a/public/react/src/modules/paths/PathDetail/DetailCardsEditAndAdd.js +++ b/public/react/src/modules/paths/PathDetail/DetailCardsEditAndAdd.js @@ -298,7 +298,6 @@ class DetailCardsEditAndAdd extends Component{ //滑动到底判断 if(e.currentTarget.scrollHeight-e.currentTarget.scrollTop===e.currentTarget.clientHeight){ // console.log("到达底部"); - debugger this.setState({ hometypepvisible:true }) diff --git a/public/react/src/modules/paths/PathDetail/PathDetailIndex.js b/public/react/src/modules/paths/PathDetail/PathDetailIndex.js index 7211fde5e..1731064c0 100644 --- a/public/react/src/modules/paths/PathDetail/PathDetailIndex.js +++ b/public/react/src/modules/paths/PathDetail/PathDetailIndex.js @@ -139,21 +139,20 @@ class PathDetailIndex extends Component{ let pathid=this.props.match.params.pathId; let url="/paths/"+pathid+".json"; axios.get(url).then((result)=>{ - if (result.data.status == 407 || result.data.status == 401) { + if (result.data.status === 407 || result.data.status === 401) { return; } - if(result.data.allow_visit===true){ - this.setState({ - detailInfoList:result.data, - items: getItems(result.data.members.length), - }) - }else{ - window.location.href = "/403"; - // this.setState({ - // Modalstype:true, - // Modalstopval:'你没有权限访问,请联系对应课程管理人员开通', - // }) - } + + if (result.data.status === 403) { + return; + } + + if(result.data.allow_visit===true){ + this.setState({ + detailInfoList:result.data, + items: getItems(result.data.members.length), + }) + } }).catch((error)=>{ console.log(error); @@ -168,6 +167,9 @@ class PathDetailIndex extends Component{ if (result.data.status == 407 || result.data.status == 401) { return; } + if (result.data.status === 403 ) { + return; + } if(result.data.allow_visit===true){ this.setState({ @@ -175,13 +177,8 @@ class PathDetailIndex extends Component{ items: getItems(result.data.members.length), user_id:undefined, }) - }else{ - window.location.href = "/403"; - // this.setState({ - // Modalstype:true, - // Modalstopval:'你没有权限访问,请联系对应课程管理人员开通', - // }) } + }).catch((error)=>{ console.log(error); }) diff --git a/public/react/src/modules/tpm/NewHeader.js b/public/react/src/modules/tpm/NewHeader.js index 37fac626d..20436f3c7 100644 --- a/public/react/src/modules/tpm/NewHeader.js +++ b/public/react/src/modules/tpm/NewHeader.js @@ -487,7 +487,6 @@ submittojoinclass=(value)=>{ } showSearchOpen=(e)=>{ - debugger this.setState({ showSearchOpentype:true }) @@ -495,7 +494,6 @@ submittojoinclass=(value)=>{ } hideshowSearchOpen=(e)=>{ - debugger let {setevaluatinghides}=this.state; if(setevaluatinghides===true){ this.setState({ @@ -520,7 +518,6 @@ submittojoinclass=(value)=>{ } setevaluatinghides=()=>{ - debugger this.setState( { setevaluatinghides:true @@ -602,7 +599,6 @@ submittojoinclass=(value)=>{ // rolearr:["",""], // console.log("618"); // console.log(user_phone_binded); - console.log(showSearchOpentype) return (
diff --git a/public/react/src/modules/tpm/TPMIndex.css b/public/react/src/modules/tpm/TPMIndex.css index c8a48440c..529c7df58 100644 --- a/public/react/src/modules/tpm/TPMIndex.css +++ b/public/react/src/modules/tpm/TPMIndex.css @@ -136,7 +136,7 @@ body>.-task-title { margin-right: 20px; } .HeaderSearch .ant-input-search .ant-input{ - height:30px; + /*height:30px;*/ background: #373e3f !important; border: 1px solid #373e3f !important; diff --git a/public/react/src/modules/tpm/challengesnew/TPMevaluation.js b/public/react/src/modules/tpm/challengesnew/TPMevaluation.js index 01b99b4c2..396358708 100644 --- a/public/react/src/modules/tpm/challengesnew/TPMevaluation.js +++ b/public/react/src/modules/tpm/challengesnew/TPMevaluation.js @@ -29,1104 +29,1104 @@ const Option = Select.Option; const RadioGroup = Radio.Group; function create_editorMD(id, width, high, placeholder, imageUrl, callback) { - var editorName = window.editormd(id, { - width: width, - height: high, - path: path, // "/editormd/lib/" - - syncScrolling: "single", - tex: true, - tocm: true, - emoji: true, - taskList: true, - codeFold: true, - searchReplace: true, - htmlDecode: "style,script,iframe", - sequenceDiagram: true, - autoFocus: false, - toolbarIcons: function () { - // Or return editormd.toolbarModes[name]; // full, simple, mini - // Using "||" set icons align right. - return ["bold", "italic", "|", "list-ul", "list-ol", "|", "code", "code-block", "|", "testIcon", "testIcon1", '|', "image", "table", '|', "watch", "clear"] - }, - toolbarCustomIcons: { - testIcon: "
", - testIcon1: "
" - }, - //这个配置在simple.html中并没有,但是为了能够提交表单,使用这个配置可以让构造出来的HTML代码直接在第二个隐藏的textarea域中,方便post提交表单。 - saveHTMLToTextarea: true, - // 用于增加自定义工具栏的功能,可以直接插入HTML标签,不使用默认的元素创建图标 - dialogMaskOpacity: 0.6, - placeholder: placeholder, - imageUpload: true, - imageFormats: ["jpg", "jpeg", "gif", "png", "bmp", "webp", "JPG", "JPEG", "GIF", "PNG", "BMP", "WEBP"], - imageUploadURL: imageUrl,//url - onload: function () { - // this.previewing(); - $("#" + id + " [type=\"latex\"]").bind("click", function () { - editorName.cm.replaceSelection("```latex"); - editorName.cm.replaceSelection("\n"); - editorName.cm.replaceSelection("\n"); - editorName.cm.replaceSelection("```"); - var __Cursor = editorName.cm.getDoc().getCursor(); - editorName.cm.setCursor(__Cursor.line - 1, 0); - }); - - $("#" + id + " [type=\"inline\"]").bind("click", function () { - editorName.cm.replaceSelection("$$$$"); - var __Cursor = editorName.cm.getDoc().getCursor(); - editorName.cm.setCursor(__Cursor.line, __Cursor.ch - 2); - editorName.cm.focus(); - }); - $("[type=\"inline\"]").attr("title", "行内公式"); - $("[type=\"latex\"]").attr("title", "多行公式"); - - window.md_elocalStorage(editorName, `exercise__${id}`, "Memochallengesnew"); - - callback && callback() - } - }); - return editorName; + var editorName = window.editormd(id, { + width: width, + height: high, + path: path, // "/editormd/lib/" + + syncScrolling: "single", + tex: true, + tocm: true, + emoji: true, + taskList: true, + codeFold: true, + searchReplace: true, + htmlDecode: "style,script,iframe", + sequenceDiagram: true, + autoFocus: false, + toolbarIcons: function () { + // Or return editormd.toolbarModes[name]; // full, simple, mini + // Using "||" set icons align right. + return ["bold", "italic", "|", "list-ul", "list-ol", "|", "code", "code-block", "|", "testIcon", "testIcon1", '|', "image", "table", '|', "watch", "clear"] + }, + toolbarCustomIcons: { + testIcon: "
", + testIcon1: "
" + }, + //这个配置在simple.html中并没有,但是为了能够提交表单,使用这个配置可以让构造出来的HTML代码直接在第二个隐藏的textarea域中,方便post提交表单。 + saveHTMLToTextarea: true, + // 用于增加自定义工具栏的功能,可以直接插入HTML标签,不使用默认的元素创建图标 + dialogMaskOpacity: 0.6, + placeholder: placeholder, + imageUpload: true, + imageFormats: ["jpg", "jpeg", "gif", "png", "bmp", "webp", "JPG", "JPEG", "GIF", "PNG", "BMP", "WEBP"], + imageUploadURL: imageUrl,//url + onload: function () { + // this.previewing(); + $("#" + id + " [type=\"latex\"]").bind("click", function () { + editorName.cm.replaceSelection("```latex"); + editorName.cm.replaceSelection("\n"); + editorName.cm.replaceSelection("\n"); + editorName.cm.replaceSelection("```"); + var __Cursor = editorName.cm.getDoc().getCursor(); + editorName.cm.setCursor(__Cursor.line - 1, 0); + }); + + $("#" + id + " [type=\"inline\"]").bind("click", function () { + editorName.cm.replaceSelection("$$$$"); + var __Cursor = editorName.cm.getDoc().getCursor(); + editorName.cm.setCursor(__Cursor.line, __Cursor.ch - 2); + editorName.cm.focus(); + }); + $("[type=\"inline\"]").attr("title", "行内公式"); + $("[type=\"latex\"]").attr("title", "多行公式"); + + window.md_elocalStorage(editorName, `exercise__${id}`, "Memochallengesnew"); + + callback && callback() + } + }); + return editorName; } export default class TPMevaluation extends Component { - constructor(props) { - super(props) - this.state = { - choice_url: undefined, - practice_url: undefined, - go_back_url: undefined, - task_pass_default: undefined, - submit_url: undefined, - value: 1, - evaluationlist:[], - shixunId:undefined, - power:false, - shixunfilepath:undefined, - evaluationvisible:false, - trees:undefined, - path:"", - main:[], - saveshixunfilepath:undefined, - selectpath:undefined, - shixunfilepathplay:undefined, - shixunfileexpectpicturepath:undefined, - shixunfilestandardpicturepath:undefined, - shixunfilepicturepath:undefined, - pathoptionvalue:-1, - showrepositoryurltiptype: false, - prev_challenge: undefined, - next_challenge: undefined, - StudentTaskPapers:false, - StudentTaskDocs:false, - selectpatharr:[], - handpathopt:false, - scorevalue:false, - markvalue:true, - scoretype:undefined - } - } - - - exerciseMD(initValue, id) { - - this.contentChanged = false; - const placeholder = ""; + constructor(props) { + super(props) + this.state = { + choice_url: undefined, + practice_url: undefined, + go_back_url: undefined, + task_pass_default: undefined, + submit_url: undefined, + value: 1, + evaluationlist:[], + shixunId:undefined, + power:false, + shixunfilepath:undefined, + evaluationvisible:false, + trees:undefined, + path:"", + main:[], + saveshixunfilepath:undefined, + selectpath:undefined, + shixunfilepathplay:undefined, + shixunfileexpectpicturepath:undefined, + shixunfilestandardpicturepath:undefined, + shixunfilepicturepath:undefined, + pathoptionvalue:-1, + showrepositoryurltiptype: false, + prev_challenge: undefined, + next_challenge: undefined, + StudentTaskPapers:false, + StudentTaskDocs:false, + selectpatharr:[], + handpathopt:false, + scorevalue:false, + markvalue:true, + scoretype:undefined + } + } + + + exerciseMD(initValue, id) { + + this.contentChanged = false; + const placeholder = ""; // amp; // 编辑时要传memoId - const imageUrl = `/api/attachments.json`; + const imageUrl = `/api/attachments.json`; // 创建editorMd - const exercise_editormd = create_editorMD(id, '100%', 400, placeholder, imageUrl, () => { - setTimeout(() => { - exercise_editormd.resize() - exercise_editormd.cm && exercise_editormd.cm.refresh() - }, 500) - - if (initValue != undefined) { - exercise_editormd.setValue(initValue) - } - exercise_editormd.cm.on("change", (_cm, changeObj) => { - console.log('....contentChanged') - this.contentChanged = true; - }) - }); - this.exercise_editormd = exercise_editormd; - window.exercise_editormd = exercise_editormd; - - } - - componentDidMount() { - let id = this.props.match.params.shixunId; - let checkpointId=this.props.match.params.checkpointId; - this.setState({ - shixunId:id, - checkpointId:checkpointId - }) - let newchoice_url= "/shixuns/"+id+"/challenges/newquestion"; - let newpractice_url= "/shixuns/"+id+"/challenges/new"; - let newgo_back_url="/shixuns/"+id+"/challenges"; - - let url = "/shixuns/" + id + "/challenges/" + checkpointId + "/edit.json?tab=1"; - axios.get(url).then((response) => { - let newprev_challenge = response.data.prev_challenge; - let next_challenge = response.data.next_challenge; - if (newprev_challenge != undefined) { - if(newprev_challenge.st===0){ - newprev_challenge = "/shixuns/" + id + "/challenges/" + newprev_challenge.id + "/editcheckpoint"; - }else{ - newprev_challenge = "/shixuns/" + id + "/challenges/" + newprev_challenge.id + "/editquestion"; - } - } - if (next_challenge != undefined) { - - if(next_challenge.st===0){ - next_challenge = "/shixuns/" + id + "/challenges/" + next_challenge.id+ "/editcheckpoint"; - }else{ - next_challenge = "/shixuns/" + id + "/challenges/" + next_challenge.id+ "/editquestion"; - } - } - let newevaluationlist=[] - if(response.data.test_sets.length===0){ - let newlist=[ - {hidden:0,input:"",output:"",score:50}, - {hidden:1,input:"",output:"",score:50} - ] - newevaluationlist=newlist - }else{ - newevaluationlist=response.data.test_sets - } - - this.setState({ - power: response.data.power, - evaluationlist:newevaluationlist, - shixunfilepath:response.data.path, - shixunfilepathplay:response.data.exec_path, - pathoptionvalue:response.data.show_type, - shixunfileexpectpicturepath:response.data.original_picture_path, - shixunfilestandardpicturepath:response.data.expect_picture_path, - shixunfilepicturepath:response.data.picture_path, - prev_challenge: newprev_challenge, - next_challenge: next_challenge, - choice_url: newchoice_url, // 导航中的新建选择题url - practice_url: newpractice_url, //string 导航中新建实践题url - go_back_url: newgo_back_url, //string 导航中的返回url - position: response.data.position, //int 关卡位置,导航栏中的第几关 - scorevalue:response.data.test_set_score, - markvalue:response.data.test_set_average, - }) - this.evaluationoninputvalueonload(); - if(response.data.power===false){ - this.props.showSnackbar("你没有权限修改"); - } - if(response.data.answer===undefined){ - this.answerMD("", "answerMD"); - }else{ - this.answerMD(response.data.answer, "answerMD"); - } - - }).catch((error) => { - console.log(error) - }); - - } - - - setevaluationlist=(newevaluationlist)=>{ - this.setState({ - evaluationlist:newevaluationlist - }) - } - - - addevaluationon=()=>{ - let {evaluationlist,markvalue}=this.state; - let newevaluationlist=evaluationlist; - newevaluationlist.push({hidden:0,input:"",output:"",score:0}); - newevaluationlist=this.oneditevaluationlist(newevaluationlist,markvalue); - this.setevaluationlist(newevaluationlist); - } - - del_test_array=(key)=>{ - let {evaluationlist,markvalue}=this.state; - let newevaluationlist=evaluationlist; - newevaluationlist.splice(key,1); - newevaluationlist=this.oneditevaluationlist(newevaluationlist,markvalue); - this.setevaluationlist(newevaluationlist); - } - - getfilepath=(e,shixunfilepath)=>{ - this.setState({ - evaluationvisible: true, - selectpath:e.target.value, - selectpatharr:[], - }); - let id = this.props.match.params.shixunId; - let url ="/shixuns/"+id+"/repository.json"; - axios.post(url,{ - path: "" - }).then((response) => { - if (response.data.status === 403||response.data.status === 401||response.data.status === 500) { - - }else{ - this.setState({ - trees:response.data.trees, - saveshixunfilepath:shixunfilepath, - path:"", - main:[], - }) - } - - }).catch((error) => { - console.log(error) - }); - } - - sendgetfilepath=(newpath,type)=>{ - let id = this.props.match.params.shixunId; - let{path,main}=this.state; - let ary=main; - let paths=path; - - this.setState({ - selectpatharr:[], - }) - if(paths===""&&type==="tree"){ - newpath=newpath+"/"; - paths=""; - if(main.length===0){ - ary.push({val:"根目录/",path:""},{val:newpath,path:paths+newpath}) - }else{ - ary.push({val:newpath,path:paths+newpath}) - } - - }else if(paths!=""&&type==="tree"){ - newpath=newpath+"/"; - ary.push({val:newpath,path:paths+newpath}) - } - - - let url ="/shixuns/"+id+"/repository.json"; - if(type==="tree"){ - - axios.post(url,{ - path: paths+newpath - }).then((response) => { - if (response.data.status === 403||response.data.status === 401||response.data.status === 500) { - - }else{ - this.setState({ - trees:response.data.trees, - path:paths+newpath, - main:ary, - // selectpath:"" - }) - } - - }).catch((error) => { - console.log(error) - }); - } - - } - - goblakepath=(path,key)=>{ - let {main,selectpath} =this.state; - let newmain=[] - for(var i=0;i<=key;i++){ - newmain.push(main[i]) - } - let id = this.props.match.params.shixunId; - let url ="/shixuns/"+id+"/repository.json"; - axios.post(url,{ - path: path - }).then((response) => { - if (response.data.status === 403||response.data.status === 401||response.data.status === 500) { - - }else { - this.setState({ - trees: response.data.trees, - path: path, - main: newmain, - // selectpath:selectpath - }) - } - }).catch((error) => { - console.log(error) - }); - } - // delesavegetfilepath=(value)=>{ - // let {selectpatharr} = this.state - // let newarr =selectpatharr; - // let newselectpath=""; - // for(var i=0; i{ - let {selectpath,saveshixunfilepath} = this.state - // let newarr =selectpatharr; - // let arrtype=false; - // let arrsum=0; - // let newselectpath=""; - // newarr.push(value) - // if(newarr.length>1&&arrtype===false){ - // for(var i=0; i { + setTimeout(() => { + exercise_editormd.resize() + exercise_editormd.cm && exercise_editormd.cm.refresh() + }, 500) + + if (initValue != undefined) { + exercise_editormd.setValue(initValue) + } + exercise_editormd.cm.on("change", (_cm, changeObj) => { + console.log('....contentChanged') + this.contentChanged = true; + }) + }); + this.exercise_editormd = exercise_editormd; + window.exercise_editormd = exercise_editormd; + + } + + componentDidMount() { + let id = this.props.match.params.shixunId; + let checkpointId=this.props.match.params.checkpointId; + this.setState({ + shixunId:id, + checkpointId:checkpointId + }) + let newchoice_url= "/shixuns/"+id+"/challenges/newquestion"; + let newpractice_url= "/shixuns/"+id+"/challenges/new"; + let newgo_back_url="/shixuns/"+id+"/challenges"; + + let url = "/shixuns/" + id + "/challenges/" + checkpointId + "/edit.json?tab=1"; + axios.get(url).then((response) => { + let newprev_challenge = response.data.prev_challenge; + let next_challenge = response.data.next_challenge; + if (newprev_challenge != undefined) { + if(newprev_challenge.st===0){ + newprev_challenge = "/shixuns/" + id + "/challenges/" + newprev_challenge.id + "/editcheckpoint"; }else{ - const type = selectpath.split(';'); - let types=false; - for(var i=0; i { + console.log(error) + }); + + } + + + setevaluationlist=(newevaluationlist)=>{ + this.setState({ + evaluationlist:newevaluationlist + }) + } + + + addevaluationon=()=>{ + let {evaluationlist,markvalue}=this.state; + let newevaluationlist=evaluationlist; + newevaluationlist.push({hidden:0,input:"",output:"",score:0}); + newevaluationlist=this.oneditevaluationlist(newevaluationlist,markvalue); + this.setevaluationlist(newevaluationlist); + } + + del_test_array=(key)=>{ + let {evaluationlist,markvalue}=this.state; + let newevaluationlist=evaluationlist; + newevaluationlist.splice(key,1); + newevaluationlist=this.oneditevaluationlist(newevaluationlist,markvalue); + this.setevaluationlist(newevaluationlist); + } + + getfilepath=(e,shixunfilepath)=>{ + this.setState({ + evaluationvisible: true, + selectpath:e.target.value, + selectpatharr:[], + }); + let id = this.props.match.params.shixunId; + let url ="/shixuns/"+id+"/repository.json"; + axios.post(url,{ + path: "" + }).then((response) => { + if (response.data.status === 403||response.data.status === 401||response.data.status === 500) { + + }else{ + this.setState({ + trees:response.data.trees, + saveshixunfilepath:shixunfilepath, + path:"", + main:[], + }) + } + + }).catch((error) => { + console.log(error) + }); + } + + sendgetfilepath=(newpath,type)=>{ + let id = this.props.match.params.shixunId; + let{path,main}=this.state; + let ary=main; + let paths=path; + + this.setState({ + selectpatharr:[], + }) + if(paths===""&&type==="tree"){ + newpath=newpath+"/"; + paths=""; + if(main.length===0){ + ary.push({val:"根目录/",path:""},{val:newpath,path:paths+newpath}) + }else{ + ary.push({val:newpath,path:paths+newpath}) + } + + }else if(paths!=""&&type==="tree"){ + newpath=newpath+"/"; + ary.push({val:newpath,path:paths+newpath}) + } + + + let url ="/shixuns/"+id+"/repository.json"; + if(type==="tree"){ + + axios.post(url,{ + path: paths+newpath + }).then((response) => { + if (response.data.status === 403||response.data.status === 401||response.data.status === 500) { - if(types===false){ - newselectpath=selectpath+value+ ";" + }else{ + this.setState({ + trees:response.data.trees, + path:paths+newpath, + main:ary, + // selectpath:"" + }) + } + + }).catch((error) => { + console.log(error) + }); + } + + } + + goblakepath=(path,key)=>{ + let {main,selectpath} =this.state; + let newmain=[] + for(var i=0;i<=key;i++){ + newmain.push(main[i]) + } + let id = this.props.match.params.shixunId; + let url ="/shixuns/"+id+"/repository.json"; + axios.post(url,{ + path: path + }).then((response) => { + if (response.data.status === 403||response.data.status === 401||response.data.status === 500) { + + }else { + this.setState({ + trees: response.data.trees, + path: path, + main: newmain, + // selectpath:selectpath + }) + } + }).catch((error) => { + console.log(error) + }); + } + // delesavegetfilepath=(value)=>{ + // let {selectpatharr} = this.state + // let newarr =selectpatharr; + // let newselectpath=""; + // for(var i=0; i{ + let {selectpath,saveshixunfilepath} = this.state + // let newarr =selectpatharr; + // let arrtype=false; + // let arrsum=0; + // let newselectpath=""; + // newarr.push(value) + // if(newarr.length>1&&arrtype===false){ + // for(var i=0; i{ + let {saveshixunfilepath,selectpath}=this.state; + this.setState({ + evaluationvisible: false, + [saveshixunfilepath]:selectpath + }); + } + evaluationhideModal=()=>{ + this.setState({ + evaluationvisible: false, + }); + } + handpathoptionvalue=(value)=>{ + this.setState({ + pathoptionvalue:value + }) + } + showrepositoryurltip=(type)=>{ + if(type===1){ + this.setState({ + showrepositoryurltiptype:true + }) + }else{ + this.setState({ + showrepositoryurltiptype:false + }) + } + } + + evaluationonChange=(e,key)=>{ + let {evaluationlist}=this.state; + let newevaluationlist=evaluationlist; + let newtype; + if(e===1){ + newtype=0; + }else{ + newtype=1; + } + // newevaluationlist[key].is_public=newtype; + // for(var i=0; i{ + let {evaluationlist,scoretype}=this.state; + + if(scoretype===key){ + this.setState({ + scoretype:undefined + }) + } + let newevaluationlist=evaluationlist; + let sum =parseInt(e.target.value); + if(isNaN(sum)){ + sum=0 + } + newevaluationlist[key].score=sum; + + this.setState({ + evaluationlist:newevaluationlist, + markvalue:false + }) + this.setevaluationlist(newevaluationlist); + } + + evaluationoninputvalue=(e,key,type)=>{ + $.fn.autoHeight = function(){ + function autoHeight(elem){ + elem.style.height = 'auto'; + elem.style.maxHeight = '140px'; + elem.scrollTop = 0; //防抖动 + elem.style.height = elem.scrollHeight + 'px'; + } + this.each(function(){ + autoHeight(this); + $(this).on('keyup', function(){ + autoHeight(this); + }); + }); + } + $('textarea[autoHeight]').autoHeight(); + + let {evaluationlist}=this.state; + let newevaluationlist=evaluationlist; + if(type==="sr"){ + newevaluationlist[key].input=e.target.value + }else if(type==="yq"){ + newevaluationlist[key].output=e.target.value + } + this.setevaluationlist(newevaluationlist); + } + + + evaluationoninputvalueonload=()=>{ + $.fn.autoHeight = function(){ + function autoHeight(elem){ + elem.style.height = 'auto'; + elem.style.maxHeight = '140px'; + elem.scrollTop = 0; //防抖动 + elem.style.height = elem.scrollHeight + 'px'; + } + this.each(function(){ + autoHeight(this); + $(this).on('keyup', function(){ + autoHeight(this); + }); + }); + } + $('textarea[autoHeight]').autoHeight(); + } + submitarbitrationevaluation=()=>{ + let{evaluationlist,shixunfilepath,shixunfilepathplay,shixunfileexpectpicturepath,shixunfilestandardpicturepath,shixunfilepicturepath,pathoptionvalue,scorevalue,markvalue}=this.state; + + + let newscorevalue; + if(scorevalue===false){ + newscorevalue=false + }else{ + //判断占比 + newscorevalue=true + + let sum=0; + for(var i=0; i100){ + this.props.showSnackbar("测试集的评分占比不能大于100"); + this.setState({ + scoretype:i + }) + return + } + sum=sum+evaluationlist[i].score + } + + if(sum>100||sum<100){ + this.props.showSnackbar("测试集的评分占比之和必须等于100"); + return + } + + + } + if(shixunfilepath===undefined||shixunfilepath===""||shixunfilepath===null){ + this.props.showSnackbar("学员任务文件路径为空"); + this.setState({ + StudentTaskPapers:true + }) + $('html').animate({ + scrollTop: 120 + }, 1000); + return + } + + if(shixunfilepathplay===undefined||shixunfilepathplay===""||shixunfilepathplay===null){ + this.props.showSnackbar("评测执行文件路径为空"); + this.setState({ + StudentTaskDocs:true + }) + $('html').animate({ + scrollTop: 130 + }, 1000); + return + } + + if(evaluationlist.length===0){ + this.props.showSnackbar("测试集不能为空"); + return + } + let id = this.props.match.params.shixunId; + let{checkpointId}=this.state; + let url = "/shixuns/"+id+"/challenges/"+checkpointId+".json"; + axios.put(url,{ + tab:1, + challenge:{ + path:shixunfilepath, + exec_path:shixunfilepathplay, + show_type:pathoptionvalue, + original_picture_path:shixunfileexpectpicturepath, + expect_picture_path:shixunfilestandardpicturepath, + picture_path:shixunfilepicturepath, + test_set_score:newscorevalue, + test_set_average:markvalue + }, + test_set:evaluationlist + } + ).then((response) => { + this.props.showSnackbar(response.data.messages); + // if(response.data.status===1){ + // window.location.href = "/shixuns/" + id + "/challenges/"+response.data.challenge_id+"/tab=3" + // } + }).catch((error) => { + console.log(error) + }); + } + handpathoptionvalues=()=>{ + this.setState({ + handpathopt:true + }) + } + handpathoptionvaluess=()=>{ + this.setState({ + handpathopt:false + }) + } + saveselectpath=(e)=>{ + + this.setState({ + selectpath:e.target.value + }) + } + updatepath=(e,name)=>{ + this.setState({ + [name]:e.target.value + }) + } + + + oneditevaluationlist=(newevaluationlist,markvalue)=>{ + + if(markvalue===true){ + if(100%newevaluationlist.length===0){ + let sum=100/newevaluationlist.length; + for(var i=0; i{ - let {saveshixunfilepath,selectpath}=this.state; - this.setState({ - evaluationvisible: false, - [saveshixunfilepath]:selectpath - }); - } - evaluationhideModal=()=>{ - this.setState({ - evaluationvisible: false, - }); - } - handpathoptionvalue=(value)=>{ - this.setState({ - pathoptionvalue:value - }) - } - showrepositoryurltip=(type)=>{ - if(type===1){ - this.setState({ - showrepositoryurltiptype:true - }) - }else{ - this.setState({ - showrepositoryurltiptype:false - }) - } - } - - evaluationonChange=(e,key)=>{ - let {evaluationlist}=this.state; - let newevaluationlist=evaluationlist; - let newtype; - if(e===1){ - newtype=0; - }else{ - newtype=1; - } - // newevaluationlist[key].is_public=newtype; - // for(var i=0; i{ - let {evaluationlist,scoretype}=this.state; - - if(scoretype===key){ - this.setState({ - scoretype:undefined - }) - } - let newevaluationlist=evaluationlist; - let sum =parseInt(e.target.value); - if(isNaN(sum)){ - sum=0 - } - newevaluationlist[key].score=sum; - - this.setState({ - evaluationlist:newevaluationlist, - markvalue:false - }) - this.setevaluationlist(newevaluationlist); - } - - evaluationoninputvalue=(e,key,type)=>{ - $.fn.autoHeight = function(){ - function autoHeight(elem){ - elem.style.height = 'auto'; - elem.style.maxHeight = '140px'; - elem.scrollTop = 0; //防抖动 - elem.style.height = elem.scrollHeight + 'px'; - } - this.each(function(){ - autoHeight(this); - $(this).on('keyup', function(){ - autoHeight(this); - }); - }); - } - $('textarea[autoHeight]').autoHeight(); - - let {evaluationlist}=this.state; - let newevaluationlist=evaluationlist; - if(type==="sr"){ - newevaluationlist[key].input=e.target.value - }else if(type==="yq"){ - newevaluationlist[key].output=e.target.value - } - this.setevaluationlist(newevaluationlist); - } - - - evaluationoninputvalueonload=()=>{ - $.fn.autoHeight = function(){ - function autoHeight(elem){ - elem.style.height = 'auto'; - elem.style.maxHeight = '140px'; - elem.scrollTop = 0; //防抖动 - elem.style.height = elem.scrollHeight + 'px'; - } - this.each(function(){ - autoHeight(this); - $(this).on('keyup', function(){ - autoHeight(this); - }); - }); - } - $('textarea[autoHeight]').autoHeight(); - } - submitarbitrationevaluation=()=>{ - let{evaluationlist,shixunfilepath,shixunfilepathplay,shixunfileexpectpicturepath,shixunfilestandardpicturepath,shixunfilepicturepath,pathoptionvalue,scorevalue,markvalue}=this.state; - - - let newscorevalue; - if(scorevalue===false){ - newscorevalue=false - }else{ - //判断占比 - newscorevalue=true - - let sum=0; - for(var i=0; i100){ - this.props.showSnackbar("测试集的评分占比不能大于100"); - this.setState({ - scoretype:i - }) - return - } - sum=sum+evaluationlist[i].score - } - - if(sum>100||sum<100){ - this.props.showSnackbar("测试集的评分占比之和必须等于100"); - return - } - - - } - if(shixunfilepath===undefined||shixunfilepath===""||shixunfilepath===null){ - this.props.showSnackbar("学员任务文件路径为空"); - this.setState({ - StudentTaskPapers:true - }) - $('html').animate({ - scrollTop: 120 - }, 1000); - return - } - - if(shixunfilepathplay===undefined||shixunfilepathplay===""||shixunfilepathplay===null){ - this.props.showSnackbar("评测执行文件路径为空"); - this.setState({ - StudentTaskDocs:true - }) - $('html').animate({ - scrollTop: 130 - }, 1000); - return - } - - if(evaluationlist.length===0){ - this.props.showSnackbar("测试集不能为空"); - return - } - let id = this.props.match.params.shixunId; - let{checkpointId}=this.state; - let url = "/shixuns/"+id+"/challenges/"+checkpointId+".json"; - axios.put(url,{ - tab:1, - challenge:{ - path:shixunfilepath, - exec_path:shixunfilepathplay, - show_type:pathoptionvalue, - original_picture_path:shixunfileexpectpicturepath, - expect_picture_path:shixunfilestandardpicturepath, - picture_path:shixunfilepicturepath, - test_set_score:newscorevalue, - test_set_average:markvalue - }, - test_set:evaluationlist - } - ).then((response) => { - this.props.showSnackbar(response.data.messages); - // if(response.data.status===1){ - // window.location.href = "/shixuns/" + id + "/challenges/"+response.data.challenge_id+"/tab=3" - // } - }).catch((error) => { - console.log(error) - }); - } - handpathoptionvalues=()=>{ - this.setState({ - handpathopt:true - }) - } - handpathoptionvaluess=()=>{ - this.setState({ - handpathopt:false - }) - } - saveselectpath=(e)=>{ - - this.setState({ - selectpath:e.target.value - }) - } - updatepath=(e,name)=>{ - this.setState({ - [name]:e.target.value - }) - } - - - oneditevaluationlist=(newevaluationlist,markvalue)=>{ - - if(markvalue===true){ - if(100%newevaluationlist.length===0){ - let sum=100/newevaluationlist.length; - for(var i=0; i{ - - let {markvalue,evaluationlist}=this.state; - let newevaluationlist=evaluationlist; - - if(e.target.value===true){ - newevaluationlist=this.oneditevaluationlist(newevaluationlist,markvalue) - } - - this.setState({ - scorevalue: e.target.value, - evaluationlist:newevaluationlist - }); - - this.setevaluationlist(newevaluationlist); - } - - //均匀比例 - onChangemarkvalue=(e)=>{ - let {evaluationlist}=this.state; - - if(e.target.value===true){ - let newevaluationlist=evaluationlist; - newevaluationlist=this.oneditevaluationlist(newevaluationlist,e.target.value); - this.setevaluationlist(newevaluationlist); - } - - this.setState({ - markvalue: e.target.value, - }); - - } - render() { - - let { - choice_url, - practice_url, - go_back_url, - position, - evaluationlist, - shixunId, - checkpointId, - power, - shixunfileexpectpicturepath, - shixunfilestandardpicturepath, - shixunfilepicturepath, - shixunfilepath, - evaluationvisible, - trees, - path, - main, - selectpath, - shixunfilepathplay, - pathoptionvalue, - showrepositoryurltiptype, - prev_challenge, - next_challenge, - StudentTaskPapers, - StudentTaskDocs, - handpathopt, - scorevalue, - markvalue, - scoretype - } = this.state; - - let tab1url="/shixuns/" + shixunId + "/challenges/"+checkpointId+"/editcheckpoint"; - let tab2url="/shixuns/" + shixunId + "/challenges/"+checkpointId+"/tab=2"; - let tab3url="/shixuns/" + shixunId + "/challenges/"+checkpointId+"/tab=3"; - // console.log(this.props) - const radioStyle = { - display: 'block', - height: '30px', - lineHeight: '30px', - marginLeft: '20px', - }; - return ( - -
-
+ } + + } + + return newevaluationlist + } + //选择得分规范 + onChangeRadioGroups=(e)=>{ + + let {markvalue,evaluationlist}=this.state; + let newevaluationlist=evaluationlist; + + if(e.target.value===true){ + newevaluationlist=this.oneditevaluationlist(newevaluationlist,markvalue) + } + + this.setState({ + scorevalue: e.target.value, + evaluationlist:newevaluationlist + }); + + this.setevaluationlist(newevaluationlist); + } + + //均匀比例 + onChangemarkvalue=(e)=>{ + let {evaluationlist}=this.state; + + if(e.target.value===true){ + let newevaluationlist=evaluationlist; + newevaluationlist=this.oneditevaluationlist(newevaluationlist,e.target.value); + this.setevaluationlist(newevaluationlist); + } + + this.setState({ + markvalue: e.target.value, + }); + + } + render() { + + let { + choice_url, + practice_url, + go_back_url, + position, + evaluationlist, + shixunId, + checkpointId, + power, + shixunfileexpectpicturepath, + shixunfilestandardpicturepath, + shixunfilepicturepath, + shixunfilepath, + evaluationvisible, + trees, + path, + main, + selectpath, + shixunfilepathplay, + pathoptionvalue, + showrepositoryurltiptype, + prev_challenge, + next_challenge, + StudentTaskPapers, + StudentTaskDocs, + handpathopt, + scorevalue, + markvalue, + scoretype + } = this.state; + + let tab1url="/shixuns/" + shixunId + "/challenges/"+checkpointId+"/editcheckpoint"; + let tab2url="/shixuns/" + shixunId + "/challenges/"+checkpointId+"/tab=2"; + let tab3url="/shixuns/" + shixunId + "/challenges/"+checkpointId+"/tab=3"; + // console.log(this.props) + const radioStyle = { + display: 'block', + height: '30px', + lineHeight: '30px', + marginLeft: '20px', + }; + return ( + +
+
- 第{position}关 - 返回 - - {prev_challenge === undefined ? "" : - 上一关 - } - - {next_challenge === undefined ? "" : - 下一关 - } - - 4||this.props.identity===undefined||this.props.status===2||this.props.status===1? "none":'block'}} - data-tip-down="新增代码编辑类型的任务">+ 实践类型 - 4||this.props.identity===undefined||this.props.status===2||this.props.status===1?"none":'block'}} - data-tip-down="新增选择题类型的任务">+ 选择题类型 - -
- -
- -
  • - 本关任务 -
  • - -
  • - 评测设置 -
  • - -
  • - 参考答案 -
  • -
    - -

    - 请先上传本关任务的所有代码文件、标准图片等所有必要的文件到 - 版本库 -

    - - -
    -
    -

    学员任务文件

    -
    - * -
    - this.updatepath(e,"shixunfilepath")} - onClick={(e)=>this.getfilepath(e,"shixunfilepath")} - /> -

    该文件将直接显示给学生,需要学生在其中填写代码

    -
    -
    + 第{position}关 + 返回 + + {prev_challenge === undefined ? "" : + 上一关 + } + + {next_challenge === undefined ? "" : + 下一关 + } + + 4||this.props.identity===undefined||this.props.status===2||this.props.status===1? "none":'block'}} + data-tip-down="新增代码编辑类型的任务">+ 实践类型 + 4||this.props.identity===undefined||this.props.status===2||this.props.status===1?"none":'block'}} + data-tip-down="新增选择题类型的任务">+ 选择题类型 + +
    + +
    + +
  • + 本关任务 +
  • + +
  • + 评测设置 +
  • + +
  • + 参考答案 +
  • +
    + +

    + 请先上传本关任务的所有代码文件、标准图片等所有必要的文件到 + 版本库 +

    + + +
    +
    +

    学员任务文件

    +
    + * +
    + this.updatepath(e,"shixunfilepath")} + onClick={(e)=>this.getfilepath(e,"shixunfilepath")} + /> +

    该文件将直接显示给学生,需要学生在其中填写代码

    +
    +
    必填项 -
    -
    -
    -
    - -
    -
    - -
    - - this.saveselectpath(e)} - value={selectpath}/> -
    - - this.evaluationenter()}>确定 - this.evaluationhideModal()}>取消 -
    -
    -
    - -
    -
    -

    评测执行文件

    -
    - * -
    - this.updatepath(e,"shixunfilepathplay")} - onClick={(e)=>this.getfilepath(e,"shixunfilepathplay")} - /> -

    该文件由平台执行,用来测试平台学员代码是否正确

    -
    -
    + className="fa fa-exclamation-circle mr3">必填项 +
    +
    +
    +
    + +
    +
    + +
    + + this.saveselectpath(e)} + value={selectpath}/> +
    + + this.evaluationenter()}>确定 + this.evaluationhideModal()}>取消 +
    +
    +
    + +
    +
    +

    评测执行文件

    +
    + * +
    + this.updatepath(e,"shixunfilepathplay")} + onClick={(e)=>this.getfilepath(e,"shixunfilepathplay")} + /> +

    该文件由平台执行,用来测试平台学员代码是否正确

    +
    +
    必填项 -
    -
    -
    -
    - - -
    -
    -

    效果展现方式

    -
    - - this.showrepositoryurltip(1)}> -
    - -
    -

    - 图片:处理或输出图片类型的任务,请选填此项
    - 可以通过设置图片路径和学员答案文件路径,展示代码对应的图片效果

    - apk/exe:写可执行文件的任务,请选填此项
    - 可以通过设置学员答案文件路径,展示二维码以供扫码下载

    - txt:输出txt文档类型的任务,请选填此项
    - 可以通过学员答案文件路径设置,展示txt文件内容

    - html:web类型的任务,请选填此项
    - 可以通过Web路由设置,展示html效果预览页 -

    -

    this.showrepositoryurltip(2)} - >知道了 -

    -
    -
    -

    该选项用来配置学员评测本关任务时,查看效果页上需要展现的文件类型

    -
    -
    - - - {pathoptionvalue===1?
    -
    -

    待处理图片路径

    -
    -
    - this.updatepath(e,"shixunfileexpectpicturepath")} - onClick={(e)=>this.getfilepath(e,"shixunfileexpectpicturepath")} - /> -

    - 该路径下的文件将在学员评测本关任务时,作为原始图片显示在查看效果页,供学员参考,任务为图片处理时请指定该路径,并注意与程序文件所在文件夹分开 -

    -
    -
    -
    -
    -
    :""} - - - {pathoptionvalue===1?
    -
    -

    标准答案图片路径

    -
    -
    - this.updatepath(e,"shixunfilestandardpicturepath")} - onClick={(e)=>this.getfilepath(e,"shixunfilestandardpicturepath")} - /> -

    - 该路径下的文件将在学员评测本关任务时,作为参考答案显示在查看效果页,供学员参考任务输出结果为文件时请指定该路径,并注意与程序文件所在文件夹分开 -

    -
    -
    -
    -
    -
    :""} - - - {pathoptionvalue===-1?"":
    -
    -

    学员答案文件路径

    -
    -
    - this.updatepath(e,"shixunfilepicturepath")} - onClick={(e)=>this.getfilepath(e,"shixunfilepicturepath")} - placeholder="请在版本库中指定用来保存学员代码实际输出结果的路径。例:src/step1/outputimages"/> -

    - 学员评测本关任务时生成的文件将保存在该路径下,并作为实际输出显示在查看效果页,供学员确认任务输出结果为文件时请指定该路径,并注意与程序文件所在文件夹分开 -

    -
    -
    -
    -
    -
    } - - -
    -
    - {/*

    测试集

    */} -

    测试集和系统评分规则

    -

    - 得分规范: - - - 通过全部测试集 - (学员评测,仅当所有测试集都正确时,才获得一次性奖励) - - - 通过部分测试集 - (学员评测,当至少有一组测试集正确时,即可获得其对应比例的奖励) - -

    - -

    + className="fa fa-exclamation-circle mr3">必填项 +

    +
    +
    +
    + + +
    +
    +

    效果展现方式

    +
    + + this.showrepositoryurltip(1)}> +
    + +
    +

    + 图片:处理或输出图片类型的任务,请选填此项
    + 可以通过设置图片路径和学员答案文件路径,展示代码对应的图片效果

    + apk/exe:写可执行文件的任务,请选填此项
    + 可以通过设置学员答案文件路径,展示二维码以供扫码下载

    + txt:输出txt文档类型的任务,请选填此项
    + 可以通过学员答案文件路径设置,展示txt文件内容

    + html:web类型的任务,请选填此项
    + 可以通过Web路由设置,展示html效果预览页 +

    +

    this.showrepositoryurltip(2)} + >知道了 +

    +
    +
    +

    该选项用来配置学员评测本关任务时,查看效果页上需要展现的文件类型

    +
    +
    + + + {pathoptionvalue===1?
    +
    +

    待处理图片路径

    +
    +
    + this.updatepath(e,"shixunfileexpectpicturepath")} + onClick={(e)=>this.getfilepath(e,"shixunfileexpectpicturepath")} + /> +

    + 该路径下的文件将在学员评测本关任务时,作为原始图片显示在查看效果页,供学员参考,任务为图片处理时请指定该路径,并注意与程序文件所在文件夹分开 +

    +
    +
    +
    +
    +
    :""} + + + {pathoptionvalue===1?
    +
    +

    标准答案图片路径

    +
    +
    + this.updatepath(e,"shixunfilestandardpicturepath")} + onClick={(e)=>this.getfilepath(e,"shixunfilestandardpicturepath")} + /> +

    + 该路径下的文件将在学员评测本关任务时,作为参考答案显示在查看效果页,供学员参考任务输出结果为文件时请指定该路径,并注意与程序文件所在文件夹分开 +

    +
    +
    +
    +
    +
    :""} + + + {pathoptionvalue===-1?"":
    +
    +

    学员答案文件路径

    +
    +
    + this.updatepath(e,"shixunfilepicturepath")} + onClick={(e)=>this.getfilepath(e,"shixunfilepicturepath")} + placeholder="请在版本库中指定用来保存学员代码实际输出结果的路径。例:src/step1/outputimages"/> +

    + 学员评测本关任务时生成的文件将保存在该路径下,并作为实际输出显示在查看效果页,供学员确认任务输出结果为文件时请指定该路径,并注意与程序文件所在文件夹分开 +

    +
    +
    +
    +
    +
    } + + +
    +
    + {/*

    测试集

    */} +

    测试集和系统评分规则

    +

    + 得分规范: + + + 通过全部测试集 + (学员评测,仅当所有测试集都正确时,才获得一次性奖励) + + + 通过部分测试集 + (学员评测,当至少有一组测试集正确时,即可获得其对应比例的奖励) + +

    + +

    系统评分占比: + value={markvalue} + onChange={this.onChangemarkvalue} + > 均分比例 自定义比例 -

    +

    -
    -
    +
    +
    -
    +
    - {evaluationlist===undefined?"":evaluationlist.length===0?"":evaluationlist.map((item,key)=>{ - return( -
    -

    - * - 组{key+1} - + {evaluationlist===undefined?"":evaluationlist.length===0?"":evaluationlist.map((item,key)=>{ + return( +

    +

    + * + 组{key+1} + {/*checked={item.is_public===1?false:true}*/} - this.editpercentage(e,key)} - value={item.score} /> + this.editpercentage(e,key)} + value={item.score} /> % + style={{display:scorevalue===true?'inline-block':'none'}} + >% this.evaluationonChange(item.hidden,key)} checked={item.hidden===1?true:false}>隐藏 - - this.del_test_array(key)}> - - - -

    - - -
    - ) - })} - -
    -
    - -

    - - 新增测试集 - -

    -

    温馨提示:建议公开测试集和隐藏测试集结合使用,降低作弊的几率;隐藏测试集,在“提交评测”时也将被自动检测

    -
    -
    -
    - - -
    4||this.props.identity===undefined||power===false?"none":"block"}}> - 提交 - 取消 -
    - - -
    - - ) - } + + this.del_test_array(key)}> + + + +

    + + +
    + ) + })} + +
    +
    + +

    + + 新增测试集 + +

    +

    温馨提示:建议公开测试集和隐藏测试集结合使用,降低作弊的几率;隐藏测试集,在“提交评测”时也将被自动检测

    +
    +
    +
    + + +
    4||this.props.identity===undefined||power===false?"none":"block"}}> + 提交 + 取消 +
    + + +
    +
    + ) + } } diff --git a/public/react/src/modules/tpm/challengesnew/TpmQuestionMain.js b/public/react/src/modules/tpm/challengesnew/TpmQuestionMain.js index 2de04f56a..614842ab8 100644 --- a/public/react/src/modules/tpm/challengesnew/TpmQuestionMain.js +++ b/public/react/src/modules/tpm/challengesnew/TpmQuestionMain.js @@ -51,7 +51,7 @@ export default class TpmQuestionMain extends Component { *
    + watch={true} className="courseMessageMD" initValue={this.props.contentMdRefval} height={700}>
    this.Clickteacher("teacher")}>{gouxuans ==="teacher"? :}老师
    -
    +
    this.Clickteacher("teacher")} src={skzbdx} className="ysldivhomedivimg"/>
    this.Clickteacher("student")}>{gouxuans==="student"? :}学生
    -
    +
    this.Clickteacher("student")} src={mytc} className="ysldivhomedivimg"/>
    this.Clickteacher("professional")}>{gouxuans==="professional"?:}专业人士
    -
    +
    this.Clickteacher("professional")} src={zyrs1} className="ysldivhomedivimg"/>

    选择你可能感兴趣的内容

    diff --git a/public/react/src/modules/user/InterestpageMax.js b/public/react/src/modules/user/InterestpageMax.js index 82b3e7e0f..e0585ed33 100644 --- a/public/react/src/modules/user/InterestpageMax.js +++ b/public/react/src/modules/user/InterestpageMax.js @@ -71,7 +71,23 @@ class InterestpageMax extends Component { }if(response.data.repertoires[i].id===9){ qdkfys=rgzn; } - var datas={id:response.data.repertoires[i].id,name:response.data.repertoires[i].name,bool:false,url:qdkfys}; + + if(response.data.repertoires[i].id===1) { + var datas = { + id: response.data.repertoires[i].id, + name: response.data.repertoires[i].name, + bool: true, + url: qdkfys + }; + } else{ + var datas = { + id: response.data.repertoires[i].id, + name: response.data.repertoires[i].name, + bool: false, + url: qdkfys + }; + } + gouxuans4.push(datas); this.setState({ gouxuans4:gouxuans4, @@ -166,8 +182,12 @@ class InterestpageMax extends Component { //兴趣页面点击 Interestcompletionpage(){ + + this.setState({ + setpagecomplet:true + }) if(this.state.gouxuans.length === 0){ - this.openNotification("请选择您的职业"); + this.openNotification("请选择职业"); return } @@ -178,7 +198,7 @@ class InterestpageMax extends Component { } } if(ints.length<1){ - this.openNotification("内容是最少得选一个"); + this.openNotification("请至少选择一个您感兴趣的内容"); return } var url = "/users/interest.json"; @@ -189,12 +209,9 @@ class InterestpageMax extends Component { if (response !== undefined) { // this.Jumptotheinterestpage(); // window.location.href = "/" - - if(response.data.message!==undefined){ - - return; + if(response.data.status===0){ + this.setMyEduCoderModals() } - this.setMyEduCoderModals() } @@ -260,15 +277,15 @@ class InterestpageMax extends Component {
    this.Clickteacher("teacher")}>{gouxuans ==="teacher"? :}老师
    -
    +
    this.Clickteacher("teacher")} src={skzbdx} className="ysldivhomedivimg2"/>
    this.Clickteacher("student")}>{gouxuans==="student"? :}学生
    -
    +
    this.Clickteacher("student")} src={mytc} className="ysldivhomedivimg2"/>
    this.Clickteacher("professional")}>{gouxuans==="professional"?:}专业人士
    -
    +
    this.Clickteacher("professional")} src={zyrs1} className="ysldivhomedivimg2"/>
    选择你可能感兴趣的内容
    @@ -285,7 +302,7 @@ class InterestpageMax extends Component { ) })}
    - +
    diff --git a/public/react/src/modules/user/common.css b/public/react/src/modules/user/common.css index b80677ee5..d23412d07 100644 --- a/public/react/src/modules/user/common.css +++ b/public/react/src/modules/user/common.css @@ -70,7 +70,7 @@ margin-right: 129px; } .ysldivhome2{ - width: 100%; + width: 800px; display: flex; flex-flow: row wrap; align-content:stretch; diff --git a/public/react/src/modules/user/commontwo.css b/public/react/src/modules/user/commontwo.css index 718139f36..d25b888c8 100644 --- a/public/react/src/modules/user/commontwo.css +++ b/public/react/src/modules/user/commontwo.css @@ -71,6 +71,7 @@ margin-top: 10px; } .ysldivhome22{ + width: 800px; display: flex; flex-flow: row wrap; align-content:stretch; diff --git a/public/stylesheets/educoder/edu-all.css b/public/stylesheets/educoder/edu-all.css index 50c5af396..4006fb615 100644 --- a/public/stylesheets/educoder/edu-all.css +++ b/public/stylesheets/educoder/edu-all.css @@ -173,7 +173,9 @@ em.vertical-line{display: inline-block;width: 2px;background: #999;height: 10px} #log_reg_content{border-radius: 5px;background: #FFFFff;width: 100%;text-align: center;position: absolute;top: 165px; left: 0px;padding: 40px 30px;box-sizing: border-box} .log_nav{border-bottom:1px solid #eaeaea;} -.log_nav li{float: left;text-align: center;font-size: 16px;padding-bottom:15px;margin: 0px 20px;cursor: pointer;} +.log_nav li{float: left;text-align: center;font-size: 16px;padding-bottom:15px; + /*margin: 0px 20px;*/ + cursor: pointer;} .log_nav li.active{border-bottom: 2px solid #459be5;} .log-botton{width: 100%;text-align: center;color: #FFFFff!important;display: block;background: #cbcbcb;height: 45px;line-height: 45px;border-radius: 4px;letter-spacing: 2px;cursor: pointer} .log-botton:hover{color: #FFFFff!important;}