Merge branches 'dev_jupyter' and 'develop' of https://bdgit.educoder.net/Hjqreturn/educoder into develop

dev_static
杨树明 5 years ago
commit ad6bb63f71

@ -6,10 +6,10 @@ class Admins::BaseController < ApplicationController
layout 'admin'
skip_before_action :verify_authenticity_token
before_action :require_login, :require_admin!
after_action :rebind_event_if_ajax_render_partial
skip_before_action :check_sign
private

@ -5,9 +5,10 @@ class Admins::ShixunSettingsController < Admins::BaseController
shixun_settings = Admins::ShixunSettingsQuery.call(params)
@editing_shixuns = shixun_settings.where(status:0).size
@pending_shixuns = shixun_settings.where(status:1).size
@processed_shixuns = shixun_settings.where(status:2).size
@processed_shixuns = shixun_settings.where(status:2, public: 0).size
@closed_shixuns = shixun_settings.where(status:3).size
@pending_public_shixuns = shixun_settings.where(public:1).size
@processed_pubic_shixuns = shixun_settings.where(public:2).size
@sort_json = {
can_copy: params[:can_copy].present? ? params[:can_copy] : false,
@ -83,9 +84,9 @@ class Admins::ShixunSettingsController < Admins::BaseController
sheet1[count_row, 6] = shixun.myshixuns_count
sheet1[count_row, 7] = shixun.myshixuns.select{|m| m.status == 1}.size
sheet1[count_row, 8] = shixun.shixun_status
sheet1[count_row, 9] = shixun.user.show_real_name
sheet1[count_row, 10] = shixun.user.school_name
sheet1[count_row, 11] = shixun.user.identity
sheet1[count_row, 9] = shixun.user&.show_real_name
sheet1[count_row, 10] = shixun.user&.school_name
sheet1[count_row, 11] = shixun.user&.identity
shixun.challenges.each do |challenge|
sheet1[count_row, 12] = "#{challenge.position}"
sheet1[count_row, 13] = challenge.subject
@ -112,13 +113,16 @@ class Admins::ShixunSettingsController < Admins::BaseController
sheet1[count_row, 2] = shixun.mirror_repositories.select{|mr| mr.main_type == "1"}.first&.type_name
sheet1[count_row, 3] = shixun.fork_from
sheet1[count_row, 4] = shixun.shixun_status
sheet1[count_row, 5] = shixun.user.show_real_name
sheet1[count_row, 6] = shixun.user.school_name
sheet1[count_row, 7] = shixun.user.identity
shixun.challenges.each do |challenge|
sheet1[count_row, 5] = shixun.user&.show_real_name
sheet1[count_row, 6] = shixun.user&.school_name
sheet1[count_row, 7] = shixun.user&.identity
challenge_count = shixun.challenges.count
shixun.challenges.each_with_index do |challenge, index|
sheet1[count_row, 8] = "#{challenge.position}"
sheet1[count_row, 9] = challenge.subject
count_row += 1
if index + 1 != challenge_count
count_row += 1
end
end
count_row += 1
end

@ -5,10 +5,8 @@ class Admins::ShixunsController < Admins::BaseController
params[:sort_direction] = params[:sort_direction].presence || 'desc'
shixuns = Admins::ShixunQuery.call(params)
@editing_shixuns = shixuns.where(status:0).size
@pending_shixuns = shixuns.where(status:1).size
@processed_shixuns = shixuns.where(status:2).size
@processed_shixuns = shixuns.where(status:2, public: 0).size
@closed_shixuns = shixuns.where(status:3).size
@none_public_shixuns = shixuns.where(public:0).size
@pending_public_shixuns = shixuns.where(public:1).size
@processed_pubic_shixuns = shixuns.where(public:2).size
@shixuns_type_check = MirrorRepository.pluck(:type_name,:id)

@ -61,7 +61,7 @@ class Admins::UsersController < Admins::BaseController
private
def update_params
params.require(:user).permit(%i[lastname nickname gender identity technical_title student_id
params.require(:user).permit(%i[lastname nickname gender identity technical_title student_id is_shixun_marker
mail phone location location_city school_id department_id admin business is_test
password professional_certification authentication])
end

@ -12,6 +12,7 @@ class ApplicationController < ActionController::Base
protect_from_forgery prepend: true, unless: -> { request.format.json? }
before_action :check_sign
before_action :user_setup
#before_action :check_account
@ -20,12 +21,37 @@ class ApplicationController < ActionController::Base
helper_method :current_user
# 所有请求必须合法签名
def check_sign
Rails.logger.info("66666 #{params}")
suffix = request.url.split(".").last.split("?").first
suffix_arr = ["xls", "xlsx", "pdf"] # excel文件先注释
unless suffix_arr.include?(suffix)
if params[:client_key].present?
randomcode = params[:randomcode]
# tip_exception(501, "请求不合理") unless (Time.now.to_i - randomcode.to_i).between?(0,5)
sign = Digest::MD5.hexdigest("#{OPENKEY}#{randomcode}")
Rails.logger.info("2222 #{sign}")
tip_exception(501, "请求不合理") if sign != params[:client_key]
else
tip_exception(501, "请求不合理")
end
end
end
# 全局配置参数
# 返回name对应的value
def edu_setting(name)
EduSetting.get(name)
end
def shixun_marker
unless current_user.is_shixun_marker? || current_user.admin_or_business?
tip_exception(403, "..")
end
end
# 实训的访问权限
def shixun_access_allowed
if !current_user.shixun_permission(@shixun)
@ -256,9 +282,10 @@ class ApplicationController < ActionController::Base
end
def user_setup
# reacct静态资源加载不需要走这一步
# # reacct静态资源加载不需要走这一步
return if params[:controller] == "main"
# Find the current user
#Rails.logger.info("current_laboratory is #{current_laboratory} domain is #{request.subdomain}")
User.current = find_current_user
uid_logger("user_setup: " + (User.current.logged? ? "#{User.current.try(:login)} (id=#{User.current.try(:id)})" : "anonymous"))
@ -400,7 +427,7 @@ class ApplicationController < ActionController::Base
end
rescue Exception => e
uid_logger("--uri_exec: exception #{e.message}")
raise Educoder::TipException.new("实训平台繁忙繁忙等级84")
raise Educoder::TipException.new(message)
end
end
@ -603,7 +630,7 @@ class ApplicationController < ActionController::Base
end
def paginate(relation)
limit = params[:limit].to_i.zero? ? 20 : params[:limit].to_i
limit = (params[:limit].to_i.zero? || params[:limit].to_i > 20) ? 20 : params[:limit].to_i
page = params[:page].to_i.zero? ? 1 : params[:page].to_i
offset = (page - 1) * limit
@ -678,4 +705,5 @@ class ApplicationController < ActionController::Base
HotSearchKeyword.add(keyword)
end
end

@ -5,6 +5,7 @@ class AttachmentsController < ApplicationController
before_action :require_login, :check_auth, except: [:show]
before_action :find_file, only: %i[show destroy]
before_action :attachment_candown, only: [:show]
skip_before_action :check_sign, only: [:show, :create]
include ApplicationHelper

@ -22,7 +22,7 @@ class CommentsController < ApplicationController
@discuss = @hack.discusses.new(reply_params)
@discuss.hidden = false
@discuss.user_id = current_user.id
@discuss.root_id = params[:parent_id]
@discuss.root_id = params[:comments][:parent_id]
@discuss.save!
rescue Exception => e
uid_logger_error("reply discuss failed : #{e.message}")
@ -32,9 +32,14 @@ class CommentsController < ApplicationController
# 列表
def index
disscusses = @hack.disscusses.where(:root_id => nil)
@disscuss_count = disscusses.count
@disscusses= paginate disscusses
discusses =
if current_user.admin_or_business?
@hack.discusses.where(root_id: nil)
else
@hack.discusses.where(root_id: nil, hidden: false)
end
@discusses_count = discusses.count
@discusses= paginate discusses
end
# 删除
@ -43,10 +48,21 @@ class CommentsController < ApplicationController
render_ok
end
# 隐藏、取消隐藏
def hidden
if current_user.admin_or_business?
@discuss = @hack.discusses.where(id: params[:id]).first
@discuss.update_attribute(:hidden, params[:hidden].to_i == 1)
sucess_status
else
Educoder::TipException(403, "..")
end
end
private
def find_hack
@hack = Hack.find_by_identifier params[:identifier]
@hack = Hack.find_by_identifier(params[:hack_identifier])
end
def comment_params

@ -10,13 +10,14 @@ class Cooperative::BaseController < ApplicationController
before_action :laboratory_exist!, :require_login, :require_cooperative_manager!
after_action :rebind_event_if_ajax_render_partial
skip_before_action :check_sign
helper_method :current_laboratory, :current_setting_or_default
private
def current_laboratory
@_current_laboratory ||= Laboratory.find_by_subdomain(request.subdomain)
@_current_laboratory ||= (Laboratory.find_by_subdomain(request.subdomain) || Laboratory.first)
# @_current_laboratory ||= Laboratory.find 1
end

@ -1,4 +1,6 @@
class DepartmentsController < ApplicationController
skip_before_action :check_sign
def for_option
render_ok(departments: current_school.departments.without_deleted.select(:id, :name).as_json)
end

@ -14,14 +14,14 @@ class DiscussesController < ApplicationController
@disscuss_count = Discuss.where(:dis_id => @container.id, :dis_type => @container.class.to_s, :root_id => nil).count
disscusses = Discuss.where(:dis_id => @container.id, :dis_type => @container.class.to_s,
:root_id => nil)
@discusses = disscusses.limit(LIMIT).joins("left join games on discusses.challenge_id = games.challenge_id and discusses.user_id = games.user_id")
.select("discusses.*, games.identifier").includes(:user, :praise_treads).offset(offset)
@discusses = disscusses.joins("left join games on discusses.challenge_id = games.challenge_id and discusses.user_id = games.user_id")
.select("discusses.*, games.identifier").includes(:user, :praise_treads)
else
disscusses = Discuss.where("dis_id = :dis_id and dis_type = :dis_type and root_id is null and
(discusses.hidden = :hidden or discusses.user_id = :user_id)",
{dis_id: @container.id, dis_type: @container.class.to_s, hidden: false, user_id: current_user.id})
@disscuss_count = disscusses.count("discusses.id")
@discusses = disscusses.limit(LIMIT).includes(:user, :praise_treads).offset(offset)
@discusses = disscusses.includes(:user, :praise_treads).limit(LIMIT).offset(offset)
end
@current_user = current_user
@ -117,13 +117,13 @@ class DiscussesController < ApplicationController
# 0 取消赞;
def plus
pt = PraiseTread.where(:praise_tread_object_id => params[:id], :praise_tread_object_type => params[:container_type],
:user_id => current_user, :praise_or_tread => 1).first
:user_id => current_user, :praise_or_tread => 1)
# 如果当前用户已赞过,则不能重复赞
if params[:type] == 1 && pt.blank?
PraiseTread.create!(:praise_tread_object_id => params[:id], :praise_tread_object_type => params[:container_type],
:user_id => current_user.id, :praise_or_tread => 1) if pt.blank?
:user_id => current_user.id, :praise_or_tread => 1)
else
pt.destroy if pt.present? # 如果已赞过,则删掉这条赞(取消);如果没赞过,则为非法请求不处理
pt.destroy_all if pt.present? # 如果已赞过,则删掉这条赞(取消);如果没赞过,则为非法请求不处理
end
@praise_count = PraiseTread.where(:praise_tread_object_id => params[:id], :praise_tread_object_type => params[:container_type],

@ -1,7 +1,7 @@
class EduSettingsController < ApplicationController
before_action :require_admin
before_action :set_edu_setting, only: [:show, :edit, :update, :destroy]
skip_before_action :check_sign
# GET /edu_settings
# GET /edu_settings.json
def index

@ -10,9 +10,6 @@ class GamesController < ApplicationController
include GamesHelper
include ApplicationHelper
def show
uid_logger("--games show start")
# 防止评测中途ajaxE被取消;3改成0是为了处理首次进入下一关的问题
@ -91,7 +88,6 @@ class GamesController < ApplicationController
end
end
def jupyter
# Jupyter没有challenge
@myshixun = Myshixun.find_by_identifier params[:identifier]
@ -103,7 +99,7 @@ class GamesController < ApplicationController
begin
@tpm_modified = @myshixun.repository_is_modified(@shixun.repo_path) # 判断TPM和TPI的版本库是否被改了
rescue
uid_logger("实训平台繁忙繁忙等级81")
uid_logger("服务器出现问题,请重置刷新页面")
end
end

@ -1,5 +1,5 @@
class GitsController < ApplicationController
skip_before_action :check_sign
# 说明:
# 以下Git认证只针对新版gitGitlab的Git认证不走该控制器
# 思路:
@ -39,7 +39,7 @@ class GitsController < ApplicationController
# 用户是否对对象拥有权限
system_user = User.find_by_login(input_username) || User.find_by_mail(input_username) || User.find_by_phone(input_username)
# 如果用户名密码错误
if system_user && !system_user.check_password?(input_password)
if system_user.blank? || system_user && !system_user.check_password?(input_password)
uid_logger_error("git start: password is wrong")
result = false
else

@ -171,8 +171,8 @@ class GraduationTopicsController < ApplicationController
unless teacher_group.present?
member = @course.course_members.where(:user_id => @graduation_topic.tea_id).first
tip_exception("分班名称不能为空") if params[:course_group_name].blank?
course_group = CourseGroup.create(:name => params[:course_group_name], :course_id => @course.id)
teacher_group = TeacherCourseGroup.create(:course_id => @course.id, :course_member_id => member.try(:id),
course_group = CourseGroup.find_or_create_by!(:name => params[:course_group_name], :course_id => @course.id)
teacher_group = TeacherCourseGroup.find_or_create_by!(:course_id => @course.id, :course_member_id => member.try(:id),
:user_id => @graduation_topic.tea_id,
:course_group_id => course_group.try(:id))
end

@ -1,10 +1,10 @@
class HackUserLastestCodesController < ApplicationController
before_action :require_login, except: [:listen_result]
before_action :find_my_hack, only: [:show, :code_debug, :code_submit, :update_code, :sync_code,
before_action :find_my_hack, only: [:show, :code_debug, :code_submit, :update_code, :sync_code, :add_notes,
:listen_result, :result, :submit_records, :restore_initial_code]
before_action :update_user_hack_status, only: [:code_debug, :code_submit]
before_action :require_auth_identity, only: [:update_code, :restore_initial_code, :sync_code]
before_action :require_manager_identity, only: [:update_code]
before_action :require_auth_identity, only: [:add_notes]
before_action :require_manager_identity, only: [:show, :update_code, :restore_initial_code, :sync_code]
def show
@my_hack.update_attribute(:submit_status, 0) if @my_hack.submit_status == 1
@ -61,13 +61,18 @@ class HackUserLastestCodesController < ApplicationController
# 提交记录
def submit_records
@records = @my_hack.hack_user_codes.created_order
end
records = @my_hack.hack_user_codes
@records_count = records.count
@records = paginate records.created_order
end
# 提交记录详情
def record_detail
@hack_user = HackUserCode.find params[:id]
set = HackSet.find_by(id: @hack_user.error_test_set_id)
@pass_set_count = set ? set.position - 1 : 0
@set_count = @hack_user.hack.hack_sets.count
@my_hack = @hack_user.hack_user_lastest_code
end
@ -80,7 +85,7 @@ class HackUserLastestCodesController < ApplicationController
testCase = ojEvaResult['testCase']
# 只有编译出错时,才正则匹配错误行数
error_line=
if params[:status] == "-4"
if ojEvaResult['status'] == "4" || ojEvaResult['status'] == "5"
regular_match_error_line ojEvaResult['outPut'], @my_hack.hack.language
end
# debug 与submit 公用的参数
@ -94,7 +99,8 @@ class HackUserLastestCodesController < ApplicationController
if ojEvaResult['execMode'] == "debug"
save_debug_data ds_params
elsif ojEvaResult['execMode'] == "submit"
save_submit_data ds_params.merge(expected_output: testCase['expectedOutput'])
save_submit_data ds_params.merge(expected_output: testCase['expectedOutput'],
error_test_set_id: ojEvaResult['failCaseNum'])
end
# 评测完成后,还原评测中的状态
@my_hack.update_attribute(:submit_status, 0)
@ -106,6 +112,11 @@ class HackUserLastestCodesController < ApplicationController
end
def add_notes
@my_hack.update_attribute(:notes, params[:notes])
render_ok
end
private
def find_my_hack
@my_hack = HackUserLastestCode.find_by(identifier: params[:identifier])
@ -137,11 +148,12 @@ class HackUserLastestCodesController < ApplicationController
# 正则错误行数
def regular_match_error_line content, language
content = Base64.decode64(content).force_encoding("utf-8")
logger.info("######content: #{content}")
case language
when 'Java'
content.scan(/.java.\d+/).map{|s| s.match(/\d+/)[0].to_i}.min
when 'C', 'C++'
content.scan(/\d:\d+: error/).map{|s| s.match(/\d+/)[0]}.min
content.scan(/\d:\d+:/).map{|s| s.match(/\d+/)[0].to_i}.min
when 'Python'
content.scan(/line \d+/).map{|s| s.match(/\d+/)[0].to_i}.min
end
@ -163,12 +175,12 @@ class HackUserLastestCodesController < ApplicationController
# 通关
if submit_params[:status] == "0"
# 编程题已经发布,且之前未通关奖励积分
@hack.increment!(:pass_num)
if @hack.status == 1 && !@my_hack.passed?
reward_attrs = { container_id: game.id, container_type: 'Hack', score: @hack.score }
reward_attrs = { container_id: @hack.id, container_type: 'Hack', score: @hack.score }
RewardGradeService.call(@my_hack.user, reward_attrs)
RewardExperienceService.call(@my_hack.user, reward_attrs)
# 评测完成更新通过数
@hack.increment!(:pass_num)
@my_hack.update_attributes(passed: true, passed_time: Time.now)
end
end

@ -44,12 +44,13 @@ class HacksController < ApplicationController
begin
logger.info("##########{hack_params}")
hack = Hack.new(hack_params)
hack.user_id = current_user.id
hack.identifier = generate_identifier Hack, 8
ActiveRecord::Base.transaction do
hack.user_id = current_user.id
hack.identifier = generate_identifier Hack, 8
hack.save!
# 创建测试集与代码
hack.hack_sets.create!(hack_sets_params)
# 新建知识点
hack_codes = hack.hack_codes.new(hack_code_params)
hack_codes.modify_time = Time.now
hack_codes.save!
@ -98,12 +99,22 @@ class HacksController < ApplicationController
# 发布功能
def publish
@hack.update_attribute(:status, 1)
base_attrs = {
trigger_user_id: current_user.id, viewed: 0, tiding_type: 'System', user_id: @hack.user_id,
parent_container_type: "HackPublish", extra: @hack.identifier
}
@hack.tidings.create!(base_attrs)
render_ok
end
# 取消发布
def cancel_publish
@hack.update_attribute(:status, 0)
base_attrs = {
trigger_user_id: current_user.id, viewed: 0, tiding_type: 'System', user_id: @hack.user_id,
parent_container_type: "HackUnPublish", extra: @hack.identifier
}
@hack.tidings.create!(base_attrs)
render_ok
end
@ -121,8 +132,19 @@ class HacksController < ApplicationController
def new;end
def destroy
@hack.destroy
render_ok
begin
base_attrs = {
user_id: @hack.user_id, viewed: 0, tiding_type: 'System', trigger_user_id: current_user.id,
parent_container_type: "HackDelete", extra: "#{@hack.name}"
}
@hack.tidings.create!(base_attrs)
@hack.destroy
render_ok
rescue => e
logger.error("####hack_delete_error: #{e.message}")
render_error("删除失败")
end
end
private
@ -167,10 +189,13 @@ class HacksController < ApplicationController
def param_update_sets sets, all_sets_id
delete_set_ids = all_sets_id - sets.map{|set|set[:id]}
@hack.hack_sets.where(id: delete_set_ids).destroy_all
logger.info("#######sets:#{sets}")
sets.each do |set|
logger.info("###set[:id] #{set[:id]}")
logger.info("###all_sets #{all_sets_id.include?(set[:id])}")
if all_sets_id.include?(set[:id])
update_attrs = {input: set[:input], output: set[:output], position: set[:position]}
@hack.hack_sets.find_by!(id: set[:id]).update_attributes(update_attrs)
@hack.hack_sets.find_by!(id: set[:id]).update_attributes!(update_attrs)
end
end
end
@ -208,6 +233,11 @@ class HacksController < ApplicationController
hacks = hacks.where(category: params[:category])
end
# 语言
if params[:language]
hacks = hacks.joins(:hack_codes).where(hack_codes: {language: params[:language]})
end
# 排序
sort_by = params[:sort_by] || "hack_user_lastest_codes_count"
sort_direction = params[:sort_direction] || "desc"

@ -11,7 +11,7 @@ class HomeworkCommonsController < ApplicationController
before_action :find_homework, only: [:edit, :show, :update, :group_list, :homework_code_repeat, :code_review_results,
:code_review_detail, :show_comment, :settings, :works_list, :update_settings,
:reference_answer, :publish_groups, :end_groups, :alter_name, :update_explanation,
:update_score, :update_student_score]
:update_score, :update_student_score, :batch_comment]
before_action :user_course_identity
before_action :homework_publish, only: [:show, :works_list, :code_review_results, :show_comment, :settings, :reference_answer,
:update_student_score]
@ -19,7 +19,7 @@ class HomeworkCommonsController < ApplicationController
:publish_homework, :end_homework, :set_public, :choose_category, :move_to_category,
:choose_category, :create_subject_homework, :multi_destroy, :group_list, :homework_code_repeat,
:code_review_results, :code_review_detail, :update_explanation, :update_settings,
:add_to_homework_bank, :publish_groups, :end_groups]
:add_to_homework_bank, :publish_groups, :end_groups, :batch_comment]
before_action :require_id_params, only: [:set_public, :multi_destroy, :publish_homework, :end_homework, :move_to_category,
:add_to_homework_bank]
before_action :course_manager, only: [:alter_name]
@ -214,7 +214,7 @@ class HomeworkCommonsController < ApplicationController
limit = params[:limit] || 20
@student_works = @student_works.page(page).per(limit)
if @homework.homework_type == "practice"
@student_works = @student_works.includes(:student_works_scores, user: :user_extension, myshixun: :games)
@student_works = @student_works.includes(:student_works_scores, :shixun_work_comments, user: :user_extension, myshixun: :games)
else
@student_works = @student_works.includes(:student_works_scores, :project, user: :user_extension)
end
@ -453,105 +453,8 @@ class HomeworkCommonsController < ApplicationController
# 课堂结束后不能再更新
unless @course.is_end
# 发布设置
UpdateHomeworkPublishSettingService.call(@homework, publish_params)
# 作业未发布时unified_setting参数不能为空
=begin
if @homework.publish_time.nil? || @homework.publish_time > Time.now
tip_exception("缺少统一设置的参数") if params[:unified_setting].nil?
if params[:unified_setting] || @course.course_groups_count == 0
tip_exception("发布时间不能为空") if params[:publish_time].blank?
tip_exception("截止时间不能为空") if params[:end_time].blank?
tip_exception("发布时间不能早于当前时间") if params[:publish_time] <= Time.now.strftime("%Y-%m-%d %H:%M:%S")
tip_exception("截止时间不能早于当前时间") if params[:end_time] <= Time.now.strftime("%Y-%m-%d %H:%M:%S")
tip_exception("截止时间不能早于发布时间") if params[:publish_time] > params[:end_time]
tip_exception("截止时间不能晚于课堂结束时间(#{@course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")}") if
@course.end_date.present? && params[:end_time] > @course.end_date.end_of_day
@homework.unified_setting = 1
@homework.homework_group_settings.destroy_all
@homework.publish_time = params[:publish_time]
# 截止时间为空时取发布时间后一个月
@homework.end_time = params[:end_time]
else
tip_exception("分班发布设置不能为空") if params[:group_settings].blank?
# 创建作业的分班设置
create_homework_group_settings @homework
setting_group_ids = []
params[:group_settings].each do |setting|
tip_exception("分班id不能为空") if setting[:group_id].length == 0
tip_exception("发布时间不能为空") if setting[:publish_time].blank?
tip_exception("截止时间不能为空") if setting[:end_time].blank?
tip_exception("发布时间不能早于当前时间") if setting[:publish_time] <= strf_time(Time.now)
tip_exception("截止时间不能早于当前时间") if setting[:end_time] <= strf_time(Time.now)
tip_exception("截止时间不能早于发布时间") if setting[:publish_time] > setting[:end_time]
tip_exception("截止时间不能晚于课堂结束时间(#{@course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")}") if
@course.end_date.present? && setting[:end_time] > @course.end_date.end_of_day
publish_time = setting[:publish_time] == "" ? Time.now : setting[:publish_time]
# 截止时间为空时取发布时间后一个月
end_time = setting[:end_time]
HomeworkGroupSetting.where(homework_common_id: @homework.id, course_group_id: setting[:group_id]).
update_all(publish_time: publish_time, end_time: end_time)
setting_group_ids << setting[:group_id]
end
# 未设置的分班发布时间和截止时间都为nil
HomeworkGroupSetting.where.not(course_group_id: setting_group_ids).where(homework_common_id: @homework.id).
update_all(publish_time: nil, end_time: nil)
# 记录已发布需要发消息的分班
publish_group_ids = HomeworkGroupSetting.where(homework_common_id: @homework.id).group_published.pluck(:course_group_id)
@homework.unified_setting = 0
@homework.publish_time = @homework.min_group_publish_time
@homework.end_time = @homework.max_group_end_time
end
# 如果作业立即发布则更新状态、发消息
if @homework.publish_time <= Time.now and @homework_detail_manual.comment_status == 0
@homework_detail_manual.comment_status = 1
send_tiding = true
end
# 作业在"提交中"状态时
else
if @homework.end_time > Time.now && @homework.unified_setting
tip_exception("截止时间不能为空") if params[:end_time].blank?
tip_exception("截止时间不能早于当前时间") if params[:end_time] <= strf_time(Time.now)
tip_exception("截止时间不能晚于课堂结束时间(#{@course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")}") if
@course.end_date.present? && params[:end_time] > strf_time(@course.end_date.end_of_day)
@homework.end_time = params[:end_time]
elsif !@homework.unified_setting
create_homework_group_settings @homework
tip_exception("分班发布设置不能为空") if params[:group_settings].blank?
params[:group_settings].each do |setting|
group_settings = HomeworkGroupSetting.where(homework_common_id: @homework.id, course_group_id: setting[:group_id])
tip_exception("分班id不能为空") if setting[:group_id].length == 0
tip_exception("发布时间不能为空") if setting[:publish_time].blank?
tip_exception("截止时间不能为空") if setting[:end_time].blank?
# 如果该发布规则 没有已发布的分班则需判断发布时间
tip_exception("发布时间不能早于等于当前时间") if setting[:publish_time] <= strf_time(Time.now) && group_settings.group_published.count == 0
tip_exception("截止时间不能早于等于当前时间") if setting[:end_time] <= strf_time(Time.now) && group_settings.none_end.count > 0
tip_exception("截止时间不能早于发布时间") if setting[:publish_time] > setting[:end_time]
tip_exception("截止时间不能晚于课堂结束时间(#{@course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")}") if
@course.end_date.present? && setting[:end_time] > strf_time(@course.end_date.end_of_day)
group_settings.none_published.update_all(publish_time: setting[:publish_time])
group_settings.none_end.update_all(end_time: setting[:end_time])
end
@homework.end_time = @homework.max_group_end_time
end
end
=end
# 补交设置
tip_exception("缺少allow_late参数") if params[:allow_late].nil?
@ -880,69 +783,6 @@ class HomeworkCommonsController < ApplicationController
## 分页参数
page = params[:page] || 1
@shixuns = @shixuns.reorder("shixuns.created_at desc").includes(:challenges, user: [user_extension: :school]).page(page).per(10)
# 新版用下面的代码
# ## 我的实训
# @shixuns =
# if params[:order_by] == 'mine'
# current_user.my_shixuns.unhidden
# else
# if current_user.admin?
# Shixun.unhidden
# else
# none_shixun_ids = ShixunSchool.where("school_id != #{current_user.school_id}").pluck(:shixun_id)
#
# @shixuns = Shixun.where.not(id: none_shixun_ids).unhidden
# end
# end
#
# ## 方向
# if params[:tag_level].present? && params[:tag_id].present?
# @shixuns = @shixuns.filter_tag(params[:tag_level].to_i, params[:tag_id].to_i)
# case params[:tag_level].to_i
# when 1 #大类
# @search_tags = Repertoire.find(params[:tag_id].to_i).name
# when 2 #子类
# @search_tags = SubRepertoire.find(params[:tag_id].to_i).name
# when 3 #tag
# tag = TagRepertoire.find(params[:tag_id].to_i)
# @search_tags = "#{tag.sub_repertoire.name} / #{tag.name}"
# end
# end
#
# ## 搜索关键字创建者、实训名称、院校名称
# if params[:keyword].present?
# keyword = params[:keyword].strip
# @shixuns = @shixuns.joins(user: [user_extenison: :school]).
# where("schools.name like '%#{keyword}%'
# or concat(lastname, firstname) like '%#{keyword}%'
# or shixuns.name like '%#{keyword.split(" ").join("%")}%'").distinct
# end
#
# ## 筛选 难度
# if params[:diff].present? && params[:diff].to_i != 0
# @shixuns = @shixuns.where(trainee: params[:diff])
# end
#
# ## 排序参数
# bsort = params[:sort] || 'desc'
# case params[:order_by] || 'hot'
# when 'hot'
# @shixuns = @shixuns.order("myshixuns_count #{bsort}")
# when 'mine'
# @shixuns = @shixuns.order("shixuns.created_at #{bsort}")
# else
# @shixuns = @shixuns.order("myshixuns_count #{bsort}")
# end
#
# @total_count = @shixuns.count
#
# ## 分页参数
# page = params[:page] || 1
# limit = params[:limit] || 15
#
# @shixuns = @shixuns.includes(:challenges, user: [user_extension: :school]).page(page).per(limit)
#
end
def create_shixun_homework
@ -1046,7 +886,7 @@ class HomeworkCommonsController < ApplicationController
course_module_id: course_module.id, position: course_module.course_second_categories.count + 1)
# 去掉不对当前用户的单位公开的实训,已发布的实训
stage.shixuns.where.not(shixuns: {id: none_shixun_ids}).unhidden.each do |shixun|
stage.shixuns.no_jupyter.where.not(shixuns: {id: none_shixun_ids}).unhidden.each do |shixun|
homework = HomeworksService.new.create_homework shixun, @course, category, current_user
@homework_ids << homework.id
CreateStudentWorkJob.perform_later(homework.id)
@ -1248,31 +1088,6 @@ class HomeworkCommonsController < ApplicationController
# homework_challenge_settings = homework.homework_challenge_settings
unless student_works.blank?
student_works.joins(:myshixun).where("myshixuns.status != 1").update_all(late_penalty: homework.late_penalty) if homework.allow_late
=begin
student_works.where("work_status != 0").includes(:myshixun).each do |student_work|
unless student_work.myshixun.is_complete?
student_work.update_attributes(work_status: 2, late_penalty: homework.late_penalty)
student_work.late_penalty = homework.late_penalty
end
HomeworksService.new.set_shixun_final_score student_work, student_work.myshixun, homework_detail_manual.answer_open_evaluation,
homework_challenge_settings
end
student_works.where("work_status = 0").each do |student_work|
myshixun = Myshixun.where(shixun_id: shixun.id, user_id: student_work.user_id).first
if myshixun.present?
student_work.update_attributes(work_status: (myshixun.is_complete? ? 1 : 2),
late_penalty: myshixun.is_complete? ? 0 : homework.late_penalty,
commit_time: myshixun.created_at, myshixun_id: myshixun.id)
student_work.late_penalty = myshixun.is_complete? ? 0 : homework.late_penalty
HomeworksService.new.set_shixun_final_score student_work, myshixun, homework_detail_manual.answer_open_evaluation,
homework_challenge_settings
end
end
=end
# 更新所有学生的效率分(重新取homework确保是更新后的)
end
end
homework.save!
@ -1558,6 +1373,21 @@ class HomeworkCommonsController < ApplicationController
end
def batch_comment
tip_exception(-1, "作业还未发布,不能评阅") if @homework_detail_manual.comment_status == 0
tip_exception("请至少输入一个评阅") if params[:comment].blank? && params[:hidden_comment].blank?
ActiveRecord::Base.transaction do
work_ids = @homework.student_works.where(work_status: [1, 2], user_id: @course.teacher_group_user_ids(current_user.id)).pluck(:id)
has_comment_ids = ShixunWorkComment.where(challenge_id: 0, student_work_id: work_ids, batch_comment: 0).pluck(:student_work_id)
batch_comment_works = ShixunWorkComment.where(challenge_id: 0, student_work_id: work_ids, batch_comment: 1)
batch_comment_works.update_all(comment: params[:comment], hidden_comment: params[:hidden_comment])
work_ids = work_ids - has_comment_ids - batch_comment_works.pluck(:student_work_id)
# @homework.student_works.where(work_status: 0, id: work_ids).update_all(work_status: 1, commit_time: @homework.end_time, update_time: Time.now, work_score: 0, final_score: 0)
HomeworkBatchCommentJob.perform_later(params[:comment], params[:hidden_comment], work_ids, @homework.id, current_user.id)
normal_status("评阅成功")
end
end
private
def find_homework

@ -1,4 +1,10 @@
class MainController < ApplicationController
skip_before_action :check_sign
def first_stamp
render :json => { status: 0, message: Time.now.to_i }
end
def index
render file: 'public/react/build/index.html', :layout => false
end

@ -3,6 +3,7 @@ class MyshixunsController < ApplicationController
before_action :find_myshixun, :except => [:training_task_status, :code_runinng_message]
before_action :find_repo_name, :except => [:training_task_status, :code_runinng_message]
skip_before_action :verify_authenticity_token, :only => [:html_content]
skip_before_action :check_sign, only: [:training_task_status, :code_runinng_message]
## TPI关卡列表
def challenges

@ -46,8 +46,8 @@ class PollsController < ApplicationController
@polls = member_show_polls.size > 0 ? member_show_polls.public_or_unset : []
else #已分班级的成员,可以查看统一设置和单独设置(试卷是发布在该班级)试卷
# 已发布 当前用户班级分组的 试卷id
not_poll_ids = @course.poll_group_settings.poll_group_not_published.where("course_group_id = #{@member_group_id}").pluck(:poll_id)
@polls = member_show_polls.where.not(id: not_poll_ids)
publish_poll_ids = @course.poll_group_settings.poll_group_published.where("course_group_id = #{@member_group_id}").pluck(:poll_id)
@polls = member_show_polls.unified_setting.or(member_show_polls.where(id: publish_poll_ids))
end
else #用户未登陆或不是该课堂成员,仅显示统一设置的(已发布的/已截止的),如有公开,则不显示锁,不公开,则显示锁
@is_teacher_or = 0
@ -722,19 +722,16 @@ class PollsController < ApplicationController
un_anonymous = params[:un_anonymous] ? true : false
# 统一设置或者分班为0则更新问卷并删除问卷分组
if unified_setting || (course_group_ids.size == 0)
params_publish_time = params[:publish_time].present? ? params[:publish_time].to_time : nil
params_end_time = nil
if params[:end_time].blank?
if params_publish_time.present?
params_end_time = params_publish_time + 30.days
end
else
params_end_time = params[:end_time].to_time
end
# params_end_time = params[:end_time].present? ? params[:end_time].to_time : nil
if poll_status == 2 && @poll.publish_time != params_publish_time
normal_status(-1,"不允许修改发布时间")
elsif poll_status == 3 && (@poll.end_time != params_end_time || @poll.publish_time != params_publish_time)
tip_exception("发布时间不能为空") if params[:publish_time].blank?
tip_exception("截止时间不能为空") if params[:end_time].blank?
tip_exception("截止时间不能早于发布时间") if params[:publish_time].to_time > params[:end_time].to_time
tip_exception("截止时间不能晚于课堂结束时间(#{@course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")}") if
@course.end_date.present? && params[:end_time].to_time > @course.end_date.end_of_day
params_publish_time = params[:publish_time].to_time
params_end_time = params[:end_time].to_time
if poll_status != 1 && @poll.publish_time != params_publish_time
normal_status(-1,"不允许修改发布时间")
elsif params_publish_time.present? && params_end_time.present? && params_end_time < params_publish_time
normal_status(-1,"截止时间不能小于发布时间")
@ -761,24 +758,25 @@ class PollsController < ApplicationController
total_common_group = poll_groups_ids & total_common #传入的分班与问卷已存在的分班的交集
old_poll_groups = poll_groups_ids - total_common_group #后来传入的分班里,没有了的班级,即需要删除
params_times.each do |t|
course_id = t[:course_group_id] #为数组可能会设置分班为各个班级id的数组
poll_publish_time = t[:publish_time].present? ? t[:publish_time].to_time : nil
# poll_end_time = t[:end_time].present? ? t[:end_time].to_time : nil
poll_end_time = nil
if t[:end_time].blank?
if poll_publish_time.present?
poll_end_time = poll_publish_time + 30.days
end
else
poll_end_time = t[:end_time].to_time
end
tip_exception("发布时间不能为空") if t[:publish_time].blank?
tip_exception("截止时间不能为空") if t[:end_time].blank?
tip_exception("截止时间不能早于发布时间") if t[:publish_time].to_time > t[:end_time].to_time
tip_exception("截止时间不能晚于课堂结束时间(#{@course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")}") if
@course.end_date.present? && t[:end_time].to_time > @course.end_date.end_of_day
course_id = t[:course_group_id]
poll_publish_time = t[:publish_time].to_time
poll_end_time = t[:end_time].to_time
poll_group = poll_groups.find_in_poll_group("course_group_id",course_id) #判断该分班是否存在
if poll_group.present? && poll_group.first.end_time <= Time.now && (poll_end_time != poll_group.first.end_time || poll_publish_time != poll_group.first.publish_time) #已截止且时间改变的,则提示错误
if poll_group.present? && (poll_group.first.publish_time < Time.now) && (poll_publish_time != poll_group.first.publish_time)
error_count += 1
end
if poll_group.present? && poll_group.first.publish_time < Time.now && poll_publish_time != poll_group.first.publish_time
if poll_group.present? && (poll_group.first.publish_time < Time.now && poll_group.first.end_time > Time.now) && (poll_end_time < Time.now)
error_count += 1
end
if error_count == 0
common_group = poll_groups_ids & course_id #传入的班级与问卷已存在的班级的交集,即表示已有分班的
new_group_ids = course_id - common_group #新传入的班级id
@ -794,12 +792,12 @@ class PollsController < ApplicationController
if the_group_setting_status == 2
poll_group_params = {
:publish_time => the_group_setting.publish_time,
:end_time => poll_end_time
:end_time => poll_end_time < Time.now ? the_group_setting.end_time : poll_end_time
}
elsif the_group_setting_status == 3
poll_group_params = {
:publish_time => the_group_setting.publish_time,
:end_time => the_group_setting.end_time
:end_time => poll_end_time
}
end
the_group_setting.update_attributes(poll_group_params)

@ -1,4 +1,5 @@
class SchoolsController < ApplicationController
skip_before_action :check_sign
def school_list
schools = School.all
@ -14,7 +15,6 @@ class SchoolsController < ApplicationController
schools = School.all
keyword = params[:keyword].to_s.strip
schools = schools.where('name LIKE ?', "%#{keyword}%") if keyword
render_ok(schools: schools.select(:id, :name).as_json)
end

@ -4,7 +4,8 @@ class ShixunListsController < ApplicationController
end
private
def search_params
params.permit(:keyword, :type, :page, :limit, :order, :status, :diff)
params.permit(:keyword, :type, :page, :limit, :order, :status, :diff, :sort, :no_jupyter)
end
end

@ -19,11 +19,12 @@ class ShixunsController < ApplicationController
:add_file, :jupyter_exec]
before_action :allowed, only: [:update, :close, :update_propaedeutics, :settings, :publish, :apply_public,
:shixun_members_added, :change_manager, :collaborators_delete,
:shixun_members_added, :change_manager, :collaborators_delete, :upload_git_file,
:cancel_apply_public, :cancel_publish, :add_collaborators, :add_file]
before_action :portion_allowed, only: [:copy]
before_action :special_allowed, only: [:send_to_course, :search_user_courses]
before_action :shixun_marker, only: [:new, :create]
## 获取课程列表
def index
@ -215,7 +216,8 @@ class ShixunsController < ApplicationController
if @shixun.shixun_info.present?
ShixunInfo.create!(shixun_id: @new_shixun.id,
description: @shixun.description,
evaluate_script: @shixun.evaluate_script)
evaluate_script: @shixun.evaluate_script,
fork_reason: params[:reason].to_s.strip)
end
# 同步私密版本库
@ -265,8 +267,20 @@ class ShixunsController < ApplicationController
# 如果是jupyter先创建一个目录,为了挂载(因为后续数据集开启Pod后环境在没销毁前你上传数据集是挂载不上目录的因此要先创建目录方便中间层挂载)
if @new_shixun.is_jupyter?
folder = EduSetting.get('shixun_folder')
raise "存储目录未定义" unless folder.present?
path = "#{folder}/#{@new_shixun.identifier}"
FileUtils.mkdir_p(path, :mode => 0777) unless File.directory?(path)
# 复制数据集
save_path = File.join(folder, @shixun.identifier)
@shixun.data_sets.each do |set|
new_date_set = Attachment.new
new_date_set.attributes = set.attributes.dup.except("id", "container_id", "disk_directory")
new_date_set.container_id = @new_shixun.id
new_date_set.disk_directory = @new_shixun.identifier
new_date_set.save!
FileUtils.cp("#{save_path}/#{set.relative_path_filename}", path)
end
end
# 同步复制关卡
if @shixun.challenges.present?
@ -350,7 +364,7 @@ class ShixunsController < ApplicationController
page = params[:page] || 1
limit = params[:limit] || 10
@member_count = @shixun.shixun_members.count
@members = @shixun.shixun_members.includes(:user).page(page).per(limit)
@members = @shixun.shixun_members.order("role = 1 desc, created_at asc").includes(:user).page(page).per(limit)
end
def fork_list
@ -454,7 +468,13 @@ class ShixunsController < ApplicationController
def update_learn_setting
begin
ActiveRecord::Base.transaction do
@shixun.update_attributes!(shixun_params)
update_params =
if params[:shixun][:vnc]
shixun_params.merge(vnc_evaluate: 1)
else
shixun_params
end
@shixun.update_attributes!(update_params)
end
rescue => e
uid_logger_error("实训学习页面设置失败--------#{e.message}")
@ -753,7 +773,7 @@ class ShixunsController < ApplicationController
# jupyter开启挑战
def jupyter_exec
begin
if is_shixun_opening?
tip_show_exception(-3, "#{@shixun.opening_time.strftime('%Y-%m-%d %H:%M:%S')}")
end
@ -767,22 +787,23 @@ class ShixunsController < ApplicationController
commit_id = commit["id"]
cloud_bridge = edu_setting('cloud_bridge')
myshixun_identifier = generate_identifier Myshixun, 10
ActiveRecord::Base.transaction do
@myshixun = @shixun.myshixuns.create!(user_id: current_user.id, identifier: myshixun_identifier,
modify_time: @shixun.modify_time, reset_time: @shixun.reset_time,
onclick_time: Time.now, commit_id: commit_id)
# fork仓库
project_fork(@myshixun, @repo_path, current_user.login)
rep_url = Base64.urlsafe_encode64(repo_ip_url @repo_path)
uri = "#{cloud_bridge}/bridge/game/openGameInstance"
params = {tpiID: "#{@myshixun.id}", tpmGitURL: rep_url, tpiRepoName: @myshixun.repo_name.split("/").last}
interface_post uri, params, 83, "实训云平台繁忙繁忙等级83"
begin
ActiveRecord::Base.transaction do
@myshixun = @shixun.myshixuns.create!(user_id: current_user.id, identifier: myshixun_identifier,
modify_time: @shixun.modify_time, reset_time: @shixun.reset_time,
onclick_time: Time.now, commit_id: commit_id)
# fork仓库
project_fork(@myshixun, @repo_path, current_user.login)
rep_url = Base64.urlsafe_encode64(repo_ip_url @repo_path)
uri = "#{cloud_bridge}/bridge/game/openGameInstance"
params = {tpiID: "#{@myshixun.id}", tpmGitURL: rep_url, tpiRepoName: @myshixun.repo_name.split("/").last}
interface_post uri, params, 83, "服务器出现问题,请重置环境"
end
rescue => e
uid_logger_error(e.message)
tip_exception("服务器出现问题,请重置环境")
end
end
rescue => e
uid_logger_error(e.message)
tip_exception("#{e.message}")
end
end
def publish
@ -862,7 +883,18 @@ class ShixunsController < ApplicationController
author_name = current_user.real_name
author_email = current_user.git_mail
@content = update_file_content content, @repo_path, @path, author_email, author_name, "Edit by browser"
end
end
def upload_git_file
upload_file = params["file"]
uid_logger("#########################file_params####{params["#{params[:file]}"]}")
raise "未上传文件" unless upload_file
content = upload_file.tempfile.read
author_name = current_user.real_name
author_email = current_user.git_mail
update_file_content(content, @repo_path, author_email, author_name, "upload file by browser")
render_ok
end
def add_collaborators
member_ids = "(" + @shixun.shixun_members.map(&:user_id).join(',') + ")"
@ -896,16 +928,20 @@ class ShixunsController < ApplicationController
# 搜索成员
if request.get?
@collaborators = @shixun.shixun_members.where("user_id != #{@shixun.user_id}")
else
if params[:user_id]
man_member = ShixunMember.where(:shixun_id => @shixun.id, :user_id => @shixun.user_id).first
cha_member = ShixunMember.where(:user_id => params[:user_id], :shixun_id => @shixun.id).first
if man_member && cha_member
man_member.update_attribute(:role, 2)
cha_member.update_attribute(:role, 1)
@shixun.update_attribute(:user_id, cha_member.user_id)
end
end
else
begin
raise("请先选择成员") if params[:user_id].blank?
man_member = ShixunMember.where(:shixun_id => @shixun.id, :user_id => @shixun.user_id).first
cha_member = ShixunMember.where(:user_id => params[:user_id], :shixun_id => @shixun.id).first
if man_member && cha_member
man_member.update_attribute(:role, 2)
cha_member.update_attribute(:role, 1)
@shixun.update_attribute(:user_id, cha_member.user_id)
end
rescue => e
logger.error("######change_manager_error: #{e.message}")
render_error(e.message)
end
end
end
@ -1127,4 +1163,5 @@ private
end
md5.hexdigest
end
end

@ -7,6 +7,8 @@ class SubjectsController < ApplicationController
:search_members, :add_subject_members, :statistics, :shixun_report, :school_report,
:up_member_position, :down_member_position, :update_team_title]
before_action :require_admin, only: [:copy_subject]
before_action :shixun_marker, only: [:new, :create, :add_shixun_to_stage]
include ApplicationHelper
include SubjectsHelper
@ -214,7 +216,15 @@ class SubjectsController < ApplicationController
GitService.add_repository(repo_path: repo_path)
# todo: 为什么保存的时候要去除后面的.git呢??
@shixun.update_column(:repo_name, repo_path.split(".")[0])
mirror_id = MirrorRepository.find_by(type_name: 'Python3.6')&.id
mirror_id =
if @shixun.is_jupyter?
folder = EduSetting.get('shixun_folder')
path = "#{folder}/#{identifier}"
FileUtils.mkdir_p(path, :mode => 0777) unless File.directory?(path)
MirrorRepository.where("type_name like '%Jupyter%'").first&.id
else
MirrorRepository.find_by(type_name: 'Python3.6')&.id
end
if mirror_id
ShixunMirrorRepository.create!(:shixun_id => @shixun.id, :mirror_repository_id => mirror_id)
@shixun.shixun_service_configs.create!(:shixun_id => @shixun.id, :mirror_repository_id => mirror_id)
@ -247,7 +257,7 @@ class SubjectsController < ApplicationController
CourseSecondCategory.create!(name: stage.name, course_id: @course.id, category_type: "shixun_homework",
course_module_id: course_module.id, position: course_module.course_second_categories.count + 1)
stage.shixuns.where(id: params[:shixun_ids], status: 2).each do |shixun|
stage.shixuns.no_jupyter.where(id: params[:shixun_ids], status: 2).each do |shixun|
homework = HomeworksService.new.create_homework shixun, @course, category, current_user
homework_ids << homework.id
end

@ -31,6 +31,9 @@ module GradeDecorator
when 'check_ta_answer' then
game = Game.find_by(id: container_id)
game.present? ? "查看实训“#{game.challenge.shixun.name}”第#{game.challenge.position}关的TA人解答消耗的金币" : ''
when 'hack' then
hack = Hack.find_by(id: container_id)
hack.present? ? "完成了题目解答“#{hack.name}”,获得金币奖励:#{hack.score}" : ''
end
end
end

@ -220,11 +220,14 @@ module TidingDecorator
when 'Journal' then
message = parent_container&.notes.present? ? '' + message_content_helper(parent_container.notes) : ''
I18n.t(locale_format(parent_container_type)) % message
when 'Hack' then
I18n.t(locale_format(parent_container_type)) % parent_container.name
end
end
def discuss_content
I18n.t(locale_format(container.parent_id.present?)) % message_content_helper(container.content)
I18n.t(locale_format(parent_container_type, container.parent_id.present?)) %
(parent_container_type == 'Hack' ? container.content : message_content_helper(container.content))
end
def grade_content
@ -250,6 +253,9 @@ module TidingDecorator
when 'shixunPublish' then
name = Shixun.find_by(id: parent_container_id)&.name || '---'
I18n.t(locale_format(parent_container_type)) % [name, container.score]
when 'Hack' then
name = Hack.find_by(id: container_id)&.name || '---'
I18n.t(locale_format(parent_container_type)) % [name, container.score]
else
I18n.t(locale_format(parent_container_type)) % container.score
end
@ -405,4 +411,8 @@ module TidingDecorator
def subject_start_course_content
I18n.t(locale_format) % belong_container&.name
end
def hack_content
I18n.t(locale_format(parent_container_type)) % (container&.name || extra)
end
end

@ -64,7 +64,7 @@ module ApplicationHelper
shixun_id = shixun_id.blank? ? -1 : shixun_id.join(",")
Shixun.select([:id, :name, :user_id, :challenges_count, :myshixuns_count, :trainee, :identifier]).where("id
in(#{shixun_id})").unhidden.order("homepage_show asc, myshixuns_count desc").limit(3)
in(#{shixun_id})").unhidden.publiced.order("homepage_show asc, myshixuns_count desc").limit(3)
end

@ -0,0 +1,20 @@
# 作业的一键评阅
class HomeworkBatchCommentJob < ApplicationJob
queue_as :default
def perform(comment, hidden_comment, work_ids, homework_id, user_id)
# Do something later
homework = HomeworkCommon.find_by(id: homework_id)
return if homework.blank?
attrs = %i[student_work_id challenge_id user_id comment hidden_comment batch_comment created_at updated_at]
same_attrs = {challenge_id: 0, user_id: user_id, comment: comment, hidden_comment: hidden_comment, batch_comment: 1}
ShixunWorkComment.bulk_insert(*attrs) do |worker|
work_ids.each do |work_id|
worker.add same_attrs.merge(student_work_id: work_id)
end
end
end
end

@ -2,13 +2,15 @@ class CourseGroup < ApplicationRecord
default_scope { order("course_groups.position ASC") }
belongs_to :course, counter_cache: true
has_many :course_members
has_many :exercise_group_settings,:dependent => :destroy
has_many :attachment_group_settings, :dependent => :destroy
has_many :homework_group_reviews, :dependent => :destroy
has_many :teacher_course_groups, :dependent => :destroy
has_many :homework_group_settings, :dependent => :destroy
scope :by_group_ids, lambda { |ids| where(id: ids)}
validates :name, length: { maximum: 60 }
validates_uniqueness_of :name, scope: :course_id, message: "不能创建相同名称的分班"
after_create :generate_invite_code

@ -10,7 +10,7 @@ class Discuss < ApplicationRecord
has_one :praise_tread_cache, as: :object, dependent: :destroy
belongs_to :dis, polymorphic: true
belongs_to :challenge
belongs_to :challenge, optional: true
after_create :send_tiding
scope :children, -> (discuss_id){ where(parent_id: discuss_id).includes(:user).reorder(created_at: :asc) }
@ -52,11 +52,21 @@ class Discuss < ApplicationRecord
private
def send_tiding
if dis_type == 'Shixun'
send_user_id = has_parent? ? parent.user_id : Challenge.find(challenge_id).user_id
parent_container_type = 'Challenge'
challenge_id = challenge_id
extra = ''
elsif dis_type == 'Hack'
send_user_id = has_parent? ? parent.user_id : Hack.find(dis_id).user_id
parent_container_type = 'Hack'
challenge_id = dis_id
extra = HackUserLastestCode.where(user_id: user_id, hack_id: dis_id).first&.identifier
end
base_attrs = {
trigger_user_id: user_id, parent_container_id: challenge_id, parent_container_type: 'Challenge',
belong_container_id: dis_id, belong_container_type: 'Shixun', viewed: 0, tiding_type: 'Comment'
trigger_user_id: user_id, parent_container_id: challenge_id, parent_container_type: parent_container_type,
belong_container_id: dis_id, belong_container_type: dis_type, viewed: 0, tiding_type: 'Comment', extra: extra
}
user_id = has_parent? ? parent.user_id : Challenge.find(challenge_id).user_id
tidings.create!(base_attrs.merge(user_id: user_id))
tidings.create!(base_attrs.merge(user_id: send_user_id))
end
end

@ -11,6 +11,11 @@ class Hack < ApplicationRecord
has_many :hack_codes, :dependent => :destroy
has_many :hack_user_lastest_codes, :dependent => :destroy
has_many :discusses, as: :dis, dependent: :destroy
# 点赞
has_many :praise_treads, as: :praise_tread_object, dependent: :destroy
# 消息
has_many :tidings, as: :container
belongs_to :user
scope :published, -> { where(status: 1) }

@ -1,5 +1,5 @@
class HackSet < ApplicationRecord
#validates :input, presence: { message: "测试集输入不能为空" }
validates :input, presence: { message: "测试集输入不能为空" }
validates :output, presence: { message: "测试集输出不能为空" }
validates_uniqueness_of :input, scope: [:hack_id, :input], message: "多个测试集的输入不能相同"
# 编程题测试集

@ -1,4 +1,5 @@
class HackUserCode < ApplicationRecord
# error_test_set_id: 错误的测试集id
# 用户编程题的信息
belongs_to :hack
belongs_to :hack_user_lastest_code

@ -12,4 +12,6 @@ class HackUserLastestCode < ApplicationRecord
scope :mine_hack, ->(author_id){ where(user_id: author_id) }
scope :passed, -> {where(status: 1)}
validates_length_of :notes, maximum: 5000, message: "笔记不能超过5000个字"
end

@ -19,6 +19,7 @@ class Poll < ApplicationRecord
scope :poll_by_ids, lambda { |ids| where(id: ids) unless ids.blank? }
scope :poll_by_status, lambda { |s| where(polls_status: s) unless s.blank? }
scope :poll_group_ended, -> {where("end_time is NOT NULL AND end_time <= ?",Time.now)}
scope :unified_setting, -> { where("unified_setting = ?",true) }
scope :poll_search, lambda { |keywords|
where("polls_name LIKE ?", "%#{keywords}%") unless keywords.blank?}
@ -103,7 +104,7 @@ class Poll < ApplicationRecord
if course.is_end
status = 4
else
if user.present? && user.student_of_course?(course)
if user.present? && user.course_identity(course) == Course::STUDENT
ex_time = get_poll_times(user.id,false)
pb_time = ex_time[:publish_time]
ed_time = ex_time[:end_time]

@ -12,7 +12,7 @@ class PraiseTread < ApplicationRecord
case self.praise_tread_object_type
when "Memo","Message","Issue"
self.tidings << Tiding.new(:trigger_user_id => self.user_id, :user_id => self.praise_tread_object.author_id, :parent_container_id => self.praise_tread_object_id, :parent_container_type => self.praise_tread_object_type, :viewed => 0, :tiding_type => "Praise")
when "Discuss","Challenge","HomeworkCommon","JournalsForMessage","Journal","GraduationTopic","GraduationTask"
when "Discuss","Challenge","HomeworkCommon","JournalsForMessage","Journal","GraduationTopic","GraduationTask", "Hack"
self.tidings << Tiding.new(:trigger_user_id => self.user_id, :user_id => self.praise_tread_object.user_id, :parent_container_id => self.praise_tread_object_id, :parent_container_type => self.praise_tread_object_type, :viewed => 0, :tiding_type => "Praise")
end
end

@ -16,7 +16,9 @@ module Searchable::Shixun
name: name,
description: Util.extract_content(description)[0..Searchable::MAXIMUM_LENGTH],
status: status,
myshixuns_count: myshixuns_count
myshixuns_count: myshixuns_count,
created_at: created_at,
publish_time: publish_time
}.merge!(searchable_user_data)
.merge!(searchable_challenge_data)
end

@ -83,6 +83,7 @@ class Shixun < ApplicationRecord
scope :publiced, lambda{ where(public: 2) }
scope :field_for_recommend, lambda{ select([:id, :name, :identifier, :myshixuns_count]) }
scope :find_by_ids,lambda{|k| where(id:k)}
scope :no_jupyter, -> { where(is_jupyter: false) }
after_create :send_tiding
#同步到trustie
@ -103,6 +104,19 @@ class Shixun < ApplicationRecord
shixun_info.try(:evaluate_script)
end
def fork_reason
case shixun_info.try(:fork_reason)
when 'Shixun'
'实训内容升级'
when 'Course'
'课堂教学使用'
when 'Subject'
'实践课程使用'
else
shixun_info.try(:fork_reason)
end
end
def fork_identifier
self.fork_from.nil? ? "--" : fork_shixuns.first&.identifier
end

@ -1,6 +1,7 @@
class ShixunInfo < ApplicationRecord
belongs_to :shixun
validates_uniqueness_of :shixun_id
validates_length_of :fork_reason, maximum: 60
after_commit :create_diff_record
private

@ -8,6 +8,8 @@ class TeacherCourseGroup < ApplicationRecord
scope :find_teacher_group_ids, lambda { |ids| where(course_group_id: ids) unless ids.blank?}
scope :get_user_groups,lambda {|ids| where(user_id:ids)}
validates_uniqueness_of :course_group_id, scope: :course_member_id
def course_members
self.course_group.course_members
end

@ -13,25 +13,24 @@ class Admins::ShixunQuery < ApplicationQuery
all_shixuns = Shixun.all
status =
case params[:status]
when "editing" then [0]
when "pending" then [1]
when "processed" then [2]
when "closed" then [3]
else
[0,1,2,3]
when "editing" then {status: 0}
when "processed" then {status: 2, public: 0}
when "pending" then {public: 1}
when "publiced" then {public: 2}
when "closed" then {status: 3}
end
public =
case params[:public]
when "editing" then [0]
when "pending" then [1]
when "processed" then [2]
else
[0,1,2]
end
all_shixuns = all_shixuns.where(status) if status.present?
all_shixuns = all_shixuns.where(status: status) if status.present?
all_shixuns = all_shixuns.where(public: public) if public.present?
if params[:fork_status].present?
all_shixuns = all_shixuns.where.not(fork_from: nil)
case params[:fork_status]
when 'Shixun', 'Course', 'Subject'
all_shixuns = all_shixuns.joins(:shixun_info).where(shixun_infos: {fork_reason: params[:fork_status]})
when 'Other'
all_shixuns = all_shixuns.joins(:shixun_info).where("fork_reason is null or fork_reason not in ('Shixun', 'Course', 'Subject')")
end
end
if params[:tag].present?
all_shixuns = all_shixuns.joins(:mirror_repositories).where("mirror_repositories.id = ?",params[:tag].to_i)

@ -15,16 +15,15 @@ class Admins::ShixunSettingsQuery < ApplicationQuery
all_shixuns = all_shixuns.where(id: params[:id]) if params[:id].present?
status =
case params[:status]
when "editing" then [0]
when "pending" then [1]
when "processed" then [2]
when "closed" then [3]
else
[0,1,2,3]
end
all_shixuns = all_shixuns.where(status: status) if status.present?
case params[:status]
when "editing" then {status: 0}
when "processed" then {status: 2, public: 0}
when "pending" then {public: 1}
when "publiced" then {public: 2}
when "closed" then {status: 3}
end
all_shixuns = all_shixuns.where(status) if status.present?
if params[:tag].present?
all_shixuns = all_shixuns.joins(:mirror_repositories).where("mirror_repositories.id = ?",params[:tag].to_i)

@ -10,7 +10,6 @@ class Admins::IdentityAuths::AgreeApplyService < ApplicationService
ActiveRecord::Base.transaction do
apply.update!(status: 1)
user.update!(authentication: true)
RewardGradeService.call(user, container_id: user.id, container_type: 'Authentication', score: 500)
deal_tiding!

@ -10,7 +10,7 @@ class Admins::ProfessionalAuths::AgreeApplyService < ApplicationService
ActiveRecord::Base.transaction do
apply.update!(status: 1)
user.update!(professional_certification: true)
user.update!(is_shixun_marker: true) if user.is_teacher?
RewardGradeService.call(user, container_id: user.id, container_type: 'Professional', score: 500)
deal_tiding!

@ -25,6 +25,7 @@ class Admins::UpdateUserService < ApplicationService
ActiveRecord::Base.transaction do
user.save!
user.user_extension.save!
user.update!(is_shixun_marker: true) if user.is_certification_teacher
update_gitlab_password if params[:password].present?
end
@ -36,7 +37,7 @@ class Admins::UpdateUserService < ApplicationService
def user_attributes
params.slice(*%i[lastname nickname mail phone admin business is_test
professional_certification authentication])
professional_certification authentication is_shixun_marker])
end
def user_extension_attributes

@ -9,7 +9,7 @@ module ElasticsearchAble
highlight: highlight_options,
body_options: body_options,
page: page,
per_page: per_page
per_page: 20
}
end
@ -37,7 +37,7 @@ module ElasticsearchAble
def per_page
per_page = params[:per_page].to_s.strip.presence || params[:limit].to_s.strip.presence
per_page.to_i <= 0 ? 20 : per_page.to_i
per_page.to_i <= 0 || per_page.to_i > 20 ? 20 : per_page.to_i
end
def page

@ -30,6 +30,6 @@ class PrivateMessages::CreateService < ApplicationService
def validate!
raise Error, '内容不能为空' if content.blank?
raise Error, '内容太长' if content.size > 255
raise Error, '内容太长' if content.size > 500
end
end

@ -33,6 +33,10 @@ class ShixunSearchService < ApplicationService
@shixuns = status == "published" ? @shixuns.where(status: 2) : @shixuns.where(status: [0, 1])
end
if params[:no_jupyter]
@shixuns = @shixuns.where(is_jupyter: 0)
end
## 筛选 难度
if params[:diff].present? && params[:diff].to_i != 0
@shixuns = @shixuns.where(trainee: params[:diff])
@ -49,12 +53,16 @@ class ShixunSearchService < ApplicationService
includes: [ :shixun_info, :challenges, :subjects, user: { user_extension: :school } ]
}
model_options.merge!(where: { id: @shixuns.pluck(:id) })
model_options.merge!(order: {"myshixuns_count" => sort_str})
model_options.merge!(order: {sort_str => order_str})
model_options.merge!(default_options)
model_options
end
def sort_str
def order_str
params[:order] || "desc"
end
def sort_str
params[:sort] || "myshixuns_count"
end
end

@ -79,7 +79,7 @@ class Subjects::CopySubjectService < ApplicationService
copy_shixun_service_configs_data!(shixun, to_shixun)
copy_challenges_data!(shixun, to_shixun)
copy_shixun_members_data!(to_shixun)
copy_jupyter_data_sets(shixun, to_shixun) if shixun.is_jupyter?
# 云上实验室
if laboratory
laboratory.laboratory_shixuns.create(shixun: to_shixun)
@ -87,6 +87,25 @@ class Subjects::CopySubjectService < ApplicationService
to_shixun
end
# 复制jupyter的数据集
def copy_jupyter_data_sets(shixun, to_shixun)
return unless shixun.is_jupyter?
folder = EduSetting.get('shixun_folder')
raise "存储目录未定义" unless folder.present?
path = "#{folder}/#{to_shixun.identifier}"
FileUtils.mkdir_p(path, :mode => 0777) unless File.directory?(path)
# 复制数据集
save_path = File.join(folder, shixun.identifier)
shixun.data_sets.each do |set|
new_date_set = Attachment.new
new_date_set.attributes = set.attributes.dup.except("id", "container_id", "disk_directory")
new_date_set.container_id = to_shixun.id
new_date_set.disk_directory = to_shixun.identifier
new_date_set.save!
FileUtils.cp("#{save_path}/#{set.relative_path_filename}", path)
end
end
# 创建实训长字段内容
def copy_shixun_info_data!(shixun, to_shixun)
to_shixun_info = ShixunInfo.new

@ -65,13 +65,18 @@ class Users::ShixunService
end
def manage_shixun_status_filter(relations)
status = case params[:status]
when 'editing' then 0
when 'applying' then 1
when 'published' then 2
when 'closed' then 3
end
relations = relations.where(status: status) if status
if params[:status] == "publiced"
relations = relations.where(public: 2)
elsif params[:status] == "applying"
relations = relations.where(public: 1)
else
status = case params[:status]
when 'editing' then 0
when 'published' then 2
when 'closed' then 3
end
relations = relations.where(status: status) if status
end
relations
end

@ -2,7 +2,7 @@
<nav id="sidebar" class="<%= sidebar_collapse ? 'active' : '' %>" data-current-controller="<%= admin_sidebar_controller %>">
<div class="sidebar-header">
<a href="/" class="sidebar-header-logo" data-toggle="tooltip" data-title="返回主站" >
<img class="rounded-circle" src="/images/<%= url_to_avatar(current_user) %>" />
<!-- <img class="rounded-circle" src="/images/<%#= url_to_avatar(current_user) %>" />-->
<span class="logo-label">后台管理</span>
</a>
<div id="sidebarCollapse" class="navbar-btn <%= sidebar_collapse ? 'active' : '' %>">

@ -8,7 +8,7 @@
<div class="d-flex position-r">
<div class="form-group mr-2">
<label for="status">状态:</label>
<% status_options = [['全部', ''], ["编辑中(#{@editing_shixuns})", "editing"], ["待审核(#{@pending_shixuns})", 'pending'], ["已发布(#{@processed_shixuns})", 'processed'],["已关闭(#{@closed_shixuns})",'closed']] %>
<% status_options = [['全部', ''], ["编辑中(#{@editing_shixuns})", "editing"], ["已发布未公开(#{@processed_shixuns})", 'processed'], ["待审核(#{@pending_public_shixuns})", 'pending'], ["已公开(#{@processed_pubic_shixuns})", 'publiced'], ["已关闭(#{@closed_shixuns})",'closed']] %>
<%= select_tag(:status, options_for_select(status_options), class: 'form-control') %>
</div>
<div class="form-group mr-2">

@ -4,33 +4,42 @@
<div class="box search-form-container shixuns-list-form">
<%= form_tag(admins_shixuns_path, method: :get, class: 'form-inline search-form',id:"shixuns-search-form",remote:true) do %>
<div class="form-group">
<label for="status">状态:</label>
<% status_options = [['全部', ''], ["编辑中(#{@editing_shixuns})", "editing"], ["待审核(#{@pending_shixuns})", 'pending'], ["已发布(#{@processed_shixuns})", 'processed'],["已关闭(#{@closed_shixuns})",'closed']] %>
<%= select_tag(:status, options_for_select(status_options), class: 'form-control') %>
</div>
<div class="d-flex flex-column w-100">
<div class="d-flex position-r">
<div class="form-group">
<label for="status">状态:</label>
<% status_options = [['全部', ''], ["编辑中(#{@editing_shixuns})", "editing"], ["已发布未公开(#{@processed_shixuns})", 'processed'], ["待审核(#{@pending_public_shixuns})", 'pending'], ["已公开(#{@processed_pubic_shixuns})", 'publiced'], ["已关闭(#{@closed_shixuns})",'closed']] %>
<%= select_tag(:status, options_for_select(status_options), class: 'form-control') %>
</div>
<div class="form-group">
<label for="status">公开:</label>
<% public_options = [['全部', ''], ["未公开(#{@none_public_shixuns})", "editing"], ["待审核(#{@pending_public_shixuns})", 'pending'], ["已公开(#{@processed_pubic_shixuns})", 'processed']] %>
<%= select_tag(:public, options_for_select(public_options), class: 'form-control') %>
</div>
<div class="form-group mr-2">
<label for="tag-choosed">技术平台:</label>
<%= select_tag(:tag, options_for_select(@shixuns_type_check.unshift(["",nil])), class: 'form-control',id:"tag-choosed") %>
</div>
<div class="form-group mr-2">
<label for="tag-choosed">技术平台:</label>
<%= select_tag(:tag, options_for_select(@shixuns_type_check.unshift(["",nil])), class: 'form-control',id:"tag-choosed") %>
</div>
<div class="form-group mr-2">
<label>搜索类型:</label>
<% auto_trial_options = [['创建者姓名', 0], ['实训名称', 1], ['学校名称', 2]] %>
<%= select_tag(:search_type, options_for_select(auto_trial_options), class: 'form-control') %>
</div>
<%= text_field_tag(:keyword, params[:keyword], class: 'form-control col-sm-2 ml-3', placeholder: '输入关键字搜索') %>
<div class="">
<a href="javascript:void(0)" class="btn btn-primary" id="shixuns-export" data-disable-with = '导出中...'>导出</a>
</div>
</div>
<div class="d-flex mt-3">
<div class="form-group">
<label for="status">fork原因</label>
<% fork_status_options = [['全部', ''], ["全部fork实训", "Fork"], ["实训内容升级", 'Shixun'], ["课堂教学使用", 'Course'],["实践课程使用",'Subject'],["其他原因",'Other']] %>
<%= select_tag(:fork_status, options_for_select(fork_status_options), class: 'form-control') %>
</div>
<div class="form-group">
<label>搜索类型:</label>
<% auto_trial_options = [['创建者姓名', 0], ['实训名称', 1], ['学校名称', 2]] %>
<%= select_tag(:search_type, options_for_select(auto_trial_options), class: 'form-control') %>
<%= submit_tag('搜索', class: 'btn btn-primary ml-3','data-disable-with': '搜索中...') %>
<%= link_to "清除", admins_shixuns_path,class: "btn btn-default",id:"shixuns-clear-search",'data-disable-with': '清除中...' %>
</div>
</div>
<%= text_field_tag(:keyword, params[:keyword], class: 'form-control col-sm-2', placeholder: '输入关键字搜索') %>
<%= submit_tag('搜索', class: 'btn btn-primary','data-disable-with': '搜索中...') %>
<%= link_to "清除", admins_shixuns_path,class: "btn btn-default",id:"shixuns-clear-search",'data-disable-with': '清除中...' %>
<% end %>
<a href="javascript:void(0)" class="btn btn-primary" id="shixuns-export" data-disable-with = '导出中...'>导出</a>
</div>
<div class="box admin-list-container shixuns-list-container">

@ -2,17 +2,18 @@
<thead class="thead-light">
<th width="4%">序号</th>
<th width="8%">ID</th>
<th width="24%" class="text-left">实训名称</th>
<th width="22%" class="text-left">实训名称</th>
<th width="8%">技术平台</th>
<th width="5%">Fork源</th>
<th width="10%">Fork原因</th>
<th width="5%">实践</th>
<th width="5%">选择</th>
<th width="4%">选择</th>
<th width="6%">状态</th>
<th width="6%">公开</th>
<th width="7%">创建者</th>
<th width="11%"><%= sort_tag('创建于', name: 'created_at', path: admins_shixuns_path) %></th>
<th width="5%">单测</th>
<th width="6%">操作</th>
<th width="6%">创建者</th>
<th width="8%"><%= sort_tag('创建于', name: 'created_at', path: admins_shixuns_path) %></th>
<th width="4%">单测</th>
<th width="4%">操作</th>
</thead>
<tbody>
<% if shixuns.present? %>
@ -31,6 +32,7 @@
<%= link_to shixun.try(:identifier), shixun_path(shixun.try(:identifier)), target: '_blank'%>
<% end%>
</td>
<td><%= overflow_hidden_span(shixun&.fork_reason, width: 150) %></td>
<td><%= shixun.challenges.where(:st => 0).size %></td>
<td><%= shixun.challenges.where(:st => 1).size %></td>
<td class="shixuns-status-<%= shixun.status %>"><%= shixun_authentication_status shixun %></td>

@ -120,6 +120,7 @@
<div class="d-flex">
<%= f.input :professional_certification, as: :boolean, label: '职业认证', checked_value: 1, unchecked_value: 0 %>
<%= f.input :authentication, as: :boolean, label: '实名认证', wrapper_html: { class: 'ml-3' }, checked_value: 1, unchecked_value: 0 %>
<%= f.input :is_shixun_marker, as: :boolean, label: '实训制作', wrapper_html: { class: 'ml-3' }, checked_value: 1, unchecked_value: 0 %>
</div>
</div>

@ -5,14 +5,16 @@ json.chooses do
json.type choose.category
end
end
json.st @challenge.st
if @tab == 0
# 本关任务tab的编辑模式
json.(@challenge, :id, :subject, :task_pass, :difficulty, :score, :exec_time)
json.(@challenge, :id, :subject, :task_pass, :difficulty, :score, :exec_time, :st)
json.tags @challenge.challenge_tags.map(&:name)
elsif @tab == 1
# 评测设置的编辑模式
json.(@challenge, :id, :path, :exec_path, :show_type, :original_picture_path, :expect_picture_path, :picture_path,
:web_route, :test_set_score, :test_set_average)
:web_route, :test_set_score, :test_set_average, :exec_time)
json.has_web_route @shixun.has_web_route?
json.test_sets @challenge.test_sets do |set|
json.hidden (set.is_public ? 0 : 1)

@ -1,7 +1,7 @@
json.(@challenge_choose, :challenge_id, :subject, :answer,
:standard_answer, :score, :difficult,
:position, :category)
json.st @challenge.st
# 选项的参数
json.choose_contents @challenge_choose.challenge_questions do |question|
json.(question, :option_name, :position, :right_key)

@ -1,6 +1,6 @@
# 导航栏公共数据
json.partial! "challenges/top_common_data", shixun_identifier: @shixun.identifier
json.(@challenge, :id, :subject, :task_pass, :difficulty, :score, :exec_time)
json.(@challenge, :id, :subject, :task_pass, :difficulty, :score, :exec_time, :st)
json.tags @challenge.challenge_tags.map(&:name)

@ -1,11 +1,16 @@
json.author do
json.partial! 'users/user', user: discuss.user
end
json.id discuss.id
json.content content_safe(discuss.content)
json.time time_from_now(discuss.created_at)
json.hack_id discuss.dis_id
json.hidden discuss.hidden
# 主贴和回复有一些不同点
if discuss.parent_id
json.can_delete discuss.can_deleted?(current_user)
else
json.praise_count discuss.praises_count
json.user_praise discuss.praise_treads.select{|pt| pt.user_id == current_user.id}.length > 0
json.can_delete discuss.can_deleted?(current_user) && child.count == 0
end

@ -1,6 +1,6 @@
json.disscuss_count @disscuss_count
json.disscuss_count @discusses_count
json.comments @discusses do |discuss|
json.partial! 'comments/discuss', locals: { discuss: discuss}
json.partial! 'comments/discuss', locals: { discuss: discuss, child: discuss.child_discuss(current_user)}
json.children discuss.child_discuss(current_user) do |c_d|
json.partial! 'comments/discuss', locals: { discuss: c_d }
end

@ -0,0 +1 @@
json.praise_count @praise_count

@ -1,8 +1,15 @@
json.(@hack_user, :id, :status, :error_line, :error_msg, :expected_output,
:input, :output, :execute_time, :execute_memory, :created_at, :code)
json.language @hack_user.hack.language
json.name @hack_user.hack.name
json.myproblem_identifier @my_hack.identifier
json.user do
json.partial! 'users/user', user: current_user
end
json.status 0
json.message "返回成功"
json.data do
json.(@hack_user, :id, :status, :error_line, :error_msg, :expected_output,
:input, :output, :execute_time, :execute_memory, :created_at, :code)
json.language @hack_user.hack.language
json.name @hack_user.hack.name
json.myproblem_identifier @my_hack.identifier
json.pass_sets_count @pass_set_count
json.set_count @set_count
json.user do
json.partial! 'users/user', user: current_user
end
end

@ -1,5 +1,5 @@
json.status 0
json.message "评测成"
json.message "评测成"
json.data do
json.(@result, :id, :status, :error_line, :error_msg,
:input, :output, :execute_time, :execute_memory)

@ -1,11 +1,15 @@
json.hack do
json.(@hack, :name, :difficult, :time_limit, :description, :score, :identifier, :status)
json.(@hack, :id, :name, :difficult, :time_limit, :description, :score, :identifier, :status, :praises_count)
json.language @hack.language
json.username @hack.user.real_name
json.username @hack.user&.real_name
json.user_path "/users/#{@hack.user&.login}"
json.code @my_hack.code
json.pass_count @hack.pass_num
json.submit_count @hack.submit_num
json.notes @my_hack.notes
json.modify_code @modify
json.comments_count @hack.discusses.count
json.user_praise @hack.praise_treads.select{|pt| pt.user_id == current_user.id}.length > 0
end
json.test_case do
@ -15,5 +19,5 @@ end
json.user do
json.partial! 'users/user', user: current_user
json.hack_manager @hack.manager?(current_user)
json.admin current_user.admin_or_business?
end

@ -1,4 +1,8 @@
json.array! @records do |hack_user|
json.(hack_user, :id, :created_at, :status, :execute_time, :execute_memory)
json.language hack_user.hack.language
end
json.records do
json.array! @records do |hack_user|
json.(hack_user, :id, :created_at, :status, :execute_time, :execute_memory)
json.language hack_user.hack.language
end
end
json.records_count @records_count

@ -108,6 +108,7 @@ if @homework.homework_type == "practice"
json.student_id work.user.try(:student_id)
json.group_name @students.select{|student| student.user_id == work.user_id}.first.try(:course_group_name)
json.work_status work.compelete_status
json.has_comment work.shixun_work_comments.size > 0
end
elsif @homework.homework_type == "group" || @homework.homework_type == "normal"
json.anonymous_comment @homework.anonymous_comment

@ -5,7 +5,10 @@ json.data_sets do
json.author set.author.real_name
json.created_on set.created_on
json.filesize number_to_human_size(set.filesize)
json.file_path "#{@absolute_folder}/#{set.relative_path_filename}"
# 这里需要去除shixunfiles目录后的标识因为Jupyter代码里面会写死这样的路径当实训fork后这个版本库的路径无法修改因此给用户展示的
# 还是/data/shixunfiles/+文件名这种形式
json.file_path "#{@absolute_folder}/#{set.relative_path_filename}".gsub("/#{@shixun.identifier}", "")
end
end
json.data_sets_count @data_count
json.data_sets_count @data_count
json.folder_name @absolute_folder

@ -1,5 +1,5 @@
json.extract! tiding, :id, :status, :viewed, :user_id, :tiding_type, :container_id, :container_type,
:parent_container_id, :parent_container_type, :belong_container_id, :belong_container_type
:parent_container_id, :parent_container_type, :belong_container_id, :belong_container_type, :extra
json.content tiding.content
json.identifier tiding.identifier

@ -14,6 +14,7 @@ json.email @user.mail
json.profile_completed @user.profile_completed?
json.professional_certification @user.professional_certification
json.main_site current_laboratory.main_site?
json.is_shixun_marker current_user.is_shixun_marker? || current_user.admin_or_business?
if @course
json.course_identity @course_identity
json.course_name @course.name

@ -1,111 +0,0 @@
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
# Code is not reloaded between requests.
config.cache_classes = true
# Eager load code on boot. This eager loads most of Rails and
# your application in memory, allowing both threaded web servers
# and those relying on copy on write to perform better.
# Rake tasks automatically ignore this option for performance.
config.eager_load = true
# Full error reports are disabled and caching is turned on.
config.consider_all_requests_local = false
config.action_controller.perform_caching = true
# Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"]
# or in config/master.key. This key is used to decrypt credentials (and other encrypted files).
# config.require_master_key = true
# Disable serving static files from the `/public` folder by default since
# Apache or NGINX already handles this.
## config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
config.public_file_server.enabled = true
# Compress JavaScripts and CSS.
config.assets.js_compressor = :uglifier
# config.assets.css_compressor = :sass
# Do not fallback to assets pipeline if a precompiled asset is missed.
config.assets.compile = false
# `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb
# Enable serving of images, stylesheets, and JavaScripts from an asset server.
# config.action_controller.asset_host = 'http://assets.example.com'
# Specifies the header that your server uses for sending files.
# config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
# Store uploaded files on the local file system (see config/storage.yml for options)
config.active_storage.service = :local
# Mount Action Cable outside main process or domain
# config.action_cable.mount_path = nil
# config.action_cable.url = 'wss://example.com/cable'
# config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ]
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
# config.force_ssl = true
# Use the lowest log level to ensure availability of diagnostic information
# when problems arise.
config.log_level = :info
# Prepend all log lines with the following tags.
config.log_tags = [ :request_id ]
# Use a different cache store in production.
# config.cache_store = :mem_cache_store
# Use a real queuing backend for Active Job (and separate queues per environment)
# config.active_job.queue_adapter = :resque
# config.active_job.queue_name_prefix = "educoderplus_#{Rails.env}"
config.action_mailer.perform_caching = false
# Ignore bad email addresses and do not raise email delivery errors.
# Set this to true and configure the email server for immediate delivery to raise delivery errors.
# config.action_mailer.raise_delivery_errors = false
# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
# the I18n.default_locale when a translation cannot be found).
config.i18n.fallbacks = true
# Send deprecation notices to registered listeners.
config.active_support.deprecation = :notify
# Use default logging formatter so that PID and timestamp are not suppressed.
config.log_formatter = ::Logger::Formatter.new
# Use a different logger for distributed setups.
# require 'syslog/logger'
# config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name')
if ENV["RAILS_LOG_TO_STDOUT"].present?
logger = ActiveSupport::Logger.new(STDOUT)
logger.formatter = config.log_formatter
config.logger = ActiveSupport::TaggedLogging.new(logger)
end
# Do not dump schema after migrations.
config.active_record.dump_schema_after_migration = false
config.active_record.belongs_to_required_by_default = false
# config.cache_store = :file_store, "#{Rails.root }/files/cache_store/"
#config.cache_store = :redis_store, 'redis://r-bp122bd1b710f274.redis.rds.aliyuncs.com:6379/0/cache', { expires_in: 90.minutes }
config.cache_store = :redis_store, 'redis://10.9.72.102:6379/0/cache', { expires_in: 90.minutes }
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
address: 'smtp.exmail.qq.com',
port: 25,
domain: 'smtp.qq.com',
user_name: 'educoder@trustie.org',
password: 'mAZc9EWbe2Kawaqo2',
authentication: 'login',
enable_starttls_auto: true }
end

@ -93,6 +93,7 @@
Challenge:
"1_end": "赞了你发布的实训任务:%s第%s关"
"2_end": "踩了你发布的实训任务:%s第%s关"
Hack_end: "赞了你发布的题目:%s"
Memo:
true_end: "赞了你的评论:%s"
false_end: "赞了发布的帖子:%s"
@ -107,8 +108,16 @@
Issue_end: "赞了你发布的项目Issue%s"
Journal_end: "赞了你的回复%s"
Discuss:
true_end: "评论了你的回复:%s"
false_end: "评论了你发布的实训:%s"
Challenge:
true_end: "评论了你的回复:%s"
false_end: "评论了你发布的实训:%s"
Hack:
true_end: "评论了你的回复:%s"
false_end: "评论了你发布的题目:%s"
Hack:
HackPublish_end: "你发布了题目:%s"
HackUnPublish_end: "你撤销发布了题目:%s"
HackDelete_end: "你删除了题目:%s"
Grade:
Avatar_end: "首次上传头像获得金币奖励:%s金币"
Phone_end: "首次绑定手机号码获得金币奖励:%s金币"
@ -118,6 +127,7 @@
Answer:
true_end: "查看实训%s第%s关的参考答案消耗金币%s金币"
false_end: "查看实训的参考答案消耗金币:%s金币"
Hack_end: "完成题目解答:%s获得金币奖励%s金币"
Game_end: "通过实训%s的第%s关获得金币奖励%s金币"
Memo_end: "发布的评论或者帖子获得平台奖励:%s金币"
Discusses_end: "发布的评论获得金币奖励:%s金币"

@ -15,6 +15,7 @@ Rails.application.routes.draw do
scope '/api' do
get 'home/index'
get 'home/search'
get 'main/first_stamp'
get 'search', to: 'searchs#index'
@ -71,7 +72,12 @@ Rails.application.routes.draw do
delete :delete_set
end
resources :comments do
post :reply
collection do
post :reply
end
member do
post :hidden
end
end
end
@ -85,6 +91,7 @@ Rails.application.routes.draw do
get :submit_records
post :restore_initial_code
post :sync_code
post :add_notes
end
collection do
@ -272,6 +279,7 @@ Rails.application.routes.draw do
post :set_secret_dir
post :commits
post :file_content
post :upload_git_file
post :update_file
post :close
post :add_file
@ -506,6 +514,7 @@ Rails.application.routes.draw do
post :alter_name
get :update_score
get :update_student_score
post :batch_comment
end
collection do
@ -1330,6 +1339,7 @@ Rails.application.routes.draw do
root 'main#index'
## react用
get '*path', to: 'main#index', constraints: ReactConstraint.new
end

@ -0,0 +1,5 @@
class AddForkReasonToShixunInfo < ActiveRecord::Migration[5.2]
def change
add_column :shixun_infos, :fork_reason, :string
end
end

@ -0,0 +1,8 @@
class ModifyTaskPassForChallenges < ActiveRecord::Migration[5.2]
def change
Challenge.find_each do |challenge|
task_pass = challenge.task_pass.gsub(" ", "").gsub("rac", '\frac')
challenge.update_attribute(:task_pass, task_pass)
end
end
end

@ -0,0 +1,6 @@
class AddPraisesCountForHacks < ActiveRecord::Migration[5.2]
def change
add_column :hacks, :praises_count, :integer, :default => 0
add_column :hacks, :comments_count, :integer, :default => 0
end
end

@ -0,0 +1,5 @@
class ModifyOpenOrNotForHacks < ActiveRecord::Migration[5.2]
def change
change_column :hacks, :open_or_not, :boolean, :default => false
end
end

@ -0,0 +1,5 @@
class AddNotesHackUserLastestCodes < ActiveRecord::Migration[5.2]
def change
add_column :hack_user_lastest_codes, :notes, :longtext
end
end

@ -0,0 +1,8 @@
class ModifyTaskPass2ForChallenges < ActiveRecord::Migration[5.2]
def change
challenges = Challenge.where("task_pass like '%frac%'")
challenges.find_each do |c|
c.update_column(:task_pass, c.task_pass.gsub('\f\frac', '\frac'))
end
end
end

@ -0,0 +1,5 @@
class AddErrorTestSetIdForHackUserLastest < ActiveRecord::Migration[5.2]
def change
add_column :hack_user_codes, :error_test_set_id, :integer
end
end

@ -0,0 +1,9 @@
class AddIsShixunMarkerForUsers < ActiveRecord::Migration[5.2]
def change
add_column :users, :is_shixun_marker, :boolean, :default => false
User.joins(:user_extension)
.where(users: {professional_certification: 1}, user_extensions: {identity: 0})
.update_all(is_shixun_marker: 1)
end
end

@ -0,0 +1,5 @@
class AddBatchCommentToShixunWork < ActiveRecord::Migration[5.2]
def change
add_column :shixun_work_comments, :batch_comment, :boolean, default: 0
end
end

@ -0,0 +1,20 @@
class ModifyCourseGroupForCourses < ActiveRecord::Migration[5.2]
def change
groups = CourseGroup.where(course_id:3429).order("created_at desc").group(:name)
ActiveRecord::Base.transaction do
groups.each do |g|
CourseGroup.where(name: g.name).where.not(id: g.id).each do |cg|
cg.course_members.each do |cm|
cm.update_attributes!(course_group_id: g.id)
end
cg.exercise_group_settings.update_all(course_group_id: g.id)
cg.attachment_group_settings.update_all(course_group_id: g.id)
cg.homework_group_reviews.update_all(course_group_id: g.id)
cg.homework_group_settings.update_all(course_group_id: g.id)
cg.teacher_course_groups.update_all(course_group_id: g.id)
cg.destroy!
end
end
end
end
end

@ -14,19 +14,19 @@ namespace :excellent_course_exercise do
course = Course.find_by(id: course_id)
course.exercises.each_with_index do |exercise, index|
# if exercise.exercise_users.where(commit_status: 1).count == 0
if exercise.exercise_users.where(commit_status: 1).count == 0
# 第一个试卷的参与人数和通过人数都是传的数据,后续的随机
if index == 0
members = course.students.order("id asc").limit(participant_count)
update_exercise_user(exercise, members, pass_count)
else
new_participant_count = rand((participant_count - 423)..participant_count)
new_pass_count = rand((new_participant_count - 113)..new_participant_count)
new_participant_count = rand((participant_count - 20)..participant_count)
new_pass_count = rand((new_participant_count - 30)..new_participant_count)
members = course.students.order("id asc").limit(new_participant_count)
update_exercise_user(exercise, members, new_pass_count)
end
# end
end
end
end
@ -36,14 +36,15 @@ namespace :excellent_course_exercise do
# index < pass_count 之前的学生都是通关的,之后的未通过
members.each_with_index do |member, index|
exercise_user = exercise.exercise_users.where(user_id: member.user_id).take
if exercise_question_ids.length == 20
question_length = exercise_question_ids.length
if question_length == 20
rand_num = index < pass_count - 1 ? rand(15..20) : rand(1..10)
elsif exercise_question_ids.length == 17
elsif question_length == 17
rand_num = index < pass_count - 1 ? rand(12..17) : rand(1..9)
elsif exercise_question_ids.length == 39
elsif question_length == 39
rand_num = index < pass_count - 1 ? rand(30..39) : rand(1..18)
else
rand_num = exercise_question_ids.length
rand_num = index < pass_count - 1 ? rand((question_length-3)..question_length) : rand(1..(question_length-8))
end
if exercise_user && exercise_user.commit_status == 0

@ -0,0 +1,32 @@
# 执行示例 RAILS_ENV=production bundle exec rake migrate_course_student:student args=3835,2526,21950,1000
# args 第一个课程 course_id第二个参数是学校school_id第三个参数是部门id第四个参数是迁移数量
#
desc "同步学校的学生"
namespace :migrate_course_student do
if ENV['args']
course_id = ENV['args'].split(",")[0] # 对应课堂的id
school_id = ENV['args'].split(",")[1] # 对应学校id
department_id = ENV['args'].split(",")[2] # 对应部门id
limit = ENV['args'].split(",")[3] # 限制导入的数量
end
task :student => :environment do
course = Course.find course_id
users = User.joins(:user_extension).where(user_extensions: {school_id: school_id, department_id: department_id, identity: 1}).limit(limit)
user_ids = []
users.each do |user|
if user.student_id.present? && !course.students.exists?(user_id: user.id)
begin
CourseMember.create!(course_id: course_id, user_id: user.id, role: 4)
user_ids << user.id
rescue Exception => e
Rails.logger(e.message)
end
end
end
CourseAddStudentCreateWorksJob.perform_later(course_id, user_ids)
end
end

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

@ -37,9 +37,9 @@ document.addEventListener('keydown', (e) => {
if(e.data==="stopParent"){
//重置停止
timebool=false;
console.log("父窗口调用停止");
// console.log("父窗口调用停止");
}else if(e.data==="clonsParent"){
console.log("父窗口调用启动");
// console.log("父窗口调用启动");
//取消启动
timebool=true;
// runEvery10Sec();

@ -30,7 +30,7 @@ const env = getClientEnvironment(publicUrl);
module.exports = {
// You may want 'eval' instead if you prefer to see the compiled output in DevTools.
// See the discussion in https://github.com/facebookincubator/create-react-app/issues/343.s
// devtool: "cheap-module-eval-source-map",
//devtool: "cheap-module-eval-source-map",
// 开启调试
//devtool: "source-map", // 开启调试
// These are the "entry points" to our application.

@ -49,6 +49,7 @@
"lodash": "^4.17.5",
"loglevel": "^1.6.1",
"material-ui": "^1.0.0-beta.40",
"md5": "^2.2.1",
"moment": "^2.23.0",
"monaco-editor": "^0.15.6",
"monaco-editor-webpack-plugin": "^1.7.0",

@ -1883,9 +1883,8 @@ a:hover.task_icons_close{background: url(../images/popup/sy_icons_close.png) -40
.newupload_nav li:last-child{ border-right: none;}
.newupload_nav li a{font-size:12px; color:#444;}
.newupload_nav_hover{ background: #3498db; }
.newupload_nav_nomal { }
.newupload_nav_hover a{color: #fff !important; }
.markdown-body { text-align: justify;word-break: break-all;}
.bor-reds{
border:1px solid #FF0000!important;
border-radius: 4px;
@ -1894,6 +1893,7 @@ a:hover.task_icons_close{background: url(../images/popup/sy_icons_close.png) -40
border-bottom-right-radius: 4px;
border-bottom-left-radius: 4px;
}
@charset "UTF-8";
/*!

@ -1242,6 +1242,12 @@
<div class="code-name">&amp;#xe6c8;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe70f;</span>
<div class="name">减号</div>
<div class="code-name">&amp;#xe70f;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe60f;</span>
<div class="name">工程</div>
@ -1758,6 +1764,108 @@
<div class="code-name">&amp;#xe6d9;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe701;</span>
<div class="name">缩小</div>
<div class="code-name">&amp;#xe701;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe707;</span>
<div class="name">放大</div>
<div class="code-name">&amp;#xe707;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe709;</span>
<div class="name">编辑</div>
<div class="code-name">&amp;#xe709;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe70b;</span>
<div class="name">公开</div>
<div class="code-name">&amp;#xe70b;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe70c;</span>
<div class="name">解析</div>
<div class="code-name">&amp;#xe70c;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe70d;</span>
<div class="name">删除</div>
<div class="code-name">&amp;#xe70d;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe70e;</span>
<div class="name">试题栏</div>
<div class="code-name">&amp;#xe70e;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe710;</span>
<div class="name">复制</div>
<div class="code-name">&amp;#xe710;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe711;</span>
<div class="name">编组</div>
<div class="code-name">&amp;#xe711;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe712;</span>
<div class="name">左右拖动</div>
<div class="code-name">&amp;#xe712;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe713;</span>
<div class="name">上下拖动</div>
<div class="code-name">&amp;#xe713;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe714;</span>
<div class="name">试卷</div>
<div class="code-name">&amp;#xe714;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe715;</span>
<div class="name">删除</div>
<div class="code-name">&amp;#xe715;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe716;</span>
<div class="name">减去</div>
<div class="code-name">&amp;#xe716;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe717;</span>
<div class="name">加上</div>
<div class="code-name">&amp;#xe717;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe718;</span>
<div class="name">减去2</div>
<div class="code-name">&amp;#xe718;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe719;</span>
<div class="name">加上2</div>
<div class="code-name">&amp;#xe719;</div>
</li>
</ul>
<div class="article markdown">
<h2 id="unicode-">Unicode 引用</h2>
@ -3626,6 +3734,15 @@
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-jianhao"></span>
<div class="name">
减号
</div>
<div class="code-name">.icon-jianhao
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-gongcheng"></span>
<div class="name">
@ -4400,6 +4517,159 @@
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-suoxiao2"></span>
<div class="name">
缩小
</div>
<div class="code-name">.icon-suoxiao2
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-fangda"></span>
<div class="name">
放大
</div>
<div class="code-name">.icon-fangda
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-bianji2"></span>
<div class="name">
编辑
</div>
<div class="code-name">.icon-bianji2
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-gongkai"></span>
<div class="name">
公开
</div>
<div class="code-name">.icon-gongkai
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-jiexi"></span>
<div class="name">
解析
</div>
<div class="code-name">.icon-jiexi
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-shanchu1"></span>
<div class="name">
删除
</div>
<div class="code-name">.icon-shanchu1
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-shitilan"></span>
<div class="name">
试题栏
</div>
<div class="code-name">.icon-shitilan
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-fuzhi3"></span>
<div class="name">
复制
</div>
<div class="code-name">.icon-fuzhi3
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-bianzu2"></span>
<div class="name">
编组
</div>
<div class="code-name">.icon-bianzu2
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-zuoyoutuodong"></span>
<div class="name">
左右拖动
</div>
<div class="code-name">.icon-zuoyoutuodong
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-shangxiatuodong"></span>
<div class="name">
上下拖动
</div>
<div class="code-name">.icon-shangxiatuodong
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-shijuan1"></span>
<div class="name">
试卷
</div>
<div class="code-name">.icon-shijuan1
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-shanchu2"></span>
<div class="name">
删除
</div>
<div class="code-name">.icon-shanchu2
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-jianqu"></span>
<div class="name">
减去
</div>
<div class="code-name">.icon-jianqu
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-jiashang"></span>
<div class="name">
加上
</div>
<div class="code-name">.icon-jiashang
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-jianqu1"></span>
<div class="name">
减去2
</div>
<div class="code-name">.icon-jianqu1
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-jiashang1"></span>
<div class="name">
加上2
</div>
<div class="code-name">.icon-jiashang1
</div>
</li>
</ul>
<div class="article markdown">
<h2 id="font-class-">font-class 引用</h2>
@ -6045,6 +6315,14 @@
<div class="code-name">#icon-pinglun</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-jianhao"></use>
</svg>
<div class="name">减号</div>
<div class="code-name">#icon-jianhao</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-gongcheng"></use>
@ -6733,6 +7011,142 @@
<div class="code-name">#icon-zhiding</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-suoxiao2"></use>
</svg>
<div class="name">缩小</div>
<div class="code-name">#icon-suoxiao2</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-fangda"></use>
</svg>
<div class="name">放大</div>
<div class="code-name">#icon-fangda</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-bianji2"></use>
</svg>
<div class="name">编辑</div>
<div class="code-name">#icon-bianji2</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-gongkai"></use>
</svg>
<div class="name">公开</div>
<div class="code-name">#icon-gongkai</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-jiexi"></use>
</svg>
<div class="name">解析</div>
<div class="code-name">#icon-jiexi</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-shanchu1"></use>
</svg>
<div class="name">删除</div>
<div class="code-name">#icon-shanchu1</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-shitilan"></use>
</svg>
<div class="name">试题栏</div>
<div class="code-name">#icon-shitilan</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-fuzhi3"></use>
</svg>
<div class="name">复制</div>
<div class="code-name">#icon-fuzhi3</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-bianzu2"></use>
</svg>
<div class="name">编组</div>
<div class="code-name">#icon-bianzu2</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-zuoyoutuodong"></use>
</svg>
<div class="name">左右拖动</div>
<div class="code-name">#icon-zuoyoutuodong</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-shangxiatuodong"></use>
</svg>
<div class="name">上下拖动</div>
<div class="code-name">#icon-shangxiatuodong</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-shijuan1"></use>
</svg>
<div class="name">试卷</div>
<div class="code-name">#icon-shijuan1</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-shanchu2"></use>
</svg>
<div class="name">删除</div>
<div class="code-name">#icon-shanchu2</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-jianqu"></use>
</svg>
<div class="name">减去</div>
<div class="code-name">#icon-jianqu</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-jiashang"></use>
</svg>
<div class="name">加上</div>
<div class="code-name">#icon-jiashang</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-jianqu1"></use>
</svg>
<div class="name">减去2</div>
<div class="code-name">#icon-jianqu1</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-jiashang1"></use>
</svg>
<div class="name">加上2</div>
<div class="code-name">#icon-jiashang1</div>
</li>
</ul>
<div class="article markdown">
<h2 id="symbol-">Symbol 引用</h2>

@ -360,7 +360,7 @@ label.infolabel{display: block;float: left;width: 56px;text-align: right;margin-
.subshaicontent a{float: left;margin-right: 20px;color: #999;cursor: pointer}
.search-new{width: 248px;height:32px;position: relative;margin-right: 35px;}
.search-new{width: 248px;height:32px;position: relative;}
.search-span{display: block;position: absolute;width: 100%;height: 100%;left:0px;top:0px;background-color: #F4F4F4;border: 1px solid #EAEAEA; border-radius: 4px;z-index: 1}
.search-new-input{height: 32px;padding-left: 5px;width: 225px;border: none;box-sizing: border-box;background: none;outline: none;position: absolute;left:0px;top:1px;z-index: 2}
.search-new img,.search-new a,.search-new .searchicon{cursor: pointer;position: absolute;right:2px;top:2px;z-index: 2}
@ -397,9 +397,9 @@ label.infolabel{display: block;float: left;width: 56px;text-align: right;margin-
.task-colspan{min-width:25%;text-align: left;display: block;float: left;color: #999; }
.colspan-grey{border-radius: 12px;background-color: #E6E6E6;padding: 3px 10px;color: #747A7F}
/*新建任务*/
.challenge_nav{padding: 40px 20px 0px 20px;border-bottom: 1px solid #eee;}
.challenge_nav li{width: auto;float: left;margin-right: 40px;position: relative}
.challenge_nav li.active:after{position: absolute;content: '';width: 50%;background-color: #4CACFF;height: 3px;border-radius: 2px;left: 25%;bottom: 0px;}
.challenge_nav{padding: 20px 20px 0px 20px;border-bottom: 1px solid #eee;}
.challenge_nav li{width: auto;float: left;margin-right: 20px;position: relative}
.challenge_nav li.active:after{position: absolute;content: '';width: 76%;background-color: #4CACFF;height: 3px;border-radius: 2px;left: 25%;bottom: 0px;}
.challenge_nav li a{display: block;width: 100%;padding-bottom: 20px;}
.add_choose_type{width: 60px;height: 20px;line-height: 19px;border-radius: 2px;background-color: #eaeaea;color: #999!important;display: block;float: left;text-align: center;margin-top: 4px;}
@ -524,7 +524,7 @@ li.li-width15{width: 15%;text-align: left}
li.li-width7{width: 7%;text-align: left}
/*-----------------------------在线课堂动态----------------------------------*/
.courseHead{width: 100%;margin-bottom:40px;background-size: 100% 100%;background-image: url("/images/educoder/course-detail.jpg");height: 240px;
.courseHead{width: 100%;margin-bottom:40px;background-size: 100% 100%;background-image: url("/images/educoder/courtailsbdpicture.jpg");height: 240px;
justify-content: center;align-items: center;display: -webkit-flex;
background-size: cover;
background-position: center;
@ -2934,7 +2934,7 @@ a.singlepublishtwo{
padding: 40px !important;
}
.editormd-html-preview{
width: 94% !important;
width: 100% !important;
color: #323232 !important;
}
#homework_editorMd_description hr{
@ -3478,3 +3478,22 @@ a.singlepublishtwo{
/*width: auto !important;*/
/*max-width: 600px !important;*/
/*}*/
.markdown-body {
text-align: justify;
word-break: break-all;
}
.RightPaneDrawer .ant-drawer-content{
background: #070f1a;
overflow: hidden !important;
}
.deletebuttom{
border: transparent;
}
.RightPaneDrawer .jupyter_data_list{
max-height: 340px;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1419,6 +1419,13 @@
"unicode": "e6c8",
"unicode_decimal": 59080
},
{
"icon_id": "7556166",
"name": "减号",
"font_class": "jianhao",
"unicode": "e70f",
"unicode_decimal": 59151
},
{
"icon_id": "7587940",
"name": "工程",
@ -2020,6 +2027,125 @@
"font_class": "zhiding",
"unicode": "e6d9",
"unicode_decimal": 59097
},
{
"icon_id": "12403050",
"name": "缩小",
"font_class": "suoxiao2",
"unicode": "e701",
"unicode_decimal": 59137
},
{
"icon_id": "12403054",
"name": "放大",
"font_class": "fangda",
"unicode": "e707",
"unicode_decimal": 59143
},
{
"icon_id": "12491363",
"name": "编辑",
"font_class": "bianji2",
"unicode": "e709",
"unicode_decimal": 59145
},
{
"icon_id": "12491366",
"name": "公开",
"font_class": "gongkai",
"unicode": "e70b",
"unicode_decimal": 59147
},
{
"icon_id": "12491369",
"name": "解析",
"font_class": "jiexi",
"unicode": "e70c",
"unicode_decimal": 59148
},
{
"icon_id": "12491370",
"name": "删除",
"font_class": "shanchu1",
"unicode": "e70d",
"unicode_decimal": 59149
},
{
"icon_id": "12491850",
"name": "试题栏",
"font_class": "shitilan",
"unicode": "e70e",
"unicode_decimal": 59150
},
{
"icon_id": "12568379",
"name": "复制",
"font_class": "fuzhi3",
"unicode": "e710",
"unicode_decimal": 59152
},
{
"icon_id": "12608142",
"name": "编组",
"font_class": "bianzu2",
"unicode": "e711",
"unicode_decimal": 59153
},
{
"icon_id": "12608146",
"name": "左右拖动",
"font_class": "zuoyoutuodong",
"unicode": "e712",
"unicode_decimal": 59154
},
{
"icon_id": "12608147",
"name": "上下拖动",
"font_class": "shangxiatuodong",
"unicode": "e713",
"unicode_decimal": 59155
},
{
"icon_id": "12621166",
"name": "试卷",
"font_class": "shijuan1",
"unicode": "e714",
"unicode_decimal": 59156
},
{
"icon_id": "12621173",
"name": "删除",
"font_class": "shanchu2",
"unicode": "e715",
"unicode_decimal": 59157
},
{
"icon_id": "12621174",
"name": "减去",
"font_class": "jianqu",
"unicode": "e716",
"unicode_decimal": 59158
},
{
"icon_id": "12621177",
"name": "加上",
"font_class": "jiashang",
"unicode": "e717",
"unicode_decimal": 59159
},
{
"icon_id": "12621395",
"name": "减去2",
"font_class": "jianqu1",
"unicode": "e718",
"unicode_decimal": 59160
},
{
"icon_id": "12621396",
"name": "加上2",
"font_class": "jiashang1",
"unicode": "e719",
"unicode_decimal": 59161
}
]
}

@ -626,6 +626,9 @@ Created by iconfont
<glyph glyph-name="pinglun" unicode="&#59080;" d="M896 704H128c-35.2 0-64-28.8-64-64v-448c0-35.2 28.8-64 64-64h256l128-64 128 64h256c35.2 0 64 28.8 64 64V640c0 35.2-28.8 64-64 64zM304 368c-26.5 0-48 21.5-48 48s21.5 48 48 48 48-21.5 48-48-21.5-48-48-48z m208 0c-26.5 0-48 21.5-48 48s21.5 48 48 48 48-21.5 48-48-21.5-48-48-48z m208 0c-26.5 0-48 21.5-48 48s21.5 48 48 48 48-21.5 48-48-21.5-48-48-48z" horiz-adv-x="1024" />
<glyph glyph-name="jianhao" unicode="&#59151;" d="M768 341.333333H256c-25.6 0-42.666667 17.066667-42.666667 42.666667s17.066667 42.666667 42.666667 42.666667h512c25.6 0 42.666667-17.066667 42.666667-42.666667s-17.066667-42.666667-42.666667-42.666667z" horiz-adv-x="1024" />
<glyph glyph-name="gongcheng" unicode="&#58895;" d="M141.9 476.8L454.1 298c18.2-10.6 38.9-16.3 59.9-16.3 21.2 0 41.7 5.6 59.4 16.3l312.4 178.6c21.7 11.8 35.2 36.5 34.5 63.1-0.8 26.2-15.4 50.2-37.4 61.2L567.3 758.4c-33.9 16.9-72.8 16.9-106.6 0L144.9 600.8c-22.5-11.6-36.4-34.5-37.2-61.1-0.8-26.3 12.3-50.4 34.2-62.9z m22.3 85.9l315.6 157.5c10.9 5.4 22.5 8.2 34.2 8.2 11.7 0 23.4-2.7 34.2-8.2l315.5-157.5c8.1-4 13.5-13.6 13.8-24.2 0.3-10.6-4.5-20.2-12.2-24.3L552 335l-0.5-0.3c-11-6.7-24-10.2-37.5-10.2s-26.7 3.6-38.5 10.5L163.1 513.8c-8 4.6-13 14.3-12.7 24.6 0.3 10.9 5.6 20 13.8 24.3zM888.4 249.7l-369-211c-3.5-2-7.1-2-10.7 0.1L139.6 249.7c-10.3 5.9-23.3 2.3-29.1-7.9-5.9-10.2-2.3-23.3 7.9-29.1l368.8-210.8c8.4-4.9 17.6-7.3 26.7-7.3 9.2 0 18.3 2.4 26.6 7.2l368.9 210.9c10.2 5.9 13.8 18.9 7.9 29.1-5.6 10.2-18.7 13.8-28.9 7.9zM888.4 387.1l-369-211c-3.5-2-7.1-2-10.7 0.1L139.6 387.1c-10.3 5.9-23.3 2.3-29.1-7.9-5.9-10.2-2.3-23.3 7.9-29.1l368.8-210.8c8.4-4.9 17.6-7.3 26.7-7.3 9.2 0 18.3 2.4 26.6 7.2L909.6 350c10.2 5.9 13.8 18.9 7.9 29.1-5.8 10.3-18.9 13.8-29.1 8z" horiz-adv-x="1024" />
@ -884,6 +887,57 @@ Created by iconfont
<glyph glyph-name="zhiding" unicode="&#59097;" d="M496.0256 671.232L129.024 212.48A20.48 20.48 0 0 1 144.9984 179.2H337.92c11.264 0 20.48-9.216 20.48-20.48v-266.24c0-11.264 9.216-20.48 20.48-20.48h266.24a20.48 20.48 0 0 1 20.48 20.48V158.72c0 11.264 9.216 20.48 20.48 20.48h192.9216a20.48 20.48 0 0 1 15.9744 33.28l-367.0016 458.752a20.48 20.48 0 0 1-31.9488 0zM153.6 896m51.2 0l614.4 0q51.2 0 51.2-51.2l0 0q0-51.2-51.2-51.2l-614.4 0q-51.2 0-51.2 51.2l0 0q0 51.2 51.2 51.2Z" horiz-adv-x="1024" />
<glyph glyph-name="suoxiao2" unicode="&#59137;" d="M921.6 418.133333h-318.577778c-5.688889 0-17.066667 0-22.755555 5.688889-5.688889 0-11.377778 5.688889-17.066667 11.377778-5.688889 5.688889-11.377778 11.377778-11.377778 17.066667 0 5.688889-5.688889 11.377778-5.688889 22.755555V793.6c0 34.133333 22.755556 56.888889 56.888889 56.888889s56.888889-22.755556 56.888889-56.888889V611.555556L927.288889 878.933333c22.755556 22.755556 56.888889 22.755556 79.644444 0s22.755556-56.888889 0-79.644444L739.555556 531.911111h182.044444c34.133333 0 56.888889-22.755556 56.888889-56.888889s-22.755556-56.888889-56.888889-56.888889zM56.888889-128c-17.066667 0-28.444444 5.688889-39.822222 17.066667-22.755556 22.755556-22.755556 56.888889 0 79.644444L284.444444 236.088889H102.4c-34.133333 0-56.888889 22.755556-56.888889 56.888889s22.755556 56.888889 56.888889 56.888889h318.577778c5.688889 0 17.066667 0 22.755555-5.688889 5.688889 0 11.377778-5.688889 17.066667-11.377778 5.688889-5.688889 11.377778-11.377778 11.377778-17.066667 0-5.688889 5.688889-11.377778 5.688889-22.755555v-318.577778c0-34.133333-22.755556-56.888889-56.888889-56.888889s-56.888889 22.755556-56.888889 56.888889V156.444444l-267.377778-267.377777c-11.377778-11.377778-22.755556-17.066667-39.822222-17.066667z" horiz-adv-x="1024" />
<glyph glyph-name="fangda" unicode="&#59143;" d="M603.022222 418.133333c-17.066667 0-28.444444 5.688889-39.822222 17.066667-22.755556 22.755556-22.755556 56.888889 0 79.644444L830.577778 782.222222h-182.044445c-34.133333 0-56.888889 22.755556-56.888889 56.888889s22.755556 56.888889 56.888889 56.888889H967.111111c5.688889 0 17.066667 0 22.755556-5.688889 5.688889 0 11.377778-5.688889 17.066666-11.377778 5.688889-5.688889 11.377778-11.377778 11.377778-17.066666 5.688889-5.688889 5.688889-17.066667 5.688889-22.755556v-318.577778c0-34.133333-22.755556-56.888889-56.888889-56.888889s-56.888889 22.755556-56.888889 56.888889V702.577778l-267.377778-267.377778c-11.377778-11.377778-22.755556-17.066667-39.822222-17.066667zM375.466667-128H56.888889c-5.688889 0-17.066667 0-22.755556 5.688889-5.688889 0-11.377778 5.688889-17.066666 11.377778-5.688889 5.688889-11.377778 11.377778-11.377778 17.066666-5.688889 5.688889-5.688889 17.066667-5.688889 22.755556v318.577778c0 34.133333 22.755556 56.888889 56.888889 56.888889s56.888889-22.755556 56.888889-56.888889v-182.044445l267.377778 267.377778c22.755556 22.755556 56.888889 22.755556 79.644444 0s22.755556-56.888889 0-79.644444L193.422222-14.222222h182.044445c34.133333 0 56.888889-22.755556 56.888889-56.888889s-22.755556-56.888889-56.888889-56.888889z" horiz-adv-x="1024" />
<glyph glyph-name="bianji2" unicode="&#59145;" d="M704.752941-97.882353H198.776471c-78.305882 0-138.541176 60.235294-138.541177 132.517647V667.105882c0 72.282353 66.258824 132.517647 138.541177 132.517647h319.247058c18.070588 0 30.117647-12.047059 30.117647-30.117647s-12.047059-24.094118-30.117647-24.094117H198.776471c-42.164706 0-78.305882-36.141176-78.305883-72.282353v-632.470588c0-42.164706 36.141176-72.282353 78.305883-72.282353h499.952941c42.164706 0 78.305882 36.141176 78.305882 72.282353V293.647059c0 18.070588 12.047059 30.117647 30.117647 30.117647s30.117647-12.047059 30.117647-30.117647v-259.011765c6.023529-72.282353-60.235294-132.517647-132.517647-132.517647zM313.223529 161.129412c-24.094118 0-54.211765 18.070588-60.235294 48.188235v30.117647l36.141177 126.494118 445.741176 445.741176c48.188235 48.188235 120.470588 48.188235 168.658824 0 48.188235-48.188235 48.188235-120.470588 0-168.658823l-445.741177-445.741177-126.494117-30.117647c-6.023529-6.023529-12.047059-6.023529-18.070589-6.023529z m36.141177 174.682353l-36.141177-114.447059 120.470589 30.117647 433.694117 433.694118c12.047059 12.047059 18.070588 24.094118 18.070589 42.164705 0 18.070588-6.023529 30.117647-18.070589 42.164706-24.094118 24.094118-60.235294 24.094118-84.329411 0L349.364706 335.811765z" horiz-adv-x="1024" />
<glyph glyph-name="gongkai" unicode="&#59147;" d="M512 42.666667C432.355556 42.666667 369.777778 105.244444 369.777778 184.888889S432.355556 327.111111 512 327.111111s142.222222-62.577778 142.222222-142.222222S591.644444 42.666667 512 42.666667z m0 227.555555c-45.511111 0-85.333333-39.822222-85.333333-85.333333S466.488889 99.555556 512 99.555556 597.333333 139.377778 597.333333 184.888889 557.511111 270.222222 512 270.222222zM256 469.333333c-17.066667 0-28.444444 11.377778-28.444444 28.444445V662.755556C244.622222 782.222222 352.711111 867.555556 483.555556 867.555556c142.222222 0 250.311111-96.711111 256-221.866667v-5.688889c0-17.066667-11.377778-28.444444-28.444445-28.444444s-28.444444 11.377778-28.444444 28.444444c-5.688889 96.711111-91.022222 170.666667-199.111111 170.666667-102.4 0-187.733333-68.266667-199.111112-153.6V497.777778c0-17.066667-11.377778-28.444444-28.444444-28.444445zM739.555556-128h-455.111112C176.355556-128 85.333333-36.977778 85.333333 71.111111v227.555556C85.333333 406.755556 176.355556 497.777778 284.444444 497.777778h455.111112c108.088889 0 199.111111-91.022222 199.111111-199.111111v-227.555556c0-108.088889-91.022222-199.111111-199.111111-199.111111z m-455.111112 568.888889C204.8 440.888889 142.222222 378.311111 142.222222 298.666667v-227.555556C142.222222-8.533333 204.8-71.111111 284.444444-71.111111h455.111112c79.644444 0 142.222222 62.577778 142.222222 142.222222v227.555556C881.777778 378.311111 819.2 440.888889 739.555556 440.888889h-455.111112z" horiz-adv-x="1024" />
<glyph glyph-name="jiexi" unicode="&#59148;" d="M506.311111-99.555556c-73.955556 0-147.911111 17.066667-216.177778 51.2-11.377778 5.688889-22.755556 22.755556-11.377777 39.822223 5.688889 11.377778 22.755556 22.755556 39.822222 11.377777 56.888889-28.444444 125.155556-45.511111 187.733333-45.511111 238.933333 0 432.355556 187.733333 432.355556 426.666667 0 85.333333-22.755556 164.977778-73.955556 233.244444-11.377778 11.377778-5.688889 28.444444 5.688889 39.822223 11.377778 11.377778 28.444444 5.688889 39.822222-5.688889 51.2-79.644444 79.644444-170.666667 79.644445-267.377778 5.688889-267.377778-216.177778-483.555556-483.555556-483.555556z m-301.511111 125.155556c-5.688889 0-11.377778 0-17.066667 5.688889C85.333333 122.311111 28.444444 253.155556 28.444444 389.688889 28.444444 651.377778 238.933333 867.555556 500.622222 867.555556c119.466667 0 233.244444-45.511111 318.577778-125.155556 11.377778-11.377778 11.377778-28.444444 0-39.822222-11.377778-11.377778-28.444444-11.377778-39.822222 0-79.644444 73.955556-176.355556 113.777778-278.755556 113.777778-227.555556 0-415.288889-187.733333-415.288889-420.977778 0-125.155556 51.2-238.933333 142.222223-318.577778 11.377778-11.377778 11.377778-28.444444 0-39.822222-5.688889-11.377778-11.377778-11.377778-22.755556-11.377778zM512 31.288889c-56.888889 0-102.4 45.511111-102.4 102.4v34.133333c-62.577778 34.133333-102.4 102.4-102.4 170.666667C307.2 446.577778 398.222222 537.6 512 537.6s204.8-91.022222 204.8-199.111111c0-68.266667-39.822222-136.533333-102.4-170.666667v-34.133333c0-51.2-39.822222-96.711111-91.022222-102.4H512z m0 449.422222c-79.644444 0-147.911111-62.577778-147.911111-142.222222 0-51.2 28.444444-96.711111 73.955555-125.155556l28.444445-17.066666v-68.266667c0-22.755556 17.066667-45.511111 45.511111-45.511111h5.688889c22.755556 0 39.822222 22.755556 39.822222 45.511111v68.266667l28.444445 17.066666c45.511111 22.755556 73.955556 73.955556 73.955555 125.155556 0 73.955556-68.266667 142.222222-147.911111 142.222222zM676.977778 497.777778c-5.688889 0-17.066667 0-22.755556 5.688889-11.377778 11.377778-11.377778 28.444444 0 39.822222L739.555556 628.622222c11.377778 11.377778 28.444444 11.377778 39.822222 0s11.377778-28.444444 0-39.822222l-85.333334-85.333333c-5.688889 0-11.377778-5.688889-17.066666-5.688889zM347.022222 497.777778c-5.688889 0-11.377778 5.688889-17.066666 5.688889L238.933333 594.488889c-11.377778 11.377778-11.377778 28.444444 0 39.822222s28.444444 11.377778 39.822223 0l85.333333-85.333333c11.377778-11.377778 11.377778-28.444444 0-39.822222 0-5.688889-5.688889-11.377778-17.066667-11.377778zM512 560.355556c-17.066667 0-28.444444 11.377778-28.444444 28.444444V685.511111c0 17.066667 11.377778 28.444444 28.444444 28.444445s28.444444-11.377778 28.444444-28.444445v-102.4c0-11.377778-11.377778-22.755556-28.444444-22.755555z" horiz-adv-x="1024" />
<glyph glyph-name="shanchu1" unicode="&#59149;" d="M672-96H358.4c-76.8 0-140.8 57.6-153.6 140.8L96 569.6c0 19.2 6.4 32 25.6 38.4 19.2 6.4 32-6.4 38.4-25.6l102.4-524.8c12.8-51.2 51.2-89.6 96-89.6h313.6c44.8 0 83.2 38.4 96 89.6l102.4 524.8c6.4 19.2 19.2 25.6 38.4 25.6 19.2-6.4 25.6-19.2 25.6-38.4L832 44.8c-19.2-83.2-83.2-140.8-160-140.8zM608 704v6.4c0 51.2-44.8 89.6-96 89.6S416 755.2 416 704h-64C352 793.6 422.4 864 512 864c83.2 0 153.6-64 160-153.6V704h-64zM384 38.4c-12.8 0-25.6 12.8-32 25.6L256 576c0 19.2 12.8 32 25.6 38.4 19.2 0 38.4-12.8 38.4-25.6l96-512c0-19.2-6.4-38.4-32-38.4 6.4 0 0 0 0 0zM640 38.4s-6.4 0 0 0c-25.6 6.4-32 19.2-32 38.4l96 512c0 19.2 19.2 32 38.4 25.6 12.8-6.4 25.6-19.2 25.6-38.4l-96-512c-6.4-12.8-19.2-25.6-32-25.6zM512 38.4c-19.2 0-32 12.8-32 32v512c0 19.2 12.8 32 32 32s32-12.8 32-32v-512c0-19.2-12.8-32-32-32zM992 640H32C12.8 640 0 652.8 0 672S12.8 704 32 704h960c19.2 0 32-12.8 32-32s-12.8-32-32-32z" horiz-adv-x="1024" />
<glyph glyph-name="shitilan" unicode="&#59150;" d="M816.118519-128H184.019753c-69.530864 0-126.419753 56.888889-126.419753 126.419753V756.938272C57.6 826.469136 114.488889 883.358025 184.019753 883.358025h568.888889l189.62963-189.62963v-695.308642c0-69.530864-56.888889-126.419753-126.419753-126.419753zM727.624691 820.148148H184.019753c-37.925926 0-63.209877-25.283951-63.209876-63.209876v-758.518519c0-37.925926 25.283951-63.209877 63.209876-63.209876h632.098766c37.925926 0 63.209877 25.283951 63.209876 63.209876V668.444444L727.624691 820.148148zM955.180247 662.123457h-189.62963c-25.283951 0-44.246914 18.962963-44.246913 44.246913l6.320987 189.62963 227.555556-233.876543z m-170.666667 82.172839v-18.962963h18.962963l-18.962963 18.962963zM670.735802 567.308642H329.402469c-18.962963 0-31.604938 12.641975-31.604938 31.604938S310.439506 630.518519 329.402469 630.518519h341.333333c18.962963 0 31.604938-12.641975 31.604939-31.604939s-12.641975-31.604938-31.604939-31.604938zM670.735802 314.469136H329.402469c-18.962963 0-31.604938 12.641975-31.604938 31.604938S310.439506 377.679012 329.402469 377.679012h341.333333c18.962963 0 31.604938-12.641975 31.604939-31.604938s-12.641975-31.604938-31.604939-31.604938zM670.735802 61.62963H329.402469c-18.962963 0-31.604938 12.641975-31.604938 31.604938s12.641975 31.604938 31.604938 31.604938h341.333333c18.962963 0 31.604938-12.641975 31.604939-31.604938s-12.641975-31.604938-31.604939-31.604938z" horiz-adv-x="1024" />
<glyph glyph-name="fuzhi3" unicode="&#59152;" d="M648.533333-128h-477.866666C75.093333-128 0-52.906667 0 42.666667v477.866666C0 616.106667 75.093333 691.2 170.666667 691.2h477.866666C744.106667 691.2 819.2 616.106667 819.2 520.533333v-477.866666c0-95.573333-75.093333-170.666667-170.666667-170.666667z m-477.866666 750.933333C116.053333 622.933333 68.266667 575.146667 68.266667 520.533333v-477.866666c0-54.613333 47.786667-102.4 102.4-102.4h477.866666c54.613333 0 102.4 47.786667 102.4 102.4v477.866666c0 54.613333-47.786667 102.4-102.4 102.4h-477.866666zM955.733333 110.933333c-20.48 0-34.133333 13.653333-34.133333 34.133334V691.2c0 54.613333-47.786667 102.4-102.4 102.4H273.066667c-20.48 0-34.133333 13.653333-34.133334 34.133333s13.653333 34.133333 34.133334 34.133334h546.133333c95.573333 0 170.666667-75.093333 170.666667-170.666667v-546.133333c0-20.48-13.653333-34.133333-34.133334-34.133334z" horiz-adv-x="1024" />
<glyph glyph-name="bianzu2" unicode="&#59153;" d="M512 353.882353m-240.941176 0a240.941176 240.941176 0 1 1 481.882352 0 240.941176 240.941176 0 1 1-481.882352 0ZM512 534.588235m-361.411765 0a361.411765 361.411765 0 1 1 722.82353 0 361.411765 361.411765 0 1 1-722.82353 0ZM402.552471 426.285176L279.491765 527.600941a9.035294 9.035294 0 0 0 0 13.974588l123.030588 101.315765a9.035294 9.035294 0 0 0 14.757647-6.987294v-52.103529a9.035294 9.035294 0 0 1 9.035294-9.035295h171.309177a9.035294 9.035294 0 0 1 9.035294 9.035295v52.103529a9.035294 9.035294 0 0 0 14.757647 6.987294l123.030588-101.315765a9.035294 9.035294 0 0 0 0-13.974588l-123.030588-101.315765a9.035294 9.035294 0 0 0-14.757647 6.987295v52.103529a9.035294 9.035294 0 0 1-9.035294 9.035294H426.345412a9.035294 9.035294 0 0 1-9.035294-9.035294v-52.103529a9.035294 9.035294 0 0 0-14.757647-6.987295z" horiz-adv-x="1024" />
<glyph glyph-name="zuoyoutuodong" unicode="&#59154;" d="M558.848-76.288L35.84 354.304a38.4 38.4 0 0 0 0 59.392L558.848 844.288a38.4 38.4 0 0 0 62.72-29.696v-221.44a38.4 38.4 0 0 1 38.4-38.4h728.064a38.4 38.4 0 0 1 38.4 38.4V814.464a38.4 38.4 0 0 0 62.72 29.696l522.88-430.592a38.4 38.4 0 0 0 0-59.392l-522.88-430.592a38.4 38.4 0 0 0-62.72 29.696v221.44a38.4 38.4 0 0 1-38.4 38.4H659.968a38.4 38.4 0 0 1-38.4-38.4v-221.44a38.4 38.4 0 0 0-62.72-29.696z" horiz-adv-x="2048" />
<glyph glyph-name="shangxiatuodong" unicode="&#59155;" d="M742.144 151.424L526.848-110.08a19.2 19.2 0 0 0-29.696 0L281.856 151.424a19.2 19.2 0 0 0 14.848 31.36h110.72a19.2 19.2 0 0 1 19.2 19.2V566.016a19.2 19.2 0 0 1-19.2 19.2H296.768a19.2 19.2 0 0 0-14.848 31.36L497.152 878.08a19.2 19.2 0 0 0 29.696 0l215.296-261.44a19.2 19.2 0 0 0-14.848-31.36h-110.72a19.2 19.2 0 0 1-19.2-19.2v-364.032a19.2 19.2 0 0 1 19.2-19.2h110.72a19.2 19.2 0 0 0 14.848-31.36z" horiz-adv-x="1024" />
<glyph glyph-name="shijuan1" unicode="&#59156;" d="M352.256 865.28h436.224c112.64 0 204.8-92.16 204.8-204.8v-552.96c0-112.64-92.16-204.8-204.8-204.8H352.256c-112.64 0-204.8 92.16-204.8 204.8v552.96c0 112.64 90.112 204.8 204.8 204.8zM788.48-128H352.256c-129.024 0-235.52 106.496-235.52 235.52v552.96C116.736 789.504 221.184 896 352.256 896h436.224C917.504 896 1024 789.504 1024 660.48v-552.96C1024-21.504 917.504-128 788.48-128zM352.256 834.56c-96.256 0-174.08-77.824-174.08-174.08v-552.96c0-96.256 77.824-174.08 174.08-174.08h436.224c96.256 0 174.08 77.824 174.08 174.08v552.96C962.56 756.736 884.736 834.56 788.48 834.56H352.256zM311.296 564.224m-40.96 0a40.96 40.96 0 1 1 81.92 0 40.96 40.96 0 1 1-81.92 0ZM311.296 332.8m-40.96 0a40.96 40.96 0 1 1 81.92 0 40.96 40.96 0 1 1-81.92 0ZM841.728 545.792H471.04c-16.384 0-30.72 14.336-30.72 30.72s14.336 30.72 30.72 30.72h370.688c16.384 0 30.72-14.336 30.72-30.72s-12.288-30.72-30.72-30.72zM841.728 314.368H471.04c-16.384 0-30.72 14.336-30.72 30.72s14.336 30.72 30.72 30.72h370.688c16.384 0 30.72-14.336 30.72-30.72s-12.288-30.72-30.72-30.72zM819.2-97.28c-26.624 32.768-43.008 61.44-47.104 88.064-4.096 24.576-2.048 59.392 8.192 104.448v6.144c0 16.384-14.336 30.72-30.72 30.72H61.44c-16.384 0-30.72-14.336-30.72-30.72v-83.968c0-63.488 51.2-114.688 114.688-114.688H819.2zM882.688-128h-737.28C65.536-128 0-62.464 0 17.408v83.968c0 34.816 26.624 61.44 61.44 61.44h688.128c34.816 0 61.44-26.624 61.44-61.44 0-4.096 0-8.192-2.048-12.288-8.192-43.008-10.24-73.728-8.192-94.208 4.096-18.432 16.384-43.008 40.96-73.728l40.96-49.152zM61.44 101.376v-83.968C61.44-29.696 98.304-66.56 145.408-66.56h614.4c-10.24 18.432-16.384 34.816-18.432 51.2-4.096 26.624-2.048 63.488 8.192 116.736H61.44z" horiz-adv-x="1024" />
<glyph glyph-name="shanchu2" unicode="&#59157;" d="M512 384m-512 0a512 512 0 1 1 1024 0 512 512 0 1 1-1024 0ZM665.6 179.2c-15.36 0-25.6 5.12-35.84 15.36L512 312.32l-117.76-117.76c-20.48-20.48-51.2-20.48-71.68 0s-20.48 51.2 0 71.68L440.32 384 322.56 501.76c-20.48 20.48-20.48 51.2 0 71.68s51.2 20.48 71.68 0L512 455.68l117.76 117.76c20.48 20.48 51.2 20.48 71.68 0s20.48-51.2 0-71.68L583.68 384l117.76-117.76c20.48-20.48 20.48-51.2 0-71.68-10.24-10.24-20.48-15.36-35.84-15.36z" horiz-adv-x="1024" />
<glyph glyph-name="jianqu" unicode="&#59158;" d="M512-128C228.693333-128 0 100.693333 0 384S228.693333 896 512 896s512-228.693333 512-512-228.693333-512-512-512z m0 989.866667C249.173333 861.866667 34.133333 646.826667 34.133333 384s215.04-477.866667 477.866667-477.866667 477.866667 215.04 477.866667 477.866667S774.826667 861.866667 512 861.866667zM699.733333 332.8h-375.466666c-20.48 0-34.133333 13.653333-34.133334 34.133333s13.653333 34.133333 34.133334 34.133334h375.466666c20.48 0 34.133333-13.653333 34.133334-34.133334s-13.653333-34.133333-34.133334-34.133333z" horiz-adv-x="1024" />
<glyph glyph-name="jiashang" unicode="&#59159;" d="M512-128C228.693333-128 0 100.693333 0 384S228.693333 896 512 896s512-228.693333 512-512-228.693333-512-512-512z m0 989.866667C249.173333 861.866667 34.133333 646.826667 34.133333 384s215.04-477.866667 477.866667-477.866667 477.866667 215.04 477.866667 477.866667S774.826667 861.866667 512 861.866667zM699.733333 332.8h-375.466666c-20.48 0-34.133333 13.653333-34.133334 34.133333s13.653333 34.133333 34.133334 34.133334h375.466666c20.48 0 34.133333-13.653333 34.133334-34.133334s-13.653333-34.133333-34.133334-34.133333zM512 145.066667c-20.48 0-34.133333 13.653333-34.133333 34.133333V554.666667c0 20.48 13.653333 34.133333 34.133333 34.133333s34.133333-13.653333 34.133333-34.133333v-375.466667c0-20.48-13.653333-34.133333-34.133333-34.133333z" horiz-adv-x="1024" />
<glyph glyph-name="jianqu1" unicode="&#59160;" d="M512-128C228.693333-128 0 100.693333 0 384S228.693333 896 512 896s512-228.693333 512-512-228.693333-512-512-512z m0 989.866667C249.173333 861.866667 34.133333 646.826667 34.133333 384s215.04-477.866667 477.866667-477.866667 477.866667 215.04 477.866667 477.866667S774.826667 861.866667 512 861.866667zM699.733333 332.8h-375.466666c-20.48 0-34.133333 13.653333-34.133334 34.133333s13.653333 34.133333 34.133334 34.133334h375.466666c20.48 0 34.133333-13.653333 34.133334-34.133334s-13.653333-34.133333-34.133334-34.133333z" horiz-adv-x="1024" />
<glyph glyph-name="jiashang1" unicode="&#59161;" d="M512-128C228.693333-128 0 100.693333 0 384S228.693333 896 512 896s512-228.693333 512-512-228.693333-512-512-512z m0 989.866667C249.173333 861.866667 34.133333 646.826667 34.133333 384s215.04-477.866667 477.866667-477.866667 477.866667 215.04 477.866667 477.866667S774.826667 861.866667 512 861.866667zM699.733333 332.8h-375.466666c-20.48 0-34.133333 13.653333-34.133334 34.133333s13.653333 34.133333 34.133334 34.133334h375.466666c20.48 0 34.133333-13.653333 34.133334-34.133334s-13.653333-34.133333-34.133334-34.133333zM512 145.066667c-20.48 0-34.133333 13.653333-34.133333 34.133333V554.666667c0 20.48 13.653333 34.133333 34.133333 34.133333s34.133333-13.653333 34.133333-34.133333v-375.466667c0-20.48-13.653333-34.133333-34.133333-34.133333z" horiz-adv-x="1024" />
</font>

Before

Width:  |  Height:  |  Size: 362 KiB

After

Width:  |  Height:  |  Size: 381 KiB

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

Loading…
Cancel
Save