diff --git a/app/controllers/item_baskets_controller.rb b/app/controllers/item_baskets_controller.rb index dc5367378..03355189d 100644 --- a/app/controllers/item_baskets_controller.rb +++ b/app/controllers/item_baskets_controller.rb @@ -12,13 +12,7 @@ class ItemBasketsController < ApplicationController end def basket_list - @single_questions_count = current_user.item_baskets.where(item_type: "SINGLE").count - @multiple_questions_count = current_user.item_baskets.where(item_type: "MULTIPLE").count - @judgement_questions_count = current_user.item_baskets.where(item_type: "JUDGMENT").count - @completion_questions_count = current_user.item_baskets.where(item_type: "COMPLETION").count - @subjective_questions_count = current_user.item_baskets.where(item_type: "SUBJECTIVE").count - @practical_questions_count = current_user.item_baskets.where(item_type: "PRACTICAL").count - @program_questions_count = current_user.item_baskets.where(item_type: "PROGRAM").count + @basket_count = current_user.item_baskets.group(:item_type).count end def create diff --git a/app/controllers/shixuns_controller.rb b/app/controllers/shixuns_controller.rb index 30de10b73..7e2a53742 100644 --- a/app/controllers/shixuns_controller.rb +++ b/app/controllers/shixuns_controller.rb @@ -1187,7 +1187,10 @@ private end def validate_wachat_support - tip_exception(-2, "..") if (params[:wechat].present? && !@shixun.is_wechat_support?) + + if (params[:wechat].present? && !@shixun.is_wechat_support?) + tip_exception(-5, "..") + end end end diff --git a/app/models/item_bank.rb b/app/models/item_bank.rb index 840f488d8..242b7de92 100644 --- a/app/models/item_bank.rb +++ b/app/models/item_bank.rb @@ -19,38 +19,26 @@ class ItemBank < ApplicationRecord end def apply? - !public && ApplyAction.where(container_type: "ItemBank", container_id: id, status: 0).exists? + !public && ApplyAction.exists?(container_type: "ItemBank", container_id: id, status: 0) end def type_string - result = case item_type - when "SINGLE" - "单选题" - when "MULTIPLE" - "多选题" - when "JUDGMENT" - "判断题" - when "COMPLETION" - "填空题" - when "SUBJECTIVE" - "简答题" - when "PRACTICAL" - "实训题" - when "PROGRAM" - "编程题" - end - result + case item_type + when "SINGLE" then "单选题" + when "MULTIPLE" then "多选题" + when "JUDGMENT" then "判断题" + when "COMPLETION" then "填空题" + when "SUBJECTIVE" then "简答题" + when "PRACTICAL" then "实训题" + when "PROGRAM" then "编程题" + end end def difficulty_string - result = case difficulty - when 1 - "简单" - when 2 - "适中" - when 3 - "困难" - end - result + case difficulty + when 1 then "简单" + when 2 then "适中" + when 3 then "困难" + end end end diff --git a/app/models/student_work.rb b/app/models/student_work.rb index 3aee0611b..f8f3bee99 100644 --- a/app/models/student_work.rb +++ b/app/models/student_work.rb @@ -223,7 +223,7 @@ class StudentWork < ApplicationRecord game_score = adjust_score.score elsif game.present? setting = homework_common.homework_group_setting game.user_id - if game.status == 2 && ((game.end_time && game.end_time < setting.end_time) || (homework_common.allow_late && game.end_time && game.end_time < homework_common.late_time)) + if game.status == 2 && ((game.end_time && setting.end_time && game.end_time < setting.end_time) || (homework_common.allow_late && homework_common.late_time && game.end_time && game.end_time < homework_common.late_time)) answer_open_evaluation = homework_common.homework_detail_manual.answer_open_evaluation game_score = answer_open_evaluation ? score : (game.final_score > 0 ? game.real_score(score) : 0) end diff --git a/app/queries/admins/shixun_settings_query.rb b/app/queries/admins/shixun_settings_query.rb index 1e45952bf..30a402d1c 100644 --- a/app/queries/admins/shixun_settings_query.rb +++ b/app/queries/admins/shixun_settings_query.rb @@ -51,6 +51,7 @@ class Admins::ShixunSettingsQuery < ApplicationQuery all_shixuns = all_shixuns.where(task_pass: params[:task_pass]) if params[:task_pass] all_shixuns = all_shixuns.where(code_hidden: params[:code_hidden]) if params[:code_hidden] all_shixuns = all_shixuns.where(vip: params[:vip]) if params[:vip] + all_shixuns = all_shixuns.where(is_wechat_support: params[:is_wechat_support]) if params[:is_wechat_support] custom_sort(all_shixuns, params[:sort_by], params[:sort_direction]) end diff --git a/app/views/admins/shixun_settings/index.html.erb b/app/views/admins/shixun_settings/index.html.erb index 16a02ab96..82d7fa3a1 100644 --- a/app/views/admins/shixun_settings/index.html.erb +++ b/app/views/admins/shixun_settings/index.html.erb @@ -71,6 +71,13 @@ 只看vip +
+ +
+ <% end %> diff --git a/app/views/item_baskets/basket_list.json.jbuilder b/app/views/item_baskets/basket_list.json.jbuilder index 11db844ab..4cb0d5592 100644 --- a/app/views/item_baskets/basket_list.json.jbuilder +++ b/app/views/item_baskets/basket_list.json.jbuilder @@ -1,7 +1,7 @@ -json.single_questions_count @single_questions_count -json.multiple_questions_count @multiple_questions_count -json.judgement_questions_count @judgement_questions_count -json.completion_questions_count @completion_questions_count -json.subjective_questions_count @subjective_questions_count -json.practical_questions_count @practical_questions_count -json.program_questions_count @program_questions_count +json.single_questions_count @basket_count&.fetch("SINGLE", 0) +json.multiple_questions_count @basket_count&.fetch("MULTIPLE", 0) +json.judgement_questions_count @basket_count&.fetch("JUDGMENT", 0) +json.completion_questions_count @basket_count&.fetch("COMPLETION", 0) +json.subjective_questions_count @basket_count&.fetch("SUBJECTIVE", 0) +json.practical_questions_count @basket_count&.fetch("PRACTICAL", 0) +json.program_questions_count @basket_count&.fetch("PROGRAM", 0) \ No newline at end of file diff --git a/lib/tasks/zip_pack.rake b/lib/tasks/zip_pack.rake index 393f7ab3c..2f11cfe5a 100644 --- a/lib/tasks/zip_pack.rake +++ b/lib/tasks/zip_pack.rake @@ -1,51 +1,78 @@ -# 执行示例 bundle exec rake zip_pack:shixun_pack args=123,2323 +# 执行示例 bundle exec rake zip_pack:shixun_pack class=Course ids=123,2323 +# 执行示例 bundle exec rake zip_pack:shixun_pack class=HomeworkCommon ids=123,2323 namespace :zip_pack do desc "手工打包作品" OUTPUT_FOLDER = "#{Rails.root}/files/archiveZip" task :shixun_pack => :environment do - if ENV['args'] - homework_ids = ENV['args'].split(",").map(&:to_i) - homeworks = HomeworkCommon.where(id: homework_ids) - homeworks.includes(:score_student_works).each do |homework| - out_file_name = "#{Time.now.strftime("%Y%m%d%H%M%S").to_s}-#{homework.course_id}-#{homework.name}.zip" - out_file_name.gsub!(" ", "-") - out_file_name.gsub!("/", "_") + if ENV['class'] && ENV['ids'] + env_ids = ENV['ids'].split(",").map(&:to_i) + folders = [] + if ENV['class'] == "Course" + courses = Course.where(id: env_ids) + courses.each do |course| + homeworks = course.practice_homeworks.homework_published + new_dir_name = "#{course.name.to_s.strip}_#{Time.now.strftime("%Y%m%d%H%M%S").to_s}" + new_dir_name.gsub!(" ", "-") + new_dir_name.gsub!("/", "_") + new_folder = "#{OUTPUT_FOLDER}/#{new_dir_name}" + zip_homework_pdf homeworks, new_folder + folders << new_folder + end + else + homeworks = HomeworkCommon.where(id: env_ids) + new_dir_name = "#{homeworks.first&.course&.name.to_s.strip}_#{Time.now.strftime("%Y%m%d%H%M%S").to_s}" + new_dir_name.gsub!(" ", "-") + new_dir_name.gsub!("/", "_") + new_folder = "#{OUTPUT_FOLDER}/#{new_dir_name}" + zip_homework_pdf homeworks, new_folder + folders << new_folder + end + + puts "下载路径: #{folders.join(",")}" + end + end - zipfile_name = "#{OUTPUT_FOLDER}/#{out_file_name}" - Dir.mkdir(File.dirname(zipfile_name)) unless File.exist?(File.dirname(zipfile_name)) + def zip_homework_pdf homeworks, folder + Dir.mkdir(folder) unless File.directory?(folder) - student_works = homework.score_student_works + homeworks.includes(:score_student_works).each do |homework| + out_file_name = "#{Time.now.strftime("%Y%m%d%H%M%S").to_s}-#{homework.course_id}-#{homework.name}.zip" + out_file_name.gsub!(" ", "-") + out_file_name.gsub!("/", "_") - if student_works.size > 0 - pdfs = [] - Zip::File.open(zipfile_name, Zip::File::CREATE) do |zip| - student_works.find_each.map do |student_work| - export = ExportShixunReportService.new(homework, student_work) - pdf = export.to_pdf - pdfs << pdf - begin - zip.add(export.filename, pdf.path) - puts "out: #{export.filename}_#{pdf.path}" - rescue => ex - Rails.logger.error(ex.message) + zipfile_name = "#{folder}/#{out_file_name}" + # Dir.mkdir(File.dirname(zipfile_name)) unless File.exist?(File.dirname(zipfile_name)) - zip.get_output_stream('FILE_NOTICE.txt'){|os| os.write("文件重复:#{export.filename}") } - next - end + student_works = homework.score_student_works + + if student_works.size > 0 + pdfs = [] + Zip::File.open(zipfile_name, Zip::File::CREATE) do |zip| + student_works.find_each.map do |student_work| + export = ExportShixunReportService.new(homework, student_work) + pdf = export.to_pdf + pdfs << pdf + begin + zip.add(export.filename, pdf.path) + puts "out: #{export.filename}_#{pdf.path}" + rescue => ex + Rails.logger.error(ex.message) + + zip.get_output_stream('FILE_NOTICE.txt'){|os| os.write("文件重复:#{export.filename}") } + next end end - zipfile = zipfile_name - else - zipfile = {:message => "no file"} end - puts "out: #{zipfile}" - + zipfile = zipfile_name + else + zipfile = {:message => "no file"} end end end + # 执行示例 bundle exec rake zip_pack:homework_attach_pack args=123 task :homework_attach_pack => :environment do include ExportHelper if ENV['args'] @@ -61,7 +88,4 @@ namespace :zip_pack do end end - def filename_for_content_disposition(name) - request.env['HTTP_USER_AGENT'] =~ %r{MSIE|Trident|Edge} ? ERB::Util.url_encode(name) : name - end end \ No newline at end of file diff --git a/public/react/package.json b/public/react/package.json index 25aa1d87f..a30780480 100644 --- a/public/react/package.json +++ b/public/react/package.json @@ -75,6 +75,7 @@ "react-codemirror": "^1.0.0", "react-codemirror2": "^6.0.0", "react-content-loader": "^3.1.1", + "react-cookies": "^0.1.1", "react-dev-utils": "^5.0.0", "react-dom": "^16.9.0", "react-hot-loader": "^4.0.0", diff --git a/public/react/src/App.js b/public/react/src/App.js index 247e7939b..96a4f91b0 100644 --- a/public/react/src/App.js +++ b/public/react/src/App.js @@ -366,6 +366,11 @@ const JupyterTPI = Loadable({ loader: () => import('./modules/tpm/jupyter'), loading: Loading }); +// 微信代码编辑器 +const WXCode = Loadable({ + loader: () => import('./modules/wxcode'), + loading: Loading +}); // //个人竞赛报名 // const PersonalCompetit = Loadable({ // loader: () => import('./modules/competition/personal/PersonalCompetit.js'), @@ -823,6 +828,11 @@ class App extends Component { render={ (props) => () }/> + () + } + /> { + + const { + isShow, + wxCode, + path, + showLoading, + // userCode, + testCase = [], + getWXCode, + last_compile_output, + test_sets_count, + sets_error_count, + getWXCodeTestCase, + restoreWXCode, + updateWXCodeForEditor, + updateWXCodeForInterval, + evaluateWxCode, + showWXCodeTextCase, + changeWXCodeEvaluateLoading + } = props; + + const {identifier} = props.match.params; + // 获取路径参数 + const _params = window.location.search; + if (_params) { + let _search = _params.split('?')[1]; + _search.split('&').forEach(item => { + console.log(item); + const _arr = item.split('='); + cookie.save(_arr[0], _arr[1], { + path: '/', + domain: '.educoder.net' + }); + }); + } + const [isActive, setIsActive] = useState(-1); + // const [isVisible, setIsVisible] = useState(false); + const editorRef = useRef(null); + let timer = null; + useEffect(() => { + // 加载代码块内容 + getWXCode(identifier); + // 加载测试集 + const params = { + path, + status: 0, + retry: 1 + }; + getWXCodeTestCase(identifier, params); + }, []); + // 关闭 + const handleCloseTestCase = () => { + // setIsVisible(false); + showWXCodeTextCase(false) + } + // 测试集 + const handleClickTestCase = () => { + // setIsVisible(true); + showWXCodeTextCase(true) + } + // 编辑器代码 + const handleEditorChange = (origin, monaco) => { + editorRef.current = monaco; // 获取当前monaco实例 + // setEditCode(origin); // 保存编辑器初始值 + editorRef.current.onDidChangeModelContent(e => { // 监听编辑器内容的变化 + // TODO 需要优化 节流 + const val = editorRef.current.getValue(); + // console.log('编辑器代码====>>>>', val); + // updateWXCodeForEditor(val); + codeChange(val); + }); + }; + + const codeChange = (code) => { + // console.log(code); + updateWXCodeForEditor(code); + if (!timer) { + timer = setInterval(function () { + clearInterval(timer); + timer = null; + // 调用更新代码 + updateWXCodeForInterval(identifier, path); + }, 10000); + } + } + + // 关闭单个测试集 + const handleCloseItem = (i, flag) => { + if (!flag) return; + setIsActive(isActive === i ? -1 : i); + } + // 初始化 + const handleResetCode = () => { + const result = window.confirm('你在本文件中修改的内容将丢失, 是否确定重新加载初始代码?'); + if (result) { + identifier && restoreWXCode(identifier, { path }); + } + } + // 评测 + const handleEvalateCode = () => { + changeWXCodeEvaluateLoading(true); + evaluateWxCode(identifier, path); + } + + const tcclasses = isShow ? `wx-code-test-case active` : 'wx-code-test-case'; + const loading = showLoading ? 'code-evaluate-loading active' : 'code-evaluate-loading'; + const _val = sets_error_count === 0; + let resultTxt = (_val) ? '全部通过' : `${sets_error_count}组测试结果不匹配`; + const iclasses = _val ? 'iconfont icon-tishi1 icon success' : 'iconfont icon-tishi1 icon fail'; + const tclasses = _val ? 'result-txt success' : 'result-txt fail'; + const ulClasses = last_compile_output ? 'case-list hasResult' : 'case-list'; + return ( +
+
+
+ +
+
+
+ + + 初始化 + + + + 测试集 + +
+ {/* */} + +
+
+ {/* 测试集 */} +
+
+
+ 共{testCase.length}个测试用例 + 关闭 +
+
+ + {test_sets_count - sets_error_count}/{test_sets_count} + {resultTxt} +
+
    + { + testCase.map((item, i) => { + const {input, output, actual_output, is_public, result} = item; + const _classes = isActive === i ? 'case-item-desc active' : 'case-item-desc'; + const iconclasses = isActive === i ? 'iconfont icon-sanjiaoxing-down icon active' : 'iconfont icon-triangle icon'; + const headerClasses = is_public ? 'item-header-desc active' : 'item-header-desc'; + // console.log(_classes); + return ( +
  • +
    handleCloseItem(i, is_public)}> +

    + + 测试集{i + 1} +

    + { + is_public + ? (result + ? + : ) + : ( + 隐藏测试集,暂不支持解锁和查看 + {/* {result + ? + : + } */} + ) + } +
    + +
    + 测试输入 + {input || '-'} + 预期输出 + {/* */} + */} + 实际输出 +